Files
GoldenCheetah/src/Metrics/PaceZones.h
Joachim Kohlhammer a5829c5c13 Semi automatic creation of ranges for power zones (#4543)
* 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
2024-10-17 18:12:15 -03:00

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