Datafilter vectors - measures()

.. measure("group", "field|date") - get the measures or dates of the
   measures.

.. enables us to work with measurements independent of activies, but
   we probably need a way of controlling interpolation so we can
   get a vector that only contains measurement points.
This commit is contained in:
Mark Liversedge
2020-04-21 10:49:01 +01:00
parent 1167cdd582
commit 7a0ed0792b
3 changed files with 106 additions and 0 deletions

View File

@@ -217,6 +217,10 @@ static struct {
{ "cumsum", 1 }, // cumsum(v) - returns a vector of cumulative sum for vector v
{ "measures", 2 }, // measures(group, field|date) - returns vector of measures; where group
// is the class of measures e.g. "Hrv" or "Body", and field is the field
// name you want to retrieve e.g. "WeightKg" for "Body" and "RMSSD" for "Hrv"
// add new ones above this line
{ "", -1 }
@@ -376,6 +380,17 @@ DataFilter::builtins()
returning << "cumsum(vector)";
} else if (i == 74) {
Measures measures = Measures();
QStringList groupSymbols = measures.getGroupSymbols();
for (int g=0; g<groupSymbols.count(); g++) {
QStringList fields = measures.getFieldSymbols(g);
fields.insert(0, "date");
foreach (QString fieldSymbol, fields)
returning << QString("measures(\"%1\", \"%2\")").arg(groupSymbols[g]).arg(fieldSymbol);
}
} else {
QString function;
@@ -1571,6 +1586,43 @@ void Leaf::validateFilter(Context *context, DataFilterRuntime *df, Leaf *leaf)
DataFiltererrors << QString(tr("too many parameters: metrics(symbol|date, start, stop)"));
}
} else if (leaf->function == "measures") {
if (leaf->fparms.count() != 2) {
leaf->inerror = true;
DataFiltererrors << QString(tr("measures(group, field) - must have group and field parameters."));
} else {
// check first field is group...
int group=-1;
QString group_symbol;
if (leaf->fparms[0]->type != String) {
leaf->inerror = true;
DataFiltererrors << QString(tr("measures group must be a string."));
} else {
group_symbol = *(leaf->fparms[0]->lvalue.s);
group = context->athlete->measures->getGroupSymbols().indexOf(group_symbol);
if (group < 0) {
leaf->inerror = true;
DataFiltererrors << QString(tr("invalid measures group '%1'.").arg(group_symbol));
}
}
// check second field is valid...
if (leaf->fparms[1]->type != String) {
leaf->inerror = true;
DataFiltererrors << QString(tr("measures field must be a string."));
} else if (group >=0) {
QString field_symbol = *(leaf->fparms[1]->lvalue.s);
int field = context->athlete->measures->getFieldSymbols(group).indexOf(field_symbol);
if (field < 0 && field_symbol != "date") {
leaf->inerror = true;
DataFiltererrors << QString(tr("invalid measures field '%1' for group '%2'.").arg(field_symbol).arg(group_symbol));
}
}
}
} else if (leaf->function == "sort") {
if (leaf->fparms.count() < 2) {
@@ -2910,6 +2962,50 @@ Result Leaf::eval(DataFilterRuntime *df, Leaf *leaf, float x, long it, RideItem
return returning;
}
// measures
if (leaf->function == "measures") {
Result returning(0);
QDate earliest(1900,01,01);
bool wantdate=false;
FilterSet fs;
fs.addFilter(m->context->isfiltered, m->context->filters);
fs.addFilter(m->context->ishomefiltered, m->context->homeFilters);
Specification spec;
spec.setFilterSet(fs);
spec.setDateRange(d); // fallback to daterange selected
// group number
QString group_symbol = *(leaf->fparms[0]->lvalue.s);
int group = m->context->athlete->measures->getGroupSymbols().indexOf(group_symbol);
// field number -- -1 means its date
QString field_symbol = *(leaf->fparms[1]->lvalue.s);
int field = m->context->athlete->measures->getFieldSymbols(group).indexOf(field_symbol);
if (field < 0) wantdate = true;
// what dates do we have measures for ?
QDate firstDate = m->context->athlete->measures->getStartDate(group);
QDate lastDate = m->context->athlete->measures->getEndDate(group);
// get measures
if (firstDate == QDate() || lastDate == QDate()) return returning;
for(QDate date=firstDate; date <= lastDate; date=date.addDays(1)) {
if (!spec.pass(date)) continue;
double value;
if (wantdate) value = earliest.daysTo(date);
else value = m->context->athlete->measures->getFieldValue(group,date,field);
returning.number += value;
returning.vector << value;
}
return returning;
}
// meanmax array
if (leaf->function == "meanmax") {

View File

@@ -25,6 +25,13 @@ Specification::Specification(DateRange dr, FilterSet fs) : dr(dr), fs(fs), it(NU
Specification::Specification(IntervalItem *it, double recintsecs) : it(it), recintsecs(recintsecs), ri(NULL) {}
Specification::Specification() : it(NULL), recintsecs(0), ri(NULL) {}
// does the date pass the specification ?
bool
Specification::pass(QDate date)
{
return (dr.pass(date));
}
// does the rideitem pass the specification ?
bool
Specification::pass(RideItem*item)

View File

@@ -83,6 +83,9 @@ class Specification
Specification(IntervalItem *it, double recintsecs);
Specification();
// does the date pass the specification ?
bool pass(QDate);
// does the rideitem pass the specification ?
bool pass(RideItem*);