From 47afd82d9eaf0f789de4dc6beafd69658e8ea2b9 Mon Sep 17 00:00:00 2001 From: Mark Liversedge Date: Sat, 23 May 2015 13:38:07 +0100 Subject: [PATCH] Route Search Refactor Part 1 of 2 .. clean code and get ready to add background scanning for routes .. next update will add background scanning --- src/AnalysisSidebar.cpp | 17 +++- src/Route.cpp | 177 +++++----------------------------------- src/Route.h | 76 ++++++++--------- src/RouteItem.cpp | 12 +-- 4 files changed, 71 insertions(+), 211 deletions(-) diff --git a/src/AnalysisSidebar.cpp b/src/AnalysisSidebar.cpp index 6f1ddca37..71bd5fc4a 100644 --- a/src/AnalysisSidebar.cpp +++ b/src/AnalysisSidebar.cpp @@ -526,12 +526,15 @@ AnalysisSidebar::showIntervalMenu(const QPoint &pos) // care as we should only really operate on user intervals QTreeWidgetItem *trItem = intervalTree->itemAt(pos); + QTreeWidgetItem *root = trItem ? trItem->parent() : NULL; QVariant v = trItem ? trItem->data(0, Qt::UserRole) : QVariant(); IntervalItem *interval = static_cast(v.value()); - if (trItem != NULL && interval) { + if (trItem != NULL && root && interval) { + // what kind if interval are we looking at ? + RideFileInterval::IntervalType type = trees.key(root, static_cast(-1)); bool isUser = interval->rideInterval != NULL; activeInterval = interval; @@ -540,13 +543,10 @@ AnalysisSidebar::showIntervalMenu(const QPoint &pos) // ZOOM IN AND OUT FOR ALL QAction *actZoomOut = new QAction(tr("Zoom Out"), intervalTree); QAction *actZoomInt = new QAction(tr("Zoom to interval"), intervalTree); - QAction *actRoute = new QAction(tr("Create as a route"), intervalTree); connect(actZoomOut, SIGNAL(triggered(void)), this, SLOT(zoomOut(void))); connect(actZoomInt, SIGNAL(triggered(void)), this, SLOT(zoomInterval(void))); - connect(actRoute, SIGNAL(triggered(void)), this, SLOT(createRouteIntervalSelected(void))); menu.addAction(actZoomOut); menu.addAction(actZoomInt); - menu.addAction(actRoute); // EDIT / DELETE USER ONLY if (isUser) { @@ -566,6 +566,15 @@ AnalysisSidebar::showIntervalMenu(const QPoint &pos) menu.addSeparator(); + // CREATE NEW ROUTE SEGMENT IF GPS PRESENT (AND NOT ALREADY A ROUTE!) + if (type != RideFileInterval::ROUTE && + context->currentRideItem() && context->currentRideItem()->present.contains("G")) { + + QAction *actRoute = new QAction(tr("Create as a route"), intervalTree); + connect(actRoute, SIGNAL(triggered(void)), this, SLOT(createRouteIntervalSelected(void))); + menu.addAction(actRoute); + } + menu.exec(intervalTree->mapToGlobal(pos)); } } diff --git a/src/Route.cpp b/src/Route.cpp index 08cfb6172..8aa98e368 100644 --- a/src/Route.cpp +++ b/src/Route.cpp @@ -86,52 +86,25 @@ RouteSegment::addRide(RouteRide _ride) int RouteSegment::addRideForRideFile(const RideFile *ride, double start, double stop, double precision) { - qDebug() << "addRideForRideFile" << ride->getTag("Filename",""); RouteRide _route = RouteRide(ride->getTag("Filename",""), ride->startTime(), start, stop, precision); rides.append(_route); return rides.count(); } -bool -RouteSegment::parseRideFileName(Context *context, const QString &name, QString *notesFileName, QDateTime *dt) -{ - static char rideFileRegExp[] = "^((\\d\\d\\d\\d)_(\\d\\d)_(\\d\\d)" - "_(\\d\\d)_(\\d\\d)_(\\d\\d))\\.(.+)$"; - QRegExp rx(rideFileRegExp); - if (!rx.exactMatch(name)) - return false; - //assert(rx.captureCount() == 8); - QDate date(rx.cap(2).toInt(), rx.cap(3).toInt(),rx.cap(4).toInt()); - QTime time(rx.cap(5).toInt(), rx.cap(6).toInt(),rx.cap(7).toInt()); - if ((! date.isValid()) || (! time.isValid())) { - QMessageBox::warning(context->mainWindow, - tr("Invalid File Name"), - tr("Invalid date/time in filename:\n%1\nSkipping file...").arg(name)); - return false; - } - *dt = QDateTime(date, time); - *notesFileName = rx.cap(1) + ".notes"; - return true; -} - void -RouteSegment::removeRideInRoute(RideFile* ride) +RouteSegment::removeRideInRoute(RideItem* ride) { for (int n=0; n< this->getRides().count();n++) { const RouteRide* routeride = &getRides().at(n); - if (ride && routeride->startTime == ride->startTime()) { + if (ride && routeride->startTime == ride->dateTime) { rides.removeAt(n); } } } void -RouteSegment::searchRouteInRide(RideFile* ride, bool freememory, QTextStream* out) +RouteSegment::searchRouteInRide(RideFile* ride) { - //*out << "searchRouteInRide " << ride->startTime().toString() << "\r\n"; - - bool candidate = false; // This RideFile is candidate - double minimumprecision = 0.100; //100m double maximumprecision = 0.010; //10m double precision = -1; @@ -140,7 +113,6 @@ RouteSegment::searchRouteInRide(RideFile* ride, bool freememory, QTextStream* ou int lastpoint = -1; // Last point to match double start = -1, stop = -1; // Start and stop secs - //foreach (RoutePoint routepoint, this->getPoints()) { for (int n=0; n< this->getPoints().count();n++) { RoutePoint routepoint = this->getPoints().at(n); @@ -171,7 +143,6 @@ RouteSegment::searchRouteInRide(RideFile* ride, bool freememory, QTextStream* ou } else { if (_distsecs; precision = 0; - *out << "start time " << start << "\r\n"; } if (minimumdistance>precision) @@ -218,10 +188,8 @@ RouteSegment::searchRouteInRide(RideFile* ride, bool freememory, QTextStream* ou break; } else { - *out << " WARNING route diverge at " << point->secs << "(" << i <<") after " << (point->secs-start)<< "secs for " << minimumdistance << "km " << routepoint.lat << "-" << routepoint.lon << "/" << point->lat << "-" << point->lon << "\r\n"; diverge++; if (diverge>2) { - *out << " STOP route diverge at " << point->secs << "(" << i <<") after " << (point->secs-start)<< "secs for " << minimumdistance << "km " << routepoint.lat << "-" << routepoint.lon << "/" << point->lat << "-" << point->lon << "\r\n"; start = -1; //try to restart n = 0; } @@ -238,112 +206,20 @@ RouteSegment::searchRouteInRide(RideFile* ride, bool freememory, QTextStream* ou if (!present) { - *out << " Route not identified (distance " << precision << "km)\r\n"; break; } else { if (n == this->getPoints().count()-1){ // OK //Add the interval and continue search - *out << " >>> Route identified in: " << name << " start: " << start << " stop: " << stop << " (distance " << precision << "km)\r\n"; this->addRideForRideFile(ride, start, stop, precision); - candidate = true; - *out << " search again..." << "\r\n"; start = -1; n=0; //break; } } - - } - - if (freememory && !candidate && ride) delete ride; // free memory - if needed } -void -RouteSegment::searchRouteInAllRides(Context* context) -{ - qDebug() << "searchRouteInAllRides()"; - - // log of progress - QFile log(context->athlete->home->logs().canonicalPath() + "/" + "routes.log"); - log.open(QIODevice::ReadWrite); - QTextStream out(&log); - - out << "SEARCH NEW ROUTE STARTS: " << QDateTime::currentDateTime().toString() + "\r\n"; - - QStringList filenames; - foreach(RideItem *item, context->athlete->rideCache->rides()) - filenames << item->fileName; - QStringListIterator iterator(filenames); - QStringList errors; - - // update statistics for ride files which are out of date - // showing a progress bar as we go - QTime elapsed; - elapsed.start(); - QString title = tr("Searching route"); - GProgressDialog *bar = NULL; - - int processed=0; - - while (iterator.hasNext()) { - QString name = iterator.next(); - QFile file(context->athlete->home->activities().canonicalPath() + "/" + name); - out << "Opening: " << name; - - RideFile *ride = NULL; - - // update progress bar - long elapsedtime = elapsed.elapsed(); - QString elapsedString = QString("%1:%2:%3").arg(elapsedtime/3600000,2) - .arg((elapsedtime%3600000)/60000,2,10,QLatin1Char('0')) - .arg((elapsedtime%60000)/1000,2,10,QLatin1Char('0')); - - // create the dialog if we need to show progress for long running uodate - if ((elapsedtime > 2000) && bar == NULL) { - bar = new GProgressDialog(title, 0, filenames.count(), context->mainWindow->init, context->mainWindow); - bar->show(); // lets hide until elapsed time is > 2 seconds - - // lets make sure it goes to the center! - QApplication::processEvents(); - } - - if (bar) { - QString title = tr("Searching route in all rides...\nElapsed: %1\n%2").arg(elapsedString).arg(name); - bar->setLabelText(title); - bar->setValue(++processed); - } - QApplication::processEvents(); - - - ride = RideFileFactory::instance().openRideFile(context, file, errors); - if (ride->isDataPresent(RideFile::lat)) { - out << " with GPS datas " << "\r\n"; - searchRouteInRide(ride, true, &out); - } - else - out << " no GPS datas " << "\r\n"; - - if (bar && bar->wasCanceled()) { - out << "SEARCH NEW ROUTE CANCELED: " << QDateTime::currentDateTime().toString() + "\r\n"; - break; - } - } - - // now zap the progress bar - if (bar) delete bar; - - // stop logging - out << "SEARCH NEW ROUTE ENDS: " << QDateTime::currentDateTime().toString() + "\r\n"; - - QMessageBox::information(context->mainWindow, tr("Route"), tr("This route '%1' was found %2 times in %3 activities.").arg(this->getName()).arg(this->getRides().count()).arg(processed)); - - log.close(); -} - - - // This function converts decimal degrees to radians double deg2rad(double deg) { @@ -372,8 +248,6 @@ RouteSegment::distance(double lat1, double lon1, double lat2, double lon2) { - - /* * Routes (list of RouteSegment) * @@ -448,19 +322,13 @@ Routes::writeRoutes() void Routes::addRide(RideItem* ride) { - searchRoutesInRide(ride->ride()); + searchRoutesInRide(ride); writeRoutes(); } // delete a ride void Routes::deleteRide(RideItem* ride) -{ - removeRideInRoutes(ride->ride()); -} - -void -Routes::removeRideInRoutes(RideFile* ride) { for (int routecount=0;routecountathlete->home->logs().canonicalPath() + "/" + "routes2.log"); - log.open(QIODevice::ReadWrite); - QTextStream out(&log); +Routes::searchRoutesInRide(RideItem* item) +{ + if (item->present.contains("G")) { - out << "SEARCH ROUTES IN NEW FILE STARTS: " << QDateTime::currentDateTime().toString() << "\r\n"; + bool doclose=true; + if(item->isOpen()) doclose=false; + RideFile *ride = item->ride(); - for (int routecount=0;routecountgetName() << "(" << route->id().toString() << ")" << (routecount+1) << "/" << routes.count() << "\r\n"; - route->searchRouteInRide(ride, false, &out); + if (ride) { + + // we opened the ride so search all segments + for (int routecount=0;routecountsearchRouteInRide(ride); + } + + if (doclose) item->close(); + } } - - // stop logging - out << "SEARCH ROUTES IN NEW FILE ENDS: " << QDateTime::currentDateTime().toString() << "\r\n"; - log.close(); } void @@ -530,10 +399,4 @@ Routes::createRouteFromInterval(IntervalItem *activeInterval) { lastLon = point->lon; } } - - // Search this route in all rides - route->searchRouteInAllRides(context); - - // Save routes - writeRoutes(); } diff --git a/src/Route.h b/src/Route.h index 622a67195..fe4ceb6a6 100644 --- a/src/Route.h +++ b/src/Route.h @@ -35,19 +35,23 @@ class Routes; struct RouteRide; struct RoutePoint; -class RouteSegment +class RouteSegment // represents a segment we match against { public: + RouteSegment(); RouteSegment(Routes *routes); - Routes *routes; + // accessors QString getName(); void setName(QString _name); - QUuid id() const { return _id; } + QList getPoints(); + QList getRides(); + QList getRouteRides(); void setId(QUuid x) { _id = x; } + // managing points and matched rides int addPoint(RoutePoint _point); int addRide(RouteRide _ride); int addRideForRideFile(const RideFile *ride, double start, double stop, double precision); @@ -55,52 +59,53 @@ class RouteSegment double distance(double lat1, double lon1, double lat2, double lon2); - void searchRouteInAllRides(Context *context); - void searchRouteInRide(RideFile* ride, bool freememory, QTextStream* log); - - void removeRideInRoute(RideFile* ride); - - QList getPoints(); - - QList getRides(); - - QList getRouteRides(); + // segments always work on actual ridefiles + void searchRouteInRide(RideFile* ride); + void removeRideInRoute(RideItem* ride); private: + + Routes *routes; QUuid _id; // unique id QString name; // name, typically users name them by year e.g. "Col de Saxel" - QList points; - QList rides; - }; -class Routes : public QObject { +class Routes : public QObject { // top-level object with API and map of segments/rides Q_OBJECT; + friend class ::RideItem; // access the route/ride map + public: + Routes(Context *context, const QDir &home); + + // managing the list of route segments void readRoutes(); int newRoute(QString name); + void createRouteFromInterval(IntervalItem *activeInterval); void updateRoute(int index, QString name); void deleteRoute(int); void writeRoutes(); - QList routes; - void createRouteFromInterval(IntervalItem *activeInterval); - void searchRoutesInRide(RideFile* ride); + // remove/searching rides void removeRideInRoutes(RideFile* ride); + void searchRoutesInRide(RideItem* ride); public slots: + + // adding and deleting rides void addRide(RideItem*); void deleteRide(RideItem* ride); signals: void routesChanged(); + protected: + QList routes; private: QDir home; @@ -108,43 +113,26 @@ class Routes : public QObject { }; -/*class RouteRide2 : public QObject { +struct RouteRide { // represents a section of a ride that matches a segment - Q_OBJECT; + RouteRide() {} + RouteRide(QString filename, QDateTime startTime, double start, double stop, double precision) : + filename(filename), startTime(startTime), start(start), stop(stop), precision(precision) {} - public : - RouteRide2(); - - RouteRide2(QDateTime startTime, double start, double stop, double precision);// : startTime(startTime), start(start), stop(stop), precision(precision) {} - - QDateTime startTime; - double start, stop; - double precision; - -};*/ - -struct RouteRide { QString filename; QDateTime startTime; double start, stop; double precision; - - - RouteRide(QString filename, QDateTime startTime, double start, double stop, double precision) : filename(filename), startTime(startTime), start(start), stop(stop), precision(precision) {} - - RouteRide() {} }; -struct RoutePoint +struct RoutePoint // represents a point within a segment { - double lon, lat; - RoutePoint() : lon(0.0), lat(0.0) {} - RoutePoint(double lon, double lat) : lon(lon), lat(lat) {} - //double value(RideFile::SeriesType series) const; + + double lon, lat; }; #endif // ROUTE_H diff --git a/src/RouteItem.cpp b/src/RouteItem.cpp index cb713b095..e7edaec59 100644 --- a/src/RouteItem.cpp +++ b/src/RouteItem.cpp @@ -56,14 +56,14 @@ RouteItem::RouteItem(RouteSegment *route, const RouteRide *routeRide, setTextAlignment(1, Qt::AlignRight); setTextAlignment(2, Qt::AlignRight); - QDateTime dt; - foreach(RideItem *item, context->athlete->rideCache->rides()) { + //QDateTime dt; + //foreach(RideItem *item, context->athlete->rideCache->rides()) { //XXX what is this code trying to do ??? XXX - if ((route->parseRideFileName(context, item->fileName, ¬esFileName, &dt)) && (dt == routeRide->startTime)) { // - fileName = item->fileName; - } - } + //if ((route->parseRideFileName(context, item->fileName, ¬esFileName, &dt)) && (dt == routeRide->startTime)) { // + // fileName = item->fileName; + //} + //} } RouteItem::RouteItem(RouteSegment *route, int type,