1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2025-07-16 20:04:23 +02:00

Compare commits

...

67 Commits
7.37 ... 7.38

Author SHA1 Message Date
84d5673e17 Merge branch 'origin/master' into Weblate. 2020-12-15 21:51:38 +01:00
e40836e6bb Added missing file associations + icons 2020-12-15 21:51:08 +01:00
88aef38f9d Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (383 of 383 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/pt_BR/
2020-12-15 02:29:30 +01:00
7d8dcec88b Try to break even less bounding box transformations 2020-12-14 22:06:59 +01:00
561d8362a9 Fixed projection comparison 2020-12-14 22:04:50 +01:00
7f9fde76e9 Merge branch 'origin/master' into Weblate. 2020-12-13 19:41:17 +01:00
239e571358 Provide propper map bounds for overviews 2020-12-13 19:40:09 +01:00
44b28e3d4d Merge branch 'origin/master' into Weblate. 2020-12-12 10:20:19 +01:00
4cef089c81 A more robust RectC to RectD algorithm 2020-12-12 10:19:48 +01:00
05ac5ccedb Merge branch 'origin/master' into Weblate. 2020-12-10 22:02:22 +01:00
22fb6071f7 Refactoring 2020-12-10 22:02:09 +01:00
2c78772a67 Merge branch 'origin/master' into Weblate. 2020-12-10 01:09:42 +01:00
0f03ef4af7 Yet another map load crash fix 2020-12-10 01:09:23 +01:00
351cc49ec9 Merge branch 'origin/master' into Weblate. 2020-12-09 23:08:07 +01:00
743a937f41 Fixed crashing async map loading
fixes #331
2020-12-09 23:07:05 +01:00
033225502f Merge branch 'origin/master' into Weblate. 2020-12-08 21:30:37 +01:00
75b8b9eab0 Upadte linux file associations 2020-12-08 21:30:17 +01:00
e76e7b71ed Check for duplicit map loads 2020-12-08 21:29:20 +01:00
41ea07d020 Merge branch 'origin/master' into Weblate. 2020-12-08 01:13:05 +01:00
4bad086152 Enable maps drag&drop 2020-12-08 01:12:39 +01:00
8be088be0a Merge branch 'origin/master' into Weblate. 2020-12-08 01:01:57 +01:00
73021bec01 Added "Open with GPXSee" associations 2020-12-08 01:01:26 +01:00
7584116168 Removed cut&paste remains 2020-12-08 00:59:18 +01:00
59b734c402 Cosmetics 2020-12-08 00:58:01 +01:00
8168d52f09 Merge branch 'origin/master' into Weblate. 2020-12-06 23:32:07 +01:00
74796e3e41 Only trigger the last maploaded 2020-12-06 23:31:45 +01:00
676024854a Merge branch 'origin/master' into Weblate. 2020-12-06 19:18:14 +01:00
10e1b5c4fb Open map files passed as program arguments
closes #327
2020-12-06 19:17:09 +01:00
54570ed97e Merge branch 'origin/master' into Weblate. 2020-12-06 13:05:35 +01:00
07fa377e38 Remove the weired file lists copies
It used to be written in the Qt4 documentation to iterate over a copy, but
there is aparently no real reason doing that...
2020-12-06 13:03:32 +01:00
2b8c3f64ac Only trigger the last loaded map 2020-12-06 12:53:39 +01:00
a60cccb57e Merge branch 'origin/master' into Weblate. 2020-12-06 00:12:05 +01:00
c2e50e5213 Use a smooth digital zoom 2020-12-06 00:11:47 +01:00
0ea8e008c2 Merge branch 'origin/master' into Weblate. 2020-12-05 12:26:33 +01:00
082435c83d Translated using Weblate (Hungarian)
Currently translated at 100.0% (383 of 383 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/hu/
2020-12-05 12:26:33 +01:00
e63ad7a244 Make the maps submenus work with large amount of items 2020-12-05 12:25:59 +01:00
32a4365543 Merge branch 'origin/master' into Weblate. 2020-12-04 00:26:20 +01:00
abd1dc2450 Added support for polyconic projections 2020-12-04 00:25:57 +01:00
5674534efd Merge branch 'origin/master' into Weblate. 2020-12-03 21:15:19 +01:00
33287f9d76 Translated using Weblate (Hungarian)
Currently translated at 100.0% (383 of 383 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/hu/
2020-12-03 21:15:18 +01:00
1dfe84c4af Translated using Weblate (Ukrainian)
Currently translated at 98.4% (377 of 383 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/uk/
2020-12-03 21:15:18 +01:00
7fe8d204bc Translated using Weblate (Turkish)
Currently translated at 100.0% (383 of 383 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/tr/
2020-12-03 21:15:18 +01:00
5080247e10 Translated using Weblate (Russian)
Currently translated at 100.0% (383 of 383 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/ru/
2020-12-03 21:15:18 +01:00
13d6c7c643 Translated using Weblate (Finnish)
Currently translated at 100.0% (383 of 383 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/fi/
2020-12-03 21:15:17 +01:00
547d7a5f23 Fix the POI search algorithm
(At least so, that it does not trigger the rtree assert. The whole RectC logic
has to be fixed to properly handle poles/dateline "overflows")
2020-12-03 21:12:41 +01:00
9e03d85b7a Fixed actions logic 2020-12-03 20:58:22 +01:00
b811132394 Translated using Weblate (Swedish)
Currently translated at 100.0% (383 of 383 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/sv/
2020-12-03 06:51:47 +01:00
ca33328d99 Merge branch 'origin/master' into Weblate. 2020-12-03 00:11:58 +01:00
41c8a4d935 Version++ 2020-12-03 00:11:49 +01:00
acd09400be Localization update 2020-12-03 00:10:24 +01:00
16bfd593c7 Merge branch 'origin/master' into Weblate. 2020-12-02 23:58:59 +01:00
9e70a1ffbb Added the "Load map dir" feature 2020-12-02 23:58:11 +01:00
1b590fbf76 Merge branch 'origin/master' into Weblate. 2020-12-02 20:51:37 +01:00
8d52dbf59f Fixed issue with Mercator projections 2020-12-02 20:51:19 +01:00
c6fd32fc61 Merge branch 'origin/master' into Weblate. 2020-12-01 20:17:58 +01:00
af6082425e Propper map size must be known from the start 2020-12-01 20:17:19 +01:00
785123f005 Merge branch 'origin/master' into Weblate. 2020-12-01 19:04:34 +01:00
df3ee11f42 Properly handle skewed charts 2020-12-01 19:03:58 +01:00
6af1ff35ab Merge branch 'origin/master' into Weblate. 2020-11-28 20:34:53 +01:00
8423fc1230 Remove the untested and broken NOS stuff 2020-11-28 20:34:25 +01:00
a62d84da67 Merge branch 'origin/master' into Weblate. 2020-11-28 14:50:31 +01:00
2431f432d4 Use the right Mercator 2020-11-28 14:50:10 +01:00
6c4ebc40ca Merge branch 'origin/master' into Weblate. 2020-11-28 14:48:55 +01:00
0cc6908b30 Fixed broken projection comparsion
+ refactoring/code cleanup
2020-11-28 14:48:20 +01:00
becf57e4eb Merge branch 'origin/master' into Weblate. 2020-11-27 01:12:51 +01:00
96733883cb Added support for BSB charts maps 2020-11-27 01:11:50 +01:00
973c086029 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (376 of 376 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/pt_BR/
2020-11-25 17:29:14 +01:00
98 changed files with 6381 additions and 3558 deletions

View File

@ -1,4 +1,4 @@
version: 7.37.{build}
version: 7.38.{build}
configuration:
- Release

View File

@ -3,7 +3,7 @@ unix:!macx {
} else {
TARGET = GPXSee
}
VERSION = 7.37
VERSION = 7.38
QT += core \
gui \
@ -22,7 +22,9 @@ HEADERS += src/common/config.h \
src/GUI/axislabelitem.h \
src/GUI/graphicsscene.h \
src/GUI/mapaction.h \
src/GUI/mapitem.h \
src/GUI/marginswidget.h \
src/GUI/planeitem.h \
src/GUI/popup.h \
src/common/garmin.h \
src/common/staticassert.h \
@ -103,6 +105,9 @@ HEADERS += src/common/config.h \
src/map/IMG/rastertile.h \
src/map/IMG/textpathitem.h \
src/map/IMG/textpointitem.h \
src/map/bsbmap.h \
src/map/invalidmap.h \
src/map/polyconic.h \
src/map/projection.h \
src/map/ellipsoid.h \
src/map/datum.h \
@ -206,6 +211,7 @@ HEADERS += src/common/config.h \
src/GUI/pngexportdialog.h
SOURCES += src/main.cpp \
src/GUI/axislabelitem.cpp \
src/GUI/mapitem.cpp \
src/GUI/marginswidget.cpp \
src/GUI/popup.cpp \
src/common/coordinates.cpp \
@ -271,11 +277,13 @@ SOURCES += src/main.cpp \
src/map/IMG/rastertile.cpp \
src/map/IMG/textpathitem.cpp \
src/map/IMG/textpointitem.cpp \
src/map/bsbmap.cpp \
src/map/maplist.cpp \
src/map/onlinemap.cpp \
src/map/downloader.cpp \
src/map/emptymap.cpp \
src/map/ozimap.cpp \
src/map/polyconic.cpp \
src/map/tar.cpp \
src/map/atlas.cpp \
src/map/ozf.cpp \
@ -425,7 +433,13 @@ macx {
icons/formats/json.icns \
icons/formats/cup.icns \
icons/formats/gpi.icns \
icons/formats/sml.icns
icons/formats/sml.icns \
icons/formats/img.icns \
icons/formats/jnx.icns \
icons/formats/kap.icns \
icons/formats/mbts.icns \
icons/formats/rmap.icns \
icons/formats/tba.icns
QMAKE_BUNDLE_DATA += locale maps icons csv
}
@ -445,7 +459,14 @@ win32 {
icons/formats/json.ico \
icons/formats/cup.ico \
icons/formats/gpi.ico \
icons/formats/sml.ico
icons/formats/sml.ico \
icons/formats/img.ico \
icons/formats/jnx.ico \
icons/formats/kap.ico \
icons/formats/map.ico \
icons/formats/mbts.ico \
icons/formats/rmap.ico \
icons/formats/tba.ico
DEFINES += _USE_MATH_DEFINES \
NOGDI
}

BIN
icons/formats/img.icns Normal file

Binary file not shown.

BIN
icons/formats/img.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 KiB

BIN
icons/formats/jnx.icns Normal file

Binary file not shown.

BIN
icons/formats/jnx.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 KiB

BIN
icons/formats/kap.icns Normal file

Binary file not shown.

BIN
icons/formats/kap.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 KiB

BIN
icons/formats/map.icns Normal file

Binary file not shown.

BIN
icons/formats/map.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 303 KiB

BIN
icons/formats/mbts.icns Normal file

Binary file not shown.

BIN
icons/formats/mbts.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 KiB

BIN
icons/formats/rmap.icns Normal file

Binary file not shown.

BIN
icons/formats/rmap.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 KiB

View File

@ -13,3 +13,10 @@ slf:#881199
cup:#20a810
gpi:#fca314
sml:#6434eb
img:#cf0a0a
jnx:#aeff00
kap:#080045
map:#f6ff00
mbts:#ff0062
rmap:#145cba
tba:#367050

BIN
icons/formats/tba.icns Normal file

Binary file not shown.

BIN
icons/formats/tba.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -42,7 +42,7 @@
</array>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>application/tcx+xml</string>
<string>application/vnd.garmin.tcx+xml</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>icons/tcx.icns</string>
@ -74,7 +74,7 @@
</array>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>application/loc+xml</string>
<string>application/vnd.groundspeak.loc+xml</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>icons/loc.icns</string>
@ -90,7 +90,7 @@
</array>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>application/slf+xml</string>
<string>application/vnd.sigma.slf+xml</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>icons/slf.icns</string>
@ -250,7 +250,7 @@
</array>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>application/sml+xml</string>
<string>application/vnd.suunto.sml+xml</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>icons/sml.icns</string>
@ -259,6 +259,193 @@
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>jpeg</string>
<string>jpg</string>
</array>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>image/jpeg</string>
</array>
<key>CFBundleTypeName</key>
<string>JPEG Image</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>csv</string>
</array>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>text/csv</string>
</array>
<key>CFBundleTypeName</key>
<string>Comma-Separated Values (CSV) Files</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>img</string>
</array>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>application/vnd.garmin.img</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>icons/img.icns</string>
<key>CFBundleTypeName</key>
<string>Garmin IMG Map</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>gmap</string>
<string>gmapi</string>
</array>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>application/vnd.garmin.gmap</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>icons/img.icns</string>
<key>CFBundleTypeName</key>
<string>Garmin Map Product File</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>jnx</string>
</array>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>application/vnd.garmin.jnx</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>icons/jnx.icns</string>
<key>CFBundleTypeName</key>
<string>Garmin JNX Map</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>kap</string>
</array>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>application/vnd.maptech.kap</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>icons/kap.icns</string>
<key>CFBundleTypeName</key>
<string>BSB Nautical Charts</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>map</string>
</array>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>application/vnd.oziexplorer.map</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>icons/map.icns</string>
<key>CFBundleTypeName</key>
<string>OziExplorer Map File</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>rmap</string>
<string>rtmap</string>
</array>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>application/vnd.twonav.rmap</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>icons/rmap.icns</string>
<key>CFBundleTypeName</key>
<string>TwoNav Raster Map File</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>tba</string>
</array>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>application/vnd.trekbuddy.tba</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>icons/tba.icns</string>
<key>CFBundleTypeName</key>
<string>TrekBuddy Atlas</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>mbtiles</string>
</array>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>application/vnd.mapbox.mbtiles</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>icons/mbts.icns</string>
<key>CFBundleTypeName</key>
<string>MBTiles Map File</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>tiff</string>
</array>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>image/tiff</string>
</array>
<key>CFBundleTypeName</key>
<string>GeoTIFF Image</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>xml</string>
</array>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>application/vnd.gpxsee.map+xml</string>
</array>
<key>CFBundleTypeName</key>
<string>GPXSee Map Definition File</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
</array>
<key>UTImportedTypeDeclarations</key>
@ -302,7 +489,7 @@
<string>tcx</string>
</array>
<key>public.mime-type</key>
<string>application/tcx+xml</string>
<string>application/vnd.garmin.tcx+xml</string>
</dict>
</dict>
<dict>
@ -344,7 +531,7 @@
<string>loc</string>
</array>
<key>public.mime-type</key>
<string>application/loc+xml</string>
<string>application/vnd.groundspeak.loc+xml</string>
</dict>
</dict>
<dict>
@ -365,7 +552,7 @@
<string>slf</string>
</array>
<key>public.mime-type</key>
<string>application/slf+xml</string>
<string>application/vnd.sigma.slf+xml</string>
</dict>
</dict>
<dict>
@ -575,7 +762,269 @@
<string>sml</string>
</array>
<key>public.mime-type</key>
<string>application/sml+xml</string>
<string>application/vnd.suunto.sml+xml</string>
</dict>
</dict>
<dict>
<key>UTTypeIdentifier</key>
<string>public.jpeg</string>
<key>UTTypeReferenceURL</key>
<string>http://www.w3.org/Graphics/JPEG/</string>
<key>UTTypeDescription</key>
<string>JPEG Image</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.image</string>
<string>public.data</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>jpeg</string>
<string>jpg</string>
</array>
<key>public.mime-type</key>
<string>image/jpeg</string>
</dict>
</dict>
<dict>
<key>UTTypeIdentifier</key>
<string>public.csv</string>
<key>UTTypeReferenceURL</key>
<string>https://tools.ietf.org/html/rfc4180</string>
<key>UTTypeDescription</key>
<string>Comma-Separated Values (CSV) Files</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>csv</string>
</array>
<key>public.mime-type</key>
<string>text/csv</string>
</dict>
</dict>
<dict>
<key>UTTypeIdentifier</key>
<string>com.garmin.img</string>
<key>UTTypeReferenceURL</key>
<string>https://sourceforge.net/projects/garmin-img/</string>
<key>UTTypeDescription</key>
<string>Garmin IMG map</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>img</string>
</array>
<key>public.mime-type</key>
<string>application/vnd.garmin.img</string>
</dict>
</dict>
<dict>
<key>UTTypeIdentifier</key>
<string>com.garmin.jnx</string>
<key>UTTypeReferenceURL</key>
<string>http://whiter.brinkster.net/en/JNX.shtml</string>
<key>UTTypeDescription</key>
<string>Garmin JNX Map</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>jnx</string>
</array>
<key>public.mime-type</key>
<string>application/vnd.garmin.jnx</string>
</dict>
</dict>
<dict>
<key>UTTypeIdentifier</key>
<string>com.garmin.gmap</string>
<key>UTTypeReferenceURL</key>
<string>https://sourceforge.net/projects/garmin-img/</string>
<key>UTTypeDescription</key>
<string>Garmin Map Product File</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.xml</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>xml</string>
</array>
<key>public.mime-type</key>
<string>application/vnd.garmin.gmap</string>
</dict>
</dict>
<dict>
<key>UTTypeIdentifier</key>
<string>com.maptech.kap</string>
<key>UTTypeReferenceURL</key>
<string>http://libbsb.sourceforge.net/bsb_file_format.html</string>
<key>UTTypeDescription</key>
<string>BSB Nautical Charts</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.image</string>
<string>public.data</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>kap</string>
</array>
<key>public.mime-type</key>
<string>image/vnd.maptech.kap</string>
</dict>
</dict>
<dict>
<key>UTTypeIdentifier</key>
<string>com.oziexplorer3.map</string>
<key>UTTypeReferenceURL</key>
<string>https://www.oziexplorer3.com/eng/help/map_file_format.html</string>
<key>UTTypeDescription</key>
<string>OziExplorer Map File</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>map</string>
</array>
<key>public.mime-type</key>
<string>application/vnd.oziexplorer.map</string>
</dict>
</dict>
<dict>
<key>UTTypeIdentifier</key>
<string>com.mapbox.mbtiles</string>
<key>UTTypeReferenceURL</key>
<string>https://github.com/mapbox/mbtiles-spec</string>
<key>UTTypeDescription</key>
<string>MBTiles Map File</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>mbtiles</string>
</array>
<key>public.mime-type</key>
<string>application/vnd.mapbox.mbtiles</string>
</dict>
</dict>
<dict>
<key>UTTypeIdentifier</key>
<string>com.twonav.rmap</string>
<key>UTTypeReferenceURL</key>
<string>https://wiki.openstreetmap.org/wiki/TwoNav_RMAP</string>
<key>UTTypeDescription</key>
<string>TwoNav Raster Map File</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>rmap</string>
<string>rtmap</string>
</array>
<key>public.mime-type</key>
<string>application/vnd.twonav.rmap</string>
</dict>
</dict>
<dict>
<key>UTTypeIdentifier</key>
<string>net.trekbuddy.tba</string>
<key>UTTypeReferenceURL</key>
<string>https://github.com/kruhc/trekbuddy</string>
<key>UTTypeDescription</key>
<string>TrekBuddy Atlas</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>tba</string>
</array>
<key>public.mime-type</key>
<string>application/vnd.trekbuddy.tba</string>
</dict>
</dict>
<dict>
<key>UTTypeIdentifier</key>
<string>public.tiff</string>
<key>UTTypeReferenceURL</key>
<string>https://www.adobe.io/open/standards/TIFF.html</string>
<key>UTTypeDescription</key>
<string>TIFF Image</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.image</string>
<string>public.data</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>tiff</string>
<string>tif</string>
</array>
<key>public.mime-type</key>
<string>image/tiff</string>
</dict>
</dict>
</array>
<key>UTExportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeIdentifier</key>
<string>org.gpxsee.map</string>
<key>UTTypeReferenceURL</key>
<string>http://www.gpxsee.org/map/1.4/</string>
<key>UTTypeDescription</key>
<string>GPXSee Map Definition File</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.xml</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>xml</string>
</array>
<key>public.mime-type</key>
<string>application/vnd.gpxsee.map+xml</string>
</dict>
</dict>
</array>

View File

@ -18,13 +18,14 @@
<li>User-definable online maps (OpenStreetMap/Google tiles, WMTS,
WMS, TMS, QuadTiles).</li>
<li>Offline maps (MBTiles, OziExplorer maps, TrekBuddy maps/atlases,
TwoNav RMaps, Garmin IMG &amp; JNX, GeoTIFF images).</li>
TwoNav RMaps, Garmin IMG &amp; JNX maps, GeoTIFF images,
BSB nautical charts).</li>
<li>Elevation, speed, heart rate, cadence, power, temperature and
gear ratio graphs.</li>
<li>Support for multiple tracks in one view.</li>
<li>Support for POI files.</li>
<li>Support for DEM files (SRTM HGT).</li>
<li>Print/export to PDF.</li>
<li>Print/export to PDF &amp; PNG.</li>
<li>Full-screen mode.</li>
<li>HiDPI/Retina displays &amp; maps support.</li>
</ul>
@ -58,7 +59,7 @@
<mimetypes>
<mimetype>application/gpx+xml</mimetype>
<mimetype>application/tcx+xml</mimetype>
<mimetype>application/vnd.garmin.tcx+xml</mimetype>
<mimetype>application/vnd.ant.fit</mimetype>
<mimetype>application/vnd.google-earth.kml+xml</mimetype>
<mimetype>application/vnd.fai.igc</mimetype>
@ -66,11 +67,24 @@
<mimetype>application/vnd.oziexplorer.plt</mimetype>
<mimetype>application/vnd.oziexplorer.rte</mimetype>
<mimetype>application/vnd.oziexplorer.wpt</mimetype>
<mimetype>application/loc+xml</mimetype>
<mimetype>application/slf+xml</mimetype>
<mimetype>application/vnd.groundspeak.loc+xml</mimetype>
<mimetype>application/vnd.sigma.slf+xml</mimetype>
<mimetype>application/geo+json</mimetype>
<mimetype>application/vnd.naviter.seeyou.cup</mimetype>
<mimetype>application/vnd.garmin.gpi</mimetype>
<mimetype>application/sml+xml</mimetype>
<mimetype>application/vnd.suunto.sml+xml</mimetype>
<mimetype>image/jpeg</mimetype>
<mimetype>text/csv</mimetype>
<mimetype>application/vnd.garmin.img</mimetype>
<mimetype>application/vnd.garmin.jnx</mimetype>
<mimetype>application/vnd.garmin.gmap+xml</mimetype>
<mimetype>image/vnd.maptech.kap</mimetype>
<mimetype>application/vnd.oziexplorer.map</mimetype>
<mimetype>application/vnd.mapbox.mbtiles</mimetype>
<mimetype>application/vnd.twonav.rmap</mimetype>
<mimetype>application/vnd.trekbuddy.tba</mimetype>
<mimetype>application/vnd.gpxsee.map+xml</mimetype>
<mimetype>application/x-tar</mimetype>
<mimetype>image/tiff</mimetype>
</mimetypes>
</component>

View File

@ -1887,6 +1887,7 @@ CI1971 / Chatham Islands Map Grid,5518,4672,5517,9001,9807,4500,8801,-44,9110,88
CI1979 / Chatham Islands Map Grid,5519,4673,5517,9001,9807,4500,8801,-44,9110,8802,-176.3,9110,8805,1,9201,8806,350000,9001,8807,650000,9001,,,,,,
DHDN / 3-degree Gauss-Kruger zone 1,5520,4314,16261,9001,9807,4530,8801,0,9102,8802,3,9102,8805,1,9201,8806,1500000,9001,8807,0,9001,,,,,,
WGS 84 / Gabon TM 2011,5523,4326,5522,9001,9807,4499,8801,0,9102,8802,11.3,9110,8805,0.9996,9201,8806,1500000,9001,8807,5500000,9001,,,,,,
SAD69(96) / Brazil Polyconic,5530,5527,19941,9001,9818,4499,8801,0,9102,8802,-54,9102,8806,5000000,9001,8807,10000000,9001,,,,,,,,,
SAD69(96) / UTM zone 21S,5531,5527,16121,9001,9807,4400,8801,0,9102,8802,-57,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
SAD69(96) / UTM zone 22S,5532,4618,16122,9001,9807,4400,8801,0,9102,8802,-51,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
SAD69(96) / UTM zone 23S,5533,5527,16123,9001,9807,4400,8801,0,9102,8802,-45,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
@ -1970,6 +1971,7 @@ SAD69(96) / UTM zone 18S,5875,5527,16118,9001,9807,4400,8801,0,9102,8802,-75,910
SAD69(96) / UTM zone 19S,5876,5527,16119,9001,9807,4400,8801,0,9102,8802,-69,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
SAD69(96) / UTM zone 20S,5877,5527,16120,9001,9807,4400,8801,0,9102,8802,-63,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
Cadastre 1997 / UTM zone 38S,5879,4475,16138,9001,9807,4400,8801,0,9102,8802,45,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
SIRGAS 2000 / Brazil Polyconic,5880,4674,19941,9001,9818,4499,8801,0,9102,8802,-54,9102,8806,5000000,9001,8807,10000000,9001,,,,,,,,,
WGS 84 / EPSG Arctic Regional zone A1,5921,4326,5906,9001,9802,4400,8821,81.19020136,9110,8822,-111,9102,8823,85,9102,8824,77,9102,8826,0,9001,8827,0,9001,,,
WGS 84 / EPSG Arctic Regional zone A2,5922,4326,5907,9001,9802,4400,8821,81.19020136,9110,8822,-39,9102,8823,85,9102,8824,77,9102,8826,0,9001,8827,0,9001,,,
WGS 84 / EPSG Arctic Regional zone A3,5923,4326,5908,9001,9802,4400,8821,81.19020136,9110,8822,33,9102,8823,85,9102,8824,77,9102,8826,0,9001,8827,0,9001,,,
@ -3046,6 +3048,8 @@ Pulkovo 1942 / Gauss-Kruger 32N,28492,4284,16332,9001,9807,4530,8801,0,9102,8802
Qatar 1974 / Qatar National Grid,28600,4285,19919,9001,9807,4400,8801,24.27,9110,8802,51.13,9110,8805,0.99999,9201,8806,200000,9001,8807,300000,9001,,,,,,
Amersfoort / RD Old,28991,4289,19913,9001,9809,4499,8801,52.0922178,9110,8802,5.23155,9110,8805,0.9999079,9201,8806,0,9001,8807,0,9001,,,,,,
Amersfoort / RD New,28992,4289,19914,9001,9809,4499,8801,52.0922178,9110,8802,5.23155,9110,8805,0.9999079,9201,8806,155000,9001,8807,463000,9001,,,,,,
SAD69 / Brazil Polyconic,29100,4291,19941,9001,9818,4499,8801,0,9102,8802,-54,9102,8806,5000000,9001,8807,10000000,9001,,,,,,,,,
SAD69 / Brazil Polyconic,29101,4618,19941,9001,9818,4499,8801,0,9102,8802,-54,9102,8806,5000000,9001,8807,10000000,9001,,,,,,,,,
SAD69 / UTM zone 18N,29118,4291,16018,9001,9807,4400,8801,0,9102,8802,-75,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
SAD69 / UTM zone 19N,29119,4291,16019,9001,9807,4400,8801,0,9102,8802,-69,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
SAD69 / UTM zone 20N,29120,4291,16020,9001,9807,4400,8801,0,9102,8802,-63,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,

Can't render this file because it is too large.

View File

@ -15,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;application/sml+xml;
MimeType=application/gpx+xml;application/vnd.garmin.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/vnd.groundspeak.loc+xml;application/vnd.sigma.slf+xml;application/geo+json;application/vnd.naviter.seeyou.cup;application/vnd.garmin.gpi;application/vnd.suunto.sml+xml;image/jpeg;text/csv;application/vnd.garmin.img;application/vnd.garmin.jnx;application/vnd.garmin.gmap+xml;image/vnd.maptech.kap;application/vnd.oziexplorer.map;application/vnd.mapbox.mbtiles;application/vnd.twonav.rmap;application/vnd.trekbuddy.tba;application/vnd.gpxsee.map+xml;application/x-tar;image/tiff;

View File

@ -7,7 +7,7 @@
; The name of the installer
Name "GPXSee"
; Program version
!define VERSION "7.37"
!define VERSION "7.38"
; The file to write
OutFile "GPXSee-${VERSION}.exe"
@ -109,14 +109,14 @@ Section "GPXSee" SEC_APP
; Associate file formats
DetailPrint "Associating file types..."
!insertmacro FILE_ASSOCIATION_ADD "gpx" "GPS Exchange Format" 8
!insertmacro FILE_ASSOCIATION_ADD "tcx" "Training Center XML" 9
!insertmacro FILE_ASSOCIATION_ADD "kml" "Keyhole Markup Language" 10
!insertmacro FILE_ASSOCIATION_ADD "fit" "Flexible and Interoperable Data Transfer" 11
!insertmacro FILE_ASSOCIATION_ADD "igc" "Flight Recorder Data Format" 12
!insertmacro FILE_ASSOCIATION_ADD "nmea" "NMEA 0183 Data" 13
!insertmacro FILE_ASSOCIATION_ADD "plt" "OziExplorer Track Point File" 14
!insertmacro FILE_ASSOCIATION_ADD "rte" "OziExplorer Route File" 15
!insertmacro FILE_ASSOCIATION_ADD "gpx" "GPS Exchange Format" 11
!insertmacro FILE_ASSOCIATION_ADD "tcx" "Training Center XML" 16
!insertmacro FILE_ASSOCIATION_ADD "kml" "Keyhole Markup Language" 17
!insertmacro FILE_ASSOCIATION_ADD "fit" "Flexible and Interoperable Data Transfer" 18
!insertmacro FILE_ASSOCIATION_ADD "igc" "Flight Recorder Data Format" 19
!insertmacro FILE_ASSOCIATION_ADD "nmea" "NMEA 0183 Data" 20
!insertmacro FILE_ASSOCIATION_ADD "plt" "OziExplorer Track Point File" 21
!insertmacro FILE_ASSOCIATION_ADD "rte" "OziExplorer Route File" 22
!insertmacro FILE_ASSOCIATION_ADD "wpt" "OziExplorer Waypoint File" 1
!insertmacro FILE_ASSOCIATION_ADD "loc" "Geocaching.com Waypoint File" 2
!insertmacro FILE_ASSOCIATION_ADD "slf" "Sigma Log File" 3
@ -124,6 +124,47 @@ Section "GPXSee" SEC_APP
!insertmacro FILE_ASSOCIATION_ADD "cup" "SeeYou CUP File" 5
!insertmacro FILE_ASSOCIATION_ADD "gpi" "Garmin POI File" 6
!insertmacro FILE_ASSOCIATION_ADD "sml" "Suunto Markup Language" 7
!insertmacro FILE_ASSOCIATION_ADD "img" "Garmin IMG Map" 8
!insertmacro FILE_ASSOCIATION_ADD "jnx" "Garmin JNX Map" 9
!insertmacro FILE_ASSOCIATION_ADD "kap" "BSB Nautical Chart" 10
!insertmacro FILE_ASSOCIATION_ADD "map" "OziExplorer Map File" 12
!insertmacro FILE_ASSOCIATION_ADD "mbtiles" "MBTiles Map File" 13
!insertmacro FILE_ASSOCIATION_ADD "rmap" "TwoNav Raster Map File" 14
!insertmacro FILE_ASSOCIATION_ADD "tba" "TrekBuddy Atlas" 15
WriteRegStr HKCR "Applications\GPXSee.exe\shell\open\command" "" "$\"$INSTDIR\GPXSee.exe$\" $\"%1$\""
WriteRegStr HKCR ".gpx\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".tcx\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".kml\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".fit\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".igc\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".nmea\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".plt\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".rte\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".wpt\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".loc\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".slf\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".geojson\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".cup\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".gpi\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".sml\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".csv\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".json\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".jpg\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".jpeg\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".img\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".jnx\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".kap\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".map\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".mbtiles\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".rmap\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".rtmap\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".tar\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".tba\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".tif\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".tiff\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".xml\OpenWithList" "GPXSee.exe" ""
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
SectionEnd
@ -210,7 +251,7 @@ Section "Uninstall"
Delete "$SMPROGRAMS\$StartMenuFolder\*.*"
RMDir "$SMPROGRAMS\$StartMenuFolder"
; Remove GPX file association
; Remove file associations
!insertmacro FILE_ASSOCIATION_REMOVE "gpx"
!insertmacro FILE_ASSOCIATION_REMOVE "tcx"
!insertmacro FILE_ASSOCIATION_REMOVE "kml"
@ -226,6 +267,47 @@ Section "Uninstall"
!insertmacro FILE_ASSOCIATION_REMOVE "cup"
!insertmacro FILE_ASSOCIATION_REMOVE "gpi"
!insertmacro FILE_ASSOCIATION_REMOVE "sml"
!insertmacro FILE_ASSOCIATION_REMOVE "img"
!insertmacro FILE_ASSOCIATION_REMOVE "jnx"
!insertmacro FILE_ASSOCIATION_REMOVE "kap"
!insertmacro FILE_ASSOCIATION_REMOVE "map"
!insertmacro FILE_ASSOCIATION_REMOVE "mbtiles"
!insertmacro FILE_ASSOCIATION_REMOVE "rmap"
!insertmacro FILE_ASSOCIATION_REMOVE "tba"
DeleteRegValue HKCR ".gpx\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".tcx\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".kml\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".fit\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".igc\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".nmea\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".plt\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".rte\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".wpt\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".loc\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".slf\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".geojson\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".cup\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".gpi\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".sml\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".csv\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".json\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".jpg\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".jpeg\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".img\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".jnx\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".kap\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".map\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".mbtiles\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".rmap\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".rtmap\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".tar\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".tba\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".tif\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".tiff\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".xml\OpenWithList" "GPXSee.exe"
DeleteRegKey HKCR "Applications\GPXSee.exe"
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
SectionEnd
@ -256,4 +338,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,35 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<!-- Data files -->
<mime-type type="application/gpx+xml">
<comment>GPS Exchange Format</comment>
<sub-class-of type="application/xml"/>
<generic-icon name="application-xml"/>
<root-XML namespaceURI="http://www.topografix.com/GPX/1/0" localName="gpx"/>
<root-XML namespaceURI="http://www.topografix.com/GPX/1/1" localName="gpx"/>
<glob pattern="*.gpx"/>
</mime-type>
<mime-type type="application/tcx+xml">
<mime-type type="application/vnd.garmin.tcx+xml">
<comment>Training Center XML</comment>
<sub-class-of type="application/xml"/>
<generic-icon name="application-xml"/>
<root-XML namespaceURI="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2" localName="TrainingCenterDatabase"/>
<glob pattern="*.tcx"/>
</mime-type>
<mime-type type="application/kml+xml">
<mime-type type="application/vnd.google-earth.kml+xml">
<comment>Keyhole Markup Language</comment>
<sub-class-of type="application/xml"/>
<generic-icon name="application-xml"/>
<root-XML namespaceURI="http://www.opengis.net/kml/2.2" localName="kml"/>
<glob pattern="*.kml"/>
</mime-type>
<mime-type type="application/loc+xml">
<mime-type type="application/vnd.groundspeak.loc+xml">
<comment>Geocaching.com Waypoint File</comment>
<sub-class-of type="application/xml"/>
<generic-icon name="application-xml"/>
<glob pattern="*.loc"/>
</mime-type>
<mime-type type="application/slf+xml">
<mime-type type="application/vnd.sigma.slf+xml">
<comment>Sigma Log Format</comment>
<sub-class-of type="application/xml"/>
<generic-icon name="application-xml"/>
@ -40,6 +46,9 @@
<comment>Flexible and Interoperable Data Transfer</comment>
<sub-class-of type="application/octet-stream"/>
<generic-icon name="application-octet-stream"/>
<magic>
<match type="string" offset="8" value=".FIT"/>
</magic>
<glob pattern="*.fit"/>
</mime-type>
@ -61,6 +70,9 @@
<comment>OziExplorer Track Point File</comment>
<sub-class-of type="text/plain"/>
<generic-icon name="text-plain"/>
<magic>
<match type="string" offset="0" value="OziExplorer Track Point File"/>
</magic>
<glob pattern="*.plt"/>
</mime-type>
@ -68,6 +80,9 @@
<comment>OziExplorer Route File</comment>
<sub-class-of type="text/plain"/>
<generic-icon name="text-plain"/>
<magic>
<match type="string" offset="0" value="OziExplorer Route File"/>
</magic>
<glob pattern="*.rte"/>
</mime-type>
@ -75,6 +90,9 @@
<comment>OziExplorer Waypoint File</comment>
<sub-class-of type="text/plain"/>
<generic-icon name="text-plain"/>
<magic>
<match type="string" offset="0" value="OziExplorer Waypoint File"/>
</magic>
<glob pattern="*.wpt"/>
</mime-type>
@ -96,13 +114,103 @@
<comment>Garmin POI File</comment>
<sub-class-of type="application/octet-stream"/>
<generic-icon name="application/octet-stream"/>
<magic>
<match type="string" offset="8" value="GRMREC"/>
</magic>
<glob pattern="*.gpi"/>
</mime-type>
<mime-type type="application/sml+xml">
<mime-type type="application/vnd.suunto.sml+xml">
<comment>Suunto Markup Language</comment>
<sub-class-of type="application/xml"/>
<generic-icon name="application-xml"/>
<root-XML namespaceURI="http://www.suunto.com/schemas/sml" localName="sml"/>
<glob pattern="*.sml"/>
</mime-type>
<!-- Maps -->
<mime-type type="application/vnd.garmin.img">
<comment>Garmin IMG Map</comment>
<sub-class-of type="application/octet-stream"/>
<generic-icon name="application-octet-stream"/>
<magic>
<match type="string" offset="16" value="DSKIMG"/>
</magic>
<glob pattern="*.img"/>
</mime-type>
<mime-type type="application/vnd.garmin.jnx">
<comment>Garmin JNX Map</comment>
<sub-class-of type="application/octet-stream"/>
<generic-icon name="application-octet-stream"/>
<glob pattern="*.jnx"/>
</mime-type>
<mime-type type="application/vnd.garmin.gmap+xml">
<comment>Garmin Map Product File</comment>
<sub-class-of type="application/xml"/>
<generic-icon name="application-xml"/>
<root-XML namespaceURI="http://www.garmin.com/xmlschemas/MapProduct/v1" localName="MapProduct"/>
<root-XML namespaceURI="http://www.garmin.com/xmlschemas/MapProduct/v2" localName="MapProduct"/>
<glob pattern="*.xml"/>
</mime-type>
<mime-type type="image/vnd.maptech.kap">
<comment>BSB Nautical Chart</comment>
<generic-icon name="image-x-generic"/>
<glob pattern="*.kap"/>
</mime-type>
<mime-type type="application/vnd.oziexplorer.map">
<comment>OziExplorer Map File</comment>
<sub-class-of type="text/plain"/>
<generic-icon name="text-plain"/>
<magic>
<match type="string" offset="0" value="OziExplorer Map Data File"/>
</magic>
<glob pattern="*.map"/>
</mime-type>
<mime-type type="application/vnd.mapbox.mbtiles">
<comment>MBTiles Map File</comment>
<sub-class-of type="application/vnd.sqlite3"/>
<generic-icon name="application/octet-stream"/>
<glob pattern="*.mbtiles"/>
</mime-type>
<mime-type type="application/vnd.twonav.rmap">
<comment>TwoNav Raster Map File</comment>
<sub-class-of type="application/octet-stream"/>
<generic-icon name="application/octet-stream"/>
<magic>
<match type="string" offset="0" value="CompeGPSRasterImage"/>
</magic>
<glob pattern="*.rmap"/>
<glob pattern="*.rtmap"/>
</mime-type>
<mime-type type="application/vnd.trekbuddy.tba">
<comment>TrekBuddy Atlas</comment>
<sub-class-of type="text/plain"/>
<generic-icon name="text-plain"/>
<magic>
<match type="string" offset="0" value="Atlas 1.0"/>
</magic>
<glob pattern="*.tba"/>
</mime-type>
<mime-type type="application/vnd.gpxsee.map+xml">
<comment>GPXSee Map Definition File</comment>
<sub-class-of type="application/xml"/>
<generic-icon name="application-xml"/>
<root-XML namespaceURI="http://www.gpxsee.org/map/1.0" localName="map"/>
<root-XML namespaceURI="http://www.gpxsee.org/map/1.1" localName="map"/>
<root-XML namespaceURI="http://www.gpxsee.org/map/1.2" localName="map"/>
<root-XML namespaceURI="http://www.gpxsee.org/map/1.3" localName="map"/>
<root-XML namespaceURI="http://www.gpxsee.org/map/1.4" localName="map"/>
<glob pattern="*.xml"/>
</mime-type>
</mime-info>

View File

@ -7,7 +7,7 @@
; The name of the installer
Name "GPXSee"
; Program version
!define VERSION "7.37"
!define VERSION "7.38"
; The file to write
OutFile "GPXSee-${VERSION}_x64.exe"
@ -116,14 +116,14 @@ Section "GPXSee" SEC_APP
; Associate file formats
DetailPrint "Associating file types..."
!insertmacro FILE_ASSOCIATION_ADD "gpx" "GPS Exchange Format" 8
!insertmacro FILE_ASSOCIATION_ADD "tcx" "Training Center XML" 9
!insertmacro FILE_ASSOCIATION_ADD "kml" "Keyhole Markup Language" 10
!insertmacro FILE_ASSOCIATION_ADD "fit" "Flexible and Interoperable Data Transfer" 11
!insertmacro FILE_ASSOCIATION_ADD "igc" "Flight Recorder Data Format" 12
!insertmacro FILE_ASSOCIATION_ADD "nmea" "NMEA 0183 Data" 13
!insertmacro FILE_ASSOCIATION_ADD "plt" "OziExplorer Track Point File" 14
!insertmacro FILE_ASSOCIATION_ADD "rte" "OziExplorer Route File" 15
!insertmacro FILE_ASSOCIATION_ADD "gpx" "GPS Exchange Format" 11
!insertmacro FILE_ASSOCIATION_ADD "tcx" "Training Center XML" 16
!insertmacro FILE_ASSOCIATION_ADD "kml" "Keyhole Markup Language" 17
!insertmacro FILE_ASSOCIATION_ADD "fit" "Flexible and Interoperable Data Transfer" 18
!insertmacro FILE_ASSOCIATION_ADD "igc" "Flight Recorder Data Format" 19
!insertmacro FILE_ASSOCIATION_ADD "nmea" "NMEA 0183 Data" 20
!insertmacro FILE_ASSOCIATION_ADD "plt" "OziExplorer Track Point File" 21
!insertmacro FILE_ASSOCIATION_ADD "rte" "OziExplorer Route File" 22
!insertmacro FILE_ASSOCIATION_ADD "wpt" "OziExplorer Waypoint File" 1
!insertmacro FILE_ASSOCIATION_ADD "loc" "Geocaching.com Waypoint File" 2
!insertmacro FILE_ASSOCIATION_ADD "slf" "Sigma Log File" 3
@ -131,6 +131,47 @@ Section "GPXSee" SEC_APP
!insertmacro FILE_ASSOCIATION_ADD "cup" "SeeYou CUP File" 5
!insertmacro FILE_ASSOCIATION_ADD "gpi" "Garmin POI File" 6
!insertmacro FILE_ASSOCIATION_ADD "sml" "Suunto Markup Language" 7
!insertmacro FILE_ASSOCIATION_ADD "img" "Garmin IMG Map" 8
!insertmacro FILE_ASSOCIATION_ADD "jnx" "Garmin JNX Map" 9
!insertmacro FILE_ASSOCIATION_ADD "kap" "BSB Nautical Chart" 10
!insertmacro FILE_ASSOCIATION_ADD "map" "OziExplorer Map File" 12
!insertmacro FILE_ASSOCIATION_ADD "mbtiles" "MBTiles Map File" 13
!insertmacro FILE_ASSOCIATION_ADD "rmap" "TwoNav Raster Map File" 14
!insertmacro FILE_ASSOCIATION_ADD "tba" "TrekBuddy Atlas" 15
WriteRegStr HKCR "Applications\GPXSee.exe\shell\open\command" "" "$\"$INSTDIR\GPXSee.exe$\" $\"%1$\""
WriteRegStr HKCR ".gpx\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".tcx\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".kml\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".fit\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".igc\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".nmea\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".plt\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".rte\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".wpt\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".loc\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".slf\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".geojson\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".cup\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".gpi\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".sml\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".csv\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".json\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".jpg\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".jpeg\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".img\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".jnx\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".kap\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".map\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".mbtiles\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".rmap\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".rtmap\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".tar\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".tba\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".tif\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".tiff\OpenWithList" "GPXSee.exe" ""
WriteRegStr HKCR ".xml\OpenWithList" "GPXSee.exe" ""
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
SectionEnd
@ -218,7 +259,7 @@ Section "Uninstall"
Delete "$SMPROGRAMS\$StartMenuFolder\*.*"
RMDir "$SMPROGRAMS\$StartMenuFolder"
; Remove File associations
; Remove file associations
!insertmacro FILE_ASSOCIATION_REMOVE "gpx"
!insertmacro FILE_ASSOCIATION_REMOVE "tcx"
!insertmacro FILE_ASSOCIATION_REMOVE "kml"
@ -234,6 +275,47 @@ Section "Uninstall"
!insertmacro FILE_ASSOCIATION_REMOVE "cup"
!insertmacro FILE_ASSOCIATION_REMOVE "gpi"
!insertmacro FILE_ASSOCIATION_REMOVE "sml"
!insertmacro FILE_ASSOCIATION_REMOVE "img"
!insertmacro FILE_ASSOCIATION_REMOVE "jnx"
!insertmacro FILE_ASSOCIATION_REMOVE "kap"
!insertmacro FILE_ASSOCIATION_REMOVE "map"
!insertmacro FILE_ASSOCIATION_REMOVE "mbtiles"
!insertmacro FILE_ASSOCIATION_REMOVE "rmap"
!insertmacro FILE_ASSOCIATION_REMOVE "tba"
DeleteRegValue HKCR ".gpx\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".tcx\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".kml\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".fit\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".igc\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".nmea\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".plt\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".rte\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".wpt\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".loc\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".slf\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".geojson\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".cup\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".gpi\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".sml\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".csv\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".json\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".jpg\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".jpeg\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".img\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".jnx\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".kap\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".map\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".mbtiles\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".rmap\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".rtmap\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".tar\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".tba\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".tif\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".tiff\OpenWithList" "GPXSee.exe"
DeleteRegValue HKCR ".xml\OpenWithList" "GPXSee.exe"
DeleteRegKey HKCR "Applications\GPXSee.exe"
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
SectionEnd

View File

@ -16,6 +16,7 @@
#include "opengl.h"
#include "gui.h"
#include "settings.h"
#include "mapaction.h"
#include "app.h"
@ -76,11 +77,25 @@ App::~App()
int App::run()
{
MapAction *lastReady = 0;
QStringList args(arguments());
_gui->show();
QStringList args(arguments());
for (int i = 1; i < args.count(); i++)
_gui->openFile(args.at(i));
for (int i = 1; i < args.count(); i++) {
if (!_gui->openFile(args.at(i), true)) {
MapAction *a;
if (!_gui->loadMap(args.at(i), a, true))
_gui->openFile(args.at(i), false);
else {
if (a)
lastReady = a;
}
}
}
if (lastReady)
lastReady->trigger();
return exec();
}
@ -89,7 +104,18 @@ bool App::event(QEvent *event)
{
if (event->type() == QEvent::FileOpen) {
QFileOpenEvent *e = static_cast<QFileOpenEvent *>(event);
return _gui->openFile(e->file());
if (!_gui->openFile(e->file(), true)) {
MapAction *a;
if (!_gui->loadMap(e->file(), a, true))
return _gui->openFile(e->file(), false);
else {
if (a)
a->trigger();
return true;
}
} else
return true;
}
return QApplication::event(event);

View File

@ -5,6 +5,7 @@
#include <QGraphicsSceneMouseEvent>
#include "map/map.h"
#include "popup.h"
#include "tooltip.h"
#include "areaitem.h"
@ -22,7 +23,7 @@ QString AreaItem::info() const
}
AreaItem::AreaItem(const Area &area, Map *map, GraphicsItem *parent)
: GraphicsItem(parent), _area(area)
: PlaneItem(parent), _area(area)
{
_map = map;
_digitalZoom = 0;
@ -158,7 +159,6 @@ void AreaItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
Q_UNUSED(event);
_pen.setWidthF((_width + 1) * pow(2, -_digitalZoom));
setZValue(zValue() + 1.0);
update();
}
@ -167,12 +167,5 @@ void AreaItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
Q_UNUSED(event);
_pen.setWidthF(_width * pow(2, -_digitalZoom));
setZValue(zValue() - 1.0);
update();
}
void AreaItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
Popup::show(event->screenPos(), info(), event->widget());
QGraphicsItem::mousePressEvent(event);
}

View File

@ -2,12 +2,9 @@
#define AREAITEM_H
#include "data/area.h"
#include "graphicsscene.h"
#include "tooltip.h"
#include "planeitem.h"
class Map;
class AreaItem : public GraphicsItem
class AreaItem : public PlaneItem
{
public:
AreaItem(const Area &area, Map *map, GraphicsItem *parent = 0);
@ -19,6 +16,7 @@ public:
const Area &area() const {return _area;}
RectC bounds() const {return _area.boundingRect();}
void setMap(Map *map);
void setColor(const QColor &color);
@ -27,17 +25,15 @@ public:
void setStyle(Qt::PenStyle style);
void setDigitalZoom(int zoom);
virtual QString info() const;
QString info() const;
protected:
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
void mousePressEvent(QGraphicsSceneMouseEvent *event);
private:
QPainterPath painterPath(const Polygon &polygon);
void updatePainterPath();
ToolTip toolTip() const;
Area _area;
Map *_map;

View File

@ -51,6 +51,7 @@
#include "graphtab.h"
#include "graphitem.h"
#include "pathitem.h"
#include "mapitem.h"
#include "mapaction.h"
#include "gui.h"
@ -130,11 +131,17 @@ void GUI::createMapActions()
if (mapDir.isNull())
return;
QString unused;
QList<Map*> maps(MapList::loadMaps(mapDir, unused));
QList<Map*> maps(MapList::loadMaps(mapDir));
for (int i = 0; i < maps.count(); i++) {
MapAction *a = createMapAction(maps.at(i));
connect(a, SIGNAL(loaded()), this, SLOT(mapInitialized()));
Map *map = maps.at(i);
if (map->isValid()) {
MapAction *a = createMapAction(map);
connect(a, SIGNAL(loaded()), this, SLOT(mapInitialized()));
} else {
qWarning("%s: %s", qPrintable(map->path()),
qPrintable(map->errorString()));
delete map;
}
}
}
@ -159,7 +166,7 @@ void GUI::mapInitialized()
_showMapAction->setEnabled(true);
_clearMapCacheAction->setEnabled(true);
} else {
qWarning("%s: %s", qPrintable(map->name()), qPrintable(map->errorString()));
qWarning("%s: %s", qPrintable(map->path()), qPrintable(map->errorString()));
action->deleteLater();
}
}
@ -306,10 +313,14 @@ void GUI::createActions()
this);
_loadMapAction->setMenuRole(QAction::NoRole);
connect(_loadMapAction, SIGNAL(triggered()), this, SLOT(loadMap()));
_loadMapDirAction = new QAction(QIcon(OPEN_FILE_ICON),
tr("Load map directory..."), this);
_loadMapDirAction->setMenuRole(QAction::NoRole);
connect(_loadMapDirAction, SIGNAL(triggered()), this, SLOT(loadMapDir()));
_clearMapCacheAction = new QAction(tr("Clear tile cache"), this);
_clearMapCacheAction->setEnabled(false);
_clearMapCacheAction->setMenuRole(QAction::NoRole);
connect(_clearMapCacheAction, SIGNAL(triggered()), _mapView,
connect(_clearMapCacheAction, SIGNAL(triggered()), this,
SLOT(clearMapCache()));
_nextMapAction = new QAction(tr("Next map"), this);
_nextMapAction->setMenuRole(QAction::NoRole);
@ -519,6 +530,7 @@ void GUI::createMenus()
_mapMenu->addActions(_mapsActionGroup->actions());
_mapsEnd = _mapMenu->addSeparator();
_mapMenu->addAction(_loadMapAction);
_mapMenu->addAction(_loadMapDirAction);
_mapMenu->addAction(_clearMapCacheAction);
_mapMenu->addSeparator();
_mapMenu->addAction(_showCoordinatesAction);
@ -759,101 +771,45 @@ void GUI::paths()
void GUI::openFile()
{
QStringList files = QFileDialog::getOpenFileNames(this, tr("Open file"),
_dataDir, Data::formats());
QStringList list = files;
QStringList files(QFileDialog::getOpenFileNames(this, tr("Open file"),
_dataDir, Data::formats()));
for (QStringList::Iterator it = list.begin(); it != list.end(); it++)
openFile(*it);
if (!list.isEmpty())
_dataDir = QFileInfo(list.first()).path();
for (int i = 0; i < files.size(); i++)
openFile(files.at(i));
if (!files.isEmpty())
_dataDir = QFileInfo(files.last()).path();
}
bool GUI::openFile(const QString &fileName)
bool GUI::openFile(const QString &fileName, bool silent)
{
if (fileName.isEmpty() || _files.contains(fileName))
return false;
if (loadFile(fileName)) {
_files.append(fileName);
_browser->setCurrent(fileName);
_fileActionGroup->setEnabled(true);
_navigationActionGroup->setEnabled(true);
updateNavigationActions();
updateStatusBarInfo();
updateWindowTitle();
if (_files.contains(fileName))
return true;
} else {
if (_files.isEmpty())
_fileActionGroup->setEnabled(false);
if (!loadFile(fileName, silent))
return false;
}
_files.append(fileName);
_browser->setCurrent(fileName);
_fileActionGroup->setEnabled(true);
// Explicitly enable the reload action as it may be disabled by loadMapDir()
_reloadFileAction->setEnabled(true);
_navigationActionGroup->setEnabled(true);
updateNavigationActions();
updateStatusBarInfo();
updateWindowTitle();
return true;
}
bool GUI::loadFile(const QString &fileName)
bool GUI::loadFile(const QString &fileName, bool silent)
{
Data data(fileName);
QList<QList<GraphItem*> > graphs;
QList<PathItem*> paths;
Data data(fileName, !silent);
if (data.isValid()) {
for (int i = 0; i < data.tracks().count(); i++) {
const Track &track = data.tracks().at(i);
_trackDistance += track.distance();
_time += track.time();
_movingTime += track.movingTime();
#ifdef ENABLE_TIMEZONES
const QDateTime date = track.date().toTimeZone(
_options.timeZone.zone());
#else // ENABLE_TIMEZONES
const QDateTime &date = track.date();
#endif // ENABLE_TIMEZONES
if (_dateRange.first.isNull() || _dateRange.first > date)
_dateRange.first = date;
if (_dateRange.second.isNull() || _dateRange.second < date)
_dateRange.second = date;
}
_trackCount += data.tracks().count();
for (int i = 0; i < data.routes().count(); i++)
_routeDistance += data.routes().at(i).distance();
_routeCount += data.routes().count();
_waypointCount += data.waypoints().count();
_areaCount += data.areas().count();
if (_pathName.isNull()) {
if (data.tracks().count() == 1 && !data.routes().count())
_pathName = data.tracks().first().name();
else if (data.routes().count() == 1 && !data.tracks().count())
_pathName = data.routes().first().name();
} else
_pathName = QString();
for (int i = 0; i < _tabs.count(); i++)
graphs.append(_tabs.at(i)->loadData(data));
if (updateGraphTabs())
_splitter->refresh();
paths = _mapView->loadData(data);
for (int i = 0; i < paths.count(); i++) {
const PathItem *pi = paths.at(i);
for (int j = 0; j < graphs.count(); j++) {
const GraphItem *gi = graphs.at(j).at(i);
if (!gi)
continue;
connect(gi, SIGNAL(sliderPositionChanged(qreal)), pi,
SLOT(moveMarker(qreal)));
connect(pi, SIGNAL(selected(bool)), gi, SLOT(hover(bool)));
connect(gi, SIGNAL(selected(bool)), pi, SLOT(hover(bool)));
}
}
loadData(data);
return true;
} else {
} else if (!silent) {
updateNavigationActions();
updateStatusBarInfo();
updateWindowTitle();
@ -865,25 +821,83 @@ bool GUI::loadFile(const QString &fileName)
error.append("\n" + tr("Line: %1").arg(data.errorLine()));
QMessageBox::critical(this, APP_NAME, error);
return false;
} else
return false;
}
void GUI::loadData(const Data &data)
{
QList<QList<GraphItem*> > graphs;
QList<PathItem*> paths;
for (int i = 0; i < data.tracks().count(); i++) {
const Track &track = data.tracks().at(i);
_trackDistance += track.distance();
_time += track.time();
_movingTime += track.movingTime();
#ifdef ENABLE_TIMEZONES
const QDateTime date = track.date().toTimeZone(
_options.timeZone.zone());
#else // ENABLE_TIMEZONES
const QDateTime &date = track.date();
#endif // ENABLE_TIMEZONES
if (_dateRange.first.isNull() || _dateRange.first > date)
_dateRange.first = date;
if (_dateRange.second.isNull() || _dateRange.second < date)
_dateRange.second = date;
}
_trackCount += data.tracks().count();
for (int i = 0; i < data.routes().count(); i++)
_routeDistance += data.routes().at(i).distance();
_routeCount += data.routes().count();
_waypointCount += data.waypoints().count();
_areaCount += data.areas().count();
if (_pathName.isNull()) {
if (data.tracks().count() == 1 && !data.routes().count())
_pathName = data.tracks().first().name();
else if (data.routes().count() == 1 && !data.tracks().count())
_pathName = data.routes().first().name();
} else
_pathName = QString();
for (int i = 0; i < _tabs.count(); i++)
graphs.append(_tabs.at(i)->loadData(data));
if (updateGraphTabs())
_splitter->refresh();
paths = _mapView->loadData(data);
for (int i = 0; i < paths.count(); i++) {
const PathItem *pi = paths.at(i);
for (int j = 0; j < graphs.count(); j++) {
const GraphItem *gi = graphs.at(j).at(i);
if (!gi)
continue;
connect(gi, SIGNAL(sliderPositionChanged(qreal)), pi,
SLOT(moveMarker(qreal)));
connect(pi, SIGNAL(selected(bool)), gi, SLOT(hover(bool)));
connect(gi, SIGNAL(selected(bool)), pi, SLOT(hover(bool)));
}
}
}
void GUI::openPOIFile()
{
QStringList files = QFileDialog::getOpenFileNames(this, tr("Open POI file"),
_poiDir, Data::formats());
QStringList list = files;
QStringList files(QFileDialog::getOpenFileNames(this, tr("Open POI file"),
_poiDir, Data::formats()));
for (QStringList::Iterator it = list.begin(); it != list.end(); it++)
openPOIFile(*it);
if (!list.isEmpty())
_poiDir = QFileInfo(list.first()).path();
for (int i = 0; i < files.size(); i++)
openPOIFile(files.at(i));
if (!files.isEmpty())
_poiDir = QFileInfo(files.last()).path();
}
bool GUI::openPOIFile(const QString &fileName)
{
if (fileName.isEmpty() || _poi->files().contains(fileName))
return false;
if (_poi->files().contains(fileName))
return true;
if (_poi->loadFile(fileName)) {
_mapView->showPOI(true);
@ -1227,7 +1241,7 @@ void GUI::plotMainPage(QPainter *painter, const QRectF &rect, qreal ratio,
sc = 1;
}
MapView::PlotFlags flags = MapView::NoFlags;
MapView::PlotFlags flags;
if (_options.hiresPrint)
flags |= MapView::HiRes;
if (expand)
@ -1427,45 +1441,73 @@ void GUI::showGraphSliderInfo(bool show)
void GUI::loadMap()
{
QStringList files = QFileDialog::getOpenFileNames(this, tr("Open map file"),
_mapDir, MapList::formats());
QStringList list = files;
QStringList files(QFileDialog::getOpenFileNames(this, tr("Open map file"),
_mapDir, MapList::formats()));
MapAction *a, *lastReady = 0;
for (QStringList::Iterator it = list.begin(); it != list.end(); it++)
loadMap(*it);
if (!list.isEmpty())
_mapDir = QFileInfo(list.first()).path();
for (int i = 0; i < files.size(); i++) {
if (loadMap(files.at(i), a) && a)
lastReady = a;
}
if (!files.isEmpty())
_mapDir = QFileInfo(files.last()).path();
if (lastReady)
lastReady->trigger();
}
bool GUI::loadMap(const QString &fileName)
static MapAction *findMapAction(const QList<QAction*> &mapActions,
const Map *map)
{
// On OS X fileName may be a directory!
if (fileName.isEmpty())
return false;
QString error;
QList<Map*> maps = MapList::loadMaps(fileName, error);
if (maps.isEmpty()) {
error = tr("Error loading map:") + "\n\n"
+ fileName + "\n\n" + error;
QMessageBox::critical(this, APP_NAME, error);
return false;
for (int i = 0; i < mapActions.count(); i++) {
const Map *m = mapActions.at(i)->data().value<Map*>();
if (map->path() == m->path())
return static_cast<MapAction*>(mapActions.at(i));
}
return 0;
}
bool GUI::loadMap(const QString &fileName, MapAction *&action, bool silent)
{
QList<Map*> maps(MapList::loadMaps(fileName));
QList<QAction*> existingActions(_mapsActionGroup->actions());
MapAction *lastReady = 0;
bool valid = false;
for (int i = 0; i < maps.size(); i++) {
Map *map = maps.at(i);
MapAction *a = createMapAction(map);
_mapMenu->insertAction(_mapsEnd, a);
if (map->isReady()) {
a->trigger();
_showMapAction->setEnabled(true);
_clearMapCacheAction->setEnabled(true);
} else
connect(a, SIGNAL(loaded()), this, SLOT(mapLoaded()));
MapAction *a;
if (!(a = findMapAction(existingActions, map))) {
if (!map->isValid()) {
if (!silent)
QMessageBox::critical(this, APP_NAME,
tr("Error loading map:") + "\n\n" + map->path() + "\n\n"
+ map->errorString());
delete map;
} else {
valid = true;
a = createMapAction(map);
_mapMenu->insertAction(_mapsEnd, a);
if (map->isReady()) {
lastReady = a;
_showMapAction->setEnabled(true);
_clearMapCacheAction->setEnabled(true);
} else
connect(a, SIGNAL(loaded()), this, SLOT(mapLoaded()));
}
} else {
valid = true;
map = a->data().value<Map*>();
if (map->isReady())
lastReady = a;
}
}
return true;
action = lastReady;
return valid;
}
void GUI::mapLoaded()
@ -1478,13 +1520,94 @@ void GUI::mapLoaded()
_showMapAction->setEnabled(true);
_clearMapCacheAction->setEnabled(true);
} else {
QString error = tr("Error loading map:") + "\n\n"
+ map->name() + "\n\n" + map->errorString();
QString error = tr("Error loading map:") + "\n\n" + map->path() + "\n\n"
+ map->errorString();
QMessageBox::critical(this, APP_NAME, error);
action->deleteLater();
}
}
void GUI::mapLoadedDir()
{
MapAction *action = static_cast<MapAction*>(QObject::sender());
Map *map = action->data().value<Map*>();
if (map->isValid()) {
_showMapAction->setEnabled(true);
_clearMapCacheAction->setEnabled(true);
QList<MapAction*> actions;
actions.append(action);
_mapView->loadMaps(actions);
} else {
QString error = tr("Error loading map:") + "\n\n" + map->path() + "\n\n"
+ map->errorString();
QMessageBox::critical(this, APP_NAME, error);
action->deleteLater();
}
}
void GUI::loadMapDir()
{
QString dir(QFileDialog::getExistingDirectory(this,
tr("Select map directory"), _mapDir, QFileDialog::ShowDirsOnly));
if (dir.isEmpty())
return;
QList<Map*> maps(MapList::loadMaps(dir));
QList<MapAction*> actions;
QList<QAction*> existingActions(_mapsActionGroup->actions());
QFileInfo fi(dir);
QMenu *menu = new QMenu(fi.fileName());
for (int i = 0; i < maps.size(); i++) {
Map *map = maps.at(i);
MapAction *a;
if (!(a = findMapAction(existingActions, map))) {
if (!map->isValid()) {
QMessageBox::critical(this, APP_NAME, tr("Error loading map:")
+ "\n\n" + map->path() + "\n\n" + map->errorString());
delete map;
} else {
a = createMapAction(map);
menu->addAction(a);
if (map->isReady()) {
_showMapAction->setEnabled(true);
_clearMapCacheAction->setEnabled(true);
actions.append(a);
} else
connect(a, SIGNAL(loaded()), this, SLOT(mapLoadedDir()));
}
} else {
map = a->data().value<Map*>();
if (map->isReady())
actions.append(a);
}
}
_mapView->loadMaps(actions);
if (menu->isEmpty())
delete menu;
else {
menu->setStyleSheet("QMenu { menu-scrollable: 1; }");
_mapMenu->insertMenu(_mapsEnd, menu);
}
_mapDir = fi.absolutePath();
_areaCount += maps.size();
_fileActionGroup->setEnabled(true);
_reloadFileAction->setEnabled(false);
}
void GUI::clearMapCache()
{
if (QMessageBox::question(this, APP_NAME,
tr("Clear the map tile cache?")) == QMessageBox::Yes)
_mapView->clearMapCache();
}
void GUI::updateStatusBarInfo()
{
if (_files.count() == 0)
@ -1535,7 +1658,7 @@ void GUI::nextMap()
if (!checked)
return;
QList<QAction*> maps = _mapsActionGroup->actions();
QList<QAction*> maps(_mapsActionGroup->actions());
for (int i = 1; i < maps.size(); i++) {
int next = (maps.indexOf(checked) + i) % maps.count();
if (maps.at(next)->isEnabled()) {
@ -1551,7 +1674,7 @@ void GUI::prevMap()
if (!checked)
return;
QList<QAction*> maps = _mapsActionGroup->actions();
QList<QAction*> maps(_mapsActionGroup->actions());
for (int i = 1; i < maps.size(); i++) {
int prev = (maps.indexOf(checked) + maps.count() - i) % maps.count();
if (maps.at(prev)->isEnabled()) {
@ -1777,9 +1900,25 @@ void GUI::dragEnterEvent(QDragEnterEvent *event)
void GUI::dropEvent(QDropEvent *event)
{
QList<QUrl> urls = event->mimeData()->urls();
for (int i = 0; i < urls.size(); i++)
openFile(urls.at(i).toLocalFile());
MapAction *lastReady = 0;
QList<QUrl> urls(event->mimeData()->urls());
for (int i = 0; i < urls.size(); i++) {
QString file(urls.at(i).toLocalFile());
if (!openFile(file, true)) {
MapAction *a;
if (!loadMap(file, a, true))
openFile(file, false);
else {
if (a)
lastReady = a;
}
}
}
if (lastReady)
lastReady->trigger();
event->acceptProposedAction();
}
@ -2397,7 +2536,7 @@ void GUI::readSettings()
QAction *GUI::mapAction(const QString &name)
{
QList<QAction *> maps = _mapsActionGroup->actions();
QList<QAction *> maps(_mapsActionGroup->actions());
// Last map
for (int i = 0; i < maps.count(); i++) {

View File

@ -30,6 +30,7 @@ class Map;
class POI;
class QScreen;
class MapAction;
class Data;
class GUI : public QMainWindow
{
@ -38,7 +39,9 @@ class GUI : public QMainWindow
public:
GUI();
bool openFile(const QString &fileName);
bool openFile(const QString &fileName, bool silent = false);
bool loadMap(const QString &fileName, MapAction *&action,
bool silent = false);
void show();
private slots:
@ -62,9 +65,11 @@ private slots:
void showTracks(bool show);
void showRoutes(bool show);
void loadMap();
void loadMapDir();
void nextMap();
void prevMap();
void openOptions();
void clearMapCache();
void mapChanged();
void graphChanged(int);
@ -91,6 +96,7 @@ private slots:
void logicalDotsPerInchChanged(qreal dpi);
void mapLoaded();
void mapLoadedDir();
void mapInitialized();
private:
@ -117,8 +123,8 @@ private:
void createBrowser();
bool openPOIFile(const QString &fileName);
bool loadFile(const QString &fileName);
bool loadMap(const QString &fileName);
bool loadFile(const QString &fileName, bool silent = false);
void loadData(const Data &data);
void updateStatusBarInfo();
void updateWindowTitle();
void updateNavigationActions();
@ -172,6 +178,7 @@ private:
QAction *_showMapAction;
QAction *_fullscreenAction;
QAction *_loadMapAction;
QAction *_loadMapDirAction;
QAction *_clearMapCacheAction;
QAction *_showGraphsAction;
QAction *_showGraphGridAction;

230
src/GUI/mapitem.cpp Normal file
View File

@ -0,0 +1,230 @@
#include <cmath>
#include <QCursor>
#include <QPainter>
#include <QGraphicsSceneMouseEvent>
#include "map/map.h"
#include "mapaction.h"
#include "popup.h"
#include "tooltip.h"
#include "mapitem.h"
static void growLeft(Map *map, const Coordinates &c, QRectF &rect)
{
QPointF p(map->ll2xy(c));
if (p.x() < rect.left())
rect.setLeft(p.x());
}
static void growRight(Map *map, const Coordinates &c, QRectF &rect)
{
QPointF p(map->ll2xy(c));
if (p.x() > rect.right())
rect.setRight(p.x());
}
static void growTop(Map *map, const Coordinates &c, QRectF &rect)
{
QPointF p(map->ll2xy(c));
if (p.y() > rect.top())
rect.setTop(p.y());
}
static void growBottom(Map *map, const Coordinates &c, QRectF &rect)
{
QPointF p(map->ll2xy(c));
if (p.y() < rect.bottom())
rect.setBottom(p.y());
}
static QRectF bbox(const RectC &rect, Map *map, int samples = 100)
{
if (!rect.isValid())
return QRectF();
double dx = rect.width() / samples;
double dy = rect.height() / samples;
QPointF tl(map->ll2xy(rect.topLeft()));
QPointF br(map->ll2xy(rect.bottomRight()));
QRectF prect(tl, br);
for (int i = 0; i <= samples; i++) {
double x = remainder(rect.left() + i * dx, 360.0);
growTop(map, Coordinates(x, rect.bottom()), prect);
growBottom(map, Coordinates(x, rect.top()), prect);
}
for (int i = 0; i <= samples; i++) {
double y = rect.bottom() + i * dy;
growLeft(map, Coordinates(rect.left(), y), prect);
growRight(map, Coordinates(rect.right(), y), prect);
}
return prect;
}
QString MapItem::info() const
{
ToolTip tt;
if (!_name.isEmpty())
tt.insert(tr("Name"), _name);
if (!_fileName.isEmpty())
tt.insert(tr("File"), _fileName);
return tt.toString();
}
MapItem::MapItem(MapAction *action, Map *map, GraphicsItem *parent)
: PlaneItem(parent)
{
Map *src = action->data().value<Map*>();
Q_ASSERT(map->isReady());
_name = src->name();
_fileName = src->path();
_bounds = src->llBounds();
connect(this, SIGNAL(triggered()), action, SLOT(trigger()));
_map = map;
_digitalZoom = 0;
_width = 2;
_opacity = 0.5;
QBrush brush(Qt::SolidPattern);
_pen = QPen(brush, _width);
updatePainterPath();
setCursor(Qt::ArrowCursor);
setAcceptHoverEvents(true);
}
void MapItem::updatePainterPath()
{
_painterPath = QPainterPath();
QRectF r(bbox(_bounds, _map));
if (r.left() > r.right()) {
QRectF r1(bbox(RectC(_bounds.topLeft(),
Coordinates(180, _bounds.bottomRight().lat())), _map));
QRectF r2(bbox(RectC(Coordinates(-180, _bounds.topLeft().lat()),
_bounds.bottomRight()), _map));
_painterPath.addRect(r1);
_painterPath.addRect(r2);
} else
_painterPath.addRect(r);
}
void MapItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
painter->setPen(_width ? _pen : QPen(Qt::NoPen));
painter->drawPath(_painterPath);
painter->fillPath(_painterPath, _brush);
//QPen p = QPen(QBrush(Qt::red), 0);
//painter->setPen(p);
//painter->drawRect(boundingRect());
}
void MapItem::setMap(Map *map)
{
prepareGeometryChange();
_map = map;
updatePainterPath();
}
void MapItem::setColor(const QColor &color)
{
if (_pen.color() == color)
return;
QColor bc(color);
bc.setAlphaF(_opacity * color.alphaF());
_pen.setColor(color);
_brush = QBrush(bc);
update();
}
void MapItem::setOpacity(qreal opacity)
{
if (_opacity == opacity)
return;
_opacity = opacity;
QColor bc(_pen.color());
bc.setAlphaF(_opacity * _pen.color().alphaF());
_brush = QBrush(bc);
update();
}
void MapItem::setWidth(qreal width)
{
if (_width == width)
return;
prepareGeometryChange();
_width = width;
_pen.setWidthF(_width * pow(2, -_digitalZoom));
}
void MapItem::setStyle(Qt::PenStyle style)
{
if (_pen.style() == style)
return;
_pen.setStyle(style);
update();
}
void MapItem::setDigitalZoom(int zoom)
{
if (_digitalZoom == zoom)
return;
prepareGeometryChange();
_digitalZoom = zoom;
_pen.setWidthF(_width * pow(2, -_digitalZoom));
}
void MapItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event);
_pen.setWidthF((_width + 1) * pow(2, -_digitalZoom));
update();
}
void MapItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event);
_pen.setWidthF(_width * pow(2, -_digitalZoom));
update();
}
void MapItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(event);
emit triggered();
}

57
src/GUI/mapitem.h Normal file
View File

@ -0,0 +1,57 @@
#ifndef MAPITEM_H
#define MAPITEM_H
#include "planeitem.h"
class MapAction;
class MapItem : public QObject, public PlaneItem
{
Q_OBJECT
public:
MapItem(MapAction *action, Map *map, GraphicsItem *parent = 0);
QPainterPath shape() const {return _painterPath;}
QRectF boundingRect() const {return _painterPath.boundingRect();}
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget);
RectC bounds() const {return _bounds;}
void setMap(Map *map);
void setColor(const QColor &color);
void setOpacity(qreal opacity);
void setWidth(qreal width);
void setStyle(Qt::PenStyle style);
void setDigitalZoom(int zoom);
QString info() const;
signals:
void triggered();
protected:
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
private:
void updatePainterPath();
RectC _bounds;
QString _name;
QString _fileName;
Map *_map;
int _digitalZoom;
qreal _width;
QPen _pen;
QBrush _brush;
qreal _opacity;
QPainterPath _painterPath;
};
#endif // MAPITEM_H

View File

@ -15,8 +15,10 @@
#include "areaitem.h"
#include "scaleitem.h"
#include "coordinatesitem.h"
#include "mapitem.h"
#include "keys.h"
#include "graphicsscene.h"
#include "mapaction.h"
#include "mapview.h"
@ -27,6 +29,20 @@
#define COORDINATES_OFFSET SCALE_OFFSET
template<typename T>
static void updateZValues(T &items)
{
for (int i = 0; i < items.size(); i++) {
const QGraphicsItem *ai = items.at(i);
for (int j = 0; j < items.size(); j++) {
QGraphicsItem *aj = items[j];
if (aj->boundingRect().contains(ai->boundingRect()))
aj->setZValue(qMin(ai->zValue() - 1, aj->zValue()));
}
}
}
MapView::MapView(Map *map, POI *poi, QWidget *parent)
: QGraphicsView(parent)
{
@ -39,7 +55,7 @@ MapView::MapView(Map *map, POI *poi, QWidget *parent)
setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setRenderHint(QPainter::Antialiasing, true);
setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
setResizeAnchor(QGraphicsView::AnchorViewCenter);
setAcceptDrops(false);
@ -170,18 +186,19 @@ void MapView::addArea(const Area &area)
}
AreaItem *ai = new AreaItem(area, _map);
_areas.append(ai);
_ar |= ai->area().boundingRect();
ai->setColor(_palette.nextColor());
ai->setWidth(_areaWidth);
ai->setStyle(_areaStyle);
ai->setOpacity(_areaOpacity);
ai->setDigitalZoom(_digitalZoom);
ai->setVisible(_showAreas);
_scene->addItem(ai);
_ar |= ai->bounds();
_areas.append(ai);
if (_showAreas)
addPOI(_poi->points(ai->area()));
addPOI(_poi->points(ai->bounds()));
}
void MapView::addWaypoints(const QVector<Waypoint> &waypoints)
@ -205,6 +222,26 @@ void MapView::addWaypoints(const QVector<Waypoint> &waypoints)
}
}
MapItem *MapView::addMap(MapAction *map)
{
MapItem *mi = new MapItem(map, _map);
mi->setColor(_palette.nextColor());
mi->setWidth(_areaWidth);
mi->setStyle(_areaStyle);
mi->setOpacity(_areaOpacity);
mi->setDigitalZoom(_digitalZoom);
mi->setVisible(_showAreas);
_scene->addItem(mi);
_ar |= mi->bounds();
_areas.append(mi);
if (_showAreas)
addPOI(_poi->points(mi->bounds()));
return mi;
}
QList<PathItem *> MapView::loadData(const Data &data)
{
QList<PathItem *> paths;
@ -227,18 +264,37 @@ QList<PathItem *> MapView::loadData(const Data &data)
else
updatePOIVisibility();
if (!data.areas().isEmpty())
updateZValues(_areas);
centerOn(contentCenter());
return paths;
}
void MapView::loadMaps(const QList<MapAction *> &maps)
{
int zoom = _map->zoom();
for (int i = 0; i < maps.size(); i++)
addMap(maps.at(i));
if (fitMapZoom() != zoom)
rescale();
else
updatePOIVisibility();
updateZValues(_areas);
centerOn(contentCenter());
}
int MapView::fitMapZoom() const
{
RectC br = _tr | _rr | _wr | _ar;
return _map->zoomFit(viewport()->size() - QSize(2*MARGIN, 2*MARGIN),
br.isNull() ? RectC(_map->xy2ll(_map->bounds().topLeft()),
_map->xy2ll(_map->bounds().bottomRight())) : br);
br.isNull() ? _map->llBounds() : br);
}
QPointF MapView::contentCenter() const
@ -373,7 +429,7 @@ void MapView::updatePOI()
addPOI(_poi->points(_routes.at(i)->path()));
if (_showAreas)
for (int i = 0; i < _areas.size(); i++)
addPOI(_poi->points(_areas.at(i)->area()));
addPOI(_poi->points(_areas.at(i)->bounds()));
if (_showWaypoints)
for (int i = 0; i< _waypoints.size(); i++)
addPOI(_poi->points(_waypoints.at(i)->waypoint()));
@ -504,6 +560,10 @@ void MapView::wheelEvent(QWheelEvent *event)
void MapView::mouseDoubleClickEvent(QMouseEvent *event)
{
QGraphicsView::mouseDoubleClickEvent(event);
if (event->isAccepted())
return;
if (event->button() != Qt::LeftButton && event->button() != Qt::RightButton)
return;

View File

@ -29,10 +29,12 @@ class ScaleItem;
class CoordinatesItem;
class PathItem;
class GraphItem;
class AreaItem;
class PlaneItem;
class MapItem;
class Area;
class GraphicsScene;
class QTimeZone;
class MapAction;
class MapView : public QGraphicsView
{
@ -49,6 +51,7 @@ public:
MapView(Map *map, POI *poi, QWidget *parent = 0);
QList<PathItem *> loadData(const Data &data);
void loadMaps(const QList<MapAction*> &maps);
void setPalette(const Palette &palette);
void setPOI(POI *poi);
@ -108,6 +111,7 @@ private:
PathItem *addTrack(const Track &track);
PathItem *addRoute(const Route &route);
MapItem *addMap(MapAction *map);
void addArea(const Area &area);
void addWaypoints(const QVector<Waypoint> &waypoints);
void addPOI(const QList<Waypoint> &waypoints);
@ -140,7 +144,7 @@ private:
QList<TrackItem*> _tracks;
QList<RouteItem*> _routes;
QList<WaypointItem*> _waypoints;
QList<AreaItem*> _areas;
QList<PlaneItem*> _areas;
POIHash _pois;
RectC _tr, _rr, _wr, _ar;

24
src/GUI/planeitem.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef PLANEITEM_H
#define PLANEITEM_H
#include "common/rectc.h"
#include "graphicsscene.h"
class Map;
class PlaneItem : public GraphicsItem
{
public:
PlaneItem(GraphicsItem *parent = 0) : GraphicsItem(parent) {}
virtual RectC bounds() const = 0;
virtual void setMap(Map *map) = 0;
virtual void setColor(const QColor &color) = 0;
virtual void setOpacity(qreal opacity) = 0;
virtual void setWidth(qreal width) = 0;
virtual void setStyle(Qt::PenStyle style) = 0;
virtual void setDigitalZoom(int zoom) = 0;
};
#endif // PLANEITEM_H

View File

@ -1,3 +1,4 @@
#include <cmath>
#include "wgs84.h"
#include "rectc.h"
@ -6,6 +7,16 @@
#define MIN_LON deg2rad(-180.0)
#define MAX_LON deg2rad(180.0)
static inline double WLON(double lon)
{
return remainder(lon, 360.0);
}
static inline double LLAT(double lat)
{
return (lat < 0.0) ? qMax(lat, -90.0) : qMin(lat, 90.0);
}
RectC::RectC(const Coordinates &center, double radius)
{
double radDist = radius / WGS84_RADIUS;
@ -151,6 +162,12 @@ RectC RectC::united(const Coordinates &c) const
return RectC(Coordinates(l, t), Coordinates(r, b));
}
RectC RectC::adjusted(double lon1, double lat1, double lon2, double lat2) const
{
return RectC(Coordinates(WLON(_tl.lon() + lon1), LLAT(_tl.lat() + lat1)),
Coordinates(WLON(_br.lon() + lon2), LLAT(_br.lat() + lat2)));
}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const RectC &rect)
{

View File

@ -16,7 +16,7 @@ public:
{return _tl.isNull() && _br.isNull();}
bool isValid() const
{return (_tl.isValid() && _br.isValid()
&& _tl.lat() > _br.lat() && _tl.lon() < _br.lon());}
&& _tl.lat() != _br.lat() && _tl.lon() != _br.lon());}
Coordinates topLeft() const {return _tl;}
Coordinates bottomRight() const {return _br;}
@ -24,14 +24,18 @@ public:
{return Coordinates((_tl.lon() + _br.lon()) / 2.0,
(_tl.lat() + _br.lat()) / 2.0);}
double width() const
{
double res = right() - left();
return (left() > right()) ? 360.0 - res : res;
}
double height() const {return (top() - bottom());}
double top() const {return _tl.lat();}
double bottom() const {return _br.lat();}
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;}
@ -43,6 +47,7 @@ public:
RectC &operator&=(const RectC &r) {*this = *this & r; return *this;}
RectC united(const Coordinates &c) const;
RectC adjusted(double lon1, double lat1, double lon2, double lat2) const;
bool intersects(const RectC &r) const
{return (right() >= r.left() && bottom() <= r.top() && left() <= r.right()

View File

@ -8,6 +8,19 @@
class Area : public QList<Polygon>
{
public:
Area() {}
Area(const RectC &rect)
{
Polygon polygon;
QVector<Coordinates> v(4);
v[0] = Coordinates(rect.left(), rect.top());
v[1] = Coordinates(rect.right(), rect.top());
v[2] = Coordinates(rect.right(), rect.bottom());
v[3] = Coordinates(rect.left(), rect.bottom());
polygon.append(v);
append(polygon);
}
const QString& name() const {return _name;}
const QString& description() const {return _desc;}
void setName(const QString &name) {_name = name;}

View File

@ -20,6 +20,7 @@
#include "cupparser.h"
#include "gpiparser.h"
#include "smlparser.h"
#include "map/map.h"
#include "data.h"
@ -82,7 +83,7 @@ void Data::processData(QList<TrackData> &trackData, QList<RouteData> &routeData)
_routes.append(Route(routeData.at(i)));
}
Data::Data(const QString &fileName)
Data::Data(const QString &fileName, bool tryUnknown)
{
QFile file(fileName);
QFileInfo fi(fileName);
@ -108,7 +109,7 @@ Data::Data(const QString &fileName)
_errorLine = it.value()->errorLine();
_errorString = it.value()->errorString();
}
} else {
} else if (tryUnknown) {
for (it = _parsers.begin(); it != _parsers.end(); it++) {
if (it.value()->parse(&file, trackData, routeData, _polygons,
_waypoints)) {

View File

@ -10,11 +10,10 @@
#include "route.h"
#include "parser.h"
class Data
{
public:
Data(const QString &fileName);
Data(const QString &fileName, bool full = true);
bool isValid() const {return _valid;}
const QString &errorString() const {return _errorString;}

View File

@ -485,15 +485,8 @@ static quint32 readCamera(QDataStream &stream, QVector<Waypoint> &waypoints,
waypoints.append(Coordinates(toWGS24(lon), toWGS24(lat)));
Area area;
Polygon polygon;
QVector<Coordinates> v(4);
v[0] = Coordinates(toWGS24(left), toWGS24(top));
v[1] = Coordinates(toWGS24(right), toWGS24(top));
v[2] = Coordinates(toWGS24(right), toWGS24(bottom));
v[3] = Coordinates(toWGS24(left), toWGS24(bottom));
polygon.append(v);
area.append(polygon);
Area area(RectC(Coordinates(toWGS24(left), toWGS24(top)),
Coordinates(toWGS24(right), toWGS24(bottom))));
switch (type) {
case 8:

View File

@ -80,12 +80,25 @@ void POI::search(const RectC &rect, QSet<int> &set) const
{
qreal min[2], max[2];
min[0] = rect.topLeft().lon();
min[1] = rect.bottomRight().lat();
max[0] = rect.bottomRight().lon();
max[1] = rect.topLeft().lat();
if (rect.left() > rect.right()) {
min[0] = rect.topLeft().lon();
min[1] = rect.bottomRight().lat();
max[0] = 180.0;
max[1] = rect.topLeft().lat();
_tree.Search(min, max, cb, &set);
_tree.Search(min, max, cb, &set);
min[0] = -180.0;
min[1] = rect.bottomRight().lat();
max[0] = rect.bottomRight().lon();
max[1] = rect.topLeft().lat();
_tree.Search(min, max, cb, &set);
} else {
min[0] = rect.topLeft().lon();
min[1] = rect.bottomRight().lat();
max[0] = rect.bottomRight().lon();
max[1] = rect.topLeft().lat();
_tree.Search(min, max, cb, &set);
}
}
QList<Waypoint> POI::points(const Path &path) const
@ -130,16 +143,10 @@ QList<Waypoint> POI::points(const Waypoint &point) const
{
QList<Waypoint> ret;
QSet<int> set;
qreal min[2], max[2];
QSet<int>::const_iterator it;
RectC br(point.coordinates(), _radius);
min[0] = br.topLeft().lon();
min[1] = br.bottomRight().lat();
max[0] = br.bottomRight().lon();
max[1] = br.topLeft().lat();
_tree.Search(min, max, cb, &set);
search(br, set);
for (it = set.constBegin(); it != set.constEnd(); ++it)
ret.append(_data.at(*it));
@ -147,22 +154,15 @@ QList<Waypoint> POI::points(const Waypoint &point) const
return ret;
}
QList<Waypoint> POI::points(const Area &area) const
QList<Waypoint> POI::points(const RectC &rect) const
{
QList<Waypoint> ret;
qreal min[2], max[2];
QSet<int> set;
QSet<int>::const_iterator it;
RectC br(area.boundingRect());
double offset = rad2deg(_radius / WGS84_RADIUS);
min[0] = br.topLeft().lon() - offset;
min[1] = br.bottomRight().lat() - offset;
max[0] = br.bottomRight().lon() + offset;
max[1] = br.topLeft().lat() + offset;
_tree.Search(min, max, cb, &set);
RectC br(rect.adjusted(-offset, offset, offset, -offset));
search(br, set);
for (it = set.constBegin(); it != set.constEnd(); ++it)
ret.append(_data.at(*it));

View File

@ -9,7 +9,6 @@
#include "waypoint.h"
class Path;
class Area;
class RectC;
class POI : public QObject
@ -29,7 +28,7 @@ public:
QList<Waypoint> points(const Path &path) const;
QList<Waypoint> points(const Waypoint &point) const;
QList<Waypoint> points(const Area &area) const;
QList<Waypoint> points(const RectC &rect) const;
const QStringList &files() const {return _files;}
void enableFile(const QString &fileName, bool enable);

View File

@ -454,4 +454,3 @@ void RasterTile::processPoints(QList<TextItem*> &textItems)
delete item;
}
}

View File

@ -78,7 +78,7 @@ void Atlas::computeBounds()
}
Atlas::Atlas(const QString &fileName, QObject *parent)
: Map(parent), _zoom(0), _mapIndex(-1), _valid(false)
: Map(fileName, parent), _zoom(0), _mapIndex(-1), _valid(false)
{
QFileInfo fi(fileName);
QByteArray ba;

465
src/map/bsbmap.cpp Normal file
View File

@ -0,0 +1,465 @@
#include <cctype>
#include <QFileInfo>
#include <QPainter>
#include "image.h"
#include "gcs.h"
#include "pcs.h"
#include "calibrationpoint.h"
#include "color.h"
#include "bsbmap.h"
#define LINE_LIMIT 1024
static inline bool isEOH(const QByteArray &line)
{
return (line.size() >= 2 && line.at(line.size() - 2) == 0x1A
&& line.at(line.size() -1) == 0);
}
static inline bool isType(const QByteArray &line, const QByteArray &type)
{
return (line.left(4) == type);
}
static inline QByteArray hdrData(const QByteArray &line)
{
return line.right(line.size() - 4);
}
static bool readHeaderLine(QFile &file, QByteArray &line)
{
char c;
while (file.getChar(&c) && line.size() < LINE_LIMIT) {
if (c == '\0') {
line.append(c);
return true;
}
if (c == '\r')
continue;
if (c == '\n') {
if (!file.getChar(&c))
return false;
if (c == ' ') {
do {
if (!file.getChar(&c))
return false;
} while (c == ' ');
line.append(',');
file.ungetChar(c);
continue;
} else {
file.ungetChar(c);
return true;
}
}
line.append(c);
}
return false;
}
static inline bool isSplitter(const QByteArray &line, int i)
{
return (line.at(i) == ',' && line.size() - i > 3 && isupper(line.at(i+1))
&& (isupper(line.at(i+2)) || isdigit(line.at(i+2))) && line.at(i+3) == '=');
}
static QList<QByteArray> split(const QByteArray &line)
{
QList<QByteArray> list;
int ls = 0;
for (int i = 0; i < line.size(); i++) {
if (isSplitter(line, i)) {
list.append(line.mid(ls, i - ls));
ls = i + 1;
}
}
list.append(line.mid(ls, line.size() - ls));
return list;
}
static QMap<QByteArray, QByteArray> kvMap(const QByteArray &line)
{
QMap<QByteArray, QByteArray> map;
QList<QByteArray> parts(split(line));
for (int i = 0; i < parts.size(); i++) {
QList<QByteArray> ba = parts.at(i).split('=');
if (ba.size() != 2)
continue;
map.insert(ba.at(0), ba.at(1));
}
return map;
}
static double parameter(const QString &str, bool *res)
{
if (str.isEmpty() || str == "NOT_APPLICABLE" || str == "UNKNOWN") {
*res = true;
return NAN;
}
return str.toDouble(res);
}
bool BSBMap::parseBSB(const QByteArray &line)
{
QMap<QByteArray, QByteArray> map(kvMap(line));
_name = QString::fromLatin1(map.value("NA"));
if (_name.isEmpty()) {
_errorString = "Invalid/missing BSB NA field";
return false;
}
QList<QByteArray> sv(map.value("RA").split(','));
unsigned w, h;
bool wok = false, hok = false;
if (sv.size() == 2) {
w = sv.at(0).toUInt(&wok);
h = sv.at(1).toUInt(&hok);
}
if (!wok || !hok || !w || !h) {
_errorString = "Invalid BSB RA field";
return false;
}
_size = QSize(w, h);
return true;
}
bool BSBMap::parseKNP(const QByteArray &line, QString &datum, QString &proj,
double &pp)
{
QMap<QByteArray, QByteArray> map(kvMap(line));
bool ok;
if (!(map.contains("PR") && map.contains("GD") && map.contains("PP"))) {
_errorString = "Missing KNP PR/GD/PP field";
return false;
}
proj = map.value("PR");
datum = map.value("GD");
pp = parameter(map.value("PP"), &ok);
if (!ok) {
_errorString = "Invalid KNP PP field";
return false;
}
_skew = parameter(map.value("SK"), &ok);
if (!ok) {
_errorString = "Invalid KNP SK field";
return false;
}
return true;
}
bool BSBMap::parseKNQ(const QByteArray &line, double params[9])
{
QMap<QByteArray, QByteArray> map(kvMap(line));
bool ok;
for (int i = 1; i <= 8; i++) {
params[i] = parameter(map.value(QString("P%1").arg(i).toLatin1()), &ok);
if (!ok) {
_errorString = QString("Invalid KNQ P%1 parameter").arg(i);
return false;
}
}
return true;
}
bool BSBMap::parseREF(const QByteArray &line, const QString &datum,
const QString &proj, double params[9], QList<ReferencePoint> &points)
{
QList<QByteArray> fields(line.split(','));
if (fields.size() == 5) {
bool xok, yok, lonok, latok;
Coordinates c(fields.at(4).toDouble(&lonok),
fields.at(3).toDouble(&latok));
if (lonok && latok && c.isValid()) {
if (_projection.isNull()) {
if (!createProjection(datum, proj, params, c))
return false;
}
CalibrationPoint p(PointD(fields.at(1).toDouble(&xok),
fields.at(2).toDouble(&yok)), c);
if (xok && yok) {
points.append(p.rp(_projection));
return true;
}
}
}
_errorString = QString(line) + ": Invalid reference point entry";
return false;
}
bool BSBMap::parseRGB(const QByteArray &line)
{
QList<QByteArray> fields(line.split(','));
bool iok, rok, gok, bok;
int i = fields.at(0).toUInt(&iok);
if (iok && fields.size() == 4 && i > 0 && i < 256) {
_palette[i-1] = Color::rgb(fields.at(1).toUInt(&rok),
fields.at(2).toUInt(&gok), fields.at(3).toUInt(&bok));
if (rok && gok && bok)
return true;
}
_errorString = QString(line) + ": Invalid RGB entry";
return false;
}
bool BSBMap::readHeader(QFile &file)
{
QByteArray line;
QString datum, proj;
double params[9];
QList<ReferencePoint> points;
while (readHeaderLine(file, line)) {
if (isEOH(line)) {
if (!_size.isValid() || !_projection.isValid()) {
_errorString = "Invalid KAP file header";
return false;
}
return createTransform(points);
}
if (isType(line, "BSB/") && !parseBSB(hdrData(line)))
return false;
else if (isType(line, "KNP/")
&& !parseKNP(hdrData(line), datum, proj, params[0]))
return false;
else if (isType(line, "KNQ/") && !parseKNQ(hdrData(line), params))
return false;
else if (isType(line, "REF/")
&& !parseREF(hdrData(line), datum, proj, params, points))
return false;
else if (isType(line, "RGB/") && !parseRGB(hdrData(line)))
return false;
line.clear();
}
_errorString = "Not a KAP file";
return false;
}
bool BSBMap::createTransform(QList<ReferencePoint> &points)
{
if (_skew > 0.0 && _skew < 360.0) {
QTransform matrix;
matrix.rotate(-_skew);
QTransform t(QImage::trueMatrix(matrix, _size.width(), _size.height()));
for (int i = 0; i < points.size(); i++)
points[i].setXY(t.map(points.at(i).xy().toPointF()));
QPolygonF a(QRectF(0, 0, _size.width(), _size.height()));
a = t.map(a);
_skewSize = a.boundingRect().toAlignedRect().size();
}
_transform = Transform(points);
if (!_transform.isValid()) {
_errorString = _transform.errorString();
return false;
}
return true;
}
bool BSBMap::createProjection(const QString &datum, const QString &proj,
double params[9], const Coordinates &c)
{
const GCS *gcs = 0;
PCS pcs;
if (datum.isEmpty())
gcs = GCS::gcs(4326);
else
gcs = GCS::gcs(datum);
if (!gcs) {
_errorString = datum + ": Unknown datum";
return false;
}
if (!proj.compare("MERCATOR", Qt::CaseInsensitive)) {
Projection::Setup setup(0, c.lon(), NAN, 0, 0, NAN, NAN);
pcs = PCS(gcs, 9804, setup, 9001);
} else if (!proj.compare("TRANSVERSE MERCATOR", Qt::CaseInsensitive)) {
Projection::Setup setup(0, params[1], params[2], 0, 0, NAN, NAN);
pcs = PCS(gcs, 9807, setup, 9001);
} else if (!proj.compare("UNIVERSAL TRANSVERSE MERCATOR",
Qt::CaseInsensitive)) {
Projection::Setup setup(0, params[0], 0.9996, 500000, 0, NAN, NAN);
pcs = PCS(gcs, 9807, setup, 9001);
} else if (!proj.compare("LAMBERT CONFORMAL CONIC", Qt::CaseInsensitive)) {
Projection::Setup setup(0, params[0], NAN, 0, 0, params[2], params[3]);
pcs = PCS(gcs, 9802, setup, 9001);
} else if (!proj.compare("POLYCONIC", Qt::CaseInsensitive)) {
Projection::Setup setup(0, params[0], NAN, 0, 0, NAN, NAN);
pcs = PCS(gcs, 9818, setup, 9001);
} else {
_errorString = proj + ": Unknown/missing projection";
return false;
}
_projection = Projection(&pcs);
return true;
}
bool BSBMap::readRow(QFile &file, char bits, uchar *buf)
{
char c;
int multiplier;
int pixel = 1, written = 0;
static const char mask[] = {0, 63, 31, 15, 7, 3, 1, 0};
do {
if (!file.getChar(&c))
return false;
} while ((uchar)c >= 0x80);
while (true) {
if (!file.getChar(&c))
return false;
if (c == '\0')
break;
pixel = (c & 0x7f) >> (7 - bits);
multiplier = c & mask[(int)bits];
while ((uchar)c >= 0x80) {
if (!file.getChar(&c))
return false;
multiplier = (multiplier << 7) + (c & 0x7f);
}
multiplier++;
if (written + multiplier > _size.width())
multiplier = _size.width() - written;
memset(buf + written, pixel - 1, multiplier);
written += multiplier;
}
while (written < _size.width())
buf[written++] = pixel - 1;
return true;
}
QImage BSBMap::readImage()
{
QFile file(_fileName);
char bits;
if (!file.open(QIODevice::ReadOnly))
return QImage();
file.seek(_dataOffset);
if (!file.getChar(&bits))
return QImage();
QImage img(_size, QImage::Format_Indexed8);
img.setColorTable(_palette);
for (int row = 0; row < _size.height(); row++) {
uchar *bsb_row = img.scanLine(row);
if (!readRow(file, bits, bsb_row))
return QImage();
}
return img;
}
BSBMap::BSBMap(const QString &fileName, QObject *parent)
: Map(fileName, parent), _fileName(fileName), _img(0), _ratio(1.0),
_dataOffset(-1), _valid(false)
{
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
_errorString = fileName + ": " + file.errorString();
return;
}
_palette.resize(256);
if (!readHeader(file))
return;
_dataOffset = file.pos();
_valid = true;
}
BSBMap::~BSBMap()
{
delete _img;
}
QPointF BSBMap::ll2xy(const Coordinates &c)
{
return QPointF(_transform.proj2img(_projection.ll2xy(c))) / _ratio;
}
Coordinates BSBMap::xy2ll(const QPointF &p)
{
return _projection.xy2ll(_transform.img2proj(p * _ratio));
}
QRectF BSBMap::bounds()
{
return _skewSize.isValid()
? QRectF(QPointF(0, 0), _skewSize / _ratio)
: QRectF(QPointF(0, 0), _size / _ratio);
}
void BSBMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
{
if (_img)
_img->draw(painter, rect, flags);
}
void BSBMap::setDevicePixelRatio(qreal deviceRatio, qreal mapRatio)
{
Q_UNUSED(deviceRatio);
_ratio = mapRatio;
if (_img)
_img->setDevicePixelRatio(_ratio);
}
void BSBMap::load()
{
if (!_img) {
if (_skew > 0.0 && _skew < 360.0) {
QTransform matrix;
matrix.rotate(-_skew);
_img = new Image(readImage().transformed(matrix));
} else
_img = new Image(readImage());
}
}
void BSBMap::unload()
{
delete _img;
_img = 0;
}

66
src/map/bsbmap.h Normal file
View File

@ -0,0 +1,66 @@
#ifndef BSBMAP_H
#define BSBMAP_H
#include <QColor>
#include "transform.h"
#include "projection.h"
#include "map.h"
class QFile;
class Image;
class BSBMap : public Map
{
Q_OBJECT
public:
BSBMap(const QString &fileName, QObject *parent = 0);
~BSBMap();
QString name() const {return _name;}
QRectF bounds();
QPointF ll2xy(const Coordinates &c);
Coordinates xy2ll(const QPointF &p);
void draw(QPainter *painter, const QRectF &rect, Flags flags);
void load();
void unload();
void setDevicePixelRatio(qreal deviceRatio, qreal mapRatio);
bool isValid() const {return _valid;}
QString errorString() const {return _errorString;}
private:
bool parseBSB(const QByteArray &line);
bool parseKNP(const QByteArray &line, QString &datum, QString &proj,
double &pp);
bool parseKNQ(const QByteArray &line, double params[9]);
bool parseREF(const QByteArray &line, const QString &datum,
const QString &proj, double params[9], QList<ReferencePoint> &points);
bool parseRGB(const QByteArray &line);
bool readHeader(QFile &file);
bool createProjection(const QString &datum, const QString &proj,
double params[9], const Coordinates &c);
bool createTransform(QList<ReferencePoint> &points);
QImage readImage();
bool readRow(QFile &file, char bits, uchar *buf);
QString _fileName;
QString _name;
Projection _projection;
Transform _transform;
qreal _skew;
Image *_img;
QSize _size;
QSize _skewSize;
qreal _ratio;
qint64 _dataOffset;
QVector<QRgb> _palette;
bool _valid;
QString _errorString;
};
#endif // BSBMAP_H

View File

@ -1,6 +1,7 @@
#ifndef CALIBRATIONPOINT_H
#define CALIBRATIONPOINT_H
#include <QDebug>
#include "transform.h"
#include "projection.h"
@ -22,10 +23,21 @@ public:
: ReferencePoint(_xy, _pp);
}
friend QDebug operator<<(QDebug dbg, const CalibrationPoint &p);
private:
PointD _xy;
PointD _pp;
Coordinates _ll;
};
#ifndef QT_NO_DEBUG
inline QDebug operator<<(QDebug dbg, const CalibrationPoint &p)
{
dbg.nospace() << "CalibrationPoint(" << p._xy << ", " << p._pp << ", "
<< p._ll << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG
#endif // CALIBRATIONPOINT_H

View File

@ -13,6 +13,11 @@ namespace Color
return (0xFF000000 | r << 16 | g << 8 | b);
}
inline QRgb rgb(quint32 r, quint32 g, quint32 b)
{
return (0xFF000000 | r << 16 | g << 8 | b);
}
}
#endif // COLOR_H

View File

@ -1,7 +1,6 @@
#include <QtGlobal>
#include <QPainter>
#include "common/rectc.h"
#include "osm.h"
#include "emptymap.h"
@ -18,7 +17,7 @@ static int limitZoom(int zoom)
}
EmptyMap::EmptyMap(QObject *parent) : Map(parent)
EmptyMap::EmptyMap(QObject *parent) : Map(QString(), parent)
{
_zoom = OSM::ZOOMS.max();
}

View File

@ -1,6 +1,7 @@
#ifndef EMPTYMAP_H
#define EMPTYMAP_H
#include "osm.h"
#include "map.h"
class EmptyMap : public Map
@ -13,6 +14,7 @@ public:
QString name() const {return QString();}
QRectF bounds();
RectC llBounds() {return OSM::BOUNDS;}
qreal resolution(const QRectF &rect);
int zoom() const {return _zoom;}

View File

@ -54,6 +54,7 @@ QList<GCS::Entry> GCS::defaults()
{
QList<GCS::Entry> list;
list.append(GCS::Entry(4326, 6326, "WGS 84", WGS84()));
list.append(GCS::Entry(4326, 6326, "WGS84", WGS84()));
return list;
}

View File

@ -55,6 +55,7 @@
#define CT_AlbersEqualArea 11
#define CT_PolarStereographic 15
#define CT_ObliqueStereographic 16
#define CT_Polyconic 22
#define IS_SET(map, key) \
@ -344,6 +345,8 @@ Projection::Method GeoTIFF::method(QMap<quint16, Value> &kv)
return Projection::Method(9829);
case CT_ObliqueStereographic:
return Projection::Method(9809);
case CT_Polyconic:
return Projection::Method(9818);
default:
_errorString = QString("%1: unknown coordinate transformation method")
.arg(kv.value(ProjCoordTransGeoKey).SHORT);

View File

@ -1,14 +1,14 @@
#include <QFileInfo>
#include <QPainter>
#include <QImageReader>
#include "common/config.h"
#include "geotiff.h"
#include "image.h"
#include "geotiffmap.h"
GeoTIFFMap::GeoTIFFMap(const QString &fileName, QObject *parent)
: Map(parent), _fileName(fileName), _img(0), _ratio(1.0), _valid(false)
: Map(fileName, parent), _fileName(fileName), _img(0), _ratio(1.0),
_valid(false)
{
QImageReader ir(fileName);
if (!ir.canRead()) {

View File

@ -1,15 +1,10 @@
#include <QPainter>
#include <QPixmapCache>
#include "common/config.h"
#include "image.h"
#define TILE_SIZE 256
Image::Image(const QString &fileName) : _img(fileName), _fileName(fileName)
{
}
void Image::draw(QPainter *painter, const QRectF &rect, Map::Flags flags)
{
#ifdef ENABLE_HIDPI
@ -19,26 +14,30 @@ void Image::draw(QPainter *painter, const QRectF &rect, Map::Flags flags)
#endif // ENABLE_HIDPI
QRectF sr(rect.topLeft() * ratio, rect.size() * ratio);
/* When OpenGL is used, big images are rendered incredibly slow or not at
all using the QPainter::drawImage() function with a source rect set. So
we have to tile the image ourself before it can be drawn.
We have to use a list of dynamically allocated pixmaps as QPainter
rendering is broken in yet another way with OpenGL and drawPixmap() does
access already deleted image instances when reusing a single pixmap. */
if (flags & Map::OpenGL) {
QList<QPixmap *> list;
for (int i = sr.left()/TILE_SIZE; i <= sr.right()/TILE_SIZE; i++) {
for (int j = sr.top()/TILE_SIZE; j <= sr.bottom()/TILE_SIZE; j++) {
QString key = _fileName + "-" + QString::number(i) + "_"
+ QString::number(j);
QPoint tl(i * TILE_SIZE, j * TILE_SIZE);
QPixmap pm;
if (!QPixmapCache::find(key, &pm)) {
QRect tile(tl, QSize(TILE_SIZE, TILE_SIZE));
pm = QPixmap::fromImage(_img.copy(tile));
if (!pm.isNull())
QPixmapCache::insert(key, pm);
}
QRect tile(tl, QSize(TILE_SIZE, TILE_SIZE));
QPixmap *pm = new QPixmap(QPixmap::fromImage(_img.copy(tile)));
list.append(pm);
#ifdef ENABLE_HIDPI
pm.setDevicePixelRatio(ratio);
pm->setDevicePixelRatio(ratio);
#endif // ENABLE_HIDPI
painter->drawPixmap(tl/ratio, pm);
painter->drawPixmap(tl/ratio, *pm);
}
}
qDeleteAll(list);
} else
painter->drawImage(rect.topLeft(), _img, sr);
}

View File

@ -9,14 +9,14 @@ class QPainter;
class Image
{
public:
Image(const QString &fileName);
Image(const QString &fileName) : _img(fileName) {}
Image(const QImage &img) : _img(img) {}
void draw(QPainter *painter, const QRectF &rect, Map::Flags flags);
void setDevicePixelRatio(qreal ratio);
private:
QImage _img;
QString _fileName;
};
#endif // IMAGE_H

View File

@ -44,7 +44,7 @@ static QList<MapData*> overlays(const QString &fileName)
}
IMGMap::IMGMap(const QString &fileName, QObject *parent)
: Map(parent), _projection(PCS::pcs(3857)), _valid(false)
: Map(fileName, parent), _projection(PCS::pcs(3857)), _valid(false)
{
if (GMAP::isGMAP(fileName))
_data.append(new GMAP(fileName));
@ -171,7 +171,7 @@ void IMGMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
polyRect &= bounds();
RectD polyRectD(_transform.img2proj(polyRect.topLeft()),
_transform.img2proj(polyRect.bottomRight()));
_data.at(n)->polys(polyRectD.toRectC(_projection, 4), _zoom,
_data.at(n)->polys(polyRectD.toRectC(_projection, 20), _zoom,
&polygons, &lines);
QRectF pointRect(QPointF(ttl.x() - TEXT_EXTENT,
@ -180,7 +180,7 @@ void IMGMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
pointRect &= bounds();
RectD pointRectD(_transform.img2proj(pointRect.topLeft()),
_transform.img2proj(pointRect.bottomRight()));
_data.at(n)->points(pointRectD.toRectC(_projection, 4),
_data.at(n)->points(pointRectD.toRectC(_projection, 20),
_zoom, &points);
tiles.append(RasterTile(this, _data.at(n)->style(), _zoom,
@ -212,10 +212,18 @@ void IMGMap::setProjection(const Projection &projection)
return;
_projection = projection;
// Limit the bounds for some well known Mercator projections
// Limit the bounds for some well known projections
// (world maps have N/S bounds up to 90/-90!)
_dataBounds = (_projection == PCS::pcs(3857) || _projection == PCS::pcs(3395))
? _data.first()->bounds() & OSM::BOUNDS : _data.first()->bounds();
if (_projection == PCS::pcs(3857) || _projection == PCS::pcs(3395))
_dataBounds = _data.first()->bounds() & OSM::BOUNDS;
else if (_projection == PCS::pcs(3031) || _projection == PCS::pcs(3976))
_dataBounds = _data.first()->bounds() & RectC(Coordinates(-180, -60),
Coordinates(180, -90));
else if (_projection == PCS::pcs(3995) || _projection == PCS::pcs(3413))
_dataBounds = _data.first()->bounds() & RectC(Coordinates(-180, 90),
Coordinates(180, 60));
else
_dataBounds = _data.first()->bounds();
updateTransform();
QPixmapCache::clear();

View File

@ -18,6 +18,7 @@ public:
QString name() const {return _data.first()->name();}
QRectF bounds() {return _bounds;}
RectC llBounds() {return _dataBounds;}
int zoom() const {return _zoom;}
void setZoom(int zoom);

31
src/map/invalidmap.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef INVALIDMAP_H
#define INVALIDMAP_H
#include "map.h"
class InvalidMap : public Map
{
Q_OBJECT
public:
InvalidMap(const QString &fileName, const QString &error, QObject *parent = 0)
: Map(fileName, parent), _errorString(error) {}
QString name() const {return QString();}
QRectF bounds() {return QRectF();}
QPointF ll2xy(const Coordinates &) {return QPointF();}
Coordinates xy2ll(const QPointF &) {return Coordinates();}
void draw(QPainter *, const QRectF &, Flags) {}
bool isValid() const {return false;}
bool isReady() const {return false;}
QString errorString() const {return _errorString;}
private:
QString _errorString;
};
#endif // INVALIDMAP_H

View File

@ -139,12 +139,13 @@ bool JNXMap::readTiles()
}
JNXMap::JNXMap(const QString &fileName, QObject *parent)
: Map(parent), _file(fileName), _zoom(0), _mapRatio(1.0), _valid(false)
: Map(fileName, parent), _file(fileName), _zoom(0), _mapRatio(1.0),
_valid(false)
{
_name = QFileInfo(fileName).fileName();
if (!_file.open(QIODevice::ReadOnly)) {
_errorString = QString("%1: Error opening file").arg(fileName);
_errorString = fileName + ": " + _file.errorString();
return;
}

View File

@ -20,6 +20,7 @@ public:
QString name() const {return _name;}
QRectF bounds();
RectC llBounds() {return _bounds;}
int zoom() const {return _zoom;}
void setZoom(int zoom) {_zoom = zoom;}

View File

@ -1,6 +1,67 @@
#include <cmath>
#include <QLineF>
#include "map.h"
#define SAMPLES 100
void Map::growLeft(const QPointF &p, RectC &rect)
{
Coordinates c(xy2ll(p));
if (c.lon() < rect.left())
rect.setLeft(c.lon());
}
void Map::growRight(const QPointF &p, RectC &rect)
{
Coordinates c(xy2ll(p));
if (c.lon() > rect.right())
rect.setRight(c.lon());
}
void Map::growTop(const QPointF &p, RectC &rect)
{
Coordinates c(xy2ll(p));
if (c.lat() > rect.top())
rect.setTop(c.lat());
}
void Map::growBottom(const QPointF &p, RectC &rect)
{
Coordinates c(xy2ll(p));
if (c.lat() < rect.bottom())
rect.setBottom(c.lat());
}
RectC Map::llBounds()
{
QRectF b(bounds());
double dx = b.width() / SAMPLES;
double dy = b.height() / SAMPLES;
Coordinates tl(xy2ll(b.topLeft()));
Coordinates br(xy2ll(b.bottomRight()));
RectC rect(tl, br);
for (int i = 0; i <= SAMPLES; i++) {
double x = b.left() + i * dx;
growBottom(QPointF(x, b.bottom()), rect);
growTop(QPointF(x, b.top()), rect);
}
for (int i = 0; i <= SAMPLES; i++) {
double y = b.top() + i * dy;
growLeft(QPointF(b.left(), y), rect);
growRight(QPointF(b.right(), y), rect);
}
return rect;
}
qreal Map::resolution(const QRectF &rect)
{
qreal cy = rect.center().y();

View File

@ -5,11 +5,10 @@
#include <QString>
#include <QRectF>
#include <QFlags>
#include "common/coordinates.h"
#include "common/rectc.h"
class QPainter;
class RectC;
class Projection;
class Map : public QObject
@ -24,11 +23,14 @@ public:
};
Q_DECLARE_FLAGS(Flags, Flag)
Map(QObject *parent = 0) : QObject(parent) {}
Map(const QString &path, QObject *parent = 0)
: QObject(parent), _path(path) {}
virtual ~Map() {}
const QString &path() const {return _path;}
virtual QString name() const = 0;
virtual RectC llBounds();
virtual QRectF bounds() = 0;
virtual qreal resolution(const QRectF &rect);
@ -56,6 +58,14 @@ public:
signals:
void tilesLoaded();
void mapLoaded();
private:
void growLeft(const QPointF &p, RectC &rect);
void growRight(const QPointF &p, RectC &rect);
void growTop(const QPointF &p, RectC &rect);
void growBottom(const QPointF &p, RectC &rect);
QString _path;
};
Q_DECLARE_METATYPE(Map*)

View File

@ -190,6 +190,8 @@ bool MapFile::createProjection(const GCS *gcs, const QString &name,
pcs = PCS(gcs, 9822, setup, 9001);
else if (name == "(A)Lambert Azimuthual Equal Area")
pcs = PCS(gcs, 9820, setup, 9001);
else if (name == "Polyconic (American)")
pcs = PCS(gcs, 9818, setup, 9001);
else if (name == "(NZTM2) New Zealand TM 2000")
pcs = PCS(gcs, 9807, Projection::Setup(0, 173.0, 0.9996, 1600000,
10000000, NAN, NAN), 9001);

View File

@ -10,11 +10,12 @@
#include "rmap.h"
#include "imgmap.h"
#include "IMG/gmap.h"
#include "bsbmap.h"
#include "invalidmap.h"
#include "maplist.h"
Map *MapList::loadFile(const QString &path, QString &errorString,
bool *terminate)
Map *MapList::loadFile(const QString &path, bool *terminate)
{
QFileInfo fi(path);
QString suffix = fi.suffix().toLower();
@ -26,12 +27,11 @@ Map *MapList::loadFile(const QString &path, QString &errorString,
map = new Atlas(path);
} else if (suffix == "xml") {
if (MapSource::isMap(path)) {
if (!(map = MapSource::loadMap(path, errorString)))
return 0;
map = MapSource::loadMap(path);
} else if (GMAP::isGMAP(path)) {
map = new IMGMap(path);
if (terminate)
*terminate = true;
map = new IMGMap(path);
}
} else if (suffix == "jnx")
map = new JNXMap(path);
@ -45,17 +45,13 @@ Map *MapList::loadFile(const QString &path, QString &errorString,
map = new IMGMap(path);
else if (suffix == "map" || suffix == "tar")
map = new OziMap(path);
else if (suffix == "kap")
map = new BSBMap(path);
if (map && map->isValid())
return map;
else {
errorString = (map) ? map->errorString() : "Unknown file format";
delete map;
return 0;
}
return map ? map : new InvalidMap(path, "Unknown file format");
}
QList<Map*> MapList::loadDir(const QString &path, QString &errorString)
QList<Map*> MapList::loadDir(const QString &path)
{
QDir md(path);
md.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
@ -69,14 +65,9 @@ QList<Map*> MapList::loadDir(const QString &path, QString &errorString)
bool terminate = false;
if (fi.isDir() && fi.fileName() != "set")
list.append(loadDir(fi.absoluteFilePath(), errorString));
list.append(loadDir(fi.absoluteFilePath()));
else if (filter().contains("*." + suffix)) {
Map *map = loadFile(fi.absoluteFilePath(), errorString, &terminate);
if (map)
list.append(map);
else
qWarning("%s: %s", qPrintable(fi.absoluteFilePath()),
qPrintable(errorString));
list.append(loadFile(fi.absoluteFilePath(), &terminate));
if (terminate)
break;
}
@ -85,15 +76,13 @@ QList<Map*> MapList::loadDir(const QString &path, QString &errorString)
return list;
}
QList<Map*> MapList::loadMaps(const QString &path, QString &errorString)
QList<Map*> MapList::loadMaps(const QString &path)
{
if (QFileInfo(path).isDir())
return loadDir(path, errorString);
return loadDir(path);
else {
QList<Map*> list;
Map *map = loadFile(path, errorString, 0);
if (map)
list.append(map);
list.append(loadFile(path, 0));
return list;
}
}
@ -106,6 +95,7 @@ QString MapList::formats()
+ qApp->translate("MapList", "Garmin IMG maps")
+ " (*.gmap *.gmapi *.img *.xml);;"
+ qApp->translate("MapList", "Garmin JNX maps") + " (*.jnx);;"
+ qApp->translate("MapList", "BSB nautical charts") + " (*.kap);;"
+ qApp->translate("MapList", "OziExplorer maps") + " (*.map);;"
+ qApp->translate("MapList", "MBTiles maps") + " (*.mbtiles);;"
+ qApp->translate("MapList", "TrekBuddy maps/atlases") + " (*.tar *.tba);;"
@ -117,7 +107,7 @@ QString MapList::formats()
QStringList MapList::filter()
{
QStringList filter;
filter << "*.gmap" << "*.gmapi" << "*.img" << "*.jnx" << "*.map"
filter << "*.gmap" << "*.gmapi" << "*.img" << "*.jnx" << "*.kap" << "*.map"
<< "*.mbtiles" << "*.rmap" << "*.rtmap" << "*.tar" << "*.tba" << "*.tif"
<< "*.tiff" << "*.xml";
return filter;

View File

@ -8,14 +8,13 @@ class Map;
class MapList
{
public:
static QList<Map*> loadMaps(const QString &path, QString &errorString);
static QList<Map*> loadMaps(const QString &path);
static QString formats();
static QStringList filter();
private:
static Map *loadFile(const QString &path, QString &errorString,
bool *terminate);
static QList<Map*> loadDir(const QString &path, QString &errorString);
static Map *loadFile(const QString &path, bool *terminate);
static QList<Map*> loadDir(const QString &path);
};
#endif // MAPLIST_H

View File

@ -5,6 +5,7 @@
#include "wmtsmap.h"
#include "wmsmap.h"
#include "osm.h"
#include "invalidmap.h"
#include "mapsource.h"
@ -236,16 +237,14 @@ bool MapSource::isMap(const QString &path)
return false;
}
Map *MapSource::loadMap(const QString &path, QString &errorString)
Map *MapSource::loadMap(const QString &path)
{
Config config;
QFile file(path);
if (!file.open(QFile::ReadOnly | QFile::Text)) {
errorString = file.errorString();
return 0;
}
if (!file.open(QFile::ReadOnly | QFile::Text))
return new InvalidMap(path, file.errorString());
QXmlStreamReader reader(&file);
if (reader.readNextStartElement()) {
@ -254,66 +253,53 @@ Map *MapSource::loadMap(const QString &path, QString &errorString)
else
reader.raiseError("Not an online map source file");
}
if (reader.error()) {
errorString = QString("%1: %2").arg(reader.lineNumber())
.arg(reader.errorString());
return 0;
}
if (reader.error())
return new InvalidMap(path, QString("%1: %2").arg(reader.lineNumber())
.arg(reader.errorString()));
if (config.name.isEmpty()) {
errorString = "Missing name definition";
return 0;
}
if (config.url.isEmpty()) {
errorString = "Missing URL definition";
return 0;
}
if (config.name.isEmpty())
return new InvalidMap(path, "Missing name definition");
if (config.url.isEmpty())
return new InvalidMap(path, "Missing URL definition");
if (config.type == WMTS || config.type == WMS) {
if (config.layer.isEmpty()) {
errorString = "Missing layer definition";
return 0;
}
if (config.format.isEmpty()) {
errorString = "Missing format definition";
return 0;
}
if (config.layer.isEmpty())
return new InvalidMap(path, "Missing layer definition");
if (config.format.isEmpty())
return new InvalidMap(path, "Missing format definition");
}
if (config.type == WMTS) {
if (config.set.isEmpty()) {
errorString = "Missing set definiton";
return 0;
}
if (config.set.isEmpty())
return new InvalidMap(path, "Missing set definiton");
}
if (config.type == WMS) {
if (config.crs.isEmpty()) {
errorString = "Missing CRS definiton";
return 0;
}
if (config.crs.isEmpty())
return new InvalidMap(path, "Missing CRS definiton");
}
switch (config.type) {
case WMTS:
return new WMTSMap(config.name, WMTS::Setup(config.url, config.layer,
config.set, config.style, config.format, config.rest,
return new WMTSMap(path, config.name, WMTS::Setup(config.url,
config.layer, config.set, config.style, config.format, config.rest,
config.coordinateSystem, config.dimensions, config.authorization),
config.tileRatio);
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.tileSize);
return new WMSMap(path, config.name, WMS::Setup(config.url,
config.layer, config.style, config.format, config.crs,
config.coordinateSystem, config.dimensions, config.authorization),
config.tileSize);
case TMS:
return new OnlineMap(config.name, config.url, config.zooms,
return new OnlineMap(path, config.name, config.url, config.zooms,
config.bounds, config.tileRatio, config.authorization,
config.tileSize, config.scalable, true, false);
case OSM:
return new OnlineMap(config.name, config.url, config.zooms,
return new OnlineMap(path, config.name, config.url, config.zooms,
config.bounds, config.tileRatio, config.authorization,
config.tileSize, config.scalable, false, false);
case QuadTiles:
return new OnlineMap(config.name, config.url, config.zooms,
return new OnlineMap(path, config.name, config.url, config.zooms,
config.bounds, config.tileRatio, config.authorization,
config.tileSize, config.scalable, false, true);
default:
return 0;
return new InvalidMap(path, "Invalid map type");
}
}

View File

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

View File

@ -55,7 +55,7 @@ static double index2mercator(int index, int zoom)
}
MBTilesMap::MBTilesMap(const QString &fileName, QObject *parent)
: Map(parent), _fileName(fileName), _mapRatio(1.0), _tileRatio(1.0),
: Map(fileName, parent), _fileName(fileName), _mapRatio(1.0), _tileRatio(1.0),
_scalable(false), _scaledSize(0), _valid(false)
{
_db = QSqlDatabase::addDatabase("QSQLITE", fileName);

View File

@ -14,6 +14,7 @@ public:
QString name() const {return _name;}
QRectF bounds();
RectC llBounds() {return _bounds;}
qreal resolution(const QRectF &rect);
int zoom() const {return _zoom;}

View File

@ -8,11 +8,11 @@
#include "onlinemap.h"
OnlineMap::OnlineMap(const QString &name, const QString &url,
const Range &zooms, const RectC &bounds, qreal tileRatio,
OnlineMap::OnlineMap(const QString &fileName, const QString &name,
const QString &url, const Range &zooms, const RectC &bounds, qreal tileRatio,
const Authorization &authorization, int tileSize, bool scalable, bool invertY,
bool quadTiles, QObject *parent)
: Map(parent), _name(name), _zooms(zooms), _bounds(bounds),
: Map(fileName, parent), _name(name), _zooms(zooms), _bounds(bounds),
_zoom(_zooms.max()), _mapRatio(1.0), _tileRatio(tileRatio),
_tileSize(tileSize), _scalable(scalable), _invertY(invertY)
{

View File

@ -11,14 +11,15 @@ class OnlineMap : public Map
Q_OBJECT
public:
OnlineMap(const QString &name, const QString &url, const Range &zooms,
const RectC &bounds, qreal tileRatio, const Authorization &authorization,
int tileSize, bool scalable, bool invertY, bool quadTiles,
QObject *parent = 0);
OnlineMap(const QString &fileName, const QString &name, const QString &url,
const Range &zooms, const RectC &bounds, qreal tileRatio,
const Authorization &authorization, int tileSize, bool scalable,
bool invertY, bool quadTiles, QObject *parent = 0);
QString name() const {return _name;}
QRectF bounds();
RectC llBounds() {return _bounds;}
qreal resolution(const QRectF &rect);
int zoom() const {return _zoom;}

View File

@ -17,7 +17,8 @@
OziMap::OziMap(const QString &fileName, QObject *parent)
: Map(parent), _img(0), _tar(0), _ozf(0), _zoom(0), _mapRatio(1.0), _valid(false)
: Map(fileName, parent), _img(0), _tar(0), _ozf(0), _zoom(0), _mapRatio(1.0),
_valid(false)
{
QFileInfo fi(fileName);
QString suffix = fi.suffix().toLower();
@ -79,7 +80,8 @@ OziMap::OziMap(const QString &fileName, QObject *parent)
}
OziMap::OziMap(const QString &fileName, Tar &tar, QObject *parent)
: Map(parent), _img(0), _tar(0), _ozf(0), _zoom(0), _mapRatio(1.0), _valid(false)
: Map(fileName, parent), _img(0), _tar(0), _ozf(0), _zoom(0), _mapRatio(1.0),
_valid(false)
{
QFileInfo fi(fileName);
QFileInfo map(fi.absolutePath());

View File

@ -199,5 +199,5 @@ bool PolarStereographic::operator==(const CT &ct) const
&& _originLongitude == other->_originLongitude
&& _falseEasting == other->_falseEasting
&& _falseNorthing == other->_falseNorthing && _two_a == other->_two_a
&& _es == other->_es);
&& _es == other->_es && _southernHemisphere == other->_southernHemisphere);
}

211
src/map/polyconic.cpp Normal file
View File

@ -0,0 +1,211 @@
/*
* Based on libgeotrans with the following Source Code Disclaimer:
1. The GEOTRANS source code ("the software") is provided free of charge by
the National Imagery and Mapping Agency (NIMA) of the United States
Department of Defense. Although NIMA makes no copyright claim under Title 17
U.S.C., NIMA claims copyrights in the source code under other legal regimes.
NIMA hereby grants to each user of the software a license to use and
distribute the software, and develop derivative works.
2. Warranty Disclaimer: The software was developed to meet only the internal
requirements of the U.S. National Imagery and Mapping Agency. The software
is provided "as is," and no warranty, express or implied, including but not
limited to the implied warranties of merchantability and fitness for
particular purpose or arising by statute or otherwise in law or from a
course of dealing or usage in trade, is made by NIMA as to the accuracy and
functioning of the software.
3. NIMA and its personnel are not required to provide technical support or
general assistance with respect to the software.
4. Neither NIMA nor its personnel will be liable for any claims, losses, or
damages arising from or connected with the use of the software. The user
agrees to hold harmless the United States National Imagery and Mapping
Agency. The user's sole and exclusive remedy is to stop using the software.
5. NIMA requests that products developed using the software credit the
source of the software with the following statement, "The product was
developed using GEOTRANS, a product of the National Imagery and Mapping
Agency and U.S. Army Engineering Research and Development Center."
6. For any products developed using the software, NIMA requires a disclaimer
that use of the software does not indicate endorsement or approval of the
product by the Secretary of Defense or the National Imagery and Mapping
Agency. Pursuant to the United States Code, 10 U.S.C. Sec. 2797, the name of
the National Imagery and Mapping Agency, the initials "NIMA", the seal of
the National Imagery and Mapping Agency, or any colorable imitation thereof
shall not be used to imply approval, endorsement, or authorization of a
product without prior written permission from United States Secretary of
Defense.
*/
#include "ellipsoid.h"
#include "polyconic.h"
#define POLY_COEFF_TIMES_SIN(coeff, x, latit) \
(coeff * (sin (x * latit)))
#define POLY_M(c0lat, c1s2lat, c2s4lat, c3s6lat) \
(_a * (c0lat - c1s2lat + c2s4lat - c3s6lat))
#define FLOAT_EQ(x, v, epsilon) \
(((v - epsilon) < x) && (x < (v + epsilon)))
Polyconic::Polyconic(const Ellipsoid *ellipsoid, double latitudeOrigin,
double longitudeOrigin, double falseEasting, double falseNorthing)
{
double j, three_es4;
double lat, sin2lat, sin4lat, sin6lat;
double a2;
double b2;
_longitudeOrigin = deg2rad(longitudeOrigin);
_latitudeOrigin = deg2rad(latitudeOrigin);
_a = ellipsoid->radius();
_b = ellipsoid->b();
if (_longitudeOrigin > M_PI)
_longitudeOrigin -= 2 * M_PI;
_falseNorthing = falseNorthing;
_falseEasting = falseEasting;
a2 = _a * _a;
b2 = _b * _b;
_es2 = (a2 - b2) / a2;
_es4 = _es2 * _es2;
_es6 = _es4 * _es2;
j = 45.0 * _es6 / 1024.0;
three_es4 = 3.0 * _es4;
_c0 = 1.0 - _es2 / 4.0 - three_es4 / 64.0 - 5.0 * _es6 / 256.0;
_c1 = 3.0 * _es2 / 8.0 + three_es4 / 32.0 + j;
_c2 = 15.0 * _es4 / 256.0 + j;
_c3 = 35.0 * _es6 / 3072.0;
lat = _c0 * _latitudeOrigin;
sin2lat = POLY_COEFF_TIMES_SIN(_c1, 2.0, _latitudeOrigin);
sin4lat = POLY_COEFF_TIMES_SIN(_c2, 4.0, _latitudeOrigin);
sin6lat = POLY_COEFF_TIMES_SIN(_c3, 6.0, _latitudeOrigin);
_M0 = POLY_M(lat, sin2lat, sin4lat, sin6lat);
}
PointD Polyconic::ll2xy(const Coordinates &c) const
{
double Longitude = deg2rad(c.lon());
double Latitude = deg2rad(c.lat());
double slat = sin(Latitude);
double lat, sin2lat, sin4lat, sin6lat;
double dlam;
double NN;
double NN_OVER_tlat;
double MM;
double EE;
dlam = Longitude - _longitudeOrigin;
if (dlam > M_PI)
dlam -= 2 * M_PI;
if (dlam < -M_PI)
dlam += 2 * M_PI;
if (Latitude == 0.0) {
return PointD(_a * dlam + _falseEasting,
-_M0 + _falseNorthing);
} else {
NN = _a / sqrt(1.0 - _es2 * (slat * slat));
NN_OVER_tlat = NN / tan(Latitude);
lat = _c0 * Latitude;
sin2lat = POLY_COEFF_TIMES_SIN(_c1, 2.0, Latitude);
sin4lat = POLY_COEFF_TIMES_SIN(_c2, 4.0, Latitude);
sin6lat = POLY_COEFF_TIMES_SIN(_c3, 6.0, Latitude);
MM = POLY_M(lat, sin2lat, sin4lat, sin6lat);
EE = dlam * slat;
return PointD(NN_OVER_tlat * sin(EE) + _falseEasting,
MM - _M0 + NN_OVER_tlat * (1.0 - cos(EE)) + _falseNorthing);
}
}
Coordinates Polyconic::xy2ll(const PointD &p) const
{
double dx;
double dy;
double dx_OVER_Poly_a;
double AA;
double BB;
double CC = 0.0;
double PHIn, Delta_PHI = 1.0;
double sin_PHIn;
double PHI, sin2PHI, sin4PHI, sin6PHI;
double Mn, Mn_prime, Ma;
double AA_Ma;
double Ma2_PLUS_BB;
double AA_MINUS_Ma;
double tolerance = 1.0e-12;
double Latitude;
double Longitude;
dy = p.y() - _falseNorthing;
dx = p.x() - _falseEasting;
dx_OVER_Poly_a = dx / _a;
if (FLOAT_EQ(dy,-_M0,1)) {
Latitude = 0.0;
Longitude = dx_OVER_Poly_a + _longitudeOrigin;
} else {
AA = (_M0 + dy) / _a;
BB = dx_OVER_Poly_a * dx_OVER_Poly_a + (AA * AA);
PHIn = AA;
while (fabs(Delta_PHI) > tolerance) {
sin_PHIn = sin(PHIn);
CC = sqrt(1.0 - _es2 * sin_PHIn * sin_PHIn) * tan(PHIn);
PHI = _c0 * PHIn;
sin2PHI = POLY_COEFF_TIMES_SIN(_c1, 2.0, PHIn);
sin4PHI = POLY_COEFF_TIMES_SIN(_c2, 4.0, PHIn);
sin6PHI = POLY_COEFF_TIMES_SIN(_c3, 6.0, PHIn);
Mn = POLY_M(PHI, sin2PHI, sin4PHI, sin6PHI);
Mn_prime = _c0 - 2.0 * _c1 * cos(2.0 * PHIn) + 4.0 * _c2
* cos(4.0 * PHIn) - 6.0 * _c3 * cos(6.0 * PHIn);
Ma = Mn / _a;
AA_Ma = AA * Ma;
Ma2_PLUS_BB = Ma * Ma + BB;
AA_MINUS_Ma = AA - Ma;
Delta_PHI = (AA_Ma * CC + AA_MINUS_Ma - 0.5 * (Ma2_PLUS_BB) * CC) /
(_es2 * sin2PHI * (Ma2_PLUS_BB - 2.0 * AA_Ma) / 4.0 * CC
+ (AA_MINUS_Ma) * (CC * Mn_prime - 2.0 / sin2PHI) - Mn_prime);
PHIn -= Delta_PHI;
}
Latitude = PHIn;
if (Latitude > M_PI_2)
Latitude = M_PI_2;
else if (Latitude < -M_PI_2)
Latitude = -M_PI_2;
if (FLOAT_EQ(fabs(Latitude), M_PI_2, 0.00001) || (Latitude == 0))
Longitude = _longitudeOrigin;
else
Longitude = (asin(dx_OVER_Poly_a * CC)) / sin(Latitude)
+ _longitudeOrigin;
}
if (Longitude > M_PI)
Longitude -= 2 * M_PI;
if (Longitude < -M_PI)
Longitude += 2 *M_PI;
if (Longitude > M_PI)
Longitude = M_PI;
else if (Longitude < -M_PI)
Longitude = -M_PI;
return Coordinates(rad2deg(Longitude), rad2deg(Latitude));
}
bool Polyconic::operator==(const CT &ct) const
{
const Polyconic *other = dynamic_cast<const Polyconic*>(&ct);
return (other != 0 && _a == other->_a && _b == other->_b
&& _latitudeOrigin == other->_latitudeOrigin
&& _longitudeOrigin == other->_longitudeOrigin
&& _falseNorthing == other->_falseNorthing
&& _falseEasting == other->_falseEasting);
}

37
src/map/polyconic.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef POLYCONIC_H
#define POLYCONIC_H
#include "ct.h"
class Ellipsoid;
class Polyconic : public CT
{
public:
Polyconic(const Ellipsoid *ellipsoid, double latitudeOrigin,
double longitudeOrigin, double falseEasting, double falseNorthing);
virtual CT *clone() const {return new Polyconic(*this);}
virtual bool operator==(const CT &ct) const;
virtual PointD ll2xy(const Coordinates &c) const;
virtual Coordinates xy2ll(const PointD &p) const;
private:
double _a;
double _b;
double _es2;
double _es4;
double _es6;
double _M0;
double _c0;
double _c1;
double _c2;
double _c3;
double _longitudeOrigin;
double _latitudeOrigin;
double _falseEasting;
double _falseNorthing;
};
#endif // POLYCONIC_H

View File

@ -8,6 +8,7 @@
#include "krovak.h"
#include "polarstereographic.h"
#include "obliquestereographic.h"
#include "polyconic.h"
#include "latlon.h"
#include "gcs.h"
#include "pcs.h"
@ -25,6 +26,7 @@ Projection::Method::Method(int id)
case 9807:
case 9809:
case 9815:
case 9818:
case 9819:
case 9820:
case 9822:
@ -85,6 +87,11 @@ Projection::Projection(const PCS *pcs) : _gcs(0), _ct(0), _geographic(false)
setup.longitudeOrigin(), setup.scale(), setup.falseEasting(),
setup.falseNorthing());
break;
case 9818:
_ct = new Polyconic(ellipsoid, setup.latitudeOrigin(),
setup.longitudeOrigin(), setup.falseEasting(),
setup.falseNorthing());
break;
case 9819:
_ct = new Krovak(ellipsoid, setup.standardParallel1(),
setup.standardParallel2(), setup.scale(), setup.latitudeOrigin(),

View File

@ -1,3 +1,4 @@
#include <cmath>
#include "common/rectc.h"
#include "projection.h"
#include "rectd.h"
@ -5,67 +6,54 @@
static void growRect(const Projection &proj, const Coordinates &c, RectD &rect)
{
if (c.isNull())
return;
PointD p(proj.ll2xy(c));
if (rect.isNull())
rect = RectD(p, p);
else {
if (p.x() < rect.left())
rect.setLeft(p.x());
if (p.x() > rect.right())
rect.setRight(p.x());
if (p.y() < rect.bottom())
rect.setBottom(p.y());
if (p.y() > rect.top())
rect.setTop(p.y());
}
if (p.x() < rect.left())
rect.setLeft(p.x());
if (p.x() > rect.right())
rect.setRight(p.x());
if (p.y() > rect.top())
rect.setTop(p.y());
if (p.y() < rect.bottom())
rect.setBottom(p.y());
}
static void growRect(const Projection &proj, const PointD &p, RectC &rect)
{
if (p.isNull())
return;
Coordinates c(proj.xy2ll(p));
if (rect.isNull())
rect = RectC(c, c);
else {
if (c.lon() < rect.left())
rect.setLeft(c.lon());
if (c.lon() > rect.right())
rect.setRight(c.lon());
if (c.lat() < rect.bottom())
rect.setBottom(c.lat());
if (c.lat() > rect.top())
rect.setTop(c.lat());
}
if (c.lon() < rect.left())
rect.setLeft(c.lon());
if (c.lon() > rect.right())
rect.setRight(c.lon());
if (c.lat() > rect.top())
rect.setTop(c.lat());
if (c.lat() < rect.bottom())
rect.setBottom(c.lat());
}
RectD::RectD(const RectC &rect, const Projection &proj, int samples)
{
RectD prect;
double dx = (rect.right() - rect.left()) / samples;
double dy = (rect.top() - rect.bottom()) / samples;
if (!rect.isValid())
return;
growRect(proj, rect.topLeft(), prect);
double dx = rect.width() / samples;
double dy = rect.height() / samples;
if (dx > 0) {
for (int i = 0; i <= samples; i++) {
double x = rect.left() + i * dx;
growRect(proj, Coordinates(x, rect.bottom()), prect);
growRect(proj, Coordinates(x, rect.top()), prect);
}
PointD tl(proj.ll2xy(rect.topLeft()));
PointD br(proj.ll2xy(rect.bottomRight()));
RectD prect(tl, br);
for (int i = 0; i <= samples; i++) {
double x = remainder(rect.left() + i * dx, 360.0);
growRect(proj, Coordinates(x, rect.bottom()), prect);
growRect(proj, Coordinates(x, rect.top()), prect);
}
if (dy > 0) {
for (int i = 0; i <= samples; i++ ) {
double y = rect.bottom() + i * dy;
growRect(proj, Coordinates(rect.left(), y), prect);
growRect(proj, Coordinates(rect.right(), y), prect);
}
for (int i = 0; i <= samples; i++) {
double y = rect.bottom() + i * dy;
growRect(proj, Coordinates(rect.left(), y), prect);
growRect(proj, Coordinates(rect.right(), y), prect);
}
*this = prect;
@ -73,26 +61,26 @@ RectD::RectD(const RectC &rect, const Projection &proj, int samples)
RectC RectD::toRectC(const Projection &proj, int samples) const
{
RectC ret;
double dx = (right() - left()) / samples;
double dy = (top() - bottom()) / samples;
if (!isValid())
return RectC();
growRect(proj, topLeft(), ret);
double dx = width() / samples;
double dy = height() / samples;
if (dx > 0) {
for (int i = 0; i <= samples; i++) {
double x = left() + i * dx;
growRect(proj, PointD(x, bottom()), ret);
growRect(proj, PointD(x, top()), ret);
}
}
if (dy > 0) {
for (int i = 0; i <= samples; i++ ) {
double y = bottom() + i * dy;
growRect(proj, PointD(left(), y), ret);
growRect(proj, PointD(right(), y), ret);
}
Coordinates c(proj.xy2ll(center()));
RectC rect(c, c);
for (int i = 0; i <= samples; i++) {
double x = left() + i * dx;
growRect(proj, PointD(x, bottom()), rect);
growRect(proj, PointD(x, top()), rect);
}
return ret;
for (int i = 0; i <= samples; i++) {
double y = bottom() + i * dy;
growRect(proj, PointD(left(), y), rect);
growRect(proj, PointD(right(), y), rect);
}
return rect;
}

View File

@ -16,6 +16,9 @@ public:
PointD topLeft() const {return _tl;}
PointD bottomRight() const {return _br;}
PointD center() const
{return PointD((_tl.x() + _br.x()) / 2.0,
(_tl.y() + _br.y()) / 2.0);}
double left() const {return _tl.x();}
double right() const {return _br.x();}
@ -35,7 +38,9 @@ public:
&& p.y() >= bottom());}
bool isNull() const {return _tl.isNull() && _br.isNull();}
bool isValid() const {return !(_tl.isNull() || _br.isNull());}
bool isValid() const
{return (_tl.isValid() && _br.isValid()
&& _tl.x() != _br.x() && _tl.y() != _br.y());}
RectC toRectC(const Projection &proj, int samples = 100) const;

View File

@ -161,7 +161,8 @@ bool RMap::parseIMP(const QByteArray &data)
}
RMap::RMap(const QString &fileName, QObject *parent)
: Map(parent), _mapRatio(1.0), _fileName(fileName), _zoom(0), _valid(false)
: Map(fileName, parent), _mapRatio(1.0), _fileName(fileName), _zoom(0),
_valid(false)
{
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {

View File

@ -67,8 +67,9 @@ void WMSMap::updateTransform()
PointD(pixelSpan, pixelSpan));
}
WMSMap::WMSMap(const QString &name, const WMS::Setup &setup, int tileSize,
QObject *parent) : Map(parent), _name(name), _tileLoader(0), _zoom(0),
WMSMap::WMSMap(const QString &fileName, const QString &name,
const WMS::Setup &setup, int tileSize, QObject *parent)
: Map(fileName, parent), _name(name), _tileLoader(0), _zoom(0),
_tileSize(tileSize), _mapRatio(1.0)
{
QString tilesDir(QDir(ProgramPaths::tilesDir()).filePath(_name));

View File

@ -14,12 +14,13 @@ class WMSMap : public Map
Q_OBJECT
public:
WMSMap(const QString &name, const WMS::Setup &setup, int tileSize,
QObject *parent = 0);
WMSMap(const QString &fileName, const QString &name, const WMS::Setup &setup,
int tileSize, QObject *parent = 0);
QString name() const {return _name;}
QRectF bounds();
RectC llBounds() {return _wms->bbox();}
int zoom() const {return _zoom;}
void setZoom(int zoom);

View File

@ -12,9 +12,10 @@
#define CAPABILITIES_FILE "capabilities.xml"
WMTSMap::WMTSMap(const QString &name, const WMTS::Setup &setup, qreal tileRatio,
QObject *parent) : Map(parent), _name(name), _tileLoader(0), _zoom(0),
_mapRatio(1.0), _tileRatio(tileRatio)
WMTSMap::WMTSMap(const QString &fileName, const QString &name,
const WMTS::Setup &setup, qreal tileRatio,
QObject *parent) : Map(fileName, parent), _name(name), _tileLoader(0),
_zoom(0), _mapRatio(1.0), _tileRatio(tileRatio)
{
QString tilesDir(QDir(ProgramPaths::tilesDir()).filePath(_name));
@ -54,9 +55,9 @@ double WMTSMap::sd2res(double scaleDenominator) const
* _wmts->projection().units().fromMeters(1.0);
}
void WMTSMap::updateTransform()
Transform WMTSMap::transform(int zoom) const
{
const WMTS::Zoom &z = _wmts->zooms().at(_zoom);
const WMTS::Zoom &z = _wmts->zooms().at(zoom);
PointD topLeft = (_wmts->cs().axisOrder() == CoordinateSystem::YX)
? PointD(z.topLeft().y(), z.topLeft().x()) : z.topLeft();
@ -64,27 +65,50 @@ void WMTSMap::updateTransform()
double pixelSpan = sd2res(z.scaleDenominator());
if (_wmts->projection().isGeographic())
pixelSpan /= deg2rad(WGS84_RADIUS);
_transform = Transform(ReferencePoint(PointD(0, 0), topLeft),
return Transform(ReferencePoint(PointD(0, 0), topLeft),
PointD(pixelSpan, pixelSpan));
}
QRectF WMTSMap::bounds()
QRectF WMTSMap::tileBounds(int zoom) const
{
const WMTS::Zoom &z = _wmts->zooms().at(_zoom);
QRectF tileBounds, bounds;
const WMTS::Zoom &z = _wmts->zooms().at(zoom);
tileBounds = (z.limits().isNull()) ?
QRectF(QPointF(0, 0), QSize(z.tile().width() * z.matrix().width(),
return (z.limits().isNull())
? QRectF(QPointF(0, 0), QSize(z.tile().width() * z.matrix().width(),
z.tile().height() * z.matrix().height()))
: QRectF(QPointF(z.limits().left() * z.tile().width(), z.limits().top()
* z.tile().height()), QSize(z.tile().width() * z.limits().width(),
z.tile().height() * z.limits().height()));
}
if (_bounds.isValid())
bounds = QRectF(_transform.proj2img(_bounds.topLeft())
/ coordinatesRatio(), _transform.proj2img(
_bounds.bottomRight()) / coordinatesRatio());
return bounds.isValid() ? tileBounds.intersected(bounds) : tileBounds;
void WMTSMap::updateTransform()
{
_transform = transform(_zoom);
}
QRectF WMTSMap::bounds()
{
QRectF tb(tileBounds(_zoom));
QRectF lb = _bounds.isValid()
? QRectF(_transform.proj2img(_bounds.topLeft()) / coordinatesRatio(),
_transform.proj2img(_bounds.bottomRight()) / coordinatesRatio())
: QRectF();
return lb.isValid() ? lb & tb : tb;
}
RectC WMTSMap::llBounds()
{
if (_wmts->bbox().isValid())
return _wmts->bbox();
else {
int maxZoom = _wmts->zooms().size() - 1;
QRectF tb(tileBounds(maxZoom));
Transform t(transform(maxZoom));
RectD rect(t.img2proj(tb.topLeft() * coordinatesRatio()),
t.img2proj(tb.bottomRight() * coordinatesRatio()));
return rect.toRectC(_wmts->projection());
}
}
int WMTSMap::zoomFit(const QSize &size, const RectC &rect)

View File

@ -14,12 +14,13 @@ class WMTSMap : public Map
Q_OBJECT
public:
WMTSMap(const QString &name, const WMTS::Setup &setup, qreal tileRatio,
QObject *parent = 0);
WMTSMap(const QString &fileName, const QString &name,
const WMTS::Setup &setup, qreal tileRatio, QObject *parent = 0);
QString name() const {return _name;}
QRectF bounds();
RectC llBounds();
int zoom() const {return _zoom;}
void setZoom(int zoom);
@ -45,6 +46,8 @@ private slots:
private:
double sd2res(double scaleDenominator) const;
Transform transform(int zoom) const;
QRectF tileBounds(int zoom) const;
void updateTransform();
QSizeF tileSize(const WMTS::Zoom &zoom) const;
qreal coordinatesRatio() const;