1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-28 05:34:47 +01:00

Fixed track tooltip area handling

Added some more waypoint info to waypoint tooltips.
Refactoring & optimization.
This commit is contained in:
Martin Tůma 2016-07-28 00:23:22 +02:00
parent dac06b9537
commit 7de08d116a
21 changed files with 380 additions and 210 deletions

View File

@ -45,7 +45,8 @@ HEADERS += src/config.h \
src/margins.h \ src/margins.h \
src/temperaturegraph.h \ src/temperaturegraph.h \
src/graphtab.h \ src/graphtab.h \
src/misc.h src/misc.h \
src/trackitem.h
SOURCES += src/main.cpp \ SOURCES += src/main.cpp \
src/gui.cpp \ src/gui.cpp \
src/gpx.cpp \ src/gpx.cpp \
@ -77,7 +78,9 @@ SOURCES += src/main.cpp \
src/fileselectwidget.cpp \ src/fileselectwidget.cpp \
src/temperaturegraph.cpp \ src/temperaturegraph.cpp \
src/trackpoint.cpp \ src/trackpoint.cpp \
src/misc.cpp src/misc.cpp \
src/waypoint.cpp \
src/trackitem.cpp
RESOURCES += gpxsee.qrc RESOURCES += gpxsee.qrc
TRANSLATIONS = lang/gpxsee_cs.ts TRANSLATIONS = lang/gpxsee_cs.ts
macx { macx {

View File

@ -564,6 +564,21 @@
<source>m</source> <source>m</source>
<translation>m</translation> <translation>m</translation>
</message> </message>
<message>
<location filename="../src/trackitem.cpp" line="14"/>
<source>Date:</source>
<translation>Datum:</translation>
</message>
<message>
<location filename="../src/trackitem.cpp" line="15"/>
<source>Distance:</source>
<translation>Vzdálenost:</translation>
</message>
<message>
<location filename="../src/trackitem.cpp" line="16"/>
<source>Time:</source>
<translation>Čas:</translation>
</message>
</context> </context>
<context> <context>
<name>SpeedGraph</name> <name>SpeedGraph</name>
@ -678,22 +693,4 @@
<translation>F</translation> <translation>F</translation>
</message> </message>
</context> </context>
<context>
<name>TrackView</name>
<message>
<location filename="../src/trackview.cpp" line="55"/>
<source>Date:</source>
<translation>Datum:</translation>
</message>
<message>
<location filename="../src/trackview.cpp" line="55"/>
<source>Distance:</source>
<translation>Vzdálenost:</translation>
</message>
<message>
<location filename="../src/trackview.cpp" line="56"/>
<source>Time:</source>
<translation>Cas:</translation>
</message>
</context>
</TS> </TS>

View File

@ -64,3 +64,13 @@ QString distance(qreal value, Units units)
+ UNIT_SPACE + QObject::tr("km"); + UNIT_SPACE + QObject::tr("km");
} }
} }
QString coordinates(const QPointF &value)
{
QChar yH = (value.y() < 0) ? 'S' : 'N';
QChar xH = (value.x() < 0) ? 'W' : 'E';
return QString::number(qAbs(value.y()), 'f', 5) + QChar(0x00B0) + " " + yH
+ ", " + QString::number(qAbs(value.x()), 'f', 5) + QChar(0x00B0) + " "
+ xH ;
}

View File

@ -2,10 +2,13 @@
#define MISC_H #define MISC_H
#include <QString> #include <QString>
#include <QPoint>
#include "units.h" #include "units.h"
double niceNum(double x, int round); double niceNum(double x, int round);
QString timeSpan(qreal time); QString timeSpan(qreal time);
QString distance(qreal value, Units units); QString distance(qreal value, Units units);
QString coordinates(const QPointF &value);
#endif // MISC_H #endif // MISC_H

View File

@ -1,48 +1,58 @@
#include "parser.h" #include "parser.h"
void Parser::handleTrackpointData(TrackpointElement element, void Parser::handleTrackpointData(DataType type, const QString &value)
const QString &value)
{ {
switch (element) { switch (type) {
case Elevation: case Elevation:
_track->last().elevation = value.toLatin1().toDouble(); _track->last().setElevation(value.toLatin1().toDouble());
break; break;
case Time: case Time:
_track->last().timestamp = QDateTime::fromString(value.toLatin1(), _track->last().setTimestamp(QDateTime::fromString(value.toLatin1(),
Qt::ISODate); Qt::ISODate));
break; break;
case Geoidheight: case Geoidheight:
_track->last().geoidheight = value.toLatin1().toDouble(); _track->last().setGeoidHeight(value.toLatin1().toDouble());
break; break;
case Speed: case Speed:
_track->last().speed = value.toDouble(); _track->last().setSpeed(value.toDouble());
break; break;
case HeartRate: case HeartRate:
_track->last().heartRate = value.toDouble(); _track->last().setHeartRate(value.toDouble());
break; break;
case Temperature: case Temperature:
_track->last().temperature = value.toDouble(); _track->last().setTemperature(value.toDouble());
break; break;
} }
} }
void Parser::handleWaypointData(WaypointElement element, const QString &value) void Parser::handleWaypointData(DataType type, const QString &value)
{ {
switch (element) { switch (type) {
case Name: case Name:
_waypoints.last().setName(value); _waypoints.last().setName(value);
break; break;
case Description: case Description:
_waypoints.last().setDescription(value); _waypoints.last().setDescription(value);
break; break;
case Time:
_waypoints.last().setTimestamp(QDateTime::fromString(
value.toLatin1(), Qt::ISODate));
break;
case Elevation:
_waypoints.last().setElevation(value.toLatin1().toDouble());
break;
case Geoidheight:
_waypoints.last().setGeoidHeight(value.toLatin1().toDouble());
break;
} }
} }
void Parser::handleTrackpointAttributes(const QXmlStreamAttributes &attr) void Parser::handleTrackpointAttributes(const QXmlStreamAttributes &attr)
{ {
_track->last().coordinates.setY(attr.value("lat").toLatin1().toDouble()); _track->last().setCoordinates(QPointF(
_track->last().coordinates.setX(attr.value("lon").toLatin1().toDouble()); attr.value("lon").toLatin1().toDouble(),
attr.value("lat").toLatin1().toDouble()));
} }
void Parser::handleWaypointAttributes(const QXmlStreamAttributes &attr) void Parser::handleWaypointAttributes(const QXmlStreamAttributes &attr)
@ -125,6 +135,12 @@ void Parser::waypointData()
handleWaypointData(Name, _reader.readElementText()); handleWaypointData(Name, _reader.readElementText());
else if (_reader.name() == "desc") else if (_reader.name() == "desc")
handleWaypointData(Description, _reader.readElementText()); handleWaypointData(Description, _reader.readElementText());
else if (_reader.name() == "ele")
handleWaypointData(Elevation, _reader.readElementText());
else if (_reader.name() == "geoidheight")
handleWaypointData(Geoidheight, _reader.readElementText());
else if (_reader.name() == "time")
handleWaypointData(Time, _reader.readElementText());
else else
_reader.skipCurrentElement(); _reader.skipCurrentElement();
} }

