mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-13 16:18:42 +00:00
Show Model Estimates on Summary
.. they get refreshed in background so everyone wins !
This commit is contained in:
@@ -465,7 +465,7 @@ MetricAggregator::getRideMetrics(QString filename)
|
||||
}
|
||||
|
||||
void
|
||||
MetricAggregator::refreshCPModelMetrics()
|
||||
MetricAggregator::refreshCPModelMetrics(bool bg)
|
||||
{
|
||||
// this needs to be done once all the other metrics
|
||||
// Calculate a *monthly* estimate of CP, W' etc using
|
||||
@@ -512,14 +512,17 @@ MetricAggregator::refreshCPModelMetrics()
|
||||
|
||||
// if we have a progress dialog lets update the bar to show
|
||||
// progress for the model parameters
|
||||
#if (!defined Q_OS_MAC) || (QT_VERSION < 0x050300) // QTBUG 39038 !!!
|
||||
QProgressDialog *bar = new QProgressDialog(tr("Update Model Estimates"), tr("Abort"), 1, (lastYear*12 + lastMonth) - (year*12 + month));
|
||||
bar->setWindowFlags(bar->windowFlags() | Qt::FramelessWindowHint);
|
||||
bar->setWindowModality(Qt::WindowModal);
|
||||
bar->setMinimumDuration(0);
|
||||
bar->setValue(1);
|
||||
bar->show(); // lets hide until elapsed time is > 6 seconds
|
||||
QApplication::processEvents();
|
||||
#if (!defined Q_OS_MAC) || (defined QT_NOBUG39038) || (QT_VERSION < 0x050300) // QTBUG 39038 !!!
|
||||
QProgressDialog *bar;
|
||||
if (!bg) {
|
||||
bar = new QProgressDialog(tr("Update Model Estimates"), tr("Abort"), 1, (lastYear*12 + lastMonth) - (year*12 + month));
|
||||
bar->setWindowFlags(bar->windowFlags() | Qt::FramelessWindowHint);
|
||||
bar->setWindowModality(Qt::WindowModal);
|
||||
bar->setMinimumDuration(0);
|
||||
bar->setValue(1);
|
||||
bar->show(); // lets hide until elapsed time is > 6 seconds
|
||||
QApplication::processEvents();
|
||||
}
|
||||
#endif
|
||||
|
||||
QList< QVector<float> > months;
|
||||
@@ -604,12 +607,12 @@ MetricAggregator::refreshCPModelMetrics()
|
||||
month ++;
|
||||
}
|
||||
|
||||
#if (!defined Q_OS_MAC) || (QT_VERSION < 0x050300)
|
||||
#if (!defined Q_OS_MAC) || (defined QT_NOBUG39038) || (QT_VERSION < 0x050300) // QTBUG 39038 !!!
|
||||
// show some progress
|
||||
bar->setValue(count);
|
||||
if (!bg) bar->setValue(count);
|
||||
#endif
|
||||
}
|
||||
#if (!defined Q_OS_MAC) || (QT_VERSION < 0x050300)
|
||||
delete bar;
|
||||
#if (!defined Q_OS_MAC) || (defined QT_NOBUG39038) || (QT_VERSION < 0x050300) // QTBUG 39038 !!!
|
||||
if (!bg) delete bar;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ class MetricAggregator : public QObject
|
||||
|
||||
void refreshMetrics();
|
||||
void refreshMetrics(QDateTime forceAfterThisDate);
|
||||
void refreshCPModelMetrics(); // metrics derived from model
|
||||
void refreshCPModelMetrics(bool bg=false); // metrics derived from model
|
||||
|
||||
void getFirstLast(QDate &, QDate &);
|
||||
DBAccess *db() { return dbaccess; }
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "TimeUtils.h"
|
||||
#include "Units.h"
|
||||
#include "Zones.h"
|
||||
#include "PDModel.h"
|
||||
#include "MetricAggregator.h"
|
||||
#include "DBAccess.h"
|
||||
#include <QtGui>
|
||||
@@ -106,6 +107,9 @@ RideSummaryWindow::RideSummaryWindow(Context *context, bool ridesummary) :
|
||||
connect(dateSetting, SIGNAL(useThruToday()), this, SLOT(useThruToday()));
|
||||
connect(dateSetting, SIGNAL(useStandardRange()), this, SLOT(useStandardRange()));
|
||||
|
||||
// concurrent callback to refresh
|
||||
connect(this, SIGNAL(doRefresh()), this, SLOT(refresh()));
|
||||
|
||||
}
|
||||
connect(context, SIGNAL(configChanged()), this, SLOT(configChanged()));
|
||||
setChartLayout(vlayout);
|
||||
@@ -536,20 +540,22 @@ RideSummaryWindow::htmlSummary()
|
||||
summary += "</table></td>";
|
||||
}
|
||||
|
||||
//XXX TOO SLOW -- NEED TO THINK ABOUT DOING THIS IN BACKGROUND
|
||||
#if 0
|
||||
// now add in the model parameters if we are not in ridesummary mode...
|
||||
// if we're summarising a range we need to get the model parameters refreshed
|
||||
if (!ridesummary && bestsCache == NULL) {
|
||||
|
||||
// update the model if neccessary
|
||||
bestsCache = new RideFileCache(context, current.from, current.to, filtered, filters, true);
|
||||
// get the PDEStimates for this athlete
|
||||
if (context->athlete->PDEstimates.count() == 0) {
|
||||
|
||||
// use sensible intervals for parameter selection
|
||||
cpModel = ecp->deriveExtendedCP_5_3_Parameters(true, bestsCache,
|
||||
RideFile::watts, 20.0f/60.0f, 90.0f/60.0f, 120.0f/60.0f,
|
||||
300.0f/60.0f, 600.0f/60.0f, 3000.0f/60.0f, 4000.0f/60.0f,
|
||||
30000.0f/60.0f);
|
||||
// ugh .. refresh in background
|
||||
WPrimeString = CPString = FTPString = PMaxString = "-";
|
||||
QFuture<void> future = QtConcurrent::run(this, &RideSummaryWindow::getPDEstimates);
|
||||
|
||||
} else {
|
||||
|
||||
// set from cached values
|
||||
getPDEstimates();
|
||||
}
|
||||
|
||||
// lets get a table going
|
||||
summary += "<td align=\"center\" valign=\"top\" width=\"%1%%\"><table>"
|
||||
@@ -560,26 +566,25 @@ RideSummaryWindow::htmlSummary()
|
||||
// W;
|
||||
summary += QString("<tr><td>%1:</td><td align=\"right\">%2</td></tr>")
|
||||
.arg("W' (kJ)")
|
||||
.arg(cpModel.etau * cpModel.ecp * 60.0f / 1000.0, 0, 'f', 1);
|
||||
.arg(WPrimeString);
|
||||
|
||||
// CP;
|
||||
summary += QString("<tr><td>%1:</td><td align=\"right\">%2</td></tr>")
|
||||
.arg("CP (watts)")
|
||||
.arg(int(cpModel.ecp));
|
||||
.arg(CPString);
|
||||
|
||||
// FTP/MMP60;
|
||||
summary += QString("<tr><td>%1:</td><td align=\"right\">%2</td></tr>")
|
||||
.arg("FTP / MMP60 (watts)")
|
||||
.arg(int(cpModel.mmp60));
|
||||
.arg(FTPString);
|
||||
|
||||
// Pmax;
|
||||
summary += QString("<tr><td>%1:</td><td align=\"right\">%2</td></tr>")
|
||||
.arg("P-max (watts)")
|
||||
.arg(int(cpModel.pMax));
|
||||
.arg(PMaxString);
|
||||
|
||||
summary += "</table></td>";
|
||||
}
|
||||
#endif
|
||||
|
||||
summary += "</tr></table>";
|
||||
|
||||
@@ -958,6 +963,69 @@ RideSummaryWindow::htmlSummary()
|
||||
return summary;
|
||||
}
|
||||
|
||||
void
|
||||
RideSummaryWindow::getPDEstimates()
|
||||
{
|
||||
bool ping = false;
|
||||
double lowWPrime=0, highWPrime=0,
|
||||
lowCP=0, highCP=0,
|
||||
lowFTP=0, highFTP=0,
|
||||
lowPMax=0, highPMax=0;
|
||||
|
||||
// refresh if needed
|
||||
if (context->athlete->PDEstimates.count() == 0) {
|
||||
ping = true;
|
||||
context->athlete->metricDB->refreshCPModelMetrics(true); //true = bg ...
|
||||
}
|
||||
|
||||
// loop through and get ...
|
||||
foreach(PDEstimate est, context->athlete->PDEstimates) {
|
||||
|
||||
// We only use the extended model for now
|
||||
if (est.model != "Ext" || est.from > myDateRange.to || est.to < myDateRange.from) continue;
|
||||
|
||||
// it definitely was during our period
|
||||
if ((est.from >= myDateRange.from && est.from <= myDateRange.to) || (est.to >= myDateRange.from && est.to <= myDateRange.to) ||
|
||||
(est.from <= myDateRange.from && est.to >= myDateRange.to)) {
|
||||
|
||||
// set low
|
||||
if (!lowWPrime || est.WPrime < lowWPrime) lowWPrime = est.WPrime;
|
||||
if (!lowCP || est.CP < lowCP) lowCP = est.CP;
|
||||
if (!lowFTP || est.FTP < lowFTP) lowFTP = est.FTP;
|
||||
if (!lowPMax || est.PMax < lowPMax) lowPMax = est.PMax;
|
||||
|
||||
// set high
|
||||
if (!highWPrime || est.WPrime > highWPrime) highWPrime = est.WPrime;
|
||||
if (!highCP || est.CP > highCP) highCP = est.CP;
|
||||
if (!highFTP || est.FTP > highFTP) highFTP = est.FTP;
|
||||
if (!highPMax || est.PMax > highPMax) highPMax = est.PMax;
|
||||
}
|
||||
}
|
||||
|
||||
// ok, so lets set the string to either
|
||||
// N/A => when its not available
|
||||
// low - high => when its a range
|
||||
// val => when low = high
|
||||
if (!lowWPrime && !highWPrime) WPrimeString = "N/A";
|
||||
else if (lowWPrime != highWPrime) WPrimeString = QString ("%1 - %2").arg(lowWPrime/1000, 0, 'f', 1).arg(highWPrime/1000, 0, 'f', 1);
|
||||
else WPrimeString = QString("%1").arg(highWPrime/1000, 0, 'f', 1);
|
||||
|
||||
if (!lowCP && !highCP) CPString = "N/A";
|
||||
else if (lowCP != highCP) CPString = QString ("%1 - %2").arg(lowCP).arg(highCP);
|
||||
else CPString = QString("%1").arg(highCP);
|
||||
|
||||
if (!lowFTP && !highFTP) FTPString = "N/A";
|
||||
else if (lowFTP != highFTP) FTPString = QString ("%1 - %2").arg(lowFTP).arg(highFTP);
|
||||
else FTPString = QString("%1").arg(highFTP);
|
||||
|
||||
if (!lowPMax && !highPMax) PMaxString = "N/A";
|
||||
else if (lowPMax != highPMax) PMaxString = QString ("%1 - %2").arg(lowPMax).arg(highPMax);
|
||||
else PMaxString = QString("%1").arg(highPMax);
|
||||
|
||||
// now refresh !
|
||||
if (ping) emit doRefresh();
|
||||
}
|
||||
|
||||
QString
|
||||
RideSummaryWindow::htmlCompareSummary() const
|
||||
{
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <QWebView>
|
||||
#include <QWebFrame>
|
||||
#include <QFormLayout>
|
||||
#include <QtConcurrent>
|
||||
|
||||
#include "SummaryMetrics.h"
|
||||
#include "RideFileCache.h"
|
||||
@@ -83,6 +84,8 @@ class RideSummaryWindow : public GcChartWindow
|
||||
bool isCompare() const { return ((ridesummary && context->isCompareIntervals)
|
||||
|| (!ridesummary && context->isCompareDateRanges)); }
|
||||
|
||||
void getPDEstimates();
|
||||
|
||||
protected slots:
|
||||
|
||||
void refresh();
|
||||
@@ -107,6 +110,10 @@ class RideSummaryWindow : public GcChartWindow
|
||||
// config changed
|
||||
void configChanged();
|
||||
|
||||
signals:
|
||||
|
||||
void doRefresh();
|
||||
|
||||
protected:
|
||||
|
||||
QString htmlSummary(); // summary of a ride or a date range
|
||||
@@ -135,6 +142,8 @@ class RideSummaryWindow : public GcChartWindow
|
||||
ExtendedCriticalPower *ecp;
|
||||
Model_eCP cpModel;
|
||||
|
||||
QString WPrimeString, CPString, FTPString, PMaxString;
|
||||
|
||||
bool force; // to force a replot
|
||||
};
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ LIBS += -lm $${LIBZ_LIBS}
|
||||
# 5.2.0 or higher
|
||||
#
|
||||
## common modules
|
||||
QT += xml sql network script svg
|
||||
QT += xml sql network script svg concurrent
|
||||
|
||||
lessThan(QT_MAJOR_VERSION, 5) {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user