Compare commits
202 Commits
Author | SHA1 | Date | |
---|---|---|---|
9bd79a4104 | |||
f9abf21e6d | |||
fb4af33d89 | |||
9eb95daf09 | |||
d291e55bdb | |||
b5893cf506 | |||
8507fe3b52 | |||
79edd6e09d | |||
491c6c9a98 | |||
3c36db9f5a | |||
c4a750f5d4 | |||
e4d7f45103 | |||
c85b90d56d | |||
7babf734bf | |||
25ac235414 | |||
630a5cea83 | |||
a0de7f25c3 | |||
7c6174a8ee | |||
0f512d1269 | |||
246b46ffcb | |||
cc4cbcbeda | |||
64e0b492e6 | |||
52a8b1de5b | |||
5045c03953 | |||
515f1aeb27 | |||
dbb82d6f44 | |||
307a03d46c | |||
b7c03b4b9e | |||
2d1e0934ce | |||
0ff66bc897 | |||
3b68f497fe | |||
a04293b411 | |||
5a4de1cef0 | |||
99d3d8fd0a | |||
d579ce3482 | |||
67ce176b74 | |||
1a88527c60 | |||
9d6a2cce45 | |||
7a5f67790e | |||
704c66449f | |||
42e1331678 | |||
ad3b666a19 | |||
3dd253828e | |||
bb5e50b009 | |||
69384ca315 | |||
676c82b7a4 | |||
5a2be6ff07 | |||
454e725587 | |||
b9d9ab85b2 | |||
15a2df12bd | |||
db7a75088a | |||
378da395fb | |||
da7d0fe32d | |||
789f314ae8 | |||
0986864c6c | |||
83ac0b5ed7 | |||
a1be73fbba | |||
7761935c29 | |||
4da0e8a1c7 | |||
066736b3d2 | |||
fdcbc4c6c2 | |||
b894df26d3 | |||
5a5c0ef68a | |||
56b7014eaf | |||
1f52dad1c6 | |||
0f8859dd20 | |||
398eb152f6 | |||
38ab835898 | |||
927740a196 | |||
4d8b7aa8ae | |||
49c94d34b3 | |||
5c2ac54bb4 | |||
003947263f | |||
6a70e5ea00 | |||
e83be4d553 | |||
ce38077281 | |||
e75a2882a5 | |||
8add7b428f | |||
846f864bd4 | |||
8683254155 | |||
ef2ffd9fc4 | |||
a9c86fd580 | |||
fe360a2578 | |||
a09a58eece | |||
abd1817d83 | |||
7c90174751 | |||
b24f27cf79 | |||
98f88db3cf | |||
f2ddfa6fb7 | |||
54ed0ca9f6 | |||
477b32f444 | |||
1fb6aad50f | |||
4fa9aac917 | |||
03db87535a | |||
92145c8445 | |||
5e8479707b | |||
2039105ba5 | |||
2605e1abeb | |||
8fd17badda | |||
7d62ef038c | |||
138e0e9505 | |||
5dffb2714b | |||
5d8330a68a | |||
ff30163175 | |||
743fb20a95 | |||
50f483663c | |||
96997ffa35 | |||
d738ad7b5a | |||
01d69a4f2a | |||
0e026d6a96 | |||
07825e5701 | |||
03e7d092c4 | |||
0b5d01a1f6 | |||
08aa087f61 | |||
6604f85f4a | |||
5343a1a922 | |||
d6e0757364 | |||
51becc4bf1 | |||
29a821f8b2 | |||
14f4dead76 | |||
96bb3bbdbb | |||
22d18b6d4e | |||
c1b79217a9 | |||
e67a14b072 | |||
473d03cf1f | |||
a339706293 | |||
39c414ca73 | |||
c59d60faed | |||
32d3eab10e | |||
e7729e8745 | |||
bf145c9eb5 | |||
de0a6b0397 | |||
8cf89a580f | |||
152e2a8a09 | |||
6b860fe18c | |||
95f138f5f0 | |||
1fc4dbbb73 | |||
0999cdcba2 | |||
cc16c9e79b | |||
1990c85fd7 | |||
58f70fa833 | |||
0f6c50d588 | |||
89dce5152e | |||
8bce6a44ed | |||
59ecd3fdf0 | |||
a10c729e52 | |||
369601f102 | |||
47d0feeb46 | |||
58a0acc718 | |||
c466527625 | |||
9cd00075c7 | |||
6f72d46d6c | |||
54467e6d45 | |||
3d2e33361d | |||
f91df0d026 | |||
9bd004359d | |||
e170f92e79 | |||
0fb5d8dae6 | |||
5ff931bb5e | |||
5bd744a8ed | |||
035883aab2 | |||
571ed087e3 | |||
c461b2e549 | |||
26b5411465 | |||
8965f450ce | |||
a958544667 | |||
ddf865834a | |||
a4abed8f1f | |||
56061c93cb | |||
7385b08262 | |||
9d79bd9a9d | |||
159e5aeae9 | |||
d8beaed876 | |||
c1584f30d2 | |||
efcefe8fec | |||
cbe312d9c8 | |||
5322ee96c8 | |||
08334d7fde | |||
51d4e04343 | |||
33bbd6a592 | |||
0f96bc602c | |||
7811527239 | |||
31da4e1906 | |||
cb6a82a10a | |||
652cbd7c11 | |||
ff0711c620 | |||
eb0ff84379 | |||
74775b2c62 | |||
6ee3a8ea8d | |||
ee3d43e249 | |||
a6fbae38b8 | |||
242babb741 | |||
e26d1abd5a | |||
e80d16bec5 | |||
412ae74bfa | |||
1c472e47b9 | |||
4a725375e2 | |||
383a196414 | |||
f05b51efa6 | |||
a56c02953f | |||
00d3849e4f | |||
c9244c0684 |
@ -1,4 +1,4 @@
|
||||
version: 7.27.{build}
|
||||
version: 7.35.{build}
|
||||
|
||||
configuration:
|
||||
- Release
|
||||
|
1
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
||||
github: tumic0
|
35
gpxsee.pro
@ -3,7 +3,7 @@ unix:!macx {
|
||||
} else {
|
||||
TARGET = GPXSee
|
||||
}
|
||||
VERSION = 7.27
|
||||
VERSION = 7.35
|
||||
|
||||
QT += core \
|
||||
gui \
|
||||
@ -21,6 +21,7 @@ INCLUDEPATH += ./src
|
||||
HEADERS += src/common/config.h \
|
||||
src/GUI/graphicsscene.h \
|
||||
src/GUI/mapaction.h \
|
||||
src/GUI/marginswidget.h \
|
||||
src/GUI/popup.h \
|
||||
src/common/garmin.h \
|
||||
src/common/staticassert.h \
|
||||
@ -53,7 +54,6 @@ HEADERS += src/common/config.h \
|
||||
src/GUI/palette.h \
|
||||
src/GUI/heartrategraph.h \
|
||||
src/GUI/trackinfo.h \
|
||||
src/GUI/exportdialog.h \
|
||||
src/GUI/fileselectwidget.h \
|
||||
src/GUI/margins.h \
|
||||
src/GUI/temperaturegraph.h \
|
||||
@ -95,7 +95,9 @@ HEADERS += src/common/config.h \
|
||||
src/map/IMG/gmap.h \
|
||||
src/map/IMG/huffmanstream.h \
|
||||
src/map/IMG/huffmantable.h \
|
||||
src/map/IMG/nodfile.h \
|
||||
src/map/IMG/mapdata.h \
|
||||
src/map/IMG/rastertile.h \
|
||||
src/map/IMG/textpathitem.h \
|
||||
src/map/IMG/textpointitem.h \
|
||||
src/map/projection.h \
|
||||
@ -196,8 +198,11 @@ HEADERS += src/common/config.h \
|
||||
src/data/cupparser.h \
|
||||
src/data/gpiparser.h \
|
||||
src/data/address.h \
|
||||
src/data/smlparser.h
|
||||
src/data/smlparser.h \
|
||||
src/GUI/pdfexportdialog.h \
|
||||
src/GUI/pngexportdialog.h
|
||||
SOURCES += src/main.cpp \
|
||||
src/GUI/marginswidget.cpp \
|
||||
src/GUI/popup.cpp \
|
||||
src/common/coordinates.cpp \
|
||||
src/common/rectc.cpp \
|
||||
@ -222,7 +227,6 @@ SOURCES += src/main.cpp \
|
||||
src/GUI/palette.cpp \
|
||||
src/GUI/heartrategraph.cpp \
|
||||
src/GUI/trackinfo.cpp \
|
||||
src/GUI/exportdialog.cpp \
|
||||
src/GUI/fileselectwidget.cpp \
|
||||
src/GUI/temperaturegraph.cpp \
|
||||
src/GUI/trackitem.cpp \
|
||||
@ -256,7 +260,9 @@ SOURCES += src/main.cpp \
|
||||
src/map/IMG/gmap.cpp \
|
||||
src/map/IMG/huffmanstream.cpp \
|
||||
src/map/IMG/huffmantable.cpp \
|
||||
src/map/IMG/nodfile.cpp \
|
||||
src/map/IMG/mapdata.cpp \
|
||||
src/map/IMG/rastertile.cpp \
|
||||
src/map/IMG/textpathitem.cpp \
|
||||
src/map/IMG/textpointitem.cpp \
|
||||
src/map/maplist.cpp \
|
||||
@ -340,12 +346,17 @@ SOURCES += src/main.cpp \
|
||||
src/data/cupparser.cpp \
|
||||
src/GUI/graphicsscene.cpp \
|
||||
src/data/gpiparser.cpp \
|
||||
src/data/smlparser.cpp
|
||||
src/data/smlparser.cpp \
|
||||
src/GUI/pdfexportdialog.cpp \
|
||||
src/GUI/pngexportdialog.cpp
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4) {
|
||||
HEADERS += src/data/geojsonparser.h
|
||||
SOURCES += src/data/geojsonparser.cpp
|
||||
}
|
||||
equals(QT_MAJOR_VERSION, 5):greaterThan(QT_MINOR_VERSION, 4) {
|
||||
HEADERS += src/GUI/timezoneinfo.h
|
||||
}
|
||||
|
||||
DEFINES += APP_VERSION=\\\"$$VERSION\\\" \
|
||||
QT_NO_DEPRECATED_WARNINGS
|
||||
@ -366,10 +377,11 @@ TRANSLATIONS = lang/gpxsee_en.ts \
|
||||
lang/gpxsee_es.ts \
|
||||
lang/gpxsee_pt_BR.ts \
|
||||
lang/gpxsee_uk.ts \
|
||||
lang/gpxsee_hu.ts
|
||||
lang/gpxsee_hu.ts \
|
||||
lang/gpxsee_it.ts
|
||||
|
||||
macx {
|
||||
ICON = icons/gpxsee.icns
|
||||
ICON = icons/app/gpxsee.icns
|
||||
QMAKE_INFO_PLIST = pkg/Info.plist
|
||||
locale.path = Contents/Resources/translations
|
||||
locale.files = lang/gpxsee_en.qm \
|
||||
@ -386,7 +398,8 @@ macx {
|
||||
lang/gpxsee_es.qm \
|
||||
lang/gpxsee_pt_BR.qm \
|
||||
lang/gpxsee_uk.qm \
|
||||
lang/gpxsee_hu.qm
|
||||
lang/gpxsee_hu.qm \
|
||||
lang/gpxsee_it.qm
|
||||
csv.path = Contents/Resources
|
||||
csv.files = pkg/csv
|
||||
maps.path = Contents/Resources
|
||||
@ -411,7 +424,7 @@ macx {
|
||||
}
|
||||
|
||||
win32 {
|
||||
RC_ICONS = icons/gpxsee.ico \
|
||||
RC_ICONS = icons/app/gpxsee.ico \
|
||||
icons/formats/gpx.ico \
|
||||
icons/formats/tcx.ico \
|
||||
icons/formats/kml.ico \
|
||||
@ -441,8 +454,8 @@ unix:!macx {
|
||||
csv.path = $$PREFIX/share/gpxsee/csv
|
||||
locale.files = lang/*.qm
|
||||
locale.path = $$PREFIX/share/gpxsee/translations
|
||||
icon.files = icons/gpxsee.png
|
||||
icon.path = $$PREFIX/share/pixmaps
|
||||
icon.files = icons/app/hicolor/*
|
||||
icon.path = $$PREFIX/share/icons/hicolor
|
||||
desktop.files = pkg/gpxsee.desktop
|
||||
desktop.path = $$PREFIX/share/applications
|
||||
mime.files = pkg/gpxsee.xml
|
||||
|
@ -1,8 +1,8 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<!-- GUI -->
|
||||
<file alias="gpxsee.png">icons/gpxsee.png</file>
|
||||
<file alias="gpxsee@2x.png">icons/gpxsee@2x.png</file>
|
||||
<file alias="gpxsee.png">icons/app/gpxsee.png</file>
|
||||
<file alias="gpxsee@2x.png">icons/app/gpxsee@2x.png</file>
|
||||
<file alias="dialog-close.png">icons/GUI/dialog-close.png</file>
|
||||
<file alias="dialog-close@2x.png">icons/GUI/dialog-close@2x.png</file>
|
||||
<file alias="document-open.png">icons/GUI/document-open.png</file>
|
||||
@ -67,10 +67,12 @@
|
||||
<file alias="cinema-11.png">icons/POI/cinema-11.png</file>
|
||||
<file alias="clothing-store-11.png">icons/POI/clothing-store-11.png</file>
|
||||
<file alias="communications-tower-11.png">icons/POI/communications-tower-11.png</file>
|
||||
<file alias="convenience-11.png">icons/POI/convenience-11.png</file>
|
||||
<file alias="dam-11.png">icons/POI/dam-11.png</file>
|
||||
<file alias="danger-11.png">icons/POI/danger-11.png</file>
|
||||
<file alias="drinking-water-11.png">icons/POI/drinking-water-11.png</file>
|
||||
<file alias="fast-food-11.png">icons/POI/fast-food-11.png</file>
|
||||
<file alias="entrance-alt1-11.png">icons/POI/entrance-alt1-11.png</file>
|
||||
<file alias="fire-station-11.png">icons/POI/fire-station-11.png</file>
|
||||
<file alias="fitness-centre-11.png">icons/POI/fitness-centre-11.png</file>
|
||||
<file alias="fuel-11.png">icons/POI/fuel-11.png</file>
|
||||
@ -97,7 +99,6 @@
|
||||
<file alias="place-of-worship-11.png">icons/POI/place-of-worship-11.png</file>
|
||||
<file alias="police-11.png">icons/POI/police-11.png</file>
|
||||
<file alias="post-11.png">icons/POI/post-11.png</file>
|
||||
<file alias="prison-11.png">icons/POI/prison-11.png</file>
|
||||
<file alias="religious-christian-11.png">icons/POI/religious-christian-11.png</file>
|
||||
<file alias="religious-jewish-11.png">icons/POI/religious-jewish-11.png</file>
|
||||
<file alias="religious-muslim-11.png">icons/POI/religious-muslim-11.png</file>
|
||||
|
BIN
icons/POI/convenience-11.png
Normal file
After Width: | Height: | Size: 650 B |
BIN
icons/POI/entrance-alt1-11.png
Normal file
After Width: | Height: | Size: 611 B |
Before Width: | Height: | Size: 323 B |
BIN
icons/app/gpxsee.dia
Normal file
Before Width: | Height: | Size: 361 KiB After Width: | Height: | Size: 361 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
BIN
icons/app/hicolor/128x128/apps/gpxsee.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
icons/app/hicolor/16x16/apps/gpxsee.png
Normal file
After Width: | Height: | Size: 571 B |
BIN
icons/app/hicolor/32x32/apps/gpxsee.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
icons/app/hicolor/48x48/apps/gpxsee.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
icons/app/hicolor/64x64/apps/gpxsee.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
33
icons/app/hicolor/scalable/apps/gpxsee.svg
Normal file
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd">
|
||||
<svg width="6cm" height="6cm" viewBox="47 79 119 119" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g>
|
||||
<rect style="fill: #ffffff" x="47.729" y="79.875" width="118.071" height="118.071" rx="10" ry="10"/>
|
||||
<rect style="fill: none; fill-opacity:0; stroke-width: 2.35099e-37; stroke-linejoin: round; stroke: #ffffff" x="47.729" y="79.875" width="118.071" height="118.071" rx="10" ry="10"/>
|
||||
</g>
|
||||
<g>
|
||||
<ellipse style="fill: #000000" cx="113" cy="90.875" rx="7.021" ry="7.021"/>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke-linejoin: round; stroke: #000000" cx="113" cy="90.875" rx="7.021" ry="7.021"/>
|
||||
</g>
|
||||
<polyline style="fill: none; fill-opacity:0; stroke-width: 4; stroke: #000000" points="61.5289,182.479 73.5,125.854 96,151.875 113,90.875 136.5,172.375 151.658,157.199 "/>
|
||||
<g>
|
||||
<ellipse style="fill: #000000" cx="73.5" cy="125.854" rx="7.021" ry="7.021"/>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="73.5" cy="125.854" rx="7.021" ry="7.021"/>
|
||||
</g>
|
||||
<g>
|
||||
<ellipse style="fill: #000000" cx="136.5" cy="172.375" rx="7.021" ry="7.021"/>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="136.5" cy="172.375" rx="7.021" ry="7.021"/>
|
||||
</g>
|
||||
<g>
|
||||
<ellipse style="fill: #000000" cx="60.7" cy="186.4" rx="7.021" ry="7.021"/>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="60.7" cy="186.4" rx="7.021" ry="7.021"/>
|
||||
</g>
|
||||
<g>
|
||||
<ellipse style="fill: #000000" cx="154.5" cy="154.354" rx="7.021" ry="7.021"/>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="154.5" cy="154.354" rx="7.021" ry="7.021"/>
|
||||
</g>
|
||||
<g>
|
||||
<ellipse style="fill: #000000" cx="96" cy="151.875" rx="7.021" ry="7.021"/>
|
||||
<ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="96" cy="151.875" rx="7.021" ry="7.021"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
BIN
icons/gpxsee.dia
@ -1,4 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="en_US">
|
||||
<context>
|
||||
<name>GUI</name>
|
||||
<message numerus="yes">
|
||||
<location filename="../src/GUI/gui.cpp" line="1392"/>
|
||||
<source>%n files</source>
|
||||
<translation>
|
||||
<numerusform>%n file</numerusform>
|
||||
<numerusform>%n files</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
2018
lang/gpxsee_it.ts
Normal file
@ -7,7 +7,7 @@
|
||||
; The name of the installer
|
||||
Name "GPXSee"
|
||||
; Program version
|
||||
!define VERSION "7.27"
|
||||
!define VERSION "7.35"
|
||||
|
||||
; The file to write
|
||||
OutFile "GPXSee-${VERSION}.exe"
|
||||
@ -17,6 +17,9 @@ SetCompressor /SOLID lzma
|
||||
; Required execution level
|
||||
RequestExecutionLevel admin
|
||||
|
||||
; Don't let the OS scale(blur) the installer GUI
|
||||
ManifestDPIAware true
|
||||
|
||||
; The default installation directory
|
||||
InstallDir "$PROGRAMFILES\GPXSee"
|
||||
|
||||
@ -177,6 +180,7 @@ SectionGroup "Localization" SEC_LOCALIZATION
|
||||
!insertmacro LOCALIZATION "French" "fr"
|
||||
!insertmacro LOCALIZATION "German" "de"
|
||||
!insertmacro LOCALIZATION "Hungarian" "hu"
|
||||
!insertmacro LOCALIZATION "Italian" "it"
|
||||
!insertmacro LOCALIZATION "Norwegian" "nb"
|
||||
!insertmacro LOCALIZATION "Polish" "pl"
|
||||
!insertmacro LOCALIZATION "Portuguese (Brazil)" "pt_BR"
|
||||
|
@ -7,7 +7,7 @@
|
||||
; The name of the installer
|
||||
Name "GPXSee"
|
||||
; Program version
|
||||
!define VERSION "7.27"
|
||||
!define VERSION "7.35"
|
||||
|
||||
; The file to write
|
||||
OutFile "GPXSee-${VERSION}_x64.exe"
|
||||
@ -17,6 +17,9 @@ SetCompressor /SOLID lzma
|
||||
; Required execution level
|
||||
RequestExecutionLevel admin
|
||||
|
||||
; Don't let the OS scale(blur) the installer GUI
|
||||
ManifestDPIAware true
|
||||
|
||||
; The default installation directory
|
||||
InstallDir "$PROGRAMFILES64\GPXSee"
|
||||
|
||||
@ -184,6 +187,7 @@ SectionGroup "Localization" SEC_LOCALIZATION
|
||||
!insertmacro LOCALIZATION "French" "fr"
|
||||
!insertmacro LOCALIZATION "German" "de"
|
||||
!insertmacro LOCALIZATION "Hungarian" "hu"
|
||||
!insertmacro LOCALIZATION "Italian" "it"
|
||||
!insertmacro LOCALIZATION "Norwegian" "nb"
|
||||
!insertmacro LOCALIZATION "Polish" "pl"
|
||||
!insertmacro LOCALIZATION "Portuguese (Brazil)" "pt_BR"
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map xmlns="http://www.gpxsee.org/map/1.4" type="WMTS">
|
||||
<name>Antarctica</name>
|
||||
<url type="REST">https://gis.ngdc.noaa.gov/arcgis/rest/services/antarctic/antarctic_basemap/MapServer/WMTS/1.0.0/WMTSCapabilities.xml</url>
|
||||
<url type="REST">https://tiles.arcgis.com/tiles/C8EMgrsFcRFL6LrL/arcgis/rest/services/Antarctic_Basemap/MapServer/WMTS/1.0.0/WMTSCapabilities.xml</url>
|
||||
<copyright>NOAA National Centers for Environmental Information (NCEI); International Bathymetric Chart of the Southern Ocean (IBCSO); General Bathymetric Chart of the Oceans (GEBCO); Natural Earth</copyright>
|
||||
<layer>antarctic_antarctic_basemap</layer>
|
||||
<layer>Antarctic_Basemap</layer>
|
||||
<set>default028mm</set>
|
||||
</map>
|
||||
|
@ -12,7 +12,8 @@ FileSelectWidget::FileSelectWidget(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
QFontMetrics fm(QApplication::font());
|
||||
_edit = new QLineEdit();
|
||||
_edit->setMinimumWidth(fm.boundingRect(QDir::homePath()).width());
|
||||
_edit->setMinimumWidth(fm.averageCharWidth() * (QDir::homePath().length()
|
||||
+ 12));
|
||||
#ifdef Q_OS_WIN32
|
||||
_button = new QPushButton("...");
|
||||
_button->setMaximumWidth(_button->sizeHint().width() / 2);
|
||||
@ -41,3 +42,33 @@ void FileSelectWidget::browse()
|
||||
if (!fileName.isEmpty())
|
||||
_edit->setText(fileName);
|
||||
}
|
||||
|
||||
bool FileSelectWidget::checkFile(QString &error) const
|
||||
{
|
||||
if (_edit->text().isEmpty()) {
|
||||
error = tr("No output file selected.");
|
||||
return false;
|
||||
}
|
||||
|
||||
QFile file(_edit->text());
|
||||
QFileInfo fi(file);
|
||||
bool exists = fi.exists();
|
||||
bool opened = false;
|
||||
|
||||
if (exists && fi.isDir()) {
|
||||
error = tr("%1 is a directory.").arg(file.fileName());
|
||||
return false;
|
||||
} else if ((exists && !fi.isWritable())
|
||||
|| !(opened = file.open(QFile::Append))) {
|
||||
error = tr("%1 is not writable.").arg(file.fileName());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (opened) {
|
||||
file.close();
|
||||
if (!exists)
|
||||
file.remove();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -14,9 +14,10 @@ class FileSelectWidget : public QWidget
|
||||
public:
|
||||
FileSelectWidget(QWidget *parent = 0);
|
||||
|
||||
QString file() {return _edit->text();}
|
||||
QString file() const {return _edit->text();}
|
||||
void setFile(const QString &file) {_edit->setText(file);}
|
||||
void setFilter(const QString &filter) {_filter = filter;}
|
||||
bool checkFile(QString &error) const;
|
||||
|
||||
private slots:
|
||||
void browse();
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include <QSet>
|
||||
#include <QGraphicsScene>
|
||||
#include <QEvent>
|
||||
#include <QMouseEvent>
|
||||
@ -494,8 +495,23 @@ void GraphView::setPalette(const Palette &palette)
|
||||
_palette = palette;
|
||||
_palette.reset();
|
||||
|
||||
for (int i = 0; i < _graphs.count(); i++)
|
||||
_graphs.at(i)->setColor(_palette.nextColor());
|
||||
QSet<GraphItem*> secondary;
|
||||
for (int i = 0; i < _graphs.count(); i++) {
|
||||
GraphItem *g = _graphs[i];
|
||||
if (g->secondaryGraph())
|
||||
secondary.insert(g->secondaryGraph());
|
||||
}
|
||||
|
||||
for (int i = 0; i < _graphs.count(); i++) {
|
||||
GraphItem *g = _graphs[i];
|
||||
if (secondary.contains(g))
|
||||
continue;
|
||||
|
||||
QColor color(_palette.nextColor());
|
||||
g->setColor(color);
|
||||
if (g->secondaryGraph())
|
||||
g->secondaryGraph()->setColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphView::setGraphWidth(int width)
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
#include <QGraphicsView>
|
||||
#include <QList>
|
||||
#include <QSet>
|
||||
#include "data/graph.h"
|
||||
#include "palette.h"
|
||||
#include "units.h"
|
||||
|
326
src/GUI/gui.cpp
@ -230,13 +230,20 @@ void GUI::createActions()
|
||||
_printFileAction->setActionGroup(_fileActionGroup);
|
||||
connect(_printFileAction, SIGNAL(triggered()), this, SLOT(printFile()));
|
||||
addAction(_printFileAction);
|
||||
_exportFileAction = new QAction(QIcon(EXPORT_FILE_ICON),
|
||||
_exportPDFFileAction = new QAction(QIcon(EXPORT_FILE_ICON),
|
||||
tr("Export to PDF..."), this);
|
||||
_exportFileAction->setMenuRole(QAction::NoRole);
|
||||
_exportFileAction->setShortcut(EXPORT_SHORTCUT);
|
||||
_exportFileAction->setActionGroup(_fileActionGroup);
|
||||
connect(_exportFileAction, SIGNAL(triggered()), this, SLOT(exportFile()));
|
||||
addAction(_exportFileAction);
|
||||
_exportPDFFileAction->setMenuRole(QAction::NoRole);
|
||||
_exportPDFFileAction->setShortcut(PDF_EXPORT_SHORTCUT);
|
||||
_exportPDFFileAction->setActionGroup(_fileActionGroup);
|
||||
connect(_exportPDFFileAction, SIGNAL(triggered()), this, SLOT(exportPDFFile()));
|
||||
addAction(_exportPDFFileAction);
|
||||
_exportPNGFileAction = new QAction(QIcon(EXPORT_FILE_ICON),
|
||||
tr("Export to PNG..."), this);
|
||||
_exportPNGFileAction->setMenuRole(QAction::NoRole);
|
||||
_exportPNGFileAction->setShortcut(PNG_EXPORT_SHORTCUT);
|
||||
_exportPNGFileAction->setActionGroup(_fileActionGroup);
|
||||
connect(_exportPNGFileAction, SIGNAL(triggered()), this, SLOT(exportPNGFile()));
|
||||
addAction(_exportPNGFileAction);
|
||||
_closeFileAction = new QAction(QIcon(CLOSE_FILE_ICON), tr("Close"), this);
|
||||
_closeFileAction->setMenuRole(QAction::NoRole);
|
||||
_closeFileAction->setShortcut(CLOSE_SHORTCUT);
|
||||
@ -248,7 +255,7 @@ void GUI::createActions()
|
||||
_reloadFileAction->setMenuRole(QAction::NoRole);
|
||||
_reloadFileAction->setShortcut(RELOAD_SHORTCUT);
|
||||
_reloadFileAction->setActionGroup(_fileActionGroup);
|
||||
connect(_reloadFileAction, SIGNAL(triggered()), this, SLOT(reloadFile()));
|
||||
connect(_reloadFileAction, SIGNAL(triggered()), this, SLOT(reloadFiles()));
|
||||
addAction(_reloadFileAction);
|
||||
_statisticsAction = new QAction(tr("Statistics..."), this);
|
||||
_statisticsAction->setMenuRole(QAction::NoRole);
|
||||
@ -497,7 +504,8 @@ void GUI::createMenus()
|
||||
fileMenu->addAction(_openFileAction);
|
||||
fileMenu->addSeparator();
|
||||
fileMenu->addAction(_printFileAction);
|
||||
fileMenu->addAction(_exportFileAction);
|
||||
fileMenu->addAction(_exportPDFFileAction);
|
||||
fileMenu->addAction(_exportPNGFileAction);
|
||||
fileMenu->addSeparator();
|
||||
fileMenu->addAction(_statisticsAction);
|
||||
fileMenu->addSeparator();
|
||||
@ -791,7 +799,12 @@ bool GUI::loadFile(const QString &fileName)
|
||||
_trackDistance += track.distance();
|
||||
_time += track.time();
|
||||
_movingTime += track.movingTime();
|
||||
const QDate &date = track.date().date();
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
const QDateTime date = track.date().toTimeZone(
|
||||
_options.timeZone.zone());
|
||||
#else // ENABLE_TIMEZONES
|
||||
const QDateTime &date = track.date();
|
||||
#endif // ENABLE_TIMEZONES
|
||||
if (_dateRange.first.isNull() || _dateRange.first > date)
|
||||
_dateRange.first = date;
|
||||
if (_dateRange.second.isNull() || _dateRange.second < date)
|
||||
@ -923,7 +936,7 @@ void GUI::openOptions()
|
||||
Options options(_options);
|
||||
bool reload = false;
|
||||
|
||||
OptionsDialog dialog(&options, this);
|
||||
OptionsDialog dialog(options, _units, this);
|
||||
if (dialog.exec() != QDialog::Accepted)
|
||||
return;
|
||||
|
||||
@ -965,6 +978,7 @@ void GUI::openOptions()
|
||||
SET_TRACK_OPTION(dataUseDEM, useDEM);
|
||||
SET_TRACK_OPTION(showSecondaryElevation, showSecondaryElevation);
|
||||
SET_TRACK_OPTION(showSecondarySpeed, showSecondarySpeed);
|
||||
SET_TRACK_OPTION(useSegments, useSegments);
|
||||
|
||||
SET_ROUTE_OPTION(dataUseDEM, useDEM);
|
||||
SET_ROUTE_OPTION(showSecondaryElevation, showSecondaryElevation);
|
||||
@ -990,9 +1004,16 @@ void GUI::openOptions()
|
||||
_mapView->setDevicePixelRatio(devicePixelRatioF(),
|
||||
options.hidpiMap ? devicePixelRatioF() : 1.0);
|
||||
#endif // ENABLE_HIDPI
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
if (options.timeZone != _options.timeZone) {
|
||||
_mapView->setTimeZone(options.timeZone.zone());
|
||||
_dateRange.first = _dateRange.first.toTimeZone(options.timeZone.zone());
|
||||
_dateRange.second = _dateRange.second.toTimeZone(options.timeZone.zone());
|
||||
}
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
if (reload)
|
||||
reloadFile();
|
||||
reloadFiles();
|
||||
|
||||
_options = options;
|
||||
}
|
||||
@ -1006,9 +1027,9 @@ void GUI::printFile()
|
||||
plot(&printer);
|
||||
}
|
||||
|
||||
void GUI::exportFile()
|
||||
void GUI::exportPDFFile()
|
||||
{
|
||||
ExportDialog dialog(&_export, this);
|
||||
PDFExportDialog dialog(_pdfExport, _units, this);
|
||||
if (dialog.exec() != QDialog::Accepted)
|
||||
return;
|
||||
|
||||
@ -1016,16 +1037,53 @@ void GUI::exportFile()
|
||||
printer.setOutputFormat(QPrinter::PdfFormat);
|
||||
printer.setCreator(QString(APP_NAME) + QString(" ")
|
||||
+ QString(APP_VERSION));
|
||||
printer.setResolution(_export.resolution);
|
||||
printer.setOrientation(_export.orientation);
|
||||
printer.setOutputFileName(_export.fileName);
|
||||
printer.setPaperSize(_export.paperSize);
|
||||
printer.setPageMargins(_export.margins.left(), _export.margins.top(),
|
||||
_export.margins.right(), _export.margins.bottom(), QPrinter::Millimeter);
|
||||
printer.setResolution(_pdfExport.resolution);
|
||||
printer.setOrientation(_pdfExport.orientation);
|
||||
printer.setOutputFileName(_pdfExport.fileName);
|
||||
printer.setPaperSize(_pdfExport.paperSize);
|
||||
printer.setPageMargins(_pdfExport.margins.left(), _pdfExport.margins.top(),
|
||||
_pdfExport.margins.right(), _pdfExport.margins.bottom(),
|
||||
QPrinter::Millimeter);
|
||||
|
||||
plot(&printer);
|
||||
}
|
||||
|
||||
void GUI::exportPNGFile()
|
||||
{
|
||||
PNGExportDialog dialog(_pngExport, this);
|
||||
if (dialog.exec() != QDialog::Accepted)
|
||||
return;
|
||||
|
||||
QImage img(_pngExport.size, QImage::Format_ARGB32_Premultiplied);
|
||||
QPainter p(&img);
|
||||
QRectF rect(0, 0, img.width(), img.height());
|
||||
QRectF contentRect(rect.adjusted(_pngExport.margins.left(),
|
||||
_pngExport.margins.top(), -_pngExport.margins.right(),
|
||||
-_pngExport.margins.bottom()));
|
||||
|
||||
if (_pngExport.antialiasing)
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
p.fillRect(rect, Qt::white);
|
||||
plotMainPage(&p, contentRect, 1.0, true);
|
||||
img.save(_pngExport.fileName);
|
||||
|
||||
if (!_tabs.isEmpty() && _options.separateGraphPage) {
|
||||
QImage img2(_pngExport.size.width(), (int)graphPlotHeight(rect, 1)
|
||||
+ _pngExport.margins.bottom(), QImage::Format_ARGB32_Premultiplied);
|
||||
QPainter p2(&img2);
|
||||
QRectF rect2(0, 0, img2.width(), img2.height());
|
||||
|
||||
if (_pngExport.antialiasing)
|
||||
p2.setRenderHint(QPainter::Antialiasing);
|
||||
p2.fillRect(rect2, Qt::white);
|
||||
plotGraphsPage(&p2, contentRect, 1);
|
||||
|
||||
QFileInfo fi(_pngExport.fileName);
|
||||
img2.save(fi.absolutePath() + "/" + fi.baseName() + "-graphs."
|
||||
+ fi.suffix());
|
||||
}
|
||||
}
|
||||
|
||||
void GUI::statistics()
|
||||
{
|
||||
QLocale l(QLocale::system());
|
||||
@ -1097,12 +1155,13 @@ void GUI::statistics()
|
||||
msgBox.exec();
|
||||
}
|
||||
|
||||
void GUI::plot(QPrinter *printer)
|
||||
void GUI::plotMainPage(QPainter *painter, const QRectF &rect, qreal ratio,
|
||||
bool expand)
|
||||
{
|
||||
QLocale l(QLocale::system());
|
||||
QPainter p(printer);
|
||||
TrackInfo info;
|
||||
qreal ih, gh, mh, ratio;
|
||||
qreal ih, gh, mh;
|
||||
int sc;
|
||||
|
||||
|
||||
if (!_pathName.isNull() && _options.printName)
|
||||
@ -1138,54 +1197,92 @@ void GUI::plot(QPrinter *printer)
|
||||
if (movingTime() > 0 && _options.printMovingTime)
|
||||
info.insert(tr("Moving time"), Format::timeSpan(movingTime()));
|
||||
|
||||
qreal fsr = 1085.0 / (qMax(printer->width(), printer->height())
|
||||
/ (qreal)printer->resolution());
|
||||
ratio = p.paintEngine()->paintDevice()->logicalDpiX() / fsr;
|
||||
if (info.isEmpty()) {
|
||||
ih = 0;
|
||||
mh = 0;
|
||||
} else {
|
||||
ih = info.contentSize().height() * ratio;
|
||||
mh = ih / 2;
|
||||
info.plot(&p, QRectF(0, 0, printer->width(), ih), ratio);
|
||||
info.plot(painter, QRectF(rect.x(), rect.y(), rect.width(), ih), ratio);
|
||||
}
|
||||
if (_graphTabWidget->isVisible() && !_options.separateGraphPage) {
|
||||
qreal r = (((qreal)(printer)->width()) / (qreal)(printer->height()));
|
||||
gh = (printer->width() > printer->height())
|
||||
? 0.15 * r * (printer->height() - ih - 2*mh)
|
||||
: 0.15 * (printer->height() - ih - 2*mh);
|
||||
qreal r = rect.width() / rect.height();
|
||||
gh = (rect.width() > rect.height())
|
||||
? 0.15 * r * (rect.height() - ih - 2*mh)
|
||||
: 0.15 * (rect.height() - ih - 2*mh);
|
||||
if (gh < 150)
|
||||
gh = 150;
|
||||
sc = 2;
|
||||
GraphTab *gt = static_cast<GraphTab*>(_graphTabWidget->currentWidget());
|
||||
gt->plot(&p, QRectF(0, printer->height() - gh, printer->width(), gh),
|
||||
ratio);
|
||||
} else
|
||||
gt->plot(painter, QRectF(rect.x(), rect.y() + rect.height() - gh,
|
||||
rect.width(), gh), ratio);
|
||||
} else {
|
||||
gh = 0;
|
||||
_mapView->plot(&p, QRectF(0, ih + mh, printer->width(), printer->height()
|
||||
- (ih + 2*mh + gh)), ratio, _options.hiresPrint);
|
||||
sc = 1;
|
||||
}
|
||||
|
||||
if (_graphTabWidget->isVisible() && _options.separateGraphPage) {
|
||||
printer->newPage();
|
||||
MapView::PlotFlags flags = MapView::NoFlags;
|
||||
if (_options.hiresPrint)
|
||||
flags |= MapView::HiRes;
|
||||
if (expand)
|
||||
flags |= MapView::Expand;
|
||||
|
||||
int cnt = 0;
|
||||
for (int i = 0; i < _tabs.size(); i++)
|
||||
if (!_tabs.at(i)->isEmpty())
|
||||
cnt++;
|
||||
_mapView->plot(painter, QRectF(rect.x(), rect.y() + ih + mh, rect.width(),
|
||||
rect.height() - (ih + sc*mh + gh)), ratio, flags);
|
||||
}
|
||||
|
||||
qreal sp = ratio * 20;
|
||||
gh = qMin((printer->height() - ((cnt - 1) * sp))/(qreal)cnt,
|
||||
0.20 * printer->height());
|
||||
void GUI::plotGraphsPage(QPainter *painter, const QRectF &rect, qreal ratio)
|
||||
{
|
||||
int cnt = 0;
|
||||
for (int i = 0; i < _tabs.size(); i++)
|
||||
if (!_tabs.at(i)->isEmpty())
|
||||
cnt++;
|
||||
|
||||
qreal y = 0;
|
||||
for (int i = 0; i < _tabs.size(); i++) {
|
||||
if (!_tabs.at(i)->isEmpty()) {
|
||||
_tabs.at(i)->plot(&p, QRectF(0, y, printer->width(), gh),
|
||||
ratio);
|
||||
y += gh + sp;
|
||||
}
|
||||
qreal sp = ratio * 20;
|
||||
qreal gh = qMin((rect.height() - ((cnt - 1) * sp))/(qreal)cnt,
|
||||
0.20 * rect.height());
|
||||
|
||||
qreal y = 0;
|
||||
for (int i = 0; i < _tabs.size(); i++) {
|
||||
if (!_tabs.at(i)->isEmpty()) {
|
||||
_tabs.at(i)->plot(painter, QRectF(rect.x(), rect.y() + y,
|
||||
rect.width(), gh), ratio);
|
||||
y += gh + sp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GUI::reloadFile()
|
||||
qreal GUI::graphPlotHeight(const QRectF &rect, qreal ratio)
|
||||
{
|
||||
int cnt = 0;
|
||||
for (int i = 0; i < _tabs.size(); i++)
|
||||
if (!_tabs.at(i)->isEmpty())
|
||||
cnt++;
|
||||
|
||||
qreal sp = ratio * 20;
|
||||
qreal gh = qMin((rect.height() - ((cnt - 1) * sp))/(qreal)cnt,
|
||||
0.20 * rect.height());
|
||||
|
||||
return cnt * gh + (cnt - 1) * sp;
|
||||
}
|
||||
|
||||
void GUI::plot(QPrinter *printer)
|
||||
{
|
||||
QPainter p(printer);
|
||||
qreal fsr = 1085.0 / (qMax(printer->width(), printer->height())
|
||||
/ (qreal)printer->resolution());
|
||||
qreal ratio = p.paintEngine()->paintDevice()->logicalDpiX() / fsr;
|
||||
QRectF rect(0, 0, printer->width(), printer->height());
|
||||
|
||||
plotMainPage(&p, rect, ratio);
|
||||
|
||||
if (!_tabs.isEmpty() && _options.separateGraphPage) {
|
||||
printer->newPage();
|
||||
plotGraphsPage(&p, rect, ratio);
|
||||
}
|
||||
}
|
||||
|
||||
void GUI::reloadFiles()
|
||||
{
|
||||
_trackCount = 0;
|
||||
_routeCount = 0;
|
||||
@ -1195,7 +1292,7 @@ void GUI::reloadFile()
|
||||
_routeDistance = 0;
|
||||
_time = 0;
|
||||
_movingTime = 0;
|
||||
_dateRange = DateRange(QDate(), QDate());
|
||||
_dateRange = DateTimeRange(QDateTime(), QDateTime());
|
||||
_pathName = QString();
|
||||
|
||||
for (int i = 0; i < _tabs.count(); i++)
|
||||
@ -1229,7 +1326,7 @@ void GUI::closeFiles()
|
||||
_routeDistance = 0;
|
||||
_time = 0;
|
||||
_movingTime = 0;
|
||||
_dateRange = DateRange(QDate(), QDate());
|
||||
_dateRange = DateTimeRange(QDateTime(), QDateTime());
|
||||
_pathName = QString();
|
||||
|
||||
_sliderPos = 0;
|
||||
@ -1539,8 +1636,7 @@ void GUI::setTimeType(TimeType type)
|
||||
|
||||
void GUI::setUnits(Units units)
|
||||
{
|
||||
_export.units = units;
|
||||
_options.units = units;
|
||||
_units = units;
|
||||
|
||||
_mapView->setUnits(units);
|
||||
for (int i = 0; i <_tabs.count(); i++)
|
||||
@ -1783,23 +1879,42 @@ void GUI::writeSettings()
|
||||
_showTicksAction->isChecked());
|
||||
settings.endGroup();
|
||||
|
||||
settings.beginGroup(EXPORT_SETTINGS_GROUP);
|
||||
if (_export.orientation != PAPER_ORIENTATION_DEFAULT)
|
||||
settings.setValue(PAPER_ORIENTATION_SETTING, _export.orientation);
|
||||
if (_export.resolution != RESOLUTION_DEFAULT)
|
||||
settings.setValue(RESOLUTION_SETTING, _export.resolution);
|
||||
if (_export.paperSize != PAPER_SIZE_DEFAULT)
|
||||
settings.setValue(PAPER_SIZE_SETTING, _export.paperSize);
|
||||
if (_export.margins.left() != MARGIN_LEFT_DEFAULT)
|
||||
settings.setValue(MARGIN_LEFT_SETTING, _export.margins.left());
|
||||
if (_export.margins.top() != MARGIN_TOP_DEFAULT)
|
||||
settings.setValue(MARGIN_TOP_SETTING, _export.margins.top());
|
||||
if (_export.margins.right() != MARGIN_RIGHT_DEFAULT)
|
||||
settings.setValue(MARGIN_RIGHT_SETTING, _export.margins.right());
|
||||
if (_export.margins.bottom() != MARGIN_BOTTOM_DEFAULT)
|
||||
settings.setValue(MARGIN_BOTTOM_SETTING, _export.margins.bottom());
|
||||
if (_export.fileName != EXPORT_FILENAME_DEFAULT)
|
||||
settings.setValue(EXPORT_FILENAME_SETTING, _export.fileName);
|
||||
settings.beginGroup(PDF_EXPORT_SETTINGS_GROUP);
|
||||
if (_pdfExport.orientation != PAPER_ORIENTATION_DEFAULT)
|
||||
settings.setValue(PAPER_ORIENTATION_SETTING, _pdfExport.orientation);
|
||||
if (_pdfExport.resolution != RESOLUTION_DEFAULT)
|
||||
settings.setValue(RESOLUTION_SETTING, _pdfExport.resolution);
|
||||
if (_pdfExport.paperSize != PAPER_SIZE_DEFAULT)
|
||||
settings.setValue(PAPER_SIZE_SETTING, _pdfExport.paperSize);
|
||||
if (_pdfExport.margins.left() != PDF_MARGIN_LEFT_DEFAULT)
|
||||
settings.setValue(PDF_MARGIN_LEFT_SETTING, _pdfExport.margins.left());
|
||||
if (_pdfExport.margins.top() != PDF_MARGIN_TOP_DEFAULT)
|
||||
settings.setValue(PDF_MARGIN_TOP_SETTING, _pdfExport.margins.top());
|
||||
if (_pdfExport.margins.right() != PDF_MARGIN_RIGHT_DEFAULT)
|
||||
settings.setValue(PDF_MARGIN_RIGHT_SETTING, _pdfExport.margins.right());
|
||||
if (_pdfExport.margins.bottom() != PDF_MARGIN_BOTTOM_DEFAULT)
|
||||
settings.setValue(PDF_MARGIN_BOTTOM_SETTING, _pdfExport.margins.bottom());
|
||||
if (_pdfExport.fileName != PDF_FILENAME_DEFAULT)
|
||||
settings.setValue(PDF_FILENAME_SETTING, _pdfExport.fileName);
|
||||
settings.endGroup();
|
||||
|
||||
settings.beginGroup(PNG_EXPORT_SETTINGS_GROUP);
|
||||
if (_pngExport.size.width() != PNG_WIDTH_DEFAULT)
|
||||
settings.setValue(PNG_WIDTH_SETTING, _pngExport.size.width());
|
||||
if (_pngExport.size.height() != PNG_HEIGHT_DEFAULT)
|
||||
settings.setValue(PNG_HEIGHT_SETTING, _pngExport.size.height());
|
||||
if (_pngExport.margins.left() != PNG_MARGIN_LEFT_DEFAULT)
|
||||
settings.setValue(PNG_MARGIN_LEFT_SETTING, _pngExport.margins.left());
|
||||
if (_pngExport.margins.top() != PNG_MARGIN_TOP_DEFAULT)
|
||||
settings.setValue(PNG_MARGIN_TOP_SETTING, _pngExport.margins.top());
|
||||
if (_pngExport.margins.right() != PNG_MARGIN_RIGHT_DEFAULT)
|
||||
settings.setValue(PNG_MARGIN_RIGHT_SETTING, _pngExport.margins.right());
|
||||
if (_pngExport.margins.bottom() != PNG_MARGIN_BOTTOM_DEFAULT)
|
||||
settings.setValue(PNG_MARGIN_BOTTOM_SETTING, _pngExport.margins.bottom());
|
||||
if (_pngExport.antialiasing != PNG_ANTIALIASING_DEFAULT)
|
||||
settings.setValue(PNG_ANTIALIASING_SETTING, _pngExport.antialiasing);
|
||||
if (_pngExport.fileName != PNG_FILENAME_DEFAULT)
|
||||
settings.setValue(PNG_FILENAME_SETTING, _pngExport.fileName);
|
||||
settings.endGroup();
|
||||
|
||||
settings.beginGroup(OPTIONS_SETTINGS_GROUP);
|
||||
@ -1867,6 +1982,13 @@ void GUI::writeSettings()
|
||||
if (_options.showSecondarySpeed != SHOW_SECONDARY_SPEED_DEFAULT)
|
||||
settings.setValue(SHOW_SECONDARY_SPEED_SETTING,
|
||||
_options.showSecondarySpeed);
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
if (_options.timeZone != TimeZoneInfo())
|
||||
settings.setValue(TIME_ZONE_SETTING, QVariant::fromValue(
|
||||
_options.timeZone));
|
||||
#endif // ENABLE_TIMEZONES
|
||||
if (_options.useSegments != USE_SEGMENTS_DEFAULT)
|
||||
settings.setValue(USE_SEGMENTS_SETTING, _options.useSegments);
|
||||
if (_options.poiRadius != POI_RADIUS_DEFAULT)
|
||||
settings.setValue(POI_RADIUS_SETTING, _options.poiRadius);
|
||||
if (_options.useOpenGL != USE_OPENGL_DEFAULT)
|
||||
@ -2058,23 +2180,42 @@ void GUI::readSettings()
|
||||
}
|
||||
settings.endGroup();
|
||||
|
||||
settings.beginGroup(EXPORT_SETTINGS_GROUP);
|
||||
_export.orientation = (QPrinter::Orientation) settings.value(
|
||||
settings.beginGroup(PDF_EXPORT_SETTINGS_GROUP);
|
||||
_pdfExport.orientation = (QPrinter::Orientation) settings.value(
|
||||
PAPER_ORIENTATION_SETTING, PAPER_ORIENTATION_DEFAULT).toInt();
|
||||
_export.resolution = settings.value(RESOLUTION_SETTING, RESOLUTION_DEFAULT)
|
||||
_pdfExport.resolution = settings.value(RESOLUTION_SETTING,
|
||||
RESOLUTION_DEFAULT).toInt();
|
||||
_pdfExport.paperSize = (QPrinter::PaperSize) settings.value(
|
||||
PAPER_SIZE_SETTING, PAPER_SIZE_DEFAULT).toInt();
|
||||
qreal ml = settings.value(PDF_MARGIN_LEFT_SETTING, PDF_MARGIN_LEFT_DEFAULT)
|
||||
.toReal();
|
||||
qreal mt = settings.value(PDF_MARGIN_TOP_SETTING, PDF_MARGIN_TOP_DEFAULT)
|
||||
.toReal();
|
||||
qreal mr = settings.value(PDF_MARGIN_RIGHT_SETTING,
|
||||
PDF_MARGIN_RIGHT_DEFAULT).toReal();
|
||||
qreal mb = settings.value(PDF_MARGIN_BOTTOM_SETTING,
|
||||
PDF_MARGIN_BOTTOM_DEFAULT).toReal();
|
||||
_pdfExport.margins = MarginsF(ml, mt, mr, mb);
|
||||
_pdfExport.fileName = settings.value(PDF_FILENAME_SETTING,
|
||||
PDF_FILENAME_DEFAULT).toString();
|
||||
settings.endGroup();
|
||||
|
||||
settings.beginGroup(PNG_EXPORT_SETTINGS_GROUP);
|
||||
_pngExport.size = QSize(settings.value(PNG_WIDTH_SETTING, PNG_WIDTH_DEFAULT)
|
||||
.toInt(), settings.value(PNG_HEIGHT_SETTING, PNG_HEIGHT_DEFAULT).toInt());
|
||||
int mli = settings.value(PNG_MARGIN_LEFT_SETTING, PNG_MARGIN_LEFT_DEFAULT)
|
||||
.toInt();
|
||||
_export.paperSize = (QPrinter::PaperSize) settings.value(PAPER_SIZE_SETTING,
|
||||
PAPER_SIZE_DEFAULT).toInt();
|
||||
qreal ml = settings.value(MARGIN_LEFT_SETTING, MARGIN_LEFT_DEFAULT)
|
||||
.toReal();
|
||||
qreal mt = settings.value(MARGIN_TOP_SETTING, MARGIN_TOP_DEFAULT).toReal();
|
||||
qreal mr = settings.value(MARGIN_RIGHT_SETTING, MARGIN_RIGHT_DEFAULT)
|
||||
.toReal();
|
||||
qreal mb = settings.value(MARGIN_BOTTOM_SETTING, MARGIN_BOTTOM_DEFAULT)
|
||||
.toReal();
|
||||
_export.margins = MarginsF(ml, mt, mr, mb);
|
||||
_export.fileName = settings.value(EXPORT_FILENAME_SETTING,
|
||||
EXPORT_FILENAME_DEFAULT).toString();
|
||||
int mti = settings.value(PNG_MARGIN_TOP_SETTING, PNG_MARGIN_TOP_DEFAULT)
|
||||
.toInt();
|
||||
int mri = settings.value(PNG_MARGIN_RIGHT_SETTING, PNG_MARGIN_RIGHT_DEFAULT)
|
||||
.toInt();
|
||||
int mbi = settings.value(PNG_MARGIN_BOTTOM_SETTING, PNG_MARGIN_BOTTOM_DEFAULT)
|
||||
.toInt();
|
||||
_pngExport.margins = QMargins(mli, mti, mri, mbi);
|
||||
_pngExport.antialiasing = settings.value(PNG_ANTIALIASING_SETTING,
|
||||
PNG_ANTIALIASING_DEFAULT).toBool();
|
||||
_pngExport.fileName = settings.value(PNG_FILENAME_SETTING,
|
||||
PNG_FILENAME_DEFAULT).toString();
|
||||
settings.endGroup();
|
||||
|
||||
settings.beginGroup(OPTIONS_SETTINGS_GROUP);
|
||||
@ -2139,6 +2280,11 @@ void GUI::readSettings()
|
||||
_options.showSecondarySpeed = settings.value(
|
||||
SHOW_SECONDARY_SPEED_SETTING,
|
||||
SHOW_SECONDARY_SPEED_DEFAULT).toBool();
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
_options.timeZone = settings.value(TIME_ZONE_SETTING).value<TimeZoneInfo>();
|
||||
#endif // ENABLE_TIMEZONES
|
||||
_options.useSegments = settings.value(USE_SEGMENTS_SETTING,
|
||||
USE_SEGMENTS_DEFAULT).toBool();
|
||||
_options.automaticPause = settings.value(AUTOMATIC_PAUSE_SETTING,
|
||||
AUTOMATIC_PAUSE_DEFAULT).toBool();
|
||||
_options.pauseInterval = settings.value(PAUSE_INTERVAL_SETTING,
|
||||
@ -2203,6 +2349,9 @@ void GUI::readSettings()
|
||||
_options.hidpiMap ? devicePixelRatioF() : 1.0);
|
||||
#endif // ENABLE_HIDPI
|
||||
_mapView->setProjection(_options.projection);
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
_mapView->setTimeZone(_options.timeZone.zone());
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
for (int i = 0; i < _tabs.count(); i++) {
|
||||
_tabs.at(i)->setPalette(_options.palette);
|
||||
@ -2227,6 +2376,7 @@ void GUI::readSettings()
|
||||
Track::useDEM(_options.dataUseDEM);
|
||||
Track::showSecondaryElevation(_options.showSecondaryElevation);
|
||||
Track::showSecondarySpeed(_options.showSecondarySpeed);
|
||||
Track::useSegments(_options.useSegments);
|
||||
Route::useDEM(_options.dataUseDEM);
|
||||
Route::showSecondaryElevation(_options.showSecondaryElevation);
|
||||
Waypoint::useDEM(_options.dataUseDEM);
|
||||
|
@ -10,7 +10,8 @@
|
||||
#include "units.h"
|
||||
#include "timetype.h"
|
||||
#include "format.h"
|
||||
#include "exportdialog.h"
|
||||
#include "pdfexportdialog.h"
|
||||
#include "pngexportdialog.h"
|
||||
#include "optionsdialog.h"
|
||||
|
||||
class QMenu;
|
||||
@ -45,10 +46,11 @@ private slots:
|
||||
void keys();
|
||||
void paths();
|
||||
void printFile();
|
||||
void exportFile();
|
||||
void exportPDFFile();
|
||||
void exportPNGFile();
|
||||
void openFile();
|
||||
void closeAll();
|
||||
void reloadFile();
|
||||
void reloadFiles();
|
||||
void statistics();
|
||||
void openPOIFile();
|
||||
void closePOIFiles();
|
||||
@ -92,11 +94,15 @@ private slots:
|
||||
void mapInitialized();
|
||||
|
||||
private:
|
||||
typedef QPair<QDate, QDate> DateRange;
|
||||
typedef QPair<QDateTime, QDateTime> DateTimeRange;
|
||||
|
||||
void loadPOIs();
|
||||
void closeFiles();
|
||||
void plot(QPrinter *printer);
|
||||
void plotMainPage(QPainter *painter, const QRectF &rect, qreal ratio,
|
||||
bool expand = false);
|
||||
void plotGraphsPage(QPainter *painter, const QRectF &rect, qreal ratio);
|
||||
qreal graphPlotHeight(const QRectF &rect, qreal ratio);
|
||||
|
||||
QAction *createPOIFileAction(const QString &fileName);
|
||||
MapAction *createMapAction(Map *map);
|
||||
@ -113,7 +119,6 @@ private:
|
||||
bool openPOIFile(const QString &fileName);
|
||||
bool loadFile(const QString &fileName);
|
||||
bool loadMap(const QString &fileName);
|
||||
void exportFile(const QString &fileName);
|
||||
void updateStatusBarInfo();
|
||||
void updateWindowTitle();
|
||||
void updateNavigationActions();
|
||||
@ -153,7 +158,8 @@ private:
|
||||
QAction *_aboutAction;
|
||||
QAction *_aboutQtAction;
|
||||
QAction *_printFileAction;
|
||||
QAction *_exportFileAction;
|
||||
QAction *_exportPDFFileAction;
|
||||
QAction *_exportPNGFileAction;
|
||||
QAction *_openFileAction;
|
||||
QAction *_closeFileAction;
|
||||
QAction *_reloadFileAction;
|
||||
@ -220,7 +226,7 @@ private:
|
||||
int _trackCount, _routeCount, _areaCount, _waypointCount;
|
||||
qreal _trackDistance, _routeDistance;
|
||||
qreal _time, _movingTime;
|
||||
DateRange _dateRange;
|
||||
DateTimeRange _dateRange;
|
||||
QString _pathName;
|
||||
|
||||
qreal _sliderPos;
|
||||
@ -228,10 +234,13 @@ private:
|
||||
QList<QByteArray> _windowStates;
|
||||
int _frameStyle;
|
||||
|
||||
Export _export;
|
||||
PDFExport _pdfExport;
|
||||
PNGExport _pngExport;
|
||||
Options _options;
|
||||
|
||||
QString _dataDir, _mapDir, _poiDir;
|
||||
|
||||
Units _units;
|
||||
};
|
||||
|
||||
#endif // GUI_H
|
||||
|
@ -18,7 +18,8 @@
|
||||
#define OPEN_SHORTCUT QKeySequence(QKeySequence::Open)
|
||||
#define CLOSE_SHORTCUT QKeySequence(QKeySequence::Close)
|
||||
#define RELOAD_SHORTCUT QKeySequence(QKeySequence::Refresh)
|
||||
#define EXPORT_SHORTCUT QKeySequence(Qt::CTRL + Qt::Key_E)
|
||||
#define PDF_EXPORT_SHORTCUT QKeySequence(Qt::CTRL + Qt::Key_E)
|
||||
#define PNG_EXPORT_SHORTCUT QKeySequence(Qt::CTRL + Qt::Key_X)
|
||||
#define SHOW_POI_SHORTCUT QKeySequence(Qt::CTRL + Qt::Key_P)
|
||||
#define SHOW_MAP_SHORTCUT QKeySequence(Qt::CTRL + Qt::Key_M)
|
||||
#define NEXT_MAP_SHORTCUT QKeySequence(QKeySequence::Forward)
|
||||
|
@ -13,7 +13,7 @@ public:
|
||||
{
|
||||
map->setParent(this);
|
||||
setData(QVariant::fromValue(map));
|
||||
setEnabled(map->isValid());
|
||||
setEnabled(map->isReady());
|
||||
connect(map, SIGNAL(mapLoaded()), this, SLOT(mapLoaded()));
|
||||
}
|
||||
|
||||
|
@ -59,8 +59,6 @@ MapView::MapView(Map *map, POI *poi, QWidget *parent)
|
||||
_poi = poi;
|
||||
connect(_poi, SIGNAL(pointsChanged()), this, SLOT(updatePOI()));
|
||||
|
||||
_units = Metric;
|
||||
_coordinatesFormat = DecimalDegrees;
|
||||
_mapOpacity = 1.0;
|
||||
_backgroundColor = Qt::white;
|
||||
_markerColor = Qt::red;
|
||||
@ -122,7 +120,6 @@ PathItem *MapView::addTrack(const Track &track)
|
||||
ti->setColor(_palette.nextColor());
|
||||
ti->setWidth(_trackWidth);
|
||||
ti->setStyle(_trackStyle);
|
||||
ti->setUnits(_units);
|
||||
ti->setVisible(_showTracks);
|
||||
ti->setDigitalZoom(_digitalZoom);
|
||||
ti->setMarkerColor(_markerColor);
|
||||
@ -149,8 +146,6 @@ PathItem *MapView::addRoute(const Route &route)
|
||||
ri->setColor(_palette.nextColor());
|
||||
ri->setWidth(_routeWidth);
|
||||
ri->setStyle(_routeStyle);
|
||||
ri->setUnits(_units);
|
||||
ri->setCoordinatesFormat(_coordinatesFormat);
|
||||
ri->setVisible(_showRoutes);
|
||||
ri->showWaypoints(_showRouteWaypoints);
|
||||
ri->showWaypointLabels(_showWaypointLabels);
|
||||
@ -200,7 +195,6 @@ void MapView::addWaypoints(const QVector<Waypoint> &waypoints)
|
||||
wi->setSize(_waypointSize);
|
||||
wi->setColor(_waypointColor);
|
||||
wi->showLabel(_showWaypointLabels);
|
||||
wi->setToolTipFormat(_units, _coordinatesFormat);
|
||||
wi->setVisible(_showWaypoints);
|
||||
wi->setDigitalZoom(_digitalZoom);
|
||||
_scene->addItem(wi);
|
||||
@ -401,7 +395,6 @@ void MapView::addPOI(const QList<Waypoint> &waypoints)
|
||||
pi->showLabel(_showPOILabels);
|
||||
pi->setVisible(_showPOI);
|
||||
pi->setDigitalZoom(_digitalZoom);
|
||||
pi->setToolTipFormat(_units, _coordinatesFormat);
|
||||
_scene->addItem(pi);
|
||||
|
||||
_pois.insert(SearchPointer<Waypoint>(&(pi->waypoint())), pi);
|
||||
@ -410,42 +403,32 @@ void MapView::addPOI(const QList<Waypoint> &waypoints)
|
||||
|
||||
void MapView::setUnits(Units units)
|
||||
{
|
||||
if (_units == units)
|
||||
return;
|
||||
|
||||
_units = units;
|
||||
|
||||
_mapScale->setUnits(_units);
|
||||
WaypointItem::setUnits(units);
|
||||
PathItem::setUnits(units);
|
||||
|
||||
for (int i = 0; i < _tracks.count(); i++)
|
||||
_tracks[i]->setUnits(_units);
|
||||
_tracks[i]->updateTicks();
|
||||
for (int i = 0; i < _routes.count(); i++)
|
||||
_routes[i]->setUnits(_units);
|
||||
for (int i = 0; i < _waypoints.size(); i++)
|
||||
_waypoints.at(i)->setToolTipFormat(_units, _coordinatesFormat);
|
||||
_routes[i]->updateTicks();
|
||||
|
||||
for (POIHash::const_iterator it = _pois.constBegin();
|
||||
it != _pois.constEnd(); it++)
|
||||
it.value()->setToolTipFormat(_units, _coordinatesFormat);
|
||||
_mapScale->setUnits(units);
|
||||
}
|
||||
|
||||
void MapView::setCoordinatesFormat(CoordinatesFormat format)
|
||||
{
|
||||
if (_coordinatesFormat == format)
|
||||
return;
|
||||
WaypointItem::setCoordinatesFormat(format);
|
||||
|
||||
_coordinatesFormat = format;
|
||||
_coordinates->setFormat(format);
|
||||
}
|
||||
|
||||
_coordinates->setFormat(_coordinatesFormat);
|
||||
|
||||
for (int i = 0; i < _waypoints.count(); i++)
|
||||
_waypoints.at(i)->setToolTipFormat(_units, _coordinatesFormat);
|
||||
for (int i = 0; i < _routes.count(); i++)
|
||||
_routes[i]->setCoordinatesFormat(_coordinatesFormat);
|
||||
|
||||
for (POIHash::const_iterator it = _pois.constBegin();
|
||||
it != _pois.constEnd(); it++)
|
||||
it.value()->setToolTipFormat(_units, _coordinatesFormat);
|
||||
void MapView::setTimeZone(const QTimeZone &zone)
|
||||
{
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
WaypointItem::setTimeZone(zone);
|
||||
PathItem::setTimeZone(zone);
|
||||
#else // ENABLE_TIMEZONES
|
||||
Q_UNUSED(zone);
|
||||
#endif // ENABLE_TIMEZONES
|
||||
}
|
||||
|
||||
void MapView::clearMapCache()
|
||||
@ -548,7 +531,7 @@ void MapView::keyPressEvent(QKeyEvent *event)
|
||||
}
|
||||
|
||||
void MapView::plot(QPainter *painter, const QRectF &target, qreal scale,
|
||||
bool hires)
|
||||
PlotFlags flags)
|
||||
{
|
||||
QRect orig, adj;
|
||||
qreal ratio, diff, q;
|
||||
@ -576,10 +559,18 @@ void MapView::plot(QPainter *painter, const QRectF &target, qreal scale,
|
||||
diff = (orig.height() * ratio) - orig.width();
|
||||
adj = orig.adjusted(-diff/2, 0, diff/2, 0);
|
||||
}
|
||||
q = (target.width() / scale) / adj.width();
|
||||
|
||||
// Expand the view if plotting into a bitmap
|
||||
if (flags & Expand) {
|
||||
qreal xdiff = (target.width() - adj.width()) / 2.0;
|
||||
qreal ydiff = (target.height() - adj.height()) / 2.0;
|
||||
adj.adjust(-xdiff, -ydiff, xdiff, ydiff);
|
||||
q = 1.0;
|
||||
} else
|
||||
q = (target.width() / scale) / adj.width();
|
||||
|
||||
// Adjust the view for printing
|
||||
if (hires) {
|
||||
if (flags & HiRes) {
|
||||
zoom = _map->zoom();
|
||||
QRectF vr(mapToScene(orig).boundingRect());
|
||||
origScene = vr.center();
|
||||
@ -611,7 +602,7 @@ void MapView::plot(QPainter *painter, const QRectF &target, qreal scale,
|
||||
render(painter, target, adj);
|
||||
|
||||
// Revert view changes to display mode
|
||||
if (hires) {
|
||||
if (flags & HiRes) {
|
||||
_map->setZoom(zoom);
|
||||
rescale();
|
||||
centerOn(origScene);
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <QVector>
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
#include <QFlags>
|
||||
#include "common/rectc.h"
|
||||
#include "common/config.h"
|
||||
#include "data/waypoint.h"
|
||||
@ -31,12 +32,20 @@ class GraphItem;
|
||||
class AreaItem;
|
||||
class Area;
|
||||
class GraphicsScene;
|
||||
class QTimeZone;
|
||||
|
||||
class MapView : public QGraphicsView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Flag {
|
||||
NoFlags = 0,
|
||||
HiRes = 1,
|
||||
Expand = 2
|
||||
};
|
||||
Q_DECLARE_FLAGS(PlotFlags, Flag)
|
||||
|
||||
MapView(Map *map, POI *poi, QWidget *parent = 0);
|
||||
|
||||
QList<PathItem *> loadData(const Data &data);
|
||||
@ -45,7 +54,8 @@ public:
|
||||
void setPOI(POI *poi);
|
||||
void setMap(Map *map);
|
||||
|
||||
void plot(QPainter *painter, const QRectF &target, qreal scale, bool hires);
|
||||
void plot(QPainter *painter, const QRectF &target, qreal scale,
|
||||
PlotFlags flags);
|
||||
|
||||
void clear();
|
||||
|
||||
@ -83,6 +93,7 @@ public slots:
|
||||
void showTicks(bool show);
|
||||
void clearMapCache();
|
||||
void setCoordinatesFormat(CoordinatesFormat format);
|
||||
void setTimeZone(const QTimeZone &zone);
|
||||
void setDevicePixelRatio(qreal deviceRatio, qreal mapRatio);
|
||||
void setProjection(int id);
|
||||
|
||||
@ -137,8 +148,6 @@ private:
|
||||
POI *_poi;
|
||||
|
||||
Palette _palette;
|
||||
Units _units;
|
||||
CoordinatesFormat _coordinatesFormat;
|
||||
qreal _mapOpacity;
|
||||
Projection _projection;
|
||||
|
||||
|
@ -16,15 +16,22 @@ public:
|
||||
qreal right() const {return _right;}
|
||||
qreal bottom() const {return _bottom;}
|
||||
|
||||
qreal &rleft() {return _left;}
|
||||
qreal &rtop() {return _top;}
|
||||
qreal &rright() {return _right;}
|
||||
qreal &rbottom() {return _bottom;}
|
||||
|
||||
private:
|
||||
qreal _left, _top, _right, _bottom;
|
||||
};
|
||||
|
||||
inline MarginsF operator*(const MarginsF &margins, qreal factor)
|
||||
{
|
||||
return MarginsF(margins.left() * factor, margins.top() * factor,
|
||||
margins.right() * factor, margins.bottom() * factor);
|
||||
}
|
||||
|
||||
inline MarginsF operator/(const MarginsF &margins, qreal factor)
|
||||
{
|
||||
return MarginsF(margins.left() / factor, margins.top() / factor,
|
||||
margins.right() / factor, margins.bottom() / factor);
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
inline QDebug operator<<(QDebug dbg, const MarginsF &margins)
|
||||
{
|
||||
|
111
src/GUI/marginswidget.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
#include <QSpinBox>
|
||||
#include <QGridLayout>
|
||||
#include "units.h"
|
||||
#include "marginswidget.h"
|
||||
|
||||
MarginsWidget::MarginsWidget(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
_top = new QSpinBox();
|
||||
_bottom = new QSpinBox();
|
||||
_left = new QSpinBox();
|
||||
_right = new QSpinBox();
|
||||
|
||||
_top->setMaximumWidth(_top->sizeHint().width());
|
||||
_bottom->setMaximumWidth(_bottom->sizeHint().width());
|
||||
_left->setMaximumWidth(_left->sizeHint().width());
|
||||
_right->setMaximumWidth(_right->sizeHint().width());
|
||||
|
||||
QGridLayout *layout = new QGridLayout();
|
||||
layout->addWidget(_top, 0, 0, 1, 2, Qt::AlignCenter);
|
||||
layout->addWidget(_left, 1, 0, 1, 1, Qt::AlignRight);
|
||||
layout->addWidget(_right, 1, 1, 1, 1, Qt::AlignLeft);
|
||||
layout->addWidget(_bottom, 2, 0, 1, 2, Qt::AlignCenter);
|
||||
|
||||
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
void MarginsWidget::setValue(const QMargins &value)
|
||||
{
|
||||
_top->setValue(value.top());
|
||||
_bottom->setValue(value.bottom());
|
||||
_left->setValue(value.left());
|
||||
_right->setValue(value.right());
|
||||
}
|
||||
|
||||
void MarginsWidget::setUnits(const QString &units)
|
||||
{
|
||||
_top->setSuffix(UNIT_SPACE + units);
|
||||
_bottom->setSuffix(UNIT_SPACE + units);
|
||||
_left->setSuffix(UNIT_SPACE + units);
|
||||
_right->setSuffix(UNIT_SPACE + units);
|
||||
|
||||
_top->setMaximumWidth(_top->sizeHint().width());
|
||||
_bottom->setMaximumWidth(_bottom->sizeHint().width());
|
||||
_left->setMaximumWidth(_left->sizeHint().width());
|
||||
_right->setMaximumWidth(_right->sizeHint().width());
|
||||
}
|
||||
|
||||
QMargins MarginsWidget::value() const
|
||||
{
|
||||
return QMargins(_left->value(), _top->value(), _right->value(),
|
||||
_bottom->value());
|
||||
}
|
||||
|
||||
|
||||
MarginsFWidget::MarginsFWidget(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
_top = new QDoubleSpinBox();
|
||||
_bottom = new QDoubleSpinBox();
|
||||
_left = new QDoubleSpinBox();
|
||||
_right = new QDoubleSpinBox();
|
||||
|
||||
_top->setMaximumWidth(_top->sizeHint().width());
|
||||
_bottom->setMaximumWidth(_bottom->sizeHint().width());
|
||||
_left->setMaximumWidth(_left->sizeHint().width());
|
||||
_right->setMaximumWidth(_right->sizeHint().width());
|
||||
|
||||
QGridLayout *layout = new QGridLayout();
|
||||
layout->addWidget(_top, 0, 0, 1, 2, Qt::AlignCenter);
|
||||
layout->addWidget(_left, 1, 0, 1, 1, Qt::AlignRight);
|
||||
layout->addWidget(_right, 1, 1, 1, 1, Qt::AlignLeft);
|
||||
layout->addWidget(_bottom, 2, 0, 1, 2, Qt::AlignCenter);
|
||||
|
||||
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
void MarginsFWidget::setValue(const MarginsF &value)
|
||||
{
|
||||
_top->setValue(value.top());
|
||||
_bottom->setValue(value.bottom());
|
||||
_left->setValue(value.left());
|
||||
_right->setValue(value.right());
|
||||
}
|
||||
|
||||
void MarginsFWidget::setUnits(const QString &units)
|
||||
{
|
||||
_top->setSuffix(UNIT_SPACE + units);
|
||||
_bottom->setSuffix(UNIT_SPACE + units);
|
||||
_left->setSuffix(UNIT_SPACE + units);
|
||||
_right->setSuffix(UNIT_SPACE + units);
|
||||
|
||||
_top->setMaximumWidth(_top->sizeHint().width());
|
||||
_bottom->setMaximumWidth(_bottom->sizeHint().width());
|
||||
_left->setMaximumWidth(_left->sizeHint().width());
|
||||
_right->setMaximumWidth(_right->sizeHint().width());
|
||||
}
|
||||
|
||||
void MarginsFWidget::setSingleStep(qreal step)
|
||||
{
|
||||
_top->setSingleStep(step);
|
||||
_bottom->setSingleStep(step);
|
||||
_left->setSingleStep(step);
|
||||
_right->setSingleStep(step);
|
||||
}
|
||||
|
||||
MarginsF MarginsFWidget::value() const
|
||||
{
|
||||
return MarginsF(_left->value(), _top->value(), _right->value(),
|
||||
_bottom->value());
|
||||
}
|
48
src/GUI/marginswidget.h
Normal file
@ -0,0 +1,48 @@
|
||||
#ifndef MARGINSWIDGET_H
|
||||
#define MARGINSWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QMargins>
|
||||
#include "margins.h"
|
||||
|
||||
class QSpinBox;
|
||||
class QDoubleSpinBox;
|
||||
|
||||
class MarginsWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MarginsWidget(QWidget *parent = 0);
|
||||
|
||||
QMargins value() const;
|
||||
void setValue(const QMargins &value);
|
||||
void setUnits(const QString &units);
|
||||
|
||||
private:
|
||||
QSpinBox *_top;
|
||||
QSpinBox *_bottom;
|
||||
QSpinBox *_left;
|
||||
QSpinBox *_right;
|
||||
};
|
||||
|
||||
class MarginsFWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MarginsFWidget(QWidget *parent = 0);
|
||||
|
||||
MarginsF value() const;
|
||||
void setValue(const MarginsF &value);
|
||||
void setUnits(const QString &units);
|
||||
void setSingleStep(qreal step);
|
||||
|
||||
private:
|
||||
QDoubleSpinBox *_top;
|
||||
QDoubleSpinBox *_bottom;
|
||||
QDoubleSpinBox *_left;
|
||||
QDoubleSpinBox *_right;
|
||||
};
|
||||
|
||||
#endif // MARGINSWIDGET_H
|
@ -56,12 +56,12 @@ QWidget *OptionsDialog::createMapPage()
|
||||
+ projections.at(i).value();
|
||||
_projection->addItem(text, QVariant(projections.at(i).key()));
|
||||
}
|
||||
_projection->setCurrentIndex(_projection->findData(_options->projection));
|
||||
_projection->setCurrentIndex(_projection->findData(_options.projection));
|
||||
|
||||
#ifdef ENABLE_HIDPI
|
||||
_hidpi = new QRadioButton(tr("High-resolution"));
|
||||
_lodpi = new QRadioButton(tr("Standard"));
|
||||
if (_options->hidpiMap)
|
||||
if (_options.hidpiMap)
|
||||
_hidpi->setChecked(true);
|
||||
else
|
||||
_lodpi->setChecked(true);
|
||||
@ -112,10 +112,10 @@ QWidget *OptionsDialog::createAppearancePage()
|
||||
{
|
||||
// Tracks
|
||||
_trackWidth = new QSpinBox();
|
||||
_trackWidth->setValue(_options->trackWidth);
|
||||
_trackWidth->setValue(_options.trackWidth);
|
||||
_trackWidth->setMinimum(1);
|
||||
_trackStyle = new StyleComboBox();
|
||||
_trackStyle->setValue(_options->trackStyle);
|
||||
_trackStyle->setValue(_options.trackStyle);
|
||||
QFormLayout *trackLayout = new QFormLayout();
|
||||
#ifdef Q_OS_MAC
|
||||
trackLayout->addRow(tr("Track width:"), _trackWidth);
|
||||
@ -129,10 +129,10 @@ QWidget *OptionsDialog::createAppearancePage()
|
||||
|
||||
// Routes
|
||||
_routeWidth = new QSpinBox();
|
||||
_routeWidth->setValue(_options->routeWidth);
|
||||
_routeWidth->setValue(_options.routeWidth);
|
||||
_routeWidth->setMinimum(1);
|
||||
_routeStyle = new StyleComboBox();
|
||||
_routeStyle->setValue(_options->routeStyle);
|
||||
_routeStyle->setValue(_options.routeStyle);
|
||||
QFormLayout *routeLayout = new QFormLayout();
|
||||
#ifdef Q_OS_MAC
|
||||
routeLayout->addRow(tr("Route width:"), _routeWidth);
|
||||
@ -146,11 +146,11 @@ QWidget *OptionsDialog::createAppearancePage()
|
||||
|
||||
// Areas
|
||||
_areaWidth = new QSpinBox();
|
||||
_areaWidth->setValue(_options->areaWidth);
|
||||
_areaWidth->setValue(_options.areaWidth);
|
||||
_areaStyle = new StyleComboBox();
|
||||
_areaStyle->setValue(_options->areaStyle);
|
||||
_areaStyle->setValue(_options.areaStyle);
|
||||
_areaOpacity = new PercentSlider();
|
||||
_areaOpacity->setValue(_options->areaOpacity);
|
||||
_areaOpacity->setValue(_options.areaOpacity);
|
||||
QFormLayout *areaLayout = new QFormLayout();
|
||||
#ifdef Q_OS_MAC
|
||||
areaLayout->addRow(tr("Area border width:"), _areaWidth);
|
||||
@ -166,18 +166,15 @@ QWidget *OptionsDialog::createAppearancePage()
|
||||
|
||||
// Palette & antialiasing
|
||||
_baseColor = new ColorBox();
|
||||
_baseColor->setColor(_options->palette.color());
|
||||
_colorOffset = new QDoubleSpinBox();
|
||||
_colorOffset->setMinimum(0);
|
||||
_colorOffset->setMaximum(1.0);
|
||||
_colorOffset->setSingleStep(0.01);
|
||||
_colorOffset->setValue(_options->palette.shift());
|
||||
_baseColor->setColor(_options.palette.color());
|
||||
_colorOffset = new PercentSlider();
|
||||
_colorOffset->setValue(_options.palette.shift() * 100);
|
||||
QFormLayout *paletteLayout = new QFormLayout();
|
||||
paletteLayout->addRow(tr("Base color:"), _baseColor);
|
||||
paletteLayout->addRow(tr("Palette shift:"), _colorOffset);
|
||||
|
||||
_pathAA = new QCheckBox(tr("Use anti-aliasing"));
|
||||
_pathAA->setChecked(_options->pathAntiAliasing);
|
||||
_pathAA->setChecked(_options.pathAntiAliasing);
|
||||
QFormLayout *pathAALayout = new QFormLayout();
|
||||
pathAALayout->addWidget(_pathAA);
|
||||
|
||||
@ -204,9 +201,9 @@ QWidget *OptionsDialog::createAppearancePage()
|
||||
// Waypoints
|
||||
_waypointSize = new QSpinBox();
|
||||
_waypointSize->setMinimum(1);
|
||||
_waypointSize->setValue(_options->waypointSize);
|
||||
_waypointSize->setValue(_options.waypointSize);
|
||||
_waypointColor = new ColorBox();
|
||||
_waypointColor->setColor(_options->waypointColor);
|
||||
_waypointColor->setColor(_options.waypointColor);
|
||||
QFormLayout *waypointLayout = new QFormLayout();
|
||||
#ifdef Q_OS_MAC
|
||||
waypointLayout->addRow(tr("Waypoint color:"), _waypointColor);
|
||||
@ -220,9 +217,9 @@ QWidget *OptionsDialog::createAppearancePage()
|
||||
|
||||
_poiSize = new QSpinBox();
|
||||
_poiSize->setMinimum(1);
|
||||
_poiSize->setValue(_options->poiSize);
|
||||
_poiSize->setValue(_options.poiSize);
|
||||
_poiColor = new ColorBox();
|
||||
_poiColor->setColor(_options->poiColor);
|
||||
_poiColor->setColor(_options.poiColor);
|
||||
QFormLayout *poiLayout = new QFormLayout();
|
||||
#ifdef Q_OS_MAC
|
||||
poiLayout->addRow(tr("POI color:"), _poiColor);
|
||||
@ -250,9 +247,9 @@ QWidget *OptionsDialog::createAppearancePage()
|
||||
|
||||
// Graphs
|
||||
_sliderColor = new ColorBox();
|
||||
_sliderColor->setColor(_options->sliderColor);
|
||||
_sliderColor->setColor(_options.sliderColor);
|
||||
_graphWidth = new QSpinBox();
|
||||
_graphWidth->setValue(_options->graphWidth);
|
||||
_graphWidth->setValue(_options.graphWidth);
|
||||
_graphWidth->setMinimum(1);
|
||||
|
||||
QFormLayout *graphLayout = new QFormLayout();
|
||||
@ -260,7 +257,7 @@ QWidget *OptionsDialog::createAppearancePage()
|
||||
graphLayout->addRow(tr("Slider color:"), _sliderColor);
|
||||
|
||||
_graphAA = new QCheckBox(tr("Use anti-aliasing"));
|
||||
_graphAA->setChecked(_options->graphAntiAliasing);
|
||||
_graphAA->setChecked(_options.graphAntiAliasing);
|
||||
QFormLayout *graphAALayout = new QFormLayout();
|
||||
graphAALayout->addWidget(_graphAA);
|
||||
|
||||
@ -274,9 +271,9 @@ QWidget *OptionsDialog::createAppearancePage()
|
||||
|
||||
// Map
|
||||
_mapOpacity = new PercentSlider();
|
||||
_mapOpacity->setValue(_options->mapOpacity);
|
||||
_mapOpacity->setValue(_options.mapOpacity);
|
||||
_backgroundColor = new ColorBox();
|
||||
_backgroundColor->setColor(_options->backgroundColor);
|
||||
_backgroundColor->setColor(_options.backgroundColor);
|
||||
_backgroundColor->enableAlphaChannel(false);
|
||||
|
||||
QFormLayout *mapLayout = new QFormLayout();
|
||||
@ -304,19 +301,19 @@ QWidget *OptionsDialog::createDataPage()
|
||||
QString filterToolTip = tr("Moving average window size");
|
||||
|
||||
_elevationFilter = new OddSpinBox();
|
||||
_elevationFilter->setValue(_options->elevationFilter);
|
||||
_elevationFilter->setValue(_options.elevationFilter);
|
||||
_elevationFilter->setToolTip(filterToolTip);
|
||||
_speedFilter = new OddSpinBox();
|
||||
_speedFilter->setValue(_options->speedFilter);
|
||||
_speedFilter->setValue(_options.speedFilter);
|
||||
_speedFilter->setToolTip(filterToolTip);
|
||||
_heartRateFilter = new OddSpinBox();
|
||||
_heartRateFilter->setValue(_options->heartRateFilter);
|
||||
_heartRateFilter->setValue(_options.heartRateFilter);
|
||||
_heartRateFilter->setToolTip(filterToolTip);
|
||||
_cadenceFilter = new OddSpinBox();
|
||||
_cadenceFilter->setValue(_options->cadenceFilter);
|
||||
_cadenceFilter->setValue(_options.cadenceFilter);
|
||||
_cadenceFilter->setToolTip(filterToolTip);
|
||||
_powerFilter = new OddSpinBox();
|
||||
_powerFilter->setValue(_options->powerFilter);
|
||||
_powerFilter->setValue(_options.powerFilter);
|
||||
_powerFilter->setToolTip(filterToolTip);
|
||||
|
||||
QFormLayout *smoothLayout = new QFormLayout();
|
||||
@ -331,7 +328,7 @@ QWidget *OptionsDialog::createDataPage()
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
_outlierEliminate = new QCheckBox(tr("Eliminate GPS outliers"));
|
||||
_outlierEliminate->setChecked(_options->outlierEliminate);
|
||||
_outlierEliminate->setChecked(_options.outlierEliminate);
|
||||
|
||||
QFormLayout *outlierLayout = new QFormLayout();
|
||||
outlierLayout->addWidget(_outlierEliminate);
|
||||
@ -352,7 +349,7 @@ QWidget *OptionsDialog::createDataPage()
|
||||
|
||||
_automaticPause = new QRadioButton(tr("Automatic"));
|
||||
_manualPause = new QRadioButton(tr("Custom"));
|
||||
if (_options->automaticPause)
|
||||
if (_options.automaticPause)
|
||||
_automaticPause->setChecked(true);
|
||||
else
|
||||
_manualPause->setChecked(true);
|
||||
@ -362,20 +359,20 @@ QWidget *OptionsDialog::createDataPage()
|
||||
_pauseSpeed->setSingleStep(0.1);
|
||||
_pauseSpeed->setMinimum(0.1);
|
||||
_pauseSpeed->setEnabled(_manualPause->isChecked());
|
||||
if (_options->units == Imperial) {
|
||||
_pauseSpeed->setValue(_options->pauseSpeed * MS2MIH);
|
||||
if (_units == Imperial) {
|
||||
_pauseSpeed->setValue(_options.pauseSpeed * MS2MIH);
|
||||
_pauseSpeed->setSuffix(UNIT_SPACE + tr("mi/h"));
|
||||
} else if (_options->units == Nautical) {
|
||||
_pauseSpeed->setValue(_options->pauseSpeed * MS2KN);
|
||||
} else if (_units == Nautical) {
|
||||
_pauseSpeed->setValue(_options.pauseSpeed * MS2KN);
|
||||
_pauseSpeed->setSuffix(UNIT_SPACE + tr("kn"));
|
||||
} else {
|
||||
_pauseSpeed->setValue(_options->pauseSpeed * MS2KMH);
|
||||
_pauseSpeed->setValue(_options.pauseSpeed * MS2KMH);
|
||||
_pauseSpeed->setSuffix(UNIT_SPACE + tr("km/h"));
|
||||
}
|
||||
_pauseInterval = new QSpinBox();
|
||||
_pauseInterval->setMinimum(1);
|
||||
_pauseInterval->setSuffix(UNIT_SPACE + tr("s"));
|
||||
_pauseInterval->setValue(_options->pauseInterval);
|
||||
_pauseInterval->setValue(_options.pauseInterval);
|
||||
_pauseInterval->setEnabled(_manualPause->isChecked());
|
||||
|
||||
connect(_automaticPause, SIGNAL(toggled(bool)), this,
|
||||
@ -403,21 +400,47 @@ QWidget *OptionsDialog::createDataPage()
|
||||
|
||||
_computedSpeed = new QRadioButton(tr("Computed from distance/time"));
|
||||
_reportedSpeed = new QRadioButton(tr("Recorded by device"));
|
||||
if (_options->useReportedSpeed)
|
||||
if (_options.useReportedSpeed)
|
||||
_reportedSpeed->setChecked(true);
|
||||
else
|
||||
_computedSpeed->setChecked(true);
|
||||
_showSecondarySpeed = new QCheckBox(tr("Show secondary speed"));
|
||||
_showSecondarySpeed->setChecked(_options->showSecondarySpeed);
|
||||
_showSecondarySpeed->setChecked(_options.showSecondarySpeed);
|
||||
|
||||
_dataGPSElevation = new QRadioButton(tr("GPS data"));
|
||||
_dataDEMElevation = new QRadioButton(tr("DEM data"));
|
||||
if (_options->dataUseDEM)
|
||||
if (_options.dataUseDEM)
|
||||
_dataDEMElevation->setChecked(true);
|
||||
else
|
||||
_dataGPSElevation->setChecked(true);
|
||||
_showSecondaryElevation = new QCheckBox(tr("Show secondary elevation"));
|
||||
_showSecondaryElevation->setChecked(_options->showSecondaryElevation);
|
||||
_showSecondaryElevation->setChecked(_options.showSecondaryElevation);
|
||||
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
_utcZone = new QRadioButton(tr("UTC"));
|
||||
_systemZone = new QRadioButton(tr("System"));
|
||||
_customZone = new QRadioButton(tr("Custom"));
|
||||
if (_options.timeZone.type() == TimeZoneInfo::UTC)
|
||||
_utcZone->setChecked(true);
|
||||
else if (_options.timeZone.type() == TimeZoneInfo::System)
|
||||
_systemZone->setChecked(true);
|
||||
else
|
||||
_customZone->setChecked(true);
|
||||
_timeZone = new QComboBox();
|
||||
_timeZone->setEnabled(_customZone->isChecked());
|
||||
QList<QByteArray> zones = QTimeZone::availableTimeZoneIds();
|
||||
for (int i = 0; i < zones.size(); i++)
|
||||
_timeZone->addItem(zones.at(i));
|
||||
_timeZone->setCurrentText(_options.timeZone.customZone().id());
|
||||
connect(_customZone, SIGNAL(toggled(bool)), _timeZone,
|
||||
SLOT(setEnabled(bool)));
|
||||
QHBoxLayout *customZoneLayout = new QHBoxLayout();
|
||||
customZoneLayout->addSpacing(20);
|
||||
customZoneLayout->addWidget(_timeZone);
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
_useSegments = new QCheckBox(tr("Use segments"));
|
||||
_useSegments->setChecked(_options.useSegments);
|
||||
|
||||
QWidget *sourceTab = new QWidget();
|
||||
QVBoxLayout *sourceTabLayout = new QVBoxLayout();
|
||||
@ -439,14 +462,34 @@ QWidget *OptionsDialog::createDataPage()
|
||||
elevationOptions->addWidget(_dataDEMElevation);
|
||||
elevationOptions->addWidget(_showSecondaryElevation);
|
||||
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
QButtonGroup *timeZoneGroup = new QButtonGroup(this);
|
||||
timeZoneGroup->addButton(_utcZone);
|
||||
timeZoneGroup->addButton(_systemZone);
|
||||
timeZoneGroup->addButton(_customZone);
|
||||
QVBoxLayout *zoneOptions = new QVBoxLayout();
|
||||
zoneOptions->addWidget(_utcZone);
|
||||
zoneOptions->addWidget(_systemZone);
|
||||
zoneOptions->addWidget(_customZone);
|
||||
zoneOptions->addItem(customZoneLayout);
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
QFormLayout *formLayout = new QFormLayout();
|
||||
formLayout->addRow(tr("Speed:"), speedOptions);
|
||||
formLayout->addRow(tr("Elevation:"), elevationOptions);
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
formLayout->addRow(tr("Time zone:"), zoneOptions);
|
||||
#endif // ENABLE_TIMEZONES
|
||||
formLayout->addRow(_useSegments);
|
||||
|
||||
sourceTabLayout->addLayout(formLayout);
|
||||
#else // Q_OS_MAC
|
||||
QFormLayout *speedLayout = new QFormLayout();
|
||||
QFormLayout *elevationLayout = new QFormLayout();
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
QFormLayout *timeZoneLayout = new QFormLayout();
|
||||
#endif // ENABLE_TIMEZONES
|
||||
QFormLayout *segmentsLayout = new QFormLayout();
|
||||
|
||||
speedLayout->addWidget(_computedSpeed);
|
||||
speedLayout->addWidget(_reportedSpeed);
|
||||
@ -462,8 +505,24 @@ QWidget *OptionsDialog::createDataPage()
|
||||
QGroupBox *elevationBox = new QGroupBox(tr("Elevation"));
|
||||
elevationBox->setLayout(elevationLayout);
|
||||
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
timeZoneLayout->addWidget(_utcZone);
|
||||
timeZoneLayout->addWidget(_systemZone);
|
||||
timeZoneLayout->addWidget(_customZone);
|
||||
timeZoneLayout->addItem(customZoneLayout);
|
||||
|
||||
QGroupBox *timeZoneBox = new QGroupBox(tr("Time zone"));
|
||||
timeZoneBox->setLayout(timeZoneLayout);
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
segmentsLayout->addWidget(_useSegments);
|
||||
|
||||
sourceTabLayout->addWidget(speedBox);
|
||||
sourceTabLayout->addWidget(elevationBox);
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
sourceTabLayout->addWidget(timeZoneBox);
|
||||
#endif // ENABLE_TIMEZONES
|
||||
sourceTabLayout->addLayout(segmentsLayout);
|
||||
#endif // Q_OS_MAC
|
||||
sourceTabLayout->addStretch();
|
||||
sourceTab->setLayout(sourceTabLayout);
|
||||
@ -482,14 +541,14 @@ QWidget *OptionsDialog::createPOIPage()
|
||||
_poiRadius = new QDoubleSpinBox();
|
||||
_poiRadius->setSingleStep(1);
|
||||
_poiRadius->setDecimals(1);
|
||||
if (_options->units == Imperial) {
|
||||
_poiRadius->setValue(_options->poiRadius / MIINM);
|
||||
if (_units == Imperial) {
|
||||
_poiRadius->setValue(_options.poiRadius / MIINM);
|
||||
_poiRadius->setSuffix(UNIT_SPACE + tr("mi"));
|
||||
} else if (_options->units == Nautical) {
|
||||
_poiRadius->setValue(_options->poiRadius / NMIINM);
|
||||
} else if (_units == Nautical) {
|
||||
_poiRadius->setValue(_options.poiRadius / NMIINM);
|
||||
_poiRadius->setSuffix(UNIT_SPACE + tr("nmi"));
|
||||
} else {
|
||||
_poiRadius->setValue(_options->poiRadius / KMINM);
|
||||
_poiRadius->setValue(_options.poiRadius / KMINM);
|
||||
_poiRadius->setSuffix(UNIT_SPACE + tr("km"));
|
||||
}
|
||||
|
||||
@ -509,7 +568,7 @@ QWidget *OptionsDialog::createExportPage()
|
||||
{
|
||||
_wysiwyg = new QRadioButton(tr("WYSIWYG"));
|
||||
_hires = new QRadioButton(tr("High-Resolution"));
|
||||
if (_options->hiresPrint)
|
||||
if (_options.hiresPrint)
|
||||
_hires->setChecked(true);
|
||||
else
|
||||
_wysiwyg->setChecked(true);
|
||||
@ -538,17 +597,17 @@ QWidget *OptionsDialog::createExportPage()
|
||||
|
||||
|
||||
_name = new QCheckBox(tr("Name"));
|
||||
_name->setChecked(_options->printName);
|
||||
_name->setChecked(_options.printName);
|
||||
_date = new QCheckBox(tr("Date"));
|
||||
_date->setChecked(_options->printDate);
|
||||
_date->setChecked(_options.printDate);
|
||||
_distance = new QCheckBox(tr("Distance"));
|
||||
_distance->setChecked(_options->printDistance);
|
||||
_distance->setChecked(_options.printDistance);
|
||||
_time = new QCheckBox(tr("Time"));
|
||||
_time->setChecked(_options->printTime);
|
||||
_time->setChecked(_options.printTime);
|
||||
_movingTime = new QCheckBox(tr("Moving time"));
|
||||
_movingTime->setChecked(_options->printMovingTime);
|
||||
_movingTime->setChecked(_options.printMovingTime);
|
||||
_itemCount = new QCheckBox(tr("Item count (>1)"));
|
||||
_itemCount->setChecked(_options->printItemCount);
|
||||
_itemCount->setChecked(_options.printItemCount);
|
||||
|
||||
QFormLayout *headerTabLayout = new QFormLayout();
|
||||
headerTabLayout->addWidget(_name);
|
||||
@ -563,7 +622,7 @@ QWidget *OptionsDialog::createExportPage()
|
||||
|
||||
|
||||
_separateGraphPage = new QCheckBox(tr("Separate graph page"));
|
||||
_separateGraphPage->setChecked(_options->separateGraphPage);
|
||||
_separateGraphPage->setChecked(_options.separateGraphPage);
|
||||
|
||||
QFormLayout *graphTabLayout = new QFormLayout();
|
||||
graphTabLayout->addWidget(_separateGraphPage);
|
||||
@ -582,23 +641,23 @@ QWidget *OptionsDialog::createExportPage()
|
||||
QWidget *OptionsDialog::createSystemPage()
|
||||
{
|
||||
_useOpenGL = new QCheckBox(tr("Use OpenGL"));
|
||||
_useOpenGL->setChecked(_options->useOpenGL);
|
||||
_useOpenGL->setChecked(_options.useOpenGL);
|
||||
#ifdef ENABLE_HTTP2
|
||||
_enableHTTP2 = new QCheckBox(tr("Enable HTTP/2"));
|
||||
_enableHTTP2->setChecked(_options->enableHTTP2);
|
||||
_enableHTTP2->setChecked(_options.enableHTTP2);
|
||||
#endif // ENABLE_HTTP2
|
||||
|
||||
_pixmapCache = new QSpinBox();
|
||||
_pixmapCache->setMinimum(16);
|
||||
_pixmapCache->setMaximum(1024);
|
||||
_pixmapCache->setSuffix(UNIT_SPACE + tr("MB"));
|
||||
_pixmapCache->setValue(_options->pixmapCache);
|
||||
_pixmapCache->setValue(_options.pixmapCache);
|
||||
|
||||
_connectionTimeout = new QSpinBox();
|
||||
_connectionTimeout->setMinimum(30);
|
||||
_connectionTimeout->setMaximum(120);
|
||||
_connectionTimeout->setSuffix(UNIT_SPACE + tr("s"));
|
||||
_connectionTimeout->setValue(_options->connectionTimeout);
|
||||
_connectionTimeout->setValue(_options.connectionTimeout);
|
||||
|
||||
QFormLayout *formLayout = new QFormLayout();
|
||||
formLayout->addRow(tr("Image cache size:"), _pixmapCache);
|
||||
@ -623,8 +682,8 @@ QWidget *OptionsDialog::createSystemPage()
|
||||
return systemPage;
|
||||
}
|
||||
|
||||
OptionsDialog::OptionsDialog(Options *options, QWidget *parent)
|
||||
: QDialog(parent), _options(options)
|
||||
OptionsDialog::OptionsDialog(Options &options, Units units, QWidget *parent)
|
||||
: QDialog(parent), _options(options), _units(units)
|
||||
{
|
||||
QStackedWidget *pages = new QStackedWidget();
|
||||
pages->addWidget(createAppearancePage());
|
||||
@ -676,74 +735,82 @@ OptionsDialog::OptionsDialog(Options *options, QWidget *parent)
|
||||
|
||||
void OptionsDialog::accept()
|
||||
{
|
||||
_options->palette.setColor(_baseColor->color());
|
||||
_options->palette.setShift(_colorOffset->value());
|
||||
_options->mapOpacity = _mapOpacity->value();
|
||||
_options->backgroundColor = _backgroundColor->color();
|
||||
_options->trackWidth = _trackWidth->value();
|
||||
_options->trackStyle = (Qt::PenStyle) _trackStyle->itemData(
|
||||
_options.palette.setColor(_baseColor->color());
|
||||
_options.palette.setShift(_colorOffset->value() / 100.0);
|
||||
_options.mapOpacity = _mapOpacity->value();
|
||||
_options.backgroundColor = _backgroundColor->color();
|
||||
_options.trackWidth = _trackWidth->value();
|
||||
_options.trackStyle = (Qt::PenStyle) _trackStyle->itemData(
|
||||
_trackStyle->currentIndex()).toInt();
|
||||
_options->routeWidth = _routeWidth->value();
|
||||
_options->routeStyle = (Qt::PenStyle) _routeStyle->itemData(
|
||||
_options.routeWidth = _routeWidth->value();
|
||||
_options.routeStyle = (Qt::PenStyle) _routeStyle->itemData(
|
||||
_routeStyle->currentIndex()).toInt();
|
||||
_options->pathAntiAliasing = _pathAA->isChecked();
|
||||
_options->areaWidth = _areaWidth->value();
|
||||
_options->areaStyle = (Qt::PenStyle) _areaStyle->itemData(
|
||||
_options.pathAntiAliasing = _pathAA->isChecked();
|
||||
_options.areaWidth = _areaWidth->value();
|
||||
_options.areaStyle = (Qt::PenStyle) _areaStyle->itemData(
|
||||
_areaStyle->currentIndex()).toInt();
|
||||
_options->areaOpacity = _areaOpacity->value();
|
||||
_options->waypointSize = _waypointSize->value();
|
||||
_options->waypointColor = _waypointColor->color();
|
||||
_options->poiSize = _poiSize->value();
|
||||
_options->poiColor = _poiColor->color();
|
||||
_options->graphWidth = _graphWidth->value();
|
||||
_options->sliderColor = _sliderColor->color();
|
||||
_options->graphAntiAliasing = _graphAA->isChecked();
|
||||
_options.areaOpacity = _areaOpacity->value();
|
||||
_options.waypointSize = _waypointSize->value();
|
||||
_options.waypointColor = _waypointColor->color();
|
||||
_options.poiSize = _poiSize->value();
|
||||
_options.poiColor = _poiColor->color();
|
||||
_options.graphWidth = _graphWidth->value();
|
||||
_options.sliderColor = _sliderColor->color();
|
||||
_options.graphAntiAliasing = _graphAA->isChecked();
|
||||
|
||||
_options->projection = _projection->itemData(_projection->currentIndex())
|
||||
_options.projection = _projection->itemData(_projection->currentIndex())
|
||||
.toInt();
|
||||
#ifdef ENABLE_HIDPI
|
||||
_options->hidpiMap = _hidpi->isChecked();
|
||||
_options.hidpiMap = _hidpi->isChecked();
|
||||
#endif // ENABLE_HIDPI
|
||||
|
||||
_options->elevationFilter = _elevationFilter->value();
|
||||
_options->speedFilter = _speedFilter->value();
|
||||
_options->heartRateFilter = _heartRateFilter->value();
|
||||
_options->cadenceFilter = _cadenceFilter->value();
|
||||
_options->powerFilter = _powerFilter->value();
|
||||
_options->outlierEliminate = _outlierEliminate->isChecked();
|
||||
_options->automaticPause = _automaticPause->isChecked();
|
||||
qreal pauseSpeed = (_options->units == Imperial)
|
||||
? _pauseSpeed->value() / MS2MIH : (_options->units == Nautical)
|
||||
_options.elevationFilter = _elevationFilter->value();
|
||||
_options.speedFilter = _speedFilter->value();
|
||||
_options.heartRateFilter = _heartRateFilter->value();
|
||||
_options.cadenceFilter = _cadenceFilter->value();
|
||||
_options.powerFilter = _powerFilter->value();
|
||||
_options.outlierEliminate = _outlierEliminate->isChecked();
|
||||
_options.automaticPause = _automaticPause->isChecked();
|
||||
qreal pauseSpeed = (_units == Imperial)
|
||||
? _pauseSpeed->value() / MS2MIH : (_units == Nautical)
|
||||
? _pauseSpeed->value() / MS2KN : _pauseSpeed->value() / MS2KMH;
|
||||
if (qAbs(pauseSpeed - _options->pauseSpeed) > 0.01)
|
||||
_options->pauseSpeed = pauseSpeed;
|
||||
_options->pauseInterval = _pauseInterval->value();
|
||||
_options->useReportedSpeed = _reportedSpeed->isChecked();
|
||||
_options->dataUseDEM = _dataDEMElevation->isChecked();
|
||||
_options->showSecondaryElevation = _showSecondaryElevation->isChecked();
|
||||
_options->showSecondarySpeed = _showSecondarySpeed->isChecked();
|
||||
if (qAbs(pauseSpeed - _options.pauseSpeed) > 0.01)
|
||||
_options.pauseSpeed = pauseSpeed;
|
||||
_options.pauseInterval = _pauseInterval->value();
|
||||
_options.useReportedSpeed = _reportedSpeed->isChecked();
|
||||
_options.dataUseDEM = _dataDEMElevation->isChecked();
|
||||
_options.showSecondaryElevation = _showSecondaryElevation->isChecked();
|
||||
_options.showSecondarySpeed = _showSecondarySpeed->isChecked();
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
_options.timeZone.setType(_utcZone->isChecked()
|
||||
? TimeZoneInfo::UTC : _systemZone->isChecked()
|
||||
? TimeZoneInfo::System : TimeZoneInfo::Custom);
|
||||
_options.timeZone.setCustomZone(QTimeZone(_timeZone->currentText()
|
||||
.toLatin1()));
|
||||
#endif // ENABLE_TIMEZONES
|
||||
_options.useSegments = _useSegments->isChecked();
|
||||
|
||||
qreal poiRadius = (_options->units == Imperial)
|
||||
? _poiRadius->value() * MIINM : (_options->units == Nautical)
|
||||
qreal poiRadius = (_units == Imperial)
|
||||
? _poiRadius->value() * MIINM : (_units == Nautical)
|
||||
? _poiRadius->value() * NMIINM : _poiRadius->value() * KMINM;
|
||||
if (qAbs(poiRadius - _options->poiRadius) > 0.01)
|
||||
_options->poiRadius = poiRadius;
|
||||
if (qAbs(poiRadius - _options.poiRadius) > 0.01)
|
||||
_options.poiRadius = poiRadius;
|
||||
|
||||
_options->useOpenGL = _useOpenGL->isChecked();
|
||||
_options.useOpenGL = _useOpenGL->isChecked();
|
||||
#ifdef ENABLE_HTTP2
|
||||
_options->enableHTTP2 = _enableHTTP2->isChecked();
|
||||
_options.enableHTTP2 = _enableHTTP2->isChecked();
|
||||
#endif // ENABLE_HTTP2
|
||||
_options->pixmapCache = _pixmapCache->value();
|
||||
_options->connectionTimeout = _connectionTimeout->value();
|
||||
_options.pixmapCache = _pixmapCache->value();
|
||||
_options.connectionTimeout = _connectionTimeout->value();
|
||||
|
||||
_options->hiresPrint = _hires->isChecked();
|
||||
_options->printName = _name->isChecked();
|
||||
_options->printDate = _date->isChecked();
|
||||
_options->printDistance = _distance->isChecked();
|
||||
_options->printTime = _time->isChecked();
|
||||
_options->printMovingTime = _movingTime->isChecked();
|
||||
_options->printItemCount = _itemCount->isChecked();
|
||||
_options->separateGraphPage = _separateGraphPage->isChecked();
|
||||
_options.hiresPrint = _hires->isChecked();
|
||||
_options.printName = _name->isChecked();
|
||||
_options.printDate = _date->isChecked();
|
||||
_options.printDistance = _distance->isChecked();
|
||||
_options.printTime = _time->isChecked();
|
||||
_options.printMovingTime = _movingTime->isChecked();
|
||||
_options.printItemCount = _itemCount->isChecked();
|
||||
_options.separateGraphPage = _separateGraphPage->isChecked();
|
||||
|
||||
QDialog::accept();
|
||||
}
|
||||
|
@ -5,6 +5,9 @@
|
||||
#include "common/config.h"
|
||||
#include "palette.h"
|
||||
#include "units.h"
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
#include "timezoneinfo.h"
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
class ColorBox;
|
||||
class StyleComboBox;
|
||||
@ -17,6 +20,7 @@ class QRadioButton;
|
||||
class PercentSlider;
|
||||
class LimitedComboBox;
|
||||
|
||||
|
||||
struct Options {
|
||||
// Appearance
|
||||
Palette palette;
|
||||
@ -56,6 +60,10 @@ struct Options {
|
||||
bool dataUseDEM;
|
||||
bool showSecondaryElevation;
|
||||
bool showSecondarySpeed;
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
TimeZoneInfo timeZone;
|
||||
#endif // ENABLE_TIMEZONES
|
||||
bool useSegments;
|
||||
// POI
|
||||
int poiRadius;
|
||||
// System
|
||||
@ -74,8 +82,6 @@ struct Options {
|
||||
bool printMovingTime;
|
||||
bool printItemCount;
|
||||
bool separateGraphPage;
|
||||
|
||||
Units units;
|
||||
};
|
||||
|
||||
class OptionsDialog : public QDialog
|
||||
@ -86,7 +92,7 @@ public slots:
|
||||
void accept();
|
||||
|
||||
public:
|
||||
OptionsDialog(Options *options, QWidget *parent = 0);
|
||||
OptionsDialog(Options &options, Units units, QWidget *parent = 0);
|
||||
|
||||
private slots:
|
||||
void automaticPauseDetectionSet(bool set);
|
||||
@ -99,11 +105,12 @@ private:
|
||||
QWidget *createSystemPage();
|
||||
QWidget *createExportPage();
|
||||
|
||||
Options *_options;
|
||||
Options &_options;
|
||||
|
||||
Units _units;
|
||||
// Appearance
|
||||
ColorBox *_baseColor;
|
||||
QDoubleSpinBox *_colorOffset;
|
||||
PercentSlider *_colorOffset;
|
||||
PercentSlider *_mapOpacity;
|
||||
ColorBox *_backgroundColor;
|
||||
QSpinBox *_trackWidth;
|
||||
@ -134,7 +141,6 @@ private:
|
||||
OddSpinBox *_cadenceFilter;
|
||||
OddSpinBox *_powerFilter;
|
||||
QCheckBox *_outlierEliminate;
|
||||
|
||||
QRadioButton *_automaticPause;
|
||||
QRadioButton *_manualPause;
|
||||
QDoubleSpinBox *_pauseSpeed;
|
||||
@ -145,6 +151,13 @@ private:
|
||||
QRadioButton *_dataDEMElevation;
|
||||
QCheckBox *_showSecondaryElevation;
|
||||
QCheckBox *_showSecondarySpeed;
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
QRadioButton *_utcZone;
|
||||
QRadioButton *_systemZone;
|
||||
QRadioButton *_customZone;
|
||||
QComboBox *_timeZone;
|
||||
#endif // ENABLE_TIMEZONES
|
||||
QCheckBox *_useSegments;
|
||||
// POI
|
||||
QDoubleSpinBox *_poiRadius;
|
||||
// System
|
||||
|
@ -21,12 +21,16 @@ static inline unsigned segments(qreal distance)
|
||||
return ceil(distance / GEOGRAPHICAL_MILE);
|
||||
}
|
||||
|
||||
Units PathItem::_units = Metric;
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
QTimeZone PathItem::_timeZone = QTimeZone::utc();
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
PathItem::PathItem(const Path &path, Map *map, QGraphicsItem *parent)
|
||||
: GraphicsItem(parent), _path(path), _map(map)
|
||||
{
|
||||
Q_ASSERT(_path.isValid());
|
||||
|
||||
_units = Metric;
|
||||
_digitalZoom = 0;
|
||||
_width = 3;
|
||||
QBrush brush(Qt::SolidPattern);
|
||||
@ -352,16 +356,6 @@ void PathItem::showTicks(bool show)
|
||||
updateTicks();
|
||||
}
|
||||
|
||||
void PathItem::setUnits(Units units)
|
||||
{
|
||||
if (_units == units)
|
||||
return;
|
||||
|
||||
prepareGeometryChange();
|
||||
_units = units;
|
||||
updateTicks();
|
||||
}
|
||||
|
||||
void PathItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
@ -1,8 +1,12 @@
|
||||
#ifndef PATHITEM_H
|
||||
#define PATHITEM_H
|
||||
|
||||
#include "common/config.h"
|
||||
#include <QGraphicsObject>
|
||||
#include <QPen>
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
#include <QTimeZone>
|
||||
#endif // ENABLE_TIMEZONES
|
||||
#include "data/path.h"
|
||||
#include "markeritem.h"
|
||||
#include "units.h"
|
||||
@ -28,7 +32,6 @@ public:
|
||||
|
||||
void setMap(Map *map);
|
||||
|
||||
void setUnits(Units units);
|
||||
void setColor(const QColor &color);
|
||||
void setWidth(qreal width);
|
||||
void setStyle(Qt::PenStyle style);
|
||||
@ -37,6 +40,13 @@ public:
|
||||
void showMarker(bool show);
|
||||
void showTicks(bool show);
|
||||
|
||||
void updateTicks();
|
||||
|
||||
static void setUnits(Units units) {_units = units;}
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
static void setTimeZone(const QTimeZone &zone) {_timeZone = zone;}
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
public slots:
|
||||
void moveMarker(qreal distance);
|
||||
void hover(bool hover);
|
||||
@ -49,7 +59,10 @@ protected:
|
||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent *event);
|
||||
|
||||
Units _units;
|
||||
static Units _units;
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
static QTimeZone _timeZone;
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
private:
|
||||
const PathSegment *segment(qreal x) const;
|
||||
@ -60,7 +73,6 @@ private:
|
||||
|
||||
qreal xInM() const;
|
||||
unsigned tickSize() const;
|
||||
void updateTicks();
|
||||
|
||||
Path _path;
|
||||
Map *_map;
|
||||
|
@ -1,30 +1,27 @@
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QFormLayout>
|
||||
#include <QGridLayout>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QGroupBox>
|
||||
#include <QComboBox>
|
||||
#include <QRadioButton>
|
||||
#include <QPushButton>
|
||||
#include <QFileInfo>
|
||||
#include <QMessageBox>
|
||||
#include <QTabWidget>
|
||||
#include <QDoubleSpinBox>
|
||||
#include "marginswidget.h"
|
||||
#include "fileselectwidget.h"
|
||||
#include "units.h"
|
||||
#include "exportdialog.h"
|
||||
#include "pdfexportdialog.h"
|
||||
|
||||
|
||||
ExportDialog::ExportDialog(Export *exp, QWidget *parent)
|
||||
: QDialog(parent), _export(exp)
|
||||
PDFExportDialog::PDFExportDialog(PDFExport &exp, Units units, QWidget *parent)
|
||||
: QDialog(parent), _export(exp), _units(units)
|
||||
{
|
||||
int index;
|
||||
|
||||
_fileSelect = new FileSelectWidget();
|
||||
_fileSelect->setFilter(tr("PDF files") + " (*.pdf);;" + tr("All files")
|
||||
+ " (*)");
|
||||
_fileSelect->setFile(_export->fileName);
|
||||
_fileSelect->setFile(_export.fileName);
|
||||
|
||||
_paperSize = new QComboBox();
|
||||
_paperSize->addItem("A2", QPrinter::A2);
|
||||
@ -39,14 +36,14 @@ ExportDialog::ExportDialog(Export *exp, QWidget *parent)
|
||||
_paperSize->addItem("Tabloid", QPrinter::Tabloid);
|
||||
_paperSize->addItem("Legal", QPrinter::Legal);
|
||||
_paperSize->addItem("Letter", QPrinter::Letter);
|
||||
if ((index = _paperSize->findData(_export->paperSize)) >= 0)
|
||||
if ((index = _paperSize->findData(_export.paperSize)) >= 0)
|
||||
_paperSize->setCurrentIndex(index);
|
||||
|
||||
_resolution = new QComboBox();
|
||||
_resolution->addItem("150 DPI", 150);
|
||||
_resolution->addItem("300 DPI", 300);
|
||||
_resolution->addItem("600 DPI", 600);
|
||||
if ((index = _resolution->findData(_export->resolution)) >= 0)
|
||||
if ((index = _resolution->findData(_export.resolution)) >= 0)
|
||||
_resolution->setCurrentIndex(index);
|
||||
|
||||
_portrait = new QRadioButton(tr("Portrait"));
|
||||
@ -54,41 +51,16 @@ ExportDialog::ExportDialog(Export *exp, QWidget *parent)
|
||||
QHBoxLayout *orientationLayout = new QHBoxLayout();
|
||||
orientationLayout->addWidget(_portrait);
|
||||
orientationLayout->addWidget(_landscape);
|
||||
if (_export->orientation == QPrinter::Portrait)
|
||||
if (_export.orientation == QPrinter::Portrait)
|
||||
_portrait->setChecked(true);
|
||||
else
|
||||
_landscape->setChecked(true);
|
||||
|
||||
_topMargin = new QDoubleSpinBox();
|
||||
_bottomMargin = new QDoubleSpinBox();
|
||||
_leftMargin = new QDoubleSpinBox();
|
||||
_rightMargin = new QDoubleSpinBox();
|
||||
QString us = (_export->units == Metric) ? tr("mm") : tr("in");
|
||||
_topMargin->setSuffix(UNIT_SPACE + us);
|
||||
_bottomMargin->setSuffix(UNIT_SPACE + us);
|
||||
_leftMargin->setSuffix(UNIT_SPACE + us);
|
||||
_rightMargin->setSuffix(UNIT_SPACE + us);
|
||||
if (_export->units == Metric) {
|
||||
_topMargin->setValue(_export->margins.top());
|
||||
_bottomMargin->setValue(_export->margins.bottom());
|
||||
_leftMargin->setValue(_export->margins.left());
|
||||
_rightMargin->setValue(_export->margins.right());
|
||||
} else {
|
||||
_topMargin->setValue(_export->margins.top() * MM2IN);
|
||||
_bottomMargin->setValue(_export->margins.bottom() * MM2IN);
|
||||
_leftMargin->setValue(_export->margins.left() * MM2IN);
|
||||
_rightMargin->setValue(_export->margins.right() * MM2IN);
|
||||
_topMargin->setSingleStep(0.1);
|
||||
_bottomMargin->setSingleStep(0.1);
|
||||
_leftMargin->setSingleStep(0.1);
|
||||
_rightMargin->setSingleStep(0.1);
|
||||
}
|
||||
|
||||
QGridLayout *marginsLayout = new QGridLayout();
|
||||
marginsLayout->addWidget(_topMargin, 0, 0, 1, 2, Qt::AlignCenter);
|
||||
marginsLayout->addWidget(_leftMargin, 1, 0, 1, 1, Qt::AlignRight);
|
||||
marginsLayout->addWidget(_rightMargin, 1, 1, 1, 1, Qt::AlignLeft);
|
||||
marginsLayout->addWidget(_bottomMargin, 2, 0, 1, 2, Qt::AlignCenter);
|
||||
_margins = new MarginsFWidget();
|
||||
_margins->setUnits((units == Metric) ? tr("cm") : tr("in"));
|
||||
_margins->setSingleStep(0.1);
|
||||
_margins->setValue((units == Metric)
|
||||
? _export.margins * MM2CM : _export.margins * MM2IN);
|
||||
|
||||
#ifndef Q_OS_MAC
|
||||
QGroupBox *pageSetupBox = new QGroupBox(tr("Page Setup"));
|
||||
@ -97,7 +69,7 @@ ExportDialog::ExportDialog(Export *exp, QWidget *parent)
|
||||
pageSetupLayout->addRow(tr("Page size:"), _paperSize);
|
||||
pageSetupLayout->addRow(tr("Resolution:"), _resolution);
|
||||
pageSetupLayout->addRow(tr("Orientation:"), orientationLayout);
|
||||
pageSetupLayout->addRow(tr("Margins:"), marginsLayout);
|
||||
pageSetupLayout->addRow(tr("Margins:"), _margins);
|
||||
#ifdef Q_OS_MAC
|
||||
QFrame *line = new QFrame();
|
||||
line->setFrameShape(QFrame::HLine);
|
||||
@ -111,7 +83,7 @@ ExportDialog::ExportDialog(Export *exp, QWidget *parent)
|
||||
|
||||
#ifndef Q_OS_MAC
|
||||
QGroupBox *outputFileBox = new QGroupBox(tr("Output file"));
|
||||
QHBoxLayout *outputFileLayout = new QHBoxLayout();
|
||||
QVBoxLayout *outputFileLayout = new QVBoxLayout();
|
||||
outputFileLayout->addWidget(_fileSelect);
|
||||
outputFileBox->setLayout(outputFileLayout);
|
||||
#endif // Q_OS_MAC
|
||||
@ -136,41 +108,13 @@ ExportDialog::ExportDialog(Export *exp, QWidget *parent)
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
}
|
||||
|
||||
bool ExportDialog::checkFile()
|
||||
void PDFExportDialog::accept()
|
||||
{
|
||||
if (_fileSelect->file().isEmpty()) {
|
||||
QMessageBox::warning(this, tr("Error"), tr("No output file selected."));
|
||||
return false;
|
||||
}
|
||||
|
||||
QFile file(_fileSelect->file());
|
||||
QFileInfo fi(file);
|
||||
bool exists = fi.exists();
|
||||
bool opened = false;
|
||||
|
||||
if (exists && fi.isDir()) {
|
||||
QMessageBox::warning(this, tr("Error"), tr("%1 is a directory.")
|
||||
.arg(file.fileName()));
|
||||
return false;
|
||||
} else if ((exists && !fi.isWritable())
|
||||
|| !(opened = file.open(QFile::Append))) {
|
||||
QMessageBox::warning(this, tr("Error"), tr("%1 is not writable.")
|
||||
.arg(file.fileName()));
|
||||
return false;
|
||||
}
|
||||
if (opened) {
|
||||
file.close();
|
||||
if (!exists)
|
||||
file.remove();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ExportDialog::accept()
|
||||
{
|
||||
if (!checkFile())
|
||||
QString error;
|
||||
if (!_fileSelect->checkFile(error)) {
|
||||
QMessageBox::warning(this, tr("Error"), error);
|
||||
return;
|
||||
}
|
||||
|
||||
QPrinter::Orientation orientation = _portrait->isChecked()
|
||||
? QPrinter::Portrait : QPrinter::Landscape;
|
||||
@ -178,17 +122,12 @@ void ExportDialog::accept()
|
||||
(_paperSize->itemData(_paperSize->currentIndex()).toInt());
|
||||
int resolution = _resolution->itemData(_resolution->currentIndex()).toInt();
|
||||
|
||||
_export->fileName = _fileSelect->file();
|
||||
_export->paperSize = paperSize;
|
||||
_export->resolution = resolution;
|
||||
_export->orientation = orientation;
|
||||
if (_export->units == Imperial)
|
||||
_export->margins = MarginsF(_leftMargin->value() / MM2IN,
|
||||
_topMargin->value() / MM2IN, _rightMargin->value() / MM2IN,
|
||||
_bottomMargin->value() / MM2IN);
|
||||
else
|
||||
_export->margins = MarginsF(_leftMargin->value(), _topMargin->value(),
|
||||
_rightMargin->value(), _bottomMargin->value());
|
||||
_export.fileName = _fileSelect->file();
|
||||
_export.paperSize = paperSize;
|
||||
_export.resolution = resolution;
|
||||
_export.orientation = orientation;
|
||||
_export.margins = (_units == Imperial)
|
||||
? _margins->value() / MM2IN : _margins->value() / MM2CM;
|
||||
|
||||
QDialog::accept();
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
#ifndef EXPORTDIALOG_H
|
||||
#define EXPORTDIALOG_H
|
||||
#ifndef PDFEXPORTDIALOG_H
|
||||
#define PDFEXPORTDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QPrinter>
|
||||
@ -9,42 +9,37 @@
|
||||
class QComboBox;
|
||||
class QRadioButton;
|
||||
class FileSelectWidget;
|
||||
class QDoubleSpinBox;
|
||||
class MarginsFWidget;
|
||||
|
||||
struct Export {
|
||||
struct PDFExport
|
||||
{
|
||||
QString fileName;
|
||||
QPrinter::PaperSize paperSize;
|
||||
QPrinter::Orientation orientation;
|
||||
MarginsF margins;
|
||||
int resolution;
|
||||
|
||||
Units units;
|
||||
};
|
||||
|
||||
class ExportDialog : public QDialog
|
||||
class PDFExportDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ExportDialog(Export *exp, QWidget *parent = 0);
|
||||
PDFExportDialog(PDFExport &exp, Units units, QWidget *parent = 0);
|
||||
|
||||
public slots:
|
||||
void accept();
|
||||
|
||||
private:
|
||||
bool checkFile();
|
||||
|
||||
Export *_export;
|
||||
PDFExport &_export;
|
||||
|
||||
Units _units;
|
||||
FileSelectWidget *_fileSelect;
|
||||
QComboBox *_paperSize;
|
||||
QComboBox *_resolution;
|
||||
QRadioButton *_portrait;
|
||||
QRadioButton *_landscape;
|
||||
QDoubleSpinBox *_topMargin;
|
||||
QDoubleSpinBox *_bottomMargin;
|
||||
QDoubleSpinBox *_leftMargin;
|
||||
QDoubleSpinBox *_rightMargin;
|
||||
MarginsFWidget *_margins;
|
||||
};
|
||||
|
||||
#endif // EXPORTDIALOG_H
|
||||
#endif // PDFEXPORTDIALOG_H
|
101
src/GUI/pngexportdialog.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
#include <QVBoxLayout>
|
||||
#include <QFormLayout>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QGroupBox>
|
||||
#include <QSpinBox>
|
||||
#include <QMessageBox>
|
||||
#include <QTabWidget>
|
||||
#include <QCheckBox>
|
||||
#include "units.h"
|
||||
#include "fileselectwidget.h"
|
||||
#include "marginswidget.h"
|
||||
#include "pngexportdialog.h"
|
||||
|
||||
|
||||
PNGExportDialog::PNGExportDialog(PNGExport &exp, QWidget *parent)
|
||||
: QDialog(parent), _export(exp)
|
||||
{
|
||||
_fileSelect = new FileSelectWidget();
|
||||
_fileSelect->setFilter(tr("PNG files") + " (*.png);;" + tr("All files")
|
||||
+ " (*)");
|
||||
_fileSelect->setFile(_export.fileName);
|
||||
|
||||
_width = new QSpinBox();
|
||||
_width->setMinimum(256);
|
||||
_width->setMaximum(4096);
|
||||
_width->setValue(_export.size.width());
|
||||
_width->setSuffix(UNIT_SPACE + tr("px"));
|
||||
_height = new QSpinBox();
|
||||
_height->setMinimum(256);
|
||||
_height->setMaximum(4096);
|
||||
_height->setValue(_export.size.height());
|
||||
_height->setSuffix(UNIT_SPACE + tr("px"));
|
||||
|
||||
_margins = new MarginsWidget();
|
||||
_margins->setValue(_export.margins);
|
||||
_margins->setUnits(tr("px"));
|
||||
|
||||
_antialiasing = new QCheckBox(tr("Use anti-aliasing"));
|
||||
_antialiasing->setChecked(_export.antialiasing);
|
||||
|
||||
#ifndef Q_OS_MAC
|
||||
QGroupBox *pageSetupBox = new QGroupBox(tr("Image Setup"));
|
||||
#endif // Q_OS_MAC
|
||||
QFormLayout *pageSetupLayout = new QFormLayout;
|
||||
pageSetupLayout->addRow(tr("Image width:"), _width);
|
||||
pageSetupLayout->addRow(tr("Image height:"), _height);
|
||||
pageSetupLayout->addRow(tr("Margins:"), _margins);
|
||||
pageSetupLayout->addWidget(_antialiasing);
|
||||
#ifdef Q_OS_MAC
|
||||
QFrame *line = new QFrame();
|
||||
line->setFrameShape(QFrame::HLine);
|
||||
line->setFrameShadow(QFrame::Sunken);
|
||||
pageSetupLayout->addRow(line);
|
||||
pageSetupLayout->addRow(tr("File:"), _fileSelect);
|
||||
pageSetupLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
|
||||
#else // Q_OS_MAC
|
||||
pageSetupBox->setLayout(pageSetupLayout);
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
#ifndef Q_OS_MAC
|
||||
QGroupBox *outputFileBox = new QGroupBox(tr("Output file"));
|
||||
QVBoxLayout *outputFileLayout = new QVBoxLayout();
|
||||
outputFileLayout->addWidget(_fileSelect);
|
||||
outputFileBox->setLayout(outputFileLayout);
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
QDialogButtonBox *buttonBox = new QDialogButtonBox();
|
||||
buttonBox->addButton(tr("Export"), QDialogButtonBox::AcceptRole);
|
||||
buttonBox->addButton(QDialogButtonBox::Cancel);
|
||||
connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
|
||||
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout;
|
||||
#ifdef Q_OS_MAC
|
||||
layout->addLayout(pageSetupLayout);
|
||||
#else // Q_OS_MAC
|
||||
layout->addWidget(pageSetupBox);
|
||||
layout->addWidget(outputFileBox);
|
||||
#endif // Q_OS_MAC
|
||||
layout->addWidget(buttonBox);
|
||||
setLayout(layout);
|
||||
|
||||
setWindowTitle(tr("Export to PNG"));
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
}
|
||||
|
||||
void PNGExportDialog::accept()
|
||||
{
|
||||
QString error;
|
||||
if (!_fileSelect->checkFile(error)) {
|
||||
QMessageBox::warning(this, tr("Error"), error);
|
||||
return;
|
||||
}
|
||||
|
||||
_export.fileName = _fileSelect->file();
|
||||
_export.size = QSize(_width->value(), _height->value());
|
||||
_export.margins = _margins->value();
|
||||
_export.antialiasing = _antialiasing->isChecked();
|
||||
|
||||
QDialog::accept();
|
||||
}
|
41
src/GUI/pngexportdialog.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef PNGEXPORTDIALOG_H
|
||||
#define PNGEXPORTDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QMargins>
|
||||
#include "margins.h"
|
||||
|
||||
class FileSelectWidget;
|
||||
class MarginsWidget;
|
||||
class QSpinBox;
|
||||
class QCheckBox;
|
||||
|
||||
struct PNGExport
|
||||
{
|
||||
QString fileName;
|
||||
QSize size;
|
||||
QMargins margins;
|
||||
bool antialiasing;
|
||||
};
|
||||
|
||||
class PNGExportDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PNGExportDialog(PNGExport &exp, QWidget *parent = 0);
|
||||
|
||||
public slots:
|
||||
void accept();
|
||||
|
||||
private:
|
||||
PNGExport &_export;
|
||||
|
||||
FileSelectWidget *_fileSelect;
|
||||
QSpinBox *_width;
|
||||
QSpinBox *_height;
|
||||
MarginsWidget *_margins;
|
||||
QCheckBox *_antialiasing;
|
||||
};
|
||||
|
||||
#endif // PNGEXPORTDIALOG_H
|
@ -47,7 +47,6 @@ RouteItem::RouteItem(const Route &route, Map *map, QGraphicsItem *parent)
|
||||
_desc = route.description();
|
||||
_comment = route.comment();
|
||||
_links = route.links();
|
||||
_coordinatesFormat = DecimalDegrees;
|
||||
}
|
||||
|
||||
void RouteItem::setMap(Map *map)
|
||||
@ -58,28 +57,6 @@ void RouteItem::setMap(Map *map)
|
||||
PathItem::setMap(map);
|
||||
}
|
||||
|
||||
void RouteItem::setUnits(Units u)
|
||||
{
|
||||
if (_units == u)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < _waypoints.count(); i++)
|
||||
_waypoints[i]->setToolTipFormat(u, _coordinatesFormat);
|
||||
|
||||
PathItem::setUnits(u);
|
||||
}
|
||||
|
||||
void RouteItem::setCoordinatesFormat(CoordinatesFormat format)
|
||||
{
|
||||
if (_coordinatesFormat == format)
|
||||
return;
|
||||
|
||||
_coordinatesFormat = format;
|
||||
|
||||
for (int i = 0; i < _waypoints.count(); i++)
|
||||
_waypoints[i]->setToolTipFormat(_units, _coordinatesFormat);
|
||||
}
|
||||
|
||||
void RouteItem::showWaypoints(bool show)
|
||||
{
|
||||
for (int i = 0; i < _waypoints.count(); i++)
|
||||
|
@ -19,8 +19,6 @@ public:
|
||||
|
||||
void setMap(Map *map);
|
||||
|
||||
void setUnits(Units u);
|
||||
void setCoordinatesFormat(CoordinatesFormat format);
|
||||
void showWaypoints(bool show);
|
||||
void showWaypointLabels(bool show);
|
||||
|
||||
@ -31,7 +29,6 @@ private:
|
||||
QString _desc;
|
||||
QString _comment;
|
||||
QVector<Link> _links;
|
||||
CoordinatesFormat _coordinatesFormat;
|
||||
|
||||
QVector<WaypointItem*> _waypoints;
|
||||
};
|
||||
|
@ -66,26 +66,45 @@
|
||||
#define SHOW_WAYPOINT_LABELS_SETTING "waypointLabels"
|
||||
#define SHOW_WAYPOINT_LABELS_DEFAULT true
|
||||
|
||||
#define EXPORT_SETTINGS_GROUP "Export"
|
||||
#define PDF_EXPORT_SETTINGS_GROUP "Export"
|
||||
#define PAPER_ORIENTATION_SETTING "orientation"
|
||||
#define PAPER_ORIENTATION_DEFAULT QPrinter::Portrait
|
||||
#define PAPER_SIZE_SETTING "size"
|
||||
#define PAPER_SIZE_DEFAULT (IMPERIAL_UNITS() ? QPrinter::Letter \
|
||||
: QPrinter::A4)
|
||||
#define MARGIN_LEFT_SETTING "marginLeft"
|
||||
#define MARGIN_LEFT_DEFAULT 5 /* mm */
|
||||
#define MARGIN_TOP_SETTING "marginTop"
|
||||
#define MARGIN_TOP_DEFAULT 5 /* mm */
|
||||
#define MARGIN_RIGHT_SETTING "marginRight"
|
||||
#define MARGIN_RIGHT_DEFAULT 5 /* mm */
|
||||
#define MARGIN_BOTTOM_SETTING "marginBottom"
|
||||
#define MARGIN_BOTTOM_DEFAULT 5 /* mm */
|
||||
#define EXPORT_FILENAME_SETTING "fileName"
|
||||
#define EXPORT_FILENAME_DEFAULT QString("%1/export.pdf"). \
|
||||
#define PDF_MARGIN_LEFT_SETTING "marginLeft"
|
||||
#define PDF_MARGIN_LEFT_DEFAULT 5 /* mm */
|
||||
#define PDF_MARGIN_TOP_SETTING "marginTop"
|
||||
#define PDF_MARGIN_TOP_DEFAULT 5 /* mm */
|
||||
#define PDF_MARGIN_RIGHT_SETTING "marginRight"
|
||||
#define PDF_MARGIN_RIGHT_DEFAULT 5 /* mm */
|
||||
#define PDF_MARGIN_BOTTOM_SETTING "marginBottom"
|
||||
#define PDF_MARGIN_BOTTOM_DEFAULT 5 /* mm */
|
||||
#define PDF_FILENAME_SETTING "fileName"
|
||||
#define PDF_FILENAME_DEFAULT QString("%1/export.pdf"). \
|
||||
arg(QDir::currentPath())
|
||||
#define RESOLUTION_SETTING "resolution"
|
||||
#define RESOLUTION_DEFAULT 600
|
||||
|
||||
#define PNG_EXPORT_SETTINGS_GROUP "PNGExport"
|
||||
#define PNG_WIDTH_SETTING "width"
|
||||
#define PNG_WIDTH_DEFAULT 600
|
||||
#define PNG_HEIGHT_SETTING "height"
|
||||
#define PNG_HEIGHT_DEFAULT 800
|
||||
#define PNG_MARGIN_LEFT_SETTING "marginLeft"
|
||||
#define PNG_MARGIN_LEFT_DEFAULT 5 /* px */
|
||||
#define PNG_MARGIN_TOP_SETTING "marginTop"
|
||||
#define PNG_MARGIN_TOP_DEFAULT 5 /* px */
|
||||
#define PNG_MARGIN_RIGHT_SETTING "marginRight"
|
||||
#define PNG_MARGIN_RIGHT_DEFAULT 5 /* px */
|
||||
#define PNG_MARGIN_BOTTOM_SETTING "marginBottom"
|
||||
#define PNG_MARGIN_BOTTOM_DEFAULT 5 /* px */
|
||||
#define PNG_ANTIALIASING_SETTING "antialiasing"
|
||||
#define PNG_ANTIALIASING_DEFAULT true
|
||||
#define PNG_FILENAME_SETTING "fileName"
|
||||
#define PNG_FILENAME_DEFAULT QString("%1/export.png"). \
|
||||
arg(QDir::currentPath())
|
||||
|
||||
#define OPTIONS_SETTINGS_GROUP "Options"
|
||||
#define PALETTE_COLOR_SETTING "paletteColor"
|
||||
#define PALETTE_COLOR_DEFAULT QColor(Qt::blue)
|
||||
@ -122,7 +141,7 @@
|
||||
#define PATH_AA_SETTING "pathAntiAliasing"
|
||||
#define PATH_AA_DEFAULT true
|
||||
#define GRAPH_AA_SETTING "graphAntiAliasing"
|
||||
#define GRAPH_AA_DEFAULT false
|
||||
#define GRAPH_AA_DEFAULT true
|
||||
#define ELEVATION_FILTER_SETTING "elevationFilter"
|
||||
#define ELEVATION_FILTER_DEFAULT 3
|
||||
#define SPEED_FILTER_SETTING "speedFilter"
|
||||
@ -149,6 +168,9 @@
|
||||
#define SHOW_SECONDARY_ELEVATION_DEFAULT false
|
||||
#define SHOW_SECONDARY_SPEED_SETTING "showSecondarySpeed"
|
||||
#define SHOW_SECONDARY_SPEED_DEFAULT false
|
||||
#define TIME_ZONE_SETTING "timeZone"
|
||||
#define USE_SEGMENTS_SETTING "useSegments"
|
||||
#define USE_SEGMENTS_DEFAULT true
|
||||
#define POI_RADIUS_SETTING "poiRadius"
|
||||
#define POI_RADIUS_DEFAULT (int)(IMPERIAL_UNITS() ? MIINM : KMINM)
|
||||
#define USE_OPENGL_SETTING "useOpenGL"
|
||||
|
69
src/GUI/timezoneinfo.h
Normal file
@ -0,0 +1,69 @@
|
||||
#ifndef TIMEZONEINFO_H
|
||||
#define TIMEZONEINFO_H
|
||||
|
||||
#include <QTimeZone>
|
||||
#include <QDataStream>
|
||||
|
||||
class TimeZoneInfo
|
||||
{
|
||||
public:
|
||||
enum Type {
|
||||
UTC,
|
||||
System,
|
||||
Custom
|
||||
};
|
||||
|
||||
TimeZoneInfo() : _type(UTC), _customZone(QTimeZone::systemTimeZone()) {}
|
||||
|
||||
Type type() const {return _type;}
|
||||
const QTimeZone &customZone() const {return _customZone;}
|
||||
QTimeZone zone() const
|
||||
{
|
||||
if (_type == UTC)
|
||||
return QTimeZone::utc();
|
||||
else if (_type == System)
|
||||
return QTimeZone::systemTimeZone();
|
||||
else
|
||||
return _customZone;
|
||||
}
|
||||
|
||||
void setType(Type type) {_type = type;}
|
||||
void setCustomZone(const QTimeZone &zone) {_customZone = zone;}
|
||||
|
||||
bool operator==(const TimeZoneInfo &other) const
|
||||
{
|
||||
if (_type == UTC || _type == System)
|
||||
return _type == other._type;
|
||||
else
|
||||
return (other._type == Custom && _customZone == other._customZone);
|
||||
}
|
||||
bool operator!=(const TimeZoneInfo &other) {return !(*this == other);}
|
||||
|
||||
private:
|
||||
friend QDataStream& operator<<(QDataStream &out, const TimeZoneInfo &info);
|
||||
friend QDataStream& operator>>(QDataStream &in, TimeZoneInfo &info);
|
||||
|
||||
Type _type;
|
||||
QTimeZone _customZone;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(TimeZoneInfo)
|
||||
|
||||
inline QDataStream &operator<<(QDataStream &out, const TimeZoneInfo &info)
|
||||
{
|
||||
out << static_cast<int>(info._type) << info._customZone;
|
||||
return out;
|
||||
}
|
||||
|
||||
inline QDataStream &operator>>(QDataStream &in, TimeZoneInfo &info)
|
||||
{
|
||||
int t;
|
||||
|
||||
in >> t;
|
||||
info._type = static_cast<TimeZoneInfo::Type>(t);
|
||||
in >> info._customZone;
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
#endif // TIMEZONEINFO_H
|
@ -22,7 +22,13 @@ QString TrackItem::info() const
|
||||
if (_movingTime > 0)
|
||||
tt.insert(tr("Moving time"), Format::timeSpan(_movingTime));
|
||||
if (!_date.isNull())
|
||||
tt.insert(tr("Date"), _date.toString(Qt::SystemLocaleShortDate));
|
||||
tt.insert(tr("Date"),
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
_date.toTimeZone(_timeZone)
|
||||
#else // ENABLE_TIMEZONES
|
||||
_date
|
||||
#endif // ENABLE_TIMEZONES
|
||||
.toString(Qt::SystemLocaleShortDate));
|
||||
if (!_links.isEmpty()) {
|
||||
QString links;
|
||||
for (int i = 0; i < _links.size(); i++) {
|
||||
|
@ -16,6 +16,7 @@ enum Units {
|
||||
#define MS2KN 1.943844490000 // m/s -> kn
|
||||
#define FT2MI 0.000189393939 // ft -> mi
|
||||
#define MM2IN 0.039370100000 // mm -> in
|
||||
#define MM2CM 0.100000000000 // mm -> cm
|
||||
#define H2S 0.000277777778 // h -> s
|
||||
#define MIN2S 0.016666666667 // min -> s
|
||||
|
||||
|
@ -13,6 +13,13 @@
|
||||
#define FS(size) \
|
||||
((int)((qreal)size * 1.41))
|
||||
|
||||
|
||||
Units WaypointItem::_units = Metric;
|
||||
CoordinatesFormat WaypointItem::_format = DecimalDegrees;
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
QTimeZone WaypointItem::_timeZone = QTimeZone::utc();
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
QString WaypointItem::info() const
|
||||
{
|
||||
ToolTip tt;
|
||||
@ -30,7 +37,12 @@ QString WaypointItem::info() const
|
||||
}
|
||||
if (_waypoint.timestamp().isValid())
|
||||
tt.insert(qApp->translate("WaypointItem", "Date"),
|
||||
_waypoint.timestamp().toString(Qt::SystemLocaleShortDate));
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
_waypoint.timestamp().toTimeZone(_timeZone)
|
||||
#else // ENABLE_TIMEZONES
|
||||
_waypoint.timestamp()
|
||||
#endif // ENABLE_TIMEZONES
|
||||
.toString(Qt::SystemLocaleShortDate));
|
||||
if (!_waypoint.description().isEmpty())
|
||||
tt.insert(qApp->translate("WaypointItem", "Description"),
|
||||
_waypoint.description());
|
||||
@ -78,9 +90,6 @@ WaypointItem::WaypointItem(const Waypoint &waypoint, Map *map,
|
||||
_font.setPixelSize(FS(_size));
|
||||
_font.setFamily(FONT_FAMILY);
|
||||
|
||||
_units = Metric;
|
||||
_format = DecimalDegrees;
|
||||
|
||||
updateCache();
|
||||
|
||||
setPos(map->ll2xy(waypoint.coordinates()));
|
||||
@ -151,12 +160,6 @@ void WaypointItem::setColor(const QColor &color)
|
||||
update();
|
||||
}
|
||||
|
||||
void WaypointItem::setToolTipFormat(Units units, CoordinatesFormat format)
|
||||
{
|
||||
_units = units;
|
||||
_format = format;
|
||||
}
|
||||
|
||||
void WaypointItem::showLabel(bool show)
|
||||
{
|
||||
if (_showLabel == show)
|
||||
|
@ -1,9 +1,13 @@
|
||||
#ifndef WAYPOINTITEM_H
|
||||
#define WAYPOINTITEM_H
|
||||
|
||||
#include "common/config.h"
|
||||
#include <cmath>
|
||||
#include <QGraphicsItem>
|
||||
#include <QFont>
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
#include <QTimeZone>
|
||||
#endif // ENABLE_TIMEZONES
|
||||
#include "data/waypoint.h"
|
||||
#include "map/map.h"
|
||||
#include "units.h"
|
||||
@ -23,7 +27,6 @@ public:
|
||||
void setColor(const QColor &color);
|
||||
void showLabel(bool show);
|
||||
void setDigitalZoom(int zoom) {setScale(pow(2, -zoom));}
|
||||
void setToolTipFormat(Units units, CoordinatesFormat format);
|
||||
|
||||
QPainterPath shape() const {return _shape;}
|
||||
QRectF boundingRect() const {return _shape.boundingRect();}
|
||||
@ -32,6 +35,13 @@ public:
|
||||
|
||||
QString info() const;
|
||||
|
||||
static void setUnits(Units units) {_units = units;}
|
||||
static void setCoordinatesFormat(CoordinatesFormat format)
|
||||
{_format = format;}
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
static void setTimeZone(const QTimeZone &zone) {_timeZone = zone;}
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
protected:
|
||||
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
|
||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
|
||||
@ -48,8 +58,11 @@ private:
|
||||
QFont _font;
|
||||
QRect _labelBB;
|
||||
|
||||
Units _units;
|
||||
CoordinatesFormat _format;
|
||||
static Units _units;
|
||||
static CoordinatesFormat _format;
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
static QTimeZone _timeZone;
|
||||
#endif // ENABLE_TIMEZONES
|
||||
};
|
||||
|
||||
#endif // WAYPOINTITEM_H
|
||||
|
@ -18,4 +18,8 @@
|
||||
#define ENABLE_GEOJSON
|
||||
#endif // QT >= 5.0
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
|
||||
#define ENABLE_TIMEZONES
|
||||
#endif // QT >= 5.5
|
||||
|
||||
#endif /* CONFIG_H */
|
||||
|
@ -15,7 +15,8 @@ public:
|
||||
bool isNull() const
|
||||
{return _tl.isNull() && _br.isNull();}
|
||||
bool isValid() const
|
||||
{return (_tl.isValid() && _br.isValid() && _tl != _br);}
|
||||
{return (_tl.isValid() && _br.isValid()
|
||||
&& _tl.lat() > _br.lat() && _tl.lon() < _br.lon());}
|
||||
|
||||
Coordinates topLeft() const {return _tl;}
|
||||
Coordinates bottomRight() const {return _br;}
|
||||
|
@ -1,7 +1,6 @@
|
||||
#ifndef RTREE_H
|
||||
#define RTREE_H
|
||||
|
||||
#include <cstdio>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <QtGlobal>
|
||||
@ -387,10 +386,10 @@ RTREE_TEMPLATE
|
||||
void RTREE_QUAL::Insert(const ELEMTYPE a_min[NUMDIMS],
|
||||
const ELEMTYPE a_max[NUMDIMS], const DATATYPE& a_dataId)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
#ifndef QT_NO_DEBUG
|
||||
for (int index=0; index<NUMDIMS; ++index)
|
||||
Q_ASSERT(a_min[index] <= a_max[index]);
|
||||
#endif //_DEBUG
|
||||
#endif // QT_NO_DEBUG
|
||||
|
||||
Rect rect;
|
||||
|
||||
@ -407,10 +406,10 @@ RTREE_TEMPLATE
|
||||
void RTREE_QUAL::Remove(const ELEMTYPE a_min[NUMDIMS],
|
||||
const ELEMTYPE a_max[NUMDIMS], const DATATYPE& a_dataId)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
#ifndef QT_NO_DEBUG
|
||||
for (int index=0; index<NUMDIMS; ++index)
|
||||
Q_ASSERT(a_min[index] <= a_max[index]);
|
||||
#endif //_DEBUG
|
||||
#endif // QT_NO_DEBUG
|
||||
|
||||
Rect rect;
|
||||
|
||||
@ -427,10 +426,10 @@ RTREE_TEMPLATE
|
||||
int RTREE_QUAL::Search(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS],
|
||||
bool a_resultCallback(DATATYPE a_data, void* a_context), void* a_context) const
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
#ifndef QT_NO_DEBUG
|
||||
for (int index=0; index<NUMDIMS; ++index)
|
||||
Q_ASSERT(a_min[index] <= a_max[index]);
|
||||
#endif //_DEBUG
|
||||
#endif // QT_NO_DEBUG
|
||||
|
||||
Rect rect;
|
||||
|
||||
@ -636,10 +635,10 @@ bool RTREE_QUAL::InsertRect(Rect* a_rect, const DATATYPE& a_id, Node** a_root,
|
||||
{
|
||||
Q_ASSERT(a_rect && a_root);
|
||||
Q_ASSERT(a_level >= 0 && a_level <= (*a_root)->m_level);
|
||||
#ifdef _DEBUG
|
||||
#ifndef QT_NO_DEBUG
|
||||
for (int index=0; index < NUMDIMS; ++index)
|
||||
Q_ASSERT(a_rect->m_min[index] <= a_rect->m_max[index]);
|
||||
#endif //_DEBUG
|
||||
#endif // QT_NO_DEBUG
|
||||
|
||||
Node* newRoot;
|
||||
Node* newNode;
|
||||
|
@ -33,18 +33,18 @@ public:
|
||||
return false;
|
||||
|
||||
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
|
||||
if (_be)
|
||||
val = data;
|
||||
else {
|
||||
for (size_t i = 0; i < sizeof(T); i++)
|
||||
*((char *)&val + i) = *((char*)&data + sizeof(T) - 1 - i);
|
||||
}
|
||||
if (_be)
|
||||
val = data;
|
||||
else {
|
||||
for (size_t i = 0; i < sizeof(T); i++)
|
||||
*((char *)&val + i) = *((char*)&data + sizeof(T) - 1 - i);
|
||||
}
|
||||
#else
|
||||
if (_be) {
|
||||
for (size_t i = 0; i < sizeof(T); i++)
|
||||
*((char *)&val + i) = *((char*)&data + sizeof(T) - 1 - i);
|
||||
} else
|
||||
val = data;
|
||||
if (_be) {
|
||||
for (size_t i = 0; i < sizeof(T); i++)
|
||||
*((char *)&val + i) = *((char*)&data + sizeof(T) - 1 - i);
|
||||
} else
|
||||
val = data;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#define RECORD_MESSAGE 20
|
||||
#define EVENT_MESSAGE 21
|
||||
#define COURSE_POINT 32
|
||||
#define TIMESTAMP_FIELD 253
|
||||
|
||||
class Event {
|
||||
@ -48,10 +49,12 @@ public:
|
||||
|
||||
class FITParser::CTX {
|
||||
public:
|
||||
CTX(QFile *file) : file(file), len(0), endian(0), timestamp(0),
|
||||
lastWrite(0), ratio(NAN) {}
|
||||
CTX(QFile *file, QVector<Waypoint> &waypoints)
|
||||
: file(file), waypoints(waypoints), len(0), endian(0), timestamp(0),
|
||||
lastWrite(0), ratio(NAN) {}
|
||||
|
||||
QFile *file;
|
||||
QVector<Waypoint> &waypoints;
|
||||
quint32 len;
|
||||
quint8 endian;
|
||||
quint32 timestamp, lastWrite;
|
||||
@ -61,6 +64,41 @@ public:
|
||||
SegmentData segment;
|
||||
};
|
||||
|
||||
static QMap<int, QString> coursePointDescInit()
|
||||
{
|
||||
QMap<int, QString> map;
|
||||
|
||||
map.insert(1, "Summit");
|
||||
map.insert(2, "Valley");
|
||||
map.insert(3, "Water");
|
||||
map.insert(4, "Food");
|
||||
map.insert(5, "Danger");
|
||||
map.insert(6, "Left");
|
||||
map.insert(7, "Right");
|
||||
map.insert(8, "Straight");
|
||||
map.insert(9, "First aid");
|
||||
map.insert(10, "Fourth category");
|
||||
map.insert(11, "Third category");
|
||||
map.insert(12, "Second category");
|
||||
map.insert(13, "First category");
|
||||
map.insert(14, "Hors category");
|
||||
map.insert(15, "Sprint");
|
||||
map.insert(16, "Left fork");
|
||||
map.insert(17, "Right fork");
|
||||
map.insert(18, "Middle fork");
|
||||
map.insert(19, "Slight left");
|
||||
map.insert(20, "Sharp left");
|
||||
map.insert(21, "Slight right");
|
||||
map.insert(22, "Sharp right");
|
||||
map.insert(23, "U-Turn");
|
||||
map.insert(24, "Segment start");
|
||||
map.insert(25, "Segment end");
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
static QMap<int, QString> coursePointDesc = coursePointDescInit();
|
||||
|
||||
|
||||
bool FITParser::readData(QFile *file, char *data, size_t size)
|
||||
{
|
||||
@ -80,17 +118,12 @@ bool FITParser::readData(QFile *file, char *data, size_t size)
|
||||
|
||||
template<class T> bool FITParser::readValue(CTX &ctx, T &val)
|
||||
{
|
||||
T data;
|
||||
|
||||
if (!readData(ctx.file, (char*)&data, sizeof(T)))
|
||||
if (!readData(ctx.file, (char*)&val, sizeof(T)))
|
||||
return false;
|
||||
|
||||
ctx.len -= sizeof(T);
|
||||
|
||||
if (ctx.endian)
|
||||
val = qFromBigEndian(data);
|
||||
else
|
||||
val = qFromLittleEndian(data);
|
||||
if (sizeof(T) > 1)
|
||||
val = (ctx.endian) ? qFromBigEndian(val) : qFromLittleEndian(val);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -167,41 +200,51 @@ bool FITParser::parseDefinitionMessage(CTX &ctx, quint8 header)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FITParser::readField(CTX &ctx, Field *field, quint32 &val)
|
||||
bool FITParser::readField(CTX &ctx, Field *field, QVariant &val, bool &valid)
|
||||
{
|
||||
quint8 v8 = (quint8)-1;
|
||||
quint16 v16 = (quint16)-1;
|
||||
bool ret;
|
||||
|
||||
val = (quint32)-1;
|
||||
#define VAL(type, inval) \
|
||||
{type var; \
|
||||
if (field->size == sizeof(var)) { \
|
||||
ret = readValue(ctx, var); \
|
||||
val = var; \
|
||||
valid = (var != (inval)); \
|
||||
} else { \
|
||||
ret = skipValue(ctx, field->size); \
|
||||
valid = false; \
|
||||
}}
|
||||
|
||||
switch (field->type) {
|
||||
case 0: // enum
|
||||
case 1: // sint8
|
||||
VAL(qint8, 0x7fU);
|
||||
break;
|
||||
case 2: // uint8
|
||||
if (field->size == 1) {
|
||||
ret = readValue(ctx, v8);
|
||||
val = v8;
|
||||
} else
|
||||
ret = skipValue(ctx, field->size);
|
||||
case 0: // enum
|
||||
VAL(quint8, 0xffU);
|
||||
break;
|
||||
case 7: // UTF8 nul terminated string
|
||||
{QByteArray ba(ctx.file->read(field->size));
|
||||
ctx.len -= field->size;
|
||||
ret = (ba.size() == field->size);
|
||||
val = ret ? ba : QString();
|
||||
valid = !ba.isEmpty();}
|
||||
break;
|
||||
case 0x83: // sint16
|
||||
VAL(qint16, 0x7fffU);
|
||||
break;
|
||||
case 0x84: // uint16
|
||||
if (field->size == 2) {
|
||||
ret = readValue(ctx, v16);
|
||||
val = v16;
|
||||
} else
|
||||
ret = skipValue(ctx, field->size);
|
||||
VAL(quint16, 0xffffU);
|
||||
break;
|
||||
case 0x85: // sint32
|
||||
VAL(qint32, 0x7fffffffU);
|
||||
break;
|
||||
case 0x86: // uint32
|
||||
if (field->size == 4)
|
||||
ret = readValue(ctx, val);
|
||||
else
|
||||
ret = skipValue(ctx, field->size);
|
||||
VAL(quint32, 0xffffffffU);
|
||||
break;
|
||||
default:
|
||||
ret = skipValue(ctx, field->size);
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -211,8 +254,10 @@ bool FITParser::readField(CTX &ctx, Field *field, quint32 &val)
|
||||
bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
||||
{
|
||||
Field *field;
|
||||
QVariant val;
|
||||
bool valid;
|
||||
Event event;
|
||||
quint32 val;
|
||||
Waypoint waypoint;
|
||||
|
||||
|
||||
if (!def->fields && !def->devFields) {
|
||||
@ -224,69 +269,79 @@ bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
||||
|
||||
for (int i = 0; i < def->numFields; i++) {
|
||||
field = &def->fields[i];
|
||||
if (!readField(ctx, field, val))
|
||||
if (!readField(ctx, field, val, valid))
|
||||
return false;
|
||||
if (!valid)
|
||||
continue;
|
||||
|
||||
if (field->id == TIMESTAMP_FIELD)
|
||||
ctx.timestamp = val;
|
||||
ctx.timestamp = val.toUInt();
|
||||
else if (def->globalId == RECORD_MESSAGE) {
|
||||
switch (field->id) {
|
||||
case 0:
|
||||
if (val != 0x7fffffff)
|
||||
ctx.trackpoint.rcoordinates().setLat(
|
||||
((qint32)val / (double)0x7fffffff) * 180);
|
||||
ctx.trackpoint.rcoordinates().setLat(
|
||||
(val.toInt() / (double)0x7fffffff) * 180);
|
||||
break;
|
||||
case 1:
|
||||
if (val != 0x7fffffff)
|
||||
ctx.trackpoint.rcoordinates().setLon(
|
||||
((qint32)val / (double)0x7fffffff) * 180);
|
||||
ctx.trackpoint.rcoordinates().setLon(
|
||||
(val.toInt() / (double)0x7fffffff) * 180);
|
||||
break;
|
||||
case 2:
|
||||
if (val != 0xffff)
|
||||
ctx.trackpoint.setElevation((val / 5.0) - 500);
|
||||
ctx.trackpoint.setElevation((val.toUInt() / 5.0) - 500);
|
||||
break;
|
||||
case 3:
|
||||
if (val != 0xff)
|
||||
ctx.trackpoint.setHeartRate(val);
|
||||
ctx.trackpoint.setHeartRate(val.toUInt());
|
||||
break;
|
||||
case 4:
|
||||
if (val != 0xff)
|
||||
ctx.trackpoint.setCadence(val);
|
||||
ctx.trackpoint.setCadence(val.toUInt());
|
||||
break;
|
||||
case 6:
|
||||
if (val != 0xffff)
|
||||
ctx.trackpoint.setSpeed(val / 1000.0f);
|
||||
ctx.trackpoint.setSpeed(val.toUInt() / 1000.0f);
|
||||
break;
|
||||
case 7:
|
||||
if (val != 0xffff)
|
||||
ctx.trackpoint.setPower(val);
|
||||
ctx.trackpoint.setPower(val.toUInt());
|
||||
break;
|
||||
case 13:
|
||||
if (val != 0x7f)
|
||||
ctx.trackpoint.setTemperature((qint8)val);
|
||||
ctx.trackpoint.setTemperature(val.toInt());
|
||||
break;
|
||||
case 73:
|
||||
if (val != 0xffffffff)
|
||||
ctx.trackpoint.setSpeed(val / 1000.0f);
|
||||
ctx.trackpoint.setSpeed(val.toUInt() / 1000.0f);
|
||||
break;
|
||||
case 78:
|
||||
if (val != 0xffffffff)
|
||||
ctx.trackpoint.setElevation((val / 5.0) - 500);
|
||||
ctx.trackpoint.setElevation((val.toUInt() / 5.0) - 500);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
} else if (def->globalId == EVENT_MESSAGE) {
|
||||
switch (field->id) {
|
||||
case 0:
|
||||
event.id = val;
|
||||
event.id = val.toUInt();
|
||||
break;
|
||||
case 1:
|
||||
event.type = val;
|
||||
event.type = val.toUInt();
|
||||
break;
|
||||
case 3:
|
||||
event.data = val;
|
||||
event.data = val.toUInt();
|
||||
break;
|
||||
}
|
||||
} else if (def->globalId == COURSE_POINT) {
|
||||
switch (field->id) {
|
||||
case 1:
|
||||
waypoint.setTimestamp(QDateTime::fromTime_t(val.toUInt()
|
||||
+ 631065600));
|
||||
break;
|
||||
case 2:
|
||||
waypoint.rcoordinates().setLat(
|
||||
(val.toInt() / (double)0x7fffffff) * 180);
|
||||
break;
|
||||
case 3:
|
||||
waypoint.rcoordinates().setLon(
|
||||
(val.toInt() / (double)0x7fffffff) * 180);
|
||||
break;
|
||||
case 5:
|
||||
waypoint.setDescription(coursePointDesc.value(val.toUInt()));
|
||||
break;
|
||||
case 6:
|
||||
waypoint.setName(val.toString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -294,7 +349,7 @@ bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
||||
|
||||
for (int i = 0; i < def->numDevFields; i++) {
|
||||
field = &def->devFields[i];
|
||||
if (!readField(ctx, field, val))
|
||||
if (!readField(ctx, field, val, valid))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -315,7 +370,9 @@ bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
||||
ctx.trackpoint = Trackpoint();
|
||||
ctx.lastWrite = ctx.timestamp;
|
||||
}
|
||||
}
|
||||
} else if (def->globalId == COURSE_POINT)
|
||||
if (waypoint.coordinates().isValid())
|
||||
ctx.waypoints.append(waypoint);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -381,9 +438,8 @@ bool FITParser::parse(QFile *file, QList<TrackData> &tracks,
|
||||
QList<Area> &polygons, QVector<Waypoint> &waypoints)
|
||||
{
|
||||
Q_UNUSED(routes);
|
||||
Q_UNUSED(waypoints);
|
||||
Q_UNUSED(polygons);
|
||||
CTX ctx(file);
|
||||
CTX ctx(file, waypoints);
|
||||
|
||||
|
||||
if (!parseHeader(ctx))
|
||||
|
@ -21,7 +21,7 @@ private:
|
||||
bool readData(QFile *file, char *data, size_t size);
|
||||
template<class T> bool readValue(CTX &ctx, T &val);
|
||||
bool skipValue(CTX &ctx, quint8 size);
|
||||
bool readField(CTX &ctx, Field *field, quint32 &val);
|
||||
bool readField(CTX &ctx, Field *field, QVariant &val, bool &valid);
|
||||
|
||||
bool parseHeader(CTX &ctx);
|
||||
bool parseRecord(CTX &ctx);
|
||||
|
@ -585,7 +585,9 @@ void KMLParser::document(QList<TrackData> &tracks, QList<Area> &areas,
|
||||
QVector<Waypoint> &waypoints)
|
||||
{
|
||||
while (_reader.readNextStartElement()) {
|
||||
if (_reader.name() == QLatin1String("Placemark"))
|
||||
if (_reader.name() == QLatin1String("Document"))
|
||||
document(tracks, areas, waypoints);
|
||||
else if (_reader.name() == QLatin1String("Placemark"))
|
||||
placemark(tracks, areas, waypoints);
|
||||
else if (_reader.name() == QLatin1String("Folder"))
|
||||
folder(tracks, areas, waypoints);
|
||||
|
@ -66,13 +66,25 @@ void TCXParser::heartRateBpm(Trackpoint &trackpoint)
|
||||
}
|
||||
}
|
||||
|
||||
void TCXParser::extensions(Trackpoint &trackpoint)
|
||||
void TCXParser::TPX(Trackpoint &trackpoint)
|
||||
{
|
||||
while (_reader.readNextStartElement()) {
|
||||
if (_reader.name() == QLatin1String("RunCadence"))
|
||||
trackpoint.setCadence(number());
|
||||
else if (_reader.name() == QLatin1String("Watts"))
|
||||
trackpoint.setPower(number());
|
||||
else if (_reader.name() == QLatin1String("Speed"))
|
||||
trackpoint.setSpeed(number());
|
||||
else
|
||||
_reader.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
void TCXParser::extensions(Trackpoint &trackpoint)
|
||||
{
|
||||
while (_reader.readNextStartElement()) {
|
||||
if (_reader.name() == QLatin1String("TPX"))
|
||||
TPX(trackpoint);
|
||||
else
|
||||
_reader.skipCurrentElement();
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ private:
|
||||
void trackpointData(Trackpoint &trackpoint);
|
||||
void waypointData(Waypoint &waypoint);
|
||||
void extensions(Trackpoint &trackpoint);
|
||||
void TPX(Trackpoint &trackpoint);
|
||||
void heartRateBpm(Trackpoint &trackpoint);
|
||||
Coordinates position();
|
||||
qreal number();
|
||||
|
@ -17,7 +17,7 @@ bool Track::_useReportedSpeed = false;
|
||||
bool Track::_useDEM = false;
|
||||
bool Track::_show2ndElevation = false;
|
||||
bool Track::_show2ndSpeed = false;
|
||||
|
||||
bool Track::_useSegments = true;
|
||||
|
||||
static qreal avg(const QVector<qreal> &v)
|
||||
{
|
||||
@ -42,6 +42,12 @@ static qreal MAD(QVector<qreal> &v, qreal m)
|
||||
return median(v);
|
||||
}
|
||||
|
||||
/*
|
||||
Modified Z-score (Iglewicz and Hoaglin)
|
||||
The acceleration data distribution has usualy a (much) higher kurtosis than
|
||||
the normal distribution thus a higher comparsion value than the usual 3.5 is
|
||||
required.
|
||||
*/
|
||||
static QSet<int> eliminate(const QVector<qreal> &v)
|
||||
{
|
||||
QSet<int> rm;
|
||||
@ -51,7 +57,7 @@ static QSet<int> eliminate(const QVector<qreal> &v)
|
||||
qreal M = MAD(w, m);
|
||||
|
||||
for (int i = 0; i < v.size(); i++)
|
||||
if (qAbs((0.6745 * (v.at(i) - m)) / M) > 3.5)
|
||||
if (qAbs((0.6745 * (v.at(i) - m)) / M) > 5.0)
|
||||
rm.insert(i);
|
||||
|
||||
return rm;
|
||||
@ -82,10 +88,20 @@ static GraphSegment filter(const GraphSegment &g, int window)
|
||||
}
|
||||
|
||||
|
||||
Track::Track(const TrackData &data) : _data(data), _pause(0)
|
||||
Track::Track(const TrackData &data) : _pause(0)
|
||||
{
|
||||
qreal ds, dt;
|
||||
|
||||
if (_useSegments)
|
||||
_data = data;
|
||||
else {
|
||||
if (!data.isEmpty()) {
|
||||
_data.append(data.first());
|
||||
for (int i = 1; i < data.size(); i++)
|
||||
_data.first() << data.at(i);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < _data.size(); i++) {
|
||||
const SegmentData &sd = _data.at(i);
|
||||
_segments.append(Segment());
|
||||
|
@ -49,10 +49,9 @@ public:
|
||||
{_outlierEliminate = eliminate;}
|
||||
static void useReportedSpeed(bool use) {_useReportedSpeed = use;}
|
||||
static void useDEM(bool use) {_useDEM = use;}
|
||||
static void showSecondaryElevation(bool show)
|
||||
{_show2ndElevation = show;}
|
||||
static void showSecondarySpeed(bool show)
|
||||
{_show2ndSpeed = show;}
|
||||
static void showSecondaryElevation(bool show) {_show2ndElevation = show;}
|
||||
static void showSecondarySpeed(bool show) {_show2ndSpeed = show;}
|
||||
static void useSegments(bool use) {_useSegments = use;}
|
||||
|
||||
private:
|
||||
struct Segment {
|
||||
@ -87,6 +86,7 @@ private:
|
||||
static bool _useDEM;
|
||||
static bool _show2ndElevation;
|
||||
static bool _show2ndSpeed;
|
||||
static bool _useSegments;
|
||||
};
|
||||
|
||||
#endif // TRACK_H
|
||||
|
@ -19,6 +19,7 @@ public:
|
||||
: _coordinates(coordinates), _elevation(NAN) {}
|
||||
|
||||
const Coordinates &coordinates() const {return _coordinates;}
|
||||
Coordinates &rcoordinates() {return _coordinates;}
|
||||
const QString &name() const {return _name;}
|
||||
const QString &description() const {return _description;}
|
||||
const QString &comment() const {return _comment;}
|
||||
|
@ -1,4 +1,7 @@
|
||||
#include "common/config.h"
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
#include "GUI/timezoneinfo.h"
|
||||
#endif // ENABLE_TIMEZONES
|
||||
#include "GUI/app.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@ -7,6 +10,9 @@ int main(int argc, char *argv[])
|
||||
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
#endif // ENABLE_HIDPI
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
qRegisterMetaTypeStreamOperators<TimeZoneInfo>("TimeZoneInfo");
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
App app(argc, argv);
|
||||
return app.run();
|
||||
|
@ -1,38 +1,9 @@
|
||||
#include "bitstream.h"
|
||||
|
||||
|
||||
bool BitStream1::read(int bits, quint32 &val)
|
||||
{
|
||||
val = 0;
|
||||
|
||||
for (int pos = 0; pos < bits; ) {
|
||||
if (!_remaining) {
|
||||
if (!_length || !_file.readUInt8(_hdl, _data))
|
||||
return false;
|
||||
_remaining = 8;
|
||||
_length--;
|
||||
}
|
||||
|
||||
quint32 get = bits - pos;
|
||||
if (get >= _remaining) {
|
||||
val |= _data << pos;
|
||||
pos += _remaining;
|
||||
_remaining = 0;
|
||||
} else {
|
||||
quint32 mask = (1<<get) - 1;
|
||||
val |= (_data & mask)<<pos;
|
||||
_data >>= get;
|
||||
_remaining -= get;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BitStream1::flush()
|
||||
{
|
||||
if (_length && !_file.seek(_hdl, _hdl.pos() + _length))
|
||||
if (_length && !_file.seek(_hdl, _file.pos(_hdl) + _length))
|
||||
return false;
|
||||
|
||||
_length = 0;
|
||||
@ -41,8 +12,35 @@ bool BitStream1::flush()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BitStream1::readUInt24(quint32 &val)
|
||||
{
|
||||
quint8 b;
|
||||
|
||||
bool BitStream4::read(int bits, quint32 &val)
|
||||
val = 0;
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (!read(8, b))
|
||||
return false;
|
||||
val |= (b << (i * 8));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool BitStream4F::flush()
|
||||
{
|
||||
if (_length && !_file.seek(_hdl, _file.pos(_hdl) + _length))
|
||||
return false;
|
||||
|
||||
_length = 0;
|
||||
_used = 32;
|
||||
_unused = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BitStream4F::read(int bits, quint32 &val)
|
||||
{
|
||||
if (bits <= 32 - (int)(_used + _unused)) {
|
||||
val = bits ? (_data << _used) >> (32 - bits) : 0;
|
||||
@ -50,6 +48,8 @@ bool BitStream4::read(int bits, quint32 &val)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_unused)
|
||||
return false;
|
||||
quint32 old = (_used < 32) ? (_data << _used) >> (32 - bits) : 0;
|
||||
quint32 bytes = qMin(_length, 4U);
|
||||
|
||||
@ -66,14 +66,149 @@ bool BitStream4::read(int bits, quint32 &val)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BitStream4::flush()
|
||||
BitStream4R::BitStream4R(const SubFile &file, SubFile::Handle &hdl,
|
||||
quint32 length) : BitStream4(file, hdl, length)
|
||||
{
|
||||
if (_length && !_file.seek(_hdl, _hdl.pos() + _length))
|
||||
return false;
|
||||
_file.seek(_hdl, _file.pos(_hdl) - 4);
|
||||
}
|
||||
|
||||
_length = 0;
|
||||
_used = 32;
|
||||
_unused = 0;
|
||||
bool BitStream4R::readBytes(int bytes, quint32 &val)
|
||||
{
|
||||
quint32 bits = _used % 8;
|
||||
quint32 b;
|
||||
|
||||
if (bits) {
|
||||
if (!read(8 - bits, b))
|
||||
return false;
|
||||
Q_ASSERT(!b);
|
||||
}
|
||||
|
||||
val = 0;
|
||||
for (int i = 0; i < bytes; i++) {
|
||||
if (!read(8, b))
|
||||
return false;
|
||||
val |= (b << (i * 8));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BitStream4R::readVUInt32(quint32 &val)
|
||||
{
|
||||
quint32 b;
|
||||
quint8 bytes, shift;
|
||||
|
||||
if (!readBytes(1, b))
|
||||
return false;
|
||||
|
||||
if ((b & 1) == 0) {
|
||||
if ((b & 2) == 0) {
|
||||
bytes = ((b >> 2) & 1) ^ 3;
|
||||
shift = 5;
|
||||
} else {
|
||||
shift = 6;
|
||||
bytes = 1;
|
||||
}
|
||||
} else {
|
||||
shift = 7;
|
||||
bytes = 0;
|
||||
}
|
||||
|
||||
val = b >> (8 - shift);
|
||||
|
||||
if (bytes) {
|
||||
if (!readBytes(bytes, b))
|
||||
return false;
|
||||
val = val | (b << shift);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BitStream4R::readVuint32SM(quint32 &val1, quint32 &val2, quint32 &val2Bits)
|
||||
{
|
||||
quint32 b, eb;
|
||||
|
||||
if (!readBytes(1, b))
|
||||
return false;
|
||||
|
||||
if (!(b & 1)) {
|
||||
val1 = b >> 3;
|
||||
val2 = b >> 1 & 3;
|
||||
val2Bits = 2;
|
||||
} else {
|
||||
eb = b & 2;
|
||||
val2 = b >> 2 & 0x3f;
|
||||
val2Bits = eb * 2 + 6;
|
||||
if (!readBytes((eb >> 1 | 2) - 1, b))
|
||||
return false;
|
||||
if (eb) {
|
||||
val2 = val2 | (b & 0xf) << 6;
|
||||
b = b >> 4 & 0xfff;
|
||||
}
|
||||
val1 = b;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BitStream4R::skip(quint32 bytes)
|
||||
{
|
||||
if (bytes * 8 > bitsAvailable())
|
||||
return false;
|
||||
|
||||
quint32 ab = (32 - (_used + _unused))/8;
|
||||
if (bytes <= ab)
|
||||
_used += bytes * 8;
|
||||
else {
|
||||
quint32 seek = ((bytes - ab)/4)*4;
|
||||
quint32 read = (bytes - ab)%4;
|
||||
if (seek && !_file.seek(_hdl, _file.pos(_hdl) - seek))
|
||||
return false;
|
||||
_length -= seek;
|
||||
if (read) {
|
||||
quint32 rb = qMin(_length, 4U);
|
||||
if (!_file.readUInt32(_hdl, _data))
|
||||
return false;
|
||||
if (!_file.seek(_hdl, _file.pos(_hdl) - 8))
|
||||
return false;
|
||||
_length -= rb;
|
||||
_unused = (4 - rb) * 8;
|
||||
_used = read * 8;
|
||||
} else
|
||||
_used = 32;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BitStream4R::resize(quint32 bytes)
|
||||
{
|
||||
quint32 ab = (32 - (_used + _unused) + 7)/8;
|
||||
|
||||
if (ab <= bytes)
|
||||
_length = bytes - ab;
|
||||
else {
|
||||
_length = 0;
|
||||
_unused += (ab - bytes) * 8;
|
||||
}
|
||||
}
|
||||
|
||||
void BitStream4R::save(State &state)
|
||||
{
|
||||
state.pos = _file.pos(_hdl);
|
||||
state.length = _length;
|
||||
state.used = _used;
|
||||
state.unused = _unused;
|
||||
state.data = _data;
|
||||
}
|
||||
|
||||
bool BitStream4R::restore(const State &state)
|
||||
{
|
||||
_length = state.length;
|
||||
_used = state.used;
|
||||
_unused = state.unused;
|
||||
_data = state.data;
|
||||
|
||||
return _file.seek(_hdl, state.pos);
|
||||
}
|
||||
|
@ -8,9 +8,11 @@ public:
|
||||
BitStream1(const SubFile &file, SubFile::Handle &hdl, quint32 length)
|
||||
: _file(file), _hdl(hdl), _length(length), _remaining(0) {}
|
||||
|
||||
bool read(int bits, quint32 &val);
|
||||
template<typename T> bool read(int bits, T &val);
|
||||
bool flush();
|
||||
quint32 bitsAvailable() const {return _length * 8 + _remaining;}
|
||||
quint64 bitsAvailable() const {return (quint64)_length * 8 + _remaining;}
|
||||
|
||||
bool readUInt24(quint32 &val);
|
||||
|
||||
private:
|
||||
const SubFile &_file;
|
||||
@ -25,15 +27,105 @@ public:
|
||||
: _file(file), _hdl(hdl), _length(length), _used(32), _unused(0),
|
||||
_data(0) {}
|
||||
|
||||
bool read(int bits, quint32 &val);
|
||||
bool flush();
|
||||
quint32 bitsAvailable() const {return _length * 8 + (32 - _used) - _unused;}
|
||||
quint64 bitsAvailable() const
|
||||
{return (quint64)_length * 8 + (32 - _used) - _unused;}
|
||||
|
||||
private:
|
||||
protected:
|
||||
const SubFile &_file;
|
||||
SubFile::Handle &_hdl;
|
||||
quint32 _length, _used, _unused;
|
||||
quint32 _data;
|
||||
};
|
||||
|
||||
class BitStream4F : public BitStream4 {
|
||||
public:
|
||||
BitStream4F(const SubFile &file, SubFile::Handle &hdl, quint32 length)
|
||||
: BitStream4(file, hdl, length) {}
|
||||
|
||||
bool read(int bits, quint32 &val);
|
||||
bool flush();
|
||||
};
|
||||
|
||||
class BitStream4R : public BitStream4 {
|
||||
public:
|
||||
struct State {
|
||||
quint32 pos;
|
||||
quint32 length;
|
||||
quint32 used;
|
||||
quint32 unused;
|
||||
quint32 data;
|
||||
};
|
||||
|
||||
BitStream4R(const SubFile &file, SubFile::Handle &hdl, quint32 length);
|
||||
|
||||
template<typename T> bool read(int bits, T &val);
|
||||
bool readBytes(int bytes, quint32 &val);
|
||||
bool readVUInt32(quint32 &val);
|
||||
bool readVuint32SM(quint32 &val1, quint32 &val2, quint32 &val2Bits);
|
||||
|
||||
bool skip(quint32 bytes);
|
||||
void resize(quint32 bytes);
|
||||
void save(State &state);
|
||||
bool restore(const State &state);
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
bool BitStream1::read(int bits, T &val)
|
||||
{
|
||||
val = 0;
|
||||
|
||||
for (int pos = 0; pos < bits; ) {
|
||||
if (!_remaining) {
|
||||
if (!_length || !_file.readUInt8(_hdl, _data))
|
||||
return false;
|
||||
_remaining = 8;
|
||||
_length--;
|
||||
}
|
||||
|
||||
quint32 get = bits - pos;
|
||||
if (get >= _remaining) {
|
||||
val |= _data << pos;
|
||||
pos += _remaining;
|
||||
_remaining = 0;
|
||||
} else {
|
||||
quint32 mask = (1<<get) - 1;
|
||||
val |= (_data & mask)<<pos;
|
||||
_data >>= get;
|
||||
_remaining -= get;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool BitStream4R::read(int bits, T &val)
|
||||
{
|
||||
if (bits <= 32 - (int)(_used + _unused)) {
|
||||
val = bits ? (_data << _used) >> (32 - bits) : 0;
|
||||
_used += bits;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_unused)
|
||||
return false;
|
||||
quint32 old = (_used < 32) ? (_data << _used) >> (32 - bits) : 0;
|
||||
quint32 bytes = qMin(_length, 4U);
|
||||
|
||||
if (!_file.readUInt32(_hdl, _data))
|
||||
return false;
|
||||
if (!_file.seek(_hdl, _file.pos(_hdl) - 8))
|
||||
return false;
|
||||
|
||||
_length -= bytes;
|
||||
_used -= 32 - bits;
|
||||
_unused = (4 - bytes) * 8;
|
||||
|
||||
val = _data >> (32 - _used) | old;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // BITSTREAM_H
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include <QXmlStreamReader>
|
||||
#include <QDir>
|
||||
#include "map/osm.h"
|
||||
#include "vectortile.h"
|
||||
#include "gmap.h"
|
||||
|
||||
@ -104,11 +103,6 @@ bool GMAP::loadTile(const QDir &dir, bool baseMap)
|
||||
if (tile->zooms().min() < _zooms.min())
|
||||
_zooms.setMin(tile->zooms().min());
|
||||
|
||||
// Limit world maps bounds so that the maps can be projected using
|
||||
// the default Web Mercator projection
|
||||
if (_bounds.height() > 120)
|
||||
_bounds &= OSM::BOUNDS;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1,74 +1,41 @@
|
||||
#include "huffmanstream.h"
|
||||
|
||||
|
||||
HuffmanStream::HuffmanStream(const SubFile &file, SubFile::Handle &hdl,
|
||||
quint32 length, const HuffmanTable &table, bool line)
|
||||
: BitStream4(file, hdl, length), _table(table), _symbolDataSize(0),
|
||||
_symbolData(0)
|
||||
bool HuffmanStreamF::init(bool line)
|
||||
{
|
||||
if (line) {
|
||||
if (!(sign(_lonSign) && sign(_latSign)))
|
||||
return;
|
||||
return false;
|
||||
} else {
|
||||
_lonSign = 0;
|
||||
_latSign = 0;
|
||||
}
|
||||
|
||||
quint32 eb;
|
||||
if (!read(1, eb))
|
||||
return;
|
||||
if (eb) {
|
||||
qWarning("Extended polygon/lines not supported");
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
bool HuffmanStream::sign(int &val)
|
||||
{
|
||||
quint32 bit;
|
||||
val = 0;
|
||||
|
||||
if (!read(1, bit))
|
||||
if (!_bs.read(1, eb))
|
||||
return false;
|
||||
|
||||
Q_ASSERT(!eb);
|
||||
if (eb)
|
||||
return false;
|
||||
if (bit) {
|
||||
if (!read(1, bit))
|
||||
return false;
|
||||
val = bit ? -1 : 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HuffmanStream::readDelta(int sign, qint32 &symbol)
|
||||
bool HuffmanStreamR::init()
|
||||
{
|
||||
quint8 size;
|
||||
quint32 next;
|
||||
quint8 nextSize = qMin((quint32)(32 - _symbolDataSize), bitsAvailable());
|
||||
|
||||
if (!read(nextSize, next))
|
||||
if (!(sign(_lonSign) && sign(_latSign)))
|
||||
return false;
|
||||
|
||||
_symbolData = (_symbolData << nextSize) | next;
|
||||
_symbolDataSize += nextSize;
|
||||
|
||||
symbol = _table.symbol(_symbolData << (32 - _symbolDataSize), size);
|
||||
|
||||
if (size <= _symbolDataSize)
|
||||
_symbolDataSize -= size;
|
||||
else
|
||||
return false;
|
||||
|
||||
if (symbol && !sign) {
|
||||
if (!_symbolDataSize)
|
||||
return false;
|
||||
else {
|
||||
sign = ((1U << (_symbolDataSize - 1)) & _symbolData) ? -1 : 1;
|
||||
_symbolDataSize--;
|
||||
}
|
||||
}
|
||||
symbol = sign * symbol;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HuffmanStreamR::init(int lonSign, int latSign, quint32 data,
|
||||
quint32 dataSize)
|
||||
{
|
||||
_lonSign = lonSign;
|
||||
_latSign = latSign;
|
||||
_symbolData = data;
|
||||
_symbolDataSize = dataSize;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -4,11 +4,15 @@
|
||||
#include "bitstream.h"
|
||||
#include "huffmantable.h"
|
||||
|
||||
class HuffmanStream : public BitStream4 {
|
||||
template <class BitStream>
|
||||
class HuffmanStream {
|
||||
public:
|
||||
HuffmanStream(const SubFile &file, SubFile::Handle &hdl, quint32 length,
|
||||
const HuffmanTable &table, bool line);
|
||||
HuffmanStream(BitStream &bitstream, const HuffmanTable &table)
|
||||
: _bs(bitstream), _table(table), _symbolDataSize(0), _symbolData(0),
|
||||
_lonSign(0), _latSign(0) {}
|
||||
|
||||
bool read(int bits, quint32 &val);
|
||||
bool readSymbol(quint32 &symbol);
|
||||
bool readNext(qint32 &lonDelta, qint32 &latDelta)
|
||||
{
|
||||
if (!(readDelta(_lonSign, lonDelta) && readDelta(_latSign, latDelta)))
|
||||
@ -17,19 +21,121 @@ public:
|
||||
return (lonDelta || latDelta);
|
||||
}
|
||||
|
||||
bool readOffset(qint32 &lonDelta, qint32 &latDelta)
|
||||
{return (readDelta(1, lonDelta) && readDelta(1, latDelta));}
|
||||
bool atEnd() const
|
||||
{return _symbolDataSize + bitsAvailable() < _table.maxSymbolSize();}
|
||||
{return _symbolDataSize + _bs.bitsAvailable() < _table.maxSymbolSize();}
|
||||
bool flush() {return _bs.flush();}
|
||||
|
||||
private:
|
||||
protected:
|
||||
bool sign(int &val);
|
||||
bool readDelta(int sign, qint32 &delta);
|
||||
|
||||
BitStream &_bs;
|
||||
const HuffmanTable &_table;
|
||||
quint32 _symbolDataSize;
|
||||
quint32 _symbolData;
|
||||
int _lonSign, _latSign;
|
||||
};
|
||||
|
||||
template <class BitStream>
|
||||
bool HuffmanStream<BitStream>::sign(int &val)
|
||||
{
|
||||
quint32 bit;
|
||||
val = 0;
|
||||
|
||||
if (!_bs.read(1, bit))
|
||||
return false;
|
||||
if (bit) {
|
||||
if (!_bs.read(1, bit))
|
||||
return false;
|
||||
val = bit ? -1 : 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class BitStream>
|
||||
bool HuffmanStream<BitStream>::read(int bits, quint32 &val)
|
||||
{
|
||||
if (_symbolDataSize < (quint32)bits) {
|
||||
quint32 next;
|
||||
quint8 nextSize = qMin((quint64)(32 - _symbolDataSize),
|
||||
_bs.bitsAvailable());
|
||||
|
||||
if (!_bs.read(nextSize, next))
|
||||
return false;
|
||||
|
||||
_symbolData = (_symbolData << nextSize) | next;
|
||||
_symbolDataSize += nextSize;
|
||||
}
|
||||
|
||||
if (_symbolDataSize < (quint32)bits)
|
||||
return false;
|
||||
|
||||
val = (_symbolData << (32-_symbolDataSize)) >> (32 - bits);
|
||||
_symbolDataSize -= bits;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class BitStream>
|
||||
bool HuffmanStream<BitStream>::readSymbol(quint32 &symbol)
|
||||
{
|
||||
quint8 size;
|
||||
quint32 next;
|
||||
quint8 nextSize = qMin((quint64)(32 - _symbolDataSize), _bs.bitsAvailable());
|
||||
|
||||
if (!_bs.read(nextSize, next))
|
||||
return false;
|
||||
|
||||
_symbolData = (_symbolData << nextSize) | next;
|
||||
_symbolDataSize += nextSize;
|
||||
|
||||
symbol = _table.symbol(_symbolData << (32 - _symbolDataSize), size);
|
||||
if (size > _symbolDataSize)
|
||||
return false;
|
||||
|
||||
_symbolDataSize -= size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class BitStream>
|
||||
bool HuffmanStream<BitStream>::readDelta(int sign, qint32 &delta)
|
||||
{
|
||||
quint32 symbol;
|
||||
if (!readSymbol(symbol))
|
||||
return false;
|
||||
|
||||
if (symbol && !sign) {
|
||||
if (!_symbolDataSize)
|
||||
return false;
|
||||
else {
|
||||
sign = ((1U << (_symbolDataSize - 1)) & _symbolData) ? -1 : 1;
|
||||
_symbolDataSize--;
|
||||
}
|
||||
}
|
||||
delta = sign * symbol;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
class HuffmanStreamF : public HuffmanStream<BitStream4F> {
|
||||
public:
|
||||
HuffmanStreamF(BitStream4F &bitstream, const HuffmanTable &table)
|
||||
: HuffmanStream(bitstream, table) {}
|
||||
|
||||
bool init(bool line);
|
||||
bool readOffset(qint32 &lonDelta, qint32 &latDelta)
|
||||
{return (readDelta(1, lonDelta) && readDelta(1, latDelta));}
|
||||
};
|
||||
|
||||
class HuffmanStreamR : public HuffmanStream<BitStream4R> {
|
||||
public:
|
||||
HuffmanStreamR(BitStream4R &bitstream, const HuffmanTable &table)
|
||||
: HuffmanStream(bitstream, table) {}
|
||||
|
||||
bool init();
|
||||
bool init(int lonSign, int latSign, quint32 data, quint32 dataSize);
|
||||
};
|
||||
|
||||
#endif // HUFFMANSTREAM_H
|
||||
|
@ -42,6 +42,8 @@ bool HuffmanTable::load(const SubFile &file, SubFile::Handle &hdl,
|
||||
_s10 = _s14 + _s1c * _s1d;
|
||||
_s18 = _s10 + (_s1 << _s0);
|
||||
|
||||
_id = id;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -55,7 +57,7 @@ bool HuffmanTable::getBuffer(const SubFile &file, SubFile::Handle &hdl,
|
||||
return false;
|
||||
if (!file.readVUInt32(hdl, recordSize))
|
||||
return false;
|
||||
recordOffset = hdl.pos() + recordSize;
|
||||
recordOffset = file.pos(hdl) + recordSize;
|
||||
if (recordOffset > offset + size)
|
||||
return false;
|
||||
};
|
||||
|
@ -13,6 +13,8 @@ public:
|
||||
quint8 maxSymbolSize() const {return _s2;}
|
||||
quint32 symbol(quint32 data, quint8 &size) const;
|
||||
|
||||
quint8 id() const {return _id;}
|
||||
|
||||
private:
|
||||
bool getBuffer(const SubFile &file, SubFile::Handle &hdl, quint32 offset,
|
||||
quint32 size, quint8 id);
|
||||
@ -22,6 +24,8 @@ private:
|
||||
quint8 *_s10, *_s14, *_s18;
|
||||
quint8 _s1c, _s1d, _s1e, _s1f, _s20;
|
||||
quint16 _s22;
|
||||
|
||||
quint8 _id;
|
||||
};
|
||||
|
||||
#endif // HUFFMANTABLE_H
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include <QMap>
|
||||
#include <QtEndian>
|
||||
#include "map/osm.h"
|
||||
#include "vectortile.h"
|
||||
#include "img.h"
|
||||
|
||||
@ -60,7 +59,7 @@ IMG::IMG(const QString &fileName) : _file(fileName)
|
||||
|
||||
QByteArray nba(QByteArray(d1, sizeof(d1)) + QByteArray(d2, sizeof(d2)));
|
||||
_name = QString::fromLatin1(nba.constData(), nba.size()-1).trimmed();
|
||||
_blockSize = 1 << (e1 + e2);
|
||||
_blockBits = e1 + e2;
|
||||
|
||||
// Read the FAT table
|
||||
quint8 flag;
|
||||
@ -133,7 +132,6 @@ IMG::IMG(const QString &fileName) : _file(fileName)
|
||||
}
|
||||
|
||||
// Create tile tree
|
||||
|
||||
int minMapZoom = 24;
|
||||
for (TileMap::const_iterator it = tileMap.constBegin();
|
||||
it != tileMap.constEnd(); ++it) {
|
||||
@ -160,19 +158,19 @@ IMG::IMG(const QString &fileName) : _file(fileName)
|
||||
minMapZoom = tile->zooms().min();
|
||||
}
|
||||
|
||||
for (TileMap::const_iterator it = tileMap.constBegin();
|
||||
it != tileMap.constEnd(); ++it) {
|
||||
VectorTile *tile = it.value();
|
||||
// Detect and mark basemap
|
||||
TileTree::Iterator it;
|
||||
for (_tileTree.GetFirst(it); !_tileTree.IsNull(it); _tileTree.GetNext(it)) {
|
||||
VectorTile *tile = _tileTree.GetAt(it);
|
||||
if (tile->zooms().min() > minMapZoom)
|
||||
_baseMap = true;
|
||||
if (tile->zooms().min() == minMapZoom)
|
||||
tile->markAsBasemap();
|
||||
}
|
||||
|
||||
// Limit world maps bounds so that the maps can be projected using
|
||||
// the default Web Mercator projection
|
||||
if (_bounds.height() > 120)
|
||||
_bounds &= OSM::BOUNDS;
|
||||
// Allow some extra zoom out on maps without basemaps, but not too much as
|
||||
// this would kill the rendering performance
|
||||
if (!_baseMap)
|
||||
_zooms.setMin(_zooms.min() - 2);
|
||||
|
||||
if (!_tileTree.Count())
|
||||
_errorString = "No usable map tile found";
|
||||
@ -203,9 +201,9 @@ template<class T> bool IMG::readValue(T &val)
|
||||
|
||||
bool IMG::readBlock(int blockNum, char *data)
|
||||
{
|
||||
if (!_file.seek((qint64)blockNum * (qint64)_blockSize))
|
||||
if (!_file.seek((quint64)blockNum << _blockBits))
|
||||
return false;
|
||||
if (read(data, _blockSize) < _blockSize)
|
||||
if (read(data, 1U<<_blockBits) < 1U<<_blockBits)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -14,14 +14,14 @@ public:
|
||||
private:
|
||||
friend class SubFile;
|
||||
|
||||
int blockSize() const {return _blockSize;}
|
||||
unsigned blockBits() const {return _blockBits;}
|
||||
bool readBlock(int blockNum, char *data);
|
||||
qint64 read(char *data, qint64 maxSize);
|
||||
template<class T> bool readValue(T &val);
|
||||
|
||||
QFile _file;
|
||||
quint8 _key;
|
||||
int _blockSize;
|
||||
unsigned _blockBits;
|
||||
};
|
||||
|
||||
#endif // IMG_H
|
||||
|
@ -151,7 +151,9 @@ Label LBLFile::label8b(Handle &hdl, quint32 offset, bool capitalize) const
|
||||
if (!c || c == 0x1d)
|
||||
break;
|
||||
|
||||
if ((c >= 0x1e && c <= 0x1f)) {
|
||||
if (c == 0x1c)
|
||||
capitalize = false;
|
||||
else if ((c >= 0x1e && c <= 0x1f)) {
|
||||
if (bap == &shieldLabel)
|
||||
bap = &label;
|
||||
else
|
||||
@ -159,7 +161,7 @@ Label LBLFile::label8b(Handle &hdl, quint32 offset, bool capitalize) const
|
||||
} else if (c <= 0x07) {
|
||||
shieldType = static_cast<Label::Shield::Type>(c);
|
||||
bap = &shieldLabel;
|
||||
} else if (bap == &shieldLabel && QChar(c).isSpace()) {
|
||||
} else if (bap == &shieldLabel && c == 0x20) {
|
||||
bap = &label;
|
||||
} else
|
||||
bap->append(c);
|
||||
|
@ -54,7 +54,7 @@ inline bool pointCb(VectorTile *tile, void *context)
|
||||
}
|
||||
|
||||
|
||||
MapData::MapData() : _typ(0), _style(0), _zooms(15, 28), _baseMap(false),
|
||||
MapData::MapData() : _typ(0), _style(0), _zooms(24, 28), _baseMap(false),
|
||||
_valid(false)
|
||||
{
|
||||
_polyCache.setMaxCost(CACHED_SUBDIVS_COUNT);
|
||||
|
@ -38,7 +38,6 @@ public:
|
||||
Coordinates coordinates;
|
||||
Label label;
|
||||
quint32 type;
|
||||
bool poi;
|
||||
quint64 id;
|
||||
|
||||
bool operator<(const Point &other) const
|
||||
@ -95,8 +94,7 @@ private:
|
||||
#ifndef QT_NO_DEBUG
|
||||
inline QDebug operator<<(QDebug dbg, const MapData::Point &point)
|
||||
{
|
||||
dbg.nospace() << "Point(" << hex << point.type << ", " << point.label
|
||||
<< ", " << point.poi << ")";
|
||||
dbg.nospace() << "Point(" << hex << point.type << ", " << point.label << ")";
|
||||
return dbg.space();
|
||||
}
|
||||
|
||||
|
@ -1,26 +1,507 @@
|
||||
#include "bitstream.h"
|
||||
#include "huffmanstream.h"
|
||||
#include "subdiv.h"
|
||||
#include "nodfile.h"
|
||||
#include "lblfile.h"
|
||||
#include "netfile.h"
|
||||
|
||||
|
||||
static bool readAdjCounts(BitStream4R &bs, QVector<quint16> &cnts, quint16 &mask)
|
||||
{
|
||||
quint32 val, cnt, bits;
|
||||
if (!bs.read(4, val))
|
||||
return false;
|
||||
|
||||
cnt = ((val >> 2) & 3) + 2;
|
||||
bits = ((val * 2) & 6) + 4;
|
||||
mask = 1<<(3 + ((val * 2) & 6));
|
||||
if (cnt == 5) {
|
||||
if (!bs.read(8, cnt))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cnt < 2)
|
||||
return false;
|
||||
cnts.resize(cnt - 1);
|
||||
for (int i = 0; i < cnts.size(); i++)
|
||||
if (!bs.read(bits, cnts[i]))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool skipShape(BitStream4R &bs)
|
||||
{
|
||||
quint32 v1, v2, v2b;
|
||||
|
||||
if (!bs.readVuint32SM(v1, v2, v2b))
|
||||
return false;
|
||||
|
||||
return bs.skip(v1);
|
||||
}
|
||||
|
||||
static bool skipAdjShapes(BitStream4R &bs, const QVector<quint16> &cnts,
|
||||
quint16 mask, bool firstIsShape)
|
||||
{
|
||||
if (firstIsShape && !skipShape(bs))
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < cnts.size(); i++) {
|
||||
if (cnts.at(i) & mask) {
|
||||
if (!skipShape(bs))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool seekToLevel(BitStream4R &bs, quint8 level)
|
||||
{
|
||||
quint32 v1, v2, v2b;
|
||||
|
||||
for (quint8 i = 1; i < level; ) {
|
||||
if (!bs.readVuint32SM(v1, v2, v2b))
|
||||
return false;
|
||||
if (!bs.skip(v1))
|
||||
return false;
|
||||
|
||||
if (v2 & 2)
|
||||
return false;
|
||||
if (v2 & 1)
|
||||
i++;
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool seekToLine(BitStream4R &bs, quint8 line)
|
||||
{
|
||||
quint32 v1, v2, v2b;
|
||||
|
||||
for (quint8 i = 0; i < line; i++) {
|
||||
if (!bs.readVuint32SM(v1, v2, v2b))
|
||||
return false;
|
||||
if (!bs.skip(v1))
|
||||
return false;
|
||||
|
||||
if (v2 & 2)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool readLine(BitStream4R &bs, const SubDiv *subdiv,
|
||||
const HuffmanTable &table, IMG::Poly &poly)
|
||||
{
|
||||
quint32 v1, v2, v2b;
|
||||
if (!bs.readVuint32SM(v1, v2, v2b))
|
||||
return false;
|
||||
bs.resize(v1);
|
||||
|
||||
quint32 lon, lat;
|
||||
if (!(bs.read(0x12 - v2b, lon) && bs.read(16, lat)))
|
||||
return false;
|
||||
if (2 < v2b)
|
||||
lon |= (v2 >> 2) << (0x12U - v2b);
|
||||
|
||||
QPoint pos = QPoint(LS(subdiv->lon(), 8) + LS((qint16)lon, 32-subdiv->bits()),
|
||||
LS(subdiv->lat(), 8) + LS((qint16)lat, 32-subdiv->bits()));
|
||||
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
|
||||
|
||||
poly.boundingRect = RectC(c, c);
|
||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||
|
||||
HuffmanStreamR stream(bs, table);
|
||||
if (!stream.init())
|
||||
return false;
|
||||
qint32 lonDelta, latDelta;
|
||||
|
||||
while (stream.readNext(lonDelta, latDelta)) {
|
||||
pos.rx() += LS(lonDelta, 32-subdiv->bits());
|
||||
if (pos.rx() < 0 && subdiv->lon() >= 0)
|
||||
pos.rx() = 0x7fffffff;
|
||||
pos.ry() += LS(latDelta, 32-subdiv->bits());
|
||||
|
||||
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
|
||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||
poly.boundingRect = poly.boundingRect.united(c);
|
||||
}
|
||||
|
||||
return stream.atEnd();
|
||||
}
|
||||
|
||||
static bool readNodeGeometry(NODFile *nod, SubFile::Handle &nodHdl,
|
||||
NODFile::AdjacencyInfo &adj, IMG::Poly &poly, quint16 cnt = 0xFFFF)
|
||||
{
|
||||
for (int i = 0; i <= cnt; i++) {
|
||||
int ret = nod->nextNode(nodHdl, adj);
|
||||
if (ret < 0)
|
||||
return false;
|
||||
else if (ret > 0)
|
||||
return (cnt == 0xFFFF);
|
||||
|
||||
Coordinates c(toWGS32(adj.nodeInfo.pos.x()),
|
||||
toWGS32(adj.nodeInfo.pos.y()));
|
||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||
poly.boundingRect = poly.boundingRect.united(c);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool skipNodes(NODFile *nod, SubFile::Handle &nodHdl,
|
||||
NODFile::AdjacencyInfo &adj, int cnt)
|
||||
{
|
||||
for (int i = 0; i < cnt; i++)
|
||||
if (nod->nextNode(nodHdl, adj))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool readShape(NODFile *nod, SubFile::Handle &nodHdl,
|
||||
NODFile::AdjacencyInfo &adj, BitStream4R &bs, const HuffmanTable &table,
|
||||
const SubDiv *subdiv, quint32 shift, IMG::Poly &poly, quint16 cnt = 0xFFFF,
|
||||
bool check = false)
|
||||
{
|
||||
quint32 v1, v2, v2b;
|
||||
if (!bs.readVuint32SM(v1, v2, v2b))
|
||||
return false;
|
||||
BitStream4R::State state;
|
||||
bs.save(state);
|
||||
bs.resize(v1);
|
||||
|
||||
quint32 flags;
|
||||
if (!bs.read(8, flags))
|
||||
return false;
|
||||
flags |= (v2 << 8);
|
||||
|
||||
bool hasCoordinatesAdjustBit = flags & (1 << (v2b + 7));
|
||||
bool useEosBit = flags & (1 << (v2b + 5));
|
||||
bool startWithStream = flags & (1 << (v2b + 6));
|
||||
|
||||
quint32 extraBits;
|
||||
int lonSign, latSign;
|
||||
|
||||
if ((flags >> (v2b + 4) & 1) == 0) {
|
||||
extraBits = v2b + 4;
|
||||
lonSign = 0;
|
||||
} else {
|
||||
extraBits = v2b + 3;
|
||||
lonSign = 1;
|
||||
if ((flags >> (v2b + 3) & 1) != 0) {
|
||||
lonSign = -1;
|
||||
}
|
||||
}
|
||||
extraBits -= 1;
|
||||
if ((flags >> extraBits & 1) == 0) {
|
||||
latSign = 0;
|
||||
} else {
|
||||
extraBits -= 1;
|
||||
latSign = -1;
|
||||
if ((flags >> extraBits & 1) == 0) {
|
||||
latSign = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (nod->nextNode(nodHdl, adj))
|
||||
return false;
|
||||
QPoint pos(adj.nodeInfo.pos);
|
||||
quint16 nodes = 0;
|
||||
|
||||
if (!startWithStream) {
|
||||
Coordinates c(toWGS32(adj.nodeInfo.pos.x()),
|
||||
toWGS32(adj.nodeInfo.pos.y()));
|
||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||
poly.boundingRect = poly.boundingRect.united(c);
|
||||
|
||||
while (!adj.eog) {
|
||||
int ret = nod->nextNode(nodHdl, adj);
|
||||
if (ret < 0)
|
||||
return false;
|
||||
else if (ret > 0)
|
||||
break;
|
||||
nodes++;
|
||||
|
||||
c = Coordinates(toWGS32(adj.nodeInfo.pos.x()),
|
||||
toWGS32(adj.nodeInfo.pos.y()));
|
||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||
poly.boundingRect = poly.boundingRect.united(c);
|
||||
pos = adj.nodeInfo.pos;
|
||||
}
|
||||
}
|
||||
|
||||
HuffmanStreamR stream(bs, table);
|
||||
if (!stream.init(lonSign, latSign, flags, extraBits))
|
||||
return false;
|
||||
qint32 lonDelta, latDelta;
|
||||
QVector<QPoint> deltas;
|
||||
|
||||
quint32 adjustBit = 0;
|
||||
quint32 stepsCnt = 0;
|
||||
quint32 steps = 0;
|
||||
quint32 eos = 0;
|
||||
|
||||
while (true) {
|
||||
if ((stepsCnt == steps) && !useEosBit) {
|
||||
if (!stream.readSymbol(steps))
|
||||
break;
|
||||
if (!steps)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!stream.readNext(lonDelta, latDelta))
|
||||
break;
|
||||
|
||||
if (hasCoordinatesAdjustBit && !stream.read(1, adjustBit))
|
||||
return false;
|
||||
|
||||
stepsCnt++;
|
||||
|
||||
if (useEosBit) {
|
||||
if (!stream.read(1, eos))
|
||||
return false;
|
||||
} else {
|
||||
if (steps == stepsCnt)
|
||||
eos = 1;
|
||||
}
|
||||
|
||||
if (!startWithStream) {
|
||||
pos.rx() += LS(lonDelta, 32-subdiv->bits()-shift);
|
||||
pos.ry() += LS(latDelta, 32-subdiv->bits()-shift);
|
||||
|
||||
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
|
||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||
poly.boundingRect = poly.boundingRect.united(c);
|
||||
} else {
|
||||
deltas.append(QPoint(lonDelta, latDelta));
|
||||
poly.points.append(QPointF());
|
||||
}
|
||||
|
||||
if (startWithStream && eos) {
|
||||
for (int i = deltas.size() - 1, j = 0; i >= 0; i--, j++) {
|
||||
pos.rx() -= LS(deltas.at(i).x(), 32-subdiv->bits()-shift);
|
||||
pos.ry() -= LS(deltas.at(i).y(), 32-subdiv->bits()-shift);
|
||||
|
||||
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
|
||||
poly.points[poly.points.size() - 1 - j] = QPointF(c.lon(), c.lat());
|
||||
poly.boundingRect = poly.boundingRect.united(c);
|
||||
}
|
||||
|
||||
pos = adj.nodeInfo.pos;
|
||||
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
|
||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||
poly.boundingRect = poly.boundingRect.united(c);
|
||||
|
||||
stepsCnt = 0;
|
||||
steps = 0;
|
||||
startWithStream = false;
|
||||
|
||||
if (adj.eog)
|
||||
eos = 0;
|
||||
}
|
||||
|
||||
if (eos) {
|
||||
if (nodes >= cnt)
|
||||
break;
|
||||
|
||||
do {
|
||||
int ret = nod->nextNode(nodHdl, adj);
|
||||
if (ret < 0)
|
||||
return false;
|
||||
else if (ret > 0)
|
||||
break;
|
||||
nodes++;
|
||||
|
||||
if (check && nodes == cnt) {
|
||||
if (!(bs.restore(state) && bs.skip(v1)
|
||||
&& bs.readVuint32SM(v1, v2, v2b)))
|
||||
return false;
|
||||
if (5 < v2b)
|
||||
v2 >>= v2b - 2;
|
||||
if (v2 & 1)
|
||||
break;
|
||||
}
|
||||
|
||||
Coordinates c(toWGS32(adj.nodeInfo.pos.x()),
|
||||
toWGS32(adj.nodeInfo.pos.y()));
|
||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||
poly.boundingRect = poly.boundingRect.united(c);
|
||||
pos = adj.nodeInfo.pos;
|
||||
} while (!adj.eog && nodes < cnt);
|
||||
|
||||
if (nodes == cnt)
|
||||
break;
|
||||
|
||||
steps = 0;
|
||||
stepsCnt = 0;
|
||||
eos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool NETFile::linkLabel(Handle &hdl, quint32 offset, quint32 size, LBLFile *lbl,
|
||||
Handle &lblHdl, Label &label)
|
||||
{
|
||||
if (!seek(hdl, offset))
|
||||
return false;
|
||||
BitStream1 bs(*this, hdl, size);
|
||||
|
||||
quint32 flags, labelPtr;
|
||||
if (!bs.read(8, flags))
|
||||
return false;
|
||||
if (!(flags & 1))
|
||||
return true;
|
||||
|
||||
if (!bs.readUInt24(labelPtr))
|
||||
return false;
|
||||
if (labelPtr & 0x3FFFFF) {
|
||||
if (labelPtr & 0x400000) {
|
||||
quint32 lblOff;
|
||||
if (lblOffset(hdl, labelPtr & 0x3FFFFF, lblOff) && lblOff)
|
||||
label = lbl->label(lblHdl, lblOff);
|
||||
} else
|
||||
label = lbl->label(lblHdl, labelPtr & 0x3FFFFF);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NETFile::init(Handle &hdl)
|
||||
{
|
||||
quint8 multiplier;
|
||||
quint16 hdrLen;
|
||||
|
||||
if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)
|
||||
&& seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset)
|
||||
&& readUInt32(hdl, _size) && readUInt8(hdl, multiplier)))
|
||||
&& readUInt32(hdl, _size) && readUInt8(hdl, _shift)))
|
||||
return false;
|
||||
|
||||
_multiplier = 1<<multiplier;
|
||||
if (hdrLen >= 0x47) {
|
||||
quint32 info;
|
||||
if (!(seek(hdl, _gmpOffset + 0x37) && readUInt32(hdl, info)))
|
||||
return false;
|
||||
_tableId = ((info >> 2) & 0xF);
|
||||
|
||||
if (!(seek(hdl, _gmpOffset + 0x43) && readUInt32(hdl, _linksOffset)
|
||||
&& readUInt32(hdl, _linksSize) && readUInt8(hdl, _linksShift)))
|
||||
return false;
|
||||
}
|
||||
|
||||
_init = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NETFile::link(const SubDiv *subdiv, quint32 shift, Handle &hdl,
|
||||
NODFile *nod, Handle &nodHdl, LBLFile *lbl, Handle &lblHdl,
|
||||
const NODFile::BlockInfo &blockInfo, quint8 linkId, quint8 lineId,
|
||||
const HuffmanTable &table, QList<IMG::Poly> *lines)
|
||||
{
|
||||
if (!_init && !init(hdl))
|
||||
return false;
|
||||
|
||||
Q_ASSERT(_tableId == table.id());
|
||||
if (_tableId != table.id())
|
||||
return false;
|
||||
|
||||
IMG::Poly poly;
|
||||
if (!nod->linkType(nodHdl, blockInfo, linkId, poly.type))
|
||||
return false;
|
||||
|
||||
NODFile::LinkInfo linkInfo;
|
||||
if (!nod->linkInfo(nodHdl, blockInfo, linkId, linkInfo))
|
||||
return false;
|
||||
|
||||
quint32 linkOffset = _linksOffset + (linkInfo.linkOffset << _linksShift);
|
||||
if (linkOffset > _linksOffset + _linksSize)
|
||||
return false;
|
||||
if (!seek(hdl, linkOffset))
|
||||
return false;
|
||||
BitStream4R bs(*this, hdl, linkOffset - _linksOffset);
|
||||
QVector<quint16> ca;
|
||||
quint16 mask = 0;
|
||||
quint32 size;
|
||||
|
||||
quint8 s68 = (linkInfo.flags >> 0x12) & 1;
|
||||
quint8 s69 = (linkInfo.flags >> 0x11) & 1;
|
||||
quint8 s6a = (linkInfo.flags >> 0x13) & 1;
|
||||
|
||||
if (s69 == 0 || s6a == 1) {
|
||||
if (!bs.readVUInt32(size))
|
||||
return false;
|
||||
}
|
||||
if (s69 == 0) {
|
||||
if (!readAdjCounts(bs, ca, mask))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!subdiv->level()) {
|
||||
NODFile::AdjacencyInfo adj(nod, blockInfo, linkId, linkInfo);
|
||||
|
||||
if (s69 == 1) {
|
||||
if (s68 == 1) {
|
||||
if (!readShape(nod, nodHdl, adj, bs, table, subdiv, shift, poly))
|
||||
return false;
|
||||
} else {
|
||||
if (!readNodeGeometry(nod, nodHdl, adj, poly))
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
quint16 mask2 = mask + 0xffff;
|
||||
for (int i = 0; i <= ca.size(); i++) {
|
||||
quint16 step = (i < ca.size()) ? ca.at(i) & mask2 : 0xFFFF;
|
||||
bool shape = (i > 0) ? ca.at(i-1) & mask : (s68 == 1);
|
||||
if (i == lineId) {
|
||||
if (shape) {
|
||||
bool check = (i < ca.size()) ? (ca.at(i) & mask) : false;
|
||||
if (!readShape(nod, nodHdl, adj, bs, table, subdiv,
|
||||
shift, poly, step, check))
|
||||
return false;
|
||||
} else {
|
||||
if (!readNodeGeometry(nod, nodHdl, adj, poly, step))
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (shape && !skipShape(bs))
|
||||
return false;
|
||||
if (!skipNodes(nod, nodHdl, adj, step))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!skipAdjShapes(bs, ca, mask, s68 == 1))
|
||||
return false;
|
||||
|
||||
if (!seekToLevel(bs, subdiv->level()))
|
||||
return false;
|
||||
if (!seekToLine(bs, lineId))
|
||||
return false;
|
||||
if (!readLine(bs, subdiv, table, poly))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lbl)
|
||||
linkLabel(hdl, linkOffset, _linksSize - (linkOffset - _linksOffset),
|
||||
lbl, lblHdl, poly.label);
|
||||
|
||||
lines->append(poly);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NETFile::lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset)
|
||||
{
|
||||
if (!_multiplier && !init(hdl))
|
||||
if (!_init && !init(hdl))
|
||||
return false;
|
||||
|
||||
if (!(seek(hdl, _offset + netOffset * _multiplier)
|
||||
if (!(seek(hdl, _offset + (netOffset << _shift))
|
||||
&& readUInt24(hdl, lblOffset)))
|
||||
return false;
|
||||
|
||||
|
@ -1,25 +1,42 @@
|
||||
#ifndef NETFILE_H
|
||||
#define NETFILE_H
|
||||
|
||||
#include "img.h"
|
||||
#include "subfile.h"
|
||||
#include "nodfile.h"
|
||||
|
||||
class NODFile;
|
||||
class LBLFile;
|
||||
class SubDiv;
|
||||
class HuffmanTable;
|
||||
|
||||
class NETFile : public SubFile
|
||||
{
|
||||
public:
|
||||
NETFile(IMG *img)
|
||||
: SubFile(img), _offset(0), _size(0), _multiplier(0) {}
|
||||
NETFile(const QString &path)
|
||||
: SubFile(path), _offset(0), _size(0), _multiplier(0) {}
|
||||
NETFile(SubFile *gmp, quint32 offset)
|
||||
: SubFile(gmp, offset), _offset(0), _size(0), _multiplier(0) {}
|
||||
NETFile(IMG *img) : SubFile(img), _offset(0), _size(0), _linksOffset(0),
|
||||
_linksSize(0), _shift(0), _linksShift(0), _init(false) {}
|
||||
NETFile(const QString &path) : SubFile(path), _offset(0), _size(0),
|
||||
_linksOffset(0), _linksSize(0), _shift(0), _linksShift(0),
|
||||
_init(false) {}
|
||||
NETFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
|
||||
_offset(0), _size(0), _linksOffset(0), _linksSize(0), _shift(0),
|
||||
_linksShift(0), _init(false) {}
|
||||
|
||||
bool lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset);
|
||||
bool link(const SubDiv *subdiv, quint32 shift, Handle &hdl, NODFile *nod,
|
||||
Handle &nodHdl, LBLFile *lbl, Handle &lblHdl,
|
||||
const NODFile::BlockInfo &blockInfo, quint8 linkId, quint8 lineId,
|
||||
const HuffmanTable &table, QList<IMG::Poly> *lines);
|
||||
|
||||
private:
|
||||
bool init(Handle &hdl);
|
||||
bool linkLabel(Handle &hdl, quint32 offset, quint32 size, LBLFile *lbl,
|
||||
Handle &lblHdl, Label &label);
|
||||
|
||||
quint32 _offset, _size;
|
||||
quint8 _multiplier;
|
||||
quint32 _offset, _size, _linksOffset, _linksSize;
|
||||
quint8 _shift, _linksShift;
|
||||
quint8 _tableId;
|
||||
bool _init;
|
||||
};
|
||||
|
||||
#endif // NETFILE_H
|
||||
|
553
src/map/IMG/nodfile.cpp
Normal file
@ -0,0 +1,553 @@
|
||||
#include "bitstream.h"
|
||||
#include "nodfile.h"
|
||||
|
||||
|
||||
#define ARRAY_SIZE(array) \
|
||||
(sizeof(array) / sizeof(array[0]))
|
||||
|
||||
static const struct
|
||||
{
|
||||
quint8 lon;
|
||||
quint8 lat;
|
||||
} LLBITS[] = {
|
||||
{0xc, 0xc}, {0x8, 0x10}, {0x10, 0x8}, {0x10, 0x10}, {0xc, 0x14},
|
||||
{0x14, 0xc}, {0x14, 0x14}
|
||||
};
|
||||
|
||||
struct NodeOffset
|
||||
{
|
||||
bool ext;
|
||||
union {
|
||||
qint32 offset;
|
||||
quint8 id;
|
||||
} u;
|
||||
};
|
||||
|
||||
static bool adjDistInfo(BitStream1 &bs, bool extraBit, bool &eog)
|
||||
{
|
||||
quint32 data, cnt;
|
||||
|
||||
if (!bs.read(extraBit | 8, data))
|
||||
return false;
|
||||
|
||||
data <<= !extraBit;
|
||||
eog |= (quint8)data & 1;
|
||||
data >>= 1;
|
||||
|
||||
for (cnt = 0; (data >> cnt) & 1; cnt++) {
|
||||
if (cnt == 4)
|
||||
break;
|
||||
}
|
||||
if (!bs.read(cnt * 4, data))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool adjNodeInfo(BitStream1 &bs, bool extraBit, NodeOffset &offset)
|
||||
{
|
||||
quint32 data;
|
||||
|
||||
if (!bs.read(9, data))
|
||||
return false;
|
||||
|
||||
data <<= !extraBit;
|
||||
|
||||
if (data & 1) {
|
||||
offset.ext = true;
|
||||
offset.u.id = data >> 1;
|
||||
} else {
|
||||
quint32 bits = (data >> 1) & 7;
|
||||
quint32 data2;
|
||||
|
||||
if (!bs.read(bits + extraBit + 1, data2))
|
||||
return false;
|
||||
|
||||
data = data2 << (6 - extraBit) | data >> 4;
|
||||
bits = 0x19 - bits;
|
||||
offset.ext = false;
|
||||
offset.u.offset = ((qint32)(data << bits) >> bits);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool skipOptAdjData(BitStream1 &bs)
|
||||
{
|
||||
// TODO
|
||||
Q_UNUSED(bs);
|
||||
Q_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool NODFile::init(Handle &hdl)
|
||||
{
|
||||
quint16 hdrLen;
|
||||
|
||||
if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)))
|
||||
return false;
|
||||
if (hdrLen < 0x7b)
|
||||
return false;
|
||||
|
||||
if (!(seek(hdl, _gmpOffset + 0x1d) && readUInt32(hdl, _flags)
|
||||
&& readUInt8(hdl, _blockShift) && readUInt8(hdl, _nodeShift)))
|
||||
return false;
|
||||
|
||||
if (!(seek(hdl, _gmpOffset + 0x67) && readUInt32(hdl, _blockOffset)
|
||||
&& readUInt32(hdl, _blockSize) && readUInt16(hdl, _blockRecordSize)
|
||||
&& readUInt32(hdl, _indexOffset) && readUInt32(hdl, _indexSize)
|
||||
&& readUInt16(hdl, _indexRecordSize) && readUInt32(hdl, _indexFlags)))
|
||||
return false;
|
||||
|
||||
if (!_indexRecordSize)
|
||||
return false;
|
||||
quint32 indexCount = _indexSize / _indexRecordSize;
|
||||
if (indexCount <= 0x100)
|
||||
_indexIdSize = 1;
|
||||
else if (indexCount <= 0x1000)
|
||||
_indexIdSize = 2;
|
||||
else if (indexCount <= 0x1000000)
|
||||
_indexIdSize = 3;
|
||||
|
||||
return (_indexIdSize > 0);
|
||||
}
|
||||
|
||||
quint32 NODFile::indexIdSize(Handle &hdl)
|
||||
{
|
||||
if (!_indexIdSize && !init(hdl))
|
||||
return 0;
|
||||
|
||||
return _indexIdSize;
|
||||
}
|
||||
|
||||
bool NODFile::readBlock(Handle &hdl, quint32 blockOffset,
|
||||
BlockInfo &blockInfo) const
|
||||
{
|
||||
blockInfo.offset = blockOffset;
|
||||
|
||||
if (!(seek(hdl, blockInfo.offset + _blockOffset)
|
||||
&& readUInt16(hdl, blockInfo.hdr.s0) && readUInt32(hdl, blockInfo.hdr.s2)
|
||||
&& readUInt32(hdl, blockInfo.hdr.s6) && readUInt32(hdl, blockInfo.hdr.sa)
|
||||
&& readUInt16(hdl, blockInfo.hdr.se) && readUInt8(hdl, blockInfo.hdr.s10)
|
||||
&& readUInt8(hdl, blockInfo.hdr.s11) && readUInt8(hdl, blockInfo.hdr.s12)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NODFile::blockInfo(Handle &hdl, quint32 blockId, BlockInfo &blockInfo) const
|
||||
{
|
||||
quint32 blockOffset;
|
||||
quint32 offset = _indexRecordSize * blockId + _indexOffset;
|
||||
quint32 offsetSize = (_indexFlags & 3) + 1;
|
||||
|
||||
if (offset > _indexOffset + _indexSize)
|
||||
return false;
|
||||
if (!(seek(hdl, offset) && readVUInt32(hdl, offsetSize, blockOffset)))
|
||||
return false;
|
||||
|
||||
return readBlock(hdl, blockOffset << _blockShift, blockInfo);
|
||||
}
|
||||
|
||||
bool NODFile::linkInfo(Handle &hdl, const BlockInfo &blockInfo, quint32 linkId,
|
||||
LinkInfo &linkInfo) const
|
||||
{
|
||||
if (linkId >= blockInfo.hdr.s10)
|
||||
return false;
|
||||
|
||||
quint32 infoOffset = ((blockInfo.hdr.se * linkId) >> 3) + 0x13
|
||||
+ ((blockInfo.hdr.s0 >> 0xb) & 1) + blockInfo.offset + _blockOffset;
|
||||
quint32 s1 = ((blockInfo.hdr.s0 >> 2) & 0x1f) + 8;
|
||||
quint32 s2 = (blockInfo.hdr.s0 >> 7) & 0xf;
|
||||
quint32 skip = (blockInfo.hdr.se * linkId) & 7;
|
||||
|
||||
if (infoOffset > _blockOffset + _blockSize || infoOffset < blockInfo.offset)
|
||||
return false;
|
||||
if (!seek(hdl, infoOffset))
|
||||
return false;
|
||||
|
||||
quint32 unused, flags;
|
||||
BitStream1 bs(*this, hdl, _blockOffset + _blockSize - infoOffset);
|
||||
if (!(bs.read(skip, unused) && bs.read(0xc, flags)))
|
||||
return false;
|
||||
|
||||
linkInfo.flags = ((flags << 8) & 0xf0000) | (flags & 0xff);
|
||||
|
||||
if (!(flags << 8 & 0x10000)) {
|
||||
if (!bs.read(s1, linkInfo.linkOffset))
|
||||
return false;
|
||||
} else {
|
||||
if (!bs.read(s1 - s2, linkInfo.linkOffset))
|
||||
return false;
|
||||
linkInfo.linkOffset += blockInfo.hdr.sa;
|
||||
}
|
||||
|
||||
if (!bs.read(s2, linkInfo.nodeOffset))
|
||||
return false;
|
||||
linkInfo.nodeOffset = (blockInfo.offset - linkInfo.nodeOffset)
|
||||
>> _nodeShift;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NODFile::nodeInfo(Handle &hdl, const BlockInfo &blockInfo,
|
||||
quint32 nodeOffset, NodeInfo &nodeInfo) const
|
||||
{
|
||||
quint32 infoOffset = (nodeOffset << _nodeShift) + _blockOffset;
|
||||
if (infoOffset > _blockOffset + _blockSize || infoOffset < blockInfo.offset)
|
||||
return false;
|
||||
if (!seek(hdl, infoOffset))
|
||||
return false;
|
||||
|
||||
BitStream1 bs(*this, hdl, _blockOffset + _blockSize - infoOffset);
|
||||
|
||||
if (!bs.read(8, nodeInfo.flags))
|
||||
return false;
|
||||
|
||||
if ((nodeInfo.flags & 7) >= ARRAY_SIZE(LLBITS))
|
||||
return false;
|
||||
quint8 lonBits = LLBITS[nodeInfo.flags & 7].lon;
|
||||
quint8 latBits = LLBITS[nodeInfo.flags & 7].lat;
|
||||
quint8 maxBits = ((_flags >> 10) & 7) | 0x18;
|
||||
|
||||
quint32 lon, lat;
|
||||
if (!(bs.read(lonBits, lon) && bs.read(latBits, lat)))
|
||||
return false;
|
||||
|
||||
quint8 lonShift = 0x20 - lonBits;
|
||||
quint8 latShift = 0x20 - latBits;
|
||||
quint8 shift = 0x20 - maxBits;
|
||||
QPoint pos((((int)(lon << lonShift) >> lonShift) << shift)
|
||||
+ blockInfo.hdr.s2, (((int)(lat << latShift) >> latShift) << shift)
|
||||
+ blockInfo.hdr.s6);
|
||||
nodeInfo.bytes = ((lonBits + latBits) >> 3) + 1;
|
||||
|
||||
if ((maxBits < 0x1c) && (nodeInfo.flags & 8)) {
|
||||
quint8 extraBits = 0x1c - maxBits;
|
||||
quint32 extraLon, extraLat;
|
||||
|
||||
if (!(bs.read(extraBits, extraLon) && bs.read(extraBits, extraLat)))
|
||||
return false;
|
||||
pos.setX(pos.x() | extraLon << 4); pos.setY(pos.y() | extraLat << 4);
|
||||
nodeInfo.bytes++;
|
||||
}
|
||||
// TODO?: extra bits
|
||||
|
||||
nodeInfo.pos = pos;
|
||||
nodeInfo.flags &= 0xf8;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NODFile::nodeOffset(Handle &hdl, const BlockInfo &blockInfo,
|
||||
quint8 nodeId, quint32 &nodeOffset) const
|
||||
{
|
||||
if (nodeId >= blockInfo.hdr.s11)
|
||||
return false;
|
||||
|
||||
quint32 offset = ((blockInfo.hdr.s10 * blockInfo.hdr.se + 7) >> 3)
|
||||
+ 0x13 + nodeId * 3 + _blockOffset + blockInfo.offset
|
||||
+ ((blockInfo.hdr.s0 >> 0xb) & 1);
|
||||
|
||||
if (!(seek(hdl, offset) && readUInt24(hdl, nodeOffset)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NODFile::nodeBlock(Handle &hdl, quint32 nodeOffset,
|
||||
BlockInfo &blockInfo) const
|
||||
{
|
||||
int low = 0;
|
||||
int high = _indexSize / _indexRecordSize - 1;
|
||||
quint32 offsetSize = (_indexFlags & 3) + 1;
|
||||
|
||||
while (low <= high) {
|
||||
quint32 m = ((low + high) / 2);
|
||||
quint32 offset = _indexRecordSize * m + _indexOffset;
|
||||
quint32 blockOffset, prevBlockOffset;
|
||||
|
||||
if (m > 0) {
|
||||
if (!(seek(hdl, offset - _indexRecordSize)
|
||||
&& readVUInt32(hdl, offsetSize, prevBlockOffset)
|
||||
&& readVUInt32(hdl, offsetSize, blockOffset)))
|
||||
return false;
|
||||
} else {
|
||||
if (!(seek(hdl, offset)
|
||||
&& readVUInt32(hdl, offsetSize, blockOffset)))
|
||||
return false;
|
||||
prevBlockOffset = 0;
|
||||
}
|
||||
prevBlockOffset <<= _blockShift;
|
||||
blockOffset <<= _blockShift;
|
||||
|
||||
if (blockOffset < nodeOffset)
|
||||
low = m + 1;
|
||||
else {
|
||||
if (prevBlockOffset <= nodeOffset)
|
||||
return readBlock(hdl, blockOffset, blockInfo);
|
||||
else
|
||||
high = m - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NODFile::absAdjInfo(Handle &hdl, AdjacencyInfo &adj) const
|
||||
{
|
||||
quint32 infoOffset = (adj.nodeOffset << _nodeShift) + _blockOffset
|
||||
+ adj.nodeInfo.bytes;
|
||||
if (!seek(hdl, infoOffset))
|
||||
return false;
|
||||
BitStream1 bs(*this, hdl, _blockOffset + _blockSize - infoOffset);
|
||||
|
||||
quint8 linkId = adj.blockInfo.hdr.s10;
|
||||
quint32 m2p = 2;
|
||||
quint32 skip = 8;
|
||||
quint32 flags;
|
||||
quint32 nextOffset = 0xFFFFFFFF;
|
||||
bool extraBit = (adj.nodeInfo.flags >> 6) & 1;
|
||||
bool linkIdValid = true;
|
||||
bool firstLoop = true;
|
||||
NodeOffset offset;
|
||||
|
||||
do {
|
||||
adj.eog = false;
|
||||
|
||||
if (!bs.read(8, flags))
|
||||
return false;
|
||||
|
||||
if (firstLoop) {
|
||||
skip >>= (flags >> 5) & 1;
|
||||
flags |= 0x20;
|
||||
}
|
||||
firstLoop = false;
|
||||
quint32 f4 = flags & 0x10;
|
||||
quint32 f4sn = (f4 >> 4) ^ 1;
|
||||
quint32 m1 = (flags >> 5) & f4sn;
|
||||
quint32 m2 = (f4 >> 3) | (f4sn & (flags >> 6));
|
||||
|
||||
if (m1) {
|
||||
if (!bs.read(8, linkId))
|
||||
return false;
|
||||
linkIdValid = true;
|
||||
}
|
||||
|
||||
if ((m2 != m2p) || (flags & 0x10) || m1) {
|
||||
quint32 data;
|
||||
if (!bs.read(skip, data))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(flags & 0x10)) {
|
||||
if (!adjDistInfo(bs, (m2 == 1 && linkIdValid), adj.eog))
|
||||
return false;
|
||||
|
||||
if (!adjNodeInfo(bs, extraBit, offset))
|
||||
return false;
|
||||
if (!offset.ext)
|
||||
nextOffset = adj.nodeOffset + offset.u.offset;
|
||||
else if (!nodeOffset(adj.extHdl, adj.blockInfo, offset.u.id,
|
||||
nextOffset))
|
||||
return false;
|
||||
|
||||
m2p = m2;
|
||||
}
|
||||
|
||||
if (flags & 0x8) {
|
||||
quint32 data;
|
||||
if (!bs.read(8, data))
|
||||
return false;
|
||||
if (!(data & 0xe0)) {
|
||||
if (!bs.read(8, data))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ((_flags & 0x18) && !skipOptAdjData(bs))
|
||||
return false;
|
||||
|
||||
if ((m2 == 1) && linkIdValid) {
|
||||
LinkInfo li;
|
||||
if (adj.linkId == 0xFFFFFFFF) {
|
||||
if (!linkInfo(adj.extHdl, adj.blockInfo, linkId, li))
|
||||
return false;
|
||||
} else
|
||||
li.linkOffset = 0xFFFFFFFF;
|
||||
|
||||
if ((adj.linkOffset == li.linkOffset) || (adj.linkId == linkId)) {
|
||||
adj.nodeOffset = nextOffset;
|
||||
if (offset.ext) {
|
||||
adj.linkId = 0xFFFFFFFF;
|
||||
return nodeBlock(hdl, adj.nodeOffset << _nodeShift,
|
||||
adj.blockInfo);
|
||||
} else {
|
||||
adj.linkId = linkId;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
linkIdValid = false;
|
||||
}
|
||||
} while (!(flags & 0x80));
|
||||
|
||||
adj.nodeOffset = 0xFFFFFFFF;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NODFile::relAdjInfo(Handle &hdl, AdjacencyInfo &adj) const
|
||||
{
|
||||
quint32 infoOffset = (adj.nodeOffset << _nodeShift) + _blockOffset
|
||||
+ adj.nodeInfo.bytes;
|
||||
if (!seek(hdl, infoOffset))
|
||||
return false;
|
||||
|
||||
BitStream1 bs(*this, hdl, _blockOffset + _blockSize - infoOffset);
|
||||
|
||||
quint32 linkId = adj.blockInfo.hdr.s10;
|
||||
quint32 skip = 8;
|
||||
quint32 flagsBits = 8;
|
||||
quint32 flags;
|
||||
quint32 nextOffset = 0xFFFFFFFF;
|
||||
NodeOffset offset;
|
||||
bool extraBit = (adj.nodeInfo.flags >> 6) & 1;
|
||||
bool linkIdValid = true;
|
||||
bool firstLoop = true;
|
||||
|
||||
do {
|
||||
adj.eog = false;
|
||||
|
||||
if (!bs.read(flagsBits, flags))
|
||||
return false;
|
||||
|
||||
flags <<= (8U - flagsBits);
|
||||
if (firstLoop) {
|
||||
skip >>= (flags >> 5) & 1;
|
||||
flags = ((flags >> 1) & 0x20) | (flags & 0xffffffdf);
|
||||
}
|
||||
firstLoop = false;
|
||||
flagsBits >>= (flags >> 3) & 1;
|
||||
quint32 m = (((flags & 0x70) == 0x30) << 1) | ((flags >> 6) & 1);
|
||||
if (!m) {
|
||||
adj.nodeOffset = 0xFFFFFFFF;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((flags & 0x60) == 0x60) {
|
||||
if (!bs.read(8, linkId))
|
||||
return false;
|
||||
linkIdValid = true;
|
||||
}
|
||||
|
||||
if (((flags & 0x70) == 0x70)) {
|
||||
quint32 data;
|
||||
if (!bs.read(skip, data))
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((flags & 0x50) == 0x50) {
|
||||
if (!adjDistInfo(bs, false, adj.eog))
|
||||
return false;
|
||||
adj.eog = true;
|
||||
}
|
||||
if ((flags >> 6) & 1) {
|
||||
if (!adjNodeInfo(bs, extraBit, offset))
|
||||
return false;
|
||||
if (!offset.ext)
|
||||
nextOffset = adj.nodeOffset + offset.u.offset;
|
||||
else if (!nodeOffset(adj.extHdl, adj.blockInfo, offset.u.id,
|
||||
nextOffset))
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((_flags & 0x18) && !skipOptAdjData(bs))
|
||||
return false;
|
||||
|
||||
if (((m == 1) && linkIdValid)) {
|
||||
LinkInfo li;
|
||||
if (adj.linkId == 0xFFFFFFFF) {
|
||||
if (!linkInfo(adj.extHdl, adj.blockInfo, linkId, li))
|
||||
return false;
|
||||
} else
|
||||
li.linkOffset = 0xFFFFFFFF;
|
||||
|
||||
if ((adj.linkOffset == li.linkOffset) || (adj.linkId == linkId)) {
|
||||
adj.nodeOffset = nextOffset;
|
||||
if (offset.ext) {
|
||||
adj.linkId = 0xFFFFFFFF;
|
||||
return nodeBlock(hdl, adj.nodeOffset << _nodeShift,
|
||||
adj.blockInfo);
|
||||
} else {
|
||||
adj.linkId = linkId;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
linkIdValid = false;
|
||||
}
|
||||
} while (!(flags & 0x80));
|
||||
|
||||
adj.nodeOffset = 0xFFFFFFFF;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int NODFile::nextNode(Handle &hdl, AdjacencyInfo &adjInfo)
|
||||
{
|
||||
if (adjInfo.nodeOffset == 0xFFFFFFFF)
|
||||
return 1;
|
||||
|
||||
if (!nodeInfo(hdl, adjInfo.blockInfo, adjInfo.nodeOffset,
|
||||
adjInfo.nodeInfo))
|
||||
return -1;
|
||||
if (!adjacencyInfo(hdl, adjInfo))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool NODFile::linkType(Handle &hdl, const BlockInfo &blockInfo, quint8 linkId,
|
||||
quint32 &type) const
|
||||
{
|
||||
quint32 offset = ((blockInfo.hdr.s10 * blockInfo.hdr.se + 7) >> 3) + 0x13
|
||||
+ blockInfo.offset + _blockOffset + ((blockInfo.hdr.s0 >> 0xb) & 1)
|
||||
+ blockInfo.hdr.s11 * 3;
|
||||
quint32 low = 0;
|
||||
quint32 high = blockInfo.hdr.s12 - 1;
|
||||
quint32 pos = blockInfo.hdr.s12;
|
||||
quint16 val;
|
||||
|
||||
if (high > 1) {
|
||||
do {
|
||||
pos = (low + high) / 2;
|
||||
|
||||
if (!(seek(hdl, offset + _blockRecordSize * pos)
|
||||
&& readUInt16(hdl, val)))
|
||||
return false;
|
||||
|
||||
if ((val >> 8) <= linkId)
|
||||
low = pos;
|
||||
else
|
||||
high = pos;
|
||||
} while (low + 1 < high);
|
||||
}
|
||||
|
||||
if (!(seek(hdl, offset + _blockRecordSize * low) && readUInt16(hdl, val)))
|
||||
return false;
|
||||
|
||||
type = val & 0x3f;
|
||||
|
||||
if ((low < high) && (pos != high)) {
|
||||
if (!(seek(hdl, offset + _blockRecordSize * high)
|
||||
&& readUInt16(hdl, val)))
|
||||
return false;
|
||||
if ((val >> 8) <= linkId)
|
||||
type = (val & 0x3f);
|
||||
}
|
||||
|
||||
type <<= 8;
|
||||
|
||||
return true;
|
||||
}
|
98
src/map/IMG/nodfile.h
Normal file
@ -0,0 +1,98 @@
|
||||
#ifndef NODFILE_H
|
||||
#define NODFILE_H
|
||||
|
||||
#include "img.h"
|
||||
#include "subfile.h"
|
||||
|
||||
class NODFile : public SubFile
|
||||
{
|
||||
public:
|
||||
struct BlockInfo
|
||||
{
|
||||
quint32 offset;
|
||||
struct
|
||||
{
|
||||
quint32 s2; // node lon base
|
||||
quint32 s6; // node lat base
|
||||
quint32 sa;
|
||||
quint16 s0; // flags
|
||||
quint16 se; // link info bit size
|
||||
quint8 s10; // links count
|
||||
quint8 s11; // nodes count
|
||||
quint8 s12; // link types count
|
||||
} hdr;
|
||||
};
|
||||
|
||||
struct LinkInfo
|
||||
{
|
||||
quint32 linkOffset;
|
||||
quint32 nodeOffset;
|
||||
quint32 flags;
|
||||
};
|
||||
|
||||
struct NodeInfo
|
||||
{
|
||||
QPoint pos;
|
||||
quint8 flags;
|
||||
quint8 bytes;
|
||||
};
|
||||
|
||||
struct AdjacencyInfo
|
||||
{
|
||||
AdjacencyInfo(const SubFile *file, const BlockInfo &blockInfo,
|
||||
quint32 linkId, const LinkInfo &linkInfo) : extHdl(file),
|
||||
blockInfo(blockInfo), nodeOffset(linkInfo.nodeOffset),
|
||||
linkOffset(linkInfo.linkOffset), linkId(linkId)
|
||||
{}
|
||||
|
||||
Handle extHdl;
|
||||
BlockInfo blockInfo;
|
||||
NodeInfo nodeInfo;
|
||||
quint32 nodeOffset;
|
||||
quint32 linkOffset;
|
||||
quint32 linkId;
|
||||
bool eog;
|
||||
};
|
||||
|
||||
NODFile(IMG *img) : SubFile(img), _indexOffset(0), _indexSize(0),
|
||||
_indexFlags(0), _blockOffset(0), _blockSize(0), _indexRecordSize(0),
|
||||
_blockRecordSize(0), _blockShift(0), _nodeShift(0), _indexIdSize(0) {}
|
||||
NODFile(const QString &path) : SubFile(path), _indexOffset(0), _indexSize(0),
|
||||
_indexFlags(0), _blockOffset(0), _blockSize(0), _indexRecordSize(0),
|
||||
_blockRecordSize(0), _blockShift(0), _nodeShift(0), _indexIdSize(0) {}
|
||||
NODFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
|
||||
_indexOffset(0), _indexSize(0), _indexFlags(0), _blockOffset(0),
|
||||
_blockSize(0), _indexRecordSize(0), _blockRecordSize(0), _blockShift(0),
|
||||
_nodeShift(0), _indexIdSize(0) {}
|
||||
|
||||
quint32 indexIdSize(Handle &hdl);
|
||||
bool blockInfo(Handle &hdl, quint32 blockId, BlockInfo &blockInfo) const;
|
||||
bool linkInfo(Handle &hdl, const BlockInfo &blockInfo, quint32 linkId,
|
||||
LinkInfo &linkInfo) const;
|
||||
bool linkType(Handle &hdl, const BlockInfo &blockInfo, quint8 linkId,
|
||||
quint32 &type) const;
|
||||
int nextNode(Handle &hdl, AdjacencyInfo &adjInfo);
|
||||
|
||||
private:
|
||||
bool init(Handle &hdl);
|
||||
bool nodeInfo(Handle &hdl, const BlockInfo &blockInfo, quint32 nodeOffset,
|
||||
NodeInfo &nodeInfo) const;
|
||||
bool nodeOffset(Handle &hdl, const BlockInfo &blockInfo, quint8 nodeId,
|
||||
quint32 &nodeOffset) const;
|
||||
bool absAdjInfo(Handle &hdl, AdjacencyInfo &adj) const;
|
||||
bool relAdjInfo(Handle &hdl, AdjacencyInfo &adj) const;
|
||||
bool adjacencyInfo(Handle &hdl, AdjacencyInfo &adj) const
|
||||
{
|
||||
return (adj.nodeInfo.flags & 0x20) ? absAdjInfo(hdl, adj)
|
||||
: relAdjInfo(hdl, adj);
|
||||
}
|
||||
bool nodeBlock(Handle &hdl, quint32 nodeOffset, BlockInfo &blockInfo) const;
|
||||
bool readBlock(Handle &hdl, quint32 blockOffset, BlockInfo &blockInfo) const;
|
||||
|
||||
quint32 _flags, _indexOffset, _indexSize, _indexFlags, _blockOffset,
|
||||
_blockSize;
|
||||
quint16 _indexRecordSize, _blockRecordSize;
|
||||
quint8 _blockShift, _nodeShift, _indexIdSize;
|
||||
};
|
||||
|
||||
#endif // NETFILE_H
|