Split Ride.

It offers to split at any time gap over 30 seconds and also at any interval.  
If the time gap is over 5 minutes it defaults to checked, otherwise it 
defaults to unchecked.

Anywhere you check, it will split the ride at that point overwriting the or
original ride with a shorter one and creating new rides after the split points
 The original would get renamed with a .bak so it could be recovered.
This commit is contained in:
Justin F. Knotzke
2009-04-06 01:01:17 +00:00
parent 3db61084a1
commit 21d5576393
6 changed files with 118 additions and 51 deletions

View File

@@ -44,6 +44,7 @@
#include "DatePickerDialog.h"
#include "ToolsDialog.h"
#include "SplitRideDialog.h"
/* temp for the qmake/QMAKE_CXXFLAGS bug with xcode */
#ifndef GC_SVN_VERSION
@@ -55,7 +56,6 @@
#define FOLDER_TYPE 0
#define RIDE_TYPE 1
#define MILES_PER_KM 0.62137119
static char *rideFileRegExp = ("^(\\d\\d\\d\\d)_(\\d\\d)_(\\d\\d)"
"_(\\d\\d)_(\\d\\d)_(\\d\\d)\\.(raw|srm|csv|tcx)$");
@@ -401,8 +401,10 @@ MainWindow::MainWindow(const QDir &home) :
SLOT (importCSV()), tr ("Ctrl+S"));
rideMenu->addAction(tr("&Import from TCX..."), this,
SLOT (importTCX()));
rideMenu->addAction(tr("Find &best intervals..."), this,
SLOT(findBestIntervals()), tr ("Ctrl+B"));
rideMenu->addAction(tr("Find &best intervals..."), this,
SLOT(findBestIntervals()), tr ("Ctrl+B"));
rideMenu->addAction(tr("Split &ride..."), this,
SLOT(splitRide()));
QMenu *optionsMenu = menuBar()->addMenu(tr("&Tools"));
optionsMenu->addAction(tr("&Options..."), this,
SLOT(showOptions()), tr("Ctrl+O"));
@@ -431,7 +433,7 @@ MainWindow::MainWindow(const QDir &home) :
}
void
MainWindow::addRide(QString name)
MainWindow::addRide(QString name, bool bSelect /*=true*/)
{
QRegExp rx(rideFileRegExp);
if (!rx.exactMatch(name)) {
@@ -468,8 +470,51 @@ MainWindow::addRide(QString name)
}
allRides->insertChild(index, last);
cpintPlot->needToScanRides = true;
if (bSelect)
{
tabWidget->setCurrentIndex(0);
treeWidget->setCurrentItem(last);
}
}
void
MainWindow::removeCurrentRide()
{
QTreeWidgetItem *_item = treeWidget->currentItem();
if (_item->type() != RIDE_TYPE)
return;
RideItem *item = reinterpret_cast<RideItem*>(_item);
QTreeWidgetItem *itemToSelect = NULL;
for (int x=0; x<allRides->childCount(); ++x)
{
if (item==allRides->child(x))
{
if ((x+1)<allRides->childCount())
itemToSelect = allRides->child(x+1);
else if (x>0)
itemToSelect = allRides->child(x-1);
break;
}
}
QString strOldFileName = item->fileName;
allRides->removeChild(item);
delete item;
QFile file(home.absolutePath() + "/" + strOldFileName);
// purposefully don't remove the old ext so the user wouldn't have to figure out what the old file type was
QString strNewName = strOldFileName + ".bak";
if (!file.rename(home.absolutePath() + "/" + strNewName))
{
QMessageBox::critical(
this, "Rename Error",
tr("Can't rename %1 to %2")
.arg(strOldFileName).arg(strNewName));
}
tabWidget->setCurrentIndex(0);
treeWidget->setCurrentItem(last);
treeWidget->setCurrentItem(itemToSelect);
}
void
@@ -546,50 +591,13 @@ MainWindow::exportCSV()
return;
QFile file(fileName);
// QFileDialog::getSaveFileName checks whether the file exists.
if (!file.open(QFile::WriteOnly | QFile::Truncate)) {
QMessageBox::critical(
this, tr("Open Error"),
tr("Can't open %1 for writing").arg(fileName));
if (!file.open(QFile::WriteOnly | QFile::Truncate))
{
QMessageBox::critical(this, tr("Split Ride"), tr("The file %1 can't be opened for writing").arg(fileName));
return;
}
// Use the column headers that make WKO+ happy.
double convertUnit;
QTextStream out(&file);
if (units=="English"){
out << "Minutes,Torq (N-m),MPH,Watts,Miles,Cadence,Hrate,ID\n";
convertUnit = MILES_PER_KM;
}
else {
out << "Minutes,Torq (N-m),Km/h,Watts,Km,Cadence,Hrate,ID\n";
// TODO: use KM_TO_MI from lib/pt.c instead?
convertUnit = 1.0;
}
QListIterator<RideFilePoint*> i(ride->ride->dataPoints());
while (i.hasNext()) {
RideFilePoint *point = i.next();
if (point->secs == 0.0)
continue;
out << point->secs/60.0;
out << ",";
out << ((point->nm >= 0) ? point->nm : 0.0);
out << ",";
out << ((point->kph >= 0) ? (point->kph * convertUnit) : 0.0);
out << ",";
out << ((point->watts >= 0) ? point->watts : 0.0);
out << ",";
out << point->km * convertUnit;
out << ",";
out << point->cad;
out << ",";
out << point->hr;
out << ",";
out << point->interval << "\n";
}
file.close();
ride->ride->writeAsCsv(file, units!="English");
}
void MainWindow::importCSV()
@@ -1175,4 +1183,9 @@ void MainWindow::showTools()
td->exec();
}
void
MainWindow::splitRide()
{
(new SplitRideDialog(this))->exec();
}

