1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2025-07-03 06:19:15 +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:
- Release
@ -17,7 +17,7 @@ environment:
LIBSSL: libcrypto-1_1.dll
- QTDIR: C:\Qt\5.13\msvc2017_64
NSI: gpxsee64.nsi
VCVARS: vcvars64.bat"
VCVARS: vcvars64.bat
OPENSSLDIR: C:\OpenSSL-v111-Win64\bin
LIBCRYPTO: libssl-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.
## 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).
* 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.
* Support for DEM files (SRTM HGT).
* Support for multiple tracks in one view.

View File

@ -3,7 +3,7 @@ unix:!macx {
} else {
TARGET = GPXSee
}
VERSION = 7.20
VERSION = 7.25
QT += core \
gui \
@ -91,8 +91,10 @@ HEADERS += src/common/config.h \
src/map/IMG/bitmapline.h \
src/map/IMG/bitstream.h \
src/map/IMG/deltastream.h \
src/map/IMG/gmap.h \
src/map/IMG/huffmanstream.h \
src/map/IMG/huffmantable.h \
src/map/IMG/mapdata.h \
src/map/IMG/textpathitem.h \
src/map/IMG/textpointitem.h \
src/map/projection.h \
@ -249,8 +251,10 @@ SOURCES += src/main.cpp \
src/map/IMG/bitmapline.cpp \
src/map/IMG/bitstream.cpp \
src/map/IMG/deltastream.cpp \
src/map/IMG/gmap.cpp \
src/map/IMG/huffmanstream.cpp \
src/map/IMG/huffmantable.cpp \
src/map/IMG/mapdata.cpp \
src/map/IMG/textpathitem.cpp \
src/map/IMG/textpointitem.cpp \
src/map/maplist.cpp \
@ -359,7 +363,8 @@ TRANSLATIONS = lang/gpxsee_en.ts \
lang/gpxsee_tr.ts \
lang/gpxsee_es.ts \
lang/gpxsee_pt_BR.ts \
lang/gpxsee_uk.ts
lang/gpxsee_uk.ts \
lang/gpxsee_hu.ts
macx {
ICON = icons/gpxsee.icns
@ -378,7 +383,8 @@ macx {
lang/gpxsee_tr.qm \
lang/gpxsee_es.qm \
lang/gpxsee_pt_BR.qm \
lang/gpxsee_uk.qm
lang/gpxsee_uk.qm \
lang/gpxsee_hu.qm
csv.path = Contents/Resources
csv.files = pkg/csv
maps.path = Contents/Resources

View File

@ -49,7 +49,7 @@
<message>
<location filename="../src/data/data.cpp" line="179"/>
<source>Supported files</source>
<translation>Formatos soportados</translation>
<translation>Formatos admitidos</translation>
</message>
<message>
<location filename="../src/data/data.cpp" line="180"/>
@ -89,7 +89,7 @@
<message>
<location filename="../src/data/data.cpp" line="189"/>
<source>JPEG images</source>
<translation>Imagen JPEG</translation>
<translation>Imágenes JPEG</translation>
</message>
<message>
<location filename="../src/data/data.cpp" line="190"/>
@ -168,7 +168,7 @@
<message>
<location filename="../src/GUI/elevationgraph.cpp" line="144"/>
<source>ft</source>
<translation>pies</translation>
<translation>ft</translation>
</message>
</context>
<context>
@ -181,7 +181,7 @@
<message>
<location filename="../src/GUI/elevationgraphitem.cpp" line="33"/>
<source>ft</source>
<translation></translation>
<translation>ft</translation>
</message>
<message>
<location filename="../src/GUI/elevationgraphitem.cpp" line="36"/>
@ -234,7 +234,7 @@
<message>
<location filename="../src/GUI/exportdialog.cpp" line="66"/>
<source>in</source>
<translation></translation>
<translation>in</translation>
</message>
<message>
<location filename="../src/GUI/exportdialog.cpp" line="94"/>
@ -301,7 +301,7 @@
<message>
<location filename="../src/GUI/exportdialog.cpp" line="157"/>
<source>%1 is not writable.</source>
<translation>%1 es de sólo lectura.</translation>
<translation>%1 es de solo lectura.</translation>
</message>
</context>
<context>
@ -319,7 +319,7 @@
<location filename="../src/GUI/format.cpp" line="61"/>
<location filename="../src/GUI/format.cpp" line="84"/>
<source>ft</source>
<translation></translation>
<translation>ft</translation>
</message>
<message>
<location filename="../src/GUI/format.cpp" line="57"/>
@ -403,17 +403,17 @@
<message>
<location filename="../src/GUI/gui.cpp" line="256"/>
<source>Load POI file...</source>
<translation>Cargar archivo de POI&apos;s...</translation>
<translation>Cargar archivo de POI...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="260"/>
<source>Close POI files</source>
<translation>Cerrar archivo de POI&apos;s</translation>
<translation>Cerrar archivos de POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="264"/>
<source>Overlap POIs</source>
<translation>Sobrescribir POI&apos;s</translation>
<translation>Sobreponer POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="269"/>
@ -423,7 +423,7 @@
<message>
<location filename="../src/GUI/gui.cpp" line="274"/>
<source>Show POIs</source>
<translation>Ver POI&apos;s</translation>
<translation>Ver POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="284"/>
@ -438,7 +438,7 @@
<message>
<location filename="../src/GUI/gui.cpp" line="296"/>
<source>Clear tile cache</source>
<translation>Limpiar cache de teselas</translation>
<translation>Limpiar antememoria de teselas</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="301"/>
@ -455,7 +455,7 @@
<message>
<location filename="../src/GUI/gui.cpp" line="322"/>
<source>Show tracks</source>
<translation>Ver tracks</translation>
<translation>Ver pistas</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="327"/>
@ -465,7 +465,7 @@
<message>
<location filename="../src/GUI/gui.cpp" line="332"/>
<source>Show waypoints</source>
<translation>Ver waypoints</translation>
<translation>Ver puntos de referencia</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="337"/>
@ -480,7 +480,7 @@
<message>
<location filename="../src/GUI/gui.cpp" line="347"/>
<source>Route waypoints</source>
<translation>Waypoints de ruta</translation>
<translation>Puntos de referencia de ruta</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="352"/>
@ -622,7 +622,7 @@
<message>
<location filename="../src/GUI/gui.cpp" line="529"/>
<source>POI files</source>
<translation>Archivos de POI&apos;s</translation>
<translation>Archivos de POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="540"/>
@ -727,22 +727,22 @@
<message>
<location filename="../src/GUI/gui.cpp" line="707"/>
<source>Zoom in</source>
<translation>Zoom +</translation>
<translation>Acercar</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="709"/>
<source>Zoom out</source>
<translation>Zoom -</translation>
<translation>Alejar</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="711"/>
<source>Digital zoom</source>
<translation>Zoom digital</translation>
<translation>Escala digital</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="712"/>
<source>Zoom</source>
<translation>Zoom</translation>
<translation>Escala</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="725"/>
@ -752,7 +752,7 @@
<message>
<location filename="../src/GUI/gui.cpp" line="727"/>
<source>POI directory:</source>
<translation>Carpeta de POIs:</translation>
<translation>Carpeta de POI:</translation>
</message>
<message>
<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="877"/>
<source>Line: %1</source>
<translation>Linea: %1</translation>
<translation>Renglón: %1</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="850"/>
<source>Open POI file</source>
<translation>Cargar archivo de POI&apos;s</translation>
<translation>Cargar archivo de POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="874"/>
<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>
<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="1103"/>
<source>Waypoints</source>
<translation>Waypoints</translation>
<translation>Puntos de referencia</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="1037"/>
@ -851,7 +851,7 @@
<message>
<location filename="../src/GUI/gui.cpp" line="1336"/>
<source>Error loading map:</source>
<translation>Error cargando archivo de mapa:</translation>
<translation>Error al cargar el archivo de mapa:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="1347"/>
@ -878,7 +878,7 @@
<message>
<location filename="../src/GUI/gearratiograph.cpp" line="27"/>
<source>Most used</source>
<translation>Mas usada</translation>
<translation>Más usada</translation>
</message>
<message>
<location filename="../src/GUI/gearratiograph.cpp" line="29"/>
@ -914,7 +914,7 @@
<message>
<location filename="../src/GUI/graphview.cpp" line="46"/>
<source>Data not available</source>
<translation>Sin datos</translation>
<translation>Sin datos disponibles</translation>
</message>
<message>
<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="118"/>
<source>ft</source>
<translation></translation>
<translation>ft</translation>
</message>
<message>
<location filename="../src/GUI/graphview.cpp" line="113"/>
@ -1017,7 +1017,7 @@
<message>
<location filename="../src/map/maplist.cpp" line="121"/>
<source>Supported files</source>
<translation>Formatos soportados</translation>
<translation>Formatos admitidos</translation>
</message>
<message>
<location filename="../src/map/maplist.cpp" line="126"/>
@ -1047,7 +1047,7 @@
<message>
<location filename="../src/map/maplist.cpp" line="128"/>
<source>GeoTIFF images</source>
<translation>Imagenes GeoTIFF</translation>
<translation>Imágenes GeoTIFF</translation>
</message>
<message>
<location filename="../src/map/maplist.cpp" line="129"/>
@ -1057,7 +1057,7 @@
<message>
<location filename="../src/map/maplist.cpp" line="130"/>
<source>Online map sources</source>
<translation>Mapas Online</translation>
<translation>Fuentes de mapas en nea</translation>
</message>
</context>
<context>
@ -1065,12 +1065,12 @@
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="61"/>
<source>High-resolution</source>
<translation>Alta resolución</translation>
<translation>Resolución alta</translation>
</message>
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="62"/>
<source>Standard</source>
<translation>Estandar</translation>
<translation>Estándar</translation>
</message>
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="67"/>
@ -1185,12 +1185,12 @@
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="211"/>
<source>Waypoint color:</source>
<translation>Color de waypoints:</translation>
<translation>Color de puntos de referencia:</translation>
</message>
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="212"/>
<source>Waypoint size:</source>
<translation>Tamaño de wapoints:</translation>
<translation>Tamaño de puntos de referencia:</translation>
</message>
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="214"/>
@ -1207,27 +1207,27 @@
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="216"/>
<source>Waypoints</source>
<translation>Waypoints</translation>
<translation>Puntos de referencia</translation>
</message>
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="227"/>
<source>POI color:</source>
<translation>Color de POI&apos;s:</translation>
<translation>Color de POI:</translation>
</message>
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="228"/>
<source>POI size:</source>
<translation>Tamaño de POI&apos;s:</translation>
<translation>Tamaño de POI:</translation>
</message>
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="232"/>
<source>POIs</source>
<translation>POI&apos;s</translation>
<translation>POI</translation>
</message>
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="258"/>
<source>Line width:</source>
<translation>Anchura de linea:</translation>
<translation>Anchura de línea:</translation>
</message>
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="259"/>
@ -1435,17 +1435,17 @@
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="509"/>
<source>High-Resolution</source>
<translation>Alta resolución</translation>
<translation>Resolución alta</translation>
</message>
<message>
<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>
<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>
<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>
<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>
<location filename="../src/GUI/optionsdialog.cpp" line="538"/>
@ -1500,17 +1500,17 @@
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="585"/>
<source>Enable HTTP/2</source>
<translation>Habilitar HTTP/2</translation>
<translation>Activar HTTP/2</translation>
</message>
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="592"/>
<source>MB</source>
<translation>Mo</translation>
<translation>MB</translation>
</message>
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="602"/>
<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>
<location filename="../src/GUI/optionsdialog.cpp" line="603"/>
@ -1591,7 +1591,7 @@
<message>
<location filename="../src/GUI/powergraphitem.cpp" line="17"/>
<source>Maximum</source>
<translation>Maxima</translation>
<translation>Máxima</translation>
</message>
<message>
<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="112"/>
<source>ft</source>
<translation></translation>
<translation>ft</translation>
</message>
<message>
<location filename="../src/GUI/scaleitem.cpp" line="111"/>

View File

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

View File

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

View File

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

View File

@ -119,7 +119,7 @@
<message>
<location filename="../src/data/data.cpp" line="195"/>
<source>SML files</source>
<translation type="unfinished"></translation>
<translation>SML файли</translation>
</message>
<message>
<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[fi]=Ohjelma GPS-lokien katseluun ja analysointiin
Comment[fr]=Visualisation et analyse de fichier GPS
Comment[nb]=GPS-loggfilleser og analysator
Comment[pl]=Przeglądarka i analizator plików dziennika GPS
Comment[ru]=Программа для просмотра и анализа GPS логов
Comment[sv]=GPS-loggfilsläsare och analysator
@ -14,4 +15,4 @@ Icon=gpxsee
Terminal=false
Type=Application
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
Name "GPXSee"
; Program version
!define VERSION "7.20"
!define VERSION "7.25"
; The file to write
OutFile "GPXSee-${VERSION}.exe"
@ -176,6 +176,7 @@ SectionGroup "Localization" SEC_LOCALIZATION
!insertmacro LOCALIZATION "Finnish" "fi"
!insertmacro LOCALIZATION "French" "fr"
!insertmacro LOCALIZATION "German" "de"
!insertmacro LOCALIZATION "Hungarian" "hu"
!insertmacro LOCALIZATION "Norwegian" "nb"
!insertmacro LOCALIZATION "Polish" "pl"
!insertmacro LOCALIZATION "Portuguese (Brazil)" "pt_BR"
@ -251,4 +252,4 @@ LangString DESC_LOCALIZATION ${LANG_ENGLISH} \
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_MSVC} $(DESC_MSVC)
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_APP} $(DESC_APP)
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_LOCALIZATION} $(DESC_LOCALIZATION)
!insertmacro MUI_FUNCTION_DESCRIPTION_END
!insertmacro MUI_FUNCTION_DESCRIPTION_END

