From 7a0ed0792b53b8b3090091cb3703cf70ef776479 Mon Sep 17 00:00:00 2001 From: Mark Liversedge Date: Tue, 21 Apr 2020 10:49:01 +0100 Subject: [PATCH] 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. --- src/Core/DataFilter.cpp | 96 ++++++++++++++++++++++++++++++++++++++ src/Core/Specification.cpp | 7 +++ src/Core/Specification.h | 3 ++ 3 files changed, 106 insertions(+) diff --git a/src/Core/DataFilter.cpp b/src/Core/DataFilter.cpp index 72ce9784e..886627eca 100644 --- a/src/Core/DataFilter.cpp +++ b/src/Core/DataFilter.cpp @@ -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; gfunction == "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") { diff --git a/src/Core/Specification.cpp b/src/Core/Specification.cpp index afddac011..2ff0ddb3c 100644 --- a/src/Core/Specification.cpp +++ b/src/Core/Specification.cpp @@ -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) diff --git a/src/Core/Specification.h b/src/Core/Specification.h index e0d71758b..0ed0e9a8c 100644 --- a/src/Core/Specification.h +++ b/src/Core/Specification.h @@ -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*);