View File

@@ -38,7 +38,8 @@ class MainWindow : public QMainWindow
public:
MainWindow(const QDir &home);
void addRide(QString name);
void addRide(QString name, bool bSelect=true);
void removeCurrentRide();
const RideFile *currentRide();
QDir home;
protected:
@@ -57,6 +58,7 @@ class MainWindow : public QMainWindow
void importSRM();
void importTCX();
void findBestIntervals();
void splitRide();
void setSmoothingFromSlider();
void setSmoothingFromLineEdit();
void setBinWidthFromSlider();

View File

@@ -61,6 +61,12 @@ static void
time_cb(struct tm *, time_t since_epoch, void *context)
{
ReadState *state = (ReadState*) context;
if (state->rideFile->startTime().isNull())
{
QDateTime t;
t.setTime_t(since_epoch);
state->rideFile->setStartTime(t);
}
if (state->start_since_epoch == 0)
state->start_since_epoch = since_epoch;
double secs = since_epoch - state->start_since_epoch;

View File

@@ -104,6 +104,49 @@ RideFile::writeAsXml(QFile &file, QString &err)
return true;
}
void RideFile::writeAsCsv(QFile &file, bool bIsMetric) const
{
// Use the column headers that make WKO+ happy.
double convertUnit;
QTextStream out(&file);
if (!bIsMetric)
{
out << "Minutes,Torq (N-m),MPH,Watts,Miles,Cadence,Hrate,ID\n";
const double MILES_PER_KM = 0.62137119;
convertUnit = MILES_PER_KM;
}
else {
out << "Minutes,Torq (N-m),Km/h,Watts,Km,Cadence,Hrate,ID\n";
// TODO: use KM_TO_MI from lib/pt.c instead?
convertUnit = 1.0;
}
QListIterator<RideFilePoint*> i(dataPoints());
while (i.hasNext()) {
RideFilePoint *point = i.next();
if (point->secs == 0.0)
continue;
out << point->secs/60.0;
out << ",";
out << ((point->nm >= 0) ? point->nm : 0.0);
out << ",";
out << ((point->kph >= 0) ? (point->kph * convertUnit) : 0.0);
out << ",";
out << ((point->watts >= 0) ? point->watts : 0.0);
out << ",";
out << point->km * convertUnit;
out << ",";
out << point->cad;
out << ",";
out << point->hr;
out << ",";
out << point->interval << "\n";
}
file.close();
}
RideFileFactory *RideFileFactory::instance_;
RideFileFactory &RideFileFactory::instance()
@@ -149,4 +192,3 @@ QStringList RideFileFactory::listRideFiles(const QDir &dir) const
}
return dir.entryList(filters, QDir::Files, QDir::Name|QDir::Reversed);
}

View File

@@ -90,6 +90,7 @@ class RideFile
}
bool writeAsXml(QFile &file, QString &err);
void writeAsCsv(QFile &file, bool bIsMetric) const;
};
struct RideFileReader {

View File

@@ -16,7 +16,7 @@ RC_FILE = images/gc.icns
macx {
LIBS += -framework Carbon
QMAKE_MAC_SDK=/Developer/SDKs/MacOSX10.4u.sdk
CONFIG+=x86 ppc
CONFIG+=x86
}
win32 {
@@ -64,7 +64,9 @@ HEADERS += \
Serial.h \
ToolsDialog.h \
Zones.h \
srm.h
srm.h \
SplitRideDialog.h
SOURCES += \
AllPlot.cpp \
@@ -98,7 +100,8 @@ SOURCES += \
ToolsDialog.cpp \
Zones.cpp \
main.cpp \
srm.cpp
srm.cpp \
SplitRideDialog.cpp
RESOURCES = application.qrc