View File

@ -7,7 +7,7 @@
; The name of the installer
Name "GPXSee"
; Program version
!define VERSION "7.20"
!define VERSION "7.25"
; The file to write
OutFile "GPXSee-${VERSION}_x64.exe"
@ -183,6 +183,7 @@ SectionGroup "Localization" SEC_LOCALIZATION
!insertmacro LOCALIZATION "Finnish" "fi"
!insertmacro LOCALIZATION "French" "fr"
!insertmacro LOCALIZATION "German" "de"
!insertmacro LOCALIZATION "Hungarian" "hu"
!insertmacro LOCALIZATION "Norwegian" "nb"
!insertmacro LOCALIZATION "Polish" "pl"
!insertmacro LOCALIZATION "Portuguese (Brazil)" "pt_BR"
@ -259,4 +260,4 @@ LangString DESC_LOCALIZATION ${LANG_ENGLISH} \
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_MSVC} $(DESC_MSVC)
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_APP} $(DESC_APP)
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_LOCALIZATION} $(DESC_LOCALIZATION)
!insertmacro MUI_FUNCTION_DESCRIPTION_END
!insertmacro MUI_FUNCTION_DESCRIPTION_END

View File

@ -1,5 +1,5 @@
<?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>
<url>https://tileserver.4umaps.com/$z/$x/$y.png</url>
<zoom min="2" max="15"/>

View File

@ -1,5 +1,5 @@
<?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>
<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>

View File

@ -1,5 +1,5 @@
<?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>
<url>https://tile.openstreetmap.org/$z/$x/$y.png</url>
<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"?>
<map xmlns="http://www.gpxsee.org/map/1.3">
<map xmlns="http://www.gpxsee.org/map/1.4">
<name>Open Topo Map</name>
<url>https://a.tile.opentopomap.org/$z/$x/$y.png</url>
<zoom max="17"/>

View File

@ -1,5 +1,5 @@
<?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>
<url>https://basemap.nationalmap.gov/ArcGIS/rest/services/USGSImageryOnly/MapServer/tile/$z/$y/$x</url>
<zoom min="2" max="15"/>

View File

@ -1,5 +1,5 @@
<?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>
<url>https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/tile/$z/$y/$x</url>
<zoom min="2" max="15"/>

View File

@ -112,7 +112,7 @@ void GUI::loadMaps()
QString mapDir(ProgramPaths::mapDir());
if (!mapDir.isNull() && !_ml->loadDir(mapDir))
qWarning("%s", qPrintable(_ml->errorString()));
qWarning("%s", qPrintable(_ml->errorPath() + ": " + _ml->errorString()));
_map = new EmptyMap(this);
}
@ -1325,7 +1325,10 @@ bool GUI::loadMap(const QString &fileName)
if (fileName.isEmpty())
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());
_mapMenu->insertAction(_mapsEnd, a);
_showMapAction->setEnabled(true);

View File

@ -2,7 +2,6 @@
#include <QGraphicsScene>
#include <QWheelEvent>
#include <QApplication>
#include <QPixmapCache>
#include <QScrollBar>
#include "data/poi.h"
#include "data/data.h"
@ -351,7 +350,6 @@ void MapView::setMap(Map *map)
centerOn(nc);
reloadMap();
QPixmapCache::clear();
}
void MapView::setPOI(POI *poi)
@ -982,7 +980,6 @@ void MapView::setDevicePixelRatio(qreal deviceRatio, qreal mapRatio)
_deviceRatio = deviceRatio;
_mapRatio = mapRatio;
QPixmapCache::clear();
QRectF vr(mapToScene(viewport()->rect()).boundingRect()
.intersected(_map->bounds()));

View File

@ -14,8 +14,8 @@ double Coordinates::distanceTo(const Coordinates &c) const
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const Coordinates &c)
{
dbg.nospace() << qSetRealNumberPrecision(10) << "Coordinates(" << c.lat()
<< ", " << c.lon() << ")";
dbg.nospace() << qSetRealNumberPrecision(10) << "Coordinates(" << c.lon()
<< ", " << c.lat() << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG

View File

@ -3,14 +3,16 @@
#include <QtGlobal>
#define LS(val, bits) ((qint32)(((quint32)(val))<<(bits)))
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)
{
return toWGS32(v<<8);
return toWGS32(LS(v, 8));
}
#endif // GARMIN_H

View File

