Files
GoldenCheetah/src/IntervalItem.cpp

307 lines
9.5 KiB
C++

/*
* Copyright (c) 2009 Mark Liversedge (liversedge@gmail.com)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "IntervalItem.h"
#include "RideFile.h"
#include "Context.h"
#include "Athlete.h"
#include "ColorButton.h"
IntervalItem::IntervalItem(const RideItem *ride, QString name, double start, double stop,
double startKM, double stopKM, int displaySequence, QColor color,
RideFileInterval::IntervalType type)
{
this->name = name;
this->start = start;
this->stop = stop;
this->startKM = startKM;
this->stopKM = stopKM;
this->displaySequence = displaySequence;
this->type = type;
this->color = color;
this->selected = false;
this->rideInterval = NULL;
this->rideItem_ = const_cast<RideItem*>(ride);
metrics_.fill(0, RideMetricFactory::instance().metricCount());
}
IntervalItem::IntervalItem() : rideItem_(NULL), name(""), type(RideFileInterval::USER), start(0), stop(0),
startKM(0), stopKM(0), displaySequence(0), color(Qt::black), rideInterval(NULL)
{
metrics_.fill(0, RideMetricFactory::instance().metricCount());
}
void
IntervalItem::setFrom(IntervalItem &other)
{
*this = other;
rideInterval = NULL;
selected = false;
}
void
IntervalItem::setValues(QString name, double duration1, double duration2,
double distance1, double distance2)
{
// apply the update
this->name = name;
start = duration1;
stop = duration2;
startKM = distance1;
stopKM = distance2;
// only accept changes if we can send on
if (type == RideFileInterval::USER && rideInterval) {
// update us and our ridefileinterval
rideInterval->start = start = duration1;
rideInterval->stop = stop = duration2;
startKM = distance1;
stopKM = distance2;
// update ridefile
rideItem_->setDirty(true);
}
// update metrics
refresh();
}
void
IntervalItem::refresh()
{
// don't open on our account - we should be called with a ride available
RideFile *f = rideItem_->ride_;
if (!f) return;
// create a temporary ride
RideFile intervalRide(f);
for (int i = f->intervalBeginSecs(start); i>= 0 &&i < f->dataPoints().size(); ++i) {
// iterate
const RideFilePoint *p = f->dataPoints()[i];
if (p->secs+f->recIntSecs() > stop) break;
// append all values
intervalRide.appendPoint(p->secs, p->cad, p->hr, p->km, p->kph, p->nm,
p->watts, p->alt, p->lon, p->lat, p->headwind,
p->slope, p->temp, p->lrbalance,
p->lte, p->rte, p->lps, p->rps,
p->lpco, p->rpco, p->lppb, p->rppb, p->lppe, p->rppe, p->lpppb, p->rpppb, p->lpppe, p->rpppe,
p->smo2, p->thb, p->rvert, p->rcad, p->rcontact, p->tcore, 0);
// copy derived data
RideFilePoint *l = intervalRide.dataPoints().last();
l->np = p->np;
l->xp = p->xp;
l->apower = p->apower;
}
// we created a blank ride (?)
if (intervalRide.dataPoints().size() == 0) return;
// ok, lets collect the metrics
const RideMetricFactory &factory = RideMetricFactory::instance();
QHash<QString,RideMetricPtr> computed= RideMetric::computeMetrics(rideItem_->context, &intervalRide, rideItem_->context->athlete->zones(),
rideItem_->context->athlete->hrZones(), factory.allMetrics());
// pack the metrics away and clean up if needed
metrics_.fill(0, factory.metricCount());
// snaffle away all the computed values into the array
QHashIterator<QString, RideMetricPtr> i(computed);
while (i.hasNext()) {
i.next();
metrics_[i.value()->index()] = i.value()->value();
}
// clean any bad values
for(int j=0; j<factory.metricCount(); j++)
if (std::isinf(metrics_[j]) || std::isnan(metrics_[j]))
metrics_[j] = 0.00f;
}
double
IntervalItem::getForSymbol(QString name, bool useMetricUnits)
{
if (metrics_.size()) {
// return the precomputed metric value
const RideMetricFactory &factory = RideMetricFactory::instance();
const RideMetric *m = factory.rideMetric(name);
if (m) {
if (useMetricUnits) return metrics_[m->index()];
else {
// little hack to set/get for conversion
const_cast<RideMetric*>(m)->setValue(metrics_[m->index()]);
return m->value(useMetricUnits);
}
}
}
return 0.0f;
}
QString
IntervalItem::getStringForSymbol(QString name, bool useMetricUnits)
{
QString returning("-");
if (metrics_.size()) {
// return the precomputed metric value
const RideMetricFactory &factory = RideMetricFactory::instance();
const RideMetric *m = factory.rideMetric(name);
if (m) {
double value = metrics_[m->index()];
if (std::isinf(value) || std::isnan(value)) value=0;
const_cast<RideMetric*>(m)->setValue(value);
returning = m->toString(useMetricUnits);
}
}
return returning;
}
/*----------------------------------------------------------------------
* Edit Interval dialog
*--------------------------------------------------------------------*/
EditIntervalDialog::EditIntervalDialog(QWidget *parent, IntervalItem &interval) :
QDialog(parent, Qt::Dialog), interval(interval)
{
setWindowTitle(tr("Edit Interval"));
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->setSpacing(5);
// Grid
QGridLayout *grid = new QGridLayout;
QLabel *name = new QLabel("Name");
QLabel *from = new QLabel("From");
QLabel *to = new QLabel("To");
QLabel *color = new QLabel("Color");
nameEdit = new QLineEdit(this);
nameEdit->setText(interval.name);
if (interval.type == RideFileInterval::USER) {
fromEdit = new QTimeEdit(this);
fromEdit->setDisplayFormat("hh:mm:ss");
fromEdit->setTime(QTime(0,0,0,0).addSecs(interval.start));
toEdit = new QTimeEdit(this);
toEdit->setDisplayFormat("hh:mm:ss");
toEdit->setTime(QTime(0,0,0,0).addSecs(interval.stop));
colorEdit = new ColorButton(this, interval.name, interval.color);
colorEdit->setAutoDefault(false);
}
grid->addWidget(name, 0,0);
grid->addWidget(nameEdit, 0,1);
if (interval.type == RideFileInterval::USER) {
grid->addWidget(from, 1,0);
grid->addWidget(fromEdit, 1,1);
grid->addWidget(to, 2,0);
grid->addWidget(toEdit, 2,1);
grid->addWidget(color, 3,0);
grid->addWidget(colorEdit, 3,1);
}
mainLayout->addLayout(grid);
// Buttons
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addStretch();
applyButton = new QPushButton(tr("&OK"), this);
cancelButton = new QPushButton(tr("&Cancel"), this);
buttonLayout->addWidget(cancelButton);
buttonLayout->addWidget(applyButton);
mainLayout->addLayout(buttonLayout);
// connect up slots
connect(applyButton, SIGNAL(clicked()), this, SLOT(applyClicked()));
connect(cancelButton, SIGNAL(clicked()), this, SLOT(cancelClicked()));
}
void
EditIntervalDialog::applyClicked()
{
// get the values back
interval.name = nameEdit->text();
if (interval.rideInterval != NULL) {
interval.start = QTime(0,0,0).secsTo(fromEdit->time());
interval.stop = QTime(0,0,0).secsTo(toEdit->time());
interval.color = colorEdit->getColor();
}
accept();
}
void
EditIntervalDialog::cancelClicked()
{
reject();
}
/*----------------------------------------------------------------------
* Interval rename dialog
*--------------------------------------------------------------------*/
RenameIntervalDialog::RenameIntervalDialog(QString &string, QWidget *parent) :
QDialog(parent, Qt::Dialog), string(string)
{
setWindowTitle(tr("Rename Intervals"));
QVBoxLayout *mainLayout = new QVBoxLayout(this);
// Grid
QGridLayout *grid = new QGridLayout;
QLabel *name = new QLabel("Name");
nameEdit = new QLineEdit(this);
nameEdit->setText(string);
grid->addWidget(name, 0,0);
grid->addWidget(nameEdit, 0,1);
mainLayout->addLayout(grid);
// Buttons
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addStretch();
applyButton = new QPushButton(tr("&OK"), this);
cancelButton = new QPushButton(tr("&Cancel"), this);
buttonLayout->addWidget(cancelButton);
buttonLayout->addWidget(applyButton);
mainLayout->addLayout(buttonLayout);
// connect up slots
connect(applyButton, SIGNAL(clicked()), this, SLOT(applyClicked()));
connect(cancelButton, SIGNAL(clicked()), this, SLOT(cancelClicked()));
}
void
RenameIntervalDialog::applyClicked()
{
// get the values back
string = nameEdit->text();
accept();
}
void
RenameIntervalDialog::cancelClicked()
{
reject();
}