mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-13 16:18:42 +00:00
Added pace zone shading to CPPlot
When enabled it is convenient to set a filter for running activities in the chart since this is not done automatically yet
This commit is contained in:
@@ -748,12 +748,14 @@ CPPlot::plotBests()
|
||||
const double *values = bestsCache->meanMaxArray(rideSeries).constData() + 1;
|
||||
|
||||
// we can only do shading of the bests curve
|
||||
// when we have power and the user wants it to
|
||||
// when we have power or speed and the user wants it to
|
||||
// be a rainbow curve. Otherwise its gonna be plain
|
||||
int shadingCP = 0;
|
||||
double shadingRatio = 1.0;
|
||||
if ((rideSeries == RideFile::wattsKg || rideSeries == RideFile::watts) && shadeMode) shadingCP = dateCP;
|
||||
if (rideSeries == RideFile::wattsKg && shadeMode) shadingRatio = appsettings->cvalue(context->athlete->cyclist, GC_WEIGHT).toDouble();
|
||||
double shadingCV = 0.0;
|
||||
if (rideSeries == RideFile::kph && shadeMode) shadingCV = dateCV;
|
||||
|
||||
//For veloclinic plot we need to start by using a 2 parameters model
|
||||
if (criticalSeries == CriticalPowerWindow::veloclinicplot) {
|
||||
@@ -779,7 +781,7 @@ CPPlot::plotBests()
|
||||
}
|
||||
|
||||
if (showBest) {
|
||||
if (shadingCP == 0) {
|
||||
if (shadingCP == 0 && shadingCV == 0.0) {
|
||||
|
||||
// PLAIN CURVE
|
||||
|
||||
@@ -877,7 +879,7 @@ CPPlot::plotBests()
|
||||
curve->attach(this);
|
||||
bestsCurves.append(curve);
|
||||
|
||||
} else {
|
||||
} else if (shadingCP > 0) {
|
||||
|
||||
//
|
||||
// RAINBOW CURVE We are plotting power AND the user wants a rainbow
|
||||
@@ -968,11 +970,88 @@ CPPlot::plotBests()
|
||||
allZoneLabels.append(label_mark);
|
||||
}
|
||||
|
||||
high = low;
|
||||
++zone;
|
||||
}
|
||||
} else if (shadingCV > 0.0) {
|
||||
|
||||
//
|
||||
// RAINBOW CURVE We are plotting speed AND the user wants a rainbow
|
||||
//
|
||||
|
||||
// set zones from shading CV
|
||||
QList <double> pace_zone;
|
||||
int n_zones = context->athlete->paceZones()->lowsFromCV(&pace_zone, shadingCV);
|
||||
|
||||
// now run through each zone and create a curve
|
||||
int high = maxNonZero - 1;
|
||||
int zone = 0;
|
||||
while (zone < n_zones && high > 0) {
|
||||
|
||||
// create the curve
|
||||
QwtPlotCurve *curve = new QwtPlotCurve("");
|
||||
bestsCurves.append(curve);
|
||||
curve->attach(this);
|
||||
|
||||
// get range for the curve
|
||||
int low = high - 1;
|
||||
int nextZone = zone + 1;
|
||||
if (nextZone >= pace_zone.size())
|
||||
low = 0;
|
||||
else {
|
||||
while ((low > 0) && (values[low] < pace_zone[nextZone]))
|
||||
--low;
|
||||
}
|
||||
|
||||
// set samples
|
||||
curve->setSamples(time.data() + low, values + low, high - low + 1);
|
||||
|
||||
// set the pen color and line width etc
|
||||
QColor color = paceZoneColor(zone, n_zones);
|
||||
if (appsettings->value(this, GC_ANTIALIAS, true).toBool() == true)
|
||||
curve->setRenderHint(QwtPlotItem::RenderAntialiased);
|
||||
QPen pen(color.darker(200));
|
||||
pen.setColor(GColor(CCP)); //XXX color ?
|
||||
double width = appsettings->value(this, GC_LINEWIDTH, 0.5).toDouble();
|
||||
pen.setWidth(width);
|
||||
curve->setPen(pen);
|
||||
|
||||
// use a linear gradient
|
||||
if (shadeMode && shadingCV) { // 0 value means no shading please - and only if proper value for shadingCV
|
||||
color.setAlpha(128);
|
||||
QColor color1 = color.darker();
|
||||
QLinearGradient linearGradient(0, 0, 0, height());
|
||||
linearGradient.setColorAt(0.0, color);
|
||||
linearGradient.setColorAt(1.0, color1);
|
||||
linearGradient.setSpread(QGradient::PadSpread);
|
||||
curve->setBrush(linearGradient); // fill below the line
|
||||
}
|
||||
|
||||
// now the labels
|
||||
if (shadeMode) {
|
||||
|
||||
QwtText text(context->athlete->paceZones()->getDefaultZoneName(zone));
|
||||
text.setFont(QFont("Helvetica", 20, QFont::Bold));
|
||||
color.setAlpha(255);
|
||||
text.setColor(color);
|
||||
QwtPlotMarker *label_mark = new QwtPlotMarker();
|
||||
|
||||
// place the text in the geometric mean in time, at a decent power
|
||||
double x, y;
|
||||
x = sqrt(time[low] * time[high]);
|
||||
y = (values[low] + values[high]) / 5;
|
||||
|
||||
label_mark->setValue(x, y);
|
||||
label_mark->setLabel(text);
|
||||
label_mark->attach(this);
|
||||
allZoneLabels.append(label_mark);
|
||||
}
|
||||
|
||||
high = low;
|
||||
++zone;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// X-AXIS
|
||||
|
||||
@@ -73,6 +73,7 @@ class CPPlot : public QwtPlot
|
||||
void setShadeMode(int x);
|
||||
void setShadeIntervals(int x);
|
||||
void setDateCP(int x) { dateCP = x; }
|
||||
void setDateCV(double x) { dateCV = x; }
|
||||
void setSeries(CriticalPowerWindow::CriticalSeriesType);
|
||||
void setPlotType(int index);
|
||||
void setModel(int sanI1, int sanI2, int anI1, int anI2,
|
||||
@@ -137,6 +138,7 @@ class CPPlot : public QwtPlot
|
||||
Context *context;
|
||||
RideFileCache *rideCache, *bestsCache;
|
||||
int dateCP;
|
||||
double dateCV;
|
||||
|
||||
// settings
|
||||
RideFile::SeriesType rideSeries;
|
||||
|
||||
@@ -157,7 +157,7 @@ CriticalPowerWindow::CriticalPowerWindow(Context *context, bool rangemode) :
|
||||
|
||||
// shading
|
||||
shadeCheck = new QCheckBox(this);
|
||||
QLabel *shading = new QLabel(tr("Power Shading"));
|
||||
QLabel *shading = new QLabel(tr("Zone Shading"));
|
||||
shadeCheck->setChecked(true);
|
||||
cl->addRow(shading, shadeCheck);
|
||||
|
||||
@@ -1090,6 +1090,13 @@ CriticalPowerWindow::rideSelected()
|
||||
} else {
|
||||
cpPlot->setDateCP(0);
|
||||
}
|
||||
if (context->athlete->paceZones()) {
|
||||
int paceZoneRange = context->athlete->paceZones()->whichRange(currentRide->dateTime.date());
|
||||
double CV = paceZoneRange >= 0.0 ? context->athlete->paceZones()->getCV(paceZoneRange) : 0.0;
|
||||
cpPlot->setDateCV(CV);
|
||||
} else {
|
||||
cpPlot->setDateCV(0.0);
|
||||
}
|
||||
cpPlot->setRide(currentRide);
|
||||
|
||||
if (!rangemode && currentRide->ride() && currentRide->ride()->dataPoints().count() == 0)
|
||||
@@ -1475,6 +1482,19 @@ CriticalPowerWindow::dateRangeChanged(DateRange dateRange)
|
||||
cpPlot->setDateCP(dateCP);
|
||||
}
|
||||
|
||||
// lets work out the average CV configure value
|
||||
if (context->athlete->paceZones()) {
|
||||
int fromZoneRange = context->athlete->paceZones()->whichRange(cfrom);
|
||||
int toZoneRange = context->athlete->paceZones()->whichRange(cto);
|
||||
|
||||
double CVfrom = fromZoneRange >= 0 ? context->athlete->paceZones()->getCV(fromZoneRange) : 0.0;
|
||||
double CVto = toZoneRange >= 0 ? context->athlete->paceZones()->getCV(toZoneRange) : CVfrom;
|
||||
if (CVfrom == 0.0) CVfrom = CVto;
|
||||
double dateCV = (CVfrom + CVto) / 2.0;
|
||||
|
||||
cpPlot->setDateCV(dateCV);
|
||||
}
|
||||
|
||||
cpPlot->setDateRange(dateRange.from, dateRange.to);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user