mirror of
https://github.com/tumic0/GPXSee.git
synced 2025-07-04 06:49:16 +02:00
Compare commits
332 Commits
Author | SHA1 | Date | |
---|---|---|---|
9e7ebe930e | |||
19bc509043 | |||
335794ee21 | |||
2404107d87 | |||
9447addd19 | |||
b1647d944c | |||
77ac919b83 | |||
4d652aeaff | |||
3ef2361523 | |||
e2b1c2c778 | |||
1f5ecdfc38 | |||
c55b4f1217 | |||
fd71a4c7ce | |||
0b6b09f226 | |||
517ca89814 | |||
455ec3a54b | |||
8cb8d97ee2 | |||
40e520d3bf | |||
6b75442312 | |||
cbc5b2466e | |||
19a847c7d4 | |||
f9e5cb206f | |||
441c738d0f | |||
0bf6d41de6 | |||
b7869e985d | |||
5152d5eb0b | |||
c0653ab0a8 | |||
41d27cabe2 | |||
e2f2e9700f | |||
654bfcd058 | |||
82c0c1f8a7 | |||
9ce6e16b60 | |||
98cd3c3922 | |||
a776f1d30e | |||
aea17c9fed | |||
23c18d4acd | |||
eb8fc7b540 | |||
bf0dd1b24a | |||
9b687bb830 | |||
9859608115 | |||
3d66b2fbb6 | |||
9f62b7114e | |||
c8f7e6f691 | |||
c85f404d28 | |||
273a0f0f27 | |||
bb6d6a4044 | |||
bd3a3b90bc | |||
521369a6ec | |||
440a5736f6 | |||
45a6cdeda0 | |||
f73c27c39c | |||
12827edcb2 | |||
3ec5c37fd5 | |||
ee24bd54f1 | |||
cc22df3bf2 | |||
ef017edbf6 | |||
d7f0cda4b2 | |||
dc03ab91d6 | |||
a898ff2807 | |||
497017091f | |||
9dd4e117f6 | |||
86535021aa | |||
92deaaaf2b | |||
86a943d143 | |||
015a9187a0 | |||
1de9c6ef5d | |||
54b6225c6c | |||
48c7299ba6 | |||
c284b9fa7c | |||
2c503a2406 | |||
27edc4d6b5 | |||
f333a76ef7 | |||
2c114f43c5 | |||
29e29591f8 | |||
e4ac9fda0e | |||
26229e5871 | |||
64bee2f2f4 | |||
e4288ee95c | |||
c9b3c2eedd | |||
42e4b0769f | |||
ce043ef8fa | |||
8c7050e273 | |||
d670107a11 | |||
7b03c4d852 | |||
2002b828dd | |||
71f0e1d0ac | |||
eb9767f2dd | |||
8d06ab6208 | |||
187cb77858 | |||
8167a995f6 | |||
b5aed7314e | |||
464d4c5327 | |||
11f4dc4b41 | |||
2d3ad41d69 | |||
a7dcc57dd1 | |||
2d5e11f001 | |||
e86f89308b | |||
378fa8dc0e | |||
dde8903013 | |||
37c4fe1eba | |||
f9db0acb03 | |||
1aa07a6a34 | |||
c302a67299 | |||
8b6d7acec5 | |||
ba70fd159d | |||
1773a1ae0d | |||
136f08aa76 | |||
f70d92805b | |||
69e66f1856 | |||
911c63df0c | |||
d16899530a | |||
e2339c67cd | |||
c809d2f17e | |||
fac0bae006 | |||
9bd03c1225 | |||
d63c666997 | |||
0cd20a1e57 | |||
2f70d46be8 | |||
325e83569c | |||
56b374ed30 | |||
df1be4aeb9 | |||
d79bdaef78 | |||
fa0c09b30c | |||
95c82c501a | |||
3b16f37e66 | |||
661e26fbdb | |||
25939cfa62 | |||
c59ea4e5cd | |||
5de1bc7e7d | |||
7c3399575b | |||
7bedd17071 | |||
06a84dcea2 | |||
ca204626a1 | |||
d16ef7b081 | |||
ef013dc036 | |||
633d52daca | |||
adbb5e5684 | |||
bd9b09df3d | |||
ede2b6004f | |||
a516055dc2 | |||
1ba3ada96e | |||
1667e0ca70 | |||
cb03c8a903 | |||
b50d5227a5 | |||
eef6360643 | |||
f38db3227f | |||
ac73c04445 | |||
c3aeb95660 | |||
3299b41ec7 | |||
6bdd97611d | |||
58fd5022ca | |||
15e09539c7 | |||
ebe1851abb | |||
a225c6d308 | |||
b3ddbd7b63 | |||
a94056ac7e | |||
e5042b11d7 | |||
aea7bbdf09 | |||
2e0eadd0e7 | |||
1c9b31d7c9 | |||
42e917efab | |||
7a9b26756a | |||
07761ea335 | |||
eaae965719 | |||
f17e5c2ea1 | |||
ca6e8638d8 | |||
21bcaf9562 | |||
66a22fbfee | |||
a160cb4eb3 | |||
2d3ca7c5f8 | |||
f5ec18a13a | |||
8c71d11fa6 | |||
f6b15e1acc | |||
857c5050f4 | |||
652471ac90 | |||
44d1d27c93 | |||
2da1f8bc70 | |||
68e20cff5b | |||
2d4d2721bf | |||
1c67f1cac9 | |||
d74816883a | |||
a09d13594d | |||
81b5631de4 | |||
6916d0e6b4 | |||
757ec98108 | |||
2ddb5dc28b | |||
2e84901e43 | |||
f61fb5657c | |||
24e216cdfc | |||
09d6de00a6 | |||
f7990ee2e6 | |||
cb01c0b590 | |||
21cf5ddaec | |||
48d4686dd4 | |||
d035a307d8 | |||
89e04f3678 | |||
e664fc188c | |||
3597a07ed7 | |||
0472cc03f3 | |||
d169a9f710 | |||
2ff2195116 | |||
cdbf2db5fe | |||
2bb635a120 | |||
465b146001 | |||
ce6d6298bb | |||
ae2ff99be8 | |||
5b6cd24839 | |||
cd22e6207a | |||
b826e497f3 | |||
7cc39f25e1 | |||
f61d9fcd55 | |||
67a1f7e108 | |||
040de56a54 | |||
a486abb159 | |||
37215959b8 | |||
1ccce095a9 | |||
057180e431 | |||
60e62da6a2 | |||
a3eafea60a | |||
962f8de160 | |||
6525d34e08 | |||
3c661ddf65 | |||
42b4216d9c | |||
4e7418111d | |||
a89ef11d73 | |||
d8b54ac342 | |||
293046590e | |||
ea2f67fc09 | |||
60b33064a7 | |||
2efc6fb6d3 | |||
eb744df9cc | |||
8c9180190a | |||
6c6d297a3c | |||
6839119794 | |||
669715aa32 | |||
fdc172ab38 | |||
05f23de1ed | |||
9a0344adac | |||
b9d5fa8772 | |||
d4de0edca6 | |||
fdeb24a196 | |||
7f650f9d6a | |||
a986293f20 | |||
ec0b0adba0 | |||
52c6bb569e | |||
0f670f9ddd | |||
dba46b09a8 | |||
ce59f13de7 | |||
b8cf3872ce | |||
b59112f74e | |||
17b3602fda | |||
c0928097cc | |||
e709fad764 | |||
fb566ae163 | |||
3d8a4cc6b7 | |||
4eb44a53f7 | |||
b61c39ea46 | |||
4767be1972 | |||
ee9e17e31c | |||
3721084d21 | |||
6076c9d82e | |||
2ef499001d | |||
e4d8ab1feb | |||
2fc82aceab | |||
475eb6185a | |||
cdf3a48516 | |||
dcc3c0086a | |||
0d6aeecebb | |||
704c68443a | |||
183b02a5e7 | |||
e91815150d | |||
73c33450ee | |||
e06d07c176 | |||
c73f30e21f | |||
bbf2044729 | |||
4a86ab9d1e | |||
16c3fea8a8 | |||
f4ec9b6ac4 | |||
44155f9ef0 | |||
a5e809a0f3 | |||
3e70f9262b | |||
3573a2edbe | |||
82d9623c6d | |||
258a9b0201 | |||
36d84f6c98 | |||
15c79a7a13 | |||
34e0294815 | |||
ad6a04b975 | |||
e0f682fcd8 | |||
a801359eed | |||
bb238f4c7e | |||
c1ebc8e74b | |||
110c8c6bed | |||
e8fffe65bf | |||
1731aa1890 | |||
c389889662 | |||
e38e12f89b | |||
26f71f5d00 | |||
65e04ce08b | |||
d84d8e03e0 | |||
475ad358ae | |||
db7e60bdfb | |||
444791fb4c | |||
be3a882baa | |||
6d6dc9f316 | |||
d86e825c60 | |||
6bb2af3da8 | |||
d195526afb | |||
9ec3956672 | |||
3098d2ab95 | |||
dccf9f7e1a | |||
e55c29c33c | |||
bd5728ffa0 | |||
af525d4e3d | |||
96e0b584a0 | |||
0d6e3bac17 | |||
d292b5f533 | |||
ec2cb21a8a | |||
3632ed8816 | |||
58acea1a2d | |||
9e63e3f47e | |||
7581c8a32a | |||
8715e0e37b | |||
36b9813e1b | |||
1a59e1cb24 | |||
7f7d25a6fa | |||
87755952b6 | |||
3821eb4d84 | |||
15af82ee49 | |||
1f8a66108b | |||
9309dd945b | |||
858741c9a5 |
@ -1,22 +1,33 @@
|
|||||||
version: 7.17.{build}
|
version: 7.26.{build}
|
||||||
configuration: Release
|
|
||||||
platform: Any CPU
|
configuration:
|
||||||
|
- Release
|
||||||
|
|
||||||
|
image:
|
||||||
|
- Visual Studio 2017
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
NSISDIR: C:\Program Files (x86)\NSIS
|
NSISDIR: C:\Program Files (x86)\NSIS
|
||||||
matrix:
|
matrix:
|
||||||
- QTDIR: C:\Qt\5.11\msvc2015
|
- QTDIR: C:\Qt\5.13\msvc2017
|
||||||
PLATFORM: x86
|
|
||||||
NSI: gpxsee.nsi
|
NSI: gpxsee.nsi
|
||||||
OPENSSLDIR: C:\OpenSSL-Win32\bin
|
VCVARS: vcvars32.bat
|
||||||
- QTDIR: C:\Qt\5.11\msvc2015_64
|
OPENSSLDIR: C:\OpenSSL-v111-Win32\bin
|
||||||
PLATFORM: x86_amd64
|
LIBCRYPTO: libssl-1_1.dll
|
||||||
|
LIBSSL: libcrypto-1_1.dll
|
||||||
|
- QTDIR: C:\Qt\5.13\msvc2017_64
|
||||||
NSI: gpxsee64.nsi
|
NSI: gpxsee64.nsi
|
||||||
OPENSSLDIR: C:\OpenSSL-Win64\bin
|
VCVARS: vcvars64.bat
|
||||||
|
OPENSSLDIR: C:\OpenSSL-v111-Win64\bin
|
||||||
|
LIBCRYPTO: libssl-1_1-x64.dll
|
||||||
|
LIBSSL: libcrypto-1_1-x64.dll
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- cmd: >-
|
- cmd: >-
|
||||||
set PATH=%QTDIR%\bin;%NSISDIR%;%PATH%
|
set PATH=%QTDIR%\bin;%NSISDIR%;%PATH%
|
||||||
|
|
||||||
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %PLATFORM%
|
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\"%VCVARS%
|
||||||
|
|
||||||
build_script:
|
build_script:
|
||||||
- cmd: >-
|
- cmd: >-
|
||||||
lrelease gpxsee.pro
|
lrelease gpxsee.pro
|
||||||
@ -44,9 +55,9 @@ build_script:
|
|||||||
|
|
||||||
copy licence.txt installer
|
copy licence.txt installer
|
||||||
|
|
||||||
copy %OPENSSLDIR%\libeay32.dll installer
|
copy %OPENSSLDIR%\%LIBCRYPTO% installer
|
||||||
|
|
||||||
copy %OPENSSLDIR%\ssleay32.dll installer
|
copy %OPENSSLDIR%\%LIBSSL% installer
|
||||||
|
|
||||||
|
|
||||||
makensis.exe installer\%NSI%
|
makensis.exe installer\%NSI%
|
||||||
|
@ -6,6 +6,7 @@ os:
|
|||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get -qq update; fi
|
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get -qq update; fi
|
||||||
|
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install qt; fi
|
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install qt; fi
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
GPXSee is a Qt-based GPS log file viewer and analyzer that supports all common GPS log file formats.
|
GPXSee is a Qt-based GPS log file viewer and analyzer that supports all common GPS log file formats.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
* Opens GPX, TCX, FIT, KML, NMEA, IGC, CUP, SLF, LOC, GeoJSON, OziExplorer (PLT, RTE, WPT), Garmin GPI&CSV and geotagged JPEG files.
|
* Opens GPX, TCX, FIT, KML, NMEA, IGC, CUP, SIGMA SLF, Suunto SML, LOC, GeoJSON, OziExplorer (PLT, RTE, WPT), Garmin GPI&CSV and geotagged JPEG files.
|
||||||
* User-definable online maps (OpenStreetMap/Google tiles, WMTS, WMS, TMS, QuadTiles).
|
* User-definable online maps (OpenStreetMap/Google tiles, WMTS, WMS, TMS, QuadTiles).
|
||||||
* Offline maps (MBTiles, OziExplorer maps, TrekBuddy maps/atlases, Garmin IMG & JNX maps, TwoNav RMaps, GeoTIFF images).
|
* Offline maps (MBTiles, OziExplorer maps, TrekBuddy maps/atlases, Garmin IMG/GMAP & JNX maps, TwoNav RMaps, GeoTIFF images).
|
||||||
* Elevation, speed, heart rate, cadence, power, temperature and gear ratio/shifts graphs.
|
* Elevation, speed, heart rate, cadence, power, temperature and gear ratio/shifts graphs.
|
||||||
* Support for DEM files (SRTM HGT).
|
* Support for DEM files (SRTM HGT).
|
||||||
* Support for multiple tracks in one view.
|
* Support for multiple tracks in one view.
|
||||||
|
39
gpxsee.pro
39
gpxsee.pro
@ -3,7 +3,7 @@ unix:!macx {
|
|||||||
} else {
|
} else {
|
||||||
TARGET = GPXSee
|
TARGET = GPXSee
|
||||||
}
|
}
|
||||||
VERSION = 7.17
|
VERSION = 7.26
|
||||||
|
|
||||||
QT += core \
|
QT += core \
|
||||||
gui \
|
gui \
|
||||||
@ -20,7 +20,9 @@ equals(QT_MAJOR_VERSION, 5) : lessThan(QT_MINOR_VERSION, 4) {QT += opengl}
|
|||||||
INCLUDEPATH += ./src
|
INCLUDEPATH += ./src
|
||||||
HEADERS += src/common/config.h \
|
HEADERS += src/common/config.h \
|
||||||
src/GUI/graphicsscene.h \
|
src/GUI/graphicsscene.h \
|
||||||
|
src/GUI/mapaction.h \
|
||||||
src/GUI/popup.h \
|
src/GUI/popup.h \
|
||||||
|
src/common/garmin.h \
|
||||||
src/common/staticassert.h \
|
src/common/staticassert.h \
|
||||||
src/common/coordinates.h \
|
src/common/coordinates.h \
|
||||||
src/common/range.h \
|
src/common/range.h \
|
||||||
@ -88,6 +90,12 @@ HEADERS += src/common/config.h \
|
|||||||
src/GUI/areaitem.h \
|
src/GUI/areaitem.h \
|
||||||
src/data/link.h \
|
src/data/link.h \
|
||||||
src/map/IMG/bitmapline.h \
|
src/map/IMG/bitmapline.h \
|
||||||
|
src/map/IMG/bitstream.h \
|
||||||
|
src/map/IMG/deltastream.h \
|
||||||
|
src/map/IMG/gmap.h \
|
||||||
|
src/map/IMG/huffmanstream.h \
|
||||||
|
src/map/IMG/huffmantable.h \
|
||||||
|
src/map/IMG/mapdata.h \
|
||||||
src/map/IMG/textpathitem.h \
|
src/map/IMG/textpathitem.h \
|
||||||
src/map/IMG/textpointitem.h \
|
src/map/IMG/textpointitem.h \
|
||||||
src/map/projection.h \
|
src/map/projection.h \
|
||||||
@ -178,7 +186,6 @@ HEADERS += src/common/config.h \
|
|||||||
src/map/IMG/lblfile.h \
|
src/map/IMG/lblfile.h \
|
||||||
src/map/IMG/vectortile.h \
|
src/map/IMG/vectortile.h \
|
||||||
src/map/IMG/subdiv.h \
|
src/map/IMG/subdiv.h \
|
||||||
src/map/IMG/units.h \
|
|
||||||
src/map/IMG/style.h \
|
src/map/IMG/style.h \
|
||||||
src/map/IMG/netfile.h \
|
src/map/IMG/netfile.h \
|
||||||
src/GUI/limitedcombobox.h \
|
src/GUI/limitedcombobox.h \
|
||||||
@ -187,7 +194,9 @@ HEADERS += src/common/config.h \
|
|||||||
src/map/IMG/label.h \
|
src/map/IMG/label.h \
|
||||||
src/data/csv.h \
|
src/data/csv.h \
|
||||||
src/data/cupparser.h \
|
src/data/cupparser.h \
|
||||||
src/data/gpiparser.h
|
src/data/gpiparser.h \
|
||||||
|
src/data/address.h \
|
||||||
|
src/data/smlparser.h
|
||||||
SOURCES += src/main.cpp \
|
SOURCES += src/main.cpp \
|
||||||
src/GUI/popup.cpp \
|
src/GUI/popup.cpp \
|
||||||
src/common/coordinates.cpp \
|
src/common/coordinates.cpp \
|
||||||
@ -240,7 +249,14 @@ SOURCES += src/main.cpp \
|
|||||||
src/GUI/gearratiographitem.cpp \
|
src/GUI/gearratiographitem.cpp \
|
||||||
src/GUI/mapview.cpp \
|
src/GUI/mapview.cpp \
|
||||||
src/GUI/areaitem.cpp \
|
src/GUI/areaitem.cpp \
|
||||||
|
src/data/waypoint.cpp \
|
||||||
src/map/IMG/bitmapline.cpp \
|
src/map/IMG/bitmapline.cpp \
|
||||||
|
src/map/IMG/bitstream.cpp \
|
||||||
|
src/map/IMG/deltastream.cpp \
|
||||||
|
src/map/IMG/gmap.cpp \
|
||||||
|
src/map/IMG/huffmanstream.cpp \
|
||||||
|
src/map/IMG/huffmantable.cpp \
|
||||||
|
src/map/IMG/mapdata.cpp \
|
||||||
src/map/IMG/textpathitem.cpp \
|
src/map/IMG/textpathitem.cpp \
|
||||||
src/map/IMG/textpointitem.cpp \
|
src/map/IMG/textpointitem.cpp \
|
||||||
src/map/maplist.cpp \
|
src/map/maplist.cpp \
|
||||||
@ -323,7 +339,8 @@ SOURCES += src/main.cpp \
|
|||||||
src/data/csv.cpp \
|
src/data/csv.cpp \
|
||||||
src/data/cupparser.cpp \
|
src/data/cupparser.cpp \
|
||||||
src/GUI/graphicsscene.cpp \
|
src/GUI/graphicsscene.cpp \
|
||||||
src/data/gpiparser.cpp
|
src/data/gpiparser.cpp \
|
||||||
|
src/data/smlparser.cpp
|
||||||
|
|
||||||
greaterThan(QT_MAJOR_VERSION, 4) {
|
greaterThan(QT_MAJOR_VERSION, 4) {
|
||||||
HEADERS += src/data/geojsonparser.h
|
HEADERS += src/data/geojsonparser.h
|
||||||
@ -347,7 +364,9 @@ TRANSLATIONS = lang/gpxsee_en.ts \
|
|||||||
lang/gpxsee_da.ts \
|
lang/gpxsee_da.ts \
|
||||||
lang/gpxsee_tr.ts \
|
lang/gpxsee_tr.ts \
|
||||||
lang/gpxsee_es.ts \
|
lang/gpxsee_es.ts \
|
||||||
lang/gpxsee_pt_BR.ts
|
lang/gpxsee_pt_BR.ts \
|
||||||
|
lang/gpxsee_uk.ts \
|
||||||
|
lang/gpxsee_hu.ts
|
||||||
|
|
||||||
macx {
|
macx {
|
||||||
ICON = icons/gpxsee.icns
|
ICON = icons/gpxsee.icns
|
||||||
@ -365,7 +384,9 @@ macx {
|
|||||||
lang/gpxsee_da.qm \
|
lang/gpxsee_da.qm \
|
||||||
lang/gpxsee_tr.qm \
|
lang/gpxsee_tr.qm \
|
||||||
lang/gpxsee_es.qm \
|
lang/gpxsee_es.qm \
|
||||||
lang/gpxsee_pt_BR.qm
|
lang/gpxsee_pt_BR.qm \
|
||||||
|
lang/gpxsee_uk.qm \
|
||||||
|
lang/gpxsee_hu.qm
|
||||||
csv.path = Contents/Resources
|
csv.path = Contents/Resources
|
||||||
csv.files = pkg/csv
|
csv.files = pkg/csv
|
||||||
maps.path = Contents/Resources
|
maps.path = Contents/Resources
|
||||||
@ -384,7 +405,8 @@ macx {
|
|||||||
icons/formats/slf.icns \
|
icons/formats/slf.icns \
|
||||||
icons/formats/json.icns \
|
icons/formats/json.icns \
|
||||||
icons/formats/cup.icns \
|
icons/formats/cup.icns \
|
||||||
icons/formats/gpi.icns
|
icons/formats/gpi.icns \
|
||||||
|
icons/formats/sml.icns
|
||||||
QMAKE_BUNDLE_DATA += locale maps icons csv
|
QMAKE_BUNDLE_DATA += locale maps icons csv
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,7 +425,8 @@ win32 {
|
|||||||
icons/formats/slf.ico \
|
icons/formats/slf.ico \
|
||||||
icons/formats/json.ico \
|
icons/formats/json.ico \
|
||||||
icons/formats/cup.ico \
|
icons/formats/cup.ico \
|
||||||
icons/formats/gpi.ico
|
icons/formats/gpi.ico \
|
||||||
|
icons/formats/sml.ico
|
||||||
DEFINES += _USE_MATH_DEFINES \
|
DEFINES += _USE_MATH_DEFINES \
|
||||||
NOGDI
|
NOGDI
|
||||||
}
|
}
|
||||||
|
BIN
icons/formats/sml.icns
Normal file
BIN
icons/formats/sml.icns
Normal file
Binary file not shown.
BIN
icons/formats/sml.ico
Normal file
BIN
icons/formats/sml.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 304 KiB |
@ -12,3 +12,4 @@ loc:#556677
|
|||||||
slf:#881199
|
slf:#881199
|
||||||
cup:#20a810
|
cup:#20a810
|
||||||
gpi:#fca314
|
gpi:#fca314
|
||||||
|
sml:#6434eb
|
||||||
|
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
1922
lang/gpxsee_hu.ts
Normal file
1922
lang/gpxsee_hu.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
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
1924
lang/gpxsee_uk.ts
Normal file
1924
lang/gpxsee_uk.ts
Normal file
File diff suppressed because it is too large
Load Diff
@ -243,6 +243,22 @@
|
|||||||
<key>CFBundleTypeRole</key>
|
<key>CFBundleTypeRole</key>
|
||||||
<string>Viewer</string>
|
<string>Viewer</string>
|
||||||
</dict>
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleTypeExtensions</key>
|
||||||
|
<array>
|
||||||
|
<string>sml</string>
|
||||||
|
</array>
|
||||||
|
<key>CFBundleTypeMIMETypes</key>
|
||||||
|
<array>
|
||||||
|
<string>application/sml+xml</string>
|
||||||
|
</array>
|
||||||
|
<key>CFBundleTypeIconFile</key>
|
||||||
|
<string>icons/sml.icns</string>
|
||||||
|
<key>CFBundleTypeName</key>
|
||||||
|
<string>Suunto Markup Language</string>
|
||||||
|
<key>CFBundleTypeRole</key>
|
||||||
|
<string>Viewer</string>
|
||||||
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
|
|
||||||
<key>UTImportedTypeDeclarations</key>
|
<key>UTImportedTypeDeclarations</key>
|
||||||
@ -538,7 +554,28 @@
|
|||||||
<string>gpi</string>
|
<string>gpi</string>
|
||||||
</array>
|
</array>
|
||||||
<key>public.mime-type</key>
|
<key>public.mime-type</key>
|
||||||
<string>application/vnd.garmin.cup</string>
|
<string>application/vnd.garmin.gpi</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>UTTypeIdentifier</key>
|
||||||
|
<string>com.suunto.sml</string>
|
||||||
|
<key>UTTypeReferenceURL</key>
|
||||||
|
<string>https://www.suunto.com</string>
|
||||||
|
<key>UTTypeDescription</key>
|
||||||
|
<string>Suunto Markup Language</string>
|
||||||
|
<key>UTTypeConformsTo</key>
|
||||||
|
<array>
|
||||||
|
<string>public.xml</string>
|
||||||
|
</array>
|
||||||
|
<key>UTTypeTagSpecification</key>
|
||||||
|
<dict>
|
||||||
|
<key>public.filename-extension</key>
|
||||||
|
<array>
|
||||||
|
<string>sml</string>
|
||||||
|
</array>
|
||||||
|
<key>public.mime-type</key>
|
||||||
|
<string>application/sml+xml</string>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
|
@ -12,17 +12,18 @@
|
|||||||
|
|
||||||
<p>Features:</p>
|
<p>Features:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Opens GPX, TCX, FIT, KML, IGC, NMEA, SLF, LOC, OziExplorer (PLT,
|
<li>Opens GPX, TCX, FIT, KML, IGC, NMEA, SIGMA SLF, Suunto SML, LOC,
|
||||||
WPT, RTE), GeoJSON, SeeYou CUP, Garmin CSV and geotagged
|
OziExplorer (PLT, WPT, RTE), GeoJSON, SeeYou CUP,
|
||||||
JPEG files.</li>
|
Garmin GPI & CSV and geotagged JPEG files.</li>
|
||||||
<li>User-definable online maps (OpenStreetMap/Google tiles, WMTS,
|
<li>User-definable online maps (OpenStreetMap/Google tiles, WMTS,
|
||||||
WMS, TMS).</li>
|
WMS, TMS, QuadTiles).</li>
|
||||||
<li>Offline maps (MBTiles, OziExplorer maps, TrekBuddy maps/atlases,
|
<li>Offline maps (MBTiles, OziExplorer maps, TrekBuddy maps/atlases,
|
||||||
TwoNav RMaps, Garmin IMG & JNX, GeoTIFF images).</li>
|
TwoNav RMaps, Garmin IMG & JNX, GeoTIFF images).</li>
|
||||||
<li>Elevation, speed, heart rate, cadence, power and temperature
|
<li>Elevation, speed, heart rate, cadence, power, temperature and
|
||||||
graphs.</li>
|
gear ratio graphs.</li>
|
||||||
<li>Support for multiple tracks in one view.</li>
|
<li>Support for multiple tracks in one view.</li>
|
||||||
<li>Support for POI files.</li>
|
<li>Support for POI files.</li>
|
||||||
|
<li>Support for DEM files (SRTM HGT).</li>
|
||||||
<li>Print/export to PDF.</li>
|
<li>Print/export to PDF.</li>
|
||||||
<li>Full-screen mode.</li>
|
<li>Full-screen mode.</li>
|
||||||
<li>HiDPI/Retina displays & maps support.</li>
|
<li>HiDPI/Retina displays & maps support.</li>
|
||||||
@ -69,5 +70,7 @@
|
|||||||
<mimetype>application/slf+xml</mimetype>
|
<mimetype>application/slf+xml</mimetype>
|
||||||
<mimetype>application/geo+json</mimetype>
|
<mimetype>application/geo+json</mimetype>
|
||||||
<mimetype>application/vnd.naviter.seeyou.cup</mimetype>
|
<mimetype>application/vnd.naviter.seeyou.cup</mimetype>
|
||||||
|
<mimetype>application/vnd.garmin.gpi</mimetype>
|
||||||
|
<mimetype>application/sml+xml</mimetype>
|
||||||
</mimetypes>
|
</mimetypes>
|
||||||
</component>
|
</component>
|
||||||
|
@ -3,12 +3,16 @@ Name=GPXSee
|
|||||||
Comment=GPS log file viewer and analyzer
|
Comment=GPS log file viewer and analyzer
|
||||||
Comment[cz]=Prohlížeč a analyzátor GPS logů
|
Comment[cz]=Prohlížeč a analyzátor GPS logů
|
||||||
Comment[fi]=Ohjelma GPS-lokien katseluun ja analysointiin
|
Comment[fi]=Ohjelma GPS-lokien katseluun ja analysointiin
|
||||||
|
Comment[fr]=Visualisation et analyse de fichier GPS
|
||||||
|
Comment[nb]=GPS-loggfilleser og analysator
|
||||||
Comment[pl]=Przeglądarka i analizator plików dziennika GPS
|
Comment[pl]=Przeglądarka i analizator plików dziennika GPS
|
||||||
Comment[ru]=Программа для просмотра и анализа GPS логов
|
Comment[ru]=Программа для просмотра и анализа GPS логов
|
||||||
Comment[sv]=GPS-loggfilsläsare och analysator
|
Comment[sv]=GPS-loggfilsläsare och analysator
|
||||||
|
Comment[tr]=GPS günlük dosyası görüntüleyici ve analizcisi
|
||||||
|
Comment[uk]=Переглядач та аналізатор GPS логів
|
||||||
Exec=gpxsee %F
|
Exec=gpxsee %F
|
||||||
Icon=gpxsee
|
Icon=gpxsee
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Type=Application
|
Type=Application
|
||||||
Categories=Graphics;Viewer;Education;Geography;Maps;Sports;Qt;
|
Categories=Graphics;Viewer;Education;Geography;Maps;Sports;Qt;
|
||||||
MimeType=application/gpx+xml;application/tcx+xml;application/vnd.ant.fit;application/vnd.google-earth.kml+xml;application/vnd.fai.igc;application/vnd.nmea.nmea;application/vnd.oziexplorer.plt;application/vnd.oziexplorer.rte;application/vnd.oziexplorer.wpt;application/loc+xml;application/slf+xml;application/geo+json;application/vnd.naviter.seeyou.cup;
|
MimeType=application/gpx+xml;application/tcx+xml;application/vnd.ant.fit;application/vnd.google-earth.kml+xml;application/vnd.fai.igc;application/vnd.nmea.nmea;application/vnd.oziexplorer.plt;application/vnd.oziexplorer.rte;application/vnd.oziexplorer.wpt;application/loc+xml;application/slf+xml;application/geo+json;application/vnd.naviter.seeyou.cup;application/vnd.garmin.gpi;application/sml+xml;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
; The name of the installer
|
; The name of the installer
|
||||||
Name "GPXSee"
|
Name "GPXSee"
|
||||||
; Program version
|
; Program version
|
||||||
!define VERSION "7.17"
|
!define VERSION "7.26"
|
||||||
|
|
||||||
; The file to write
|
; The file to write
|
||||||
OutFile "GPXSee-${VERSION}.exe"
|
OutFile "GPXSee-${VERSION}.exe"
|
||||||
@ -106,20 +106,21 @@ Section "GPXSee" SEC_APP
|
|||||||
|
|
||||||
; Associate file formats
|
; Associate file formats
|
||||||
DetailPrint "Associating file types..."
|
DetailPrint "Associating file types..."
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "gpx" "GPS Exchange Format" 7
|
!insertmacro FILE_ASSOCIATION_ADD "gpx" "GPS Exchange Format" 8
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "tcx" "Training Center XML" 8
|
!insertmacro FILE_ASSOCIATION_ADD "tcx" "Training Center XML" 9
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "kml" "Keyhole Markup Language" 9
|
!insertmacro FILE_ASSOCIATION_ADD "kml" "Keyhole Markup Language" 10
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "fit" "Flexible and Interoperable Data Transfer" 10
|
!insertmacro FILE_ASSOCIATION_ADD "fit" "Flexible and Interoperable Data Transfer" 11
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "igc" "Flight Recorder Data Format" 11
|
!insertmacro FILE_ASSOCIATION_ADD "igc" "Flight Recorder Data Format" 12
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "nmea" "NMEA 0183 Data" 12
|
!insertmacro FILE_ASSOCIATION_ADD "nmea" "NMEA 0183 Data" 13
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "plt" "OziExplorer Track Point File" 13
|
!insertmacro FILE_ASSOCIATION_ADD "plt" "OziExplorer Track Point File" 14
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "rte" "OziExplorer Route File" 14
|
!insertmacro FILE_ASSOCIATION_ADD "rte" "OziExplorer Route File" 15
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "wpt" "OziExplorer Waypoint File" 1
|
!insertmacro FILE_ASSOCIATION_ADD "wpt" "OziExplorer Waypoint File" 1
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "loc" "Geocaching.com Waypoint File" 2
|
!insertmacro FILE_ASSOCIATION_ADD "loc" "Geocaching.com Waypoint File" 2
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "slf" "Sigma Log File" 3
|
!insertmacro FILE_ASSOCIATION_ADD "slf" "Sigma Log File" 3
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "geojson" "GeoJSON" 4
|
!insertmacro FILE_ASSOCIATION_ADD "geojson" "GeoJSON" 4
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "cup" "SeeYou CUP File" 5
|
!insertmacro FILE_ASSOCIATION_ADD "cup" "SeeYou CUP File" 5
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "gpi" "Garmin POI File" 6
|
!insertmacro FILE_ASSOCIATION_ADD "gpi" "Garmin POI File" 6
|
||||||
|
!insertmacro FILE_ASSOCIATION_ADD "sml" "Suunto Markup Language" 7
|
||||||
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
|
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
|
||||||
|
|
||||||
SectionEnd
|
SectionEnd
|
||||||
@ -147,30 +148,17 @@ Section "MSVC runtime" SEC_MSVC
|
|||||||
|
|
||||||
SectionIn RO
|
SectionIn RO
|
||||||
|
|
||||||
DetailPrint "Checking whether Visual C++ 2015 Redistributable is already installed..."
|
|
||||||
${If} ${RunningX64}
|
|
||||||
ReadRegDword $R0 HKLM "SOFTWARE\Wow6432Node\Microsoft\VisualStudio\14.0\VC\Runtimes\x86" "Installed"
|
|
||||||
${Else}
|
|
||||||
ReadRegDword $R0 HKLM "SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x86" "Installed"
|
|
||||||
${EndIf}
|
|
||||||
|
|
||||||
StrCmp $R0 "1" 0 +3
|
|
||||||
DetailPrint "Visual C++ 2015 Redistributable is already installed, skipping install."
|
|
||||||
Goto done
|
|
||||||
|
|
||||||
DetailPrint "Installing Visual C++ 2015 Redistributable..."
|
|
||||||
SetOutPath $TEMP
|
SetOutPath $TEMP
|
||||||
File "vcredist_x86.exe"
|
File "vc_redist.x86.exe"
|
||||||
ExecWait '"$TEMP\vcredist_x86.exe" /install /quiet /norestart'
|
ExecWait '"$TEMP\vc_redist.x86.exe" /install /quiet /norestart'
|
||||||
SetOutPath $INSTDIR
|
SetOutPath $INSTDIR
|
||||||
|
|
||||||
done:
|
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
Section "OpenSSL" SEC_OPENSSL
|
Section "OpenSSL" SEC_OPENSSL
|
||||||
|
|
||||||
File "libeay32.dll"
|
File "libcrypto-1_1.dll"
|
||||||
File "ssleay32.dll"
|
File "libssl-1_1.dll"
|
||||||
|
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
@ -188,6 +176,7 @@ SectionGroup "Localization" SEC_LOCALIZATION
|
|||||||
!insertmacro LOCALIZATION "Finnish" "fi"
|
!insertmacro LOCALIZATION "Finnish" "fi"
|
||||||
!insertmacro LOCALIZATION "French" "fr"
|
!insertmacro LOCALIZATION "French" "fr"
|
||||||
!insertmacro LOCALIZATION "German" "de"
|
!insertmacro LOCALIZATION "German" "de"
|
||||||
|
!insertmacro LOCALIZATION "Hungarian" "hu"
|
||||||
!insertmacro LOCALIZATION "Norwegian" "nb"
|
!insertmacro LOCALIZATION "Norwegian" "nb"
|
||||||
!insertmacro LOCALIZATION "Polish" "pl"
|
!insertmacro LOCALIZATION "Polish" "pl"
|
||||||
!insertmacro LOCALIZATION "Portuguese (Brazil)" "pt_BR"
|
!insertmacro LOCALIZATION "Portuguese (Brazil)" "pt_BR"
|
||||||
@ -195,6 +184,7 @@ SectionGroup "Localization" SEC_LOCALIZATION
|
|||||||
!insertmacro LOCALIZATION "Spanish" "es"
|
!insertmacro LOCALIZATION "Spanish" "es"
|
||||||
!insertmacro LOCALIZATION "Swedish" "sv"
|
!insertmacro LOCALIZATION "Swedish" "sv"
|
||||||
!insertmacro LOCALIZATION "Turkish" "tr"
|
!insertmacro LOCALIZATION "Turkish" "tr"
|
||||||
|
!insertmacro LOCALIZATION "Ukrainian" "uk"
|
||||||
SectionGroupEnd
|
SectionGroupEnd
|
||||||
|
|
||||||
;--------------------------------
|
;--------------------------------
|
||||||
@ -231,6 +221,7 @@ Section "Uninstall"
|
|||||||
!insertmacro FILE_ASSOCIATION_REMOVE "geojson"
|
!insertmacro FILE_ASSOCIATION_REMOVE "geojson"
|
||||||
!insertmacro FILE_ASSOCIATION_REMOVE "cup"
|
!insertmacro FILE_ASSOCIATION_REMOVE "cup"
|
||||||
!insertmacro FILE_ASSOCIATION_REMOVE "gpi"
|
!insertmacro FILE_ASSOCIATION_REMOVE "gpi"
|
||||||
|
!insertmacro FILE_ASSOCIATION_REMOVE "sml"
|
||||||
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
|
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
|
||||||
|
|
||||||
SectionEnd
|
SectionEnd
|
||||||
@ -243,7 +234,7 @@ SectionEnd
|
|||||||
LangString DESC_QT ${LANG_ENGLISH} \
|
LangString DESC_QT ${LANG_ENGLISH} \
|
||||||
"QT cross-platform application framework."
|
"QT cross-platform application framework."
|
||||||
LangString DESC_MSVC ${LANG_ENGLISH} \
|
LangString DESC_MSVC ${LANG_ENGLISH} \
|
||||||
"Visual C++ 2015 runtime components. If already installed, will be skipped."
|
"Microsoft Visual C++ 2017 runtime. If already installed, will be skipped."
|
||||||
LangString DESC_OPENSSL ${LANG_ENGLISH} \
|
LangString DESC_OPENSSL ${LANG_ENGLISH} \
|
||||||
"OpenSSL library. Required for HTTPS to work."
|
"OpenSSL library. Required for HTTPS to work."
|
||||||
LangString DESC_ANGLE ${LANG_ENGLISH} \
|
LangString DESC_ANGLE ${LANG_ENGLISH} \
|
||||||
|
@ -91,4 +91,18 @@
|
|||||||
<generic-icon name="text-plain"/>
|
<generic-icon name="text-plain"/>
|
||||||
<glob pattern="*.cup"/>
|
<glob pattern="*.cup"/>
|
||||||
</mime-type>
|
</mime-type>
|
||||||
|
|
||||||
|
<mime-type type="application/vnd.garmin.gpi">
|
||||||
|
<comment>Garmin POI File</comment>
|
||||||
|
<sub-class-of type="application/octet-stream"/>
|
||||||
|
<generic-icon name="application/octet-stream"/>
|
||||||
|
<glob pattern="*.gpi"/>
|
||||||
|
</mime-type>
|
||||||
|
|
||||||
|
<mime-type type="application/sml+xml">
|
||||||
|
<comment>Suunto Markup Language</comment>
|
||||||
|
<sub-class-of type="application/xml"/>
|
||||||
|
<generic-icon name="application-xml"/>
|
||||||
|
<glob pattern="*.sml"/>
|
||||||
|
</mime-type>
|
||||||
</mime-info>
|
</mime-info>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
; The name of the installer
|
; The name of the installer
|
||||||
Name "GPXSee"
|
Name "GPXSee"
|
||||||
; Program version
|
; Program version
|
||||||
!define VERSION "7.17"
|
!define VERSION "7.26"
|
||||||
|
|
||||||
; The file to write
|
; The file to write
|
||||||
OutFile "GPXSee-${VERSION}_x64.exe"
|
OutFile "GPXSee-${VERSION}_x64.exe"
|
||||||
@ -113,20 +113,21 @@ Section "GPXSee" SEC_APP
|
|||||||
|
|
||||||
; Associate file formats
|
; Associate file formats
|
||||||
DetailPrint "Associating file types..."
|
DetailPrint "Associating file types..."
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "gpx" "GPS Exchange Format" 7
|
!insertmacro FILE_ASSOCIATION_ADD "gpx" "GPS Exchange Format" 8
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "tcx" "Training Center XML" 8
|
!insertmacro FILE_ASSOCIATION_ADD "tcx" "Training Center XML" 9
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "kml" "Keyhole Markup Language" 9
|
!insertmacro FILE_ASSOCIATION_ADD "kml" "Keyhole Markup Language" 10
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "fit" "Flexible and Interoperable Data Transfer" 10
|
!insertmacro FILE_ASSOCIATION_ADD "fit" "Flexible and Interoperable Data Transfer" 11
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "igc" "Flight Recorder Data Format" 11
|
!insertmacro FILE_ASSOCIATION_ADD "igc" "Flight Recorder Data Format" 12
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "nmea" "NMEA 0183 Data" 12
|
!insertmacro FILE_ASSOCIATION_ADD "nmea" "NMEA 0183 Data" 13
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "plt" "OziExplorer Track Point File" 13
|
!insertmacro FILE_ASSOCIATION_ADD "plt" "OziExplorer Track Point File" 14
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "rte" "OziExplorer Route File" 14
|
!insertmacro FILE_ASSOCIATION_ADD "rte" "OziExplorer Route File" 15
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "wpt" "OziExplorer Waypoint File" 1
|
!insertmacro FILE_ASSOCIATION_ADD "wpt" "OziExplorer Waypoint File" 1
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "loc" "Geocaching.com Waypoint File" 2
|
!insertmacro FILE_ASSOCIATION_ADD "loc" "Geocaching.com Waypoint File" 2
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "slf" "Sigma Log File" 3
|
!insertmacro FILE_ASSOCIATION_ADD "slf" "Sigma Log File" 3
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "geojson" "GeoJSON" 4
|
!insertmacro FILE_ASSOCIATION_ADD "geojson" "GeoJSON" 4
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "cup" "SeeYou CUP File" 5
|
!insertmacro FILE_ASSOCIATION_ADD "cup" "SeeYou CUP File" 5
|
||||||
!insertmacro FILE_ASSOCIATION_ADD "gpi" "Garmin POI File" 6
|
!insertmacro FILE_ASSOCIATION_ADD "gpi" "Garmin POI File" 6
|
||||||
|
!insertmacro FILE_ASSOCIATION_ADD "sml" "Suunto Markup Language" 7
|
||||||
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
|
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
|
||||||
|
|
||||||
SectionEnd
|
SectionEnd
|
||||||
@ -154,25 +155,17 @@ Section "MSVC runtime" SEC_MSVC
|
|||||||
|
|
||||||
SectionIn RO
|
SectionIn RO
|
||||||
|
|
||||||
DetailPrint "Checking whether Visual C++ 2015 Redistributable is already installed..."
|
|
||||||
ReadRegDword $R0 HKLM "SOFTWARE\Wow6432Node\Microsoft\VisualStudio\14.0\VC\Runtimes\x64" "Installed"
|
|
||||||
StrCmp $R0 "1" 0 +3
|
|
||||||
DetailPrint "Visual C++ 2015 Redistributable is already installed, skipping install."
|
|
||||||
Goto done
|
|
||||||
|
|
||||||
DetailPrint "Installing Visual C++ 2015 Redistributable..."
|
|
||||||
SetOutPath $TEMP
|
SetOutPath $TEMP
|
||||||
File "vcredist_x64.exe"
|
File "vc_redist.x64.exe"
|
||||||
ExecWait '"$TEMP\vcredist_x64.exe" /install /quiet /norestart'
|
ExecWait '"$TEMP\vc_redist.x64.exe" /install /quiet /norestart'
|
||||||
SetOutPath $INSTDIR
|
SetOutPath $INSTDIR
|
||||||
|
|
||||||
done:
|
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
Section "OpenSSL" SEC_OPENSSL
|
Section "OpenSSL" SEC_OPENSSL
|
||||||
|
|
||||||
File "libeay32.dll"
|
File "libcrypto-1_1-x64.dll"
|
||||||
File "ssleay32.dll"
|
File "libssl-1_1-x64.dll"
|
||||||
|
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
@ -190,6 +183,7 @@ SectionGroup "Localization" SEC_LOCALIZATION
|
|||||||
!insertmacro LOCALIZATION "Finnish" "fi"
|
!insertmacro LOCALIZATION "Finnish" "fi"
|
||||||
!insertmacro LOCALIZATION "French" "fr"
|
!insertmacro LOCALIZATION "French" "fr"
|
||||||
!insertmacro LOCALIZATION "German" "de"
|
!insertmacro LOCALIZATION "German" "de"
|
||||||
|
!insertmacro LOCALIZATION "Hungarian" "hu"
|
||||||
!insertmacro LOCALIZATION "Norwegian" "nb"
|
!insertmacro LOCALIZATION "Norwegian" "nb"
|
||||||
!insertmacro LOCALIZATION "Polish" "pl"
|
!insertmacro LOCALIZATION "Polish" "pl"
|
||||||
!insertmacro LOCALIZATION "Portuguese (Brazil)" "pt_BR"
|
!insertmacro LOCALIZATION "Portuguese (Brazil)" "pt_BR"
|
||||||
@ -197,6 +191,7 @@ SectionGroup "Localization" SEC_LOCALIZATION
|
|||||||
!insertmacro LOCALIZATION "Spanish" "es"
|
!insertmacro LOCALIZATION "Spanish" "es"
|
||||||
!insertmacro LOCALIZATION "Swedish" "sv"
|
!insertmacro LOCALIZATION "Swedish" "sv"
|
||||||
!insertmacro LOCALIZATION "Turkish" "tr"
|
!insertmacro LOCALIZATION "Turkish" "tr"
|
||||||
|
!insertmacro LOCALIZATION "Ukrainian" "uk"
|
||||||
SectionGroupEnd
|
SectionGroupEnd
|
||||||
|
|
||||||
;--------------------------------
|
;--------------------------------
|
||||||
@ -234,6 +229,7 @@ Section "Uninstall"
|
|||||||
!insertmacro FILE_ASSOCIATION_REMOVE "geojson"
|
!insertmacro FILE_ASSOCIATION_REMOVE "geojson"
|
||||||
!insertmacro FILE_ASSOCIATION_REMOVE "cup"
|
!insertmacro FILE_ASSOCIATION_REMOVE "cup"
|
||||||
!insertmacro FILE_ASSOCIATION_REMOVE "gpi"
|
!insertmacro FILE_ASSOCIATION_REMOVE "gpi"
|
||||||
|
!insertmacro FILE_ASSOCIATION_REMOVE "sml"
|
||||||
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
|
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
|
||||||
|
|
||||||
SectionEnd
|
SectionEnd
|
||||||
@ -246,7 +242,7 @@ SectionEnd
|
|||||||
LangString DESC_QT ${LANG_ENGLISH} \
|
LangString DESC_QT ${LANG_ENGLISH} \
|
||||||
"QT cross-platform application framework."
|
"QT cross-platform application framework."
|
||||||
LangString DESC_MSVC ${LANG_ENGLISH} \
|
LangString DESC_MSVC ${LANG_ENGLISH} \
|
||||||
"Visual C++ 2015 runtime components. If already installed, will be skipped."
|
"Microsoft Visual C++ 2017 runtime. If already installed, will be skipped."
|
||||||
LangString DESC_OPENSSL ${LANG_ENGLISH} \
|
LangString DESC_OPENSSL ${LANG_ENGLISH} \
|
||||||
"OpenSSL library. Required for HTTPS to work."
|
"OpenSSL library. Required for HTTPS to work."
|
||||||
LangString DESC_ANGLE ${LANG_ENGLISH} \
|
LangString DESC_ANGLE ${LANG_ENGLISH} \
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<map xmlns="http://www.gpxsee.org/map/1.3">
|
<map xmlns="http://www.gpxsee.org/map/1.4">
|
||||||
<name>4UMaps</name>
|
<name>4UMaps</name>
|
||||||
<url>https://4umaps.com/$z/$x/$y.png</url>
|
<url>https://tileserver.4umaps.com/$z/$x/$y.png</url>
|
||||||
<zoom min="2" max="15"/>
|
<zoom min="2" max="15"/>
|
||||||
<bounds bottom="-65"/>
|
<bounds bottom="-65"/>
|
||||||
<copyright>Map data: © OpenStreetMap contributors (ODbL) | Rendering: © 4UMaps.eu</copyright>
|
<copyright>Map data: © OpenStreetMap contributors (ODbL) | Rendering: © 4UMaps.eu</copyright>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<map xmlns="http://www.gpxsee.org/map/1.3" type="WMTS">
|
<map xmlns="http://www.gpxsee.org/map/1.4" type="WMTS">
|
||||||
<name>Antarctica</name>
|
<name>Antarctica</name>
|
||||||
<url type="REST">https://gis.ngdc.noaa.gov/arcgis/rest/services/antarctic/antarctic_basemap/MapServer/WMTS/1.0.0/WMTSCapabilities.xml</url>
|
<url type="REST">https://gis.ngdc.noaa.gov/arcgis/rest/services/antarctic/antarctic_basemap/MapServer/WMTS/1.0.0/WMTSCapabilities.xml</url>
|
||||||
<copyright>NOAA National Centers for Environmental Information (NCEI); International Bathymetric Chart of the Southern Ocean (IBCSO); General Bathymetric Chart of the Oceans (GEBCO); Natural Earth</copyright>
|
<copyright>NOAA National Centers for Environmental Information (NCEI); International Bathymetric Chart of the Southern Ocean (IBCSO); General Bathymetric Chart of the Oceans (GEBCO); Natural Earth</copyright>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<map xmlns="http://www.gpxsee.org/map/1.3">
|
<map xmlns="http://www.gpxsee.org/map/1.4">
|
||||||
<name>Open Street Map</name>
|
<name>Open Street Map</name>
|
||||||
<url>http://tile.openstreetmap.org/$z/$x/$y.png</url>
|
<url>https://tile.openstreetmap.org/$z/$x/$y.png</url>
|
||||||
<copyright>Map data: © OpenStreetMap contributors (ODbL) | Rendering: © OpenStreetMap (CC-BY-SA)</copyright>
|
<copyright>Map data: © OpenStreetMap contributors (ODbL) | Rendering: © OpenStreetMap (CC-BY-SA)</copyright>
|
||||||
</map>
|
</map>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<map xmlns="http://www.gpxsee.org/map/1.3">
|
<map xmlns="http://www.gpxsee.org/map/1.4">
|
||||||
<name>Open Topo Map</name>
|
<name>Open Topo Map</name>
|
||||||
<url>https://a.tile.opentopomap.org/$z/$x/$y.png</url>
|
<url>https://a.tile.opentopomap.org/$z/$x/$y.png</url>
|
||||||
<zoom max="17"/>
|
<zoom max="17"/>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<map xmlns="http://www.gpxsee.org/map/1.3">
|
<map xmlns="http://www.gpxsee.org/map/1.4">
|
||||||
<name>USGS Imagery</name>
|
<name>USGS Imagery</name>
|
||||||
<url>https://basemap.nationalmap.gov/ArcGIS/rest/services/USGSImageryOnly/MapServer/tile/$z/$y/$x</url>
|
<url>https://basemap.nationalmap.gov/ArcGIS/rest/services/USGSImageryOnly/MapServer/tile/$z/$y/$x</url>
|
||||||
<zoom min="2" max="15"/>
|
<zoom min="2" max="15"/>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<map xmlns="http://www.gpxsee.org/map/1.3">
|
<map xmlns="http://www.gpxsee.org/map/1.4">
|
||||||
<name>USGS Topo</name>
|
<name>USGS Topo</name>
|
||||||
<url>https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/tile/$z/$y/$x</url>
|
<url>https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/tile/$z/$y/$x</url>
|
||||||
<zoom min="2" max="15"/>
|
<zoom min="2" max="15"/>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#include "areaitem.h"
|
#include "areaitem.h"
|
||||||
|
|
||||||
|
|
||||||
ToolTip AreaItem::toolTip() const
|
QString AreaItem::info() const
|
||||||
{
|
{
|
||||||
ToolTip tt;
|
ToolTip tt;
|
||||||
|
|
||||||
@ -18,11 +18,11 @@ ToolTip AreaItem::toolTip() const
|
|||||||
tt.insert(qApp->translate("PolygonItem", "Description"),
|
tt.insert(qApp->translate("PolygonItem", "Description"),
|
||||||
_area.description());
|
_area.description());
|
||||||
|
|
||||||
return tt;
|
return tt.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
AreaItem::AreaItem(const Area &area, Map *map, QGraphicsItem *parent)
|
AreaItem::AreaItem(const Area &area, Map *map, GraphicsItem *parent)
|
||||||
: QGraphicsItem(parent), _area(area)
|
: GraphicsItem(parent), _area(area)
|
||||||
{
|
{
|
||||||
_map = map;
|
_map = map;
|
||||||
_digitalZoom = 0;
|
_digitalZoom = 0;
|
||||||
@ -173,6 +173,6 @@ void AreaItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
|
|||||||
|
|
||||||
void AreaItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
void AreaItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||||
{
|
{
|
||||||
Popup::show(event->screenPos(), toolTip().toString(), event->widget());
|
Popup::show(event->screenPos(), info(), event->widget());
|
||||||
QGraphicsItem::mousePressEvent(event);
|
QGraphicsItem::mousePressEvent(event);
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
#ifndef AREAITEM_H
|
#ifndef AREAITEM_H
|
||||||
#define AREAITEM_H
|
#define AREAITEM_H
|
||||||
|
|
||||||
#include <QGraphicsItem>
|
|
||||||
#include "data/area.h"
|
#include "data/area.h"
|
||||||
|
#include "graphicsscene.h"
|
||||||
#include "tooltip.h"
|
#include "tooltip.h"
|
||||||
|
|
||||||
class Map;
|
class Map;
|
||||||
|
|
||||||
class AreaItem : public QGraphicsItem
|
class AreaItem : public GraphicsItem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AreaItem(const Area &area, Map *map, QGraphicsItem *parent = 0);
|
AreaItem(const Area &area, Map *map, GraphicsItem *parent = 0);
|
||||||
|
|
||||||
QPainterPath shape() const {return _painterPath;}
|
QPainterPath shape() const {return _painterPath;}
|
||||||
QRectF boundingRect() const {return _painterPath.boundingRect();}
|
QRectF boundingRect() const {return _painterPath.boundingRect();}
|
||||||
@ -27,6 +27,8 @@ public:
|
|||||||
void setStyle(Qt::PenStyle style);
|
void setStyle(Qt::PenStyle style);
|
||||||
void setDigitalZoom(int zoom);
|
void setDigitalZoom(int zoom);
|
||||||
|
|
||||||
|
virtual QString info() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
|
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
|
||||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
|
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
CadenceGraphItem::CadenceGraphItem(const Graph &graph, GraphType type,
|
CadenceGraphItem::CadenceGraphItem(const Graph &graph, GraphType type,
|
||||||
int width, const QColor &color, QGraphicsItem *parent)
|
int width, const QColor &color, QGraphicsItem *parent)
|
||||||
: GraphItem(graph, type, width, color, parent)
|
: GraphItem(graph, type, width, color, Qt::SolidLine, parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,35 +65,38 @@ void ElevationGraph::setInfo()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GraphItem *ElevationGraph::loadGraph(const Graph &graph, Type type)
|
GraphItem *ElevationGraph::loadGraph(const Graph &graph, PathType type,
|
||||||
|
const QColor &color, bool primary)
|
||||||
{
|
{
|
||||||
if (!graph.isValid()) {
|
if (!graph.isValid())
|
||||||
_palette.nextColor();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
ElevationGraphItem *gi = new ElevationGraphItem(graph, _graphType, _width,
|
ElevationGraphItem *gi = new ElevationGraphItem(graph, _graphType, _width,
|
||||||
_palette.nextColor());
|
color, primary ? Qt::SolidLine : Qt::DashLine);
|
||||||
gi->setUnits(_units);
|
gi->setUnits(_units);
|
||||||
|
|
||||||
if (type == Track) {
|
if (type == TrackPath) {
|
||||||
_tracks.append(gi);
|
_tracks.append(gi);
|
||||||
if (_showTracks)
|
if (_showTracks)
|
||||||
addGraph(gi);
|
addGraph(gi);
|
||||||
|
|
||||||
_trackAscent += gi->ascent();
|
if (primary) {
|
||||||
_trackDescent += gi->descent();
|
_trackAscent += gi->ascent();
|
||||||
_trackMax = nMax(_trackMax, gi->max());
|
_trackDescent += gi->descent();
|
||||||
_trackMin = nMin(_trackMin, gi->min());
|
_trackMax = nMax(_trackMax, gi->max());
|
||||||
|
_trackMin = nMin(_trackMin, gi->min());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
_routes.append(gi);
|
_routes.append(gi);
|
||||||
if (_showRoutes)
|
if (_showRoutes)
|
||||||
addGraph(gi);
|
addGraph(gi);
|
||||||
|
|
||||||
_routeAscent += gi->ascent();
|
if (primary) {
|
||||||
_routeDescent += gi->descent();
|
_routeAscent += gi->ascent();
|
||||||
_routeMax = nMax(_routeMax, gi->max());
|
_routeDescent += gi->descent();
|
||||||
_routeMin = nMin(_routeMin, gi->min());
|
_routeMax = nMax(_routeMax, gi->max());
|
||||||
|
_routeMin = nMin(_routeMin, gi->min());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return gi;
|
return gi;
|
||||||
@ -102,11 +105,32 @@ GraphItem *ElevationGraph::loadGraph(const Graph &graph, Type type)
|
|||||||
QList<GraphItem*> ElevationGraph::loadData(const Data &data)
|
QList<GraphItem*> ElevationGraph::loadData(const Data &data)
|
||||||
{
|
{
|
||||||
QList<GraphItem*> graphs;
|
QList<GraphItem*> graphs;
|
||||||
|
GraphItem *primary, *secondary;
|
||||||
|
|
||||||
for (int i = 0; i < data.tracks().count(); i++)
|
for (int i = 0; i < data.tracks().count(); i++) {
|
||||||
graphs.append(loadGraph(data.tracks().at(i).elevation(), Track));
|
QColor color(_palette.nextColor());
|
||||||
for (int i = 0; i < data.routes().count(); i++)
|
const GraphPair &gp = data.tracks().at(i).elevation();
|
||||||
graphs.append(loadGraph(data.routes().at(i).elevation(), Route));
|
|
||||||
|
primary = loadGraph(gp.primary(), TrackPath, color, true);
|
||||||
|
secondary = primary
|
||||||
|
? loadGraph(gp.secondary(), TrackPath, color, false) : 0;
|
||||||
|
if (primary && secondary)
|
||||||
|
primary->setSecondaryGraph(secondary);
|
||||||
|
|
||||||
|
graphs.append(primary);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < data.routes().count(); i++) {
|
||||||
|
QColor color(_palette.nextColor());
|
||||||
|
const GraphPair &gp = data.routes().at(i).elevation();
|
||||||
|
|
||||||
|
primary = loadGraph(gp.primary(), RoutePath, color, true);
|
||||||
|
secondary = primary
|
||||||
|
? loadGraph(gp.secondary(), RoutePath, color, false) : 0;
|
||||||
|
if (primary && secondary)
|
||||||
|
primary->setSecondaryGraph(secondary);
|
||||||
|
|
||||||
|
graphs.append(primary);
|
||||||
|
}
|
||||||
for (int i = 0; i < data.areas().count(); i++)
|
for (int i = 0; i < data.areas().count(); i++)
|
||||||
_palette.nextColor();
|
_palette.nextColor();
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ public:
|
|||||||
void showRoutes(bool show);
|
void showRoutes(bool show);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum Type {Track, Route};
|
enum PathType {TrackPath, RoutePath};
|
||||||
|
|
||||||
qreal max() const;
|
qreal max() const;
|
||||||
qreal min() const;
|
qreal min() const;
|
||||||
@ -31,7 +31,8 @@ private:
|
|||||||
void setYUnits(Units units);
|
void setYUnits(Units units);
|
||||||
void setInfo();
|
void setInfo();
|
||||||
|
|
||||||
GraphItem *loadGraph(const Graph &graph, Type type);
|
GraphItem *loadGraph(const Graph &graph, PathType type, const QColor &color,
|
||||||
|
bool primary);
|
||||||
void showItems(const QList<ElevationGraphItem *> &list, bool show);
|
void showItems(const QList<ElevationGraphItem *> &list, bool show);
|
||||||
|
|
||||||
qreal _trackAscent, _trackDescent;
|
qreal _trackAscent, _trackDescent;
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
|
|
||||||
ElevationGraphItem::ElevationGraphItem(const Graph &graph, GraphType type,
|
ElevationGraphItem::ElevationGraphItem(const Graph &graph, GraphType type,
|
||||||
int width, const QColor &color, QGraphicsItem *parent)
|
int width, const QColor &color, Qt::PenStyle style, QGraphicsItem *parent)
|
||||||
: GraphItem(graph, type, width, color, parent)
|
: GraphItem(graph, type, width, color, style, parent)
|
||||||
{
|
{
|
||||||
_min = GraphItem::min();
|
_min = GraphItem::min();
|
||||||
_max = GraphItem::max();
|
_max = GraphItem::max();
|
||||||
@ -42,5 +42,6 @@ QString ElevationGraphItem::info() const
|
|||||||
tt.insert(tr("Minimum"), l.toString(min() * scale, 'f', 0)
|
tt.insert(tr("Minimum"), l.toString(min() * scale, 'f', 0)
|
||||||
+ UNIT_SPACE + su);
|
+ UNIT_SPACE + su);
|
||||||
|
|
||||||
|
|
||||||
return tt.toString();
|
return tt.toString();
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,10 @@ class ElevationGraphItem : public GraphItem
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum DataType {GPS, DEM};
|
||||||
|
|
||||||
ElevationGraphItem(const Graph &graph, GraphType type, int width,
|
ElevationGraphItem(const Graph &graph, GraphType type, int width,
|
||||||
const QColor &color, QGraphicsItem *parent = 0);
|
const QColor &color, Qt::PenStyle style, QGraphicsItem *parent = 0);
|
||||||
|
|
||||||
qreal ascent() const {return _ascent;}
|
qreal ascent() const {return _ascent;}
|
||||||
qreal descent() const {return _descent;}
|
qreal descent() const {return _descent;}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
GearRatioGraphItem::GearRatioGraphItem(const Graph &graph, GraphType type,
|
GearRatioGraphItem::GearRatioGraphItem(const Graph &graph, GraphType type,
|
||||||
int width, const QColor &color, QGraphicsItem *parent)
|
int width, const QColor &color, QGraphicsItem *parent)
|
||||||
: GraphItem(graph, type, width, color, parent)
|
: GraphItem(graph, type, width, color, Qt::SolidLine, parent)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < graph.size(); i++) {
|
for (int i = 0; i < graph.size(); i++) {
|
||||||
const GraphSegment &segment = graph.at(i);
|
const GraphSegment &segment = graph.at(i);
|
||||||
|
@ -46,3 +46,9 @@ void GraphicsScene::helpEvent(QGraphicsSceneHelpEvent *event)
|
|||||||
|
|
||||||
/* No need to process QGraphicsScene::helpEvent() */
|
/* No need to process QGraphicsScene::helpEvent() */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GraphicsScene::clear()
|
||||||
|
{
|
||||||
|
Popup::clear();
|
||||||
|
QGraphicsScene::clear();
|
||||||
|
}
|
||||||
|
@ -18,6 +18,9 @@ class GraphicsScene : public QGraphicsScene
|
|||||||
public:
|
public:
|
||||||
GraphicsScene(QObject *parent = 0) : QGraphicsScene(parent) {}
|
GraphicsScene(QObject *parent = 0) : QGraphicsScene(parent) {}
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void clear();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void helpEvent(QGraphicsSceneHelpEvent *event);
|
void helpEvent(QGraphicsSceneHelpEvent *event);
|
||||||
|
|
||||||
|
@ -5,13 +5,13 @@
|
|||||||
|
|
||||||
|
|
||||||
GraphItem::GraphItem(const Graph &graph, GraphType type, int width,
|
GraphItem::GraphItem(const Graph &graph, GraphType type, int width,
|
||||||
const QColor &color, QGraphicsItem *parent)
|
const QColor &color, Qt::PenStyle style, QGraphicsItem *parent)
|
||||||
: GraphicsItem(parent), _graph(graph), _type(type)
|
: GraphicsItem(parent), _graph(graph), _type(type), _secondaryGraph(0)
|
||||||
{
|
{
|
||||||
Q_ASSERT(_graph.isValid());
|
Q_ASSERT(_graph.isValid());
|
||||||
|
|
||||||
_units = Metric;
|
_units = Metric;
|
||||||
_pen = QPen(color, width);
|
_pen = QPen(color, width, style);
|
||||||
_sx = 0; _sy = 0;
|
_sx = 0; _sy = 0;
|
||||||
_time = _graph.hasTime();
|
_time = _graph.hasTime();
|
||||||
setZValue(2.0);
|
setZValue(2.0);
|
||||||
|
@ -12,8 +12,8 @@ class GraphItem : public QObject, public GraphicsItem
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GraphItem(const Graph &graph, GraphType type, int width, const QColor &color,
|
GraphItem(const Graph &graph, GraphType type, int width,
|
||||||
QGraphicsItem *parent = 0);
|
const QColor &color, Qt::PenStyle style, QGraphicsItem *parent = 0);
|
||||||
virtual ~GraphItem() {}
|
virtual ~GraphItem() {}
|
||||||
|
|
||||||
virtual QString info() const = 0;
|
virtual QString info() const = 0;
|
||||||
@ -35,6 +35,9 @@ public:
|
|||||||
void setWidth(int width);
|
void setWidth(int width);
|
||||||
void setUnits(Units units) {_units = units;}
|
void setUnits(Units units) {_units = units;}
|
||||||
|
|
||||||
|
GraphItem *secondaryGraph() const {return _secondaryGraph;}
|
||||||
|
void setSecondaryGraph(GraphItem *graph) {_secondaryGraph = graph;}
|
||||||
|
|
||||||
qreal yAtX(qreal x);
|
qreal yAtX(qreal x);
|
||||||
qreal distanceAtTime(qreal time);
|
qreal distanceAtTime(qreal time);
|
||||||
|
|
||||||
@ -69,6 +72,8 @@ private:
|
|||||||
qreal _sx, _sy;
|
qreal _sx, _sy;
|
||||||
QPen _pen;
|
QPen _pen;
|
||||||
bool _time;
|
bool _time;
|
||||||
|
|
||||||
|
GraphItem *_secondaryGraph;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // GRAPHITEM_H
|
#endif // GRAPHITEM_H
|
||||||
|
@ -274,8 +274,8 @@ void GraphView::redraw(const QSizeF &size)
|
|||||||
rx = RangeF(bounds().left() * _xScale, bounds().right() * _xScale);
|
rx = RangeF(bounds().left() * _xScale, bounds().right() * _xScale);
|
||||||
ry = RangeF(bounds().top() * _yScale + _yOffset, bounds().bottom() * _yScale
|
ry = RangeF(bounds().top() * _yScale + _yOffset, bounds().bottom() * _yScale
|
||||||
+ _yOffset);
|
+ _yOffset);
|
||||||
if (ry.size() < _minYRange)
|
if (ry.size() < _minYRange * _yScale)
|
||||||
ry.resize(_minYRange);
|
ry.resize(_minYRange * _yScale);
|
||||||
|
|
||||||
_xAxis->setRange(rx);
|
_xAxis->setRange(rx);
|
||||||
_yAxis->setRange(ry);
|
_yAxis->setRange(ry);
|
||||||
@ -419,14 +419,16 @@ void GraphView::updateSliderInfo()
|
|||||||
{
|
{
|
||||||
QLocale l(QLocale::system());
|
QLocale l(QLocale::system());
|
||||||
qreal r = 0, y = 0;
|
qreal r = 0, y = 0;
|
||||||
|
GraphItem *cardinal = (_graphs.count() == 1 || (_graphs.count() == 2
|
||||||
|
&& _graphs.first()->secondaryGraph())) ? _graphs.first() : 0;
|
||||||
|
|
||||||
if (_graphs.count() == 1) {
|
if (cardinal) {
|
||||||
QRectF br(_graphs.first()->bounds());
|
QRectF br(_bounds);
|
||||||
if (br.height() < _minYRange)
|
if (br.height() < _minYRange)
|
||||||
br.adjust(0, -(_minYRange/2 - br.height()/2), 0,
|
br.adjust(0, -(_minYRange/2 - br.height()/2), 0,
|
||||||
_minYRange/2 - br.height()/2);
|
_minYRange/2 - br.height()/2);
|
||||||
|
|
||||||
y = _graphs.first()->yAtX(_sliderPos);
|
y = cardinal->yAtX(_sliderPos);
|
||||||
r = (y - br.bottom()) / br.height();
|
r = (y - br.bottom()) / br.height();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -436,11 +438,17 @@ void GraphView::updateSliderInfo()
|
|||||||
|
|
||||||
_sliderInfo->setSide(s);
|
_sliderInfo->setSide(s);
|
||||||
_sliderInfo->setPos(QPointF(0, _slider->boundingRect().height() * r));
|
_sliderInfo->setPos(QPointF(0, _slider->boundingRect().height() * r));
|
||||||
_sliderInfo->setText(_graphType == Time ? Format::timeSpan(_sliderPos,
|
QString xText(_graphType == Time ? Format::timeSpan(_sliderPos,
|
||||||
bounds().width() > 3600) : l.toString(_sliderPos * _xScale, 'f', 1)
|
bounds().width() > 3600) : l.toString(_sliderPos * _xScale, 'f', 1)
|
||||||
+ UNIT_SPACE + _xUnits, (_graphs.count() > 1) ? QString()
|
+ UNIT_SPACE + _xUnits);
|
||||||
: l.toString(-y * _yScale + _yOffset, 'f', _precision) + UNIT_SPACE
|
QString yText((!cardinal) ? QString() : l.toString(-y * _yScale + _yOffset,
|
||||||
+ _yUnits);
|
'f', _precision) + UNIT_SPACE + _yUnits);
|
||||||
|
if (cardinal && cardinal->secondaryGraph()) {
|
||||||
|
qreal delta = y - cardinal->secondaryGraph()->yAtX(_sliderPos);
|
||||||
|
yText += " " + QChar(0x0394) + l.toString(-delta * _yScale + _yOffset,
|
||||||
|
'f', _precision) + UNIT_SPACE + _yUnits;
|
||||||
|
}
|
||||||
|
_sliderInfo->setText(xText, yText);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphView::emitSliderPositionChanged(const QPointF &pos)
|
void GraphView::emitSliderPositionChanged(const QPointF &pos)
|
||||||
|
243
src/GUI/gui.cpp
243
src/GUI/gui.cpp
@ -51,6 +51,7 @@
|
|||||||
#include "graphtab.h"
|
#include "graphtab.h"
|
||||||
#include "graphitem.h"
|
#include "graphitem.h"
|
||||||
#include "pathitem.h"
|
#include "pathitem.h"
|
||||||
|
#include "mapaction.h"
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
|
|
||||||
|
|
||||||
@ -58,7 +59,6 @@
|
|||||||
|
|
||||||
GUI::GUI()
|
GUI::GUI()
|
||||||
{
|
{
|
||||||
loadMaps();
|
|
||||||
loadPOIs();
|
loadPOIs();
|
||||||
|
|
||||||
createMapView();
|
createMapView();
|
||||||
@ -106,24 +106,13 @@ GUI::GUI()
|
|||||||
updateStatusBarInfo();
|
updateStatusBarInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUI::loadMaps()
|
|
||||||
{
|
|
||||||
_ml = new MapList(this);
|
|
||||||
QString mapDir(ProgramPaths::mapDir());
|
|
||||||
|
|
||||||
if (!mapDir.isNull() && !_ml->loadDir(mapDir))
|
|
||||||
qWarning("%s", qPrintable(_ml->errorString()));
|
|
||||||
|
|
||||||
_map = new EmptyMap(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GUI::loadPOIs()
|
void GUI::loadPOIs()
|
||||||
{
|
{
|
||||||
_poi = new POI(this);
|
_poi = new POI(this);
|
||||||
QString poiDir(ProgramPaths::poiDir());
|
|
||||||
|
|
||||||
if (!poiDir.isNull() && !_poi->loadDir(poiDir))
|
QString poiDir(ProgramPaths::poiDir());
|
||||||
qWarning("%s", qPrintable(_poi->errorString()));
|
if (!poiDir.isNull())
|
||||||
|
_poi->loadDir(poiDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUI::createBrowser()
|
void GUI::createBrowser()
|
||||||
@ -134,40 +123,56 @@ void GUI::createBrowser()
|
|||||||
|
|
||||||
void GUI::createMapActions()
|
void GUI::createMapActions()
|
||||||
{
|
{
|
||||||
_mapsSignalMapper = new QSignalMapper(this);
|
|
||||||
_mapsActionGroup = new QActionGroup(this);
|
_mapsActionGroup = new QActionGroup(this);
|
||||||
_mapsActionGroup->setExclusive(true);
|
_mapsActionGroup->setExclusive(true);
|
||||||
|
|
||||||
for (int i = 0; i < _ml->maps().count(); i++)
|
QString mapDir(ProgramPaths::mapDir());
|
||||||
createMapAction(_ml->maps().at(i));
|
if (mapDir.isNull())
|
||||||
|
return;
|
||||||
|
|
||||||
connect(_mapsSignalMapper, SIGNAL(mapped(int)), this,
|
QString unused;
|
||||||
SLOT(mapChanged(int)));
|
QList<Map*> maps(MapList::loadMaps(mapDir, unused));
|
||||||
|
for (int i = 0; i < maps.count(); i++) {
|
||||||
|
MapAction *a = createMapAction(maps.at(i));
|
||||||
|
connect(a, SIGNAL(loaded()), this, SLOT(mapInitialized()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QAction *GUI::createMapAction(const Map *map)
|
MapAction *GUI::createMapAction(Map *map)
|
||||||
{
|
{
|
||||||
QAction *a = new QAction(map->name(), this);
|
MapAction *a = new MapAction(map);
|
||||||
a->setMenuRole(QAction::NoRole);
|
a->setMenuRole(QAction::NoRole);
|
||||||
a->setCheckable(true);
|
a->setCheckable(true);
|
||||||
a->setActionGroup(_mapsActionGroup);
|
a->setActionGroup(_mapsActionGroup);
|
||||||
|
connect(a, SIGNAL(triggered()), this, SLOT(mapChanged()));
|
||||||
_mapActions.append(a);
|
|
||||||
_mapsSignalMapper->setMapping(a, _mapActions.size() - 1);
|
|
||||||
connect(a, SIGNAL(triggered()), _mapsSignalMapper, SLOT(map()));
|
|
||||||
|
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GUI::mapInitialized()
|
||||||
|
{
|
||||||
|
MapAction *action = static_cast<MapAction*>(QObject::sender());
|
||||||
|
Map *map = action->data().value<Map*>();
|
||||||
|
|
||||||
|
if (map->isValid()) {
|
||||||
|
if (!_mapsActionGroup->checkedAction())
|
||||||
|
action->trigger();
|
||||||
|
_showMapAction->setEnabled(true);
|
||||||
|
_clearMapCacheAction->setEnabled(true);
|
||||||
|
} else {
|
||||||
|
qWarning("%s: %s", qPrintable(map->name()), qPrintable(map->errorString()));
|
||||||
|
action->deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GUI::createPOIFilesActions()
|
void GUI::createPOIFilesActions()
|
||||||
{
|
{
|
||||||
_poiFilesSignalMapper = new QSignalMapper(this);
|
_poiFilesSignalMapper = new QSignalMapper(this);
|
||||||
|
connect(_poiFilesSignalMapper, SIGNAL(mapped(int)), this,
|
||||||
|
SLOT(poiFileChecked(int)));
|
||||||
|
|
||||||
for (int i = 0; i < _poi->files().count(); i++)
|
for (int i = 0; i < _poi->files().count(); i++)
|
||||||
createPOIFileAction(_poi->files().at(i));
|
createPOIFileAction(_poi->files().at(i));
|
||||||
|
|
||||||
connect(_poiFilesSignalMapper, SIGNAL(mapped(int)), this,
|
|
||||||
SLOT(poiFileChecked(int)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QAction *GUI::createPOIFileAction(const QString &fileName)
|
QAction *GUI::createPOIFileAction(const QString &fileName)
|
||||||
@ -281,8 +286,10 @@ void GUI::createActions()
|
|||||||
createPOIFilesActions();
|
createPOIFilesActions();
|
||||||
|
|
||||||
// Map actions
|
// Map actions
|
||||||
|
createMapActions();
|
||||||
_showMapAction = new QAction(QIcon(SHOW_MAP_ICON), tr("Show map"),
|
_showMapAction = new QAction(QIcon(SHOW_MAP_ICON), tr("Show map"),
|
||||||
this);
|
this);
|
||||||
|
_showMapAction->setEnabled(false);
|
||||||
_showMapAction->setMenuRole(QAction::NoRole);
|
_showMapAction->setMenuRole(QAction::NoRole);
|
||||||
_showMapAction->setCheckable(true);
|
_showMapAction->setCheckable(true);
|
||||||
_showMapAction->setShortcut(SHOW_MAP_SHORTCUT);
|
_showMapAction->setShortcut(SHOW_MAP_SHORTCUT);
|
||||||
@ -294,10 +301,10 @@ void GUI::createActions()
|
|||||||
_loadMapAction->setMenuRole(QAction::NoRole);
|
_loadMapAction->setMenuRole(QAction::NoRole);
|
||||||
connect(_loadMapAction, SIGNAL(triggered()), this, SLOT(loadMap()));
|
connect(_loadMapAction, SIGNAL(triggered()), this, SLOT(loadMap()));
|
||||||
_clearMapCacheAction = new QAction(tr("Clear tile cache"), this);
|
_clearMapCacheAction = new QAction(tr("Clear tile cache"), this);
|
||||||
|
_clearMapCacheAction->setEnabled(false);
|
||||||
_clearMapCacheAction->setMenuRole(QAction::NoRole);
|
_clearMapCacheAction->setMenuRole(QAction::NoRole);
|
||||||
connect(_clearMapCacheAction, SIGNAL(triggered()), _mapView,
|
connect(_clearMapCacheAction, SIGNAL(triggered()), _mapView,
|
||||||
SLOT(clearMapCache()));
|
SLOT(clearMapCache()));
|
||||||
createMapActions();
|
|
||||||
_nextMapAction = new QAction(tr("Next map"), this);
|
_nextMapAction = new QAction(tr("Next map"), this);
|
||||||
_nextMapAction->setMenuRole(QAction::NoRole);
|
_nextMapAction->setMenuRole(QAction::NoRole);
|
||||||
_nextMapAction->setShortcut(NEXT_MAP_SHORTCUT);
|
_nextMapAction->setShortcut(NEXT_MAP_SHORTCUT);
|
||||||
@ -308,10 +315,6 @@ void GUI::createActions()
|
|||||||
_prevMapAction->setShortcut(PREV_MAP_SHORTCUT);
|
_prevMapAction->setShortcut(PREV_MAP_SHORTCUT);
|
||||||
connect(_prevMapAction, SIGNAL(triggered()), this, SLOT(prevMap()));
|
connect(_prevMapAction, SIGNAL(triggered()), this, SLOT(prevMap()));
|
||||||
addAction(_prevMapAction);
|
addAction(_prevMapAction);
|
||||||
if (_ml->maps().isEmpty()) {
|
|
||||||
_showMapAction->setEnabled(false);
|
|
||||||
_clearMapCacheAction->setEnabled(false);
|
|
||||||
}
|
|
||||||
_showCoordinatesAction = new QAction(tr("Show cursor coordinates"), this);
|
_showCoordinatesAction = new QAction(tr("Show cursor coordinates"), this);
|
||||||
_showCoordinatesAction->setMenuRole(QAction::NoRole);
|
_showCoordinatesAction->setMenuRole(QAction::NoRole);
|
||||||
_showCoordinatesAction->setCheckable(true);
|
_showCoordinatesAction->setCheckable(true);
|
||||||
@ -451,11 +454,11 @@ void GUI::createActions()
|
|||||||
_degreesMinutesAction->setActionGroup(ag);
|
_degreesMinutesAction->setActionGroup(ag);
|
||||||
connect(_degreesMinutesAction, SIGNAL(triggered()), this,
|
connect(_degreesMinutesAction, SIGNAL(triggered()), this,
|
||||||
SLOT(setDegreesMinutes()));
|
SLOT(setDegreesMinutes()));
|
||||||
_DMSAction = new QAction(tr("Degrees, minutes, seconds (DMS)"), this);
|
_dmsAction = new QAction(tr("Degrees, minutes, seconds (DMS)"), this);
|
||||||
_DMSAction->setMenuRole(QAction::NoRole);
|
_dmsAction->setMenuRole(QAction::NoRole);
|
||||||
_DMSAction->setCheckable(true);
|
_dmsAction->setCheckable(true);
|
||||||
_DMSAction->setActionGroup(ag);
|
_dmsAction->setActionGroup(ag);
|
||||||
connect(_DMSAction, SIGNAL(triggered()), this, SLOT(setDMS()));
|
connect(_dmsAction, SIGNAL(triggered()), this, SLOT(setDMS()));
|
||||||
_fullscreenAction = new QAction(QIcon(FULLSCREEN_ICON),
|
_fullscreenAction = new QAction(QIcon(FULLSCREEN_ICON),
|
||||||
tr("Fullscreen mode"), this);
|
tr("Fullscreen mode"), this);
|
||||||
_fullscreenAction->setMenuRole(QAction::NoRole);
|
_fullscreenAction->setMenuRole(QAction::NoRole);
|
||||||
@ -506,7 +509,7 @@ void GUI::createMenus()
|
|||||||
#endif // Q_OS_MAC
|
#endif // Q_OS_MAC
|
||||||
|
|
||||||
_mapMenu = menuBar()->addMenu(tr("&Map"));
|
_mapMenu = menuBar()->addMenu(tr("&Map"));
|
||||||
_mapMenu->addActions(_mapActions);
|
_mapMenu->addActions(_mapsActionGroup->actions());
|
||||||
_mapsEnd = _mapMenu->addSeparator();
|
_mapsEnd = _mapMenu->addSeparator();
|
||||||
_mapMenu->addAction(_loadMapAction);
|
_mapMenu->addAction(_loadMapAction);
|
||||||
_mapMenu->addAction(_clearMapCacheAction);
|
_mapMenu->addAction(_clearMapCacheAction);
|
||||||
@ -559,7 +562,7 @@ void GUI::createMenus()
|
|||||||
QMenu *coordinatesMenu = settingsMenu->addMenu(tr("Coordinates format"));
|
QMenu *coordinatesMenu = settingsMenu->addMenu(tr("Coordinates format"));
|
||||||
coordinatesMenu->addAction(_decimalDegreesAction);
|
coordinatesMenu->addAction(_decimalDegreesAction);
|
||||||
coordinatesMenu->addAction(_degreesMinutesAction);
|
coordinatesMenu->addAction(_degreesMinutesAction);
|
||||||
coordinatesMenu->addAction(_DMSAction);
|
coordinatesMenu->addAction(_dmsAction);
|
||||||
settingsMenu->addSeparator();
|
settingsMenu->addSeparator();
|
||||||
settingsMenu->addAction(_showToolbarsAction);
|
settingsMenu->addAction(_showToolbarsAction);
|
||||||
settingsMenu->addAction(_fullscreenAction);
|
settingsMenu->addAction(_fullscreenAction);
|
||||||
@ -608,6 +611,7 @@ void GUI::createToolBars()
|
|||||||
|
|
||||||
void GUI::createMapView()
|
void GUI::createMapView()
|
||||||
{
|
{
|
||||||
|
_map = new EmptyMap(this);
|
||||||
_mapView = new MapView(_map, _poi, this);
|
_mapView = new MapView(_map, _poi, this);
|
||||||
_mapView->setSizePolicy(QSizePolicy(QSizePolicy::Ignored,
|
_mapView->setSizePolicy(QSizePolicy(QSizePolicy::Ignored,
|
||||||
QSizePolicy::Expanding));
|
QSizePolicy::Expanding));
|
||||||
@ -905,9 +909,14 @@ void GUI::openOptions()
|
|||||||
Track::action(options.option); \
|
Track::action(options.option); \
|
||||||
reload = true; \
|
reload = true; \
|
||||||
}
|
}
|
||||||
#define SET_DATA_OPTION(option, action) \
|
#define SET_ROUTE_OPTION(option, action) \
|
||||||
if (options.option != _options.option) { \
|
if (options.option != _options.option) { \
|
||||||
Data::action(options.option); \
|
Route::action(options.option); \
|
||||||
|
reload = true; \
|
||||||
|
}
|
||||||
|
#define SET_WAYPOINT_OPTION(option, action) \
|
||||||
|
if (options.option != _options.option) { \
|
||||||
|
Waypoint::action(options.option); \
|
||||||
reload = true; \
|
reload = true; \
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -949,16 +958,22 @@ void GUI::openOptions()
|
|||||||
SET_TRACK_OPTION(cadenceFilter, setCadenceFilter);
|
SET_TRACK_OPTION(cadenceFilter, setCadenceFilter);
|
||||||
SET_TRACK_OPTION(powerFilter, setPowerFilter);
|
SET_TRACK_OPTION(powerFilter, setPowerFilter);
|
||||||
SET_TRACK_OPTION(outlierEliminate, setOutlierElimination);
|
SET_TRACK_OPTION(outlierEliminate, setOutlierElimination);
|
||||||
|
SET_TRACK_OPTION(automaticPause, setAutomaticPause);
|
||||||
SET_TRACK_OPTION(pauseSpeed, setPauseSpeed);
|
SET_TRACK_OPTION(pauseSpeed, setPauseSpeed);
|
||||||
SET_TRACK_OPTION(pauseInterval, setPauseInterval);
|
SET_TRACK_OPTION(pauseInterval, setPauseInterval);
|
||||||
SET_TRACK_OPTION(useReportedSpeed, useReportedSpeed);
|
SET_TRACK_OPTION(useReportedSpeed, useReportedSpeed);
|
||||||
|
SET_TRACK_OPTION(dataUseDEM, useDEM);
|
||||||
|
SET_TRACK_OPTION(showSecondaryElevation, showSecondaryElevation);
|
||||||
|
SET_TRACK_OPTION(showSecondarySpeed, showSecondarySpeed);
|
||||||
|
|
||||||
SET_DATA_OPTION(dataUseDEM, useDEM);
|
SET_ROUTE_OPTION(dataUseDEM, useDEM);
|
||||||
|
SET_ROUTE_OPTION(showSecondaryElevation, showSecondaryElevation);
|
||||||
|
|
||||||
|
SET_WAYPOINT_OPTION(dataUseDEM, useDEM);
|
||||||
|
SET_WAYPOINT_OPTION(showSecondaryElevation, showSecondaryElevation);
|
||||||
|
|
||||||
if (options.poiRadius != _options.poiRadius)
|
if (options.poiRadius != _options.poiRadius)
|
||||||
_poi->setRadius(options.poiRadius);
|
_poi->setRadius(options.poiRadius);
|
||||||
if (options.poiUseDEM != _options.poiUseDEM)
|
|
||||||
_poi->useDEM(options.poiUseDEM);
|
|
||||||
|
|
||||||
if (options.pixmapCache != _options.pixmapCache)
|
if (options.pixmapCache != _options.pixmapCache)
|
||||||
QPixmapCache::setCacheLimit(options.pixmapCache * 1024);
|
QPixmapCache::setCacheLimit(options.pixmapCache * 1024);
|
||||||
@ -1321,22 +1336,49 @@ void GUI::loadMap()
|
|||||||
|
|
||||||
bool GUI::loadMap(const QString &fileName)
|
bool GUI::loadMap(const QString &fileName)
|
||||||
{
|
{
|
||||||
|
// On OS X fileName may be a directory!
|
||||||
|
|
||||||
if (fileName.isEmpty())
|
if (fileName.isEmpty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (_ml->loadFile(fileName)) {
|
QString error;
|
||||||
QAction *a = createMapAction(_ml->maps().last());
|
QList<Map*> maps = MapList::loadMaps(fileName, error);
|
||||||
|
if (maps.isEmpty()) {
|
||||||
|
error = tr("Error loading map:") + "\n\n"
|
||||||
|
+ fileName + "\n\n" + error;
|
||||||
|
QMessageBox::critical(this, APP_NAME, error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < maps.size(); i++) {
|
||||||
|
Map *map = maps.at(i);
|
||||||
|
MapAction *a = createMapAction(map);
|
||||||
_mapMenu->insertAction(_mapsEnd, a);
|
_mapMenu->insertAction(_mapsEnd, a);
|
||||||
|
if (map->isReady()) {
|
||||||
|
a->trigger();
|
||||||
|
_showMapAction->setEnabled(true);
|
||||||
|
_clearMapCacheAction->setEnabled(true);
|
||||||
|
} else
|
||||||
|
connect(a, SIGNAL(loaded()), this, SLOT(mapLoaded()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GUI::mapLoaded()
|
||||||
|
{
|
||||||
|
MapAction *action = static_cast<MapAction*>(QObject::sender());
|
||||||
|
Map *map = action->data().value<Map*>();
|
||||||
|
|
||||||
|
if (map->isValid()) {
|
||||||
|
action->trigger();
|
||||||
_showMapAction->setEnabled(true);
|
_showMapAction->setEnabled(true);
|
||||||
_clearMapCacheAction->setEnabled(true);
|
_clearMapCacheAction->setEnabled(true);
|
||||||
a->trigger();
|
|
||||||
return true;
|
|
||||||
} else {
|
} else {
|
||||||
QString error = tr("Error loading map:") + "\n\n"
|
QString error = tr("Error loading map:") + "\n\n"
|
||||||
+ fileName + "\n\n" + _ml->errorString();
|
+ map->name() + "\n\n" + map->errorString();
|
||||||
QMessageBox::critical(this, APP_NAME, error);
|
QMessageBox::critical(this, APP_NAME, error);
|
||||||
|
action->deleteLater();
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1378,31 +1420,42 @@ void GUI::updateWindowTitle()
|
|||||||
setWindowTitle(APP_NAME);
|
setWindowTitle(APP_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUI::mapChanged(int index)
|
void GUI::mapChanged()
|
||||||
{
|
{
|
||||||
_map = _ml->maps().at(index);
|
_map = _mapsActionGroup->checkedAction()->data().value<Map*>();
|
||||||
_mapView->setMap(_map);
|
_mapView->setMap(_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUI::nextMap()
|
void GUI::nextMap()
|
||||||
{
|
{
|
||||||
if (_ml->maps().count() < 2)
|
QAction *checked = _mapsActionGroup->checkedAction();
|
||||||
|
if (!checked)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int next = (_ml->maps().indexOf(_map) + 1) % _ml->maps().count();
|
QList<QAction*> maps = _mapsActionGroup->actions();
|
||||||
_mapActions.at(next)->setChecked(true);
|
for (int i = 1; i < maps.size(); i++) {
|
||||||
mapChanged(next);
|
int next = (maps.indexOf(checked) + i) % maps.count();
|
||||||
|
if (maps.at(next)->isEnabled()) {
|
||||||
|
maps.at(next)->trigger();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUI::prevMap()
|
void GUI::prevMap()
|
||||||
{
|
{
|
||||||
if (_ml->maps().count() < 2)
|
QAction *checked = _mapsActionGroup->checkedAction();
|
||||||
|
if (!checked)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int prev = (_ml->maps().indexOf(_map) + _ml->maps().count() - 1)
|
QList<QAction*> maps = _mapsActionGroup->actions();
|
||||||
% _ml->maps().count();
|
for (int i = 1; i < maps.size(); i++) {
|
||||||
_mapActions.at(prev)->setChecked(true);
|
int prev = (maps.indexOf(checked) + maps.count() - i) % maps.count();
|
||||||
mapChanged(prev);
|
if (maps.at(prev)->isEnabled()) {
|
||||||
|
maps.at(prev)->trigger();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUI::poiFileChecked(int index)
|
void GUI::poiFileChecked(int index)
|
||||||
@ -1654,7 +1707,7 @@ void GUI::writeSettings()
|
|||||||
: _nauticalUnitsAction->isChecked() ? Nautical : Metric;
|
: _nauticalUnitsAction->isChecked() ? Nautical : Metric;
|
||||||
if (units != UNITS_DEFAULT)
|
if (units != UNITS_DEFAULT)
|
||||||
settings.setValue(UNITS_SETTING, units);
|
settings.setValue(UNITS_SETTING, units);
|
||||||
CoordinatesFormat format = _DMSAction->isChecked() ? DMS
|
CoordinatesFormat format = _dmsAction->isChecked() ? DMS
|
||||||
: _degreesMinutesAction->isChecked() ? DegreesMinutes : DecimalDegrees;
|
: _degreesMinutesAction->isChecked() ? DegreesMinutes : DecimalDegrees;
|
||||||
if (format != COORDINATES_DEFAULT)
|
if (format != COORDINATES_DEFAULT)
|
||||||
settings.setValue(COORDINATES_SETTING, format);
|
settings.setValue(COORDINATES_SETTING, format);
|
||||||
@ -1798,6 +1851,8 @@ void GUI::writeSettings()
|
|||||||
settings.setValue(POWER_FILTER_SETTING, _options.powerFilter);
|
settings.setValue(POWER_FILTER_SETTING, _options.powerFilter);
|
||||||
if (_options.outlierEliminate != OUTLIER_ELIMINATE_DEFAULT)
|
if (_options.outlierEliminate != OUTLIER_ELIMINATE_DEFAULT)
|
||||||
settings.setValue(OUTLIER_ELIMINATE_SETTING, _options.outlierEliminate);
|
settings.setValue(OUTLIER_ELIMINATE_SETTING, _options.outlierEliminate);
|
||||||
|
if (_options.automaticPause != AUTOMATIC_PAUSE_DEFAULT)
|
||||||
|
settings.setValue(AUTOMATIC_PAUSE_SETTING, _options.automaticPause);
|
||||||
if (_options.pauseSpeed != PAUSE_SPEED_DEFAULT)
|
if (_options.pauseSpeed != PAUSE_SPEED_DEFAULT)
|
||||||
settings.setValue(PAUSE_SPEED_SETTING, _options.pauseSpeed);
|
settings.setValue(PAUSE_SPEED_SETTING, _options.pauseSpeed);
|
||||||
if (_options.pauseInterval != PAUSE_INTERVAL_DEFAULT)
|
if (_options.pauseInterval != PAUSE_INTERVAL_DEFAULT)
|
||||||
@ -1806,10 +1861,14 @@ void GUI::writeSettings()
|
|||||||
settings.setValue(USE_REPORTED_SPEED_SETTING, _options.useReportedSpeed);
|
settings.setValue(USE_REPORTED_SPEED_SETTING, _options.useReportedSpeed);
|
||||||
if (_options.dataUseDEM != DATA_USE_DEM_DEFAULT)
|
if (_options.dataUseDEM != DATA_USE_DEM_DEFAULT)
|
||||||
settings.setValue(DATA_USE_DEM_SETTING, _options.dataUseDEM);
|
settings.setValue(DATA_USE_DEM_SETTING, _options.dataUseDEM);
|
||||||
|
if (_options.showSecondaryElevation != SHOW_SECONDARY_ELEVATION_DEFAULT)
|
||||||
|
settings.setValue(SHOW_SECONDARY_ELEVATION_SETTING,
|
||||||
|
_options.showSecondaryElevation);
|
||||||
|
if (_options.showSecondarySpeed != SHOW_SECONDARY_SPEED_DEFAULT)
|
||||||
|
settings.setValue(SHOW_SECONDARY_SPEED_SETTING,
|
||||||
|
_options.showSecondarySpeed);
|
||||||
if (_options.poiRadius != POI_RADIUS_DEFAULT)
|
if (_options.poiRadius != POI_RADIUS_DEFAULT)
|
||||||
settings.setValue(POI_RADIUS_SETTING, _options.poiRadius);
|
settings.setValue(POI_RADIUS_SETTING, _options.poiRadius);
|
||||||
if (_options.poiUseDEM != POI_USE_DEM_DEFAULT)
|
|
||||||
settings.setValue(POI_USE_DEM_SETTING, _options.poiUseDEM);
|
|
||||||
if (_options.useOpenGL != USE_OPENGL_DEFAULT)
|
if (_options.useOpenGL != USE_OPENGL_DEFAULT)
|
||||||
settings.setValue(USE_OPENGL_SETTING, _options.useOpenGL);
|
settings.setValue(USE_OPENGL_SETTING, _options.useOpenGL);
|
||||||
#ifdef ENABLE_HTTP2
|
#ifdef ENABLE_HTTP2
|
||||||
@ -1876,7 +1935,7 @@ void GUI::readSettings()
|
|||||||
|
|
||||||
value = settings.value(COORDINATES_SETTING, COORDINATES_DEFAULT).toInt();
|
value = settings.value(COORDINATES_SETTING, COORDINATES_DEFAULT).toInt();
|
||||||
if (value == DMS)
|
if (value == DMS)
|
||||||
_DMSAction->trigger();
|
_dmsAction->trigger();
|
||||||
else if (value == DegreesMinutes)
|
else if (value == DegreesMinutes)
|
||||||
_degreesMinutesAction->trigger();
|
_degreesMinutesAction->trigger();
|
||||||
else
|
else
|
||||||
@ -1893,9 +1952,11 @@ void GUI::readSettings()
|
|||||||
_showMapAction->setChecked(true);
|
_showMapAction->setChecked(true);
|
||||||
else
|
else
|
||||||
_mapView->showMap(false);
|
_mapView->showMap(false);
|
||||||
if (_ml->maps().count()) {
|
QAction *ma = mapAction(settings.value(CURRENT_MAP_SETTING).toString());
|
||||||
int index = mapIndex(settings.value(CURRENT_MAP_SETTING).toString());
|
if (ma) {
|
||||||
_mapActions.at(index)->trigger();
|
ma->trigger();
|
||||||
|
_showMapAction->setEnabled(true);
|
||||||
|
_clearMapCacheAction->setEnabled(true);
|
||||||
}
|
}
|
||||||
if (settings.value(SHOW_COORDINATES_SETTING, SHOW_COORDINATES_DEFAULT)
|
if (settings.value(SHOW_COORDINATES_SETTING, SHOW_COORDINATES_DEFAULT)
|
||||||
.toBool()) {
|
.toBool()) {
|
||||||
@ -2072,12 +2133,18 @@ void GUI::readSettings()
|
|||||||
USE_REPORTED_SPEED_DEFAULT).toBool();
|
USE_REPORTED_SPEED_DEFAULT).toBool();
|
||||||
_options.dataUseDEM = settings.value(DATA_USE_DEM_SETTING,
|
_options.dataUseDEM = settings.value(DATA_USE_DEM_SETTING,
|
||||||
DATA_USE_DEM_DEFAULT).toBool();
|
DATA_USE_DEM_DEFAULT).toBool();
|
||||||
|
_options.showSecondaryElevation = settings.value(
|
||||||
|
SHOW_SECONDARY_ELEVATION_SETTING,
|
||||||
|
SHOW_SECONDARY_ELEVATION_DEFAULT).toBool();
|
||||||
|
_options.showSecondarySpeed = settings.value(
|
||||||
|
SHOW_SECONDARY_SPEED_SETTING,
|
||||||
|
SHOW_SECONDARY_SPEED_DEFAULT).toBool();
|
||||||
|
_options.automaticPause = settings.value(AUTOMATIC_PAUSE_SETTING,
|
||||||
|
AUTOMATIC_PAUSE_DEFAULT).toBool();
|
||||||
_options.pauseInterval = settings.value(PAUSE_INTERVAL_SETTING,
|
_options.pauseInterval = settings.value(PAUSE_INTERVAL_SETTING,
|
||||||
PAUSE_INTERVAL_DEFAULT).toInt();
|
PAUSE_INTERVAL_DEFAULT).toInt();
|
||||||
_options.poiRadius = settings.value(POI_RADIUS_SETTING, POI_RADIUS_DEFAULT)
|
_options.poiRadius = settings.value(POI_RADIUS_SETTING, POI_RADIUS_DEFAULT)
|
||||||
.toInt();
|
.toInt();
|
||||||
_options.poiUseDEM = settings.value(POI_USE_DEM_SETTING,
|
|
||||||
POI_USE_DEM_DEFAULT).toBool();
|
|
||||||
_options.useOpenGL = settings.value(USE_OPENGL_SETTING, USE_OPENGL_DEFAULT)
|
_options.useOpenGL = settings.value(USE_OPENGL_SETTING, USE_OPENGL_DEFAULT)
|
||||||
.toBool();
|
.toBool();
|
||||||
#ifdef ENABLE_HTTP2
|
#ifdef ENABLE_HTTP2
|
||||||
@ -2153,24 +2220,42 @@ void GUI::readSettings()
|
|||||||
Track::setCadenceFilter(_options.cadenceFilter);
|
Track::setCadenceFilter(_options.cadenceFilter);
|
||||||
Track::setPowerFilter(_options.powerFilter);
|
Track::setPowerFilter(_options.powerFilter);
|
||||||
Track::setOutlierElimination(_options.outlierEliminate);
|
Track::setOutlierElimination(_options.outlierEliminate);
|
||||||
|
Track::setAutomaticPause(_options.automaticPause);
|
||||||
Track::setPauseSpeed(_options.pauseSpeed);
|
Track::setPauseSpeed(_options.pauseSpeed);
|
||||||
Track::setPauseInterval(_options.pauseInterval);
|
Track::setPauseInterval(_options.pauseInterval);
|
||||||
Track::useReportedSpeed(_options.useReportedSpeed);
|
Track::useReportedSpeed(_options.useReportedSpeed);
|
||||||
Data::useDEM(_options.dataUseDEM);
|
Track::useDEM(_options.dataUseDEM);
|
||||||
|
Track::showSecondaryElevation(_options.showSecondaryElevation);
|
||||||
|
Track::showSecondarySpeed(_options.showSecondarySpeed);
|
||||||
|
Route::useDEM(_options.dataUseDEM);
|
||||||
|
Route::showSecondaryElevation(_options.showSecondaryElevation);
|
||||||
|
Waypoint::useDEM(_options.dataUseDEM);
|
||||||
|
Waypoint::showSecondaryElevation(_options.showSecondaryElevation);
|
||||||
|
|
||||||
_poi->setRadius(_options.poiRadius);
|
_poi->setRadius(_options.poiRadius);
|
||||||
_poi->useDEM(_options.poiUseDEM);
|
|
||||||
|
|
||||||
QPixmapCache::setCacheLimit(_options.pixmapCache * 1024);
|
QPixmapCache::setCacheLimit(_options.pixmapCache * 1024);
|
||||||
|
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
int GUI::mapIndex(const QString &name)
|
QAction *GUI::mapAction(const QString &name)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < _ml->maps().count(); i++)
|
QList<QAction *> maps = _mapsActionGroup->actions();
|
||||||
if (_ml->maps().at(i)->name() == name)
|
|
||||||
return i;
|
// Last map
|
||||||
|
for (int i = 0; i < maps.count(); i++) {
|
||||||
|
Map *map = maps.at(i)->data().value<Map*>();
|
||||||
|
if (map->name() == name && map->isReady())
|
||||||
|
return maps.at(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any usable map
|
||||||
|
for (int i = 0; i < maps.count(); i++) {
|
||||||
|
Map *map = maps.at(i)->data().value<Map*>();
|
||||||
|
if (map->isReady())
|
||||||
|
return maps.at(i);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -26,9 +26,9 @@ class FileBrowser;
|
|||||||
class GraphTab;
|
class GraphTab;
|
||||||
class MapView;
|
class MapView;
|
||||||
class Map;
|
class Map;
|
||||||
class MapList;
|
|
||||||
class POI;
|
class POI;
|
||||||
class QScreen;
|
class QScreen;
|
||||||
|
class MapAction;
|
||||||
|
|
||||||
class GUI : public QMainWindow
|
class GUI : public QMainWindow
|
||||||
{
|
{
|
||||||
@ -64,7 +64,7 @@ private slots:
|
|||||||
void prevMap();
|
void prevMap();
|
||||||
void openOptions();
|
void openOptions();
|
||||||
|
|
||||||
void mapChanged(int);
|
void mapChanged();
|
||||||
void graphChanged(int);
|
void graphChanged(int);
|
||||||
void poiFileChecked(int);
|
void poiFileChecked(int);
|
||||||
|
|
||||||
@ -88,16 +88,18 @@ private slots:
|
|||||||
void screenChanged(QScreen *screen);
|
void screenChanged(QScreen *screen);
|
||||||
void logicalDotsPerInchChanged(qreal dpi);
|
void logicalDotsPerInchChanged(qreal dpi);
|
||||||
|
|
||||||
|
void mapLoaded();
|
||||||
|
void mapInitialized();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef QPair<QDate, QDate> DateRange;
|
typedef QPair<QDate, QDate> DateRange;
|
||||||
|
|
||||||
void loadMaps();
|
|
||||||
void loadPOIs();
|
void loadPOIs();
|
||||||
void closeFiles();
|
void closeFiles();
|
||||||
void plot(QPrinter *printer);
|
void plot(QPrinter *printer);
|
||||||
|
|
||||||
QAction *createPOIFileAction(const QString &fileName);
|
QAction *createPOIFileAction(const QString &fileName);
|
||||||
QAction *createMapAction(const Map *map);
|
MapAction *createMapAction(Map *map);
|
||||||
void createPOIFilesActions();
|
void createPOIFilesActions();
|
||||||
void createMapActions();
|
void createMapActions();
|
||||||
void createActions();
|
void createActions();
|
||||||
@ -127,7 +129,7 @@ private:
|
|||||||
qreal distance() const;
|
qreal distance() const;
|
||||||
qreal time() const;
|
qreal time() const;
|
||||||
qreal movingTime() const;
|
qreal movingTime() const;
|
||||||
int mapIndex(const QString &name);
|
QAction *mapAction(const QString &name);
|
||||||
void readSettings();
|
void readSettings();
|
||||||
void writeSettings();
|
void writeSettings();
|
||||||
|
|
||||||
@ -180,7 +182,7 @@ private:
|
|||||||
QAction *_nauticalUnitsAction;
|
QAction *_nauticalUnitsAction;
|
||||||
QAction *_decimalDegreesAction;
|
QAction *_decimalDegreesAction;
|
||||||
QAction *_degreesMinutesAction;
|
QAction *_degreesMinutesAction;
|
||||||
QAction *_DMSAction;
|
QAction *_dmsAction;
|
||||||
QAction *_totalTimeAction;
|
QAction *_totalTimeAction;
|
||||||
QAction *_movingTimeAction;
|
QAction *_movingTimeAction;
|
||||||
QAction *_nextMapAction;
|
QAction *_nextMapAction;
|
||||||
@ -196,11 +198,9 @@ private:
|
|||||||
QAction *_showCoordinatesAction;
|
QAction *_showCoordinatesAction;
|
||||||
QAction *_openOptionsAction;
|
QAction *_openOptionsAction;
|
||||||
QAction *_mapsEnd;
|
QAction *_mapsEnd;
|
||||||
QList<QAction*> _mapActions;
|
|
||||||
QList<QAction*> _poiFilesActions;
|
|
||||||
|
|
||||||
|
QList<QAction*> _poiFilesActions;
|
||||||
QSignalMapper *_poiFilesSignalMapper;
|
QSignalMapper *_poiFilesSignalMapper;
|
||||||
QSignalMapper *_mapsSignalMapper;
|
|
||||||
|
|
||||||
QLabel *_fileNameLabel;
|
QLabel *_fileNameLabel;
|
||||||
QLabel *_distanceLabel;
|
QLabel *_distanceLabel;
|
||||||
@ -212,7 +212,6 @@ private:
|
|||||||
QList<GraphTab*> _tabs;
|
QList<GraphTab*> _tabs;
|
||||||
|
|
||||||
POI *_poi;
|
POI *_poi;
|
||||||
MapList *_ml;
|
|
||||||
Map *_map;
|
Map *_map;
|
||||||
|
|
||||||
FileBrowser *_browser;
|
FileBrowser *_browser;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
HeartRateGraphItem::HeartRateGraphItem(const Graph &graph, GraphType type,
|
HeartRateGraphItem::HeartRateGraphItem(const Graph &graph, GraphType type,
|
||||||
int width, const QColor &color, QGraphicsItem *parent)
|
int width, const QColor &color, QGraphicsItem *parent)
|
||||||
: GraphItem(graph, type, width, color, parent)
|
: GraphItem(graph, type, width, color, Qt::SolidLine, parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
32
src/GUI/mapaction.h
Normal file
32
src/GUI/mapaction.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef MAPACTION_H
|
||||||
|
#define MAPACTION_H
|
||||||
|
|
||||||
|
#include <QAction>
|
||||||
|
#include "map/map.h"
|
||||||
|
|
||||||
|
class MapAction : public QAction
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MapAction(Map *map, QObject *parent = 0) : QAction(map->name(), parent)
|
||||||
|
{
|
||||||
|
map->setParent(this);
|
||||||
|
setData(QVariant::fromValue(map));
|
||||||
|
setEnabled(map->isValid());
|
||||||
|
connect(map, SIGNAL(mapLoaded()), this, SLOT(mapLoaded()));
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void loaded();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void mapLoaded()
|
||||||
|
{
|
||||||
|
Map *map = data().value<Map*>();
|
||||||
|
setEnabled(map->isValid());
|
||||||
|
emit loaded();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MAPACTION_H
|
@ -2,7 +2,6 @@
|
|||||||
#include <QGraphicsScene>
|
#include <QGraphicsScene>
|
||||||
#include <QWheelEvent>
|
#include <QWheelEvent>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QPixmapCache>
|
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
#include "data/poi.h"
|
#include "data/poi.h"
|
||||||
#include "data/data.h"
|
#include "data/data.h"
|
||||||
@ -55,7 +54,7 @@ MapView::MapView(Map *map, POI *poi, QWidget *parent)
|
|||||||
_map = map;
|
_map = map;
|
||||||
_map->load();
|
_map->load();
|
||||||
_map->setProjection(_projection);
|
_map->setProjection(_projection);
|
||||||
connect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
|
connect(_map, SIGNAL(tilesLoaded()), this, SLOT(reloadMap()));
|
||||||
|
|
||||||
_poi = poi;
|
_poi = poi;
|
||||||
connect(_poi, SIGNAL(pointsChanged()), this, SLOT(updatePOI()));
|
connect(_poi, SIGNAL(pointsChanged()), this, SLOT(updatePOI()));
|
||||||
@ -317,7 +316,7 @@ void MapView::setMap(Map *map)
|
|||||||
RectC cr(_map->xy2ll(vr.topLeft()), _map->xy2ll(vr.bottomRight()));
|
RectC cr(_map->xy2ll(vr.topLeft()), _map->xy2ll(vr.bottomRight()));
|
||||||
|
|
||||||
_map->unload();
|
_map->unload();
|
||||||
disconnect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
|
disconnect(_map, SIGNAL(tilesLoaded()), this, SLOT(reloadMap()));
|
||||||
|
|
||||||
_map = map;
|
_map = map;
|
||||||
_map->load();
|
_map->load();
|
||||||
@ -325,7 +324,7 @@ void MapView::setMap(Map *map)
|
|||||||
#ifdef ENABLE_HIDPI
|
#ifdef ENABLE_HIDPI
|
||||||
_map->setDevicePixelRatio(_deviceRatio, _mapRatio);
|
_map->setDevicePixelRatio(_deviceRatio, _mapRatio);
|
||||||
#endif // ENABLE_HIDPI
|
#endif // ENABLE_HIDPI
|
||||||
connect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
|
connect(_map, SIGNAL(tilesLoaded()), this, SLOT(reloadMap()));
|
||||||
|
|
||||||
digitalZoom(0);
|
digitalZoom(0);
|
||||||
|
|
||||||
@ -351,7 +350,6 @@ void MapView::setMap(Map *map)
|
|||||||
centerOn(nc);
|
centerOn(nc);
|
||||||
|
|
||||||
reloadMap();
|
reloadMap();
|
||||||
QPixmapCache::clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapView::setPOI(POI *poi)
|
void MapView::setPOI(POI *poi)
|
||||||
@ -453,10 +451,7 @@ void MapView::setCoordinatesFormat(CoordinatesFormat format)
|
|||||||
void MapView::clearMapCache()
|
void MapView::clearMapCache()
|
||||||
{
|
{
|
||||||
_map->clearCache();
|
_map->clearCache();
|
||||||
|
reloadMap();
|
||||||
fitMapZoom();
|
|
||||||
rescale();
|
|
||||||
centerOn(contentCenter());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapView::digitalZoom(int zoom)
|
void MapView::digitalZoom(int zoom)
|
||||||
@ -982,7 +977,6 @@ void MapView::setDevicePixelRatio(qreal deviceRatio, qreal mapRatio)
|
|||||||
|
|
||||||
_deviceRatio = deviceRatio;
|
_deviceRatio = deviceRatio;
|
||||||
_mapRatio = mapRatio;
|
_mapRatio = mapRatio;
|
||||||
QPixmapCache::clear();
|
|
||||||
|
|
||||||
QRectF vr(mapToScene(viewport()->rect()).boundingRect()
|
QRectF vr(mapToScene(viewport()->rect()).boundingRect()
|
||||||
.intersected(_map->bounds()));
|
.intersected(_map->bounds()));
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <QRadioButton>
|
#include <QRadioButton>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QSysInfo>
|
#include <QSysInfo>
|
||||||
|
#include <QButtonGroup>
|
||||||
#include "map/pcs.h"
|
#include "map/pcs.h"
|
||||||
#include "icons.h"
|
#include "icons.h"
|
||||||
#include "colorbox.h"
|
#include "colorbox.h"
|
||||||
@ -37,6 +38,12 @@ static QFrame *line()
|
|||||||
#endif // Q_OS_MAC
|
#endif // Q_OS_MAC
|
||||||
|
|
||||||
|
|
||||||
|
void OptionsDialog::automaticPauseDetectionSet(bool set)
|
||||||
|
{
|
||||||
|
_pauseInterval->setEnabled(!set);
|
||||||
|
_pauseSpeed->setEnabled(!set);
|
||||||
|
}
|
||||||
|
|
||||||
QWidget *OptionsDialog::createMapPage()
|
QWidget *OptionsDialog::createMapPage()
|
||||||
{
|
{
|
||||||
_projection = new LimitedComboBox(200);
|
_projection = new LimitedComboBox(200);
|
||||||
@ -343,10 +350,18 @@ QWidget *OptionsDialog::createDataPage()
|
|||||||
filterTab->setLayout(filterTabLayout);
|
filterTab->setLayout(filterTabLayout);
|
||||||
|
|
||||||
|
|
||||||
|
_automaticPause = new QRadioButton(tr("Automatic"));
|
||||||
|
_manualPause = new QRadioButton(tr("Custom"));
|
||||||
|
if (_options->automaticPause)
|
||||||
|
_automaticPause->setChecked(true);
|
||||||
|
else
|
||||||
|
_manualPause->setChecked(true);
|
||||||
|
|
||||||
_pauseSpeed = new QDoubleSpinBox();
|
_pauseSpeed = new QDoubleSpinBox();
|
||||||
_pauseSpeed->setDecimals(1);
|
_pauseSpeed->setDecimals(1);
|
||||||
_pauseSpeed->setSingleStep(0.1);
|
_pauseSpeed->setSingleStep(0.1);
|
||||||
_pauseSpeed->setMinimum(0.1);
|
_pauseSpeed->setMinimum(0.1);
|
||||||
|
_pauseSpeed->setEnabled(_manualPause->isChecked());
|
||||||
if (_options->units == Imperial) {
|
if (_options->units == Imperial) {
|
||||||
_pauseSpeed->setValue(_options->pauseSpeed * MS2MIH);
|
_pauseSpeed->setValue(_options->pauseSpeed * MS2MIH);
|
||||||
_pauseSpeed->setSuffix(UNIT_SPACE + tr("mi/h"));
|
_pauseSpeed->setSuffix(UNIT_SPACE + tr("mi/h"));
|
||||||
@ -361,10 +376,26 @@ QWidget *OptionsDialog::createDataPage()
|
|||||||
_pauseInterval->setMinimum(1);
|
_pauseInterval->setMinimum(1);
|
||||||
_pauseInterval->setSuffix(UNIT_SPACE + tr("s"));
|
_pauseInterval->setSuffix(UNIT_SPACE + tr("s"));
|
||||||
_pauseInterval->setValue(_options->pauseInterval);
|
_pauseInterval->setValue(_options->pauseInterval);
|
||||||
|
_pauseInterval->setEnabled(_manualPause->isChecked());
|
||||||
|
|
||||||
QFormLayout *pauseLayout = new QFormLayout();
|
connect(_automaticPause, SIGNAL(toggled(bool)), this,
|
||||||
pauseLayout->addRow(tr("Minimal speed:"), _pauseSpeed);
|
SLOT(automaticPauseDetectionSet(bool)));
|
||||||
pauseLayout->addRow(tr("Minimal duration:"), _pauseInterval);
|
|
||||||
|
QHBoxLayout *pauseTypeLayout = new QHBoxLayout();
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
pauseTypeLayout->addStretch();
|
||||||
|
#endif
|
||||||
|
pauseTypeLayout->addWidget(_automaticPause);
|
||||||
|
pauseTypeLayout->addWidget(_manualPause);
|
||||||
|
pauseTypeLayout->addStretch();
|
||||||
|
|
||||||
|
QFormLayout *pauseValuesLayout = new QFormLayout();
|
||||||
|
pauseValuesLayout->addRow(tr("Minimal speed:"), _pauseSpeed);
|
||||||
|
pauseValuesLayout->addRow(tr("Minimal duration:"), _pauseInterval);
|
||||||
|
|
||||||
|
QVBoxLayout *pauseLayout = new QVBoxLayout();
|
||||||
|
pauseLayout->addLayout(pauseTypeLayout);
|
||||||
|
pauseLayout->addLayout(pauseValuesLayout);
|
||||||
|
|
||||||
QWidget *pauseTab = new QWidget();
|
QWidget *pauseTab = new QWidget();
|
||||||
pauseTab->setLayout(pauseLayout);
|
pauseTab->setLayout(pauseLayout);
|
||||||
@ -376,6 +407,8 @@ QWidget *OptionsDialog::createDataPage()
|
|||||||
_reportedSpeed->setChecked(true);
|
_reportedSpeed->setChecked(true);
|
||||||
else
|
else
|
||||||
_computedSpeed->setChecked(true);
|
_computedSpeed->setChecked(true);
|
||||||
|
_showSecondarySpeed = new QCheckBox(tr("Show secondary speed"));
|
||||||
|
_showSecondarySpeed->setChecked(_options->showSecondarySpeed);
|
||||||
|
|
||||||
_dataGPSElevation = new QRadioButton(tr("GPS data"));
|
_dataGPSElevation = new QRadioButton(tr("GPS data"));
|
||||||
_dataDEMElevation = new QRadioButton(tr("DEM data"));
|
_dataDEMElevation = new QRadioButton(tr("DEM data"));
|
||||||
@ -383,19 +416,28 @@ QWidget *OptionsDialog::createDataPage()
|
|||||||
_dataDEMElevation->setChecked(true);
|
_dataDEMElevation->setChecked(true);
|
||||||
else
|
else
|
||||||
_dataGPSElevation->setChecked(true);
|
_dataGPSElevation->setChecked(true);
|
||||||
|
_showSecondaryElevation = new QCheckBox(tr("Show secondary elevation"));
|
||||||
|
_showSecondaryElevation->setChecked(_options->showSecondaryElevation);
|
||||||
|
|
||||||
QWidget *sourceTab = new QWidget();
|
QWidget *sourceTab = new QWidget();
|
||||||
QVBoxLayout *sourceTabLayout = new QVBoxLayout();
|
QVBoxLayout *sourceTabLayout = new QVBoxLayout();
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
|
QButtonGroup *speedGroup = new QButtonGroup(this);
|
||||||
|
speedGroup->addButton(_computedSpeed);
|
||||||
|
speedGroup->addButton(_reportedSpeed);
|
||||||
QVBoxLayout *speedOptions = new QVBoxLayout();
|
QVBoxLayout *speedOptions = new QVBoxLayout();
|
||||||
speedOptions->addWidget(_computedSpeed);
|
speedOptions->addWidget(_computedSpeed);
|
||||||
speedOptions->addWidget(_reportedSpeed);
|
speedOptions->addWidget(_reportedSpeed);
|
||||||
|
speedOptions->addWidget(_showSecondarySpeed);
|
||||||
|
|
||||||
|
QButtonGroup *elevationGroup = new QButtonGroup(this);
|
||||||
|
elevationGroup->addButton(_dataGPSElevation);
|
||||||
|
elevationGroup->addButton(_dataDEMElevation);
|
||||||
QVBoxLayout *elevationOptions = new QVBoxLayout();
|
QVBoxLayout *elevationOptions = new QVBoxLayout();
|
||||||
elevationOptions->addWidget(_dataGPSElevation);
|
elevationOptions->addWidget(_dataGPSElevation);
|
||||||
elevationOptions->addWidget(_dataDEMElevation);
|
elevationOptions->addWidget(_dataDEMElevation);
|
||||||
|
elevationOptions->addWidget(_showSecondaryElevation);
|
||||||
|
|
||||||
QFormLayout *formLayout = new QFormLayout();
|
QFormLayout *formLayout = new QFormLayout();
|
||||||
formLayout->addRow(tr("Speed:"), speedOptions);
|
formLayout->addRow(tr("Speed:"), speedOptions);
|
||||||
@ -408,12 +450,14 @@ QWidget *OptionsDialog::createDataPage()
|
|||||||
|
|
||||||
speedLayout->addWidget(_computedSpeed);
|
speedLayout->addWidget(_computedSpeed);
|
||||||
speedLayout->addWidget(_reportedSpeed);
|
speedLayout->addWidget(_reportedSpeed);
|
||||||
|
speedLayout->addWidget(_showSecondarySpeed);
|
||||||
|
|
||||||
QGroupBox *speedBox = new QGroupBox(tr("Speed"));
|
QGroupBox *speedBox = new QGroupBox(tr("Speed"));
|
||||||
speedBox->setLayout(speedLayout);
|
speedBox->setLayout(speedLayout);
|
||||||
|
|
||||||
elevationLayout->addWidget(_dataGPSElevation);
|
elevationLayout->addWidget(_dataGPSElevation);
|
||||||
elevationLayout->addWidget(_dataDEMElevation);
|
elevationLayout->addWidget(_dataDEMElevation);
|
||||||
|
elevationLayout->addWidget(_showSecondaryElevation);
|
||||||
|
|
||||||
QGroupBox *elevationBox = new QGroupBox(tr("Elevation"));
|
QGroupBox *elevationBox = new QGroupBox(tr("Elevation"));
|
||||||
elevationBox->setLayout(elevationLayout);
|
elevationBox->setLayout(elevationLayout);
|
||||||
@ -435,13 +479,6 @@ QWidget *OptionsDialog::createDataPage()
|
|||||||
|
|
||||||
QWidget *OptionsDialog::createPOIPage()
|
QWidget *OptionsDialog::createPOIPage()
|
||||||
{
|
{
|
||||||
_poiGPSElevation = new QRadioButton(tr("GPS data"));
|
|
||||||
_poiDEMElevation = new QRadioButton(tr("DEM data"));
|
|
||||||
if (_options->poiUseDEM)
|
|
||||||
_poiDEMElevation->setChecked(true);
|
|
||||||
else
|
|
||||||
_poiGPSElevation->setChecked(true);
|
|
||||||
|
|
||||||
_poiRadius = new QDoubleSpinBox();
|
_poiRadius = new QDoubleSpinBox();
|
||||||
_poiRadius->setSingleStep(1);
|
_poiRadius->setSingleStep(1);
|
||||||
_poiRadius->setDecimals(1);
|
_poiRadius->setDecimals(1);
|
||||||
@ -456,13 +493,8 @@ QWidget *OptionsDialog::createPOIPage()
|
|||||||
_poiRadius->setSuffix(UNIT_SPACE + tr("km"));
|
_poiRadius->setSuffix(UNIT_SPACE + tr("km"));
|
||||||
}
|
}
|
||||||
|
|
||||||
QVBoxLayout *elevationLayout = new QVBoxLayout();
|
|
||||||
elevationLayout->addWidget(_poiGPSElevation);
|
|
||||||
elevationLayout->addWidget(_poiDEMElevation);
|
|
||||||
|
|
||||||
QFormLayout *poiLayout = new QFormLayout();
|
QFormLayout *poiLayout = new QFormLayout();
|
||||||
poiLayout->addRow(tr("Radius:"), _poiRadius);
|
poiLayout->addRow(tr("Radius:"), _poiRadius);
|
||||||
poiLayout->addRow(tr("Elevation:"), elevationLayout);
|
|
||||||
|
|
||||||
QWidget *poiTab = new QWidget();
|
QWidget *poiTab = new QWidget();
|
||||||
poiTab->setLayout(poiLayout);
|
poiTab->setLayout(poiLayout);
|
||||||
@ -679,6 +711,7 @@ void OptionsDialog::accept()
|
|||||||
_options->cadenceFilter = _cadenceFilter->value();
|
_options->cadenceFilter = _cadenceFilter->value();
|
||||||
_options->powerFilter = _powerFilter->value();
|
_options->powerFilter = _powerFilter->value();
|
||||||
_options->outlierEliminate = _outlierEliminate->isChecked();
|
_options->outlierEliminate = _outlierEliminate->isChecked();
|
||||||
|
_options->automaticPause = _automaticPause->isChecked();
|
||||||
qreal pauseSpeed = (_options->units == Imperial)
|
qreal pauseSpeed = (_options->units == Imperial)
|
||||||
? _pauseSpeed->value() / MS2MIH : (_options->units == Nautical)
|
? _pauseSpeed->value() / MS2MIH : (_options->units == Nautical)
|
||||||
? _pauseSpeed->value() / MS2KN : _pauseSpeed->value() / MS2KMH;
|
? _pauseSpeed->value() / MS2KN : _pauseSpeed->value() / MS2KMH;
|
||||||
@ -687,13 +720,14 @@ void OptionsDialog::accept()
|
|||||||
_options->pauseInterval = _pauseInterval->value();
|
_options->pauseInterval = _pauseInterval->value();
|
||||||
_options->useReportedSpeed = _reportedSpeed->isChecked();
|
_options->useReportedSpeed = _reportedSpeed->isChecked();
|
||||||
_options->dataUseDEM = _dataDEMElevation->isChecked();
|
_options->dataUseDEM = _dataDEMElevation->isChecked();
|
||||||
|
_options->showSecondaryElevation = _showSecondaryElevation->isChecked();
|
||||||
|
_options->showSecondarySpeed = _showSecondarySpeed->isChecked();
|
||||||
|
|
||||||
qreal poiRadius = (_options->units == Imperial)
|
qreal poiRadius = (_options->units == Imperial)
|
||||||
? _poiRadius->value() * MIINM : (_options->units == Nautical)
|
? _poiRadius->value() * MIINM : (_options->units == Nautical)
|
||||||
? _poiRadius->value() * NMIINM : _poiRadius->value() * KMINM;
|
? _poiRadius->value() * NMIINM : _poiRadius->value() * KMINM;
|
||||||
if (qAbs(poiRadius - _options->poiRadius) > 0.01)
|
if (qAbs(poiRadius - _options->poiRadius) > 0.01)
|
||||||
_options->poiRadius = poiRadius;
|
_options->poiRadius = poiRadius;
|
||||||
_options->poiUseDEM = _poiDEMElevation->isChecked();
|
|
||||||
|
|
||||||
_options->useOpenGL = _useOpenGL->isChecked();
|
_options->useOpenGL = _useOpenGL->isChecked();
|
||||||
#ifdef ENABLE_HTTP2
|
#ifdef ENABLE_HTTP2
|
||||||
|
@ -49,13 +49,15 @@ struct Options {
|
|||||||
int cadenceFilter;
|
int cadenceFilter;
|
||||||
int powerFilter;
|
int powerFilter;
|
||||||
bool outlierEliminate;
|
bool outlierEliminate;
|
||||||
|
bool automaticPause;
|
||||||
qreal pauseSpeed;
|
qreal pauseSpeed;
|
||||||
int pauseInterval;
|
int pauseInterval;
|
||||||
bool useReportedSpeed;
|
bool useReportedSpeed;
|
||||||
bool dataUseDEM;
|
bool dataUseDEM;
|
||||||
|
bool showSecondaryElevation;
|
||||||
|
bool showSecondarySpeed;
|
||||||
// POI
|
// POI
|
||||||
int poiRadius;
|
int poiRadius;
|
||||||
bool poiUseDEM;
|
|
||||||
// System
|
// System
|
||||||
bool useOpenGL;
|
bool useOpenGL;
|
||||||
#ifdef ENABLE_HTTP2
|
#ifdef ENABLE_HTTP2
|
||||||
@ -86,6 +88,9 @@ public slots:
|
|||||||
public:
|
public:
|
||||||
OptionsDialog(Options *options, QWidget *parent = 0);
|
OptionsDialog(Options *options, QWidget *parent = 0);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void automaticPauseDetectionSet(bool set);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QWidget *createMapPage();
|
QWidget *createMapPage();
|
||||||
QWidget *createAppearancePage();
|
QWidget *createAppearancePage();
|
||||||
@ -129,16 +134,19 @@ private:
|
|||||||
OddSpinBox *_cadenceFilter;
|
OddSpinBox *_cadenceFilter;
|
||||||
OddSpinBox *_powerFilter;
|
OddSpinBox *_powerFilter;
|
||||||
QCheckBox *_outlierEliminate;
|
QCheckBox *_outlierEliminate;
|
||||||
|
|
||||||
|
QRadioButton *_automaticPause;
|
||||||
|
QRadioButton *_manualPause;
|
||||||
QDoubleSpinBox *_pauseSpeed;
|
QDoubleSpinBox *_pauseSpeed;
|
||||||
QSpinBox *_pauseInterval;
|
QSpinBox *_pauseInterval;
|
||||||
QRadioButton *_computedSpeed;
|
QRadioButton *_computedSpeed;
|
||||||
QRadioButton *_reportedSpeed;
|
QRadioButton *_reportedSpeed;
|
||||||
QRadioButton *_dataGPSElevation;
|
QRadioButton *_dataGPSElevation;
|
||||||
QRadioButton *_dataDEMElevation;
|
QRadioButton *_dataDEMElevation;
|
||||||
|
QCheckBox *_showSecondaryElevation;
|
||||||
|
QCheckBox *_showSecondarySpeed;
|
||||||
// POI
|
// POI
|
||||||
QDoubleSpinBox *_poiRadius;
|
QDoubleSpinBox *_poiRadius;
|
||||||
QRadioButton *_poiGPSElevation;
|
|
||||||
QRadioButton *_poiDEMElevation;
|
|
||||||
// System
|
// System
|
||||||
QSpinBox *_pixmapCache;
|
QSpinBox *_pixmapCache;
|
||||||
QSpinBox *_connectionTimeout;
|
QSpinBox *_connectionTimeout;
|
||||||
|
@ -163,3 +163,9 @@ void Popup::show(const QPoint &pos, const QString &text, QWidget *w)
|
|||||||
PopupLabel::_instance->place(pos, w);
|
PopupLabel::_instance->place(pos, w);
|
||||||
PopupLabel::_instance->showNormal();
|
PopupLabel::_instance->showNormal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Popup::clear()
|
||||||
|
{
|
||||||
|
if (PopupLabel::_instance)
|
||||||
|
delete PopupLabel::_instance;
|
||||||
|
}
|
||||||
|
@ -9,6 +9,7 @@ class Popup
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void show(const QPoint &pos, const QString &text, QWidget *w);
|
static void show(const QPoint &pos, const QString &text, QWidget *w);
|
||||||
|
static void clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // POPUP_H
|
#endif // POPUP_H
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
PowerGraphItem::PowerGraphItem(const Graph &graph, GraphType type, int width,
|
PowerGraphItem::PowerGraphItem(const Graph &graph, GraphType type, int width,
|
||||||
const QColor &color, QGraphicsItem *parent)
|
const QColor &color, QGraphicsItem *parent)
|
||||||
: GraphItem(graph, type, width, color, parent)
|
: GraphItem(graph, type, width, color, Qt::SolidLine, parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,8 @@ QString RouteItem::info() const
|
|||||||
tt.insert(tr("Name"), _name);
|
tt.insert(tr("Name"), _name);
|
||||||
if (!_desc.isEmpty())
|
if (!_desc.isEmpty())
|
||||||
tt.insert(tr("Description"), _desc);
|
tt.insert(tr("Description"), _desc);
|
||||||
|
if (!_comment.isEmpty() && _comment != _desc)
|
||||||
|
tt.insert(tr("Comment"), _comment);
|
||||||
tt.insert(tr("Distance"), Format::distance(path().last().last().distance(),
|
tt.insert(tr("Distance"), Format::distance(path().last().last().distance(),
|
||||||
_units));
|
_units));
|
||||||
if (!_links.isEmpty()) {
|
if (!_links.isEmpty()) {
|
||||||
@ -43,6 +45,7 @@ RouteItem::RouteItem(const Route &route, Map *map, QGraphicsItem *parent)
|
|||||||
|
|
||||||
_name = route.name();
|
_name = route.name();
|
||||||
_desc = route.description();
|
_desc = route.description();
|
||||||
|
_comment = route.comment();
|
||||||
_links = route.links();
|
_links = route.links();
|
||||||
_coordinatesFormat = DecimalDegrees;
|
_coordinatesFormat = DecimalDegrees;
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
QString _name;
|
QString _name;
|
||||||
QString _desc;
|
QString _desc;
|
||||||
|
QString _comment;
|
||||||
QVector<Link> _links;
|
QVector<Link> _links;
|
||||||
CoordinatesFormat _coordinatesFormat;
|
CoordinatesFormat _coordinatesFormat;
|
||||||
|
|
||||||
|
@ -135,6 +135,8 @@
|
|||||||
#define POWER_FILTER_DEFAULT 3
|
#define POWER_FILTER_DEFAULT 3
|
||||||
#define OUTLIER_ELIMINATE_SETTING "outlierEliminate"
|
#define OUTLIER_ELIMINATE_SETTING "outlierEliminate"
|
||||||
#define OUTLIER_ELIMINATE_DEFAULT true
|
#define OUTLIER_ELIMINATE_DEFAULT true
|
||||||
|
#define AUTOMATIC_PAUSE_SETTING "automaticPause"
|
||||||
|
#define AUTOMATIC_PAUSE_DEFAULT true
|
||||||
#define PAUSE_SPEED_SETTING "pauseSpeed"
|
#define PAUSE_SPEED_SETTING "pauseSpeed"
|
||||||
#define PAUSE_SPEED_DEFAULT 0.5 /* m/s */
|
#define PAUSE_SPEED_DEFAULT 0.5 /* m/s */
|
||||||
#define PAUSE_INTERVAL_SETTING "pauseInterval"
|
#define PAUSE_INTERVAL_SETTING "pauseInterval"
|
||||||
@ -143,10 +145,12 @@
|
|||||||
#define USE_REPORTED_SPEED_DEFAULT false
|
#define USE_REPORTED_SPEED_DEFAULT false
|
||||||
#define DATA_USE_DEM_SETTING "dataUseDEM"
|
#define DATA_USE_DEM_SETTING "dataUseDEM"
|
||||||
#define DATA_USE_DEM_DEFAULT false
|
#define DATA_USE_DEM_DEFAULT false
|
||||||
|
#define SHOW_SECONDARY_ELEVATION_SETTING "showSecondaryElevation"
|
||||||
|
#define SHOW_SECONDARY_ELEVATION_DEFAULT false
|
||||||
|
#define SHOW_SECONDARY_SPEED_SETTING "showSecondarySpeed"
|
||||||
|
#define SHOW_SECONDARY_SPEED_DEFAULT false
|
||||||
#define POI_RADIUS_SETTING "poiRadius"
|
#define POI_RADIUS_SETTING "poiRadius"
|
||||||
#define POI_RADIUS_DEFAULT (int)(IMPERIAL_UNITS() ? MIINM : KMINM)
|
#define POI_RADIUS_DEFAULT (int)(IMPERIAL_UNITS() ? MIINM : KMINM)
|
||||||
#define POI_USE_DEM_SETTING "poiUseDEM"
|
|
||||||
#define POI_USE_DEM_DEFAULT false
|
|
||||||
#define USE_OPENGL_SETTING "useOpenGL"
|
#define USE_OPENGL_SETTING "useOpenGL"
|
||||||
#define USE_OPENGL_DEFAULT false
|
#define USE_OPENGL_DEFAULT false
|
||||||
#define ENABLE_HTTP2_SETTING "enableHTTP2"
|
#define ENABLE_HTTP2_SETTING "enableHTTP2"
|
||||||
|
@ -40,31 +40,46 @@ void SpeedGraph::setInfo()
|
|||||||
clearInfo();
|
clearInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GraphItem *SpeedGraph::loadGraph(const Graph &graph, const Track &track,
|
||||||
|
const QColor &color, bool primary)
|
||||||
|
{
|
||||||
|
if (!graph.isValid())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
SpeedGraphItem *gi = new SpeedGraphItem(graph, _graphType, _width,
|
||||||
|
color, primary ? Qt::SolidLine : Qt::DashLine, track.movingTime());
|
||||||
|
gi->setTimeType(_timeType);
|
||||||
|
gi->setUnits(_units);
|
||||||
|
|
||||||
|
_tracks.append(gi);
|
||||||
|
if (_showTracks)
|
||||||
|
addGraph(gi);
|
||||||
|
|
||||||
|
if (primary) {
|
||||||
|
_avg.append(QPointF(track.distance(), gi->avg()));
|
||||||
|
_mavg.append(QPointF(track.distance(), gi->mavg()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return gi;
|
||||||
|
}
|
||||||
|
|
||||||
QList<GraphItem*> SpeedGraph::loadData(const Data &data)
|
QList<GraphItem*> SpeedGraph::loadData(const Data &data)
|
||||||
{
|
{
|
||||||
QList<GraphItem*> graphs;
|
QList<GraphItem*> graphs;
|
||||||
|
|
||||||
for (int i = 0; i < data.tracks().count(); i++) {
|
for (int i = 0; i < data.tracks().count(); i++) {
|
||||||
|
GraphItem *primary, *secondary;
|
||||||
|
QColor color(_palette.nextColor());
|
||||||
const Track &track = data.tracks().at(i);
|
const Track &track = data.tracks().at(i);
|
||||||
const Graph &graph = track.speed();
|
const GraphPair &gp = track.speed();
|
||||||
|
|
||||||
if (!graph.isValid()) {
|
primary = loadGraph(gp.primary(), track, color, true);
|
||||||
_palette.nextColor();
|
secondary = primary
|
||||||
graphs.append(0);
|
? loadGraph(gp.secondary(), track, color, false) : 0;
|
||||||
} else {
|
if (primary && secondary)
|
||||||
SpeedGraphItem *gi = new SpeedGraphItem(graph, _graphType, _width,
|
primary->setSecondaryGraph(secondary);
|
||||||
_palette.nextColor(), track.movingTime());
|
|
||||||
gi->setTimeType(_timeType);
|
|
||||||
gi->setUnits(_units);
|
|
||||||
|
|
||||||
_tracks.append(gi);
|
graphs.append(primary);
|
||||||
if (_showTracks)
|
|
||||||
addGraph(gi);
|
|
||||||
|
|
||||||
_avg.append(QPointF(track.distance(), gi->avg()));
|
|
||||||
_mavg.append(QPointF(track.distance(), gi->mavg()));
|
|
||||||
graphs.append(gi);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < data.routes().count(); i++) {
|
for (int i = 0; i < data.routes().count(); i++) {
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "graphtab.h"
|
#include "graphtab.h"
|
||||||
|
|
||||||
class SpeedGraphItem;
|
class SpeedGraphItem;
|
||||||
|
class Track;
|
||||||
|
|
||||||
class SpeedGraph : public GraphTab
|
class SpeedGraph : public GraphTab
|
||||||
{
|
{
|
||||||
@ -22,6 +23,8 @@ public:
|
|||||||
void showTracks(bool show);
|
void showTracks(bool show);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
GraphItem *loadGraph(const Graph &graph, const Track &track,
|
||||||
|
const QColor &color, bool primary);
|
||||||
qreal avg() const;
|
qreal avg() const;
|
||||||
qreal max() const {return bounds().bottom();}
|
qreal max() const {return bounds().bottom();}
|
||||||
void setYUnits();
|
void setYUnits();
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
|
|
||||||
SpeedGraphItem::SpeedGraphItem(const Graph &graph, GraphType type, int width,
|
SpeedGraphItem::SpeedGraphItem(const Graph &graph, GraphType type, int width,
|
||||||
const QColor &color, qreal movingTime, QGraphicsItem *parent)
|
const QColor &color, Qt::PenStyle style, qreal movingTime,
|
||||||
: GraphItem(graph, type, width, color, parent)
|
QGraphicsItem *parent) : GraphItem(graph, type, width, color, style, parent)
|
||||||
{
|
{
|
||||||
_timeType = Total;
|
_timeType = Total;
|
||||||
|
|
||||||
|
@ -10,7 +10,8 @@ class SpeedGraphItem : public GraphItem
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
SpeedGraphItem(const Graph &graph, GraphType type, int width,
|
SpeedGraphItem(const Graph &graph, GraphType type, int width,
|
||||||
const QColor &color, qreal movingTime, QGraphicsItem *parent = 0);
|
const QColor &color, Qt::PenStyle style, qreal movingTime,
|
||||||
|
QGraphicsItem *parent = 0);
|
||||||
|
|
||||||
qreal avg() const {return _avg;}
|
qreal avg() const {return _avg;}
|
||||||
qreal mavg() const {return _mavg;}
|
qreal mavg() const {return _mavg;}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
TemperatureGraphItem::TemperatureGraphItem(const Graph &graph, GraphType type,
|
TemperatureGraphItem::TemperatureGraphItem(const Graph &graph, GraphType type,
|
||||||
int width, const QColor &color, QGraphicsItem *parent)
|
int width, const QColor &color, QGraphicsItem *parent)
|
||||||
: GraphItem(graph, type, width, color, parent)
|
: GraphItem(graph, type, width, color, Qt::SolidLine, parent)
|
||||||
{
|
{
|
||||||
_min = GraphItem::min();
|
_min = GraphItem::min();
|
||||||
_max = GraphItem::max();
|
_max = GraphItem::max();
|
||||||
|
@ -1,10 +1,21 @@
|
|||||||
#include <QImageReader>
|
|
||||||
#include <QLabel>
|
|
||||||
#include "popup.h"
|
#include "popup.h"
|
||||||
#include "tooltip.h"
|
#include "tooltip.h"
|
||||||
|
|
||||||
|
static QSize thumbnailSize(const ImageInfo &img, int limit)
|
||||||
|
{
|
||||||
|
int width, height;
|
||||||
|
if (img.size().width() > img.size().height()) {
|
||||||
|
width = qMin(img.size().width(), limit);
|
||||||
|
qreal ratio = img.size().width() / (qreal)img.size().height();
|
||||||
|
height = (int)(width / ratio);
|
||||||
|
} else {
|
||||||
|
height = qMin(img.size().height(), limit);
|
||||||
|
qreal ratio = img.size().height() / (qreal)img.size().width();
|
||||||
|
width = (int)(height / ratio);
|
||||||
|
}
|
||||||
|
|
||||||
#define THUMBNAIL_MAX_SIZE 240
|
return QSize(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
void ToolTip::insert(const QString &key, const QString &value)
|
void ToolTip::insert(const QString &key, const QString &value)
|
||||||
{
|
{
|
||||||
@ -15,22 +26,17 @@ QString ToolTip::toString() const
|
|||||||
{
|
{
|
||||||
QString html;
|
QString html;
|
||||||
|
|
||||||
if (_img.isValid()) {
|
if (_images.size()) {
|
||||||
int width, height;
|
html = "<div align=\"center\">";
|
||||||
if (_img.size().width() > _img.size().height()) {
|
for (int i = 0; i < _images.size(); i++) {
|
||||||
width = qMin(_img.size().width(), THUMBNAIL_MAX_SIZE);
|
const ImageInfo &img = _images.at(i);
|
||||||
qreal ratio = _img.size().width() / (qreal)_img.size().height();
|
QSize size(thumbnailSize(img, qMin(960/_images.size(), 240)));
|
||||||
height = (int)(width / ratio);
|
|
||||||
} else {
|
|
||||||
height = qMin(_img.size().height(), THUMBNAIL_MAX_SIZE);
|
|
||||||
qreal ratio = _img.size().height() / (qreal)_img.size().width();
|
|
||||||
width = (int)(height / ratio);
|
|
||||||
}
|
|
||||||
|
|
||||||
html += "<div align=\"center\">";
|
html += QString("<a href=\"file:%0\">"
|
||||||
html += QString("<a href=\"file:%0\">"
|
"<img src=\"%0\" width=\"%1\" height=\"%2\"/></a>")
|
||||||
"<img src=\"%0\" width=\"%1\" height=\"%2\"/></a>")
|
.arg(img.path(), QString::number(size.width()),
|
||||||
.arg(_img.path(), QString::number(width), QString::number(height));
|
QString::number(size.height()));
|
||||||
|
}
|
||||||
html += "</div>";
|
html += "</div>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
#include <QVector>
|
||||||
#include "common/kv.h"
|
#include "common/kv.h"
|
||||||
#include "data/imageinfo.h"
|
#include "data/imageinfo.h"
|
||||||
|
|
||||||
@ -10,12 +11,12 @@ class ToolTip
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void insert(const QString &key, const QString &value);
|
void insert(const QString &key, const QString &value);
|
||||||
void setImage(const ImageInfo &image) {_img = image;}
|
void setImages(const QVector<ImageInfo> &images) {_images = images;}
|
||||||
QString toString() const;
|
QString toString() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<KV<QString, QString> > _list;
|
QList<KV<QString, QString> > _list;
|
||||||
ImageInfo _img;
|
QVector<ImageInfo> _images;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TOOLTIP_H
|
#endif // TOOLTIP_H
|
||||||
|
@ -13,6 +13,8 @@ QString TrackItem::info() const
|
|||||||
tt.insert(tr("Name"), _name);
|
tt.insert(tr("Name"), _name);
|
||||||
if (!_desc.isEmpty())
|
if (!_desc.isEmpty())
|
||||||
tt.insert(tr("Description"), _desc);
|
tt.insert(tr("Description"), _desc);
|
||||||
|
if (!_comment.isEmpty() && _comment != _desc)
|
||||||
|
tt.insert(tr("Comment"), _comment);
|
||||||
tt.insert(tr("Distance"), Format::distance(path().last().last().distance(),
|
tt.insert(tr("Distance"), Format::distance(path().last().last().distance(),
|
||||||
_units));
|
_units));
|
||||||
if (_time > 0)
|
if (_time > 0)
|
||||||
@ -41,6 +43,7 @@ TrackItem::TrackItem(const Track &track, Map *map, QGraphicsItem *parent)
|
|||||||
{
|
{
|
||||||
_name = track.name();
|
_name = track.name();
|
||||||
_desc = track.description();
|
_desc = track.description();
|
||||||
|
_comment = track.comment();
|
||||||
_links = track.links();
|
_links = track.links();
|
||||||
_date = track.date();
|
_date = track.date();
|
||||||
_time = track.time();
|
_time = track.time();
|
||||||
|
@ -22,6 +22,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
QString _name;
|
QString _name;
|
||||||
QString _desc;
|
QString _desc;
|
||||||
|
QString _comment;
|
||||||
QVector<Link> _links;
|
QVector<Link> _links;
|
||||||
QDateTime _date;
|
QDateTime _date;
|
||||||
qreal _time;
|
qreal _time;
|
||||||
|
@ -21,15 +21,36 @@ QString WaypointItem::info() const
|
|||||||
tt.insert(qApp->translate("WaypointItem", "Name"), _waypoint.name());
|
tt.insert(qApp->translate("WaypointItem", "Name"), _waypoint.name());
|
||||||
tt.insert(qApp->translate("WaypointItem", "Coordinates"),
|
tt.insert(qApp->translate("WaypointItem", "Coordinates"),
|
||||||
Format::coordinates(_waypoint.coordinates(), _format));
|
Format::coordinates(_waypoint.coordinates(), _format));
|
||||||
if (_waypoint.hasElevation())
|
if (!std::isnan(_waypoint.elevations().first)) {
|
||||||
tt.insert(qApp->translate("WaypointItem", "Elevation"),
|
QString val = Format::elevation(_waypoint.elevations().first, _units);
|
||||||
Format::elevation(_waypoint.elevation(), _units));
|
if (!std::isnan(_waypoint.elevations().second))
|
||||||
|
val += " (" + Format::elevation(_waypoint.elevations().second,
|
||||||
|
_units) + ")";
|
||||||
|
tt.insert(qApp->translate("WaypointItem", "Elevation"), val);
|
||||||
|
}
|
||||||
if (_waypoint.timestamp().isValid())
|
if (_waypoint.timestamp().isValid())
|
||||||
tt.insert(qApp->translate("WaypointItem", "Date"),
|
tt.insert(qApp->translate("WaypointItem", "Date"),
|
||||||
_waypoint.timestamp().toString(Qt::SystemLocaleShortDate));
|
_waypoint.timestamp().toString(Qt::SystemLocaleShortDate));
|
||||||
if (!_waypoint.description().isEmpty())
|
if (!_waypoint.description().isEmpty())
|
||||||
tt.insert(qApp->translate("WaypointItem", "Description"),
|
tt.insert(qApp->translate("WaypointItem", "Description"),
|
||||||
_waypoint.description());
|
_waypoint.description());
|
||||||
|
if (!_waypoint.comment().isEmpty()
|
||||||
|
&& _waypoint.comment() != _waypoint.description())
|
||||||
|
tt.insert(qApp->translate("WaypointItem", "Comment"),
|
||||||
|
_waypoint.comment());
|
||||||
|
if (_waypoint.address().isValid()) {
|
||||||
|
QString addr("<address>");
|
||||||
|
addr += _waypoint.address().street();
|
||||||
|
addr += "<br/>" + _waypoint.address().city();
|
||||||
|
if (!_waypoint.address().postalCode().isEmpty())
|
||||||
|
addr += "<br/>" + _waypoint.address().postalCode();
|
||||||
|
if (!_waypoint.address().state().isEmpty())
|
||||||
|
addr += "<br/>" + _waypoint.address().state();
|
||||||
|
if (!_waypoint.address().country().isEmpty())
|
||||||
|
addr += "<br/>" + _waypoint.address().country();
|
||||||
|
addr += "</address>";
|
||||||
|
tt.insert(qApp->translate("WaypointItem", "Address"), addr);
|
||||||
|
}
|
||||||
if (!_waypoint.links().isEmpty()) {
|
if (!_waypoint.links().isEmpty()) {
|
||||||
QString links;
|
QString links;
|
||||||
for (int i = 0; i < _waypoint.links().size(); i++) {
|
for (int i = 0; i < _waypoint.links().size(); i++) {
|
||||||
@ -41,7 +62,7 @@ QString WaypointItem::info() const
|
|||||||
}
|
}
|
||||||
tt.insert(qApp->translate("WaypointItem", "Links"), links);
|
tt.insert(qApp->translate("WaypointItem", "Links"), links);
|
||||||
}
|
}
|
||||||
tt.setImage(_waypoint.image());
|
tt.setImages(_waypoint.images());
|
||||||
|
|
||||||
return tt.toString();
|
return tt.toString();
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,8 @@ double Coordinates::distanceTo(const Coordinates &c) const
|
|||||||
#ifndef QT_NO_DEBUG
|
#ifndef QT_NO_DEBUG
|
||||||
QDebug operator<<(QDebug dbg, const Coordinates &c)
|
QDebug operator<<(QDebug dbg, const Coordinates &c)
|
||||||
{
|
{
|
||||||
dbg.nospace() << "Coordinates(" << c.lon() << ", " << c.lat() << ")";
|
dbg.nospace() << qSetRealNumberPrecision(10) << "Coordinates(" << c.lon()
|
||||||
|
<< ", " << c.lat() << ")";
|
||||||
return dbg.space();
|
return dbg.space();
|
||||||
}
|
}
|
||||||
#endif // QT_NO_DEBUG
|
#endif // QT_NO_DEBUG
|
||||||
|
18
src/common/garmin.h
Normal file
18
src/common/garmin.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef GARMIN_H
|
||||||
|
#define GARMIN_H
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
#define LS(val, bits) ((qint32)(((quint32)(val))<<(bits)))
|
||||||
|
|
||||||
|
inline double toWGS32(qint32 v)
|
||||||
|
{
|
||||||
|
return ((double)v / (double)(1U<<31)) * 180.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double toWGS24(qint32 v)
|
||||||
|
{
|
||||||
|
return toWGS32(LS(v, 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // GARMIN_H
|
@ -28,6 +28,9 @@ public:
|
|||||||
double left() const {return _tl.lon();}
|
double left() const {return _tl.lon();}
|
||||||
double right() const {return _br.lon();}
|
double right() const {return _br.lon();}
|
||||||
|
|
||||||
|
double width() const {return (right() - left());}
|
||||||
|
double height() const {return (top() - bottom());}
|
||||||
|
|
||||||
void setLeft(double val) {_tl.rlon() = val;}
|
void setLeft(double val) {_tl.rlon() = val;}
|
||||||
void setRight(double val) {_br.rlon() = val;}
|
void setRight(double val) {_br.rlon() = val;}
|
||||||
void setTop(double val) {_tl.rlat() = val;}
|
void setTop(double val) {_tl.rlat() = val;}
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#define TIFF_SHORT 3
|
#define TIFF_SHORT 3
|
||||||
#define TIFF_LONG 4
|
#define TIFF_LONG 4
|
||||||
#define TIFF_RATIONAL 5
|
#define TIFF_RATIONAL 5
|
||||||
|
#define TIFF_SRATIONAL 10
|
||||||
#define TIFF_DOUBLE 12
|
#define TIFF_DOUBLE 12
|
||||||
|
|
||||||
class TIFFFile
|
class TIFFFile
|
||||||
|
35
src/data/address.h
Normal file
35
src/data/address.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#ifndef ADDRESS_H
|
||||||
|
#define ADDRESS_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
class Address
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Address() {}
|
||||||
|
Address(const QString &street, const QString &city)
|
||||||
|
: _street(street), _city(city) {}
|
||||||
|
|
||||||
|
const QString &street() const {return _street;}
|
||||||
|
const QString &city() const {return _city;}
|
||||||
|
const QString &state() const {return _state;}
|
||||||
|
const QString &country() const {return _country;}
|
||||||
|
const QString &postalCode() const {return _postalCode;}
|
||||||
|
|
||||||
|
void setStreet(const QString &street) {_street = street;}
|
||||||
|
void setCity(const QString &city) {_city = city;}
|
||||||
|
void setState(const QString &state) {_state = state;}
|
||||||
|
void setCountry(const QString &country) {_country = country;}
|
||||||
|
void setPostalCode(const QString &postalCode) {_postalCode = postalCode;}
|
||||||
|
|
||||||
|
bool isValid() const {return !(_street.isEmpty() || _city.isEmpty());}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString _street;
|
||||||
|
QString _city;
|
||||||
|
QString _state;
|
||||||
|
QString _country;
|
||||||
|
QString _postalCode;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ADDRESS_H
|
@ -19,7 +19,7 @@
|
|||||||
#include "exifparser.h"
|
#include "exifparser.h"
|
||||||
#include "cupparser.h"
|
#include "cupparser.h"
|
||||||
#include "gpiparser.h"
|
#include "gpiparser.h"
|
||||||
#include "dem.h"
|
#include "smlparser.h"
|
||||||
#include "data.h"
|
#include "data.h"
|
||||||
|
|
||||||
|
|
||||||
@ -41,78 +41,48 @@ static GeoJSONParser geojson;
|
|||||||
static EXIFParser exif;
|
static EXIFParser exif;
|
||||||
static CUPParser cup;
|
static CUPParser cup;
|
||||||
static GPIParser gpi;
|
static GPIParser gpi;
|
||||||
|
static SMLParser sml;
|
||||||
|
|
||||||
static QHash<QString, Parser*> parsers()
|
static QMap<QString, Parser*> parsers()
|
||||||
{
|
{
|
||||||
QHash<QString, Parser*> hash;
|
QMap<QString, Parser*> map;
|
||||||
|
|
||||||
hash.insert("gpx", &gpx);
|
map.insert("gpx", &gpx);
|
||||||
hash.insert("tcx", &tcx);
|
map.insert("tcx", &tcx);
|
||||||
hash.insert("kml", &kml);
|
map.insert("kml", &kml);
|
||||||
hash.insert("fit", &fit);
|
map.insert("fit", &fit);
|
||||||
hash.insert("csv", &csv);
|
map.insert("csv", &csv);
|
||||||
hash.insert("igc", &igc);
|
map.insert("igc", &igc);
|
||||||
hash.insert("nmea", &nmea);
|
map.insert("nmea", &nmea);
|
||||||
hash.insert("plt", &plt);
|
map.insert("plt", &plt);
|
||||||
hash.insert("wpt", &wpt);
|
map.insert("wpt", &wpt);
|
||||||
hash.insert("rte", &rte);
|
map.insert("rte", &rte);
|
||||||
hash.insert("loc", &loc);
|
map.insert("loc", &loc);
|
||||||
hash.insert("slf", &slf);
|
map.insert("slf", &slf);
|
||||||
#ifdef ENABLE_GEOJSON
|
#ifdef ENABLE_GEOJSON
|
||||||
hash.insert("json", &geojson);
|
map.insert("json", &geojson);
|
||||||
hash.insert("geojson", &geojson);
|
map.insert("geojson", &geojson);
|
||||||
#endif // ENABLE_GEOJSON
|
#endif // ENABLE_GEOJSON
|
||||||
hash.insert("jpeg", &exif);
|
map.insert("jpeg", &exif);
|
||||||
hash.insert("jpg", &exif);
|
map.insert("jpg", &exif);
|
||||||
hash.insert("cup", &cup);
|
map.insert("cup", &cup);
|
||||||
hash.insert("gpi", &gpi);
|
map.insert("gpi", &gpi);
|
||||||
|
map.insert("sml", &sml);
|
||||||
|
|
||||||
return hash;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QMap<QString, Parser*> Data::_parsers = parsers();
|
||||||
QHash<QString, Parser*> Data::_parsers = parsers();
|
|
||||||
bool Data::_useDEM = false;
|
|
||||||
|
|
||||||
void Data::processData(QList<TrackData> &trackData, QList<RouteData> &routeData)
|
void Data::processData(QList<TrackData> &trackData, QList<RouteData> &routeData)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < trackData.count(); i++) {
|
for (int i = 0; i < trackData.count(); i++)
|
||||||
TrackData &track = trackData[i];
|
|
||||||
for (int j = 0; j < track.size(); j++) {
|
|
||||||
SegmentData &segment = track[j];
|
|
||||||
for (int k = 0; k < segment.size(); k++) {
|
|
||||||
Trackpoint &t = segment[k];
|
|
||||||
if (!t.hasElevation() || _useDEM) {
|
|
||||||
qreal elevation = DEM::elevation(t.coordinates());
|
|
||||||
if (!std::isnan(elevation))
|
|
||||||
t.setElevation(elevation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_tracks.append(Track(trackData.at(i)));
|
_tracks.append(Track(trackData.at(i)));
|
||||||
}
|
for (int i = 0; i < routeData.count(); i++)
|
||||||
for (int i = 0; i < routeData.count(); i++) {
|
|
||||||
RouteData &route = routeData[i];
|
|
||||||
for (int j = 0; j < route.size(); j++) {
|
|
||||||
Waypoint &w = route[j];
|
|
||||||
if (!w.hasElevation() || _useDEM) {
|
|
||||||
qreal elevation = DEM::elevation(w.coordinates());
|
|
||||||
if (!std::isnan(elevation))
|
|
||||||
w.setElevation(elevation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_routes.append(Route(routeData.at(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());
|
|
||||||
if (!std::isnan(elevation))
|
|
||||||
_waypoints[i].setElevation(elevation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Data::Data(const QString &fileName, bool poi)
|
Data::Data(const QString &fileName)
|
||||||
{
|
{
|
||||||
QFile file(fileName);
|
QFile file(fileName);
|
||||||
QFileInfo fi(fileName);
|
QFileInfo fi(fileName);
|
||||||
@ -127,12 +97,11 @@ Data::Data(const QString &fileName, bool poi)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<QString, Parser*>::iterator it;
|
QMap<QString, Parser*>::iterator it;
|
||||||
if ((it = _parsers.find(fi.suffix().toLower())) != _parsers.end()) {
|
if ((it = _parsers.find(fi.suffix().toLower())) != _parsers.end()) {
|
||||||
if (it.value()->parse(&file, trackData, routeData, _polygons,
|
if (it.value()->parse(&file, trackData, routeData, _polygons,
|
||||||
_waypoints)) {
|
_waypoints)) {
|
||||||
if (!poi)
|
processData(trackData, routeData);
|
||||||
processData(trackData, routeData);
|
|
||||||
_valid = true;
|
_valid = true;
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
@ -143,8 +112,7 @@ Data::Data(const QString &fileName, bool poi)
|
|||||||
for (it = _parsers.begin(); it != _parsers.end(); it++) {
|
for (it = _parsers.begin(); it != _parsers.end(); it++) {
|
||||||
if (it.value()->parse(&file, trackData, routeData, _polygons,
|
if (it.value()->parse(&file, trackData, routeData, _polygons,
|
||||||
_waypoints)) {
|
_waypoints)) {
|
||||||
if (!poi)
|
processData(trackData, routeData);
|
||||||
processData(trackData, routeData);
|
|
||||||
_valid = true;
|
_valid = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -163,17 +131,8 @@ Data::Data(const QString &fileName, bool poi)
|
|||||||
|
|
||||||
QString Data::formats()
|
QString Data::formats()
|
||||||
{
|
{
|
||||||
QStringList l(filter());
|
|
||||||
qSort(l);
|
|
||||||
QString supported;
|
|
||||||
for (int i = 0; i < l.size(); i++) {
|
|
||||||
supported += l.at(i);
|
|
||||||
if (i != l.size() - 1)
|
|
||||||
supported += " ";
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
qApp->translate("Data", "Supported files") + " (" + supported + ");;"
|
qApp->translate("Data", "Supported files") + " (" + filter().join(" ") + ");;"
|
||||||
+ qApp->translate("Data", "CSV files") + " (*.csv);;"
|
+ qApp->translate("Data", "CSV files") + " (*.csv);;"
|
||||||
+ qApp->translate("Data", "CUP files") + " (*.cup);;"
|
+ qApp->translate("Data", "CUP files") + " (*.cup);;"
|
||||||
+ qApp->translate("Data", "FIT files") + " (*.fit);;"
|
+ qApp->translate("Data", "FIT files") + " (*.fit);;"
|
||||||
@ -189,6 +148,7 @@ QString Data::formats()
|
|||||||
+ qApp->translate("Data", "NMEA files") + " (*.nmea);;"
|
+ qApp->translate("Data", "NMEA files") + " (*.nmea);;"
|
||||||
+ qApp->translate("Data", "OziExplorer files") + " (*.plt *.rte *.wpt);;"
|
+ qApp->translate("Data", "OziExplorer files") + " (*.plt *.rte *.wpt);;"
|
||||||
+ qApp->translate("Data", "SLF files") + " (*.slf);;"
|
+ qApp->translate("Data", "SLF files") + " (*.slf);;"
|
||||||
|
+ qApp->translate("Data", "SML files") + " (*.sml);;"
|
||||||
+ qApp->translate("Data", "TCX files") + " (*.tcx);;"
|
+ qApp->translate("Data", "TCX files") + " (*.tcx);;"
|
||||||
+ qApp->translate("Data", "All files") + " (*)";
|
+ qApp->translate("Data", "All files") + " (*)";
|
||||||
}
|
}
|
||||||
@ -196,15 +156,10 @@ QString Data::formats()
|
|||||||
QStringList Data::filter()
|
QStringList Data::filter()
|
||||||
{
|
{
|
||||||
QStringList filter;
|
QStringList filter;
|
||||||
QHash<QString, Parser*>::iterator it;
|
|
||||||
|
|
||||||
for (it = _parsers.begin(); it != _parsers.end(); it++)
|
for (QMap<QString, Parser*>::iterator it = _parsers.begin();
|
||||||
filter << QString("*.%1").arg(it.key());
|
it != _parsers.end(); it++)
|
||||||
|
filter << "*." + it.key();
|
||||||
|
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Data::useDEM(bool use)
|
|
||||||
{
|
|
||||||
_useDEM = use;
|
|
||||||
}
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#define DATA_H
|
#define DATA_H
|
||||||
|
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QHash>
|
#include <QMap>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include "waypoint.h"
|
#include "waypoint.h"
|
||||||
@ -14,7 +14,7 @@
|
|||||||
class Data
|
class Data
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Data(const QString &fileName, bool poi = false);
|
Data(const QString &fileName);
|
||||||
|
|
||||||
bool isValid() const {return _valid;}
|
bool isValid() const {return _valid;}
|
||||||
const QString &errorString() const {return _errorString;}
|
const QString &errorString() const {return _errorString;}
|
||||||
@ -28,8 +28,6 @@ public:
|
|||||||
static QString formats();
|
static QString formats();
|
||||||
static QStringList filter();
|
static QStringList filter();
|
||||||
|
|
||||||
static void useDEM(bool use);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void processData(QList<TrackData> &trackData, QList<RouteData> &routeData);
|
void processData(QList<TrackData> &trackData, QList<RouteData> &routeData);
|
||||||
|
|
||||||
@ -42,8 +40,7 @@ private:
|
|||||||
QList<Area> _polygons;
|
QList<Area> _polygons;
|
||||||
QVector<Waypoint> _waypoints;
|
QVector<Waypoint> _waypoints;
|
||||||
|
|
||||||
static QHash<QString, Parser*> _parsers;
|
static QMap<QString, Parser*> _parsers;
|
||||||
static bool _useDEM;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DATA_H
|
#endif // DATA_H
|
||||||
|
@ -82,7 +82,10 @@ double EXIFParser::altitude(TIFFFile &file, const IFDEntry &alt,
|
|||||||
|
|
||||||
double EXIFParser::coordinate(TIFFFile &file, const IFDEntry &ll) const
|
double EXIFParser::coordinate(TIFFFile &file, const IFDEntry &ll) const
|
||||||
{
|
{
|
||||||
if (!(ll.type == TIFF_RATIONAL && ll.count == 3))
|
// Some broken image creators like NOKIA phones use a wrong (SRATIONAL)
|
||||||
|
// data type
|
||||||
|
if (!((ll.type == TIFF_RATIONAL || ll.type == TIFF_SRATIONAL)
|
||||||
|
&& ll.count == 3))
|
||||||
return NAN;
|
return NAN;
|
||||||
|
|
||||||
if (!file.seek(ll.offset))
|
if (!file.seek(ll.offset))
|
||||||
@ -209,7 +212,7 @@ bool EXIFParser::parseTIFF(QFile *file, QVector<Waypoint> &waypoints)
|
|||||||
|
|
||||||
Waypoint wp(c);
|
Waypoint wp(c);
|
||||||
wp.setName(QFileInfo(file->fileName()).baseName());
|
wp.setName(QFileInfo(file->fileName()).baseName());
|
||||||
wp.setImage(img);
|
wp.addImage(img);
|
||||||
wp.setElevation(altitude(tiff, GPSIFD.value(GPSAltitude),
|
wp.setElevation(altitude(tiff, GPSIFD.value(GPSAltitude),
|
||||||
GPSIFD.value(GPSAltitudeRef)));
|
GPSIFD.value(GPSAltitudeRef)));
|
||||||
wp.setTimestamp(QDateTime(QDate::fromString(text(tiff,
|
wp.setTimestamp(QDateTime(QDate::fromString(text(tiff,
|
||||||
|
@ -1,8 +1,17 @@
|
|||||||
|
#include <cstring>
|
||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
#include <QTextCodec>
|
#include <QTextCodec>
|
||||||
#include <QtEndian>
|
#include <QtEndian>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
#include <QIODevice>
|
||||||
|
#include <QApplication>
|
||||||
#include <QBuffer>
|
#include <QBuffer>
|
||||||
|
#include <QImageReader>
|
||||||
|
#include <QCryptographicHash>
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||||
|
#include <QTemporaryDir>
|
||||||
|
#endif // QT_VERSION >= 5
|
||||||
|
#include "common/garmin.h"
|
||||||
#include "gpiparser.h"
|
#include "gpiparser.h"
|
||||||
|
|
||||||
|
|
||||||
@ -27,10 +36,25 @@ private:
|
|||||||
QString _str;
|
QString _str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CryptDevice : public QIODevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CryptDevice(QIODevice *device, quint32 key, quint32 blockSize,
|
||||||
|
QObject *parent = 0);
|
||||||
|
bool isSequential() const {return true;}
|
||||||
|
|
||||||
#define BLOCK_KEY 0xf870b5
|
protected:
|
||||||
|
qint64 readData(char *data, qint64 maxSize);
|
||||||
|
qint64 writeData(const char *, qint64) {return -1;}
|
||||||
|
|
||||||
void demangle(quint8 *data, quint32 size, quint32 key)
|
private:
|
||||||
|
QIODevice *_device;
|
||||||
|
quint32 _key;
|
||||||
|
QByteArray _block;
|
||||||
|
int _available;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void demangle(quint8 *data, quint32 size, quint32 key)
|
||||||
{
|
{
|
||||||
static const unsigned char shuf[] = {
|
static const unsigned char shuf[] = {
|
||||||
0xb, 0xc, 0xa, 0x0,
|
0xb, 0xc, 0xa, 0x0,
|
||||||
@ -40,29 +64,77 @@ void demangle(quint8 *data, quint32 size, quint32 key)
|
|||||||
};
|
};
|
||||||
|
|
||||||
int hiCnt = 0, loCnt;
|
int hiCnt = 0, loCnt;
|
||||||
quint8 sum = shuf[(key >> 0x10) + key + (key >> 0x18) + (key >> 8) & 0xf];
|
quint8 sum = shuf[((key >> 24) + (key >> 16) + (key >> 8) + key) & 0xf];
|
||||||
|
|
||||||
for (quint32 i = 0; i < size; i++) {
|
for (quint32 i = 0; i < size; i++) {
|
||||||
quint8 hiAdd = shuf[key >> (hiCnt << 2) & 0xf] + sum;
|
quint8 hiAdd = shuf[key >> (hiCnt << 2) & 0xf] + sum;
|
||||||
loCnt = (hiCnt > 6) ? 0 : hiCnt + 1;
|
loCnt = (hiCnt > 6) ? 0 : hiCnt + 1;
|
||||||
quint8 loAdd = shuf[key >> (loCnt << 2) & 0xf] + sum;
|
quint8 loAdd = shuf[key >> (loCnt << 2) & 0xf] + sum;
|
||||||
quint8 hi = data[i] + hiAdd * 0xf0;
|
quint8 hi = data[i] - (hiAdd << 4);
|
||||||
quint8 lo = data[i] - loAdd;
|
quint8 lo = data[i] - loAdd;
|
||||||
data[i] = (hi & 0xf0) | (lo & 0x0f);
|
data[i] = (hi & 0xf0) | (lo & 0x0f);
|
||||||
hiCnt = (loCnt > 6) ? 0 : loCnt + 1;
|
hiCnt = (loCnt > 6) ? 0 : loCnt + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline double toWGS(qint32 v)
|
CryptDevice::CryptDevice(QIODevice *device, quint32 key, quint32 blockSize,
|
||||||
|
QObject *parent) : QIODevice(parent), _device(device), _key(key), _available(0)
|
||||||
{
|
{
|
||||||
return (double)(((double)v / (double)(1U<<31)) * (double)180);
|
_block.resize(blockSize);
|
||||||
|
setOpenMode(_device->openMode());
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 CryptDevice::readData(char *data, qint64 maxSize)
|
||||||
|
{
|
||||||
|
qint64 rs, ts = 0;
|
||||||
|
int cs;
|
||||||
|
|
||||||
|
if (_available) {
|
||||||
|
cs = qMin(maxSize, (qint64)_available);
|
||||||
|
memcpy(data, _block.constData() + _block.size() - _available, cs);
|
||||||
|
_available -= cs;
|
||||||
|
maxSize -= cs;
|
||||||
|
ts = cs;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (maxSize) {
|
||||||
|
if ((rs = _device->read(_block.data(), _block.size())) < 0)
|
||||||
|
return -1;
|
||||||
|
else if (!rs)
|
||||||
|
break;
|
||||||
|
_available = rs;
|
||||||
|
demangle((quint8*)_block.data(), _available, _key);
|
||||||
|
cs = qMin(maxSize, (qint64)_available);
|
||||||
|
memcpy(data + ts, _block.constData(), cs);
|
||||||
|
_available -= cs;
|
||||||
|
maxSize -= cs;
|
||||||
|
ts += cs;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ts;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static qint32 readInt24(QDataStream &stream)
|
||||||
|
{
|
||||||
|
unsigned char data[3];
|
||||||
|
quint32 val;
|
||||||
|
|
||||||
|
stream.readRawData((char*)data, sizeof(data));
|
||||||
|
val = data[0] | ((quint32)data[1]) << 8 | ((quint32)data[2]) << 16;
|
||||||
|
return (val > 0x7FFFFF) ? (val & 0x7FFFFF) - 0x800000 : val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static quint16 nextHeaderType(QDataStream &stream)
|
static quint16 nextHeaderType(QDataStream &stream)
|
||||||
{
|
{
|
||||||
quint16 type = 0;
|
quint16 type = 0;
|
||||||
stream.device()->peek((char*)&type, sizeof(type));
|
|
||||||
return qFromLittleEndian(type);
|
if (stream.device()->peek((char*)&type, sizeof(type))
|
||||||
|
< (qint64)sizeof(type)) {
|
||||||
|
stream.setStatus(QDataStream::ReadCorruptData);
|
||||||
|
return 0xFFFF;
|
||||||
|
} else
|
||||||
|
return qFromLittleEndian(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
static quint8 readRecordHeader(QDataStream &stream, RecordHeader &hdr)
|
static quint8 readRecordHeader(QDataStream &stream, RecordHeader &hdr)
|
||||||
@ -82,18 +154,6 @@ static quint32 skipRecord(QDataStream &stream)
|
|||||||
return rs + rh.size;
|
return rs + rh.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static quint32 readFprsRecord(QDataStream &stream)
|
|
||||||
{
|
|
||||||
RecordHeader rh;
|
|
||||||
quint16 s1;
|
|
||||||
quint8 rs, s2, s3, s4;
|
|
||||||
|
|
||||||
rs = readRecordHeader(stream, rh);
|
|
||||||
stream >> s1 >> s2 >> s3 >> s4;
|
|
||||||
|
|
||||||
return rs + 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
static quint16 readString(QDataStream &stream, QTextCodec *codec, QString &str)
|
static quint16 readString(QDataStream &stream, QTextCodec *codec, QString &str)
|
||||||
{
|
{
|
||||||
quint16 len;
|
quint16 len;
|
||||||
@ -110,15 +170,16 @@ static quint32 readTranslatedObjects(QDataStream &stream, QTextCodec *codec,
|
|||||||
QList<TranslatedString> &objects)
|
QList<TranslatedString> &objects)
|
||||||
{
|
{
|
||||||
qint32 size = 0, ret;
|
qint32 size = 0, ret;
|
||||||
char lang[2];
|
char lang[3];
|
||||||
|
|
||||||
|
memset(lang, 0, sizeof(lang));
|
||||||
objects.clear();
|
objects.clear();
|
||||||
|
|
||||||
stream >> size;
|
stream >> size;
|
||||||
ret = size + 4;
|
ret = size + 4;
|
||||||
while (size > 0) {
|
while (stream.status() == QDataStream::Ok && size > 0) {
|
||||||
QString str;
|
QString str;
|
||||||
stream.readRawData(lang, sizeof(lang));
|
stream.readRawData(lang, sizeof(lang) - 1);
|
||||||
size -= readString(stream, codec, str) + 2;
|
size -= readString(stream, codec, str) + 2;
|
||||||
objects.append(TranslatedString(lang, str));
|
objects.append(TranslatedString(lang, str));
|
||||||
}
|
}
|
||||||
@ -129,163 +190,16 @@ static quint32 readTranslatedObjects(QDataStream &stream, QTextCodec *codec,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static quint32 readDescription(QDataStream &stream, QTextCodec *codec,
|
static quint32 readFprsRecord(QDataStream &stream)
|
||||||
Waypoint &waypoint)
|
|
||||||
{
|
{
|
||||||
RecordHeader rh;
|
RecordHeader rh;
|
||||||
quint8 rs;
|
|
||||||
quint32 ds;
|
|
||||||
QList<TranslatedString> obj;
|
|
||||||
|
|
||||||
rs = readRecordHeader(stream, rh);
|
|
||||||
ds = readTranslatedObjects(stream, codec, obj);
|
|
||||||
if (!obj.isEmpty())
|
|
||||||
waypoint.setDescription(obj.first().str());
|
|
||||||
|
|
||||||
if (ds != rh.size)
|
|
||||||
stream.setStatus(QDataStream::ReadCorruptData);
|
|
||||||
|
|
||||||
return rs + rh.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static quint32 readNotes(QDataStream &stream, QTextCodec *codec,
|
|
||||||
Waypoint &waypoint)
|
|
||||||
{
|
|
||||||
RecordHeader rh;
|
|
||||||
quint8 rs, s1;
|
|
||||||
quint32 ds = 1;
|
|
||||||
|
|
||||||
rs = readRecordHeader(stream, rh);
|
|
||||||
stream >> s1;
|
|
||||||
if (s1 & 0x1) {
|
|
||||||
QList<TranslatedString> obj;
|
|
||||||
ds += readTranslatedObjects(stream, codec, obj);
|
|
||||||
if (!obj.isEmpty() && waypoint.description().isNull())
|
|
||||||
waypoint.setDescription(obj.first().str());
|
|
||||||
}
|
|
||||||
if (s1 & 0x2) {
|
|
||||||
QString str;
|
|
||||||
ds += readString(stream, codec, str);
|
|
||||||
if (!str.isEmpty() && waypoint.description().isNull())
|
|
||||||
waypoint.setDescription(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ds != rh.size)
|
|
||||||
stream.setStatus(QDataStream::ReadCorruptData);
|
|
||||||
|
|
||||||
return rs + rh.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static quint32 readContact(QDataStream &stream, QTextCodec *codec,
|
|
||||||
Waypoint &waypoint)
|
|
||||||
{
|
|
||||||
RecordHeader rh;
|
|
||||||
quint8 rs;
|
|
||||||
quint16 s1;
|
quint16 s1;
|
||||||
quint32 ds = 2;
|
quint8 rs, s2, s3, s4;
|
||||||
QString str;
|
|
||||||
QList<TranslatedString> obj;
|
|
||||||
|
|
||||||
rs = readRecordHeader(stream, rh);
|
rs = readRecordHeader(stream, rh);
|
||||||
stream >> s1;
|
stream >> s1 >> s2 >> s3 >> s4;
|
||||||
|
|
||||||
if (s1 & 0x1) // phone
|
return rs + 5;
|
||||||
ds += readString(stream, codec, str);
|
|
||||||
if (s1 & 0x2) // phone2
|
|
||||||
ds += readString(stream, codec, str);
|
|
||||||
if (s1 & 0x4) // fax
|
|
||||||
ds += readString(stream, codec, str);
|
|
||||||
if (s1 & 0x8) // mail
|
|
||||||
ds += readString(stream, codec, str);
|
|
||||||
if (s1 & 0x10) { // web
|
|
||||||
ds += readString(stream, codec, str);
|
|
||||||
QUrl url(str);
|
|
||||||
waypoint.addLink(Link(url.scheme().isEmpty()
|
|
||||||
? "http://" + str : str, str));
|
|
||||||
}
|
|
||||||
if (s1 & 0x20) // unknown
|
|
||||||
ds += readTranslatedObjects(stream, codec, obj);
|
|
||||||
|
|
||||||
if (ds != rh.size)
|
|
||||||
stream.setStatus(QDataStream::ReadCorruptData);
|
|
||||||
|
|
||||||
return rs + rh.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static quint32 readPOI(QDataStream &stream, QTextCodec *codec,
|
|
||||||
QVector<Waypoint> &waypoints)
|
|
||||||
{
|
|
||||||
RecordHeader rh;
|
|
||||||
quint8 rs;
|
|
||||||
quint32 ds;
|
|
||||||
qint32 s1, s2;
|
|
||||||
quint16 s3;
|
|
||||||
QList<TranslatedString> obj;
|
|
||||||
|
|
||||||
rs = readRecordHeader(stream, rh);
|
|
||||||
stream >> s1 >> s2 >> s3;
|
|
||||||
stream.skipRawData(s3);
|
|
||||||
ds = 10 + s3;
|
|
||||||
ds += readTranslatedObjects(stream, codec, obj);
|
|
||||||
|
|
||||||
waypoints.append(Waypoint(Coordinates(toWGS(s2), toWGS(s1))));
|
|
||||||
if (!obj.isEmpty())
|
|
||||||
waypoints.last().setName(obj.first().str());
|
|
||||||
|
|
||||||
while (ds < rh.size) {
|
|
||||||
switch(nextHeaderType(stream)) {
|
|
||||||
case 10:
|
|
||||||
ds += readDescription(stream, codec, waypoints.last());
|
|
||||||
break;
|
|
||||||
case 12:
|
|
||||||
ds += readContact(stream, codec, waypoints.last());
|
|
||||||
break;
|
|
||||||
case 14:
|
|
||||||
ds += readNotes(stream, codec, waypoints.last());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ds += skipRecord(stream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ds != rh.size)
|
|
||||||
stream.setStatus(QDataStream::ReadCorruptData);
|
|
||||||
|
|
||||||
return rs + rh.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static quint32 readSpatialIndex(QDataStream &stream, QTextCodec *codec,
|
|
||||||
QVector<Waypoint> &waypoints)
|
|
||||||
{
|
|
||||||
RecordHeader rh;
|
|
||||||
quint32 ds, s5;
|
|
||||||
qint32 top, right, bottom, left;
|
|
||||||
quint16 s6;
|
|
||||||
quint8 rs;
|
|
||||||
|
|
||||||
rs = readRecordHeader(stream, rh);
|
|
||||||
stream >> top >> right >> bottom >> left >> s5 >> s6;
|
|
||||||
stream.skipRawData(s6);
|
|
||||||
ds = 22 + s6;
|
|
||||||
if (rh.flags & 0x8) {
|
|
||||||
while (ds < rh.size) {
|
|
||||||
switch(nextHeaderType(stream)) {
|
|
||||||
case 2:
|
|
||||||
ds += readPOI(stream, codec, waypoints);
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
ds += readSpatialIndex(stream, codec, waypoints);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ds += skipRecord(stream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ds != rh.size)
|
|
||||||
stream.setStatus(QDataStream::ReadCorruptData);
|
|
||||||
|
|
||||||
return rs + rh.size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static quint32 readFileDataRecord(QDataStream &stream, QTextCodec *codec)
|
static quint32 readFileDataRecord(QDataStream &stream, QTextCodec *codec)
|
||||||
@ -326,6 +240,29 @@ static quint32 readFileDataRecord(QDataStream &stream, QTextCodec *codec)
|
|||||||
stream.skipRawData(ss1);
|
stream.skipRawData(ss1);
|
||||||
ds += ss1 + 2;
|
ds += ss1 + 2;
|
||||||
}
|
}
|
||||||
|
// structure of higher fields not known
|
||||||
|
|
||||||
|
if (ds > rh.size)
|
||||||
|
stream.setStatus(QDataStream::ReadCorruptData);
|
||||||
|
else if (ds < rh.size)
|
||||||
|
// skip remaining unknown fields
|
||||||
|
stream.skipRawData(rh.size - ds);
|
||||||
|
|
||||||
|
return rs + rh.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static quint32 readDescription(QDataStream &stream, QTextCodec *codec,
|
||||||
|
Waypoint &waypoint)
|
||||||
|
{
|
||||||
|
RecordHeader rh;
|
||||||
|
quint8 rs;
|
||||||
|
quint32 ds;
|
||||||
|
QList<TranslatedString> obj;
|
||||||
|
|
||||||
|
rs = readRecordHeader(stream, rh);
|
||||||
|
ds = readTranslatedObjects(stream, codec, obj);
|
||||||
|
if (!obj.isEmpty())
|
||||||
|
waypoint.setDescription(obj.first().str());
|
||||||
|
|
||||||
if (ds != rh.size)
|
if (ds != rh.size)
|
||||||
stream.setStatus(QDataStream::ReadCorruptData);
|
stream.setStatus(QDataStream::ReadCorruptData);
|
||||||
@ -333,33 +270,397 @@ static quint32 readFileDataRecord(QDataStream &stream, QTextCodec *codec)
|
|||||||
return rs + rh.size;
|
return rs + rh.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GPIParser::readFileHeader(QDataStream &stream, quint32 &ebs)
|
static quint32 readNotes(QDataStream &stream, QTextCodec *codec,
|
||||||
|
Waypoint &waypoint)
|
||||||
{
|
{
|
||||||
RecordHeader rh;
|
RecordHeader rh;
|
||||||
quint32 ds, s7;
|
quint8 rs, s1;
|
||||||
quint16 s10;
|
quint32 ds = 1;
|
||||||
quint8 s5, s6, s8, s9;
|
|
||||||
char magic[6];
|
rs = readRecordHeader(stream, rh);
|
||||||
|
stream >> s1;
|
||||||
|
if (s1 & 0x1) {
|
||||||
|
QList<TranslatedString> obj;
|
||||||
|
ds += readTranslatedObjects(stream, codec, obj);
|
||||||
|
if (!obj.isEmpty())
|
||||||
|
waypoint.setComment(obj.first().str());
|
||||||
|
}
|
||||||
|
if (s1 & 0x2) {
|
||||||
|
QString str;
|
||||||
|
ds += readString(stream, codec, str);
|
||||||
|
if (!str.isEmpty())
|
||||||
|
waypoint.setComment(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ds != rh.size)
|
||||||
|
stream.setStatus(QDataStream::ReadCorruptData);
|
||||||
|
|
||||||
|
return rs + rh.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static quint32 readContact(QDataStream &stream, QTextCodec *codec,
|
||||||
|
Waypoint &waypoint)
|
||||||
|
{
|
||||||
|
RecordHeader rh;
|
||||||
|
quint8 rs;
|
||||||
|
quint16 flags;
|
||||||
|
quint32 ds = 2;
|
||||||
|
QString str;
|
||||||
|
QList<TranslatedString> obj;
|
||||||
|
|
||||||
|
rs = readRecordHeader(stream, rh);
|
||||||
|
stream >> flags;
|
||||||
|
|
||||||
|
if (flags & 0x1) // phone
|
||||||
|
ds += readString(stream, codec, str);
|
||||||
|
if (flags & 0x2) // phone2
|
||||||
|
ds += readString(stream, codec, str);
|
||||||
|
if (flags & 0x4) // fax
|
||||||
|
ds += readString(stream, codec, str);
|
||||||
|
if (flags & 0x8) // mail
|
||||||
|
ds += readString(stream, codec, str);
|
||||||
|
if (flags & 0x10) { // web
|
||||||
|
ds += readString(stream, codec, str);
|
||||||
|
QUrl url(str);
|
||||||
|
waypoint.addLink(Link(url.scheme().isEmpty()
|
||||||
|
? "http://" + str : str, str));
|
||||||
|
}
|
||||||
|
if (flags & 0x20) // unknown
|
||||||
|
ds += readTranslatedObjects(stream, codec, obj);
|
||||||
|
|
||||||
|
if (ds != rh.size)
|
||||||
|
stream.setStatus(QDataStream::ReadCorruptData);
|
||||||
|
|
||||||
|
return rs + rh.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static quint32 readAddress(QDataStream &stream, QTextCodec *codec,
|
||||||
|
Waypoint &waypoint)
|
||||||
|
{
|
||||||
|
RecordHeader rh;
|
||||||
|
quint8 rs;
|
||||||
|
quint16 flags;
|
||||||
|
quint32 ds = 2;
|
||||||
|
QList<TranslatedString> obj;
|
||||||
|
QString str;
|
||||||
|
Address addr;
|
||||||
|
|
||||||
|
rs = readRecordHeader(stream, rh);
|
||||||
|
stream >> flags;
|
||||||
|
|
||||||
|
if (flags & 0x1) {
|
||||||
|
ds += readTranslatedObjects(stream, codec, obj);
|
||||||
|
if (!obj.isEmpty())
|
||||||
|
addr.setCity(obj.first().str());
|
||||||
|
}
|
||||||
|
if (flags & 0x2) {
|
||||||
|
ds += readTranslatedObjects(stream, codec, obj);
|
||||||
|
if (!obj.isEmpty())
|
||||||
|
addr.setCountry(obj.first().str());
|
||||||
|
}
|
||||||
|
if (flags & 0x4) {
|
||||||
|
ds += readTranslatedObjects(stream, codec, obj);
|
||||||
|
if (!obj.isEmpty())
|
||||||
|
addr.setState(obj.first().str());
|
||||||
|
}
|
||||||
|
if (flags & 0x8) {
|
||||||
|
ds += readString(stream, codec, str);
|
||||||
|
addr.setPostalCode(str);
|
||||||
|
}
|
||||||
|
if (flags & 0x10) {
|
||||||
|
ds += readTranslatedObjects(stream, codec, obj);
|
||||||
|
if (!obj.isEmpty())
|
||||||
|
addr.setStreet(obj.first().str());
|
||||||
|
}
|
||||||
|
if (flags & 0x20) // unknown
|
||||||
|
ds += readString(stream, codec, str);
|
||||||
|
|
||||||
|
waypoint.setAddress(addr);
|
||||||
|
|
||||||
|
if (ds != rh.size)
|
||||||
|
stream.setStatus(QDataStream::ReadCorruptData);
|
||||||
|
|
||||||
|
return rs + rh.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||||
|
static const QTemporaryDir &tempDir()
|
||||||
|
{
|
||||||
|
static QTemporaryDir dir;
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
static quint32 readImageInfo(QDataStream &stream, Waypoint &waypoint,
|
||||||
|
const QString &fileName, int &imgId)
|
||||||
|
{
|
||||||
|
RecordHeader rh;
|
||||||
|
quint8 rs, s1;
|
||||||
|
quint32 size;
|
||||||
|
|
||||||
|
rs = readRecordHeader(stream, rh);
|
||||||
|
stream >> s1 >> size;
|
||||||
|
|
||||||
|
QByteArray ba;
|
||||||
|
ba.resize(size);
|
||||||
|
stream.readRawData(ba.data(), ba.size());
|
||||||
|
|
||||||
|
if (tempDir().isValid()) {
|
||||||
|
QBuffer buf(&ba);
|
||||||
|
QImageReader ir(&buf);
|
||||||
|
|
||||||
|
QByteArray id(fileName.toUtf8() + QByteArray::number(imgId++));
|
||||||
|
QFile imgFile(tempDir().path() + "/" + QString("%0.%1").arg(
|
||||||
|
QCryptographicHash::hash(id, QCryptographicHash::Sha1).toHex(),
|
||||||
|
QString(ir.format())));
|
||||||
|
imgFile.open(QIODevice::WriteOnly);
|
||||||
|
imgFile.write(ba);
|
||||||
|
imgFile.close();
|
||||||
|
|
||||||
|
waypoint.addImage(ImageInfo(imgFile.fileName(), ir.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size + 5 != rh.size)
|
||||||
|
stream.setStatus(QDataStream::ReadCorruptData);
|
||||||
|
|
||||||
|
return rs + rh.size;
|
||||||
|
}
|
||||||
|
#endif // QT_VERSION >= 5
|
||||||
|
|
||||||
|
static int speed(quint8 flags)
|
||||||
|
{
|
||||||
|
switch (flags >> 4) {
|
||||||
|
case 0x8:
|
||||||
|
return 40;
|
||||||
|
case 0x9:
|
||||||
|
return 30;
|
||||||
|
case 0xA:
|
||||||
|
return 50;
|
||||||
|
case 0xB:
|
||||||
|
return 70;
|
||||||
|
case 0xC:
|
||||||
|
return 80;
|
||||||
|
case 0xD:
|
||||||
|
return 90;
|
||||||
|
case 0xE:
|
||||||
|
return 100;
|
||||||
|
case 0xF:
|
||||||
|
return 120;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static quint32 readCamera(QDataStream &stream, QVector<Waypoint> &waypoints,
|
||||||
|
QList<Area> &polygons)
|
||||||
|
{
|
||||||
|
RecordHeader rh;
|
||||||
|
quint8 flags, type, s7, rs;
|
||||||
|
qint32 top, right, bottom, left, lat, lon;
|
||||||
|
quint32 ds = 15;
|
||||||
|
|
||||||
|
|
||||||
|
rs = readRecordHeader(stream, rh);
|
||||||
|
top = readInt24(stream);
|
||||||
|
right = readInt24(stream);
|
||||||
|
bottom = readInt24(stream);
|
||||||
|
left = readInt24(stream);
|
||||||
|
stream >> flags >> type >> s7;
|
||||||
|
|
||||||
|
if (s7) {
|
||||||
|
quint32 skip = s7 + 2 + s7/4;
|
||||||
|
stream.skipRawData(skip);
|
||||||
|
lat = readInt24(stream);
|
||||||
|
lon = readInt24(stream);
|
||||||
|
ds += skip + 6;
|
||||||
|
} else {
|
||||||
|
quint8 s8;
|
||||||
|
stream.skipRawData(9);
|
||||||
|
stream >> s8;
|
||||||
|
quint32 skip = 3 + s8 + s8/4;
|
||||||
|
stream.skipRawData(skip);
|
||||||
|
lat = readInt24(stream);
|
||||||
|
lon = readInt24(stream);
|
||||||
|
ds += skip + 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
waypoints.append(Coordinates(toWGS24(lon), toWGS24(lat)));
|
||||||
|
|
||||||
|
Area area;
|
||||||
|
Polygon polygon;
|
||||||
|
QVector<Coordinates> v(4);
|
||||||
|
v[0] = Coordinates(toWGS24(left), toWGS24(top));
|
||||||
|
v[1] = Coordinates(toWGS24(right), toWGS24(top));
|
||||||
|
v[2] = Coordinates(toWGS24(right), toWGS24(bottom));
|
||||||
|
v[3] = Coordinates(toWGS24(left), toWGS24(bottom));
|
||||||
|
polygon.append(v);
|
||||||
|
area.append(polygon);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 8:
|
||||||
|
area.setDescription(QString("%1 mi/h")
|
||||||
|
.arg(speed(flags)));
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
area.setDescription(QString("%1 km/h")
|
||||||
|
.arg(speed(flags)));
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
case 11:
|
||||||
|
area.setDescription("Red light camera");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
polygons.append(area);
|
||||||
|
|
||||||
|
if (ds > rh.size)
|
||||||
|
stream.setStatus(QDataStream::ReadCorruptData);
|
||||||
|
else if (ds < rh.size)
|
||||||
|
stream.skipRawData(rh.size - ds);
|
||||||
|
|
||||||
|
return rs + rh.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static quint32 readPOI(QDataStream &stream, QTextCodec *codec,
|
||||||
|
QVector<Waypoint> &waypoints, const QString &fileName, int &imgId)
|
||||||
|
{
|
||||||
|
RecordHeader rh;
|
||||||
|
quint8 rs;
|
||||||
|
quint32 ds;
|
||||||
|
qint32 lat, lon;
|
||||||
|
quint16 s3;
|
||||||
|
QList<TranslatedString> obj;
|
||||||
|
|
||||||
|
rs = readRecordHeader(stream, rh);
|
||||||
|
stream >> lat >> lon >> s3;
|
||||||
|
stream.skipRawData(s3);
|
||||||
|
ds = 10 + s3;
|
||||||
|
ds += readTranslatedObjects(stream, codec, obj);
|
||||||
|
|
||||||
|
waypoints.append(Waypoint(Coordinates(toWGS32(lon), toWGS32(lat))));
|
||||||
|
if (!obj.isEmpty())
|
||||||
|
waypoints.last().setName(obj.first().str());
|
||||||
|
|
||||||
|
while (stream.status() == QDataStream::Ok && ds < rh.size) {
|
||||||
|
switch(nextHeaderType(stream)) {
|
||||||
|
case 10:
|
||||||
|
ds += readDescription(stream, codec, waypoints.last());
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
ds += readAddress(stream, codec, waypoints.last());
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
ds += readContact(stream, codec, waypoints.last());
|
||||||
|
break;
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||||
|
case 13:
|
||||||
|
ds += readImageInfo(stream, waypoints.last(), fileName, imgId);
|
||||||
|
break;
|
||||||
|
#endif // QT_VERSION >= 5
|
||||||
|
case 14:
|
||||||
|
ds += readNotes(stream, codec, waypoints.last());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ds += skipRecord(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ds != rh.size)
|
||||||
|
stream.setStatus(QDataStream::ReadCorruptData);
|
||||||
|
|
||||||
|
return rs + rh.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static quint32 readSpatialIndex(QDataStream &stream, QTextCodec *codec,
|
||||||
|
QVector<Waypoint> &waypoints, QList<Area> &polygons, const QString &fileName,
|
||||||
|
int &imgId)
|
||||||
|
{
|
||||||
|
RecordHeader rh;
|
||||||
|
quint32 ds, s5;
|
||||||
|
qint32 top, right, bottom, left;
|
||||||
|
quint16 s6;
|
||||||
|
quint8 rs;
|
||||||
|
|
||||||
|
rs = readRecordHeader(stream, rh);
|
||||||
|
stream >> top >> right >> bottom >> left >> s5 >> s6;
|
||||||
|
stream.skipRawData(s6);
|
||||||
|
ds = 22 + s6;
|
||||||
|
if (rh.flags & 0x8) {
|
||||||
|
while (stream.status() == QDataStream::Ok && ds < rh.size) {
|
||||||
|
switch(nextHeaderType(stream)) {
|
||||||
|
case 2:
|
||||||
|
ds += readPOI(stream, codec, waypoints, fileName, imgId);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
ds += readSpatialIndex(stream, codec, waypoints, polygons,
|
||||||
|
fileName, imgId);
|
||||||
|
break;
|
||||||
|
case 19:
|
||||||
|
ds += readCamera(stream, waypoints, polygons);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ds += skipRecord(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ds != rh.size)
|
||||||
|
stream.setStatus(QDataStream::ReadCorruptData);
|
||||||
|
|
||||||
|
return rs + rh.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void readPOIDatabase(QDataStream &stream, QTextCodec *codec,
|
||||||
|
QVector<Waypoint> &waypoints, QList<Area> &polygons, const QString &fileName,
|
||||||
|
int &imgId)
|
||||||
|
{
|
||||||
|
RecordHeader rh;
|
||||||
|
QList<TranslatedString> obj;
|
||||||
|
quint32 ds;
|
||||||
|
|
||||||
readRecordHeader(stream, rh);
|
readRecordHeader(stream, rh);
|
||||||
stream.readRawData(magic, sizeof(magic));
|
ds = readTranslatedObjects(stream, codec, obj);
|
||||||
if (memcmp(magic, "GRMREC", sizeof(magic))) {
|
ds += readSpatialIndex(stream, codec, waypoints, polygons, fileName, imgId);
|
||||||
_errorString = "Not a GPI file";
|
if (rh.flags & 0x8) {
|
||||||
return false;
|
while (stream.status() == QDataStream::Ok && ds < rh.size) {
|
||||||
|
switch(nextHeaderType(stream)) {
|
||||||
|
case 5: // symbol
|
||||||
|
case 7: // category
|
||||||
|
default:
|
||||||
|
ds += skipRecord(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
stream >> s5 >> s6 >> s7 >> s8 >> s9 >> s10;
|
|
||||||
stream.skipRawData(s10);
|
|
||||||
ds = sizeof(magic) + 10 + s10;
|
|
||||||
if (rh.flags & 8)
|
|
||||||
ds += readFprsRecord(stream);
|
|
||||||
|
|
||||||
ebs = (s8 & 0x4) ? s9 * 8 + 8 : 0;
|
if (ds != rh.size)
|
||||||
|
stream.setStatus(QDataStream::ReadCorruptData);
|
||||||
|
}
|
||||||
|
|
||||||
if (stream.status() != QDataStream::Ok || ds != rh.size) {
|
bool GPIParser::readData(QDataStream &stream, QTextCodec *codec,
|
||||||
_errorString = "Invalid file header";
|
QVector<Waypoint> &waypoints, QList<Area> &polygons, const QString &fileName)
|
||||||
return false;
|
{
|
||||||
} else
|
int imgId = 0;
|
||||||
return true;
|
|
||||||
|
while (stream.status() == QDataStream::Ok) {
|
||||||
|
switch (nextHeaderType(stream)) {
|
||||||
|
case 0x09: // POI database
|
||||||
|
readPOIDatabase(stream, codec, waypoints, polygons, fileName,
|
||||||
|
imgId);
|
||||||
|
break;
|
||||||
|
case 0xffff: // EOF
|
||||||
|
skipRecord(stream);
|
||||||
|
if (stream.status() == QDataStream::Ok)
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
case 0x16: // route
|
||||||
|
case 0x15: // info header
|
||||||
|
default:
|
||||||
|
skipRecord(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_errorString = "Invalid/corrupted GPI data";
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GPIParser::readGPIHeader(QDataStream &stream, QTextCodec **codec)
|
bool GPIParser::readGPIHeader(QDataStream &stream, QTextCodec **codec)
|
||||||
@ -394,58 +695,33 @@ bool GPIParser::readGPIHeader(QDataStream &stream, QTextCodec **codec)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPIParser::readPOIDatabase(QDataStream &stream, QTextCodec *codec,
|
bool GPIParser::readFileHeader(QDataStream &stream, quint32 &ebs)
|
||||||
QVector<Waypoint> &waypoints)
|
|
||||||
{
|
{
|
||||||
RecordHeader rh;
|
RecordHeader rh;
|
||||||
QList<TranslatedString> obj;
|
quint32 ds, s7;
|
||||||
quint32 ds;
|
quint16 s10;
|
||||||
|
quint8 s5, s6, s8, s9;
|
||||||
|
char magic[6];
|
||||||
|
|
||||||
readRecordHeader(stream, rh);
|
readRecordHeader(stream, rh);
|
||||||
ds = readTranslatedObjects(stream, codec, obj);
|
stream.readRawData(magic, sizeof(magic));
|
||||||
ds += readSpatialIndex(stream, codec, waypoints);
|
if (memcmp(magic, "GRMREC", sizeof(magic))) {
|
||||||
if (rh.flags & 0x8) {
|
_errorString = "Not a GPI file";
|
||||||
while (ds < rh.size) {
|
return false;
|
||||||
switch(nextHeaderType(stream)) {
|
|
||||||
case 5: // symbol
|
|
||||||
case 7: // category
|
|
||||||
default:
|
|
||||||
ds += skipRecord(stream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
stream >> s5 >> s6 >> s7 >> s8 >> s9 >> s10;
|
||||||
|
stream.skipRawData(s10);
|
||||||
|
ds = sizeof(magic) + 10 + s10;
|
||||||
|
if (rh.flags & 8)
|
||||||
|
ds += readFprsRecord(stream);
|
||||||
|
|
||||||
if (ds != rh.size)
|
ebs = (s8 & 0x4) ? s9 * 8 + 8 : 0;
|
||||||
stream.setStatus(QDataStream::ReadCorruptData);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GPIParser::readEntry(QDataStream &stream, QTextCodec *codec,
|
if (stream.status() != QDataStream::Ok || ds != rh.size) {
|
||||||
QVector<Waypoint> &waypoints)
|
_errorString = "Invalid file header";
|
||||||
{
|
return false;
|
||||||
switch (nextHeaderType(stream)) {
|
} else
|
||||||
case 0x09: // POI database
|
return true;
|
||||||
readPOIDatabase(stream, codec, waypoints);
|
|
||||||
break;
|
|
||||||
case 0xffff: // EOF
|
|
||||||
skipRecord(stream);
|
|
||||||
return false;
|
|
||||||
case 0x16: // route
|
|
||||||
case 0x15: // info header
|
|
||||||
default:
|
|
||||||
skipRecord(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GPIParser::readData(QDataStream &stream, QTextCodec *codec,
|
|
||||||
QVector<Waypoint> &waypoints)
|
|
||||||
{
|
|
||||||
while (stream.status() == QDataStream::Ok)
|
|
||||||
if (!readEntry(stream, codec, waypoints))
|
|
||||||
return stream.atEnd();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GPIParser::parse(QFile *file, QList<TrackData> &tracks,
|
bool GPIParser::parse(QFile *file, QList<TrackData> &tracks,
|
||||||
@ -453,11 +729,9 @@ bool GPIParser::parse(QFile *file, QList<TrackData> &tracks,
|
|||||||
{
|
{
|
||||||
Q_UNUSED(tracks);
|
Q_UNUSED(tracks);
|
||||||
Q_UNUSED(routes);
|
Q_UNUSED(routes);
|
||||||
Q_UNUSED(polygons);
|
|
||||||
QDataStream stream(file);
|
QDataStream stream(file);
|
||||||
QTextCodec *codec = 0;
|
QTextCodec *codec = 0;
|
||||||
quint32 ebs;
|
quint32 ebs;
|
||||||
bool ret;
|
|
||||||
|
|
||||||
stream.setByteOrder(QDataStream::LittleEndian);
|
stream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
@ -465,24 +739,11 @@ bool GPIParser::parse(QFile *file, QList<TrackData> &tracks,
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (ebs) {
|
if (ebs) {
|
||||||
QByteArray ba(stream.device()->readAll());
|
CryptDevice dev(stream.device(), 0xf870b5, ebs);
|
||||||
for (int i = 0; i < (ba.size() / (int)ebs); i++)
|
QDataStream cryptStream(&dev);
|
||||||
demangle((quint8*)(ba.data() + i * ebs), ebs, BLOCK_KEY);
|
cryptStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
demangle((quint8*)(ba.data() + (ba.size() / (int)ebs) * ebs),
|
return readData(cryptStream, codec, waypoints, polygons,
|
||||||
ba.size() - ((ba.size() / (int)ebs) * ebs), BLOCK_KEY);
|
file->fileName());
|
||||||
|
|
||||||
QBuffer buffer(&ba);
|
|
||||||
buffer.open(QIODevice::ReadOnly);
|
|
||||||
QDataStream memStream(&buffer);
|
|
||||||
memStream.setByteOrder(QDataStream::LittleEndian);
|
|
||||||
ret = readData(memStream, codec, waypoints);
|
|
||||||
} else
|
} else
|
||||||
ret = readData(stream, codec, waypoints);
|
return readData(stream, codec, waypoints, polygons, file->fileName());
|
||||||
|
|
||||||
|
|
||||||
if (!ret) {
|
|
||||||
_errorString = "Invalid/corrupted GPI data";
|
|
||||||
return false;
|
|
||||||
} else
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
@ -18,11 +18,8 @@ private:
|
|||||||
bool readFileHeader(QDataStream &stream, quint32 &ebs);
|
bool readFileHeader(QDataStream &stream, quint32 &ebs);
|
||||||
bool readGPIHeader(QDataStream &stream, QTextCodec **codec);
|
bool readGPIHeader(QDataStream &stream, QTextCodec **codec);
|
||||||
bool readData(QDataStream &stream, QTextCodec *codec,
|
bool readData(QDataStream &stream, QTextCodec *codec,
|
||||||
QVector<Waypoint> &waypoints);
|
QVector<Waypoint> &waypoints, QList<Area> &polygons,
|
||||||
bool readEntry(QDataStream &stream, QTextCodec *codec,
|
const QString &fileName);
|
||||||
QVector<Waypoint> &waypoints);
|
|
||||||
void readPOIDatabase(QDataStream &stream, QTextCodec *codec,
|
|
||||||
QVector<Waypoint> &waypoints);
|
|
||||||
|
|
||||||
QString _errorString;
|
QString _errorString;
|
||||||
};
|
};
|
||||||
|
@ -69,8 +69,10 @@ Coordinates GPXParser::coordinates()
|
|||||||
void GPXParser::rpExtension(SegmentData *autoRoute)
|
void GPXParser::rpExtension(SegmentData *autoRoute)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == QLatin1String("rpt"))
|
if (_reader.name() == QLatin1String("rpt")) {
|
||||||
autoRoute->append(Trackpoint(coordinates()));
|
if (autoRoute)
|
||||||
|
autoRoute->append(Trackpoint(coordinates()));
|
||||||
|
}
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -91,11 +93,45 @@ void GPXParser::tpExtension(Trackpoint &trackpoint)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPXParser::rteptExtensions(SegmentData *autoRoute)
|
void GPXParser::address(Waypoint &waypoint)
|
||||||
|
{
|
||||||
|
Address addr;
|
||||||
|
|
||||||
|
while (_reader.readNextStartElement()) {
|
||||||
|
if (_reader.name() == QLatin1String("StreetAddress"))
|
||||||
|
addr.setStreet(_reader.readElementText());
|
||||||
|
else if (_reader.name() == QLatin1String("City"))
|
||||||
|
addr.setCity(_reader.readElementText());
|
||||||
|
else if (_reader.name() == QLatin1String("PostalCode"))
|
||||||
|
addr.setPostalCode(_reader.readElementText());
|
||||||
|
else if (_reader.name() == QLatin1String("State"))
|
||||||
|
addr.setState(_reader.readElementText());
|
||||||
|
else if (_reader.name() == QLatin1String("Country"))
|
||||||
|
addr.setCountry(_reader.readElementText());
|
||||||
|
else
|
||||||
|
_reader.skipCurrentElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
waypoint.setAddress(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPXParser::wpExtension(Waypoint &waypoint)
|
||||||
|
{
|
||||||
|
while (_reader.readNextStartElement()) {
|
||||||
|
if (_reader.name() == QLatin1String("Address"))
|
||||||
|
address(waypoint);
|
||||||
|
else
|
||||||
|
_reader.skipCurrentElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPXParser::waypointExtensions(Waypoint &waypoint, SegmentData *autoRoute)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == QLatin1String("RoutePointExtension"))
|
if (_reader.name() == QLatin1String("RoutePointExtension"))
|
||||||
rpExtension(autoRoute);
|
rpExtension(autoRoute);
|
||||||
|
else if (_reader.name() == QLatin1String("WaypointExtension"))
|
||||||
|
wpExtension(waypoint);
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
}
|
}
|
||||||
@ -156,6 +192,8 @@ void GPXParser::waypointData(Waypoint &waypoint, SegmentData *autoRoute)
|
|||||||
waypoint.setName(_reader.readElementText());
|
waypoint.setName(_reader.readElementText());
|
||||||
else if (_reader.name() == QLatin1String("desc"))
|
else if (_reader.name() == QLatin1String("desc"))
|
||||||
waypoint.setDescription(_reader.readElementText());
|
waypoint.setDescription(_reader.readElementText());
|
||||||
|
else if (_reader.name() == QLatin1String("cmt"))
|
||||||
|
waypoint.setComment(_reader.readElementText());
|
||||||
else if (_reader.name() == QLatin1String("ele"))
|
else if (_reader.name() == QLatin1String("ele"))
|
||||||
waypoint.setElevation(number());
|
waypoint.setElevation(number());
|
||||||
else if (_reader.name() == QLatin1String("geoidheight"))
|
else if (_reader.name() == QLatin1String("geoidheight"))
|
||||||
@ -170,8 +208,8 @@ void GPXParser::waypointData(Waypoint &waypoint, SegmentData *autoRoute)
|
|||||||
link10.setURL(_reader.readElementText());
|
link10.setURL(_reader.readElementText());
|
||||||
else if (_reader.name() == QLatin1String("urlname"))
|
else if (_reader.name() == QLatin1String("urlname"))
|
||||||
link10.setText(_reader.readElementText());
|
link10.setText(_reader.readElementText());
|
||||||
else if (autoRoute && _reader.name() == QLatin1String("extensions"))
|
else if (_reader.name() == QLatin1String("extensions"))
|
||||||
rteptExtensions(autoRoute);
|
waypointExtensions(waypoint, autoRoute);
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
}
|
}
|
||||||
@ -208,6 +246,8 @@ void GPXParser::routepoints(RouteData &route, QList<TrackData> &tracks)
|
|||||||
route.setName(_reader.readElementText());
|
route.setName(_reader.readElementText());
|
||||||
else if (_reader.name() == QLatin1String("desc"))
|
else if (_reader.name() == QLatin1String("desc"))
|
||||||
route.setDescription(_reader.readElementText());
|
route.setDescription(_reader.readElementText());
|
||||||
|
else if (_reader.name() == QLatin1String("cmt"))
|
||||||
|
route.setComment(_reader.readElementText());
|
||||||
else if (_reader.name() == QLatin1String("link")) {
|
else if (_reader.name() == QLatin1String("link")) {
|
||||||
Link l(link());
|
Link l(link());
|
||||||
if (!l.URL().isEmpty())
|
if (!l.URL().isEmpty())
|
||||||
@ -242,6 +282,8 @@ void GPXParser::track(TrackData &track)
|
|||||||
track.setName(_reader.readElementText());
|
track.setName(_reader.readElementText());
|
||||||
else if (_reader.name() == QLatin1String("desc"))
|
else if (_reader.name() == QLatin1String("desc"))
|
||||||
track.setDescription(_reader.readElementText());
|
track.setDescription(_reader.readElementText());
|
||||||
|
else if (_reader.name() == QLatin1String("cmt"))
|
||||||
|
track.setComment(_reader.readElementText());
|
||||||
else if (_reader.name() == QLatin1String("link")) {
|
else if (_reader.name() == QLatin1String("link")) {
|
||||||
Link l(link());
|
Link l(link());
|
||||||
if (!l.URL().isEmpty())
|
if (!l.URL().isEmpty())
|
||||||
|
@ -21,11 +21,13 @@ private:
|
|||||||
void rpExtension(SegmentData *autoRoute);
|
void rpExtension(SegmentData *autoRoute);
|
||||||
void tpExtension(Trackpoint &trackpoint);
|
void tpExtension(Trackpoint &trackpoint);
|
||||||
void trkptExtensions(Trackpoint &trackpoint);
|
void trkptExtensions(Trackpoint &trackpoint);
|
||||||
void rteptExtensions(SegmentData *autoRoute);
|
void wpExtension(Waypoint &waypoint);
|
||||||
|
void waypointExtensions(Waypoint &waypoint, SegmentData *autoRoute);
|
||||||
void area(Area &area);
|
void area(Area &area);
|
||||||
void gpxExtensions(QList<Area> &areas);
|
void gpxExtensions(QList<Area> &areas);
|
||||||
void trackpointData(Trackpoint &trackpoint);
|
void trackpointData(Trackpoint &trackpoint);
|
||||||
void waypointData(Waypoint &waypoint, SegmentData *autoRoute = 0);
|
void waypointData(Waypoint &waypoint, SegmentData *autoRoute = 0);
|
||||||
|
void address(Waypoint &waypoint);
|
||||||
qreal number();
|
qreal number();
|
||||||
QDateTime time();
|
QDateTime time();
|
||||||
Coordinates coordinates();
|
Coordinates coordinates();
|
||||||
|
@ -67,4 +67,17 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class GraphPair
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GraphPair(const Graph &primary, const Graph &secondary)
|
||||||
|
: _primary(primary), _secondary(secondary) {}
|
||||||
|
|
||||||
|
const Graph &primary() const {return _primary;}
|
||||||
|
const Graph &secondary() const {return _secondary;}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Graph _primary, _secondary;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // GRAPH_H
|
#endif // GRAPH_H
|
||||||
|
@ -87,16 +87,18 @@ static bool readTimestamp(const char *data, QTime &time)
|
|||||||
|
|
||||||
static bool readARecord(const char *line, qint64 len)
|
static bool readARecord(const char *line, qint64 len)
|
||||||
{
|
{
|
||||||
if (len < 7 || line[0] != 'A')
|
/* The minimal A record length should be 7 according to the specification,
|
||||||
|
but records with length of 6 exist in the wild */
|
||||||
|
if (len < 6 || line[0] != 'A')
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (int i = 1; i < 7; i++)
|
for (int i = 1; i < 6; i++)
|
||||||
if (!::isprint(line[i]))
|
if (!::isprint(line[i]))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IGCParser::readHRecord(const char *line, int len)
|
bool IGCParser::readHRecord(CTX &ctx, const char *line, int len)
|
||||||
{
|
{
|
||||||
if (len < 11 || ::strncmp(line, "HFDTE", 5))
|
if (len < 11 || ::strncmp(line, "HFDTE", 5))
|
||||||
return true;
|
return true;
|
||||||
@ -112,9 +114,9 @@ bool IGCParser::readHRecord(const char *line, int len)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_date = QDate(y + 2000 <= QDate::currentDate().year() ? 2000 + y : 1900 + y,
|
ctx.date = QDate(y + 2000 <= QDate::currentDate().year()
|
||||||
m, d);
|
? 2000 + y : 1900 + y, m, d);
|
||||||
if (!_date.isValid()) {
|
if (!ctx.date.isValid()) {
|
||||||
_errorString = "Invalid date";
|
_errorString = "Invalid date";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -122,8 +124,8 @@ bool IGCParser::readHRecord(const char *line, int len)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IGCParser::readBRecord(SegmentData &segment, const char *line,
|
bool IGCParser::readBRecord(CTX &ctx, const char *line, int len,
|
||||||
int len)
|
SegmentData &segment)
|
||||||
{
|
{
|
||||||
qreal lat, lon, ele;
|
qreal lat, lon, ele;
|
||||||
QTime time;
|
QTime time;
|
||||||
@ -152,20 +154,20 @@ bool IGCParser::readBRecord(SegmentData &segment, const char *line,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (time < _time && !segment.isEmpty()
|
if (time < ctx.time && !segment.isEmpty()
|
||||||
&& _date == segment.last().timestamp().date())
|
&& ctx.date == segment.last().timestamp().date())
|
||||||
_date = _date.addDays(1);
|
ctx.date = ctx.date.addDays(1);
|
||||||
_time = time;
|
ctx.time = time;
|
||||||
|
|
||||||
Trackpoint t(Coordinates(lon, lat));
|
Trackpoint t(Coordinates(lon, lat));
|
||||||
t.setTimestamp(QDateTime(_date, _time, Qt::UTC));
|
t.setTimestamp(QDateTime(ctx.date, ctx.time, Qt::UTC));
|
||||||
t.setElevation(ele);
|
t.setElevation(ele);
|
||||||
segment.append(t);
|
segment.append(t);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IGCParser::readCRecord(RouteData &route, const char *line, int len)
|
bool IGCParser::readCRecord(const char *line, int len, RouteData &route)
|
||||||
{
|
{
|
||||||
qreal lat, lon;
|
qreal lat, lon;
|
||||||
|
|
||||||
@ -202,6 +204,7 @@ bool IGCParser::parse(QFile *file, QList<TrackData> &tracks,
|
|||||||
qint64 len;
|
qint64 len;
|
||||||
char line[76 + 2 + 1 + 1];
|
char line[76 + 2 + 1 + 1];
|
||||||
bool route = false, track = false;
|
bool route = false, track = false;
|
||||||
|
CTX ctx;
|
||||||
|
|
||||||
|
|
||||||
_errorLine = 1;
|
_errorLine = 1;
|
||||||
@ -225,28 +228,28 @@ bool IGCParser::parse(QFile *file, QList<TrackData> &tracks,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (line[0] == 'H') {
|
if (line[0] == 'H') {
|
||||||
if (!readHRecord(line, len))
|
if (!readHRecord(ctx, line, len))
|
||||||
return false;
|
return false;
|
||||||
} else if (line[0] == 'C') {
|
} else if (line[0] == 'C') {
|
||||||
if (route) {
|
if (route) {
|
||||||
if (!readCRecord(routes.last() ,line, len))
|
if (!readCRecord(line, len, routes.last()))
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
route = true;
|
route = true;
|
||||||
routes.append(RouteData());
|
routes.append(RouteData());
|
||||||
}
|
}
|
||||||
} else if (line[0] == 'B') {
|
} else if (line[0] == 'B') {
|
||||||
if (_date.isNull()) {
|
if (ctx.date.isNull()) {
|
||||||
_errorString = "Missing date header";
|
_errorString = "Missing date header";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!track) {
|
if (!track) {
|
||||||
tracks.append(TrackData());
|
tracks.append(TrackData());
|
||||||
tracks.last().append(SegmentData());
|
tracks.last().append(SegmentData());
|
||||||
_time = QTime(0, 0);
|
ctx.time = QTime(0, 0);
|
||||||
track = true;
|
track = true;
|
||||||
}
|
}
|
||||||
if (!readBRecord(tracks.last().last(), line, len))
|
if (!readBRecord(ctx, line, len, tracks.last().last()))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,15 +17,17 @@ public:
|
|||||||
int errorLine() const {return _errorLine;}
|
int errorLine() const {return _errorLine;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool readHRecord(const char *line, int len);
|
struct CTX {
|
||||||
bool readBRecord(SegmentData &segment, const char *line, int len);
|
QDate date;
|
||||||
bool readCRecord(RouteData &route, const char *line, int len);
|
QTime time;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool readHRecord(CTX &ctx, const char *line, int len);
|
||||||
|
bool readBRecord(CTX &ctx, const char *line, int len, SegmentData &segment);
|
||||||
|
bool readCRecord(const char *line, int len, RouteData &route);
|
||||||
|
|
||||||
int _errorLine;
|
int _errorLine;
|
||||||
QString _errorString;
|
QString _errorString;
|
||||||
|
|
||||||
QDate _date;
|
|
||||||
QTime _time;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // IGCPARSER_H
|
#endif // IGCPARSER_H
|
||||||
|
@ -7,15 +7,15 @@ class Link {
|
|||||||
public:
|
public:
|
||||||
Link() {}
|
Link() {}
|
||||||
Link(const QString &URL, const QString &text = QString())
|
Link(const QString &URL, const QString &text = QString())
|
||||||
: _URL(URL), _text(text) {}
|
: _url(URL), _text(text) {}
|
||||||
|
|
||||||
void setURL(const QString &URL) {_URL = URL;}
|
void setURL(const QString &URL) {_url = URL;}
|
||||||
void setText(const QString &text) {_text = text;}
|
void setText(const QString &text) {_text = text;}
|
||||||
const QString &URL() const {return _URL;}
|
const QString &URL() const {return _url;}
|
||||||
const QString &text() const {return _text;}
|
const QString &text() const {return _text;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString _URL;
|
QString _url;
|
||||||
QString _text;
|
QString _text;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -227,7 +227,8 @@ bool NMEAParser::readEW(const char *data, int len, qreal &lon)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NMEAParser::readRMC(SegmentData &segment, const char *line, int len)
|
bool NMEAParser::readRMC(CTX &ctx, const char *line, int len,
|
||||||
|
SegmentData &segment)
|
||||||
{
|
{
|
||||||
int col = 1;
|
int col = 1;
|
||||||
const char *vp = line;
|
const char *vp = line;
|
||||||
@ -280,23 +281,24 @@ bool NMEAParser::readRMC(SegmentData &segment, const char *line, int len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!date.isNull()) {
|
if (!date.isNull()) {
|
||||||
if (_date.isNull() && !_time.isNull() && !segment.isEmpty())
|
if (ctx.date.isNull() && !ctx.time.isNull() && !segment.isEmpty())
|
||||||
segment.last().setTimestamp(QDateTime(date, _time, Qt::UTC));
|
segment.last().setTimestamp(QDateTime(date, ctx.time, Qt::UTC));
|
||||||
_date = date;
|
ctx.date = date;
|
||||||
}
|
}
|
||||||
|
|
||||||
Coordinates c(lon, lat);
|
Coordinates c(lon, lat);
|
||||||
if (valid && !_GGA && c.isValid()) {
|
if (valid && !ctx.GGA && c.isValid()) {
|
||||||
Trackpoint t(c);
|
Trackpoint t(c);
|
||||||
if (!_date.isNull() && !time.isNull())
|
if (!ctx.date.isNull() && !time.isNull())
|
||||||
t.setTimestamp(QDateTime(_date, time, Qt::UTC));
|
t.setTimestamp(QDateTime(ctx.date, time, Qt::UTC));
|
||||||
segment.append(t);
|
segment.append(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NMEAParser::readGGA(SegmentData &segment, const char *line, int len)
|
bool NMEAParser::readGGA(CTX &ctx, const char *line, int len,
|
||||||
|
SegmentData &segment)
|
||||||
{
|
{
|
||||||
int col = 1;
|
int col = 1;
|
||||||
const char *vp = line;
|
const char *vp = line;
|
||||||
@ -306,7 +308,7 @@ bool NMEAParser::readGGA(SegmentData &segment, const char *line, int len)
|
|||||||
if (*lp == ',' || *lp == '*') {
|
if (*lp == ',' || *lp == '*') {
|
||||||
switch (col) {
|
switch (col) {
|
||||||
case 1:
|
case 1:
|
||||||
if (!readTime(vp, lp - vp, _time))
|
if (!readTime(vp, lp - vp, ctx.time))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
@ -360,19 +362,19 @@ bool NMEAParser::readGGA(SegmentData &segment, const char *line, int len)
|
|||||||
Coordinates c(lon, lat);
|
Coordinates c(lon, lat);
|
||||||
if (c.isValid()) {
|
if (c.isValid()) {
|
||||||
Trackpoint t(c);
|
Trackpoint t(c);
|
||||||
if (!(_time.isNull() || _date.isNull()))
|
if (!(ctx.time.isNull() || ctx.date.isNull()))
|
||||||
t.setTimestamp(QDateTime(_date, _time, Qt::UTC));
|
t.setTimestamp(QDateTime(ctx.date, ctx.time, Qt::UTC));
|
||||||
if (!std::isnan(ele))
|
if (!std::isnan(ele))
|
||||||
t.setElevation(ele - gh);
|
t.setElevation(ele - gh);
|
||||||
segment.append(t);
|
segment.append(t);
|
||||||
|
|
||||||
_GGA = true;
|
ctx.GGA = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NMEAParser::readWPL(QVector<Waypoint> &waypoints, const char *line, int len)
|
bool NMEAParser::readWPL(const char *line, int len, QVector<Waypoint> &waypoints)
|
||||||
{
|
{
|
||||||
int col = 1;
|
int col = 1;
|
||||||
const char *vp = line;
|
const char *vp = line;
|
||||||
@ -423,7 +425,7 @@ bool NMEAParser::readWPL(QVector<Waypoint> &waypoints, const char *line, int len
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NMEAParser::readZDA(const char *line, int len)
|
bool NMEAParser::readZDA(CTX &ctx, const char *line, int len)
|
||||||
{
|
{
|
||||||
int col = 1;
|
int col = 1;
|
||||||
const char *vp = line;
|
const char *vp = line;
|
||||||
@ -468,8 +470,8 @@ bool NMEAParser::readZDA(const char *line, int len)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_date = QDate(y, m, d);
|
ctx.date = QDate(y, m, d);
|
||||||
if (!_date.isValid()) {
|
if (!ctx.date.isValid()) {
|
||||||
_errorString = "Invalid date";
|
_errorString = "Invalid date";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -486,13 +488,11 @@ bool NMEAParser::parse(QFile *file, QList<TrackData> &tracks,
|
|||||||
qint64 len;
|
qint64 len;
|
||||||
char line[80 + 2 + 1 + 1];
|
char line[80 + 2 + 1 + 1];
|
||||||
SegmentData segment;
|
SegmentData segment;
|
||||||
|
CTX ctx;
|
||||||
|
|
||||||
|
|
||||||
_errorLine = 1;
|
_errorLine = 1;
|
||||||
_errorString.clear();
|
_errorString.clear();
|
||||||
_date = QDate();
|
|
||||||
_time = QTime();
|
|
||||||
_GGA = false;
|
|
||||||
|
|
||||||
while (!file->atEnd()) {
|
while (!file->atEnd()) {
|
||||||
len = file->readLine(line, sizeof(line));
|
len = file->readLine(line, sizeof(line));
|
||||||
@ -507,16 +507,16 @@ bool NMEAParser::parse(QFile *file, QList<TrackData> &tracks,
|
|||||||
|
|
||||||
if (validSentence(line, len)) {
|
if (validSentence(line, len)) {
|
||||||
if (!memcmp(line + 3, "RMC,", 4)) {
|
if (!memcmp(line + 3, "RMC,", 4)) {
|
||||||
if (!readRMC(segment, line + 7, len - 7))
|
if (!readRMC(ctx, line + 7, len - 7, segment))
|
||||||
return false;
|
return false;
|
||||||
} else if (!memcmp(line + 3, "GGA,", 4)) {
|
} else if (!memcmp(line + 3, "GGA,", 4)) {
|
||||||
if (!readGGA(segment, line + 7, len - 7))
|
if (!readGGA(ctx, line + 7, len - 7, segment))
|
||||||
return false;
|
return false;
|
||||||
} else if (!memcmp(line + 3, "WPL,", 4)) {
|
} else if (!memcmp(line + 3, "WPL,", 4)) {
|
||||||
if (!readWPL(waypoints, line + 7, len - 7))
|
if (!readWPL(line + 7, len - 7, waypoints))
|
||||||
return false;
|
return false;
|
||||||
} else if (!memcmp(line + 3, "ZDA,", 4)) {
|
} else if (!memcmp(line + 3, "ZDA,", 4)) {
|
||||||
if (!readZDA(line + 7, len - 7))
|
if (!readZDA(ctx, line + 7, len - 7))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
class NMEAParser : public Parser
|
class NMEAParser : public Parser
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NMEAParser() : _errorLine(0), _GGA(false) {}
|
NMEAParser() : _errorLine(0) {}
|
||||||
|
|
||||||
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
|
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
|
||||||
QList<Area> &polygons, QVector<Waypoint> &waypoints);
|
QList<Area> &polygons, QVector<Waypoint> &waypoints);
|
||||||
@ -16,6 +16,14 @@ public:
|
|||||||
int errorLine() const {return _errorLine;}
|
int errorLine() const {return _errorLine;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct CTX {
|
||||||
|
CTX() : GGA(false) {}
|
||||||
|
|
||||||
|
QDate date;
|
||||||
|
QTime time;
|
||||||
|
bool GGA;
|
||||||
|
};
|
||||||
|
|
||||||
bool readEW(const char *data, int len, qreal &lon);
|
bool readEW(const char *data, int len, qreal &lon);
|
||||||
bool readLon(const char *data, int len, qreal &lon);
|
bool readLon(const char *data, int len, qreal &lon);
|
||||||
bool readNS(const char *data, int len, qreal &lat);
|
bool readNS(const char *data, int len, qreal &lat);
|
||||||
@ -25,17 +33,13 @@ private:
|
|||||||
bool readAltitude(const char *data, int len, qreal &ele);
|
bool readAltitude(const char *data, int len, qreal &ele);
|
||||||
bool readGeoidHeight(const char *data, int len, qreal &gh);
|
bool readGeoidHeight(const char *data, int len, qreal &gh);
|
||||||
|
|
||||||
bool readRMC(SegmentData &segment, const char *line, int len);
|
bool readRMC(CTX &ctx, const char *line, int len, SegmentData &segment);
|
||||||
bool readGGA(SegmentData &segment, const char *line, int len);
|
bool readGGA(CTX &ctx, const char *line, int len, SegmentData &segment);
|
||||||
bool readWPL(QVector<Waypoint> &waypoints, const char *line, int len);
|
bool readWPL(const char *line, int len, QVector<Waypoint> &waypoints);
|
||||||
bool readZDA(const char *line, int len);
|
bool readZDA(CTX &ctx, const char *line, int len);
|
||||||
|
|
||||||
int _errorLine;
|
int _errorLine;
|
||||||
QString _errorString;
|
QString _errorString;
|
||||||
|
|
||||||
QDate _date;
|
|
||||||
QTime _time;
|
|
||||||
bool _GGA;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NMEAPARSER_H
|
#endif // NMEAPARSER_H
|
||||||
|
@ -14,28 +14,19 @@ POI::POI(QObject *parent) : QObject(parent)
|
|||||||
{
|
{
|
||||||
_errorLine = 0;
|
_errorLine = 0;
|
||||||
_radius = 1000;
|
_radius = 1000;
|
||||||
_useDEM = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool POI::loadFile(const QString &path, bool dir)
|
bool POI::loadFile(const QString &path)
|
||||||
{
|
{
|
||||||
Data data(path, true);
|
Data data(path);
|
||||||
FileIndex index;
|
FileIndex index;
|
||||||
|
|
||||||
index.enabled = true;
|
index.enabled = true;
|
||||||
index.start = _data.size();
|
index.start = _data.size();
|
||||||
|
|
||||||
if (!data.isValid()) {
|
if (!data.isValid()) {
|
||||||
if (dir) {
|
_errorString = data.errorString();
|
||||||
if (data.errorLine())
|
_errorLine = data.errorLine();
|
||||||
_errorString += QString("%1:%2: %3\n").arg(path)
|
|
||||||
.arg(data.errorLine()).arg(data.errorString());
|
|
||||||
else
|
|
||||||
_errorString += path + ": " + data.errorString() + "\n";
|
|
||||||
} else {
|
|
||||||
_errorString = data.errorString();
|
|
||||||
_errorLine = data.errorLine();
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,37 +50,22 @@ bool POI::loadFile(const QString &path, bool dir)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool POI::loadFile(const QString &path)
|
void POI::loadDir(const QString &path)
|
||||||
{
|
|
||||||
_errorString.clear();
|
|
||||||
_errorLine = 0;
|
|
||||||
|
|
||||||
return loadFile(path, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool POI::loadDir(const QString &path)
|
|
||||||
{
|
{
|
||||||
QDir md(path);
|
QDir md(path);
|
||||||
md.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
|
md.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
QFileInfoList fl = md.entryInfoList();
|
QFileInfoList fl = md.entryInfoList();
|
||||||
bool ret = true;
|
|
||||||
|
|
||||||
_errorString.clear();
|
|
||||||
_errorLine = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < fl.size(); i++) {
|
for (int i = 0; i < fl.size(); i++) {
|
||||||
const QFileInfo &fi = fl.at(i);
|
const QFileInfo &fi = fl.at(i);
|
||||||
|
|
||||||
if (fi.isDir()) {
|
if (fi.isDir())
|
||||||
if (!loadDir(fi.absoluteFilePath()))
|
loadDir(fi.absoluteFilePath());
|
||||||
ret = false;
|
else
|
||||||
} else {
|
if (!loadFile(fi.absoluteFilePath()))
|
||||||
if (!loadFile(fi.absoluteFilePath(), true))
|
qWarning(qPrintable(fi.absoluteFilePath() + ": "
|
||||||
ret = false;
|
+ _errorString));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool cb(size_t data, void* context)
|
static bool cb(size_t data, void* context)
|
||||||
@ -112,17 +88,6 @@ void POI::search(const RectC &rect, QSet<int> &set) const
|
|||||||
_tree.Search(min, max, cb, &set);
|
_tree.Search(min, max, cb, &set);
|
||||||
}
|
}
|
||||||
|
|
||||||
void POI::appendElevation(QList<Waypoint> &points) const
|
|
||||||
{
|
|
||||||
for (int i = 0; i < points.size(); i++) {
|
|
||||||
if (!points.at(i).hasElevation() || _useDEM) {
|
|
||||||
qreal elevation = DEM::elevation(points.at(i).coordinates());
|
|
||||||
if (!std::isnan(elevation))
|
|
||||||
points[i].setElevation(elevation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<Waypoint> POI::points(const Path &path) const
|
QList<Waypoint> POI::points(const Path &path) const
|
||||||
{
|
{
|
||||||
QList<Waypoint> ret;
|
QList<Waypoint> ret;
|
||||||
@ -158,8 +123,6 @@ QList<Waypoint> POI::points(const Path &path) const
|
|||||||
for (it = set.constBegin(); it != set.constEnd(); ++it)
|
for (it = set.constBegin(); it != set.constEnd(); ++it)
|
||||||
ret.append(_data.at(*it));
|
ret.append(_data.at(*it));
|
||||||
|
|
||||||
appendElevation(ret);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,8 +144,6 @@ QList<Waypoint> POI::points(const Waypoint &point) const
|
|||||||
for (it = set.constBegin(); it != set.constEnd(); ++it)
|
for (it = set.constBegin(); it != set.constEnd(); ++it)
|
||||||
ret.append(_data.at(*it));
|
ret.append(_data.at(*it));
|
||||||
|
|
||||||
appendElevation(ret);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,8 +167,6 @@ QList<Waypoint> POI::points(const Area &area) const
|
|||||||
for (it = set.constBegin(); it != set.constEnd(); ++it)
|
for (it = set.constBegin(); it != set.constEnd(); ++it)
|
||||||
ret.append(_data.at(*it));
|
ret.append(_data.at(*it));
|
||||||
|
|
||||||
appendElevation(ret);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,10 +212,3 @@ void POI::setRadius(unsigned radius)
|
|||||||
|
|
||||||
emit pointsChanged();
|
emit pointsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void POI::useDEM(bool use)
|
|
||||||
{
|
|
||||||
_useDEM = use;
|
|
||||||
|
|
||||||
emit pointsChanged();
|
|
||||||
}
|
|
||||||
|
@ -20,13 +20,12 @@ public:
|
|||||||
POI(QObject *parent = 0);
|
POI(QObject *parent = 0);
|
||||||
|
|
||||||
bool loadFile(const QString &path);
|
bool loadFile(const QString &path);
|
||||||
bool loadDir(const QString &path);
|
void loadDir(const QString &path);
|
||||||
const QString &errorString() const {return _errorString;}
|
const QString &errorString() const {return _errorString;}
|
||||||
int errorLine() const {return _errorLine;}
|
int errorLine() const {return _errorLine;}
|
||||||
|
|
||||||
unsigned radius() const {return _radius;}
|
unsigned radius() const {return _radius;}
|
||||||
void setRadius(unsigned radius);
|
void setRadius(unsigned radius);
|
||||||
void useDEM(bool use);
|
|
||||||
|
|
||||||
QList<Waypoint> points(const Path &path) const;
|
QList<Waypoint> points(const Path &path) const;
|
||||||
QList<Waypoint> points(const Waypoint &point) const;
|
QList<Waypoint> points(const Waypoint &point) const;
|
||||||
@ -49,7 +48,6 @@ private:
|
|||||||
|
|
||||||
bool loadFile(const QString &path, bool dir);
|
bool loadFile(const QString &path, bool dir);
|
||||||
void search(const RectC &rect, QSet<int> &set) const;
|
void search(const RectC &rect, QSet<int> &set) const;
|
||||||
void appendElevation(QList<Waypoint> &points) const;
|
|
||||||
|
|
||||||
POITree _tree;
|
POITree _tree;
|
||||||
QVector<Waypoint> _data;
|
QVector<Waypoint> _data;
|
||||||
@ -57,7 +55,6 @@ private:
|
|||||||
QList<FileIndex> _indexes;
|
QList<FileIndex> _indexes;
|
||||||
|
|
||||||
unsigned _radius;
|
unsigned _radius;
|
||||||
bool _useDEM;
|
|
||||||
|
|
||||||
QString _errorString;
|
QString _errorString;
|
||||||
int _errorLine;
|
int _errorLine;
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
|
#include "dem.h"
|
||||||
#include "route.h"
|
#include "route.h"
|
||||||
|
|
||||||
|
bool Route::_useDEM = false;
|
||||||
|
bool Route::_show2ndElevation = false;
|
||||||
|
|
||||||
Route::Route(const RouteData &data) : _data(data)
|
Route::Route(const RouteData &data) : _data(data)
|
||||||
{
|
{
|
||||||
@ -25,7 +28,7 @@ Path Route::path() const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Graph Route::elevation() const
|
Graph Route::gpsElevation() const
|
||||||
{
|
{
|
||||||
Graph graph;
|
Graph graph;
|
||||||
graph.append(GraphSegment());
|
graph.append(GraphSegment());
|
||||||
@ -38,6 +41,38 @@ Graph Route::elevation() const
|
|||||||
return graph;
|
return graph;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Graph Route::demElevation() const
|
||||||
|
{
|
||||||
|
Graph graph;
|
||||||
|
graph.append(GraphSegment());
|
||||||
|
GraphSegment &gs = graph.last();
|
||||||
|
|
||||||
|
for (int i = 0; i < _data.size(); i++) {
|
||||||
|
qreal dem = DEM::elevation(_data.at(i).coordinates());
|
||||||
|
if (!std::isnan(dem))
|
||||||
|
gs.append(GraphPoint(_distance.at(i), NAN, dem));
|
||||||
|
}
|
||||||
|
|
||||||
|
return graph;
|
||||||
|
}
|
||||||
|
|
||||||
|
GraphPair Route::elevation() const
|
||||||
|
{
|
||||||
|
if (_useDEM) {
|
||||||
|
Graph dem(demElevation());
|
||||||
|
if (dem.isValid())
|
||||||
|
return GraphPair(dem, _show2ndElevation ? gpsElevation() : Graph());
|
||||||
|
else
|
||||||
|
return GraphPair(gpsElevation(), Graph());
|
||||||
|
} else {
|
||||||
|
Graph gps(gpsElevation());
|
||||||
|
if (gps.isValid())
|
||||||
|
return GraphPair(gps, _show2ndElevation ? demElevation() : Graph());
|
||||||
|
else
|
||||||
|
return GraphPair(demElevation(), Graph());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
qreal Route::distance() const
|
qreal Route::distance() const
|
||||||
{
|
{
|
||||||
return (_distance.isEmpty()) ? 0 : _distance.last();
|
return (_distance.isEmpty()) ? 0 : _distance.last();
|
||||||
|
@ -11,23 +11,31 @@ class Route
|
|||||||
public:
|
public:
|
||||||
Route(const RouteData &data);
|
Route(const RouteData &data);
|
||||||
|
|
||||||
Path path() const;
|
|
||||||
|
|
||||||
const RouteData &data() const {return _data;}
|
const RouteData &data() const {return _data;}
|
||||||
|
Path path() const;
|
||||||
Graph elevation() const;
|
GraphPair elevation() const;
|
||||||
|
|
||||||
qreal distance() const;
|
qreal distance() const;
|
||||||
|
|
||||||
const QString &name() const {return _data.name();}
|
const QString &name() const {return _data.name();}
|
||||||
const QString &description() const {return _data.description();}
|
const QString &description() const {return _data.description();}
|
||||||
|
const QString &comment() const {return _data.comment();}
|
||||||
const QVector<Link> &links() const {return _data.links();}
|
const QVector<Link> &links() const {return _data.links();}
|
||||||
|
|
||||||
bool isValid() const {return _data.size() >= 2;}
|
bool isValid() const {return _data.size() >= 2;}
|
||||||
|
|
||||||
|
static void useDEM(bool use) {_useDEM = use;}
|
||||||
|
static void showSecondaryElevation(bool show)
|
||||||
|
{_show2ndElevation = show;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Graph gpsElevation() const;
|
||||||
|
Graph demElevation() const;
|
||||||
|
|
||||||
RouteData _data;
|
RouteData _data;
|
||||||
QVector<qreal> _distance;
|
QVector<qreal> _distance;
|
||||||
|
|
||||||
|
static bool _useDEM;
|
||||||
|
static bool _show2ndElevation;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ROUTE_H
|
#endif // ROUTE_H
|
||||||
|
@ -11,15 +11,18 @@ class RouteData : public QVector<Waypoint>
|
|||||||
public:
|
public:
|
||||||
const QString &name() const {return _name;}
|
const QString &name() const {return _name;}
|
||||||
const QString &description() const {return _desc;}
|
const QString &description() const {return _desc;}
|
||||||
|
const QString &comment() const {return _comment;}
|
||||||
const QVector<Link> &links() const {return _links;}
|
const QVector<Link> &links() const {return _links;}
|
||||||
|
|
||||||
void setName(const QString &name) {_name = name;}
|
void setName(const QString &name) {_name = name;}
|
||||||
void setDescription(const QString &desc) {_desc = desc;}
|
void setDescription(const QString &desc) {_desc = desc;}
|
||||||
|
void setComment(const QString &comment) {_comment = comment;}
|
||||||
void addLink(const Link &link) {_links.append(link);}
|
void addLink(const Link &link) {_links.append(link);}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString _name;
|
QString _name;
|
||||||
QString _desc;
|
QString _desc;
|
||||||
|
QString _comment;
|
||||||
QVector<Link> _links;
|
QVector<Link> _links;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
163
src/data/smlparser.cpp
Normal file
163
src/data/smlparser.cpp
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
#include "smlparser.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef QT_NO_DEBUG
|
||||||
|
QDebug operator<<(QDebug dbg, const SMLParser::Sensors &sensors)
|
||||||
|
{
|
||||||
|
dbg.nospace() << "Sensors(" << sensors.cadence << ", "
|
||||||
|
<< sensors.temperature << ", " << sensors.hr << "," << sensors.power
|
||||||
|
<< ", " << sensors.speed << ")";
|
||||||
|
|
||||||
|
return dbg.space();
|
||||||
|
}
|
||||||
|
#endif // QT_NO_DEBUG
|
||||||
|
|
||||||
|
|
||||||
|
void SMLParser::sample(SegmentData &segment, QMap<QDateTime, Sensors> &map)
|
||||||
|
{
|
||||||
|
QDateTime timestamp;
|
||||||
|
Sensors sensors;
|
||||||
|
qreal lat = NAN, lon = NAN, altitude = NAN;
|
||||||
|
bool ok, periodic = false;
|
||||||
|
|
||||||
|
while (_reader.readNextStartElement()) {
|
||||||
|
if (_reader.name() == QLatin1String("Latitude")) {
|
||||||
|
lat = _reader.readElementText().toDouble(&ok);
|
||||||
|
if (!ok || lat < -90 || lon > 90) {
|
||||||
|
_reader.raiseError("Invalid Latitude");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (_reader.name() == QLatin1String("Longitude")) {
|
||||||
|
lon = _reader.readElementText().toDouble(&ok);
|
||||||
|
if (!ok || lat < -180 || lon > 180) {
|
||||||
|
_reader.raiseError("Invalid Longitude");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (_reader.name() == QLatin1String("UTC")) {
|
||||||
|
timestamp = QDateTime::fromString(_reader.readElementText(),
|
||||||
|
Qt::ISODate);
|
||||||
|
if (!timestamp.isValid()) {
|
||||||
|
_reader.raiseError("Invalid timestamp");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (_reader.name() == QLatin1String("GPSAltitude")) {
|
||||||
|
altitude = _reader.readElementText().toDouble(&ok);
|
||||||
|
if (!ok) {
|
||||||
|
_reader.raiseError("Invalid GPS altitude");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (_reader.name() == QLatin1String("SampleType")) {
|
||||||
|
if (_reader.readElementText() == "periodic")
|
||||||
|
periodic = true;
|
||||||
|
} else if (_reader.name() == QLatin1String("Cadence")) {
|
||||||
|
sensors.cadence = _reader.readElementText().toDouble(&ok);
|
||||||
|
if (!ok || sensors.cadence < 0) {
|
||||||
|
_reader.raiseError("Invalid Cadence");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (_reader.name() == QLatin1String("Temperature")) {
|
||||||
|
sensors.temperature = _reader.readElementText().toDouble(&ok);
|
||||||
|
// Temperature is in Kelvin units
|
||||||
|
if (!ok || sensors.temperature < 0) {
|
||||||
|
_reader.raiseError("Invalid Temperature");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (_reader.name() == QLatin1String("HR")) {
|
||||||
|
sensors.hr = _reader.readElementText().toDouble(&ok);
|
||||||
|
if (!ok || sensors.hr < 0) {
|
||||||
|
_reader.raiseError("Invalid HR");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (_reader.name() == QLatin1String("BikePower")) {
|
||||||
|
sensors.power = _reader.readElementText().toDouble(&ok);
|
||||||
|
if (!ok || sensors.power < 0) {
|
||||||
|
_reader.raiseError("Invalid BikePower");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (_reader.name() == QLatin1String("Speed")) {
|
||||||
|
sensors.speed = _reader.readElementText().toDouble(&ok);
|
||||||
|
if (!ok || sensors.speed < 0) {
|
||||||
|
_reader.raiseError("Invalid Speed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
_reader.skipCurrentElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (periodic && timestamp.isValid())
|
||||||
|
map.insert(timestamp, sensors);
|
||||||
|
else if (!(std::isnan(lon) || std::isnan(lat))) {
|
||||||
|
Trackpoint t(Coordinates(rad2deg(lon), rad2deg(lat)));
|
||||||
|
t.setTimestamp(timestamp);
|
||||||
|
t.setElevation(altitude);
|
||||||
|
|
||||||
|
segment.append(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SMLParser::samples(SegmentData &segment)
|
||||||
|
{
|
||||||
|
QMap<QDateTime, Sensors> sensors;
|
||||||
|
QMap<QDateTime, Sensors>::const_iterator it;
|
||||||
|
|
||||||
|
while (_reader.readNextStartElement()) {
|
||||||
|
if (_reader.name() == QLatin1String("Sample")) {
|
||||||
|
sample(segment, sensors);
|
||||||
|
} else
|
||||||
|
_reader.skipCurrentElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < segment.size(); i++) {
|
||||||
|
Trackpoint &t = segment[i];
|
||||||
|
if ((it = sensors.lowerBound(t.timestamp())) != sensors.constEnd()) {
|
||||||
|
t.setCadence(it->cadence * 60);
|
||||||
|
t.setTemperature(it->temperature - 273.15);
|
||||||
|
t.setHeartRate(it->hr * 60);
|
||||||
|
t.setPower(it->power);
|
||||||
|
t.setSpeed(it->speed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SMLParser::deviceLog(TrackData &track)
|
||||||
|
{
|
||||||
|
while (_reader.readNextStartElement()) {
|
||||||
|
if (_reader.name() == QLatin1String("Samples")) {
|
||||||
|
track.append(SegmentData());
|
||||||
|
samples(track.last());
|
||||||
|
} else
|
||||||
|
_reader.skipCurrentElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SMLParser::sml(QList<TrackData> &tracks)
|
||||||
|
{
|
||||||
|
while (_reader.readNextStartElement()) {
|
||||||
|
if (_reader.name() == QLatin1String("DeviceLog")) {
|
||||||
|
tracks.append(TrackData());
|
||||||
|
deviceLog(tracks.last());
|
||||||
|
} else
|
||||||
|
_reader.skipCurrentElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SMLParser::parse(QFile *file, QList<TrackData> &tracks,
|
||||||
|
QList<RouteData> &routes, QList<Area> &polygons,
|
||||||
|
QVector<Waypoint> &waypoints)
|
||||||
|
{
|
||||||
|
Q_UNUSED(routes);
|
||||||
|
Q_UNUSED(polygons);
|
||||||
|
Q_UNUSED(waypoints);
|
||||||
|
|
||||||
|
_reader.clear();
|
||||||
|
_reader.setDevice(file);
|
||||||
|
|
||||||
|
if (_reader.readNextStartElement()) {
|
||||||
|
if (_reader.name() == QLatin1String("sml"))
|
||||||
|
sml(tracks);
|
||||||
|
else
|
||||||
|
_reader.raiseError("Not a SML file");
|
||||||
|
}
|
||||||
|
|
||||||
|
return !_reader.error();
|
||||||
|
}
|
38
src/data/smlparser.h
Normal file
38
src/data/smlparser.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#ifndef SMLPARSER_H
|
||||||
|
#define SMLPARSER_H
|
||||||
|
|
||||||
|
#include <QXmlStreamReader>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QDebug>
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
class SMLParser : public Parser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
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:
|
||||||
|
struct Sensors
|
||||||
|
{
|
||||||
|
Sensors()
|
||||||
|
: cadence(NAN), temperature(NAN), hr(NAN), power(NAN), speed(NAN) {}
|
||||||
|
|
||||||
|
qreal cadence, temperature, hr, power, speed;
|
||||||
|
};
|
||||||
|
|
||||||
|
void sml(QList<TrackData> &tracks);
|
||||||
|
void deviceLog(TrackData &track);
|
||||||
|
void samples(SegmentData &segment);
|
||||||
|
void sample(SegmentData &segment, QMap<QDateTime, Sensors> &map);
|
||||||
|
|
||||||
|
#ifndef QT_NO_DEBUG
|
||||||
|
friend QDebug operator<<(QDebug dbg, const Sensors &sensors);
|
||||||
|
#endif // QT_NO_DEBUG
|
||||||
|
|
||||||
|
QXmlStreamReader _reader;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SMLPARSER_H
|
@ -1,3 +1,4 @@
|
|||||||
|
#include "dem.h"
|
||||||
#include "track.h"
|
#include "track.h"
|
||||||
|
|
||||||
|
|
||||||
@ -7,13 +8,27 @@ int Track::_heartRateWindow = 3;
|
|||||||
int Track::_cadenceWindow = 3;
|
int Track::_cadenceWindow = 3;
|
||||||
int Track::_powerWindow = 3;
|
int Track::_powerWindow = 3;
|
||||||
|
|
||||||
|
bool Track::_automaticPause = true;
|
||||||
qreal Track::_pauseSpeed = 0.5;
|
qreal Track::_pauseSpeed = 0.5;
|
||||||
int Track::_pauseInterval = 10;
|
int Track::_pauseInterval = 10;
|
||||||
|
|
||||||
bool Track::_outlierEliminate = true;
|
bool Track::_outlierEliminate = true;
|
||||||
bool Track::_useReportedSpeed = false;
|
bool Track::_useReportedSpeed = false;
|
||||||
|
bool Track::_useDEM = false;
|
||||||
|
bool Track::_show2ndElevation = false;
|
||||||
|
bool Track::_show2ndSpeed = false;
|
||||||
|
|
||||||
|
|
||||||
|
static qreal avg(const QVector<qreal> &v)
|
||||||
|
{
|
||||||
|
qreal sum = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < v.size(); i++)
|
||||||
|
sum += v.at(i);
|
||||||
|
|
||||||
|
return sum/v.size();
|
||||||
|
}
|
||||||
|
|
||||||
static qreal median(QVector<qreal> &v)
|
static qreal median(QVector<qreal> &v)
|
||||||
{
|
{
|
||||||
qSort(v.begin(), v.end());
|
qSort(v.begin(), v.end());
|
||||||
@ -24,8 +39,7 @@ static qreal MAD(QVector<qreal> &v, qreal m)
|
|||||||
{
|
{
|
||||||
for (int i = 0; i < v.size(); i++)
|
for (int i = 0; i < v.size(); i++)
|
||||||
v[i] = qAbs(v.at(i) - m);
|
v[i] = qAbs(v.at(i) - m);
|
||||||
qSort(v.begin(), v.end());
|
return median(v);
|
||||||
return v.at(v.size() / 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static QSet<int> eliminate(const QVector<qreal> &v)
|
static QSet<int> eliminate(const QVector<qreal> &v)
|
||||||
@ -37,7 +51,7 @@ static QSet<int> eliminate(const QVector<qreal> &v)
|
|||||||
qreal M = MAD(w, m);
|
qreal M = MAD(w, m);
|
||||||
|
|
||||||
for (int i = 0; i < v.size(); i++)
|
for (int i = 0; i < v.size(); i++)
|
||||||
if (qAbs((0.6745 * (v.at(i) - m)) / M) > 5)
|
if (qAbs((0.6745 * (v.at(i) - m)) / M) > 3.5)
|
||||||
rm.insert(i);
|
rm.insert(i);
|
||||||
|
|
||||||
return rm;
|
return rm;
|
||||||
@ -132,17 +146,39 @@ Track::Track(const TrackData &data) : _data(data), _pause(0)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!hasTime)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
|
||||||
// get stop-points + pause duration
|
// get stop-points + pause duration
|
||||||
|
int pauseInterval;
|
||||||
|
qreal pauseSpeed;
|
||||||
|
|
||||||
|
if (_automaticPause) {
|
||||||
|
pauseSpeed = (avg(seg.speed) > 2.8) ? 0.40 : 0.15;
|
||||||
|
pauseInterval = 10;
|
||||||
|
} else {
|
||||||
|
pauseSpeed = _pauseSpeed;
|
||||||
|
pauseInterval = _pauseInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ss = 0, la = 0;
|
||||||
for (int j = 1; j < seg.time.size(); j++) {
|
for (int j = 1; j < seg.time.size(); j++) {
|
||||||
if (seg.time.at(j) > seg.time.at(j-1) + _pauseInterval
|
if (seg.speed.at(j) > pauseSpeed)
|
||||||
&& seg.speed.at(j) < _pauseSpeed) {
|
ss = -1;
|
||||||
_pause += seg.time.at(j) - seg.time.at(j-1);
|
else if (ss < 0)
|
||||||
seg.stop.insert(j-1);
|
ss = j-1;
|
||||||
seg.stop.insert(j);
|
|
||||||
|
if (ss >= 0 && seg.time.at(j) > seg.time.at(ss) + pauseInterval) {
|
||||||
|
int l = qMax(ss, la);
|
||||||
|
_pause += seg.time.at(j) - seg.time.at(l);
|
||||||
|
for (int k = l; k <= j; k++)
|
||||||
|
seg.stop.insert(k);
|
||||||
|
la = j;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_outlierEliminate || !hasTime)
|
if (!_outlierEliminate)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
||||||
@ -181,7 +217,7 @@ Track::Track(const TrackData &data) : _data(data), _pause(0)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Graph Track::elevation() const
|
Graph Track::gpsElevation() const
|
||||||
{
|
{
|
||||||
Graph ret;
|
Graph ret;
|
||||||
|
|
||||||
@ -205,7 +241,48 @@ Graph Track::elevation() const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Graph Track::speed() const
|
Graph Track::demElevation() const
|
||||||
|
{
|
||||||
|
Graph ret;
|
||||||
|
|
||||||
|
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++) {
|
||||||
|
qreal dem = DEM::elevation(sd.at(j).coordinates());
|
||||||
|
if (std::isnan(dem) || seg.outliers.contains(j))
|
||||||
|
continue;
|
||||||
|
gs.append(GraphPoint(seg.distance.at(j), seg.time.at(j), dem));
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.append(filter(gs, _elevationWindow));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
GraphPair Track::elevation() const
|
||||||
|
{
|
||||||
|
if (_useDEM) {
|
||||||
|
Graph dem(demElevation());
|
||||||
|
if (dem.isValid())
|
||||||
|
return GraphPair(dem, _show2ndElevation ? gpsElevation() : Graph());
|
||||||
|
else
|
||||||
|
return GraphPair(gpsElevation(), Graph());
|
||||||
|
} else {
|
||||||
|
Graph gps(gpsElevation());
|
||||||
|
if (gps.isValid())
|
||||||
|
return GraphPair(gps, _show2ndElevation ? demElevation() : Graph());
|
||||||
|
else
|
||||||
|
return GraphPair(demElevation(), Graph());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Graph Track::computedSpeed() const
|
||||||
{
|
{
|
||||||
Graph ret;
|
Graph ret;
|
||||||
|
|
||||||
@ -219,14 +296,10 @@ Graph Track::speed() const
|
|||||||
qreal v;
|
qreal v;
|
||||||
|
|
||||||
for (int j = 0; j < sd.size(); j++) {
|
for (int j = 0; j < sd.size(); j++) {
|
||||||
if (seg.stop.contains(j) && (!std::isnan(seg.speed.at(j))
|
if (seg.stop.contains(j) && !std::isnan(seg.speed.at(j))) {
|
||||||
|| sd.at(j).hasSpeed())) {
|
|
||||||
v = 0;
|
v = 0;
|
||||||
stop.append(gs.size());
|
stop.append(gs.size());
|
||||||
} else if (_useReportedSpeed && sd.at(j).hasSpeed()
|
} else if (!std::isnan(seg.speed.at(j)) && !seg.outliers.contains(j))
|
||||||
&& !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);
|
v = seg.speed.at(j);
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
@ -244,6 +317,60 @@ Graph Track::speed() const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Graph Track::reportedSpeed() const
|
||||||
|
{
|
||||||
|
Graph ret;
|
||||||
|
|
||||||
|
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;
|
||||||
|
QList<int> stop;
|
||||||
|
qreal v;
|
||||||
|
|
||||||
|
for (int j = 0; j < sd.size(); j++) {
|
||||||
|
if (seg.stop.contains(j) && sd.at(j).hasSpeed()) {
|
||||||
|
v = 0;
|
||||||
|
stop.append(gs.size());
|
||||||
|
} else if (sd.at(j).hasSpeed() && !seg.outliers.contains(j))
|
||||||
|
v = sd.at(j).speed();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
GraphPair Track::speed() const
|
||||||
|
{
|
||||||
|
if (_useReportedSpeed) {
|
||||||
|
Graph reported(reportedSpeed());
|
||||||
|
if (reported.isValid())
|
||||||
|
return GraphPair(reported, _show2ndSpeed ? computedSpeed()
|
||||||
|
: Graph());
|
||||||
|
else
|
||||||
|
return GraphPair(computedSpeed(), Graph());
|
||||||
|
} else {
|
||||||
|
Graph computed(computedSpeed());
|
||||||
|
if (computed.isValid())
|
||||||
|
return GraphPair(computed, _show2ndSpeed ? reportedSpeed()
|
||||||
|
: Graph());
|
||||||
|
else
|
||||||
|
return GraphPair(reportedSpeed(), Graph());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Graph Track::heartRate() const
|
Graph Track::heartRate() const
|
||||||
{
|
{
|
||||||
Graph ret;
|
Graph ret;
|
||||||
|
@ -17,8 +17,8 @@ public:
|
|||||||
|
|
||||||
Path path() const;
|
Path path() const;
|
||||||
|
|
||||||
Graph elevation() const;
|
GraphPair elevation() const;
|
||||||
Graph speed() const;
|
GraphPair speed() const;
|
||||||
Graph heartRate() const;
|
Graph heartRate() const;
|
||||||
Graph temperature() const;
|
Graph temperature() const;
|
||||||
Graph cadence() const;
|
Graph cadence() const;
|
||||||
@ -32,6 +32,7 @@ public:
|
|||||||
|
|
||||||
const QString &name() const {return _data.name();}
|
const QString &name() const {return _data.name();}
|
||||||
const QString &description() const {return _data.description();}
|
const QString &description() const {return _data.description();}
|
||||||
|
const QString &comment() const {return _data.comment();}
|
||||||
const QVector<Link> &links() const {return _data.links();}
|
const QVector<Link> &links() const {return _data.links();}
|
||||||
|
|
||||||
bool isValid() const;
|
bool isValid() const;
|
||||||
@ -41,11 +42,17 @@ public:
|
|||||||
static void setHeartRateFilter(int window) {_heartRateWindow = window;}
|
static void setHeartRateFilter(int window) {_heartRateWindow = window;}
|
||||||
static void setCadenceFilter(int window) {_cadenceWindow = window;}
|
static void setCadenceFilter(int window) {_cadenceWindow = window;}
|
||||||
static void setPowerFilter(int window) {_powerWindow = window;}
|
static void setPowerFilter(int window) {_powerWindow = window;}
|
||||||
|
static void setAutomaticPause(bool set) {_automaticPause = set;}
|
||||||
static void setPauseSpeed(qreal speed) {_pauseSpeed = speed;}
|
static void setPauseSpeed(qreal speed) {_pauseSpeed = speed;}
|
||||||
static void setPauseInterval(int interval) {_pauseInterval = interval;}
|
static void setPauseInterval(int interval) {_pauseInterval = interval;}
|
||||||
static void setOutlierElimination(bool eliminate)
|
static void setOutlierElimination(bool eliminate)
|
||||||
{_outlierEliminate = eliminate;}
|
{_outlierEliminate = eliminate;}
|
||||||
static void useReportedSpeed(bool use) {_useReportedSpeed = use;}
|
static void useReportedSpeed(bool use) {_useReportedSpeed = use;}
|
||||||
|
static void useDEM(bool use) {_useDEM = use;}
|
||||||
|
static void showSecondaryElevation(bool show)
|
||||||
|
{_show2ndElevation = show;}
|
||||||
|
static void showSecondarySpeed(bool show)
|
||||||
|
{_show2ndSpeed = show;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Segment {
|
struct Segment {
|
||||||
@ -58,6 +65,11 @@ private:
|
|||||||
|
|
||||||
bool discardStopPoint(const Segment &seg, int i) const;
|
bool discardStopPoint(const Segment &seg, int i) const;
|
||||||
|
|
||||||
|
Graph demElevation() const;
|
||||||
|
Graph gpsElevation() const;
|
||||||
|
Graph reportedSpeed() const;
|
||||||
|
Graph computedSpeed() const;
|
||||||
|
|
||||||
TrackData _data;
|
TrackData _data;
|
||||||
QList<Segment> _segments;
|
QList<Segment> _segments;
|
||||||
qreal _pause;
|
qreal _pause;
|
||||||
@ -68,9 +80,13 @@ private:
|
|||||||
static int _heartRateWindow;
|
static int _heartRateWindow;
|
||||||
static int _cadenceWindow;
|
static int _cadenceWindow;
|
||||||
static int _powerWindow;
|
static int _powerWindow;
|
||||||
|
static bool _automaticPause;
|
||||||
static qreal _pauseSpeed;
|
static qreal _pauseSpeed;
|
||||||
static int _pauseInterval;
|
static int _pauseInterval;
|
||||||
static bool _useReportedSpeed;
|
static bool _useReportedSpeed;
|
||||||
|
static bool _useDEM;
|
||||||
|
static bool _show2ndElevation;
|
||||||
|
static bool _show2ndSpeed;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TRACK_H
|
#endif // TRACK_H
|
||||||
|
@ -14,15 +14,18 @@ class TrackData : public QList<SegmentData>
|
|||||||
public:
|
public:
|
||||||
const QString &name() const {return _name;}
|
const QString &name() const {return _name;}
|
||||||
const QString &description() const {return _desc;}
|
const QString &description() const {return _desc;}
|
||||||
|
const QString &comment() const {return _comment;}
|
||||||
const QVector<Link> &links() const {return _links;}
|
const QVector<Link> &links() const {return _links;}
|
||||||
|
|
||||||
void setName(const QString &name) {_name = name;}
|
void setName(const QString &name) {_name = name;}
|
||||||
void setDescription(const QString &desc) {_desc = desc;}
|
void setDescription(const QString &desc) {_desc = desc;}
|
||||||
|
void setComment(const QString &comment) {_comment = comment;}
|
||||||
void addLink(const Link &link) {_links.append(link);}
|
void addLink(const Link &link) {_links.append(link);}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString _name;
|
QString _name;
|
||||||
QString _desc;
|
QString _desc;
|
||||||
|
QString _comment;
|
||||||
QVector<Link> _links;
|
QVector<Link> _links;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
23
src/data/waypoint.cpp
Normal file
23
src/data/waypoint.cpp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#include "dem.h"
|
||||||
|
#include "waypoint.h"
|
||||||
|
|
||||||
|
bool Waypoint::_useDEM = false;
|
||||||
|
bool Waypoint::_show2ndElevation = false;
|
||||||
|
|
||||||
|
QPair<qreal, qreal> Waypoint::elevations() const
|
||||||
|
{
|
||||||
|
if (_useDEM) {
|
||||||
|
qreal dem = DEM::elevation(coordinates());
|
||||||
|
if (!std::isnan(dem))
|
||||||
|
return QPair<qreal, qreal>(dem, _show2ndElevation ? elevation()
|
||||||
|
: NAN);
|
||||||
|
else
|
||||||
|
return QPair<qreal, qreal>(elevation(), NAN);
|
||||||
|
} else {
|
||||||
|
if (hasElevation())
|
||||||
|
return QPair<qreal, qreal>(elevation(), _show2ndElevation
|
||||||
|
? DEM::elevation(coordinates()) : NAN);
|
||||||
|
else
|
||||||
|
return QPair<qreal, qreal>(DEM::elevation(coordinates()), NAN);
|
||||||
|
}
|
||||||
|
}
|
@ -4,34 +4,42 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
|
#include <QVector>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include "common/coordinates.h"
|
#include "common/coordinates.h"
|
||||||
#include "imageinfo.h"
|
#include "imageinfo.h"
|
||||||
#include "link.h"
|
#include "link.h"
|
||||||
|
#include "address.h"
|
||||||
|
|
||||||
class Waypoint
|
class Waypoint
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Waypoint() {_elevation = NAN;}
|
Waypoint() : _elevation(NAN) {}
|
||||||
Waypoint(const Coordinates &coordinates) : _coordinates(coordinates)
|
Waypoint(const Coordinates &coordinates)
|
||||||
{_elevation = NAN;}
|
: _coordinates(coordinates), _elevation(NAN) {}
|
||||||
|
|
||||||
const Coordinates &coordinates() const {return _coordinates;}
|
const Coordinates &coordinates() const {return _coordinates;}
|
||||||
const QString &name() const {return _name;}
|
const QString &name() const {return _name;}
|
||||||
const QString &description() const {return _description;}
|
const QString &description() const {return _description;}
|
||||||
const ImageInfo &image() const {return _image;}
|
const QString &comment() const {return _comment;}
|
||||||
|
const Address &address() const {return _address;}
|
||||||
|
const QVector<ImageInfo> &images() const {return _images;}
|
||||||
const QVector<Link> &links() const {return _links;}
|
const QVector<Link> &links() const {return _links;}
|
||||||
const QDateTime ×tamp() const {return _timestamp;}
|
const QDateTime ×tamp() const {return _timestamp;}
|
||||||
qreal elevation() const {return _elevation;}
|
qreal elevation() const {return _elevation;}
|
||||||
|
|
||||||
|
QPair<qreal, qreal> elevations() const;
|
||||||
|
|
||||||
void setCoordinates(const Coordinates &coordinates)
|
void setCoordinates(const Coordinates &coordinates)
|
||||||
{_coordinates = coordinates;}
|
{_coordinates = coordinates;}
|
||||||
void setName(const QString &name) {_name = name;}
|
void setName(const QString &name) {_name = name;}
|
||||||
void setDescription(const QString &description)
|
void setDescription(const QString &description)
|
||||||
{_description = description;}
|
{_description = description;}
|
||||||
|
void setComment(const QString &comment) {_comment = comment;}
|
||||||
|
void setAddress(const Address &address) {_address = address;}
|
||||||
void setTimestamp(const QDateTime ×tamp) {_timestamp = timestamp;}
|
void setTimestamp(const QDateTime ×tamp) {_timestamp = timestamp;}
|
||||||
void setElevation(qreal elevation) {_elevation = elevation;}
|
void setElevation(qreal elevation) {_elevation = elevation;}
|
||||||
void setImage(const ImageInfo &image) {_image = image;}
|
void addImage(const ImageInfo &image) {_images.append(image);}
|
||||||
void addLink(const Link &link) {_links.append(link);}
|
void addLink(const Link &link) {_links.append(link);}
|
||||||
|
|
||||||
bool hasElevation() const {return !std::isnan(_elevation);}
|
bool hasElevation() const {return !std::isnan(_elevation);}
|
||||||
@ -40,14 +48,23 @@ public:
|
|||||||
{return this->_name == other._name
|
{return this->_name == other._name
|
||||||
&& this->_coordinates == other._coordinates;}
|
&& this->_coordinates == other._coordinates;}
|
||||||
|
|
||||||
|
static void useDEM(bool use) {_useDEM = use;}
|
||||||
|
static void showSecondaryElevation(bool show)
|
||||||
|
{_show2ndElevation = show;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Coordinates _coordinates;
|
Coordinates _coordinates;
|
||||||
QString _name;
|
QString _name;
|
||||||
QString _description;
|
QString _description;
|
||||||
ImageInfo _image;
|
QString _comment;
|
||||||
|
Address _address;
|
||||||
|
QVector<ImageInfo> _images;
|
||||||
QVector<Link> _links;
|
QVector<Link> _links;
|
||||||
QDateTime _timestamp;
|
QDateTime _timestamp;
|
||||||
qreal _elevation;
|
qreal _elevation;
|
||||||
|
|
||||||
|
static bool _useDEM;
|
||||||
|
static bool _show2ndElevation;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline uint qHash(const Waypoint &key)
|
inline uint qHash(const Waypoint &key)
|
||||||
@ -59,11 +76,9 @@ inline uint qHash(const Waypoint &key)
|
|||||||
inline QDebug operator<<(QDebug dbg, const Waypoint &waypoint)
|
inline QDebug operator<<(QDebug dbg, const Waypoint &waypoint)
|
||||||
{
|
{
|
||||||
dbg.nospace() << "Waypoint(" << waypoint.coordinates() << ", "
|
dbg.nospace() << "Waypoint(" << waypoint.coordinates() << ", "
|
||||||
<< waypoint.name() << ", " << waypoint.description() << ")";
|
<< waypoint.name() << ")";
|
||||||
return dbg.space();
|
return dbg.space();
|
||||||
}
|
}
|
||||||
#endif // QT_NO_DEBUG
|
#endif // QT_NO_DEBUG
|
||||||
|
|
||||||
Q_DECLARE_TYPEINFO(Waypoint, Q_MOVABLE_TYPE);
|
|
||||||
|
|
||||||
#endif // WAYPOINT_H
|
#endif // WAYPOINT_H
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
||||||
|
#include <QtCore/qmath.h>
|
||||||
|
#else // QT5
|
||||||
|
#include <QtMath>
|
||||||
|
#endif // QT5
|
||||||
#include "bitmapline.h"
|
#include "bitmapline.h"
|
||||||
|
|
||||||
|
|
||||||
static QImage img2line(const QImage &img, int width)
|
static QImage img2line(const QImage &img, int width)
|
||||||
{
|
{
|
||||||
Q_ASSERT(img.format() == QImage::Format_ARGB32_Premultiplied);
|
Q_ASSERT(img.format() == QImage::Format_ARGB32_Premultiplied);
|
||||||
@ -32,8 +38,8 @@ void BitmapLine::draw(QPainter *painter, const QPolygonF &line,
|
|||||||
painter->save();
|
painter->save();
|
||||||
painter->translate(segment.p1());
|
painter->translate(segment.p1());
|
||||||
painter->rotate(-segment.angle());
|
painter->rotate(-segment.angle());
|
||||||
painter->drawImage(0, -img.height()/2, img2line(img, segment.length()));
|
painter->drawImage(0.0, -img.height()/2.0, img2line(img,
|
||||||
|
qCeil(segment.length())));
|
||||||
painter->restore();
|
painter->restore();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user