~ubuntu-branches/ubuntu/saucy/goldencheetah/saucy

« back to all changes in this revision

Viewing changes to src/AllPlot.cpp

  • Committer: Package Import Robot
  • Author(s): KURASHIKI Satoru
  • Date: 2013-08-18 07:02:45 UTC
  • mfrom: (4.1.8 sid)
  • Revision ID: package-import@ubuntu.com-20130818070245-zgdvb47e1k3mtgil
Tags: 3.0-3
debian/control: remove needless dependency. (Closes: #719571)

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
 
30
30
#include <assert.h>
31
31
#include <qwt_plot_curve.h>
 
32
#include <qwt_plot_intervalcurve.h>
32
33
#include <qwt_plot_grid.h>
33
34
#include <qwt_plot_layout.h>
34
35
#include <qwt_plot_marker.h>
 
36
#include <qwt_scale_div.h>
 
37
#include <qwt_scale_widget.h>
 
38
#include <qwt_compat.h>
35
39
#include <qwt_text.h>
36
40
#include <qwt_legend.h>
37
 
#include <qwt_data.h>
 
41
#include <qwt_series_data.h>
38
42
#include <QMultiMap>
39
43
 
40
 
class IntervalPlotData : public QwtData
 
44
class IntervalPlotData : public QwtSeriesData<QPointF>
41
45
{
42
46
    public:
43
47
    IntervalPlotData(AllPlot *allPlot, MainWindow *mainWindow) :
45
49
    double x(size_t i) const ;
46
50
    double y(size_t i) const ;
47
51
    size_t size() const ;
48
 
    virtual QwtData *copy() const ;
 
52
    //virtual QwtData *copy() const ;
49
53
    void init() ;
50
54
    IntervalItem *intervalNum(int n) const;
51
55
    int intervalCount() const;
52
56
    AllPlot *allPlot;
53
57
    MainWindow *mainWindow;
 
58
 
 
59
    virtual QPointF sample(size_t i) const;
 
60
    virtual QRectF boundingRect() const;
54
61
};
55
62
 
56
63
// define a background class to handle shading of power zones
75
82
 
76
83
    virtual void draw(QPainter *painter,
77
84
                      const QwtScaleMap &, const QwtScaleMap &yMap,
78
 
                      const QRect &rect) const
 
85
                      const QRectF &rect) const
