1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2025-07-06 15:42:51 +02:00

Compare commits

..

77 Commits
7.2 ... 7.3

Author SHA1 Message Date
fc8fda7a82 Merge branch 'origin/master' into Weblate. 2019-02-18 22:53:00 +01:00
18392db8f0 Invalidate the coordinates on map change under cursor 2019-02-18 22:51:38 +01:00
4aa1f7a557 Merge branch 'origin/master' into Weblate. 2019-02-18 22:37:33 +01:00
bb71cfc426 Fixed "display map coordinates" issues 2019-02-18 22:36:45 +01:00
8807c37770 Properly save/restore window layout + fullscreen switch normalization
Fixes #183
2019-02-18 22:33:18 +01:00
e2eec179d5 Translated using Weblate (Turkish)
Currently translated at 100.0% (338 of 338 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/tr/
2019-02-18 13:31:24 +01:00
1f5922685b Translated using Weblate (Czech)
Currently translated at 100.0% (338 of 338 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/cs/
2019-02-17 23:12:45 +01:00
dc70af3f3c Translated using Weblate (German)
Currently translated at 100.0% (338 of 338 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/de/
2019-02-17 23:12:45 +01:00
e499574a50 Merge branch 'origin/master' into Weblate. 2019-02-17 22:19:08 +01:00
5840e6832f Translated using Weblate (Swedish)
Currently translated at 100.0% (338 of 338 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/sv/
2019-02-17 22:19:07 +01:00
463ac2d243 Translated using Weblate (Russian)
Currently translated at 100.0% (338 of 338 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/ru/
2019-02-17 22:19:07 +01:00
481138ec6e Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (338 of 338 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/pt_BR/
2019-02-17 22:19:07 +01:00
a320231dff Translated using Weblate (Norwegian Bokmål)
Currently translated at 91.4% (309 of 338 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/nb_NO/
2019-02-17 22:19:06 +01:00
a7ab72c564 Translated using Weblate (Finnish)
Currently translated at 100.0% (338 of 338 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/fi/
2019-02-17 22:19:06 +01:00
7f7d7a916a Display the coordinates always in black like the scale 2019-02-17 22:18:16 +01:00
a9ddd4d20f Merge branch 'origin/master' into Weblate. 2019-02-17 20:28:20 +01:00
2e036279bb Translations update 2019-02-17 20:28:17 +01:00
dea135d9df Merge branch 'origin/master' into Weblate. 2019-02-17 20:21:07 +01:00
12f3c252bb Added the "show cursor coordinates" option
Closes #167
2019-02-17 20:20:20 +01:00
a1ef211d0f Merge branch 'origin/master' into Weblate. 2019-02-17 15:33:54 +01:00
3d0c36b459 Added missing GPX TrackPointExtension cadence and speed values fetching 2019-02-17 15:32:39 +01:00
eb2af0fb5c Merge branch 'origin/master' into Weblate. 2019-02-17 15:19:34 +01:00
2da8efd497 Translated using Weblate (Russian)
Currently translated at 100.0% (337 of 337 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/ru/
2019-02-17 15:19:34 +01:00
c0e55ec25c Translated using Weblate (Finnish)
Currently translated at 100.0% (337 of 337 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/fi/
2019-02-17 15:19:33 +01:00
a2b8cec3be CZ & DE translations update 2019-02-17 15:19:12 +01:00
064928f844 Translated using Weblate (Russian)
Currently translated at 99.7% (336 of 337 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/ru/
2019-02-17 11:15:51 +01:00
693cce4da3 Translated using Weblate (Russian)
Currently translated at 99.7% (336 of 337 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/ru/
2019-02-17 09:51:50 +01:00
a7570faed7 Translated using Weblate (Finnish)
Currently translated at 99.7% (336 of 337 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/fi/
2019-02-17 09:51:48 +01:00
4ccb57ffd7 Translated using Weblate (Russian)
Currently translated at 98.5% (332 of 337 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/ru/
2019-02-17 09:06:43 +01:00
cece8002e2 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (337 of 337 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/pt_BR/
2019-02-17 09:06:42 +01:00
451c0c757f Translated using Weblate (Finnish)
Currently translated at 98.5% (332 of 337 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/fi/
2019-02-17 09:06:42 +01:00
e13bded88f pt_BR translations update 2019-02-16 19:56:04 +01:00
9887151bfd Enabled pt_BR localization 2019-02-16 19:54:50 +01:00
b535ed239b Translated using Weblate (Turkish)
Currently translated at 100.0% (337 of 337 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/tr/
2019-02-16 19:48:43 +01:00
9f43594abd Translated using Weblate (Swedish)
Currently translated at 100.0% (337 of 337 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/sv/
2019-02-16 19:48:43 +01:00
87cbd7bdb1 Translated using Weblate (Spanish)
Currently translated at 74.2% (250 of 337 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/es/
2019-02-16 19:48:42 +01:00
d49420e88d Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.4% (334 of 336 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/pt_BR/
2019-02-16 19:48:41 +01:00
d9d8588d8d Translated using Weblate (Norwegian Bokmål)
Currently translated at 91.4% (308 of 337 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/nb_NO/
2019-02-16 19:48:31 +01:00
a0eacedf3a Merge branch 'origin/master' into Weblate. 2019-02-16 12:41:10 +01:00
e04179e63e Translated using Weblate (Portuguese (Brazil))
Currently translated at 3.0% (10 of 336 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/pt_BR/
2019-02-16 12:41:09 +01:00
79ecc565eb Translation sources update 2019-02-16 12:41:03 +01:00
aaf8c12084 Added the "Show map markers" setting. 2019-02-16 12:39:23 +01:00
4ab4ff9bf1 Removed obsolete code 2019-02-16 09:58:57 +01:00
d5367ccf34 Enable border-less areas 2019-02-16 09:57:47 +01:00
54d0eea43e Removed obsolete translations 2019-02-16 09:04:44 +01:00
6543de4ca3 Updated German translation 2019-02-16 09:02:17 +01:00
b06ce107af Merge branch 'origin/master' into Weblate. 2019-02-16 08:15:38 +01:00
47c408703f Added pt-BR translation stub 2019-02-16 08:15:16 +01:00
3033ce2d6c Merge branch 'origin/master' into Weblate. 2019-02-15 20:33:16 +01:00
1444a88ad0 Enable empty WMTS styles 2019-02-15 20:32:53 +01:00
ec9d81c65a Added support for oblique stereographic projections 2019-02-15 20:32:13 +01:00
a777008fe4 Translated using Weblate (Turkish)
Currently translated at 97.3% (329 of 338 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/tr/
2019-02-13 18:10:27 +01:00
a73c96996d Merge branch 'origin/master' into Weblate. 2019-02-13 00:59:37 +01:00
d168fd8cd5 Fixed typo 2019-02-13 00:59:26 +01:00
a8df2f68d1 Merge branch 'origin/master' into Weblate. 2019-02-13 00:56:45 +01:00
be07640634 Czech translation update 2019-02-13 00:56:25 +01:00
9924702ba7 Merge branch 'origin/master' into Weblate. 2019-02-13 00:49:11 +01:00
6ee2322033 Translations update 2019-02-13 00:49:00 +01:00
08f2d4e4d2 Merge branch 'origin/master' into Weblate. 2019-02-13 00:47:48 +01:00
69d635be10 Moved the area appearance controls to the paths tab + layout polishing 2019-02-13 00:45:59 +01:00
a6b327f773 Code cleanup 2019-02-13 00:45:34 +01:00
143f53fbd9 Only ignore invalid segments, do not invalidate the whole track 2019-02-13 00:33:00 +01:00
5432a835f9 Merge branch 'origin/master' into Weblate. 2019-02-12 00:20:59 +01:00
cd74b0d43e Fixed broken distance re-computation 2019-02-12 00:20:39 +01:00
94374e748b Merge branch 'origin/master' into Weblate. 2019-02-11 23:55:00 +01:00
a882d1fe68 Fixed exchanged min/max graph info 2019-02-11 23:53:10 +01:00
4a8be940a1 Merge branch 'origin/master' into Weblate. 2019-02-11 23:29:57 +01:00
f379da61e3 Version++ 2019-02-11 23:29:45 +01:00
9f1b697bcf Merge branch 'origin/master' into Weblate. 2019-02-11 23:28:30 +01:00
0308dbbb09 Added support for track segments 2019-02-11 23:28:08 +01:00
516ca53ff0 Translated using Weblate (Finnish)
Currently translated at 100.0% (329 of 329 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/fi/
2019-02-05 19:39:55 +01:00
3c112b0b6f Unify OS X platform name 2019-02-04 22:33:34 +01:00
54f24880cf Fixed Windows build 2019-02-03 16:34:33 +01:00
67168b8063 Added support for GPX area extensions 2019-02-01 00:26:27 +01:00
4854bff31b Fixed KML Polygons loading 2019-02-01 00:25:41 +01:00
50306ecb84 Added support for polygon objects 2019-01-31 01:46:53 +01:00
91e633e9fa Added GeoJSON and DEM files info. 2019-01-28 23:02:33 +01:00
104 changed files with 7587 additions and 3873 deletions

View File

@ -1,4 +1,4 @@
version: 7.2.{build}
version: 7.3.{build}
configuration: Release
platform: Any CPU
environment:

View File

@ -1,18 +1,18 @@
# GPXSee
GPXSee is a Qt-based GPS log file viewer and analyzer that supports GPX, TCX,
KML, FIT, IGC, NMEA, SLF, LOC and OziExplorer files.
GPXSee is a Qt-based GPS log file viewer and analyzer that supports all common GPS log file formats.
## Features
* Opens GPX, TCX, FIT, KML, IGC, NMEA, SLF, LOC, GeoJSON, OziExplorer (PLT, RTE, WPT) and Garmin CSV files.
* User-definable online maps (OpenStreetMap/Google tiles, WMTS, WMS, TMS).
* Offline maps (MBTiles, OziExplorer maps, TrekBuddy maps/atlases, Garmin JNX maps, GeoTIFF images).
* Elevation, speed, heart rate, cadence, power, temperature and gear ratio/shifts graphs.
* Support for DEM files (SRTM HGT).
* Support for multiple tracks in one view.
* Support for POI files.
* Print/export to PDF.
* Full-screen mode.
* HiDPI/Retina displays & maps support.
* Native GUI for Windows, Mac OS X and Linux.
* Opens GPX, TCX, FIT, KML, IGC, NMEA, SLF, LOC, OziExplorer (PLT, RTE, WPT) and Garmin CSV files.
![GPXSee - Linux](https://a.fsdn.com/con/app/proj/gpxsee/screenshots/linux2.png)

View File

@ -1,9 +1,9 @@
unix:!mac {
unix:!macx {
TARGET = gpxsee
} else {
TARGET = GPXSee
}
VERSION = 7.2
VERSION = 7.3
QT += core \
gui \
@ -82,6 +82,7 @@ HEADERS += src/common/config.h \
src/GUI/searchpointer.h \
src/GUI/mapview.h \
src/GUI/font.h \
src/GUI/areaitem.h \
src/map/projection.h \
src/map/ellipsoid.h \
src/map/datum.h \
@ -131,6 +132,7 @@ HEADERS += src/common/config.h \
src/map/image.h \
src/map/mbtilesmap.h \
src/map/osm.h \
src/map/polarstereographic.h \
src/data/graph.h \
src/data/poi.h \
src/data/waypoint.h \
@ -153,7 +155,10 @@ HEADERS += src/common/config.h \
src/data/locparser.h \
src/data/slfparser.h \
src/data/dem.h \
src/map/polarstereographic.h
src/data/polygon.h \
src/data/area.h \
src/map/obliquestereographic.h \
src/GUI/coordinatesitem.h
SOURCES += src/main.cpp \
src/common/coordinates.cpp \
src/common/rectc.cpp \
@ -203,6 +208,7 @@ SOURCES += src/main.cpp \
src/GUI/powergraphitem.cpp \
src/GUI/gearratiographitem.cpp \
src/GUI/mapview.cpp \
src/GUI/areaitem.cpp \
src/map/maplist.cpp \
src/map/onlinemap.cpp \
src/map/downloader.cpp \
@ -247,6 +253,8 @@ SOURCES += src/main.cpp \
src/map/image.cpp \
src/map/mbtilesmap.cpp \
src/map/osm.cpp \
src/map/polarstereographic.cpp \
src/map/rectd.cpp \
src/data/data.cpp \
src/data/poi.cpp \
src/data/track.cpp \
@ -263,8 +271,9 @@ SOURCES += src/main.cpp \
src/data/locparser.cpp \
src/data/slfparser.cpp \
src/data/dem.cpp \
src/map/polarstereographic.cpp \
src/map/rectd.cpp
src/data/polygon.cpp \
src/map/obliquestereographic.cpp \
src/GUI/coordinatesitem.cpp
greaterThan(QT_MAJOR_VERSION, 4) {
HEADERS += src/data/geojsonparser.h
@ -286,7 +295,8 @@ TRANSLATIONS = lang/gpxsee_en.ts \
lang/gpxsee_nb.ts \
lang/gpxsee_da.ts \
lang/gpxsee_tr.ts \
lang/gpxsee_es.ts
lang/gpxsee_es.ts \
lang/gpxsee_pt_BR.ts
macx {
ICON = icons/gpxsee.icns
@ -303,7 +313,8 @@ macx {
lang/gpxsee_nb.qm \
lang/gpxsee_da.qm \
lang/gpxsee_tr.qm \
lang/gpxsee_es.qm
lang/gpxsee_es.qm \
lang/gpxsee_pt_BR.qm
csv.path = Contents/Resources
csv.files = pkg/csv
maps.path = Contents/Resources
@ -338,7 +349,8 @@ win32 {
icons/formats/loc.ico \
icons/formats/slf.ico \
icons/formats/json.ico
DEFINES += _USE_MATH_DEFINES
DEFINES += _USE_MATH_DEFINES \
NOGDI
}
unix:!macx {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1835
lang/gpxsee_pt_BR.ts Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,7 @@ Montserrat 1958 / British West Indies Grid,2004,4604,19942,9001,9807,4400,8801,0
St. Kitts 1955 / British West Indies Grid,2005,4605,19942,9001,9807,4400,8801,0,9102,8802,-62,9102,8805,0.9995,9201,8806,400000,9001,8807,0,9001,,,,,,
St. Lucia 1955 / British West Indies Grid,2006,4606,19942,9001,9807,4400,8801,0,9102,8802,-62,9102,8805,0.9995,9201,8806,400000,9001,8807,0,9001,,,,,,
St. Vincent 45 / British West Indies Grid,2007,4607,19942,9001,9807,4400,8801,0,9102,8802,-62,9102,8805,0.9995,9201,8806,400000,9001,8807,0,9001,,,,,,
NAD83(CSRS98) / New Brunswick Stereo,2036,4140,19946,9001,9809,4500,8801,46.3,9110,8802,-66.3,9110,8805,0.999912,9201,8806,2500000,9001,8807,7500000,9001,,,,,,
NAD83(CSRS98) / UTM zone 19N,2037,4140,16019,9001,9807,4400,8801,0,9102,8802,-69,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
NAD83(CSRS98) / UTM zone 20N,2038,4140,16020,9001,9807,4400,8801,0,9102,8802,-63,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
Israel 1993 / Israeli TM Grid,2039,4141,18204,9001,9807,4400,8801,31.4403817,9110,8802,35.1216261,9110,8805,1.0000067,9201,8806,219529.584,9001,8807,626907.39,9001,,,,,,
@ -113,6 +114,10 @@ Pulkovo 1942(83) / Gauss Kruger zone 4,2167,4178,16264,9001,9807,4530,8801,0,910
Pulkovo 1942(83) / Gauss Kruger zone 5,2168,4178,16265,9001,9807,4530,8801,0,9102,8802,15,9102,8805,1,9201,8806,5500000,9001,8807,0,9001,,,,,,
Luxembourg 1930 / Gauss,2169,4181,19966,9001,9807,4530,8801,49.5,9110,8802,6.1,9110,8805,1,9201,8806,80000,9001,8807,100000,9001,,,,,,
MGI / Slovenia Grid,2170,4312,19967,9001,9807,4530,8801,0,9110,8802,15,9110,8805,0.9999,9201,8806,500000,9001,8807,0,9001,,,,,,
Pulkovo 1942(58) / Poland zone I,2171,4179,18281,9001,9809,4530,8801,50.373,9110,8802,21.05,9110,8805,0.9998,9201,8806,4637000,9001,8807,5647000,9001,,,,,,
Pulkovo 1942(58) / Poland zone II,2172,4179,18282,9001,9809,4530,8801,53.0007,9110,8802,21.301,9110,8805,0.9998,9201,8806,4603000,9001,8807,5806000,9001,,,,,,
Pulkovo 1942(58) / Poland zone III,2173,4179,18283,9001,9809,4530,8801,53.35,9110,8802,17.003,9110,8805,0.9998,9201,8806,3501000,9001,8807,5999000,9001,,,,,,
Pulkovo 1942(58) / Poland zone IV,2174,4179,18284,9001,9809,4530,8801,51.4015,9110,8802,16.402,9110,8805,0.9998,9201,8806,3703000,9001,8807,5627000,9001,,,,,,
Pulkovo 1942(58) / Poland zone V,2175,4179,18285,9001,9807,4530,8801,0,9110,8802,18.573,9110,8805,0.999983,9201,8806,237000,9001,8807,-4700000,9001,,,,,,
ETRS89 / Poland CS2000 zone 5,2176,4258,18305,9001,9807,4531,8801,0,9102,8802,15,9102,8805,0.999923,9201,8806,5500000,9001,8807,0,9001,,,,,,
ETRS89 / Poland CS2000 zone 6,2177,4258,18306,9001,9807,4531,8801,0,9102,8802,18,9102,8805,0.999923,9201,8806,6500000,9001,8807,0,9001,,,,,,
@ -215,6 +220,7 @@ NAD83 / Washington South (ftUS),2286,4269,15368,9003,9802,4497,8821,45.2,9110,88
NAD83 / Wisconsin North (ftUS),2287,4269,15369,9003,9802,4497,8821,45.1,9110,8822,-90,9110,8823,46.46,9110,8824,45.34,9110,8826,1968500,9003,8827,0,9003,,,
NAD83 / Wisconsin Central (ftUS),2288,4269,15370,9003,9802,4497,8821,43.5,9110,8822,-90,9110,8823,45.3,9110,8824,44.15,9110,8826,1968500,9003,8827,0,9003,,,
NAD83 / Wisconsin South (ftUS),2289,4269,15371,9003,9802,4497,8821,42,9110,8822,-90,9110,8823,44.04,9110,8824,42.44,9110,8826,1968500,9003,8827,0,9003,,,
NAD83(CSRS98) / Prince Edward Isl. Stereographic (NAD83),2292,4140,19960,9001,9809,4496,8801,47.15,9110,8802,-63,9110,8805,0.999912,9201,8806,400000,9001,8807,800000,9001,,,,,,
Batavia / TM 109 SE,2308,4211,16709,9001,9807,4400,8801,0,9102,8802,109,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
WGS 84 / TM 116 SE,2309,4326,16716,9001,9807,4400,8801,0,9102,8802,116,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
WGS 84 / TM 132 SE,2310,4326,16732,9001,9807,4400,8801,0,9102,8802,132,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
@ -793,6 +799,8 @@ NAD83(CSRS) / MTM zone 7,2949,4617,17707,9001,9807,4496,8801,0,9110,8802,-70.3,9
NAD83(CSRS) / MTM zone 8,2950,4617,17708,9001,9807,4496,8801,0,9110,8802,-73.3,9110,8805,0.9999,9201,8806,304800,9001,8807,0,9001,,,,,,
NAD83(CSRS) / MTM zone 9,2951,4617,17709,9001,9807,4496,8801,0,9110,8802,-76.3,9110,8805,0.9999,9201,8806,304800,9001,8807,0,9001,,,,,,
NAD83(CSRS) / MTM zone 10,2952,4617,17710,9001,9807,4496,8801,0,9110,8802,-79.3,9110,8805,0.9999,9201,8806,304800,9001,8807,0,9001,,,,,,
NAD83(CSRS) / New Brunswick Stereographic,2953,4617,19946,9001,9809,4500,8801,46.3,9110,8802,-66.3,9110,8805,0.999912,9201,8806,2500000,9001,8807,7500000,9001,,,,,,
NAD83(CSRS) / Prince Edward Isl. Stereographic (NAD83),2954,4617,19960,9001,9809,4496,8801,47.15,9110,8802,-63,9110,8805,0.999912,9201,8806,400000,9001,8807,800000,9001,,,,,,
NAD83(CSRS) / UTM zone 11N,2955,4617,16011,9001,9807,4400,8801,0,9102,8802,-117,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
NAD83(CSRS) / UTM zone 12N,2956,4617,16012,9001,9807,4400,8801,0,9102,8802,-111,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
NAD83(CSRS) / UTM zone 13N,2957,4617,16013,9001,9807,4400,8801,0,9102,8802,-105,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
@ -940,6 +948,7 @@ MAGNA-SIRGAS / Colombia Bogota zone,3116,4686,18057,9001,9807,4500,8801,4.354632
MAGNA-SIRGAS / Colombia East Central zone,3117,4686,18058,9001,9807,4500,8801,4.35463215,9110,8802,-71.04390285,9110,8805,1,9201,8806,1000000,9001,8807,1000000,9001,,,,,,
MAGNA-SIRGAS / Colombia East zone,3118,4686,18059,9001,9807,4500,8801,4.35463215,9110,8802,-68.04390285,9110,8805,1,9201,8806,1000000,9001,8807,1000000,9001,,,,,,
Douala 1948 / AEF west,3119,4192,18415,9001,9807,4400,8801,0,9110,8802,10.3,9110,8805,0.999,9201,8806,1000000,9001,8807,1000000,9001,,,,,,
Pulkovo 1942(58) / Poland zone I,3120,4179,18280,9001,9809,4530,8801,50.373,9110,8802,21.05,9110,8805,0.9998,9201,8806,4637000,9001,8807,5467000,9001,,,,,,
PRS92 / Philippines zone 1,3121,4683,18171,9001,9807,4499,8801,0,9102,8802,117,9102,8805,0.99995,9201,8806,500000,9001,8807,0,9001,,,,,,
PRS92 / Philippines zone 2,3122,4683,18172,9001,9807,4499,8801,0,9102,8802,119,9102,8805,0.99995,9201,8806,500000,9001,8807,0,9001,,,,,,
PRS92 / Philippines zone 3,3123,4683,18173,9001,9807,4499,8801,0,9102,8802,121,9102,8805,0.99995,9201,8806,500000,9001,8807,0,9001,,,,,,
@ -1127,6 +1136,7 @@ CSG67 / UTM zone 21N,3312,4623,16021,9001,9807,4400,8801,0,9102,8802,-57,9102,88
RGFG95 / UTM zone 21N,3313,4624,16021,9001,9807,4400,8801,0,9102,8802,-57,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
Katanga 1955 / Katanga Lambert,3314,4695,17401,9001,9802,4400,8821,0,9102,8822,26,9102,8823,-6.5,9102,8824,-11.5,9102,8826,0,9001,8827,0,9001,,,
Katanga 1955 / Katanga TM,3315,4695,17402,9001,9807,4400,8801,-9,9102,8802,26,9102,8805,0.9998,9201,8806,0,9001,8807,0,9001,,,,,,
Pulkovo 1942(58) / GUGiK-80,3328,4179,18286,9001,9809,4530,8801,52.1,9110,8802,19.1,9110,8805,0.999714,9201,8806,500000,9001,8807,500000,9001,,,,,,
Pulkovo 1942(58) / 3-degree Gauss-Kruger zone 5,3329,4179,16265,9001,9807,4530,8801,0,9102,8802,15,9102,8805,1,9201,8806,5500000,9001,8807,0,9001,,,,,,
Pulkovo 1942(58) / 3-degree Gauss-Kruger zone 6,3330,4179,16266,9001,9807,4530,8801,0,9102,8802,18,9102,8805,1,9201,8806,6500000,9001,8807,0,9001,,,,,,
Pulkovo 1942(58) / 3-degree Gauss-Kruger zone 7,3331,4179,16267,9001,9807,4530,8801,0,9102,8802,21,9102,8805,1,9201,8806,7500000,9001,8807,0,9001,,,,,,
@ -1585,6 +1595,7 @@ Pulkovo 1942(58) / 3-degree Gauss-Kruger zone 10,3840,4179,16270,9001,9807,4530,
Pulkovo 1942(83) / 3-degree Gauss-Kruger zone 6,3841,4178,16266,9001,9807,4530,8801,0,9102,8802,18,9102,8805,1,9201,8806,6500000,9001,8807,0,9001,,,,,,
Pulkovo 1942(83) / 3-degree Gauss-Kruger zone 7,3842,4178,16266,9001,9807,4530,8801,0,9102,8802,18,9102,8805,1,9201,8806,6500000,9001,8807,0,9001,,,,,,
Pulkovo 1942(83) / 3-degree Gauss-Kruger zone 8,3843,4178,16266,9001,9807,4530,8801,0,9102,8802,18,9102,8805,1,9201,8806,6500000,9001,8807,0,9001,,,,,,
Pulkovo 1942(58) / Stereo70,3844,4179,19926,9001,9809,4530,8801,46,9102,8802,25,9102,8805,0.99975,9201,8806,500000,9001,8807,500000,9001,,,,,,
SWEREF99 / RT90 7.5 gon V emulation,3845,4619,17339,9001,9807,4530,8801,0,9110,8802,11.18225,9110,8805,1.000006,9201,8806,1500025.141,9001,8807,-667.282,9001,,,,,,
SWEREF99 / RT90 5 gon V emulation,3846,4619,17340,9001,9807,4530,8801,0,9110,8802,13.332256,9110,8805,1.0000058,9201,8806,1500044.695,9001,8807,-667.13,9001,,,,,,
SWEREF99 / RT90 2.5 gon V emulation,3847,4619,17341,9001,9807,4530,8801,0,9110,8802,15.4822624306,9110,8805,1.00000561024,9201,8806,1500064.274,9001,8807,-667.711,9001,,,,,,
@ -2476,6 +2487,7 @@ Corrego Alegre 1970-72 / UTM zone 23S,22523,4225,16123,9001,9807,4400,8801,0,910
Corrego Alegre 1970-72 / UTM zone 24S,22524,4225,16124,9001,9807,4400,8801,0,9102,8802,-39,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
Corrego Alegre 1970-72 / UTM zone 25S,22525,4225,16125,9001,9807,4400,8801,0,9102,8802,-33,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
Deir ez Zor / Syria Lambert,22770,4227,19948,9001,9801,4499,8801,34.39,9110,8802,37.21,9110,8805,0.9996256,9201,8806,300000,9001,8807,300000,9001,,,,,,
Deir ez Zor / Levant Stereographic,22780,4227,19949,9001,9809,4499,8801,38,9105,8802,43.5,9105,8805,0.9995341,9201,8806,0,9001,8807,0,9001,,,,,,
Egypt 1907 / Blue Belt,22991,4229,18071,9001,9807,4400,8801,30,9102,8802,35,9102,8805,1,9201,8806,300000,9001,8807,1100000,9001,,,,,,
Egypt 1907 / Red Belt,22992,4229,18072,9001,9807,4400,8801,30,9102,8802,31,9102,8805,1,9201,8806,615000,9001,8807,810000,9001,,,,,,
Egypt 1907 / Purple Belt,22993,4229,18073,9001,9807,4400,8801,30,9102,8802,27,9102,8805,1,9201,8806,700000,9001,8807,200000,9001,,,,,,
@ -3032,6 +3044,8 @@ Pulkovo 1942 / Gauss-Kruger 30N,28490,4284,16330,9001,9807,4530,8801,0,9102,8802
Pulkovo 1942 / Gauss-Kruger 31N,28491,4284,16331,9001,9807,4530,8801,0,9102,8802,-177,9102,8805,1,9201,8806,500000,9001,8807,0,9001,,,,,,
Pulkovo 1942 / Gauss-Kruger 32N,28492,4284,16332,9001,9807,4530,8801,0,9102,8802,-171,9102,8805,1,9201,8806,500000,9001,8807,0,9001,,,,,,
Qatar 1974 / Qatar National Grid,28600,4285,19919,9001,9807,4400,8801,24.27,9110,8802,51.13,9110,8805,0.99999,9201,8806,200000,9001,8807,300000,9001,,,,,,
Amersfoort / RD Old,28991,4289,19913,9001,9809,4499,8801,52.0922178,9110,8802,5.23155,9110,8805,0.9999079,9201,8806,0,9001,8807,0,9001,,,,,,
Amersfoort / RD New,28992,4289,19914,9001,9809,4499,8801,52.0922178,9110,8802,5.23155,9110,8805,0.9999079,9201,8806,155000,9001,8807,463000,9001,,,,,,
SAD69 / UTM zone 18N,29118,4291,16018,9001,9807,4400,8801,0,9102,8802,-75,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
SAD69 / UTM zone 19N,29119,4291,16019,9001,9807,4400,8801,0,9102,8802,-69,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
SAD69 / UTM zone 20N,29120,4291,16020,9001,9807,4400,8801,0,9102,8802,-63,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
@ -3150,6 +3164,8 @@ DHDN / 3-degree Gauss-Kruger zone 4,31468,4314,16264,9001,9807,4530,8801,0,9102,
DHDN / 3-degree Gauss-Kruger zone 5,31469,4314,16265,9001,9807,4530,8801,0,9102,8802,15,9102,8805,1,9201,8806,5500000,9001,8807,0,9001,,,,,,
Conakry 1905 / UTM zone 28N,31528,4315,16028,9001,9807,4400,8801,0,9102,8802,-15,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
Conakry 1905 / UTM zone 29N,31529,4315,16029,9001,9807,4400,8801,0,9102,8802,-9,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
Dealul Piscului 1930 / Stereo 33,31600,4316,19927,9001,9809,4499,8801,45.54,9110,8802,25.23328772,9110,8805,0.9996667,9201,8806,500000,9001,8807,500000,9001,,,,,,
Dealul Piscului 1970/ Stereo 70,31700,4317,19926,9001,9809,4530,8801,46,9102,8802,25,9102,8805,0.99975,9201,8806,500000,9001,8807,500000,9001,,,,,,
NGN / UTM zone 38N,31838,4318,16038,9001,9807,4400,8801,0,9102,8802,45,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
NGN / UTM zone 39N,31839,4318,16039,9001,9807,4400,8801,0,9102,8802,51,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
KUDAMS / KTM,31900,4319,19928,9001,9807,4400,8801,0,9102,8802,48,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,

Can't render this file because it is too large.

View File

@ -7,7 +7,7 @@
; The name of the installer
Name "GPXSee"
; Program version
!define VERSION "7.2"
!define VERSION "7.3"
; The file to write
OutFile "GPXSee-${VERSION}.exe"
@ -188,6 +188,7 @@ SectionGroup "Localization" SEC_LOCALIZATION
!insertmacro LOCALIZATION "German" "de"
!insertmacro LOCALIZATION "Norwegian" "nb"
!insertmacro LOCALIZATION "Polish" "pl"
!insertmacro LOCALIZATION "Portuguese (Brazil)" "pt_BR"
!insertmacro LOCALIZATION "Russian" "ru"
!insertmacro LOCALIZATION "Spanish" "es"
!insertmacro LOCALIZATION "Swedish" "sv"

View File

@ -7,7 +7,7 @@
; The name of the installer
Name "GPXSee"
; Program version
!define VERSION "7.2"
!define VERSION "7.3"
; The file to write
OutFile "GPXSee-${VERSION}_x64.exe"
@ -190,6 +190,7 @@ SectionGroup "Localization" SEC_LOCALIZATION
!insertmacro LOCALIZATION "German" "de"
!insertmacro LOCALIZATION "Norwegian" "nb"
!insertmacro LOCALIZATION "Polish" "pl"
!insertmacro LOCALIZATION "Portuguese (Brazil)" "pt_BR"
!insertmacro LOCALIZATION "Russian" "ru"
!insertmacro LOCALIZATION "Spanish" "es"
!insertmacro LOCALIZATION "Swedish" "sv"

155
src/GUI/areaitem.cpp Normal file
View File

@ -0,0 +1,155 @@
#include <cmath>
#include <QApplication>
#include <QCursor>
#include <QPainter>
#include "map/map.h"
#include "tooltip.h"
#include "areaitem.h"
QString AreaItem::toolTip() const
{
ToolTip tt;
if (!_area.name().isEmpty())
tt.insert(qApp->translate("PolygonItem", "Name"), _area.name());
if (!_area.description().isEmpty())
tt.insert(qApp->translate("PolygonItem", "Description"),
_area.description());
return tt.toString();
}
AreaItem::AreaItem(const Area &area, Map *map, QGraphicsItem *parent)
: QGraphicsItem(parent), _area(area)
{
_map = map;
_digitalZoom = 0;
_width = 2;
_opacity = 0.5;
QBrush brush(Qt::SolidPattern);
_pen = QPen(brush, _width);
updatePainterPath();
setCursor(Qt::ArrowCursor);
setAcceptHoverEvents(true);
setToolTip(toolTip());
}
QPainterPath AreaItem::painterPath(const Polygon &polygon)
{
QPainterPath path;
const QVector<Coordinates> &lr = polygon.first();
path.moveTo(_map->ll2xy(lr.first()));
for (int i = 1; i < lr.size(); i++)
path.lineTo(_map->ll2xy(lr.at(i)));
path.closeSubpath();
for (int i = 1; i < polygon.size(); i++) {
const QVector<Coordinates> &lr = polygon.at(i);
QPainterPath hole;
hole.moveTo(_map->ll2xy(lr.first()));
for (int j = 1; j < lr.size(); j++)
hole.lineTo(_map->ll2xy(lr.at(j)));
hole.closeSubpath();
path = path.subtracted(hole);
}
return path;
}
void AreaItem::updatePainterPath()
{
_painterPath = QPainterPath();
for (int i = 0; i < _area.size(); i++)
_painterPath.addPath(painterPath(_area.at(i)));
}
void AreaItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
painter->setPen(_width ? _pen : QPen(Qt::NoPen));
painter->drawPath(_painterPath);
painter->fillPath(_painterPath, _brush);
/*
QPen p = QPen(QBrush(Qt::red), 0);
painter->setPen(p);
painter->drawRect(boundingRect());
*/
}
void AreaItem::setMap(Map *map)
{
prepareGeometryChange();
_map = map;
updatePainterPath();
}
void AreaItem::setColor(const QColor &color)
{
if (_pen.color() == color)
return;
QColor bc(color);
bc.setAlphaF(_opacity * color.alphaF());
_pen.setColor(color);
_brush = QBrush(bc);
update();
}
void AreaItem::setOpacity(qreal opacity)
{
if (_opacity == opacity)
return;
_opacity = opacity;
QColor bc(_pen.color());
bc.setAlphaF(_opacity * _pen.color().alphaF());
_brush = QBrush(bc);
update();
}
void AreaItem::setWidth(qreal width)
{
if (_width == width)
return;
prepareGeometryChange();
_width = width;
_pen.setWidthF(_width * pow(2, -_digitalZoom));
}
void AreaItem::setStyle(Qt::PenStyle style)
{
if (_pen.style() == style)
return;
_pen.setStyle(style);
update();
}
void AreaItem::setDigitalZoom(int zoom)
{
if (_digitalZoom == zoom)
return;
prepareGeometryChange();
_digitalZoom = zoom;
_pen.setWidthF(_width * pow(2, -_digitalZoom));
}

46
src/GUI/areaitem.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef AREAITEM_H
#define AREAITEM_H
#include <QGraphicsItem>
#include "data/area.h"
class Map;
class AreaItem : public QGraphicsItem
{
public:
AreaItem(const Area &area, Map *map, QGraphicsItem *parent = 0);
QPainterPath shape() const {return _painterPath;}
QRectF boundingRect() const {return _painterPath.boundingRect();}
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget);
const Area &area() const {return _area;}
void setMap(Map *map);
void setColor(const QColor &color);
void setOpacity(qreal opacity);
void setWidth(qreal width);
void setStyle(Qt::PenStyle style);
void setDigitalZoom(int zoom);
private:
QPainterPath painterPath(const Polygon &polygon);
void updatePainterPath();
QString toolTip() const;
Area _area;
Map *_map;
int _digitalZoom;
qreal _width;
QPen _pen;
QBrush _brush;
qreal _opacity;
QPainterPath _painterPath;
};
#endif // AREAITEM_H

View File

@ -32,15 +32,16 @@ QList<GraphItem*> CadenceGraph::loadData(const Data &data)
QList<GraphItem*> graphs;
for (int i = 0; i < data.tracks().count(); i++) {
const Graph &graph = data.tracks().at(i)->cadence();
const Track &track = data.tracks().at(i);
const Graph &graph = track.cadence();
if (graph.size() < 2) {
if (!graph.isValid()) {
skipColor();
graphs.append(0);
} else {
CadenceGraphItem *gi = new CadenceGraphItem(graph, _graphType);
GraphView::addGraph(gi);
_avg.append(QPointF(data.tracks().at(i)->distance(), gi->avg()));
_avg.append(QPointF(track.distance(), gi->avg()));
graphs.append(gi);
}
}
@ -50,6 +51,9 @@ QList<GraphItem*> CadenceGraph::loadData(const Data &data)
graphs.append(0);
}
for (int i = 0; i < data.areas().count(); i++)
skipColor();
setInfo();
redraw();

View File

@ -6,17 +6,6 @@
CadenceGraphItem::CadenceGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent) : GraphItem(graph, type, parent)
{
qreal sum = 0;
_max = graph.first().y();
for (int i = 1; i < graph.size(); i++) {
qreal y = graph.at(i).y();
sum += y * (graph.at(i).s() - graph.at(i-1).s());
if (y > _max)
_max = y;
}
_avg = sum/graph.last().s();
setToolTip(toolTip());
}

View File

@ -11,13 +11,8 @@ public:
CadenceGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent = 0);
qreal max() const {return _max;}
qreal avg() const {return _avg;}
private:
QString toolTip() const;
qreal _avg, _max;
};
#endif // CADENCEGRAPHITEM_H

View File

@ -0,0 +1,57 @@
#include <QFontMetrics>
#include <QPainter>
#include "font.h"
#include "coordinatesitem.h"
CoordinatesItem::CoordinatesItem(QGraphicsItem *parent) : QGraphicsItem(parent)
{
_format = DecimalDegrees;
_font.setPixelSize(FONT_SIZE);
_font.setFamily(FONT_FAMILY);
updateBoundingRect();
}
void CoordinatesItem::paint(QPainter *painter,
const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
if (!_c.isValid())
return;
QFontMetrics fm(_font);
painter->setFont(_font);
painter->setPen(QPen(Qt::black));
painter->drawText(0, -fm.descent(), Format::coordinates(_c, _format));
/*
painter->setPen(Qt::red);
painter->drawRect(boundingRect());
*/
}
void CoordinatesItem::setCoordinates(const Coordinates &c)
{
_c = c;
update();
}
void CoordinatesItem::setFormat(const CoordinatesFormat &format)
{
prepareGeometryChange();
_format = format;
updateBoundingRect();
}
void CoordinatesItem::updateBoundingRect()
{
QFontMetrics fm(_font);
_boundingRect = fm.tightBoundingRect(Format::coordinates(
Coordinates(-180, -90), _format));
_boundingRect.moveBottom(-fm.descent());
}

30
src/GUI/coordinatesitem.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef COORDINATESITEM_H
#define COORDINATESITEM_H
#include <QGraphicsItem>
#include <QFont>
#include "common/coordinates.h"
#include "format.h"
class CoordinatesItem : public QGraphicsItem
{
public:
CoordinatesItem(QGraphicsItem *parent = 0);
QRectF boundingRect() const {return _boundingRect;}
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget);
void setCoordinates(const Coordinates &c);
void setFormat(const CoordinatesFormat &format);
private:
void updateBoundingRect();
Coordinates _c;
CoordinatesFormat _format;
QRectF _boundingRect;
QFont _font;
};
#endif // COORDINATESITEM_H

View File

@ -69,7 +69,7 @@ void ElevationGraph::setInfo()
GraphItem *ElevationGraph::loadGraph(const Graph &graph, Type type)
{
if (graph.size() < 2) {
if (!graph.isValid()) {
skipColor();
return 0;
}
@ -97,9 +97,11 @@ QList<GraphItem*> ElevationGraph::loadData(const Data &data)
QList<GraphItem*> graphs;
for (int i = 0; i < data.tracks().count(); i++)
graphs.append(loadGraph(data.tracks().at(i)->elevation(), Track));
graphs.append(loadGraph(data.tracks().at(i).elevation(), Track));
for (int i = 0; i < data.routes().count(); i++)
graphs.append(loadGraph(data.routes().at(i)->elevation(), Route));
graphs.append(loadGraph(data.routes().at(i).elevation(), Route));
for (int i = 0; i < data.areas().count(); i++)
skipColor();
setInfo();
redraw();

View File

@ -6,22 +6,22 @@
ElevationGraphItem::ElevationGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent) : GraphItem(graph, type, parent)
{
_min = GraphItem::min();
_max = GraphItem::max();
_ascent = _descent = 0;
_min = _max = graph.first().y();
for (int i = 0; i < graph.size(); i++) {
const GraphSegment &segment = graph.at(i);
for (int j = 1; j < graph.size(); j++) {
qreal cur = graph.at(j).y();
qreal prev = graph.at(j-1).y();
for (int j = 1; j < segment.size(); j++) {
qreal cur = segment.at(j).y();
qreal prev = segment.at(j-1).y();
if (cur > prev)
_ascent += cur - prev;
if (cur < prev)
_descent += prev - cur;
if (cur < _min)
_min = cur;
if (cur > _max)
_max = cur;
if (cur > prev)
_ascent += cur - prev;
if (cur < prev)
_descent += prev - cur;
}
}
setToolTip(toolTip(Metric));

View File

@ -13,8 +13,8 @@ public:
qreal ascent() const {return _ascent;}
qreal descent() const {return _descent;}
qreal min() const {return _min;}
qreal max() const {return _max;}
qreal min() const {return _min;}
void setUnits(Units units);

View File

@ -34,9 +34,9 @@ QList<GraphItem*> GearRatioGraph::loadData(const Data &data)
QList<GraphItem*> graphs;
for (int i = 0; i < data.tracks().count(); i++) {
const Graph &graph = data.tracks().at(i)->ratio();
const Graph &graph = data.tracks().at(i).ratio();
if (graph.size() < 2) {
if (!graph.isValid()) {
skipColor();
graphs.append(0);
} else {
@ -55,6 +55,9 @@ QList<GraphItem*> GearRatioGraph::loadData(const Data &data)
graphs.append(0);
}
for (int i = 0; i < data.areas().count(); i++)
skipColor();
setInfo();
redraw();

View File

@ -8,19 +8,6 @@ GearRatioGraphItem::GearRatioGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent) : GraphItem(graph, type, parent), _top(NAN)
{
qreal val = NAN;
_min = _max = graph.first().y();
for (int i = 1; i < graph.size(); i++) {
const GraphPoint &p = graph.at(i);
qreal val = _map.value(p.y());
_map.insert(p.y(), val + (p.s() - graph.at(i-1).s()));
if (p.y() < _min)
_min = p.y();
if (p.y() > _max)
_max = p.y();
}
for (QMap<qreal, qreal>::const_iterator it = _map.constBegin();
it != _map.constEnd(); ++it) {

View File

@ -12,8 +12,6 @@ public:
GearRatioGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent = 0);
qreal min() const {return _min;}
qreal max() const {return _max;}
qreal top() const {return _top;}
const QMap<qreal, qreal> &map() const {return _map;}
@ -22,7 +20,7 @@ private:
QString toolTip() const;
QMap<qreal, qreal> _map;
qreal _top, _min, _max;
qreal _top;
};
#endif // GEARRATIOGRAPHITEM_H

View File

@ -3,26 +3,17 @@
GraphItem::GraphItem(const Graph &graph, GraphType type, QGraphicsItem *parent)
: QGraphicsObject(parent)
: QGraphicsObject(parent), _graph(graph), _type(type)
{
Q_ASSERT(_graph.isValid());
_id = 0;
_width = 1;
_pen = QPen(Qt::black, _width);
_type = type;
_graph = graph;
_sx = 1.0; _sy = 1.0;
_time = _graph.hasTime();
_time = true;
for (int i = 0; i < _graph.size(); i++) {
if (std::isnan(_graph.at(i).t())) {
_time = false;
break;
}
}
setZValue(1.0);
setZValue(2.0);
updatePath();
updateShape();
@ -89,18 +80,31 @@ void GraphItem::setWidth(int width)
updateShape();
}
const GraphSegment *GraphItem::segment(qreal x, GraphType type) const
{
for (int i = 0; i < _graph.size(); i++)
if (x <= _graph.at(i).last().x(type))
return &(_graph.at(i));
return 0;
}
qreal GraphItem::yAtX(qreal x)
{
const GraphSegment *seg = segment(x, _type);
if (!seg)
return NAN;
int low = 0;
int high = _graph.count() - 1;
int high = seg->count() - 1;
int mid = 0;
Q_ASSERT(high > low);
Q_ASSERT(x >= _graph.at(low).x(_type) && x <= _graph.at(high).x(_type));
if (!(x >= seg->at(low).x(_type) && x <= seg->at(high).x(_type)))
return NAN;
while (low <= high) {
mid = low + ((high - low) / 2);
const GraphPoint &p = _graph.at(mid);
const GraphPoint &p = seg->at(mid);
if (p.x(_type) > x)
high = mid - 1;
else if (p.x(_type) < x)
@ -110,58 +114,56 @@ qreal GraphItem::yAtX(qreal x)
}
QLineF l;
if (_graph.at(mid).x(_type) < x)
l = QLineF(_graph.at(mid).x(_type), _graph.at(mid).y(),
_graph.at(mid+1).x(_type), _graph.at(mid+1).y());
if (seg->at(mid).x(_type) < x)
l = QLineF(seg->at(mid).x(_type), seg->at(mid).y(),
seg->at(mid+1).x(_type), seg->at(mid+1).y());
else
l = QLineF(_graph.at(mid-1).x(_type), _graph.at(mid-1).y(),
_graph.at(mid).x(_type), _graph.at(mid).y());
l = QLineF(seg->at(mid-1).x(_type), seg->at(mid-1).y(),
seg->at(mid).x(_type), seg->at(mid).y());
return -l.pointAt((x - l.p1().x()) / (l.p2().x() - l.p1().x())).y();
}
qreal GraphItem::distanceAtTime(qreal time)
{
const GraphSegment *seg = segment(time, Time);
if (!seg)
return NAN;
int low = 0;
int high = _graph.count() - 1;
int high = seg->count() - 1;
int mid = 0;
Q_ASSERT(high > low);
Q_ASSERT(time >= _graph.at(low).t() && time <= _graph.at(high).t());
if (!(time >= seg->at(low).t() && time <= seg->at(high).t()))
return NAN;
while (low <= high) {
mid = low + ((high - low) / 2);
const GraphPoint &p = _graph.at(mid);
const GraphPoint &p = seg->at(mid);
if (p.t() > time)
high = mid - 1;
else if (p.t() < time)
low = mid + 1;
else
return _graph.at(mid).s();
return seg->at(mid).s();
}
QLineF l;
if (_graph.at(mid).t() < time)
l = QLineF(_graph.at(mid).t(), _graph.at(mid).s(), _graph.at(mid+1).t(),
_graph.at(mid+1).s());
if (seg->at(mid).t() < time)
l = QLineF(seg->at(mid).t(), seg->at(mid).s(), seg->at(mid+1).t(),
seg->at(mid+1).s());
else
l = QLineF(_graph.at(mid-1).t(), _graph.at(mid-1).s(),
_graph.at(mid).t(), _graph.at(mid).s());
l = QLineF(seg->at(mid-1).t(), seg->at(mid-1).s(),
seg->at(mid).t(), seg->at(mid).s());
return l.pointAt((time - l.p1().x()) / (l.p2().x() - l.p1().x())).y();
}
void GraphItem::emitSliderPositionChanged(qreal pos)
{
if (_type == Time) {
if (_time) {
if (pos >= _graph.first().t() && pos <= _graph.last().t())
emit sliderPositionChanged(distanceAtTime(pos));
else
emit sliderPositionChanged(NAN);
} else
emit sliderPositionChanged(NAN);
} else
if (_type == Time)
emit sliderPositionChanged(_time ? distanceAtTime(pos) : NAN);
else
emit sliderPositionChanged(pos);
}
@ -197,9 +199,13 @@ void GraphItem::updatePath()
if (_type == Time && !_time)
return;
_path.moveTo(_graph.first().x(_type) * _sx, -_graph.first().y() * _sy);
for (int i = 1; i < _graph.size(); i++)
_path.lineTo(_graph.at(i).x(_type) * _sx, -_graph.at(i).y() * _sy);
for (int i = 0; i < _graph.size(); i++) {
const GraphSegment &segment = _graph.at(i);
_path.moveTo(segment.first().x(_type) * _sx, -segment.first().y() * _sy);
for (int i = 1; i < segment.size(); i++)
_path.lineTo(segment.at(i).x(_type) * _sx, -segment.at(i).y() * _sy);
}
}
void GraphItem::updateBounds()
@ -211,18 +217,71 @@ void GraphItem::updateBounds()
qreal bottom, top, left, right;
QPointF p = QPointF(_graph.first().x(_type), -_graph.first().y());
QPointF p = QPointF(_graph.first().first().x(_type),
-_graph.first().first().y());
bottom = p.y(); top = p.y(); left = p.x(); right = p.x();
for (int i = 1; i < _graph.size(); i++) {
p = QPointF(_graph.at(i).x(_type), -_graph.at(i).y());
bottom = qMax(bottom, p.y()); top = qMin(top, p.y());
right = qMax(right, p.x()); left = qMin(left, p.x());
for (int i = 0; i < _graph.size(); i++) {
const GraphSegment &segment = _graph.at(i);
for (int j = 0; j < segment.size(); j++) {
p = QPointF(segment.at(j).x(_type), -segment.at(j).y());
bottom = qMax(bottom, p.y()); top = qMin(top, p.y());
right = qMax(right, p.x()); left = qMin(left, p.x());
}
}
_bounds = QRectF(QPointF(left, top), QPointF(right, bottom));
}
qreal GraphItem::max() const
{
qreal ret = _graph.first().first().y();
for (int i = 0; i < _graph.size(); i++) {
const GraphSegment &segment = _graph.at(i);
for (int j = 0; j < segment.size(); j++) {
qreal y = segment.at(j).y();
if (y > ret)
ret = y;
}
}
return ret;
}
qreal GraphItem::min() const
{
qreal ret = _graph.first().first().y();
for (int i = 0; i < _graph.size(); i++) {
const GraphSegment &segment = _graph.at(i);
for (int j = 0; j < segment.size(); j++) {
qreal y = segment.at(j).y();
if (y < ret)
ret = y;
}
}
return ret;
}
qreal GraphItem::avg() const
{
qreal sum = 0;
for (int i = 0; i < _graph.size(); i++) {
const GraphSegment &segment = _graph.at(i);
for (int j = 1; j < segment.size(); j++)
sum += segment.at(j).y() * (segment.at(j).s() - segment.at(j-1).s());
}
return sum/_graph.last().last().s();
}
void GraphItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event);

View File

@ -21,6 +21,10 @@ public:
const QRectF &bounds() const {return _bounds;}
qreal max() const;
qreal min() const;
qreal avg() const;
void setScale(qreal sx, qreal sy);
void setGraphType(GraphType type);
int id() const {return _id;}
@ -46,6 +50,7 @@ private:
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
const GraphSegment *segment(qreal x, GraphType type) const;
void updatePath();
void updateShape();
void updateBounds();

View File

@ -34,9 +34,9 @@ GraphView::GraphView(QWidget *parent)
setBackgroundBrush(QBrush(palette().brush(QPalette::Base)));
_xAxis = new AxisItem(AxisItem::X);
_xAxis->setZValue(2.0);
_xAxis->setZValue(1.0);
_yAxis = new AxisItem(AxisItem::Y);
_yAxis->setZValue(2.0);
_yAxis->setZValue(1.0);
_slider = new SliderItem();
_slider->setZValue(3.0);
_sliderInfo = new SliderInfoItem(_slider);

View File

@ -88,6 +88,7 @@ GUI::GUI()
_trackCount = 0;
_routeCount = 0;
_waypointCount = 0;
_areaCount = 0;
_trackDistance = 0;
_routeDistance = 0;
_time = 0;
@ -312,6 +313,11 @@ void GUI::createActions()
_showMapAction->setEnabled(false);
_clearMapCacheAction->setEnabled(false);
}
_showCoordinatesAction = new QAction(tr("Show cursor coordinates"), this);
_showCoordinatesAction->setMenuRole(QAction::NoRole);
_showCoordinatesAction->setCheckable(true);
connect(_showCoordinatesAction, SIGNAL(triggered(bool)), _mapView,
SLOT(showCoordinates(bool)));
// Data actions
_showTracksAction = new QAction(tr("Show tracks"), this);
@ -329,6 +335,11 @@ void GUI::createActions()
_showWaypointsAction->setCheckable(true);
connect(_showWaypointsAction, SIGNAL(triggered(bool)), _mapView,
SLOT(showWaypoints(bool)));
_showAreasAction = new QAction(tr("Show areas"), this);
_showAreasAction->setMenuRole(QAction::NoRole);
_showAreasAction->setCheckable(true);
connect(_showAreasAction, SIGNAL(triggered(bool)), _mapView,
SLOT(showAreas(bool)));
_showWaypointLabelsAction = new QAction(tr("Waypoint labels"), this);
_showWaypointLabelsAction->setMenuRole(QAction::NoRole);
_showWaypointLabelsAction->setCheckable(true);
@ -375,6 +386,11 @@ void GUI::createActions()
_showGraphSliderInfoAction->setCheckable(true);
connect(_showGraphSliderInfoAction, SIGNAL(triggered(bool)), this,
SLOT(showGraphSliderInfo(bool)));
_showMarkersAction = new QAction(tr("Show path markers"), this);
_showMarkersAction->setMenuRole(QAction::NoRole);
_showMarkersAction->setCheckable(true);
connect(_showMarkersAction, SIGNAL(triggered(bool)), _mapView,
SLOT(showMarkers(bool)));
// Settings actions
_showToolbarsAction = new QAction(tr("Show toolbars"), this);
@ -491,6 +507,8 @@ void GUI::createMenus()
_mapMenu->addAction(_loadMapAction);
_mapMenu->addAction(_clearMapCacheAction);
_mapMenu->addSeparator();
_mapMenu->addAction(_showCoordinatesAction);
_mapMenu->addSeparator();
_mapMenu->addAction(_showMapAction);
QMenu *graphMenu = menuBar()->addMenu(tr("&Graph"));
@ -499,6 +517,7 @@ void GUI::createMenus()
graphMenu->addSeparator();
graphMenu->addAction(_showGraphGridAction);
graphMenu->addAction(_showGraphSliderInfoAction);
graphMenu->addAction(_showMarkersAction);
graphMenu->addSeparator();
graphMenu->addAction(_showGraphsAction);
@ -521,6 +540,7 @@ void GUI::createMenus()
dataMenu->addSeparator();
dataMenu->addAction(_showTracksAction);
dataMenu->addAction(_showRoutesAction);
dataMenu->addAction(_showAreasAction);
dataMenu->addAction(_showWaypointsAction);
QMenu *settingsMenu = menuBar()->addMenu(tr("&Settings"));
@ -558,6 +578,7 @@ void GUI::createToolBars()
#endif // Q_OS_MAC
_fileToolBar = addToolBar(tr("File"));
_fileToolBar->setObjectName("File");
_fileToolBar->setIconSize(iconSize);
_fileToolBar->addAction(_openFileAction);
_fileToolBar->addAction(_reloadFileAction);
@ -565,12 +586,14 @@ void GUI::createToolBars()
_fileToolBar->addAction(_printFileAction);
_showToolBar = addToolBar(tr("Show"));
_showToolBar->setObjectName("Show");
_showToolBar->setIconSize(iconSize);
_showToolBar->addAction(_showPOIAction);
_showToolBar->addAction(_showMapAction);
_showToolBar->addAction(_showGraphsAction);
_navigationToolBar = addToolBar(tr("Navigation"));
_navigationToolBar->setObjectName("Navigation");
_navigationToolBar->setIconSize(iconSize);
_navigationToolBar->addAction(_firstAction);
_navigationToolBar->addAction(_prevAction);
@ -753,10 +776,11 @@ bool GUI::loadFile(const QString &fileName)
if (data.isValid()) {
for (int i = 0; i < data.tracks().count(); i++) {
_trackDistance += data.tracks().at(i)->distance();
_time += data.tracks().at(i)->time();
_movingTime += data.tracks().at(i)->movingTime();
const QDate &date = data.tracks().at(i)->date().date();
const Track &track = data.tracks().at(i);
_trackDistance += track.distance();
_time += track.time();
_movingTime += track.movingTime();
const QDate &date = track.date().date();
if (_dateRange.first.isNull() || _dateRange.first > date)
_dateRange.first = date;
if (_dateRange.second.isNull() || _dateRange.second < date)
@ -765,16 +789,17 @@ bool GUI::loadFile(const QString &fileName)
_trackCount += data.tracks().count();
for (int i = 0; i < data.routes().count(); i++)
_routeDistance += data.routes().at(i)->distance();
_routeDistance += data.routes().at(i).distance();
_routeCount += data.routes().count();
_waypointCount += data.waypoints().count();
_areaCount += data.areas().count();
if (_pathName.isNull()) {
if (data.tracks().count() == 1 && !data.routes().count())
_pathName = data.tracks().first()->name();
_pathName = data.tracks().first().name();
else if (data.routes().count() == 1 && !data.tracks().count())
_pathName = data.routes().first()->name();
_pathName = data.routes().first().name();
} else
_pathName = QString();
@ -893,8 +918,11 @@ void GUI::openOptions()
SET_VIEW_OPTION(backgroundColor, setBackgroundColor);
SET_VIEW_OPTION(trackWidth, setTrackWidth);
SET_VIEW_OPTION(routeWidth, setRouteWidth);
SET_VIEW_OPTION(areaWidth, setAreaWidth);
SET_VIEW_OPTION(trackStyle, setTrackStyle);
SET_VIEW_OPTION(routeStyle, setRouteStyle);
SET_VIEW_OPTION(areaStyle, setAreaStyle);
SET_VIEW_OPTION(areaOpacity, setAreaOpacity);
SET_VIEW_OPTION(waypointSize, setWaypointSize);
SET_VIEW_OPTION(waypointColor, setWaypointColor);
SET_VIEW_OPTION(poiSize, setPOISize);
@ -1000,6 +1028,9 @@ void GUI::statistics()
if (_showWaypointsAction->isChecked() && _waypointCount > 1)
text.append("<tr><td>" + tr("Waypoints") + ":</td><td>"
+ l.toString(_waypointCount) + "</td></tr>");
if (_showAreasAction->isChecked() && _areaCount > 1)
text.append("<tr><td>" + tr("Areas") + ":</td><td>"
+ l.toString(_areaCount) + "</td></tr>");
if (_dateRange.first.isValid()) {
if (_dateRange.first == _dateRange.second) {
@ -1065,6 +1096,8 @@ void GUI::plot(QPrinter *printer)
info.insert(tr("Routes"), l.toString(_routeCount));
if (_showWaypointsAction->isChecked() && _waypointCount > 1)
info.insert(tr("Waypoints"), l.toString(_waypointCount));
if (_showAreasAction->isChecked() && _areaCount > 1)
info.insert(tr("Areas"), l.toString(_areaCount));
}
if (_dateRange.first.isValid() && _options.printDate) {
@ -1138,6 +1171,7 @@ void GUI::reloadFile()
_trackCount = 0;
_routeCount = 0;
_waypointCount = 0;
_areaCount = 0;
_trackDistance = 0;
_routeDistance = 0;
_time = 0;
@ -1171,6 +1205,7 @@ void GUI::closeFiles()
_trackCount = 0;
_routeCount = 0;
_waypointCount = 0;
_areaCount = 0;
_trackDistance = 0;
_routeDistance = 0;
_time = 0;
@ -1206,13 +1241,11 @@ void GUI::showGraphs(bool show)
void GUI::showToolbars(bool show)
{
if (show) {
addToolBar(_fileToolBar);
addToolBar(_showToolBar);
addToolBar(_navigationToolBar);
_fileToolBar->show();
_showToolBar->show();
_navigationToolBar->show();
Q_ASSERT(!_windowStates.isEmpty());
restoreState(_windowStates.last());
_windowStates.pop_back();
} else {
_windowStates.append(saveState());
removeToolBar(_fileToolBar);
removeToolBar(_showToolBar);
removeToolBar(_navigationToolBar);
@ -1223,26 +1256,16 @@ void GUI::showFullscreen(bool show)
{
if (show) {
_frameStyle = _mapView->frameStyle();
_showGraphs = _showGraphsAction->isChecked();
statusBar()->hide();
menuBar()->hide();
showToolbars(false);
showGraphs(false);
_showGraphsAction->setChecked(false);
_mapView->setFrameStyle(QFrame::NoFrame);
showFullScreen();
} else {
statusBar()->show();
menuBar()->show();
if (_showToolbarsAction->isChecked())
showToolbars(true);
_showGraphsAction->setChecked(_showGraphs);
if (_showGraphsAction->isEnabled())
showGraphs(_showGraphs);
showToolbars(true);
_mapView->setFrameStyle(_frameStyle);
showNormal();
}
}
@ -1457,7 +1480,8 @@ bool GUI::updateMapView()
if (_options.alwaysShowMap)
_mapView->setHidden(false);
else
_mapView->setHidden(!(_trackCount + _routeCount + _waypointCount));
_mapView->setHidden(!(_trackCount + _routeCount + _waypointCount
+ _areaCount));
return (hidden != _mapView->isHidden());
}
@ -1612,6 +1636,8 @@ void GUI::dropEvent(QDropEvent *event)
QList<QUrl> urls = event->mimeData()->urls();
for (int i = 0; i < urls.size(); i++)
openFile(urls.at(i).toLocalFile());
event->acceptProposedAction();
}
void GUI::writeSettings()
@ -1624,6 +1650,10 @@ void GUI::writeSettings()
settings.setValue(WINDOW_SIZE_SETTING, size());
if (pos() != WINDOW_POS_DEFAULT)
settings.setValue(WINDOW_POS_SETTING, pos());
if (_windowStates.isEmpty())
settings.setValue(WINDOW_STATE_SETTING, saveState());
else
settings.setValue(WINDOW_STATE_SETTING, _windowStates.first());
settings.endGroup();
settings.beginGroup(SETTINGS_SETTINGS_GROUP);
@ -1648,6 +1678,9 @@ void GUI::writeSettings()
settings.setValue(CURRENT_MAP_SETTING, _map->name());
if (_showMapAction->isChecked() != SHOW_MAP_DEFAULT)
settings.setValue(SHOW_MAP_SETTING, _showMapAction->isChecked());
if (_showCoordinatesAction->isChecked() != SHOW_COORDINATES_DEFAULT)
settings.setValue(SHOW_COORDINATES_SETTING,
_showCoordinatesAction->isChecked());
settings.endGroup();
settings.beginGroup(GRAPH_SETTINGS_GROUP);
@ -1663,6 +1696,9 @@ void GUI::writeSettings()
!= SHOW_GRAPH_SLIDER_INFO_DEFAULT)
settings.setValue(SHOW_GRAPH_SLIDER_INFO_SETTING,
_showGraphSliderInfoAction->isChecked());
if (_showMarkersAction->isChecked() != SHOW_MARKERS_DEFAULT)
settings.setValue(SHOW_MARKERS_SETTING,
_showMarkersAction->isChecked());
settings.endGroup();
settings.beginGroup(POI_SETTINGS_GROUP);
@ -1692,6 +1728,8 @@ void GUI::writeSettings()
if (_showWaypointsAction->isChecked() != SHOW_WAYPOINTS_DEFAULT)
settings.setValue(SHOW_WAYPOINTS_SETTING,
_showWaypointsAction->isChecked());
if (_showAreasAction->isChecked() != SHOW_AREAS_DEFAULT)
settings.setValue(SHOW_AREAS_SETTING, _showAreasAction->isChecked());
if (_showWaypointLabelsAction->isChecked() != SHOW_WAYPOINT_LABELS_DEFAULT)
settings.setValue(SHOW_WAYPOINT_LABELS_SETTING,
_showWaypointLabelsAction->isChecked());
@ -1732,10 +1770,16 @@ void GUI::writeSettings()
settings.setValue(TRACK_WIDTH_SETTING, _options.trackWidth);
if (_options.routeWidth != ROUTE_WIDTH_DEFAULT)
settings.setValue(ROUTE_WIDTH_SETTING, _options.routeWidth);
if (_options.areaWidth != AREA_WIDTH_DEFAULT)
settings.setValue(AREA_WIDTH_SETTING, _options.areaWidth);
if (_options.trackStyle != TRACK_STYLE_DEFAULT)
settings.setValue(TRACK_STYLE_SETTING, (int)_options.trackStyle);
if (_options.routeStyle != ROUTE_STYLE_DEFAULT)
settings.setValue(ROUTE_STYLE_SETTING, (int)_options.routeStyle);
if (_options.areaStyle != AREA_STYLE_DEFAULT)
settings.setValue(AREA_STYLE_SETTING, (int)_options.areaStyle);
if (_options.areaOpacity != AREA_OPACITY_DEFAULT)
settings.setValue(AREA_OPACITY_SETTING, (int)_options.areaOpacity);
if (_options.waypointSize != WAYPOINT_SIZE_DEFAULT)
settings.setValue(WAYPOINT_SIZE_SETTING, _options.waypointSize);
if (_options.waypointColor != WAYPOINT_COLOR_DEFAULT)
@ -1820,6 +1864,7 @@ void GUI::readSettings()
settings.beginGroup(WINDOW_SETTINGS_GROUP);
resize(settings.value(WINDOW_SIZE_SETTING, WINDOW_SIZE_DEFAULT).toSize());
move(settings.value(WINDOW_POS_SETTING, WINDOW_POS_DEFAULT).toPoint());
restoreState(settings.value(WINDOW_STATE_SETTING).toByteArray());
settings.endGroup();
settings.beginGroup(SETTINGS_SETTINGS_GROUP);
@ -1860,6 +1905,11 @@ void GUI::readSettings()
int index = mapIndex(settings.value(CURRENT_MAP_SETTING).toString());
_mapActions.at(index)->trigger();
}
if (settings.value(SHOW_COORDINATES_SETTING, SHOW_COORDINATES_DEFAULT)
.toBool()) {
_showCoordinatesAction->setChecked(true);
_mapView->showCoordinates(true);
}
settings.endGroup();
settings.beginGroup(GRAPH_SETTINGS_GROUP);
@ -1883,6 +1933,10 @@ void GUI::readSettings()
showGraphSliderInfo(false);
else
_showGraphSliderInfoAction->setChecked(true);
if (!settings.value(SHOW_MARKERS_SETTING, SHOW_MARKERS_DEFAULT).toBool())
_mapView->showMarkers(false);
else
_showMarkersAction->setChecked(true);
settings.endGroup();
settings.beginGroup(POI_SETTINGS_GROUP);
@ -1931,6 +1985,10 @@ void GUI::readSettings()
_mapView->showWaypoints(false);
else
_showWaypointsAction->setChecked(true);
if (!settings.value(SHOW_AREAS_SETTING, SHOW_AREAS_DEFAULT).toBool())
_mapView->showAreas(false);
else
_showAreasAction->setChecked(true);
if (!settings.value(SHOW_WAYPOINT_LABELS_SETTING,
SHOW_WAYPOINT_LABELS_DEFAULT).toBool())
_mapView->showWaypointLabels(false);
@ -1976,10 +2034,16 @@ void GUI::readSettings()
TRACK_WIDTH_DEFAULT).toInt();
_options.routeWidth = settings.value(ROUTE_WIDTH_SETTING,
ROUTE_WIDTH_DEFAULT).toInt();
_options.areaWidth = settings.value(AREA_WIDTH_SETTING,
AREA_WIDTH_DEFAULT).toInt();
_options.trackStyle = (Qt::PenStyle) settings.value(TRACK_STYLE_SETTING,
(int)TRACK_STYLE_DEFAULT).toInt();
_options.routeStyle = (Qt::PenStyle) settings.value(ROUTE_STYLE_SETTING,
(int)ROUTE_STYLE_DEFAULT).toInt();
_options.areaStyle = (Qt::PenStyle) settings.value(AREA_STYLE_SETTING,
(int)AREA_STYLE_DEFAULT).toInt();
_options.areaOpacity = settings.value(AREA_OPACITY_SETTING,
AREA_OPACITY_DEFAULT).toInt();
_options.pathAntiAliasing = settings.value(PATH_AA_SETTING, PATH_AA_DEFAULT)
.toBool();
_options.waypointSize = settings.value(WAYPOINT_SIZE_SETTING,
@ -2058,8 +2122,11 @@ void GUI::readSettings()
_mapView->setBackgroundColor(_options.backgroundColor);
_mapView->setTrackWidth(_options.trackWidth);
_mapView->setRouteWidth(_options.routeWidth);
_mapView->setAreaWidth(_options.areaWidth);
_mapView->setTrackStyle(_options.trackStyle);
_mapView->setRouteStyle(_options.routeStyle);
_mapView->setAreaStyle(_options.areaStyle);
_mapView->setAreaOpacity(_options.areaOpacity);
_mapView->setWaypointSize(_options.waypointSize);
_mapView->setWaypointColor(_options.waypointColor);
_mapView->setPOISize(_options.poiSize);

View File

@ -190,7 +190,10 @@ private:
QAction *_showRoutesAction;
QAction *_showWaypointsAction;
QAction *_showWaypointLabelsAction;
QAction *_showAreasAction;
QAction *_showRouteWaypointsAction;
QAction *_showMarkersAction;
QAction *_showCoordinatesAction;
QAction *_openOptionsAction;
QAction *_mapsEnd;
QList<QAction*> _mapActions;
@ -215,20 +218,16 @@ private:
FileBrowser *_browser;
QList<QString> _files;
int _trackCount;
int _routeCount;
int _waypointCount;
qreal _trackDistance;
qreal _routeDistance;
qreal _time;
qreal _movingTime;
int _trackCount, _routeCount, _areaCount, _waypointCount;
qreal _trackDistance, _routeDistance;
qreal _time, _movingTime;
DateRange _dateRange;
QString _pathName;
qreal _sliderPos;
QList<QByteArray> _windowStates;
int _frameStyle;
bool _showGraphs;
Export _export;
Options _options;

View File

@ -32,15 +32,16 @@ QList<GraphItem*> HeartRateGraph::loadData(const Data &data)
QList<GraphItem*> graphs;
for (int i = 0; i < data.tracks().count(); i++) {
const Graph &graph = data.tracks().at(i)->heartRate();
const Track &track = data.tracks().at(i);
const Graph &graph = track.heartRate();
if (graph.size() < 2) {
if (!graph.isValid()) {
skipColor();
graphs.append(0);
} else {
HeartRateGraphItem *gi = new HeartRateGraphItem(graph, _graphType);
GraphView::addGraph(gi);
_avg.append(QPointF(data.tracks().at(i)->distance(), gi->avg()));
_avg.append(QPointF(track.distance(), gi->avg()));
graphs.append(gi);
}
}
@ -50,6 +51,9 @@ QList<GraphItem*> HeartRateGraph::loadData(const Data &data)
graphs.append(0);
}
for (int i = 0; i < data.areas().count(); i++)
skipColor();
setInfo();
redraw();

View File

@ -6,17 +6,6 @@
HeartRateGraphItem::HeartRateGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent) : GraphItem(graph, type, parent)
{
qreal sum = 0;
_max = graph.first().y();
for (int i = 1; i < graph.size(); i++) {
qreal y = graph.at(i).y();
sum += y * (graph.at(i).s() - graph.at(i-1).s());
if (y > _max)
_max = y;
}
_avg = sum/graph.last().s();
setToolTip(toolTip());
}

View File

@ -11,13 +11,8 @@ public:
HeartRateGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent = 0);
qreal max() const {return _max;}
qreal avg() const {return _avg;}
private:
QString toolTip() const;
qreal _avg, _max;
};
#endif // HEARTRATEGRAPHITEM_H

View File

@ -11,7 +11,9 @@
#include "trackitem.h"
#include "routeitem.h"
#include "waypointitem.h"
#include "areaitem.h"
#include "scaleitem.h"
#include "coordinatesitem.h"
#include "keys.h"
#include "mapview.h"
@ -20,6 +22,7 @@
#define MIN_DIGITAL_ZOOM -3
#define MARGIN 10
#define SCALE_OFFSET 7
#define COORDINATES_OFFSET SCALE_OFFSET
MapView::MapView(Map *map, POI *poi, QWidget *parent)
@ -36,10 +39,15 @@ MapView::MapView(Map *map, POI *poi, QWidget *parent)
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setRenderHint(QPainter::Antialiasing, true);
setAcceptDrops(false);
setMouseTracking(true);
_mapScale = new ScaleItem();
_mapScale->setZValue(2.0);
_scene->addItem(_mapScale);
_coordinates = new CoordinatesItem();
_coordinates->setZValue(2.0);
_coordinates->setVisible(false);
_scene->addItem(_coordinates);
_map = map;
_map->load();
@ -50,19 +58,21 @@ MapView::MapView(Map *map, POI *poi, QWidget *parent)
_units = Metric;
_coordinatesFormat = DecimalDegrees;
_opacity = 1.0;
_mapOpacity = 1.0;
_backgroundColor = Qt::white;
_markerColor = Qt::red;
_showMap = true;
_showTracks = true;
_showRoutes = true;
_showAreas = true;
_showWaypoints = true;
_showWaypointLabels = true;
_showPOI = true;
_showPOILabels = true;
_overlapPOIs = true;
_showRouteWaypoints = true;
_showMarkers = true;
_trackWidth = 3;
_routeWidth = 3;
_trackStyle = Qt::SolidLine;
@ -92,12 +102,13 @@ void MapView::centerOn(const QPointF &pos)
QRectF vr(mapToScene(viewport()->rect()).boundingRect());
_res = _map->resolution(vr);
_mapScale->setResolution(_res);
_coordinates->setCoordinates(Coordinates());
}
PathItem *MapView::addTrack(const Track &track)
{
if (track.isNull()) {
_palette.nextColor();
if (!track.isValid()) {
skipColor();
return 0;
}
@ -111,6 +122,7 @@ PathItem *MapView::addTrack(const Track &track)
ti->setVisible(_showTracks);
ti->setDigitalZoom(_digitalZoom);
ti->setMarkerColor(_markerColor);
ti->showMarker(_showMarkers);
_scene->addItem(ti);
if (_showTracks)
@ -121,8 +133,8 @@ PathItem *MapView::addTrack(const Track &track)
PathItem *MapView::addRoute(const Route &route)
{
if (route.isNull()) {
_palette.nextColor();
if (!route.isValid()) {
skipColor();
return 0;
}
@ -139,6 +151,7 @@ PathItem *MapView::addRoute(const Route &route)
ri->showWaypointLabels(_showWaypointLabels);
ri->setDigitalZoom(_digitalZoom);
ri->setMarkerColor(_markerColor);
ri->showMarker(_showMarkers);
_scene->addItem(ri);
if (_showRoutes)
@ -147,6 +160,28 @@ PathItem *MapView::addRoute(const Route &route)
return ri;
}
void MapView::addArea(const Area &area)
{
if (!area.isValid()) {
skipColor();
return;
}
AreaItem *ai = new AreaItem(area, _map);
_areas.append(ai);
_ar |= ai->area().boundingRect();
ai->setColor(_palette.nextColor());
ai->setWidth(_areaWidth);
ai->setStyle(_areaStyle);
ai->setOpacity(_areaOpacity);
ai->setDigitalZoom(_digitalZoom);
ai->setVisible(_showAreas);
_scene->addItem(ai);
if (_showAreas)
addPOI(_poi->points(ai->area()));
}
void MapView::addWaypoints(const QVector<Waypoint> &waypoints)
{
for (int i = 0; i < waypoints.count(); i++) {
@ -175,12 +210,15 @@ QList<PathItem *> MapView::loadData(const Data &data)
int zoom = _map->zoom();
for (int i = 0; i < data.tracks().count(); i++)
paths.append(addTrack(*(data.tracks().at(i))));
paths.append(addTrack(data.tracks().at(i)));
for (int i = 0; i < data.routes().count(); i++)
paths.append(addRoute(*(data.routes().at(i))));
paths.append(addRoute(data.routes().at(i)));
for (int i = 0; i < data.areas().count(); i++)
addArea(data.areas().at(i));
addWaypoints(data.waypoints());
if (_tracks.empty() && _routes.empty() && _waypoints.empty())
if (_tracks.empty() && _routes.empty() && _waypoints.empty()
&& _areas.empty())
return paths;
if (fitMapZoom() != zoom)
@ -195,7 +233,7 @@ QList<PathItem *> MapView::loadData(const Data &data)
int MapView::fitMapZoom() const
{
RectC br = _tr | _rr | _wr;
RectC br = _tr | _rr | _wr | _ar;
return _map->zoomFit(viewport()->size() - QSize(2*MARGIN, 2*MARGIN),
br.isNull() ? RectC(_map->xy2ll(_map->bounds().topLeft()),
@ -204,7 +242,7 @@ int MapView::fitMapZoom() const
QPointF MapView::contentCenter() const
{
RectC br = _tr | _rr | _wr;
RectC br = _tr | _rr | _wr | _ar;
return br.isNull() ? sceneRect().center() : _map->ll2xy(br.center());
}
@ -239,6 +277,8 @@ void MapView::rescale()
_tracks.at(i)->setMap(_map);
for (int i = 0; i < _routes.size(); i++)
_routes.at(i)->setMap(_map);
for (int i = 0; i < _areas.size(); i++)
_areas.at(i)->setMap(_map);
for (int i = 0; i < _waypoints.size(); i++)
_waypoints.at(i)->setMap(_map);
@ -258,6 +298,8 @@ void MapView::setPalette(const Palette &palette)
_tracks.at(i)->setColor(_palette.nextColor());
for (int i = 0; i < _routes.count(); i++)
_routes.at(i)->setColor(_palette.nextColor());
for (int i = 0; i < _areas.count(); i++)
_areas.at(i)->setColor(_palette.nextColor());
}
void MapView::setMap(Map *map)
@ -285,6 +327,8 @@ void MapView::setMap(Map *map)
_tracks.at(i)->setMap(map);
for (int i = 0; i < _routes.size(); i++)
_routes.at(i)->setMap(map);
for (int i = 0; i < _areas.size(); i++)
_areas.at(i)->setMap(map);
for (int i = 0; i < _waypoints.size(); i++)
_waypoints.at(i)->setMap(map);
@ -327,6 +371,9 @@ void MapView::updatePOI()
if (_showRoutes)
for (int i = 0; i < _routes.size(); i++)
addPOI(_poi->points(_routes.at(i)->path()));
if (_showAreas)
for (int i = 0; i < _areas.size(); i++)
addPOI(_poi->points(_areas.at(i)->area()));
if (_showWaypoints)
for (int i = 0; i< _waypoints.size(); i++)
addPOI(_poi->points(_waypoints.at(i)->waypoint()));
@ -384,6 +431,8 @@ void MapView::setCoordinatesFormat(CoordinatesFormat format)
_coordinatesFormat = format;
_coordinates->setFormat(_coordinatesFormat);
for (int i = 0; i < _waypoints.count(); i++)
_waypoints.at(i)->setToolTipFormat(_units, _coordinatesFormat);
for (int i = 0; i < _routes.count(); i++)
@ -419,6 +468,8 @@ void MapView::digitalZoom(int zoom)
_tracks.at(i)->setDigitalZoom(_digitalZoom);
for (int i = 0; i < _routes.size(); i++)
_routes.at(i)->setDigitalZoom(_digitalZoom);
for (int i = 0; i < _areas.size(); i++)
_areas.at(i)->setDigitalZoom(_digitalZoom);
for (int i = 0; i < _waypoints.size(); i++)
_waypoints.at(i)->setDigitalZoom(_digitalZoom);
for (it = _pois.constBegin(); it != _pois.constEnd(); it++)
@ -536,7 +587,7 @@ void MapView::plot(QPainter *painter, const QRectF &target, qreal scale,
painter->device()->logicalDpiY()
/ (qreal)metric(QPaintDevice::PdmDpiY));
adj = QRect(0, 0, adj.width() * s.x(), adj.height() * s.y());
_map->zoomFit(adj.size(), _tr | _rr | _wr);
_map->zoomFit(adj.size(), _tr | _rr | _wr | _ar);
rescale();
QPointF center = contentCenter();
@ -579,17 +630,21 @@ void MapView::clear()
_pois.clear();
_tracks.clear();
_routes.clear();
_areas.clear();
_waypoints.clear();
_scene->removeItem(_mapScale);
_scene->removeItem(_coordinates);
_scene->clear();
_scene->addItem(_mapScale);
_scene->addItem(_coordinates);
_palette.reset();
_tr = RectC();
_rr = RectC();
_wr = RectC();
_ar = RectC();
digitalZoom(0);
@ -627,13 +682,22 @@ void MapView::showWaypoints(bool show)
updatePOI();
}
void MapView::showAreas(bool show)
{
_showAreas = show;
for (int i = 0; i < _areas.count(); i++)
_areas.at(i)->setVisible(show);
updatePOI();
}
void MapView::showWaypointLabels(bool show)
{
_showWaypointLabels = show;
for (int i = 0; i < _waypoints.size(); i++)
_waypoints.at(i)->showLabel(show);
for (int i = 0; i < _routes.size(); i++)
_routes.at(i)->showWaypointLabels(show);
}
@ -646,6 +710,16 @@ void MapView::showRouteWaypoints(bool show)
_routes.at(i)->showWaypoints(show);
}
void MapView::showMarkers(bool show)
{
_showMarkers = show;
for (int i = 0; i < _tracks.size(); i++)
_tracks.at(i)->showMarker(show);
for (int i = 0; i < _routes.size(); i++)
_routes.at(i)->showMarker(show);
}
void MapView::showMap(bool show)
{
_showMap = show;
@ -674,6 +748,11 @@ void MapView::showPOILabels(bool show)
updatePOIVisibility();
}
void MapView::showCoordinates(bool show)
{
_coordinates->setVisible(show);
}
void MapView::setPOIOverlap(bool overlap)
{
_overlapPOIs = overlap;
@ -697,6 +776,14 @@ void MapView::setRouteWidth(int width)
_routes.at(i)->setWidth(width);
}
void MapView::setAreaWidth(int width)
{
_areaWidth = width;
for (int i = 0; i < _areas.count(); i++)
_areas.at(i)->setWidth(width);
}
void MapView::setTrackStyle(Qt::PenStyle style)
{
_trackStyle = style;
@ -713,6 +800,22 @@ void MapView::setRouteStyle(Qt::PenStyle style)
_routes.at(i)->setStyle(style);
}
void MapView::setAreaStyle(Qt::PenStyle style)
{
_areaStyle = style;
for (int i = 0; i < _areas.count(); i++)
_areas.at(i)->setStyle(style);
}
void MapView::setAreaOpacity(int opacity)
{
_areaOpacity = opacity / 100.0;
for (int i = 0; i < _areas.count(); i++)
_areas.at(i)->setOpacity(_areaOpacity);
}
void MapView::setWaypointSize(int size)
{
_waypointSize = size;
@ -751,7 +854,7 @@ void MapView::setPOIColor(const QColor &color)
void MapView::setMapOpacity(int opacity)
{
_opacity = opacity / 100.0;
_mapOpacity = opacity / 100.0;
reloadMap();
}
@ -769,8 +872,8 @@ void MapView::drawBackground(QPainter *painter, const QRectF &rect)
QRectF ir = rect.intersected(_map->bounds());
Map::Flags flags = Map::NoFlags;
if (_opacity < 1.0)
painter->setOpacity(_opacity);
if (_mapOpacity < 1.0)
painter->setOpacity(_mapOpacity);
if (_plot)
flags = Map::Block;
@ -794,11 +897,18 @@ void MapView::resizeEvent(QResizeEvent *event)
void MapView::paintEvent(QPaintEvent *event)
{
QPointF scenePos = mapToScene(rect().bottomRight() + QPoint(
QPointF scaleScenePos = mapToScene(rect().bottomRight() + QPoint(
-(SCALE_OFFSET + _mapScale->boundingRect().width()),
-(SCALE_OFFSET + _mapScale->boundingRect().height())));
if (_mapScale->pos() != scenePos && !_plot)
_mapScale->setPos(scenePos);
if (_mapScale->pos() != scaleScenePos && !_plot)
_mapScale->setPos(scaleScenePos);
if (_coordinates->isVisible()) {
QPointF coordinatesScenePos = mapToScene(rect().bottomLeft()
+ QPoint(COORDINATES_OFFSET, -COORDINATES_OFFSET));
if (_coordinates->pos() != coordinatesScenePos && !_plot)
_coordinates->setPos(coordinatesScenePos);
}
QGraphicsView::paintEvent(event);
}
@ -816,6 +926,20 @@ void MapView::scrollContentsBy(int dx, int dy)
}
}
void MapView::mouseMoveEvent(QMouseEvent *event)
{
if (_coordinates->isVisible())
_coordinates->setCoordinates(_map->xy2ll(mapToScene(event->pos())));
QGraphicsView::mouseMoveEvent(event);
}
void MapView::leaveEvent(QEvent *event)
{
_coordinates->setCoordinates(Coordinates());
QGraphicsView::leaveEvent(event);
}
void MapView::useOpenGL(bool use)
{
_opengl = use;
@ -867,6 +991,8 @@ void MapView::setDevicePixelRatio(qreal deviceRatio, qreal mapRatio)
_tracks.at(i)->setMap(_map);
for (int i = 0; i < _routes.size(); i++)
_routes.at(i)->setMap(_map);
for (int i = 0; i < _areas.size(); i++)
_areas.at(i)->setMap(_map);
for (int i = 0; i < _waypoints.size(); i++)
_waypoints.at(i)->setMap(_map);

View File

@ -12,6 +12,7 @@
#include "units.h"
#include "format.h"
#include "palette.h"
#include "data/polygon.h"
class Data;
class POI;
@ -22,8 +23,11 @@ class TrackItem;
class RouteItem;
class WaypointItem;
class ScaleItem;
class CoordinatesItem;
class PathItem;
class GraphItem;
class AreaItem;
class Area;
class MapView : public QGraphicsView
{
@ -46,8 +50,11 @@ public:
void setMarkerColor(const QColor &color);
void setTrackWidth(int width);
void setRouteWidth(int width);
void setAreaWidth(int width);
void setTrackStyle(Qt::PenStyle style);
void setRouteStyle(Qt::PenStyle style);
void setAreaStyle(Qt::PenStyle style);
void setAreaOpacity(int opacity);
void setWaypointSize(int size);
void setWaypointColor(const QColor &color);
void setPOISize(int size);
@ -65,8 +72,11 @@ public slots:
void showPOILabels(bool show);
void showTracks(bool show);
void showRoutes(bool show);
void showAreas(bool show);
void showWaypoints(bool show);
void showRouteWaypoints(bool show);
void showMarkers(bool show);
void showCoordinates(bool show);
void clearMapCache();
void setCoordinatesFormat(CoordinatesFormat format);
void setDevicePixelRatio(qreal deviceRatio, qreal mapRatio);
@ -78,6 +88,7 @@ private slots:
private:
PathItem *addTrack(const Track &track);
PathItem *addRoute(const Route &route);
void addArea(const Area &area);
void addWaypoints(const QVector<Waypoint> &waypoints);
void addPOI(const QList<Waypoint> &waypoints);
void loadPOI();
@ -90,6 +101,7 @@ private:
void zoom(int zoom, const QPoint &pos);
void digitalZoom(int zoom);
void updatePOIVisibility();
void skipColor() {_palette.nextColor();}
void mouseDoubleClickEvent(QMouseEvent *event);
void wheelEvent(QWheelEvent *event);
@ -98,43 +110,38 @@ private:
void resizeEvent(QResizeEvent *event);
void paintEvent(QPaintEvent *event);
void scrollContentsBy(int dx, int dy);
void mouseMoveEvent(QMouseEvent *event);
void leaveEvent(QEvent *event);
QGraphicsScene *_scene;
ScaleItem *_mapScale;
CoordinatesItem *_coordinates;
QList<TrackItem*> _tracks;
QList<RouteItem*> _routes;
QList<WaypointItem*> _waypoints;
QList<AreaItem*> _areas;
QHash<SearchPointer<Waypoint>, WaypointItem*> _pois;
RectC _tr, _rr, _wr;
RectC _tr, _rr, _wr, _ar;
qreal _res;
Map *_map;
POI *_poi;
Palette _palette;
Units _units;
CoordinatesFormat _coordinatesFormat;
qreal _mapOpacity;
qreal _opacity;
QColor _backgroundColor;
bool _showMap;
bool _showTracks;
bool _showRoutes;
bool _showWaypoints;
bool _showWaypointLabels;
bool _showPOI;
bool _showPOILabels;
bool _showMap, _showTracks, _showRoutes, _showAreas, _showWaypoints,
_showWaypointLabels, _showPOI, _showPOILabels, _showRouteWaypoints,
_showMarkers;
bool _overlapPOIs;
bool _showRouteWaypoints;
int _trackWidth;
int _routeWidth;
Qt::PenStyle _trackStyle;
Qt::PenStyle _routeStyle;
int _waypointSize;
int _poiSize;
QColor _waypointColor;
QColor _poiColor;
QColor _markerColor;
int _trackWidth, _routeWidth, _areaWidth;
Qt::PenStyle _trackStyle, _routeStyle, _areaStyle;
int _waypointSize, _poiSize;
QColor _backgroundColor, _waypointColor, _poiColor, _markerColor;
qreal _areaOpacity;
int _digitalZoom;
bool _plot;

View File

@ -93,22 +93,7 @@ QWidget *OptionsDialog::createMapPage()
QWidget *OptionsDialog::createAppearancePage()
{
// Paths
_baseColor = new ColorBox();
_baseColor->setColor(_options->palette.color());
_colorOffset = new QDoubleSpinBox();
_colorOffset->setMinimum(0);
_colorOffset->setMaximum(1.0);
_colorOffset->setSingleStep(0.01);
_colorOffset->setValue(_options->palette.shift());
QFormLayout *paletteLayout = new QFormLayout();
paletteLayout->addRow(tr("Base color:"), _baseColor);
paletteLayout->addRow(tr("Palette shift:"), _colorOffset);
#ifndef Q_OS_MAC
QGroupBox *colorBox = new QGroupBox(tr("Colors"));
colorBox->setLayout(paletteLayout);
#endif // Q_OS_MAC
// Tracks
_trackWidth = new QSpinBox();
_trackWidth->setValue(_options->trackWidth);
_trackWidth->setMinimum(1);
@ -125,6 +110,7 @@ QWidget *OptionsDialog::createAppearancePage()
trackBox->setLayout(trackLayout);
#endif // Q_OS_MAC
// Routes
_routeWidth = new QSpinBox();
_routeWidth->setValue(_options->routeWidth);
_routeWidth->setMinimum(1);
@ -141,6 +127,38 @@ QWidget *OptionsDialog::createAppearancePage()
routeBox->setLayout(routeLayout);
#endif // Q_OS_MAC
// Areas
_areaWidth = new QSpinBox();
_areaWidth->setValue(_options->areaWidth);
_areaStyle = new StyleComboBox();
_areaStyle->setValue(_options->areaStyle);
_areaOpacity = new PercentSlider();
_areaOpacity->setValue(_options->areaOpacity);
QFormLayout *areaLayout = new QFormLayout();
#ifdef Q_OS_MAC
areaLayout->addRow(tr("Area border width:"), _areaWidth);
areaLayout->addRow(tr("Area border style:"), _areaStyle);
areaLayout->addRow(tr("Area fill opacity:"), _areaOpacity);
#else // Q_OS_MAC
areaLayout->addRow(tr("Width:"), _areaWidth);
areaLayout->addRow(tr("Style:"), _areaStyle);
areaLayout->addRow(tr("Fill opacity:"), _areaOpacity);
QGroupBox *areaBox = new QGroupBox(tr("Areas"));
areaBox->setLayout(areaLayout);
#endif // Q_OS_MAC
// Palette & antialiasing
_baseColor = new ColorBox();
_baseColor->setColor(_options->palette.color());
_colorOffset = new QDoubleSpinBox();
_colorOffset->setMinimum(0);
_colorOffset->setMaximum(1.0);
_colorOffset->setSingleStep(0.01);
_colorOffset->setValue(_options->palette.shift());
QFormLayout *paletteLayout = new QFormLayout();
paletteLayout->addRow(tr("Base color:"), _baseColor);
paletteLayout->addRow(tr("Palette shift:"), _colorOffset);
_pathAA = new QCheckBox(tr("Use anti-aliasing"));
_pathAA->setChecked(_options->pathAntiAliasing);
QFormLayout *pathAALayout = new QFormLayout();
@ -149,17 +167,18 @@ QWidget *OptionsDialog::createAppearancePage()
QWidget *pathTab = new QWidget();
QVBoxLayout *pathTabLayout = new QVBoxLayout();
#ifdef Q_OS_MAC
pathTabLayout->addLayout(paletteLayout);
pathTabLayout->addWidget(line());
pathTabLayout->addLayout(trackLayout);
pathTabLayout->addWidget(line());
pathTabLayout->addLayout(routeLayout);
pathTabLayout->addWidget(line());
pathTabLayout->addLayout(areaLayout);
pathTabLayout->addWidget(line());
#else // Q_OS_MAC
pathTabLayout->addWidget(colorBox);
pathTabLayout->addWidget(trackBox);
pathTabLayout->addWidget(routeBox);
pathTabLayout->addWidget(areaBox);
#endif // Q_OS_MAC
pathTabLayout->addLayout(paletteLayout);
pathTabLayout->addLayout(pathAALayout);
pathTabLayout->addStretch();
pathTab->setLayout(pathTabLayout);
@ -298,10 +317,6 @@ QWidget *OptionsDialog::createDataPage()
QFormLayout *outlierLayout = new QFormLayout();
outlierLayout->addWidget(_outlierEliminate);
#ifndef Q_OS_MAC
QGroupBox *outlierBox = new QGroupBox(tr("Outlier elimination"));
outlierBox->setLayout(outlierLayout);
#endif // Q_OS_MAC
QWidget *filterTab = new QWidget();
QVBoxLayout *filterTabLayout = new QVBoxLayout();
@ -309,11 +324,10 @@ QWidget *OptionsDialog::createDataPage()
filterTabLayout->addWidget(new QLabel(tr("Smoothing:")));
filterTabLayout->addLayout(smoothLayout);
filterTabLayout->addWidget(line());
filterTabLayout->addLayout(outlierLayout);
#else // Q_OS_MAC
filterTabLayout->addWidget(smoothBox);
filterTabLayout->addWidget(outlierBox);
#endif // Q_OS_MAC
filterTabLayout->addLayout(outlierLayout);
filterTabLayout->addStretch();
filterTab->setLayout(filterTabLayout);
@ -630,6 +644,10 @@ void OptionsDialog::accept()
_options->routeStyle = (Qt::PenStyle) _routeStyle->itemData(
_routeStyle->currentIndex()).toInt();
_options->pathAntiAliasing = _pathAA->isChecked();
_options->areaWidth = _areaWidth->value();
_options->areaStyle = (Qt::PenStyle) _areaStyle->itemData(
_areaStyle->currentIndex()).toInt();
_options->areaOpacity = _areaOpacity->value();
_options->waypointSize = _waypointSize->value();
_options->waypointColor = _waypointColor->color();
_options->poiSize = _poiSize->value();

View File

@ -21,8 +21,11 @@ struct Options {
Palette palette;
int trackWidth;
int routeWidth;
int areaWidth;
Qt::PenStyle trackStyle;
Qt::PenStyle routeStyle;
Qt::PenStyle areaStyle;
int areaOpacity;
QColor waypointColor;
QColor poiColor;
int waypointSize;
@ -101,6 +104,9 @@ private:
StyleComboBox *_trackStyle;
QSpinBox *_routeWidth;
StyleComboBox *_routeStyle;
QSpinBox *_areaWidth;
StyleComboBox *_areaStyle;
PercentSlider *_areaOpacity;
QCheckBox *_pathAA;
QSpinBox *_waypointSize;
ColorBox *_waypointColor;

View File

@ -8,30 +8,33 @@
#define GEOGRAPHICAL_MILE 1855.3248
static unsigned segments(qreal distance)
static inline bool isValid(const QPointF &p)
{
return (!std::isnan(p.x()) && !std::isnan(p.y()));
}
static inline unsigned segments(qreal distance)
{
return ceil(distance / GEOGRAPHICAL_MILE);
}
PathItem::PathItem(const Path &path, Map *map, QGraphicsItem *parent)
: QGraphicsObject(parent)
: QGraphicsObject(parent), _path(path), _map(map)
{
Q_ASSERT(path.count() >= 2);
Q_ASSERT(_path.isValid());
_path = path;
_map = map;
_digitalZoom = 0;
_width = 3;
QBrush brush(Qt::SolidPattern);
_pen = QPen(brush, _width);
_showMarker = true;
updatePainterPath();
updateShape();
_markerDistance = _path.first().first().distance();
_marker = new MarkerItem(this);
_marker->setPos(position(_path.at(0).distance()));
_markerDistance = _path.at(0).distance();
_marker->setPos(position(_markerDistance));
setCursor(Qt::ArrowCursor);
setAcceptHoverEvents(true);
@ -74,23 +77,27 @@ void PathItem::updatePainterPath()
{
_painterPath = QPainterPath();
_painterPath.moveTo(_map->ll2xy(_path.first().coordinates()));
for (int i = 1; i < _path.size(); i++) {
const PathPoint &p1 = _path.at(i-1);
const PathPoint &p2 = _path.at(i);
unsigned n = segments(p2.distance() - p1.distance());
for (int i = 0; i < _path.size(); i++) {
const PathSegment &segment = _path.at(i);
_painterPath.moveTo(_map->ll2xy(segment.first().coordinates()));
if (n > 1) {
GreatCircle gc(p1.coordinates(), p2.coordinates());
Coordinates last = p1.coordinates();
for (int j = 1; j < segment.size(); j++) {
const PathPoint &p1 = segment.at(j-1);
const PathPoint &p2 = segment.at(j);
unsigned n = segments(p2.distance() - p1.distance());
for (unsigned j = 1; j <= n; j++) {
Coordinates c(gc.pointAt(j/(double)n));
addSegment(last, c);
last = c;
}
} else
addSegment(p1.coordinates(), p2.coordinates());
if (n > 1) {
GreatCircle gc(p1.coordinates(), p2.coordinates());
Coordinates last = p1.coordinates();
for (unsigned k = 1; k <= n; k++) {
Coordinates c(gc.pointAt(k/(double)n));
addSegment(last, c);
last = c;
}
} else
addSegment(p1.coordinates(), p2.coordinates());
}
}
}
@ -119,7 +126,9 @@ void PathItem::setMap(Map *map)
updatePainterPath();
updateShape();
_marker->setPos(position(_markerDistance));
QPointF pos = position(_markerDistance);
if (isValid(pos))
_marker->setPos(pos);
}
void PathItem::setColor(const QColor &color)
@ -167,35 +176,48 @@ void PathItem::setDigitalZoom(int zoom)
updateShape();
}
const PathSegment *PathItem::segment(qreal x) const
{
for (int i = 0; i < _path.size(); i++)
if (x <= _path.at(i).last().distance())
return &(_path.at(i));
return 0;
}
QPointF PathItem::position(qreal x) const
{
const PathSegment *seg = segment(x);
if (!seg)
return QPointF(NAN, NAN);
int low = 0;
int high = _path.count() - 1;
int high = seg->count() - 1;
int mid = 0;
Q_ASSERT(high > low);
Q_ASSERT(x >= _path.at(low).distance() && x <= _path.at(high).distance());
if (!(x >= seg->first().distance() && x <= seg->last().distance()))
return QPointF(NAN, NAN);
while (low <= high) {
mid = low + ((high - low) / 2);
qreal val = _path.at(mid).distance();
qreal val = seg->at(mid).distance();
if (val > x)
high = mid - 1;
else if (val < x)
low = mid + 1;
else
return _map->ll2xy(_path.at(mid).coordinates());
return _map->ll2xy(seg->at(mid).coordinates());
}
Coordinates c1, c2;
qreal p1, p2;
if (_path.at(mid).distance() < x) {
c1 = _path.at(mid).coordinates(); c2 = _path.at(mid+1).coordinates();
p1 = _path.at(mid).distance(); p2 = _path.at(mid+1).distance();
if (seg->at(mid).distance() < x) {
c1 = seg->at(mid).coordinates(); c2 = seg->at(mid+1).coordinates();
p1 = seg->at(mid).distance(); p2 = seg->at(mid+1).distance();
} else {
c1 = _path.at(mid-1).coordinates(); c2 = _path.at(mid).coordinates();
p1 = _path.at(mid-1).distance(); p2 = _path.at(mid).distance();
c1 = seg->at(mid-1).coordinates(); c2 = seg->at(mid).coordinates();
p1 = seg->at(mid-1).distance(); p2 = seg->at(mid).distance();
}
unsigned n = segments(p2 - p1);
@ -225,11 +247,12 @@ QPointF PathItem::position(qreal x) const
void PathItem::moveMarker(qreal distance)
{
if (distance >= _path.first().distance()
&& distance <= _path.last().distance()) {
_marker->setVisible(true);
_marker->setPos(position(distance));
_markerDistance = distance;
_markerDistance = distance;
QPointF pos(position(distance));
if (isValid(pos)) {
_marker->setVisible(_showMarker);
_marker->setPos(pos);
} else
_marker->setVisible(false);
}
@ -252,6 +275,15 @@ void PathItem::hover(bool hover)
update();
}
void PathItem::showMarker(bool show)
{
if (_showMarker == show)
return;
_showMarker = show;
_marker->setVisible(show && isValid(position(_markerDistance)));
}
void PathItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event);

View File

@ -29,6 +29,7 @@ public:
void setStyle(Qt::PenStyle style);
void setDigitalZoom(int zoom);
void setMarkerColor(const QColor &color);
void showMarker(bool show);
public slots:
void moveMarker(qreal distance);
@ -42,6 +43,7 @@ protected:
MarkerItem *_marker;
private:
const PathSegment *segment(qreal x) const;
QPointF position(qreal distance) const;
void updatePainterPath();
void updateShape();
@ -59,6 +61,7 @@ private:
QPen _pen;
QPainterPath _shape;
QPainterPath _painterPath;
bool _showMarker;
};
#endif // PATHITEM_H

View File

@ -22,6 +22,7 @@ PercentSlider::PercentSlider(QWidget *parent) : QWidget(parent)
QFontMetrics fm(_label->font());
_label->setFixedWidth(fm.boundingRect(format(_slider->maximum())).width());
_label->setAlignment(Qt::AlignRight);
_label->setText(format(_slider->value()));
connect(_slider, SIGNAL(sliderMoved(int)), this, SLOT(updateLabel(int)));

View File

@ -32,15 +32,16 @@ QList<GraphItem*> PowerGraph::loadData(const Data &data)
QList<GraphItem*> graphs;
for (int i = 0; i < data.tracks().count(); i++) {
const Graph &graph = data.tracks().at(i)->power();
const Track &track = data.tracks().at(i);
const Graph &graph = track.power();
if (graph.size() < 2) {
if (!graph.isValid()) {
skipColor();
graphs.append(0);
} else {
PowerGraphItem *gi = new PowerGraphItem(graph, _graphType);
GraphView::addGraph(gi);
_avg.append(QPointF(data.tracks().at(i)->distance(), gi->avg()));
_avg.append(QPointF(track.distance(), gi->avg()));
graphs.append(gi);
}
}
@ -50,6 +51,9 @@ QList<GraphItem*> PowerGraph::loadData(const Data &data)
graphs.append(0);
}
for (int i = 0; i < data.areas().count(); i++)
skipColor();
setInfo();
redraw();

View File

@ -6,17 +6,6 @@
PowerGraphItem::PowerGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent) : GraphItem(graph, type, parent)
{
qreal sum = 0;
_max = graph.first().y();
for (int i = 1; i < graph.size(); i++) {
qreal y = graph.at(i).y();
sum += y * (graph.at(i).s() - graph.at(i-1).s());
if (y > _max)
_max = y;
}
_avg = sum/graph.last().s();
setToolTip(toolTip());
}

View File

@ -11,13 +11,8 @@ public:
PowerGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent = 0);
qreal max() const {return _max;}
qreal avg() const {return _avg;}
private:
QString toolTip() const;
qreal _avg, _max;
};
#endif // POWERGRAPHITEM_H

View File

@ -15,7 +15,8 @@ QString RouteItem::toolTip(Units units) const
tt.insert(tr("Name"), _name);
if (!_desc.isEmpty())
tt.insert(tr("Description"), _desc);
tt.insert(tr("Distance"), Format::distance(_path.last().distance(), units));
tt.insert(tr("Distance"), Format::distance(_path.last().last().distance(),
units));
return tt.toString();
}

View File

@ -9,6 +9,7 @@
#define WINDOW_SIZE_DEFAULT QSize(600, 800)
#define WINDOW_POS_SETTING "pos"
#define WINDOW_POS_DEFAULT QPoint(10, 10)
#define WINDOW_STATE_SETTING "state"
#define SETTINGS_SETTINGS_GROUP "Settings"
#define TIME_TYPE_SETTING "timeType"
@ -29,11 +30,15 @@
#define SHOW_GRAPH_GRIDS_DEFAULT true
#define SHOW_GRAPH_SLIDER_INFO_SETTING "sliderInfo"
#define SHOW_GRAPH_SLIDER_INFO_DEFAULT true
#define SHOW_MARKERS_SETTING "pathMarkers"
#define SHOW_MARKERS_DEFAULT true
#define MAP_SETTINGS_GROUP "Map"
#define CURRENT_MAP_SETTING "map"
#define SHOW_MAP_SETTING "show"
#define SHOW_MAP_DEFAULT true
#define SHOW_COORDINATES_SETTING "coordinates"
#define SHOW_COORDINATES_DEFAULT false
#define POI_SETTINGS_GROUP "POI"
#define OVERLAP_POI_SETTING "overlap"
@ -52,6 +57,8 @@
#define SHOW_ROUTES_DEFAULT true
#define SHOW_WAYPOINTS_SETTING "waypoints"
#define SHOW_WAYPOINTS_DEFAULT true
#define SHOW_AREAS_SETTING "areas"
#define SHOW_AREAS_DEFAULT true
#define SHOW_ROUTE_WAYPOINTS_SETTING "routeWaypoints"
#define SHOW_ROUTE_WAYPOINTS_DEFAULT true
#define SHOW_WAYPOINT_LABELS_SETTING "waypointLabels"
@ -90,10 +97,16 @@
#define TRACK_WIDTH_DEFAULT 3
#define ROUTE_WIDTH_SETTING "routeWidth"
#define ROUTE_WIDTH_DEFAULT 3
#define AREA_WIDTH_SETTING "areaWidth"
#define AREA_WIDTH_DEFAULT 2
#define TRACK_STYLE_SETTING "trackStyle"
#define TRACK_STYLE_DEFAULT Qt::SolidLine
#define ROUTE_STYLE_SETTING "routeStyle"
#define ROUTE_STYLE_DEFAULT Qt::DotLine
#define AREA_STYLE_SETTING "areaStyle"
#define AREA_STYLE_DEFAULT Qt::SolidLine
#define AREA_OPACITY_SETTING "areaOpacity"
#define AREA_OPACITY_DEFAULT 50
#define WAYPOINT_SIZE_SETTING "waypointSize"
#define WAYPOINT_SIZE_DEFAULT 8
#define WAYPOINT_COLOR_SETTING "waypointColor"

View File

@ -40,19 +40,19 @@ QList<GraphItem*> SpeedGraph::loadData(const Data &data)
QList<GraphItem*> graphs;
for (int i = 0; i < data.tracks().count(); i++) {
const Track *track = data.tracks().at(i);
const Graph &graph = track->speed();
const Track &track = data.tracks().at(i);
const Graph &graph = track.speed();
if (graph.size() < 2) {
if (!graph.isValid()) {
skipColor();
graphs.append(0);
} else {
SpeedGraphItem *gi = new SpeedGraphItem(graph, _graphType,
track->movingTime());
track.movingTime());
gi->setTimeType(_timeType);
GraphView::addGraph(gi);
_avg.append(QPointF(track->distance(), gi->avg()));
_mavg.append(QPointF(track->distance(), gi->mavg()));
_avg.append(QPointF(track.distance(), gi->avg()));
_mavg.append(QPointF(track.distance(), gi->mavg()));
graphs.append(gi);
}
}
@ -62,6 +62,9 @@ QList<GraphItem*> SpeedGraph::loadData(const Data &data)
graphs.append(0);
}
for (int i = 0; i < data.areas().count(); i++)
skipColor();
setInfo();
redraw();

View File

@ -10,15 +10,9 @@ SpeedGraphItem::SpeedGraphItem(const Graph &graph, GraphType type,
_units = Metric;
_timeType = Total;
_avg = graph.last().s() / graph.last().t();
_mavg = graph.last().s() / movingTime;
_max = graph.first().y();
for (int i = 1; i < graph.size(); i++) {
qreal y = graph.at(i).y();
if (y > _max)
_max = y;
}
_max = GraphItem::max();
_avg = graph.last().last().s() / graph.last().last().t();
_mavg = graph.last().last().s() / movingTime;
setToolTip(toolTip());
}

View File

@ -12,9 +12,9 @@ public:
SpeedGraphItem(const Graph &graph, GraphType type, qreal movingTime,
QGraphicsItem *parent = 0);
qreal max() const {return _max;}
qreal avg() const {return _avg;}
qreal mavg() const {return _mavg;}
qreal max() const {return _max;}
void setUnits(Units units);
void setTimeType(TimeType type);

View File

@ -34,16 +34,17 @@ QList<GraphItem*> TemperatureGraph::loadData(const Data &data)
QList<GraphItem*> graphs;
for (int i = 0; i < data.tracks().count(); i++) {
const Graph &graph = data.tracks().at(i)->temperature();
const Track &track = data.tracks().at(i);
const Graph &graph = track.temperature();
if (graph.size() < 2) {
if (!graph.isValid()) {
skipColor();
graphs.append(0);
} else {
TemperatureGraphItem *gi = new TemperatureGraphItem(graph,
_graphType);
GraphView::addGraph(gi);
_avg.append(QPointF(data.tracks().at(i)->distance(), gi->avg()));
_avg.append(QPointF(track.distance(), gi->avg()));
graphs.append(gi);
}
}
@ -53,6 +54,9 @@ QList<GraphItem*> TemperatureGraph::loadData(const Data &data)
graphs.append(0);
}
for (int i = 0; i < data.areas().count(); i++)
skipColor();
setInfo();
redraw();

View File

@ -6,20 +6,9 @@
TemperatureGraphItem::TemperatureGraphItem(const Graph &graph, GraphType type,
QGraphicsItem *parent) : GraphItem(graph, type, parent)
{
qreal sum = 0;
_min = _max = graph.first().y();
for (int j = 1; j < graph.size(); j++) {
qreal y = graph.at(j).y();
sum += graph.at(j).y() * (graph.at(j).s() - graph.at(j-1).s());
if (y > _max)
_max = y;
if (y < _min)
_min = y;
}
_avg = sum/graph.last().s();
_min = GraphItem::min();
_max = GraphItem::max();
_avg = GraphItem::avg();
setToolTip(toolTip(Metric));
}

View File

@ -20,7 +20,7 @@ public:
private:
QString toolTip(Units units) const;
qreal _avg, _min, _max;
qreal _min, _max, _avg;
};
#endif // TEMPERATUREGRAPHITEM_H

View File

@ -7,6 +7,9 @@ void ToolTip::insert(const QString &key, const QString &value)
QString ToolTip::toString()
{
if (_list.isEmpty())
return QString();
QString ret = "<table>";
for (int i = 0; i < _list.count(); i++)

View File

@ -13,7 +13,8 @@ QString TrackItem::toolTip(Units units) const
tt.insert(tr("Name"), _name);
if (!_desc.isEmpty())
tt.insert(tr("Description"), _desc);
tt.insert(tr("Distance"), Format::distance(_path.last().distance(), units));
tt.insert(tr("Distance"), Format::distance(_path.last().last().distance(),
units));
if (_time > 0)
tt.insert(tr("Total time"), Format::timeSpan(_time));
if (_movingTime > 0)

39
src/data/area.h Normal file
View File

@ -0,0 +1,39 @@
#ifndef AREA_H
#define AREA_H
#include <QString>
#include <QList>
#include "polygon.h"
class Area : public QList<Polygon>
{
public:
const QString& name() const {return _name;}
const QString& description() const {return _desc;}
void setName(const QString &name) {_name = name;}
void setDescription(const QString &desc) {_desc = desc;}
bool isValid() const
{
if (isEmpty())
return false;
for (int i = 0; i < size(); i++)
if (!at(i).isValid())
return false;
return true;
}
RectC boundingRect() const
{
RectC ret;
for (int i = 0; i < size(); i++)
ret |= at(i).boundingRect();
return ret;
}
private:
QString _name;
QString _desc;
};
#endif // AREA_H

View File

@ -1,10 +1,12 @@
#include "csvparser.h"
bool CSVParser::parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QVector<Waypoint> &waypoints)
QList<RouteData> &routes, QList<Area> &polygons,
QVector<Waypoint> &waypoints)
{
Q_UNUSED(tracks);
Q_UNUSED(routes);
Q_UNUSED(polygons);
bool res;
_errorLine = 1;

View File

@ -9,7 +9,7 @@ public:
CSVParser() : _errorLine(0) {}
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
QVector<Waypoint> &waypoints);
QList<Area> &polygons, QVector<Waypoint> &waypoints);
QString errorString() const {return _errorString;}
int errorLine() const {return _errorLine;}

View File

@ -63,20 +63,13 @@ static QHash<QString, Parser*> parsers()
QHash<QString, Parser*> Data::_parsers = parsers();
bool Data::_useDEM = false;
Data::~Data()
void Data::processData(const QList<TrackData> &trackData,
const QList<RouteData> &routeData)
{
for (int i = 0; i < _tracks.count(); i++)
delete _tracks.at(i);
for (int i = 0; i < _routes.count(); i++)
delete _routes.at(i);
}
void Data::processData()
{
for (int i = 0; i < _trackData.count(); i++)
_tracks.append(new Track(_trackData.at(i)));
for (int i = 0; i < _routeData.count(); i++)
_routes.append(new Route(_routeData.at(i)));
for (int i = 0; i < trackData.count(); i++)
_tracks.append(Track(trackData.at(i)));
for (int i = 0; i < routeData.count(); i++)
_routes.append(Route(routeData.at(i)));
for (int i = 0; i < _waypoints.size(); i++) {
if (!_waypoints.at(i).hasElevation() || _useDEM) {
qreal elevation = DEM::elevation(_waypoints.at(i).coordinates());
@ -90,6 +83,8 @@ Data::Data(const QString &fileName, bool poi)
{
QFile file(fileName);
QFileInfo fi(fileName);
QList<TrackData> trackData;
QList<RouteData> routeData;
_valid = false;
_errorLine = 0;
@ -101,9 +96,10 @@ Data::Data(const QString &fileName, bool poi)
QHash<QString, Parser*>::iterator it;
if ((it = _parsers.find(fi.suffix().toLower())) != _parsers.end()) {
if (it.value()->parse(&file, _trackData, _routeData, _waypoints)) {
if (it.value()->parse(&file, trackData, routeData, _polygons,
_waypoints)) {
if (!poi)
processData();
processData(trackData, routeData);
_valid = true;
return;
} else {
@ -112,9 +108,10 @@ Data::Data(const QString &fileName, bool poi)
}
} else {
for (it = _parsers.begin(); it != _parsers.end(); it++) {
if (it.value()->parse(&file, _trackData, _routeData, _waypoints)) {
if (it.value()->parse(&file, trackData, routeData, _polygons,
_waypoints)) {
if (!poi)
processData();
processData(trackData, routeData);
_valid = true;
return;
}

View File

@ -15,15 +15,15 @@ class Data
{
public:
Data(const QString &fileName, bool poi = false);
~Data();
bool isValid() const {return _valid;}
const QString &errorString() const {return _errorString;}
int errorLine() const {return _errorLine;}
const QList<Track*> &tracks() const {return _tracks;}
const QList<Route*> &routes() const {return _routes;}
const QList<Track> &tracks() const {return _tracks;}
const QList<Route> &routes() const {return _routes;}
const QVector<Waypoint> &waypoints() const {return _waypoints;}
const QList<Area> &areas() const {return _polygons;}
static QString formats();
static QStringList filter();
@ -31,19 +31,18 @@ public:
static void useDEM(bool use);
private:
void processData();
void processData(const QList<TrackData> &trackData,
const QList<RouteData> &routeData);
bool _valid;
QString _errorString;
int _errorLine;
QList<Track*> _tracks;
QList<Route*> _routes;
QList<Track> _tracks;
QList<Route> _routes;
QList<Area> _polygons;
QVector<Waypoint> _waypoints;
QList<TrackData> _trackData;
QList<RouteData> _routeData;
static QHash<QString, Parser*> _parsers;
static bool _useDEM;
};

View File

@ -58,7 +58,7 @@ public:
MessageDefinition defs[16];
qreal ratio;
Trackpoint trackpoint;
TrackData track;
SegmentData segment;
};
@ -306,7 +306,7 @@ bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
ctx.trackpoint.setTimestamp(QDateTime::fromTime_t(ctx.timestamp
+ 631065600));
ctx.trackpoint.setRatio(ctx.ratio);
ctx.track.append(ctx.trackpoint);
ctx.segment.append(ctx.trackpoint);
ctx.trackpoint = Trackpoint();
ctx.lastWrite = ctx.timestamp;
}
@ -372,10 +372,12 @@ bool FITParser::parseHeader(CTX &ctx)
}
bool FITParser::parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QVector<Waypoint> &waypoints)
QList<RouteData> &routes,
QList<Area> &polygons, QVector<Waypoint> &waypoints)
{
Q_UNUSED(routes);
Q_UNUSED(waypoints);
Q_UNUSED(polygons);
CTX ctx(file);
@ -386,7 +388,8 @@ bool FITParser::parse(QFile *file, QList<TrackData> &tracks,
if (!parseRecord(ctx))
return false;
tracks.append(ctx.track);
tracks.append(TrackData());
tracks.last().append(ctx.segment);
return true;
}

View File

@ -9,7 +9,7 @@ class FITParser : public Parser
{
public:
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
QVector<Waypoint> &waypoints);
QList<Area> &polygons, QVector<Waypoint> &waypoints);
QString errorString() const {return _errorString;}
int errorLine() const {return 0;}

View File

@ -3,20 +3,7 @@
#include "geojsonparser.h"
enum Type {
Unknown,
Point,
LineString,
MultiPoint,
Polygon,
MultiLineString,
MultiPolygon,
GeometryCollection,
Feature,
FeatureCollection
};
static Type type(const QJsonObject &json)
GeoJSONParser::Type GeoJSONParser::type(const QJsonObject &json)
{
QString str(json["type"].toString());
@ -57,6 +44,8 @@ bool GeoJSONParser::point(const QJsonArray &coordinates, Waypoint &waypoint,
waypoint.setElevation(coordinates.at(2).toDouble());
if (properties.contains("title") && properties["title"].isString())
waypoint.setName(properties["title"].toString());
if (properties.contains("name") && properties["name"].isString())
waypoint.setName(properties["name"].toString());
if (properties.contains("description")
&& properties["description"].isString())
waypoint.setDescription(properties["description"].toString());
@ -69,7 +58,7 @@ bool GeoJSONParser::multiPoint(const QJsonArray &coordinates,
{
for (int i = 0; i < coordinates.size(); i++) {
if (!coordinates.at(i).isArray()) {
_errorString = "Invalid MultiPoint Coordinates";
_errorString = "Invalid MultiPoint coordinates";
return false;
} else {
waypoints.resize(waypoints.size() + 1);
@ -81,20 +70,14 @@ bool GeoJSONParser::multiPoint(const QJsonArray &coordinates,
return true;
}
bool GeoJSONParser::lineString(const QJsonArray &coordinates, TrackData &track,
const QJsonObject &properties)
bool GeoJSONParser::lineString(const QJsonArray &coordinates,
SegmentData &segment)
{
if (properties.contains("title") && properties["title"].isString())
track.setName(properties["title"].toString());
if (properties.contains("description")
&& properties["description"].isString())
track.setDescription(properties["description"].toString());
for (int i = 0; i < coordinates.size(); i++) {
QJsonArray point(coordinates.at(i).toArray());
if (point.count() < 2 || !point.at(0).isDouble()
|| !point.at(1).isDouble()) {
_errorString = "Invalid LineString Coordinates";
_errorString = "Invalid LineString coordinates";
return false;
}
@ -102,23 +85,115 @@ bool GeoJSONParser::lineString(const QJsonArray &coordinates, TrackData &track,
point.at(1).toDouble()));
if (point.count() == 3 && point.at(2).isDouble())
t.setElevation(point.at(2).toDouble());
track.append(t);
segment.append(t);
}
return true;
}
bool GeoJSONParser::lineString(const QJsonArray &coordinates, TrackData &track,
const QJsonObject &properties)
{
if (properties.contains("title") && properties["title"].isString())
track.setName(properties["title"].toString());
if (properties.contains("name") && properties["name"].isString())
track.setName(properties["name"].toString());
if (properties.contains("description")
&& properties["description"].isString())
track.setDescription(properties["description"].toString());
track.append(SegmentData());
lineString(coordinates, track.last());
return true;
}
bool GeoJSONParser::multiLineString(const QJsonArray &coordinates,
QList<TrackData> &tracks, const QJsonObject &properties)
TrackData &track, const QJsonObject &properties)
{
if (properties.contains("title") && properties["title"].isString())
track.setName(properties["title"].toString());
if (properties.contains("name") && properties["name"].isString())
track.setName(properties["name"].toString());
if (properties.contains("description")
&& properties["description"].isString())
track.setDescription(properties["description"].toString());
for (int i = 0; i < coordinates.size(); i++) {
if (!coordinates.at(i).isArray()) {
_errorString = "Invalid MultiLineString coordinates";
return false;
} else {
track.append(SegmentData());
if (!lineString(coordinates.at(i).toArray(), track.last()))
return false;
}
}
return true;
}
bool GeoJSONParser::polygon(const QJsonArray &coordinates, ::Polygon &pg)
{
for (int i = 0; i < coordinates.size(); i++) {
if (!coordinates.at(i).isArray()) {
_errorString = "Invalid MultiLineString Coordinates";
_errorString = "Invalid Polygon linear ring";
return false;
}
const QJsonArray lr(coordinates.at(i).toArray());
pg.append(QVector<Coordinates>());
QVector<Coordinates> &data = pg.last();
for (int j = 0; j < lr.size(); j++) {
QJsonArray point(lr.at(j).toArray());
if (point.count() < 2 || !point.at(0).isDouble()
|| !point.at(1).isDouble()) {
_errorString = "Invalid Polygon linear ring coordinates";
return false;
}
data.append(Coordinates(point.at(0).toDouble(),
point.at(1).toDouble()));
}
}
return true;
}
bool GeoJSONParser::polygon(const QJsonArray &coordinates, Area &area,
const QJsonObject &properties)
{
if (properties.contains("title") && properties["title"].isString())
area.setName(properties["title"].toString());
if (properties.contains("name") && properties["name"].isString())
area.setName(properties["name"].toString());
if (properties.contains("description")
&& properties["description"].isString())
area.setDescription(properties["description"].toString());
area.append(::Polygon());
return polygon(coordinates, area.last());
}
bool GeoJSONParser::multiPolygon(const QJsonArray &coordinates,
Area &area, const QJsonObject &properties)
{
if (properties.contains("title") && properties["title"].isString())
area.setName(properties["title"].toString());
if (properties.contains("name") && properties["name"].isString())
area.setName(properties["name"].toString());
if (properties.contains("description")
&& properties["description"].isString())
area.setDescription(properties["description"].toString());
for (int i = 0; i < coordinates.size(); i++) {
if (!coordinates.at(i).isArray()) {
_errorString = "Invalid MultiPolygon coordinates";
return false;
} else {
tracks.append(TrackData());
if (!lineString(coordinates.at(i).toArray(), tracks.last(),
properties))
area.append(::Polygon());
if (!polygon(coordinates.at(i).toArray(), area.last()))
return false;
}
}
@ -127,8 +202,8 @@ bool GeoJSONParser::multiLineString(const QJsonArray &coordinates,
}
bool GeoJSONParser::geometryCollection(const QJsonObject &json,
QList<TrackData> &tracks, QVector<Waypoint> &waypoints,
const QJsonObject &properties)
QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints, const QJsonObject &properties)
{
if (!json.contains("geometries") || !json["geometries"].isArray()) {
_errorString = "Invalid/missing GeometryCollection geometries array";
@ -157,15 +232,25 @@ bool GeoJSONParser::geometryCollection(const QJsonObject &json,
return false;
break;
case MultiLineString:
if (!multiLineString(geometry["coordinates"].toArray(), tracks,
properties))
tracks.append(TrackData());
if (!multiLineString(geometry["coordinates"].toArray(),
tracks.last(), properties))
return false;
break;
case Polygon:
areas.append(Area());
if (!polygon(geometry["coordinates"].toArray(), areas.last(),
properties))
return false;
break;
case MultiPolygon:
areas.append(Area());
if (!multiPolygon(geometry["coordinates"].toArray(),
areas.last(), properties))
return false;
break;
case GeometryCollection:
if (!geometryCollection(geometry, tracks, waypoints,
if (!geometryCollection(geometry, tracks, areas, waypoints,
properties))
return false;
break;
@ -180,7 +265,7 @@ bool GeoJSONParser::geometryCollection(const QJsonObject &json,
}
bool GeoJSONParser::feature(const QJsonObject &json, QList<TrackData> &tracks,
QVector<Waypoint> &waypoints)
QList<Area> &areas, QVector<Waypoint> &waypoints)
{
QJsonObject properties(json["properties"].toObject());
QJsonObject geometry(json["geometry"].toObject());
@ -198,13 +283,19 @@ bool GeoJSONParser::feature(const QJsonObject &json, QList<TrackData> &tracks,
return lineString(geometry["coordinates"].toArray(), tracks.last(),
properties);
case MultiLineString:
return multiLineString(geometry["coordinates"].toArray(), tracks,
properties);
tracks.append(TrackData());
return multiLineString(geometry["coordinates"].toArray(),
tracks.last(), properties);
case GeometryCollection:
return geometryCollection(geometry, tracks, waypoints);
return geometryCollection(geometry, tracks, areas, waypoints);
case Polygon:
areas.append(Area());
return polygon(geometry["coordinates"].toArray(), areas.last(),
properties);
case MultiPolygon:
return true;
areas.append(Area());
return multiPolygon(geometry["coordinates"].toArray(), areas.last(),
properties);
default:
_errorString = geometry["type"].toString()
+ ": invalid/missing Feature geometry";
@ -213,7 +304,8 @@ bool GeoJSONParser::feature(const QJsonObject &json, QList<TrackData> &tracks,
}
bool GeoJSONParser::featureCollection(const QJsonObject &json,
QList<TrackData> &tracks, QVector<Waypoint> &waypoints)
QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints)
{
if (!json.contains("features") || !json["features"].isArray()) {
_errorString = "Invalid/missing FeatureCollection features array";
@ -222,7 +314,7 @@ bool GeoJSONParser::featureCollection(const QJsonObject &json,
QJsonArray features(json["features"].toArray());
for (int i = 0; i < features.size(); i++)
if (!feature(features.at(i).toObject(), tracks, waypoints))
if (!feature(features.at(i).toObject(), tracks, areas, waypoints))
return false;
return true;
@ -230,7 +322,7 @@ bool GeoJSONParser::featureCollection(const QJsonObject &json,
bool GeoJSONParser::parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QVector<Waypoint> &waypoints)
QList<RouteData> &routes, QList<Area> &areas, QVector<Waypoint> &waypoints)
{
Q_UNUSED(routes);
QJsonParseError error;
@ -254,16 +346,20 @@ bool GeoJSONParser::parse(QFile *file, QList<TrackData> &tracks,
tracks.append(TrackData());
return lineString(json["coordinates"].toArray(), tracks.last());
case MultiLineString:
return multiLineString(json["coordinates"].toArray(), tracks);
tracks.append(TrackData());
return multiLineString(json["coordinates"].toArray(), tracks.last());
case GeometryCollection:
return geometryCollection(json, tracks, waypoints);
return geometryCollection(json, tracks, areas, waypoints);
case Feature:
return feature(json, tracks, waypoints);
return feature(json, tracks, areas, waypoints);
case FeatureCollection:
return featureCollection(json, tracks, waypoints);
return featureCollection(json, tracks, areas, waypoints);
case Polygon:
areas.append(Area());
return polygon(json["coordinates"].toArray(), areas.last());
case MultiPolygon:
return true;
areas.append(Area());
return multiPolygon(json["coordinates"].toArray(), areas.last());
case Unknown:
if (json["type"].toString().isNull())
_errorString = "Not a GeoJSON file";

View File

@ -11,25 +11,46 @@ class GeoJSONParser : public Parser
{
public:
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
QVector<Waypoint> &waypoints);
QList<Area> &areas, QVector<Waypoint> &waypoints);
QString errorString() const {return _errorString;}
int errorLine() const {return 0;}
private:
enum Type {
Unknown,
Point,
LineString,
MultiPoint,
Polygon,
MultiLineString,
MultiPolygon,
GeometryCollection,
Feature,
FeatureCollection
};
Type type(const QJsonObject &json);
bool point(const QJsonArray &coordinates, Waypoint &waypoint,
const QJsonObject &properties = QJsonObject());
bool multiPoint(const QJsonArray &coordinates,
QVector<Waypoint> &waypoints, const QJsonObject &properties = QJsonObject());
bool lineString(const QJsonArray &coordinates, SegmentData &segment);
bool lineString(const QJsonArray &coordinates, TrackData &track,
const QJsonObject &properties = QJsonObject());
bool multiLineString(const QJsonArray &coordinates,
QList<TrackData> &tracks, const QJsonObject &properties = QJsonObject());
TrackData &track, const QJsonObject &properties = QJsonObject());
bool polygon(const QJsonArray &coordinates, ::Polygon &pg);
bool polygon(const QJsonArray &coordinates, Area &area,
const QJsonObject &properties = QJsonObject());
bool multiPolygon(const QJsonArray &coordinates, Area &area,
const QJsonObject &properties = QJsonObject());
bool geometryCollection(const QJsonObject &json, QList<TrackData> &tracks,
QVector<Waypoint> &waypoints, const QJsonObject &properties = QJsonObject());
QList<Area> &areas, QVector<Waypoint> &waypoints,
const QJsonObject &properties = QJsonObject());
bool feature(const QJsonObject &json, QList<TrackData> &tracks,
QVector<Waypoint> &waypoints);
QList<Area> &areas, QVector<Waypoint> &waypoints);
bool featureCollection(const QJsonObject &json, QList<TrackData> &tracks,
QVector<Waypoint> &waypoints);
QList<Area> &areas, QVector<Waypoint> &waypoints);
QString _errorString;
};

View File

@ -51,7 +51,7 @@ Coordinates GPXParser::coordinates()
return Coordinates(lon, lat);
}
void GPXParser::rpExtension(TrackData *autoRoute)
void GPXParser::rpExtension(SegmentData *autoRoute)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("rpt"))
@ -67,12 +67,16 @@ void GPXParser::tpExtension(Trackpoint &trackpoint)
trackpoint.setHeartRate(number());
else if (_reader.name() == QLatin1String("atemp"))
trackpoint.setTemperature(number());
else if (_reader.name() == QLatin1String("cad"))
trackpoint.setCadence(number());
else if (_reader.name() == QLatin1String("speed"))
trackpoint.setSpeed(number());
else
_reader.skipCurrentElement();
}
}
void GPXParser::rteptExtensions(TrackData *autoRoute)
void GPXParser::rteptExtensions(SegmentData *autoRoute)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("RoutePointExtension"))
@ -124,7 +128,7 @@ void GPXParser::trackpointData(Trackpoint &trackpoint)
trackpoint.setElevation(trackpoint.elevation() - gh);
}
void GPXParser::waypointData(Waypoint &waypoint, TrackData *autoRoute)
void GPXParser::waypointData(Waypoint &waypoint, SegmentData *autoRoute)
{
qreal gh = NAN;
@ -149,12 +153,12 @@ void GPXParser::waypointData(Waypoint &waypoint, TrackData *autoRoute)
waypoint.setElevation(waypoint.elevation() - gh);
}
void GPXParser::trackpoints(TrackData &track)
void GPXParser::trackpoints(SegmentData &segment)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("trkpt")) {
track.append(Trackpoint(coordinates()));
trackpointData(track.last());
segment.append(Trackpoint(coordinates()));
trackpointData(segment.last());
} else
_reader.skipCurrentElement();
}
@ -163,11 +167,13 @@ void GPXParser::trackpoints(TrackData &track)
void GPXParser::routepoints(RouteData &route, QList<TrackData> &tracks)
{
TrackData autoRoute;
autoRoute.append(SegmentData());
SegmentData &autoRouteSegment = autoRoute.last();
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("rtept")) {
route.append(Waypoint(coordinates()));
waypointData(route.last(), &autoRoute);
waypointData(route.last(), &autoRouteSegment);
} else if (_reader.name() == QLatin1String("name"))
route.setName(_reader.readElementText());
else if (_reader.name() == QLatin1String("desc"))
@ -176,7 +182,7 @@ void GPXParser::routepoints(RouteData &route, QList<TrackData> &tracks)
_reader.skipCurrentElement();
}
if (!autoRoute.isEmpty()) {
if (!autoRouteSegment.isEmpty()) {
autoRoute.setName(route.name());
autoRoute.setDescription(route.description());
tracks.append(autoRoute);
@ -186,9 +192,10 @@ void GPXParser::routepoints(RouteData &route, QList<TrackData> &tracks)
void GPXParser::track(TrackData &track)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("trkseg"))
trackpoints(track);
else if (_reader.name() == QLatin1String("name"))
if (_reader.name() == QLatin1String("trkseg")) {
track.append(SegmentData());
trackpoints(track.last());
} else if (_reader.name() == QLatin1String("name"))
track.setName(_reader.readElementText());
else if (_reader.name() == QLatin1String("desc"))
track.setDescription(_reader.readElementText());
@ -197,8 +204,42 @@ void GPXParser::track(TrackData &track)
}
}
void GPXParser::area(Area &area)
{
area.append(Polygon());
area.last().append(QVector<Coordinates>());
QVector<Coordinates> &points = area.last().last();
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("point")) {
Coordinates c(coordinates());
_reader.readElementText();
if (c.isValid())
points.append(c);
else
return;
} else if (_reader.name() == QLatin1String("name"))
area.setName(_reader.readElementText());
else if (_reader.name() == QLatin1String("desc"))
area.setDescription(_reader.readElementText());
else
_reader.skipCurrentElement();
}
}
void GPXParser::gpxExtensions(QList<Area> &areas)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("area")) {
areas.append(Area());
area(areas.last());
} else
_reader.skipCurrentElement();
}
}
void GPXParser::gpx(QList<TrackData> &tracks, QList<RouteData> &routes,
QVector<Waypoint> &waypoints)
QList<Area> &areas, QVector<Waypoint> &waypoints)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("trk")) {
@ -210,13 +251,15 @@ void GPXParser::gpx(QList<TrackData> &tracks, QList<RouteData> &routes,
} else if (_reader.name() == QLatin1String("wpt")) {
waypoints.append(Waypoint(coordinates()));
waypointData(waypoints.last());
} else
} else if (_reader.name() == QLatin1String("extensions"))
gpxExtensions(areas);
else
_reader.skipCurrentElement();
}
}
bool GPXParser::parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QVector<Waypoint> &waypoints)
QList<RouteData> &routes, QList<Area> &areas, QVector<Waypoint> &waypoints)
{
_reader.clear();
_reader.setDevice(file);
@ -224,7 +267,7 @@ bool GPXParser::parse(QFile *file, QList<TrackData> &tracks,
if (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("gpx"))
gpx(tracks, routes, waypoints);
gpx(tracks, routes, areas, waypoints);
else
_reader.raiseError("Not a GPX file");
}

View File

@ -8,23 +8,25 @@
class GPXParser : public Parser
{
public:
bool parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QVector<Waypoint> &waypoints);
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
QList<Area> &areas, QVector<Waypoint> &waypoints);
QString errorString() const {return _reader.errorString();}
int errorLine() const {return _reader.lineNumber();}
private:
void gpx(QList<TrackData> &tracks, QList<RouteData> &routes,
QVector<Waypoint> &waypoints);
QList<Area> &areas, QVector<Waypoint> &waypoints);
void track(TrackData &track);
void trackpoints(TrackData &track);
void trackpoints(SegmentData &segment);
void routepoints(RouteData &route, QList<TrackData> &tracks);
void rpExtension(TrackData *autoRoute);
void rpExtension(SegmentData *autoRoute);
void tpExtension(Trackpoint &trackpoint);
void trkptExtensions(Trackpoint &trackpoint);
void rteptExtensions(TrackData *autoRoute);
void rteptExtensions(SegmentData *autoRoute);
void area(Area &area);
void gpxExtensions(QList<Area> &areas);
void trackpointData(Trackpoint &trackpoint);
void waypointData(Waypoint &waypoint, TrackData *autoRoute = 0);
void waypointData(Waypoint &waypoint, SegmentData *autoRoute = 0);
qreal number();
QDateTime time();
Coordinates coordinates();

View File

@ -1,6 +1,7 @@
#ifndef GRAPH_H
#define GRAPH_H
#include <QList>
#include <QVector>
#include <QDebug>
#include <cmath>
@ -39,6 +40,30 @@ inline QDebug operator<<(QDebug dbg, const GraphPoint &point)
}
#endif // QT_NO_DEBUG
typedef QVector<GraphPoint> Graph;
typedef QVector<GraphPoint> GraphSegment;
class Graph : public QList<GraphSegment>
{
public:
bool isValid() const
{
if (isEmpty())
return false;
for (int i = 0; i < size(); i++)
if (at(i).size() < 2)
return false;
return true;
}
bool hasTime() const
{
for (int i = 0; i < size(); i++) {
const GraphSegment &segment = at(i);
for (int j = 0; j < segment.size(); j++)
if (std::isnan(segment.at(j).t()))
return false;
}
return true;
}
};
#endif // GRAPH_H

View File

@ -122,7 +122,8 @@ bool IGCParser::readHRecord(const char *line, int len)
return true;
}
bool IGCParser::readBRecord(TrackData &track, const char *line, int len)
bool IGCParser::readBRecord(SegmentData &segment, const char *line,
int len)
{
qreal lat, lon, ele;
QTime time;
@ -158,7 +159,7 @@ bool IGCParser::readBRecord(TrackData &track, const char *line, int len)
Trackpoint t(Coordinates(lon, lat));
t.setTimestamp(QDateTime(_date, _time, Qt::UTC));
t.setElevation(ele);
track.append(t);
segment.append(t);
return true;
}
@ -192,9 +193,11 @@ bool IGCParser::readCRecord(RouteData &route, const char *line, int len)
}
bool IGCParser::parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QVector<Waypoint> &waypoints)
QList<RouteData> &routes, QList<Area> &polygons,
QVector<Waypoint> &waypoints)
{
Q_UNUSED(waypoints);
Q_UNUSED(polygons);
qint64 len;
char line[76 + 2 + 1 + 1];
bool route = false, track = false;
@ -238,10 +241,11 @@ bool IGCParser::parse(QFile *file, QList<TrackData> &tracks,
}
if (!track) {
tracks.append(TrackData());
tracks.last().append(SegmentData());
_time = QTime(0, 0);
track = true;
}
if (!readBRecord(tracks.last(), line, len))
if (!readBRecord(tracks.last().last(), line, len))
return false;
}
}

View File

@ -11,14 +11,14 @@ class IGCParser : public Parser
public:
IGCParser() : _errorLine(0) {}
bool parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QVector<Waypoint> &waypoints);
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
QList<Area> &polygons, QVector<Waypoint> &waypoints);
QString errorString() const {return _errorString;}
int errorLine() const {return _errorLine;}
private:
bool readHRecord(const char *line, int len);
bool readBRecord(TrackData &track, const char *line, int len);
bool readBRecord(SegmentData &segment, const char *line, int len);
bool readCRecord(RouteData &route, const char *line, int len);
int _errorLine;

View File

@ -127,7 +127,7 @@ bool KMLParser::pointCoordinates(Waypoint &waypoint)
return true;
}
bool KMLParser::lineCoordinates(TrackData &track)
bool KMLParser::lineCoordinates(SegmentData &segment)
{
QString data = _reader.readElementText();
const QChar *sp, *ep, *cp, *vp;
@ -170,11 +170,11 @@ bool KMLParser::lineCoordinates(TrackData &track)
if (!res)
return false;
track.append(Trackpoint(Coordinates(val[0], val[1])));
if (!track.last().coordinates().isValid())
segment.append(Trackpoint(Coordinates(val[0], val[1])));
if (!segment.last().coordinates().isValid())
return false;
if (c == 2)
track.last().setElevation(val[2]);
segment.last().setElevation(val[2]);
while (cp->isSpace())
cp++;
@ -186,6 +186,63 @@ bool KMLParser::lineCoordinates(TrackData &track)
return true;
}
bool KMLParser::polygonCoordinates(QVector<Coordinates> &points)
{
QString data = _reader.readElementText();
const QChar *sp, *ep, *cp, *vp;
int c = 0;
qreal val[3];
bool res;
sp = data.constData();
ep = sp + data.size();
for (cp = sp; cp < ep; cp++)
if (!cp->isSpace())
break;
for (vp = cp; cp <= ep; cp++) {
if (*cp == ',') {
if (c > 1)
return false;
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
val[c] = QString(vp, cp - vp).toDouble(&res);
#else // QT_VERSION < 5
val[c] = QStringRef(&data, vp - sp, cp - vp).toDouble(&res);
#endif // QT_VERSION < 5
if (!res)
return false;
c++;
vp = cp + 1;
} else if (cp->isSpace() || cp->isNull()) {
if (c < 1 || c > 2)
return false;
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
val[c] = QString(vp, cp - vp).toDouble(&res);
#else // QT_VERSION < 5
val[c] = QStringRef(&data, vp - sp, cp - vp).toDouble(&res);
#endif // QT_VERSION < 5
if (!res)
return false;
points.append(Coordinates(val[0], val[1]));
if (!points.last().isValid())
return false;
while (cp->isSpace())
cp++;
c = 0;
vp = cp;
}
}
return true;
}
QDateTime KMLParser::timeStamp()
{
QDateTime ts;
@ -200,17 +257,63 @@ QDateTime KMLParser::timeStamp()
return ts;
}
void KMLParser::lineString(TrackData &track)
void KMLParser::lineString(SegmentData &segment)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("coordinates")) {
if (!lineCoordinates(track))
if (!lineCoordinates(segment))
_reader.raiseError("Invalid coordinates");
} else
_reader.skipCurrentElement();
}
}
void KMLParser::linearRing(QVector<Coordinates> &coordinates)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("coordinates")) {
if (!polygonCoordinates(coordinates))
_reader.raiseError("Invalid coordinates");
} else
_reader.skipCurrentElement();
}
}
void KMLParser::boundary(QVector<Coordinates> &coordinates)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("LinearRing"))
linearRing(coordinates);
else
_reader.skipCurrentElement();
}
}
void KMLParser::polygon(Area &area)
{
area.append(Polygon());
Polygon &polygon = area.last();
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("outerBoundaryIs")) {
if (!polygon.isEmpty()) {
_reader.raiseError("Multiple polygon outerBoundaryIss");
return;
}
polygon.append(QVector<Coordinates>());
boundary(polygon.last());
} else if (_reader.name() == QLatin1String("innerBoundaryIs")) {
if (polygon.isEmpty()) {
_reader.raiseError("Missing polygon outerBoundaryIs");
return;
}
polygon.append(QVector<Coordinates>());
boundary(polygon.last());
} else
_reader.skipCurrentElement();
}
}
void KMLParser::point(Waypoint &waypoint)
{
while (_reader.readNextStartElement()) {
@ -225,15 +328,15 @@ void KMLParser::point(Waypoint &waypoint)
_reader.raiseError("Missing Point coordinates");
}
void KMLParser::heartRate(TrackData &track, int start)
void KMLParser::heartRate(SegmentData &segment, int start)
{
int i = start;
const char error[] = "Heartrate data count mismatch";
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("value")) {
if (i < track.size())
track[i++].setHeartRate(number());
if (i < segment.size())
segment[i++].setHeartRate(number());
else {
_reader.raiseError(error);
return;
@ -242,19 +345,19 @@ void KMLParser::heartRate(TrackData &track, int start)
_reader.skipCurrentElement();
}
if (i != track.size())
if (i != segment.size())
_reader.raiseError(error);
}
void KMLParser::cadence(TrackData &track, int start)
void KMLParser::cadence(SegmentData &segment, int start)
{
int i = start;
const char error[] = "Cadence data count mismatch";
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("value")) {
if (i < track.size())
track[i++].setCadence(number());
if (i < segment.size())
segment[i++].setCadence(number());
else {
_reader.raiseError(error);
return;
@ -263,19 +366,19 @@ void KMLParser::cadence(TrackData &track, int start)
_reader.skipCurrentElement();
}
if (i != track.size())
if (i != segment.size())
_reader.raiseError(error);
}
void KMLParser::speed(TrackData &track, int start)
void KMLParser::speed(SegmentData &segment, int start)
{
int i = start;
const char error[] = "Speed data count mismatch";
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("value")) {
if (i < track.size())
track[i++].setSpeed(number());
if (i < segment.size())
segment[i++].setSpeed(number());
else {
_reader.raiseError(error);
return;
@ -284,19 +387,19 @@ void KMLParser::speed(TrackData &track, int start)
_reader.skipCurrentElement();
}
if (i != track.size())
if (i != segment.size())
_reader.raiseError(error);
}
void KMLParser::temperature(TrackData &track, int start)
void KMLParser::temperature(SegmentData &segment, int start)
{
int i = start;
const char error[] = "Temperature data count mismatch";
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("value")) {
if (i < track.size())
track[i++].setTemperature(number());
if (i < segment.size())
segment[i++].setTemperature(number());
else {
_reader.raiseError(error);
return;
@ -305,11 +408,11 @@ void KMLParser::temperature(TrackData &track, int start)
_reader.skipCurrentElement();
}
if (i != track.size())
if (i != segment.size())
_reader.raiseError(error);
}
void KMLParser::schemaData(TrackData &track, int start)
void KMLParser::schemaData(SegmentData &segment, int start)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("SimpleArrayData")) {
@ -317,13 +420,13 @@ void KMLParser::schemaData(TrackData &track, int start)
QStringRef name = attr.value("name");
if (name == QLatin1String("Heartrate"))
heartRate(track, start);
heartRate(segment, start);
else if (name == QLatin1String("Cadence"))
cadence(track, start);
cadence(segment, start);
else if (name == QLatin1String("Speed"))
speed(track, start);
speed(segment, start);
else if (name == QLatin1String("Temperature"))
temperature(track, start);
temperature(segment, start);
else
_reader.skipCurrentElement();
} else
@ -331,56 +434,57 @@ void KMLParser::schemaData(TrackData &track, int start)
}
}
void KMLParser::extendedData(TrackData &track, int start)
void KMLParser::extendedData(SegmentData &segment, int start)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("SchemaData"))
schemaData(track, start);
schemaData(segment, start);
else
_reader.skipCurrentElement();
}
}
void KMLParser::track(TrackData &track)
void KMLParser::track(SegmentData &segment)
{
const char error[] = "gx:coord/when element count mismatch";
int first = track.size();
int first = segment.size();
int i = first;
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("when")) {
track.append(Trackpoint());
track.last().setTimestamp(time());
segment.append(Trackpoint());
segment.last().setTimestamp(time());
} else if (_reader.name() == QLatin1String("coord")) {
if (i == track.size()) {
if (i == segment.size()) {
_reader.raiseError(error);
return;
} else if (!coord(track[i])) {
} else if (!coord(segment[i])) {
_reader.raiseError("Invalid coordinates");
return;
}
i++;
} else if (_reader.name() == QLatin1String("ExtendedData"))
extendedData(track, first);
extendedData(segment, first);
else
_reader.skipCurrentElement();
}
if (i != track.size())
if (i != segment.size())
_reader.raiseError(error);
}
void KMLParser::multiTrack(TrackData &t)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("Track"))
track(t);
else
if (_reader.name() == QLatin1String("Track")) {
t.append(SegmentData());
track(t.last());
} else
_reader.skipCurrentElement();
}
}
void KMLParser::multiGeometry(QList<TrackData> &tracks,
void KMLParser::multiGeometry(QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints, const QString &name, const QString &desc,
const QDateTime timestamp)
{
@ -395,15 +499,23 @@ void KMLParser::multiGeometry(QList<TrackData> &tracks,
} else if (_reader.name() == QLatin1String("LineString")) {
tracks.append(TrackData());
TrackData &t = tracks.last();
t.append(SegmentData());
t.setName(name);
t.setDescription(desc);
lineString(t);
lineString(t.last());
} else if (_reader.name() == QLatin1String("Polygon")) {
areas.append(Area());
Area &a = areas.last();
a.setName(name);
a.setDescription(desc);
polygon(a);
} else
_reader.skipCurrentElement();
}
}
void KMLParser::placemark(QList<TrackData> &tracks, QVector<Waypoint> &waypoints)
void KMLParser::placemark(QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints)
{
QString name, desc;
QDateTime timestamp;
@ -416,7 +528,7 @@ void KMLParser::placemark(QList<TrackData> &tracks, QVector<Waypoint> &waypoints
else if (_reader.name() == QLatin1String("TimeStamp"))
timestamp = timeStamp();
else if (_reader.name() == QLatin1String("MultiGeometry"))
multiGeometry(tracks, waypoints, name, desc, timestamp);
multiGeometry(tracks, areas, waypoints, name, desc, timestamp);
else if (_reader.name() == QLatin1String("Point")) {
waypoints.append(Waypoint());
Waypoint &w = waypoints.last();
@ -428,66 +540,77 @@ void KMLParser::placemark(QList<TrackData> &tracks, QVector<Waypoint> &waypoints
|| _reader.name() == QLatin1String("LinearRing")) {
tracks.append(TrackData());
TrackData &t = tracks.last();
t.append(SegmentData());
t.setName(name);
t.setDescription(desc);
lineString(t);
lineString(t.last());
} else if (_reader.name() == QLatin1String("Track")) {
tracks.append(TrackData());
TrackData &t = tracks.last();
t.append(SegmentData());
t.setName(name);
t.setDescription(desc);
track(t);
track(t.last());
} else if (_reader.name() == QLatin1String("MultiTrack")) {
tracks.append(TrackData());
TrackData &t = tracks.last();
t.setName(name);
t.setDescription(desc);
multiTrack(t);
} else if (_reader.name() == QLatin1String("Polygon")) {
areas.append(Area());
Area &a = areas.last();
a.setName(name);
a.setDescription(desc);
polygon(a);
} else
_reader.skipCurrentElement();
}
}
void KMLParser::folder(QList<TrackData> &tracks, QVector<Waypoint> &waypoints)
void KMLParser::folder(QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("Placemark"))
placemark(tracks, waypoints);
placemark(tracks, areas, waypoints);
else if (_reader.name() == QLatin1String("Folder"))
folder(tracks, waypoints);
folder(tracks, areas, waypoints);
else
_reader.skipCurrentElement();
}
}
void KMLParser::document(QList<TrackData> &tracks, QVector<Waypoint> &waypoints)
void KMLParser::document(QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("Placemark"))
placemark(tracks, waypoints);
placemark(tracks, areas, waypoints);
else if (_reader.name() == QLatin1String("Folder"))
folder(tracks, waypoints);
folder(tracks, areas, waypoints);
else
_reader.skipCurrentElement();
}
}
void KMLParser::kml(QList<TrackData> &tracks, QVector<Waypoint> &waypoints)
void KMLParser::kml(QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("Document"))
document(tracks, waypoints);
document(tracks, areas, waypoints);
else if (_reader.name() == QLatin1String("Placemark"))
placemark(tracks, waypoints);
placemark(tracks, areas, waypoints);
else if (_reader.name() == QLatin1String("Folder"))
folder(tracks, waypoints);
folder(tracks, areas, waypoints);
else
_reader.skipCurrentElement();
}
}
bool KMLParser::parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QVector<Waypoint> &waypoints)
QList<RouteData> &routes, QList<Area> &areas, QVector<Waypoint> &waypoints)
{
Q_UNUSED(routes);
@ -496,7 +619,7 @@ bool KMLParser::parse(QFile *file, QList<TrackData> &tracks,
if (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("kml"))
kml(tracks, waypoints);
kml(tracks, areas, waypoints);
else
_reader.raiseError("Not a KML file");
}

View File

@ -8,31 +8,40 @@
class KMLParser : public Parser
{
public:
bool parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QVector<Waypoint> &waypoints);
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
QList<Area> &areas, QVector<Waypoint> &waypoints);
QString errorString() const {return _reader.errorString();}
int errorLine() const {return _reader.lineNumber();}
private:
void kml(QList<TrackData> &tracks, QVector<Waypoint> &waypoints);
void document(QList<TrackData> &tracks, QVector<Waypoint> &waypoints);
void folder(QList<TrackData> &tracks, QVector<Waypoint> &waypoints);
void placemark(QList<TrackData> &tracks, QVector<Waypoint> &waypoints);
void multiGeometry(QList<TrackData> &tracks, QVector<Waypoint> &waypoints,
const QString &name, const QString &desc, const QDateTime timestamp);
void track(TrackData &track);
void kml(QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints);
void document(QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints);
void folder(QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints);
void placemark(QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints);
void multiGeometry(QList<TrackData> &tracks, QList<Area> &areas,
QVector<Waypoint> &waypoints, const QString &name, const QString &desc,
const QDateTime timestamp);
void track(SegmentData &segment);
void multiTrack(TrackData &t);
void lineString(TrackData &track);
void lineString(SegmentData &segment);
void linearRing(QVector<Coordinates> &coordinates);
void boundary(QVector<Coordinates> &coordinates);
void polygon(Area &area);
void point(Waypoint &waypoint);
bool pointCoordinates(Waypoint &waypoint);
bool lineCoordinates(TrackData &track);
bool lineCoordinates(SegmentData &segment);
bool polygonCoordinates(QVector<Coordinates> &points);
bool coord(Trackpoint &trackpoint);
void extendedData(TrackData &track, int start);
void schemaData(TrackData &track, int start);
void heartRate(TrackData &track, int start);
void cadence(TrackData &track, int start);
void speed(TrackData &track, int start);
void temperature(TrackData &track, int start);
void extendedData(SegmentData &segment, int start);
void schemaData(SegmentData &segment, int start);
void heartRate(SegmentData &segment, int start);
void cadence(SegmentData &segment, int start);
void speed(SegmentData &segment, int start);
void temperature(SegmentData &segment, int start);
QDateTime timeStamp();
qreal number();
QDateTime time();

