mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-13 16:18:42 +00:00
GPS support in RideFile
RideFile data points now include lon and lat members for the longitude degrees and latitute degrees from the source ride files. As a result most of the RideFile readers now set longitude and latitude to zero for each data point, except for: * Gc Format Files - now support read/write * Wko Format Files - now support read * Tcx Format Files - now support read (smoothed if smart recording) Although there are no features within GC at this point in time that use positioning data this may change over time. Critically, as users save files to the new GC file format whilst adding interval data it is important that this positioning data is not discarded before new features arrive.
This commit is contained in:
committed by
Sean Rhea
parent
2745291f59
commit
45d7d3c610
@@ -225,7 +225,7 @@ RideFile *Computrainer3dpFileReader::openRideFile(QFile & file,
|
||||
// special case first data point
|
||||
rideFile->appendPoint((double) ms/1000, (double) cad,
|
||||
(double) hr, km, speed, 0.0, watts,
|
||||
altitude, 0, 0);
|
||||
altitude, 0, 0, 0, 0);
|
||||
}
|
||||
// while loop since an interval in the .3dp file might
|
||||
// span more than one CT_EMIT_MS interval
|
||||
@@ -271,6 +271,8 @@ RideFile *Computrainer3dpFileReader::openRideFile(QFile & file,
|
||||
0.0,
|
||||
((double) watts_sum) / CT_EMIT_MS,
|
||||
interpol_alt,
|
||||
0, // lon
|
||||
0, // lat
|
||||
0,
|
||||
0);
|
||||
|
||||
|
||||
@@ -202,7 +202,7 @@ RideFile *CsvFileReader::openRideFile(QFile &file, QStringList &errors) const
|
||||
watts = 0;
|
||||
|
||||
rideFile->appendPoint(minutes * 60.0, cad, hr, km,
|
||||
kph, nm, watts, alt, interval);
|
||||
kph, nm, watts, alt, 0.0, 0.0, interval);
|
||||
}
|
||||
++lineno;
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ GcFileReader::openRideFile(QFile &file, QStringList &errors) const
|
||||
bool recIntSet = false;
|
||||
for (QDomElement sample = samples.firstChildElement("sample");
|
||||
!sample.isNull(); sample = sample.nextSiblingElement("sample")) {
|
||||
double secs, cad, hr, km, kph, nm, watts, alt;
|
||||
double secs, cad, hr, km, kph, nm, watts, alt, lon, lat;
|
||||
secs = sample.attribute("secs", "0.0").toDouble();
|
||||
cad = sample.attribute("cad", "0.0").toDouble();
|
||||
hr = sample.attribute("hr", "0.0").toDouble();
|
||||
@@ -95,9 +95,11 @@ GcFileReader::openRideFile(QFile &file, QStringList &errors) const
|
||||
nm = sample.attribute("nm", "0.0").toDouble();
|
||||
watts = sample.attribute("watts", "0.0").toDouble();
|
||||
alt = sample.attribute("alt", "0.0").toDouble();
|
||||
lon = sample.attribute("lon", "0.0").toDouble();
|
||||
lat = sample.attribute("lat", "0.0").toDouble();
|
||||
while ((interval < intervalStops.size()) && (secs >= intervalStops[interval]))
|
||||
++interval;
|
||||
rideFile->appendPoint(secs, cad, hr, km, kph, nm, watts, alt, interval);
|
||||
rideFile->appendPoint(secs, cad, hr, km, kph, nm, watts, alt, lon, lat, interval);
|
||||
if (!recIntSet) {
|
||||
rideFile->setRecIntSecs(sample.attribute("len").toDouble());
|
||||
recIntSet = true;
|
||||
@@ -165,6 +167,8 @@ GcFileReader::writeRideFile(const RideFile *ride, QFile &file) const
|
||||
add_sample(nm);
|
||||
add_sample(watts);
|
||||
add_sample(alt);
|
||||
add_sample(lon);
|
||||
add_sample(lat);
|
||||
sample.setAttribute("len", QString("%1").arg(ride->recIntSecs()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ RideFile *ManualFileReader::openRideFile(QFile &file, QStringList &errors) const
|
||||
interval = 0;
|
||||
|
||||
rideFile->appendPoint(minutes * 60.0, cad, hr, km,
|
||||
kph, nm, watts, alt, interval, bs);
|
||||
kph, nm, watts, alt, 0.0, 0.0, interval, bs);
|
||||
|
||||
rideSec = minutes * 60.0;
|
||||
}
|
||||
|
||||
@@ -200,7 +200,7 @@ this differently
|
||||
next_interval = intervals.at(interval);
|
||||
}
|
||||
}
|
||||
rideFile->appendPoint(seconds, cad, hr, km, kph, nm, watts, alt, interval);
|
||||
rideFile->appendPoint(seconds, cad, hr, km, kph, nm, watts, alt, 0.0, 0.0, interval);
|
||||
//fprintf(stderr, " %f, %f, %f, %f, %f, %f, %f, %d\n", seconds, cad, hr, km, kph, nm, watts, alt, interval);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ QuarqParser::incrementTime( const double new_time )
|
||||
while (time_diff > seconds_from_start) {
|
||||
|
||||
rideFile->appendPoint(seconds_from_start, cad, hr, km,
|
||||
kph, nm, watts, 0, 0, 0);
|
||||
kph, nm, watts, 0, 0.0, 0.0, 0, 0);
|
||||
|
||||
seconds_from_start += SAMPLE_INTERVAL;
|
||||
}
|
||||
@@ -114,7 +114,7 @@ QuarqParser::endElement( const QString&, const QString&, const QString& qName)
|
||||
// flush one last data point
|
||||
if (qName == "Qollector") {
|
||||
rideFile->appendPoint(seconds_from_start, cad, hr, km,
|
||||
kph, nm, watts, 0, 0, 0);
|
||||
kph, nm, watts, 0, 0.0, 0.0, 0, 0);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
@@ -70,7 +70,7 @@ time_cb(struct tm *, time_t since_epoch, void *context)
|
||||
double secs = since_epoch - state->start_since_epoch;
|
||||
state->rideFile->appendPoint(secs, 0.0, 0.0,
|
||||
state->last_miles * KM_PER_MILE, 0.0,
|
||||
0.0, 0.0, 0.0, state->last_interval);
|
||||
0.0, 0.0, 0.0, 0.0, 0.0, state->last_interval);
|
||||
state->last_secs = secs;
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ data_cb(double secs, double nm, double mph, double watts, double miles, double a
|
||||
|
||||
ReadState *state = (ReadState*) context;
|
||||
state->rideFile->appendPoint(secs, cad, hr, miles * KM_PER_MILE,
|
||||
mph * KM_PER_MILE, nm, watts, alt, interval);
|
||||
mph * KM_PER_MILE, nm, watts, alt, 0.0, 0.0, interval);
|
||||
state->last_secs = secs;
|
||||
state->last_miles = miles;
|
||||
state->last_interval = interval;
|
||||
|
||||
@@ -200,10 +200,10 @@ QStringList RideFileFactory::listRideFiles(const QDir &dir) const
|
||||
|
||||
void RideFile::appendPoint(double secs, double cad, double hr, double km,
|
||||
double kph, double nm, double watts, double alt,
|
||||
int interval, double bs)
|
||||
double lon, double lat, int interval, double bs)
|
||||
{
|
||||
dataPoints_.append(new RideFilePoint(secs, cad, hr, km, kph,
|
||||
nm, watts, alt, interval,bs));
|
||||
nm, watts, alt, lon, lat, interval,bs));
|
||||
dataPresent.secs |= (secs != 0);
|
||||
dataPresent.cad |= (cad != 0);
|
||||
dataPresent.hr |= (hr != 0);
|
||||
@@ -212,5 +212,7 @@ void RideFile::appendPoint(double secs, double cad, double hr, double km,
|
||||
dataPresent.nm |= (nm != 0);
|
||||
dataPresent.watts |= (watts != 0);
|
||||
dataPresent.alt |= (alt != 0);
|
||||
dataPresent.lon |= (lon != 0);
|
||||
dataPresent.lat |= (lat != 0);
|
||||
dataPresent.interval |= (interval != 0);
|
||||
}
|
||||
|
||||
@@ -43,24 +43,24 @@
|
||||
|
||||
struct RideFilePoint
|
||||
{
|
||||
double secs, cad, hr, km, kph, nm, watts, alt;
|
||||
double secs, cad, hr, km, kph, nm, watts, alt, lon, lat;;
|
||||
int interval;
|
||||
double bs; // to init in order
|
||||
RideFilePoint() : secs(0.0), cad(0.0), hr(0.0), km(0.0), kph(0.0),
|
||||
nm(0.0), watts(0.0), alt(0.0), interval(0), bs(0.0) {}
|
||||
nm(0.0), watts(0.0), alt(0.0), lon(0.0), lat(0.0), interval(0), bs(0.0) {}
|
||||
RideFilePoint(double secs, double cad, double hr, double km, double kph,
|
||||
double nm, double watts, double alt, int interval, double bs) :
|
||||
double nm, double watts, double alt, double lon, double lat, int interval, double bs) :
|
||||
secs(secs), cad(cad), hr(hr), km(km), kph(kph), nm(nm),
|
||||
watts(watts), alt(alt), interval(interval), bs(bs) {}
|
||||
watts(watts), alt(alt), lon(lon), lat(lat), interval(interval), bs(bs) {}
|
||||
};
|
||||
|
||||
struct RideFileDataPresent
|
||||
{
|
||||
bool secs, cad, hr, km, kph, nm, watts, alt, interval;
|
||||
bool secs, cad, hr, km, kph, nm, watts, alt, lon, lat, interval;
|
||||
// whether non-zero data of each field is present
|
||||
RideFileDataPresent():
|
||||
secs(false), cad(false), hr(false), km(false),
|
||||
kph(false), nm(false), watts(false), alt(false), interval(false) {}
|
||||
kph(false), nm(false), watts(false), alt(false), lon(false), lat(false), interval(false) {}
|
||||
};
|
||||
|
||||
struct RideFileInterval
|
||||
@@ -107,7 +107,7 @@ class RideFile
|
||||
|
||||
void appendPoint(double secs, double cad, double hr, double km,
|
||||
double kph, double nm, double watts, double alt,
|
||||
int interval, double bs=0.0);
|
||||
double lon, double lat, int interval, double bs=0.0);
|
||||
|
||||
const QList<RideFileInterval> &intervals() const { return intervals_; }
|
||||
void addInterval(double start, double stop, const QString &name) {
|
||||
|
||||
@@ -139,7 +139,7 @@ SplitRideDialog::CreateNewRideFile(const RideFile *ride, int nRecStart, int nRec
|
||||
{
|
||||
RideFilePoint *pPoint = ride->dataPoints().at(nItem);
|
||||
newRideFile->appendPoint(pPoint->secs-pointStart->secs, pPoint->cad, pPoint->hr, pPoint->km - pointStart->km,
|
||||
pPoint->kph, pPoint->nm, pPoint->watts, pPoint->alt, pPoint->interval-pointStart->interval);
|
||||
pPoint->kph, pPoint->nm, pPoint->watts, pPoint->alt, pPoint->lon, pPoint->lat, pPoint->interval-pointStart->interval);
|
||||
}
|
||||
|
||||
QString fileName;
|
||||
|
||||
@@ -202,7 +202,7 @@ RideFile *SrmFileReader::openRideFile(QFile &file, QStringList &errorStrings) co
|
||||
km += result->recIntSecs() * kph / 3600.0;
|
||||
|
||||
double nm = watts / 2.0 / PI / cad * 60.0;
|
||||
result->appendPoint(secs, cad, hr, km, kph, nm, watts, alt, interval);
|
||||
result->appendPoint(secs, cad, hr, km, kph, nm, watts, alt, 0.0, 0.0, interval);
|
||||
|
||||
++blkidx;
|
||||
if ((blkidx == blockhdrs[blknum].chunkcnt) && (blknum + 1 < blockcnt)) {
|
||||
|
||||
@@ -89,6 +89,14 @@ TcxParser::endElement( const QString&, const QString&, const QString& qName)
|
||||
{
|
||||
alt = buffer.toDouble();
|
||||
}
|
||||
else if (qName == "LongitudeDegrees")
|
||||
{
|
||||
lon = buffer.toDouble();
|
||||
}
|
||||
else if (qName == "LatitudeDegrees")
|
||||
{
|
||||
lat = buffer.toDouble();
|
||||
}
|
||||
else if (qName == "Trackpoint")
|
||||
{
|
||||
// nh - there are track points that don't have any distance info. We need to ignore them
|
||||
@@ -135,7 +143,7 @@ TcxParser::endElement( const QString&, const QString&, const QString& qName)
|
||||
if(rideFile->dataPoints().empty()) {
|
||||
// first point
|
||||
rideFile->appendPoint(secs, cadence, hr, distance,
|
||||
speed, torque, power, alt, lap);
|
||||
speed, torque, power, alt, lon, lat, lap);
|
||||
}
|
||||
else {
|
||||
// assumption that the change in ride is linear... :)
|
||||
@@ -148,10 +156,12 @@ TcxParser::endElement( const QString&, const QString&, const QString& qName)
|
||||
double deltaTorque = torque - prevPoint->nm;
|
||||
double deltaPower = power - prevPoint->watts;
|
||||
double deltaAlt = alt - prevPoint->alt;
|
||||
double deltaLon = lon - prevPoint->lon;
|
||||
double deltaLat = lat - prevPoint->lat;
|
||||
if(deltaSecs == 1) {
|
||||
// no smart recording, just insert the data
|
||||
rideFile->appendPoint(secs, cadence, hr, distance,
|
||||
speed, torque, power, alt, lap);
|
||||
speed, torque, power, alt, lon, lat, lap);
|
||||
}
|
||||
else {
|
||||
for(int i = 1; i <= deltaSecs; i++) {
|
||||
@@ -161,6 +171,8 @@ TcxParser::endElement( const QString&, const QString&, const QString& qName)
|
||||
kph = kph > 0.35 ? kph : 0;
|
||||
double cad = prevPoint->cad + (deltaCad * weight);
|
||||
cad = cad > 0.35 ? cad : 0;
|
||||
double lat = prevPoint->lat + (deltaLat * weight);
|
||||
double lon = prevPoint->lon + (deltaLon * weight);
|
||||
rideFile->appendPoint(
|
||||
prevPoint->secs + (deltaSecs * weight),
|
||||
prevPoint->cad + (deltaCad * weight),
|
||||
@@ -170,6 +182,8 @@ TcxParser::endElement( const QString&, const QString&, const QString& qName)
|
||||
prevPoint->nm + (deltaTorque * weight),
|
||||
prevPoint->watts + (deltaPower * weight),
|
||||
prevPoint->alt + (deltaAlt * weight),
|
||||
lon, // lon
|
||||
lat, // lat
|
||||
lap);
|
||||
}
|
||||
prevPoint = rideFile->dataPoints().back();
|
||||
|
||||
@@ -54,6 +54,8 @@ private:
|
||||
double hr;
|
||||
double lastAltitude;
|
||||
double alt;
|
||||
double lat;
|
||||
double lon;
|
||||
};
|
||||
|
||||
#endif // _TcxParser_h
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
// global variable called WKO_HOMEDIR.
|
||||
//
|
||||
// 2. UNUSED GRAPHS
|
||||
// Windspeed, Temperature, GPS and other data is available from WKO
|
||||
// Windspeed, Temperature, Slope et al are available from WKO
|
||||
// data files but is discarded currently since it is not supported by RideFile
|
||||
//
|
||||
// 3. GOTO
|
||||
@@ -50,10 +50,6 @@
|
||||
// Shared between a number of functions to simplify parameter passing and avoid
|
||||
// refactoring as a class.
|
||||
//
|
||||
// 5. METRIC/IMPERIAL CONVERSION
|
||||
// Code is available to support conversion from WKO standard of all metric but it is not
|
||||
// enabled -- need to understand how metric/imperial conversion is supposed to be managed
|
||||
//
|
||||
|
||||
#include "WkoRideFile.h"
|
||||
#include <QRegExp>
|
||||
@@ -160,7 +156,7 @@ RideFile *WkoFileReader::openRideFile(QFile &file, QStringList &errors) const
|
||||
WKO_UCHAR *WkoParseRawData(WKO_UCHAR *fb, RideFile *rideFile, QStringList &errors)
|
||||
{
|
||||
WKO_ULONG WKO_xormasks[32]; // xormasks used all over
|
||||
double cad, hr, km, kph, nm, watts, alt, interval;
|
||||
double cad=0, hr=0, km=0, kph=0, nm=0, watts=0, alt=0, lon=0, lat=0, interval=0;
|
||||
|
||||
int isnull=0;
|
||||
WKO_ULONG records, data;
|
||||
@@ -367,7 +363,6 @@ WKO_UCHAR *WkoParseRawData(WKO_UCHAR *fb, RideFile *rideFile, QStringList &error
|
||||
case 'G' : /* two longs */
|
||||
{
|
||||
signed long llat, llon;
|
||||
double lat,lon;
|
||||
char slat[20], slon[20];
|
||||
|
||||
// stored 2s complement
|
||||
@@ -420,7 +415,7 @@ WKO_UCHAR *WkoParseRawData(WKO_UCHAR *fb, RideFile *rideFile, QStringList &error
|
||||
|
||||
// !! needs to be modified to support the new alt patch
|
||||
rideFile->appendPoint((double)rtime/1000, cad, hr, km,
|
||||
kph, nm, watts, alt, 0);
|
||||
kph, nm, watts, alt, lon, lat, 0);
|
||||
}
|
||||
|
||||
// increment time - even for null records (perhaps especially for null
|
||||
|
||||
Reference in New Issue
Block a user