Esempio n. 1
0
void
PowerHist::recalc()
{
    QVector<unsigned int> *array;
    QVector<unsigned int> *selectedArray;
    int arrayLength = 0;
    double delta;

    // make sure the interval length is set
    if (dt <= 0)
	return;

    if (selected == watts) {
	array = &wattsArray;
	delta = wattsDelta;
	arrayLength = wattsArray.size();
	selectedArray = &wattsSelectedArray;
    }
    else if (selected == wattsZone) {
	array = &wattsZoneArray;
	delta = 1;
	arrayLength = wattsZoneArray.size();
	selectedArray = &wattsZoneSelectedArray;
    }
    else if (selected == nm) {
	array = &nmArray;
	delta = nmDelta;
	arrayLength = nmArray.size();
	selectedArray = &nmSelectedArray;
    }
    else if (selected == hr) {
	array = &hrArray;
	delta = hrDelta;
	arrayLength = hrArray.size();
	selectedArray = &hrSelectedArray;
    }
    else if (selected == hrZone) {
	array = &hrZoneArray;
	delta = 1;
	arrayLength = hrZoneArray.size();
	selectedArray = &hrZoneSelectedArray;
    }
    else if (selected == kph) {
	array = &kphArray;
	delta = kphDelta;
	arrayLength = kphArray.size();
	selectedArray = &kphSelectedArray;
    }
    else if (selected == cad) {
	array = &cadArray;
	delta = cadDelta;
	arrayLength = cadArray.size();
	selectedArray = &cadSelectedArray;
    }

    if (!array)
        return;

    // binning of data when not zoned
    if (selected != wattsZone && selected != hrZone) {

        // we add a bin on the end since the last "incomplete" bin
        // will be dropped otherwise
        int count = int(ceil((arrayLength - 1) / binw))+1;

        // allocate space for data, plus beginning and ending point
        QVector<double> parameterValue(count+2, 0.0);
        QVector<double> totalTime(count+2, 0.0);
        QVector<double> totalTimeSelected(count+2, 0.0);
        int i;
        for (i = 1; i <= count; ++i) {
            int high = i * binw;
            int low = high - binw;
            if (low==0 && !withz)
                low++;
            parameterValue[i] = high * delta;
            totalTime[i]  = 1e-9;  // nonzero to accomodate log plot
            totalTimeSelected[i] = 1e-9;  // nonzero to accomodate log plot
            while (low < high && low<arrayLength) {
                if (selectedArray && (*selectedArray).size()>low)
                    totalTimeSelected[i] += dt * (*selectedArray)[low];
                totalTime[i] += dt * (*array)[low++];
            }
        }
        totalTime[i] = 1e-9;       // nonzero to accomodate log plot
        parameterValue[i] = i * delta * binw;
        totalTime[0] = 1e-9;
        parameterValue[0] = 0;

        // convert vectors from absolute time to percentage
        // if the user has selected that
        if (!absolutetime) {
            percentify(totalTime, 1);
            percentify(totalTimeSelected, 1);
        }

        curve->setData(parameterValue.data(), totalTime.data(), count + 2);
        curveSelected->setData(parameterValue.data(), totalTimeSelected.data(), count + 2);

        // make see through if we're shading zones
        QBrush brush = curve->brush();
        QColor bcol = brush.color();
        bool zoning = (selected == watts && shadeZones()) || (selected == hr && shadeHRZones());
        bcol.setAlpha(zoning ? 165 : 200);
        brush.setColor(bcol);
        curve->setBrush(brush);

        setAxisScaleDraw(QwtPlot::xBottom, new QwtScaleDraw);

        // HR typically starts at 80 or so, rather than zero
        // lets crop the chart so we can focus on the data
        // if we're working with HR data...
        if (selected == hr) {
            double MinX=0;
            for (int i=0; i<hrArray.size(); i++) {
                if (hrArray[i] > 0) {
                    MinX = i;
                    break;
                }
            }
            setAxisScale(xBottom, MinX, parameterValue[count + 1]);

        } else {

            setAxisScale(xBottom, 0.0, parameterValue[count + 1]);
        }

        // we only do zone labels when using absolute values
        refreshZoneLabels();
        refreshHRZoneLabels();

    } else {

        // we're not binning instead we are prettyfing the columnar
        // display in much the same way as the weekly summary workds
        // Each zone column will have 4 points
        QVector<double> xaxis (array->size() * 4);
        QVector<double> yaxis (array->size() * 4);
        QVector<double> selectedxaxis (selectedArray->size() * 4);
        QVector<double> selectedyaxis (selectedArray->size() * 4);

        // samples to time
        for (int i=0, offset=0; i<array->size(); i++) {

            double x = (double) i - 0.5;
            double y = dt * (double)(*array)[i];

            xaxis[offset] = x +0.05;
            yaxis[offset] = 0;
            offset++;
            xaxis[offset] = x+0.05;
            yaxis[offset] = y;
            offset++;
            xaxis[offset] = x+0.95;
            yaxis[offset] = y;
            offset++;
            xaxis[offset] = x +0.95;
            yaxis[offset] = 0;
            offset++;
        }

        for (int i=0, offset=0; i<selectedArray->size(); i++) {
            double x = (double)i - 0.5;
            double y = dt * (double)(*selectedArray)[i];

            selectedxaxis[offset] = x +0.05;
            selectedyaxis[offset] = 0;
            offset++;
            selectedxaxis[offset] = x+0.05;
            selectedyaxis[offset] = y;
            offset++;
            selectedxaxis[offset] = x+0.95;
            selectedyaxis[offset] = y;
            offset++;
            selectedxaxis[offset] = x +0.95;
            selectedyaxis[offset] = 0;
            offset++;
        }

        if (!absolutetime) {
            percentify(yaxis, 2);
            percentify(selectedyaxis, 2);
        }
        // set those curves
        curve->setData(xaxis.data(), yaxis.data(), xaxis.size());

        // Opaque - we don't need to show zone shading
        QBrush brush = curve->brush();
        QColor bcol = brush.color();
        bcol.setAlpha(200);
        brush.setColor(bcol);
        curve->setBrush(brush);

        curveSelected->setData(selectedxaxis.data(), selectedyaxis.data(), selectedxaxis.size());

        // zone scale draw
        if (selected == wattsZone && rideItem && rideItem->zones) {
            setAxisScaleDraw(QwtPlot::xBottom, new ZoneScaleDraw(rideItem->zones, rideItem->zoneRange()));
            setAxisScale(QwtPlot::xBottom, -0.99, rideItem->zones->numZones(rideItem->zoneRange()), 1);
        }

        // hr scale draw
        int hrRange;
        if (selected == hrZone && rideItem && mainWindow->hrZones() &&
            (hrRange=mainWindow->hrZones()->whichRange(rideItem->dateTime.date())) != -1) {
            setAxisScaleDraw(QwtPlot::xBottom, new HrZoneScaleDraw(mainWindow->hrZones(), hrRange));
            setAxisScale(QwtPlot::xBottom, -0.99, mainWindow->hrZones()->numZones(hrRange), 1);
        }

        setAxisMaxMinor(QwtPlot::xBottom, 0);
    }

    setYMax();
    replot();
}
Esempio n. 2
0
void
PowerHist::recalc(bool force)
{
    QVector<unsigned int> *array = NULL;
    QVector<unsigned int> *selectedArray = NULL;
    int arrayLength = 0;

    // lets make sure we need to recalculate
    if (force == false &&
        LASTsource == source &&
        LASTcache == cache &&
        LASTrideItem == rideItem &&
        LASTseries == series &&
        LASTshade == shade &&
        LASTuseMetricUnits == context->athlete->useMetricUnits &&
        LASTlny == lny &&
        LASTzoned == zoned &&
        LASTbinw == binw &&
        LASTwithz == withz &&
        LASTdt == dt &&
        LASTabsolutetime == absolutetime) {
        return; // nothing has changed

    } else {

        // remember for next time
        LASTsource = source;
        LASTcache = cache;
        LASTrideItem = rideItem;
        LASTseries = series;
        LASTshade = shade;
        LASTuseMetricUnits = context->athlete->useMetricUnits;
        LASTlny = lny;
        LASTzoned = zoned;
        LASTbinw = binw;
        LASTwithz = withz;
        LASTdt = dt;
        LASTabsolutetime = absolutetime;
    }


    if (source == Ride && !rideItem) return;

    // make sure the interval length is set if not plotting metrics
    if (source != Metric && dt <= 0) return;

    if (source == Metric) {

        // we use the metricArray
        array = &metricArray;
        arrayLength = metricArray.size();
        selectedArray = NULL;

    } else if (series == RideFile::watts && zoned == false) {

        array = &wattsArray;
        arrayLength = wattsArray.size();
        selectedArray = &wattsSelectedArray;

    } else if ((series == RideFile::watts || series == RideFile::wattsKg) && zoned == true) {

        array = &wattsZoneArray;
        arrayLength = wattsZoneArray.size();
        selectedArray = &wattsZoneSelectedArray;

    } else if (series == RideFile::aPower && zoned == false) {

        array = &aPowerArray;
        arrayLength = aPowerArray.size();
        selectedArray = &aPowerSelectedArray;

    } else if (series == RideFile::wattsKg && zoned == false) {

        array = &wattsKgArray;
        arrayLength = wattsKgArray.size();
        selectedArray = &wattsKgSelectedArray;

    } else if (series == RideFile::nm) {

        array = &nmArray;
        arrayLength = nmArray.size();
        selectedArray = &nmSelectedArray;

    } else if (series == RideFile::hr && zoned == false) {

        array = &hrArray;
        arrayLength = hrArray.size();
        selectedArray = &hrSelectedArray;

    } else if (series == RideFile::hr && zoned == true) {

        array = &hrZoneArray;
        arrayLength = hrZoneArray.size();
        selectedArray = &hrZoneSelectedArray;

    } else if (series == RideFile::kph) {

        array = &kphArray;
        arrayLength = kphArray.size();
        selectedArray = &kphSelectedArray;

    } else if (series == RideFile::cad) {
        array = &cadArray;
        arrayLength = cadArray.size();
        selectedArray = &cadSelectedArray;
    }

    RideFile::SeriesType baseSeries = (series == RideFile::wattsKg) ? RideFile::watts : series;

    // null curve please -- we have no data!
    if (!array || arrayLength == 0 || (source == Ride && !rideItem->ride()->isDataPresent(baseSeries))) {
        // create empty curves when no data
        const double zero = 0;
        curve->setData(&zero, &zero, 0);
        curveSelected->setData(&zero, &zero, 0);
        updatePlot();
        return;
    }

    // binning of data when not zoned - we can't zone for series besides
    // watts and hr so ignore zoning for those data series
    if (zoned == false || (zoned == true && (series != RideFile::watts && series != RideFile::wattsKg && series != RideFile::hr))) {

        // we add a bin on the end since the last "incomplete" bin
        // will be dropped otherwise
        int count = int(ceil((arrayLength - 1) / (binw)))+1;

        // allocate space for data, plus beginning and ending point
        QVector<double> parameterValue(count+2, 0.0);
        QVector<double> totalTime(count+2, 0.0);
        QVector<double> totalTimeSelected(count+2, 0.0);
        int i;
        for (i = 1; i <= count; ++i) {
            double high = i * round(binw/delta);
            double low = high - round(binw/delta);
            if (low==0 && !withz) low++;
            parameterValue[i] = high*delta;
            totalTime[i]  = 1e-9;  // nonzero to accomodate log plot
            totalTimeSelected[i] = 1e-9;  // nonzero to accomodate log plot
            while (low < high && low<arrayLength) {
                if (selectedArray && (*selectedArray).size()>low)
                    totalTimeSelected[i] += dt * (*selectedArray)[low];
                totalTime[i] += dt * (*array)[low++];
            }
        }
        totalTime[i] = 1e-9;       // nonzero to accomodate log plot
        totalTimeSelected[i] = 1e-9;       // nonzero to accomodate log plot
        parameterValue[i] = i * delta * binw;
        totalTime[0] = 1e-9;
        totalTimeSelected[0] = 1e-9;
        parameterValue[0] = 0;

        // convert vectors from absolute time to percentage
        // if the user has selected that
        if (!absolutetime) {
            percentify(totalTime, 1);
            percentify(totalTimeSelected, 1);
        }

        curve->setData(parameterValue.data(), totalTime.data(), count + 2);
        curveSelected->setData(parameterValue.data(), totalTimeSelected.data(), count + 2);

        QwtScaleDraw *sd = new QwtScaleDraw;
        sd->setTickLength(QwtScaleDiv::MajorTick, 3);
        setAxisScaleDraw(QwtPlot::xBottom, sd);

        // HR typically starts at 80 or so, rather than zero
        // lets crop the chart so we can focus on the data
        // if we're working with HR data...
        minX=0;
        if (!withz && series == RideFile::hr) {
            for (int i=1; i<hrArray.size(); i++) {
                if (hrArray[i] > 0.1) {
                    minX = i;
                    break;
                }
            }
        }
        setAxisScale(xBottom, minX, parameterValue[count + 1]);

        // we only do zone labels when using absolute values
        refreshZoneLabels();
        refreshHRZoneLabels();

    } else {

        // we're not binning instead we are prettyfing the columnar
        // display in much the same way as the weekly summary workds
        // Each zone column will have 4 points
        QVector<double> xaxis (array->size() * 4);
        QVector<double> yaxis (array->size() * 4);
        QVector<double> selectedxaxis (selectedArray->size() * 4);
        QVector<double> selectedyaxis (selectedArray->size() * 4);

        // samples to time
        for (int i=0, offset=0; i<array->size(); i++) {

            double x = (double) i - 0.5;
            double y = dt * (double)(*array)[i];

            xaxis[offset] = x +0.05;
            yaxis[offset] = 0;
            offset++;
            xaxis[offset] = x+0.05;
            yaxis[offset] = y;
            offset++;
            xaxis[offset] = x+0.95;
            yaxis[offset] = y;
            offset++;
            xaxis[offset] = x +0.95;
            yaxis[offset] = 0;
            offset++;
        }

        for (int i=0, offset=0; i<selectedArray->size(); i++) {
            double x = (double)i - 0.5;
            double y = dt * (double)(*selectedArray)[i];

            selectedxaxis[offset] = x +0.05;
            selectedyaxis[offset] = 0;
            offset++;
            selectedxaxis[offset] = x+0.05;
            selectedyaxis[offset] = y;
            offset++;
            selectedxaxis[offset] = x+0.95;
            selectedyaxis[offset] = y;
            offset++;
            selectedxaxis[offset] = x +0.95;
            selectedyaxis[offset] = 0;
            offset++;
        }

        if (!absolutetime) {
            percentify(yaxis, 2);
            percentify(selectedyaxis, 2);
        }

        // set those curves
        curve->setData(xaxis.data(), yaxis.data(), xaxis.size());
        curveSelected->setData(selectedxaxis.data(), selectedyaxis.data(), selectedxaxis.size());

        // zone scale draw
        if ((series == RideFile::watts || series == RideFile::wattsKg) && zoned && rideItem && rideItem->zones) {
            setAxisScaleDraw(QwtPlot::xBottom, new ZoneScaleDraw(rideItem->zones, rideItem->zoneRange()));
            if (rideItem->zoneRange() >= 0)
                setAxisScale(QwtPlot::xBottom, -0.99, rideItem->zones->numZones(rideItem->zoneRange()), 1);
            else
                setAxisScale(QwtPlot::xBottom, -0.99, 0, 1);
        }

        // hr scale draw
        int hrRange;
        if (series == RideFile::hr && zoned && rideItem && context->athlete->hrZones() &&
            (hrRange=context->athlete->hrZones()->whichRange(rideItem->dateTime.date())) != -1) {
            setAxisScaleDraw(QwtPlot::xBottom, new HrZoneScaleDraw(context->athlete->hrZones(), hrRange));

            if (hrRange >= 0)
                setAxisScale(QwtPlot::xBottom, -0.99, context->athlete->hrZones()->numZones(hrRange), 1);
            else
                setAxisScale(QwtPlot::xBottom, -0.99, 0, 1);
        }

        // watts zoned for a time range
        if (source == Cache && zoned && (series == RideFile::watts || series == RideFile::wattsKg) && context->athlete->zones()) {
            setAxisScaleDraw(QwtPlot::xBottom, new ZoneScaleDraw(context->athlete->zones(), 0));
            if (context->athlete->zones()->getRangeSize())
                setAxisScale(QwtPlot::xBottom, -0.99, context->athlete->zones()->numZones(0), 1); // use zones from first defined range
        }

        // hr zoned for a time range
        if (source == Cache && zoned && series == RideFile::hr && context->athlete->hrZones()) {
            setAxisScaleDraw(QwtPlot::xBottom, new HrZoneScaleDraw(context->athlete->hrZones(), 0));
            if (context->athlete->hrZones()->getRangeSize())
                setAxisScale(QwtPlot::xBottom, -0.99, context->athlete->hrZones()->numZones(0), 1); // use zones from first defined range
        }

        setAxisMaxMinor(QwtPlot::xBottom, 0);
    }

    setYMax();
    configChanged(); // setup the curve colors to appropriate values
    updatePlot();
}