View File

@ -18,11 +18,9 @@ public:
int errorLine() const {return _reader.lineNumber();} int errorLine() const {return _reader.lineNumber();}
private: private:
enum TrackpointElement { enum DataType {
Elevation, Time, Geoidheight, Speed, HeartRate, Temperature Name, Description, Elevation, Time, Geoidheight, Speed, HeartRate,
}; Temperature
enum WaypointElement {
Name, Description
}; };
bool parse(); bool parse();
@ -35,9 +33,9 @@ private:
void waypointData(); void waypointData();
void handleWaypointAttributes(const QXmlStreamAttributes &attr); void handleWaypointAttributes(const QXmlStreamAttributes &attr);
void handleWaypointData(WaypointElement element, const QString &value); void handleWaypointData(DataType type, const QString &value);
void handleTrackpointAttributes(const QXmlStreamAttributes &attr); void handleTrackpointAttributes(const QXmlStreamAttributes &attr);
void handleTrackpointData(TrackpointElement element, const QString &value); void handleTrackpointData(DataType type, const QString &value);
QXmlStreamReader _reader; QXmlStreamReader _reader;
QList<QVector<Trackpoint> > &_tracks; QList<QVector<Trackpoint> > &_tracks;

View File

@ -1,6 +1,8 @@
#include <QFile> #include <QFile>
#include <QSet> #include <QSet>
#include <QList> #include <QList>
#include <QPainterPath>
#include "waypointitem.h"
#include "ll.h" #include "ll.h"
#include "gpx.h" #include "gpx.h"
#include "poi.h" #include "poi.h"
@ -50,10 +52,10 @@ bool POI::loadGPXFile(const QString &fileName)
index.end = _data.size() - 1; index.end = _data.size() - 1;
for (int i = index.start; i <= index.end; i++) { for (int i = index.start; i <= index.end; i++) {
const QPointF &p = _data.at(i).coordinates(); QPointF p = ll2mercator(_data.at(i).coordinates());
qreal c[2]; qreal c[2];
c[0] = p.x(); c[0] = p.x();
c[1] = p.y(); c[1] = -p.y();
_tree.Insert(c, c, i); _tree.Insert(c, c, i);
} }
@ -105,24 +107,27 @@ bool POI::loadCSVFile(const QString &fileName)
_errorLine = ln; _errorLine = ln;
return false; return false;
} }
Waypoint wp(QPointF(lon, lat));
QByteArray ba = list[2].trimmed(); QByteArray ba = list[2].trimmed();
QString name = QString::fromUtf8(ba.data(), ba.size()); QString name = QString::fromUtf8(ba.data(), ba.size());
QString description; wp.setName(name);
if (list.size() > 3) { if (list.size() > 3) {
ba = list[3].trimmed(); ba = list[3].trimmed();
description = QString::fromUtf8(ba.data(), ba.size()); wp.setDescription(QString::fromUtf8(ba.data(), ba.size()));
} }
_data.append(Waypoint(QPointF(lon, lat), name, description)); _data.append(wp);
ln++; ln++;
} }
index.end = _data.size() - 1; index.end = _data.size() - 1;
for (int i = index.start; i <= index.end; i++) { for (int i = index.start; i <= index.end; i++) {
const QPointF &p = _data.at(i).coordinates(); QPointF p = ll2mercator(_data.at(i).coordinates());
qreal c[2]; qreal c[2];
c[0] = p.x(); c[0] = p.x();
c[1] = p.y(); c[1] = -p.y();
_tree.Insert(c, c, i); _tree.Insert(c, c, i);
} }
@ -140,14 +145,39 @@ static bool cb(size_t data, void* context)
return true; return true;
} }
QVector<Waypoint> POI::points(const QVector<QPointF> &path, qreal radius) const QVector<Waypoint> POI::points(const QPainterPath &path, qreal radius) const
{ {
QVector<Waypoint> ret; QVector<Waypoint> ret;
QSet<int> set; QSet<int> set;
qreal min[2], max[2]; qreal min[2], max[2];
for (int i = 0; i < path.count(); i++) { for (int i = 0; i < path.elementCount(); i++) {
const QPointF &p = path.at(i); const QPointF &p = path.elementAt(i);
min[0] = p.x() - radius;
min[1] = p.y() - radius;
max[0] = p.x() + radius;
max[1] = p.y() + radius;
_tree.Search(min, max, cb, &set);
}
QSet<int>::const_iterator i = set.constBegin();
while (i != set.constEnd()) {
ret.append(_data.at(*i));
++i;
}
return ret;
}
QVector<Waypoint> POI::points(const QList<WaypointItem*> &list, qreal radius)
const
{
QVector<Waypoint> ret;
QSet<int> set;
qreal min[2], max[2];
for (int i = 0; i < list.count(); i++) {
const QPointF &p = list.at(i)->coordinates();
min[0] = p.x() - radius; min[0] = p.x() - radius;
min[1] = p.y() - radius; min[1] = p.y() - radius;
max[0] = p.x() + radius; max[0] = p.x() + radius;

View File

@ -8,6 +8,10 @@
#include "waypoint.h" #include "waypoint.h"
#include "rtree.h" #include "rtree.h"
class QPainterPath;
class WaypointItem;
#define POI_RADIUS 0.01
class POI class POI
{ {
@ -17,8 +21,11 @@ public:
const QString &errorString() const {return _error;} const QString &errorString() const {return _error;}
int errorLine() const {return _errorLine;} int errorLine() const {return _errorLine;}
QVector<Waypoint> points(const QVector<QPointF> &path, QVector<Waypoint> points(const QPainterPath &path,
qreal radius = 0.01) const; qreal radius = POI_RADIUS) const;
QVector<Waypoint> points(const QList<WaypointItem*> &list,
qreal radius = POI_RADIUS) const;
const QStringList &files() const {return _files;} const QStringList &files() const {return _files;}
void enableFile(const QString &fileName, bool enable); void enableFile(const QString &fileName, bool enable);
void clear(); void clear();

View File

@ -94,11 +94,11 @@ void TemperatureGraph::setXUnits()
void TemperatureGraph::setYUnits() void TemperatureGraph::setYUnits()
{ {
if (_units == Metric) { if (_units == Metric) {
GraphView::setYUnits(QString::fromUtf8("\xC2\xB0") + tr("C")); GraphView::setYUnits(QChar(0x00B0) + tr("C"));
setYScale(1); setYScale(1);
setYOffset(0); setYOffset(0);
} else { } else {
GraphView::setYUnits(QString::fromUtf8("\xC2\xB0") + tr("F")); GraphView::setYUnits(QChar(0x00B0) + tr("F"));
setYScale(C2FS); setYScale(C2FS);
setYOffset(C2FO); setYOffset(C2FO);
} }

View File

@ -85,7 +85,8 @@ Track::Track(const QVector<Trackpoint> &data) : _data(data)
_dd.append(dist); _dd.append(dist);
for (int i = 1; i < _data.count(); i++) { for (int i = 1; i < _data.count(); i++) {
dist += llDistance(_data.at(i).coordinates, _data.at(i-1).coordinates); dist += llDistance(_data.at(i).coordinates(),
_data.at(i-1).coordinates());
_dd.append(dist); _dd.append(dist);
} }
} }
@ -99,8 +100,8 @@ void Track::elevationGraph(QVector<QPointF> &graph) const
for (int i = 0; i < _data.size(); i++) for (int i = 0; i < _data.size(); i++)
if (_data.at(i).hasElevation()) if (_data.at(i).hasElevation())
raw.append(QPointF(_dd.at(i), _data.at(i).elevation raw.append(QPointF(_dd.at(i), _data.at(i).elevation()
- _data.at(i).geoidheight)); - _data.at(i).geoidHeight()));
graph = filter(raw, WINDOW_EF); graph = filter(raw, WINDOW_EF);
} }
@ -117,9 +118,10 @@ void Track::speedGraph(QVector<QPointF> &graph) const
raw.append(QPointF(0, 0)); raw.append(QPointF(0, 0));
for (int i = 1; i < _data.size(); i++) { for (int i = 1; i < _data.size(); i++) {
if (_data.at(i).hasSpeed()) if (_data.at(i).hasSpeed())
v = _data.at(i).speed; v = _data.at(i).speed();
else if (_data.at(i).hasTimestamp()) { else if (_data.at(i).hasTimestamp()) {
if (!(dt = _data.at(i-1).timestamp.msecsTo(_data.at(i).timestamp))) dt = _data.at(i-1).timestamp().msecsTo(_data.at(i).timestamp());
if (!dt)
continue; continue;
ds = _dd.at(i) - _dd.at(i-1); ds = _dd.at(i) - _dd.at(i-1);
v = ds / ((qreal)dt / 1000.0); v = ds / ((qreal)dt / 1000.0);
@ -141,7 +143,7 @@ void Track::heartRateGraph(QVector<QPointF> &graph) const
for (int i = 0; i < _data.count(); i++) for (int i = 0; i < _data.count(); i++)
if (_data.at(i).hasHeartRate()) if (_data.at(i).hasHeartRate())
raw.append(QPointF(_dd.at(i), _data.at(i).heartRate)); raw.append(QPointF(_dd.at(i), _data.at(i).heartRate()));
graph = filter(eliminate(raw, WINDOW_HE), WINDOW_HF); graph = filter(eliminate(raw, WINDOW_HE), WINDOW_HF);
} }
@ -153,13 +155,13 @@ void Track::temperatureGraph(QVector<QPointF> &graph) const
for (int i = 0; i < _data.size(); i++) for (int i = 0; i < _data.size(); i++)
if (_data.at(i).hasTemperature()) if (_data.at(i).hasTemperature())
graph.append(QPointF(_dd.at(i), _data.at(i).temperature)); graph.append(QPointF(_dd.at(i), _data.at(i).temperature()));
} }
void Track::track(QVector<QPointF> &track) const void Track::track(QVector<QPointF> &track) const
{ {
for (int i = 0; i < _data.size(); i++) for (int i = 0; i < _data.size(); i++)
track.append(_data.at(i).coordinates); track.append(_data.at(i).coordinates());
} }
qreal Track::time() const qreal Track::time() const
@ -167,13 +169,14 @@ qreal Track::time() const
if (_data.size() < 2) if (_data.size() < 2)
return 0; return 0;
return (_data.first().timestamp.msecsTo(_data.last().timestamp) / 1000.0); return (_data.first().timestamp().msecsTo(_data.last().timestamp())
/ 1000.0);
} }
QDateTime Track::date() const QDateTime Track::date() const
{ {
if (_data.size()) if (_data.size())
return _data.first().timestamp; return _data.first().timestamp();
else else
return QDateTime(); return QDateTime();
} }

View File

@ -19,6 +19,8 @@ public:
qreal time() const; qreal time() const;
QDateTime date() const; QDateTime date() const;
bool isNull() const {return (_data.count() < 2) ? true : false;}
private: private:
const QVector<Trackpoint> &_data; const QVector<Trackpoint> &_data;
QVector<qreal> _dd; QVector<qreal> _dd;

75
src/trackitem.cpp Normal file
View File

@ -0,0 +1,75 @@
#include <QCursor>
#include <QPen>
#include "ll.h"
#include "misc.h"
#include "trackitem.h"
#define TRACK_WIDTH 3
QString TrackItem::toolTip()
{
QString date = _date.date().toString(Qt::SystemLocaleShortDate);
return "<b>" + QObject::tr("Date:") + "</b> " + date + "<br><b>"
+ QObject::tr("Distance:") + "</b> " + distance(_distance, _units)
+ "<br><b>" + QObject::tr("Time:") + "</b> " + timeSpan(_time);
}
void TrackItem::updateShape()
{
QPainterPathStroker s;
s.setWidth(TRACK_WIDTH * 1.0/scale());
_shape = s.createStroke(path().simplified());
}
TrackItem::TrackItem(const Track &track)
{
QVector<QPointF> t;
QPainterPath path;
track.track(t);
Q_ASSERT(t.count() >= 2);
const QPointF &p = t.at(0);
path.moveTo(ll2mercator(QPointF(p.x(), -p.y())));
for (int i = 1; i < t.size(); i++) {
const QPointF &p = t.at(i);
path.lineTo(ll2mercator(QPointF(p.x(), -p.y())));
}
_units = Metric;
_date = track.date();
_distance = track.distance();
_time = track.time();
setPath(path);
setToolTip(toolTip());
setCursor(Qt::ArrowCursor);
updateShape();
QBrush brush(Qt::SolidPattern);
QPen pen(brush, TRACK_WIDTH);
pen.setCosmetic(true);
setPen(pen);
}
void TrackItem::setScale(qreal scale)
{
QGraphicsPathItem::setScale(scale);
updateShape();
}
void TrackItem::setColor(const QColor &color)
{
QPen p(pen());
p.setColor(color);
setPen(p);
}
void TrackItem::setUnits(enum Units units)
{
_units = units;
setToolTip(toolTip());
}

32
src/trackitem.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef TRACKITEM_H
#define TRACKITEM_H
#include <QGraphicsPathItem>
#include <QDateTime>
#include "units.h"
#include "track.h"
class TrackItem : public QGraphicsPathItem
{
public:
TrackItem(const Track &track);
QPainterPath shape() const {return _shape;}
void setScale(qreal scale);
void setUnits(enum Units units);
void setColor(const QColor &color);
private:
void updateShape();
QString toolTip();
QPainterPath _shape;
Units _units;
QDateTime _date;
qreal _time;
qreal _distance;
};
#endif // TRACKITEM_H

View File

@ -2,10 +2,10 @@
QDebug operator<<(QDebug dbg, const Trackpoint &trackpoint) QDebug operator<<(QDebug dbg, const Trackpoint &trackpoint)
{ {
dbg.nospace() << "Trackpoint(" << trackpoint.coordinates << ", " dbg.nospace() << "Trackpoint(" << trackpoint.coordinates() << ", "
<< trackpoint.timestamp << ", " << trackpoint.elevation << ", " << trackpoint.timestamp() << ", " << trackpoint.elevation() << ", "
<< trackpoint.geoidheight << ", " << trackpoint.speed << ", " << trackpoint.geoidHeight() << ", " << trackpoint.speed() << ", "
<< trackpoint.heartRate << ", " << trackpoint.temperature << ")"; << trackpoint.heartRate() << ", " << trackpoint.temperature() << ")";
return dbg.maybeSpace(); return dbg.maybeSpace();
} }

View File

@ -10,26 +10,42 @@ class Trackpoint
{ {
public: public:
Trackpoint() { Trackpoint() {
elevation = NAN; _elevation = NAN; _geoidHeight = 0; _speed = NAN; _heartRate = NAN;
geoidheight = 0; _temperature = NAN;
speed = NAN;
heartRate = NAN;
temperature = NAN;
} }
Trackpoint(const QPointF &coordinates) {_coordinates = coordinates;}
bool hasTimestamp() const {return !timestamp.isNull();} const QPointF &coordinates() const {return _coordinates;}
bool hasElevation() const {return !std::isnan(elevation);} const QDateTime &timestamp() const {return _timestamp;}
bool hasSpeed() const {return !std::isnan(speed);} qreal elevation() const {return _elevation;}
bool hasHeartRate() const {return !std::isnan(heartRate);} qreal geoidHeight() const {return _geoidHeight;}
bool hasTemperature() const {return !std::isnan(temperature);} qreal speed() const {return _speed;}
qreal heartRate() const {return _heartRate;}
qreal temperature() const {return _temperature;}
QPointF coordinates; void setCoordinates(const QPointF &coordinates)
QDateTime timestamp; {_coordinates = coordinates;}
qreal elevation; void setTimestamp(const QDateTime &timestamp) {_timestamp = timestamp;}
qreal geoidheight; void setElevation(qreal elevation) {_elevation = elevation;}
qreal speed; void setGeoidHeight(qreal geoidHeight) {_geoidHeight = geoidHeight;}
qreal heartRate; void setSpeed(qreal speed) {_speed = speed;}
qreal temperature; void setHeartRate(qreal heartRate) {_heartRate = heartRate;}
void setTemperature(qreal temperature) {_temperature = temperature;}
bool hasTimestamp() const {return !_timestamp.isNull();}
bool hasElevation() const {return !std::isnan(_elevation);}
bool hasSpeed() const {return !std::isnan(_speed);}
bool hasHeartRate() const {return !std::isnan(_heartRate);}
bool hasTemperature() const {return !std::isnan(_temperature);}
private:
QPointF _coordinates;
QDateTime _timestamp;
qreal _elevation;
qreal _geoidHeight;
qreal _speed;
qreal _heartRate;
qreal _temperature;
}; };
QDebug operator<<(QDebug dbg, const Trackpoint &trackpoint); QDebug operator<<(QDebug dbg, const Trackpoint &trackpoint);

View File

@ -2,19 +2,18 @@
#include <QGraphicsScene> #include <QGraphicsScene>
#include <QPainterPath> #include <QPainterPath>
#include <QWheelEvent> #include <QWheelEvent>
#include "ll.h"
#include "poi.h" #include "poi.h"
#include "gpx.h" #include "gpx.h"
#include "map.h" #include "map.h"
#include "trackitem.h"
#include "waypointitem.h" #include "waypointitem.h"
#include "markeritem.h" #include "markeritem.h"
#include "scaleitem.h" #include "scaleitem.h"
#include "ll.h"
#include "misc.h"
#include "trackview.h" #include "trackview.h"
#define MARGIN 10.0 #define MARGIN 10.0
#define TRACK_WIDTH 3
#define SCALE_OFFSET 7 #define SCALE_OFFSET 7
TrackView::TrackView(QWidget *parent) TrackView::TrackView(QWidget *parent)
@ -48,71 +47,41 @@ TrackView::~TrackView()
delete _mapScale; delete _mapScale;
} }
QString TrackView::toolTip(const TrackInfo &info) void TrackView::addTrack(const Track &track)
{ {
QString date = info.date.date().toString(Qt::SystemLocaleShortDate); if (track.isNull()) {
return "<b>" + tr("Date:") + "</b> " + date + "<br><b>" + tr("Distance:")
+ "</b> " + distance(info.distance, _units) + "<br><b>" + tr("Time:")
+ "</b> " + timeSpan(info.time);
}
void TrackView::addTrack(const QVector<QPointF> &track, const TrackInfo &info)
{
QPainterPath path;
QGraphicsPathItem *pi;
MarkerItem *mi;
if (track.size() < 2) {
_palette.color(); _palette.color();
return; return;
} }
_tracks.append(track); TrackItem *pi = new TrackItem(track);
const QPointF &p = track.at(0);
path.moveTo(ll2mercator(QPointF(p.x(), -p.y())));
for (int i = 1; i < track.size(); i++) {
const QPointF &p = track.at(i);
path.lineTo(ll2mercator(QPointF(p.x(), -p.y())));
}
_maxPath = qMax(path.length(), _maxPath);
pi = new QGraphicsPathItem(path);
_paths.append(pi); _paths.append(pi);
_info.append(info);
_zoom = qMin(_zoom, scale2zoom(trackScale())); _zoom = qMin(_zoom, scale2zoom(trackScale()));
_scale = mapScale(_zoom); _scale = mapScale(_zoom);
QBrush brush(_palette.color(), Qt::SolidPattern);
QPen pen(brush, TRACK_WIDTH * _scale);
pi->setPen(pen);
pi->setScale(1.0/_scale); pi->setScale(1.0/_scale);
pi->setToolTip(toolTip(info)); pi->setColor(_palette.color());
pi->setCursor(Qt::ArrowCursor);
_scene->addItem(pi); _scene->addItem(pi);
mi = new MarkerItem(pi); MarkerItem *mi = new MarkerItem(pi);
_markers.append(mi); _markers.append(mi);
mi->setPos(pi->path().pointAtPercent(0)); mi->setPos(pi->path().pointAtPercent(0));
mi->setScale(_scale); mi->setScale(_scale);
_maxPath = qMax(pi->path().length(), _maxPath);
_maxDistance = qMax(track.distance(), _maxDistance);
} }
void TrackView::addWaypoints(const QList<Waypoint> &waypoints) void TrackView::addWaypoints(const QList<Waypoint> &waypoints)
{ {
for (int i = 0; i < waypoints.count(); i++) { for (int i = 0; i < waypoints.count(); i++) {
const Waypoint &w = waypoints.at(i); const Waypoint &w = waypoints.at(i);
WaypointItem *wi = new WaypointItem(
Waypoint(ll2mercator(QPointF(w.coordinates().x(),
-w.coordinates().y())), w.name(), w.description()));
wi->setPos(wi->entry().coordinates() * 1.0/_scale); WaypointItem *wi = new WaypointItem(w);
wi->setPos(wi->coordinates() * 1.0/_scale);
wi->setZValue(1); wi->setZValue(1);
_scene->addItem(wi); _scene->addItem(wi);
_locations.append(wi); _waypoints.append(wi);
_waypoints.append(w.coordinates());
} }
_zoom = qMin(_zoom, scale2zoom(waypointScale())); _zoom = qMin(_zoom, scale2zoom(waypointScale()));
@ -123,22 +92,15 @@ void TrackView::loadGPX(const GPX &gpx)
{ {
int zoom = _zoom; int zoom = _zoom;
for (int i = 0; i < gpx.trackCount(); i++) { for (int i = 0; i < gpx.trackCount(); i++)
QVector<QPointF> track; addTrack(gpx.track(i));
TrackInfo info = {gpx.track(i).date(), gpx.track(i).distance(),
gpx.track(i).time()};
gpx.track(i).track(track);
addTrack(track, info);
_maxDistance = qMax(gpx.track(i).distance(), _maxDistance);
}
addWaypoints(gpx.waypoints()); addWaypoints(gpx.waypoints());
if (_paths.empty() && _locations.empty()) if (_paths.empty() && _waypoints.empty())
return; return;
if ((_paths.size() > 1 && _zoom < zoom) if ((_paths.size() > 1 && _zoom < zoom)
|| (_locations.size() && _zoom < zoom)) || (_waypoints.size() && _zoom < zoom))
rescale(_scale); rescale(_scale);
QRectF br = trackBoundingRect() | waypointBoundingRect(); QRectF br = trackBoundingRect() | waypointBoundingRect();
@ -168,17 +130,17 @@ QRectF TrackView::waypointBoundingRect() const
{ {
qreal bottom, top, left, right; qreal bottom, top, left, right;
if (_locations.empty()) if (_waypoints.empty())
return QRectF(); return QRectF();
const QPointF &p = _locations.at(0)->pos(); const QPointF &p = _waypoints.at(0)->pos();
bottom = p.y(); bottom = p.y();
top = p.y(); top = p.y();
left = p.x(); left = p.x();
right = p.x(); right = p.x();
for (int i = 1; i < _locations.size(); i++) { for (int i = 1; i < _waypoints.size(); i++) {
const QPointF &p = _locations.at(i)->pos(); const QPointF &p = _waypoints.at(i)->pos();
bottom = qMax(bottom, p.y()); bottom = qMax(bottom, p.y());
top = qMin(top, p.y()); top = qMin(top, p.y());
right = qMax(right, p.x()); right = qMax(right, p.x());
@ -208,17 +170,17 @@ qreal TrackView::waypointScale() const
{ {
qreal bottom, top, left, right; qreal bottom, top, left, right;
if (_locations.size() < 2) if (_waypoints.size() < 2)
return mapScale(ZOOM_MAX); return mapScale(ZOOM_MAX);
const QPointF &p = _locations.at(0)->entry().coordinates(); const QPointF &p = _waypoints.at(0)->coordinates();
bottom = p.y(); bottom = p.y();
top = p.y(); top = p.y();
left = p.x(); left = p.x();
right = p.x(); right = p.x();
for (int i = 1; i < _locations.size(); i++) { for (int i = 1; i < _waypoints.size(); i++) {
const QPointF &p = _locations.at(i)->entry().coordinates(); const QPointF &p = _waypoints.at(i)->coordinates();
bottom = qMax(bottom, p.y()); bottom = qMax(bottom, p.y());
top = qMin(top, p.y()); top = qMin(top, p.y());
right = qMax(right, p.x()); right = qMax(right, p.x());
@ -242,19 +204,14 @@ void TrackView::rescale(qreal scale)
for (int i = 0; i < _paths.size(); i++) { for (int i = 0; i < _paths.size(); i++) {
_markers.at(i)->setScale(scale); _markers.at(i)->setScale(scale);
_paths.at(i)->setScale(1.0/scale); _paths.at(i)->setScale(1.0/scale);
QPen pen(_paths.at(i)->pen());
pen.setWidthF(TRACK_WIDTH * scale);
_paths.at(i)->setPen(pen);
} }
for (int i = 0; i < _locations.size(); i++) for (int i = 0; i < _waypoints.size(); i++)
_locations.at(i)->setPos(_locations.at(i)->entry().coordinates() _waypoints.at(i)->setPos(_waypoints.at(i)->coordinates() * 1.0/scale);
* 1.0/scale);
QHash<Waypoint, WaypointItem*>::const_iterator it, jt; QHash<Waypoint, WaypointItem*>::const_iterator it, jt;
for (it = _pois.constBegin(); it != _pois.constEnd(); it++) { for (it = _pois.constBegin(); it != _pois.constEnd(); it++) {
it.value()->setPos(it.value()->entry().coordinates() * 1.0/scale); it.value()->setPos(it.value()->coordinates() * 1.0/scale);
it.value()->show(); it.value()->show();
} }
@ -277,11 +234,8 @@ void TrackView::addPOI(const QVector<Waypoint> &waypoints)
if (_pois.contains(w)) if (_pois.contains(w))
continue; continue;
WaypointItem *pi = new WaypointItem( WaypointItem *pi = new WaypointItem(w);
Waypoint(ll2mercator(QPointF(w.coordinates().x(), pi->setPos(pi->coordinates() * 1.0/_scale);
-w.coordinates().y())), w.name(), w.description()));
pi->setPos(pi->entry().coordinates() * 1.0/_scale);
pi->setZValue(1); pi->setZValue(1);
_scene->addItem(pi); _scene->addItem(pi);
@ -293,11 +247,11 @@ void TrackView::loadPOI(const POI &poi)
{ {
QHash<Waypoint, WaypointItem*>::const_iterator it,jt; QHash<Waypoint, WaypointItem*>::const_iterator it,jt;
if (!_tracks.size() && !_waypoints.size()) if (!_paths.size() && !_waypoints.size())
return; return;
for (int i = 0; i < _tracks.size(); i++) for (int i = 0; i < _paths.size(); i++)
addPOI(poi.points(_tracks.at(i))); addPOI(poi.points(_paths.at(i)->path()));
addPOI(poi.points(_waypoints)); addPOI(poi.points(_waypoints));
for (it = _pois.constBegin(); it != _pois.constEnd(); it++) { for (it = _pois.constBegin(); it != _pois.constEnd(); it++) {
@ -324,8 +278,8 @@ void TrackView::setUnits(enum Units units)
_mapScale->setUnits(units); _mapScale->setUnits(units);
for (int i = 0; i < _info.count(); i++) for (int i = 0; i < _paths.count(); i++)
_paths[i]->setToolTip(toolTip(_info.at(i))); _paths[i]->setUnits(units);
} }
void TrackView::redraw() void TrackView::redraw()
@ -342,7 +296,7 @@ void TrackView::rescale()
void TrackView::zoom(int z, const QPointF &pos) void TrackView::zoom(int z, const QPointF &pos)
{ {
if (_paths.isEmpty() && _locations.isEmpty()) if (_paths.isEmpty() && _waypoints.isEmpty())
return; return;
qreal scale = _scale; qreal scale = _scale;
@ -366,7 +320,7 @@ void TrackView::zoom(int z, const QPointF &pos)
void TrackView::wheelEvent(QWheelEvent *event) void TrackView::wheelEvent(QWheelEvent *event)
{ {
if (_paths.isEmpty() && _locations.isEmpty()) if (_paths.isEmpty() && _waypoints.isEmpty())
return; return;
QPointF pos = mapToScene(event->pos()); QPointF pos = mapToScene(event->pos());
@ -444,15 +398,11 @@ void TrackView::clear()
_pois.clear(); _pois.clear();
_paths.clear(); _paths.clear();
_info.clear(); _waypoints.clear();
_locations.clear();
_markers.clear(); _markers.clear();
_scene->clear(); _scene->clear();
_palette.reset(); _palette.reset();
_tracks.clear();
_waypoints.clear();
_maxPath = 0; _maxPath = 0;
_maxDistance = 0; _maxDistance = 0;
_zoom = ZOOM_MAX; _zoom = ZOOM_MAX;
@ -479,7 +429,7 @@ void TrackView::movePositionMarker(qreal val)
void TrackView::drawBackground(QPainter *painter, const QRectF &rect) void TrackView::drawBackground(QPainter *painter, const QRectF &rect)
{ {
if ((_paths.isEmpty() && _locations.isEmpty()) || !_map) { if ((_paths.isEmpty() && _waypoints.isEmpty()) || !_map) {
painter->fillRect(rect, Qt::white); painter->fillRect(rect, Qt::white);
return; return;
} }
@ -510,7 +460,7 @@ void TrackView::drawBackground(QPainter *painter, const QRectF &rect)
void TrackView::resizeEvent(QResizeEvent *e) void TrackView::resizeEvent(QResizeEvent *e)
{ {
if (_paths.isEmpty() && _locations.isEmpty()) if (_paths.isEmpty() && _waypoints.isEmpty())
return; return;
rescale(); rescale();

View File

@ -5,7 +5,6 @@
#include <QVector> #include <QVector>
#include <QHash> #include <QHash>
#include <QList> #include <QList>
#include <QDateTime>
#include "units.h" #include "units.h"
#include "palette.h" #include "palette.h"
#include "waypoint.h" #include "waypoint.h"
@ -13,6 +12,8 @@
class GPX; class GPX;
class POI; class POI;
class Map; class Map;
class Track;
class TrackItem;
class WaypointItem; class WaypointItem;
class MarkerItem; class MarkerItem;
class ScaleItem; class ScaleItem;
@ -37,25 +38,17 @@ public:
void plot(QPainter *painter, const QRectF &target); void plot(QPainter *painter, const QRectF &target);
int trackCount() const {return _paths.count();} int trackCount() const {return _paths.count();}
int waypointCount() const {return _locations.count();} int waypointCount() const {return _waypoints.count();}
public slots: public slots:
void movePositionMarker(qreal val); void movePositionMarker(qreal val);
void redraw(); void redraw();
private: private:
struct TrackInfo { void addTrack(const Track &track);
QDateTime date;
qreal distance;
qreal time;
};
void addTrack(const QVector<QPointF> &track, const TrackInfo &info);
void addWaypoints(const QList<Waypoint> &waypoints); void addWaypoints(const QList<Waypoint> &waypoints);
void addPOI(const QVector<Waypoint> &waypoints); void addPOI(const QVector<Waypoint> &waypoints);
QString toolTip(const TrackInfo &info);
QRectF trackBoundingRect() const; QRectF trackBoundingRect() const;
QRectF waypointBoundingRect() const; QRectF waypointBoundingRect() const;
qreal trackScale() const; qreal trackScale() const;
@ -72,13 +65,10 @@ private:
void paintEvent(QPaintEvent *e); void paintEvent(QPaintEvent *e);
QGraphicsScene *_scene; QGraphicsScene *_scene;
QList<QGraphicsPathItem*> _paths; QList<TrackItem*> _paths;
QList<TrackInfo> _info;
QList<MarkerItem*> _markers; QList<MarkerItem*> _markers;
QList<WaypointItem*> _locations; QList<WaypointItem*> _waypoints;
QHash<Waypoint, WaypointItem*> _pois; QHash<Waypoint, WaypointItem*> _pois;
QList<QVector<QPointF> > _tracks;
QVector<QPointF> _waypoints;
Map *_map; Map *_map;
ScaleItem *_mapScale; ScaleItem *_mapScale;

9
src/waypoint.cpp Normal file
View File

@ -0,0 +1,9 @@
#include "waypoint.h"
QDebug operator<<(QDebug dbg, const Waypoint &waypoint)
{
dbg.nospace() << "Waypoint(" << waypoint.coordinates() << ", "
<< waypoint.name() << ", " << waypoint.description() << ")";
return dbg.maybeSpace();
}

View File

@ -3,25 +3,33 @@
#include <QPointF> #include <QPointF>
#include <QString> #include <QString>
#include <QDateTime>
#include <QHash> #include <QHash>
#include <QDebug>
#include <cmath>
class Waypoint class Waypoint
{ {
public: public:
Waypoint() {} Waypoint() {_elevation = NAN; _geoidHeight = 0;}
Waypoint(const QPointF &coordinates, const QString &name, Waypoint(const QPointF &coordinates)
const QString &description) : _coordinates(coordinates) {_elevation = NAN; _geoidHeight = 0;}
: _coordinates(coordinates), _name(name), _description(description) {}
const QPointF &coordinates() const {return _coordinates;} const QPointF &coordinates() const {return _coordinates;}
const QString &name() const {return _name;} const QString &name() const {return _name;}
const QString &description() const {return _description;} const QString &description() const {return _description;}
const QDateTime &timestamp() const {return _timestamp;}
qreal elevation() const {return _elevation;}
qreal geoidHeight() const {return _geoidHeight;}
void setCoordinates(const QPointF &coordinates) void setCoordinates(const QPointF &coordinates)
{_coordinates = coordinates;} {_coordinates = coordinates;}
void setName(const QString &name) void setName(const QString &name) {_name = name;}
{_name = name;}
void setDescription(const QString &description) void setDescription(const QString &description)
{_description = description;} {_description = description;}
void setTimestamp(const QDateTime &timestamp) {_timestamp = timestamp;}
void setElevation(qreal elevation) {_elevation = elevation;}
void setGeoidHeight(qreal geoidHeight) {_geoidHeight = geoidHeight;}
bool operator==(const Waypoint &other) const bool operator==(const Waypoint &other) const
{return this->_name == other._name {return this->_name == other._name
@ -31,6 +39,9 @@ private:
QPointF _coordinates; QPointF _coordinates;
QString _name; QString _name;
QString _description; QString _description;
QDateTime _timestamp;
qreal _elevation;
qreal _geoidHeight;
}; };
inline uint qHash(const Waypoint &key) inline uint qHash(const Waypoint &key)
@ -38,4 +49,6 @@ inline uint qHash(const Waypoint &key)
return ::qHash(key.name()); return ::qHash(key.name());
} }
QDebug operator<<(QDebug dbg, const Waypoint &Waypoint);
#endif // WAYPOINT_H #endif // WAYPOINT_H

View File

@ -1,20 +1,35 @@
#include <QPainter> #include <QPainter>
#include "config.h" #include "config.h"
#include "ll.h"
#include "misc.h"
#include "waypointitem.h" #include "waypointitem.h"
#define POINT_SIZE 8 #define POINT_SIZE 8
WaypointItem::WaypointItem(const Waypoint &entry, QGraphicsItem *parent) static QString tt(const Waypoint &waypoint)
{
QString date = waypoint.timestamp().toString(Qt::SystemLocaleShortDate);
return "<b>" + QObject::tr("Coordinates:") + "</b> "
+ coordinates(waypoint.coordinates()) + "<br><b>"
+ QObject::tr("Description:") + "</b> " + waypoint.description()
+ "<br><b>" + QObject::tr("Elevation:") + "</b> "
+ QString::number(waypoint.elevation() - waypoint.geoidHeight())
+ "<br><b>" + QObject::tr("Date:") + "</b> " + date;
}
WaypointItem::WaypointItem(const Waypoint &waypoint, QGraphicsItem *parent)
: QGraphicsItem(parent) : QGraphicsItem(parent)
{ {
_entry = entry; _label = waypoint.name();
_coordinates = ll2mercator(QPointF(waypoint.coordinates().x(),
-waypoint.coordinates().y()));
updateBoundingRect(); updateBoundingRect();
if (!entry.description().isEmpty()) { setToolTip(tt(waypoint));
setToolTip(entry.description()); setCursor(Qt::ArrowCursor);
setCursor(Qt::ArrowCursor);
}
} }
void WaypointItem::updateBoundingRect() void WaypointItem::updateBoundingRect()
@ -23,7 +38,7 @@ void WaypointItem::updateBoundingRect()
font.setPixelSize(FONT_SIZE); font.setPixelSize(FONT_SIZE);
font.setFamily(FONT_FAMILY); font.setFamily(FONT_FAMILY);
QFontMetrics fm(font); QFontMetrics fm(font);
QRect ts = fm.tightBoundingRect(_entry.name()); QRect ts = fm.tightBoundingRect(_label);
_boundingRect = QRectF(-POINT_SIZE/2, -POINT_SIZE/2, ts.width() _boundingRect = QRectF(-POINT_SIZE/2, -POINT_SIZE/2, ts.width()
+ POINT_SIZE, ts.height() + fm.descent() + POINT_SIZE); + POINT_SIZE, ts.height() + fm.descent() + POINT_SIZE);
@ -38,11 +53,11 @@ void WaypointItem::paint(QPainter *painter,
font.setPixelSize(FONT_SIZE); font.setPixelSize(FONT_SIZE);
font.setFamily(FONT_FAMILY); font.setFamily(FONT_FAMILY);
QFontMetrics fm(font); QFontMetrics fm(font);
QRect ts = fm.tightBoundingRect(_entry.name()); QRect ts = fm.tightBoundingRect(_label);
painter->setFont(font); painter->setFont(font);
painter->drawText(POINT_SIZE/2 - qMax(ts.x(), 0), POINT_SIZE/2 + ts.height(), painter->drawText(POINT_SIZE/2 - qMax(ts.x(), 0), POINT_SIZE/2 + ts.height(),
_entry.name()); _label);
painter->setBrush(Qt::SolidPattern); painter->setBrush(Qt::SolidPattern);
painter->drawEllipse(-POINT_SIZE/2, -POINT_SIZE/2, POINT_SIZE, POINT_SIZE); painter->drawEllipse(-POINT_SIZE/2, -POINT_SIZE/2, POINT_SIZE, POINT_SIZE);

View File

@ -7,8 +7,8 @@
class WaypointItem : public QGraphicsItem class WaypointItem : public QGraphicsItem
{ {
public: public:
WaypointItem(const Waypoint &entry, QGraphicsItem *parent = 0); WaypointItem(const Waypoint &waypoint, QGraphicsItem *parent = 0);
const Waypoint &entry() const {return _entry;} const QPointF &coordinates() {return _coordinates;}
QRectF boundingRect() const {return _boundingRect;} QRectF boundingRect() const {return _boundingRect;}
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
@ -17,7 +17,8 @@ public:
private: private:
void updateBoundingRect(); void updateBoundingRect();
Waypoint _entry; QString _label;
QPointF _coordinates;
QRectF _boundingRect; QRectF _boundingRect;
}; };