79
86
    {
80
87
        RideItem *rideItem = parent->rideItem;
81
88
 
89
96
            int num_zones = zone_lows.size();
90
97
            if (num_zones > 0) {
91
98
                for (int z = 0; z < num_zones; z ++) {
92
 
                    QRect r = rect;
 
99
                    QRect r = rect.toRect();
93
100
 
94
101
                    QColor shading_color = zoneColor(z, num_zones);
95
102
                    shading_color.setHsv(
175
182
 
176
183
        void draw(QPainter *painter,
177
184
                  const QwtScaleMap &, const QwtScaleMap &yMap,
178
 
                  const QRect &rect) const
 
185
                  const QRectF &rect) const
179
186
        {
180
187
            if (parent->shadeZones()) {
181
188
                int x = (rect.left() + rect.right()) / 2;
182
189
                int y = yMap.transform(watts);
183
190
 
184
191
                // the following code based on source for QwtPlotMarker::draw()
185
 
                QRect tr(QPoint(0, 0), text.textSize(painter->font()));
 
192
                QRect tr(QPoint(0, 0), text.textSize(painter->font()).toSize());
186
193
                tr.moveCenter(QPoint(x, y));
187
194
                text.draw(painter, tr);
188
195
            }
189
196
        }
190
197
};
191
198
 
 
199
class TimeScaleDraw: public QwtScaleDraw
 
200
{
 
201
 
 
202
    public:
 
203
 
 
204
    TimeScaleDraw(bool *bydist) : QwtScaleDraw(), bydist(bydist) {}
 
205
 
 
206
    virtual QwtText label(double v) const
 
207
    {
 
208
        if (*bydist) {
 
209
            return QString("%1").arg(v);
 
210
        } else {
 
211
            QTime t = QTime().addSecs(v*60.00);
 
212
            if (scaleMap().sDist() > 5)
 
213
                return t.toString("hh:mm");
 
214
            return t.toString("hh:mm:ss");
 
215
        }
 
216
    }
 
217
    private:
 
218
    bool *bydist;
 
219
 
 
220
};
 
221
 
192
222
 
193
223
static inline double
194
224
max(double a, double b) { if (a > b) return a; else return b; }
196
226
AllPlot::AllPlot(AllPlotWindow *parent, MainWindow *mainWindow):
197
227
    QwtPlot(parent),
198
228
    rideItem(NULL),
199
 
    unit(0),
200
229
    shade_zones(true),
201
230
    showPowerState(3),
202
 
    showHrState(Qt::Checked),
203
 
    showSpeedState(Qt::Checked),
204
 
    showCadState(Qt::Checked),
205
 
    showAltState(Qt::Checked),
 
231
    showHr(true),
 
232
    showSpeed(true),
 
233
    showCad(true),
 
234
    showAlt(true),
 
235
    showTemp(true),
 
236
    showWind(true),
 
237
    showTorque(true),
 
238
    showBalance(true),
206
239
    bydist(false),
 
240
    mainWindow(mainWindow),
207
241
    parent(parent)
208
242
{
209
 
    boost::shared_ptr<QSettings> settings = GetApplicationSettings();
210
 
    unit = settings->value(GC_UNIT);
 
243
    setInstanceName("AllPlot");
211
244
 
212
245
    referencePlot = NULL;
213
246
 
214
 
    useMetricUnits = (unit.toString() == "Metric");
215
 
 
216
 
    // options for turning off/on shading on all plot
217
 
    // will come in with a future patch, for now we
218
 
    // enable zone shading by default, since this is
219
 
    // the current default behaviour
220
 
    if (false) shade_zones = false;
221
 
    else shade_zones = true;
222
 
 
223
 
    smooth = settings->value(GC_RIDE_PLOT_SMOOTHING).toInt();
224
 
    if (smooth < 1) smooth = 1;
 
247
    useMetricUnits = mainWindow->useMetricUnits;
 
248
 
 
249
    if (appsettings->value(this, GC_SHADEZONES, true).toBool()==false)
 
250
        shade_zones = false;
 
251
 
 
252
    smooth = 1;
225
253
 
226
254
    // create a background object for shading
227
255
    bg = new AllPlotBackground(this);
228
256
    bg->attach(this);
229
257
 
230
 
    insertLegend(new QwtLegend(), QwtPlot::BottomLegend);
231
 
    setCanvasBackground(GColor(CPLOTBACKGROUND));
 
258
    //insertLegend(new QwtLegend(), QwtPlot::BottomLegend);
 
259
    setCanvasBackground(GColor(CRIDEPLOTBACKGROUND));
 
260
    canvas()->setFrameStyle(QFrame::NoFrame);
232
261
 
233
262
    setXTitle();
234
263
 
235
264
    wattsCurve = new QwtPlotCurve(tr("Power"));
 
265
    wattsCurve->setYAxis(yLeft);
236
266
 
237
267
    hrCurve = new QwtPlotCurve(tr("Heart Rate"));
238
268
    hrCurve->setYAxis(yLeft2);
247
277
    // altCurve->setRenderHint(QwtPlotItem::RenderAntialiased);
248
278
    altCurve->setYAxis(yRight2);
249
279
 
 
280
    tempCurve = new QwtPlotCurve(tr("Temperature"));
 
281
    if (useMetricUnits)
 
282
        tempCurve->setYAxis(yRight); // with speed
 
283
    else
 
284
        tempCurve->setYAxis(yLeft2); // with cadence
 
285
 
 
286
    windCurve = new QwtPlotIntervalCurve(tr("Wind"));
 
287
    windCurve->setYAxis(yRight);
 
288
 
 
289
    torqueCurve = new QwtPlotCurve(tr("Torque"));
 
290
    torqueCurve->setYAxis(yRight);
 
291
 
 
292
    balanceLCurve = new QwtPlotCurve(tr("Left Balance"));
 
293
    balanceLCurve->setYAxis(yLeft2);
 
294
 
 
295
    balanceRCurve = new QwtPlotCurve(tr("Right Balance"));
 
296
    balanceRCurve->setYAxis(yLeft2);
 
297
 
250
298
    intervalHighlighterCurve = new QwtPlotCurve();
251
299
    intervalHighlighterCurve->setYAxis(yLeft);
252
 
    intervalHighlighterCurve->setData(IntervalPlotData(this, mainWindow));
 
300
    intervalHighlighterCurve->setData(new IntervalPlotData(this, mainWindow));
253
301
    intervalHighlighterCurve->attach(this);
254
 
    this->legend()->remove(intervalHighlighterCurve); // don't show in legend
 
302
    //this->legend()->remove(intervalHighlighterCurve); // don't show in legend
255
303
 
 
304
    // setup that grid
256
305
    grid = new QwtPlotGrid();
257
 
    grid->enableX(false);
 
306
    grid->enableX(true);
 
307
    grid->enableY(true);
258
308
    grid->attach(this);
259
309
 
260
310
    // get rid of nasty blank space on right of the plot
261
311
    plotLayout()->setAlignCanvasToScales(true);
 
312
    setAxisMaxMinor(xBottom, 0);
 
313
    setAxisMaxMinor(yLeft, 0);
 
314
    setAxisMaxMinor(yLeft2, 0);
 
315
    setAxisMaxMinor(yRight, 0);
 
316
    setAxisMaxMinor(yRight2, 0);
262
317
 
263
318
    configChanged(); // set colors
264
319
}
266
321
void
267
322
AllPlot::configChanged()
268
323
{
269
 
 
270
 
    double width = 1.0;
271
 
 
272
 
    boost::shared_ptr<QSettings> settings = GetApplicationSettings();
273
 
    useMetricUnits = (settings->value(GC_UNIT).toString() == "Metric");
274
 
 
275
 
    // placeholder for setting antialiasing, will come
276
 
    // in with a future patch. For now antialiasing is
277
 
    // not enabled since it can slow down plotting on
278
 
    // windows and linux platforms.
279
 
    if (false) {
 
324
    useMetricUnits = mainWindow->useMetricUnits;
 
325
    double width = appsettings->value(this, GC_LINEWIDTH, 2.0).toDouble();
 
326
 
 
327
    if (appsettings->value(this, GC_ANTIALIAS, false).toBool() == true) {
280
328
        wattsCurve->setRenderHint(QwtPlotItem::RenderAntialiased);
281
329
        hrCurve->setRenderHint(QwtPlotItem::RenderAntialiased);
282
330
        speedCurve->setRenderHint(QwtPlotItem::RenderAntialiased);
283
331
        cadCurve->setRenderHint(QwtPlotItem::RenderAntialiased);
284
332
        altCurve->setRenderHint(QwtPlotItem::RenderAntialiased);
 
333
        tempCurve->setRenderHint(QwtPlotItem::RenderAntialiased);
 
334
        windCurve->setRenderHint(QwtPlotItem::RenderAntialiased);
 
335
        torqueCurve->setRenderHint(QwtPlotItem::RenderAntialiased);
 
336
        balanceLCurve->setRenderHint(QwtPlotItem::RenderAntialiased);
 
337
        balanceRCurve->setRenderHint(QwtPlotItem::RenderAntialiased);
285
338
        intervalHighlighterCurve->setRenderHint(QwtPlotItem::RenderAntialiased);
286
339
    }
287
340
 
288
 
    setCanvasBackground(GColor(CPLOTBACKGROUND));
 
341
    setCanvasBackground(GColor(CRIDEPLOTBACKGROUND));
289
342
    QPen wattsPen = QPen(GColor(CPOWER));
290
343
    wattsPen.setWidth(width);
291
344
    wattsCurve->setPen(wattsPen);
304
357
    QColor brush_color = GColor(CALTITUDEBRUSH);
305
358
    brush_color.setAlpha(200);
306
359
    altCurve->setBrush(brush_color);   // fill below the line
 
360
    QPen tempPen = QPen(GColor(CTEMP));
 
361
    tempPen.setWidth(width);
 
362
    tempCurve->setPen(tempPen);
 
363
    if (smooth == 1)
 
364
        tempCurve->setStyle(QwtPlotCurve::Dots);
 
365
    else
 
366
        tempCurve->setStyle(QwtPlotCurve::Lines);
 
367
    //QPen windPen = QPen(GColor(CWINDSPEED));
 
368
    //windPen.setWidth(width);
 
369
    windCurve->setPen(Qt::NoPen);
 
370
    QColor wbrush_color = GColor(CWINDSPEED);
 
371
    wbrush_color.setAlpha(200);
 
372
    windCurve->setBrush(wbrush_color);   // fill below the line
 
373
    QPen torquePen = QPen(GColor(CTORQUE));
 
374
    torquePen.setWidth(width);
 
375
    torqueCurve->setPen(torquePen);
 
376
    QPen balanceLPen = QPen(GColor(CBALANCERIGHT));
 
377
    balanceLPen.setWidth(width);
 
378
    balanceLCurve->setPen(balanceLPen);
 
379
    QColor brbrush_color = GColor(CBALANCERIGHT);
 
380
    brbrush_color.setAlpha(200);
 
381
    balanceLCurve->setBrush(brbrush_color);   // fill below the line
 
382
    QPen balanceRPen = QPen(GColor(CBALANCELEFT));
 
383
    balanceRPen.setWidth(width);
 
384
    balanceRCurve->setPen(balanceRPen);
 
385
    QColor blbrush_color = GColor(CBALANCELEFT);
 
386
    blbrush_color.setAlpha(200);
 
387
    balanceRCurve->setBrush(blbrush_color);   // fill below the line
 
388
 
307
389
    QPen ihlPen = QPen(GColor(CINTERVALHIGHLIGHTER));
308
390
    ihlPen.setWidth(width);
309
391
    intervalHighlighterCurve->setPen(ihlPen);
310
392
    QColor ihlbrush = QColor(GColor(CINTERVALHIGHLIGHTER));
311
 
    ihlbrush.setAlpha(64);
 
393
    ihlbrush.setAlpha(128);
312
394
    intervalHighlighterCurve->setBrush(ihlbrush);   // fill below the line
313
 
    this->legend()->remove(intervalHighlighterCurve); // don't show in legend
 
395
    //this->legend()->remove(intervalHighlighterCurve); // don't show in legend
314
396
    QPen gridPen(GColor(CPLOTGRID));
315
397
    gridPen.setStyle(Qt::DotLine);
316
398
    grid->setPen(gridPen);
 
399
 
 
400
    // curve brushes
 
401
    if (parent->isPaintBrush()) {
 
402
        QColor p;
 
403
        p = wattsCurve->pen().color();
 
404
        p.setAlpha(64);
 
405
        wattsCurve->setBrush(QBrush(p));
 
406
 
 
407
        p = hrCurve->pen().color();
 
408
        p.setAlpha(64);
 
409
        hrCurve->setBrush(QBrush(p));
 
410
 
 
411
        p = speedCurve->pen().color();
 
412
        p.setAlpha(64);
 
413
        speedCurve->setBrush(QBrush(p));
 
414
 
 
415
        p = cadCurve->pen().color();
 
416
        p.setAlpha(64);
 
417
        cadCurve->setBrush(QBrush(p));
 
418
 
 
419
        p = torqueCurve->pen().color();
 
420
        p.setAlpha(64);
 
421
        torqueCurve->setBrush(QBrush(p));
 
422
 
 
423
        /*p = balanceLCurve->pen().color();
 
424
        p.setAlpha(64);
 
425
        balanceLCurve->setBrush(QBrush(p));
 
426
 
 
427
        p = balanceRCurve->pen().color();
 
428
        p.setAlpha(64);
 
429
        balanceRCurve->setBrush(QBrush(p));*/
 
430
    } else {
 
431
        wattsCurve->setBrush(Qt::NoBrush);
 
432
        hrCurve->setBrush(Qt::NoBrush);
 
433
        speedCurve->setBrush(Qt::NoBrush);
 
434
        cadCurve->setBrush(Qt::NoBrush);
 
435
        torqueCurve->setBrush(Qt::NoBrush);
 
436
        //balanceLCurve->setBrush(Qt::NoBrush);
 
437
        //balanceRCurve->setBrush(Qt::NoBrush);
 
438
    }
 
439
 
 
440
    QPalette pal;
 
441
 
 
442
    // tick draw
 
443
    TimeScaleDraw *tsd = new TimeScaleDraw(&this->bydist) ;
 
444
    tsd->setTickLength(QwtScaleDiv::MajorTick, 3);
 
445
    setAxisScaleDraw(QwtPlot::xBottom, tsd);
 
446
 
 
447
    QwtScaleDraw *sd = new QwtScaleDraw;
 
448
    sd->setTickLength(QwtScaleDiv::MajorTick, 3);
 
449
    setAxisScaleDraw(QwtPlot::yLeft, sd);
 
450
    pal.setColor(QPalette::WindowText, GColor(CPOWER));
 
451
    pal.setColor(QPalette::Text, GColor(CPOWER));
 
452
    axisWidget(QwtPlot::yLeft)->setPalette(pal);
 
453
 
 
454
    sd = new QwtScaleDraw;
 
455
    sd->setTickLength(QwtScaleDiv::MajorTick, 3);
 
456
    setAxisScaleDraw(QwtPlot::yLeft2, sd);
 
457
    pal.setColor(QPalette::WindowText, GColor(CHEARTRATE));
 
458
    pal.setColor(QPalette::Text, GColor(CHEARTRATE));
 
459
    axisWidget(QwtPlot::yLeft2)->setPalette(pal);
 
460
 
 
461
    sd = new QwtScaleDraw;
 
462
    sd->setTickLength(QwtScaleDiv::MajorTick, 3);
 
463
    setAxisScaleDraw(QwtPlot::yRight, sd);
 
464
    pal.setColor(QPalette::WindowText, GColor(CSPEED));
 
465
    pal.setColor(QPalette::Text, GColor(CSPEED));
 
466
    axisWidget(QwtPlot::yRight)->setPalette(pal);
 
467
 
 
468
    sd = new QwtScaleDraw;
 
469
    sd->setTickLength(QwtScaleDiv::MajorTick, 3);
 
470
    setAxisScaleDraw(QwtPlot::yRight2, sd);
 
471
    pal.setColor(QPalette::WindowText, GColor(CALTITUDE));
 
472
    pal.setColor(QPalette::Text, GColor(CALTITUDE));
 
473
    axisWidget(QwtPlot::yRight2)->setPalette(pal);
 
474
 
317
475
}
318
476
 
319
477
struct DataPoint {
320
 
    double time, hr, watts, speed, cad, alt;
321
 
    DataPoint(double t, double h, double w, double s, double c, double a) :
322
 
        time(t), hr(h), watts(w), speed(s), cad(c), alt(a) {}
 
478
    double time, hr, watts, speed, cad, alt, temp, wind, torque, lrbalance;
 
479
    DataPoint(double t, double h, double w, double s, double c, double a, double te, double wi, double tq, double lrb) :
 
480
        time(t), hr(h), watts(w), speed(s), cad(c), alt(a), temp(te), wind(wi), torque(tq), lrbalance(lrb) {}
323
481
};
324
482
 
325
483
bool AllPlot::shadeZones() const
327
485
    return shade_zones;
328
486
}
329
487
 
 
488
void
 
489
AllPlot::setAxisTitle(int axis, QString label)
 
490
{
 
491
    // setup the default fonts
 
492
    QFont stGiles; // hoho - Chart Font St. Giles ... ok you have to be British to get this joke
 
493
    stGiles.fromString(appsettings->value(this, GC_FONT_CHARTLABELS, QFont().toString()).toString());
 
494
    stGiles.setPointSize(appsettings->value(NULL, GC_FONT_CHARTLABELS_SIZE, 8).toInt());
 
495
 
 
496
    QwtText title(label);
 
497
    title.setFont(stGiles);
 
498
    QwtPlot::setAxisFont(axis, stGiles);
 
499
    QwtPlot::setAxisTitle(axis, title);
 
500
}
 
501
 
330
502
void AllPlot::refreshZoneLabels()
331
503
{
332
504
    foreach(AllPlotZoneLabel *label, zoneLabels) {
365
537
    int rideTimeSecs = (int) ceil(timeArray[arrayLength - 1]);
366
538
    if (rideTimeSecs > 7*24*60*60) {
367
539
        QwtArray<double> data;
 
540
        QVector<QwtIntervalSample> intData;
 
541
 
368
542
        if (!wattsArray.empty())
369
543
            wattsCurve->setData(data, data);
370
544
        if (!hrArray.empty())
375
549
            cadCurve->setData(data, data);
376
550
        if (!altArray.empty())
377
551
            altCurve->setData(data, data);
 
552
        if (!tempArray.empty())
 
553
            tempCurve->setData(data, data);
 
554
        if (!windArray.empty())
 
555
            windCurve->setData(new QwtIntervalSeriesData(intData));
 
556
        if (!torqueArray.empty())
 
557
            torqueCurve->setData(data, data);
 
558
        if (!balanceArray.empty())
 
559
            balanceLCurve->setData(data, data);
 
560
        if (!balanceArray.empty())
 
561
            balanceRCurve->setData(data, data);
 
562
 
378
563
        return;
379
564
    }
380
 
    double totalWatts = 0.0;
381
 
    double totalHr = 0.0;
382
 
    double totalSpeed = 0.0;
383
 
    double totalCad = 0.0;
384
 
    double totalDist = 0.0;
385
 
    double totalAlt = 0.0;
386
 
 
387
 
    QList<DataPoint> list;
388
 
 
389
 
    smoothWatts.resize(rideTimeSecs + 1); //(rideTimeSecs + 1);
390
 
    smoothHr.resize(rideTimeSecs + 1);
391
 
    smoothSpeed.resize(rideTimeSecs + 1);
392
 
    smoothCad.resize(rideTimeSecs + 1);
393
 
    smoothTime.resize(rideTimeSecs + 1);
394
 
    smoothDistance.resize(rideTimeSecs + 1);
395
 
    smoothAltitude.resize(rideTimeSecs + 1);
396
 
 
397
 
    for (int secs = 0; ((secs < smooth)
398
 
                        && (secs < rideTimeSecs)); ++secs) {
399
 
        smoothWatts[secs] = 0.0;
400
 
        smoothHr[secs]    = 0.0;
401
 
        smoothSpeed[secs] = 0.0;
402
 
        smoothCad[secs]   = 0.0;
403
 
        smoothTime[secs]  = secs / 60.0;
404
 
        smoothDistance[secs]  = 0.0;
405
 
        smoothAltitude[secs]  = 0.0;
406
 
    }
407
 
 
408
 
    int i = 0;
409
 
    for (int secs = smooth; secs <= rideTimeSecs; ++secs) {
410
 
        while ((i < arrayLength) && (timeArray[i] <= secs)) {
411
 
            DataPoint dp(timeArray[i],
412
 
                         (!hrArray.empty() ? hrArray[i] : 0),
413
 
                         (!wattsArray.empty() ? wattsArray[i] : 0),
414
 
                         (!speedArray.empty() ? speedArray[i] : 0),
415
 
                         (!cadArray.empty() ? cadArray[i] : 0),
416
 
                         (!altArray.empty() ? altArray[i] : 0));
417
 
            if (!wattsArray.empty())
418
 
                totalWatts += wattsArray[i];
419
 
            if (!hrArray.empty())
420
 
                totalHr    += hrArray[i];
421
 
            if (!speedArray.empty())
422
 
                totalSpeed += speedArray[i];
423
 
            if (!cadArray.empty())
424
 
                totalCad   += cadArray[i];
425
 
            if (!altArray.empty())
426
 
                totalAlt   += altArray[i];
427
 
            totalDist   = distanceArray[i];
428
 
            list.append(dp);
429
 
            ++i;
430
 
        }
431
 
        while (!list.empty() && (list.front().time < secs - smooth)) {
432
 
            DataPoint &dp = list.front();
433
 
            totalWatts -= dp.watts;
434
 
            totalHr    -= dp.hr;
435
 
            totalSpeed -= dp.speed;
436
 
            totalCad   -= dp.cad;
437
 
            totalAlt   -= dp.alt;
438
 
            list.removeFirst();
439
 
        }
440
 
        // TODO: this is wrong.  We should do a weighted average over the
441
 
        // seconds represented by each point...
442
 
        if (list.empty()) {
 
565
    // we should only smooth the curves if smoothed rate is greater than sample rate
 
566
    if (smooth > rideItem->ride()->recIntSecs()) {
 
567
 
 
568
        double totalWatts = 0.0;
 
569
        double totalHr = 0.0;
 
570
        double totalSpeed = 0.0;
 
571
        double totalCad = 0.0;
 
572
        double totalDist = 0.0;
 
573
        double totalAlt = 0.0;
 
574
        double totalTemp = 0.0;
 
575
        double totalWind = 0.0;
 
576
        double totalTorque = 0.0;
 
577
        double totalBalance = 0.0;
 
578
 
 
579
        QList<DataPoint> list;
 
580
 
 
581
        smoothWatts.resize(rideTimeSecs + 1); //(rideTimeSecs + 1);
 
582
        smoothHr.resize(rideTimeSecs + 1);
 
583
        smoothSpeed.resize(rideTimeSecs + 1);
 
584
        smoothCad.resize(rideTimeSecs + 1);
 
585
        smoothTime.resize(rideTimeSecs + 1);
 
586
        smoothDistance.resize(rideTimeSecs + 1);
 
587
        smoothAltitude.resize(rideTimeSecs + 1);
 
588
        smoothTemp.resize(rideTimeSecs + 1);
 
589
        smoothWind.resize(rideTimeSecs + 1);
 
590
        smoothRelSpeed.resize(rideTimeSecs + 1);
 
591
        smoothTorque.resize(rideTimeSecs + 1);
 
592
        smoothBalanceL.resize(rideTimeSecs + 1);
 
593
        smoothBalanceR.resize(rideTimeSecs + 1);
 
594
 
 
595
        for (int secs = 0; ((secs < smooth)
 
596
                            && (secs < rideTimeSecs)); ++secs) {
443
597
            smoothWatts[secs] = 0.0;
444
598
            smoothHr[secs]    = 0.0;
445
599
            smoothSpeed[secs] = 0.0;
446
600
            smoothCad[secs]   = 0.0;
447
 
            smoothAltitude[secs]   = smoothAltitude[secs - 1];
448
 
        }
449
 
        else {
450
 
            smoothWatts[secs]    = totalWatts / list.size();
451
 
            smoothHr[secs]       = totalHr / list.size();
452
 
            smoothSpeed[secs]    = totalSpeed / list.size();
453
 
            smoothCad[secs]      = totalCad / list.size();
454
 
            smoothAltitude[secs]      = totalAlt / list.size();
455
 
        }
456
 
        smoothDistance[secs] = totalDist;
457
 
        smoothTime[secs]  = secs / 60.0;
 
601
            smoothTime[secs]  = secs / 60.0;
 
602
            smoothDistance[secs]  = 0.0;
 
603
            smoothAltitude[secs]  = 0.0;
 
604
            smoothTemp[secs]  = 0.0;
 
605
            smoothWind[secs]  = 0.0;
 
606
            smoothRelSpeed[secs] = QwtIntervalSample();
 
607
            smoothTorque[secs]  = 0.0;
 
608
            smoothBalanceL[secs]  = 50;
 
609
            smoothBalanceR[secs]  = 50;
 
610
        }
 
611
 
 
612
        int i = 0;
 
613
        for (int secs = smooth; secs <= rideTimeSecs; ++secs) {
 
614
            while ((i < arrayLength) && (timeArray[i] <= secs)) {
 
615
                DataPoint dp(timeArray[i],
 
616
                             (!hrArray.empty() ? hrArray[i] : 0),
 
617
                             (!wattsArray.empty() ? wattsArray[i] : 0),
 
618
                             (!speedArray.empty() ? speedArray[i] : 0),
 
619
                             (!cadArray.empty() ? cadArray[i] : 0),
 
620
                             (!altArray.empty() ? altArray[i] : 0),
 
621
                             (!tempArray.empty() ? tempArray[i] : 0),
 
622
                             (!windArray.empty() ? windArray[i] : 0),
 
623
                             (!torqueArray.empty() ? torqueArray[i] : 0),
 
624
                             (!balanceArray.empty() ? balanceArray[i] : 0));
 
625
                if (!wattsArray.empty())
 
626
                    totalWatts += wattsArray[i];
 
627
                if (!hrArray.empty())
 
628
                    totalHr    += hrArray[i];
 
629
                if (!speedArray.empty())
 
630
                    totalSpeed += speedArray[i];
 
631
                if (!cadArray.empty())
 
632
                    totalCad   += cadArray[i];
 
633
                if (!altArray.empty())
 
634
                    totalAlt   += altArray[i];
 
635
                if (!tempArray.empty() ) {
 
636
                    if (tempArray[i] == RideFile::noTemp) {
 
637
                        dp.temp = (i>0 && !list.empty()?list.back().temp:0.0);
 
638
                        totalTemp   += dp.temp;
 
639
                    }
 
640
                    else {
 
641
                        totalTemp   += tempArray[i];
 
642
                    }
 
643
                }
 
644
                if (!windArray.empty())
 
645
                    totalWind   += windArray[i];
 
646
                if (!torqueArray.empty())
 
647
                    totalTorque   += torqueArray[i];
 
648
                if (!balanceArray.empty())
 
649
                    totalBalance   += (balanceArray[i]>0?balanceArray[i]:50);
 
650
 
 
651
                totalDist   = distanceArray[i];
 
652
                list.append(dp);
 
653
                ++i;
 
654
            }
 
655
            while (!list.empty() && (list.front().time < secs - smooth)) {
 
656
                DataPoint &dp = list.front();
 
657
                totalWatts -= dp.watts;
 
658
                totalHr    -= dp.hr;
 
659
                totalSpeed -= dp.speed;
 
660
                totalCad   -= dp.cad;
 
661
                totalAlt   -= dp.alt;
 
662
                totalTemp   -= dp.temp;
 
663
                totalWind   -= dp.wind;
 
664
                totalTorque   -= dp.torque;
 
665
                totalBalance   -= (dp.lrbalance>0?dp.lrbalance:50);
 
666
                list.removeFirst();
 
667
            }
 
668
            // TODO: this is wrong.  We should do a weighted average over the
 
669
            // seconds represented by each point...
 
670
            if (list.empty()) {
 
671
                smoothWatts[secs] = 0.0;
 
672
                smoothHr[secs]    = 0.0;
 
673
                smoothSpeed[secs] = 0.0;
 
674
                smoothCad[secs]   = 0.0;
 
675
                smoothAltitude[secs]   = smoothAltitude[secs - 1];
 
676
                smoothTemp[secs]   = 0.0;
 
677
                smoothWind[secs] = 0.0;
 
678
                smoothRelSpeed[secs] =  QwtIntervalSample();
 
679
                smoothTorque[secs] = 0.0;
 
680
                smoothBalanceL[secs] = 50;
 
681
                smoothBalanceR[secs] = 50;
 
682
            }
 
683
            else {
 
684
                smoothWatts[secs]    = totalWatts / list.size();
 
685
                smoothHr[secs]       = totalHr / list.size();
 
686
                smoothSpeed[secs]    = totalSpeed / list.size();
 
687
                smoothCad[secs]      = totalCad / list.size();
 
688
                smoothAltitude[secs]      = totalAlt / list.size();
 
689
                smoothTemp[secs]      = totalTemp / list.size();
 
690
                smoothWind[secs]    = totalWind / list.size();
 
691
                smoothRelSpeed[secs] =  QwtIntervalSample( bydist ? totalDist : secs / 60.0, QwtInterval(qMin(totalWind / list.size(), totalSpeed / list.size()), qMax(totalWind / list.size(), totalSpeed / list.size()) ) );
 
692
                smoothTorque[secs]    = totalTorque / list.size();
 
693
 
 
694
                double balance = totalBalance / list.size();
 
695
                if (balance == 0) {
 
696
                    smoothBalanceL[secs]    = 50;
 
697
                    smoothBalanceR[secs]    = 50;
 
698
                } else if (balance >= 50) {
 
699
                    smoothBalanceL[secs]    = balance;
 
700
                    smoothBalanceR[secs]    = 50;
 
701
                }
 
702
                else {
 
703
                    smoothBalanceL[secs]    = 50;
 
704
                    smoothBalanceR[secs]    = balance;
 
705
                }
 
706
            }
 
707
            smoothDistance[secs] = totalDist;
 
708
            smoothTime[secs]  = secs / 60.0;
 
709
        }
 
710
 
 
711
    } else {
 
712
 
 
713
        // no smoothing .. just raw data
 
714
        smoothWatts.resize(0);
 
715
        smoothHr.resize(0);
 
716
        smoothSpeed.resize(0);
 
717
        smoothCad.resize(0);
 
718
        smoothTime.resize(0);
 
719
        smoothDistance.resize(0);
 
720
        smoothAltitude.resize(0);
 
721
        smoothTemp.resize(0);
 
722
        smoothWind.resize(0);
 
723
        smoothRelSpeed.resize(0);
 
724
        smoothTorque.resize(0);
 
725
        smoothBalanceL.resize(0);
 
726
        smoothBalanceR.resize(0);
 
727
 
 
728
        foreach (RideFilePoint *dp, rideItem->ride()->dataPoints()) {
 
729
            smoothWatts.append(dp->watts);
 
730
            smoothHr.append(dp->hr);
 
731
            smoothSpeed.append(useMetricUnits ? dp->kph : dp->kph * MILES_PER_KM);
 
732
            smoothCad.append(dp->cad);
 
733
            smoothTime.append(dp->secs/60);
 
734
            smoothDistance.append(useMetricUnits ? dp->km : dp->km * MILES_PER_KM);
 
735
            smoothAltitude.append(useMetricUnits ? dp->alt : dp->alt * FEET_PER_METER);
 
736
            smoothTemp.append(useMetricUnits ? dp->temp : dp->temp * FAHRENHEIT_PER_CENTIGRADE + FAHRENHEIT_ADD_CENTIGRADE);
 
737
            smoothWind.append(useMetricUnits ? dp->headwind : dp->headwind * MILES_PER_KM);
 
738
            smoothTorque.append(dp->nm);
 
739
 
 
740
            if (dp->lrbalance == 0) {
 
741
                smoothBalanceL.append(50);
 
742
                smoothBalanceR.append(50);
 
743
            }
 
744
            else if (dp->lrbalance >= 50) {
 
745
                smoothBalanceL.append(dp->lrbalance);
 
746
                smoothBalanceR.append(50);
 
747
            }
 
748
            else {
 
749
                smoothBalanceL.append(50);
 
750
                smoothBalanceR.append(dp->lrbalance);
 
751
            }
 
752
 
 
753
            double head = dp->headwind * (useMetricUnits ? 1.0f : MILES_PER_KM);
 
754
            double speed = dp->kph * (useMetricUnits ? 1.0f : MILES_PER_KM);
 
755
            smoothRelSpeed.append(QwtIntervalSample( bydist ? smoothDistance.last() : smoothTime.last(), QwtInterval(qMin(head, speed) , qMax(head, speed) ) ));
 
756
 
 
757
        }
458
758
    }
459
759
 
460
760
    QVector<double> &xaxis = bydist ? smoothDistance : smoothTime;
461
 
    int startingIndex = qMin(smooth, rideTimeSecs);
462
 
    int totalPoints = rideTimeSecs + 1 - startingIndex;
463
 
    // set curves
464
 
    if (!wattsArray.empty())
 
761
    int startingIndex = qMin(smooth, xaxis.count());
 
762
    int totalPoints = xaxis.count() - startingIndex;
 
763
 
 
764
    // set curves - we set the intervalHighlighter to whichver is available
 
765
    if (!wattsArray.empty()) {
465
766
        wattsCurve->setData(xaxis.data() + startingIndex, smoothWatts.data() + startingIndex, totalPoints);
466
 
    if (!hrArray.empty())
 
767
        intervalHighlighterCurve->setYAxis(yLeft);
 
768
 
 
769
    } if (!hrArray.empty()) {
467
770
        hrCurve->setData(xaxis.data() + startingIndex, smoothHr.data() + startingIndex, totalPoints);
468
 
    if (!speedArray.empty())
 
771
        intervalHighlighterCurve->setYAxis(yLeft2);
 
772
 
 
773
    } if (!speedArray.empty()) {
469
774
        speedCurve->setData(xaxis.data() + startingIndex, smoothSpeed.data() + startingIndex, totalPoints);
470
 
    if (!cadArray.empty())
 
775
        intervalHighlighterCurve->setYAxis(yRight);
 
776
 
 
777
    } if (!cadArray.empty()) {
471
778
        cadCurve->setData(xaxis.data() + startingIndex, smoothCad.data() + startingIndex, totalPoints);
472
 
    if (!altArray.empty())
 
779
        intervalHighlighterCurve->setYAxis(yLeft2);
 
780
 
 
781
    } if (!altArray.empty()) {
473
782
        altCurve->setData(xaxis.data() + startingIndex, smoothAltitude.data() + startingIndex, totalPoints);
 
783
        intervalHighlighterCurve->setYAxis(yRight2);
 
784
 
 
785
    } if (!tempArray.empty()) {
 
786
        tempCurve->setData(xaxis.data() + startingIndex, smoothTemp.data() + startingIndex, totalPoints);
 
787
        if (useMetricUnits)
 
788
            intervalHighlighterCurve->setYAxis(yRight);
 
789
        else
 
790
            intervalHighlighterCurve->setYAxis(yLeft2);
 
791
 
 
792
 
 
793
    } if (!windArray.empty()) {
 
794
        windCurve->setData(new QwtIntervalSeriesData(smoothRelSpeed));
 
795
        intervalHighlighterCurve->setYAxis(yRight);
 
796
 
 
797
    } if (!torqueArray.empty()) {
 
798
        torqueCurve->setData(xaxis.data() + startingIndex, smoothTorque.data() + startingIndex, totalPoints);
 
799
        intervalHighlighterCurve->setYAxis(yRight);
 
800
 
 
801
    } if (!balanceArray.empty()) {
 
802
        balanceLCurve->setData(xaxis.data() + startingIndex, smoothBalanceL.data() + startingIndex, totalPoints);
 
803
        intervalHighlighterCurve->setYAxis(yLeft2);
 
804
        balanceRCurve->setData(xaxis.data() + startingIndex, smoothBalanceR.data() + startingIndex, totalPoints);
 
805
        intervalHighlighterCurve->setYAxis(yLeft2);
 
806
    }
474
807
 
475
808
    setYMax();
476
809
    refreshIntervalMarkers();
516
849
AllPlot::setYMax()
517
850
{
518
851
    if (wattsCurve->isVisible()) {
 
852
        double maxY = (referencePlot == NULL) ? (1.05 * wattsCurve->maxYValue()) :
 
853
                                             (1.05 * referencePlot->wattsCurve->maxYValue());
 
854
 
 
855
        int axisHeight = qRound( plotLayout()->canvasRect().height() );
 
856
        QFontMetrics labelWidthMetric = QFontMetrics( QwtPlot::axisFont(yLeft) );
 
857
        int labelWidth = labelWidthMetric.width( (maxY > 1000) ? " 8,888 " : " 888 " );
 
858
 
 
859
        int step = 100;
 
860
        while( ( qCeil(maxY / step) * labelWidth ) > axisHeight )
 
861
        {
 
862
            nextStep(step);
 
863
        }
 
864
 
 
865
        QwtValueList xytick[QwtScaleDiv::NTickTypes];
 
866
        for (int i=0;i<maxY;i+=step)
 
867
            xytick[QwtScaleDiv::MajorTick]<<i;
 
868
 
519
869
        setAxisTitle(yLeft, tr("Watts"));
520
 
        if (referencePlot == NULL)
521
 
            setAxisScale(yLeft, 0.0, 1.05 * wattsCurve->maxYValue());
522
 
        else
523
 
            setAxisScale(yLeft, 0.0, 1.05 * referencePlot->wattsCurve->maxYValue());
 
870
        setAxisScaleDiv(QwtPlot::yLeft,QwtScaleDiv(0.0,maxY,xytick));
524
871
        setAxisLabelRotation(yLeft,270);
525
872
        setAxisLabelAlignment(yLeft,Qt::AlignVCenter);
526
873
    }
527
 
    if (hrCurve->isVisible() || cadCurve->isVisible()) {
 
874
    if (hrCurve->isVisible() || cadCurve->isVisible() || (!useMetricUnits && tempCurve->isVisible()) || balanceLCurve->isVisible()) {
 
875
        double ymin = 0;
528
876
        double ymax = 0;
 
877
 
529
878
        QStringList labels;
530
879
        if (hrCurve->isVisible()) {
531
880
            labels << tr("BPM");
541
890
            else
542
891
                ymax = qMax(ymax, referencePlot->cadCurve->maxYValue());
543
892
        }
 
893
        if (tempCurve->isVisible() && !useMetricUnits) {
 
894
 
 
895
            labels << QString::fromUtf8("°F");
 
896
 
 
897
            if (referencePlot == NULL) {
 
898
                ymin = qMin(ymin, tempCurve->minYValue());
 
899
                ymax = qMax(ymax, tempCurve->maxYValue());
 
900
            }
 
901
            else {
 
902
                ymin = qMin(ymin, referencePlot->tempCurve->minYValue());
 
903
                ymax = qMax(ymax, referencePlot->tempCurve->maxYValue());
 
904
            }
 
905
        }
 
906
        if (balanceLCurve->isVisible()) {
 
907
            labels << tr("% left");
 
908
            if (referencePlot == NULL)
 
909
                ymax = qMax(ymax, balanceLCurve->maxYValue());
 
910
            else
 
911
                ymax = qMax(ymax, referencePlot->balanceLCurve->maxYValue());
 
912
 
 
913
            balanceLCurve->setBaseline(50);
 
914
            balanceRCurve->setBaseline(50);
 
915
        }
 
916
 
 
917
        int axisHeight = qRound( plotLayout()->canvasRect().height() );
 
918
        QFontMetrics labelWidthMetric = QFontMetrics( QwtPlot::axisFont(yLeft) );
 
919
        int labelWidth = labelWidthMetric.width( "888 " );
 
920
 
 
921
        ymax *= 1.05;
 
922
        int step = 10;
 
923
        while( ( qCeil(ymax / step) * labelWidth ) > axisHeight )
 
924
        {
 
925
            nextStep(step);
 
926
        }
 
927
 
 
928
        QwtValueList xytick[QwtScaleDiv::NTickTypes];
 
929
        for (int i=0;i<ymax;i+=step)
 
930
            xytick[QwtScaleDiv::MajorTick]<<i;
 
931
 
544
932
        setAxisTitle(yLeft2, labels.join(" / "));
545
 
        setAxisScale(yLeft2, 0.0, 1.05 * ymax);
 
933
        setAxisScaleDiv(yLeft2,QwtScaleDiv(ymin, ymax, xytick));
546
934
        setAxisLabelRotation(yLeft2,270);
547
935
        setAxisLabelAlignment(yLeft2,Qt::AlignVCenter);
548
936
    }
549
 
    if (speedCurve->isVisible()) {
550
 
        setAxisTitle(yRight, (useMetricUnits ? tr("km/h") : tr("MPH")));
551
 
        if (referencePlot == NULL)
552
 
            setAxisScale(yRight, 0.0, 1.05 * speedCurve->maxYValue());
553
 
        else
554
 
            setAxisScale(yRight, 0.0, 1.05 * referencePlot->speedCurve->maxYValue());
 
937
    if (speedCurve->isVisible() || (useMetricUnits && tempCurve->isVisible()) || torqueCurve->isVisible()) {
 
938
        double ymin = 0;
 
939
        double ymax = 0;
 
940
 
 
941
        QStringList labels;
 
942
 
 
943
        if (speedCurve->isVisible()) {
 
944
            labels << (useMetricUnits ? tr("KPH") : tr("MPH"));
 
945
 
 
946
            if (referencePlot == NULL)
 
947
                ymax = speedCurve->maxYValue();
 
948
            else
 
949
                ymax = referencePlot->speedCurve->maxYValue();
 
950
        }
 
951
        if (tempCurve->isVisible() && useMetricUnits) {
 
952
 
 
953
            labels << QString::fromUtf8("°C");
 
954
 
 
955
            if (referencePlot == NULL) {
 
956
                ymin = qMin(ymin, tempCurve->minYValue());
 
957
                ymax = qMax(ymax, tempCurve->maxYValue());
 
958
            }
 
959
            else {
 
960
                ymin = qMin(ymin, referencePlot->tempCurve->minYValue());
 
961
                ymax = qMax(ymax, referencePlot->tempCurve->maxYValue());
 
962
            }
 
963
        }
 
964
        if (torqueCurve->isVisible()) {
 
965
            labels << (useMetricUnits ? tr("Nm") : tr("ftLb"));
 
966
 
 
967
            if (referencePlot == NULL)
 
968
                ymax = qMax(ymax, torqueCurve->maxYValue());
 
969
            else
 
970
                ymax = qMax(ymax, referencePlot->torqueCurve->maxYValue());
 
971
        }
 
972
        setAxisTitle(yRight, labels.join(" / "));
 
973
        setAxisScale(yRight, ymin, 1.05 * ymax);
555
974
        setAxisLabelRotation(yRight,90);
556
975
        setAxisLabelAlignment(yRight,Qt::AlignVCenter);
557
976
    }
566
985
            ymin = referencePlot->altCurve->minYValue();
567
986
            ymax = qMax(ymin + 100, 1.05 * referencePlot->altCurve->maxYValue());
568
987
        }
569
 
        setAxisScale(yRight2, ymin, ymax);
 
988
        ymin = (ymin < 0 ? -100 : 0) + ( qRound(ymin) / 100 ) * 100;
 
989
 
 
990
        int axisHeight = qRound( plotLayout()->canvasRect().height() );
 
991
        QFontMetrics labelWidthMetric = QFontMetrics( QwtPlot::axisFont(yLeft) );
 
992
        int labelWidth = labelWidthMetric.width( (ymax > 1000) ? " 8888 " : " 888 " );
 
993
 
 
994
        int step = 10;
 
995
        while( ( qCeil( (ymax - ymin ) / step) * labelWidth ) > axisHeight )
 
996
        {
 
997
            nextStep(step);
 
998
        }
 
999
 
 
1000
        QwtValueList xytick[QwtScaleDiv::NTickTypes];
 
1001
        for (int i=ymin;i<ymax;i+=step)
 
1002
            xytick[QwtScaleDiv::MajorTick]<<i;
 
1003
 
 
1004
        //setAxisScale(yRight2, ymin, ymax);
 
1005
        setAxisScaleDiv(yRight2,QwtScaleDiv(ymin,ymax,xytick));
570
1006
        setAxisLabelRotation(yRight2,90);
571
1007
        setAxisLabelAlignment(yRight2,Qt::AlignVCenter);
572
1008
        altCurve->setBaseline(ymin);
582
1018
AllPlot::setXTitle()
583
1019
{
584
1020
    if (bydist)
585
 
        setAxisTitle(xBottom, tr("Distance ")+QString(unit.toString() == "Metric"?"(km)":"(miles)"));
 
1021
        setAxisTitle(xBottom, tr("Distance ")+QString(useMetricUnits?"(km)":"(miles)"));
586
1022
    else
587
 
        setAxisTitle(xBottom, tr("Time (minutes)"));
 
1023
        setAxisTitle(xBottom, tr("Time (Hours:Minutes)"));
588
1024
}
589
1025
 
590
1026
void
591
1027
AllPlot::setDataFromPlot(AllPlot *plot, int startidx, int stopidx)
592
1028
{
593
 
    if (plot == NULL) return;
 
1029
    if (plot == NULL) {
 
1030
        rideItem = NULL;
 
1031
        return;
 
1032
    }
594
1033
 
595
1034
    referencePlot = plot;
596
1035
 
597
 
    setTitle(plot->rideItem->ride()->startTime().toString(GC_DATETIME_FORMAT));
598
 
 
 
1036
    // You got to give me some data first!
 
1037
    if (!plot->distanceArray.count() || !plot->timeArray.count()) return;
599
1038
 
600
1039
    // reference the plot for data and state
601
1040
    rideItem = plot->rideItem;
621
1060
    double *smoothC = &plot->smoothCad[startidx];
622
1061
    double *smoothA = &plot->smoothAltitude[startidx];
623
1062
    double *smoothD = &plot->smoothDistance[startidx];
 
1063
    double *smoothTE = &plot->smoothTemp[startidx];
 
1064
    //double *smoothWND = &plot->smoothWind[startidx];
 
1065
    double *smoothNM = &plot->smoothTorque[startidx];
 
1066
    double *smoothBALL = &plot->smoothBalanceL[startidx];
 
1067
    double *smoothBALR = &plot->smoothBalanceR[startidx];
 
1068
 
 
1069
    QwtIntervalSample *smoothRS = &plot->smoothRelSpeed[startidx];
624
1070
 
625
1071
    double *xaxis = bydist ? smoothD : smoothT;
626
1072
 
627
1073
    // attach appropriate curves
628
 
    if (this->legend()) this->legend()->hide();
 
1074
    //if (this->legend()) this->legend()->hide();
629
1075
 
630
1076
    wattsCurve->detach();
631
1077
    hrCurve->detach();
632
1078
    speedCurve->detach();
633
1079
    cadCurve->detach();
634
1080
    altCurve->detach();
 
1081
    tempCurve->detach();
 
1082
    windCurve->detach();
 
1083
    torqueCurve->detach();
 
1084
    balanceLCurve->detach();
 
1085
    balanceRCurve->detach();
 
1086
 
 
1087
    wattsCurve->setVisible(rideItem->ride()->areDataPresent()->watts && showPowerState < 2);
 
1088
    hrCurve->setVisible(rideItem->ride()->areDataPresent()->hr && showHr);
 
1089
    speedCurve->setVisible(rideItem->ride()->areDataPresent()->kph && showSpeed);
 
1090
    cadCurve->setVisible(rideItem->ride()->areDataPresent()->cad && showCad);
 
1091
    altCurve->setVisible(rideItem->ride()->areDataPresent()->alt && showAlt);
 
1092
    tempCurve->setVisible(rideItem->ride()->areDataPresent()->temp && showTemp);
 
1093
    windCurve->setVisible(rideItem->ride()->areDataPresent()->headwind && showWind);
 
1094
    torqueCurve->setVisible(rideItem->ride()->areDataPresent()->nm && showTorque);
 
1095
    balanceLCurve->setVisible(rideItem->ride()->areDataPresent()->lrbalance && showBalance);
 
1096
    balanceRCurve->setVisible(rideItem->ride()->areDataPresent()->lrbalance && showBalance);
635
1097
 
636
1098
    wattsCurve->setData(xaxis,smoothW,stopidx-startidx);
637
1099
    hrCurve->setData(xaxis, smoothHR,stopidx-startidx);
638
1100
    speedCurve->setData(xaxis, smoothS, stopidx-startidx);
639
1101
    cadCurve->setData(xaxis, smoothC, stopidx-startidx);
640
1102
    altCurve->setData(xaxis, smoothA, stopidx-startidx);
 
1103
    tempCurve->setData(xaxis, smoothTE, stopidx-startidx);
 
1104
 
 
1105
    QVector<QwtIntervalSample> tmpWND(stopidx-startidx);
 
1106
    qMemCopy( tmpWND.data(), smoothRS, (stopidx-startidx) * sizeof( QwtIntervalSample ) );
 
1107
    windCurve->setData(new QwtIntervalSeriesData(tmpWND));
 
1108
    torqueCurve->setData(xaxis, smoothNM, stopidx-startidx);
 
1109
    balanceLCurve->setData(xaxis, smoothBALL, stopidx-startidx);
 
1110
    balanceRCurve->setData(xaxis, smoothBALR, stopidx-startidx);
 
1111
 
 
1112
    /*QVector<double> _time(stopidx-startidx);
 
1113
    qMemCopy( _time.data(), xaxis, (stopidx-startidx) * sizeof( double ) );
 
1114
 
 
1115
    QVector<QwtIntervalSample> tmpWND(stopidx-startidx);
 
1116
    for (int i=0;i<_time.count();i++) {
 
1117
        QwtIntervalSample inter = QwtIntervalSample(_time.at(i), 20,50);
 
1118
        tmpWND.append(inter); // plot->smoothRelSpeed.at(i)
 
1119
    }*/
 
1120
 
 
1121
    QwtSymbol sym;
 
1122
    sym.setPen(QPen(GColor(CPLOTMARKER)));
 
1123
    if (stopidx-startidx < 150) {
 
1124
        sym.setStyle(QwtSymbol::Ellipse);
 
1125
        sym.setSize(3);
 
1126
    } else {
 
1127
        sym.setStyle(QwtSymbol::NoSymbol);
 
1128
        sym.setSize(0);
 
1129
    }
 
1130
 
 
1131
    wattsCurve->setSymbol(new QwtSymbol(sym));
 
1132
    hrCurve->setSymbol(new QwtSymbol(sym));
 
1133
    speedCurve->setSymbol(new QwtSymbol(sym));
 
1134
    cadCurve->setSymbol(new QwtSymbol(sym));
 
1135
    altCurve->setSymbol(new QwtSymbol(sym));
 
1136
    tempCurve->setSymbol(new QwtSymbol(sym));
 
1137
    torqueCurve->setSymbol(new QwtSymbol(sym));
 
1138
    balanceLCurve->setSymbol(new QwtSymbol(sym));
 
1139
    balanceRCurve->setSymbol(new QwtSymbol(sym));
641
1140
 
642
1141
    setYMax();
643
 
    setAxisMaxMajor(yLeft, 5);
644
 
    setAxisMaxMajor(yLeft2, 5);
645
 
    setAxisMaxMajor(yRight, 5);
646
 
    setAxisMaxMajor(yRight2, 5);
647
1142
 
648
1143
    setAxisScale(xBottom, xaxis[0], xaxis[stopidx-startidx-1]);
649
1144
 
650
 
    if (!plot->smoothAltitude.empty()) altCurve->attach(this);
651
 
    if (!plot->smoothWatts.empty()) wattsCurve->attach(this);
652
 
    if (!plot->smoothHr.empty()) hrCurve->attach(this);
653
 
    if (!plot->smoothSpeed.empty()) speedCurve->attach(this);
654
 
    if (!plot->smoothCad.empty()) cadCurve->attach(this);
 
1145
    if (!plot->smoothAltitude.empty()) {
 
1146
        altCurve->attach(this);
 
1147
        intervalHighlighterCurve->setYAxis(yRight2);
 
1148
    }
 
1149
    if (!plot->smoothWatts.empty()) {
 
1150
        wattsCurve->attach(this);
 
1151
        intervalHighlighterCurve->setYAxis(yLeft);
 
1152
    }
 
1153
    if (!plot->smoothHr.empty()) {
 
1154
        hrCurve->attach(this);
 
1155
        intervalHighlighterCurve->setYAxis(yLeft2);
 
1156
    }
 
1157
    if (!plot->smoothSpeed.empty()) {
 
1158
        speedCurve->attach(this);
 
1159
        intervalHighlighterCurve->setYAxis(yRight);
 
1160
    }
 
1161
    if (!plot->smoothCad.empty()) {
 
1162
        cadCurve->attach(this);
 
1163
        intervalHighlighterCurve->setYAxis(yLeft2);
 
1164
    }
 
1165
    if (!plot->smoothTemp.empty()) {
 
1166
        tempCurve->attach(this);
 
1167
        intervalHighlighterCurve->setYAxis(yRight);
 
1168
    }
 
1169
    if (!plot->smoothWind.empty()) {
 
1170
        windCurve->attach(this);
 
1171
        intervalHighlighterCurve->setYAxis(yRight);
 
1172
    }
 
1173
    if (!plot->smoothTorque.empty()) {
 
1174
        torqueCurve->attach(this);
 
1175
        intervalHighlighterCurve->setYAxis(yRight);
 
1176
    }
 
1177
    if (!plot->smoothBalanceL.empty()) {
 
1178
        balanceLCurve->attach(this);
 
1179
        balanceRCurve->attach(this);
 
1180
        intervalHighlighterCurve->setYAxis(yLeft2);
 
1181
    }
 
1182
 
655
1183
 
656
1184
    refreshIntervalMarkers();
657
1185
    refreshZoneLabels();
658
1186
 
659
 
    if (this->legend()) this->legend()->show();
 
1187
    //if (this->legend()) this->legend()->show();
660
1188
    //replot();
661
1189
}
662
1190
 
669
1197
    wattsArray.clear();
670
1198
 
671
1199
    RideFile *ride = rideItem->ride();
672
 
    if (ride && ride->deviceType() != QString("Manual CSV")) {
673
 
 
 
1200
    if (ride && ride->dataPoints().size()) {
674
1201
        const RideFileDataPresent *dataPresent = ride->areDataPresent();
675
1202
        int npoints = ride->dataPoints().size();
676
1203
        wattsArray.resize(dataPresent->watts ? npoints : 0);
678
1205
        speedArray.resize(dataPresent->kph ? npoints : 0);
679
1206
        cadArray.resize(dataPresent->cad ? npoints : 0);
680
1207
        altArray.resize(dataPresent->alt ? npoints : 0);
 
1208
        tempArray.resize(dataPresent->temp ? npoints : 0);
 
1209
        windArray.resize(dataPresent->headwind ? npoints : 0);
 
1210
        torqueArray.resize(dataPresent->nm ? npoints : 0);
 
1211
        balanceArray.resize(dataPresent->lrbalance ? npoints : 0);
681
1212
        timeArray.resize(npoints);
682
1213
        distanceArray.resize(npoints);
683
1214
 
687
1218
        speedCurve->detach();
688
1219
        cadCurve->detach();
689
1220
        altCurve->detach();
 
1221
        tempCurve->detach();
 
1222
        windCurve->detach();
 
1223
        torqueCurve->detach();
 
1224
        balanceLCurve->detach();
 
1225
        balanceRCurve->detach();
 
1226
 
690
1227
        if (!altArray.empty()) altCurve->attach(this);
691
1228
        if (!wattsArray.empty()) wattsCurve->attach(this);
692
1229
        if (!hrArray.empty()) hrCurve->attach(this);
693
1230
        if (!speedArray.empty()) speedCurve->attach(this);
694
1231
        if (!cadArray.empty()) cadCurve->attach(this);
 
1232
        if (!tempArray.empty()) tempCurve->attach(this);
 
1233
        if (!windArray.empty()) windCurve->attach(this);
 
1234
        if (!torqueArray.empty()) torqueCurve->attach(this);
 
1235
        if (!balanceArray.empty()) {
 
1236
            balanceLCurve->attach(this);
 
1237
            balanceRCurve->attach(this);
 
1238
        }
695
1239
 
696
1240
        wattsCurve->setVisible(dataPresent->watts && showPowerState < 2);
697
 
        hrCurve->setVisible(dataPresent->hr && showHrState == Qt::Checked);
698
 
        speedCurve->setVisible(dataPresent->kph && showSpeedState == Qt::Checked);
699
 
        cadCurve->setVisible(dataPresent->cad && showCadState == Qt::Checked);
700
 
        altCurve->setVisible(dataPresent->alt && showAltState == Qt::Checked);
 
1241
        hrCurve->setVisible(dataPresent->hr && showHr);
 
1242
        speedCurve->setVisible(dataPresent->kph && showSpeed);
 
1243
        cadCurve->setVisible(dataPresent->cad && showCad);
 
1244
        altCurve->setVisible(dataPresent->alt && showAlt);
 
1245
        tempCurve->setVisible(dataPresent->temp && showTemp);
 
1246
        windCurve->setVisible(dataPresent->headwind && showWind);
 
1247
        torqueCurve->setVisible(dataPresent->nm && showWind);
 
1248
        balanceLCurve->setVisible(dataPresent->lrbalance && showBalance);
 
1249
        balanceRCurve->setVisible(dataPresent->lrbalance && showBalance);
701
1250
 
702
1251
        arrayLength = 0;
703
1252
        foreach (const RideFilePoint *point, ride->dataPoints()) {
731
1280
                altArray[arrayLength]   = (useMetricUnits
732
1281
                                           ? point->alt
733
1282
                                           : point->alt * FEET_PER_METER);
 
1283
            if (!tempArray.empty())
 
1284
                tempArray[arrayLength]   = point->temp;
 
1285
 
 
1286
            if (!windArray.empty())
 
1287
                windArray[arrayLength] = max(0,
 
1288
                                             (useMetricUnits
 
1289
                                              ? point->headwind
 
1290
                                              : point->headwind * MILES_PER_KM));
 
1291
 
 
1292
            if (!balanceArray.empty())
 
1293
                balanceArray[arrayLength]   = point->lrbalance;
 
1294
 
734
1295
            distanceArray[arrayLength] = max(0,
735
1296
                                             (useMetricUnits
736
1297
                                              ? point->km
737
1298
                                              : point->km * MILES_PER_KM));
 
1299
 
 
1300
            if (!torqueArray.empty())
 
1301
                torqueArray[arrayLength] = max(0,
 
1302
                                              (useMetricUnits
 
1303
                                               ? point->nm
 
1304
                                               : point->nm * FEET_LB_PER_NM));
738
1305
            ++arrayLength;
739
1306
        }
740
1307
        recalc();
741
1308
    }
742
1309
    else {
743
 
        setTitle("no data");
 
1310
        //setTitle("no data");
744
1311
 
745
1312
        wattsCurve->detach();
746
1313
        hrCurve->detach();
747
1314
        speedCurve->detach();
748
1315
        cadCurve->detach();
749
1316
        altCurve->detach();
 
1317
        tempCurve->detach();
 
1318
        windCurve->detach();
 
1319
        torqueCurve->detach();
 
1320
        balanceLCurve->detach();
 
1321
        balanceRCurve->detach();
 
1322
 
750
1323
        foreach(QwtPlotMarker *mrk, d_mrk)
751
1324
            delete mrk;
752
1325
        d_mrk.clear();
754
1327
}
755
1328
 
756
1329
void
757
 
AllPlot::showPower(int id)
 
1330
AllPlot::setShowPower(int id)
758
1331
{
759
1332
    if (showPowerState == id) return;
760
1333
 
770
1343
}
771
1344
 
772
1345
void
773
 
AllPlot::showHr(int state)
774
 
{
775
 
    showHrState = state;
776
 
    assert(state != Qt::PartiallyChecked);
777
 
    hrCurve->setVisible(state == Qt::Checked);
778
 
    setYMax();
779
 
    replot();
780
 
}
781
 
 
782
 
void
783
 
AllPlot::showSpeed(int state)
784
 
{
785
 
    showSpeedState = state;
786
 
    assert(state != Qt::PartiallyChecked);
787
 
    speedCurve->setVisible(state == Qt::Checked);
788
 
    setYMax();
789
 
    replot();
790
 
}
791
 
 
792
 
void
793
 
AllPlot::showCad(int state)
794
 
{
795
 
    showCadState = state;
796
 
    assert(state != Qt::PartiallyChecked);
797
 
    cadCurve->setVisible(state == Qt::Checked);
798
 
    setYMax();
799
 
    replot();
800
 
}
801
 
 
802
 
void
803
 
AllPlot::showAlt(int state)
804
 
{
805
 
    showAltState = state;
806
 
    assert(state != Qt::PartiallyChecked);
807
 
    altCurve->setVisible(state == Qt::Checked);
808
 
    setYMax();
809
 
    replot();
810
 
}
811
 
 
812
 
void
813
 
AllPlot::showGrid(int state)
814
 
{
815
 
    assert(state != Qt::PartiallyChecked);
816
 
    grid->setVisible(state == Qt::Checked);
 
1346
AllPlot::setShowHr(bool show)
 
1347
{
 
1348
    showHr = show;
 
1349
    hrCurve->setVisible(show);
 
1350
    setYMax();
 
1351
    replot();
 
1352
}
 
1353
 
 
1354
void
 
1355
AllPlot::setShowSpeed(bool show)
 
1356
{
 
1357
    showSpeed = show;
 
1358
    speedCurve->setVisible(show);
 
1359
    setYMax();
 
1360
    replot();
 
1361
}
 
1362
 
 
1363
void
 
1364
AllPlot::setShowCad(bool show)
 
1365
{
 
1366
    showCad = show;
 
1367
    cadCurve->setVisible(show);
 
1368
    setYMax();
 
1369
    replot();
 
1370
}
 
1371
 
 
1372
void
 
1373
AllPlot::setShowAlt(bool show)
 
1374
{
 
1375
    showAlt = show;
 
1376
    altCurve->setVisible(show);
 
1377
    setYMax();
 
1378
    replot();
 
1379
}
 
1380
 
 
1381
void
 
1382
AllPlot::setShowTemp(bool show)
 
1383
{
 
1384
    showTemp = show;
 
1385
    tempCurve->setVisible(show);
 
1386
    setYMax();
 
1387
    replot();
 
1388
}
 
1389
 
 
1390
void
 
1391
AllPlot::setShowWind(bool show)
 
1392
{
 
1393
    showWind = show;
 
1394
    windCurve->setVisible(show);
 
1395
    setYMax();
 
1396
    replot();
 
1397
}
 
1398
 
 
1399
void
 
1400
AllPlot::setShowTorque(bool show)
 
1401
{
 
1402
    showTorque = show;
 
1403
    torqueCurve->setVisible(show);
 
1404
    setYMax();
 
1405
    replot();
 
1406
}
 
1407
 
 
1408
void
 
1409
AllPlot::setShowBalance(bool show)
 
1410
{
 
1411
    showBalance = show;
 
1412
    balanceLCurve->setVisible(show);
 
1413
    balanceRCurve->setVisible(show);
 
1414
    setYMax();
 
1415
    replot();
 
1416
}
 
1417
 
 
1418
void
 
1419
AllPlot::setShowGrid(bool show)
 
1420
{
 
1421
    grid->setVisible(show);
 
1422
    replot();
 
1423
}
 
1424
 
 
1425
void
 
1426
AllPlot::setPaintBrush(int state)
 
1427
{
 
1428
    if (state) {
 
1429
 
 
1430
        QColor p;
 
1431
        p = wattsCurve->pen().color();
 
1432
        p.setAlpha(64);
 
1433
        wattsCurve->setBrush(QBrush(p));
 
1434
 
 
1435
        p = hrCurve->pen().color();
 
1436
        p.setAlpha(64);
 
1437
        hrCurve->setBrush(QBrush(p));
 
1438
 
 
1439
        p = speedCurve->pen().color();
 
1440
        p.setAlpha(64);
 
1441
        speedCurve->setBrush(QBrush(p));
 
1442
 
 
1443
        p = cadCurve->pen().color();
 
1444
        p.setAlpha(64);
 
1445
        cadCurve->setBrush(QBrush(p));
 
1446
 
 
1447
        p = tempCurve->pen().color();
 
1448
        p.setAlpha(64);
 
1449
        tempCurve->setBrush(QBrush(p));
 
1450
 
 
1451
        p = torqueCurve->pen().color();
 
1452
        p.setAlpha(64);
 
1453
        torqueCurve->setBrush(QBrush(p));
 
1454
 
 
1455
        /*p = balanceLCurve->pen().color();
 
1456
        p.setAlpha(64);
 
1457
        balanceLCurve->setBrush(QBrush(p));
 
1458
 
 
1459
        p = balanceRCurve->pen().color();
 
1460
        p.setAlpha(64);
 
1461
        balanceRCurve->setBrush(QBrush(p));*/
 
1462
    } else {
 
1463
        wattsCurve->setBrush(Qt::NoBrush);
 
1464
        hrCurve->setBrush(Qt::NoBrush);
 
1465
        speedCurve->setBrush(Qt::NoBrush);
 
1466
        cadCurve->setBrush(Qt::NoBrush);
 
1467
        tempCurve->setBrush(Qt::NoBrush);
 
1468
        torqueCurve->setBrush(Qt::NoBrush);
 
1469
        //balanceLCurve->setBrush(Qt::NoBrush);
 
1470
        //balanceRCurve->setBrush(Qt::NoBrush);
 
1471
    }
817
1472
    replot();
818
1473
}
819
1474
 
821
1476
AllPlot::setSmoothing(int value)
822
1477
{
823
1478
    smooth = value;
824
 
    boost::shared_ptr<QSettings> settings = GetApplicationSettings();
825
 
    settings->setValue(GC_RIDE_PLOT_SMOOTHING, value);
826
1479
    recalc();
827
1480
}
828
1481
 
968
1621
 
969
1622
 
970
1623
size_t IntervalPlotData::size() const { return intervalCount()*4; }
971
 
QwtData *IntervalPlotData::copy() const {
972
 
    return new IntervalPlotData(allPlot, mainWindow);
 
1624
 
 
1625
QPointF IntervalPlotData::sample(size_t i) const {
 
1626
    return QPointF(x(i), y(i));
 
1627
}
 
1628
 
 
1629
QRectF IntervalPlotData::boundingRect() const
 
1630
{
 
1631
    return QRectF(-100, 5000, 5100, 5100);
973
1632
}
974
1633
 
975
1634
void
977
1636
{
978
1637
    if (index >= 0 && curve != intervalHighlighterCurve) {
979
1638
 
980
 
        double value = curve->y(index);
 
1639
        double yvalue = curve->sample(index).y();
 
1640
        double xvalue = curve->sample(index).x();
 
1641
 
 
1642
        QString xstring;
 
1643
        if (bydist) {
 
1644
            xstring = QString("%1").arg(xvalue);
 
1645
        } else {
 
1646
            QTime t = QTime().addSecs(xvalue*60.00);
 
1647
            xstring = t.toString("hh:mm:ss");
 
1648
        }
981
1649
 
982
1650
        // output the tooltip
983
 
        QString text = QString("%1 %2")
984
 
                        .arg(value, 0, 'f', 0)
985
 
                        .arg(this->axisTitle(curve->yAxis()).text());
 
1651
        QString text = QString("%1 %2\n%3 %4")
 
1652
                        .arg(yvalue, 0, 'f', 0)
 
1653
                        .arg(this->axisTitle(curve->yAxis()).text())
 
1654
                        .arg(xstring)
 
1655
                        .arg(this->axisTitle(curve->xAxis()).text());
986
1656
 
987
1657
        // set that text up
988
1658
        tooltip->setText(text);
993
1663
        tooltip->setText("");
994
1664
    }
995
1665
}
 
1666
 
 
1667
void
 
1668
AllPlot::nextStep( int& step )
 
1669
{
 
1670
    if( step < 50 )
 
1671
    {
 
1672
        step += 10;
 
1673
    }
 
1674
    else if( step == 50 )
 
1675
    {
 
1676
        step = 100;
 
1677
    }
 
1678
    else if( step >= 100 && step < 1000 )
 
1679
    {
 
1680
        step += 100;
 
1681
    }
 
1682
    else if( step >= 1000 && step < 5000)
 
1683
    {
 
1684
        step += 500;
 
1685
    }
 
1686
    else
 
1687
    {
 
1688
        step += 1000;
 
1689
    }
 
1690
}