Exemple #1
0
    virtual void draw(QPainter *painter,
		      const QwtScaleMap &xMap, const QwtScaleMap &,
		      const QRect &rect) const
    {
	RideItem *rideItem = parent->rideItem;

	if (! rideItem)
	    return;

	const Zones *zones       = rideItem->zones;
	int zone_range     = rideItem->zoneRange();

	if (parent->shadeZones() && (zone_range >= 0)) {
	    QList <int> zone_lows = zones->getZoneLows(zone_range);
	    int num_zones = zone_lows.size();
	    if (num_zones > 0) {
		for (int z = 0; z < num_zones; z ++) {
		    QRect r = rect;

		    QColor shading_color =
			zoneColor(z, num_zones);
		    shading_color.setHsv(
					 shading_color.hue(),
					 shading_color.saturation() / 4,
					 shading_color.value()
					 );
		    r.setLeft(xMap.transform(zone_lows[z]));
		    if (z + 1 < num_zones)
			r.setRight(xMap.transform(zone_lows[z + 1]));
		    if (r.right() >= r.left())
			painter->fillRect(r, shading_color);
		}
	    }
	}
    }
    PfPvPlotZoneLabel(PfPvPlot *_parent, int _zone_number)
    {
        parent = _parent;
        zone_number = _zone_number;

        RideItem *rideItem = parent->rideItem;
        const Zones *zones = rideItem->zones;
        int zone_range = rideItem->zoneRange();

        setZ(1.0 + zone_number / 100.0);

        // create new zone labels if we're shading
        if (zone_range >= 0) {

            // retrieve zone setup
            QList <int> zone_lows = zones->getZoneLows(zone_range);
            QList <QString> zone_names = zones->getZoneNames(zone_range);
            int num_zones = zone_lows.size();
            assert(zone_names.size() == num_zones);

            if (zone_number < num_zones) {

                watts = ((zone_number + 1 < num_zones) ?  0.5 * (zone_lows[zone_number] + zone_lows[zone_number + 1]) : ( (zone_number > 0) ?  (1.5 * zone_lows[zone_number] - 0.5 * zone_lows[zone_number - 1]) : 2.0 * zone_lows[zone_number]));

                text = QwtText(zone_names[zone_number]);
                text.setFont(QFont("Helvetica",24, QFont::Bold));
                QColor text_color = zoneColor(zone_number, num_zones);
                text_color.setAlpha(64);
                text.setColor(text_color);
            }
        }
    }
Exemple #3
0
    PfPvPlotZoneLabel(PfPvPlot *_parent, int _zone_number)
    {
        parent = _parent;
        RideItem *rideItem = parent->rideItem;
        zone_number = _zone_number;

        // get zone data from ride or athlete ...
        const Zones *zones;
        int zone_range = -1;

        if (parent->context->isCompareIntervals) {

            zones = parent->context->athlete->zones();
            if (!zones) return;

            // use first compare interval date
            if (parent->context->compareIntervals.count())
                zone_range = zones->whichRange(parent->context->compareIntervals[0].data->startTime().date());

            // still not set 
            if (zone_range == -1)
                zone_range = zones->whichRange(QDate::currentDate());

        } else if (rideItem) {

            zones = rideItem->zones;
            zone_range = rideItem->zoneRange();

        } else {

            return; // nulls

        }

        setZ(1.0 + zone_number / 100.0);

        // create new zone labels if we're shading
        if (zone_range >= 0) {

            // retrieve zone setup
            QList <int> zone_lows = zones->getZoneLows(zone_range);
            QList <QString> zone_names = zones->getZoneNames(zone_range);
            int num_zones = zone_lows.size();
            if(zone_names.size() != num_zones) return;

            if (zone_number < num_zones) {

                watts = ((zone_number + 1 < num_zones) ?  0.5 * (zone_lows[zone_number] + zone_lows[zone_number + 1]) : ( (zone_number > 0) ?  (1.5 * zone_lows[zone_number] - 0.5 * zone_lows[zone_number - 1]) : 2.0 * zone_lows[zone_number]));

                text = QwtText(zone_names[zone_number]);
                text.setFont(QFont("Helvetica",24, QFont::Bold));
                QColor text_color = zoneColor(zone_number, num_zones);
                text_color.setAlpha(64);
                text.setColor(text_color);
            }
        }
    }
