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

Compare commits

..

97 Commits
5.2 ... 5.6

Author SHA1 Message Date
b4cf614f77 Added missing "other sample dimensions" support for WMS 2018-04-08 19:13:16 +02:00
ca710b6a22 Fixed typo in german ts file
ts files update
2018-04-08 18:50:34 +02:00
c894e75c17 Adjusted stuff to comply with the new map version 1 xsd 2018-04-08 17:48:13 +02:00
259a15332e Fixed QT4 build 2018-04-07 23:04:26 +02:00
c4915891e7 Code cleanup 2018-04-07 18:42:25 +02:00
c5256b25e9 Added missing namespace 2018-04-05 21:13:48 +02:00
81b3a517f8 Use the correct axis order defaults for WMS/WMTS maps 2018-04-05 20:38:23 +02:00
3aa1ab4b4c Set a less restrictive lower bound for WMS scale denominators 2018-04-03 23:14:47 +02:00
d4fb8ed9c9 Fixed error reporting 2018-04-03 23:05:17 +02:00
fb16c3f2db Fixed tile cache reload logic 2018-04-03 22:36:08 +02:00
4096d87a6a Improved default WMS/WMTS style handling 2018-04-03 22:35:13 +02:00
68eac5b8cc Yet another WMS corner case handling fix 2018-04-03 01:14:58 +02:00
88d6904ded Yet another WMS bounding box computation fix 2018-04-03 00:08:01 +02:00
021558b114 Fixed QT4 build 2018-04-02 23:33:10 +02:00
b8815ca9f5 Fixed layer bounding box & scale denominator range joining 2018-04-02 23:27:42 +02:00
e845e216bd Added support for WMS multi-layer maps 2018-04-02 19:59:52 +02:00
60cc869ade The "default" style does not to be set wxplicitly 2018-04-02 18:30:57 +02:00
e3e8fdbacf Fixed WMS 1.1.x support
Added support for HTTP basic authorization
2018-04-01 20:01:25 +02:00
16f2d7ad34 Added support for WMS 1.1.x versions 2018-03-31 11:27:01 +02:00
aecda0e517 Version++ 2018-03-30 10:48:57 +02:00
bf3589812a Initial WMS support (no multi-layer support for now) 2018-03-30 10:25:05 +02:00
8821536419 Fixed most clazy warnings 2018-03-29 00:29:08 +02:00
bda24d9091 Use $HOME as the default open directory (on all platforms) 2018-03-28 02:01:27 +02:00
820e614921 Fixed broken data size copy 2018-03-26 01:02:31 +02:00
35703e3363 Refactoring 2018-03-22 20:00:30 +01:00
a54821863f Includes cleanup 2018-03-21 19:23:17 +01:00
5bc3b2ad05 Merge branch 'master' of https://github.com/tumic0/GPXSee 2018-03-21 19:10:42 +01:00
992fd2c5cd Code cleanup 2018-03-21 19:09:37 +01:00
4b4a1902ef Indent cleanup 2018-03-21 18:52:57 +01:00
7d3bc2112a Update gpxsee.desktop (#85)
Add Swedish translation
2018-03-20 21:29:45 +01:00
4ea2f0752a Do not display negative zeros.
Fixes #86
2018-03-20 21:17:20 +01:00
0bb3b3812c Fixed broken release builds 2018-03-19 22:40:49 +01:00
b23639bef2 Version++ 2018-03-19 20:11:12 +01:00
2d8bf2dbb9 Added missing Swiss grid map file support 2018-03-19 19:56:31 +01:00
29efa84075 Do not depend on the initializing ellipsoid 2018-03-19 19:13:48 +01:00
3d06fe8831 Also clear the error URLs when clearing the tile cache.
Code cleanup.
2018-03-15 18:46:34 +01:00
fe1f6c80b4 Use the correct units for azimuths 2018-03-15 00:27:44 +01:00
35d1e69d7f Merge branch 'master' of https://github.com/tumic0/GPXSee 2018-03-14 07:25:28 +01:00
3043128565 Added finite HTTP response timeout 2018-03-14 07:23:07 +01:00
e56a9e33f3 Added ETRS-TM35FIN (#82) 2018-03-13 09:17:59 +01:00
07aca435d8 Update gpxsee_sv.ts (#81)
Latest strings translated
2018-03-12 20:54:10 +01:00
4e4a3d042a Translations update (#80) 2018-03-12 20:53:15 +01:00
bf5ae22f0d Handle the WGS84 ellipsoid only definitions like the GRS80 ellipsoid only definitions 2018-03-12 20:05:53 +01:00
309fdb675c Removed unused definitions 2018-03-11 20:53:16 +01:00
e0daf367fb Added support for WGS84 GeoTIFF images with the GCS defined using the ellipsoid only 2018-03-11 20:11:42 +01:00
32d8672698 REST variables (dimensions) are apparently case-insensitive 2018-03-11 19:23:40 +01:00
0ef89e200d Translations update 2018-03-11 16:28:30 +01:00
6d6c232dba Version++ 2018-03-11 10:49:02 +01:00
8132ff722d Added support for WMTS dimensions 2018-03-11 10:31:41 +01:00
49792064d7 Fixed error handling 2018-03-11 09:24:04 +01:00
7aef81d823 Added support for EPSG 21781 PCS (Swiss grid)
Fixed swapped LCC1 and LCC2 GeoTIFF coordinate transformation codes
2018-03-11 01:10:24 +01:00
1d3d1aa5b7 Fixed broken zoom rectangle computation 2018-03-10 21:04:14 +01:00
bcd14726f3 Added pace info 2018-03-10 20:25:13 +01:00
fd15799114 Includes cleanup 2018-03-10 09:25:52 +01:00
a8bc2ae4c4 Fixed wrong data type 2018-03-10 08:40:55 +01:00
67aba4703b Some more code cleanup 2018-03-09 23:24:08 +01:00
a64e5e13c3 Remove the 1px offset workaround as it does not work properly anyway... 2018-03-09 21:53:06 +01:00
60fcff7658 Code cleanup 2018-03-09 18:57:23 +01:00
bc881836ac Improved map index caching 2018-03-09 18:56:54 +01:00
de05f5e64b Some more offline map code cleanup 2018-03-08 19:08:39 +01:00
16476dbf74 Offline map code cleanup/refactoring 2018-03-08 02:24:10 +01:00
a21464d98d Added missing virtual destructors 2018-03-08 00:57:09 +01:00
d6746bc444 Code cleanup 2018-03-06 19:28:07 +01:00
e4d8af2040 Update README.md 2018-03-01 20:30:02 +01:00
b40e0d3bbf Fixed accessing of un-initialized variable 2018-03-01 19:06:55 +01:00
9300d671a1 Fixed invalid memory access 2018-03-01 19:06:34 +01:00
b9ed0c3933 Improved scale computation on offline & WMTS maps 2018-02-28 22:19:46 +01:00
46cefada94 Code cleanup 2018-02-27 21:50:29 +01:00
e1e49b32e6 Added some more map definition checking 2018-02-27 01:02:22 +01:00
fa99d01a77 Extended error checking 2018-02-26 22:35:58 +01:00
688e309ef7 Update gpxsee_sv.ts (#79)
Change shortcut letter for "Data"
2018-02-26 19:22:34 +01:00
ae4723acb1 Added GCS 4178 and related PCSs 2018-02-26 19:21:00 +01:00
8c6f70d837 Code cleanup 2018-02-26 19:13:57 +01:00
d1b0e2ef73 Improved error reporting 2018-02-26 19:05:53 +01:00
962310df7d Fixed single point zoom fit on WMTS maps 2018-02-25 19:33:12 +01:00
f8c031e931 Translation update/cleanup 2018-02-25 09:31:19 +01:00
8022a9efbe Update gpxsee_sv.ts (#78) 2018-02-25 09:18:10 +01:00
fbab4b0097 Made the axis order an attribute of the set rather than a separate element 2018-02-25 08:58:40 +01:00
5e5ff6d96f Added support for REST WMTS maps 2018-02-25 02:31:01 +01:00
55e967673c Use image/png as the default image format 2018-02-24 22:31:37 +01:00
757ba6a566 Fixed QT4 build 2018-02-24 16:48:38 +01:00
ee80260e46 Improved capabilities xml parsing
Improved bounds handling
2018-02-24 16:44:30 +01:00
fa3e6d8550 Added error checking 2018-02-24 11:40:54 +01:00
6e95d484cd Added support for OGC:CRS84 CRS to WMTS maps 2018-02-24 11:20:29 +01:00
376587202b Properly handling non-integer tile matrix ids 2018-02-24 10:34:27 +01:00
d11ffc9ea4 Added tile matrix set limits handling
Added axis order setting
2018-02-24 01:59:03 +01:00
bf6ebdc088 Translations update (#77) 2018-02-23 00:13:49 +01:00
619df591e2 Added support for geographic2d "projected" WMTS maps 2018-02-22 21:02:56 +01:00
10aa7d3945 Code cleanup 2018-02-22 18:12:47 +01:00
12319fd8fd Cleanup 2018-02-22 18:07:51 +01:00
ccb7336e3f Added menu accelerator keys 2018-02-22 08:18:10 +01:00
a7fea3878c Version++ 2018-02-22 00:56:49 +01:00
a6cf88aa92 Fixed visual artefacts on transparent tiles 2018-02-22 00:50:45 +01:00
b054cf9046 Using the correct projection for Lambert azimuthal equal area 2018-02-22 00:46:05 +01:00
9c5153f89a Fixed QT4 build 2018-02-21 00:13:11 +01:00
2ebcdeeeff Added ETRS89 data 2018-02-20 23:38:29 +01:00
1bc4833a81 Added initial WMTS support 2018-02-20 23:37:19 +01:00
97 changed files with 6048 additions and 3631 deletions

View File

@ -1,4 +1,4 @@
version: 5.2.{build}
version: 5.6.{build}
configuration: Release
platform: Any CPU
environment:

View File

@ -3,7 +3,7 @@ GPXSee is a Qt-based GPS log file viewer and analyzer that supports GPX, TCX,
KML, FIT, IGC and NMEA files.
## Features
* User-definable online maps.
* User-definable online maps (OSM/Google tiles, WMTS).
* Offline maps (OziExplorer maps, TrekBuddy maps/atlases, GeoTIFF images).
* Elevation, speed, heart rate, cadence, power and temperature graphs.
* Support for multiple tracks in one view.

View File

@ -1,5 +1,5 @@
TARGET = GPXSee
VERSION = 5.2
VERSION = 5.6
QT += core \
gui \
network
@ -116,7 +116,14 @@ HEADERS += src/config.h \
src/map/primemeridian.h \
src/map/linearunits.h \
src/map/ct.h \
src/map/mapsource.h
src/map/mapsource.h \
src/map/tileloader.h \
src/map/wmtsmap.h \
src/map/wmts.h \
src/map/wmsmap.h \
src/map/wms.h \
src/map/crs.h \
src/map/coordinatesystem.h
SOURCES += src/main.cpp \
src/common/coordinates.cpp \
src/common/rectc.cpp \
@ -202,7 +209,14 @@ SOURCES += src/main.cpp \
src/map/angularunits.cpp \
src/map/primemeridian.cpp \
src/map/linearunits.cpp \
src/map/mapsource.cpp
src/map/mapsource.cpp \
src/map/tileloader.cpp \
src/map/wmtsmap.cpp \
src/map/wmts.cpp \
src/map/wmsmap.cpp \
src/map/wms.cpp \
src/map/crs.cpp \
src/map/coordinatesystem.cpp
RESOURCES += gpxsee.qrc
TRANSLATIONS = lang/gpxsee_cs.ts \
lang/gpxsee_sv.ts \

View File

@ -301,376 +301,380 @@
<context>
<name>GUI</name>
<message>
<location filename="../src/GUI/gui.cpp" line="588"/>
<location filename="../src/GUI/gui.cpp" line="592"/>
<source>GPXSee is distributed under the terms of the GNU General Public License version 3. For more info about GPXSee visit the project homepage at </source>
<translation>Program GPXSee je distribuován pod podmínkami licence GNU General Public License verze 3. Pro více informací navštivte stránky programu na adrese </translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="662"/>
<location filename="../src/GUI/gui.cpp" line="666"/>
<source>Open file</source>
<translation>Otevřít soubor</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="751"/>
<location filename="../src/GUI/gui.cpp" line="757"/>
<source>Open POI file</source>
<translation>Otevřít POI soubor</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="195"/>
<location filename="../src/GUI/gui.cpp" line="199"/>
<source>Quit</source>
<translation>Ukončit</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="204"/>
<location filename="../src/GUI/gui.cpp" line="605"/>
<location filename="../src/GUI/gui.cpp" line="606"/>
<location filename="../src/GUI/gui.cpp" line="208"/>
<location filename="../src/GUI/gui.cpp" line="609"/>
<location filename="../src/GUI/gui.cpp" line="610"/>
<source>Keyboard controls</source>
<translation>Ovládací klávesy</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="229"/>
<location filename="../src/GUI/gui.cpp" line="233"/>
<source>Close</source>
<translation>Zavřít</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="235"/>
<location filename="../src/GUI/gui.cpp" line="239"/>
<source>Reload</source>
<translation>Znovu načíst</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="517"/>
<location filename="../src/GUI/gui.cpp" line="521"/>
<source>Show</source>
<translation>Zobrazit</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="428"/>
<location filename="../src/GUI/gui.cpp" line="511"/>
<location filename="../src/GUI/gui.cpp" line="515"/>
<source>File</source>
<translation>Soubor</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="246"/>
<location filename="../src/GUI/gui.cpp" line="250"/>
<source>Close POI files</source>
<translation>Zavřit POI soubory</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="248"/>
<location filename="../src/GUI/gui.cpp" line="252"/>
<source>Overlap POIs</source>
<translation>Překrývat POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="252"/>
<location filename="../src/GUI/gui.cpp" line="256"/>
<source>Show POI labels</source>
<translation>Zobrazit názvy POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="257"/>
<location filename="../src/GUI/gui.cpp" line="261"/>
<source>Show POIs</source>
<translation>Zobrazit POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="266"/>
<location filename="../src/GUI/gui.cpp" line="270"/>
<source>Show map</source>
<translation>Zobrazit mapu</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="276"/>
<location filename="../src/GUI/gui.cpp" line="280"/>
<source>Clear tile cache</source>
<translation>Vymazat mezipaměť dlaždic</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="213"/>
<location filename="../src/GUI/gui.cpp" line="217"/>
<source>Open...</source>
<translation>Otevřít...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="202"/>
<location filename="../src/GUI/gui.cpp" line="639"/>
<location filename="../src/GUI/gui.cpp" line="640"/>
<location filename="../src/GUI/gui.cpp" line="206"/>
<location filename="../src/GUI/gui.cpp" line="643"/>
<location filename="../src/GUI/gui.cpp" line="644"/>
<source>Paths</source>
<translation>Cesty</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="243"/>
<location filename="../src/GUI/gui.cpp" line="247"/>
<source>Load POI file...</source>
<translation>Nahrát POI soubor...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="274"/>
<location filename="../src/GUI/gui.cpp" line="278"/>
<source>Load map...</source>
<translation>Nahrát mapu...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="280"/>
<location filename="../src/GUI/gui.cpp" line="284"/>
<location filename="../src/GUI/gui.cpp" line="622"/>
<location filename="../src/GUI/gui.cpp" line="288"/>
<location filename="../src/GUI/gui.cpp" line="626"/>
<source>Next map</source>
<translation>Následující mapa</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="294"/>
<location filename="../src/GUI/gui.cpp" line="298"/>
<source>Show tracks</source>
<translation>Zobrazit cesty</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="298"/>
<location filename="../src/GUI/gui.cpp" line="302"/>
<source>Show routes</source>
<translation>Zobrazit trasy</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="302"/>
<location filename="../src/GUI/gui.cpp" line="306"/>
<source>Show waypoints</source>
<translation>Zobrazit navigační body</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="306"/>
<location filename="../src/GUI/gui.cpp" line="310"/>
<source>Waypoint labels</source>
<translation>Názvy navigačních bodů</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="317"/>
<location filename="../src/GUI/gui.cpp" line="321"/>
<source>Show graphs</source>
<translation>Zobrazit grafy</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="337"/>
<location filename="../src/GUI/gui.cpp" line="341"/>
<source>Show grid</source>
<translation>Zobrazit mřížku</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="341"/>
<location filename="../src/GUI/gui.cpp" line="345"/>
<source>Show slider info</source>
<translation>Zobrazit informace o posuvníku</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="347"/>
<location filename="../src/GUI/gui.cpp" line="351"/>
<source>Show toolbars</source>
<translation>Zobrazovat nástrojové lišty</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="353"/>
<location filename="../src/GUI/gui.cpp" line="357"/>
<source>Total time</source>
<translation>Celkový čas</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="358"/>
<location filename="../src/GUI/gui.cpp" line="926"/>
<location filename="../src/GUI/gui.cpp" line="362"/>
<location filename="../src/GUI/gui.cpp" line="934"/>
<source>Moving time</source>
<translation>Čistý čas</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="365"/>
<location filename="../src/GUI/gui.cpp" line="369"/>
<source>Metric</source>
<translation>Metrické</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="370"/>
<location filename="../src/GUI/gui.cpp" line="374"/>
<source>Imperial</source>
<translation>Imperiální</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="375"/>
<location filename="../src/GUI/gui.cpp" line="379"/>
<source>Nautical</source>
<translation>Námořní</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="382"/>
<location filename="../src/GUI/gui.cpp" line="386"/>
<source>Decimal degrees (DD)</source>
<translation>Desetinné stupně (DD)</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="387"/>
<location filename="../src/GUI/gui.cpp" line="391"/>
<source>Degrees and decimal minutes (DMM)</source>
<translation>Stupně a desetinné minuty (DMM)</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="393"/>
<location filename="../src/GUI/gui.cpp" line="397"/>
<source>Degrees, minutes, seconds (DMS)</source>
<translation>Stupně, minuty, vteřiny (DMS)</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="398"/>
<location filename="../src/GUI/gui.cpp" line="402"/>
<source>Fullscreen mode</source>
<translation>Celoobrazovkový režim</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="404"/>
<location filename="../src/GUI/gui.cpp" line="408"/>
<source>Options...</source>
<translation>Nastavení...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="410"/>
<location filename="../src/GUI/gui.cpp" line="414"/>
<source>Next</source>
<translation>Následující</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="413"/>
<location filename="../src/GUI/gui.cpp" line="417"/>
<source>Previous</source>
<translation>Předchozí</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="417"/>
<location filename="../src/GUI/gui.cpp" line="421"/>
<source>Last</source>
<translation>Poslední</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="420"/>
<location filename="../src/GUI/gui.cpp" line="424"/>
<source>First</source>
<translation>První</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="442"/>
<source>Map</source>
<translation>Mapa</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="450"/>
<source>Graph</source>
<translation>Graf</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="459"/>
<source>POI</source>
<translation>POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="460"/>
<location filename="../src/GUI/gui.cpp" line="464"/>
<source>POI files</source>
<translation>POI soubory</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="471"/>
<source>Data</source>
<translation>Data</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="472"/>
<location filename="../src/GUI/gui.cpp" line="476"/>
<source>Display</source>
<translation>Zobrazit</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="480"/>
<source>Settings</source>
<translation>Nastavení</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="484"/>
<location filename="../src/GUI/gui.cpp" line="488"/>
<source>Units</source>
<translation>Jednotky</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="488"/>
<location filename="../src/GUI/gui.cpp" line="492"/>
<source>Coordinates format</source>
<translation>Formát souřadnic</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="498"/>
<source>Help</source>
<translation>Nápověda</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="615"/>
<location filename="../src/GUI/gui.cpp" line="619"/>
<source>Append file</source>
<translation>Přidat soubor</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="616"/>
<location filename="../src/GUI/gui.cpp" line="620"/>
<source>Next/Previous</source>
<translation>Následující/Předchozí</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="618"/>
<location filename="../src/GUI/gui.cpp" line="622"/>
<source>Toggle graph type</source>
<translation>Přepnout typ grafu</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="620"/>
<location filename="../src/GUI/gui.cpp" line="624"/>
<source>Toggle time type</source>
<translation>Přepnout typ času</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="624"/>
<location filename="../src/GUI/gui.cpp" line="628"/>
<source>Previous map</source>
<translation>Předchozí mapa</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="625"/>
<location filename="../src/GUI/gui.cpp" line="629"/>
<source>Zoom in</source>
<translation>Přiblížit</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="627"/>
<location filename="../src/GUI/gui.cpp" line="631"/>
<source>Zoom out</source>
<translation>Oddálit</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="629"/>
<location filename="../src/GUI/gui.cpp" line="633"/>
<source>Digital zoom</source>
<translation>Digitální zoom</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="630"/>
<location filename="../src/GUI/gui.cpp" line="634"/>
<source>Zoom</source>
<translation>Zoom</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="1127"/>
<location filename="../src/GUI/gui.cpp" line="1135"/>
<source>Open map file</source>
<translation>Otevřít mapový soubor</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="1165"/>
<location filename="../src/GUI/gui.cpp" line="1175"/>
<source>No files loaded</source>
<translation>Nejsou načteny žádné soubory</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="912"/>
<location filename="../src/GUI/gui.cpp" line="915"/>
<location filename="../src/GUI/gui.cpp" line="920"/>
<location filename="../src/GUI/gui.cpp" line="923"/>
<source>Date</source>
<translation>Datum</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="643"/>
<location filename="../src/GUI/gui.cpp" line="432"/>
<source>&amp;File</source>
<translation>&amp;Soubor</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="446"/>
<source>&amp;Map</source>
<translation>&amp;Mapa</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="454"/>
<source>&amp;Graph</source>
<translation>&amp;Graf</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="463"/>
<source>&amp;POI</source>
<translation>&amp;POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="475"/>
<source>&amp;Data</source>
<translation>&amp;Data</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="484"/>
<source>&amp;Settings</source>
<translation>&amp;Nastavení</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="502"/>
<source>&amp;Help</source>
<translation>N&amp;ápověda</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="647"/>
<source>Map directory:</source>
<translation>Adresář s mapami:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="645"/>
<location filename="../src/GUI/gui.cpp" line="649"/>
<source>POI directory:</source>
<translation>Adresář s POI body:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="647"/>
<location filename="../src/GUI/gui.cpp" line="651"/>
<source>GCS file:</source>
<translation>Soubor s GCS daty:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="648"/>
<location filename="../src/GUI/gui.cpp" line="652"/>
<source>PCS file:</source>
<translation>Soubor s PCS daty:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="650"/>
<location filename="../src/GUI/gui.cpp" line="654"/>
<source>Ellipsoids file:</source>
<translation>Soubor s daty elipsoidů:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="653"/>
<location filename="../src/GUI/gui.cpp" line="657"/>
<source>User override directory:</source>
<translation>Uživatelský adresář:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="904"/>
<location filename="../src/GUI/gui.cpp" line="912"/>
<source>Routes</source>
<translation>Trasy</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="1154"/>
<location filename="../src/GUI/gui.cpp" line="1164"/>
<source>Error loading map:</source>
<translation>Mapu nelze načíst:</translation>
</message>
<message numerus="yes">
<location filename="../src/GUI/gui.cpp" line="1169"/>
<location filename="../src/GUI/gui.cpp" line="1179"/>
<source>%n files</source>
<translation>
<numerusform>%n soubor</numerusform>
@ -679,97 +683,97 @@
</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="609"/>
<location filename="../src/GUI/gui.cpp" line="613"/>
<source>Next file</source>
<translation>Následující soubor</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="585"/>
<location filename="../src/GUI/gui.cpp" line="589"/>
<source>Version </source>
<translation>Verze </translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="218"/>
<location filename="../src/GUI/gui.cpp" line="222"/>
<source>Print...</source>
<translation>Tisknout...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="223"/>
<location filename="../src/GUI/gui.cpp" line="227"/>
<source>Export to PDF...</source>
<translation>Exportovat do PDF...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="906"/>
<location filename="../src/GUI/gui.cpp" line="914"/>
<source>Waypoints</source>
<translation>Navigační body</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="610"/>
<location filename="../src/GUI/gui.cpp" line="614"/>
<source>Previous file</source>
<translation>Předchozí soubor</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="310"/>
<location filename="../src/GUI/gui.cpp" line="314"/>
<source>Route waypoints</source>
<translation>Body tras</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="612"/>
<location filename="../src/GUI/gui.cpp" line="616"/>
<source>First file</source>
<translation>První soubor</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="614"/>
<location filename="../src/GUI/gui.cpp" line="618"/>
<source>Last file</source>
<translation>Poslední soubor</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="740"/>
<location filename="../src/GUI/gui.cpp" line="746"/>
<source>Error loading data file:</source>
<translation>Datový soubor nelze načíst:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="743"/>
<location filename="../src/GUI/gui.cpp" line="768"/>
<location filename="../src/GUI/gui.cpp" line="749"/>
<location filename="../src/GUI/gui.cpp" line="776"/>
<source>Line: %1</source>
<translation>Řádka: %1</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="765"/>
<location filename="../src/GUI/gui.cpp" line="773"/>
<source>Error loading POI file:</source>
<translation>Soubor POI nelze načíst:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="898"/>
<location filename="../src/GUI/gui.cpp" line="906"/>
<source>Name</source>
<translation>Název</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="902"/>
<location filename="../src/GUI/gui.cpp" line="910"/>
<source>Tracks</source>
<translation>Cesty</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="207"/>
<location filename="../src/GUI/gui.cpp" line="584"/>
<location filename="../src/GUI/gui.cpp" line="211"/>
<location filename="../src/GUI/gui.cpp" line="588"/>
<source>About GPXSee</source>
<translation>O aplikaci GPXSee</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="522"/>
<location filename="../src/GUI/gui.cpp" line="526"/>
<source>Navigation</source>
<translation>Navigace</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="325"/>
<location filename="../src/GUI/gui.cpp" line="922"/>
<location filename="../src/GUI/gui.cpp" line="329"/>
<location filename="../src/GUI/gui.cpp" line="930"/>
<source>Distance</source>
<translation>Vzdálenost</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="331"/>
<location filename="../src/GUI/gui.cpp" line="481"/>
<location filename="../src/GUI/gui.cpp" line="924"/>
<location filename="../src/GUI/gui.cpp" line="335"/>
<location filename="../src/GUI/gui.cpp" line="485"/>
<location filename="../src/GUI/gui.cpp" line="932"/>
<source>Time</source>
<translation>Čas</translation>
</message>
@ -875,27 +879,27 @@
<context>
<name>MapList</name>
<message>
<location filename="../src/map/maplist.cpp" line="131"/>
<location filename="../src/map/maplist.cpp" line="130"/>
<source>Supported files</source>
<translation>Podporované soubory</translation>
</message>
<message>
<location filename="../src/map/maplist.cpp" line="132"/>
<location filename="../src/map/maplist.cpp" line="131"/>
<source>OziExplorer maps</source>
<translation>OziExplorer mapy</translation>
</message>
<message>
<location filename="../src/map/maplist.cpp" line="133"/>
<location filename="../src/map/maplist.cpp" line="132"/>
<source>TrekBuddy maps/atlases</source>
<translation>TrekBuddy mapy/atlasy</translation>
</message>
<message>
<location filename="../src/map/maplist.cpp" line="134"/>
<location filename="../src/map/maplist.cpp" line="133"/>
<source>GeoTIFF images</source>
<translation>GeoTIFF obrázky</translation>
</message>
<message>
<location filename="../src/map/maplist.cpp" line="135"/>
<location filename="../src/map/maplist.cpp" line="134"/>
<source>Online map sources</source>
<translation>Online mapové zdroje</translation>
</message>
@ -1380,33 +1384,53 @@
<context>
<name>SpeedGraph</name>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="14"/>
<location filename="../src/GUI/speedgraph.cpp" line="16"/>
<location filename="../src/GUI/speedgraph.h" line="14"/>
<source>Speed</source>
<translation>Rychlost</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="89"/>
<location filename="../src/GUI/speedgraph.cpp" line="96"/>
<source>km/h</source>
<translation>km/h</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="22"/>
<location filename="../src/GUI/speedgraph.cpp" line="28"/>
<source>Average</source>
<translation>Průměr</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="24"/>
<location filename="../src/GUI/speedgraph.cpp" line="25"/>
<source>min/km</source>
<translation>min/km</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="26"/>
<source>min/mi</source>
<translation>min/mi</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="26"/>
<source>min/nmi</source>
<translation>min/nmi</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="30"/>
<source>Maximum</source>
<translation>Maximum</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="83"/>
<location filename="../src/GUI/speedgraph.cpp" line="32"/>
<source>Pace</source>
<translation>Tempo</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="90"/>
<source>kn</source>
<translation>kn</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="86"/>
<location filename="../src/GUI/speedgraph.cpp" line="93"/>
<source>mi/h</source>
<translation>mi/h</translation>
</message>
@ -1414,30 +1438,50 @@
<context>
<name>SpeedGraphItem</name>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="22"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="23"/>
<source>km/h</source>
<translation>km/h</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="21"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="22"/>
<source>mi/h</source>
<translation>mi/h</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="22"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="23"/>
<source>kn</source>
<translation>kn</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="24"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="26"/>
<source>min/km</source>
<translation>min/km</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="27"/>
<source>min/mi</source>
<translation>min/mi</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="27"/>
<source>min/nmi</source>
<translation>min/nmi</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="29"/>
<source>Maximum</source>
<translation>Maximum</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="26"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="31"/>
<source>Average</source>
<translation>Průměr</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="33"/>
<source>Pace</source>
<translation>Tempo</translation>
</message>
</context>
<context>
<name>TemperatureGraph</name>

View File

@ -284,7 +284,7 @@
<message>
<location filename="../src/GUI/format.cpp" line="62"/>
<source>nmi</source>
<translation type="unfinished"></translation>
<translation>nmi</translation>
</message>
<message>
<location filename="../src/GUI/format.cpp" line="66"/>
@ -301,365 +301,334 @@
<context>
<name>GUI</name>
<message>
<location filename="../src/GUI/gui.cpp" line="588"/>
<location filename="../src/GUI/gui.cpp" line="592"/>
<source>GPXSee is distributed under the terms of the GNU General Public License version 3. For more info about GPXSee visit the project homepage at </source>
<translation>GPXSee wird unter der GNU General Public License version 3 vertrieben. Mehr Informationen zu GPXSee auf der Homepage </translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="643"/>
<location filename="../src/GUI/gui.cpp" line="647"/>
<source>Map directory:</source>
<translation>Kartenverzeichnis:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="645"/>
<location filename="../src/GUI/gui.cpp" line="649"/>
<source>POI directory:</source>
<translation>POI-Verzeichnis:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="647"/>
<location filename="../src/GUI/gui.cpp" line="651"/>
<source>GCS file:</source>
<translation>GCS-Datei:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="648"/>
<location filename="../src/GUI/gui.cpp" line="652"/>
<source>PCS file:</source>
<translation>PCS-Datei:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="650"/>
<location filename="../src/GUI/gui.cpp" line="654"/>
<source>Ellipsoids file:</source>
<translation>Ellipsoidendatei:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="653"/>
<location filename="../src/GUI/gui.cpp" line="657"/>
<source>User override directory:</source>
<translation>Benutzerverzeichnis:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="662"/>
<location filename="../src/GUI/gui.cpp" line="666"/>
<source>Open file</source>
<translation>Datei öffnen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="751"/>
<location filename="../src/GUI/gui.cpp" line="757"/>
<source>Open POI file</source>
<translation>POI Datei öffnen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="195"/>
<location filename="../src/GUI/gui.cpp" line="199"/>
<source>Quit</source>
<translation>Beenden</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="204"/>
<location filename="../src/GUI/gui.cpp" line="605"/>
<location filename="../src/GUI/gui.cpp" line="606"/>
<location filename="../src/GUI/gui.cpp" line="208"/>
<location filename="../src/GUI/gui.cpp" line="609"/>
<location filename="../src/GUI/gui.cpp" line="610"/>
<source>Keyboard controls</source>
<translation>Tastaturkürzel</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="229"/>
<location filename="../src/GUI/gui.cpp" line="233"/>
<source>Close</source>
<translation>Schließen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="235"/>
<location filename="../src/GUI/gui.cpp" line="239"/>
<source>Reload</source>
<translation>Neu Laden</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="517"/>
<location filename="../src/GUI/gui.cpp" line="521"/>
<source>Show</source>
<translation>Ansicht</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="428"/>
<location filename="../src/GUI/gui.cpp" line="511"/>
<location filename="../src/GUI/gui.cpp" line="515"/>
<source>File</source>
<translation>Datei</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="246"/>
<location filename="../src/GUI/gui.cpp" line="250"/>
<source>Close POI files</source>
<translation>POI-Datei schließen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="248"/>
<location filename="../src/GUI/gui.cpp" line="252"/>
<source>Overlap POIs</source>
<translation>POI überlappen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="252"/>
<location filename="../src/GUI/gui.cpp" line="256"/>
<source>Show POI labels</source>
<translation>POI-Labels anzeigen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="257"/>
<location filename="../src/GUI/gui.cpp" line="261"/>
<source>Show POIs</source>
<translation>POIs anzeigen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="266"/>
<location filename="../src/GUI/gui.cpp" line="270"/>
<source>Show map</source>
<translation>Karte anzeigen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="276"/>
<location filename="../src/GUI/gui.cpp" line="280"/>
<source>Clear tile cache</source>
<translation>Tile-Cache bereinigen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="213"/>
<location filename="../src/GUI/gui.cpp" line="217"/>
<source>Open...</source>
<translation>Öffnen...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="202"/>
<location filename="../src/GUI/gui.cpp" line="639"/>
<location filename="../src/GUI/gui.cpp" line="640"/>
<location filename="../src/GUI/gui.cpp" line="206"/>
<location filename="../src/GUI/gui.cpp" line="643"/>
<location filename="../src/GUI/gui.cpp" line="644"/>
<source>Paths</source>
<translation>Pfade</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="243"/>
<location filename="../src/GUI/gui.cpp" line="247"/>
<source>Load POI file...</source>
<translation>POI-Datei laden...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="274"/>
<location filename="../src/GUI/gui.cpp" line="278"/>
<source>Load map...</source>
<translation>Karte laden...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="280"/>
<location filename="../src/GUI/gui.cpp" line="284"/>
<location filename="../src/GUI/gui.cpp" line="622"/>
<location filename="../src/GUI/gui.cpp" line="288"/>
<location filename="../src/GUI/gui.cpp" line="626"/>
<source>Next map</source>
<translation>Nächste Karte</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="294"/>
<location filename="../src/GUI/gui.cpp" line="298"/>
<source>Show tracks</source>
<translation>Strecken anzeigen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="298"/>
<location filename="../src/GUI/gui.cpp" line="302"/>
<source>Show routes</source>
<translation>Routen anzeigen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="302"/>
<location filename="../src/GUI/gui.cpp" line="306"/>
<source>Show waypoints</source>
<translation>Wegpunkte anzeigen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="306"/>
<location filename="../src/GUI/gui.cpp" line="310"/>
<source>Waypoint labels</source>
<translation>Wegpunkt Labels</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="317"/>
<location filename="../src/GUI/gui.cpp" line="321"/>
<source>Show graphs</source>
<translation>Graphen anzeigen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="337"/>
<location filename="../src/GUI/gui.cpp" line="341"/>
<source>Show grid</source>
<translation>Gitter anzeigen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="341"/>
<location filename="../src/GUI/gui.cpp" line="345"/>
<source>Show slider info</source>
<translation>Schieberinfo anzeigen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="347"/>
<location filename="../src/GUI/gui.cpp" line="351"/>
<source>Show toolbars</source>
<translation>Toolbars anzeigen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="353"/>
<location filename="../src/GUI/gui.cpp" line="357"/>
<source>Total time</source>
<translation>Gesamtzeit</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="358"/>
<location filename="../src/GUI/gui.cpp" line="926"/>
<location filename="../src/GUI/gui.cpp" line="362"/>
<location filename="../src/GUI/gui.cpp" line="934"/>
<source>Moving time</source>
<translation>Bewegungszeit</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="365"/>
<location filename="../src/GUI/gui.cpp" line="369"/>
<source>Metric</source>
<translation>Metrisch</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="370"/>
<location filename="../src/GUI/gui.cpp" line="374"/>
<source>Imperial</source>
<translation>Imperial</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="375"/>
<location filename="../src/GUI/gui.cpp" line="379"/>
<source>Nautical</source>
<translation type="unfinished"></translation>
<translation>Nautisch</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="382"/>
<location filename="../src/GUI/gui.cpp" line="386"/>
<source>Decimal degrees (DD)</source>
<translation type="unfinished"></translation>
<translation>Dezimalgrad (DD)</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="387"/>
<location filename="../src/GUI/gui.cpp" line="391"/>
<source>Degrees and decimal minutes (DMM)</source>
<translation type="unfinished"></translation>
<translation>Grad und Dezimalminuten (DMM)</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="393"/>
<location filename="../src/GUI/gui.cpp" line="397"/>
<source>Degrees, minutes, seconds (DMS)</source>
<translation type="unfinished"></translation>
<translation>Grad, Minuten, Sekunden (DMS)</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="398"/>
<location filename="../src/GUI/gui.cpp" line="402"/>
<source>Fullscreen mode</source>
<translation>Vollbildmodus</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="404"/>
<location filename="../src/GUI/gui.cpp" line="408"/>
<source>Options...</source>
<translation>Einstellungen...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="410"/>
<location filename="../src/GUI/gui.cpp" line="414"/>
<source>Next</source>
<translation>Nächste</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="413"/>
<location filename="../src/GUI/gui.cpp" line="417"/>
<source>Previous</source>
<translation>Vorherige</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="417"/>
<location filename="../src/GUI/gui.cpp" line="421"/>
<source>Last</source>
<translation>Letzte</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="420"/>
<location filename="../src/GUI/gui.cpp" line="424"/>
<source>First</source>
<translation>Erste</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="442"/>
<source>Map</source>
<translation>Karte</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="450"/>
<source>Graph</source>
<translation>Graph</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="459"/>
<source>POI</source>
<translation>POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="460"/>
<location filename="../src/GUI/gui.cpp" line="464"/>
<source>POI files</source>
<translation>POI-Dateien</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="471"/>
<source>Data</source>
<translation>Daten</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="472"/>
<location filename="../src/GUI/gui.cpp" line="476"/>
<source>Display</source>
<translation>Anzeige</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="480"/>
<source>Settings</source>
<translation>Einstellungen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="484"/>
<location filename="../src/GUI/gui.cpp" line="488"/>
<source>Units</source>
<translation>Einheiten</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="488"/>
<location filename="../src/GUI/gui.cpp" line="492"/>
<source>Coordinates format</source>
<translation type="unfinished"></translation>
<translation>Koordinatenformate</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="498"/>
<source>Help</source>
<translation>Hilfe</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="615"/>
<location filename="../src/GUI/gui.cpp" line="619"/>
<source>Append file</source>
<translation>An Datei anhängen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="616"/>
<location filename="../src/GUI/gui.cpp" line="620"/>
<source>Next/Previous</source>
<translation>Nächste/Vorherige</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="618"/>
<location filename="../src/GUI/gui.cpp" line="622"/>
<source>Toggle graph type</source>
<translation>Graphtyp umschalten</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="620"/>
<location filename="../src/GUI/gui.cpp" line="624"/>
<source>Toggle time type</source>
<translation>Zeittyp umschalten</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="624"/>
<location filename="../src/GUI/gui.cpp" line="628"/>
<source>Previous map</source>
<translation>Vorherige Karte</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="625"/>
<location filename="../src/GUI/gui.cpp" line="629"/>
<source>Zoom in</source>
<translation>Hineinzoomen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="627"/>
<location filename="../src/GUI/gui.cpp" line="631"/>
<source>Zoom out</source>
<translation>Herauszoomen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="629"/>
<location filename="../src/GUI/gui.cpp" line="633"/>
<source>Digital zoom</source>
<translation>Digitaler Zoom</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="630"/>
<location filename="../src/GUI/gui.cpp" line="634"/>
<source>Zoom</source>
<translation>Zoom</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="1127"/>
<location filename="../src/GUI/gui.cpp" line="1135"/>
<source>Open map file</source>
<translation>Karte Datei öffnen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="1154"/>
<location filename="../src/GUI/gui.cpp" line="1164"/>
<source>Error loading map:</source>
<translation>Fehler beim Laden der Karte-Datei:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="1165"/>
<location filename="../src/GUI/gui.cpp" line="1175"/>
<source>No files loaded</source>
<translation>Keine Dateien geladen</translation>
</message>
<message numerus="yes">
<location filename="../src/GUI/gui.cpp" line="1169"/>
<location filename="../src/GUI/gui.cpp" line="1179"/>
<source>%n files</source>
<translation>
<numerusform>%n Datei</numerusform>
@ -667,108 +636,143 @@
</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="912"/>
<location filename="../src/GUI/gui.cpp" line="915"/>
<location filename="../src/GUI/gui.cpp" line="920"/>
<location filename="../src/GUI/gui.cpp" line="923"/>
<source>Date</source>
<translation>Datum</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="904"/>
<location filename="../src/GUI/gui.cpp" line="912"/>
<source>Routes</source>
<translation>Routen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="609"/>
<location filename="../src/GUI/gui.cpp" line="613"/>
<source>Next file</source>
<translation>Nächste Datei</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="585"/>
<location filename="../src/GUI/gui.cpp" line="589"/>
<source>Version </source>
<translation>Version </translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="218"/>
<location filename="../src/GUI/gui.cpp" line="222"/>
<source>Print...</source>
<translation>Drucken...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="223"/>
<location filename="../src/GUI/gui.cpp" line="227"/>
<source>Export to PDF...</source>
<translation>Als PDF exportieren...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="906"/>
<location filename="../src/GUI/gui.cpp" line="914"/>
<source>Waypoints</source>
<translation>Wegpunkte</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="610"/>
<location filename="../src/GUI/gui.cpp" line="614"/>
<source>Previous file</source>
<translation>Vorherige Datei</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="310"/>
<location filename="../src/GUI/gui.cpp" line="314"/>
<source>Route waypoints</source>
<translation>Routen Wegpunkte</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="612"/>
<location filename="../src/GUI/gui.cpp" line="432"/>
<source>&amp;File</source>
<translation>&amp;Datei</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="446"/>
<source>&amp;Map</source>
<translation>&amp;Map</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="454"/>
<source>&amp;Graph</source>
<translation>&amp;Graph</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="463"/>
<source>&amp;POI</source>
<translation>&amp;POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="475"/>
<source>&amp;Data</source>
<translation>D&amp;ata</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="484"/>
<source>&amp;Settings</source>
<translation>&amp;Einstellungen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="502"/>
<source>&amp;Help</source>
<translation>&amp;Hilfe</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="616"/>
<source>First file</source>
<translation>Erste Datei</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="614"/>
<location filename="../src/GUI/gui.cpp" line="618"/>
<source>Last file</source>
<translation>Letzte Datei</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="740"/>
<location filename="../src/GUI/gui.cpp" line="746"/>
<source>Error loading data file:</source>
<translation>Fehler beim Laden der Datei:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="743"/>
<location filename="../src/GUI/gui.cpp" line="768"/>
<location filename="../src/GUI/gui.cpp" line="749"/>
<location filename="../src/GUI/gui.cpp" line="776"/>
<source>Line: %1</source>
<translation>Linie: %1</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="765"/>
<location filename="../src/GUI/gui.cpp" line="773"/>
<source>Error loading POI file:</source>
<translation>Fehler beim Laden der POI-Datei:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="898"/>
<location filename="../src/GUI/gui.cpp" line="906"/>
<source>Name</source>
<translation>Name</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="902"/>
<location filename="../src/GUI/gui.cpp" line="910"/>
<source>Tracks</source>
<translation>Strecken</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="207"/>
<location filename="../src/GUI/gui.cpp" line="584"/>
<location filename="../src/GUI/gui.cpp" line="211"/>
<location filename="../src/GUI/gui.cpp" line="588"/>
<source>About GPXSee</source>
<translation>Über GPXSee</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="522"/>
<location filename="../src/GUI/gui.cpp" line="526"/>
<source>Navigation</source>
<translation>Navigation</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="325"/>
<location filename="../src/GUI/gui.cpp" line="922"/>
<location filename="../src/GUI/gui.cpp" line="329"/>
<location filename="../src/GUI/gui.cpp" line="930"/>
<source>Distance</source>
<translation>Distanz</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="331"/>
<location filename="../src/GUI/gui.cpp" line="481"/>
<location filename="../src/GUI/gui.cpp" line="924"/>
<location filename="../src/GUI/gui.cpp" line="335"/>
<location filename="../src/GUI/gui.cpp" line="485"/>
<location filename="../src/GUI/gui.cpp" line="932"/>
<source>Time</source>
<translation>Zeit</translation>
</message>
@ -799,7 +803,7 @@
<message>
<location filename="../src/GUI/graphview.cpp" line="120"/>
<source>nmi</source>
<translation type="unfinished"></translation>
<translation>nmi</translation>
</message>
<message>
<location filename="../src/GUI/graphview.cpp" line="134"/>
@ -874,27 +878,27 @@
<context>
<name>MapList</name>
<message>
<location filename="../src/map/maplist.cpp" line="131"/>
<location filename="../src/map/maplist.cpp" line="130"/>
<source>Supported files</source>
<translation>Unterstütze Dateien</translation>
</message>
<message>
<location filename="../src/map/maplist.cpp" line="132"/>
<location filename="../src/map/maplist.cpp" line="131"/>
<source>OziExplorer maps</source>
<translation>OziExplorer Karten</translation>
</message>
<message>
<location filename="../src/map/maplist.cpp" line="133"/>
<location filename="../src/map/maplist.cpp" line="132"/>
<source>TrekBuddy maps/atlases</source>
<translation>TrekBuddy Karten/Atlanten</translation>
</message>
<message>
<location filename="../src/map/maplist.cpp" line="134"/>
<location filename="../src/map/maplist.cpp" line="133"/>
<source>GeoTIFF images</source>
<translation>GeoTIFF Bilder</translation>
</message>
<message>
<location filename="../src/map/maplist.cpp" line="135"/>
<location filename="../src/map/maplist.cpp" line="134"/>
<source>Online map sources</source>
<translation>Online-Kartenquellen</translation>
</message>
@ -1121,7 +1125,7 @@
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="296"/>
<source>kn</source>
<translation type="unfinished"></translation>
<translation>kn</translation>
</message>
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="299"/>
@ -1161,7 +1165,7 @@
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="331"/>
<source>nmi</source>
<translation type="unfinished"></translation>
<translation>nmi</translation>
</message>
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="334"/>
@ -1363,7 +1367,7 @@
<message>
<location filename="../src/GUI/scaleitem.cpp" line="86"/>
<source>nmi</source>
<translation type="unfinished"></translation>
<translation>nmi</translation>
</message>
<message>
<location filename="../src/GUI/scaleitem.cpp" line="89"/>
@ -1379,33 +1383,53 @@
<context>
<name>SpeedGraph</name>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="14"/>
<location filename="../src/GUI/speedgraph.cpp" line="16"/>
<location filename="../src/GUI/speedgraph.h" line="14"/>
<source>Speed</source>
<translation>Geschwindigkeit</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="89"/>
<location filename="../src/GUI/speedgraph.cpp" line="96"/>
<source>km/h</source>
<translation>km/h</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="22"/>
<location filename="../src/GUI/speedgraph.cpp" line="28"/>
<source>Average</source>
<translation>Durchschnitt</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="24"/>
<location filename="../src/GUI/speedgraph.cpp" line="25"/>
<source>min/km</source>
<translation>min/km</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="26"/>
<source>min/mi</source>
<translation>min/mi</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="26"/>
<source>min/nmi</source>
<translation>min/nmi</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="30"/>
<source>Maximum</source>
<translation>Maximum</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="83"/>
<source>kn</source>
<translation type="unfinished"></translation>
<location filename="../src/GUI/speedgraph.cpp" line="32"/>
<source>Pace</source>
<translation>Tempo</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="86"/>
<location filename="../src/GUI/speedgraph.cpp" line="90"/>
<source>kn</source>
<translation>kn</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="93"/>
<source>mi/h</source>
<translation>mi/h</translation>
</message>
@ -1413,30 +1437,50 @@
<context>
<name>SpeedGraphItem</name>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="22"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="23"/>
<source>km/h</source>
<translation>km/h</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="21"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="22"/>
<source>mi/h</source>
<translation>mi/h</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="22"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="23"/>
<source>kn</source>
<translation type="unfinished"></translation>
<translation>kn</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="24"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="26"/>
<source>min/km</source>
<translation>min/km</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="27"/>
<source>min/mi</source>
<translation>min/mi</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="27"/>
<source>min/nmi</source>
<translation>min/nmi</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="29"/>
<source>Maximum</source>
<translation>Maximum</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="26"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="31"/>
<source>Average</source>
<translation>Durchschnitt</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="33"/>
<source>Pace</source>
<translation>Tempo</translation>
</message>
</context>
<context>
<name>TemperatureGraph</name>

View File

@ -301,376 +301,380 @@
<context>
<name>GUI</name>
<message>
<location filename="../src/GUI/gui.cpp" line="588"/>
<location filename="../src/GUI/gui.cpp" line="592"/>
<source>GPXSee is distributed under the terms of the GNU General Public License version 3. For more info about GPXSee visit the project homepage at </source>
<translation>GPXSee levitetään GNU yleisen lisenssin version 3 alaisena. Voit katsoa lisätietoja GPXSee:stä projektin kotisivulla </translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="662"/>
<location filename="../src/GUI/gui.cpp" line="666"/>
<source>Open file</source>
<translation>Avaa tiedosto</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="751"/>
<location filename="../src/GUI/gui.cpp" line="757"/>
<source>Open POI file</source>
<translation>Avaa POI-tiedosto</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="195"/>
<location filename="../src/GUI/gui.cpp" line="199"/>
<source>Quit</source>
<translation>Lopeta</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="204"/>
<location filename="../src/GUI/gui.cpp" line="605"/>
<location filename="../src/GUI/gui.cpp" line="606"/>
<location filename="../src/GUI/gui.cpp" line="208"/>
<location filename="../src/GUI/gui.cpp" line="609"/>
<location filename="../src/GUI/gui.cpp" line="610"/>
<source>Keyboard controls</source>
<translation>Näppäimistön säätimet</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="229"/>
<location filename="../src/GUI/gui.cpp" line="233"/>
<source>Close</source>
<translation>Sulje</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="235"/>
<location filename="../src/GUI/gui.cpp" line="239"/>
<source>Reload</source>
<translation>Lataa uudelleen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="517"/>
<location filename="../src/GUI/gui.cpp" line="521"/>
<source>Show</source>
<translation>Näytä</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="428"/>
<location filename="../src/GUI/gui.cpp" line="511"/>
<location filename="../src/GUI/gui.cpp" line="515"/>
<source>File</source>
<translation>Tiedosto</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="246"/>
<location filename="../src/GUI/gui.cpp" line="250"/>
<source>Close POI files</source>
<translation>Sulje POI-tiedostot</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="248"/>
<location filename="../src/GUI/gui.cpp" line="252"/>
<source>Overlap POIs</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="252"/>
<location filename="../src/GUI/gui.cpp" line="256"/>
<source>Show POI labels</source>
<translation>Näytä POI:n nimiöt</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="257"/>
<location filename="../src/GUI/gui.cpp" line="261"/>
<source>Show POIs</source>
<translation>Näytä POI:t</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="266"/>
<location filename="../src/GUI/gui.cpp" line="270"/>
<source>Show map</source>
<translation>Näytä kartta</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="276"/>
<location filename="../src/GUI/gui.cpp" line="280"/>
<source>Clear tile cache</source>
<translation>Tyhjennä välimuisti</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="213"/>
<location filename="../src/GUI/gui.cpp" line="217"/>
<source>Open...</source>
<translation>Avaa...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="202"/>
<location filename="../src/GUI/gui.cpp" line="639"/>
<location filename="../src/GUI/gui.cpp" line="640"/>
<location filename="../src/GUI/gui.cpp" line="206"/>
<location filename="../src/GUI/gui.cpp" line="643"/>
<location filename="../src/GUI/gui.cpp" line="644"/>
<source>Paths</source>
<translation>Tiedostopolut</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="243"/>
<location filename="../src/GUI/gui.cpp" line="247"/>
<source>Load POI file...</source>
<translation>Lataa POI-tiedosto...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="274"/>
<location filename="../src/GUI/gui.cpp" line="278"/>
<source>Load map...</source>
<translation>Lataa kartta...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="280"/>
<location filename="../src/GUI/gui.cpp" line="284"/>
<location filename="../src/GUI/gui.cpp" line="622"/>
<location filename="../src/GUI/gui.cpp" line="288"/>
<location filename="../src/GUI/gui.cpp" line="626"/>
<source>Next map</source>
<translation>Seuraava kartta</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="294"/>
<location filename="../src/GUI/gui.cpp" line="298"/>
<source>Show tracks</source>
<translation>Näytä jäljet</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="298"/>
<location filename="../src/GUI/gui.cpp" line="302"/>
<source>Show routes</source>
<translation>Näytä reitit</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="302"/>
<location filename="../src/GUI/gui.cpp" line="306"/>
<source>Show waypoints</source>
<translation>Näytä reittipisteet</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="306"/>
<location filename="../src/GUI/gui.cpp" line="310"/>
<source>Waypoint labels</source>
<translation>Reittipisteen nimiöt</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="317"/>
<location filename="../src/GUI/gui.cpp" line="321"/>
<source>Show graphs</source>
<translation>Näytä kaaviokuvat</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="337"/>
<location filename="../src/GUI/gui.cpp" line="341"/>
<source>Show grid</source>
<translation>Näytä ruudukko</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="341"/>
<location filename="../src/GUI/gui.cpp" line="345"/>
<source>Show slider info</source>
<translation>Näytä liukusäätimen arvo</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="347"/>
<location filename="../src/GUI/gui.cpp" line="351"/>
<source>Show toolbars</source>
<translation>Näytä työkalupalkit</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="353"/>
<location filename="../src/GUI/gui.cpp" line="357"/>
<source>Total time</source>
<translation>Kokonaisaika</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="358"/>
<location filename="../src/GUI/gui.cpp" line="926"/>
<location filename="../src/GUI/gui.cpp" line="362"/>
<location filename="../src/GUI/gui.cpp" line="934"/>
<source>Moving time</source>
<translation>Liikkumisaika</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="365"/>
<location filename="../src/GUI/gui.cpp" line="369"/>
<source>Metric</source>
<translation>Metriset</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="370"/>
<location filename="../src/GUI/gui.cpp" line="374"/>
<source>Imperial</source>
<translation>Brittiläiset</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="375"/>
<location filename="../src/GUI/gui.cpp" line="379"/>
<source>Nautical</source>
<translation>Merelliset</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="382"/>
<location filename="../src/GUI/gui.cpp" line="386"/>
<source>Decimal degrees (DD)</source>
<translation>Desimaaliasteet (DD)</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="387"/>
<location filename="../src/GUI/gui.cpp" line="391"/>
<source>Degrees and decimal minutes (DMM)</source>
<translation>Asteet, desimaaliminuutit (DMM)</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="393"/>
<location filename="../src/GUI/gui.cpp" line="397"/>
<source>Degrees, minutes, seconds (DMS)</source>
<translation>Asteet, minuutit, sekunnit (DMS)</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="398"/>
<location filename="../src/GUI/gui.cpp" line="402"/>
<source>Fullscreen mode</source>
<translation>Kokoruututila</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="404"/>
<location filename="../src/GUI/gui.cpp" line="408"/>
<source>Options...</source>
<translation>Valinnat...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="410"/>
<location filename="../src/GUI/gui.cpp" line="414"/>
<source>Next</source>
<translation>Seuraava</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="413"/>
<location filename="../src/GUI/gui.cpp" line="417"/>
<source>Previous</source>
<translation>Edellinen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="417"/>
<location filename="../src/GUI/gui.cpp" line="421"/>
<source>Last</source>
<translation>Viimeinen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="420"/>
<location filename="../src/GUI/gui.cpp" line="424"/>
<source>First</source>
<translation>Ensimmäinen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="442"/>
<source>Map</source>
<translation>Kartat</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="450"/>
<source>Graph</source>
<translation>Kaaviokuva</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="459"/>
<source>POI</source>
<translation>POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="460"/>
<location filename="../src/GUI/gui.cpp" line="464"/>
<source>POI files</source>
<translation>POI-tiedostot</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="471"/>
<source>Data</source>
<translation>Tiedot</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="472"/>
<location filename="../src/GUI/gui.cpp" line="476"/>
<source>Display</source>
<translation>Näytä</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="480"/>
<source>Settings</source>
<translation>Asetukset</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="484"/>
<location filename="../src/GUI/gui.cpp" line="488"/>
<source>Units</source>
<translation>Yksiköt</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="488"/>
<location filename="../src/GUI/gui.cpp" line="492"/>
<source>Coordinates format</source>
<translation>Koordinaattien muoto</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="498"/>
<source>Help</source>
<translation>Ohje</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="615"/>
<location filename="../src/GUI/gui.cpp" line="619"/>
<source>Append file</source>
<translation>Lisää tiedosto</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="616"/>
<location filename="../src/GUI/gui.cpp" line="620"/>
<source>Next/Previous</source>
<translation>Next/Previous</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="618"/>
<location filename="../src/GUI/gui.cpp" line="622"/>
<source>Toggle graph type</source>
<translation>Vaihda kaaviokuvan tyyppi</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="620"/>
<location filename="../src/GUI/gui.cpp" line="624"/>
<source>Toggle time type</source>
<translation>Vaihda ajan tyyppi</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="624"/>
<location filename="../src/GUI/gui.cpp" line="628"/>
<source>Previous map</source>
<translation>Edellinen kartta</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="625"/>
<location filename="../src/GUI/gui.cpp" line="629"/>
<source>Zoom in</source>
<translation>Lähennä</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="627"/>
<location filename="../src/GUI/gui.cpp" line="631"/>
<source>Zoom out</source>
<translation>Loitonna</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="629"/>
<location filename="../src/GUI/gui.cpp" line="633"/>
<source>Digital zoom</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="630"/>
<location filename="../src/GUI/gui.cpp" line="634"/>
<source>Zoom</source>
<translation>Zoom</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="1127"/>
<location filename="../src/GUI/gui.cpp" line="1135"/>
<source>Open map file</source>
<translation>Avaa karttatiedosto</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="1165"/>
<location filename="../src/GUI/gui.cpp" line="1175"/>
<source>No files loaded</source>
<translation>Yhtään tiedostoja ei ladattu</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="912"/>
<location filename="../src/GUI/gui.cpp" line="915"/>
<location filename="../src/GUI/gui.cpp" line="920"/>
<location filename="../src/GUI/gui.cpp" line="923"/>
<source>Date</source>
<translation>Päivämäärä</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="643"/>
<location filename="../src/GUI/gui.cpp" line="432"/>
<source>&amp;File</source>
<translation>&amp;Tiedosto</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="446"/>
<source>&amp;Map</source>
<translation>&amp;Kartat</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="454"/>
<source>&amp;Graph</source>
<translation>Kaa&amp;viokuva</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="463"/>
<source>&amp;POI</source>
<translation>&amp;POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="475"/>
<source>&amp;Data</source>
<translation>Tie&amp;dot</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="484"/>
<source>&amp;Settings</source>
<translation>&amp;Asetukset</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="502"/>
<source>&amp;Help</source>
<translation>&amp;Ohje</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="647"/>
<source>Map directory:</source>
<translation>Karttojen hakemisto:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="645"/>
<location filename="../src/GUI/gui.cpp" line="649"/>
<source>POI directory:</source>
<translation>POI:n hakemisto:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="647"/>
<location filename="../src/GUI/gui.cpp" line="651"/>
<source>GCS file:</source>
<translation>GCS-tiedosto:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="648"/>
<location filename="../src/GUI/gui.cpp" line="652"/>
<source>PCS file:</source>
<translation>PCS-tiedosto:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="650"/>
<location filename="../src/GUI/gui.cpp" line="654"/>
<source>Ellipsoids file:</source>
<translation>Ellipsoids-tiedosto:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="653"/>
<location filename="../src/GUI/gui.cpp" line="657"/>
<source>User override directory:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="904"/>
<location filename="../src/GUI/gui.cpp" line="912"/>
<source>Routes</source>
<translation>Reitit</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="1154"/>
<location filename="../src/GUI/gui.cpp" line="1164"/>
<source>Error loading map:</source>
<translation>Virhe ladattaessa karttaa:</translation>
</message>
<message numerus="yes">
<location filename="../src/GUI/gui.cpp" line="1169"/>
<location filename="../src/GUI/gui.cpp" line="1179"/>
<source>%n files</source>
<translation>
<numerusform>%n tiedosto</numerusform>
@ -678,97 +682,97 @@
</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="609"/>
<location filename="../src/GUI/gui.cpp" line="613"/>
<source>Next file</source>
<translation>Seuraava tiedosto</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="585"/>
<location filename="../src/GUI/gui.cpp" line="589"/>
<source>Version </source>
<translation>Versio </translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="218"/>
<location filename="../src/GUI/gui.cpp" line="222"/>
<source>Print...</source>
<translation>Tulosta...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="223"/>
<location filename="../src/GUI/gui.cpp" line="227"/>
<source>Export to PDF...</source>
<translation>Vie PDF:ksi...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="906"/>
<location filename="../src/GUI/gui.cpp" line="914"/>
<source>Waypoints</source>
<translation>Reittipisteet</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="610"/>
<location filename="../src/GUI/gui.cpp" line="614"/>
<source>Previous file</source>
<translation>Edellinen tiedosto</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="310"/>
<location filename="../src/GUI/gui.cpp" line="314"/>
<source>Route waypoints</source>
<translation>Reittipisteet</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="612"/>
<location filename="../src/GUI/gui.cpp" line="616"/>
<source>First file</source>
<translation>Ensimmäinen tiedosto</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="614"/>
<location filename="../src/GUI/gui.cpp" line="618"/>
<source>Last file</source>
<translation>Viimeinen tiedosto</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="740"/>
<location filename="../src/GUI/gui.cpp" line="746"/>
<source>Error loading data file:</source>
<translation>Virhe ladattaessa datatiedostoa:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="743"/>
<location filename="../src/GUI/gui.cpp" line="768"/>
<location filename="../src/GUI/gui.cpp" line="749"/>
<location filename="../src/GUI/gui.cpp" line="776"/>
<source>Line: %1</source>
<translation>Rivi: %1</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="765"/>
<location filename="../src/GUI/gui.cpp" line="773"/>
<source>Error loading POI file:</source>
<translation>Virhe ladattaessa POI-tiedostoa:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="898"/>
<location filename="../src/GUI/gui.cpp" line="906"/>
<source>Name</source>
<translation>Nimi</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="902"/>
<location filename="../src/GUI/gui.cpp" line="910"/>
<source>Tracks</source>
<translation>Jäljet</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="207"/>
<location filename="../src/GUI/gui.cpp" line="584"/>
<location filename="../src/GUI/gui.cpp" line="211"/>
<location filename="../src/GUI/gui.cpp" line="588"/>
<source>About GPXSee</source>
<translation>Tietoja GPXSee:stä</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="522"/>
<location filename="../src/GUI/gui.cpp" line="526"/>
<source>Navigation</source>
<translation>Navigointi</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="325"/>
<location filename="../src/GUI/gui.cpp" line="922"/>
<location filename="../src/GUI/gui.cpp" line="329"/>
<location filename="../src/GUI/gui.cpp" line="930"/>
<source>Distance</source>
<translation>Etäisyys</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="331"/>
<location filename="../src/GUI/gui.cpp" line="481"/>
<location filename="../src/GUI/gui.cpp" line="924"/>
<location filename="../src/GUI/gui.cpp" line="335"/>
<location filename="../src/GUI/gui.cpp" line="485"/>
<location filename="../src/GUI/gui.cpp" line="932"/>
<source>Time</source>
<translation>Aika</translation>
</message>
@ -874,27 +878,27 @@
<context>
<name>MapList</name>
<message>
<location filename="../src/map/maplist.cpp" line="131"/>
<location filename="../src/map/maplist.cpp" line="130"/>
<source>Supported files</source>
<translation>Tuetut tiedostot</translation>
</message>
<message>
<location filename="../src/map/maplist.cpp" line="132"/>
<location filename="../src/map/maplist.cpp" line="131"/>
<source>OziExplorer maps</source>
<translation>OziExplorer -kartat</translation>
</message>
<message>
<location filename="../src/map/maplist.cpp" line="133"/>
<location filename="../src/map/maplist.cpp" line="132"/>
<source>TrekBuddy maps/atlases</source>
<translation>TrekBuddy -kartat/kartastot</translation>
</message>
<message>
<location filename="../src/map/maplist.cpp" line="134"/>
<location filename="../src/map/maplist.cpp" line="133"/>
<source>GeoTIFF images</source>
<translation>GeoTIFF -kuvat</translation>
</message>
<message>
<location filename="../src/map/maplist.cpp" line="135"/>
<location filename="../src/map/maplist.cpp" line="134"/>
<source>Online map sources</source>
<translation>Online-karttojen lähteet</translation>
</message>
@ -1379,33 +1383,53 @@
<context>
<name>SpeedGraph</name>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="14"/>
<location filename="../src/GUI/speedgraph.cpp" line="16"/>
<location filename="../src/GUI/speedgraph.h" line="14"/>
<source>Speed</source>
<translation>Vauhti</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="89"/>
<location filename="../src/GUI/speedgraph.cpp" line="96"/>
<source>km/h</source>
<translation>km/t</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="22"/>
<location filename="../src/GUI/speedgraph.cpp" line="28"/>
<source>Average</source>
<translation>Keskiarvo</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="24"/>
<location filename="../src/GUI/speedgraph.cpp" line="25"/>
<source>min/km</source>
<translation>min/km</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="26"/>
<source>min/mi</source>
<translation>min/mi</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="26"/>
<source>min/nmi</source>
<translation>min/mpk</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="30"/>
<source>Maximum</source>
<translation>Maksimi</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="83"/>
<location filename="../src/GUI/speedgraph.cpp" line="32"/>
<source>Pace</source>
<translation>Tahti</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="90"/>
<source>kn</source>
<translation>kn</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="86"/>
<location filename="../src/GUI/speedgraph.cpp" line="93"/>
<source>mi/h</source>
<translation>mph</translation>
</message>
@ -1413,30 +1437,50 @@
<context>
<name>SpeedGraphItem</name>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="22"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="23"/>
<source>km/h</source>
<translation>km/t</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="21"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="22"/>
<source>mi/h</source>
<translation>mph</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="22"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="23"/>
<source>kn</source>
<translation>kn</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="24"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="26"/>
<source>min/km</source>
<translation>min/km</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="27"/>
<source>min/mi</source>
<translation>min/mi</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="27"/>
<source>min/nmi</source>
<translation>min/mpk</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="29"/>
<source>Maximum</source>
<translation>Maksimi</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="26"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="31"/>
<source>Average</source>
<translation>Keskiarvo</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="33"/>
<source>Pace</source>
<translation>Tahti</translation>
</message>
</context>
<context>
<name>TemperatureGraph</name>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="de">
<TS version="2.1" language="fr">
<context>
<name>CadenceGraph</name>
<message>
@ -284,7 +284,7 @@
<message>
<location filename="../src/GUI/format.cpp" line="62"/>
<source>nmi</source>
<translation type="unfinished"></translation>
<translation>nmi</translation>
</message>
<message>
<location filename="../src/GUI/format.cpp" line="66"/>
@ -301,365 +301,334 @@
<context>
<name>GUI</name>
<message>
<location filename="../src/GUI/gui.cpp" line="588"/>
<location filename="../src/GUI/gui.cpp" line="592"/>
<source>GPXSee is distributed under the terms of the GNU General Public License version 3. For more info about GPXSee visit the project homepage at </source>
<translation>GPXSee est distribué selon les termes de la licence publique générale GNU (version 3). Pour plus d&apos;information sur GPXSee, visiter le site du projet sur </translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="643"/>
<location filename="../src/GUI/gui.cpp" line="647"/>
<source>Map directory:</source>
<translation>Dossier des cartes :</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="645"/>
<location filename="../src/GUI/gui.cpp" line="649"/>
<source>POI directory:</source>
<translation>Dossier des POI:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="647"/>
<location filename="../src/GUI/gui.cpp" line="651"/>
<source>GCS file:</source>
<translation>Fichier GCS :</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="648"/>
<location filename="../src/GUI/gui.cpp" line="652"/>
<source>PCS file:</source>
<translation>Fichier PCS :</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="650"/>
<location filename="../src/GUI/gui.cpp" line="654"/>
<source>Ellipsoids file:</source>
<translation>Fichier des ellipsoïdes :</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="653"/>
<location filename="../src/GUI/gui.cpp" line="657"/>
<source>User override directory:</source>
<translation>Dossier de l&apos;utilisateur :</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="662"/>
<location filename="../src/GUI/gui.cpp" line="666"/>
<source>Open file</source>
<translation>Ouvrir un fichier</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="751"/>
<location filename="../src/GUI/gui.cpp" line="757"/>
<source>Open POI file</source>
<translation>Ouvrir un fichier POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="195"/>
<location filename="../src/GUI/gui.cpp" line="199"/>
<source>Quit</source>
<translation>Quitter</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="204"/>
<location filename="../src/GUI/gui.cpp" line="605"/>
<location filename="../src/GUI/gui.cpp" line="606"/>
<location filename="../src/GUI/gui.cpp" line="208"/>
<location filename="../src/GUI/gui.cpp" line="609"/>
<location filename="../src/GUI/gui.cpp" line="610"/>
<source>Keyboard controls</source>
<translation>Raccourcis clavier</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="229"/>
<location filename="../src/GUI/gui.cpp" line="233"/>
<source>Close</source>
<translation>Fermer</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="235"/>
<location filename="../src/GUI/gui.cpp" line="239"/>
<source>Reload</source>
<translation>Actualiser</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="517"/>
<location filename="../src/GUI/gui.cpp" line="521"/>
<source>Show</source>
<translation>Afficher</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="428"/>
<location filename="../src/GUI/gui.cpp" line="511"/>
<location filename="../src/GUI/gui.cpp" line="515"/>
<source>File</source>
<translation>Fichier</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="246"/>
<location filename="../src/GUI/gui.cpp" line="250"/>
<source>Close POI files</source>
<translation>Fermer les fichiers POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="248"/>
<location filename="../src/GUI/gui.cpp" line="252"/>
<source>Overlap POIs</source>
<translation>Superposer les POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="252"/>
<location filename="../src/GUI/gui.cpp" line="256"/>
<source>Show POI labels</source>
<translation>Afficher les notes des POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="257"/>
<location filename="../src/GUI/gui.cpp" line="261"/>
<source>Show POIs</source>
<translation>Afficher les POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="266"/>
<location filename="../src/GUI/gui.cpp" line="270"/>
<source>Show map</source>
<translation>Afficher la carte</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="276"/>
<location filename="../src/GUI/gui.cpp" line="280"/>
<source>Clear tile cache</source>
<translation>Effacer les tuiles en cache</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="213"/>
<location filename="../src/GUI/gui.cpp" line="217"/>
<source>Open...</source>
<translation>Ouvrir...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="202"/>
<location filename="../src/GUI/gui.cpp" line="639"/>
<location filename="../src/GUI/gui.cpp" line="640"/>
<location filename="../src/GUI/gui.cpp" line="206"/>
<location filename="../src/GUI/gui.cpp" line="643"/>
<location filename="../src/GUI/gui.cpp" line="644"/>
<source>Paths</source>
<translation>Chemin d&apos;accès</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="243"/>
<location filename="../src/GUI/gui.cpp" line="247"/>
<source>Load POI file...</source>
<translation>Charger un fichier POI...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="274"/>
<location filename="../src/GUI/gui.cpp" line="278"/>
<source>Load map...</source>
<translation>Charger une carte...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="280"/>
<location filename="../src/GUI/gui.cpp" line="284"/>
<location filename="../src/GUI/gui.cpp" line="622"/>
<location filename="../src/GUI/gui.cpp" line="288"/>
<location filename="../src/GUI/gui.cpp" line="626"/>
<source>Next map</source>
<translation>Carte suivante</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="294"/>
<location filename="../src/GUI/gui.cpp" line="298"/>
<source>Show tracks</source>
<translation>Afficher la trace</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="298"/>
<location filename="../src/GUI/gui.cpp" line="302"/>
<source>Show routes</source>
<translation>Afficher la route</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="302"/>
<location filename="../src/GUI/gui.cpp" line="306"/>
<source>Show waypoints</source>
<translation>Afficher les points de jalonnement</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="306"/>
<location filename="../src/GUI/gui.cpp" line="310"/>
<source>Waypoint labels</source>
<translation>Étiquettes des jalons</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="317"/>
<location filename="../src/GUI/gui.cpp" line="321"/>
<source>Show graphs</source>
<translation>Afficher les graphes</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="337"/>
<location filename="../src/GUI/gui.cpp" line="341"/>
<source>Show grid</source>
<translation>Afficher la grille</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="341"/>
<location filename="../src/GUI/gui.cpp" line="345"/>
<source>Show slider info</source>
<translation>Afficher les infos du curseur</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="347"/>
<location filename="../src/GUI/gui.cpp" line="351"/>
<source>Show toolbars</source>
<translation>Afficher la barre d&apos;outils</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="353"/>
<location filename="../src/GUI/gui.cpp" line="357"/>
<source>Total time</source>
<translation>Durée totale</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="358"/>
<location filename="../src/GUI/gui.cpp" line="926"/>
<location filename="../src/GUI/gui.cpp" line="362"/>
<location filename="../src/GUI/gui.cpp" line="934"/>
<source>Moving time</source>
<translation>Durée en déplacement</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="365"/>
<location filename="../src/GUI/gui.cpp" line="369"/>
<source>Metric</source>
<translation>Métrique</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="370"/>
<location filename="../src/GUI/gui.cpp" line="374"/>
<source>Imperial</source>
<translation>Impérial</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="375"/>
<location filename="../src/GUI/gui.cpp" line="379"/>
<source>Nautical</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="382"/>
<location filename="../src/GUI/gui.cpp" line="386"/>
<source>Decimal degrees (DD)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="387"/>
<location filename="../src/GUI/gui.cpp" line="391"/>
<source>Degrees and decimal minutes (DMM)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="393"/>
<location filename="../src/GUI/gui.cpp" line="397"/>
<source>Degrees, minutes, seconds (DMS)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="398"/>
<location filename="../src/GUI/gui.cpp" line="402"/>
<source>Fullscreen mode</source>
<translation>Mode plein écran</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="404"/>
<location filename="../src/GUI/gui.cpp" line="408"/>
<source>Options...</source>
<translation>Options...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="410"/>
<location filename="../src/GUI/gui.cpp" line="414"/>
<source>Next</source>
<translation>Suivant</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="413"/>
<location filename="../src/GUI/gui.cpp" line="417"/>
<source>Previous</source>
<translation>Précèdant</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="417"/>
<location filename="../src/GUI/gui.cpp" line="421"/>
<source>Last</source>
<translation>Dernier</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="420"/>
<location filename="../src/GUI/gui.cpp" line="424"/>
<source>First</source>
<translation>Premier</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="442"/>
<source>Map</source>
<translation>Carte</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="450"/>
<source>Graph</source>
<translation>Graphe</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="459"/>
<source>POI</source>
<translation>POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="460"/>
<location filename="../src/GUI/gui.cpp" line="464"/>
<source>POI files</source>
<translation>Fichiers POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="471"/>
<source>Data</source>
<translation>Données</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="472"/>
<location filename="../src/GUI/gui.cpp" line="476"/>
<source>Display</source>
<translation>Affichage</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="480"/>
<source>Settings</source>
<translation>Paramètres</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="484"/>
<location filename="../src/GUI/gui.cpp" line="488"/>
<source>Units</source>
<translation>Système d&apos;unités</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="488"/>
<location filename="../src/GUI/gui.cpp" line="492"/>
<source>Coordinates format</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="498"/>
<source>Help</source>
<translation>Aide</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="615"/>
<location filename="../src/GUI/gui.cpp" line="619"/>
<source>Append file</source>
<translation>Joindre un fichier</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="616"/>
<location filename="../src/GUI/gui.cpp" line="620"/>
<source>Next/Previous</source>
<translation>Suivant/Précèdant</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="618"/>
<location filename="../src/GUI/gui.cpp" line="622"/>
<source>Toggle graph type</source>
<translation>Controler le type de graphe</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="620"/>
<location filename="../src/GUI/gui.cpp" line="624"/>
<source>Toggle time type</source>
<translation>Controler le type de durée</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="624"/>
<location filename="../src/GUI/gui.cpp" line="628"/>
<source>Previous map</source>
<translation>Carte précèdente</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="625"/>
<location filename="../src/GUI/gui.cpp" line="629"/>
<source>Zoom in</source>
<translation>Zoomer</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="627"/>
<location filename="../src/GUI/gui.cpp" line="631"/>
<source>Zoom out</source>
<translation>Dézoomer</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="629"/>
<location filename="../src/GUI/gui.cpp" line="633"/>
<source>Digital zoom</source>
<translation>Zoom numérique</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="630"/>
<location filename="../src/GUI/gui.cpp" line="634"/>
<source>Zoom</source>
<translation>Zoom</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="1127"/>
<location filename="../src/GUI/gui.cpp" line="1135"/>
<source>Open map file</source>
<translation>Ouvrir un fichier de carte</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="1154"/>
<location filename="../src/GUI/gui.cpp" line="1164"/>
<source>Error loading map:</source>
<translation>Erreur lors du chargement de la carte :</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="1165"/>
<location filename="../src/GUI/gui.cpp" line="1175"/>
<source>No files loaded</source>
<translation>Aucun fichier chargé</translation>
</message>
<message numerus="yes">
<location filename="../src/GUI/gui.cpp" line="1169"/>
<location filename="../src/GUI/gui.cpp" line="1179"/>
<source>%n files</source>
<translation>
<numerusform>%n fichier</numerusform>
@ -667,108 +636,143 @@
</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="912"/>
<location filename="../src/GUI/gui.cpp" line="915"/>
<location filename="../src/GUI/gui.cpp" line="920"/>
<location filename="../src/GUI/gui.cpp" line="923"/>
<source>Date</source>
<translation>Date</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="904"/>
<location filename="../src/GUI/gui.cpp" line="912"/>
<source>Routes</source>
<translation>Routes</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="609"/>
<location filename="../src/GUI/gui.cpp" line="613"/>
<source>Next file</source>
<translation>Fichier suivant</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="585"/>
<location filename="../src/GUI/gui.cpp" line="589"/>
<source>Version </source>
<translation>Version </translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="218"/>
<location filename="../src/GUI/gui.cpp" line="222"/>
<source>Print...</source>
<translation>Imprimer...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="223"/>
<location filename="../src/GUI/gui.cpp" line="227"/>
<source>Export to PDF...</source>
<translation>Exporter au format PDF...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="906"/>
<location filename="../src/GUI/gui.cpp" line="914"/>
<source>Waypoints</source>
<translation>Points de jalonnement</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="610"/>
<location filename="../src/GUI/gui.cpp" line="614"/>
<source>Previous file</source>
<translation>Fichier précédent</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="310"/>
<location filename="../src/GUI/gui.cpp" line="314"/>
<source>Route waypoints</source>
<translation>Jalons de route</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="612"/>
<location filename="../src/GUI/gui.cpp" line="432"/>
<source>&amp;File</source>
<translation>&amp;Fichier</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="446"/>
<source>&amp;Map</source>
<translation>&amp;Carte</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="454"/>
<source>&amp;Graph</source>
<translation>&amp;Graphe</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="463"/>
<source>&amp;POI</source>
<translation>&amp;POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="475"/>
<source>&amp;Data</source>
<translation>&amp;Données</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="484"/>
<source>&amp;Settings</source>
<translation>Pa&amp;ramètres</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="502"/>
<source>&amp;Help</source>
<translation>&amp;Aide</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="616"/>
<source>First file</source>
<translation>Premier fichier</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="614"/>
<location filename="../src/GUI/gui.cpp" line="618"/>
<source>Last file</source>
<translation>Dernier fichier</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="740"/>
<location filename="../src/GUI/gui.cpp" line="746"/>
<source>Error loading data file:</source>
<translation>Erreur lors du chargement des données:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="743"/>
<location filename="../src/GUI/gui.cpp" line="768"/>
<location filename="../src/GUI/gui.cpp" line="749"/>
<location filename="../src/GUI/gui.cpp" line="776"/>
<source>Line: %1</source>
<translation>Ligne : %1</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="765"/>
<location filename="../src/GUI/gui.cpp" line="773"/>
<source>Error loading POI file:</source>
<translation>Erreur lors du chargement du fichier POI :</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="898"/>
<location filename="../src/GUI/gui.cpp" line="906"/>
<source>Name</source>
<translation>Nom</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="902"/>
<location filename="../src/GUI/gui.cpp" line="910"/>
<source>Tracks</source>
<translation>Traces</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="207"/>
<location filename="../src/GUI/gui.cpp" line="584"/>
<location filename="../src/GUI/gui.cpp" line="211"/>
<location filename="../src/GUI/gui.cpp" line="588"/>
<source>About GPXSee</source>
<translation>À propos de GPXSee</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="522"/>
<location filename="../src/GUI/gui.cpp" line="526"/>
<source>Navigation</source>
<translation>Navigation</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="325"/>
<location filename="../src/GUI/gui.cpp" line="922"/>
<location filename="../src/GUI/gui.cpp" line="329"/>
<location filename="../src/GUI/gui.cpp" line="930"/>
<source>Distance</source>
<translation>Distance</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="331"/>
<location filename="../src/GUI/gui.cpp" line="481"/>
<location filename="../src/GUI/gui.cpp" line="924"/>
<location filename="../src/GUI/gui.cpp" line="335"/>
<location filename="../src/GUI/gui.cpp" line="485"/>
<location filename="../src/GUI/gui.cpp" line="932"/>
<source>Time</source>
<translation>Temps</translation>
</message>
@ -799,7 +803,7 @@
<message>
<location filename="../src/GUI/graphview.cpp" line="120"/>
<source>nmi</source>
<translation type="unfinished"></translation>
<translation>nmi</translation>
</message>
<message>
<location filename="../src/GUI/graphview.cpp" line="134"/>
@ -874,27 +878,27 @@
<context>
<name>MapList</name>
<message>
<location filename="../src/map/maplist.cpp" line="131"/>
<location filename="../src/map/maplist.cpp" line="130"/>
<source>Supported files</source>
<translation>Formats pris en charge</translation>
</message>
<message>
<location filename="../src/map/maplist.cpp" line="132"/>
<location filename="../src/map/maplist.cpp" line="131"/>
<source>OziExplorer maps</source>
<translation>Cartes OziExplorer</translation>
</message>
<message>
<location filename="../src/map/maplist.cpp" line="133"/>
<location filename="../src/map/maplist.cpp" line="132"/>
<source>TrekBuddy maps/atlases</source>
<translation>Cartes ou atlas TrekBuddy</translation>
</message>
<message>
<location filename="../src/map/maplist.cpp" line="134"/>
<location filename="../src/map/maplist.cpp" line="133"/>
<source>GeoTIFF images</source>
<translation>Images GeoTIFF</translation>
</message>
<message>
<location filename="../src/map/maplist.cpp" line="135"/>
<location filename="../src/map/maplist.cpp" line="134"/>
<source>Online map sources</source>
<translation>Cartes en ligne</translation>
</message>
@ -1161,7 +1165,7 @@
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="331"/>
<source>nmi</source>
<translation type="unfinished"></translation>
<translation>nmi</translation>
</message>
<message>
<location filename="../src/GUI/optionsdialog.cpp" line="334"/>
@ -1363,7 +1367,7 @@
<message>
<location filename="../src/GUI/scaleitem.cpp" line="86"/>
<source>nmi</source>
<translation type="unfinished"></translation>
<translation>nmi</translation>
</message>
<message>
<location filename="../src/GUI/scaleitem.cpp" line="89"/>
@ -1379,33 +1383,53 @@
<context>
<name>SpeedGraph</name>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="14"/>
<location filename="../src/GUI/speedgraph.cpp" line="16"/>
<location filename="../src/GUI/speedgraph.h" line="14"/>
<source>Speed</source>
<translation>Vitesse</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="89"/>
<location filename="../src/GUI/speedgraph.cpp" line="96"/>
<source>km/h</source>
<translation>km/h</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="22"/>
<location filename="../src/GUI/speedgraph.cpp" line="28"/>
<source>Average</source>
<translation>Moyenne</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="24"/>
<location filename="../src/GUI/speedgraph.cpp" line="25"/>
<source>min/km</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="26"/>
<source>min/mi</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="26"/>
<source>min/nmi</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="30"/>
<source>Maximum</source>
<translation>Maximum</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="83"/>
<location filename="../src/GUI/speedgraph.cpp" line="32"/>
<source>Pace</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="90"/>
<source>kn</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="86"/>
<location filename="../src/GUI/speedgraph.cpp" line="93"/>
<source>mi/h</source>
<translation>mi/h</translation>
</message>
@ -1413,30 +1437,50 @@
<context>
<name>SpeedGraphItem</name>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="22"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="23"/>
<source>km/h</source>
<translation>km/h</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="21"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="22"/>
<source>mi/h</source>
<translation>mi/h</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="22"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="23"/>
<source>kn</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="24"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="26"/>
<source>min/km</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="27"/>
<source>min/mi</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="27"/>
<source>min/nmi</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="29"/>
<source>Maximum</source>
<translation>Maximum</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="26"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="31"/>
<source>Average</source>
<translation>Moyenne</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="33"/>
<source>Pace</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>TemperatureGraph</name>

View File

@ -301,376 +301,380 @@
<context>
<name>GUI</name>
<message>
<location filename="../src/GUI/gui.cpp" line="588"/>
<location filename="../src/GUI/gui.cpp" line="592"/>
<source>GPXSee is distributed under the terms of the GNU General Public License version 3. For more info about GPXSee visit the project homepage at </source>
<translation>GPXSee распространяется в соответствиями с условиями версии 3 Стандартной Общественной Лицензии GNU. Для получения дополнительной информации о GPXSee посетите страницу проекта </translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="662"/>
<location filename="../src/GUI/gui.cpp" line="666"/>
<source>Open file</source>
<translation>Открыть файл</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="751"/>
<location filename="../src/GUI/gui.cpp" line="757"/>
<source>Open POI file</source>
<translation>Открыть файл с точками POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="195"/>
<location filename="../src/GUI/gui.cpp" line="199"/>
<source>Quit</source>
<translation>Выход</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="204"/>
<location filename="../src/GUI/gui.cpp" line="605"/>
<location filename="../src/GUI/gui.cpp" line="606"/>
<location filename="../src/GUI/gui.cpp" line="208"/>
<location filename="../src/GUI/gui.cpp" line="609"/>
<location filename="../src/GUI/gui.cpp" line="610"/>
<source>Keyboard controls</source>
<translation>Управление с помощью клавиатуры</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="229"/>
<location filename="../src/GUI/gui.cpp" line="233"/>
<source>Close</source>
<translation>Закрыть</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="235"/>
<location filename="../src/GUI/gui.cpp" line="239"/>
<source>Reload</source>
<translation>Обновить</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="517"/>
<location filename="../src/GUI/gui.cpp" line="521"/>
<source>Show</source>
<translation>Показать</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="428"/>
<location filename="../src/GUI/gui.cpp" line="511"/>
<location filename="../src/GUI/gui.cpp" line="515"/>
<source>File</source>
<translation>Файл</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="246"/>
<location filename="../src/GUI/gui.cpp" line="250"/>
<source>Close POI files</source>
<translation>Закрыть файлы с точками POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="248"/>
<location filename="../src/GUI/gui.cpp" line="252"/>
<source>Overlap POIs</source>
<translation>Наложение точек POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="252"/>
<location filename="../src/GUI/gui.cpp" line="256"/>
<source>Show POI labels</source>
<translation>Показать подписи к точкам POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="257"/>
<location filename="../src/GUI/gui.cpp" line="261"/>
<source>Show POIs</source>
<translation>Показать точки POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="266"/>
<location filename="../src/GUI/gui.cpp" line="270"/>
<source>Show map</source>
<translation>Показать карту</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="276"/>
<location filename="../src/GUI/gui.cpp" line="280"/>
<source>Clear tile cache</source>
<translation>Очистить кэш</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="213"/>
<location filename="../src/GUI/gui.cpp" line="217"/>
<source>Open...</source>
<translation>Открыть...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="202"/>
<location filename="../src/GUI/gui.cpp" line="639"/>
<location filename="../src/GUI/gui.cpp" line="640"/>
<location filename="../src/GUI/gui.cpp" line="206"/>
<location filename="../src/GUI/gui.cpp" line="643"/>
<location filename="../src/GUI/gui.cpp" line="644"/>
<source>Paths</source>
<translation>Пути</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="243"/>
<location filename="../src/GUI/gui.cpp" line="247"/>
<source>Load POI file...</source>
<translation>Загрузить файл с точками POI...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="274"/>
<location filename="../src/GUI/gui.cpp" line="278"/>
<source>Load map...</source>
<translation>Загрузить карту...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="280"/>
<location filename="../src/GUI/gui.cpp" line="284"/>
<location filename="../src/GUI/gui.cpp" line="622"/>
<location filename="../src/GUI/gui.cpp" line="288"/>
<location filename="../src/GUI/gui.cpp" line="626"/>
<source>Next map</source>
<translation>Следующая карта</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="294"/>
<location filename="../src/GUI/gui.cpp" line="298"/>
<source>Show tracks</source>
<translation>Показать треки</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="298"/>
<location filename="../src/GUI/gui.cpp" line="302"/>
<source>Show routes</source>
<translation>Показать маршруты</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="302"/>
<location filename="../src/GUI/gui.cpp" line="306"/>
<source>Show waypoints</source>
<translation>Показать точки</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="306"/>
<location filename="../src/GUI/gui.cpp" line="310"/>
<source>Waypoint labels</source>
<translation>Подписи точек</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="317"/>
<location filename="../src/GUI/gui.cpp" line="321"/>
<source>Show graphs</source>
<translation>Показать графики</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="337"/>
<location filename="../src/GUI/gui.cpp" line="341"/>
<source>Show grid</source>
<translation>Показать сетку</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="341"/>
<location filename="../src/GUI/gui.cpp" line="345"/>
<source>Show slider info</source>
<translation>Показать значение на слайдере</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="347"/>
<location filename="../src/GUI/gui.cpp" line="351"/>
<source>Show toolbars</source>
<translation>Показывать панели инструментов</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="353"/>
<location filename="../src/GUI/gui.cpp" line="357"/>
<source>Total time</source>
<translation>Общее время</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="358"/>
<location filename="../src/GUI/gui.cpp" line="926"/>
<location filename="../src/GUI/gui.cpp" line="362"/>
<location filename="../src/GUI/gui.cpp" line="934"/>
<source>Moving time</source>
<translation>Время движения</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="365"/>
<location filename="../src/GUI/gui.cpp" line="369"/>
<source>Metric</source>
<translation>Метрические</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="370"/>
<location filename="../src/GUI/gui.cpp" line="374"/>
<source>Imperial</source>
<translation>Британские</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="375"/>
<location filename="../src/GUI/gui.cpp" line="379"/>
<source>Nautical</source>
<translation>Морские</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="382"/>
<location filename="../src/GUI/gui.cpp" line="386"/>
<source>Decimal degrees (DD)</source>
<translation>Десятичные градусы (DD)</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="387"/>
<location filename="../src/GUI/gui.cpp" line="391"/>
<source>Degrees and decimal minutes (DMM)</source>
<translation>Градусы, десятичные минуты (DMM)</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="393"/>
<location filename="../src/GUI/gui.cpp" line="397"/>
<source>Degrees, minutes, seconds (DMS)</source>
<translation>Градусы, минуты, секунды (DMS)</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="398"/>
<location filename="../src/GUI/gui.cpp" line="402"/>
<source>Fullscreen mode</source>
<translation>Полноэкранный режим</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="404"/>
<location filename="../src/GUI/gui.cpp" line="408"/>
<source>Options...</source>
<translation>Параметры...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="410"/>
<location filename="../src/GUI/gui.cpp" line="414"/>
<source>Next</source>
<translation>Следующий</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="413"/>
<location filename="../src/GUI/gui.cpp" line="417"/>
<source>Previous</source>
<translation>Предыдущий</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="417"/>
<location filename="../src/GUI/gui.cpp" line="421"/>
<source>Last</source>
<translation>Последний</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="420"/>
<location filename="../src/GUI/gui.cpp" line="424"/>
<source>First</source>
<translation>Первый</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="442"/>
<source>Map</source>
<translation>Карты</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="450"/>
<source>Graph</source>
<translation>График</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="459"/>
<source>POI</source>
<translation>Точки POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="460"/>
<location filename="../src/GUI/gui.cpp" line="464"/>
<source>POI files</source>
<translation>Файлы с точками POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="471"/>
<source>Data</source>
<translation>Данные</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="472"/>
<location filename="../src/GUI/gui.cpp" line="476"/>
<source>Display</source>
<translation>Отображать</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="480"/>
<source>Settings</source>
<translation>Параметры</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="484"/>
<location filename="../src/GUI/gui.cpp" line="488"/>
<source>Units</source>
<translation>Единицы</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="488"/>
<location filename="../src/GUI/gui.cpp" line="492"/>
<source>Coordinates format</source>
<translation>Формат координат</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="498"/>
<source>Help</source>
<translation>Справка</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="615"/>
<location filename="../src/GUI/gui.cpp" line="619"/>
<source>Append file</source>
<translation>Добавить файл</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="616"/>
<location filename="../src/GUI/gui.cpp" line="620"/>
<source>Next/Previous</source>
<translation>Next/Previous</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="618"/>
<location filename="../src/GUI/gui.cpp" line="622"/>
<source>Toggle graph type</source>
<translation>Переключить тип графика</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="620"/>
<location filename="../src/GUI/gui.cpp" line="624"/>
<source>Toggle time type</source>
<translation>Переключить тип времени</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="624"/>
<location filename="../src/GUI/gui.cpp" line="628"/>
<source>Previous map</source>
<translation>Предыдущая карта</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="625"/>
<location filename="../src/GUI/gui.cpp" line="629"/>
<source>Zoom in</source>
<translation>Увеличить</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="627"/>
<location filename="../src/GUI/gui.cpp" line="631"/>
<source>Zoom out</source>
<translation>Уменьшить</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="629"/>
<location filename="../src/GUI/gui.cpp" line="633"/>
<source>Digital zoom</source>
<translation>Цифровой зум</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="630"/>
<location filename="../src/GUI/gui.cpp" line="634"/>
<source>Zoom</source>
<translation>Zoom</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="1127"/>
<location filename="../src/GUI/gui.cpp" line="1135"/>
<source>Open map file</source>
<translation>Открыть файл карты</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="1165"/>
<location filename="../src/GUI/gui.cpp" line="1175"/>
<source>No files loaded</source>
<translation>Нет загруженных файлов</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="912"/>
<location filename="../src/GUI/gui.cpp" line="915"/>
<location filename="../src/GUI/gui.cpp" line="920"/>
<location filename="../src/GUI/gui.cpp" line="923"/>
<source>Date</source>
<translation>Дата</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="643"/>
<location filename="../src/GUI/gui.cpp" line="432"/>
<source>&amp;File</source>
<translation>&amp;Файл</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="446"/>
<source>&amp;Map</source>
<translation>&amp;Карты</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="454"/>
<source>&amp;Graph</source>
<translation>&amp;График</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="463"/>
<source>&amp;POI</source>
<translation>&amp;Точки POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="475"/>
<source>&amp;Data</source>
<translation>&amp;Данные</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="484"/>
<source>&amp;Settings</source>
<translation>&amp;Параметры</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="502"/>
<source>&amp;Help</source>
<translation>&amp;Справка</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="647"/>
<source>Map directory:</source>
<translation>Директория с картами:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="645"/>
<location filename="../src/GUI/gui.cpp" line="649"/>
<source>POI directory:</source>
<translation>Директория с POI:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="647"/>
<location filename="../src/GUI/gui.cpp" line="651"/>
<source>GCS file:</source>
<translation>GCS файл:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="648"/>
<location filename="../src/GUI/gui.cpp" line="652"/>
<source>PCS file:</source>
<translation>PCS файл:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="650"/>
<location filename="../src/GUI/gui.cpp" line="654"/>
<source>Ellipsoids file:</source>
<translation>Ellipsoids файл:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="653"/>
<location filename="../src/GUI/gui.cpp" line="657"/>
<source>User override directory:</source>
<translation>Каталог пользовательских настроек:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="904"/>
<location filename="../src/GUI/gui.cpp" line="912"/>
<source>Routes</source>
<translation>Маршруты</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="1154"/>
<location filename="../src/GUI/gui.cpp" line="1164"/>
<source>Error loading map:</source>
<translation>Ошибка загрузки карты:</translation>
</message>
<message numerus="yes">
<location filename="../src/GUI/gui.cpp" line="1169"/>
<location filename="../src/GUI/gui.cpp" line="1179"/>
<source>%n files</source>
<translation>
<numerusform>%n файл</numerusform>
@ -679,97 +683,97 @@
</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="609"/>
<location filename="../src/GUI/gui.cpp" line="613"/>
<source>Next file</source>
<translation>Следующий файл</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="585"/>
<location filename="../src/GUI/gui.cpp" line="589"/>
<source>Version </source>
<translation>Версия </translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="218"/>
<location filename="../src/GUI/gui.cpp" line="222"/>
<source>Print...</source>
<translation>Печать...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="223"/>
<location filename="../src/GUI/gui.cpp" line="227"/>
<source>Export to PDF...</source>
<translation>Экспорт в PDF...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="906"/>
<location filename="../src/GUI/gui.cpp" line="914"/>
<source>Waypoints</source>
<translation>Точки</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="610"/>
<location filename="../src/GUI/gui.cpp" line="614"/>
<source>Previous file</source>
<translation>Предыдущий файл</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="310"/>
<location filename="../src/GUI/gui.cpp" line="314"/>
<source>Route waypoints</source>
<translation>Маршрутные точки</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="612"/>
<location filename="../src/GUI/gui.cpp" line="616"/>
<source>First file</source>
<translation>Первый файл</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="614"/>
<location filename="../src/GUI/gui.cpp" line="618"/>
<source>Last file</source>
<translation>Последний файл</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="740"/>
<location filename="../src/GUI/gui.cpp" line="746"/>
<source>Error loading data file:</source>
<translation>Ошибка загрузки файла данных:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="743"/>
<location filename="../src/GUI/gui.cpp" line="768"/>
<location filename="../src/GUI/gui.cpp" line="749"/>
<location filename="../src/GUI/gui.cpp" line="776"/>
<source>Line: %1</source>
<translation>Строка: %1</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="765"/>
<location filename="../src/GUI/gui.cpp" line="773"/>
<source>Error loading POI file:</source>
<translation>Ошибка загрузки файла с точками POI:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="898"/>
<location filename="../src/GUI/gui.cpp" line="906"/>
<source>Name</source>
<translation>Имя</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="902"/>
<location filename="../src/GUI/gui.cpp" line="910"/>
<source>Tracks</source>
<translation>Треки</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="207"/>
<location filename="../src/GUI/gui.cpp" line="584"/>
<location filename="../src/GUI/gui.cpp" line="211"/>
<location filename="../src/GUI/gui.cpp" line="588"/>
<source>About GPXSee</source>
<translation>О GPXSee</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="522"/>
<location filename="../src/GUI/gui.cpp" line="526"/>
<source>Navigation</source>
<translation>Навигация</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="325"/>
<location filename="../src/GUI/gui.cpp" line="922"/>
<location filename="../src/GUI/gui.cpp" line="329"/>
<location filename="../src/GUI/gui.cpp" line="930"/>
<source>Distance</source>
<translation>Расстояние</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="331"/>
<location filename="../src/GUI/gui.cpp" line="481"/>
<location filename="../src/GUI/gui.cpp" line="924"/>
<location filename="../src/GUI/gui.cpp" line="335"/>
<location filename="../src/GUI/gui.cpp" line="485"/>
<location filename="../src/GUI/gui.cpp" line="932"/>
<source>Time</source>
<translation>Время</translation>
</message>
@ -875,27 +879,27 @@
<context>
<name>MapList</name>
<message>
<location filename="../src/map/maplist.cpp" line="131"/>
<location filename="../src/map/maplist.cpp" line="130"/>
<source>Supported files</source>
<translation>Все поддерживаемые файлы</translation>
</message>
<message>
<location filename="../src/map/maplist.cpp" line="132"/>
<location filename="../src/map/maplist.cpp" line="131"/>
<source>OziExplorer maps</source>
<translation>OziExplorer карты</translation>
</message>
<message>
<location filename="../src/map/maplist.cpp" line="133"/>
<location filename="../src/map/maplist.cpp" line="132"/>
<source>TrekBuddy maps/atlases</source>
<translation>TrekBuddy карты/атласы</translation>
</message>
<message>
<location filename="../src/map/maplist.cpp" line="134"/>
<location filename="../src/map/maplist.cpp" line="133"/>
<source>GeoTIFF images</source>
<translation>GeoTIFF изображения</translation>
</message>
<message>
<location filename="../src/map/maplist.cpp" line="135"/>
<location filename="../src/map/maplist.cpp" line="134"/>
<source>Online map sources</source>
<translation>Источники онлайн карт</translation>
</message>
@ -1380,33 +1384,53 @@
<context>
<name>SpeedGraph</name>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="14"/>
<location filename="../src/GUI/speedgraph.cpp" line="16"/>
<location filename="../src/GUI/speedgraph.h" line="14"/>
<source>Speed</source>
<translation>Скорость</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="89"/>
<location filename="../src/GUI/speedgraph.cpp" line="96"/>
<source>km/h</source>
<translation>км/ч</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="22"/>
<location filename="../src/GUI/speedgraph.cpp" line="28"/>
<source>Average</source>
<translation>Cреднее</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="24"/>
<location filename="../src/GUI/speedgraph.cpp" line="25"/>
<source>min/km</source>
<translation>мин/км</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="26"/>
<source>min/mi</source>
<translation>мин/мл</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="26"/>
<source>min/nmi</source>
<translation>мин/мор.мл</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="30"/>
<source>Maximum</source>
<translation>Максимум</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="83"/>
<location filename="../src/GUI/speedgraph.cpp" line="32"/>
<source>Pace</source>
<translation>Темп</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="90"/>
<source>kn</source>
<translation>уз</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="86"/>
<location filename="../src/GUI/speedgraph.cpp" line="93"/>
<source>mi/h</source>
<translation>мл/ч</translation>
</message>
@ -1414,30 +1438,50 @@
<context>
<name>SpeedGraphItem</name>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="22"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="23"/>
<source>km/h</source>
<translation>км/ч</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="21"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="22"/>
<source>mi/h</source>
<translation>мл/ч</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="22"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="23"/>
<source>kn</source>
<translation>уз</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="24"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="26"/>
<source>min/km</source>
<translation>мин/км</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="27"/>
<source>min/mi</source>
<translation>мин/мл</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="27"/>
<source>min/nmi</source>
<translation>мин/мор.мл</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="29"/>
<source>Maximum</source>
<translation>Максимум</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="26"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="31"/>
<source>Average</source>
<translation>Cреднее</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="33"/>
<source>Pace</source>
<translation>Темп</translation>
</message>
</context>
<context>
<name>TemperatureGraph</name>

View File

@ -301,365 +301,334 @@
<context>
<name>GUI</name>
<message>
<location filename="../src/GUI/gui.cpp" line="588"/>
<location filename="../src/GUI/gui.cpp" line="592"/>
<source>GPXSee is distributed under the terms of the GNU General Public License version 3. For more info about GPXSee visit the project homepage at </source>
<translation>GPXSee distribueras under vilkoren för GNU General Public License version 3. För mer info om GPXSee, besök hemsidan </translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="643"/>
<location filename="../src/GUI/gui.cpp" line="647"/>
<source>Map directory:</source>
<translation>Kartmapp:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="645"/>
<location filename="../src/GUI/gui.cpp" line="649"/>
<source>POI directory:</source>
<translation>POI-mapp:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="647"/>
<location filename="../src/GUI/gui.cpp" line="651"/>
<source>GCS file:</source>
<translation>GCS-fil:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="648"/>
<location filename="../src/GUI/gui.cpp" line="652"/>
<source>PCS file:</source>
<translation>PCS-fil:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="650"/>
<location filename="../src/GUI/gui.cpp" line="654"/>
<source>Ellipsoids file:</source>
<translation>Ellipsoids-fil:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="653"/>
<location filename="../src/GUI/gui.cpp" line="657"/>
<source>User override directory:</source>
<translation>Användarspecificerad mapp:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="662"/>
<location filename="../src/GUI/gui.cpp" line="666"/>
<source>Open file</source>
<translation>Öppna fil</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="751"/>
<location filename="../src/GUI/gui.cpp" line="757"/>
<source>Open POI file</source>
<translation>Öppna POI-fil</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="195"/>
<location filename="../src/GUI/gui.cpp" line="199"/>
<source>Quit</source>
<translation>Avsluta</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="204"/>
<location filename="../src/GUI/gui.cpp" line="605"/>
<location filename="../src/GUI/gui.cpp" line="606"/>
<location filename="../src/GUI/gui.cpp" line="208"/>
<location filename="../src/GUI/gui.cpp" line="609"/>
<location filename="../src/GUI/gui.cpp" line="610"/>
<source>Keyboard controls</source>
<translation>Snabbtangenter</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="229"/>
<location filename="../src/GUI/gui.cpp" line="233"/>
<source>Close</source>
<translation>Stäng</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="235"/>
<location filename="../src/GUI/gui.cpp" line="239"/>
<source>Reload</source>
<translation>Uppdatera</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="517"/>
<location filename="../src/GUI/gui.cpp" line="521"/>
<source>Show</source>
<translation>Visa</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="428"/>
<location filename="../src/GUI/gui.cpp" line="511"/>
<location filename="../src/GUI/gui.cpp" line="515"/>
<source>File</source>
<translation>Arkiv</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="246"/>
<location filename="../src/GUI/gui.cpp" line="250"/>
<source>Close POI files</source>
<translation>Stäng POI-filer</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="248"/>
<location filename="../src/GUI/gui.cpp" line="252"/>
<source>Overlap POIs</source>
<translation>Överlappa POI:er</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="252"/>
<location filename="../src/GUI/gui.cpp" line="256"/>
<source>Show POI labels</source>
<translation>Visa POI-namn</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="257"/>
<location filename="../src/GUI/gui.cpp" line="261"/>
<source>Show POIs</source>
<translation>Visa POI:er</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="266"/>
<location filename="../src/GUI/gui.cpp" line="270"/>
<source>Show map</source>
<translation>Visa karta</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="276"/>
<location filename="../src/GUI/gui.cpp" line="280"/>
<source>Clear tile cache</source>
<translation>Rensa kart-cache</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="213"/>
<location filename="../src/GUI/gui.cpp" line="217"/>
<source>Open...</source>
<translation>Öppna...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="202"/>
<location filename="../src/GUI/gui.cpp" line="639"/>
<location filename="../src/GUI/gui.cpp" line="640"/>
<location filename="../src/GUI/gui.cpp" line="206"/>
<location filename="../src/GUI/gui.cpp" line="643"/>
<location filename="../src/GUI/gui.cpp" line="644"/>
<source>Paths</source>
<translation type="unfinished">Sökvägar</translation>
<translation>Sökvägar</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="243"/>
<location filename="../src/GUI/gui.cpp" line="247"/>
<source>Load POI file...</source>
<translation>Läs in POI-fil...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="274"/>
<location filename="../src/GUI/gui.cpp" line="278"/>
<source>Load map...</source>
<translation>Läs in karta...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="280"/>
<location filename="../src/GUI/gui.cpp" line="284"/>
<location filename="../src/GUI/gui.cpp" line="622"/>
<location filename="../src/GUI/gui.cpp" line="288"/>
<location filename="../src/GUI/gui.cpp" line="626"/>
<source>Next map</source>
<translation>Nästa karta</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="294"/>
<location filename="../src/GUI/gui.cpp" line="298"/>
<source>Show tracks</source>
<translation>Visa spår</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="298"/>
<location filename="../src/GUI/gui.cpp" line="302"/>
<source>Show routes</source>
<translation>Visa rutter</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="302"/>
<location filename="../src/GUI/gui.cpp" line="306"/>
<source>Show waypoints</source>
<translation>Visa vägpunkter</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="306"/>
<location filename="../src/GUI/gui.cpp" line="310"/>
<source>Waypoint labels</source>
<translation>Vägpunktsnamn</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="317"/>
<location filename="../src/GUI/gui.cpp" line="321"/>
<source>Show graphs</source>
<translation>Visa diagram</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="337"/>
<location filename="../src/GUI/gui.cpp" line="341"/>
<source>Show grid</source>
<translation>Visa stödlinjer</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="341"/>
<location filename="../src/GUI/gui.cpp" line="345"/>
<source>Show slider info</source>
<translation>Visa reglageinfo</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="347"/>
<location filename="../src/GUI/gui.cpp" line="351"/>
<source>Show toolbars</source>
<translation>Visa verktygsfält</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="353"/>
<location filename="../src/GUI/gui.cpp" line="357"/>
<source>Total time</source>
<translation>Total tid</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="358"/>
<location filename="../src/GUI/gui.cpp" line="926"/>
<location filename="../src/GUI/gui.cpp" line="362"/>
<location filename="../src/GUI/gui.cpp" line="934"/>
<source>Moving time</source>
<translation>Förflyttningstid</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="365"/>
<location filename="../src/GUI/gui.cpp" line="369"/>
<source>Metric</source>
<translation>Meter</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="370"/>
<location filename="../src/GUI/gui.cpp" line="374"/>
<source>Imperial</source>
<translation>Imperial</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="375"/>
<location filename="../src/GUI/gui.cpp" line="379"/>
<source>Nautical</source>
<translation>Nautiska</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="382"/>
<location filename="../src/GUI/gui.cpp" line="386"/>
<source>Decimal degrees (DD)</source>
<translation>Decimala grader (DD)</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="387"/>
<location filename="../src/GUI/gui.cpp" line="391"/>
<source>Degrees and decimal minutes (DMM)</source>
<translation>Grader och decimala minuter (DMM)</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="393"/>
<location filename="../src/GUI/gui.cpp" line="397"/>
<source>Degrees, minutes, seconds (DMS)</source>
<translation>Grader, minuter, sekunder (DMS)</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="398"/>
<location filename="../src/GUI/gui.cpp" line="402"/>
<source>Fullscreen mode</source>
<translation>Helskärmsläge</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="404"/>
<location filename="../src/GUI/gui.cpp" line="408"/>
<source>Options...</source>
<translation>Alternativ...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="410"/>
<location filename="../src/GUI/gui.cpp" line="414"/>
<source>Next</source>
<translation>Nästa</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="413"/>
<location filename="../src/GUI/gui.cpp" line="417"/>
<source>Previous</source>
<translation>Föregående</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="417"/>
<location filename="../src/GUI/gui.cpp" line="421"/>
<source>Last</source>
<translation>Sista</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="420"/>
<location filename="../src/GUI/gui.cpp" line="424"/>
<source>First</source>
<translation>Första</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="442"/>
<source>Map</source>
<translation>Karta</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="450"/>
<source>Graph</source>
<translation>Diagram</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="459"/>
<source>POI</source>
<translation>POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="460"/>
<location filename="../src/GUI/gui.cpp" line="464"/>
<source>POI files</source>
<translation>POI-filer</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="471"/>
<source>Data</source>
<translation>Data</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="472"/>
<location filename="../src/GUI/gui.cpp" line="476"/>
<source>Display</source>
<translation>Visa</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="480"/>
<source>Settings</source>
<translation>Inställningar</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="484"/>
<location filename="../src/GUI/gui.cpp" line="488"/>
<source>Units</source>
<translation>Enhet</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="488"/>
<location filename="../src/GUI/gui.cpp" line="492"/>
<source>Coordinates format</source>
<translation>Koordinatformat</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="498"/>
<source>Help</source>
<translation>Hjälp</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="615"/>
<location filename="../src/GUI/gui.cpp" line="619"/>
<source>Append file</source>
<translation>Lägg till fil</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="616"/>
<location filename="../src/GUI/gui.cpp" line="620"/>
<source>Next/Previous</source>
<translation>Nästa/Föregående</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="618"/>
<location filename="../src/GUI/gui.cpp" line="622"/>
<source>Toggle graph type</source>
<translation>Växla diagramtyp</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="620"/>
<location filename="../src/GUI/gui.cpp" line="624"/>
<source>Toggle time type</source>
<translation>Växla tidstyp</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="624"/>
<location filename="../src/GUI/gui.cpp" line="628"/>
<source>Previous map</source>
<translation>Föregående karta</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="625"/>
<location filename="../src/GUI/gui.cpp" line="629"/>
<source>Zoom in</source>
<translation>Zooma in</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="627"/>
<location filename="../src/GUI/gui.cpp" line="631"/>
<source>Zoom out</source>
<translation>Zooma ut</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="629"/>
<location filename="../src/GUI/gui.cpp" line="633"/>
<source>Digital zoom</source>
<translation>Digital zoom</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="630"/>
<location filename="../src/GUI/gui.cpp" line="634"/>
<source>Zoom</source>
<translation>Zoom</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="1127"/>
<location filename="../src/GUI/gui.cpp" line="1135"/>
<source>Open map file</source>
<translation>Öppna kartfil</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="1154"/>
<location filename="../src/GUI/gui.cpp" line="1164"/>
<source>Error loading map:</source>
<translation>Fel vid inläsning av karta:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="1165"/>
<location filename="../src/GUI/gui.cpp" line="1175"/>
<source>No files loaded</source>
<translation>Inga filer inlästa</translation>
</message>
<message numerus="yes">
<location filename="../src/GUI/gui.cpp" line="1169"/>
<location filename="../src/GUI/gui.cpp" line="1179"/>
<source>%n files</source>
<translation>
<numerusform>%n filer</numerusform>
@ -667,108 +636,143 @@
</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="912"/>
<location filename="../src/GUI/gui.cpp" line="915"/>
<location filename="../src/GUI/gui.cpp" line="920"/>
<location filename="../src/GUI/gui.cpp" line="923"/>
<source>Date</source>
<translation>Datum</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="904"/>
<location filename="../src/GUI/gui.cpp" line="912"/>
<source>Routes</source>
<translation>Rutter</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="609"/>
<location filename="../src/GUI/gui.cpp" line="613"/>
<source>Next file</source>
<translation>Nästa fil</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="585"/>
<location filename="../src/GUI/gui.cpp" line="589"/>
<source>Version </source>
<translation>Version </translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="218"/>
<location filename="../src/GUI/gui.cpp" line="222"/>
<source>Print...</source>
<translation>Skriv ut...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="223"/>
<location filename="../src/GUI/gui.cpp" line="227"/>
<source>Export to PDF...</source>
<translation>Exportera till PDF...</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="906"/>
<location filename="../src/GUI/gui.cpp" line="914"/>
<source>Waypoints</source>
<translation>Vägpunkter</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="610"/>
<location filename="../src/GUI/gui.cpp" line="614"/>
<source>Previous file</source>
<translation>Föregående fil</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="310"/>
<location filename="../src/GUI/gui.cpp" line="314"/>
<source>Route waypoints</source>
<translation>Ruttvägpunkter</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="612"/>
<location filename="../src/GUI/gui.cpp" line="432"/>
<source>&amp;File</source>
<translation>&amp;Arkiv</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="446"/>
<source>&amp;Map</source>
<translation>&amp;Karta</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="454"/>
<source>&amp;Graph</source>
<translation>&amp;Diagram</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="463"/>
<source>&amp;POI</source>
<translation>&amp;POI</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="475"/>
<source>&amp;Data</source>
<translation>Da&amp;ta</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="484"/>
<source>&amp;Settings</source>
<translation>&amp;Inställningar</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="502"/>
<source>&amp;Help</source>
<translation>&amp;Hjälp</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="616"/>
<source>First file</source>
<translation>Första filen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="614"/>
<location filename="../src/GUI/gui.cpp" line="618"/>
<source>Last file</source>
<translation>Sista filen</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="740"/>
<location filename="../src/GUI/gui.cpp" line="746"/>
<source>Error loading data file:</source>
<translation>Fel vid inläsning av datafil:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="743"/>
<location filename="../src/GUI/gui.cpp" line="768"/>
<location filename="../src/GUI/gui.cpp" line="749"/>
<location filename="../src/GUI/gui.cpp" line="776"/>
<source>Line: %1</source>
<translation>Rad: %1</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="765"/>
<location filename="../src/GUI/gui.cpp" line="773"/>
<source>Error loading POI file:</source>
<translation>Fel vid inläsning av POI-fil:</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="898"/>
<location filename="../src/GUI/gui.cpp" line="906"/>
<source>Name</source>
<translation>Namn</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="902"/>
<location filename="../src/GUI/gui.cpp" line="910"/>
<source>Tracks</source>
<translation>Spår</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="207"/>
<location filename="../src/GUI/gui.cpp" line="584"/>
<location filename="../src/GUI/gui.cpp" line="211"/>
<location filename="../src/GUI/gui.cpp" line="588"/>
<source>About GPXSee</source>
<translation>Om GPXSee</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="522"/>
<location filename="../src/GUI/gui.cpp" line="526"/>
<source>Navigation</source>
<translation>Navigation</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="325"/>
<location filename="../src/GUI/gui.cpp" line="922"/>
<location filename="../src/GUI/gui.cpp" line="329"/>
<location filename="../src/GUI/gui.cpp" line="930"/>
<source>Distance</source>
<translation>Avstånd</translation>
</message>
<message>
<location filename="../src/GUI/gui.cpp" line="331"/>
<location filename="../src/GUI/gui.cpp" line="481"/>
<location filename="../src/GUI/gui.cpp" line="924"/>
<location filename="../src/GUI/gui.cpp" line="335"/>
<location filename="../src/GUI/gui.cpp" line="485"/>
<location filename="../src/GUI/gui.cpp" line="932"/>
<source>Time</source>
<translation>Tid</translation>
</message>
@ -874,27 +878,27 @@
<context>
<name>MapList</name>
<message>
<location filename="../src/map/maplist.cpp" line="131"/>
<location filename="../src/map/maplist.cpp" line="130"/>
<source>Supported files</source>
<translation>Filer som stöds</translation>
</message>
<message>
<location filename="../src/map/maplist.cpp" line="132"/>
<location filename="../src/map/maplist.cpp" line="131"/>
<source>OziExplorer maps</source>
<translation>OziExplorer-kartor</translation>
</message>
<message>
<location filename="../src/map/maplist.cpp" line="133"/>
<location filename="../src/map/maplist.cpp" line="132"/>
<source>TrekBuddy maps/atlases</source>
<translation>TrekBuddy-kartor/-atlaser</translation>
</message>
<message>
<location filename="../src/map/maplist.cpp" line="134"/>
<location filename="../src/map/maplist.cpp" line="133"/>
<source>GeoTIFF images</source>
<translation>GeoTIFF-bilder</translation>
</message>
<message>
<location filename="../src/map/maplist.cpp" line="135"/>
<location filename="../src/map/maplist.cpp" line="134"/>
<source>Online map sources</source>
<translation>Online-kartkällor</translation>
</message>
@ -1379,33 +1383,53 @@
<context>
<name>SpeedGraph</name>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="14"/>
<location filename="../src/GUI/speedgraph.cpp" line="16"/>
<location filename="../src/GUI/speedgraph.h" line="14"/>
<source>Speed</source>
<translation>Hastighet</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="89"/>
<location filename="../src/GUI/speedgraph.cpp" line="96"/>
<source>km/h</source>
<translation>km/h</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="22"/>
<location filename="../src/GUI/speedgraph.cpp" line="28"/>
<source>Average</source>
<translation>Medel</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="24"/>
<location filename="../src/GUI/speedgraph.cpp" line="25"/>
<source>min/km</source>
<translation>min/km</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="26"/>
<source>min/mi</source>
<translation>min/mi</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="26"/>
<source>min/nmi</source>
<translation>min/nmi</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="30"/>
<source>Maximum</source>
<translation>Max</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="83"/>
<location filename="../src/GUI/speedgraph.cpp" line="32"/>
<source>Pace</source>
<translation>Tempo</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="90"/>
<source>kn</source>
<translation>knop</translation>
</message>
<message>
<location filename="../src/GUI/speedgraph.cpp" line="86"/>
<location filename="../src/GUI/speedgraph.cpp" line="93"/>
<source>mi/h</source>
<translation>mi/h</translation>
</message>
@ -1413,30 +1437,50 @@
<context>
<name>SpeedGraphItem</name>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="22"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="23"/>
<source>km/h</source>
<translation>km/h</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="21"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="22"/>
<source>mi/h</source>
<translation>mi/h</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="22"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="23"/>
<source>kn</source>
<translation>knop</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="24"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="26"/>
<source>min/km</source>
<translation>min/km</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="27"/>
<source>min/mi</source>
<translation>min/mi</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="27"/>
<source>min/nmi</source>
<translation>min/nmi</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="29"/>
<source>Maximum</source>
<translation>Maximum</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="26"/>
<location filename="../src/GUI/speedgraphitem.cpp" line="31"/>
<source>Average</source>
<translation>Medel</translation>
</message>
<message>
<location filename="../src/GUI/speedgraphitem.cpp" line="33"/>
<source>Pace</source>
<translation>Tempo</translation>
</message>
</context>
<context>
<name>TemperatureGraph</name>

View File

@ -21,7 +21,7 @@ Canton Astro 1966,4716,6716,9122,7022,8901,9603,298,-304,-375
Cape,4222,6222,9122,7012,8901,9603,-136,-108,-292
Cape Canaveral,4717,6717,9122,7008,8901,9603,-2,150,181
Carthage,4223,6223,9122,7012,8901,9603,-263,6,431
CH-1903,4149,6149,9122,7004,8901,9603,674,15,405
CH-1903,4149,6149,9122,7004,8901,9603,674.374,15.056,405.343
Chatham 1971,4672,6672,9122,7022,8901,9603,175,-38,113
Chua Astro,4224,6224,9122,7022,8901,9603,-134,229,-29
Corrego Alegre,4225,6225,9122,7022,8901,9603,-206,172,-6
@ -29,6 +29,7 @@ Djakarta (Batavia),4211,6211,9122,7004,8901,9603,-377,681,-50
DOS 1968,,,9122,7022,8901,9603,230,-199,-752
Easter Island 1967,4719,6719,9122,7022,8901,9603,211,147,111
Egypt,4199,6199,9122,7022,8901,9603,-130,-117,-151
ETRS 89,4258,6258,9122,7019,8901,9603,0,0,0
European 1950,4230,6230,9122,7022,8901,9603,-87,-98,-121
European 1950 (Mean France),,,9122,7022,8901,9603,-87,-96,-120
European 1950 (Spain and Portugal),,,9122,7022,8901,9603,-84,-107,-120
@ -104,6 +105,7 @@ Rijksdriehoeksmeting,4289,6289,9122,7004,8901,9603,593,26,478
Rome 1940,4806,6806,9122,7022,8906,9603,-225,-65,9
RT 90,4124,6124,9122,7004,8901,9603,498,-36,568
S42,4179,6179,9122,7024,8901,9603,28,-121,-77
S42 (83),4178,6178,9122,7024,8901,9603,26,-121,-78
Santo (DOS),4730,6730,9122,7022,8901,9603,170,42,84
Sao Braz,4184,6184,9122,7022,8901,9603,-203,141,53
Sapper Hill 1943,4292,6292,9122,7022,8901,9603,-355,16,74

1 Adindan 4201 6201 9122 7012 8901 9603 -162 -12 206
21 Cape 4222 6222 9122 7012 8901 9603 -136 -108 -292
22 Cape Canaveral 4717 6717 9122 7008 8901 9603 -2 150 181
23 Carthage 4223 6223 9122 7012 8901 9603 -263 6 431
24 CH-1903 4149 6149 9122 7004 8901 9603 674 674.374 15 15.056 405 405.343
25 Chatham 1971 4672 6672 9122 7022 8901 9603 175 -38 113
26 Chua Astro 4224 6224 9122 7022 8901 9603 -134 229 -29
27 Corrego Alegre 4225 6225 9122 7022 8901 9603 -206 172 -6
29 DOS 1968 9122 7022 8901 9603 230 -199 -752
30 Easter Island 1967 4719 6719 9122 7022 8901 9603 211 147 111
31 Egypt 4199 6199 9122 7022 8901 9603 -130 -117 -151
32 ETRS 89 4258 6258 9122 7019 8901 9603 0 0 0
33 European 1950 4230 6230 9122 7022 8901 9603 -87 -98 -121
34 European 1950 (Mean France) 9122 7022 8901 9603 -87 -96 -120
35 European 1950 (Spain and Portugal) 9122 7022 8901 9603 -84 -107 -120
105 Rome 1940 4806 6806 9122 7022 8906 9603 -225 -65 9
106 RT 90 4124 6124 9122 7004 8901 9603 498 -36 568
107 S42 4179 6179 9122 7024 8901 9603 28 -121 -77
108 S42 (83) 4178 6178 9122 7024 8901 9603 26 -121 -78
109 Santo (DOS) 4730 6730 9122 7022 8901 9603 170 42 84
110 Sao Braz 4184 6184 9122 7022 8901 9603 -203 141 53
111 Sapper Hill 1943 4292 6292 9122 7022 8901 9603 -355 16 74

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,7 @@ Comment=GPS log file viewer and analyzer
Comment[cz]=Prohlížeč a analyzátor GPS logů
Comment[fi]=Ohjelma GPS-lokien katseluun ja analysointiin
Comment[ru]=Программа для просмотра и анализа GPS логов
Comment[sv]=GPS-loggfilsläsare och analysator
Exec=gpxsee %F
Icon=gpxsee
Terminal=false

View File

@ -5,7 +5,7 @@
; The name of the installer
Name "GPXSee"
; Program version
!define VERSION "5.2"
!define VERSION "5.6"
; The file to write
OutFile "GPXSee-${VERSION}.exe"

View File

@ -5,7 +5,7 @@
; The name of the installer
Name "GPXSee"
; Program version
!define VERSION "5.2"
!define VERSION "5.6"
; The file to write
OutFile "GPXSee-${VERSION}_x64.exe"

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<map>
<map xmlns="http://www.gpxsee.org/map/1">
<name>4UMaps</name>
<url>http://4umaps.eu/$z/$x/$y.png</url>
<copyright>Map data: © OpenStreetMap contributors (ODbL) | Rendering: © 4UMaps.eu</copyright>
<zoom min="2" max="15"/>
<bounds bottom="-65"/>
<copyright>Map data: © OpenStreetMap contributors (ODbL) | Rendering: © 4UMaps.eu</copyright>
</map>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<map>
<map xmlns="http://www.gpxsee.org/map/1">
<name>Open Street Map</name>
<url>http://tile.openstreetmap.org/$z/$x/$y.png</url>
<copyright>Map data: © OpenStreetMap contributors (ODbL) | Rendering: © OpenStreetMap (CC-BY-SA)</copyright>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<map>
<map xmlns="http://www.gpxsee.org/map/1">
<name>Open Topo Map</name>
<url>https://a.tile.opentopomap.org/$z/$x/$y.png</url>
<zoom max="17"/>
<copyright>Map data: © OpenStreetMap contributors (ODbL), SRTM | Rendering: © OpenTopoMap (CC-BY-SA)</copyright>
<zoom max="17"/>
</map>

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<map>
<map xmlns="http://www.gpxsee.org/map/1">
<name>USGS Imagery</name>
<url>https://navigator.er.usgs.gov/tiles/aerial_Imagery.cgi/$z/$x/$y</url>
<copyright>Map services and data available from U.S. Geological Survey, National Geospatial Program.</copyright>
<zoom min="2" max="15"/>
<bounds bottom="0" top="74"/>
<copyright>Map services and data available from U.S. Geological Survey, National Geospatial Program.</copyright>
</map>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<map>
<map xmlns="http://www.gpxsee.org/map/1">
<name>USGS Topo</name>
<url>https://navigator.er.usgs.gov/tiles/tcr.cgi/$z/$x/$y.png</url>
<zoom min="2" max="15"/>
<copyright>Map services and data available from U.S. Geological Survey, National Geospatial Program.</copyright>
<zoom min="2" max="15"/>
</map>

View File

@ -4,7 +4,9 @@
#include <QFileOpenEvent>
#include <QNetworkProxyFactory>
#include <QLibraryInfo>
#include "map/onlinemap.h"
#include "map/wmts.h"
#include "map/wms.h"
#include "map/tileloader.h"
#include "map/downloader.h"
#include "map/ellipsoid.h"
#include "map/gcs.h"
@ -23,12 +25,12 @@ App::App(int &argc, char **argv) : QApplication(argc, argv),
installTranslator(gpxsee);
QTranslator *qt = new QTranslator(this);
#if defined(Q_OS_WINDOWS) || defined(Q_OS_MAC)
#if defined(Q_OS_WIN32) || defined(Q_OS_MAC)
qt->load(QLocale::system(), "qt", "_", TRANSLATIONS_DIR);
#else // Q_OS_WINDOWS || Q_OS_MAC
#else // Q_OS_WIN32 || Q_OS_MAC
qt->load(QLocale::system(), "qt", "_", QLibraryInfo::location(
QLibraryInfo::TranslationsPath));
#endif // Q_OS_WINDOWS || Q_OS_MAC
#endif // Q_OS_WIN32 || Q_OS_MAC
installTranslator(qt);
#ifdef Q_OS_MAC
@ -36,7 +38,10 @@ App::App(int &argc, char **argv) : QApplication(argc, argv),
#endif // Q_OS_MAC
QNetworkProxyFactory::setUseSystemConfiguration(true);
OnlineMap::setDownloader(new Downloader(this));
Downloader *dl = new Downloader(this);
TileLoader::setDownloader(dl);
WMTS::setDownloader(dl);
WMS::setDownloader(dl);
OPENGL_SET_SAMPLES(4);
loadDatums();
loadPCSs();

View File

@ -73,10 +73,10 @@ QString Format::distance(qreal value, Units units)
QString Format::elevation(qreal value, Units units)
{
if (units == Metric)
return QString::number(value, 'f', 0) + UNIT_SPACE
return QString::number(qRound(value)) + UNIT_SPACE
+ qApp->translate("Format", "m");
else
return QString::number(value * M2FT, 'f', 0) + UNIT_SPACE
return QString::number(qRound(value * M2FT)) + UNIT_SPACE
+ qApp->translate("Format", "ft");
}

View File

@ -12,6 +12,7 @@ class GraphItem : public QGraphicsObject
public:
GraphItem(const Graph &graph, GraphType type, QGraphicsItem *parent = 0);
virtual ~GraphItem() {}
QPainterPath shape() const {return _shape;}
QRectF boundingRect() const {return _shape.boundingRect();}

View File

@ -16,6 +16,7 @@ class GraphTab : public GraphView
public:
GraphTab(QWidget *parent = 0) : GraphView(parent)
{setFrameShape(QFrame::NoFrame);}
virtual ~GraphTab() {}
virtual QString label() const = 0;
virtual void loadData(const Data &data, const QList<PathItem *> &paths) = 0;

View File

@ -81,12 +81,12 @@ GraphView::~GraphView()
void GraphView::createXLabel()
{
_xAxis->setLabel(QString("%1 [%2]").arg(_xLabel).arg(_xUnits));
_xAxis->setLabel(QString("%1 [%2]").arg(_xLabel, _xUnits));
}
void GraphView::createYLabel()
{
_yAxis->setLabel(QString("%1 [%2]").arg(_yLabel).arg(_yUnits));
_yAxis->setLabel(QString("%1 [%2]").arg(_yLabel, _yUnits));
}
void GraphView::setYLabel(const QString &label)

View File

@ -82,6 +82,10 @@ GUI::GUI()
_sliderPos = 0;
_dataDir = QDir::homePath();
_mapDir = QDir::homePath();
_poiDir = QDir::homePath();
readSettings();
updateGraphTabs();
@ -425,7 +429,7 @@ void GUI::createActions()
void GUI::createMenus()
{
QMenu *fileMenu = menuBar()->addMenu(tr("File"));
QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
fileMenu->addAction(_openFileAction);
fileMenu->addSeparator();
fileMenu->addAction(_printFileAction);
@ -439,7 +443,7 @@ void GUI::createMenus()
fileMenu->addAction(_exitAction);
#endif // Q_OS_MAC
_mapMenu = menuBar()->addMenu(tr("Map"));
_mapMenu = menuBar()->addMenu(tr("&Map"));
_mapMenu->addActions(_mapActions);
_mapsEnd = _mapMenu->addSeparator();
_mapMenu->addAction(_loadMapAction);
@ -447,7 +451,7 @@ void GUI::createMenus()
_mapMenu->addSeparator();
_mapMenu->addAction(_showMapAction);
QMenu *graphMenu = menuBar()->addMenu(tr("Graph"));
QMenu *graphMenu = menuBar()->addMenu(tr("&Graph"));
graphMenu->addAction(_distanceGraphAction);
graphMenu->addAction(_timeGraphAction);
graphMenu->addSeparator();
@ -456,7 +460,7 @@ void GUI::createMenus()
graphMenu->addSeparator();
graphMenu->addAction(_showGraphsAction);
QMenu *poiMenu = menuBar()->addMenu(tr("POI"));
QMenu *poiMenu = menuBar()->addMenu(tr("&POI"));
_poiFilesMenu = poiMenu->addMenu(tr("POI files"));
_poiFilesMenu->addActions(_poiFilesActions);
poiMenu->addSeparator();
@ -468,7 +472,7 @@ void GUI::createMenus()
poiMenu->addSeparator();
poiMenu->addAction(_showPOIAction);
QMenu *dataMenu = menuBar()->addMenu(tr("Data"));
QMenu *dataMenu = menuBar()->addMenu(tr("&Data"));
QMenu *displayMenu = dataMenu->addMenu(tr("Display"));
displayMenu->addAction(_showWaypointLabelsAction);
displayMenu->addAction(_showRouteWaypointsAction);
@ -477,7 +481,7 @@ void GUI::createMenus()
dataMenu->addAction(_showRoutesAction);
dataMenu->addAction(_showWaypointsAction);
QMenu *settingsMenu = menuBar()->addMenu(tr("Settings"));
QMenu *settingsMenu = menuBar()->addMenu(tr("&Settings"));
QMenu *timeMenu = settingsMenu->addMenu(tr("Time"));
timeMenu->addAction(_totalTimeAction);
timeMenu->addAction(_movingTimeAction);
@ -495,7 +499,7 @@ void GUI::createMenus()
settingsMenu->addSeparator();
settingsMenu->addAction(_openOptionsAction);
QMenu *helpMenu = menuBar()->addMenu(tr("Help"));
QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
helpMenu->addAction(_pathsAction);
helpMenu->addAction(_keysAction);
helpMenu->addSeparator();
@ -660,11 +664,13 @@ void GUI::paths()
void GUI::openFile()
{
QStringList files = QFileDialog::getOpenFileNames(this, tr("Open file"),
QString(), Data::formats());
_dataDir, Data::formats());
QStringList list = files;
for (QStringList::Iterator it = list.begin(); it != list.end(); it++)
openFile(*it);
if (!list.isEmpty())
_dataDir = QFileInfo(list.first()).path();
}
bool GUI::openFile(const QString &fileName)
@ -749,11 +755,13 @@ bool GUI::loadFile(const QString &fileName)
void GUI::openPOIFile()
{
QStringList files = QFileDialog::getOpenFileNames(this, tr("Open POI file"),
QString(), Data::formats());
_poiDir, Data::formats());
QStringList list = files;
for (QStringList::Iterator it = list.begin(); it != list.end(); it++)
openPOIFile(*it);
if (!list.isEmpty())
_poiDir = QFileInfo(list.first()).path();
}
bool GUI::openPOIFile(const QString &fileName)
@ -1125,11 +1133,13 @@ void GUI::showGraphSliderInfo(bool show)
void GUI::loadMap()
{
QStringList files = QFileDialog::getOpenFileNames(this, tr("Open map file"),
QString(), MapList::formats());
_mapDir, MapList::formats());
QStringList list = files;
for (QStringList::Iterator it = list.begin(); it != list.end(); it++)
loadMap(*it);
if (!list.isEmpty())
_mapDir = QFileInfo(list.first()).path();
}
bool GUI::loadMap(const QString &fileName)

View File

@ -224,6 +224,8 @@ private:
Export _export;
Options _options;
QString _dataDir, _mapDir, _poiDir;
};
#endif // GUI_H

View File

@ -23,7 +23,7 @@ void InfoItem::updateBoundingRect()
for (i = _list.constBegin(); i != _list.constEnd(); i++) {
width += fm.width(i->key + ": ");
width += fm.width(i->value) + ((i == _list.end() - 1) ? 0 : PADDING);
width += fm.width(i->value) + ((i == _list.constEnd() - 1) ? 0 : PADDING);
}
_boundingRect = QRectF(0, 0, width, _list.isEmpty() ? 0 : fm.height());
@ -49,8 +49,8 @@ void InfoItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
painter->drawText(width, fm.height() - fm.descent(), i->key + ": ");
width += fm.width(i->key + ": ");
painter->drawText(width, fm.height() - fm.descent(), i->value);
width += fm.width(i->value) + ((i == _list.end() - 1) ? 0 : PADDING);
if (i != _list.end() - 1) {
width += fm.width(i->value) + ((i == _list.constEnd() - 1) ? 0 : PADDING);
if (i != _list.constEnd() - 1) {
painter->save();
painter->setPen(Qt::gray);
painter->drawLine(width - PADDING/2, fm.descent(),

View File

@ -76,6 +76,7 @@ MapView::MapView(Map *map, POI *poi, QWidget *parent)
_digitalZoom = 0;
_map->setBackgroundColor(_backgroundColor);
_res = _map->resolution(_map->bounds());
_scene->setSceneRect(_map->bounds());
centerOn(_scene->sceneRect().center());
@ -84,18 +85,8 @@ MapView::MapView(Map *map, POI *poi, QWidget *parent)
void MapView::centerOn(const QPointF &pos)
{
QGraphicsView::centerOn(pos);
/* Fix the offset caused by QGraphicsView::centerOn() approximation */
QPointF center = mapToScene(viewport()->rect().center());
QPoint offset((int)(pos.x() - center.x()), (int)(pos.y() - center.y()));
if (qAbs(offset.x()) == 1)
horizontalScrollBar()->setValue(horizontalScrollBar()->value()
+ offset.x());
if (qAbs(offset.y()) == 1)
verticalScrollBar()->setValue(verticalScrollBar()->value()
+ offset.y());
_res = _map->resolution(pos);
QRectF vr(mapToScene(viewport()->rect()).boundingRect());
_res = _map->resolution(vr);
_mapScale->setResolution(_res);
}
@ -177,7 +168,7 @@ void MapView::addWaypoints(const QList<Waypoint> &waypoints)
QList<PathItem *> MapView::loadData(const Data &data)
{
QList<PathItem *> paths;
qreal zoom = _map->zoom();
int zoom = _map->zoom();
for (int i = 0; i < data.tracks().count(); i++)
paths.append(addTrack(*(data.tracks().at(i))));
@ -188,7 +179,7 @@ QList<PathItem *> MapView::loadData(const Data &data)
if (_tracks.empty() && _routes.empty() && _waypoints.empty())
return paths;
if (mapZoom() != zoom)
if (fitMapZoom() != zoom)
rescale();
else
updatePOIVisibility();
@ -198,13 +189,13 @@ QList<PathItem *> MapView::loadData(const Data &data)
return paths;
}
qreal MapView::mapZoom() const
int MapView::fitMapZoom() const
{
RectC br = _tr | _rr | _wr;
return _map->zoomFit(viewport()->size() - QSize(2*MARGIN, 2*MARGIN),
br.isNull() ? RectC(_map->xy2ll(sceneRect().topLeft()),
_map->xy2ll(sceneRect().bottomRight())) : br);
br.isNull() ? RectC(_map->xy2ll(_map->bounds().topLeft()),
_map->xy2ll(_map->bounds().bottomRight())) : br);
}
QPointF MapView::contentCenter() const
@ -267,9 +258,9 @@ void MapView::setPalette(const Palette &palette)
void MapView::setMap(Map *map)
{
QPointF pos = mapToScene(viewport()->rect().center());
Coordinates center = _map->xy2ll(pos);
qreal resolution = _map->resolution(pos);
QRectF vr(mapToScene(viewport()->rect()).boundingRect()
.intersected(_map->bounds()));
RectC cr(_map->xy2ll(vr.topLeft()), _map->xy2ll(vr.bottomRight()));
_map->unload();
disconnect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
@ -281,7 +272,7 @@ void MapView::setMap(Map *map)
digitalZoom(0);
_map->zoomFit(resolution, center);
_map->zoomFit(viewport()->rect().size(), cr);
_scene->setSceneRect(_map->bounds());
for (int i = 0; i < _tracks.size(); i++)
@ -296,7 +287,7 @@ void MapView::setMap(Map *map)
it.value()->setMap(_map);
updatePOIVisibility();
centerOn(_map->ll2xy(center));
centerOn(_map->ll2xy(cr.center()));
resetCachedContent();
QPixmapCache::clear();
@ -398,7 +389,10 @@ void MapView::setCoordinatesFormat(CoordinatesFormat format)
void MapView::clearMapCache()
{
_map->clearCache();
resetCachedContent();
fitMapZoom();
rescale();
centerOn(contentCenter());
}
void MapView::digitalZoom(int zoom)
@ -499,9 +493,9 @@ void MapView::plot(QPainter *painter, const QRectF &target, qreal scale,
bool hires)
{
QRect orig, adj;
qreal ratio, diff, origRes, q;
qreal ratio, diff, q;
QPointF origScene, origPos;
Coordinates origLL;
RectC origC;
// Enter plot mode
@ -526,9 +520,9 @@ void MapView::plot(QPainter *painter, const QRectF &target, qreal scale,
// Adjust the view for printing
if (hires) {
origScene = mapToScene(orig.center());
origLL = _map->xy2ll(origScene);
origRes = _map->resolution(origScene);
QRectF vr(mapToScene(orig).boundingRect());
origC = RectC(_map->xy2ll(vr.topLeft()), _map->xy2ll(vr.bottomRight()));
origScene = vr.center();
QPointF s(painter->device()->logicalDpiX()
/ (qreal)metric(QPaintDevice::PdmDpiX),
@ -558,7 +552,7 @@ void MapView::plot(QPainter *painter, const QRectF &target, qreal scale,
// Revert view changes to display mode
if (hires) {
_map->zoomFit(origRes, origLL);
_map->zoomFit(orig.size(), origC);
rescale();
centerOn(origScene);
}
@ -761,25 +755,22 @@ void MapView::setBackgroundColor(const QColor &color)
void MapView::drawBackground(QPainter *painter, const QRectF &rect)
{
painter->fillRect(rect, _backgroundColor);
if (_showMap) {
QRectF ir = rect.intersected(_map->bounds());
if (_opacity < 1.0 || ir != rect)
painter->fillRect(rect, _backgroundColor);
if (_opacity < 1.0)
painter->setOpacity(_opacity);
_map->draw(painter, ir);
} else
painter->fillRect(rect, _backgroundColor);
}
}
void MapView::resizeEvent(QResizeEvent *event)
{
QGraphicsView::resizeEvent(event);
qreal zoom = _map->zoom();
if (mapZoom() != zoom)
int zoom = _map->zoom();
if (fitMapZoom() != zoom)
rescale();
centerOn(contentCenter());
@ -800,8 +791,8 @@ void MapView::scrollContentsBy(int dx, int dy)
{
QGraphicsView::scrollContentsBy(dx, dy);
QPointF center = mapToScene(viewport()->rect().center());
qreal res = _map->resolution(center);
QRectF sr(mapToScene(viewport()->rect()).boundingRect());
qreal res = _map->resolution(sr);
if (qMax(res, _res) / qMin(res, _res) > 1.1) {
_mapScale->setResolution(res);

View File

@ -80,7 +80,7 @@ private:
void loadPOI();
void clearPOI();
qreal mapZoom() const;
int fitMapZoom() const;
QPointF contentCenter() const;
void rescale();
void centerOn(const QPointF &pos);

View File

@ -1,16 +1,18 @@
#include "data/data.h"
#include "config.h"
#include "tooltip.h"
#include "format.h"
#include "speedgraphitem.h"
#include "speedgraph.h"
SpeedGraph::SpeedGraph(QWidget *parent) : GraphTab(parent)
{
_units = Metric;
_timeType = Total;
_showTracks = true;
setYUnits(Metric);
setYUnits();
setYLabel(tr("Speed"));
setSliderPrecision(1);
@ -19,10 +21,15 @@ SpeedGraph::SpeedGraph(QWidget *parent) : GraphTab(parent)
void SpeedGraph::setInfo()
{
if (_showTracks) {
QString pace = Format::timeSpan((3600.0 / (avg() * yScale())), false);
QString pu = (_units == Metric) ? tr("min/km") : (_units == Imperial) ?
tr("min/mi") : tr("min/nmi");
GraphView::addInfo(tr("Average"), QString::number(avg() * yScale(), 'f',
1) + UNIT_SPACE + yUnits());
GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale(), 'f',
1) + UNIT_SPACE + yUnits());
GraphView::addInfo(tr("Pace"), pace + UNIT_SPACE + pu);
} else
clearInfo();
}
@ -77,12 +84,12 @@ void SpeedGraph::clear()
GraphView::clear();
}
void SpeedGraph::setYUnits(Units units)
void SpeedGraph::setYUnits()
{
if (units == Nautical) {
if (_units == Nautical) {
GraphView::setYUnits(tr("kn"));
setYScale(MS2KN);
} else if (units == Imperial) {
} else if (_units == Imperial) {
GraphView::setYUnits(tr("mi/h"));
setYScale(MS2MIH);
} else {
@ -93,7 +100,9 @@ void SpeedGraph::setYUnits(Units units)
void SpeedGraph::setUnits(Units units)
{
setYUnits(units);
_units = units;
setYUnits();
setInfo();
GraphView::setUnits(units);

View File

@ -21,13 +21,14 @@ public:
private:
qreal avg() const;
qreal max() const {return bounds().bottom();}
void setYUnits(Units units);
void setYUnits();
void setInfo();
QList<QPointF> _avg;
QList<QPointF> _mavg;
enum TimeType _timeType;
Units _units;
TimeType _timeType;
bool _showTracks;
};

View File

@ -1,4 +1,5 @@
#include "tooltip.h"
#include "format.h"
#include "speedgraphitem.h"
SpeedGraphItem::SpeedGraphItem(const Graph &graph, GraphType type,
@ -20,11 +21,16 @@ QString SpeedGraphItem::toolTip() const
? MS2KN : MS2KMH;
QString su = (_units == Imperial) ? tr("mi/h") : (_units == Nautical)
? tr("kn") : tr("km/h");
QString pace = Format::timeSpan((3600.0 / ((_timeType == Total)
? avg() * scale : mavg() * scale)), false);
QString pu = (_units == Metric) ? tr("min/km") : (_units == Imperial) ?
tr("min/mi") : tr("min/nmi");
tt.insert(tr("Maximum"), QString::number(max() * scale, 'f', 1)
+ UNIT_SPACE + su);
tt.insert(tr("Average"), QString::number((_timeType == Total)
? avg() * scale : mavg() * scale, 'f', 1) + UNIT_SPACE + su);
tt.insert(tr("Pace"), pace + UNIT_SPACE + pu);
return tt.toString();
}

View File

@ -15,7 +15,6 @@ class Coordinates
{
public:
Coordinates() {_lon = NAN; _lat = NAN;}
Coordinates(const Coordinates &c) {_lon = c._lon; _lat = c._lat;}
Coordinates(qreal lon, qreal lat) {_lon = lon; _lat = lat;}
qreal &rlon() {return _lon;}

View File

@ -8,6 +8,15 @@ void RangeF::resize(qreal size)
_max += adj;
}
RangeF RangeF::operator&(const RangeF &r) const
{
if (isNull() || r.isNull())
return RangeF();
RangeF tmp(qMax(this->_min, r._min), qMin(this->_max, r._max));
return tmp.isValid() ? tmp : RangeF();
}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const Range &range)
{

View File

@ -14,6 +14,11 @@ public:
int max() const {return _max;}
int size() const {return (_max - _min);}
bool isValid() const {return size() >= 0;}
void setMin(int min) {_min = min;}
void setMax(int max) {_max = max;}
private:
int _min, _max;
};
@ -24,10 +29,19 @@ public:
RangeF() {_min = 0; _max = 0;}
RangeF(qreal min, qreal max) {_min = min, _max = max;}
RangeF operator&(const RangeF &r) const;
RangeF &operator&=(const RangeF &r) {*this = *this & r; return *this;}
qreal min() const {return _min;}
qreal max() const {return _max;}
qreal size() const {return (_max - _min);}
bool isNull() const {return _min == 0 && _max == 0;}
bool isValid() const {return size() >= 0;}
void setMin(qreal min) {_min = min;}
void setMax(qreal max) {_max = max;}
void resize(qreal size);
private:

View File

@ -44,6 +44,76 @@ RectC RectC::operator|(const RectC &r) const
return tmp;
}
RectC RectC::operator&(const RectC &r) const
{
if (isNull() || r.isNull())
return RectC();
qreal l1 = _tl.lon();
qreal r1 = _tl.lon();
if (_br.lon() - _tl.lon() < 0)
l1 = _br.lon();
else
r1 = _br.lon();
qreal l2 = r._tl.lon();
qreal r2 = r._tl.lon();
if (r._br.lon() - r._tl.lon() < 0)
l2 = r._br.lon();
else
r2 = r._br.lon();
if (l1 > r2 || l2 > r1)
return RectC();
qreal t1 = _tl.lat();
qreal b1 = _tl.lat();
if (_br.lat() - _tl.lat() < 0)
t1 = _br.lat();
else
b1 = _br.lat();
qreal t2 = r._tl.lat();
qreal b2 = r._tl.lat();
if (r._br.lat() - r._tl.lat() < 0)
t2 = r._br.lat();
else
b2 = r._br.lat();
if (t1 > b2 || t2 > b1)
return RectC();
RectC tmp;
tmp._tl.setLon(qMax(l1, l2));
tmp._br.setLon(qMin(r1, r2));
tmp._tl.setLat(qMax(t1, t2));
tmp._br.setLat(qMin(b1, b2));
return tmp;
}
RectC RectC::normalized() const
{
RectC r;
if (_br.lon() < _tl.lon()) {
r._tl.setLon(_br.lon());
r._br.setLon(_tl.lon());
} else {
r._tl.setLon(_tl.lon());
r._br.setLon(_br.lon());
}
if (_br.lat() < _tl.lat()) {
r._tl.setLat(_br.lat());
r._br.setLat(_tl.lat());
} else {
r._tl.setLat(_tl.lat());
r._br.setLat(_br.lat());
}
return r;
}
void RectC::unite(const Coordinates &c)
{
if (isNull()) {

View File

@ -30,8 +30,11 @@ public:
RectC operator|(const RectC &r) const;
RectC &operator|=(const RectC &r) {*this = *this | r; return *this;}
RectC operator&(const RectC &r) const;
RectC &operator&=(const RectC &r) {*this = *this & r; return *this;}
void unite(const Coordinates &c);
RectC normalized() const;
private:
Coordinates _tl, _br;

View File

@ -23,13 +23,13 @@ static QHash<QString, Parser*> parsers()
{
QHash<QString, Parser*> hash;
hash.insert("gpx", &gpx);
hash.insert("tcx", &tcx);
hash.insert("kml", &kml);
hash.insert("fit", &fit);
hash.insert("csv", &csv);
hash.insert("igc", &igc);
hash.insert("nmea", &nmea);
hash.insert("gpx", &gpx);
hash.insert("tcx", &tcx);
hash.insert("kml", &kml);
hash.insert("fit", &fit);
hash.insert("csv", &csv);
hash.insert("igc", &igc);
hash.insert("nmea", &nmea);
return hash;
}

View File

@ -41,6 +41,7 @@ Defense.
*/
#include "ellipsoid.h"
#include "albersequal.h"
@ -69,7 +70,6 @@ AlbersEqual::AlbersEqual(const Ellipsoid *ellipsoid, double standardParallel1,
double sp1, sp2;
_e = ellipsoid;
_latitudeOrigin = deg2rad(latitudeOrigin);
_longitudeOrigin = deg2rad(longitudeOrigin);
_falseEasting = falseEasting;
@ -78,7 +78,9 @@ AlbersEqual::AlbersEqual(const Ellipsoid *ellipsoid, double standardParallel1,
sp1 = deg2rad(standardParallel1);
sp2 = deg2rad(standardParallel2);
_es2 = 2 * _e->flattening() - _e->flattening() * _e->flattening();
_a2 = ellipsoid->radius() * ellipsoid->radius();
_es2 = 2 * ellipsoid->flattening() - ellipsoid->flattening()
* ellipsoid->flattening();
_es = sqrt(_es2);
_one_minus_es2 = 1 - _es2;
_two_es = 2 * _es;
@ -108,7 +110,7 @@ AlbersEqual::AlbersEqual(const Ellipsoid *ellipsoid, double standardParallel1,
_n = sin_lat1;
_C = sqr_m1 + _n * q1;
_a_over_n = _e->radius() / _n;
_a_over_n = ellipsoid->radius() / _n;
nq0 = _n * q0;
_rho0 = (_C < nq0) ? 0 : _a_over_n * sqrt(_C - nq0);
}
@ -171,7 +173,7 @@ Coordinates AlbersEqual::xy2ll(const QPointF &p) const
if (rho != 0.0)
theta = atan2(dx, rho0_minus_dy);
rho_n = rho * _n;
q = (_C - (rho_n * rho_n) / (_e->radius() * _e->radius())) / _n;
q = (_C - (rho_n * rho_n) / _a2) / _n;
qc = 1 - ((_one_minus_es2) / (_two_es)) * log((1.0 - _es) / (1.0 + _es));
if (fabs(fabs(qc) - fabs(q)) > 1.0e-6) {
q_over_2 = q / 2.0;

View File

@ -1,9 +1,10 @@
#ifndef ALBERSEQUAL_H
#define ALBERSEQUAL_H
#include "ellipsoid.h"
#include "ct.h"
class Ellipsoid;
class AlbersEqual : public CT
{
public:
@ -17,13 +18,12 @@ public:
virtual Coordinates xy2ll(const QPointF &p) const;
private:
const Ellipsoid *_e;
double _latitudeOrigin;
double _longitudeOrigin;
double _falseEasting;
double _falseNorthing;
double _a2;
double _rho0;
double _C;
double _n;

View File

@ -8,7 +8,8 @@ static double sDMS2deg(double val)
const char *decimal;
QString qstr(QString::number(qAbs(val), 'f', 7));
const char *str = qstr.toLatin1().constData();
QByteArray ba = qstr.toLatin1();
const char *str = ba.constData();
decimal = strrchr(str, '.');
int deg = str2int(str, decimal - str);
int min = str2int(decimal + 1, 2);

View File

@ -2,6 +2,7 @@
#include <QtAlgorithms>
#include <QPainter>
#include "common/rectc.h"
#include "offlinemap.h"
#include "tar.h"
#include "atlas.h"
@ -15,8 +16,8 @@ static bool resCmp(const OfflineMap *m1, const OfflineMap *m2)
{
qreal r1, r2;
r1 = m1->resolution(m1->bounds().center());
r2 = m2->resolution(m2->bounds().center());
r1 = m1->resolution(m1->bounds());
r2 = m2->resolution(m2->bounds());
return r1 > r2;
}
@ -37,8 +38,8 @@ void Atlas::computeZooms()
_zooms.append(QPair<int, int>(0, _maps.count() - 1));
for (int i = 1; i < _maps.count(); i++) {
qreal last = _maps.at(i-1)->resolution(_maps.at(i)->bounds().center());
qreal cur = _maps.at(i)->resolution(_maps.at(i)->bounds().center());
qreal last = _maps.at(i-1)->resolution(_maps.at(i)->bounds());
qreal cur = _maps.at(i)->resolution(_maps.at(i)->bounds());
if (cur < last * ZOOM_THRESHOLD) {
_zooms.last().second = i-1;
_zooms.append(QPair<int, int>(i, _maps.count() - 1));
@ -78,21 +79,19 @@ void Atlas::computeBounds()
BR(_maps.at(i))), QRectF(offsets.at(i), _maps.at(i)->bounds().size())));
}
Atlas::Atlas(const QString &fileName, QObject *parent) : Map(parent)
Atlas::Atlas(const QString &fileName, QObject *parent)
: Map(parent), _zoom(0), _mapIndex(-1), _valid(false)
{
QFileInfo fi(fileName);
QByteArray ba;
QString suffix = fi.suffix().toLower();
Tar tar;
Tar tar(fileName);
_valid = false;
_zoom = 0;
_name = fi.dir().dirName();
_ci = -1; _cz = -1;
if (suffix == "tar") {
if (!tar.load(fileName)) {
if (!tar.open()) {
_errorString = "Error reading tar file";
return;
}
@ -112,7 +111,6 @@ Atlas::Atlas(const QString &fileName, QObject *parent) : Map(parent)
return;
}
QDir dir(fi.absolutePath());
QFileInfoList layers = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
for (int n = 0; n < layers.count(); n++) {
@ -149,12 +147,6 @@ Atlas::Atlas(const QString &fileName, QObject *parent) : Map(parent)
_valid = true;
}
Atlas::~Atlas()
{
for (int i = 0; i < _maps.size(); i++)
delete _maps.at(i);
}
QRectF Atlas::bounds() const
{
QSizeF s(0, 0);
@ -169,28 +161,24 @@ QRectF Atlas::bounds() const
return QRectF(QPointF(0, 0), s);
}
qreal Atlas::resolution(const QPointF &p) const
qreal Atlas::resolution(const QRectF &rect) const
{
int idx = _zooms.at(_zoom).first;
for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).second; i++) {
if (_bounds.at(i).second.contains(_maps.at(i)->xy2pp(p))) {
if (_bounds.at(i).second.contains(_maps.at(i)->xy2pp(rect.center()))) {
idx = i;
break;
}
}
return _maps.at(idx)->resolution(p);
return _maps.at(idx)->resolution(rect);
}
qreal Atlas::zoom() const
{
return _zoom;
}
qreal Atlas::zoomFit(const QSize &size, const RectC &br)
int Atlas::zoomFit(const QSize &size, const RectC &br)
{
_zoom = 0;
_mapIndex = -1;
if (!br.isValid()) {
_zoom = _zooms.size() - 1;
@ -217,35 +205,19 @@ qreal Atlas::zoomFit(const QSize &size, const RectC &br)
return _zoom;
}
qreal Atlas::zoomFit(qreal resolution, const Coordinates &c)
{
_zoom = 0;
for (int z = 0; z < _zooms.count(); z++) {
for (int i = _zooms.at(z).first; i <= _zooms.at(z).second; i++) {
if (!_bounds.at(i).first.contains(_maps.at(i)->ll2pp(c)))
continue;
if (_maps.at(i)->resolution(_maps.at(i)->ll2xy(c)) < resolution)
return _zoom;
_zoom = z;
break;
}
}
return _zoom;
}
qreal Atlas::zoomIn()
int Atlas::zoomIn()
{
_zoom = qMin(_zoom + 1, _zooms.size() - 1);
_mapIndex = -1;
return _zoom;
}
qreal Atlas::zoomOut()
int Atlas::zoomOut()
{
_zoom = qMax(_zoom - 1, 0);
_mapIndex = -1;
return _zoom;
}
@ -253,26 +225,21 @@ QPointF Atlas::ll2xy(const Coordinates &c)
{
QPointF pp;
if (_cz != _zoom) {
_ci = -1;
_cz = _zoom;
}
if (_ci >= 0)
pp = _maps.at(_ci)->ll2pp(c);
if (_ci < 0 || !_bounds.at(_ci).first.contains(pp)) {
_ci = _zooms.at(_zoom).first;
if (_mapIndex >= 0)
pp = _maps.at(_mapIndex)->ll2pp(c);
if (_mapIndex < 0 || !_bounds.at(_mapIndex).first.contains(pp)) {
_mapIndex = _zooms.at(_zoom).first;
for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).second; i++) {
pp = _maps.at(i)->ll2pp(c);
if (_bounds.at(i).first.contains(pp)) {
_ci = i;
_mapIndex = i;
break;
}
}
}
QPointF p = _maps.at(_ci)->pp2xy(pp);
return p + _bounds.at(_ci).second.topLeft();
QPointF p = _maps.at(_mapIndex)->pp2xy(pp);
return p + _bounds.at(_mapIndex).second.topLeft();
}
Coordinates Atlas::xy2ll(const QPointF &p)
@ -332,10 +299,10 @@ bool Atlas::isAtlas(const QString &path)
{
QFileInfo fi(path);
QString suffix = fi.suffix().toLower();
Tar tar;
Tar tar(path);
if (suffix == "tar") {
if (!tar.load(path))
if (!tar.open())
return false;
QString tbaFileName = fi.completeBaseName() + ".tba";
return tar.contains(tbaFileName);

View File

@ -1,10 +1,9 @@
#ifndef ATLAS_H
#define ATLAS_H
#include <QFileInfoList>
#include "map.h"
#include "offlinemap.h"
class OfflineMap;
class Atlas : public Map
{
@ -12,18 +11,16 @@ class Atlas : public Map
public:
Atlas(const QString &fileName, QObject *parent = 0);
~Atlas();
const QString &name() const {return _name;}
QRectF bounds() const;
qreal resolution(const QPointF &p) const;
qreal resolution(const QRectF &rect) const;
qreal zoom() const;
qreal zoomFit(const QSize &size, const RectC &br);
qreal zoomFit(qreal resolution, const Coordinates &c);
qreal zoomIn();
qreal zoomOut();
int zoom() const {return _zoom;}
int zoomFit(const QSize &size, const RectC &br);
int zoomIn();
int zoomOut();
QPointF ll2xy(const Coordinates &c);
Coordinates xy2ll(const QPointF &p);
@ -33,7 +30,7 @@ public:
void unload();
bool isValid() const {return _valid;}
const QString &errorString() const {return _errorString;}
QString errorString() const {return _errorString;}
static bool isAtlas(const QString &path);
@ -43,15 +40,15 @@ private:
void computeBounds();
QString _name;
bool _valid;
QString _errorString;
QList<OfflineMap*> _maps;
QVector<QPair<int, int> > _zooms;
QVector<QPair<QRectF, QRectF> > _bounds;
int _zoom;
int _mapIndex;
int _ci, _cz;
bool _valid;
QString _errorString;
};
#endif // ATLAS_H

View File

@ -0,0 +1,56 @@
#include "coordinatesystem.h"
CoordinateSystem::CoordinateSystem(int code)
{
switch (code) {
case 1024:
case 1035:
case 1039:
case 4400:
case 4409:
case 4463:
case 4464:
case 4465:
case 4466:
case 4467:
case 4469:
case 4470:
case 4495:
case 4496:
case 4497:
case 4498:
case 4499:
_axisOrder = XY;
break;
case 4500:
case 4530:
case 4531:
case 4532:
_axisOrder = YX;
break;
default:
_axisOrder = Unknown;
break;
}
}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const CoordinateSystem &cs)
{
QString ao;
switch (cs.axisOrder()) {
case CoordinateSystem::XY:
ao = "XY";
break;
case CoordinateSystem::YX:
ao = "YX";
break;
default:
ao = "Unknown";
}
dbg.nospace() << "CoordinateSystem(" << ao << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG

View File

@ -0,0 +1,27 @@
#ifndef COORDINATESYSTEM_H
#define COORDINATESYSTEM_H
#include <QDebug>
class CoordinateSystem
{
public:
enum AxisOrder {Unknown, XY, YX};
CoordinateSystem() : _axisOrder(Unknown) {}
CoordinateSystem(AxisOrder axisOrder) : _axisOrder(axisOrder) {}
CoordinateSystem(int code);
bool isValid() const {return (_axisOrder != Unknown);}
AxisOrder axisOrder() const {return _axisOrder;}
private:
AxisOrder _axisOrder;
};
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const CoordinateSystem &cs);
#endif // QT_NO_DEBUG
#endif // COORDINATESYSTEM_H

45
src/map/crs.cpp Normal file
View File

@ -0,0 +1,45 @@
#include <QStringList>
#include "pcs.h"
#include "crs.h"
Projection CRS::projection(const QString &crs)
{
QStringList list(crs.split(':'));
QString authority, code;
bool res;
int epsg;
const PCS *pcs;
const GCS *gcs;
switch (list.size()) {
case 2:
authority = list.at(0);
code = list.at(1);
break;
case 7:
authority = list.at(4);
code = list.at(6);
break;
default:
return Projection();
}
if (authority == "EPSG") {
epsg = code.toInt(&res);
if (!res)
return Projection();
if ((pcs = PCS::pcs(epsg)))
return Projection(pcs);
else if ((gcs = GCS::gcs(epsg)))
return Projection(gcs);
else
return Projection();
} else if (authority == "OGC") {
if (code == "CRS84")
return Projection(GCS::gcs(4326), CoordinateSystem::XY);
else
return Projection();
} else
return Projection();
}

11
src/map/crs.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef CRS_H
#define CRS_H
#include "projection.h"
namespace CRS
{
Projection projection(const QString &crs);
}
#endif // CRS_H

View File

@ -2,6 +2,7 @@
#include <QFileInfo>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QBasicTimer>
#include "config.h"
#include "downloader.h"
@ -25,15 +26,68 @@
#define ATTR_LEVEL (QNetworkRequest::Attribute)(QNetworkRequest::User + 2)
#define MAX_REDIRECT_LEVEL 5
#define TIMEOUT 30 /* s */
Authorization::Authorization(const QString &username, const QString &password)
{
QString concatenated = username + ":" + password;
QByteArray data = concatenated.toLocal8Bit().toBase64();
_header = "Basic " + data;
}
class Downloader::ReplyTimeout : public QObject
{
public:
static void setTimeout(QNetworkReply *reply, int timeout)
{
Q_ASSERT(reply);
new ReplyTimeout(reply, timeout);
}
private:
ReplyTimeout(QNetworkReply *reply, int timeout) : QObject(reply)
{
_timer.start(timeout * 1000, this);
}
void timerEvent(QTimerEvent *ev)
{
if (!_timer.isActive() || ev->timerId() != _timer.timerId())
return;
QNetworkReply *reply = static_cast<QNetworkReply*>(parent());
if (reply->isRunning())
reply->close();
_timer.stop();
}
QBasicTimer _timer;
};
class Downloader::Redirect
{
public:
Redirect() : _level(0) {}
Redirect(const QUrl &origin, int level) :
_origin(origin), _level(level) {}
const QUrl &origin() const {return _origin;}
int level() const {return _level;}
private:
QUrl _origin;
int _level;
};
Downloader::Downloader(QObject *parent) : QObject(parent)
{
connect(&_manager, SIGNAL(finished(QNetworkReply*)),
SLOT(downloadFinished(QNetworkReply*)));
SLOT(downloadFinished(QNetworkReply*)));
}
bool Downloader::doDownload(const Download &dl, const Redirect &redirect)
bool Downloader::doDownload(const Download &dl,
const QByteArray &authorization, const Redirect *redirect)
{
QUrl url(dl.url());
@ -44,14 +98,20 @@ bool Downloader::doDownload(const Download &dl, const Redirect &redirect)
QNetworkRequest request(url);
request.setAttribute(ATTR_FILE, QVariant(dl.file()));
if (!redirect.isNull()) {
request.setAttribute(ATTR_ORIGIN, QVariant(redirect.origin()));
request.setAttribute(ATTR_LEVEL, QVariant(redirect.level()));
if (redirect) {
request.setAttribute(ATTR_ORIGIN, QVariant(redirect->origin()));
request.setAttribute(ATTR_LEVEL, QVariant(redirect->level()));
}
request.setRawHeader("User-Agent", USER_AGENT);
QNetworkReply *reply = _manager.get(request);
if (!authorization.isNull())
request.setRawHeader("Authorization", authorization);
_currentDownloads.insert(url, reply);
QNetworkReply *reply = _manager.get(request);
if (reply) {
_currentDownloads.insert(url);
ReplyTimeout::setTimeout(reply, TIMEOUT);
} else
return false;
return true;
}
@ -61,7 +121,7 @@ bool Downloader::saveToDisk(const QString &filename, QIODevice *data)
QFile file(filename);
if (!file.open(QIODevice::WriteOnly)) {
qWarning("Error writing map tile: %s: %s\n",
qWarning("Error writing file: %s: %s\n",
qPrintable(filename), qPrintable(file.errorString()));
return false;
}
@ -80,11 +140,11 @@ void Downloader::downloadFinished(QNetworkReply *reply)
QUrl origin = reply->request().attribute(ATTR_ORIGIN).toUrl();
if (origin.isEmpty()) {
_errorDownloads.insert(url);
qWarning("Error downloading map tile: %s: %s\n",
qWarning("Error downloading file: %s: %s\n",
url.toEncoded().constData(), qPrintable(reply->errorString()));
} else {
_errorDownloads.insert(origin);
qWarning("Error downloading map tile: %s -> %s: %s\n",
qWarning("Error downloading file: %s -> %s: %s\n",
origin.toEncoded().constData(), url.toEncoded().constData(),
qPrintable(reply->errorString()));
}
@ -99,17 +159,18 @@ void Downloader::downloadFinished(QNetworkReply *reply)
if (location == url) {
_errorDownloads.insert(url);
qWarning("Error downloading map tile: %s: "
qWarning("Error downloading file: %s: "
"redirect loop\n", url.toEncoded().constData());
} else if (level >= MAX_REDIRECT_LEVEL) {
_errorDownloads.insert(origin);
qWarning("Error downloading map tile: %s: "
qWarning("Error downloading file: %s: "
"redirect level limit reached\n",
origin.toEncoded().constData());
} else {
Redirect redirect(origin.isEmpty() ? url : origin, level + 1);
Download dl(location, filename);
doDownload(dl, redirect);
doDownload(dl, reply->request().rawHeader("Authorization"),
&redirect);
}
} else
if (!saveToDisk(filename, reply))
@ -123,12 +184,13 @@ void Downloader::downloadFinished(QNetworkReply *reply)
emit finished();
}
bool Downloader::get(const QList<Download> &list)
bool Downloader::get(const QList<Download> &list,
const Authorization &authorization)
{
bool finishEmitted = false;
for (int i = 0; i < list.count(); i++)
finishEmitted |= doDownload(list.at(i));
finishEmitted |= doDownload(list.at(i), authorization.header());
return finishEmitted;
}

View File

@ -1,20 +1,18 @@
#ifndef DOWNLOADER_H
#ifndef DOWNLOADER_H
#define DOWNLOADER_H
#include <QNetworkAccessManager>
#include <QUrl>
#include <QList>
#include <QMap>
#include <QSet>
class QNetworkReply;
class Download
{
public:
Download(const QUrl &url, const QString &file)
{_url = url; _file = file;}
Download(const QUrl &url, const QString &file) : _url(url), _file(file) {}
const QUrl& url() const {return _url;}
const QString& file() const {return _file;}
@ -23,6 +21,17 @@ private:
QString _file;
};
class Authorization
{
public:
Authorization() {}
Authorization(const QString &username, const QString &password);
const QByteArray &header() const {return _header;}
private:
QByteArray _header;
};
class Downloader : public QObject
{
@ -31,7 +40,9 @@ class Downloader : public QObject
public:
Downloader(QObject *parent = 0);
bool get(const QList<Download> &list);
bool get(const QList<Download> &list, const Authorization &authorization
= Authorization());
void clearErrors() {_errorDownloads.clear();}
signals:
void finished();
@ -40,28 +51,15 @@ private slots:
void downloadFinished(QNetworkReply *reply);
private:
class Redirect
{
public:
Redirect() : _level(0) {}
Redirect(const QUrl &origin, int level) :
_origin(origin), _level(level) {}
class Redirect;
class ReplyTimeout;
const QUrl &origin() const {return _origin;}
int level() const {return _level;}
bool isNull() const {return (_level == 0);}
private:
QUrl _origin;
int _level;
};
bool doDownload(const Download &dl, const Redirect &redirect = Redirect());
bool doDownload(const Download &dl, const QByteArray &authorization,
const Redirect *redirect = 0);
bool saveToDisk(const QString &filename, QIODevice *data);
QNetworkAccessManager _manager;
QMap<QUrl, QNetworkReply *> _currentDownloads;
QSet<QUrl> _currentDownloads;
QSet<QUrl> _errorDownloads;
};

View File

@ -14,9 +14,9 @@ QMap<int, Ellipsoid> Ellipsoid::WGS84()
const Ellipsoid *Ellipsoid::ellipsoid(int id)
{
QMap<int, Ellipsoid>::const_iterator it = _ellipsoids.find(id);
QMap<int, Ellipsoid>::const_iterator it(_ellipsoids.find(id));
if (it == _ellipsoids.end())
if (it == _ellipsoids.constEnd())
return 0;
else
return &(it.value());

View File

@ -6,8 +6,9 @@
#include "emptymap.h"
#define SCALE_MIN 0.5
#define SCALE_MAX 1.0E-6
#define ZOOM_MIN 0
#define ZOOM_MAX 19
#define TILE_SIZE 256
static QPointF ll2m(const Coordinates &c)
{
@ -19,10 +20,30 @@ static Coordinates m2ll(const QPointF &p)
return Coordinates(p.x(), rad2deg(2 * atan(exp(deg2rad(p.y()))) - M_PI/2));
}
static qreal zoom2scale(int zoom)
{
return (360.0/(qreal)((1<<zoom) * TILE_SIZE));
}
static int scale2zoom(qreal scale)
{
return (int)log2(360.0/(scale * (qreal)TILE_SIZE));
}
static int limitZoom(int zoom)
{
if (zoom < ZOOM_MIN)
return ZOOM_MIN;
if (zoom > ZOOM_MAX)
return ZOOM_MAX;
return zoom;
}
EmptyMap::EmptyMap(QObject *parent) : Map(parent)
{
_scale = SCALE_MAX;
_zoom = ZOOM_MAX;
}
QRectF EmptyMap::bounds() const
@ -30,49 +51,38 @@ QRectF EmptyMap::bounds() const
return QRectF(ll2xy(Coordinates(-180, 85)), ll2xy(Coordinates(180, -85)));
}
qreal EmptyMap::zoomFit(const QSize &size, const RectC &br)
int EmptyMap::zoomFit(const QSize &size, const RectC &br)
{
if (!br.isValid())
_scale = SCALE_MAX;
_zoom = ZOOM_MAX;
else {
QRectF tbr(ll2m(br.topLeft()), ll2m(br.bottomRight()));
QPointF sc(tbr.width() / size.width(), tbr.height() / size.height());
_scale = qMax(sc.x(), sc.y());
_zoom = limitZoom(scale2zoom(qMax(sc.x(), sc.y())));
}
_scale = qMax(_scale, SCALE_MAX);
_scale = qMin(_scale, SCALE_MIN);
return _scale;
return _zoom;
}
qreal EmptyMap::zoomFit(qreal resolution, const Coordinates &c)
qreal EmptyMap::resolution(const QRectF &rect) const
{
_scale = (360.0 * resolution) / (WGS84_RADIUS * 2 * M_PI
* cos(deg2rad(c.lat())));
qreal scale = zoom2scale(_zoom);
_scale = qMax(_scale, SCALE_MAX);
_scale = qMin(_scale, SCALE_MIN);
return _scale;
return (WGS84_RADIUS * 2.0 * M_PI * scale / 360.0
* cos(2.0 * atan(exp(deg2rad(-rect.center().y() * scale))) - M_PI/2));
}
qreal EmptyMap::resolution(const QPointF &p) const
int EmptyMap::zoomIn()
{
return (WGS84_RADIUS * 2 * M_PI * _scale / 360.0
* cos(2.0 * atan(exp(deg2rad(-p.y() * _scale))) - M_PI/2));
_zoom = qMin(_zoom + 1, ZOOM_MAX);
return _zoom;
}
qreal EmptyMap::zoomIn()
int EmptyMap::zoomOut()
{
_scale = qMax(_scale / 2.0, SCALE_MAX);
return _scale;
}
qreal EmptyMap::zoomOut()
{
_scale = qMin(_scale * 2.0, SCALE_MIN);
return _scale;
_zoom = qMax(_zoom - 1, ZOOM_MIN);
return _zoom;
}
void EmptyMap::draw(QPainter *painter, const QRectF &rect)
@ -82,12 +92,13 @@ void EmptyMap::draw(QPainter *painter, const QRectF &rect)
QPointF EmptyMap::ll2xy(const Coordinates &c) const
{
qreal scale = zoom2scale(_zoom);
QPointF m = ll2m(c);
return QPointF(m.x() / _scale, m.y() / -_scale);
return QPointF(m.x() / scale, m.y() / -scale);
}
Coordinates EmptyMap::xy2ll(const QPointF &p) const
{
QPointF m(p.x() * _scale, -p.y() * _scale);
return m2ll(QPointF(p.x() * _scale, -p.y() * _scale));
qreal scale = zoom2scale(_zoom);
return m2ll(QPointF(p.x() * scale, -p.y() * scale));
}

View File

@ -1,7 +1,6 @@
#ifndef EMPTYMAP_H
#define EMPTYMAP_H
#include "common/coordinates.h"
#include "map.h"
class EmptyMap : public Map
@ -14,13 +13,12 @@ public:
const QString &name() const {return _name;}
QRectF bounds() const;
qreal resolution(const QPointF &p) const;
qreal resolution(const QRectF &rect) const;
qreal zoom() const {return _scale;}
qreal zoomFit(const QSize &size, const RectC &br);
qreal zoomFit(qreal resolution, const Coordinates &c);
qreal zoomIn();
qreal zoomOut();
int zoom() const {return _zoom;}
int zoomFit(const QSize &size, const RectC &br);
int zoomIn();
int zoomOut();
QPointF ll2xy(const Coordinates &c)
{return static_cast<const EmptyMap &>(*this).ll2xy(c);}
@ -34,7 +32,7 @@ private:
Coordinates xy2ll(const QPointF &p) const;
QString _name;
qreal _scale;
int _zoom;
};
#endif // EMPTYMAP_H

View File

@ -92,62 +92,62 @@ void GCS::loadList(const QString &path)
QByteArray line = file.readLine();
QList<QByteArray> list = line.split(',');
if (list.size() < 10) {
qWarning("%s: %d: Format error", qPrintable(path), ln);
qWarning("%s:%d: Format error", qPrintable(path), ln);
continue;
}
int id = parameter(list[1], &res);
if (!res) {
qWarning("%s: %d: Invalid GCS code", qPrintable(path), ln);
qWarning("%s:%d: Invalid GCS code", qPrintable(path), ln);
continue;
}
int gd = parameter(list[2], &res);
if (!res) {
qWarning("%s: %d: Invalid geodetic datum code", qPrintable(path),
qWarning("%s:%d: Invalid geodetic datum code", qPrintable(path),
ln);
continue;
}
int au = list[3].trimmed().toInt(&res);
if (!res) {
qWarning("%s: %d: Invalid angular units code", qPrintable(path),
qWarning("%s:%d: Invalid angular units code", qPrintable(path),
ln);
continue;
}
int el = list[4].trimmed().toInt(&res);
if (!res) {
qWarning("%s: %d: Invalid ellipsoid code", qPrintable(path), ln);
qWarning("%s:%d: Invalid ellipsoid code", qPrintable(path), ln);
continue;
}
int pm = list[5].trimmed().toInt(&res);
if (!res) {
qWarning("%s: %d: Invalid prime meridian code", qPrintable(path),
qWarning("%s:%d: Invalid prime meridian code", qPrintable(path),
ln);
continue;
}
int ct = list[6].trimmed().toInt(&res);
if (!res) {
qWarning("%s: %d: Invalid coordinates transformation code",
qWarning("%s:%d: Invalid coordinates transformation code",
qPrintable(path), ln);
continue;
}
double dx = list[7].trimmed().toDouble(&res);
if (!res) {
qWarning("%s: %d: Invalid dx", qPrintable(path), ln);
qWarning("%s:%d: Invalid dx", qPrintable(path), ln);
continue;
}
double dy = list[8].trimmed().toDouble(&res);
if (!res) {
qWarning("%s: %d: Invalid dy", qPrintable(path), ln);
qWarning("%s:%d: Invalid dy", qPrintable(path), ln);
continue;
}
double dz = list[9].trimmed().toDouble(&res);
if (!res) {
qWarning("%s: %d: Invalid dz", qPrintable(path), ln);
qWarning("%s:%d: Invalid dz", qPrintable(path), ln);
continue;
}
if (!(e = Ellipsoid::ellipsoid(el))) {
qWarning("%s: %d: Unknown ellipsoid code", qPrintable(path), ln);
qWarning("%s:%d: Unknown ellipsoid code", qPrintable(path), ln);
continue;
}
@ -157,7 +157,7 @@ void GCS::loadList(const QString &path)
datum = Datum(e, dx, dy, dz);
break;
default:
qWarning("%s: %d: Unknown coordinates transformation method",
qWarning("%s:%d: Unknown coordinates transformation method",
qPrintable(path), ln);
continue;
}
@ -166,7 +166,7 @@ void GCS::loadList(const QString &path)
if (gcs.isValid())
_gcss.append(Entry(id, gd, list[0].trimmed(), gcs));
else
qWarning("%s: %d: Unknown prime meridian/angular units code",
qWarning("%s:%d: Unknown prime meridian/angular units code",
qPrintable(path), ln);
}
}

View File

@ -25,7 +25,6 @@ public:
Coordinates toWGS84(const Coordinates &c) const;
Coordinates fromWGS84(const Coordinates &c) const;
static const GCS *gcs(int id);
static const GCS *gcs(int geodeticDatum, int primeMeridian,
int angularUnits);

View File

@ -1,7 +1,7 @@
#include <QFileInfo>
#include <QtEndian>
#include "pcs.h"
#include "latlon.h"
#include "tifffile.h"
#include "geotiff.h"
@ -9,41 +9,53 @@
#define TIFF_SHORT 3
#define TIFF_LONG 4
#define ModelPixelScaleTag 33550
#define ModelTiepointTag 33922
#define ModelTransformationTag 34264
#define GeoKeyDirectoryTag 34735
#define GeoDoubleParamsTag 34736
#define ImageWidth 256
#define ImageHeight 257
#define ModelPixelScaleTag 33550
#define ModelTiepointTag 33922
#define ModelTransformationTag 34264
#define GeoKeyDirectoryTag 34735
#define GeoDoubleParamsTag 34736
#define GTModelTypeGeoKey 1024
#define GTRasterTypeGeoKey 1025
#define GeographicTypeGeoKey 2048
#define GeogGeodeticDatumGeoKey 2050
#define GeogPrimeMeridianGeoKey 2051
#define GeogAngularUnitsGeoKey 2054
#define ProjectedCSTypeGeoKey 3072
#define ProjectionGeoKey 3074
#define ProjCoordTransGeoKey 3075
#define ProjLinearUnitsGeoKey 3076
#define ProjStdParallel1GeoKey 3078
#define ProjStdParallel2GeoKey 3079
#define ProjNatOriginLongGeoKey 3080
#define ProjNatOriginLatGeoKey 3081
#define ProjFalseEastingGeoKey 3082
#define ProjFalseNorthingGeoKey 3083
#define ProjScaleAtNatOriginGeoKey 3092
#define GTModelTypeGeoKey 1024
#define GTRasterTypeGeoKey 1025
#define GeographicTypeGeoKey 2048
#define GeogGeodeticDatumGeoKey 2050
#define GeogPrimeMeridianGeoKey 2051
#define GeogAngularUnitsGeoKey 2054
#define GeogEllipsoidGeoKey 2056
#define GeogAzimuthUnitsGeoKey 2060
#define ProjectedCSTypeGeoKey 3072
#define ProjectionGeoKey 3074
#define ProjCoordTransGeoKey 3075
#define ProjLinearUnitsGeoKey 3076
#define ProjStdParallel1GeoKey 3078
#define ProjStdParallel2GeoKey 3079
#define ProjNatOriginLongGeoKey 3080
#define ProjNatOriginLatGeoKey 3081
#define ProjFalseEastingGeoKey 3082
#define ProjFalseNorthingGeoKey 3083
#define ProjCenterLongGeoKey 3088
#define ProjCenterLatGeoKey 3089
#define ProjScaleAtNatOriginGeoKey 3092
#define ProjScaleAtCenterGeoKey 3093
#define ProjAzimuthAngleGeoKey 3094
#define ProjRectifiedGridAngleGeoKey 3096
#define ModelTypeProjected 1
#define ModelTypeGeographic 2
#define ModelTypeGeocentric 3
#define CT_TransverseMercator 1
#define CT_ObliqueMercator 3
#define CT_Mercator 7
#define CT_LambertConfConic_2SP 8
#define CT_LambertConfConic_1SP 9
#define CT_LambertAzimEqualArea 10
#define CT_AlbersEqualArea 11
#define ModelTypeProjected 1
#define ModelTypeGeographic 2
#define ModelTypeGeocentric 3
#define IS_SET(map, key) \
((map).contains(key) && (map).value(key).SHORT != 32767)
#define ARRAY_SIZE(a) \
(sizeof(a) / sizeof(*a))
typedef struct {
quint16 KeyDirectoryVersion;
@ -219,10 +231,12 @@ bool GeoTIFF::readKeys(TIFFFile &file, Ctx &ctx, QMap<quint16, Value> &kv) const
case GeogGeodeticDatumGeoKey:
case GeogPrimeMeridianGeoKey:
case GeogAngularUnitsGeoKey:
case GeogAzimuthUnitsGeoKey:
case ProjectedCSTypeGeoKey:
case ProjectionGeoKey:
case ProjCoordTransGeoKey:
case ProjLinearUnitsGeoKey:
case GeogEllipsoidGeoKey:
if (entry.TIFFTagLocation != 0 || entry.Count != 1)
return false;
value.SHORT = entry.ValueOffset;
@ -235,6 +249,11 @@ bool GeoTIFF::readKeys(TIFFFile &file, Ctx &ctx, QMap<quint16, Value> &kv) const
case ProjFalseNorthingGeoKey:
case ProjStdParallel1GeoKey:
case ProjStdParallel2GeoKey:
case ProjCenterLongGeoKey:
case ProjCenterLatGeoKey:
case ProjScaleAtCenterGeoKey:
case ProjAzimuthAngleGeoKey:
case ProjRectifiedGridAngleGeoKey:
if (!readGeoValue(file, ctx.values, entry.ValueOffset,
value.DOUBLE))
return false;
@ -272,13 +291,20 @@ const GCS *GeoTIFF::gcs(QMap<quint16, Value> &kv)
if (!(gcs = GCS::gcs(kv.value(GeographicTypeGeoKey).SHORT)))
_errorString = QString("%1: unknown GCS")
.arg(kv.value(GeographicTypeGeoKey).SHORT);
} else if (IS_SET(kv, GeogGeodeticDatumGeoKey)) {
} else if (IS_SET(kv, GeogGeodeticDatumGeoKey)
|| kv.value(GeogEllipsoidGeoKey).SHORT == 7019
|| kv.value(GeogEllipsoidGeoKey).SHORT == 7030) {
int pm = IS_SET(kv, GeogPrimeMeridianGeoKey)
? kv.value(GeogPrimeMeridianGeoKey).SHORT : 8901;
int au = IS_SET(kv, GeogAngularUnitsGeoKey)
? kv.value(GeogAngularUnitsGeoKey).SHORT : 9102;
if (!(gcs = GCS::gcs(kv.value(GeogGeodeticDatumGeoKey).SHORT, pm, au)))
// If only the ellipsoid is defined and it is GRS80 or WGS84, handle
// such definition as a WGS84 geodetic datum.
int gd = IS_SET(kv, GeogGeodeticDatumGeoKey)
? kv.value(GeogGeodeticDatumGeoKey).SHORT : 6326;
if (!(gcs = GCS::gcs(gd, pm, au)))
_errorString = QString("%1+%2: unknown geodetic datum + prime"
" meridian combination")
.arg(kv.value(GeogGeodeticDatumGeoKey).SHORT)
@ -297,17 +323,19 @@ Projection::Method GeoTIFF::method(QMap<quint16, Value> &kv)
}
switch (kv.value(ProjCoordTransGeoKey).SHORT) {
case 1:
case CT_TransverseMercator:
return Projection::Method(9807);
case 7:
case CT_ObliqueMercator:
return Projection::Method(9815);
case CT_Mercator:
return Projection::Method(1024);
case 8:
return Projection::Method(9801);
case 9:
case CT_LambertConfConic_2SP:
return Projection::Method(9802);
case 10:
case CT_LambertConfConic_1SP:
return Projection::Method(9801);
case CT_LambertAzimEqualArea:
return Projection::Method(9820);
case 11:
case CT_AlbersEqualArea:
return Projection::Method(9822);
default:
_errorString = QString("%1: unknown coordinate transformation method")
@ -325,8 +353,7 @@ bool GeoTIFF::projectedModel(QMap<quint16, Value> &kv)
.arg(kv.value(ProjectedCSTypeGeoKey).SHORT);
return false;
}
_projection = Projection(pcs->gcs(), pcs->method(), pcs->setup(),
pcs->units());
_projection = Projection(pcs);
} else if (IS_SET(kv, ProjectionGeoKey)) {
const GCS *g = gcs(kv);
if (!g)
@ -338,9 +365,10 @@ bool GeoTIFF::projectedModel(QMap<quint16, Value> &kv)
.arg(kv.value(ProjectionGeoKey).SHORT);
return false;
}
_projection = Projection(pcs->gcs(), pcs->method(), pcs->setup(),
pcs->units());
_projection = Projection(pcs);
} else {
double lat0, lon0, scale, fe, fn, sp1, sp2;
const GCS *g = gcs(kv);
if (!g)
return false;
@ -350,6 +378,8 @@ bool GeoTIFF::projectedModel(QMap<quint16, Value> &kv)
AngularUnits au(IS_SET(kv, GeogAngularUnitsGeoKey)
? kv.value(GeogAngularUnitsGeoKey).SHORT : 9102);
AngularUnits zu(IS_SET(kv, GeogAzimuthUnitsGeoKey)
? kv.value(GeogAzimuthUnitsGeoKey).SHORT : 9102);
LinearUnits lu(IS_SET(kv, ProjLinearUnitsGeoKey)
? kv.value(ProjLinearUnitsGeoKey).SHORT : 9001);
if (lu.isNull()) {
@ -358,17 +388,48 @@ bool GeoTIFF::projectedModel(QMap<quint16, Value> &kv)
return false;
}
Projection::Setup setup(
au.toDegrees(kv.value(ProjNatOriginLatGeoKey).DOUBLE),
au.toDegrees(kv.value(ProjNatOriginLongGeoKey).DOUBLE),
kv.value(ProjScaleAtNatOriginGeoKey).DOUBLE,
lu.toMeters(kv.value(ProjFalseEastingGeoKey).DOUBLE),
lu.toMeters(kv.value(ProjFalseNorthingGeoKey).DOUBLE),
au.toDegrees(kv.value(ProjStdParallel1GeoKey).DOUBLE),
au.toDegrees(kv.value(ProjStdParallel2GeoKey).DOUBLE)
);
if (kv.contains(ProjNatOriginLatGeoKey))
lat0 = au.toDegrees(kv.value(ProjNatOriginLatGeoKey).DOUBLE);
else if (kv.contains(ProjCenterLatGeoKey))
lat0 = au.toDegrees(kv.value(ProjCenterLatGeoKey).DOUBLE);
else
lat0 = NAN;
if (kv.contains(ProjNatOriginLongGeoKey))
lon0 = au.toDegrees(kv.value(ProjNatOriginLongGeoKey).DOUBLE);
else if (kv.contains(ProjCenterLongGeoKey))
lon0 = au.toDegrees(kv.value(ProjCenterLongGeoKey).DOUBLE);
else
lon0 = NAN;
if (kv.contains(ProjScaleAtNatOriginGeoKey))
scale = kv.value(ProjScaleAtNatOriginGeoKey).DOUBLE;
else if (kv.contains(ProjScaleAtCenterGeoKey))
scale = kv.value(ProjScaleAtCenterGeoKey).DOUBLE;
else
scale = NAN;
if (kv.contains(ProjStdParallel1GeoKey))
sp1 = au.toDegrees(kv.value(ProjStdParallel1GeoKey).DOUBLE);
else if (kv.contains(ProjAzimuthAngleGeoKey))
sp1 = zu.toDegrees(kv.value(ProjAzimuthAngleGeoKey).DOUBLE);
else
sp1 = NAN;
if (kv.contains(ProjStdParallel2GeoKey))
sp2 = au.toDegrees(kv.value(ProjStdParallel2GeoKey).DOUBLE);
else if (kv.contains(ProjRectifiedGridAngleGeoKey))
sp2 = au.toDegrees(kv.value(ProjRectifiedGridAngleGeoKey).DOUBLE);
else
sp2 = NAN;
if (kv.contains(ProjFalseNorthingGeoKey))
fn = lu.toMeters(kv.value(ProjFalseNorthingGeoKey).DOUBLE);
else
fn = NAN;
if (kv.contains(ProjFalseEastingGeoKey))
fe = lu.toMeters(kv.value(ProjFalseEastingGeoKey).DOUBLE);
else
fe = NAN;
_projection = Projection(g, m, setup, lu);
Projection::Setup setup(lat0, lon0, scale, fe, fn, sp1, sp2);
PCS pcs(g, m, setup, lu, CoordinateSystem());
_projection = Projection(&pcs);
}
return true;
@ -385,7 +446,7 @@ bool GeoTIFF::geographicModel(QMap<quint16, Value> &kv)
return true;
}
bool GeoTIFF::load(const QString &path)
GeoTIFF::GeoTIFF(const QString &path)
{
quint32 ifd;
QList<ReferencePoint> points;
@ -399,86 +460,76 @@ bool GeoTIFF::load(const QString &path)
if (!file.open(QIODevice::ReadOnly)) {
_errorString = QString("Error opening TIFF file: %1")
.arg(file.errorString());
return false;
return;
}
if (!file.readHeader(ifd)) {
_errorString = "Invalid TIFF header";
return false;
return;
}
while (ifd) {
if (!readIFD(file, ifd, ctx)) {
_errorString = "Invalid IFD";
return false;
return;
}
}
if (!ctx.keys) {
_errorString = "Not a GeoTIFF file";
return false;
return;
}
if (ctx.scale) {
if (!readScale(file, ctx.scale, scale)) {
_errorString = "Error reading model pixel scale";
return false;
return;
}
}
if (ctx.tiepoints) {
if (!readTiepoints(file, ctx.tiepoints, ctx.tiepointCount, points)) {
_errorString = "Error reading raster->model tiepoint pairs";
return false;
return;
}
}
if (!readKeys(file, ctx, kv)) {
_errorString = "Error reading Geo key/value";
return false;
return;
}
switch (kv.value(GTModelTypeGeoKey).SHORT) {
case ModelTypeProjected:
if (!projectedModel(kv))
return false;
return;
break;
case ModelTypeGeographic:
if (!geographicModel(kv))
return false;
return;
break;
case ModelTypeGeocentric:
_errorString = "Geocentric models are not supported";
return false;
return;
default:
_errorString = "Unknown/missing model type";
return false;
return;
}
if (ctx.scale && ctx.tiepoints) {
const ReferencePoint &p = points.first();
_transform = QTransform(scale.x(), 0, 0, -scale.y(), p.pp.x() - p.xy.x()
/ scale.x(), p.pp.y() + p.xy.x() / scale.y()).inverted();
} else if (ctx.tiepointCount > 1) {
Transform t(points);
if (t.isNull()) {
_errorString = t.errorString();
return false;
}
_transform = t.transform();
} else if (ctx.matrix) {
if (ctx.scale && ctx.tiepoints)
_transform = Transform(points.first(), scale);
else if (ctx.tiepointCount > 1)
_transform = Transform(points);
else if (ctx.matrix) {
double m[16];
if (!readMatrix(file, ctx.matrix, m)) {
_errorString = "Error reading transformation matrix";
return false;
return;
}
if (m[2] != 0.0 || m[6] != 0.0 || m[8] != 0.0 || m[9] != 0.0
|| m[10] != 0.0 || m[11] != 0.0) {
_errorString = "Not a baseline transformation matrix";
}
_transform = QTransform(m[0], m[1], m[4], m[5], m[3], m[7]).inverted();
_transform = Transform(m);
} else {
_errorString = "Incomplete/missing model transformation info";
return false;
return;
}
return true;
if (!_transform.isValid())
_errorString = _transform.errorString();
}

View File

@ -1,23 +1,24 @@
#ifndef GEOTIFF_H
#define GEOTIFF_H
#include <QTransform>
#include <QFile>
#include <QMap>
#include "gcs.h"
#include "projection.h"
#include "tifffile.h"
#include <QList>
#include "transform.h"
#include "linearunits.h"
#include "projection.h"
class TIFFFile;
class GCS;
class GeoTIFF
{
public:
bool load(const QString &path);
GeoTIFF(const QString &path);
bool isValid() const {return _projection.isValid() && _transform.isValid();}
const QString &errorString() const {return _errorString;}
const Projection &projection() const {return _projection;}
const QTransform &transform() const {return _transform;}
const Transform &transform() const {return _transform;}
private:
union Value {
@ -52,7 +53,7 @@ private:
bool geographicModel(QMap<quint16, Value> &kv);
bool projectedModel(QMap<quint16, Value> &kv);
QTransform _transform;
Transform _transform;
Projection _projection;
QString _errorString;

View File

@ -1,193 +1,72 @@
/*
* 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 <cmath>
#include "ellipsoid.h"
#include "lambertazimuthal.h"
#ifndef M_PI_2
#define M_PI_2 1.57079632679489661923
#endif // M_PI_2
#define sin2(x) (sin(x) * sin(x))
#define sqr(x) ((x) * (x))
LambertAzimuthal::LambertAzimuthal(const Ellipsoid *ellipsoid,
double latitudeOrigin, double longitudeOrigin, double falseEasting,
double falseNorthing)
{
double es2, es4, es6;
double lat0 = deg2rad(latitudeOrigin);
es2 = 2 * ellipsoid->flattening() - ellipsoid->flattening()
* ellipsoid->flattening();
es4 = es2 * es2;
es6 = es4 * es2;
_ra = ellipsoid->radius() * (1.0 - es2 / 6.0 - 17.0 * es4 / 360.0 - 67.0
* es6 / 3024.0);
_latOrigin = deg2rad(latitudeOrigin);
_sinLatOrigin = sin(_latOrigin);
_cosLatOrigin = cos(_latOrigin);
_absLatOrigin = fabs(_latOrigin);
_lonOrigin = deg2rad(longitudeOrigin);
if (_lonOrigin > M_PI)
_lonOrigin -= 2.0 * M_PI;
_falseNorthing = falseNorthing;
_falseEasting = falseEasting;
_falseNorthing = falseNorthing;
_lon0 = deg2rad(longitudeOrigin);
_a = ellipsoid->radius();
_es2 = 2.0 * ellipsoid->flattening() - ellipsoid->flattening()
* ellipsoid->flattening();
_es = sqrt(_es2);
double q0 = (1.0 - _es2) * ((sin(lat0) / (1.0 - _es2 * sin2(lat0)))
- ((1.0/(2.0*_es)) * log((1.0 - _es * sin(lat0)) / (1.0 + _es
* sin(lat0)))));
_qP = (1.0 - _es2) * ((1.0 / (1.0 - _es2)) - ((1.0/(2.0*_es))
* log((1.0 - _es) / (1.0 + _es))));
_beta0 = asin(q0 / _qP);
_Rq = _a * sqrt(_qP / 2.0);
_D = _a * (cos(lat0) / sqrt(1.0 - _es2 * sin2(lat0))) / (_Rq * cos(_beta0));
}
QPointF LambertAzimuthal::ll2xy(const Coordinates &c) const
{
double dlam;
double k_prime;
double cd;
double rlat = deg2rad(c.lat());
double slat = sin(rlat);
double clat = cos(rlat);
double cos_c;
double sin_dlam, cos_dlam;
double Ra_kprime;
double Ra_PI_OVER_2_Lat;
QPointF p;
double lon = deg2rad(c.lon());
double lat = deg2rad(c.lat());
double q = (1.0 - _es2) * ((sin(lat) / (1.0 - _es2 * sin2(lat)))
- ((1.0/(2.0*_es)) * log((1.0 - _es * sin(lat)) / (1.0 + _es
* sin(lat)))));
double beta = asin(q / _qP);
double B = _Rq * sqrt(2.0 / (1.0 + sin(_beta0) * sin(beta) + (cos(_beta0)
* cos(beta) * cos(lon - _lon0))));
dlam = deg2rad(c.lon()) - _lonOrigin;
if (dlam > M_PI)
dlam -= 2.0 * M_PI;
if (dlam < -M_PI)
dlam += 2.0 * M_PI;
double x = _falseEasting + ((B * _D) * (cos(beta) * sin(lon - _lon0)));
double y = _falseNorthing + (B / _D) * ((cos(_beta0) * sin(beta))
- (sin(_beta0) * cos(beta) * cos(lon - _lon0)));
sin_dlam = sin(dlam);
cos_dlam = cos(dlam);
if (fabs(_absLatOrigin - M_PI_2) < 1.0e-10) {
if (_latOrigin >= 0.0) {
Ra_PI_OVER_2_Lat = _ra * (M_PI_2 - rlat);
p.rx() = Ra_PI_OVER_2_Lat * sin_dlam + _falseEasting;
p.ry() = -1.0 * (Ra_PI_OVER_2_Lat * cos_dlam) + _falseNorthing;
} else {
Ra_PI_OVER_2_Lat = _ra * (M_PI_2 + rlat);
p.rx() = Ra_PI_OVER_2_Lat * sin_dlam + _falseEasting;
p.ry() = Ra_PI_OVER_2_Lat * cos_dlam + _falseNorthing;
}
} else if (_absLatOrigin <= 1.0e-10) {
cos_c = clat * cos_dlam;
if (fabs(fabs(cos_c) - 1.0) < 1.0e-14) {
if (cos_c >= 0.0) {
p.rx() = _falseEasting;
p.ry() = _falseNorthing;
} else
return QPointF(NAN, NAN);
} else {
cd = acos(cos_c);
k_prime = cd / sin(cd);
Ra_kprime = _ra * k_prime;
p.rx() = Ra_kprime * clat * sin_dlam + _falseEasting;
p.ry() = Ra_kprime * slat + _falseNorthing;
}
} else {
cos_c = (_sinLatOrigin * slat) + (_cosLatOrigin * clat * cos_dlam);
if (fabs(fabs(cos_c) - 1.0) < 1.0e-14) {
if (cos_c >= 0.0) {
p.rx() = _falseEasting;
p.ry() = _falseNorthing;
} else
return QPointF(NAN, NAN);
} else {
cd = acos(cos_c);
k_prime = cd / sin(cd);
Ra_kprime = _ra * k_prime;
p.rx() = Ra_kprime * clat * sin_dlam + _falseEasting;
p.ry() = Ra_kprime * (_cosLatOrigin * slat - _sinLatOrigin * clat
* cos_dlam) + _falseNorthing;
}
}
return p;
return QPointF(x, y);
}
Coordinates LambertAzimuthal::xy2ll(const QPointF &p) const
{
double dx, dy;
double rho;
double cd;
double sin_c, cos_c, dy_sinc;
double lat, lon;
double es4 = _es2 * _es2;
double es6 = _es2 * es4;
double rho = sqrt(sqr((p.x() - _falseEasting) / _D) + sqr(_D * (p.y()
- _falseNorthing)));
double C = 2.0 * asin(rho / (2.0*_Rq));
double betaS = asin((cos(C) * sin(_beta0)) + ((_D * (p.y() -_falseNorthing)
* sin(C) * cos(_beta0)) / rho));
dy = p.y() - _falseNorthing;
dx = p.x() - _falseEasting;
rho = sqrt(dx * dx + dy * dy);
if (fabs(rho) <= 1.0e-10) {
lat = _latOrigin;
lon = _lonOrigin;
} else {
cd = rho / _ra;
sin_c = sin(cd);
cos_c = cos(cd);
dy_sinc = dy * sin_c;
lat = asin((cos_c * _sinLatOrigin) + ((dy_sinc * _cosLatOrigin) / rho));
if (fabs(_absLatOrigin - M_PI_2) < 1.0e-10) {
if (_latOrigin >= 0.0)
lon = _lonOrigin + atan2(dx, -dy);
else
lon = _lonOrigin + atan2(dx, dy);
}
else
lon = _lonOrigin + atan2((dx * sin_c), ((rho * _cosLatOrigin
* cos_c) - (dy_sinc * _sinLatOrigin)));
}
if (lat > M_PI_2)
lat = M_PI_2;
else if (lat < -M_PI_2)
lat = -M_PI_2;
if (lon > M_PI)
lon -= 2.0 * M_PI;
if (lon < -M_PI)
lon += 2.0 * M_PI;
if (lon > M_PI)
lon = M_PI;
else if (lon < -M_PI)
lon = -M_PI;
double lon = _lon0 + atan((p.x() - _falseEasting) * sin(C) / (_D * rho
* cos(_beta0) * cos(C) - sqr(_D) * (p.y() - _falseNorthing) * sin(_beta0)
* sin(C)));
double lat = betaS + ((_es2/3.0 + 31.0*es4/180.0 + 517.0*es6/5040.0)
* sin(2.0*betaS)) + ((23.0*es4/360.0 + 251.0*es6/3780.0) * sin(4.0*betaS))
+ ((761.0*es6/45360.0)*sin(6.0*betaS));
return Coordinates(rad2deg(lon), rad2deg(lat));
}

View File

@ -1,9 +1,10 @@
#ifndef LAMBERTAZIMUTHAL_H
#define LAMBERTAZIMUTHAL_H
#include "ellipsoid.h"
#include "ct.h"
class Ellipsoid;
class LambertAzimuthal : public CT
{
public:
@ -16,15 +17,10 @@ public:
virtual Coordinates xy2ll(const QPointF &p) const;
private:
double _ra;
double _sinLatOrigin;
double _cosLatOrigin;
double _absLatOrigin;
double _latOrigin;
double _lonOrigin;
double _lon0;
double _falseNorthing;
double _falseEasting;
double _a, _es, _es2, _qP, _beta0, _Rq, _D;
};
#endif // LAMBERTAZIMUTHAL_H

View File

@ -42,6 +42,7 @@ Defense.
*/
#include <cmath>
#include "ellipsoid.h"
#include "lambertconic.h"
#ifndef M_PI_2

View File

@ -1,9 +1,10 @@
#ifndef LAMBERTCONIC_H
#define LAMBERTCONIC_H
#include "ellipsoid.h"
#include "ct.h"
class Ellipsoid;
class LambertConic1 : public CT
{
public:

View File

@ -5,9 +5,9 @@
#include <QString>
#include <QRectF>
#include <QColor>
#include "common/coordinates.h"
class QPainter;
class Coordinates;
class RectC;
class Map : public QObject
@ -15,18 +15,18 @@ class Map : public QObject
Q_OBJECT
public:
Map(QObject *parent = 0) : QObject(parent) {_backgroundColor = Qt::white;}
Map(QObject *parent = 0) : QObject(parent), _backgroundColor(Qt::white) {}
virtual ~Map() {}
virtual const QString &name() const = 0;
virtual QRectF bounds() const = 0;
virtual qreal resolution(const QPointF &p) const = 0;
virtual qreal resolution(const QRectF &rect) const = 0;
virtual qreal zoom() const = 0;
virtual qreal zoomFit(const QSize &size, const RectC &br) = 0;
virtual qreal zoomFit(qreal resolution, const Coordinates &c) = 0;
virtual qreal zoomIn() = 0;
virtual qreal zoomOut() = 0;
virtual int zoom() const = 0;
virtual int zoomFit(const QSize &size, const RectC &br) = 0;
virtual int zoomIn() = 0;
virtual int zoomOut() = 0;
virtual QPointF ll2xy(const Coordinates &c) = 0;
virtual Coordinates xy2ll(const QPointF &p) = 0;
@ -40,6 +40,9 @@ public:
void setBackgroundColor(const QColor &color) {_backgroundColor = color;}
virtual bool isValid() const {return true;}
virtual QString errorString() const {return QString();}
signals:
void loaded();

View File

@ -1,5 +1,7 @@
#include <QIODevice>
#include "utm.h"
#include "gcs.h"
#include "pcs.h"
#include "mapfile.h"
@ -127,7 +129,7 @@ int MapFile::parse(QIODevice &device, QList<CalibrationPoint> &points,
ln++;
}
return (ln == 1) ? 1 : 0;
return (ln < 9) ? ln : 0;
}
bool MapFile::parseMapFile(QIODevice &device, QList<CalibrationPoint> &points,
@ -162,18 +164,21 @@ const GCS *MapFile::createGCS(const QString &datum)
bool MapFile::createProjection(const GCS *gcs, const QString &name,
const Projection::Setup &setup, QList<CalibrationPoint> &points)
{
PCS pcs;
if (name == "Mercator")
_projection = Projection(gcs, 1024, setup, 9001);
pcs = PCS(gcs, 1024, setup, 9001);
else if (name == "Transverse Mercator")
_projection = Projection(gcs, 9807, setup, 9001);
else if (name == "Latitude/Longitude")
pcs = PCS(gcs, 9807, setup, 9001);
else if (name == "Latitude/Longitude") {
_projection = Projection(gcs);
else if (name == "Lambert Conformal Conic")
_projection = Projection(gcs, 9802, setup, 9001);
return true;
} else if (name == "Lambert Conformal Conic")
pcs = PCS(gcs, 9802, setup, 9001);
else if (name == "Albers Equal Area")
_projection = Projection(gcs, 9822, setup, 9001);
pcs = PCS(gcs, 9822, setup, 9001);
else if (name == "(A)Lambert Azimuthual Equal Area")
_projection = Projection(gcs, 9820, setup, 9001);
pcs = PCS(gcs, 9820, setup, 9001);
else if (name == "(UTM) Universal Transverse Mercator") {
int zone;
if (points.first().zone)
@ -184,42 +189,47 @@ bool MapFile::createProjection(const GCS *gcs, const QString &name,
_errorString = "Can not determine UTM zone";
return false;
}
_projection = Projection(gcs, 9807, UTM::setup(zone), 9001);
pcs = PCS(gcs, 9807, UTM::setup(zone), 9001);
} else if (name == "(NZTM2) New Zealand TM 2000")
_projection = Projection(gcs, 9807, Projection::Setup(0, 173.0, 0.9996,
1600000, 10000000, NAN, NAN), 9001);
pcs = PCS(gcs, 9807, Projection::Setup(0, 173.0, 0.9996, 1600000,
10000000, NAN, NAN), 9001);
else if (name == "(BNG) British National Grid")
_projection = Projection(gcs, 9807, Projection::Setup(49, -2, 0.999601,
400000, -100000, NAN, NAN), 9001);
pcs = PCS(gcs, 9807, Projection::Setup(49, -2, 0.999601, 400000,
-100000, NAN, NAN), 9001);
else if (name == "(IG) Irish Grid")
_projection = Projection(gcs, 9807, Projection::Setup(53.5, -8,
1.000035, 200000, 250000, NAN, NAN), 9001);
pcs = PCS(gcs, 9807, Projection::Setup(53.5, -8, 1.000035, 200000,
250000, NAN, NAN), 9001);
else if (name == "(SG) Swedish Grid")
_projection = Projection(gcs, 9807, Projection::Setup(0, 15.808278, 1,
1500000, 0, NAN, NAN), 9001);
pcs = PCS(gcs, 9807, Projection::Setup(0, 15.808278, 1, 1500000, 0, NAN,
NAN), 9001);
else if (name == "(I) France Zone I")
_projection = Projection(gcs, 9802, Projection::Setup(49.5, 2.337229,
NAN, 600000, 1200000, 48.598523, 50.395912), 9001);
pcs = PCS(gcs, 9802, Projection::Setup(49.5, 2.337229, NAN, 600000,
1200000, 48.598523, 50.395912), 9001);
else if (name == "(II) France Zone II")
_projection = Projection(gcs, 9802, Projection::Setup(46.8, 2.337229,
NAN, 600000, 2200000, 45.898919, 47.696014), 9001);
pcs = PCS(gcs, 9802, Projection::Setup(46.8, 2.337229, NAN, 600000,
2200000, 45.898919, 47.696014), 9001);
else if (name == "(III) France Zone III")
_projection = Projection(gcs, 9802, Projection::Setup(44.1, 2.337229,
NAN, 600000, 3200000, 43.199291, 44.996094), 9001);
pcs = PCS(gcs, 9802, Projection::Setup(44.1, 2.337229, NAN, 600000,
3200000, 43.199291, 44.996094), 9001);
else if (name == "(IV) France Zone IV")
_projection = Projection(gcs, 9802, Projection::Setup(42.165, 2.337229,
NAN, 234.358, 4185861.369, 41.560388, 42.767663), 9001);
pcs = PCS(gcs, 9802, Projection::Setup(42.165, 2.337229, NAN, 234.358,
4185861.369, 41.560388, 42.767663), 9001);
else if (name == "(VICGRID) Victoria Australia")
_projection = Projection(gcs, 9802, Projection::Setup(-37, 145, NAN,
2500000, 4500000, -36, -38), 9001);
pcs = PCS(gcs, 9802, Projection::Setup(-37, 145, NAN, 2500000, 4500000,
-36, -38), 9001);
else if (name == "(VG94) VICGRID94 Victoria Australia")
_projection = Projection(gcs, 9802, Projection::Setup(-37, 145, NAN,
2500000, 2500000, -36, -38), 9001);
pcs = PCS(gcs, 9802, Projection::Setup(-37, 145, NAN, 2500000, 2500000,
-36, -38), 9001);
else if (name == "(SUI) Swiss Grid")
pcs = PCS(gcs, 9815, Projection::Setup(46.570866, 7.26225, 1.0, 600000,
200000, 90.0, 90.0), 9001);
else {
_errorString = QString("%1: Unknown map projection").arg(name);
return false;
}
_projection = Projection(&pcs);
return true;
}
@ -234,18 +244,16 @@ bool MapFile::computeTransformation(QList<CalibrationPoint> &points)
rp.append(points.at(i).rp);
}
Transform t(rp);
if (t.isNull()) {
_errorString = t.errorString();
_transform = Transform(rp);
if (!_transform.isValid()) {
_errorString = _transform.errorString();
return false;
}
_transform = t.transform();
return true;
}
bool MapFile::load(QIODevice &file)
MapFile::MapFile(QIODevice &file)
{
QList<CalibrationPoint> points;
QString ct, datum;
@ -253,13 +261,11 @@ bool MapFile::load(QIODevice &file)
const GCS *gcs;
if (!parseMapFile(file, points, ct, setup, datum))
return false;
return;
if (!(gcs = createGCS(datum)))
return false;
return;
if (!createProjection(gcs, ct, setup, points))
return false;
return;
if (!computeTransformation(points))
return false;
return true;
return;
}

View File

@ -1,20 +1,23 @@
#ifndef MAPFILE_H
#define MAPFILE_H
#include <QIODevice>
#include <QTransform>
#include "gcs.h"
#include "transform.h"
#include "projection.h"
class QIODevice;
class GCS;
class MapFile
{
public:
bool load(QIODevice &file);
MapFile(QIODevice &file);
bool isValid() const
{return !_image.isNull() && _projection.isValid() && _transform.isValid();}
const QString &errorString() const {return _errorString;}
const Projection &projection() const {return _projection;}
const QTransform &transform() const {return _transform;}
const Transform &transform() const {return _transform;}
const QString &name() const {return _name;}
const QString &image() const {return _image;}
@ -41,7 +44,7 @@ private:
QSize _size;
Projection _projection;
QTransform _transform;
Transform _transform;
QString _errorString;
};

View File

@ -1,6 +1,5 @@
#include <QFileInfo>
#include <QDir>
#include "common/range.h"
#include "atlas.h"
#include "offlinemap.h"
#include "onlinemap.h"
@ -13,7 +12,7 @@ bool MapList::loadSource(const QString &path, bool dir)
MapSource ms;
Map *map;
if (!ms.loadFile(path, &map)) {
if (!(map = ms.loadFile(path))) {
if (dir)
_errorString += path + ": " + ms.errorString() + "\n";
else

View File

@ -3,9 +3,8 @@
#include <QObject>
#include <QString>
#include "map.h"
class Tar;
class Map;
class MapList : public QObject
{

View File

@ -1,9 +1,10 @@
#include <QFile>
#include <QXmlStreamReader>
#include "onlinemap.h"
#include "wmtsmap.h"
#include "wmsmap.h"
#include "mapsource.h"
#define ZOOM_MAX 19
#define ZOOM_MIN 0
#define BOUNDS_LEFT -180
@ -11,6 +12,23 @@
#define BOUNDS_RIGHT 180
#define BOUNDS_BOTTOM -85.0511
MapSource::Config::Config() : type(OSM), zooms(ZOOM_MIN, ZOOM_MAX),
bounds(Coordinates(BOUNDS_LEFT, BOUNDS_TOP), Coordinates(BOUNDS_RIGHT,
BOUNDS_BOTTOM)), format("image/png"), rest(false) {}
static CoordinateSystem coordinateSystem(QXmlStreamReader &reader)
{
QXmlStreamAttributes attr = reader.attributes();
if (attr.value("axis") == "yx")
return CoordinateSystem::YX;
else if (attr.value("axis") == "xy")
return CoordinateSystem::XY;
else
return CoordinateSystem::Unknown;
}
Range MapSource::zooms(QXmlStreamReader &reader)
{
const QXmlStreamAttributes &attr = reader.attributes();
@ -18,11 +36,7 @@ Range MapSource::zooms(QXmlStreamReader &reader)
bool res;
if (attr.hasAttribute("min")) {
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
min = attr.value("min").toString().toInt(&res);
#else // QT_VERSION < 5
min = attr.value("min").toInt(&res);
#endif // QT_VERSION < 5
if (!res || (min < ZOOM_MIN || min > ZOOM_MAX)) {
reader.raiseError("Invalid minimal zoom level");
return Range();
@ -31,11 +45,7 @@ Range MapSource::zooms(QXmlStreamReader &reader)
min = ZOOM_MIN;
if (attr.hasAttribute("max")) {
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
max = attr.value("max").toString().toInt(&res);
#else // QT_VERSION < 5
max = attr.value("max").toInt(&res);
#endif // QT_VERSION < 5
if (!res || (max < ZOOM_MIN || max > ZOOM_MAX)) {
reader.raiseError("Invalid maximal zoom level");
return Range();
@ -43,7 +53,7 @@ Range MapSource::zooms(QXmlStreamReader &reader)
} else
max = ZOOM_MAX;
if (min > max || max < min) {
if (min > max) {
reader.raiseError("Invalid maximal/minimal zoom level combination");
return Range();
}
@ -58,11 +68,7 @@ RectC MapSource::bounds(QXmlStreamReader &reader)
bool res;
if (attr.hasAttribute("top")) {
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
top = attr.value("top").toString().toDouble(&res);
#else // QT_VERSION < 5
top = attr.value("top").toDouble(&res);
#endif // QT_VERSION < 5
if (!res || (top < BOUNDS_BOTTOM || top > BOUNDS_TOP)) {
reader.raiseError("Invalid bounds top value");
return RectC();
@ -71,11 +77,7 @@ RectC MapSource::bounds(QXmlStreamReader &reader)
top = BOUNDS_TOP;
if (attr.hasAttribute("bottom")) {
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
bottom = attr.value("bottom").toString().toDouble(&res);
#else // QT_VERSION < 5
bottom = attr.value("bottom").toDouble(&res);
#endif // QT_VERSION < 5
if (!res || (bottom < BOUNDS_BOTTOM || bottom > BOUNDS_TOP)) {
reader.raiseError("Invalid bounds bottom value");
return RectC();
@ -84,11 +86,7 @@ RectC MapSource::bounds(QXmlStreamReader &reader)
bottom = BOUNDS_BOTTOM;
if (attr.hasAttribute("left")) {
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
left = attr.value("left").toString().toDouble(&res);
#else // QT_VERSION < 5
left = attr.value("left").toDouble(&res);
#endif // QT_VERSION < 5
if (!res || (left < BOUNDS_LEFT || left > BOUNDS_RIGHT)) {
reader.raiseError("Invalid bounds left value");
return RectC();
@ -97,11 +95,7 @@ RectC MapSource::bounds(QXmlStreamReader &reader)
left = BOUNDS_LEFT;
if (attr.hasAttribute("right")) {
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
right = attr.value("right").toString().toDouble(&res);
#else // QT_VERSION < 5
right = attr.value("right").toDouble(&res);
#endif // QT_VERSION < 5
if (!res || (right < BOUNDS_LEFT || right > BOUNDS_RIGHT)) {
reader.raiseError("Invalid bounds right value");
return RectC();
@ -109,11 +103,11 @@ RectC MapSource::bounds(QXmlStreamReader &reader)
} else
right = BOUNDS_RIGHT;
if (bottom > top || top < bottom) {
if (bottom >= top) {
reader.raiseError("Invalid bottom/top bounds combination");
return RectC();
}
if (left > right || right < left) {
if (left >= right) {
reader.raiseError("Invalid left/right bounds combination");
return RectC();
}
@ -121,52 +115,128 @@ RectC MapSource::bounds(QXmlStreamReader &reader)
return RectC(Coordinates(left, top), Coordinates(right, bottom));
}
void MapSource::map(QXmlStreamReader &reader, Map **map)
void MapSource::map(QXmlStreamReader &reader, Config &config)
{
QString name, url;
Range z(ZOOM_MIN, ZOOM_MAX);
RectC b(Coordinates(BOUNDS_LEFT, BOUNDS_TOP),
Coordinates(BOUNDS_RIGHT, BOUNDS_BOTTOM));
const QXmlStreamAttributes &attr = reader.attributes();
config.type = (attr.value("type") == "WMTS") ? WMTS
: (attr.value("type") == "WMS") ? WMS : OSM;
while (reader.readNextStartElement()) {
if (reader.name() == "name")
name = reader.readElementText();
else if (reader.name() == "url")
url = reader.readElementText();
else if (reader.name() == "zoom") {
z = zooms(reader);
config.name = reader.readElementText();
else if (reader.name() == "url") {
config.rest = (reader.attributes().value("type") == "REST")
? true : false;
config.url = reader.readElementText();
} else if (reader.name() == "zoom") {
config.zooms = zooms(reader);
reader.skipCurrentElement();
} else if (reader.name() == "bounds") {
b = bounds(reader);
config.bounds = bounds(reader);
reader.skipCurrentElement();
} else if (reader.name() == "format")
config.format = reader.readElementText();
else if (reader.name() == "layer")
config.layer = reader.readElementText();
else if (reader.name() == "style")
config.style = reader.readElementText();
else if (reader.name() == "set") {
config.coordinateSystem = coordinateSystem(reader);
config.set = reader.readElementText();
} else if (reader.name() == "dimension") {
QXmlStreamAttributes attr = reader.attributes();
if (!attr.hasAttribute("id"))
reader.raiseError("Missing dimension id");
else
config.dimensions.append(QPair<QString, QString>(
attr.value("id").toString(), reader.readElementText()));
} else if (reader.name() == "crs") {
config.coordinateSystem = coordinateSystem(reader);
config.crs = reader.readElementText();
} else if (reader.name() == "authorization") {
QXmlStreamAttributes attr = reader.attributes();
config.authorization = Authorization(
attr.value("username").toString(),
attr.value("password").toString());
reader.skipCurrentElement();
} else
reader.skipCurrentElement();
}
*map = reader.error() ? 0 : new OnlineMap(name, url, z, b);
}
bool MapSource::loadFile(const QString &path, Map **map)
Map *MapSource::loadFile(const QString &path)
{
QFile file(path);
QXmlStreamReader reader;
Config config;
Map *m;
if (!file.open(QFile::ReadOnly | QFile::Text)) {
_errorString = file.errorString();
return false;
return 0;
}
reader.setDevice(&file);
if (reader.readNextStartElement()) {
if (reader.name() == "map")
MapSource::map(reader, map);
map(reader, config);
else
reader.raiseError("Not an online map source file");
}
if (reader.error()) {
_errorString = QString("%1: %2").arg(reader.lineNumber())
.arg(reader.errorString());
return 0;
}
_errorString = reader.error() ? QString("%1: %2").arg(reader.lineNumber())
.arg(reader.errorString()) : QString();
if (config.name.isEmpty()) {
_errorString = "Missing name definition";
return 0;
}
if (config.url.isEmpty()) {
_errorString = "Missing URL definition";
return 0;
}
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.type == WMTS) {
if (config.set.isEmpty()) {
_errorString = "Missing set definiton";
return 0;
}
}
if (config.type == WMS) {
if (config.crs.isEmpty()) {
_errorString = "Missing CRS definiton";
return 0;
}
}
return !reader.error();
if (config.type == WMTS)
m = new WMTSMap(config.name, WMTS::Setup(config.url, config.layer,
config.set, config.style, config.format, config.rest,
config.coordinateSystem, config.dimensions, config.authorization));
else if (config.type == WMS)
m = new WMSMap(config.name, WMS::Setup(config.url, config.layer,
config.style, config.format, config.crs, config.coordinateSystem,
config.dimensions, config.authorization));
else
m = new OnlineMap(config.name, config.url, config.zooms, config.bounds);
if (!m->isValid()) {
_errorString = m->errorString();
delete m;
return 0;
}
return m;
}

View File

@ -4,6 +4,8 @@
#include <QList>
#include "common/range.h"
#include "common/rectc.h"
#include "downloader.h"
#include "coordinatesystem.h"
class Map;
class QXmlStreamReader;
@ -11,13 +13,38 @@ class QXmlStreamReader;
class MapSource
{
public:
bool loadFile(const QString &path, Map **map);
Map *loadFile(const QString &path);
const QString &errorString() const {return _errorString;}
private:
enum Type {
OSM,
WMTS,
WMS
};
struct Config {
Type type;
QString name;
QString url;
Range zooms;
RectC bounds;
QString layer;
QString style;
QString set;
QString format;
QString crs;
CoordinateSystem coordinateSystem;
bool rest;
QList<QPair<QString, QString> > dimensions;
Authorization authorization;
Config();
};
RectC bounds(QXmlStreamReader &reader);
Range zooms(QXmlStreamReader &reader);
void map(QXmlStreamReader &reader, Map **map);
void map(QXmlStreamReader &reader, Config &config);
QString _errorString;
};

View File

@ -5,7 +5,8 @@
#include <cfloat>
#include <QDebug>
class Matrix {
class Matrix
{
public:
Matrix() {_h = 0; _w = 0; _m = 0;}
Matrix(size_t h, size_t w);

View File

@ -1,4 +1,3 @@
#include <QtGlobal>
#include <QPainter>
#include <QFileInfo>
#include <QMap>
@ -9,56 +8,49 @@
#include <QPixmapCache>
#include "common/coordinates.h"
#include "common/rectc.h"
#include "tar.h"
#include "ozf.h"
#include "mapfile.h"
#include "geotiff.h"
#include "offlinemap.h"
void OfflineMap::computeResolution()
bool OfflineMap::setImageInfo(const QString &path)
{
Coordinates tl = xy2ll((bounds().topLeft()));
Coordinates br = xy2ll(bounds().bottomRight());
qreal ds = tl.distanceTo(br);
qreal ps = QLineF(bounds().topLeft(), bounds().bottomRight()).length();
_resolution = ds/ps;
}
bool OfflineMap::getImageInfo(const QString &path)
{
QFileInfo ii(_imgPath);
QFileInfo ii(_map.path);
if (ii.isRelative())
ii.setFile(path + "/" + _imgPath);
ii.setFile(path + "/" + _map.path);
if (!ii.exists()) {
int last = _imgPath.lastIndexOf('\\');
if (last >= 0 && last < _imgPath.length() - 1) {
QStringRef fn(&_imgPath, last + 1, _imgPath.length() - last - 1);
int last = _map.path.lastIndexOf('\\');
if (last >= 0 && last < _map.path.length() - 1) {
QStringRef fn(&_map.path, last + 1, _map.path.length() - last - 1);
ii.setFile(path + "/" + fn.toString());
}
}
if (ii.exists())
_imgPath = ii.absoluteFilePath();
_map.path = ii.absoluteFilePath();
else {
_errorString = QString("%1: No such image file").arg(_imgPath);
_errorString = QString("%1: No such image file").arg(_map.path);
return false;
}
if (OZF::isOZF(_imgPath)) {
if (!_ozf.load(_imgPath)) {
if (OZF::isOZF(_map.path)) {
_ozf = new OZF(_map.path);
if (!_ozf->open()) {
_errorString = QString("%1: Error loading OZF file")
.arg(QFileInfo(_imgPath).fileName());
.arg(_ozf->fileName());
return false;
}
_scale = _ozf->scale(_zoom);
} else {
QImageReader img(_imgPath);
_size = img.size();
if (!_size.isValid()) {
QImageReader img(_map.path);
_map.size = img.size();
if (!_map.size.isValid()) {
_errorString = QString("%1: Error reading map image")
.arg(QFileInfo(_imgPath).fileName());
.arg(QFileInfo(_map.path).fileName());
return false;
}
}
@ -66,27 +58,33 @@ bool OfflineMap::getImageInfo(const QString &path)
return true;
}
bool OfflineMap::getTileInfo(const QStringList &tiles, const QString &path)
bool OfflineMap::setTileInfo(const QStringList &tiles, const QString &path)
{
if (!_map.size.isValid()) {
_errorString = "Missing total image size (IWH)";
return false;
}
QRegExp rx("_[0-9]+_[0-9]+\\.");
for (int i = 0; i < tiles.size(); i++) {
if (tiles.at(i).contains(rx)) {
_tileName = QString(tiles.at(i)).replace(rx, "_%1_%2.");
_tile.path = QString(tiles.at(i)).replace(rx, "_%1_%2.");
if (path.isNull()) {
QByteArray ba = _tar.file(tiles.at(i));
if (_tar) {
QByteArray ba = _tar->file(tiles.at(i));
QBuffer buffer(&ba);
_tileSize = QImageReader(&buffer).size();
_tile.size = QImageReader(&buffer).size();
} else {
_tileName = path + "/" + _tileName;
_tileSize = QImageReader(path + "/" + tiles.at(i)).size();
_tile.path = path + "/" + _tile.path;
_tile.size = QImageReader(path + "/" + tiles.at(i)).size();
}
if (!_tileSize.isValid()) {
if (!_tile.size.isValid()) {
_errorString = QString("Error retrieving tile size: "
"%1: Invalid image").arg(QFileInfo(tiles.at(i)).fileName());
return false;
}
_map.path = QString();
return true;
}
}
@ -95,72 +93,59 @@ bool OfflineMap::getTileInfo(const QStringList &tiles, const QString &path)
return false;
}
bool OfflineMap::totalSizeSet()
{
if (!_size.isValid()) {
_errorString = "Missing total image size (IWH)";
return false;
} else
return true;
}
OfflineMap::OfflineMap(const QString &fileName, QObject *parent)
: Map(parent)
: Map(parent), _img(0), _tar(0), _ozf(0), _zoom(0), _valid(false)
{
QFileInfo fi(fileName);
QString suffix = fi.suffix().toLower();
_valid = false;
_img = 0;
_resolution = 0.0;
_zoom = 0;
_scale = QPointF(1.0, 1.0);
if (suffix == "tar") {
if (!_tar.load(fileName)) {
_tar = new Tar(fileName);
if (!_tar->open()) {
_errorString = "Error reading tar file";
return;
}
QString mapFileName = fi.completeBaseName() + ".map";
QByteArray ba = _tar.file(mapFileName);
QByteArray ba = _tar->file(mapFileName);
if (ba.isNull()) {
_errorString = "Map file not found";
return;
}
QBuffer mapFile(&ba);
MapFile mf;
if (!mf.load(mapFile)) {
QBuffer buffer(&ba);
MapFile mf(buffer);
if (!mf.isValid()) {
_errorString = mf.errorString();
return;
} else {
_name = mf.name();
_size = mf.size();
_imgPath = mf.image();
_map.size = mf.size();
_map.path = mf.image();
_projection = mf.projection();
_transform = mf.transform();
}
} else if (suffix == "map") {
MapFile mf;
QFile mapFile(fileName);
if (!mf.load(mapFile)) {
QFile file(fileName);
MapFile mf(file);
if (!mf.isValid()) {
_errorString = mf.errorString();
return;
} else {
_name = mf.name();
_size = mf.size();
_imgPath = mf.image();
_map.size = mf.size();
_map.path = mf.image();
_projection = mf.projection();
_transform = mf.transform();
}
} else if (suffix == "tif" || suffix == "tiff") {
GeoTIFF gt;
if (!gt.load(fileName)) {
GeoTIFF gt(fileName);
if (!gt.isValid()) {
_errorString = gt.errorString();
return;
} else {
_name = fi.fileName();
_imgPath = fileName;
_map.path = fileName;
_projection = gt.projection();
_transform = gt.transform();
}
@ -169,93 +154,78 @@ OfflineMap::OfflineMap(const QString &fileName, QObject *parent)
return;
}
if (_tar.isOpen()) {
if (!totalSizeSet())
if (_tar) {
if (!setTileInfo(_tar->files()))
return;
if (!getTileInfo(_tar.files()))
return;
_imgPath = QString();
} else {
QDir set(fi.absolutePath() + "/" + "set");
if (set.exists()) {
if (!totalSizeSet())
if (!setTileInfo(set.entryList(), set.absolutePath()))
return;
if (!getTileInfo(set.entryList(), set.absolutePath()))
return;
_imgPath = QString();
} else {
if (!getImageInfo(fi.absolutePath()))
if (!setImageInfo(fi.absolutePath()))
return;
}
}
_inverted = _transform.inverted();
computeResolution();
_valid = true;
}
OfflineMap::OfflineMap(const QString &fileName, Tar &tar, QObject *parent)
: Map(parent)
: Map(parent), _img(0), _tar(0), _ozf(0), _zoom(0), _valid(false)
{
QFileInfo fi(fileName);
MapFile mf;
_valid = false;
_img = 0;
_resolution = 0.0;
_zoom = 0;
_scale = QPointF(1.0, 1.0);
QFileInfo map(fi.absolutePath());
QFileInfo layer(map.absolutePath());
QString mapFile = layer.fileName() + "/" + map.fileName() + "/"
+ fi.fileName();
QByteArray ba = tar.file(mapFile);
if (ba.isNull()) {
_errorString = "Map file not found";
return;
}
QBuffer buffer(&ba);
if (!mf.load(buffer)) {
MapFile mf(buffer);
if (!mf.isValid()) {
_errorString = mf.errorString();
return;
}
_name = mf.name();
_size = mf.size();
_map.size = mf.size();
_projection = mf.projection();
_transform = mf.transform();
_tar = new Tar(fi.absolutePath() + "/" + fi.completeBaseName() + ".tar");
_inverted = _transform.inverted();
computeResolution();
_tarPath = fi.absolutePath() + "/" + fi.completeBaseName() + ".tar";
_valid = true;
}
OfflineMap::~OfflineMap()
{
delete _img;
delete _tar;
delete _ozf;
}
void OfflineMap::load()
{
if (!_tarPath.isNull() && !_tileSize.isValid()) {
if (!_tar.load(_tarPath)) {
qWarning("%s: error loading tar file", qPrintable(_tarPath));
if (_tar && !_tar->isOpen()) {
if (!_tar->open()) {
qWarning("%s: error loading tar file",
qPrintable(_tar->fileName()));
return;
}
if (!getTileInfo(_tar.files()))
qWarning("%s: %s", qPrintable(_tarPath), qPrintable(_errorString));
if (!setTileInfo(_tar->files()))
qWarning("%s: %s", qPrintable(_tar->fileName()),
qPrintable(_errorString));
return;
}
if (!_img && !_imgPath.isNull() && !_ozf.isOpen()) {
_img = new QImage(_imgPath);
if (!_ozf && !_img && _map.isValid()) {
_img = new QImage(_map.path);
if (_img->isNull())
qWarning("%s: error loading map image", qPrintable(_imgPath));
qWarning("%s: error loading map image", qPrintable(_map.path));
}
}
@ -265,26 +235,26 @@ void OfflineMap::unload()
_img = 0;
}
void OfflineMap::drawTiled(QPainter *painter, const QRectF &rect)
void OfflineMap::drawTiled(QPainter *painter, const QRectF &rect) const
{
QPoint tl = QPoint((int)floor(rect.left() / (qreal)_tileSize.width())
* _tileSize.width(), (int)floor(rect.top() / _tileSize.height())
* _tileSize.height());
QPoint tl = QPoint((int)floor(rect.left() / (qreal)_tile.size.width())
* _tile.size.width(), (int)floor(rect.top() / _tile.size.height())
* _tile.size.height());
QSizeF s(rect.right() - tl.x(), rect.bottom() - tl.y());
for (int i = 0; i < ceil(s.width() / _tileSize.width()); i++) {
for (int j = 0; j < ceil(s.height() / _tileSize.height()); j++) {
int x = tl.x() + i * _tileSize.width();
int y = tl.y() + j * _tileSize.height();
for (int i = 0; i < ceil(s.width() / _tile.size.width()); i++) {
for (int j = 0; j < ceil(s.height() / _tile.size.height()); j++) {
int x = tl.x() + i * _tile.size.width();
int y = tl.y() + j * _tile.size.height();
QString tileName(_tileName.arg(QString::number(x),
QString tileName(_tile.path.arg(QString::number(x),
QString::number(y)));
QPixmap pixmap;
if (_tar.isOpen()) {
QString key = _tar.fileName() + "/" + tileName;
if (_tar) {
QString key = _tar->fileName() + "/" + tileName;
if (!QPixmapCache::find(key, &pixmap)) {
QByteArray ba = _tar.file(tileName);
QByteArray ba = _tar->file(tileName);
pixmap = QPixmap::fromImage(QImage::fromData(ba));
if (!pixmap.isNull())
QPixmapCache::insert(key, pixmap);
@ -294,8 +264,8 @@ void OfflineMap::drawTiled(QPainter *painter, const QRectF &rect)
if (pixmap.isNull()) {
qWarning("%s: error loading tile image", qPrintable(
_tileName.arg(QString::number(x), QString::number(y))));
painter->fillRect(QRectF(QPoint(x, y), _tileSize),
_tile.path.arg(QString::number(x), QString::number(y))));
painter->fillRect(QRectF(QPoint(x, y), _tile.size),
_backgroundColor);
} else
painter->drawPixmap(QPoint(x, y), pixmap);
@ -303,30 +273,30 @@ void OfflineMap::drawTiled(QPainter *painter, const QRectF &rect)
}
}
void OfflineMap::drawOZF(QPainter *painter, const QRectF &rect)
void OfflineMap::drawOZF(QPainter *painter, const QRectF &rect) const
{
QPoint tl = QPoint((int)floor(rect.left() / _ozf.tileSize().width())
* _ozf.tileSize().width(), (int)floor(rect.top()
/ _ozf.tileSize().height()) * _ozf.tileSize().height());
QPoint tl = QPoint((int)floor(rect.left() / _ozf->tileSize().width())
* _ozf->tileSize().width(), (int)floor(rect.top()
/ _ozf->tileSize().height()) * _ozf->tileSize().height());
QSizeF s(rect.right() - tl.x(), rect.bottom() - tl.y());
for (int i = 0; i < ceil(s.width() / _ozf.tileSize().width()); i++) {
for (int j = 0; j < ceil(s.height() / _ozf.tileSize().height()); j++) {
int x = tl.x() + i * _ozf.tileSize().width();
int y = tl.y() + j * _ozf.tileSize().height();
for (int i = 0; i < ceil(s.width() / _ozf->tileSize().width()); i++) {
for (int j = 0; j < ceil(s.height() / _ozf->tileSize().height()); j++) {
int x = tl.x() + i * _ozf->tileSize().width();
int y = tl.y() + j * _ozf->tileSize().height();
QPixmap pixmap;
QString key = _ozf.fileName() + "/" + QString::number(_zoom) + "_"
QString key = _ozf->fileName() + "/" + QString::number(_zoom) + "_"
+ QString::number(x) + "_" + QString::number(y);
if (!QPixmapCache::find(key, &pixmap)) {
pixmap = _ozf.tile(_zoom, x, y);
pixmap = _ozf->tile(_zoom, x, y);
if (!pixmap.isNull())
QPixmapCache::insert(key, pixmap);
}
if (pixmap.isNull()) {
qWarning("%s: error loading tile image", qPrintable(key));
painter->fillRect(QRectF(QPoint(x, y), _ozf.tileSize()),
painter->fillRect(QRectF(QPoint(x, y), _ozf->tileSize()),
_backgroundColor);
} else
painter->drawPixmap(QPoint(x, y), pixmap);
@ -334,7 +304,7 @@ void OfflineMap::drawOZF(QPainter *painter, const QRectF &rect)
}
}
void OfflineMap::drawImage(QPainter *painter, const QRectF &rect)
void OfflineMap::drawImage(QPainter *painter, const QRectF &rect) const
{
QRect r(rect.toRect());
painter->drawImage(r.left(), r.top(), *_img, r.left(), r.top(),
@ -343,9 +313,9 @@ void OfflineMap::drawImage(QPainter *painter, const QRectF &rect)
void OfflineMap::draw(QPainter *painter, const QRectF &rect)
{
if (_ozf.isOpen())
if (_ozf)
drawOZF(painter, rect);
else if (_tileSize.isValid())
else if (_tile.isValid())
drawTiled(painter, rect);
else if (_img && !_img->isNull())
drawImage(painter, rect);
@ -353,73 +323,54 @@ void OfflineMap::draw(QPainter *painter, const QRectF &rect)
painter->fillRect(rect, _backgroundColor);
}
QPointF OfflineMap::ll2xy(const Coordinates &c)
QPointF OfflineMap::ll2xy(const Coordinates &c) const
{
if (_ozf.isOpen()) {
QPointF p(_transform.map(_projection.ll2xy(c)));
return QPointF(p.x() * _scale.x(), p.y() * _scale.y());
} else
return _transform.map(_projection.ll2xy(c));
QPointF p(_transform.proj2img(_projection.ll2xy(c)));
return _ozf ? QPointF(p.x() * _scale.x(), p.y() * _scale.y()) : p;
}
Coordinates OfflineMap::xy2ll(const QPointF &p)
Coordinates OfflineMap::xy2ll(const QPointF &p) const
{
if (_ozf.isOpen()) {
return _projection.xy2ll(_inverted.map(QPointF(p.x() / _scale.x(),
p.y() / _scale.y())));
} else
return _projection.xy2ll(_inverted.map(p));
return _ozf
? _projection.xy2ll(_transform.img2proj(QPointF(p.x() / _scale.x(),
p.y() / _scale.y())))
: _projection.xy2ll(_transform.img2proj(p));
}
QRectF OfflineMap::bounds() const
{
if (_ozf.isOpen())
return QRectF(QPointF(0, 0), _ozf.size(_zoom));
else
return QRectF(QPointF(0, 0), _size);
return _ozf
? QRectF(QPointF(0, 0), _ozf->size(_zoom))
: QRectF(QPointF(0, 0), _map.size);
}
qreal OfflineMap::resolution(const QPointF &p) const
qreal OfflineMap::resolution(const QRectF &rect) const
{
Q_UNUSED(p);
Coordinates tl = xy2ll((rect.topLeft()));
Coordinates br = xy2ll(rect.bottomRight());
if (_ozf.isOpen())
return _resolution / ((_scale.x() + _scale.y()) / 2.0);
else
return _resolution;
qreal ds = tl.distanceTo(br);
qreal ps = QLineF(rect.topLeft(), rect.bottomRight()).length();
return ds/ps;
}
qreal OfflineMap::zoomFit(const QSize &size, const RectC &br)
int OfflineMap::zoomFit(const QSize &size, const RectC &rect)
{
if (_ozf.isOpen()) {
if (!br.isValid())
rescale(0);
else {
QRect sbr(QRectF(_transform.map(_projection.ll2xy(br.topLeft())),
_transform.map(_projection.ll2xy(br.bottomRight())))
.toRect().normalized());
if (!_ozf)
return _zoom;
for (int i = 0; i < _ozf.zooms(); i++) {
rescale(i);
if (sbr.size().width() * _scale.x() <= size.width()
&& sbr.size().height() * _scale.y() <= size.height())
break;
}
}
}
if (!rect.isValid())
rescale(0);
else {
QPointF tl(_transform.proj2img(_projection.ll2xy(rect.topLeft())));
QPointF br(_transform.proj2img(_projection.ll2xy(rect.bottomRight())));
QRect sbr(QRectF(tl, br).toRect().normalized());
return _zoom;
}
qreal OfflineMap::zoomFit(qreal resolution, const Coordinates &c)
{
Q_UNUSED(c);
if (_ozf.isOpen()) {
for (int i = 0; i < _ozf.zooms(); i++) {
for (int i = 0; i < _ozf->zooms(); i++) {
rescale(i);
qreal sr = _resolution / ((_scale.x() + _scale.y()) / 2.0);
if (sr >= resolution)
if (sbr.size().width() * _scale.x() <= size.width()
&& sbr.size().height() * _scale.y() <= size.height())
break;
}
}
@ -427,18 +378,18 @@ qreal OfflineMap::zoomFit(qreal resolution, const Coordinates &c)
return _zoom;
}
qreal OfflineMap::zoomIn()
int OfflineMap::zoomIn()
{
if (_ozf.isOpen())
if (_ozf)
rescale(qMax(_zoom - 1, 0));
return _zoom;
}
qreal OfflineMap::zoomOut()
int OfflineMap::zoomOut()
{
if (_ozf.isOpen())
rescale(qMin(_zoom + 1, _ozf.zooms() - 1));
if (_ozf)
rescale(qMin(_zoom + 1, _ozf->zooms() - 1));
return _zoom;
}
@ -446,7 +397,5 @@ qreal OfflineMap::zoomOut()
void OfflineMap::rescale(int zoom)
{
_zoom = zoom;
_scale = QPointF(
(qreal)_ozf.size(_zoom).width() / (qreal)_ozf.size(0).width(),
(qreal)_ozf.size(_zoom).height() / (qreal)_ozf.size(0).height());
_scale = _ozf->scale(zoom);
}

View File

@ -1,15 +1,12 @@
#ifndef OFFLINEMAP_H
#define OFFLINEMAP_H
#include <QTransform>
#include "projection.h"
#include "transform.h"
#include "linearunits.h"
#include "projection.h"
#include "map.h"
#include "tar.h"
#include "ozf.h"
class QIODevice;
class Tar;
class OZF;
class QImage;
class OfflineMap : public Map
@ -24,16 +21,17 @@ public:
const QString &name() const {return _name;}
QRectF bounds() const;
qreal resolution(const QPointF &p) const;
qreal resolution(const QRectF &rect) const;
qreal zoom() const {return _zoom;}
qreal zoomFit(const QSize &size, const RectC &br);
qreal zoomFit(qreal resolution, const Coordinates &c);
qreal zoomIn();
qreal zoomOut();
int zoom() const {return _zoom;}
int zoomFit(const QSize &size, const RectC &rect);
int zoomIn();
int zoomOut();
QPointF ll2xy(const Coordinates &c);
Coordinates xy2ll(const QPointF &p);
QPointF ll2xy(const Coordinates &c)
{return static_cast<const OfflineMap &>(*this).ll2xy(c);}
Coordinates xy2ll(const QPointF &p)
{return static_cast<const OfflineMap &>(*this).xy2ll(p);}
void draw(QPainter *painter, const QRectF &rect);
@ -41,43 +39,43 @@ public:
void unload();
bool isValid() const {return _valid;}
const QString &errorString() const {return _errorString;}
QString errorString() const {return _errorString;}
QPointF ll2pp(const Coordinates &c) const
{return _projection.ll2xy(c);}
QPointF xy2pp(const QPointF &p) const
{return _inverted.map(p);}
{return _transform.img2proj(p);}
QPointF pp2xy(const QPointF &p) const
{return _transform.map(p);}
{return _transform.proj2img(p);}
private:
bool getTileInfo(const QStringList &tiles, const QString &path = QString());
bool getImageInfo(const QString &path);
bool totalSizeSet();
struct ImageInfo {
QSize size;
QString path;
void drawTiled(QPainter *painter, const QRectF &rect);
void drawOZF(QPainter *painter, const QRectF &rect);
void drawImage(QPainter *painter, const QRectF &rect);
bool isValid() const {return size.isValid() && !path.isEmpty();}
};
QPointF ll2xy(const Coordinates &c) const;
Coordinates xy2ll(const QPointF &p) const;
bool setTileInfo(const QStringList &tiles, const QString &path = QString());
bool setImageInfo(const QString &path);
void drawTiled(QPainter *painter, const QRectF &rect) const;
void drawOZF(QPainter *painter, const QRectF &rect) const;
void drawImage(QPainter *painter, const QRectF &rect) const;
void computeResolution();
void rescale(int zoom);
QString _name;
Projection _projection;
QTransform _transform, _inverted;
OZF _ozf;
Tar _tar;
QString _tarPath;
Transform _transform;
QImage *_img;
QString _imgPath;
QSize _tileSize;
QString _tileName;
QSize _size;
Tar *_tar;
OZF *_ozf;
ImageInfo _map, _tile;
int _zoom;
qreal _resolution;
QPointF _scale;
bool _valid;

View File

@ -1,5 +1,3 @@
#include <QFileInfo>
#include <QDir>
#include <QPainter>
#include "common/coordinates.h"
#include "common/rectc.h"
@ -41,45 +39,35 @@ static int scale2zoom(qreal scale)
return (int)log2(360.0/(scale * (qreal)TILE_SIZE));
}
static bool loadTileFile(Tile &tile, const QString &file)
{
if (!tile.pixmap().load(file)) {
qWarning("%s: error loading tile file\n", qPrintable(file));
return false;
}
return true;
}
Downloader *OnlineMap::downloader;
OnlineMap::OnlineMap(const QString &name, const QString &url,
const Range &zooms, const RectC &bounds, QObject *parent)
: Map(parent), _name(name), _url(url), _zooms(zooms), _bounds(bounds)
const Range &zooms, const RectC &bounds, QObject *parent) :
Map(parent), _name(name), _zooms(zooms), _bounds(bounds),
_block(false), _valid(false)
{
_block = false;
_zoom = _zooms.max();
QString dir(TILES_DIR + "/" + _name);
QString path = TILES_DIR + QString("/") + name;
if (!QDir().mkpath(path))
qWarning("Error creating tiles dir: %s\n", qPrintable(path));
_zoom = _zooms.max();
_tileLoader = TileLoader(url, dir);
if (!QDir().mkpath(dir)) {
_errorString = "Error creating tiles dir";
return;
}
_valid = true;
}
void OnlineMap::load()
{
connect(downloader, SIGNAL(finished()), this, SLOT(emitLoaded()));
connect(TileLoader::downloader(), SIGNAL(finished()), this,
SLOT(emitLoaded()));
}
void OnlineMap::unload()
{
disconnect(downloader, SIGNAL(finished()), this, SLOT(emitLoaded()));
}
void OnlineMap::fillTile(Tile &tile)
{
tile.pixmap() = QPixmap(TILE_SIZE, TILE_SIZE);
tile.pixmap().fill(_backgroundColor);
disconnect(TileLoader::downloader(), SIGNAL(finished()), this,
SLOT(emitLoaded()));
}
void OnlineMap::emitLoaded()
@ -87,91 +75,6 @@ void OnlineMap::emitLoaded()
emit loaded();
}
void OnlineMap::loadTilesAsync(QList<Tile> &list)
{
QList<Download> dl;
for (int i = 0; i < list.size(); i++) {
Tile &t = list[i];
QString file = tileFile(t);
QFileInfo fi(file);
if (!fi.exists()) {
fillTile(t);
dl.append(Download(tileUrl(t), file));
} else
loadTileFile(t, file);
}
if (!dl.empty())
downloader->get(dl);
}
void OnlineMap::loadTilesSync(QList<Tile> &list)
{
QList<Download> dl;
for (int i = 0; i < list.size(); i++) {
Tile &t = list[i];
QString file = tileFile(t);
QFileInfo fi(file);
if (!fi.exists())
dl.append(Download(tileUrl(t), file));
else
loadTileFile(t, file);
}
if (dl.empty())
return;
QEventLoop wait;
connect(downloader, SIGNAL(finished()), &wait, SLOT(quit()));
if (downloader->get(dl))
wait.exec();
for (int i = 0; i < list.size(); i++) {
Tile &t = list[i];
if (t.pixmap().isNull()) {
QString file = tileFile(t);
QFileInfo fi(file);
if (!(fi.exists() && loadTileFile(t, file)))
fillTile(t);
}
}
}
QString OnlineMap::tileUrl(const Tile &tile) const
{
QString url(_url);
url.replace("$z", QString::number(tile.zoom()));
url.replace("$x", QString::number(tile.xy().x()));
url.replace("$y", QString::number(tile.xy().y()));
return url;
}
QString OnlineMap::tileFile(const Tile &tile) const
{
QString file = TILES_DIR + QString("/%1/%2-%3-%4").arg(name())
.arg(tile.zoom()).arg(tile.xy().x()).arg(tile.xy().y());
return file;
}
void OnlineMap::clearCache()
{
QString path = TILES_DIR + QString("/") + name();
QDir dir = QDir(path);
QStringList list = dir.entryList();
for (int i = 0; i < list.count(); i++)
dir.remove(list.at(i));
}
QRectF OnlineMap::bounds() const
{
return QRectF(ll2xy(_bounds.topLeft()), ll2xy(_bounds.bottomRight()));
@ -187,7 +90,7 @@ int OnlineMap::limitZoom(int zoom) const
return zoom;
}
qreal OnlineMap::zoomFit(const QSize &size, const RectC &br)
int OnlineMap::zoomFit(const QSize &size, const RectC &br)
{
if (!br.isValid())
_zoom = _zooms.max();
@ -201,29 +104,21 @@ qreal OnlineMap::zoomFit(const QSize &size, const RectC &br)
return _zoom;
}
qreal OnlineMap::zoomFit(qreal resolution, const Coordinates &c)
{
_zoom = limitZoom((int)log2((WGS84_RADIUS * 2.0 * M_PI
* cos(deg2rad(c.lat()))) / (resolution * TILE_SIZE)));
return _zoom;
}
qreal OnlineMap::resolution(const QPointF &p) const
qreal OnlineMap::resolution(const QRectF &rect) const
{
qreal scale = zoom2scale(_zoom);
return (WGS84_RADIUS * 2.0 * M_PI * scale / 360.0
* cos(2.0 * atan(exp(deg2rad(-p.y() * scale))) - M_PI/2));
* cos(2.0 * atan(exp(deg2rad(-rect.center().y() * scale))) - M_PI/2));
}
qreal OnlineMap::zoomIn()
int OnlineMap::zoomIn()
{
_zoom = qMin(_zoom + 1, _zooms.max());
return _zoom;
}
qreal OnlineMap::zoomOut()
int OnlineMap::zoomOut()
{
_zoom = qMax(_zoom - 1, _zooms.min());
return _zoom;
@ -245,15 +140,19 @@ void OnlineMap::draw(QPainter *painter, const QRectF &rect)
tiles.append(Tile(QPoint(tile.x() + i, tile.y() + j), _zoom));
if (_block)
loadTilesSync(tiles);
_tileLoader.loadTilesSync(tiles);
else
loadTilesAsync(tiles);
_tileLoader.loadTilesAsync(tiles);
for (int i = 0; i < tiles.count(); i++) {
Tile &t = tiles[i];
QPoint tp(tl.x() + (t.xy().x() - tile.x()) * TILE_SIZE,
tl.y() + (t.xy().y() - tile.y()) * TILE_SIZE);
painter->drawPixmap(tp, t.pixmap());
if (t.pixmap().isNull())
painter->fillRect(QRect(tp, QSize(TILE_SIZE, TILE_SIZE)),
_backgroundColor);
else
painter->drawPixmap(tp, t.pixmap());
}
}

View File

@ -1,13 +1,10 @@
#ifndef ONLINEMAP_H
#define ONLINEMAP_H
#include "common/coordinates.h"
#include "common/range.h"
#include "common/rectc.h"
#include "map.h"
#include "tile.h"
class Downloader;
#include "tileloader.h"
class OnlineMap : public Map
{
@ -20,13 +17,12 @@ public:
const QString &name() const {return _name;}
QRectF bounds() const;
qreal resolution(const QPointF &p) const;
qreal resolution(const QRectF &rect) const;
qreal zoom() const {return _zoom;}
qreal zoomFit(const QSize &size, const RectC &br);
qreal zoomFit(qreal resolution, const Coordinates &c);
qreal zoomIn();
qreal zoomOut();
int zoom() const {return _zoom;}
int zoomFit(const QSize &size, const RectC &br);
int zoomIn();
int zoomOut();
QPointF ll2xy(const Coordinates &c)
{return static_cast<const OnlineMap &>(*this).ll2xy(c);}
@ -36,36 +32,31 @@ public:
void draw(QPainter *painter, const QRectF &rect);
void setBlockingMode(bool block) {_block = block;}
void clearCache();
static void setDownloader(Downloader *downloader)
{OnlineMap::downloader = downloader;}
void clearCache() {_tileLoader.clearCache();}
void load();
void unload();
bool isValid() const {return _valid;}
QString errorString() const {return _errorString;}
private slots:
void emitLoaded();
private:
QPointF ll2xy(const Coordinates &c) const;
Coordinates xy2ll(const QPointF &p) const;
void fillTile(Tile &tile);
QString tileUrl(const Tile &tile) const;
QString tileFile(const Tile &tile) const;
void loadTilesAsync(QList<Tile> &list);
void loadTilesSync(QList<Tile> &list);
int limitZoom(int zoom) const;
TileLoader _tileLoader;
QString _name;
QString _url;
Range _zooms;
RectC _bounds;
int _zoom;
bool _block;
static Downloader *downloader;
bool _valid;
QString _errorString;
};
#endif // ONLINEMAP_H

View File

@ -185,12 +185,8 @@ bool OZF::readTileTable()
return _zooms.isEmpty() ? false : true;
}
bool OZF::load(const QString &path)
bool OZF::open()
{
if (_file.isOpen())
_file.close();
_file.setFileName(path);
if (!_file.open(QIODevice::ReadOnly))
return false;
@ -227,7 +223,7 @@ QPixmap OZF::tile(int zoom, int x, int y)
quint32 bes = qToBigEndian(tileSize().width() * tileSize().height());
QByteArray ba;
ba.resize(sizeof(bes) + size);
*(ba.data()) = bes;
memcpy(ba.data(), &bes, sizeof(bes));
if (!read(ba.data() + sizeof(bes), size, 16))
return QPixmap();
@ -250,6 +246,12 @@ QSize OZF::size(int zoom) const
return _zooms.at(zoom).size;
}
QPointF OZF::scale(int zoom) const
{
return QPointF((qreal)size(zoom).width() / (qreal)size(0).width(),
(qreal)size(zoom).height() / (qreal)size(0).height());
}
bool OZF::isOZF(const QString &path)
{
QFile file(path);

View File

@ -12,15 +12,17 @@
class OZF
{
public:
OZF() : _tileSize(0), _decrypt(false), _key(0) {}
OZF(const QString &name) : _tileSize(0), _decrypt(false), _key(0),
_file(name) {}
bool load(const QString &path);
bool open();
QString fileName() const {return _file.fileName();}
bool isOpen() const {return _file.isOpen();}
int zooms() const {return _zooms.size();}
QSize size(int zoom) const;
QPointF scale(int zoom) const;
QSize tileSize() const {return QSize(_tileSize, _tileSize);}
QPixmap tile(int zoom, int x, int y);

View File

@ -22,6 +22,7 @@ static bool parameter(int key, double val, int units, Projection::Setup &setup)
{
switch (key) {
case 8801:
case 8811:
case 8821:
{AngularUnits au(units);
if (au.isNull())
@ -29,6 +30,7 @@ static bool parameter(int key, double val, int units, Projection::Setup &setup)
setup.setLatitudeOrigin(au.toDegrees(val));}
return true;
case 8802:
case 8812:
case 8822:
{AngularUnits au(units);
if (au.isNull())
@ -36,9 +38,11 @@ static bool parameter(int key, double val, int units, Projection::Setup &setup)
setup.setLongitudeOrigin(au.toDegrees(val));}
return true;
case 8805:
case 8815:
setup.setScale(val);
return true;
case 8806:
case 8816:
case 8826:
{LinearUnits lu(units);
if (lu.isNull())
@ -46,18 +50,21 @@ static bool parameter(int key, double val, int units, Projection::Setup &setup)
setup.setFalseEasting(lu.toMeters(val));}
return true;
case 8807:
case 8817:
case 8827:
{LinearUnits lu(units);
if (lu.isNull())
return false;
setup.setFalseNorthing(lu.toMeters(val));}
return true;
case 8813:
case 8823:
{AngularUnits au(units);
if (au.isNull())
return false;
setup.setStandardParallel1(au.toDegrees(val));}
return true;
case 8814:
case 8824:
{AngularUnits au(units);
if (au.isNull())
@ -74,7 +81,7 @@ static int projectionSetup(const QList<QByteArray> &list,
{
bool r1, r2, r3;
for (int i = 6; i < 24; i += 3) {
for (int i = 7; i < 28; i += 3) {
QString ks = list[i].trimmed();
if (ks.isEmpty())
break;
@ -83,10 +90,10 @@ static int projectionSetup(const QList<QByteArray> &list,
double val = list[i+1].trimmed().toDouble(&r2);
int un = list[i+2].trimmed().toInt(&r3);
if (!r1 || !r2 || !r3)
return (i - 6)/3 + 1;
return (i - 7)/3 + 1;
if (!parameter(key, val, un, setup))
return (i - 6)/3 + 1;
return (i - 7)/3 + 1;
}
return 0;
@ -129,49 +136,60 @@ void PCS::loadList(const QString &path)
QByteArray line = file.readLine();
QList<QByteArray> list = line.split(',');
if (list.size() != 24) {
qWarning("%s: %d: Format error", qPrintable(path), ln);
if (list.size() != 28) {
qWarning("%s:%d: Format error", qPrintable(path), ln);
continue;
}
int id = list[1].trimmed().toInt(&res);
if (!res) {
qWarning("%s: %d: Invalid PCS code", qPrintable(path), ln);
qWarning("%s:%d: Invalid PCS code", qPrintable(path), ln);
continue;
}
int gcsid = list[2].trimmed().toInt(&res);
if (!res) {
qWarning("%s: %d: Invalid GCS code", qPrintable(path), ln);
qWarning("%s:%d: Invalid GCS code", qPrintable(path), ln);
continue;
}
int proj = list[3].trimmed().toInt(&res);
if (!res) {
qWarning("%s: %d: Invalid projection code", qPrintable(path), ln);
qWarning("%s:%d: Invalid projection code", qPrintable(path), ln);
continue;
}
int units = list[4].trimmed().toInt(&res);
if (!res) {
qWarning("%s: %d: Invalid linear units code", qPrintable(path), ln);
qWarning("%s:%d: Invalid linear units code", qPrintable(path), ln);
continue;
}
int transform = list[5].trimmed().toInt(&res);
if (!res) {
qWarning("%s: %d: Invalid coordinate transformation code",
qWarning("%s:%d: Invalid coordinate transformation code",
qPrintable(path), ln);
continue;
}
int cs = list[6].trimmed().toInt(&res);
if (!res) {
qWarning("%s:%d: Invalid coordinate system code",
qPrintable(path), ln);
continue;
}
if (LinearUnits(units).isNull()) {
qWarning("%s: %d: Unknown linear units code", qPrintable(path), ln);
if (!LinearUnits(units).isValid()) {
qWarning("%s:%d: Unknown linear units code", qPrintable(path), ln);
continue;
}
if (Projection::Method(transform).isNull()) {
qWarning("%s: %d: Unknown coordinate transformation code",
if (!Projection::Method(transform).isValid()) {
qWarning("%s:%d: Unknown coordinate transformation code",
qPrintable(path), ln);
continue;
}
if (!CoordinateSystem(cs).isValid()) {
qWarning("%s:%d: Unknown coordinate system code", qPrintable(path),
ln);
continue;
}
if (!(gcs = GCS::gcs(gcsid))) {
qWarning("%s: %d: Unknown GCS code", qPrintable(path), ln);
qWarning("%s:%d: Unknown GCS code", qPrintable(path), ln);
continue;
}
@ -182,7 +200,7 @@ void PCS::loadList(const QString &path)
continue;
}
PCS pcs(gcs, transform, setup, units);
PCS pcs(gcs, transform, setup, units, cs);
_pcss.append(Entry(id, proj, pcs));
}
}

View File

@ -5,6 +5,7 @@
#include <QList>
#include "gcs.h"
#include "linearunits.h"
#include "coordinatesystem.h"
#include "projection.h"
class PCS
@ -12,18 +13,20 @@ class PCS
public:
PCS() : _gcs(0) {}
PCS(const GCS *gcs, const Projection::Method &method,
const Projection::Setup &setup, const LinearUnits &units)
: _gcs(gcs), _method(method), _setup(setup), _units(units) {}
const Projection::Setup &setup, const LinearUnits &units,
const CoordinateSystem &cs = CoordinateSystem())
: _gcs(gcs), _method(method), _setup(setup), _units(units), _cs(cs) {}
PCS(const GCS *gcs, int proj);
const GCS *gcs() const {return _gcs;}
const Projection::Method &method() const {return _method;}
const Projection::Setup &setup() const {return _setup;}
const LinearUnits &units() const {return _units;}
const CoordinateSystem &coordinateSystem() const {return _cs;}
bool isNull() const
{return (_gcs->isNull() && _units.isNull() && _method.isNull()
&& _setup.isNull());}
&& _setup.isNull());}
bool isValid() const
{return (_gcs->isValid() && _units.isValid() && _method.isValid());}
@ -38,9 +41,9 @@ private:
Projection::Method _method;
Projection::Setup _setup;
LinearUnits _units;
CoordinateSystem _cs;
static QList<Entry> _pcss;
static GCS _nullGCS;
};
#ifndef QT_NO_DEBUG

View File

@ -6,6 +6,7 @@
#include "lambertazimuthal.h"
#include "latlon.h"
#include "gcs.h"
#include "pcs.h"
#include "projection.h"
@ -16,6 +17,7 @@ Projection::Method::Method(int id)
case 9801:
case 9802:
case 9807:
case 9815:
case 9820:
case 9822:
case 9841:
@ -26,29 +28,31 @@ Projection::Method::Method(int id)
}
}
Projection::Projection(const GCS *gcs, const Method &method, const Setup &setup,
const LinearUnits &units) : _gcs(gcs), _units(units)
Projection::Projection(const PCS *pcs) : _gcs(pcs->gcs()), _units(pcs->units()),
_cs(pcs->coordinateSystem()), _geographic(false)
{
const Ellipsoid *ellipsoid = _gcs->datum().ellipsoid();
const Projection::Setup &setup = pcs->setup();
switch (method.id()) {
case 9807:
_ct = new TransverseMercator(ellipsoid, setup.latitudeOrigin(),
setup.longitudeOrigin(), setup.scale(), setup.falseEasting(),
setup.falseNorthing());
break;
switch (pcs->method().id()) {
case 1024:
case 9841:
_ct = new Mercator();
break;
case 9801:
case 9815: // Oblique mercator aproximation using LCC1
_ct = new LambertConic1(ellipsoid, setup.latitudeOrigin(),
setup.longitudeOrigin(), setup.scale(), setup.falseEasting(),
setup.falseNorthing());
break;
case 9802:
_ct = new LambertConic2(ellipsoid, setup.standardParallel1(),
setup.standardParallel2(), setup.latitudeOrigin(),
setup.longitudeOrigin(), setup.falseEasting(),
setup.falseNorthing());
break;
case 9801:
_ct = new LambertConic1(ellipsoid, setup.latitudeOrigin(),
case 9807:
_ct = new TransverseMercator(ellipsoid, setup.latitudeOrigin(),
setup.longitudeOrigin(), setup.scale(), setup.falseEasting(),
setup.falseNorthing());
break;
@ -68,17 +72,19 @@ Projection::Projection(const GCS *gcs, const Method &method, const Setup &setup,
}
}
Projection::Projection(const GCS *gcs) : _gcs(gcs)
Projection::Projection(const GCS *gcs, const CoordinateSystem &cs)
: _gcs(gcs), _units(LinearUnits(9001)), _cs(cs), _geographic(true)
{
_ct = new LatLon(gcs->angularUnits());
_units = LinearUnits(9001);
}
Projection::Projection(const Projection &p)
{
_gcs = p._gcs;
_units = p._units;
_ct = p._ct->clone();
_ct = p._ct ? p._ct->clone() : 0;
_geographic = p._geographic;
_cs = p._cs;
}
Projection::~Projection()
@ -90,19 +96,23 @@ Projection &Projection::operator=(const Projection &p)
{
_gcs = p._gcs;
_units = p._units;
_ct = p._ct->clone();
_ct = p._ct ? p._ct->clone() : 0;
_geographic = p._geographic;
_cs = p._cs;
return *this;
}
QPointF Projection::ll2xy(const Coordinates &c) const
{
return _units.fromMeters(_ct->ll2xy(_gcs->fromWGS84(c)));
return isValid()
? _units.fromMeters(_ct->ll2xy(_gcs->fromWGS84(c))) : QPointF();
}
Coordinates Projection::xy2ll(const QPointF &p) const
{
return _gcs->toWGS84(_ct->xy2ll(_units.toMeters(p)));
return isValid()
? _gcs->toWGS84(_ct->xy2ll(_units.toMeters(p))) : Coordinates();
}
#ifndef QT_NO_DEBUG

View File

@ -5,8 +5,10 @@
#include <QDebug>
#include "common/coordinates.h"
#include "linearunits.h"
#include "coordinatesystem.h"
class GCS;
class PCS;
class CT;
class AngularUnits;
@ -68,22 +70,31 @@ public:
int _id;
};
Projection() : _gcs(0), _ct(0) {}
Projection() : _gcs(0), _ct(0), _geographic(false) {}
Projection(const Projection &p);
Projection(const GCS *gcs, const Method &method, const Setup &setup,
const LinearUnits &units);
Projection(const GCS *gcs);
Projection(const PCS *pcs);
Projection(const GCS *gcs, const CoordinateSystem &cs
= CoordinateSystem(CoordinateSystem::YX));
~Projection();
Projection &operator=(const Projection &p);
bool isNull() const {return (_gcs == 0 && _ct == 0 && _units.isNull());}
bool isValid() const {return !(_gcs == 0 || _ct == 0 || _units.isNull());}
bool isGeographic() const {return _geographic;}
QPointF ll2xy(const Coordinates &c) const;
Coordinates xy2ll(const QPointF &p) const;
const LinearUnits &units() const {return _units;}
const CoordinateSystem &coordinateSystem() const {return _cs;}
private:
const GCS * _gcs;
CT *_ct;
const GCS *_gcs;
const CT *_ct;
LinearUnits _units;
CoordinateSystem _cs;
bool _geographic;
};
#ifndef QT_NO_DEBUG

View File

@ -44,17 +44,12 @@ static quint64 number(const char* data, size_t size, int base = 8)
return val;
}
bool Tar::load(const QString &path)
bool Tar::open()
{
if (_file.isOpen())
_file.close();
_index.clear();
_file.setFileName(path);
if (!_file.open(QIODevice::ReadOnly))
return false;
QFileInfo fi(path);
QFileInfo fi(_file.fileName());
QString tmiPath = fi.path() + "/" + fi.completeBaseName() + ".tmi";
if (loadTmi(tmiPath))
@ -121,8 +116,8 @@ QByteArray Tar::file(const QString &name)
struct Header *hdr = (struct Header*)&buffer;
quint64 size;
QMap<QString, quint64>::const_iterator it = _index.find(name);
if (it == _index.end())
QMap<QString, quint64>::const_iterator it(_index.find(name));
if (it == _index.constEnd())
return QByteArray();
Q_ASSERT(_file.isOpen());

View File

@ -8,7 +8,9 @@
class Tar
{
public:
bool load(const QString &path);
Tar(const QString &name) : _file(name) {}
bool open();
QStringList files() const {return _index.keys();}
QByteArray file(const QString &name);

View File

@ -7,7 +7,7 @@
class TIFFFile : public QFile
{
public:
TIFFFile() : QFile(), _be(false) {}
TIFFFile() : _be(false) {}
TIFFFile(const QString &path) : QFile(path), _be(false) {}
bool readHeader(quint32 &ifd);
@ -33,8 +33,8 @@ public:
val = data;
#endif
return true;
}
return true;
}
private:
bool _be;

View File

@ -8,23 +8,26 @@
class Tile
{
public:
Tile(const QPoint &xy, int zoom)
{_xy = xy; _zoom = zoom;}
Tile(const QPoint &xy, const QVariant &zoom, const QRectF &bbox = QRectF())
{_xy = xy; _zoom = zoom; _bbox = bbox;}
int zoom() const {return _zoom;}
const QPoint& xy() const {return _xy;}
const QVariant &zoom() const {return _zoom;}
const QPoint &xy() const {return _xy;}
const QRectF &bbox() const {return _bbox;}
QPixmap& pixmap() {return _pixmap;}
private:
int _zoom;
QVariant _zoom;
QPoint _xy;
QRectF _bbox;
QPixmap _pixmap;
};
#ifndef QT_NO_DEBUG
inline QDebug operator<<(QDebug dbg, const Tile &tile)
{
dbg.nospace() << "Tile(" << tile.zoom() << ", " << tile.xy() << ")";
dbg.nospace() << "Tile(" << tile.zoom() << ", " << tile.xy() << ", "
<< tile.bbox() << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG

110
src/map/tileloader.cpp Normal file
View File

@ -0,0 +1,110 @@
#include <QDir>
#include <QFileInfo>
#include <QEventLoop>
#include "downloader.h"
#include "tileloader.h"
static bool loadTileFile(Tile &tile, const QString &file)
{
if (!tile.pixmap().load(file)) {
qWarning("%s: error loading tile file\n", qPrintable(file));
return false;
}
return true;
}
Downloader *TileLoader::_downloader = 0;
void TileLoader::loadTilesAsync(QList<Tile> &list)
{
QList<Download> dl;
for (int i = 0; i < list.size(); i++) {
Tile &t = list[i];
QString file = tileFile(t);
QFileInfo fi(file);
if (!fi.exists())
dl.append(Download(tileUrl(t), file));
else
loadTileFile(t, file);
}
if (!dl.empty())
_downloader->get(dl, _authorization);
}
void TileLoader::loadTilesSync(QList<Tile> &list)
{
QList<Download> dl;
for (int i = 0; i < list.size(); i++) {
Tile &t = list[i];
QString file = tileFile(t);
QFileInfo fi(file);
if (!fi.exists())
dl.append(Download(tileUrl(t), file));
else
loadTileFile(t, file);
}
if (dl.empty())
return;
QEventLoop wait;
QObject::connect(_downloader, SIGNAL(finished()), &wait, SLOT(quit()));
if (_downloader->get(dl, _authorization))
wait.exec();
for (int i = 0; i < list.size(); i++) {
Tile &t = list[i];
if (t.pixmap().isNull()) {
QString file = tileFile(t);
if (QFileInfo(file).exists())
loadTileFile(t, file);
}
}
}
void TileLoader::clearCache()
{
QDir dir = QDir(_dir);
QStringList list = dir.entryList();
for (int i = 0; i < list.count(); i++)
dir.remove(list.at(i));
_downloader->clearErrors();
}
QString TileLoader::tileUrl(const Tile &tile) const
{
QString url(_url);
if (!tile.bbox().isNull()) {
QString bbox = QString("%1,%2,%3,%4").arg(
QString::number(tile.bbox().left(), 'f', 6),
QString::number(tile.bbox().bottom(), 'f', 6),
QString::number(tile.bbox().right(), 'f', 6),
QString::number(tile.bbox().top(), 'f', 6));
url.replace("$bbox", bbox);
} else {
url.replace("$z", tile.zoom().toString());
url.replace("$x", QString::number(tile.xy().x()));
url.replace("$y", QString::number(tile.xy().y()));
}
return url;
}
QString TileLoader::tileFile(const Tile &tile) const
{
QString file = _dir + QString("/%1-%2-%3").arg(tile.zoom().toString())
.arg(tile.xy().x()).arg(tile.xy().y());
return file;
}

35
src/map/tileloader.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef TILELOADER_H
#define TILELOADER_H
#include <QString>
#include "tile.h"
#include "downloader.h"
class TileLoader
{
public:
TileLoader() {}
TileLoader(const QString &url, const QString &dir,
const Authorization &authorization = Authorization())
: _url(url), _dir(dir), _authorization(authorization) {}
void loadTilesAsync(QList<Tile> &list);
void loadTilesSync(QList<Tile> &list);
void clearCache();
static Downloader *downloader() {return _downloader;}
static void setDownloader(Downloader *downloader)
{_downloader = downloader;}
private:
QString tileUrl(const Tile &tile) const;
QString tileFile(const Tile &tile) const;
QString _url;
QString _dir;
Authorization _authorization;
static Downloader *_downloader;
};
#endif // TILELOADER_Honlinemap

View File

@ -2,6 +2,9 @@
#include "matrix.h"
#include "transform.h"
#define NULL_QTRANSFORM 0,0,0,0,0,0,0,0,0
void Transform::simple(const QList<ReferencePoint> &points)
{
if (points.at(0).xy.x() == points.at(1).xy.x()
@ -18,7 +21,8 @@ void Transform::simple(const QList<ReferencePoint> &points)
dX = points.at(1).xy.x() - points.at(1).pp.x() * sX;
dY = points.at(0).xy.y() - points.at(0).pp.y() * sY;
_transform = QTransform(sX, 0, 0, sY, dX, dY);
_proj2img = QTransform(sX, 0, 0, sY, dX, dY);
_img2proj = _proj2img.inverted();
}
void Transform::affine(const QList<ReferencePoint> &points)
@ -59,8 +63,15 @@ void Transform::affine(const QList<ReferencePoint> &points)
return;
}
_transform = QTransform(M.m(0,3), M.m(0,4), M.m(1,3), M.m(1,4), M.m(2,3),
_proj2img = QTransform(M.m(0,3), M.m(0,4), M.m(1,3), M.m(1,4), M.m(2,3),
M.m(2,4));
_img2proj = _proj2img.inverted();
}
Transform::Transform()
: _proj2img(NULL_QTRANSFORM), _img2proj(NULL_QTRANSFORM)
{
}
Transform::Transform(const QList<ReferencePoint> &points)
@ -73,6 +84,29 @@ Transform::Transform(const QList<ReferencePoint> &points)
affine(points);
}
Transform::Transform(const ReferencePoint &p, const QPointF &scale)
: _proj2img(NULL_QTRANSFORM), _img2proj(NULL_QTRANSFORM)
{
if (scale.x() == 0.0 || scale.y() == 0.0) {
_errorString = "Invalid scale factor";
return;
}
_img2proj = QTransform(scale.x(), 0, 0, -scale.y(), p.pp.x() - p.xy.x()
/ scale.x(), p.pp.y() + p.xy.x() / scale.y());
_proj2img = _img2proj.inverted();
}
Transform::Transform(double m[16])
: _proj2img(NULL_QTRANSFORM), _img2proj(NULL_QTRANSFORM)
{
_img2proj = QTransform(m[0], m[1], m[4], m[5], m[3], m[7]);
if (!_img2proj.isInvertible())
_errorString = "Singular transformation matrix";
else
_proj2img = _img2proj.inverted();
}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const ReferencePoint &p)
{

View File

@ -3,7 +3,7 @@
#include <QTransform>
#include <QList>
#include "common/coordinates.h"
#include <QDebug>
struct ReferencePoint {
QPoint xy;
@ -13,17 +13,23 @@ struct ReferencePoint {
class Transform
{
public:
Transform();
Transform(const QList<ReferencePoint> &points);
Transform(const ReferencePoint &p, const QPointF &scale);
Transform(double m[16]);
bool isNull() {return _transform.type() == QTransform::TxNone;}
QPointF proj2img(const QPointF &p) const {return _proj2img.map(p);}
QPointF img2proj(const QPointF &p) const {return _img2proj.map(p);}
bool isValid() const
{return _proj2img.isInvertible() && _img2proj.isInvertible();}
const QString &errorString() const {return _errorString;}
const QTransform &transform() const {return _transform;}
private:
void simple(const QList<ReferencePoint> &points);
void affine(const QList<ReferencePoint> &points);
QTransform _transform;
QTransform _proj2img, _img2proj;
QString _errorString;
};

View File

@ -47,14 +47,14 @@ Defense.
#define SPHSN(lat) \
((double)(_e->radius() / sqrt(1.e0 - _es * pow(sin(lat), 2))))
((double)(_a / sqrt(1.e0 - _es * pow(sin(lat), 2))))
#define SPHTMD(lat) \
((double)(_ap * lat - _bp * sin(2.e0 * lat) + _cp * sin(4.e0 * lat) \
- _dp * sin(6.e0 * lat) + _ep * sin(8.e0 * lat)))
#define DENOM(lat) \
((double)(sqrt(1.e0 - _es * pow(sin(lat),2))))
#define SPHSR(lat) \
((double)(_e->radius() * (1.e0 - _es) / pow(DENOM(lat), 3)))
((double)(_a * (1.e0 - _es) / pow(DENOM(lat), 3)))
TransverseMercator::TransverseMercator(const Ellipsoid *ellipsoid,
@ -65,31 +65,32 @@ TransverseMercator::TransverseMercator(const Ellipsoid *ellipsoid,
double b;
_e = ellipsoid;
_a = ellipsoid->radius();
_longitudeOrigin = deg2rad(longitudeOrigin);
_latitudeOrigin = deg2rad(latitudeOrigin);
_scale = scale;
_falseEasting = falseEasting;
_falseNorthing = falseNorthing;
_es = 2 * _e->flattening() - _e->flattening() * _e->flattening();
_es = 2 * ellipsoid->flattening() - ellipsoid->flattening()
* ellipsoid->flattening();
_ebs = (1 / (1 - _es)) - 1;
b = _e->radius() * (1 - _e->flattening());
b = _a * (1 - ellipsoid->flattening());
tn = (_e->radius() - b) / (_e->radius() + b);
tn = (_a - b) / (_a + b);
tn2 = tn * tn;
tn3 = tn2 * tn;
tn4 = tn3 * tn;
tn5 = tn4 * tn;
_ap = _e->radius() * (1.e0 - tn + 5.e0 * (tn2 - tn3) / 4.e0 + 81.e0
_ap = _a * (1.e0 - tn + 5.e0 * (tn2 - tn3) / 4.e0 + 81.e0
* (tn4 - tn5) / 64.e0);
_bp = 3.e0 * _e->radius() * (tn - tn2 + 7.e0 * (tn3 - tn4) / 8.e0 + 55.e0
_bp = 3.e0 * _a * (tn - tn2 + 7.e0 * (tn3 - tn4) / 8.e0 + 55.e0
* tn5 / 64.e0 ) / 2.e0;
_cp = 15.e0 * _e->radius() * (tn2 - tn3 + 3.e0 * (tn4 - tn5 ) / 4.e0) / 16.0;
_dp = 35.e0 * _e->radius() * (tn3 - tn4 + 11.e0 * tn5 / 16.e0) / 48.e0;
_ep = 315.e0 * _e->radius() * (tn4 - tn5) / 512.e0;
_cp = 15.e0 * _a * (tn2 - tn3 + 3.e0 * (tn4 - tn5 ) / 4.e0) / 16.0;
_dp = 35.e0 * _a * (tn3 - tn4 + 11.e0 * tn5 / 16.e0) / 48.e0;
_ep = 315.e0 * _a * (tn4 - tn5) / 512.e0;
}
QPointF TransverseMercator::ll2xy(const Coordinates &c) const

View File

@ -2,7 +2,8 @@
#define TRANSVERSEMERCATOR_H
#include "ct.h"
#include "ellipsoid.h"
class Ellipsoid;
class TransverseMercator : public CT
{
@ -17,12 +18,12 @@ public:
virtual Coordinates xy2ll(const QPointF &p) const;
private:
const Ellipsoid *_e;
double _longitudeOrigin;
double _latitudeOrigin;
double _scale;
double _falseEasting;
double _falseNorthing;
double _a;
double _es;
double _ebs;

View File

@ -3,11 +3,10 @@
#include "projection.h"
class UTM
namespace UTM
{
public:
static int zone(const Coordinates &c);
static Projection::Setup setup(int zone);
};
int zone(const Coordinates &c);
Projection::Setup setup(int zone);
}
#endif // UTM_H

288
src/map/wms.cpp Normal file
View File

@ -0,0 +1,288 @@
#include <QFileInfo>
#include <QEventLoop>
#include <QXmlStreamReader>
#include <QStringList>
#include "downloader.h"
#include "crs.h"
#include "wms.h"
Downloader *WMS::_downloader = 0;
WMS::CTX::CTX(const Setup &setup) : setup(setup), formatSupported(false)
{
QStringList ll = setup.layer().split(',');
if (setup.style().isEmpty()) {
for (int i = 0; i < ll.size(); i++)
layers.append(Layer(ll.at(i)));
} else {
QStringList sl = setup.style().split(',');
if (ll.size() != sl.size())
return;
for (int i = 0; i < ll.size(); i++)
layers.append(Layer(ll.at(i), sl.at(i)));
}
}
void WMS::getMap(QXmlStreamReader &reader, CTX &ctx)
{
while (reader.readNextStartElement()) {
if (reader.name() == "Format") {
if (reader.readElementText() == ctx.setup.format())
ctx.formatSupported = true;
} else
reader.skipCurrentElement();
}
}
void WMS::request(QXmlStreamReader &reader, CTX &ctx)
{
while (reader.readNextStartElement()) {
if (reader.name() == "GetMap")
getMap(reader, ctx);
else
reader.skipCurrentElement();
}
}
QString WMS::style(QXmlStreamReader &reader)
{
QString name;
while (reader.readNextStartElement()) {
if (reader.name() == "Name")
name = reader.readElementText();
else
reader.skipCurrentElement();
}
return name;
}
RectC WMS::geographicBoundingBox(QXmlStreamReader &reader)
{
qreal left = NAN, top = NAN, right = NAN, bottom = NAN;
while (reader.readNextStartElement()) {
if (reader.name() == "westBoundLongitude")
left = reader.readElementText().toDouble();
else if (reader.name() == "eastBoundLongitude")
right = reader.readElementText().toDouble();
else if (reader.name() == "northBoundLatitude")
top = reader.readElementText().toDouble();
else if (reader.name() == "southBoundLatitude")
bottom = reader.readElementText().toDouble();
else
reader.skipCurrentElement();
}
return RectC(Coordinates(left, top), Coordinates(right, bottom));
}
void WMS::layer(QXmlStreamReader &reader, CTX &ctx,
const QList<QString> &pCRSs, const QList<QString> &pStyles,
RangeF &pScaleDenominator, RectC &pBoundingBox)
{
QString name;
QList<QString> CRSs(pCRSs);
QList<QString> styles(pStyles);
RangeF scaleDenominator(pScaleDenominator);
RectC boundingBox(pBoundingBox);
int index;
while (reader.readNextStartElement()) {
if (reader.name() == "Name")
name = reader.readElementText();
else if (reader.name() == "CRS" || reader.name() == "SRS")
CRSs.append(reader.readElementText());
else if (reader.name() == "Style")
styles.append(style(reader));
else if (reader.name() == "MinScaleDenominator") {
double sd = reader.readElementText().toDouble();
if (sd > 0)
scaleDenominator.setMin(sd);
} else if (reader.name() == "MaxScaleDenominator") {
double sd = reader.readElementText().toDouble();
if (sd > 0)
scaleDenominator.setMax(sd);
} else if (reader.name() == "LatLonBoundingBox") {
QXmlStreamAttributes attr = reader.attributes();
boundingBox = RectC(Coordinates(
attr.value("minx").toString().toDouble(),
attr.value("maxy").toString().toDouble()),
Coordinates(attr.value("maxx").toString().toDouble(),
attr.value("miny").toString().toDouble()));
reader.skipCurrentElement();
} else if (reader.name() == "EX_GeographicBoundingBox")
boundingBox = geographicBoundingBox(reader);
else if (reader.name() == "Layer")
layer(reader, ctx, CRSs, styles, scaleDenominator, boundingBox);
else
reader.skipCurrentElement();
}
if ((index = ctx.layers.indexOf(name)) >= 0) {
Layer &layer = ctx.layers[index];
layer.scaleDenominator = scaleDenominator;
layer.boundingBox = boundingBox;
layer.isDefined = true;
layer.hasStyle = styles.contains(layer.style) || layer.style.isEmpty();
layer.hasCRS = CRSs.contains(ctx.setup.crs());
}
}
void WMS::capability(QXmlStreamReader &reader, CTX &ctx)
{
QList<QString> CRSs;
QList<QString> styles;
RangeF scaleDenominator(133.295598991, 559082264.0287178);
RectC boundingBox;
while (reader.readNextStartElement()) {
if (reader.name() == "Layer")
layer(reader, ctx, CRSs, styles, scaleDenominator, boundingBox);
else if (reader.name() == "Request")
request(reader, ctx);
else
reader.skipCurrentElement();
}
}
void WMS::capabilities(QXmlStreamReader &reader, CTX &ctx)
{
_version = reader.attributes().value("version").toString();
while (reader.readNextStartElement()) {
if (reader.name() == "Capability")
capability(reader, ctx);
else
reader.skipCurrentElement();
}
}
bool WMS::parseCapabilities(const QString &path, const Setup &setup)
{
QFile file(path);
CTX ctx(setup);
QXmlStreamReader reader;
if (ctx.layers.isEmpty()) {
_errorString = "Invalid layers/styles list definition";
return false;
}
if (!file.open(QFile::ReadOnly | QFile::Text)) {
_errorString = file.errorString();
return false;
}
reader.setDevice(&file);
if (reader.readNextStartElement()) {
if (reader.name() == "WMS_Capabilities"
|| reader.name() == "WMT_MS_Capabilities")
capabilities(reader, ctx);
else
reader.raiseError("Not a WMS Capabilities XML file");
}
if (reader.error()) {
_errorString = QString("%1:%2: %3").arg(path).arg(reader.lineNumber())
.arg(reader.errorString());
return false;
}
if (!ctx.formatSupported) {
_errorString = ctx.setup.format() + ": format not provided";
return false;
}
for (int i = 0; i < ctx.layers.size(); i++) {
const Layer &layer = ctx.layers.at(i);
if (!layer.isDefined) {
_errorString = layer.name + ": layer not provided";
return false;
}
if (!layer.hasStyle) {
_errorString = layer.style + ": style not provided for layer "
+ layer.name;
return false;
}
if (!layer.hasCRS) {
_errorString = ctx.setup.crs() + ": CRS not provided for layer "
+ layer.name;
return false;
}
if (!layer.scaleDenominator.isValid()
|| layer.scaleDenominator.isNull()) {
_errorString = "Invalid scale denominator range for layer "
+ layer.name;
return false;
}
if (!layer.boundingBox.isValid()) {
_errorString = "Invalid/missing bounding box for layer "
+ layer.name;
return false;
}
}
_projection = CRS::projection(ctx.setup.crs());
if (_projection.isNull()) {
_errorString = ctx.setup.crs() + ": unknown CRS";
return false;
}
_boundingBox = ctx.layers.first().boundingBox;
for (int i = 1; i < ctx.layers.size(); i++)
_boundingBox &= ctx.layers.at(i).boundingBox;
if (_boundingBox.isNull()) {
_errorString = "Empty layers bounding box join";
return false;
}
_scaleDenominator = ctx.layers.first().scaleDenominator;
for (int i = 1; i < ctx.layers.size(); i++)
_scaleDenominator &= ctx.layers.at(i).scaleDenominator;
if (_scaleDenominator.isNull()) {
_errorString = "Empty layers scale denominator range join";
return false;
}
return true;
}
bool WMS::getCapabilities(const QString &url, const QString &file,
const Authorization &authorization)
{
QList<Download> dl;
dl.append(Download(url, file));
QEventLoop wait;
QObject::connect(_downloader, SIGNAL(finished()), &wait, SLOT(quit()));
if (_downloader->get(dl, authorization))
wait.exec();
if (QFileInfo(file).exists())
return true;
else {
_errorString = "Error downloading capabilities XML file";
return false;
}
}
WMS::WMS(const QString &file, const WMS::Setup &setup) : _valid(false)
{
QString capaUrl = QString("%1?service=WMS&request=GetCapabilities")
.arg(setup.url());
if (!QFileInfo(file).exists())
if (!getCapabilities(capaUrl, file, setup.authorization()))
return;
if (!parseCapabilities(file, setup))
return;
_valid = true;
}

113
src/map/wms.h Normal file
View File

@ -0,0 +1,113 @@
#ifndef WMS_H
#define WMS_H
#include <QString>
#include <QRectF>
#include "common/range.h"
#include "common/rectc.h"
#include "projection.h"
#include "downloader.h"
#include "coordinatesystem.h"
class QXmlStreamReader;
class WMS
{
public:
class Setup
{
public:
Setup(const QString &url, const QString &layer, const QString &style,
const QString &format, const QString &crs,
const CoordinateSystem &cs,
const QList<QPair<QString, QString> > &dimensions,
const Authorization &authorization = Authorization())
: _url(url), _layer(layer), _style(style), _format(format),
_crs(crs), _cs(cs), _dimensions(dimensions),
_authorization(authorization) {}
const QString &url() const {return _url;}
const Authorization &authorization() const {return _authorization;}
const QString &layer() const {return _layer;}
const QString &style() const {return _style;}
const QString &format() const {return _format;}
const QString &crs() const {return _crs;}
const CoordinateSystem &coordinateSystem() const {return _cs;}
const QList<QPair<QString, QString> > &dimensions() const
{return _dimensions;}
private:
QString _url;
QString _layer;
QString _style;
QString _format;
QString _crs;
CoordinateSystem _cs;
QList<QPair<QString, QString> > _dimensions;
Authorization _authorization;
};
WMS(const QString &path, const Setup &setup);
const Projection &projection() const {return _projection;}
const RangeF &scaleDenominator() const {return _scaleDenominator;}
const RectC &boundingBox() const {return _boundingBox;}
const QString &version() const {return _version;}
bool isValid() const {return _valid;}
const QString &errorString() const {return _errorString;}
static void setDownloader(Downloader *downloader)
{_downloader = downloader;}
private:
struct Layer {
QString name;
QString style;
RangeF scaleDenominator;
RectC boundingBox;
bool isDefined;
bool hasStyle;
bool hasCRS;
Layer(const QString &name, const QString &style = QString())
: name(name), style(style), isDefined(false), hasStyle(false),
hasCRS(false) {}
bool operator==(const Layer &other) const
{return this->name == other.name;}
};
struct CTX {
const Setup &setup;
QList<Layer> layers;
bool formatSupported;
CTX(const Setup &setup);
};
RectC geographicBoundingBox(QXmlStreamReader &reader);
QString style(QXmlStreamReader &reader);
void getMap(QXmlStreamReader &reader, CTX &ctx);
void request(QXmlStreamReader &reader, CTX &ctx);
void layer(QXmlStreamReader &reader, CTX &ctx, const QList<QString> &pCRSs,
const QList<QString> &pStyles, RangeF &pScaleDenominator,
RectC &pBoundingBox);
void capability(QXmlStreamReader &reader, CTX &ctx);
void capabilities(QXmlStreamReader &reader, CTX &ctx);
bool parseCapabilities(const QString &path, const Setup &setup);
bool getCapabilities(const QString &url, const QString &file,
const Authorization &authorization);
Projection _projection;
RangeF _scaleDenominator;
RectC _boundingBox;
QString _version;
bool _valid;
QString _errorString;
static Downloader *_downloader;
};
#endif // WMS_H

256
src/map/wmsmap.cpp Normal file
View File

@ -0,0 +1,256 @@
#include <QDir>
#include <QPainter>
#include "common/wgs84.h"
#include "common/rectc.h"
#include "config.h"
#include "downloader.h"
#include "wmsmap.h"
#define CAPABILITIES_FILE "capabilities.xml"
#define TILE_SIZE 256
qreal WMSMap::sd2res(qreal scaleDenominator) const
{
return scaleDenominator * 0.28e-3 * _projection.units().fromMeters(1.0);
}
QString WMSMap::tileUrl(const QString &version) const
{
QString url;
url = QString("%1?version=%2&request=GetMap&bbox=$bbox"
"&width=%3&height=%4&layers=%5&styles=%6&format=%7&transparent=true")
.arg(_setup.url(), version, QString::number(TILE_SIZE),
QString::number(TILE_SIZE), _setup.layer(), _setup.style(),
_setup.format());
if (version >= "1.3.0")
url.append(QString("&CRS=%1").arg(_setup.crs()));
else
url.append(QString("&SRS=%1").arg(_setup.crs()));
for (int i = 0; i < _setup.dimensions().size(); i++) {
const QPair<QString, QString> &dim = _setup.dimensions().at(i);
url.append(QString("&%1=%2").arg(dim.first, dim.second));
}
return url;
}
QString WMSMap::tilesDir() const
{
return QString(TILES_DIR + "/" + _name);
}
void WMSMap::computeZooms(const RangeF &scaleDenominator)
{
_zooms.clear();
if (scaleDenominator.size() > 0) {
qreal ld = log2(scaleDenominator.max()) - log2(scaleDenominator.min());
int cld = ceil(ld);
qreal step = ld / (qreal)cld;
qreal lmax = log2(scaleDenominator.max());
for (int i = 0; i <= cld; i++)
_zooms.append(pow(2.0, lmax - i * step));
} else
_zooms.append(scaleDenominator.min());
}
void WMSMap::updateTransform()
{
qreal scaleDenominator = _zooms.at(_zoom);
ReferencePoint tl, br;
qreal pixelSpan = sd2res(scaleDenominator);
if (_projection.isGeographic())
pixelSpan /= deg2rad(WGS84_RADIUS);
tl.xy = QPoint(0, 0);
tl.pp = _boundingBox.topLeft();
br.xy = QPoint(_boundingBox.width() / pixelSpan, -_boundingBox.height()
/ pixelSpan);
br.pp = _boundingBox.bottomRight();
QList<ReferencePoint> points;
points << tl << br;
_transform = Transform(points);
}
bool WMSMap::loadWMS()
{
QString file = tilesDir() + "/" + CAPABILITIES_FILE;
WMS wms(file, _setup);
if (!wms.isValid()) {
_errorString = wms.errorString();
return false;
}
_projection = wms.projection();
RectC bb = wms.boundingBox().normalized();
_boundingBox = QRectF(_projection.ll2xy(Coordinates(bb.topLeft().lon(),
bb.bottomRight().lat())), _projection.ll2xy(Coordinates(
bb.bottomRight().lon(), bb.topLeft().lat())));
_tileLoader = TileLoader(tileUrl(wms.version()), tilesDir(),
_setup.authorization());
if (wms.version() >= "1.3.0") {
if (_setup.coordinateSystem().axisOrder() == CoordinateSystem::Unknown)
_cs = _projection.coordinateSystem();
else
_cs = _setup.coordinateSystem();
} else
_cs = CoordinateSystem::XY;
computeZooms(wms.scaleDenominator());
updateTransform();
return true;
}
WMSMap::WMSMap(const QString &name, const WMS::Setup &setup, QObject *parent)
: Map(parent), _name(name), _setup(setup), _zoom(0), _block(false),
_valid(false)
{
if (!QDir().mkpath(tilesDir())) {
_errorString = "Error creating tiles dir";
return;
}
_valid = loadWMS();
}
void WMSMap::clearCache()
{
_tileLoader.clearCache();
_zoom = 0;
if (!loadWMS())
qWarning("%s: %s\n", qPrintable(_name), qPrintable(_errorString));
}
void WMSMap::load()
{
connect(TileLoader::downloader(), SIGNAL(finished()), this,
SLOT(emitLoaded()));
}
void WMSMap::unload()
{
disconnect(TileLoader::downloader(), SIGNAL(finished()), this,
SLOT(emitLoaded()));
}
void WMSMap::emitLoaded()
{
emit loaded();
}
QRectF WMSMap::bounds() const
{
qreal pixelSpan = sd2res(_zooms.at(_zoom));
if (_projection.isGeographic())
pixelSpan /= deg2rad(WGS84_RADIUS);
QSizeF size(_boundingBox.width() / pixelSpan, -_boundingBox.height()
/ pixelSpan);
return QRectF(QPointF(0, 0), size);
}
qreal WMSMap::resolution(const QRectF &rect) const
{
Coordinates tl = xy2ll((rect.topLeft()));
Coordinates br = xy2ll(rect.bottomRight());
qreal ds = tl.distanceTo(br);
qreal ps = QLineF(rect.topLeft(), rect.bottomRight()).length();
return ds/ps;
}
int WMSMap::zoomFit(const QSize &size, const RectC &br)
{
if (br.isValid()) {
QRectF tbr(_projection.ll2xy(br.topLeft()),
_projection.ll2xy(br.bottomRight()));
QPointF sc(tbr.width() / size.width(), tbr.height() / size.height());
qreal resolution = qMax(qAbs(sc.x()), qAbs(sc.y()));
if (_projection.isGeographic())
resolution *= deg2rad(WGS84_RADIUS);
_zoom = 0;
for (int i = 0; i < _zooms.size(); i++) {
if (sd2res(_zooms.at(i)) < resolution)
break;
_zoom = i;
}
} else
_zoom = _zooms.size() - 1;
updateTransform();
return _zoom;
}
int WMSMap::zoomIn()
{
_zoom = qMin(_zoom + 1, _zooms.size() - 1);
updateTransform();
return _zoom;
}
int WMSMap::zoomOut()
{
_zoom = qMax(_zoom - 1, 0);
updateTransform();
return _zoom;
}
QPointF WMSMap::ll2xy(const Coordinates &c) const
{
return _transform.proj2img(_projection.ll2xy(c));
}
Coordinates WMSMap::xy2ll(const QPointF &p) const
{
return _projection.xy2ll(_transform.img2proj(p));
}
void WMSMap::draw(QPainter *painter, const QRectF &rect)
{
QPoint tl = QPoint((int)floor(rect.left() / (qreal)TILE_SIZE),
(int)floor(rect.top() / (qreal)TILE_SIZE));
QPoint br = QPoint((int)ceil(rect.right() / (qreal)TILE_SIZE),
(int)ceil(rect.bottom() / (qreal)TILE_SIZE));
QList<Tile> tiles;
for (int i = tl.x(); i < br.x(); i++) {
for (int j = tl.y(); j < br.y(); j++) {
QPointF ttl(_transform.img2proj(QPointF(i * TILE_SIZE,
j * TILE_SIZE)));
QPointF tbr(_transform.img2proj(QPointF(i * TILE_SIZE + TILE_SIZE
- 1, j * TILE_SIZE + TILE_SIZE - 1)));
QRectF bbox = (_cs.axisOrder() == CoordinateSystem::YX)
? QRectF(QPointF(tbr.y(), tbr.x()), QPointF(ttl.y(), ttl.x()))
: QRectF(ttl, tbr);
tiles.append(Tile(QPoint(i, j), _zoom, bbox));
}
}
if (_block)
_tileLoader.loadTilesSync(tiles);
else
_tileLoader.loadTilesAsync(tiles);
for (int i = 0; i < tiles.count(); i++) {
Tile &t = tiles[i];
QPoint tp(t.xy().x() * TILE_SIZE, t.xy().y() * TILE_SIZE);
if (t.pixmap().isNull())
painter->fillRect(QRect(tp, QSize(TILE_SIZE, TILE_SIZE)),
_backgroundColor);
else
painter->drawPixmap(tp, t.pixmap());
}
}

74
src/map/wmsmap.h Normal file
View File

@ -0,0 +1,74 @@
#ifndef WMSMAP_H
#define WMSMAP_H
#include "transform.h"
#include "projection.h"
#include "map.h"
#include "wms.h"
#include "tileloader.h"
class WMSMap : public Map
{
Q_OBJECT
public:
WMSMap(const QString &name, const WMS::Setup &setup, QObject *parent = 0);
const QString &name() const {return _name;}
QRectF bounds() const;
qreal resolution(const QRectF &rect) const;
int zoom() const {return _zoom;}
int zoomFit(const QSize &size, const RectC &br);
int zoomIn();
int zoomOut();
QPointF ll2xy(const Coordinates &c)
{return static_cast<const WMSMap &>(*this).ll2xy(c);}
Coordinates xy2ll(const QPointF &p)
{return static_cast<const WMSMap &>(*this).xy2ll(p);}
void draw(QPainter *painter, const QRectF &rect);
void setBlockingMode(bool block) {_block = block;}
void clearCache();
void load();
void unload();
bool isValid() const {return _valid;}
QString errorString() const {return _errorString;}
private slots:
void emitLoaded();
private:
QString tileUrl(const QString &version) const;
qreal sd2res(qreal scaleDenominator) const;
QString tilesDir() const;
void computeZooms(const RangeF &scaleDenominator);
void updateTransform();
bool loadWMS();
QPointF ll2xy(const Coordinates &c) const;
Coordinates xy2ll(const QPointF &p) const;
QString _name;
WMS::Setup _setup;
TileLoader _tileLoader;
Projection _projection;
Transform _transform;
CoordinateSystem _cs;
QVector<qreal> _zooms;
QRectF _boundingBox;
int _zoom;
bool _block;
bool _valid;
QString _errorString;
};
#endif // WMSMAP_H

376
src/map/wmts.cpp Normal file
View File

@ -0,0 +1,376 @@
#include <QXmlStreamReader>
#include <QFile>
#include <QFileInfo>
#include <QEventLoop>
#include <QTextStream>
#include <QStringList>
#include <QtAlgorithms>
#include <QXmlStreamReader>
#include "downloader.h"
#include "pcs.h"
#include "crs.h"
#include "wmts.h"
Downloader *WMTS::_downloader = 0;
WMTS::TileMatrix WMTS::tileMatrix(QXmlStreamReader &reader)
{
TileMatrix matrix;
while (reader.readNextStartElement()) {
if (reader.name() == "Identifier")
matrix.id = reader.readElementText();
else if (reader.name() == "ScaleDenominator")
matrix.scaleDenominator = reader.readElementText().toDouble();
else if (reader.name() == "TopLeftCorner") {
QString str = reader.readElementText();
QTextStream ts(&str);
ts >> matrix.topLeft.rx() >> matrix.topLeft.ry();
} else if (reader.name() == "TileWidth")
matrix.tile.setWidth(reader.readElementText().toInt());
else if (reader.name() == "TileHeight")
matrix.tile.setHeight(reader.readElementText().toInt());
else if (reader.name() == "MatrixWidth")
matrix.matrix.setWidth(reader.readElementText().toInt());
else if (reader.name() == "MatrixHeight")
matrix.matrix.setHeight(reader.readElementText().toInt());
else
reader.skipCurrentElement();
}
if (!matrix.isValid())
reader.raiseError("Invalid TileMatrix definition");
return matrix;
}
void WMTS::tileMatrixSet(QXmlStreamReader &reader, CTX &ctx)
{
QString id, crs;
QSet<TileMatrix> matrixes;
while (reader.readNextStartElement()) {
if (reader.name() == "Identifier")
id = reader.readElementText();
else if (reader.name() == "SupportedCRS")
crs = reader.readElementText();
else if (reader.name() == "TileMatrix")
matrixes.insert(tileMatrix(reader));
else
reader.skipCurrentElement();
}
if (id == ctx.setup.set()) {
ctx.crs = crs;
_matrixes = matrixes;
}
}
WMTS::MatrixLimits WMTS::tileMatrixLimits(QXmlStreamReader &reader)
{
MatrixLimits limits;
while (reader.readNextStartElement()) {
if (reader.name() == "TileMatrix")
limits.id = reader.readElementText();
else if (reader.name() == "MinTileRow")
limits.rect.setTop(reader.readElementText().toInt());
else if (reader.name() == "MaxTileRow")
limits.rect.setBottom(reader.readElementText().toInt());
else if (reader.name() == "MinTileCol")
limits.rect.setLeft(reader.readElementText().toInt());
else if (reader.name() == "MaxTileCol")
limits.rect.setRight(reader.readElementText().toInt());
else
reader.skipCurrentElement();
}
if (!limits.isValid())
reader.raiseError("Invalid TileMatrixLimits definition");
return limits;
}
QSet<WMTS::MatrixLimits> WMTS::tileMatrixSetLimits(QXmlStreamReader &reader)
{
QSet<MatrixLimits> limits;
while (reader.readNextStartElement()) {
if (reader.name() == "TileMatrixLimits")
limits.insert(tileMatrixLimits(reader));
else
reader.skipCurrentElement();
}
return limits;
}
void WMTS::tileMatrixSetLink(QXmlStreamReader &reader, CTX &ctx)
{
QString id;
QSet<MatrixLimits> limits;
while (reader.readNextStartElement()) {
if (reader.name() == "TileMatrixSet")
id = reader.readElementText();
else if (reader.name() == "TileMatrixSetLimits")
limits = tileMatrixSetLimits(reader);
else
reader.skipCurrentElement();
}
if (id == ctx.setup.set()) {
ctx.hasSet = true;
_limits = limits;
}
}
RectC WMTS::wgs84BoundingBox(QXmlStreamReader &reader)
{
Coordinates topLeft, bottomRight;
while (reader.readNextStartElement()) {
if (reader.name() == "LowerCorner") {
QString str = reader.readElementText();
QTextStream(&str) >> topLeft.rlon() >> bottomRight.rlat();
} else if (reader.name() == "UpperCorner") {
QString str = reader.readElementText();
QTextStream(&str) >> bottomRight.rlon() >> topLeft.rlat();
} else
reader.skipCurrentElement();
}
return RectC(topLeft, bottomRight);
}
QString WMTS::style(QXmlStreamReader &reader)
{
QString id;
while (reader.readNextStartElement()) {
if (reader.name() == "Identifier")
id = reader.readElementText();
else
reader.skipCurrentElement();
}
return id;
}
void WMTS::layer(QXmlStreamReader &reader, CTX &ctx)
{
QString id, tpl;
RectC bounds;
QStringList formats, styles;
while (reader.readNextStartElement()) {
if (reader.name() == "Identifier")
id = reader.readElementText();
else if (reader.name() == "TileMatrixSetLink")
tileMatrixSetLink(reader, ctx);
else if (reader.name() == "WGS84BoundingBox")
bounds = wgs84BoundingBox(reader);
else if (reader.name() == "ResourceURL") {
const QXmlStreamAttributes &attr = reader.attributes();
if (attr.value("resourceType") == "tile")
tpl = attr.value("template").toString();
reader.skipCurrentElement();
} else if (reader.name() == "Style")
styles.append(style(reader));
else if (reader.name() == "Format")
formats.append(reader.readElementText());
else
reader.skipCurrentElement();
}
if (id == ctx.setup.layer()) {
ctx.hasLayer = true;
_bounds = bounds;
if (ctx.setup.rest())
_tileUrl = tpl;
if (styles.contains(ctx.setup.style()) || ctx.setup.style().isEmpty())
ctx.hasStyle = true;
if (formats.contains(ctx.setup.format()))
ctx.hasFormat = true;
}
}
void WMTS::contents(QXmlStreamReader &reader, CTX &ctx)
{
while (reader.readNextStartElement()) {
if (reader.name() == "TileMatrixSet")
tileMatrixSet(reader, ctx);
else if (reader.name() == "Layer")
layer(reader, ctx);
else
reader.skipCurrentElement();
}
}
void WMTS::capabilities(QXmlStreamReader &reader, CTX &ctx)
{
while (reader.readNextStartElement()) {
if (reader.name() == "Contents")
contents(reader, ctx);
else
reader.skipCurrentElement();
}
}
bool WMTS::parseCapabilities(const QString &path, const Setup &setup)
{
QFile file(path);
CTX ctx(setup);
QXmlStreamReader reader;
if (!file.open(QFile::ReadOnly | QFile::Text)) {
_errorString = file.errorString();
return false;
}
reader.setDevice(&file);
if (reader.readNextStartElement()) {
if (reader.name() == "Capabilities")
capabilities(reader, ctx);
else
reader.raiseError("Not a Capabilities XML file");
}
if (reader.error()) {
_errorString = QString("%1:%2: %3").arg(path).arg(reader.lineNumber())
.arg(reader.errorString());
return false;
}
if (!ctx.hasLayer) {
_errorString = ctx.setup.layer() + ": layer not provided";
return false;
}
if (!ctx.hasStyle) {
_errorString = ctx.setup.style() + ": style not provided";
return false;
}
if (!ctx.setup.rest() && !ctx.hasFormat) {
_errorString = ctx.setup.format() + ": format not provided";
return false;
}
if (!ctx.hasSet) {
_errorString = ctx.setup.set() + ": set not provided";
return false;
}
if (ctx.crs.isNull()) {
_errorString = "Missing CRS definition";
return false;
}
_projection = CRS::projection(ctx.crs);
if (_projection.isNull()) {
_errorString = ctx.crs + ": unknown CRS";
return false;
}
if (_matrixes.isEmpty()) {
_errorString = "No usable tile matrix found";
return false;
}
if (ctx.setup.rest() && _tileUrl.isNull()) {
_errorString = "Missing tile URL template";
return false;
}
return true;
}
bool WMTS::getCapabilities(const QString &url, const QString &file,
const Authorization &authorization)
{
QList<Download> dl;
dl.append(Download(url, file));
QEventLoop wait;
QObject::connect(_downloader, SIGNAL(finished()), &wait, SLOT(quit()));
if (_downloader->get(dl, authorization))
wait.exec();
if (QFileInfo(file).exists())
return true;
else {
_errorString = "Error downloading capabilities XML file";
return false;
}
}
WMTS::WMTS(const QString &file, const WMTS::Setup &setup) : _valid(false)
{
QString capaUrl = setup.rest() ? setup.url() :
QString("%1?service=WMTS&Version=1.0.0&request=GetCapabilities")
.arg(setup.url());
if (!QFileInfo(file).exists())
if (!getCapabilities(capaUrl, file, setup.authorization()))
return;
if (!parseCapabilities(file, setup))
return;
QString style = setup.style().isEmpty() ? "default" : setup.style();
if (!setup.rest()) {
_tileUrl = QString("%1?service=WMTS&Version=1.0.0&request=GetTile"
"&Format=%2&Layer=%3&Style=%4&TileMatrixSet=%5&TileMatrix=$z"
"&TileRow=$y&TileCol=$x").arg(setup.url(), setup.format(),
setup.layer(), style, setup.set());
for (int i = 0; i < setup.dimensions().size(); i++) {
const QPair<QString, QString> &dim = setup.dimensions().at(i);
_tileUrl.append(QString("&%1=%2").arg(dim.first, dim.second));
}
} else {
_tileUrl.replace("{Style}", style, Qt::CaseInsensitive);
_tileUrl.replace("{TileMatrixSet}", setup.set(), Qt::CaseInsensitive);
_tileUrl.replace("{TileMatrix}", "$z", Qt::CaseInsensitive);
_tileUrl.replace("{TileRow}", "$y", Qt::CaseInsensitive);
_tileUrl.replace("{TileCol}", "$x", Qt::CaseInsensitive);
for (int i = 0; i < setup.dimensions().size(); i++) {
const QPair<QString, QString> &dim = setup.dimensions().at(i);
_tileUrl.replace(QString("{%1}").arg(dim.first), dim.second,
Qt::CaseInsensitive);
}
}
_valid = true;
}
QList<WMTS::Zoom> WMTS::zooms() const
{
QList<Zoom> zooms;
QSet<TileMatrix>::const_iterator mi;
QSet<MatrixLimits>::const_iterator li;
for (mi = _matrixes.constBegin(); mi != _matrixes.constEnd(); ++mi) {
if ((li = _limits.find(MatrixLimits(mi->id))) == _limits.constEnd())
zooms.append(Zoom(mi->id, mi->scaleDenominator, mi->topLeft,
mi->tile, mi->matrix, QRect()));
else
zooms.append(Zoom(mi->id, mi->scaleDenominator, mi->topLeft,
mi->tile, mi->matrix, li->rect));
}
qSort(zooms);
return zooms;
}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const WMTS::Setup &setup)
{
dbg.nospace() << "Setup(" << setup.url() << ", " << setup.layer() << ", "
<< setup.set() << ", " << setup.style() << ", " << setup.format() << ", "
<< setup.rest() << ")";
return dbg.space();
}
QDebug operator<<(QDebug dbg, const WMTS::Zoom &zoom)
{
dbg.nospace() << "Zoom(" << zoom.id() << ", " << zoom.scaleDenominator()
<< ", " << zoom.topLeft() << ", " << zoom.tile() << ", " << zoom.matrix()
<< ", " << zoom.limits() << ")";
return dbg.space();
}
#endif // QT_NO_DEBUG

178
src/map/wmts.h Normal file
View File

@ -0,0 +1,178 @@
#ifndef WMTS_H
#define WMTS_H
#include <QSize>
#include <QRect>
#include <QSet>
#include <QList>
#include <QHash>
#include "common/rectc.h"
#include "projection.h"
#include "downloader.h"
#include "coordinatesystem.h"
class QXmlStreamReader;
class WMTS
{
public:
class Setup
{
public:
Setup(const QString &url, const QString &layer, const QString &set,
const QString &style, const QString &format, bool rest,
const CoordinateSystem &cs,
const QList<QPair<QString, QString> > &dimensions,
const Authorization &authorization = Authorization())
: _url(url), _layer(layer), _set(set), _style(style),
_format(format), _rest(rest), _cs(cs), _dimensions(dimensions),
_authorization(authorization) {}
const QString &url() const {return _url;}
const Authorization &authorization() const {return _authorization;}
const QString &layer() const {return _layer;}
const QString &set() const {return _set;}
const QString &style() const {return _style;}
const QString &format() const {return _format;}
bool rest() const {return _rest;}
const CoordinateSystem &coordinateSystem() const {return _cs;}
const QList<QPair<QString, QString> > &dimensions() const
{return _dimensions;}
private:
QString _url;
QString _layer;
QString _set;
QString _style;
QString _format;
bool _rest;
CoordinateSystem _cs;
QList<QPair<QString, QString> > _dimensions;
Authorization _authorization;
};
class Zoom
{
public:
Zoom(const QString &id, qreal scaleDenominator, const QPointF &topLeft,
const QSize &tile, const QSize &matrix, const QRect &limits) :
_id(id), _scaleDenominator(scaleDenominator), _topLeft(topLeft),
_tile(tile), _matrix(matrix), _limits(limits) {}
bool operator<(const Zoom &other) const
{return _scaleDenominator > other._scaleDenominator;}
const QString &id() const {return _id;}
qreal scaleDenominator() const {return _scaleDenominator;}
const QPointF &topLeft() const {return _topLeft;}
const QSize &tile() const {return _tile;}
const QSize &matrix() const {return _matrix;}
const QRect &limits() const {return _limits;}
private:
QString _id;
qreal _scaleDenominator;
QPointF _topLeft;
QSize _tile;
QSize _matrix;
QRect _limits;
};
WMTS(const QString &path, const Setup &setup);
const RectC &bounds() const {return _bounds;}
QList<Zoom> zooms() const;
const Projection &projection() const {return _projection;}
const QString &tileUrl() const {return _tileUrl;}
bool isValid() const {return _valid;}
const QString &errorString() const {return _errorString;}
static void setDownloader(Downloader *downloader)
{_downloader = downloader;}
private:
struct TileMatrix {
QString id;
qreal scaleDenominator;
QPointF topLeft;
QSize tile;
QSize matrix;
TileMatrix() : scaleDenominator(0) {}
bool operator==(const TileMatrix &other) const
{return this->id == other.id;}
bool isValid() const
{return !id.isEmpty() && scaleDenominator > 0 && tile.isValid()
&& matrix.isValid();}
};
struct MatrixLimits {
QString id;
QRect rect;
MatrixLimits() {}
MatrixLimits(const QString &id) : id(id) {}
bool operator==(const MatrixLimits &other) const
{return this->id == other.id;}
bool isValid() const
{return !id.isEmpty() && rect.isValid();}
};
struct CTX {
const Setup &setup;
QString crs;
bool hasLayer;
bool hasStyle;
bool hasFormat;
bool hasSet;
CTX(const Setup &setup) : setup(setup), hasLayer(false), hasStyle(false),
hasFormat(false), hasSet(false) {}
};
RectC wgs84BoundingBox(QXmlStreamReader &reader);
MatrixLimits tileMatrixLimits(QXmlStreamReader &reader);
TileMatrix tileMatrix(QXmlStreamReader &reader);
QSet<MatrixLimits> tileMatrixSetLimits(QXmlStreamReader &reader);
QString style(QXmlStreamReader &reader);
void tileMatrixSet(QXmlStreamReader &reader, CTX &ctx);
void tileMatrixSetLink(QXmlStreamReader &reader, CTX &ctx);
void layer(QXmlStreamReader &reader, CTX &ctx);
void contents(QXmlStreamReader &reader, CTX &ctx);
void capabilities(QXmlStreamReader &reader, CTX &ctx);
bool parseCapabilities(const QString &path, const Setup &setup);
bool getCapabilities(const QString &url, const QString &file,
const Authorization &authorization);
QSet<TileMatrix> _matrixes;
QSet<MatrixLimits> _limits;
RectC _bounds;
Projection _projection;
QString _tileUrl;
bool _valid;
QString _errorString;
static Downloader *_downloader;
friend uint qHash(const WMTS::TileMatrix &key);
friend uint qHash(const WMTS::MatrixLimits &key);
};
inline uint qHash(const WMTS::TileMatrix &key)
{
return ::qHash(key.id);
}
inline uint qHash(const WMTS::MatrixLimits &key)
{
return ::qHash(key.id);
}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const WMTS::Setup &setup);
QDebug operator<<(QDebug dbg, const WMTS::Zoom &zoom);
#endif // QT_NO_DEBUG
#endif // WMTS_H

215
src/map/wmtsmap.cpp Normal file
View File

@ -0,0 +1,215 @@
#include <QPainter>
#include "common/rectc.h"
#include "common/wgs84.h"
#include "config.h"
#include "transform.h"
#include "downloader.h"
#include "wmts.h"
#include "wmtsmap.h"
#define CAPABILITIES_FILE "capabilities.xml"
bool WMTSMap::loadWMTS()
{
QString file = tilesDir() + "/" + CAPABILITIES_FILE;
WMTS wmts(file, _setup);
if (!wmts.isValid()) {
_errorString = wmts.errorString();
return false;
}
_bounds = wmts.bounds();
_zooms = wmts.zooms();
_projection = wmts.projection();
_tileLoader = TileLoader(wmts.tileUrl(), tilesDir(),
_setup.authorization());
if (_setup.coordinateSystem().axisOrder() == CoordinateSystem::Unknown)
_cs = _projection.coordinateSystem();
else
_cs = _setup.coordinateSystem();
updateTransform();
return true;
}
WMTSMap::WMTSMap(const QString &name, const WMTS::Setup &setup, QObject *parent)
: Map(parent), _name(name), _setup(setup), _zoom(0), _block(false),
_valid(false)
{
if (!QDir().mkpath(tilesDir())) {
_errorString = "Error creating tiles dir";
return;
}
_valid = loadWMTS();
}
void WMTSMap::clearCache()
{
_tileLoader.clearCache();
_zoom = 0;
if (!loadWMTS())
qWarning("%s: %s\n", qPrintable(_name), qPrintable(_errorString));
}
QString WMTSMap::tilesDir() const
{
return QString(TILES_DIR + "/" + _name);
}
qreal WMTSMap::sd2res(qreal scaleDenominator) const
{
return scaleDenominator * 0.28e-3 * _projection.units().fromMeters(1.0);
}
void WMTSMap::updateTransform()
{
const WMTS::Zoom &z = _zooms.at(_zoom);
ReferencePoint tl, br;
QPointF topLeft = (_cs.axisOrder() == CoordinateSystem::YX)
? QPointF(z.topLeft().y(), z.topLeft().x()) : z.topLeft();
qreal pixelSpan = sd2res(z.scaleDenominator());
if (_projection.isGeographic())
pixelSpan /= deg2rad(WGS84_RADIUS);
QPointF tileSpan(z.tile().width() * pixelSpan, z.tile().height() * pixelSpan);
QPointF bottomRight(topLeft.x() + tileSpan.x() * z.matrix().width(),
topLeft.y() - tileSpan.y() * z.matrix().height());
tl.xy = QPoint(0, 0);
tl.pp = topLeft;
br.xy = QPoint(z.tile().width() * z.matrix().width(),
z.tile().height() * z.matrix().height());
br.pp = bottomRight;
QList<ReferencePoint> points;
points << tl << br;
_transform = Transform(points);
}
void WMTSMap::load()
{
connect(TileLoader::downloader(), SIGNAL(finished()), this,
SLOT(emitLoaded()));
}
void WMTSMap::unload()
{
disconnect(TileLoader::downloader(), SIGNAL(finished()), this,
SLOT(emitLoaded()));
}
void WMTSMap::emitLoaded()
{
emit loaded();
}
QRectF WMTSMap::bounds() const
{
const WMTS::Zoom &z = _zooms.at(_zoom);
QRectF tileBounds, bounds;
tileBounds = (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()));
bounds = _bounds.isValid() ? QRectF(ll2xy(_bounds.topLeft()),
ll2xy(_bounds.bottomRight())) : QRectF();
return _bounds.isValid() ? tileBounds.intersected(bounds) : tileBounds;
}
int WMTSMap::zoomFit(const QSize &size, const RectC &br)
{
if (br.isValid()) {
QRectF tbr(_projection.ll2xy(br.topLeft()),
_projection.ll2xy(br.bottomRight()));
QPointF sc(tbr.width() / size.width(), tbr.height() / size.height());
qreal resolution = qMax(qAbs(sc.x()), qAbs(sc.y()));
if (_projection.isGeographic())
resolution *= deg2rad(WGS84_RADIUS);
_zoom = 0;
for (int i = 0; i < _zooms.size(); i++) {
if (sd2res(_zooms.at(i).scaleDenominator()) < resolution)
break;
_zoom = i;
}
} else
_zoom = _zooms.size() - 1;
updateTransform();
return _zoom;
}
qreal WMTSMap::resolution(const QRectF &rect) const
{
Coordinates tl = xy2ll((rect.topLeft()));
Coordinates br = xy2ll(rect.bottomRight());
qreal ds = tl.distanceTo(br);
qreal ps = QLineF(rect.topLeft(), rect.bottomRight()).length();
return ds/ps;
}
int WMTSMap::zoomIn()
{
_zoom = qMin(_zoom + 1, _zooms.size() - 1);
updateTransform();
return _zoom;
}
int WMTSMap::zoomOut()
{
_zoom = qMax(_zoom - 1, 0);
updateTransform();
return _zoom;
}
void WMTSMap::draw(QPainter *painter, const QRectF &rect)
{
const WMTS::Zoom &z = _zooms.at(_zoom);
QPoint tl = QPoint((int)floor(rect.left() / (qreal)z.tile().width()),
(int)floor(rect.top() / (qreal)z.tile().height()));
QPoint br = QPoint((int)ceil(rect.right() / (qreal)z.tile().width()),
(int)ceil(rect.bottom() / (qreal)z.tile().height()));
QList<Tile> tiles;
for (int i = tl.x(); i < br.x(); i++)
for (int j = tl.y(); j < br.y(); j++)
tiles.append(Tile(QPoint(i, j), z.id()));
if (_block)
_tileLoader.loadTilesSync(tiles);
else
_tileLoader.loadTilesAsync(tiles);
for (int i = 0; i < tiles.count(); i++) {
Tile &t = tiles[i];
QPoint tp(t.xy().x() * z.tile().width(), t.xy().y() * z.tile().height());
if (t.pixmap().isNull())
painter->fillRect(QRect(tp, z.tile()), _backgroundColor);
else
painter->drawPixmap(tp, t.pixmap());
}
}
QPointF WMTSMap::ll2xy(const Coordinates &c) const
{
return _transform.proj2img(_projection.ll2xy(c));
}
Coordinates WMTSMap::xy2ll(const QPointF &p) const
{
return _projection.xy2ll(_transform.img2proj(p));
}

71
src/map/wmtsmap.h Normal file
View File

@ -0,0 +1,71 @@
#ifndef WMTSMAP_H
#define WMTSMAP_H
#include "transform.h"
#include "projection.h"
#include "map.h"
#include "wmts.h"
#include "tileloader.h"
class WMTSMap : public Map
{
Q_OBJECT
public:
WMTSMap(const QString &name, const WMTS::Setup &setup, QObject *parent = 0);
const QString &name() const {return _name;}
QRectF bounds() const;
qreal resolution(const QRectF &rect) const;
int zoom() const {return _zoom;}
int zoomFit(const QSize &size, const RectC &br);
int zoomIn();
int zoomOut();
QPointF ll2xy(const Coordinates &c)
{return static_cast<const WMTSMap &>(*this).ll2xy(c);}
Coordinates xy2ll(const QPointF &p)
{return static_cast<const WMTSMap &>(*this).xy2ll(p);}
void draw(QPainter *painter, const QRectF &rect);
void setBlockingMode(bool block) {_block = block;}
void clearCache();
void load();
void unload();
bool isValid() const {return _valid;}
QString errorString() const {return _errorString;}
private slots:
void emitLoaded();
private:
bool loadWMTS();
qreal sd2res(qreal scaleDenominator) const;
QString tilesDir() const;
void updateTransform();
QPointF ll2xy(const Coordinates &c) const;
Coordinates xy2ll(const QPointF &p) const;
QString _name;
WMTS::Setup _setup;
TileLoader _tileLoader;
RectC _bounds;
QList<WMTS::Zoom> _zooms;
Projection _projection;
Transform _transform;
CoordinateSystem _cs;
int _zoom;
bool _block;
bool _valid;
QString _errorString;
};
#endif // WMTSMAP_H