Compare commits
174 Commits
Author | SHA1 | Date | |
---|---|---|---|
609e73256a | |||
50c43dc0b7 | |||
b6194d535e | |||
a4906050b8 | |||
d1d0341ce5 | |||
1b27be6173 | |||
2eed9884a5 | |||
afee454b92 | |||
8ade76b9f4 | |||
45ca0f306c | |||
faf445d708 | |||
7ed4821e81 | |||
524a854d35 | |||
800189cec5 | |||
dc209bd96e | |||
d71b9f5e19 | |||
781bc8c38f | |||
a49c2cd7c2 | |||
75bd542feb | |||
c43a68c3b0 | |||
d211371ed0 | |||
eaed49786a | |||
baf574b68b | |||
f4561ba0b5 | |||
c120ad9715 | |||
0f49beeff5 | |||
f2bfd5711b | |||
3d43a0e472 | |||
049ca264b2 | |||
3635a7dfdc | |||
2ae572ba88 | |||
5fac30c962 | |||
4e29801d9a | |||
0ace6da8a3 | |||
cfcaa72cd2 | |||
1b1f706c5c | |||
b4d240d8fe | |||
ed9ebfffac | |||
fa03ecd419 | |||
609202fe57 | |||
f55d6d8501 | |||
731b309ac9 | |||
f85977d881 | |||
12e395270b | |||
45b637ba17 | |||
f139d33502 | |||
63e7735abe | |||
27122f94ef | |||
0644bb72a0 | |||
a4d14511de | |||
1225d350d4 | |||
a1d93cc548 | |||
80f5bbfbce | |||
70c9431ee4 | |||
de7664ccc7 | |||
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 |
@ -1,4 +1,4 @@
|
||||
version: 7.31.{build}
|
||||
version: 7.37.{build}
|
||||
|
||||
configuration:
|
||||
- Release
|
||||
|
13
README.md
@ -9,7 +9,7 @@ GPXSee is a Qt-based GPS log file viewer and analyzer that supports all common G
|
||||
* Support for DEM files (SRTM HGT).
|
||||
* Support for multiple tracks in one view.
|
||||
* Support for POI files.
|
||||
* Print/export to PDF.
|
||||
* Print/export to PDF/PNG.
|
||||
* Full-screen mode.
|
||||
* HiDPI/Retina displays & maps support.
|
||||
* Native GUI for Windows, Mac OS X and Linux.
|
||||
@ -43,3 +43,14 @@ make # nmake on windows
|
||||
|
||||
## Translations
|
||||
GPXSee uses [Weblate](https://hosted.weblate.org/projects/gpxsee/translations/) for translations.
|
||||
|
||||
## License
|
||||
GPXSee is licensed under GPL-3.0 (only). However, some 3rd party parts are using different, GPL compatible,
|
||||
licenses:
|
||||
* [Oxygen icons](icons/GUI) - LGPLv3
|
||||
* [Mapbox Maki icons](icons/POI) - CC0
|
||||
* [RTree implementation](src/common/rtree.h) - Public domain
|
||||
* [Albers](src/map/albersequal.cpp), [Geocentric](src/map/geocentric.cpp), [LCC](src/map/lambertconic.cpp),
|
||||
[Mercator](src/map/mercator.cpp), [Polar Stereographic](src/map/polarstereographic.cpp)
|
||||
and [Transverse Mercator](src/map/transversemercator.cpp) projections - NIMA Source Code Disclaimer
|
||||
* [Projection parameters CSV files](pkg/csv) - BSD/EPSG/Public domain
|
||||
|
28
gpxsee.pro
@ -3,7 +3,7 @@ unix:!macx {
|
||||
} else {
|
||||
TARGET = GPXSee
|
||||
}
|
||||
VERSION = 7.31
|
||||
VERSION = 7.37
|
||||
|
||||
QT += core \
|
||||
gui \
|
||||
@ -19,8 +19,10 @@ equals(QT_MAJOR_VERSION, 5) : lessThan(QT_MINOR_VERSION, 4) {QT += opengl}
|
||||
|
||||
INCLUDEPATH += ./src
|
||||
HEADERS += src/common/config.h \
|
||||
src/GUI/axislabelitem.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 +55,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 \
|
||||
@ -93,8 +94,10 @@ HEADERS += src/common/config.h \
|
||||
src/map/IMG/bitstream.h \
|
||||
src/map/IMG/deltastream.h \
|
||||
src/map/IMG/gmap.h \
|
||||
src/map/IMG/huffmanbuffer.h \
|
||||
src/map/IMG/huffmanstream.h \
|
||||
src/map/IMG/huffmantable.h \
|
||||
src/map/IMG/huffmantext.h \
|
||||
src/map/IMG/nodfile.h \
|
||||
src/map/IMG/mapdata.h \
|
||||
src/map/IMG/rastertile.h \
|
||||
@ -198,8 +201,12 @@ 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/axislabelitem.cpp \
|
||||
src/GUI/marginswidget.cpp \
|
||||
src/GUI/popup.cpp \
|
||||
src/common/coordinates.cpp \
|
||||
src/common/rectc.cpp \
|
||||
@ -224,7 +231,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,8 +262,10 @@ SOURCES += src/main.cpp \
|
||||
src/map/IMG/bitstream.cpp \
|
||||
src/map/IMG/deltastream.cpp \
|
||||
src/map/IMG/gmap.cpp \
|
||||
src/map/IMG/huffmanbuffer.cpp \
|
||||
src/map/IMG/huffmanstream.cpp \
|
||||
src/map/IMG/huffmantable.cpp \
|
||||
src/map/IMG/huffmantext.cpp \
|
||||
src/map/IMG/nodfile.cpp \
|
||||
src/map/IMG/mapdata.cpp \
|
||||
src/map/IMG/rastertile.cpp \
|
||||
@ -344,7 +352,9 @@ 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
|
||||
@ -377,7 +387,7 @@ TRANSLATIONS = lang/gpxsee_en.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 \
|
||||
@ -420,7 +430,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 \
|
||||
@ -450,8 +460,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
@ -7,7 +7,7 @@
|
||||
; The name of the installer
|
||||
Name "GPXSee"
|
||||
; Program version
|
||||
!define VERSION "7.31"
|
||||
!define VERSION "7.37"
|
||||
|
||||
; 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"
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
; The name of the installer
|
||||
Name "GPXSee"
|
||||
; Program version
|
||||
!define VERSION "7.31"
|
||||
!define VERSION "7.37"
|
||||
|
||||
; 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"
|
||||
|
||||
|
@ -41,6 +41,7 @@ AxisItem::AxisItem(Type type, QGraphicsItem *parent)
|
||||
{
|
||||
_type = type;
|
||||
_size = 0;
|
||||
_zoom = 1.0;
|
||||
|
||||
_font.setPixelSize(FONT_SIZE);
|
||||
_font.setFamily(FONT_FAMILY);
|
||||
@ -52,8 +53,10 @@ void AxisItem::setRange(const RangeF &range)
|
||||
_range = range;
|
||||
|
||||
QFontMetrics fm(_font);
|
||||
Ticks ticks(_range.min(), _range.max(), (_type == X) ? XTICKS : YTICKS);
|
||||
Ticks ticks(_range.min(), _range.max(),
|
||||
(_type == X) ? XTICKS * _zoom : YTICKS * _zoom);
|
||||
_ticks = QVector<Tick>(ticks.count());
|
||||
|
||||
for (int i = 0; i < ticks.count(); i++) {
|
||||
Tick &t = _ticks[i];
|
||||
t.value = ticks.val(i);
|
||||
@ -72,34 +75,23 @@ void AxisItem::setSize(qreal size)
|
||||
update();
|
||||
}
|
||||
|
||||
void AxisItem::setLabel(const QString& label)
|
||||
{
|
||||
prepareGeometryChange();
|
||||
QFontMetrics fm(_font);
|
||||
_label = label;
|
||||
_labelBB = fm.tightBoundingRect(label);
|
||||
updateBoundingRect();
|
||||
update();
|
||||
}
|
||||
|
||||
void AxisItem::updateBoundingRect()
|
||||
{
|
||||
QFontMetrics fm(_font);
|
||||
QRect es = _ticks.isEmpty() ? QRect() : _ticks.last().boundingBox;
|
||||
QRect ss = _ticks.isEmpty() ? QRect() : _ticks.first().boundingBox;
|
||||
QRect ls(_labelBB);
|
||||
|
||||
if (_type == X) {
|
||||
_boundingRect = QRectF(-ss.width()/2, -TICK/2, _size + es.width()/2
|
||||
+ ss.width()/2, ls.height() + es.height() - fm.descent() + TICK
|
||||
+ 2*PADDING + 1);
|
||||
+ ss.width()/2, es.height() - 2*fm.descent() + TICK + 2*PADDING);
|
||||
} else {
|
||||
int mtw = 0;
|
||||
for (int i = 0; i < _ticks.count(); i++)
|
||||
mtw = qMax(_ticks.at(i).boundingBox.width(), mtw);
|
||||
_boundingRect = QRectF(-(ls.height() + mtw + 2*PADDING + TICK/2),
|
||||
-(_size + es.height()/2 + fm.descent()), ls.height() + mtw + 2*PADDING
|
||||
+ TICK, _size + es.height()/2 + fm.descent() + ss.height()/2);
|
||||
_boundingRect = QRectF(-(mtw + 2*PADDING + TICK/2 - fm.descent()),
|
||||
-(_size + es.height()/2 + fm.descent()), mtw + 2*PADDING
|
||||
+ TICK - fm.descent(), _size + es.height()/2 + fm.descent()
|
||||
+ ss.height()/2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,7 +100,6 @@ void AxisItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
||||
{
|
||||
Q_UNUSED(option);
|
||||
Q_UNUSED(widget);
|
||||
QFontMetrics fm(_font);
|
||||
QRect ts;
|
||||
|
||||
painter->setRenderHint(QPainter::Antialiasing, false);
|
||||
@ -130,9 +121,6 @@ void AxisItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
||||
- (ts.width()/2), ts.height() + TICK/2 + PADDING,
|
||||
_locale.toString(val));
|
||||
}
|
||||
|
||||
painter->drawText(_size/2 - _labelBB.width()/2, _labelBB.height()
|
||||
+ ts.height() - 2*fm.descent() + TICK/2 + 2*PADDING, _label);
|
||||
} else {
|
||||
painter->drawLine(0, 0, 0, -_size);
|
||||
|
||||
@ -149,17 +137,10 @@ void AxisItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
||||
-((_size/_range.size()) * (val - _range.min())) + (ts.height()/2),
|
||||
_locale.toString(val));
|
||||
}
|
||||
|
||||
painter->rotate(-90);
|
||||
painter->drawText(_size/2 - _labelBB.width()/2, -(mtw + 2*PADDING
|
||||
+ TICK/2), _label);
|
||||
painter->rotate(90);
|
||||
}
|
||||
|
||||
/*
|
||||
painter->setPen(Qt::red);
|
||||
painter->drawRect(boundingRect());
|
||||
*/
|
||||
//painter->setPen(Qt::red);
|
||||
//painter->drawRect(boundingRect());
|
||||
}
|
||||
|
||||
QSizeF AxisItem::margin() const
|
||||
@ -168,15 +149,15 @@ QSizeF AxisItem::margin() const
|
||||
QRect es = _ticks.isEmpty() ? QRect() : _ticks.last().boundingBox;
|
||||
|
||||
if (_type == X) {
|
||||
return QSizeF(es.width()/2, _labelBB.height() + es.height()
|
||||
- fm.descent() + TICK/2 + 2*PADDING);
|
||||
return QSizeF(es.width()/2, es.height() - 2*fm.descent() + TICK/2
|
||||
+ 2*PADDING);
|
||||
} else {
|
||||
int mtw = 0;
|
||||
for (int i = 0; i < _ticks.count(); i++)
|
||||
mtw = qMax(_ticks.at(i).boundingBox.width(), mtw);
|
||||
|
||||
return QSizeF(_labelBB.height() -fm.descent() + mtw + 2*PADDING
|
||||
+ TICK/2, es.height()/2 + fm.descent());
|
||||
return QSizeF(mtw + 2*PADDING + TICK/2 - fm.descent(),
|
||||
es.height()/2 + fm.descent());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,13 +13,15 @@ public:
|
||||
|
||||
AxisItem(Type type, QGraphicsItem *parent = 0);
|
||||
|
||||
/* Note: The items position is at the 0 point of the axis line, not at the
|
||||
top-left point of the bounding rect as usual */
|
||||
QRectF boundingRect() const {return _boundingRect;}
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
||||
QWidget *widget);
|
||||
|
||||
void setRange(const RangeF &range);
|
||||
void setSize(qreal size);
|
||||
void setLabel(const QString& label);
|
||||
void setZoom(qreal zoom) {_zoom = zoom;}
|
||||
|
||||
QSizeF margin() const;
|
||||
QList<qreal> ticks() const;
|
||||
@ -35,12 +37,11 @@ private:
|
||||
Type _type;
|
||||
RangeF _range;
|
||||
qreal _size;
|
||||
QString _label;
|
||||
QRect _labelBB;
|
||||
QVector<Tick> _ticks;
|
||||
QRectF _boundingRect;
|
||||
QFont _font;
|
||||
QLocale _locale;
|
||||
qreal _zoom;
|
||||
};
|
||||
|
||||
#endif // AXISITEM_H
|
||||
|
54
src/GUI/axislabelitem.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
#include <QPainter>
|
||||
#include <QFontMetrics>
|
||||
#include "font.h"
|
||||
#include "axislabelitem.h"
|
||||
|
||||
|
||||
AxisLabelItem::AxisLabelItem(Type type, QGraphicsItem *parent)
|
||||
: QGraphicsItem(parent), _type(type)
|
||||
{
|
||||
_font.setPixelSize(FONT_SIZE);
|
||||
_font.setFamily(FONT_FAMILY);
|
||||
}
|
||||
|
||||
void AxisLabelItem::setLabel(const QString& label, const QString &units)
|
||||
{
|
||||
prepareGeometryChange();
|
||||
QFontMetrics fm(_font);
|
||||
_label = QString("%1 [%2]").arg(label, units.isEmpty() ? "-" : units);
|
||||
_labelBB = fm.tightBoundingRect(_label);
|
||||
updateBoundingRect();
|
||||
update();
|
||||
}
|
||||
|
||||
void AxisLabelItem::updateBoundingRect()
|
||||
{
|
||||
QFontMetrics fm(_font);
|
||||
|
||||
if (_type == X)
|
||||
_boundingRect = QRectF(0, 0, _labelBB.width(), fm.height());
|
||||
else
|
||||
_boundingRect = QRectF(0, 0, fm.height(), _labelBB.width());
|
||||
}
|
||||
|
||||
void AxisLabelItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
||||
QWidget *widget)
|
||||
{
|
||||
Q_UNUSED(option);
|
||||
Q_UNUSED(widget);
|
||||
QFontMetrics fm(_font);
|
||||
|
||||
painter->setFont(_font);
|
||||
|
||||
if (_type == X) {
|
||||
painter->drawText(0, fm.height() - fm.descent(), _label);
|
||||
} else {
|
||||
painter->rotate(-90);
|
||||
painter->drawText(-_labelBB.width(), fm.height() - fm.descent(), _label);
|
||||
painter->rotate(90);
|
||||
}
|
||||
|
||||
//painter->setRenderHint(QPainter::Antialiasing, false);
|
||||
//painter->setPen(Qt::red);
|
||||
//painter->drawRect(boundingRect());
|
||||
}
|
30
src/GUI/axislabelitem.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef AXISLABELITEM_H
|
||||
#define AXISLABELITEM_H
|
||||
|
||||
#include <QGraphicsItem>
|
||||
#include <QFont>
|
||||
|
||||
class AxisLabelItem : public QGraphicsItem
|
||||
{
|
||||
public:
|
||||
enum Type {X, Y};
|
||||
|
||||
AxisLabelItem(Type type, QGraphicsItem *parent = 0);
|
||||
|
||||
QRectF boundingRect() const {return _boundingRect;}
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
||||
QWidget *widget);
|
||||
|
||||
void setLabel(const QString& label, const QString &units);
|
||||
|
||||
private:
|
||||
void updateBoundingRect();
|
||||
|
||||
Type _type;
|
||||
QString _label;
|
||||
QFont _font;
|
||||
QRect _labelBB;
|
||||
QRectF _boundingRect;
|
||||
};
|
||||
|
||||
#endif // AXISLABELITEM_H
|
@ -15,6 +15,8 @@ public:
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
||||
QWidget *widget);
|
||||
|
||||
CoordinatesFormat format() const {return _format;}
|
||||
|
||||
void setCoordinates(const Coordinates &c);
|
||||
void setFormat(const CoordinatesFormat &format);
|
||||
void setDigitalZoom(qreal zoom);
|
||||
|
@ -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();
|
||||
|
@ -11,7 +11,7 @@ GraphItem::GraphItem(const Graph &graph, GraphType type, int width,
|
||||
Q_ASSERT(_graph.isValid());
|
||||
|
||||
_units = Metric;
|
||||
_pen = QPen(color, width, style);
|
||||
_pen = QPen(color, width, style, Qt::FlatCap);
|
||||
_sx = 0; _sy = 0;
|
||||
_time = _graph.hasTime();
|
||||
setZValue(2.0);
|
||||
|
@ -14,8 +14,7 @@ class GraphTab : public GraphView
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GraphTab(QWidget *parent = 0) : GraphView(parent)
|
||||
{setFrameShape(QFrame::NoFrame);}
|
||||
GraphTab(QWidget *parent = 0) : GraphView(parent) {}
|
||||
virtual ~GraphTab() {}
|
||||
|
||||
virtual QString label() const = 0;
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "data/graph.h"
|
||||
#include "opengl.h"
|
||||
#include "axisitem.h"
|
||||
#include "axislabelitem.h"
|
||||
#include "slideritem.h"
|
||||
#include "sliderinfoitem.h"
|
||||
#include "infoitem.h"
|
||||
@ -22,6 +23,9 @@
|
||||
|
||||
#define MARGIN 10.0
|
||||
|
||||
#define IW(item) ((item)->boundingRect().width())
|
||||
#define IH(item) ((item)->boundingRect().height())
|
||||
|
||||
GraphView::GraphView(QWidget *parent)
|
||||
: QGraphicsView(parent)
|
||||
{
|
||||
@ -38,6 +42,10 @@ GraphView::GraphView(QWidget *parent)
|
||||
_xAxis->setZValue(1.0);
|
||||
_yAxis = new AxisItem(AxisItem::Y);
|
||||
_yAxis->setZValue(1.0);
|
||||
_xAxisLabel = new AxisLabelItem(AxisLabelItem::X);
|
||||
_xAxisLabel->setZValue(1.0);
|
||||
_yAxisLabel = new AxisLabelItem(AxisLabelItem::Y);
|
||||
_yAxisLabel->setZValue(1.0);
|
||||
_slider = new SliderItem();
|
||||
_slider->setZValue(4.0);
|
||||
_sliderInfo = new SliderInfoItem(_slider);
|
||||
@ -73,34 +81,24 @@ GraphView::~GraphView()
|
||||
{
|
||||
delete _xAxis;
|
||||
delete _yAxis;
|
||||
delete _xAxisLabel;
|
||||
delete _yAxisLabel;
|
||||
delete _slider;
|
||||
delete _info;
|
||||
delete _grid;
|
||||
delete _message;
|
||||
}
|
||||
|
||||
void GraphView::createXLabel()
|
||||
{
|
||||
_xAxis->setLabel(QString("%1 [%2]").arg(_xLabel,
|
||||
_xUnits.isEmpty() ? "-" : _xUnits));
|
||||
}
|
||||
|
||||
void GraphView::createYLabel()
|
||||
{
|
||||
_yAxis->setLabel(QString("%1 [%2]").arg(_yLabel,
|
||||
_yUnits.isEmpty() ? "-" : _yUnits));
|
||||
}
|
||||
|
||||
void GraphView::setYLabel(const QString &label)
|
||||
{
|
||||
_yLabel = label;
|
||||
createYLabel();
|
||||
_yAxisLabel->setLabel(_yLabel, _yUnits);
|
||||
}
|
||||
|
||||
void GraphView::setYUnits(const QString &units)
|
||||
{
|
||||
_yUnits = units;
|
||||
createYLabel();
|
||||
_yAxisLabel->setLabel(_yLabel, _yUnits);
|
||||
}
|
||||
|
||||
void GraphView::setXUnits()
|
||||
@ -144,7 +142,7 @@ void GraphView::setXUnits()
|
||||
}
|
||||
}
|
||||
|
||||
createXLabel();
|
||||
_xAxisLabel->setLabel(_xLabel, _xUnits);
|
||||
}
|
||||
|
||||
void GraphView::setUnits(Units units)
|
||||
@ -163,6 +161,7 @@ void GraphView::setGraphType(GraphType type)
|
||||
{
|
||||
_graphType = type;
|
||||
_bounds = QRectF();
|
||||
_zoom = 1.0;
|
||||
|
||||
for (int i = 0; i < _graphs.count(); i++) {
|
||||
GraphItem *gi = _graphs.at(i);
|
||||
@ -257,6 +256,8 @@ void GraphView::redraw(const QSizeF &size)
|
||||
if (_bounds.isNull()) {
|
||||
removeItem(_xAxis);
|
||||
removeItem(_yAxis);
|
||||
removeItem(_xAxisLabel);
|
||||
removeItem(_yAxisLabel);
|
||||
removeItem(_slider);
|
||||
removeItem(_info);
|
||||
removeItem(_grid);
|
||||
@ -268,6 +269,8 @@ void GraphView::redraw(const QSizeF &size)
|
||||
removeItem(_message);
|
||||
addItem(_xAxis);
|
||||
addItem(_yAxis);
|
||||
addItem(_xAxisLabel);
|
||||
addItem(_yAxisLabel);
|
||||
addItem(_slider);
|
||||
addItem(_info);
|
||||
addItem(_grid);
|
||||
@ -278,7 +281,9 @@ void GraphView::redraw(const QSizeF &size)
|
||||
if (ry.size() < _minYRange * _yScale)
|
||||
ry.resize(_minYRange * _yScale);
|
||||
|
||||
_xAxis->setZoom(_zoom);
|
||||
_xAxis->setRange(rx);
|
||||
_xAxis->setZoom(_zoom);
|
||||
_yAxis->setRange(ry);
|
||||
mx = _xAxis->margin();
|
||||
my = _yAxis->margin();
|
||||
@ -288,9 +293,10 @@ void GraphView::redraw(const QSizeF &size)
|
||||
r.adjust(0, -(_minYRange/2 - r.height()/2), 0,
|
||||
_minYRange/2 - r.height()/2);
|
||||
|
||||
sx = (size.width() - (my.width() + mx.width())) / r.width();
|
||||
sx = (size.width() - (my.width() + mx.width()) - IW(_yAxisLabel))
|
||||
/ r.width();
|
||||
sy = (size.height() - (mx.height() + my.height())
|
||||
- _info->boundingRect().height()) / r.height();
|
||||
- IH(_info) - IH(_xAxisLabel)) / r.height();
|
||||
sx *= _zoom;
|
||||
|
||||
for (int i = 0; i < _graphs.size(); i++)
|
||||
@ -316,10 +322,12 @@ void GraphView::redraw(const QSizeF &size)
|
||||
_slider->setArea(r);
|
||||
updateSliderPosition();
|
||||
|
||||
r |= _xAxis->sceneBoundingRect();
|
||||
r |= _yAxis->sceneBoundingRect();
|
||||
_info->setPos(r.topLeft() + QPointF(r.width()/2
|
||||
- _info->boundingRect().width()/2, -_info->boundingRect().height()));
|
||||
_info->setPos(QPointF(r.width()/2 - IW(_info)/2 - (IW(_yAxisLabel)
|
||||
+ IW(_yAxis))/2, r.top() - IH(_info) - my.height()));
|
||||
_xAxisLabel->setPos(QPointF(r.width()/2 - IW(_xAxisLabel)/2,
|
||||
r.bottom() + mx.height()));
|
||||
_yAxisLabel->setPos(QPointF(r.left() - my.width() - IW(_yAxisLabel),
|
||||
r.bottom() - (r.height()/2 + IH(_yAxisLabel)/2)));
|
||||
|
||||
_scene->setSceneRect(_scene->itemsBoundingRect());
|
||||
}
|
||||
@ -367,8 +375,10 @@ void GraphView::wheelEvent(QWheelEvent *e)
|
||||
void GraphView::paintEvent(QPaintEvent *e)
|
||||
{
|
||||
QRectF viewRect(mapToScene(rect()).boundingRect());
|
||||
_info->setPos(QPointF(viewRect.left() + (viewRect.width()
|
||||
- _info->boundingRect().width())/2.0, _info->pos().y()));
|
||||
_info->setPos(QPointF(viewRect.left() + (viewRect.width() - IW(_info))/2.0,
|
||||
_info->pos().y()));
|
||||
_xAxisLabel->setPos(QPointF(viewRect.left() + (viewRect.width()
|
||||
- IW(_xAxisLabel))/2.0, _xAxisLabel->pos().y()));
|
||||
|
||||
QGraphicsView::paintEvent(e);
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
|
||||
class AxisItem;
|
||||
class AxisLabelItem;
|
||||
class SliderItem;
|
||||
class SliderInfoItem;
|
||||
class GraphItem;
|
||||
@ -86,8 +87,6 @@ private slots:
|
||||
private:
|
||||
void redraw(const QSizeF &size);
|
||||
void setXUnits();
|
||||
void createXLabel();
|
||||
void createYLabel();
|
||||
void updateSliderPosition();
|
||||
void updateSliderInfo();
|
||||
void removeItem(QGraphicsItem *item);
|
||||
@ -96,6 +95,7 @@ private:
|
||||
GraphicsScene *_scene;
|
||||
|
||||
AxisItem *_xAxis, *_yAxis;
|
||||
AxisLabelItem *_xAxisLabel, *_yAxisLabel;
|
||||
SliderItem *_slider;
|
||||
SliderInfoItem *_sliderInfo;
|
||||
InfoItem *_info;
|
||||
|
@ -23,10 +23,8 @@ void GridItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
||||
painter->drawLine(0, -_yTicks.at(i), boundingRect().width(),
|
||||
-_yTicks.at(i));
|
||||
|
||||
/*
|
||||
painter->setPen(Qt::red);
|
||||
painter->drawRect(boundingRect());
|
||||
*/
|
||||
//painter->setPen(Qt::red);
|
||||
//painter->drawRect(boundingRect());
|
||||
}
|
||||
|
||||
void GridItem::setTicks(const QList<qreal> &x, const QList<qreal> &y)
|
||||
|
315
src/GUI/gui.cpp
@ -140,10 +140,9 @@ void GUI::createMapActions()
|
||||
|
||||
MapAction *GUI::createMapAction(Map *map)
|
||||
{
|
||||
MapAction *a = new MapAction(map);
|
||||
MapAction *a = new MapAction(map, _mapsActionGroup);
|
||||
a->setMenuRole(QAction::NoRole);
|
||||
a->setCheckable(true);
|
||||
a->setActionGroup(_mapsActionGroup);
|
||||
connect(a, SIGNAL(triggered()), this, SLOT(mapChanged()));
|
||||
|
||||
return a;
|
||||
@ -230,13 +229,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);
|
||||
@ -497,7 +503,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();
|
||||
@ -624,15 +631,15 @@ void GUI::createMapView()
|
||||
void GUI::createGraphTabs()
|
||||
{
|
||||
_graphTabWidget = new QTabWidget();
|
||||
connect(_graphTabWidget, SIGNAL(currentChanged(int)), this,
|
||||
SLOT(graphChanged(int)));
|
||||
|
||||
_graphTabWidget->setSizePolicy(QSizePolicy(QSizePolicy::Ignored,
|
||||
QSizePolicy::Preferred));
|
||||
_graphTabWidget->setMinimumHeight(200);
|
||||
#ifdef Q_OS_WIN32
|
||||
#ifndef Q_OS_MAC
|
||||
_graphTabWidget->setDocumentMode(true);
|
||||
#endif // Q_OS_WIN32
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
connect(_graphTabWidget, SIGNAL(currentChanged(int)), this,
|
||||
SLOT(graphChanged(int)));
|
||||
|
||||
_tabs.append(new ElevationGraph(_graphTabWidget));
|
||||
_tabs.append(new SpeedGraph(_graphTabWidget));
|
||||
@ -642,9 +649,13 @@ void GUI::createGraphTabs()
|
||||
_tabs.append(new TemperatureGraph(_graphTabWidget));
|
||||
_tabs.append(new GearRatioGraph(_graphTabWidget));
|
||||
|
||||
for (int i = 0; i < _tabs.count(); i++)
|
||||
for (int i = 0; i < _tabs.count(); i++) {
|
||||
#if defined(Q_OS_WIN32) || defined(Q_OS_MAC)
|
||||
_tabs.at(i)->setFrameShape(QFrame::NoFrame);
|
||||
#endif // Q_OS_WIN32 || Q_OS_MAC
|
||||
connect(_tabs.at(i), SIGNAL(sliderPositionChanged(qreal)), this,
|
||||
SLOT(sliderPositionChanged(qreal)));
|
||||
}
|
||||
}
|
||||
|
||||
void GUI::createStatusBar()
|
||||
@ -713,7 +724,10 @@ void GUI::keys()
|
||||
+ "</i></td></tr><tr><td>" + tr("Zoom out") + "</td><td><i>"
|
||||
+ QKeySequence(ZOOM_OUT).toString() + "</i></td></tr><tr><td>"
|
||||
+ tr("Digital zoom") + "</td><td><i>" + QKeySequence(MODIFIER).toString()
|
||||
+ tr("Zoom") + "</i></td></tr></table></div>");
|
||||
+ tr("Zoom") + "</i></td></tr><tr><td></td><td></td></tr><tr><td>"
|
||||
+ tr("Copy coordinates") + "</td><td><i>"
|
||||
+ QKeySequence(MODIFIER).toString() + tr("Left Click")
|
||||
+ "</i></td></tr></table></div>");
|
||||
|
||||
msgBox.exec();
|
||||
}
|
||||
@ -928,7 +942,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;
|
||||
|
||||
@ -970,6 +984,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);
|
||||
@ -1018,9 +1033,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;
|
||||
|
||||
@ -1028,16 +1043,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, "png");
|
||||
|
||||
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(), "png");
|
||||
}
|
||||
}
|
||||
|
||||
void GUI::statistics()
|
||||
{
|
||||
QLocale l(QLocale::system());
|
||||
@ -1109,12 +1161,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)
|
||||
@ -1150,53 +1203,91 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
@ -1551,8 +1642,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++)
|
||||
@ -1795,23 +1885,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);
|
||||
@ -1884,6 +1993,8 @@ void GUI::writeSettings()
|
||||
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)
|
||||
@ -2075,23 +2186,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);
|
||||
@ -2159,6 +2289,8 @@ void GUI::readSettings()
|
||||
#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,
|
||||
@ -2250,6 +2382,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,7 +46,8 @@ private slots:
|
||||
void keys();
|
||||
void paths();
|
||||
void printFile();
|
||||
void exportFile();
|
||||
void exportPDFFile();
|
||||
void exportPNGFile();
|
||||
void openFile();
|
||||
void closeAll();
|
||||
void reloadFiles();
|
||||
@ -97,6 +99,10 @@ private:
|
||||
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;
|
||||
@ -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
|
||||
|
@ -53,10 +53,8 @@ void InfoItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
painter->setPen(Qt::red);
|
||||
painter->drawRect(boundingRect());
|
||||
*/
|
||||
//painter->setPen(Qt::red);
|
||||
//painter->drawRect(boundingRect());
|
||||
}
|
||||
|
||||
void InfoItem::insert(const QString &key, const QString &value)
|
||||
|
@ -8,6 +8,7 @@
|
||||
#define PREV_KEY Qt::Key_Backspace
|
||||
#define FIRST_KEY Qt::Key_Home
|
||||
#define LAST_KEY Qt::Key_End
|
||||
#define MODIFIER_KEY Qt::Key_Shift
|
||||
#define MODIFIER Qt::ShiftModifier
|
||||
#define ZOOM_IN Qt::Key_Plus
|
||||
#define ZOOM_OUT Qt::Key_Minus
|
||||
@ -18,7 +19,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)
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <QWheelEvent>
|
||||
#include <QApplication>
|
||||
#include <QScrollBar>
|
||||
#include <QClipboard>
|
||||
#include "data/poi.h"
|
||||
#include "data/data.h"
|
||||
#include "map/map.h"
|
||||
@ -522,7 +523,12 @@ void MapView::keyPressEvent(QKeyEvent *event)
|
||||
else if (_digitalZoom && event->key() == Qt::Key_Escape) {
|
||||
digitalZoom(0);
|
||||
return;
|
||||
} else {
|
||||
} else {
|
||||
if (event->key() == MODIFIER_KEY) {
|
||||
_cursor = viewport()->cursor();
|
||||
viewport()->setCursor(Qt::CrossCursor);
|
||||
}
|
||||
|
||||
QGraphicsView::keyPressEvent(event);
|
||||
return;
|
||||
}
|
||||
@ -530,8 +536,26 @@ void MapView::keyPressEvent(QKeyEvent *event)
|
||||
zoom(z, pos);
|
||||
}
|
||||
|
||||
void MapView::keyReleaseEvent(QKeyEvent *event)
|
||||
{
|
||||
if (event->key() == MODIFIER_KEY
|
||||
&& viewport()->cursor().shape() == Qt::CrossCursor)
|
||||
viewport()->setCursor(_cursor);
|
||||
|
||||
QGraphicsView::keyReleaseEvent(event);
|
||||
}
|
||||
|
||||
void MapView::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton && event->modifiers() & MODIFIER)
|
||||
QApplication::clipboard()->setText(Format::coordinates(
|
||||
_map->xy2ll(mapToScene(event->pos())), _coordinates->format()));
|
||||
else
|
||||
QGraphicsView::mousePressEvent(event);
|
||||
}
|
||||
|
||||
void MapView::plot(QPainter *painter, const QRectF &target, qreal scale,
|
||||
bool hires)
|
||||
PlotFlags flags)
|
||||
{
|
||||
QRect orig, adj;
|
||||
qreal ratio, diff, q;
|
||||
@ -559,10 +583,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();
|
||||
@ -594,7 +626,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"
|
||||
@ -38,6 +39,13 @@ 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);
|
||||
@ -46,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();
|
||||
|
||||
@ -114,13 +123,15 @@ private:
|
||||
void updatePOIVisibility();
|
||||
void skipColor() {_palette.nextColor();}
|
||||
|
||||
void mouseMoveEvent(QMouseEvent *event);
|
||||
void mousePressEvent(QMouseEvent *event);
|
||||
void mouseDoubleClickEvent(QMouseEvent *event);
|
||||
void wheelEvent(QWheelEvent *event);
|
||||
void keyPressEvent(QKeyEvent *event);
|
||||
void keyReleaseEvent(QKeyEvent *event);
|
||||
void drawBackground(QPainter *painter, const QRectF &rect);
|
||||
void paintEvent(QPaintEvent *event);
|
||||
void scrollContentsBy(int dx, int dy);
|
||||
void mouseMoveEvent(QMouseEvent *event);
|
||||
void leaveEvent(QEvent *event);
|
||||
|
||||
GraphicsScene *_scene;
|
||||
@ -154,6 +165,7 @@ private:
|
||||
|
||||
int _digitalZoom;
|
||||
bool _plot;
|
||||
QCursor _cursor;
|
||||
|
||||
#ifdef ENABLE_HIDPI
|
||||
qreal _deviceRatio;
|
||||
|
@ -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,15 +166,15 @@ QWidget *OptionsDialog::createAppearancePage()
|
||||
|
||||
// Palette & antialiasing
|
||||
_baseColor = new ColorBox();
|
||||
_baseColor->setColor(_options->palette.color());
|
||||
_baseColor->setColor(_options.palette.color());
|
||||
_colorOffset = new PercentSlider();
|
||||
_colorOffset->setValue(_options->palette.shift() * 100);
|
||||
_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);
|
||||
|
||||
@ -201,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);
|
||||
@ -217,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);
|
||||
@ -247,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();
|
||||
@ -257,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);
|
||||
|
||||
@ -271,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();
|
||||
@ -301,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();
|
||||
@ -328,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);
|
||||
@ -349,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);
|
||||
@ -359,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,
|
||||
@ -400,29 +400,29 @@ 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)
|
||||
if (_options.timeZone.type() == TimeZoneInfo::UTC)
|
||||
_utcZone->setChecked(true);
|
||||
else if (_options->timeZone.type() == TimeZoneInfo::System)
|
||||
else if (_options.timeZone.type() == TimeZoneInfo::System)
|
||||
_systemZone->setChecked(true);
|
||||
else
|
||||
_customZone->setChecked(true);
|
||||
@ -431,7 +431,7 @@ QWidget *OptionsDialog::createDataPage()
|
||||
QList<QByteArray> zones = QTimeZone::availableTimeZoneIds();
|
||||
for (int i = 0; i < zones.size(); i++)
|
||||
_timeZone->addItem(zones.at(i));
|
||||
_timeZone->setCurrentText(_options->timeZone.customZone().id());
|
||||
_timeZone->setCurrentText(_options.timeZone.customZone().id());
|
||||
connect(_customZone, SIGNAL(toggled(bool)), _timeZone,
|
||||
SLOT(setEnabled(bool)));
|
||||
QHBoxLayout *customZoneLayout = new QHBoxLayout();
|
||||
@ -439,6 +439,9 @@ QWidget *OptionsDialog::createDataPage()
|
||||
customZoneLayout->addWidget(_timeZone);
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
_useSegments = new QCheckBox(tr("Use segments"));
|
||||
_useSegments->setChecked(_options.useSegments);
|
||||
|
||||
QWidget *sourceTab = new QWidget();
|
||||
QVBoxLayout *sourceTabLayout = new QVBoxLayout();
|
||||
|
||||
@ -474,17 +477,25 @@ QWidget *OptionsDialog::createDataPage()
|
||||
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
|
||||
|
||||
QFormLayout *segmentsLayout = new QFormLayout();
|
||||
segmentsLayout->addWidget(_useSegments);
|
||||
|
||||
sourceTabLayout->addLayout(formLayout);
|
||||
sourceTabLayout->addWidget(line());
|
||||
sourceTabLayout->addLayout(segmentsLayout);
|
||||
|
||||
#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);
|
||||
@ -510,11 +521,14 @@ QWidget *OptionsDialog::createDataPage()
|
||||
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);
|
||||
@ -533,14 +547,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"));
|
||||
}
|
||||
|
||||
@ -560,7 +574,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);
|
||||
@ -589,17 +603,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);
|
||||
@ -614,7 +628,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);
|
||||
@ -633,23 +647,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);
|
||||
@ -674,8 +688,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());
|
||||
@ -727,81 +741,82 @@ OptionsDialog::OptionsDialog(Options *options, QWidget *parent)
|
||||
|
||||
void OptionsDialog::accept()
|
||||
{
|
||||
_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(
|
||||
_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()
|
||||
_options.timeZone.setType(_utcZone->isChecked()
|
||||
? TimeZoneInfo::UTC : _systemZone->isChecked()
|
||||
? TimeZoneInfo::System : TimeZoneInfo::Custom);
|
||||
_options->timeZone.setCustomZone(QTimeZone(_timeZone->currentText()
|
||||
_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();
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ struct Options {
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
TimeZoneInfo timeZone;
|
||||
#endif // ENABLE_TIMEZONES
|
||||
bool useSegments;
|
||||
// POI
|
||||
int poiRadius;
|
||||
// System
|
||||
@ -81,8 +82,6 @@ struct Options {
|
||||
bool printMovingTime;
|
||||
bool printItemCount;
|
||||
bool separateGraphPage;
|
||||
|
||||
Units units;
|
||||
};
|
||||
|
||||
class OptionsDialog : public QDialog
|
||||
@ -93,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);
|
||||
@ -106,8 +105,9 @@ private:
|
||||
QWidget *createSystemPage();
|
||||
QWidget *createExportPage();
|
||||
|
||||
Options *_options;
|
||||
Options &_options;
|
||||
|
||||
Units _units;
|
||||
// Appearance
|
||||
ColorBox *_baseColor;
|
||||
PercentSlider *_colorOffset;
|
||||
@ -157,6 +157,7 @@ private:
|
||||
QRadioButton *_customZone;
|
||||
QComboBox *_timeZone;
|
||||
#endif // ENABLE_TIMEZONES
|
||||
QCheckBox *_useSegments;
|
||||
// POI
|
||||
QDoubleSpinBox *_poiRadius;
|
||||
// System
|
||||
|
@ -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
|
@ -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"
|
||||
@ -150,6 +169,8 @@
|
||||
#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"
|
||||
|
@ -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
|
||||
|
||||
|
@ -15,4 +15,15 @@ inline double toWGS24(qint32 v)
|
||||
return toWGS32(LS(v, 8));
|
||||
}
|
||||
|
||||
inline quint8 vs(const quint8 b0)
|
||||
{
|
||||
static const quint8 sizes[] = {4, 1, 2, 1, 3, 1, 2, 1};
|
||||
return sizes[b0 & 0x07];
|
||||
}
|
||||
|
||||
inline quint8 bs(const quint8 val)
|
||||
{
|
||||
return (val + 7) >> 3;
|
||||
}
|
||||
|
||||
#endif // GARMIN_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,29 @@
|
||||
// TITLE
|
||||
//
|
||||
// R-TREES: A DYNAMIC INDEX STRUCTURE FOR SPATIAL SEARCHING
|
||||
//
|
||||
// DESCRIPTION
|
||||
//
|
||||
// A C++ templated version of the RTree algorithm.
|
||||
// For more information please read the comments in RTree.h
|
||||
//
|
||||
// AUTHORS
|
||||
//
|
||||
// * 1983 Original algorithm and test code by Antonin Guttman
|
||||
// and Michael Stonebraker, UC Berkely
|
||||
// * 1994 ANSI C ported from original test code by Melinda Green
|
||||
// (melinda@superliminal.com)
|
||||
// * 1995 Sphere volume fix for degeneracy problem submitted by Paul Brook
|
||||
// * 2004 Templated C++ port by Greg Douglas
|
||||
// * 2018 Iterator fix and Qt macros by Martin Tuma
|
||||
//
|
||||
// LICENSE:
|
||||
//
|
||||
// Entirely free for all uses. Enjoy!
|
||||
|
||||
#ifndef RTREE_H
|
||||
#define RTREE_H
|
||||
|
||||
#include <cstdio>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <QtGlobal>
|
||||
@ -387,10 +409,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 +429,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 +449,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 +658,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;
|
||||
|
@ -51,13 +51,13 @@ class FITParser::CTX {
|
||||
public:
|
||||
CTX(QFile *file, QVector<Waypoint> &waypoints)
|
||||
: file(file), waypoints(waypoints), len(0), endian(0), timestamp(0),
|
||||
lastWrite(0), ratio(NAN) {}
|
||||
ratio(NAN) {}
|
||||
|
||||
QFile *file;
|
||||
QVector<Waypoint> &waypoints;
|
||||
quint32 len;
|
||||
quint8 endian;
|
||||
quint32 timestamp, lastWrite;
|
||||
quint32 timestamp;
|
||||
MessageDefinition defs[16];
|
||||
qreal ratio;
|
||||
Trackpoint trackpoint;
|
||||
@ -361,14 +361,12 @@ bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
||||
ctx.ratio = ((qreal)front / (qreal)rear);
|
||||
}
|
||||
} else if (def->globalId == RECORD_MESSAGE) {
|
||||
if (ctx.timestamp > ctx.lastWrite
|
||||
&& ctx.trackpoint.coordinates().isValid()) {
|
||||
if (ctx.trackpoint.coordinates().isValid()) {
|
||||
ctx.trackpoint.setTimestamp(QDateTime::fromTime_t(ctx.timestamp
|
||||
+ 631065600));
|
||||
ctx.trackpoint.setRatio(ctx.ratio);
|
||||
ctx.segment.append(ctx.trackpoint);
|
||||
ctx.trackpoint = Trackpoint();
|
||||
ctx.lastWrite = ctx.timestamp;
|
||||
}
|
||||
} else if (def->globalId == COURSE_POINT)
|
||||
if (waypoint.coordinates().isValid())
|
||||
|
@ -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)
|
||||
{
|
||||
@ -88,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
|
||||
|
@ -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,9 +12,25 @@ bool BitStream1::flush()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BitStream4::flush()
|
||||
bool BitStream1::readUInt24(quint32 &val)
|
||||
{
|
||||
if (_length && !_file.seek(_hdl, _hdl.pos() + _length))
|
||||
quint8 b;
|
||||
|
||||
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;
|
||||
@ -82,7 +69,7 @@ bool BitStream4F::read(int bits, quint32 &val)
|
||||
BitStream4R::BitStream4R(const SubFile &file, SubFile::Handle &hdl,
|
||||
quint32 length) : BitStream4(file, hdl, length)
|
||||
{
|
||||
_file.seek(_hdl, _hdl.pos() - 4);
|
||||
_file.seek(_hdl, _file.pos(_hdl) - 4);
|
||||
}
|
||||
|
||||
bool BitStream4R::readBytes(int bytes, quint32 &val)
|
||||
@ -96,7 +83,14 @@ bool BitStream4R::readBytes(int bytes, quint32 &val)
|
||||
Q_ASSERT(!b);
|
||||
}
|
||||
|
||||
return read(bytes * 8, val);
|
||||
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)
|
||||
@ -139,7 +133,7 @@ bool BitStream4R::readVuint32SM(quint32 &val1, quint32 &val2, quint32 &val2Bits)
|
||||
return false;
|
||||
|
||||
if (!(b & 1)) {
|
||||
val1 = b >> 3 & 0x1f;
|
||||
val1 = b >> 3;
|
||||
val2 = b >> 1 & 3;
|
||||
val2Bits = 2;
|
||||
} else {
|
||||
@ -169,14 +163,14 @@ bool BitStream4R::skip(quint32 bytes)
|
||||
else {
|
||||
quint32 seek = ((bytes - ab)/4)*4;
|
||||
quint32 read = (bytes - ab)%4;
|
||||
if (seek && !_file.seek(_hdl, _hdl.pos() - seek))
|
||||
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, _hdl.pos() - 8))
|
||||
if (!_file.seek(_hdl, _file.pos(_hdl) - 8))
|
||||
return false;
|
||||
_length -= rb;
|
||||
_unused = (4 - rb) * 8;
|
||||
@ -188,14 +182,33 @@ bool BitStream4R::skip(quint32 bytes)
|
||||
return true;
|
||||
}
|
||||
|
||||
void BitStream4R::resize(quint32 length)
|
||||
void BitStream4R::resize(quint32 bytes)
|
||||
{
|
||||
quint32 ab = (32 - _used)/8;
|
||||
quint32 ab = (32 - (_used + _unused) + 7)/8;
|
||||
|
||||
if (ab < length)
|
||||
_length = length - ab;
|
||||
if (ab <= bytes)
|
||||
_length = bytes - ab;
|
||||
else {
|
||||
_length = 0;
|
||||
_used += length * 8;
|
||||
_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,10 +8,12 @@ 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();
|
||||
quint64 bitsAvailable() const {return (quint64)_length * 8 + _remaining;}
|
||||
|
||||
bool readUInt24(quint32 &val);
|
||||
|
||||
private:
|
||||
const SubFile &_file;
|
||||
SubFile::Handle &_hdl;
|
||||
@ -25,7 +27,6 @@ public:
|
||||
: _file(file), _hdl(hdl), _length(length), _used(32), _unused(0),
|
||||
_data(0) {}
|
||||
|
||||
bool flush();
|
||||
quint64 bitsAvailable() const
|
||||
{return (quint64)_length * 8 + (32 - _used) - _unused;}
|
||||
|
||||
@ -42,10 +43,19 @@ public:
|
||||
: 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);
|
||||
@ -54,9 +64,42 @@ public:
|
||||
bool readVuint32SM(quint32 &val1, quint32 &val2, quint32 &val2Bits);
|
||||
|
||||
bool skip(quint32 bytes);
|
||||
void resize(quint32 length);
|
||||
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)
|
||||
{
|
||||
@ -73,7 +116,7 @@ bool BitStream4R::read(int bits, T &val)
|
||||
|
||||
if (!_file.readUInt32(_hdl, _data))
|
||||
return false;
|
||||
if (!_file.seek(_hdl, _hdl.pos() - 8))
|
||||
if (!_file.seek(_hdl, _file.pos(_hdl) - 8))
|
||||
return false;
|
||||
|
||||
_length -= bytes;
|
||||
|
@ -81,7 +81,11 @@ bool GMAP::loadTile(const QDir &dir, bool baseMap)
|
||||
QFileInfoList ml = dir.entryInfoList(QDir::Files);
|
||||
for (int i = 0; i < ml.size(); i++) {
|
||||
const QFileInfo &fi = ml.at(i);
|
||||
tile->addFile(fi.absoluteFilePath(), tileType(fi.suffix()));
|
||||
SubFile::Type tt = tileType(fi.suffix());
|
||||
if (VectorTile::isTileFile(tt)) {
|
||||
_files.append(new QString(fi.absoluteFilePath()));
|
||||
tile->addFile(_files.last(), tt);
|
||||
}
|
||||
}
|
||||
|
||||
if (!tile->init()) {
|
||||
@ -131,8 +135,10 @@ GMAP::GMAP(const QString &fileName) : _fileName(fileName)
|
||||
fi.absoluteFilePath() == baseMap.absoluteFilePath());
|
||||
}
|
||||
|
||||
if (baseDir.exists(typFilePath))
|
||||
_typ = new SubFile(baseDir.filePath(typFilePath));
|
||||
if (baseDir.exists(typFilePath)) {
|
||||
_files.append(new QString(baseDir.filePath(typFilePath)));
|
||||
_typ = new SubFile(_files.last());
|
||||
}
|
||||
|
||||
if (!_tileTree.Count())
|
||||
_errorString = "No usable map tile found";
|
||||
@ -140,6 +146,11 @@ GMAP::GMAP(const QString &fileName) : _fileName(fileName)
|
||||
_valid = true;
|
||||
}
|
||||
|
||||
GMAP::~GMAP()
|
||||
{
|
||||
qDeleteAll(_files);
|
||||
}
|
||||
|
||||
bool GMAP::isGMAP(const QString &path)
|
||||
{
|
||||
QFile file(path);
|
||||
|
@ -10,6 +10,7 @@ class GMAP : public MapData
|
||||
{
|
||||
public:
|
||||
GMAP(const QString &fileName);
|
||||
~GMAP();
|
||||
|
||||
QString fileName() const {return _fileName;}
|
||||
|
||||
@ -25,6 +26,7 @@ private:
|
||||
bool loadTile(const QDir &dir, bool baseMap);
|
||||
|
||||
QString _fileName;
|
||||
QList<const QString*> _files;
|
||||
};
|
||||
|
||||
#endif // GMAP_H
|
||||
|
24
src/map/IMG/huffmanbuffer.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
#include "rgnfile.h"
|
||||
#include "huffmanbuffer.h"
|
||||
|
||||
bool HuffmanBuffer::load(const RGNFile *rgn, SubFile::Handle &rgnHdl)
|
||||
{
|
||||
quint32 recordSize, recordOffset = rgn->dictOffset();
|
||||
|
||||
for (int i = 0; i <= _id; i++) {
|
||||
if (!rgn->seek(rgnHdl, recordOffset))
|
||||
return false;
|
||||
if (!rgn->readVUInt32(rgnHdl, recordSize))
|
||||
return false;
|
||||
recordOffset = rgn->pos(rgnHdl) + recordSize;
|
||||
if (recordOffset > rgn->dictOffset() + rgn->dictSize())
|
||||
return false;
|
||||
};
|
||||
|
||||
resize(recordSize);
|
||||
for (int i = 0; i < QByteArray::size(); i++)
|
||||
if (!rgn->readUInt8(rgnHdl, *((quint8*)(data() + i))))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
21
src/map/IMG/huffmanbuffer.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef HUFFMANBUFFER_H
|
||||
#define HUFFMANBUFFER_H
|
||||
|
||||
#include <QByteArray>
|
||||
#include "subfile.h"
|
||||
|
||||
class RGNFile;
|
||||
|
||||
class HuffmanBuffer : public QByteArray
|
||||
{
|
||||
public:
|
||||
HuffmanBuffer(quint8 id) : _id(id) {}
|
||||
|
||||
quint8 id() const {return _id;}
|
||||
bool load(const RGNFile *rgn, SubFile::Handle &rgnHdl);
|
||||
|
||||
private:
|
||||
quint8 _id;
|
||||
};
|
||||
|
||||
#endif // HUFFMANBUFFER_H
|
@ -13,10 +13,10 @@ bool HuffmanStreamF::init(bool line)
|
||||
quint32 eb;
|
||||
if (!_bs.read(1, eb))
|
||||
return false;
|
||||
if (eb) {
|
||||
qWarning() << "Extended lines/polygons not supported";
|
||||
|
||||
Q_ASSERT(!eb);
|
||||
if (eb)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -28,3 +28,14 @@ bool HuffmanStreamR::init()
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HuffmanStreamR::init(int lonSign, int latSign, quint32 data,
|
||||
quint32 dataSize)
|
||||
{
|
||||
_lonSign = lonSign;
|
||||
_latSign = latSign;
|
||||
_symbolData = data;
|
||||
_symbolDataSize = dataSize;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -11,6 +11,8 @@ public:
|
||||
: _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)))
|
||||
@ -52,7 +54,31 @@ bool HuffmanStream<BitStream>::sign(int &val)
|
||||
}
|
||||
|
||||
template <class BitStream>
|
||||
bool HuffmanStream<BitStream>::readDelta(int sign, qint32 &symbol)
|
||||
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;
|
||||
@ -65,10 +91,19 @@ bool HuffmanStream<BitStream>::readDelta(int sign, qint32 &symbol)
|
||||
_symbolDataSize += nextSize;
|
||||
|
||||
symbol = _table.symbol(_symbolData << (32 - _symbolDataSize), size);
|
||||
if (size > _symbolDataSize)
|
||||
return false;
|
||||
|
||||
if (size <= _symbolDataSize)
|
||||
_symbolDataSize -= size;
|
||||
else
|
||||
_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) {
|
||||
@ -79,7 +114,7 @@ bool HuffmanStream<BitStream>::readDelta(int sign, qint32 &symbol)
|
||||
_symbolDataSize--;
|
||||
}
|
||||
}
|
||||
symbol = sign * symbol;
|
||||
delta = sign * symbol;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -100,6 +135,7 @@ public:
|
||||
: HuffmanStream(bitstream, table) {}
|
||||
|
||||
bool init();
|
||||
bool init(int lonSign, int latSign, quint32 data, quint32 dataSize);
|
||||
};
|
||||
|
||||
#endif // HUFFMANSTREAM_H
|
||||
|
@ -1,17 +1,7 @@
|
||||
#include "common/garmin.h"
|
||||
#include "huffmantable.h"
|
||||
|
||||
|
||||
static quint8 vs(const quint8 b0)
|
||||
{
|
||||
static const quint8 sizes[] = {4, 1, 2, 1, 3, 1, 2, 1};
|
||||
return sizes[b0 & 0x07];
|
||||
}
|
||||
|
||||
static inline quint8 bs(const quint8 val)
|
||||
{
|
||||
return (val + 7) >> 3;
|
||||
}
|
||||
|
||||
static inline quint32 readVUint32(const quint8 *buffer, quint32 bytes)
|
||||
{
|
||||
quint32 val = 0;
|
||||
@ -22,10 +12,9 @@ static inline quint32 readVUint32(const quint8 *buffer, quint32 bytes)
|
||||
return val;
|
||||
}
|
||||
|
||||
bool HuffmanTable::load(const SubFile &file, SubFile::Handle &hdl,
|
||||
quint32 offset, quint32 size, quint32 id)
|
||||
bool HuffmanTable::load(const RGNFile *rgn, SubFile::Handle &rgnHdl)
|
||||
{
|
||||
if (!getBuffer(file, hdl, offset, size, id))
|
||||
if (!_buffer.load(rgn, rgnHdl))
|
||||
return false;
|
||||
|
||||
_s0 = (quint8)_buffer.at(0) & 0x0F;
|
||||
@ -42,31 +31,6 @@ bool HuffmanTable::load(const SubFile &file, SubFile::Handle &hdl,
|
||||
_s10 = _s14 + _s1c * _s1d;
|
||||
_s18 = _s10 + (_s1 << _s0);
|
||||
|
||||
_id = id;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HuffmanTable::getBuffer(const SubFile &file, SubFile::Handle &hdl,
|
||||
quint32 offset, quint32 size, quint8 id)
|
||||
{
|
||||
quint32 recordSize, recordOffset = offset;
|
||||
|
||||
for (int i = 0; i <= id; i++) {
|
||||
if (!file.seek(hdl, recordOffset))
|
||||
return false;
|
||||
if (!file.readVUInt32(hdl, recordSize))
|
||||
return false;
|
||||
recordOffset = hdl.pos() + recordSize;
|
||||
if (recordOffset > offset + size)
|
||||
return false;
|
||||
};
|
||||
|
||||
_buffer.resize(recordSize);
|
||||
for (int i = 0; i < _buffer.size(); i++)
|
||||
if (!file.readUInt8(hdl, *((quint8*)(_buffer.data() + i))))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1,31 +1,26 @@
|
||||
#ifndef HUFFMANTABLE_H
|
||||
#define HUFFMANTABLE_H
|
||||
|
||||
#include "subfile.h"
|
||||
#include "huffmanbuffer.h"
|
||||
|
||||
class RGNFile;
|
||||
|
||||
class HuffmanTable {
|
||||
public:
|
||||
HuffmanTable() : _s2(0) {}
|
||||
HuffmanTable(quint8 id) : _buffer(id) {}
|
||||
|
||||
bool load(const SubFile &file, SubFile::Handle &hdl, quint32 offset,
|
||||
quint32 size, quint32 id);
|
||||
bool isNull() const {return _s2 == 0;}
|
||||
bool load(const RGNFile *rgn, SubFile::Handle &rgnHdl);
|
||||
quint8 maxSymbolSize() const {return _s2;}
|
||||
quint32 symbol(quint32 data, quint8 &size) const;
|
||||
|
||||
quint8 id() const {return _id;}
|
||||
quint8 id() const {return _buffer.id();}
|
||||
|
||||
private:
|
||||
bool getBuffer(const SubFile &file, SubFile::Handle &hdl, quint32 offset,
|
||||
quint32 size, quint8 id);
|
||||
|
||||
QByteArray _buffer;
|
||||
HuffmanBuffer _buffer;
|
||||
quint8 _s0, _s1, _s2, _s3;
|
||||
quint8 *_s10, *_s14, *_s18;
|
||||
quint8 _s1c, _s1d, _s1e, _s1f, _s20;
|
||||
quint16 _s22;
|
||||
|
||||
quint8 _id;
|
||||
};
|
||||
|
||||
#endif // HUFFMANTABLE_H
|
||||
|
169
src/map/IMG/huffmantext.cpp
Normal file
@ -0,0 +1,169 @@
|
||||
#include "common/garmin.h"
|
||||
#include "subfile.h"
|
||||
#include "huffmantext.h"
|
||||
|
||||
|
||||
static inline quint32 readVUint32(const quint8 *buffer, quint32 bytes)
|
||||
{
|
||||
quint32 val = 0;
|
||||
|
||||
for (quint32 i = 0; i < bytes; i++)
|
||||
val = val | (quint32)*(buffer - i) << ((bytes - i - 1) << 3);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
bool HuffmanText::load(const RGNFile *rgn, SubFile::Handle &rgnHdl)
|
||||
{
|
||||
if (!_buffer.load(rgn, rgnHdl))
|
||||
return false;
|
||||
|
||||
quint8 *buffer = (quint8 *)_buffer.constData();
|
||||
_b0 = buffer[0];
|
||||
_b1 = buffer[1];
|
||||
_b2 = buffer[2];
|
||||
_b3 = buffer[3];
|
||||
_vs = vs(buffer[4]);
|
||||
_bs3 = bs(_b3);
|
||||
_bs1 = bs(_b1);
|
||||
_mul = _bs1 + 1 + _vs;
|
||||
_bp1 = buffer + _vs + 4;
|
||||
_bp2 = _bp1 + _mul * _b2;
|
||||
_bp3 = _bp2 + ((_bs3 + 1) << (_b0 & 0xf));
|
||||
_bp4 = _bp3 - 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HuffmanText::fetch(const SubFile *file, SubFile::Handle &hdl,
|
||||
quint32 &data, quint32 &bits, quint32 &usedBits, quint32 &usedData) const
|
||||
{
|
||||
quint32 rs, ls, old;
|
||||
|
||||
bits = _b1 - bits;
|
||||
|
||||
if (usedBits < bits) {
|
||||
old = usedBits ? usedData >> (0x20 - usedBits) : 0;
|
||||
if (!file->readVUInt32SW(hdl, 4, usedData))
|
||||
return false;
|
||||
ls = bits - usedBits;
|
||||
rs = 0x20 - (bits - usedBits);
|
||||
old = usedData >> rs | old << ls;
|
||||
} else {
|
||||
ls = bits;
|
||||
rs = usedBits - bits;
|
||||
old = usedData >> (0x20 - bits);
|
||||
}
|
||||
|
||||
usedData = usedData << ls;
|
||||
data = data | old << (0x20 - _b1);
|
||||
usedBits = rs;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HuffmanText::decode(const SubFile *file, SubFile::Handle &hdl,
|
||||
QVector<quint8> &str) const
|
||||
{
|
||||
quint32 bits = 0;
|
||||
quint32 data = 0;
|
||||
quint32 usedBits = 0;
|
||||
quint32 usedData = 0;
|
||||
quint32 ls = 8;
|
||||
quint32 lo = _vs * 8 - 8;
|
||||
|
||||
|
||||
while (true) {
|
||||
if (!fetch(file, hdl, data, bits, usedBits, usedData))
|
||||
return false;
|
||||
|
||||
quint32 off = (data >> (0x20 - (_b0 & 0xf))) * (_bs3 + 1);
|
||||
quint32 sb = _bp2[off];
|
||||
quint32 ss = 0;
|
||||
quint32 sym = _b2 - 1;
|
||||
quint32 size;
|
||||
|
||||
if ((_b0 & 0xf) == 0 || (sb & 1) == 0) {
|
||||
if ((_b0 & 0xf) != 0) {
|
||||
ss = sb >> 1;
|
||||
sym = _bp2[off + 1];
|
||||
}
|
||||
|
||||
quint8 *tp = _bp1 + ss * _mul;
|
||||
quint32 sd = data >> (0x20 - _b1);
|
||||
while (ss < sym) {
|
||||
quint32 cnt = (sym + 1 + ss) >> 1;
|
||||
quint8 *prev = _bp1 + cnt * _mul;
|
||||
quint32 nd = readVUint32(prev + _bs1 - 1, _bs1);
|
||||
|
||||
if (sd <= nd) {
|
||||
sym = cnt - (sd < nd);
|
||||
if (sd < nd) {
|
||||
prev = tp;
|
||||
cnt = ss;
|
||||
}
|
||||
}
|
||||
tp = prev;
|
||||
ss = cnt;
|
||||
}
|
||||
|
||||
quint32 o1 = readVUint32(tp + _bs1 - 1, _bs1);
|
||||
tp = tp + _bs1;
|
||||
quint32 o2 = readVUint32(tp + _vs, _vs);
|
||||
size = tp[0];
|
||||
quint32 os = (sd - o1) >> (_b1 - size);
|
||||
|
||||
if ((_b0 & 0x10) == 0) {
|
||||
sym = readVUint32(_bp4 + (o2 + 1 + os) * _bs3, _bs3);
|
||||
} else {
|
||||
quint32 v = (os + o2) * _b3;
|
||||
quint32 idx = v >> 3;
|
||||
quint32 r = v & 7;
|
||||
quint32 shift = 8 - r;
|
||||
sym = _bp3[idx] >> r;
|
||||
if (shift < _b3) {
|
||||
quint32 sz = bs(_b3 - shift);
|
||||
quint32 val = readVUint32(_bp3 + idx + sz, sz);
|
||||
sym = sym | val << shift;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sym = readVUint32(_bp2 + off + _bs3, _bs3);
|
||||
size = (sb >> 1);
|
||||
}
|
||||
|
||||
if (_b1 < size)
|
||||
return false;
|
||||
data = data << size;
|
||||
bits = _b1 - size;
|
||||
|
||||
if ((_b3 & 7) == 0) {
|
||||
for (quint32 i = 0; i < (_b3 >> 3); i++) {
|
||||
str.append((quint8)sym);
|
||||
if (((quint8)sym == '\0'))
|
||||
return true;
|
||||
sym = sym >> 8;
|
||||
}
|
||||
} else {
|
||||
quint32 cnt = _b3;
|
||||
|
||||
if (ls <= _b3) {
|
||||
do {
|
||||
quint32 shift = ls;
|
||||
lo = sym << (8 - shift) | (quint32)((quint8)lo >> shift);
|
||||
sym = sym >> shift;
|
||||
str.append((uchar)lo);
|
||||
if (((uchar)lo == '\0'))
|
||||
return true;
|
||||
cnt = cnt - ls;
|
||||
ls = 8;
|
||||
} while (7 < cnt);
|
||||
ls = 8;
|
||||
}
|
||||
if (cnt != 0) {
|
||||
lo = sym << (8 - cnt) | (quint32)((quint8)lo >> cnt);
|
||||
ls = ls - cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
35
src/map/IMG/huffmantext.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef HUFFMANTEXT_H
|
||||
#define HUFFMANTEXT_H
|
||||
|
||||
#include "huffmanbuffer.h"
|
||||
|
||||
class HuffmanText
|
||||
{
|
||||
public:
|
||||
HuffmanText() : _buffer(0) {}
|
||||
|
||||
bool load(const RGNFile *rgn, SubFile::Handle &rgnHdl);
|
||||
bool decode(const SubFile *file, SubFile::Handle &hdl,
|
||||
QVector<quint8> &str) const;
|
||||
|
||||
private:
|
||||
bool fetch(const SubFile *file, SubFile::Handle &hdl, quint32 &data,
|
||||
quint32 &bits, quint32 &usedBits, quint32 &usedData) const;
|
||||
|
||||
HuffmanBuffer _buffer;
|
||||
|
||||
quint32 _b0;
|
||||
quint32 _b1;
|
||||
quint32 _b2;
|
||||
quint32 _b3;
|
||||
quint32 _vs;
|
||||
quint32 _bs3;
|
||||
quint32 _bs1;
|
||||
quint32 _mul;
|
||||
quint8 *_bp1;
|
||||
quint8 *_bp2;
|
||||
quint8 *_bp3;
|
||||
quint8 *_bp4;
|
||||
};
|
||||
|
||||
#endif // HUFFMANTEXT_H
|
@ -1,4 +1,6 @@
|
||||
#include <QTextCodec>
|
||||
#include "huffmantext.h"
|
||||
#include "rgnfile.h"
|
||||
#include "lblfile.h"
|
||||
|
||||
enum Charset {Normal, Symbol, Special};
|
||||
@ -55,21 +57,48 @@ static QString capitalized(const QString &str)
|
||||
}
|
||||
|
||||
|
||||
bool LBLFile::init(Handle &hdl)
|
||||
LBLFile::~LBLFile()
|
||||
{
|
||||
quint16 codepage;
|
||||
quint8 multiplier, poiMultiplier;
|
||||
delete _huffmanText;
|
||||
delete[] _table;
|
||||
}
|
||||
|
||||
if (!(seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset)
|
||||
&& readUInt32(hdl, _size) && readUInt8(hdl, multiplier)
|
||||
bool LBLFile::load(Handle &hdl, const RGNFile *rgn, Handle &rgnHdl)
|
||||
{
|
||||
quint16 hdrLen, codepage;
|
||||
|
||||
if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)
|
||||
&& seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset)
|
||||
&& readUInt32(hdl, _size) && readUInt8(hdl, _multiplier)
|
||||
&& readUInt8(hdl, _encoding) && seek(hdl, _gmpOffset + 0x57)
|
||||
&& readUInt32(hdl, _poiOffset) && readUInt32(hdl, _poiSize)
|
||||
&& readUInt8(hdl, poiMultiplier) && seek(hdl, _gmpOffset + 0xAA)
|
||||
&& readUInt8(hdl, _poiMultiplier) && seek(hdl, _gmpOffset + 0xAA)
|
||||
&& readUInt16(hdl, codepage)))
|
||||
return false;
|
||||
|
||||
_multiplier = 1<<multiplier;
|
||||
_poiMultiplier = 1<<poiMultiplier;
|
||||
if (hdrLen >= 0x132) {
|
||||
quint32 offset, size;
|
||||
quint16 recordSize;
|
||||
if (!(seek(hdl, _gmpOffset + 0x124) && readUInt32(hdl, offset)
|
||||
&& readUInt32(hdl, size) && readUInt16(hdl, recordSize)))
|
||||
return false;
|
||||
|
||||
if (size && recordSize) {
|
||||
_table = new quint32[size / recordSize];
|
||||
if (!seek(hdl, offset))
|
||||
return false;
|
||||
for (quint32 i = 0; i < size / recordSize; i++) {
|
||||
if (!readVUInt32(hdl, recordSize, _table[i]))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_encoding == 11) {
|
||||
_huffmanText = new HuffmanText();
|
||||
if (!_huffmanText->load(rgn, rgnHdl))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (codepage == 65001)
|
||||
_codec = QTextCodec::codecForName("UTF-8");
|
||||
@ -82,6 +111,14 @@ bool LBLFile::init(Handle &hdl)
|
||||
return true;
|
||||
}
|
||||
|
||||
void LBLFile::clear()
|
||||
{
|
||||
delete _huffmanText;
|
||||
delete[] _table;
|
||||
_huffmanText = 0;
|
||||
_table = 0;
|
||||
}
|
||||
|
||||
Label LBLFile::label6b(Handle &hdl, quint32 offset, bool capitalize) const
|
||||
{
|
||||
Label::Shield::Type shieldType = Label::Shield::None;
|
||||
@ -135,20 +172,16 @@ Label LBLFile::label6b(Handle &hdl, quint32 offset, bool capitalize) const
|
||||
}
|
||||
}
|
||||
|
||||
Label LBLFile::label8b(Handle &hdl, quint32 offset, bool capitalize) const
|
||||
Label LBLFile::str2label(const QVector<quint8> &str, bool capitalize) const
|
||||
{
|
||||
Label::Shield::Type shieldType = Label::Shield::None;
|
||||
QByteArray label, shieldLabel;
|
||||
QByteArray *bap = &label;
|
||||
quint8 c;
|
||||
|
||||
if (!seek(hdl, offset))
|
||||
return Label();
|
||||
for (int i = 0; i < str.size(); i++) {
|
||||
const quint8 &c = str.at(i);
|
||||
|
||||
while (true) {
|
||||
if (!readUInt8(hdl, c))
|
||||
return Label();
|
||||
if (!c || c == 0x1d)
|
||||
if (c == 0 || c == 0x1d)
|
||||
break;
|
||||
|
||||
if (c == 0x1c)
|
||||
@ -158,10 +191,10 @@ Label LBLFile::label8b(Handle &hdl, quint32 offset, bool capitalize) const
|
||||
bap = &label;
|
||||
else
|
||||
bap->append(' ');
|
||||
} else if (c <= 0x07) {
|
||||
} 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);
|
||||
@ -175,21 +208,74 @@ Label LBLFile::label8b(Handle &hdl, quint32 offset, bool capitalize) const
|
||||
Label::Shield(shieldType, shieldText));
|
||||
}
|
||||
|
||||
Label LBLFile::label(Handle &hdl, quint32 offset, bool poi, bool capitalize)
|
||||
Label LBLFile::label8b(Handle &hdl, quint32 offset, bool capitalize) const
|
||||
{
|
||||
if (!_multiplier && !init(hdl))
|
||||
return QString();
|
||||
QVector<quint8> str;
|
||||
quint8 c;
|
||||
|
||||
if (!seek(hdl, offset))
|
||||
return Label();
|
||||
|
||||
do {
|
||||
if (!readUInt8(hdl, c))
|
||||
return Label();
|
||||
str.append(c);
|
||||
} while (c);
|
||||
|
||||
return str2label(str, capitalize);
|
||||
}
|
||||
|
||||
Label LBLFile::labelHuffman(Handle &hdl, quint32 offset, bool capitalize) const
|
||||
{
|
||||
QVector<quint8> str;
|
||||
|
||||
if (!seek(hdl, offset))
|
||||
return Label();
|
||||
if (!_huffmanText->decode(this, hdl, str))
|
||||
return Label();
|
||||
if (!_table)
|
||||
return str2label(str, capitalize);
|
||||
|
||||
|
||||
QVector<quint8> str2;
|
||||
for (int i = 0; i < str.size(); i++) {
|
||||
quint32 val = _table[str.at(i)];
|
||||
if (val) {
|
||||
if (!seek(hdl, _offset + ((val & 0x7fffff) << _multiplier)))
|
||||
return Label();
|
||||
|
||||
if (str2.size() && str2.back() == '\0')
|
||||
str2[str2.size() - 1] = ' ';
|
||||
else if (str2.size())
|
||||
str2.append(' ');
|
||||
if (!_huffmanText->decode(this, hdl, str2))
|
||||
return Label();
|
||||
} else {
|
||||
if (str.at(i) == 7) {
|
||||
str2.append(0);
|
||||
break;
|
||||
}
|
||||
if (str2.size() && str2.back() == '\0')
|
||||
str2[str2.size() - 1] = ' ';
|
||||
str2.append(str.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
return str2label(str2, capitalize);
|
||||
}
|
||||
|
||||
Label LBLFile::label(Handle &hdl, quint32 offset, bool poi, bool capitalize) const
|
||||
{
|
||||
quint32 labelOffset;
|
||||
if (poi) {
|
||||
quint32 poiOffset;
|
||||
if (!(_poiSize >= offset * _poiMultiplier
|
||||
&& seek(hdl, _poiOffset + offset * _poiMultiplier)
|
||||
if (!(_poiSize >= (offset << _poiMultiplier)
|
||||
&& seek(hdl, _poiOffset + (offset << _poiMultiplier))
|
||||
&& readUInt24(hdl, poiOffset) && (poiOffset & 0x3FFFFF)))
|
||||
return QString();
|
||||
labelOffset = _offset + (poiOffset & 0x3FFFFF) * _multiplier;
|
||||
labelOffset = _offset + ((poiOffset & 0x3FFFFF) << _multiplier);
|
||||
} else
|
||||
labelOffset = _offset + offset * _multiplier;
|
||||
labelOffset = _offset + (offset << _multiplier);
|
||||
|
||||
if (labelOffset > _offset + _size)
|
||||
return QString();
|
||||
@ -200,6 +286,8 @@ Label LBLFile::label(Handle &hdl, quint32 offset, bool poi, bool capitalize)
|
||||
case 9:
|
||||
case 10:
|
||||
return label8b(hdl, labelOffset, capitalize);
|
||||
case 11:
|
||||
return labelHuffman(hdl, labelOffset, capitalize);
|
||||
default:
|
||||
return Label();
|
||||
}
|
||||
|
@ -5,28 +5,40 @@
|
||||
#include "label.h"
|
||||
|
||||
class QTextCodec;
|
||||
class HuffmanText;
|
||||
class RGNFile;
|
||||
|
||||
class LBLFile : public SubFile
|
||||
{
|
||||
public:
|
||||
LBLFile(IMG *img)
|
||||
: SubFile(img), _codec(0), _offset(0), _size(0), _poiOffset(0),
|
||||
_poiSize(0), _poiMultiplier(0), _multiplier(0), _encoding(0) {}
|
||||
LBLFile(const QString &path)
|
||||
: SubFile(path), _codec(0), _offset(0), _size(0), _poiOffset(0),
|
||||
_poiSize(0), _poiMultiplier(0), _multiplier(0), _encoding(0) {}
|
||||
: SubFile(img), _huffmanText(0), _table(0), _codec(0), _offset(0),
|
||||
_size(0), _poiOffset(0), _poiSize(0), _poiMultiplier(0), _multiplier(0),
|
||||
_encoding(0) {}
|
||||
LBLFile(const QString *path)
|
||||
: SubFile(path), _huffmanText(0), _table(0), _codec(0), _offset(0),
|
||||
_size(0), _poiOffset(0), _poiSize(0), _poiMultiplier(0), _multiplier(0),
|
||||
_encoding(0) {}
|
||||
LBLFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
|
||||
_codec(0), _offset(0), _size(0), _poiOffset(0), _poiSize(0),
|
||||
_poiMultiplier(0), _multiplier(0), _encoding(0) {}
|
||||
_huffmanText(0), _table(0), _codec(0), _offset(0), _size(0),
|
||||
_poiOffset(0), _poiSize(0), _poiMultiplier(0), _multiplier(0),
|
||||
_encoding(0) {}
|
||||
~LBLFile();
|
||||
|
||||
bool load(Handle &hdl, const RGNFile *rgn, Handle &rgnHdl);
|
||||
void clear();
|
||||
|
||||
Label label(Handle &hdl, quint32 offset, bool poi = false,
|
||||
bool capitalize = true);
|
||||
bool capitalize = true) const;
|
||||
|
||||
private:
|
||||
bool init(Handle &hdl);
|
||||
|
||||
Label str2label(const QVector<quint8> &str, bool capitalize) const;
|
||||
Label label6b(Handle &hdl, quint32 offset, bool capitalize) const;
|
||||
Label label8b(Handle &hdl, quint32 offset, bool capitalize) const;
|
||||
Label labelHuffman(Handle &hdl, quint32 offset, bool capitalize) const;
|
||||
|
||||
HuffmanText *_huffmanText;
|
||||
quint32 *_table;
|
||||
|
||||
QTextCodec *_codec;
|
||||
quint32 _offset;
|
||||
|
@ -107,7 +107,7 @@ void MapData::load()
|
||||
else {
|
||||
QString typFile(ProgramPaths::typFile());
|
||||
if (!typFile.isEmpty()) {
|
||||
SubFile typ(typFile);
|
||||
SubFile typ(&typFile);
|
||||
_style = new Style(&typ);
|
||||
} else
|
||||
_style = new Style();
|
||||
|
@ -21,7 +21,7 @@ public:
|
||||
struct Poly {
|
||||
/* QPointF insted of Coordinates for performance reasons (no need to
|
||||
duplicate all the vectors for drawing). Note, that we do not want to
|
||||
ll2xy() the points in the IMG class as this can not be done in
|
||||
ll2xy() the points in the MapData class as this can not be done in
|
||||
parallel. */
|
||||
QVector<QPointF> points;
|
||||
Label label;
|
||||
@ -38,22 +38,12 @@ public:
|
||||
Coordinates coordinates;
|
||||
Label label;
|
||||
quint32 type;
|
||||
bool poi;
|
||||
quint64 id;
|
||||
|
||||
bool operator<(const Point &other) const
|
||||
{return id < other.id;}
|
||||
};
|
||||
|
||||
struct Polys {
|
||||
Polys() {}
|
||||
Polys(const QList<Poly> &polygons, const QList<Poly> &lines)
|
||||
: polygons(polygons), lines(lines) {}
|
||||
|
||||
QList<Poly> polygons;
|
||||
QList<Poly> lines;
|
||||
};
|
||||
|
||||
MapData();
|
||||
virtual ~MapData();
|
||||
|
||||
@ -88,15 +78,26 @@ protected:
|
||||
QString _errorString;
|
||||
|
||||
private:
|
||||
struct Polys {
|
||||
Polys() {}
|
||||
Polys(const QList<Poly> &polygons, const QList<Poly> &lines)
|
||||
: polygons(polygons), lines(lines) {}
|
||||
|
||||
QList<Poly> polygons;
|
||||
QList<Poly> lines;
|
||||
};
|
||||
|
||||
QCache<const SubDiv*, Polys> _polyCache;
|
||||
QCache<const SubDiv*, QList<Point> > _pointCache;
|
||||
|
||||
friend class VectorTile;
|
||||
friend struct PolyCTX;
|
||||
};
|
||||
|
||||
#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();
|
||||
}
|
||||
|
||||
|
@ -2,10 +2,12 @@
|
||||
#include "huffmanstream.h"
|
||||
#include "subdiv.h"
|
||||
#include "nodfile.h"
|
||||
#include "lblfile.h"
|
||||
#include "rgnfile.h"
|
||||
#include "netfile.h"
|
||||
|
||||
|
||||
bool adjCnts(BitStream4R &bs, QVector<quint16> &cnts, quint16 &mask)
|
||||
static bool readAdjCounts(BitStream4R &bs, QVector<quint16> &cnts, quint16 &mask)
|
||||
{
|
||||
quint32 val, cnt, bits;
|
||||
if (!bs.read(4, val))
|
||||
@ -17,7 +19,6 @@ bool adjCnts(BitStream4R &bs, QVector<quint16> &cnts, quint16 &mask)
|
||||
if (cnt == 5) {
|
||||
if (!bs.read(8, cnt))
|
||||
return false;
|
||||
Q_ASSERT(cnt > 4);
|
||||
}
|
||||
|
||||
if (cnt < 2)
|
||||
@ -30,14 +31,25 @@ bool adjCnts(BitStream4R &bs, QVector<quint16> &cnts, quint16 &mask)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool skipNodes(BitStream4R &bs, const QVector<quint16> &cnts, quint16 mask)
|
||||
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) {
|
||||
quint32 v1, v2, v2b;
|
||||
if (!bs.readVuint32SM(v1, v2, v2b))
|
||||
return false;
|
||||
if (!bs.skip(v1))
|
||||
if (!skipShape(bs))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -45,7 +57,7 @@ bool skipNodes(BitStream4R &bs, const QVector<quint16> &cnts, quint16 mask)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool seekToLevel(BitStream4R &bs, quint8 level)
|
||||
static bool seekToLevel(BitStream4R &bs, quint8 level)
|
||||
{
|
||||
quint32 v1, v2, v2b;
|
||||
|
||||
@ -55,7 +67,6 @@ bool seekToLevel(BitStream4R &bs, quint8 level)
|
||||
if (!bs.skip(v1))
|
||||
return false;
|
||||
|
||||
Q_ASSERT(!(v2 & 2));
|
||||
if (v2 & 2)
|
||||
return false;
|
||||
if (v2 & 1)
|
||||
@ -65,7 +76,7 @@ bool seekToLevel(BitStream4R &bs, quint8 level)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool seekToLine(BitStream4R &bs, quint8 line)
|
||||
static bool seekToLine(BitStream4R &bs, quint8 line)
|
||||
{
|
||||
quint32 v1, v2, v2b;
|
||||
|
||||
@ -75,7 +86,6 @@ bool seekToLine(BitStream4R &bs, quint8 line)
|
||||
if (!bs.skip(v1))
|
||||
return false;
|
||||
|
||||
Q_ASSERT(!(v2 & 2));
|
||||
if (v2 & 2)
|
||||
return false;
|
||||
}
|
||||
@ -83,42 +93,329 @@ bool seekToLine(BitStream4R &bs, quint8 line)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool NETFile::init(Handle &hdl)
|
||||
static bool readLine(BitStream4R &bs, const SubDiv *subdiv,
|
||||
const HuffmanTable *table, MapData::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(const NODFile *nod, SubFile::Handle &nodHdl,
|
||||
NODFile::AdjacencyInfo &adj, MapData::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(const 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(const NODFile *nod, SubFile::Handle &nodHdl,
|
||||
NODFile::AdjacencyInfo &adj, BitStream4R &bs, const HuffmanTable *table,
|
||||
const SubDiv *subdiv, quint32 shift, MapData::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;
|
||||
}
|
||||
|
||||
|
||||
NETFile::~NETFile()
|
||||
{
|
||||
delete _huffmanTable;
|
||||
}
|
||||
|
||||
bool NETFile::linkLabel(Handle &hdl, quint32 offset, quint32 size,
|
||||
const LBLFile *lbl, Handle &lblHdl, Label &label) const
|
||||
{
|
||||
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)
|
||||
label = lbl->label(lblHdl, labelPtr & 0x3FFFFF);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NETFile::load(Handle &hdl, const RGNFile *rgn, Handle &rgnHdl)
|
||||
{
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
_multiplier = 1<<multiplier;
|
||||
quint8 tableId = ((info >> 2) & 0xF);
|
||||
if (_linksSize && (!rgn->huffmanTable() || rgn->huffmanTable()->id()
|
||||
!= tableId)) {
|
||||
_huffmanTable = new HuffmanTable(tableId);
|
||||
if (!_huffmanTable->load(rgn, rgnHdl))
|
||||
return false;
|
||||
}
|
||||
|
||||
_tp = _huffmanTable ? _huffmanTable : rgn->huffmanTable();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NETFile::link(const SubDiv *subdiv, Handle &hdl, NODFile *nod,
|
||||
Handle &nodHdl, const NODFile::BlockInfo blockInfo, quint8 linkId,
|
||||
quint8 lineId, const HuffmanTable &table, QList<IMG::Poly> *lines)
|
||||
void NETFile::clear()
|
||||
{
|
||||
if (!_multiplier && !init(hdl))
|
||||
return false;
|
||||
delete _huffmanTable;
|
||||
_huffmanTable = 0;
|
||||
}
|
||||
|
||||
// TODO
|
||||
if (!subdiv->level())
|
||||
bool NETFile::link(const SubDiv *subdiv, quint32 shift, Handle &hdl,
|
||||
const NODFile *nod, Handle &nodHdl, const LBLFile *lbl, Handle &lblHdl,
|
||||
const NODFile::BlockInfo &blockInfo, quint8 linkId, quint8 lineId,
|
||||
QList<MapData::Poly> *lines) const
|
||||
{
|
||||
MapData::Poly poly;
|
||||
if (!nod->linkType(nodHdl, blockInfo, linkId, poly.type))
|
||||
return false;
|
||||
|
||||
NODFile::LinkInfo linkInfo;
|
||||
@ -126,95 +423,87 @@ bool NETFile::link(const SubDiv *subdiv, Handle &hdl, NODFile *nod,
|
||||
return false;
|
||||
|
||||
quint32 linkOffset = _linksOffset + (linkInfo.linkOffset << _linksShift);
|
||||
Q_ASSERT(linkOffset <= _linksOffset + _linksSize);
|
||||
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 (s6a == 1) {
|
||||
QVector<quint16> ca;
|
||||
quint16 mask;
|
||||
|
||||
if (!seek(hdl, linkOffset))
|
||||
return false;
|
||||
|
||||
BitStream4R bs(*this, hdl, linkOffset - _linksOffset);
|
||||
quint32 size;
|
||||
|
||||
if (s69 == 0 || s6a == 1) {
|
||||
if (!bs.readVUInt32(size))
|
||||
return false;
|
||||
|
||||
if (s69 == 0) {
|
||||
if (!adjCnts(bs, ca, mask))
|
||||
return false;
|
||||
}
|
||||
if (s68 == 1) {
|
||||
quint32 v1, v2, v2b;
|
||||
if (!bs.readVuint32SM(v1, v2, v2b))
|
||||
return false;
|
||||
Q_ASSERT(v1);
|
||||
if (!bs.skip(v1))
|
||||
return false;
|
||||
}
|
||||
if (!skipNodes(bs, ca, mask))
|
||||
}
|
||||
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, _tp, 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, _tp, 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;
|
||||
|
||||
quint32 v1, v2, v2b;
|
||||
if (!bs.readVuint32SM(v1, v2, v2b))
|
||||
if (!readLine(bs, subdiv, _tp, poly))
|
||||
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()));
|
||||
|
||||
IMG::Poly poly;
|
||||
if (!nod->linkType(nodHdl, blockInfo, linkId, poly.type))
|
||||
return false;
|
||||
poly.boundingRect = RectC(c, c);
|
||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||
|
||||
Q_ASSERT(_tableId == table.id());
|
||||
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);
|
||||
}
|
||||
|
||||
lines->append(poly);
|
||||
}
|
||||
|
||||
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)
|
||||
bool NETFile::lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset) const
|
||||
{
|
||||
if (!_multiplier && !init(hdl))
|
||||
return false;
|
||||
|
||||
if (!(seek(hdl, _offset + netOffset * _multiplier)
|
||||
if (!(seek(hdl, _offset + (netOffset << _shift))
|
||||
&& readUInt24(hdl, lblOffset)))
|
||||
return false;
|
||||
|
||||
|
@ -1,37 +1,44 @@
|
||||
#ifndef NETFILE_H
|
||||
#define NETFILE_H
|
||||
|
||||
#include "img.h"
|
||||
#include "subfile.h"
|
||||
#include "nodfile.h"
|
||||
|
||||
class NODFile;
|
||||
class LBLFile;
|
||||
class RGNFile;
|
||||
class SubDiv;
|
||||
class HuffmanTable;
|
||||
|
||||
class NETFile : public SubFile
|
||||
{
|
||||
public:
|
||||
NETFile(IMG *img) : SubFile(img), _offset(0), _size(0), _linksOffset(0),
|
||||
_linksSize(0), _multiplier(0), _linksShift(0) {}
|
||||
NETFile(const QString &path) : SubFile(path), _offset(0), _size(0),
|
||||
_linksOffset(0), _linksSize(0), _multiplier(0), _linksShift(0) {}
|
||||
NETFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
|
||||
_offset(0), _size(0), _linksOffset(0), _linksSize(0), _multiplier(0),
|
||||
NETFile(IMG *img) : SubFile(img), _huffmanTable(0), _tp(0), _offset(0),
|
||||
_size(0), _linksOffset(0), _linksSize(0), _shift(0), _linksShift(0) {}
|
||||
NETFile(const QString *path) : SubFile(path), _huffmanTable(0), _tp(0),
|
||||
_offset(0), _size(0), _linksOffset(0), _linksSize(0), _shift(0),
|
||||
_linksShift(0) {}
|
||||
NETFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
|
||||
_huffmanTable(0), _tp(0), _offset(0), _size(0), _linksOffset(0),
|
||||
_linksSize(0), _shift(0), _linksShift(0) {}
|
||||
~NETFile();
|
||||
|
||||
bool lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset);
|
||||
bool link(const SubDiv *subdiv, Handle &hdl, NODFile *nod, Handle &nodHdl,
|
||||
const NODFile::BlockInfo blockInfo, quint8 linkId, quint8 lineId,
|
||||
const HuffmanTable &table, QList<IMG::Poly> *lines);
|
||||
bool load(Handle &hdl, const RGNFile *rgn, Handle &rgnHdl);
|
||||
void clear();
|
||||
|
||||
bool lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset) const;
|
||||
bool link(const SubDiv *subdiv, quint32 shift, Handle &hdl,
|
||||
const NODFile *nod, Handle &nodHdl, const LBLFile *lbl, Handle &lblHdl,
|
||||
const NODFile::BlockInfo &blockInfo, quint8 linkId, quint8 lineId,
|
||||
QList<MapData::Poly> *lines) const;
|
||||
|
||||
private:
|
||||
bool init(Handle &hdl);
|
||||
bool linkLabel(Handle &hdl, quint32 offset, quint32 size,
|
||||
const LBLFile *lbl, Handle &lblHdl, Label &label) const;
|
||||
|
||||
HuffmanTable *_huffmanTable;
|
||||
const HuffmanTable *_tp;
|
||||
quint32 _offset, _size, _linksOffset, _linksSize;
|
||||
quint8 _multiplier, _linksShift;
|
||||
quint8 _tableId;
|
||||
quint8 _shift, _linksShift;
|
||||
};
|
||||
|
||||
#endif // NETFILE_H
|
||||
|
@ -1,79 +1,161 @@
|
||||
#include "bitstream.h"
|
||||
#include "nodfile.h"
|
||||
|
||||
bool NODFile::init(Handle &hdl)
|
||||
{
|
||||
quint16 hdrLen;
|
||||
|
||||
if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)))
|
||||
#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;
|
||||
|
||||
if (hdrLen >= 0x7b) {
|
||||
if (!(seek(hdl, _gmpOffset + 0x21) && 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)))
|
||||
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;
|
||||
}
|
||||
|
||||
quint32 NODFile::indexIdSize(Handle &hdl)
|
||||
static bool skipOptAdjData(BitStream1 &bs)
|
||||
{
|
||||
if (!_indexRecordSize && !init(hdl))
|
||||
return 0;
|
||||
|
||||
quint32 indexCount = _indexSize / _indexRecordSize;
|
||||
if (indexCount <= 0x100)
|
||||
return 1;
|
||||
else if (indexCount <= 0x1000)
|
||||
return 2;
|
||||
else if (indexCount <= 0x1000000)
|
||||
return 3;
|
||||
else
|
||||
return 0;
|
||||
// TODO
|
||||
Q_UNUSED(bs);
|
||||
Q_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NODFile::blockInfo(Handle &hdl, quint32 blockIndexId,
|
||||
BlockInfo &blockInfo) const
|
||||
|
||||
bool NODFile::load(Handle &hdl)
|
||||
{
|
||||
quint32 blockOffset;
|
||||
quint32 offset = _indexRecordSize * blockIndexId + _indexOffset;
|
||||
quint32 offsetSize = (_indexFlags & 3) + 1;
|
||||
quint16 hdrLen;
|
||||
|
||||
if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)))
|
||||
return false;
|
||||
if (hdrLen < 0x7b)
|
||||
return true;
|
||||
|
||||
Q_ASSERT(offset <= _indexOffset + _indexSize);
|
||||
if (!(seek(hdl, offset) && readVUInt32(hdl, offsetSize, blockOffset)))
|
||||
if (!(seek(hdl, _gmpOffset + 0x1d) && readUInt32(hdl, _flags)
|
||||
&& readUInt8(hdl, _blockShift) && readUInt8(hdl, _nodeShift)))
|
||||
return false;
|
||||
|
||||
blockInfo.offset = (blockOffset << _blockShift) + _blockOffset;
|
||||
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 (!(seek(hdl, blockInfo.offset) && readUInt16(hdl, blockInfo.h0)
|
||||
&& readUInt32(hdl, blockInfo.h2) && readUInt32(hdl, blockInfo.h6)
|
||||
&& readUInt32(hdl, blockInfo.ha) && readUInt16(hdl, blockInfo.he)
|
||||
&& readUInt8(hdl, blockInfo.h10) && readUInt8(hdl, blockInfo.h11)
|
||||
&& readUInt8(hdl, blockInfo.h12)))
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
Q_ASSERT(linkId < blockInfo.h10);
|
||||
if (linkId >= blockInfo.hdr.s10)
|
||||
return false;
|
||||
|
||||
quint32 infoOffset = ((blockInfo.he * linkId) >> 3) + 0x13
|
||||
+ ((blockInfo.h0 >> 0xb) & 1) + blockInfo.offset;
|
||||
quint32 s1 = ((blockInfo.h0 >> 2) & 0x1f) + 8;
|
||||
quint32 s2 = (blockInfo.h0 >> 7) & 0xf;
|
||||
quint32 skip = (blockInfo.he * linkId) & 7;
|
||||
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;
|
||||
|
||||
Q_ASSERT(infoOffset <= _blockOffset + _blockSize);
|
||||
if (infoOffset > _blockOffset + _blockSize || infoOffset < blockInfo.offset)
|
||||
return false;
|
||||
if (!seek(hdl, infoOffset))
|
||||
return false;
|
||||
|
||||
@ -90,59 +172,374 @@ bool NODFile::linkInfo(Handle &hdl, const BlockInfo &blockInfo, quint32 linkId,
|
||||
} else {
|
||||
if (!bs.read(s1 - s2, linkInfo.linkOffset))
|
||||
return false;
|
||||
linkInfo.linkOffset += blockInfo.ha;
|
||||
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) const
|
||||
{
|
||||
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.h10 * blockInfo.he + 7) >> 3) + 0x13 +
|
||||
blockInfo.offset + ((blockInfo.h0 >> 0xb) & 1) + (quint32)blockInfo.h11
|
||||
* 3;
|
||||
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.h12 - 1;
|
||||
quint32 pos;
|
||||
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))
|
||||
return false;
|
||||
if (!readUInt16(hdl, val))
|
||||
if (!(seek(hdl, offset + _blockRecordSize * pos)
|
||||
&& readUInt16(hdl, val)))
|
||||
return false;
|
||||
|
||||
quint32 tmp = pos;
|
||||
if ((val >> 8) <= linkId) {
|
||||
if ((val >> 8) <= linkId)
|
||||
low = pos;
|
||||
tmp = high;
|
||||
}
|
||||
high = tmp;
|
||||
else
|
||||
high = pos;
|
||||
} while (low + 1 < high);
|
||||
}
|
||||
|
||||
if (!seek(hdl, offset + _blockRecordSize * low))
|
||||
return false;
|
||||
if (!readUInt16(hdl, val))
|
||||
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))
|
||||
if (!(seek(hdl, offset + _blockRecordSize * high)
|
||||
&& readUInt16(hdl, val)))
|
||||
return false;
|
||||
if (!readUInt16(hdl, val))
|
||||
return false;
|
||||
if ((val >> 8) <= linkId) {
|
||||
if ((val >> 8) <= linkId)
|
||||
type = (val & 0x3f);
|
||||
}
|
||||
}
|
||||
|
||||
type *= 256;
|
||||
type <<= 8;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1,54 +1,98 @@
|
||||
#ifndef NODFILE_H
|
||||
#define NODFILE_H
|
||||
|
||||
#include "img.h"
|
||||
#include "subfile.h"
|
||||
|
||||
class NODFile : public SubFile
|
||||
{
|
||||
public:
|
||||
struct BlockInfo {
|
||||
struct BlockInfo
|
||||
{
|
||||
quint32 offset;
|
||||
quint16 h0;
|
||||
quint32 h2;
|
||||
quint32 h6;
|
||||
quint32 ha;
|
||||
quint16 he;
|
||||
quint8 h10; // links count
|
||||
quint8 h11;
|
||||
quint8 h12;
|
||||
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 {
|
||||
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) {}
|
||||
NODFile(const QString &path) : SubFile(path), _indexOffset(0), _indexSize(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) {}
|
||||
_blockRecordSize(0), _blockShift(0), _nodeShift(0), _indexIdSize(0) {}
|
||||
NODFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
|
||||
_indexOffset(0), _indexSize(0),_indexFlags(0), _blockOffset(0),
|
||||
_indexOffset(0), _indexSize(0), _indexFlags(0), _blockOffset(0),
|
||||
_blockSize(0), _indexRecordSize(0), _blockRecordSize(0), _blockShift(0),
|
||||
_nodeShift(0) {}
|
||||
_nodeShift(0), _indexIdSize(0) {}
|
||||
|
||||
quint32 indexIdSize(Handle &hdl);
|
||||
bool blockInfo(Handle &hdl, quint32 blockIndexId,
|
||||
BlockInfo &blockInfo) const;
|
||||
bool load(Handle &hdl);
|
||||
|
||||
quint32 indexIdSize() const {return _indexIdSize;}
|
||||
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) const;
|
||||
|
||||
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 _indexOffset, _indexSize, _indexFlags, _blockOffset, _blockSize;
|
||||
quint32 _flags, _indexOffset, _indexSize, _indexFlags, _blockOffset,
|
||||
_blockSize;
|
||||
quint16 _indexRecordSize, _blockRecordSize;
|
||||
quint8 _blockShift, _nodeShift;
|
||||
quint8 _blockShift, _nodeShift, _indexIdSize;
|
||||
};
|
||||
|
||||
#endif // NETFILE_H
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <QFont>
|
||||
#include <QPainter>
|
||||
#include "map/imgmap.h"
|
||||
#include "textpathitem.h"
|
||||
#include "textpointitem.h"
|
||||
#include "bitmapline.h"
|
||||
@ -28,7 +29,7 @@ static int minPOIZoom(Style::POIClass cl)
|
||||
case Style::Food:
|
||||
case Style::Shopping:
|
||||
case Style::Services:
|
||||
return 27;
|
||||
return 26;
|
||||
case Style::Accommodation:
|
||||
case Style::Recreation:
|
||||
return 25;
|
||||
@ -166,6 +167,10 @@ void RasterTile::render()
|
||||
{
|
||||
QList<TextItem*> textItems;
|
||||
|
||||
ll2xy(_polygons);
|
||||
ll2xy(_lines);
|
||||
ll2xy(_points);
|
||||
|
||||
processPoints(textItems);
|
||||
processPolygons(textItems);
|
||||
processLines(textItems);
|
||||
@ -186,6 +191,25 @@ void RasterTile::render()
|
||||
qDeleteAll(textItems);
|
||||
}
|
||||
|
||||
void RasterTile::ll2xy(QList<MapData::Poly> &polys)
|
||||
{
|
||||
for (int i = 0; i < polys.size(); i++) {
|
||||
MapData::Poly &poly = polys[i];
|
||||
for (int j = 0; j < poly.points.size(); j++) {
|
||||
QPointF &p = poly.points[j];
|
||||
p = _map->ll2xy(Coordinates(p.x(), p.y()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RasterTile::ll2xy(QList<MapData::Point> &points)
|
||||
{
|
||||
for (int i = 0; i < points.size(); i++) {
|
||||
QPointF p(_map->ll2xy(points.at(i).coordinates));
|
||||
points[i].coordinates = Coordinates(p.x(), p.y());
|
||||
}
|
||||
}
|
||||
|
||||
void RasterTile::drawPolygons(QPainter *painter)
|
||||
{
|
||||
for (int n = 0; n < _style->drawOrder().size(); n++) {
|
||||
@ -237,10 +261,28 @@ void RasterTile::drawTextItems(QPainter *painter,
|
||||
textItems.at(i)->paint(painter);
|
||||
}
|
||||
|
||||
static void removeDuplicitLabel(QList<TextItem *> &labels, const QString &text,
|
||||
const QRectF &tileRect)
|
||||
{
|
||||
for (int i = 0; i < labels.size(); i++) {
|
||||
TextItem *item = labels.at(i);
|
||||
if (tileRect.contains(item->boundingRect()) && *(item->text()) == text) {
|
||||
labels.removeAt(i);
|
||||
delete item;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RasterTile::processPolygons(QList<TextItem*> &textItems)
|
||||
{
|
||||
QRectF tileRect(_xy, _img.size());
|
||||
QSet<QString> set;
|
||||
QList<TextItem *> labels;
|
||||
|
||||
for (int i = 0; i < _polygons.size(); i++) {
|
||||
MapData::Poly &poly = _polygons[i];
|
||||
bool exists = set.contains(poly.label.text());
|
||||
|
||||
if (poly.label.text().isEmpty())
|
||||
continue;
|
||||
@ -253,12 +295,20 @@ void RasterTile::processPolygons(QList<TextItem*> &textItems)
|
||||
centroid(poly.points).toPoint(), &poly.label.text(),
|
||||
poiFont(), 0, &style.brush().color());
|
||||
if (item->isValid() && !item->collides(textItems)
|
||||
&& rectNearPolygon(poly.points, item->boundingRect()))
|
||||
textItems.append(item);
|
||||
else
|
||||
&& !item->collides(labels)
|
||||
&& !(exists && tileRect.contains(item->boundingRect()))
|
||||
&& rectNearPolygon(poly.points, item->boundingRect())) {
|
||||
if (exists)
|
||||
removeDuplicitLabel(labels, poly.label.text(), tileRect);
|
||||
else
|
||||
set.insert(poly.label.text());
|
||||
labels.append(item);
|
||||
} else
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
|
||||
textItems.append(labels);
|
||||
}
|
||||
|
||||
void RasterTile::processLines(QList<TextItem*> &textItems)
|
||||
@ -372,14 +422,15 @@ void RasterTile::processPoints(QList<TextItem*> &textItems)
|
||||
for (int i = 0; i < _points.size(); i++) {
|
||||
MapData::Point &point = _points[i];
|
||||
const Style::Point &style = _style->point(point.type);
|
||||
bool poi = Style::isPOI(point.type);
|
||||
|
||||
if (point.poi && _zoom < minPOIZoom(Style::poiClass(point.type)))
|
||||
if (poi && _zoom < minPOIZoom(Style::poiClass(point.type)))
|
||||
continue;
|
||||
|
||||
const QString *label = point.label.text().isEmpty()
|
||||
? 0 : &(point.label.text());
|
||||
const QImage *img = style.img().isNull() ? 0 : &style.img();
|
||||
const QFont *fnt = point.poi
|
||||
const QFont *fnt = poi
|
||||
? poiFont(style.textFontSize()) : font(style.textFontSize());
|
||||
const QColor *color = style.textColor().isValid()
|
||||
? &style.textColor() : 0;
|
||||
|
@ -7,14 +7,15 @@
|
||||
class QPainter;
|
||||
class TextItem;
|
||||
class Style;
|
||||
class IMGMap;
|
||||
|
||||
class RasterTile
|
||||
{
|
||||
public:
|
||||
RasterTile(const Style *style, int zoom, const QRect &rect,
|
||||
RasterTile(IMGMap *map, const Style *style, int zoom, const QRect &rect,
|
||||
const QString &key, const QList<MapData::Poly> &polygons,
|
||||
const QList<MapData::Poly> &lines, QList<MapData::Point> &points)
|
||||
: _style(style), _zoom(zoom), _xy(rect.topLeft()),
|
||||
: _map(map), _style(style), _zoom(zoom), _xy(rect.topLeft()),
|
||||
_key(key), _img(rect.size(), QImage::Format_ARGB32_Premultiplied),
|
||||
_polygons(polygons), _lines(lines), _points(points) {}
|
||||
|
||||
@ -25,6 +26,9 @@ public:
|
||||
void render();
|
||||
|
||||
private:
|
||||
void ll2xy(QList<MapData::Poly> &polys);
|
||||
void ll2xy(QList<MapData::Point> &points);
|
||||
|
||||
void drawPolygons(QPainter *painter);
|
||||
void drawLines(QPainter *painter);
|
||||
void drawTextItems(QPainter *painter, const QList<TextItem*> &textItems);
|
||||
@ -35,6 +39,7 @@ private:
|
||||
void processShields(const QRect &tileRect, QList<TextItem*> &textItems);
|
||||
void processStreetNames(const QRect &tileRect, QList<TextItem*> &textItems);
|
||||
|
||||
IMGMap *_map;
|
||||
const Style *_style;
|
||||
int _zoom;
|
||||
QPoint _xy;
|
||||
|