1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2025-07-20 13:54:24 +02:00

Compare commits

..

44 Commits
7.12 ... 7.14

Author SHA1 Message Date
d3558198ca Translated using Weblate (German)
Currently translated at 100.0% (343 of 343 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/de/
2019-09-29 11:58:18 +02:00
acc69f5c3d Merge branch 'origin/master' into Weblate. 2019-09-29 11:47:55 +02:00
7a900f2252 Version++ 2019-09-29 11:48:08 +02:00
dad76a4e89 Merge branch 'origin/master' into Weblate. 2019-09-29 11:24:33 +02:00
e28e69b248 Added support for enchanced altitude and speed entries 2019-09-29 11:24:20 +02:00
7fffd6a161 Merge branch 'origin/master' into Weblate. 2019-09-29 00:03:21 +02:00
c4fd82e5a0 Properly handle routes without elevation data as well 2019-09-29 00:03:14 +02:00
fa08c0dbea Properly handle files without elevation data 2019-09-28 23:56:59 +02:00
070eff2115 Print a warning message on unsupported IMG compression 2019-09-28 23:55:26 +02:00
20a4870904 Merge branch 'origin/master' into Weblate. 2019-09-21 00:37:02 +02:00
1bb9908936 Some more code cleanup 2019-09-21 00:36:49 +02:00
36555b3140 Code cleanup 2019-09-20 00:23:47 +02:00
6564fb36ab Merge branch 'origin/master' into Weblate. 2019-09-20 00:23:46 +02:00
1a3356b8fe Cosmetics 2019-09-18 09:18:09 +02:00
7ad64922c9 Merge branch 'origin/master' into Weblate. 2019-09-18 09:18:09 +02:00
64a8ec1b84 Merge branch 'origin/master' into Weblate. 2019-09-18 09:12:36 +02:00
0a75298b2b Made the variable record info parsing universal 2019-09-18 09:11:46 +02:00
99be5699af Merge branch 'origin/master' into Weblate. 2019-09-18 08:38:05 +02:00
cdb641b204 Properly read variable length values
Code cleanup
2019-09-18 08:37:33 +02:00
f57bd48840 Merge branch 'origin/master' into Weblate. 2019-09-10 19:45:52 +02:00
c2abf2c146 Prefer loading speed over "NT maps not supported" reporting 2019-09-10 19:45:06 +02:00
a5a2070ccc Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (343 of 343 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/pt_BR/
2019-09-09 12:35:04 +02:00
ed7cb1beb1 Translated using Weblate (Norwegian Bokmål)
Currently translated at 91.3% (313 of 343 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/nb_NO/
2019-09-09 12:35:04 +02:00
37d832bc7f Translated using Weblate (French)
Currently translated at 100.0% (343 of 343 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/fr/
2019-09-09 12:35:04 +02:00
c322bf9f68 Translated using Weblate (Turkish)
Currently translated at 100.0% (343 of 343 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/tr/
2019-09-07 21:35:43 +02:00
2705ffbbfe Translated using Weblate (Russian)
Currently translated at 100.0% (343 of 343 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/ru/
2019-09-07 00:22:41 +02:00
e8962dd50f Translated using Weblate (Czech)
Currently translated at 100.0% (343 of 343 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/cs/
2019-09-07 00:22:40 +02:00
b37e32d622 Translated using Weblate (Finnish)
Currently translated at 100.0% (343 of 343 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/fi/
2019-09-07 00:22:40 +02:00
2b1d0d2189 Translated using Weblate (Swedish)
Currently translated at 100.0% (343 of 343 strings)

Translation: GPXSee/Translations
Translate-URL: https://hosted.weblate.org/projects/gpxsee/translations/sv/
2019-09-07 00:22:39 +02:00
33e3471ca3 Added pt_PT translation file stub 2019-09-06 20:10:40 +02:00
bf55f1e07d ts files update 2019-09-06 20:10:09 +02:00
37a0eec48f Added support for pseudo-NT IMG maps (e.g. TopoHispania) 2019-09-05 22:31:13 +02:00
fcaacb4b6a Version++ 2019-08-29 20:18:35 +02:00
f9c593e6d1 Fixed the "DEM values not used in route points" issue 2019-08-29 20:15:03 +02:00
37e07accd4 Fixed percent slider updates 2019-08-27 20:19:06 +02:00
a7117361be Cosmetics 2019-08-27 20:18:39 +02:00
548c03d543 Added support for graph zooming 2019-08-26 21:03:40 +02:00
1addb1118d Fixed broken maximal ticks count limitation 2019-08-26 20:40:14 +02:00
ae64ef9d83 Only use B records with a valid fix in IGC files 2019-08-25 13:05:27 +02:00
3d16cf2500 Removed forgotten debug stuff 2019-08-25 11:38:41 +02:00
609ac0c57a Graph loading performance improvement
+ code/API cleanup
2019-08-25 10:54:25 +02:00
a70c6f0f24 Fixed broken gear ratio statistics 2019-08-22 19:56:55 +02:00
3ad0c89511 Added missing area-under-mouse highlighting 2019-08-19 19:22:16 +02:00
1497d42bd5 Added CUP files support info 2019-08-18 00:13:04 +02:00
79 changed files with 6865 additions and 3242 deletions

View File

@ -1,4 +1,4 @@
version: 7.12.{build} version: 7.14.{build}
configuration: Release configuration: Release
platform: Any CPU platform: Any CPU
environment: environment:

View File

@ -2,7 +2,7 @@
GPXSee is a Qt-based GPS log file viewer and analyzer that supports all common GPS log file formats. GPXSee is a Qt-based GPS log file viewer and analyzer that supports all common GPS log file formats.
## Features ## 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). * 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). * 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. * Elevation, speed, heart rate, cadence, power, temperature and gear ratio/shifts graphs.

View File

@ -3,7 +3,7 @@ unix:!macx {
} else { } else {
TARGET = GPXSee TARGET = GPXSee
} }
VERSION = 7.12 VERSION = 7.14
QT += core \ QT += core \
gui \ 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

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

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

View File

@ -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.12" !define VERSION "7.14"
; The file to write ; The file to write
OutFile "GPXSee-${VERSION}.exe" OutFile "GPXSee-${VERSION}.exe"

View File

@ -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.12" !define VERSION "7.14"
; The file to write ; The file to write
OutFile "GPXSee-${VERSION}_x64.exe" OutFile "GPXSee-${VERSION}_x64.exe"

View File

@ -153,3 +153,21 @@ void AreaItem::setDigitalZoom(int zoom)
_digitalZoom = zoom; _digitalZoom = zoom;
_pen.setWidthF(_width * pow(2, -_digitalZoom)); _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();
}

View File

@ -27,6 +27,9 @@ public:
void setDigitalZoom(int zoom); void setDigitalZoom(int zoom);
private: private:
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
QPainterPath painterPath(const Polygon &polygon); QPainterPath painterPath(const Polygon &polygon);
void updatePainterPath(); void updatePainterPath();
QString toolTip() const; QString toolTip() const;

View File

@ -30,7 +30,7 @@ private:
Ticks::Ticks(double minValue, double maxValue, int maxCount) Ticks::Ticks(double minValue, double maxValue, int maxCount)
{ {
double range = niceNum(maxValue - minValue, false); double range = niceNum(maxValue - minValue, false);
_d = niceNum(range / maxCount, true); _d = niceNum(range / maxCount, false);
_min = ceil(minValue / _d) * _d; _min = ceil(minValue / _d) * _d;
_max = floor(maxValue / _d) * _d; _max = floor(maxValue / _d) * _d;
} }

View File

@ -14,6 +14,11 @@ CadenceGraph::CadenceGraph(QWidget *parent) : GraphTab(parent)
setSliderPrecision(1); setSliderPrecision(1);
} }
CadenceGraph::~CadenceGraph()
{
qDeleteAll(_tracks);
}
void CadenceGraph::setInfo() void CadenceGraph::setInfo()
{ {
if (_showTracks) { if (_showTracks) {
@ -36,23 +41,28 @@ QList<GraphItem*> CadenceGraph::loadData(const Data &data)
const Graph &graph = track.cadence(); const Graph &graph = track.cadence();
if (!graph.isValid()) { if (!graph.isValid()) {
skipColor(); _palette.nextColor();
graphs.append(0); graphs.append(0);
} else { } else {
CadenceGraphItem *gi = new CadenceGraphItem(graph, _graphType); CadenceGraphItem *gi = new CadenceGraphItem(graph, _graphType,
GraphView::addGraph(gi); _width, _palette.nextColor());
_tracks.append(gi);
if (_showTracks)
addGraph(gi);
_avg.append(QPointF(track.distance(), gi->avg())); _avg.append(QPointF(track.distance(), gi->avg()));
graphs.append(gi); graphs.append(gi);
} }
} }
for (int i = 0; i < data.routes().count(); i++) { for (int i = 0; i < data.routes().count(); i++) {
skipColor(); _palette.nextColor();
graphs.append(0); graphs.append(0);
} }
for (int i = 0; i < data.areas().count(); i++) for (int i = 0; i < data.areas().count(); i++)
skipColor(); _palette.nextColor();
setInfo(); setInfo();
redraw(); redraw();
@ -75,6 +85,9 @@ qreal CadenceGraph::avg() const
void CadenceGraph::clear() void CadenceGraph::clear()
{ {
qDeleteAll(_tracks);
_tracks.clear();
_avg.clear(); _avg.clear();
GraphTab::clear(); GraphTab::clear();
@ -84,7 +97,13 @@ void CadenceGraph::showTracks(bool show)
{ {
_showTracks = 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(); setInfo();
redraw(); redraw();

View File

@ -3,18 +3,20 @@
#include "graphtab.h" #include "graphtab.h"
class CadenceGraphItem;
class CadenceGraph : public GraphTab class CadenceGraph : public GraphTab
{ {
Q_OBJECT Q_OBJECT
public: public:
CadenceGraph(QWidget *parent = 0); CadenceGraph(QWidget *parent = 0);
~CadenceGraph();
QString label() const {return tr("Cadence");} QString label() const {return tr("Cadence");}
QList<GraphItem*> loadData(const Data &data); QList<GraphItem*> loadData(const Data &data);
void clear(); void clear();
void showTracks(bool show); void showTracks(bool show);
void showRoutes(bool show) {Q_UNUSED(show);}
private: private:
qreal avg() const; qreal avg() const;
@ -24,6 +26,7 @@ private:
QVector<QPointF> _avg; QVector<QPointF> _avg;
bool _showTracks; bool _showTracks;
QList<CadenceGraphItem *> _tracks;
}; };
#endif // CADENCEGRAPH_H #endif // CADENCEGRAPH_H

View File

@ -4,7 +4,8 @@
CadenceGraphItem::CadenceGraphItem(const Graph &graph, GraphType type, 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()); setToolTip(toolTip());
} }

View File

@ -8,8 +8,8 @@ class CadenceGraphItem : public GraphItem
Q_OBJECT Q_OBJECT
public: public:
CadenceGraphItem(const Graph &graph, GraphType type, CadenceGraphItem(const Graph &graph, GraphType type, int width,
QGraphicsItem *parent = 0); const QColor &color, QGraphicsItem *parent = 0);
private: private:
QString toolTip() const; QString toolTip() const;

View File

@ -8,26 +8,18 @@
static qreal nMin(qreal a, qreal b) static qreal nMin(qreal a, qreal b)
{ {
if (!std::isnan(a) && !std::isnan(b)) if (std::isnan(a))
return qMin(a, b); return std::isnan(b) ? NAN : b;
else if (!std::isnan(a))
return a;
else if (!std::isnan(b))
return b;
else else
return NAN; return std::isnan(b) ? a : qMin(a, b);
} }
static qreal nMax(qreal a, qreal b) static qreal nMax(qreal a, qreal b)
{ {
if (!std::isnan(a) && !std::isnan(b)) if (std::isnan(a))
return qMax(a, b); return std::isnan(b) ? NAN : b;
else if (!std::isnan(a))
return a;
else if (!std::isnan(b))
return b;
else else
return NAN; return std::isnan(b) ? a : qMax(a, b);
} }
ElevationGraph::ElevationGraph(QWidget *parent) : GraphTab(parent) ElevationGraph::ElevationGraph(QWidget *parent) : GraphTab(parent)
@ -49,6 +41,12 @@ ElevationGraph::ElevationGraph(QWidget *parent) : GraphTab(parent)
setMinYRange(50.0); setMinYRange(50.0);
} }
ElevationGraph::~ElevationGraph()
{
qDeleteAll(_tracks);
qDeleteAll(_routes);
}
void ElevationGraph::setInfo() void ElevationGraph::setInfo()
{ {
if (std::isnan(max()) || std::isnan(min())) if (std::isnan(max()) || std::isnan(min()))
@ -70,19 +68,28 @@ void ElevationGraph::setInfo()
GraphItem *ElevationGraph::loadGraph(const Graph &graph, Type type) GraphItem *ElevationGraph::loadGraph(const Graph &graph, Type type)
{ {
if (!graph.isValid()) { if (!graph.isValid()) {
skipColor(); _palette.nextColor();
return 0; return 0;
} }
ElevationGraphItem *gi = new ElevationGraphItem(graph, _graphType); ElevationGraphItem *gi = new ElevationGraphItem(graph, _graphType, _width,
GraphView::addGraph(gi, type); _palette.nextColor());
gi->setUnits(_units);
if (type == Track) { if (type == Track) {
_tracks.append(gi);
if (_showTracks)
addGraph(gi);
_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);
if (_showRoutes)
addGraph(gi);
_routeAscent += gi->ascent(); _routeAscent += gi->ascent();
_routeDescent += gi->descent(); _routeDescent += gi->descent();
_routeMax = nMax(_routeMax, gi->max()); _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++) for (int i = 0; i < data.routes().count(); i++)
graphs.append(loadGraph(data.routes().at(i).elevation(), Route)); graphs.append(loadGraph(data.routes().at(i).elevation(), Route));
for (int i = 0; i < data.areas().count(); i++) for (int i = 0; i < data.areas().count(); i++)
skipColor(); _palette.nextColor();
setInfo(); setInfo();
redraw(); redraw();
@ -111,6 +118,11 @@ QList<GraphItem*> ElevationGraph::loadData(const Data &data)
void ElevationGraph::clear() void ElevationGraph::clear()
{ {
qDeleteAll(_tracks);
_tracks.clear();
qDeleteAll(_routes);
_routes.clear();
_trackAscent = 0; _trackAscent = 0;
_routeAscent = 0; _routeAscent = 0;
_trackDescent = 0; _trackDescent = 0;
@ -142,12 +154,23 @@ void ElevationGraph::setUnits(Units units)
GraphView::setUnits(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) void ElevationGraph::showTracks(bool show)
{ {
_showTracks = show; _showTracks = show;
showItems(_tracks, show);
setInfo(); setInfo();
showGraph(show, Track);
redraw(); redraw();
} }
@ -156,7 +179,7 @@ void ElevationGraph::showRoutes(bool show)
{ {
_showRoutes = show; _showRoutes = show;
showGraph(show, Route); showItems(_routes, show);
setInfo(); setInfo();
redraw(); redraw();

View File

@ -3,12 +3,15 @@
#include "graphtab.h" #include "graphtab.h"
class ElevationGraphItem;
class ElevationGraph : public GraphTab class ElevationGraph : public GraphTab
{ {
Q_OBJECT Q_OBJECT
public: public:
ElevationGraph(QWidget *parent = 0); ElevationGraph(QWidget *parent = 0);
~ElevationGraph();
QString label() const {return tr("Elevation");} QString label() const {return tr("Elevation");}
QList<GraphItem*> loadData(const Data &data); QList<GraphItem*> loadData(const Data &data);
@ -29,6 +32,7 @@ private:
void setInfo(); void setInfo();
GraphItem *loadGraph(const Graph &graph, Type type); GraphItem *loadGraph(const Graph &graph, Type type);
void showItems(const QList<ElevationGraphItem *> &list, bool show);
qreal _trackAscent, _trackDescent; qreal _trackAscent, _trackDescent;
qreal _routeAscent, _routeDescent; qreal _routeAscent, _routeDescent;
@ -36,6 +40,7 @@ private:
qreal _trackMin, _routeMin; qreal _trackMin, _routeMin;
bool _showTracks, _showRoutes; bool _showTracks, _showRoutes;
QList<ElevationGraphItem *> _tracks, _routes;
}; };
#endif // ELEVATIONGRAPH_H #endif // ELEVATIONGRAPH_H

View File

@ -4,7 +4,8 @@
ElevationGraphItem::ElevationGraphItem(const Graph &graph, GraphType type, 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(); _min = GraphItem::min();
_max = GraphItem::max(); _max = GraphItem::max();

View File

@ -8,8 +8,8 @@ class ElevationGraphItem : public GraphItem
Q_OBJECT Q_OBJECT
public: public:
ElevationGraphItem(const Graph &graph, GraphType type, ElevationGraphItem(const Graph &graph, GraphType type, int width,
QGraphicsItem *parent = 0); const QColor &color, QGraphicsItem *parent = 0);
qreal ascent() const {return _ascent;} qreal ascent() const {return _ascent;}
qreal descent() const {return _descent;} qreal descent() const {return _descent;}

View File

@ -14,6 +14,11 @@ GearRatioGraph::GearRatioGraph(QWidget *parent) : GraphTab(parent)
setSliderPrecision(2); setSliderPrecision(2);
} }
GearRatioGraph::~GearRatioGraph()
{
qDeleteAll(_tracks);
}
void GearRatioGraph::setInfo() void GearRatioGraph::setInfo()
{ {
if (_showTracks) { if (_showTracks) {
@ -37,11 +42,15 @@ QList<GraphItem*> GearRatioGraph::loadData(const Data &data)
const Graph &graph = data.tracks().at(i).ratio(); const Graph &graph = data.tracks().at(i).ratio();
if (!graph.isValid()) { if (!graph.isValid()) {
skipColor(); _palette.nextColor();
graphs.append(0); graphs.append(0);
} else { } else {
GearRatioGraphItem *gi = new GearRatioGraphItem(graph, _graphType); GearRatioGraphItem *gi = new GearRatioGraphItem(graph, _graphType,
GraphView::addGraph(gi); _width, _palette.nextColor());
_tracks.append(gi);
if (_showTracks)
addGraph(gi);
for (QMap<qreal, qreal>::const_iterator it = gi->map().constBegin(); for (QMap<qreal, qreal>::const_iterator it = gi->map().constBegin();
it != gi->map().constEnd(); ++it) 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++) { for (int i = 0; i < data.routes().count(); i++) {
skipColor(); _palette.nextColor();
graphs.append(0); graphs.append(0);
} }
for (int i = 0; i < data.areas().count(); i++) for (int i = 0; i < data.areas().count(); i++)
skipColor(); _palette.nextColor();
setInfo(); setInfo();
redraw(); redraw();
@ -70,10 +79,7 @@ qreal GearRatioGraph::top() const
for (QMap<qreal, qreal>::const_iterator it = _map.constBegin(); for (QMap<qreal, qreal>::const_iterator it = _map.constBegin();
it != _map.constEnd(); ++it) { it != _map.constEnd(); ++it) {
if (it == _map.constBegin()) { if (std::isnan(val) || it.value() > val) {
val = it.value();
key = it.key();
} else if (it.value() > val) {
val = it.value(); val = it.value();
key = it.key(); key = it.key();
} }
@ -84,6 +90,9 @@ qreal GearRatioGraph::top() const
void GearRatioGraph::clear() void GearRatioGraph::clear()
{ {
qDeleteAll(_tracks);
_tracks.clear();
_map.clear(); _map.clear();
GraphTab::clear(); GraphTab::clear();
@ -93,7 +102,13 @@ void GearRatioGraph::showTracks(bool show)
{ {
_showTracks = 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(); setInfo();
redraw(); redraw();

View File

@ -4,12 +4,15 @@
#include <QMap> #include <QMap>
#include "graphtab.h" #include "graphtab.h"
class GearRatioGraphItem;
class GearRatioGraph : public GraphTab class GearRatioGraph : public GraphTab
{ {
Q_OBJECT Q_OBJECT
public: public:
GearRatioGraph(QWidget *parent = 0); GearRatioGraph(QWidget *parent = 0);
~GearRatioGraph();
QString label() const {return tr("Gear ratio");} QString label() const {return tr("Gear ratio");}
QList<GraphItem*> loadData(const Data &data); QList<GraphItem*> loadData(const Data &data);
@ -25,6 +28,7 @@ private:
QMap<qreal, qreal> _map; QMap<qreal, qreal> _map;
bool _showTracks; bool _showTracks;
QList<GearRatioGraphItem*> _tracks;
}; };
#endif // GEARRATIOGRAPH_H #endif // GEARRATIOGRAPH_H

View File

@ -5,21 +5,27 @@
GearRatioGraphItem::GearRatioGraphItem(const Graph &graph, GraphType type, 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 (int i = 0; i < graph.size(); i++) {
const GraphSegment &segment = graph.at(i);
for (QMap<qreal, qreal>::const_iterator it = _map.constBegin(); for (int j = 1; j < segment.size(); j++) {
it != _map.constEnd(); ++it) { qreal dx = segment.at(j).s() - segment.at(j-1).s();
if (it == _map.constBegin()) { _map.insert(segment.at(j).y(), _map.value(segment.at(j).y()) + dx);
val = it.value();
_top = it.key();
} else if (it.value() > val) {
val = it.value();
_top = it.key();
} }
} }
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()); setToolTip(toolTip());
} }

View File

@ -9,8 +9,8 @@ class GearRatioGraphItem : public GraphItem
Q_OBJECT Q_OBJECT
public: public:
GearRatioGraphItem(const Graph &graph, GraphType type, GearRatioGraphItem(const Graph &graph, GraphType type, int width,
QGraphicsItem *parent = 0); const QColor &color, QGraphicsItem *parent = 0);
qreal top() const {return _top;} qreal top() const {return _top;}

View File

@ -2,30 +2,25 @@
#include "graphitem.h" #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) : QGraphicsObject(parent), _graph(graph), _type(type)
{ {
Q_ASSERT(_graph.isValid()); Q_ASSERT(_graph.isValid());
_id = 0; _pen = QPen(color, width);
_width = 1; _sx = 0; _sy = 0;
_pen = QPen(Qt::black, _width);
_sx = 1.0; _sy = 1.0;
_time = _graph.hasTime(); _time = _graph.hasTime();
setZValue(2.0); setZValue(2.0);
updatePath();
updateShape();
updateBounds();
setAcceptHoverEvents(true); setAcceptHoverEvents(true);
updateBounds();
} }
void GraphItem::updateShape() void GraphItem::updateShape()
{ {
QPainterPathStroker s; QPainterPathStroker s;
s.setWidth(_width + 1); s.setWidth(_pen.width() + 1);
_shape = s.createStroke(_path); _shape = s.createStroke(_path);
} }
@ -54,7 +49,6 @@ void GraphItem::setGraphType(GraphType type)
_type = type; _type = type;
updatePath(); updatePath();
updateShape();
updateBounds(); updateBounds();
} }
@ -69,12 +63,11 @@ void GraphItem::setColor(const QColor &color)
void GraphItem::setWidth(int width) void GraphItem::setWidth(int width)
{ {
if (width == _width) if (width == _pen.width())
return; return;
prepareGeometryChange(); prepareGeometryChange();
_width = width;
_pen.setWidth(width); _pen.setWidth(width);
updateShape(); updateShape();
@ -170,10 +163,10 @@ void GraphItem::emitSliderPositionChanged(qreal pos)
void GraphItem::hover(bool hover) void GraphItem::hover(bool hover)
{ {
if (hover) { if (hover) {
_pen.setWidth(_width + 1); _pen.setWidth(_pen.width() + 1);
setZValue(zValue() + 1.0); setZValue(zValue() + 1.0);
} else { } else {
_pen.setWidth(_width); _pen.setWidth(_pen.width() - 1);
setZValue(zValue() - 1.0); setZValue(zValue() - 1.0);
} }
@ -189,23 +182,30 @@ void GraphItem::setScale(qreal sx, qreal sy)
_sx = sx; _sy = sy; _sx = sx; _sy = sy;
updatePath(); updatePath();
updateShape();
} }
void GraphItem::updatePath() void GraphItem::updatePath()
{ {
_path = QPainterPath(); if (_sx == 0 && _sy == 0)
if (_type == Time && !_time)
return; return;
for (int i = 0; i < _graph.size(); i++) { prepareGeometryChange();
const GraphSegment &segment = _graph.at(i);
_path.moveTo(segment.first().x(_type) * _sx, -segment.first().y() * _sy); _path = QPainterPath();
for (int i = 1; i < segment.size(); i++)
_path.lineTo(segment.at(i).x(_type) * _sx, -segment.at(i).y() * _sy); 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() void GraphItem::updateBounds()
@ -286,7 +286,7 @@ void GraphItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{ {
Q_UNUSED(event); Q_UNUSED(event);
_pen.setWidthF(_width + 1); _pen.setWidth(_pen.width() + 1);
setZValue(zValue() + 1.0); setZValue(zValue() + 1.0);
update(); update();
@ -297,7 +297,7 @@ void GraphItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{ {
Q_UNUSED(event); Q_UNUSED(event);
_pen.setWidthF(_width); _pen.setWidth(_pen.width() - 1);
setZValue(zValue() - 1.0); setZValue(zValue() - 1.0);
update(); update();

View File

@ -11,7 +11,8 @@ class GraphItem : public QGraphicsObject
Q_OBJECT Q_OBJECT
public: 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() {} virtual ~GraphItem() {}
QPainterPath shape() const {return _shape;} QPainterPath shape() const {return _shape;}
@ -27,8 +28,6 @@ public:
void setScale(qreal sx, qreal sy); void setScale(qreal sx, qreal sy);
void setGraphType(GraphType type); void setGraphType(GraphType type);
int id() const {return _id;}
void setId(int id) {_id = id;}
void setColor(const QColor &color); void setColor(const QColor &color);
void setWidth(int width); void setWidth(int width);
virtual void setUnits(Units units) {Q_UNUSED(units);} virtual void setUnits(Units units) {Q_UNUSED(units);}
@ -55,17 +54,13 @@ private:
void updateShape(); void updateShape();
void updateBounds(); void updateBounds();
int _id;
QPen _pen;
int _width;
Graph _graph; Graph _graph;
GraphType _type; GraphType _type;
QPainterPath _path; QPainterPath _path;
QPainterPath _shape; QPainterPath _shape;
QRectF _bounds; QRectF _bounds;
qreal _sx, _sy; qreal _sx, _sy;
QPen _pen;
bool _time; bool _time;
}; };

View File

@ -1,8 +1,7 @@
#include <QGraphicsScene> #include <QGraphicsScene>
#include <QEvent> #include <QEvent>
#include <QMouseEvent> #include <QMouseEvent>
#include <QPaintEngine> #include <QScrollBar>
#include <QPaintDevice>
#include <QGraphicsSimpleTextItem> #include <QGraphicsSimpleTextItem>
#include <QPalette> #include <QPalette>
#include <QLocale> #include <QLocale>
@ -64,6 +63,8 @@ GraphView::GraphView(QWidget *parent)
_units = Metric; _units = Metric;
_graphType = Distance; _graphType = Distance;
_xLabel = tr("Distance"); _xLabel = tr("Distance");
_zoom = 1.0;
} }
GraphView::~GraphView() GraphView::~GraphView()
@ -74,8 +75,6 @@ GraphView::~GraphView()
delete _info; delete _info;
delete _grid; delete _grid;
delete _message; delete _message;
qDeleteAll(_graphs);
} }
void GraphView::createXLabel() void GraphView::createXLabel()
@ -166,14 +165,7 @@ void GraphView::setGraphType(GraphType type)
for (int i = 0; i < _graphs.count(); i++) { for (int i = 0; i < _graphs.count(); i++) {
GraphItem *gi = _graphs.at(i); GraphItem *gi = _graphs.at(i);
gi->setGraphType(type); gi->setGraphType(type);
if (!_hide.contains(gi->id())) { _bounds |= gi->bounds();
if (gi->bounds().width() > 0)
addItem(gi);
else
removeItem(gi);
}
if (gi->scene() == _scene)
_bounds |= gi->bounds();
} }
if (type == Distance) if (type == Distance)
@ -195,29 +187,31 @@ void GraphView::showSliderInfo(bool show)
_sliderInfo->setVisible(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, connect(this, SIGNAL(sliderPositionChanged(qreal)), graph,
SLOT(emitSliderPositionChanged(qreal))); SLOT(emitSliderPositionChanged(qreal)));
_graphs.append(graph); _graphs.append(graph);
_scene->addItem(graph);
_bounds |= graph->bounds();
if (!_hide.contains(id)) { setXUnits();
_visible.append(graph); }
if (graph->bounds().width() > 0) {
_scene->addItem(graph); void GraphView::removeGraph(GraphItem *graph)
_bounds |= graph->bounds(); {
} disconnect(this, SIGNAL(sliderPositionChanged(qreal)), graph,
setXUnits(); 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) void GraphView::removeItem(QGraphicsItem *item)
@ -232,29 +226,6 @@ void GraphView::addItem(QGraphicsItem *item)
_scene->addItem(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 GraphView::bounds() const
{ {
QRectF br(_bounds); QRectF br(_bounds);
@ -313,9 +284,10 @@ void GraphView::redraw(const QSizeF &size)
sx = (size.width() - (my.width() + mx.width())) / r.width(); sx = (size.width() - (my.width() + mx.width())) / r.width();
sy = (size.height() - (mx.height() + my.height()) sy = (size.height() - (mx.height() + my.height())
- _info->boundingRect().height()) / r.height(); - _info->boundingRect().height()) / r.height();
sx *= _zoom;
for (int i = 0; i < _visible.size(); i++) for (int i = 0; i < _graphs.size(); i++)
_visible.at(i)->setScale(sx, sy); _graphs.at(i)->setScale(sx, sy);
QPointF p(r.left() * sx, r.top() * sy); QPointF p(r.left() * sx, r.top() * sy);
QSizeF s(r.width() * sx, r.height() * sy); QSizeF s(r.width() * sx, r.height() * sy);
@ -360,6 +332,40 @@ void GraphView::mousePressEvent(QMouseEvent *e)
QGraphicsView::mousePressEvent(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) void GraphView::plot(QPainter *painter, const QRectF &target, qreal scale)
{ {
QSizeF canvas = QSizeF(target.width() / scale, target.height() / 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() void GraphView::clear()
{ {
_graphs.clear();
_slider->clear(); _slider->clear();
_info->clear(); _info->clear();
qDeleteAll(_graphs);
_graphs.clear();
_visible.clear();
_palette.reset(); _palette.reset();
_bounds = QRectF(); _bounds = QRectF();
_sliderPos = 0; _sliderPos = 0;
_zoom = 1.0;
_scene->setSceneRect(0, 0, 0, 0); _scene->setSceneRect(0, 0, 0, 0);
} }
void GraphView::updateSliderPosition() void GraphView::updateSliderPosition()
{ {
if (bounds().width() <= 0)
return;
if (_sliderPos <= bounds().right() && _sliderPos >= bounds().left()) { if (_sliderPos <= bounds().right() && _sliderPos >= bounds().left()) {
_slider->setPos((_sliderPos / bounds().width()) _slider->setPos((_sliderPos / bounds().width())
* _slider->area().width(), _slider->area().bottom()); * _slider->area().width(), _slider->area().bottom());
_slider->setVisible(!_visible.isEmpty()); _slider->setVisible(true);
updateSliderInfo();
} else { } else {
_slider->setPos(_slider->area().left(), _slider->area().bottom()); _slider->setPos(_slider->area().left(), _slider->area().bottom());
_slider->setVisible(false); _slider->setVisible(false);
} }
if (_slider->isVisible())
updateSliderInfo();
} }
void GraphView::updateSliderInfo() void GraphView::updateSliderInfo()
{ {
QLocale l(QLocale::system()); QLocale l(QLocale::system());
qreal r, y; qreal r = 0, y = 0;
if (_graphs.count() == 1) {
if (_visible.count() > 1) { QRectF br(_graphs.first()->bounds());
r = 0;
y = 0;
} else {
QRectF br(_visible.first()->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 = _visible.first()->yAtX(_sliderPos); y = _graphs.first()->yAtX(_sliderPos);
r = (y - br.bottom()) / br.height(); r = (y - br.bottom()) / br.height();
} }
@ -435,7 +432,7 @@ void GraphView::updateSliderInfo()
_sliderInfo->setPos(QPointF(0, _slider->boundingRect().height() * r)); _sliderInfo->setPos(QPointF(0, _slider->boundingRect().height() * r));
_sliderInfo->setText(_graphType == Time ? Format::timeSpan(_sliderPos, _sliderInfo->setText(_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, (_visible.count() > 1) ? QString() + UNIT_SPACE + _xUnits, (_graphs.count() > 1) ? QString()
: l.toString(-y * _yScale + _yOffset, 'f', _precision) + UNIT_SPACE : l.toString(-y * _yScale + _yOffset, 'f', _precision) + UNIT_SPACE
+ _yUnits); + _yUnits);
} }
@ -455,7 +452,7 @@ void GraphView::emitSliderPositionChanged(const QPointF &pos)
void GraphView::setSliderPosition(qreal pos) void GraphView::setSliderPosition(qreal pos)
{ {
if (_visible.isEmpty()) if (_graphs.isEmpty())
return; return;
_sliderPos = pos; _sliderPos = pos;
@ -483,11 +480,8 @@ void GraphView::setPalette(const Palette &palette)
_palette = palette; _palette = palette;
_palette.reset(); _palette.reset();
for (int i = 0; i < _graphs.count(); i++) { for (int i = 0; i < _graphs.count(); i++)
QColor color(_palette.nextColor()); _graphs.at(i)->setColor(_palette.nextColor());
color.setAlpha(255);
_graphs.at(i)->setColor(color);
}
} }
void GraphView::setGraphWidth(int width) void GraphView::setGraphWidth(int width)

View File

@ -46,9 +46,9 @@ signals:
void sliderPositionChanged(qreal); void sliderPositionChanged(qreal);
protected: 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 setGraphType(GraphType type);
void setUnits(Units units); void setUnits(Units units);
@ -68,12 +68,11 @@ protected:
void redraw(); void redraw();
void addInfo(const QString &key, const QString &value); void addInfo(const QString &key, const QString &value);
void clearInfo(); void clearInfo();
void skipColor() {_palette.nextColor();}
void changeEvent(QEvent *e);
QList<GraphItem*> _graphs;
GraphType _graphType; GraphType _graphType;
Units _units;
Palette _palette;
int _width;
private slots: private slots:
void emitSliderPositionChanged(const QPointF &pos); void emitSliderPositionChanged(const QPointF &pos);
@ -91,15 +90,9 @@ private:
void resizeEvent(QResizeEvent *e); void resizeEvent(QResizeEvent *e);
void mousePressEvent(QMouseEvent *e); void mousePressEvent(QMouseEvent *e);
void wheelEvent(QWheelEvent *e);
Units _units; void changeEvent(QEvent *e);
qreal _xScale, _yScale; void paintEvent(QPaintEvent *event);
qreal _yOffset;
QString _xUnits, _yUnits;
QString _xLabel, _yLabel;
int _precision;
qreal _minYRange;
qreal _sliderPos;
QGraphicsScene *_scene; QGraphicsScene *_scene;
@ -109,12 +102,19 @@ private:
InfoItem *_info; InfoItem *_info;
GridItem *_grid; GridItem *_grid;
QGraphicsSimpleTextItem *_message; QGraphicsSimpleTextItem *_message;
QList<GraphItem*> _graphs;
QList<GraphItem*> _visible;
QSet<int> _hide;
QRectF _bounds; QRectF _bounds;
Palette _palette; qreal _sliderPos;
int _width;
qreal _xScale, _yScale;
qreal _yOffset;
QString _xUnits, _yUnits;
QString _xLabel, _yLabel;
int _precision;
qreal _minYRange;
qreal _zoom;
}; };
#endif // GRAPHVIEW_H #endif // GRAPHVIEW_H

View File

@ -14,6 +14,11 @@ HeartRateGraph::HeartRateGraph(QWidget *parent) : GraphTab(parent)
setSliderPrecision(0); setSliderPrecision(0);
} }
HeartRateGraph::~HeartRateGraph()
{
qDeleteAll(_tracks);
}
void HeartRateGraph::setInfo() void HeartRateGraph::setInfo()
{ {
if (_showTracks) { if (_showTracks) {
@ -36,23 +41,28 @@ QList<GraphItem*> HeartRateGraph::loadData(const Data &data)
const Graph &graph = track.heartRate(); const Graph &graph = track.heartRate();
if (!graph.isValid()) { if (!graph.isValid()) {
skipColor(); _palette.nextColor();
graphs.append(0); graphs.append(0);
} else { } else {
HeartRateGraphItem *gi = new HeartRateGraphItem(graph, _graphType); HeartRateGraphItem *gi = new HeartRateGraphItem(graph, _graphType,
GraphView::addGraph(gi); _width, _palette.nextColor());
_tracks.append(gi);
if (_showTracks)
addGraph(gi);
_avg.append(QPointF(track.distance(), gi->avg())); _avg.append(QPointF(track.distance(), gi->avg()));
graphs.append(gi); graphs.append(gi);
} }
} }
for (int i = 0; i < data.routes().count(); i++) { for (int i = 0; i < data.routes().count(); i++) {
skipColor(); _palette.nextColor();
graphs.append(0); graphs.append(0);
} }
for (int i = 0; i < data.areas().count(); i++) for (int i = 0; i < data.areas().count(); i++)
skipColor(); _palette.nextColor();
setInfo(); setInfo();
redraw(); redraw();
@ -75,6 +85,9 @@ qreal HeartRateGraph::avg() const
void HeartRateGraph::clear() void HeartRateGraph::clear()
{ {
qDeleteAll(_tracks);
_tracks.clear();
_avg.clear(); _avg.clear();
GraphTab::clear(); GraphTab::clear();
@ -84,7 +97,13 @@ void HeartRateGraph::showTracks(bool show)
{ {
_showTracks = 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(); setInfo();
redraw(); redraw();

View File

@ -3,12 +3,15 @@
#include "graphtab.h" #include "graphtab.h"
class HeartRateGraphItem;
class HeartRateGraph : public GraphTab class HeartRateGraph : public GraphTab
{ {
Q_OBJECT Q_OBJECT
public: public:
HeartRateGraph(QWidget *parent = 0); HeartRateGraph(QWidget *parent = 0);
~HeartRateGraph();
QString label() const {return tr("Heart rate");} QString label() const {return tr("Heart rate");}
QList<GraphItem*> loadData(const Data &data); QList<GraphItem*> loadData(const Data &data);
@ -23,6 +26,7 @@ private:
QVector<QPointF> _avg; QVector<QPointF> _avg;
bool _showTracks; bool _showTracks;
QList<HeartRateGraphItem*> _tracks;
}; };
#endif // HEARTRATEGRAPH_H #endif // HEARTRATEGRAPH_H

View File

@ -4,7 +4,8 @@
HeartRateGraphItem::HeartRateGraphItem(const Graph &graph, GraphType type, 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()); setToolTip(toolTip());
} }

View File

@ -8,8 +8,8 @@ class HeartRateGraphItem : public GraphItem
Q_OBJECT Q_OBJECT
public: public:
HeartRateGraphItem(const Graph &graph, GraphType type, HeartRateGraphItem(const Graph &graph, GraphType type, int width,
QGraphicsItem *parent = 0); const QColor &color, QGraphicsItem *parent = 0);
private: private:
QString toolTip() const; QString toolTip() const;

View File

@ -24,7 +24,7 @@ PercentSlider::PercentSlider(QWidget *parent) : QWidget(parent)
_label->setAlignment(Qt::AlignRight); _label->setAlignment(Qt::AlignRight);
_label->setText(format(_slider->value())); _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(); QHBoxLayout *layout = new QHBoxLayout();
layout->addWidget(_slider); layout->addWidget(_slider);

View File

@ -14,6 +14,11 @@ PowerGraph::PowerGraph(QWidget *parent) : GraphTab(parent)
setSliderPrecision(1); setSliderPrecision(1);
} }
PowerGraph::~PowerGraph()
{
qDeleteAll(_tracks);
}
void PowerGraph::setInfo() void PowerGraph::setInfo()
{ {
if (_showTracks) { if (_showTracks) {
@ -36,23 +41,27 @@ QList<GraphItem*> PowerGraph::loadData(const Data &data)
const Graph &graph = track.power(); const Graph &graph = track.power();
if (!graph.isValid()) { if (!graph.isValid()) {
skipColor(); _palette.nextColor();
graphs.append(0); graphs.append(0);
} else { } else {
PowerGraphItem *gi = new PowerGraphItem(graph, _graphType); PowerGraphItem *gi = new PowerGraphItem(graph, _graphType, _width,
GraphView::addGraph(gi); _palette.nextColor());
_tracks.append(gi);
if (_showTracks)
addGraph(gi);
_avg.append(QPointF(track.distance(), gi->avg())); _avg.append(QPointF(track.distance(), gi->avg()));
graphs.append(gi); graphs.append(gi);
} }
} }
for (int i = 0; i < data.routes().count(); i++) { for (int i = 0; i < data.routes().count(); i++) {
skipColor(); _palette.nextColor();
graphs.append(0); graphs.append(0);
} }
for (int i = 0; i < data.areas().count(); i++) for (int i = 0; i < data.areas().count(); i++)
skipColor(); _palette.nextColor();
setInfo(); setInfo();
redraw(); redraw();
@ -75,6 +84,9 @@ qreal PowerGraph::avg() const
void PowerGraph::clear() void PowerGraph::clear()
{ {
qDeleteAll(_tracks);
_tracks.clear();
_avg.clear(); _avg.clear();
GraphTab::clear(); GraphTab::clear();
@ -84,7 +96,13 @@ void PowerGraph::showTracks(bool show)
{ {
_showTracks = 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(); setInfo();
redraw(); redraw();

View File

@ -3,12 +3,15 @@
#include "graphtab.h" #include "graphtab.h"
class PowerGraphItem;
class PowerGraph : public GraphTab class PowerGraph : public GraphTab
{ {
Q_OBJECT Q_OBJECT
public: public:
PowerGraph(QWidget *parent = 0); PowerGraph(QWidget *parent = 0);
~PowerGraph();
QString label() const {return tr("Power");} QString label() const {return tr("Power");}
QList<GraphItem*> loadData(const Data &data); QList<GraphItem*> loadData(const Data &data);
@ -23,6 +26,7 @@ private:
QVector<QPointF> _avg; QVector<QPointF> _avg;
bool _showTracks; bool _showTracks;
QList<PowerGraphItem*> _tracks;
}; };
#endif // POWERGRAPH_H #endif // POWERGRAPH_H

View File

@ -3,8 +3,9 @@
#include "powergraphitem.h" #include "powergraphitem.h"
PowerGraphItem::PowerGraphItem(const Graph &graph, GraphType type, PowerGraphItem::PowerGraphItem(const Graph &graph, GraphType type, int width,
QGraphicsItem *parent) : GraphItem(graph, type, parent) const QColor &color, QGraphicsItem *parent)
: GraphItem(graph, type, width, color, parent)
{ {
setToolTip(toolTip()); setToolTip(toolTip());
} }

View File

@ -8,8 +8,8 @@ class PowerGraphItem : public GraphItem
Q_OBJECT Q_OBJECT
public: public:
PowerGraphItem(const Graph &graph, GraphType type, PowerGraphItem(const Graph &graph, GraphType type, int width,
QGraphicsItem *parent = 0); const QColor &color, QGraphicsItem *parent = 0);
private: private:
QString toolTip() const; QString toolTip() const;

View File

@ -24,7 +24,7 @@ QString RouteItem::toolTip(Units units) const
RouteItem::RouteItem(const Route &route, Map *map, QGraphicsItem *parent) RouteItem::RouteItem(const Route &route, Map *map, QGraphicsItem *parent)
: PathItem(route.path(), map, parent) : PathItem(route.path(), map, parent)
{ {
const QVector<Waypoint> &waypoints = route.waypoints(); const RouteData &waypoints = route.data();
_waypoints.resize(waypoints.size()); _waypoints.resize(waypoints.size());
for (int i = 0; i < waypoints.size(); i++) for (int i = 0; i < waypoints.size(); i++)

View File

@ -18,6 +18,11 @@ SpeedGraph::SpeedGraph(QWidget *parent) : GraphTab(parent)
setSliderPrecision(1); setSliderPrecision(1);
} }
SpeedGraph::~SpeedGraph()
{
qDeleteAll(_tracks);
}
void SpeedGraph::setInfo() void SpeedGraph::setInfo()
{ {
if (_showTracks) { if (_showTracks) {
@ -44,13 +49,18 @@ QList<GraphItem*> SpeedGraph::loadData(const Data &data)
const Graph &graph = track.speed(); const Graph &graph = track.speed();
if (!graph.isValid()) { if (!graph.isValid()) {
skipColor(); _palette.nextColor();
graphs.append(0); graphs.append(0);
} else { } else {
SpeedGraphItem *gi = new SpeedGraphItem(graph, _graphType, SpeedGraphItem *gi = new SpeedGraphItem(graph, _graphType, _width,
track.movingTime()); _palette.nextColor(), track.movingTime());
gi->setTimeType(_timeType); gi->setTimeType(_timeType);
GraphView::addGraph(gi); gi->setUnits(_units);
_tracks.append(gi);
if (_showTracks)
addGraph(gi);
_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); graphs.append(gi);
@ -58,12 +68,12 @@ QList<GraphItem*> SpeedGraph::loadData(const Data &data)
} }
for (int i = 0; i < data.routes().count(); i++) { for (int i = 0; i < data.routes().count(); i++) {
skipColor(); _palette.nextColor();
graphs.append(0); graphs.append(0);
} }
for (int i = 0; i < data.areas().count(); i++) for (int i = 0; i < data.areas().count(); i++)
skipColor(); _palette.nextColor();
setInfo(); setInfo();
redraw(); redraw();
@ -87,6 +97,9 @@ qreal SpeedGraph::avg() const
void SpeedGraph::clear() void SpeedGraph::clear()
{ {
qDeleteAll(_tracks);
_tracks.clear();
_avg.clear(); _avg.clear();
_mavg.clear(); _mavg.clear();
@ -121,8 +134,8 @@ void SpeedGraph::setTimeType(enum TimeType type)
{ {
_timeType = type; _timeType = type;
for (int i = 0; i < _graphs.size(); i++) for (int i = 0; i < _tracks.size(); i++)
static_cast<SpeedGraphItem*>(_graphs.at(i))->setTimeType(type); _tracks.at(i)->setTimeType(type);
setInfo(); setInfo();
redraw(); redraw();
@ -132,7 +145,13 @@ void SpeedGraph::showTracks(bool show)
{ {
_showTracks = 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(); setInfo();
redraw(); redraw();

View File

@ -4,12 +4,15 @@
#include <QList> #include <QList>
#include "graphtab.h" #include "graphtab.h"
class SpeedGraphItem;
class SpeedGraph : public GraphTab class SpeedGraph : public GraphTab
{ {
Q_OBJECT Q_OBJECT
public: public:
SpeedGraph(QWidget *parent = 0); SpeedGraph(QWidget *parent = 0);
~SpeedGraph();
QString label() const {return tr("Speed");} QString label() const {return tr("Speed");}
QList<GraphItem*> loadData(const Data &data); QList<GraphItem*> loadData(const Data &data);
@ -29,7 +32,9 @@ private:
Units _units; Units _units;
TimeType _timeType; TimeType _timeType;
bool _showTracks; bool _showTracks;
QList<SpeedGraphItem *> _tracks;
}; };
#endif // SPEEDGRAPH_H #endif // SPEEDGRAPH_H

View File

@ -4,8 +4,9 @@
#include "speedgraphitem.h" #include "speedgraphitem.h"
SpeedGraphItem::SpeedGraphItem(const Graph &graph, GraphType type, SpeedGraphItem::SpeedGraphItem(const Graph &graph, GraphType type, int width,
qreal movingTime, QGraphicsItem *parent) : GraphItem(graph, type, parent) const QColor &color, qreal movingTime, QGraphicsItem *parent)
: GraphItem(graph, type, width, color, parent)
{ {
_units = Metric; _units = Metric;
_timeType = Total; _timeType = Total;

View File

@ -9,8 +9,8 @@ class SpeedGraphItem : public GraphItem
Q_OBJECT Q_OBJECT
public: public:
SpeedGraphItem(const Graph &graph, GraphType type, qreal movingTime, SpeedGraphItem(const Graph &graph, GraphType type, int width,
QGraphicsItem *parent = 0); const QColor &color, 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;}
@ -23,9 +23,8 @@ private:
QString toolTip() const; QString toolTip() const;
qreal _avg, _mavg, _max; qreal _avg, _mavg, _max;
Units _units;
TimeType _timeType; TimeType _timeType;
Units _units;
}; };
#endif // SPEEDGRAPHITEM_H #endif // SPEEDGRAPHITEM_H

View File

@ -14,6 +14,11 @@ TemperatureGraph::TemperatureGraph(QWidget *parent) : GraphTab(parent)
setSliderPrecision(1); setSliderPrecision(1);
} }
TemperatureGraph::~TemperatureGraph()
{
qDeleteAll(_tracks);
}
void TemperatureGraph::setInfo() void TemperatureGraph::setInfo()
{ {
if (_showTracks) { if (_showTracks) {
@ -38,24 +43,29 @@ QList<GraphItem*> TemperatureGraph::loadData(const Data &data)
const Graph &graph = track.temperature(); const Graph &graph = track.temperature();
if (!graph.isValid()) { if (!graph.isValid()) {
skipColor(); _palette.nextColor();
graphs.append(0); graphs.append(0);
} else { } else {
TemperatureGraphItem *gi = new TemperatureGraphItem(graph, TemperatureGraphItem *gi = new TemperatureGraphItem(graph,
_graphType); _graphType, _width, _palette.nextColor());
GraphView::addGraph(gi); gi->setUnits(_units);
_tracks.append(gi);
if (_showTracks)
addGraph(gi);
_avg.append(QPointF(track.distance(), gi->avg())); _avg.append(QPointF(track.distance(), gi->avg()));
graphs.append(gi); graphs.append(gi);
} }
} }
for (int i = 0; i < data.routes().count(); i++) { for (int i = 0; i < data.routes().count(); i++) {
skipColor(); _palette.nextColor();
graphs.append(0); graphs.append(0);
} }
for (int i = 0; i < data.areas().count(); i++) for (int i = 0; i < data.areas().count(); i++)
skipColor(); _palette.nextColor();
setInfo(); setInfo();
redraw(); redraw();
@ -78,6 +88,9 @@ qreal TemperatureGraph::avg() const
void TemperatureGraph::clear() void TemperatureGraph::clear()
{ {
qDeleteAll(_tracks);
_tracks.clear();
_avg.clear(); _avg.clear();
GraphTab::clear(); GraphTab::clear();
@ -108,7 +121,13 @@ void TemperatureGraph::showTracks(bool show)
{ {
_showTracks = 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(); setInfo();
redraw(); redraw();

View File

@ -3,12 +3,15 @@
#include "graphtab.h" #include "graphtab.h"
class TemperatureGraphItem;
class TemperatureGraph : public GraphTab class TemperatureGraph : public GraphTab
{ {
Q_OBJECT Q_OBJECT
public: public:
TemperatureGraph(QWidget *parent = 0); TemperatureGraph(QWidget *parent = 0);
~TemperatureGraph();
QString label() const {return tr("Temperature");} QString label() const {return tr("Temperature");}
QList<GraphItem*> loadData(const Data &data); QList<GraphItem*> loadData(const Data &data);
@ -26,6 +29,7 @@ private:
QVector<QPointF> _avg; QVector<QPointF> _avg;
bool _showTracks; bool _showTracks;
QList<TemperatureGraphItem *> _tracks;
}; };
#endif // TEMPERATUREGRAPH_H #endif // TEMPERATUREGRAPH_H

View File

@ -4,7 +4,8 @@
TemperatureGraphItem::TemperatureGraphItem(const Graph &graph, GraphType type, 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(); _min = GraphItem::min();
_max = GraphItem::max(); _max = GraphItem::max();

View File

@ -8,8 +8,8 @@ class TemperatureGraphItem : public GraphItem
Q_OBJECT Q_OBJECT
public: public:
TemperatureGraphItem(const Graph &graph, GraphType type, TemperatureGraphItem(const Graph &graph, GraphType type, int width,
QGraphicsItem *parent = 0); const QColor &color, QGraphicsItem *parent = 0);
qreal max() const {return _max;} qreal max() const {return _max;}
qreal min() const {return _min;} qreal min() const {return _min;}

View File

@ -71,13 +71,35 @@ static QHash<QString, Parser*> parsers()
QHash<QString, Parser*> Data::_parsers = parsers(); QHash<QString, Parser*> Data::_parsers = parsers();
bool Data::_useDEM = false; bool Data::_useDEM = false;
void Data::processData(const QList<TrackData> &trackData, void Data::processData(QList<TrackData> &trackData, QList<RouteData> &routeData)
const 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++) { for (int i = 0; i < _waypoints.size(); i++) {
if (!_waypoints.at(i).hasElevation() || _useDEM) { if (!_waypoints.at(i).hasElevation() || _useDEM) {
qreal elevation = DEM::elevation(_waypoints.at(i).coordinates()); qreal elevation = DEM::elevation(_waypoints.at(i).coordinates());
@ -181,6 +203,4 @@ QStringList Data::filter()
void Data::useDEM(bool use) void Data::useDEM(bool use)
{ {
_useDEM = use; _useDEM = use;
Route::useDEM(use);
Track::useDEM(use);
} }

View File

@ -31,8 +31,7 @@ public:
static void useDEM(bool use); static void useDEM(bool use);
private: private:
void processData(const QList<TrackData> &trackData, void processData(QList<TrackData> &trackData, QList<RouteData> &routeData);
const QList<RouteData> &routeData);
bool _valid; bool _valid;
QString _errorString; QString _errorString;

View File

@ -265,6 +265,14 @@ bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
if (val != 0x7f) if (val != 0x7f)
ctx.trackpoint.setTemperature((qint8)val); ctx.trackpoint.setTemperature((qint8)val);
break; 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: default:
break; break;

View File

@ -54,6 +54,7 @@ public:
return false; return false;
return true; return true;
} }
bool hasTime() const bool hasTime() const
{ {
for (int i = 0; i < size(); i++) { for (int i = 0; i < size(); i++) {

View File

@ -130,6 +130,8 @@ bool IGCParser::readBRecord(SegmentData &segment, const char *line,
if (len < 35) if (len < 35)
return false; return false;
if (line[24] != 'A')
return true;
if (!readTimestamp(line + 1, time)) { if (!readTimestamp(line + 1, time)) {
_errorString = "Invalid timestamp"; _errorString = "Invalid timestamp";

View File

@ -1,9 +1,6 @@
#include "dem.h"
#include "route.h" #include "route.h"
bool Route::_useDEM = false;
Route::Route(const RouteData &data) : _data(data) Route::Route(const RouteData &data) : _data(data)
{ {
qreal dist = 0; qreal dist = 0;
@ -34,19 +31,9 @@ Graph Route::elevation() const
graph.append(GraphSegment()); graph.append(GraphSegment());
GraphSegment &gs = graph.last(); GraphSegment &gs = graph.last();
for (int i = 0; i < _data.size(); i++) { for (int i = 0; i < _data.size(); i++)
if (_data.at(i).hasElevation() && !_useDEM) if (_data.at(i).hasElevation())
gs.append(GraphPoint(_distance.at(i), NAN, gs.append(GraphPoint(_distance.at(i), NAN, _data.at(i).elevation()));
_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()));
}
}
return graph; return graph;
} }

View File

@ -13,7 +13,7 @@ public:
Path path() const; Path path() const;
const QVector<Waypoint> &waypoints() const {return _data;} const RouteData &data() const {return _data;}
Graph elevation() const; Graph elevation() const;
@ -24,13 +24,9 @@ public:
bool isValid() const {return _data.size() >= 2;} bool isValid() const {return _data.size() >= 2;}
static void useDEM(bool use) {_useDEM = use;}
private: private:
RouteData _data; RouteData _data;
QVector<qreal> _distance; QVector<qreal> _distance;
static bool _useDEM;
}; };
#endif // ROUTE_H #endif // ROUTE_H

View File

@ -1,4 +1,3 @@
#include "dem.h"
#include "track.h" #include "track.h"
@ -13,7 +12,6 @@ int Track::_pauseInterval = 10;
bool Track::_outlierEliminate = true; bool Track::_outlierEliminate = true;
bool Track::_useReportedSpeed = false; bool Track::_useReportedSpeed = false;
bool Track::_useDEM = false;
static qreal median(QVector<qreal> &v) static qreal median(QVector<qreal> &v)
@ -178,21 +176,10 @@ Graph Track::elevation() const
GraphSegment gs; GraphSegment gs;
for (int j = 0; j < sd.size(); j++) { for (int j = 0; j < sd.size(); j++) {
if (seg.outliers.contains(j)) if (!sd.at(j).hasElevation() || seg.outliers.contains(j))
continue; continue;
gs.append(GraphPoint(seg.distance.at(j), seg.time.at(j),
if (sd.at(j).hasElevation() && !_useDEM) sd.at(j).elevation()));
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()));
}
} }
ret.append(filter(gs, _elevationWindow)); ret.append(filter(gs, _elevationWindow));

View File

@ -45,7 +45,6 @@ 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;}
private: private:
struct Segment { struct Segment {
@ -71,7 +70,6 @@ private:
static qreal _pauseSpeed; static qreal _pauseSpeed;
static int _pauseInterval; static int _pauseInterval;
static bool _useReportedSpeed; static bool _useReportedSpeed;
static bool _useDEM;
}; };
#endif // TRACK_H #endif // TRACK_H

View File

@ -9,7 +9,7 @@
#define CHECK(condition) \ #define CHECK(condition) \
if (!(condition)) { \ if (!(condition)) { \
_errorString = "Invalid/corrupted IMG file"; \ _errorString = "Unsupported or invalid IMG file"; \
return; \ return; \
} }
@ -85,11 +85,6 @@ IMG::IMG(const QString &fileName)
&& read(type, sizeof(type)) && readValue(size) && readValue(part)); && read(type, sizeof(type)) && readValue(size) && readValue(part));
SubFile::Type tt = SubFile::type(type); SubFile::Type tt = SubFile::type(type);
if (tt == SubFile::GMP) {
_errorString = "NT maps not supported";
return;
}
QString fn(QByteArray(name, sizeof(name))); QString fn(QByteArray(name, sizeof(name)));
if (SubFile::isTileFile(tt)) { if (SubFile::isTileFile(tt)) {
VectorTile *tile; VectorTile *tile;
@ -101,7 +96,7 @@ IMG::IMG(const QString &fileName)
tile = *it; tile = *it;
SubFile *file = part ? tile->file(tt) SubFile *file = part ? tile->file(tt)
: tile->addFile(this, tt, size); : tile->addFile(this, tt);
CHECK(file); CHECK(file);
_file.seek(offset + 0x20); _file.seek(offset + 0x20);
@ -114,7 +109,7 @@ IMG::IMG(const QString &fileName)
} else if (tt == SubFile::TYP) { } else if (tt == SubFile::TYP) {
SubFile *typ = 0; SubFile *typ = 0;
if (typFile.isNull()) { if (typFile.isNull()) {
_typ = new SubFile(this, size); _typ = new SubFile(this);
typ = _typ; typ = _typ;
typFile = fn; typFile = fn;
} else if (fn == typFile) } else if (fn == typFile)
@ -166,7 +161,7 @@ void IMG::load()
{ {
Q_ASSERT(!_style); Q_ASSERT(!_style);
if (_typ && _typ->isValid()) if (_typ)
_style = new Style(_typ); _style = new Style(_typ);
else { else {
QFile typFile(ProgramPaths::typFile()); QFile typFile(ProgramPaths::typFile());

View File

@ -56,11 +56,11 @@ bool LBLFile::init()
quint16 codepage; quint16 codepage;
quint8 multiplier, poiMultiplier; quint8 multiplier, poiMultiplier;
if (!(seek(hdl, 0x15) && readUInt32(hdl, _offset) if (!(seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset)
&& readUInt32(hdl, _size) && readByte(hdl, multiplier) && 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) && readUInt32(hdl, _poiOffset) && readUInt32(hdl, _poiSize)
&& readByte(hdl, poiMultiplier) && seek(hdl, 0xAA) && readByte(hdl, poiMultiplier) && seek(hdl, _gmpOffset + 0xAA)
&& readUInt16(hdl, codepage))) && readUInt16(hdl, codepage)))
return false; return false;

View File

@ -9,9 +9,12 @@ class QTextCodec;
class LBLFile : public SubFile class LBLFile : public SubFile
{ {
public: public:
LBLFile(IMG *img, quint32 size) LBLFile(IMG *img)
: SubFile(img, size), _codec(0), _offset(0), _size(0), _poiOffset(0), : SubFile(img), _codec(0), _offset(0), _size(0), _poiOffset(0),
_poiSize(0), _poiMultiplier(0), _multiplier(0), _encoding(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); Label label(Handle &hdl, quint32 offset, bool poi = false);

View File

@ -5,7 +5,7 @@ bool NETFile::init()
Handle hdl; Handle hdl;
quint8 multiplier; quint8 multiplier;
if (!(seek(hdl, 0x15) && readUInt32(hdl, _offset) if (!(seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset)
&& readUInt32(hdl, _size) && readByte(hdl, multiplier))) && readUInt32(hdl, _size) && readByte(hdl, multiplier)))
return false; return false;

View File

@ -6,8 +6,9 @@
class NETFile : public SubFile class NETFile : public SubFile
{ {
public: public:
NETFile(IMG *img, quint32 size) NETFile(IMG *img) : SubFile(img), _offset(0), _size(0), _multiplier(0) {}
: SubFile(img, size), _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); bool lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset);

View File

@ -1,10 +1,26 @@
#include "trefile.h" #include "common/rectc.h"
#include "units.h" #include "units.h"
#include "lblfile.h" #include "lblfile.h"
#include "netfile.h" #include "netfile.h"
#include "rgnfile.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) bool RGNFile::BitStream::read(int bits, quint32 &val)
{ {
val = 0; val = 0;
@ -34,29 +50,42 @@ bool RGNFile::BitStream::read(int bits, quint32 &val)
return true; 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) qint32 &delta)
{ {
quint32 value; quint32 value;
int bo = 0;
if (!read(bits, value)) if (!read(bits, value))
return false; return false;
if (extraBit) { value >>= extraBit;
value>>=1;
bo = 1;
}
if (!sign) { if (!sign) {
qint32 signMask = 1 << (bits - bo - 1); qint32 signMask = 1 << (bits - extraBit - 1);
if (value & signMask) { if (value & signMask) {
qint32 comp = value ^ signMask; qint32 comp = value ^ signMask;
if (comp) if (comp)
delta = comp - signMask; delta = comp - signMask;
else { else {
qint32 other; qint32 other;
if (!readDelta(bits - bo, sign, false, other)) if (!readDelta(bits - extraBit, sign, false, other))
return false; return false;
if (other < 0) if (other < 0)
delta = 1 - signMask + other; delta = 1 - signMask + other;
@ -73,42 +102,15 @@ bool RGNFile::BitStream::readDelta(int bits, int sign, bool extraBit,
return true; return true;
} }
bool RGNFile::BitStream::finish() bool RGNFile::DeltaStream::sign(int &val)
{
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)
{ {
quint32 bit; quint32 bit;
val = 0; val = 0;
if (!bs.read(1, bit)) if (!read(1, bit))
return false; return false;
if (bit) { if (bit) {
if (!bs.read(1, bit)) if (!read(1, bit))
return false; return false;
val = bit ? -1 : 1; val = bit ? -1 : 1;
} }
@ -116,20 +118,41 @@ bool RGNFile::sign(BitStream &bs, int &val)
return true; return true;
} }
int RGNFile::bitSize(quint8 baseSize, bool variableSign, bool extraBit)
bool RGNFile::init()
{ {
int bits = 2; Handle hdl;
if (baseSize <= 9) quint16 hdrLen;
bits += baseSize;
else
bits += 2 * baseSize - 9;
if (variableSign) if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)
bits++; && seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset)
if (extraBit) && readUInt32(hdl, _size)))
bits++; 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, 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) poly.type = (segment.type() == Segment::Polygon)
? ((quint32)(type & 0x7F)) << 8 : ((quint32)(type & 0x3F)) << 8; ? ((quint32)(type & 0x7F)) << 8 : ((quint32)(type & 0x3F)) << 8;
RectC br;
QPoint pos(subdiv->lon() + ((qint32)lon<<(24-subdiv->bits())), QPoint pos(subdiv->lon() + ((qint32)lon<<(24-subdiv->bits())),
subdiv->lat() + ((qint32)lat<<(24-subdiv->bits()))); subdiv->lat() + ((qint32)lat<<(24-subdiv->bits())));
Coordinates c(toWGS84(pos.x()), toWGS84(pos.y())); Coordinates c(toWGS84(pos.x()), toWGS84(pos.y()));
br = br.united(c); RectC br(c, c);
poly.points.append(QPointF(c.lon(), c.lat())); poly.points.append(QPointF(c.lon(), c.lat()));
BitStream bs(*this, hdl, len); qint32 lonDelta, latDelta;
int lonSign, latSign; DeltaStream stream(*this, hdl, len, bitstreamInfo, labelPtr & 0x400000,
if (!sign(bs, lonSign) || !sign(bs, latSign)) false);
return false; while (stream.readNext(lonDelta, latDelta)) {
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;
pos.rx() += lonDelta<<(24-subdiv->bits()); pos.rx() += lonDelta<<(24-subdiv->bits());
pos.ry() += latDelta<<(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())); poly.points.append(QPointF(c.lon(), c.lat()));
br = br.united(c); br = br.united(c);
} }
if (!bs.finish()) if (!(stream.atEnd() && stream.flush()))
return false; return false;
if (!rect.intersects(br)) 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, const SubDiv *subdiv, const Segment &segment, LBLFile *lbl, Handle &lblHdl,
QList<IMG::Poly> *polys) const QList<IMG::Poly> *polys) const
{ {
quint32 labelPtr; quint32 len, labelPtr = 0;
quint8 type, subtype, len8, len82, bitstreamInfo; quint8 type, subtype, bitstreamInfo;
qint16 lon, lat; qint16 lon, lat;
quint16 len;
if (!seek(hdl, segment.start())) if (!seek(hdl, segment.start()))
@ -235,7 +246,8 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
IMG::Poly poly; IMG::Poly poly;
if (!(readByte(hdl, type) && readByte(hdl, subtype) 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; return false;
if (subtype & 0x80) { if (subtype & 0x80) {
@ -243,40 +255,17 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
return false; 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); poly.type = 0x10000 + (quint16(type) << 8) + (subtype & 0x1F);
RectC br;
QPoint pos(subdiv->lon() + ((qint32)lon<<(24-subdiv->bits())), QPoint pos(subdiv->lon() + ((qint32)lon<<(24-subdiv->bits())),
subdiv->lat() + ((qint32)lat<<(24-subdiv->bits()))); subdiv->lat() + ((qint32)lat<<(24-subdiv->bits())));
Coordinates c(toWGS84(pos.x()), toWGS84(pos.y())); Coordinates c(toWGS84(pos.x()), toWGS84(pos.y()));
br = br.united(c); RectC br(c, c);
poly.points.append(QPointF(c.lon(), c.lat())); poly.points.append(QPointF(c.lon(), c.lat()));
BitStream bs(*this, hdl, len); qint32 lonDelta, latDelta;
int lonSign, latSign; DeltaStream stream(*this, hdl, len - 1, bitstreamInfo, false, true);
if (!sign(bs, lonSign) || !sign(bs, latSign)) while (stream.readNext(lonDelta, latDelta)) {
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;
pos.rx() += lonDelta<<(24-subdiv->bits()); pos.rx() += lonDelta<<(24-subdiv->bits());
pos.ry() += latDelta<<(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())); poly.points.append(QPointF(c.lon(), c.lat()));
br = br.united(c); br = br.united(c);
} }
if (!bs.finish()) if (!(stream.atEnd() && stream.flush()))
return false; return false;
if (subtype & 0x20) { if ((subtype & 0x20)) {
if (!readUInt24(hdl, labelPtr)) if (!readUInt24(hdl, labelPtr))
return false; return false;
if (lbl && (labelPtr & 0x3FFFFF)) } else
poly.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF); labelPtr = 0;
}
if (!rect.intersects(br)) if (!rect.intersects(br))
continue; continue;
if (lbl && (labelPtr & 0x3FFFFF))
poly.label = lbl->label(lblHdl, labelPtr & 0x3FFFFF);
polys->append(poly); polys->append(poly);
} }
@ -404,7 +395,7 @@ void RGNFile::objects(const RectC &rect, const SubDiv *subdiv, LBLFile *lbl,
{ {
Handle rgnHdl, lblHdl, netHdl; Handle rgnHdl, lblHdl, netHdl;
if (!_size && !init()) if (!_init && !init())
return; return;
QVector<RGNFile::Segment> seg(segments(rgnHdl, subdiv)); 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; Handle rgnHdl, lblHdl;
if (!_size && !init()) if (!_init && !init())
return; return;
if (polygons && subdiv->polygonsOffset() != subdiv->polygonsEnd()) { if (polygons && subdiv->polygonsOffset() != subdiv->polygonsEnd()) {

View File

@ -11,10 +11,13 @@ class NETFile;
class RGNFile : public SubFile class RGNFile : public SubFile
{ {
public: public:
RGNFile(IMG *img, quint32 size) RGNFile(IMG *img)
: SubFile(img, size), _offset(0), _size(0), _polygonsOffset(0), : SubFile(img), _offset(0), _size(0), _polygonsOffset(0),
_polygonsSize(), _linesOffset(), _linesSize(), _pointsOffset(), _polygonsSize(0), _linesOffset(0), _linesSize(0), _pointsOffset(0),
_pointsSize() {} _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, void objects(const RectC &rect, const SubDiv *subdiv, LBLFile *lbl,
NETFile *net, QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines, NETFile *net, QList<IMG::Poly> *polygons, QList<IMG::Poly> *lines,
@ -53,27 +56,45 @@ private:
class BitStream { class BitStream {
public: 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) {} : _file(file), _hdl(hdl), _length(length), _remaining(0) {}
bool read(int bits, quint32 &val); bool read(int bits, quint32 &val);
bool readDelta(int bits, int sign, bool extraBit, qint32 &delta); bool flush() {return _file.seek(_hdl, _hdl.pos + _length);}
bool hasNext(int bits) const quint32 bitsAvailable() const {return _length * 8 + _remaining;}
{return _length * 8 + _remaining >= (quint32)bits;}
bool finish();
private: private:
const SubFile &_file; const SubFile &_file;
Handle &_hdl; Handle &_hdl;
quint16 _length; quint32 _length, _remaining;
quint32 _remaining;
quint8 _data; quint8 _data;
}; };
static bool sign(BitStream &bs, int &val); class DeltaStream : public BitStream {
static int bitSize(quint8 baseSize, bool variableSign, bool extraBit); 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(); bool init();
QVector<Segment> segments(Handle &hdl, const SubDiv *subdiv) const; QVector<Segment> segments(Handle &hdl, const SubDiv *subdiv) const;
bool polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv, bool polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
const Segment &segment, LBLFile *lbl, Handle &lblHdl, NETFile *net, const Segment &segment, LBLFile *lbl, Handle &lblHdl, NETFile *net,
@ -99,6 +120,8 @@ private:
quint32 _linesSize; quint32 _linesSize;
quint32 _pointsOffset; quint32 _pointsOffset;
quint32 _pointsSize; quint32 _pointsSize;
bool _init;
}; };
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG

View File

@ -942,7 +942,7 @@ Style::Style(SubFile *typ)
defaultPolygonStyle(); defaultPolygonStyle();
defaultPointStyle(); defaultPointStyle();
if (typ && typ->isValid()) if (typ)
parseTYPFile(typ); parseTYPFile(typ);
} }

View File

@ -20,21 +20,13 @@ SubFile::Type SubFile::type(const char str[3])
return Unknown; 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)) if (!_file->open(QIODevice::ReadOnly))
qWarning("Error opening %s: %s", qPrintable(_file->fileName()), qWarning("Error opening %s: %s", qPrintable(_file->fileName()),
qPrintable(_file->errorString())); 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 bool SubFile::seek(Handle &handle, quint32 pos) const
{ {
Q_ASSERT(_img || _file); Q_ASSERT(_img || _file);
@ -46,9 +38,9 @@ bool SubFile::seek(Handle &handle, quint32 pos) const
int blockNum = pos / blockSize; int blockNum = pos / blockSize;
if (handle.blockNum != blockNum) { if (handle.blockNum != blockNum) {
if (blockNum >= _blocks.size()) if (blockNum >= _blocks->size())
return false; return false;
if (!_img->readBlock(_blocks.at(blockNum), handle.data)) if (!_img->readBlock(_blocks->at(blockNum), handle.data))
return false; return false;
handle.blockNum = blockNum; 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 QString SubFile::fileName() const
@ -88,15 +106,15 @@ QString SubFile::fileName() const
QDebug operator<<(QDebug dbg, const SubFile &file) QDebug operator<<(QDebug dbg, const SubFile &file)
{ {
bool continuous = true; bool continuous = true;
for (int i = 1; i < file._blocks.size(); i++) { for (int i = 1; i < file._blocks->size(); i++) {
if (file._blocks.at(i) != file._blocks.at(i-1) + 1) { if (file._blocks->at(i) != file._blocks->at(i-1) + 1) {
continuous = false; continuous = false;
break; break;
} }
} }
dbg.nospace() << "SubFile(" << file._size << ", " << file._blocks.size() dbg.nospace() << "SubFile(" << file._blocks->size() << ", "
<< ", " << continuous << ")"; << continuous << ")";
return dbg.space(); return dbg.space();
} }
#endif // QT_NO_DEBUG #endif // QT_NO_DEBUG

View File

@ -22,13 +22,14 @@ public:
int pos; 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); SubFile(QFile *file);
void addBlock(quint16 block) {_blocks.append(block);} void addBlock(quint16 block) {_blocks->append(block);}
bool isValid() const;
quint32 size() const;
bool seek(Handle &handle, quint32 pos) const; bool seek(Handle &handle, quint32 pos) const;
bool readByte(Handle &handle, quint8 &val) const; bool readByte(Handle &handle, quint8 &val) const;
@ -80,20 +81,28 @@ public:
return true; return true;
} }
quint16 offset() const {return _blocks.first();} bool readVUInt32(Handle &hdl, quint32 &val) const;
quint16 offset() const {return _blocks->first();}
QString fileName() const; QString fileName() const;
static Type type(const char str[3]); static Type type(const char str[3]);
static bool isTileFile(Type type) 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); friend QDebug operator<<(QDebug dbg, const SubFile &file);
protected:
quint32 _gmpOffset;
private: private:
IMG *_img; IMG *_img;
QFile *_file; QFile *_file;
quint32 _size; QVector<quint16> *_blocks;
QVector<quint16> _blocks; QVector<quint16> _blockData;
}; };
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG

View File

@ -43,28 +43,28 @@ bool TREFile::init()
quint8 locked; quint8 locked;
quint16 hdrLen; quint16 hdrLen;
if (!(seek(hdl, 0) && readUInt16(hdl, hdrLen) if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)
&& seek(hdl, 0x0D) && readByte(hdl, locked))) && seek(hdl, _gmpOffset + 0x0D) && readByte(hdl, locked)))
return false; return false;
// Tile bounds // Tile bounds
qint32 north, east, south, west; qint32 north, east, south, west;
if (!(seek(hdl, 0x15) && readInt24(hdl, north) && readInt24(hdl, east) if (!(seek(hdl, _gmpOffset + 0x15) && readInt24(hdl, north)
&& readInt24(hdl, south) && readInt24(hdl, west))) && readInt24(hdl, east) && readInt24(hdl, south) && readInt24(hdl, west)))
return false; return false;
_bounds = RectC(Coordinates(toWGS84(west), toWGS84(north)), _bounds = RectC(Coordinates(toWGS84(west), toWGS84(north)),
Coordinates(toWGS84(east), toWGS84(south))); Coordinates(toWGS84(east), toWGS84(south)));
// Levels & subdivs info // Levels & subdivs info
quint32 levelsOffset, levelsSize, subdivSize; 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, levelsSize) && readUInt32(hdl, _subdivOffset)
&& readUInt32(hdl, subdivSize))) && readUInt32(hdl, subdivSize)))
return false; return false;
// TRE7 info // TRE7 info
if (hdrLen > 0x9A) { if (hdrLen > 0x9A) {
if (!(seek(hdl, 0x7C) && readUInt32(hdl, _extended.offset) if (!(seek(hdl, _gmpOffset + 0x7C) && readUInt32(hdl, _extended.offset)
&& readUInt32(hdl, _extended.size) && readUInt32(hdl, _extended.size)
&& readUInt16(hdl, _extended.itemSize))) && readUInt16(hdl, _extended.itemSize)))
return false; return false;
@ -80,7 +80,7 @@ bool TREFile::init()
if (locked) { if (locked) {
quint32 key; quint32 key;
quint8 unlocked[64]; quint8 unlocked[64];
if (!seek(hdl, 0xAA) || !readUInt32(hdl, key)) if (!seek(hdl, _gmpOffset + 0xAA) || !readUInt32(hdl, key))
return false; return false;
unlock(unlocked, levels, levelsSize, key); unlock(unlocked, levels, levelsSize, key);
memcpy(levels, unlocked, levelsSize); memcpy(levels, unlocked, levelsSize);

View File

@ -13,7 +13,8 @@ class SubDiv;
class TREFile : public SubFile class TREFile : public SubFile
{ {
public: public:
TREFile(IMG *img, quint32 size) : SubFile(img, size) {} TREFile(IMG *img) : SubFile(img) {}
TREFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset) {}
~TREFile(); ~TREFile();
bool init(); bool init();

View File

@ -11,26 +11,31 @@ SubFile *VectorTile::file(SubFile::Type type)
return _lbl; return _lbl;
case SubFile::NET: case SubFile::NET:
return _net; return _net;
case SubFile::GMP:
return _gmp;
default: default:
return 0; return 0;
} }
} }
SubFile *VectorTile::addFile(IMG *img, SubFile::Type type, quint32 size) SubFile *VectorTile::addFile(IMG *img, SubFile::Type type)
{ {
switch (type) { switch (type) {
case SubFile::TRE: case SubFile::TRE:
_tre = new TREFile(img, size); _tre = new TREFile(img);
return _tre; return _tre;
case SubFile::RGN: case SubFile::RGN:
_rgn = new RGNFile(img, size); _rgn = new RGNFile(img);
return _rgn; return _rgn;
case SubFile::LBL: case SubFile::LBL:
_lbl = new LBLFile(img, size); _lbl = new LBLFile(img);
return _lbl; return _lbl;
case SubFile::NET: case SubFile::NET:
_net = new NETFile(img, size); _net = new NETFile(img);
return _net; return _net;
case SubFile::GMP:
_gmp = new SubFile(img);
return _gmp;
default: default:
return 0; return 0;
} }
@ -38,14 +43,30 @@ SubFile *VectorTile::addFile(IMG *img, SubFile::Type type, quint32 size)
bool VectorTile::init() bool VectorTile::init()
{ {
if (!(_tre && _tre->isValid() && _tre->init() && _rgn if (_gmp && !initGMP())
&& _rgn->isValid()))
return false; return false;
if (_lbl && !_lbl->isValid())
if (!(_tre && _tre->init() && _rgn))
return false; 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; return false;
_tre = new TREFile(_gmp, tre);
_rgn = new RGNFile(_gmp, rgn);
_lbl = new LBLFile(_gmp, lbl);
_net = new NETFile(_gmp, net);
return true; return true;
} }

View File

@ -10,8 +10,9 @@
class VectorTile { class VectorTile {
public: public:
VectorTile() : _tre(0), _rgn(0), _lbl(0), _net(0) {} VectorTile() : _tre(0), _rgn(0), _lbl(0), _net(0), _gmp(0) {}
~VectorTile() {delete _tre; delete _rgn; delete _lbl; delete _net;} ~VectorTile()
{delete _tre; delete _rgn; delete _lbl; delete _net; delete _gmp;}
bool init(); bool init();
void clear() {_tre->clear();} void clear() {_tre->clear();}
@ -19,7 +20,7 @@ public:
const RectC &bounds() const {return _tre->bounds();} const RectC &bounds() const {return _tre->bounds();}
SubFile *file(SubFile::Type type); 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, void objects(const RectC &rect, int bits, QList<IMG::Poly> *polygons,
QList<IMG::Poly> *lines, QList<IMG::Point> *points) const; QList<IMG::Poly> *lines, QList<IMG::Point> *points) const;
@ -27,10 +28,13 @@ public:
friend QDebug operator<<(QDebug dbg, const VectorTile &tile); friend QDebug operator<<(QDebug dbg, const VectorTile &tile);
private: private:
bool initGMP();
TREFile *_tre; TREFile *_tre;
RGNFile *_rgn; RGNFile *_rgn;
LBLFile *_lbl; LBLFile *_lbl;
NETFile *_net; NETFile *_net;
SubFile *_gmp;
}; };
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG