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

Compare commits

...

115 Commits
7.20 ... 7.25

Author SHA1 Message Date
bf0dd1b24a Version++ 2020-03-04 19:49:11 +01:00
9859608115 Added missing support for URLs defined in OnlineResources 2020-03-04 19:47:23 +01:00
9f62b7114e The service parameter is expected in the GetMap request by some servers
(The WMS specification is not 100% clear here)
2020-03-03 09:38:18 +01:00
c85f404d28 Enable specifiing of format parameters 2020-03-03 09:29:16 +01:00
bb6d6a4044 Version++ 2020-03-01 14:39:40 +01:00
521369a6ec Make the WMS tile size configurable 2020-03-01 13:59:15 +01:00
45a6cdeda0 Strip the format parameters for format comparsion 2020-03-01 13:26:19 +01:00
12827edcb2 Removed obsolete include 2020-03-01 11:46:44 +01:00
ee24bd54f1 Fixed tile cache reload issues 2020-03-01 11:43:08 +01:00
cc22df3bf2 Cosmetics 2020-03-01 10:30:00 +01:00
d7f0cda4b2 Properly parse the ScaleHint tag 2020-02-29 21:40:13 +01:00
a898ff2807 Use 72dpi in the ScaleHint to scaleDenominator transformation 2020-02-29 20:11:49 +01:00
9dd4e117f6 Added missing WMS 1.1 ScaleHint handling 2020-02-29 13:47:27 +01:00
92deaaaf2b Use the latest xmlns 2020-02-23 12:45:36 +01:00
015a9187a0 Fixed memory leak
(formal only, the data is allocated during the whole application life anyway)
2020-02-20 09:02:01 +01:00
1de9c6ef5d Version++ 2020-02-17 20:19:11 +01:00
54b6225c6c Fixed "rect inversion" problems 2020-02-17 19:23:36 +01:00
48c7299ba6 Improved railroad lines default style 2020-02-17 19:21:36 +01:00
c284b9fa7c Back to lon, lat order to not correspond with all the APIs 2020-02-17 19:20:18 +01:00
2c503a2406 Enable world basemap projection in web mercator projection 2020-02-17 09:47:47 +01:00
27edc4d6b5 Properly handle IMG basemaps (gmapbmap.img) 2020-02-17 09:19:15 +01:00
f333a76ef7 Some more regions/countries rendering improvement 2020-02-16 20:31:09 +01:00
2c114f43c5 Code cleanup 2020-02-16 15:59:51 +01:00
29e29591f8 Fixed typo 2020-02-16 13:59:19 +01:00
e4ac9fda0e Improved country names labels handling 2020-02-16 12:57:40 +01:00
26229e5871 Fixed tile bounds exceeding map bounds 2020-02-16 08:43:37 +01:00
64bee2f2f4 Use a beter default min zoom value 2020-02-15 21:58:29 +01:00
e4288ee95c Remove devel code 2020-02-15 21:51:47 +01:00
c9b3c2eedd Compute the min map zoom from the tiles 2020-02-15 21:49:00 +01:00
42e4b0769f Fixed broken tile/subdivs/polygon bounds/coordinates
+ do the coordinates left shift in a C++ standard defined way
2020-02-15 11:46:16 +01:00
ce043ef8fa Do not try to open the user style file when it is not set 2020-02-14 20:00:42 +01:00
8c7050e273 Fixed broken subdiv bounds 2020-02-14 09:20:10 +01:00
d670107a11 Fixed gap between the basemap and normal map tiles on some maps 2020-02-13 22:49:15 +01:00
7b03c4d852 Fixed error handling 2020-02-13 22:48:47 +01:00
2002b828dd Version++ 2020-02-12 20:35:59 +01:00
71f0e1d0ac Cleanup the data loading code 2020-02-12 20:33:23 +01:00
eb9767f2dd Cleanup the map loading code 2020-02-12 20:32:57 +01:00
8d06ab6208 Enable loading of GMAP maps when Garmin BaseCamp has associated them 2020-02-12 09:37:03 +01:00
187cb77858 Added missing Hungarian localization copy 2020-02-12 08:36:56 +01:00
8167a995f6 Added GMAP support info 2020-02-11 23:31:51 +01:00
b5aed7314e Merge branch 'origin/master' into Weblate. 2020-02-11 21:16:44 +01:00
464d4c5327 Removed forgotten devel code 2020-02-11 21:16:31 +01:00
11f4dc4b41 Merge branch 'origin/master' into Weblate. 2020-02-11 21:04:43 +01:00
2d3ad41d69 Use the GMAP basemaps rather than discarding them
+ some minor point rendering issues fixes
2020-02-11 21:03:55 +01:00
a7dcc57dd1 Translated using Weblate (Spanish)
Currently translated at 100.0% (351 of 351 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/es/
2020-02-11 18:50:35 +01:00
2d5e11f001 Properly handle basemap entries with './xxx' paths 2020-02-10 19:40:39 +01:00
e86f89308b Decreased GMAP read block size to 4K 2020-02-10 19:40:04 +01:00
378fa8dc0e Make caching work for both IMG and GMAP maps 2020-02-10 19:38:45 +01:00
dde8903013 Merge branch 'origin/master' into Weblate. 2020-02-10 09:33:37 +01:00
37c4fe1eba Cosmetics 2020-02-10 09:33:31 +01:00
f9db0acb03 Merge branch 'origin/master' into Weblate. 2020-02-10 09:26:32 +01:00
1aa07a6a34 Removed duplicit code 2020-02-10 09:26:23 +01:00
c302a67299 Merge branch 'origin/master' into Weblate. 2020-02-10 09:11:05 +01:00
8b6d7acec5 Give the compiler more posibilities for optimization 2020-02-10 09:10:09 +01:00
ba70fd159d Merge branch 'origin/master' into Weblate. 2020-02-10 08:55:45 +01:00
1773a1ae0d Cosmetics 2020-02-10 08:55:34 +01:00
136f08aa76 Merge branch 'origin/master' into Weblate. 2020-02-09 23:27:36 +01:00
f70d92805b Version++ 2020-02-09 23:27:22 +01:00
69e66f1856 Merge branch 'origin/master' into Weblate. 2020-02-09 23:25:25 +01:00
911c63df0c Added support for GMAP maps 2020-02-09 23:24:48 +01:00
d16899530a Merge branch 'origin/master' into Weblate. 2020-02-08 16:17:00 +01:00
e2339c67cd Fixed bitstream4 flush 2020-02-08 16:16:24 +01:00
c809d2f17e Merge branch 'origin/master' into Weblate. 2020-02-08 16:02:00 +01:00
fac0bae006 Fixed crash on GMP tiles without LBL or NET parts 2020-02-08 16:01:22 +01:00
9bd03c1225 Merge branch 'origin/master' into Weblate. 2020-02-08 10:55:07 +01:00
d63c666997 Code cleanup 2020-02-08 10:54:59 +01:00
0cd20a1e57 Unions can not have non-POD members 2020-02-08 10:52:26 +01:00
2f70d46be8 Merge branch 'origin/master' into Weblate. 2020-02-07 22:11:25 +01:00
325e83569c Redesigned IMG caching
(Cache encoded data rather than raw data)
2020-02-07 22:10:06 +01:00
56b374ed30 Merge branch 'origin/master' into Weblate. 2020-02-04 23:04:08 +01:00
df1be4aeb9 Added missing reference 2020-02-04 23:03:50 +01:00
d79bdaef78 Merge branch 'origin/master' into Weblate. 2020-02-04 23:02:01 +01:00
fa0c09b30c Code cleanup 2020-02-04 23:01:47 +01:00
95c82c501a Merge branch 'origin/master' into Weblate. 2020-02-04 21:48:14 +01:00
3b16f37e66 Some micro-optimizatoins and code cleanup 2020-02-04 21:47:31 +01:00
661e26fbdb Merge branch 'origin/master' into Weblate. 2020-02-03 23:18:28 +01:00
25939cfa62 Fixed typo
(I'd rather not investigate how it could work...)
2020-02-03 23:18:00 +01:00
c59ea4e5cd Merge branch 'origin/master' into Weblate. 2020-02-03 22:58:35 +01:00
5de1bc7e7d Update gpxsee.desktop (#271) 2020-02-03 22:58:29 +01:00
7c3399575b Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (351 of 351 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/nb_NO/
2020-02-03 09:37:41 +01:00
7bedd17071 Translated using Weblate (Polish)
Currently translated at 98.3% (345 of 351 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/pl/
2020-02-03 09:37:39 +01:00
06a84dcea2 Code cleanup 2020-02-02 09:03:35 +01:00
ca204626a1 Some hot path inlining 2020-02-01 19:21:41 +01:00
d16ef7b081 Translated using Weblate (Hungarian)
Currently translated at 100.0% (351 of 351 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/hu/
2020-01-30 09:01:52 +01:00
ef013dc036 Translated using Weblate (Hungarian)
Currently translated at 100.0% (351 of 351 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/hu/
2020-01-28 23:51:08 +01:00
633d52daca Added Hungarian localization 2020-01-28 22:02:16 +01:00
adbb5e5684 Translated using Weblate (Hungarian)
Currently translated at 98.0% (344 of 351 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/hu/
2020-01-28 14:34:01 +01:00
bd9b09df3d Merge branch 'origin/master' into Weblate. 2020-01-26 18:24:52 +01:00
ede2b6004f Added SML info 2020-01-26 18:24:48 +01:00
a516055dc2 Merge branch 'origin/master' into Weblate. 2020-01-26 18:06:26 +01:00
1ba3ada96e Added Hungarian localization stub 2020-01-26 18:05:50 +01:00
1667e0ca70 Merge branch 'origin/master' into Weblate. 2020-01-26 15:59:41 +01:00
b50d5227a5 Merge branch 'origin/master' into Weblate. 2020-01-26 14:08:23 +01:00
f38db3227f Merge branch 'origin/master' into Weblate. 2020-01-26 13:24:27 +01:00
c3aeb95660 Merge branch 'origin/master' into Weblate. 2020-01-26 13:14:09 +01:00
6bdd97611d Merge branch 'origin/master' into Weblate. 2020-01-26 13:08:16 +01:00
15e09539c7 Merge branch 'origin/master' into Weblate. 2020-01-26 13:02:48 +01:00
a225c6d308 Merge branch 'origin/master' into Weblate. 2020-01-26 12:57:56 +01:00
a94056ac7e Merge branch 'origin/master' into Weblate. 2020-01-26 12:56:15 +01:00
aea7bbdf09 Merge branch 'origin/master' into Weblate. 2020-01-26 12:51:40 +01:00
1c9b31d7c9 Merge branch 'origin/master' into Weblate. 2020-01-26 12:50:07 +01:00
7a9b26756a Merge branch 'origin/master' into Weblate. 2020-01-26 12:40:03 +01:00
eaae965719 Merge branch 'origin/master' into Weblate. 2020-01-26 12:33:41 +01:00
ca6e8638d8 Merge branch 'origin/master' into Weblate. 2020-01-26 12:17:38 +01:00
66a22fbfee Merge branch 'origin/master' into Weblate. 2020-01-26 12:08:32 +01:00
2d3ca7c5f8 Merge branch 'origin/master' into Weblate. 2020-01-26 12:02:53 +01:00
8c71d11fa6 Merge branch 'origin/master' into Weblate. 2020-01-26 11:59:36 +01:00
857c5050f4 Merge branch 'origin/master' into Weblate. 2020-01-26 11:52:39 +01:00
44d1d27c93 Merge branch 'origin/master' into Weblate. 2020-01-26 11:50:38 +01:00
68e20cff5b Merge branch 'origin/master' into Weblate. 2020-01-26 11:43:41 +01:00
1c67f1cac9 Merge branch 'origin/master' into Weblate. 2020-01-26 11:41:12 +01:00
a09d13594d Merge branch 'origin/master' into Weblate. 2020-01-26 11:28:42 +01:00
6916d0e6b4 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (351 of 351 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/uk/
2020-01-25 22:21:36 +01:00
757ec98108 Translated using Weblate (Russian)
Currently translated at 100.0% (351 of 351 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/ru/
2020-01-25 22:21:35 +01:00
2ddb5dc28b Translated using Weblate (Finnish)
Currently translated at 100.0% (351 of 351 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/fi/
2020-01-25 22:21:35 +01:00
64 changed files with 3420 additions and 952 deletions

View File

@ -1,4 +1,4 @@
version: 7.20.{build} version: 7.25.{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

View File

@ -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.

View File

@ -3,7 +3,7 @@ unix:!macx {
} else { } else {
TARGET = GPXSee TARGET = GPXSee
} }
VERSION = 7.20 VERSION = 7.25
QT += core \ QT += core \
gui \ gui \
@ -91,8 +91,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 \
@ -249,8 +251,10 @@ SOURCES += src/main.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 +363,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 +383,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

View File

@ -49,7 +49,7 @@
<message> <message>
<location filename="../src/data/data.cpp" line="179"/> <location filename="../src/data/data.cpp" line="179"/>
<source>Supported files</source> <source>Supported files</source>
<translation>Formatos soportados</translation> <translation>Formatos admitidos</translation>
</message> </message>
<message> <message>
<location filename="../src/data/data.cpp" line="180"/> <location filename="../src/data/data.cpp" line="180"/>
@ -89,7 +89,7 @@
<message> <message>
<location filename="../src/data/data.cpp" line="189"/> <location filename="../src/data/data.cpp" line="189"/>
<source>JPEG images</source> <source>JPEG images</source>
<translation>Imagen JPEG</translation> <translation>Imágenes JPEG</translation>
</message> </message>
<message> <message>
<location filename="../src/data/data.cpp" line="190"/> <location filename="../src/data/data.cpp" line="190"/>
@ -168,7 +168,7 @@
<message> <message>
<location filename="../src/GUI/elevationgraph.cpp" line="144"/> <location filename="../src/GUI/elevationgraph.cpp" line="144"/>
<source>ft</source> <source>ft</source>
<translation>pies</translation> <translation>ft</translation>
</message> </message>
</context> </context>
<context> <context>
@ -181,7 +181,7 @@
<message> <message>
<location filename="../src/GUI/elevationgraphitem.cpp" line="33"/> <location filename="../src/GUI/elevationgraphitem.cpp" line="33"/>
<source>ft</source> <source>ft</source>
<translation></translation> <translation>ft</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/elevationgraphitem.cpp" line="36"/> <location filename="../src/GUI/elevationgraphitem.cpp" line="36"/>
@ -234,7 +234,7 @@
<message> <message>
<location filename="../src/GUI/exportdialog.cpp" line="66"/> <location filename="../src/GUI/exportdialog.cpp" line="66"/>
<source>in</source> <source>in</source>
<translation></translation> <translation>in</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/exportdialog.cpp" line="94"/> <location filename="../src/GUI/exportdialog.cpp" line="94"/>
@ -301,7 +301,7 @@
<message> <message>
<location filename="../src/GUI/exportdialog.cpp" line="157"/> <location filename="../src/GUI/exportdialog.cpp" line="157"/>
<source>%1 is not writable.</source> <source>%1 is not writable.</source>
<translation>%1 es de sólo lectura.</translation> <translation>%1 es de solo lectura.</translation>
</message> </message>
</context> </context>
<context> <context>
@ -319,7 +319,7 @@
<location filename="../src/GUI/format.cpp" line="61"/> <location filename="../src/GUI/format.cpp" line="61"/>
<location filename="../src/GUI/format.cpp" line="84"/> <location filename="../src/GUI/format.cpp" line="84"/>
<source>ft</source> <source>ft</source>
<translation></translation> <translation>ft</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/format.cpp" line="57"/> <location filename="../src/GUI/format.cpp" line="57"/>
@ -403,17 +403,17 @@
<message> <message>
<location filename="../src/GUI/gui.cpp" line="256"/> <location filename="../src/GUI/gui.cpp" line="256"/>
<source>Load POI file...</source> <source>Load POI file...</source>
<translation>Cargar archivo de POI&apos;s...</translation> <translation>Cargar archivo de POI...</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="260"/> <location filename="../src/GUI/gui.cpp" line="260"/>
<source>Close POI files</source> <source>Close POI files</source>
<translation>Cerrar archivo de POI&apos;s</translation> <translation>Cerrar archivos de POI</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="264"/> <location filename="../src/GUI/gui.cpp" line="264"/>
<source>Overlap POIs</source> <source>Overlap POIs</source>
<translation>Sobrescribir POI&apos;s</translation> <translation>Sobreponer POI</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="269"/> <location filename="../src/GUI/gui.cpp" line="269"/>
@ -423,7 +423,7 @@
<message> <message>
<location filename="../src/GUI/gui.cpp" line="274"/> <location filename="../src/GUI/gui.cpp" line="274"/>
<source>Show POIs</source> <source>Show POIs</source>
<translation>Ver POI&apos;s</translation> <translation>Ver POI</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="284"/> <location filename="../src/GUI/gui.cpp" line="284"/>
@ -438,7 +438,7 @@
<message> <message>
<location filename="../src/GUI/gui.cpp" line="296"/> <location filename="../src/GUI/gui.cpp" line="296"/>
<source>Clear tile cache</source> <source>Clear tile cache</source>
<translation>Limpiar cache de teselas</translation> <translation>Limpiar antememoria de teselas</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="301"/> <location filename="../src/GUI/gui.cpp" line="301"/>
@ -455,7 +455,7 @@
<message> <message>
<location filename="../src/GUI/gui.cpp" line="322"/> <location filename="../src/GUI/gui.cpp" line="322"/>
<source>Show tracks</source> <source>Show tracks</source>
<translation>Ver tracks</translation> <translation>Ver pistas</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="327"/> <location filename="../src/GUI/gui.cpp" line="327"/>
@ -465,7 +465,7 @@
<message> <message>
<location filename="../src/GUI/gui.cpp" line="332"/> <location filename="../src/GUI/gui.cpp" line="332"/>
<source>Show waypoints</source> <source>Show waypoints</source>
<translation>Ver waypoints</translation> <translation>Ver puntos de referencia</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="337"/> <location filename="../src/GUI/gui.cpp" line="337"/>
@ -480,7 +480,7 @@
<message> <message>
<location filename="../src/GUI/gui.cpp" line="347"/> <location filename="../src/GUI/gui.cpp" line="347"/>
<source>Route waypoints</source> <source>Route waypoints</source>
<translation>Waypoints de ruta</translation> <translation>Puntos de referencia de ruta</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="352"/> <location filename="../src/GUI/gui.cpp" line="352"/>
@ -622,7 +622,7 @@
<message> <message>
<location filename="../src/GUI/gui.cpp" line="529"/> <location filename="../src/GUI/gui.cpp" line="529"/>
<source>POI files</source> <source>POI files</source>
<translation>Archivos de POI&apos;s</translation> <translation>Archivos de POI</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="540"/> <location filename="../src/GUI/gui.cpp" line="540"/>
@ -727,22 +727,22 @@
<message> <message>
<location filename="../src/GUI/gui.cpp" line="707"/> <location filename="../src/GUI/gui.cpp" line="707"/>
<source>Zoom in</source> <source>Zoom in</source>
<translation>Zoom +</translation> <translation>Acercar</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="709"/> <location filename="../src/GUI/gui.cpp" line="709"/>
<source>Zoom out</source> <source>Zoom out</source>
<translation>Zoom -</translation> <translation>Alejar</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="711"/> <location filename="../src/GUI/gui.cpp" line="711"/>
<source>Digital zoom</source> <source>Digital zoom</source>
<translation>Zoom digital</translation> <translation>Escala digital</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="712"/> <location filename="../src/GUI/gui.cpp" line="712"/>
<source>Zoom</source> <source>Zoom</source>
<translation>Zoom</translation> <translation>Escala</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="725"/> <location filename="../src/GUI/gui.cpp" line="725"/>
@ -752,7 +752,7 @@
<message> <message>
<location filename="../src/GUI/gui.cpp" line="727"/> <location filename="../src/GUI/gui.cpp" line="727"/>
<source>POI directory:</source> <source>POI directory:</source>
<translation>Carpeta de POIs:</translation> <translation>Carpeta de POI:</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="729"/> <location filename="../src/GUI/gui.cpp" line="729"/>
@ -788,17 +788,17 @@
<location filename="../src/GUI/gui.cpp" line="842"/> <location filename="../src/GUI/gui.cpp" line="842"/>
<location filename="../src/GUI/gui.cpp" line="877"/> <location filename="../src/GUI/gui.cpp" line="877"/>
<source>Line: %1</source> <source>Line: %1</source>
<translation>Linea: %1</translation> <translation>Renglón: %1</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="850"/> <location filename="../src/GUI/gui.cpp" line="850"/>
<source>Open POI file</source> <source>Open POI file</source>
<translation>Cargar archivo de POI&apos;s</translation> <translation>Cargar archivo de POI</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="874"/> <location filename="../src/GUI/gui.cpp" line="874"/>
<source>Error loading POI file:</source> <source>Error loading POI file:</source>
<translation>Error cargando archivo de POI&apos;s:</translation> <translation>Error al cargar el archivo de POI:</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="1028"/> <location filename="../src/GUI/gui.cpp" line="1028"/>
@ -816,7 +816,7 @@
<location filename="../src/GUI/gui.cpp" line="1034"/> <location filename="../src/GUI/gui.cpp" line="1034"/>
<location filename="../src/GUI/gui.cpp" line="1103"/> <location filename="../src/GUI/gui.cpp" line="1103"/>
<source>Waypoints</source> <source>Waypoints</source>
<translation>Waypoints</translation> <translation>Puntos de referencia</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="1037"/> <location filename="../src/GUI/gui.cpp" line="1037"/>
@ -851,7 +851,7 @@
<message> <message>
<location filename="../src/GUI/gui.cpp" line="1336"/> <location filename="../src/GUI/gui.cpp" line="1336"/>
<source>Error loading map:</source> <source>Error loading map:</source>
<translation>Error cargando archivo de mapa:</translation> <translation>Error al cargar el archivo de mapa:</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="1347"/> <location filename="../src/GUI/gui.cpp" line="1347"/>
@ -878,7 +878,7 @@
<message> <message>
<location filename="../src/GUI/gearratiograph.cpp" line="27"/> <location filename="../src/GUI/gearratiograph.cpp" line="27"/>
<source>Most used</source> <source>Most used</source>
<translation>Mas usada</translation> <translation>Más usada</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gearratiograph.cpp" line="29"/> <location filename="../src/GUI/gearratiograph.cpp" line="29"/>
@ -914,7 +914,7 @@
<message> <message>
<location filename="../src/GUI/graphview.cpp" line="46"/> <location filename="../src/GUI/graphview.cpp" line="46"/>
<source>Data not available</source> <source>Data not available</source>
<translation>Sin datos</translation> <translation>Sin datos disponibles</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/graphview.cpp" line="66"/> <location filename="../src/GUI/graphview.cpp" line="66"/>
@ -926,7 +926,7 @@
<location filename="../src/GUI/graphview.cpp" line="110"/> <location filename="../src/GUI/graphview.cpp" line="110"/>
<location filename="../src/GUI/graphview.cpp" line="118"/> <location filename="../src/GUI/graphview.cpp" line="118"/>
<source>ft</source> <source>ft</source>
<translation></translation> <translation>ft</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/graphview.cpp" line="113"/> <location filename="../src/GUI/graphview.cpp" line="113"/>
@ -1017,7 +1017,7 @@
<message> <message>
<location filename="../src/map/maplist.cpp" line="121"/> <location filename="../src/map/maplist.cpp" line="121"/>
<source>Supported files</source> <source>Supported files</source>
<translation>Formatos soportados</translation> <translation>Formatos admitidos</translation>
</message> </message>
<message> <message>
<location filename="../src/map/maplist.cpp" line="126"/> <location filename="../src/map/maplist.cpp" line="126"/>
@ -1047,7 +1047,7 @@
<message> <message>
<location filename="../src/map/maplist.cpp" line="128"/> <location filename="../src/map/maplist.cpp" line="128"/>
<source>GeoTIFF images</source> <source>GeoTIFF images</source>
<translation>Imagenes GeoTIFF</translation> <translation>Imágenes GeoTIFF</translation>
</message> </message>
<message> <message>
<location filename="../src/map/maplist.cpp" line="129"/> <location filename="../src/map/maplist.cpp" line="129"/>
@ -1057,7 +1057,7 @@
<message> <message>
<location filename="../src/map/maplist.cpp" line="130"/> <location filename="../src/map/maplist.cpp" line="130"/>
<source>Online map sources</source> <source>Online map sources</source>
<translation>Mapas Online</translation> <translation>Fuentes de mapas en nea</translation>
</message> </message>
</context> </context>
<context> <context>
@ -1065,12 +1065,12 @@
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="61"/> <location filename="../src/GUI/optionsdialog.cpp" line="61"/>
<source>High-resolution</source> <source>High-resolution</source>
<translation>Alta resolución</translation> <translation>Resolución alta</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="62"/> <location filename="../src/GUI/optionsdialog.cpp" line="62"/>
<source>Standard</source> <source>Standard</source>
<translation>Estandar</translation> <translation>Estándar</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="67"/> <location filename="../src/GUI/optionsdialog.cpp" line="67"/>
@ -1185,12 +1185,12 @@
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="211"/> <location filename="../src/GUI/optionsdialog.cpp" line="211"/>
<source>Waypoint color:</source> <source>Waypoint color:</source>
<translation>Color de waypoints:</translation> <translation>Color de puntos de referencia:</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="212"/> <location filename="../src/GUI/optionsdialog.cpp" line="212"/>
<source>Waypoint size:</source> <source>Waypoint size:</source>
<translation>Tamaño de wapoints:</translation> <translation>Tamaño de puntos de referencia:</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="214"/> <location filename="../src/GUI/optionsdialog.cpp" line="214"/>
@ -1207,27 +1207,27 @@
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="216"/> <location filename="../src/GUI/optionsdialog.cpp" line="216"/>
<source>Waypoints</source> <source>Waypoints</source>
<translation>Waypoints</translation> <translation>Puntos de referencia</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="227"/> <location filename="../src/GUI/optionsdialog.cpp" line="227"/>
<source>POI color:</source> <source>POI color:</source>
<translation>Color de POI&apos;s:</translation> <translation>Color de POI:</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="228"/> <location filename="../src/GUI/optionsdialog.cpp" line="228"/>
<source>POI size:</source> <source>POI size:</source>
<translation>Tamaño de POI&apos;s:</translation> <translation>Tamaño de POI:</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="232"/> <location filename="../src/GUI/optionsdialog.cpp" line="232"/>
<source>POIs</source> <source>POIs</source>
<translation>POI&apos;s</translation> <translation>POI</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="258"/> <location filename="../src/GUI/optionsdialog.cpp" line="258"/>
<source>Line width:</source> <source>Line width:</source>
<translation>Anchura de linea:</translation> <translation>Anchura de línea:</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="259"/> <location filename="../src/GUI/optionsdialog.cpp" line="259"/>
@ -1435,17 +1435,17 @@
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="509"/> <location filename="../src/GUI/optionsdialog.cpp" line="509"/>
<source>High-Resolution</source> <source>High-Resolution</source>
<translation>Alta resolución</translation> <translation>Resolución alta</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="514"/> <location filename="../src/GUI/optionsdialog.cpp" line="514"/>
<source>The printed area is approximately the display area. The map zoom level does not change.</source> <source>The printed area is approximately the display area. The map zoom level does not change.</source>
<translation>El área que se imprime es la que muestra la pantalla. El zoom del mapa no cambiará.</translation> <translation>El área que se imprime es aproximadamente la que muestra la pantalla. La escala del mapa no cambiará.</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="516"/> <location filename="../src/GUI/optionsdialog.cpp" line="516"/>
<source>The zoom level will be changed so that the whole content (tracks/waypoints) fits to the printed area and the map resolution is as close as possible to the print resolution.</source> <source>The zoom level will be changed so that the whole content (tracks/waypoints) fits to the printed area and the map resolution is as close as possible to the print resolution.</source>
<translation>El zoom del mapa se cambia para que el area impresa se ajuste a todos los elementos( tracks, waypoints...) y la resolución sea lo mas próxima posible a la de impresión.</translation> <translation>La escala del mapa se cambia para que el área impresa se ajuste a todos los elementos (pistas, puntos de referencia...) y la resolución sea lo mas próxima posible a la de impresión.</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="538"/> <location filename="../src/GUI/optionsdialog.cpp" line="538"/>
@ -1500,17 +1500,17 @@
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="585"/> <location filename="../src/GUI/optionsdialog.cpp" line="585"/>
<source>Enable HTTP/2</source> <source>Enable HTTP/2</source>
<translation>Habilitar HTTP/2</translation> <translation>Activar HTTP/2</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="592"/> <location filename="../src/GUI/optionsdialog.cpp" line="592"/>
<source>MB</source> <source>MB</source>
<translation>Mo</translation> <translation>MB</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="602"/> <location filename="../src/GUI/optionsdialog.cpp" line="602"/>
<source>Image cache size:</source> <source>Image cache size:</source>
<translation>Tamaño del cache de imágenes:</translation> <translation>Tamaño de antememoria de imágenes:</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="603"/> <location filename="../src/GUI/optionsdialog.cpp" line="603"/>
@ -1591,7 +1591,7 @@
<message> <message>
<location filename="../src/GUI/powergraphitem.cpp" line="17"/> <location filename="../src/GUI/powergraphitem.cpp" line="17"/>
<source>Maximum</source> <source>Maximum</source>
<translation>Maxima</translation> <translation>Máxima</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/powergraphitem.cpp" line="18"/> <location filename="../src/GUI/powergraphitem.cpp" line="18"/>
@ -1639,7 +1639,7 @@
<location filename="../src/GUI/scaleitem.cpp" line="109"/> <location filename="../src/GUI/scaleitem.cpp" line="109"/>
<location filename="../src/GUI/scaleitem.cpp" line="112"/> <location filename="../src/GUI/scaleitem.cpp" line="112"/>
<source>ft</source> <source>ft</source>
<translation></translation> <translation>ft</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/scaleitem.cpp" line="111"/> <location filename="../src/GUI/scaleitem.cpp" line="111"/>

View File

@ -114,7 +114,7 @@
<message> <message>
<location filename="../src/data/data.cpp" line="195"/> <location filename="../src/data/data.cpp" line="195"/>
<source>SML files</source> <source>SML files</source>
<translation type="unfinished"></translation> <translation>SML-tiedostot</translation>
</message> </message>
<message> <message>
<location filename="../src/data/data.cpp" line="196"/> <location filename="../src/data/data.cpp" line="196"/>

1900
lang/gpxsee_hu.ts Normal file

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,7 @@
<location filename="../src/GUI/cadencegraph.cpp" line="12"/> <location filename="../src/GUI/cadencegraph.cpp" line="12"/>
<location filename="../src/GUI/cadencegraph.h" line="16"/> <location filename="../src/GUI/cadencegraph.h" line="16"/>
<source>Cadence</source> <source>Cadence</source>
<translation type="unfinished">Stegfrekvens</translation> <translation>Stegfrekvens</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/cadencegraph.cpp" line="27"/> <location filename="../src/GUI/cadencegraph.cpp" line="27"/>
@ -214,7 +214,7 @@
<message> <message>
<location filename="../src/GUI/exportdialog.cpp" line="25"/> <location filename="../src/GUI/exportdialog.cpp" line="25"/>
<source>All files</source> <source>All files</source>
<translation type="unfinished">Alle filer</translation> <translation>Alle filer</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/exportdialog.cpp" line="52"/> <location filename="../src/GUI/exportdialog.cpp" line="52"/>
@ -239,7 +239,7 @@
<message> <message>
<location filename="../src/GUI/exportdialog.cpp" line="94"/> <location filename="../src/GUI/exportdialog.cpp" line="94"/>
<source>Page Setup</source> <source>Page Setup</source>
<translation>Sideinnstilling</translation> <translation>Sideoppsett</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/exportdialog.cpp" line="97"/> <location filename="../src/GUI/exportdialog.cpp" line="97"/>
@ -373,17 +373,17 @@
<message> <message>
<location filename="../src/GUI/gui.cpp" line="217"/> <location filename="../src/GUI/gui.cpp" line="217"/>
<source>Open...</source> <source>Open...</source>
<translation type="unfinished">Åpne</translation> <translation>Åpne</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="222"/> <location filename="../src/GUI/gui.cpp" line="222"/>
<source>Print...</source> <source>Print...</source>
<translation type="unfinished">Skriv ut</translation> <translation>Skriv ut</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="229"/> <location filename="../src/GUI/gui.cpp" line="229"/>
<source>Export to PDF...</source> <source>Export to PDF...</source>
<translation type="unfinished">Eksporter til PDF</translation> <translation>Eksporter til PDF</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="235"/> <location filename="../src/GUI/gui.cpp" line="235"/>
@ -398,12 +398,12 @@
<message> <message>
<location filename="../src/GUI/gui.cpp" line="248"/> <location filename="../src/GUI/gui.cpp" line="248"/>
<source>Statistics...</source> <source>Statistics...</source>
<translation type="unfinished">Statistikk</translation> <translation>Statistikk</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="256"/> <location filename="../src/GUI/gui.cpp" line="256"/>
<source>Load POI file...</source> <source>Load POI file...</source>
<translation type="unfinished">Last inn POI-fil</translation> <translation>Last inn POI-fil</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="260"/> <location filename="../src/GUI/gui.cpp" line="260"/>
@ -433,7 +433,7 @@
<message> <message>
<location filename="../src/GUI/gui.cpp" line="292"/> <location filename="../src/GUI/gui.cpp" line="292"/>
<source>Load map...</source> <source>Load map...</source>
<translation type="unfinished">Last inn kart</translation> <translation>Last inn kart</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="296"/> <location filename="../src/GUI/gui.cpp" line="296"/>
@ -485,7 +485,7 @@
<message> <message>
<location filename="../src/GUI/gui.cpp" line="352"/> <location filename="../src/GUI/gui.cpp" line="352"/>
<source>km/mi markers</source> <source>km/mi markers</source>
<translation type="unfinished">km/mi-markører</translation> <translation>km/mi-markører</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="359"/> <location filename="../src/GUI/gui.cpp" line="359"/>
@ -520,7 +520,7 @@
<message> <message>
<location filename="../src/GUI/gui.cpp" line="393"/> <location filename="../src/GUI/gui.cpp" line="393"/>
<source>Show path markers</source> <source>Show path markers</source>
<translation type="unfinished">Vis veimarkører</translation> <translation>Vis veimarkører</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="400"/> <location filename="../src/GUI/gui.cpp" line="400"/>
@ -557,17 +557,17 @@
<message> <message>
<location filename="../src/GUI/gui.cpp" line="441"/> <location filename="../src/GUI/gui.cpp" line="441"/>
<source>Decimal degrees (DD)</source> <source>Decimal degrees (DD)</source>
<translation type="unfinished">Desimalgrader (DD)</translation> <translation>Desimalgrader (DD)</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="447"/> <location filename="../src/GUI/gui.cpp" line="447"/>
<source>Degrees and decimal minutes (DMM)</source> <source>Degrees and decimal minutes (DMM)</source>
<translation type="unfinished">Desimalgrader og desimalminutter (DMM)</translation> <translation>Desimalgrader og desimalminutter (DMM)</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="454"/> <location filename="../src/GUI/gui.cpp" line="454"/>
<source>Degrees, minutes, seconds (DMS)</source> <source>Degrees, minutes, seconds (DMS)</source>
<translation type="unfinished">Grader, minutter, sekunder (DMS)</translation> <translation>Grader, minutter, sekunder (DMS)</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="460"/> <location filename="../src/GUI/gui.cpp" line="460"/>
@ -577,7 +577,7 @@
<message> <message>
<location filename="../src/GUI/gui.cpp" line="467"/> <location filename="../src/GUI/gui.cpp" line="467"/>
<source>Options...</source> <source>Options...</source>
<translation type="unfinished">Valg</translation> <translation>Valg</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="473"/> <location filename="../src/GUI/gui.cpp" line="473"/>
@ -647,7 +647,7 @@
<message> <message>
<location filename="../src/GUI/gui.cpp" line="559"/> <location filename="../src/GUI/gui.cpp" line="559"/>
<source>Coordinates format</source> <source>Coordinates format</source>
<translation type="unfinished">Koordinatformat</translation> <translation>Koordinatformat</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/gui.cpp" line="569"/> <location filename="../src/GUI/gui.cpp" line="569"/>
@ -861,7 +861,7 @@
<message numerus="yes"> <message numerus="yes">
<location filename="../src/GUI/gui.cpp" line="1351"/> <location filename="../src/GUI/gui.cpp" line="1351"/>
<source>%n files</source> <source>%n files</source>
<translation type="unfinished"> <translation>
<numerusform>%n fil</numerusform> <numerusform>%n fil</numerusform>
<numerusform>%n filer</numerusform> <numerusform>%n filer</numerusform>
</translation> </translation>
@ -974,7 +974,7 @@
<message> <message>
<location filename="../src/GUI/heartrategraph.cpp" line="11"/> <location filename="../src/GUI/heartrategraph.cpp" line="11"/>
<source>bpm</source> <source>bpm</source>
<translation type="unfinished">s/m</translation> <translation>bpm</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/heartrategraph.cpp" line="12"/> <location filename="../src/GUI/heartrategraph.cpp" line="12"/>
@ -1095,12 +1095,12 @@
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="176"/> <location filename="../src/GUI/optionsdialog.cpp" line="176"/>
<source>Palette shift:</source> <source>Palette shift:</source>
<translation type="unfinished">Palettforskyvning:</translation> <translation>Palettforskyvning:</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="120"/> <location filename="../src/GUI/optionsdialog.cpp" line="120"/>
<source>Track width:</source> <source>Track width:</source>
<translation type="unfinished">Sporbredde:</translation> <translation>Sporbredde:</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="80"/> <location filename="../src/GUI/optionsdialog.cpp" line="80"/>
@ -1115,7 +1115,7 @@
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="121"/> <location filename="../src/GUI/optionsdialog.cpp" line="121"/>
<source>Track style:</source> <source>Track style:</source>
<translation type="unfinished">Sporstil:</translation> <translation>Sporstil:</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="123"/> <location filename="../src/GUI/optionsdialog.cpp" line="123"/>
@ -1159,12 +1159,12 @@
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="156"/> <location filename="../src/GUI/optionsdialog.cpp" line="156"/>
<source>Area border style:</source> <source>Area border style:</source>
<translation type="unfinished">Kantstil for område:</translation> <translation>Kantstil for område:</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="157"/> <location filename="../src/GUI/optionsdialog.cpp" line="157"/>
<source>Area fill opacity:</source> <source>Area fill opacity:</source>
<translation type="unfinished">Fylldekkevne for område:</translation> <translation>Ugjennomsiktighet for område:</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="161"/> <location filename="../src/GUI/optionsdialog.cpp" line="161"/>
@ -1232,7 +1232,7 @@
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="259"/> <location filename="../src/GUI/optionsdialog.cpp" line="259"/>
<source>Slider color:</source> <source>Slider color:</source>
<translation type="unfinished">Linjalfarge:</translation> <translation>Farge skyveregulering:</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="282"/> <location filename="../src/GUI/optionsdialog.cpp" line="282"/>
@ -1374,7 +1374,7 @@
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="448"/> <location filename="../src/GUI/optionsdialog.cpp" line="448"/>
<source>Elevation</source> <source>Elevation</source>
<translation type="unfinished">Høyde</translation> <translation>Høyde</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/optionsdialog.cpp" line="459"/> <location filename="../src/GUI/optionsdialog.cpp" line="459"/>
@ -1668,17 +1668,17 @@
<message> <message>
<location filename="../src/GUI/speedgraph.cpp" line="31"/> <location filename="../src/GUI/speedgraph.cpp" line="31"/>
<source>min/km</source> <source>min/km</source>
<translation type="unfinished">min/km</translation> <translation>min/km</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/speedgraph.cpp" line="32"/> <location filename="../src/GUI/speedgraph.cpp" line="32"/>
<source>min/mi</source> <source>min/mi</source>
<translation type="unfinished">min/mi</translation> <translation>min/mi</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/speedgraph.cpp" line="32"/> <location filename="../src/GUI/speedgraph.cpp" line="32"/>
<source>min/nmi</source> <source>min/nmi</source>
<translation type="unfinished">min/nmi</translation> <translation>min/nmi</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/speedgraph.cpp" line="34"/> <location filename="../src/GUI/speedgraph.cpp" line="34"/>
@ -1741,7 +1741,7 @@
<message> <message>
<location filename="../src/GUI/speedgraphitem.cpp" line="28"/> <location filename="../src/GUI/speedgraphitem.cpp" line="28"/>
<source>min/nmi</source> <source>min/nmi</source>
<translation type="unfinished">min/nmi</translation> <translation>min/nmi</translation>
</message> </message>
<message> <message>
<location filename="../src/GUI/speedgraphitem.cpp" line="31"/> <location filename="../src/GUI/speedgraphitem.cpp" line="31"/>

View File

@ -59,7 +59,7 @@
<message> <message>
<location filename="../src/data/data.cpp" line="181"/> <location filename="../src/data/data.cpp" line="181"/>
<source>CUP files</source> <source>CUP files</source>
<translation type="unfinished"></translation> <translation>Pliki CUP</translation>
</message> </message>
<message> <message>
<location filename="../src/data/data.cpp" line="182"/> <location filename="../src/data/data.cpp" line="182"/>
@ -74,7 +74,7 @@
<message> <message>
<location filename="../src/data/data.cpp" line="186"/> <location filename="../src/data/data.cpp" line="186"/>
<source>GPI files</source> <source>GPI files</source>
<translation type="unfinished"></translation> <translation>Pliki GPI</translation>
</message> </message>
<message> <message>
<location filename="../src/data/data.cpp" line="187"/> <location filename="../src/data/data.cpp" line="187"/>
@ -114,7 +114,7 @@
<message> <message>
<location filename="../src/data/data.cpp" line="195"/> <location filename="../src/data/data.cpp" line="195"/>
<source>SML files</source> <source>SML files</source>
<translation type="unfinished"></translation> <translation>Pliki SML</translation>
</message> </message>
<message> <message>
<location filename="../src/data/data.cpp" line="196"/> <location filename="../src/data/data.cpp" line="196"/>

View File

@ -114,7 +114,7 @@
<message> <message>
<location filename="../src/data/data.cpp" line="195"/> <location filename="../src/data/data.cpp" line="195"/>
<source>SML files</source> <source>SML files</source>
<translation type="unfinished"></translation> <translation>SML файлы</translation>
</message> </message>
<message> <message>
<location filename="../src/data/data.cpp" line="196"/> <location filename="../src/data/data.cpp" line="196"/>

View File

@ -119,7 +119,7 @@
<message> <message>
<location filename="../src/data/data.cpp" line="195"/> <location filename="../src/data/data.cpp" line="195"/>
<source>SML files</source> <source>SML files</source>
<translation type="unfinished"></translation> <translation>SML файли</translation>
</message> </message>
<message> <message>
<location filename="../src/data/data.cpp" line="196"/> <location filename="../src/data/data.cpp" line="196"/>

View File

@ -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;

View File

@ -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.25"
; 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"

View File

@ -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.25"
; 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"

View File

@ -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"/>

View File

@ -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>

View File

@ -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>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -112,7 +112,7 @@ void GUI::loadMaps()
QString mapDir(ProgramPaths::mapDir()); QString mapDir(ProgramPaths::mapDir());
if (!mapDir.isNull() && !_ml->loadDir(mapDir)) if (!mapDir.isNull() && !_ml->loadDir(mapDir))
qWarning("%s", qPrintable(_ml->errorString())); qWarning("%s", qPrintable(_ml->errorPath() + ": " + _ml->errorString()));
_map = new EmptyMap(this); _map = new EmptyMap(this);
} }
@ -1325,7 +1325,10 @@ bool GUI::loadMap(const QString &fileName)
if (fileName.isEmpty()) if (fileName.isEmpty())
return false; return false;
if (_ml->loadFile(fileName)) { QFileInfo fi(fileName);
bool res = fi.isDir() ? _ml->loadDir(fileName) : _ml->loadFile(fileName);
if (res) {
QAction *a = createMapAction(_ml->maps().last()); QAction *a = createMapAction(_ml->maps().last());
_mapMenu->insertAction(_mapsEnd, a); _mapMenu->insertAction(_mapsEnd, a);
_showMapAction->setEnabled(true); _showMapAction->setEnabled(true);

View File

@ -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"
@ -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)
@ -982,7 +980,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()));

View File

@ -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

View File

@ -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

View File

@ -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;}

View File

@ -44,37 +44,37 @@ 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;
} }
QHash<QString, Parser*> Data::_parsers = parsers(); QMap<QString, Parser*> Data::_parsers = parsers();
bool Data::_useDEM = false; bool Data::_useDEM = false;
void Data::processData(QList<TrackData> &trackData, QList<RouteData> &routeData) void Data::processData(QList<TrackData> &trackData, QList<RouteData> &routeData)
@ -130,7 +130,7 @@ 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)) {
@ -166,17 +166,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,10 +191,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;
} }

View File

@ -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"
@ -42,7 +42,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; static bool _useDEM;
}; };

