mirror of
https://github.com/tumic0/GPXSee.git
synced 2025-07-20 13:54:24 +02:00
Compare commits
169 Commits
Author | SHA1 | Date | |
---|---|---|---|
14f4dead76 | |||
96bb3bbdbb | |||
22d18b6d4e | |||
c1b79217a9 | |||
e67a14b072 | |||
473d03cf1f | |||
a339706293 | |||
39c414ca73 | |||
c59d60faed | |||
32d3eab10e | |||
e7729e8745 | |||
bf145c9eb5 | |||
de0a6b0397 | |||
8cf89a580f | |||
152e2a8a09 | |||
6b860fe18c | |||
95f138f5f0 | |||
1fc4dbbb73 | |||
0999cdcba2 | |||
cc16c9e79b | |||
1990c85fd7 | |||
58f70fa833 | |||
0f6c50d588 | |||
89dce5152e | |||
8bce6a44ed | |||
59ecd3fdf0 | |||
a10c729e52 | |||
369601f102 | |||
47d0feeb46 | |||
58a0acc718 | |||
c466527625 | |||
9cd00075c7 | |||
6f72d46d6c | |||
54467e6d45 | |||
3d2e33361d | |||
f91df0d026 | |||
9bd004359d | |||
e170f92e79 | |||
0fb5d8dae6 | |||
5ff931bb5e | |||
5bd744a8ed | |||
035883aab2 | |||
571ed087e3 | |||
c461b2e549 | |||
26b5411465 | |||
8965f450ce | |||
a958544667 | |||
ddf865834a | |||
a4abed8f1f | |||
56061c93cb | |||
7385b08262 | |||
9d79bd9a9d | |||
159e5aeae9 | |||
d8beaed876 | |||
c1584f30d2 | |||
efcefe8fec | |||
cbe312d9c8 | |||
5322ee96c8 | |||
08334d7fde | |||
51d4e04343 | |||
33bbd6a592 | |||
0f96bc602c | |||
7811527239 | |||
31da4e1906 | |||
cb6a82a10a | |||
652cbd7c11 | |||
ff0711c620 | |||
eb0ff84379 | |||
74775b2c62 | |||
6ee3a8ea8d | |||
ee3d43e249 | |||
a6fbae38b8 | |||
242babb741 | |||
e26d1abd5a | |||
e80d16bec5 | |||
412ae74bfa | |||
1c472e47b9 | |||
4a725375e2 | |||
383a196414 | |||
f05b51efa6 | |||
a56c02953f | |||
00d3849e4f | |||
c9244c0684 | |||
d94938261a | |||
d5fc06d9d1 | |||
9e7ebe930e | |||
19bc509043 | |||
335794ee21 | |||
2404107d87 | |||
9447addd19 | |||
b1647d944c | |||
77ac919b83 | |||
4d652aeaff | |||
3ef2361523 | |||
e2b1c2c778 | |||
1f5ecdfc38 | |||
c55b4f1217 | |||
fd71a4c7ce | |||
0b6b09f226 | |||
517ca89814 | |||
455ec3a54b | |||
8cb8d97ee2 | |||
40e520d3bf | |||
6b75442312 | |||
cbc5b2466e | |||
19a847c7d4 | |||
f9e5cb206f | |||
441c738d0f | |||
0bf6d41de6 | |||
b7869e985d | |||
5152d5eb0b | |||
c0653ab0a8 | |||
41d27cabe2 | |||
e2f2e9700f | |||
654bfcd058 | |||
82c0c1f8a7 | |||
9ce6e16b60 | |||
98cd3c3922 | |||
a776f1d30e | |||
aea17c9fed | |||
23c18d4acd | |||
eb8fc7b540 | |||
bf0dd1b24a | |||
9b687bb830 | |||
9859608115 | |||
3d66b2fbb6 | |||
9f62b7114e | |||
c8f7e6f691 | |||
c85f404d28 | |||
273a0f0f27 | |||
bb6d6a4044 | |||
bd3a3b90bc | |||
521369a6ec | |||
440a5736f6 | |||
45a6cdeda0 | |||
f73c27c39c | |||
12827edcb2 | |||
3ec5c37fd5 | |||
ee24bd54f1 | |||
cc22df3bf2 | |||
ef017edbf6 | |||
d7f0cda4b2 | |||
dc03ab91d6 | |||
a898ff2807 | |||
497017091f | |||
9dd4e117f6 | |||
86535021aa | |||
92deaaaf2b | |||
86a943d143 | |||
015a9187a0 | |||
1de9c6ef5d | |||
54b6225c6c | |||
48c7299ba6 | |||
c284b9fa7c | |||
2c503a2406 | |||
27edc4d6b5 | |||
f333a76ef7 | |||
2c114f43c5 | |||
29e29591f8 | |||
e4ac9fda0e | |||
26229e5871 | |||
64bee2f2f4 | |||
e4288ee95c | |||
c9b3c2eedd | |||
42e4b0769f | |||
ce043ef8fa | |||
8c7050e273 | |||
d670107a11 | |||
7b03c4d852 |
@ -1,4 +1,4 @@
|
||||
version: 7.22.{build}
|
||||
version: 7.31.{build}
|
||||
|
||||
configuration:
|
||||
- Release
|
||||
|
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
||||
github: tumic0
|
17
gpxsee.pro
17
gpxsee.pro
@ -3,7 +3,7 @@ unix:!macx {
|
||||
} else {
|
||||
TARGET = GPXSee
|
||||
}
|
||||
VERSION = 7.22
|
||||
VERSION = 7.31
|
||||
|
||||
QT += core \
|
||||
gui \
|
||||
@ -20,6 +20,7 @@ equals(QT_MAJOR_VERSION, 5) : lessThan(QT_MINOR_VERSION, 4) {QT += opengl}
|
||||
INCLUDEPATH += ./src
|
||||
HEADERS += src/common/config.h \
|
||||
src/GUI/graphicsscene.h \
|
||||
src/GUI/mapaction.h \
|
||||
src/GUI/popup.h \
|
||||
src/common/garmin.h \
|
||||
src/common/staticassert.h \
|
||||
@ -94,7 +95,9 @@ HEADERS += src/common/config.h \
|
||||
src/map/IMG/gmap.h \
|
||||
src/map/IMG/huffmanstream.h \
|
||||
src/map/IMG/huffmantable.h \
|
||||
src/map/IMG/nodfile.h \
|
||||
src/map/IMG/mapdata.h \
|
||||
src/map/IMG/rastertile.h \
|
||||
src/map/IMG/textpathitem.h \
|
||||
src/map/IMG/textpointitem.h \
|
||||
src/map/projection.h \
|
||||
@ -248,13 +251,16 @@ SOURCES += src/main.cpp \
|
||||
src/GUI/gearratiographitem.cpp \
|
||||
src/GUI/mapview.cpp \
|
||||
src/GUI/areaitem.cpp \
|
||||
src/data/waypoint.cpp \
|
||||
src/map/IMG/bitmapline.cpp \
|
||||
src/map/IMG/bitstream.cpp \
|
||||
src/map/IMG/deltastream.cpp \
|
||||
src/map/IMG/gmap.cpp \
|
||||
src/map/IMG/huffmanstream.cpp \
|
||||
src/map/IMG/huffmantable.cpp \
|
||||
src/map/IMG/nodfile.cpp \
|
||||
src/map/IMG/mapdata.cpp \
|
||||
src/map/IMG/rastertile.cpp \
|
||||
src/map/IMG/textpathitem.cpp \
|
||||
src/map/IMG/textpointitem.cpp \
|
||||
src/map/maplist.cpp \
|
||||
@ -344,6 +350,9 @@ greaterThan(QT_MAJOR_VERSION, 4) {
|
||||
HEADERS += src/data/geojsonparser.h
|
||||
SOURCES += src/data/geojsonparser.cpp
|
||||
}
|
||||
equals(QT_MAJOR_VERSION, 5):greaterThan(QT_MINOR_VERSION, 4) {
|
||||
HEADERS += src/GUI/timezoneinfo.h
|
||||
}
|
||||
|
||||
DEFINES += APP_VERSION=\\\"$$VERSION\\\" \
|
||||
QT_NO_DEPRECATED_WARNINGS
|
||||
@ -364,7 +373,8 @@ TRANSLATIONS = lang/gpxsee_en.ts \
|
||||
lang/gpxsee_es.ts \
|
||||
lang/gpxsee_pt_BR.ts \
|
||||
lang/gpxsee_uk.ts \
|
||||
lang/gpxsee_hu.ts
|
||||
lang/gpxsee_hu.ts \
|
||||
lang/gpxsee_it.ts
|
||||
|
||||
macx {
|
||||
ICON = icons/gpxsee.icns
|
||||
@ -384,7 +394,8 @@ macx {
|
||||
lang/gpxsee_es.qm \
|
||||
lang/gpxsee_pt_BR.qm \
|
||||
lang/gpxsee_uk.qm \
|
||||
lang/gpxsee_hu.qm
|
||||
lang/gpxsee_hu.qm \
|
||||
lang/gpxsee_it.qm
|
||||
csv.path = Contents/Resources
|
||||
csv.files = pkg/csv
|
||||
maps.path = Contents/Resources
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="en_US">
|
||||
<context>
|
||||
<name>GUI</name>
|
||||
<message numerus="yes">
|
||||
<location filename="../src/GUI/gui.cpp" line="1392"/>
|
||||
<source>%n files</source>
|
||||
<translation>
|
||||
<numerusform>%n file</numerusform>
|
||||
<numerusform>%n files</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1940
lang/gpxsee_it.ts
Normal file
1940
lang/gpxsee_it.ts
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,7 @@
|
||||
; The name of the installer
|
||||
Name "GPXSee"
|
||||
; Program version
|
||||
!define VERSION "7.22"
|
||||
!define VERSION "7.31"
|
||||
|
||||
; The file to write
|
||||
OutFile "GPXSee-${VERSION}.exe"
|
||||
@ -177,6 +177,7 @@ SectionGroup "Localization" SEC_LOCALIZATION
|
||||
!insertmacro LOCALIZATION "French" "fr"
|
||||
!insertmacro LOCALIZATION "German" "de"
|
||||
!insertmacro LOCALIZATION "Hungarian" "hu"
|
||||
!insertmacro LOCALIZATION "Italian" "it"
|
||||
!insertmacro LOCALIZATION "Norwegian" "nb"
|
||||
!insertmacro LOCALIZATION "Polish" "pl"
|
||||
!insertmacro LOCALIZATION "Portuguese (Brazil)" "pt_BR"
|
||||
|
@ -7,7 +7,7 @@
|
||||
; The name of the installer
|
||||
Name "GPXSee"
|
||||
; Program version
|
||||
!define VERSION "7.22"
|
||||
!define VERSION "7.31"
|
||||
|
||||
; The file to write
|
||||
OutFile "GPXSee-${VERSION}_x64.exe"
|
||||
@ -184,6 +184,7 @@ SectionGroup "Localization" SEC_LOCALIZATION
|
||||
!insertmacro LOCALIZATION "French" "fr"
|
||||
!insertmacro LOCALIZATION "German" "de"
|
||||
!insertmacro LOCALIZATION "Hungarian" "hu"
|
||||
!insertmacro LOCALIZATION "Italian" "it"
|
||||
!insertmacro LOCALIZATION "Norwegian" "nb"
|
||||
!insertmacro LOCALIZATION "Polish" "pl"
|
||||
!insertmacro LOCALIZATION "Portuguese (Brazil)" "pt_BR"
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map xmlns="http://www.gpxsee.org/map/1.3">
|
||||
<map xmlns="http://www.gpxsee.org/map/1.4">
|
||||
<name>4UMaps</name>
|
||||
<url>https://tileserver.4umaps.com/$z/$x/$y.png</url>
|
||||
<zoom min="2" max="15"/>
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map xmlns="http://www.gpxsee.org/map/1.3" type="WMTS">
|
||||
<map xmlns="http://www.gpxsee.org/map/1.4" type="WMTS">
|
||||
<name>Antarctica</name>
|
||||
<url type="REST">https://gis.ngdc.noaa.gov/arcgis/rest/services/antarctic/antarctic_basemap/MapServer/WMTS/1.0.0/WMTSCapabilities.xml</url>
|
||||
<url type="REST">https://tiles.arcgis.com/tiles/C8EMgrsFcRFL6LrL/arcgis/rest/services/Antarctic_Basemap/MapServer/WMTS/1.0.0/WMTSCapabilities.xml</url>
|
||||
<copyright>NOAA National Centers for Environmental Information (NCEI); International Bathymetric Chart of the Southern Ocean (IBCSO); General Bathymetric Chart of the Oceans (GEBCO); Natural Earth</copyright>
|
||||
<layer>antarctic_antarctic_basemap</layer>
|
||||
<layer>Antarctic_Basemap</layer>
|
||||
<set>default028mm</set>
|
||||
</map>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map xmlns="http://www.gpxsee.org/map/1.3">
|
||||
<map xmlns="http://www.gpxsee.org/map/1.4">
|
||||
<name>Open Street Map</name>
|
||||
<url>https://tile.openstreetmap.org/$z/$x/$y.png</url>
|
||||
<copyright>Map data: © OpenStreetMap contributors (ODbL) | Rendering: © OpenStreetMap (CC-BY-SA)</copyright>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map xmlns="http://www.gpxsee.org/map/1.3">
|
||||
<map xmlns="http://www.gpxsee.org/map/1.4">
|
||||
<name>Open Topo Map</name>
|
||||
<url>https://a.tile.opentopomap.org/$z/$x/$y.png</url>
|
||||
<zoom max="17"/>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map xmlns="http://www.gpxsee.org/map/1.3">
|
||||
<map xmlns="http://www.gpxsee.org/map/1.4">
|
||||
<name>USGS Imagery</name>
|
||||
<url>https://basemap.nationalmap.gov/ArcGIS/rest/services/USGSImageryOnly/MapServer/tile/$z/$y/$x</url>
|
||||
<zoom min="2" max="15"/>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map xmlns="http://www.gpxsee.org/map/1.3">
|
||||
<map xmlns="http://www.gpxsee.org/map/1.4">
|
||||
<name>USGS Topo</name>
|
||||
<url>https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/tile/$z/$y/$x</url>
|
||||
<zoom min="2" max="15"/>
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
CadenceGraphItem::CadenceGraphItem(const Graph &graph, GraphType type,
|
||||
int width, const QColor &color, QGraphicsItem *parent)
|
||||
: GraphItem(graph, type, width, color, parent)
|
||||
: GraphItem(graph, type, width, color, Qt::SolidLine, parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -65,35 +65,38 @@ void ElevationGraph::setInfo()
|
||||
}
|
||||
}
|
||||
|
||||
GraphItem *ElevationGraph::loadGraph(const Graph &graph, Type type)
|
||||
GraphItem *ElevationGraph::loadGraph(const Graph &graph, PathType type,
|
||||
const QColor &color, bool primary)
|
||||
{
|
||||
if (!graph.isValid()) {
|
||||
_palette.nextColor();
|
||||
if (!graph.isValid())
|
||||
return 0;
|
||||
}
|
||||
|
||||
ElevationGraphItem *gi = new ElevationGraphItem(graph, _graphType, _width,
|
||||
_palette.nextColor());
|
||||
color, primary ? Qt::SolidLine : Qt::DashLine);
|
||||
gi->setUnits(_units);
|
||||
|
||||
if (type == Track) {
|
||||
if (type == TrackPath) {
|
||||
_tracks.append(gi);
|
||||
if (_showTracks)
|
||||
addGraph(gi);
|
||||
|
||||
_trackAscent += gi->ascent();
|
||||
_trackDescent += gi->descent();
|
||||
_trackMax = nMax(_trackMax, gi->max());
|
||||
_trackMin = nMin(_trackMin, gi->min());
|
||||
if (primary) {
|
||||
_trackAscent += gi->ascent();
|
||||
_trackDescent += gi->descent();
|
||||
_trackMax = nMax(_trackMax, gi->max());
|
||||
_trackMin = nMin(_trackMin, gi->min());
|
||||
}
|
||||
} else {
|
||||
_routes.append(gi);
|
||||
if (_showRoutes)
|
||||
addGraph(gi);
|
||||
|
||||
_routeAscent += gi->ascent();
|
||||
_routeDescent += gi->descent();
|
||||
_routeMax = nMax(_routeMax, gi->max());
|
||||
_routeMin = nMin(_routeMin, gi->min());
|
||||
if (primary) {
|
||||
_routeAscent += gi->ascent();
|
||||
_routeDescent += gi->descent();
|
||||
_routeMax = nMax(_routeMax, gi->max());
|
||||
_routeMin = nMin(_routeMin, gi->min());
|
||||
}
|
||||
}
|
||||
|
||||
return gi;
|
||||
@ -102,11 +105,32 @@ GraphItem *ElevationGraph::loadGraph(const Graph &graph, Type type)
|
||||
QList<GraphItem*> ElevationGraph::loadData(const Data &data)
|
||||
{
|
||||
QList<GraphItem*> graphs;
|
||||
GraphItem *primary, *secondary;
|
||||
|
||||
for (int i = 0; i < data.tracks().count(); i++)
|
||||
graphs.append(loadGraph(data.tracks().at(i).elevation(), Track));
|
||||
for (int i = 0; i < data.routes().count(); i++)
|
||||
graphs.append(loadGraph(data.routes().at(i).elevation(), Route));
|
||||
for (int i = 0; i < data.tracks().count(); i++) {
|
||||
QColor color(_palette.nextColor());
|
||||
const GraphPair &gp = data.tracks().at(i).elevation();
|
||||
|
||||
primary = loadGraph(gp.primary(), TrackPath, color, true);
|
||||
secondary = primary
|
||||
? loadGraph(gp.secondary(), TrackPath, color, false) : 0;
|
||||
if (primary && secondary)
|
||||
primary->setSecondaryGraph(secondary);
|
||||
|
||||
graphs.append(primary);
|
||||
}
|
||||
for (int i = 0; i < data.routes().count(); i++) {
|
||||
QColor color(_palette.nextColor());
|
||||
const GraphPair &gp = data.routes().at(i).elevation();
|
||||
|
||||
primary = loadGraph(gp.primary(), RoutePath, color, true);
|
||||
secondary = primary
|
||||
? loadGraph(gp.secondary(), RoutePath, color, false) : 0;
|
||||
if (primary && secondary)
|
||||
primary->setSecondaryGraph(secondary);
|
||||
|
||||
graphs.append(primary);
|
||||
}
|
||||
for (int i = 0; i < data.areas().count(); i++)
|
||||
_palette.nextColor();
|
||||
|
||||
|
@ -21,7 +21,7 @@ public:
|
||||
void showRoutes(bool show);
|
||||
|
||||
private:
|
||||
enum Type {Track, Route};
|
||||
enum PathType {TrackPath, RoutePath};
|
||||
|
||||
qreal max() const;
|
||||
qreal min() const;
|
||||
@ -31,7 +31,8 @@ private:
|
||||
void setYUnits(Units units);
|
||||
void setInfo();
|
||||
|
||||
GraphItem *loadGraph(const Graph &graph, Type type);
|
||||
GraphItem *loadGraph(const Graph &graph, PathType type, const QColor &color,
|
||||
bool primary);
|
||||
void showItems(const QList<ElevationGraphItem *> &list, bool show);
|
||||
|
||||
qreal _trackAscent, _trackDescent;
|
||||
|
@ -4,8 +4,8 @@
|
||||
|
||||
|
||||
ElevationGraphItem::ElevationGraphItem(const Graph &graph, GraphType type,
|
||||
int width, const QColor &color, QGraphicsItem *parent)
|
||||
: GraphItem(graph, type, width, color, parent)
|
||||
int width, const QColor &color, Qt::PenStyle style, QGraphicsItem *parent)
|
||||
: GraphItem(graph, type, width, color, style, parent)
|
||||
{
|
||||
_min = GraphItem::min();
|
||||
_max = GraphItem::max();
|
||||
@ -42,5 +42,6 @@ QString ElevationGraphItem::info() const
|
||||
tt.insert(tr("Minimum"), l.toString(min() * scale, 'f', 0)
|
||||
+ UNIT_SPACE + su);
|
||||
|
||||
|
||||
return tt.toString();
|
||||
}
|
||||
|
@ -8,8 +8,10 @@ class ElevationGraphItem : public GraphItem
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum DataType {GPS, DEM};
|
||||
|
||||
ElevationGraphItem(const Graph &graph, GraphType type, int width,
|
||||
const QColor &color, QGraphicsItem *parent = 0);
|
||||
const QColor &color, Qt::PenStyle style, QGraphicsItem *parent = 0);
|
||||
|
||||
qreal ascent() const {return _ascent;}
|
||||
qreal descent() const {return _descent;}
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
GearRatioGraphItem::GearRatioGraphItem(const Graph &graph, GraphType type,
|
||||
int width, const QColor &color, QGraphicsItem *parent)
|
||||
: GraphItem(graph, type, width, color, parent)
|
||||
: GraphItem(graph, type, width, color, Qt::SolidLine, parent)
|
||||
{
|
||||
for (int i = 0; i < graph.size(); i++) {
|
||||
const GraphSegment &segment = graph.at(i);
|
||||
|
@ -5,13 +5,13 @@
|
||||
|
||||
|
||||
GraphItem::GraphItem(const Graph &graph, GraphType type, int width,
|
||||
const QColor &color, QGraphicsItem *parent)
|
||||
: GraphicsItem(parent), _graph(graph), _type(type)
|
||||
const QColor &color, Qt::PenStyle style, QGraphicsItem *parent)
|
||||
: GraphicsItem(parent), _graph(graph), _type(type), _secondaryGraph(0)
|
||||
{
|
||||
Q_ASSERT(_graph.isValid());
|
||||
|
||||
_units = Metric;
|
||||
_pen = QPen(color, width);
|
||||
_pen = QPen(color, width, style);
|
||||
_sx = 0; _sy = 0;
|
||||
_time = _graph.hasTime();
|
||||
setZValue(2.0);
|
||||
|
@ -12,8 +12,8 @@ class GraphItem : public QObject, public GraphicsItem
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GraphItem(const Graph &graph, GraphType type, int width, const QColor &color,
|
||||
QGraphicsItem *parent = 0);
|
||||
GraphItem(const Graph &graph, GraphType type, int width,
|
||||
const QColor &color, Qt::PenStyle style, QGraphicsItem *parent = 0);
|
||||
virtual ~GraphItem() {}
|
||||
|
||||
virtual QString info() const = 0;
|
||||
@ -35,6 +35,9 @@ public:
|
||||
void setWidth(int width);
|
||||
void setUnits(Units units) {_units = units;}
|
||||
|
||||
GraphItem *secondaryGraph() const {return _secondaryGraph;}
|
||||
void setSecondaryGraph(GraphItem *graph) {_secondaryGraph = graph;}
|
||||
|
||||
qreal yAtX(qreal x);
|
||||
qreal distanceAtTime(qreal time);
|
||||
|
||||
@ -69,6 +72,8 @@ private:
|
||||
qreal _sx, _sy;
|
||||
QPen _pen;
|
||||
bool _time;
|
||||
|
||||
GraphItem *_secondaryGraph;
|
||||
};
|
||||
|
||||
#endif // GRAPHITEM_H
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include <QSet>
|
||||
#include <QGraphicsScene>
|
||||
#include <QEvent>
|
||||
#include <QMouseEvent>
|
||||
@ -274,8 +275,8 @@ void GraphView::redraw(const QSizeF &size)
|
||||
rx = RangeF(bounds().left() * _xScale, bounds().right() * _xScale);
|
||||
ry = RangeF(bounds().top() * _yScale + _yOffset, bounds().bottom() * _yScale
|
||||
+ _yOffset);
|
||||
if (ry.size() < _minYRange)
|
||||
ry.resize(_minYRange);
|
||||
if (ry.size() < _minYRange * _yScale)
|
||||
ry.resize(_minYRange * _yScale);
|
||||
|
||||
_xAxis->setRange(rx);
|
||||
_yAxis->setRange(ry);
|
||||
@ -419,14 +420,16 @@ void GraphView::updateSliderInfo()
|
||||
{
|
||||
QLocale l(QLocale::system());
|
||||
qreal r = 0, y = 0;
|
||||
GraphItem *cardinal = (_graphs.count() == 1 || (_graphs.count() == 2
|
||||
&& _graphs.first()->secondaryGraph())) ? _graphs.first() : 0;
|
||||
|
||||
if (_graphs.count() == 1) {
|
||||
QRectF br(_graphs.first()->bounds());
|
||||
if (cardinal) {
|
||||
QRectF br(_bounds);
|
||||
if (br.height() < _minYRange)
|
||||
br.adjust(0, -(_minYRange/2 - br.height()/2), 0,
|
||||
_minYRange/2 - br.height()/2);
|
||||
|
||||
y = _graphs.first()->yAtX(_sliderPos);
|
||||
y = cardinal->yAtX(_sliderPos);
|
||||
r = (y - br.bottom()) / br.height();
|
||||
}
|
||||
|
||||
@ -436,11 +439,17 @@ void GraphView::updateSliderInfo()
|
||||
|
||||
_sliderInfo->setSide(s);
|
||||
_sliderInfo->setPos(QPointF(0, _slider->boundingRect().height() * r));
|
||||
_sliderInfo->setText(_graphType == Time ? Format::timeSpan(_sliderPos,
|
||||
QString xText(_graphType == Time ? Format::timeSpan(_sliderPos,
|
||||
bounds().width() > 3600) : l.toString(_sliderPos * _xScale, 'f', 1)
|
||||
+ UNIT_SPACE + _xUnits, (_graphs.count() > 1) ? QString()
|
||||
: l.toString(-y * _yScale + _yOffset, 'f', _precision) + UNIT_SPACE
|
||||
+ _yUnits);
|
||||
+ UNIT_SPACE + _xUnits);
|
||||
QString yText((!cardinal) ? QString() : l.toString(-y * _yScale + _yOffset,
|
||||
'f', _precision) + UNIT_SPACE + _yUnits);
|
||||
if (cardinal && cardinal->secondaryGraph()) {
|
||||
qreal delta = y - cardinal->secondaryGraph()->yAtX(_sliderPos);
|
||||
yText += " " + QChar(0x0394) + l.toString(-delta * _yScale + _yOffset,
|
||||
'f', _precision) + UNIT_SPACE + _yUnits;
|
||||
}
|
||||
_sliderInfo->setText(xText, yText);
|
||||
}
|
||||
|
||||
void GraphView::emitSliderPositionChanged(const QPointF &pos)
|
||||
@ -486,8 +495,23 @@ void GraphView::setPalette(const Palette &palette)
|
||||
_palette = palette;
|
||||
_palette.reset();
|
||||
|
||||
for (int i = 0; i < _graphs.count(); i++)
|
||||
_graphs.at(i)->setColor(_palette.nextColor());
|
||||
QSet<GraphItem*> secondary;
|
||||
for (int i = 0; i < _graphs.count(); i++) {
|
||||
GraphItem *g = _graphs[i];
|
||||
if (g->secondaryGraph())
|
||||
secondary.insert(g->secondaryGraph());
|
||||
}
|
||||
|
||||
for (int i = 0; i < _graphs.count(); i++) {
|
||||
GraphItem *g = _graphs[i];
|
||||
if (secondary.contains(g))
|
||||
continue;
|
||||
|
||||
QColor color(_palette.nextColor());
|
||||
g->setColor(color);
|
||||
if (g->secondaryGraph())
|
||||
g->secondaryGraph()->setColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphView::setGraphWidth(int width)
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
#include <QGraphicsView>
|
||||
#include <QList>
|
||||
#include <QSet>
|
||||
#include "data/graph.h"
|
||||
#include "palette.h"
|
||||
#include "units.h"
|
||||
|
257
src/GUI/gui.cpp
257
src/GUI/gui.cpp
@ -51,6 +51,7 @@
|
||||
#include "graphtab.h"
|
||||
#include "graphitem.h"
|
||||
#include "pathitem.h"
|
||||
#include "mapaction.h"
|
||||
#include "gui.h"
|
||||
|
||||
|
||||
@ -58,7 +59,6 @@
|
||||
|
||||
GUI::GUI()
|
||||
{
|
||||
loadMaps();
|
||||
loadPOIs();
|
||||
|
||||
createMapView();
|
||||
@ -106,24 +106,13 @@ GUI::GUI()
|
||||
updateStatusBarInfo();
|
||||
}
|
||||
|
||||
void GUI::loadMaps()
|
||||
{
|
||||
_ml = new MapList(this);
|
||||
QString mapDir(ProgramPaths::mapDir());
|
||||
|
||||
if (!mapDir.isNull() && !_ml->loadDir(mapDir))
|
||||
qWarning("%s", qPrintable(_ml->errorPath() + ": " + _ml->errorString()));
|
||||
|
||||
_map = new EmptyMap(this);
|
||||
}
|
||||
|
||||
void GUI::loadPOIs()
|
||||
{
|
||||
_poi = new POI(this);
|
||||
QString poiDir(ProgramPaths::poiDir());
|
||||
|
||||
if (!poiDir.isNull() && !_poi->loadDir(poiDir))
|
||||
qWarning("%s", qPrintable(_poi->errorString()));
|
||||
QString poiDir(ProgramPaths::poiDir());
|
||||
if (!poiDir.isNull())
|
||||
_poi->loadDir(poiDir);
|
||||
}
|
||||
|
||||
void GUI::createBrowser()
|
||||
@ -134,40 +123,56 @@ void GUI::createBrowser()
|
||||
|
||||
void GUI::createMapActions()
|
||||
{
|
||||
_mapsSignalMapper = new QSignalMapper(this);
|
||||
_mapsActionGroup = new QActionGroup(this);
|
||||
_mapsActionGroup->setExclusive(true);
|
||||
|
||||
for (int i = 0; i < _ml->maps().count(); i++)
|
||||
createMapAction(_ml->maps().at(i));
|
||||
QString mapDir(ProgramPaths::mapDir());
|
||||
if (mapDir.isNull())
|
||||
return;
|
||||
|
||||
connect(_mapsSignalMapper, SIGNAL(mapped(int)), this,
|
||||
SLOT(mapChanged(int)));
|
||||
QString unused;
|
||||
QList<Map*> maps(MapList::loadMaps(mapDir, unused));
|
||||
for (int i = 0; i < maps.count(); i++) {
|
||||
MapAction *a = createMapAction(maps.at(i));
|
||||
connect(a, SIGNAL(loaded()), this, SLOT(mapInitialized()));
|
||||
}
|
||||
}
|
||||
|
||||
QAction *GUI::createMapAction(const Map *map)
|
||||
MapAction *GUI::createMapAction(Map *map)
|
||||
{
|
||||
QAction *a = new QAction(map->name(), this);
|
||||
MapAction *a = new MapAction(map);
|
||||
a->setMenuRole(QAction::NoRole);
|
||||
a->setCheckable(true);
|
||||
a->setActionGroup(_mapsActionGroup);
|
||||
|
||||
_mapActions.append(a);
|
||||
_mapsSignalMapper->setMapping(a, _mapActions.size() - 1);
|
||||
connect(a, SIGNAL(triggered()), _mapsSignalMapper, SLOT(map()));
|
||||
connect(a, SIGNAL(triggered()), this, SLOT(mapChanged()));
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
void GUI::mapInitialized()
|
||||
{
|
||||
MapAction *action = static_cast<MapAction*>(QObject::sender());
|
||||
Map *map = action->data().value<Map*>();
|
||||
|
||||
if (map->isValid()) {
|
||||
if (!_mapsActionGroup->checkedAction())
|
||||
action->trigger();
|
||||
_showMapAction->setEnabled(true);
|
||||
_clearMapCacheAction->setEnabled(true);
|
||||
} else {
|
||||
qWarning("%s: %s", qPrintable(map->name()), qPrintable(map->errorString()));
|
||||
action->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
void GUI::createPOIFilesActions()
|
||||
{
|
||||
_poiFilesSignalMapper = new QSignalMapper(this);
|
||||
connect(_poiFilesSignalMapper, SIGNAL(mapped(int)), this,
|
||||
SLOT(poiFileChecked(int)));
|
||||
|
||||
for (int i = 0; i < _poi->files().count(); i++)
|
||||
createPOIFileAction(_poi->files().at(i));
|
||||
|
||||
connect(_poiFilesSignalMapper, SIGNAL(mapped(int)), this,
|
||||
SLOT(poiFileChecked(int)));
|
||||
}
|
||||
|
||||
QAction *GUI::createPOIFileAction(const QString &fileName)
|
||||
@ -243,7 +248,7 @@ void GUI::createActions()
|
||||
_reloadFileAction->setMenuRole(QAction::NoRole);
|
||||
_reloadFileAction->setShortcut(RELOAD_SHORTCUT);
|
||||
_reloadFileAction->setActionGroup(_fileActionGroup);
|
||||
connect(_reloadFileAction, SIGNAL(triggered()), this, SLOT(reloadFile()));
|
||||
connect(_reloadFileAction, SIGNAL(triggered()), this, SLOT(reloadFiles()));
|
||||
addAction(_reloadFileAction);
|
||||
_statisticsAction = new QAction(tr("Statistics..."), this);
|
||||
_statisticsAction->setMenuRole(QAction::NoRole);
|
||||
@ -281,8 +286,10 @@ void GUI::createActions()
|
||||
createPOIFilesActions();
|
||||
|
||||
// Map actions
|
||||
createMapActions();
|
||||
_showMapAction = new QAction(QIcon(SHOW_MAP_ICON), tr("Show map"),
|
||||
this);
|
||||
_showMapAction->setEnabled(false);
|
||||
_showMapAction->setMenuRole(QAction::NoRole);
|
||||
_showMapAction->setCheckable(true);
|
||||
_showMapAction->setShortcut(SHOW_MAP_SHORTCUT);
|
||||
@ -294,10 +301,10 @@ void GUI::createActions()
|
||||
_loadMapAction->setMenuRole(QAction::NoRole);
|
||||
connect(_loadMapAction, SIGNAL(triggered()), this, SLOT(loadMap()));
|
||||
_clearMapCacheAction = new QAction(tr("Clear tile cache"), this);
|
||||
_clearMapCacheAction->setEnabled(false);
|
||||
_clearMapCacheAction->setMenuRole(QAction::NoRole);
|
||||
connect(_clearMapCacheAction, SIGNAL(triggered()), _mapView,
|
||||
SLOT(clearMapCache()));
|
||||
createMapActions();
|
||||
_nextMapAction = new QAction(tr("Next map"), this);
|
||||
_nextMapAction->setMenuRole(QAction::NoRole);
|
||||
_nextMapAction->setShortcut(NEXT_MAP_SHORTCUT);
|
||||
@ -308,10 +315,6 @@ void GUI::createActions()
|
||||
_prevMapAction->setShortcut(PREV_MAP_SHORTCUT);
|
||||
connect(_prevMapAction, SIGNAL(triggered()), this, SLOT(prevMap()));
|
||||
addAction(_prevMapAction);
|
||||
if (_ml->maps().isEmpty()) {
|
||||
_showMapAction->setEnabled(false);
|
||||
_clearMapCacheAction->setEnabled(false);
|
||||
}
|
||||
_showCoordinatesAction = new QAction(tr("Show cursor coordinates"), this);
|
||||
_showCoordinatesAction->setMenuRole(QAction::NoRole);
|
||||
_showCoordinatesAction->setCheckable(true);
|
||||
@ -506,7 +509,7 @@ void GUI::createMenus()
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
_mapMenu = menuBar()->addMenu(tr("&Map"));
|
||||
_mapMenu->addActions(_mapActions);
|
||||
_mapMenu->addActions(_mapsActionGroup->actions());
|
||||
_mapsEnd = _mapMenu->addSeparator();
|
||||
_mapMenu->addAction(_loadMapAction);
|
||||
_mapMenu->addAction(_clearMapCacheAction);
|
||||
@ -608,6 +611,7 @@ void GUI::createToolBars()
|
||||
|
||||
void GUI::createMapView()
|
||||
{
|
||||
_map = new EmptyMap(this);
|
||||
_mapView = new MapView(_map, _poi, this);
|
||||
_mapView->setSizePolicy(QSizePolicy(QSizePolicy::Ignored,
|
||||
QSizePolicy::Expanding));
|
||||
@ -787,7 +791,12 @@ bool GUI::loadFile(const QString &fileName)
|
||||
_trackDistance += track.distance();
|
||||
_time += track.time();
|
||||
_movingTime += track.movingTime();
|
||||
const QDate &date = track.date().date();
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
const QDateTime date = track.date().toTimeZone(
|
||||
_options.timeZone.zone());
|
||||
#else // ENABLE_TIMEZONES
|
||||
const QDateTime &date = track.date();
|
||||
#endif // ENABLE_TIMEZONES
|
||||
if (_dateRange.first.isNull() || _dateRange.first > date)
|
||||
_dateRange.first = date;
|
||||
if (_dateRange.second.isNull() || _dateRange.second < date)
|
||||
@ -905,9 +914,14 @@ void GUI::openOptions()
|
||||
Track::action(options.option); \
|
||||
reload = true; \
|
||||
}
|
||||
#define SET_DATA_OPTION(option, action) \
|
||||
#define SET_ROUTE_OPTION(option, action) \
|
||||
if (options.option != _options.option) { \
|
||||
Data::action(options.option); \
|
||||
Route::action(options.option); \
|
||||
reload = true; \
|
||||
}
|
||||
#define SET_WAYPOINT_OPTION(option, action) \
|
||||
if (options.option != _options.option) { \
|
||||
Waypoint::action(options.option); \
|
||||
reload = true; \
|
||||
}
|
||||
|
||||
@ -953,13 +967,18 @@ void GUI::openOptions()
|
||||
SET_TRACK_OPTION(pauseSpeed, setPauseSpeed);
|
||||
SET_TRACK_OPTION(pauseInterval, setPauseInterval);
|
||||
SET_TRACK_OPTION(useReportedSpeed, useReportedSpeed);
|
||||
SET_TRACK_OPTION(dataUseDEM, useDEM);
|
||||
SET_TRACK_OPTION(showSecondaryElevation, showSecondaryElevation);
|
||||
SET_TRACK_OPTION(showSecondarySpeed, showSecondarySpeed);
|
||||
|
||||
SET_DATA_OPTION(dataUseDEM, useDEM);
|
||||
SET_ROUTE_OPTION(dataUseDEM, useDEM);
|
||||
SET_ROUTE_OPTION(showSecondaryElevation, showSecondaryElevation);
|
||||
|
||||
SET_WAYPOINT_OPTION(dataUseDEM, useDEM);
|
||||
SET_WAYPOINT_OPTION(showSecondaryElevation, showSecondaryElevation);
|
||||
|
||||
if (options.poiRadius != _options.poiRadius)
|
||||
_poi->setRadius(options.poiRadius);
|
||||
if (options.poiUseDEM != _options.poiUseDEM)
|
||||
_poi->useDEM(options.poiUseDEM);
|
||||
|
||||
if (options.pixmapCache != _options.pixmapCache)
|
||||
QPixmapCache::setCacheLimit(options.pixmapCache * 1024);
|
||||
@ -976,9 +995,16 @@ void GUI::openOptions()
|
||||
_mapView->setDevicePixelRatio(devicePixelRatioF(),
|
||||
options.hidpiMap ? devicePixelRatioF() : 1.0);
|
||||
#endif // ENABLE_HIDPI
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
if (options.timeZone != _options.timeZone) {
|
||||
_mapView->setTimeZone(options.timeZone.zone());
|
||||
_dateRange.first = _dateRange.first.toTimeZone(options.timeZone.zone());
|
||||
_dateRange.second = _dateRange.second.toTimeZone(options.timeZone.zone());
|
||||
}
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
if (reload)
|
||||
reloadFile();
|
||||
reloadFiles();
|
||||
|
||||
_options = options;
|
||||
}
|
||||
@ -1171,7 +1197,7 @@ void GUI::plot(QPrinter *printer)
|
||||
}
|
||||
}
|
||||
|
||||
void GUI::reloadFile()
|
||||
void GUI::reloadFiles()
|
||||
{
|
||||
_trackCount = 0;
|
||||
_routeCount = 0;
|
||||
@ -1181,7 +1207,7 @@ void GUI::reloadFile()
|
||||
_routeDistance = 0;
|
||||
_time = 0;
|
||||
_movingTime = 0;
|
||||
_dateRange = DateRange(QDate(), QDate());
|
||||
_dateRange = DateTimeRange(QDateTime(), QDateTime());
|
||||
_pathName = QString();
|
||||
|
||||
for (int i = 0; i < _tabs.count(); i++)
|
||||
@ -1215,7 +1241,7 @@ void GUI::closeFiles()
|
||||
_routeDistance = 0;
|
||||
_time = 0;
|
||||
_movingTime = 0;
|
||||
_dateRange = DateRange(QDate(), QDate());
|
||||
_dateRange = DateTimeRange(QDateTime(), QDateTime());
|
||||
_pathName = QString();
|
||||
|
||||
_sliderPos = 0;
|
||||
@ -1322,25 +1348,49 @@ void GUI::loadMap()
|
||||
|
||||
bool GUI::loadMap(const QString &fileName)
|
||||
{
|
||||
// On OS X fileName may be a directory!
|
||||
|
||||
if (fileName.isEmpty())
|
||||
return false;
|
||||
|
||||
QFileInfo fi(fileName);
|
||||
bool res = fi.isDir() ? _ml->loadDir(fileName) : _ml->loadFile(fileName);
|
||||
QString error;
|
||||
QList<Map*> maps = MapList::loadMaps(fileName, error);
|
||||
if (maps.isEmpty()) {
|
||||
error = tr("Error loading map:") + "\n\n"
|
||||
+ fileName + "\n\n" + error;
|
||||
QMessageBox::critical(this, APP_NAME, error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (res) {
|
||||
QAction *a = createMapAction(_ml->maps().last());
|
||||
for (int i = 0; i < maps.size(); i++) {
|
||||
Map *map = maps.at(i);
|
||||
MapAction *a = createMapAction(map);
|
||||
_mapMenu->insertAction(_mapsEnd, a);
|
||||
if (map->isReady()) {
|
||||
a->trigger();
|
||||
_showMapAction->setEnabled(true);
|
||||
_clearMapCacheAction->setEnabled(true);
|
||||
} else
|
||||
connect(a, SIGNAL(loaded()), this, SLOT(mapLoaded()));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GUI::mapLoaded()
|
||||
{
|
||||
MapAction *action = static_cast<MapAction*>(QObject::sender());
|
||||
Map *map = action->data().value<Map*>();
|
||||
|
||||
if (map->isValid()) {
|
||||
action->trigger();
|
||||
_showMapAction->setEnabled(true);
|
||||
_clearMapCacheAction->setEnabled(true);
|
||||
a->trigger();
|
||||
return true;
|
||||
} else {
|
||||
QString error = tr("Error loading map:") + "\n\n"
|
||||
+ fileName + "\n\n" + _ml->errorString();
|
||||
+ map->name() + "\n\n" + map->errorString();
|
||||
QMessageBox::critical(this, APP_NAME, error);
|
||||
|
||||
return false;
|
||||
action->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1382,31 +1432,42 @@ void GUI::updateWindowTitle()
|
||||
setWindowTitle(APP_NAME);
|
||||
}
|
||||
|
||||
void GUI::mapChanged(int index)
|
||||
void GUI::mapChanged()
|
||||
{
|
||||
_map = _ml->maps().at(index);
|
||||
_map = _mapsActionGroup->checkedAction()->data().value<Map*>();
|
||||
_mapView->setMap(_map);
|
||||
}
|
||||
|
||||
void GUI::nextMap()
|
||||
{
|
||||
if (_ml->maps().count() < 2)
|
||||
QAction *checked = _mapsActionGroup->checkedAction();
|
||||
if (!checked)
|
||||
return;
|
||||
|
||||
int next = (_ml->maps().indexOf(_map) + 1) % _ml->maps().count();
|
||||
_mapActions.at(next)->setChecked(true);
|
||||
mapChanged(next);
|
||||
QList<QAction*> maps = _mapsActionGroup->actions();
|
||||
for (int i = 1; i < maps.size(); i++) {
|
||||
int next = (maps.indexOf(checked) + i) % maps.count();
|
||||
if (maps.at(next)->isEnabled()) {
|
||||
maps.at(next)->trigger();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GUI::prevMap()
|
||||
{
|
||||
if (_ml->maps().count() < 2)
|
||||
QAction *checked = _mapsActionGroup->checkedAction();
|
||||
if (!checked)
|
||||
return;
|
||||
|
||||
int prev = (_ml->maps().indexOf(_map) + _ml->maps().count() - 1)
|
||||
% _ml->maps().count();
|
||||
_mapActions.at(prev)->setChecked(true);
|
||||
mapChanged(prev);
|
||||
QList<QAction*> maps = _mapsActionGroup->actions();
|
||||
for (int i = 1; i < maps.size(); i++) {
|
||||
int prev = (maps.indexOf(checked) + maps.count() - i) % maps.count();
|
||||
if (maps.at(prev)->isEnabled()) {
|
||||
maps.at(prev)->trigger();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GUI::poiFileChecked(int index)
|
||||
@ -1812,10 +1873,19 @@ void GUI::writeSettings()
|
||||
settings.setValue(USE_REPORTED_SPEED_SETTING, _options.useReportedSpeed);
|
||||
if (_options.dataUseDEM != DATA_USE_DEM_DEFAULT)
|
||||
settings.setValue(DATA_USE_DEM_SETTING, _options.dataUseDEM);
|
||||
if (_options.showSecondaryElevation != SHOW_SECONDARY_ELEVATION_DEFAULT)
|
||||
settings.setValue(SHOW_SECONDARY_ELEVATION_SETTING,
|
||||
_options.showSecondaryElevation);
|
||||
if (_options.showSecondarySpeed != SHOW_SECONDARY_SPEED_DEFAULT)
|
||||
settings.setValue(SHOW_SECONDARY_SPEED_SETTING,
|
||||
_options.showSecondarySpeed);
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
if (_options.timeZone != TimeZoneInfo())
|
||||
settings.setValue(TIME_ZONE_SETTING, QVariant::fromValue(
|
||||
_options.timeZone));
|
||||
#endif // ENABLE_TIMEZONES
|
||||
if (_options.poiRadius != POI_RADIUS_DEFAULT)
|
||||
settings.setValue(POI_RADIUS_SETTING, _options.poiRadius);
|
||||
if (_options.poiUseDEM != POI_USE_DEM_DEFAULT)
|
||||
settings.setValue(POI_USE_DEM_SETTING, _options.poiUseDEM);
|
||||
if (_options.useOpenGL != USE_OPENGL_DEFAULT)
|
||||
settings.setValue(USE_OPENGL_SETTING, _options.useOpenGL);
|
||||
#ifdef ENABLE_HTTP2
|
||||
@ -1899,9 +1969,11 @@ void GUI::readSettings()
|
||||
_showMapAction->setChecked(true);
|
||||
else
|
||||
_mapView->showMap(false);
|
||||
if (_ml->maps().count()) {
|
||||
int index = mapIndex(settings.value(CURRENT_MAP_SETTING).toString());
|
||||
_mapActions.at(index)->trigger();
|
||||
QAction *ma = mapAction(settings.value(CURRENT_MAP_SETTING).toString());
|
||||
if (ma) {
|
||||
ma->trigger();
|
||||
_showMapAction->setEnabled(true);
|
||||
_clearMapCacheAction->setEnabled(true);
|
||||
}
|
||||
if (settings.value(SHOW_COORDINATES_SETTING, SHOW_COORDINATES_DEFAULT)
|
||||
.toBool()) {
|
||||
@ -2078,14 +2150,21 @@ void GUI::readSettings()
|
||||
USE_REPORTED_SPEED_DEFAULT).toBool();
|
||||
_options.dataUseDEM = settings.value(DATA_USE_DEM_SETTING,
|
||||
DATA_USE_DEM_DEFAULT).toBool();
|
||||
_options.showSecondaryElevation = settings.value(
|
||||
SHOW_SECONDARY_ELEVATION_SETTING,
|
||||
SHOW_SECONDARY_ELEVATION_DEFAULT).toBool();
|
||||
_options.showSecondarySpeed = settings.value(
|
||||
SHOW_SECONDARY_SPEED_SETTING,
|
||||
SHOW_SECONDARY_SPEED_DEFAULT).toBool();
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
_options.timeZone = settings.value(TIME_ZONE_SETTING).value<TimeZoneInfo>();
|
||||
#endif // ENABLE_TIMEZONES
|
||||
_options.automaticPause = settings.value(AUTOMATIC_PAUSE_SETTING,
|
||||
AUTOMATIC_PAUSE_DEFAULT).toBool();
|
||||
_options.pauseInterval = settings.value(PAUSE_INTERVAL_SETTING,
|
||||
PAUSE_INTERVAL_DEFAULT).toInt();
|
||||
_options.poiRadius = settings.value(POI_RADIUS_SETTING, POI_RADIUS_DEFAULT)
|
||||
.toInt();
|
||||
_options.poiUseDEM = settings.value(POI_USE_DEM_SETTING,
|
||||
POI_USE_DEM_DEFAULT).toBool();
|
||||
_options.useOpenGL = settings.value(USE_OPENGL_SETTING, USE_OPENGL_DEFAULT)
|
||||
.toBool();
|
||||
#ifdef ENABLE_HTTP2
|
||||
@ -2144,6 +2223,9 @@ void GUI::readSettings()
|
||||
_options.hidpiMap ? devicePixelRatioF() : 1.0);
|
||||
#endif // ENABLE_HIDPI
|
||||
_mapView->setProjection(_options.projection);
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
_mapView->setTimeZone(_options.timeZone.zone());
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
for (int i = 0; i < _tabs.count(); i++) {
|
||||
_tabs.at(i)->setPalette(_options.palette);
|
||||
@ -2165,21 +2247,38 @@ void GUI::readSettings()
|
||||
Track::setPauseSpeed(_options.pauseSpeed);
|
||||
Track::setPauseInterval(_options.pauseInterval);
|
||||
Track::useReportedSpeed(_options.useReportedSpeed);
|
||||
Data::useDEM(_options.dataUseDEM);
|
||||
Track::useDEM(_options.dataUseDEM);
|
||||
Track::showSecondaryElevation(_options.showSecondaryElevation);
|
||||
Track::showSecondarySpeed(_options.showSecondarySpeed);
|
||||
Route::useDEM(_options.dataUseDEM);
|
||||
Route::showSecondaryElevation(_options.showSecondaryElevation);
|
||||
Waypoint::useDEM(_options.dataUseDEM);
|
||||
Waypoint::showSecondaryElevation(_options.showSecondaryElevation);
|
||||
|
||||
_poi->setRadius(_options.poiRadius);
|
||||
_poi->useDEM(_options.poiUseDEM);
|
||||
|
||||
QPixmapCache::setCacheLimit(_options.pixmapCache * 1024);
|
||||
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
int GUI::mapIndex(const QString &name)
|
||||
QAction *GUI::mapAction(const QString &name)
|
||||
{
|
||||
for (int i = 0; i < _ml->maps().count(); i++)
|
||||
if (_ml->maps().at(i)->name() == name)
|
||||
return i;
|
||||
QList<QAction *> maps = _mapsActionGroup->actions();
|
||||
|
||||
// Last map
|
||||
for (int i = 0; i < maps.count(); i++) {
|
||||
Map *map = maps.at(i)->data().value<Map*>();
|
||||
if (map->name() == name && map->isReady())
|
||||
return maps.at(i);
|
||||
}
|
||||
|
||||
// Any usable map
|
||||
for (int i = 0; i < maps.count(); i++) {
|
||||
Map *map = maps.at(i)->data().value<Map*>();
|
||||
if (map->isReady())
|
||||
return maps.at(i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -26,9 +26,9 @@ class FileBrowser;
|
||||
class GraphTab;
|
||||
class MapView;
|
||||
class Map;
|
||||
class MapList;
|
||||
class POI;
|
||||
class QScreen;
|
||||
class MapAction;
|
||||
|
||||
class GUI : public QMainWindow
|
||||
{
|
||||
@ -48,7 +48,7 @@ private slots:
|
||||
void exportFile();
|
||||
void openFile();
|
||||
void closeAll();
|
||||
void reloadFile();
|
||||
void reloadFiles();
|
||||
void statistics();
|
||||
void openPOIFile();
|
||||
void closePOIFiles();
|
||||
@ -64,7 +64,7 @@ private slots:
|
||||
void prevMap();
|
||||
void openOptions();
|
||||
|
||||
void mapChanged(int);
|
||||
void mapChanged();
|
||||
void graphChanged(int);
|
||||
void poiFileChecked(int);
|
||||
|
||||
@ -88,16 +88,18 @@ private slots:
|
||||
void screenChanged(QScreen *screen);
|
||||
void logicalDotsPerInchChanged(qreal dpi);
|
||||
|
||||
private:
|
||||
typedef QPair<QDate, QDate> DateRange;
|
||||
void mapLoaded();
|
||||
void mapInitialized();
|
||||
|
||||
private:
|
||||
typedef QPair<QDateTime, QDateTime> DateTimeRange;
|
||||
|
||||
void loadMaps();
|
||||
void loadPOIs();
|
||||
void closeFiles();
|
||||
void plot(QPrinter *printer);
|
||||
|
||||
QAction *createPOIFileAction(const QString &fileName);
|
||||
QAction *createMapAction(const Map *map);
|
||||
MapAction *createMapAction(Map *map);
|
||||
void createPOIFilesActions();
|
||||
void createMapActions();
|
||||
void createActions();
|
||||
@ -127,7 +129,7 @@ private:
|
||||
qreal distance() const;
|
||||
qreal time() const;
|
||||
qreal movingTime() const;
|
||||
int mapIndex(const QString &name);
|
||||
QAction *mapAction(const QString &name);
|
||||
void readSettings();
|
||||
void writeSettings();
|
||||
|
||||
@ -196,11 +198,9 @@ private:
|
||||
QAction *_showCoordinatesAction;
|
||||
QAction *_openOptionsAction;
|
||||
QAction *_mapsEnd;
|
||||
QList<QAction*> _mapActions;
|
||||
QList<QAction*> _poiFilesActions;
|
||||
|
||||
QList<QAction*> _poiFilesActions;
|
||||
QSignalMapper *_poiFilesSignalMapper;
|
||||
QSignalMapper *_mapsSignalMapper;
|
||||
|
||||
QLabel *_fileNameLabel;
|
||||
QLabel *_distanceLabel;
|
||||
@ -212,7 +212,6 @@ private:
|
||||
QList<GraphTab*> _tabs;
|
||||
|
||||
POI *_poi;
|
||||
MapList *_ml;
|
||||
Map *_map;
|
||||
|
||||
FileBrowser *_browser;
|
||||
@ -221,7 +220,7 @@ private:
|
||||
int _trackCount, _routeCount, _areaCount, _waypointCount;
|
||||
qreal _trackDistance, _routeDistance;
|
||||
qreal _time, _movingTime;
|
||||
DateRange _dateRange;
|
||||
DateTimeRange _dateRange;
|
||||
QString _pathName;
|
||||
|
||||
qreal _sliderPos;
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
HeartRateGraphItem::HeartRateGraphItem(const Graph &graph, GraphType type,
|
||||
int width, const QColor &color, QGraphicsItem *parent)
|
||||
: GraphItem(graph, type, width, color, parent)
|
||||
: GraphItem(graph, type, width, color, Qt::SolidLine, parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
32
src/GUI/mapaction.h
Normal file
32
src/GUI/mapaction.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef MAPACTION_H
|
||||
#define MAPACTION_H
|
||||
|
||||
#include <QAction>
|
||||
#include "map/map.h"
|
||||
|
||||
class MapAction : public QAction
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MapAction(Map *map, QObject *parent = 0) : QAction(map->name(), parent)
|
||||
{
|
||||
map->setParent(this);
|
||||
setData(QVariant::fromValue(map));
|
||||
setEnabled(map->isReady());
|
||||
connect(map, SIGNAL(mapLoaded()), this, SLOT(mapLoaded()));
|
||||
}
|
||||
|
||||
signals:
|
||||
void loaded();
|
||||
|
||||
private slots:
|
||||
void mapLoaded()
|
||||
{
|
||||
Map *map = data().value<Map*>();
|
||||
setEnabled(map->isValid());
|
||||
emit loaded();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // MAPACTION_H
|
@ -2,7 +2,6 @@
|
||||
#include <QGraphicsScene>
|
||||
#include <QWheelEvent>
|
||||
#include <QApplication>
|
||||
#include <QPixmapCache>
|
||||
#include <QScrollBar>
|
||||
#include "data/poi.h"
|
||||
#include "data/data.h"
|
||||
@ -55,13 +54,11 @@ MapView::MapView(Map *map, POI *poi, QWidget *parent)
|
||||
_map = map;
|
||||
_map->load();
|
||||
_map->setProjection(_projection);
|
||||
connect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
|
||||
connect(_map, SIGNAL(tilesLoaded()), this, SLOT(reloadMap()));
|
||||
|
||||
_poi = poi;
|
||||
connect(_poi, SIGNAL(pointsChanged()), this, SLOT(updatePOI()));
|
||||
|
||||
_units = Metric;
|
||||
_coordinatesFormat = DecimalDegrees;
|
||||
_mapOpacity = 1.0;
|
||||
_backgroundColor = Qt::white;
|
||||
_markerColor = Qt::red;
|
||||
@ -123,7 +120,6 @@ PathItem *MapView::addTrack(const Track &track)
|
||||
ti->setColor(_palette.nextColor());
|
||||
ti->setWidth(_trackWidth);
|
||||
ti->setStyle(_trackStyle);
|
||||
ti->setUnits(_units);
|
||||
ti->setVisible(_showTracks);
|
||||
ti->setDigitalZoom(_digitalZoom);
|
||||
ti->setMarkerColor(_markerColor);
|
||||
@ -150,8 +146,6 @@ PathItem *MapView::addRoute(const Route &route)
|
||||
ri->setColor(_palette.nextColor());
|
||||
ri->setWidth(_routeWidth);
|
||||
ri->setStyle(_routeStyle);
|
||||
ri->setUnits(_units);
|
||||
ri->setCoordinatesFormat(_coordinatesFormat);
|
||||
ri->setVisible(_showRoutes);
|
||||
ri->showWaypoints(_showRouteWaypoints);
|
||||
ri->showWaypointLabels(_showWaypointLabels);
|
||||
@ -201,7 +195,6 @@ void MapView::addWaypoints(const QVector<Waypoint> &waypoints)
|
||||
wi->setSize(_waypointSize);
|
||||
wi->setColor(_waypointColor);
|
||||
wi->showLabel(_showWaypointLabels);
|
||||
wi->setToolTipFormat(_units, _coordinatesFormat);
|
||||
wi->setVisible(_showWaypoints);
|
||||
wi->setDigitalZoom(_digitalZoom);
|
||||
_scene->addItem(wi);
|
||||
@ -317,7 +310,7 @@ void MapView::setMap(Map *map)
|
||||
RectC cr(_map->xy2ll(vr.topLeft()), _map->xy2ll(vr.bottomRight()));
|
||||
|
||||
_map->unload();
|
||||
disconnect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
|
||||
disconnect(_map, SIGNAL(tilesLoaded()), this, SLOT(reloadMap()));
|
||||
|
||||
_map = map;
|
||||
_map->load();
|
||||
@ -325,7 +318,7 @@ void MapView::setMap(Map *map)
|
||||
#ifdef ENABLE_HIDPI
|
||||
_map->setDevicePixelRatio(_deviceRatio, _mapRatio);
|
||||
#endif // ENABLE_HIDPI
|
||||
connect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
|
||||
connect(_map, SIGNAL(tilesLoaded()), this, SLOT(reloadMap()));
|
||||
|
||||
digitalZoom(0);
|
||||
|
||||
@ -351,7 +344,6 @@ void MapView::setMap(Map *map)
|
||||
centerOn(nc);
|
||||
|
||||
reloadMap();
|
||||
QPixmapCache::clear();
|
||||
}
|
||||
|
||||
void MapView::setPOI(POI *poi)
|
||||
@ -403,7 +395,6 @@ void MapView::addPOI(const QList<Waypoint> &waypoints)
|
||||
pi->showLabel(_showPOILabels);
|
||||
pi->setVisible(_showPOI);
|
||||
pi->setDigitalZoom(_digitalZoom);
|
||||
pi->setToolTipFormat(_units, _coordinatesFormat);
|
||||
_scene->addItem(pi);
|
||||
|
||||
_pois.insert(SearchPointer<Waypoint>(&(pi->waypoint())), pi);
|
||||
@ -412,51 +403,38 @@ void MapView::addPOI(const QList<Waypoint> &waypoints)
|
||||
|
||||
void MapView::setUnits(Units units)
|
||||
{
|
||||
if (_units == units)
|
||||
return;
|
||||
|
||||
_units = units;
|
||||
|
||||
_mapScale->setUnits(_units);
|
||||
WaypointItem::setUnits(units);
|
||||
PathItem::setUnits(units);
|
||||
|
||||
for (int i = 0; i < _tracks.count(); i++)
|
||||
_tracks[i]->setUnits(_units);
|
||||
_tracks[i]->updateTicks();
|
||||
for (int i = 0; i < _routes.count(); i++)
|
||||
_routes[i]->setUnits(_units);
|
||||
for (int i = 0; i < _waypoints.size(); i++)
|
||||
_waypoints.at(i)->setToolTipFormat(_units, _coordinatesFormat);
|
||||
_routes[i]->updateTicks();
|
||||
|
||||
for (POIHash::const_iterator it = _pois.constBegin();
|
||||
it != _pois.constEnd(); it++)
|
||||
it.value()->setToolTipFormat(_units, _coordinatesFormat);
|
||||
_mapScale->setUnits(units);
|
||||
}
|
||||
|
||||
void MapView::setCoordinatesFormat(CoordinatesFormat format)
|
||||
{
|
||||
if (_coordinatesFormat == format)
|
||||
return;
|
||||
WaypointItem::setCoordinatesFormat(format);
|
||||
|
||||
_coordinatesFormat = format;
|
||||
_coordinates->setFormat(format);
|
||||
}
|
||||
|
||||
_coordinates->setFormat(_coordinatesFormat);
|
||||
|
||||
for (int i = 0; i < _waypoints.count(); i++)
|
||||
_waypoints.at(i)->setToolTipFormat(_units, _coordinatesFormat);
|
||||
for (int i = 0; i < _routes.count(); i++)
|
||||
_routes[i]->setCoordinatesFormat(_coordinatesFormat);
|
||||
|
||||
for (POIHash::const_iterator it = _pois.constBegin();
|
||||
it != _pois.constEnd(); it++)
|
||||
it.value()->setToolTipFormat(_units, _coordinatesFormat);
|
||||
void MapView::setTimeZone(const QTimeZone &zone)
|
||||
{
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
WaypointItem::setTimeZone(zone);
|
||||
PathItem::setTimeZone(zone);
|
||||
#else // ENABLE_TIMEZONES
|
||||
Q_UNUSED(zone);
|
||||
#endif // ENABLE_TIMEZONES
|
||||
}
|
||||
|
||||
void MapView::clearMapCache()
|
||||
{
|
||||
_map->clearCache();
|
||||
|
||||
fitMapZoom();
|
||||
rescale();
|
||||
centerOn(contentCenter());
|
||||
reloadMap();
|
||||
}
|
||||
|
||||
void MapView::digitalZoom(int zoom)
|
||||
@ -982,7 +960,6 @@ void MapView::setDevicePixelRatio(qreal deviceRatio, qreal mapRatio)
|
||||
|
||||
_deviceRatio = deviceRatio;
|
||||
_mapRatio = mapRatio;
|
||||
QPixmapCache::clear();
|
||||
|
||||
QRectF vr(mapToScene(viewport()->rect()).boundingRect()
|
||||
.intersected(_map->bounds()));
|
||||
|
@ -31,6 +31,7 @@ class GraphItem;
|
||||
class AreaItem;
|
||||
class Area;
|
||||
class GraphicsScene;
|
||||
class QTimeZone;
|
||||
|
||||
class MapView : public QGraphicsView
|
||||
{
|
||||
@ -83,6 +84,7 @@ public slots:
|
||||
void showTicks(bool show);
|
||||
void clearMapCache();
|
||||
void setCoordinatesFormat(CoordinatesFormat format);
|
||||
void setTimeZone(const QTimeZone &zone);
|
||||
void setDevicePixelRatio(qreal deviceRatio, qreal mapRatio);
|
||||
void setProjection(int id);
|
||||
|
||||
@ -137,8 +139,6 @@ private:
|
||||
POI *_poi;
|
||||
|
||||
Palette _palette;
|
||||
Units _units;
|
||||
CoordinatesFormat _coordinatesFormat;
|
||||
qreal _mapOpacity;
|
||||
Projection _projection;
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <QRadioButton>
|
||||
#include <QLabel>
|
||||
#include <QSysInfo>
|
||||
#include <QButtonGroup>
|
||||
#include "map/pcs.h"
|
||||
#include "icons.h"
|
||||
#include "colorbox.h"
|
||||
@ -166,11 +167,8 @@ QWidget *OptionsDialog::createAppearancePage()
|
||||
// Palette & antialiasing
|
||||
_baseColor = new ColorBox();
|
||||
_baseColor->setColor(_options->palette.color());
|
||||
_colorOffset = new QDoubleSpinBox();
|
||||
_colorOffset->setMinimum(0);
|
||||
_colorOffset->setMaximum(1.0);
|
||||
_colorOffset->setSingleStep(0.01);
|
||||
_colorOffset->setValue(_options->palette.shift());
|
||||
_colorOffset = new PercentSlider();
|
||||
_colorOffset->setValue(_options->palette.shift() * 100);
|
||||
QFormLayout *paletteLayout = new QFormLayout();
|
||||
paletteLayout->addRow(tr("Base color:"), _baseColor);
|
||||
paletteLayout->addRow(tr("Palette shift:"), _colorOffset);
|
||||
@ -406,6 +404,8 @@ QWidget *OptionsDialog::createDataPage()
|
||||
_reportedSpeed->setChecked(true);
|
||||
else
|
||||
_computedSpeed->setChecked(true);
|
||||
_showSecondarySpeed = new QCheckBox(tr("Show secondary speed"));
|
||||
_showSecondarySpeed->setChecked(_options->showSecondarySpeed);
|
||||
|
||||
_dataGPSElevation = new QRadioButton(tr("GPS data"));
|
||||
_dataDEMElevation = new QRadioButton(tr("DEM data"));
|
||||
@ -413,43 +413,108 @@ QWidget *OptionsDialog::createDataPage()
|
||||
_dataDEMElevation->setChecked(true);
|
||||
else
|
||||
_dataGPSElevation->setChecked(true);
|
||||
_showSecondaryElevation = new QCheckBox(tr("Show secondary elevation"));
|
||||
_showSecondaryElevation->setChecked(_options->showSecondaryElevation);
|
||||
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
_utcZone = new QRadioButton(tr("UTC"));
|
||||
_systemZone = new QRadioButton(tr("System"));
|
||||
_customZone = new QRadioButton(tr("Custom"));
|
||||
if (_options->timeZone.type() == TimeZoneInfo::UTC)
|
||||
_utcZone->setChecked(true);
|
||||
else if (_options->timeZone.type() == TimeZoneInfo::System)
|
||||
_systemZone->setChecked(true);
|
||||
else
|
||||
_customZone->setChecked(true);
|
||||
_timeZone = new QComboBox();
|
||||
_timeZone->setEnabled(_customZone->isChecked());
|
||||
QList<QByteArray> zones = QTimeZone::availableTimeZoneIds();
|
||||
for (int i = 0; i < zones.size(); i++)
|
||||
_timeZone->addItem(zones.at(i));
|
||||
_timeZone->setCurrentText(_options->timeZone.customZone().id());
|
||||
connect(_customZone, SIGNAL(toggled(bool)), _timeZone,
|
||||
SLOT(setEnabled(bool)));
|
||||
QHBoxLayout *customZoneLayout = new QHBoxLayout();
|
||||
customZoneLayout->addSpacing(20);
|
||||
customZoneLayout->addWidget(_timeZone);
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
QWidget *sourceTab = new QWidget();
|
||||
QVBoxLayout *sourceTabLayout = new QVBoxLayout();
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
QButtonGroup *speedGroup = new QButtonGroup(this);
|
||||
speedGroup->addButton(_computedSpeed);
|
||||
speedGroup->addButton(_reportedSpeed);
|
||||
QVBoxLayout *speedOptions = new QVBoxLayout();
|
||||
speedOptions->addWidget(_computedSpeed);
|
||||
speedOptions->addWidget(_reportedSpeed);
|
||||
speedOptions->addWidget(_showSecondarySpeed);
|
||||
|
||||
QButtonGroup *elevationGroup = new QButtonGroup(this);
|
||||
elevationGroup->addButton(_dataGPSElevation);
|
||||
elevationGroup->addButton(_dataDEMElevation);
|
||||
QVBoxLayout *elevationOptions = new QVBoxLayout();
|
||||
elevationOptions->addWidget(_dataGPSElevation);
|
||||
elevationOptions->addWidget(_dataDEMElevation);
|
||||
elevationOptions->addWidget(_showSecondaryElevation);
|
||||
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
QButtonGroup *timeZoneGroup = new QButtonGroup(this);
|
||||
timeZoneGroup->addButton(_utcZone);
|
||||
timeZoneGroup->addButton(_systemZone);
|
||||
timeZoneGroup->addButton(_customZone);
|
||||
QVBoxLayout *zoneOptions = new QVBoxLayout();
|
||||
zoneOptions->addWidget(_utcZone);
|
||||
zoneOptions->addWidget(_systemZone);
|
||||
zoneOptions->addWidget(_customZone);
|
||||
zoneOptions->addItem(customZoneLayout);
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
QFormLayout *formLayout = new QFormLayout();
|
||||
formLayout->addRow(tr("Speed:"), speedOptions);
|
||||
formLayout->addRow(tr("Elevation:"), elevationOptions);
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
formLayout->addRow(tr("Time zone:"), zoneOptions);
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
sourceTabLayout->addLayout(formLayout);
|
||||
#else // Q_OS_MAC
|
||||
QFormLayout *speedLayout = new QFormLayout();
|
||||
QFormLayout *elevationLayout = new QFormLayout();
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
QFormLayout *timeZoneLayout = new QFormLayout();
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
speedLayout->addWidget(_computedSpeed);
|
||||
speedLayout->addWidget(_reportedSpeed);
|
||||
speedLayout->addWidget(_showSecondarySpeed);
|
||||
|
||||
QGroupBox *speedBox = new QGroupBox(tr("Speed"));
|
||||
speedBox->setLayout(speedLayout);
|
||||
|
||||
elevationLayout->addWidget(_dataGPSElevation);
|
||||
elevationLayout->addWidget(_dataDEMElevation);
|
||||
elevationLayout->addWidget(_showSecondaryElevation);
|
||||
|
||||
QGroupBox *elevationBox = new QGroupBox(tr("Elevation"));
|
||||
elevationBox->setLayout(elevationLayout);
|
||||
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
timeZoneLayout->addWidget(_utcZone);
|
||||
timeZoneLayout->addWidget(_systemZone);
|
||||
timeZoneLayout->addWidget(_customZone);
|
||||
timeZoneLayout->addItem(customZoneLayout);
|
||||
|
||||
QGroupBox *timeZoneBox = new QGroupBox(tr("Time zone"));
|
||||
timeZoneBox->setLayout(timeZoneLayout);
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
sourceTabLayout->addWidget(speedBox);
|
||||
sourceTabLayout->addWidget(elevationBox);
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
sourceTabLayout->addWidget(timeZoneBox);
|
||||
#endif // ENABLE_TIMEZONES
|
||||
#endif // Q_OS_MAC
|
||||
sourceTabLayout->addStretch();
|
||||
sourceTab->setLayout(sourceTabLayout);
|
||||
@ -465,13 +530,6 @@ QWidget *OptionsDialog::createDataPage()
|
||||
|
||||
QWidget *OptionsDialog::createPOIPage()
|
||||
{
|
||||
_poiGPSElevation = new QRadioButton(tr("GPS data"));
|
||||
_poiDEMElevation = new QRadioButton(tr("DEM data"));
|
||||
if (_options->poiUseDEM)
|
||||
_poiDEMElevation->setChecked(true);
|
||||
else
|
||||
_poiGPSElevation->setChecked(true);
|
||||
|
||||
_poiRadius = new QDoubleSpinBox();
|
||||
_poiRadius->setSingleStep(1);
|
||||
_poiRadius->setDecimals(1);
|
||||
@ -486,13 +544,8 @@ QWidget *OptionsDialog::createPOIPage()
|
||||
_poiRadius->setSuffix(UNIT_SPACE + tr("km"));
|
||||
}
|
||||
|
||||
QVBoxLayout *elevationLayout = new QVBoxLayout();
|
||||
elevationLayout->addWidget(_poiGPSElevation);
|
||||
elevationLayout->addWidget(_poiDEMElevation);
|
||||
|
||||
QFormLayout *poiLayout = new QFormLayout();
|
||||
poiLayout->addRow(tr("Radius:"), _poiRadius);
|
||||
poiLayout->addRow(tr("Elevation:"), elevationLayout);
|
||||
|
||||
QWidget *poiTab = new QWidget();
|
||||
poiTab->setLayout(poiLayout);
|
||||
@ -675,7 +728,7 @@ OptionsDialog::OptionsDialog(Options *options, QWidget *parent)
|
||||
void OptionsDialog::accept()
|
||||
{
|
||||
_options->palette.setColor(_baseColor->color());
|
||||
_options->palette.setShift(_colorOffset->value());
|
||||
_options->palette.setShift(_colorOffset->value() / 100.0);
|
||||
_options->mapOpacity = _mapOpacity->value();
|
||||
_options->backgroundColor = _backgroundColor->color();
|
||||
_options->trackWidth = _trackWidth->value();
|
||||
@ -718,13 +771,21 @@ void OptionsDialog::accept()
|
||||
_options->pauseInterval = _pauseInterval->value();
|
||||
_options->useReportedSpeed = _reportedSpeed->isChecked();
|
||||
_options->dataUseDEM = _dataDEMElevation->isChecked();
|
||||
_options->showSecondaryElevation = _showSecondaryElevation->isChecked();
|
||||
_options->showSecondarySpeed = _showSecondarySpeed->isChecked();
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
_options->timeZone.setType(_utcZone->isChecked()
|
||||
? TimeZoneInfo::UTC : _systemZone->isChecked()
|
||||
? TimeZoneInfo::System : TimeZoneInfo::Custom);
|
||||
_options->timeZone.setCustomZone(QTimeZone(_timeZone->currentText()
|
||||
.toLatin1()));
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
qreal poiRadius = (_options->units == Imperial)
|
||||
? _poiRadius->value() * MIINM : (_options->units == Nautical)
|
||||
? _poiRadius->value() * NMIINM : _poiRadius->value() * KMINM;
|
||||
if (qAbs(poiRadius - _options->poiRadius) > 0.01)
|
||||
_options->poiRadius = poiRadius;
|
||||
_options->poiUseDEM = _poiDEMElevation->isChecked();
|
||||
|
||||
_options->useOpenGL = _useOpenGL->isChecked();
|
||||
#ifdef ENABLE_HTTP2
|
||||
|
@ -5,6 +5,9 @@
|
||||
#include "common/config.h"
|
||||
#include "palette.h"
|
||||
#include "units.h"
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
#include "timezoneinfo.h"
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
class ColorBox;
|
||||
class StyleComboBox;
|
||||
@ -17,6 +20,7 @@ class QRadioButton;
|
||||
class PercentSlider;
|
||||
class LimitedComboBox;
|
||||
|
||||
|
||||
struct Options {
|
||||
// Appearance
|
||||
Palette palette;
|
||||
@ -54,9 +58,13 @@ struct Options {
|
||||
int pauseInterval;
|
||||
bool useReportedSpeed;
|
||||
bool dataUseDEM;
|
||||
bool showSecondaryElevation;
|
||||
bool showSecondarySpeed;
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
TimeZoneInfo timeZone;
|
||||
#endif // ENABLE_TIMEZONES
|
||||
// POI
|
||||
int poiRadius;
|
||||
bool poiUseDEM;
|
||||
// System
|
||||
bool useOpenGL;
|
||||
#ifdef ENABLE_HTTP2
|
||||
@ -102,7 +110,7 @@ private:
|
||||
|
||||
// Appearance
|
||||
ColorBox *_baseColor;
|
||||
QDoubleSpinBox *_colorOffset;
|
||||
PercentSlider *_colorOffset;
|
||||
PercentSlider *_mapOpacity;
|
||||
ColorBox *_backgroundColor;
|
||||
QSpinBox *_trackWidth;
|
||||
@ -133,7 +141,6 @@ private:
|
||||
OddSpinBox *_cadenceFilter;
|
||||
OddSpinBox *_powerFilter;
|
||||
QCheckBox *_outlierEliminate;
|
||||
|
||||
QRadioButton *_automaticPause;
|
||||
QRadioButton *_manualPause;
|
||||
QDoubleSpinBox *_pauseSpeed;
|
||||
@ -142,10 +149,16 @@ private:
|
||||
QRadioButton *_reportedSpeed;
|
||||
QRadioButton *_dataGPSElevation;
|
||||
QRadioButton *_dataDEMElevation;
|
||||
QCheckBox *_showSecondaryElevation;
|
||||
QCheckBox *_showSecondarySpeed;
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
QRadioButton *_utcZone;
|
||||
QRadioButton *_systemZone;
|
||||
QRadioButton *_customZone;
|
||||
QComboBox *_timeZone;
|
||||
#endif // ENABLE_TIMEZONES
|
||||
// POI
|
||||
QDoubleSpinBox *_poiRadius;
|
||||
QRadioButton *_poiGPSElevation;
|
||||
QRadioButton *_poiDEMElevation;
|
||||
// System
|
||||
QSpinBox *_pixmapCache;
|
||||
QSpinBox *_connectionTimeout;
|
||||
|
@ -21,12 +21,16 @@ static inline unsigned segments(qreal distance)
|
||||
return ceil(distance / GEOGRAPHICAL_MILE);
|
||||
}
|
||||
|
||||
Units PathItem::_units = Metric;
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
QTimeZone PathItem::_timeZone = QTimeZone::utc();
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
PathItem::PathItem(const Path &path, Map *map, QGraphicsItem *parent)
|
||||
: GraphicsItem(parent), _path(path), _map(map)
|
||||
{
|
||||
Q_ASSERT(_path.isValid());
|
||||
|
||||
_units = Metric;
|
||||
_digitalZoom = 0;
|
||||
_width = 3;
|
||||
QBrush brush(Qt::SolidPattern);
|
||||
@ -352,16 +356,6 @@ void PathItem::showTicks(bool show)
|
||||
updateTicks();
|
||||
}
|
||||
|
||||
void PathItem::setUnits(Units units)
|
||||
{
|
||||
if (_units == units)
|
||||
return;
|
||||
|
||||
prepareGeometryChange();
|
||||
_units = units;
|
||||
updateTicks();
|
||||
}
|
||||
|
||||
void PathItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
@ -1,8 +1,12 @@
|
||||
#ifndef PATHITEM_H
|
||||
#define PATHITEM_H
|
||||
|
||||
#include "common/config.h"
|
||||
#include <QGraphicsObject>
|
||||
#include <QPen>
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
#include <QTimeZone>
|
||||
#endif // ENABLE_TIMEZONES
|
||||
#include "data/path.h"
|
||||
#include "markeritem.h"
|
||||
#include "units.h"
|
||||
@ -28,7 +32,6 @@ public:
|
||||
|
||||
void setMap(Map *map);
|
||||
|
||||
void setUnits(Units units);
|
||||
void setColor(const QColor &color);
|
||||
void setWidth(qreal width);
|
||||
void setStyle(Qt::PenStyle style);
|
||||
@ -37,6 +40,13 @@ public:
|
||||
void showMarker(bool show);
|
||||
void showTicks(bool show);
|
||||
|
||||
void updateTicks();
|
||||
|
||||
static void setUnits(Units units) {_units = units;}
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
static void setTimeZone(const QTimeZone &zone) {_timeZone = zone;}
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
public slots:
|
||||
void moveMarker(qreal distance);
|
||||
void hover(bool hover);
|
||||
@ -49,7 +59,10 @@ protected:
|
||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent *event);
|
||||
|
||||
Units _units;
|
||||
static Units _units;
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
static QTimeZone _timeZone;
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
private:
|
||||
const PathSegment *segment(qreal x) const;
|
||||
@ -60,7 +73,6 @@ private:
|
||||
|
||||
qreal xInM() const;
|
||||
unsigned tickSize() const;
|
||||
void updateTicks();
|
||||
|
||||
Path _path;
|
||||
Map *_map;
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
PowerGraphItem::PowerGraphItem(const Graph &graph, GraphType type, int width,
|
||||
const QColor &color, QGraphicsItem *parent)
|
||||
: GraphItem(graph, type, width, color, parent)
|
||||
: GraphItem(graph, type, width, color, Qt::SolidLine, parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,8 @@ QString RouteItem::info() const
|
||||
tt.insert(tr("Name"), _name);
|
||||
if (!_desc.isEmpty())
|
||||
tt.insert(tr("Description"), _desc);
|
||||
if (!_comment.isEmpty() && _comment != _desc)
|
||||
tt.insert(tr("Comment"), _comment);
|
||||
tt.insert(tr("Distance"), Format::distance(path().last().last().distance(),
|
||||
_units));
|
||||
if (!_links.isEmpty()) {
|
||||
@ -43,8 +45,8 @@ RouteItem::RouteItem(const Route &route, Map *map, QGraphicsItem *parent)
|
||||
|
||||
_name = route.name();
|
||||
_desc = route.description();
|
||||
_comment = route.comment();
|
||||
_links = route.links();
|
||||
_coordinatesFormat = DecimalDegrees;
|
||||
}
|
||||
|
||||
void RouteItem::setMap(Map *map)
|
||||
@ -55,28 +57,6 @@ void RouteItem::setMap(Map *map)
|
||||
PathItem::setMap(map);
|
||||
}
|
||||
|
||||
void RouteItem::setUnits(Units u)
|
||||
{
|
||||
if (_units == u)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < _waypoints.count(); i++)
|
||||
_waypoints[i]->setToolTipFormat(u, _coordinatesFormat);
|
||||
|
||||
PathItem::setUnits(u);
|
||||
}
|
||||
|
||||
void RouteItem::setCoordinatesFormat(CoordinatesFormat format)
|
||||
{
|
||||
if (_coordinatesFormat == format)
|
||||
return;
|
||||
|
||||
_coordinatesFormat = format;
|
||||
|
||||
for (int i = 0; i < _waypoints.count(); i++)
|
||||
_waypoints[i]->setToolTipFormat(_units, _coordinatesFormat);
|
||||
}
|
||||
|
||||
void RouteItem::showWaypoints(bool show)
|
||||
{
|
||||
for (int i = 0; i < _waypoints.count(); i++)
|
||||
|
@ -19,8 +19,6 @@ public:
|
||||
|
||||
void setMap(Map *map);
|
||||
|
||||
void setUnits(Units u);
|
||||
void setCoordinatesFormat(CoordinatesFormat format);
|
||||
void showWaypoints(bool show);
|
||||
void showWaypointLabels(bool show);
|
||||
|
||||
@ -29,8 +27,8 @@ public:
|
||||
private:
|
||||
QString _name;
|
||||
QString _desc;
|
||||
QString _comment;
|
||||
QVector<Link> _links;
|
||||
CoordinatesFormat _coordinatesFormat;
|
||||
|
||||
QVector<WaypointItem*> _waypoints;
|
||||
};
|
||||
|
@ -145,10 +145,13 @@
|
||||
#define USE_REPORTED_SPEED_DEFAULT false
|
||||
#define DATA_USE_DEM_SETTING "dataUseDEM"
|
||||
#define DATA_USE_DEM_DEFAULT false
|
||||
#define SHOW_SECONDARY_ELEVATION_SETTING "showSecondaryElevation"
|
||||
#define SHOW_SECONDARY_ELEVATION_DEFAULT false
|
||||
#define SHOW_SECONDARY_SPEED_SETTING "showSecondarySpeed"
|
||||
#define SHOW_SECONDARY_SPEED_DEFAULT false
|
||||
#define TIME_ZONE_SETTING "timeZone"
|
||||
#define POI_RADIUS_SETTING "poiRadius"
|
||||
#define POI_RADIUS_DEFAULT (int)(IMPERIAL_UNITS() ? MIINM : KMINM)
|
||||
#define POI_USE_DEM_SETTING "poiUseDEM"
|
||||
#define POI_USE_DEM_DEFAULT false
|
||||
#define USE_OPENGL_SETTING "useOpenGL"
|
||||
#define USE_OPENGL_DEFAULT false
|
||||
#define ENABLE_HTTP2_SETTING "enableHTTP2"
|
||||
|
@ -40,31 +40,46 @@ void SpeedGraph::setInfo()
|
||||
clearInfo();
|
||||
}
|
||||
|
||||
GraphItem *SpeedGraph::loadGraph(const Graph &graph, const Track &track,
|
||||
const QColor &color, bool primary)
|
||||
{
|
||||
if (!graph.isValid())
|
||||
return 0;
|
||||
|
||||
SpeedGraphItem *gi = new SpeedGraphItem(graph, _graphType, _width,
|
||||
color, primary ? Qt::SolidLine : Qt::DashLine, track.movingTime());
|
||||
gi->setTimeType(_timeType);
|
||||
gi->setUnits(_units);
|
||||
|
||||
_tracks.append(gi);
|
||||
if (_showTracks)
|
||||
addGraph(gi);
|
||||
|
||||
if (primary) {
|
||||
_avg.append(QPointF(track.distance(), gi->avg()));
|
||||
_mavg.append(QPointF(track.distance(), gi->mavg()));
|
||||
}
|
||||
|
||||
return gi;
|
||||
}
|
||||
|
||||
QList<GraphItem*> SpeedGraph::loadData(const Data &data)
|
||||
{
|
||||
QList<GraphItem*> graphs;
|
||||
|
||||
for (int i = 0; i < data.tracks().count(); i++) {
|
||||
GraphItem *primary, *secondary;
|
||||
QColor color(_palette.nextColor());
|
||||
const Track &track = data.tracks().at(i);
|
||||
const Graph &graph = track.speed();
|
||||
const GraphPair &gp = track.speed();
|
||||
|
||||
if (!graph.isValid()) {
|
||||
_palette.nextColor();
|
||||
graphs.append(0);
|
||||
} else {
|
||||
SpeedGraphItem *gi = new SpeedGraphItem(graph, _graphType, _width,
|
||||
_palette.nextColor(), track.movingTime());
|
||||
gi->setTimeType(_timeType);
|
||||
gi->setUnits(_units);
|
||||
primary = loadGraph(gp.primary(), track, color, true);
|
||||
secondary = primary
|
||||
? loadGraph(gp.secondary(), track, color, false) : 0;
|
||||
if (primary && secondary)
|
||||
primary->setSecondaryGraph(secondary);
|
||||
|
||||
_tracks.append(gi);
|
||||
if (_showTracks)
|
||||
addGraph(gi);
|
||||
|
||||
_avg.append(QPointF(track.distance(), gi->avg()));
|
||||
_mavg.append(QPointF(track.distance(), gi->mavg()));
|
||||
graphs.append(gi);
|
||||
}
|
||||
graphs.append(primary);
|
||||
}
|
||||
|
||||
for (int i = 0; i < data.routes().count(); i++) {
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "graphtab.h"
|
||||
|
||||
class SpeedGraphItem;
|
||||
class Track;
|
||||
|
||||
class SpeedGraph : public GraphTab
|
||||
{
|
||||
@ -22,6 +23,8 @@ public:
|
||||
void showTracks(bool show);
|
||||
|
||||
private:
|
||||
GraphItem *loadGraph(const Graph &graph, const Track &track,
|
||||
const QColor &color, bool primary);
|
||||
qreal avg() const;
|
||||
qreal max() const {return bounds().bottom();}
|
||||
void setYUnits();
|
||||
|
@ -5,8 +5,8 @@
|
||||
|
||||
|
||||
SpeedGraphItem::SpeedGraphItem(const Graph &graph, GraphType type, int width,
|
||||
const QColor &color, qreal movingTime, QGraphicsItem *parent)
|
||||
: GraphItem(graph, type, width, color, parent)
|
||||
const QColor &color, Qt::PenStyle style, qreal movingTime,
|
||||
QGraphicsItem *parent) : GraphItem(graph, type, width, color, style, parent)
|
||||
{
|
||||
_timeType = Total;
|
||||
|
||||
|
@ -10,7 +10,8 @@ class SpeedGraphItem : public GraphItem
|
||||
|
||||
public:
|
||||
SpeedGraphItem(const Graph &graph, GraphType type, int width,
|
||||
const QColor &color, qreal movingTime, QGraphicsItem *parent = 0);
|
||||
const QColor &color, Qt::PenStyle style, qreal movingTime,
|
||||
QGraphicsItem *parent = 0);
|
||||
|
||||
qreal avg() const {return _avg;}
|
||||
qreal mavg() const {return _mavg;}
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
TemperatureGraphItem::TemperatureGraphItem(const Graph &graph, GraphType type,
|
||||
int width, const QColor &color, QGraphicsItem *parent)
|
||||
: GraphItem(graph, type, width, color, parent)
|
||||
: GraphItem(graph, type, width, color, Qt::SolidLine, parent)
|
||||
{
|
||||
_min = GraphItem::min();
|
||||
_max = GraphItem::max();
|
||||
|
69
src/GUI/timezoneinfo.h
Normal file
69
src/GUI/timezoneinfo.h
Normal file
@ -0,0 +1,69 @@
|
||||
#ifndef TIMEZONEINFO_H
|
||||
#define TIMEZONEINFO_H
|
||||
|
||||
#include <QTimeZone>
|
||||
#include <QDataStream>
|
||||
|
||||
class TimeZoneInfo
|
||||
{
|
||||
public:
|
||||
enum Type {
|
||||
UTC,
|
||||
System,
|
||||
Custom
|
||||
};
|
||||
|
||||
TimeZoneInfo() : _type(UTC), _customZone(QTimeZone::systemTimeZone()) {}
|
||||
|
||||
Type type() const {return _type;}
|
||||
const QTimeZone &customZone() const {return _customZone;}
|
||||
QTimeZone zone() const
|
||||
{
|
||||
if (_type == UTC)
|
||||
return QTimeZone::utc();
|
||||
else if (_type == System)
|
||||
return QTimeZone::systemTimeZone();
|
||||
else
|
||||
return _customZone;
|
||||
}
|
||||
|
||||
void setType(Type type) {_type = type;}
|
||||
void setCustomZone(const QTimeZone &zone) {_customZone = zone;}
|
||||
|
||||
bool operator==(const TimeZoneInfo &other) const
|
||||
{
|
||||
if (_type == UTC || _type == System)
|
||||
return _type == other._type;
|
||||
else
|
||||
return (other._type == Custom && _customZone == other._customZone);
|
||||
}
|
||||
bool operator!=(const TimeZoneInfo &other) {return !(*this == other);}
|
||||
|
||||
private:
|
||||
friend QDataStream& operator<<(QDataStream &out, const TimeZoneInfo &info);
|
||||
friend QDataStream& operator>>(QDataStream &in, TimeZoneInfo &info);
|
||||
|
||||
Type _type;
|
||||
QTimeZone _customZone;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(TimeZoneInfo)
|
||||
|
||||
inline QDataStream &operator<<(QDataStream &out, const TimeZoneInfo &info)
|
||||
{
|
||||
out << static_cast<int>(info._type) << info._customZone;
|
||||
return out;
|
||||
}
|
||||
|
||||
inline QDataStream &operator>>(QDataStream &in, TimeZoneInfo &info)
|
||||
{
|
||||
int t;
|
||||
|
||||
in >> t;
|
||||
info._type = static_cast<TimeZoneInfo::Type>(t);
|
||||
in >> info._customZone;
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
#endif // TIMEZONEINFO_H
|
@ -13,6 +13,8 @@ QString TrackItem::info() const
|
||||
tt.insert(tr("Name"), _name);
|
||||
if (!_desc.isEmpty())
|
||||
tt.insert(tr("Description"), _desc);
|
||||
if (!_comment.isEmpty() && _comment != _desc)
|
||||
tt.insert(tr("Comment"), _comment);
|
||||
tt.insert(tr("Distance"), Format::distance(path().last().last().distance(),
|
||||
_units));
|
||||
if (_time > 0)
|
||||
@ -20,7 +22,13 @@ QString TrackItem::info() const
|
||||
if (_movingTime > 0)
|
||||
tt.insert(tr("Moving time"), Format::timeSpan(_movingTime));
|
||||
if (!_date.isNull())
|
||||
tt.insert(tr("Date"), _date.toString(Qt::SystemLocaleShortDate));
|
||||
tt.insert(tr("Date"),
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
_date.toTimeZone(_timeZone)
|
||||
#else // ENABLE_TIMEZONES
|
||||
_date
|
||||
#endif // ENABLE_TIMEZONES
|
||||
.toString(Qt::SystemLocaleShortDate));
|
||||
if (!_links.isEmpty()) {
|
||||
QString links;
|
||||
for (int i = 0; i < _links.size(); i++) {
|
||||
@ -41,6 +49,7 @@ TrackItem::TrackItem(const Track &track, Map *map, QGraphicsItem *parent)
|
||||
{
|
||||
_name = track.name();
|
||||
_desc = track.description();
|
||||
_comment = track.comment();
|
||||
_links = track.links();
|
||||
_date = track.date();
|
||||
_time = track.time();
|
||||
|
@ -22,6 +22,7 @@ public:
|
||||
private:
|
||||
QString _name;
|
||||
QString _desc;
|
||||
QString _comment;
|
||||
QVector<Link> _links;
|
||||
QDateTime _date;
|
||||
qreal _time;
|
||||
|
@ -13,6 +13,13 @@
|
||||
#define FS(size) \
|
||||
((int)((qreal)size * 1.41))
|
||||
|
||||
|
||||
Units WaypointItem::_units = Metric;
|
||||
CoordinatesFormat WaypointItem::_format = DecimalDegrees;
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
QTimeZone WaypointItem::_timeZone = QTimeZone::utc();
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
QString WaypointItem::info() const
|
||||
{
|
||||
ToolTip tt;
|
||||
@ -21,15 +28,28 @@ QString WaypointItem::info() const
|
||||
tt.insert(qApp->translate("WaypointItem", "Name"), _waypoint.name());
|
||||
tt.insert(qApp->translate("WaypointItem", "Coordinates"),
|
||||
Format::coordinates(_waypoint.coordinates(), _format));
|
||||
if (_waypoint.hasElevation())
|
||||
tt.insert(qApp->translate("WaypointItem", "Elevation"),
|
||||
Format::elevation(_waypoint.elevation(), _units));
|
||||
if (!std::isnan(_waypoint.elevations().first)) {
|
||||
QString val = Format::elevation(_waypoint.elevations().first, _units);
|
||||
if (!std::isnan(_waypoint.elevations().second))
|
||||
val += " (" + Format::elevation(_waypoint.elevations().second,
|
||||
_units) + ")";
|
||||
tt.insert(qApp->translate("WaypointItem", "Elevation"), val);
|
||||
}
|
||||
if (_waypoint.timestamp().isValid())
|
||||
tt.insert(qApp->translate("WaypointItem", "Date"),
|
||||
_waypoint.timestamp().toString(Qt::SystemLocaleShortDate));
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
_waypoint.timestamp().toTimeZone(_timeZone)
|
||||
#else // ENABLE_TIMEZONES
|
||||
_waypoint.timestamp()
|
||||
#endif // ENABLE_TIMEZONES
|
||||
.toString(Qt::SystemLocaleShortDate));
|
||||
if (!_waypoint.description().isEmpty())
|
||||
tt.insert(qApp->translate("WaypointItem", "Description"),
|
||||
_waypoint.description());
|
||||
if (!_waypoint.comment().isEmpty()
|
||||
&& _waypoint.comment() != _waypoint.description())
|
||||
tt.insert(qApp->translate("WaypointItem", "Comment"),
|
||||
_waypoint.comment());
|
||||
if (_waypoint.address().isValid()) {
|
||||
QString addr("<address>");
|
||||
addr += _waypoint.address().street();
|
||||
@ -70,9 +90,6 @@ WaypointItem::WaypointItem(const Waypoint &waypoint, Map *map,
|
||||
_font.setPixelSize(FS(_size));
|
||||
_font.setFamily(FONT_FAMILY);
|
||||
|
||||
_units = Metric;
|
||||
_format = DecimalDegrees;
|
||||
|
||||
updateCache();
|
||||
|
||||
setPos(map->ll2xy(waypoint.coordinates()));
|
||||
@ -143,12 +160,6 @@ void WaypointItem::setColor(const QColor &color)
|
||||
update();
|
||||
}
|
||||
|
||||
void WaypointItem::setToolTipFormat(Units units, CoordinatesFormat format)
|
||||
{
|
||||
_units = units;
|
||||
_format = format;
|
||||
}
|
||||
|
||||
void WaypointItem::showLabel(bool show)
|
||||
{
|
||||
if (_showLabel == show)
|
||||
|
@ -1,9 +1,13 @@
|
||||
#ifndef WAYPOINTITEM_H
|
||||
#define WAYPOINTITEM_H
|
||||
|
||||
#include "common/config.h"
|
||||
#include <cmath>
|
||||
#include <QGraphicsItem>
|
||||
#include <QFont>
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
#include <QTimeZone>
|
||||
#endif // ENABLE_TIMEZONES
|
||||
#include "data/waypoint.h"
|
||||
#include "map/map.h"
|
||||
#include "units.h"
|
||||
@ -23,7 +27,6 @@ public:
|
||||
void setColor(const QColor &color);
|
||||
void showLabel(bool show);
|
||||
void setDigitalZoom(int zoom) {setScale(pow(2, -zoom));}
|
||||
void setToolTipFormat(Units units, CoordinatesFormat format);
|
||||
|
||||
QPainterPath shape() const {return _shape;}
|
||||
QRectF boundingRect() const {return _shape.boundingRect();}
|
||||
@ -32,6 +35,13 @@ public:
|
||||
|
||||
QString info() const;
|
||||
|
||||
static void setUnits(Units units) {_units = units;}
|
||||
static void setCoordinatesFormat(CoordinatesFormat format)
|
||||
{_format = format;}
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
static void setTimeZone(const QTimeZone &zone) {_timeZone = zone;}
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
protected:
|
||||
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
|
||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
|
||||
@ -48,8 +58,11 @@ private:
|
||||
QFont _font;
|
||||
QRect _labelBB;
|
||||
|
||||
Units _units;
|
||||
CoordinatesFormat _format;
|
||||
static Units _units;
|
||||
static CoordinatesFormat _format;
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
static QTimeZone _timeZone;
|
||||
#endif // ENABLE_TIMEZONES
|
||||
};
|
||||
|
||||
#endif // WAYPOINTITEM_H
|
||||
|
@ -18,4 +18,8 @@
|
||||
#define ENABLE_GEOJSON
|
||||
#endif // QT >= 5.0
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
|
||||
#define ENABLE_TIMEZONES
|
||||
#endif // QT >= 5.5
|
||||
|
||||
#endif /* CONFIG_H */
|
||||
|
@ -14,8 +14,8 @@ double Coordinates::distanceTo(const Coordinates &c) const
|
||||
#ifndef QT_NO_DEBUG
|
||||
QDebug operator<<(QDebug dbg, const Coordinates &c)
|
||||
{
|
||||
dbg.nospace() << qSetRealNumberPrecision(10) << "Coordinates(" << c.lat()
|
||||
<< ", " << c.lon() << ")";
|
||||
dbg.nospace() << qSetRealNumberPrecision(10) << "Coordinates(" << c.lon()
|
||||
<< ", " << c.lat() << ")";
|
||||
return dbg.space();
|
||||
}
|
||||
#endif // QT_NO_DEBUG
|
||||
|
@ -3,14 +3,16 @@
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#define LS(val, bits) ((qint32)(((quint32)(val))<<(bits)))
|
||||
|
||||
inline double toWGS32(qint32 v)
|
||||
{
|
||||
return (double)(((double)v / (double)(1U<<31)) * (double)180);
|
||||
return ((double)v / (double)(1U<<31)) * 180.0;
|
||||
}
|
||||
|
||||
inline double toWGS24(qint32 v)
|
||||
{
|
||||
return toWGS32(v<<8);
|
||||
return toWGS32(LS(v, 8));
|
||||
}
|
||||
|
||||
#endif // GARMIN_H
|
||||
|
@ -28,6 +28,9 @@ public:
|
||||
double left() const {return _tl.lon();}
|
||||
double right() const {return _br.lon();}
|
||||
|
||||
double width() const {return (right() - left());}
|
||||
double height() const {return (top() - bottom());}
|
||||
|
||||
void setLeft(double val) {_tl.rlon() = val;}
|
||||
void setRight(double val) {_br.rlon() = val;}
|
||||
void setTop(double val) {_tl.rlat() = val;}
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include "cupparser.h"
|
||||
#include "gpiparser.h"
|
||||
#include "smlparser.h"
|
||||
#include "dem.h"
|
||||
#include "data.h"
|
||||
|
||||
|
||||
@ -73,49 +72,17 @@ static QMap<QString, Parser*> parsers()
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
QMap<QString, Parser*> Data::_parsers = parsers();
|
||||
bool Data::_useDEM = false;
|
||||
|
||||
void Data::processData(QList<TrackData> &trackData, QList<RouteData> &routeData)
|
||||
{
|
||||
for (int i = 0; i < trackData.count(); i++) {
|
||||
TrackData &track = trackData[i];
|
||||
for (int j = 0; j < track.size(); j++) {
|
||||
SegmentData &segment = track[j];
|
||||
for (int k = 0; k < segment.size(); k++) {
|
||||
Trackpoint &t = segment[k];
|
||||
if (!t.hasElevation() || _useDEM) {
|
||||
qreal elevation = DEM::elevation(t.coordinates());
|
||||
if (!std::isnan(elevation))
|
||||
t.setElevation(elevation);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < trackData.count(); i++)
|
||||
_tracks.append(Track(trackData.at(i)));
|
||||
}
|
||||
for (int i = 0; i < routeData.count(); i++) {
|
||||
RouteData &route = routeData[i];
|
||||
for (int j = 0; j < route.size(); j++) {
|
||||
Waypoint &w = route[j];
|
||||
if (!w.hasElevation() || _useDEM) {
|
||||
qreal elevation = DEM::elevation(w.coordinates());
|
||||
if (!std::isnan(elevation))
|
||||
w.setElevation(elevation);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < routeData.count(); i++)
|
||||
_routes.append(Route(routeData.at(i)));
|
||||
}
|
||||
for (int i = 0; i < _waypoints.size(); i++) {
|
||||
if (!_waypoints.at(i).hasElevation() || _useDEM) {
|
||||
qreal elevation = DEM::elevation(_waypoints.at(i).coordinates());
|
||||
if (!std::isnan(elevation))
|
||||
_waypoints[i].setElevation(elevation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Data::Data(const QString &fileName, bool poi)
|
||||
Data::Data(const QString &fileName)
|
||||
{
|
||||
QFile file(fileName);
|
||||
QFileInfo fi(fileName);
|
||||
@ -134,8 +101,7 @@ Data::Data(const QString &fileName, bool poi)
|
||||
if ((it = _parsers.find(fi.suffix().toLower())) != _parsers.end()) {
|
||||
if (it.value()->parse(&file, trackData, routeData, _polygons,
|
||||
_waypoints)) {
|
||||
if (!poi)
|
||||
processData(trackData, routeData);
|
||||
processData(trackData, routeData);
|
||||
_valid = true;
|
||||
return;
|
||||
} else {
|
||||
@ -146,8 +112,7 @@ Data::Data(const QString &fileName, bool poi)
|
||||
for (it = _parsers.begin(); it != _parsers.end(); it++) {
|
||||
if (it.value()->parse(&file, trackData, routeData, _polygons,
|
||||
_waypoints)) {
|
||||
if (!poi)
|
||||
processData(trackData, routeData);
|
||||
processData(trackData, routeData);
|
||||
_valid = true;
|
||||
return;
|
||||
}
|
||||
@ -198,8 +163,3 @@ QStringList Data::filter()
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
void Data::useDEM(bool use)
|
||||
{
|
||||
_useDEM = use;
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
class Data
|
||||
{
|
||||
public:
|
||||
Data(const QString &fileName, bool poi = false);
|
||||
Data(const QString &fileName);
|
||||
|
||||
bool isValid() const {return _valid;}
|
||||
const QString &errorString() const {return _errorString;}
|
||||
@ -28,8 +28,6 @@ public:
|
||||
static QString formats();
|
||||
static QStringList filter();
|
||||
|
||||
static void useDEM(bool use);
|
||||
|
||||
private:
|
||||
void processData(QList<TrackData> &trackData, QList<RouteData> &routeData);
|
||||
|
||||
@ -43,7 +41,6 @@ private:
|
||||
QVector<Waypoint> _waypoints;
|
||||
|
||||
static QMap<QString, Parser*> _parsers;
|
||||
static bool _useDEM;
|
||||
};
|
||||
|
||||
#endif // DATA_H
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#define RECORD_MESSAGE 20
|
||||
#define EVENT_MESSAGE 21
|
||||
#define COURSE_POINT 32
|
||||
#define TIMESTAMP_FIELD 253
|
||||
|
||||
class Event {
|
||||
@ -48,10 +49,12 @@ public:
|
||||
|
||||
class FITParser::CTX {
|
||||
public:
|
||||
CTX(QFile *file) : file(file), len(0), endian(0), timestamp(0),
|
||||
lastWrite(0), ratio(NAN) {}
|
||||
CTX(QFile *file, QVector<Waypoint> &waypoints)
|
||||
: file(file), waypoints(waypoints), len(0), endian(0), timestamp(0),
|
||||
lastWrite(0), ratio(NAN) {}
|
||||
|
||||
QFile *file;
|
||||
QVector<Waypoint> &waypoints;
|
||||
quint32 len;
|
||||
quint8 endian;
|
||||
quint32 timestamp, lastWrite;
|
||||
@ -61,6 +64,41 @@ public:
|
||||
SegmentData segment;
|
||||
};
|
||||
|
||||
static QMap<int, QString> coursePointDescInit()
|
||||
{
|
||||
QMap<int, QString> map;
|
||||
|
||||
map.insert(1, "Summit");
|
||||
map.insert(2, "Valley");
|
||||
map.insert(3, "Water");
|
||||
map.insert(4, "Food");
|
||||
map.insert(5, "Danger");
|
||||
map.insert(6, "Left");
|
||||
map.insert(7, "Right");
|
||||
map.insert(8, "Straight");
|
||||
map.insert(9, "First aid");
|
||||
map.insert(10, "Fourth category");
|
||||
map.insert(11, "Third category");
|
||||
map.insert(12, "Second category");
|
||||
map.insert(13, "First category");
|
||||
map.insert(14, "Hors category");
|
||||
map.insert(15, "Sprint");
|
||||
map.insert(16, "Left fork");
|
||||
map.insert(17, "Right fork");
|
||||
map.insert(18, "Middle fork");
|
||||
map.insert(19, "Slight left");
|
||||
map.insert(20, "Sharp left");
|
||||
map.insert(21, "Slight right");
|
||||
map.insert(22, "Sharp right");
|
||||
map.insert(23, "U-Turn");
|
||||
map.insert(24, "Segment start");
|
||||
map.insert(25, "Segment end");
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
static QMap<int, QString> coursePointDesc = coursePointDescInit();
|
||||
|
||||
|
||||
bool FITParser::readData(QFile *file, char *data, size_t size)
|
||||
{
|
||||
@ -80,17 +118,12 @@ bool FITParser::readData(QFile *file, char *data, size_t size)
|
||||
|
||||
template<class T> bool FITParser::readValue(CTX &ctx, T &val)
|
||||
{
|
||||
T data;
|
||||
|
||||
if (!readData(ctx.file, (char*)&data, sizeof(T)))
|
||||
if (!readData(ctx.file, (char*)&val, sizeof(T)))
|
||||
return false;
|
||||
|
||||
ctx.len -= sizeof(T);
|
||||
|
||||
if (ctx.endian)
|
||||
val = qFromBigEndian(data);
|
||||
else
|
||||
val = qFromLittleEndian(data);
|
||||
if (sizeof(T) > 1)
|
||||
val = (ctx.endian) ? qFromBigEndian(val) : qFromLittleEndian(val);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -167,41 +200,51 @@ bool FITParser::parseDefinitionMessage(CTX &ctx, quint8 header)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FITParser::readField(CTX &ctx, Field *field, quint32 &val)
|
||||
bool FITParser::readField(CTX &ctx, Field *field, QVariant &val, bool &valid)
|
||||
{
|
||||
quint8 v8 = (quint8)-1;
|
||||
quint16 v16 = (quint16)-1;
|
||||
bool ret;
|
||||
|
||||
val = (quint32)-1;
|
||||
#define VAL(type, inval) \
|
||||
{type var; \
|
||||
if (field->size == sizeof(var)) { \
|
||||
ret = readValue(ctx, var); \
|
||||
val = var; \
|
||||
valid = (var != (inval)); \
|
||||
} else { \
|
||||
ret = skipValue(ctx, field->size); \
|
||||
valid = false; \
|
||||
}}
|
||||
|
||||
switch (field->type) {
|
||||
case 0: // enum
|
||||
case 1: // sint8
|
||||
VAL(qint8, 0x7fU);
|
||||
break;
|
||||
case 2: // uint8
|
||||
if (field->size == 1) {
|
||||
ret = readValue(ctx, v8);
|
||||
val = v8;
|
||||
} else
|
||||
ret = skipValue(ctx, field->size);
|
||||
case 0: // enum
|
||||
VAL(quint8, 0xffU);
|
||||
break;
|
||||
case 7: // UTF8 nul terminated string
|
||||
{QByteArray ba(ctx.file->read(field->size));
|
||||
ctx.len -= field->size;
|
||||
ret = (ba.size() == field->size);
|
||||
val = ret ? ba : QString();
|
||||
valid = !ba.isEmpty();}
|
||||
break;
|
||||
case 0x83: // sint16
|
||||
VAL(qint16, 0x7fffU);
|
||||
break;
|
||||
case 0x84: // uint16
|
||||
if (field->size == 2) {
|
||||
ret = readValue(ctx, v16);
|
||||
val = v16;
|
||||
} else
|
||||
ret = skipValue(ctx, field->size);
|
||||
VAL(quint16, 0xffffU);
|
||||
break;
|
||||
case 0x85: // sint32
|
||||
VAL(qint32, 0x7fffffffU);
|
||||
break;
|
||||
case 0x86: // uint32
|
||||
if (field->size == 4)
|
||||
ret = readValue(ctx, val);
|
||||
else
|
||||
ret = skipValue(ctx, field->size);
|
||||
VAL(quint32, 0xffffffffU);
|
||||
break;
|
||||
default:
|
||||
ret = skipValue(ctx, field->size);
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -211,8 +254,10 @@ bool FITParser::readField(CTX &ctx, Field *field, quint32 &val)
|
||||
bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
||||
{
|
||||
Field *field;
|
||||
QVariant val;
|
||||
bool valid;
|
||||
Event event;
|
||||
quint32 val;
|
||||
Waypoint waypoint;
|
||||
|
||||
|
||||
if (!def->fields && !def->devFields) {
|
||||
@ -224,69 +269,79 @@ bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
||||
|
||||
for (int i = 0; i < def->numFields; i++) {
|
||||
field = &def->fields[i];
|
||||
if (!readField(ctx, field, val))
|
||||
if (!readField(ctx, field, val, valid))
|
||||
return false;
|
||||
if (!valid)
|
||||
continue;
|
||||
|
||||
if (field->id == TIMESTAMP_FIELD)
|
||||
ctx.timestamp = val;
|
||||
ctx.timestamp = val.toUInt();
|
||||
else if (def->globalId == RECORD_MESSAGE) {
|
||||
switch (field->id) {
|
||||
case 0:
|
||||
if (val != 0x7fffffff)
|
||||
ctx.trackpoint.rcoordinates().setLat(
|
||||
((qint32)val / (double)0x7fffffff) * 180);
|
||||
ctx.trackpoint.rcoordinates().setLat(
|
||||
(val.toInt() / (double)0x7fffffff) * 180);
|
||||
break;
|
||||
case 1:
|
||||
if (val != 0x7fffffff)
|
||||
ctx.trackpoint.rcoordinates().setLon(
|
||||
((qint32)val / (double)0x7fffffff) * 180);
|
||||
ctx.trackpoint.rcoordinates().setLon(
|
||||
(val.toInt() / (double)0x7fffffff) * 180);
|
||||
break;
|
||||
case 2:
|
||||
if (val != 0xffff)
|
||||
ctx.trackpoint.setElevation((val / 5.0) - 500);
|
||||
ctx.trackpoint.setElevation((val.toUInt() / 5.0) - 500);
|
||||
break;
|
||||
case 3:
|
||||
if (val != 0xff)
|
||||
ctx.trackpoint.setHeartRate(val);
|
||||
ctx.trackpoint.setHeartRate(val.toUInt());
|
||||
break;
|
||||
case 4:
|
||||
if (val != 0xff)
|
||||
ctx.trackpoint.setCadence(val);
|
||||
ctx.trackpoint.setCadence(val.toUInt());
|
||||
break;
|
||||
case 6:
|
||||
if (val != 0xffff)
|
||||
ctx.trackpoint.setSpeed(val / 1000.0f);
|
||||
ctx.trackpoint.setSpeed(val.toUInt() / 1000.0f);
|
||||
break;
|
||||
case 7:
|
||||
if (val != 0xffff)
|
||||
ctx.trackpoint.setPower(val);
|
||||
ctx.trackpoint.setPower(val.toUInt());
|
||||
break;
|
||||
case 13:
|
||||
if (val != 0x7f)
|
||||
ctx.trackpoint.setTemperature((qint8)val);
|
||||
ctx.trackpoint.setTemperature(val.toInt());
|
||||
break;
|
||||
case 73:
|
||||
if (val != 0xffffffff)
|
||||
ctx.trackpoint.setSpeed(val / 1000.0f);
|
||||
ctx.trackpoint.setSpeed(val.toUInt() / 1000.0f);
|
||||
break;
|
||||
case 78:
|
||||
if (val != 0xffffffff)
|
||||
ctx.trackpoint.setElevation((val / 5.0) - 500);
|
||||
ctx.trackpoint.setElevation((val.toUInt() / 5.0) - 500);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
} else if (def->globalId == EVENT_MESSAGE) {
|
||||
switch (field->id) {
|
||||
case 0:
|
||||
event.id = val;
|
||||
event.id = val.toUInt();
|
||||
break;
|
||||
case 1:
|
||||
event.type = val;
|
||||
event.type = val.toUInt();
|
||||
break;
|
||||
case 3:
|
||||
event.data = val;
|
||||
event.data = val.toUInt();
|
||||
break;
|
||||
}
|
||||
} else if (def->globalId == COURSE_POINT) {
|
||||
switch (field->id) {
|
||||
case 1:
|
||||
waypoint.setTimestamp(QDateTime::fromTime_t(val.toUInt()
|
||||
+ 631065600));
|
||||
break;
|
||||
case 2:
|
||||
waypoint.rcoordinates().setLat(
|
||||
(val.toInt() / (double)0x7fffffff) * 180);
|
||||
break;
|
||||
case 3:
|
||||
waypoint.rcoordinates().setLon(
|
||||
(val.toInt() / (double)0x7fffffff) * 180);
|
||||
break;
|
||||
case 5:
|
||||
waypoint.setDescription(coursePointDesc.value(val.toUInt()));
|
||||
break;
|
||||
case 6:
|
||||
waypoint.setName(val.toString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -294,7 +349,7 @@ bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
||||
|
||||
for (int i = 0; i < def->numDevFields; i++) {
|
||||
field = &def->devFields[i];
|
||||
if (!readField(ctx, field, val))
|
||||
if (!readField(ctx, field, val, valid))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -315,7 +370,9 @@ bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
||||
ctx.trackpoint = Trackpoint();
|
||||
ctx.lastWrite = ctx.timestamp;
|
||||
}
|
||||
}
|
||||
} else if (def->globalId == COURSE_POINT)
|
||||
if (waypoint.coordinates().isValid())
|
||||
ctx.waypoints.append(waypoint);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -381,9 +438,8 @@ bool FITParser::parse(QFile *file, QList<TrackData> &tracks,
|
||||
QList<Area> &polygons, QVector<Waypoint> &waypoints)
|
||||
{
|
||||
Q_UNUSED(routes);
|
||||
Q_UNUSED(waypoints);
|
||||
Q_UNUSED(polygons);
|
||||
CTX ctx(file);
|
||||
CTX ctx(file, waypoints);
|
||||
|
||||
|
||||
if (!parseHeader(ctx))
|
||||
|
@ -21,7 +21,7 @@ private:
|
||||
bool readData(QFile *file, char *data, size_t size);
|
||||
template<class T> bool readValue(CTX &ctx, T &val);
|
||||
bool skipValue(CTX &ctx, quint8 size);
|
||||
bool readField(CTX &ctx, Field *field, quint32 &val);
|
||||
bool readField(CTX &ctx, Field *field, QVariant &val, bool &valid);
|
||||
|
||||
bool parseHeader(CTX &ctx);
|
||||
bool parseRecord(CTX &ctx);
|
||||
|
@ -282,14 +282,14 @@ static quint32 readNotes(QDataStream &stream, QTextCodec *codec,
|
||||
if (s1 & 0x1) {
|
||||
QList<TranslatedString> obj;
|
||||
ds += readTranslatedObjects(stream, codec, obj);
|
||||
if (!obj.isEmpty() && waypoint.description().isNull())
|
||||
waypoint.setDescription(obj.first().str());
|
||||
if (!obj.isEmpty())
|
||||
waypoint.setComment(obj.first().str());
|
||||
}
|
||||
if (s1 & 0x2) {
|
||||
QString str;
|
||||
ds += readString(stream, codec, str);
|
||||
if (!str.isEmpty() && waypoint.description().isNull())
|
||||
waypoint.setDescription(str);
|
||||
if (!str.isEmpty())
|
||||
waypoint.setComment(str);
|
||||
}
|
||||
|
||||
if (ds != rh.size)
|
||||
|
@ -192,6 +192,8 @@ void GPXParser::waypointData(Waypoint &waypoint, SegmentData *autoRoute)
|
||||
waypoint.setName(_reader.readElementText());
|
||||
else if (_reader.name() == QLatin1String("desc"))
|
||||
waypoint.setDescription(_reader.readElementText());
|
||||
else if (_reader.name() == QLatin1String("cmt"))
|
||||
waypoint.setComment(_reader.readElementText());
|
||||
else if (_reader.name() == QLatin1String("ele"))
|
||||
waypoint.setElevation(number());
|
||||
else if (_reader.name() == QLatin1String("geoidheight"))
|
||||
@ -244,6 +246,8 @@ void GPXParser::routepoints(RouteData &route, QList<TrackData> &tracks)
|
||||
route.setName(_reader.readElementText());
|
||||
else if (_reader.name() == QLatin1String("desc"))
|
||||
route.setDescription(_reader.readElementText());
|
||||
else if (_reader.name() == QLatin1String("cmt"))
|
||||
route.setComment(_reader.readElementText());
|
||||
else if (_reader.name() == QLatin1String("link")) {
|
||||
Link l(link());
|
||||
if (!l.URL().isEmpty())
|
||||
@ -278,6 +282,8 @@ void GPXParser::track(TrackData &track)
|
||||
track.setName(_reader.readElementText());
|
||||
else if (_reader.name() == QLatin1String("desc"))
|
||||
track.setDescription(_reader.readElementText());
|
||||
else if (_reader.name() == QLatin1String("cmt"))
|
||||
track.setComment(_reader.readElementText());
|
||||
else if (_reader.name() == QLatin1String("link")) {
|
||||
Link l(link());
|
||||
if (!l.URL().isEmpty())
|
||||
|
@ -67,4 +67,17 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class GraphPair
|
||||
{
|
||||
public:
|
||||
GraphPair(const Graph &primary, const Graph &secondary)
|
||||
: _primary(primary), _secondary(secondary) {}
|
||||
|
||||
const Graph &primary() const {return _primary;}
|
||||
const Graph &secondary() const {return _secondary;}
|
||||
|
||||
private:
|
||||
Graph _primary, _secondary;
|
||||
};
|
||||
|
||||
#endif // GRAPH_H
|
||||
|
@ -87,10 +87,12 @@ static bool readTimestamp(const char *data, QTime &time)
|
||||
|
||||
static bool readARecord(const char *line, qint64 len)
|
||||
{
|
||||
if (len < 7 || line[0] != 'A')
|
||||
/* The minimal A record length should be 7 according to the specification,
|
||||
but records with length of 6 exist in the wild */
|
||||
if (len < 6 || line[0] != 'A')
|
||||
return false;
|
||||
|
||||
for (int i = 1; i < 7; i++)
|
||||
for (int i = 1; i < 6; i++)
|
||||
if (!::isprint(line[i]))
|
||||
return false;
|
||||
return true;
|
||||
|
@ -585,7 +585,9 @@ void KMLParser::document(QList<TrackData> &tracks, QList<Area> &areas,
|
||||
QVector<Waypoint> &waypoints)
|
||||
{
|
||||
while (_reader.readNextStartElement()) {
|
||||
if (_reader.name() == QLatin1String("Placemark"))
|
||||
if (_reader.name() == QLatin1String("Document"))
|
||||
document(tracks, areas, waypoints);
|
||||
else if (_reader.name() == QLatin1String("Placemark"))
|
||||
placemark(tracks, areas, waypoints);
|
||||
else if (_reader.name() == QLatin1String("Folder"))
|
||||
folder(tracks, areas, waypoints);
|
||||
|
@ -14,28 +14,19 @@ POI::POI(QObject *parent) : QObject(parent)
|
||||
{
|
||||
_errorLine = 0;
|
||||
_radius = 1000;
|
||||
_useDEM = false;
|
||||
}
|
||||
|
||||
bool POI::loadFile(const QString &path, bool dir)
|
||||
bool POI::loadFile(const QString &path)
|
||||
{
|
||||
Data data(path, true);
|
||||
Data data(path);
|
||||
FileIndex index;
|
||||
|
||||
index.enabled = true;
|
||||
index.start = _data.size();
|
||||
|
||||
if (!data.isValid()) {
|
||||
if (dir) {
|
||||
if (data.errorLine())
|
||||
_errorString += QString("%1:%2: %3\n").arg(path)
|
||||
.arg(data.errorLine()).arg(data.errorString());
|
||||
else
|
||||
_errorString += path + ": " + data.errorString() + "\n";
|
||||
} else {
|
||||
_errorString = data.errorString();
|
||||
_errorLine = data.errorLine();
|
||||
}
|
||||
_errorString = data.errorString();
|
||||
_errorLine = data.errorLine();
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -59,37 +50,22 @@ bool POI::loadFile(const QString &path, bool dir)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool POI::loadFile(const QString &path)
|
||||
{
|
||||
_errorString.clear();
|
||||
_errorLine = 0;
|
||||
|
||||
return loadFile(path, false);
|
||||
}
|
||||
|
||||
bool POI::loadDir(const QString &path)
|
||||
void POI::loadDir(const QString &path)
|
||||
{
|
||||
QDir md(path);
|
||||
md.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
QFileInfoList fl = md.entryInfoList();
|
||||
bool ret = true;
|
||||
|
||||
_errorString.clear();
|
||||
_errorLine = 0;
|
||||
|
||||
for (int i = 0; i < fl.size(); i++) {
|
||||
const QFileInfo &fi = fl.at(i);
|
||||
|
||||
if (fi.isDir()) {
|
||||
if (!loadDir(fi.absoluteFilePath()))
|
||||
ret = false;
|
||||
} else {
|
||||
if (!loadFile(fi.absoluteFilePath(), true))
|
||||
ret = false;
|
||||
}
|
||||
if (fi.isDir())
|
||||
loadDir(fi.absoluteFilePath());
|
||||
else
|
||||
if (!loadFile(fi.absoluteFilePath()))
|
||||
qWarning("%s: %s", qPrintable(fi.absoluteFilePath()),
|
||||
qPrintable(_errorString));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool cb(size_t data, void* context)
|
||||
@ -112,17 +88,6 @@ void POI::search(const RectC &rect, QSet<int> &set) const
|
||||
_tree.Search(min, max, cb, &set);
|
||||
}
|
||||
|
||||
void POI::appendElevation(QList<Waypoint> &points) const
|
||||
{
|
||||
for (int i = 0; i < points.size(); i++) {
|
||||
if (!points.at(i).hasElevation() || _useDEM) {
|
||||
qreal elevation = DEM::elevation(points.at(i).coordinates());
|
||||
if (!std::isnan(elevation))
|
||||
points[i].setElevation(elevation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QList<Waypoint> POI::points(const Path &path) const
|
||||
{
|
||||
QList<Waypoint> ret;
|
||||
@ -158,8 +123,6 @@ QList<Waypoint> POI::points(const Path &path) const
|
||||
for (it = set.constBegin(); it != set.constEnd(); ++it)
|
||||
ret.append(_data.at(*it));
|
||||
|
||||
appendElevation(ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -181,8 +144,6 @@ QList<Waypoint> POI::points(const Waypoint &point) const
|
||||
for (it = set.constBegin(); it != set.constEnd(); ++it)
|
||||
ret.append(_data.at(*it));
|
||||
|
||||
appendElevation(ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -206,8 +167,6 @@ QList<Waypoint> POI::points(const Area &area) const
|
||||
for (it = set.constBegin(); it != set.constEnd(); ++it)
|
||||
ret.append(_data.at(*it));
|
||||
|
||||
appendElevation(ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -253,10 +212,3 @@ void POI::setRadius(unsigned radius)
|
||||
|
||||
emit pointsChanged();
|
||||
}
|
||||
|
||||
void POI::useDEM(bool use)
|
||||
{
|
||||
_useDEM = use;
|
||||
|
||||
emit pointsChanged();
|
||||
}
|
||||
|
@ -20,13 +20,12 @@ public:
|
||||
POI(QObject *parent = 0);
|
||||
|
||||
bool loadFile(const QString &path);
|
||||
bool loadDir(const QString &path);
|
||||
void loadDir(const QString &path);
|
||||
const QString &errorString() const {return _errorString;}
|
||||
int errorLine() const {return _errorLine;}
|
||||
|
||||
unsigned radius() const {return _radius;}
|
||||
void setRadius(unsigned radius);
|
||||
void useDEM(bool use);
|
||||
|
||||
QList<Waypoint> points(const Path &path) const;
|
||||
QList<Waypoint> points(const Waypoint &point) const;
|
||||
@ -49,7 +48,6 @@ private:
|
||||
|
||||
bool loadFile(const QString &path, bool dir);
|
||||
void search(const RectC &rect, QSet<int> &set) const;
|
||||
void appendElevation(QList<Waypoint> &points) const;
|
||||
|
||||
POITree _tree;
|
||||
QVector<Waypoint> _data;
|
||||
@ -57,7 +55,6 @@ private:
|
||||
QList<FileIndex> _indexes;
|
||||
|
||||
unsigned _radius;
|
||||
bool _useDEM;
|
||||
|
||||
QString _errorString;
|
||||
int _errorLine;
|
||||
|
@ -1,5 +1,8 @@
|
||||
#include "dem.h"
|
||||
#include "route.h"
|
||||
|
||||
bool Route::_useDEM = false;
|
||||
bool Route::_show2ndElevation = false;
|
||||
|
||||
Route::Route(const RouteData &data) : _data(data)
|
||||
{
|
||||
@ -25,7 +28,7 @@ Path Route::path() const
|
||||
return ret;
|
||||
}
|
||||
|
||||
Graph Route::elevation() const
|
||||
Graph Route::gpsElevation() const
|
||||
{
|
||||
Graph graph;
|
||||
graph.append(GraphSegment());
|
||||
@ -38,6 +41,38 @@ Graph Route::elevation() const
|
||||
return graph;
|
||||
}
|
||||
|
||||
Graph Route::demElevation() const
|
||||
{
|
||||
Graph graph;
|
||||
graph.append(GraphSegment());
|
||||
GraphSegment &gs = graph.last();
|
||||
|
||||
for (int i = 0; i < _data.size(); i++) {
|
||||
qreal dem = DEM::elevation(_data.at(i).coordinates());
|
||||
if (!std::isnan(dem))
|
||||
gs.append(GraphPoint(_distance.at(i), NAN, dem));
|
||||
}
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
GraphPair Route::elevation() const
|
||||
{
|
||||
if (_useDEM) {
|
||||
Graph dem(demElevation());
|
||||
if (dem.isValid())
|
||||
return GraphPair(dem, _show2ndElevation ? gpsElevation() : Graph());
|
||||
else
|
||||
return GraphPair(gpsElevation(), Graph());
|
||||
} else {
|
||||
Graph gps(gpsElevation());
|
||||
if (gps.isValid())
|
||||
return GraphPair(gps, _show2ndElevation ? demElevation() : Graph());
|
||||
else
|
||||
return GraphPair(demElevation(), Graph());
|
||||
}
|
||||
}
|
||||
|
||||
qreal Route::distance() const
|
||||
{
|
||||
return (_distance.isEmpty()) ? 0 : _distance.last();
|
||||
|
@ -11,23 +11,31 @@ class Route
|
||||
public:
|
||||
Route(const RouteData &data);
|
||||
|
||||
Path path() const;
|
||||
|
||||
const RouteData &data() const {return _data;}
|
||||
|
||||
Graph elevation() const;
|
||||
|
||||
Path path() const;
|
||||
GraphPair elevation() const;
|
||||
qreal distance() const;
|
||||
|
||||
const QString &name() const {return _data.name();}
|
||||
const QString &description() const {return _data.description();}
|
||||
const QString &comment() const {return _data.comment();}
|
||||
const QVector<Link> &links() const {return _data.links();}
|
||||
|
||||
bool isValid() const {return _data.size() >= 2;}
|
||||
|
||||
static void useDEM(bool use) {_useDEM = use;}
|
||||
static void showSecondaryElevation(bool show)
|
||||
{_show2ndElevation = show;}
|
||||
|
||||
private:
|
||||
Graph gpsElevation() const;
|
||||
Graph demElevation() const;
|
||||
|
||||
RouteData _data;
|
||||
QVector<qreal> _distance;
|
||||
|
||||
static bool _useDEM;
|
||||
static bool _show2ndElevation;
|
||||
};
|
||||
|
||||
#endif // ROUTE_H
|
||||
|
@ -11,15 +11,18 @@ class RouteData : public QVector<Waypoint>
|
||||
public:
|
||||
const QString &name() const {return _name;}
|
||||
const QString &description() const {return _desc;}
|
||||
const QString &comment() const {return _comment;}
|
||||
const QVector<Link> &links() const {return _links;}
|
||||
|
||||
void setName(const QString &name) {_name = name;}
|
||||
void setDescription(const QString &desc) {_desc = desc;}
|
||||
void setComment(const QString &comment) {_comment = comment;}
|
||||
void addLink(const Link &link) {_links.append(link);}
|
||||
|
||||
private:
|
||||
QString _name;
|
||||
QString _desc;
|
||||
QString _comment;
|
||||
QVector<Link> _links;
|
||||
};
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include "dem.h"
|
||||
#include "track.h"
|
||||
|
||||
|
||||
@ -13,6 +14,9 @@ int Track::_pauseInterval = 10;
|
||||
|
||||
bool Track::_outlierEliminate = true;
|
||||
bool Track::_useReportedSpeed = false;
|
||||
bool Track::_useDEM = false;
|
||||
bool Track::_show2ndElevation = false;
|
||||
bool Track::_show2ndSpeed = false;
|
||||
|
||||
|
||||
static qreal avg(const QVector<qreal> &v)
|
||||
@ -38,6 +42,12 @@ static qreal MAD(QVector<qreal> &v, qreal m)
|
||||
return median(v);
|
||||
}
|
||||
|
||||
/*
|
||||
Modified Z-score (Iglewicz and Hoaglin)
|
||||
The acceleration data distribution has usualy a (much) higher kurtosis than
|
||||
the normal distribution thus a higher comparsion value than the usual 3.5 is
|
||||
required.
|
||||
*/
|
||||
static QSet<int> eliminate(const QVector<qreal> &v)
|
||||
{
|
||||
QSet<int> rm;
|
||||
@ -47,7 +57,7 @@ static QSet<int> eliminate(const QVector<qreal> &v)
|
||||
qreal M = MAD(w, m);
|
||||
|
||||
for (int i = 0; i < v.size(); i++)
|
||||
if (qAbs((0.6745 * (v.at(i) - m)) / M) > 5)
|
||||
if (qAbs((0.6745 * (v.at(i) - m)) / M) > 5.0)
|
||||
rm.insert(i);
|
||||
|
||||
return rm;
|
||||
@ -213,7 +223,7 @@ Track::Track(const TrackData &data) : _data(data), _pause(0)
|
||||
}
|
||||
}
|
||||
|
||||
Graph Track::elevation() const
|
||||
Graph Track::gpsElevation() const
|
||||
{
|
||||
Graph ret;
|
||||
|
||||
@ -237,7 +247,48 @@ Graph Track::elevation() const
|
||||
return ret;
|
||||
}
|
||||
|
||||
Graph Track::speed() const
|
||||
Graph Track::demElevation() const
|
||||
{
|
||||
Graph ret;
|
||||
|
||||
for (int i = 0; i < _data.size(); i++) {
|
||||
const SegmentData &sd = _data.at(i);
|
||||
if (sd.size() < 2)
|
||||
continue;
|
||||
const Segment &seg = _segments.at(i);
|
||||
GraphSegment gs;
|
||||
|
||||
for (int j = 0; j < sd.size(); j++) {
|
||||
qreal dem = DEM::elevation(sd.at(j).coordinates());
|
||||
if (std::isnan(dem) || seg.outliers.contains(j))
|
||||
continue;
|
||||
gs.append(GraphPoint(seg.distance.at(j), seg.time.at(j), dem));
|
||||
}
|
||||
|
||||
ret.append(filter(gs, _elevationWindow));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
GraphPair Track::elevation() const
|
||||
{
|
||||
if (_useDEM) {
|
||||
Graph dem(demElevation());
|
||||
if (dem.isValid())
|
||||
return GraphPair(dem, _show2ndElevation ? gpsElevation() : Graph());
|
||||
else
|
||||
return GraphPair(gpsElevation(), Graph());
|
||||
} else {
|
||||
Graph gps(gpsElevation());
|
||||
if (gps.isValid())
|
||||
return GraphPair(gps, _show2ndElevation ? demElevation() : Graph());
|
||||
else
|
||||
return GraphPair(demElevation(), Graph());
|
||||
}
|
||||
}
|
||||
|
||||
Graph Track::computedSpeed() const
|
||||
{
|
||||
Graph ret;
|
||||
|
||||
@ -251,14 +302,10 @@ Graph Track::speed() const
|
||||
qreal v;
|
||||
|
||||
for (int j = 0; j < sd.size(); j++) {
|
||||
if (seg.stop.contains(j) && (!std::isnan(seg.speed.at(j))
|
||||
|| sd.at(j).hasSpeed())) {
|
||||
if (seg.stop.contains(j) && !std::isnan(seg.speed.at(j))) {
|
||||
v = 0;
|
||||
stop.append(gs.size());
|
||||
} else if (_useReportedSpeed && sd.at(j).hasSpeed()
|
||||
&& !seg.outliers.contains(j))
|
||||
v = sd.at(j).speed();
|
||||
else if (!std::isnan(seg.speed.at(j)) && !seg.outliers.contains(j))
|
||||
} else if (!std::isnan(seg.speed.at(j)) && !seg.outliers.contains(j))
|
||||
v = seg.speed.at(j);
|
||||
else
|
||||
continue;
|
||||
@ -276,6 +323,60 @@ Graph Track::speed() const
|
||||
return ret;
|
||||
}
|
||||
|
||||
Graph Track::reportedSpeed() const
|
||||
{
|
||||
Graph ret;
|
||||
|
||||
for (int i = 0; i < _data.size(); i++) {
|
||||
const SegmentData &sd = _data.at(i);
|
||||
if (sd.size() < 2)
|
||||
continue;
|
||||
const Segment &seg = _segments.at(i);
|
||||
GraphSegment gs;
|
||||
QList<int> stop;
|
||||
qreal v;
|
||||
|
||||
for (int j = 0; j < sd.size(); j++) {
|
||||
if (seg.stop.contains(j) && sd.at(j).hasSpeed()) {
|
||||
v = 0;
|
||||
stop.append(gs.size());
|
||||
} else if (sd.at(j).hasSpeed() && !seg.outliers.contains(j))
|
||||
v = sd.at(j).speed();
|
||||
else
|
||||
continue;
|
||||
|
||||
gs.append(GraphPoint(seg.distance.at(j), seg.time.at(j), v));
|
||||
}
|
||||
|
||||
ret.append(filter(gs, _speedWindow));
|
||||
GraphSegment &filtered = ret.last();
|
||||
|
||||
for (int j = 0; j < stop.size(); j++)
|
||||
filtered[stop.at(j)].setY(0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
GraphPair Track::speed() const
|
||||
{
|
||||
if (_useReportedSpeed) {
|
||||
Graph reported(reportedSpeed());
|
||||
if (reported.isValid())
|
||||
return GraphPair(reported, _show2ndSpeed ? computedSpeed()
|
||||
: Graph());
|
||||
else
|
||||
return GraphPair(computedSpeed(), Graph());
|
||||
} else {
|
||||
Graph computed(computedSpeed());
|
||||
if (computed.isValid())
|
||||
return GraphPair(computed, _show2ndSpeed ? reportedSpeed()
|
||||
: Graph());
|
||||
else
|
||||
return GraphPair(reportedSpeed(), Graph());
|
||||
}
|
||||
}
|
||||
|
||||
Graph Track::heartRate() const
|
||||
{
|
||||
Graph ret;
|
||||
|
@ -17,8 +17,8 @@ public:
|
||||
|
||||
Path path() const;
|
||||
|
||||
Graph elevation() const;
|
||||
Graph speed() const;
|
||||
GraphPair elevation() const;
|
||||
GraphPair speed() const;
|
||||
Graph heartRate() const;
|
||||
Graph temperature() const;
|
||||
Graph cadence() const;
|
||||
@ -32,6 +32,7 @@ public:
|
||||
|
||||
const QString &name() const {return _data.name();}
|
||||
const QString &description() const {return _data.description();}
|
||||
const QString &comment() const {return _data.comment();}
|
||||
const QVector<Link> &links() const {return _data.links();}
|
||||
|
||||
bool isValid() const;
|
||||
@ -47,6 +48,11 @@ public:
|
||||
static void setOutlierElimination(bool eliminate)
|
||||
{_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;}
|
||||
|
||||
private:
|
||||
struct Segment {
|
||||
@ -59,6 +65,11 @@ private:
|
||||
|
||||
bool discardStopPoint(const Segment &seg, int i) const;
|
||||
|
||||
Graph demElevation() const;
|
||||
Graph gpsElevation() const;
|
||||
Graph reportedSpeed() const;
|
||||
Graph computedSpeed() const;
|
||||
|
||||
TrackData _data;
|
||||
QList<Segment> _segments;
|
||||
qreal _pause;
|
||||
@ -73,6 +84,9 @@ private:
|
||||
static qreal _pauseSpeed;
|
||||
static int _pauseInterval;
|
||||
static bool _useReportedSpeed;
|
||||
static bool _useDEM;
|
||||
static bool _show2ndElevation;
|
||||
static bool _show2ndSpeed;
|
||||
};
|
||||
|
||||
#endif // TRACK_H
|
||||
|
@ -14,15 +14,18 @@ class TrackData : public QList<SegmentData>
|
||||
public:
|
||||
const QString &name() const {return _name;}
|
||||
const QString &description() const {return _desc;}
|
||||
const QString &comment() const {return _comment;}
|
||||
const QVector<Link> &links() const {return _links;}
|
||||
|
||||
void setName(const QString &name) {_name = name;}
|
||||
void setDescription(const QString &desc) {_desc = desc;}
|
||||
void setComment(const QString &comment) {_comment = comment;}
|
||||
void addLink(const Link &link) {_links.append(link);}
|
||||
|
||||
private:
|
||||
QString _name;
|
||||
QString _desc;
|
||||
QString _comment;
|
||||
QVector<Link> _links;
|
||||
};
|
||||
|
||||
|
23
src/data/waypoint.cpp
Normal file
23
src/data/waypoint.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
#include "dem.h"
|
||||
#include "waypoint.h"
|
||||
|
||||
bool Waypoint::_useDEM = false;
|
||||
bool Waypoint::_show2ndElevation = false;
|
||||
|
||||
QPair<qreal, qreal> Waypoint::elevations() const
|
||||
{
|
||||
if (_useDEM) {
|
||||
qreal dem = DEM::elevation(coordinates());
|
||||
if (!std::isnan(dem))
|
||||
return QPair<qreal, qreal>(dem, _show2ndElevation ? elevation()
|
||||
: NAN);
|
||||
else
|
||||
return QPair<qreal, qreal>(elevation(), NAN);
|
||||
} else {
|
||||
if (hasElevation())
|
||||
return QPair<qreal, qreal>(elevation(), _show2ndElevation
|
||||
? DEM::elevation(coordinates()) : NAN);
|
||||
else
|
||||
return QPair<qreal, qreal>(DEM::elevation(coordinates()), NAN);
|
||||
}
|
||||
}
|
@ -14,24 +14,29 @@
|
||||
class Waypoint
|
||||
{
|
||||
public:
|
||||
Waypoint() {_elevation = NAN;}
|
||||
Waypoint(const Coordinates &coordinates) : _coordinates(coordinates)
|
||||
{_elevation = NAN;}
|
||||
Waypoint() : _elevation(NAN) {}
|
||||
Waypoint(const Coordinates &coordinates)
|
||||
: _coordinates(coordinates), _elevation(NAN) {}
|
||||
|
||||
const Coordinates &coordinates() const {return _coordinates;}
|
||||
Coordinates &rcoordinates() {return _coordinates;}
|
||||
const QString &name() const {return _name;}
|
||||
const QString &description() const {return _description;}
|
||||
const QString &comment() const {return _comment;}
|
||||
const Address &address() const {return _address;}
|
||||
const QVector<ImageInfo> &images() const {return _images;}
|
||||
const QVector<Link> &links() const {return _links;}
|
||||
const QDateTime ×tamp() const {return _timestamp;}
|
||||
qreal elevation() const {return _elevation;}
|
||||
|
||||
QPair<qreal, qreal> elevations() const;
|
||||
|
||||
void setCoordinates(const Coordinates &coordinates)
|
||||
{_coordinates = coordinates;}
|
||||
void setName(const QString &name) {_name = name;}
|
||||
void setDescription(const QString &description)
|
||||
{_description = description;}
|
||||
void setComment(const QString &comment) {_comment = comment;}
|
||||
void setAddress(const Address &address) {_address = address;}
|
||||
void setTimestamp(const QDateTime ×tamp) {_timestamp = timestamp;}
|
||||
void setElevation(qreal elevation) {_elevation = elevation;}
|
||||
@ -44,15 +49,23 @@ public:
|
||||
{return this->_name == other._name
|
||||
&& this->_coordinates == other._coordinates;}
|
||||
|
||||
static void useDEM(bool use) {_useDEM = use;}
|
||||
static void showSecondaryElevation(bool show)
|
||||
{_show2ndElevation = show;}
|
||||
|
||||
private:
|
||||
Coordinates _coordinates;
|
||||
QString _name;
|
||||
QString _description;
|
||||
QString _comment;
|
||||
Address _address;
|
||||
QVector<ImageInfo> _images;
|
||||
QVector<Link> _links;
|
||||
QDateTime _timestamp;
|
||||
qreal _elevation;
|
||||
|
||||
static bool _useDEM;
|
||||
static bool _show2ndElevation;
|
||||
};
|
||||
|
||||
inline uint qHash(const Waypoint &key)
|
||||
@ -64,11 +77,9 @@ inline uint qHash(const Waypoint &key)
|
||||
inline QDebug operator<<(QDebug dbg, const Waypoint &waypoint)
|
||||
{
|
||||
dbg.nospace() << "Waypoint(" << waypoint.coordinates() << ", "
|
||||
<< waypoint.name() << ", " << waypoint.description() << ")";
|
||||
<< waypoint.name() << ")";
|
||||
return dbg.space();
|
||||
}
|
||||
#endif // QT_NO_DEBUG
|
||||
|
||||
Q_DECLARE_TYPEINFO(Waypoint, Q_MOVABLE_TYPE);
|
||||
|
||||
#endif // WAYPOINT_H
|
||||
|
@ -1,4 +1,7 @@
|
||||
#include "common/config.h"
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
#include "GUI/timezoneinfo.h"
|
||||
#endif // ENABLE_TIMEZONES
|
||||
#include "GUI/app.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@ -7,6 +10,9 @@ int main(int argc, char *argv[])
|
||||
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
#endif // ENABLE_HIDPI
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
qRegisterMetaTypeStreamOperators<TimeZoneInfo>("TimeZoneInfo");
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
App app(argc, argv);
|
||||
return app.run();
|
||||
|
@ -1,7 +1,13 @@
|
||||
#include <QPainter>
|
||||
#include <QImage>
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
||||
#include <QtCore/qmath.h>
|
||||
#else // QT5
|
||||
#include <QtMath>
|
||||
#endif // QT5
|
||||
#include "bitmapline.h"
|
||||
|
||||
|
||||
static QImage img2line(const QImage &img, int width)
|
||||
{
|
||||
Q_ASSERT(img.format() == QImage::Format_ARGB32_Premultiplied);
|
||||
@ -32,8 +38,8 @@ void BitmapLine::draw(QPainter *painter, const QPolygonF &line,
|
||||
painter->save();
|
||||
painter->translate(segment.p1());
|
||||
painter->rotate(-segment.angle());
|
||||
painter->drawImage(0, -img.height()/2, img2line(img, segment.length()));
|
||||
painter->drawImage(0.0, -img.height()/2.0, img2line(img,
|
||||
qCeil(segment.length())));
|
||||
painter->restore();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,8 +41,19 @@ bool BitStream1::flush()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BitStream4::flush()
|
||||
{
|
||||
if (_length && !_file.seek(_hdl, _hdl.pos() + _length))
|
||||
return false;
|
||||
|
||||
bool BitStream4::read(int bits, quint32 &val)
|
||||
_length = 0;
|
||||
_used = 32;
|
||||
_unused = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BitStream4F::read(int bits, quint32 &val)
|
||||
{
|
||||
if (bits <= 32 - (int)(_used + _unused)) {
|
||||
val = bits ? (_data << _used) >> (32 - bits) : 0;
|
||||
@ -50,6 +61,8 @@ bool BitStream4::read(int bits, quint32 &val)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_unused)
|
||||
return false;
|
||||
quint32 old = (_used < 32) ? (_data << _used) >> (32 - bits) : 0;
|
||||
quint32 bytes = qMin(_length, 4U);
|
||||
|
||||
@ -66,14 +79,123 @@ bool BitStream4::read(int bits, quint32 &val)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BitStream4::flush()
|
||||
BitStream4R::BitStream4R(const SubFile &file, SubFile::Handle &hdl,
|
||||
quint32 length) : BitStream4(file, hdl, length)
|
||||
{
|
||||
if (_length && !_file.seek(_hdl, _hdl.pos() + _length))
|
||||
_file.seek(_hdl, _hdl.pos() - 4);
|
||||
}
|
||||
|
||||
bool BitStream4R::readBytes(int bytes, quint32 &val)
|
||||
{
|
||||
quint32 bits = _used % 8;
|
||||
quint32 b;
|
||||
|
||||
if (bits) {
|
||||
if (!read(8 - bits, b))
|
||||
return false;
|
||||
Q_ASSERT(!b);
|
||||
}
|
||||
|
||||
return read(bytes * 8, val);
|
||||
}
|
||||
|
||||
bool BitStream4R::readVUInt32(quint32 &val)
|
||||
{
|
||||
quint32 b;
|
||||
quint8 bytes, shift;
|
||||
|
||||
if (!readBytes(1, b))
|
||||
return false;
|
||||
|
||||
_length = 0;
|
||||
_used = 32;
|
||||
_unused = 0;
|
||||
if ((b & 1) == 0) {
|
||||
if ((b & 2) == 0) {
|
||||
bytes = ((b >> 2) & 1) ^ 3;
|
||||
shift = 5;
|
||||
} else {
|
||||
shift = 6;
|
||||
bytes = 1;
|
||||
}
|
||||
} else {
|
||||
shift = 7;
|
||||
bytes = 0;
|
||||
}
|
||||
|
||||
val = b >> (8 - shift);
|
||||
|
||||
if (bytes) {
|
||||
if (!readBytes(bytes, b))
|
||||
return false;
|
||||
val = val | (b << shift);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BitStream4R::readVuint32SM(quint32 &val1, quint32 &val2, quint32 &val2Bits)
|
||||
{
|
||||
quint32 b, eb;
|
||||
|
||||
if (!readBytes(1, b))
|
||||
return false;
|
||||
|
||||
if (!(b & 1)) {
|
||||
val1 = b >> 3 & 0x1f;
|
||||
val2 = b >> 1 & 3;
|
||||
val2Bits = 2;
|
||||
} else {
|
||||
eb = b & 2;
|
||||
val2 = b >> 2 & 0x3f;
|
||||
val2Bits = eb * 2 + 6;
|
||||
if (!readBytes((eb >> 1 | 2) - 1, b))
|
||||
return false;
|
||||
if (eb) {
|
||||
val2 = val2 | (b & 0xf) << 6;
|
||||
b = b >> 4 & 0xfff;
|
||||
}
|
||||
val1 = b;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BitStream4R::skip(quint32 bytes)
|
||||
{
|
||||
if (bytes * 8 > bitsAvailable())
|
||||
return false;
|
||||
|
||||
quint32 ab = (32 - (_used + _unused))/8;
|
||||
if (bytes <= ab)
|
||||
_used += bytes * 8;
|
||||
else {
|
||||
quint32 seek = ((bytes - ab)/4)*4;
|
||||
quint32 read = (bytes - ab)%4;
|
||||
if (seek && !_file.seek(_hdl, _hdl.pos() - 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))
|
||||
return false;
|
||||
_length -= rb;
|
||||
_unused = (4 - rb) * 8;
|
||||
_used = read * 8;
|
||||
} else
|
||||
_used = 32;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BitStream4R::resize(quint32 length)
|
||||
{
|
||||
quint32 ab = (32 - _used)/8;
|
||||
|
||||
if (ab < length)
|
||||
_length = length - ab;
|
||||
else {
|
||||
_length = 0;
|
||||
_used += length * 8;
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ public:
|
||||
|
||||
bool read(int bits, quint32 &val);
|
||||
bool flush();
|
||||
quint32 bitsAvailable() const {return _length * 8 + _remaining;}
|
||||
quint64 bitsAvailable() const {return (quint64)_length * 8 + _remaining;}
|
||||
|
||||
private:
|
||||
const SubFile &_file;
|
||||
@ -25,15 +25,64 @@ public:
|
||||
: _file(file), _hdl(hdl), _length(length), _used(32), _unused(0),
|
||||
_data(0) {}
|
||||
|
||||
bool read(int bits, quint32 &val);
|
||||
bool flush();
|
||||
quint32 bitsAvailable() const {return _length * 8 + (32 - _used) - _unused;}
|
||||
quint64 bitsAvailable() const
|
||||
{return (quint64)_length * 8 + (32 - _used) - _unused;}
|
||||
|
||||
private:
|
||||
protected:
|
||||
const SubFile &_file;
|
||||
SubFile::Handle &_hdl;
|
||||
quint32 _length, _used, _unused;
|
||||
quint32 _data;
|
||||
};
|
||||
|
||||
class BitStream4F : public BitStream4 {
|
||||
public:
|
||||
BitStream4F(const SubFile &file, SubFile::Handle &hdl, quint32 length)
|
||||
: BitStream4(file, hdl, length) {}
|
||||
|
||||
bool read(int bits, quint32 &val);
|
||||
};
|
||||
|
||||
class BitStream4R : public BitStream4 {
|
||||
public:
|
||||
BitStream4R(const SubFile &file, SubFile::Handle &hdl, quint32 length);
|
||||
|
||||
template<typename T> bool read(int bits, T &val);
|
||||
bool readBytes(int bytes, quint32 &val);
|
||||
bool readVUInt32(quint32 &val);
|
||||
bool readVuint32SM(quint32 &val1, quint32 &val2, quint32 &val2Bits);
|
||||
|
||||
bool skip(quint32 bytes);
|
||||
void resize(quint32 length);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
bool BitStream4R::read(int bits, T &val)
|
||||
{
|
||||
if (bits <= 32 - (int)(_used + _unused)) {
|
||||
val = bits ? (_data << _used) >> (32 - bits) : 0;
|
||||
_used += bits;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_unused)
|
||||
return false;
|
||||
quint32 old = (_used < 32) ? (_data << _used) >> (32 - bits) : 0;
|
||||
quint32 bytes = qMin(_length, 4U);
|
||||
|
||||
if (!_file.readUInt32(_hdl, _data))
|
||||
return false;
|
||||
if (!_file.seek(_hdl, _hdl.pos() - 8))
|
||||
return false;
|
||||
|
||||
_length -= bytes;
|
||||
_used -= 32 - bits;
|
||||
_unused = (4 - bytes) * 8;
|
||||
|
||||
val = _data >> (32 - _used) | old;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // BITSTREAM_H
|
||||
|
@ -84,11 +84,13 @@ bool GMAP::loadTile(const QDir &dir, bool baseMap)
|
||||
tile->addFile(fi.absoluteFilePath(), tileType(fi.suffix()));
|
||||
}
|
||||
|
||||
if (!tile->init(baseMap)) {
|
||||
if (!tile->init()) {
|
||||
qWarning("%s: Invalid map tile", qPrintable(dir.path()));
|
||||
delete tile;
|
||||
return false;
|
||||
}
|
||||
if (baseMap)
|
||||
tile->markAsBasemap();
|
||||
|
||||
double min[2], max[2];
|
||||
min[0] = tile->bounds().left();
|
||||
@ -98,6 +100,8 @@ bool GMAP::loadTile(const QDir &dir, bool baseMap)
|
||||
_tileTree.Insert(min, max, tile);
|
||||
|
||||
_bounds |= tile->bounds();
|
||||
if (tile->zooms().min() < _zooms.min())
|
||||
_zooms.setMin(tile->zooms().min());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1,74 +1,30 @@
|
||||
#include "huffmanstream.h"
|
||||
|
||||
|
||||
HuffmanStream::HuffmanStream(const SubFile &file, SubFile::Handle &hdl,
|
||||
quint32 length, const HuffmanTable &table, bool line)
|
||||
: BitStream4(file, hdl, length), _table(table), _symbolDataSize(0),
|
||||
_symbolData(0)
|
||||
bool HuffmanStreamF::init(bool line)
|
||||
{
|
||||
if (line) {
|
||||
if (!(sign(_lonSign) && sign(_latSign)))
|
||||
return;
|
||||
return false;
|
||||
} else {
|
||||
_lonSign = 0;
|
||||
_latSign = 0;
|
||||
}
|
||||
|
||||
quint32 eb;
|
||||
if (!read(1, eb))
|
||||
return;
|
||||
if (!_bs.read(1, eb))
|
||||
return false;
|
||||
if (eb) {
|
||||
qWarning("Extended polygon/lines not supported");
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
bool HuffmanStream::sign(int &val)
|
||||
{
|
||||
quint32 bit;
|
||||
val = 0;
|
||||
|
||||
if (!read(1, bit))
|
||||
qWarning() << "Extended lines/polygons not supported";
|
||||
return false;
|
||||
if (bit) {
|
||||
if (!read(1, bit))
|
||||
return false;
|
||||
val = bit ? -1 : 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HuffmanStream::readDelta(int sign, qint32 &symbol)
|
||||
bool HuffmanStreamR::init()
|
||||
{
|
||||
quint8 size;
|
||||
quint32 next;
|
||||
quint8 nextSize = qMin((quint32)(32 - _symbolDataSize), bitsAvailable());
|
||||
|
||||
if (!read(nextSize, next))
|
||||
if (!(sign(_lonSign) && sign(_latSign)))
|
||||
return false;
|
||||
|
||||
_symbolData = (_symbolData << nextSize) | next;
|
||||
_symbolDataSize += nextSize;
|
||||
|
||||
symbol = _table.symbol(_symbolData << (32 - _symbolDataSize), size);
|
||||
|
||||
if (size <= _symbolDataSize)
|
||||
_symbolDataSize -= size;
|
||||
else
|
||||
return false;
|
||||
|
||||
if (symbol && !sign) {
|
||||
if (!_symbolDataSize)
|
||||
return false;
|
||||
else {
|
||||
sign = ((1U << (_symbolDataSize - 1)) & _symbolData) ? -1 : 1;
|
||||
_symbolDataSize--;
|
||||
}
|
||||
}
|
||||
symbol = sign * symbol;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -4,10 +4,12 @@
|
||||
#include "bitstream.h"
|
||||
#include "huffmantable.h"
|
||||
|
||||
class HuffmanStream : public BitStream4 {
|
||||
template <class BitStream>
|
||||
class HuffmanStream {
|
||||
public:
|
||||
HuffmanStream(const SubFile &file, SubFile::Handle &hdl, quint32 length,
|
||||
const HuffmanTable &table, bool line);
|
||||
HuffmanStream(BitStream &bitstream, const HuffmanTable &table)
|
||||
: _bs(bitstream), _table(table), _symbolDataSize(0), _symbolData(0),
|
||||
_lonSign(0), _latSign(0) {}
|
||||
|
||||
bool readNext(qint32 &lonDelta, qint32 &latDelta)
|
||||
{
|
||||
@ -17,19 +19,87 @@ public:
|
||||
return (lonDelta || latDelta);
|
||||
}
|
||||
|
||||
bool readOffset(qint32 &lonDelta, qint32 &latDelta)
|
||||
{return (readDelta(1, lonDelta) && readDelta(1, latDelta));}
|
||||
bool atEnd() const
|
||||
{return _symbolDataSize + bitsAvailable() < _table.maxSymbolSize();}
|
||||
{return _symbolDataSize + _bs.bitsAvailable() < _table.maxSymbolSize();}
|
||||
bool flush() {return _bs.flush();}
|
||||
|
||||
private:
|
||||
protected:
|
||||
bool sign(int &val);
|
||||
bool readDelta(int sign, qint32 &delta);
|
||||
|
||||
BitStream &_bs;
|
||||
const HuffmanTable &_table;
|
||||
quint32 _symbolDataSize;
|
||||
quint32 _symbolData;
|
||||
int _lonSign, _latSign;
|
||||
};
|
||||
|
||||
template <class BitStream>
|
||||
bool HuffmanStream<BitStream>::sign(int &val)
|
||||
{
|
||||
quint32 bit;
|
||||
val = 0;
|
||||
|
||||
if (!_bs.read(1, bit))
|
||||
return false;
|
||||
if (bit) {
|
||||
if (!_bs.read(1, bit))
|
||||
return false;
|
||||
val = bit ? -1 : 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class BitStream>
|
||||
bool HuffmanStream<BitStream>::readDelta(int sign, qint32 &symbol)
|
||||
{
|
||||
quint8 size;
|
||||
quint32 next;
|
||||
quint8 nextSize = qMin((quint64)(32 - _symbolDataSize), _bs.bitsAvailable());
|
||||
|
||||
if (!_bs.read(nextSize, next))
|
||||
return false;
|
||||
|
||||
_symbolData = (_symbolData << nextSize) | next;
|
||||
_symbolDataSize += nextSize;
|
||||
|
||||
symbol = _table.symbol(_symbolData << (32 - _symbolDataSize), size);
|
||||
|
||||
if (size <= _symbolDataSize)
|
||||
_symbolDataSize -= size;
|
||||
else
|
||||
return false;
|
||||
|
||||
if (symbol && !sign) {
|
||||
if (!_symbolDataSize)
|
||||
return false;
|
||||
else {
|
||||
sign = ((1U << (_symbolDataSize - 1)) & _symbolData) ? -1 : 1;
|
||||
_symbolDataSize--;
|
||||
}
|
||||
}
|
||||
symbol = sign * symbol;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
class HuffmanStreamF : public HuffmanStream<BitStream4F> {
|
||||
public:
|
||||
HuffmanStreamF(BitStream4F &bitstream, const HuffmanTable &table)
|
||||
: HuffmanStream(bitstream, table) {}
|
||||
|
||||
bool init(bool line);
|
||||
bool readOffset(qint32 &lonDelta, qint32 &latDelta)
|
||||
{return (readDelta(1, lonDelta) && readDelta(1, latDelta));}
|
||||
};
|
||||
|
||||
class HuffmanStreamR : public HuffmanStream<BitStream4R> {
|
||||
public:
|
||||
HuffmanStreamR(BitStream4R &bitstream, const HuffmanTable &table)
|
||||
: HuffmanStream(bitstream, table) {}
|
||||
|
||||
bool init();
|
||||
};
|
||||
|
||||
#endif // HUFFMANSTREAM_H
|
||||
|
@ -42,6 +42,8 @@ bool HuffmanTable::load(const SubFile &file, SubFile::Handle &hdl,
|
||||
_s10 = _s14 + _s1c * _s1d;
|
||||
_s18 = _s10 + (_s1 << _s0);
|
||||
|
||||
_id = id;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,8 @@ public:
|
||||
quint8 maxSymbolSize() const {return _s2;}
|
||||
quint32 symbol(quint32 data, quint8 &size) const;
|
||||
|
||||
quint8 id() const {return _id;}
|
||||
|
||||
private:
|
||||
bool getBuffer(const SubFile &file, SubFile::Handle &hdl, quint32 offset,
|
||||
quint32 size, quint8 id);
|
||||
@ -22,6 +24,8 @@ private:
|
||||
quint8 *_s10, *_s14, *_s18;
|
||||
quint8 _s1c, _s1d, _s1e, _s1f, _s20;
|
||||
quint16 _s22;
|
||||
|
||||
quint8 _id;
|
||||
};
|
||||
|
||||
#endif // HUFFMANTABLE_H
|
||||
|
@ -59,7 +59,7 @@ IMG::IMG(const QString &fileName) : _file(fileName)
|
||||
|
||||
QByteArray nba(QByteArray(d1, sizeof(d1)) + QByteArray(d2, sizeof(d2)));
|
||||
_name = QString::fromLatin1(nba.constData(), nba.size()-1).trimmed();
|
||||
_blockSize = 1 << (e1 + e2);
|
||||
_blockBits = e1 + e2;
|
||||
|
||||
// Read the FAT table
|
||||
quint8 flag;
|
||||
@ -132,11 +132,12 @@ IMG::IMG(const QString &fileName) : _file(fileName)
|
||||
}
|
||||
|
||||
// Create tile tree
|
||||
int minMapZoom = 24;
|
||||
for (TileMap::const_iterator it = tileMap.constBegin();
|
||||
it != tileMap.constEnd(); ++it) {
|
||||
VectorTile *tile = it.value();
|
||||
|
||||
if (!tile->init(false)) {
|
||||
if (!tile->init()) {
|
||||
qWarning("%s: %s: Invalid map tile", qPrintable(_file.fileName()),
|
||||
qPrintable(it.key()));
|
||||
delete tile;
|
||||
@ -151,8 +152,26 @@ IMG::IMG(const QString &fileName) : _file(fileName)
|
||||
_tileTree.Insert(min, max, tile);
|
||||
|
||||
_bounds |= tile->bounds();
|
||||
if (tile->zooms().min() < _zooms.min())
|
||||
_zooms.setMin(tile->zooms().min());
|
||||
if (tile->zooms().min() < minMapZoom)
|
||||
minMapZoom = tile->zooms().min();
|
||||
}
|
||||
|
||||
// Detect and mark basemap
|
||||
TileTree::Iterator it;
|
||||
for (_tileTree.GetFirst(it); !_tileTree.IsNull(it); _tileTree.GetNext(it)) {
|
||||
VectorTile *tile = _tileTree.GetAt(it);
|
||||
if (tile->zooms().min() > minMapZoom)
|
||||
_baseMap = true;
|
||||
if (tile->zooms().min() == minMapZoom)
|
||||
tile->markAsBasemap();
|
||||
}
|
||||
// Allow some extra zoom out on maps without basemaps, but not too much as
|
||||
// this would kill the rendering performance
|
||||
if (!_baseMap)
|
||||
_zooms.setMin(_zooms.min() - 2);
|
||||
|
||||
if (!_tileTree.Count())
|
||||
_errorString = "No usable map tile found";
|
||||
else
|
||||
@ -182,9 +201,9 @@ template<class T> bool IMG::readValue(T &val)
|
||||
|
||||
bool IMG::readBlock(int blockNum, char *data)
|
||||
{
|
||||
if (!_file.seek((qint64)blockNum * (qint64)_blockSize))
|
||||
if (!_file.seek((quint64)blockNum << _blockBits))
|
||||
return false;
|
||||
if (read(data, _blockSize) < _blockSize)
|
||||
if (read(data, 1U<<_blockBits) < 1U<<_blockBits)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -14,14 +14,14 @@ public:
|
||||
private:
|
||||
friend class SubFile;
|
||||
|
||||
int blockSize() const {return _blockSize;}
|
||||
unsigned blockBits() const {return _blockBits;}
|
||||
bool readBlock(int blockNum, char *data);
|
||||
qint64 read(char *data, qint64 maxSize);
|
||||
template<class T> bool readValue(T &val);
|
||||
|
||||
QFile _file;
|
||||
quint8 _key;
|
||||
int _blockSize;
|
||||
unsigned _blockBits;
|
||||
};
|
||||
|
||||
#endif // IMG_H
|
||||
|
@ -30,15 +30,20 @@ static quint8 SPECIAL_CHARS[] = {
|
||||
'8', '9', '~', '~', '~', '~', '~', '~'
|
||||
};
|
||||
|
||||
static QString capitalize(const QString &str)
|
||||
static bool isAllUpperCase(const QString &str)
|
||||
{
|
||||
if (str.isEmpty())
|
||||
return str;
|
||||
return false;
|
||||
for (int i = 0; i < str.size(); i++)
|
||||
if (str.at(i).isLetter() && !(str.at(i).isUpper()
|
||||
|| str.at(i) == QChar(0x00DF)))
|
||||
return str;
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static QString capitalized(const QString &str)
|
||||
{
|
||||
QString ret(str);
|
||||
for (int i = 0; i < str.size(); i++)
|
||||
if (i && !str.at(i-1).isSpace())
|
||||
@ -77,7 +82,7 @@ bool LBLFile::init(Handle &hdl)
|
||||
return true;
|
||||
}
|
||||
|
||||
Label LBLFile::label6b(Handle &hdl, quint32 offset) const
|
||||
Label LBLFile::label6b(Handle &hdl, quint32 offset, bool capitalize) const
|
||||
{
|
||||
Label::Shield::Type shieldType = Label::Shield::None;
|
||||
QByteArray label, shieldLabel;
|
||||
@ -95,9 +100,12 @@ Label LBLFile::label6b(Handle &hdl, quint32 offset) const
|
||||
int c[]= {b1>>2, (b1&0x3)<<4|b2>>4, (b2&0xF)<<2|b3>>6, b3&0x3F};
|
||||
|
||||
for (int cpt = 0; cpt < 4; cpt++) {
|
||||
if (c[cpt] > 0x2f || (curCharSet == Normal && c[cpt] == 0x1d))
|
||||
return Label(capitalize(QString::fromLatin1(label)),
|
||||
Label::Shield(shieldType, shieldLabel));
|
||||
if (c[cpt] > 0x2f || (curCharSet == Normal && c[cpt] == 0x1d)) {
|
||||
QString text(QString::fromLatin1(label));
|
||||
return Label(capitalize && isAllUpperCase(text)
|
||||
? capitalized(text) : text, Label::Shield(shieldType,
|
||||
shieldLabel));
|
||||
}
|
||||
switch (curCharSet) {
|
||||
case Normal:
|
||||
if (c[cpt] == 0x1c)
|
||||
@ -127,7 +135,7 @@ Label LBLFile::label6b(Handle &hdl, quint32 offset) const
|
||||
}
|
||||
}
|
||||
|
||||
Label LBLFile::label8b(Handle &hdl, quint32 offset) const
|
||||
Label LBLFile::label8b(Handle &hdl, quint32 offset, bool capitalize) const
|
||||
{
|
||||
Label::Shield::Type shieldType = Label::Shield::None;
|
||||
QByteArray label, shieldLabel;
|
||||
@ -143,7 +151,9 @@ Label LBLFile::label8b(Handle &hdl, quint32 offset) const
|
||||
if (!c || c == 0x1d)
|
||||
break;
|
||||
|
||||
if ((c >= 0x1e && c <= 0x1f)) {
|
||||
if (c == 0x1c)
|
||||
capitalize = false;
|
||||
else if ((c >= 0x1e && c <= 0x1f)) {
|
||||
if (bap == &shieldLabel)
|
||||
bap = &label;
|
||||
else
|
||||
@ -157,12 +167,15 @@ Label LBLFile::label8b(Handle &hdl, quint32 offset) const
|
||||
bap->append(c);
|
||||
}
|
||||
|
||||
return Label(capitalize(_codec ? _codec->toUnicode(label)
|
||||
: QString::fromLatin1(label)), Label::Shield(shieldType, _codec
|
||||
? _codec->toUnicode(shieldLabel) : QString::fromLatin1(shieldLabel)));
|
||||
QString text(_codec ? _codec->toUnicode(label) : QString::fromLatin1(label));
|
||||
QString shieldText(_codec ? _codec->toUnicode(shieldLabel)
|
||||
: QString::fromLatin1(shieldLabel));
|
||||
|
||||
return Label(capitalize && isAllUpperCase(text) ? capitalized(text) : text,
|
||||
Label::Shield(shieldType, shieldText));
|
||||
}
|
||||
|
||||
Label LBLFile::label(Handle &hdl, quint32 offset, bool poi)
|
||||
Label LBLFile::label(Handle &hdl, quint32 offset, bool poi, bool capitalize)
|
||||
{
|
||||
if (!_multiplier && !init(hdl))
|
||||
return QString();
|
||||
@ -183,10 +196,10 @@ Label LBLFile::label(Handle &hdl, quint32 offset, bool poi)
|
||||
|
||||
switch (_encoding) {
|
||||
case 6:
|
||||
return label6b(hdl, labelOffset);
|
||||
return label6b(hdl, labelOffset, capitalize);
|
||||
case 9:
|
||||
case 10:
|
||||
return label8b(hdl, labelOffset);
|
||||
return label8b(hdl, labelOffset, capitalize);
|
||||
default:
|
||||
return Label();
|
||||
}
|
||||
|
@ -19,13 +19,14 @@ public:
|
||||
_codec(0), _offset(0), _size(0), _poiOffset(0), _poiSize(0),
|
||||
_poiMultiplier(0), _multiplier(0), _encoding(0) {}
|
||||
|
||||
Label label(Handle &hdl, quint32 offset, bool poi = false);
|
||||
Label label(Handle &hdl, quint32 offset, bool poi = false,
|
||||
bool capitalize = true);
|
||||
|
||||
private:
|
||||
bool init(Handle &hdl);
|
||||
|
||||
Label label6b(Handle &hdl, quint32 offset) const;
|
||||
Label label8b(Handle &hdl, quint32 offset) const;
|
||||
Label label6b(Handle &hdl, quint32 offset, bool capitalize) const;
|
||||
Label label8b(Handle &hdl, quint32 offset, bool capitalize) const;
|
||||
|
||||
QTextCodec *_codec;
|
||||
quint32 _offset;
|
||||
|
@ -54,7 +54,8 @@ inline bool pointCb(VectorTile *tile, void *context)
|
||||
}
|
||||
|
||||
|
||||
MapData::MapData() : _typ(0), _style(0), _baseMap(false), _valid(false)
|
||||
MapData::MapData() : _typ(0), _style(0), _zooms(24, 28), _baseMap(false),
|
||||
_valid(false)
|
||||
{
|
||||
_polyCache.setMaxCost(CACHED_SUBDIVS_COUNT);
|
||||
_pointCache.setMaxCost(CACHED_SUBDIVS_COUNT);
|
||||
@ -104,8 +105,12 @@ void MapData::load()
|
||||
if (_typ)
|
||||
_style = new Style(_typ);
|
||||
else {
|
||||
SubFile typ(ProgramPaths::typFile());
|
||||
_style = new Style(&typ);
|
||||
QString typFile(ProgramPaths::typFile());
|
||||
if (!typFile.isEmpty()) {
|
||||
SubFile typ(typFile);
|
||||
_style = new Style(&typ);
|
||||
} else
|
||||
_style = new Style();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <QDebug>
|
||||
#include "common/rectc.h"
|
||||
#include "common/rtree.h"
|
||||
#include "common/range.h"
|
||||
#include "label.h"
|
||||
|
||||
class Style;
|
||||
@ -58,6 +59,7 @@ public:
|
||||
|
||||
const QString &name() const {return _name;}
|
||||
const RectC &bounds() const {return _bounds;}
|
||||
const Range &zooms() const {return _zooms;}
|
||||
const Style *style() const {return _style;}
|
||||
void polys(const RectC &rect, int bits, QList<Poly> *polygons,
|
||||
QList<Poly> *lines);
|
||||
@ -79,6 +81,7 @@ protected:
|
||||
SubFile *_typ;
|
||||
Style *_style;
|
||||
TileTree _tileTree;
|
||||
Range _zooms;
|
||||
bool _baseMap;
|
||||
|
||||
bool _valid;
|
||||
|
@ -1,5 +1,89 @@
|
||||
#include "bitstream.h"
|
||||
#include "huffmanstream.h"
|
||||
#include "subdiv.h"
|
||||
#include "nodfile.h"
|
||||
#include "netfile.h"
|
||||
|
||||
|
||||
bool adjCnts(BitStream4R &bs, QVector<quint16> &cnts, quint16 &mask)
|
||||
{
|
||||
quint32 val, cnt, bits;
|
||||
if (!bs.read(4, val))
|
||||
return false;
|
||||
|
||||
cnt = ((val >> 2) & 3) + 2;
|
||||
bits = ((val * 2) & 6) + 4;
|
||||
mask = 1<<(3 + ((val * 2) & 6));
|
||||
if (cnt == 5) {
|
||||
if (!bs.read(8, cnt))
|
||||
return false;
|
||||
Q_ASSERT(cnt > 4);
|
||||
}
|
||||
|
||||
if (cnt < 2)
|
||||
return false;
|
||||
cnts.resize(cnt - 1);
|
||||
for (int i = 0; i < cnts.size(); i++)
|
||||
if (!bs.read(bits, cnts[i]))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool skipNodes(BitStream4R &bs, const QVector<quint16> &cnts, quint16 mask)
|
||||
{
|
||||
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))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool seekToLevel(BitStream4R &bs, quint8 level)
|
||||
{
|
||||
quint32 v1, v2, v2b;
|
||||
|
||||
for (quint8 i = 1; i < level; ) {
|
||||
if (!bs.readVuint32SM(v1, v2, v2b))
|
||||
return false;
|
||||
if (!bs.skip(v1))
|
||||
return false;
|
||||
|
||||
Q_ASSERT(!(v2 & 2));
|
||||
if (v2 & 2)
|
||||
return false;
|
||||
if (v2 & 1)
|
||||
i++;
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool seekToLine(BitStream4R &bs, quint8 line)
|
||||
{
|
||||
quint32 v1, v2, v2b;
|
||||
|
||||
for (quint8 i = 0; i < line; i++) {
|
||||
if (!bs.readVuint32SM(v1, v2, v2b))
|
||||
return false;
|
||||
if (!bs.skip(v1))
|
||||
return false;
|
||||
|
||||
Q_ASSERT(!(v2 & 2));
|
||||
if (v2 & 2)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool NETFile::init(Handle &hdl)
|
||||
{
|
||||
quint8 multiplier;
|
||||
@ -10,11 +94,121 @@ bool NETFile::init(Handle &hdl)
|
||||
&& readUInt32(hdl, _size) && readUInt8(hdl, multiplier)))
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
if (!_multiplier && !init(hdl))
|
||||
return false;
|
||||
|
||||
// TODO
|
||||
if (!subdiv->level())
|
||||
return false;
|
||||
|
||||
NODFile::LinkInfo linkInfo;
|
||||
if (!nod->linkInfo(nodHdl, blockInfo, linkId, linkInfo))
|
||||
return false;
|
||||
|
||||
quint32 linkOffset = _linksOffset + (linkInfo.linkOffset << _linksShift);
|
||||
Q_ASSERT(linkOffset <= _linksOffset + _linksSize);
|
||||
|
||||
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 (!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))
|
||||
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))
|
||||
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);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NETFile::lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset)
|
||||
{
|
||||
if (!_multiplier && !init(hdl))
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user