View File

@ -58,10 +58,12 @@ void LOCParser::loc(QVector<Waypoint> &waypoints)
}
bool LOCParser::parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QVector<Waypoint> &waypoints)
QList<RouteData> &routes, QList<Area> &polygons,
QVector<Waypoint> &waypoints)
{
Q_UNUSED(tracks);
Q_UNUSED(routes);
Q_UNUSED(polygons);
_reader.clear();
_reader.setDevice(file);

View File

@ -7,8 +7,8 @@
class LOCParser : public Parser
{
public:
bool parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QVector<Waypoint> &waypoints);
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
QList<Area> &polygons, QVector<Waypoint> &waypoints);
QString errorString() const {return _reader.errorString();}
int errorLine() const {return _reader.lineNumber();}

View File

@ -227,7 +227,7 @@ bool NMEAParser::readEW(const char *data, int len, qreal &lon)
return true;
}
bool NMEAParser::readRMC(TrackData &track, const char *line, int len)
bool NMEAParser::readRMC(SegmentData &segment, const char *line, int len)
{
int col = 1;
const char *vp = line;
@ -280,8 +280,8 @@ bool NMEAParser::readRMC(TrackData &track, const char *line, int len)
}
if (!date.isNull()) {
if (_date.isNull() && !_time.isNull() && !track.isEmpty())
track.last().setTimestamp(QDateTime(date, _time, Qt::UTC));
if (_date.isNull() && !_time.isNull() && !segment.isEmpty())
segment.last().setTimestamp(QDateTime(date, _time, Qt::UTC));
_date = date;
}
@ -290,13 +290,13 @@ bool NMEAParser::readRMC(TrackData &track, const char *line, int len)
Trackpoint t(c);
if (!_date.isNull() && !time.isNull())
t.setTimestamp(QDateTime(_date, time, Qt::UTC));
track.append(t);
segment.append(t);
}
return true;
}
bool NMEAParser::readGGA(TrackData &track, const char *line, int len)
bool NMEAParser::readGGA(SegmentData &segment, const char *line, int len)
{
int col = 1;
const char *vp = line;
@ -364,7 +364,7 @@ bool NMEAParser::readGGA(TrackData &track, const char *line, int len)
t.setTimestamp(QDateTime(_date, _time, Qt::UTC));
if (!std::isnan(ele))
t.setElevation(ele - gh);
track.append(t);
segment.append(t);
_GGA = true;
}
@ -478,11 +478,14 @@ bool NMEAParser::readZDA(const char *line, int len)
}
bool NMEAParser::parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QVector<Waypoint> &waypoints)
QList<RouteData> &routes, QList<Area> &polygons,
QVector<Waypoint> &waypoints)
{
Q_UNUSED(routes);
Q_UNUSED(polygons);
qint64 len;
char line[80 + 2 + 1 + 1];
SegmentData segment;
_errorLine = 1;
@ -491,9 +494,6 @@ bool NMEAParser::parse(QFile *file, QList<TrackData> &tracks,
_time = QTime();
_GGA = false;
tracks.append(TrackData());
TrackData &track = tracks.last();
while (!file->atEnd()) {
len = file->readLine(line, sizeof(line));
@ -507,10 +507,10 @@ bool NMEAParser::parse(QFile *file, QList<TrackData> &tracks,
if (validSentence(line, len)) {
if (!memcmp(line + 3, "RMC,", 4)) {
if (!readRMC(track, line + 7, len - 7))
if (!readRMC(segment, line + 7, len - 7))
return false;
} else if (!memcmp(line + 3, "GGA,", 4)) {
if (!readGGA(track, line + 7, len - 7))
if (!readGGA(segment, line + 7, len - 7))
return false;
} else if (!memcmp(line + 3, "WPL,", 4)) {
if (!readWPL(waypoints, line + 7, len - 7))
@ -524,10 +524,15 @@ bool NMEAParser::parse(QFile *file, QList<TrackData> &tracks,
_errorLine++;
}
if (!tracks.last().size() && !waypoints.size()) {
if (!segment.size() && !waypoints.size()) {
_errorString = "No usable NMEA sentence found";
return false;
}
if (segment.size()) {
tracks.append(TrackData());
tracks.last().append(segment);
}
return true;
}

View File

@ -10,8 +10,8 @@ class NMEAParser : public Parser
public:
NMEAParser() : _errorLine(0), _GGA(false) {}
bool parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QVector<Waypoint> &waypoints);
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
QList<Area> &polygons, QVector<Waypoint> &waypoints);
QString errorString() const {return _errorString;}
int errorLine() const {return _errorLine;}
@ -25,8 +25,8 @@ private:
bool readAltitude(const char *data, int len, qreal &ele);
bool readGeoidHeight(const char *data, int len, qreal &gh);
bool readRMC(TrackData &track, const char *line, int len);
bool readGGA(TrackData &track, const char *line, int len);
bool readRMC(SegmentData &segment, const char *line, int len);
bool readGGA(SegmentData &segment, const char *line, int len);
bool readWPL(QVector<Waypoint> &waypoints, const char *line, int len);
bool readZDA(const char *line, int len);

View File

@ -27,10 +27,12 @@ static QByteArray &decode(QByteArray &ba)
bool PLTParser::parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QVector<Waypoint> &waypoints)
QList<RouteData> &routes, QList<Area> &polygons,
QVector<Waypoint> &waypoints)
{
Q_UNUSED(waypoints);
Q_UNUSED(routes);
Q_UNUSED(polygons);
bool res;
const GCS *gcs = 0;
@ -39,6 +41,8 @@ bool PLTParser::parse(QFile *file, QList<TrackData> &tracks,
tracks.append(TrackData());
TrackData &track = tracks.last();
track.append(SegmentData());
SegmentData &segment = track.last();
while (!file->atEnd()) {
QByteArray line = file->readLine();
@ -103,7 +107,8 @@ bool PLTParser::parse(QFile *file, QList<TrackData> &tracks,
}
}
track.append(tp);
segment.append(tp);
}
_errorLine++;
@ -113,10 +118,12 @@ bool PLTParser::parse(QFile *file, QList<TrackData> &tracks,
}
bool RTEParser::parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QVector<Waypoint> &waypoints)
QList<RouteData> &routes, QList<Area> &polygons,
QVector<Waypoint> &waypoints)
{
Q_UNUSED(waypoints);
Q_UNUSED(tracks);
Q_UNUSED(polygons);
bool res, record = false;
const GCS *gcs = 0;
@ -211,10 +218,12 @@ bool RTEParser::parse(QFile *file, QList<TrackData> &tracks,
}
bool WPTParser::parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QVector<Waypoint> &waypoints)
QList<RouteData> &routes, QList<Area> &polygons,
QVector<Waypoint> &waypoints)
{
Q_UNUSED(tracks);
Q_UNUSED(routes);
Q_UNUSED(polygons);
bool res;
const GCS *gcs = 0;

View File

@ -9,7 +9,7 @@ public:
PLTParser() : _errorLine(0) {}
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
QVector<Waypoint> &waypoints);
QList<Area> &polygons, QVector<Waypoint> &waypoints);
QString errorString() const {return _errorString;}
int errorLine() const {return _errorLine;}
@ -24,7 +24,7 @@ public:
RTEParser() : _errorLine(0) {}
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
QVector<Waypoint> &waypoints);
QList<Area> &polygons, QVector<Waypoint> &waypoints);
QString errorString() const {return _errorString;}
int errorLine() const {return _errorLine;}
@ -39,7 +39,7 @@ public:
WPTParser() : _errorLine(0) {}
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
QVector<Waypoint> &waypoints);
QList<Area> &polygons, QVector<Waypoint> &waypoints);
QString errorString() const {return _errorString;}
int errorLine() const {return _errorLine;}