View File

@ -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();
} }
} }

View File

@ -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;
} }

161
src/map/IMG/gmap.cpp Normal file
View File

@ -0,0 +1,161 @@
#include <QXmlStreamReader>
#include <QDir>
#include "map/osm.h"
#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());
// Limit world maps bounds so that the maps can be projected using
// the default Web Mercator projection
if (_bounds.height() > 120)
_bounds &= OSM::BOUNDS;
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
View 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

View File

@ -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;

View File

@ -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();}

View File

@ -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;
}; };

View File

@ -1,27 +1,11 @@
#include <QMap> #include <QMap>
#include <QtEndian> #include <QtEndian>
#include "common/programpaths.h" #include "map/osm.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 &rect;
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 +25,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 +35,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 +61,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 +88,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 +133,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,73 +154,32 @@ 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();
}
// Limit world maps bounds so that the maps can be projected using
// the default Web Mercator projection
if (_bounds.height() > 120)
_bounds &= OSM::BOUNDS;
if (!_tileTree.Count()) if (!_tileTree.Count())
_errorString = "No usable map tile found"; _errorString = "No usable map tile found";
else else
_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 +201,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

View File

@ -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

View File

@ -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;
@ -157,12 +165,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 +194,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();
} }

View File

@ -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
View 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 &rect;
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 &rect;
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
View 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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -1,4 +1,5 @@
#include <QImage> #include <QImage>
#include <QPainter>
#include "style.h" #include "style.h"
@ -79,13 +80,19 @@ void Style::defaultPolygonStyle()
<< 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