Exemple #4
0
void
PfPvPlot::refreshZoneItems()
{
    // clear out any zone curves which are presently defined
    if (zoneCurves.size()) {

        QListIterator<QwtPlotCurve *> i(zoneCurves);
        while (i.hasNext()) {
            QwtPlotCurve *curve = i.next();
            curve->detach();
            //delete curve;
        }
    }
    zoneCurves.clear();

    // delete any existing power zone labels
    if (zoneLabels.size()) {

        QListIterator<PfPvPlotZoneLabel *> i(zoneLabels);
        while (i.hasNext()) {
            PfPvPlotZoneLabel *label = i.next();
            label->detach();
            delete label;
        }
    }
    zoneLabels.clear();

    // set zones from ride or athlete and date of
    // first item in the compare set
    const Zones *zones;
    int zone_range = -1;

    // comparing does zones for items selected not current ride
    if (context->isCompareIntervals) {

        zones = context->athlete->zones();

        // no athlete zones anyway!
        if (!zones) return;

        // use first compare interval date
        if (context->compareIntervals.count()) {
            zone_range = zones->whichRange(context->compareIntervals[0].data->startTime().date());
        }

        // still not set 
        if (zone_range == -1) {
            zone_range = zones->whichRange(QDate::currentDate());
        }

    } else if (rideItem) {

        zones = rideItem->zones;
        zone_range = rideItem->zoneRange();

    } else {

        return; // null ride and not compare etc
    }

    if (zone_range >= 0) {
        setCP(zones->getCP(zone_range));

        // populate the zone curves
        QList <int> zone_power = zones->getZoneLows(zone_range);
        QList <QString> zone_name = zones->getZoneNames(zone_range);
        int num_zones = zone_power.size();
        if (zone_name.size() != num_zones) return;

        if (num_zones > 0) {
            QPen *pen = new QPen();
            pen->setStyle(Qt::NoPen);

            QwtArray<double> yvalues;

            // generate x values
            for (int z = 0; z < num_zones; z ++) {

                QwtPlotCurve *curve = new QwtPlotCurve(zone_name[z]);

                curve->setPen(*pen);
                QColor brush_color = zoneColor(z, num_zones);
                brush_color.setHsv(brush_color.hue(), brush_color.saturation() / 4, brush_color.value());
                curve->setBrush(brush_color);   // fill below the line
                curve->setZ(1 - 1e-6 * zone_power[z]);

                // generate data for curve
                if (z < num_zones - 1) {
                    QwtArray <double> contour_yvalues;
                    int watts = zone_power[z + 1];
                    int dwatts = (double) watts;
                    for (int i = 0; i < contour_xvalues.size(); i ++) {
                        contour_yvalues.append( (1e6 * contour_xvalues[i] < watts) ?  1e6 : dwatts / contour_xvalues[i]);
                    }
                    curve->setSamples(contour_xvalues, contour_yvalues);

                } else {

                    // top zone has a curve at "infinite" power
                    QwtArray <double> contour_x;
                    QwtArray <double> contour_y;
                    contour_x.append(contour_xvalues[0]);
                    contour_x.append(contour_xvalues[contour_xvalues.size() - 1]);
                    contour_y.append(1e6);
                    contour_y.append(1e6);
                    curve->setSamples(contour_x, contour_y);
                }

                curve->setVisible(shade_zones);
                curve->attach(this);
                zoneCurves.append(curve);
            }

            delete pen;

            // generate labels for existing zones
            for (int z = 0; z < num_zones; z ++) {
                PfPvPlotZoneLabel *label = new PfPvPlotZoneLabel(this, z);
                label->setVisible(shade_zones);
                label->attach(this);
                zoneLabels.append(label);
            }
        }
    }
}
void
WWPowerScale::paint(QPainter *painter)
{
    int rnum = -1;

    // CP etc are not available so draw nothing
    if (context->athlete->zones(false) == NULL || (rnum = context->athlete->zones(false)->whichRange(QDate::currentDate())) == -1) return;

    // lets get the zones, CP and PMAX
    int CP = context->athlete->zones(false)->getCP(rnum);
    int Pmax = context->athlete->zones(false)->getPmax(rnum);
    Q_UNUSED(Pmax); // for now ........
    int numZones = context->athlete->zones(false)->numZones(rnum);

    QFontMetrics fontMetrics(workoutWidget()->markerFont);
    QFontMetrics bfontMetrics(workoutWidget()->bigFont);

    for(int i=0; i<numZones; i++) {

        // zoneinfo here
        QString name, description;
        int low, high;

        // get zoneinfo  for a given range and zone
        context->athlete->zones(false)->zoneInfo(rnum, i, name, description, low, high);

        // draw coordinates
        int ylow=workoutWidget()->transform(0,low).y();
        int yhigh=workoutWidget()->transform(0,high).y();

        // stay within left block
        if (yhigh < workoutWidget()->canvas().y()) yhigh = workoutWidget()->canvas().y();
        int ymid = (yhigh + ylow) / 2;

        // bounding rect for zone color
        QRect bound(QPoint(workoutWidget()->left().topRight().x()-POWERSCALEWIDTH, yhigh),
                    QPoint(workoutWidget()->left().topRight().x(), ylow));

        // draw rect
        painter->fillRect(bound, QBrush(zoneColor(i,numZones)));

        // HIGH % LABELS
        if (i<(numZones-1)) {

            // percent labels for high only - but skip the last zone its off to infinity..
            QString label = QString("%1%").arg(int(double(high) / double(CP) * 100.00f));
            QRect textBound = fontMetrics.boundingRect(label);
            painter->setFont(workoutWidget()->markerFont);
            painter->setPen(workoutWidget()->markerPen);

            painter->drawText(QPoint(workoutWidget()->left().right()-SPACING-textBound.width()-POWERSCALEWIDTH,
                                        yhigh+(fontMetrics.ascent()/2)), // we use ascent not height to line up numbers
                                        label);
        }

        // if we have gridlines enabled and don't paint on canvas border
        if (GRIDLINES && yhigh > workoutWidget()->canvas().y()) {

            QColor color(zoneColor(i,numZones));
            color.setAlpha(128);
            painter->setPen(QPen(color));

            // zone high
            painter->drawLine(QPoint(workoutWidget()->canvas().x(), yhigh),
                             QPoint(workoutWidget()->canvas().x()+workoutWidget()->canvas().width(), yhigh));

            // ZONE LABELS MID CANVAS AND FEINT
            QRect boundText = bfontMetrics.boundingRect(name);
            painter->setFont(workoutWidget()->bigFont);

            painter->drawText(QPoint(workoutWidget()->canvas().center().x() - (boundText.width()/2),
                                    ymid+(bfontMetrics.ascent()/2)), // we use ascent not height to line up numbers
                                    name);
        }
    }

    // CP !
    QPen cppen(GColor(CPLOTMARKER));
    cppen.setStyle(Qt::DashLine);
    painter->setPen(cppen);

    double CPy = workoutWidget()->transform(0, CP).y();

    // zone high
    painter->drawLine(QPoint(workoutWidget()->canvas().x(), CPy),
                      QPoint(workoutWidget()->canvas().x()+workoutWidget()->canvas().width(), CPy));

}
Exemple #6
0
void
CpintPlot::plot_allCurve(CpintPlot *thisPlot,
                         int n_values,
                         const double *power_values)
{
    clear_CP_Curves();

    QVector<double> energyBests(n_values);
    QVector<double> time_values(n_values);
    // generate an array of time values
    for (int t = 0; t < n_values; t++) {
        time_values[t] = (t + 1) / 60.0;
        energyBests[t] = power_values[t] * time_values[t] * 60.0 / 1000.0;
    }

    // generate zones from derived CP value
    if (cp > 0) {
        QList <int> power_zone;
        int n_zones = zones->lowsFromCP(&power_zone, (int) int(cp));
        int high = n_values - 1;
        int zone = 0;
        while (zone < n_zones && high > 0) {
            int low = high - 1;
            int nextZone = zone + 1;
            if (nextZone >= power_zone.size())
                low = 0;
            else {
                while ((low > 0) && (power_values[low] < power_zone[nextZone]))
                    --low;
            }

            QColor color = zoneColor(zone, n_zones);
            QString name = zones->getDefaultZoneName(zone);
            QwtPlotCurve *curve = new QwtPlotCurve(name);
            if (appsettings->value(this, GC_ANTIALIAS, false).toBool() == true)
                curve->setRenderHint(QwtPlotItem::RenderAntialiased);
            QPen pen(color.darker(200));
            pen.setWidth(appsettings->value(this, GC_LINEWIDTH, 2.0).toDouble());
            curve->setPen(pen);
            curve->attach(thisPlot);

            // use a linear gradient
            color.setAlpha(180);
            QColor color1 = color;
            color1.setAlpha(64);
            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

            if (series == RideFile::none) { // this is Energy mode 
                curve->setData(time_values.data() + low,
                               energyBests.data() + low, high - low + 1);
            } else {
                curve->setData(time_values.data() + low,
                               power_values + low, high - low + 1);
            }
            allCurves.append(curve);

            if (series != RideFile::none || energyBests[high] > 100.0) {
                QwtText text(name);
                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;
                if (series == RideFile::none) {
                    x = (time_values[low] + time_values[high]) / 2;
                    y = (energyBests[low] + energyBests[high]) / 5;
                }
                else {
                    x = sqrt(time_values[low] * time_values[high]);
                    y = (power_values[low] + power_values[high]) / 5;
                }
                label_mark->setValue(x, y);
                label_mark->setLabel(text);
                label_mark->attach(thisPlot);
                allZoneLabels.append(label_mark);
            }

            high = low;
            ++zone;
        }
    }
    // no zones available: just plot the curve without zones
    else {
        QwtPlotCurve *curve = new QwtPlotCurve(tr("maximal power"));
        if (appsettings->value(this, GC_ANTIALIAS, false).toBool() == true)
            curve->setRenderHint(QwtPlotItem::RenderAntialiased);
        QPen pen(GColor(CCP));
        pen.setWidth(appsettings->value(this, GC_LINEWIDTH, 2.0).toDouble());
        curve->setPen(pen);
        QColor brush_color = GColor(CCP);
        brush_color.setAlpha(200);
        curve->setBrush(brush_color);   // brush fills below the line
        if (series == RideFile::none)
            curve->setData(time_values.data(), energyBests.data(), n_values);
        else
            curve->setData(time_values.data(), power_values, n_values);
        curve->attach(thisPlot);
        allCurves.append(curve);
    }

    // Energy mode is really only interesting in the range where energy is
    // linear in interval duration--up to about 1 hour.
    double xmax = (series == RideFile::none)  ? 60.0 : time_values[n_values - 1];

    if (series == RideFile::vam)
        thisPlot->setAxisScale(thisPlot->xBottom, (double) 4.993, (double)xmax);
    else
        thisPlot->setAxisScale(thisPlot->xBottom, (double) 0.017, (double)xmax);

    double ymax;
    if (series == RideFile::none) {
        int i = std::lower_bound(time_values.begin(), time_values.end(), 60.0) - time_values.begin();
        ymax = 10 * ceil(energyBests[i] / 10);
    }
    else {
        ymax = 100 * ceil(power_values[0] / 100);
        if (ymax == 100)
            ymax = 5 * ceil(power_values[0] / 5);
    }
    thisPlot->setAxisScale(thisPlot->yLeft, 0, ymax);
}
void
PfPvPlot::refreshZoneItems()
{
    // clear out any zone curves which are presently defined
    if (zoneCurves.size()) {

        QListIterator<QwtPlotCurve *> i(zoneCurves);
        while (i.hasNext()) {
            QwtPlotCurve *curve = i.next();
            curve->detach();
            delete curve;
        }
    }
    zoneCurves.clear();

    // delete any existing power zone labels
    if (zoneLabels.size()) {

        QListIterator<PfPvPlotZoneLabel *> i(zoneLabels);
        while (i.hasNext()) {
            PfPvPlotZoneLabel *label = i.next();
            label->detach();
            delete label;
        }
    }
    zoneLabels.clear();

    // give up for a null ride
    if (! rideItem) return;

    const Zones *zones = rideItem->zones;
    int zone_range = rideItem->zoneRange();

    if (zone_range >= 0) {
        setCP(zones->getCP(zone_range));

        // populate the zone curves
        QList <int> zone_power = zones->getZoneLows(zone_range);
        QList <QString> zone_name = zones->getZoneNames(zone_range);
        int num_zones = zone_power.size();
        assert(zone_name.size() == num_zones);

        if (num_zones > 0) {
            QPen *pen = new QPen();
            pen->setStyle(Qt::NoPen);

            QwtArray<double> yvalues;

            // generate x values
            for (int z = 0; z < num_zones; z ++) {

                QwtPlotCurve *curve = new QwtPlotCurve(zone_name[z]);

                curve->setPen(*pen);
                QColor brush_color = zoneColor(z, num_zones);
                brush_color.setHsv(brush_color.hue(), brush_color.saturation() / 4, brush_color.value());
                curve->setBrush(brush_color);   // fill below the line
                curve->setZ(1 - 1e-6 * zone_power[z]);

                // generate data for curve
                if (z < num_zones - 1) {
                    QwtArray <double> contour_yvalues;
                    int watts = zone_power[z + 1];
                    int dwatts = (double) watts;
                    for (int i = 0; i < contour_xvalues.size(); i ++) {
                        contour_yvalues.append( (1e6 * contour_xvalues[i] < watts) ?  1e6 : dwatts / contour_xvalues[i]);
                    }
                    curve->setData(contour_xvalues, contour_yvalues);

                } else {

                    // top zone has a curve at "infinite" power
                    QwtArray <double> contour_x;
                    QwtArray <double> contour_y;
                    contour_x.append(contour_xvalues[0]);
                    contour_x.append(contour_xvalues[contour_xvalues.size() - 1]);
                    contour_y.append(1e6);
                    contour_y.append(1e6);
                    curve->setData(contour_x, contour_y);
                }

                curve->setVisible(shade_zones);
                curve->attach(this);
                zoneCurves.append(curve);
            }

            delete pen;

            // generate labels for existing zones
            for (int z = 0; z < num_zones; z ++) {
                PfPvPlotZoneLabel *label = new PfPvPlotZoneLabel(this, z);
                label->setVisible(shade_zones);
                label->attach(this);
                zoneLabels.append(label);
            }
        }
    }
}