mirror of
https://github.com/tumic0/GPXSee.git
synced 2025-07-18 04:44:23 +02:00
Compare commits
187 Commits
Author | SHA1 | Date | |
---|---|---|---|
cbe312d9c8 | |||
08334d7fde | |||
33bbd6a592 | |||
7811527239 | |||
31da4e1906 | |||
652cbd7c11 | |||
eb0ff84379 | |||
6ee3a8ea8d | |||
ee3d43e249 | |||
242babb741 | |||
e26d1abd5a | |||
e80d16bec5 | |||
412ae74bfa | |||
1c472e47b9 | |||
4a725375e2 | |||
383a196414 | |||
f05b51efa6 | |||
a56c02953f | |||
00d3849e4f | |||
c9244c0684 | |||
d94938261a | |||
d5fc06d9d1 | |||
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 | |||
b50d5227a5 | |||
f38db3227f | |||
c3aeb95660 | |||
6bdd97611d | |||
15e09539c7 | |||
a225c6d308 | |||
a94056ac7e | |||
aea7bbdf09 | |||
1c9b31d7c9 | |||
7a9b26756a | |||
eaae965719 | |||
ca6e8638d8 | |||
66a22fbfee | |||
2d3ca7c5f8 | |||
8c71d11fa6 | |||
857c5050f4 | |||
44d1d27c93 | |||
68e20cff5b | |||
1c67f1cac9 | |||
a09d13594d | |||
6916d0e6b4 | |||
757ec98108 | |||
2ddb5dc28b |
@ -1,4 +1,4 @@
|
|||||||
version: 7.20.{build}
|
version: 7.29.{build}
|
||||||
|
|
||||||
configuration:
|
configuration:
|
||||||
- Release
|
- Release
|
||||||
@ -17,7 +17,7 @@ environment:
|
|||||||
LIBSSL: libcrypto-1_1.dll
|
LIBSSL: libcrypto-1_1.dll
|
||||||
- QTDIR: C:\Qt\5.13\msvc2017_64
|
- QTDIR: C:\Qt\5.13\msvc2017_64
|
||||||
NSI: gpxsee64.nsi
|
NSI: gpxsee64.nsi
|
||||||
VCVARS: vcvars64.bat"
|
VCVARS: vcvars64.bat
|
||||||
OPENSSLDIR: C:\OpenSSL-v111-Win64\bin
|
OPENSSLDIR: C:\OpenSSL-v111-Win64\bin
|
||||||
LIBCRYPTO: libssl-1_1-x64.dll
|
LIBCRYPTO: libssl-1_1-x64.dll
|
||||||
LIBSSL: libcrypto-1_1-x64.dll
|
LIBSSL: libcrypto-1_1-x64.dll
|
||||||
|
@ -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.
|
||||||
|
14
gpxsee.pro
14
gpxsee.pro
@ -3,7 +3,7 @@ unix:!macx {
|
|||||||
} else {
|
} else {
|
||||||
TARGET = GPXSee
|
TARGET = GPXSee
|
||||||
}
|
}
|
||||||
VERSION = 7.20
|
VERSION = 7.29
|
||||||
|
|
||||||
QT += core \
|
QT += core \
|
||||||
gui \
|
gui \
|
||||||
@ -20,6 +20,7 @@ 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/garmin.h \
|
||||||
src/common/staticassert.h \
|
src/common/staticassert.h \
|
||||||
@ -91,8 +92,10 @@ HEADERS += src/common/config.h \
|
|||||||
src/map/IMG/bitmapline.h \
|
src/map/IMG/bitmapline.h \
|
||||||
src/map/IMG/bitstream.h \
|
src/map/IMG/bitstream.h \
|
||||||
src/map/IMG/deltastream.h \
|
src/map/IMG/deltastream.h \
|
||||||
|
src/map/IMG/gmap.h \
|
||||||
src/map/IMG/huffmanstream.h \
|
src/map/IMG/huffmanstream.h \
|
||||||
src/map/IMG/huffmantable.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 \
|
||||||
@ -246,11 +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/bitstream.cpp \
|
||||||
src/map/IMG/deltastream.cpp \
|
src/map/IMG/deltastream.cpp \
|
||||||
|
src/map/IMG/gmap.cpp \
|
||||||
src/map/IMG/huffmanstream.cpp \
|
src/map/IMG/huffmanstream.cpp \
|
||||||
src/map/IMG/huffmantable.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 \
|
||||||
@ -359,7 +365,8 @@ TRANSLATIONS = lang/gpxsee_en.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_uk.ts \
|
||||||
|
lang/gpxsee_hu.ts
|
||||||
|
|
||||||
macx {
|
macx {
|
||||||
ICON = icons/gpxsee.icns
|
ICON = icons/gpxsee.icns
|
||||||
@ -378,7 +385,8 @@ macx {
|
|||||||
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_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
|
||||||
|
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
1923
lang/gpxsee_hu.ts
Normal file
1923
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
File diff suppressed because it is too large
Load Diff
@ -4,6 +4,7 @@ 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[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
|
||||||
@ -14,4 +15,4 @@ 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;application/vnd.garmin.gpi;
|
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.20"
|
!define VERSION "7.29"
|
||||||
|
|
||||||
; The file to write
|
; The file to write
|
||||||
OutFile "GPXSee-${VERSION}.exe"
|
OutFile "GPXSee-${VERSION}.exe"
|
||||||
@ -176,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"
|
||||||
|
@ -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.20"
|
!define VERSION "7.29"
|
||||||
|
|
||||||
; The file to write
|
; The file to write
|
||||||
OutFile "GPXSee-${VERSION}_x64.exe"
|
OutFile "GPXSee-${VERSION}_x64.exe"
|
||||||
@ -183,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"
|
||||||
|
@ -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>4UMaps</name>
|
<name>4UMaps</name>
|
||||||
<url>https://tileserver.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"/>
|
||||||
|
@ -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,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 Street Map</name>
|
<name>Open Street Map</name>
|
||||||
<url>https://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>
|
||||||
|
@ -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"/>
|
||||||
|
@ -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,36 +65,39 @@ 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);
|
||||||
|
|
||||||
|
if (primary) {
|
||||||
_trackAscent += gi->ascent();
|
_trackAscent += gi->ascent();
|
||||||
_trackDescent += gi->descent();
|
_trackDescent += gi->descent();
|
||||||
_trackMax = nMax(_trackMax, gi->max());
|
_trackMax = nMax(_trackMax, gi->max());
|
||||||
_trackMin = nMin(_trackMin, gi->min());
|
_trackMin = nMin(_trackMin, gi->min());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
_routes.append(gi);
|
_routes.append(gi);
|
||||||
if (_showRoutes)
|
if (_showRoutes)
|
||||||
addGraph(gi);
|
addGraph(gi);
|
||||||
|
|
||||||
|
if (primary) {
|
||||||
_routeAscent += gi->ascent();
|
_routeAscent += gi->ascent();
|
||||||
_routeDescent += gi->descent();
|
_routeDescent += gi->descent();
|
||||||
_routeMax = nMax(_routeMax, gi->max());
|
_routeMax = nMax(_routeMax, gi->max());
|
||||||
_routeMin = nMin(_routeMin, gi->min());
|
_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);
|
||||||
|
@ -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
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include <QSet>
|
||||||
#include <QGraphicsScene>
|
#include <QGraphicsScene>
|
||||||
#include <QEvent>
|
#include <QEvent>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
@ -274,8 +275,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 +420,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 +439,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)
|
||||||
@ -486,8 +495,23 @@ void GraphView::setPalette(const Palette &palette)
|
|||||||
_palette = palette;
|
_palette = palette;
|
||||||
_palette.reset();
|
_palette.reset();
|
||||||
|
|
||||||
for (int i = 0; i < _graphs.count(); i++)
|
QSet<GraphItem*> secondary;
|
||||||
_graphs.at(i)->setColor(_palette.nextColor());
|
for (int i = 0; i < _graphs.count(); i++) {
|
||||||
|
GraphItem *g = _graphs[i];
|
||||||
|
if (g->secondaryGraph())
|
||||||
|
secondary.insert(g->secondaryGraph());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < _graphs.count(); i++) {
|
||||||
|
GraphItem *g = _graphs[i];
|
||||||
|
if (secondary.contains(g))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
QColor color(_palette.nextColor());
|
||||||
|
g->setColor(color);
|
||||||
|
if (g->secondaryGraph())
|
||||||
|
g->secondaryGraph()->setColor(color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphView::setGraphWidth(int width)
|
void GraphView::setGraphWidth(int width)
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#include <QGraphicsView>
|
#include <QGraphicsView>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QSet>
|
|
||||||
#include "data/graph.h"
|
#include "data/graph.h"
|
||||||
#include "palette.h"
|
#include "palette.h"
|
||||||
#include "units.h"
|
#include "units.h"
|
||||||
|
219
src/GUI/gui.cpp
219
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);
|
||||||
@ -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);
|
||||||
@ -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; \
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -953,13 +962,18 @@ void GUI::openOptions()
|
|||||||
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);
|
||||||
@ -1322,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);
|
_showMapAction->setEnabled(true);
|
||||||
_clearMapCacheAction->setEnabled(true);
|
_clearMapCacheAction->setEnabled(true);
|
||||||
a->trigger();
|
} else
|
||||||
|
connect(a, SIGNAL(loaded()), this, SLOT(mapLoaded()));
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
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);
|
||||||
|
_clearMapCacheAction->setEnabled(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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1379,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)
|
||||||
@ -1809,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
|
||||||
@ -1896,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()) {
|
||||||
@ -2075,14 +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,
|
_options.automaticPause = settings.value(AUTOMATIC_PAUSE_SETTING,
|
||||||
AUTOMATIC_PAUSE_DEFAULT).toBool();
|
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
|
||||||
@ -2162,21 +2224,38 @@ void GUI::readSettings()
|
|||||||
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();
|
||||||
|
|
||||||
@ -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->isReady());
|
||||||
|
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"
|
||||||
@ -406,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"));
|
||||||
@ -413,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);
|
||||||
@ -438,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);
|
||||||
@ -465,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);
|
||||||
@ -486,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);
|
||||||
@ -718,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
|
||||||
|
@ -54,9 +54,10 @@ struct Options {
|
|||||||
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
|
||||||
@ -142,10 +143,10 @@ private:
|
|||||||
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;
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -145,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,20 +40,14 @@ void SpeedGraph::setInfo()
|
|||||||
clearInfo();
|
clearInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<GraphItem*> SpeedGraph::loadData(const Data &data)
|
GraphItem *SpeedGraph::loadGraph(const Graph &graph, const Track &track,
|
||||||
|
const QColor &color, bool primary)
|
||||||
{
|
{
|
||||||
QList<GraphItem*> graphs;
|
if (!graph.isValid())
|
||||||
|
return 0;
|
||||||
|
|
||||||
for (int i = 0; i < data.tracks().count(); i++) {
|
|
||||||
const Track &track = data.tracks().at(i);
|
|
||||||
const Graph &graph = track.speed();
|
|
||||||
|
|
||||||
if (!graph.isValid()) {
|
|
||||||
_palette.nextColor();
|
|
||||||
graphs.append(0);
|
|
||||||
} else {
|
|
||||||
SpeedGraphItem *gi = new SpeedGraphItem(graph, _graphType, _width,
|
SpeedGraphItem *gi = new SpeedGraphItem(graph, _graphType, _width,
|
||||||
_palette.nextColor(), track.movingTime());
|
color, primary ? Qt::SolidLine : Qt::DashLine, track.movingTime());
|
||||||
gi->setTimeType(_timeType);
|
gi->setTimeType(_timeType);
|
||||||
gi->setUnits(_units);
|
gi->setUnits(_units);
|
||||||
|
|
||||||
@ -61,10 +55,31 @@ QList<GraphItem*> SpeedGraph::loadData(const Data &data)
|
|||||||
if (_showTracks)
|
if (_showTracks)
|
||||||
addGraph(gi);
|
addGraph(gi);
|
||||||
|
|
||||||
|
if (primary) {
|
||||||
_avg.append(QPointF(track.distance(), gi->avg()));
|
_avg.append(QPointF(track.distance(), gi->avg()));
|
||||||
_mavg.append(QPointF(track.distance(), gi->mavg()));
|
_mavg.append(QPointF(track.distance(), gi->mavg()));
|
||||||
graphs.append(gi);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return gi;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<GraphItem*> SpeedGraph::loadData(const Data &data)
|
||||||
|
{
|
||||||
|
QList<GraphItem*> graphs;
|
||||||
|
|
||||||
|
for (int i = 0; i < data.tracks().count(); i++) {
|
||||||
|
GraphItem *primary, *secondary;
|
||||||
|
QColor color(_palette.nextColor());
|
||||||
|
const Track &track = data.tracks().at(i);
|
||||||
|
const GraphPair &gp = track.speed();
|
||||||
|
|
||||||
|
primary = loadGraph(gp.primary(), track, color, true);
|
||||||
|
secondary = primary
|
||||||
|
? loadGraph(gp.secondary(), track, color, false) : 0;
|
||||||
|
if (primary && secondary)
|
||||||
|
primary->setSecondaryGraph(secondary);
|
||||||
|
|
||||||
|
graphs.append(primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
||||||
|
@ -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,23 @@ 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()) {
|
if (_waypoint.address().isValid()) {
|
||||||
QString addr("<address>");
|
QString addr("<address>");
|
||||||
addr += _waypoint.address().street();
|
addr += _waypoint.address().street();
|
||||||
|
@ -14,8 +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() << qSetRealNumberPrecision(10) << "Coordinates(" << c.lat()
|
dbg.nospace() << qSetRealNumberPrecision(10) << "Coordinates(" << c.lon()
|
||||||
<< ", " << c.lon() << ")";
|
<< ", " << c.lat() << ")";
|
||||||
return dbg.space();
|
return dbg.space();
|
||||||
}
|
}
|
||||||
#endif // QT_NO_DEBUG
|
#endif // QT_NO_DEBUG
|
||||||
|
@ -3,14 +3,16 @@
|
|||||||
|
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
#define LS(val, bits) ((qint32)(((quint32)(val))<<(bits)))
|
||||||
|
|
||||||
inline double toWGS32(qint32 v)
|
inline double toWGS32(qint32 v)
|
||||||
{
|
{
|
||||||
return (double)(((double)v / (double)(1U<<31)) * (double)180);
|
return ((double)v / (double)(1U<<31)) * 180.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline double toWGS24(qint32 v)
|
inline double toWGS24(qint32 v)
|
||||||
{
|
{
|
||||||
return toWGS32(v<<8);
|
return toWGS32(LS(v, 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // GARMIN_H
|
#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;}
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
#include "cupparser.h"
|
#include "cupparser.h"
|
||||||
#include "gpiparser.h"
|
#include "gpiparser.h"
|
||||||
#include "smlparser.h"
|
#include "smlparser.h"
|
||||||
#include "dem.h"
|
|
||||||
#include "data.h"
|
#include "data.h"
|
||||||
|
|
||||||
|
|
||||||
@ -44,78 +43,46 @@ static CUPParser cup;
|
|||||||
static GPIParser gpi;
|
static GPIParser gpi;
|
||||||
static SMLParser sml;
|
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);
|
||||||
hash.insert("sml", &sml);
|
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);
|
||||||
@ -130,11 +97,10 @@ 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;
|
||||||
@ -146,7 +112,6 @@ 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;
|
||||||
@ -166,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);;"
|
||||||
@ -200,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
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#define RECORD_MESSAGE 20
|
#define RECORD_MESSAGE 20
|
||||||
#define EVENT_MESSAGE 21
|
#define EVENT_MESSAGE 21
|
||||||
|
#define COURSE_POINT 32
|
||||||
#define TIMESTAMP_FIELD 253
|
#define TIMESTAMP_FIELD 253
|
||||||
|
|
||||||
class Event {
|
class Event {
|
||||||
@ -48,10 +49,12 @@ public:
|
|||||||
|
|
||||||
class FITParser::CTX {
|
class FITParser::CTX {
|
||||||
public:
|
public:
|
||||||
CTX(QFile *file) : file(file), len(0), endian(0), timestamp(0),
|
CTX(QFile *file, QVector<Waypoint> &waypoints)
|
||||||
|
: file(file), waypoints(waypoints), len(0), endian(0), timestamp(0),
|
||||||
lastWrite(0), ratio(NAN) {}
|
lastWrite(0), ratio(NAN) {}
|
||||||
|
|
||||||
QFile *file;
|
QFile *file;
|
||||||
|
QVector<Waypoint> &waypoints;
|
||||||
quint32 len;
|
quint32 len;
|
||||||
quint8 endian;
|
quint8 endian;
|
||||||
quint32 timestamp, lastWrite;
|
quint32 timestamp, lastWrite;
|
||||||
@ -61,6 +64,41 @@ public:
|
|||||||
SegmentData segment;
|
SegmentData segment;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static QMap<int, QString> coursePointDescInit()
|
||||||
|
{
|
||||||
|
QMap<int, QString> map;
|
||||||
|
|
||||||
|
map.insert(1, "Summit");
|
||||||
|
map.insert(2, "Valley");
|
||||||
|
map.insert(3, "Water");
|
||||||
|
map.insert(4, "Food");
|
||||||
|
map.insert(5, "Danger");
|
||||||
|
map.insert(6, "Left");
|
||||||
|
map.insert(7, "Right");
|
||||||
|
map.insert(8, "Straight");
|
||||||
|
map.insert(9, "First aid");
|
||||||
|
map.insert(10, "Fourth category");
|
||||||
|
map.insert(11, "Third category");
|
||||||
|
map.insert(12, "Second category");
|
||||||
|
map.insert(13, "First category");
|
||||||
|
map.insert(14, "Hors category");
|
||||||
|
map.insert(15, "Sprint");
|
||||||
|
map.insert(16, "Left fork");
|
||||||
|
map.insert(17, "Right fork");
|
||||||
|
map.insert(18, "Middle fork");
|
||||||
|
map.insert(19, "Slight left");
|
||||||
|
map.insert(20, "Sharp left");
|
||||||
|
map.insert(21, "Slight right");
|
||||||
|
map.insert(22, "Sharp right");
|
||||||
|
map.insert(23, "U-Turn");
|
||||||
|
map.insert(24, "Segment start");
|
||||||
|
map.insert(25, "Segment end");
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QMap<int, QString> coursePointDesc = coursePointDescInit();
|
||||||
|
|
||||||
|
|
||||||
bool FITParser::readData(QFile *file, char *data, size_t size)
|
bool FITParser::readData(QFile *file, char *data, size_t size)
|
||||||
{
|
{
|
||||||
@ -80,17 +118,12 @@ bool FITParser::readData(QFile *file, char *data, size_t size)
|
|||||||
|
|
||||||
template<class T> bool FITParser::readValue(CTX &ctx, T &val)
|
template<class T> bool FITParser::readValue(CTX &ctx, T &val)
|
||||||
{
|
{
|
||||||
T data;
|
if (!readData(ctx.file, (char*)&val, sizeof(T)))
|
||||||
|
|
||||||
if (!readData(ctx.file, (char*)&data, sizeof(T)))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ctx.len -= sizeof(T);
|
ctx.len -= sizeof(T);
|
||||||
|
if (sizeof(T) > 1)
|
||||||
if (ctx.endian)
|
val = (ctx.endian) ? qFromBigEndian(val) : qFromLittleEndian(val);
|
||||||
val = qFromBigEndian(data);
|
|
||||||
else
|
|
||||||
val = qFromLittleEndian(data);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -167,41 +200,51 @@ bool FITParser::parseDefinitionMessage(CTX &ctx, quint8 header)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FITParser::readField(CTX &ctx, Field *field, quint32 &val)
|
bool FITParser::readField(CTX &ctx, Field *field, QVariant &val, bool &valid)
|
||||||
{
|
{
|
||||||
quint8 v8 = (quint8)-1;
|
|
||||||
quint16 v16 = (quint16)-1;
|
|
||||||
bool ret;
|
bool ret;
|
||||||
|
|
||||||
val = (quint32)-1;
|
#define VAL(type, inval) \
|
||||||
|
{type var; \
|
||||||
|
if (field->size == sizeof(var)) { \
|
||||||
|
ret = readValue(ctx, var); \
|
||||||
|
val = var; \
|
||||||
|
valid = (var != (inval)); \
|
||||||
|
} else { \
|
||||||
|
ret = skipValue(ctx, field->size); \
|
||||||
|
valid = false; \
|
||||||
|
}}
|
||||||
|
|
||||||
switch (field->type) {
|
switch (field->type) {
|
||||||
case 0: // enum
|
|
||||||
case 1: // sint8
|
case 1: // sint8
|
||||||
|
VAL(qint8, 0x7fU);
|
||||||
|
break;
|
||||||
case 2: // uint8
|
case 2: // uint8
|
||||||
if (field->size == 1) {
|
case 0: // enum
|
||||||
ret = readValue(ctx, v8);
|
VAL(quint8, 0xffU);
|
||||||
val = v8;
|
break;
|
||||||
} else
|
case 7: // UTF8 nul terminated string
|
||||||
ret = skipValue(ctx, field->size);
|
{QByteArray ba(ctx.file->read(field->size));
|
||||||
|
ctx.len -= field->size;
|
||||||
|
ret = (ba.size() == field->size);
|
||||||
|
val = ret ? ba : QString();
|
||||||
|
valid = !ba.isEmpty();}
|
||||||
break;
|
break;
|
||||||
case 0x83: // sint16
|
case 0x83: // sint16
|
||||||
|
VAL(qint16, 0x7fffU);
|
||||||
|
break;
|
||||||
case 0x84: // uint16
|
case 0x84: // uint16
|
||||||
if (field->size == 2) {
|
VAL(quint16, 0xffffU);
|
||||||
ret = readValue(ctx, v16);
|
|
||||||
val = v16;
|
|
||||||
} else
|
|
||||||
ret = skipValue(ctx, field->size);
|
|
||||||
break;
|
break;
|
||||||
case 0x85: // sint32
|
case 0x85: // sint32
|
||||||
|
VAL(qint32, 0x7fffffffU);
|
||||||
|
break;
|
||||||
case 0x86: // uint32
|
case 0x86: // uint32
|
||||||
if (field->size == 4)
|
VAL(quint32, 0xffffffffU);
|
||||||
ret = readValue(ctx, val);
|
|
||||||
else
|
|
||||||
ret = skipValue(ctx, field->size);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = skipValue(ctx, field->size);
|
ret = skipValue(ctx, field->size);
|
||||||
|
valid = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,8 +254,10 @@ bool FITParser::readField(CTX &ctx, Field *field, quint32 &val)
|
|||||||
bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
||||||
{
|
{
|
||||||
Field *field;
|
Field *field;
|
||||||
|
QVariant val;
|
||||||
|
bool valid;
|
||||||
Event event;
|
Event event;
|
||||||
quint32 val;
|
Waypoint waypoint;
|
||||||
|
|
||||||
|
|
||||||
if (!def->fields && !def->devFields) {
|
if (!def->fields && !def->devFields) {
|
||||||
@ -224,69 +269,79 @@ bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
|||||||
|
|
||||||
for (int i = 0; i < def->numFields; i++) {
|
for (int i = 0; i < def->numFields; i++) {
|
||||||
field = &def->fields[i];
|
field = &def->fields[i];
|
||||||
if (!readField(ctx, field, val))
|
if (!readField(ctx, field, val, valid))
|
||||||
return false;
|
return false;
|
||||||
|
if (!valid)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (field->id == TIMESTAMP_FIELD)
|
if (field->id == TIMESTAMP_FIELD)
|
||||||
ctx.timestamp = val;
|
ctx.timestamp = val.toUInt();
|
||||||
else if (def->globalId == RECORD_MESSAGE) {
|
else if (def->globalId == RECORD_MESSAGE) {
|
||||||
switch (field->id) {
|
switch (field->id) {
|
||||||
case 0:
|
case 0:
|
||||||
if (val != 0x7fffffff)
|
|
||||||
ctx.trackpoint.rcoordinates().setLat(
|
ctx.trackpoint.rcoordinates().setLat(
|
||||||
((qint32)val / (double)0x7fffffff) * 180);
|
(val.toInt() / (double)0x7fffffff) * 180);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if (val != 0x7fffffff)
|
|
||||||
ctx.trackpoint.rcoordinates().setLon(
|
ctx.trackpoint.rcoordinates().setLon(
|
||||||
((qint32)val / (double)0x7fffffff) * 180);
|
(val.toInt() / (double)0x7fffffff) * 180);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (val != 0xffff)
|
ctx.trackpoint.setElevation((val.toUInt() / 5.0) - 500);
|
||||||
ctx.trackpoint.setElevation((val / 5.0) - 500);
|
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
if (val != 0xff)
|
ctx.trackpoint.setHeartRate(val.toUInt());
|
||||||
ctx.trackpoint.setHeartRate(val);
|
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
if (val != 0xff)
|
ctx.trackpoint.setCadence(val.toUInt());
|
||||||
ctx.trackpoint.setCadence(val);
|
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
if (val != 0xffff)
|
ctx.trackpoint.setSpeed(val.toUInt() / 1000.0f);
|
||||||
ctx.trackpoint.setSpeed(val / 1000.0f);
|
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
if (val != 0xffff)
|
ctx.trackpoint.setPower(val.toUInt());
|
||||||
ctx.trackpoint.setPower(val);
|
|
||||||
break;
|
break;
|
||||||
case 13:
|
case 13:
|
||||||
if (val != 0x7f)
|
ctx.trackpoint.setTemperature(val.toInt());
|
||||||
ctx.trackpoint.setTemperature((qint8)val);
|
|
||||||
break;
|
break;
|
||||||
case 73:
|
case 73:
|
||||||
if (val != 0xffffffff)
|
ctx.trackpoint.setSpeed(val.toUInt() / 1000.0f);
|
||||||
ctx.trackpoint.setSpeed(val / 1000.0f);
|
|
||||||
break;
|
break;
|
||||||
case 78:
|
case 78:
|
||||||
if (val != 0xffffffff)
|
ctx.trackpoint.setElevation((val.toUInt() / 5.0) - 500);
|
||||||
ctx.trackpoint.setElevation((val / 5.0) - 500);
|
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
} else if (def->globalId == EVENT_MESSAGE) {
|
} else if (def->globalId == EVENT_MESSAGE) {
|
||||||
switch (field->id) {
|
switch (field->id) {
|
||||||
case 0:
|
case 0:
|
||||||
event.id = val;
|
event.id = val.toUInt();
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
event.type = val;
|
event.type = val.toUInt();
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
event.data = val;
|
event.data = val.toUInt();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (def->globalId == COURSE_POINT) {
|
||||||
|
switch (field->id) {
|
||||||
|
case 1:
|
||||||
|
waypoint.setTimestamp(QDateTime::fromTime_t(val.toUInt()
|
||||||
|
+ 631065600));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
waypoint.rcoordinates().setLat(
|
||||||
|
(val.toInt() / (double)0x7fffffff) * 180);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
waypoint.rcoordinates().setLon(
|
||||||
|
(val.toInt() / (double)0x7fffffff) * 180);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
waypoint.setDescription(coursePointDesc.value(val.toUInt()));
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
waypoint.setName(val.toString());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -294,7 +349,7 @@ bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
|||||||
|
|
||||||
for (int i = 0; i < def->numDevFields; i++) {
|
for (int i = 0; i < def->numDevFields; i++) {
|
||||||
field = &def->devFields[i];
|
field = &def->devFields[i];
|
||||||
if (!readField(ctx, field, val))
|
if (!readField(ctx, field, val, valid))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,7 +370,9 @@ bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
|||||||
ctx.trackpoint = Trackpoint();
|
ctx.trackpoint = Trackpoint();
|
||||||
ctx.lastWrite = ctx.timestamp;
|
ctx.lastWrite = ctx.timestamp;
|
||||||
}
|
}
|
||||||
}
|
} else if (def->globalId == COURSE_POINT)
|
||||||
|
if (waypoint.coordinates().isValid())
|
||||||
|
ctx.waypoints.append(waypoint);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -381,9 +438,8 @@ bool FITParser::parse(QFile *file, QList<TrackData> &tracks,
|
|||||||
QList<Area> &polygons, QVector<Waypoint> &waypoints)
|
QList<Area> &polygons, QVector<Waypoint> &waypoints)
|
||||||
{
|
{
|
||||||
Q_UNUSED(routes);
|
Q_UNUSED(routes);
|
||||||
Q_UNUSED(waypoints);
|
|
||||||
Q_UNUSED(polygons);
|
Q_UNUSED(polygons);
|
||||||
CTX ctx(file);
|
CTX ctx(file, waypoints);
|
||||||
|
|
||||||
|
|
||||||
if (!parseHeader(ctx))
|
if (!parseHeader(ctx))
|
||||||
|
@ -21,7 +21,7 @@ private:
|
|||||||
bool readData(QFile *file, char *data, size_t size);
|
bool readData(QFile *file, char *data, size_t size);
|
||||||
template<class T> bool readValue(CTX &ctx, T &val);
|
template<class T> bool readValue(CTX &ctx, T &val);
|
||||||
bool skipValue(CTX &ctx, quint8 size);
|
bool skipValue(CTX &ctx, quint8 size);
|
||||||
bool readField(CTX &ctx, Field *field, quint32 &val);
|
bool readField(CTX &ctx, Field *field, QVariant &val, bool &valid);
|
||||||
|
|
||||||
bool parseHeader(CTX &ctx);
|
bool parseHeader(CTX &ctx);
|
||||||
bool parseRecord(CTX &ctx);
|
bool parseRecord(CTX &ctx);
|
||||||
|
@ -282,14 +282,14 @@ static quint32 readNotes(QDataStream &stream, QTextCodec *codec,
|
|||||||
if (s1 & 0x1) {
|
if (s1 & 0x1) {
|
||||||
QList<TranslatedString> obj;
|
QList<TranslatedString> obj;
|
||||||
ds += readTranslatedObjects(stream, codec, obj);
|
ds += readTranslatedObjects(stream, codec, obj);
|
||||||
if (!obj.isEmpty() && waypoint.description().isNull())
|
if (!obj.isEmpty())
|
||||||
waypoint.setDescription(obj.first().str());
|
waypoint.setComment(obj.first().str());
|
||||||
}
|
}
|
||||||
if (s1 & 0x2) {
|
if (s1 & 0x2) {
|
||||||
QString str;
|
QString str;
|
||||||
ds += readString(stream, codec, str);
|
ds += readString(stream, codec, str);
|
||||||
if (!str.isEmpty() && waypoint.description().isNull())
|
if (!str.isEmpty())
|
||||||
waypoint.setDescription(str);
|
waypoint.setComment(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ds != rh.size)
|
if (ds != rh.size)
|
||||||
|
@ -192,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"))
|
||||||
@ -244,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())
|
||||||
@ -278,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())
|
||||||
|
@ -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,10 +87,12 @@ 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;
|
||||||
|
@ -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) {
|
|
||||||
if (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();
|
_errorString = data.errorString();
|
||||||
_errorLine = data.errorLine();
|
_errorLine = data.errorLine();
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,39 +50,24 @@ 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("%s: %s", qPrintable(fi.absoluteFilePath()),
|
||||||
ret = false;
|
qPrintable(_errorString));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool cb(size_t data, void* context)
|
static bool cb(size_t data, void* context)
|
||||||
{
|
{
|
||||||
QSet<int> *set = (QSet<int>*) context;
|
QSet<int> *set = (QSet<int>*) 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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include "dem.h"
|
||||||
#include "track.h"
|
#include "track.h"
|
||||||
|
|
||||||
|
|
||||||
@ -13,6 +14,9 @@ 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)
|
static qreal avg(const QVector<qreal> &v)
|
||||||
@ -47,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;
|
||||||
@ -213,7 +217,7 @@ Track::Track(const TrackData &data) : _data(data), _pause(0)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Graph Track::elevation() const
|
Graph Track::gpsElevation() const
|
||||||
{
|
{
|
||||||
Graph ret;
|
Graph ret;
|
||||||
|
|
||||||
@ -237,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;
|
||||||
|
|
||||||
@ -251,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;
|
||||||
@ -276,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;
|
||||||
@ -47,6 +48,11 @@ public:
|
|||||||
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 {
|
||||||
@ -59,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;
|
||||||
@ -73,6 +84,9 @@ private:
|
|||||||
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);
|
||||||
|
}
|
||||||
|
}
|
@ -14,24 +14,29 @@
|
|||||||
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;}
|
||||||
|
Coordinates &rcoordinates() {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 QString &comment() const {return _comment;}
|
||||||
const Address &address() const {return _address;}
|
const Address &address() const {return _address;}
|
||||||
const QVector<ImageInfo> &images() const {return _images;}
|
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 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;}
|
||||||
@ -44,15 +49,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;
|
||||||
|
QString _comment;
|
||||||
Address _address;
|
Address _address;
|
||||||
QVector<ImageInfo> _images;
|
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)
|
||||||
@ -64,11 +77,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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ bool BitStream1::read(int bits, quint32 &val)
|
|||||||
|
|
||||||
bool BitStream1::flush()
|
bool BitStream1::flush()
|
||||||
{
|
{
|
||||||
if (_length && !_file.seek(_hdl, _hdl.pos + _length))
|
if (_length && !_file.seek(_hdl, _hdl.pos() + _length))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_length = 0;
|
_length = 0;
|
||||||
@ -50,18 +50,13 @@ bool BitStream4::read(int bits, quint32 &val)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
quint32 old = 0;
|
quint32 old = (_used < 32) ? (_data << _used) >> (32 - bits) : 0;
|
||||||
if (_used < 32) {
|
quint32 bytes = qMin(_length, 4U);
|
||||||
old = (_data << _used) >> (32 - bits);
|
|
||||||
bits = (bits - 32) + _used;
|
|
||||||
}
|
|
||||||
_used = bits;
|
|
||||||
|
|
||||||
quint32 bytes = qMin(_length, (quint32)4);
|
|
||||||
|
|
||||||
if (!_file.readVUInt32SW(_hdl, bytes, _data))
|
if (!_file.readVUInt32SW(_hdl, bytes, _data))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
_used -= 32 - bits;
|
||||||
_length -= bytes;
|
_length -= bytes;
|
||||||
_unused = (4 - bytes) * 8;
|
_unused = (4 - bytes) * 8;
|
||||||
_data <<= _unused;
|
_data <<= _unused;
|
||||||
@ -73,11 +68,12 @@ bool BitStream4::read(int bits, quint32 &val)
|
|||||||
|
|
||||||
bool BitStream4::flush()
|
bool BitStream4::flush()
|
||||||
{
|
{
|
||||||
if (_length && !_file.seek(_hdl, _hdl.pos + _length))
|
if (_length && !_file.seek(_hdl, _hdl.pos() + _length))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_length = 0;
|
_length = 0;
|
||||||
_unused = 32;
|
_used = 32;
|
||||||
|
_unused = 0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
155
src/map/IMG/gmap.cpp
Normal file
155
src/map/IMG/gmap.cpp
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
#include <QXmlStreamReader>
|
||||||
|
#include <QDir>
|
||||||
|
#include "vectortile.h"
|
||||||
|
#include "gmap.h"
|
||||||
|
|
||||||
|
|
||||||
|
static SubFile::Type tileType(const QString &suffix)
|
||||||
|
{
|
||||||
|
if (!suffix.compare("TRE"))
|
||||||
|
return SubFile::TRE;
|
||||||
|
else if (!suffix.compare("RGN"))
|
||||||
|
return SubFile::RGN;
|
||||||
|
else if (!suffix.compare("LBL"))
|
||||||
|
return SubFile::LBL;
|
||||||
|
else if (!suffix.compare("TYP"))
|
||||||
|
return SubFile::TYP;
|
||||||
|
else if (!suffix.compare("GMP"))
|
||||||
|
return SubFile::GMP;
|
||||||
|
else if (!suffix.compare("NET"))
|
||||||
|
return SubFile::NET;
|
||||||
|
else
|
||||||
|
return SubFile::Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GMAP::subProduct(QXmlStreamReader &reader, QString &dataDir,
|
||||||
|
QString &baseMap)
|
||||||
|
{
|
||||||
|
while (reader.readNextStartElement()) {
|
||||||
|
if (reader.name() == "Directory")
|
||||||
|
dataDir = reader.readElementText();
|
||||||
|
else if (reader.name() == "BaseMap")
|
||||||
|
baseMap = reader.readElementText();
|
||||||
|
else
|
||||||
|
reader.skipCurrentElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GMAP::mapProduct(QXmlStreamReader &reader, QString &dataDir,
|
||||||
|
QString &typFile, QString &baseMap)
|
||||||
|
{
|
||||||
|
while (reader.readNextStartElement()) {
|
||||||
|
if (reader.name() == "Name")
|
||||||
|
_name = reader.readElementText();
|
||||||
|
else if (reader.name() == "TYP")
|
||||||
|
typFile = reader.readElementText();
|
||||||
|
else if (reader.name() == "SubProduct")
|
||||||
|
subProduct(reader, dataDir, baseMap);
|
||||||
|
else
|
||||||
|
reader.skipCurrentElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GMAP::readXML(const QString &path, QString &dataDir, QString &typFile,
|
||||||
|
QString &baseMap)
|
||||||
|
{
|
||||||
|
QFile file(path);
|
||||||
|
|
||||||
|
if (!file.open(QFile::ReadOnly | QFile::Text))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QXmlStreamReader reader(&file);
|
||||||
|
if (reader.readNextStartElement()) {
|
||||||
|
if (reader.name() == "MapProduct")
|
||||||
|
mapProduct(reader, dataDir, typFile, baseMap);
|
||||||
|
else
|
||||||
|
reader.raiseError("Not a GMAP XML file");
|
||||||
|
}
|
||||||
|
if (reader.error()) {
|
||||||
|
_errorString = QString("%1: %2").arg(reader.lineNumber())
|
||||||
|
.arg(reader.errorString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GMAP::loadTile(const QDir &dir, bool baseMap)
|
||||||
|
{
|
||||||
|
VectorTile *tile = new VectorTile();
|
||||||
|
|
||||||
|
QFileInfoList ml = dir.entryInfoList(QDir::Files);
|
||||||
|
for (int i = 0; i < ml.size(); i++) {
|
||||||
|
const QFileInfo &fi = ml.at(i);
|
||||||
|
tile->addFile(fi.absoluteFilePath(), tileType(fi.suffix()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tile->init()) {
|
||||||
|
qWarning("%s: Invalid map tile", qPrintable(dir.path()));
|
||||||
|
delete tile;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (baseMap)
|
||||||
|
tile->markAsBasemap();
|
||||||
|
|
||||||
|
double min[2], max[2];
|
||||||
|
min[0] = tile->bounds().left();
|
||||||
|
min[1] = tile->bounds().bottom();
|
||||||
|
max[0] = tile->bounds().right();
|
||||||
|
max[1] = tile->bounds().top();
|
||||||
|
_tileTree.Insert(min, max, tile);
|
||||||
|
|
||||||
|
_bounds |= tile->bounds();
|
||||||
|
if (tile->zooms().min() < _zooms.min())
|
||||||
|
_zooms.setMin(tile->zooms().min());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
GMAP::GMAP(const QString &fileName) : _fileName(fileName)
|
||||||
|
{
|
||||||
|
QString dataDirPath, typFilePath, baseMapPath;
|
||||||
|
if (!readXML(fileName, dataDirPath, typFilePath, baseMapPath))
|
||||||
|
return;
|
||||||
|
|
||||||
|
QDir baseDir(QFileInfo(fileName).absoluteDir());
|
||||||
|
if (!baseDir.exists(dataDirPath)) {
|
||||||
|
_errorString = "Missing/invalid map data directory";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QDir dataDir(baseDir.filePath(dataDirPath));
|
||||||
|
QFileInfoList ml = dataDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
|
|
||||||
|
|
||||||
|
QFileInfo baseMap(dataDir.filePath(baseMapPath));
|
||||||
|
_baseMap = !baseMapPath.isEmpty() && baseMap.exists();
|
||||||
|
|
||||||
|
for (int i = 0; i < ml.size(); i++) {
|
||||||
|
const QFileInfo &fi = ml.at(i);
|
||||||
|
if (fi.isDir())
|
||||||
|
loadTile(QDir(fi.absoluteFilePath()),
|
||||||
|
fi.absoluteFilePath() == baseMap.absoluteFilePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (baseDir.exists(typFilePath))
|
||||||
|
_typ = new SubFile(baseDir.filePath(typFilePath));
|
||||||
|
|
||||||
|
if (!_tileTree.Count())
|
||||||
|
_errorString = "No usable map tile found";
|
||||||
|
else
|
||||||
|
_valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GMAP::isGMAP(const QString &path)
|
||||||
|
{
|
||||||
|
QFile file(path);
|
||||||
|
|
||||||
|
if (!file.open(QFile::ReadOnly | QFile::Text))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QXmlStreamReader reader(&file);
|
||||||
|
if (reader.readNextStartElement() && reader.name() == "MapProduct")
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
30
src/map/IMG/gmap.h
Normal file
30
src/map/IMG/gmap.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#ifndef GMAP_H
|
||||||
|
#define GMAP_H
|
||||||
|
|
||||||
|
#include "mapdata.h"
|
||||||
|
|
||||||
|
class QXmlStreamReader;
|
||||||
|
class QDir;
|
||||||
|
|
||||||
|
class GMAP : public MapData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GMAP(const QString &fileName);
|
||||||
|
|
||||||
|
QString fileName() const {return _fileName;}
|
||||||
|
|
||||||
|
static bool isGMAP(const QString &path);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool readXML(const QString &path, QString &dataDir, QString &typFile,
|
||||||
|
QString &baseMap);
|
||||||
|
void mapProduct(QXmlStreamReader &reader, QString &dataDir,
|
||||||
|
QString &typFile, QString &baseMap);
|
||||||
|
void subProduct(QXmlStreamReader &reader, QString &dataDir,
|
||||||
|
QString &baseMap);
|
||||||
|
bool loadTile(const QDir &dir, bool baseMap);
|
||||||
|
|
||||||
|
QString _fileName;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // GMAP_H
|
@ -23,29 +23,6 @@ HuffmanStream::HuffmanStream(const SubFile &file, SubFile::Handle &hdl,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HuffmanStream::readNext(qint32 &lonDelta, qint32 &latDelta)
|
|
||||||
{
|
|
||||||
if (!readDelta(_lonSign, lonDelta))
|
|
||||||
return false;
|
|
||||||
if (!readDelta(_latSign, latDelta))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!(lonDelta|latDelta))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HuffmanStream::readOffset(qint32 &lonDelta, qint32 &latDelta)
|
|
||||||
{
|
|
||||||
if (!readDelta(1, lonDelta))
|
|
||||||
return false;
|
|
||||||
if (!readDelta(1, latDelta))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HuffmanStream::sign(int &val)
|
bool HuffmanStream::sign(int &val)
|
||||||
{
|
{
|
||||||
quint32 bit;
|
quint32 bit;
|
||||||
@ -64,21 +41,17 @@ bool HuffmanStream::sign(int &val)
|
|||||||
|
|
||||||
bool HuffmanStream::readDelta(int sign, qint32 &symbol)
|
bool HuffmanStream::readDelta(int sign, qint32 &symbol)
|
||||||
{
|
{
|
||||||
uchar size;
|
quint8 size;
|
||||||
|
|
||||||
if (_symbolDataSize < 32) {
|
|
||||||
quint32 next;
|
quint32 next;
|
||||||
quint8 nextSize = qMin((quint32)(32 - _symbolDataSize),
|
quint8 nextSize = qMin((quint32)(32 - _symbolDataSize), bitsAvailable());
|
||||||
bitsAvailable());
|
|
||||||
|
|
||||||
if (!read(nextSize, next))
|
if (!read(nextSize, next))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_symbolData = (_symbolData << nextSize) | next;
|
_symbolData = (_symbolData << nextSize) | next;
|
||||||
_symbolDataSize += nextSize;
|
_symbolDataSize += nextSize;
|
||||||
}
|
|
||||||
|
|
||||||
symbol = _table.symbol(_symbolData << (32U - _symbolDataSize), size);
|
symbol = _table.symbol(_symbolData << (32 - _symbolDataSize), size);
|
||||||
|
|
||||||
if (size <= _symbolDataSize)
|
if (size <= _symbolDataSize)
|
||||||
_symbolDataSize -= size;
|
_symbolDataSize -= size;
|
||||||
|
@ -9,8 +9,16 @@ public:
|
|||||||
HuffmanStream(const SubFile &file, SubFile::Handle &hdl, quint32 length,
|
HuffmanStream(const SubFile &file, SubFile::Handle &hdl, quint32 length,
|
||||||
const HuffmanTable &table, bool line);
|
const HuffmanTable &table, bool line);
|
||||||
|
|
||||||
bool readNext(qint32 &lonDelta, qint32 &latDelta);
|
bool readNext(qint32 &lonDelta, qint32 &latDelta)
|
||||||
bool readOffset(qint32 &lonDelta, qint32 &latDelta);
|
{
|
||||||
|
if (!(readDelta(_lonSign, lonDelta) && readDelta(_latSign, latDelta)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return (lonDelta || latDelta);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool readOffset(qint32 &lonDelta, qint32 &latDelta)
|
||||||
|
{return (readDelta(1, lonDelta) && readDelta(1, latDelta));}
|
||||||
bool atEnd() const
|
bool atEnd() const
|
||||||
{return _symbolDataSize + bitsAvailable() < _table.maxSymbolSize();}
|
{return _symbolDataSize + bitsAvailable() < _table.maxSymbolSize();}
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ bool HuffmanTable::getBuffer(const SubFile &file, SubFile::Handle &hdl,
|
|||||||
return false;
|
return false;
|
||||||
if (!file.readVUInt32(hdl, recordSize))
|
if (!file.readVUInt32(hdl, recordSize))
|
||||||
return false;
|
return false;
|
||||||
recordOffset = hdl.pos + recordSize;
|
recordOffset = hdl.pos() + recordSize;
|
||||||
if (recordOffset > offset + size)
|
if (recordOffset > offset + size)
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
@ -1,27 +1,10 @@
|
|||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QtEndian>
|
#include <QtEndian>
|
||||||
#include "common/programpaths.h"
|
|
||||||
#include "vectortile.h"
|
#include "vectortile.h"
|
||||||
#include "img.h"
|
#include "img.h"
|
||||||
|
|
||||||
|
|
||||||
#define CACHE_SIZE 8388608 /* 8MB */
|
typedef QMap<QByteArray, VectorTile*> TileMap;
|
||||||
|
|
||||||
typedef QMap<QString, VectorTile*> TileMap;
|
|
||||||
|
|
||||||
struct CTX
|
|
||||||
{
|
|
||||||
CTX(const RectC &rect, int bits, QList<IMG::Poly> *polygons,
|
|
||||||
QList<IMG::Poly> *lines, QList<IMG::Point> *points)
|
|
||||||
: rect(rect), bits(bits), polygons(polygons), lines(lines),
|
|
||||||
points(points) {}
|
|
||||||
|
|
||||||
const RectC ▭
|
|
||||||
int bits;
|
|
||||||
QList<IMG::Poly> *polygons;
|
|
||||||
QList<IMG::Poly> *lines;
|
|
||||||
QList<IMG::Point> *points;
|
|
||||||
};
|
|
||||||
|
|
||||||
static SubFile::Type tileType(const char str[3])
|
static SubFile::Type tileType(const char str[3])
|
||||||
{
|
{
|
||||||
@ -41,8 +24,7 @@ static SubFile::Type tileType(const char str[3])
|
|||||||
return SubFile::Unknown;
|
return SubFile::Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
IMG::IMG(const QString &fileName)
|
IMG::IMG(const QString &fileName) : _file(fileName)
|
||||||
: _file(fileName), _typ(0), _style(0), _valid(false)
|
|
||||||
{
|
{
|
||||||
#define CHECK(condition) \
|
#define CHECK(condition) \
|
||||||
if (!(condition)) { \
|
if (!(condition)) { \
|
||||||
@ -52,7 +34,7 @@ IMG::IMG(const QString &fileName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
TileMap tileMap;
|
TileMap tileMap;
|
||||||
QString typFile;
|
QByteArray typFile;
|
||||||
|
|
||||||
if (!_file.open(QFile::ReadOnly)) {
|
if (!_file.open(QFile::ReadOnly)) {
|
||||||
_errorString = _file.errorString();
|
_errorString = _file.errorString();
|
||||||
@ -78,8 +60,6 @@ IMG::IMG(const QString &fileName)
|
|||||||
QByteArray nba(QByteArray(d1, sizeof(d1)) + QByteArray(d2, sizeof(d2)));
|
QByteArray nba(QByteArray(d1, sizeof(d1)) + QByteArray(d2, sizeof(d2)));
|
||||||
_name = QString::fromLatin1(nba.constData(), nba.size()-1).trimmed();
|
_name = QString::fromLatin1(nba.constData(), nba.size()-1).trimmed();
|
||||||
_blockSize = 1 << (e1 + e2);
|
_blockSize = 1 << (e1 + e2);
|
||||||
_blockCache.setMaxCost(CACHE_SIZE / _blockSize);
|
|
||||||
|
|
||||||
|
|
||||||
// Read the FAT table
|
// Read the FAT table
|
||||||
quint8 flag;
|
quint8 flag;
|
||||||
@ -107,7 +87,7 @@ IMG::IMG(const QString &fileName)
|
|||||||
&& read(type, sizeof(type)) && readValue(size) && readValue(part));
|
&& read(type, sizeof(type)) && readValue(size) && readValue(part));
|
||||||
SubFile::Type tt = tileType(type);
|
SubFile::Type tt = tileType(type);
|
||||||
|
|
||||||
QString fn(QByteArray(name, sizeof(name)));
|
QByteArray fn(name, sizeof(name));
|
||||||
if (VectorTile::isTileFile(tt)) {
|
if (VectorTile::isTileFile(tt)) {
|
||||||
VectorTile *tile;
|
VectorTile *tile;
|
||||||
TileMap::const_iterator it = tileMap.find(fn);
|
TileMap::const_iterator it = tileMap.find(fn);
|
||||||
@ -152,6 +132,8 @@ IMG::IMG(const QString &fileName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create tile tree
|
// Create tile tree
|
||||||
|
|
||||||
|
int minMapZoom = 24;
|
||||||
for (TileMap::const_iterator it = tileMap.constBegin();
|
for (TileMap::const_iterator it = tileMap.constBegin();
|
||||||
it != tileMap.constEnd(); ++it) {
|
it != tileMap.constEnd(); ++it) {
|
||||||
VectorTile *tile = it.value();
|
VectorTile *tile = it.value();
|
||||||
@ -171,6 +153,19 @@ IMG::IMG(const QString &fileName)
|
|||||||
_tileTree.Insert(min, max, tile);
|
_tileTree.Insert(min, max, tile);
|
||||||
|
|
||||||
_bounds |= tile->bounds();
|
_bounds |= tile->bounds();
|
||||||
|
if (tile->zooms().min() < _zooms.min())
|
||||||
|
_zooms.setMin(tile->zooms().min());
|
||||||
|
if (tile->zooms().min() < minMapZoom)
|
||||||
|
minMapZoom = tile->zooms().min();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (TileMap::const_iterator it = tileMap.constBegin();
|
||||||
|
it != tileMap.constEnd(); ++it) {
|
||||||
|
VectorTile *tile = it.value();
|
||||||
|
if (tile->zooms().min() > minMapZoom)
|
||||||
|
_baseMap = true;
|
||||||
|
if (tile->zooms().min() == minMapZoom)
|
||||||
|
tile->markAsBasemap();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_tileTree.Count())
|
if (!_tileTree.Count())
|
||||||
@ -179,65 +174,6 @@ IMG::IMG(const QString &fileName)
|
|||||||
_valid = true;
|
_valid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
IMG::~IMG()
|
|
||||||
{
|
|
||||||
TileTree::Iterator it;
|
|
||||||
for (_tileTree.GetFirst(it); !_tileTree.IsNull(it); _tileTree.GetNext(it))
|
|
||||||
delete _tileTree.GetAt(it);
|
|
||||||
|
|
||||||
delete _typ;
|
|
||||||
delete _style;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IMG::load()
|
|
||||||
{
|
|
||||||
Q_ASSERT(!_style);
|
|
||||||
|
|
||||||
if (_typ)
|
|
||||||
_style = new Style(_typ);
|
|
||||||
else {
|
|
||||||
QFile typFile(ProgramPaths::typFile());
|
|
||||||
if (typFile.open(QIODevice::ReadOnly)) {
|
|
||||||
SubFile typ(&typFile);
|
|
||||||
_style = new Style(&typ);
|
|
||||||
} else
|
|
||||||
_style = new Style();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void IMG::clear()
|
|
||||||
{
|
|
||||||
TileTree::Iterator it;
|
|
||||||
for (_tileTree.GetFirst(it); !_tileTree.IsNull(it); _tileTree.GetNext(it))
|
|
||||||
_tileTree.GetAt(it)->clear();
|
|
||||||
|
|
||||||
delete _style;
|
|
||||||
_style = 0;
|
|
||||||
|
|
||||||
_blockCache.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool cb(VectorTile *tile, void *context)
|
|
||||||
{
|
|
||||||
CTX *ctx = (CTX*)context;
|
|
||||||
tile->objects(ctx->rect, ctx->bits, ctx->polygons, ctx->lines, ctx->points);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IMG::objects(const RectC &rect, int bits, QList<Poly> *polygons,
|
|
||||||
QList<Poly> *lines, QList<Point> *points)
|
|
||||||
{
|
|
||||||
CTX ctx(rect, bits, polygons, lines, points);
|
|
||||||
double min[2], max[2];
|
|
||||||
|
|
||||||
min[0] = rect.left();
|
|
||||||
min[1] = rect.bottom();
|
|
||||||
max[0] = rect.right();
|
|
||||||
max[1] = rect.top();
|
|
||||||
|
|
||||||
_tileTree.Search(min, max, cb, &ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
qint64 IMG::read(char *data, qint64 maxSize)
|
qint64 IMG::read(char *data, qint64 maxSize)
|
||||||
{
|
{
|
||||||
qint64 ret = _file.read(data, maxSize);
|
qint64 ret = _file.read(data, maxSize);
|
||||||
@ -259,33 +195,12 @@ template<class T> bool IMG::readValue(T &val)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IMG::readBlock(int blockNum, QByteArray &data)
|
bool IMG::readBlock(int blockNum, char *data)
|
||||||
{
|
{
|
||||||
QByteArray *block = _blockCache[blockNum];
|
|
||||||
if (!block) {
|
|
||||||
if (!_file.seek((qint64)blockNum * (qint64)_blockSize))
|
if (!_file.seek((qint64)blockNum * (qint64)_blockSize))
|
||||||
return false;
|
return false;
|
||||||
data.resize(_blockSize);
|
if (read(data, _blockSize) < _blockSize)
|
||||||
if (read(data.data(), _blockSize) < _blockSize)
|
|
||||||
return false;
|
return false;
|
||||||
_blockCache.insert(blockNum, new QByteArray(data));
|
|
||||||
} else
|
|
||||||
data = *block;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef QT_NO_DEBUG
|
|
||||||
QDebug operator<<(QDebug dbg, const IMG::Point &point)
|
|
||||||
{
|
|
||||||
dbg.nospace() << "Point(" << hex << point.type << ", " << point.label
|
|
||||||
<< ", " << point.poi << ")";
|
|
||||||
return dbg.space();
|
|
||||||
}
|
|
||||||
|
|
||||||
QDebug operator<<(QDebug dbg, const IMG::Poly &poly)
|
|
||||||
{
|
|
||||||
dbg.nospace() << "Poly(" << hex << poly.type << ", " << poly.label << ")";
|
|
||||||
return dbg.space();
|
|
||||||
}
|
|
||||||
#endif // QT_NO_DEBUG
|
|
||||||
|
@ -2,92 +2,26 @@
|
|||||||
#define IMG_H
|
#define IMG_H
|
||||||
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QByteArray>
|
#include "mapdata.h"
|
||||||
#include <QCache>
|
|
||||||
#include <QDebug>
|
|
||||||
#include "common/rtree.h"
|
|
||||||
#include "common/rectc.h"
|
|
||||||
#include "style.h"
|
|
||||||
#include "label.h"
|
|
||||||
|
|
||||||
class VectorTile;
|
class IMG : public MapData
|
||||||
class SubFile;
|
|
||||||
|
|
||||||
class IMG
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct Poly {
|
|
||||||
/* QPointF insted of Coordinates for performance reasons (no need to
|
|
||||||
duplicate all the vectors for drawing). Note, that we do not want to
|
|
||||||
ll2xy() the points in the IMG class as this can not be done in
|
|
||||||
parallel. */
|
|
||||||
QVector<QPointF> points;
|
|
||||||
Label label;
|
|
||||||
quint32 type;
|
|
||||||
|
|
||||||
bool operator<(const Poly &other) const
|
|
||||||
{return type > other.type;}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Point {
|
|
||||||
Point() : id(0) {}
|
|
||||||
|
|
||||||
Coordinates coordinates;
|
|
||||||
Label label;
|
|
||||||
quint32 type;
|
|
||||||
bool poi;
|
|
||||||
quint64 id;
|
|
||||||
|
|
||||||
bool operator<(const Point &other) const
|
|
||||||
{return id < other.id;}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
IMG(const QString &fileName);
|
IMG(const QString &fileName);
|
||||||
~IMG();
|
|
||||||
|
|
||||||
void load();
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
QString fileName() const {return _file.fileName();}
|
QString fileName() const {return _file.fileName();}
|
||||||
const QString &name() const {return _name;}
|
|
||||||
const RectC &bounds() const {return _bounds;}
|
|
||||||
|
|
||||||
void objects(const RectC &rect, int bits, QList<Poly> *polygons,
|
|
||||||
QList<Poly> *lines, QList<Point> *points);
|
|
||||||
const Style *style() const {return _style;}
|
|
||||||
|
|
||||||
bool isValid() const {return _valid;}
|
|
||||||
const QString &errorString() const {return _errorString;}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class SubFile;
|
friend class SubFile;
|
||||||
|
|
||||||
typedef RTree<VectorTile*, double, 2> TileTree;
|
|
||||||
|
|
||||||
int blockSize() const {return _blockSize;}
|
int blockSize() const {return _blockSize;}
|
||||||
bool readBlock(int blockNum, QByteArray &data);
|
bool readBlock(int blockNum, char *data);
|
||||||
qint64 read(char *data, qint64 maxSize);
|
qint64 read(char *data, qint64 maxSize);
|
||||||
template<class T> bool readValue(T &val);
|
template<class T> bool readValue(T &val);
|
||||||
|
|
||||||
QFile _file;
|
QFile _file;
|
||||||
quint8 _key;
|
quint8 _key;
|
||||||
int _blockSize;
|
int _blockSize;
|
||||||
QCache<int, QByteArray> _blockCache;
|
|
||||||
|
|
||||||
QString _name;
|
|
||||||
RectC _bounds;
|
|
||||||
TileTree _tileTree;
|
|
||||||
SubFile *_typ;
|
|
||||||
Style *_style;
|
|
||||||
|
|
||||||
bool _valid;
|
|
||||||
QString _errorString;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef QT_NO_DEBUG
|
|
||||||
QDebug operator<<(QDebug dbg, const IMG::Point &point);
|
|
||||||
QDebug operator<<(QDebug dbg, const IMG::Poly &poly);
|
|
||||||
#endif // QT_NO_DEBUG
|
|
||||||
|
|
||||||
#endif // IMG_H
|
#endif // IMG_H
|
||||||
|
@ -30,15 +30,20 @@ static quint8 SPECIAL_CHARS[] = {
|
|||||||
'8', '9', '~', '~', '~', '~', '~', '~'
|
'8', '9', '~', '~', '~', '~', '~', '~'
|
||||||
};
|
};
|
||||||
|
|
||||||
static QString capitalize(const QString &str)
|
static bool isAllUpperCase(const QString &str)
|
||||||
{
|
{
|
||||||
if (str.isEmpty())
|
if (str.isEmpty())
|
||||||
return str;
|
return false;
|
||||||
for (int i = 0; i < str.size(); i++)
|
for (int i = 0; i < str.size(); i++)
|
||||||
if (str.at(i).isLetter() && !(str.at(i).isUpper()
|
if (str.at(i).isLetter() && !(str.at(i).isUpper()
|
||||||
|| str.at(i) == QChar(0x00DF)))
|
|| str.at(i) == QChar(0x00DF)))
|
||||||
return str;
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString capitalized(const QString &str)
|
||||||
|
{
|
||||||
QString ret(str);
|
QString ret(str);
|
||||||
for (int i = 0; i < str.size(); i++)
|
for (int i = 0; i < str.size(); i++)
|
||||||
if (i && !str.at(i-1).isSpace())
|
if (i && !str.at(i-1).isSpace())
|
||||||
@ -77,7 +82,7 @@ bool LBLFile::init(Handle &hdl)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Label LBLFile::label6b(Handle &hdl, quint32 offset) const
|
Label LBLFile::label6b(Handle &hdl, quint32 offset, bool capitalize) const
|
||||||
{
|
{
|
||||||
Label::Shield::Type shieldType = Label::Shield::None;
|
Label::Shield::Type shieldType = Label::Shield::None;
|
||||||
QByteArray label, shieldLabel;
|
QByteArray label, shieldLabel;
|
||||||
@ -95,9 +100,12 @@ Label LBLFile::label6b(Handle &hdl, quint32 offset) const
|
|||||||
int c[]= {b1>>2, (b1&0x3)<<4|b2>>4, (b2&0xF)<<2|b3>>6, b3&0x3F};
|
int c[]= {b1>>2, (b1&0x3)<<4|b2>>4, (b2&0xF)<<2|b3>>6, b3&0x3F};
|
||||||
|
|
||||||
for (int cpt = 0; cpt < 4; cpt++) {
|
for (int cpt = 0; cpt < 4; cpt++) {
|
||||||
if (c[cpt] > 0x2f || (curCharSet == Normal && c[cpt] == 0x1d))
|
if (c[cpt] > 0x2f || (curCharSet == Normal && c[cpt] == 0x1d)) {
|
||||||
return Label(capitalize(QString::fromLatin1(label)),
|
QString text(QString::fromLatin1(label));
|
||||||
Label::Shield(shieldType, shieldLabel));
|
return Label(capitalize && isAllUpperCase(text)
|
||||||
|
? capitalized(text) : text, Label::Shield(shieldType,
|
||||||
|
shieldLabel));
|
||||||
|
}
|
||||||
switch (curCharSet) {
|
switch (curCharSet) {
|
||||||
case Normal:
|
case Normal:
|
||||||
if (c[cpt] == 0x1c)
|
if (c[cpt] == 0x1c)
|
||||||
@ -127,7 +135,7 @@ Label LBLFile::label6b(Handle &hdl, quint32 offset) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Label LBLFile::label8b(Handle &hdl, quint32 offset) const
|
Label LBLFile::label8b(Handle &hdl, quint32 offset, bool capitalize) const
|
||||||
{
|
{
|
||||||
Label::Shield::Type shieldType = Label::Shield::None;
|
Label::Shield::Type shieldType = Label::Shield::None;
|
||||||
QByteArray label, shieldLabel;
|
QByteArray label, shieldLabel;
|
||||||
@ -143,7 +151,9 @@ Label LBLFile::label8b(Handle &hdl, quint32 offset) const
|
|||||||
if (!c || c == 0x1d)
|
if (!c || c == 0x1d)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if ((c >= 0x1e && c <= 0x1f)) {
|
if (c == 0x1c)
|
||||||
|
capitalize = false;
|
||||||
|
else if ((c >= 0x1e && c <= 0x1f)) {
|
||||||
if (bap == &shieldLabel)
|
if (bap == &shieldLabel)
|
||||||
bap = &label;
|
bap = &label;
|
||||||
else
|
else
|
||||||
@ -157,12 +167,15 @@ Label LBLFile::label8b(Handle &hdl, quint32 offset) const
|
|||||||
bap->append(c);
|
bap->append(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Label(capitalize(_codec ? _codec->toUnicode(label)
|
QString text(_codec ? _codec->toUnicode(label) : QString::fromLatin1(label));
|
||||||
: QString::fromLatin1(label)), Label::Shield(shieldType, _codec
|
QString shieldText(_codec ? _codec->toUnicode(shieldLabel)
|
||||||
? _codec->toUnicode(shieldLabel) : QString::fromLatin1(shieldLabel)));
|
: QString::fromLatin1(shieldLabel));
|
||||||
|
|
||||||
|
return Label(capitalize && isAllUpperCase(text) ? capitalized(text) : text,
|
||||||
|
Label::Shield(shieldType, shieldText));
|
||||||
}
|
}
|
||||||
|
|
||||||
Label LBLFile::label(Handle &hdl, quint32 offset, bool poi)
|
Label LBLFile::label(Handle &hdl, quint32 offset, bool poi, bool capitalize)
|
||||||
{
|
{
|
||||||
if (!_multiplier && !init(hdl))
|
if (!_multiplier && !init(hdl))
|
||||||
return QString();
|
return QString();
|
||||||
@ -183,10 +196,10 @@ Label LBLFile::label(Handle &hdl, quint32 offset, bool poi)
|
|||||||
|
|
||||||
switch (_encoding) {
|
switch (_encoding) {
|
||||||
case 6:
|
case 6:
|
||||||
return label6b(hdl, labelOffset);
|
return label6b(hdl, labelOffset, capitalize);
|
||||||
case 9:
|
case 9:
|
||||||
case 10:
|
case 10:
|
||||||
return label8b(hdl, labelOffset);
|
return label8b(hdl, labelOffset, capitalize);
|
||||||
default:
|
default:
|
||||||
return Label();
|
return Label();
|
||||||
}
|
}
|
||||||
|
@ -12,17 +12,21 @@ public:
|
|||||||
LBLFile(IMG *img)
|
LBLFile(IMG *img)
|
||||||
: SubFile(img), _codec(0), _offset(0), _size(0), _poiOffset(0),
|
: SubFile(img), _codec(0), _offset(0), _size(0), _poiOffset(0),
|
||||||
_poiSize(0), _poiMultiplier(0), _multiplier(0), _encoding(0) {}
|
_poiSize(0), _poiMultiplier(0), _multiplier(0), _encoding(0) {}
|
||||||
|
LBLFile(const QString &path)
|
||||||
|
: SubFile(path), _codec(0), _offset(0), _size(0), _poiOffset(0),
|
||||||
|
_poiSize(0), _poiMultiplier(0), _multiplier(0), _encoding(0) {}
|
||||||
LBLFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
|
LBLFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
|
||||||
_codec(0), _offset(0), _size(0), _poiOffset(0), _poiSize(0),
|
_codec(0), _offset(0), _size(0), _poiOffset(0), _poiSize(0),
|
||||||
_poiMultiplier(0), _multiplier(0), _encoding(0) {}
|
_poiMultiplier(0), _multiplier(0), _encoding(0) {}
|
||||||
|
|
||||||
Label label(Handle &hdl, quint32 offset, bool poi = false);
|
Label label(Handle &hdl, quint32 offset, bool poi = false,
|
||||||
|
bool capitalize = true);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool init(Handle &hdl);
|
bool init(Handle &hdl);
|
||||||
|
|
||||||
Label label6b(Handle &hdl, quint32 offset) const;
|
Label label6b(Handle &hdl, quint32 offset, bool capitalize) const;
|
||||||
Label label8b(Handle &hdl, quint32 offset) const;
|
Label label8b(Handle &hdl, quint32 offset, bool capitalize) const;
|
||||||
|
|
||||||
QTextCodec *_codec;
|
QTextCodec *_codec;
|
||||||
quint32 _offset;
|
quint32 _offset;
|
||||||
|
128
src/map/IMG/mapdata.cpp
Normal file
128
src/map/IMG/mapdata.cpp
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
#include "common/programpaths.h"
|
||||||
|
#include "vectortile.h"
|
||||||
|
#include "style.h"
|
||||||
|
#include "mapdata.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define CACHED_SUBDIVS_COUNT 2048 // ~32MB for both caches together
|
||||||
|
|
||||||
|
struct PolyCTX
|
||||||
|
{
|
||||||
|
PolyCTX(const RectC &rect, int bits, bool baseMap,
|
||||||
|
QList<MapData::Poly> *polygons, QList<MapData::Poly> *lines,
|
||||||
|
QCache<const SubDiv*, MapData::Polys> *polyCache)
|
||||||
|
: rect(rect), bits(bits), baseMap(baseMap), polygons(polygons),
|
||||||
|
lines(lines), polyCache(polyCache) {}
|
||||||
|
|
||||||
|
const RectC ▭
|
||||||
|
int bits;
|
||||||
|
bool baseMap;
|
||||||
|
QList<MapData::Poly> *polygons;
|
||||||
|
QList<MapData::Poly> *lines;
|
||||||
|
QCache<const SubDiv*, MapData::Polys> *polyCache;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PointCTX
|
||||||
|
{
|
||||||
|
PointCTX(const RectC &rect, int bits, bool baseMap,
|
||||||
|
QList<MapData::Point> *points,
|
||||||
|
QCache<const SubDiv*, QList<MapData::Point> > *pointCache)
|
||||||
|
: rect(rect), bits(bits), baseMap(baseMap), points(points),
|
||||||
|
pointCache(pointCache) {}
|
||||||
|
|
||||||
|
const RectC ▭
|
||||||
|
int bits;
|
||||||
|
bool baseMap;
|
||||||
|
QList<MapData::Point> *points;
|
||||||
|
QCache<const SubDiv*, QList<MapData::Point> > *pointCache;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool polyCb(VectorTile *tile, void *context)
|
||||||
|
{
|
||||||
|
PolyCTX *ctx = (PolyCTX*)context;
|
||||||
|
tile->polys(ctx->rect, ctx->bits, ctx->baseMap, ctx->polygons, ctx->lines,
|
||||||
|
ctx->polyCache);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool pointCb(VectorTile *tile, void *context)
|
||||||
|
{
|
||||||
|
PointCTX *ctx = (PointCTX*)context;
|
||||||
|
tile->points(ctx->rect, ctx->bits, ctx->baseMap, ctx->points,
|
||||||
|
ctx->pointCache);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MapData::MapData() : _typ(0), _style(0), _zooms(15, 28), _baseMap(false),
|
||||||
|
_valid(false)
|
||||||
|
{
|
||||||
|
_polyCache.setMaxCost(CACHED_SUBDIVS_COUNT);
|
||||||
|
_pointCache.setMaxCost(CACHED_SUBDIVS_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
MapData::~MapData()
|
||||||
|
{
|
||||||
|
TileTree::Iterator it;
|
||||||
|
for (_tileTree.GetFirst(it); !_tileTree.IsNull(it); _tileTree.GetNext(it))
|
||||||
|
delete _tileTree.GetAt(it);
|
||||||
|
|
||||||
|
delete _typ;
|
||||||
|
delete _style;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapData::polys(const RectC &rect, int bits, QList<Poly> *polygons,
|
||||||
|
QList<Poly> *lines)
|
||||||
|
{
|
||||||
|
PolyCTX ctx(rect, bits, _baseMap, polygons, lines, &_polyCache);
|
||||||
|
double min[2], max[2];
|
||||||
|
|
||||||
|
min[0] = rect.left();
|
||||||
|
min[1] = rect.bottom();
|
||||||
|
max[0] = rect.right();
|
||||||
|
max[1] = rect.top();
|
||||||
|
|
||||||
|
_tileTree.Search(min, max, polyCb, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapData::points(const RectC &rect, int bits, QList<Point> *points)
|
||||||
|
{
|
||||||
|
PointCTX ctx(rect, bits, _baseMap, points, &_pointCache);
|
||||||
|
double min[2], max[2];
|
||||||
|
|
||||||
|
min[0] = rect.left();
|
||||||
|
min[1] = rect.bottom();
|
||||||
|
max[0] = rect.right();
|
||||||
|
max[1] = rect.top();
|
||||||
|
|
||||||
|
_tileTree.Search(min, max, pointCb, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapData::load()
|
||||||
|
{
|
||||||
|
Q_ASSERT(!_style);
|
||||||
|
|
||||||
|
if (_typ)
|
||||||
|
_style = new Style(_typ);
|
||||||
|
else {
|
||||||
|
QString typFile(ProgramPaths::typFile());
|
||||||
|
if (!typFile.isEmpty()) {
|
||||||
|
SubFile typ(typFile);
|
||||||
|
_style = new Style(&typ);
|
||||||
|
} else
|
||||||
|
_style = new Style();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapData::clear()
|
||||||
|
{
|
||||||
|
TileTree::Iterator it;
|
||||||
|
for (_tileTree.GetFirst(it); !_tileTree.IsNull(it); _tileTree.GetNext(it))
|
||||||
|
_tileTree.GetAt(it)->clear();
|
||||||
|
|
||||||
|
delete _style;
|
||||||
|
_style = 0;
|
||||||
|
|
||||||
|
_polyCache.clear();
|
||||||
|
_pointCache.clear();
|
||||||
|
}
|
110
src/map/IMG/mapdata.h
Normal file
110
src/map/IMG/mapdata.h
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
#ifndef MAPDATA_H
|
||||||
|
#define MAPDATA_H
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
#include <QPointF>
|
||||||
|
#include <QCache>
|
||||||
|
#include <QDebug>
|
||||||
|
#include "common/rectc.h"
|
||||||
|
#include "common/rtree.h"
|
||||||
|
#include "common/range.h"
|
||||||
|
#include "label.h"
|
||||||
|
|
||||||
|
class Style;
|
||||||
|
class SubDiv;
|
||||||
|
class SubFile;
|
||||||
|
class VectorTile;
|
||||||
|
|
||||||
|
class MapData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Poly {
|
||||||
|
/* QPointF insted of Coordinates for performance reasons (no need to
|
||||||
|
duplicate all the vectors for drawing). Note, that we do not want to
|
||||||
|
ll2xy() the points in the IMG class as this can not be done in
|
||||||
|
parallel. */
|
||||||
|
QVector<QPointF> points;
|
||||||
|
Label label;
|
||||||
|
quint32 type;
|
||||||
|
RectC boundingRect;
|
||||||
|
|
||||||
|
bool operator<(const Poly &other) const
|
||||||
|
{return type > other.type;}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Point {
|
||||||
|
Point() : id(0) {}
|
||||||
|
|
||||||
|
Coordinates coordinates;
|
||||||
|
Label label;
|
||||||
|
quint32 type;
|
||||||
|
bool poi;
|
||||||
|
quint64 id;
|
||||||
|
|
||||||
|
bool operator<(const Point &other) const
|
||||||
|
{return id < other.id;}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Polys {
|
||||||
|
Polys() {}
|
||||||
|
Polys(const QList<Poly> &polygons, const QList<Poly> &lines)
|
||||||
|
: polygons(polygons), lines(lines) {}
|
||||||
|
|
||||||
|
QList<Poly> polygons;
|
||||||
|
QList<Poly> lines;
|
||||||
|
};
|
||||||
|
|
||||||
|
MapData();
|
||||||
|
virtual ~MapData();
|
||||||
|
|
||||||
|
const QString &name() const {return _name;}
|
||||||
|
const RectC &bounds() const {return _bounds;}
|
||||||
|
const Range &zooms() const {return _zooms;}
|
||||||
|
const Style *style() const {return _style;}
|
||||||
|
void polys(const RectC &rect, int bits, QList<Poly> *polygons,
|
||||||
|
QList<Poly> *lines);
|
||||||
|
void points(const RectC &rect, int bits, QList<Point> *points);
|
||||||
|
|
||||||
|
void load();
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
virtual QString fileName() const = 0;
|
||||||
|
|
||||||
|
bool isValid() const {return _valid;}
|
||||||
|
QString errorString() const {return _errorString;}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
typedef RTree<VectorTile*, double, 2> TileTree;
|
||||||
|
|
||||||
|
QString _name;
|
||||||
|
RectC _bounds;
|
||||||
|
SubFile *_typ;
|
||||||
|
Style *_style;
|
||||||
|
TileTree _tileTree;
|
||||||
|
Range _zooms;
|
||||||
|
bool _baseMap;
|
||||||
|
|
||||||
|
bool _valid;
|
||||||
|
QString _errorString;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QCache<const SubDiv*, Polys> _polyCache;
|
||||||
|
QCache<const SubDiv*, QList<Point> > _pointCache;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef QT_NO_DEBUG
|
||||||
|
inline QDebug operator<<(QDebug dbg, const MapData::Point &point)
|
||||||
|
{
|
||||||
|
dbg.nospace() << "Point(" << hex << point.type << ", " << point.label
|
||||||
|
<< ", " << point.poi << ")";
|
||||||
|
return dbg.space();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QDebug operator<<(QDebug dbg, const MapData::Poly &poly)
|
||||||
|
{
|
||||||
|
dbg.nospace() << "Poly(" << hex << poly.type << ", " << poly.label << ")";
|
||||||
|
return dbg.space();
|
||||||
|
}
|
||||||
|
#endif // QT_NO_DEBUG
|
||||||
|
|
||||||
|
#endif // MAPDATA_H
|
@ -6,9 +6,12 @@
|
|||||||
class NETFile : public SubFile
|
class NETFile : public SubFile
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NETFile(IMG *img) : SubFile(img), _offset(0), _size(0), _multiplier(0) {}
|
NETFile(IMG *img)
|
||||||
NETFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
|
: SubFile(img), _offset(0), _size(0), _multiplier(0) {}
|
||||||
_offset(0), _size(0), _multiplier(0) {}
|
NETFile(const QString &path)
|
||||||
|
: SubFile(path), _offset(0), _size(0), _multiplier(0) {}
|
||||||
|
NETFile(SubFile *gmp, quint32 offset)
|
||||||
|
: SubFile(gmp, offset), _offset(0), _size(0), _multiplier(0) {}
|
||||||
|
|
||||||
bool lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset);
|
bool lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset);
|
||||||
|
|
||||||
|
@ -8,6 +8,20 @@
|
|||||||
#include "rgnfile.h"
|
#include "rgnfile.h"
|
||||||
|
|
||||||
|
|
||||||
|
static quint64 pointId(const QPoint &pos, quint32 type, quint32 labelPtr)
|
||||||
|
{
|
||||||
|
quint64 id;
|
||||||
|
|
||||||
|
uint hash = qHash(QPair<uint,uint>(qHash(QPair<int, int>(pos.x(),
|
||||||
|
pos.y())), labelPtr & 0x3FFFFF));
|
||||||
|
id = ((quint64)type)<<32 | hash;
|
||||||
|
// Make country labels precedent over city labels
|
||||||
|
if (!(type >= 0x1400 && type <= 0x153f))
|
||||||
|
id |= 1ULL<<63;
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
bool RGNFile::skipClassFields(Handle &hdl) const
|
bool RGNFile::skipClassFields(Handle &hdl) const
|
||||||
{
|
{
|
||||||
quint8 flags;
|
quint8 flags;
|
||||||
@ -35,11 +49,11 @@ bool RGNFile::skipClassFields(Handle &hdl) const
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return seek(hdl, hdl.pos + rs);
|
return seek(hdl, hdl.pos() + rs);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RGNFile::skipLclFields(Handle &hdl, const quint32 flags[3],
|
bool RGNFile::skipLclFields(Handle &hdl, const quint32 flags[3],
|
||||||
Segment::Type type) const
|
SegmentType type) const
|
||||||
{
|
{
|
||||||
quint32 bitfield = 0xFFFFFFFF;
|
quint32 bitfield = 0xFFFFFFFF;
|
||||||
|
|
||||||
@ -53,7 +67,7 @@ bool RGNFile::skipLclFields(Handle &hdl, const quint32 flags[3],
|
|||||||
quint32 m = flags[(i >> 4) + 1] >> ((i * 2) & 0x1e) & 3;
|
quint32 m = flags[(i >> 4) + 1] >> ((i * 2) & 0x1e) & 3;
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 5:
|
case 5:
|
||||||
if (m == 1 && type == Segment::Point) {
|
if (m == 1 && type == Point) {
|
||||||
quint16 u16;
|
quint16 u16;
|
||||||
if (!readUInt16(hdl, u16))
|
if (!readUInt16(hdl, u16))
|
||||||
return false;
|
return false;
|
||||||
@ -116,11 +130,16 @@ bool RGNFile::init(Handle &hdl)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RGNFile::polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
|
bool RGNFile::polyObjects(Handle &hdl, const SubDiv *subdiv,
|
||||||
const Segment &segment, LBLFile *lbl, Handle &lblHdl, NETFile *net,
|
SegmentType segmentType, LBLFile *lbl, Handle &lblHdl, NETFile *net,
|
||||||
Handle &netHdl, QList<IMG::Poly> *polys) const
|
Handle &netHdl, QList<IMG::Poly> *polys) const
|
||||||
{
|
{
|
||||||
if (!seek(hdl, segment.start()))
|
const SubDiv::Segment &segment = (segmentType == Line)
|
||||||
|
? subdiv->lines() : subdiv->polygons();
|
||||||
|
|
||||||
|
if (!segment.isValid())
|
||||||
|
return true;
|
||||||
|
if (!seek(hdl, segment.offset()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
quint32 labelPtr;
|
quint32 labelPtr;
|
||||||
@ -128,7 +147,7 @@ bool RGNFile::polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
|
|||||||
qint16 lon, lat;
|
qint16 lon, lat;
|
||||||
quint16 len;
|
quint16 len;
|
||||||
|
|
||||||
while (hdl.pos < (int)segment.end()) {
|
while (hdl.pos() < (int)segment.end()) {
|
||||||
IMG::Poly poly;
|
IMG::Poly poly;
|
||||||
|
|
||||||
if (!(readUInt8(hdl, type) && readUInt24(hdl, labelPtr)
|
if (!(readUInt8(hdl, type) && readUInt24(hdl, labelPtr)
|
||||||
@ -145,33 +164,32 @@ bool RGNFile::polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
|
|||||||
if (!readUInt8(hdl, bitstreamInfo))
|
if (!readUInt8(hdl, bitstreamInfo))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
poly.type = (segment.type() == Segment::Polygon)
|
poly.type = (segmentType == Polygon)
|
||||||
? ((quint32)(type & 0x7F)) << 8 : ((quint32)(type & 0x3F)) << 8;
|
? ((quint32)(type & 0x7F)) << 8 : ((quint32)(type & 0x3F)) << 8;
|
||||||
|
|
||||||
|
|
||||||
QPoint pos(subdiv->lon() + ((qint32)lon<<(24-subdiv->bits())),
|
QPoint pos(subdiv->lon() + LS(lon, 24-subdiv->bits()),
|
||||||
subdiv->lat() + ((qint32)lat<<(24-subdiv->bits())));
|
subdiv->lat() + LS(lat, 24-subdiv->bits()));
|
||||||
Coordinates c(toWGS24(pos.x()), toWGS24(pos.y()));
|
Coordinates c(toWGS24(pos.x()), toWGS24(pos.y()));
|
||||||
RectC br(c, c);
|
poly.boundingRect = RectC(c, c);
|
||||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||||
|
|
||||||
qint32 lonDelta, latDelta;
|
qint32 lonDelta, latDelta;
|
||||||
DeltaStream stream(*this, hdl, len, bitstreamInfo, labelPtr & 0x400000,
|
DeltaStream stream(*this, hdl, len, bitstreamInfo, labelPtr & 0x400000,
|
||||||
false);
|
false);
|
||||||
while (stream.readNext(lonDelta, latDelta)) {
|
while (stream.readNext(lonDelta, latDelta)) {
|
||||||
pos.rx() += lonDelta<<(24-subdiv->bits());
|
pos.rx() += LS(lonDelta, (24-subdiv->bits()));
|
||||||
pos.ry() += latDelta<<(24-subdiv->bits());
|
if (pos.rx() >= 0x800000 && subdiv->lon() >= 0)
|
||||||
|
pos.rx() = 0x7fffff;
|
||||||
|
pos.ry() += LS(latDelta, (24-subdiv->bits()));
|
||||||
|
|
||||||
Coordinates c(toWGS24(pos.x()), toWGS24(pos.y()));
|
Coordinates c(toWGS24(pos.x()), toWGS24(pos.y()));
|
||||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||||
br = br.united(c);
|
poly.boundingRect = poly.boundingRect.united(c);
|
||||||
}
|
}
|
||||||
if (!(stream.atEnd() && stream.flush()))
|
if (!(stream.atEnd() && stream.flush()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!rect.intersects(br))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (lbl && (labelPtr & 0x3FFFFF)) {
|
if (lbl && (labelPtr & 0x3FFFFF)) {
|
||||||
if (labelPtr & 0x800000) {
|
if (labelPtr & 0x800000) {
|
||||||
quint32 lblOff;
|
quint32 lblOff;
|
||||||
@ -188,22 +206,25 @@ bool RGNFile::polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
|
bool RGNFile::extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift,
|
||||||
const SubDiv *subdiv, quint32 shift, const Segment &segment, LBLFile *lbl,
|
SegmentType segmentType, LBLFile *lbl, Handle &lblHdl,
|
||||||
Handle &lblHdl, QList<IMG::Poly> *polys, bool line) const
|
QList<IMG::Poly> *polys) const
|
||||||
{
|
{
|
||||||
quint32 labelPtr, len;
|
quint32 labelPtr, len;
|
||||||
quint8 type, subtype;
|
quint8 type, subtype;
|
||||||
qint16 lon, lat;
|
qint16 lon, lat;
|
||||||
|
const SubDiv::Segment &segment = (segmentType == Line)
|
||||||
|
? subdiv->extLines() : subdiv->extPolygons();
|
||||||
|
|
||||||
|
|
||||||
if (!seek(hdl, segment.start()))
|
if (!segment.isValid())
|
||||||
|
return true;
|
||||||
|
if (!seek(hdl, segment.offset()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
while (hdl.pos < (int)segment.end()) {
|
while (hdl.pos() < (int)segment.end()) {
|
||||||
IMG::Poly poly;
|
IMG::Poly poly;
|
||||||
QPoint pos;
|
QPoint pos;
|
||||||
RectC br;
|
|
||||||
|
|
||||||
if (!(readUInt8(hdl, type) && readUInt8(hdl, subtype)
|
if (!(readUInt8(hdl, type) && readUInt8(hdl, subtype)
|
||||||
&& readInt16(hdl, lon) && readInt16(hdl, lat)
|
&& readInt16(hdl, lon) && readInt16(hdl, lat)
|
||||||
@ -214,38 +235,41 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
|
|||||||
labelPtr = 0;
|
labelPtr = 0;
|
||||||
|
|
||||||
if (!_huffmanTable.isNull()) {
|
if (!_huffmanTable.isNull()) {
|
||||||
pos = QPoint((subdiv->lon()<<8) + ((qint32)lon<<(32-subdiv->bits())),
|
pos = QPoint(LS(subdiv->lon(), 8) + LS(lon, 32-subdiv->bits()),
|
||||||
(subdiv->lat()<<8) + ((qint32)lat<<(32-subdiv->bits())));
|
LS(subdiv->lat(), 8) + LS(lat, (32-subdiv->bits())));
|
||||||
|
|
||||||
qint32 lonDelta, latDelta;
|
qint32 lonDelta, latDelta;
|
||||||
HuffmanStream stream(*this, hdl, len, _huffmanTable, line);
|
HuffmanStream stream(*this, hdl, len, _huffmanTable,
|
||||||
|
segmentType == Line);
|
||||||
|
|
||||||
if (shift) {
|
if (shift) {
|
||||||
if (!stream.readOffset(lonDelta, latDelta))
|
if (!stream.readOffset(lonDelta, latDelta))
|
||||||
return false;
|
return false;
|
||||||
pos = QPoint(pos.x() | lonDelta<<(32-subdiv->bits()-shift),
|
pos = QPoint(pos.x() | LS(lonDelta, 32-subdiv->bits()-shift),
|
||||||
pos.y() | latDelta<<(32-subdiv->bits()-shift));
|
pos.y() | LS(latDelta, 32-subdiv->bits()-shift));
|
||||||
}
|
}
|
||||||
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
|
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
|
||||||
br = RectC(c, c);
|
poly.boundingRect = RectC(c, c);
|
||||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||||
|
|
||||||
while (stream.readNext(lonDelta, latDelta)) {
|
while (stream.readNext(lonDelta, latDelta)) {
|
||||||
pos.rx() += lonDelta<<(32-subdiv->bits()-shift);
|
pos.rx() += LS(lonDelta, 32-subdiv->bits()-shift);
|
||||||
pos.ry() += latDelta<<(32-subdiv->bits()-shift);
|
if (pos.rx() < 0 && subdiv->lon() >= 0)
|
||||||
|
pos.rx() = 0x7fffffff;
|
||||||
|
pos.ry() += LS(latDelta, 32-subdiv->bits()-shift);
|
||||||
|
|
||||||
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
|
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
|
||||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||||
br = br.united(c);
|
poly.boundingRect = poly.boundingRect.united(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(stream.atEnd() && stream.flush()))
|
if (!(stream.atEnd() && stream.flush()))
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
pos = QPoint(subdiv->lon() + ((qint32)lon<<(24-subdiv->bits())),
|
pos = QPoint(subdiv->lon() + LS(lon, 24-subdiv->bits()),
|
||||||
subdiv->lat() + ((qint32)lat<<(24-subdiv->bits())));
|
subdiv->lat() + LS(lat, 24-subdiv->bits()));
|
||||||
Coordinates c(toWGS24(pos.x()), toWGS24(pos.y()));
|
Coordinates c(toWGS24(pos.x()), toWGS24(pos.y()));
|
||||||
br = RectC(c, c);
|
poly.boundingRect = RectC(c, c);
|
||||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||||
|
|
||||||
quint8 bitstreamInfo;
|
quint8 bitstreamInfo;
|
||||||
@ -256,12 +280,14 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
|
|||||||
DeltaStream stream(*this, hdl, len - 1, bitstreamInfo, false, true);
|
DeltaStream stream(*this, hdl, len - 1, bitstreamInfo, false, true);
|
||||||
|
|
||||||
while (stream.readNext(lonDelta, latDelta)) {
|
while (stream.readNext(lonDelta, latDelta)) {
|
||||||
pos.rx() += lonDelta<<(24-subdiv->bits());
|
pos.rx() += LS(lonDelta, 24-subdiv->bits());
|
||||||
pos.ry() += latDelta<<(24-subdiv->bits());
|
if (pos.rx() >= 0x800000 && subdiv->lon() >= 0)
|
||||||
|
pos.rx() = 0x7fffff;
|
||||||
|
pos.ry() += LS(latDelta, 24-subdiv->bits());
|
||||||
|
|
||||||
Coordinates c(toWGS24(pos.x()), toWGS24(pos.y()));
|
Coordinates c(toWGS24(pos.x()), toWGS24(pos.y()));
|
||||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||||
br = br.united(c);
|
poly.boundingRect = poly.boundingRect.united(c);
|
||||||
}
|
}
|
||||||
if (!(stream.atEnd() && stream.flush()))
|
if (!(stream.atEnd() && stream.flush()))
|
||||||
return false;
|
return false;
|
||||||
@ -271,13 +297,10 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
|
|||||||
return false;
|
return false;
|
||||||
if (subtype & 0x80 && !skipClassFields(hdl))
|
if (subtype & 0x80 && !skipClassFields(hdl))
|
||||||
return false;
|
return false;
|
||||||
if (subtype & 0x40 && !skipLclFields(hdl, line ? _linesFlags
|
if (subtype & 0x40 && !skipLclFields(hdl, segmentType == Line
|
||||||
: _polygonsFlags, segment.type()))
|
? _linesFlags : _polygonsFlags, segmentType))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!rect.intersects(br))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (lbl && (labelPtr & 0x3FFFFF))
|
if (lbl && (labelPtr & 0x3FFFFF))
|
||||||
poly.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF);
|
poly.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF);
|
||||||
|
|
||||||
@ -287,20 +310,24 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RGNFile::pointObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
|
bool RGNFile::pointObjects(Handle &hdl, const SubDiv *subdiv,
|
||||||
const Segment &segment, LBLFile *lbl, Handle &lblHdl,
|
SegmentType segmentType, LBLFile *lbl, Handle &lblHdl,
|
||||||
QList<IMG::Point> *points) const
|
QList<IMG::Point> *points) const
|
||||||
{
|
{
|
||||||
|
const SubDiv::Segment &segment = (segmentType == IndexedPoint)
|
||||||
|
? subdiv->idxPoints() : subdiv->points();
|
||||||
|
|
||||||
|
if (!segment.isValid())
|
||||||
|
return true;
|
||||||
|
if (!seek(hdl, segment.offset()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
while (hdl.pos() < (int)segment.end()) {
|
||||||
|
IMG::Point point;
|
||||||
quint8 type, subtype;
|
quint8 type, subtype;
|
||||||
qint16 lon, lat;
|
qint16 lon, lat;
|
||||||
quint32 labelPtr;
|
quint32 labelPtr;
|
||||||
|
|
||||||
if (!seek(hdl, segment.start()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
while (hdl.pos < (int)segment.end()) {
|
|
||||||
IMG::Point point;
|
|
||||||
|
|
||||||
if (!(readUInt8(hdl, type) && readUInt24(hdl, labelPtr)
|
if (!(readUInt8(hdl, type) && readUInt24(hdl, labelPtr)
|
||||||
&& readInt16(hdl, lon) && readInt16(hdl, lat)))
|
&& readInt16(hdl, lon) && readInt16(hdl, lat)))
|
||||||
return false;
|
return false;
|
||||||
@ -310,22 +337,17 @@ bool RGNFile::pointObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
|
|||||||
} else
|
} else
|
||||||
subtype = 0;
|
subtype = 0;
|
||||||
|
|
||||||
|
QPoint pos(subdiv->lon() + LS(lon, 24-subdiv->bits()),
|
||||||
|
subdiv->lat() + LS(lat, 24-subdiv->bits()));
|
||||||
|
|
||||||
point.type = (quint16)type<<8 | subtype;
|
point.type = (quint16)type<<8 | subtype;
|
||||||
|
point.coordinates = Coordinates(toWGS24(pos.x()), toWGS24(pos.y()));
|
||||||
qint16 lonOffset = lon<<(24-subdiv->bits());
|
point.id = pointId(pos, point.type, labelPtr & 0x3FFFFF);
|
||||||
qint16 latOffset = lat<<(24-subdiv->bits());
|
|
||||||
point.coordinates = Coordinates(toWGS24(subdiv->lon() + lonOffset),
|
|
||||||
toWGS24(subdiv->lat() + latOffset));
|
|
||||||
|
|
||||||
if (!rect.contains(point.coordinates))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
point.poi = labelPtr & 0x400000;
|
point.poi = labelPtr & 0x400000;
|
||||||
if (lbl && (labelPtr & 0x3FFFFF)) {
|
if (lbl && (labelPtr & 0x3FFFFF))
|
||||||
point.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF, point.poi);
|
point.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF, point.poi,
|
||||||
point.id = ((quint64)point.type)<<40 | ((quint64)lbl->offset())<<24
|
!(point.type == 0x1400 || point.type == 0x1500
|
||||||
| (labelPtr & 0x3FFFFF);
|
|| point.type == 0x1e00));
|
||||||
}
|
|
||||||
|
|
||||||
points->append(point);
|
points->append(point);
|
||||||
}
|
}
|
||||||
@ -333,48 +355,47 @@ bool RGNFile::pointObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RGNFile::extPointObjects(const RectC &rect, Handle &hdl,
|
bool RGNFile::extPointObjects(Handle &hdl, const SubDiv *subdiv, LBLFile *lbl,
|
||||||
const SubDiv *subdiv, const Segment &segment, LBLFile *lbl,
|
|
||||||
Handle &lblHdl, QList<IMG::Point> *points) const
|
Handle &lblHdl, QList<IMG::Point> *points) const
|
||||||
{
|
{
|
||||||
quint8 type, subtype;
|
const SubDiv::Segment &segment = subdiv->extPoints();
|
||||||
qint16 lon, lat;
|
|
||||||
quint32 labelPtr;
|
|
||||||
|
|
||||||
if (!seek(hdl, segment.start()))
|
if (!segment.isValid())
|
||||||
|
return true;
|
||||||
|
if (!seek(hdl, segment.offset()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
while (hdl.pos < (int)segment.end()) {
|
while (hdl.pos() < (int)segment.end()) {
|
||||||
IMG::Point point;
|
IMG::Point point;
|
||||||
|
qint16 lon, lat;
|
||||||
|
quint8 type, subtype;
|
||||||
|
quint32 labelPtr = 0;
|
||||||
|
|
||||||
if (!(readUInt8(hdl, type) && readUInt8(hdl, subtype)
|
if (!(readUInt8(hdl, type) && readUInt8(hdl, subtype)
|
||||||
&& readInt16(hdl, lon) && readInt16(hdl, lat)))
|
&& readInt16(hdl, lon) && readInt16(hdl, lat)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
point.type = 0x10000 | (((quint32)type)<<8) | (subtype & 0x1F);
|
|
||||||
|
|
||||||
qint16 lonOffset = lon<<(24-subdiv->bits());
|
|
||||||
qint16 latOffset = lat<<(24-subdiv->bits());
|
|
||||||
point.coordinates = Coordinates(toWGS24(subdiv->lon() + lonOffset),
|
|
||||||
toWGS24(subdiv->lat() + latOffset));
|
|
||||||
labelPtr = 0;
|
|
||||||
|
|
||||||
if (subtype & 0x20 && !readUInt24(hdl, labelPtr))
|
if (subtype & 0x20 && !readUInt24(hdl, labelPtr))
|
||||||
return false;
|
return false;
|
||||||
if (subtype & 0x80 && !skipClassFields(hdl))
|
if (subtype & 0x80 && !skipClassFields(hdl))
|
||||||
return false;
|
return false;
|
||||||
if (subtype & 0x40 && !skipLclFields(hdl, _pointsFlags, segment.type()))
|
if (subtype & 0x40 && !skipLclFields(hdl, _pointsFlags, Point))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!rect.contains(point.coordinates))
|
QPoint pos(subdiv->lon() + LS(lon, 24-subdiv->bits()),
|
||||||
|
subdiv->lat() + LS(lat, 24-subdiv->bits()));
|
||||||
|
|
||||||
|
point.type = 0x10000 | (((quint32)type)<<8) | (subtype & 0x1F);
|
||||||
|
// Discard NT points breaking style draw order logic (and causing huge
|
||||||
|
// performance drawback)
|
||||||
|
if (point.type == 0x11400)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
point.coordinates = Coordinates(toWGS24(pos.x()), toWGS24(pos.y()));
|
||||||
|
point.id = pointId(pos, point.type, labelPtr & 0x3FFFFF);
|
||||||
point.poi = labelPtr & 0x400000;
|
point.poi = labelPtr & 0x400000;
|
||||||
if (lbl && (labelPtr & 0x3FFFFF)) {
|
if (lbl && (labelPtr & 0x3FFFFF))
|
||||||
point.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF, point.poi);
|
point.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF, point.poi);
|
||||||
point.id = ((quint64)point.type)<<40
|
|
||||||
| ((quint64)lbl->offset())<<24 | (labelPtr & 0x3FFFFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
points->append(point);
|
points->append(point);
|
||||||
}
|
}
|
||||||
@ -382,85 +403,13 @@ bool RGNFile::extPointObjects(const RectC &rect, Handle &hdl,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RGNFile::objects(const RectC &rect, const SubDiv *subdiv,
|
QMap<RGNFile::SegmentType, SubDiv::Segment> RGNFile::segments(Handle &hdl,
|
||||||
LBLFile *lbl, NETFile *net, QList<IMG::Poly> *polygons,
|
SubDiv *subdiv) const
|
||||||
QList<IMG::Poly> *lines, QList<IMG::Point> *points)
|
|
||||||
{
|
{
|
||||||
Handle rgnHdl, lblHdl, netHdl;
|
QMap<SegmentType, SubDiv::Segment> ret;
|
||||||
|
|
||||||
if (!_init && !init(rgnHdl))
|
|
||||||
return;
|
|
||||||
|
|
||||||
QVector<Segment> seg(segments(rgnHdl, subdiv));
|
|
||||||
|
|
||||||
for (int i = 0; i < seg.size(); i++) {
|
|
||||||
const Segment &segment = seg.at(i);
|
|
||||||
|
|
||||||
if (segment.start() == segment.end())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
switch (segment.type()) {
|
|
||||||
case Segment::Point:
|
|
||||||
case Segment::IndexedPoint:
|
|
||||||
if (points)
|
|
||||||
pointObjects(rect, rgnHdl, subdiv, segment, lbl, lblHdl,
|
|
||||||
points);
|
|
||||||
break;
|
|
||||||
case Segment::Line:
|
|
||||||
if (lines)
|
|
||||||
polyObjects(rect, rgnHdl, subdiv, segment, lbl, lblHdl, net,
|
|
||||||
netHdl, lines);
|
|
||||||
break;
|
|
||||||
case Segment::Polygon:
|
|
||||||
if (polygons)
|
|
||||||
polyObjects(rect, rgnHdl, subdiv, segment, lbl, lblHdl, net,
|
|
||||||
netHdl, polygons);
|
|
||||||
break;
|
|
||||||
case Segment::RoadReference:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RGNFile::extObjects(const RectC &rect, const SubDiv *subdiv, quint32 shift,
|
|
||||||
LBLFile *lbl, QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines,
|
|
||||||
QList<IMG::Point> *points)
|
|
||||||
{
|
|
||||||
Handle rgnHdl, lblHdl;
|
|
||||||
|
|
||||||
if (!_init && !init(rgnHdl))
|
|
||||||
return;
|
|
||||||
if (polygons && subdiv->polygonsOffset() != subdiv->polygonsEnd()) {
|
|
||||||
quint32 start = _polygonsOffset + subdiv->polygonsOffset();
|
|
||||||
quint32 end = subdiv->polygonsEnd()
|
|
||||||
? _polygonsOffset + subdiv->polygonsEnd()
|
|
||||||
: _polygonsOffset + _polygonsSize;
|
|
||||||
extPolyObjects(rect, rgnHdl, subdiv, shift, Segment(start, end,
|
|
||||||
Segment::Polygon), lbl, lblHdl, polygons, false);
|
|
||||||
}
|
|
||||||
if (lines && subdiv->linesOffset() != subdiv->linesEnd()) {
|
|
||||||
quint32 start = _linesOffset + subdiv->linesOffset();
|
|
||||||
quint32 end = subdiv->linesEnd()
|
|
||||||
? _linesOffset + subdiv->linesEnd()
|
|
||||||
: _linesOffset + _linesSize;
|
|
||||||
extPolyObjects(rect, rgnHdl, subdiv, shift, Segment(start, end,
|
|
||||||
Segment::Line), lbl, lblHdl, lines, true);
|
|
||||||
}
|
|
||||||
if (points && subdiv->pointsOffset() != subdiv->pointsEnd()) {
|
|
||||||
quint32 start = _pointsOffset + subdiv->pointsOffset();
|
|
||||||
quint32 end = subdiv->pointsEnd()
|
|
||||||
? _pointsOffset + subdiv->pointsEnd()
|
|
||||||
: _pointsOffset + _pointsSize;
|
|
||||||
extPointObjects(rect, rgnHdl, subdiv, Segment(start, end,
|
|
||||||
Segment::Point), lbl, lblHdl, points);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QVector<RGNFile::Segment> RGNFile::segments(Handle &hdl, const SubDiv *subdiv)
|
|
||||||
const
|
|
||||||
{
|
|
||||||
if (subdiv->offset() == subdiv->end() || !(subdiv->objects() & 0x1F))
|
if (subdiv->offset() == subdiv->end() || !(subdiv->objects() & 0x1F))
|
||||||
return QVector<Segment>();
|
return ret;
|
||||||
|
|
||||||
quint32 offset = _offset + subdiv->offset();
|
quint32 offset = _offset + subdiv->offset();
|
||||||
|
|
||||||
@ -470,57 +419,63 @@ QVector<RGNFile::Segment> RGNFile::segments(Handle &hdl, const SubDiv *subdiv)
|
|||||||
no++;
|
no++;
|
||||||
|
|
||||||
if (!seek(hdl, offset))
|
if (!seek(hdl, offset))
|
||||||
return QVector<Segment>();
|
return ret;
|
||||||
|
|
||||||
QVector<Segment> ret;
|
|
||||||
quint32 start = offset + 2 * (no - 1);
|
quint32 start = offset + 2 * (no - 1);
|
||||||
quint16 po;
|
quint32 ls = 0;
|
||||||
int cnt = 0;
|
SegmentType lt = (SegmentType)0;
|
||||||
|
|
||||||
for (quint16 mask = 0x1; mask <= 0x10; mask <<= 1) {
|
for (quint8 mask = 0x1; mask <= 0x10; mask <<= 1) {
|
||||||
if (subdiv->objects() & mask) {
|
if (subdiv->objects() & mask) {
|
||||||
if (cnt) {
|
if (ls) {
|
||||||
if (!readUInt16(hdl, po))
|
quint16 po;
|
||||||
return QVector<Segment>();
|
if (!readUInt16(hdl, po) || !po)
|
||||||
|
return QMap<RGNFile::SegmentType, SubDiv::Segment>();
|
||||||
start = offset + po;
|
start = offset + po;
|
||||||
|
ret.insert(lt, SubDiv::Segment(ls, start));
|
||||||
}
|
}
|
||||||
if (!ret.isEmpty())
|
|
||||||
ret.last().setEnd(start);
|
lt = (SegmentType)mask;
|
||||||
ret.append(Segment(start, (Segment::Type)mask));
|
ls = start;
|
||||||
cnt++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.last().setEnd(subdiv->end() ? _offset + subdiv->end() : _offset + _size);
|
ret.insert(lt, SubDiv::Segment(ls, subdiv->end()
|
||||||
|
? _offset + subdiv->end() : _offset + _size));
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef QT_NO_DEBUG
|
bool RGNFile::subdivInit(Handle &hdl, SubDiv *subdiv) const
|
||||||
QDebug operator<<(QDebug dbg, const RGNFile::Segment &segment)
|
|
||||||
{
|
{
|
||||||
QString type;
|
QMap<RGNFile::SegmentType, SubDiv::Segment> seg(segments(hdl, subdiv));
|
||||||
switch (segment.type()) {
|
SubDiv::Segment extPoints, extLines, extPolygons;
|
||||||
case RGNFile::Segment::Point:
|
|
||||||
type = "Point";
|
if (subdiv->extPointsOffset() != subdiv->extPointsEnd()) {
|
||||||
break;
|
quint32 start = _pointsOffset + subdiv->extPointsOffset();
|
||||||
case RGNFile::Segment::IndexedPoint:
|
quint32 end = subdiv->extPointsEnd()
|
||||||
type = "IndexedPoint";
|
? _pointsOffset + subdiv->extPointsEnd()
|
||||||
break;
|
: _pointsOffset + _pointsSize;
|
||||||
case RGNFile::Segment::Line:
|
extPoints = SubDiv::Segment(start, end);
|
||||||
type = "Line";
|
}
|
||||||
break;
|
if (subdiv->extPolygonsOffset() != subdiv->extPolygonsEnd()) {
|
||||||
case RGNFile::Segment::Polygon:
|
quint32 start = _polygonsOffset + subdiv->extPolygonsOffset();
|
||||||
type = "Polygon";
|
quint32 end = subdiv->extPolygonsEnd()
|
||||||
break;
|
? _polygonsOffset + subdiv->extPolygonsEnd()
|
||||||
case RGNFile::Segment::RoadReference:
|
: _polygonsOffset + _polygonsSize;
|
||||||
type = "RoadReference";
|
extPolygons = SubDiv::Segment(start, end);
|
||||||
break;
|
}
|
||||||
|
if (subdiv->extLinesOffset() != subdiv->extLinesEnd()) {
|
||||||
|
quint32 start = _linesOffset + subdiv->extLinesOffset();
|
||||||
|
quint32 end = subdiv->extLinesEnd()
|
||||||
|
? _linesOffset + subdiv->extLinesEnd()
|
||||||
|
: _linesOffset + _linesSize;
|
||||||
|
extLines = SubDiv::Segment(start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
dbg.nospace() << "Segment(" << segment.start() << ", " << segment.end()
|
subdiv->init(seg.value(Point), seg.value(IndexedPoint), seg.value(Line),
|
||||||
- segment.start() << ", " << type << ")";
|
seg.value(Polygon), seg.value(RoadReference), extPoints, extLines,
|
||||||
|
extPolygons);
|
||||||
|
|
||||||
return dbg.space();
|
return true;
|
||||||
}
|
}
|
||||||
#endif // QT_NO_DEBUG
|
|
||||||
|
@ -12,26 +12,7 @@ class NETFile;
|
|||||||
class RGNFile : public SubFile
|
class RGNFile : public SubFile
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RGNFile(IMG *img)
|
enum SegmentType {
|
||||||
: SubFile(img), _offset(0), _size(0), _polygonsOffset(0),
|
|
||||||
_polygonsSize(0), _linesOffset(0), _linesSize(0), _pointsOffset(0),
|
|
||||||
_pointsSize(0), _init(false) {clearFlags();}
|
|
||||||
RGNFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset), _offset(0),
|
|
||||||
_size(0), _polygonsOffset(0), _polygonsSize(0), _linesOffset(0),
|
|
||||||
_linesSize(0), _pointsOffset(0), _pointsSize(0), _init(false)
|
|
||||||
{clearFlags();}
|
|
||||||
|
|
||||||
void objects(const RectC &rect, const SubDiv *subdiv,
|
|
||||||
LBLFile *lbl, NETFile *net, QList<IMG::Poly> *polygons,
|
|
||||||
QList<IMG::Poly> *lines, QList<IMG::Point> *points);
|
|
||||||
void extObjects(const RectC &rect, const SubDiv *subdiv, quint32 shift,
|
|
||||||
LBLFile *lbl, QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines,
|
|
||||||
QList<IMG::Point> *points);
|
|
||||||
|
|
||||||
private:
|
|
||||||
class Segment {
|
|
||||||
public:
|
|
||||||
enum Type {
|
|
||||||
Point = 0x1,
|
Point = 0x1,
|
||||||
IndexedPoint = 0x2,
|
IndexedPoint = 0x2,
|
||||||
Line = 0x4,
|
Line = 0x4,
|
||||||
@ -39,47 +20,42 @@ private:
|
|||||||
RoadReference = 0x10
|
RoadReference = 0x10
|
||||||
};
|
};
|
||||||
|
|
||||||
Segment() : _start(0), _end(0), _type(Point) {}
|
RGNFile(IMG *img)
|
||||||
Segment(quint32 start, Type type)
|
: SubFile(img), _offset(0), _size(0), _polygonsOffset(0),
|
||||||
: _start(start), _end(0), _type(type) {}
|
_polygonsSize(0), _linesOffset(0), _linesSize(0), _pointsOffset(0),
|
||||||
Segment(quint32 start, quint32 end, Type type)
|
_pointsSize(0), _init(false) {clearFlags();}
|
||||||
: _start(start), _end(end), _type(type) {}
|
RGNFile(const QString &path)
|
||||||
|
: SubFile(path), _offset(0), _size(0), _polygonsOffset(0),
|
||||||
void setEnd(quint32 end) {_end = end;}
|
_polygonsSize(0), _linesOffset(0), _linesSize(0), _pointsOffset(0),
|
||||||
|
_pointsSize(0), _init(false) {clearFlags();}
|
||||||
quint32 start() const {return _start;}
|
RGNFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset), _offset(0),
|
||||||
quint32 end() const {return _end;}
|
_size(0), _polygonsOffset(0), _polygonsSize(0), _linesOffset(0),
|
||||||
Type type() const {return _type;}
|
_linesSize(0), _pointsOffset(0), _pointsSize(0), _init(false)
|
||||||
|
{clearFlags();}
|
||||||
private:
|
|
||||||
quint32 _start;
|
|
||||||
quint32 _end;
|
|
||||||
Type _type;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
bool initialized() const {return _init;}
|
||||||
bool init(Handle &hdl);
|
bool init(Handle &hdl);
|
||||||
|
|
||||||
QVector<Segment> segments(Handle &hdl, const SubDiv *subdiv) const;
|
bool polyObjects(Handle &hdl, const SubDiv *subdiv, SegmentType segmentType,
|
||||||
bool polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
|
LBLFile *lbl, Handle &lblHdl, NETFile *net, Handle &netHdl,
|
||||||
const Segment &segment, LBLFile *lbl, Handle &lblHdl, NETFile *net,
|
QList<IMG::Poly> *polys) const;
|
||||||
Handle &netHdl, QList<IMG::Poly> *polys) const;
|
bool pointObjects(Handle &hdl, const SubDiv *subdiv, SegmentType segmentType,
|
||||||
bool pointObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
|
LBLFile *lbl, Handle &lblHdl, QList<IMG::Point> *points) const;
|
||||||
const Segment &segment, LBLFile *lbl, Handle &lblHdl,
|
bool extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift,
|
||||||
QList<IMG::Point> *points) const;
|
SegmentType segmentType, LBLFile *lbl, Handle &lblHdl,
|
||||||
bool extPolyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
|
QList<IMG::Poly> *polys) const;
|
||||||
quint32 shift, const Segment &segment, LBLFile *lbl, Handle &lblHdl,
|
bool extPointObjects(Handle &hdl, const SubDiv *subdiv, LBLFile *lbl,
|
||||||
QList<IMG::Poly> *polys, bool line) const;
|
Handle &lblHdl, QList<IMG::Point> *points) const;
|
||||||
bool extPointObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
|
|
||||||
const Segment &segment, LBLFile *lbl, Handle &lblHdl,
|
|
||||||
QList<IMG::Point> *points) const;
|
|
||||||
|
|
||||||
|
bool subdivInit(Handle &hdl, SubDiv *subdiv) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QMap<SegmentType, SubDiv::Segment> segments(Handle &hdl, SubDiv *subdiv)
|
||||||
|
const;
|
||||||
void clearFlags();
|
void clearFlags();
|
||||||
|
|
||||||
bool skipClassFields(Handle &hdl) const;
|
bool skipClassFields(Handle &hdl) const;
|
||||||
bool skipLclFields(Handle &hdl, const quint32 flags[3],
|
bool skipLclFields(Handle &hdl, const quint32 flags[3], SegmentType type)
|
||||||
Segment::Type type) const;
|
const;
|
||||||
|
|
||||||
friend QDebug operator<<(QDebug dbg, const RGNFile::Segment &segment);
|
|
||||||
|
|
||||||
quint32 _offset;
|
quint32 _offset;
|
||||||
quint32 _size;
|
quint32 _size;
|
||||||
@ -99,8 +75,4 @@ private:
|
|||||||
bool _init;
|
bool _init;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef QT_NO_DEBUG
|
|
||||||
QDebug operator<<(QDebug dbg, const RGNFile::Segment &segment);
|
|
||||||
#endif // QT_NO_DEBUG
|
|
||||||
|
|
||||||
#endif // RGNFILE_H
|
#endif // RGNFILE_H
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
#include <QPainter>
|
||||||
#include "style.h"
|
#include "style.h"
|
||||||
|
|
||||||
|
|
||||||
@ -24,12 +25,12 @@ void Style::defaultPolygonStyle()
|
|||||||
_polygons[TYPE(0x12)] = Polygon(QBrush("#e6e2d9"));
|
_polygons[TYPE(0x12)] = Polygon(QBrush("#e6e2d9"));
|
||||||
_polygons[TYPE(0x13)] = Polygon(QBrush("#dbd0b6"),
|
_polygons[TYPE(0x13)] = Polygon(QBrush("#dbd0b6"),
|
||||||
QPen(QColor("#cdccc4"), 1));
|
QPen(QColor("#cdccc4"), 1));
|
||||||
_polygons[TYPE(0x14)] = Polygon(QBrush("#d4ebb8"));
|
_polygons[TYPE(0x14)] = Polygon(QBrush("#cadfaf"));
|
||||||
_polygons[TYPE(0x15)] = Polygon(QBrush("#d4ebb8"));
|
_polygons[TYPE(0x15)] = Polygon(QBrush("#cadfaf"));
|
||||||
_polygons[TYPE(0x16)] = Polygon(QBrush(QColor("#9ac269"),
|
_polygons[TYPE(0x16)] = Polygon(QBrush(QColor("#9ac269"),
|
||||||
Qt::BDiagPattern));
|
Qt::BDiagPattern));
|
||||||
_polygons[TYPE(0x17)] = Polygon(QBrush("#d4ebb8"));
|
_polygons[TYPE(0x17)] = Polygon(QBrush("#e4efcf"));
|
||||||
_polygons[TYPE(0x18)] = Polygon(QBrush("#d4ebb8"));
|
_polygons[TYPE(0x18)] = Polygon(QBrush("#e3edc6"));
|
||||||
_polygons[TYPE(0x19)] = Polygon(QBrush("#e3edc6"), QPen("#c9d3a5"));
|
_polygons[TYPE(0x19)] = Polygon(QBrush("#e3edc6"), QPen("#c9d3a5"));
|
||||||
_polygons[TYPE(0x1a)] = Polygon(QBrush("#000000", Qt::Dense6Pattern),
|
_polygons[TYPE(0x1a)] = Polygon(QBrush("#000000", Qt::Dense6Pattern),
|
||||||
QPen(QColor("#cdccc4"), 1));
|
QPen(QColor("#cdccc4"), 1));
|
||||||
@ -59,33 +60,39 @@ void Style::defaultPolygonStyle()
|
|||||||
_polygons[TYPE(0x4a)] = Polygon(QBrush("#f1f0e5"), QPen("#f1f0e5"));
|
_polygons[TYPE(0x4a)] = Polygon(QBrush("#f1f0e5"), QPen("#f1f0e5"));
|
||||||
_polygons[TYPE(0x4c)] = Polygon(QBrush("#9fc4e1", Qt::Dense6Pattern));
|
_polygons[TYPE(0x4c)] = Polygon(QBrush("#9fc4e1", Qt::Dense6Pattern));
|
||||||
_polygons[TYPE(0x4d)] = Polygon(QBrush("#ddf1fd"));
|
_polygons[TYPE(0x4d)] = Polygon(QBrush("#ddf1fd"));
|
||||||
_polygons[TYPE(0x4e)] = Polygon(QBrush("#e3edc1"));
|
_polygons[TYPE(0x4e)] = Polygon(QBrush("#f8f8f8"));
|
||||||
_polygons[TYPE(0x4f)] = Polygon(QBrush("#d4ebb8"));
|
_polygons[TYPE(0x4f)] = Polygon(QBrush("#e4efcf"));
|
||||||
_polygons[TYPE(0x50)] = Polygon(QBrush("#d4ebb8"));
|
_polygons[TYPE(0x50)] = Polygon(QBrush("#cadfaf"));
|
||||||
_polygons[TYPE(0x51)] = Polygon(QBrush("#9fc4e1", Qt::Dense4Pattern));
|
_polygons[TYPE(0x51)] = Polygon(QBrush("#9fc4e1", Qt::Dense4Pattern));
|
||||||
_polygons[TYPE(0x52)] = Polygon(QBrush("#d4ebb8"));
|
_polygons[TYPE(0x52)] = Polygon(QBrush("#cadfaf"));
|
||||||
|
|
||||||
_drawOrder << TYPE(0x4b) << TYPE(0x4a) << TYPE(0x01) << TYPE(0x02)
|
_drawOrder << TYPE(0x4b) << TYPE(0x4a) << TYPE(0x01) << TYPE(0x02)
|
||||||
<< TYPE(0x03) << TYPE(0x17) << TYPE(0x18) << TYPE(0x19) << TYPE(0x1a)
|
<< TYPE(0x03) << TYPE(0x17) << TYPE(0x18) << TYPE(0x1a) << TYPE(0x28)
|
||||||
<< TYPE(0x28) << TYPE(0x29) << TYPE(0x32) << TYPE(0x3b) << TYPE(0x3c)
|
<< TYPE(0x29) << TYPE(0x32) << TYPE(0x3b) << TYPE(0x3c) << TYPE(0x3d)
|
||||||
<< TYPE(0x3d) << TYPE(0x3e) << TYPE(0x3f) << TYPE(0x40) << TYPE(0x41)
|
<< TYPE(0x3e) << TYPE(0x3f) << TYPE(0x40) << TYPE(0x41) << TYPE(0x42)
|
||||||
<< TYPE(0x42) << TYPE(0x43) << TYPE(0x44) << TYPE(0x45) << TYPE(0x46)
|
<< TYPE(0x43) << TYPE(0x44) << TYPE(0x45) << TYPE(0x46) << TYPE(0x47)
|
||||||
<< TYPE(0x47) << TYPE(0x48) << TYPE(0x49) << TYPE(0x4c) << TYPE(0x4d)
|
<< TYPE(0x48) << TYPE(0x49) << TYPE(0x4c) << TYPE(0x4d) << TYPE(0x4e)
|
||||||
<< TYPE(0x4e) << TYPE(0x4f) << TYPE(0x50) << TYPE(0x51) << TYPE(0x52)
|
<< TYPE(0x4f) << TYPE(0x50) << TYPE(0x51) << TYPE(0x52) << TYPE(0x14)
|
||||||
<< TYPE(0x14) << TYPE(0x15) << TYPE(0x16) << TYPE(0x1e) << TYPE(0x1f)
|
<< TYPE(0x15) << TYPE(0x16) << TYPE(0x1e) << TYPE(0x1f) << TYPE(0x04)
|
||||||
<< TYPE(0x04) << TYPE(0x05) << TYPE(0x06) << TYPE(0x07) << TYPE(0x08)
|
<< TYPE(0x05) << TYPE(0x06) << TYPE(0x07) << TYPE(0x08) << TYPE(0x09)
|
||||||
<< TYPE(0x09) << TYPE(0x0a) << TYPE(0x0b) << TYPE(0x0c) << TYPE(0x0d)
|
<< TYPE(0x0a) << TYPE(0x0b) << TYPE(0x0c) << TYPE(0x0d) << TYPE(0x0e)
|
||||||
<< TYPE(0x0e) << TYPE(0x0f) << TYPE(0x10) << TYPE(0x11) << TYPE(0x12)
|
<< TYPE(0x0f) << TYPE(0x10) << TYPE(0x11) << TYPE(0x12) << TYPE(0x19)
|
||||||
<< TYPE(0x13);
|
<< TYPE(0x13);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QImage railroad()
|
||||||
|
{
|
||||||
|
QImage img(16, 4, QImage::Format_ARGB32_Premultiplied);
|
||||||
|
img.fill(QColor("#717171"));
|
||||||
|
QPainter p(&img);
|
||||||
|
p.setPen(QPen(Qt::white, 2));
|
||||||
|
p.drawLine(9, 2, 15, 2);
|
||||||
|
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
|
||||||
void Style::defaultLineStyle()
|
void Style::defaultLineStyle()
|
||||||
{
|
{
|
||||||
QVector<qreal> pattern;
|
|
||||||
pattern << 4 << 4;
|
|
||||||
QPen rr(QColor("#717171"), 3, Qt::CustomDashLine);
|
|
||||||
rr.setDashPattern(pattern);
|
|
||||||
|
|
||||||
_lines[TYPE(0x01)] = Line(QPen(QColor("#9bd772"), 2, Qt::SolidLine),
|
_lines[TYPE(0x01)] = Line(QPen(QColor("#9bd772"), 2, Qt::SolidLine),
|
||||||
QPen(QColor("#72a35a"), 6, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
|
QPen(QColor("#72a35a"), 6, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
|
||||||
_lines[TYPE(0x02)] = Line(QPen(QColor("#ffcc78"), 2, Qt::SolidLine),
|
_lines[TYPE(0x02)] = Line(QPen(QColor("#ffcc78"), 2, Qt::SolidLine),
|
||||||
@ -109,13 +116,13 @@ void Style::defaultLineStyle()
|
|||||||
QPen(QColor("#e8a541"), 6, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
|
QPen(QColor("#e8a541"), 6, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
|
||||||
_lines[TYPE(0x0c)] = Line(QPen(QColor("#ffffff"), 3, Qt::SolidLine),
|
_lines[TYPE(0x0c)] = Line(QPen(QColor("#ffffff"), 3, Qt::SolidLine),
|
||||||
QPen(QColor("#d5cdc0"), 5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
|
QPen(QColor("#d5cdc0"), 5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
|
||||||
_lines[TYPE(0x14)] = Line(rr, QPen(Qt::white, 3, Qt::SolidLine,
|
_lines[TYPE(0x14)] = Line(railroad());
|
||||||
Qt::RoundCap, Qt::RoundJoin));
|
|
||||||
_lines[TYPE(0x16)] = Line(QPen(QColor("#aba083"), 1, Qt::DotLine));
|
_lines[TYPE(0x16)] = Line(QPen(QColor("#aba083"), 1, Qt::DotLine));
|
||||||
_lines[TYPE(0x18)] = Line(QPen(QColor("#9fc4e1"), 2, Qt::SolidLine));
|
_lines[TYPE(0x18)] = Line(QPen(QColor("#9fc4e1"), 2, Qt::SolidLine));
|
||||||
_lines[TYPE(0x18)].setTextColor(QColor("#9fc4e1"));
|
_lines[TYPE(0x18)].setTextColor(QColor("#9fc4e1"));
|
||||||
//_lines[TYPE(0x1a)] = Line(QPen(QColor("#7697b7"), 1, Qt::DashLine));
|
//_lines[TYPE(0x1a)] = Line(QPen(QColor("#7697b7"), 1, Qt::DashLine));
|
||||||
_lines[TYPE(0x1b)] = Line(QPen(QColor("#7697b7"), 1, Qt::DashLine));
|
_lines[TYPE(0x1b)] = Line(QPen(QColor("#7697b7"), 1, Qt::DashLine));
|
||||||
|
_lines[TYPE(0x1c)] = Line(QPen(QColor("#505145"), 1, Qt::DashLine));
|
||||||
_lines[TYPE(0x1e)] = Line(QPen(QColor("#505145"), 2, Qt::DashDotLine));
|
_lines[TYPE(0x1e)] = Line(QPen(QColor("#505145"), 2, Qt::DashDotLine));
|
||||||
_lines[TYPE(0x1f)] = Line(QPen(QColor("#9fc4e1"), 3, Qt::SolidLine));
|
_lines[TYPE(0x1f)] = Line(QPen(QColor("#9fc4e1"), 3, Qt::SolidLine));
|
||||||
_lines[TYPE(0x1f)].setTextColor(QColor("#9fc4e1"));
|
_lines[TYPE(0x1f)].setTextColor(QColor("#9fc4e1"));
|
||||||
@ -145,6 +152,17 @@ void Style::defaultLineStyle()
|
|||||||
|
|
||||||
void Style::defaultPointStyle()
|
void Style::defaultPointStyle()
|
||||||
{
|
{
|
||||||
|
// Countries
|
||||||
|
_points[TYPE(0x14)].setTextColor(QColor("#505145"));
|
||||||
|
_points[TYPE(0x14)].setTextFontSize(Small);
|
||||||
|
_points[TYPE(0x15)].setTextColor(QColor("#505145"));
|
||||||
|
_points[TYPE(0x15)].setTextFontSize(Small);
|
||||||
|
|
||||||
|
// Regions
|
||||||
|
_points[TYPE(0x1e)].setTextColor(QColor("#505145"));
|
||||||
|
_points[TYPE(0x1e)].setTextFontSize(ExtraSmall);
|
||||||
|
_points[TYPE(0x28)].setTextFontSize(Small);
|
||||||
|
|
||||||
// Cities
|
// Cities
|
||||||
_points[TYPE(0x01)].setTextFontSize(Large);
|
_points[TYPE(0x01)].setTextFontSize(Large);
|
||||||
_points[TYPE(0x02)].setTextFontSize(Large);
|
_points[TYPE(0x02)].setTextFontSize(Large);
|
||||||
@ -341,7 +359,7 @@ static bool skipLocalization(SubFile *file, SubFile::Handle &hdl)
|
|||||||
len = len >> 2;
|
len = len >> 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!file->seek(hdl, hdl.pos + len))
|
if (!file->seek(hdl, hdl.pos() + len))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -890,7 +908,7 @@ bool Style::parseDrawOrder(SubFile *file, SubFile::Handle &hdl,
|
|||||||
|
|
||||||
bool Style::parseTYPFile(SubFile *file)
|
bool Style::parseTYPFile(SubFile *file)
|
||||||
{
|
{
|
||||||
SubFile::Handle hdl;
|
SubFile::Handle hdl(file);
|
||||||
Section points, lines, polygons, order;
|
Section points, lines, polygons, order;
|
||||||
quint16 tmp16, codepage;
|
quint16 tmp16, codepage;
|
||||||
|
|
||||||
@ -939,9 +957,6 @@ Style::Style(SubFile *typ)
|
|||||||
|
|
||||||
if (typ)
|
if (typ)
|
||||||
parseTYPFile(typ);
|
parseTYPFile(typ);
|
||||||
|
|
||||||
// Override stuff breaking the style display logic
|
|
||||||
_points[0x11400] = Point(None);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Style::Line &Style::line(quint32 type) const
|
const Style::Line &Style::line(quint32 type) const
|
||||||
|
@ -16,7 +16,8 @@ public:
|
|||||||
None = 1,
|
None = 1,
|
||||||
Small = 2,
|
Small = 2,
|
||||||
Normal = 3,
|
Normal = 3,
|
||||||
Large = 4
|
Large = 4,
|
||||||
|
ExtraSmall = 5
|
||||||
};
|
};
|
||||||
|
|
||||||
enum POIClass {
|
enum POIClass {
|
||||||
|
@ -7,55 +7,147 @@
|
|||||||
|
|
||||||
class SubDiv {
|
class SubDiv {
|
||||||
public:
|
public:
|
||||||
SubDiv(quint32 offset, qint32 lon, qint32 lat, int bits, quint8 objects)
|
class Segment {
|
||||||
: _offset(offset), _end(0), _lon(lon), _lat(lat), _bits(bits),
|
public:
|
||||||
_objects(objects), _polygonsOffset(0), _polygonsEnd(0), _linesOffset(0),
|
Segment() : _offset(0), _end(0) {}
|
||||||
_linesEnd(0), _pointsOffset(0), _pointsEnd(0) {}
|
Segment(quint32 ofset, quint32 end) : _offset(ofset), _end(end) {}
|
||||||
void setEnd(quint32 end) {_end = end;}
|
|
||||||
|
bool isValid() const {return (_end > _offset);}
|
||||||
|
|
||||||
quint32 offset() const {return _offset;}
|
quint32 offset() const {return _offset;}
|
||||||
quint32 end() const {return _end;}
|
quint32 end() const {return _end;}
|
||||||
|
|
||||||
|
private:
|
||||||
|
quint32 _offset, _end;
|
||||||
|
};
|
||||||
|
|
||||||
|
SubDiv(quint32 offset, qint32 lon, qint32 lat, int bits, quint8 objects)
|
||||||
|
: _lon(lon), _lat(lat), _bits(bits), _init(false)
|
||||||
|
{
|
||||||
|
_tre.objects = objects;
|
||||||
|
_tre.offset = offset;
|
||||||
|
_tre.end = 0;
|
||||||
|
|
||||||
|
_tre.extPolygonsOffset = 0;
|
||||||
|
_tre.extPolygonsEnd = 0;
|
||||||
|
_tre.extLinesOffset = 0;
|
||||||
|
_tre.extLinesEnd = 0;
|
||||||
|
_tre.extPointsOffset = 0;
|
||||||
|
_tre.extPointsEnd = 0;
|
||||||
|
}
|
||||||
|
void setEnd(quint32 end) {_tre.end = end;}
|
||||||
|
void setExtOffsets(quint32 polygon, quint32 line, quint32 point)
|
||||||
|
{
|
||||||
|
_tre.extPolygonsOffset = polygon;
|
||||||
|
_tre.extLinesOffset = line;
|
||||||
|
_tre.extPointsOffset = point;
|
||||||
|
}
|
||||||
|
void setExtEnds(quint32 polygon, quint32 line, quint32 point)
|
||||||
|
{
|
||||||
|
_tre.extPolygonsEnd = polygon;
|
||||||
|
_tre.extLinesEnd = line;
|
||||||
|
_tre.extPointsEnd = point;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init(const Segment &points, const Segment &idxPoints,
|
||||||
|
const Segment &lines, const Segment &polygons,
|
||||||
|
const Segment &roadReferences, const Segment &extPoints,
|
||||||
|
const Segment &extLines, const Segment &extPolygons)
|
||||||
|
{
|
||||||
|
_rgn.pointsOffset = points.offset();
|
||||||
|
_rgn.pointsEnd = points.end();
|
||||||
|
_rgn.idxPointsOffset = idxPoints.offset();
|
||||||
|
_rgn.idxPointsEnd = idxPoints.end();
|
||||||
|
_rgn.linesOffset = lines.offset();
|
||||||
|
_rgn.linesEnd = lines.end();
|
||||||
|
_rgn.polygonsOffset = polygons.offset();
|
||||||
|
_rgn.polygonsEnd = polygons.end();
|
||||||
|
_rgn.roadReferencesOffset = roadReferences.offset();
|
||||||
|
_rgn.roadReferencesEnd = roadReferences.end();
|
||||||
|
_rgn.extPointsOffset = extPoints.offset();
|
||||||
|
_rgn.extPointsEnd = extPoints.end();
|
||||||
|
_rgn.extLinesOffset = extLines.offset();
|
||||||
|
_rgn.extLinesEnd = extLines.end();
|
||||||
|
_rgn.extPolygonsOffset = extPolygons.offset();
|
||||||
|
_rgn.extPolygonsEnd = extPolygons.end();
|
||||||
|
|
||||||
|
_init = true;
|
||||||
|
}
|
||||||
|
bool initialized() const {return _init;}
|
||||||
|
|
||||||
qint32 lon() const {return _lon;}
|
qint32 lon() const {return _lon;}
|
||||||
qint32 lat() const {return _lat;}
|
qint32 lat() const {return _lat;}
|
||||||
quint8 bits() const {return _bits;}
|
quint8 bits() const {return _bits;}
|
||||||
quint8 objects() const {return _objects;}
|
|
||||||
|
|
||||||
// Extended types objects (TRE7)
|
// Valid only after initialization
|
||||||
void setExtOffsets(quint32 polygon, quint32 line, quint32 point)
|
Segment points() const
|
||||||
{_polygonsOffset = polygon; _linesOffset = line; _pointsOffset = point;}
|
{return Segment(_rgn.pointsOffset, _rgn.pointsEnd);}
|
||||||
void setExtEnds(quint32 polygon, quint32 line, quint32 point)
|
Segment idxPoints() const
|
||||||
{_polygonsEnd = polygon; _linesEnd = line; _pointsEnd = point;}
|
{return Segment(_rgn.idxPointsOffset, _rgn.idxPointsEnd);}
|
||||||
|
Segment lines() const
|
||||||
|
{return Segment(_rgn.linesOffset, _rgn.linesEnd);}
|
||||||
|
Segment polygons() const
|
||||||
|
{return Segment(_rgn.polygonsOffset, _rgn.polygonsEnd);}
|
||||||
|
Segment extPoints() const
|
||||||
|
{return Segment(_rgn.extPointsOffset, _rgn.extPointsEnd);}
|
||||||
|
Segment extLines() const
|
||||||
|
{return Segment(_rgn.extLinesOffset, _rgn.extLinesEnd);}
|
||||||
|
Segment extPolygons() const
|
||||||
|
{return Segment(_rgn.extPolygonsOffset, _rgn.extPolygonsEnd);}
|
||||||
|
|
||||||
quint32 polygonsOffset() const {return _polygonsOffset;}
|
// Valid only until initialization
|
||||||
quint32 polygonsEnd() const {return _polygonsEnd;}
|
quint8 objects() const {return _tre.objects;}
|
||||||
quint32 linesOffset() const {return _linesOffset;}
|
quint32 offset() const {return _tre.offset;}
|
||||||
quint32 linesEnd() const {return _linesEnd;}
|
quint32 end() const {return _tre.end;}
|
||||||
quint32 pointsOffset() const {return _pointsOffset;}
|
quint32 extPolygonsOffset() const {return _tre.extPolygonsOffset;}
|
||||||
quint32 pointsEnd() const {return _pointsEnd;}
|
quint32 extPolygonsEnd() const {return _tre.extPolygonsEnd;}
|
||||||
|
quint32 extLinesOffset() const {return _tre.extLinesOffset;}
|
||||||
|
quint32 extLinesEnd() const {return _tre.extLinesEnd;}
|
||||||
|
quint32 extPointsOffset() const {return _tre.extPointsOffset;}
|
||||||
|
quint32 extPointsEnd() const {return _tre.extPointsEnd;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
quint32 _offset;
|
struct TRE
|
||||||
quint32 _end;
|
{
|
||||||
qint32 _lon, _lat;
|
quint8 objects;
|
||||||
quint8 _bits;
|
quint32 offset;
|
||||||
quint8 _objects;
|
quint32 end;
|
||||||
|
|
||||||
quint32 _polygonsOffset;
|
quint32 extPolygonsOffset;
|
||||||
quint32 _polygonsEnd;
|
quint32 extPolygonsEnd;
|
||||||
quint32 _linesOffset;
|
quint32 extLinesOffset;
|
||||||
quint32 _linesEnd;
|
quint32 extLinesEnd;
|
||||||
quint32 _pointsOffset;
|
quint32 extPointsOffset;
|
||||||
quint32 _pointsEnd;
|
quint32 extPointsEnd;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef QT_NO_DEBUG
|
struct RGN
|
||||||
inline QDebug operator<<(QDebug dbg, const SubDiv &subdiv)
|
|
||||||
{
|
{
|
||||||
Coordinates c(toWGS24(subdiv.lon()), toWGS24(subdiv.lat()));
|
quint32 pointsOffset;
|
||||||
dbg.nospace() << "SubDiv(" << c << ", " << subdiv.offset()
|
quint32 pointsEnd;
|
||||||
<< ", " << subdiv.end() << ", " << subdiv.objects() << ")";
|
quint32 idxPointsOffset;
|
||||||
return dbg.space();
|
quint32 idxPointsEnd;
|
||||||
}
|
quint32 linesOffset;
|
||||||
#endif // QT_NO_DEBUG
|
quint32 linesEnd;
|
||||||
|
quint32 polygonsOffset;
|
||||||
|
quint32 polygonsEnd;
|
||||||
|
quint32 roadReferencesOffset;
|
||||||
|
quint32 roadReferencesEnd;
|
||||||
|
quint32 extPointsOffset;
|
||||||
|
quint32 extPointsEnd;
|
||||||
|
quint32 extLinesOffset;
|
||||||
|
quint32 extLinesEnd;
|
||||||
|
quint32 extPolygonsOffset;
|
||||||
|
quint32 extPolygonsEnd;
|
||||||
|
};
|
||||||
|
|
||||||
|
qint32 _lon, _lat;
|
||||||
|
quint8 _bits;
|
||||||
|
bool _init;
|
||||||
|
union {
|
||||||
|
TRE _tre;
|
||||||
|
RGN _rgn;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
#endif // SUBDIV_H
|
#endif // SUBDIV_H
|
||||||
|
@ -5,39 +5,40 @@
|
|||||||
|
|
||||||
bool SubFile::seek(Handle &handle, quint32 pos) const
|
bool SubFile::seek(Handle &handle, quint32 pos) const
|
||||||
{
|
{
|
||||||
if (_file)
|
if (handle._file) {
|
||||||
return _file->seek(pos);
|
int blockNum = pos / BLOCK_SIZE;
|
||||||
else {
|
|
||||||
|
if (handle._blockNum != blockNum) {
|
||||||
|
if (!handle._file->seek((qint64)blockNum * BLOCK_SIZE))
|
||||||
|
return false;
|
||||||
|
if (handle._file->read(handle._data.data(), BLOCK_SIZE) < 0)
|
||||||
|
return false;
|
||||||
|
handle._blockNum = blockNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle._blockPos = pos % BLOCK_SIZE;
|
||||||
|
handle._pos = pos;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
quint32 blockSize = _img->blockSize();
|
quint32 blockSize = _img->blockSize();
|
||||||
int blockNum = pos / blockSize;
|
int blockNum = pos / blockSize;
|
||||||
|
|
||||||
if (handle.blockNum != blockNum) {
|
if (handle._blockNum != blockNum) {
|
||||||
if (blockNum >= _blocks->size())
|
if (blockNum >= _blocks->size())
|
||||||
return false;
|
return false;
|
||||||
if (!_img->readBlock(_blocks->at(blockNum), handle.data))
|
if (!_img->readBlock(_blocks->at(blockNum), handle._data.data()))
|
||||||
return false;
|
return false;
|
||||||
handle.blockNum = blockNum;
|
handle._blockNum = blockNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle.blockPos = pos % blockSize;
|
handle._blockPos = pos % blockSize;
|
||||||
handle.pos = pos;
|
handle._pos = pos;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SubFile::readByte(Handle &handle, quint8 &val) const
|
|
||||||
{
|
|
||||||
if (_file)
|
|
||||||
return _file->getChar((char*)&val);
|
|
||||||
else {
|
|
||||||
val = handle.data.at(handle.blockPos++);
|
|
||||||
handle.pos++;
|
|
||||||
return (handle.blockPos >= _img->blockSize())
|
|
||||||
? seek(handle, handle.pos) : true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SubFile::readVUInt32(Handle &hdl, quint32 &val) const
|
bool SubFile::readVUInt32(Handle &hdl, quint32 &val) const
|
||||||
{
|
{
|
||||||
quint8 bytes, shift, b;
|
quint8 bytes, shift, b;
|
||||||
@ -69,20 +70,6 @@ bool SubFile::readVUInt32(Handle &hdl, quint32 &val) const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SubFile::readVUInt32SW(Handle &hdl, quint32 bytes, quint32 &val) const
|
|
||||||
{
|
|
||||||
quint8 b;
|
|
||||||
|
|
||||||
val = 0;
|
|
||||||
for (quint32 i = bytes; i; i--) {
|
|
||||||
if (!readByte(hdl, b))
|
|
||||||
return false;
|
|
||||||
val |= ((quint32)b) << ((i-1) * 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SubFile::readVBitfield32(Handle &hdl, quint32 &bitfield) const
|
bool SubFile::readVBitfield32(Handle &hdl, quint32 &bitfield) const
|
||||||
{
|
{
|
||||||
quint8 bits;
|
quint8 bits;
|
||||||
@ -91,7 +78,7 @@ bool SubFile::readVBitfield32(Handle &hdl, quint32 &bitfield) const
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!(bits & 1)) {
|
if (!(bits & 1)) {
|
||||||
seek(hdl, hdl.pos - 1);
|
seek(hdl, hdl._pos - 1);
|
||||||
if (!((bits>>1) & 1)) {
|
if (!((bits>>1) & 1)) {
|
||||||
if (!((bits>>2) & 1)) {
|
if (!((bits>>2) & 1)) {
|
||||||
if (!readUInt32(hdl, bitfield))
|
if (!readUInt32(hdl, bitfield))
|
||||||
@ -111,8 +98,3 @@ bool SubFile::readVBitfield32(Handle &hdl, quint32 &bitfield) const
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SubFile::fileName() const
|
|
||||||
{
|
|
||||||
return _file ? _file->fileName() : _img->fileName();
|
|
||||||
}
|
|
||||||
|
@ -2,36 +2,56 @@
|
|||||||
#define SUBFILE_H
|
#define SUBFILE_H
|
||||||
|
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QDebug>
|
#include <QFile>
|
||||||
|
#include "img.h"
|
||||||
|
|
||||||
class QFile;
|
|
||||||
class IMG;
|
#define BLOCK_SIZE 4096
|
||||||
|
|
||||||
class SubFile
|
class SubFile
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum Type {Unknown, TRE, RGN, LBL, NET, TYP, GMP};
|
enum Type {Unknown, TRE, RGN, LBL, NET, TYP, GMP};
|
||||||
|
|
||||||
struct Handle
|
class Handle
|
||||||
{
|
{
|
||||||
Handle() : blockNum(-1), blockPos(-1), pos(-1) {}
|
public:
|
||||||
|
Handle(const SubFile *subFile)
|
||||||
|
: _file(0), _blockNum(-1), _blockPos(-1), _pos(-1)
|
||||||
|
{
|
||||||
|
if (subFile && subFile->_path) {
|
||||||
|
_file = new QFile(*(subFile->_path));
|
||||||
|
_file->open(QIODevice::ReadOnly);
|
||||||
|
_data.resize(BLOCK_SIZE);
|
||||||
|
} else if (subFile)
|
||||||
|
_data.resize(subFile->_img->blockSize());
|
||||||
|
}
|
||||||
|
~Handle() {delete _file;}
|
||||||
|
|
||||||
QByteArray data;
|
int pos() const {return _pos;}
|
||||||
int blockNum;
|
|
||||||
int blockPos;
|
private:
|
||||||
int pos;
|
friend class SubFile;
|
||||||
|
|
||||||
|
QFile *_file;
|
||||||
|
QByteArray _data;
|
||||||
|
int _blockNum;
|
||||||
|
int _blockPos;
|
||||||
|
int _pos;
|
||||||
};
|
};
|
||||||
|
|
||||||
SubFile(IMG *img)
|
SubFile(IMG *img)
|
||||||
: _gmpOffset(0), _img(img), _blocks(new QVector<quint16>()), _file(0) {}
|
: _gmpOffset(0), _img(img), _blocks(new QVector<quint16>()), _path(0) {}
|
||||||
SubFile(SubFile *gmp, quint32 offset) : _gmpOffset(offset), _img(gmp->_img),
|
SubFile(SubFile *gmp, quint32 offset) : _gmpOffset(offset), _img(gmp->_img),
|
||||||
_blocks(gmp->_blocks), _file(gmp->_file) {}
|
_blocks(gmp->_blocks), _path(gmp->_path) {}
|
||||||
SubFile(QFile *file)
|
SubFile(const QString &path)
|
||||||
: _gmpOffset(0), _img(0), _blocks(0), _file(file) {}
|
: _gmpOffset(0), _img(0), _blocks(0), _path(new QString(path)) {}
|
||||||
~SubFile()
|
~SubFile()
|
||||||
{
|
{
|
||||||
if (!_gmpOffset)
|
if (!_gmpOffset) {
|
||||||
delete _blocks;
|
delete _blocks;
|
||||||
|
delete _path;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addBlock(quint16 block) {_blocks->append(block);}
|
void addBlock(quint16 block) {_blocks->append(block);}
|
||||||
@ -97,22 +117,41 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool readVUInt32SW(Handle &hdl, quint32 bytes, quint32 &val) const
|
||||||
|
{
|
||||||
|
quint8 b;
|
||||||
|
|
||||||
|
val = 0;
|
||||||
|
for (quint32 i = bytes; i; i--) {
|
||||||
|
if (!readByte(hdl, b))
|
||||||
|
return false;
|
||||||
|
val |= ((quint32)b) << ((i-1) * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool readVUInt32(Handle &hdl, quint32 &val) const;
|
bool readVUInt32(Handle &hdl, quint32 &val) const;
|
||||||
bool readVUInt32SW(Handle &hdl, quint32 bytes, quint32 &val) const;
|
|
||||||
bool readVBitfield32(Handle &hdl, quint32 &bitfield) const;
|
bool readVBitfield32(Handle &hdl, quint32 &bitfield) const;
|
||||||
|
|
||||||
quint16 offset() const {return _blocks->first();}
|
QString fileName() const {return _path ? *_path : _img->fileName();}
|
||||||
QString fileName() const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
quint32 _gmpOffset;
|
quint32 _gmpOffset;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool readByte(Handle &handle, quint8 &val) const;
|
bool readByte(Handle &handle, quint8 &val) const
|
||||||
|
{
|
||||||
|
int blockSize = _img ? _img->blockSize() : BLOCK_SIZE;
|
||||||
|
val = handle._data.at(handle._blockPos++);
|
||||||
|
handle._pos++;
|
||||||
|
return (handle._blockPos >= blockSize)
|
||||||
|
? seek(handle, handle._pos) : true;
|
||||||
|
}
|
||||||
|
|
||||||
IMG *_img;
|
IMG *_img;
|
||||||
QVector<quint16> *_blocks;
|
QVector<quint16> *_blocks;
|
||||||
QFile *_file;
|
QString *_path;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SUBFILE_H
|
#endif // SUBFILE_H
|
||||||
|
@ -3,6 +3,11 @@
|
|||||||
#include "trefile.h"
|
#include "trefile.h"
|
||||||
|
|
||||||
|
|
||||||
|
static inline double RB(qint32 val)
|
||||||
|
{
|
||||||
|
return (val == -0x800000 || val == 0x800000) ? 180.0 : toWGS24(val);
|
||||||
|
}
|
||||||
|
|
||||||
static void demangle(quint8 *data, quint32 size, quint32 key)
|
static void demangle(quint8 *data, quint32 size, quint32 key)
|
||||||
{
|
{
|
||||||
static const unsigned char shuf[] = {
|
static const unsigned char shuf[] = {
|
||||||
@ -39,10 +44,11 @@ TREFile::~TREFile()
|
|||||||
|
|
||||||
bool TREFile::init()
|
bool TREFile::init()
|
||||||
{
|
{
|
||||||
Handle hdl;
|
Handle hdl(this);
|
||||||
quint8 locked;
|
quint8 locked;
|
||||||
quint16 hdrLen;
|
quint16 hdrLen;
|
||||||
|
|
||||||
|
|
||||||
if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)
|
if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)
|
||||||
&& seek(hdl, _gmpOffset + 0x0D) && readUInt8(hdl, locked)))
|
&& seek(hdl, _gmpOffset + 0x0D) && readUInt8(hdl, locked)))
|
||||||
return false;
|
return false;
|
||||||
@ -53,7 +59,8 @@ bool TREFile::init()
|
|||||||
&& readInt24(hdl, east) && readInt24(hdl, south) && readInt24(hdl, west)))
|
&& readInt24(hdl, east) && readInt24(hdl, south) && readInt24(hdl, west)))
|
||||||
return false;
|
return false;
|
||||||
_bounds = RectC(Coordinates(toWGS24(west), toWGS24(north)),
|
_bounds = RectC(Coordinates(toWGS24(west), toWGS24(north)),
|
||||||
Coordinates(toWGS24(east), toWGS24(south)));
|
Coordinates(RB(east), toWGS24(south)));
|
||||||
|
Q_ASSERT(_bounds.left() <= _bounds.right());
|
||||||
|
|
||||||
// Levels & subdivs info
|
// Levels & subdivs info
|
||||||
quint32 levelsOffset, levelsSize, subdivSize;
|
quint32 levelsOffset, levelsSize, subdivSize;
|
||||||
@ -108,12 +115,14 @@ bool TREFile::init()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_isBaseMap = false;
|
||||||
|
|
||||||
return (_firstLevel >= 0);
|
return (_firstLevel >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TREFile::load(int idx)
|
bool TREFile::load(int idx)
|
||||||
{
|
{
|
||||||
Handle hdl;
|
Handle hdl(this);
|
||||||
QList<SubDiv*> sl;
|
QList<SubDiv*> sl;
|
||||||
SubDiv *s = 0;
|
SubDiv *s = 0;
|
||||||
SubDivTree *tree = new SubDivTree();
|
SubDivTree *tree = new SubDivTree();
|
||||||
@ -130,8 +139,8 @@ bool TREFile::load(int idx)
|
|||||||
|
|
||||||
for (int j = 0; j < _levels.at(idx).subdivs; j++) {
|
for (int j = 0; j < _levels.at(idx).subdivs; j++) {
|
||||||
quint32 oo;
|
quint32 oo;
|
||||||
qint32 lon, lat;
|
qint32 lon, lat, width, height;
|
||||||
quint16 width, height, nextLevel;
|
quint16 nextLevel;
|
||||||
|
|
||||||
if (!(readUInt32(hdl, oo) && readInt24(hdl, lon) && readInt24(hdl, lat)
|
if (!(readUInt32(hdl, oo) && readInt24(hdl, lon) && readInt24(hdl, lat)
|
||||||
&& readUInt16(hdl, width) && readUInt16(hdl, height)))
|
&& readUInt16(hdl, width) && readUInt16(hdl, height)))
|
||||||
@ -147,17 +156,16 @@ bool TREFile::load(int idx)
|
|||||||
s->setEnd(offset);
|
s->setEnd(offset);
|
||||||
|
|
||||||
width &= 0x7FFF;
|
width &= 0x7FFF;
|
||||||
width <<= (24 - _levels.at(idx).bits);
|
width = LS(width, 24 - _levels.at(idx).bits);
|
||||||
height <<= (24 - _levels.at(idx).bits);
|
height = LS(height, 24 - _levels.at(idx).bits);
|
||||||
|
|
||||||
|
|
||||||
s = new SubDiv(offset, lon, lat, _levels.at(idx).bits, objects);
|
s = new SubDiv(offset, lon, lat, _levels.at(idx).bits, objects);
|
||||||
sl.append(s);
|
sl.append(s);
|
||||||
|
|
||||||
double min[2], max[2];
|
double min[2], max[2];
|
||||||
RectC bounds(Coordinates(toWGS24(lon - width),
|
RectC bounds(Coordinates(toWGS24(lon - width), toWGS24(lat + height)),
|
||||||
toWGS24(lat + height + 1)), Coordinates(toWGS24(lon + width + 1),
|
Coordinates(RB(lon + width), toWGS24(lat - height)));
|
||||||
toWGS24(lat - height)));
|
Q_ASSERT(bounds.left() <= bounds.right());
|
||||||
|
|
||||||
min[0] = bounds.left();
|
min[0] = bounds.left();
|
||||||
min[1] = bounds.bottom();
|
min[1] = bounds.bottom();
|
||||||
@ -199,7 +207,7 @@ bool TREFile::load(int idx)
|
|||||||
if (i)
|
if (i)
|
||||||
sl.at(i-1)->setExtEnds(polygons, lines, points);
|
sl.at(i-1)->setExtEnds(polygons, lines, points);
|
||||||
|
|
||||||
if (!seek(hdl, hdl.pos + _extended.itemSize - 12))
|
if (!seek(hdl, hdl.pos() + _extended.itemSize - 12))
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,8 +244,15 @@ void TREFile::clear()
|
|||||||
_subdivs.clear();
|
_subdivs.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
int TREFile::level(int bits)
|
int TREFile::level(int bits, bool baseMap)
|
||||||
{
|
{
|
||||||
|
if (baseMap) {
|
||||||
|
if (!_isBaseMap && _levels.first().bits > bits)
|
||||||
|
return -1;
|
||||||
|
if (_isBaseMap && bits > _levels.last().bits)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int idx = _firstLevel;
|
int idx = _firstLevel;
|
||||||
|
|
||||||
for (int i = idx + 1; i < _levels.size(); i++) {
|
for (int i = idx + 1; i < _levels.size(); i++) {
|
||||||
@ -259,10 +274,10 @@ static bool cb(SubDiv *subdiv, void *context)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<SubDiv*> TREFile::subdivs(const RectC &rect, int bits)
|
QList<SubDiv*> TREFile::subdivs(const RectC &rect, int bits, bool baseMap)
|
||||||
{
|
{
|
||||||
QList<SubDiv*> list;
|
QList<SubDiv*> list;
|
||||||
SubDivTree *tree = _subdivs.value(level(bits));
|
SubDivTree *tree = _subdivs.value(level(bits, baseMap));
|
||||||
double min[2], max[2];
|
double min[2], max[2];
|
||||||
|
|
||||||
min[0] = rect.left();
|
min[0] = rect.left();
|
||||||
|
@ -14,16 +14,20 @@ class TREFile : public SubFile
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TREFile(IMG *img) : SubFile(img) {}
|
TREFile(IMG *img) : SubFile(img) {}
|
||||||
|
TREFile(const QString &path) : SubFile(path) {}
|
||||||
TREFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset) {}
|
TREFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset) {}
|
||||||
~TREFile();
|
~TREFile();
|
||||||
|
|
||||||
bool init();
|
bool init();
|
||||||
|
void markAsBasemap() {_isBaseMap = true;}
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
const RectC &bounds() const {return _bounds;}
|
const RectC &bounds() const {return _bounds;}
|
||||||
QList<SubDiv*> subdivs(const RectC &rect, int bits);
|
QList<SubDiv*> subdivs(const RectC &rect, int bits, bool baseMap);
|
||||||
quint32 shift(quint8 bits) const
|
quint32 shift(quint8 bits) const
|
||||||
{return (bits == _levels.last().bits) ? (_flags >> 0xb) & 7 : 0;}
|
{return (bits == _levels.last().bits) ? (_flags >> 0xb) & 7 : 0;}
|
||||||
|
Range zooms() const
|
||||||
|
{return Range(_levels.at(_firstLevel).bits, _levels.last().bits);}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct MapLevel {
|
struct MapLevel {
|
||||||
@ -41,7 +45,7 @@ private:
|
|||||||
typedef RTree<SubDiv*, double, 2> SubDivTree;
|
typedef RTree<SubDiv*, double, 2> SubDivTree;
|
||||||
|
|
||||||
bool load(int idx);
|
bool load(int idx);
|
||||||
int level(int bits);
|
int level(int bits, bool baseMap);
|
||||||
bool parsePoly(Handle hdl, quint32 pos, const QMap<int, int> &level2bits,
|
bool parsePoly(Handle hdl, quint32 pos, const QMap<int, int> &level2bits,
|
||||||
QMap<quint32, int> &map);
|
QMap<quint32, int> &map);
|
||||||
bool parsePoints(Handle hdl, quint32 pos, const QMap<int, int> &level2bits);
|
bool parsePoints(Handle hdl, quint32 pos, const QMap<int, int> &level2bits);
|
||||||
@ -54,6 +58,7 @@ private:
|
|||||||
Extended _extended;
|
Extended _extended;
|
||||||
int _firstLevel;
|
int _firstLevel;
|
||||||
quint32 _flags;
|
quint32 _flags;
|
||||||
|
bool _isBaseMap;
|
||||||
|
|
||||||
QMap<int, SubDivTree*> _subdivs;
|
QMap<int, SubDivTree*> _subdivs;
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,23 @@
|
|||||||
#include "vectortile.h"
|
#include "vectortile.h"
|
||||||
|
|
||||||
|
|
||||||
|
static void copyPolys(const RectC &rect, QList<IMG::Poly> *src,
|
||||||
|
QList<IMG::Poly> *dst)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < src->size(); i++)
|
||||||
|
if (rect.intersects(src->at(i).boundingRect))
|
||||||
|
dst->append(src->at(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void copyPoints(const RectC &rect, QList<IMG::Point> *src,
|
||||||
|
QList<IMG::Point> *dst)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < src->size(); j++)
|
||||||
|
if (rect.contains(src->at(j).coordinates))
|
||||||
|
dst->append(src->at(j));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
SubFile *VectorTile::file(SubFile::Type type)
|
SubFile *VectorTile::file(SubFile::Type type)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -41,6 +59,29 @@ SubFile *VectorTile::addFile(IMG *img, SubFile::Type type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SubFile *VectorTile::addFile(const QString &path, SubFile::Type type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case SubFile::TRE:
|
||||||
|
_tre = new TREFile(path);
|
||||||
|
return _tre;
|
||||||
|
case SubFile::RGN:
|
||||||
|
_rgn = new RGNFile(path);
|
||||||
|
return _rgn;
|
||||||
|
case SubFile::LBL:
|
||||||
|
_lbl = new LBLFile(path);
|
||||||
|
return _lbl;
|
||||||
|
case SubFile::NET:
|
||||||
|
_net = new NETFile(path);
|
||||||
|
return _net;
|
||||||
|
case SubFile::GMP:
|
||||||
|
_gmp = new SubFile(path);
|
||||||
|
return _gmp;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool VectorTile::init()
|
bool VectorTile::init()
|
||||||
{
|
{
|
||||||
if (_gmp && !initGMP())
|
if (_gmp && !initGMP())
|
||||||
@ -54,7 +95,7 @@ bool VectorTile::init()
|
|||||||
|
|
||||||
bool VectorTile::initGMP()
|
bool VectorTile::initGMP()
|
||||||
{
|
{
|
||||||
SubFile::Handle hdl;
|
SubFile::Handle hdl(_gmp);
|
||||||
quint32 tre, rgn, lbl, net;
|
quint32 tre, rgn, lbl, net;
|
||||||
|
|
||||||
if (!(_gmp->seek(hdl, 0x19) && _gmp->readUInt32(hdl, tre)
|
if (!(_gmp->seek(hdl, 0x19) && _gmp->readUInt32(hdl, tre)
|
||||||
@ -62,25 +103,84 @@ bool VectorTile::initGMP()
|
|||||||
&& _gmp->readUInt32(hdl, net)))
|
&& _gmp->readUInt32(hdl, net)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_tre = new TREFile(_gmp, tre);
|
_tre = tre ? new TREFile(_gmp, tre) : 0;
|
||||||
_rgn = new RGNFile(_gmp, rgn);
|
_rgn = rgn ? new RGNFile(_gmp, rgn) : 0;
|
||||||
_lbl = new LBLFile(_gmp, lbl);
|
_lbl = lbl ? new LBLFile(_gmp, lbl) : 0;
|
||||||
_net = new NETFile(_gmp, net);
|
_net = net ? new NETFile(_gmp, net) : 0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VectorTile::objects(const RectC &rect, int bits,
|
void VectorTile::polys(const RectC &rect, int bits, bool baseMap,
|
||||||
QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines,
|
QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines,
|
||||||
QList<IMG::Point> *points) const
|
QCache<const SubDiv *, IMG::Polys> *polyCache) const
|
||||||
{
|
{
|
||||||
QList<SubDiv*> subdivs = _tre->subdivs(rect, bits);
|
SubFile::Handle rgnHdl(_rgn), lblHdl(_lbl), netHdl(_net);
|
||||||
for (int i = 0; i < subdivs.size(); i++) {
|
|
||||||
const SubDiv *subdiv = subdivs.at(i);
|
|
||||||
quint32 shift = _tre->shift(subdiv->bits());
|
|
||||||
|
|
||||||
_rgn->objects(rect, subdiv, _lbl, _net, polygons, lines, points);
|
if (!_rgn->initialized() && !_rgn->init(rgnHdl))
|
||||||
_rgn->extObjects(rect, subdiv, shift, _lbl, polygons, lines, points);
|
return;
|
||||||
|
|
||||||
|
QList<SubDiv*> subdivs = _tre->subdivs(rect, bits, baseMap);
|
||||||
|
for (int i = 0; i < subdivs.size(); i++) {
|
||||||
|
SubDiv *subdiv = subdivs.at(i);
|
||||||
|
|
||||||
|
IMG::Polys *polys = polyCache->object(subdiv);
|
||||||
|
if (!polys) {
|
||||||
|
quint32 shift = _tre->shift(subdiv->bits());
|
||||||
|
QList<IMG::Poly> p, l;
|
||||||
|
|
||||||
|
if (!subdiv->initialized() && !_rgn->subdivInit(rgnHdl, subdiv))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
_rgn->polyObjects(rgnHdl, subdiv, RGNFile::Polygon, _lbl, lblHdl,
|
||||||
|
_net, netHdl, &p);
|
||||||
|
_rgn->polyObjects(rgnHdl, subdiv, RGNFile::Line, _lbl, lblHdl,
|
||||||
|
_net, netHdl, &l);
|
||||||
|
_rgn->extPolyObjects(rgnHdl, subdiv, shift, RGNFile::Polygon, _lbl,
|
||||||
|
lblHdl, &p);
|
||||||
|
_rgn->extPolyObjects(rgnHdl, subdiv, shift, RGNFile::Line, _lbl,
|
||||||
|
lblHdl, &l);
|
||||||
|
|
||||||
|
copyPolys(rect, &p, polygons);
|
||||||
|
copyPolys(rect, &l, lines);
|
||||||
|
polyCache->insert(subdiv, new IMG::Polys(p, l));
|
||||||
|
} else {
|
||||||
|
copyPolys(rect, &(polys->polygons), polygons);
|
||||||
|
copyPolys(rect, &(polys->lines), lines);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VectorTile::points(const RectC &rect, int bits, bool baseMap,
|
||||||
|
QList<IMG::Point> *points, QCache<const SubDiv *,
|
||||||
|
QList<IMG::Point> > *pointCache) const
|
||||||
|
{
|
||||||
|
SubFile::Handle rgnHdl(_rgn), lblHdl(_lbl);
|
||||||
|
|
||||||
|
if (!_rgn->initialized() && !_rgn->init(rgnHdl))
|
||||||
|
return;
|
||||||
|
|
||||||
|
QList<SubDiv*> subdivs = _tre->subdivs(rect, bits, baseMap);
|
||||||
|
for (int i = 0; i < subdivs.size(); i++) {
|
||||||
|
SubDiv *subdiv = subdivs.at(i);
|
||||||
|
|
||||||
|
QList<IMG::Point> *pl = pointCache->object(subdiv);
|
||||||
|
if (!pl) {
|
||||||
|
QList<IMG::Point> p;
|
||||||
|
|
||||||
|
if (!subdiv->initialized() && !_rgn->subdivInit(rgnHdl, subdiv))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
_rgn->pointObjects(rgnHdl, subdiv, RGNFile::Point, _lbl, lblHdl,
|
||||||
|
&p);
|
||||||
|
_rgn->pointObjects(rgnHdl, subdiv, RGNFile::IndexedPoint, _lbl,
|
||||||
|
lblHdl, &p);
|
||||||
|
_rgn->extPointObjects(rgnHdl, subdiv, _lbl, lblHdl, &p);
|
||||||
|
|
||||||
|
copyPoints(rect, &p, points);
|
||||||
|
pointCache->insert(subdiv, new QList<IMG::Point>(p));
|
||||||
|
} else
|
||||||
|
copyPoints(rect, pl, points);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user