View File

@ -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 {

View File

@ -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; {
quint8 objects;
quint32 offset;
quint32 end;
quint32 extPolygonsOffset;
quint32 extPolygonsEnd;
quint32 extLinesOffset;
quint32 extLinesEnd;
quint32 extPointsOffset;
quint32 extPointsEnd;
};
struct RGN
{
quint32 pointsOffset;
quint32 pointsEnd;
quint32 idxPointsOffset;
quint32 idxPointsEnd;
quint32 linesOffset;
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; qint32 _lon, _lat;
quint8 _bits; quint8 _bits;
quint8 _objects; bool _init;
union {
quint32 _polygonsOffset; TRE _tre;
quint32 _polygonsEnd; RGN _rgn;
quint32 _linesOffset; };
quint32 _linesEnd;
quint32 _pointsOffset;
quint32 _pointsEnd;
}; };
#ifndef QT_NO_DEBUG
inline QDebug operator<<(QDebug dbg, const SubDiv &subdiv)
{
Coordinates c(toWGS24(subdiv.lon()), toWGS24(subdiv.lat()));
dbg.nospace() << "SubDiv(" << c << ", " << subdiv.offset()
<< ", " << subdiv.end() << ", " << subdiv.objects() << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG
#endif // SUBDIV_H #endif // SUBDIV_H

View File

@ -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();
}

