Simplifying Bézier paths (2023) https://raphlinus.github.io/curves/2023/04/18/bezpath-simpli...
Parallel curves of cubic Béziers (2022) https://raphlinus.github.io/curves/2022/09/09/parallel-bezie...
Fitting cubic Bézier curves (2021) https://raphlinus.github.io/curves/2021/03/11/bezier-fitting...
I’ve been building a vector editor that by default draws shapes with smooth curvature and shows the comb. [1] In addition to the four point types mentioned in the article, you get a new “curve” point type. I’ve also been making a font editor with the same drawing capability. [2]
Both are free static web apps that use local storage and have import/export capability for SVG files (and OTF files for the font editor).
Feel I should also call out Freyr’s videos for anyone who has missed them - continuity of splines [2] and the beauty of Bézier curves [3]
[1] https://gadgetoid.github.io/asdf
γ(t)=A⋅(1−t)^3+B⋅3(1−t)^2⋅t+C⋅3(1−t)t^2+D⋅t^3
The rule is simple: descending powers of (1−t), ascending powers of t, with coefficients taken from the n'th row of Pascal's triangle.
I've never seen the connection between the equation for Bezier Curves (more specifically the linear equations of curves with N control points aka "binding points" / "points of stability" / "fixed points" / "immovable points", etc.) and Pascal's Triangle before!
Brilliant!
Great article, too!
Take a row of pascal's triangle, add a zero in front (shift it to the right by one place), and divide it by the row below it.
0 1 4 6 4 1 /
1 5 10 10 5 1
= ...
From this you can prove that a linear bezier line (of any degree) must have equally spaced control points.When I said:
"(more specifically the linear equations of curves with N control points aka "binding points" / "points of stability" / "fixed points" / "immovable points", etc.)" -- there's a terminology mix-up here -- the control points (A, B, C, D) are (obviously) variable / flexible in nature, but the values from Pascal's Triangle are (obviously!) bound/stable/fixed to their respective row!
So that's what I meant to say...
So my apologies for having messed-up the terminology there!
(You know what I meant! :-) )
Anyway, some very interesting responses and connections! Thanks to everyone who responded!
The choice function is also exactly the same as the pascal triangle!
The one sticking point is instability in the middle of s curves which seems difficult. We're getting better control for every fully convex or non-convex path in exchange for chaos at the boundary between the two. I wonder if incorporating some other error term of the curvature in those regions might help, perhaps guaranteeing that the curvature derivatives are close to continuous whenever the curvatures themselves get too small?
One other thought is that you could use a saturating function of the tangent circle radius so that 0 curvature points don't have to have their control points go to infinity, perhaps making the saturation point a function of the distance to the nearby nodes to keep the scale reasonable.
I have to wonder - if you want smooth joins, why not use uniform B-splines instead of Bézier curves? With B-splines you don’t have to set constraints or compute curvature, it’s built in. What are the reasons to prefer Bézier?
There’s an old 1985 tech report by Tony DeRose (formerly of Pixar Research) that categorized the different ways to smoothly join curves - "Geometric Continuity: A Parametrization Independent Measure of Continuity for Computer Aided Geometric Design.”
That paper has a simple constraint formula for matching curvature between cubic Béziers, one that has a couple degrees of freedom. It’s the “G2 (curvature continuity)” formula mentioned on Wikipedia here: https://en.wikipedia.org/wiki/Composite_B%C3%A9zier_curve#Sm.... It’d be interesting to know whether that somehow works out to be mathematically equivalent to this post’s technique or not.
Additionally B-splines (like Catmull-Rom) have the issue that moving one point affects a larger area of the spline than an equivalent bezier. The local control of beziers makes them more desirable for precise illustration.
As for the formula you cited, it tells you where to put the control point for continuity in function of two scalars, but those scalars don't directly map to intuitive controls. It also doesn't help when moving a curve point while preserving curvature on both sides because it only tells you one side in function of the other. I.e. continuity of curvature is a weaker constraint than having the desired curvature.
I initially experimented with something similar but found that numerical drift would steadily accumulate during interactive editing. The post shows this with the last example before curvature handles: rotating the tangents there preserves curvature continuity but the curve tends to blow up for certain angles, because the tangent is a poor proxy for indicating desired curvature.
Minor edit here to note, it just occurred to me that the curvature constraint affects the curve over a span of 7 control points, whereas editing a B-spline control point affects the curve over a span of 4 control points. B-splines are strictly more localized than Curvature Béziers…
One reason B-splines aren’t well known & used is because seemingly most/all online content launches into the math and discussion of knots. The uniform B-spline doesn’t need knots, and I wish more tutorials would start there rather than intimidating people with the math.
BTW yes you’re right about the ‘scalars’ (the beta parameters) in the G2 curvature matching equation. I haven’t tried this and I don’t know what they do. I was wondering if these might have a relationship to the ‘heuristic’ the Acko article derives? That was kind of my question.
To clarify, I meant B-splines _lack local control_ like Catmull-Rom splines, not that the latter is an instance of the former. Though indeed, all cubic splines are just cubic polynomials.
I disagree with your characterization that the proposed solution lacks local control, because edits only affect the segments in question, just like with a classic bezier. From the point of view of curvature handles, the handles you don't touch don't change. (The splitting of a curvature bezier is imo the best illustration of this.)
Re: the meaning of the scalars, I imagine they are derived similarly as the perpendicular-distance diagram in the post. If you plug bezier formulas into curvature formulas, a lot of terms cancel out.
My claim that the Curvature Bézier has less locality, of course, was based only on editing one of the Bézier’s shared join points. When you edit a shared point’s position (by moving an anchor) or tangent (by moving either of the interior control points), you are affecting 2 segments, not just one, hence the 7 control point span. I’m being a bit sloppy but I’m sure you understand what I mean there - the portion of curve affected by a single control point edit technically affects a section of the curve that’s fully determined by exactly 7 consecutive control points. (Assuming cubic!)
Re-thinking B-spline, I believe I goofed - editing a control point affect 4 consecutive curve segments, which is the non-locality you’re referring to, but which is also a span of 7 control points, so very similar to editing one of the constrained Bézier’s shared anchor points. The window of which 7 control points slides smoothly with B-spline: the edited control point is the middle of the 7 control point span. With a curvature-constrained Bézier, each shared anchor and its two surrounding control points affect the curve defined by the same 7 control points.
So yes cubic Bézier segments that aren’t constrained in any way (i.e., the “cusp” and “corner” types), sure those have a kind of ‘locality’ in that editing the two interior control points affects only the 1 segment defined by 4 control points. But as soon as you add constraints on the tangents, neighboring segments affect each other, and your control naturally becomes less ‘local’, right?
So anyway, given that adding constraints to Bézier splines will cause neighbors to affect each other and control point edits are no longer confined to a single segment, are there other reasons to stick with Bézier?
The locality of a bezier, even with symmetric constraints, amounts to the fact that the user's specified positions (the endpoints) and tangent directions are preserved exactly and can be modified independently. This makes detailed edits easy. And because curvature beziers only differ from classic beziers in the tangent lengths (not directions), the same properties hold.
The "7 control point span" you talk about is really a 5 point span, because adjusting the lengths of the bezier tangents at the far ends serves to explicitly preserve the user's intent, namely the radius of curvature.
Catmull-Rom e.g. ties together the tangent at a control point with the position of the previous and next control point. And B-splines don't guarantee going through any control point at all except the endpoints, with the tangents not even independently controllable.
This is why artists like beziers.
It’s true B-splines are approximating and Béziers are considered interpolating (even though 50% of the control points are approximating), and that very well might be the primary or even only reason to choose Bézier for many design goals. It’s also true that with uniform B-splines you can choose to interpolate any given control point at the small cost of duplicating control points (and of course non-uniform B-splines have additional ways).
My only observation, of course, is just that B-splines have the built-in property that curvature is smooth across segments, so if that’s your main goal for a given task, they seem like a decent choice if you can accept the tradeoffs. It is, of course, possible to mix and match curve types.
- place nodes at extrema (top/bottom, left/right)
- place nodes at points of inflection (middle of an _S_ curve)
- where possible/appropriate observe the "rule of 30" and place off-curve nodes not quote one-third of the way towards the other on-curve node
If one expected (or enforced) those rules, does the problem/math become easier?
Placing points at X/Y extremes is by itself useless because beziers are rotation invariant. i.e. If that's the best place for the control points, then by the same argument if you rotated the curve by 45° the points would need to be on diagonal extremes. It's only useful with typography where many letters are oval. IIRC this rule originated because buggy rendering code assumed the curve would never extend beyond the XY bounding box of the control points.
Placing nodes at inflection points is actually a bad idea because there are very few configurations where curvature remains continuous. It's better to construct S bends with the inflection point in the middle, because then you always get a smooth transition.
Picking a specific spacing between control points makes it more likely that equal tangents represent approximately the same curvature on both sides, but it's not guaranteed either.
Further, these rules facilitate using the shift key to constrain off-curve node placement to in-line w/ the matching on-curve node horizontally or vertically.
For e.g. animation purposes, you need to reparametrize to arc length which destroys the apparent C1 continuity.
This WP entry mentions several other alternatives to smooth joins besides matching curvature:
https://en.wikipedia.org/wiki/Composite_B%C3%A9zier_curve#Sm...