The Continuity of Splines [video](youtube.com) |
The Continuity of Splines [video](youtube.com) |
PS. I would also highly recommend these sources which have been covered before on HN:
Curves and Surfaces by Bartosz Ciechanowski [1]
A Primer on Bézier Curves by Pomax [2]
If I understand your suggestion correctly, I believe what this buys you is directional control of your spline at the spline endpoints and a more constant parameterization (one that doesn’t accelerate or decelerate at the spline endpoints). Perhaps the most common alternative is to insert duplicate knots at the spline endpoints, inserting as many extra knots as you need to reach the support requirements of your segment (degree minus one, right?). The problem with this is that you end up with several segments decreasing in size to zero, so the parameterization decelerates to zero. The derivatives also shrink to zero, which can cause problems depending on what you’re doing. Another common technique is to pretend the control points keep going straight after they end, meaning insert implicit ‘phantom’ control points beyond the first & last control point of a spline that matches the direction & magnitude of the first & last explicit segments. (Freya discusses this at 46 minutes into the video.) If your spline was degree 2 and starts with control point p1, then you could insert the phantom point p0 where p1-p0 = p2-p1. This gives you enough control points to evaluate the spline up to your explicit endpoint p1, but you lose a little bit of control over the tangent at the endpoint. If you wanted a different tangent than p2-p1, then you could, as you suggest, add explicit phantom control points. The continuity is the same in all three cases here, but the direction and tangent magnitude are unique to each approach with your suggestion offering the most control.
l(t) = t x0 + (1-t) x1
m(t) = t^2 (x0 - x1) + t x1 + x2
and so on.I wonder if the beginning can be skipped if the first video was already seen?
It looks similar because it's a sequel to the original video.
One fun basis for 3rd degree parametric polynomials that Freya skipped is a basis of values through which a polynomial can be interpolated. You can pick any 4 nodes in the interval, but I recommend [0, 0.25, 0.75, 1] for the least erratic behavior.
Example: https://observablehq.com/@jrus/bez-cheb – try dragging the blue dots.
Or for a higher degree polynomial, choose "Chebyshev nodes": equally spaced points on a semicircle projected down onto the diameter. This is one of the most "intuitive" control methods for manipulating a single parametric polynomial segment; the downside of this basis is that it doesn't facilitate matching boundary slope (etc.) between adjacent segments.
The "Hermite" basis (which is equivalent to the Bernstein basis up to some constant scale factors in the 3rd degree case) is in a certain sense what you get when you instead pick the nodes [0, 0, 1, 1] to interpolate; that gives you a double root at each end so you can also pick the slope there.
* * *
Freya: if you are looking for a next project, animating Raph’s excellent PhD thesis would be a great public service. :-) https://levien.com/phd/thesis.pdf
For something a bit easier, chord-length parametrized splines are surprisingly effective, definitely worth playing around with. e.g. the natural cubic spline using chord length for parameter spacing. Implementation (but no demo) here: https://observablehq.com/@jrus/cubic-spline#parametric_NCS
Regarding collaboration with Freya, if she is open to it, please get in touch. I do have some ideas.
[1]: A New Shape Control and Classification for Cubic Bézier Curves, Yang and Huang, 1993, PDF cache: https://github.com/paperjs/paper.js/files/752955/A.New.Shape...
While you’re here, it’s a bit of a tangent, but the introductory part of the video talking about lerp reminded me again that not enough people know about (not quite uniformly) interpolating along a circular arc using two lerps and one division:
For complex numbers a (start), m ("midpoint" on the circle), b (end), and t (parameter in [0,1], or in [-∞, ∞] to cover the whole circle),
circle_interp = (a, m, b, t) =>
lerp(a * (b - m), b * (m - a), t) / lerp(b - m, m - a, t)
https://observablehq.com/@jrus/circle-arc-interpolationConveniently, this works for points in a straight line (a circle of infinite diameter) and we never need to explicitly construct the center or radius of the circle.
I was astonished to find this, and even more astonished to find it had never been clearly published anywhere (at least not that I could find after a lot of searching).
[This parametrization of the circle can equivalently be rewritten as a rational quadratic Bézier, but this formula is IMO a lot clearer to understand.]
(I originally dug into Beziers because I was several levels deep into "Processing.js's text-in-a-box fitting is bad, how can I fix that". Queue learning how OpenType works, how TTF/CFF works, how Beziers work, writing up a code playground tutorial before we really had code playgrounds, and then going "...I can use this for more, can't I?"... And thanks to that I've talked to far smarter people with formal training in both the type design and maths communities. I still consider myself an amateur, but an amateur with expert acquaintances =)
Random tangent, but I’m glad you joined the discussion! Maybe you’re sick of curves by now, and I realize you said you left out many topics, but I was curious if you’d considered the quadratic B-spline or any other quadratic curves? I feel like we always talk about linear and cubic and hardly anyone considers quadratics. There are good reasons for that, but I like the order-2 B-spline for it’s continuity and because it’s halfway interpolating in the sense that it interpolates every midpoint of the linear skeleton. It’s slightly smoother than the Catmull-Rom (which is a bit lumpy IMO), and I think the continuity is equally good, right?