View File

@ -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

View File

@ -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();

View File

@ -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;
}; };

View File

@ -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);
} }
} }

View File

@ -1,7 +1,6 @@
#ifndef VECTORTILE_H #ifndef VECTORTILE_H
#define VECTORTILE_H #define VECTORTILE_H
#include "img.h"
#include "trefile.h" #include "trefile.h"
#include "trefile.h" #include "trefile.h"
#include "rgnfile.h" #include "rgnfile.h"
@ -17,15 +16,22 @@ public:
} }
bool init(); bool init();
void markAsBasemap() {_tre->markAsBasemap();}
void clear() {_tre->clear();} void clear() {_tre->clear();}
const RectC &bounds() const {return _tre->bounds();} const RectC &bounds() const {return _tre->bounds();}
Range zooms() const {return _tre->zooms();}
SubFile *file(SubFile::Type type); SubFile *file(SubFile::Type type);
SubFile *addFile(IMG *img, SubFile::Type type); SubFile *addFile(IMG *img, SubFile::Type type);
SubFile *addFile(const QString &path, SubFile::Type type);
void objects(const RectC &rect, int bits, QList<IMG::Poly> *polygons, void polys(const RectC &rect, int bits, bool baseMap,
QList<IMG::Poly> *lines, QList<IMG::Point> *points) const; QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines,
QCache<const SubDiv *, IMG::Polys> *polyCache) const;
void points(const RectC &rect, int bits, bool baseMap,
QList<IMG::Point> *points, QCache<const SubDiv*,
QList<IMG::Point> > *pointCache) const;
static bool isTileFile(SubFile::Type type) static bool isTileFile(SubFile::Type type)
{ {
@ -34,8 +40,6 @@ public:
|| type == SubFile::GMP); || type == SubFile::GMP);
} }
friend QDebug operator<<(QDebug dbg, const VectorTile &tile);
private: private:
bool initGMP(); bool initGMP();

