From 45d7d3c61059c97ffc1b5bc528211d05c51bbffe Mon Sep 17 00:00:00 2001 From: Mark Liversedge Date: Mon, 14 Dec 2009 18:16:06 +0000 Subject: [PATCH] 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. --- src/Computrainer3dpFile.cpp | 4 +++- src/CsvRideFile.cpp | 2 +- src/GcRideFile.cpp | 8 ++++++-- src/ManualRideFile.cpp | 2 +- src/PolarRideFile.cpp | 2 +- src/QuarqParser.cpp | 4 ++-- src/RawRideFile.cpp | 4 ++-- src/RideFile.cpp | 6 ++++-- src/RideFile.h | 14 +++++++------- src/SplitRideDialog.cpp | 2 +- src/SrmRideFile.cpp | 2 +- src/TcxParser.cpp | 18 ++++++++++++++++-- src/TcxParser.h | 2 ++ src/WkoRideFile.cpp | 11 +++-------- 14 files changed, 50 insertions(+), 31 deletions(-) diff --git a/src/Computrainer3dpFile.cpp b/src/Computrainer3dpFile.cpp index 3c157169a..5b799206d 100644 --- a/src/Computrainer3dpFile.cpp +++ b/src/Computrainer3dpFile.cpp @@ -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); diff --git a/src/CsvRideFile.cpp b/src/CsvRideFile.cpp index a3f13c601..23661b233 100644 --- a/src/CsvRideFile.cpp +++ b/src/CsvRideFile.cpp @@ -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; } diff --git a/src/GcRideFile.cpp b/src/GcRideFile.cpp index 2b4a046c0..b6219f7a8 100644 --- a/src/GcRideFile.cpp +++ b/src/GcRideFile.cpp @@ -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())); } } diff --git a/src/ManualRideFile.cpp b/src/ManualRideFile.cpp index fc124c35e..54f78d080 100644 --- a/src/ManualRideFile.cpp +++ b/src/ManualRideFile.cpp @@ -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; } diff --git a/src/PolarRideFile.cpp b/src/PolarRideFile.cpp index 3f812bb10..c4fce8298 100644 --- a/src/PolarRideFile.cpp +++ b/src/PolarRideFile.cpp @@ -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); } diff --git a/src/QuarqParser.cpp b/src/QuarqParser.cpp index 5f94d8976..b25f1e9d3 100644 --- a/src/QuarqParser.cpp +++ b/src/QuarqParser.cpp @@ -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; diff --git a/src/RawRideFile.cpp b/src/RawRideFile.cpp index 2010cf591..922092c48 100644 --- a/src/RawRideFile.cpp +++ b/src/RawRideFile.cpp @@ -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; diff --git a/src/RideFile.cpp b/src/RideFile.cpp index d8ec58339..1e4e1ac27 100644 --- a/src/RideFile.cpp +++ b/src/RideFile.cpp @@ -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); } diff --git a/src/RideFile.h b/src/RideFile.h index f9f3a23e3..e1242a585 100644 --- a/src/RideFile.h +++ b/src/RideFile.h @@ -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 &intervals() const { return intervals_; } void addInterval(double start, double stop, const QString &name) { diff --git a/src/SplitRideDialog.cpp b/src/SplitRideDialog.cpp index 95c8c6999..bb6d4b00a 100644 --- a/src/SplitRideDialog.cpp +++ b/src/SplitRideDialog.cpp @@ -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; diff --git a/src/SrmRideFile.cpp b/src/SrmRideFile.cpp index 9f0ca1bb6..857976a0a 100644 --- a/src/SrmRideFile.cpp +++ b/src/SrmRideFile.cpp @@ -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)) { diff --git a/src/TcxParser.cpp b/src/TcxParser.cpp index 87e4f502a..f659266ae 100644 --- a/src/TcxParser.cpp +++ b/src/TcxParser.cpp @@ -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(); diff --git a/src/TcxParser.h b/src/TcxParser.h index 2719f1e3b..7c15b291b 100644 --- a/src/TcxParser.h +++ b/src/TcxParser.h @@ -54,6 +54,8 @@ private: double hr; double lastAltitude; double alt; + double lat; + double lon; }; #endif // _TcxParser_h diff --git a/src/WkoRideFile.cpp b/src/WkoRideFile.cpp index 9d7a3228f..1e047ae24 100644 --- a/src/WkoRideFile.cpp +++ b/src/WkoRideFile.cpp @@ -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 @@ -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