mirror of
https://github.com/tumic0/GPXSee.git
synced 2025-06-27 03:29:16 +02:00
Added elevation correction(geoidheight subtraction)
Improved info output in PDF exports.
This commit is contained in:
@ -14,6 +14,11 @@ public:
|
||||
void loadGPX(const GPX &gpx);
|
||||
void clear();
|
||||
|
||||
qreal ascent() const {return _ascent;}
|
||||
qreal descent() const {return _descent;}
|
||||
qreal max() const {return _max;}
|
||||
qreal min() const {return _min;}
|
||||
|
||||
private:
|
||||
qreal _ascent, _descent;
|
||||
qreal _max, _min;
|
||||
|
125
src/gpx.cpp
125
src/gpx.cpp
@ -11,68 +11,6 @@
|
||||
#define WINDOW_SF 11
|
||||
|
||||
|
||||
bool GPX::loadFile(const QString &fileName)
|
||||
{
|
||||
QFile file(fileName);
|
||||
bool ret;
|
||||
|
||||
_data.clear();
|
||||
_error.clear();
|
||||
|
||||
if (!file.open(QFile::ReadOnly | QFile::Text)) {
|
||||
_error = qPrintable(file.errorString());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(ret = _parser.loadFile(&file, _data)))
|
||||
_error = _parser.errorString();
|
||||
file.close();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static QVector<QPointF> filter(const QVector<QPointF> &v, int window)
|
||||
{
|
||||
qreal acc = 0;
|
||||
QVector<QPointF> ret;
|
||||
|
||||
if (v.size() < window)
|
||||
return QVector<QPointF>(v);
|
||||
|
||||
for (int i = 0; i < window; i++)
|
||||
acc += v.at(i).y();
|
||||
for (int i = 0; i <= window/2; i++)
|
||||
ret.append(QPointF(v.at(i).x(), acc/window));
|
||||
|
||||
for (int i = window/2 + 1; i < v.size() - window/2; i++) {
|
||||
acc += v.at(i + window/2).y() - v.at(i - (window/2 + 1)).y();
|
||||
ret.append(QPointF(v.at(i).x(), acc/window));
|
||||
}
|
||||
|
||||
for (int i = v.size() - window/2; i < v.size(); i++)
|
||||
ret.append(QPointF(v.at(i).x(), acc/window));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void GPX::elevationGraph(QVector<QPointF> &graph) const
|
||||
{
|
||||
qreal dist = 0;
|
||||
QVector<QPointF> raw;
|
||||
|
||||
if (!_data.size())
|
||||
return;
|
||||
|
||||
raw.append(QPointF(0, _data.at(0).elevation));
|
||||
for (int i = 1; i < _data.size(); i++) {
|
||||
dist += llDistance(_data.at(i).coordinates, _data.at(i-1).coordinates);
|
||||
raw.append(QPointF(dist, _data.at(i).elevation));
|
||||
}
|
||||
|
||||
graph = filter(raw, WINDOW_EF);
|
||||
}
|
||||
|
||||
static bool lt(const QPointF &p1, const QPointF &p2)
|
||||
{
|
||||
return p1.y() < p2.y();
|
||||
@ -120,6 +58,69 @@ static QVector<QPointF> eliminate(const QVector<QPointF> &v, int window)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static QVector<QPointF> filter(const QVector<QPointF> &v, int window)
|
||||
{
|
||||
qreal acc = 0;
|
||||
QVector<QPointF> ret;
|
||||
|
||||
if (v.size() < window)
|
||||
return QVector<QPointF>(v);
|
||||
|
||||
for (int i = 0; i < window; i++)
|
||||
acc += v.at(i).y();
|
||||
for (int i = 0; i <= window/2; i++)
|
||||
ret.append(QPointF(v.at(i).x(), acc/window));
|
||||
|
||||
for (int i = window/2 + 1; i < v.size() - window/2; i++) {
|
||||
acc += v.at(i + window/2).y() - v.at(i - (window/2 + 1)).y();
|
||||
ret.append(QPointF(v.at(i).x(), acc/window));
|
||||
}
|
||||
|
||||
for (int i = v.size() - window/2; i < v.size(); i++)
|
||||
ret.append(QPointF(v.at(i).x(), acc/window));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool GPX::loadFile(const QString &fileName)
|
||||
{
|
||||
QFile file(fileName);
|
||||
bool ret;
|
||||
|
||||
_data.clear();
|
||||
_error.clear();
|
||||
|
||||
if (!file.open(QFile::ReadOnly | QFile::Text)) {
|
||||
_error = qPrintable(file.errorString());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(ret = _parser.loadFile(&file, _data)))
|
||||
_error = _parser.errorString();
|
||||
file.close();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void GPX::elevationGraph(QVector<QPointF> &graph) const
|
||||
{
|
||||
qreal dist = 0;
|
||||
QVector<QPointF> raw;
|
||||
|
||||
if (!_data.size())
|
||||
return;
|
||||
|
||||
raw.append(QPointF(0, _data.at(0).elevation));
|
||||
for (int i = 1; i < _data.size(); i++) {
|
||||
dist += llDistance(_data.at(i).coordinates, _data.at(i-1).coordinates);
|
||||
raw.append(QPointF(dist, _data.at(i).elevation
|
||||
- _data.at(i).geoidheight));
|
||||
}
|
||||
|
||||
graph = filter(raw, WINDOW_EF);
|
||||
}
|
||||
|
||||
void GPX::speedGraph(QVector<QPointF> &graph) const
|
||||
{
|
||||
qreal dist = 0, v, ds, dt;
|
||||
|
@ -216,9 +216,11 @@ void Graph::plot(QPainter *painter, const QRectF &target)
|
||||
QSizeF canvas = QSizeF(orig.height() * ratio, orig.height());
|
||||
|
||||
resize(canvas);
|
||||
_slider->setVisible(false);
|
||||
_slider->hide();
|
||||
_info->hide();
|
||||
_scene->render(painter, target, QRectF(), Qt::KeepAspectRatioByExpanding);
|
||||
_slider->setVisible(true);
|
||||
_slider->show();
|
||||
_info->show();
|
||||
resize(orig);
|
||||
}
|
||||
|
||||
|
28
src/gui.cpp
28
src/gui.cpp
@ -8,7 +8,6 @@
|
||||
#include <QPainter>
|
||||
#include <QKeyEvent>
|
||||
#include <QDir>
|
||||
#include "gui.h"
|
||||
#include "config.h"
|
||||
#include "icons.h"
|
||||
#include "keys.h"
|
||||
@ -16,10 +15,13 @@
|
||||
#include "elevationgraph.h"
|
||||
#include "speedgraph.h"
|
||||
#include "track.h"
|
||||
#include "infoitem.h"
|
||||
#include "gui.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
|
||||
static QString timeSpan(qreal time)
|
||||
{
|
||||
unsigned h, m, s;
|
||||
@ -287,12 +289,28 @@ void GUI::saveFile(const QString &fileName)
|
||||
printer.setOutputFileName(fileName);
|
||||
|
||||
QPainter p(&printer);
|
||||
int margin = (printer.paperRect().height() - printer.pageRect().height())
|
||||
/ 2;
|
||||
_track->plot(&p, QRectF(0, 0, printer.width(), (0.80 * printer.height())
|
||||
- margin));
|
||||
|
||||
_track->plot(&p, QRectF(0, 300, printer.width(), (0.80 * printer.height())
|
||||
- 400));
|
||||
_elevationGraph->plot(&p, QRectF(0, 0.80 * printer.height(),
|
||||
printer.width(), printer.height() * 0.20));
|
||||
|
||||
QGraphicsScene scene;
|
||||
InfoItem info;
|
||||
info.insert(tr("Distance"), QString::number(_distance / 1000, 'f', 1) + " "
|
||||
+ tr("km"));
|
||||
info.insert(tr("Time"), timeSpan(_time));
|
||||
info.insert(tr("Ascent"), QString::number(_elevationGraph->ascent(), 'f', 0)
|
||||
+ " " + tr("m"));
|
||||
info.insert(tr("Descent"), QString::number(_elevationGraph->descent(), 'f',
|
||||
0) + " " + tr("m"));
|
||||
info.insert(tr("Maximum"), QString::number(_elevationGraph->max(), 'f', 0)
|
||||
+ " " + tr("m"));
|
||||
info.insert(tr("Minimum"), QString::number(_elevationGraph->min(), 'f', 0)
|
||||
+ " " + tr("m"));
|
||||
scene.addItem(&info);
|
||||
scene.render(&p, QRectF(0, 0, printer.width(), 200));
|
||||
|
||||
p.end();
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,8 @@ void Parser::handleTrekPointData(QVector<TrackPoint> &data,
|
||||
if (element == "time")
|
||||
data.last().timestamp = QDateTime::fromString(value.toLatin1(),
|
||||
Qt::ISODate);
|
||||
if (element == "geoidheight")
|
||||
data.last().geoidheight = value.toLatin1().toDouble();
|
||||
}
|
||||
|
||||
void Parser::handleTrekPointAttributes(QVector<TrackPoint> &data,
|
||||
@ -41,7 +43,8 @@ void Parser::extensions(QVector<TrackPoint> &data)
|
||||
void Parser::trekPointData(QVector<TrackPoint> &data)
|
||||
{
|
||||
while (_reader.readNextStartElement()) {
|
||||
if (_reader.name() == "ele" || _reader.name() == "time")
|
||||
if (_reader.name() == "ele" || _reader.name() == "time"
|
||||
|| _reader.name() == "geoidheight")
|
||||
handleTrekPointData(data, _reader.name(), _reader.readElementText());
|
||||
else if (_reader.name() == "extensions")
|
||||
extensions(data);
|
||||
|
@ -10,9 +10,10 @@ struct TrackPoint
|
||||
QPointF coordinates;
|
||||
QDateTime timestamp;
|
||||
qreal elevation;
|
||||
qreal geoidheight;
|
||||
qreal speed;
|
||||
|
||||
TrackPoint() {speed = -1;}
|
||||
TrackPoint() {elevation = 0; geoidheight = 0; speed = -1;}
|
||||
};
|
||||
|
||||
class Parser
|
||||
|
@ -18,30 +18,21 @@ SpeedGraph::SpeedGraph(QWidget *parent) : Graph(parent)
|
||||
void SpeedGraph::loadGPX(const GPX &gpx)
|
||||
{
|
||||
QVector<QPointF> data;
|
||||
qreal max = 0, sum = 0, w = 0, avg;
|
||||
qreal max = 0;
|
||||
|
||||
|
||||
gpx.speedGraph(data);
|
||||
if (data.isEmpty())
|
||||
return;
|
||||
|
||||
avg = gpx.distance() / gpx.time();
|
||||
_avg.append(QPointF(gpx.distance(), avg));
|
||||
_avg.append(QPointF(gpx.distance(), gpx.distance() / gpx.time()));
|
||||
|
||||
for (int i = 0; i < data.size(); i++)
|
||||
max = qMax(max, data.at(i).y());
|
||||
|
||||
|
||||
sum = 0; w = 0;
|
||||
for (QList<QPointF>::iterator it = _avg.begin(); it != _avg.end(); it++) {
|
||||
sum += it->y() * it->x();
|
||||
w += it->x();
|
||||
}
|
||||
avg = sum / w;
|
||||
_max = qMax(_max, max);
|
||||
|
||||
|
||||
addInfo(tr("Average"), QString::number(avg * _yScale, 'f', 1) + " "
|
||||
addInfo(tr("Average"), QString::number(avg() * _yScale, 'f', 1) + " "
|
||||
+ _yUnits);
|
||||
addInfo(tr("Maximum"), QString::number(_max * _yScale, 'f', 1) + " "
|
||||
+ _yUnits);
|
||||
@ -49,6 +40,19 @@ void SpeedGraph::loadGPX(const GPX &gpx)
|
||||
Graph::loadData(data);
|
||||
}
|
||||
|
||||
qreal SpeedGraph::avg() const
|
||||
{
|
||||
qreal sum = 0, w = 0;
|
||||
QList<QPointF>::const_iterator it;
|
||||
|
||||
for (it = _avg.begin(); it != _avg.end(); it++) {
|
||||
sum += it->y() * it->x();
|
||||
w += it->x();
|
||||
}
|
||||
|
||||
return (sum / w);
|
||||
}
|
||||
|
||||
void SpeedGraph::clear()
|
||||
{
|
||||
_max = 0;
|
||||
|
@ -15,6 +15,9 @@ public:
|
||||
void loadGPX(const GPX &gpx);
|
||||
void clear();
|
||||
|
||||
qreal avg() const;
|
||||
qreal max() const {return _max;}
|
||||
|
||||
private:
|
||||
qreal _max;
|
||||
QList<QPointF> _avg;
|
||||
|
Reference in New Issue
Block a user