mirror of
https://github.com/tumic0/GPXSee.git
synced 2025-07-04 14:49:30 +02:00
Compare commits
152 Commits
Author | SHA1 | Date | |
---|---|---|---|
0e4a5abc2b | |||
7a2f6b96a9 | |||
24c03fc15b | |||
f9af06267a | |||
2f9751672e | |||
140e975524 | |||
e6a39b5146 | |||
937251fbdc | |||
6e92557806 | |||
a3625ac89d | |||
a7e02bdc8b | |||
ed4e201b08 | |||
06901d8d7a | |||
698f14c835 | |||
f8806417d4 | |||
52e8eb1f6e | |||
0483d393ac | |||
5aa21380cb | |||
254deae04a | |||
076a091a5b | |||
bb7787b001 | |||
bc6d48d1fe | |||
9bae94f30d | |||
351fc0309a | |||
d8116c7f5d | |||
083dd39bef | |||
bd64ca4f57 | |||
b382a5e674 | |||
20687a1df7 | |||
bb82750e9b | |||
51e6058960 | |||
db3f111815 | |||
219311577f | |||
26d4770f47 | |||
db0d9ceffb | |||
fc9b01480c | |||
cd8f415615 | |||
824393879b | |||
f79f555d6f | |||
13e9a50d59 | |||
f1667e70b5 | |||
1ce347230b | |||
d4f3e293df | |||
7492b74aed | |||
71dbb176bb | |||
301107add1 | |||
60ae4c0268 | |||
bd76e508ae | |||
e9f7642cde | |||
5c73cb55cb | |||
c39298000d | |||
e17d7d4a8f | |||
65b74b146d | |||
b937b9f2cb | |||
d7fe0fa9bf | |||
9657104f50 | |||
5a692c71a8 | |||
e8ede272ae | |||
39a8a144dd | |||
02700a485d | |||
99ea19e35a | |||
a6bb0f1520 | |||
0a74684713 | |||
332a4d9393 | |||
db98f381b5 | |||
31a600638f | |||
2ff18bc373 | |||
c2e301f4e8 | |||
a25303fe98 | |||
2bee8656a4 | |||
4a31f6f76d | |||
eaef588443 | |||
87a808265e | |||
a39cef2abd | |||
960827e92b | |||
7de1b84f77 | |||
4b1fa13429 | |||
f10857eddc | |||
781fc22113 | |||
9ced0fd3a7 | |||
3e71d1b785 | |||
491bf5614b | |||
fc873719e1 | |||
99c3edddfd | |||
fde8ad620b | |||
7855c69729 | |||
8749be9103 | |||
7432459c93 | |||
6f9f49a435 | |||
eda5046518 | |||
b867ce9a7f | |||
cfdb12c4ae | |||
9436f98023 | |||
c89137204e | |||
905f80b1ce | |||
e707cc30ad | |||
4ef1fa77f8 | |||
df104b16c6 | |||
8f9049a8d4 | |||
d483cd35cd | |||
c2b09df118 | |||
9957e1834e | |||
7e537d819a | |||
8d1be76043 | |||
b68567f000 | |||
09a5f57109 | |||
ca8ff6c7ee | |||
e9c15ef956 | |||
e39f0881ab | |||
6f05d38d31 | |||
9cb91a35ef | |||
bb0073d7e7 | |||
3291ea86ef | |||
97d646bb19 | |||
672df4255e | |||
3fcf04daf7 | |||
3daab92b84 | |||
89f384feed | |||
fc555fd7d0 | |||
d58322b412 | |||
70222f4ae2 | |||
fe1aaa73a0 | |||
57741f8c2d | |||
6eb3a4f7de | |||
295a89b3cc | |||
dc3fdc4c3b | |||
3867b723a9 | |||
d7fc400d73 | |||
f8f6859e7d | |||
2501f834c8 | |||
3f4b70ee48 | |||
384d20b1a5 | |||
b4a06057f8 | |||
9f14eb7e70 | |||
dcf1c686e5 | |||
a8d183639e | |||
d9e025a18c | |||
0a9077545b | |||
bbc1d43290 | |||
524d72ce3c | |||
9f74bbb27a | |||
ce34d449c2 | |||
21dbd3958d | |||
92ac7c0c10 | |||
1f71b3a3b2 | |||
27886ea96a | |||
3176271955 | |||
d4b46a4bb6 | |||
3b2d4dcd31 | |||
de196e8281 | |||
f376f7139b | |||
9fe10f10b8 |
@ -1,4 +1,4 @@
|
|||||||
version: 5.17.{build}
|
version: 6.2.{build}
|
||||||
configuration: Release
|
configuration: Release
|
||||||
platform: Any CPU
|
platform: Any CPU
|
||||||
environment:
|
environment:
|
||||||
|
18
README.md
18
README.md
@ -3,23 +3,29 @@ GPXSee is a Qt-based GPS log file viewer and analyzer that supports GPX, TCX,
|
|||||||
KML, FIT, IGC, NMEA, SLF, LOC and OziExplorer files.
|
KML, FIT, IGC, NMEA, SLF, LOC and OziExplorer files.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
* [User-definable online maps](https://github.com/tumic0/GPXSee-maps) (OSM/Google tiles, WMTS, WMS).
|
* User-definable online maps (OpenStreetMap/Google tiles, WMTS, WMS, TMS).
|
||||||
* Offline maps (OziExplorer maps, TrekBuddy maps/atlases, Garmin JNX maps, GeoTIFF images).
|
* Offline maps (MBTiles, OziExplorer maps, TrekBuddy maps/atlases, Garmin JNX maps, GeoTIFF images).
|
||||||
* Elevation, speed, heart rate, cadence, power, temperature and gear ratio/shifts graphs.
|
* Elevation, speed, heart rate, cadence, power, temperature and gear ratio/shifts graphs.
|
||||||
* Support for multiple tracks in one view.
|
* Support for multiple tracks in one view.
|
||||||
* Support for POI files.
|
* Support for POI files.
|
||||||
* Print/export to PDF.
|
* Print/export to PDF.
|
||||||
* Full-screen mode.
|
* Full-screen mode.
|
||||||
|
* HiDPI/Retina displays & maps support.
|
||||||
* Native GUI for Windows, Mac OS X and Linux.
|
* Native GUI for Windows, Mac OS X and Linux.
|
||||||
* Opens GPX, TCX, FIT, KML, IGC, NMEA, SLF, LOC, OziExplorer (PLT, RTE, WPT) and Garmin CSV files.
|
* Opens GPX, TCX, FIT, KML, IGC, NMEA, SLF, LOC, OziExplorer (PLT, RTE, WPT) and Garmin CSV files.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
Build requirements:
|
||||||
|
* Qt 4.8 or QT 5.x (Qt >= 5.10.1 recommended for all features)
|
||||||
|
* C++03 compiler (tested: msvc2015, gcc >= 4.8, clang/Apple LLVM version 8.1.0)
|
||||||
|
|
||||||
|
Build steps:
|
||||||
```shell
|
```shell
|
||||||
lrelease gpxsee.pro
|
lrelease gpxsee.pro
|
||||||
qmake gpxsee.pro
|
qmake gpxsee.pro
|
||||||
make
|
make # nmake on windows
|
||||||
```
|
```
|
||||||
|
|
||||||
## Download
|
## Download
|
||||||
@ -31,3 +37,9 @@ make
|
|||||||
|
|
||||||
## Homepage
|
## Homepage
|
||||||
http://www.gpxsee.org
|
http://www.gpxsee.org
|
||||||
|
|
||||||
|
## Maps
|
||||||
|
[GPXSee maps repository](https://github.com/tumic0/GPXSee-maps)
|
||||||
|
|
||||||
|
## Translations
|
||||||
|
GPXSee uses [Weblate](https://hosted.weblate.org/projects/gpxsee/translations/) for translations.
|
||||||
|
38
gpxsee.pro
38
gpxsee.pro
@ -1,9 +1,10 @@
|
|||||||
TARGET = GPXSee
|
TARGET = GPXSee
|
||||||
VERSION = 5.17
|
VERSION = 6.2
|
||||||
|
|
||||||
QT += core \
|
QT += core \
|
||||||
gui \
|
gui \
|
||||||
network
|
network \
|
||||||
|
sql
|
||||||
greaterThan(QT_MAJOR_VERSION, 4) {
|
greaterThan(QT_MAJOR_VERSION, 4) {
|
||||||
QT += widgets
|
QT += widgets
|
||||||
QT += printsupport
|
QT += printsupport
|
||||||
@ -20,6 +21,7 @@ HEADERS += src/config.h \
|
|||||||
src/common/wgs84.h \
|
src/common/wgs84.h \
|
||||||
src/common/str2int.h \
|
src/common/str2int.h \
|
||||||
src/common/rtree.h \
|
src/common/rtree.h \
|
||||||
|
src/common/kv.h \
|
||||||
src/GUI/app.h \
|
src/GUI/app.h \
|
||||||
src/GUI/icons.h \
|
src/GUI/icons.h \
|
||||||
src/GUI/gui.h \
|
src/GUI/gui.h \
|
||||||
@ -89,7 +91,7 @@ HEADERS += src/config.h \
|
|||||||
src/map/downloader.h \
|
src/map/downloader.h \
|
||||||
src/map/tile.h \
|
src/map/tile.h \
|
||||||
src/map/emptymap.h \
|
src/map/emptymap.h \
|
||||||
src/map/offlinemap.h \
|
src/map/ozimap.h \
|
||||||
src/map/tar.h \
|
src/map/tar.h \
|
||||||
src/map/ozf.h \
|
src/map/ozf.h \
|
||||||
src/map/atlas.h \
|
src/map/atlas.h \
|
||||||
@ -137,9 +139,13 @@ HEADERS += src/config.h \
|
|||||||
src/map/mercator.h \
|
src/map/mercator.h \
|
||||||
src/map/jnxmap.h \
|
src/map/jnxmap.h \
|
||||||
src/map/krovak.h \
|
src/map/krovak.h \
|
||||||
src/GUI/kv.h \
|
|
||||||
src/data/locparser.h \
|
src/data/locparser.h \
|
||||||
src/data/slfparser.h
|
src/data/slfparser.h \
|
||||||
|
src/map/geotiffmap.h \
|
||||||
|
src/map/image.h \
|
||||||
|
src/common/greatcircle.h \
|
||||||
|
src/map/mbtilesmap.h \
|
||||||
|
src/map/osm.h
|
||||||
SOURCES += src/main.cpp \
|
SOURCES += src/main.cpp \
|
||||||
src/common/coordinates.cpp \
|
src/common/coordinates.cpp \
|
||||||
src/common/rectc.cpp \
|
src/common/rectc.cpp \
|
||||||
@ -192,7 +198,7 @@ SOURCES += src/main.cpp \
|
|||||||
src/map/onlinemap.cpp \
|
src/map/onlinemap.cpp \
|
||||||
src/map/downloader.cpp \
|
src/map/downloader.cpp \
|
||||||
src/map/emptymap.cpp \
|
src/map/emptymap.cpp \
|
||||||
src/map/offlinemap.cpp \
|
src/map/ozimap.cpp \
|
||||||
src/map/tar.cpp \
|
src/map/tar.cpp \
|
||||||
src/map/atlas.cpp \
|
src/map/atlas.cpp \
|
||||||
src/map/ozf.cpp \
|
src/map/ozf.cpp \
|
||||||
@ -242,28 +248,37 @@ SOURCES += src/main.cpp \
|
|||||||
src/map/krovak.cpp \
|
src/map/krovak.cpp \
|
||||||
src/map/map.cpp \
|
src/map/map.cpp \
|
||||||
src/data/locparser.cpp \
|
src/data/locparser.cpp \
|
||||||
src/data/slfparser.cpp
|
src/data/slfparser.cpp \
|
||||||
|
src/map/geotiffmap.cpp \
|
||||||
|
src/map/image.cpp \
|
||||||
|
src/common/greatcircle.cpp \
|
||||||
|
src/map/mbtilesmap.cpp \
|
||||||
|
src/map/osm.cpp
|
||||||
|
|
||||||
RESOURCES += gpxsee.qrc
|
RESOURCES += gpxsee.qrc
|
||||||
TRANSLATIONS = lang/gpxsee_cs.ts \
|
TRANSLATIONS = lang/gpxsee_en.ts \
|
||||||
|
lang/gpxsee_cs.ts \
|
||||||
lang/gpxsee_sv.ts \
|
lang/gpxsee_sv.ts \
|
||||||
lang/gpxsee_de.ts \
|
lang/gpxsee_de.ts \
|
||||||
lang/gpxsee_ru.ts \
|
lang/gpxsee_ru.ts \
|
||||||
lang/gpxsee_fi.ts \
|
lang/gpxsee_fi.ts \
|
||||||
lang/gpxsee_fr.ts \
|
lang/gpxsee_fr.ts \
|
||||||
lang/gpxsee_pl.ts
|
lang/gpxsee_pl.ts \
|
||||||
|
lang/gpxsee_nb.ts
|
||||||
|
|
||||||
macx {
|
macx {
|
||||||
ICON = icons/gpxsee.icns
|
ICON = icons/gpxsee.icns
|
||||||
QMAKE_INFO_PLIST = pkg/Info.plist
|
QMAKE_INFO_PLIST = pkg/Info.plist
|
||||||
LOCALE.path = Contents/Resources/translations
|
LOCALE.path = Contents/Resources/translations
|
||||||
LOCALE.files = lang/gpxsee_cs.qm \
|
LOCALE.files = lang/gpxsee_en.qm \
|
||||||
|
lang/gpxsee_cs.qm \
|
||||||
lang/gpxsee_de.qm \
|
lang/gpxsee_de.qm \
|
||||||
lang/gpxsee_fi.qm \
|
lang/gpxsee_fi.qm \
|
||||||
lang/gpxsee_fr.qm \
|
lang/gpxsee_fr.qm \
|
||||||
lang/gpxsee_ru.qm \
|
lang/gpxsee_ru.qm \
|
||||||
lang/gpxsee_sv.qm \
|
lang/gpxsee_sv.qm \
|
||||||
lang/gpxsee_pl.qm
|
lang/gpxsee_pl.qm \
|
||||||
|
lang/gpxsee_nb.qm
|
||||||
CSV.path = Contents/Resources
|
CSV.path = Contents/Resources
|
||||||
CSV.files = pkg/csv
|
CSV.files = pkg/csv
|
||||||
MAPS.path = Contents/Resources
|
MAPS.path = Contents/Resources
|
||||||
@ -299,3 +314,4 @@ win32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DEFINES += APP_VERSION=\\\"$$VERSION\\\"
|
DEFINES += APP_VERSION=\\\"$$VERSION\\\"
|
||||||
|
DEFINES *= QT_USE_QSTRINGBUILDER
|
||||||
|
@ -40,5 +40,7 @@
|
|||||||
<file>icons/document-print_32@2x.png</file>
|
<file>icons/document-print_32@2x.png</file>
|
||||||
<file>icons/view-filter.png</file>
|
<file>icons/view-filter.png</file>
|
||||||
<file>icons/view-filter@2x.png</file>
|
<file>icons/view-filter@2x.png</file>
|
||||||
|
<file>icons/applications-internet_32.png</file>
|
||||||
|
<file>icons/applications-internet_32@2x.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
BIN
icons/applications-internet_32.png
Normal file
BIN
icons/applications-internet_32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
BIN
icons/applications-internet_32@2x.png
Normal file
BIN
icons/applications-internet_32@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.1 KiB |
File diff suppressed because it is too large
Load Diff
1747
lang/gpxsee_da.ts
Normal file
1747
lang/gpxsee_da.ts
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
14
lang/gpxsee_en.ts
Normal file
14
lang/gpxsee_en.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE TS>
|
||||||
|
<TS version="2.1" language="en_US">
|
||||||
|
<context>
|
||||||
|
<name>GUI</name>
|
||||||
|
<message numerus="yes">
|
||||||
|
<source>%n files</source>
|
||||||
|
<translation>
|
||||||
|
<numerusform>%n file</numerusform>
|
||||||
|
<numerusform>%n files</numerusform>
|
||||||
|
</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
</TS>
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1745
lang/gpxsee_nb.ts
Normal file
1745
lang/gpxsee_nb.ts
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -8,21 +8,23 @@
|
|||||||
<summary>GPS log file viewer and analyzer</summary>
|
<summary>GPS log file viewer and analyzer</summary>
|
||||||
<description>
|
<description>
|
||||||
<p>GPXSee is a GPS log file viewer and analyzer that supports GPX, TCX,
|
<p>GPXSee is a GPS log file viewer and analyzer that supports GPX, TCX,
|
||||||
KML, FIT, IGC, NMEA and OziExplorer files.</p>
|
KML, FIT, IGC, NMEA, SLF, LOC and OziExplorer files.</p>
|
||||||
|
|
||||||
<p>Features:</p>
|
<p>Features:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>User-definable online maps (OSM/Google tiles, WMTS, WMS).</li>
|
<li>User-definable online maps (OpenStreetMap/Google tiles, WMTS,
|
||||||
<li>Offline maps (OziExplorer maps, TrekBuddy maps/atlases, GeoTIFF
|
WMS, TMS).</li>
|
||||||
images).</li>
|
<li>Offline maps (MBTiles, OziExplorer maps, TrekBuddy maps/atlases,
|
||||||
|
GeoTIFF images).</li>
|
||||||
<li>Elevation, speed, heart rate, cadence, power and temperature
|
<li>Elevation, speed, heart rate, cadence, power and temperature
|
||||||
graphs.</li>
|
graphs.</li>
|
||||||
<li>Support for multiple tracks in one view.</li>
|
<li>Support for multiple tracks in one view.</li>
|
||||||
<li>Support for POI files.</li>
|
<li>Support for POI files.</li>
|
||||||
<li>Print/export to PDF.</li>
|
<li>Print/export to PDF.</li>
|
||||||
<li>Full-screen mode.</li>
|
<li>Full-screen mode.</li>
|
||||||
<li>Opens GPX, TCX, FIT, KML, IGC, NMEA, OziExplorer (PLT, WPT, RTE)
|
<li>HiDPI/Retina displays & maps support.</li>
|
||||||
and Garmin CSV files.</li>
|
<li>Opens GPX, TCX, FIT, KML, IGC, NMEA, SLF, LOC, OziExplorer (PLT,
|
||||||
|
WPT, RTE) and Garmin CSV files.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</description>
|
</description>
|
||||||
|
|
||||||
@ -38,6 +40,10 @@
|
|||||||
<categories>
|
<categories>
|
||||||
<category>Graphics</category>
|
<category>Graphics</category>
|
||||||
<category>Viewer</category>
|
<category>Viewer</category>
|
||||||
|
<category>Maps</category>
|
||||||
|
<category>Geoscience</category>
|
||||||
|
<category>Geography</category>
|
||||||
|
<category>DataVisualization</category>
|
||||||
</categories>
|
</categories>
|
||||||
|
|
||||||
<url type="homepage">http://www.gpxsee.org</url>
|
<url type="homepage">http://www.gpxsee.org</url>
|
||||||
@ -58,5 +64,7 @@
|
|||||||
<mimetype>application/vnd.oziexplorer.plt</mimetype>
|
<mimetype>application/vnd.oziexplorer.plt</mimetype>
|
||||||
<mimetype>application/vnd.oziexplorer.rte</mimetype>
|
<mimetype>application/vnd.oziexplorer.rte</mimetype>
|
||||||
<mimetype>application/vnd.oziexplorer.wpt</mimetype>
|
<mimetype>application/vnd.oziexplorer.wpt</mimetype>
|
||||||
|
<mimetype>application/loc+xml</mimetype>
|
||||||
|
<mimetype>application/slf+xml</mimetype>
|
||||||
</mimetypes>
|
</mimetypes>
|
||||||
</component>
|
</component>
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
; The name of the installer
|
; The name of the installer
|
||||||
Name "GPXSee"
|
Name "GPXSee"
|
||||||
; Program version
|
; Program version
|
||||||
!define VERSION "5.17"
|
!define VERSION "6.2"
|
||||||
|
|
||||||
; The file to write
|
; The file to write
|
||||||
OutFile "GPXSee-${VERSION}.exe"
|
OutFile "GPXSee-${VERSION}.exe"
|
||||||
@ -153,10 +153,12 @@ Section "QT framework" SEC_QT
|
|||||||
File "Qt5Widgets.dll"
|
File "Qt5Widgets.dll"
|
||||||
File "Qt5PrintSupport.dll"
|
File "Qt5PrintSupport.dll"
|
||||||
File "Qt5Network.dll"
|
File "Qt5Network.dll"
|
||||||
|
File "Qt5Sql.dll"
|
||||||
File /r "platforms"
|
File /r "platforms"
|
||||||
File /r "imageformats"
|
File /r "imageformats"
|
||||||
File /r "printsupport"
|
File /r "printsupport"
|
||||||
File /r "styles"
|
File /r "styles"
|
||||||
|
File /r "sqldrivers"
|
||||||
|
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
@ -204,6 +206,7 @@ SectionGroup "Localization" SEC_LOCALIZATION
|
|||||||
!insertmacro LOCALIZATION "Finnish" "fi"
|
!insertmacro LOCALIZATION "Finnish" "fi"
|
||||||
!insertmacro LOCALIZATION "French" "fr"
|
!insertmacro LOCALIZATION "French" "fr"
|
||||||
!insertmacro LOCALIZATION "German" "de"
|
!insertmacro LOCALIZATION "German" "de"
|
||||||
|
!insertmacro LOCALIZATION "Norwegian" "nb"
|
||||||
!insertmacro LOCALIZATION "Polish" "pl"
|
!insertmacro LOCALIZATION "Polish" "pl"
|
||||||
!insertmacro LOCALIZATION "Russian" "ru"
|
!insertmacro LOCALIZATION "Russian" "ru"
|
||||||
!insertmacro LOCALIZATION "Swedish" "sv"
|
!insertmacro LOCALIZATION "Swedish" "sv"
|
||||||
@ -270,4 +273,4 @@ LangString DESC_LOCALIZATION ${LANG_ENGLISH} \
|
|||||||
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_MSVC} $(DESC_MSVC)
|
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_MSVC} $(DESC_MSVC)
|
||||||
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_APP} $(DESC_APP)
|
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_APP} $(DESC_APP)
|
||||||
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_LOCALIZATION} $(DESC_LOCALIZATION)
|
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_LOCALIZATION} $(DESC_LOCALIZATION)
|
||||||
!insertmacro MUI_FUNCTION_DESCRIPTION_END
|
!insertmacro MUI_FUNCTION_DESCRIPTION_END
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
; The name of the installer
|
; The name of the installer
|
||||||
Name "GPXSee"
|
Name "GPXSee"
|
||||||
; Program version
|
; Program version
|
||||||
!define VERSION "5.17"
|
!define VERSION "6.2"
|
||||||
|
|
||||||
; The file to write
|
; The file to write
|
||||||
OutFile "GPXSee-${VERSION}_x64.exe"
|
OutFile "GPXSee-${VERSION}_x64.exe"
|
||||||
@ -160,10 +160,12 @@ Section "QT framework" SEC_QT
|
|||||||
File "Qt5Widgets.dll"
|
File "Qt5Widgets.dll"
|
||||||
File "Qt5PrintSupport.dll"
|
File "Qt5PrintSupport.dll"
|
||||||
File "Qt5Network.dll"
|
File "Qt5Network.dll"
|
||||||
|
File "Qt5Sql.dll"
|
||||||
File /r "platforms"
|
File /r "platforms"
|
||||||
File /r "imageformats"
|
File /r "imageformats"
|
||||||
File /r "printsupport"
|
File /r "printsupport"
|
||||||
File /r "styles"
|
File /r "styles"
|
||||||
|
File /r "sqldrivers"
|
||||||
|
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
@ -206,6 +208,7 @@ SectionGroup "Localization" SEC_LOCALIZATION
|
|||||||
!insertmacro LOCALIZATION "Finnish" "fi"
|
!insertmacro LOCALIZATION "Finnish" "fi"
|
||||||
!insertmacro LOCALIZATION "French" "fr"
|
!insertmacro LOCALIZATION "French" "fr"
|
||||||
!insertmacro LOCALIZATION "German" "de"
|
!insertmacro LOCALIZATION "German" "de"
|
||||||
|
!insertmacro LOCALIZATION "Norwegian" "nb"
|
||||||
!insertmacro LOCALIZATION "Polish" "pl"
|
!insertmacro LOCALIZATION "Polish" "pl"
|
||||||
!insertmacro LOCALIZATION "Russian" "ru"
|
!insertmacro LOCALIZATION "Russian" "ru"
|
||||||
!insertmacro LOCALIZATION "Swedish" "sv"
|
!insertmacro LOCALIZATION "Swedish" "sv"
|
||||||
@ -273,4 +276,4 @@ LangString DESC_LOCALIZATION ${LANG_ENGLISH} \
|
|||||||
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_MSVC} $(DESC_MSVC)
|
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_MSVC} $(DESC_MSVC)
|
||||||
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_APP} $(DESC_APP)
|
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_APP} $(DESC_APP)
|
||||||
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_LOCALIZATION} $(DESC_LOCALIZATION)
|
!insertmacro MUI_DESCRIPTION_TEXT ${SEC_LOCALIZATION} $(DESC_LOCALIZATION)
|
||||||
!insertmacro MUI_FUNCTION_DESCRIPTION_END
|
!insertmacro MUI_FUNCTION_DESCRIPTION_END
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <QNetworkProxyFactory>
|
#include <QNetworkProxyFactory>
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
#include <QLibraryInfo>
|
#include <QLibraryInfo>
|
||||||
|
#include <QSettings>
|
||||||
#include "map/downloader.h"
|
#include "map/downloader.h"
|
||||||
#include "map/ellipsoid.h"
|
#include "map/ellipsoid.h"
|
||||||
#include "map/gcs.h"
|
#include "map/gcs.h"
|
||||||
@ -12,6 +13,7 @@
|
|||||||
#include "opengl.h"
|
#include "opengl.h"
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "settings.h"
|
||||||
#include "app.h"
|
#include "app.h"
|
||||||
|
|
||||||
|
|
||||||
@ -36,7 +38,16 @@ App::App(int &argc, char **argv) : QApplication(argc, argv),
|
|||||||
#endif // Q_OS_MAC
|
#endif // Q_OS_MAC
|
||||||
|
|
||||||
QNetworkProxyFactory::setUseSystemConfiguration(true);
|
QNetworkProxyFactory::setUseSystemConfiguration(true);
|
||||||
Downloader::setNetworkAccessManager(new QNetworkAccessManager(this));
|
QSettings settings(APP_NAME, APP_NAME);
|
||||||
|
settings.beginGroup(OPTIONS_SETTINGS_GROUP);
|
||||||
|
#ifdef ENABLE_HTTP2
|
||||||
|
Downloader::enableHTTP2(settings.value(ENABLE_HTTP2_SETTING,
|
||||||
|
ENABLE_HTTP2_DEFAULT).toBool());
|
||||||
|
#endif // ENABLE_HTTP2
|
||||||
|
Downloader::setTimeout(settings.value(CONNECTION_TIMEOUT_SETTING,
|
||||||
|
CONNECTION_TIMEOUT_DEFAULT).toInt());
|
||||||
|
settings.endGroup();
|
||||||
|
|
||||||
OPENGL_SET_SAMPLES(4);
|
OPENGL_SET_SAMPLES(4);
|
||||||
loadDatums();
|
loadDatums();
|
||||||
loadPCSs();
|
loadPCSs();
|
||||||
|
@ -36,7 +36,8 @@ Ticks::Ticks(double minValue, double maxValue, int maxCount)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AxisItem::AxisItem(Type type, QGraphicsItem *parent) : QGraphicsItem(parent)
|
AxisItem::AxisItem(Type type, QGraphicsItem *parent)
|
||||||
|
: QGraphicsItem(parent), _locale(QLocale::system())
|
||||||
{
|
{
|
||||||
_type = type;
|
_type = type;
|
||||||
_size = 0;
|
_size = 0;
|
||||||
@ -56,7 +57,7 @@ void AxisItem::setRange(const RangeF &range)
|
|||||||
for (int i = 0; i < ticks.count(); i++) {
|
for (int i = 0; i < ticks.count(); i++) {
|
||||||
Tick &t = _ticks[i];
|
Tick &t = _ticks[i];
|
||||||
t.value = ticks.val(i);
|
t.value = ticks.val(i);
|
||||||
t.boundingBox = fm.tightBoundingRect(QString::number(t.value));
|
t.boundingBox = fm.tightBoundingRect(_locale.toString(t.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
updateBoundingRect();
|
updateBoundingRect();
|
||||||
@ -126,7 +127,7 @@ void AxisItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
|||||||
TICK/2, (_size/_range.size()) * (val - _range.min()), -TICK/2);
|
TICK/2, (_size/_range.size()) * (val - _range.min()), -TICK/2);
|
||||||
painter->drawText(((_size/_range.size()) * (val - _range.min()))
|
painter->drawText(((_size/_range.size()) * (val - _range.min()))
|
||||||
- (ts.width()/2), ts.height() + TICK/2 + PADDING,
|
- (ts.width()/2), ts.height() + TICK/2 + PADDING,
|
||||||
QString::number(val));
|
_locale.toString(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
painter->drawText(_size/2 - _labelBB.width()/2, _labelBB.height()
|
painter->drawText(_size/2 - _labelBB.width()/2, _labelBB.height()
|
||||||
@ -145,7 +146,7 @@ void AxisItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
|||||||
* (val - _range.min())));
|
* (val - _range.min())));
|
||||||
painter->drawText(-(ts.width() + PADDING + TICK/2),
|
painter->drawText(-(ts.width() + PADDING + TICK/2),
|
||||||
-((_size/_range.size()) * (val - _range.min())) + (ts.height()/2),
|
-((_size/_range.size()) * (val - _range.min())) + (ts.height()/2),
|
||||||
QString::number(val));
|
_locale.toString(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
painter->rotate(-90);
|
painter->rotate(-90);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <QGraphicsItem>
|
#include <QGraphicsItem>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
#include <QLocale>
|
||||||
#include "common/range.h"
|
#include "common/range.h"
|
||||||
|
|
||||||
class AxisItem : public QGraphicsItem
|
class AxisItem : public QGraphicsItem
|
||||||
@ -39,6 +40,7 @@ private:
|
|||||||
QVector<Tick> _ticks;
|
QVector<Tick> _ticks;
|
||||||
QRectF _boundingRect;
|
QRectF _boundingRect;
|
||||||
QFont _font;
|
QFont _font;
|
||||||
|
QLocale _locale;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // AXISITEM_H
|
#endif // AXISITEM_H
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include <QLocale>
|
||||||
#include "data/data.h"
|
#include "data/data.h"
|
||||||
#include "cadencegraphitem.h"
|
#include "cadencegraphitem.h"
|
||||||
#include "cadencegraph.h"
|
#include "cadencegraph.h"
|
||||||
@ -7,7 +8,7 @@ CadenceGraph::CadenceGraph(QWidget *parent) : GraphTab(parent)
|
|||||||
{
|
{
|
||||||
_showTracks = true;
|
_showTracks = true;
|
||||||
|
|
||||||
GraphView::setYUnits(tr("1/min"));
|
GraphView::setYUnits(tr("rpm"));
|
||||||
setYLabel(tr("Cadence"));
|
setYLabel(tr("Cadence"));
|
||||||
|
|
||||||
setSliderPrecision(1);
|
setSliderPrecision(1);
|
||||||
@ -16,9 +17,11 @@ CadenceGraph::CadenceGraph(QWidget *parent) : GraphTab(parent)
|
|||||||
void CadenceGraph::setInfo()
|
void CadenceGraph::setInfo()
|
||||||
{
|
{
|
||||||
if (_showTracks) {
|
if (_showTracks) {
|
||||||
GraphView::addInfo(tr("Average"), QString::number(avg() * yScale()
|
QLocale l(QLocale::system());
|
||||||
|
|
||||||
|
GraphView::addInfo(tr("Average"), l.toString(avg() * yScale()
|
||||||
+ yOffset(), 'f', 1) + UNIT_SPACE + yUnits());
|
+ yOffset(), 'f', 1) + UNIT_SPACE + yUnits());
|
||||||
GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale()
|
GraphView::addInfo(tr("Maximum"), l.toString(max() * yScale()
|
||||||
+ yOffset(), 'f', 1) + UNIT_SPACE + yUnits());
|
+ yOffset(), 'f', 1) + UNIT_SPACE + yUnits());
|
||||||
} else
|
} else
|
||||||
clearInfo();
|
clearInfo();
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
#include <QLocale>
|
||||||
#include "tooltip.h"
|
#include "tooltip.h"
|
||||||
#include "cadencegraphitem.h"
|
#include "cadencegraphitem.h"
|
||||||
|
|
||||||
|
|
||||||
CadenceGraphItem::CadenceGraphItem(const Graph &graph, GraphType type,
|
CadenceGraphItem::CadenceGraphItem(const Graph &graph, GraphType type,
|
||||||
QGraphicsItem *parent) : GraphItem(graph, type, parent)
|
QGraphicsItem *parent) : GraphItem(graph, type, parent)
|
||||||
{
|
{
|
||||||
@ -16,11 +18,12 @@ CadenceGraphItem::CadenceGraphItem(const Graph &graph, GraphType type,
|
|||||||
QString CadenceGraphItem::toolTip() const
|
QString CadenceGraphItem::toolTip() const
|
||||||
{
|
{
|
||||||
ToolTip tt;
|
ToolTip tt;
|
||||||
|
QLocale l(QLocale::system());
|
||||||
|
|
||||||
tt.insert(tr("Maximum"), QString::number(max(), 'f', 1)
|
tt.insert(tr("Maximum"), l.toString(max(), 'f', 1)
|
||||||
+ UNIT_SPACE + tr("1/min"));
|
+ UNIT_SPACE + tr("rpm"));
|
||||||
tt.insert(tr("Average"), QString::number(avg(), 'f', 1)
|
tt.insert(tr("Average"), l.toString(avg(), 'f', 1)
|
||||||
+ UNIT_SPACE + tr("1/min"));
|
+ UNIT_SPACE + tr("rpm"));
|
||||||
|
|
||||||
return tt.toString();
|
return tt.toString();
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <QLocale>
|
||||||
#include "data/data.h"
|
#include "data/data.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "tooltip.h"
|
#include "tooltip.h"
|
||||||
@ -54,13 +55,15 @@ void ElevationGraph::setInfo()
|
|||||||
if (std::isnan(max()) || std::isnan(min()))
|
if (std::isnan(max()) || std::isnan(min()))
|
||||||
clearInfo();
|
clearInfo();
|
||||||
else {
|
else {
|
||||||
GraphView::addInfo(tr("Ascent"), QString::number(ascent() * yScale(),
|
QLocale l(QLocale::system());
|
||||||
|
|
||||||
|
GraphView::addInfo(tr("Ascent"), l.toString(ascent() * yScale(),
|
||||||
'f', 0) + UNIT_SPACE + yUnits());
|
'f', 0) + UNIT_SPACE + yUnits());
|
||||||
GraphView::addInfo(tr("Descent"), QString::number(descent() * yScale(),
|
GraphView::addInfo(tr("Descent"), l.toString(descent() * yScale(),
|
||||||
'f', 0) + UNIT_SPACE + yUnits());
|
'f', 0) + UNIT_SPACE + yUnits());
|
||||||
GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale(), 'f',
|
GraphView::addInfo(tr("Maximum"), l.toString(max() * yScale(), 'f',
|
||||||
0) + UNIT_SPACE + yUnits());
|
0) + UNIT_SPACE + yUnits());
|
||||||
GraphView::addInfo(tr("Minimum"), QString::number(min() * yScale(), 'f',
|
GraphView::addInfo(tr("Minimum"), l.toString(min() * yScale(), 'f',
|
||||||
0) + UNIT_SPACE + yUnits());
|
0) + UNIT_SPACE + yUnits());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
#include <QLocale>
|
||||||
#include "tooltip.h"
|
#include "tooltip.h"
|
||||||
#include "elevationgraphitem.h"
|
#include "elevationgraphitem.h"
|
||||||
|
|
||||||
|
|
||||||
ElevationGraphItem::ElevationGraphItem(const Graph &graph, GraphType type,
|
ElevationGraphItem::ElevationGraphItem(const Graph &graph, GraphType type,
|
||||||
QGraphicsItem *parent) : GraphItem(graph, type, parent)
|
QGraphicsItem *parent) : GraphItem(graph, type, parent)
|
||||||
{
|
{
|
||||||
@ -24,14 +26,15 @@ QString ElevationGraphItem::toolTip(Units units) const
|
|||||||
ToolTip tt;
|
ToolTip tt;
|
||||||
qreal scale = (units == Metric) ? 1.0 : M2FT;
|
qreal scale = (units == Metric) ? 1.0 : M2FT;
|
||||||
QString su = (units == Metric) ? tr("m") : tr("ft");
|
QString su = (units == Metric) ? tr("m") : tr("ft");
|
||||||
|
QLocale l(QLocale::system());
|
||||||
|
|
||||||
tt.insert(tr("Ascent"), QString::number(ascent() * scale, 'f', 0)
|
tt.insert(tr("Ascent"), l.toString(ascent() * scale, 'f', 0)
|
||||||
+ UNIT_SPACE + su);
|
+ UNIT_SPACE + su);
|
||||||
tt.insert(tr("Descent"), QString::number(descent() * scale, 'f', 0)
|
tt.insert(tr("Descent"), l.toString(descent() * scale, 'f', 0)
|
||||||
+ UNIT_SPACE + su);
|
+ UNIT_SPACE + su);
|
||||||
tt.insert(tr("Maximum"), QString::number(max() * scale, 'f', 0)
|
tt.insert(tr("Maximum"), l.toString(max() * scale, 'f', 0)
|
||||||
+ UNIT_SPACE + su);
|
+ UNIT_SPACE + su);
|
||||||
tt.insert(tr("Minimum"), QString::number(min() * scale, 'f', 0)
|
tt.insert(tr("Minimum"), l.toString(min() * scale, 'f', 0)
|
||||||
+ UNIT_SPACE + su);
|
+ UNIT_SPACE + su);
|
||||||
|
|
||||||
return tt.toString();
|
return tt.toString();
|
||||||
|
@ -22,7 +22,8 @@ ExportDialog::ExportDialog(Export *exp, QWidget *parent)
|
|||||||
int index;
|
int index;
|
||||||
|
|
||||||
_fileSelect = new FileSelectWidget();
|
_fileSelect = new FileSelectWidget();
|
||||||
_fileSelect->setFilter(tr("PDF files (*.pdf);;All files (*)"));
|
_fileSelect->setFilter(tr("PDF files") + " (*.pdf);;" + tr("All files")
|
||||||
|
+ " (*)");
|
||||||
_fileSelect->setFile(_export->fileName);
|
_fileSelect->setFile(_export->fileName);
|
||||||
|
|
||||||
_paperSize = new QComboBox();
|
_paperSize = new QComboBox();
|
||||||
|
@ -46,37 +46,41 @@ QString Format::timeSpan(qreal time, bool full)
|
|||||||
|
|
||||||
QString Format::distance(qreal value, Units units)
|
QString Format::distance(qreal value, Units units)
|
||||||
{
|
{
|
||||||
|
QLocale l(QLocale::system());
|
||||||
|
|
||||||
if (units == Imperial) {
|
if (units == Imperial) {
|
||||||
if (value < MIINM)
|
if (value < MIINM)
|
||||||
return QString::number(value * M2FT, 'f', 0) + UNIT_SPACE
|
return l.toString(value * M2FT, 'f', 0) + UNIT_SPACE
|
||||||
+ qApp->translate("Format", "ft");
|
+ qApp->translate("Format", "ft");
|
||||||
else
|
else
|
||||||
return QString::number(value * M2MI, 'f', 1) + UNIT_SPACE
|
return l.toString(value * M2MI, 'f', 1) + UNIT_SPACE
|
||||||
+ qApp->translate("Format", "mi");
|
+ qApp->translate("Format", "mi");
|
||||||
} else if (units == Nautical) {
|
} else if (units == Nautical) {
|
||||||
if (value < NMIINM)
|
if (value < NMIINM)
|
||||||
return QString::number(value * M2FT, 'f', 0) + UNIT_SPACE
|
return l.toString(value * M2FT, 'f', 0) + UNIT_SPACE
|
||||||
+ qApp->translate("Format", "ft");
|
+ qApp->translate("Format", "ft");
|
||||||
else
|
else
|
||||||
return QString::number(value * M2NMI, 'f', 1) + UNIT_SPACE
|
return l.toString(value * M2NMI, 'f', 1) + UNIT_SPACE
|
||||||
+ qApp->translate("Format", "nmi");
|
+ qApp->translate("Format", "nmi");
|
||||||
} else {
|
} else {
|
||||||
if (value < KMINM)
|
if (value < KMINM)
|
||||||
return QString::number(value, 'f', 0) + UNIT_SPACE
|
return l.toString(value, 'f', 0) + UNIT_SPACE
|
||||||
+ qApp->translate("Format", "m");
|
+ qApp->translate("Format", "m");
|
||||||
else
|
else
|
||||||
return QString::number(value * M2KM, 'f', 1) + UNIT_SPACE
|
return l.toString(value * M2KM, 'f', 1) + UNIT_SPACE
|
||||||
+ qApp->translate("Format", "km");
|
+ qApp->translate("Format", "km");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Format::elevation(qreal value, Units units)
|
QString Format::elevation(qreal value, Units units)
|
||||||
{
|
{
|
||||||
|
QLocale l(QLocale::system());
|
||||||
|
|
||||||
if (units == Metric)
|
if (units == Metric)
|
||||||
return QString::number(qRound(value)) + UNIT_SPACE
|
return l.toString(qRound(value)) + UNIT_SPACE
|
||||||
+ qApp->translate("Format", "m");
|
+ qApp->translate("Format", "m");
|
||||||
else
|
else
|
||||||
return QString::number(qRound(value * M2FT)) + UNIT_SPACE
|
return l.toString(qRound(value * M2FT)) + UNIT_SPACE
|
||||||
+ qApp->translate("Format", "ft");
|
+ qApp->translate("Format", "ft");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +99,8 @@ QString Format::coordinates(const Coordinates &value, CoordinatesFormat type)
|
|||||||
+ deg2DMS(qAbs(value.lon())) + xH;
|
+ deg2DMS(qAbs(value.lon())) + xH;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return QString::number(qAbs(value.lat()), 'f', 5) + yH + ","
|
QLocale l(QLocale::system());
|
||||||
+ QChar(0x00A0) + QString::number(qAbs(value.lon()), 'f', 5) + xH;
|
return l.toString(qAbs(value.lat()), 'f', 5) + yH + ","
|
||||||
|
+ QChar(0x00A0) + l.toString(qAbs(value.lon()), 'f', 5) + xH;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include <QLocale>
|
||||||
#include "data/data.h"
|
#include "data/data.h"
|
||||||
#include "gearratiographitem.h"
|
#include "gearratiographitem.h"
|
||||||
#include "gearratiograph.h"
|
#include "gearratiograph.h"
|
||||||
@ -16,11 +17,13 @@ GearRatioGraph::GearRatioGraph(QWidget *parent) : GraphTab(parent)
|
|||||||
void GearRatioGraph::setInfo()
|
void GearRatioGraph::setInfo()
|
||||||
{
|
{
|
||||||
if (_showTracks) {
|
if (_showTracks) {
|
||||||
GraphView::addInfo(tr("Most used"), QString::number(top() * yScale(),
|
QLocale l(QLocale::system());
|
||||||
|
|
||||||
|
GraphView::addInfo(tr("Most used"), l.toString(top() * yScale(),
|
||||||
'f', 2) + UNIT_SPACE + yUnits());
|
'f', 2) + UNIT_SPACE + yUnits());
|
||||||
GraphView::addInfo(tr("Minimum"), QString::number(min() * yScale(), 'f',
|
GraphView::addInfo(tr("Minimum"), l.toString(min() * yScale(), 'f',
|
||||||
2) + UNIT_SPACE + yUnits());
|
2) + UNIT_SPACE + yUnits());
|
||||||
GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale(), 'f',
|
GraphView::addInfo(tr("Maximum"), l.toString(max() * yScale(), 'f',
|
||||||
2) + UNIT_SPACE + yUnits());
|
2) + UNIT_SPACE + yUnits());
|
||||||
} else
|
} else
|
||||||
clearInfo();
|
clearInfo();
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
#include <QMap>
|
#include <QMap>
|
||||||
|
#include <QLocale>
|
||||||
#include "tooltip.h"
|
#include "tooltip.h"
|
||||||
#include "gearratiographitem.h"
|
#include "gearratiographitem.h"
|
||||||
|
|
||||||
|
|
||||||
GearRatioGraphItem::GearRatioGraphItem(const Graph &graph, GraphType type,
|
GearRatioGraphItem::GearRatioGraphItem(const Graph &graph, GraphType type,
|
||||||
QGraphicsItem *parent) : GraphItem(graph, type, parent), _top(NAN)
|
QGraphicsItem *parent) : GraphItem(graph, type, parent), _top(NAN)
|
||||||
{
|
{
|
||||||
@ -30,10 +32,11 @@ GearRatioGraphItem::GearRatioGraphItem(const Graph &graph, GraphType type,
|
|||||||
QString GearRatioGraphItem::toolTip() const
|
QString GearRatioGraphItem::toolTip() const
|
||||||
{
|
{
|
||||||
ToolTip tt;
|
ToolTip tt;
|
||||||
|
QLocale l(QLocale::system());
|
||||||
|
|
||||||
tt.insert(tr("Minimum"), QString::number(min(), 'f', 2));
|
tt.insert(tr("Minimum"), l.toString(min(), 'f', 2));
|
||||||
tt.insert(tr("Maximum"), QString::number(max(), 'f', 2));
|
tt.insert(tr("Maximum"), l.toString(max(), 'f', 2));
|
||||||
tt.insert(tr("Most used"), QString::number(top(), 'f', 2));
|
tt.insert(tr("Most used"), l.toString(top(), 'f', 2));
|
||||||
|
|
||||||
return tt.toString();
|
return tt.toString();
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <QPaintDevice>
|
#include <QPaintDevice>
|
||||||
#include <QGraphicsSimpleTextItem>
|
#include <QGraphicsSimpleTextItem>
|
||||||
#include <QPalette>
|
#include <QPalette>
|
||||||
|
#include <QLocale>
|
||||||
#include "data/graph.h"
|
#include "data/graph.h"
|
||||||
#include "opengl.h"
|
#include "opengl.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@ -413,8 +414,10 @@ void GraphView::updateSliderPosition()
|
|||||||
|
|
||||||
void GraphView::updateSliderInfo()
|
void GraphView::updateSliderInfo()
|
||||||
{
|
{
|
||||||
|
QLocale l(QLocale::system());
|
||||||
qreal r, y;
|
qreal r, y;
|
||||||
|
|
||||||
|
|
||||||
if (_visible.count() > 1) {
|
if (_visible.count() > 1) {
|
||||||
r = 0;
|
r = 0;
|
||||||
y = 0;
|
y = 0;
|
||||||
@ -435,9 +438,9 @@ void GraphView::updateSliderInfo()
|
|||||||
_sliderInfo->setSide(s);
|
_sliderInfo->setSide(s);
|
||||||
_sliderInfo->setPos(QPointF(0, _slider->boundingRect().height() * r));
|
_sliderInfo->setPos(QPointF(0, _slider->boundingRect().height() * r));
|
||||||
_sliderInfo->setText(_graphType == Time ? Format::timeSpan(_sliderPos,
|
_sliderInfo->setText(_graphType == Time ? Format::timeSpan(_sliderPos,
|
||||||
bounds().width() > 3600) : QString::number(_sliderPos * _xScale, 'f', 1)
|
bounds().width() > 3600) : l.toString(_sliderPos * _xScale, 'f', 1)
|
||||||
+ UNIT_SPACE + _xUnits, (_visible.count() > 1) ? QString()
|
+ UNIT_SPACE + _xUnits, (_visible.count() > 1) ? QString()
|
||||||
: QString::number(-y * _yScale + _yOffset, 'f', _precision) + UNIT_SPACE
|
: l.toString(-y * _yScale + _yOffset, 'f', _precision) + UNIT_SPACE
|
||||||
+ _yUnits);
|
+ _yUnits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
115
src/GUI/gui.cpp
115
src/GUI/gui.cpp
@ -147,44 +147,47 @@ void GUI::createMapActions()
|
|||||||
_mapsActionGroup = new QActionGroup(this);
|
_mapsActionGroup = new QActionGroup(this);
|
||||||
_mapsActionGroup->setExclusive(true);
|
_mapsActionGroup->setExclusive(true);
|
||||||
|
|
||||||
for (int i = 0; i < _ml->maps().count(); i++) {
|
for (int i = 0; i < _ml->maps().count(); i++)
|
||||||
QAction *a = new QAction(_ml->maps().at(i)->name(), this);
|
createMapAction(_ml->maps().at(i));
|
||||||
a->setMenuRole(QAction::NoRole);
|
|
||||||
a->setCheckable(true);
|
|
||||||
a->setActionGroup(_mapsActionGroup);
|
|
||||||
|
|
||||||
_mapsSignalMapper->setMapping(a, i);
|
|
||||||
connect(a, SIGNAL(triggered()), _mapsSignalMapper, SLOT(map()));
|
|
||||||
|
|
||||||
_mapActions.append(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(_mapsSignalMapper, SIGNAL(mapped(int)), this,
|
connect(_mapsSignalMapper, SIGNAL(mapped(int)), this,
|
||||||
SLOT(mapChanged(int)));
|
SLOT(mapChanged(int)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QAction *GUI::createMapAction(const Map *map)
|
||||||
|
{
|
||||||
|
QAction *a = new QAction(map->name(), this);
|
||||||
|
a->setMenuRole(QAction::NoRole);
|
||||||
|
a->setCheckable(true);
|
||||||
|
a->setActionGroup(_mapsActionGroup);
|
||||||
|
|
||||||
|
_mapActions.append(a);
|
||||||
|
_mapsSignalMapper->setMapping(a, _mapActions.size() - 1);
|
||||||
|
connect(a, SIGNAL(triggered()), _mapsSignalMapper, SLOT(map()));
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
void GUI::createPOIFilesActions()
|
void GUI::createPOIFilesActions()
|
||||||
{
|
{
|
||||||
_poiFilesSignalMapper = new QSignalMapper(this);
|
_poiFilesSignalMapper = new QSignalMapper(this);
|
||||||
|
|
||||||
for (int i = 0; i < _poi->files().count(); i++)
|
for (int i = 0; i < _poi->files().count(); i++)
|
||||||
createPOIFileAction(i);
|
createPOIFileAction(_poi->files().at(i));
|
||||||
|
|
||||||
connect(_poiFilesSignalMapper, SIGNAL(mapped(int)), this,
|
connect(_poiFilesSignalMapper, SIGNAL(mapped(int)), this,
|
||||||
SLOT(poiFileChecked(int)));
|
SLOT(poiFileChecked(int)));
|
||||||
}
|
}
|
||||||
|
|
||||||
QAction *GUI::createPOIFileAction(int index)
|
QAction *GUI::createPOIFileAction(const QString &fileName)
|
||||||
{
|
{
|
||||||
QAction *a = new QAction(QFileInfo(_poi->files().at(index)).fileName(),
|
QAction *a = new QAction(QFileInfo(fileName).fileName(), this);
|
||||||
this);
|
|
||||||
a->setMenuRole(QAction::NoRole);
|
a->setMenuRole(QAction::NoRole);
|
||||||
a->setCheckable(true);
|
a->setCheckable(true);
|
||||||
|
|
||||||
_poiFilesSignalMapper->setMapping(a, index);
|
|
||||||
connect(a, SIGNAL(triggered()), _poiFilesSignalMapper, SLOT(map()));
|
|
||||||
|
|
||||||
_poiFilesActions.append(a);
|
_poiFilesActions.append(a);
|
||||||
|
_poiFilesSignalMapper->setMapping(a, _poiFilesActions.size() - 1);
|
||||||
|
connect(a, SIGNAL(triggered()), _poiFilesSignalMapper, SLOT(map()));
|
||||||
|
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
@ -838,7 +841,15 @@ bool GUI::openPOIFile(const QString &fileName)
|
|||||||
if (fileName.isEmpty() || _poi->files().contains(fileName))
|
if (fileName.isEmpty() || _poi->files().contains(fileName))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!_poi->loadFile(fileName)) {
|
if (_poi->loadFile(fileName)) {
|
||||||
|
_mapView->showPOI(true);
|
||||||
|
_showPOIAction->setChecked(true);
|
||||||
|
QAction *action = createPOIFileAction(fileName);
|
||||||
|
action->setChecked(true);
|
||||||
|
_poiFilesMenu->addAction(action);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
QString error = tr("Error loading POI file:") + "\n\n"
|
QString error = tr("Error loading POI file:") + "\n\n"
|
||||||
+ fileName + "\n\n" + _poi->errorString();
|
+ fileName + "\n\n" + _poi->errorString();
|
||||||
if (_poi->errorLine())
|
if (_poi->errorLine())
|
||||||
@ -846,14 +857,6 @@ bool GUI::openPOIFile(const QString &fileName)
|
|||||||
QMessageBox::critical(this, APP_NAME, error);
|
QMessageBox::critical(this, APP_NAME, error);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
} else {
|
|
||||||
_mapView->showPOI(true);
|
|
||||||
_showPOIAction->setChecked(true);
|
|
||||||
QAction *action = createPOIFileAction(_poi->files().indexOf(fileName));
|
|
||||||
action->setChecked(true);
|
|
||||||
_poiFilesMenu->addAction(action);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -931,6 +934,11 @@ void GUI::openOptions()
|
|||||||
if (options.enableHTTP2 != _options.enableHTTP2)
|
if (options.enableHTTP2 != _options.enableHTTP2)
|
||||||
Downloader::enableHTTP2(options.enableHTTP2);
|
Downloader::enableHTTP2(options.enableHTTP2);
|
||||||
#endif // ENABLE_HTTP2
|
#endif // ENABLE_HTTP2
|
||||||
|
#ifdef ENABLE_HIDPI
|
||||||
|
if (options.hidpiMap != _options.hidpiMap)
|
||||||
|
_mapView->setDevicePixelRatio(options.hidpiMap ? devicePixelRatioF()
|
||||||
|
: 1.0);
|
||||||
|
#endif // ENABLE_HIDPI
|
||||||
|
|
||||||
if (reload)
|
if (reload)
|
||||||
reloadFile();
|
reloadFile();
|
||||||
@ -971,6 +979,8 @@ void GUI::exportFile()
|
|||||||
|
|
||||||
void GUI::statistics()
|
void GUI::statistics()
|
||||||
{
|
{
|
||||||
|
QLocale l(QLocale::system());
|
||||||
|
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN32
|
||||||
QString text = "<style>td {white-space: pre; padding-right: 4em;}"
|
QString text = "<style>td {white-space: pre; padding-right: 4em;}"
|
||||||
"th {text-align: left; padding-top: 0.5em;}</style><table>";
|
"th {text-align: left; padding-top: 0.5em;}</style><table>";
|
||||||
@ -981,21 +991,21 @@ void GUI::statistics()
|
|||||||
|
|
||||||
if (_showTracksAction->isChecked() && _trackCount > 1)
|
if (_showTracksAction->isChecked() && _trackCount > 1)
|
||||||
text.append("<tr><td>" + tr("Tracks") + ":</td><td>"
|
text.append("<tr><td>" + tr("Tracks") + ":</td><td>"
|
||||||
+ QString::number(_trackCount) + "</td></tr>");
|
+ l.toString(_trackCount) + "</td></tr>");
|
||||||
if (_showRoutesAction->isChecked() && _routeCount > 1)
|
if (_showRoutesAction->isChecked() && _routeCount > 1)
|
||||||
text.append("<tr><td>" + tr("Routes") + ":</td><td>"
|
text.append("<tr><td>" + tr("Routes") + ":</td><td>"
|
||||||
+ QString::number(_routeCount) + "</td></tr>");
|
+ l.toString(_routeCount) + "</td></tr>");
|
||||||
if (_showWaypointsAction->isChecked() && _waypointCount > 1)
|
if (_showWaypointsAction->isChecked() && _waypointCount > 1)
|
||||||
text.append("<tr><td>" + tr("Waypoints") + ":</td><td>"
|
text.append("<tr><td>" + tr("Waypoints") + ":</td><td>"
|
||||||
+ QString::number(_waypointCount) + "</td></tr>");
|
+ l.toString(_waypointCount) + "</td></tr>");
|
||||||
|
|
||||||
if (_dateRange.first.isValid()) {
|
if (_dateRange.first.isValid()) {
|
||||||
if (_dateRange.first == _dateRange.second) {
|
if (_dateRange.first == _dateRange.second) {
|
||||||
QString format = QLocale::system().dateFormat(QLocale::LongFormat);
|
QString format = l.dateFormat(QLocale::LongFormat);
|
||||||
text.append("<tr><td>" + tr("Date") + ":</td><td>"
|
text.append("<tr><td>" + tr("Date") + ":</td><td>"
|
||||||
+ _dateRange.first.toString(format) + "</td></tr>");
|
+ _dateRange.first.toString(format) + "</td></tr>");
|
||||||
} else {
|
} else {
|
||||||
QString format = QLocale::system().dateFormat(QLocale::ShortFormat);
|
QString format = l.dateFormat(QLocale::ShortFormat);
|
||||||
text.append("<tr><td>" + tr("Date") + ":</td><td>"
|
text.append("<tr><td>" + tr("Date") + ":</td><td>"
|
||||||
+ QString("%1 - %2").arg(_dateRange.first.toString(format),
|
+ QString("%1 - %2").arg(_dateRange.first.toString(format),
|
||||||
_dateRange.second.toString(format)) + "</td></tr>");
|
_dateRange.second.toString(format)) + "</td></tr>");
|
||||||
@ -1037,6 +1047,7 @@ void GUI::statistics()
|
|||||||
|
|
||||||
void GUI::plot(QPrinter *printer)
|
void GUI::plot(QPrinter *printer)
|
||||||
{
|
{
|
||||||
|
QLocale l(QLocale::system());
|
||||||
QPainter p(printer);
|
QPainter p(printer);
|
||||||
TrackInfo info;
|
TrackInfo info;
|
||||||
qreal ih, gh, mh, ratio;
|
qreal ih, gh, mh, ratio;
|
||||||
@ -1047,19 +1058,19 @@ void GUI::plot(QPrinter *printer)
|
|||||||
|
|
||||||
if (_options.printItemCount) {
|
if (_options.printItemCount) {
|
||||||
if (_showTracksAction->isChecked() && _trackCount > 1)
|
if (_showTracksAction->isChecked() && _trackCount > 1)
|
||||||
info.insert(tr("Tracks"), QString::number(_trackCount));
|
info.insert(tr("Tracks"), l.toString(_trackCount));
|
||||||
if (_showRoutesAction->isChecked() && _routeCount > 1)
|
if (_showRoutesAction->isChecked() && _routeCount > 1)
|
||||||
info.insert(tr("Routes"), QString::number(_routeCount));
|
info.insert(tr("Routes"), l.toString(_routeCount));
|
||||||
if (_showWaypointsAction->isChecked() && _waypointCount > 1)
|
if (_showWaypointsAction->isChecked() && _waypointCount > 1)
|
||||||
info.insert(tr("Waypoints"), QString::number(_waypointCount));
|
info.insert(tr("Waypoints"), l.toString(_waypointCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_dateRange.first.isValid() && _options.printDate) {
|
if (_dateRange.first.isValid() && _options.printDate) {
|
||||||
if (_dateRange.first == _dateRange.second) {
|
if (_dateRange.first == _dateRange.second) {
|
||||||
QString format = QLocale::system().dateFormat(QLocale::LongFormat);
|
QString format = l.dateFormat(QLocale::LongFormat);
|
||||||
info.insert(tr("Date"), _dateRange.first.toString(format));
|
info.insert(tr("Date"), _dateRange.first.toString(format));
|
||||||
} else {
|
} else {
|
||||||
QString format = QLocale::system().dateFormat(QLocale::ShortFormat);
|
QString format = l.dateFormat(QLocale::ShortFormat);
|
||||||
info.insert(tr("Date"), QString("%1 - %2")
|
info.insert(tr("Date"), QString("%1 - %2")
|
||||||
.arg(_dateRange.first.toString(format),
|
.arg(_dateRange.first.toString(format),
|
||||||
_dateRange.second.toString(format)));
|
_dateRange.second.toString(format)));
|
||||||
@ -1286,18 +1297,11 @@ bool GUI::loadMap(const QString &fileName)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (_ml->loadFile(fileName)) {
|
if (_ml->loadFile(fileName)) {
|
||||||
QAction *a = new QAction(_ml->maps().last()->name(), this);
|
QAction *a = createMapAction(_ml->maps().last());
|
||||||
a->setMenuRole(QAction::NoRole);
|
|
||||||
a->setCheckable(true);
|
|
||||||
a->setActionGroup(_mapsActionGroup);
|
|
||||||
_mapsSignalMapper->setMapping(a, _ml->maps().size() - 1);
|
|
||||||
connect(a, SIGNAL(triggered()), _mapsSignalMapper, SLOT(map()));
|
|
||||||
_mapActions.append(a);
|
|
||||||
_mapMenu->insertAction(_mapsEnd, a);
|
_mapMenu->insertAction(_mapsEnd, a);
|
||||||
_showMapAction->setEnabled(true);
|
_showMapAction->setEnabled(true);
|
||||||
_clearMapCacheAction->setEnabled(true);
|
_clearMapCacheAction->setEnabled(true);
|
||||||
_mapActions.last()->trigger();
|
a->trigger();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
QString error = tr("Error loading map:") + "\n\n"
|
QString error = tr("Error loading map:") + "\n\n"
|
||||||
@ -1795,6 +1799,10 @@ void GUI::writeSettings()
|
|||||||
settings.setValue(SLIDER_COLOR_SETTING, _options.sliderColor);
|
settings.setValue(SLIDER_COLOR_SETTING, _options.sliderColor);
|
||||||
if (_options.alwaysShowMap != ALWAYS_SHOW_MAP_DEFAULT)
|
if (_options.alwaysShowMap != ALWAYS_SHOW_MAP_DEFAULT)
|
||||||
settings.setValue(ALWAYS_SHOW_MAP_SETTING, _options.alwaysShowMap);
|
settings.setValue(ALWAYS_SHOW_MAP_SETTING, _options.alwaysShowMap);
|
||||||
|
#ifdef ENABLE_HIDPI
|
||||||
|
if (_options.hidpiMap != HIDPI_MAP_DEFAULT)
|
||||||
|
settings.setValue(HIDPI_MAP_SETTING, _options.hidpiMap);
|
||||||
|
#endif // ENABLE_HIDPI
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2030,6 +2038,10 @@ void GUI::readSettings()
|
|||||||
SLIDER_COLOR_DEFAULT).value<QColor>();
|
SLIDER_COLOR_DEFAULT).value<QColor>();
|
||||||
_options.alwaysShowMap = settings.value(ALWAYS_SHOW_MAP_SETTING,
|
_options.alwaysShowMap = settings.value(ALWAYS_SHOW_MAP_SETTING,
|
||||||
ALWAYS_SHOW_MAP_DEFAULT).toBool();
|
ALWAYS_SHOW_MAP_DEFAULT).toBool();
|
||||||
|
#ifdef ENABLE_HIDPI
|
||||||
|
_options.hidpiMap = settings.value(HIDPI_MAP_SETTING, HIDPI_MAP_SETTING)
|
||||||
|
.toBool();
|
||||||
|
#endif // ENABLE_HIDPI
|
||||||
|
|
||||||
_mapView->setPalette(_options.palette);
|
_mapView->setPalette(_options.palette);
|
||||||
_mapView->setMapOpacity(_options.mapOpacity);
|
_mapView->setMapOpacity(_options.mapOpacity);
|
||||||
@ -2046,6 +2058,9 @@ void GUI::readSettings()
|
|||||||
_mapView->setMarkerColor(_options.sliderColor);
|
_mapView->setMarkerColor(_options.sliderColor);
|
||||||
if (_options.useOpenGL)
|
if (_options.useOpenGL)
|
||||||
_mapView->useOpenGL(true);
|
_mapView->useOpenGL(true);
|
||||||
|
#ifdef ENABLE_HIDPI
|
||||||
|
_mapView->setDevicePixelRatio(_options.hidpiMap ? devicePixelRatioF() : 1.0);
|
||||||
|
#endif // ENABLE_HIDPI
|
||||||
|
|
||||||
for (int i = 0; i < _tabs.count(); i++) {
|
for (int i = 0; i < _tabs.count(); i++) {
|
||||||
_tabs.at(i)->setPalette(_options.palette);
|
_tabs.at(i)->setPalette(_options.palette);
|
||||||
@ -2070,10 +2085,6 @@ void GUI::readSettings()
|
|||||||
_poi->setRadius(_options.poiRadius);
|
_poi->setRadius(_options.poiRadius);
|
||||||
|
|
||||||
QPixmapCache::setCacheLimit(_options.pixmapCache * 1024);
|
QPixmapCache::setCacheLimit(_options.pixmapCache * 1024);
|
||||||
Downloader::setTimeout(_options.connectionTimeout);
|
|
||||||
#ifdef ENABLE_HTTP2
|
|
||||||
Downloader::enableHTTP2(_options.enableHTTP2);
|
|
||||||
#endif // ENABLE_HTTP2
|
|
||||||
|
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
}
|
}
|
||||||
@ -2131,7 +2142,7 @@ void GUI::show()
|
|||||||
void GUI::screenChanged(QScreen *screen)
|
void GUI::screenChanged(QScreen *screen)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_HIDPI
|
#ifdef ENABLE_HIDPI
|
||||||
_mapView->updateDevicePixelRatio();
|
_mapView->setDevicePixelRatio(_options.hidpiMap ? devicePixelRatioF() : 1.0);
|
||||||
|
|
||||||
disconnect(SIGNAL(logicalDotsPerInchChanged(qreal)), this,
|
disconnect(SIGNAL(logicalDotsPerInchChanged(qreal)), this,
|
||||||
SLOT(logicalDotsPerInchChanged(qreal)));
|
SLOT(logicalDotsPerInchChanged(qreal)));
|
||||||
@ -2147,6 +2158,6 @@ void GUI::logicalDotsPerInchChanged(qreal dpi)
|
|||||||
Q_UNUSED(dpi)
|
Q_UNUSED(dpi)
|
||||||
|
|
||||||
#ifdef ENABLE_HIDPI
|
#ifdef ENABLE_HIDPI
|
||||||
_mapView->updateDevicePixelRatio();
|
_mapView->setDevicePixelRatio(_options.hidpiMap ? devicePixelRatioF() : 1.0);
|
||||||
#endif // ENBLE_HIDPI
|
#endif // ENBLE_HIDPI
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,8 @@ private:
|
|||||||
void closeFiles();
|
void closeFiles();
|
||||||
void plot(QPrinter *printer);
|
void plot(QPrinter *printer);
|
||||||
|
|
||||||
QAction *createPOIFileAction(int index);
|
QAction *createPOIFileAction(const QString &fileName);
|
||||||
|
QAction *createMapAction(const Map *map);
|
||||||
void createPOIFilesActions();
|
void createPOIFilesActions();
|
||||||
void createMapActions();
|
void createMapActions();
|
||||||
void createActions();
|
void createActions();
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include <QLocale>
|
||||||
#include "data/data.h"
|
#include "data/data.h"
|
||||||
#include "heartrategraphitem.h"
|
#include "heartrategraphitem.h"
|
||||||
#include "heartrategraph.h"
|
#include "heartrategraph.h"
|
||||||
@ -7,7 +8,7 @@ HeartRateGraph::HeartRateGraph(QWidget *parent) : GraphTab(parent)
|
|||||||
{
|
{
|
||||||
_showTracks = true;
|
_showTracks = true;
|
||||||
|
|
||||||
GraphView::setYUnits(tr("1/min"));
|
GraphView::setYUnits(tr("bpm"));
|
||||||
setYLabel(tr("Heart rate"));
|
setYLabel(tr("Heart rate"));
|
||||||
|
|
||||||
setSliderPrecision(0);
|
setSliderPrecision(0);
|
||||||
@ -16,9 +17,11 @@ HeartRateGraph::HeartRateGraph(QWidget *parent) : GraphTab(parent)
|
|||||||
void HeartRateGraph::setInfo()
|
void HeartRateGraph::setInfo()
|
||||||
{
|
{
|
||||||
if (_showTracks) {
|
if (_showTracks) {
|
||||||
GraphView::addInfo(tr("Average"), QString::number(avg() * yScale(), 'f',
|
QLocale l(QLocale::system());
|
||||||
|
|
||||||
|
GraphView::addInfo(tr("Average"), l.toString(avg() * yScale(), 'f',
|
||||||
0) + UNIT_SPACE + yUnits());
|
0) + UNIT_SPACE + yUnits());
|
||||||
GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale(), 'f',
|
GraphView::addInfo(tr("Maximum"), l.toString(max() * yScale(), 'f',
|
||||||
0) + UNIT_SPACE + yUnits());
|
0) + UNIT_SPACE + yUnits());
|
||||||
} else
|
} else
|
||||||
clearInfo();
|
clearInfo();
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
#include <QLocale>
|
||||||
#include "tooltip.h"
|
#include "tooltip.h"
|
||||||
#include "heartrategraphitem.h"
|
#include "heartrategraphitem.h"
|
||||||
|
|
||||||
|
|
||||||
HeartRateGraphItem::HeartRateGraphItem(const Graph &graph, GraphType type,
|
HeartRateGraphItem::HeartRateGraphItem(const Graph &graph, GraphType type,
|
||||||
QGraphicsItem *parent) : GraphItem(graph, type, parent)
|
QGraphicsItem *parent) : GraphItem(graph, type, parent)
|
||||||
{
|
{
|
||||||
@ -16,11 +18,12 @@ HeartRateGraphItem::HeartRateGraphItem(const Graph &graph, GraphType type,
|
|||||||
QString HeartRateGraphItem::toolTip() const
|
QString HeartRateGraphItem::toolTip() const
|
||||||
{
|
{
|
||||||
ToolTip tt;
|
ToolTip tt;
|
||||||
|
QLocale l(QLocale::system());
|
||||||
|
|
||||||
tt.insert(tr("Maximum"), QString::number(max(), 'f', 0)
|
tt.insert(tr("Maximum"), l.toString(max(), 'f', 0)
|
||||||
+ UNIT_SPACE + tr("1/min"));
|
+ UNIT_SPACE + tr("bpm"));
|
||||||
tt.insert(tr("Average"), QString::number(avg(), 'f', 0)
|
tt.insert(tr("Average"), l.toString(avg(), 'f', 0)
|
||||||
+ UNIT_SPACE + tr("1/min"));
|
+ UNIT_SPACE + tr("bpm"));
|
||||||
|
|
||||||
return tt.toString();
|
return tt.toString();
|
||||||
}
|
}
|
||||||
|
@ -25,5 +25,6 @@
|
|||||||
#define SYSTEM_ICON ":/icons/preferences-system.png"
|
#define SYSTEM_ICON ":/icons/preferences-system.png"
|
||||||
#define PRINT_EXPORT_ICON ":/icons/document-print_32.png"
|
#define PRINT_EXPORT_ICON ":/icons/document-print_32.png"
|
||||||
#define DATA_ICON ":/icons/view-filter.png"
|
#define DATA_ICON ":/icons/view-filter.png"
|
||||||
|
#define MAPS_ICON ":/icons/applications-internet_32.png"
|
||||||
|
|
||||||
#endif /* ICONS_H */
|
#endif /* ICONS_H */
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include <QGraphicsItem>
|
#include <QGraphicsItem>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include "kv.h"
|
#include "common/kv.h"
|
||||||
|
|
||||||
class InfoItem : public QGraphicsItem
|
class InfoItem : public QGraphicsItem
|
||||||
{
|
{
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
#define MAX_DIGITAL_ZOOM 2
|
#define MAX_DIGITAL_ZOOM 2
|
||||||
#define MIN_DIGITAL_ZOOM -3
|
#define MIN_DIGITAL_ZOOM -3
|
||||||
#define MARGIN 10.0
|
#define MARGIN 10
|
||||||
#define SCALE_OFFSET 7
|
#define SCALE_OFFSET 7
|
||||||
|
|
||||||
MapView::MapView(Map *map, POI *poi, QWidget *parent)
|
MapView::MapView(Map *map, POI *poi, QWidget *parent)
|
||||||
@ -41,10 +41,6 @@ MapView::MapView(Map *map, POI *poi, QWidget *parent)
|
|||||||
_scene->addItem(_mapScale);
|
_scene->addItem(_mapScale);
|
||||||
|
|
||||||
_map = map;
|
_map = map;
|
||||||
#ifdef ENABLE_HIDPI
|
|
||||||
_ratio = devicePixelRatioF();
|
|
||||||
_map->setDevicePixelRatio(_ratio);
|
|
||||||
#endif // ENABLE_HIDPI
|
|
||||||
_map->load();
|
_map->load();
|
||||||
connect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
|
connect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
|
||||||
|
|
||||||
@ -75,6 +71,10 @@ MapView::MapView(Map *map, POI *poi, QWidget *parent)
|
|||||||
_poiSize = 8;
|
_poiSize = 8;
|
||||||
_poiColor = Qt::black;
|
_poiColor = Qt::black;
|
||||||
|
|
||||||
|
#ifdef ENABLE_HIDPI
|
||||||
|
_ratio = 1.0;
|
||||||
|
#endif // ENABLE_HIDPI
|
||||||
|
_opengl = false;
|
||||||
_plot = false;
|
_plot = false;
|
||||||
_digitalZoom = 0;
|
_digitalZoom = 0;
|
||||||
|
|
||||||
@ -268,10 +268,10 @@ void MapView::setMap(Map *map)
|
|||||||
disconnect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
|
disconnect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
|
||||||
|
|
||||||
_map = map;
|
_map = map;
|
||||||
|
_map->load();
|
||||||
#ifdef ENABLE_HIDPI
|
#ifdef ENABLE_HIDPI
|
||||||
_map->setDevicePixelRatio(_ratio);
|
_map->setDevicePixelRatio(_ratio);
|
||||||
#endif // ENABLE_HIDPI
|
#endif // ENABLE_HIDPI
|
||||||
_map->load();
|
|
||||||
connect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
|
connect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
|
||||||
|
|
||||||
digitalZoom(0);
|
digitalZoom(0);
|
||||||
@ -765,9 +765,17 @@ void MapView::drawBackground(QPainter *painter, const QRectF &rect)
|
|||||||
|
|
||||||
if (_showMap) {
|
if (_showMap) {
|
||||||
QRectF ir = rect.intersected(_map->bounds());
|
QRectF ir = rect.intersected(_map->bounds());
|
||||||
|
Map::Flags flags = Map::NoFlags;
|
||||||
|
|
||||||
if (_opacity < 1.0)
|
if (_opacity < 1.0)
|
||||||
painter->setOpacity(_opacity);
|
painter->setOpacity(_opacity);
|
||||||
_map->draw(painter, ir, _plot);
|
|
||||||
|
if (_plot)
|
||||||
|
flags = Map::Block;
|
||||||
|
else if (_opengl)
|
||||||
|
flags = Map::OpenGL;
|
||||||
|
|
||||||
|
_map->draw(painter, ir, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -808,6 +816,8 @@ void MapView::scrollContentsBy(int dx, int dy)
|
|||||||
|
|
||||||
void MapView::useOpenGL(bool use)
|
void MapView::useOpenGL(bool use)
|
||||||
{
|
{
|
||||||
|
_opengl = use;
|
||||||
|
|
||||||
if (use)
|
if (use)
|
||||||
setViewport(new OPENGL_WIDGET);
|
setViewport(new OPENGL_WIDGET);
|
||||||
else
|
else
|
||||||
@ -834,23 +844,19 @@ void MapView::reloadMap()
|
|||||||
_scene->invalidate();
|
_scene->invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapView::updateDevicePixelRatio()
|
void MapView::setDevicePixelRatio(qreal ratio)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_HIDPI
|
#ifdef ENABLE_HIDPI
|
||||||
if (_ratio == devicePixelRatioF())
|
if (_ratio == ratio)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_ratio = devicePixelRatioF();
|
_ratio = ratio;
|
||||||
|
|
||||||
QRectF vr(mapToScene(viewport()->rect()).boundingRect()
|
QRectF vr(mapToScene(viewport()->rect()).boundingRect()
|
||||||
.intersected(_map->bounds()));
|
.intersected(_map->bounds()));
|
||||||
RectC cr(_map->xy2ll(vr.topLeft()), _map->xy2ll(vr.bottomRight()));
|
RectC cr(_map->xy2ll(vr.topLeft()), _map->xy2ll(vr.bottomRight()));
|
||||||
|
|
||||||
_map->setDevicePixelRatio(_ratio);
|
_map->setDevicePixelRatio(_ratio);
|
||||||
|
|
||||||
digitalZoom(0);
|
|
||||||
|
|
||||||
_map->zoomFit(viewport()->rect().size(), cr);
|
|
||||||
_scene->setSceneRect(_map->bounds());
|
_scene->setSceneRect(_map->bounds());
|
||||||
|
|
||||||
for (int i = 0; i < _tracks.size(); i++)
|
for (int i = 0; i < _tracks.size(); i++)
|
||||||
@ -870,5 +876,7 @@ void MapView::updateDevicePixelRatio()
|
|||||||
centerOn(nc);
|
centerOn(nc);
|
||||||
|
|
||||||
reloadMap();
|
reloadMap();
|
||||||
|
#else // ENABLE_HIDPI
|
||||||
|
Q_UNUSED(ratio);
|
||||||
#endif // ENABLE_HIDPI
|
#endif // ENABLE_HIDPI
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ public slots:
|
|||||||
void showRouteWaypoints(bool show);
|
void showRouteWaypoints(bool show);
|
||||||
void clearMapCache();
|
void clearMapCache();
|
||||||
void setCoordinatesFormat(CoordinatesFormat format);
|
void setCoordinatesFormat(CoordinatesFormat format);
|
||||||
void updateDevicePixelRatio();
|
void setDevicePixelRatio(qreal ratio);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void updatePOI();
|
void updatePOI();
|
||||||
@ -142,6 +142,7 @@ private:
|
|||||||
#ifdef ENABLE_HIDPI
|
#ifdef ENABLE_HIDPI
|
||||||
qreal _ratio;
|
qreal _ratio;
|
||||||
#endif // ENABLE_HIDPI
|
#endif // ENABLE_HIDPI
|
||||||
|
bool _opengl;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MAPVIEW_H
|
#endif // MAPVIEW_H
|
||||||
|
@ -34,26 +34,61 @@ static QFrame *line()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QWidget *OptionsDialog::createGeneralPage()
|
QWidget *OptionsDialog::createMapPage()
|
||||||
{
|
{
|
||||||
_alwaysShowMap = new QCheckBox(tr("Always show the map"));
|
_alwaysShowMap = new QCheckBox(tr("Always show the map"));
|
||||||
_alwaysShowMap->setChecked(_options->alwaysShowMap);
|
_alwaysShowMap->setChecked(_options->alwaysShowMap);
|
||||||
_alwaysShowMap->setToolTip("<p>" +
|
_alwaysShowMap->setToolTip("<p>" +
|
||||||
tr("Show the map even when no files are loaded.") + "</p>");
|
tr("Show the map even when no files are loaded.") + "</p>");
|
||||||
|
|
||||||
|
#ifdef ENABLE_HIDPI
|
||||||
|
_hidpi = new QRadioButton(tr("High-resolution"));
|
||||||
|
_lodpi = new QRadioButton(tr("Standard"));
|
||||||
|
if (_options->hidpiMap)
|
||||||
|
_hidpi->setChecked(true);
|
||||||
|
else
|
||||||
|
_lodpi->setChecked(true);
|
||||||
|
QLabel *lhi = new QLabel(tr("Non-HiDPI maps are loaded as HiDPI maps. "
|
||||||
|
"The map is sharp but map objects are small/hard to read."));
|
||||||
|
QLabel *llo = new QLabel(tr("Non-HiDPI maps are loaded such as they are. "
|
||||||
|
"Map objects have the expected size but the map is blurry."));
|
||||||
|
QFont f = lhi->font();
|
||||||
|
f.setPointSize(f.pointSize() - 1);
|
||||||
|
lhi->setWordWrap(true);
|
||||||
|
llo->setWordWrap(true);
|
||||||
|
lhi->setFont(f);
|
||||||
|
llo->setFont(f);
|
||||||
|
#endif // ENABLE_HIDPI
|
||||||
|
|
||||||
QFormLayout *showMapLayout = new QFormLayout();
|
QFormLayout *showMapLayout = new QFormLayout();
|
||||||
showMapLayout->addWidget(_alwaysShowMap);
|
showMapLayout->addWidget(_alwaysShowMap);
|
||||||
|
|
||||||
QWidget *generalTab = new QWidget();
|
QWidget *mapTab = new QWidget();
|
||||||
QVBoxLayout *generalTabLayout = new QVBoxLayout();
|
QVBoxLayout *mapTabLayout = new QVBoxLayout();
|
||||||
generalTabLayout->addLayout(showMapLayout);
|
mapTabLayout->addLayout(showMapLayout);
|
||||||
generalTabLayout->addStretch();
|
mapTabLayout->addStretch();
|
||||||
generalTab->setLayout(generalTabLayout);
|
mapTab->setLayout(mapTabLayout);
|
||||||
|
|
||||||
QTabWidget *generalPage = new QTabWidget();
|
#ifdef ENABLE_HIDPI
|
||||||
generalPage->addTab(generalTab, tr("General"));
|
QVBoxLayout *hidpiTabLayout = new QVBoxLayout();
|
||||||
|
hidpiTabLayout->addWidget(_lodpi);
|
||||||
|
hidpiTabLayout->addWidget(llo);
|
||||||
|
hidpiTabLayout->addSpacing(10);
|
||||||
|
hidpiTabLayout->addWidget(_hidpi);
|
||||||
|
hidpiTabLayout->addWidget(lhi);
|
||||||
|
hidpiTabLayout->addStretch();
|
||||||
|
|
||||||
return generalPage;
|
QWidget *hidpiTab = new QWidget();
|
||||||
|
hidpiTab->setLayout(hidpiTabLayout);
|
||||||
|
#endif // ENABLE_HIDPI
|
||||||
|
|
||||||
|
QTabWidget *mapPage = new QTabWidget();
|
||||||
|
mapPage->addTab(mapTab, tr("General"));
|
||||||
|
#ifdef ENABLE_HIDPI
|
||||||
|
mapPage->addTab(hidpiTab, tr("HiDPI display mode"));
|
||||||
|
#endif // ENABLE_HIDPI
|
||||||
|
|
||||||
|
return mapPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget *OptionsDialog::createAppearancePage()
|
QWidget *OptionsDialog::createAppearancePage()
|
||||||
@ -483,8 +518,8 @@ OptionsDialog::OptionsDialog(Options *options, QWidget *parent)
|
|||||||
: QDialog(parent), _options(options)
|
: QDialog(parent), _options(options)
|
||||||
{
|
{
|
||||||
QStackedWidget *pages = new QStackedWidget();
|
QStackedWidget *pages = new QStackedWidget();
|
||||||
pages->addWidget(createGeneralPage());
|
|
||||||
pages->addWidget(createAppearancePage());
|
pages->addWidget(createAppearancePage());
|
||||||
|
pages->addWidget(createMapPage());
|
||||||
pages->addWidget(createDataPage());
|
pages->addWidget(createDataPage());
|
||||||
pages->addWidget(createPOIPage());
|
pages->addWidget(createPOIPage());
|
||||||
pages->addWidget(createExportPage());
|
pages->addWidget(createExportPage());
|
||||||
@ -492,9 +527,9 @@ OptionsDialog::OptionsDialog(Options *options, QWidget *parent)
|
|||||||
|
|
||||||
QListWidget *menu = new QListWidget();
|
QListWidget *menu = new QListWidget();
|
||||||
menu->setIconSize(QSize(MENU_ICON_SIZE, MENU_ICON_SIZE));
|
menu->setIconSize(QSize(MENU_ICON_SIZE, MENU_ICON_SIZE));
|
||||||
new QListWidgetItem(QIcon(APP_ICON), tr("General"), menu);
|
|
||||||
new QListWidgetItem(QIcon(APPEARANCE_ICON), tr("Appearance"),
|
new QListWidgetItem(QIcon(APPEARANCE_ICON), tr("Appearance"),
|
||||||
menu);
|
menu);
|
||||||
|
new QListWidgetItem(QIcon(MAPS_ICON), tr("Maps"), menu);
|
||||||
new QListWidgetItem(QIcon(DATA_ICON), tr("Data"), menu);
|
new QListWidgetItem(QIcon(DATA_ICON), tr("Data"), menu);
|
||||||
new QListWidgetItem(QIcon(POI_ICON), tr("POI"), menu);
|
new QListWidgetItem(QIcon(POI_ICON), tr("POI"), menu);
|
||||||
new QListWidgetItem(QIcon(PRINT_EXPORT_ICON), tr("Print & Export"),
|
new QListWidgetItem(QIcon(PRINT_EXPORT_ICON), tr("Print & Export"),
|
||||||
@ -532,8 +567,6 @@ OptionsDialog::OptionsDialog(Options *options, QWidget *parent)
|
|||||||
|
|
||||||
void OptionsDialog::accept()
|
void OptionsDialog::accept()
|
||||||
{
|
{
|
||||||
_options->alwaysShowMap = _alwaysShowMap->isChecked();
|
|
||||||
|
|
||||||
_options->palette.setColor(_baseColor->color());
|
_options->palette.setColor(_baseColor->color());
|
||||||
_options->palette.setShift(_colorOffset->value());
|
_options->palette.setShift(_colorOffset->value());
|
||||||
_options->mapOpacity = _mapOpacity->value();
|
_options->mapOpacity = _mapOpacity->value();
|
||||||
@ -553,6 +586,11 @@ void OptionsDialog::accept()
|
|||||||
_options->sliderColor = _sliderColor->color();
|
_options->sliderColor = _sliderColor->color();
|
||||||
_options->graphAntiAliasing = _graphAA->isChecked();
|
_options->graphAntiAliasing = _graphAA->isChecked();
|
||||||
|
|
||||||
|
_options->alwaysShowMap = _alwaysShowMap->isChecked();
|
||||||
|
#ifdef ENABLE_HIDPI
|
||||||
|
_options->hidpiMap = _hidpi->isChecked();
|
||||||
|
#endif // ENABLE_HIDPI
|
||||||
|
|
||||||
_options->elevationFilter = _elevationFilter->value();
|
_options->elevationFilter = _elevationFilter->value();
|
||||||
_options->speedFilter = _speedFilter->value();
|
_options->speedFilter = _speedFilter->value();
|
||||||
_options->heartRateFilter = _heartRateFilter->value();
|
_options->heartRateFilter = _heartRateFilter->value();
|
||||||
|
@ -18,8 +18,6 @@ class QRadioButton;
|
|||||||
class PercentSlider;
|
class PercentSlider;
|
||||||
|
|
||||||
struct Options {
|
struct Options {
|
||||||
// General
|
|
||||||
bool alwaysShowMap;
|
|
||||||
// Appearance
|
// Appearance
|
||||||
Palette palette;
|
Palette palette;
|
||||||
int trackWidth;
|
int trackWidth;
|
||||||
@ -36,6 +34,11 @@ struct Options {
|
|||||||
bool graphAntiAliasing;
|
bool graphAntiAliasing;
|
||||||
int mapOpacity;
|
int mapOpacity;
|
||||||
QColor backgroundColor;
|
QColor backgroundColor;
|
||||||
|
// Map
|
||||||
|
bool alwaysShowMap;
|
||||||
|
#ifdef ENABLE_HIDPI
|
||||||
|
bool hidpiMap;
|
||||||
|
#endif // ENABLE_HIDPI
|
||||||
// Data
|
// Data
|
||||||
int elevationFilter;
|
int elevationFilter;
|
||||||
int speedFilter;
|
int speedFilter;
|
||||||
@ -79,7 +82,7 @@ public slots:
|
|||||||
void accept();
|
void accept();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QWidget *createGeneralPage();
|
QWidget *createMapPage();
|
||||||
QWidget *createAppearancePage();
|
QWidget *createAppearancePage();
|
||||||
QWidget *createDataPage();
|
QWidget *createDataPage();
|
||||||
QWidget *createPOIPage();
|
QWidget *createPOIPage();
|
||||||
@ -88,8 +91,6 @@ private:
|
|||||||
|
|
||||||
Options *_options;
|
Options *_options;
|
||||||
|
|
||||||
// General
|
|
||||||
QCheckBox *_alwaysShowMap;
|
|
||||||
// Appearance
|
// Appearance
|
||||||
ColorBox *_baseColor;
|
ColorBox *_baseColor;
|
||||||
QDoubleSpinBox *_colorOffset;
|
QDoubleSpinBox *_colorOffset;
|
||||||
@ -107,6 +108,12 @@ private:
|
|||||||
QSpinBox *_graphWidth;
|
QSpinBox *_graphWidth;
|
||||||
ColorBox *_sliderColor;
|
ColorBox *_sliderColor;
|
||||||
QCheckBox *_graphAA;
|
QCheckBox *_graphAA;
|
||||||
|
// Map
|
||||||
|
QCheckBox *_alwaysShowMap;
|
||||||
|
#ifdef ENABLE_HIDPI
|
||||||
|
QRadioButton *_hidpi;
|
||||||
|
QRadioButton *_lodpi;
|
||||||
|
#endif // ENABLE_HIDPI
|
||||||
// Data
|
// Data
|
||||||
OddSpinBox *_elevationFilter;
|
OddSpinBox *_elevationFilter;
|
||||||
OddSpinBox *_speedFilter;
|
OddSpinBox *_speedFilter;
|
||||||
|
@ -2,12 +2,20 @@
|
|||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QCursor>
|
#include <QCursor>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
#include "common/greatcircle.h"
|
||||||
#include "map/map.h"
|
#include "map/map.h"
|
||||||
#include "tooltip.h"
|
#include "tooltip.h"
|
||||||
#include "nicenum.h"
|
#include "nicenum.h"
|
||||||
#include "pathitem.h"
|
#include "pathitem.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define GEOGRAPHICAL_MILE 1855.3248
|
||||||
|
|
||||||
|
static unsigned segments(qreal distance)
|
||||||
|
{
|
||||||
|
return ceil(distance / GEOGRAPHICAL_MILE);
|
||||||
|
}
|
||||||
|
|
||||||
PathItem::PathItem(const Path &path, Map *map, QGraphicsItem *parent)
|
PathItem::PathItem(const Path &path, Map *map, QGraphicsItem *parent)
|
||||||
: QGraphicsObject(parent)
|
: QGraphicsObject(parent)
|
||||||
{
|
{
|
||||||
@ -21,7 +29,7 @@ PathItem::PathItem(const Path &path, Map *map, QGraphicsItem *parent)
|
|||||||
QBrush brush(Qt::SolidPattern);
|
QBrush brush(Qt::SolidPattern);
|
||||||
_pen = QPen(brush, _width);
|
_pen = QPen(brush, _width);
|
||||||
|
|
||||||
updatePainterPath(map);
|
updatePainterPath();
|
||||||
updateShape();
|
updateShape();
|
||||||
|
|
||||||
_marker = new MarkerItem(this);
|
_marker = new MarkerItem(this);
|
||||||
@ -39,13 +47,53 @@ void PathItem::updateShape()
|
|||||||
_shape = s.createStroke(_painterPath);
|
_shape = s.createStroke(_painterPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PathItem::updatePainterPath(Map *map)
|
void PathItem::addSegment(const Coordinates &c1, const Coordinates &c2)
|
||||||
|
{
|
||||||
|
if (fabs(c1.lon() - c2.lon()) > 180.0) {
|
||||||
|
QPointF p;
|
||||||
|
|
||||||
|
if (c2.lon() < 0) {
|
||||||
|
QLineF l(QPointF(c1.lon(), c1.lat()), QPointF(c2.lon() + 360,
|
||||||
|
c2.lat()));
|
||||||
|
QLineF dl(QPointF(180, -90), QPointF(180, 90));
|
||||||
|
l.intersect(dl, &p);
|
||||||
|
_painterPath.lineTo(_map->ll2xy(Coordinates(180, p.y())));
|
||||||
|
_painterPath.moveTo(_map->ll2xy(Coordinates(-180, p.y())));
|
||||||
|
} else {
|
||||||
|
QLineF l(QPointF(c1.lon(), c1.lat()), QPointF(c2.lon() - 360,
|
||||||
|
c2.lat()));
|
||||||
|
QLineF dl(QPointF(-180, -90), QPointF(-180, 90));
|
||||||
|
l.intersect(dl, &p);
|
||||||
|
_painterPath.lineTo(_map->ll2xy(Coordinates(-180, p.y())));
|
||||||
|
_painterPath.moveTo(_map->ll2xy(Coordinates(180, p.y())));
|
||||||
|
}
|
||||||
|
_painterPath.lineTo(_map->ll2xy(c2));
|
||||||
|
} else
|
||||||
|
_painterPath.lineTo(_map->ll2xy(c2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PathItem::updatePainterPath()
|
||||||
{
|
{
|
||||||
_painterPath = QPainterPath();
|
_painterPath = QPainterPath();
|
||||||
|
|
||||||
_painterPath.moveTo(map->ll2xy(_path.first().coordinates()));
|
_painterPath.moveTo(_map->ll2xy(_path.first().coordinates()));
|
||||||
for (int i = 1; i < _path.size(); i++)
|
for (int i = 1; i < _path.size(); i++) {
|
||||||
_painterPath.lineTo(map->ll2xy(_path.at(i).coordinates()));
|
const PathPoint &p1 = _path.at(i-1);
|
||||||
|
const PathPoint &p2 = _path.at(i);
|
||||||
|
unsigned n = segments(p2.distance() - p1.distance());
|
||||||
|
|
||||||
|
if (n > 1) {
|
||||||
|
GreatCircle gc(p1.coordinates(), p2.coordinates());
|
||||||
|
Coordinates last = p1.coordinates();
|
||||||
|
|
||||||
|
for (unsigned j = 1; j <= n; j++) {
|
||||||
|
Coordinates c(gc.pointAt(j/(double)n));
|
||||||
|
addSegment(last, c);
|
||||||
|
last = c;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
addSegment(p1.coordinates(), p2.coordinates());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PathItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
void PathItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
||||||
@ -70,7 +118,7 @@ void PathItem::setMap(Map *map)
|
|||||||
|
|
||||||
_map = map;
|
_map = map;
|
||||||
|
|
||||||
updatePainterPath(map);
|
updatePainterPath();
|
||||||
updateShape();
|
updateShape();
|
||||||
|
|
||||||
_marker->setPos(position(_markerDistance));
|
_marker->setPos(position(_markerDistance));
|
||||||
@ -141,19 +189,40 @@ QPointF PathItem::position(qreal x) const
|
|||||||
return _map->ll2xy(_path.at(mid).coordinates());
|
return _map->ll2xy(_path.at(mid).coordinates());
|
||||||
}
|
}
|
||||||
|
|
||||||
QLineF l;
|
Coordinates c1, c2;
|
||||||
qreal p1, p2;
|
qreal p1, p2;
|
||||||
|
|
||||||
if (_path.at(mid).distance() < x) {
|
if (_path.at(mid).distance() < x) {
|
||||||
l = QLineF(_map->ll2xy(_path.at(mid).coordinates()),
|
c1 = _path.at(mid).coordinates(); c2 = _path.at(mid+1).coordinates();
|
||||||
_map->ll2xy(_path.at(mid+1).coordinates()));
|
|
||||||
p1 = _path.at(mid).distance(); p2 = _path.at(mid+1).distance();
|
p1 = _path.at(mid).distance(); p2 = _path.at(mid+1).distance();
|
||||||
} else {
|
} else {
|
||||||
l = QLineF(_map->ll2xy(_path.at(mid-1).coordinates()),
|
c1 = _path.at(mid-1).coordinates(); c2 = _path.at(mid).coordinates();
|
||||||
_map->ll2xy(_path.at(mid).coordinates()));
|
|
||||||
p1 = _path.at(mid-1).distance(); p2 = _path.at(mid).distance();
|
p1 = _path.at(mid-1).distance(); p2 = _path.at(mid).distance();
|
||||||
}
|
}
|
||||||
|
|
||||||
return l.pointAt((x - p1) / (p2 - p1));
|
unsigned n = segments(p2 - p1);
|
||||||
|
if (n > 1) {
|
||||||
|
GreatCircle gc(c1, c2);
|
||||||
|
|
||||||
|
// Great circle point
|
||||||
|
double f = (x - p1) / (p2 - p1);
|
||||||
|
QPointF p(_map->ll2xy(gc.pointAt(f)));
|
||||||
|
|
||||||
|
// Segment line of the great circle path
|
||||||
|
double f1 = floor(n * f) / n;
|
||||||
|
double f2 = ceil(n * f) / n;
|
||||||
|
QLineF l(_map->ll2xy(gc.pointAt(f1)), _map->ll2xy(gc.pointAt(f2)));
|
||||||
|
|
||||||
|
// Project the great circle point to the segment line
|
||||||
|
QLineF u = l.unitVector();
|
||||||
|
double lambda = (u.dx() * (p.x() - l.p1().x())) + (u.dy() * (p.y()
|
||||||
|
- l.p1().y()));
|
||||||
|
return QPointF((u.dx() * lambda) + l.p1().x(), (u.dy() * lambda)
|
||||||
|
+ l.p1().y());
|
||||||
|
} else {
|
||||||
|
QLineF l(_map->ll2xy(c1), _map->ll2xy(c2));
|
||||||
|
return l.pointAt((x - p1) / (p2 - p1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PathItem::moveMarker(qreal distance)
|
void PathItem::moveMarker(qreal distance)
|
||||||
|
@ -43,8 +43,10 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QPointF position(qreal distance) const;
|
QPointF position(qreal distance) const;
|
||||||
void updatePainterPath(Map *map);
|
void updatePainterPath();
|
||||||
void updateShape();
|
void updateShape();
|
||||||
|
void addSegment(const Coordinates &c1, const Coordinates &c2);
|
||||||
|
|
||||||
|
|
||||||
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
|
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
|
||||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
|
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
#include <QSlider>
|
#include <QSlider>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
|
#include <QLocale>
|
||||||
#include "units.h"
|
#include "units.h"
|
||||||
#include "percentslider.h"
|
#include "percentslider.h"
|
||||||
|
|
||||||
|
|
||||||
static QString format(int value)
|
static QString format(int value)
|
||||||
{
|
{
|
||||||
return QString::number(value) + UNIT_SPACE + QString("%");
|
return QLocale::system().toString(value) + UNIT_SPACE + QString("%");
|
||||||
}
|
}
|
||||||
|
|
||||||
PercentSlider::PercentSlider(QWidget *parent) : QWidget(parent)
|
PercentSlider::PercentSlider(QWidget *parent) : QWidget(parent)
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include <QLocale>
|
||||||
#include "data/data.h"
|
#include "data/data.h"
|
||||||
#include "powergraphitem.h"
|
#include "powergraphitem.h"
|
||||||
#include "powergraph.h"
|
#include "powergraph.h"
|
||||||
@ -16,9 +17,11 @@ PowerGraph::PowerGraph(QWidget *parent) : GraphTab(parent)
|
|||||||
void PowerGraph::setInfo()
|
void PowerGraph::setInfo()
|
||||||
{
|
{
|
||||||
if (_showTracks) {
|
if (_showTracks) {
|
||||||
GraphView::addInfo(tr("Average"), QString::number(avg() * yScale()
|
QLocale l(QLocale::system());
|
||||||
|
|
||||||
|
GraphView::addInfo(tr("Average"), l.toString(avg() * yScale()
|
||||||
+ yOffset(), 'f', 1) + UNIT_SPACE + yUnits());
|
+ yOffset(), 'f', 1) + UNIT_SPACE + yUnits());
|
||||||
GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale()
|
GraphView::addInfo(tr("Maximum"), l.toString(max() * yScale()
|
||||||
+ yOffset(), 'f', 1) + UNIT_SPACE + yUnits());
|
+ yOffset(), 'f', 1) + UNIT_SPACE + yUnits());
|
||||||
} else
|
} else
|
||||||
clearInfo();
|
clearInfo();
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
#include <QLocale>
|
||||||
#include "tooltip.h"
|
#include "tooltip.h"
|
||||||
#include "powergraphitem.h"
|
#include "powergraphitem.h"
|
||||||
|
|
||||||
|
|
||||||
PowerGraphItem::PowerGraphItem(const Graph &graph, GraphType type,
|
PowerGraphItem::PowerGraphItem(const Graph &graph, GraphType type,
|
||||||
QGraphicsItem *parent) : GraphItem(graph, type, parent)
|
QGraphicsItem *parent) : GraphItem(graph, type, parent)
|
||||||
{
|
{
|
||||||
@ -16,11 +18,12 @@ PowerGraphItem::PowerGraphItem(const Graph &graph, GraphType type,
|
|||||||
QString PowerGraphItem::toolTip() const
|
QString PowerGraphItem::toolTip() const
|
||||||
{
|
{
|
||||||
ToolTip tt;
|
ToolTip tt;
|
||||||
|
QLocale l(QLocale::system());
|
||||||
|
|
||||||
tt.insert(tr("Maximum"), QString::number(max(), 'f', 1)
|
tt.insert(tr("Maximum"), l.toString(max(), 'f', 1)
|
||||||
+ UNIT_SPACE + tr("1/min"));
|
+ UNIT_SPACE + tr("W"));
|
||||||
tt.insert(tr("Average"), QString::number(avg(), 'f', 1)
|
tt.insert(tr("Average"), l.toString(avg(), 'f', 1)
|
||||||
+ UNIT_SPACE + tr("1/min"));
|
+ UNIT_SPACE + tr("W"));
|
||||||
|
|
||||||
return tt.toString();
|
return tt.toString();
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#define BORDER_WIDTH 1
|
#define BORDER_WIDTH 1
|
||||||
#define SCALE_WIDTH 132
|
#define SCALE_WIDTH 135
|
||||||
#define SCALE_HEIGHT 5
|
#define SCALE_HEIGHT 5
|
||||||
#define SEGMENTS 3
|
#define SEGMENTS 3
|
||||||
#define PADDING 4
|
#define PADDING 4
|
||||||
|
@ -156,5 +156,7 @@
|
|||||||
#define SLIDER_COLOR_DEFAULT QColor(Qt::red)
|
#define SLIDER_COLOR_DEFAULT QColor(Qt::red)
|
||||||
#define ALWAYS_SHOW_MAP_SETTING "alwaysShowMap"
|
#define ALWAYS_SHOW_MAP_SETTING "alwaysShowMap"
|
||||||
#define ALWAYS_SHOW_MAP_DEFAULT true
|
#define ALWAYS_SHOW_MAP_DEFAULT true
|
||||||
|
#define HIDPI_MAP_SETTING "HiDPIMap"
|
||||||
|
#define HIDPI_MAP_DEFAULT true
|
||||||
|
|
||||||
#endif // SETTINGS_H
|
#endif // SETTINGS_H
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include <QLocale>
|
||||||
#include "data/data.h"
|
#include "data/data.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "tooltip.h"
|
#include "tooltip.h"
|
||||||
@ -21,13 +22,14 @@ SpeedGraph::SpeedGraph(QWidget *parent) : GraphTab(parent)
|
|||||||
void SpeedGraph::setInfo()
|
void SpeedGraph::setInfo()
|
||||||
{
|
{
|
||||||
if (_showTracks) {
|
if (_showTracks) {
|
||||||
|
QLocale l(QLocale::system());
|
||||||
QString pace = Format::timeSpan((3600.0 / (avg() * yScale())), false);
|
QString pace = Format::timeSpan((3600.0 / (avg() * yScale())), false);
|
||||||
QString pu = (_units == Metric) ? tr("min/km") : (_units == Imperial) ?
|
QString pu = (_units == Metric) ? tr("min/km") : (_units == Imperial) ?
|
||||||
tr("min/mi") : tr("min/nmi");
|
tr("min/mi") : tr("min/nmi");
|
||||||
|
|
||||||
GraphView::addInfo(tr("Average"), QString::number(avg() * yScale(), 'f',
|
GraphView::addInfo(tr("Average"), l.toString(avg() * yScale(), 'f',
|
||||||
1) + UNIT_SPACE + yUnits());
|
1) + UNIT_SPACE + yUnits());
|
||||||
GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale(), 'f',
|
GraphView::addInfo(tr("Maximum"), l.toString(max() * yScale(), 'f',
|
||||||
1) + UNIT_SPACE + yUnits());
|
1) + UNIT_SPACE + yUnits());
|
||||||
GraphView::addInfo(tr("Pace"), pace + UNIT_SPACE + pu);
|
GraphView::addInfo(tr("Pace"), pace + UNIT_SPACE + pu);
|
||||||
} else
|
} else
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
|
#include <QLocale>
|
||||||
#include "tooltip.h"
|
#include "tooltip.h"
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
#include "speedgraphitem.h"
|
#include "speedgraphitem.h"
|
||||||
|
|
||||||
|
|
||||||
SpeedGraphItem::SpeedGraphItem(const Graph &graph, GraphType type,
|
SpeedGraphItem::SpeedGraphItem(const Graph &graph, GraphType type,
|
||||||
qreal movingTime, QGraphicsItem *parent) : GraphItem(graph, type, parent)
|
qreal movingTime, QGraphicsItem *parent) : GraphItem(graph, type, parent)
|
||||||
{
|
{
|
||||||
@ -25,10 +27,11 @@ QString SpeedGraphItem::toolTip() const
|
|||||||
? avg() * scale : mavg() * scale)), false);
|
? avg() * scale : mavg() * scale)), false);
|
||||||
QString pu = (_units == Metric) ? tr("min/km") : (_units == Imperial) ?
|
QString pu = (_units == Metric) ? tr("min/km") : (_units == Imperial) ?
|
||||||
tr("min/mi") : tr("min/nmi");
|
tr("min/mi") : tr("min/nmi");
|
||||||
|
QLocale l(QLocale::system());
|
||||||
|
|
||||||
tt.insert(tr("Maximum"), QString::number(max() * scale, 'f', 1)
|
tt.insert(tr("Maximum"), l.toString(max() * scale, 'f', 1)
|
||||||
+ UNIT_SPACE + su);
|
+ UNIT_SPACE + su);
|
||||||
tt.insert(tr("Average"), QString::number((_timeType == Total)
|
tt.insert(tr("Average"), l.toString((_timeType == Total)
|
||||||
? avg() * scale : mavg() * scale, 'f', 1) + UNIT_SPACE + su);
|
? avg() * scale : mavg() * scale, 'f', 1) + UNIT_SPACE + su);
|
||||||
tt.insert(tr("Pace"), pace + UNIT_SPACE + pu);
|
tt.insert(tr("Pace"), pace + UNIT_SPACE + pu);
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include <QLocale>
|
||||||
#include "data/data.h"
|
#include "data/data.h"
|
||||||
#include "temperaturegraphitem.h"
|
#include "temperaturegraphitem.h"
|
||||||
#include "temperaturegraph.h"
|
#include "temperaturegraph.h"
|
||||||
@ -16,11 +17,13 @@ TemperatureGraph::TemperatureGraph(QWidget *parent) : GraphTab(parent)
|
|||||||
void TemperatureGraph::setInfo()
|
void TemperatureGraph::setInfo()
|
||||||
{
|
{
|
||||||
if (_showTracks) {
|
if (_showTracks) {
|
||||||
GraphView::addInfo(tr("Average"), QString::number(avg() * yScale()
|
QLocale l(QLocale::system());
|
||||||
|
|
||||||
|
GraphView::addInfo(tr("Average"), l.toString(avg() * yScale()
|
||||||
+ yOffset(), 'f', 1) + UNIT_SPACE + yUnits());
|
+ yOffset(), 'f', 1) + UNIT_SPACE + yUnits());
|
||||||
GraphView::addInfo(tr("Minimum"), QString::number(min() * yScale()
|
GraphView::addInfo(tr("Minimum"), l.toString(min() * yScale()
|
||||||
+ yOffset(), 'f', 1) + UNIT_SPACE + yUnits());
|
+ yOffset(), 'f', 1) + UNIT_SPACE + yUnits());
|
||||||
GraphView::addInfo(tr("Maximum"), QString::number(max() * yScale()
|
GraphView::addInfo(tr("Maximum"), l.toString(max() * yScale()
|
||||||
+ yOffset(), 'f', 1) + UNIT_SPACE + yUnits());
|
+ yOffset(), 'f', 1) + UNIT_SPACE + yUnits());
|
||||||
} else
|
} else
|
||||||
clearInfo();
|
clearInfo();
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
#include <QLocale>
|
||||||
#include "tooltip.h"
|
#include "tooltip.h"
|
||||||
#include "temperaturegraphitem.h"
|
#include "temperaturegraphitem.h"
|
||||||
|
|
||||||
|
|
||||||
TemperatureGraphItem::TemperatureGraphItem(const Graph &graph, GraphType type,
|
TemperatureGraphItem::TemperatureGraphItem(const Graph &graph, GraphType type,
|
||||||
QGraphicsItem *parent) : GraphItem(graph, type, parent)
|
QGraphicsItem *parent) : GraphItem(graph, type, parent)
|
||||||
{
|
{
|
||||||
@ -20,12 +22,13 @@ QString TemperatureGraphItem::toolTip(Units units) const
|
|||||||
qreal offset = (units == Metric) ? 0 : C2FO;
|
qreal offset = (units == Metric) ? 0 : C2FO;
|
||||||
QString su = (units == Metric) ?
|
QString su = (units == Metric) ?
|
||||||
QChar(0x00B0) + tr("C") : QChar(0x00B0) + tr("F");
|
QChar(0x00B0) + tr("C") : QChar(0x00B0) + tr("F");
|
||||||
|
QLocale l(QLocale::system());
|
||||||
|
|
||||||
tt.insert(tr("Average"), QString::number(avg() * scale + offset, 'f', 1)
|
tt.insert(tr("Average"), l.toString(avg() * scale + offset, 'f', 1)
|
||||||
+ UNIT_SPACE + su);
|
+ UNIT_SPACE + su);
|
||||||
tt.insert(tr("Maximum"), QString::number(max() * scale + offset, 'f', 1)
|
tt.insert(tr("Maximum"), l.toString(max() * scale + offset, 'f', 1)
|
||||||
+ UNIT_SPACE + su);
|
+ UNIT_SPACE + su);
|
||||||
tt.insert(tr("Minimum"), QString::number(min() * scale + offset, 'f', 1)
|
tt.insert(tr("Minimum"), l.toString(min() * scale + offset, 'f', 1)
|
||||||
+ UNIT_SPACE + su);
|
+ UNIT_SPACE + su);
|
||||||
|
|
||||||
return tt.toString();
|
return tt.toString();
|
||||||
|
@ -2,8 +2,7 @@
|
|||||||
|
|
||||||
void ToolTip::insert(const QString &key, const QString &value)
|
void ToolTip::insert(const QString &key, const QString &value)
|
||||||
{
|
{
|
||||||
QPair<QString, QString> entry(key, value);
|
_list.append(KV(key, value));
|
||||||
_list.append(entry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ToolTip::toString()
|
QString ToolTip::toString()
|
||||||
@ -11,8 +10,8 @@ QString ToolTip::toString()
|
|||||||
QString ret = "<table>";
|
QString ret = "<table>";
|
||||||
|
|
||||||
for (int i = 0; i < _list.count(); i++)
|
for (int i = 0; i < _list.count(); i++)
|
||||||
ret += "<tr><td align=\"right\"><b>" + _list.at(i).first
|
ret += "<tr><td align=\"right\"><b>" + _list.at(i).key()
|
||||||
+ ": </b></td><td>" + _list.at(i).second + "</td></tr>";
|
+ ": </b></td><td>" + _list.at(i).value() + "</td></tr>";
|
||||||
|
|
||||||
ret += "</table>";
|
ret += "</table>";
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QPair>
|
#include "common/kv.h"
|
||||||
|
|
||||||
class ToolTip
|
class ToolTip
|
||||||
{
|
{
|
||||||
@ -12,7 +12,7 @@ public:
|
|||||||
QString toString();
|
QString toString();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<QPair<QString, QString> > _list;
|
QList<KV> _list;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TOOLTIP_H
|
#endif // TOOLTIP_H
|
||||||
|
@ -32,6 +32,8 @@ private:
|
|||||||
double _lat, _lon;
|
double _lat, _lon;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_TYPEINFO(Coordinates, Q_PRIMITIVE_TYPE);
|
||||||
|
|
||||||
inline bool operator==(const Coordinates &c1, const Coordinates &c2)
|
inline bool operator==(const Coordinates &c1, const Coordinates &c2)
|
||||||
{return (c1.lat() == c2.lat() && c1.lon() == c2.lon());}
|
{return (c1.lat() == c2.lat() && c1.lon() == c2.lon());}
|
||||||
inline bool operator!=(const Coordinates &c1, const Coordinates &c2)
|
inline bool operator!=(const Coordinates &c1, const Coordinates &c2)
|
||||||
|
34
src/common/greatcircle.cpp
Normal file
34
src/common/greatcircle.cpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#include "greatcircle.h"
|
||||||
|
|
||||||
|
GreatCircle::GreatCircle(const Coordinates &c1, const Coordinates &c2)
|
||||||
|
{
|
||||||
|
double lat1 = deg2rad(c1.lat());
|
||||||
|
double lon1 = deg2rad(c1.lon());
|
||||||
|
double lat2 = deg2rad(c2.lat());
|
||||||
|
double lon2 = deg2rad(c2.lon());
|
||||||
|
|
||||||
|
double cosLat1 = cos(lat1);
|
||||||
|
double cosLat2 = cos(lat2);
|
||||||
|
_sinLat1 = sin(lat1);
|
||||||
|
_sinLat2 = sin(lat2);
|
||||||
|
|
||||||
|
_xA = cosLat1 * cos(lon1);
|
||||||
|
_xB = cosLat2 * cos(lon2);
|
||||||
|
_yA = cosLat1 * sin(lon1);
|
||||||
|
_yB = cosLat2 * sin(lon2);
|
||||||
|
|
||||||
|
_d = 2 * asin(sqrt(pow((sin((lat1 - lat2) / 2)), 2) + cosLat1 * cosLat2
|
||||||
|
* pow(sin((lon1 - lon2) / 2), 2)));
|
||||||
|
_sinD = sin(_d);
|
||||||
|
}
|
||||||
|
|
||||||
|
Coordinates GreatCircle::pointAt(double f) const
|
||||||
|
{
|
||||||
|
double A = sin((1.0 - f) * _d) / _sinD;
|
||||||
|
double B = sin(f * _d) / _sinD;
|
||||||
|
double x = A * _xA + B * _xB;
|
||||||
|
double y = A * _yA + B * _yB;
|
||||||
|
double z = A * _sinLat1 + B * _sinLat2;
|
||||||
|
|
||||||
|
return Coordinates(rad2deg(atan2(y, x)), rad2deg(atan2(z, sqrt(x*x + y*y))));
|
||||||
|
}
|
20
src/common/greatcircle.h
Normal file
20
src/common/greatcircle.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#ifndef GREATCIRCLE_H
|
||||||
|
#define GREATCIRCLE_H
|
||||||
|
|
||||||
|
#include "coordinates.h"
|
||||||
|
|
||||||
|
class GreatCircle
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GreatCircle(const Coordinates &c1, const Coordinates &c2);
|
||||||
|
|
||||||
|
Coordinates pointAt(double f) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
double _xA, _xB, _yA, _yB;
|
||||||
|
double _d;
|
||||||
|
double _sinD;
|
||||||
|
double _sinLat1, _sinLat2;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // GREATCIRCLE_H
|
@ -8,7 +8,7 @@ class Range
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Range() {_min = 0; _max = 0;}
|
Range() {_min = 0; _max = 0;}
|
||||||
Range(int min, int max) {_min = min, _max = max;}
|
Range(int min, int max) : _min(min), _max(max) {}
|
||||||
|
|
||||||
int min() const {return _min;}
|
int min() const {return _min;}
|
||||||
int max() const {return _max;}
|
int max() const {return _max;}
|
||||||
@ -19,6 +19,8 @@ public:
|
|||||||
void setMin(int min) {_min = min;}
|
void setMin(int min) {_min = min;}
|
||||||
void setMax(int max) {_max = max;}
|
void setMax(int max) {_max = max;}
|
||||||
|
|
||||||
|
bool contains(int val) const {return (val >= _min && val <= _max);}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int _min, _max;
|
int _min, _max;
|
||||||
};
|
};
|
||||||
@ -27,7 +29,7 @@ class RangeF
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RangeF() {_min = 0; _max = 0;}
|
RangeF() {_min = 0; _max = 0;}
|
||||||
RangeF(qreal min, qreal max) {_min = min, _max = max;}
|
RangeF(qreal min, qreal max) : _min(min), _max(max) {}
|
||||||
|
|
||||||
RangeF operator&(const RangeF &r) const;
|
RangeF operator&(const RangeF &r) const;
|
||||||
RangeF &operator&=(const RangeF &r) {*this = *this & r; return *this;}
|
RangeF &operator&=(const RangeF &r) {*this = *this & r; return *this;}
|
||||||
|
@ -23,6 +23,11 @@ public:
|
|||||||
{return Coordinates((_tl.lon() + _br.lon()) / 2.0,
|
{return Coordinates((_tl.lon() + _br.lon()) / 2.0,
|
||||||
(_tl.lat() + _br.lat()) / 2.0);}
|
(_tl.lat() + _br.lat()) / 2.0);}
|
||||||
|
|
||||||
|
double top() const {return _tl.lat();}
|
||||||
|
double bottom() const {return _br.lat();}
|
||||||
|
double left() const {return _tl.lon();}
|
||||||
|
double right() const {return _br.lon();}
|
||||||
|
|
||||||
RectC operator|(const RectC &r) const;
|
RectC operator|(const RectC &r) const;
|
||||||
RectC &operator|=(const RectC &r) {*this = *this | r; return *this;}
|
RectC &operator|=(const RectC &r) {*this = *this | r; return *this;}
|
||||||
RectC operator&(const RectC &r) const;
|
RectC operator&(const RectC &r) const;
|
||||||
|
@ -18,16 +18,16 @@ bool CSVParser::parse(QFile *file, QList<TrackData> &tracks,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
qreal lat = list[0].trimmed().toDouble(&res);
|
qreal lon = list[0].trimmed().toDouble(&res);
|
||||||
if (!res || (lat < -90.0 || lat > 90.0)) {
|
|
||||||
_errorString = "Invalid latitude";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
qreal lon = list[1].trimmed().toDouble(&res);
|
|
||||||
if (!res || (lon < -180.0 || lon > 180.0)) {
|
if (!res || (lon < -180.0 || lon > 180.0)) {
|
||||||
_errorString = "Invalid longitude";
|
_errorString = "Invalid longitude";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
qreal lat = list[1].trimmed().toDouble(&res);
|
||||||
|
if (!res || (lat < -90.0 || lat > 90.0)) {
|
||||||
|
_errorString = "Invalid latitude";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Waypoint wp(Coordinates(lon, lat));
|
Waypoint wp(Coordinates(lon, lat));
|
||||||
|
|
||||||
QByteArray ba = list[2].trimmed();
|
QByteArray ba = list[2].trimmed();
|
||||||
|
@ -98,9 +98,9 @@ bool Data::loadFile(const QString &fileName)
|
|||||||
file.reset();
|
file.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
qWarning("Error loading data file: %s:\n", qPrintable(fileName));
|
qWarning("Error loading data file: %s:", qPrintable(fileName));
|
||||||
for (it = _parsers.begin(); it != _parsers.end(); it++)
|
for (it = _parsers.begin(); it != _parsers.end(); it++)
|
||||||
qWarning("%s: line %d: %s\n", qPrintable(it.key()),
|
qWarning("%s: line %d: %s", qPrintable(it.key()),
|
||||||
it.value()->errorLine(), qPrintable(it.value()->errorString()));
|
it.value()->errorLine(), qPrintable(it.value()->errorString()));
|
||||||
|
|
||||||
_errorLine = 0;
|
_errorLine = 0;
|
||||||
|
@ -98,7 +98,7 @@ template<class T> bool FITParser::readValue(CTX &ctx, T &val)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FITParser::skipValue(CTX &ctx, size_t size)
|
bool FITParser::skipValue(CTX &ctx, quint8 size)
|
||||||
{
|
{
|
||||||
ctx.len -= size;
|
ctx.len -= size;
|
||||||
return ctx.file->seek(ctx.file->pos() + size);
|
return ctx.file->seek(ctx.file->pos() + size);
|
||||||
|
@ -20,7 +20,7 @@ private:
|
|||||||
|
|
||||||
bool readData(QFile *file, char *data, size_t size);
|
bool readData(QFile *file, char *data, size_t size);
|
||||||
template<class T> bool readValue(CTX &ctx, T &val);
|
template<class T> bool readValue(CTX &ctx, T &val);
|
||||||
bool skipValue(CTX &ctx, size_t size);
|
bool skipValue(CTX &ctx, quint8 size);
|
||||||
bool readField(CTX &ctx, Field *field, quint32 &val);
|
bool readField(CTX &ctx, Field *field, quint32 &val);
|
||||||
|
|
||||||
bool parseHeader(CTX &ctx);
|
bool parseHeader(CTX &ctx);
|
||||||
|
@ -54,7 +54,7 @@ Coordinates GPXParser::coordinates()
|
|||||||
void GPXParser::rpExtension(TrackData *autoRoute)
|
void GPXParser::rpExtension(TrackData *autoRoute)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "rpt")
|
if (_reader.name() == QLatin1String("rpt"))
|
||||||
autoRoute->append(Trackpoint(coordinates()));
|
autoRoute->append(Trackpoint(coordinates()));
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
}
|
}
|
||||||
@ -63,9 +63,9 @@ void GPXParser::rpExtension(TrackData *autoRoute)
|
|||||||
void GPXParser::tpExtension(Trackpoint &trackpoint)
|
void GPXParser::tpExtension(Trackpoint &trackpoint)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "hr")
|
if (_reader.name() == QLatin1String("hr"))
|
||||||
trackpoint.setHeartRate(number());
|
trackpoint.setHeartRate(number());
|
||||||
else if (_reader.name() == "atemp")
|
else if (_reader.name() == QLatin1String("atemp"))
|
||||||
trackpoint.setTemperature(number());
|
trackpoint.setTemperature(number());
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
@ -75,7 +75,7 @@ void GPXParser::tpExtension(Trackpoint &trackpoint)
|
|||||||
void GPXParser::rteptExtensions(TrackData *autoRoute)
|
void GPXParser::rteptExtensions(TrackData *autoRoute)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "RoutePointExtension")
|
if (_reader.name() == QLatin1String("RoutePointExtension"))
|
||||||
rpExtension(autoRoute);
|
rpExtension(autoRoute);
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
@ -85,17 +85,18 @@ void GPXParser::rteptExtensions(TrackData *autoRoute)
|
|||||||
void GPXParser::trkptExtensions(Trackpoint &trackpoint)
|
void GPXParser::trkptExtensions(Trackpoint &trackpoint)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "speed")
|
if (_reader.name() == QLatin1String("speed"))
|
||||||
trackpoint.setSpeed(number());
|
trackpoint.setSpeed(number());
|
||||||
else if (_reader.name() == "hr" || _reader.name() == "heartrate")
|
else if (_reader.name() == QLatin1String("hr")
|
||||||
|
|| _reader.name() == QLatin1String("heartrate"))
|
||||||
trackpoint.setHeartRate(number());
|
trackpoint.setHeartRate(number());
|
||||||
else if (_reader.name() == "temp")
|
else if (_reader.name() == QLatin1String("temp"))
|
||||||
trackpoint.setTemperature(number());
|
trackpoint.setTemperature(number());
|
||||||
else if (_reader.name() == "cadence")
|
else if (_reader.name() == QLatin1String("cadence"))
|
||||||
trackpoint.setCadence(number());
|
trackpoint.setCadence(number());
|
||||||
else if (_reader.name() == "power")
|
else if (_reader.name() == QLatin1String("power"))
|
||||||
trackpoint.setPower(number());
|
trackpoint.setPower(number());
|
||||||
else if (_reader.name() == "TrackPointExtension")
|
else if (_reader.name() == QLatin1String("TrackPointExtension"))
|
||||||
tpExtension(trackpoint);
|
tpExtension(trackpoint);
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
@ -107,13 +108,13 @@ void GPXParser::trackpointData(Trackpoint &trackpoint)
|
|||||||
qreal gh = NAN;
|
qreal gh = NAN;
|
||||||
|
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "ele")
|
if (_reader.name() == QLatin1String("ele"))
|
||||||
trackpoint.setElevation(number());
|
trackpoint.setElevation(number());
|
||||||
else if (_reader.name() == "time")
|
else if (_reader.name() == QLatin1String("time"))
|
||||||
trackpoint.setTimestamp(time());
|
trackpoint.setTimestamp(time());
|
||||||
else if (_reader.name() == "geoidheight")
|
else if (_reader.name() == QLatin1String("geoidheight"))
|
||||||
gh = number();
|
gh = number();
|
||||||
else if (_reader.name() == "extensions")
|
else if (_reader.name() == QLatin1String("extensions"))
|
||||||
trkptExtensions(trackpoint);
|
trkptExtensions(trackpoint);
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
@ -128,17 +129,17 @@ void GPXParser::waypointData(Waypoint &waypoint, TrackData *autoRoute)
|
|||||||
qreal gh = NAN;
|
qreal gh = NAN;
|
||||||
|
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "name")
|
if (_reader.name() == QLatin1String("name"))
|
||||||
waypoint.setName(_reader.readElementText());
|
waypoint.setName(_reader.readElementText());
|
||||||
else if (_reader.name() == "desc")
|
else if (_reader.name() == QLatin1String("desc"))
|
||||||
waypoint.setDescription(_reader.readElementText());
|
waypoint.setDescription(_reader.readElementText());
|
||||||
else if (_reader.name() == "ele")
|
else if (_reader.name() == QLatin1String("ele"))
|
||||||
waypoint.setElevation(number());
|
waypoint.setElevation(number());
|
||||||
else if (_reader.name() == "geoidheight")
|
else if (_reader.name() == QLatin1String("geoidheight"))
|
||||||
gh = number();
|
gh = number();
|
||||||
else if (_reader.name() == "time")
|
else if (_reader.name() == QLatin1String("time"))
|
||||||
waypoint.setTimestamp(time());
|
waypoint.setTimestamp(time());
|
||||||
else if (autoRoute && _reader.name() == "extensions")
|
else if (autoRoute && _reader.name() == QLatin1String("extensions"))
|
||||||
rteptExtensions(autoRoute);
|
rteptExtensions(autoRoute);
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
@ -151,7 +152,7 @@ void GPXParser::waypointData(Waypoint &waypoint, TrackData *autoRoute)
|
|||||||
void GPXParser::trackpoints(TrackData &track)
|
void GPXParser::trackpoints(TrackData &track)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "trkpt") {
|
if (_reader.name() == QLatin1String("trkpt")) {
|
||||||
track.append(Trackpoint(coordinates()));
|
track.append(Trackpoint(coordinates()));
|
||||||
trackpointData(track.last());
|
trackpointData(track.last());
|
||||||
} else
|
} else
|
||||||
@ -164,12 +165,12 @@ void GPXParser::routepoints(RouteData &route, QList<TrackData> &tracks)
|
|||||||
TrackData autoRoute;
|
TrackData autoRoute;
|
||||||
|
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "rtept") {
|
if (_reader.name() == QLatin1String("rtept")) {
|
||||||
route.append(Waypoint(coordinates()));
|
route.append(Waypoint(coordinates()));
|
||||||
waypointData(route.last(), &autoRoute);
|
waypointData(route.last(), &autoRoute);
|
||||||
} else if (_reader.name() == "name")
|
} else if (_reader.name() == QLatin1String("name"))
|
||||||
route.setName(_reader.readElementText());
|
route.setName(_reader.readElementText());
|
||||||
else if (_reader.name() == "desc")
|
else if (_reader.name() == QLatin1String("desc"))
|
||||||
route.setDescription(_reader.readElementText());
|
route.setDescription(_reader.readElementText());
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
@ -185,11 +186,11 @@ void GPXParser::routepoints(RouteData &route, QList<TrackData> &tracks)
|
|||||||
void GPXParser::track(TrackData &track)
|
void GPXParser::track(TrackData &track)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "trkseg")
|
if (_reader.name() == QLatin1String("trkseg"))
|
||||||
trackpoints(track);
|
trackpoints(track);
|
||||||
else if (_reader.name() == "name")
|
else if (_reader.name() == QLatin1String("name"))
|
||||||
track.setName(_reader.readElementText());
|
track.setName(_reader.readElementText());
|
||||||
else if (_reader.name() == "desc")
|
else if (_reader.name() == QLatin1String("desc"))
|
||||||
track.setDescription(_reader.readElementText());
|
track.setDescription(_reader.readElementText());
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
@ -200,13 +201,13 @@ void GPXParser::gpx(QList<TrackData> &tracks, QList<RouteData> &routes,
|
|||||||
QList<Waypoint> &waypoints)
|
QList<Waypoint> &waypoints)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "trk") {
|
if (_reader.name() == QLatin1String("trk")) {
|
||||||
tracks.append(TrackData());
|
tracks.append(TrackData());
|
||||||
track(tracks.back());
|
track(tracks.back());
|
||||||
} else if (_reader.name() == "rte") {
|
} else if (_reader.name() == QLatin1String("rte")) {
|
||||||
routes.append(RouteData());
|
routes.append(RouteData());
|
||||||
routepoints(routes.back(), tracks);
|
routepoints(routes.back(), tracks);
|
||||||
} else if (_reader.name() == "wpt") {
|
} else if (_reader.name() == QLatin1String("wpt")) {
|
||||||
waypoints.append(Waypoint(coordinates()));
|
waypoints.append(Waypoint(coordinates()));
|
||||||
waypointData(waypoints.last());
|
waypointData(waypoints.last());
|
||||||
} else
|
} else
|
||||||
@ -222,7 +223,7 @@ bool GPXParser::parse(QFile *file, QList<TrackData> &tracks,
|
|||||||
_reader.setNamespaceProcessing(false);
|
_reader.setNamespaceProcessing(false);
|
||||||
|
|
||||||
if (_reader.readNextStartElement()) {
|
if (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "gpx")
|
if (_reader.name() == QLatin1String("gpx"))
|
||||||
gpx(tracks, routes, waypoints);
|
gpx(tracks, routes, waypoints);
|
||||||
else
|
else
|
||||||
_reader.raiseError("Not a GPX file");
|
_reader.raiseError("Not a GPX file");
|
||||||
|
@ -98,12 +98,14 @@ static bool readARecord(const char *line, qint64 len)
|
|||||||
|
|
||||||
bool IGCParser::readHRecord(const char *line, int len)
|
bool IGCParser::readHRecord(const char *line, int len)
|
||||||
{
|
{
|
||||||
if (len < 10 || ::strncmp(line, "HFDTE", 5))
|
if (len < 11 || ::strncmp(line, "HFDTE", 5))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
int d = str2int(line + 5, 2);
|
int offset = (len < 16 || ::strncmp(line + 5, "DATE:", 5)) ? 5 : 10;
|
||||||
int m = str2int(line + 7, 2);
|
|
||||||
int y = str2int(line + 9, 2);
|
int d = str2int(line + offset, 2);
|
||||||
|
int m = str2int(line + offset + 2, 2);
|
||||||
|
int y = str2int(line + offset + 4, 2);
|
||||||
|
|
||||||
if (y < 0 || m < 0 || d < 0) {
|
if (y < 0 || m < 0 || d < 0) {
|
||||||
_errorString = "Invalid date header format";
|
_errorString = "Invalid date header format";
|
||||||
|
@ -191,7 +191,7 @@ QDateTime KMLParser::timeStamp()
|
|||||||
QDateTime ts;
|
QDateTime ts;
|
||||||
|
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "when")
|
if (_reader.name() == QLatin1String("when"))
|
||||||
ts = time();
|
ts = time();
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
@ -203,7 +203,7 @@ QDateTime KMLParser::timeStamp()
|
|||||||
void KMLParser::lineString(TrackData &track)
|
void KMLParser::lineString(TrackData &track)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "coordinates") {
|
if (_reader.name() == QLatin1String("coordinates")) {
|
||||||
if (!lineCoordinates(track))
|
if (!lineCoordinates(track))
|
||||||
_reader.raiseError("Invalid coordinates");
|
_reader.raiseError("Invalid coordinates");
|
||||||
} else
|
} else
|
||||||
@ -214,7 +214,7 @@ void KMLParser::lineString(TrackData &track)
|
|||||||
void KMLParser::point(Waypoint &waypoint)
|
void KMLParser::point(Waypoint &waypoint)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "coordinates") {
|
if (_reader.name() == QLatin1String("coordinates")) {
|
||||||
if (!pointCoordinates(waypoint))
|
if (!pointCoordinates(waypoint))
|
||||||
_reader.raiseError("Invalid coordinates");
|
_reader.raiseError("Invalid coordinates");
|
||||||
} else
|
} else
|
||||||
@ -231,7 +231,7 @@ void KMLParser::heartRate(TrackData &track, int start)
|
|||||||
const char error[] = "Heartrate data count mismatch";
|
const char error[] = "Heartrate data count mismatch";
|
||||||
|
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "value") {
|
if (_reader.name() == QLatin1String("value")) {
|
||||||
if (i < track.size())
|
if (i < track.size())
|
||||||
track[i++].setHeartRate(number());
|
track[i++].setHeartRate(number());
|
||||||
else {
|
else {
|
||||||
@ -252,7 +252,7 @@ void KMLParser::cadence(TrackData &track, int start)
|
|||||||
const char error[] = "Cadence data count mismatch";
|
const char error[] = "Cadence data count mismatch";
|
||||||
|
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "value") {
|
if (_reader.name() == QLatin1String("value")) {
|
||||||
if (i < track.size())
|
if (i < track.size())
|
||||||
track[i++].setCadence(number());
|
track[i++].setCadence(number());
|
||||||
else {
|
else {
|
||||||
@ -273,7 +273,7 @@ void KMLParser::speed(TrackData &track, int start)
|
|||||||
const char error[] = "Speed data count mismatch";
|
const char error[] = "Speed data count mismatch";
|
||||||
|
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "value") {
|
if (_reader.name() == QLatin1String("value")) {
|
||||||
if (i < track.size())
|
if (i < track.size())
|
||||||
track[i++].setSpeed(number());
|
track[i++].setSpeed(number());
|
||||||
else {
|
else {
|
||||||
@ -294,7 +294,7 @@ void KMLParser::temperature(TrackData &track, int start)
|
|||||||
const char error[] = "Temperature data count mismatch";
|
const char error[] = "Temperature data count mismatch";
|
||||||
|
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "value") {
|
if (_reader.name() == QLatin1String("value")) {
|
||||||
if (i < track.size())
|
if (i < track.size())
|
||||||
track[i++].setTemperature(number());
|
track[i++].setTemperature(number());
|
||||||
else {
|
else {
|
||||||
@ -312,17 +312,17 @@ void KMLParser::temperature(TrackData &track, int start)
|
|||||||
void KMLParser::schemaData(TrackData &track, int start)
|
void KMLParser::schemaData(TrackData &track, int start)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "SimpleArrayData") {
|
if (_reader.name() == QLatin1String("SimpleArrayData")) {
|
||||||
QXmlStreamAttributes attr = _reader.attributes();
|
QXmlStreamAttributes attr = _reader.attributes();
|
||||||
QStringRef name = attr.value("name");
|
QStringRef name = attr.value("name");
|
||||||
|
|
||||||
if (name == "Heartrate")
|
if (name == QLatin1String("Heartrate"))
|
||||||
heartRate(track, start);
|
heartRate(track, start);
|
||||||
else if (name == "Cadence")
|
else if (name == QLatin1String("Cadence"))
|
||||||
cadence(track, start);
|
cadence(track, start);
|
||||||
else if (name == "Speed")
|
else if (name == QLatin1String("Speed"))
|
||||||
speed(track, start);
|
speed(track, start);
|
||||||
else if (name == "Temperature")
|
else if (name == QLatin1String("Temperature"))
|
||||||
temperature(track, start);
|
temperature(track, start);
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
@ -334,7 +334,7 @@ void KMLParser::schemaData(TrackData &track, int start)
|
|||||||
void KMLParser::extendedData(TrackData &track, int start)
|
void KMLParser::extendedData(TrackData &track, int start)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "SchemaData")
|
if (_reader.name() == QLatin1String("SchemaData"))
|
||||||
schemaData(track, start);
|
schemaData(track, start);
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
@ -348,10 +348,10 @@ void KMLParser::track(TrackData &track)
|
|||||||
int i = first;
|
int i = first;
|
||||||
|
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "when") {
|
if (_reader.name() == QLatin1String("when")) {
|
||||||
track.append(Trackpoint());
|
track.append(Trackpoint());
|
||||||
track.last().setTimestamp(time());
|
track.last().setTimestamp(time());
|
||||||
} else if (_reader.name() == "coord") {
|
} else if (_reader.name() == QLatin1String("coord")) {
|
||||||
if (i == track.size()) {
|
if (i == track.size()) {
|
||||||
_reader.raiseError(error);
|
_reader.raiseError(error);
|
||||||
return;
|
return;
|
||||||
@ -360,7 +360,7 @@ void KMLParser::track(TrackData &track)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
} else if (_reader.name() == "ExtendedData")
|
} else if (_reader.name() == QLatin1String("ExtendedData"))
|
||||||
extendedData(track, first);
|
extendedData(track, first);
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
@ -373,7 +373,7 @@ void KMLParser::track(TrackData &track)
|
|||||||
void KMLParser::multiTrack(TrackData &t)
|
void KMLParser::multiTrack(TrackData &t)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "Track")
|
if (_reader.name() == QLatin1String("Track"))
|
||||||
track(t);
|
track(t);
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
@ -385,14 +385,14 @@ void KMLParser::multiGeometry(QList<TrackData> &tracks,
|
|||||||
const QDateTime timestamp)
|
const QDateTime timestamp)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "Point") {
|
if (_reader.name() == QLatin1String("Point")) {
|
||||||
waypoints.append(Waypoint());
|
waypoints.append(Waypoint());
|
||||||
Waypoint &w = waypoints.last();
|
Waypoint &w = waypoints.last();
|
||||||
w.setName(name);
|
w.setName(name);
|
||||||
w.setDescription(desc);
|
w.setDescription(desc);
|
||||||
w.setTimestamp(timestamp);
|
w.setTimestamp(timestamp);
|
||||||
point(w);
|
point(w);
|
||||||
} else if (_reader.name() == "LineString") {
|
} else if (_reader.name() == QLatin1String("LineString")) {
|
||||||
tracks.append(TrackData());
|
tracks.append(TrackData());
|
||||||
TrackData &t = tracks.last();
|
TrackData &t = tracks.last();
|
||||||
t.setName(name);
|
t.setName(name);
|
||||||
@ -409,35 +409,35 @@ void KMLParser::placemark(QList<TrackData> &tracks, QList<Waypoint> &waypoints)
|
|||||||
QDateTime timestamp;
|
QDateTime timestamp;
|
||||||
|
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "name")
|
if (_reader.name() == QLatin1String("name"))
|
||||||
name = _reader.readElementText();
|
name = _reader.readElementText();
|
||||||
else if (_reader.name() == "description")
|
else if (_reader.name() == QLatin1String("description"))
|
||||||
desc = _reader.readElementText();
|
desc = _reader.readElementText();
|
||||||
else if (_reader.name() == "TimeStamp")
|
else if (_reader.name() == QLatin1String("TimeStamp"))
|
||||||
timestamp = timeStamp();
|
timestamp = timeStamp();
|
||||||
else if (_reader.name() == "MultiGeometry")
|
else if (_reader.name() == QLatin1String("MultiGeometry"))
|
||||||
multiGeometry(tracks, waypoints, name, desc, timestamp);
|
multiGeometry(tracks, waypoints, name, desc, timestamp);
|
||||||
else if (_reader.name() == "Point") {
|
else if (_reader.name() == QLatin1String("Point")) {
|
||||||
waypoints.append(Waypoint());
|
waypoints.append(Waypoint());
|
||||||
Waypoint &w = waypoints.last();
|
Waypoint &w = waypoints.last();
|
||||||
w.setName(name);
|
w.setName(name);
|
||||||
w.setDescription(desc);
|
w.setDescription(desc);
|
||||||
w.setTimestamp(timestamp);
|
w.setTimestamp(timestamp);
|
||||||
point(w);
|
point(w);
|
||||||
} else if (_reader.name() == "LineString"
|
} else if (_reader.name() == QLatin1String("LineString")
|
||||||
|| _reader.name() == "LinearRing") {
|
|| _reader.name() == QLatin1String("LinearRing")) {
|
||||||
tracks.append(TrackData());
|
tracks.append(TrackData());
|
||||||
TrackData &t = tracks.last();
|
TrackData &t = tracks.last();
|
||||||
t.setName(name);
|
t.setName(name);
|
||||||
t.setDescription(desc);
|
t.setDescription(desc);
|
||||||
lineString(t);
|
lineString(t);
|
||||||
} else if (_reader.name() == "Track") {
|
} else if (_reader.name() == QLatin1String("Track")) {
|
||||||
tracks.append(TrackData());
|
tracks.append(TrackData());
|
||||||
TrackData &t = tracks.last();
|
TrackData &t = tracks.last();
|
||||||
t.setName(name);
|
t.setName(name);
|
||||||
t.setDescription(desc);
|
t.setDescription(desc);
|
||||||
track(t);
|
track(t);
|
||||||
} else if (_reader.name() == "MultiTrack") {
|
} else if (_reader.name() == QLatin1String("MultiTrack")) {
|
||||||
tracks.append(TrackData());
|
tracks.append(TrackData());
|
||||||
TrackData &t = tracks.last();
|
TrackData &t = tracks.last();
|
||||||
t.setName(name);
|
t.setName(name);
|
||||||
@ -451,9 +451,9 @@ void KMLParser::placemark(QList<TrackData> &tracks, QList<Waypoint> &waypoints)
|
|||||||
void KMLParser::folder(QList<TrackData> &tracks, QList<Waypoint> &waypoints)
|
void KMLParser::folder(QList<TrackData> &tracks, QList<Waypoint> &waypoints)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "Placemark")
|
if (_reader.name() == QLatin1String("Placemark"))
|
||||||
placemark(tracks, waypoints);
|
placemark(tracks, waypoints);
|
||||||
else if (_reader.name() == "Folder")
|
else if (_reader.name() == QLatin1String("Folder"))
|
||||||
folder(tracks, waypoints);
|
folder(tracks, waypoints);
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
@ -463,9 +463,9 @@ void KMLParser::folder(QList<TrackData> &tracks, QList<Waypoint> &waypoints)
|
|||||||
void KMLParser::document(QList<TrackData> &tracks, QList<Waypoint> &waypoints)
|
void KMLParser::document(QList<TrackData> &tracks, QList<Waypoint> &waypoints)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "Placemark")
|
if (_reader.name() == QLatin1String("Placemark"))
|
||||||
placemark(tracks, waypoints);
|
placemark(tracks, waypoints);
|
||||||
else if (_reader.name() == "Folder")
|
else if (_reader.name() == QLatin1String("Folder"))
|
||||||
folder(tracks, waypoints);
|
folder(tracks, waypoints);
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
@ -475,11 +475,11 @@ void KMLParser::document(QList<TrackData> &tracks, QList<Waypoint> &waypoints)
|
|||||||
void KMLParser::kml(QList<TrackData> &tracks, QList<Waypoint> &waypoints)
|
void KMLParser::kml(QList<TrackData> &tracks, QList<Waypoint> &waypoints)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "Document")
|
if (_reader.name() == QLatin1String("Document"))
|
||||||
document(tracks, waypoints);
|
document(tracks, waypoints);
|
||||||
else if (_reader.name() == "Placemark")
|
else if (_reader.name() == QLatin1String("Placemark"))
|
||||||
placemark(tracks, waypoints);
|
placemark(tracks, waypoints);
|
||||||
else if (_reader.name() == "Folder")
|
else if (_reader.name() == QLatin1String("Folder"))
|
||||||
folder(tracks, waypoints);
|
folder(tracks, waypoints);
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
@ -495,7 +495,7 @@ bool KMLParser::parse(QFile *file, QList<TrackData> &tracks,
|
|||||||
_reader.setDevice(file);
|
_reader.setDevice(file);
|
||||||
|
|
||||||
if (_reader.readNextStartElement()) {
|
if (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "kml")
|
if (_reader.name() == QLatin1String("kml"))
|
||||||
kml(tracks, waypoints);
|
kml(tracks, waypoints);
|
||||||
else
|
else
|
||||||
_reader.raiseError("Not a KML file");
|
_reader.raiseError("Not a KML file");
|
||||||
|
@ -31,11 +31,11 @@ Coordinates LOCParser::coordinates()
|
|||||||
void LOCParser::waypoint(Waypoint &waypoint)
|
void LOCParser::waypoint(Waypoint &waypoint)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "name") {
|
if (_reader.name() == QLatin1String("name")) {
|
||||||
const QXmlStreamAttributes &attr = _reader.attributes();
|
const QXmlStreamAttributes &attr = _reader.attributes();
|
||||||
waypoint.setName(attr.value("id").toString());
|
waypoint.setName(attr.value("id").toString());
|
||||||
waypoint.setDescription(_reader.readElementText());
|
waypoint.setDescription(_reader.readElementText());
|
||||||
} else if (_reader.name() == "coord") {
|
} else if (_reader.name() == QLatin1String("coord")) {
|
||||||
waypoint.setCoordinates(coordinates());
|
waypoint.setCoordinates(coordinates());
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
} else
|
} else
|
||||||
@ -49,7 +49,7 @@ void LOCParser::waypoint(Waypoint &waypoint)
|
|||||||
void LOCParser::loc(QList<Waypoint> &waypoints)
|
void LOCParser::loc(QList<Waypoint> &waypoints)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "waypoint") {
|
if (_reader.name() == QLatin1String("waypoint")) {
|
||||||
waypoints.append(Waypoint());
|
waypoints.append(Waypoint());
|
||||||
waypoint(waypoints.last());
|
waypoint(waypoints.last());
|
||||||
} else
|
} else
|
||||||
@ -67,7 +67,7 @@ bool LOCParser::parse(QFile *file, QList<TrackData> &tracks,
|
|||||||
_reader.setDevice(file);
|
_reader.setDevice(file);
|
||||||
|
|
||||||
if (_reader.readNextStartElement()) {
|
if (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "loc")
|
if (_reader.name() == QLatin1String("loc"))
|
||||||
loc(waypoints);
|
loc(waypoints);
|
||||||
else
|
else
|
||||||
_reader.raiseError("Not a LOC file");
|
_reader.raiseError("Not a LOC file");
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include "common/rectc.h"
|
#include "common/rectc.h"
|
||||||
|
#include "common/greatcircle.h"
|
||||||
#include "data.h"
|
#include "data.h"
|
||||||
#include "poi.h"
|
#include "poi.h"
|
||||||
|
|
||||||
@ -94,23 +95,45 @@ static bool cb(size_t data, void* context)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void POI::search(const RectC &rect, QSet<int> &set) const
|
||||||
|
{
|
||||||
|
qreal min[2], max[2];
|
||||||
|
|
||||||
|
min[0] = rect.topLeft().lon();
|
||||||
|
min[1] = rect.bottomRight().lat();
|
||||||
|
max[0] = rect.bottomRight().lon();
|
||||||
|
max[1] = rect.topLeft().lat();
|
||||||
|
|
||||||
|
_tree.Search(min, max, cb, &set);
|
||||||
|
}
|
||||||
|
|
||||||
QList<Waypoint> POI::points(const Path &path) const
|
QList<Waypoint> POI::points(const Path &path) const
|
||||||
{
|
{
|
||||||
QList<Waypoint> ret;
|
QList<Waypoint> ret;
|
||||||
QSet<int> set;
|
QSet<int> set;
|
||||||
qreal min[2], max[2];
|
|
||||||
QSet<int>::const_iterator it;
|
QSet<int>::const_iterator it;
|
||||||
|
|
||||||
for (int i = 0; i < path.count(); i++) {
|
|
||||||
RectC br(path.at(i).coordinates(), _radius);
|
|
||||||
min[0] = br.topLeft().lon();
|
|
||||||
min[1] = br.bottomRight().lat();
|
|
||||||
max[0] = br.bottomRight().lon();
|
|
||||||
max[1] = br.topLeft().lat();
|
|
||||||
|
|
||||||
_tree.Search(min, max, cb, &set);
|
for (int i = 1; i < path.count(); i++) {
|
||||||
|
double ds = path.at(i).distance() - path.at(i-1).distance();
|
||||||
|
unsigned n = (unsigned)ceil(ds / _radius);
|
||||||
|
|
||||||
|
if (n > 1) {
|
||||||
|
GreatCircle gc(path.at(i-1).coordinates(), path.at(i).coordinates());
|
||||||
|
for (unsigned j = 0; j < n; j++) {
|
||||||
|
RectC br(gc.pointAt((double)j/n), _radius);
|
||||||
|
search(br, set);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
RectC br(path.at(i-1).coordinates(), _radius);
|
||||||
|
search(br, set);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RectC br(path.last().coordinates(), _radius);
|
||||||
|
search(br, set);
|
||||||
|
|
||||||
|
|
||||||
for (it = set.constBegin(); it != set.constEnd(); ++it)
|
for (it = set.constBegin(); it != set.constEnd(); ++it)
|
||||||
ret.append(_data.at(*it));
|
ret.append(_data.at(*it));
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#include "waypoint.h"
|
#include "waypoint.h"
|
||||||
#include "path.h"
|
#include "path.h"
|
||||||
|
|
||||||
class WaypointItem;
|
|
||||||
|
|
||||||
class POI : public QObject
|
class POI : public QObject
|
||||||
{
|
{
|
||||||
@ -45,6 +44,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool loadFile(const QString &path, bool dir);
|
bool loadFile(const QString &path, bool dir);
|
||||||
|
void search(const RectC &rect, QSet<int> &set) const;
|
||||||
|
|
||||||
POITree _tree;
|
POITree _tree;
|
||||||
QVector<Waypoint> _data;
|
QVector<Waypoint> _data;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
void SLFParser::warning(const char *text) const
|
void SLFParser::warning(const char *text) const
|
||||||
{
|
{
|
||||||
const QFile *file = static_cast<QFile *>(_reader.device());
|
const QFile *file = static_cast<QFile *>(_reader.device());
|
||||||
qWarning("%s:%lld: %s\n", qPrintable(file->fileName()),
|
qWarning("%s:%lld: %s", qPrintable(file->fileName()),
|
||||||
_reader.lineNumber(), text);
|
_reader.lineNumber(), text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ bool SLFParser::data(const QXmlStreamAttributes &attr, const char *name,
|
|||||||
void SLFParser::entries(const QDateTime &date, TrackData &track)
|
void SLFParser::entries(const QDateTime &date, TrackData &track)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "Entry") {
|
if (_reader.name() == QLatin1String("Entry")) {
|
||||||
qreal val, lat, lon;
|
qreal val, lat, lon;
|
||||||
QXmlStreamAttributes attr(_reader.attributes());
|
QXmlStreamAttributes attr(_reader.attributes());
|
||||||
|
|
||||||
@ -70,11 +70,11 @@ void SLFParser::entries(const QDateTime &date, TrackData &track)
|
|||||||
void SLFParser::generalInformation(QDateTime &date, TrackData &track)
|
void SLFParser::generalInformation(QDateTime &date, TrackData &track)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "name")
|
if (_reader.name() == QLatin1String("name"))
|
||||||
track.setName(_reader.readElementText());
|
track.setName(_reader.readElementText());
|
||||||
else if (_reader.name() == "description")
|
else if (_reader.name() == QLatin1String("description"))
|
||||||
track.setDescription(_reader.readElementText());
|
track.setDescription(_reader.readElementText());
|
||||||
else if (_reader.name() == "startDate") {
|
else if (_reader.name() == QLatin1String("startDate")) {
|
||||||
QString ds(_reader.readElementText());
|
QString ds(_reader.readElementText());
|
||||||
QLocale locale(QLocale::English);
|
QLocale locale(QLocale::English);
|
||||||
date = locale.toDateTime(ds.mid(0, ds.indexOf("GMT"))
|
date = locale.toDateTime(ds.mid(0, ds.indexOf("GMT"))
|
||||||
@ -89,9 +89,9 @@ void SLFParser::activity(TrackData &track)
|
|||||||
QDateTime date;
|
QDateTime date;
|
||||||
|
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "Entries")
|
if (_reader.name() == QLatin1String("Entries"))
|
||||||
entries(date, track);
|
entries(date, track);
|
||||||
else if (_reader.name() == "GeneralInformation")
|
else if (_reader.name() == QLatin1String("GeneralInformation"))
|
||||||
generalInformation(date, track);
|
generalInformation(date, track);
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
@ -108,7 +108,7 @@ bool SLFParser::parse(QFile *file, QList<TrackData> &tracks,
|
|||||||
_reader.setDevice(file);
|
_reader.setDevice(file);
|
||||||
|
|
||||||
if (_reader.readNextStartElement()) {
|
if (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "Activity") {
|
if (_reader.name() == QLatin1String("Activity")) {
|
||||||
tracks.append(TrackData());
|
tracks.append(TrackData());
|
||||||
activity(tracks.last());
|
activity(tracks.last());
|
||||||
} else
|
} else
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
void TCXParser::warning(const char *text) const
|
void TCXParser::warning(const char *text) const
|
||||||
{
|
{
|
||||||
const QFile *file = static_cast<QFile *>(_reader.device());
|
const QFile *file = static_cast<QFile *>(_reader.device());
|
||||||
qWarning("%s:%lld: %s\n", qPrintable(file->fileName()),
|
qWarning("%s:%lld: %s", qPrintable(file->fileName()),
|
||||||
_reader.lineNumber(), text);
|
_reader.lineNumber(), text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,13 +37,13 @@ Coordinates TCXParser::position()
|
|||||||
bool res;
|
bool res;
|
||||||
|
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "LatitudeDegrees") {
|
if (_reader.name() == QLatin1String("LatitudeDegrees")) {
|
||||||
val = _reader.readElementText().toDouble(&res);
|
val = _reader.readElementText().toDouble(&res);
|
||||||
if (!res || (val < -90.0 || val > 90.0))
|
if (!res || (val < -90.0 || val > 90.0))
|
||||||
_reader.raiseError("Invalid LatitudeDegrees");
|
_reader.raiseError("Invalid LatitudeDegrees");
|
||||||
else
|
else
|
||||||
pos.setLat(val);
|
pos.setLat(val);
|
||||||
} else if (_reader.name() == "LongitudeDegrees") {
|
} else if (_reader.name() == QLatin1String("LongitudeDegrees")) {
|
||||||
val = _reader.readElementText().toDouble(&res);
|
val = _reader.readElementText().toDouble(&res);
|
||||||
if (!res || (val < -180.0 || val > 180.0))
|
if (!res || (val < -180.0 || val > 180.0))
|
||||||
_reader.raiseError("Invalid LongitudeDegrees");
|
_reader.raiseError("Invalid LongitudeDegrees");
|
||||||
@ -59,7 +59,7 @@ Coordinates TCXParser::position()
|
|||||||
void TCXParser::heartRateBpm(Trackpoint &trackpoint)
|
void TCXParser::heartRateBpm(Trackpoint &trackpoint)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "Value")
|
if (_reader.name() == QLatin1String("Value"))
|
||||||
trackpoint.setHeartRate(number());
|
trackpoint.setHeartRate(number());
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
@ -69,9 +69,9 @@ void TCXParser::heartRateBpm(Trackpoint &trackpoint)
|
|||||||
void TCXParser::extensions(Trackpoint &trackpoint)
|
void TCXParser::extensions(Trackpoint &trackpoint)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "RunCadence")
|
if (_reader.name() == QLatin1String("RunCadence"))
|
||||||
trackpoint.setCadence(number());
|
trackpoint.setCadence(number());
|
||||||
else if (_reader.name() == "Watts")
|
else if (_reader.name() == QLatin1String("Watts"))
|
||||||
trackpoint.setPower(number());
|
trackpoint.setPower(number());
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
@ -81,17 +81,17 @@ void TCXParser::extensions(Trackpoint &trackpoint)
|
|||||||
void TCXParser::trackpointData(Trackpoint &trackpoint)
|
void TCXParser::trackpointData(Trackpoint &trackpoint)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "Position")
|
if (_reader.name() == QLatin1String("Position"))
|
||||||
trackpoint.setCoordinates(position());
|
trackpoint.setCoordinates(position());
|
||||||
else if (_reader.name() == "AltitudeMeters")
|
else if (_reader.name() == QLatin1String("AltitudeMeters"))
|
||||||
trackpoint.setElevation(number());
|
trackpoint.setElevation(number());
|
||||||
else if (_reader.name() == "Time")
|
else if (_reader.name() == QLatin1String("Time"))
|
||||||
trackpoint.setTimestamp(time());
|
trackpoint.setTimestamp(time());
|
||||||
else if (_reader.name() == "HeartRateBpm")
|
else if (_reader.name() == QLatin1String("HeartRateBpm"))
|
||||||
heartRateBpm(trackpoint);
|
heartRateBpm(trackpoint);
|
||||||
else if (_reader.name() == "Cadence")
|
else if (_reader.name() == QLatin1String("Cadence"))
|
||||||
trackpoint.setCadence(number());
|
trackpoint.setCadence(number());
|
||||||
else if (_reader.name() == "Extensions")
|
else if (_reader.name() == QLatin1String("Extensions"))
|
||||||
extensions(trackpoint);
|
extensions(trackpoint);
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
@ -101,15 +101,15 @@ void TCXParser::trackpointData(Trackpoint &trackpoint)
|
|||||||
void TCXParser::waypointData(Waypoint &waypoint)
|
void TCXParser::waypointData(Waypoint &waypoint)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "Position")
|
if (_reader.name() == QLatin1String("Position"))
|
||||||
waypoint.setCoordinates(position());
|
waypoint.setCoordinates(position());
|
||||||
else if (_reader.name() == "Name")
|
else if (_reader.name() == QLatin1String("Name"))
|
||||||
waypoint.setName(_reader.readElementText());
|
waypoint.setName(_reader.readElementText());
|
||||||
else if (_reader.name() == "Notes")
|
else if (_reader.name() == QLatin1String("Notes"))
|
||||||
waypoint.setDescription(_reader.readElementText());
|
waypoint.setDescription(_reader.readElementText());
|
||||||
else if (_reader.name() == "AltitudeMeters")
|
else if (_reader.name() == QLatin1String("AltitudeMeters"))
|
||||||
waypoint.setElevation(number());
|
waypoint.setElevation(number());
|
||||||
else if (_reader.name() == "Time")
|
else if (_reader.name() == QLatin1String("Time"))
|
||||||
waypoint.setTimestamp(time());
|
waypoint.setTimestamp(time());
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
@ -119,7 +119,7 @@ void TCXParser::waypointData(Waypoint &waypoint)
|
|||||||
void TCXParser::trackpoints(TrackData &track)
|
void TCXParser::trackpoints(TrackData &track)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "Trackpoint") {
|
if (_reader.name() == QLatin1String("Trackpoint")) {
|
||||||
Trackpoint t;
|
Trackpoint t;
|
||||||
trackpointData(t);
|
trackpointData(t);
|
||||||
if (t.coordinates().isValid())
|
if (t.coordinates().isValid())
|
||||||
@ -134,7 +134,7 @@ void TCXParser::trackpoints(TrackData &track)
|
|||||||
void TCXParser::lap(TrackData &track)
|
void TCXParser::lap(TrackData &track)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "Track")
|
if (_reader.name() == QLatin1String("Track"))
|
||||||
trackpoints(track);
|
trackpoints(track);
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
@ -144,13 +144,13 @@ void TCXParser::lap(TrackData &track)
|
|||||||
void TCXParser::course(QList<Waypoint> &waypoints, TrackData &track)
|
void TCXParser::course(QList<Waypoint> &waypoints, TrackData &track)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "Track")
|
if (_reader.name() == QLatin1String("Track"))
|
||||||
trackpoints(track);
|
trackpoints(track);
|
||||||
else if (_reader.name() == "Name")
|
else if (_reader.name() == QLatin1String("Name"))
|
||||||
track.setName(_reader.readElementText());
|
track.setName(_reader.readElementText());
|
||||||
else if (_reader.name() == "Notes")
|
else if (_reader.name() == QLatin1String("Notes"))
|
||||||
track.setDescription(_reader.readElementText());
|
track.setDescription(_reader.readElementText());
|
||||||
else if (_reader.name() == "CoursePoint") {
|
else if (_reader.name() == QLatin1String("CoursePoint")) {
|
||||||
Waypoint w;
|
Waypoint w;
|
||||||
waypointData(w);
|
waypointData(w);
|
||||||
if (w.coordinates().isValid())
|
if (w.coordinates().isValid())
|
||||||
@ -165,7 +165,7 @@ void TCXParser::course(QList<Waypoint> &waypoints, TrackData &track)
|
|||||||
void TCXParser::activity(TrackData &track)
|
void TCXParser::activity(TrackData &track)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "Lap")
|
if (_reader.name() == QLatin1String("Lap"))
|
||||||
lap(track);
|
lap(track);
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
@ -175,7 +175,7 @@ void TCXParser::activity(TrackData &track)
|
|||||||
void TCXParser::courses(QList<TrackData> &tracks, QList<Waypoint> &waypoints)
|
void TCXParser::courses(QList<TrackData> &tracks, QList<Waypoint> &waypoints)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "Course") {
|
if (_reader.name() == QLatin1String("Course")) {
|
||||||
tracks.append(TrackData());
|
tracks.append(TrackData());
|
||||||
course(waypoints, tracks.back());
|
course(waypoints, tracks.back());
|
||||||
} else
|
} else
|
||||||
@ -186,7 +186,7 @@ void TCXParser::courses(QList<TrackData> &tracks, QList<Waypoint> &waypoints)
|
|||||||
void TCXParser::sport(QList<TrackData> &tracks)
|
void TCXParser::sport(QList<TrackData> &tracks)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "Activity") {
|
if (_reader.name() == QLatin1String("Activity")) {
|
||||||
tracks.append(TrackData());
|
tracks.append(TrackData());
|
||||||
activity(tracks.back());
|
activity(tracks.back());
|
||||||
} else
|
} else
|
||||||
@ -197,7 +197,8 @@ void TCXParser::sport(QList<TrackData> &tracks)
|
|||||||
void TCXParser::multiSportSession(QList<TrackData> &tracks)
|
void TCXParser::multiSportSession(QList<TrackData> &tracks)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "FirstSport" || _reader.name() == "NextSport")
|
if (_reader.name() == QLatin1String("FirstSport")
|
||||||
|
|| _reader.name() == QLatin1String("NextSport"))
|
||||||
sport(tracks);
|
sport(tracks);
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
@ -207,10 +208,10 @@ void TCXParser::multiSportSession(QList<TrackData> &tracks)
|
|||||||
void TCXParser::activities(QList<TrackData> &tracks)
|
void TCXParser::activities(QList<TrackData> &tracks)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "Activity") {
|
if (_reader.name() == QLatin1String("Activity")) {
|
||||||
tracks.append(TrackData());
|
tracks.append(TrackData());
|
||||||
activity(tracks.back());
|
activity(tracks.back());
|
||||||
} else if (_reader.name() == "MultiSportSession")
|
} else if (_reader.name() == QLatin1String("MultiSportSession"))
|
||||||
multiSportSession(tracks);
|
multiSportSession(tracks);
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
@ -220,9 +221,9 @@ void TCXParser::activities(QList<TrackData> &tracks)
|
|||||||
void TCXParser::tcx(QList<TrackData> &tracks, QList<Waypoint> &waypoints)
|
void TCXParser::tcx(QList<TrackData> &tracks, QList<Waypoint> &waypoints)
|
||||||
{
|
{
|
||||||
while (_reader.readNextStartElement()) {
|
while (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "Courses")
|
if (_reader.name() == QLatin1String("Courses"))
|
||||||
courses(tracks, waypoints);
|
courses(tracks, waypoints);
|
||||||
else if (_reader.name() == "Activities")
|
else if (_reader.name() == QLatin1String("Activities"))
|
||||||
activities(tracks);
|
activities(tracks);
|
||||||
else
|
else
|
||||||
_reader.skipCurrentElement();
|
_reader.skipCurrentElement();
|
||||||
@ -238,7 +239,7 @@ bool TCXParser::parse(QFile *file, QList<TrackData> &tracks,
|
|||||||
_reader.setDevice(file);
|
_reader.setDevice(file);
|
||||||
|
|
||||||
if (_reader.readNextStartElement()) {
|
if (_reader.readNextStartElement()) {
|
||||||
if (_reader.name() == "TrainingCenterDatabase")
|
if (_reader.name() == QLatin1String("TrainingCenterDatabase"))
|
||||||
tcx(tracks, waypoints);
|
tcx(tracks, waypoints);
|
||||||
else
|
else
|
||||||
_reader.raiseError("Not a TCX file");
|
_reader.raiseError("Not a TCX file");
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#include <QtAlgorithms>
|
#include <QtAlgorithms>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include "common/rectc.h"
|
#include "common/rectc.h"
|
||||||
#include "offlinemap.h"
|
#include "ozimap.h"
|
||||||
#include "tar.h"
|
#include "tar.h"
|
||||||
#include "atlas.h"
|
#include "atlas.h"
|
||||||
|
|
||||||
@ -12,7 +12,7 @@
|
|||||||
#define TL(m) ((m)->xy2pp((m)->bounds().topLeft()))
|
#define TL(m) ((m)->xy2pp((m)->bounds().topLeft()))
|
||||||
#define BR(m) ((m)->xy2pp((m)->bounds().bottomRight()))
|
#define BR(m) ((m)->xy2pp((m)->bounds().bottomRight()))
|
||||||
|
|
||||||
static bool resCmp(OfflineMap *m1, OfflineMap *m2)
|
static bool resCmp(OziMap *m1, OziMap *m2)
|
||||||
{
|
{
|
||||||
qreal r1, r2;
|
qreal r1, r2;
|
||||||
|
|
||||||
@ -22,12 +22,12 @@ static bool resCmp(OfflineMap *m1, OfflineMap *m2)
|
|||||||
return r1 > r2;
|
return r1 > r2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool xCmp(OfflineMap *m1, OfflineMap *m2)
|
static bool xCmp(OziMap *m1, OziMap *m2)
|
||||||
{
|
{
|
||||||
return TL(m1).x() < TL(m2).x();
|
return TL(m1).x() < TL(m2).x();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool yCmp(OfflineMap *m1, OfflineMap *m2)
|
static bool yCmp(OziMap *m1, OziMap *m2)
|
||||||
{
|
{
|
||||||
return TL(m1).y() > TL(m2).y();
|
return TL(m1).y() > TL(m2).y();
|
||||||
}
|
}
|
||||||
@ -52,7 +52,7 @@ void Atlas::computeBounds()
|
|||||||
QVector<QPointF> offsets(_maps.count());
|
QVector<QPointF> offsets(_maps.count());
|
||||||
|
|
||||||
for (int z = 0; z < _zooms.count(); z++) {
|
for (int z = 0; z < _zooms.count(); z++) {
|
||||||
QList<OfflineMap*> m;
|
QList<OziMap*> m;
|
||||||
for (int i = _zooms.at(z).first; i <= _zooms.at(z).last; i++)
|
for (int i = _zooms.at(z).first; i <= _zooms.at(z).last; i++)
|
||||||
m.append(_maps.at(i));
|
m.append(_maps.at(i));
|
||||||
|
|
||||||
@ -119,11 +119,11 @@ Atlas::Atlas(const QString &fileName, QObject *parent)
|
|||||||
QString mapFile = maps.at(i).absoluteFilePath() + "/"
|
QString mapFile = maps.at(i).absoluteFilePath() + "/"
|
||||||
+ maps.at(i).fileName() + ".map";
|
+ maps.at(i).fileName() + ".map";
|
||||||
|
|
||||||
OfflineMap *map;
|
OziMap *map;
|
||||||
if (tar.isOpen())
|
if (tar.isOpen())
|
||||||
map = new OfflineMap(mapFile, tar, this);
|
map = new OziMap(mapFile, tar, this);
|
||||||
else
|
else
|
||||||
map = new OfflineMap(mapFile, this);
|
map = new OziMap(mapFile, this);
|
||||||
|
|
||||||
if (map->isValid())
|
if (map->isValid())
|
||||||
_maps.append(map);
|
_maps.append(map);
|
||||||
@ -255,14 +255,12 @@ Coordinates Atlas::xy2ll(const QPointF &p)
|
|||||||
return _maps.at(idx)->xy2ll(p2);
|
return _maps.at(idx)->xy2ll(p2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Atlas::draw(QPainter *painter, const QRectF &rect, bool block)
|
void Atlas::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||||
{
|
{
|
||||||
Q_UNUSED(block);
|
|
||||||
|
|
||||||
// All in one map
|
// All in one map
|
||||||
for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).last; i++) {
|
for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).last; i++) {
|
||||||
if (_bounds.at(i).xy.contains(rect)) {
|
if (_bounds.at(i).xy.contains(rect)) {
|
||||||
draw(painter, rect, i);
|
draw(painter, rect, i, flags);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -271,20 +269,21 @@ void Atlas::draw(QPainter *painter, const QRectF &rect, bool block)
|
|||||||
for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).last; i++) {
|
for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).last; i++) {
|
||||||
QRectF ir = rect.intersected(_bounds.at(i).xy);
|
QRectF ir = rect.intersected(_bounds.at(i).xy);
|
||||||
if (!ir.isNull())
|
if (!ir.isNull())
|
||||||
draw(painter, ir, i);
|
draw(painter, ir, i, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Atlas::draw(QPainter *painter, const QRectF &rect, int mapIndex)
|
void Atlas::draw(QPainter *painter, const QRectF &rect, int mapIndex,
|
||||||
|
Flags flags)
|
||||||
{
|
{
|
||||||
OfflineMap *map = _maps.at(mapIndex);
|
OziMap *map = _maps.at(mapIndex);
|
||||||
const QPointF offset = _bounds.at(mapIndex).xy.topLeft();
|
const QPointF offset = _bounds.at(mapIndex).xy.topLeft();
|
||||||
QRectF pr = QRectF(rect.topLeft() - offset, rect.size());
|
QRectF pr = QRectF(rect.topLeft() - offset, rect.size());
|
||||||
|
|
||||||
map->load();
|
map->load();
|
||||||
|
|
||||||
painter->translate(offset);
|
painter->translate(offset);
|
||||||
map->draw(painter, pr, true);
|
map->draw(painter, pr, flags);
|
||||||
painter->translate(-offset);
|
painter->translate(-offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include "map.h"
|
#include "map.h"
|
||||||
#include "rectd.h"
|
#include "rectd.h"
|
||||||
|
|
||||||
class OfflineMap;
|
class OziMap;
|
||||||
|
|
||||||
class Atlas : public Map
|
class Atlas : public Map
|
||||||
{
|
{
|
||||||
@ -26,7 +26,7 @@ public:
|
|||||||
QPointF ll2xy(const Coordinates &c);
|
QPointF ll2xy(const Coordinates &c);
|
||||||
Coordinates xy2ll(const QPointF &p);
|
Coordinates xy2ll(const QPointF &p);
|
||||||
|
|
||||||
void draw(QPainter *painter, const QRectF &rect, bool block);
|
void draw(QPainter *painter, const QRectF &rect, Flags flags);
|
||||||
|
|
||||||
void setDevicePixelRatio(qreal ratio);
|
void setDevicePixelRatio(qreal ratio);
|
||||||
void unload();
|
void unload();
|
||||||
@ -53,13 +53,13 @@ private:
|
|||||||
Bounds(const RectD &pp, const QRectF &xy) : pp(pp), xy(xy) {}
|
Bounds(const RectD &pp, const QRectF &xy) : pp(pp), xy(xy) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
void draw(QPainter *painter, const QRectF &rect, int mapIndex);
|
void draw(QPainter *painter, const QRectF &rect, int mapIndex, Flags flags);
|
||||||
void computeZooms();
|
void computeZooms();
|
||||||
void computeBounds();
|
void computeBounds();
|
||||||
|
|
||||||
QString _name;
|
QString _name;
|
||||||
|
|
||||||
QList<OfflineMap*> _maps;
|
QList<OziMap*> _maps;
|
||||||
QVector<Zoom> _zooms;
|
QVector<Zoom> _zooms;
|
||||||
QVector<Bounds> _bounds;
|
QVector<Bounds> _bounds;
|
||||||
int _zoom;
|
int _zoom;
|
||||||
|
@ -20,8 +20,10 @@
|
|||||||
|
|
||||||
#define ATTR_REDIRECT QNetworkRequest::RedirectionTargetAttribute
|
#define ATTR_REDIRECT QNetworkRequest::RedirectionTargetAttribute
|
||||||
#define ATTR_FILE QNetworkRequest::User
|
#define ATTR_FILE QNetworkRequest::User
|
||||||
#define ATTR_ORIGIN (QNetworkRequest::Attribute)(QNetworkRequest::User + 1)
|
#define ATTR_ORIGIN \
|
||||||
#define ATTR_LEVEL (QNetworkRequest::Attribute)(QNetworkRequest::User + 2)
|
static_cast<QNetworkRequest::Attribute>(QNetworkRequest::User + 1)
|
||||||
|
#define ATTR_LEVEL \
|
||||||
|
static_cast<QNetworkRequest::Attribute>(QNetworkRequest::User + 2)
|
||||||
|
|
||||||
#define MAX_REDIRECT_LEVEL 5
|
#define MAX_REDIRECT_LEVEL 5
|
||||||
#define RETRIES 3
|
#define RETRIES 3
|
||||||
@ -78,19 +80,25 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
QNetworkAccessManager *Downloader::_manager = 0;
|
|
||||||
int Downloader::_timeout = 30;
|
int Downloader::_timeout = 30;
|
||||||
#ifdef ENABLE_HTTP2
|
#ifdef ENABLE_HTTP2
|
||||||
bool Downloader::_http2 = true;
|
bool Downloader::_http2 = true;
|
||||||
#endif // ENABLE_HTTP2
|
#endif // ENABLE_HTTP2
|
||||||
|
|
||||||
|
QNetworkAccessManager *Downloader::manager()
|
||||||
|
{
|
||||||
|
static QNetworkAccessManager manager;
|
||||||
|
return &manager;
|
||||||
|
}
|
||||||
|
|
||||||
bool Downloader::doDownload(const Download &dl,
|
bool Downloader::doDownload(const Download &dl,
|
||||||
const QByteArray &authorization, const Redirect *redirect)
|
const QByteArray &authorization, const Redirect *redirect)
|
||||||
{
|
{
|
||||||
QUrl url(dl.url());
|
const QUrl &url = dl.url();
|
||||||
|
|
||||||
if (!url.isValid() || !(url.scheme() == "http" || url.scheme() == "https")) {
|
if (!url.isValid() || !(url.scheme() == QLatin1String("http")
|
||||||
qWarning("%s: Invalid URL\n", qPrintable(url.toString()));
|
|| url.scheme() == QLatin1String("https"))) {
|
||||||
|
qWarning("%s: Invalid URL", qPrintable(url.toString()));
|
||||||
if (redirect)
|
if (redirect)
|
||||||
_errorDownloads.insert(redirect->origin(), RETRIES);
|
_errorDownloads.insert(redirect->origin(), RETRIES);
|
||||||
return false;
|
return false;
|
||||||
@ -115,7 +123,7 @@ bool Downloader::doDownload(const Download &dl,
|
|||||||
QVariant(_http2));
|
QVariant(_http2));
|
||||||
#endif // ENABLE_HTTP2
|
#endif // ENABLE_HTTP2
|
||||||
|
|
||||||
QNetworkReply *reply = _manager->get(request);
|
QNetworkReply *reply = manager()->get(request);
|
||||||
if (reply && reply->isRunning()) {
|
if (reply && reply->isRunning()) {
|
||||||
_currentDownloads.insert(url);
|
_currentDownloads.insert(url);
|
||||||
ReplyTimeout::setTimeout(reply, _timeout);
|
ReplyTimeout::setTimeout(reply, _timeout);
|
||||||
@ -138,7 +146,7 @@ bool Downloader::saveToDisk(const QString &filename, QIODevice *data)
|
|||||||
QFile file(filename);
|
QFile file(filename);
|
||||||
|
|
||||||
if (!file.open(QIODevice::WriteOnly)) {
|
if (!file.open(QIODevice::WriteOnly)) {
|
||||||
qWarning("Error writing file: %s: %s\n",
|
qWarning("Error writing file: %s: %s",
|
||||||
qPrintable(filename), qPrintable(file.errorString()));
|
qPrintable(filename), qPrintable(file.errorString()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -159,34 +167,33 @@ void Downloader::insertError(const QUrl &url, QNetworkReply::NetworkError error)
|
|||||||
|
|
||||||
void Downloader::downloadFinished(QNetworkReply *reply)
|
void Downloader::downloadFinished(QNetworkReply *reply)
|
||||||
{
|
{
|
||||||
QUrl url = reply->request().url();
|
QUrl url(reply->request().url());
|
||||||
QNetworkReply::NetworkError error = reply->error();
|
QNetworkReply::NetworkError error = reply->error();
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
QUrl origin = reply->request().attribute(ATTR_ORIGIN).toUrl();
|
QUrl origin(reply->request().attribute(ATTR_ORIGIN).toUrl());
|
||||||
if (origin.isEmpty()) {
|
if (origin.isEmpty()) {
|
||||||
insertError(url, error);
|
insertError(url, error);
|
||||||
qWarning("Error downloading file: %s: %s\n",
|
qWarning("Error downloading file: %s: %s",
|
||||||
url.toEncoded().constData(), qPrintable(reply->errorString()));
|
url.toEncoded().constData(), qPrintable(reply->errorString()));
|
||||||
} else {
|
} else {
|
||||||
insertError(origin, error);
|
insertError(origin, error);
|
||||||
qWarning("Error downloading file: %s -> %s: %s\n",
|
qWarning("Error downloading file: %s -> %s: %s",
|
||||||
origin.toEncoded().constData(), url.toEncoded().constData(),
|
origin.toEncoded().constData(), url.toEncoded().constData(),
|
||||||
qPrintable(reply->errorString()));
|
qPrintable(reply->errorString()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
QUrl location = reply->attribute(ATTR_REDIRECT).toUrl();
|
QUrl location(reply->attribute(ATTR_REDIRECT).toUrl());
|
||||||
QString filename = reply->request().attribute(ATTR_FILE)
|
QString filename(reply->request().attribute(ATTR_FILE).toString());
|
||||||
.toString();
|
|
||||||
|
|
||||||
if (!location.isEmpty()) {
|
if (!location.isEmpty()) {
|
||||||
QUrl origin = reply->request().attribute(ATTR_ORIGIN).toUrl();
|
QUrl origin(reply->request().attribute(ATTR_ORIGIN).toUrl());
|
||||||
int level = reply->request().attribute(ATTR_LEVEL).toInt();
|
int level = reply->request().attribute(ATTR_LEVEL).toInt();
|
||||||
|
|
||||||
if (level >= MAX_REDIRECT_LEVEL) {
|
if (level >= MAX_REDIRECT_LEVEL) {
|
||||||
_errorDownloads.insert(origin, RETRIES);
|
_errorDownloads.insert(origin, RETRIES);
|
||||||
qWarning("Error downloading file: %s: "
|
qWarning("Error downloading file: %s: "
|
||||||
"redirect level limit reached (redirect loop?)\n",
|
"redirect level limit reached (redirect loop?)",
|
||||||
origin.toEncoded().constData());
|
origin.toEncoded().constData());
|
||||||
} else {
|
} else {
|
||||||
QUrl redirectUrl;
|
QUrl redirectUrl;
|
||||||
@ -225,3 +232,11 @@ bool Downloader::get(const QList<Download> &list,
|
|||||||
|
|
||||||
return finishEmitted;
|
return finishEmitted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP2
|
||||||
|
void Downloader::enableHTTP2(bool enable)
|
||||||
|
{
|
||||||
|
_http2 = enable;
|
||||||
|
manager()->clearConnectionCache();
|
||||||
|
}
|
||||||
|
#endif // ENABLE_HTTP2
|
||||||
|
@ -15,8 +15,8 @@ class Download
|
|||||||
public:
|
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 QUrl &url() const {return _url;}
|
||||||
const QString& file() const {return _file;}
|
const QString &file() const {return _file;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QUrl _url;
|
QUrl _url;
|
||||||
@ -48,10 +48,8 @@ public:
|
|||||||
|
|
||||||
static void setTimeout(int timeout) {_timeout = timeout;}
|
static void setTimeout(int timeout) {_timeout = timeout;}
|
||||||
#ifdef ENABLE_HTTP2
|
#ifdef ENABLE_HTTP2
|
||||||
static void enableHTTP2(bool enable) {_http2 = enable;}
|
static void enableHTTP2(bool enable);
|
||||||
#endif // ENABLE_HTTP2
|
#endif // ENABLE_HTTP2
|
||||||
static void setNetworkAccessManager(QNetworkAccessManager *manager)
|
|
||||||
{_manager = manager;}
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void finished();
|
void finished();
|
||||||
@ -69,6 +67,8 @@ private:
|
|||||||
const Redirect *redirect = 0);
|
const Redirect *redirect = 0);
|
||||||
bool saveToDisk(const QString &filename, QIODevice *data);
|
bool saveToDisk(const QString &filename, QIODevice *data);
|
||||||
|
|
||||||
|
static QNetworkAccessManager *manager();
|
||||||
|
|
||||||
QSet<QUrl> _currentDownloads;
|
QSet<QUrl> _currentDownloads;
|
||||||
QHash<QUrl, int> _errorDownloads;
|
QHash<QUrl, int> _errorDownloads;
|
||||||
|
|
||||||
@ -76,7 +76,6 @@ private:
|
|||||||
#ifdef ENABLE_HTTP2
|
#ifdef ENABLE_HTTP2
|
||||||
static bool _http2;
|
static bool _http2;
|
||||||
#endif // ENABLE_HTTP2
|
#endif // ENABLE_HTTP2
|
||||||
static QNetworkAccessManager *_manager;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DOWNLOADER_H
|
#endif // DOWNLOADER_H
|
||||||
|
@ -1,41 +1,18 @@
|
|||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include "common/coordinates.h"
|
|
||||||
#include "common/rectc.h"
|
#include "common/rectc.h"
|
||||||
#include "common/wgs84.h"
|
#include "osm.h"
|
||||||
#include "emptymap.h"
|
#include "emptymap.h"
|
||||||
|
|
||||||
|
|
||||||
#define ZOOM_MIN 0
|
|
||||||
#define ZOOM_MAX 19
|
|
||||||
#define TILE_SIZE 256
|
#define TILE_SIZE 256
|
||||||
|
|
||||||
static QPointF ll2m(const Coordinates &c)
|
|
||||||
{
|
|
||||||
return QPointF(c.lon(), rad2deg(log(tan(M_PI_4 + deg2rad(c.lat())/2.0))));
|
|
||||||
}
|
|
||||||
|
|
||||||
static Coordinates m2ll(const QPointF &p)
|
|
||||||
{
|
|
||||||
return Coordinates(p.x(), rad2deg(2.0 * 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)
|
static int limitZoom(int zoom)
|
||||||
{
|
{
|
||||||
if (zoom < ZOOM_MIN)
|
if (zoom < OSM::ZOOMS.min())
|
||||||
return ZOOM_MIN;
|
return OSM::ZOOMS.min();
|
||||||
if (zoom > ZOOM_MAX)
|
if (zoom > OSM::ZOOMS.max())
|
||||||
return ZOOM_MAX;
|
return OSM::ZOOMS.max();
|
||||||
|
|
||||||
return zoom;
|
return zoom;
|
||||||
}
|
}
|
||||||
@ -43,23 +20,23 @@ static int limitZoom(int zoom)
|
|||||||
|
|
||||||
EmptyMap::EmptyMap(QObject *parent) : Map(parent)
|
EmptyMap::EmptyMap(QObject *parent) : Map(parent)
|
||||||
{
|
{
|
||||||
_zoom = ZOOM_MAX;
|
_zoom = OSM::ZOOMS.max();
|
||||||
}
|
}
|
||||||
|
|
||||||
QRectF EmptyMap::bounds()
|
QRectF EmptyMap::bounds()
|
||||||
{
|
{
|
||||||
return QRectF(ll2xy(Coordinates(-180, 85)), ll2xy(Coordinates(180, -85)));
|
return QRectF(ll2xy(OSM::BOUNDS.topLeft()), ll2xy(OSM::BOUNDS.bottomRight()));
|
||||||
}
|
}
|
||||||
|
|
||||||
int EmptyMap::zoomFit(const QSize &size, const RectC &rect)
|
int EmptyMap::zoomFit(const QSize &size, const RectC &rect)
|
||||||
{
|
{
|
||||||
if (!rect.isValid())
|
if (!rect.isValid())
|
||||||
_zoom = ZOOM_MAX;
|
_zoom = OSM::ZOOMS.max();
|
||||||
else {
|
else {
|
||||||
QRectF tbr(ll2m(rect.topLeft()), ll2m(rect.bottomRight()));
|
QRectF tbr(OSM::ll2m(rect.topLeft()), OSM::ll2m(rect.bottomRight()));
|
||||||
QPointF sc(tbr.width() / size.width(), tbr.height() / size.height());
|
QPointF sc(tbr.width() / size.width(), tbr.height() / size.height());
|
||||||
|
|
||||||
_zoom = limitZoom(scale2zoom(qMax(sc.x(), -sc.y())));
|
_zoom = limitZoom(OSM::scale2zoom(qMax(sc.x(), -sc.y()), TILE_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
return _zoom;
|
return _zoom;
|
||||||
@ -67,40 +44,37 @@ int EmptyMap::zoomFit(const QSize &size, const RectC &rect)
|
|||||||
|
|
||||||
qreal EmptyMap::resolution(const QRectF &rect)
|
qreal EmptyMap::resolution(const QRectF &rect)
|
||||||
{
|
{
|
||||||
qreal scale = zoom2scale(_zoom);
|
return OSM::resolution(rect.center(), _zoom, TILE_SIZE);
|
||||||
|
|
||||||
return (WGS84_RADIUS * 2.0 * M_PI * scale / 360.0
|
|
||||||
* cos(2.0 * atan(exp(deg2rad(-rect.center().y() * scale))) - M_PI/2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int EmptyMap::zoomIn()
|
int EmptyMap::zoomIn()
|
||||||
{
|
{
|
||||||
_zoom = qMin(_zoom + 1, ZOOM_MAX);
|
_zoom = qMin(_zoom + 1, OSM::ZOOMS.max());
|
||||||
return _zoom;
|
return _zoom;
|
||||||
}
|
}
|
||||||
|
|
||||||
int EmptyMap::zoomOut()
|
int EmptyMap::zoomOut()
|
||||||
{
|
{
|
||||||
_zoom = qMax(_zoom - 1, ZOOM_MIN);
|
_zoom = qMax(_zoom - 1, OSM::ZOOMS.min());
|
||||||
return _zoom;
|
return _zoom;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmptyMap::draw(QPainter *painter, const QRectF &rect, bool block)
|
void EmptyMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||||
{
|
{
|
||||||
Q_UNUSED(painter);
|
Q_UNUSED(painter);
|
||||||
Q_UNUSED(rect);
|
Q_UNUSED(rect);
|
||||||
Q_UNUSED(block);
|
Q_UNUSED(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
QPointF EmptyMap::ll2xy(const Coordinates &c)
|
QPointF EmptyMap::ll2xy(const Coordinates &c)
|
||||||
{
|
{
|
||||||
qreal scale = zoom2scale(_zoom);
|
qreal scale = OSM::zoom2scale(_zoom, TILE_SIZE);
|
||||||
QPointF m = ll2m(c);
|
QPointF m = OSM::ll2m(c);
|
||||||
return QPointF(m.x() / scale, m.y() / -scale);
|
return QPointF(m.x() / scale, m.y() / -scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
Coordinates EmptyMap::xy2ll(const QPointF &p)
|
Coordinates EmptyMap::xy2ll(const QPointF &p)
|
||||||
{
|
{
|
||||||
qreal scale = zoom2scale(_zoom);
|
qreal scale = OSM::zoom2scale(_zoom, TILE_SIZE);
|
||||||
return m2ll(QPointF(p.x() * scale, -p.y() * scale));
|
return OSM::m2ll(QPointF(p.x() * scale, -p.y() * scale));
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ public:
|
|||||||
QPointF ll2xy(const Coordinates &c);
|
QPointF ll2xy(const Coordinates &c);
|
||||||
Coordinates xy2ll(const QPointF &p);
|
Coordinates xy2ll(const QPointF &p);
|
||||||
|
|
||||||
void draw(QPainter *painter, const QRectF &rect, bool block);
|
void draw(QPainter *painter, const QRectF &rect, Flags flags);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int _zoom;
|
int _zoom;
|
||||||
|
81
src/map/geotiffmap.cpp
Normal file
81
src/map/geotiffmap.cpp
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#include <QFileInfo>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QImageReader>
|
||||||
|
#include "config.h"
|
||||||
|
#include "geotiff.h"
|
||||||
|
#include "image.h"
|
||||||
|
#include "geotiffmap.h"
|
||||||
|
|
||||||
|
|
||||||
|
GeoTIFFMap::GeoTIFFMap(const QString &fileName, QObject *parent)
|
||||||
|
: Map(parent), _fileName(fileName), _img(0), _ratio(1.0), _valid(false)
|
||||||
|
{
|
||||||
|
QImageReader ir(fileName);
|
||||||
|
if (!ir.canRead()) {
|
||||||
|
_errorString = "Unsupported/invalid image file";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_size = ir.size();
|
||||||
|
|
||||||
|
GeoTIFF gt(fileName);
|
||||||
|
if (!gt.isValid()) {
|
||||||
|
_errorString = gt.errorString();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
_projection = gt.projection();
|
||||||
|
_transform = gt.transform();
|
||||||
|
}
|
||||||
|
|
||||||
|
_valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
GeoTIFFMap::~GeoTIFFMap()
|
||||||
|
{
|
||||||
|
delete _img;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString GeoTIFFMap::name() const
|
||||||
|
{
|
||||||
|
QFileInfo fi(_fileName);
|
||||||
|
return fi.fileName();
|
||||||
|
}
|
||||||
|
|
||||||
|
QPointF GeoTIFFMap::ll2xy(const Coordinates &c)
|
||||||
|
{
|
||||||
|
return QPointF(_transform.proj2img(_projection.ll2xy(c))) / _ratio;
|
||||||
|
}
|
||||||
|
|
||||||
|
Coordinates GeoTIFFMap::xy2ll(const QPointF &p)
|
||||||
|
{
|
||||||
|
return _projection.xy2ll(_transform.img2proj(p * _ratio));
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF GeoTIFFMap::bounds()
|
||||||
|
{
|
||||||
|
return QRectF(QPointF(0, 0), _size / _ratio);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GeoTIFFMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||||
|
{
|
||||||
|
if (_img)
|
||||||
|
_img->draw(painter, rect, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GeoTIFFMap::setDevicePixelRatio(qreal ratio)
|
||||||
|
{
|
||||||
|
_ratio = ratio;
|
||||||
|
if (_img)
|
||||||
|
_img->setDevicePixelRatio(_ratio);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GeoTIFFMap::load()
|
||||||
|
{
|
||||||
|
if (!_img)
|
||||||
|
_img = new Image(_fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GeoTIFFMap::unload()
|
||||||
|
{
|
||||||
|
delete _img;
|
||||||
|
_img = 0;
|
||||||
|
}
|
45
src/map/geotiffmap.h
Normal file
45
src/map/geotiffmap.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#ifndef GEOTIFFMAP_H
|
||||||
|
#define GEOTIFFMAP_H
|
||||||
|
|
||||||
|
#include "transform.h"
|
||||||
|
#include "projection.h"
|
||||||
|
#include "map.h"
|
||||||
|
|
||||||
|
class Image;
|
||||||
|
|
||||||
|
class GeoTIFFMap : public Map
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
GeoTIFFMap(const QString &fileName, QObject *parent = 0);
|
||||||
|
~GeoTIFFMap();
|
||||||
|
|
||||||
|
QString name() const;
|
||||||
|
|
||||||
|
QRectF bounds();
|
||||||
|
QPointF ll2xy(const Coordinates &c);
|
||||||
|
Coordinates xy2ll(const QPointF &p);
|
||||||
|
|
||||||
|
void draw(QPainter *painter, const QRectF &rect, Flags flags);
|
||||||
|
|
||||||
|
void load();
|
||||||
|
void unload();
|
||||||
|
void setDevicePixelRatio(qreal ratio);
|
||||||
|
|
||||||
|
bool isValid() const {return _valid;}
|
||||||
|
QString errorString() const {return _errorString;}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString _fileName;
|
||||||
|
Projection _projection;
|
||||||
|
Transform _transform;
|
||||||
|
Image *_img;
|
||||||
|
QSize _size;
|
||||||
|
qreal _ratio;
|
||||||
|
|
||||||
|
bool _valid;
|
||||||
|
QString _errorString;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // GEOTIFFMAP_H
|
53
src/map/image.cpp
Normal file
53
src/map/image.cpp
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#include <QPainter>
|
||||||
|
#include <QPixmapCache>
|
||||||
|
#include "config.h"
|
||||||
|
#include "image.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define TILE_SIZE 256
|
||||||
|
|
||||||
|
Image::Image(const QString &fileName) : _img(fileName), _fileName(fileName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::draw(QPainter *painter, const QRectF &rect, Map::Flags flags)
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_HIDPI
|
||||||
|
qreal ratio = _img.devicePixelRatioF();
|
||||||
|
#else // ENABLE_HIDPI
|
||||||
|
qreal ratio = 1.0;
|
||||||
|
#endif // ENABLE_HIDPI
|
||||||
|
QRectF sr(rect.topLeft() * ratio, rect.size() * ratio);
|
||||||
|
|
||||||
|
if (flags & Map::OpenGL) {
|
||||||
|
for (int i = sr.left()/TILE_SIZE; i <= sr.right()/TILE_SIZE; i++) {
|
||||||
|
for (int j = sr.top()/TILE_SIZE; j <= sr.bottom()/TILE_SIZE; j++) {
|
||||||
|
QString key = _fileName + "-" + QString::number(i) + "_"
|
||||||
|
+ QString::number(j);
|
||||||
|
QPoint tl(i * TILE_SIZE, j * TILE_SIZE);
|
||||||
|
QPixmap pm;
|
||||||
|
|
||||||
|
if (!QPixmapCache::find(key, &pm)) {
|
||||||
|
QRect tile(tl, QSize(TILE_SIZE, TILE_SIZE));
|
||||||
|
pm = QPixmap::fromImage(_img.copy(tile));
|
||||||
|
if (!pm.isNull())
|
||||||
|
QPixmapCache::insert(key, pm);
|
||||||
|
}
|
||||||
|
#ifdef ENABLE_HIDPI
|
||||||
|
pm.setDevicePixelRatio(ratio);
|
||||||
|
#endif // ENABLE_HIDPI
|
||||||
|
painter->drawPixmap(tl/ratio, pm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
painter->drawImage(rect.topLeft(), _img, sr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::setDevicePixelRatio(qreal ratio)
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_HIDPI
|
||||||
|
_img.setDevicePixelRatio(ratio);
|
||||||
|
#else // ENABLE_HIDPI
|
||||||
|
Q_UNUSED(ratio);
|
||||||
|
#endif // ENABLE_HIDPI
|
||||||
|
}
|
22
src/map/image.h
Normal file
22
src/map/image.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#ifndef IMAGE_H
|
||||||
|
#define IMAGE_H
|
||||||
|
|
||||||
|
#include <QImage>
|
||||||
|
#include "map.h"
|
||||||
|
|
||||||
|
class QPainter;
|
||||||
|
|
||||||
|
class Image
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Image(const QString &fileName);
|
||||||
|
|
||||||
|
void draw(QPainter *painter, const QRectF &rect, Map::Flags flags);
|
||||||
|
void setDevicePixelRatio(qreal ratio);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QImage _img;
|
||||||
|
QString _fileName;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // IMAGE_H
|
@ -245,9 +245,9 @@ bool JNXMap::cb(Tile *tile, void *context)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void JNXMap::draw(QPainter *painter, const QRectF &rect, bool block)
|
void JNXMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||||
{
|
{
|
||||||
Q_UNUSED(block);
|
Q_UNUSED(flags);
|
||||||
const RTree<Tile*, qreal, 2> &tree = _zooms.at(_zoom).tree;
|
const RTree<Tile*, qreal, 2> &tree = _zooms.at(_zoom).tree;
|
||||||
Ctx ctx(painter, &_file, _ratio);
|
Ctx ctx(painter, &_file, _ratio);
|
||||||
QRectF rr(rect.topLeft() * _ratio, rect.size() * _ratio);
|
QRectF rr(rect.topLeft() * _ratio, rect.size() * _ratio);
|
||||||
|
@ -30,7 +30,7 @@ public:
|
|||||||
QPointF ll2xy(const Coordinates &c);
|
QPointF ll2xy(const Coordinates &c);
|
||||||
Coordinates xy2ll(const QPointF &p);
|
Coordinates xy2ll(const QPointF &p);
|
||||||
|
|
||||||
void draw(QPainter *painter, const QRectF &rect, bool block);
|
void draw(QPainter *painter, const QRectF &rect, Flags flags);
|
||||||
|
|
||||||
void setDevicePixelRatio(qreal ratio) {_ratio = ratio;}
|
void setDevicePixelRatio(qreal ratio) {_ratio = ratio;}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QRectF>
|
#include <QRectF>
|
||||||
|
#include <QFlags>
|
||||||
#include "common/coordinates.h"
|
#include "common/coordinates.h"
|
||||||
|
|
||||||
class QPainter;
|
class QPainter;
|
||||||
@ -14,6 +15,13 @@ class Map : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum Flag {
|
||||||
|
NoFlags = 0,
|
||||||
|
Block = 1,
|
||||||
|
OpenGL = 2
|
||||||
|
};
|
||||||
|
Q_DECLARE_FLAGS(Flags, Flag)
|
||||||
|
|
||||||
Map(QObject *parent = 0) : QObject(parent) {}
|
Map(QObject *parent = 0) : QObject(parent) {}
|
||||||
virtual ~Map() {}
|
virtual ~Map() {}
|
||||||
|
|
||||||
@ -22,21 +30,21 @@ public:
|
|||||||
virtual QRectF bounds() = 0;
|
virtual QRectF bounds() = 0;
|
||||||
virtual qreal resolution(const QRectF &rect);
|
virtual qreal resolution(const QRectF &rect);
|
||||||
|
|
||||||
virtual int zoom() const = 0;
|
virtual int zoom() const {return 0;}
|
||||||
virtual void setZoom(int zoom) = 0;
|
virtual void setZoom(int) {}
|
||||||
virtual int zoomFit(const QSize &size, const RectC &rect) = 0;
|
virtual int zoomFit(const QSize &, const RectC &) {return 0;}
|
||||||
virtual int zoomIn() = 0;
|
virtual int zoomIn() {return 0;}
|
||||||
virtual int zoomOut() = 0;
|
virtual int zoomOut() {return 0;}
|
||||||
|
|
||||||
virtual QPointF ll2xy(const Coordinates &c) = 0;
|
virtual QPointF ll2xy(const Coordinates &c) = 0;
|
||||||
virtual Coordinates xy2ll(const QPointF &p) = 0;
|
virtual Coordinates xy2ll(const QPointF &p) = 0;
|
||||||
|
|
||||||
virtual void draw(QPainter *painter, const QRectF &rect, bool block) = 0;
|
virtual void draw(QPainter *painter, const QRectF &rect, Flags flags) = 0;
|
||||||
|
|
||||||
virtual void clearCache() {}
|
virtual void clearCache() {}
|
||||||
virtual void load() {}
|
virtual void load() {}
|
||||||
virtual void unload() {}
|
virtual void unload() {}
|
||||||
virtual void setDevicePixelRatio(qreal ratio) {Q_UNUSED(ratio);}
|
virtual void setDevicePixelRatio(qreal) {}
|
||||||
|
|
||||||
virtual bool isValid() const {return true;}
|
virtual bool isValid() const {return true;}
|
||||||
virtual QString errorString() const {return QString();}
|
virtual QString errorString() const {return QString();}
|
||||||
@ -45,4 +53,6 @@ signals:
|
|||||||
void loaded();
|
void loaded();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_OPERATORS_FOR_FLAGS(Map::Flags)
|
||||||
|
|
||||||
#endif // MAP_H
|
#endif // MAP_H
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include "atlas.h"
|
#include "atlas.h"
|
||||||
#include "offlinemap.h"
|
#include "ozimap.h"
|
||||||
#include "onlinemap.h"
|
#include "onlinemap.h"
|
||||||
#include "jnxmap.h"
|
#include "jnxmap.h"
|
||||||
|
#include "geotiffmap.h"
|
||||||
#include "mapsource.h"
|
#include "mapsource.h"
|
||||||
|
#include "mbtilesmap.h"
|
||||||
#include "maplist.h"
|
#include "maplist.h"
|
||||||
|
|
||||||
|
|
||||||
@ -53,8 +55,12 @@ bool MapList::loadFile(const QString &path, bool *atlas, bool dir)
|
|||||||
return loadSource(path, dir);
|
return loadSource(path, dir);
|
||||||
else if (suffix == "jnx")
|
else if (suffix == "jnx")
|
||||||
return loadMap(new JNXMap(path, this), path, dir);
|
return loadMap(new JNXMap(path, this), path, dir);
|
||||||
|
else if (suffix == "tif" || suffix == "tiff")
|
||||||
|
return loadMap(new GeoTIFFMap(path, this), path, dir);
|
||||||
|
else if (suffix == "mbtiles")
|
||||||
|
return loadMap(new MBTilesMap(path, this), path, dir);
|
||||||
else
|
else
|
||||||
return loadMap(new OfflineMap(path, this), path, dir);
|
return loadMap(new OziMap(path, this), path, dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MapList::loadDirR(const QString &path)
|
bool MapList::loadDirR(const QString &path)
|
||||||
@ -108,7 +114,9 @@ void MapList::clear()
|
|||||||
QString MapList::formats()
|
QString MapList::formats()
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
tr("Supported files") + " (*.jnx *.map *.tar *.tba *.tif *.tiff *.xml);;"
|
tr("Supported files")
|
||||||
|
+ " (*.jnx *.map *.mbtiles *.tar *.tba *.tif *.tiff *.xml);;"
|
||||||
|
+ tr("MBTiles maps") + " (*.mbtiles);;"
|
||||||
+ tr("Garmin JNX maps") + " (*.jnx);;"
|
+ tr("Garmin JNX maps") + " (*.jnx);;"
|
||||||
+ tr("OziExplorer maps") + " (*.map);;"
|
+ tr("OziExplorer maps") + " (*.map);;"
|
||||||
+ tr("TrekBuddy maps/atlases") + " (*.tar *.tba);;"
|
+ tr("TrekBuddy maps/atlases") + " (*.tar *.tba);;"
|
||||||
@ -120,6 +128,6 @@ QStringList MapList::filter()
|
|||||||
{
|
{
|
||||||
QStringList filter;
|
QStringList filter;
|
||||||
filter << "*.jnx" << "*.map" << "*.tba" << "*.tar" << "*.xml" << "*.tif"
|
filter << "*.jnx" << "*.map" << "*.tba" << "*.tar" << "*.xml" << "*.tif"
|
||||||
<< "*.tiff";
|
<< "*.tiff" << "*.mbtiles";
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,15 @@
|
|||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QXmlStreamReader>
|
#include <QXmlStreamReader>
|
||||||
|
#include "config.h"
|
||||||
#include "onlinemap.h"
|
#include "onlinemap.h"
|
||||||
#include "wmtsmap.h"
|
#include "wmtsmap.h"
|
||||||
#include "wmsmap.h"
|
#include "wmsmap.h"
|
||||||
|
#include "osm.h"
|
||||||
#include "mapsource.h"
|
#include "mapsource.h"
|
||||||
|
|
||||||
#define ZOOM_MAX 19
|
|
||||||
#define ZOOM_MIN 0
|
|
||||||
#define BOUNDS_LEFT -180
|
|
||||||
#define BOUNDS_TOP 85.0511
|
|
||||||
#define BOUNDS_RIGHT 180
|
|
||||||
#define BOUNDS_BOTTOM -85.0511
|
|
||||||
|
|
||||||
|
MapSource::Config::Config() : type(OSM), zooms(OSM::ZOOMS), bounds(OSM::BOUNDS),
|
||||||
MapSource::Config::Config() : type(OSM), zooms(ZOOM_MIN, ZOOM_MAX),
|
format("image/png"), rest(false), tileRatio(1.0) {}
|
||||||
bounds(Coordinates(BOUNDS_LEFT, BOUNDS_TOP), Coordinates(BOUNDS_RIGHT,
|
|
||||||
BOUNDS_BOTTOM)), format("image/png"), rest(false), tileRatio(1.0) {}
|
|
||||||
|
|
||||||
|
|
||||||
static CoordinateSystem coordinateSystem(QXmlStreamReader &reader)
|
static CoordinateSystem coordinateSystem(QXmlStreamReader &reader)
|
||||||
@ -37,21 +31,21 @@ Range MapSource::zooms(QXmlStreamReader &reader)
|
|||||||
|
|
||||||
if (attr.hasAttribute("min")) {
|
if (attr.hasAttribute("min")) {
|
||||||
min = attr.value("min").toString().toInt(&res);
|
min = attr.value("min").toString().toInt(&res);
|
||||||
if (!res || (min < ZOOM_MIN || min > ZOOM_MAX)) {
|
if (!res || !OSM::ZOOMS.contains(min)) {
|
||||||
reader.raiseError("Invalid minimal zoom level");
|
reader.raiseError("Invalid minimal zoom level");
|
||||||
return Range();
|
return Range();
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
min = ZOOM_MIN;
|
min = OSM::ZOOMS.min();
|
||||||
|
|
||||||
if (attr.hasAttribute("max")) {
|
if (attr.hasAttribute("max")) {
|
||||||
max = attr.value("max").toString().toInt(&res);
|
max = attr.value("max").toString().toInt(&res);
|
||||||
if (!res || (max < ZOOM_MIN || max > ZOOM_MAX)) {
|
if (!res || !OSM::ZOOMS.contains(max)) {
|
||||||
reader.raiseError("Invalid maximal zoom level");
|
reader.raiseError("Invalid maximal zoom level");
|
||||||
return Range();
|
return Range();
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
max = ZOOM_MAX;
|
max = OSM::ZOOMS.max();
|
||||||
|
|
||||||
if (min > max) {
|
if (min > max) {
|
||||||
reader.raiseError("Invalid maximal/minimal zoom level combination");
|
reader.raiseError("Invalid maximal/minimal zoom level combination");
|
||||||
@ -69,39 +63,41 @@ RectC MapSource::bounds(QXmlStreamReader &reader)
|
|||||||
|
|
||||||
if (attr.hasAttribute("top")) {
|
if (attr.hasAttribute("top")) {
|
||||||
top = attr.value("top").toString().toDouble(&res);
|
top = attr.value("top").toString().toDouble(&res);
|
||||||
if (!res || (top < BOUNDS_BOTTOM || top > BOUNDS_TOP)) {
|
if (!res || (top < OSM::BOUNDS.bottom() || top > OSM::BOUNDS.top())) {
|
||||||
reader.raiseError("Invalid bounds top value");
|
reader.raiseError("Invalid bounds top value");
|
||||||
return RectC();
|
return RectC();
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
top = BOUNDS_TOP;
|
top = OSM::BOUNDS.top();
|
||||||
|
|
||||||
if (attr.hasAttribute("bottom")) {
|
if (attr.hasAttribute("bottom")) {
|
||||||
bottom = attr.value("bottom").toString().toDouble(&res);
|
bottom = attr.value("bottom").toString().toDouble(&res);
|
||||||
if (!res || (bottom < BOUNDS_BOTTOM || bottom > BOUNDS_TOP)) {
|
if (!res || (bottom < OSM::BOUNDS.bottom()
|
||||||
|
|| bottom > OSM::BOUNDS.top())) {
|
||||||
reader.raiseError("Invalid bounds bottom value");
|
reader.raiseError("Invalid bounds bottom value");
|
||||||
return RectC();
|
return RectC();
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
bottom = BOUNDS_BOTTOM;
|
bottom = OSM::BOUNDS.bottom();
|
||||||
|
|
||||||
if (attr.hasAttribute("left")) {
|
if (attr.hasAttribute("left")) {
|
||||||
left = attr.value("left").toString().toDouble(&res);
|
left = attr.value("left").toString().toDouble(&res);
|
||||||
if (!res || (left < BOUNDS_LEFT || left > BOUNDS_RIGHT)) {
|
if (!res || (left < OSM::BOUNDS.left() || left > OSM::BOUNDS.right())) {
|
||||||
reader.raiseError("Invalid bounds left value");
|
reader.raiseError("Invalid bounds left value");
|
||||||
return RectC();
|
return RectC();
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
left = BOUNDS_LEFT;
|
left = OSM::BOUNDS.left();
|
||||||
|
|
||||||
if (attr.hasAttribute("right")) {
|
if (attr.hasAttribute("right")) {
|
||||||
right = attr.value("right").toString().toDouble(&res);
|
right = attr.value("right").toString().toDouble(&res);
|
||||||
if (!res || (right < BOUNDS_LEFT || right > BOUNDS_RIGHT)) {
|
if (!res || (right < OSM::BOUNDS.left()
|
||||||
|
|| right > OSM::BOUNDS.right())) {
|
||||||
reader.raiseError("Invalid bounds right value");
|
reader.raiseError("Invalid bounds right value");
|
||||||
return RectC();
|
return RectC();
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
right = BOUNDS_RIGHT;
|
right = OSM::BOUNDS.right();
|
||||||
|
|
||||||
if (bottom >= top) {
|
if (bottom >= top) {
|
||||||
reader.raiseError("Invalid bottom/top bounds combination");
|
reader.raiseError("Invalid bottom/top bounds combination");
|
||||||
@ -118,8 +114,20 @@ RectC MapSource::bounds(QXmlStreamReader &reader)
|
|||||||
void MapSource::map(QXmlStreamReader &reader, Config &config)
|
void MapSource::map(QXmlStreamReader &reader, Config &config)
|
||||||
{
|
{
|
||||||
const QXmlStreamAttributes &attr = reader.attributes();
|
const QXmlStreamAttributes &attr = reader.attributes();
|
||||||
config.type = (attr.value("type") == "WMTS") ? WMTS
|
QStringRef type = attr.value("type");
|
||||||
: (attr.value("type") == "WMS") ? WMS : OSM;
|
|
||||||
|
if (type == "WMTS")
|
||||||
|
config.type = WMTS;
|
||||||
|
else if (type == "WMS")
|
||||||
|
config.type = WMS;
|
||||||
|
else if (type == "TMS")
|
||||||
|
config.type = TMS;
|
||||||
|
else if (type == "OSM" || type.isEmpty())
|
||||||
|
config.type = OSM;
|
||||||
|
else {
|
||||||
|
reader.raiseError("Invalid map type");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
while (reader.readNextStartElement()) {
|
while (reader.readNextStartElement()) {
|
||||||
if (reader.name() == "name")
|
if (reader.name() == "name")
|
||||||
@ -148,8 +156,8 @@ void MapSource::map(QXmlStreamReader &reader, Config &config)
|
|||||||
if (!attr.hasAttribute("id"))
|
if (!attr.hasAttribute("id"))
|
||||||
reader.raiseError("Missing dimension id");
|
reader.raiseError("Missing dimension id");
|
||||||
else
|
else
|
||||||
config.dimensions.append(QPair<QString, QString>(
|
config.dimensions.append(KV(attr.value("id").toString(),
|
||||||
attr.value("id").toString(), reader.readElementText()));
|
reader.readElementText()));
|
||||||
} else if (reader.name() == "crs") {
|
} else if (reader.name() == "crs") {
|
||||||
config.coordinateSystem = coordinateSystem(reader);
|
config.coordinateSystem = coordinateSystem(reader);
|
||||||
config.crs = reader.readElementText();
|
config.crs = reader.readElementText();
|
||||||
@ -160,12 +168,16 @@ void MapSource::map(QXmlStreamReader &reader, Config &config)
|
|||||||
attr.value("password").toString());
|
attr.value("password").toString());
|
||||||
reader.skipCurrentElement();
|
reader.skipCurrentElement();
|
||||||
} else if (reader.name() == "tilePixelRatio") {
|
} else if (reader.name() == "tilePixelRatio") {
|
||||||
|
#ifdef ENABLE_HIDPI
|
||||||
bool res;
|
bool res;
|
||||||
qreal val = reader.readElementText().toDouble(&res);
|
qreal val = reader.readElementText().toDouble(&res);
|
||||||
if (!res)
|
if (!res)
|
||||||
reader.raiseError("Invalid tilePixelRatio");
|
reader.raiseError("Invalid tilePixelRatio");
|
||||||
else
|
else
|
||||||
config.tileRatio = val;
|
config.tileRatio = val;
|
||||||
|
#else // ENABLE_HIDPI
|
||||||
|
reader.raiseError("HiDPI maps not supported");
|
||||||
|
#endif // ENABLE_HIDPI
|
||||||
} else
|
} else
|
||||||
reader.skipCurrentElement();
|
reader.skipCurrentElement();
|
||||||
}
|
}
|
||||||
@ -226,16 +238,23 @@ Map *MapSource::loadMap(const QString &path, QString &errorString)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.type == WMTS)
|
switch (config.type) {
|
||||||
return new WMTSMap(config.name, WMTS::Setup(config.url, config.layer,
|
case WMTS:
|
||||||
config.set, config.style, config.format, config.rest,
|
return new WMTSMap(config.name, WMTS::Setup(config.url, config.layer,
|
||||||
config.coordinateSystem, config.dimensions, config.authorization),
|
config.set, config.style, config.format, config.rest,
|
||||||
config.tileRatio);
|
config.coordinateSystem, config.dimensions, config.authorization),
|
||||||
else if (config.type == WMS)
|
config.tileRatio);
|
||||||
return new WMSMap(config.name, WMS::Setup(config.url, config.layer,
|
case WMS:
|
||||||
config.style, config.format, config.crs, config.coordinateSystem,
|
return new WMSMap(config.name, WMS::Setup(config.url, config.layer,
|
||||||
config.dimensions, config.authorization));
|
config.style, config.format, config.crs, config.coordinateSystem,
|
||||||
else
|
config.dimensions, config.authorization));
|
||||||
return new OnlineMap(config.name, config.url, config.zooms,
|
case TMS:
|
||||||
config.bounds, config.tileRatio, config.authorization);
|
return new OnlineMap(config.name, config.url, config.zooms,
|
||||||
|
config.bounds, config.tileRatio, config.authorization, true);
|
||||||
|
case OSM:
|
||||||
|
return new OnlineMap(config.name, config.url, config.zooms,
|
||||||
|
config.bounds, config.tileRatio, config.authorization, false);
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <QList>
|
#include <QList>
|
||||||
#include "common/range.h"
|
#include "common/range.h"
|
||||||
#include "common/rectc.h"
|
#include "common/rectc.h"
|
||||||
|
#include "common/kv.h"
|
||||||
#include "downloader.h"
|
#include "downloader.h"
|
||||||
#include "coordinatesystem.h"
|
#include "coordinatesystem.h"
|
||||||
|
|
||||||
@ -19,7 +20,8 @@ private:
|
|||||||
enum Type {
|
enum Type {
|
||||||
OSM,
|
OSM,
|
||||||
WMTS,
|
WMTS,
|
||||||
WMS
|
WMS,
|
||||||
|
TMS
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Config {
|
struct Config {
|
||||||
@ -35,7 +37,7 @@ private:
|
|||||||
QString crs;
|
QString crs;
|
||||||
CoordinateSystem coordinateSystem;
|
CoordinateSystem coordinateSystem;
|
||||||
bool rest;
|
bool rest;
|
||||||
QList<QPair<QString, QString> > dimensions;
|
QList<KV> dimensions;
|
||||||
Authorization authorization;
|
Authorization authorization;
|
||||||
qreal tileRatio;
|
qreal tileRatio;
|
||||||
|
|
||||||
|
260
src/map/mbtilesmap.cpp
Normal file
260
src/map/mbtilesmap.cpp
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
#include <QSqlQuery>
|
||||||
|
#include <QSqlRecord>
|
||||||
|
#include <QSqlField>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QPixmapCache>
|
||||||
|
#include "common/rectc.h"
|
||||||
|
#include "osm.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "mbtilesmap.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define META_TYPE(type) static_cast<QMetaType::Type>(type)
|
||||||
|
|
||||||
|
static double index2mercator(int index, int zoom)
|
||||||
|
{
|
||||||
|
return rad2deg(-M_PI + 2 * M_PI * ((double)index / (1<<zoom)));
|
||||||
|
}
|
||||||
|
|
||||||
|
MBTilesMap::MBTilesMap(const QString &fileName, QObject *parent)
|
||||||
|
: Map(parent), _fileName(fileName), _deviceRatio(1.0), _tileRatio(1.0),
|
||||||
|
_valid(false)
|
||||||
|
{
|
||||||
|
_db = QSqlDatabase::addDatabase("QSQLITE", fileName);
|
||||||
|
_db.setDatabaseName(fileName);
|
||||||
|
|
||||||
|
if (!_db.open()) {
|
||||||
|
_errorString = fileName + ": Error opening database file";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSqlRecord r = _db.record("tiles");
|
||||||
|
if (r.isEmpty()
|
||||||
|
|| r.field(0).name() != "zoom_level"
|
||||||
|
|| META_TYPE(r.field(0).type()) != QMetaType::Int
|
||||||
|
|| r.field(1).name() != "tile_column"
|
||||||
|
|| META_TYPE(r.field(1).type()) != QMetaType::Int
|
||||||
|
|| r.field(2).name() != "tile_row"
|
||||||
|
|| META_TYPE(r.field(2).type()) != QMetaType::Int
|
||||||
|
|| r.field(3).name() != "tile_data"
|
||||||
|
|| META_TYPE(r.field(3).type()) != QMetaType::QByteArray) {
|
||||||
|
_errorString = "Invalid table format";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
QSqlQuery query("SELECT min(zoom_level), max(zoom_level) FROM tiles",
|
||||||
|
_db);
|
||||||
|
if (!query.first()) {
|
||||||
|
_errorString = "Empty tile set";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_zooms = Range(query.value(0).toInt(), query.value(1).toInt());
|
||||||
|
if (_zooms.min() < 0 || !_zooms.isValid()) {
|
||||||
|
_errorString = "Invalid zoom levels";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_zoom = _zooms.max();
|
||||||
|
|
||||||
|
{
|
||||||
|
QString sql = QString("SELECT min(tile_column), min(tile_row), "
|
||||||
|
"max(tile_column), max(tile_row) FROM tiles WHERE zoom_level = %1")
|
||||||
|
.arg(_zooms.min());
|
||||||
|
QSqlQuery query(sql, _db);
|
||||||
|
query.first();
|
||||||
|
|
||||||
|
double minX = index2mercator(qMin((1<<_zooms.min()) - 1,
|
||||||
|
qMax(0, query.value(0).toInt())), _zooms.min());
|
||||||
|
double minY = index2mercator(qMin((1<<_zooms.min()) - 1,
|
||||||
|
qMax(0, query.value(1).toInt())), _zooms.min());
|
||||||
|
double maxX = index2mercator(qMin((1<<_zooms.min()) - 1,
|
||||||
|
qMax(0, query.value(2).toInt())) + 1, _zooms.min());
|
||||||
|
double maxY = index2mercator(qMin((1<<_zooms.min()) - 1,
|
||||||
|
qMax(0, query.value(3).toInt())) + 1, _zooms.min());
|
||||||
|
Coordinates tl(OSM::m2ll(QPointF(minX, maxY)));
|
||||||
|
Coordinates br(OSM::m2ll(QPointF(maxX, minY)));
|
||||||
|
// Workaround of broken zoom levels 0 and 1 due to numerical instability
|
||||||
|
tl.rlat() = qMin(tl.lat(), OSM::BOUNDS.top());
|
||||||
|
br.rlat() = qMax(br.lat(), OSM::BOUNDS.bottom());
|
||||||
|
_bounds = RectC(tl, br);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
QString sql = QString("SELECT tile_data FROM tiles LIMIT 1");
|
||||||
|
QSqlQuery query(sql, _db);
|
||||||
|
query.first();
|
||||||
|
QImage tile = QImage::fromData(query.value(0).toByteArray());
|
||||||
|
if (tile.isNull() || tile.size().width() != tile.size().height()) {
|
||||||
|
_errorString = "Unsupported/invalid tile images";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_tileSize = tile.size().width();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
QSqlQuery query("SELECT value FROM metadata WHERE name = 'name'", _db);
|
||||||
|
if (query.first())
|
||||||
|
_name = query.value(0).toString();
|
||||||
|
else {
|
||||||
|
qWarning("%s: missing map name", qPrintable(_fileName));
|
||||||
|
_name = QFileInfo(_fileName).fileName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
QSqlQuery query(
|
||||||
|
"SELECT value FROM metadata WHERE name = 'tilepixelratio'", _db);
|
||||||
|
if (query.first()) {
|
||||||
|
bool ok;
|
||||||
|
_tileRatio = query.value(0).toString().toDouble(&ok);
|
||||||
|
if (!ok) {
|
||||||
|
_errorString = "Invalid tile pixel ratio";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_db.close();
|
||||||
|
|
||||||
|
_valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MBTilesMap::load()
|
||||||
|
{
|
||||||
|
_db.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MBTilesMap::unload()
|
||||||
|
{
|
||||||
|
_db.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF MBTilesMap::bounds()
|
||||||
|
{
|
||||||
|
return QRectF(ll2xy(_bounds.topLeft()), ll2xy(_bounds.bottomRight()));
|
||||||
|
}
|
||||||
|
|
||||||
|
int MBTilesMap::limitZoom(int zoom) const
|
||||||
|
{
|
||||||
|
if (zoom < _zooms.min())
|
||||||
|
return _zooms.min();
|
||||||
|
if (zoom > _zooms.max())
|
||||||
|
return _zooms.max();
|
||||||
|
|
||||||
|
return zoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MBTilesMap::zoomFit(const QSize &size, const RectC &rect)
|
||||||
|
{
|
||||||
|
if (!rect.isValid())
|
||||||
|
_zoom = _zooms.max();
|
||||||
|
else {
|
||||||
|
QRectF tbr(OSM::ll2m(rect.topLeft()), OSM::ll2m(rect.bottomRight()));
|
||||||
|
QPointF sc(tbr.width() / size.width(), tbr.height() / size.height());
|
||||||
|
_zoom = limitZoom(OSM::scale2zoom(qMax(sc.x(), -sc.y())
|
||||||
|
/ coordinatesRatio(), _tileSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
return _zoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal MBTilesMap::resolution(const QRectF &rect)
|
||||||
|
{
|
||||||
|
return OSM::resolution(rect.center(), _zoom, _tileSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
int MBTilesMap::zoomIn()
|
||||||
|
{
|
||||||
|
_zoom = qMin(_zoom + 1, _zooms.max());
|
||||||
|
return _zoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MBTilesMap::zoomOut()
|
||||||
|
{
|
||||||
|
_zoom = qMax(_zoom - 1, _zooms.min());
|
||||||
|
return _zoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal MBTilesMap::coordinatesRatio() const
|
||||||
|
{
|
||||||
|
return _deviceRatio > 1.0 ? _deviceRatio / _tileRatio : 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal MBTilesMap::imageRatio() const
|
||||||
|
{
|
||||||
|
return _deviceRatio > 1.0 ? _deviceRatio : _tileRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal MBTilesMap::tileSize() const
|
||||||
|
{
|
||||||
|
return (_tileSize / coordinatesRatio());
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray MBTilesMap::tileData(int zoom, const QPoint &tile) const
|
||||||
|
{
|
||||||
|
QSqlQuery query(_db);
|
||||||
|
query.prepare("SELECT tile_data FROM tiles "
|
||||||
|
"WHERE zoom_level=:zoom AND tile_column=:x AND tile_row=:y");
|
||||||
|
query.bindValue(":zoom", zoom);
|
||||||
|
query.bindValue(":x", tile.x());
|
||||||
|
query.bindValue(":y", (1<<zoom) - tile.y() - 1);
|
||||||
|
query.exec();
|
||||||
|
|
||||||
|
if (query.first())
|
||||||
|
return query.value(0).toByteArray();
|
||||||
|
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MBTilesMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||||
|
{
|
||||||
|
Q_UNUSED(flags);
|
||||||
|
qreal scale = OSM::zoom2scale(_zoom, _tileSize);
|
||||||
|
QRectF b(bounds());
|
||||||
|
|
||||||
|
|
||||||
|
QPoint tile = OSM::mercator2tile(QPointF(rect.topLeft().x() * scale,
|
||||||
|
-rect.topLeft().y() * scale) * coordinatesRatio(), _zoom);
|
||||||
|
QPointF tl(floor(rect.left() / tileSize())
|
||||||
|
* tileSize(), floor(rect.top() / tileSize()) * tileSize());
|
||||||
|
|
||||||
|
QSizeF s(qMin(rect.right() - tl.x(), b.width()),
|
||||||
|
qMin(rect.bottom() - tl.y(), b.height()));
|
||||||
|
for (int i = 0; i < ceil(s.width() / tileSize()); i++) {
|
||||||
|
for (int j = 0; j < ceil(s.height() / tileSize()); j++) {
|
||||||
|
QPixmap pm;
|
||||||
|
QPoint t(tile.x() + i, tile.y() + j);
|
||||||
|
QString key = _fileName + "-" + QString::number(_zoom) + "_"
|
||||||
|
+ QString::number(t.x()) + "_" + QString::number(t.y());
|
||||||
|
|
||||||
|
if (!QPixmapCache::find(key, &pm))
|
||||||
|
if (pm.loadFromData(tileData(_zoom, t)))
|
||||||
|
QPixmapCache::insert(key, pm);
|
||||||
|
|
||||||
|
QPointF tp(qMax(tl.x(), b.left()) + (t.x() - tile.x()) * tileSize(),
|
||||||
|
qMax(tl.y(), b.top()) + (t.y() - tile.y()) * tileSize());
|
||||||
|
if (!pm.isNull()) {
|
||||||
|
#ifdef ENABLE_HIDPI
|
||||||
|
pm.setDevicePixelRatio(imageRatio());
|
||||||
|
#endif // ENABLE_HIDPI
|
||||||
|
painter->drawPixmap(tp, pm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QPointF MBTilesMap::ll2xy(const Coordinates &c)
|
||||||
|
{
|
||||||
|
qreal scale = OSM::zoom2scale(_zoom, _tileSize);
|
||||||
|
QPointF m = OSM::ll2m(c);
|
||||||
|
return QPointF(m.x() / scale, m.y() / -scale) / coordinatesRatio();
|
||||||
|
}
|
||||||
|
|
||||||
|
Coordinates MBTilesMap::xy2ll(const QPointF &p)
|
||||||
|
{
|
||||||
|
qreal scale = OSM::zoom2scale(_zoom, _tileSize);
|
||||||
|
return OSM::m2ll(QPointF(p.x() * scale, -p.y() * scale)
|
||||||
|
* coordinatesRatio());
|
||||||
|
}
|
57
src/map/mbtilesmap.h
Normal file
57
src/map/mbtilesmap.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#ifndef MBTILESMAP_H
|
||||||
|
#define MBTILESMAP_H
|
||||||
|
|
||||||
|
#include <QSqlDatabase>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include "common/range.h"
|
||||||
|
#include "map.h"
|
||||||
|
|
||||||
|
class MBTilesMap : public Map
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MBTilesMap(const QString &fileName, QObject *parent = 0);
|
||||||
|
|
||||||
|
QString name() const {return _name;}
|
||||||
|
|
||||||
|
QRectF bounds();
|
||||||
|
qreal resolution(const QRectF &rect);
|
||||||
|
|
||||||
|
int zoom() const {return _zoom;}
|
||||||
|
void setZoom(int zoom) {_zoom = zoom;}
|
||||||
|
int zoomFit(const QSize &size, const RectC &rect);
|
||||||
|
int zoomIn();
|
||||||
|
int zoomOut();
|
||||||
|
|
||||||
|
QPointF ll2xy(const Coordinates &c);
|
||||||
|
Coordinates xy2ll(const QPointF &p);
|
||||||
|
|
||||||
|
void draw(QPainter *painter, const QRectF &rect, Flags flags);
|
||||||
|
|
||||||
|
void load();
|
||||||
|
void unload();
|
||||||
|
void setDevicePixelRatio(qreal ratio) {_deviceRatio = ratio;}
|
||||||
|
|
||||||
|
bool isValid() const {return _valid;}
|
||||||
|
QString errorString() const {return _errorString;}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int limitZoom(int zoom) const;
|
||||||
|
qreal tileSize() const;
|
||||||
|
qreal coordinatesRatio() const;
|
||||||
|
qreal imageRatio() const;
|
||||||
|
QByteArray tileData(int zoom, const QPoint &tile) const;
|
||||||
|
|
||||||
|
QSqlDatabase _db;
|
||||||
|
|
||||||
|
QString _fileName, _name;
|
||||||
|
RectC _bounds;
|
||||||
|
Range _zooms;
|
||||||
|
int _zoom;
|
||||||
|
int _tileSize;
|
||||||
|
qreal _deviceRatio, _tileRatio;
|
||||||
|
|
||||||
|
bool _valid;
|
||||||
|
QString _errorString;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MBTILESMAP_H
|
@ -1,66 +1,25 @@
|
|||||||
|
#include <QtCore>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include "common/coordinates.h"
|
|
||||||
#include "common/rectc.h"
|
#include "common/rectc.h"
|
||||||
#include "common/wgs84.h"
|
|
||||||
#include "downloader.h"
|
#include "downloader.h"
|
||||||
|
#include "osm.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "onlinemap.h"
|
#include "onlinemap.h"
|
||||||
|
|
||||||
|
|
||||||
#define TILE_SIZE 256
|
#define TILE_SIZE 256
|
||||||
#define EPSILON 1e-6
|
|
||||||
|
|
||||||
static QPointF ll2m(const Coordinates &c)
|
|
||||||
{
|
|
||||||
return QPointF(c.lon(), rad2deg(log(tan(M_PI_4 + deg2rad(c.lat())/2.0))));
|
|
||||||
}
|
|
||||||
|
|
||||||
static Coordinates m2ll(const QPointF &p)
|
|
||||||
{
|
|
||||||
return Coordinates(p.x(), rad2deg(2.0 * atan(exp(deg2rad(p.y()))) - M_PI_2));
|
|
||||||
}
|
|
||||||
|
|
||||||
static QPoint mercator2tile(const QPointF &m, int z)
|
|
||||||
{
|
|
||||||
QPoint tile;
|
|
||||||
|
|
||||||
tile.setX((int)(floor((m.x() + 180.0) / 360.0 * (1<<z))));
|
|
||||||
tile.setY((int)(floor((1.0 - (m.y() / 180.0)) / 2.0 * (1<<z))));
|
|
||||||
|
|
||||||
return tile;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)) + EPSILON);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
OnlineMap::OnlineMap(const QString &name, const QString &url,
|
OnlineMap::OnlineMap(const QString &name, const QString &url,
|
||||||
const Range &zooms, const RectC &bounds, qreal tileRatio,
|
const Range &zooms, const RectC &bounds, qreal tileRatio,
|
||||||
const Authorization &authorization, QObject *parent)
|
const Authorization &authorization, bool invertY, QObject *parent)
|
||||||
: Map(parent), _name(name), _zooms(zooms), _bounds(bounds),
|
: Map(parent), _name(name), _zooms(zooms), _bounds(bounds),
|
||||||
_zoom(_zooms.max()), _deviceRatio(1.0), _tileRatio(tileRatio), _valid(false)
|
_zoom(_zooms.max()), _deviceRatio(1.0), _tileRatio(tileRatio),
|
||||||
|
_invertY(invertY)
|
||||||
{
|
{
|
||||||
QString dir(TILES_DIR + "/" + _name);
|
_tileLoader = new TileLoader(TILES_DIR + "/" + _name, this);
|
||||||
|
|
||||||
_tileLoader = new TileLoader(this);
|
|
||||||
_tileLoader->setUrl(url);
|
_tileLoader->setUrl(url);
|
||||||
_tileLoader->setDir(dir);
|
|
||||||
_tileLoader->setAuthorization(authorization);
|
_tileLoader->setAuthorization(authorization);
|
||||||
connect(_tileLoader, SIGNAL(finished()), this, SIGNAL(loaded()));
|
connect(_tileLoader, SIGNAL(finished()), this, SIGNAL(loaded()));
|
||||||
|
|
||||||
if (!QDir().mkpath(dir)) {
|
|
||||||
_errorString = "Error creating tiles dir";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_valid = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QRectF OnlineMap::bounds()
|
QRectF OnlineMap::bounds()
|
||||||
@ -83,9 +42,10 @@ int OnlineMap::zoomFit(const QSize &size, const RectC &rect)
|
|||||||
if (!rect.isValid())
|
if (!rect.isValid())
|
||||||
_zoom = _zooms.max();
|
_zoom = _zooms.max();
|
||||||
else {
|
else {
|
||||||
QRectF tbr(ll2m(rect.topLeft()), ll2m(rect.bottomRight()));
|
QRectF tbr(OSM::ll2m(rect.topLeft()), OSM::ll2m(rect.bottomRight()));
|
||||||
QPointF sc(tbr.width() / size.width(), tbr.height() / size.height());
|
QPointF sc(tbr.width() / size.width(), tbr.height() / size.height());
|
||||||
_zoom = limitZoom(scale2zoom(qMax(sc.x(), -sc.y()) / coordinatesRatio()));
|
_zoom = limitZoom(OSM::scale2zoom(qMax(sc.x(), -sc.y())
|
||||||
|
/ coordinatesRatio(), TILE_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
return _zoom;
|
return _zoom;
|
||||||
@ -93,10 +53,7 @@ int OnlineMap::zoomFit(const QSize &size, const RectC &rect)
|
|||||||
|
|
||||||
qreal OnlineMap::resolution(const QRectF &rect)
|
qreal OnlineMap::resolution(const QRectF &rect)
|
||||||
{
|
{
|
||||||
qreal scale = zoom2scale(_zoom);
|
return OSM::resolution(rect.center(), _zoom, TILE_SIZE);
|
||||||
|
|
||||||
return (WGS84_RADIUS * 2.0 * M_PI * scale / 360.0
|
|
||||||
* cos(2.0 * atan(exp(deg2rad(-rect.center().y() * scale))) - M_PI/2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int OnlineMap::zoomIn()
|
int OnlineMap::zoomIn()
|
||||||
@ -126,30 +83,39 @@ qreal OnlineMap::tileSize() const
|
|||||||
return (TILE_SIZE / coordinatesRatio());
|
return (TILE_SIZE / coordinatesRatio());
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnlineMap::draw(QPainter *painter, const QRectF &rect, bool block)
|
void OnlineMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||||
{
|
{
|
||||||
qreal scale = zoom2scale(_zoom);
|
qreal scale = OSM::zoom2scale(_zoom, TILE_SIZE);
|
||||||
|
QRectF b(bounds());
|
||||||
|
|
||||||
QPoint tile = mercator2tile(QPointF(rect.topLeft().x() * scale,
|
QPoint tile = OSM::mercator2tile(QPointF(rect.topLeft().x() * scale,
|
||||||
-rect.topLeft().y() * scale) * coordinatesRatio(), _zoom);
|
-rect.topLeft().y() * scale) * coordinatesRatio(), _zoom);
|
||||||
QPointF tl(floor(rect.left() / tileSize())
|
QPointF tl(floor(rect.left() / tileSize())
|
||||||
* tileSize(), floor(rect.top() / tileSize()) * tileSize());
|
* tileSize(), floor(rect.top() / tileSize()) * tileSize());
|
||||||
|
|
||||||
QList<Tile> tiles;
|
QSizeF s(qMin(rect.right() - tl.x(), b.width()),
|
||||||
QSizeF s(rect.right() - tl.x(), rect.bottom() - tl.y());
|
qMin(rect.bottom() - tl.y(), b.height()));
|
||||||
for (int i = 0; i < ceil(s.width() / tileSize()); i++)
|
int width = qCeil(s.width() / tileSize());
|
||||||
for (int j = 0; j < ceil(s.height() / tileSize()); j++)
|
int height = qCeil(s.height() / tileSize());
|
||||||
tiles.append(Tile(QPoint(tile.x() + i, tile.y() + j), _zoom));
|
|
||||||
|
|
||||||
if (block)
|
QVector<Tile> tiles;
|
||||||
|
tiles.reserve(width * height);
|
||||||
|
for (int i = 0; i < width; i++)
|
||||||
|
for (int j = 0; j < height; j++)
|
||||||
|
tiles.append(Tile(QPoint(tile.x() + i, _invertY ? (1<<_zoom)
|
||||||
|
- (tile.y() + j) - 1 : tile.y() + j), _zoom));
|
||||||
|
|
||||||
|
if (flags & Map::Block)
|
||||||
_tileLoader->loadTilesSync(tiles);
|
_tileLoader->loadTilesSync(tiles);
|
||||||
else
|
else
|
||||||
_tileLoader->loadTilesAsync(tiles);
|
_tileLoader->loadTilesAsync(tiles);
|
||||||
|
|
||||||
for (int i = 0; i < tiles.count(); i++) {
|
for (int i = 0; i < tiles.count(); i++) {
|
||||||
Tile &t = tiles[i];
|
Tile &t = tiles[i];
|
||||||
QPointF tp(tl.x() + (t.xy().x() - tile.x()) * tileSize(),
|
QPointF tp = _zoom ? QPointF(tl.x() + (t.xy().x() - tile.x())
|
||||||
tl.y() + (t.xy().y() - tile.y()) * tileSize());
|
* tileSize(), tl.y() + ((_invertY ? (1<<_zoom) - t.xy().y() - 1 :
|
||||||
|
t.xy().y()) - tile.y()) * tileSize()) : QPointF(-128, -128);
|
||||||
|
|
||||||
if (!t.pixmap().isNull()) {
|
if (!t.pixmap().isNull()) {
|
||||||
#ifdef ENABLE_HIDPI
|
#ifdef ENABLE_HIDPI
|
||||||
t.pixmap().setDevicePixelRatio(imageRatio());
|
t.pixmap().setDevicePixelRatio(imageRatio());
|
||||||
@ -161,13 +127,14 @@ void OnlineMap::draw(QPainter *painter, const QRectF &rect, bool block)
|
|||||||
|
|
||||||
QPointF OnlineMap::ll2xy(const Coordinates &c)
|
QPointF OnlineMap::ll2xy(const Coordinates &c)
|
||||||
{
|
{
|
||||||
qreal scale = zoom2scale(_zoom);
|
qreal scale = OSM::zoom2scale(_zoom, TILE_SIZE);
|
||||||
QPointF m = ll2m(c);
|
QPointF m = OSM::ll2m(c);
|
||||||
return QPointF(m.x() / scale, m.y() / -scale) / coordinatesRatio();
|
return QPointF(m.x() / scale, m.y() / -scale) / coordinatesRatio();
|
||||||
}
|
}
|
||||||
|
|
||||||
Coordinates OnlineMap::xy2ll(const QPointF &p)
|
Coordinates OnlineMap::xy2ll(const QPointF &p)
|
||||||
{
|
{
|
||||||
qreal scale = zoom2scale(_zoom);
|
qreal scale = OSM::zoom2scale(_zoom, TILE_SIZE);
|
||||||
return m2ll(QPointF(p.x() * scale, -p.y() * scale) * coordinatesRatio());
|
return OSM::m2ll(QPointF(p.x() * scale, -p.y() * scale)
|
||||||
|
* coordinatesRatio());
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ class OnlineMap : public Map
|
|||||||
public:
|
public:
|
||||||
OnlineMap(const QString &name, const QString &url, const Range &zooms,
|
OnlineMap(const QString &name, const QString &url, const Range &zooms,
|
||||||
const RectC &bounds, qreal tileRatio, const Authorization &authorization,
|
const RectC &bounds, qreal tileRatio, const Authorization &authorization,
|
||||||
QObject *parent = 0);
|
bool invertY, QObject *parent = 0);
|
||||||
|
|
||||||
QString name() const {return _name;}
|
QString name() const {return _name;}
|
||||||
|
|
||||||
@ -29,14 +29,11 @@ public:
|
|||||||
QPointF ll2xy(const Coordinates &c);
|
QPointF ll2xy(const Coordinates &c);
|
||||||
Coordinates xy2ll(const QPointF &p);
|
Coordinates xy2ll(const QPointF &p);
|
||||||
|
|
||||||
void draw(QPainter *painter, const QRectF &rect, bool block);
|
void draw(QPainter *painter, const QRectF &rect, Flags flags);
|
||||||
|
|
||||||
void setDevicePixelRatio(qreal ratio) {_deviceRatio = ratio;}
|
void setDevicePixelRatio(qreal ratio) {_deviceRatio = ratio;}
|
||||||
void clearCache() {_tileLoader->clearCache();}
|
void clearCache() {_tileLoader->clearCache();}
|
||||||
|
|
||||||
bool isValid() const {return _valid;}
|
|
||||||
QString errorString() const {return _errorString;}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int limitZoom(int zoom) const;
|
int limitZoom(int zoom) const;
|
||||||
qreal tileSize() const;
|
qreal tileSize() const;
|
||||||
@ -49,9 +46,7 @@ private:
|
|||||||
RectC _bounds;
|
RectC _bounds;
|
||||||
int _zoom;
|
int _zoom;
|
||||||
qreal _deviceRatio, _tileRatio;
|
qreal _deviceRatio, _tileRatio;
|
||||||
|
bool _invertY;
|
||||||
bool _valid;
|
|
||||||
QString _errorString;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ONLINEMAP_H
|
#endif // ONLINEMAP_H
|
||||||
|
40
src/map/osm.cpp
Normal file
40
src/map/osm.cpp
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#include <QtCore>
|
||||||
|
#include "common/wgs84.h"
|
||||||
|
#include "osm.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define EPSILON 1e-6
|
||||||
|
|
||||||
|
QPointF OSM::ll2m(const Coordinates &c)
|
||||||
|
{
|
||||||
|
return QPointF(c.lon(), rad2deg(log(tan(M_PI_4 + deg2rad(c.lat())/2.0))));
|
||||||
|
}
|
||||||
|
|
||||||
|
Coordinates OSM::m2ll(const QPointF &p)
|
||||||
|
{
|
||||||
|
return Coordinates(p.x(), rad2deg(2.0 * atan(exp(deg2rad(p.y()))) - M_PI_2));
|
||||||
|
}
|
||||||
|
|
||||||
|
QPoint OSM::mercator2tile(const QPointF &m, int zoom)
|
||||||
|
{
|
||||||
|
return QPoint(qFloor((m.x() + 180.0) / 360.0 * (1<<zoom)),
|
||||||
|
qFloor((1.0 - (m.y() / 180.0)) / 2.0 * (1<<zoom)));
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal OSM::zoom2scale(int zoom, int tileSize)
|
||||||
|
{
|
||||||
|
return (360.0/(qreal)((1<<zoom) * tileSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
int OSM::scale2zoom(qreal scale, int tileSize)
|
||||||
|
{
|
||||||
|
return (int)(log2(360.0/(scale * (qreal)tileSize)) + EPSILON);
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal OSM::resolution(const QPointF &p, int zoom, int tileSize)
|
||||||
|
{
|
||||||
|
qreal scale = zoom2scale(zoom, tileSize);
|
||||||
|
|
||||||
|
return (WGS84_RADIUS * 2.0 * M_PI * scale / 360.0
|
||||||
|
* cos(2.0 * atan(exp(deg2rad(-p.y() * scale))) - M_PI/2));
|
||||||
|
}
|
23
src/map/osm.h
Normal file
23
src/map/osm.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#ifndef OSM_H
|
||||||
|
#define OSM_H
|
||||||
|
|
||||||
|
#include <QPointF>
|
||||||
|
#include <common/coordinates.h>
|
||||||
|
#include <common/rectc.h>
|
||||||
|
#include <common/range.h>
|
||||||
|
|
||||||
|
namespace OSM
|
||||||
|
{
|
||||||
|
static const RectC BOUNDS(Coordinates(-180, 85.0511),
|
||||||
|
Coordinates(180, -85.0511));
|
||||||
|
static const Range ZOOMS(0, 19);
|
||||||
|
|
||||||
|
QPointF ll2m(const Coordinates &c);
|
||||||
|
Coordinates m2ll(const QPointF &p);
|
||||||
|
QPoint mercator2tile(const QPointF &m, int zoom);
|
||||||
|
qreal zoom2scale(int zoom, int tileSize);
|
||||||
|
int scale2zoom(qreal scale, int tileSize);
|
||||||
|
qreal resolution(const QPointF &p, int zoom, int tileSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // OSM_H
|
@ -3,20 +3,118 @@
|
|||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QBuffer>
|
#include <QBuffer>
|
||||||
#include <QImage>
|
|
||||||
#include <QImageReader>
|
#include <QImageReader>
|
||||||
#include <QPixmapCache>
|
#include <QPixmapCache>
|
||||||
#include "common/coordinates.h"
|
#include "common/coordinates.h"
|
||||||
#include "common/rectc.h"
|
#include "common/rectc.h"
|
||||||
#include "tar.h"
|
#include "tar.h"
|
||||||
#include "ozf.h"
|
#include "ozf.h"
|
||||||
|
#include "image.h"
|
||||||
#include "mapfile.h"
|
#include "mapfile.h"
|
||||||
#include "geotiff.h"
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "offlinemap.h"
|
#include "ozimap.h"
|
||||||
|
|
||||||
|
|
||||||
bool OfflineMap::setImageInfo(const QString &path)
|
OziMap::OziMap(const QString &fileName, QObject *parent)
|
||||||
|
: Map(parent), _img(0), _tar(0), _ozf(0), _zoom(0), _ratio(1.0), _valid(false)
|
||||||
|
{
|
||||||
|
QFileInfo fi(fileName);
|
||||||
|
QString suffix = fi.suffix().toLower();
|
||||||
|
|
||||||
|
|
||||||
|
if (suffix == "tar") {
|
||||||
|
_tar = new Tar(fileName);
|
||||||
|
if (!_tar->open()) {
|
||||||
|
_errorString = "Error reading tar file";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString mapFileName = fi.completeBaseName() + ".map";
|
||||||
|
QByteArray ba = _tar->file(mapFileName);
|
||||||
|
if (ba.isNull()) {
|
||||||
|
_errorString = "Map file not found";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QBuffer buffer(&ba);
|
||||||
|
MapFile mf(buffer);
|
||||||
|
if (!mf.isValid()) {
|
||||||
|
_errorString = mf.errorString();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
_name = mf.name();
|
||||||
|
_map.size = mf.size();
|
||||||
|
_map.path = mf.image();
|
||||||
|
_projection = mf.projection();
|
||||||
|
_transform = mf.transform();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!setTileInfo(_tar->files()))
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
QFile file(fileName);
|
||||||
|
MapFile mf(file);
|
||||||
|
if (!mf.isValid()) {
|
||||||
|
_errorString = mf.errorString();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
_name = mf.name();
|
||||||
|
_map.size = mf.size();
|
||||||
|
_map.path = mf.image();
|
||||||
|
_projection = mf.projection();
|
||||||
|
_transform = mf.transform();
|
||||||
|
}
|
||||||
|
|
||||||
|
QDir set(fi.absolutePath() + "/" + "set");
|
||||||
|
if (set.exists()) {
|
||||||
|
if (!setTileInfo(set.entryList(), set.absolutePath()))
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if (!setImageInfo(fi.absolutePath()))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
OziMap::OziMap(const QString &fileName, Tar &tar, QObject *parent)
|
||||||
|
: Map(parent), _img(0), _tar(0), _ozf(0), _zoom(0), _ratio(1.0), _valid(false)
|
||||||
|
{
|
||||||
|
QFileInfo fi(fileName);
|
||||||
|
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);
|
||||||
|
MapFile mf(buffer);
|
||||||
|
if (!mf.isValid()) {
|
||||||
|
_errorString = mf.errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_name = mf.name();
|
||||||
|
_map.size = mf.size();
|
||||||
|
_projection = mf.projection();
|
||||||
|
_transform = mf.transform();
|
||||||
|
_tar = new Tar(fi.absolutePath() + "/" + fi.completeBaseName() + ".tar");
|
||||||
|
|
||||||
|
_valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
OziMap::~OziMap()
|
||||||
|
{
|
||||||
|
delete _img;
|
||||||
|
delete _tar;
|
||||||
|
delete _ozf;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OziMap::setImageInfo(const QString &path)
|
||||||
{
|
{
|
||||||
QFileInfo ii(_map.path);
|
QFileInfo ii(_map.path);
|
||||||
|
|
||||||
@ -40,26 +138,25 @@ bool OfflineMap::setImageInfo(const QString &path)
|
|||||||
|
|
||||||
if (OZF::isOZF(_map.path)) {
|
if (OZF::isOZF(_map.path)) {
|
||||||
_ozf = new OZF(_map.path);
|
_ozf = new OZF(_map.path);
|
||||||
if (!_ozf->open()) {
|
if (!_ozf || !_ozf->open()) {
|
||||||
_errorString = QString("%1: Error loading OZF file")
|
_errorString = QString("%1: Error loading OZF file").arg(_map.path);
|
||||||
.arg(_ozf->fileName());
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_scale = _ozf->scale(_zoom);
|
_scale = _ozf->scale(_zoom);
|
||||||
} else {
|
} else {
|
||||||
QImageReader img(_map.path);
|
QImageReader ir(_map.path);
|
||||||
_map.size = img.size();
|
if (!ir.canRead()) {
|
||||||
if (!_map.size.isValid()) {
|
_errorString = QString("%1: Unsupported/invalid image file")
|
||||||
_errorString = QString("%1: Error reading map image")
|
.arg(_map.path);
|
||||||
.arg(QFileInfo(_map.path).fileName());
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
_map.size = ir.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OfflineMap::setTileInfo(const QStringList &tiles, const QString &path)
|
bool OziMap::setTileInfo(const QStringList &tiles, const QString &path)
|
||||||
{
|
{
|
||||||
if (!_map.size.isValid()) {
|
if (!_map.size.isValid()) {
|
||||||
_errorString = "Missing total image size (IWH)";
|
_errorString = "Missing total image size (IWH)";
|
||||||
@ -94,122 +191,7 @@ bool OfflineMap::setTileInfo(const QStringList &tiles, const QString &path)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
OfflineMap::OfflineMap(const QString &fileName, QObject *parent)
|
void OziMap::load()
|
||||||
: Map(parent), _img(0), _tar(0), _ozf(0), _zoom(0), _ratio(1.0), _valid(false)
|
|
||||||
{
|
|
||||||
QFileInfo fi(fileName);
|
|
||||||
QString suffix = fi.suffix().toLower();
|
|
||||||
|
|
||||||
|
|
||||||
if (suffix == "tar") {
|
|
||||||
_tar = new Tar(fileName);
|
|
||||||
if (!_tar->open()) {
|
|
||||||
_errorString = "Error reading tar file";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString mapFileName = fi.completeBaseName() + ".map";
|
|
||||||
QByteArray ba = _tar->file(mapFileName);
|
|
||||||
if (ba.isNull()) {
|
|
||||||
_errorString = "Map file not found";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
QBuffer buffer(&ba);
|
|
||||||
MapFile mf(buffer);
|
|
||||||
if (!mf.isValid()) {
|
|
||||||
_errorString = mf.errorString();
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
_name = mf.name();
|
|
||||||
_map.size = mf.size();
|
|
||||||
_map.path = mf.image();
|
|
||||||
_projection = mf.projection();
|
|
||||||
_transform = mf.transform();
|
|
||||||
}
|
|
||||||
} else if (suffix == "map") {
|
|
||||||
QFile file(fileName);
|
|
||||||
MapFile mf(file);
|
|
||||||
if (!mf.isValid()) {
|
|
||||||
_errorString = mf.errorString();
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
_name = mf.name();
|
|
||||||
_map.size = mf.size();
|
|
||||||
_map.path = mf.image();
|
|
||||||
_projection = mf.projection();
|
|
||||||
_transform = mf.transform();
|
|
||||||
}
|
|
||||||
} else if (suffix == "tif" || suffix == "tiff") {
|
|
||||||
GeoTIFF gt(fileName);
|
|
||||||
if (!gt.isValid()) {
|
|
||||||
_errorString = gt.errorString();
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
_name = fi.fileName();
|
|
||||||
_map.path = fileName;
|
|
||||||
_projection = gt.projection();
|
|
||||||
_transform = gt.transform();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_errorString = "Not a map file";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_tar) {
|
|
||||||
if (!setTileInfo(_tar->files()))
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
QDir set(fi.absolutePath() + "/" + "set");
|
|
||||||
if (set.exists()) {
|
|
||||||
if (!setTileInfo(set.entryList(), set.absolutePath()))
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
if (!setImageInfo(fi.absolutePath()))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_valid = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
OfflineMap::OfflineMap(const QString &fileName, Tar &tar, QObject *parent)
|
|
||||||
: Map(parent), _img(0), _tar(0), _ozf(0), _zoom(0), _ratio(1.0), _valid(false)
|
|
||||||
{
|
|
||||||
QFileInfo fi(fileName);
|
|
||||||
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);
|
|
||||||
MapFile mf(buffer);
|
|
||||||
if (!mf.isValid()) {
|
|
||||||
_errorString = mf.errorString();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_name = mf.name();
|
|
||||||
_map.size = mf.size();
|
|
||||||
_projection = mf.projection();
|
|
||||||
_transform = mf.transform();
|
|
||||||
_tar = new Tar(fi.absolutePath() + "/" + fi.completeBaseName() + ".tar");
|
|
||||||
|
|
||||||
_valid = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
OfflineMap::~OfflineMap()
|
|
||||||
{
|
|
||||||
delete _img;
|
|
||||||
delete _tar;
|
|
||||||
delete _ozf;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OfflineMap::load()
|
|
||||||
{
|
{
|
||||||
if (_tar && !_tar->isOpen()) {
|
if (_tar && !_tar->isOpen()) {
|
||||||
if (!_tar->open()) {
|
if (!_tar->open()) {
|
||||||
@ -223,25 +205,17 @@ void OfflineMap::load()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_ozf && !_img && _map.isValid()) {
|
if (!_tile.isValid() && !_ozf && !_img)
|
||||||
_img = new QImage(_map.path);
|
_img = new Image(_map.path);
|
||||||
if (!_img || _img->isNull()) {
|
|
||||||
qWarning("%s: error loading map image", qPrintable(_map.path));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#ifdef ENABLE_HIDPI
|
|
||||||
_img->setDevicePixelRatio(_ratio);
|
|
||||||
#endif // ENABLE_HIDPI
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OfflineMap::unload()
|
void OziMap::unload()
|
||||||
{
|
{
|
||||||
delete _img;
|
delete _img;
|
||||||
_img = 0;
|
_img = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OfflineMap::drawTiled(QPainter *painter, const QRectF &rect) const
|
void OziMap::drawTiled(QPainter *painter, const QRectF &rect) const
|
||||||
{
|
{
|
||||||
QSizeF ts(_tile.size.width() / _ratio, _tile.size.height() / _ratio);
|
QSizeF ts(_tile.size.width() / _ratio, _tile.size.height() / _ratio);
|
||||||
QPointF tl(floor(rect.left() / ts.width()) * ts.width(),
|
QPointF tl(floor(rect.left() / ts.width()) * ts.width(),
|
||||||
@ -282,7 +256,7 @@ void OfflineMap::drawTiled(QPainter *painter, const QRectF &rect) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OfflineMap::drawOZF(QPainter *painter, const QRectF &rect) const
|
void OziMap::drawOZF(QPainter *painter, const QRectF &rect) const
|
||||||
{
|
{
|
||||||
QSizeF ts(_ozf->tileSize().width() / _ratio, _ozf->tileSize().height()
|
QSizeF ts(_ozf->tileSize().width() / _ratio, _ozf->tileSize().height()
|
||||||
/ _ratio);
|
/ _ratio);
|
||||||
@ -317,25 +291,19 @@ void OfflineMap::drawOZF(QPainter *painter, const QRectF &rect) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OfflineMap::drawImage(QPainter *painter, const QRectF &rect) const
|
void OziMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||||
{
|
{
|
||||||
painter->drawImage(rect.topLeft(), *_img, QRectF(rect.topLeft() * _ratio,
|
Q_UNUSED(flags);
|
||||||
rect.size() * _ratio));
|
|
||||||
}
|
|
||||||
|
|
||||||
void OfflineMap::draw(QPainter *painter, const QRectF &rect, bool block)
|
|
||||||
{
|
|
||||||
Q_UNUSED(block);
|
|
||||||
|
|
||||||
if (_ozf)
|
if (_ozf)
|
||||||
drawOZF(painter, rect);
|
drawOZF(painter, rect);
|
||||||
|
else if (_img)
|
||||||
|
_img->draw(painter, rect, flags);
|
||||||
else if (_tile.isValid())
|
else if (_tile.isValid())
|
||||||
drawTiled(painter, rect);
|
drawTiled(painter, rect);
|
||||||
else if (_img && !_img->isNull())
|
|
||||||
drawImage(painter, rect);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QPointF OfflineMap::ll2xy(const Coordinates &c)
|
QPointF OziMap::ll2xy(const Coordinates &c)
|
||||||
{
|
{
|
||||||
QPointF p(_transform.proj2img(_projection.ll2xy(c)));
|
QPointF p(_transform.proj2img(_projection.ll2xy(c)));
|
||||||
return _ozf
|
return _ozf
|
||||||
@ -343,7 +311,7 @@ QPointF OfflineMap::ll2xy(const Coordinates &c)
|
|||||||
: p / _ratio;
|
: p / _ratio;
|
||||||
}
|
}
|
||||||
|
|
||||||
Coordinates OfflineMap::xy2ll(const QPointF &p)
|
Coordinates OziMap::xy2ll(const QPointF &p)
|
||||||
{
|
{
|
||||||
return _ozf
|
return _ozf
|
||||||
? _projection.xy2ll(_transform.img2proj(QPointF(p.x() / _scale.x(),
|
? _projection.xy2ll(_transform.img2proj(QPointF(p.x() / _scale.x(),
|
||||||
@ -351,14 +319,14 @@ Coordinates OfflineMap::xy2ll(const QPointF &p)
|
|||||||
: _projection.xy2ll(_transform.img2proj(p * _ratio));
|
: _projection.xy2ll(_transform.img2proj(p * _ratio));
|
||||||
}
|
}
|
||||||
|
|
||||||
QRectF OfflineMap::bounds()
|
QRectF OziMap::bounds()
|
||||||
{
|
{
|
||||||
return _ozf
|
return _ozf
|
||||||
? QRectF(QPointF(0, 0), _ozf->size(_zoom) / _ratio)
|
? QRectF(QPointF(0, 0), _ozf->size(_zoom) / _ratio)
|
||||||
: QRectF(QPointF(0, 0), _map.size / _ratio);
|
: QRectF(QPointF(0, 0), _map.size / _ratio);
|
||||||
}
|
}
|
||||||
|
|
||||||
int OfflineMap::zoomFit(const QSize &size, const RectC &rect)
|
int OziMap::zoomFit(const QSize &size, const RectC &rect)
|
||||||
{
|
{
|
||||||
if (!_ozf)
|
if (!_ozf)
|
||||||
return _zoom;
|
return _zoom;
|
||||||
@ -381,7 +349,7 @@ int OfflineMap::zoomFit(const QSize &size, const RectC &rect)
|
|||||||
return _zoom;
|
return _zoom;
|
||||||
}
|
}
|
||||||
|
|
||||||
int OfflineMap::zoomIn()
|
int OziMap::zoomIn()
|
||||||
{
|
{
|
||||||
if (_ozf)
|
if (_ozf)
|
||||||
rescale(qMax(_zoom - 1, 0));
|
rescale(qMax(_zoom - 1, 0));
|
||||||
@ -389,7 +357,7 @@ int OfflineMap::zoomIn()
|
|||||||
return _zoom;
|
return _zoom;
|
||||||
}
|
}
|
||||||
|
|
||||||
int OfflineMap::zoomOut()
|
int OziMap::zoomOut()
|
||||||
{
|
{
|
||||||
if (_ozf)
|
if (_ozf)
|
||||||
rescale(qMin(_zoom + 1, _ozf->zooms() - 1));
|
rescale(qMin(_zoom + 1, _ozf->zooms() - 1));
|
||||||
@ -397,8 +365,15 @@ int OfflineMap::zoomOut()
|
|||||||
return _zoom;
|
return _zoom;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OfflineMap::rescale(int zoom)
|
void OziMap::rescale(int zoom)
|
||||||
{
|
{
|
||||||
_zoom = zoom;
|
_zoom = zoom;
|
||||||
_scale = _ozf->scale(zoom);
|
_scale = _ozf->scale(zoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OziMap::setDevicePixelRatio(qreal ratio)
|
||||||
|
{
|
||||||
|
_ratio = ratio;
|
||||||
|
if (_img)
|
||||||
|
_img->setDevicePixelRatio(_ratio);
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
#ifndef OFFLINEMAP_H
|
#ifndef OZIMAP_H
|
||||||
#define OFFLINEMAP_H
|
#define OZIMAP_H
|
||||||
|
|
||||||
#include "transform.h"
|
#include "transform.h"
|
||||||
#include "projection.h"
|
#include "projection.h"
|
||||||
@ -7,16 +7,16 @@
|
|||||||
|
|
||||||
class Tar;
|
class Tar;
|
||||||
class OZF;
|
class OZF;
|
||||||
class QImage;
|
class Image;
|
||||||
|
|
||||||
class OfflineMap : public Map
|
class OziMap : public Map
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
OfflineMap(const QString &fileName, QObject *parent = 0);
|
OziMap(const QString &fileName, QObject *parent = 0);
|
||||||
OfflineMap(const QString &fileName, Tar &tar, QObject *parent = 0);
|
OziMap(const QString &fileName, Tar &tar, QObject *parent = 0);
|
||||||
~OfflineMap();
|
~OziMap();
|
||||||
|
|
||||||
QString name() const {return _name;}
|
QString name() const {return _name;}
|
||||||
|
|
||||||
@ -31,9 +31,9 @@ public:
|
|||||||
QPointF ll2xy(const Coordinates &c);
|
QPointF ll2xy(const Coordinates &c);
|
||||||
Coordinates xy2ll(const QPointF &p);
|
Coordinates xy2ll(const QPointF &p);
|
||||||
|
|
||||||
void draw(QPainter *painter, const QRectF &rect, bool block);
|
void draw(QPainter *painter, const QRectF &rect, Flags flags);
|
||||||
|
|
||||||
void setDevicePixelRatio(qreal ratio) {_ratio = ratio;}
|
void setDevicePixelRatio(qreal ratio);
|
||||||
void load();
|
void load();
|
||||||
void unload();
|
void unload();
|
||||||
|
|
||||||
@ -60,14 +60,14 @@ private:
|
|||||||
|
|
||||||
void drawTiled(QPainter *painter, const QRectF &rect) const;
|
void drawTiled(QPainter *painter, const QRectF &rect) const;
|
||||||
void drawOZF(QPainter *painter, const QRectF &rect) const;
|
void drawOZF(QPainter *painter, const QRectF &rect) const;
|
||||||
void drawImage(QPainter *painter, const QRectF &rect) const;
|
void drawImage(QPainter *painter, const QRectF &rect, Flags flags) const;
|
||||||
|
|
||||||
void rescale(int zoom);
|
void rescale(int zoom);
|
||||||
|
|
||||||
QString _name;
|
QString _name;
|
||||||
Projection _projection;
|
Projection _projection;
|
||||||
Transform _transform;
|
Transform _transform;
|
||||||
QImage *_img;
|
Image *_img;
|
||||||
Tar *_tar;
|
Tar *_tar;
|
||||||
OZF *_ozf;
|
OZF *_ozf;
|
||||||
ImageInfo _map, _tile;
|
ImageInfo _map, _tile;
|
||||||
@ -79,4 +79,4 @@ private:
|
|||||||
QString _errorString;
|
QString _errorString;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // OFFLINEMAP_H
|
#endif // OZIMAP_H
|
@ -96,7 +96,7 @@ bool Tar::loadTmi(const QString &path)
|
|||||||
QByteArray line = file.readLine();
|
QByteArray line = file.readLine();
|
||||||
int pos = line.indexOf(':');
|
int pos = line.indexOf(':');
|
||||||
if (line.size() < 10 || pos < 7 || !line.startsWith("block")) {
|
if (line.size() < 10 || pos < 7 || !line.startsWith("block")) {
|
||||||
qWarning("%s:%d: syntax error\n", qPrintable(path), ln);
|
qWarning("%s:%d: syntax error", qPrintable(path), ln);
|
||||||
_index.clear();
|
_index.clear();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
class Tile
|
class Tile
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
Tile() {}
|
||||||
Tile(const QPoint &xy, const QVariant &zoom, const RectD &bbox = RectD())
|
Tile(const QPoint &xy, const QVariant &zoom, const RectD &bbox = RectD())
|
||||||
{_xy = xy; _zoom = zoom; _bbox = bbox;}
|
{_xy = xy; _zoom = zoom; _bbox = bbox;}
|
||||||
|
|
||||||
|
@ -7,51 +7,65 @@
|
|||||||
static bool loadTileFile(Tile &tile, const QString &file)
|
static bool loadTileFile(Tile &tile, const QString &file)
|
||||||
{
|
{
|
||||||
if (!tile.pixmap().load(file)) {
|
if (!tile.pixmap().load(file)) {
|
||||||
qWarning("%s: error loading tile file\n", qPrintable(file));
|
qWarning("%s: error loading tile file", qPrintable(file));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
TileLoader::TileLoader(QObject *parent) : QObject(parent)
|
TileLoader::TileLoader(const QString &dir, QObject *parent)
|
||||||
|
: QObject(parent), _dir(dir)
|
||||||
{
|
{
|
||||||
|
if (!QDir().mkpath(_dir))
|
||||||
|
qWarning("%s: %s", qPrintable(_dir), "Error creating tiles directory");
|
||||||
|
|
||||||
_downloader = new Downloader(this);
|
_downloader = new Downloader(this);
|
||||||
connect(_downloader, SIGNAL(finished()), this, SIGNAL(finished()));
|
connect(_downloader, SIGNAL(finished()), this, SIGNAL(finished()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileLoader::loadTilesAsync(QList<Tile> &list)
|
void TileLoader::loadTilesAsync(QVector<Tile> &list)
|
||||||
{
|
{
|
||||||
QList<Download> dl;
|
QList<Download> dl;
|
||||||
|
|
||||||
for (int i = 0; i < list.size(); i++) {
|
for (int i = 0; i < list.size(); i++) {
|
||||||
Tile &t = list[i];
|
Tile &t = list[i];
|
||||||
QString file = tileFile(t);
|
QString file(tileFile(t));
|
||||||
QFileInfo fi(file);
|
QFileInfo fi(file);
|
||||||
|
|
||||||
if (!fi.exists())
|
if (fi.exists())
|
||||||
dl.append(Download(tileUrl(t), file));
|
|
||||||
else
|
|
||||||
loadTileFile(t, file);
|
loadTileFile(t, file);
|
||||||
|
else {
|
||||||
|
QUrl url(tileUrl(t));
|
||||||
|
if (url.isLocalFile())
|
||||||
|
loadTileFile(t, url.toLocalFile());
|
||||||
|
else
|
||||||
|
dl.append(Download(url, file));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dl.empty())
|
if (!dl.empty())
|
||||||
_downloader->get(dl, _authorization);
|
_downloader->get(dl, _authorization);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileLoader::loadTilesSync(QList<Tile> &list)
|
void TileLoader::loadTilesSync(QVector<Tile> &list)
|
||||||
{
|
{
|
||||||
QList<Download> dl;
|
QList<Download> dl;
|
||||||
|
|
||||||
for (int i = 0; i < list.size(); i++) {
|
for (int i = 0; i < list.size(); i++) {
|
||||||
Tile &t = list[i];
|
Tile &t = list[i];
|
||||||
QString file = tileFile(t);
|
QString file(tileFile(t));
|
||||||
QFileInfo fi(file);
|
QFileInfo fi(file);
|
||||||
|
|
||||||
if (!fi.exists())
|
if (fi.exists())
|
||||||
dl.append(Download(tileUrl(t), file));
|
|
||||||
else
|
|
||||||
loadTileFile(t, file);
|
loadTileFile(t, file);
|
||||||
|
else {
|
||||||
|
QUrl url(tileUrl(t));
|
||||||
|
if (url.isLocalFile())
|
||||||
|
loadTileFile(t, url.toLocalFile());
|
||||||
|
else
|
||||||
|
dl.append(Download(url, file));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dl.empty())
|
if (dl.empty())
|
||||||
@ -84,7 +98,7 @@ void TileLoader::clearCache()
|
|||||||
_downloader->clearErrors();
|
_downloader->clearErrors();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString TileLoader::tileUrl(const Tile &tile) const
|
QUrl TileLoader::tileUrl(const Tile &tile) const
|
||||||
{
|
{
|
||||||
QString url(_url);
|
QString url(_url);
|
||||||
|
|
||||||
@ -101,13 +115,12 @@ QString TileLoader::tileUrl(const Tile &tile) const
|
|||||||
url.replace("$y", QString::number(tile.xy().y()));
|
url.replace("$y", QString::number(tile.xy().y()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return url;
|
return QUrl(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString TileLoader::tileFile(const Tile &tile) const
|
QString TileLoader::tileFile(const Tile &tile) const
|
||||||
{
|
{
|
||||||
QString file = _dir + QString("/%1-%2-%3").arg(tile.zoom().toString())
|
return _dir + QLatin1Char('/') + tile.zoom().toString() + QLatin1Char('-')
|
||||||
.arg(tile.xy().x()).arg(tile.xy().y());
|
+ QString::number(tile.xy().x()) + QLatin1Char('-')
|
||||||
|
+ QString::number(tile.xy().y());
|
||||||
return file;
|
|
||||||
}
|
}
|
||||||
|
@ -11,22 +11,21 @@ class TileLoader : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TileLoader(QObject *parent = 0);
|
TileLoader(const QString &dir, QObject *parent = 0);
|
||||||
|
|
||||||
void setUrl(const QString &url) {_url = url;}
|
void setUrl(const QString &url) {_url = url;}
|
||||||
void setDir(const QString &dir) {_dir = dir;}
|
|
||||||
void setAuthorization(const Authorization &authorization)
|
void setAuthorization(const Authorization &authorization)
|
||||||
{_authorization = authorization;}
|
{_authorization = authorization;}
|
||||||
|
|
||||||
void loadTilesAsync(QList<Tile> &list);
|
void loadTilesAsync(QVector<Tile> &list);
|
||||||
void loadTilesSync(QList<Tile> &list);
|
void loadTilesSync(QVector<Tile> &list);
|
||||||
void clearCache();
|
void clearCache();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void finished();
|
void finished();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString tileUrl(const Tile &tile) const;
|
QUrl tileUrl(const Tile &tile) const;
|
||||||
QString tileFile(const Tile &tile) const;
|
QString tileFile(const Tile &tile) const;
|
||||||
|
|
||||||
Downloader *_downloader;
|
Downloader *_downloader;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user