1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-10-07 07:13:21 +02:00
GPXSee/src/track.cpp

203 lines
3.7 KiB
C++
Raw Normal View History

2015-11-23 02:37:08 +01:00
#include "ll.h"
2015-10-05 01:43:48 +02:00
#include "track.h"
#define WINDOW_EF 3
#define WINDOW_SE 11
2016-03-25 13:11:26 +01:00
#define WINDOW_SF 7
#define WINDOW_HE 11
#define WINDOW_HF 3
2016-01-14 00:37:51 +01:00
2016-09-19 00:56:10 +02:00
static bool lt(qreal v1, qreal v2)
2015-10-05 01:43:48 +02:00
{
2016-09-19 00:56:10 +02:00
return v1 < v2;
2015-10-05 01:43:48 +02:00
}
2016-09-19 00:56:10 +02:00
static qreal median(QVector<qreal> v)
2015-10-05 01:43:48 +02:00
{
qSort(v.begin(), v.end(), lt);
2016-09-19 00:56:10 +02:00
return v.at(v.size() / 2);
2015-10-05 01:43:48 +02:00
}
2016-09-19 00:56:10 +02:00
static qreal MAD(QVector<qreal> v, qreal m)
2015-10-05 01:43:48 +02:00
{
for (int i = 0; i < v.size(); i++)
2016-09-19 00:56:10 +02:00
v[i] = (qAbs(v.at(i) - m));
qSort(v.begin(), v.end(), lt);
2016-09-19 00:56:10 +02:00
return v.at(v.size() / 2);
2015-12-06 00:51:02 +01:00
}
2016-09-19 00:56:10 +02:00
static QVector<qreal> eliminate(const QVector<qreal> &v, int window)
2015-12-06 00:51:02 +01:00
{
QList<int> rm;
2016-09-19 00:56:10 +02:00
QVector<qreal> ret;
qreal m, M;
2015-12-06 00:51:02 +01:00
2015-11-23 02:37:08 +01:00
if (v.size() < window)
2016-09-19 00:56:10 +02:00
return QVector<qreal>(v);
2015-10-05 01:43:48 +02:00
for (int i = window/2; i < v.size() - window/2; i++) {
m = median(v.mid(i - window/2, window));
M = MAD(v.mid(i - window/2, window), m);
2016-09-19 00:56:10 +02:00
if (qAbs((0.6745 * (v.at(i) - m)) / M) > 3.5)
rm.append(i);
2015-11-25 23:17:39 +01:00
}
QList<int>::const_iterator it = rm.begin();
for (int i = 0; i < v.size(); i++) {
if (it == rm.end() || *it != i)
ret.append(v.at(i));
else
it++;
2015-11-25 23:17:39 +01:00
}
2015-11-23 02:37:08 +01:00
return ret;
2015-10-05 01:43:48 +02:00
}
2016-09-19 00:56:10 +02:00
static QVector<qreal> filter(const QVector<qreal> &v, int window)
2015-10-05 01:43:48 +02:00
{
qreal acc = 0;
2016-09-19 00:56:10 +02:00
QVector<qreal> ret;
2015-12-06 00:51:02 +01:00
if (v.size() < window)
2016-09-19 00:56:10 +02:00
return QVector<qreal>(v);
2015-10-05 01:43:48 +02:00
for (int i = 0; i < window; i++)
2016-09-19 00:56:10 +02:00
acc += v.at(i);
for (int i = 0; i <= window/2; i++)
2016-09-19 00:56:10 +02:00
ret.append(acc/window);
2015-10-05 01:43:48 +02:00
for (int i = window/2 + 1; i < v.size() - window/2; i++) {
2016-09-19 00:56:10 +02:00
acc += v.at(i + window/2) - v.at(i - (window/2 + 1));
ret.append(acc/window);
2015-10-05 01:43:48 +02:00
}
for (int i = v.size() - window/2; i < v.size(); i++)
2016-09-19 00:56:10 +02:00
ret.append(acc/window);
2015-11-23 02:37:08 +01:00
return ret;
2016-01-14 00:37:51 +01:00
}
Track::Track(const QVector<Trackpoint> &data) : _data(data)
{
2016-06-27 20:30:45 +02:00
qreal dist = 0;
2016-09-19 00:56:10 +02:00
qint64 time;
2016-09-19 00:56:10 +02:00
_dd.append(0);
_td.append(0);
for (int i = 1; i < data.count(); i++) {
dist += llDistance(data.at(i).coordinates(), data.at(i-1).coordinates());
2016-06-27 20:30:45 +02:00
_dd.append(dist);
2016-09-19 00:56:10 +02:00
if (data.first().hasTimestamp() && data.at(i).hasTimestamp()) {
time = _data.first().timestamp().msecsTo(_data.at(i).timestamp());
_td.append((qreal)time / 1000.0);
}
2016-06-27 20:30:45 +02:00
}
2016-09-19 00:56:10 +02:00
if (_dd.size() != _td.size())
_td.clear();
}
2016-09-19 00:56:10 +02:00
Graph Track::elevation() const
2015-11-23 02:37:08 +01:00
{
2016-09-19 00:56:10 +02:00
Graph ret;
QVector<qreal> raw;
2015-10-05 01:43:48 +02:00
if (!_data.size())
2016-09-19 00:56:10 +02:00
return ret;
2016-06-27 20:30:45 +02:00
for (int i = 0; i < _data.size(); i++)
2016-06-16 20:47:32 +02:00
if (_data.at(i).hasElevation())
2016-09-19 00:56:10 +02:00
raw.append(_data.at(i).elevation() - _data.at(i).geoidHeight());
ret.y = filter(raw, WINDOW_EF);
ret.distance = _dd;
ret.time = _td;
2015-10-05 01:43:48 +02:00
2016-09-19 00:56:10 +02:00
return ret;
2015-10-05 01:43:48 +02:00
}
2016-09-19 00:56:10 +02:00
Graph Track::speed() const
2015-10-05 01:43:48 +02:00
{
2016-09-19 00:56:10 +02:00
Graph ret;
qreal v, ds, dt;
QVector<qreal> raw;
2015-10-05 01:43:48 +02:00
if (!_data.size())
2016-09-19 00:56:10 +02:00
return ret;
2015-10-05 01:43:48 +02:00
2016-09-19 00:56:10 +02:00
raw.append(0);
for (int i = 1; i < _data.size(); i++) {
2016-06-16 20:47:32 +02:00
if (_data.at(i).hasSpeed())
v = _data.at(i).speed();
2016-06-16 20:47:32 +02:00
else if (_data.at(i).hasTimestamp()) {
2016-09-19 00:56:10 +02:00
dt = _td.at(i) - _td.at(i-1);
if (!dt)
continue;
2016-06-27 20:30:45 +02:00
ds = _dd.at(i) - _dd.at(i-1);
2016-09-19 00:56:10 +02:00
v = ds / dt;
} else
2016-06-16 20:47:32 +02:00
continue;
2015-10-05 01:43:48 +02:00
2016-09-19 00:56:10 +02:00
raw.append(v);
}
2015-10-05 01:43:48 +02:00
2016-09-19 00:56:10 +02:00
ret.y = filter(eliminate(raw, WINDOW_SE), WINDOW_SF);
ret.distance = _dd;
ret.time = _td;
return ret;
2015-10-05 01:43:48 +02:00
}
2016-09-19 00:56:10 +02:00
Graph Track::heartRate() const
2015-11-23 02:37:08 +01:00
{
2016-09-19 00:56:10 +02:00
Graph ret;
QVector<qreal> raw;
2016-03-23 20:48:22 +01:00
if (!_data.size())
2016-09-19 00:56:10 +02:00
return ret;
2016-03-23 20:48:22 +01:00
2016-06-27 20:30:45 +02:00
for (int i = 0; i < _data.count(); i++)
2016-06-16 20:47:32 +02:00
if (_data.at(i).hasHeartRate())
2016-09-19 00:56:10 +02:00
raw.append(_data.at(i).heartRate());
ret.y = filter(eliminate(raw, WINDOW_HE), WINDOW_HF);
ret.distance = _dd;
ret.time = _td;
2015-11-23 02:37:08 +01:00
2016-09-19 00:56:10 +02:00
return ret;
}
2015-11-23 02:37:08 +01:00
2016-09-19 00:56:10 +02:00
Graph Track::temperature() const
2016-06-16 20:47:32 +02:00
{
2016-09-19 00:56:10 +02:00
Graph ret;
2016-06-16 20:47:32 +02:00
2016-06-27 20:30:45 +02:00
for (int i = 0; i < _data.size(); i++)
2016-06-16 20:47:32 +02:00
if (_data.at(i).hasTemperature())
2016-09-19 00:56:10 +02:00
ret.y.append(_data.at(i).temperature());
2016-09-19 00:56:10 +02:00
ret.distance = _dd;
ret.time = _td;
return ret;
2016-06-16 20:47:32 +02:00
}
qreal Track::distance() const
2015-12-20 09:33:40 +01:00
{
return (_dd.isEmpty()) ? 0 : _dd.last();
}
2015-12-20 09:33:40 +01:00
qreal Track::time() const
{
return (_data.size() < 2) ? 0 :
(_data.first().timestamp().msecsTo(_data.last().timestamp()) / 1000.0);
2015-12-20 09:33:40 +01:00
}
2016-01-14 00:37:51 +01:00
QDateTime Track::date() const
2016-01-14 00:37:51 +01:00
{
return (_data.size()) ? _data.first().timestamp() : QDateTime();
2016-01-14 00:37:51 +01:00
}