1
0
mirror of https://github.com/Pomax/BezierInfo-2.git synced 2025-08-31 12:01:54 +02:00

Edits to offsetting section (#199)

Many punctuation, some style
This commit is contained in:
Simon Cozens
2019-06-11 02:06:44 +01:00
committed by Pomax
parent 3e8690e761
commit de6435e9a0

View File

@@ -1,16 +1,16 @@
# Curve offsetting
Perhaps you are like me, and you've been writing various small programs that use Bézier curves in some way or another, and at some point you make the step to implementing path extrusion. But you don't want to do it pixel based, you want to stay in the vector world. You find that extruding lines is relatively easy, and tracing outlines is coming along nicely (although junction caps and fillets are a bit of a hassle), and then decide to do things properly and add Bézier curves to the mix. Now you have a problem.
Perhaps you're like me, and you've been writing various small programs that use Bézier curves in some way or another, and at some point you make the step to implementing path extrusion. But you don't want to do it pixel based; you want to stay in the vector world. You find that extruding lines is relatively easy, and tracing outlines is coming along nicely (although junction caps and fillets are a bit of a hassle), and then you decide to do things properly and add Bézier curves to the mix. Now you have a problem.
Unlike lines, you can't simply extrude a Bézier curve by taking a copy and moving it around, because of the curvatures; rather than a uniform thickness you get an extrusion that looks too thin in places, if you're lucky, but more likely will self-intersect. The trick, then, is to scale the curve, rather than simply copying it. But how do you scale a Bézier curve?
Unlike lines, you can't simply extrude a Bézier curve by taking a copy and moving it around, because of the curvatures; rather than a uniform thickness, you get an extrusion that looks too thin in places, if you're lucky, but more likely will self-intersect. The trick, then, is to scale the curve, rather than simply copying it. But how do you scale a Bézier curve?
Bottom line: **you can't**. So you cheat. We're not going to do true curve scaling, or rather curve offsetting, because that's impossible. Instead we're going to try to generate 'looks good enough' offset curves.
<div className="note">
### "What do you mean, you can't. Prove it."
### "What do you mean, 'you can't'? Prove it."
First off, when I say "you can't" what I really mean is "you can't offset a Bézier curve with another Bézier curve". not even by using a really high order curve. You can find the function that describes the offset curve, but it won't be a polynomial, and as such it cannot be represented as a Bézier curve, which **has** to be a polynomial. Let's look at why this is:
First off, when I say "you can't," what I really mean is "you can't offset a Bézier curve with another Bézier curve", not even by using a really high order curve. You can find the function that describes the offset curve, but it won't be a polynomial, and as such it cannot be represented as a Bézier curve, which **has** to be a polynomial. Let's look at why this is:
From a mathematical point of view, an offset curve `O(t)` is a curve such that, given our original curve `B(t)`, any point on `O(t)` is a fixed distance `d` away from coordinate `B(t)`. So let's math that:
@@ -49,11 +49,11 @@ There is a small class of polynomials where the square root is also a polynomial
So, since the tangent length isn't a polynomial, the normalised tangent won't be a polynomial either, which means `N(t)` won't be a polynomial, which means that `d` times `N(t)` won't be a polynomial, which means that, ultimately, `O(t)` won't be a polynomial, which means that even if we can determine the function for `O(t)` just fine (and that's far from trivial!), it simply cannot be represented as a Bézier curve.
And that's one reason why Bézier curves are tricky: there are actually a `lot` of curves that cannot be represent as a Bézier curve at all. They can't even model their own offset curves. They're weird that way. So how do all those other programs do it? Well, much like we're about to do, they cheat. We're going to approximate an offset curve in a way that will look relatively close to what the real offset curve would look like, if we could compute it.
And that's one reason why Bézier curves are tricky: there are actually a *lot* of curves that cannot be represented as a Bézier curve at all. They can't even model their own offset curves. They're weird that way. So how do all those other programs do it? Well, much like we're about to do, they cheat. We're going to approximate an offset curve in a way that will look relatively close to what the real offset curve would look like, if we could compute it.
</div>
So, you cannot offset a Bézier curve perfectly with another Bézier curve, no matter how high-order you make that other Bézier curve. However, we can chop up a curve into "safe" sub-curves (where safe means that all the control points are always on a single side of the baseline, and the midpoint of the curve at `t=0.5` is roughly in the center of the polygon defined by the curve coordinates) and then point-scale each sub-curve with respect to its scaling origin (which is the intersection of the point normals at the start and end points).
So, you cannot offset a Bézier curve perfectly with another Bézier curve, no matter how high-order you make that other Bézier curve. However, we can chop up a curve into "safe" sub-curves (where "safe" means that all the control points are always on a single side of the baseline, and the midpoint of the curve at `t=0.5` is roughly in the center of the polygon defined by the curve coordinates) and then point-scale each sub-curve with respect to its scaling origin (which is the intersection of the point normals at the start and end points).
A good way to do this reduction is to first find the curve's extreme points, as explained in the earlier section on curve extremities, and use these as initial splitting points. After this initial split, we can check each individual segment to see if it's "safe enough" based on where the center of the curve is. If the on-curve point for `t=0.5` is too far off from the center, we simply split the segment down the middle. Generally this is more than enough to end up with safe segments.