.. Added if else logic but could not avoid
needing the statement to be terminated with a
semi-colon (;)
.. so examples are:
if (TSS>100) TSS; else 0;
if (TSS>100) {
temp <- TSS;
temp;
} else {
temp <- BikeScore;
temp;
}
.. Doesn't add much beyond the existing conditional statement
using '?' and ':' but is a lot more readable (!)
.. You can now use compound statements in data filters
.. A compound statement is:
{ s1; } evaluates to s1
{ s1; s2; s3; .. sn; } evaluates to sn
.. It is possible to use the recently added user defined
symbols to build up processing logic:
{ temp <- TSS; temp > 100 }
is functionally equivalent to
TSS > 100
.. At present there are no control statements outside of
the ? and ?: operators but these will no doubt be added
in due course.
.. allow users to introduce their own symbols
into a datafilter with:
symbol <- expression
Which will initialise symbol and evaluate it
with the expression. The symbol can override
a metric name, but that would be rather dumb!
.. x ?: y
Evaluates to x if it is non-zero, otherwise it
evaluates to y. y is only evaluated once and only
if x is zero. Similarly, x is only evaluated once
and returned if it is non-zero.
.. allow users to use a set command to add
an override or set metadata under certain
conditions.
e.g. set(Workout_Code, "HT", IF>0.9)
set(TSS, 65, TSS <= 0 && Route = "Fave Loop")
.. we should probably add an unset() command
to do the reverse and clear values under
conditions too.
USE WITH CAUTION -- TAKE A BACKUP BEFORE
MAKING ANY RADICAL CHANGES TO YOUR DATA
.. passed to eval and symbols now recongised.
.. sample data is referenced using symbol names
in all caps to make it clear you are referencing
ride dample data.
.. the next commits will add defining formulas and plotting
the derived data series in allplot.
.. To select in a vector. The notation
is a selection criteria followed by
a list of values / vectors
e.g. which(x>0, TSS[date:date])
will create a vector where TSS is non
zero for the day.
"x" is replaced with the vector values
and as such is a special symbol.
.. also fixed a bug with the snip cache.
.. when running a formula it may use a vector
operation to calculate e.g. an average for the
date range.
.. these get called for every ride, but actually they
perform the same calculation over and over
.. we cache the vector operation and result to avoid
repeated calculations; these are only cached whilst
a datafilter is being evaluated, so we do not need
to worry about stale/refreshing.
.. estimate(model, duration) or to get the model
parameters estimate(model, parameter) always
for the date of the ride.
e.g. estimate(2p, cp) gets the estimated CP
for the date of the ride using the classic
2 parameter model
Models are one of;
2p - classic monod scherrer
3p - morton 3p
ext - gc extended
ws - ward-smith
velo - veloclinic
Parameters are one of;
w' - W'
cp - critical power
ftp - functional threshold power
pmax - max power
For watts per kilo just add / config(weight)
or Athlete_Weight to take into account ride
specific weight settings / overrides.
.. can now use a formula in the lts, sts
sb, rr functions.
.. e.g lts(TSS/2) evaluates to the "CTL"
value for the ride if using TSS/2 as
the input.
NOTE: you only get a value where a ride
exists. We may want to think about the
way we scope formulas; are they iterating
over rides or dates ?
.. to use when e.g. using a data filter as an input
into the PMC functions. The data series is stored
against a signature for the function as opposed to
the metric symbol.
.. we need to do it for an expr not the data filter
.. to use when e.g. using a data filter as an input
into the PMC functions. The data series is stored
against a signature for the function as opposed to
the metric symbol.
.. but do continue to highlight bad symbols etc
with a red wavy line.
.. still need to;
a) syntax highlight in the formula edit (just symbols
and literals, not parsing content)
b) add an error navigator to click on errors and have the
text highlighted that incurred that error.
.. the daterange() commit broke almost every builtin
function ! (it converted them to integers due to
and if/else logic error.
.. also tidied parser to separate literals and symbols
whilst making builtin functions expr elements to
look more closely at precedence
.. oopsie on binary expression.
NOTE: it may be better to highlight tokens rather than
via the parser as errors make it impossible to
highlight the "intention" of the user
Particularly useful when working with a vector
but can be used with other things.
e.g. max(xPower, BikeScore)
Or, for getting a ride's TSS expressed as a percentage
of the average TSS for the currently selected daterange.
e.g. TSS / mean(TSS[daterange(start):daterange(stop)])
You can create a vector using the notation:
expr [ from : to ]
Where 'expr' will be evaluated for every activity
between the dates from and to.
e.g. TSS[today - 90 : today]
will evaluate to TSS for the last 90 days
e.g. Activities [ date:date ] > 1
Will find all days with more than one workout.
.. when using a vector in any arithmetic expression it
will be evaluated to a sum; this will be fixed shortly
to enable the use of sum/mean/max/min functions.
.. If needed we can add vector operations but this will
likely confuse many users (hell, they confuse developers)
so we will need a good reason to add them !
Lastly, I have also added daterange(from) and daterange(to)
literals to get access to the currently selected daterange
when working in the trends view.
.. update the editor to do some basic syntax
highlighting; literals in red, comments in
blue and so on.
.. next commit will focus on highlighting errors
with a wavy line and some form of error list.
.. updated the datafilter to handle general functions
and parse them without needing them declared in the lexer
.. makes it much easier to add new functions in the future
.. did this to add core math functions;
* sin, cos, tan, asin, acos, atan,
* sinh, cosh, tanh, asinh, acosh, atanh
* exp, log, log10, ceil, floor, round
* fabs, isinf, isnan
.. we can add more later; erf/gamma spring to mind !
.. uses the C/C++ notation:
expr ? expr2 : expr3
Where expr is the condition e.g. X>2
and expr2 is what to evaluate to if expr is true
and expr3 is what to evaluate to if expr is false
e.g.
(Workout_Code = "1L3") ? 1 : 0
Will evaluate as 1 for all workouts where the
workout code is 1L3 and 0 for all other workouts.
.. get rid of terrible cut and paste code, duplicating
eval for particular leafs
.. eval returns a Result() object which can be numeric
or textual (date strings are parsed to numeric)
.. can now add formulas to LTM as well as adding more
functions that may be useful (conditionals, maths
spring to mind first).
.. will rerun as ride selection changes.
.. but will never stop until cleared so use at your
own risk, as will run EVERY time you select a
different ride.
.. introduce concept of configChanged(what) to
pass details of what config has been changed
.. fixed zones changes to re-read after write
to correct the save twice to get changes to
zones bug.
.. next parts need to spot changes (part 2) and
then action appropriately (part 3)
.. to enable queries such as;
Date > "2014/02/28"
for rides since 28th February 2014
.. might be useful to allow localised dates
but using this makes it easier to document !
.. a query like today > "1900/01/01" will pass
on all rides, but user being an idiot.