View File

@ -13,6 +13,9 @@
#include "IMG/textpathitem.h" #include "IMG/textpathitem.h"
#include "IMG/textpointitem.h" #include "IMG/textpointitem.h"
#include "IMG/bitmapline.h" #include "IMG/bitmapline.h"
#include "IMG/style.h"
#include "IMG/img.h"
#include "IMG/gmap.h"
#include "pcs.h" #include "pcs.h"
#include "rectd.h" #include "rectd.h"
#include "imgmap.h" #include "imgmap.h"
@ -35,9 +38,9 @@ public:
const QString &key() const {return _key;} const QString &key() const {return _key;}
const QPoint &xy() const {return _xy;} const QPoint &xy() const {return _xy;}
QImage &img() {return _img;} QImage &img() {return _img;}
QList<IMG::Poly> &polygons() {return _polygons;} QList<MapData::Poly> &polygons() {return _polygons;}
QList<IMG::Poly> &lines() {return _lines;} QList<MapData::Poly> &lines() {return _lines;}
QList<IMG::Point> &points() {return _points;} QList<MapData::Point> &points() {return _points;}
void render() void render()
{ {
@ -70,14 +73,12 @@ private:
QPoint _xy; QPoint _xy;
QString _key; QString _key;
QImage _img; QImage _img;
QList<IMG::Poly> _polygons; QList<MapData::Poly> _polygons;
QList<IMG::Poly> _lines; QList<MapData::Poly> _lines;
QList<IMG::Point> _points; QList<MapData::Point> _points;
}; };
static const Range zooms(12, 28);
static const QColor shieldColor(Qt::white); static const QColor shieldColor(Qt::white);
static const QColor shieldBgColor1("#dd3e3e"); static const QColor shieldBgColor1("#dd3e3e");
static const QColor shieldBgColor2("#379947"); static const QColor shieldBgColor2("#379947");
@ -126,6 +127,7 @@ static QFont *font(Style::FontSize size, Style::FontSize defaultSize
static QFont large = pixelSizeFont(16); static QFont large = pixelSizeFont(16);
static QFont normal = pixelSizeFont(14); static QFont normal = pixelSizeFont(14);
static QFont small = pixelSizeFont(12); static QFont small = pixelSizeFont(12);
static QFont extraSmall = pixelSizeFont(10);
switch (size) { switch (size) {
case Style::None: case Style::None:
@ -136,6 +138,8 @@ static QFont *font(Style::FontSize size, Style::FontSize defaultSize
return &normal; return &normal;
case Style::Small: case Style::Small:
return &small; return &small;
case Style::ExtraSmall:
return &extraSmall;
default: default:
return font(defaultSize); return font(defaultSize);
} }
@ -201,25 +205,20 @@ static qreal area(const QVector<QPointF> &polygon)
return area; return area;
} }
static QPointF centroid(const QVector<QPointF> polygon) static QPointF centroid(const QVector<QPointF> &polygon)
{ {
qreal cx = 0, cy = 0, factor = 0; qreal cx = 0, cy = 0;
qreal A = area(polygon); qreal factor = 1.0 / (6.0 * area(polygon));
for (int i = 0; i < polygon.size(); i++) { for (int i = 0; i < polygon.size(); i++) {
int j = (i + 1) % polygon.size(); int j = (i + 1) % polygon.size();
factor=(polygon.at(i).x() * polygon.at(j).y() - polygon[j].x() qreal f = (polygon.at(i).x() * polygon.at(j).y() - polygon.at(j).x()
* polygon[i].y()); * polygon.at(i).y());
cx+=(polygon[i].x() + polygon[j].x()) * factor; cx += (polygon.at(i).x() + polygon.at(j).x()) * f;
cy+=(polygon[i].y() + polygon[j].y()) * factor; cy += (polygon.at(i).y() + polygon.at(j).y()) * f;
} }
A *= 6.0f; return QPointF(cx * factor, cy * factor);
factor = 1/A;
cx *= factor;
cy *= factor;
return QPointF(cx, cy);
} }
static bool rectNearPolygon(const QPolygonF &polygon, const QRectF &rect) static bool rectNearPolygon(const QPolygonF &polygon, const QRectF &rect)
@ -231,15 +230,21 @@ static bool rectNearPolygon(const QPolygonF &polygon, const QRectF &rect)
|| polygon.containsPoint(rect.bottomRight(), Qt::OddEvenFill))); || polygon.containsPoint(rect.bottomRight(), Qt::OddEvenFill)));
} }
IMGMap::IMGMap(const QString &fileName, QObject *parent) IMGMap::IMGMap(const QString &fileName, QObject *parent)
: Map(parent), _img(fileName), _projection(PCS::pcs(3857)), _valid(false) : Map(parent), _projection(PCS::pcs(3857)), _valid(false)
{ {
if (!_img.isValid()) { if (GMAP::isGMAP(fileName))
_errorString = _img.errorString(); _data = new GMAP(fileName);
else
_data = new IMG(fileName);
if (!_data->isValid()) {
_errorString = _data->errorString();
return; return;
} }
_zoom = zooms.min(); _zoom = _data->zooms().min();
updateTransform(); updateTransform();
_valid = true; _valid = true;
@ -247,17 +252,17 @@ IMGMap::IMGMap(const QString &fileName, QObject *parent)
void IMGMap::load() void IMGMap::load()
{ {
_img.load(); _data->load();
} }
void IMGMap::unload() void IMGMap::unload()
{ {
_img.clear(); _data->clear();
} }
QRectF IMGMap::bounds() QRectF IMGMap::bounds()
{ {
RectD prect(_img.bounds(), _projection); RectD prect(_data->bounds(), _projection);
return QRectF(_transform.proj2img(prect.topLeft()), return QRectF(_transform.proj2img(prect.topLeft()),
_transform.proj2img(prect.bottomRight())); _transform.proj2img(prect.bottomRight()));
} }
@ -267,8 +272,8 @@ int IMGMap::zoomFit(const QSize &size, const RectC &rect)
if (rect.isValid()) { if (rect.isValid()) {
RectD pr(rect, _projection, 10); RectD pr(rect, _projection, 10);
_zoom = zooms.min(); _zoom = _data->zooms().min();
for (int i = zooms.min() + 1; i <= zooms.max(); i++) { for (int i = _data->zooms().min() + 1; i <= _data->zooms().max(); i++) {
Transform t(transform(i)); Transform t(transform(i));
QRectF r(t.proj2img(pr.topLeft()), t.proj2img(pr.bottomRight())); QRectF r(t.proj2img(pr.topLeft()), t.proj2img(pr.bottomRight()));
if (size.width() < r.width() || size.height() < r.height()) if (size.width() < r.width() || size.height() < r.height())
@ -276,7 +281,7 @@ int IMGMap::zoomFit(const QSize &size, const RectC &rect)
_zoom = i; _zoom = i;
} }
} else } else
_zoom = zooms.max(); _zoom = _data->zooms().max();
updateTransform(); updateTransform();
@ -285,14 +290,14 @@ int IMGMap::zoomFit(const QSize &size, const RectC &rect)
int IMGMap::zoomIn() int IMGMap::zoomIn()
{ {
_zoom = qMin(_zoom + 1, zooms.max()); _zoom = qMin(_zoom + 1, _data->zooms().max());
updateTransform(); updateTransform();
return _zoom; return _zoom;
} }
int IMGMap::zoomOut() int IMGMap::zoomOut()
{ {
_zoom = qMax(_zoom - 1, zooms.min()); _zoom = qMax(_zoom - 1, _data->zooms().min());
updateTransform(); updateTransform();
return _zoom; return _zoom;
} }
@ -307,7 +312,7 @@ Transform IMGMap::transform(int zoom) const
{ {
double scale = _projection.isGeographic() double scale = _projection.isGeographic()
? 360.0 / (1<<zoom) : (2.0 * M_PI * WGS84_RADIUS) / (1<<zoom); ? 360.0 / (1<<zoom) : (2.0 * M_PI * WGS84_RADIUS) / (1<<zoom);
PointD topLeft(_projection.ll2xy(_img.bounds().topLeft())); PointD topLeft(_projection.ll2xy(_data->bounds().topLeft()));
return Transform(ReferencePoint(PointD(0, 0), topLeft), return Transform(ReferencePoint(PointD(0, 0), topLeft),
PointD(scale, scale)); PointD(scale, scale));
} }
@ -327,15 +332,14 @@ Coordinates IMGMap::xy2ll(const QPointF &p)
return _projection.xy2ll(_transform.img2proj(p)); return _projection.xy2ll(_transform.img2proj(p));
} }
void IMGMap::drawPolygons(QPainter *painter, const QList<MapData::Poly> &polygons)
void IMGMap::drawPolygons(QPainter *painter, const QList<IMG::Poly> &polygons)
{ {
for (int n = 0; n < _img.style()->drawOrder().size(); n++) { for (int n = 0; n < _data->style()->drawOrder().size(); n++) {
for (int i = 0; i < polygons.size(); i++) { for (int i = 0; i < polygons.size(); i++) {
const IMG::Poly &poly = polygons.at(i); const MapData::Poly &poly = polygons.at(i);
if (poly.type != _img.style()->drawOrder().at(n)) if (poly.type != _data->style()->drawOrder().at(n))
continue; continue;
const Style::Polygon &style = _img.style()->polygon(poly.type); const Style::Polygon &style = _data->style()->polygon(poly.type);
painter->setPen(style.pen()); painter->setPen(style.pen());
painter->setBrush(style.brush()); painter->setBrush(style.brush());
@ -344,13 +348,13 @@ void IMGMap::drawPolygons(QPainter *painter, const QList<IMG::Poly> &polygons)
} }
} }
void IMGMap::drawLines(QPainter *painter, const QList<IMG::Poly> &lines) void IMGMap::drawLines(QPainter *painter, const QList<MapData::Poly> &lines)
{ {
painter->setBrush(Qt::NoBrush); painter->setBrush(Qt::NoBrush);
for (int i = 0; i < lines.size(); i++) { for (int i = 0; i < lines.size(); i++) {
const IMG::Poly &poly = lines.at(i); const MapData::Poly &poly = lines.at(i);
const Style::Line &style = _img.style()->line(poly.type); const Style::Line &style = _data->style()->line(poly.type);
if (style.background() == Qt::NoPen) if (style.background() == Qt::NoPen)
continue; continue;
@ -360,8 +364,8 @@ void IMGMap::drawLines(QPainter *painter, const QList<IMG::Poly> &lines)
} }
for (int i = 0; i < lines.size(); i++) { for (int i = 0; i < lines.size(); i++) {
const IMG::Poly &poly = lines.at(i); const MapData::Poly &poly = lines.at(i);
const Style::Line &style = _img.style()->line(poly.type); const Style::Line &style = _data->style()->line(poly.type);
if (!style.img().isNull()) if (!style.img().isNull())
BitmapLine::draw(painter, poly.points, style.img()); BitmapLine::draw(painter, poly.points, style.img());
@ -378,12 +382,11 @@ void IMGMap::drawTextItems(QPainter *painter, const QList<TextItem*> &textItems)
textItems.at(i)->paint(painter); textItems.at(i)->paint(painter);
} }
void IMGMap::processPolygons(QList<MapData::Poly> &polygons,
void IMGMap::processPolygons(QList<IMG::Poly> &polygons,
QList<TextItem*> &textItems) QList<TextItem*> &textItems)
{ {
for (int i = 0; i < polygons.size(); i++) { for (int i = 0; i < polygons.size(); i++) {
IMG::Poly &poly = polygons[i]; MapData::Poly &poly = polygons[i];
for (int j = 0; j < poly.points.size(); j++) { for (int j = 0; j < poly.points.size(); j++) {
QPointF &p = poly.points[j]; QPointF &p = poly.points[j];
p = ll2xy(Coordinates(p.x(), p.y())); p = ll2xy(Coordinates(p.x(), p.y()));
@ -395,7 +398,7 @@ void IMGMap::processPolygons(QList<IMG::Poly> &polygons,
if (_zoom <= 23 && (Style::isWaterArea(poly.type) if (_zoom <= 23 && (Style::isWaterArea(poly.type)
|| Style::isMilitaryArea(poly.type) || Style::isMilitaryArea(poly.type)
|| Style::isNatureReserve(poly.type))) { || Style::isNatureReserve(poly.type))) {
const Style::Polygon &style = _img.style()->polygon(poly.type); const Style::Polygon &style = _data->style()->polygon(poly.type);
TextPointItem *item = new TextPointItem( TextPointItem *item = new TextPointItem(
centroid(poly.points).toPoint(), &poly.label.text(), centroid(poly.points).toPoint(), &poly.label.text(),
poiFont(), 0, &style.brush().color()); poiFont(), 0, &style.brush().color());
@ -408,13 +411,13 @@ void IMGMap::processPolygons(QList<IMG::Poly> &polygons,
} }
} }
void IMGMap::processLines(QList<IMG::Poly> &lines, const QRect &tileRect, void IMGMap::processLines(QList<MapData::Poly> &lines, const QRect &tileRect,
QList<TextItem*> &textItems) QList<TextItem*> &textItems)
{ {
qStableSort(lines); qStableSort(lines);
for (int i = 0; i < lines.size(); i++) { for (int i = 0; i < lines.size(); i++) {
IMG::Poly &poly = lines[i]; MapData::Poly &poly = lines[i];
for (int j = 0; j < poly.points.size(); j++) { for (int j = 0; j < poly.points.size(); j++) {
QPointF &p = poly.points[j]; QPointF &p = poly.points[j];
p = ll2xy(Coordinates(p.x(), p.y())); p = ll2xy(Coordinates(p.x(), p.y()));
@ -426,12 +429,12 @@ void IMGMap::processLines(QList<IMG::Poly> &lines, const QRect &tileRect,
processShields(lines, tileRect, textItems); processShields(lines, tileRect, textItems);
} }
void IMGMap::processStreetNames(QList<IMG::Poly> &lines, const QRect &tileRect, void IMGMap::processStreetNames(QList<MapData::Poly> &lines,
QList<TextItem*> &textItems) const QRect &tileRect, QList<TextItem*> &textItems)
{ {
for (int i = 0; i < lines.size(); i++) { for (int i = 0; i < lines.size(); i++) {
IMG::Poly &poly = lines[i]; MapData::Poly &poly = lines[i];
const Style::Line &style = _img.style()->line(poly.type); const Style::Line &style = _data->style()->line(poly.type);
if (style.img().isNull() && style.foreground() == Qt::NoPen) if (style.img().isNull() && style.foreground() == Qt::NoPen)
continue; continue;
@ -455,7 +458,7 @@ void IMGMap::processStreetNames(QList<IMG::Poly> &lines, const QRect &tileRect,
} }
} }
void IMGMap::processShields(QList<IMG::Poly> &lines, const QRect &tileRect, void IMGMap::processShields(QList<MapData::Poly> &lines, const QRect &tileRect,
QList<TextItem*> &textItems) QList<TextItem*> &textItems)
{ {
for (int type = FIRST_SHIELD; type <= LAST_SHIELD; type++) { for (int type = FIRST_SHIELD; type <= LAST_SHIELD; type++) {
@ -466,7 +469,7 @@ void IMGMap::processShields(QList<IMG::Poly> &lines, const QRect &tileRect,
QHash<Label::Shield, const Label::Shield*> sp; QHash<Label::Shield, const Label::Shield*> sp;
for (int i = 0; i < lines.size(); i++) { for (int i = 0; i < lines.size(); i++) {
const IMG::Poly &poly = lines.at(i); const MapData::Poly &poly = lines.at(i);
const Label::Shield &shield = poly.label.shield(); const Label::Shield &shield = poly.label.shield();
if (!shield.isValid() || shield.type() != type if (!shield.isValid() || shield.type() != type
|| !Style::isMajorRoad(poly.type)) || !Style::isMajorRoad(poly.type))
@ -519,14 +522,14 @@ void IMGMap::processShields(QList<IMG::Poly> &lines, const QRect &tileRect,
} }
} }
void IMGMap::processPoints(QList<IMG::Point> &points, void IMGMap::processPoints(QList<MapData::Point> &points,
QList<TextItem*> &textItems) QList<TextItem*> &textItems)
{ {
qSort(points); qSort(points);
for (int i = 0; i < points.size(); i++) { for (int i = 0; i < points.size(); i++) {
IMG::Point &point = points[i]; MapData::Point &point = points[i];
const Style::Point &style = _img.style()->point(point.type); const Style::Point &style = _data->style()->point(point.type);
if (point.poi && _zoom < minPOIZoom(Style::poiClass(point.type))) if (point.poi && _zoom < minPOIZoom(Style::poiClass(point.type)))
continue; continue;
@ -580,7 +583,7 @@ void IMGMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
for (int j = 0; j < height; j++) { for (int j = 0; j < height; j++) {
QPixmap pm; QPixmap pm;
QPoint ttl(tl.x() + i * TILE_SIZE, tl.y() + j * TILE_SIZE); QPoint ttl(tl.x() + i * TILE_SIZE, tl.y() + j * TILE_SIZE);
QString key = _img.fileName() + "-" + QString::number(_zoom) + "_" QString key = _data->fileName() + "-" + QString::number(_zoom) + "_"
+ QString::number(ttl.x()) + "_" + QString::number(ttl.y()); + QString::number(ttl.x()) + "_" + QString::number(ttl.y());
if (QPixmapCache::find(key, pm)) if (QPixmapCache::find(key, pm))
painter->drawPixmap(ttl, pm); painter->drawPixmap(ttl, pm);
@ -588,15 +591,22 @@ void IMGMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
tiles.append(RasterTile(this, ttl, key)); tiles.append(RasterTile(this, ttl, key));
RasterTile &tile = tiles.last(); RasterTile &tile = tiles.last();
RectD polyRect(_transform.img2proj(ttl), _transform.img2proj( QRectF polyRect(ttl, QPointF(ttl.x() + TILE_SIZE,
QPointF(ttl.x() + TILE_SIZE, ttl.y() + TILE_SIZE))); ttl.y() + TILE_SIZE));
_img.objects(polyRect.toRectC(_projection, 4), _zoom, polyRect &= bounds().adjusted(0.5, 0.5, -0.5, -0.5);
&(tile.polygons()), &(tile.lines()), 0); RectD polyRectD(_transform.img2proj(polyRect.topLeft()),
RectD pointRect(_transform.img2proj(QPointF(ttl.x() - TEXT_EXTENT, _transform.img2proj(polyRect.bottomRight()));
ttl.y() - TEXT_EXTENT)), _transform.img2proj(QPointF(ttl.x() _data->polys(polyRectD.toRectC(_projection, 4), _zoom,
+ TILE_SIZE + TEXT_EXTENT, ttl.y() + TILE_SIZE + TEXT_EXTENT))); &(tile.polygons()), &(tile.lines()));
_img.objects(pointRect.toRectC(_projection, 4), _zoom,
0, 0, &(tile.points())); QRectF pointRect(QPointF(ttl.x() - TEXT_EXTENT,
ttl.y() - TEXT_EXTENT), QPointF(ttl.x() + TILE_SIZE
+ TEXT_EXTENT, ttl.y() + TILE_SIZE + TEXT_EXTENT));
pointRect &= bounds().adjusted(0.5, 0.5, -0.5, -0.5);
RectD pointRectD(_transform.img2proj(pointRect.topLeft()),
_transform.img2proj(pointRect.bottomRight()));
_data->points(pointRectD.toRectC(_projection, 4), _zoom,
&(tile.points()));
} }
} }
} }

View File

@ -4,7 +4,7 @@
#include "map.h" #include "map.h"
#include "projection.h" #include "projection.h"
#include "transform.h" #include "transform.h"
#include "IMG/img.h" #include "IMG/mapdata.h"
class TextItem; class TextItem;
@ -14,8 +14,9 @@ class IMGMap : public Map
public: public:
IMGMap(const QString &fileName, QObject *parent = 0); IMGMap(const QString &fileName, QObject *parent = 0);
~IMGMap() {delete _data;}
QString name() const {return _img.name();} QString name() const {return _data->name();}
QRectF bounds(); QRectF bounds();
@ -43,21 +44,21 @@ private:
Transform transform(int zoom) const; Transform transform(int zoom) const;
void updateTransform(); void updateTransform();
void drawPolygons(QPainter *painter, const QList<IMG::Poly> &polygons); void drawPolygons(QPainter *painter, const QList<MapData::Poly> &polygons);
void drawLines(QPainter *painter, const QList<IMG::Poly> &lines); void drawLines(QPainter *painter, const QList<MapData::Poly> &lines);
void drawTextItems(QPainter *painter, const QList<TextItem*> &textItems); void drawTextItems(QPainter *painter, const QList<TextItem*> &textItems);
void processPolygons(QList<IMG::Poly> &polygons, void processPolygons(QList<MapData::Poly> &polygons,
QList<TextItem *> &textItems); QList<TextItem *> &textItems);
void processLines(QList<IMG::Poly> &lines, const QRect &tileRect, void processLines(QList<MapData::Poly> &lines, const QRect &tileRect,
QList<TextItem*> &textItems); QList<TextItem*> &textItems);
void processPoints(QList<IMG::Point> &points, QList<TextItem*> &textItems); void processPoints(QList<MapData::Point> &points, QList<TextItem*> &textItems);
void processShields(QList<IMG::Poly> &lines, const QRect &tileRect, void processShields(QList<MapData::Poly> &lines, const QRect &tileRect,
QList<TextItem*> &textItems); QList<TextItem*> &textItems);
void processStreetNames(QList<IMG::Poly> &lines, const QRect &tileRect, void processStreetNames(QList<MapData::Poly> &lines, const QRect &tileRect,
QList<TextItem*> &textItems); QList<TextItem*> &textItems);
IMG _img; MapData *_data;
int _zoom; int _zoom;
Projection _projection; Projection _projection;
Transform _transform; Transform _transform;

View File

@ -8,51 +8,52 @@
#include "mbtilesmap.h" #include "mbtilesmap.h"
#include "rmap.h" #include "rmap.h"
#include "imgmap.h" #include "imgmap.h"
#include "IMG/gmap.h"
#include "maplist.h" #include "maplist.h"
bool MapList::loadMap(Map* map, const QString &path, bool dir) bool MapList::loadMap(Map *map, const QString &path)
{ {
if (map->isValid()) { if (map && map->isValid()) {
_maps.append(map); _maps.append(map);
return true; return true;
} else { } else {
if (dir) _errorPath = path;
_errorString += path + ": " + map->errorString() + "\n"; _errorString = (map) ? map->errorString() : "Unknown file format";
else
_errorString = map->errorString();
return false; return false;
} }
} }
Map *MapList::loadSource(const QString &path, bool dir) Map *MapList::loadSource(const QString &path)
{ {
QString err; Map *map = MapSource::loadMap(path, _errorString);
Map *map = MapSource::loadMap(path, err);
if (!map) { if (!map)
if (dir) _errorPath = path;
_errorString += path + ": " + err + "\n";
else else
_errorString = err;
} else
map->setParent(this); map->setParent(this);
return map; return map;
} }
bool MapList::loadFile(const QString &path, bool *atlas, bool dir) bool MapList::loadFile(const QString &path, bool *terminate)
{ {
QFileInfo fi(path); QFileInfo fi(path);
QString suffix = fi.suffix().toLower(); QString suffix = fi.suffix().toLower();
Map *map; Map *map = 0;
if (Atlas::isAtlas(path)) { if (Atlas::isAtlas(path)) {
*atlas = true; if (terminate)
*terminate = true;
map = new Atlas(path, this); map = new Atlas(path, this);
} else if (suffix == "xml") { } else if (suffix == "xml") {
if (!(map = loadSource(path, dir))) if (MapSource::isMap(path) && !(map = loadSource(path)))
return false; return false;
else if (GMAP::isGMAP(path)) {
if (terminate)
*terminate = true;
map = new IMGMap(path, this);
}
} else if (suffix == "jnx") } else if (suffix == "jnx")
map = new JNXMap(path, this); map = new JNXMap(path, this);
else if (suffix == "tif" || suffix == "tiff") else if (suffix == "tif" || suffix == "tiff")
@ -63,10 +64,10 @@ bool MapList::loadFile(const QString &path, bool *atlas, bool dir)
map = new RMap(path, this); map = new RMap(path, this);
else if (suffix == "img") else if (suffix == "img")
map = new IMGMap(path, this); map = new IMGMap(path, this);
else else if (suffix == "map" || suffix == "tar")
map = new OziMap(path, this); map = new OziMap(path, this);
if (!loadMap(map, path, dir)) { if (!loadMap(map, path)) {
delete map; delete map;
return false; return false;
} }
@ -74,7 +75,7 @@ bool MapList::loadFile(const QString &path, bool *atlas, bool dir)
return true; return true;
} }
bool MapList::loadDirR(const QString &path) bool MapList::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);
@ -85,15 +86,15 @@ bool MapList::loadDirR(const QString &path)
for (int i = 0; i < ml.size(); i++) { for (int i = 0; i < ml.size(); i++) {
const QFileInfo &fi = ml.at(i); const QFileInfo &fi = ml.at(i);
QString suffix = fi.suffix().toLower(); QString suffix = fi.suffix().toLower();
bool atlas = false; bool terminate = false;
if (fi.isDir() && fi.fileName() != "set") { if (fi.isDir() && fi.fileName() != "set") {
if (!loadDirR(fi.absoluteFilePath())) if (!loadDir(fi.absoluteFilePath()))
ret = false; ret = false;
} else if (filter().contains("*." + suffix)) { } else if (filter().contains("*." + suffix)) {
if (!loadFile(fi.absoluteFilePath(), &atlas, true)) if (!loadFile(fi.absoluteFilePath(), &terminate))
ret = false; ret = false;
if (atlas) if (terminate)
break; break;
} }
} }
@ -101,26 +102,11 @@ bool MapList::loadDirR(const QString &path)
return ret; return ret;
} }
bool MapList::loadFile(const QString &path)
{
bool atlas;
_errorString.clear();
return loadFile(path, &atlas, false);
}
bool MapList::loadDir(const QString &path)
{
_errorString.clear();
return loadDirR(path);
}
QString MapList::formats() QString MapList::formats()
{ {
return return
tr("Supported files") tr("Supported files") + " (" + filter().join(" ") + ");;"
+ " (*.img *.jnx *.map *.mbtiles *.rmap *.rtmap *.tar *.tba *.tif *.tiff *.xml);;" + tr("Garmin IMG maps") + " (*.gmap *.gmapi *.img *.xml);;"
+ tr("Garmin IMG maps") + " (*.img);;"
+ tr("Garmin JNX maps") + " (*.jnx);;" + tr("Garmin JNX maps") + " (*.jnx);;"
+ tr("OziExplorer maps") + " (*.map);;" + tr("OziExplorer maps") + " (*.map);;"
+ tr("MBTiles maps") + " (*.mbtiles);;" + tr("MBTiles maps") + " (*.mbtiles);;"
@ -133,7 +119,8 @@ QString MapList::formats()
QStringList MapList::filter() QStringList MapList::filter()
{ {
QStringList filter; QStringList filter;
filter << "*.img" << "*.jnx" << "*.map" << "*.tba" << "*.tar" << "*.xml" filter << "*.gmap" << "*.gmapi" << "*.img" << "*.jnx" << "*.map"
<< "*.tif" << "*.tiff" << "*.mbtiles" << "*.rmap" << "*.rtmap" << "*.img"; << "*.mbtiles" << "*.rmap" << "*.rtmap" << "*.tar" << "*.tba" << "*.tif"
<< "*.tiff" << "*.xml";
return filter; return filter;
} }

View File

@ -13,23 +13,24 @@ class MapList : public QObject
public: public:
MapList(QObject *parent = 0) : QObject(parent) {} MapList(QObject *parent = 0) : QObject(parent) {}
bool loadFile(const QString &path); bool loadFile(const QString &path, bool *terminate = 0);
bool loadDir(const QString &path); bool loadDir(const QString &path);
const QList<Map*> &maps() const {return _maps;} const QList<Map*> &maps() const {return _maps;}
const QString &errorString() const {return _errorString;} const QString &errorString() const {return _errorString;}
const QString &errorPath() const {return _errorPath;}
static QString formats(); static QString formats();
static QStringList filter(); static QStringList filter();
private: private:
bool loadFile(const QString &path, bool *atlas, bool dir); Map *loadSource(const QString &path);
bool loadDirR(const QString &path); bool loadMap(Map *map, const QString &path);
Map *loadSource(const QString &path, bool dir);
bool loadMap(Map *map, const QString &path, bool dir);
QList<Map*> _maps; QList<Map*> _maps;
QString _errorString; QString _errorString;
QString _errorPath;
}; };
#endif // MAPLIST_H #endif // MAPLIST_H

View File

@ -222,6 +222,20 @@ void MapSource::map(QXmlStreamReader &reader, Config &config)
} }
} }
bool MapSource::isMap(const QString &path)
{
QFile file(path);
if (!file.open(QFile::ReadOnly | QFile::Text))
return false;
QXmlStreamReader reader(&file);
if (reader.readNextStartElement() && reader.name() == "map")
return true;
return false;
}
Map *MapSource::loadMap(const QString &path, QString &errorString) Map *MapSource::loadMap(const QString &path, QString &errorString)
{ {
Config config; Config config;
@ -286,7 +300,7 @@ Map *MapSource::loadMap(const QString &path, QString &errorString)
case WMS: case WMS:
return new WMSMap(config.name, WMS::Setup(config.url, config.layer, return new WMSMap(config.name, WMS::Setup(config.url, config.layer,
config.style, config.format, config.crs, config.coordinateSystem, config.style, config.format, config.crs, config.coordinateSystem,
config.dimensions, config.authorization)); config.dimensions, config.authorization), config.tileSize);
case TMS: case TMS:
return new OnlineMap(config.name, config.url, config.zooms, return new OnlineMap(config.name, config.url, config.zooms,
config.bounds, config.tileRatio, config.authorization, config.bounds, config.tileRatio, config.authorization,

View File

@ -15,6 +15,7 @@ class MapSource
{ {
public: public:
static Map *loadMap(const QString &path, QString &errorString); static Map *loadMap(const QString &path, QString &errorString);
static bool isMap(const QString &path);
private: private:
enum Type { enum Type {

View File

@ -169,6 +169,17 @@ void TileLoader::clearCache()
dir.remove(list.at(i)); dir.remove(list.at(i));
_downloader->clearErrors(); _downloader->clearErrors();
QPixmapCache::clear();
}
void TileLoader::setScaledSize(int size)
{
if (_scaledSize == size)
return;
_scaledSize = size;
QPixmapCache::clear();
} }
QUrl TileLoader::tileUrl(const Tile &tile) const QUrl TileLoader::tileUrl(const Tile &tile) const

View File

@ -16,7 +16,7 @@ public:
void setUrl(const QString &url) {_url = url;} void setUrl(const QString &url) {_url = url;}
void setAuthorization(const Authorization &authorization) void setAuthorization(const Authorization &authorization)
{_authorization = authorization;} {_authorization = authorization;}
void setScaledSize(int size) {_scaledSize = size;} void setScaledSize(int size);
void setQuadTiles(bool quadTiles) {_quadTiles = quadTiles;} void setQuadTiles(bool quadTiles) {_quadTiles = quadTiles;}
void loadTilesAsync(QVector<Tile> &list); void loadTilesAsync(QVector<Tile> &list);

View File

@ -1,3 +1,4 @@
#include <cmath>
#include <QFileInfo> #include <QFileInfo>
#include <QEventLoop> #include <QEventLoop>
#include <QXmlStreamReader> #include <QXmlStreamReader>
@ -7,6 +8,19 @@
#include "wms.h" #include "wms.h"
static QString bareFormat(const QString &format)
{
return format.left(format.indexOf(';')).trimmed();
}
static inline double hint2denominator(double h)
{
/* Some WMS 1.1.1 servers use a 72dpi resolution by default. Using the usual
90dpi (0.28mm) resolution known from later standards (WMS 1.3, WMTS) does
make them return emty images in the "max" scale level. */
return h / (M_SQRT2 * 0.36e-3);
}
WMS::CTX::CTX(const Setup &setup) : setup(setup), formatSupported(false) WMS::CTX::CTX(const Setup &setup) : setup(setup), formatSupported(false)
{ {
QStringList ll = setup.layer().split(','); QStringList ll = setup.layer().split(',');
@ -24,13 +38,48 @@ WMS::CTX::CTX(const Setup &setup) : setup(setup), formatSupported(false)
} }
} }
void WMS::get(QXmlStreamReader &reader, CTX &ctx)
{
while (reader.readNextStartElement()) {
if (reader.name() == "OnlineResource") {
QXmlStreamAttributes attr = reader.attributes();
ctx.url = attr.value("xlink:href").toString();
reader.skipCurrentElement();
} else
reader.skipCurrentElement();
}
}
void WMS::http(QXmlStreamReader &reader, CTX &ctx)
{
while (reader.readNextStartElement()) {
if (reader.name() == "Get")
get(reader, ctx);
else
reader.skipCurrentElement();
}
}
void WMS::dcpType(QXmlStreamReader &reader, CTX &ctx)
{
while (reader.readNextStartElement()) {
if (reader.name() == "HTTP")
http(reader, ctx);
else
reader.skipCurrentElement();
}
}
void WMS::getMap(QXmlStreamReader &reader, CTX &ctx) void WMS::getMap(QXmlStreamReader &reader, CTX &ctx)
{ {
while (reader.readNextStartElement()) { while (reader.readNextStartElement()) {
if (reader.name() == "Format") { if (reader.name() == "Format") {
if (reader.readElementText() == ctx.setup.format()) QString format(reader.readElementText());
if (bareFormat(format) == bareFormat(ctx.setup.format()))
ctx.formatSupported = true; ctx.formatSupported = true;
} else } else if (reader.name() == "DCPType")
dcpType(reader, ctx);
else
reader.skipCurrentElement(); reader.skipCurrentElement();
} }
} }
@ -97,7 +146,16 @@ void WMS::layer(QXmlStreamReader &reader, CTX &ctx,
CRSs.append(reader.readElementText()); CRSs.append(reader.readElementText());
else if (reader.name() == "Style") else if (reader.name() == "Style")
styles.append(style(reader)); styles.append(style(reader));
else if (reader.name() == "MinScaleDenominator") { else if (reader.name() == "ScaleHint") {
QXmlStreamAttributes attr = reader.attributes();
double minHint = attr.value("min").toString().toDouble();
double maxHint = attr.value("max").toString().toDouble();
if (minHint > 0)
scaleDenominator.setMin(hint2denominator(minHint));
if (maxHint > 0)
scaleDenominator.setMax(hint2denominator(maxHint));
reader.skipCurrentElement();
} else if (reader.name() == "MinScaleDenominator") {
double sd = reader.readElementText().toDouble(); double sd = reader.readElementText().toDouble();
if (sd > 0) if (sd > 0)
scaleDenominator.setMin(sd); scaleDenominator.setMin(sd);
@ -248,6 +306,8 @@ bool WMS::parseCapabilities(const QString &path, const Setup &setup)
return false; return false;
} }
_tileUrl = ctx.url.isEmpty() ? setup.url() : ctx.url;
return true; return true;
} }

View File

@ -54,6 +54,7 @@ public:
const RangeF &scaleDenominator() const {return _scaleDenominator;} const RangeF &scaleDenominator() const {return _scaleDenominator;}
const RectC &boundingBox() const {return _boundingBox;} const RectC &boundingBox() const {return _boundingBox;}
const QString &version() const {return _version;} const QString &version() const {return _version;}
const QString &tileUrl() const {return _tileUrl;}
bool isValid() const {return _valid;} bool isValid() const {return _valid;}
const QString &errorString() const {return _errorString;} const QString &errorString() const {return _errorString;}
@ -79,12 +80,16 @@ private:
const Setup &setup; const Setup &setup;
QList<Layer> layers; QList<Layer> layers;
bool formatSupported; bool formatSupported;
QString url;
CTX(const Setup &setup); CTX(const Setup &setup);
}; };
RectC geographicBoundingBox(QXmlStreamReader &reader); RectC geographicBoundingBox(QXmlStreamReader &reader);
QString style(QXmlStreamReader &reader); QString style(QXmlStreamReader &reader);
void get(QXmlStreamReader &reader, CTX &ctx);
void http(QXmlStreamReader &reader, CTX &ctx);
void dcpType(QXmlStreamReader &reader, CTX &ctx);
void getMap(QXmlStreamReader &reader, CTX &ctx); void getMap(QXmlStreamReader &reader, CTX &ctx);
void request(QXmlStreamReader &reader, CTX &ctx); void request(QXmlStreamReader &reader, CTX &ctx);
void layer(QXmlStreamReader &reader, CTX &ctx, const QList<QString> &pCRSs, void layer(QXmlStreamReader &reader, CTX &ctx, const QList<QString> &pCRSs,
@ -100,6 +105,7 @@ private:
RangeF _scaleDenominator; RangeF _scaleDenominator;
RectC _boundingBox; RectC _boundingBox;
QString _version; QString _version;
QString _tileUrl;
bool _valid; bool _valid;
QString _errorString; QString _errorString;

View File

@ -10,7 +10,6 @@
#define CAPABILITIES_FILE "capabilities.xml" #define CAPABILITIES_FILE "capabilities.xml"
#define TILE_SIZE 256
#define EPSILON 1e-6 #define EPSILON 1e-6
double WMSMap::sd2res(double scaleDenominator) const double WMSMap::sd2res(double scaleDenominator) const
@ -18,14 +17,14 @@ double WMSMap::sd2res(double scaleDenominator) const
return scaleDenominator * 0.28e-3 * _projection.units().fromMeters(1.0); return scaleDenominator * 0.28e-3 * _projection.units().fromMeters(1.0);
} }
QString WMSMap::tileUrl(const QString &version) const QString WMSMap::tileUrl(const QString &baseUrl, const QString &version) const
{ {
QString url; QString url;
url = QString("%1%2version=%3&request=GetMap&bbox=$bbox" url = QString("%1%2service=WMS&version=%3&request=GetMap&bbox=$bbox"
"&width=%4&height=%5&layers=%6&styles=%7&format=%8&transparent=true") "&width=%4&height=%5&layers=%6&styles=%7&format=%8&transparent=true")
.arg(_setup.url(), _setup.url().contains('?') ? "&" : "?", version, .arg(baseUrl, baseUrl.contains('?') ? "&" : "?", version,
QString::number(TILE_SIZE), QString::number(TILE_SIZE), _setup.layer(), QString::number(_tileSize), QString::number(_tileSize), _setup.layer(),
_setup.style(), _setup.format()); _setup.style(), _setup.format());
if (version >= "1.3.0") if (version >= "1.3.0")
@ -84,7 +83,7 @@ bool WMSMap::loadWMS()
_projection = wms.projection(); _projection = wms.projection();
_bbox = wms.boundingBox(); _bbox = wms.boundingBox();
_bounds = RectD(_bbox, _projection); _bounds = RectD(_bbox, _projection);
_tileLoader->setUrl(tileUrl(wms.version())); _tileLoader->setUrl(tileUrl(wms.tileUrl(), wms.version()));
if (wms.version() >= "1.3.0") { if (wms.version() >= "1.3.0") {
if (_setup.coordinateSystem().axisOrder() == CoordinateSystem::Unknown) if (_setup.coordinateSystem().axisOrder() == CoordinateSystem::Unknown)
@ -100,9 +99,9 @@ bool WMSMap::loadWMS()
return true; return true;
} }
WMSMap::WMSMap(const QString &name, const WMS::Setup &setup, QObject *parent) WMSMap::WMSMap(const QString &name, const WMS::Setup &setup, int tileSize,
: Map(parent), _name(name), _setup(setup), _tileLoader(0), _zoom(0), QObject *parent) : Map(parent), _name(name), _setup(setup), _tileLoader(0),
_mapRatio(1.0), _valid(false) _zoom(0), _tileSize(tileSize), _mapRatio(1.0), _valid(false)
{ {
_tileLoader = new TileLoader(tilesDir(), this); _tileLoader = new TileLoader(tilesDir(), this);
_tileLoader->setAuthorization(_setup.authorization()); _tileLoader->setAuthorization(_setup.authorization());
@ -180,7 +179,7 @@ Coordinates WMSMap::xy2ll(const QPointF &p)
qreal WMSMap::tileSize() const qreal WMSMap::tileSize() const
{ {
return (TILE_SIZE / _mapRatio); return (_tileSize / _mapRatio);
} }
void WMSMap::draw(QPainter *painter, const QRectF &rect, Flags flags) void WMSMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
@ -194,10 +193,10 @@ void WMSMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
tiles.reserve((br.x() - tl.x()) * (br.y() - tl.y())); tiles.reserve((br.x() - tl.x()) * (br.y() - tl.y()));
for (int i = tl.x(); i < br.x(); i++) { for (int i = tl.x(); i < br.x(); i++) {
for (int j = tl.y(); j < br.y(); j++) { for (int j = tl.y(); j < br.y(); j++) {
PointD ttl(_transform.img2proj(QPointF(i * TILE_SIZE, PointD ttl(_transform.img2proj(QPointF(i * _tileSize,
j * TILE_SIZE))); j * _tileSize)));
PointD tbr(_transform.img2proj(QPointF(i * TILE_SIZE + TILE_SIZE, PointD tbr(_transform.img2proj(QPointF(i * _tileSize + _tileSize,
j * TILE_SIZE + TILE_SIZE))); j * _tileSize + _tileSize)));
RectD bbox = (_cs.axisOrder() == CoordinateSystem::YX) RectD bbox = (_cs.axisOrder() == CoordinateSystem::YX)
? RectD(PointD(tbr.y(), tbr.x()), PointD(ttl.y(), ttl.x())) ? RectD(PointD(tbr.y(), tbr.x()), PointD(ttl.y(), ttl.x()))
: RectD(ttl, tbr); : RectD(ttl, tbr);

View File

@ -14,7 +14,8 @@ class WMSMap : public Map
Q_OBJECT Q_OBJECT
public: public:
WMSMap(const QString &name, const WMS::Setup &setup, QObject *parent = 0); WMSMap(const QString &name, const WMS::Setup &setup, int tileSize,
QObject *parent = 0);
QString name() const {return _name;} QString name() const {return _name;}
@ -39,7 +40,7 @@ public:
QString errorString() const {return _errorString;} QString errorString() const {return _errorString;}
private: private:
QString tileUrl(const QString &version) const; QString tileUrl(const QString &baseUrl, const QString &version) const;
double sd2res(double scaleDenominator) const; double sd2res(double scaleDenominator) const;
QString tilesDir() const; QString tilesDir() const;
void computeZooms(const RangeF &scaleDenominator); void computeZooms(const RangeF &scaleDenominator);
@ -58,6 +59,7 @@ private:
RectC _bbox; RectC _bbox;
RectD _bounds; RectD _bounds;
int _zoom; int _zoom;
int _tileSize;
qreal _mapRatio; qreal _mapRatio;
bool _valid; bool _valid;

View File

@ -12,6 +12,11 @@
#include "wmts.h" #include "wmts.h"
static QString bareFormat(const QString &format)
{
return format.left(format.indexOf(';')).trimmed();
}
static void skipParentElement(QXmlStreamReader &reader) static void skipParentElement(QXmlStreamReader &reader)
{ {
while (reader.readNextStartElement()) while (reader.readNextStartElement())
@ -182,7 +187,8 @@ void WMTS::layer(QXmlStreamReader &reader, CTX &ctx)
if (s == ctx.setup.style()) if (s == ctx.setup.style())
ctx.hasStyle = true; ctx.hasStyle = true;
} else if (reader.name() == "Format") { } else if (reader.name() == "Format") {
if (reader.readElementText() == ctx.setup.format()) QString format(reader.readElementText());
if (bareFormat(format) == bareFormat(ctx.setup.format()))
ctx.hasFormat = true; ctx.hasFormat = true;
} else } else
reader.skipCurrentElement(); reader.skipCurrentElement();