View File

@ -8,6 +8,7 @@
#include "trackdata.h"
#include "routedata.h"
#include "waypoint.h"
#include "area.h"
class Parser
@ -16,7 +17,8 @@ public:
virtual ~Parser() {}
virtual bool parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QVector<Waypoint> &waypoints) = 0;
QList<RouteData> &routes, QList<Area> &polygons,
QVector<Waypoint> &waypoints) = 0;
virtual QString errorString() const = 0;
virtual int errorLine() const = 0;
};

View File

@ -1,14 +1,27 @@
#include "path.h"
bool Path::isValid() const
{
if (isEmpty())
return false;
for (int i = 0; i < size(); i++)
if (at(i).size() < 2)
return false;
return true;
}
RectC Path::boundingRect() const
{
RectC ret;
if (size() < 2)
if (!isValid())
return ret;
for (int i = 0; i < size(); i++)
ret = ret.united(at(i).coordinates());
for (int i = 0; i < size(); i++) {
const PathSegment &segment = at(i);
for (int j = 0; j < segment.size(); j++)
ret = ret.united(segment.at(j).coordinates());
}
return ret;
}

View File

@ -27,10 +27,12 @@ Q_DECLARE_TYPEINFO(PathPoint, Q_PRIMITIVE_TYPE);
QDebug operator<<(QDebug dbg, const PathPoint &point);
#endif // QT_NO_DEBUG
typedef QVector<PathPoint> PathSegment;
class Path : public QVector<PathPoint>
class Path : public QList<PathSegment>
{
public:
bool isValid() const;
RectC boundingRect() const;
};

