diff --git a/src/BinRideFile.cpp b/src/BinRideFile.cpp index 629530a68..4892e5e32 100644 --- a/src/BinRideFile.cpp +++ b/src/BinRideFile.cpp @@ -660,7 +660,7 @@ struct BinFileReaderState foreach(int num, unknown_format_identifiers) { errors << QString("unknow format identifier %1; ignoring it").arg(num); } - foreach(int num, unused_record_types) { + /*foreach(int num, unused_record_types) { errors << QString("unused record type \"%1\" (%2)\n").arg(global_record_types[num].toAscii().constData()) .arg(num); } @@ -673,7 +673,7 @@ struct BinFileReaderState .arg(global_record_types[record_type].toAscii().constData()) .arg(record_type); } - } + }*/ foreach(int num, unexpected_record_types) { errors << QString("unexpected record type %1 (%2)\n").arg(global_record_types[num]).arg(num); } diff --git a/src/CriticalPowerWindow.cpp b/src/CriticalPowerWindow.cpp index ba9557e9d..7e4436d65 100644 --- a/src/CriticalPowerWindow.cpp +++ b/src/CriticalPowerWindow.cpp @@ -62,7 +62,7 @@ CriticalPowerWindow::CriticalPowerWindow(const QDir &home, MainWindow *parent) : //cpintAllValue->setFixedWidth(width); //cpintCPValue->setFixedWidth(width); // so lines up nicely - cpintTimeValue->setReadOnly(true); + cpintTimeValue->setReadOnly(false); cpintTodayValue->setReadOnly(true); cpintAllValue->setReadOnly(true); cpintCPValue->setReadOnly(true); @@ -93,6 +93,8 @@ CriticalPowerWindow::CriticalPowerWindow(const QDir &home, MainWindow *parent) : connect(picker, SIGNAL(moved(const QPoint &)), SLOT(pickerMoved(const QPoint &))); + connect(cpintTimeValue, SIGNAL(editingFinished()), + this, SLOT(cpintTimeValueEntered())); connect(cpintSetCPButton, SIGNAL(clicked()), this, SLOT(cpintSetCPButtonClicked())); connect(cComboSeason, SIGNAL(currentIndexChanged(int)), @@ -183,19 +185,16 @@ curve_to_point(double x, const QwtPlotCurve *curve) } void -CriticalPowerWindow::pickerMoved(const QPoint &pos) +CriticalPowerWindow::updateCpint(double minutes) { - double minutes = cpintPlot->invTransform(QwtPlot::xBottom, pos.x()); - cpintTimeValue->setText(interval_to_str(60.0*minutes)); - // current ride { unsigned watts = curve_to_point(minutes, cpintPlot->getThisCurve()); QString label; if (watts > 0) - label = QString(cpintPlot->energyMode() ? "%1 kJ" : "%1 watts").arg(watts); + label = QString(cpintPlot->energyMode() ? "%1 kJ" : "%1 watts").arg(watts); else - label = tr("no data"); + label = tr("no data"); cpintTodayValue->setText(label); } @@ -204,9 +203,9 @@ CriticalPowerWindow::pickerMoved(const QPoint &pos) unsigned watts = curve_to_point(minutes, cpintPlot->getCPCurve()); QString label; if (watts > 0) - label = QString(cpintPlot->energyMode() ? "%1 kJ" : "%1 watts").arg(watts); + label = QString(cpintPlot->energyMode() ? "%1 kJ" : "%1 watts").arg(watts); else - label = tr("no data"); + label = tr("no data"); cpintCPValue->setText(label); } @@ -215,7 +214,7 @@ CriticalPowerWindow::pickerMoved(const QPoint &pos) QString label; int index = (int) ceil(minutes * 60); if (cpintPlot->getBests().count() > index) { - QDate date = cpintPlot->getBestDates()[index]; + QDate date = cpintPlot->getBestDates()[index]; unsigned watts = cpintPlot->getBests()[index]; if (cpintPlot->energyMode()) label = QString("%1 kJ (%2)").arg(watts * minutes * 60.0 / 1000.0, 0, 'f', 0); @@ -223,12 +222,28 @@ CriticalPowerWindow::pickerMoved(const QPoint &pos) label = QString("%1 watts (%2)").arg(watts); label = label.arg(date.isValid() ? date.toString(tr("MM/dd/yyyy")) : tr("no date")); } - else - label = tr("no data"); + else { + label = tr("no data"); + } cpintAllValue->setText(label); } } +void +CriticalPowerWindow::cpintTimeValueEntered() +{ + double minutes = str_to_interval(cpintTimeValue->text()) / 60.0; + updateCpint(minutes); +} + +void +CriticalPowerWindow::pickerMoved(const QPoint &pos) +{ + double minutes = cpintPlot->invTransform(QwtPlot::xBottom, pos.x()); + cpintTimeValue->setText(interval_to_str(60.0*minutes)); + updateCpint(minutes); +} + void CriticalPowerWindow::addSeasons() { QFile seasonFile(home.absolutePath() + "/seasons.xml"); diff --git a/src/CriticalPowerWindow.h b/src/CriticalPowerWindow.h index f13fa37b0..74f21e5aa 100644 --- a/src/CriticalPowerWindow.h +++ b/src/CriticalPowerWindow.h @@ -51,13 +51,16 @@ class CriticalPowerWindow : public GcWindow void setMode(int x) { yAxisCombo->setCurrentIndex(x); } protected slots: - + void cpintTimeValueEntered(); void cpintSetCPButtonClicked(); void pickerMoved(const QPoint &pos); void rideSelected(); void seasonSelected(int season); void setEnergyMode(int index); + private: + void updateCpint(double minutes); + protected: QDir home; diff --git a/src/TacxCafRideFile.cpp b/src/TacxCafRideFile.cpp index ed4ef62f0..9cc531300 100644 --- a/src/TacxCafRideFile.cpp +++ b/src/TacxCafRideFile.cpp @@ -167,26 +167,43 @@ bool readRideInformationBlock(RideFile* rideFile, const QByteArray& block) { return true; } +struct RideFilePoint readSinglePoint(const QByteArray& record, const double& timeInSeconds, const double& recordingIntervalInSeconds, + const float& startDistance = 0.0f, const float& lastDistance = 0.0f) { + float distance = readFloatFromByteArray(record); + float relativeDistance = distance - startDistance; + + quint8 heartRate = readByteFromByteArray(record.mid(4)); + quint8 cadence = readByteFromByteArray(record.mid(5)); + quint16 powerX10 = readUnsignedShortFromByteArray(record.mid(6)); + double power = powerX10 / 10.0; + + double speed = (relativeDistance - lastDistance) / recordingIntervalInSeconds; + + struct RideFilePoint point(timeInSeconds, cadence, heartRate, relativeDistance / 1000.0, speed * 3.6, 0.0, power, 0.0, 0.0, 0.0, 0.0, 0); + + return point; +} + bool readRideData(RideFile *rideFile, const QByteArray& block, const int nrOfRecords, const qint16 version) { const int dataRecordSize = (version == 100) ? TACX_RIDE_DATA_BLOCK_SIZE : TACX_RIDE_DATA_BLOCK_SIZE + 8; double seconds = rideFile->recIntSecs(); + + struct RideFilePoint firstDataPoint = readSinglePoint(block, seconds, rideFile->recIntSecs()); + float startDistance = firstDataPoint.km * 1000.0; float lastDistance = 0.0f; for(int i = 0; i < nrOfRecords; i++, seconds += rideFile->recIntSecs()) { const QByteArray& record = block.mid(i * dataRecordSize); + struct RideFilePoint nextDataPoint = readSinglePoint(record, seconds, rideFile->recIntSecs(), startDistance, lastDistance); + lastDistance = nextDataPoint.km * 1000.0; - float distance = readFloatFromByteArray(record); - quint8 heartRate = readByteFromByteArray(record.mid(4)); - quint8 cadence = readByteFromByteArray(record.mid(5)); - quint16 powerX10 = readUnsignedShortFromByteArray(record.mid(6)); - double power = powerX10 / 10.0; - - double speed = (distance - lastDistance) / rideFile->recIntSecs(); - - rideFile->appendPoint(seconds, cadence, heartRate, distance / 1000.0, speed * 3.6, 0.0, power, 0.0, 0.0, 0.0, 0.0, 0); - lastDistance = distance; + rideFile->appendPoint(nextDataPoint.secs, nextDataPoint.cad, + nextDataPoint.hr, nextDataPoint.km, + nextDataPoint.kph, nextDataPoint.nm, + nextDataPoint.watts, nextDataPoint.alt, + nextDataPoint.lon, nextDataPoint.lat, + nextDataPoint.headwind, nextDataPoint.interval); } - return true; } diff --git a/src/TimeUtils.cpp b/src/TimeUtils.cpp index 1b4af2e7c..a9dba1cfd 100644 --- a/src/TimeUtils.cpp +++ b/src/TimeUtils.cpp @@ -18,11 +18,12 @@ #include "TimeUtils.h" #include +#include QString time_to_string(double secs) { QString result; - unsigned rounded = (unsigned) round(secs); + unsigned rounded = static_cast(round(secs)); bool needs_colon = false; if (rounded >= 3600) { result += QString("%1").arg(rounded / 3600); @@ -38,12 +39,24 @@ QString time_to_string(double secs) return result; } -QString interval_to_str(double secs) +double str_to_interval(QString s) +{ + QRegExp rx("(\\d+\\s*h)?\\s*(\\d{1,2}\\s*m)?\\s*(\\d{1,2})(\\.\\d+)?\\s*s"); + rx.indexIn(s); + QString hour = rx.cap(1); + QString min = rx.cap(2); + QString sec = rx.cap(3) + rx.cap(4); + hour.chop(1); + min.chop(1); + return 3600.0 * hour.toUInt() + 60.0 * min.toUInt() + sec.toDouble(); +} + +QString interval_to_str(double secs) { if (secs < 60.0) return QString("%1s").arg(secs, 0, 'f', 2, QLatin1Char('0')); QString result; - unsigned rounded = (unsigned) round(secs); + unsigned rounded = static_cast(round(secs)); bool needs_colon = false; if (rounded >= 3600) { result += QString("%1h").arg(rounded / 3600); diff --git a/src/TimeUtils.h b/src/TimeUtils.h index c555a2a12..46dd42117 100644 --- a/src/TimeUtils.h +++ b/src/TimeUtils.h @@ -24,6 +24,7 @@ #include QString interval_to_str(double secs); // output like 1h 2m 3s +double str_to_interval(QString s); // convert 1h 2m 3s -> 3123.0 , e.g. QString time_to_string(double secs); // output like 1:02:03 /* takes a string containing an ISO 8601 timestamp and converts it to local time