@ -28,6 +28,9 @@ public:
double left() const {return _tl.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 setRight(double val) {_br.rlon() = val;}
void setTop(double val) {_tl.rlat() = val;}

View File

@ -44,37 +44,37 @@ static CUPParser cup;
static GPIParser gpi;
static SMLParser sml;
static QHash<QString, Parser*> parsers()
static QMap<QString, Parser*> parsers()
{
QHash<QString, Parser*> hash;
QMap<QString, Parser*> map;
hash.insert("gpx", &gpx);
hash.insert("tcx", &tcx);
hash.insert("kml", &kml);
hash.insert("fit", &fit);
hash.insert("csv", &csv);
hash.insert("igc", &igc);
hash.insert("nmea", &nmea);
hash.insert("plt", &plt);
hash.insert("wpt", &wpt);
hash.insert("rte", &rte);
hash.insert("loc", &loc);
hash.insert("slf", &slf);
map.insert("gpx", &gpx);
map.insert("tcx", &tcx);
map.insert("kml", &kml);
map.insert("fit", &fit);
map.insert("csv", &csv);
map.insert("igc", &igc);
map.insert("nmea", &nmea);
map.insert("plt", &plt);
map.insert("wpt", &wpt);
map.insert("rte", &rte);
map.insert("loc", &loc);
map.insert("slf", &slf);
#ifdef ENABLE_GEOJSON
hash.insert("json", &geojson);
hash.insert("geojson", &geojson);
map.insert("json", &geojson);
map.insert("geojson", &geojson);
#endif // ENABLE_GEOJSON
hash.insert("jpeg", &exif);
hash.insert("jpg", &exif);
hash.insert("cup", &cup);
hash.insert("gpi", &gpi);
hash.insert("sml", &sml);
map.insert("jpeg", &exif);
map.insert("jpg", &exif);
map.insert("cup", &cup);
map.insert("gpi", &gpi);
map.insert("sml", &sml);
return hash;
return map;
}
QHash<QString, Parser*> Data::_parsers = parsers();
QMap<QString, Parser*> Data::_parsers = parsers();
bool Data::_useDEM = false;
void Data::processData(QList<TrackData> &trackData, QList<RouteData> &routeData)
@ -130,7 +130,7 @@ Data::Data(const QString &fileName, bool poi)
return;
}
QHash<QString, Parser*>::iterator it;
QMap<QString, Parser*>::iterator it;
if ((it = _parsers.find(fi.suffix().toLower())) != _parsers.end()) {
if (it.value()->parse(&file, trackData, routeData, _polygons,
_waypoints)) {
@ -166,17 +166,8 @@ Data::Data(const QString &fileName, bool poi)
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
qApp->translate("Data", "Supported files") + " (" + supported + ");;"
qApp->translate("Data", "Supported files") + " (" + filter().join(" ") + ");;"
+ qApp->translate("Data", "CSV files") + " (*.csv);;"
+ qApp->translate("Data", "CUP files") + " (*.cup);;"
+ qApp->translate("Data", "FIT files") + " (*.fit);;"
@ -200,10 +191,10 @@ QString Data::formats()
QStringList Data::filter()
{
QStringList filter;
QHash<QString, Parser*>::iterator it;
for (it = _parsers.begin(); it != _parsers.end(); it++)
filter << QString("*.%1").arg(it.key());
for (QMap<QString, Parser*>::iterator it = _parsers.begin();
it != _parsers.end(); it++)
filter << "*." + it.key();
return filter;
}

View File

@ -2,7 +2,7 @@
#define DATA_H
#include <QList>
#include <QHash>
#include <QMap>
#include <QString>
#include <QStringList>
#include "waypoint.h"
@ -42,7 +42,7 @@ private:
QList<Area> _polygons;
QVector<Waypoint> _waypoints;
static QHash<QString, Parser*> _parsers;
static QMap<QString, Parser*> _parsers;
static bool _useDEM;
};

View File

@ -1,7 +1,13 @@
#include <QPainter>
#include <QImage>
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
#include <QtCore/qmath.h>
#else // QT5
#include <QtMath>
#endif // QT5
#include "bitmapline.h"
static QImage img2line(const QImage &img, int width)
{
Q_ASSERT(img.format() == QImage::Format_ARGB32_Premultiplied);
@ -32,8 +38,8 @@ void BitmapLine::draw(QPainter *painter, const QPolygonF &line,
painter->save();
painter->translate(segment.p1());
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();
}
}

View File

@ -32,7 +32,7 @@ bool BitStream1::read(int bits, quint32 &val)
bool BitStream1::flush()
{
if (_length && !_file.seek(_hdl, _hdl.pos + _length))
if (_length && !_file.seek(_hdl, _hdl.pos() + _length))
return false;
_length = 0;
@ -50,18 +50,13 @@ bool BitStream4::read(int bits, quint32 &val)
return true;
}
quint32 old = 0;
if (_used < 32) {
old = (_data << _used) >> (32 - bits);
bits = (bits - 32) + _used;
}
_used = bits;
quint32 bytes = qMin(_length, (quint32)4);
quint32 old = (_used < 32) ? (_data << _used) >> (32 - bits) : 0;
quint32 bytes = qMin(_length, 4U);
if (!_file.readVUInt32SW(_hdl, bytes, _data))
return false;
_used -= 32 - bits;
_length -= bytes;
_unused = (4 - bytes) * 8;
_data <<= _unused;
@ -73,11 +68,12 @@ bool BitStream4::read(int bits, quint32 &val)
bool BitStream4::flush()
{
if (_length && !_file.seek(_hdl, _hdl.pos + _length))
if (_length && !_file.seek(_hdl, _hdl.pos() + _length))
return false;
_length = 0;
_unused = 32;
_used = 32;
_unused = 0;
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)
{
quint32 bit;
@ -64,21 +41,17 @@ bool HuffmanStream::sign(int &val)
bool HuffmanStream::readDelta(int sign, qint32 &symbol)
{
uchar size;
quint8 size;
quint32 next;
quint8 nextSize = qMin((quint32)(32 - _symbolDataSize), bitsAvailable());
if (_symbolDataSize < 32) {
quint32 next;
quint8 nextSize = qMin((quint32)(32 - _symbolDataSize),
bitsAvailable());
if (!read(nextSize, next))
return false;
if (!read(nextSize, next))
return false;
_symbolData = (_symbolData << nextSize) | next;
_symbolDataSize += nextSize;
_symbolData = (_symbolData << nextSize) | next;
_symbolDataSize += nextSize;
}
symbol = _table.symbol(_symbolData << (32U - _symbolDataSize), size);
symbol = _table.symbol(_symbolData << (32 - _symbolDataSize), size);
if (size <= _symbolDataSize)
_symbolDataSize -= size;

View File

@ -9,8 +9,16 @@ public:
HuffmanStream(const SubFile &file, SubFile::Handle &hdl, quint32 length,
const HuffmanTable &table, bool line);
bool readNext(qint32 &lonDelta, qint32 &latDelta);
bool readOffset(qint32 &lonDelta, qint32 &latDelta);
bool readNext(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
{return _symbolDataSize + bitsAvailable() < _table.maxSymbolSize();}

View File

@ -55,7 +55,7 @@ bool HuffmanTable::getBuffer(const SubFile &file, SubFile::Handle &hdl,
return false;
if (!file.readVUInt32(hdl, recordSize))
return false;
recordOffset = hdl.pos + recordSize;
recordOffset = hdl.pos() + recordSize;
if (recordOffset > offset + size)
return false;
};

View File

@ -1,27 +1,11 @@
#include <QMap>
#include <QtEndian>
#include "common/programpaths.h"
#include "map/osm.h"
#include "vectortile.h"
#include "img.h"
#define CACHE_SIZE 8388608 /* 8MB */
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;
};
typedef QMap<QByteArray, VectorTile*> TileMap;
static SubFile::Type tileType(const char str[3])
{
@ -41,8 +25,7 @@ static SubFile::Type tileType(const char str[3])
return SubFile::Unknown;
}
IMG::IMG(const QString &fileName)
: _file(fileName), _typ(0), _style(0), _valid(false)
IMG::IMG(const QString &fileName) : _file(fileName)
{
#define CHECK(condition) \
if (!(condition)) { \
@ -52,7 +35,7 @@ IMG::IMG(const QString &fileName)
}
TileMap tileMap;
QString typFile;
QByteArray typFile;
if (!_file.open(QFile::ReadOnly)) {
_errorString = _file.errorString();
@ -78,8 +61,6 @@ IMG::IMG(const QString &fileName)
QByteArray nba(QByteArray(d1, sizeof(d1)) + QByteArray(d2, sizeof(d2)));
_name = QString::fromLatin1(nba.constData(), nba.size()-1).trimmed();
_blockSize = 1 << (e1 + e2);
_blockCache.setMaxCost(CACHE_SIZE / _blockSize);
// Read the FAT table
quint8 flag;
@ -107,7 +88,7 @@ IMG::IMG(const QString &fileName)
&& read(type, sizeof(type)) && readValue(size) && readValue(part));
SubFile::Type tt = tileType(type);
QString fn(QByteArray(name, sizeof(name)));
QByteArray fn(name, sizeof(name));
if (VectorTile::isTileFile(tt)) {
VectorTile *tile;
TileMap::const_iterator it = tileMap.find(fn);
@ -152,6 +133,8 @@ IMG::IMG(const QString &fileName)
}
// Create tile tree
int minMapZoom = 24;
for (TileMap::const_iterator it = tileMap.constBegin();
it != tileMap.constEnd(); ++it) {
VectorTile *tile = it.value();
@ -171,73 +154,32 @@ IMG::IMG(const QString &fileName)
_tileTree.Insert(min, max, tile);
_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())
_errorString = "No usable map tile found";
else
_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 ret = _file.read(data, maxSize);
@ -259,33 +201,12 @@ template<class T> bool IMG::readValue(T &val)
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))
return false;
data.resize(_blockSize);
if (read(data.data(), _blockSize) < _blockSize)
return false;
_blockCache.insert(blockNum, new QByteArray(data));
} else
data = *block;
if (!_file.seek((qint64)blockNum * (qint64)_blockSize))
return false;
if (read(data, _blockSize) < _blockSize)
return false;
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
#include <QFile>
#include <QByteArray>
#include <QCache>
#include <QDebug>
#include "common/rtree.h"
#include "common/rectc.h"
#include "style.h"
#include "label.h"
#include "mapdata.h"
class VectorTile;
class SubFile;
class IMG
class IMG : public 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;
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();
void load();
void clear();
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:
friend class SubFile;
typedef RTree<VectorTile*, double, 2> TileTree;
int blockSize() const {return _blockSize;}
bool readBlock(int blockNum, QByteArray &data);
bool readBlock(int blockNum, char *data);
qint64 read(char *data, qint64 maxSize);
template<class T> bool readValue(T &val);
QFile _file;
quint8 _key;
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

View File

@ -30,15 +30,20 @@ static quint8 SPECIAL_CHARS[] = {
'8', '9', '~', '~', '~', '~', '~', '~'
};
static QString capitalize(const QString &str)
static bool isAllUpperCase(const QString &str)
{
if (str.isEmpty())
return str;
return false;
for (int i = 0; i < str.size(); i++)
if (str.at(i).isLetter() && !(str.at(i).isUpper()
|| str.at(i) == QChar(0x00DF)))
return str;
return false;
return true;
}
static QString capitalized(const QString &str)
{
QString ret(str);
for (int i = 0; i < str.size(); i++)
if (i && !str.at(i-1).isSpace())
@ -77,7 +82,7 @@ bool LBLFile::init(Handle &hdl)
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;
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};
for (int cpt = 0; cpt < 4; cpt++) {
if (c[cpt] > 0x2f || (curCharSet == Normal && c[cpt] == 0x1d))
return Label(capitalize(QString::fromLatin1(label)),
Label::Shield(shieldType, shieldLabel));
if (c[cpt] > 0x2f || (curCharSet == Normal && c[cpt] == 0x1d)) {
QString text(QString::fromLatin1(label));
return Label(capitalize && isAllUpperCase(text)
? capitalized(text) : text, Label::Shield(shieldType,
shieldLabel));
}
switch (curCharSet) {
case Normal:
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;
QByteArray label, shieldLabel;
@ -157,12 +165,15 @@ Label LBLFile::label8b(Handle &hdl, quint32 offset) const
bap->append(c);
}
return Label(capitalize(_codec ? _codec->toUnicode(label)
: QString::fromLatin1(label)), Label::Shield(shieldType, _codec
? _codec->toUnicode(shieldLabel) : QString::fromLatin1(shieldLabel)));
QString text(_codec ? _codec->toUnicode(label) : QString::fromLatin1(label));
QString shieldText(_codec ? _codec->toUnicode(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))
return QString();
@ -183,10 +194,10 @@ Label LBLFile::label(Handle &hdl, quint32 offset, bool poi)
switch (_encoding) {
case 6:
return label6b(hdl, labelOffset);
return label6b(hdl, labelOffset, capitalize);
case 9:
case 10:
return label8b(hdl, labelOffset);
return label8b(hdl, labelOffset, capitalize);
default:
return Label();
}

View File

@ -12,17 +12,21 @@ public:
LBLFile(IMG *img)
: SubFile(img), _codec(0), _offset(0), _size(0), _poiOffset(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),
_codec(0), _offset(0), _size(0), _poiOffset(0), _poiSize(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:
bool init(Handle &hdl);
Label label6b(Handle &hdl, quint32 offset) const;
Label label8b(Handle &hdl, quint32 offset) const;
Label label6b(Handle &hdl, quint32 offset, bool capitalize) const;
Label label8b(Handle &hdl, quint32 offset, bool capitalize) const;
QTextCodec *_codec;
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
{
public:
NETFile(IMG *img) : SubFile(img), _offset(0), _size(0), _multiplier(0) {}
NETFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
_offset(0), _size(0), _multiplier(0) {}
NETFile(IMG *img)
: SubFile(img), _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);

View File

@ -8,6 +8,20 @@
#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
{
quint8 flags;
@ -35,11 +49,11 @@ bool RGNFile::skipClassFields(Handle &hdl) const
break;
}
return seek(hdl, hdl.pos + rs);
return seek(hdl, hdl.pos() + rs);
}
bool RGNFile::skipLclFields(Handle &hdl, const quint32 flags[3],
Segment::Type type) const
SegmentType type) const
{
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;
switch (i) {
case 5:
if (m == 1 && type == Segment::Point) {
if (m == 1 && type == Point) {
quint16 u16;
if (!readUInt16(hdl, u16))
return false;
@ -116,11 +130,16 @@ bool RGNFile::init(Handle &hdl)
return true;
}
bool RGNFile::polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
const Segment &segment, LBLFile *lbl, Handle &lblHdl, NETFile *net,
bool RGNFile::polyObjects(Handle &hdl, const SubDiv *subdiv,
SegmentType segmentType, LBLFile *lbl, Handle &lblHdl, NETFile *net,
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;
quint32 labelPtr;
@ -128,7 +147,7 @@ bool RGNFile::polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
qint16 lon, lat;
quint16 len;
while (hdl.pos < (int)segment.end()) {
while (hdl.pos() < (int)segment.end()) {
IMG::Poly poly;
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))
return false;
poly.type = (segment.type() == Segment::Polygon)
poly.type = (segmentType == Polygon)
? ((quint32)(type & 0x7F)) << 8 : ((quint32)(type & 0x3F)) << 8;
QPoint pos(subdiv->lon() + ((qint32)lon<<(24-subdiv->bits())),
subdiv->lat() + ((qint32)lat<<(24-subdiv->bits())));
QPoint pos(subdiv->lon() + LS(lon, 24-subdiv->bits()),
subdiv->lat() + LS(lat, 24-subdiv->bits()));
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()));
qint32 lonDelta, latDelta;
DeltaStream stream(*this, hdl, len, bitstreamInfo, labelPtr & 0x400000,
false);
while (stream.readNext(lonDelta, latDelta)) {
pos.rx() += lonDelta<<(24-subdiv->bits());
pos.ry() += latDelta<<(24-subdiv->bits());
pos.rx() += LS(lonDelta, (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()));
poly.points.append(QPointF(c.lon(), c.lat()));
br = br.united(c);
poly.boundingRect = poly.boundingRect.united(c);
}
if (!(stream.atEnd() && stream.flush()))
return false;
if (!rect.intersects(br))
continue;
if (lbl && (labelPtr & 0x3FFFFF)) {
if (labelPtr & 0x800000) {
quint32 lblOff;
@ -188,22 +206,25 @@ bool RGNFile::polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
return true;
}
bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
const SubDiv *subdiv, quint32 shift, const Segment &segment, LBLFile *lbl,
Handle &lblHdl, QList<IMG::Poly> *polys, bool line) const
bool RGNFile::extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift,
SegmentType segmentType, LBLFile *lbl, Handle &lblHdl,
QList<IMG::Poly> *polys) const
{
quint32 labelPtr, len;
quint8 type, subtype;
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;
while (hdl.pos < (int)segment.end()) {
while (hdl.pos() < (int)segment.end()) {
IMG::Poly poly;
QPoint pos;
RectC br;
if (!(readUInt8(hdl, type) && readUInt8(hdl, subtype)
&& readInt16(hdl, lon) && readInt16(hdl, lat)
@ -214,38 +235,41 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
labelPtr = 0;
if (!_huffmanTable.isNull()) {
pos = QPoint((subdiv->lon()<<8) + ((qint32)lon<<(32-subdiv->bits())),
(subdiv->lat()<<8) + ((qint32)lat<<(32-subdiv->bits())));
pos = QPoint(LS(subdiv->lon(), 8) + LS(lon, 32-subdiv->bits()),
LS(subdiv->lat(), 8) + LS(lat, (32-subdiv->bits())));
qint32 lonDelta, latDelta;
HuffmanStream stream(*this, hdl, len, _huffmanTable, line);
HuffmanStream stream(*this, hdl, len, _huffmanTable,
segmentType == Line);
if (shift) {
if (!stream.readOffset(lonDelta, latDelta))
return false;
pos = QPoint(pos.x() | lonDelta<<(32-subdiv->bits()-shift),
pos.y() | latDelta<<(32-subdiv->bits()-shift));
pos = QPoint(pos.x() | LS(lonDelta, 32-subdiv->bits()-shift),
pos.y() | LS(latDelta, 32-subdiv->bits()-shift));
}
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()));
while (stream.readNext(lonDelta, latDelta)) {
pos.rx() += lonDelta<<(32-subdiv->bits()-shift);
pos.ry() += latDelta<<(32-subdiv->bits()-shift);
pos.rx() += LS(lonDelta, 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()));
poly.points.append(QPointF(c.lon(), c.lat()));
br = br.united(c);
poly.boundingRect = poly.boundingRect.united(c);
}
if (!(stream.atEnd() && stream.flush()))
return false;
} else {
pos = QPoint(subdiv->lon() + ((qint32)lon<<(24-subdiv->bits())),
subdiv->lat() + ((qint32)lat<<(24-subdiv->bits())));
pos = QPoint(subdiv->lon() + LS(lon, 24-subdiv->bits()),
subdiv->lat() + LS(lat, 24-subdiv->bits()));
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()));
quint8 bitstreamInfo;
@ -256,12 +280,14 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
DeltaStream stream(*this, hdl, len - 1, bitstreamInfo, false, true);
while (stream.readNext(lonDelta, latDelta)) {
pos.rx() += lonDelta<<(24-subdiv->bits());
pos.ry() += latDelta<<(24-subdiv->bits());
pos.rx() += LS(lonDelta, 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()));
poly.points.append(QPointF(c.lon(), c.lat()));
br = br.united(c);
poly.boundingRect = poly.boundingRect.united(c);
}
if (!(stream.atEnd() && stream.flush()))
return false;
@ -271,13 +297,10 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
return false;
if (subtype & 0x80 && !skipClassFields(hdl))
return false;
if (subtype & 0x40 && !skipLclFields(hdl, line ? _linesFlags
: _polygonsFlags, segment.type()))
if (subtype & 0x40 && !skipLclFields(hdl, segmentType == Line
? _linesFlags : _polygonsFlags, segmentType))
return false;
if (!rect.intersects(br))
continue;
if (lbl && (labelPtr & 0x3FFFFF))
poly.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF);
@ -287,19 +310,23 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
return true;
}
bool RGNFile::pointObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
const Segment &segment, LBLFile *lbl, Handle &lblHdl,
bool RGNFile::pointObjects(Handle &hdl, const SubDiv *subdiv,
SegmentType segmentType, LBLFile *lbl, Handle &lblHdl,
QList<IMG::Point> *points) const
{
quint8 type, subtype;
qint16 lon, lat;
quint32 labelPtr;
const SubDiv::Segment &segment = (segmentType == IndexedPoint)
? subdiv->idxPoints() : subdiv->points();
if (!seek(hdl, segment.start()))
if (!segment.isValid())
return true;
if (!seek(hdl, segment.offset()))
return false;
while (hdl.pos < (int)segment.end()) {
while (hdl.pos() < (int)segment.end()) {
IMG::Point point;
quint8 type, subtype;
qint16 lon, lat;
quint32 labelPtr;
if (!(readUInt8(hdl, type) && readUInt24(hdl, labelPtr)
&& readInt16(hdl, lon) && readInt16(hdl, lat)))
@ -310,22 +337,17 @@ bool RGNFile::pointObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
} else
subtype = 0;
QPoint pos(subdiv->lon() + LS(lon, 24-subdiv->bits()),
subdiv->lat() + LS(lat, 24-subdiv->bits()));
point.type = (quint16)type<<8 | subtype;
qint16 lonOffset = lon<<(24-subdiv->bits());
qint16 latOffset = lat<<(24-subdiv->bits());
point.coordinates = Coordinates(toWGS24(subdiv->lon() + lonOffset),
toWGS24(subdiv->lat() + latOffset));
if (!rect.contains(point.coordinates))
continue;
point.coordinates = Coordinates(toWGS24(pos.x()), toWGS24(pos.y()));
point.id = pointId(pos, point.type, labelPtr & 0x3FFFFF);
point.poi = labelPtr & 0x400000;
if (lbl && (labelPtr & 0x3FFFFF)) {
point.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF, point.poi);
point.id = ((quint64)point.type)<<40 | ((quint64)lbl->offset())<<24
| (labelPtr & 0x3FFFFF);
}
if (lbl && (labelPtr & 0x3FFFFF))
point.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF, point.poi,
!(point.type == 0x1400 || point.type == 0x1500
|| point.type == 0x1e00));
points->append(point);
}
@ -333,48 +355,47 @@ bool RGNFile::pointObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
return true;
}
bool RGNFile::extPointObjects(const RectC &rect, Handle &hdl,
const SubDiv *subdiv, const Segment &segment, LBLFile *lbl,
bool RGNFile::extPointObjects(Handle &hdl, const SubDiv *subdiv, LBLFile *lbl,
Handle &lblHdl, QList<IMG::Point> *points) const
{
quint8 type, subtype;
qint16 lon, lat;
quint32 labelPtr;
const SubDiv::Segment &segment = subdiv->extPoints();
if (!seek(hdl, segment.start()))
if (!segment.isValid())
return true;
if (!seek(hdl, segment.offset()))
return false;
while (hdl.pos < (int)segment.end()) {
while (hdl.pos() < (int)segment.end()) {
IMG::Point point;
qint16 lon, lat;
quint8 type, subtype;
quint32 labelPtr = 0;
if (!(readUInt8(hdl, type) && readUInt8(hdl, subtype)
&& readInt16(hdl, lon) && readInt16(hdl, lat)))
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))
return false;
if (subtype & 0x80 && !skipClassFields(hdl))
return false;
if (subtype & 0x40 && !skipLclFields(hdl, _pointsFlags, segment.type()))
if (subtype & 0x40 && !skipLclFields(hdl, _pointsFlags, Point))
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;
point.coordinates = Coordinates(toWGS24(pos.x()), toWGS24(pos.y()));
point.id = pointId(pos, point.type, labelPtr & 0x3FFFFF);
point.poi = labelPtr & 0x400000;
if (lbl && (labelPtr & 0x3FFFFF)) {
if (lbl && (labelPtr & 0x3FFFFF))
point.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF, point.poi);
point.id = ((quint64)point.type)<<40
| ((quint64)lbl->offset())<<24 | (labelPtr & 0x3FFFFF);
}
points->append(point);
}
@ -382,85 +403,13 @@ bool RGNFile::extPointObjects(const RectC &rect, Handle &hdl,
return true;
}
void RGNFile::objects(const RectC &rect, const SubDiv *subdiv,
LBLFile *lbl, NETFile *net, QList<IMG::Poly> *polygons,
QList<IMG::Poly> *lines, QList<IMG::Point> *points)
QMap<RGNFile::SegmentType, SubDiv::Segment> RGNFile::segments(Handle &hdl,
SubDiv *subdiv) const
{
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))
return QVector<Segment>();
return ret;
quint32 offset = _offset + subdiv->offset();
@ -470,57 +419,63 @@ QVector<RGNFile::Segment> RGNFile::segments(Handle &hdl, const SubDiv *subdiv)
no++;
if (!seek(hdl, offset))
return QVector<Segment>();
return ret;
QVector<Segment> ret;
quint32 start = offset + 2 * (no - 1);
quint16 po;
int cnt = 0;
quint32 ls = 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 (cnt) {
if (!readUInt16(hdl, po))
return QVector<Segment>();
if (ls) {
quint16 po;
if (!readUInt16(hdl, po) || !po)
return QMap<RGNFile::SegmentType, SubDiv::Segment>();
start = offset + po;
ret.insert(lt, SubDiv::Segment(ls, start));
}
if (!ret.isEmpty())
ret.last().setEnd(start);
ret.append(Segment(start, (Segment::Type)mask));
cnt++;
lt = (SegmentType)mask;
ls = start;
}
}
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;
}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const RGNFile::Segment &segment)
bool RGNFile::subdivInit(Handle &hdl, SubDiv *subdiv) const
{
QString type;
switch (segment.type()) {
case RGNFile::Segment::Point:
type = "Point";
break;
case RGNFile::Segment::IndexedPoint:
type = "IndexedPoint";
break;
case RGNFile::Segment::Line:
type = "Line";
break;
case RGNFile::Segment::Polygon:
type = "Polygon";
break;
case RGNFile::Segment::RoadReference:
type = "RoadReference";
break;
QMap<RGNFile::SegmentType, SubDiv::Segment> seg(segments(hdl, subdiv));
SubDiv::Segment extPoints, extLines, extPolygons;
if (subdiv->extPointsOffset() != subdiv->extPointsEnd()) {
quint32 start = _pointsOffset + subdiv->extPointsOffset();
quint32 end = subdiv->extPointsEnd()
? _pointsOffset + subdiv->extPointsEnd()
: _pointsOffset + _pointsSize;
extPoints = SubDiv::Segment(start, end);
}
if (subdiv->extPolygonsOffset() != subdiv->extPolygonsEnd()) {
quint32 start = _polygonsOffset + subdiv->extPolygonsOffset();
quint32 end = subdiv->extPolygonsEnd()
? _polygonsOffset + subdiv->extPolygonsEnd()
: _polygonsOffset + _polygonsSize;
extPolygons = SubDiv::Segment(start, end);
}
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()
- segment.start() << ", " << type << ")";
subdiv->init(seg.value(Point), seg.value(IndexedPoint), seg.value(Line),
seg.value(Polygon), seg.value(RoadReference), extPoints, extLines,
extPolygons);
return dbg.space();
return true;
}
#endif // QT_NO_DEBUG

View File

@ -12,74 +12,50 @@ class NETFile;
class RGNFile : public SubFile
{
public:
enum SegmentType {
Point = 0x1,
IndexedPoint = 0x2,
Line = 0x4,
Polygon = 0x8,
RoadReference = 0x10
};
RGNFile(IMG *img)
: SubFile(img), _offset(0), _size(0), _polygonsOffset(0),
_polygonsSize(0), _linesOffset(0), _linesSize(0), _pointsOffset(0),
_pointsSize(0), _init(false) {clearFlags();}
RGNFile(const QString &path)
: SubFile(path), _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,
IndexedPoint = 0x2,
Line = 0x4,
Polygon = 0x8,
RoadReference = 0x10
};
Segment() : _start(0), _end(0), _type(Point) {}
Segment(quint32 start, Type type)
: _start(start), _end(0), _type(type) {}
Segment(quint32 start, quint32 end, Type type)
: _start(start), _end(end), _type(type) {}
void setEnd(quint32 end) {_end = end;}
quint32 start() const {return _start;}
quint32 end() const {return _end;}
Type type() const {return _type;}
private:
quint32 _start;
quint32 _end;
Type _type;
};
bool initialized() const {return _init;}
bool init(Handle &hdl);
QVector<Segment> segments(Handle &hdl, const SubDiv *subdiv) const;
bool polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
const Segment &segment, LBLFile *lbl, Handle &lblHdl, NETFile *net,
Handle &netHdl, QList<IMG::Poly> *polys) const;
bool pointObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
const Segment &segment, LBLFile *lbl, Handle &lblHdl,
QList<IMG::Point> *points) const;
bool extPolyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
quint32 shift, const Segment &segment, LBLFile *lbl, Handle &lblHdl,
QList<IMG::Poly> *polys, bool line) const;
bool extPointObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
const Segment &segment, LBLFile *lbl, Handle &lblHdl,
QList<IMG::Point> *points) const;
bool polyObjects(Handle &hdl, const SubDiv *subdiv, SegmentType segmentType,
LBLFile *lbl, Handle &lblHdl, NETFile *net, Handle &netHdl,
QList<IMG::Poly> *polys) const;
bool pointObjects(Handle &hdl, const SubDiv *subdiv, SegmentType segmentType,
LBLFile *lbl, Handle &lblHdl, QList<IMG::Point> *points) const;
bool extPolyObjects(Handle &hdl, const SubDiv *subdiv, quint32 shift,
SegmentType segmentType, LBLFile *lbl, Handle &lblHdl,
QList<IMG::Poly> *polys) const;
bool extPointObjects(Handle &hdl, const SubDiv *subdiv, 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();
bool skipClassFields(Handle &hdl) const;
bool skipLclFields(Handle &hdl, const quint32 flags[3],
Segment::Type type) const;
friend QDebug operator<<(QDebug dbg, const RGNFile::Segment &segment);
bool skipLclFields(Handle &hdl, const quint32 flags[3], SegmentType type)
const;
quint32 _offset;
quint32 _size;
@ -99,8 +75,4 @@ private:
bool _init;
};
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const RGNFile::Segment &segment);
#endif // QT_NO_DEBUG
#endif // RGNFILE_H

