Files
GoldenCheetah/src/SplitRideDialog.cpp
Andy Froncioni 79b6506004 Added headwind to Aerolab calculation for iAero
Added a headwind data field, which is available when using
an iAero head unit, to dramatically improve the calculation
of Chung analysis for users of more recent iAero devices.

All other data files than the iAero have the headwind term set to
zero when they append a point.
2010-03-06 13:11:36 -05:00

205 lines
6.9 KiB
C++

/*
* Copyright (c) 2009 Ned Harding (ned@hardinggroup.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 "SplitRideDialog.h"
#include "GcRideFile.h"
#include "MainWindow.h"
#include "RideFile.h"
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <QtGui>
#include <boost/scoped_ptr.hpp>
namespace
{
QString MakeTimeString(double secs)
{
QString strTime;
double mins = ((int) secs) / 60;
secs = secs - mins * 60.0;
double hrs = ((int) mins) / 60;
mins = mins - hrs * 60.0;
strTime.sprintf("%02.0f:%02.0f:%02.0f", hrs, mins, secs);
return strTime;
}
class ListItem_Split : public QListWidgetItem
{
public:
int m_nRecNum;
explicit ListItem_Split(int nRecNum, const QString &text, QListWidget *view)
: QListWidgetItem(text, view)
, m_nRecNum(nRecNum)
{
}
};
}
SplitRideDialog::SplitRideDialog(MainWindow *mainWindow)
: mainWindow(mainWindow)
{
setAttribute(Qt::WA_DeleteOnClose);
setWindowTitle("Split Ride");
listWidget = new QListWidget(this);
listWidget->setSelectionMode(QAbstractItemView::SingleSelection);
QLabel *splitLabel = new QLabel(tr("Split at the following positions:"), this);
QLabel *labelSpacer = new QLabel(this);
labelSpacer->setIndent(10);
okButton = new QPushButton(tr("&OK"), this);
cancelButton = new QPushButton(tr("&Cancel"), this);
connect(okButton, SIGNAL(clicked()), this, SLOT(okClicked()));
connect(cancelButton, SIGNAL(clicked()), this, SLOT(cancelClicked()));
connect(listWidget,
SIGNAL(itemSelectionChanged()), this, SLOT(selectionChanged()));
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addWidget(okButton);
buttonLayout->addWidget(cancelButton);
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->addWidget(splitLabel);
mainLayout->addWidget(listWidget);
mainLayout->addWidget(labelSpacer);
mainLayout->addLayout(buttonLayout);
const RideFile *ride = mainWindow->currentRide();
QMap<int,QString> splitPoints;
QList<RideFileInterval> intervals = ride->intervals();
if (!intervals.empty()) {
intervals.removeFirst();
foreach (RideFileInterval interval, intervals) {
int nDataPoint = ride->intervalBegin(interval);
QString strDesc = QString("Interval %1").arg(interval.name);
splitPoints.insert(nDataPoint, strDesc);
}
}
for (int nDataPoint = 1; nDataPoint < ride->dataPoints().size(); ++nDataPoint) {
const RideFilePoint *point = ride->dataPoints()[nDataPoint];
double dLastSeconds = ride->dataPoints()[nDataPoint - 1]->secs;
if ((point->secs-dLastSeconds)>=30 && !splitPoints.contains(nDataPoint)) {
QString strDesc = "Time Gap: " + MakeTimeString(point->secs-dLastSeconds);
splitPoints.insert(nDataPoint, strDesc);
}
}
QMapIterator<int,QString> i(splitPoints);
while (i.hasNext()) {
i.next();
int nDataPoint = i.key();
const RideFilePoint *point = ride->dataPoints()[nDataPoint];
QString strDesc = MakeTimeString(point->secs) + " - " + i.value();
ListItem_Split *pItem = new ListItem_Split(nDataPoint, strDesc, listWidget);
if (nDataPoint > 0) {
double dLastSeconds = ride->dataPoints()[nDataPoint - 1]->secs;
if ((point->secs-dLastSeconds)>20*60)
pItem->setCheckState(Qt::Checked);
else
pItem->setCheckState(Qt::Unchecked);
}
}
}
void
SplitRideDialog::cancelClicked()
{
reject();
}
void
SplitRideDialog::CreateNewRideFile(const RideFile *ride, int nRecStart, int nRecEnd)
{
QDateTime newStart = ride->startTime();
RideFilePoint *pointStart = ride->dataPoints().at(nRecStart);
newStart = newStart.addMSecs(static_cast<qint64>(pointStart->secs*1000 + 0.5));
boost::scoped_ptr<RideFile> newRideFile(new RideFile(newStart, ride->recIntSecs()));
for (int nItem = nRecStart; nItem<nRecEnd; ++nItem)
{
RideFilePoint *pPoint = ride->dataPoints().at(nItem);
newRideFile->appendPoint(pPoint->secs-pointStart->secs, pPoint->cad, pPoint->hr, pPoint->km - pointStart->km,
pPoint->kph, pPoint->nm, pPoint->watts, pPoint->alt, pPoint->lon, pPoint->lat, pPoint->headwind, pPoint->interval-pointStart->interval);
}
newRideFile->setDeviceType(ride->deviceType());
double endSecs = ride->dataPoints().at(nRecEnd - 1)->secs + ride->recIntSecs();
foreach (RideFileInterval interval, ride->intervals()) {
if ((interval.start >= pointStart->secs) && (interval.stop <= endSecs)) {
newRideFile->addInterval(interval.start - pointStart->secs,
interval.stop - pointStart->secs,
interval.name);
}
}
QString fileName;
fileName.sprintf("%04d_%02d_%02d_%02d_%02d_%02d.gc",
newStart.date().year(), newStart.date().month(),
newStart.date().day(), newStart.time().hour(), newStart.time().minute(),
newStart.time().second());
QString filePath = mainWindow->home.absolutePath() + "/" + fileName;
QFile file(filePath);
if (file.exists())
{
QMessageBox::critical(this, tr("Split Ride"), tr("The file %1 already exists and will not be overwritten").arg(filePath));
return;
}
newRideFile->writeAsCsv(file, true);
GcFileReader f;
f.writeRideFile(newRideFile.get(), file);
mainWindow->addRide(fileName, false);
}
void
SplitRideDialog::okClicked()
{
const RideFile *ride = mainWindow->currentRide();
int nStartPoint = 0;
for (int nRow=0; nRow<listWidget->count(); ++nRow)
{
const ListItem_Split *pItem = static_cast<const ListItem_Split *>(listWidget->item(nRow));
if (pItem->checkState()==Qt::Checked)
{
CreateNewRideFile(ride, nStartPoint, pItem->m_nRecNum);
nStartPoint = pItem->m_nRecNum;
}
}
if (nStartPoint!=0)
{
CreateNewRideFile(ride, nStartPoint, mainWindow->currentRide()->dataPoints().count());
mainWindow->removeCurrentRide();
}
done(0);
}
void
SplitRideDialog::selectionChanged()
{
}