mirror of
https://github.com/tumic0/GPXSee.git
synced 2025-07-06 15:42:51 +02:00
Compare commits
77 Commits
Author | SHA1 | Date | |
---|---|---|---|
fc8fda7a82 | |||
18392db8f0 | |||
4aa1f7a557 | |||
bb71cfc426 | |||
8807c37770 | |||
e2eec179d5 | |||
1f5922685b | |||
dc70af3f3c | |||
e499574a50 | |||
5840e6832f | |||
463ac2d243 | |||
481138ec6e | |||
a320231dff | |||
a7ab72c564 | |||
7f7d7a916a | |||
a9ddd4d20f | |||
2e036279bb | |||
dea135d9df | |||
12f3c252bb | |||
a1ef211d0f | |||
3d0c36b459 | |||
eb2af0fb5c | |||
2da8efd497 | |||
c0e55ec25c | |||
a2b8cec3be | |||
064928f844 | |||
693cce4da3 | |||
a7570faed7 | |||
4ccb57ffd7 | |||
cece8002e2 | |||
451c0c757f | |||
e13bded88f | |||
9887151bfd | |||
b535ed239b | |||
9f43594abd | |||
87cbd7bdb1 | |||
d49420e88d | |||
d9d8588d8d | |||
a0eacedf3a | |||
e04179e63e | |||
79ecc565eb | |||
aaf8c12084 | |||
4ab4ff9bf1 | |||
d5367ccf34 | |||
54d0eea43e | |||
6543de4ca3 | |||
b06ce107af | |||
47c408703f | |||
3033ce2d6c | |||
1444a88ad0 | |||
ec9d81c65a | |||
a777008fe4 | |||
a73c96996d | |||
d168fd8cd5 | |||
a8df2f68d1 | |||
be07640634 | |||
9924702ba7 | |||
6ee2322033 | |||
08f2d4e4d2 | |||
69d635be10 | |||
a6b327f773 | |||
143f53fbd9 | |||
5432a835f9 | |||
cd74b0d43e | |||
94374e748b | |||
a882d1fe68 | |||
4a8be940a1 | |||
f379da61e3 | |||
9f1b697bcf | |||
0308dbbb09 | |||
516ca53ff0 | |||
3c112b0b6f | |||
54f24880cf | |||
67168b8063 | |||
4854bff31b | |||
50306ecb84 | |||
91e633e9fa |
@ -1,4 +1,4 @@
|
||||
version: 7.2.{build}
|
||||
version: 7.3.{build}
|
||||
configuration: Release
|
||||
platform: Any CPU
|
||||
environment:
|
||||
|
@ -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.
|
||||
|
||||

|
||||
|
||||
|
28
gpxsee.pro
28
gpxsee.pro
@ -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
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
@ -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.
|
@ -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"
|
||||
|
@ -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
155
src/GUI/areaitem.cpp
Normal 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
46
src/GUI/areaitem.h
Normal 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
|
@ -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();
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
57
src/GUI/coordinatesitem.cpp
Normal file
57
src/GUI/coordinatesitem.cpp
Normal 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
30
src/GUI/coordinatesitem.h
Normal 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
|
@ -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();
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
117
src/GUI/gui.cpp
117
src/GUI/gui.cpp
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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)));
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ public:
|
||||
private:
|
||||
QString toolTip(Units units) const;
|
||||
|
||||
qreal _avg, _min, _max;
|
||||
qreal _min, _max, _avg;
|
||||
};
|
||||
|
||||
#endif // TEMPERATUREGRAPHITEM_H
|
||||
|
@ -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++)
|
||||
|
@ -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
39
src/data/area.h
Normal 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
|
@ -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;
|
||||
|
@ -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;}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;}
|
||||
|
||||
|
@ -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";
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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();}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
15
src/data/polygon.cpp
Normal 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
17
src/data/polygon.h
Normal 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
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
Reference in New Issue
Block a user