W3C home > Mailing lists > Public > public-css-archive@w3.org > June 2019

Re: [csswg-drafts] [css-easing-2] Complex easing/timing functions (#229)

From: VisibleCode via GitHub <sysbot+gh@w3.org>
Date: Fri, 07 Jun 2019 05:13:07 +0000
To: public-css-archive@w3.org
Message-ID: <issue_comment.created-499758999-1559884386-sysbot+gh@w3.org>
> <dbaron> dbaron: nice pictures and few/no equations

I wasn't sure if spelling out the equations would be necessary at this stage. As mentioned upthread, the piecewise curves here are supposed to be [Cubic Hermite splines](https://en.wikipedia.org/wiki/Cubic_Hermite_spline). They are a standard thing and very closely related to Bezier curves.

Hermite splines can be given as a sequence of (_t_, _p_, _m_) triples, corresponding to the knots. In this context those correspond to (_time_, _progress_, _velocity_), with _time_ and _progress_ ranging between 0 and 1, apart from under/overshoot.

(n.b. the strawman CSS syntax from earlier gives _t_ last, and as a percentage, just because it's trying to imitate CSS gradient syntax.)

I'll use _t<sub>0</sub>_ to mean the _t_ from the first knot, _t<sub>1</sub>_ from the second knot, and so on...

For evaluating the curve in between knots, it's probably easiest to convert the segments to [Bernstein form](https://en.wikipedia.org/wiki/Bernstein_polynomial). (Bezier curves are made of polynomials in Bernstein form.)

Converting one Hermite segment, between knots _n_ and _n+1_, to Bernstein form and re-parameterizing for the unit interval:

 C<sub>0</sub> = p<sub>n</sub>
 C<sub>1</sub> = p<sub>n</sub> + m<sub>n</sub> / 3
 C<sub>2</sub> = p<sub>n+1</sub> - m<sub>n+1</sub> / 3
 C<sub>3</sub> = p<sub>n+1</sub>

Evaluating the converted segment at _t_, using [De Casteljau's algorithm](https://en.wikipedia.org/wiki/De_Casteljau's_algorithm), as is commonly done for Beziers:

 lerp(a, b, x) = (1 - x) * a + x * b

 t<sub>unit</sub> = (t - t<sub>n</sub>) / (t<sub>n+1</sub> - t<sub>n</sub>)

 B<sub>0</sub> = lerp(C<sub>0</sub>, C<sub>1</sub>, t<sub>unit</sub>)
 B<sub>1</sub> = lerp(C<sub>1</sub>, C<sub>2</sub>, t<sub>unit</sub>)
 B<sub>2</sub> = lerp(C<sub>2</sub>, C<sub>3</sub>, t<sub>unit</sub>)

 A<sub>0</sub> = lerp(B<sub>0</sub>, B<sub>1</sub>, t<sub>unit</sub>)
 A<sub>1</sub> = lerp(B<sub>1</sub>, B<sub>2</sub>, t<sub>unit</sub>)
 
 result = lerp(A<sub>0</sub>, A<sub>1</sub>, t<sub>unit</sub>)

One non-standard thing is that I'm allowing zero length segments (where _t<sub>n</sub>_ == _t<sub>n+1</sub>_) to represent abrupt changes in the curve; these trivial segments shouldn't get evaluated.

When I have a chance, I'll follow up on how to compute unspecified _m<sub>n</sub>_ values (missing or `auto` in the strawman syntax).

-- 
GitHub Notification of comment by visiblecode
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/229#issuecomment-499758999 using your GitHub account
Received on Friday, 7 June 2019 05:13:09 UTC

This archive was generated by hypermail 2.4.0 : Tuesday, 19 October 2021 01:31:10 UTC