View File

@ -1,4 +1,5 @@
#include <QImage>
#include <QPainter>
#include "style.h"
@ -79,13 +80,19 @@ void Style::defaultPolygonStyle()
<< 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()
{
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),
QPen(QColor("#72a35a"), 6, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
_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));
_lines[TYPE(0x0c)] = Line(QPen(QColor("#ffffff"), 3, Qt::SolidLine),
QPen(QColor("#d5cdc0"), 5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
_lines[TYPE(0x14)] = Line(rr, QPen(Qt::white, 3, Qt::SolidLine,
Qt::RoundCap, Qt::RoundJoin));
_lines[TYPE(0x14)] = Line(railroad());
_lines[TYPE(0x16)] = Line(QPen(QColor("#aba083"), 1, Qt::DotLine));
_lines[TYPE(0x18)] = Line(QPen(QColor("#9fc4e1"), 2, Qt::SolidLine));
_lines[TYPE(0x18)].setTextColor(QColor("#9fc4e1"));
//_lines[TYPE(0x1a)] = 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(0x1f)] = Line(QPen(QColor("#9fc4e1"), 3, Qt::SolidLine));
_lines[TYPE(0x1f)].setTextColor(QColor("#9fc4e1"));
@ -145,6 +152,17 @@ void Style::defaultLineStyle()
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
_points[TYPE(0x01)].setTextFontSize(Large);
_points[TYPE(0x02)].setTextFontSize(Large);
@ -341,7 +359,7 @@ static bool skipLocalization(SubFile *file, SubFile::Handle &hdl)
len = len >> 2;
}
if (!file->seek(hdl, hdl.pos + len))
if (!file->seek(hdl, hdl.pos() + len))
return false;
return true;
@ -890,7 +908,7 @@ bool Style::parseDrawOrder(SubFile *file, SubFile::Handle &hdl,
bool Style::parseTYPFile(SubFile *file)
{
SubFile::Handle hdl;
SubFile::Handle hdl(file);
Section points, lines, polygons, order;
quint16 tmp16, codepage;
@ -939,9 +957,6 @@ Style::Style(SubFile *typ)
if (typ)
parseTYPFile(typ);
// Override stuff breaking the style display logic
_points[0x11400] = Point(None);
}
const Style::Line &Style::line(quint32 type) const

View File

@ -16,7 +16,8 @@ public:
None = 1,
Small = 2,
Normal = 3,
Large = 4
Large = 4,
ExtraSmall = 5
};
enum POIClass {

View File

@ -7,55 +7,147 @@
class SubDiv {
public:
SubDiv(quint32 offset, qint32 lon, qint32 lat, int bits, quint8 objects)
: _offset(offset), _end(0), _lon(lon), _lat(lat), _bits(bits),
_objects(objects), _polygonsOffset(0), _polygonsEnd(0), _linesOffset(0),
_linesEnd(0), _pointsOffset(0), _pointsEnd(0) {}
void setEnd(quint32 end) {_end = end;}
class Segment {
public:
Segment() : _offset(0), _end(0) {}
Segment(quint32 ofset, quint32 end) : _offset(ofset), _end(end) {}
bool isValid() const {return (_end > _offset);}
quint32 offset() const {return _offset;}
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;}
quint32 offset() const {return _offset;}
quint32 end() const {return _end;}
qint32 lon() const {return _lon;}
qint32 lat() const {return _lat;}
quint8 bits() const {return _bits;}
quint8 objects() const {return _objects;}
// Extended types objects (TRE7)
void setExtOffsets(quint32 polygon, quint32 line, quint32 point)
{_polygonsOffset = polygon; _linesOffset = line; _pointsOffset = point;}
void setExtEnds(quint32 polygon, quint32 line, quint32 point)
{_polygonsEnd = polygon; _linesEnd = line; _pointsEnd = point;}
// Valid only after initialization
Segment points() const
{return Segment(_rgn.pointsOffset, _rgn.pointsEnd);}
Segment idxPoints() const
{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;}
quint32 polygonsEnd() const {return _polygonsEnd;}
quint32 linesOffset() const {return _linesOffset;}
quint32 linesEnd() const {return _linesEnd;}
quint32 pointsOffset() const {return _pointsOffset;}
quint32 pointsEnd() const {return _pointsEnd;}
// Valid only until initialization
quint8 objects() const {return _tre.objects;}
quint32 offset() const {return _tre.offset;}
quint32 end() const {return _tre.end;}
quint32 extPolygonsOffset() const {return _tre.extPolygonsOffset;}
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:
quint32 _offset;
quint32 _end;
struct TRE
{
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;
quint8 _bits;
quint8 _objects;
quint32 _polygonsOffset;
quint32 _polygonsEnd;
quint32 _linesOffset;
quint32 _linesEnd;
quint32 _pointsOffset;
quint32 _pointsEnd;
bool _init;
union {
TRE _tre;
RGN _rgn;
};
};
#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

View File

@ -5,39 +5,40 @@
bool SubFile::seek(Handle &handle, quint32 pos) const
{
if (_file)
return _file->seek(pos);
else {
if (handle._file) {
int blockNum = pos / BLOCK_SIZE;
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();
int blockNum = pos / blockSize;
if (handle.blockNum != blockNum) {
if (handle._blockNum != blockNum) {
if (blockNum >= _blocks->size())
return false;
if (!_img->readBlock(_blocks->at(blockNum), handle.data))
if (!_img->readBlock(_blocks->at(blockNum), handle._data.data()))
return false;
handle.blockNum = blockNum;
handle._blockNum = blockNum;
}
handle.blockPos = pos % blockSize;
handle.pos = pos;
handle._blockPos = pos % blockSize;
handle._pos = pos;
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
{
quint8 bytes, shift, b;
@ -69,20 +70,6 @@ bool SubFile::readVUInt32(Handle &hdl, quint32 &val) const
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
{
quint8 bits;
@ -91,7 +78,7 @@ bool SubFile::readVBitfield32(Handle &hdl, quint32 &bitfield) const
return false;
if (!(bits & 1)) {
seek(hdl, hdl.pos - 1);
seek(hdl, hdl._pos - 1);
if (!((bits>>1) & 1)) {
if (!((bits>>2) & 1)) {
if (!readUInt32(hdl, bitfield))
@ -111,8 +98,3 @@ bool SubFile::readVBitfield32(Handle &hdl, quint32 &bitfield) const
return true;
}
QString SubFile::fileName() const
{
return _file ? _file->fileName() : _img->fileName();
}

View File

@ -2,36 +2,56 @@
#define SUBFILE_H
#include <QVector>
#include <QDebug>
#include <QFile>
#include "img.h"
class QFile;
class IMG;
#define BLOCK_SIZE 4096
class SubFile
{
public:
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 blockNum;
int blockPos;
int pos;
int pos() const {return _pos;}
private:
friend class SubFile;
QFile *_file;
QByteArray _data;
int _blockNum;
int _blockPos;
int _pos;
};
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),
_blocks(gmp->_blocks), _file(gmp->_file) {}
SubFile(QFile *file)
: _gmpOffset(0), _img(0), _blocks(0), _file(file) {}
_blocks(gmp->_blocks), _path(gmp->_path) {}
SubFile(const QString &path)
: _gmpOffset(0), _img(0), _blocks(0), _path(new QString(path)) {}
~SubFile()
{
if (!_gmpOffset)
if (!_gmpOffset) {
delete _blocks;
delete _path;
}
}
void addBlock(quint16 block) {_blocks->append(block);}
@ -97,22 +117,41 @@ public:
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 readVUInt32SW(Handle &hdl, quint32 bytes, quint32 &val) const;
bool readVBitfield32(Handle &hdl, quint32 &bitfield) const;
quint16 offset() const {return _blocks->first();}
QString fileName() const;
QString fileName() const {return _path ? *_path : _img->fileName();}
protected:
quint32 _gmpOffset;
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;
QVector<quint16> *_blocks;
QFile *_file;
QString *_path;
};
#endif // SUBFILE_H

View File

@ -3,6 +3,11 @@
#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 const unsigned char shuf[] = {
@ -39,10 +44,11 @@ TREFile::~TREFile()
bool TREFile::init()
{
Handle hdl;
Handle hdl(this);
quint8 locked;
quint16 hdrLen;
if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)
&& seek(hdl, _gmpOffset + 0x0D) && readUInt8(hdl, locked)))
return false;
@ -53,7 +59,8 @@ bool TREFile::init()
&& readInt24(hdl, east) && readInt24(hdl, south) && readInt24(hdl, west)))
return false;
_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
quint32 levelsOffset, levelsSize, subdivSize;
@ -108,12 +115,14 @@ bool TREFile::init()
}
}
_isBaseMap = false;
return (_firstLevel >= 0);
}
bool TREFile::load(int idx)
{
Handle hdl;
Handle hdl(this);
QList<SubDiv*> sl;
SubDiv *s = 0;
SubDivTree *tree = new SubDivTree();
@ -130,8 +139,8 @@ bool TREFile::load(int idx)
for (int j = 0; j < _levels.at(idx).subdivs; j++) {
quint32 oo;
qint32 lon, lat;
quint16 width, height, nextLevel;
qint32 lon, lat, width, height;
quint16 nextLevel;
if (!(readUInt32(hdl, oo) && readInt24(hdl, lon) && readInt24(hdl, lat)
&& readUInt16(hdl, width) && readUInt16(hdl, height)))
@ -147,17 +156,16 @@ bool TREFile::load(int idx)
s->setEnd(offset);
width &= 0x7FFF;
width <<= (24 - _levels.at(idx).bits);
height <<= (24 - _levels.at(idx).bits);
width = LS(width, 24 - _levels.at(idx).bits);
height = LS(height, 24 - _levels.at(idx).bits);
s = new SubDiv(offset, lon, lat, _levels.at(idx).bits, objects);
sl.append(s);
double min[2], max[2];
RectC bounds(Coordinates(toWGS24(lon - width),
toWGS24(lat + height + 1)), Coordinates(toWGS24(lon + width + 1),
toWGS24(lat - height)));
RectC bounds(Coordinates(toWGS24(lon - width), toWGS24(lat + height)),
Coordinates(RB(lon + width), toWGS24(lat - height)));
Q_ASSERT(bounds.left() <= bounds.right());
min[0] = bounds.left();
min[1] = bounds.bottom();
@ -199,7 +207,7 @@ bool TREFile::load(int idx)
if (i)
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;
}
@ -236,8 +244,15 @@ void TREFile::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;
for (int i = idx + 1; i < _levels.size(); i++) {
@ -259,10 +274,10 @@ static bool cb(SubDiv *subdiv, void *context)
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;
SubDivTree *tree = _subdivs.value(level(bits));
SubDivTree *tree = _subdivs.value(level(bits, baseMap));
double min[2], max[2];
min[0] = rect.left();

View File

@ -14,16 +14,20 @@ class TREFile : public SubFile
{
public:
TREFile(IMG *img) : SubFile(img) {}
TREFile(const QString &path) : SubFile(path) {}
TREFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset) {}
~TREFile();
bool init();
void markAsBasemap() {_isBaseMap = true;}
void clear();
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
{return (bits == _levels.last().bits) ? (_flags >> 0xb) & 7 : 0;}
Range zooms() const
{return Range(_levels.at(_firstLevel).bits, _levels.last().bits);}
private:
struct MapLevel {
@ -41,7 +45,7 @@ private:
typedef RTree<SubDiv*, double, 2> SubDivTree;
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,
QMap<quint32, int> &map);
bool parsePoints(Handle hdl, quint32 pos, const QMap<int, int> &level2bits);
@ -54,6 +58,7 @@ private:
Extended _extended;
int _firstLevel;
quint32 _flags;
bool _isBaseMap;
QMap<int, SubDivTree*> _subdivs;
};

View File

@ -1,5 +1,23 @@
#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)
{
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()
{
if (_gmp && !initGMP())
@ -54,7 +95,7 @@ bool VectorTile::init()
bool VectorTile::initGMP()
{
SubFile::Handle hdl;
SubFile::Handle hdl(_gmp);
quint32 tre, rgn, lbl, net;
if (!(_gmp->seek(hdl, 0x19) && _gmp->readUInt32(hdl, tre)
@ -62,25 +103,84 @@ bool VectorTile::initGMP()
&& _gmp->readUInt32(hdl, net)))
return false;
_tre = new TREFile(_gmp, tre);
_rgn = new RGNFile(_gmp, rgn);
_lbl = new LBLFile(_gmp, lbl);
_net = new NETFile(_gmp, net);
_tre = tre ? new TREFile(_gmp, tre) : 0;
_rgn = rgn ? new RGNFile(_gmp, rgn) : 0;
_lbl = lbl ? new LBLFile(_gmp, lbl) : 0;
_net = net ? new NETFile(_gmp, net) : 0;
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::Point> *points) const
QCache<const SubDiv *, IMG::Polys> *polyCache) const
{
QList<SubDiv*> subdivs = _tre->subdivs(rect, bits);
for (int i = 0; i < subdivs.size(); i++) {
const SubDiv *subdiv = subdivs.at(i);
quint32 shift = _tre->shift(subdiv->bits());
SubFile::Handle rgnHdl(_rgn), lblHdl(_lbl), netHdl(_net);
_rgn->objects(rect, subdiv, _lbl, _net, polygons, lines, points);
_rgn->extObjects(rect, subdiv, shift, _lbl, polygons, lines, points);
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);
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
#define VECTORTILE_H
#include "img.h"
#include "trefile.h"
#include "trefile.h"
#include "rgnfile.h"
@ -17,15 +16,22 @@ public:
}
bool init();
void markAsBasemap() {_tre->markAsBasemap();}
void clear() {_tre->clear();}
const RectC &bounds() const {return _tre->bounds();}
Range zooms() const {return _tre->zooms();}
SubFile *file(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,
QList<IMG::Poly> *lines, QList<IMG::Point> *points) const;
void polys(const RectC &rect, int bits, bool baseMap,
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)
{
@ -34,8 +40,6 @@ public:
|| type == SubFile::GMP);
}
friend QDebug operator<<(QDebug dbg, const VectorTile &tile);
private:
bool initGMP();

View File

@ -13,6 +13,9 @@
#include "IMG/textpathitem.h"
#include "IMG/textpointitem.h"
#include "IMG/bitmapline.h"
#include "IMG/style.h"
#include "IMG/img.h"
#include "IMG/gmap.h"
#include "pcs.h"
#include "rectd.h"
#include "imgmap.h"
@ -35,9 +38,9 @@ public:
const QString &key() const {return _key;}
const QPoint &xy() const {return _xy;}
QImage &img() {return _img;}
QList<IMG::Poly> &polygons() {return _polygons;}
QList<IMG::Poly> &lines() {return _lines;}
QList<IMG::Point> &points() {return _points;}
QList<MapData::Poly> &polygons() {return _polygons;}
QList<MapData::Poly> &lines() {return _lines;}
QList<MapData::Point> &points() {return _points;}
void render()
{
@ -70,14 +73,12 @@ private:
QPoint _xy;
QString _key;
QImage _img;
QList<IMG::Poly> _polygons;
QList<IMG::Poly> _lines;
QList<IMG::Point> _points;
QList<MapData::Poly> _polygons;
QList<MapData::Poly> _lines;
QList<MapData::Point> _points;
};
static const Range zooms(12, 28);
static const QColor shieldColor(Qt::white);
static const QColor shieldBgColor1("#dd3e3e");
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 normal = pixelSizeFont(14);
static QFont small = pixelSizeFont(12);
static QFont extraSmall = pixelSizeFont(10);
switch (size) {
case Style::None:
@ -136,6 +138,8 @@ static QFont *font(Style::FontSize size, Style::FontSize defaultSize
return &normal;
case Style::Small:
return &small;
case Style::ExtraSmall:
return &extraSmall;
default:
return font(defaultSize);
}
@ -201,25 +205,20 @@ static qreal area(const QVector<QPointF> &polygon)
return area;
}
static QPointF centroid(const QVector<QPointF> polygon)
static QPointF centroid(const QVector<QPointF> &polygon)
{
qreal cx = 0, cy = 0, factor = 0;
qreal A = area(polygon);
qreal cx = 0, cy = 0;
qreal factor = 1.0 / (6.0 * area(polygon));
for (int i = 0; i < polygon.size(); i++) {
int j = (i + 1) % polygon.size();
factor=(polygon.at(i).x() * polygon.at(j).y() - polygon[j].x()
* polygon[i].y());
cx+=(polygon[i].x() + polygon[j].x()) * factor;
cy+=(polygon[i].y() + polygon[j].y()) * factor;
qreal f = (polygon.at(i).x() * polygon.at(j).y() - polygon.at(j).x()
* polygon.at(i).y());
cx += (polygon.at(i).x() + polygon.at(j).x()) * f;
cy += (polygon.at(i).y() + polygon.at(j).y()) * f;
}
A *= 6.0f;
factor = 1/A;
cx *= factor;
cy *= factor;
return QPointF(cx, cy);
return QPointF(cx * factor, cy * factor);
}
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)));
}
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()) {
_errorString = _img.errorString();
if (GMAP::isGMAP(fileName))
_data = new GMAP(fileName);
else
_data = new IMG(fileName);
if (!_data->isValid()) {
_errorString = _data->errorString();
return;
}
_zoom = zooms.min();
_zoom = _data->zooms().min();
updateTransform();
_valid = true;
@ -247,17 +252,17 @@ IMGMap::IMGMap(const QString &fileName, QObject *parent)
void IMGMap::load()
{
_img.load();
_data->load();
}
void IMGMap::unload()
{
_img.clear();
_data->clear();
}
QRectF IMGMap::bounds()
{
RectD prect(_img.bounds(), _projection);
RectD prect(_data->bounds(), _projection);
return QRectF(_transform.proj2img(prect.topLeft()),
_transform.proj2img(prect.bottomRight()));
}
@ -267,8 +272,8 @@ int IMGMap::zoomFit(const QSize &size, const RectC &rect)
if (rect.isValid()) {
RectD pr(rect, _projection, 10);
_zoom = zooms.min();
for (int i = zooms.min() + 1; i <= zooms.max(); i++) {
_zoom = _data->zooms().min();
for (int i = _data->zooms().min() + 1; i <= _data->zooms().max(); i++) {
Transform t(transform(i));
QRectF r(t.proj2img(pr.topLeft()), t.proj2img(pr.bottomRight()));
if (size.width() < r.width() || size.height() < r.height())
@ -276,7 +281,7 @@ int IMGMap::zoomFit(const QSize &size, const RectC &rect)
_zoom = i;
}
} else
_zoom = zooms.max();
_zoom = _data->zooms().max();
updateTransform();
@ -285,14 +290,14 @@ int IMGMap::zoomFit(const QSize &size, const RectC &rect)
int IMGMap::zoomIn()
{
_zoom = qMin(_zoom + 1, zooms.max());
_zoom = qMin(_zoom + 1, _data->zooms().max());
updateTransform();
return _zoom;
}
int IMGMap::zoomOut()
{
_zoom = qMax(_zoom - 1, zooms.min());
_zoom = qMax(_zoom - 1, _data->zooms().min());
updateTransform();
return _zoom;
}
@ -307,7 +312,7 @@ Transform IMGMap::transform(int zoom) const
{
double scale = _projection.isGeographic()
? 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),
PointD(scale, scale));
}
@ -327,15 +332,14 @@ Coordinates IMGMap::xy2ll(const QPointF &p)
return _projection.xy2ll(_transform.img2proj(p));
}
void IMGMap::drawPolygons(QPainter *painter, const QList<IMG::Poly> &polygons)
void IMGMap::drawPolygons(QPainter *painter, const QList<MapData::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++) {
const IMG::Poly &poly = polygons.at(i);
if (poly.type != _img.style()->drawOrder().at(n))
const MapData::Poly &poly = polygons.at(i);
if (poly.type != _data->style()->drawOrder().at(n))
continue;
const Style::Polygon &style = _img.style()->polygon(poly.type);
const Style::Polygon &style = _data->style()->polygon(poly.type);
painter->setPen(style.pen());
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);
for (int i = 0; i < lines.size(); i++) {
const IMG::Poly &poly = lines.at(i);
const Style::Line &style = _img.style()->line(poly.type);
const MapData::Poly &poly = lines.at(i);
const Style::Line &style = _data->style()->line(poly.type);
if (style.background() == Qt::NoPen)
continue;
@ -360,8 +364,8 @@ void IMGMap::drawLines(QPainter *painter, const QList<IMG::Poly> &lines)
}
for (int i = 0; i < lines.size(); i++) {
const IMG::Poly &poly = lines.at(i);
const Style::Line &style = _img.style()->line(poly.type);
const MapData::Poly &poly = lines.at(i);
const Style::Line &style = _data->style()->line(poly.type);
if (!style.img().isNull())
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);
}
void IMGMap::processPolygons(QList<IMG::Poly> &polygons,
void IMGMap::processPolygons(QList<MapData::Poly> &polygons,
QList<TextItem*> &textItems)
{
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++) {
QPointF &p = poly.points[j];
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)
|| Style::isMilitaryArea(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(
centroid(poly.points).toPoint(), &poly.label.text(),
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)
{
qStableSort(lines);
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++) {
QPointF &p = poly.points[j];
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);
}
void IMGMap::processStreetNames(QList<IMG::Poly> &lines, const QRect &tileRect,
QList<TextItem*> &textItems)
void IMGMap::processStreetNames(QList<MapData::Poly> &lines,
const QRect &tileRect, QList<TextItem*> &textItems)
{
for (int i = 0; i < lines.size(); i++) {
IMG::Poly &poly = lines[i];
const Style::Line &style = _img.style()->line(poly.type);
MapData::Poly &poly = lines[i];
const Style::Line &style = _data->style()->line(poly.type);
if (style.img().isNull() && style.foreground() == Qt::NoPen)
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)
{
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;
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();
if (!shield.isValid() || shield.type() != 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)
{
qSort(points);
for (int i = 0; i < points.size(); i++) {
IMG::Point &point = points[i];
const Style::Point &style = _img.style()->point(point.type);
MapData::Point &point = points[i];
const Style::Point &style = _data->style()->point(point.type);
if (point.poi && _zoom < minPOIZoom(Style::poiClass(point.type)))
continue;
@ -580,7 +583,7 @@ void IMGMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
for (int j = 0; j < height; j++) {
QPixmap pm;
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());
if (QPixmapCache::find(key, 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));
RasterTile &tile = tiles.last();
RectD polyRect(_transform.img2proj(ttl), _transform.img2proj(
QPointF(ttl.x() + TILE_SIZE, ttl.y() + TILE_SIZE)));
_img.objects(polyRect.toRectC(_projection, 4), _zoom,
&(tile.polygons()), &(tile.lines()), 0);
RectD pointRect(_transform.img2proj(QPointF(ttl.x() - TEXT_EXTENT,
ttl.y() - TEXT_EXTENT)), _transform.img2proj(QPointF(ttl.x()
+ TILE_SIZE + TEXT_EXTENT, ttl.y() + TILE_SIZE + TEXT_EXTENT)));
_img.objects(pointRect.toRectC(_projection, 4), _zoom,
0, 0, &(tile.points()));
QRectF polyRect(ttl, QPointF(ttl.x() + TILE_SIZE,
ttl.y() + TILE_SIZE));
polyRect &= bounds().adjusted(0.5, 0.5, -0.5, -0.5);
RectD polyRectD(_transform.img2proj(polyRect.topLeft()),
_transform.img2proj(polyRect.bottomRight()));
_data->polys(polyRectD.toRectC(_projection, 4), _zoom,
&(tile.polygons()), &(tile.lines()));
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 "projection.h"
#include "transform.h"
#include "IMG/img.h"
#include "IMG/mapdata.h"
class TextItem;
@ -14,8 +14,9 @@ class IMGMap : public Map
public:
IMGMap(const QString &fileName, QObject *parent = 0);
~IMGMap() {delete _data;}
QString name() const {return _img.name();}
QString name() const {return _data->name();}
QRectF bounds();
@ -43,21 +44,21 @@ private:
Transform transform(int zoom) const;
void updateTransform();
void drawPolygons(QPainter *painter, const QList<IMG::Poly> &polygons);
void drawLines(QPainter *painter, const QList<IMG::Poly> &lines);
void drawPolygons(QPainter *painter, const QList<MapData::Poly> &polygons);
void drawLines(QPainter *painter, const QList<MapData::Poly> &lines);
void drawTextItems(QPainter *painter, const QList<TextItem*> &textItems);
void processPolygons(QList<IMG::Poly> &polygons,
void processPolygons(QList<MapData::Poly> &polygons,
QList<TextItem *> &textItems);
void processLines(QList<IMG::Poly> &lines, const QRect &tileRect,
void processLines(QList<MapData::Poly> &lines, const QRect &tileRect,
QList<TextItem*> &textItems);
void processPoints(QList<IMG::Point> &points, QList<TextItem*> &textItems);
void processShields(QList<IMG::Poly> &lines, const QRect &tileRect,
void processPoints(QList<MapData::Point> &points, QList<TextItem*> &textItems);
void processShields(QList<MapData::Poly> &lines, const QRect &tileRect,
QList<TextItem*> &textItems);
void processStreetNames(QList<IMG::Poly> &lines, const QRect &tileRect,
void processStreetNames(QList<MapData::Poly> &lines, const QRect &tileRect,
QList<TextItem*> &textItems);
IMG _img;
MapData *_data;
int _zoom;
Projection _projection;
Transform _transform;

View File

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

View File

@ -13,23 +13,24 @@ class MapList : public QObject
public:
MapList(QObject *parent = 0) : QObject(parent) {}
bool loadFile(const QString &path);
bool loadFile(const QString &path, bool *terminate = 0);
bool loadDir(const QString &path);
const QList<Map*> &maps() const {return _maps;}
const QString &errorString() const {return _errorString;}
const QString &errorPath() const {return _errorPath;}
static QString formats();
static QStringList filter();
private:
bool loadFile(const QString &path, bool *atlas, bool dir);
bool loadDirR(const QString &path);
Map *loadSource(const QString &path, bool dir);
bool loadMap(Map *map, const QString &path, bool dir);
Map *loadSource(const QString &path);
bool loadMap(Map *map, const QString &path);
QList<Map*> _maps;
QString _errorString;
QString _errorPath;
};
#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)
{
Config config;
@ -286,7 +300,7 @@ Map *MapSource::loadMap(const QString &path, QString &errorString)
case WMS:
return new WMSMap(config.name, WMS::Setup(config.url, config.layer,
config.style, config.format, config.crs, config.coordinateSystem,
config.dimensions, config.authorization));
config.dimensions, config.authorization), config.tileSize);
case TMS:
return new OnlineMap(config.name, config.url, config.zooms,
config.bounds, config.tileRatio, config.authorization,

View File

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

View File

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

View File

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

View File

@ -1,3 +1,4 @@
#include <cmath>
#include <QFileInfo>
#include <QEventLoop>
#include <QXmlStreamReader>
@ -7,6 +8,19 @@
#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)
{
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)
{
while (reader.readNextStartElement()) {
if (reader.name() == "Format") {
if (reader.readElementText() == ctx.setup.format())
QString format(reader.readElementText());
if (bareFormat(format) == bareFormat(ctx.setup.format()))
ctx.formatSupported = true;
} else
} else if (reader.name() == "DCPType")
dcpType(reader, ctx);
else
reader.skipCurrentElement();
}
}
@ -97,7 +146,16 @@ void WMS::layer(QXmlStreamReader &reader, CTX &ctx,
CRSs.append(reader.readElementText());
else if (reader.name() == "Style")
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();
if (sd > 0)
scaleDenominator.setMin(sd);
@ -248,6 +306,8 @@ bool WMS::parseCapabilities(const QString &path, const Setup &setup)
return false;
}
_tileUrl = ctx.url.isEmpty() ? setup.url() : ctx.url;
return true;
}

View File

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

View File

@ -10,7 +10,6 @@
#define CAPABILITIES_FILE "capabilities.xml"
#define TILE_SIZE 256
#define EPSILON 1e-6
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);
}
QString WMSMap::tileUrl(const QString &version) const
QString WMSMap::tileUrl(const QString &baseUrl, const QString &version) const
{
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")
.arg(_setup.url(), _setup.url().contains('?') ? "&" : "?", version,
QString::number(TILE_SIZE), QString::number(TILE_SIZE), _setup.layer(),
.arg(baseUrl, baseUrl.contains('?') ? "&" : "?", version,
QString::number(_tileSize), QString::number(_tileSize), _setup.layer(),
_setup.style(), _setup.format());
if (version >= "1.3.0")
@ -84,7 +83,7 @@ bool WMSMap::loadWMS()
_projection = wms.projection();
_bbox = wms.boundingBox();
_bounds = RectD(_bbox, _projection);
_tileLoader->setUrl(tileUrl(wms.version()));
_tileLoader->setUrl(tileUrl(wms.tileUrl(), wms.version()));
if (wms.version() >= "1.3.0") {
if (_setup.coordinateSystem().axisOrder() == CoordinateSystem::Unknown)
@ -100,9 +99,9 @@ bool WMSMap::loadWMS()
return true;
}
WMSMap::WMSMap(const QString &name, const WMS::Setup &setup, QObject *parent)
: Map(parent), _name(name), _setup(setup), _tileLoader(0), _zoom(0),
_mapRatio(1.0), _valid(false)
WMSMap::WMSMap(const QString &name, const WMS::Setup &setup, int tileSize,
QObject *parent) : Map(parent), _name(name), _setup(setup), _tileLoader(0),
_zoom(0), _tileSize(tileSize), _mapRatio(1.0), _valid(false)
{
_tileLoader = new TileLoader(tilesDir(), this);
_tileLoader->setAuthorization(_setup.authorization());
@ -180,7 +179,7 @@ Coordinates WMSMap::xy2ll(const QPointF &p)
qreal WMSMap::tileSize() const
{
return (TILE_SIZE / _mapRatio);
return (_tileSize / _mapRatio);
}
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()));
for (int i = tl.x(); i < br.x(); i++) {
for (int j = tl.y(); j < br.y(); j++) {
PointD ttl(_transform.img2proj(QPointF(i * TILE_SIZE,
j * TILE_SIZE)));
PointD tbr(_transform.img2proj(QPointF(i * TILE_SIZE + TILE_SIZE,
j * TILE_SIZE + TILE_SIZE)));
PointD ttl(_transform.img2proj(QPointF(i * _tileSize,
j * _tileSize)));
PointD tbr(_transform.img2proj(QPointF(i * _tileSize + _tileSize,
j * _tileSize + _tileSize)));
RectD bbox = (_cs.axisOrder() == CoordinateSystem::YX)
? RectD(PointD(tbr.y(), tbr.x()), PointD(ttl.y(), ttl.x()))
: RectD(ttl, tbr);

View File

@ -14,7 +14,8 @@ class WMSMap : public Map
Q_OBJECT
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;}
@ -39,7 +40,7 @@ public:
QString errorString() const {return _errorString;}
private:
QString tileUrl(const QString &version) const;
QString tileUrl(const QString &baseUrl, const QString &version) const;
double sd2res(double scaleDenominator) const;
QString tilesDir() const;
void computeZooms(const RangeF &scaleDenominator);
@ -58,6 +59,7 @@ private:
RectC _bbox;
RectD _bounds;
int _zoom;
int _tileSize;
qreal _mapRatio;
bool _valid;

View File

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