View File

@ -4,6 +4,9 @@
#include "common/greatcircle.h"
#include "data.h"
#include "dem.h"
#include "path.h"
#include "area.h"
#include "common/wgs84.h"
#include "poi.h"
@ -126,23 +129,28 @@ QList<Waypoint> POI::points(const Path &path) const
QSet<int>::const_iterator it;
for (int i = 1; i < path.count(); i++) {
double ds = path.at(i).distance() - path.at(i-1).distance();
unsigned n = (unsigned)ceil(ds / _radius);
for (int i = 0; i < path.count(); i++) {
const PathSegment &segment = path.at(i);
if (n > 1) {
GreatCircle gc(path.at(i-1).coordinates(), path.at(i).coordinates());
for (unsigned j = 0; j < n; j++) {
RectC br(gc.pointAt((double)j/n), _radius);
for (int j = 1; j < segment.size(); j++) {
double ds = segment.at(j).distance() - segment.at(j-1).distance();
unsigned n = (unsigned)ceil(ds / _radius);
if (n > 1) {
GreatCircle gc(segment.at(j-1).coordinates(),
segment.at(j).coordinates());
for (unsigned k = 0; k < n; k++) {
RectC br(gc.pointAt((double)k/n), _radius);
search(br, set);
}
} else {
RectC br(segment.at(j-1).coordinates(), _radius);
search(br, set);
}
} else {
RectC br(path.at(i-1).coordinates(), _radius);
search(br, set);
}
}
RectC br(path.last().coordinates(), _radius);
RectC br(path.last().last().coordinates(), _radius);
search(br, set);
@ -177,6 +185,31 @@ QList<Waypoint> POI::points(const Waypoint &point) const
return ret;
}
QList<Waypoint> POI::points(const Area &area) const
{
QList<Waypoint> ret;
qreal min[2], max[2];
QSet<int> set;
QSet<int>::const_iterator it;
RectC br(area.boundingRect());
double offset = rad2deg(_radius / WGS84_RADIUS);
min[0] = br.topLeft().lon() - offset;
min[1] = br.bottomRight().lat() - offset;
max[0] = br.bottomRight().lon() + offset;
max[1] = br.topLeft().lat() + offset;
_tree.Search(min, max, cb, &set);
for (it = set.constBegin(); it != set.constEnd(); ++it)
ret.append(_data.at(*it));
appendElevation(ret);
return ret;
}
void POI::enableFile(const QString &fileName, bool enable)
{
int i;

View File

@ -7,8 +7,10 @@
#include <QStringList>
#include "common/rtree.h"
#include "waypoint.h"
#include "path.h"
class Path;
class Area;
class RectC;
class POI : public QObject
{
@ -28,6 +30,7 @@ public:
QList<Waypoint> points(const Path &path) const;
QList<Waypoint> points(const Waypoint &point) const;
QList<Waypoint> points(const Area &area) const;
const QStringList &files() const {return _files;}
void enableFile(const QString &fileName, bool enable);

15
src/data/polygon.cpp Normal file
View File

@ -0,0 +1,15 @@
#include "polygon.h"
RectC Polygon::boundingRect() const
{
if (isEmpty())
return RectC();
if (first().size() < 3)
return RectC();
RectC rect;
for (int i = 0; i < first().size(); i++)
rect = rect.united(first().at(i));
return rect;
}

17
src/data/polygon.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef POLYGON_H
#define POLYGON_H
#include <QList>
#include <QVector>
#include "common/coordinates.h"
#include "common/rectc.h"
class Polygon : public QList<QVector<Coordinates> >
{
public:
bool isValid() const {return !isEmpty() && first().size() >= 3;}
RectC boundingRect() const;
};
#endif // POLYGON_H

View File

@ -19,9 +19,11 @@ Route::Route(const RouteData &data) : _data(data)
Path Route::path() const
{
Path ret;
ret.append(PathSegment());
PathSegment &ps = ret.last();
for (int i = 0; i < _data.size(); i++)
ret.append(PathPoint(_data.at(i).coordinates(), _distance.at(i)));
ps.append(PathPoint(_data.at(i).coordinates(), _distance.at(i)));
return ret;
}
@ -29,17 +31,19 @@ Path Route::path() const
Graph Route::elevation() const
{
Graph graph;
graph.append(GraphSegment());
GraphSegment &gs = graph.last();
for (int i = 0; i < _data.size(); i++) {
if (_data.at(i).hasElevation() && !_useDEM)
graph.append(GraphPoint(_distance.at(i), NAN,
gs.append(GraphPoint(_distance.at(i), NAN,
_data.at(i).elevation()));
else {
qreal elevation = DEM::elevation(_data.at(i).coordinates());
if (!std::isnan(elevation))
graph.append(GraphPoint(_distance.at(i), NAN, elevation));
gs.append(GraphPoint(_distance.at(i), NAN, elevation));
else if (_data.at(i).hasElevation())
graph.append(GraphPoint(_distance.at(i), NAN,
gs.append(GraphPoint(_distance.at(i), NAN,
_data.at(i).elevation()));
}
}

View File

@ -22,12 +22,12 @@ public:
const QString &name() const {return _data.name();}
const QString &description() const {return _data.description();}
bool isNull() const {return (_data.count() < 2);}
bool isValid() const {return _data.size() >= 2;}
static void useDEM(bool use) {_useDEM = use;}
private:
const RouteData &_data;
RouteData _data;
QVector<qreal> _distance;
static bool _useDEM;

View File

@ -26,7 +26,7 @@ bool SLFParser::data(const QXmlStreamAttributes &attr, const char *name,
return res;
}
void SLFParser::entries(const QDateTime &date, TrackData &track)
void SLFParser::entries(const QDateTime &date, SegmentData &segment)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("Entry")) {
@ -60,7 +60,7 @@ void SLFParser::entries(const QDateTime &date, TrackData &track)
if (data(attr, "trainingTimeAbsolute", val))
t.setTimestamp(date.addMSecs(val * 10));
track.append(t);
segment.append(t);
}
_reader.skipCurrentElement();
@ -89,9 +89,10 @@ void SLFParser::activity(TrackData &track)
QDateTime date;
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("Entries"))
entries(date, track);
else if (_reader.name() == QLatin1String("GeneralInformation"))
if (_reader.name() == QLatin1String("Entries")) {
track.append(SegmentData());
entries(date, track.last());
} else if (_reader.name() == QLatin1String("GeneralInformation"))
generalInformation(date, track);
else
_reader.skipCurrentElement();
@ -99,10 +100,12 @@ void SLFParser::activity(TrackData &track)
}
bool SLFParser::parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QVector<Waypoint> &waypoints)
QList<RouteData> &routes, QList<Area> &polygons,
QVector<Waypoint> &waypoints)
{
Q_UNUSED(waypoints);
Q_UNUSED(routes);
Q_UNUSED(polygons);
_reader.clear();
_reader.setDevice(file);

View File

@ -8,15 +8,15 @@ class QDateTime;
class SLFParser : public Parser
{
bool parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QVector<Waypoint> &waypoints);
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
QList<Area> &polygons, QVector<Waypoint> &waypoints);
QString errorString() const {return _reader.errorString();}
int errorLine() const {return _reader.lineNumber();}
private:
void generalInformation(QDateTime &date, TrackData &track);
void activity(TrackData &track);
void entries(const QDateTime &date, TrackData &track);
void entries(const QDateTime &date, SegmentData &segment);
bool data(const QXmlStreamAttributes &attr, const char *name, qreal &val);
void warning(const char *text) const;

View File

@ -116,14 +116,14 @@ void TCXParser::waypointData(Waypoint &waypoint)
}
}
void TCXParser::trackpoints(TrackData &track)
void TCXParser::trackpoints(SegmentData &segment)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("Trackpoint")) {
Trackpoint t;
trackpointData(t);
if (t.coordinates().isValid())
track.append(t);
segment.append(t);
else
warning("Missing Trackpoint coordinates");
} else
@ -131,11 +131,11 @@ void TCXParser::trackpoints(TrackData &track)
}
}
void TCXParser::lap(TrackData &track)
void TCXParser::lap(SegmentData &segment)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("Track"))
trackpoints(track);
trackpoints(segment);
else
_reader.skipCurrentElement();
}
@ -144,9 +144,10 @@ void TCXParser::lap(TrackData &track)
void TCXParser::course(QVector<Waypoint> &waypoints, TrackData &track)
{
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("Track"))
trackpoints(track);
else if (_reader.name() == QLatin1String("Name"))
if (_reader.name() == QLatin1String("Track")) {
track.append(SegmentData());
trackpoints(track.last());
} else if (_reader.name() == QLatin1String("Name"))
track.setName(_reader.readElementText());
else if (_reader.name() == QLatin1String("Notes"))
track.setDescription(_reader.readElementText());
@ -164,9 +165,11 @@ void TCXParser::course(QVector<Waypoint> &waypoints, TrackData &track)
void TCXParser::activity(TrackData &track)
{
track.append(SegmentData());
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("Lap"))
lap(track);
lap(track.last());
else if (_reader.name() == QLatin1String("Notes"))
track.setDescription(_reader.readElementText());
else
@ -190,7 +193,7 @@ void TCXParser::sport(QList<TrackData> &tracks)
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("Activity")) {
tracks.append(TrackData());
activity(tracks.back());
activity(tracks.last());
} else
_reader.skipCurrentElement();
}
@ -212,7 +215,7 @@ void TCXParser::activities(QList<TrackData> &tracks)
while (_reader.readNextStartElement()) {
if (_reader.name() == QLatin1String("Activity")) {
tracks.append(TrackData());
activity(tracks.back());
activity(tracks.last());
} else if (_reader.name() == QLatin1String("MultiSportSession"))
multiSportSession(tracks);
else
@ -233,9 +236,11 @@ void TCXParser::tcx(QList<TrackData> &tracks, QVector<Waypoint> &waypoints)
}
bool TCXParser::parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QVector<Waypoint> &waypoints)
QList<RouteData> &routes, QList<Area> &polygons,
QVector<Waypoint> &waypoints)
{
Q_UNUSED(routes);
Q_UNUSED(polygons);
_reader.clear();
_reader.setDevice(file);

View File

@ -8,8 +8,8 @@
class TCXParser : public Parser
{
public:
bool parse(QFile *file, QList<TrackData> &tracks,
QList<RouteData> &routes, QVector<Waypoint> &waypoints);
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
QList<Area> &polygons, QVector<Waypoint> &waypoints);
QString errorString() const {return _reader.errorString();}
int errorLine() const {return _reader.lineNumber();}
@ -21,8 +21,8 @@ private:
void sport(QList<TrackData> &tracks);
void course(QVector<Waypoint> &waypoints, TrackData &track);
void activity(TrackData &track);
void lap(TrackData &track);
void trackpoints(TrackData &track);
void lap(SegmentData &segment);
void trackpoints(SegmentData &segment);
void trackpointData(Trackpoint &trackpoint);
void waypointData(Waypoint &waypoint);
void extensions(Trackpoint &trackpoint);

View File

@ -45,13 +45,13 @@ static QSet<int> eliminate(const QVector<qreal> &v)
return rm;
}
static Graph filter(const Graph &g, int window)
static GraphSegment filter(const GraphSegment &g, int window)
{
if (g.size() < window || window < 2)
return Graph(g);
return GraphSegment(g);
qreal acc = 0;
Graph ret(g.size());
GraphSegment ret(g.size());
for (int i = 0; i < window; i++)
acc += g.at(i).y();
@ -70,239 +70,333 @@ static Graph filter(const Graph &g, int window)
}
Track::Track(const TrackData &data) : _data(data)
Track::Track(const TrackData &data) : _data(data), _pause(0)
{
QVector<qreal> acceleration;
qreal ds, dt;
_time.append(0);
_distance.append(0);
_speed.append(0);
acceleration.append(0);
for (int i = 1; i < _data.count(); i++) {
ds = _data.at(i).coordinates().distanceTo(_data.at(i-1).coordinates());
_distance.append(_distance.at(i-1) + ds);
if (_data.first().hasTimestamp() && _data.at(i).hasTimestamp()
&& _data.at(i).timestamp() >= _data.at(i-1).timestamp())
_time.append(_data.first().timestamp().msecsTo(
_data.at(i).timestamp()) / 1000.0);
else
_time.append(NAN);
dt = _time.at(i) - _time.at(i-1);
if (dt < 1e-3) {
_speed.append(_speed.at(i-1));
acceleration.append(acceleration.at(i-1));
} else {
_speed.append(ds / dt);
qreal dv = _speed.at(i) - _speed.at(i-1);
acceleration.append(dv / dt);
}
}
_pause = 0;
for (int i = 1; i < _data.count(); i++) {
if (_time.at(i) > _time.at(i-1) + _pauseInterval
&& _speed.at(i) < _pauseSpeed) {
_pause += _time.at(i) - _time.at(i-1);
_stop.insert(i-1);
_stop.insert(i);
}
}
if (!_outlierEliminate)
return;
_outliers = eliminate(acceleration);
QSet<int>::const_iterator it;
for (it = _stop.constBegin(); it != _stop.constEnd(); ++it)
_outliers.remove(*it);
int last = 0;
for (int i = 0; i < _data.size(); i++) {
if (_outliers.contains(i))
last++;
else
break;
}
for (int i = last + 1; i < _data.size(); i++) {
if (_outliers.contains(i))
const SegmentData &sd = _data.at(i);
if (sd.isEmpty())
continue;
if (discardStopPoint(i)) {
_distance[i] = _distance.at(last);
_speed[i] = 0;
} else {
ds = _data.at(i).coordinates().distanceTo(
_data.at(last).coordinates());
_distance[i] = _distance.at(last) + ds;
dt = _time.at(i) - _time.at(last);
_speed[i] = (dt < 1e-3) ? _speed.at(last) : ds / dt;
// precompute distances, times, speeds and acceleration
QVector<qreal> acceleration;
_segments.append(Segment());
Segment &seg = _segments.last();
seg.distance.append(i ? _segments.at(i-1).distance.last() : 0);
seg.time.append(i ? _segments.at(i-1).time.last() :
sd.first().hasTimestamp() ? 0 : NAN);
seg.speed.append(sd.first().hasTimestamp() ? 0 : NAN);
acceleration.append(sd.first().hasTimestamp() ? 0 : NAN);
for (int j = 1; j < sd.size(); j++) {
ds = sd.at(j).coordinates().distanceTo(
sd.at(j-1).coordinates());
seg.distance.append(seg.distance.last() + ds);
if (sd.at(j).timestamp() >= sd.at(j-1).timestamp())
dt = sd.at(j-1).timestamp().msecsTo(
sd.at(j).timestamp()) / 1000.0;
else
dt = NAN;
seg.time.append(seg.time.last() + dt);
if (dt < 1e-3) {
seg.speed.append(seg.speed.last());
acceleration.append(acceleration.last());
} else {
qreal v = ds / dt;
qreal dv = v - seg.speed.last();
seg.speed.append(v);
acceleration.append(dv / dt);
}
}
// get stop-points + pause duration
for (int j = 1; j < seg.time.size(); j++) {
if (seg.time.at(j) > seg.time.at(j-1) + _pauseInterval
&& seg.speed.at(j) < _pauseSpeed) {
_pause += seg.time.at(j) - seg.time.at(j-1);
seg.stop.insert(j-1);
seg.stop.insert(j);
}
}
if (!_outlierEliminate)
continue;
// eliminate outliers
seg.outliers = eliminate(acceleration);
// stop-points can not be outliers
QSet<int>::const_iterator it;
for (it = seg.stop.constBegin(); it != seg.stop.constEnd(); ++it)
seg.outliers.remove(*it);
// recompute distances (and dependand data) without outliers
int last = 0;
for (int j = 0; j < sd.size(); j++) {
if (seg.outliers.contains(j))
last++;
else
break;
}
for (int j = last + 1; j < sd.size(); j++) {
if (seg.outliers.contains(j))
continue;
if (discardStopPoint(seg, j)) {
seg.distance[j] = seg.distance.at(last);
seg.speed[j] = 0;
} else {
ds = sd.at(j).coordinates().distanceTo(
sd.at(last).coordinates());
seg.distance[j] = seg.distance.at(last) + ds;
dt = seg.time.at(j) - seg.time.at(last);
seg.speed[j] = (dt < 1e-3) ? seg.speed.at(last) : ds / dt;
}
last = j;
}
last = i;
}
}
Graph Track::elevation() const
{
Graph raw;
Graph ret;
for (int i = 0; i < _data.size(); i++) {
if (_outliers.contains(i))
const SegmentData &sd = _data.at(i);
if (sd.size() < 2)
continue;
const Segment &seg = _segments.at(i);
GraphSegment gs;
if (_data.at(i).hasElevation() && !_useDEM)
raw.append(GraphPoint(_distance.at(i), _time.at(i),
_data.at(i).elevation()));
else {
qreal elevation = DEM::elevation(_data.at(i).coordinates());
if (!std::isnan(elevation))
raw.append(GraphPoint(_distance.at(i), _time.at(i), elevation));
else if (_data.at(i).hasElevation())
raw.append(GraphPoint(_distance.at(i), _time.at(i),
_data.at(i).elevation()));
for (int j = 0; j < sd.size(); j++) {
if (seg.outliers.contains(j))
continue;
if (sd.at(j).hasElevation() && !_useDEM)
gs.append(GraphPoint(seg.distance.at(j), seg.time.at(j),
sd.at(j).elevation()));
else {
qreal elevation = DEM::elevation(sd.at(j).coordinates());
if (!std::isnan(elevation))
gs.append(GraphPoint(seg.distance.at(j), seg.time.at(j),
elevation));
else if (sd.at(j).hasElevation())
gs.append(GraphPoint(seg.distance.at(j), seg.time.at(j),
sd.at(j).elevation()));
}
}
ret.append(filter(gs, _elevationWindow));
}
return filter(raw, _elevationWindow);
return ret;
}
Graph Track::speed() const
{
Graph raw, filtered;
qreal v;
QList<int> stop;
Graph ret;
for (int i = 0; i < _data.size(); i++) {
if (_stop.contains(i) && (!std::isnan(_speed.at(i))
|| _data.at(i).hasSpeed())) {
v = 0;
stop.append(raw.size());
} else if (_useReportedSpeed && _data.at(i).hasSpeed()
&& !_outliers.contains(i))
v = _data.at(i).speed();
else if (!std::isnan(_speed.at(i)) && !_outliers.contains(i))
v = _speed.at(i);
else
const SegmentData &sd = _data.at(i);
if (sd.size() < 2)
continue;
const Segment &seg = _segments.at(i);
GraphSegment gs;
QList<int> stop;
qreal v;
raw.append(GraphPoint(_distance.at(i), _time.at(i), v));
for (int j = 0; j < sd.size(); j++) {
if (seg.stop.contains(j) && (!std::isnan(seg.speed.at(j))
|| sd.at(j).hasSpeed())) {
v = 0;
stop.append(gs.size());
} else if (_useReportedSpeed && sd.at(j).hasSpeed()
&& seg.outliers.contains(j))
v = sd.at(j).speed();
else if (!std::isnan(seg.speed.at(j)) && !seg.outliers.contains(j))
v = seg.speed.at(j);
else
continue;
gs.append(GraphPoint(seg.distance.at(j), seg.time.at(j), v));
}
ret.append(filter(gs, _speedWindow));
GraphSegment &filtered = ret.last();
for (int j = 0; j < stop.size(); j++)
filtered[stop.at(j)].setY(0);
}
filtered = filter(raw, _speedWindow);
for (int i = 0; i < stop.size(); i++)
filtered[stop.at(i)].setY(0);
return filtered;
return ret;
}
Graph Track::heartRate() const
{
Graph raw;
Graph ret;
for (int i = 0; i < _data.count(); i++)
if (_data.at(i).hasHeartRate() && !_outliers.contains(i))
raw.append(GraphPoint(_distance.at(i), _time.at(i),
_data.at(i).heartRate()));
for (int i = 0; i < _data.size(); i++) {
const SegmentData &sd = _data.at(i);
if (sd.size() < 2)
continue;
const Segment &seg = _segments.at(i);
GraphSegment gs;
return filter(raw, _heartRateWindow);
for (int j = 0; j < sd.size(); j++)
if (sd.at(j).hasHeartRate() && !seg.outliers.contains(j))
gs.append(GraphPoint(seg.distance.at(j), seg.time.at(j),
sd.at(j).heartRate()));
ret.append(filter(gs, _heartRateWindow));
}
return ret;
}
Graph Track::temperature() const
{
Graph raw;
Graph ret;
for (int i = 0; i < _data.size(); i++)
if (_data.at(i).hasTemperature() && !_outliers.contains(i))
raw.append(GraphPoint(_distance.at(i), _time.at(i),
_data.at(i).temperature()));
for (int i = 0; i < _data.size(); i++) {
const SegmentData &sd = _data.at(i);
if (sd.size() < 2)
continue;
const Segment &seg = _segments.at(i);
GraphSegment gs;
return raw;
for (int j = 0; j < sd.count(); j++) {
if (sd.at(j).hasTemperature() && !seg.outliers.contains(j))
gs.append(GraphPoint(seg.distance.at(j), seg.time.at(j),
sd.at(j).temperature()));
}
ret.append(gs);
}
return ret;
}
Graph Track::ratio() const
{
Graph raw;
Graph ret;
for (int i = 0; i < _data.size(); i++)
if (_data.at(i).hasRatio() && !_outliers.contains(i))
raw.append(GraphPoint(_distance.at(i), _time.at(i),
_data.at(i).ratio()));
for (int i = 0; i < _data.size(); i++) {
const SegmentData &sd = _data.at(i);
if (sd.size() < 2)
continue;
const Segment &seg = _segments.at(i);
GraphSegment gs;
return raw;
for (int j = 0; j < sd.size(); j++)
if (sd.at(j).hasRatio() && !seg.outliers.contains(j))
gs.append(GraphPoint(seg.distance.at(j), seg.time.at(j),
sd.at(j).ratio()));
ret.append(gs);
}
return ret;
}
Graph Track::cadence() const
{
Graph raw, filtered;
QList<int> stop;
qreal c;
Graph ret;
for (int i = 0; i < _data.size(); i++) {
if (_data.at(i).hasCadence() && _stop.contains(i)) {
c = 0;
stop.append(raw.size());
} else if (_data.at(i).hasCadence() && !_outliers.contains(i))
c = _data.at(i).cadence();
else
const SegmentData &sd = _data.at(i);
if (sd.size() < 2)
continue;
const Segment &seg = _segments.at(i);
GraphSegment gs;
QList<int> stop;
qreal c;
raw.append(GraphPoint(_distance.at(i), _time.at(i), c));
for (int j = 0; j < sd.size(); j++) {
if (sd.at(j).hasCadence() && seg.stop.contains(j)) {
c = 0;
stop.append(gs.size());
} else if (sd.at(j).hasCadence() && !seg.outliers.contains(j))
c = sd.at(j).cadence();
else
continue;
gs.append(GraphPoint(seg.distance.at(j), seg.time.at(j), c));
}
ret.append(filter(gs, _cadenceWindow));
GraphSegment &filtered = ret.last();
for (int j = 0; j < stop.size(); j++)
filtered[stop.at(j)].setY(0);
}
filtered = filter(raw, _cadenceWindow);
for (int i = 0; i < stop.size(); i++)
filtered[stop.at(i)].setY(0);
return filtered;
return ret;
}
Graph Track::power() const
{
Graph raw, filtered;
Graph ret;
QList<int> stop;
qreal p;
for (int i = 0; i < _data.size(); i++) {
if (_data.at(i).hasPower() && _stop.contains(i)) {
p = 0;
stop.append(raw.size());
} else if (_data.at(i).hasPower() && !_outliers.contains(i))
p = _data.at(i).power();
else
continue;
raw.append(GraphPoint(_distance.at(i), _time.at(i), p));
for (int i = 0; i < _data.size(); i++) {
const SegmentData &sd = _data.at(i);
if (sd.size() < 2)
continue;
const Segment &seg = _segments.at(i);
GraphSegment gs;
for (int j = 0; j < sd.size(); j++) {
if (sd.at(j).hasPower() && seg.stop.contains(j)) {
p = 0;
stop.append(gs.size());
} else if (sd.at(j).hasPower() && !seg.outliers.contains(j))
p = sd.at(j).power();
else
continue;
gs.append(GraphPoint(seg.distance.at(j), seg.time.at(j), p));
}
ret.append(filter(gs, _powerWindow));
GraphSegment &filtered = ret.last();
for (int j = 0; j < stop.size(); j++)
filtered[stop.at(j)].setY(0);
}
filtered = filter(raw, _powerWindow);
for (int i = 0; i < stop.size(); i++)
filtered[stop.at(i)].setY(0);
return filtered;
return ret;
}
qreal Track::distance() const
{
for (int i = _distance.size() - 1; i >= 0; i--)
if (!_outliers.contains(i))
return _distance.at(i);
for (int i = _segments.size() - 1; i >= 0; i--) {
const Segment &seg = _segments.at(i);
for (int j = seg.distance.size() - 1; j >= 0; j--)
if (!seg.outliers.contains(j))
return seg.distance.at(j);
}
return 0;
}
qreal Track::time() const
{
for (int i = _data.size() - 1; i >= 0; i--)
if (!_outliers.contains(i))
return _data.first().timestamp().msecsTo(_data.at(i).timestamp())
/ 1000.0;
for (int i = _segments.size() - 1; i >= 0; i--) {
const Segment &seg = _segments.at(i);
for (int j = seg.time.size() - 1; j >= 0; j--)
if (!seg.outliers.contains(j))
return seg.time.at(j);
}
return 0;
}
@ -314,22 +408,41 @@ qreal Track::movingTime() const
QDateTime Track::date() const
{
return (_data.size()) ? _data.first().timestamp() : QDateTime();
return (_data.size() && _data.first().size())
? _data.first().first().timestamp() : QDateTime();
}
Path Track::path() const
{
Path ret;
for (int i = 0; i < _data.size(); i++)
if (!_outliers.contains(i) && !discardStopPoint(i))
ret.append(PathPoint(_data.at(i).coordinates(), _distance.at(i)));
for (int i = 0; i < _data.size(); i++) {
const SegmentData &sd = _data.at(i);
if (sd.size() < 2)
continue;
const Segment &seg = _segments.at(i);
ret.append(PathSegment());
PathSegment &ps = ret.last();
for (int j = 0; j < sd.size(); j++)
if (!seg.outliers.contains(j) && !discardStopPoint(seg, j))
ps.append(PathPoint(sd.at(j).coordinates(),
seg.distance.at(j)));
}
return ret;
}
bool Track::discardStopPoint(int i) const
bool Track::discardStopPoint(const Segment &seg, int i) const
{
return (_stop.contains(i) && i > 0 && _stop.contains(i-1)
&& i < _data.size() - 1 && _stop.contains(i+1));
return (seg.stop.contains(i) && seg.stop.contains(i-1)
&& seg.stop.contains(i+1) && i > 0 && i < seg.distance.size() - 1);
}
bool Track::isValid() const
{
for (int i = 0; i < _data.size(); i++)
if (_data.at(i).size() >= 2)
return true;
return false;
}

View File

@ -33,7 +33,7 @@ public:
const QString &name() const {return _data.name();}
const QString &description() const {return _data.description();}
bool isNull() const {return (_data.size() < 2);}
bool isValid() const;
static void setElevationFilter(int window) {_elevationWindow = window;}
static void setSpeedFilter(int window) {_speedWindow = window;}
@ -48,17 +48,18 @@ public:
static void useDEM(bool use) {_useDEM = use;}
private:
bool discardStopPoint(int i) const;
struct Segment {
QVector<qreal> distance;
QVector<qreal> time;
QVector<qreal> speed;
QSet<int> outliers;
QSet<int> stop;
};
const TrackData &_data;
QVector<qreal> _distance;
QVector<qreal> _time;
QVector<qreal> _speed;
QSet<int> _outliers;
QSet<int> _stop;
bool discardStopPoint(const Segment &seg, int i) const;
TrackData _data;
QList<Segment> _segments;
qreal _pause;
static bool _outlierEliminate;

View File

@ -1,11 +1,14 @@
#ifndef TRACKDATA_H
#define TRACKDATA_H
#include <QList>
#include <QVector>
#include <QString>
#include "trackpoint.h"
class TrackData : public QVector<Trackpoint>
typedef QVector<Trackpoint> SegmentData;
class TrackData : public QList<SegmentData>
{
public:
const QString& name() const {return _name;}

View File

@ -57,6 +57,7 @@
#define CT_LambertAzimEqualArea 10
#define CT_AlbersEqualArea 11
#define CT_PolarStereographic 15
#define CT_ObliqueStereographic 16
#define IS_SET(map, key) \
@ -347,6 +348,8 @@ Projection::Method GeoTIFF::method(QMap<quint16, Value> &kv)
return Projection::Method(9822);
case CT_PolarStereographic:
return Projection::Method(9829);
case CT_ObliqueStereographic:
return Projection::Method(9809);
default:
_errorString = QString("%1: unknown coordinate transformation method")
.arg(kv.value(ProjCoordTransGeoKey).SHORT);

View File

@ -20,13 +20,11 @@ bool MapList::loadMap(Map* map, const QString &path, bool dir)
_errorString += path + ": " + map->errorString() + "\n";
else
_errorString = map->errorString();
delete map;
return false;
}
}
bool MapList::loadSource(const QString &path, bool dir)
Map *MapList::loadSource(const QString &path, bool dir)
{
QString err;
Map *map = MapSource::loadMap(path, err);
@ -36,31 +34,39 @@ bool MapList::loadSource(const QString &path, bool dir)
_errorString += path + ": " + err + "\n";
else
_errorString = err;
return false;
}
map->setParent(this);
} else
map->setParent(this);
return loadMap(map, path, dir);
return map;
}
bool MapList::loadFile(const QString &path, bool *atlas, bool dir)
{
QFileInfo fi(path);
QString suffix = fi.suffix().toLower();
Map *map;
if (Atlas::isAtlas(path)) {
*atlas = true;
return loadMap(new Atlas(path, this), path, dir);
} else if (suffix == "xml")
return loadSource(path, dir);
else if (suffix == "jnx")
return loadMap(new JNXMap(path, this), path, dir);
map = new Atlas(path, this);
} else if (suffix == "xml") {
if (!(map = loadSource(path, dir)))
return false;
} else if (suffix == "jnx")
map = new JNXMap(path, this);
else if (suffix == "tif" || suffix == "tiff")
return loadMap(new GeoTIFFMap(path, this), path, dir);
map = new GeoTIFFMap(path, this);
else if (suffix == "mbtiles")
return loadMap(new MBTilesMap(path, this), path, dir);
map = new MBTilesMap(path, this);
else
return loadMap(new OziMap(path, this), path, dir);
map = new OziMap(path, this);
if (!loadMap(map, path, dir)) {
delete map;
return false;
}
return true;
}
bool MapList::loadDirR(const QString &path)
@ -104,13 +110,6 @@ bool MapList::loadDir(const QString &path)
return loadDirR(path);
}
void MapList::clear()
{
for (int i = 0; i < _maps.count(); i++)
delete _maps.at(i);
_maps.clear();
}
QString MapList::formats()
{
return

View File

@ -15,7 +15,6 @@ public:
bool loadFile(const QString &path);
bool loadDir(const QString &path);
void clear();
const QList<Map*> &maps() const {return _maps;}
const QString &errorString() const {return _errorString;}
@ -26,7 +25,7 @@ public:
private:
bool loadFile(const QString &path, bool *atlas, bool dir);
bool loadDirR(const QString &path);
bool loadSource(const QString &path, bool dir);
Map *loadSource(const QString &path, bool dir);
bool loadMap(Map *map, const QString &path, bool dir);
QList<Map*> _maps;

Some files were not shown because too many files have changed in this diff Show More