From dad85e46a79a4e6d95f571fd68402484e570bae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20T=C5=AFma?= Date: Tue, 9 Aug 2016 01:16:19 +0200 Subject: [PATCH] Added support for GPX routes --- gpxsee.pro | 8 +- lang/gpxsee_cs.ts | 172 ++++++++++++++++++------------ src/elevationgraph.cpp | 62 ++++++----- src/elevationgraph.h | 4 +- src/gpx.h | 6 +- src/gui.cpp | 192 +++++++++++++++++++++------------ src/gui.h | 22 ++-- src/heartrategraph.cpp | 18 ++-- src/heartrategraph.h | 2 +- src/parser.cpp | 61 +++++++++++ src/parser.h | 13 ++- src/route.cpp | 25 +++++ src/route.h | 23 ++++ src/routeitem.cpp | 74 +++++++++++++ src/routeitem.h | 32 ++++++ src/settings.h | 17 ++- src/speedgraph.cpp | 16 +-- src/speedgraph.h | 2 +- src/temperaturegraph.cpp | 16 +-- src/temperaturegraph.h | 2 +- src/track.h | 1 - src/trackitem.cpp | 55 +++++++--- src/trackitem.h | 20 +++- src/trackview.cpp | 223 +++++++++++++++++++++++++++++---------- src/trackview.h | 30 ++++-- src/waypoint.h | 2 + src/waypointitem.cpp | 49 ++++++--- src/waypointitem.h | 2 + 28 files changed, 853 insertions(+), 296 deletions(-) create mode 100644 src/route.cpp create mode 100644 src/route.h create mode 100644 src/routeitem.cpp create mode 100644 src/routeitem.h diff --git a/gpxsee.pro b/gpxsee.pro index 2ae68b49..3087e890 100644 --- a/gpxsee.pro +++ b/gpxsee.pro @@ -47,7 +47,9 @@ HEADERS += src/config.h \ src/graphtab.h \ src/misc.h \ src/trackitem.h \ - src/tooltip.h + src/tooltip.h \ + src/route.h \ + src/routeitem.h SOURCES += src/main.cpp \ src/gui.cpp \ src/gpx.cpp \ @@ -82,7 +84,9 @@ SOURCES += src/main.cpp \ src/misc.cpp \ src/waypoint.cpp \ src/trackitem.cpp \ - src/tooltip.cpp + src/tooltip.cpp \ + src/route.cpp \ + src/routeitem.cpp RESOURCES += gpxsee.qrc TRANSLATIONS = lang/gpxsee_cs.ts macx { diff --git a/lang/gpxsee_cs.ts b/lang/gpxsee_cs.ts index 6ffb154c..489994bc 100644 --- a/lang/gpxsee_cs.ts +++ b/lang/gpxsee_cs.ts @@ -163,17 +163,17 @@ GUI - + GPXSee is distributed under the terms of the GNU General Public License version 3. For more info about GPXSee visit the project homepage at Program GPXSee je distribuován pod podmínkami licence GNU General Public License verze 3. Pro více informací navštivte stránky programu na adrese - + Open file Otevřít soubor - + Open POI file Otevřít POI soubor @@ -189,8 +189,8 @@ - - + + Keyboard controls Ovládací klávesy @@ -205,20 +205,20 @@ Znovu načíst - + Show Zobrazit - - + + File Soubor - - + + Data sources Zdroje dat @@ -238,125 +238,150 @@ Překrývat POI - + + Show POI labels + Zobrazovat názvy POI + + + Show POIs Zobrazit POI - + Show map Zobrazit mapu - + Clear tile cache Vymazat mezipaměť dlaždic - - + + Next map Následující mapa - + + Show tracks + Zobrazit cesty + + + + Show routes + Zobrazit trasy + + + + Show waypoints + Zobrazit navigační body + + + Show graphs Zobrazovat grafy - + Show toolbars Zobrazovat nástrojové lišty - + Metric Metrické - + Imperial Imperiální - + Fullscreen mode Celoobrazovkový režim - + Next Následující - + Previous Předchozí - + Last Poslední - + First První - + Map Mapa - + POI POI - + POI files POI soubory - + + Data + Data + + + Settings Nastavení - + Units Jednotky - + Help Nápověda - + Previous map Předchozí mapa - - + + Date Datum - + No GPX files loaded Nejsou načteny žádné GPX soubory - + Next file Následující soubor - + Version Verze @@ -371,123 +396,133 @@ Exportovat do PDF... - + + Show waypoint labels + Zobrazovat názvy navigačních bodů + + + + Rendering + Zobrazení + + + Previous file Předchozí soubor - + First file První soubor - + Last file Poslední soubor - + Append modifier Modifikátor nahradit/přidat - + Map (tiles) source URLs are read on program startup from the following file: URL mapových zdrojů (dlaždic) jsou načteny při startu programu z následujícího souboru: - + The file format is one map entry per line, consisting of the map name and tiles URL delimited by a TAB character. The tile X and Y coordinates are replaced with $x and $y in the URL and the zoom level is replaced with $z. An example map file could look like: Formát souboru je jeden mapový záznam na řádku, kde mapový záznam sestává ze jména mapy a URL dlaždic navzájem oddělených tabulátorem. Souřadnice dlaždice jsou v URL nahrazeny řetězci $x a $y, úroven přiblížení (zoom) pak řetězcem $z. Příklad: - + To make GPXSee load a POI file automatically on startup, add the file to the following directory: POI soubory, které se mají automaticky nahrát při startu programu jsou načítány z následujícího adresáře: - + GPX files (*.gpx);;All files (*) Soubory GPX (*.gpx);;Všechny soubory (*) - - + + Line: %1 Řádka: %1 - + GPX files (*.gpx);;CSV files (*.csv);;All files (*) Soubory GPX (*.gpx);;Soubory CSV (*.csv);;Všechny soubory (*) - + Tracks Počet tras - + mi mi - + About GPXSee O aplikaci GPXSee - + Navigation Navigace - + Map sources Mapové zdroje - + POIs POI body - - + + Distance Vzdálenost - + Time Čas - + %1 tracks Počet tras: %1 - + km km - - + + Error Chyba - + Error loading GPX file: %1 Soubor GPX nelze otevřít: %1 - + Error loading POI file: %1 Soubor POI nelze otevřít: @@ -725,22 +760,27 @@ WaypointItem - + + Name + Název + + + Coordinates Souřadnice - + Elevation Výška - + Date Datum - + Description Popis diff --git a/src/elevationgraph.cpp b/src/elevationgraph.cpp index 7aa6f4d4..d960801e 100644 --- a/src/elevationgraph.cpp +++ b/src/elevationgraph.cpp @@ -17,7 +17,7 @@ ElevationGraph::ElevationGraph(QWidget *parent) : GraphTab(parent) setMinYRange(50.0); } -void ElevationGraph::addInfo() +void ElevationGraph::setInfo() { GraphView::addInfo(tr("Ascent"), QString::number(_ascent * yScale(), 'f', 0) + UNIT_SPACE + yUnits()); @@ -27,40 +27,51 @@ void ElevationGraph::addInfo() + UNIT_SPACE + yUnits()); GraphView::addInfo(tr("Minimum"), QString::number(min() * yScale(), 'f', 0) + UNIT_SPACE + yUnits()); +} - redraw(); +void ElevationGraph::loadPath(const QVector &data) +{ + qreal ascent = 0, descent = 0; + + if (data.count() < 2) { + skipColor(); + return; + } + + for (int j = 1; j < data.size(); j++) { + qreal cur = data.at(j).y(); + qreal prev = data.at(j-1).y(); + + if (cur > prev) + ascent += cur - prev; + if (cur < prev) + descent += prev - cur; + } + + _ascent += ascent; + _descent += descent; + + loadData(data); } void ElevationGraph::loadGPX(const GPX &gpx) { for (int i = 0; i < gpx.trackCount(); i++) { QVector data; - qreal ascent = 0, descent = 0; - gpx.track(i).elevationGraph(data); - if (data.count() < 2) { - skipColor(); - continue; - } + loadPath(data); + } - for (int j = 1; j < data.size(); j++) { - qreal cur = data.at(j).y(); - qreal prev = data.at(j-1).y(); - - if (cur > prev) - ascent += cur - prev; - if (cur < prev) - descent += prev - cur; - } - - _ascent += ascent; - _descent += descent; - - loadData(data); + for (int i = 0; i < gpx.routeCount(); i++) { + QVector data; + gpx.route(i).elevationGraph(data); + loadPath(data); } setXUnits(); - addInfo(); + setInfo(); + + redraw(); } void ElevationGraph::clear() @@ -106,9 +117,10 @@ void ElevationGraph::setYUnits() void ElevationGraph::setUnits(enum Units units) { _units = units; + setXUnits(); setYUnits(); + setInfo(); - clearInfo(); - addInfo(); + redraw(); } diff --git a/src/elevationgraph.h b/src/elevationgraph.h index ed59e29d..27148dff 100644 --- a/src/elevationgraph.h +++ b/src/elevationgraph.h @@ -25,7 +25,9 @@ private: void setXUnits(); void setYUnits(); - void addInfo(); + void setInfo(); + + void loadPath(const QVector &data); qreal _ascent, _descent; enum Units _units; diff --git a/src/gpx.h b/src/gpx.h index d3407d2c..e3862f30 100644 --- a/src/gpx.h +++ b/src/gpx.h @@ -7,18 +7,21 @@ #include #include "waypoint.h" #include "track.h" +#include "route.h" #include "parser.h" class GPX { public: - GPX() : _parser(_tracks, _waypoints), _errorLine(0) {} + GPX() : _parser(_tracks, _routes, _waypoints), _errorLine(0) {} bool loadFile(const QString &fileName); const QString &errorString() const {return _error;} int errorLine() const {return _errorLine;} int trackCount() const {return _tracks.count();} Track track(int i) const {return Track(_tracks.at(i));} + int routeCount() const {return _routes.count();} + Route route(int i) const {return Route(_routes.at(i));} const QList &waypoints() const {return _waypoints;} private: @@ -27,6 +30,7 @@ private: int _errorLine; QList > _tracks; + QList > _routes; QList _waypoints; }; diff --git a/src/gui.cpp b/src/gui.cpp index 6bd2ced0..fcbfac1e 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -44,12 +44,12 @@ GUI::GUI(QWidget *parent) : QMainWindow(parent) loadMaps(); loadPOIs(); - createActions(); - createMenus(); - createToolBars(); createTrackView(); createTrackGraphs(); createStatusBar(); + createActions(); + createMenus(); + createToolBars(); _browser = new FileBrowser(this); _browser->setFilter(QStringList("*.gpx")); @@ -189,7 +189,7 @@ void GUI::createActions() tr("About GPXSee"), this); connect(_aboutAction, SIGNAL(triggered()), this, SLOT(about())); - // File related actions + // File actions _openFileAction = new QAction(QIcon(QPixmap(OPEN_FILE_ICON)), tr("Open"), this); _openFileAction->setShortcut(OPEN_SHORTCUT); @@ -228,8 +228,12 @@ void GUI::createActions() connect(_closePOIAction, SIGNAL(triggered()), this, SLOT(closePOIFiles())); _overlapPOIAction = new QAction(tr("Overlap POIs"), this); _overlapPOIAction->setCheckable(true); - connect(_overlapPOIAction, SIGNAL(triggered(bool)), this, - SLOT(overlapPOIs(bool))); + connect(_overlapPOIAction, SIGNAL(triggered(bool)), _track, + SLOT(setPOIOverlap(bool))); + _showPOILabelsAction = new QAction(tr("Show POI labels"), this); + _showPOILabelsAction->setCheckable(true); + connect(_showPOILabelsAction, SIGNAL(triggered(bool)), _track, + SLOT(showPOILabels(bool))); _showPOIAction = new QAction(QIcon(QPixmap(SHOW_POI_ICON)), tr("Show POIs"), this); _showPOIAction->setCheckable(true); @@ -264,6 +268,24 @@ void GUI::createActions() addAction(_prevMapAction); } + // Data actions + _showTracksAction = new QAction(tr("Show tracks"), this); + _showTracksAction->setCheckable(true); + connect(_showTracksAction, SIGNAL(triggered(bool)), _track, + SLOT(showTracks(bool))); + _showRoutesAction = new QAction(tr("Show routes"), this); + _showRoutesAction->setCheckable(true); + connect(_showRoutesAction, SIGNAL(triggered(bool)), _track, + SLOT(showRoutes(bool))); + _showWaypointsAction = new QAction(tr("Show waypoints"), this); + _showWaypointsAction->setCheckable(true); + connect(_showWaypointsAction, SIGNAL(triggered(bool)), _track, + SLOT(showWaypoints(bool))); + _showWaypointLabelsAction = new QAction(tr("Show waypoint labels"), this); + _showWaypointLabelsAction->setCheckable(true); + connect(_showWaypointLabelsAction, SIGNAL(triggered(bool)), _track, + SLOT(showWaypointLabels(bool))); + // Settings actions _showGraphsAction = new QAction(tr("Show graphs"), this); _showGraphsAction->setCheckable(true); @@ -314,53 +336,62 @@ void GUI::createActions() void GUI::createMenus() { - _fileMenu = menuBar()->addMenu(tr("File")); - _fileMenu->addAction(_openFileAction); - _fileMenu->addSeparator(); - _fileMenu->addAction(_printFileAction); - _fileMenu->addAction(_exportFileAction); - _fileMenu->addSeparator(); - _fileMenu->addAction(_reloadFileAction); - _fileMenu->addSeparator(); - _fileMenu->addAction(_closeFileAction); + QMenu *fileMenu = menuBar()->addMenu(tr("File")); + fileMenu->addAction(_openFileAction); + fileMenu->addSeparator(); + fileMenu->addAction(_printFileAction); + fileMenu->addAction(_exportFileAction); + fileMenu->addSeparator(); + fileMenu->addAction(_reloadFileAction); + fileMenu->addSeparator(); + fileMenu->addAction(_closeFileAction); #ifndef Q_OS_MAC - _fileMenu->addSeparator(); - _fileMenu->addAction(_exitAction); + fileMenu->addSeparator(); + fileMenu->addAction(_exitAction); #endif // Q_OS_MAC - _mapMenu = menuBar()->addMenu(tr("Map")); - _mapMenu->addActions(_mapActions); - _mapMenu->addSeparator(); - _mapMenu->addAction(_clearMapCacheAction); - _mapMenu->addSeparator(); - _mapMenu->addAction(_showMapAction); + QMenu *mapMenu = menuBar()->addMenu(tr("Map")); + mapMenu->addActions(_mapActions); + mapMenu->addSeparator(); + mapMenu->addAction(_clearMapCacheAction); + mapMenu->addSeparator(); + mapMenu->addAction(_showMapAction); - _poiMenu = menuBar()->addMenu(tr("POI")); - _poiFilesMenu = _poiMenu->addMenu(tr("POI files")); + QMenu *poiMenu = menuBar()->addMenu(tr("POI")); + _poiFilesMenu = poiMenu->addMenu(tr("POI files")); _poiFilesMenu->addActions(_poiFilesActions); - _poiMenu->addSeparator(); - _poiMenu->addAction(_openPOIAction); - _poiMenu->addAction(_closePOIAction); - _poiMenu->addSeparator(); - _poiMenu->addAction(_overlapPOIAction); - _poiMenu->addSeparator(); - _poiMenu->addAction(_showPOIAction); + poiMenu->addSeparator(); + poiMenu->addAction(_openPOIAction); + poiMenu->addAction(_closePOIAction); + poiMenu->addSeparator(); + poiMenu->addAction(_showPOILabelsAction); + poiMenu->addAction(_overlapPOIAction); + poiMenu->addSeparator(); + poiMenu->addAction(_showPOIAction); - _settingsMenu = menuBar()->addMenu(tr("Settings")); - _unitsMenu = _settingsMenu->addMenu(tr("Units")); - _unitsMenu->addAction(_metricUnitsAction); - _unitsMenu->addAction(_imperialUnitsAction); - _settingsMenu->addSeparator(); - _settingsMenu->addAction(_showToolbarsAction); - _settingsMenu->addAction(_showGraphsAction); - _settingsMenu->addSeparator(); - _settingsMenu->addAction(_fullscreenAction); + QMenu *dataMenu = menuBar()->addMenu(tr("Data")); + dataMenu->addAction(_showTracksAction); + dataMenu->addAction(_showRoutesAction); + dataMenu->addAction(_showWaypointsAction); + dataMenu->addSeparator(); + QMenu *displayMenu = dataMenu->addMenu(tr("Rendering")); + displayMenu->addAction(_showWaypointLabelsAction); - _helpMenu = menuBar()->addMenu(tr("Help")); - _helpMenu->addAction(_dataSourcesAction); - _helpMenu->addAction(_keysAction); - _helpMenu->addSeparator(); - _helpMenu->addAction(_aboutAction); + QMenu *settingsMenu = menuBar()->addMenu(tr("Settings")); + QMenu *unitsMenu = settingsMenu->addMenu(tr("Units")); + unitsMenu->addAction(_metricUnitsAction); + unitsMenu->addAction(_imperialUnitsAction); + settingsMenu->addSeparator(); + settingsMenu->addAction(_showToolbarsAction); + settingsMenu->addAction(_showGraphsAction); + settingsMenu->addSeparator(); + settingsMenu->addAction(_fullscreenAction); + + QMenu *helpMenu = menuBar()->addMenu(tr("Help")); + helpMenu->addAction(_dataSourcesAction); + helpMenu->addAction(_keysAction); + helpMenu->addSeparator(); + helpMenu->addAction(_aboutAction); } void GUI::createToolBars() @@ -706,8 +737,8 @@ void GUI::plot(QPrinter *printer) ? 0.15 * r * (printer->height() - ih - 2*mh) : 0.15 * (printer->height() - ih - 2*mh); gh = qMax(gh, ratio * 150); - GraphView *gv = static_cast(_trackGraphs->currentWidget()); - gv->plot(&p, QRectF(0, printer->height() - gh, printer->width(), gh)); + GraphTab *gt = static_cast(_trackGraphs->currentWidget()); + gt->plot(&p, QRectF(0, printer->height() - gh, printer->width(), gh)); } else gh = 0; _track->plot(&p, QRectF(0, ih + mh, printer->width(), printer->height() @@ -771,11 +802,6 @@ void GUI::closeAll() updateTrackView(); } -void GUI::overlapPOIs(bool checked) -{ - _track->setPOIOverlap(checked); -} - void GUI::showPOI(bool checked) { if (checked) @@ -841,6 +867,11 @@ void GUI::showFullscreen(bool checked) } } +void GUI::showWaypointLabels(bool checked) +{ + _track->showWaypointLabels(checked); +} + void GUI::clearMapCache() { _currentMap->clearCache(); @@ -920,8 +951,8 @@ void GUI::graphChanged(int index) if (index < 0) return; - GraphView *gv = static_cast(_trackGraphs->widget(index)); - gv->setSliderPosition(_sliderPos); + GraphTab *gt = static_cast(_trackGraphs->widget(index)); + gt->setSliderPosition(_sliderPos); } void GUI::updateNavigationActions() @@ -972,7 +1003,8 @@ void GUI::updateGraphTabs() void GUI::updateTrackView() { - _track->setHidden(!(_track->trackCount() + _track->waypointCount())); + _track->setHidden(!(_track->trackCount() + _track->routeCount() + + _track->waypointCount())); } void GUI::setMetricUnits() @@ -1106,6 +1138,16 @@ void GUI::writeSettings() } settings.endArray(); settings.endGroup(); + + settings.beginGroup(DATA_SETTINGS_GROUP); + settings.setValue(SHOW_TRACKS_SETTING, _showTracksAction->isChecked()); + settings.setValue(SHOW_ROUTES_SETTING, _showRoutesAction->isChecked()); + settings.setValue(SHOW_WAYPOINTS_SETTING, + _showWaypointsAction->isChecked()); + settings.setValue(SHOW_WAYPOINT_LABELS_SETTING, + _showWaypointLabelsAction->isChecked()); + + settings.endGroup(); } void GUI::readSettings() @@ -1125,15 +1167,13 @@ void GUI::readSettings() _imperialUnitsAction->setChecked(true); } else _metricUnitsAction->setChecked(true); - if (settings.value(SHOW_TOOLBARS_SETTING, true).toBool() == false) { + if (settings.value(SHOW_TOOLBARS_SETTING, true).toBool() == false) showToolbars(false); - _showToolbarsAction->setChecked(false); - } else + else _showToolbarsAction->setChecked(true); - if (settings.value(SHOW_GRAPHS_SETTING, true).toBool() == false) { + if (settings.value(SHOW_GRAPHS_SETTING, true).toBool() == false) showGraphs(false); - _showGraphsAction->setChecked(false); - } else + else _showGraphsAction->setChecked(true); settings.endGroup(); @@ -1151,11 +1191,14 @@ void GUI::readSettings() settings.endGroup(); settings.beginGroup(POI_SETTINGS_GROUP); - if (settings.value(OVERLAP_POI_SETTING, true).toBool() == false) { + if (settings.value(OVERLAP_POI_SETTING, true).toBool() == false) _track->setPOIOverlap(false); - _overlapPOIAction->setChecked(false); - } else + else _overlapPOIAction->setChecked(true); + if (settings.value(LABELS_POI_SETTING, true).toBool() == false) + _track->showPOILabels(false); + else + _showPOILabelsAction->setChecked(true); if (settings.value(SHOW_POI_SETTING, false).toBool() == true) _showPOIAction->setChecked(true); for (int i = 0; i < _poiFilesActions.count(); i++) @@ -1172,6 +1215,25 @@ void GUI::readSettings() } settings.endArray(); settings.endGroup(); + + settings.beginGroup(DATA_SETTINGS_GROUP); + if (settings.value(SHOW_TRACKS_SETTING, true).toBool() == false) + _track->showTracks(false); + else + _showTracksAction->setChecked(true); + if (settings.value(SHOW_ROUTES_SETTING, true).toBool() == false) + _track->showRoutes(false); + else + _showRoutesAction->setChecked(true); + if (settings.value(SHOW_WAYPOINTS_SETTING, true).toBool() == false) + _track->showWaypoints(false); + else + _showWaypointsAction->setChecked(true); + if (settings.value(SHOW_WAYPOINT_LABELS_SETTING, true).toBool() == false) + _track->showWaypointLabels(false); + else + _showWaypointLabelsAction->setChecked(true); + settings.endGroup(); } int GUI::mapIndex(const QString &name) diff --git a/src/gui.h b/src/gui.h index c56fdf1f..57a12f09 100644 --- a/src/gui.h +++ b/src/gui.h @@ -43,12 +43,12 @@ private slots: void reloadFile(); void openPOIFile(); void closePOIFiles(); - void overlapPOIs(bool checked); void showPOI(bool checked); void showMap(bool checked); void showGraphs(bool checked); void showToolbars(bool checked); void showFullscreen(bool checked); + void showWaypointLabels(bool checked); void clearMapCache(); void nextMap(); void prevMap(); @@ -94,28 +94,20 @@ private: void updateGraphTabs(); void updateTrackView(); - void keyPressEvent(QKeyEvent * event); + void keyPressEvent(QKeyEvent *event); void closeEvent(QCloseEvent *event); int mapIndex(const QString &name); void readSettings(); void writeSettings(); - QMenu *_fileMenu; - QMenu *_helpMenu; - QMenu *_poiMenu; - QMenu *_mapMenu; - QMenu *_settingsMenu; - QMenu *_unitsMenu; - QMenu *_poiFilesMenu; - QToolBar *_fileToolBar; QToolBar *_showToolBar; QToolBar *_navigationToolBar; - QTabWidget *_trackGraphs; + QMenu *_poiFilesMenu; + QActionGroup *_fileActionGroup; QActionGroup *_navigationActionGroup; - QAction *_exitAction; QAction *_keysAction; QAction *_dataSourcesAction; @@ -130,6 +122,7 @@ private: QAction *_closePOIAction; QAction *_showPOIAction; QAction *_overlapPOIAction; + QAction *_showPOILabelsAction; QAction *_showMapAction; QAction *_fullscreenAction; QAction *_clearMapCacheAction; @@ -143,6 +136,10 @@ private: QAction *_imperialUnitsAction; QAction *_nextMapAction; QAction *_prevMapAction; + QAction *_showTracksAction; + QAction *_showRoutesAction; + QAction *_showWaypointsAction; + QAction *_showWaypointLabelsAction; QList _mapActions; QList _poiFilesActions; @@ -153,6 +150,7 @@ private: QLabel *_timeLabel; TrackView *_track; + QTabWidget *_trackGraphs; QList _tabs; POI _poi; diff --git a/src/heartrategraph.cpp b/src/heartrategraph.cpp index 6e910917..b6eee0bd 100644 --- a/src/heartrategraph.cpp +++ b/src/heartrategraph.cpp @@ -13,14 +13,12 @@ HeartRateGraph::HeartRateGraph(QWidget *parent) : GraphTab(parent) setSliderPrecision(0); } -void HeartRateGraph::addInfo() +void HeartRateGraph::setInfo() { GraphView::addInfo(tr("Average"), QString::number(avg() * yScale(), 'f', 0) + UNIT_SPACE + yUnits()); GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale(), 'f', 0) + UNIT_SPACE + yUnits()); - - redraw(); } void HeartRateGraph::loadGPX(const GPX &gpx) @@ -44,8 +42,13 @@ void HeartRateGraph::loadGPX(const GPX &gpx) loadData(data); } + for (int i = 0; i < gpx.routeCount(); i++) + skipColor(); + setXUnits(); - addInfo(); + setInfo(); + + redraw(); } qreal HeartRateGraph::avg() const @@ -92,8 +95,9 @@ void HeartRateGraph::setXUnits() void HeartRateGraph::setUnits(enum Units units) { _units = units; - setXUnits(); - clearInfo(); - addInfo(); + setXUnits(); + setInfo(); + + redraw(); } diff --git a/src/heartrategraph.h b/src/heartrategraph.h index c6046396..4d412b79 100644 --- a/src/heartrategraph.h +++ b/src/heartrategraph.h @@ -21,7 +21,7 @@ private: qreal avg() const; qreal max() const {return bounds().bottom();} void setXUnits(); - void addInfo(); + void setInfo(); QList _avg; enum Units _units; diff --git a/src/parser.cpp b/src/parser.cpp index ef04232d..7c00487a 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -52,6 +52,30 @@ void Parser::handleWaypointData(DataType type, const QString &value) } } +void Parser::handleRoutepointData(DataType type, const QString &value) +{ + switch (type) { + case Name: + _route->last().setName(value); + break; + case Description: + _route->last().setDescription(value); + break; + case Time: + _route->last().setTimestamp(QDateTime::fromString( + value.toLatin1(), Qt::ISODate)); + break; + case Elevation: + _route->last().setElevation(value.toLatin1().toDouble()); + break; + case Geoidheight: + _route->last().setGeoidHeight(value.toLatin1().toDouble()); + break; + default: + break; + } +} + void Parser::handleTrackpointAttributes(const QXmlStreamAttributes &attr) { _track->last().setCoordinates(QPointF( @@ -59,6 +83,13 @@ void Parser::handleTrackpointAttributes(const QXmlStreamAttributes &attr) attr.value("lat").toLatin1().toDouble())); } +void Parser::handleRoutepointAttributes(const QXmlStreamAttributes &attr) +{ + _route->last().setCoordinates(QPointF( + attr.value("lon").toLatin1().toDouble(), + attr.value("lat").toLatin1().toDouble())); +} + void Parser::handleWaypointAttributes(const QXmlStreamAttributes &attr) { _waypoints.last().setCoordinates(QPointF( @@ -110,6 +141,20 @@ void Parser::trackpointData() } } +void Parser::routepointData() +{ + while (_reader.readNextStartElement()) { + if (_reader.name() == "name") + handleRoutepointData(Name, _reader.readElementText()); + else if (_reader.name() == "ele") + handleRoutepointData(Elevation, _reader.readElementText()); + else if (_reader.name() == "geoidheight") + handleRoutepointData(Geoidheight, _reader.readElementText()); + else + _reader.skipCurrentElement(); + } +} + void Parser::trackpoints() { while (_reader.readNextStartElement()) { @@ -122,6 +167,18 @@ void Parser::trackpoints() } } +void Parser::routepoints() +{ + while (_reader.readNextStartElement()) { + if (_reader.name() == "rtept") { + _route->append(Waypoint()); + handleRoutepointAttributes(_reader.attributes()); + routepointData(); + } else + _reader.skipCurrentElement(); + } +} + void Parser::track() { while (_reader.readNextStartElement()) { @@ -157,6 +214,10 @@ void Parser::gpx() _tracks.append(QVector()); _track = &_tracks.back(); track(); + } else if (_reader.name() == "rte") { + _routes.append(QVector()); + _route = &_routes.back(); + routepoints(); } else if (_reader.name() == "wpt") { _waypoints.append(Waypoint()); handleWaypointAttributes(_reader.attributes()); diff --git a/src/parser.h b/src/parser.h index cbc5f588..bfd75f70 100644 --- a/src/parser.h +++ b/src/parser.h @@ -11,8 +11,11 @@ class Parser { public: - Parser(QList > &tracks, QList &waypoints) - : _tracks(tracks), _waypoints(waypoints) {_track = 0;} + Parser(QList > &tracks, + QList > &routes, QList &waypoints) + : _tracks(tracks), _routes(routes), _waypoints(waypoints) + {_track = 0; _route = 0;} + bool loadFile(QIODevice *device); QString errorString() const {return _reader.errorString();} int errorLine() const {return _reader.lineNumber();} @@ -27,20 +30,26 @@ private: void gpx(); void track(); void trackpoints(); + void routepoints(); void tpExtension(); void extensions(); void trackpointData(); + void routepointData(); void waypointData(); void handleWaypointAttributes(const QXmlStreamAttributes &attr); void handleWaypointData(DataType type, const QString &value); void handleTrackpointAttributes(const QXmlStreamAttributes &attr); void handleTrackpointData(DataType type, const QString &value); + void handleRoutepointAttributes(const QXmlStreamAttributes &attr); + void handleRoutepointData(DataType type, const QString &value); QXmlStreamReader _reader; QList > &_tracks; + QList > &_routes; QList &_waypoints; QVector *_track; + QVector *_route; }; #endif // PARSER_H diff --git a/src/route.cpp b/src/route.cpp new file mode 100644 index 00000000..5cb9b2e7 --- /dev/null +++ b/src/route.cpp @@ -0,0 +1,25 @@ +#include "ll.h" +#include "route.h" + +Route::Route(const QVector &data) : _data(data) +{ + qreal dist = 0; + + _dd.append(dist); + for (int i = 1; i < _data.count(); i++) { + dist += llDistance(_data.at(i).coordinates(), + _data.at(i-1).coordinates()); + _dd.append(dist); + } +} + +void Route::elevationGraph(QVector &graph) const +{ + if (!_data.size()) + return; + + for (int i = 0; i < _data.size(); i++) + if (_data.at(i).hasElevation()) + graph.append(QPointF(_dd.at(i), _data.at(i).elevation() + - _data.at(i).geoidHeight())); +} diff --git a/src/route.h b/src/route.h new file mode 100644 index 00000000..4e3607c1 --- /dev/null +++ b/src/route.h @@ -0,0 +1,23 @@ +#ifndef ROUTE_H +#define ROUTE_H + +#include +#include "waypoint.h" + +class Route +{ +public: + Route(const QVector &data); + + const QVector &route() const {return _data;} + void elevationGraph(QVector &graph) const; + qreal distance() const {return _dd.last();} + + bool isNull() const {return (_data.count() < 2) ? true : false;} + +private: + const QVector &_data; + QVector _dd; +}; + +#endif // ROUTE_H diff --git a/src/routeitem.cpp b/src/routeitem.cpp new file mode 100644 index 00000000..504e6d64 --- /dev/null +++ b/src/routeitem.cpp @@ -0,0 +1,74 @@ +#include +#include "ll.h" +#include "waypoint.h" +#include "waypointitem.h" +#include "routeitem.h" + + +#define ROUTE_WIDTH 3 + +RouteItem::RouteItem(const Route &route, QGraphicsItem *parent) + : QGraphicsItem(parent) +{ + WaypointItem *wi; + + const QVector &r = route.route(); + Q_ASSERT(r.count() >= 2); + + wi = new WaypointItem(r.at(0)); + wi->setParentItem(this); + const QPointF &p = r.at(0).coordinates(); + _path.moveTo(ll2mercator(QPointF(p.x(), -p.y()))); + for (int i = 1; i < r.size(); i++) { + const QPointF &p = r.at(i).coordinates(); + _path.lineTo(ll2mercator(QPointF(p.x(), -p.y()))); + wi = new WaypointItem(r.at(i)); + wi->setParentItem(this); + } + + QBrush brush(Qt::SolidPattern); + _pen = QPen(brush, ROUTE_WIDTH, Qt::DotLine); + + _marker = new MarkerItem(this); + _marker->setPos(_path.pointAtPercent(0)); +} + +void RouteItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, + QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + painter->setPen(_pen); + painter->drawPath(_path); + +/* + painter->setPen(Qt::red); + painter->drawRect(boundingRect()); +*/ +} + +void RouteItem::setScale(qreal scale) +{ + prepareGeometryChange(); + + _pen.setWidthF(ROUTE_WIDTH * 1.0/scale); + QGraphicsItem::setScale(scale); + _marker->setScale(1.0/scale); + + QList childs = childItems(); + for (int i = 0; i < childs.count(); i++) + childs.at(i)->setScale(1.0/scale); +} + +void RouteItem::setColor(const QColor &color) +{ + _pen.setColor(color); + update(); +} + +void RouteItem::moveMarker(qreal t) +{ + Q_ASSERT(t >= 0 && t <= 1.0); + _marker->setPos(_path.pointAtPercent(t)); +} diff --git a/src/routeitem.h b/src/routeitem.h new file mode 100644 index 00000000..6a55b3e4 --- /dev/null +++ b/src/routeitem.h @@ -0,0 +1,32 @@ +#ifndef ROUTEITEM_H +#define ROUTEITEM_H + +#include +#include "markeritem.h" +#include "route.h" + +class RouteItem : public QGraphicsItem +{ +public: + RouteItem(const Route &route, QGraphicsItem *parent = 0); + + QRectF boundingRect() const {return _path.boundingRect();} + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, + QWidget *widget); + + const QPainterPath &path() const {return _path;} + + void setScale(qreal scale); + void setColor(const QColor &color); + + void showMarker(bool show) {_marker->setVisible(show);} + void moveMarker(qreal t); + +private: + QPainterPath _path; + QPen _pen; + + MarkerItem *_marker; +}; + +#endif // ROUTEITEM_H diff --git a/src/settings.h b/src/settings.h index 20519bb4..d25f842b 100644 --- a/src/settings.h +++ b/src/settings.h @@ -3,21 +3,28 @@ #define WINDOW_SETTINGS_GROUP "Window" #define WINDOW_SIZE_SETTING "size" -#define WINDOW_POS_SETTING "pos" +#define WINDOW_POS_SETTING "pos" #define SETTINGS_SETTINGS_GROUP "Settings" -#define UNITS_SETTING "units" +#define UNITS_SETTING "units" #define SHOW_TOOLBARS_SETTING "toolbar" -#define SHOW_GRAPHS_SETTING "graphs" +#define SHOW_GRAPHS_SETTING "graphs" #define MAP_SETTINGS_GROUP "Map" -#define CURRENT_MAP_SETTING "map" +#define CURRENT_MAP_SETTING "map" #define SHOW_MAP_SETTING "show" -#define POI_SETTINGS_GROUP "POI" +#define POI_SETTINGS_GROUP "POI" #define OVERLAP_POI_SETTING "overlap" +#define LABELS_POI_SETTING "labels" #define SHOW_POI_SETTING "show" #define DISABLED_POI_FILE_SETTINGS_PREFIX "disabled" #define DISABLED_POI_FILE_SETTING "file" +#define DATA_SETTINGS_GROUP "Data" +#define SHOW_TRACKS_SETTING "tracks" +#define SHOW_ROUTES_SETTING "routes" +#define SHOW_WAYPOINTS_SETTING "waypoints" +#define SHOW_WAYPOINT_LABELS_SETTING "waypointLabels" + #endif // SETTINGS_H diff --git a/src/speedgraph.cpp b/src/speedgraph.cpp index fcd60ef3..a2aebe5f 100644 --- a/src/speedgraph.cpp +++ b/src/speedgraph.cpp @@ -14,14 +14,12 @@ SpeedGraph::SpeedGraph(QWidget *parent) : GraphTab(parent) setSliderPrecision(1); } -void SpeedGraph::addInfo() +void SpeedGraph::setInfo() { GraphView::addInfo(tr("Average"), QString::number(avg() * yScale(), 'f', 1) + UNIT_SPACE + yUnits()); GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale(), 'f', 1) + UNIT_SPACE + yUnits()); - - redraw(); } void SpeedGraph::loadGPX(const GPX &gpx) @@ -41,8 +39,13 @@ void SpeedGraph::loadGPX(const GPX &gpx) loadData(data); } + for (int i = 0; i < gpx.routeCount(); i++) + skipColor(); + setXUnits(); - addInfo(); + setInfo(); + + redraw(); } qreal SpeedGraph::avg() const @@ -100,9 +103,10 @@ void SpeedGraph::setYUnits() void SpeedGraph::setUnits(enum Units units) { _units = units; + setXUnits(); setYUnits(); + setInfo(); - clearInfo(); - addInfo(); + redraw(); } diff --git a/src/speedgraph.h b/src/speedgraph.h index 0827fb19..458f4e20 100644 --- a/src/speedgraph.h +++ b/src/speedgraph.h @@ -23,7 +23,7 @@ private: qreal max() const {return bounds().bottom();} void setXUnits(); void setYUnits(); - void addInfo(); + void setInfo(); QList _avg; enum Units _units; diff --git a/src/temperaturegraph.cpp b/src/temperaturegraph.cpp index 3c894cab..25cf9dd4 100644 --- a/src/temperaturegraph.cpp +++ b/src/temperaturegraph.cpp @@ -13,7 +13,7 @@ TemperatureGraph::TemperatureGraph(QWidget *parent) : GraphTab(parent) setSliderPrecision(1); } -void TemperatureGraph::addInfo() +void TemperatureGraph::setInfo() { GraphView::addInfo(tr("Average"), QString::number(avg() * yScale() + yOffset(), 'f', 1) + UNIT_SPACE + yUnits()); @@ -21,8 +21,6 @@ void TemperatureGraph::addInfo() + yOffset(), 'f', 1) + UNIT_SPACE + yUnits()); GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale() + yOffset(), 'f', 1) + UNIT_SPACE + yUnits()); - - redraw(); } void TemperatureGraph::loadGPX(const GPX &gpx) @@ -46,8 +44,13 @@ void TemperatureGraph::loadGPX(const GPX &gpx) loadData(data); } + for (int i = 0; i < gpx.routeCount(); i++) + skipColor(); + setXUnits(); - addInfo(); + setInfo(); + + redraw(); } qreal TemperatureGraph::avg() const @@ -107,9 +110,10 @@ void TemperatureGraph::setYUnits() void TemperatureGraph::setUnits(enum Units units) { _units = units; + setXUnits(); setYUnits(); + setInfo(); - clearInfo(); - addInfo(); + redraw(); } diff --git a/src/temperaturegraph.h b/src/temperaturegraph.h index 4838f8e8..166e9869 100644 --- a/src/temperaturegraph.h +++ b/src/temperaturegraph.h @@ -23,7 +23,7 @@ private: qreal max() const {return bounds().bottom();} void setXUnits(); void setYUnits(); - void addInfo(); + void setInfo(); QList _avg; enum Units _units; diff --git a/src/track.h b/src/track.h index b8d09f18..dea99b12 100644 --- a/src/track.h +++ b/src/track.h @@ -24,7 +24,6 @@ public: private: const QVector &_data; QVector _dd; - qreal _distance; }; #endif // TRACK_H diff --git a/src/trackitem.cpp b/src/trackitem.cpp index d0df08db..bcf41139 100644 --- a/src/trackitem.cpp +++ b/src/trackitem.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include "ll.h" #include "misc.h" #include "tooltip.h" @@ -28,23 +28,22 @@ void TrackItem::updateShape() { QPainterPathStroker s; s.setWidth(TRACK_WIDTH * 1.0/scale()); - _shape = s.createStroke(path().simplified()); + _shape = s.createStroke(_path.simplified()); } TrackItem::TrackItem(const Track &track, QGraphicsItem *parent) - : QGraphicsPathItem(parent) + : QGraphicsItem(parent) { QVector t; - QPainterPath path; track.track(t); Q_ASSERT(t.count() >= 2); const QPointF &p = t.at(0); - path.moveTo(ll2mercator(QPointF(p.x(), -p.y()))); + _path.moveTo(ll2mercator(QPointF(p.x(), -p.y()))); for (int i = 1; i < t.size(); i++) { const QPointF &p = t.at(i); - path.lineTo(ll2mercator(QPointF(p.x(), -p.y()))); + _path.lineTo(ll2mercator(QPointF(p.x(), -p.y()))); } _units = Metric; @@ -52,32 +51,48 @@ TrackItem::TrackItem(const Track &track, QGraphicsItem *parent) _distance = track.distance(); _time = track.time(); - setPath(path); setToolTip(toolTip()); setCursor(Qt::ArrowCursor); updateShape(); QBrush brush(Qt::SolidPattern); - QPen pen(brush, TRACK_WIDTH); - setPen(pen); + _pen = QPen(brush, TRACK_WIDTH); + + _marker = new MarkerItem(this); + _marker->setPos(_path.pointAtPercent(0)); +} + +void TrackItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, + QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + painter->setPen(_pen); + painter->drawPath(_path); + +/* + painter->setPen(Qt::red); + painter->drawRect(boundingRect()); +*/ } void TrackItem::setScale(qreal scale) { - QGraphicsPathItem::setScale(scale); - updateShape(); + prepareGeometryChange(); - QPen p(pen()); - p.setWidthF(TRACK_WIDTH * 1.0/scale); - setPen(p); + _pen.setWidthF(TRACK_WIDTH * 1.0/scale); + QGraphicsItem::setScale(scale); + _marker->setScale(1.0/scale); + + updateShape(); } void TrackItem::setColor(const QColor &color) { - QPen p(pen()); - p.setColor(color); - setPen(p); + _pen.setColor(color); + update(); } void TrackItem::setUnits(enum Units units) @@ -85,3 +100,9 @@ void TrackItem::setUnits(enum Units units) _units = units; setToolTip(toolTip()); } + +void TrackItem::moveMarker(qreal t) +{ + Q_ASSERT(t >= 0 && t <= 1.0); + _marker->setPos(_path.pointAtPercent(t)); +} diff --git a/src/trackitem.h b/src/trackitem.h index aa759275..8d59570d 100644 --- a/src/trackitem.h +++ b/src/trackitem.h @@ -1,27 +1,41 @@ #ifndef TRACKITEM_H #define TRACKITEM_H -#include +#include #include #include "units.h" #include "track.h" +#include "markeritem.h" -class TrackItem : public QGraphicsPathItem + +class TrackItem : public QGraphicsItem { public: TrackItem(const Track &track, QGraphicsItem *parent = 0); QPainterPath shape() const {return _shape;} - void setScale(qreal scale); + QRectF boundingRect() const {return _shape.boundingRect();} + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, + QWidget *widget); + const QPainterPath &path() const {return _path;} + + void setScale(qreal scale); void setUnits(enum Units units); void setColor(const QColor &color); + void showMarker(bool show) {_marker->setVisible(show);} + void moveMarker(qreal t); + private: void updateShape(); QString toolTip(); + QPainterPath _path; QPainterPath _shape; + QPen _pen; + + MarkerItem *_marker; Units _units; QDateTime _date; diff --git a/src/trackview.cpp b/src/trackview.cpp index 9964433e..e421668d 100644 --- a/src/trackview.cpp +++ b/src/trackview.cpp @@ -7,8 +7,8 @@ #include "gpx.h" #include "map.h" #include "trackitem.h" +#include "routeitem.h" #include "waypointitem.h" -#include "markeritem.h" #include "scaleitem.h" #include "trackview.h" @@ -37,9 +37,16 @@ TrackView::TrackView(QWidget *parent) _maxPath = 0; _maxDistance = 0; - _plot = false; _units = Metric; - _overlap = true; + + _showTracks = true; + _showRoutes = true; + _showWaypoints = true; + _showWaypointLabels = true; + _showPOILabels = true; + _overlapPOIs = true; + + _plot = false; } TrackView::~TrackView() @@ -55,23 +62,39 @@ void TrackView::addTrack(const Track &track) return; } - TrackItem *pi = new TrackItem(track); - _paths.append(pi); + TrackItem *ti = new TrackItem(track); + _tracks.append(ti); _zoom = qMin(_zoom, scale2zoom(trackScale())); _scale = mapScale(_zoom); - pi->setScale(1.0/_scale); - pi->setColor(_palette.color()); - _scene->addItem(pi); + ti->setScale(1.0/_scale); + ti->setColor(_palette.color()); + ti->setVisible(_showTracks); + _scene->addItem(ti); - MarkerItem *mi = new MarkerItem(pi); - _markers.append(mi); - mi->setPos(pi->path().pointAtPercent(0)); - mi->setScale(_scale); - - _maxPath = qMax(pi->path().length(), _maxPath); + _maxPath = qMax(ti->path().length(), _maxPath); _maxDistance = qMax(track.distance(), _maxDistance); } +void TrackView::addRoute(const Route &route) +{ + if (route.isNull()) { + _palette.color(); + return; + } + + RouteItem *ri = new RouteItem(route); + _routes.append(ri); + _zoom = qMin(_zoom, scale2zoom(routeScale())); + _scale = mapScale(_zoom); + ri->setScale(1.0/_scale); + ri->setColor(_palette.color()); + ri->setVisible(_showRoutes); + _scene->addItem(ri); + + _maxPath = qMax(ri->path().length(), _maxPath); + _maxDistance = qMax(route.distance(), _maxDistance); +} + void TrackView::addWaypoints(const QList &waypoints) { for (int i = 0; i < waypoints.count(); i++) { @@ -80,6 +103,8 @@ void TrackView::addWaypoints(const QList &waypoints) WaypointItem *wi = new WaypointItem(w); wi->setScale(1.0/_scale); wi->setZValue(1); + wi->showLabel(_showWaypointLabels); + wi->setVisible(_showWaypoints); _scene->addItem(wi); _waypoints.append(wi); @@ -95,16 +120,19 @@ void TrackView::loadGPX(const GPX &gpx) for (int i = 0; i < gpx.trackCount(); i++) addTrack(gpx.track(i)); + for (int i = 0; i < gpx.routeCount(); i++) + addRoute(gpx.route(i)); addWaypoints(gpx.waypoints()); - if (_paths.empty() && _waypoints.empty()) + if (_tracks.empty() && _routes.empty() && _waypoints.empty()) return; - if ((_paths.size() > 1 && _zoom < zoom) + if ((_tracks.size() > 1 && _zoom < zoom) || (_waypoints.size() && _zoom < zoom)) rescale(_scale); - QRectF br = trackBoundingRect() | waypointBoundingRect(); + QRectF br = trackBoundingRect() | routeBoundingRect() + | waypointBoundingRect(); QRectF ba = br.adjusted(-TILE_SIZE, -TILE_SIZE, TILE_SIZE, TILE_SIZE); _scene->setSceneRect(ba); centerOn(ba.center()); @@ -117,12 +145,24 @@ void TrackView::loadGPX(const GPX &gpx) QRectF TrackView::trackBoundingRect() const { - if (_paths.empty()) + if (_tracks.empty()) return QRectF(); - QRectF br = _paths.at(0)->sceneBoundingRect(); - for (int i = 1; i < _paths.size(); i++) - br |= _paths.at(i)->sceneBoundingRect(); + QRectF br = _tracks.at(0)->sceneBoundingRect(); + for (int i = 1; i < _tracks.size(); i++) + br |= _tracks.at(i)->sceneBoundingRect(); + + return br; +} + +QRectF TrackView::routeBoundingRect() const +{ + if (_routes.empty()) + return QRectF(); + + QRectF br = _routes.at(0)->sceneBoundingRect(); + for (int i = 1; i < _routes.size(); i++) + br |= _routes.at(i)->sceneBoundingRect(); return br; } @@ -153,13 +193,29 @@ QRectF TrackView::waypointBoundingRect() const qreal TrackView::trackScale() const { - if (_paths.empty()) + if (_tracks.empty()) return mapScale(ZOOM_MAX); - QRectF br = _paths.at(0)->path().boundingRect(); + QRectF br = _tracks.at(0)->path().boundingRect(); - for (int i = 1; i < _paths.size(); i++) - br |= _paths.at(i)->path().boundingRect(); + for (int i = 1; i < _tracks.size(); i++) + br |= _tracks.at(i)->path().boundingRect(); + + QPointF sc(br.width() / (viewport()->width() - MARGIN/2), + br.height() / (viewport()->height() - MARGIN/2)); + + return qMax(sc.x(), sc.y()); +} + +qreal TrackView::routeScale() const +{ + if (_routes.empty()) + return mapScale(ZOOM_MAX); + + QRectF br = _routes.at(0)->path().boundingRect(); + + for (int i = 1; i < _routes.size(); i++) + br |= _routes.at(i)->path().boundingRect(); QPointF sc(br.width() / (viewport()->width() - MARGIN/2), br.height() / (viewport()->height() - MARGIN/2)); @@ -215,10 +271,11 @@ void TrackView::checkPOIOverlap() void TrackView::rescale(qreal scale) { - for (int i = 0; i < _paths.size(); i++) { - _markers.at(i)->setScale(scale); - _paths.at(i)->setScale(1.0/scale); - } + for (int i = 0; i < _tracks.size(); i++) + _tracks.at(i)->setScale(1.0/scale); + + for (int i = 0; i < _routes.size(); i++) + _routes.at(i)->setScale(1.0/scale); for (int i = 0; i < _waypoints.size(); i++) _waypoints.at(i)->setScale(1.0/scale); @@ -229,7 +286,7 @@ void TrackView::rescale(qreal scale) it.value()->show(); } - if (!_overlap) + if (!_overlapPOIs) checkPOIOverlap(); _scale = scale; @@ -246,6 +303,7 @@ void TrackView::addPOI(const QVector &waypoints) WaypointItem *pi = new WaypointItem(w); pi->setScale(1.0/_scale); pi->setZValue(1); + pi->showLabel(_showPOILabels); _scene->addItem(pi); _pois.insert(w, pi); @@ -254,14 +312,16 @@ void TrackView::addPOI(const QVector &waypoints) void TrackView::loadPOI(const POI &poi) { - if (!_paths.size() && !_waypoints.size()) + if (!_tracks.size() && !_routes.size() && !_waypoints.size()) return; - for (int i = 0; i < _paths.size(); i++) - addPOI(poi.points(_paths.at(i)->path())); + for (int i = 0; i < _tracks.size(); i++) + addPOI(poi.points(_tracks.at(i)->path())); + for (int i = 0; i < _routes.size(); i++) + addPOI(poi.points(_routes.at(i)->path())); addPOI(poi.points(_waypoints)); - if (!_overlap) + if (!_overlapPOIs) checkPOIOverlap(); } @@ -280,8 +340,8 @@ void TrackView::setUnits(enum Units units) _mapScale->setUnits(units); - for (int i = 0; i < _paths.count(); i++) - _paths[i]->setUnits(units); + for (int i = 0; i < _tracks.count(); i++) + _tracks[i]->setUnits(units); for (int i = 0; i < _waypoints.size(); i++) _waypoints.at(i)->setUnits(units); @@ -298,21 +358,24 @@ void TrackView::redraw() void TrackView::rescale() { - _zoom = qMin(scale2zoom(trackScale()), scale2zoom(waypointScale())); + _zoom = qMin(qMin(scale2zoom(trackScale()), scale2zoom(routeScale())), + scale2zoom(waypointScale())); + rescale(mapScale(_zoom)); _mapScale->setZoom(_zoom); } void TrackView::zoom(int z, const QPointF &pos) { - if (_paths.isEmpty() && _waypoints.isEmpty()) + if (_tracks.isEmpty() && _routes.isEmpty() && _waypoints.isEmpty()) return; qreal scale = _scale; _zoom = z; rescale(mapScale(_zoom)); - QRectF br = trackBoundingRect() | waypointBoundingRect(); + QRectF br = trackBoundingRect() | routeBoundingRect() + | waypointBoundingRect(); QRectF ba = br.adjusted(-TILE_SIZE, -TILE_SIZE, TILE_SIZE, TILE_SIZE); _scene->setSceneRect(ba); @@ -329,7 +392,7 @@ void TrackView::zoom(int z, const QPointF &pos) void TrackView::wheelEvent(QWheelEvent *event) { - if (_paths.isEmpty() && _waypoints.isEmpty()) + if (_tracks.isEmpty() && _routes.isEmpty() && _waypoints.isEmpty()) return; QPointF pos = mapToScene(event->pos()); @@ -406,9 +469,9 @@ void TrackView::clear() _scene->removeItem(_mapScale); _pois.clear(); - _paths.clear(); + _tracks.clear(); + _routes.clear(); _waypoints.clear(); - _markers.clear(); _scene->clear(); _palette.reset(); @@ -424,23 +487,75 @@ void TrackView::movePositionMarker(qreal val) { qreal mp = val / _maxDistance; - for (int i = 0; i < _paths.size(); i++) { - qreal f = _maxPath / _paths.at(i)->path().length(); + for (int i = 0; i < _tracks.size(); i++) { + qreal f = _maxPath / _tracks.at(i)->path().length(); if (mp * f < 0 || mp * f > 1.0) - _markers.at(i)->setVisible(false); + _tracks.at(i)->showMarker(false); else { - QPointF pos = _paths.at(i)->path().pointAtPercent(mp * f); - _markers.at(i)->setPos(pos); - _markers.at(i)->setVisible(true); + _tracks.at(i)->moveMarker(mp * f); + _tracks.at(i)->showMarker(true); + } + } + + for (int i = 0; i < _routes.size(); i++) { + qreal f = _maxPath / _routes.at(i)->path().length(); + if (mp * f < 0 || mp * f > 1.0) + _routes.at(i)->showMarker(false); + else { + _routes.at(i)->moveMarker(mp * f); + _routes.at(i)->showMarker(true); } } } +void TrackView::showTracks(bool show) +{ + _showTracks = show; + + for (int i = 0; i < _tracks.count(); i++) + _tracks.at(i)->setVisible(show); +} + +void TrackView::showRoutes(bool show) +{ + _showRoutes = show; + + for (int i = 0; i < _routes.count(); i++) + _routes.at(i)->setVisible(show); +} + +void TrackView::showWaypoints(bool show) +{ + _showWaypoints = show; + + for (int i = 0; i < _waypoints.count(); i++) + _waypoints.at(i)->setVisible(show); +} + +void TrackView::showWaypointLabels(bool show) +{ + _showWaypointLabels = show; + + for (int i = 0; i < _waypoints.size(); i++) + _waypoints.at(i)->showLabel(show); +} + +void TrackView::showPOILabels(bool show) +{ + _showPOILabels = show; + + QHash::const_iterator it; + for (it = _pois.constBegin(); it != _pois.constEnd(); it++) + it.value()->showLabel(show); + + setPOIOverlap(_overlapPOIs); +} + void TrackView::setPOIOverlap(bool overlap) { - _overlap = overlap; + _overlapPOIs = overlap; - if (_overlap) { + if (_overlapPOIs) { QHash::const_iterator it; for (it = _pois.constBegin(); it != _pois.constEnd(); it++) it.value()->show(); @@ -450,7 +565,8 @@ void TrackView::setPOIOverlap(bool overlap) void TrackView::drawBackground(QPainter *painter, const QRectF &rect) { - if ((_paths.isEmpty() && _waypoints.isEmpty()) || !_map) { + if ((_tracks.isEmpty() && _routes.isEmpty() && _waypoints.isEmpty()) + || !_map) { painter->fillRect(rect, Qt::white); return; } @@ -481,12 +597,13 @@ void TrackView::drawBackground(QPainter *painter, const QRectF &rect) void TrackView::resizeEvent(QResizeEvent *e) { - if (_paths.isEmpty() && _waypoints.isEmpty()) + if (_tracks.isEmpty() && _routes.isEmpty() && _waypoints.isEmpty()) return; rescale(); - QRectF br = trackBoundingRect() | waypointBoundingRect(); + QRectF br = trackBoundingRect() | routeBoundingRect() + | waypointBoundingRect(); QRectF ba = br.adjusted(-TILE_SIZE, -TILE_SIZE, TILE_SIZE, TILE_SIZE); if (ba.width() < e->size().width()) { diff --git a/src/trackview.h b/src/trackview.h index f5278ed1..2eeabff0 100644 --- a/src/trackview.h +++ b/src/trackview.h @@ -13,9 +13,10 @@ class GPX; class POI; class Map; class Track; +class Route; class TrackItem; +class RouteItem; class WaypointItem; -class MarkerItem; class ScaleItem; class TrackView : public QGraphicsView @@ -34,25 +35,35 @@ public: void setMap(Map *map); void setUnits(enum Units units); - void setPOIOverlap(bool overlap); void plot(QPainter *painter, const QRectF &target); - int trackCount() const {return _paths.count();} + int trackCount() const {return _tracks.count();} + int routeCount() const {return _routes.count();} int waypointCount() const {return _waypoints.count();} public slots: void movePositionMarker(qreal val); void redraw(); + void setPOIOverlap(bool overlap); + void showWaypointLabels(bool show); + void showPOILabels(bool show); + void showTracks(bool show); + void showRoutes(bool show); + void showWaypoints(bool show); + private: void addTrack(const Track &track); + void addRoute(const Route &route); void addWaypoints(const QList &waypoints); void addPOI(const QVector &waypoints); QRectF trackBoundingRect() const; + QRectF routeBoundingRect() const; QRectF waypointBoundingRect() const; qreal trackScale() const; + qreal routeScale() const; qreal waypointScale() const; qreal mapScale(int zoom) const; void rescale(qreal scale); @@ -67,8 +78,8 @@ private: void paintEvent(QPaintEvent *e); QGraphicsScene *_scene; - QList _paths; - QList _markers; + QList _tracks; + QList _routes; QList _waypoints; QHash _pois; @@ -82,7 +93,14 @@ private: int _zoom; Units _units; - bool _overlap; + + bool _showTracks; + bool _showRoutes; + bool _showWaypoints; + bool _showWaypointLabels; + bool _showPOILabels; + bool _overlapPOIs; + bool _plot; }; diff --git a/src/waypoint.h b/src/waypoint.h index cae61c69..561ed0eb 100644 --- a/src/waypoint.h +++ b/src/waypoint.h @@ -31,6 +31,8 @@ public: void setElevation(qreal elevation) {_elevation = elevation;} void setGeoidHeight(qreal geoidHeight) {_geoidHeight = geoidHeight;} + bool hasElevation() const {return !std::isnan(_elevation);} + bool operator==(const Waypoint &other) const {return this->_name == other._name && this->_coordinates == other._coordinates;} diff --git a/src/waypointitem.cpp b/src/waypointitem.cpp index 7346da59..ddb5369b 100644 --- a/src/waypointitem.cpp +++ b/src/waypointitem.cpp @@ -13,6 +13,8 @@ QString WaypointItem::toolTip() { ToolTip tt; + if (!_waypoint.name().isEmpty() && !_showLabel) + tt.insert(qApp->translate("WaypointItem", "Name"), _waypoint.name()); tt.insert(qApp->translate("WaypointItem", "Coordinates"), ::coordinates(_waypoint.coordinates())); if (!std::isnan(_waypoint.elevation())) @@ -32,6 +34,7 @@ WaypointItem::WaypointItem(const Waypoint &waypoint, QGraphicsItem *parent) : QGraphicsItem(parent) { _units = Metric; + _showLabel = true; _waypoint = waypoint; _coordinates = ll2mercator(QPointF(waypoint.coordinates().x(), @@ -46,14 +49,18 @@ WaypointItem::WaypointItem(const Waypoint &waypoint, QGraphicsItem *parent) void WaypointItem::updateBoundingRect() { - QFont font; - font.setPixelSize(FONT_SIZE); - font.setFamily(FONT_FAMILY); - QFontMetrics fm(font); - QRect ts = fm.tightBoundingRect(_waypoint.name()); + if (_showLabel) { + QFont font; + font.setPixelSize(FONT_SIZE); + font.setFamily(FONT_FAMILY); + QFontMetrics fm(font); + QRect ts = fm.tightBoundingRect(_waypoint.name()); - _boundingRect = QRectF(-POINT_SIZE/2, -POINT_SIZE/2, ts.width() - + POINT_SIZE, ts.height() + fm.descent() + POINT_SIZE); + _boundingRect = QRectF(-POINT_SIZE/2, -POINT_SIZE/2, ts.width() + + POINT_SIZE, ts.height() + fm.descent() + POINT_SIZE); + } else + _boundingRect = QRectF(-POINT_SIZE/2, -POINT_SIZE/2, POINT_SIZE, + POINT_SIZE); } void WaypointItem::paint(QPainter *painter, @@ -61,15 +68,19 @@ void WaypointItem::paint(QPainter *painter, { Q_UNUSED(option); Q_UNUSED(widget); - QFont font; - font.setPixelSize(FONT_SIZE); - font.setFamily(FONT_FAMILY); - QFontMetrics fm(font); - QRect ts = fm.tightBoundingRect(_waypoint.name()); - painter->setFont(font); - painter->drawText(POINT_SIZE/2 - qMax(ts.x(), 0), POINT_SIZE/2 + ts.height(), - _waypoint.name()); + if (_showLabel) { + QFont font; + font.setPixelSize(FONT_SIZE); + font.setFamily(FONT_FAMILY); + QFontMetrics fm(font); + QRect ts = fm.tightBoundingRect(_waypoint.name()); + + painter->setFont(font); + painter->drawText(POINT_SIZE/2 - qMax(ts.x(), 0), POINT_SIZE/2 + + ts.height(), _waypoint.name()); + } + painter->setBrush(Qt::SolidPattern); painter->drawEllipse(-POINT_SIZE/2, -POINT_SIZE/2, POINT_SIZE, POINT_SIZE); @@ -90,3 +101,11 @@ void WaypointItem::setUnits(enum Units units) _units = units; setToolTip(toolTip()); } + +void WaypointItem::showLabel(bool show) +{ + prepareGeometryChange(); + _showLabel = show; + updateBoundingRect(); + setToolTip(toolTip()); +} diff --git a/src/waypointitem.h b/src/waypointitem.h index d09dc9e2..deb2361f 100644 --- a/src/waypointitem.h +++ b/src/waypointitem.h @@ -15,6 +15,7 @@ public: void setUnits(enum Units units); void setScale(qreal scale); + void showLabel(bool show); QRectF boundingRect() const {return _boundingRect;} void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, @@ -28,6 +29,7 @@ private: QPointF _coordinates; Waypoint _waypoint; Units _units; + bool _showLabel; }; #endif // WAYPOINTITEM_H