mirror of
https://github.com/tumic0/GPXSee.git
synced 2025-07-06 07:32:51 +02:00
Compare commits
67 Commits
Author | SHA1 | Date | |
---|---|---|---|
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 |
@ -1,4 +1,4 @@
|
|||||||
version: 7.23.{build}
|
version: 7.27.{build}
|
||||||
|
|
||||||
configuration:
|
configuration:
|
||||||
- Release
|
- Release
|
||||||
|
@ -3,7 +3,7 @@ unix:!macx {
|
|||||||
} else {
|
} else {
|
||||||
TARGET = GPXSee
|
TARGET = GPXSee
|
||||||
}
|
}
|
||||||
VERSION = 7.23
|
VERSION = 7.27
|
||||||
|
|
||||||
QT += core \
|
QT += core \
|
||||||
gui \
|
gui \
|
||||||
@ -20,6 +20,7 @@ equals(QT_MAJOR_VERSION, 5) : lessThan(QT_MINOR_VERSION, 4) {QT += opengl}
|
|||||||
INCLUDEPATH += ./src
|
INCLUDEPATH += ./src
|
||||||
HEADERS += src/common/config.h \
|
HEADERS += src/common/config.h \
|
||||||
src/GUI/graphicsscene.h \
|
src/GUI/graphicsscene.h \
|
||||||
|
src/GUI/mapaction.h \
|
||||||
src/GUI/popup.h \
|
src/GUI/popup.h \
|
||||||
src/common/garmin.h \
|
src/common/garmin.h \
|
||||||
src/common/staticassert.h \
|
src/common/staticassert.h \
|
||||||
@ -248,6 +249,7 @@ SOURCES += src/main.cpp \
|
|||||||
src/GUI/gearratiographitem.cpp \
|
src/GUI/gearratiographitem.cpp \
|
||||||
src/GUI/mapview.cpp \
|
src/GUI/mapview.cpp \
|
||||||
src/GUI/areaitem.cpp \
|
src/GUI/areaitem.cpp \
|
||||||
|
src/data/waypoint.cpp \
|
||||||
src/map/IMG/bitmapline.cpp \
|
src/map/IMG/bitmapline.cpp \
|
||||||
src/map/IMG/bitstream.cpp \
|
src/map/IMG/bitstream.cpp \
|
||||||
src/map/IMG/deltastream.cpp \
|
src/map/IMG/deltastream.cpp \
|
||||||
|
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
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
|
; The name of the installer
|
||||||
Name "GPXSee"
|
Name "GPXSee"
|
||||||
; Program version
|
; Program version
|
||||||
!define VERSION "7.23"
|
!define VERSION "7.27"
|
||||||
|
|
||||||
; The file to write
|
; The file to write
|
||||||
OutFile "GPXSee-${VERSION}.exe"
|
OutFile "GPXSee-${VERSION}.exe"
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
; The name of the installer
|
; The name of the installer
|
||||||
Name "GPXSee"
|
Name "GPXSee"
|
||||||
; Program version
|
; Program version
|
||||||
!define VERSION "7.23"
|
!define VERSION "7.27"
|
||||||
|
|
||||||
; The file to write
|
; The file to write
|
||||||
OutFile "GPXSee-${VERSION}_x64.exe"
|
OutFile "GPXSee-${VERSION}_x64.exe"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?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>
|
<name>4UMaps</name>
|
||||||
<url>https://tileserver.4umaps.com/$z/$x/$y.png</url>
|
<url>https://tileserver.4umaps.com/$z/$x/$y.png</url>
|
||||||
<zoom min="2" max="15"/>
|
<zoom min="2" max="15"/>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-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>
|
<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://gis.ngdc.noaa.gov/arcgis/rest/services/antarctic/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>
|
<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>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?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>
|
<name>Open Street Map</name>
|
||||||
<url>https://tile.openstreetmap.org/$z/$x/$y.png</url>
|
<url>https://tile.openstreetmap.org/$z/$x/$y.png</url>
|
||||||
<copyright>Map data: © OpenStreetMap contributors (ODbL) | Rendering: © OpenStreetMap (CC-BY-SA)</copyright>
|
<copyright>Map data: © OpenStreetMap contributors (ODbL) | Rendering: © OpenStreetMap (CC-BY-SA)</copyright>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?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>
|
<name>Open Topo Map</name>
|
||||||
<url>https://a.tile.opentopomap.org/$z/$x/$y.png</url>
|
<url>https://a.tile.opentopomap.org/$z/$x/$y.png</url>
|
||||||
<zoom max="17"/>
|
<zoom max="17"/>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?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>
|
<name>USGS Imagery</name>
|
||||||
<url>https://basemap.nationalmap.gov/ArcGIS/rest/services/USGSImageryOnly/MapServer/tile/$z/$y/$x</url>
|
<url>https://basemap.nationalmap.gov/ArcGIS/rest/services/USGSImageryOnly/MapServer/tile/$z/$y/$x</url>
|
||||||
<zoom min="2" max="15"/>
|
<zoom min="2" max="15"/>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?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>
|
<name>USGS Topo</name>
|
||||||
<url>https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/tile/$z/$y/$x</url>
|
<url>https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/tile/$z/$y/$x</url>
|
||||||
<zoom min="2" max="15"/>
|
<zoom min="2" max="15"/>
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
CadenceGraphItem::CadenceGraphItem(const Graph &graph, GraphType type,
|
CadenceGraphItem::CadenceGraphItem(const Graph &graph, GraphType type,
|
||||||
int width, const QColor &color, QGraphicsItem *parent)
|
int width, const QColor &color, QGraphicsItem *parent)
|
||||||
: GraphItem(graph, type, width, color, parent)
|
: GraphItem(graph, type, width, color, Qt::SolidLine, parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,36 +65,39 @@ 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()) {
|
if (!graph.isValid())
|
||||||
_palette.nextColor();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
ElevationGraphItem *gi = new ElevationGraphItem(graph, _graphType, _width,
|
ElevationGraphItem *gi = new ElevationGraphItem(graph, _graphType, _width,
|
||||||
_palette.nextColor());
|
color, primary ? Qt::SolidLine : Qt::DashLine);
|
||||||
gi->setUnits(_units);
|
gi->setUnits(_units);
|
||||||
|
|
||||||
if (type == Track) {
|
if (type == TrackPath) {
|
||||||
_tracks.append(gi);
|
_tracks.append(gi);
|
||||||
if (_showTracks)
|
if (_showTracks)
|
||||||
addGraph(gi);
|
addGraph(gi);
|
||||||
|
|
||||||
|
if (primary) {
|
||||||
_trackAscent += gi->ascent();
|
_trackAscent += gi->ascent();
|
||||||
_trackDescent += gi->descent();
|
_trackDescent += gi->descent();
|
||||||
_trackMax = nMax(_trackMax, gi->max());
|
_trackMax = nMax(_trackMax, gi->max());
|
||||||
_trackMin = nMin(_trackMin, gi->min());
|
_trackMin = nMin(_trackMin, gi->min());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
_routes.append(gi);
|
_routes.append(gi);
|
||||||
if (_showRoutes)
|
if (_showRoutes)
|
||||||
addGraph(gi);
|
addGraph(gi);
|
||||||
|
|
||||||
|
if (primary) {
|
||||||
_routeAscent += gi->ascent();
|
_routeAscent += gi->ascent();
|
||||||
_routeDescent += gi->descent();
|
_routeDescent += gi->descent();
|
||||||
_routeMax = nMax(_routeMax, gi->max());
|
_routeMax = nMax(_routeMax, gi->max());
|
||||||
_routeMin = nMin(_routeMin, gi->min());
|
_routeMin = nMin(_routeMin, gi->min());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return gi;
|
return gi;
|
||||||
}
|
}
|
||||||
@ -102,11 +105,32 @@ GraphItem *ElevationGraph::loadGraph(const Graph &graph, Type type)
|
|||||||
QList<GraphItem*> ElevationGraph::loadData(const Data &data)
|
QList<GraphItem*> ElevationGraph::loadData(const Data &data)
|
||||||
{
|
{
|
||||||
QList<GraphItem*> graphs;
|
QList<GraphItem*> graphs;
|
||||||
|
GraphItem *primary, *secondary;
|
||||||
|
|
||||||
for (int i = 0; i < data.tracks().count(); i++)
|
for (int i = 0; i < data.tracks().count(); i++) {
|
||||||
graphs.append(loadGraph(data.tracks().at(i).elevation(), Track));
|
QColor color(_palette.nextColor());
|
||||||
for (int i = 0; i < data.routes().count(); i++)
|
const GraphPair &gp = data.tracks().at(i).elevation();
|
||||||
graphs.append(loadGraph(data.routes().at(i).elevation(), Route));
|
|
||||||
|
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++)
|
for (int i = 0; i < data.areas().count(); i++)
|
||||||
_palette.nextColor();
|
_palette.nextColor();
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ public:
|
|||||||
void showRoutes(bool show);
|
void showRoutes(bool show);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum Type {Track, Route};
|
enum PathType {TrackPath, RoutePath};
|
||||||
|
|
||||||
qreal max() const;
|
qreal max() const;
|
||||||
qreal min() const;
|
qreal min() const;
|
||||||
@ -31,7 +31,8 @@ private:
|
|||||||
void setYUnits(Units units);
|
void setYUnits(Units units);
|
||||||
void setInfo();
|
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);
|
void showItems(const QList<ElevationGraphItem *> &list, bool show);
|
||||||
|
|
||||||
qreal _trackAscent, _trackDescent;
|
qreal _trackAscent, _trackDescent;
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
|
|
||||||
ElevationGraphItem::ElevationGraphItem(const Graph &graph, GraphType type,
|
ElevationGraphItem::ElevationGraphItem(const Graph &graph, GraphType type,
|
||||||
int width, const QColor &color, QGraphicsItem *parent)
|
int width, const QColor &color, Qt::PenStyle style, QGraphicsItem *parent)
|
||||||
: GraphItem(graph, type, width, color, parent)
|
: GraphItem(graph, type, width, color, style, parent)
|
||||||
{
|
{
|
||||||
_min = GraphItem::min();
|
_min = GraphItem::min();
|
||||||
_max = GraphItem::max();
|
_max = GraphItem::max();
|
||||||
@ -42,5 +42,6 @@ QString ElevationGraphItem::info() const
|
|||||||
tt.insert(tr("Minimum"), l.toString(min() * scale, 'f', 0)
|
tt.insert(tr("Minimum"), l.toString(min() * scale, 'f', 0)
|
||||||
+ UNIT_SPACE + su);
|
+ UNIT_SPACE + su);
|
||||||
|
|
||||||
|
|
||||||
return tt.toString();
|
return tt.toString();
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,10 @@ class ElevationGraphItem : public GraphItem
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum DataType {GPS, DEM};
|
||||||
|
|
||||||
ElevationGraphItem(const Graph &graph, GraphType type, int width,
|
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 ascent() const {return _ascent;}
|
||||||
qreal descent() const {return _descent;}
|
qreal descent() const {return _descent;}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
GearRatioGraphItem::GearRatioGraphItem(const Graph &graph, GraphType type,
|
GearRatioGraphItem::GearRatioGraphItem(const Graph &graph, GraphType type,
|
||||||
int width, const QColor &color, QGraphicsItem *parent)
|
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++) {
|
for (int i = 0; i < graph.size(); i++) {
|
||||||
const GraphSegment &segment = graph.at(i);
|
const GraphSegment &segment = graph.at(i);
|
||||||
|
@ -5,13 +5,13 @@
|
|||||||
|
|
||||||
|
|
||||||
GraphItem::GraphItem(const Graph &graph, GraphType type, int width,
|
GraphItem::GraphItem(const Graph &graph, GraphType type, int width,
|
||||||
const QColor &color, QGraphicsItem *parent)
|
const QColor &color, Qt::PenStyle style, QGraphicsItem *parent)
|
||||||
: GraphicsItem(parent), _graph(graph), _type(type)
|
: GraphicsItem(parent), _graph(graph), _type(type), _secondaryGraph(0)
|
||||||
{
|
{
|
||||||
Q_ASSERT(_graph.isValid());
|
Q_ASSERT(_graph.isValid());
|
||||||
|
|
||||||
_units = Metric;
|
_units = Metric;
|
||||||
_pen = QPen(color, width);
|
_pen = QPen(color, width, style);
|
||||||
_sx = 0; _sy = 0;
|
_sx = 0; _sy = 0;
|
||||||
_time = _graph.hasTime();
|
_time = _graph.hasTime();
|
||||||
setZValue(2.0);
|
setZValue(2.0);
|
||||||
|
@ -12,8 +12,8 @@ class GraphItem : public QObject, public GraphicsItem
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GraphItem(const Graph &graph, GraphType type, int width, const QColor &color,
|
GraphItem(const Graph &graph, GraphType type, int width,
|
||||||
QGraphicsItem *parent = 0);
|
const QColor &color, Qt::PenStyle style, QGraphicsItem *parent = 0);
|
||||||
virtual ~GraphItem() {}
|
virtual ~GraphItem() {}
|
||||||
|
|
||||||
virtual QString info() const = 0;
|
virtual QString info() const = 0;
|
||||||
@ -35,6 +35,9 @@ public:
|
|||||||
void setWidth(int width);
|
void setWidth(int width);
|
||||||
void setUnits(Units units) {_units = units;}
|
void setUnits(Units units) {_units = units;}
|
||||||
|
|
||||||
|
GraphItem *secondaryGraph() const {return _secondaryGraph;}
|
||||||
|
void setSecondaryGraph(GraphItem *graph) {_secondaryGraph = graph;}
|
||||||
|
|
||||||
qreal yAtX(qreal x);
|
qreal yAtX(qreal x);
|
||||||
qreal distanceAtTime(qreal time);
|
qreal distanceAtTime(qreal time);
|
||||||
|
|
||||||
@ -69,6 +72,8 @@ private:
|
|||||||
qreal _sx, _sy;
|
qreal _sx, _sy;
|
||||||
QPen _pen;
|
QPen _pen;
|
||||||
bool _time;
|
bool _time;
|
||||||
|
|
||||||
|
GraphItem *_secondaryGraph;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // GRAPHITEM_H
|
#endif // GRAPHITEM_H
|
||||||
|
@ -274,8 +274,8 @@ void GraphView::redraw(const QSizeF &size)
|
|||||||
rx = RangeF(bounds().left() * _xScale, bounds().right() * _xScale);
|
rx = RangeF(bounds().left() * _xScale, bounds().right() * _xScale);
|
||||||
ry = RangeF(bounds().top() * _yScale + _yOffset, bounds().bottom() * _yScale
|
ry = RangeF(bounds().top() * _yScale + _yOffset, bounds().bottom() * _yScale
|
||||||
+ _yOffset);
|
+ _yOffset);
|
||||||
if (ry.size() < _minYRange)
|
if (ry.size() < _minYRange * _yScale)
|
||||||
ry.resize(_minYRange);
|
ry.resize(_minYRange * _yScale);
|
||||||
|
|
||||||
_xAxis->setRange(rx);
|
_xAxis->setRange(rx);
|
||||||
_yAxis->setRange(ry);
|
_yAxis->setRange(ry);
|
||||||
@ -419,14 +419,16 @@ void GraphView::updateSliderInfo()
|
|||||||
{
|
{
|
||||||
QLocale l(QLocale::system());
|
QLocale l(QLocale::system());
|
||||||
qreal r = 0, y = 0;
|
qreal r = 0, y = 0;
|
||||||
|
GraphItem *cardinal = (_graphs.count() == 1 || (_graphs.count() == 2
|
||||||
|
&& _graphs.first()->secondaryGraph())) ? _graphs.first() : 0;
|
||||||
|
|
||||||
if (_graphs.count() == 1) {
|
if (cardinal) {
|
||||||
QRectF br(_graphs.first()->bounds());
|
QRectF br(_bounds);
|
||||||
if (br.height() < _minYRange)
|
if (br.height() < _minYRange)
|
||||||
br.adjust(0, -(_minYRange/2 - br.height()/2), 0,
|
br.adjust(0, -(_minYRange/2 - br.height()/2), 0,
|
||||||
_minYRange/2 - br.height()/2);
|
_minYRange/2 - br.height()/2);
|
||||||
|
|
||||||
y = _graphs.first()->yAtX(_sliderPos);
|
y = cardinal->yAtX(_sliderPos);
|
||||||
r = (y - br.bottom()) / br.height();
|
r = (y - br.bottom()) / br.height();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -436,11 +438,17 @@ void GraphView::updateSliderInfo()
|
|||||||
|
|
||||||
_sliderInfo->setSide(s);
|
_sliderInfo->setSide(s);
|
||||||
_sliderInfo->setPos(QPointF(0, _slider->boundingRect().height() * r));
|
_sliderInfo->setPos(QPointF(0, _slider->boundingRect().height() * r));
|
||||||
_sliderInfo->setText(_graphType == Time ? Format::timeSpan(_sliderPos,
|
QString xText(_graphType == Time ? Format::timeSpan(_sliderPos,
|
||||||
bounds().width() > 3600) : l.toString(_sliderPos * _xScale, 'f', 1)
|
bounds().width() > 3600) : l.toString(_sliderPos * _xScale, 'f', 1)
|
||||||
+ UNIT_SPACE + _xUnits, (_graphs.count() > 1) ? QString()
|
+ UNIT_SPACE + _xUnits);
|
||||||
: l.toString(-y * _yScale + _yOffset, 'f', _precision) + UNIT_SPACE
|
QString yText((!cardinal) ? QString() : l.toString(-y * _yScale + _yOffset,
|
||||||
+ _yUnits);
|
'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)
|
void GraphView::emitSliderPositionChanged(const QPointF &pos)
|
||||||
|
220
src/GUI/gui.cpp
220
src/GUI/gui.cpp
@ -51,6 +51,7 @@
|
|||||||
#include "graphtab.h"
|
#include "graphtab.h"
|
||||||
#include "graphitem.h"
|
#include "graphitem.h"
|
||||||
#include "pathitem.h"
|
#include "pathitem.h"
|
||||||
|
#include "mapaction.h"
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
|
|
||||||
|
|
||||||
@ -58,7 +59,6 @@
|
|||||||
|
|
||||||
GUI::GUI()
|
GUI::GUI()
|
||||||
{
|
{
|
||||||
loadMaps();
|
|
||||||
loadPOIs();
|
loadPOIs();
|
||||||
|
|
||||||
createMapView();
|
createMapView();
|
||||||
@ -106,24 +106,13 @@ GUI::GUI()
|
|||||||
updateStatusBarInfo();
|
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()
|
void GUI::loadPOIs()
|
||||||
{
|
{
|
||||||
_poi = new POI(this);
|
_poi = new POI(this);
|
||||||
QString poiDir(ProgramPaths::poiDir());
|
|
||||||
|
|
||||||
if (!poiDir.isNull() && !_poi->loadDir(poiDir))
|
QString poiDir(ProgramPaths::poiDir());
|
||||||
qWarning("%s", qPrintable(_poi->errorString()));
|
if (!poiDir.isNull())
|
||||||
|
_poi->loadDir(poiDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUI::createBrowser()
|
void GUI::createBrowser()
|
||||||
@ -134,40 +123,56 @@ void GUI::createBrowser()
|
|||||||
|
|
||||||
void GUI::createMapActions()
|
void GUI::createMapActions()
|
||||||
{
|
{
|
||||||
_mapsSignalMapper = new QSignalMapper(this);
|
|
||||||
_mapsActionGroup = new QActionGroup(this);
|
_mapsActionGroup = new QActionGroup(this);
|
||||||
_mapsActionGroup->setExclusive(true);
|
_mapsActionGroup->setExclusive(true);
|
||||||
|
|
||||||
for (int i = 0; i < _ml->maps().count(); i++)
|
QString mapDir(ProgramPaths::mapDir());
|
||||||
createMapAction(_ml->maps().at(i));
|
if (mapDir.isNull())
|
||||||
|
return;
|
||||||
|
|
||||||
connect(_mapsSignalMapper, SIGNAL(mapped(int)), this,
|
QString unused;
|
||||||
SLOT(mapChanged(int)));
|
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->setMenuRole(QAction::NoRole);
|
||||||
a->setCheckable(true);
|
a->setCheckable(true);
|
||||||
a->setActionGroup(_mapsActionGroup);
|
a->setActionGroup(_mapsActionGroup);
|
||||||
|
connect(a, SIGNAL(triggered()), this, SLOT(mapChanged()));
|
||||||
_mapActions.append(a);
|
|
||||||
_mapsSignalMapper->setMapping(a, _mapActions.size() - 1);
|
|
||||||
connect(a, SIGNAL(triggered()), _mapsSignalMapper, SLOT(map()));
|
|
||||||
|
|
||||||
return a;
|
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()
|
void GUI::createPOIFilesActions()
|
||||||
{
|
{
|
||||||
_poiFilesSignalMapper = new QSignalMapper(this);
|
_poiFilesSignalMapper = new QSignalMapper(this);
|
||||||
|
connect(_poiFilesSignalMapper, SIGNAL(mapped(int)), this,
|
||||||
|
SLOT(poiFileChecked(int)));
|
||||||
|
|
||||||
for (int i = 0; i < _poi->files().count(); i++)
|
for (int i = 0; i < _poi->files().count(); i++)
|
||||||
createPOIFileAction(_poi->files().at(i));
|
createPOIFileAction(_poi->files().at(i));
|
||||||
|
|
||||||
connect(_poiFilesSignalMapper, SIGNAL(mapped(int)), this,
|
|
||||||
SLOT(poiFileChecked(int)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QAction *GUI::createPOIFileAction(const QString &fileName)
|
QAction *GUI::createPOIFileAction(const QString &fileName)
|
||||||
@ -281,8 +286,10 @@ void GUI::createActions()
|
|||||||
createPOIFilesActions();
|
createPOIFilesActions();
|
||||||
|
|
||||||
// Map actions
|
// Map actions
|
||||||
|
createMapActions();
|
||||||
_showMapAction = new QAction(QIcon(SHOW_MAP_ICON), tr("Show map"),
|
_showMapAction = new QAction(QIcon(SHOW_MAP_ICON), tr("Show map"),
|
||||||
this);
|
this);
|
||||||
|
_showMapAction->setEnabled(false);
|
||||||
_showMapAction->setMenuRole(QAction::NoRole);
|
_showMapAction->setMenuRole(QAction::NoRole);
|
||||||
_showMapAction->setCheckable(true);
|
_showMapAction->setCheckable(true);
|
||||||
_showMapAction->setShortcut(SHOW_MAP_SHORTCUT);
|
_showMapAction->setShortcut(SHOW_MAP_SHORTCUT);
|
||||||
@ -294,10 +301,10 @@ void GUI::createActions()
|
|||||||
_loadMapAction->setMenuRole(QAction::NoRole);
|
_loadMapAction->setMenuRole(QAction::NoRole);
|
||||||
connect(_loadMapAction, SIGNAL(triggered()), this, SLOT(loadMap()));
|
connect(_loadMapAction, SIGNAL(triggered()), this, SLOT(loadMap()));
|
||||||
_clearMapCacheAction = new QAction(tr("Clear tile cache"), this);
|
_clearMapCacheAction = new QAction(tr("Clear tile cache"), this);
|
||||||
|
_clearMapCacheAction->setEnabled(false);
|
||||||
_clearMapCacheAction->setMenuRole(QAction::NoRole);
|
_clearMapCacheAction->setMenuRole(QAction::NoRole);
|
||||||
connect(_clearMapCacheAction, SIGNAL(triggered()), _mapView,
|
connect(_clearMapCacheAction, SIGNAL(triggered()), _mapView,
|
||||||
SLOT(clearMapCache()));
|
SLOT(clearMapCache()));
|
||||||
createMapActions();
|
|
||||||
_nextMapAction = new QAction(tr("Next map"), this);
|
_nextMapAction = new QAction(tr("Next map"), this);
|
||||||
_nextMapAction->setMenuRole(QAction::NoRole);
|
_nextMapAction->setMenuRole(QAction::NoRole);
|
||||||
_nextMapAction->setShortcut(NEXT_MAP_SHORTCUT);
|
_nextMapAction->setShortcut(NEXT_MAP_SHORTCUT);
|
||||||
@ -308,10 +315,6 @@ void GUI::createActions()
|
|||||||
_prevMapAction->setShortcut(PREV_MAP_SHORTCUT);
|
_prevMapAction->setShortcut(PREV_MAP_SHORTCUT);
|
||||||
connect(_prevMapAction, SIGNAL(triggered()), this, SLOT(prevMap()));
|
connect(_prevMapAction, SIGNAL(triggered()), this, SLOT(prevMap()));
|
||||||
addAction(_prevMapAction);
|
addAction(_prevMapAction);
|
||||||
if (_ml->maps().isEmpty()) {
|
|
||||||
_showMapAction->setEnabled(false);
|
|
||||||
_clearMapCacheAction->setEnabled(false);
|
|
||||||
}
|
|
||||||
_showCoordinatesAction = new QAction(tr("Show cursor coordinates"), this);
|
_showCoordinatesAction = new QAction(tr("Show cursor coordinates"), this);
|
||||||
_showCoordinatesAction->setMenuRole(QAction::NoRole);
|
_showCoordinatesAction->setMenuRole(QAction::NoRole);
|
||||||
_showCoordinatesAction->setCheckable(true);
|
_showCoordinatesAction->setCheckable(true);
|
||||||
@ -506,7 +509,7 @@ void GUI::createMenus()
|
|||||||
#endif // Q_OS_MAC
|
#endif // Q_OS_MAC
|
||||||
|
|
||||||
_mapMenu = menuBar()->addMenu(tr("&Map"));
|
_mapMenu = menuBar()->addMenu(tr("&Map"));
|
||||||
_mapMenu->addActions(_mapActions);
|
_mapMenu->addActions(_mapsActionGroup->actions());
|
||||||
_mapsEnd = _mapMenu->addSeparator();
|
_mapsEnd = _mapMenu->addSeparator();
|
||||||
_mapMenu->addAction(_loadMapAction);
|
_mapMenu->addAction(_loadMapAction);
|
||||||
_mapMenu->addAction(_clearMapCacheAction);
|
_mapMenu->addAction(_clearMapCacheAction);
|
||||||
@ -608,6 +611,7 @@ void GUI::createToolBars()
|
|||||||
|
|
||||||
void GUI::createMapView()
|
void GUI::createMapView()
|
||||||
{
|
{
|
||||||
|
_map = new EmptyMap(this);
|
||||||
_mapView = new MapView(_map, _poi, this);
|
_mapView = new MapView(_map, _poi, this);
|
||||||
_mapView->setSizePolicy(QSizePolicy(QSizePolicy::Ignored,
|
_mapView->setSizePolicy(QSizePolicy(QSizePolicy::Ignored,
|
||||||
QSizePolicy::Expanding));
|
QSizePolicy::Expanding));
|
||||||
@ -905,9 +909,14 @@ void GUI::openOptions()
|
|||||||
Track::action(options.option); \
|
Track::action(options.option); \
|
||||||
reload = true; \
|
reload = true; \
|
||||||
}
|
}
|
||||||
#define SET_DATA_OPTION(option, action) \
|
#define SET_ROUTE_OPTION(option, action) \
|
||||||
if (options.option != _options.option) { \
|
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; \
|
reload = true; \
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -953,13 +962,18 @@ void GUI::openOptions()
|
|||||||
SET_TRACK_OPTION(pauseSpeed, setPauseSpeed);
|
SET_TRACK_OPTION(pauseSpeed, setPauseSpeed);
|
||||||
SET_TRACK_OPTION(pauseInterval, setPauseInterval);
|
SET_TRACK_OPTION(pauseInterval, setPauseInterval);
|
||||||
SET_TRACK_OPTION(useReportedSpeed, useReportedSpeed);
|
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)
|
if (options.poiRadius != _options.poiRadius)
|
||||||
_poi->setRadius(options.poiRadius);
|
_poi->setRadius(options.poiRadius);
|
||||||
if (options.poiUseDEM != _options.poiUseDEM)
|
|
||||||
_poi->useDEM(options.poiUseDEM);
|
|
||||||
|
|
||||||
if (options.pixmapCache != _options.pixmapCache)
|
if (options.pixmapCache != _options.pixmapCache)
|
||||||
QPixmapCache::setCacheLimit(options.pixmapCache * 1024);
|
QPixmapCache::setCacheLimit(options.pixmapCache * 1024);
|
||||||
@ -1322,25 +1336,49 @@ void GUI::loadMap()
|
|||||||
|
|
||||||
bool GUI::loadMap(const QString &fileName)
|
bool GUI::loadMap(const QString &fileName)
|
||||||
{
|
{
|
||||||
|
// On OS X fileName may be a directory!
|
||||||
|
|
||||||
if (fileName.isEmpty())
|
if (fileName.isEmpty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
QFileInfo fi(fileName);
|
QString error;
|
||||||
bool res = fi.isDir() ? _ml->loadDir(fileName) : _ml->loadFile(fileName);
|
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) {
|
for (int i = 0; i < maps.size(); i++) {
|
||||||
QAction *a = createMapAction(_ml->maps().last());
|
Map *map = maps.at(i);
|
||||||
|
MapAction *a = createMapAction(map);
|
||||||
_mapMenu->insertAction(_mapsEnd, a);
|
_mapMenu->insertAction(_mapsEnd, a);
|
||||||
|
if (map->isReady()) {
|
||||||
|
a->trigger();
|
||||||
_showMapAction->setEnabled(true);
|
_showMapAction->setEnabled(true);
|
||||||
_clearMapCacheAction->setEnabled(true);
|
_clearMapCacheAction->setEnabled(true);
|
||||||
a->trigger();
|
} else
|
||||||
|
connect(a, SIGNAL(loaded()), this, SLOT(mapLoaded()));
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
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);
|
||||||
} else {
|
} else {
|
||||||
QString error = tr("Error loading map:") + "\n\n"
|
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);
|
QMessageBox::critical(this, APP_NAME, error);
|
||||||
|
action->deleteLater();
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1382,31 +1420,42 @@ void GUI::updateWindowTitle()
|
|||||||
setWindowTitle(APP_NAME);
|
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);
|
_mapView->setMap(_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUI::nextMap()
|
void GUI::nextMap()
|
||||||
{
|
{
|
||||||
if (_ml->maps().count() < 2)
|
QAction *checked = _mapsActionGroup->checkedAction();
|
||||||
|
if (!checked)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int next = (_ml->maps().indexOf(_map) + 1) % _ml->maps().count();
|
QList<QAction*> maps = _mapsActionGroup->actions();
|
||||||
_mapActions.at(next)->setChecked(true);
|
for (int i = 1; i < maps.size(); i++) {
|
||||||
mapChanged(next);
|
int next = (maps.indexOf(checked) + i) % maps.count();
|
||||||
|
if (maps.at(next)->isEnabled()) {
|
||||||
|
maps.at(next)->trigger();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUI::prevMap()
|
void GUI::prevMap()
|
||||||
{
|
{
|
||||||
if (_ml->maps().count() < 2)
|
QAction *checked = _mapsActionGroup->checkedAction();
|
||||||
|
if (!checked)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int prev = (_ml->maps().indexOf(_map) + _ml->maps().count() - 1)
|
QList<QAction*> maps = _mapsActionGroup->actions();
|
||||||
% _ml->maps().count();
|
for (int i = 1; i < maps.size(); i++) {
|
||||||
_mapActions.at(prev)->setChecked(true);
|
int prev = (maps.indexOf(checked) + maps.count() - i) % maps.count();
|
||||||
mapChanged(prev);
|
if (maps.at(prev)->isEnabled()) {
|
||||||
|
maps.at(prev)->trigger();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUI::poiFileChecked(int index)
|
void GUI::poiFileChecked(int index)
|
||||||
@ -1812,10 +1861,14 @@ void GUI::writeSettings()
|
|||||||
settings.setValue(USE_REPORTED_SPEED_SETTING, _options.useReportedSpeed);
|
settings.setValue(USE_REPORTED_SPEED_SETTING, _options.useReportedSpeed);
|
||||||
if (_options.dataUseDEM != DATA_USE_DEM_DEFAULT)
|
if (_options.dataUseDEM != DATA_USE_DEM_DEFAULT)
|
||||||
settings.setValue(DATA_USE_DEM_SETTING, _options.dataUseDEM);
|
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);
|
||||||
if (_options.poiRadius != POI_RADIUS_DEFAULT)
|
if (_options.poiRadius != POI_RADIUS_DEFAULT)
|
||||||
settings.setValue(POI_RADIUS_SETTING, _options.poiRadius);
|
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)
|
if (_options.useOpenGL != USE_OPENGL_DEFAULT)
|
||||||
settings.setValue(USE_OPENGL_SETTING, _options.useOpenGL);
|
settings.setValue(USE_OPENGL_SETTING, _options.useOpenGL);
|
||||||
#ifdef ENABLE_HTTP2
|
#ifdef ENABLE_HTTP2
|
||||||
@ -1899,9 +1952,11 @@ void GUI::readSettings()
|
|||||||
_showMapAction->setChecked(true);
|
_showMapAction->setChecked(true);
|
||||||
else
|
else
|
||||||
_mapView->showMap(false);
|
_mapView->showMap(false);
|
||||||
if (_ml->maps().count()) {
|
QAction *ma = mapAction(settings.value(CURRENT_MAP_SETTING).toString());
|
||||||
int index = mapIndex(settings.value(CURRENT_MAP_SETTING).toString());
|
if (ma) {
|
||||||
_mapActions.at(index)->trigger();
|
ma->trigger();
|
||||||
|
_showMapAction->setEnabled(true);
|
||||||
|
_clearMapCacheAction->setEnabled(true);
|
||||||
}
|
}
|
||||||
if (settings.value(SHOW_COORDINATES_SETTING, SHOW_COORDINATES_DEFAULT)
|
if (settings.value(SHOW_COORDINATES_SETTING, SHOW_COORDINATES_DEFAULT)
|
||||||
.toBool()) {
|
.toBool()) {
|
||||||
@ -2078,14 +2133,18 @@ void GUI::readSettings()
|
|||||||
USE_REPORTED_SPEED_DEFAULT).toBool();
|
USE_REPORTED_SPEED_DEFAULT).toBool();
|
||||||
_options.dataUseDEM = settings.value(DATA_USE_DEM_SETTING,
|
_options.dataUseDEM = settings.value(DATA_USE_DEM_SETTING,
|
||||||
DATA_USE_DEM_DEFAULT).toBool();
|
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();
|
||||||
_options.automaticPause = settings.value(AUTOMATIC_PAUSE_SETTING,
|
_options.automaticPause = settings.value(AUTOMATIC_PAUSE_SETTING,
|
||||||
AUTOMATIC_PAUSE_DEFAULT).toBool();
|
AUTOMATIC_PAUSE_DEFAULT).toBool();
|
||||||
_options.pauseInterval = settings.value(PAUSE_INTERVAL_SETTING,
|
_options.pauseInterval = settings.value(PAUSE_INTERVAL_SETTING,
|
||||||
PAUSE_INTERVAL_DEFAULT).toInt();
|
PAUSE_INTERVAL_DEFAULT).toInt();
|
||||||
_options.poiRadius = settings.value(POI_RADIUS_SETTING, POI_RADIUS_DEFAULT)
|
_options.poiRadius = settings.value(POI_RADIUS_SETTING, POI_RADIUS_DEFAULT)
|
||||||
.toInt();
|
.toInt();
|
||||||
_options.poiUseDEM = settings.value(POI_USE_DEM_SETTING,
|
|
||||||
POI_USE_DEM_DEFAULT).toBool();
|
|
||||||
_options.useOpenGL = settings.value(USE_OPENGL_SETTING, USE_OPENGL_DEFAULT)
|
_options.useOpenGL = settings.value(USE_OPENGL_SETTING, USE_OPENGL_DEFAULT)
|
||||||
.toBool();
|
.toBool();
|
||||||
#ifdef ENABLE_HTTP2
|
#ifdef ENABLE_HTTP2
|
||||||
@ -2165,21 +2224,38 @@ void GUI::readSettings()
|
|||||||
Track::setPauseSpeed(_options.pauseSpeed);
|
Track::setPauseSpeed(_options.pauseSpeed);
|
||||||
Track::setPauseInterval(_options.pauseInterval);
|
Track::setPauseInterval(_options.pauseInterval);
|
||||||
Track::useReportedSpeed(_options.useReportedSpeed);
|
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->setRadius(_options.poiRadius);
|
||||||
_poi->useDEM(_options.poiUseDEM);
|
|
||||||
|
|
||||||
QPixmapCache::setCacheLimit(_options.pixmapCache * 1024);
|
QPixmapCache::setCacheLimit(_options.pixmapCache * 1024);
|
||||||
|
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
int GUI::mapIndex(const QString &name)
|
QAction *GUI::mapAction(const QString &name)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < _ml->maps().count(); i++)
|
QList<QAction *> maps = _mapsActionGroup->actions();
|
||||||
if (_ml->maps().at(i)->name() == name)
|
|
||||||
return i;
|
// 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -26,9 +26,9 @@ class FileBrowser;
|
|||||||
class GraphTab;
|
class GraphTab;
|
||||||
class MapView;
|
class MapView;
|
||||||
class Map;
|
class Map;
|
||||||
class MapList;
|
|
||||||
class POI;
|
class POI;
|
||||||
class QScreen;
|
class QScreen;
|
||||||
|
class MapAction;
|
||||||
|
|
||||||
class GUI : public QMainWindow
|
class GUI : public QMainWindow
|
||||||
{
|
{
|
||||||
@ -64,7 +64,7 @@ private slots:
|
|||||||
void prevMap();
|
void prevMap();
|
||||||
void openOptions();
|
void openOptions();
|
||||||
|
|
||||||
void mapChanged(int);
|
void mapChanged();
|
||||||
void graphChanged(int);
|
void graphChanged(int);
|
||||||
void poiFileChecked(int);
|
void poiFileChecked(int);
|
||||||
|
|
||||||
@ -88,16 +88,18 @@ private slots:
|
|||||||
void screenChanged(QScreen *screen);
|
void screenChanged(QScreen *screen);
|
||||||
void logicalDotsPerInchChanged(qreal dpi);
|
void logicalDotsPerInchChanged(qreal dpi);
|
||||||
|
|
||||||
|
void mapLoaded();
|
||||||
|
void mapInitialized();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef QPair<QDate, QDate> DateRange;
|
typedef QPair<QDate, QDate> DateRange;
|
||||||
|
|
||||||
void loadMaps();
|
|
||||||
void loadPOIs();
|
void loadPOIs();
|
||||||
void closeFiles();
|
void closeFiles();
|
||||||
void plot(QPrinter *printer);
|
void plot(QPrinter *printer);
|
||||||
|
|
||||||
QAction *createPOIFileAction(const QString &fileName);
|
QAction *createPOIFileAction(const QString &fileName);
|
||||||
QAction *createMapAction(const Map *map);
|
MapAction *createMapAction(Map *map);
|
||||||
void createPOIFilesActions();
|
void createPOIFilesActions();
|
||||||
void createMapActions();
|
void createMapActions();
|
||||||
void createActions();
|
void createActions();
|
||||||
@ -127,7 +129,7 @@ private:
|
|||||||
qreal distance() const;
|
qreal distance() const;
|
||||||
qreal time() const;
|
qreal time() const;
|
||||||
qreal movingTime() const;
|
qreal movingTime() const;
|
||||||
int mapIndex(const QString &name);
|
QAction *mapAction(const QString &name);
|
||||||
void readSettings();
|
void readSettings();
|
||||||
void writeSettings();
|
void writeSettings();
|
||||||
|
|
||||||
@ -196,11 +198,9 @@ private:
|
|||||||
QAction *_showCoordinatesAction;
|
QAction *_showCoordinatesAction;
|
||||||
QAction *_openOptionsAction;
|
QAction *_openOptionsAction;
|
||||||
QAction *_mapsEnd;
|
QAction *_mapsEnd;
|
||||||
QList<QAction*> _mapActions;
|
|
||||||
QList<QAction*> _poiFilesActions;
|
|
||||||
|
|
||||||
|
QList<QAction*> _poiFilesActions;
|
||||||
QSignalMapper *_poiFilesSignalMapper;
|
QSignalMapper *_poiFilesSignalMapper;
|
||||||
QSignalMapper *_mapsSignalMapper;
|
|
||||||
|
|
||||||
QLabel *_fileNameLabel;
|
QLabel *_fileNameLabel;
|
||||||
QLabel *_distanceLabel;
|
QLabel *_distanceLabel;
|
||||||
@ -212,7 +212,6 @@ private:
|
|||||||
QList<GraphTab*> _tabs;
|
QList<GraphTab*> _tabs;
|
||||||
|
|
||||||
POI *_poi;
|
POI *_poi;
|
||||||
MapList *_ml;
|
|
||||||
Map *_map;
|
Map *_map;
|
||||||
|
|
||||||
FileBrowser *_browser;
|
FileBrowser *_browser;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
HeartRateGraphItem::HeartRateGraphItem(const Graph &graph, GraphType type,
|
HeartRateGraphItem::HeartRateGraphItem(const Graph &graph, GraphType type,
|
||||||
int width, const QColor &color, QGraphicsItem *parent)
|
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->isValid());
|
||||||
|
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 <QGraphicsScene>
|
||||||
#include <QWheelEvent>
|
#include <QWheelEvent>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QPixmapCache>
|
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
#include "data/poi.h"
|
#include "data/poi.h"
|
||||||
#include "data/data.h"
|
#include "data/data.h"
|
||||||
@ -55,7 +54,7 @@ MapView::MapView(Map *map, POI *poi, QWidget *parent)
|
|||||||
_map = map;
|
_map = map;
|
||||||
_map->load();
|
_map->load();
|
||||||
_map->setProjection(_projection);
|
_map->setProjection(_projection);
|
||||||
connect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
|
connect(_map, SIGNAL(tilesLoaded()), this, SLOT(reloadMap()));
|
||||||
|
|
||||||
_poi = poi;
|
_poi = poi;
|
||||||
connect(_poi, SIGNAL(pointsChanged()), this, SLOT(updatePOI()));
|
connect(_poi, SIGNAL(pointsChanged()), this, SLOT(updatePOI()));
|
||||||
@ -317,7 +316,7 @@ void MapView::setMap(Map *map)
|
|||||||
RectC cr(_map->xy2ll(vr.topLeft()), _map->xy2ll(vr.bottomRight()));
|
RectC cr(_map->xy2ll(vr.topLeft()), _map->xy2ll(vr.bottomRight()));
|
||||||
|
|
||||||
_map->unload();
|
_map->unload();
|
||||||
disconnect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
|
disconnect(_map, SIGNAL(tilesLoaded()), this, SLOT(reloadMap()));
|
||||||
|
|
||||||
_map = map;
|
_map = map;
|
||||||
_map->load();
|
_map->load();
|
||||||
@ -325,7 +324,7 @@ void MapView::setMap(Map *map)
|
|||||||
#ifdef ENABLE_HIDPI
|
#ifdef ENABLE_HIDPI
|
||||||
_map->setDevicePixelRatio(_deviceRatio, _mapRatio);
|
_map->setDevicePixelRatio(_deviceRatio, _mapRatio);
|
||||||
#endif // ENABLE_HIDPI
|
#endif // ENABLE_HIDPI
|
||||||
connect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
|
connect(_map, SIGNAL(tilesLoaded()), this, SLOT(reloadMap()));
|
||||||
|
|
||||||
digitalZoom(0);
|
digitalZoom(0);
|
||||||
|
|
||||||
@ -351,7 +350,6 @@ void MapView::setMap(Map *map)
|
|||||||
centerOn(nc);
|
centerOn(nc);
|
||||||
|
|
||||||
reloadMap();
|
reloadMap();
|
||||||
QPixmapCache::clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapView::setPOI(POI *poi)
|
void MapView::setPOI(POI *poi)
|
||||||
@ -453,10 +451,7 @@ void MapView::setCoordinatesFormat(CoordinatesFormat format)
|
|||||||
void MapView::clearMapCache()
|
void MapView::clearMapCache()
|
||||||
{
|
{
|
||||||
_map->clearCache();
|
_map->clearCache();
|
||||||
|
reloadMap();
|
||||||
fitMapZoom();
|
|
||||||
rescale();
|
|
||||||
centerOn(contentCenter());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapView::digitalZoom(int zoom)
|
void MapView::digitalZoom(int zoom)
|
||||||
@ -982,7 +977,6 @@ void MapView::setDevicePixelRatio(qreal deviceRatio, qreal mapRatio)
|
|||||||
|
|
||||||
_deviceRatio = deviceRatio;
|
_deviceRatio = deviceRatio;
|
||||||
_mapRatio = mapRatio;
|
_mapRatio = mapRatio;
|
||||||
QPixmapCache::clear();
|
|
||||||
|
|
||||||
QRectF vr(mapToScene(viewport()->rect()).boundingRect()
|
QRectF vr(mapToScene(viewport()->rect()).boundingRect()
|
||||||
.intersected(_map->bounds()));
|
.intersected(_map->bounds()));
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <QRadioButton>
|
#include <QRadioButton>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QSysInfo>
|
#include <QSysInfo>
|
||||||
|
#include <QButtonGroup>
|
||||||
#include "map/pcs.h"
|
#include "map/pcs.h"
|
||||||
#include "icons.h"
|
#include "icons.h"
|
||||||
#include "colorbox.h"
|
#include "colorbox.h"
|
||||||
@ -406,6 +407,8 @@ QWidget *OptionsDialog::createDataPage()
|
|||||||
_reportedSpeed->setChecked(true);
|
_reportedSpeed->setChecked(true);
|
||||||
else
|
else
|
||||||
_computedSpeed->setChecked(true);
|
_computedSpeed->setChecked(true);
|
||||||
|
_showSecondarySpeed = new QCheckBox(tr("Show secondary speed"));
|
||||||
|
_showSecondarySpeed->setChecked(_options->showSecondarySpeed);
|
||||||
|
|
||||||
_dataGPSElevation = new QRadioButton(tr("GPS data"));
|
_dataGPSElevation = new QRadioButton(tr("GPS data"));
|
||||||
_dataDEMElevation = new QRadioButton(tr("DEM data"));
|
_dataDEMElevation = new QRadioButton(tr("DEM data"));
|
||||||
@ -413,19 +416,28 @@ QWidget *OptionsDialog::createDataPage()
|
|||||||
_dataDEMElevation->setChecked(true);
|
_dataDEMElevation->setChecked(true);
|
||||||
else
|
else
|
||||||
_dataGPSElevation->setChecked(true);
|
_dataGPSElevation->setChecked(true);
|
||||||
|
_showSecondaryElevation = new QCheckBox(tr("Show secondary elevation"));
|
||||||
|
_showSecondaryElevation->setChecked(_options->showSecondaryElevation);
|
||||||
|
|
||||||
QWidget *sourceTab = new QWidget();
|
QWidget *sourceTab = new QWidget();
|
||||||
QVBoxLayout *sourceTabLayout = new QVBoxLayout();
|
QVBoxLayout *sourceTabLayout = new QVBoxLayout();
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
|
QButtonGroup *speedGroup = new QButtonGroup(this);
|
||||||
|
speedGroup->addButton(_computedSpeed);
|
||||||
|
speedGroup->addButton(_reportedSpeed);
|
||||||
QVBoxLayout *speedOptions = new QVBoxLayout();
|
QVBoxLayout *speedOptions = new QVBoxLayout();
|
||||||
speedOptions->addWidget(_computedSpeed);
|
speedOptions->addWidget(_computedSpeed);
|
||||||
speedOptions->addWidget(_reportedSpeed);
|
speedOptions->addWidget(_reportedSpeed);
|
||||||
|
speedOptions->addWidget(_showSecondarySpeed);
|
||||||
|
|
||||||
|
QButtonGroup *elevationGroup = new QButtonGroup(this);
|
||||||
|
elevationGroup->addButton(_dataGPSElevation);
|
||||||
|
elevationGroup->addButton(_dataDEMElevation);
|
||||||
QVBoxLayout *elevationOptions = new QVBoxLayout();
|
QVBoxLayout *elevationOptions = new QVBoxLayout();
|
||||||
elevationOptions->addWidget(_dataGPSElevation);
|
elevationOptions->addWidget(_dataGPSElevation);
|
||||||
elevationOptions->addWidget(_dataDEMElevation);
|
elevationOptions->addWidget(_dataDEMElevation);
|
||||||
|
elevationOptions->addWidget(_showSecondaryElevation);
|
||||||
|
|
||||||
QFormLayout *formLayout = new QFormLayout();
|
QFormLayout *formLayout = new QFormLayout();
|
||||||
formLayout->addRow(tr("Speed:"), speedOptions);
|
formLayout->addRow(tr("Speed:"), speedOptions);
|
||||||
@ -438,12 +450,14 @@ QWidget *OptionsDialog::createDataPage()
|
|||||||
|
|
||||||
speedLayout->addWidget(_computedSpeed);
|
speedLayout->addWidget(_computedSpeed);
|
||||||
speedLayout->addWidget(_reportedSpeed);
|
speedLayout->addWidget(_reportedSpeed);
|
||||||
|
speedLayout->addWidget(_showSecondarySpeed);
|
||||||
|
|
||||||
QGroupBox *speedBox = new QGroupBox(tr("Speed"));
|
QGroupBox *speedBox = new QGroupBox(tr("Speed"));
|
||||||
speedBox->setLayout(speedLayout);
|
speedBox->setLayout(speedLayout);
|
||||||
|
|
||||||
elevationLayout->addWidget(_dataGPSElevation);
|
elevationLayout->addWidget(_dataGPSElevation);
|
||||||
elevationLayout->addWidget(_dataDEMElevation);
|
elevationLayout->addWidget(_dataDEMElevation);
|
||||||
|
elevationLayout->addWidget(_showSecondaryElevation);
|
||||||
|
|
||||||
QGroupBox *elevationBox = new QGroupBox(tr("Elevation"));
|
QGroupBox *elevationBox = new QGroupBox(tr("Elevation"));
|
||||||
elevationBox->setLayout(elevationLayout);
|
elevationBox->setLayout(elevationLayout);
|
||||||
@ -465,13 +479,6 @@ QWidget *OptionsDialog::createDataPage()
|
|||||||
|
|
||||||
QWidget *OptionsDialog::createPOIPage()
|
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 = new QDoubleSpinBox();
|
||||||
_poiRadius->setSingleStep(1);
|
_poiRadius->setSingleStep(1);
|
||||||
_poiRadius->setDecimals(1);
|
_poiRadius->setDecimals(1);
|
||||||
@ -486,13 +493,8 @@ QWidget *OptionsDialog::createPOIPage()
|
|||||||
_poiRadius->setSuffix(UNIT_SPACE + tr("km"));
|
_poiRadius->setSuffix(UNIT_SPACE + tr("km"));
|
||||||
}
|
}
|
||||||
|
|
||||||
QVBoxLayout *elevationLayout = new QVBoxLayout();
|
|
||||||
elevationLayout->addWidget(_poiGPSElevation);
|
|
||||||
elevationLayout->addWidget(_poiDEMElevation);
|
|
||||||
|
|
||||||
QFormLayout *poiLayout = new QFormLayout();
|
QFormLayout *poiLayout = new QFormLayout();
|
||||||
poiLayout->addRow(tr("Radius:"), _poiRadius);
|
poiLayout->addRow(tr("Radius:"), _poiRadius);
|
||||||
poiLayout->addRow(tr("Elevation:"), elevationLayout);
|
|
||||||
|
|
||||||
QWidget *poiTab = new QWidget();
|
QWidget *poiTab = new QWidget();
|
||||||
poiTab->setLayout(poiLayout);
|
poiTab->setLayout(poiLayout);
|
||||||
@ -718,13 +720,14 @@ void OptionsDialog::accept()
|
|||||||
_options->pauseInterval = _pauseInterval->value();
|
_options->pauseInterval = _pauseInterval->value();
|
||||||
_options->useReportedSpeed = _reportedSpeed->isChecked();
|
_options->useReportedSpeed = _reportedSpeed->isChecked();
|
||||||
_options->dataUseDEM = _dataDEMElevation->isChecked();
|
_options->dataUseDEM = _dataDEMElevation->isChecked();
|
||||||
|
_options->showSecondaryElevation = _showSecondaryElevation->isChecked();
|
||||||
|
_options->showSecondarySpeed = _showSecondarySpeed->isChecked();
|
||||||
|
|
||||||
qreal poiRadius = (_options->units == Imperial)
|
qreal poiRadius = (_options->units == Imperial)
|
||||||
? _poiRadius->value() * MIINM : (_options->units == Nautical)
|
? _poiRadius->value() * MIINM : (_options->units == Nautical)
|
||||||
? _poiRadius->value() * NMIINM : _poiRadius->value() * KMINM;
|
? _poiRadius->value() * NMIINM : _poiRadius->value() * KMINM;
|
||||||
if (qAbs(poiRadius - _options->poiRadius) > 0.01)
|
if (qAbs(poiRadius - _options->poiRadius) > 0.01)
|
||||||
_options->poiRadius = poiRadius;
|
_options->poiRadius = poiRadius;
|
||||||
_options->poiUseDEM = _poiDEMElevation->isChecked();
|
|
||||||
|
|
||||||
_options->useOpenGL = _useOpenGL->isChecked();
|
_options->useOpenGL = _useOpenGL->isChecked();
|
||||||
#ifdef ENABLE_HTTP2
|
#ifdef ENABLE_HTTP2
|
||||||
|
@ -54,9 +54,10 @@ struct Options {
|
|||||||
int pauseInterval;
|
int pauseInterval;
|
||||||
bool useReportedSpeed;
|
bool useReportedSpeed;
|
||||||
bool dataUseDEM;
|
bool dataUseDEM;
|
||||||
|
bool showSecondaryElevation;
|
||||||
|
bool showSecondarySpeed;
|
||||||
// POI
|
// POI
|
||||||
int poiRadius;
|
int poiRadius;
|
||||||
bool poiUseDEM;
|
|
||||||
// System
|
// System
|
||||||
bool useOpenGL;
|
bool useOpenGL;
|
||||||
#ifdef ENABLE_HTTP2
|
#ifdef ENABLE_HTTP2
|
||||||
@ -142,10 +143,10 @@ private:
|
|||||||
QRadioButton *_reportedSpeed;
|
QRadioButton *_reportedSpeed;
|
||||||
QRadioButton *_dataGPSElevation;
|
QRadioButton *_dataGPSElevation;
|
||||||
QRadioButton *_dataDEMElevation;
|
QRadioButton *_dataDEMElevation;
|
||||||
|
QCheckBox *_showSecondaryElevation;
|
||||||
|
QCheckBox *_showSecondarySpeed;
|
||||||
// POI
|
// POI
|
||||||
QDoubleSpinBox *_poiRadius;
|
QDoubleSpinBox *_poiRadius;
|
||||||
QRadioButton *_poiGPSElevation;
|
|
||||||
QRadioButton *_poiDEMElevation;
|
|
||||||
// System
|
// System
|
||||||
QSpinBox *_pixmapCache;
|
QSpinBox *_pixmapCache;
|
||||||
QSpinBox *_connectionTimeout;
|
QSpinBox *_connectionTimeout;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
PowerGraphItem::PowerGraphItem(const Graph &graph, GraphType type, int width,
|
PowerGraphItem::PowerGraphItem(const Graph &graph, GraphType type, int width,
|
||||||
const QColor &color, QGraphicsItem *parent)
|
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);
|
tt.insert(tr("Name"), _name);
|
||||||
if (!_desc.isEmpty())
|
if (!_desc.isEmpty())
|
||||||
tt.insert(tr("Description"), _desc);
|
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(),
|
tt.insert(tr("Distance"), Format::distance(path().last().last().distance(),
|
||||||
_units));
|
_units));
|
||||||
if (!_links.isEmpty()) {
|
if (!_links.isEmpty()) {
|
||||||
@ -43,6 +45,7 @@ RouteItem::RouteItem(const Route &route, Map *map, QGraphicsItem *parent)
|
|||||||
|
|
||||||
_name = route.name();
|
_name = route.name();
|
||||||
_desc = route.description();
|
_desc = route.description();
|
||||||
|
_comment = route.comment();
|
||||||
_links = route.links();
|
_links = route.links();
|
||||||
_coordinatesFormat = DecimalDegrees;
|
_coordinatesFormat = DecimalDegrees;
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
QString _name;
|
QString _name;
|
||||||
QString _desc;
|
QString _desc;
|
||||||
|
QString _comment;
|
||||||
QVector<Link> _links;
|
QVector<Link> _links;
|
||||||
CoordinatesFormat _coordinatesFormat;
|
CoordinatesFormat _coordinatesFormat;
|
||||||
|
|
||||||
|
@ -145,10 +145,12 @@
|
|||||||
#define USE_REPORTED_SPEED_DEFAULT false
|
#define USE_REPORTED_SPEED_DEFAULT false
|
||||||
#define DATA_USE_DEM_SETTING "dataUseDEM"
|
#define DATA_USE_DEM_SETTING "dataUseDEM"
|
||||||
#define DATA_USE_DEM_DEFAULT false
|
#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 POI_RADIUS_SETTING "poiRadius"
|
#define POI_RADIUS_SETTING "poiRadius"
|
||||||
#define POI_RADIUS_DEFAULT (int)(IMPERIAL_UNITS() ? MIINM : KMINM)
|
#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_SETTING "useOpenGL"
|
||||||
#define USE_OPENGL_DEFAULT false
|
#define USE_OPENGL_DEFAULT false
|
||||||
#define ENABLE_HTTP2_SETTING "enableHTTP2"
|
#define ENABLE_HTTP2_SETTING "enableHTTP2"
|
||||||
|
@ -40,20 +40,14 @@ void SpeedGraph::setInfo()
|
|||||||
clearInfo();
|
clearInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<GraphItem*> SpeedGraph::loadData(const Data &data)
|
GraphItem *SpeedGraph::loadGraph(const Graph &graph, const Track &track,
|
||||||
|
const QColor &color, bool primary)
|
||||||
{
|
{
|
||||||
QList<GraphItem*> graphs;
|
if (!graph.isValid())
|
||||||
|
return 0;
|
||||||
|
|
||||||
for (int i = 0; i < data.tracks().count(); i++) {
|
|
||||||
const Track &track = data.tracks().at(i);
|
|
||||||
const Graph &graph = track.speed();
|
|
||||||
|
|
||||||
if (!graph.isValid()) {
|
|
||||||
_palette.nextColor();
|
|
||||||
graphs.append(0);
|
|
||||||
} else {
|
|
||||||
SpeedGraphItem *gi = new SpeedGraphItem(graph, _graphType, _width,
|
SpeedGraphItem *gi = new SpeedGraphItem(graph, _graphType, _width,
|
||||||
_palette.nextColor(), track.movingTime());
|
color, primary ? Qt::SolidLine : Qt::DashLine, track.movingTime());
|
||||||
gi->setTimeType(_timeType);
|
gi->setTimeType(_timeType);
|
||||||
gi->setUnits(_units);
|
gi->setUnits(_units);
|
||||||
|
|
||||||
@ -61,10 +55,31 @@ QList<GraphItem*> SpeedGraph::loadData(const Data &data)
|
|||||||
if (_showTracks)
|
if (_showTracks)
|
||||||
addGraph(gi);
|
addGraph(gi);
|
||||||
|
|
||||||
|
if (primary) {
|
||||||
_avg.append(QPointF(track.distance(), gi->avg()));
|
_avg.append(QPointF(track.distance(), gi->avg()));
|
||||||
_mavg.append(QPointF(track.distance(), gi->mavg()));
|
_mavg.append(QPointF(track.distance(), gi->mavg()));
|
||||||
graphs.append(gi);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 GraphPair &gp = track.speed();
|
||||||
|
|
||||||
|
primary = loadGraph(gp.primary(), track, color, true);
|
||||||
|
secondary = primary
|
||||||
|
? loadGraph(gp.secondary(), track, color, false) : 0;
|
||||||
|
if (primary && secondary)
|
||||||
|
primary->setSecondaryGraph(secondary);
|
||||||
|
|
||||||
|
graphs.append(primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < data.routes().count(); i++) {
|
for (int i = 0; i < data.routes().count(); i++) {
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "graphtab.h"
|
#include "graphtab.h"
|
||||||
|
|
||||||
class SpeedGraphItem;
|
class SpeedGraphItem;
|
||||||
|
class Track;
|
||||||
|
|
||||||
class SpeedGraph : public GraphTab
|
class SpeedGraph : public GraphTab
|
||||||
{
|
{
|
||||||
@ -22,6 +23,8 @@ public:
|
|||||||
void showTracks(bool show);
|
void showTracks(bool show);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
GraphItem *loadGraph(const Graph &graph, const Track &track,
|
||||||
|
const QColor &color, bool primary);
|
||||||
qreal avg() const;
|
qreal avg() const;
|
||||||
qreal max() const {return bounds().bottom();}
|
qreal max() const {return bounds().bottom();}
|
||||||
void setYUnits();
|
void setYUnits();
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
|
|
||||||
SpeedGraphItem::SpeedGraphItem(const Graph &graph, GraphType type, int width,
|
SpeedGraphItem::SpeedGraphItem(const Graph &graph, GraphType type, int width,
|
||||||
const QColor &color, qreal movingTime, QGraphicsItem *parent)
|
const QColor &color, Qt::PenStyle style, qreal movingTime,
|
||||||
: GraphItem(graph, type, width, color, parent)
|
QGraphicsItem *parent) : GraphItem(graph, type, width, color, style, parent)
|
||||||
{
|
{
|
||||||
_timeType = Total;
|
_timeType = Total;
|
||||||
|
|
||||||
|
@ -10,7 +10,8 @@ class SpeedGraphItem : public GraphItem
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
SpeedGraphItem(const Graph &graph, GraphType type, int width,
|
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 avg() const {return _avg;}
|
||||||
qreal mavg() const {return _mavg;}
|
qreal mavg() const {return _mavg;}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
TemperatureGraphItem::TemperatureGraphItem(const Graph &graph, GraphType type,
|
TemperatureGraphItem::TemperatureGraphItem(const Graph &graph, GraphType type,
|
||||||
int width, const QColor &color, QGraphicsItem *parent)
|
int width, const QColor &color, QGraphicsItem *parent)
|
||||||
: GraphItem(graph, type, width, color, parent)
|
: GraphItem(graph, type, width, color, Qt::SolidLine, parent)
|
||||||
{
|
{
|
||||||
_min = GraphItem::min();
|
_min = GraphItem::min();
|
||||||
_max = GraphItem::max();
|
_max = GraphItem::max();
|
||||||
|
@ -13,6 +13,8 @@ QString TrackItem::info() const
|
|||||||
tt.insert(tr("Name"), _name);
|
tt.insert(tr("Name"), _name);
|
||||||
if (!_desc.isEmpty())
|
if (!_desc.isEmpty())
|
||||||
tt.insert(tr("Description"), _desc);
|
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(),
|
tt.insert(tr("Distance"), Format::distance(path().last().last().distance(),
|
||||||
_units));
|
_units));
|
||||||
if (_time > 0)
|
if (_time > 0)
|
||||||
@ -41,6 +43,7 @@ TrackItem::TrackItem(const Track &track, Map *map, QGraphicsItem *parent)
|
|||||||
{
|
{
|
||||||
_name = track.name();
|
_name = track.name();
|
||||||
_desc = track.description();
|
_desc = track.description();
|
||||||
|
_comment = track.comment();
|
||||||
_links = track.links();
|
_links = track.links();
|
||||||
_date = track.date();
|
_date = track.date();
|
||||||
_time = track.time();
|
_time = track.time();
|
||||||
|
@ -22,6 +22,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
QString _name;
|
QString _name;
|
||||||
QString _desc;
|
QString _desc;
|
||||||
|
QString _comment;
|
||||||
QVector<Link> _links;
|
QVector<Link> _links;
|
||||||
QDateTime _date;
|
QDateTime _date;
|
||||||
qreal _time;
|
qreal _time;
|
||||||
|
@ -21,15 +21,23 @@ QString WaypointItem::info() const
|
|||||||
tt.insert(qApp->translate("WaypointItem", "Name"), _waypoint.name());
|
tt.insert(qApp->translate("WaypointItem", "Name"), _waypoint.name());
|
||||||
tt.insert(qApp->translate("WaypointItem", "Coordinates"),
|
tt.insert(qApp->translate("WaypointItem", "Coordinates"),
|
||||||
Format::coordinates(_waypoint.coordinates(), _format));
|
Format::coordinates(_waypoint.coordinates(), _format));
|
||||||
if (_waypoint.hasElevation())
|
if (!std::isnan(_waypoint.elevations().first)) {
|
||||||
tt.insert(qApp->translate("WaypointItem", "Elevation"),
|
QString val = Format::elevation(_waypoint.elevations().first, _units);
|
||||||
Format::elevation(_waypoint.elevation(), _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())
|
if (_waypoint.timestamp().isValid())
|
||||||
tt.insert(qApp->translate("WaypointItem", "Date"),
|
tt.insert(qApp->translate("WaypointItem", "Date"),
|
||||||
_waypoint.timestamp().toString(Qt::SystemLocaleShortDate));
|
_waypoint.timestamp().toString(Qt::SystemLocaleShortDate));
|
||||||
if (!_waypoint.description().isEmpty())
|
if (!_waypoint.description().isEmpty())
|
||||||
tt.insert(qApp->translate("WaypointItem", "Description"),
|
tt.insert(qApp->translate("WaypointItem", "Description"),
|
||||||
_waypoint.description());
|
_waypoint.description());
|
||||||
|
if (!_waypoint.comment().isEmpty()
|
||||||
|
&& _waypoint.comment() != _waypoint.description())
|
||||||
|
tt.insert(qApp->translate("WaypointItem", "Comment"),
|
||||||
|
_waypoint.comment());
|
||||||
if (_waypoint.address().isValid()) {
|
if (_waypoint.address().isValid()) {
|
||||||
QString addr("<address>");
|
QString addr("<address>");
|
||||||
addr += _waypoint.address().street();
|
addr += _waypoint.address().street();
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
#include "cupparser.h"
|
#include "cupparser.h"
|
||||||
#include "gpiparser.h"
|
#include "gpiparser.h"
|
||||||
#include "smlparser.h"
|
#include "smlparser.h"
|
||||||
#include "dem.h"
|
|
||||||
#include "data.h"
|
#include "data.h"
|
||||||
|
|
||||||
|
|
||||||
@ -73,49 +72,17 @@ static QMap<QString, Parser*> parsers()
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QMap<QString, Parser*> Data::_parsers = parsers();
|
QMap<QString, Parser*> Data::_parsers = parsers();
|
||||||
bool Data::_useDEM = false;
|
|
||||||
|
|
||||||
void Data::processData(QList<TrackData> &trackData, QList<RouteData> &routeData)
|
void Data::processData(QList<TrackData> &trackData, QList<RouteData> &routeData)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < trackData.count(); i++) {
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_tracks.append(Track(trackData.at(i)));
|
_tracks.append(Track(trackData.at(i)));
|
||||||
}
|
for (int i = 0; i < routeData.count(); 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_routes.append(Route(routeData.at(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);
|
QFile file(fileName);
|
||||||
QFileInfo fi(fileName);
|
QFileInfo fi(fileName);
|
||||||
@ -134,7 +101,6 @@ Data::Data(const QString &fileName, bool poi)
|
|||||||
if ((it = _parsers.find(fi.suffix().toLower())) != _parsers.end()) {
|
if ((it = _parsers.find(fi.suffix().toLower())) != _parsers.end()) {
|
||||||
if (it.value()->parse(&file, trackData, routeData, _polygons,
|
if (it.value()->parse(&file, trackData, routeData, _polygons,
|
||||||
_waypoints)) {
|
_waypoints)) {
|
||||||
if (!poi)
|
|
||||||
processData(trackData, routeData);
|
processData(trackData, routeData);
|
||||||
_valid = true;
|
_valid = true;
|
||||||
return;
|
return;
|
||||||
@ -146,7 +112,6 @@ Data::Data(const QString &fileName, bool poi)
|
|||||||
for (it = _parsers.begin(); it != _parsers.end(); it++) {
|
for (it = _parsers.begin(); it != _parsers.end(); it++) {
|
||||||
if (it.value()->parse(&file, trackData, routeData, _polygons,
|
if (it.value()->parse(&file, trackData, routeData, _polygons,
|
||||||
_waypoints)) {
|
_waypoints)) {
|
||||||
if (!poi)
|
|
||||||
processData(trackData, routeData);
|
processData(trackData, routeData);
|
||||||
_valid = true;
|
_valid = true;
|
||||||
return;
|
return;
|
||||||
@ -198,8 +163,3 @@ QStringList Data::filter()
|
|||||||
|
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Data::useDEM(bool use)
|
|
||||||
{
|
|
||||||
_useDEM = use;
|
|
||||||
}
|
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
class Data
|
class Data
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Data(const QString &fileName, bool poi = false);
|
Data(const QString &fileName);
|
||||||
|
|
||||||
bool isValid() const {return _valid;}
|
bool isValid() const {return _valid;}
|
||||||
const QString &errorString() const {return _errorString;}
|
const QString &errorString() const {return _errorString;}
|
||||||
@ -28,8 +28,6 @@ public:
|
|||||||
static QString formats();
|
static QString formats();
|
||||||
static QStringList filter();
|
static QStringList filter();
|
||||||
|
|
||||||
static void useDEM(bool use);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void processData(QList<TrackData> &trackData, QList<RouteData> &routeData);
|
void processData(QList<TrackData> &trackData, QList<RouteData> &routeData);
|
||||||
|
|
||||||
@ -43,7 +41,6 @@ private:
|
|||||||
QVector<Waypoint> _waypoints;
|
QVector<Waypoint> _waypoints;
|
||||||
|
|
||||||
static QMap<QString, Parser*> _parsers;
|
static QMap<QString, Parser*> _parsers;
|
||||||
static bool _useDEM;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DATA_H
|
#endif // DATA_H
|
||||||
|
@ -282,14 +282,14 @@ static quint32 readNotes(QDataStream &stream, QTextCodec *codec,
|
|||||||
if (s1 & 0x1) {
|
if (s1 & 0x1) {
|
||||||
QList<TranslatedString> obj;
|
QList<TranslatedString> obj;
|
||||||
ds += readTranslatedObjects(stream, codec, obj);
|
ds += readTranslatedObjects(stream, codec, obj);
|
||||||
if (!obj.isEmpty() && waypoint.description().isNull())
|
if (!obj.isEmpty())
|
||||||
waypoint.setDescription(obj.first().str());
|
waypoint.setComment(obj.first().str());
|
||||||
}
|
}
|
||||||
if (s1 & 0x2) {
|
if (s1 & 0x2) {
|
||||||
QString str;
|
QString str;
|
||||||
ds += readString(stream, codec, str);
|
ds += readString(stream, codec, str);
|
||||||
if (!str.isEmpty() && waypoint.description().isNull())
|
if (!str.isEmpty())
|
||||||
waypoint.setDescription(str);
|
waypoint.setComment(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ds != rh.size)
|
if (ds != rh.size)
|
||||||
|
@ -192,6 +192,8 @@ void GPXParser::waypointData(Waypoint &waypoint, SegmentData *autoRoute)
|
|||||||
waypoint.setName(_reader.readElementText());
|
waypoint.setName(_reader.readElementText());
|
||||||
else if (_reader.name() == QLatin1String("desc"))
|
else if (_reader.name() == QLatin1String("desc"))
|
||||||
waypoint.setDescription(_reader.readElementText());
|
waypoint.setDescription(_reader.readElementText());
|
||||||
|
else if (_reader.name() == QLatin1String("cmt"))
|
||||||
|
waypoint.setComment(_reader.readElementText());
|
||||||
else if (_reader.name() == QLatin1String("ele"))
|
else if (_reader.name() == QLatin1String("ele"))
|
||||||
waypoint.setElevation(number());
|
waypoint.setElevation(number());
|
||||||
else if (_reader.name() == QLatin1String("geoidheight"))
|
else if (_reader.name() == QLatin1String("geoidheight"))
|
||||||
@ -244,6 +246,8 @@ void GPXParser::routepoints(RouteData &route, QList<TrackData> &tracks)
|
|||||||
route.setName(_reader.readElementText());
|
route.setName(_reader.readElementText());
|
||||||
else if (_reader.name() == QLatin1String("desc"))
|
else if (_reader.name() == QLatin1String("desc"))
|
||||||
route.setDescription(_reader.readElementText());
|
route.setDescription(_reader.readElementText());
|
||||||
|
else if (_reader.name() == QLatin1String("cmt"))
|
||||||
|
route.setComment(_reader.readElementText());
|
||||||
else if (_reader.name() == QLatin1String("link")) {
|
else if (_reader.name() == QLatin1String("link")) {
|
||||||
Link l(link());
|
Link l(link());
|
||||||
if (!l.URL().isEmpty())
|
if (!l.URL().isEmpty())
|
||||||
@ -278,6 +282,8 @@ void GPXParser::track(TrackData &track)
|
|||||||
track.setName(_reader.readElementText());
|
track.setName(_reader.readElementText());
|
||||||
else if (_reader.name() == QLatin1String("desc"))
|
else if (_reader.name() == QLatin1String("desc"))
|
||||||
track.setDescription(_reader.readElementText());
|
track.setDescription(_reader.readElementText());
|
||||||
|
else if (_reader.name() == QLatin1String("cmt"))
|
||||||
|
track.setComment(_reader.readElementText());
|
||||||
else if (_reader.name() == QLatin1String("link")) {
|
else if (_reader.name() == QLatin1String("link")) {
|
||||||
Link l(link());
|
Link l(link());
|
||||||
if (!l.URL().isEmpty())
|
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
|
#endif // GRAPH_H
|
||||||
|
@ -87,10 +87,12 @@ static bool readTimestamp(const char *data, QTime &time)
|
|||||||
|
|
||||||
static bool readARecord(const char *line, qint64 len)
|
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;
|
return false;
|
||||||
|
|
||||||
for (int i = 1; i < 7; i++)
|
for (int i = 1; i < 6; i++)
|
||||||
if (!::isprint(line[i]))
|
if (!::isprint(line[i]))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
|
@ -14,28 +14,19 @@ POI::POI(QObject *parent) : QObject(parent)
|
|||||||
{
|
{
|
||||||
_errorLine = 0;
|
_errorLine = 0;
|
||||||
_radius = 1000;
|
_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;
|
FileIndex index;
|
||||||
|
|
||||||
index.enabled = true;
|
index.enabled = true;
|
||||||
index.start = _data.size();
|
index.start = _data.size();
|
||||||
|
|
||||||
if (!data.isValid()) {
|
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();
|
_errorString = data.errorString();
|
||||||
_errorLine = data.errorLine();
|
_errorLine = data.errorLine();
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,37 +50,22 @@ bool POI::loadFile(const QString &path, bool dir)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool POI::loadFile(const QString &path)
|
void POI::loadDir(const QString &path)
|
||||||
{
|
|
||||||
_errorString.clear();
|
|
||||||
_errorLine = 0;
|
|
||||||
|
|
||||||
return loadFile(path, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool POI::loadDir(const QString &path)
|
|
||||||
{
|
{
|
||||||
QDir md(path);
|
QDir md(path);
|
||||||
md.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
|
md.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
QFileInfoList fl = md.entryInfoList();
|
QFileInfoList fl = md.entryInfoList();
|
||||||
bool ret = true;
|
|
||||||
|
|
||||||
_errorString.clear();
|
|
||||||
_errorLine = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < fl.size(); i++) {
|
for (int i = 0; i < fl.size(); i++) {
|
||||||
const QFileInfo &fi = fl.at(i);
|
const QFileInfo &fi = fl.at(i);
|
||||||
|
|
||||||
if (fi.isDir()) {
|
if (fi.isDir())
|
||||||
if (!loadDir(fi.absoluteFilePath()))
|
loadDir(fi.absoluteFilePath());
|
||||||
ret = false;
|
else
|
||||||
} else {
|
if (!loadFile(fi.absoluteFilePath()))
|
||||||
if (!loadFile(fi.absoluteFilePath(), true))
|
qWarning("%s: %s", qPrintable(fi.absoluteFilePath()),
|
||||||
ret = false;
|
qPrintable(_errorString));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool cb(size_t data, void* context)
|
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);
|
_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> POI::points(const Path &path) const
|
||||||
{
|
{
|
||||||
QList<Waypoint> ret;
|
QList<Waypoint> ret;
|
||||||
@ -158,8 +123,6 @@ QList<Waypoint> POI::points(const Path &path) const
|
|||||||
for (it = set.constBegin(); it != set.constEnd(); ++it)
|
for (it = set.constBegin(); it != set.constEnd(); ++it)
|
||||||
ret.append(_data.at(*it));
|
ret.append(_data.at(*it));
|
||||||
|
|
||||||
appendElevation(ret);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,8 +144,6 @@ QList<Waypoint> POI::points(const Waypoint &point) const
|
|||||||
for (it = set.constBegin(); it != set.constEnd(); ++it)
|
for (it = set.constBegin(); it != set.constEnd(); ++it)
|
||||||
ret.append(_data.at(*it));
|
ret.append(_data.at(*it));
|
||||||
|
|
||||||
appendElevation(ret);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,8 +167,6 @@ QList<Waypoint> POI::points(const Area &area) const
|
|||||||
for (it = set.constBegin(); it != set.constEnd(); ++it)
|
for (it = set.constBegin(); it != set.constEnd(); ++it)
|
||||||
ret.append(_data.at(*it));
|
ret.append(_data.at(*it));
|
||||||
|
|
||||||
appendElevation(ret);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,10 +212,3 @@ void POI::setRadius(unsigned radius)
|
|||||||
|
|
||||||
emit pointsChanged();
|
emit pointsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void POI::useDEM(bool use)
|
|
||||||
{
|
|
||||||
_useDEM = use;
|
|
||||||
|
|
||||||
emit pointsChanged();
|
|
||||||
}
|
|
||||||
|
@ -20,13 +20,12 @@ public:
|
|||||||
POI(QObject *parent = 0);
|
POI(QObject *parent = 0);
|
||||||
|
|
||||||
bool loadFile(const QString &path);
|
bool loadFile(const QString &path);
|
||||||
bool loadDir(const QString &path);
|
void loadDir(const QString &path);
|
||||||
const QString &errorString() const {return _errorString;}
|
const QString &errorString() const {return _errorString;}
|
||||||
int errorLine() const {return _errorLine;}
|
int errorLine() const {return _errorLine;}
|
||||||
|
|
||||||
unsigned radius() const {return _radius;}
|
unsigned radius() const {return _radius;}
|
||||||
void setRadius(unsigned radius);
|
void setRadius(unsigned radius);
|
||||||
void useDEM(bool use);
|
|
||||||
|
|
||||||
QList<Waypoint> points(const Path &path) const;
|
QList<Waypoint> points(const Path &path) const;
|
||||||
QList<Waypoint> points(const Waypoint &point) const;
|
QList<Waypoint> points(const Waypoint &point) const;
|
||||||
@ -49,7 +48,6 @@ private:
|
|||||||
|
|
||||||
bool loadFile(const QString &path, bool dir);
|
bool loadFile(const QString &path, bool dir);
|
||||||
void search(const RectC &rect, QSet<int> &set) const;
|
void search(const RectC &rect, QSet<int> &set) const;
|
||||||
void appendElevation(QList<Waypoint> &points) const;
|
|
||||||
|
|
||||||
POITree _tree;
|
POITree _tree;
|
||||||
QVector<Waypoint> _data;
|
QVector<Waypoint> _data;
|
||||||
@ -57,7 +55,6 @@ private:
|
|||||||
QList<FileIndex> _indexes;
|
QList<FileIndex> _indexes;
|
||||||
|
|
||||||
unsigned _radius;
|
unsigned _radius;
|
||||||
bool _useDEM;
|
|
||||||
|
|
||||||
QString _errorString;
|
QString _errorString;
|
||||||
int _errorLine;
|
int _errorLine;
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
|
#include "dem.h"
|
||||||
#include "route.h"
|
#include "route.h"
|
||||||
|
|
||||||
|
bool Route::_useDEM = false;
|
||||||
|
bool Route::_show2ndElevation = false;
|
||||||
|
|
||||||
Route::Route(const RouteData &data) : _data(data)
|
Route::Route(const RouteData &data) : _data(data)
|
||||||
{
|
{
|
||||||
@ -25,7 +28,7 @@ Path Route::path() const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Graph Route::elevation() const
|
Graph Route::gpsElevation() const
|
||||||
{
|
{
|
||||||
Graph graph;
|
Graph graph;
|
||||||
graph.append(GraphSegment());
|
graph.append(GraphSegment());
|
||||||
@ -38,6 +41,38 @@ Graph Route::elevation() const
|
|||||||
return graph;
|
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
|
qreal Route::distance() const
|
||||||
{
|
{
|
||||||
return (_distance.isEmpty()) ? 0 : _distance.last();
|
return (_distance.isEmpty()) ? 0 : _distance.last();
|
||||||
|
@ -11,23 +11,31 @@ class Route
|
|||||||
public:
|
public:
|
||||||
Route(const RouteData &data);
|
Route(const RouteData &data);
|
||||||
|
|
||||||
Path path() const;
|
|
||||||
|
|
||||||
const RouteData &data() const {return _data;}
|
const RouteData &data() const {return _data;}
|
||||||
|
Path path() const;
|
||||||
Graph elevation() const;
|
GraphPair elevation() const;
|
||||||
|
|
||||||
qreal distance() const;
|
qreal distance() const;
|
||||||
|
|
||||||
const QString &name() const {return _data.name();}
|
const QString &name() const {return _data.name();}
|
||||||
const QString &description() const {return _data.description();}
|
const QString &description() const {return _data.description();}
|
||||||
|
const QString &comment() const {return _data.comment();}
|
||||||
const QVector<Link> &links() const {return _data.links();}
|
const QVector<Link> &links() const {return _data.links();}
|
||||||
|
|
||||||
bool isValid() const {return _data.size() >= 2;}
|
bool isValid() const {return _data.size() >= 2;}
|
||||||
|
|
||||||
|
static void useDEM(bool use) {_useDEM = use;}
|
||||||
|
static void showSecondaryElevation(bool show)
|
||||||
|
{_show2ndElevation = show;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Graph gpsElevation() const;
|
||||||
|
Graph demElevation() const;
|
||||||
|
|
||||||
RouteData _data;
|
RouteData _data;
|
||||||
QVector<qreal> _distance;
|
QVector<qreal> _distance;
|
||||||
|
|
||||||
|
static bool _useDEM;
|
||||||
|
static bool _show2ndElevation;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ROUTE_H
|
#endif // ROUTE_H
|
||||||
|
@ -11,15 +11,18 @@ class RouteData : public QVector<Waypoint>
|
|||||||
public:
|
public:
|
||||||
const QString &name() const {return _name;}
|
const QString &name() const {return _name;}
|
||||||
const QString &description() const {return _desc;}
|
const QString &description() const {return _desc;}
|
||||||
|
const QString &comment() const {return _comment;}
|
||||||
const QVector<Link> &links() const {return _links;}
|
const QVector<Link> &links() const {return _links;}
|
||||||
|
|
||||||
void setName(const QString &name) {_name = name;}
|
void setName(const QString &name) {_name = name;}
|
||||||
void setDescription(const QString &desc) {_desc = desc;}
|
void setDescription(const QString &desc) {_desc = desc;}
|
||||||
|
void setComment(const QString &comment) {_comment = comment;}
|
||||||
void addLink(const Link &link) {_links.append(link);}
|
void addLink(const Link &link) {_links.append(link);}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString _name;
|
QString _name;
|
||||||
QString _desc;
|
QString _desc;
|
||||||
|
QString _comment;
|
||||||
QVector<Link> _links;
|
QVector<Link> _links;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include "dem.h"
|
||||||
#include "track.h"
|
#include "track.h"
|
||||||
|
|
||||||
|
|
||||||
@ -13,6 +14,9 @@ int Track::_pauseInterval = 10;
|
|||||||
|
|
||||||
bool Track::_outlierEliminate = true;
|
bool Track::_outlierEliminate = true;
|
||||||
bool Track::_useReportedSpeed = false;
|
bool Track::_useReportedSpeed = false;
|
||||||
|
bool Track::_useDEM = false;
|
||||||
|
bool Track::_show2ndElevation = false;
|
||||||
|
bool Track::_show2ndSpeed = false;
|
||||||
|
|
||||||
|
|
||||||
static qreal avg(const QVector<qreal> &v)
|
static qreal avg(const QVector<qreal> &v)
|
||||||
@ -47,7 +51,7 @@ static QSet<int> eliminate(const QVector<qreal> &v)
|
|||||||
qreal M = MAD(w, m);
|
qreal M = MAD(w, m);
|
||||||
|
|
||||||
for (int i = 0; i < v.size(); i++)
|
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) > 3.5)
|
||||||
rm.insert(i);
|
rm.insert(i);
|
||||||
|
|
||||||
return rm;
|
return rm;
|
||||||
@ -213,7 +217,7 @@ Track::Track(const TrackData &data) : _data(data), _pause(0)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Graph Track::elevation() const
|
Graph Track::gpsElevation() const
|
||||||
{
|
{
|
||||||
Graph ret;
|
Graph ret;
|
||||||
|
|
||||||
@ -237,7 +241,48 @@ Graph Track::elevation() const
|
|||||||
return ret;
|
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;
|
Graph ret;
|
||||||
|
|
||||||
@ -251,14 +296,10 @@ Graph Track::speed() const
|
|||||||
qreal v;
|
qreal v;
|
||||||
|
|
||||||
for (int j = 0; j < sd.size(); j++) {
|
for (int j = 0; j < sd.size(); j++) {
|
||||||
if (seg.stop.contains(j) && (!std::isnan(seg.speed.at(j))
|
if (seg.stop.contains(j) && !std::isnan(seg.speed.at(j))) {
|
||||||
|| sd.at(j).hasSpeed())) {
|
|
||||||
v = 0;
|
v = 0;
|
||||||
stop.append(gs.size());
|
stop.append(gs.size());
|
||||||
} else if (_useReportedSpeed && sd.at(j).hasSpeed()
|
} else if (!std::isnan(seg.speed.at(j)) && !seg.outliers.contains(j))
|
||||||
&& !seg.outliers.contains(j))
|
|
||||||
v = sd.at(j).speed();
|
|
||||||
else if (!std::isnan(seg.speed.at(j)) && !seg.outliers.contains(j))
|
|
||||||
v = seg.speed.at(j);
|
v = seg.speed.at(j);
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
@ -276,6 +317,60 @@ Graph Track::speed() const
|
|||||||
return ret;
|
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 Track::heartRate() const
|
||||||
{
|
{
|
||||||
Graph ret;
|
Graph ret;
|
||||||
|
@ -17,8 +17,8 @@ public:
|
|||||||
|
|
||||||
Path path() const;
|
Path path() const;
|
||||||
|
|
||||||
Graph elevation() const;
|
GraphPair elevation() const;
|
||||||
Graph speed() const;
|
GraphPair speed() const;
|
||||||
Graph heartRate() const;
|
Graph heartRate() const;
|
||||||
Graph temperature() const;
|
Graph temperature() const;
|
||||||
Graph cadence() const;
|
Graph cadence() const;
|
||||||
@ -32,6 +32,7 @@ public:
|
|||||||
|
|
||||||
const QString &name() const {return _data.name();}
|
const QString &name() const {return _data.name();}
|
||||||
const QString &description() const {return _data.description();}
|
const QString &description() const {return _data.description();}
|
||||||
|
const QString &comment() const {return _data.comment();}
|
||||||
const QVector<Link> &links() const {return _data.links();}
|
const QVector<Link> &links() const {return _data.links();}
|
||||||
|
|
||||||
bool isValid() const;
|
bool isValid() const;
|
||||||
@ -47,6 +48,11 @@ public:
|
|||||||
static void setOutlierElimination(bool eliminate)
|
static void setOutlierElimination(bool eliminate)
|
||||||
{_outlierEliminate = eliminate;}
|
{_outlierEliminate = eliminate;}
|
||||||
static void useReportedSpeed(bool use) {_useReportedSpeed = use;}
|
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:
|
private:
|
||||||
struct Segment {
|
struct Segment {
|
||||||
@ -59,6 +65,11 @@ private:
|
|||||||
|
|
||||||
bool discardStopPoint(const Segment &seg, int i) const;
|
bool discardStopPoint(const Segment &seg, int i) const;
|
||||||
|
|
||||||
|
Graph demElevation() const;
|
||||||
|
Graph gpsElevation() const;
|
||||||
|
Graph reportedSpeed() const;
|
||||||
|
Graph computedSpeed() const;
|
||||||
|
|
||||||
TrackData _data;
|
TrackData _data;
|
||||||
QList<Segment> _segments;
|
QList<Segment> _segments;
|
||||||
qreal _pause;
|
qreal _pause;
|
||||||
@ -73,6 +84,9 @@ private:
|
|||||||
static qreal _pauseSpeed;
|
static qreal _pauseSpeed;
|
||||||
static int _pauseInterval;
|
static int _pauseInterval;
|
||||||
static bool _useReportedSpeed;
|
static bool _useReportedSpeed;
|
||||||
|
static bool _useDEM;
|
||||||
|
static bool _show2ndElevation;
|
||||||
|
static bool _show2ndSpeed;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TRACK_H
|
#endif // TRACK_H
|
||||||
|
@ -14,15 +14,18 @@ class TrackData : public QList<SegmentData>
|
|||||||
public:
|
public:
|
||||||
const QString &name() const {return _name;}
|
const QString &name() const {return _name;}
|
||||||
const QString &description() const {return _desc;}
|
const QString &description() const {return _desc;}
|
||||||
|
const QString &comment() const {return _comment;}
|
||||||
const QVector<Link> &links() const {return _links;}
|
const QVector<Link> &links() const {return _links;}
|
||||||
|
|
||||||
void setName(const QString &name) {_name = name;}
|
void setName(const QString &name) {_name = name;}
|
||||||
void setDescription(const QString &desc) {_desc = desc;}
|
void setDescription(const QString &desc) {_desc = desc;}
|
||||||
|
void setComment(const QString &comment) {_comment = comment;}
|
||||||
void addLink(const Link &link) {_links.append(link);}
|
void addLink(const Link &link) {_links.append(link);}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString _name;
|
QString _name;
|
||||||
QString _desc;
|
QString _desc;
|
||||||
|
QString _comment;
|
||||||
QVector<Link> _links;
|
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,28 @@
|
|||||||
class Waypoint
|
class Waypoint
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Waypoint() {_elevation = NAN;}
|
Waypoint() : _elevation(NAN) {}
|
||||||
Waypoint(const Coordinates &coordinates) : _coordinates(coordinates)
|
Waypoint(const Coordinates &coordinates)
|
||||||
{_elevation = NAN;}
|
: _coordinates(coordinates), _elevation(NAN) {}
|
||||||
|
|
||||||
const Coordinates &coordinates() const {return _coordinates;}
|
const Coordinates &coordinates() const {return _coordinates;}
|
||||||
const QString &name() const {return _name;}
|
const QString &name() const {return _name;}
|
||||||
const QString &description() const {return _description;}
|
const QString &description() const {return _description;}
|
||||||
|
const QString &comment() const {return _comment;}
|
||||||
const Address &address() const {return _address;}
|
const Address &address() const {return _address;}
|
||||||
const QVector<ImageInfo> &images() const {return _images;}
|
const QVector<ImageInfo> &images() const {return _images;}
|
||||||
const QVector<Link> &links() const {return _links;}
|
const QVector<Link> &links() const {return _links;}
|
||||||
const QDateTime ×tamp() const {return _timestamp;}
|
const QDateTime ×tamp() const {return _timestamp;}
|
||||||
qreal elevation() const {return _elevation;}
|
qreal elevation() const {return _elevation;}
|
||||||
|
|
||||||
|
QPair<qreal, qreal> elevations() const;
|
||||||
|
|
||||||
void setCoordinates(const Coordinates &coordinates)
|
void setCoordinates(const Coordinates &coordinates)
|
||||||
{_coordinates = coordinates;}
|
{_coordinates = coordinates;}
|
||||||
void setName(const QString &name) {_name = name;}
|
void setName(const QString &name) {_name = name;}
|
||||||
void setDescription(const QString &description)
|
void setDescription(const QString &description)
|
||||||
{_description = description;}
|
{_description = description;}
|
||||||
|
void setComment(const QString &comment) {_comment = comment;}
|
||||||
void setAddress(const Address &address) {_address = address;}
|
void setAddress(const Address &address) {_address = address;}
|
||||||
void setTimestamp(const QDateTime ×tamp) {_timestamp = timestamp;}
|
void setTimestamp(const QDateTime ×tamp) {_timestamp = timestamp;}
|
||||||
void setElevation(qreal elevation) {_elevation = elevation;}
|
void setElevation(qreal elevation) {_elevation = elevation;}
|
||||||
@ -44,15 +48,23 @@ public:
|
|||||||
{return this->_name == other._name
|
{return this->_name == other._name
|
||||||
&& this->_coordinates == other._coordinates;}
|
&& this->_coordinates == other._coordinates;}
|
||||||
|
|
||||||
|
static void useDEM(bool use) {_useDEM = use;}
|
||||||
|
static void showSecondaryElevation(bool show)
|
||||||
|
{_show2ndElevation = show;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Coordinates _coordinates;
|
Coordinates _coordinates;
|
||||||
QString _name;
|
QString _name;
|
||||||
QString _description;
|
QString _description;
|
||||||
|
QString _comment;
|
||||||
Address _address;
|
Address _address;
|
||||||
QVector<ImageInfo> _images;
|
QVector<ImageInfo> _images;
|
||||||
QVector<Link> _links;
|
QVector<Link> _links;
|
||||||
QDateTime _timestamp;
|
QDateTime _timestamp;
|
||||||
qreal _elevation;
|
qreal _elevation;
|
||||||
|
|
||||||
|
static bool _useDEM;
|
||||||
|
static bool _show2ndElevation;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline uint qHash(const Waypoint &key)
|
inline uint qHash(const Waypoint &key)
|
||||||
@ -64,11 +76,9 @@ inline uint qHash(const Waypoint &key)
|
|||||||
inline QDebug operator<<(QDebug dbg, const Waypoint &waypoint)
|
inline QDebug operator<<(QDebug dbg, const Waypoint &waypoint)
|
||||||
{
|
{
|
||||||
dbg.nospace() << "Waypoint(" << waypoint.coordinates() << ", "
|
dbg.nospace() << "Waypoint(" << waypoint.coordinates() << ", "
|
||||||
<< waypoint.name() << ", " << waypoint.description() << ")";
|
<< waypoint.name() << ")";
|
||||||
return dbg.space();
|
return dbg.space();
|
||||||
}
|
}
|
||||||
#endif // QT_NO_DEBUG
|
#endif // QT_NO_DEBUG
|
||||||
|
|
||||||
Q_DECLARE_TYPEINFO(Waypoint, Q_MOVABLE_TYPE);
|
|
||||||
|
|
||||||
#endif // WAYPOINT_H
|
#endif // WAYPOINT_H
|
||||||
|
@ -425,7 +425,7 @@ QMap<RGNFile::SegmentType, SubDiv::Segment> RGNFile::segments(Handle &hdl,
|
|||||||
quint32 ls = 0;
|
quint32 ls = 0;
|
||||||
SegmentType lt = (SegmentType)0;
|
SegmentType lt = (SegmentType)0;
|
||||||
|
|
||||||
for (quint16 mask = 0x1; mask <= 0x10; mask <<= 1) {
|
for (quint8 mask = 0x1; mask <= 0x10; mask <<= 1) {
|
||||||
if (subdiv->objects() & mask) {
|
if (subdiv->objects() & mask) {
|
||||||
if (ls) {
|
if (ls) {
|
||||||
quint16 po;
|
quint16 po;
|
||||||
|
@ -260,13 +260,6 @@ void IMGMap::unload()
|
|||||||
_data->clear();
|
_data->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
QRectF IMGMap::bounds()
|
|
||||||
{
|
|
||||||
RectD prect(_data->bounds(), _projection);
|
|
||||||
return QRectF(_transform.proj2img(prect.topLeft()),
|
|
||||||
_transform.proj2img(prect.bottomRight()));
|
|
||||||
}
|
|
||||||
|
|
||||||
int IMGMap::zoomFit(const QSize &size, const RectC &rect)
|
int IMGMap::zoomFit(const QSize &size, const RectC &rect)
|
||||||
{
|
{
|
||||||
if (rect.isValid()) {
|
if (rect.isValid()) {
|
||||||
@ -320,6 +313,10 @@ Transform IMGMap::transform(int zoom) const
|
|||||||
void IMGMap::updateTransform()
|
void IMGMap::updateTransform()
|
||||||
{
|
{
|
||||||
_transform = transform(_zoom);
|
_transform = transform(_zoom);
|
||||||
|
|
||||||
|
RectD prect(_data->bounds(), _projection);
|
||||||
|
_bounds = QRectF(_transform.proj2img(prect.topLeft()),
|
||||||
|
_transform.proj2img(prect.bottomRight()));
|
||||||
}
|
}
|
||||||
|
|
||||||
QPointF IMGMap::ll2xy(const Coordinates &c)
|
QPointF IMGMap::ll2xy(const Coordinates &c)
|
||||||
|
@ -18,7 +18,7 @@ public:
|
|||||||
|
|
||||||
QString name() const {return _data->name();}
|
QString name() const {return _data->name();}
|
||||||
|
|
||||||
QRectF bounds();
|
QRectF bounds() {return _bounds;}
|
||||||
|
|
||||||
virtual int zoom() const {return _zoom;}
|
virtual int zoom() const {return _zoom;}
|
||||||
virtual void setZoom(int zoom);
|
virtual void setZoom(int zoom);
|
||||||
@ -62,6 +62,7 @@ private:
|
|||||||
int _zoom;
|
int _zoom;
|
||||||
Projection _projection;
|
Projection _projection;
|
||||||
Transform _transform;
|
Transform _transform;
|
||||||
|
QRectF _bounds;
|
||||||
|
|
||||||
bool _valid;
|
bool _valid;
|
||||||
QString _errorString;
|
QString _errorString;
|
||||||
|
@ -50,12 +50,15 @@ public:
|
|||||||
virtual void setProjection(const Projection &) {}
|
virtual void setProjection(const Projection &) {}
|
||||||
|
|
||||||
virtual bool isValid() const {return true;}
|
virtual bool isValid() const {return true;}
|
||||||
|
virtual bool isReady() const {return true;}
|
||||||
virtual QString errorString() const {return QString();}
|
virtual QString errorString() const {return QString();}
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void loaded();
|
void tilesLoaded();
|
||||||
|
void mapLoaded();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(Map*)
|
||||||
Q_DECLARE_OPERATORS_FOR_FLAGS(Map::Flags)
|
Q_DECLARE_OPERATORS_FOR_FLAGS(Map::Flags)
|
||||||
|
|
||||||
#endif // MAP_H
|
#endif // MAP_H
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QApplication>
|
||||||
#include "atlas.h"
|
#include "atlas.h"
|
||||||
#include "ozimap.h"
|
#include "ozimap.h"
|
||||||
#include "jnxmap.h"
|
#include "jnxmap.h"
|
||||||
@ -12,31 +13,8 @@
|
|||||||
#include "maplist.h"
|
#include "maplist.h"
|
||||||
|
|
||||||
|
|
||||||
bool MapList::loadMap(Map *map, const QString &path)
|
Map *MapList::loadFile(const QString &path, QString &errorString,
|
||||||
{
|
bool *terminate)
|
||||||
if (map && map->isValid()) {
|
|
||||||
_maps.append(map);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
_errorPath = path;
|
|
||||||
_errorString = (map) ? map->errorString() : "Unknown file format";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Map *MapList::loadSource(const QString &path)
|
|
||||||
{
|
|
||||||
Map *map = MapSource::loadMap(path, _errorString);
|
|
||||||
|
|
||||||
if (!map)
|
|
||||||
_errorPath = path;
|
|
||||||
else
|
|
||||||
map->setParent(this);
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MapList::loadFile(const QString &path, bool *terminate)
|
|
||||||
{
|
{
|
||||||
QFileInfo fi(path);
|
QFileInfo fi(path);
|
||||||
QString suffix = fi.suffix().toLower();
|
QString suffix = fi.suffix().toLower();
|
||||||
@ -45,75 +23,95 @@ bool MapList::loadFile(const QString &path, bool *terminate)
|
|||||||
if (Atlas::isAtlas(path)) {
|
if (Atlas::isAtlas(path)) {
|
||||||
if (terminate)
|
if (terminate)
|
||||||
*terminate = true;
|
*terminate = true;
|
||||||
map = new Atlas(path, this);
|
map = new Atlas(path);
|
||||||
} else if (suffix == "xml") {
|
} else if (suffix == "xml") {
|
||||||
if (MapSource::isMap(path) && !(map = loadSource(path)))
|
if (MapSource::isMap(path)) {
|
||||||
return false;
|
if (!(map = MapSource::loadMap(path, errorString)))
|
||||||
else if (GMAP::isGMAP(path)) {
|
return 0;
|
||||||
|
} else if (GMAP::isGMAP(path)) {
|
||||||
if (terminate)
|
if (terminate)
|
||||||
*terminate = true;
|
*terminate = true;
|
||||||
map = new IMGMap(path);
|
map = new IMGMap(path);
|
||||||
}
|
}
|
||||||
} else if (suffix == "jnx")
|
} else if (suffix == "jnx")
|
||||||
map = new JNXMap(path, this);
|
map = new JNXMap(path);
|
||||||
else if (suffix == "tif" || suffix == "tiff")
|
else if (suffix == "tif" || suffix == "tiff")
|
||||||
map = new GeoTIFFMap(path, this);
|
map = new GeoTIFFMap(path);
|
||||||
else if (suffix == "mbtiles")
|
else if (suffix == "mbtiles")
|
||||||
map = new MBTilesMap(path, this);
|
map = new MBTilesMap(path);
|
||||||
else if (suffix == "rmap" || suffix == "rtmap")
|
else if (suffix == "rmap" || suffix == "rtmap")
|
||||||
map = new RMap(path, this);
|
map = new RMap(path);
|
||||||
else if (suffix == "img")
|
else if (suffix == "img")
|
||||||
map = new IMGMap(path, this);
|
map = new IMGMap(path);
|
||||||
else if (suffix == "map" || suffix == "tar")
|
else if (suffix == "map" || suffix == "tar")
|
||||||
map = new OziMap(path, this);
|
map = new OziMap(path);
|
||||||
|
|
||||||
if (!loadMap(map, path)) {
|
if (map && map->isValid())
|
||||||
|
return map;
|
||||||
|
else {
|
||||||
|
errorString = (map) ? map->errorString() : "Unknown file format";
|
||||||
delete map;
|
delete map;
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MapList::loadDir(const QString &path)
|
QList<Map*> MapList::loadDir(const QString &path, QString &errorString)
|
||||||
{
|
{
|
||||||
QDir md(path);
|
QDir md(path);
|
||||||
md.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
|
md.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
md.setSorting(QDir::DirsLast);
|
md.setSorting(QDir::DirsLast);
|
||||||
QFileInfoList ml = md.entryInfoList();
|
QFileInfoList ml = md.entryInfoList();
|
||||||
bool ret = true;
|
QList<Map*> list;
|
||||||
|
|
||||||
for (int i = 0; i < ml.size(); i++) {
|
for (int i = 0; i < ml.size(); i++) {
|
||||||
const QFileInfo &fi = ml.at(i);
|
const QFileInfo &fi = ml.at(i);
|
||||||
QString suffix = fi.suffix().toLower();
|
QString suffix = fi.suffix().toLower();
|
||||||
bool terminate = false;
|
bool terminate = false;
|
||||||
|
|
||||||
if (fi.isDir() && fi.fileName() != "set") {
|
if (fi.isDir() && fi.fileName() != "set")
|
||||||
if (!loadDir(fi.absoluteFilePath()))
|
list.append(loadDir(fi.absoluteFilePath(), errorString));
|
||||||
ret = false;
|
else if (filter().contains("*." + suffix)) {
|
||||||
} else if (filter().contains("*." + suffix)) {
|
Map *map = loadFile(fi.absoluteFilePath(), errorString, &terminate);
|
||||||
if (!loadFile(fi.absoluteFilePath(), &terminate))
|
if (map)
|
||||||
ret = false;
|
list.append(map);
|
||||||
|
else
|
||||||
|
qWarning("%s: %s", qPrintable(fi.absoluteFilePath()),
|
||||||
|
qPrintable(errorString));
|
||||||
if (terminate)
|
if (terminate)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<Map*> MapList::loadMaps(const QString &path, QString &errorString)
|
||||||
|
{
|
||||||
|
if (QFileInfo(path).isDir())
|
||||||
|
return loadDir(path, errorString);
|
||||||
|
else {
|
||||||
|
QList<Map*> list;
|
||||||
|
Map *map = loadFile(path, errorString, 0);
|
||||||
|
if (map)
|
||||||
|
list.append(map);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MapList::formats()
|
QString MapList::formats()
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
tr("Supported files") + " (" + filter().join(" ") + ");;"
|
qApp->translate("MapList", "Supported files")
|
||||||
+ tr("Garmin IMG maps") + " (*.gmap *.gmapi *.img *.xml);;"
|
+ " (" + filter().join(" ") + ");;"
|
||||||
+ tr("Garmin JNX maps") + " (*.jnx);;"
|
+ qApp->translate("MapList", "Garmin IMG maps")
|
||||||
+ tr("OziExplorer maps") + " (*.map);;"
|
+ " (*.gmap *.gmapi *.img *.xml);;"
|
||||||
+ tr("MBTiles maps") + " (*.mbtiles);;"
|
+ qApp->translate("MapList", "Garmin JNX maps") + " (*.jnx);;"
|
||||||
+ tr("TrekBuddy maps/atlases") + " (*.tar *.tba);;"
|
+ qApp->translate("MapList", "OziExplorer maps") + " (*.map);;"
|
||||||
+ tr("GeoTIFF images") + " (*.tif *.tiff);;"
|
+ qApp->translate("MapList", "MBTiles maps") + " (*.mbtiles);;"
|
||||||
+ tr("TwoNav maps") + " (*.rmap *.rtmap);;"
|
+ qApp->translate("MapList", "TrekBuddy maps/atlases") + " (*.tar *.tba);;"
|
||||||
+ tr("Online map sources") + " (*.xml)";
|
+ qApp->translate("MapList", "GeoTIFF images") + " (*.tif *.tiff);;"
|
||||||
|
+ qApp->translate("MapList", "TwoNav maps") + " (*.rmap *.rtmap);;"
|
||||||
|
+ qApp->translate("MapList", "Online map sources") + " (*.xml)";
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList MapList::filter()
|
QStringList MapList::filter()
|
||||||
|
@ -1,36 +1,21 @@
|
|||||||
#ifndef MAPLIST_H
|
#ifndef MAPLIST_H
|
||||||
#define MAPLIST_H
|
#define MAPLIST_H
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
class Map;
|
class Map;
|
||||||
|
|
||||||
class MapList : public QObject
|
class MapList
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MapList(QObject *parent = 0) : QObject(parent) {}
|
static QList<Map*> loadMaps(const QString &path, QString &errorString);
|
||||||
|
|
||||||
bool loadFile(const QString &path, bool *terminate = 0);
|
|
||||||
bool loadDir(const QString &path);
|
|
||||||
|
|
||||||
const QList<Map*> &maps() const {return _maps;}
|
|
||||||
|
|
||||||
const QString &errorString() const {return _errorString;}
|
|
||||||
const QString &errorPath() const {return _errorPath;}
|
|
||||||
|
|
||||||
static QString formats();
|
static QString formats();
|
||||||
static QStringList filter();
|
static QStringList filter();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Map *loadSource(const QString &path);
|
static Map *loadFile(const QString &path, QString &errorString,
|
||||||
bool loadMap(Map *map, const QString &path);
|
bool *terminate);
|
||||||
|
static QList<Map*> loadDir(const QString &path, QString &errorString);
|
||||||
QList<Map*> _maps;
|
|
||||||
QString _errorString;
|
|
||||||
QString _errorPath;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MAPLIST_H
|
#endif // MAPLIST_H
|
||||||
|
@ -300,7 +300,7 @@ Map *MapSource::loadMap(const QString &path, QString &errorString)
|
|||||||
case WMS:
|
case WMS:
|
||||||
return new WMSMap(config.name, WMS::Setup(config.url, config.layer,
|
return new WMSMap(config.name, WMS::Setup(config.url, config.layer,
|
||||||
config.style, config.format, config.crs, config.coordinateSystem,
|
config.style, config.format, config.crs, config.coordinateSystem,
|
||||||
config.dimensions, config.authorization));
|
config.dimensions, config.authorization), config.tileSize);
|
||||||
case TMS:
|
case TMS:
|
||||||
return new OnlineMap(config.name, config.url, config.zooms,
|
return new OnlineMap(config.name, config.url, config.zooms,
|
||||||
config.bounds, config.tileRatio, config.authorization,
|
config.bounds, config.tileRatio, config.authorization,
|
||||||
|
@ -21,7 +21,7 @@ OnlineMap::OnlineMap(const QString &name, const QString &url,
|
|||||||
_tileLoader->setUrl(url);
|
_tileLoader->setUrl(url);
|
||||||
_tileLoader->setAuthorization(authorization);
|
_tileLoader->setAuthorization(authorization);
|
||||||
_tileLoader->setQuadTiles(quadTiles);
|
_tileLoader->setQuadTiles(quadTiles);
|
||||||
connect(_tileLoader, SIGNAL(finished()), this, SIGNAL(loaded()));
|
connect(_tileLoader, SIGNAL(finished()), this, SIGNAL(tilesLoaded()));
|
||||||
}
|
}
|
||||||
|
|
||||||
QRectF OnlineMap::bounds()
|
QRectF OnlineMap::bounds()
|
||||||
|
@ -169,6 +169,17 @@ void TileLoader::clearCache()
|
|||||||
dir.remove(list.at(i));
|
dir.remove(list.at(i));
|
||||||
|
|
||||||
_downloader->clearErrors();
|
_downloader->clearErrors();
|
||||||
|
|
||||||
|
QPixmapCache::clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TileLoader::setScaledSize(int size)
|
||||||
|
{
|
||||||
|
if (_scaledSize == size)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_scaledSize = size;
|
||||||
|
QPixmapCache::clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
QUrl TileLoader::tileUrl(const Tile &tile) const
|
QUrl TileLoader::tileUrl(const Tile &tile) const
|
||||||
|
@ -16,7 +16,7 @@ public:
|
|||||||
void setUrl(const QString &url) {_url = url;}
|
void setUrl(const QString &url) {_url = url;}
|
||||||
void setAuthorization(const Authorization &authorization)
|
void setAuthorization(const Authorization &authorization)
|
||||||
{_authorization = authorization;}
|
{_authorization = authorization;}
|
||||||
void setScaledSize(int size) {_scaledSize = size;}
|
void setScaledSize(int size);
|
||||||
void setQuadTiles(bool quadTiles) {_quadTiles = quadTiles;}
|
void setQuadTiles(bool quadTiles) {_quadTiles = quadTiles;}
|
||||||
|
|
||||||
void loadTilesAsync(QVector<Tile> &list);
|
void loadTilesAsync(QVector<Tile> &list);
|
||||||
|
143
src/map/wms.cpp
143
src/map/wms.cpp
@ -1,3 +1,4 @@
|
|||||||
|
#include <cmath>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QEventLoop>
|
#include <QEventLoop>
|
||||||
#include <QXmlStreamReader>
|
#include <QXmlStreamReader>
|
||||||
@ -7,6 +8,19 @@
|
|||||||
#include "wms.h"
|
#include "wms.h"
|
||||||
|
|
||||||
|
|
||||||
|
static QString bareFormat(const QString &format)
|
||||||
|
{
|
||||||
|
return format.left(format.indexOf(';')).trimmed();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline double hint2denominator(double h)
|
||||||
|
{
|
||||||
|
/* Some WMS 1.1.1 servers use a 72dpi resolution by default. Using the usual
|
||||||
|
90dpi (0.28mm) resolution known from later standards (WMS 1.3, WMTS) does
|
||||||
|
make them return emty images in the "max" scale level. */
|
||||||
|
return h / (M_SQRT2 * 0.36e-3);
|
||||||
|
}
|
||||||
|
|
||||||
WMS::CTX::CTX(const Setup &setup) : setup(setup), formatSupported(false)
|
WMS::CTX::CTX(const Setup &setup) : setup(setup), formatSupported(false)
|
||||||
{
|
{
|
||||||
QStringList ll = setup.layer().split(',');
|
QStringList ll = setup.layer().split(',');
|
||||||
@ -24,13 +38,48 @@ WMS::CTX::CTX(const Setup &setup) : setup(setup), formatSupported(false)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WMS::get(QXmlStreamReader &reader, CTX &ctx)
|
||||||
|
{
|
||||||
|
while (reader.readNextStartElement()) {
|
||||||
|
if (reader.name() == "OnlineResource") {
|
||||||
|
QXmlStreamAttributes attr = reader.attributes();
|
||||||
|
ctx.url = attr.value("xlink:href").toString();
|
||||||
|
reader.skipCurrentElement();
|
||||||
|
} else
|
||||||
|
reader.skipCurrentElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WMS::http(QXmlStreamReader &reader, CTX &ctx)
|
||||||
|
{
|
||||||
|
while (reader.readNextStartElement()) {
|
||||||
|
if (reader.name() == "Get")
|
||||||
|
get(reader, ctx);
|
||||||
|
else
|
||||||
|
reader.skipCurrentElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WMS::dcpType(QXmlStreamReader &reader, CTX &ctx)
|
||||||
|
{
|
||||||
|
while (reader.readNextStartElement()) {
|
||||||
|
if (reader.name() == "HTTP")
|
||||||
|
http(reader, ctx);
|
||||||
|
else
|
||||||
|
reader.skipCurrentElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void WMS::getMap(QXmlStreamReader &reader, CTX &ctx)
|
void WMS::getMap(QXmlStreamReader &reader, CTX &ctx)
|
||||||
{
|
{
|
||||||
while (reader.readNextStartElement()) {
|
while (reader.readNextStartElement()) {
|
||||||
if (reader.name() == "Format") {
|
if (reader.name() == "Format") {
|
||||||
if (reader.readElementText() == ctx.setup.format())
|
QString format(reader.readElementText());
|
||||||
|
if (bareFormat(format) == bareFormat(ctx.setup.format()))
|
||||||
ctx.formatSupported = true;
|
ctx.formatSupported = true;
|
||||||
} else
|
} else if (reader.name() == "DCPType")
|
||||||
|
dcpType(reader, ctx);
|
||||||
|
else
|
||||||
reader.skipCurrentElement();
|
reader.skipCurrentElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,7 +146,16 @@ void WMS::layer(QXmlStreamReader &reader, CTX &ctx,
|
|||||||
CRSs.append(reader.readElementText());
|
CRSs.append(reader.readElementText());
|
||||||
else if (reader.name() == "Style")
|
else if (reader.name() == "Style")
|
||||||
styles.append(style(reader));
|
styles.append(style(reader));
|
||||||
else if (reader.name() == "MinScaleDenominator") {
|
else if (reader.name() == "ScaleHint") {
|
||||||
|
QXmlStreamAttributes attr = reader.attributes();
|
||||||
|
double minHint = attr.value("min").toString().toDouble();
|
||||||
|
double maxHint = attr.value("max").toString().toDouble();
|
||||||
|
if (minHint > 0)
|
||||||
|
scaleDenominator.setMin(hint2denominator(minHint));
|
||||||
|
if (maxHint > 0)
|
||||||
|
scaleDenominator.setMax(hint2denominator(maxHint));
|
||||||
|
reader.skipCurrentElement();
|
||||||
|
} else if (reader.name() == "MinScaleDenominator") {
|
||||||
double sd = reader.readElementText().toDouble();
|
double sd = reader.readElementText().toDouble();
|
||||||
if (sd > 0)
|
if (sd > 0)
|
||||||
scaleDenominator.setMin(sd);
|
scaleDenominator.setMin(sd);
|
||||||
@ -160,10 +218,10 @@ void WMS::capabilities(QXmlStreamReader &reader, CTX &ctx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WMS::parseCapabilities(const QString &path, const Setup &setup)
|
bool WMS::parseCapabilities()
|
||||||
{
|
{
|
||||||
QFile file(path);
|
QFile file(_path);
|
||||||
CTX ctx(setup);
|
CTX ctx(_setup);
|
||||||
QXmlStreamReader reader;
|
QXmlStreamReader reader;
|
||||||
|
|
||||||
|
|
||||||
@ -186,7 +244,7 @@ bool WMS::parseCapabilities(const QString &path, const Setup &setup)
|
|||||||
reader.raiseError("Not a WMS Capabilities XML file");
|
reader.raiseError("Not a WMS Capabilities XML file");
|
||||||
}
|
}
|
||||||
if (reader.error()) {
|
if (reader.error()) {
|
||||||
_errorString = QString("%1:%2: %3").arg(path).arg(reader.lineNumber())
|
_errorString = QString("%1:%2: %3").arg(_path).arg(reader.lineNumber())
|
||||||
.arg(reader.errorString());
|
.arg(reader.errorString());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -232,10 +290,10 @@ bool WMS::parseCapabilities(const QString &path, const Setup &setup)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_boundingBox = ctx.layers.first().boundingBox;
|
_bbox = ctx.layers.first().boundingBox;
|
||||||
for (int i = 1; i < ctx.layers.size(); i++)
|
for (int i = 1; i < ctx.layers.size(); i++)
|
||||||
_boundingBox &= ctx.layers.at(i).boundingBox;
|
_bbox &= ctx.layers.at(i).boundingBox;
|
||||||
if (_boundingBox.isNull()) {
|
if (_bbox.isNull()) {
|
||||||
_errorString = "Empty layers bounding box join";
|
_errorString = "Empty layers bounding box join";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -248,40 +306,57 @@ bool WMS::parseCapabilities(const QString &path, const Setup &setup)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_version >= "1.3.0") {
|
||||||
|
if (_setup.coordinateSystem().axisOrder() == CoordinateSystem::Unknown)
|
||||||
|
_cs = _projection.coordinateSystem();
|
||||||
|
else
|
||||||
|
_cs = _setup.coordinateSystem();
|
||||||
|
} else
|
||||||
|
_cs = CoordinateSystem::XY;
|
||||||
|
|
||||||
|
_getMapUrl = ctx.url.isEmpty() ? _setup.url() : ctx.url;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WMS::getCapabilities(const QString &url, const QString &file,
|
bool WMS::downloadCapabilities(const QString &url)
|
||||||
const Authorization &authorization)
|
|
||||||
{
|
{
|
||||||
Downloader d;
|
if (!_downloader) {
|
||||||
QList<Download> dl;
|
_downloader = new Downloader(this);
|
||||||
|
connect(_downloader, SIGNAL(finished()), this,
|
||||||
dl.append(Download(url, file));
|
SLOT(capabilitiesReady()));
|
||||||
|
|
||||||
QEventLoop wait;
|
|
||||||
QObject::connect(&d, SIGNAL(finished()), &wait, SLOT(quit()));
|
|
||||||
if (d.get(dl, authorization))
|
|
||||||
wait.exec();
|
|
||||||
|
|
||||||
if (!QFileInfo(file).exists()) {
|
|
||||||
_errorString = "Error downloading capabilities XML file";
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
QList<Download> dl;
|
||||||
|
dl.append(Download(url, _path));
|
||||||
|
|
||||||
|
return _downloader->get(dl, _setup.authorization());
|
||||||
}
|
}
|
||||||
|
|
||||||
WMS::WMS(const QString &file, const WMS::Setup &setup) : _valid(false)
|
void WMS::capabilitiesReady()
|
||||||
{
|
{
|
||||||
QString capaUrl = QString("%1%2service=WMS&request=GetCapabilities")
|
if (!QFileInfo(_path).exists()) {
|
||||||
|
_errorString = "Error downloading capabilities XML file";
|
||||||
|
_valid = false;
|
||||||
|
} else {
|
||||||
|
_ready = true;
|
||||||
|
_valid = parseCapabilities();
|
||||||
|
}
|
||||||
|
|
||||||
|
emit downloadFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
WMS::WMS(const QString &file, const WMS::Setup &setup, QObject *parent)
|
||||||
|
: QObject(parent), _setup(setup), _path(file), _downloader(0), _valid(false),
|
||||||
|
_ready(false)
|
||||||
|
{
|
||||||
|
QString url = QString("%1%2service=WMS&request=GetCapabilities")
|
||||||
.arg(setup.url(), setup.url().contains('?') ? "&" : "?");
|
.arg(setup.url(), setup.url().contains('?') ? "&" : "?");
|
||||||
|
|
||||||
if (!QFileInfo(file).exists())
|
if (!QFileInfo(file).exists())
|
||||||
if (!getCapabilities(capaUrl, file, setup.authorization()))
|
_valid = downloadCapabilities(url);
|
||||||
return;
|
else {
|
||||||
if (!parseCapabilities(file, setup))
|
_ready = true;
|
||||||
return;
|
_valid = parseCapabilities();
|
||||||
|
}
|
||||||
_valid = true;
|
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,10 @@
|
|||||||
|
|
||||||
class QXmlStreamReader;
|
class QXmlStreamReader;
|
||||||
|
|
||||||
class WMS
|
class WMS : public QObject
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class Setup
|
class Setup
|
||||||
{
|
{
|
||||||
@ -48,16 +50,26 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
WMS(const QString &path, const Setup &setup);
|
WMS(const QString &path, const Setup &setup, QObject *parent = 0);
|
||||||
|
|
||||||
|
const RectC &bbox() const {return _bbox;}
|
||||||
const Projection &projection() const {return _projection;}
|
const Projection &projection() const {return _projection;}
|
||||||
|
CoordinateSystem cs() const {return _cs;}
|
||||||
const RangeF &scaleDenominator() const {return _scaleDenominator;}
|
const RangeF &scaleDenominator() const {return _scaleDenominator;}
|
||||||
const RectC &boundingBox() const {return _boundingBox;}
|
|
||||||
const QString &version() const {return _version;}
|
const QString &version() const {return _version;}
|
||||||
|
const QString &getMapUrl() const {return _getMapUrl;}
|
||||||
|
const WMS::Setup &setup() const {return _setup;}
|
||||||
|
|
||||||
|
bool isReady() const {return _valid && _ready;}
|
||||||
bool isValid() const {return _valid;}
|
bool isValid() const {return _valid;}
|
||||||
const QString &errorString() const {return _errorString;}
|
const QString &errorString() const {return _errorString;}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void downloadFinished();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void capabilitiesReady();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Layer {
|
struct Layer {
|
||||||
QString name;
|
QString name;
|
||||||
@ -79,12 +91,16 @@ private:
|
|||||||
const Setup &setup;
|
const Setup &setup;
|
||||||
QList<Layer> layers;
|
QList<Layer> layers;
|
||||||
bool formatSupported;
|
bool formatSupported;
|
||||||
|
QString url;
|
||||||
|
|
||||||
CTX(const Setup &setup);
|
CTX(const Setup &setup);
|
||||||
};
|
};
|
||||||
|
|
||||||
RectC geographicBoundingBox(QXmlStreamReader &reader);
|
RectC geographicBoundingBox(QXmlStreamReader &reader);
|
||||||
QString style(QXmlStreamReader &reader);
|
QString style(QXmlStreamReader &reader);
|
||||||
|
void get(QXmlStreamReader &reader, CTX &ctx);
|
||||||
|
void http(QXmlStreamReader &reader, CTX &ctx);
|
||||||
|
void dcpType(QXmlStreamReader &reader, CTX &ctx);
|
||||||
void getMap(QXmlStreamReader &reader, CTX &ctx);
|
void getMap(QXmlStreamReader &reader, CTX &ctx);
|
||||||
void request(QXmlStreamReader &reader, CTX &ctx);
|
void request(QXmlStreamReader &reader, CTX &ctx);
|
||||||
void layer(QXmlStreamReader &reader, CTX &ctx, const QList<QString> &pCRSs,
|
void layer(QXmlStreamReader &reader, CTX &ctx, const QList<QString> &pCRSs,
|
||||||
@ -92,19 +108,21 @@ private:
|
|||||||
RectC &pBoundingBox);
|
RectC &pBoundingBox);
|
||||||
void capability(QXmlStreamReader &reader, CTX &ctx);
|
void capability(QXmlStreamReader &reader, CTX &ctx);
|
||||||
void capabilities(QXmlStreamReader &reader, CTX &ctx);
|
void capabilities(QXmlStreamReader &reader, CTX &ctx);
|
||||||
bool parseCapabilities(const QString &path, const Setup &setup);
|
bool parseCapabilities();
|
||||||
bool getCapabilities(const QString &url, const QString &file,
|
bool downloadCapabilities(const QString &url);
|
||||||
const Authorization &authorization);
|
|
||||||
|
|
||||||
|
WMS::Setup _setup;
|
||||||
|
QString _path;
|
||||||
|
Downloader *_downloader;
|
||||||
Projection _projection;
|
Projection _projection;
|
||||||
RangeF _scaleDenominator;
|
RangeF _scaleDenominator;
|
||||||
RectC _boundingBox;
|
RectC _bbox;
|
||||||
QString _version;
|
QString _version;
|
||||||
|
QString _getMapUrl;
|
||||||
|
CoordinateSystem _cs;
|
||||||
|
|
||||||
bool _valid;
|
bool _valid, _ready;
|
||||||
QString _errorString;
|
QString _errorString;
|
||||||
|
|
||||||
static Downloader *_downloader;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // WMS_H
|
#endif // WMS_H
|
||||||
|
@ -10,114 +10,98 @@
|
|||||||
|
|
||||||
|
|
||||||
#define CAPABILITIES_FILE "capabilities.xml"
|
#define CAPABILITIES_FILE "capabilities.xml"
|
||||||
#define TILE_SIZE 256
|
|
||||||
#define EPSILON 1e-6
|
#define EPSILON 1e-6
|
||||||
|
|
||||||
double WMSMap::sd2res(double scaleDenominator) const
|
double WMSMap::sd2res(double scaleDenominator) const
|
||||||
{
|
{
|
||||||
return scaleDenominator * 0.28e-3 * _projection.units().fromMeters(1.0);
|
return scaleDenominator * _wms->projection().units().fromMeters(1.0)
|
||||||
|
* 0.28e-3;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString WMSMap::tileUrl(const QString &version) const
|
QString WMSMap::tileUrl() const
|
||||||
{
|
{
|
||||||
QString url;
|
const WMS::Setup &setup = _wms->setup();
|
||||||
|
|
||||||
url = QString("%1%2version=%3&request=GetMap&bbox=$bbox"
|
QString url = QString("%1%2service=WMS&version=%3&request=GetMap&bbox=$bbox"
|
||||||
"&width=%4&height=%5&layers=%6&styles=%7&format=%8&transparent=true")
|
"&width=%4&height=%5&layers=%6&styles=%7&format=%8&transparent=true")
|
||||||
.arg(_setup.url(), _setup.url().contains('?') ? "&" : "?", version,
|
.arg(_wms->getMapUrl(), _wms->getMapUrl().contains('?') ? "&" : "?",
|
||||||
QString::number(TILE_SIZE), QString::number(TILE_SIZE), _setup.layer(),
|
_wms->version(), QString::number(_tileSize), QString::number(_tileSize),
|
||||||
_setup.style(), _setup.format());
|
setup.layer(), setup.style(), setup.format());
|
||||||
|
|
||||||
if (version >= "1.3.0")
|
if (_wms->version() >= "1.3.0")
|
||||||
url.append(QString("&CRS=%1").arg(_setup.crs()));
|
url.append(QString("&CRS=%1").arg(setup.crs()));
|
||||||
else
|
else
|
||||||
url.append(QString("&SRS=%1").arg(_setup.crs()));
|
url.append(QString("&SRS=%1").arg(setup.crs()));
|
||||||
|
|
||||||
for (int i = 0; i < _setup.dimensions().size(); i++) {
|
for (int i = 0; i < setup.dimensions().size(); i++) {
|
||||||
const KV<QString, QString> &dim = _setup.dimensions().at(i);
|
const KV<QString, QString> &dim = setup.dimensions().at(i);
|
||||||
url.append(QString("&%1=%2").arg(dim.key(), dim.value()));
|
url.append(QString("&%1=%2").arg(dim.key(), dim.value()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString WMSMap::tilesDir() const
|
void WMSMap::computeZooms()
|
||||||
{
|
|
||||||
return QString(QDir(ProgramPaths::tilesDir()).filePath(_name));
|
|
||||||
}
|
|
||||||
|
|
||||||
void WMSMap::computeZooms(const RangeF &scaleDenominator)
|
|
||||||
{
|
{
|
||||||
_zooms.clear();
|
_zooms.clear();
|
||||||
|
|
||||||
if (scaleDenominator.size() > 0) {
|
const RangeF &sd = _wms->scaleDenominator();
|
||||||
double ld = log2(scaleDenominator.max() - EPSILON)
|
if (sd.size() > 0) {
|
||||||
- log2(scaleDenominator.min() + EPSILON);
|
double ld = log2(sd.max() - EPSILON) - log2(sd.min() + EPSILON);
|
||||||
int cld = (int)ceil(ld);
|
int cld = (int)ceil(ld);
|
||||||
double step = ld / (double)cld;
|
double step = ld / (double)cld;
|
||||||
double lmax = log2(scaleDenominator.max() - EPSILON);
|
double lmax = log2(sd.max() - EPSILON);
|
||||||
for (int i = 0; i <= cld; i++)
|
for (int i = 0; i <= cld; i++)
|
||||||
_zooms.append(pow(2.0, lmax - i * step));
|
_zooms.append(pow(2.0, lmax - i * step));
|
||||||
} else
|
} else
|
||||||
_zooms.append(scaleDenominator.min() + EPSILON);
|
_zooms.append(sd.min() + EPSILON);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WMSMap::updateTransform()
|
void WMSMap::updateTransform()
|
||||||
{
|
{
|
||||||
double pixelSpan = sd2res(_zooms.at(_zoom));
|
double pixelSpan = sd2res(_zooms.at(_zoom));
|
||||||
if (_projection.isGeographic())
|
if (_wms->projection().isGeographic())
|
||||||
pixelSpan /= deg2rad(WGS84_RADIUS);
|
pixelSpan /= deg2rad(WGS84_RADIUS);
|
||||||
_transform = Transform(ReferencePoint(PointD(0, 0),
|
_transform = Transform(ReferencePoint(PointD(0, 0),
|
||||||
_projection.ll2xy(_bbox.topLeft())), PointD(pixelSpan, pixelSpan));
|
_wms->projection().ll2xy(_wms->bbox().topLeft())),
|
||||||
|
PointD(pixelSpan, pixelSpan));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WMSMap::loadWMS()
|
WMSMap::WMSMap(const QString &name, const WMS::Setup &setup, int tileSize,
|
||||||
|
QObject *parent) : Map(parent), _name(name), _tileLoader(0), _zoom(0),
|
||||||
|
_tileSize(tileSize), _mapRatio(1.0)
|
||||||
{
|
{
|
||||||
QString file = tilesDir() + "/" + CAPABILITIES_FILE;
|
QString tilesDir(QDir(ProgramPaths::tilesDir()).filePath(_name));
|
||||||
|
|
||||||
WMS wms(file, _setup);
|
_tileLoader = new TileLoader(tilesDir, this);
|
||||||
if (!wms.isValid()) {
|
_tileLoader->setAuthorization(setup.authorization());
|
||||||
_errorString = wms.errorString();
|
connect(_tileLoader, SIGNAL(finished()), this, SIGNAL(tilesLoaded()));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_projection = wms.projection();
|
_wms = new WMS(QDir(tilesDir).filePath(CAPABILITIES_FILE), setup, this);
|
||||||
_bbox = wms.boundingBox();
|
connect(_wms, SIGNAL(downloadFinished()), this, SLOT(wmsReady()));
|
||||||
_bounds = RectD(_bbox, _projection);
|
if (_wms->isReady())
|
||||||
_tileLoader->setUrl(tileUrl(wms.version()));
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
if (wms.version() >= "1.3.0") {
|
void WMSMap::init()
|
||||||
if (_setup.coordinateSystem().axisOrder() == CoordinateSystem::Unknown)
|
{
|
||||||
_cs = _projection.coordinateSystem();
|
_tileLoader->setUrl(tileUrl());
|
||||||
else
|
_bounds = RectD(_wms->bbox(), _wms->projection());
|
||||||
_cs = _setup.coordinateSystem();
|
computeZooms();
|
||||||
} else
|
|
||||||
_cs = CoordinateSystem::XY;
|
|
||||||
|
|
||||||
computeZooms(wms.scaleDenominator());
|
|
||||||
updateTransform();
|
updateTransform();
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WMSMap::WMSMap(const QString &name, const WMS::Setup &setup, QObject *parent)
|
void WMSMap::wmsReady()
|
||||||
: Map(parent), _name(name), _setup(setup), _tileLoader(0), _zoom(0),
|
|
||||||
_mapRatio(1.0), _valid(false)
|
|
||||||
{
|
{
|
||||||
_tileLoader = new TileLoader(tilesDir(), this);
|
if (_wms->isValid())
|
||||||
_tileLoader->setAuthorization(_setup.authorization());
|
init();
|
||||||
connect(_tileLoader, SIGNAL(finished()), this, SIGNAL(loaded()));
|
|
||||||
|
|
||||||
_valid = loadWMS();
|
emit mapLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WMSMap::clearCache()
|
void WMSMap::clearCache()
|
||||||
{
|
{
|
||||||
_tileLoader->clearCache();
|
_tileLoader->clearCache();
|
||||||
_zoom = 0;
|
|
||||||
|
|
||||||
if (!loadWMS())
|
|
||||||
qWarning("%s: %s", qPrintable(_name), qPrintable(_errorString));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QRectF WMSMap::bounds()
|
QRectF WMSMap::bounds()
|
||||||
@ -129,10 +113,10 @@ QRectF WMSMap::bounds()
|
|||||||
int WMSMap::zoomFit(const QSize &size, const RectC &rect)
|
int WMSMap::zoomFit(const QSize &size, const RectC &rect)
|
||||||
{
|
{
|
||||||
if (rect.isValid()) {
|
if (rect.isValid()) {
|
||||||
RectD prect(rect, _projection);
|
RectD prect(rect, _wms->projection());
|
||||||
PointD sc(prect.width() / size.width(), prect.height() / size.height());
|
PointD sc(prect.width() / size.width(), prect.height() / size.height());
|
||||||
double resolution = qMax(qAbs(sc.x()), qAbs(sc.y()));
|
double resolution = qMax(qAbs(sc.x()), qAbs(sc.y()));
|
||||||
if (_projection.isGeographic())
|
if (_wms->projection().isGeographic())
|
||||||
resolution *= deg2rad(WGS84_RADIUS);
|
resolution *= deg2rad(WGS84_RADIUS);
|
||||||
|
|
||||||
_zoom = 0;
|
_zoom = 0;
|
||||||
@ -170,17 +154,17 @@ int WMSMap::zoomOut()
|
|||||||
|
|
||||||
QPointF WMSMap::ll2xy(const Coordinates &c)
|
QPointF WMSMap::ll2xy(const Coordinates &c)
|
||||||
{
|
{
|
||||||
return _transform.proj2img(_projection.ll2xy(c)) / _mapRatio;
|
return _transform.proj2img(_wms->projection().ll2xy(c)) / _mapRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
Coordinates WMSMap::xy2ll(const QPointF &p)
|
Coordinates WMSMap::xy2ll(const QPointF &p)
|
||||||
{
|
{
|
||||||
return _projection.xy2ll(_transform.img2proj(p * _mapRatio));
|
return _wms->projection().xy2ll(_transform.img2proj(p * _mapRatio));
|
||||||
}
|
}
|
||||||
|
|
||||||
qreal WMSMap::tileSize() const
|
qreal WMSMap::tileSize() const
|
||||||
{
|
{
|
||||||
return (TILE_SIZE / _mapRatio);
|
return (_tileSize / _mapRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WMSMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
void WMSMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||||
@ -194,11 +178,11 @@ void WMSMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
|||||||
tiles.reserve((br.x() - tl.x()) * (br.y() - tl.y()));
|
tiles.reserve((br.x() - tl.x()) * (br.y() - tl.y()));
|
||||||
for (int i = tl.x(); i < br.x(); i++) {
|
for (int i = tl.x(); i < br.x(); i++) {
|
||||||
for (int j = tl.y(); j < br.y(); j++) {
|
for (int j = tl.y(); j < br.y(); j++) {
|
||||||
PointD ttl(_transform.img2proj(QPointF(i * TILE_SIZE,
|
PointD ttl(_transform.img2proj(QPointF(i * _tileSize,
|
||||||
j * TILE_SIZE)));
|
j * _tileSize)));
|
||||||
PointD tbr(_transform.img2proj(QPointF(i * TILE_SIZE + TILE_SIZE,
|
PointD tbr(_transform.img2proj(QPointF(i * _tileSize + _tileSize,
|
||||||
j * TILE_SIZE + TILE_SIZE)));
|
j * _tileSize + _tileSize)));
|
||||||
RectD bbox = (_cs.axisOrder() == CoordinateSystem::YX)
|
RectD bbox = (_wms->cs().axisOrder() == CoordinateSystem::YX)
|
||||||
? RectD(PointD(tbr.y(), tbr.x()), PointD(ttl.y(), ttl.x()))
|
? RectD(PointD(tbr.y(), tbr.x()), PointD(ttl.y(), ttl.x()))
|
||||||
: RectD(ttl, tbr);
|
: RectD(ttl, tbr);
|
||||||
|
|
||||||
|
@ -14,7 +14,8 @@ class WMSMap : public Map
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
WMSMap(const QString &name, const WMS::Setup &setup, QObject *parent = 0);
|
WMSMap(const QString &name, const WMS::Setup &setup, int tileSize,
|
||||||
|
QObject *parent = 0);
|
||||||
|
|
||||||
QString name() const {return _name;}
|
QString name() const {return _name;}
|
||||||
|
|
||||||
@ -35,33 +36,30 @@ public:
|
|||||||
{_mapRatio = mapRatio;}
|
{_mapRatio = mapRatio;}
|
||||||
void clearCache();
|
void clearCache();
|
||||||
|
|
||||||
bool isValid() const {return _valid;}
|
bool isReady() const {return _wms->isReady();}
|
||||||
QString errorString() const {return _errorString;}
|
bool isValid() const {return _wms->isValid();}
|
||||||
|
QString errorString() const {return _wms->errorString();}
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void wmsReady();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString tileUrl(const QString &version) const;
|
QString tileUrl() const;
|
||||||
double sd2res(double scaleDenominator) const;
|
double sd2res(double scaleDenominator) const;
|
||||||
QString tilesDir() const;
|
void computeZooms();
|
||||||
void computeZooms(const RangeF &scaleDenominator);
|
|
||||||
void updateTransform();
|
void updateTransform();
|
||||||
bool loadWMS();
|
|
||||||
qreal tileSize() const;
|
qreal tileSize() const;
|
||||||
|
void init();
|
||||||
|
|
||||||
QString _name;
|
QString _name;
|
||||||
|
WMS *_wms;
|
||||||
WMS::Setup _setup;
|
|
||||||
TileLoader *_tileLoader;
|
TileLoader *_tileLoader;
|
||||||
Projection _projection;
|
|
||||||
Transform _transform;
|
|
||||||
CoordinateSystem _cs;
|
|
||||||
QVector<double> _zooms;
|
|
||||||
RectC _bbox;
|
|
||||||
RectD _bounds;
|
RectD _bounds;
|
||||||
|
Transform _transform;
|
||||||
|
QVector<double> _zooms;
|
||||||
int _zoom;
|
int _zoom;
|
||||||
|
int _tileSize;
|
||||||
qreal _mapRatio;
|
qreal _mapRatio;
|
||||||
|
|
||||||
bool _valid;
|
|
||||||
QString _errorString;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // WMSMAP_H
|
#endif // WMSMAP_H
|
||||||
|
134
src/map/wmts.cpp
134
src/map/wmts.cpp
@ -12,6 +12,11 @@
|
|||||||
#include "wmts.h"
|
#include "wmts.h"
|
||||||
|
|
||||||
|
|
||||||
|
static QString bareFormat(const QString &format)
|
||||||
|
{
|
||||||
|
return format.left(format.indexOf(';')).trimmed();
|
||||||
|
}
|
||||||
|
|
||||||
static void skipParentElement(QXmlStreamReader &reader)
|
static void skipParentElement(QXmlStreamReader &reader)
|
||||||
{
|
{
|
||||||
while (reader.readNextStartElement())
|
while (reader.readNextStartElement())
|
||||||
@ -53,7 +58,7 @@ void WMTS::tileMatrixSet(QXmlStreamReader &reader, CTX &ctx)
|
|||||||
{
|
{
|
||||||
while (reader.readNextStartElement()) {
|
while (reader.readNextStartElement()) {
|
||||||
if (reader.name() == "Identifier") {
|
if (reader.name() == "Identifier") {
|
||||||
if (reader.readElementText() != ctx.setup.set()) {
|
if (reader.readElementText() != _setup.set()) {
|
||||||
skipParentElement(reader);
|
skipParentElement(reader);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -109,7 +114,7 @@ void WMTS::tileMatrixSetLink(QXmlStreamReader &reader, CTX &ctx)
|
|||||||
{
|
{
|
||||||
while (reader.readNextStartElement()) {
|
while (reader.readNextStartElement()) {
|
||||||
if (reader.name() == "TileMatrixSet") {
|
if (reader.name() == "TileMatrixSet") {
|
||||||
if (reader.readElementText() == ctx.setup.set())
|
if (reader.readElementText() == _setup.set())
|
||||||
ctx.hasSet = true;
|
ctx.hasSet = true;
|
||||||
else {
|
else {
|
||||||
skipParentElement(reader);
|
skipParentElement(reader);
|
||||||
@ -158,7 +163,7 @@ void WMTS::layer(QXmlStreamReader &reader, CTX &ctx)
|
|||||||
{
|
{
|
||||||
while (reader.readNextStartElement()) {
|
while (reader.readNextStartElement()) {
|
||||||
if (reader.name() == "Identifier") {
|
if (reader.name() == "Identifier") {
|
||||||
if (reader.readElementText() == ctx.setup.layer())
|
if (reader.readElementText() == _setup.layer())
|
||||||
ctx.hasLayer = true;
|
ctx.hasLayer = true;
|
||||||
else {
|
else {
|
||||||
skipParentElement(reader);
|
skipParentElement(reader);
|
||||||
@ -167,10 +172,10 @@ void WMTS::layer(QXmlStreamReader &reader, CTX &ctx)
|
|||||||
} else if (reader.name() == "TileMatrixSetLink")
|
} else if (reader.name() == "TileMatrixSetLink")
|
||||||
tileMatrixSetLink(reader, ctx);
|
tileMatrixSetLink(reader, ctx);
|
||||||
else if (reader.name() == "WGS84BoundingBox")
|
else if (reader.name() == "WGS84BoundingBox")
|
||||||
_bounds = wgs84BoundingBox(reader);
|
ctx.bbox = wgs84BoundingBox(reader);
|
||||||
else if (reader.name() == "ResourceURL") {
|
else if (reader.name() == "ResourceURL") {
|
||||||
const QXmlStreamAttributes &attr = reader.attributes();
|
const QXmlStreamAttributes &attr = reader.attributes();
|
||||||
if (attr.value("resourceType") == "tile" && ctx.setup.rest())
|
if (attr.value("resourceType") == "tile" && _setup.rest())
|
||||||
_tileUrl = attr.value("template").toString();
|
_tileUrl = attr.value("template").toString();
|
||||||
reader.skipCurrentElement();
|
reader.skipCurrentElement();
|
||||||
} else if (reader.name() == "Style") {
|
} else if (reader.name() == "Style") {
|
||||||
@ -179,10 +184,11 @@ void WMTS::layer(QXmlStreamReader &reader, CTX &ctx)
|
|||||||
QString s = style(reader);
|
QString s = style(reader);
|
||||||
if (isDefault)
|
if (isDefault)
|
||||||
ctx.defaultStyle = s;
|
ctx.defaultStyle = s;
|
||||||
if (s == ctx.setup.style())
|
if (s == _setup.style())
|
||||||
ctx.hasStyle = true;
|
ctx.hasStyle = true;
|
||||||
} else if (reader.name() == "Format") {
|
} else if (reader.name() == "Format") {
|
||||||
if (reader.readElementText() == ctx.setup.format())
|
QString format(reader.readElementText());
|
||||||
|
if (bareFormat(format) == bareFormat(_setup.format()))
|
||||||
ctx.hasFormat = true;
|
ctx.hasFormat = true;
|
||||||
} else
|
} else
|
||||||
reader.skipCurrentElement();
|
reader.skipCurrentElement();
|
||||||
@ -226,9 +232,9 @@ void WMTS::createZooms(const CTX &ctx)
|
|||||||
qSort(_zooms);
|
qSort(_zooms);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WMTS::parseCapabilities(const QString &path, CTX &ctx)
|
bool WMTS::parseCapabilities(CTX &ctx)
|
||||||
{
|
{
|
||||||
QFile file(path);
|
QFile file(_path);
|
||||||
QXmlStreamReader reader;
|
QXmlStreamReader reader;
|
||||||
|
|
||||||
if (!file.open(QFile::ReadOnly | QFile::Text)) {
|
if (!file.open(QFile::ReadOnly | QFile::Text)) {
|
||||||
@ -244,30 +250,30 @@ bool WMTS::parseCapabilities(const QString &path, CTX &ctx)
|
|||||||
reader.raiseError("Not a Capabilities XML file");
|
reader.raiseError("Not a Capabilities XML file");
|
||||||
}
|
}
|
||||||
if (reader.error()) {
|
if (reader.error()) {
|
||||||
_errorString = QString("%1:%2: %3").arg(path).arg(reader.lineNumber())
|
_errorString = QString("%1:%2: %3").arg(_path).arg(reader.lineNumber())
|
||||||
.arg(reader.errorString());
|
.arg(reader.errorString());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ctx.hasLayer) {
|
if (!ctx.hasLayer) {
|
||||||
_errorString = ctx.setup.layer() + ": layer not provided";
|
_errorString = _setup.layer() + ": layer not provided";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!ctx.hasStyle && !ctx.setup.style().isEmpty()) {
|
if (!ctx.hasStyle && !_setup.style().isEmpty()) {
|
||||||
_errorString = ctx.setup.style() + ": style not provided";
|
_errorString = _setup.style() + ": style not provided";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!ctx.hasStyle && ctx.setup.style().isEmpty()
|
if (!ctx.hasStyle && _setup.style().isEmpty()
|
||||||
&& ctx.defaultStyle.isEmpty()) {
|
&& ctx.defaultStyle.isEmpty()) {
|
||||||
_errorString = "Default style not provided";
|
_errorString = "Default style not provided";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!ctx.setup.rest() && !ctx.hasFormat) {
|
if (!_setup.rest() && !ctx.hasFormat) {
|
||||||
_errorString = ctx.setup.format() + ": format not provided";
|
_errorString = _setup.format() + ": format not provided";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!ctx.hasSet) {
|
if (!ctx.hasSet) {
|
||||||
_errorString = ctx.setup.set() + ": set not provided";
|
_errorString = _setup.set() + ": set not provided";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (ctx.crs.isNull()) {
|
if (ctx.crs.isNull()) {
|
||||||
@ -284,74 +290,92 @@ bool WMTS::parseCapabilities(const QString &path, CTX &ctx)
|
|||||||
_errorString = "No usable tile matrix found";
|
_errorString = "No usable tile matrix found";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (ctx.setup.rest() && _tileUrl.isNull()) {
|
if (_setup.rest() && _tileUrl.isNull()) {
|
||||||
_errorString = "Missing tile URL template";
|
_errorString = "Missing tile URL template";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
_bbox = ctx.bbox;
|
||||||
|
_cs = (_setup.coordinateSystem().axisOrder() == CoordinateSystem::Unknown)
|
||||||
|
? _projection.coordinateSystem() : _setup.coordinateSystem();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WMTS::downloadCapabilities(const QString &url, const QString &file,
|
bool WMTS::downloadCapabilities(const QString &url)
|
||||||
const Authorization &authorization)
|
|
||||||
{
|
{
|
||||||
Downloader d;
|
if (!_downloader) {
|
||||||
QList<Download> dl;
|
_downloader = new Downloader(this);
|
||||||
|
connect(_downloader, SIGNAL(finished()), this,
|
||||||
dl.append(Download(url, file));
|
SLOT(capabilitiesReady()));
|
||||||
|
|
||||||
QEventLoop wait;
|
|
||||||
QObject::connect(&d, SIGNAL(finished()), &wait, SLOT(quit()));
|
|
||||||
if (d.get(dl, authorization))
|
|
||||||
wait.exec();
|
|
||||||
|
|
||||||
if (!QFileInfo(file).exists()) {
|
|
||||||
_errorString = "Error downloading capabilities XML file";
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
QList<Download> dl;
|
||||||
|
dl.append(Download(url, _path));
|
||||||
|
|
||||||
|
return _downloader->get(dl, _setup.authorization());
|
||||||
}
|
}
|
||||||
|
|
||||||
WMTS::WMTS(const QString &file, const WMTS::Setup &setup) : _valid(false)
|
void WMTS::capabilitiesReady()
|
||||||
{
|
{
|
||||||
QUrl url(setup.rest() ? setup.url() : QString(
|
if (!QFileInfo(_path).exists()) {
|
||||||
"%1%2service=WMTS&Version=1.0.0&request=GetCapabilities").arg(setup.url(),
|
_errorString = "Error downloading capabilities XML file";
|
||||||
setup.url().contains('?') ? "&" : "?"));
|
_valid = false;
|
||||||
|
} else {
|
||||||
|
_ready = true;
|
||||||
|
_valid = init();
|
||||||
|
}
|
||||||
|
|
||||||
if (!url.isLocalFile() && !QFileInfo(file).exists())
|
emit downloadFinished();
|
||||||
if (!downloadCapabilities(url.toString(), file, setup.authorization()))
|
}
|
||||||
return;
|
|
||||||
|
|
||||||
CTX ctx(setup);
|
bool WMTS::init()
|
||||||
if (!parseCapabilities(url.isLocalFile() ? url.toLocalFile() : file, ctx))
|
{
|
||||||
return;
|
CTX ctx;
|
||||||
|
if (!parseCapabilities(ctx))
|
||||||
|
return false;
|
||||||
|
|
||||||
QString style = setup.style().isEmpty() ? ctx.defaultStyle : setup.style();
|
QString style = _setup.style().isEmpty() ? ctx.defaultStyle : _setup.style();
|
||||||
if (!setup.rest()) {
|
if (!_setup.rest()) {
|
||||||
_tileUrl = QString("%1%2service=WMTS&Version=1.0.0&request=GetTile"
|
_tileUrl = QString("%1%2service=WMTS&Version=1.0.0&request=GetTile"
|
||||||
"&Format=%3&Layer=%4&Style=%5&TileMatrixSet=%6&TileMatrix=$z"
|
"&Format=%3&Layer=%4&Style=%5&TileMatrixSet=%6&TileMatrix=$z"
|
||||||
"&TileRow=$y&TileCol=$x").arg(setup.url(),
|
"&TileRow=$y&TileCol=$x").arg(_setup.url(),
|
||||||
setup.url().contains('?') ? "&" : "?" , setup.format(),
|
_setup.url().contains('?') ? "&" : "?" , _setup.format(),
|
||||||
setup.layer(), style, setup.set());
|
_setup.layer(), style, _setup.set());
|
||||||
for (int i = 0; i < setup.dimensions().size(); i++) {
|
for (int i = 0; i < _setup.dimensions().size(); i++) {
|
||||||
const KV<QString, QString> &dim = setup.dimensions().at(i);
|
const KV<QString, QString> &dim = _setup.dimensions().at(i);
|
||||||
_tileUrl.append(QString("&%1=%2").arg(dim.key(), dim.value()));
|
_tileUrl.append(QString("&%1=%2").arg(dim.key(), dim.value()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_tileUrl.replace("{Style}", style, Qt::CaseInsensitive);
|
_tileUrl.replace("{Style}", style, Qt::CaseInsensitive);
|
||||||
_tileUrl.replace("{TileMatrixSet}", setup.set(), Qt::CaseInsensitive);
|
_tileUrl.replace("{TileMatrixSet}", _setup.set(), Qt::CaseInsensitive);
|
||||||
_tileUrl.replace("{TileMatrix}", "$z", Qt::CaseInsensitive);
|
_tileUrl.replace("{TileMatrix}", "$z", Qt::CaseInsensitive);
|
||||||
_tileUrl.replace("{TileRow}", "$y", Qt::CaseInsensitive);
|
_tileUrl.replace("{TileRow}", "$y", Qt::CaseInsensitive);
|
||||||
_tileUrl.replace("{TileCol}", "$x", Qt::CaseInsensitive);
|
_tileUrl.replace("{TileCol}", "$x", Qt::CaseInsensitive);
|
||||||
for (int i = 0; i < setup.dimensions().size(); i++) {
|
for (int i = 0; i < _setup.dimensions().size(); i++) {
|
||||||
const KV<QString, QString> &dim = setup.dimensions().at(i);
|
const KV<QString, QString> &dim = _setup.dimensions().at(i);
|
||||||
_tileUrl.replace(QString("{%1}").arg(dim.key()), dim.value(),
|
_tileUrl.replace(QString("{%1}").arg(dim.key()), dim.value(),
|
||||||
Qt::CaseInsensitive);
|
Qt::CaseInsensitive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_valid = true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
WMTS::WMTS(const QString &file, const WMTS::Setup &setup, QObject *parent)
|
||||||
|
: QObject(parent), _setup(setup), _downloader(0), _valid(false), _ready(false)
|
||||||
|
{
|
||||||
|
QUrl url(setup.rest() ? setup.url() : QString(
|
||||||
|
"%1%2service=WMTS&Version=1.0.0&request=GetCapabilities").arg(setup.url(),
|
||||||
|
setup.url().contains('?') ? "&" : "?"));
|
||||||
|
|
||||||
|
_path = url.isLocalFile() ? url.toLocalFile() : file;
|
||||||
|
|
||||||
|
if (!url.isLocalFile() && !QFileInfo(file).exists())
|
||||||
|
_valid = downloadCapabilities(url.toString());
|
||||||
|
else {
|
||||||
|
_ready = true;
|
||||||
|
_valid = init();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef QT_NO_DEBUG
|
#ifndef QT_NO_DEBUG
|
||||||
|
@ -14,8 +14,10 @@
|
|||||||
|
|
||||||
class QXmlStreamReader;
|
class QXmlStreamReader;
|
||||||
|
|
||||||
class WMTS
|
class WMTS : public QObject
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class Setup
|
class Setup
|
||||||
{
|
{
|
||||||
@ -79,16 +81,24 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
WMTS(const QString &path, const Setup &setup);
|
WMTS(const QString &path, const Setup &setup, QObject *parent = 0);
|
||||||
|
|
||||||
const RectC &bounds() const {return _bounds;}
|
const RectC &bbox() const {return _bbox;}
|
||||||
const QList<Zoom> &zooms() const {return _zooms;}
|
const QList<Zoom> &zooms() const {return _zooms;}
|
||||||
const Projection &projection() const {return _projection;}
|
const Projection &projection() const {return _projection;}
|
||||||
const QString &tileUrl() const {return _tileUrl;}
|
const QString &tileUrl() const {return _tileUrl;}
|
||||||
|
CoordinateSystem cs() const {return _cs;}
|
||||||
|
|
||||||
|
bool isReady() const {return _valid && _ready;}
|
||||||
bool isValid() const {return _valid;}
|
bool isValid() const {return _valid;}
|
||||||
const QString &errorString() const {return _errorString;}
|
const QString &errorString() const {return _errorString;}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void downloadFinished();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void capabilitiesReady();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct TileMatrix {
|
struct TileMatrix {
|
||||||
QString id;
|
QString id;
|
||||||
@ -118,18 +128,18 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct CTX {
|
struct CTX {
|
||||||
const Setup &setup;
|
|
||||||
QSet<TileMatrix> matrixes;
|
QSet<TileMatrix> matrixes;
|
||||||
QSet<MatrixLimits> limits;
|
QSet<MatrixLimits> limits;
|
||||||
QString crs;
|
QString crs;
|
||||||
QString defaultStyle;
|
QString defaultStyle;
|
||||||
|
RectC bbox;
|
||||||
bool hasLayer;
|
bool hasLayer;
|
||||||
bool hasStyle;
|
bool hasStyle;
|
||||||
bool hasFormat;
|
bool hasFormat;
|
||||||
bool hasSet;
|
bool hasSet;
|
||||||
|
|
||||||
CTX(const Setup &setup) : setup(setup), hasLayer(false), hasStyle(false),
|
CTX() : hasLayer(false), hasStyle(false), hasFormat(false), hasSet(false)
|
||||||
hasFormat(false), hasSet(false) {}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
RectC wgs84BoundingBox(QXmlStreamReader &reader);
|
RectC wgs84BoundingBox(QXmlStreamReader &reader);
|
||||||
@ -142,17 +152,21 @@ private:
|
|||||||
void layer(QXmlStreamReader &reader, CTX &ctx);
|
void layer(QXmlStreamReader &reader, CTX &ctx);
|
||||||
void contents(QXmlStreamReader &reader, CTX &ctx);
|
void contents(QXmlStreamReader &reader, CTX &ctx);
|
||||||
void capabilities(QXmlStreamReader &reader, CTX &ctx);
|
void capabilities(QXmlStreamReader &reader, CTX &ctx);
|
||||||
bool parseCapabilities(const QString &path, CTX &ctx);
|
bool parseCapabilities(CTX &ctx);
|
||||||
bool downloadCapabilities(const QString &url, const QString &file,
|
bool downloadCapabilities(const QString &url);
|
||||||
const Authorization &authorization);
|
|
||||||
void createZooms(const CTX &ctx);
|
void createZooms(const CTX &ctx);
|
||||||
|
bool init();
|
||||||
|
|
||||||
|
WMTS::Setup _setup;
|
||||||
|
QString _path;
|
||||||
|
Downloader *_downloader;
|
||||||
|
RectC _bbox;
|
||||||
QList<Zoom> _zooms;
|
QList<Zoom> _zooms;
|
||||||
RectC _bounds;
|
|
||||||
Projection _projection;
|
Projection _projection;
|
||||||
QString _tileUrl;
|
QString _tileUrl;
|
||||||
|
CoordinateSystem _cs;
|
||||||
|
|
||||||
bool _valid;
|
bool _valid, _ready;
|
||||||
QString _errorString;
|
QString _errorString;
|
||||||
|
|
||||||
friend uint qHash(const WMTS::TileMatrix &key);
|
friend uint qHash(const WMTS::TileMatrix &key);
|
||||||
|
@ -12,70 +12,57 @@
|
|||||||
|
|
||||||
#define CAPABILITIES_FILE "capabilities.xml"
|
#define CAPABILITIES_FILE "capabilities.xml"
|
||||||
|
|
||||||
bool WMTSMap::loadWMTS()
|
WMTSMap::WMTSMap(const QString &name, const WMTS::Setup &setup, qreal tileRatio,
|
||||||
|
QObject *parent) : Map(parent), _name(name), _tileLoader(0), _zoom(0),
|
||||||
|
_mapRatio(1.0), _tileRatio(tileRatio)
|
||||||
{
|
{
|
||||||
QString file = tilesDir() + "/" + CAPABILITIES_FILE;
|
QString tilesDir(QDir(ProgramPaths::tilesDir()).filePath(_name));
|
||||||
|
|
||||||
WMTS wmts(file, _setup);
|
_tileLoader = new TileLoader(tilesDir, this);
|
||||||
if (!wmts.isValid()) {
|
_tileLoader->setAuthorization(setup.authorization());
|
||||||
_errorString = wmts.errorString();
|
connect(_tileLoader, SIGNAL(finished()), this, SIGNAL(tilesLoaded()));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_zooms = wmts.zooms();
|
_wmts = new WMTS(QDir(tilesDir).filePath(CAPABILITIES_FILE), setup, this);
|
||||||
_projection = wmts.projection();
|
connect(_wmts, SIGNAL(downloadFinished()), this, SLOT(wmtsReady()));
|
||||||
_tileLoader->setUrl(wmts.tileUrl());
|
if (_wmts->isReady())
|
||||||
_bounds = RectD(wmts.bounds(), _projection);
|
init();
|
||||||
|
|
||||||
if (_setup.coordinateSystem().axisOrder() == CoordinateSystem::Unknown)
|
|
||||||
_cs = _projection.coordinateSystem();
|
|
||||||
else
|
|
||||||
_cs = _setup.coordinateSystem();
|
|
||||||
|
|
||||||
updateTransform();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WMTSMap::WMTSMap(const QString &name, const WMTS::Setup &setup, qreal tileRatio,
|
void WMTSMap::init()
|
||||||
QObject *parent) : Map(parent), _name(name), _setup(setup), _tileLoader(0),
|
|
||||||
_zoom(0), _mapRatio(1.0), _tileRatio(tileRatio), _valid(false)
|
|
||||||
{
|
{
|
||||||
_tileLoader = new TileLoader(tilesDir(), this);
|
_tileLoader->setUrl(_wmts->tileUrl());
|
||||||
_tileLoader->setAuthorization(_setup.authorization());
|
_bounds = RectD(_wmts->bbox(), _wmts->projection());
|
||||||
connect(_tileLoader, SIGNAL(finished()), this, SIGNAL(loaded()));
|
updateTransform();
|
||||||
|
}
|
||||||
|
|
||||||
_valid = loadWMTS();
|
void WMTSMap::wmtsReady()
|
||||||
|
{
|
||||||
|
if (_wmts->isValid())
|
||||||
|
init();
|
||||||
|
|
||||||
|
emit mapLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WMTSMap::clearCache()
|
void WMTSMap::clearCache()
|
||||||
{
|
{
|
||||||
_tileLoader->clearCache();
|
_tileLoader->clearCache();
|
||||||
_zoom = 0;
|
|
||||||
|
|
||||||
if (!loadWMTS())
|
|
||||||
qWarning("%s: %s", qPrintable(_name), qPrintable(_errorString));
|
|
||||||
}
|
|
||||||
|
|
||||||
QString WMTSMap::tilesDir() const
|
|
||||||
{
|
|
||||||
return QString(QDir(ProgramPaths::tilesDir()).filePath(_name));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double WMTSMap::sd2res(double scaleDenominator) const
|
double WMTSMap::sd2res(double scaleDenominator) const
|
||||||
{
|
{
|
||||||
return scaleDenominator * 0.28e-3 * _projection.units().fromMeters(1.0);
|
return scaleDenominator * 0.28e-3
|
||||||
|
* _wmts->projection().units().fromMeters(1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WMTSMap::updateTransform()
|
void WMTSMap::updateTransform()
|
||||||
{
|
{
|
||||||
const WMTS::Zoom &z = _zooms.at(_zoom);
|
const WMTS::Zoom &z = _wmts->zooms().at(_zoom);
|
||||||
|
|
||||||
PointD topLeft = (_cs.axisOrder() == CoordinateSystem::YX)
|
PointD topLeft = (_wmts->cs().axisOrder() == CoordinateSystem::YX)
|
||||||
? PointD(z.topLeft().y(), z.topLeft().x()) : z.topLeft();
|
? PointD(z.topLeft().y(), z.topLeft().x()) : z.topLeft();
|
||||||
|
|
||||||
double pixelSpan = sd2res(z.scaleDenominator());
|
double pixelSpan = sd2res(z.scaleDenominator());
|
||||||
if (_projection.isGeographic())
|
if (_wmts->projection().isGeographic())
|
||||||
pixelSpan /= deg2rad(WGS84_RADIUS);
|
pixelSpan /= deg2rad(WGS84_RADIUS);
|
||||||
_transform = Transform(ReferencePoint(PointD(0, 0), topLeft),
|
_transform = Transform(ReferencePoint(PointD(0, 0), topLeft),
|
||||||
PointD(pixelSpan, pixelSpan));
|
PointD(pixelSpan, pixelSpan));
|
||||||
@ -83,7 +70,7 @@ void WMTSMap::updateTransform()
|
|||||||
|
|
||||||
QRectF WMTSMap::bounds()
|
QRectF WMTSMap::bounds()
|
||||||
{
|
{
|
||||||
const WMTS::Zoom &z = _zooms.at(_zoom);
|
const WMTS::Zoom &z = _wmts->zooms().at(_zoom);
|
||||||
QRectF tileBounds, bounds;
|
QRectF tileBounds, bounds;
|
||||||
|
|
||||||
tileBounds = (z.limits().isNull()) ?
|
tileBounds = (z.limits().isNull()) ?
|
||||||
@ -95,29 +82,29 @@ QRectF WMTSMap::bounds()
|
|||||||
|
|
||||||
if (_bounds.isValid())
|
if (_bounds.isValid())
|
||||||
bounds = QRectF(_transform.proj2img(_bounds.topLeft())
|
bounds = QRectF(_transform.proj2img(_bounds.topLeft())
|
||||||
/ coordinatesRatio(), _transform.proj2img(_bounds.bottomRight())
|
/ coordinatesRatio(), _transform.proj2img(
|
||||||
/ coordinatesRatio());
|
_bounds.bottomRight()) / coordinatesRatio());
|
||||||
return bounds.isValid() ? tileBounds.intersected(bounds) : tileBounds;
|
return bounds.isValid() ? tileBounds.intersected(bounds) : tileBounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
int WMTSMap::zoomFit(const QSize &size, const RectC &rect)
|
int WMTSMap::zoomFit(const QSize &size, const RectC &rect)
|
||||||
{
|
{
|
||||||
if (rect.isValid()) {
|
if (rect.isValid()) {
|
||||||
RectD prect(rect, _projection);
|
RectD prect(rect, _wmts->projection());
|
||||||
PointD sc(prect.width() / size.width(), prect.height() / size.height());
|
PointD sc(prect.width() / size.width(), prect.height() / size.height());
|
||||||
double resolution = qMax(qAbs(sc.x()), qAbs(sc.y()));
|
double resolution = qMax(qAbs(sc.x()), qAbs(sc.y()));
|
||||||
if (_projection.isGeographic())
|
if (_wmts->projection().isGeographic())
|
||||||
resolution *= deg2rad(WGS84_RADIUS);
|
resolution *= deg2rad(WGS84_RADIUS);
|
||||||
|
|
||||||
_zoom = 0;
|
_zoom = 0;
|
||||||
for (int i = 0; i < _zooms.size(); i++) {
|
for (int i = 0; i < _wmts->zooms().size(); i++) {
|
||||||
if (sd2res(_zooms.at(i).scaleDenominator()) < resolution
|
if (sd2res(_wmts->zooms().at(i).scaleDenominator()) < resolution
|
||||||
/ coordinatesRatio())
|
/ coordinatesRatio())
|
||||||
break;
|
break;
|
||||||
_zoom = i;
|
_zoom = i;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
_zoom = _zooms.size() - 1;
|
_zoom = _wmts->zooms().size() - 1;
|
||||||
|
|
||||||
updateTransform();
|
updateTransform();
|
||||||
return _zoom;
|
return _zoom;
|
||||||
@ -131,7 +118,7 @@ void WMTSMap::setZoom(int zoom)
|
|||||||
|
|
||||||
int WMTSMap::zoomIn()
|
int WMTSMap::zoomIn()
|
||||||
{
|
{
|
||||||
_zoom = qMin(_zoom + 1, _zooms.size() - 1);
|
_zoom = qMin(_zoom + 1, _wmts->zooms().size() - 1);
|
||||||
updateTransform();
|
updateTransform();
|
||||||
return _zoom;
|
return _zoom;
|
||||||
}
|
}
|
||||||
@ -161,7 +148,7 @@ QSizeF WMTSMap::tileSize(const WMTS::Zoom &zoom) const
|
|||||||
|
|
||||||
void WMTSMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
void WMTSMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
||||||
{
|
{
|
||||||
const WMTS::Zoom &z = _zooms.at(_zoom);
|
const WMTS::Zoom &z = _wmts->zooms().at(_zoom);
|
||||||
QSizeF ts(tileSize(z));
|
QSizeF ts(tileSize(z));
|
||||||
|
|
||||||
QPoint tl = QPoint(qFloor(rect.left() / ts.width()),
|
QPoint tl = QPoint(qFloor(rect.left() / ts.width()),
|
||||||
@ -194,10 +181,12 @@ void WMTSMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
|
|||||||
|
|
||||||
QPointF WMTSMap::ll2xy(const Coordinates &c)
|
QPointF WMTSMap::ll2xy(const Coordinates &c)
|
||||||
{
|
{
|
||||||
return _transform.proj2img(_projection.ll2xy(c)) / coordinatesRatio();
|
return _transform.proj2img(_wmts->projection().ll2xy(c))
|
||||||
|
/ coordinatesRatio();
|
||||||
}
|
}
|
||||||
|
|
||||||
Coordinates WMTSMap::xy2ll(const QPointF &p)
|
Coordinates WMTSMap::xy2ll(const QPointF &p)
|
||||||
{
|
{
|
||||||
return _projection.xy2ll(_transform.img2proj(p * coordinatesRatio()));
|
return _wmts->projection().xy2ll(_transform.img2proj(p
|
||||||
|
* coordinatesRatio()));
|
||||||
}
|
}
|
||||||
|
@ -36,31 +36,28 @@ public:
|
|||||||
{_mapRatio = mapRatio;}
|
{_mapRatio = mapRatio;}
|
||||||
void clearCache();
|
void clearCache();
|
||||||
|
|
||||||
bool isValid() const {return _valid;}
|
bool isReady() const {return _wmts->isReady();}
|
||||||
QString errorString() const {return _errorString;}
|
bool isValid() const {return _wmts->isValid();}
|
||||||
|
QString errorString() const {return _wmts->errorString();}
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void wmtsReady();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool loadWMTS();
|
|
||||||
double sd2res(double scaleDenominator) const;
|
double sd2res(double scaleDenominator) const;
|
||||||
QString tilesDir() const;
|
|
||||||
void updateTransform();
|
void updateTransform();
|
||||||
QSizeF tileSize(const WMTS::Zoom &zoom) const;
|
QSizeF tileSize(const WMTS::Zoom &zoom) const;
|
||||||
qreal coordinatesRatio() const;
|
qreal coordinatesRatio() const;
|
||||||
qreal imageRatio() const;
|
qreal imageRatio() const;
|
||||||
|
void init();
|
||||||
|
|
||||||
QString _name;
|
QString _name;
|
||||||
WMTS::Setup _setup;
|
WMTS *_wmts;
|
||||||
TileLoader *_tileLoader;
|
TileLoader *_tileLoader;
|
||||||
RectD _bounds;
|
|
||||||
QList<WMTS::Zoom> _zooms;
|
|
||||||
Projection _projection;
|
|
||||||
Transform _transform;
|
Transform _transform;
|
||||||
CoordinateSystem _cs;
|
RectD _bounds;
|
||||||
int _zoom;
|
int _zoom;
|
||||||
qreal _mapRatio, _tileRatio;
|
qreal _mapRatio, _tileRatio;
|
||||||
|
|
||||||
bool _valid;
|
|
||||||
QString _errorString;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // WMTSMAP_H
|
#endif // WMTSMAP_H
|
||||||
|
Reference in New Issue
Block a user