mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-04-13 12:42:20 +00:00
* Changed the UI of CPPage to inline-editing of all values in all tables * Added a sports-specific selector for the model (cp2, cp3, ext, manual) * Allowed to create new ranges either manually or based on the estimated values of the model * Added option to reset each ranges values to those of the selected model * Added message to create a new range if todays estimate differs from those of the currently active one * Refined semi automatic power zones * Added a dialog to inspect and accept only some values while adoption * Added info messages * when the model does not provide FTP or PMAX * that AeTP is only a very rough estimate * Added a tolerance in comparison before proposing new values * Using the following order for defaults when adding a new manual range * selected row * last row * predefined defaults * Zones-Tab: To prevent crashes, a message is shown instead of the real interface if a metric refresh is ongoing * Changed Pace- and HR-Tabs to use inline editing * Moved the unittests into the same structure as the sourcecode * Added a simple (incomplete) unittest for kphToPace * Improved setting the column width * En-/Disabling the action buttons (add, delete, ...) based on the contents state * Changed the layout to prevent jumping widgets when showing / hiding buttons * Fixed compiler warnings from Visual-C++ * Adopt dialog: Refined layout * Fixed the unit of "From BPM" on HR-Page * Set the default mode to manual Fixes #1381
230 lines
7.5 KiB
C++
230 lines
7.5 KiB
C++
/*
|
|
* Copyright (c) 2006 Sean C. Rhea (srhea@srhea.net)
|
|
* Copyright (c) 2014 Mark Liversedge (liversedge@gmail.com)
|
|
*
|
|
* [mostly cut and paste from Zones.cpp]
|
|
*
|
|
* 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
|
|
*/
|
|
|
|
#ifndef _PaceZones_h
|
|
#define _PaceZones_h
|
|
#include "GoldenCheetah.h"
|
|
#include "Context.h"
|
|
#include "Athlete.h"
|
|
|
|
#include <QtCore>
|
|
|
|
// A zone "scheme" defines how power zones
|
|
// are calculated as a percentage of CV
|
|
// The default is to use Coggan percentages
|
|
// but this can be overriden in power.zones
|
|
struct PaceZoneScheme {
|
|
QList <int> zone_default;
|
|
QList <bool> zone_default_is_pct;
|
|
QList <QString> zone_default_name;
|
|
QList <QString> zone_default_desc;
|
|
int nzones_default;
|
|
};
|
|
|
|
// A zone "info" defines a *single zone*
|
|
// in absolute watts terms e.g.
|
|
// "L4" "Threshold" is between 270w and 315w
|
|
struct PaceZoneInfo {
|
|
QString name, desc;
|
|
double lo, hi;
|
|
PaceZoneInfo(const QString &n, const QString &d, double l, double h) :
|
|
name(n), desc(d), lo(l), hi(h) {}
|
|
|
|
// used by std::sort
|
|
bool operator< (PaceZoneInfo right) const {
|
|
return ((lo < right.lo) || ((lo == right.lo) && (hi < right.hi)));
|
|
}
|
|
};
|
|
|
|
// A zone "range" defines the power zones
|
|
// that are active for a *specific date period*
|
|
// e.g. between 01/01/2008 and 01/04/2008
|
|
// my CV was 290 and I chose to setup
|
|
// 7 zoneinfos from Active Recovery through
|
|
// to muscular Endurance
|
|
struct PaceZoneRange {
|
|
QDate begin, end;
|
|
double cv;
|
|
double aet;
|
|
QList<PaceZoneInfo> zones;
|
|
bool zonesSetFromCV;
|
|
PaceZoneRange(const QDate &b, const QDate &e) :
|
|
begin(b), end(e), cv(0), aet(0), zonesSetFromCV(false) {}
|
|
PaceZoneRange(const QDate &b, const QDate &e, double _cv, double _aet) :
|
|
begin(b), end(e), cv(_cv), aet(_aet), zonesSetFromCV(false) {}
|
|
|
|
// used by std::sort
|
|
bool operator< (PaceZoneRange right) const {
|
|
return (((! right.begin.isNull()) &&
|
|
(begin.isNull() || begin < right.begin )) ||
|
|
((begin == right.begin) && (! end.isNull()) &&
|
|
( right.end.isNull() || end < right.end )));
|
|
}
|
|
};
|
|
|
|
|
|
class PaceZones : public QObject
|
|
{
|
|
Q_OBJECT
|
|
G_OBJECT
|
|
|
|
|
|
private:
|
|
|
|
// Sport
|
|
bool swim;
|
|
|
|
// Scheme
|
|
bool defaults_from_user;
|
|
PaceZoneScheme scheme;
|
|
|
|
// CV History
|
|
QList<PaceZoneRange> ranges;
|
|
|
|
// utility
|
|
QString err, warning, fileName_;
|
|
void setZonesFromCV(PaceZoneRange &range);
|
|
|
|
public:
|
|
|
|
PaceZones(bool swim=false) : swim(swim), defaults_from_user(false) {
|
|
initializeZoneParameters();
|
|
}
|
|
|
|
//
|
|
// Zone settings - Scheme (& default scheme)
|
|
//
|
|
PaceZoneScheme getScheme() const { return scheme; }
|
|
void setScheme(PaceZoneScheme x) { scheme = x; }
|
|
|
|
// get defaults from the current scheme
|
|
QString getDefaultZoneName(int z) const;
|
|
QString getDefaultZoneDesc(int z) const;
|
|
|
|
// set zone parameters to either user-specified defaults
|
|
// or to defaults using Skiba's coefficients
|
|
void initializeZoneParameters();
|
|
|
|
// Sport
|
|
bool isSwim() { return swim; }
|
|
|
|
//
|
|
// Zone history - Ranges
|
|
//
|
|
// How many ranges in our history
|
|
int getRangeSize() const;
|
|
|
|
// Add ranges
|
|
void addZoneRange(QDate _start, QDate _end, double _cv, double _aet);
|
|
int addZoneRange(QDate _start, double _cv, double _aet);
|
|
void addZoneRange();
|
|
|
|
// Get / Set ZoneRange details
|
|
PaceZoneRange getZoneRange(int rnum) { return ranges[rnum]; }
|
|
void setZoneRange(int rnum, PaceZoneRange x) { ranges[rnum] = x; }
|
|
|
|
// get and set CV for a given range
|
|
double getCV(int rnum) const;
|
|
void setCV(int rnum, double cv);
|
|
|
|
// get and set AeT for a given range
|
|
double getAeT(int rnum) const;
|
|
void setAeT(int rnum, double aet);
|
|
|
|
// calculate and then set zoneinfo for a given range
|
|
void setZonesFromCV(int rnum);
|
|
|
|
// delete the range rnum, and adjust dates on adjacent zone; return
|
|
// the range number of the range extended to cover the deleted zone
|
|
int deleteRange(const int rnum);
|
|
|
|
//
|
|
// read and write power.zones
|
|
//
|
|
bool read(QFile &file);
|
|
void write(QDir home);
|
|
const QString &fileName() const { return fileName_; }
|
|
const QString &errorString() const { return err; }
|
|
const QString &warningString() const { return warning; }
|
|
|
|
|
|
//
|
|
// Typical APIs to get details of ranges and zones
|
|
//
|
|
|
|
// which range is active for a particular date
|
|
int whichRange(const QDate &date) const;
|
|
|
|
// which zone is the power value in for a given range
|
|
// will return -1 if not in any zone
|
|
int whichZone(int range, double value) const;
|
|
|
|
// how many zones are there for a given range
|
|
int numZones(int range) const;
|
|
|
|
// get zoneinfo for a given range and zone
|
|
void zoneInfo(int range, int zone,
|
|
QString &name, QString &description,
|
|
double &low, double &high) const;
|
|
|
|
QString summarize(int rnum, QVector<double> &time_in_zone, QColor color = QColor(Qt::darkGray)) const;
|
|
|
|
// get all highs/lows for zones (plot shading uses these)
|
|
int lowsFromCV(QList <double> *lows, double CV) const;
|
|
QList <double> getZoneLows(int rnum) const;
|
|
QList <double> getZoneHighs(int rnum) const;
|
|
QList <QString> getZoneNames(int rnum) const;
|
|
|
|
// get/set range start and end date
|
|
QDate getStartDate(int rnum) const;
|
|
QDate getEndDate(int rnum) const;
|
|
QString getStartDateString(int rnum) const;
|
|
QString getEndDateString(int rnum) const;
|
|
void setEndDate(int rnum, QDate date);
|
|
void setStartDate(int rnum, QDate date);
|
|
|
|
// When was this last updated?
|
|
QDateTime modificationTime;
|
|
|
|
// calculate a CRC for the zones data - used to see if zones
|
|
// data is changed since last referenced in Metric code
|
|
// could also be used in Configuration pages (later)
|
|
quint16 getFingerprint() const;
|
|
|
|
// this is the fingerprint for a specific DATE so that we
|
|
// can be more granular -- did the zone config for the date of
|
|
// a particular ride change ?
|
|
quint16 getFingerprint(QDate date) const;
|
|
|
|
// convert to/from Pace
|
|
double kphFromTime(QTimeEdit *cvedit, bool metric) const;
|
|
double kphFromTime(const QTime &time, bool metric) const;
|
|
QString kphToPaceString(double kph, bool metric) const;
|
|
QTime kphToPaceTime(double kph, bool metric) const;
|
|
QString paceUnits(bool metric) const;
|
|
QString paceSetting() const;
|
|
static bool isPaceUnit(QString unit);
|
|
};
|
|
|
|
QColor paceZoneColor(int zone, int num_zones);
|
|
|
|
#endif // _PaceZones_h
|