mirror of
https://github.com/tumic0/GPXSee.git
synced 2025-07-20 13:54:24 +02:00
Compare commits
44 Commits
Author | SHA1 | Date | |
---|---|---|---|
d3558198ca | |||
acc69f5c3d | |||
7a900f2252 | |||
dad76a4e89 | |||
e28e69b248 | |||
7fffd6a161 | |||
c4fd82e5a0 | |||
fa08c0dbea | |||
070eff2115 | |||
20a4870904 | |||
1bb9908936 | |||
36555b3140 | |||
6564fb36ab | |||
1a3356b8fe | |||
7ad64922c9 | |||
64a8ec1b84 | |||
0a75298b2b | |||
99be5699af | |||
cdb641b204 | |||
f57bd48840 | |||
c2abf2c146 | |||
a5a2070ccc | |||
ed7cb1beb1 | |||
37d832bc7f | |||
c322bf9f68 | |||
2705ffbbfe | |||
e8962dd50f | |||
b37e32d622 | |||
2b1d0d2189 | |||
33e3471ca3 | |||
bf55f1e07d | |||
37a0eec48f | |||
fcaacb4b6a | |||
f9c593e6d1 | |||
37e07accd4 | |||
a7117361be | |||
548c03d543 | |||
1addb1118d | |||
ae64ef9d83 | |||
3d16cf2500 | |||
609ac0c57a | |||
a70c6f0f24 | |||
3ad0c89511 | |||
1497d42bd5 |
@ -1,4 +1,4 @@
|
||||
version: 7.12.{build}
|
||||
version: 7.14.{build}
|
||||
configuration: Release
|
||||
platform: Any CPU
|
||||
environment:
|
||||
|
@ -2,7 +2,7 @@
|
||||
GPXSee is a Qt-based GPS log file viewer and analyzer that supports all common GPS log file formats.
|
||||
|
||||
## Features
|
||||
* Opens GPX, TCX, FIT, KML, IGC, NMEA, SLF, LOC, GeoJSON, OziExplorer (PLT, RTE, WPT), Garmin CSV and geotagged JPEG files.
|
||||
* Opens GPX, TCX, FIT, KML, NMEA, IGC, CUP, SLF, LOC, GeoJSON, OziExplorer (PLT, RTE, WPT), Garmin CSV and geotagged JPEG files.
|
||||
* User-definable online maps (OpenStreetMap/Google tiles, WMTS, WMS, TMS, QuadTiles).
|
||||
* Offline maps (MBTiles, OziExplorer maps, TrekBuddy maps/atlases, Garmin IMG & JNX maps, TwoNav RMaps, GeoTIFF images).
|
||||
* Elevation, speed, heart rate, cadence, power, temperature and gear ratio/shifts graphs.
|
||||
|
@ -3,7 +3,7 @@ unix:!macx {
|
||||
} else {
|
||||
TARGET = GPXSee
|
||||
}
|
||||
VERSION = 7.12
|
||||
VERSION = 7.14
|
||||
|
||||
QT += core \
|
||||
gui \
|
||||
|
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
1456
lang/gpxsee_en.ts
1456
lang/gpxsee_en.ts
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
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
1860
lang/gpxsee_pt_PT.ts
Normal file
1860
lang/gpxsee_pt_PT.ts
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,7 @@
|
||||
; The name of the installer
|
||||
Name "GPXSee"
|
||||
; Program version
|
||||
!define VERSION "7.12"
|
||||
!define VERSION "7.14"
|
||||
|
||||
; The file to write
|
||||
OutFile "GPXSee-${VERSION}.exe"
|
||||
|
@ -7,7 +7,7 @@
|
||||
; The name of the installer
|
||||
Name "GPXSee"
|
||||
; Program version
|
||||
!define VERSION "7.12"
|
||||
!define VERSION "7.14"
|
||||
|
||||
; The file to write
|
||||
OutFile "GPXSee-${VERSION}_x64.exe"
|
||||
|
@ -153,3 +153,21 @@ void AreaItem::setDigitalZoom(int zoom)
|
||||
_digitalZoom = zoom;
|
||||
_pen.setWidthF(_width * pow(2, -_digitalZoom));
|
||||
}
|
||||
|
||||
void AreaItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
_pen.setWidthF((_width + 1) * pow(2, -_digitalZoom));
|
||||
setZValue(zValue() + 1.0);
|
||||
update();
|
||||
}
|
||||
|
||||
void AreaItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
_pen.setWidthF(_width * pow(2, -_digitalZoom));
|
||||
setZValue(zValue() - 1.0);
|
||||
update();
|
||||
}
|
||||
|
@ -27,6 +27,9 @@ public:
|
||||
void setDigitalZoom(int zoom);
|
||||
|
||||
private:
|
||||
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
|
||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
|
||||
|
||||
QPainterPath painterPath(const Polygon &polygon);
|
||||
void updatePainterPath();
|
||||
QString toolTip() const;
|
||||
|
@ -30,7 +30,7 @@ private:
|
||||
Ticks::Ticks(double minValue, double maxValue, int maxCount)
|
||||
{
|
||||
double range = niceNum(maxValue - minValue, false);
|
||||
_d = niceNum(range / maxCount, true);
|
||||
_d = niceNum(range / maxCount, false);
|
||||
_min = ceil(minValue / _d) * _d;
|
||||
_max = floor(maxValue / _d) * _d;
|
||||
}
|
||||
|
@ -14,6 +14,11 @@ CadenceGraph::CadenceGraph(QWidget *parent) : GraphTab(parent)
|
||||
setSliderPrecision(1);
|
||||
}
|
||||
|
||||
CadenceGraph::~CadenceGraph()
|
||||
{
|
||||
qDeleteAll(_tracks);
|
||||
}
|
||||
|
||||
void CadenceGraph::setInfo()
|
||||
{
|
||||
if (_showTracks) {
|
||||
@ -36,23 +41,28 @@ QList<GraphItem*> CadenceGraph::loadData(const Data &data)
|
||||
const Graph &graph = track.cadence();
|
||||
|
||||
if (!graph.isValid()) {
|
||||
skipColor();
|
||||
_palette.nextColor();
|
||||
graphs.append(0);
|
||||
} else {
|
||||
CadenceGraphItem *gi = new CadenceGraphItem(graph, _graphType);
|
||||
GraphView::addGraph(gi);
|
||||
CadenceGraphItem *gi = new CadenceGraphItem(graph, _graphType,
|
||||
_width, _palette.nextColor());
|
||||
|
||||
_tracks.append(gi);
|
||||
if (_showTracks)
|
||||
addGraph(gi);
|
||||
|
||||
_avg.append(QPointF(track.distance(), gi->avg()));
|
||||
graphs.append(gi);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < data.routes().count(); i++) {
|
||||
skipColor();
|
||||
_palette.nextColor();
|
||||
graphs.append(0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < data.areas().count(); i++)
|
||||
skipColor();
|
||||
_palette.nextColor();
|
||||
|
||||
setInfo();
|
||||
redraw();
|
||||
@ -75,6 +85,9 @@ qreal CadenceGraph::avg() const
|
||||
|
||||
void CadenceGraph::clear()
|
||||
{
|
||||
qDeleteAll(_tracks);
|
||||
_tracks.clear();
|
||||
|
||||
_avg.clear();
|
||||
|
||||
GraphTab::clear();
|
||||
@ -84,7 +97,13 @@ void CadenceGraph::showTracks(bool show)
|
||||
{
|
||||
_showTracks = show;
|
||||
|
||||
showGraph(show);
|
||||
for (int i = 0; i < _tracks.size(); i++) {
|
||||
if (show)
|
||||
addGraph(_tracks.at(i));
|
||||
else
|
||||
removeGraph(_tracks.at(i));
|
||||
}
|
||||
|
||||
setInfo();
|
||||
|
||||
redraw();
|
||||
|
@ -3,18 +3,20 @@
|
||||
|
||||
#include "graphtab.h"
|
||||
|
||||
class CadenceGraphItem;
|
||||
|
||||
class CadenceGraph : public GraphTab
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CadenceGraph(QWidget *parent = 0);
|
||||
~CadenceGraph();
|
||||
|
||||
QString label() const {return tr("Cadence");}
|
||||
QList<GraphItem*> loadData(const Data &data);
|
||||
void clear();
|
||||
void showTracks(bool show);
|
||||
void showRoutes(bool show) {Q_UNUSED(show);}
|
||||
|
||||
private:
|
||||
qreal avg() const;
|
||||
@ -24,6 +26,7 @@ private:
|
||||
QVector<QPointF> _avg;
|
||||
|
||||
bool _showTracks;
|
||||
QList<CadenceGraphItem *> _tracks;
|
||||
};
|
||||
|
||||
#endif // CADENCEGRAPH_H
|
||||
|
@ -4,7 +4,8 @@
|
||||
|
||||
|
||||
CadenceGraphItem::CadenceGraphItem(const Graph &graph, GraphType type,
|
||||
QGraphicsItem *parent) : GraphItem(graph, type, parent)
|
||||
int width, const QColor &color, QGraphicsItem *parent)
|
||||
: GraphItem(graph, type, width, color, parent)
|
||||
{
|
||||
setToolTip(toolTip());
|
||||
}
|
||||
|
@ -8,8 +8,8 @@ class CadenceGraphItem : public GraphItem
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CadenceGraphItem(const Graph &graph, GraphType type,
|
||||
QGraphicsItem *parent = 0);
|
||||
CadenceGraphItem(const Graph &graph, GraphType type, int width,
|
||||
const QColor &color, QGraphicsItem *parent = 0);
|
||||
|
||||
private:
|
||||
QString toolTip() const;
|
||||
|
@ -8,26 +8,18 @@
|
||||
|
||||
static qreal nMin(qreal a, qreal b)
|
||||
{
|
||||
if (!std::isnan(a) && !std::isnan(b))
|
||||
return qMin(a, b);
|
||||
else if (!std::isnan(a))
|
||||
return a;
|
||||
else if (!std::isnan(b))
|
||||
return b;
|
||||
if (std::isnan(a))
|
||||
return std::isnan(b) ? NAN : b;
|
||||
else
|
||||
return NAN;
|
||||
return std::isnan(b) ? a : qMin(a, b);
|
||||
}
|
||||
|
||||
static qreal nMax(qreal a, qreal b)
|
||||
{
|
||||
if (!std::isnan(a) && !std::isnan(b))
|
||||
return qMax(a, b);
|
||||
else if (!std::isnan(a))
|
||||
return a;
|
||||
else if (!std::isnan(b))
|
||||
return b;
|
||||
if (std::isnan(a))
|
||||
return std::isnan(b) ? NAN : b;
|
||||
else
|
||||
return NAN;
|
||||
return std::isnan(b) ? a : qMax(a, b);
|
||||
}
|
||||
|
||||
ElevationGraph::ElevationGraph(QWidget *parent) : GraphTab(parent)
|
||||
@ -49,6 +41,12 @@ ElevationGraph::ElevationGraph(QWidget *parent) : GraphTab(parent)
|
||||
setMinYRange(50.0);
|
||||
}
|
||||
|
||||
ElevationGraph::~ElevationGraph()
|
||||
{
|
||||
qDeleteAll(_tracks);
|
||||
qDeleteAll(_routes);
|
||||
}
|
||||
|
||||
void ElevationGraph::setInfo()
|
||||
{
|
||||
if (std::isnan(max()) || std::isnan(min()))
|
||||
@ -70,19 +68,28 @@ void ElevationGraph::setInfo()
|
||||
GraphItem *ElevationGraph::loadGraph(const Graph &graph, Type type)
|
||||
{
|
||||
if (!graph.isValid()) {
|
||||
skipColor();
|
||||
_palette.nextColor();
|
||||
return 0;
|
||||
}
|
||||
|
||||
ElevationGraphItem *gi = new ElevationGraphItem(graph, _graphType);
|
||||
GraphView::addGraph(gi, type);
|
||||
ElevationGraphItem *gi = new ElevationGraphItem(graph, _graphType, _width,
|
||||
_palette.nextColor());
|
||||
gi->setUnits(_units);
|
||||
|
||||
if (type == Track) {
|
||||
_tracks.append(gi);
|
||||
if (_showTracks)
|
||||
addGraph(gi);
|
||||
|
||||
_trackAscent += gi->ascent();
|
||||
_trackDescent += gi->descent();
|
||||
_trackMax = nMax(_trackMax, gi->max());
|
||||
_trackMin = nMin(_trackMin, gi->min());
|
||||
} else {
|
||||
_routes.append(gi);
|
||||
if (_showRoutes)
|
||||
addGraph(gi);
|
||||
|
||||
_routeAscent += gi->ascent();
|
||||
_routeDescent += gi->descent();
|
||||
_routeMax = nMax(_routeMax, gi->max());
|
||||
@ -101,7 +108,7 @@ QList<GraphItem*> ElevationGraph::loadData(const Data &data)
|
||||
for (int i = 0; i < data.routes().count(); i++)
|
||||
graphs.append(loadGraph(data.routes().at(i).elevation(), Route));
|
||||
for (int i = 0; i < data.areas().count(); i++)
|
||||
skipColor();
|
||||
_palette.nextColor();
|
||||
|
||||
setInfo();
|
||||
redraw();
|
||||
@ -111,6 +118,11 @@ QList<GraphItem*> ElevationGraph::loadData(const Data &data)
|
||||
|
||||
void ElevationGraph::clear()
|
||||
{
|
||||
qDeleteAll(_tracks);
|
||||
_tracks.clear();
|
||||
qDeleteAll(_routes);
|
||||
_routes.clear();
|
||||
|
||||
_trackAscent = 0;
|
||||
_routeAscent = 0;
|
||||
_trackDescent = 0;
|
||||
@ -142,12 +154,23 @@ void ElevationGraph::setUnits(Units units)
|
||||
GraphView::setUnits(units);
|
||||
}
|
||||
|
||||
void ElevationGraph::showItems(const QList<ElevationGraphItem *> &list,
|
||||
bool show)
|
||||
{
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
if (show)
|
||||
addGraph(list.at(i));
|
||||
else
|
||||
removeGraph(list.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
void ElevationGraph::showTracks(bool show)
|
||||
{
|
||||
_showTracks = show;
|
||||
|
||||
showItems(_tracks, show);
|
||||
setInfo();
|
||||
showGraph(show, Track);
|
||||
|
||||
redraw();
|
||||
}
|
||||
@ -156,7 +179,7 @@ void ElevationGraph::showRoutes(bool show)
|
||||
{
|
||||
_showRoutes = show;
|
||||
|
||||
showGraph(show, Route);
|
||||
showItems(_routes, show);
|
||||
setInfo();
|
||||
|
||||
redraw();
|
||||
|
@ -3,12 +3,15 @@
|
||||
|
||||
#include "graphtab.h"
|
||||
|
||||
class ElevationGraphItem;
|
||||
|
||||
class ElevationGraph : public GraphTab
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ElevationGraph(QWidget *parent = 0);
|
||||
~ElevationGraph();
|
||||
|
||||
QString label() const {return tr("Elevation");}
|
||||
QList<GraphItem*> loadData(const Data &data);
|
||||
@ -29,6 +32,7 @@ private:
|
||||
void setInfo();
|
||||
|
||||
GraphItem *loadGraph(const Graph &graph, Type type);
|
||||
void showItems(const QList<ElevationGraphItem *> &list, bool show);
|
||||
|
||||
qreal _trackAscent, _trackDescent;
|
||||
qreal _routeAscent, _routeDescent;
|
||||
@ -36,6 +40,7 @@ private:
|
||||
qreal _trackMin, _routeMin;
|
||||
|
||||
bool _showTracks, _showRoutes;
|
||||
QList<ElevationGraphItem *> _tracks, _routes;
|
||||
};
|
||||
|
||||
#endif // ELEVATIONGRAPH_H
|
||||
|
@ -4,7 +4,8 @@
|
||||
|
||||
|
||||
ElevationGraphItem::ElevationGraphItem(const Graph &graph, GraphType type,
|
||||
QGraphicsItem *parent) : GraphItem(graph, type, parent)
|
||||
int width, const QColor &color, QGraphicsItem *parent)
|
||||
: GraphItem(graph, type, width, color, parent)
|
||||
{
|
||||
_min = GraphItem::min();
|
||||
_max = GraphItem::max();
|
||||
|
@ -8,8 +8,8 @@ class ElevationGraphItem : public GraphItem
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ElevationGraphItem(const Graph &graph, GraphType type,
|
||||
QGraphicsItem *parent = 0);
|
||||
ElevationGraphItem(const Graph &graph, GraphType type, int width,
|
||||
const QColor &color, QGraphicsItem *parent = 0);
|
||||
|
||||
qreal ascent() const {return _ascent;}
|
||||
qreal descent() const {return _descent;}
|
||||
|
@ -14,6 +14,11 @@ GearRatioGraph::GearRatioGraph(QWidget *parent) : GraphTab(parent)
|
||||
setSliderPrecision(2);
|
||||
}
|
||||
|
||||
GearRatioGraph::~GearRatioGraph()
|
||||
{
|
||||
qDeleteAll(_tracks);
|
||||
}
|
||||
|
||||
void GearRatioGraph::setInfo()
|
||||
{
|
||||
if (_showTracks) {
|
||||
@ -37,11 +42,15 @@ QList<GraphItem*> GearRatioGraph::loadData(const Data &data)
|
||||
const Graph &graph = data.tracks().at(i).ratio();
|
||||
|
||||
if (!graph.isValid()) {
|
||||
skipColor();
|
||||
_palette.nextColor();
|
||||
graphs.append(0);
|
||||
} else {
|
||||
GearRatioGraphItem *gi = new GearRatioGraphItem(graph, _graphType);
|
||||
GraphView::addGraph(gi);
|
||||
GearRatioGraphItem *gi = new GearRatioGraphItem(graph, _graphType,
|
||||
_width, _palette.nextColor());
|
||||
|
||||
_tracks.append(gi);
|
||||
if (_showTracks)
|
||||
addGraph(gi);
|
||||
|
||||
for (QMap<qreal, qreal>::const_iterator it = gi->map().constBegin();
|
||||
it != gi->map().constEnd(); ++it)
|
||||
@ -51,12 +60,12 @@ QList<GraphItem*> GearRatioGraph::loadData(const Data &data)
|
||||
}
|
||||
|
||||
for (int i = 0; i < data.routes().count(); i++) {
|
||||
skipColor();
|
||||
_palette.nextColor();
|
||||
graphs.append(0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < data.areas().count(); i++)
|
||||
skipColor();
|
||||
_palette.nextColor();
|
||||
|
||||
setInfo();
|
||||
redraw();
|
||||
@ -70,10 +79,7 @@ qreal GearRatioGraph::top() const
|
||||
|
||||
for (QMap<qreal, qreal>::const_iterator it = _map.constBegin();
|
||||
it != _map.constEnd(); ++it) {
|
||||
if (it == _map.constBegin()) {
|
||||
val = it.value();
|
||||
key = it.key();
|
||||
} else if (it.value() > val) {
|
||||
if (std::isnan(val) || it.value() > val) {
|
||||
val = it.value();
|
||||
key = it.key();
|
||||
}
|
||||
@ -84,6 +90,9 @@ qreal GearRatioGraph::top() const
|
||||
|
||||
void GearRatioGraph::clear()
|
||||
{
|
||||
qDeleteAll(_tracks);
|
||||
_tracks.clear();
|
||||
|
||||
_map.clear();
|
||||
|
||||
GraphTab::clear();
|
||||
@ -93,7 +102,13 @@ void GearRatioGraph::showTracks(bool show)
|
||||
{
|
||||
_showTracks = show;
|
||||
|
||||
showGraph(show);
|
||||
for (int i = 0; i < _tracks.size(); i++) {
|
||||
if (show)
|
||||
addGraph(_tracks.at(i));
|
||||
else
|
||||
removeGraph(_tracks.at(i));
|
||||
}
|
||||
|
||||
setInfo();
|
||||
|
||||
redraw();
|
||||
|
@ -4,12 +4,15 @@
|
||||
#include <QMap>
|
||||
#include "graphtab.h"
|
||||
|
||||
class GearRatioGraphItem;
|
||||
|
||||
class GearRatioGraph : public GraphTab
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GearRatioGraph(QWidget *parent = 0);
|
||||
~GearRatioGraph();
|
||||
|
||||
QString label() const {return tr("Gear ratio");}
|
||||
QList<GraphItem*> loadData(const Data &data);
|
||||
@ -25,6 +28,7 @@ private:
|
||||
QMap<qreal, qreal> _map;
|
||||
|
||||
bool _showTracks;
|
||||
QList<GearRatioGraphItem*> _tracks;
|
||||
};
|
||||
|
||||
#endif // GEARRATIOGRAPH_H
|
||||
|
@ -5,21 +5,27 @@
|
||||
|
||||
|
||||
GearRatioGraphItem::GearRatioGraphItem(const Graph &graph, GraphType type,
|
||||
QGraphicsItem *parent) : GraphItem(graph, type, parent), _top(NAN)
|
||||
int width, const QColor &color, QGraphicsItem *parent)
|
||||
: GraphItem(graph, type, width, color, parent)
|
||||
{
|
||||
qreal val = NAN;
|
||||
|
||||
for (QMap<qreal, qreal>::const_iterator it = _map.constBegin();
|
||||
it != _map.constEnd(); ++it) {
|
||||
if (it == _map.constBegin()) {
|
||||
val = it.value();
|
||||
_top = it.key();
|
||||
} else if (it.value() > val) {
|
||||
val = it.value();
|
||||
_top = it.key();
|
||||
for (int i = 0; i < graph.size(); i++) {
|
||||
const GraphSegment &segment = graph.at(i);
|
||||
for (int j = 1; j < segment.size(); j++) {
|
||||
qreal dx = segment.at(j).s() - segment.at(j-1).s();
|
||||
_map.insert(segment.at(j).y(), _map.value(segment.at(j).y()) + dx);
|
||||
}
|
||||
}
|
||||
|
||||
qreal key = NAN, val = NAN;
|
||||
for (QMap<qreal, qreal>::const_iterator it = _map.constBegin();
|
||||
it != _map.constEnd(); ++it) {
|
||||
if (std::isnan(val) || it.value() > val) {
|
||||
val = it.value();
|
||||
key = it.key();
|
||||
}
|
||||
}
|
||||
_top = key;
|
||||
|
||||
setToolTip(toolTip());
|
||||
}
|
||||
|
||||
|
@ -9,8 +9,8 @@ class GearRatioGraphItem : public GraphItem
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GearRatioGraphItem(const Graph &graph, GraphType type,
|
||||
QGraphicsItem *parent = 0);
|
||||
GearRatioGraphItem(const Graph &graph, GraphType type, int width,
|
||||
const QColor &color, QGraphicsItem *parent = 0);
|
||||
|
||||
qreal top() const {return _top;}
|
||||
|
||||
|
@ -2,30 +2,25 @@
|
||||
#include "graphitem.h"
|
||||
|
||||
|
||||
GraphItem::GraphItem(const Graph &graph, GraphType type, QGraphicsItem *parent)
|
||||
GraphItem::GraphItem(const Graph &graph, GraphType type, int width,
|
||||
const QColor &color, QGraphicsItem *parent)
|
||||
: QGraphicsObject(parent), _graph(graph), _type(type)
|
||||
{
|
||||
Q_ASSERT(_graph.isValid());
|
||||
|
||||
_id = 0;
|
||||
_width = 1;
|
||||
_pen = QPen(Qt::black, _width);
|
||||
_sx = 1.0; _sy = 1.0;
|
||||
_pen = QPen(color, width);
|
||||
_sx = 0; _sy = 0;
|
||||
_time = _graph.hasTime();
|
||||
|
||||
setZValue(2.0);
|
||||
|
||||
updatePath();
|
||||
updateShape();
|
||||
updateBounds();
|
||||
|
||||
setAcceptHoverEvents(true);
|
||||
|
||||
updateBounds();
|
||||
}
|
||||
|
||||
void GraphItem::updateShape()
|
||||
{
|
||||
QPainterPathStroker s;
|
||||
s.setWidth(_width + 1);
|
||||
s.setWidth(_pen.width() + 1);
|
||||
_shape = s.createStroke(_path);
|
||||
}
|
||||
|
||||
@ -54,7 +49,6 @@ void GraphItem::setGraphType(GraphType type)
|
||||
|
||||
_type = type;
|
||||
updatePath();
|
||||
updateShape();
|
||||
updateBounds();
|
||||
}
|
||||
|
||||
@ -69,12 +63,11 @@ void GraphItem::setColor(const QColor &color)
|
||||
|
||||
void GraphItem::setWidth(int width)
|
||||
{
|
||||
if (width == _width)
|
||||
if (width == _pen.width())
|
||||
return;
|
||||
|
||||
prepareGeometryChange();
|
||||
|
||||
_width = width;
|
||||
_pen.setWidth(width);
|
||||
|
||||
updateShape();
|
||||
@ -170,10 +163,10 @@ void GraphItem::emitSliderPositionChanged(qreal pos)
|
||||
void GraphItem::hover(bool hover)
|
||||
{
|
||||
if (hover) {
|
||||
_pen.setWidth(_width + 1);
|
||||
_pen.setWidth(_pen.width() + 1);
|
||||
setZValue(zValue() + 1.0);
|
||||
} else {
|
||||
_pen.setWidth(_width);
|
||||
_pen.setWidth(_pen.width() - 1);
|
||||
setZValue(zValue() - 1.0);
|
||||
}
|
||||
|
||||
@ -189,23 +182,30 @@ void GraphItem::setScale(qreal sx, qreal sy)
|
||||
|
||||
_sx = sx; _sy = sy;
|
||||
updatePath();
|
||||
updateShape();
|
||||
}
|
||||
|
||||
void GraphItem::updatePath()
|
||||
{
|
||||
_path = QPainterPath();
|
||||
|
||||
if (_type == Time && !_time)
|
||||
if (_sx == 0 && _sy == 0)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < _graph.size(); i++) {
|
||||
const GraphSegment &segment = _graph.at(i);
|
||||
prepareGeometryChange();
|
||||
|
||||
_path.moveTo(segment.first().x(_type) * _sx, -segment.first().y() * _sy);
|
||||
for (int i = 1; i < segment.size(); i++)
|
||||
_path.lineTo(segment.at(i).x(_type) * _sx, -segment.at(i).y() * _sy);
|
||||
_path = QPainterPath();
|
||||
|
||||
if (!(_type == Time && !_time)) {
|
||||
for (int i = 0; i < _graph.size(); i++) {
|
||||
const GraphSegment &segment = _graph.at(i);
|
||||
|
||||
_path.moveTo(segment.first().x(_type) * _sx, -segment.first().y()
|
||||
* _sy);
|
||||
for (int i = 1; i < segment.size(); i++)
|
||||
_path.lineTo(segment.at(i).x(_type) * _sx, -segment.at(i).y()
|
||||
* _sy);
|
||||
}
|
||||
}
|
||||
|
||||
updateShape();
|
||||
}
|
||||
|
||||
void GraphItem::updateBounds()
|
||||
@ -286,7 +286,7 @@ void GraphItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
_pen.setWidthF(_width + 1);
|
||||
_pen.setWidth(_pen.width() + 1);
|
||||
setZValue(zValue() + 1.0);
|
||||
update();
|
||||
|
||||
@ -297,7 +297,7 @@ void GraphItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
_pen.setWidthF(_width);
|
||||
_pen.setWidth(_pen.width() - 1);
|
||||
setZValue(zValue() - 1.0);
|
||||
update();
|
||||
|
||||
|
@ -11,7 +11,8 @@ class GraphItem : public QGraphicsObject
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GraphItem(const Graph &graph, GraphType type, QGraphicsItem *parent = 0);
|
||||
GraphItem(const Graph &graph, GraphType type, int width, const QColor &color,
|
||||
QGraphicsItem *parent = 0);
|
||||
virtual ~GraphItem() {}
|
||||
|
||||
QPainterPath shape() const {return _shape;}
|
||||
@ -27,8 +28,6 @@ public:
|
||||
|
||||
void setScale(qreal sx, qreal sy);
|
||||
void setGraphType(GraphType type);
|
||||
int id() const {return _id;}
|
||||
void setId(int id) {_id = id;}
|
||||
void setColor(const QColor &color);
|
||||
void setWidth(int width);
|
||||
virtual void setUnits(Units units) {Q_UNUSED(units);}
|
||||
@ -55,17 +54,13 @@ private:
|
||||
void updateShape();
|
||||
void updateBounds();
|
||||
|
||||
int _id;
|
||||
QPen _pen;
|
||||
int _width;
|
||||
|
||||
Graph _graph;
|
||||
GraphType _type;
|
||||
|
||||
QPainterPath _path;
|
||||
QPainterPath _shape;
|
||||
QRectF _bounds;
|
||||
qreal _sx, _sy;
|
||||
QPen _pen;
|
||||
|
||||
bool _time;
|
||||
};
|
||||
|
@ -1,8 +1,7 @@
|
||||
#include <QGraphicsScene>
|
||||
#include <QEvent>
|
||||
#include <QMouseEvent>
|
||||
#include <QPaintEngine>
|
||||
#include <QPaintDevice>
|
||||
#include <QScrollBar>
|
||||
#include <QGraphicsSimpleTextItem>
|
||||
#include <QPalette>
|
||||
#include <QLocale>
|
||||
@ -64,6 +63,8 @@ GraphView::GraphView(QWidget *parent)
|
||||
_units = Metric;
|
||||
_graphType = Distance;
|
||||
_xLabel = tr("Distance");
|
||||
|
||||
_zoom = 1.0;
|
||||
}
|
||||
|
||||
GraphView::~GraphView()
|
||||
@ -74,8 +75,6 @@ GraphView::~GraphView()
|
||||
delete _info;
|
||||
delete _grid;
|
||||
delete _message;
|
||||
|
||||
qDeleteAll(_graphs);
|
||||
}
|
||||
|
||||
void GraphView::createXLabel()
|
||||
@ -166,14 +165,7 @@ void GraphView::setGraphType(GraphType type)
|
||||
for (int i = 0; i < _graphs.count(); i++) {
|
||||
GraphItem *gi = _graphs.at(i);
|
||||
gi->setGraphType(type);
|
||||
if (!_hide.contains(gi->id())) {
|
||||
if (gi->bounds().width() > 0)
|
||||
addItem(gi);
|
||||
else
|
||||
removeItem(gi);
|
||||
}
|
||||
if (gi->scene() == _scene)
|
||||
_bounds |= gi->bounds();
|
||||
_bounds |= gi->bounds();
|
||||
}
|
||||
|
||||
if (type == Distance)
|
||||
@ -195,29 +187,31 @@ void GraphView::showSliderInfo(bool show)
|
||||
_sliderInfo->setVisible(show);
|
||||
}
|
||||
|
||||
void GraphView::addGraph(GraphItem *graph, int id)
|
||||
void GraphView::addGraph(GraphItem *graph)
|
||||
{
|
||||
QColor color(_palette.nextColor());
|
||||
color.setAlpha(255);
|
||||
|
||||
graph->setUnits(_units);
|
||||
graph->setId(id);
|
||||
graph->setColor(color);
|
||||
graph->setWidth(_width);
|
||||
|
||||
connect(this, SIGNAL(sliderPositionChanged(qreal)), graph,
|
||||
SLOT(emitSliderPositionChanged(qreal)));
|
||||
|
||||
_graphs.append(graph);
|
||||
_scene->addItem(graph);
|
||||
_bounds |= graph->bounds();
|
||||
|
||||
if (!_hide.contains(id)) {
|
||||
_visible.append(graph);
|
||||
if (graph->bounds().width() > 0) {
|
||||
_scene->addItem(graph);
|
||||
_bounds |= graph->bounds();
|
||||
}
|
||||
setXUnits();
|
||||
}
|
||||
setXUnits();
|
||||
}
|
||||
|
||||
void GraphView::removeGraph(GraphItem *graph)
|
||||
{
|
||||
disconnect(this, SIGNAL(sliderPositionChanged(qreal)), graph,
|
||||
SLOT(emitSliderPositionChanged(qreal)));
|
||||
|
||||
_graphs.removeOne(graph);
|
||||
_scene->removeItem(graph);
|
||||
|
||||
_bounds = QRectF();
|
||||
for (int i = 0; i < _graphs.count(); i++)
|
||||
_bounds |= _graphs.at(i)->bounds();
|
||||
|
||||
setXUnits();
|
||||
}
|
||||
|
||||
void GraphView::removeItem(QGraphicsItem *item)
|
||||
@ -232,29 +226,6 @@ void GraphView::addItem(QGraphicsItem *item)
|
||||
_scene->addItem(item);
|
||||
}
|
||||
|
||||
void GraphView::showGraph(bool show, int id)
|
||||
{
|
||||
if (show)
|
||||
_hide.remove(id);
|
||||
else
|
||||
_hide.insert(id);
|
||||
|
||||
_visible.clear();
|
||||
_bounds = QRectF();
|
||||
for (int i = 0; i < _graphs.count(); i++) {
|
||||
GraphItem *gi = _graphs.at(i);
|
||||
if (_hide.contains(gi->id()))
|
||||
removeItem(gi);
|
||||
else {
|
||||
_visible.append(gi);
|
||||
if (gi->bounds().width() > 0) {
|
||||
addItem(gi);
|
||||
_bounds |= gi->bounds();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QRectF GraphView::bounds() const
|
||||
{
|
||||
QRectF br(_bounds);
|
||||
@ -313,9 +284,10 @@ void GraphView::redraw(const QSizeF &size)
|
||||
sx = (size.width() - (my.width() + mx.width())) / r.width();
|
||||
sy = (size.height() - (mx.height() + my.height())
|
||||
- _info->boundingRect().height()) / r.height();
|
||||
sx *= _zoom;
|
||||
|
||||
for (int i = 0; i < _visible.size(); i++)
|
||||
_visible.at(i)->setScale(sx, sy);
|
||||
for (int i = 0; i < _graphs.size(); i++)
|
||||
_graphs.at(i)->setScale(sx, sy);
|
||||
|
||||
QPointF p(r.left() * sx, r.top() * sy);
|
||||
QSizeF s(r.width() * sx, r.height() * sy);
|
||||
@ -360,6 +332,40 @@ void GraphView::mousePressEvent(QMouseEvent *e)
|
||||
QGraphicsView::mousePressEvent(e);
|
||||
}
|
||||
|
||||
void GraphView::wheelEvent(QWheelEvent *e)
|
||||
{
|
||||
static int deg = 0;
|
||||
|
||||
deg += e->delta() / 8;
|
||||
if (qAbs(deg) < 15)
|
||||
return;
|
||||
deg = 0;
|
||||
|
||||
QPointF pos = mapToScene(e->pos());
|
||||
QRectF gr(_grid->boundingRect());
|
||||
QPointF r(pos.x() / gr.width(), pos.y() / gr.height());
|
||||
|
||||
_zoom = (e->delta() > 0) ? _zoom * 1.25 : qMax(_zoom / 1.25, 1.0);
|
||||
redraw();
|
||||
|
||||
QRectF ngr(_grid->boundingRect());
|
||||
QPointF npos(mapFromScene(QPointF(r.x() * ngr.width(),
|
||||
r.y() * ngr.height())));
|
||||
QScrollBar *sb = horizontalScrollBar();
|
||||
sb->setSliderPosition(sb->sliderPosition() + npos.x() - e->pos().x());
|
||||
|
||||
QGraphicsView::wheelEvent(e);
|
||||
}
|
||||
|
||||
void GraphView::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
QRectF viewRect(mapToScene(rect()).boundingRect());
|
||||
_info->setPos(QPointF(viewRect.left() + (viewRect.width()
|
||||
- _info->boundingRect().width())/2.0, _info->pos().y()));
|
||||
|
||||
QGraphicsView::paintEvent(event);
|
||||
}
|
||||
|
||||
void GraphView::plot(QPainter *painter, const QRectF &target, qreal scale)
|
||||
{
|
||||
QSizeF canvas = QSizeF(target.width() / scale, target.height() / scale);
|
||||
@ -376,54 +382,45 @@ void GraphView::plot(QPainter *painter, const QRectF &target, qreal scale)
|
||||
|
||||
void GraphView::clear()
|
||||
{
|
||||
_graphs.clear();
|
||||
|
||||
_slider->clear();
|
||||
_info->clear();
|
||||
|
||||
qDeleteAll(_graphs);
|
||||
_graphs.clear();
|
||||
_visible.clear();
|
||||
_palette.reset();
|
||||
|
||||
_bounds = QRectF();
|
||||
_sliderPos = 0;
|
||||
_zoom = 1.0;
|
||||
|
||||
_scene->setSceneRect(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void GraphView::updateSliderPosition()
|
||||
{
|
||||
if (bounds().width() <= 0)
|
||||
return;
|
||||
|
||||
if (_sliderPos <= bounds().right() && _sliderPos >= bounds().left()) {
|
||||
_slider->setPos((_sliderPos / bounds().width())
|
||||
* _slider->area().width(), _slider->area().bottom());
|
||||
_slider->setVisible(!_visible.isEmpty());
|
||||
_slider->setVisible(true);
|
||||
updateSliderInfo();
|
||||
} else {
|
||||
_slider->setPos(_slider->area().left(), _slider->area().bottom());
|
||||
_slider->setVisible(false);
|
||||
}
|
||||
|
||||
if (_slider->isVisible())
|
||||
updateSliderInfo();
|
||||
}
|
||||
|
||||
void GraphView::updateSliderInfo()
|
||||
{
|
||||
QLocale l(QLocale::system());
|
||||
qreal r, y;
|
||||
qreal r = 0, y = 0;
|
||||
|
||||
|
||||
if (_visible.count() > 1) {
|
||||
r = 0;
|
||||
y = 0;
|
||||
} else {
|
||||
QRectF br(_visible.first()->bounds());
|
||||
if (_graphs.count() == 1) {
|
||||
QRectF br(_graphs.first()->bounds());
|
||||
if (br.height() < _minYRange)
|
||||
br.adjust(0, -(_minYRange/2 - br.height()/2), 0,
|
||||
_minYRange/2 - br.height()/2);
|
||||
|
||||
y = _visible.first()->yAtX(_sliderPos);
|
||||
y = _graphs.first()->yAtX(_sliderPos);
|
||||
r = (y - br.bottom()) / br.height();
|
||||
}
|
||||
|
||||
@ -435,7 +432,7 @@ void GraphView::updateSliderInfo()
|
||||
_sliderInfo->setPos(QPointF(0, _slider->boundingRect().height() * r));
|
||||
_sliderInfo->setText(_graphType == Time ? Format::timeSpan(_sliderPos,
|
||||
bounds().width() > 3600) : l.toString(_sliderPos * _xScale, 'f', 1)
|
||||
+ UNIT_SPACE + _xUnits, (_visible.count() > 1) ? QString()
|
||||
+ UNIT_SPACE + _xUnits, (_graphs.count() > 1) ? QString()
|
||||
: l.toString(-y * _yScale + _yOffset, 'f', _precision) + UNIT_SPACE
|
||||
+ _yUnits);
|
||||
}
|
||||
@ -455,7 +452,7 @@ void GraphView::emitSliderPositionChanged(const QPointF &pos)
|
||||
|
||||
void GraphView::setSliderPosition(qreal pos)
|
||||
{
|
||||
if (_visible.isEmpty())
|
||||
if (_graphs.isEmpty())
|
||||
return;
|
||||
|
||||
_sliderPos = pos;
|
||||
@ -483,11 +480,8 @@ void GraphView::setPalette(const Palette &palette)
|
||||
_palette = palette;
|
||||
_palette.reset();
|
||||
|
||||
for (int i = 0; i < _graphs.count(); i++) {
|
||||
QColor color(_palette.nextColor());
|
||||
color.setAlpha(255);
|
||||
_graphs.at(i)->setColor(color);
|
||||
}
|
||||
for (int i = 0; i < _graphs.count(); i++)
|
||||
_graphs.at(i)->setColor(_palette.nextColor());
|
||||
}
|
||||
|
||||
void GraphView::setGraphWidth(int width)
|
||||
|
@ -46,9 +46,9 @@ signals:
|
||||
void sliderPositionChanged(qreal);
|
||||
|
||||
protected:
|
||||
void addGraph(GraphItem *graph, int id = 0);
|
||||
void addGraph(GraphItem *graph);
|
||||
void removeGraph(GraphItem *graph);
|
||||
|
||||
void showGraph(bool show, int id = 0);
|
||||
void setGraphType(GraphType type);
|
||||
void setUnits(Units units);
|
||||
|
||||
@ -68,12 +68,11 @@ protected:
|
||||
void redraw();
|
||||
void addInfo(const QString &key, const QString &value);
|
||||
void clearInfo();
|
||||
void skipColor() {_palette.nextColor();}
|
||||
|
||||
void changeEvent(QEvent *e);
|
||||
|
||||
QList<GraphItem*> _graphs;
|
||||
GraphType _graphType;
|
||||
Units _units;
|
||||
Palette _palette;
|
||||
int _width;
|
||||
|
||||
private slots:
|
||||
void emitSliderPositionChanged(const QPointF &pos);
|
||||
@ -91,15 +90,9 @@ private:
|
||||
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
void mousePressEvent(QMouseEvent *e);
|
||||
|
||||
Units _units;
|
||||
qreal _xScale, _yScale;
|
||||
qreal _yOffset;
|
||||
QString _xUnits, _yUnits;
|
||||
QString _xLabel, _yLabel;
|
||||
int _precision;
|
||||
qreal _minYRange;
|
||||
qreal _sliderPos;
|
||||
void wheelEvent(QWheelEvent *e);
|
||||
void changeEvent(QEvent *e);
|
||||
void paintEvent(QPaintEvent *event);
|
||||
|
||||
QGraphicsScene *_scene;
|
||||
|
||||
@ -109,12 +102,19 @@ private:
|
||||
InfoItem *_info;
|
||||
GridItem *_grid;
|
||||
QGraphicsSimpleTextItem *_message;
|
||||
QList<GraphItem*> _graphs;
|
||||
|
||||
QList<GraphItem*> _visible;
|
||||
QSet<int> _hide;
|
||||
QRectF _bounds;
|
||||
Palette _palette;
|
||||
int _width;
|
||||
qreal _sliderPos;
|
||||
|
||||
qreal _xScale, _yScale;
|
||||
qreal _yOffset;
|
||||
QString _xUnits, _yUnits;
|
||||
QString _xLabel, _yLabel;
|
||||
int _precision;
|
||||
qreal _minYRange;
|
||||
|
||||
qreal _zoom;
|
||||
};
|
||||
|
||||
#endif // GRAPHVIEW_H
|
||||
|
@ -14,6 +14,11 @@ HeartRateGraph::HeartRateGraph(QWidget *parent) : GraphTab(parent)
|
||||
setSliderPrecision(0);
|
||||
}
|
||||
|
||||
HeartRateGraph::~HeartRateGraph()
|
||||
{
|
||||
qDeleteAll(_tracks);
|
||||
}
|
||||
|
||||
void HeartRateGraph::setInfo()
|
||||
{
|
||||
if (_showTracks) {
|
||||
@ -36,23 +41,28 @@ QList<GraphItem*> HeartRateGraph::loadData(const Data &data)
|
||||
const Graph &graph = track.heartRate();
|
||||
|
||||
if (!graph.isValid()) {
|
||||
skipColor();
|
||||
_palette.nextColor();
|
||||
graphs.append(0);
|
||||
} else {
|
||||
HeartRateGraphItem *gi = new HeartRateGraphItem(graph, _graphType);
|
||||
GraphView::addGraph(gi);
|
||||
HeartRateGraphItem *gi = new HeartRateGraphItem(graph, _graphType,
|
||||
_width, _palette.nextColor());
|
||||
|
||||
_tracks.append(gi);
|
||||
if (_showTracks)
|
||||
addGraph(gi);
|
||||
|
||||
_avg.append(QPointF(track.distance(), gi->avg()));
|
||||
graphs.append(gi);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < data.routes().count(); i++) {
|
||||
skipColor();
|
||||
_palette.nextColor();
|
||||
graphs.append(0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < data.areas().count(); i++)
|
||||
skipColor();
|
||||
_palette.nextColor();
|
||||
|
||||
setInfo();
|
||||
redraw();
|
||||
@ -75,6 +85,9 @@ qreal HeartRateGraph::avg() const
|
||||
|
||||
void HeartRateGraph::clear()
|
||||
{
|
||||
qDeleteAll(_tracks);
|
||||
_tracks.clear();
|
||||
|
||||
_avg.clear();
|
||||
|
||||
GraphTab::clear();
|
||||
@ -84,7 +97,13 @@ void HeartRateGraph::showTracks(bool show)
|
||||
{
|
||||
_showTracks = show;
|
||||
|
||||
showGraph(show);
|
||||
for (int i = 0; i < _tracks.size(); i++) {
|
||||
if (show)
|
||||
addGraph(_tracks.at(i));
|
||||
else
|
||||
removeGraph(_tracks.at(i));
|
||||
}
|
||||
|
||||
setInfo();
|
||||
|
||||
redraw();
|
||||
|
@ -3,12 +3,15 @@
|
||||
|
||||
#include "graphtab.h"
|
||||
|
||||
class HeartRateGraphItem;
|
||||
|
||||
class HeartRateGraph : public GraphTab
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
HeartRateGraph(QWidget *parent = 0);
|
||||
~HeartRateGraph();
|
||||
|
||||
QString label() const {return tr("Heart rate");}
|
||||
QList<GraphItem*> loadData(const Data &data);
|
||||
@ -23,6 +26,7 @@ private:
|
||||
QVector<QPointF> _avg;
|
||||
|
||||
bool _showTracks;
|
||||
QList<HeartRateGraphItem*> _tracks;
|
||||
};
|
||||
|
||||
#endif // HEARTRATEGRAPH_H
|
||||
|
@ -4,7 +4,8 @@
|
||||
|
||||
|
||||
HeartRateGraphItem::HeartRateGraphItem(const Graph &graph, GraphType type,
|
||||
QGraphicsItem *parent) : GraphItem(graph, type, parent)
|
||||
int width, const QColor &color, QGraphicsItem *parent)
|
||||
: GraphItem(graph, type, width, color, parent)
|
||||
{
|
||||
setToolTip(toolTip());
|
||||
}
|
||||
|
@ -8,8 +8,8 @@ class HeartRateGraphItem : public GraphItem
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
HeartRateGraphItem(const Graph &graph, GraphType type,
|
||||
QGraphicsItem *parent = 0);
|
||||
HeartRateGraphItem(const Graph &graph, GraphType type, int width,
|
||||
const QColor &color, QGraphicsItem *parent = 0);
|
||||
|
||||
private:
|
||||
QString toolTip() const;
|
||||
|
@ -24,7 +24,7 @@ PercentSlider::PercentSlider(QWidget *parent) : QWidget(parent)
|
||||
_label->setAlignment(Qt::AlignRight);
|
||||
_label->setText(format(_slider->value()));
|
||||
|
||||
connect(_slider, SIGNAL(sliderMoved(int)), this, SLOT(updateLabel(int)));
|
||||
connect(_slider, SIGNAL(valueChanged(int)), this, SLOT(updateLabel(int)));
|
||||
|
||||
QHBoxLayout *layout = new QHBoxLayout();
|
||||
layout->addWidget(_slider);
|
||||
|
@ -14,6 +14,11 @@ PowerGraph::PowerGraph(QWidget *parent) : GraphTab(parent)
|
||||
setSliderPrecision(1);
|
||||
}
|
||||
|
||||
PowerGraph::~PowerGraph()
|
||||
{
|
||||
qDeleteAll(_tracks);
|
||||
}
|
||||
|
||||
void PowerGraph::setInfo()
|
||||
{
|
||||
if (_showTracks) {
|
||||
@ -36,23 +41,27 @@ QList<GraphItem*> PowerGraph::loadData(const Data &data)
|
||||
const Graph &graph = track.power();
|
||||
|
||||
if (!graph.isValid()) {
|
||||
skipColor();
|
||||
_palette.nextColor();
|
||||
graphs.append(0);
|
||||
} else {
|
||||
PowerGraphItem *gi = new PowerGraphItem(graph, _graphType);
|
||||
GraphView::addGraph(gi);
|
||||
PowerGraphItem *gi = new PowerGraphItem(graph, _graphType, _width,
|
||||
_palette.nextColor());
|
||||
|
||||
_tracks.append(gi);
|
||||
if (_showTracks)
|
||||
addGraph(gi);
|
||||
_avg.append(QPointF(track.distance(), gi->avg()));
|
||||
graphs.append(gi);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < data.routes().count(); i++) {
|
||||
skipColor();
|
||||
_palette.nextColor();
|
||||
graphs.append(0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < data.areas().count(); i++)
|
||||
skipColor();
|
||||
_palette.nextColor();
|
||||
|
||||
setInfo();
|
||||
redraw();
|
||||
@ -75,6 +84,9 @@ qreal PowerGraph::avg() const
|
||||
|
||||
void PowerGraph::clear()
|
||||
{
|
||||
qDeleteAll(_tracks);
|
||||
_tracks.clear();
|
||||
|
||||
_avg.clear();
|
||||
|
||||
GraphTab::clear();
|
||||
@ -84,7 +96,13 @@ void PowerGraph::showTracks(bool show)
|
||||
{
|
||||
_showTracks = show;
|
||||
|
||||
showGraph(show);
|
||||
for (int i = 0; i < _tracks.size(); i++) {
|
||||
if (show)
|
||||
addGraph(_tracks.at(i));
|
||||
else
|
||||
removeGraph(_tracks.at(i));
|
||||
}
|
||||
|
||||
setInfo();
|
||||
|
||||
redraw();
|
||||
|
@ -3,12 +3,15 @@
|
||||
|
||||
#include "graphtab.h"
|
||||
|
||||
class PowerGraphItem;
|
||||
|
||||
class PowerGraph : public GraphTab
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PowerGraph(QWidget *parent = 0);
|
||||
~PowerGraph();
|
||||
|
||||
QString label() const {return tr("Power");}
|
||||
QList<GraphItem*> loadData(const Data &data);
|
||||
@ -23,6 +26,7 @@ private:
|
||||
QVector<QPointF> _avg;
|
||||
|
||||
bool _showTracks;
|
||||
QList<PowerGraphItem*> _tracks;
|
||||
};
|
||||
|
||||
#endif // POWERGRAPH_H
|
||||
|
@ -3,8 +3,9 @@
|
||||
#include "powergraphitem.h"
|
||||
|
||||
|
||||
PowerGraphItem::PowerGraphItem(const Graph &graph, GraphType type,
|
||||
QGraphicsItem *parent) : GraphItem(graph, type, parent)
|
||||
PowerGraphItem::PowerGraphItem(const Graph &graph, GraphType type, int width,
|
||||
const QColor &color, QGraphicsItem *parent)
|
||||
: GraphItem(graph, type, width, color, parent)
|
||||
{
|
||||
setToolTip(toolTip());
|
||||
}
|
||||
|
@ -8,8 +8,8 @@ class PowerGraphItem : public GraphItem
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PowerGraphItem(const Graph &graph, GraphType type,
|
||||
QGraphicsItem *parent = 0);
|
||||
PowerGraphItem(const Graph &graph, GraphType type, int width,
|
||||
const QColor &color, QGraphicsItem *parent = 0);
|
||||
|
||||
private:
|
||||
QString toolTip() const;
|
||||
|
@ -24,7 +24,7 @@ QString RouteItem::toolTip(Units units) const
|
||||
RouteItem::RouteItem(const Route &route, Map *map, QGraphicsItem *parent)
|
||||
: PathItem(route.path(), map, parent)
|
||||
{
|
||||
const QVector<Waypoint> &waypoints = route.waypoints();
|
||||
const RouteData &waypoints = route.data();
|
||||
|
||||
_waypoints.resize(waypoints.size());
|
||||
for (int i = 0; i < waypoints.size(); i++)
|
||||
|
@ -18,6 +18,11 @@ SpeedGraph::SpeedGraph(QWidget *parent) : GraphTab(parent)
|
||||
setSliderPrecision(1);
|
||||
}
|
||||
|
||||
SpeedGraph::~SpeedGraph()
|
||||
{
|
||||
qDeleteAll(_tracks);
|
||||
}
|
||||
|
||||
void SpeedGraph::setInfo()
|
||||
{
|
||||
if (_showTracks) {
|
||||
@ -44,13 +49,18 @@ QList<GraphItem*> SpeedGraph::loadData(const Data &data)
|
||||
const Graph &graph = track.speed();
|
||||
|
||||
if (!graph.isValid()) {
|
||||
skipColor();
|
||||
_palette.nextColor();
|
||||
graphs.append(0);
|
||||
} else {
|
||||
SpeedGraphItem *gi = new SpeedGraphItem(graph, _graphType,
|
||||
track.movingTime());
|
||||
SpeedGraphItem *gi = new SpeedGraphItem(graph, _graphType, _width,
|
||||
_palette.nextColor(), track.movingTime());
|
||||
gi->setTimeType(_timeType);
|
||||
GraphView::addGraph(gi);
|
||||
gi->setUnits(_units);
|
||||
|
||||
_tracks.append(gi);
|
||||
if (_showTracks)
|
||||
addGraph(gi);
|
||||
|
||||
_avg.append(QPointF(track.distance(), gi->avg()));
|
||||
_mavg.append(QPointF(track.distance(), gi->mavg()));
|
||||
graphs.append(gi);
|
||||
@ -58,12 +68,12 @@ QList<GraphItem*> SpeedGraph::loadData(const Data &data)
|
||||
}
|
||||
|
||||
for (int i = 0; i < data.routes().count(); i++) {
|
||||
skipColor();
|
||||
_palette.nextColor();
|
||||
graphs.append(0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < data.areas().count(); i++)
|
||||
skipColor();
|
||||
_palette.nextColor();
|
||||
|
||||
setInfo();
|
||||
redraw();
|
||||
@ -87,6 +97,9 @@ qreal SpeedGraph::avg() const
|
||||
|
||||
void SpeedGraph::clear()
|
||||
{
|
||||
qDeleteAll(_tracks);
|
||||
_tracks.clear();
|
||||
|
||||
_avg.clear();
|
||||
_mavg.clear();
|
||||
|
||||
@ -121,8 +134,8 @@ void SpeedGraph::setTimeType(enum TimeType type)
|
||||
{
|
||||
_timeType = type;
|
||||
|
||||
for (int i = 0; i < _graphs.size(); i++)
|
||||
static_cast<SpeedGraphItem*>(_graphs.at(i))->setTimeType(type);
|
||||
for (int i = 0; i < _tracks.size(); i++)
|
||||
_tracks.at(i)->setTimeType(type);
|
||||
|
||||
setInfo();
|
||||
redraw();
|
||||
@ -132,7 +145,13 @@ void SpeedGraph::showTracks(bool show)
|
||||
{
|
||||
_showTracks = show;
|
||||
|
||||
showGraph(show);
|
||||
for (int i = 0; i < _tracks.size(); i++) {
|
||||
if (show)
|
||||
addGraph(_tracks.at(i));
|
||||
else
|
||||
removeGraph(_tracks.at(i));
|
||||
}
|
||||
|
||||
setInfo();
|
||||
|
||||
redraw();
|
||||
|
@ -4,12 +4,15 @@
|
||||
#include <QList>
|
||||
#include "graphtab.h"
|
||||
|
||||
class SpeedGraphItem;
|
||||
|
||||
class SpeedGraph : public GraphTab
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SpeedGraph(QWidget *parent = 0);
|
||||
~SpeedGraph();
|
||||
|
||||
QString label() const {return tr("Speed");}
|
||||
QList<GraphItem*> loadData(const Data &data);
|
||||
@ -29,7 +32,9 @@ private:
|
||||
|
||||
Units _units;
|
||||
TimeType _timeType;
|
||||
|
||||
bool _showTracks;
|
||||
QList<SpeedGraphItem *> _tracks;
|
||||
};
|
||||
|
||||
#endif // SPEEDGRAPH_H
|
||||
|
@ -4,8 +4,9 @@
|
||||
#include "speedgraphitem.h"
|
||||
|
||||
|
||||
SpeedGraphItem::SpeedGraphItem(const Graph &graph, GraphType type,
|
||||
qreal movingTime, QGraphicsItem *parent) : GraphItem(graph, type, parent)
|
||||
SpeedGraphItem::SpeedGraphItem(const Graph &graph, GraphType type, int width,
|
||||
const QColor &color, qreal movingTime, QGraphicsItem *parent)
|
||||
: GraphItem(graph, type, width, color, parent)
|
||||
{
|
||||
_units = Metric;
|
||||
_timeType = Total;
|
||||
|
@ -9,8 +9,8 @@ class SpeedGraphItem : public GraphItem
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SpeedGraphItem(const Graph &graph, GraphType type, qreal movingTime,
|
||||
QGraphicsItem *parent = 0);
|
||||
SpeedGraphItem(const Graph &graph, GraphType type, int width,
|
||||
const QColor &color, qreal movingTime, QGraphicsItem *parent = 0);
|
||||
|
||||
qreal avg() const {return _avg;}
|
||||
qreal mavg() const {return _mavg;}
|
||||
@ -23,9 +23,8 @@ private:
|
||||
QString toolTip() const;
|
||||
|
||||
qreal _avg, _mavg, _max;
|
||||
|
||||
Units _units;
|
||||
TimeType _timeType;
|
||||
Units _units;
|
||||
};
|
||||
|
||||
#endif // SPEEDGRAPHITEM_H
|
||||
|
@ -14,6 +14,11 @@ TemperatureGraph::TemperatureGraph(QWidget *parent) : GraphTab(parent)
|
||||
setSliderPrecision(1);
|
||||
}
|
||||
|
||||
TemperatureGraph::~TemperatureGraph()
|
||||
{
|
||||
qDeleteAll(_tracks);
|
||||
}
|
||||
|
||||
void TemperatureGraph::setInfo()
|
||||
{
|
||||
if (_showTracks) {
|
||||
@ -38,24 +43,29 @@ QList<GraphItem*> TemperatureGraph::loadData(const Data &data)
|
||||
const Graph &graph = track.temperature();
|
||||
|
||||
if (!graph.isValid()) {
|
||||
skipColor();
|
||||
_palette.nextColor();
|
||||
graphs.append(0);
|
||||
} else {
|
||||
TemperatureGraphItem *gi = new TemperatureGraphItem(graph,
|
||||
_graphType);
|
||||
GraphView::addGraph(gi);
|
||||
_graphType, _width, _palette.nextColor());
|
||||
gi->setUnits(_units);
|
||||
|
||||
_tracks.append(gi);
|
||||
if (_showTracks)
|
||||
addGraph(gi);
|
||||
|
||||
_avg.append(QPointF(track.distance(), gi->avg()));
|
||||
graphs.append(gi);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < data.routes().count(); i++) {
|
||||
skipColor();
|
||||
_palette.nextColor();
|
||||
graphs.append(0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < data.areas().count(); i++)
|
||||
skipColor();
|
||||
_palette.nextColor();
|
||||
|
||||
setInfo();
|
||||
redraw();
|
||||
@ -78,6 +88,9 @@ qreal TemperatureGraph::avg() const
|
||||
|
||||
void TemperatureGraph::clear()
|
||||
{
|
||||
qDeleteAll(_tracks);
|
||||
_tracks.clear();
|
||||
|
||||
_avg.clear();
|
||||
|
||||
GraphTab::clear();
|
||||
@ -108,7 +121,13 @@ void TemperatureGraph::showTracks(bool show)
|
||||
{
|
||||
_showTracks = show;
|
||||
|
||||
showGraph(show);
|
||||
for (int i = 0; i < _tracks.size(); i++) {
|
||||
if (show)
|
||||
addGraph(_tracks.at(i));
|
||||
else
|
||||
removeGraph(_tracks.at(i));
|
||||
}
|
||||
|
||||
setInfo();
|
||||
|
||||
redraw();
|
||||
|
@ -3,12 +3,15 @@
|
||||
|
||||
#include "graphtab.h"
|
||||
|
||||
class TemperatureGraphItem;
|
||||
|
||||
class TemperatureGraph : public GraphTab
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TemperatureGraph(QWidget *parent = 0);
|
||||
~TemperatureGraph();
|
||||
|
||||
QString label() const {return tr("Temperature");}
|
||||
QList<GraphItem*> loadData(const Data &data);
|
||||
@ -26,6 +29,7 @@ private:
|
||||
QVector<QPointF> _avg;
|
||||
|
||||
bool _showTracks;
|
||||
QList<TemperatureGraphItem *> _tracks;
|
||||
};
|
||||
|
||||
#endif // TEMPERATUREGRAPH_H
|
||||
|
@ -4,7 +4,8 @@
|
||||
|
||||
|
||||
TemperatureGraphItem::TemperatureGraphItem(const Graph &graph, GraphType type,
|
||||
QGraphicsItem *parent) : GraphItem(graph, type, parent)
|
||||
int width, const QColor &color, QGraphicsItem *parent)
|
||||
: GraphItem(graph, type, width, color, parent)
|
||||
{
|
||||
_min = GraphItem::min();
|
||||
_max = GraphItem::max();
|
||||
|
@ -8,8 +8,8 @@ class TemperatureGraphItem : public GraphItem
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TemperatureGraphItem(const Graph &graph, GraphType type,
|
||||
QGraphicsItem *parent = 0);
|
||||
TemperatureGraphItem(const Graph &graph, GraphType type, int width,
|
||||
const QColor &color, QGraphicsItem *parent = 0);
|
||||
|
||||
qreal max() const {return _max;}
|
||||
qreal min() const {return _min;}
|
||||
|
@ -71,13 +71,35 @@ static QHash<QString, Parser*> parsers()
|
||||
QHash<QString, Parser*> Data::_parsers = parsers();
|
||||
bool Data::_useDEM = false;
|
||||
|
||||
void Data::processData(const QList<TrackData> &trackData,
|
||||
const 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)));
|
||||
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)));
|
||||
}
|
||||
for (int i = 0; i < _waypoints.size(); i++) {
|
||||
if (!_waypoints.at(i).hasElevation() || _useDEM) {
|
||||
qreal elevation = DEM::elevation(_waypoints.at(i).coordinates());
|
||||
@ -181,6 +203,4 @@ QStringList Data::filter()
|
||||
void Data::useDEM(bool use)
|
||||
{
|
||||
_useDEM = use;
|
||||
Route::useDEM(use);
|
||||
Track::useDEM(use);
|
||||
}
|
||||
|
@ -31,8 +31,7 @@ public:
|
||||
static void useDEM(bool use);
|
||||
|
||||
private:
|
||||
void processData(const QList<TrackData> &trackData,
|
||||
const QList<RouteData> &routeData);
|
||||
void processData(QList<TrackData> &trackData, QList<RouteData> &routeData);
|
||||
|
||||
bool _valid;
|
||||
QString _errorString;
|
||||
|
@ -265,6 +265,14 @@ bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
||||
if (val != 0x7f)
|
||||
ctx.trackpoint.setTemperature((qint8)val);
|
||||
break;
|
||||
case 73:
|
||||
if (val != 0xffffffff)
|
||||
ctx.trackpoint.setSpeed(val / 1000.0f);
|
||||
break;
|
||||
case 78:
|
||||
if (val != 0xffffffff)
|
||||
ctx.trackpoint.setElevation((val / 5.0) - 500);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
|
@ -54,6 +54,7 @@ public:
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hasTime() const
|
||||
{
|
||||
for (int i = 0; i < size(); i++) {
|
||||
|
@ -130,6 +130,8 @@ bool IGCParser::readBRecord(SegmentData &segment, const char *line,
|
||||
|
||||
if (len < 35)
|
||||
return false;
|
||||
if (line[24] != 'A')
|
||||
return true;
|
||||
|
||||
if (!readTimestamp(line + 1, time)) {
|
||||
_errorString = "Invalid timestamp";
|
||||
|
@ -1,9 +1,6 @@
|
||||
#include "dem.h"
|
||||
#include "route.h"
|
||||
|
||||
|
||||
bool Route::_useDEM = false;
|
||||
|
||||
Route::Route(const RouteData &data) : _data(data)
|
||||
{
|
||||
qreal dist = 0;
|
||||
@ -34,19 +31,9 @@ Graph Route::elevation() const
|
||||
graph.append(GraphSegment());
|
||||
GraphSegment &gs = graph.last();
|
||||
|
||||
for (int i = 0; i < _data.size(); i++) {
|
||||
if (_data.at(i).hasElevation() && !_useDEM)
|
||||
gs.append(GraphPoint(_distance.at(i), NAN,
|
||||
_data.at(i).elevation()));
|
||||
else {
|
||||
qreal elevation = DEM::elevation(_data.at(i).coordinates());
|
||||
if (!std::isnan(elevation))
|
||||
gs.append(GraphPoint(_distance.at(i), NAN, elevation));
|
||||
else if (_data.at(i).hasElevation())
|
||||
gs.append(GraphPoint(_distance.at(i), NAN,
|
||||
_data.at(i).elevation()));
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < _data.size(); i++)
|
||||
if (_data.at(i).hasElevation())
|
||||
gs.append(GraphPoint(_distance.at(i), NAN, _data.at(i).elevation()));
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ public:
|
||||
|
||||
Path path() const;
|
||||
|
||||
const QVector<Waypoint> &waypoints() const {return _data;}
|
||||
const RouteData &data() const {return _data;}
|
||||
|
||||
Graph elevation() const;
|
||||
|
||||
@ -24,13 +24,9 @@ public:
|
||||
|
||||
bool isValid() const {return _data.size() >= 2;}
|
||||
|
||||
static void useDEM(bool use) {_useDEM = use;}
|
||||
|
||||
private:
|
||||
RouteData _data;
|
||||
QVector<qreal> _distance;
|
||||
|
||||
static bool _useDEM;
|
||||
};
|
||||
|
||||
#endif // ROUTE_H
|
||||
|
@ -1,4 +1,3 @@
|
||||
#include "dem.h"
|
||||
#include "track.h"
|
||||
|
||||
|
||||
@ -13,7 +12,6 @@ int Track::_pauseInterval = 10;
|
||||
|
||||
bool Track::_outlierEliminate = true;
|
||||
bool Track::_useReportedSpeed = false;
|
||||
bool Track::_useDEM = false;
|
||||
|
||||
|
||||
static qreal median(QVector<qreal> &v)
|
||||
@ -178,21 +176,10 @@ Graph Track::elevation() const
|
||||
GraphSegment gs;
|
||||
|
||||
for (int j = 0; j < sd.size(); j++) {
|
||||
if (seg.outliers.contains(j))
|
||||
if (!sd.at(j).hasElevation() || seg.outliers.contains(j))
|
||||
continue;
|
||||
|
||||
if (sd.at(j).hasElevation() && !_useDEM)
|
||||
gs.append(GraphPoint(seg.distance.at(j), seg.time.at(j),
|
||||
sd.at(j).elevation()));
|
||||
else {
|
||||
qreal elevation = DEM::elevation(sd.at(j).coordinates());
|
||||
if (!std::isnan(elevation))
|
||||
gs.append(GraphPoint(seg.distance.at(j), seg.time.at(j),
|
||||
elevation));
|
||||
else if (sd.at(j).hasElevation())
|
||||
gs.append(GraphPoint(seg.distance.at(j), seg.time.at(j),
|
||||
sd.at(j).elevation()));
|
||||
}
|
||||
gs.append(GraphPoint(seg.distance.at(j), seg.time.at(j),
|
||||
sd.at(j).elevation()));
|
||||
}
|
||||
|
||||
ret.append(filter(gs, _elevationWindow));
|
||||
|
@ -45,7 +45,6 @@ public:
|
||||
static void setOutlierElimination(bool eliminate)
|
||||
{_outlierEliminate = eliminate;}
|
||||
static void useReportedSpeed(bool use) {_useReportedSpeed = use;}
|
||||
static void useDEM(bool use) {_useDEM = use;}
|
||||
|
||||
private:
|
||||
struct Segment {
|
||||
@ -71,7 +70,6 @@ private:
|
||||
static qreal _pauseSpeed;
|
||||
static int _pauseInterval;
|
||||
static bool _useReportedSpeed;
|
||||
static bool _useDEM;
|
||||
};
|
||||
|
||||
#endif // TRACK_H
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#define CHECK(condition) \
|
||||
if (!(condition)) { \
|
||||
_errorString = "Invalid/corrupted IMG file"; \
|
||||
_errorString = "Unsupported or invalid IMG file"; \
|
||||
return; \
|
||||
}
|
||||
|
||||
@ -85,11 +85,6 @@ IMG::IMG(const QString &fileName)
|
||||
&& read(type, sizeof(type)) && readValue(size) && readValue(part));
|
||||
SubFile::Type tt = SubFile::type(type);
|
||||
|
||||
if (tt == SubFile::GMP) {
|
||||
_errorString = "NT maps not supported";
|
||||
return;
|
||||
}
|
||||
|
||||
QString fn(QByteArray(name, sizeof(name)));
|
||||
if (SubFile::isTileFile(tt)) {
|
||||
VectorTile *tile;
|
||||
@ -101,7 +96,7 @@ IMG::IMG(const QString &fileName)
|
||||
tile = *it;
|
||||
|
||||
SubFile *file = part ? tile->file(tt)
|
||||
: tile->addFile(this, tt, size);
|
||||
: tile->addFile(this, tt);
|
||||
CHECK(file);
|
||||
|
||||
_file.seek(offset + 0x20);
|
||||
@ -114,7 +109,7 @@ IMG::IMG(const QString &fileName)
|
||||
} else if (tt == SubFile::TYP) {
|
||||
SubFile *typ = 0;
|
||||
if (typFile.isNull()) {
|
||||
_typ = new SubFile(this, size);
|
||||
_typ = new SubFile(this);
|
||||
typ = _typ;
|
||||
typFile = fn;
|
||||
} else if (fn == typFile)
|
||||
@ -166,7 +161,7 @@ void IMG::load()
|
||||
{
|
||||
Q_ASSERT(!_style);
|
||||
|
||||
if (_typ && _typ->isValid())
|
||||
if (_typ)
|
||||
_style = new Style(_typ);
|
||||
else {
|
||||
QFile typFile(ProgramPaths::typFile());
|
||||
|
@ -56,11 +56,11 @@ bool LBLFile::init()
|
||||
quint16 codepage;
|
||||
quint8 multiplier, poiMultiplier;
|
||||
|
||||
if (!(seek(hdl, 0x15) && readUInt32(hdl, _offset)
|
||||
if (!(seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset)
|
||||
&& readUInt32(hdl, _size) && readByte(hdl, multiplier)
|
||||
&& readByte(hdl, _encoding) && seek(hdl, 0x57)
|
||||
&& readByte(hdl, _encoding) && seek(hdl, _gmpOffset + 0x57)
|
||||
&& readUInt32(hdl, _poiOffset) && readUInt32(hdl, _poiSize)
|
||||
&& readByte(hdl, poiMultiplier) && seek(hdl, 0xAA)
|
||||
&& readByte(hdl, poiMultiplier) && seek(hdl, _gmpOffset + 0xAA)
|
||||
&& readUInt16(hdl, codepage)))
|
||||
return false;
|
||||
|
||||
|
@ -9,9 +9,12 @@ class QTextCodec;
|
||||
class LBLFile : public SubFile
|
||||
{
|
||||
public:
|
||||
LBLFile(IMG *img, quint32 size)
|
||||
: SubFile(img, size), _codec(0), _offset(0), _size(0), _poiOffset(0),
|
||||
LBLFile(IMG *img)
|
||||
: SubFile(img), _codec(0), _offset(0), _size(0), _poiOffset(0),
|
||||
_poiSize(0), _poiMultiplier(0), _multiplier(0), _encoding(0) {}
|
||||
LBLFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
|
||||
_codec(0), _offset(0), _size(0), _poiOffset(0), _poiSize(0),
|
||||
_poiMultiplier(0), _multiplier(0), _encoding(0) {}
|
||||
|
||||
Label label(Handle &hdl, quint32 offset, bool poi = false);
|
||||
|
||||
|
@ -5,7 +5,7 @@ bool NETFile::init()
|
||||
Handle hdl;
|
||||
quint8 multiplier;
|
||||
|
||||
if (!(seek(hdl, 0x15) && readUInt32(hdl, _offset)
|
||||
if (!(seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset)
|
||||
&& readUInt32(hdl, _size) && readByte(hdl, multiplier)))
|
||||
return false;
|
||||
|
||||
|
@ -6,8 +6,9 @@
|
||||
class NETFile : public SubFile
|
||||
{
|
||||
public:
|
||||
NETFile(IMG *img, quint32 size)
|
||||
: SubFile(img, size), _offset(0), _size(0), _multiplier(0) {}
|
||||
NETFile(IMG *img) : SubFile(img), _offset(0), _size(0), _multiplier(0) {}
|
||||
NETFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
|
||||
_offset(0), _size(0), _multiplier(0) {}
|
||||
|
||||
bool lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset);
|
||||
|
||||
|
@ -1,10 +1,26 @@
|
||||
#include "trefile.h"
|
||||
#include "common/rectc.h"
|
||||
#include "units.h"
|
||||
#include "lblfile.h"
|
||||
#include "netfile.h"
|
||||
#include "rgnfile.h"
|
||||
|
||||
|
||||
static int bitSize(quint8 baseSize, bool variableSign, bool extraBit)
|
||||
{
|
||||
int bits = 2;
|
||||
if (baseSize <= 9)
|
||||
bits += baseSize;
|
||||
else
|
||||
bits += 2 * baseSize - 9;
|
||||
|
||||
if (variableSign)
|
||||
bits++;
|
||||
if (extraBit)
|
||||
bits++;
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
bool RGNFile::BitStream::read(int bits, quint32 &val)
|
||||
{
|
||||
val = 0;
|
||||
@ -34,29 +50,42 @@ bool RGNFile::BitStream::read(int bits, quint32 &val)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RGNFile::BitStream::readDelta(int bits, int sign, bool extraBit,
|
||||
RGNFile::DeltaStream::DeltaStream(const SubFile &file, Handle &hdl,
|
||||
quint32 length, quint8 info, bool extraBit, bool extended)
|
||||
: BitStream(file, hdl, length), _readBits(0xFFFFFFFF)
|
||||
{
|
||||
_extraBit = extraBit ? 1 : 0;
|
||||
if (!(sign(_lonSign) && sign(_latSign)))
|
||||
return;
|
||||
if (extended) {
|
||||
quint32 b;
|
||||
if (!read(1, b))
|
||||
return;
|
||||
}
|
||||
_lonBits = bitSize(info & 0x0F, !_lonSign, extraBit);
|
||||
_latBits = bitSize(info >> 4, !_latSign, false);
|
||||
_readBits = _lonBits + _latBits;
|
||||
}
|
||||
|
||||
bool RGNFile::DeltaStream::readDelta(int bits, int sign, int extraBit,
|
||||
qint32 &delta)
|
||||
{
|
||||
quint32 value;
|
||||
int bo = 0;
|
||||
|
||||
if (!read(bits, value))
|
||||
return false;
|
||||
|
||||
if (extraBit) {
|
||||
value>>=1;
|
||||
bo = 1;
|
||||
}
|
||||
value >>= extraBit;
|
||||
|
||||
if (!sign) {
|
||||
qint32 signMask = 1 << (bits - bo - 1);
|
||||
qint32 signMask = 1 << (bits - extraBit - 1);
|
||||
if (value & signMask) {
|
||||
qint32 comp = value ^ signMask;
|
||||
if (comp)
|
||||
delta = comp - signMask;
|
||||
else {
|
||||
qint32 other;
|
||||
if (!readDelta(bits - bo, sign, false, other))
|
||||
if (!readDelta(bits - extraBit, sign, false, other))
|
||||
return false;
|
||||
if (other < 0)
|
||||
delta = 1 - signMask + other;
|
||||
@ -73,42 +102,15 @@ bool RGNFile::BitStream::readDelta(int bits, int sign, bool extraBit,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RGNFile::BitStream::finish()
|
||||
{
|
||||
while (_length--)
|
||||
if (!_file.readByte(_hdl, _data))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool RGNFile::init()
|
||||
{
|
||||
Handle hdl;
|
||||
|
||||
if (!(seek(hdl, 0x15) && readUInt32(hdl, _offset)
|
||||
&& readUInt32(hdl, _size) && readUInt32(hdl, _polygonsOffset)
|
||||
&& readUInt32(hdl, _polygonsSize) && seek(hdl, 0x39)
|
||||
&& readUInt32(hdl, _linesOffset) && readUInt32(hdl, _linesSize)
|
||||
&& seek(hdl, 0x55) && readUInt32(hdl, _pointsOffset)
|
||||
&& readUInt32(hdl, _pointsSize)))
|
||||
return false;
|
||||
|
||||
if (_offset + _size > size())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RGNFile::sign(BitStream &bs, int &val)
|
||||
bool RGNFile::DeltaStream::sign(int &val)
|
||||
{
|
||||
quint32 bit;
|
||||
val = 0;
|
||||
|
||||
if (!bs.read(1, bit))
|
||||
if (!read(1, bit))
|
||||
return false;
|
||||
if (bit) {
|
||||
if (!bs.read(1, bit))
|
||||
if (!read(1, bit))
|
||||
return false;
|
||||
val = bit ? -1 : 1;
|
||||
}
|
||||
@ -116,20 +118,41 @@ bool RGNFile::sign(BitStream &bs, int &val)
|
||||
return true;
|
||||
}
|
||||
|
||||
int RGNFile::bitSize(quint8 baseSize, bool variableSign, bool extraBit)
|
||||
|
||||
bool RGNFile::init()
|
||||
{
|
||||
int bits = 2;
|
||||
if (baseSize <= 9)
|
||||
bits += baseSize;
|
||||
else
|
||||
bits += 2 * baseSize - 9;
|
||||
Handle hdl;
|
||||
quint16 hdrLen;
|
||||
|
||||
if (variableSign)
|
||||
bits++;
|
||||
if (extraBit)
|
||||
bits++;
|
||||
if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)
|
||||
&& seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset)
|
||||
&& readUInt32(hdl, _size)))
|
||||
return false;
|
||||
|
||||
return bits;
|
||||
if (hdrLen >= 0x5D) {
|
||||
if (!(readUInt32(hdl, _polygonsOffset) && readUInt32(hdl, _polygonsSize)
|
||||
&& seek(hdl, _gmpOffset + 0x39) && readUInt32(hdl, _linesOffset)
|
||||
&& readUInt32(hdl, _linesSize) && seek(hdl, _gmpOffset + 0x55)
|
||||
&& readUInt32(hdl, _pointsOffset) && readUInt32(hdl, _pointsSize)))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hdrLen >= 0x7D) {
|
||||
quint32 dictOffset, dictSize;
|
||||
if (!(seek(hdl, _gmpOffset + 0x71) && readUInt32(hdl, dictOffset)
|
||||
&& readUInt32(hdl, dictSize)))
|
||||
return false;
|
||||
|
||||
// NT maps
|
||||
if (dictSize || dictOffset) {
|
||||
qWarning("NT compression not supported");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
_init = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RGNFile::polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
|
||||
@ -167,28 +190,17 @@ bool RGNFile::polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
|
||||
poly.type = (segment.type() == Segment::Polygon)
|
||||
? ((quint32)(type & 0x7F)) << 8 : ((quint32)(type & 0x3F)) << 8;
|
||||
|
||||
RectC br;
|
||||
|
||||
QPoint pos(subdiv->lon() + ((qint32)lon<<(24-subdiv->bits())),
|
||||
subdiv->lat() + ((qint32)lat<<(24-subdiv->bits())));
|
||||
Coordinates c(toWGS84(pos.x()), toWGS84(pos.y()));
|
||||
br = br.united(c);
|
||||
RectC br(c, c);
|
||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||
|
||||
BitStream bs(*this, hdl, len);
|
||||
int lonSign, latSign;
|
||||
if (!sign(bs, lonSign) || !sign(bs, latSign))
|
||||
return false;
|
||||
bool extraBit = labelPtr & 0x400000;
|
||||
int lonBits = bitSize(bitstreamInfo & 0x0F, !lonSign, extraBit);
|
||||
int latBits = bitSize(bitstreamInfo >> 4, !latSign, false);
|
||||
|
||||
while (bs.hasNext(lonBits + latBits)) {
|
||||
qint32 lonDelta, latDelta;
|
||||
|
||||
if (!(bs.readDelta(lonBits, lonSign, extraBit, lonDelta)
|
||||
&& bs.readDelta(latBits, latSign, false, latDelta)))
|
||||
return false;
|
||||
|
||||
qint32 lonDelta, latDelta;
|
||||
DeltaStream stream(*this, hdl, len, bitstreamInfo, labelPtr & 0x400000,
|
||||
false);
|
||||
while (stream.readNext(lonDelta, latDelta)) {
|
||||
pos.rx() += lonDelta<<(24-subdiv->bits());
|
||||
pos.ry() += latDelta<<(24-subdiv->bits());
|
||||
|
||||
@ -196,7 +208,7 @@ bool RGNFile::polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
|
||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||
br = br.united(c);
|
||||
}
|
||||
if (!bs.finish())
|
||||
if (!(stream.atEnd() && stream.flush()))
|
||||
return false;
|
||||
|
||||
if (!rect.intersects(br))
|
||||
@ -222,10 +234,9 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
|
||||
const SubDiv *subdiv, const Segment &segment, LBLFile *lbl, Handle &lblHdl,
|
||||
QList<IMG::Poly> *polys) const
|
||||
{
|
||||
quint32 labelPtr;
|
||||
quint8 type, subtype, len8, len82, bitstreamInfo;
|
||||
quint32 len, labelPtr = 0;
|
||||
quint8 type, subtype, bitstreamInfo;
|
||||
qint16 lon, lat;
|
||||
quint16 len;
|
||||
|
||||
|
||||
if (!seek(hdl, segment.start()))
|
||||
@ -235,7 +246,8 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
|
||||
IMG::Poly poly;
|
||||
|
||||
if (!(readByte(hdl, type) && readByte(hdl, subtype)
|
||||
&& readInt16(hdl, lon) && readInt16(hdl, lat) && readByte(hdl, len8)))
|
||||
&& readInt16(hdl, lon) && readInt16(hdl, lat)
|
||||
&& readVUInt32(hdl, len) && readByte(hdl, bitstreamInfo)))
|
||||
return false;
|
||||
|
||||
if (subtype & 0x80) {
|
||||
@ -243,40 +255,17 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (len8 & 0x01)
|
||||
len = (len8>>1) - 1;
|
||||
else {
|
||||
if (!readByte(hdl, len82))
|
||||
return false;
|
||||
len = ((len8 | ((quint16)len82<<8))>>2) - 1;
|
||||
}
|
||||
if (!readByte(hdl, bitstreamInfo))
|
||||
return false;
|
||||
poly.type = 0x10000 + (quint16(type) << 8) + (subtype & 0x1F);
|
||||
|
||||
RectC br;
|
||||
QPoint pos(subdiv->lon() + ((qint32)lon<<(24-subdiv->bits())),
|
||||
subdiv->lat() + ((qint32)lat<<(24-subdiv->bits())));
|
||||
Coordinates c(toWGS84(pos.x()), toWGS84(pos.y()));
|
||||
br = br.united(c);
|
||||
RectC br(c, c);
|
||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||
|
||||
BitStream bs(*this, hdl, len);
|
||||
int lonSign, latSign;
|
||||
if (!sign(bs, lonSign) || !sign(bs, latSign))
|
||||
return false;
|
||||
quint32 extraBit;
|
||||
bs.read(1, extraBit);
|
||||
int lonBits = bitSize(bitstreamInfo & 0x0F, !lonSign, extraBit);
|
||||
int latBits = bitSize(bitstreamInfo >> 4, !latSign, extraBit);
|
||||
|
||||
while (bs.hasNext(lonBits + latBits)) {
|
||||
qint32 lonDelta, latDelta;
|
||||
|
||||
if (!(bs.readDelta(lonBits, lonSign, false, lonDelta)
|
||||
&& bs.readDelta(latBits, latSign, false, latDelta)))
|
||||
return false;
|
||||
|
||||
qint32 lonDelta, latDelta;
|
||||
DeltaStream stream(*this, hdl, len - 1, bitstreamInfo, false, true);
|
||||
while (stream.readNext(lonDelta, latDelta)) {
|
||||
pos.rx() += lonDelta<<(24-subdiv->bits());
|
||||
pos.ry() += latDelta<<(24-subdiv->bits());
|
||||
|
||||
@ -284,19 +273,21 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
|
||||
poly.points.append(QPointF(c.lon(), c.lat()));
|
||||
br = br.united(c);
|
||||
}
|
||||
if (!bs.finish())
|
||||
if (!(stream.atEnd() && stream.flush()))
|
||||
return false;
|
||||
|
||||
if (subtype & 0x20) {
|
||||
if ((subtype & 0x20)) {
|
||||
if (!readUInt24(hdl, labelPtr))
|
||||
return false;
|
||||
if (lbl && (labelPtr & 0x3FFFFF))
|
||||
poly.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF);
|
||||
}
|
||||
} else
|
||||
labelPtr = 0;
|
||||
|
||||
if (!rect.intersects(br))
|
||||
continue;
|
||||
|
||||
if (lbl && (labelPtr & 0x3FFFFF))
|
||||
poly.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF);
|
||||
|
||||
polys->append(poly);
|
||||
}
|
||||
|
||||
@ -404,7 +395,7 @@ void RGNFile::objects(const RectC &rect, const SubDiv *subdiv, LBLFile *lbl,
|
||||
{
|
||||
Handle rgnHdl, lblHdl, netHdl;
|
||||
|
||||
if (!_size && !init())
|
||||
if (!_init && !init())
|
||||
return;
|
||||
|
||||
QVector<RGNFile::Segment> seg(segments(rgnHdl, subdiv));
|
||||
@ -436,7 +427,7 @@ void RGNFile::extObjects(const RectC &rect, const SubDiv *subdiv, LBLFile *lbl,
|
||||
{
|
||||
Handle rgnHdl, lblHdl;
|
||||
|
||||
if (!_size && !init())
|
||||
if (!_init && !init())
|
||||
return;
|
||||
|
||||
if (polygons && subdiv->polygonsOffset() != subdiv->polygonsEnd()) {
|
||||
|
@ -11,10 +11,13 @@ class NETFile;
|
||||
class RGNFile : public SubFile
|
||||
{
|
||||
public:
|
||||
RGNFile(IMG *img, quint32 size)
|
||||
: SubFile(img, size), _offset(0), _size(0), _polygonsOffset(0),
|
||||
_polygonsSize(), _linesOffset(), _linesSize(), _pointsOffset(),
|
||||
_pointsSize() {}
|
||||
RGNFile(IMG *img)
|
||||
: SubFile(img), _offset(0), _size(0), _polygonsOffset(0),
|
||||
_polygonsSize(0), _linesOffset(0), _linesSize(0), _pointsOffset(0),
|
||||
_pointsSize(0), _init(false) {}
|
||||
RGNFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset), _offset(0),
|
||||
_size(0), _polygonsOffset(0), _polygonsSize(0), _linesOffset(0),
|
||||
_linesSize(0), _pointsOffset(0), _pointsSize(0), _init(false) {}
|
||||
|
||||
void objects(const RectC &rect, const SubDiv *subdiv, LBLFile *lbl,
|
||||
NETFile *net, QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines,
|
||||
@ -53,27 +56,45 @@ private:
|
||||
|
||||
class BitStream {
|
||||
public:
|
||||
BitStream(const SubFile &file, Handle &hdl, quint16 length)
|
||||
BitStream(const SubFile &file, Handle &hdl, quint32 length)
|
||||
: _file(file), _hdl(hdl), _length(length), _remaining(0) {}
|
||||
|
||||
bool read(int bits, quint32 &val);
|
||||
bool readDelta(int bits, int sign, bool extraBit, qint32 &delta);
|
||||
bool hasNext(int bits) const
|
||||
{return _length * 8 + _remaining >= (quint32)bits;}
|
||||
bool finish();
|
||||
bool flush() {return _file.seek(_hdl, _hdl.pos + _length);}
|
||||
quint32 bitsAvailable() const {return _length * 8 + _remaining;}
|
||||
|
||||
private:
|
||||
const SubFile &_file;
|
||||
Handle &_hdl;
|
||||
quint16 _length;
|
||||
quint32 _remaining;
|
||||
quint32 _length, _remaining;
|
||||
quint8 _data;
|
||||
};
|
||||
|
||||
static bool sign(BitStream &bs, int &val);
|
||||
static int bitSize(quint8 baseSize, bool variableSign, bool extraBit);
|
||||
class DeltaStream : public BitStream {
|
||||
public:
|
||||
DeltaStream(const SubFile &file, Handle &hdl, quint32 length,
|
||||
quint8 info, bool extraBit, bool extended);
|
||||
|
||||
bool readNext(qint32 &lonDelta, qint32 &latDelta)
|
||||
{
|
||||
return hasNext()
|
||||
? (readDelta(_lonBits, _lonSign, _extraBit, lonDelta)
|
||||
&& readDelta(_latBits, _latSign, false, latDelta))
|
||||
: false;
|
||||
}
|
||||
bool atEnd() const {return (_readBits != 0xFFFFFFFF && !hasNext());}
|
||||
|
||||
private:
|
||||
bool hasNext() const {return bitsAvailable() >= _readBits;}
|
||||
bool sign(int &val);
|
||||
bool readDelta(int bits, int sign, int extraBit, qint32 &delta);
|
||||
|
||||
int _lonSign, _latSign, _extraBit;
|
||||
quint32 _lonBits, _latBits, _readBits;
|
||||
};
|
||||
|
||||
bool init();
|
||||
|
||||
QVector<Segment> segments(Handle &hdl, const SubDiv *subdiv) const;
|
||||
bool polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
|
||||
const Segment &segment, LBLFile *lbl, Handle &lblHdl, NETFile *net,
|
||||
@ -99,6 +120,8 @@ private:
|
||||
quint32 _linesSize;
|
||||
quint32 _pointsOffset;
|
||||
quint32 _pointsSize;
|
||||
|
||||
bool _init;
|
||||
};
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
|
@ -942,7 +942,7 @@ Style::Style(SubFile *typ)
|
||||
defaultPolygonStyle();
|
||||
defaultPointStyle();
|
||||
|
||||
if (typ && typ->isValid())
|
||||
if (typ)
|
||||
parseTYPFile(typ);
|
||||
}
|
||||
|
||||
|
@ -20,21 +20,13 @@ SubFile::Type SubFile::type(const char str[3])
|
||||
return Unknown;
|
||||
}
|
||||
|
||||
SubFile::SubFile(QFile *file) : _img(0), _file(file), _size(0)
|
||||
SubFile::SubFile(QFile *file) :_gmpOffset(0), _img(0), _file(file), _blocks(0)
|
||||
{
|
||||
if (!_file->open(QIODevice::ReadOnly))
|
||||
qWarning("Error opening %s: %s", qPrintable(_file->fileName()),
|
||||
qPrintable(_file->errorString()));
|
||||
}
|
||||
|
||||
bool SubFile::isValid() const
|
||||
{
|
||||
return _file
|
||||
? _file->isOpen()
|
||||
: ((quint32)_img->blockSize() * (quint32)_blocks.size() - _size
|
||||
< (quint32)_img->blockSize());
|
||||
}
|
||||
|
||||
bool SubFile::seek(Handle &handle, quint32 pos) const
|
||||
{
|
||||
Q_ASSERT(_img || _file);
|
||||
@ -46,9 +38,9 @@ bool SubFile::seek(Handle &handle, quint32 pos) const
|
||||
int blockNum = pos / blockSize;
|
||||
|
||||
if (handle.blockNum != blockNum) {
|
||||
if (blockNum >= _blocks.size())
|
||||
if (blockNum >= _blocks->size())
|
||||
return false;
|
||||
if (!_img->readBlock(_blocks.at(blockNum), handle.data))
|
||||
if (!_img->readBlock(_blocks->at(blockNum), handle.data))
|
||||
return false;
|
||||
handle.blockNum = blockNum;
|
||||
}
|
||||
@ -74,9 +66,35 @@ bool SubFile::readByte(Handle &handle, quint8 &val) const
|
||||
}
|
||||
}
|
||||
|
||||
quint32 SubFile::size() const
|
||||
bool SubFile::readVUInt32(Handle &hdl, quint32 &val) const
|
||||
{
|
||||
return _file ? (quint32)_file->size() : _size;
|
||||
quint8 bytes, shift, b;
|
||||
|
||||
if (!readByte(hdl, b))
|
||||
return false;
|
||||
|
||||
if ((b & 1) == 0) {
|
||||
if ((b & 2) == 0) {
|
||||
bytes = ((b >> 2) & 1) ^ 3;
|
||||
shift = 5;
|
||||
} else {
|
||||
shift = 6;
|
||||
bytes = 1;
|
||||
}
|
||||
} else {
|
||||
shift = 7;
|
||||
bytes = 0;
|
||||
}
|
||||
|
||||
val = b >> (8 - shift);
|
||||
|
||||
for (int i = 1; i <= bytes; i++) {
|
||||
if (!readByte(hdl, b))
|
||||
return false;
|
||||
val |= (((quint32)b) << (i * 8)) >> (8 - shift);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString SubFile::fileName() const
|
||||
@ -88,15 +106,15 @@ QString SubFile::fileName() const
|
||||
QDebug operator<<(QDebug dbg, const SubFile &file)
|
||||
{
|
||||
bool continuous = true;
|
||||
for (int i = 1; i < file._blocks.size(); i++) {
|
||||
if (file._blocks.at(i) != file._blocks.at(i-1) + 1) {
|
||||
for (int i = 1; i < file._blocks->size(); i++) {
|
||||
if (file._blocks->at(i) != file._blocks->at(i-1) + 1) {
|
||||
continuous = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dbg.nospace() << "SubFile(" << file._size << ", " << file._blocks.size()
|
||||
<< ", " << continuous << ")";
|
||||
dbg.nospace() << "SubFile(" << file._blocks->size() << ", "
|
||||
<< continuous << ")";
|
||||
return dbg.space();
|
||||
}
|
||||
#endif // QT_NO_DEBUG
|
||||
|
@ -22,13 +22,14 @@ public:
|
||||
int pos;
|
||||
};
|
||||
|
||||
SubFile(IMG *img, quint32 size) : _img(img), _file(0), _size(size) {}
|
||||
SubFile(IMG *img) : _gmpOffset(0), _img(img), _file(0),
|
||||
_blocks(&_blockData) {}
|
||||
SubFile(SubFile *gmp, quint32 offset) : _gmpOffset(offset), _img(gmp->_img),
|
||||
_file(0), _blocks(&(gmp->_blockData)) {}
|
||||
SubFile(QFile *file);
|
||||
|
||||
void addBlock(quint16 block) {_blocks.append(block);}
|
||||
bool isValid() const;
|
||||
void addBlock(quint16 block) {_blocks->append(block);}
|
||||
|
||||
quint32 size() const;
|
||||
bool seek(Handle &handle, quint32 pos) const;
|
||||
bool readByte(Handle &handle, quint8 &val) const;
|
||||
|
||||
@ -80,20 +81,28 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
quint16 offset() const {return _blocks.first();}
|
||||
bool readVUInt32(Handle &hdl, quint32 &val) const;
|
||||
|
||||
quint16 offset() const {return _blocks->first();}
|
||||
QString fileName() const;
|
||||
|
||||
static Type type(const char str[3]);
|
||||
static bool isTileFile(Type type)
|
||||
{return (type == TRE || type == LBL || type == RGN || type == NET);}
|
||||
{
|
||||
return (type == TRE || type == LBL || type == RGN || type == NET
|
||||
|| type == GMP);
|
||||
}
|
||||
|
||||
friend QDebug operator<<(QDebug dbg, const SubFile &file);
|
||||
|
||||
protected:
|
||||
quint32 _gmpOffset;
|
||||
|
||||
private:
|
||||
IMG *_img;
|
||||
QFile *_file;
|
||||
quint32 _size;
|
||||
QVector<quint16> _blocks;
|
||||
QVector<quint16> *_blocks;
|
||||
QVector<quint16> _blockData;
|
||||
};
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
|
@ -43,28 +43,28 @@ bool TREFile::init()
|
||||
quint8 locked;
|
||||
quint16 hdrLen;
|
||||
|
||||
if (!(seek(hdl, 0) && readUInt16(hdl, hdrLen)
|
||||
&& seek(hdl, 0x0D) && readByte(hdl, locked)))
|
||||
if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)
|
||||
&& seek(hdl, _gmpOffset + 0x0D) && readByte(hdl, locked)))
|
||||
return false;
|
||||
|
||||
// Tile bounds
|
||||
qint32 north, east, south, west;
|
||||
if (!(seek(hdl, 0x15) && readInt24(hdl, north) && readInt24(hdl, east)
|
||||
&& readInt24(hdl, south) && readInt24(hdl, west)))
|
||||
if (!(seek(hdl, _gmpOffset + 0x15) && readInt24(hdl, north)
|
||||
&& readInt24(hdl, east) && readInt24(hdl, south) && readInt24(hdl, west)))
|
||||
return false;
|
||||
_bounds = RectC(Coordinates(toWGS84(west), toWGS84(north)),
|
||||
Coordinates(toWGS84(east), toWGS84(south)));
|
||||
|
||||
// Levels & subdivs info
|
||||
quint32 levelsOffset, levelsSize, subdivSize;
|
||||
if (!(seek(hdl, 0x21) && readUInt32(hdl, levelsOffset)
|
||||
if (!(seek(hdl, _gmpOffset + 0x21) && readUInt32(hdl, levelsOffset)
|
||||
&& readUInt32(hdl, levelsSize) && readUInt32(hdl, _subdivOffset)
|
||||
&& readUInt32(hdl, subdivSize)))
|
||||
return false;
|
||||
|
||||
// TRE7 info
|
||||
if (hdrLen > 0x9A) {
|
||||
if (!(seek(hdl, 0x7C) && readUInt32(hdl, _extended.offset)
|
||||
if (!(seek(hdl, _gmpOffset + 0x7C) && readUInt32(hdl, _extended.offset)
|
||||
&& readUInt32(hdl, _extended.size)
|
||||
&& readUInt16(hdl, _extended.itemSize)))
|
||||
return false;
|
||||
@ -80,7 +80,7 @@ bool TREFile::init()
|
||||
if (locked) {
|
||||
quint32 key;
|
||||
quint8 unlocked[64];
|
||||
if (!seek(hdl, 0xAA) || !readUInt32(hdl, key))
|
||||
if (!seek(hdl, _gmpOffset + 0xAA) || !readUInt32(hdl, key))
|
||||
return false;
|
||||
unlock(unlocked, levels, levelsSize, key);
|
||||
memcpy(levels, unlocked, levelsSize);
|
||||
|
@ -13,7 +13,8 @@ class SubDiv;
|
||||
class TREFile : public SubFile
|
||||
{
|
||||
public:
|
||||
TREFile(IMG *img, quint32 size) : SubFile(img, size) {}
|
||||
TREFile(IMG *img) : SubFile(img) {}
|
||||
TREFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset) {}
|
||||
~TREFile();
|
||||
|
||||
bool init();
|
||||
|
@ -11,26 +11,31 @@ SubFile *VectorTile::file(SubFile::Type type)
|
||||
return _lbl;
|
||||
case SubFile::NET:
|
||||
return _net;
|
||||
case SubFile::GMP:
|
||||
return _gmp;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
SubFile *VectorTile::addFile(IMG *img, SubFile::Type type, quint32 size)
|
||||
SubFile *VectorTile::addFile(IMG *img, SubFile::Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case SubFile::TRE:
|
||||
_tre = new TREFile(img, size);
|
||||
_tre = new TREFile(img);
|
||||
return _tre;
|
||||
case SubFile::RGN:
|
||||
_rgn = new RGNFile(img, size);
|
||||
_rgn = new RGNFile(img);
|
||||
return _rgn;
|
||||
case SubFile::LBL:
|
||||
_lbl = new LBLFile(img, size);
|
||||
_lbl = new LBLFile(img);
|
||||
return _lbl;
|
||||
case SubFile::NET:
|
||||
_net = new NETFile(img, size);
|
||||
_net = new NETFile(img);
|
||||
return _net;
|
||||
case SubFile::GMP:
|
||||
_gmp = new SubFile(img);
|
||||
return _gmp;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -38,14 +43,30 @@ SubFile *VectorTile::addFile(IMG *img, SubFile::Type type, quint32 size)
|
||||
|
||||
bool VectorTile::init()
|
||||
{
|
||||
if (!(_tre && _tre->isValid() && _tre->init() && _rgn
|
||||
&& _rgn->isValid()))
|
||||
if (_gmp && !initGMP())
|
||||
return false;
|
||||
if (_lbl && !_lbl->isValid())
|
||||
|
||||
if (!(_tre && _tre->init() && _rgn))
|
||||
return false;
|
||||
if (_net && !_net->isValid())
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VectorTile::initGMP()
|
||||
{
|
||||
SubFile::Handle hdl;
|
||||
quint32 tre, rgn, lbl, net;
|
||||
|
||||
if (!(_gmp->seek(hdl, 0x19) && _gmp->readUInt32(hdl, tre)
|
||||
&& _gmp->readUInt32(hdl, rgn) && _gmp->readUInt32(hdl, lbl)
|
||||
&& _gmp->readUInt32(hdl, net)))
|
||||
return false;
|
||||
|
||||
_tre = new TREFile(_gmp, tre);
|
||||
_rgn = new RGNFile(_gmp, rgn);
|
||||
_lbl = new LBLFile(_gmp, lbl);
|
||||
_net = new NETFile(_gmp, net);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -10,8 +10,9 @@
|
||||
|
||||
class VectorTile {
|
||||
public:
|
||||
VectorTile() : _tre(0), _rgn(0), _lbl(0), _net(0) {}
|
||||
~VectorTile() {delete _tre; delete _rgn; delete _lbl; delete _net;}
|
||||
VectorTile() : _tre(0), _rgn(0), _lbl(0), _net(0), _gmp(0) {}
|
||||
~VectorTile()
|
||||
{delete _tre; delete _rgn; delete _lbl; delete _net; delete _gmp;}
|
||||
|
||||
bool init();
|
||||
void clear() {_tre->clear();}
|
||||
@ -19,7 +20,7 @@ public:
|
||||
const RectC &bounds() const {return _tre->bounds();}
|
||||
|
||||
SubFile *file(SubFile::Type type);
|
||||
SubFile *addFile(IMG *img, SubFile::Type type, quint32 size);
|
||||
SubFile *addFile(IMG *img, SubFile::Type type);
|
||||
|
||||
void objects(const RectC &rect, int bits, QList<IMG::Poly> *polygons,
|
||||
QList<IMG::Poly> *lines, QList<IMG::Point> *points) const;
|
||||
@ -27,10 +28,13 @@ public:
|
||||
friend QDebug operator<<(QDebug dbg, const VectorTile &tile);
|
||||
|
||||
private:
|
||||
bool initGMP();
|
||||
|
||||
TREFile *_tre;
|
||||
RGNFile *_rgn;
|
||||
LBLFile *_lbl;
|
||||
NETFile *_net;
|
||||
SubFile *_gmp;
|
||||
};
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
|
Reference in New Issue
Block a user