mirror of
https://github.com/Pomax/BezierInfo-2.git
synced 2025-09-02 21:02:49 +02:00
we don't need B''(t) for extrema
This commit is contained in:
@@ -40,5 +40,5 @@ If we drop all the zero-terms, this gives us:
|
||||
|
||||
We can see that our original curve definition has been simplified considerably. The following graphics illustrate the result of aligning our example curves to the x-axis, with the cubic case using the coordinates that were just used in the example formulae:
|
||||
|
||||
<Graphic title="Aligning a quadratic curve" setup={this.setupQuadratic} draw={this.draw} />
|
||||
<Graphic title="Aligning a cubic curve" setup={this.setupCubic} draw={this.draw} />
|
||||
<graphics-element title="Aligning a quadratic curve" src="./quadratic.js"></graphics-element>
|
||||
<graphics-element title="Aligning a cubic curve" src="./cubic.js"></graphics-element>
|
||||
|
7
chapters/aligning/cubic.js
Normal file
7
chapters/aligning/cubic.js
Normal file
@@ -0,0 +1,7 @@
|
||||
setup() {
|
||||
|
||||
}
|
||||
|
||||
draw() {
|
||||
clear();
|
||||
}
|
7
chapters/aligning/quadratic.js
Normal file
7
chapters/aligning/quadratic.js
Normal file
@@ -0,0 +1,7 @@
|
||||
setup() {
|
||||
|
||||
}
|
||||
|
||||
draw() {
|
||||
clear();
|
||||
}
|
@@ -1,31 +1,42 @@
|
||||
# Finding extremities: root finding
|
||||
|
||||
Now that we understand (well, superficially anyway) the component functions, we can find the extremities of our Bézier curve by finding maxima and minima on the component functions, by solving the equations B'(t) = 0 and B''(t) = 0. That said, in the case of quadratic curves there is no B''(t), so we only need to compute B'(t) = 0. So, how do we compute the first and second derivatives? Fairly easily, actually, until our derivatives are 4th order or higher... then things get really hard. But let's start simple:
|
||||
Now that we understand (well, superficially anyway) the component functions, we can find the extremities of our Bézier curve by finding maxima and minima on the component functions, by solving the equation B'(t) = 0. We've already seen that the derivative of a Bézier curve is a simpler Bézier curve, but how do we solve the equality? Fairly easily, actually, until our derivatives are 4th order or higher... then things get really hard. But let's start simple:
|
||||
|
||||
### Quadratic curves: linear derivatives.
|
||||
|
||||
Finding the solution for "where is this line 0" should be trivial:
|
||||
The derivative of a quadratic Bézier curve is a linear Bézier curve, interpolating between just two terms, which means finding the solution for "where is this line 0" is effectively trivial by rewriting it to a function of `t` and solving. First we turn our cubic Bézier function into a quadratic one, by following the rule mentioned at the end of the [derivatives section](#derivatives):
|
||||
|
||||
\[
|
||||
\begin{aligned}
|
||||
l(x) = ax + b &= 0,\\
|
||||
ax + b &= 0,\\
|
||||
ax &= -b \\
|
||||
x &= \frac{-b}{a}
|
||||
B'(t) = a(1-t) + b(t) &= 0,\\
|
||||
a - at + bt &= 0,\\
|
||||
(b-a)t + a &= 0\\
|
||||
\end{aligned}
|
||||
\]
|
||||
|
||||
Done. And quadratic curves have no meaningful second derivative, so we're *really* done.
|
||||
And then we turn this into our solution for `t` using basic arithmetics:
|
||||
|
||||
\[
|
||||
\begin{aligned}
|
||||
(b-a)t + a &= 0,\\
|
||||
(b-a)t &= -a,\\
|
||||
t &= \frac{-a}{b-a}\\
|
||||
\end{aligned}
|
||||
\]
|
||||
|
||||
Done.
|
||||
|
||||
Although with the [caveat](https://en.wikipedia.org/wiki/Caveat_emptor#Caveat_lector) that if `b-a` is zero, there is no solution and we probably shouldn't try to perform that division.
|
||||
|
||||
### Cubic curves: the quadratic formula.
|
||||
|
||||
The derivative of a cubic curve is a quadratic curve, and finding the roots for a quadratic Bézier curve means we can apply the [Quadratic formula](https://en.wikipedia.org/wiki/Quadratic_formula). If you've seen it before, you'll remember it, and if you haven't, it looks like this:
|
||||
The derivative of a cubic Bézier curve is a quadratic Bézier curve, and finding the roots for a quadratic polynomial means we can apply the [Quadratic formula](https://en.wikipedia.org/wiki/Quadratic_formula). If you've seen it before, you'll remember it, and if you haven't, it looks like this:
|
||||
|
||||
\[
|
||||
Given\ f(t) = at^2 + bt + c,\ f(t)=0\ when\ t = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}
|
||||
\]
|
||||
|
||||
So, if we can express a Bézier component function as a plain polynomial, we're done: we just plug in the values into the quadratic formula, check if that square root is negative or not (if it is, there are no roots) and then just compute the two values that come out (because of that plus/minus sign we get two). Any value between 0 and 1 is a root that matters for Bézier curves, anything below or above that is irrelevant (because Bézier curves are only defined over the interval [0,1]). So, how do we convert?
|
||||
So, if we can rewrite the Bézier component function as a plain polynomial, we're done: we just plug in the values into the quadratic formula, check if that square root is negative or not (if it is, there are no roots) and then just compute the two values that come out (because of that plus/minus sign we get two). Any value between 0 and 1 is a root that matters for Bézier curves, anything below or above that is irrelevant (because Bézier curves are only defined over the interval [0,1]). So, how do we convert?
|
||||
|
||||
First we turn our cubic Bézier function into a quadratic one, by following the rule mentioned at the end of the [derivatives section](#derivatives):
|
||||
|
||||
@@ -48,7 +59,7 @@ And then, using these *v* values, we can find out what our *a*, *b*, and *c* sho
|
||||
\end{aligned}
|
||||
\]
|
||||
|
||||
This gives us thee coefficients *a*, *b*, and *c* that are expressed in terms of *v* values, where the *v* values are just convenient expressions of our original *p* values, so we can do some trivial substitution to get:
|
||||
This gives us three coefficients {a, b, c} that are expressed in terms of `v` values, where the `v` values are expressions of our original coordinate values, so we can do some substitution to get:
|
||||
|
||||
\[
|
||||
\begin{aligned}
|
||||
@@ -58,12 +69,14 @@ This gives us thee coefficients *a*, *b*, and *c* that are expressed in terms of
|
||||
\end{aligned}
|
||||
\]
|
||||
|
||||
Easy-peasy. We can now almost trivially find the roots by plugging those values into the quadratic formula. We also note that the second derivative of a cubic curve means computing the first derivative of a quadratic curve, and we just saw how to do that in the section above.
|
||||
Easy-peasy. We can now almost trivially find the roots by plugging those values into the quadratic formula.
|
||||
|
||||
### Quartic curves: Cardano's algorithm.
|
||||
|
||||
Quartic—fourth degree—curves have a cubic function as derivative. Now, cubic functions are a bit of a problem because they're really hard to solve. But, way back in the 16<sup>th</sup> century, [Gerolamo Cardano](https://en.wikipedia.org/wiki/Gerolamo_Cardano) figured out that even if the general cubic function is really hard to solve, it can be rewritten to a form for which finding the roots is "easy", and then the only hard part is figuring out how to go from that form to the
|
||||
generic form. So:
|
||||
We haven't really looked at them before now, but the next step up would be a Quartic curve, a fourth degree Bézier curve. As expected, these have a derivative that is a cubic function, and now things get much harder. Cubic functions don't have a "simple" rule to find their roots, like the quadratic formula, and instead require quite a bit of rewriting to a form that we can even start to try to solve.
|
||||
|
||||
|
||||
Back in the 16<sup>th</sup> century, before Bézier curves were a thing, and even before _calculus itself_ was a thing, [Gerolamo Cardano](https://en.wikipedia.org/wiki/Gerolamo_Cardano) figured out that even if the general cubic function is really hard to solve, it can be rewritten to a form for which finding the roots is "easier" (even if not "easy"):
|
||||
|
||||
\[
|
||||
\begin{aligned}
|
||||
@@ -72,9 +85,11 @@ generic form. So:
|
||||
\end{aligned}
|
||||
\]
|
||||
|
||||
This is easier because for the "easier formula" we can use [regular calculus](http://www.wolframalpha.com/input/?i=t^3+%2B+pt+%2B+q) to find the roots. (As a cubic function, however, it can have up to three roots, but two of those can be complex. For the purpose of Bézier curve extremities, we can completely ignore those complex roots, since our *t* is a plain real number from 0 to 1.)
|
||||
We can see that the easier formula only has two constants, rather than four, and only two expressions involving `t`, rather than three: this makes things considerably easier to solve because it lets us use [regular calculus](http://www.wolframalpha.com/input/?i=t^3+%2B+pt+%2B+q) to find the values that satisfy the equasion.
|
||||
|
||||
So, the trick is to figure out how to turn the first formula into the second formula, and to then work out the maths that gives us the roots. This is explained in detail over at [Ken J. Ward's page](https://trans4mind.com/personal_development/mathematics/polynomials/cubicAlgebra.htm) for solving the cubic equation, so instead of showing the maths, I'm simply going to show the programming code for solving the cubic equation, with the complex roots getting totally ignored.
|
||||
Now, there is one small hitch: as a cubic function, the solutions may be [complex numbers](https://en.wikipedia.org/wiki/Complex_number) rather than plain numbers... And Cardona realised this, centuries befor complex numbers were a well-understood and established part of number theory. His interpretation of them was "these numbers are impossible but that's okay because they disappear again in later steps", allowing him to not think about them too much, but we have it even easier: as we're trying to find the roots for display purposes, we don't even _care_ about complex numbers: we're going to simplify Cardano's approach just that tiny bit further by throwing away any solution that's not a plain number.
|
||||
|
||||
So, how do we rewrite the hard formula into the easier formula? This is explained in detail over at [Ken J. Ward's page](https://trans4mind.com/personal_development/mathematics/polynomials/cubicAlgebra.htm) for solving the cubic equation, so instead of showing the maths, I'm simply going to show the programming code for solving the cubic equation, with the complex roots getting totally ignored, but if you're interested you should definitely head over to Ken's page and give the procedure a read-through.
|
||||
|
||||
<div class="howtocode">
|
||||
|
||||
@@ -168,27 +183,27 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
|
||||
</div>
|
||||
|
||||
And that's it. The maths is complicated, but the code is pretty much just "follow the maths, while caching as many values as we can to reduce recomputing things as much as possible" and now we have a way to find all roots for a cubic function and can just move on with using that to find extremities of our curves.
|
||||
And that's it. The maths is complicated, but the code is pretty much just "follow the maths, while caching as many values as we can to prevent recomputing things as much as possible" and now we have a way to find all roots for a cubic function and can just move on with using that to find extremities of our curves.
|
||||
|
||||
### Quintic and higher order curves: finding numerical solutions
|
||||
|
||||
The problem with this is that as the order of the curve goes up, we can't actually solve those equations the normal way. We can't take the function, and then work out what the solutions are. Not to mention that even solving a third order derivative (for a fourth order curve) is already a royal pain in the backside. We need a better solution. We need numerical approaches.
|
||||
And this is where thing stop, because we _cannot_ find the roots for polynomials of degree 5 or higher using algebra (a fact known as [the Abel–Ruffini theorem](https://en.wikipedia.org/wiki/Abel%E2%80%93Ruffini_theorem)). Instead, for occasions like these, where algebra simply cannot yield an answer, we turn to [numerical analysis](https://en.wikipedia.org/wiki/Numerical_analysis).
|
||||
|
||||
That's a fancy word for saying "rather than solve the function, treat the problem as a sequence of identical operations, the performing of which gets us closer and closer to the real answer". As it turns out, there is a really nice numerical root-finding algorithm, called the [Newton-Raphson](http://en.wikipedia.org/wiki/Newton-Raphson) root finding method (yes, after *[that](https://en.wikipedia.org/wiki/Isaac_Newton)* Newton), which we can make use of.
|
||||
That's a fancy term for saying "rather than trying to find exact answers by manipulating symbols, find approximate answers by describing the underlying process as a combination of steps, each of which _can_ be assigned a number via symbolic manipulation". For example, trying to mathematically compute how much water fits in a completely crazy three dimensional shape is very hard, even if it got you the perfect, precise answer. A much easier approach, which would be less perfect but still entirely useful, would be to just grab a buck and start filling the shape until it was full: just count the number of buckets of water you used. And if we want a more precise answer, we can use smaller buckets.
|
||||
|
||||
The Newton-Raphson approach consists of picking a value *t* (any value will do), and getting the corresponding value of the function at that *t* value. For normal functions, we can treat that value as a height. If the height is zero, we're done, we have found a root. If it's not, we take the tangent of the curve at that point, and extend it until it passes the x-axis, which will be at some new point *t*. We then repeat the procedure with this new value, and we keep doing this until we find our root.
|
||||
So that's what we're going to do here, too: we're going to treat the problem as a sequence of steps, and the smaller we can make each step, the closer we'll get to that "perfect, precise" answer. And as it turns out, there is a really nice numerical root-finding algorithm, called the [Newton-Raphson](http://en.wikipedia.org/wiki/Newton-Raphson) root finding method (yes, after *[that](https://en.wikipedia.org/wiki/Isaac_Newton)* Newton), which we can make use of. The Newton-Raphson approach consists of taking our impossible-to-solve function `f(x)`, picking some intial value `x` (literally any value will do), and calculating `f(x)`. We can think of that value as the "height" of the function at `x`. If that height is zero, we're done, we have found a root. If it isn't, we calculate the tangent line at `f(x)` and calculate at which `x` value _its_ height is zero (which we've already seen is very easy). That will give us a new `x` and we repeat the process until we find a root.
|
||||
|
||||
Mathematically, this means that for some *t*, at step *n=1*, we perform the following calculation until *f<sub>y</sub>*(*t*) is zero, so that the next *t* is the same as the one we already have:
|
||||
Mathematically, this means that for some `x`, at step `n=1`, we perform the following calculation until `f<sub>y</sub>(x)` is zero, so that the next `t` is the same as the one we already have:
|
||||
|
||||
\[
|
||||
t_{n+1} = t_n - \frac{f_y(t_n)}{f'_y(t_n)}
|
||||
x_{n+1} = x_n - \frac{f_y(x_n)}{f'_y(x_n)}
|
||||
\]
|
||||
|
||||
(The Wikipedia article has a decent animation for this process, so I'm not adding a sketch for that here unless there are requests for it)
|
||||
(The Wikipedia article has a decent animation for this process, so I will not add a graphic for that here)
|
||||
|
||||
Now, this works well only if we can pick good starting points, and our curve is continuously differentiable and doesn't have oscillations. Glossing over the exact meaning of those terms, the curves we're dealing with conform to those constraints, so as long as we pick good starting points, this will work. So the question is: which starting points do we pick?
|
||||
Now, this works well only if we can pick good starting points, and our curve is [continuously differentiable](https://en.wikipedia.org/wiki/Continuous_function) and doesn't have [oscillations](https://en.wikipedia.org/wiki/Oscillation_(mathematics)). Glossing over the exact meaning of those terms, the curves we're dealing with conform to those constraints, so as long as we pick good starting points, this will work. So the question is: which starting points do we pick?
|
||||
|
||||
As it turns out, Newton-Raphson is so blindingly fast, so we could get away with just not picking: we simply run the algorithm from *t=0* to *t=1* at small steps (say, 1/200<sup>th</sup>) and the result will be all the roots we want. Of course, this may pose problems for high order Bézier curves: 200 steps for a 200<sup>th</sup> order Bézier curve is going to go wrong, but that's okay: there is no reason, ever, to use Bézier curves of crazy high orders. You might use a fifth order curve to get the "nicest still remotely workable" approximation of a full circle with a single Bézier curve, that's pretty much as high as you'll ever need to go.
|
||||
As it turns out, Newton-Raphson is so blindingly fast that we could get away with just not picking: we simply run the algorithm from *t=0* to *t=1* at small steps (say, 1/200<sup>th</sup>) and the result will be all the roots we want. Of course, this may pose problems for high order Bézier curves: 200 steps for a 200<sup>th</sup> order Bézier curve is going to go wrong, but that's okay: there is no reason (at least, none that I know of) to _ever_ use Bézier curves of crazy high orders. You might use a fifth order curve to get the "nicest still remotely workable" approximation of a full circle with a single Bézier curve, but that's pretty much as high as you'll ever need to go.
|
||||
|
||||
### In conclusion:
|
||||
|
||||
|
@@ -62,9 +62,7 @@ plotDimension(dim, dimension) {
|
||||
|
||||
// Is there a solution for B'(t) = 0?
|
||||
let dpoints = dimension.dpoints[0];
|
||||
let a = dpoints[1].y - dpoints[0].y;
|
||||
let b = dpoints[0].y;
|
||||
let t3 = -b / a;
|
||||
let t3 = -dpoints[0].y / (dpoints[1].y - dpoints[0].y);
|
||||
|
||||
// Is that solution a value in [0,1]?
|
||||
if (t3 > 0 && t3 < 1) {
|
||||
|
BIN
images/chapters/aligning/74a3ba53c0d1a79938bd2b1b8d57497d.png
Normal file
BIN
images/chapters/aligning/74a3ba53c0d1a79938bd2b1b8d57497d.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 967 B |
BIN
images/chapters/extremities/4723d5fb04fe6aa379f7a73f7d251c84.png
Normal file
BIN
images/chapters/extremities/4723d5fb04fe6aa379f7a73f7d251c84.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
1
images/latex/1c0367fad2a0d6946db1f55a8520793a.svg
Normal file
1
images/latex/1c0367fad2a0d6946db1f55a8520793a.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 5.5 KiB |
1
images/latex/6db78123d4b676ffdf85d53670c77468.svg
Normal file
1
images/latex/6db78123d4b676ffdf85d53670c77468.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 7.1 KiB |
1
images/latex/c621cc41f6f22ee1beedbcb510fa5b6b.svg
Normal file
1
images/latex/c621cc41f6f22ee1beedbcb510fa5b6b.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 6.1 KiB |
262
index.html
262
index.html
@@ -2908,30 +2908,52 @@ function drawCurve(points[], t):
|
||||
Now that we understand (well, superficially anyway) the component
|
||||
functions, we can find the extremities of our Bézier curve by
|
||||
finding maxima and minima on the component functions, by solving the
|
||||
equations B'(t) = 0 and B''(t) = 0. That said, in the case of
|
||||
quadratic curves there is no B''(t), so we only need to compute
|
||||
B'(t) = 0. So, how do we compute the first and second derivatives?
|
||||
Fairly easily, actually, until our derivatives are 4th order or
|
||||
higher... then things get really hard. But let's start simple:
|
||||
equation B'(t) = 0. We've already seen that the derivative of a
|
||||
Bézier curve is a simpler Bézier curve, but how do we solve the
|
||||
equality? Fairly easily, actually, until our derivatives are 4th
|
||||
order or higher... then things get really hard. But let's start
|
||||
simple:
|
||||
</p>
|
||||
<h3>Quadratic curves: linear derivatives.</h3>
|
||||
<p>
|
||||
Finding the solution for "where is this line 0" should be trivial:
|
||||
The derivative of a quadratic Bézier curve is a linear Bézier curve,
|
||||
interpolating between just two terms, which means finding the
|
||||
solution for "where is this line 0" is effectively trivial by
|
||||
rewriting it to a function of <code>t</code> and solving. First we
|
||||
turn our cubic Bézier function into a quadratic one, by following
|
||||
the rule mentioned at the end of the
|
||||
<a href="#derivatives">derivatives section</a>:
|
||||
</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/ec28870926b6ed08625d942b578e6fbe.svg"
|
||||
width="132px"
|
||||
height="104px"
|
||||
src="images/latex/6db78123d4b676ffdf85d53670c77468.svg"
|
||||
width="189px"
|
||||
height="64px"
|
||||
/>
|
||||
<p>
|
||||
Done. And quadratic curves have no meaningful second derivative, so
|
||||
we're <em>really</em> done.
|
||||
And then we turn this into our solution for <code>t</code> using
|
||||
basic arithmetics:
|
||||
</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/1c0367fad2a0d6946db1f55a8520793a.svg"
|
||||
width="139px"
|
||||
height="77px"
|
||||
/>
|
||||
<p>Done.</p>
|
||||
<p>
|
||||
Although with the
|
||||
<a href="https://en.wikipedia.org/wiki/Caveat_emptor#Caveat_lector"
|
||||
>caveat</a
|
||||
>
|
||||
that if <code>b-a</code> is zero, there is no solution and we
|
||||
probably shouldn't try to perform that division.
|
||||
</p>
|
||||
<h3>Cubic curves: the quadratic formula.</h3>
|
||||
<p>
|
||||
The derivative of a cubic curve is a quadratic curve, and finding
|
||||
the roots for a quadratic Bézier curve means we can apply the
|
||||
The derivative of a cubic Bézier curve is a quadratic Bézier curve,
|
||||
and finding the roots for a quadratic polynomial means we can apply
|
||||
the
|
||||
<a href="https://en.wikipedia.org/wiki/Quadratic_formula"
|
||||
>Quadratic formula</a
|
||||
>. If you've seen it before, you'll remember it, and if you haven't,
|
||||
@@ -2944,7 +2966,7 @@ function drawCurve(points[], t):
|
||||
height="40px"
|
||||
/>
|
||||
<p>
|
||||
So, if we can express a Bézier component function as a plain
|
||||
So, if we can rewrite the Bézier component function as a plain
|
||||
polynomial, we're done: we just plug in the values into the
|
||||
quadratic formula, check if that square root is negative or not (if
|
||||
it is, there are no roots) and then just compute the two values that
|
||||
@@ -2975,11 +2997,10 @@ function drawCurve(points[], t):
|
||||
height="119px"
|
||||
/>
|
||||
<p>
|
||||
This gives us thee coefficients <em>a</em>, <em>b</em>, and
|
||||
<em>c</em> that are expressed in terms of <em>v</em> values, where
|
||||
the <em>v</em> values are just convenient expressions of our
|
||||
original <em>p</em> values, so we can do some trivial substitution
|
||||
to get:
|
||||
This gives us three coefficients {a, b, c} that are expressed in
|
||||
terms of <code>v</code> values, where the <code>v</code> values are
|
||||
expressions of our original coordinate values, so we can do some
|
||||
substitution to get:
|
||||
</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
@@ -2989,23 +3010,26 @@ function drawCurve(points[], t):
|
||||
/>
|
||||
<p>
|
||||
Easy-peasy. We can now almost trivially find the roots by plugging
|
||||
those values into the quadratic formula. We also note that the
|
||||
second derivative of a cubic curve means computing the first
|
||||
derivative of a quadratic curve, and we just saw how to do that in
|
||||
the section above.
|
||||
those values into the quadratic formula.
|
||||
</p>
|
||||
<h3>Quartic curves: Cardano's algorithm.</h3>
|
||||
<p>
|
||||
Quartic—fourth degree—curves have a cubic function as derivative.
|
||||
Now, cubic functions are a bit of a problem because they're really
|
||||
hard to solve. But, way back in the 16<sup>th</sup> century,
|
||||
We haven't really looked at them before now, but the next step up
|
||||
would be a Quartic curve, a fourth degree Bézier curve. As expected,
|
||||
these have a derivative that is a cubic function, and now things get
|
||||
much harder. Cubic functions don't have a "simple" rule to find
|
||||
their roots, like the quadratic formula, and instead require quite a
|
||||
bit of rewriting to a form that we can even start to try to solve.
|
||||
</p>
|
||||
<p>
|
||||
Back in the 16<sup>th</sup> century, before Bézier curves were a
|
||||
thing, and even before <em>calculus itself</em> was a thing,
|
||||
<a href="https://en.wikipedia.org/wiki/Gerolamo_Cardano"
|
||||
>Gerolamo Cardano</a
|
||||
>
|
||||
figured out that even if the general cubic function is really hard
|
||||
to solve, it can be rewritten to a form for which finding the roots
|
||||
is "easy", and then the only hard part is figuring out how to go
|
||||
from that form to the generic form. So:
|
||||
is "easier" (even if not "easy"):
|
||||
</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
@@ -3014,26 +3038,43 @@ function drawCurve(points[], t):
|
||||
height="44px"
|
||||
/>
|
||||
<p>
|
||||
This is easier because for the "easier formula" we can use
|
||||
We can see that the easier formula only has two constants, rather
|
||||
than four, and only two expressions involving <code>t</code>, rather
|
||||
than three: this makes things considerably easier to solve because
|
||||
it lets us use
|
||||
<a href="http://www.wolframalpha.com/input/?i=t%5E3+%2B+pt+%2B+q"
|
||||
>regular calculus</a
|
||||
>
|
||||
to find the roots. (As a cubic function, however, it can have up to
|
||||
three roots, but two of those can be complex. For the purpose of
|
||||
Bézier curve extremities, we can completely ignore those complex
|
||||
roots, since our <em>t</em> is a plain real number from 0 to 1.)
|
||||
to find the values that satisfy the equasion.
|
||||
</p>
|
||||
<p>
|
||||
So, the trick is to figure out how to turn the first formula into
|
||||
the second formula, and to then work out the maths that gives us the
|
||||
roots. This is explained in detail over at
|
||||
Now, there is one small hitch: as a cubic function, the solutions
|
||||
may be
|
||||
<a href="https://en.wikipedia.org/wiki/Complex_number"
|
||||
>complex numbers</a
|
||||
>
|
||||
rather than plain numbers... And Cardona realised this, centuries
|
||||
befor complex numbers were a well-understood and established part of
|
||||
number theory. His interpretation of them was "these numbers are
|
||||
impossible but that's okay because they disappear again in later
|
||||
steps", allowing him to not think about them too much, but we have
|
||||
it even easier: as we're trying to find the roots for display
|
||||
purposes, we don't even <em>care</em> about complex numbers: we're
|
||||
going to simplify Cardano's approach just that tiny bit further by
|
||||
throwing away any solution that's not a plain number.
|
||||
</p>
|
||||
<p>
|
||||
So, how do we rewrite the hard formula into the easier formula? This
|
||||
is explained in detail over at
|
||||
<a
|
||||
href="https://trans4mind.com/personal_development/mathematics/polynomials/cubicAlgebra.htm"
|
||||
>Ken J. Ward's page</a
|
||||
>
|
||||
for solving the cubic equation, so instead of showing the maths, I'm
|
||||
simply going to show the programming code for solving the cubic
|
||||
equation, with the complex roots getting totally ignored.
|
||||
equation, with the complex roots getting totally ignored, but if
|
||||
you're interested you should definitely head over to Ken's page and
|
||||
give the procedure a read-through.
|
||||
</p>
|
||||
<div class="howtocode">
|
||||
<h3>Implementing Cardano's algorithm for finding all real roots</h3>
|
||||
@@ -3135,24 +3176,41 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<p>
|
||||
And that's it. The maths is complicated, but the code is pretty much
|
||||
just "follow the maths, while caching as many values as we can to
|
||||
reduce recomputing things as much as possible" and now we have a way
|
||||
to find all roots for a cubic function and can just move on with
|
||||
prevent recomputing things as much as possible" and now we have a
|
||||
way to find all roots for a cubic function and can just move on with
|
||||
using that to find extremities of our curves.
|
||||
</p>
|
||||
<h3>Quintic and higher order curves: finding numerical solutions</h3>
|
||||
<p>
|
||||
The problem with this is that as the order of the curve goes up, we
|
||||
can't actually solve those equations the normal way. We can't take
|
||||
the function, and then work out what the solutions are. Not to
|
||||
mention that even solving a third order derivative (for a fourth
|
||||
order curve) is already a royal pain in the backside. We need a
|
||||
better solution. We need numerical approaches.
|
||||
And this is where thing stop, because we <em>cannot</em> find the
|
||||
roots for polynomials of degree 5 or higher using algebra (a fact
|
||||
known as
|
||||
<a href="https://en.wikipedia.org/wiki/Abel%E2%80%93Ruffini_theorem"
|
||||
>the Abel–Ruffini theorem</a
|
||||
>). Instead, for occasions like these, where algebra simply cannot
|
||||
yield an answer, we turn to
|
||||
<a href="https://en.wikipedia.org/wiki/Numerical_analysis"
|
||||
>numerical analysis</a
|
||||
>.
|
||||
</p>
|
||||
<p>
|
||||
That's a fancy word for saying "rather than solve the function,
|
||||
treat the problem as a sequence of identical operations, the
|
||||
performing of which gets us closer and closer to the real answer".
|
||||
As it turns out, there is a really nice numerical root-finding
|
||||
That's a fancy term for saying "rather than trying to find exact
|
||||
answers by manipulating symbols, find approximate answers by
|
||||
describing the underlying process as a combination of steps, each of
|
||||
which <em>can</em> be assigned a number via symbolic manipulation".
|
||||
For example, trying to mathematically compute how much water fits in
|
||||
a completely crazy three dimensional shape is very hard, even if it
|
||||
got you the perfect, precise answer. A much easier approach, which
|
||||
would be less perfect but still entirely useful, would be to just
|
||||
grab a buck and start filling the shape until it was full: just
|
||||
count the number of buckets of water you used. And if we want a more
|
||||
precise answer, we can use smaller buckets.
|
||||
</p>
|
||||
<p>
|
||||
So that's what we're going to do here, too: we're going to treat the
|
||||
problem as a sequence of steps, and the smaller we can make each
|
||||
step, the closer we'll get to that "perfect, precise" answer. And as
|
||||
it turns out, there is a really nice numerical root-finding
|
||||
algorithm, called the
|
||||
<a href="http://en.wikipedia.org/wiki/Newton-Raphson"
|
||||
>Newton-Raphson</a
|
||||
@@ -3161,56 +3219,60 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<em
|
||||
><a href="https://en.wikipedia.org/wiki/Isaac_Newton">that</a></em
|
||||
>
|
||||
Newton), which we can make use of.
|
||||
Newton), which we can make use of. The Newton-Raphson approach
|
||||
consists of taking our impossible-to-solve function
|
||||
<code>f(x)</code>, picking some intial value
|
||||
<code>x</code> (literally any value will do), and calculating
|
||||
<code>f(x)</code>. We can think of that value as the "height" of the
|
||||
function at <code>x</code>. If that height is zero, we're done, we
|
||||
have found a root. If it isn't, we calculate the tangent line at
|
||||
<code>f(x)</code> and calculate at which <code>x</code> value
|
||||
<em>its</em> height is zero (which we've already seen is very easy).
|
||||
That will give us a new <code>x</code> and we repeat the process
|
||||
until we find a root.
|
||||
</p>
|
||||
<p>
|
||||
The Newton-Raphson approach consists of picking a value
|
||||
<em>t</em> (any value will do), and getting the corresponding value
|
||||
of the function at that <em>t</em> value. For normal functions, we
|
||||
can treat that value as a height. If the height is zero, we're done,
|
||||
we have found a root. If it's not, we take the tangent of the curve
|
||||
at that point, and extend it until it passes the x-axis, which will
|
||||
be at some new point <em>t</em>. We then repeat the procedure with
|
||||
this new value, and we keep doing this until we find our root.
|
||||
</p>
|
||||
<p>
|
||||
Mathematically, this means that for some <em>t</em>, at step
|
||||
<em>n=1</em>, we perform the following calculation until
|
||||
<em>f<sub>y</sub></em
|
||||
>(<em>t</em>) is zero, so that the next <em>t</em> is the same as
|
||||
the one we already have:
|
||||
Mathematically, this means that for some <code>x</code>, at step
|
||||
<code>n=1</code>, we perform the following calculation until
|
||||
<code>f<sub>y</sub>(x)</code> is zero, so that the next
|
||||
<code>t</code> is the same as the one we already have:
|
||||
</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/04336edba7697ca91861821e32fc14be.svg"
|
||||
width="124px"
|
||||
height="45px"
|
||||
src="images/latex/c621cc41f6f22ee1beedbcb510fa5b6b.svg"
|
||||
width="139px"
|
||||
height="43px"
|
||||
/>
|
||||
<p>
|
||||
(The Wikipedia article has a decent animation for this process, so
|
||||
I'm not adding a sketch for that here unless there are requests for
|
||||
it)
|
||||
(The Wikipedia article has a decent animation for this process, so I
|
||||
will not add a graphic for that here)
|
||||
</p>
|
||||
<p>
|
||||
Now, this works well only if we can pick good starting points, and
|
||||
our curve is continuously differentiable and doesn't have
|
||||
oscillations. Glossing over the exact meaning of those terms, the
|
||||
curves we're dealing with conform to those constraints, so as long
|
||||
as we pick good starting points, this will work. So the question is:
|
||||
which starting points do we pick?
|
||||
our curve is
|
||||
<a href="https://en.wikipedia.org/wiki/Continuous_function"
|
||||
>continuously differentiable</a
|
||||
>
|
||||
and doesn't have
|
||||
<a href="https://en.wikipedia.org/wiki/Oscillation_(mathematics)"
|
||||
>oscillations</a
|
||||
>. Glossing over the exact meaning of those terms, the curves we're
|
||||
dealing with conform to those constraints, so as long as we pick
|
||||
good starting points, this will work. So the question is: which
|
||||
starting points do we pick?
|
||||
</p>
|
||||
<p>
|
||||
As it turns out, Newton-Raphson is so blindingly fast, so we could
|
||||
As it turns out, Newton-Raphson is so blindingly fast that we could
|
||||
get away with just not picking: we simply run the algorithm from
|
||||
<em>t=0</em> to <em>t=1</em> at small steps (say,
|
||||
1/200<sup>th</sup>) and the result will be all the roots we want. Of
|
||||
course, this may pose problems for high order Bézier curves: 200
|
||||
steps for a 200<sup>th</sup> order Bézier curve is going to go
|
||||
wrong, but that's okay: there is no reason, ever, to use Bézier
|
||||
curves of crazy high orders. You might use a fifth order curve to
|
||||
get the "nicest still remotely workable" approximation of a full
|
||||
circle with a single Bézier curve, that's pretty much as high as
|
||||
you'll ever need to go.
|
||||
wrong, but that's okay: there is no reason (at least, none that I
|
||||
know of) to <em>ever</em> use Bézier curves of crazy high orders.
|
||||
You might use a fifth order curve to get the "nicest still remotely
|
||||
workable" approximation of a full circle with a single Bézier curve,
|
||||
but that's pretty much as high as you'll ever need to go.
|
||||
</p>
|
||||
<h3>In conclusion:</h3>
|
||||
<p>
|
||||
@@ -3228,7 +3290,7 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<img
|
||||
width="825px"
|
||||
height="275px"
|
||||
src="images\chapters\extremities\d92d9d414c71c1917da540840c104170.png"
|
||||
src="images\chapters\extremities\4723d5fb04fe6aa379f7a73f7d251c84.png"
|
||||
loading="lazy"
|
||||
/>
|
||||
Scripts are disabled. Showing fallback image.
|
||||
@@ -3385,16 +3447,38 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
aligning our example curves to the x-axis, with the cubic case using
|
||||
the coordinates that were just used in the example formulae:
|
||||
</p>
|
||||
<Graphic
|
||||
<graphics-element
|
||||
title="Aligning a quadratic curve"
|
||||
setup="{this.setupQuadratic}"
|
||||
draw="{this.draw}"
|
||||
width="275"
|
||||
height="275"
|
||||
src="./chapters/aligning/quadratic.js"
|
||||
>
|
||||
<fallback-image>
|
||||
<img
|
||||
width="275px"
|
||||
height="275px"
|
||||
src="images\chapters\aligning\74a3ba53c0d1a79938bd2b1b8d57497d.png"
|
||||
loading="lazy"
|
||||
/>
|
||||
<Graphic
|
||||
Scripts are disabled. Showing fallback image.
|
||||
</fallback-image></graphics-element
|
||||
>
|
||||
<graphics-element
|
||||
title="Aligning a cubic curve"
|
||||
setup="{this.setupCubic}"
|
||||
draw="{this.draw}"
|
||||
width="275"
|
||||
height="275"
|
||||
src="./chapters/aligning/cubic.js"
|
||||
>
|
||||
<fallback-image>
|
||||
<img
|
||||
width="275px"
|
||||
height="275px"
|
||||
src="images\chapters\aligning\74a3ba53c0d1a79938bd2b1b8d57497d.png"
|
||||
loading="lazy"
|
||||
/>
|
||||
Scripts are disabled. Showing fallback image.
|
||||
</fallback-image></graphics-element
|
||||
>
|
||||
</section>
|
||||
<section id="tightbounds">
|
||||
<h1><a href="#tightbounds">Tight boxes</a></h1>
|
||||
|
262
ja-JP/index.html
262
ja-JP/index.html
@@ -2578,30 +2578,52 @@ function drawCurve(points[], t):
|
||||
Now that we understand (well, superficially anyway) the component
|
||||
functions, we can find the extremities of our Bézier curve by
|
||||
finding maxima and minima on the component functions, by solving the
|
||||
equations B'(t) = 0 and B''(t) = 0. That said, in the case of
|
||||
quadratic curves there is no B''(t), so we only need to compute
|
||||
B'(t) = 0. So, how do we compute the first and second derivatives?
|
||||
Fairly easily, actually, until our derivatives are 4th order or
|
||||
higher... then things get really hard. But let's start simple:
|
||||
equation B'(t) = 0. We've already seen that the derivative of a
|
||||
Bézier curve is a simpler Bézier curve, but how do we solve the
|
||||
equality? Fairly easily, actually, until our derivatives are 4th
|
||||
order or higher... then things get really hard. But let's start
|
||||
simple:
|
||||
</p>
|
||||
<h3>Quadratic curves: linear derivatives.</h3>
|
||||
<p>
|
||||
Finding the solution for "where is this line 0" should be trivial:
|
||||
The derivative of a quadratic Bézier curve is a linear Bézier curve,
|
||||
interpolating between just two terms, which means finding the
|
||||
solution for "where is this line 0" is effectively trivial by
|
||||
rewriting it to a function of <code>t</code> and solving. First we
|
||||
turn our cubic Bézier function into a quadratic one, by following
|
||||
the rule mentioned at the end of the
|
||||
<a href="#derivatives">derivatives section</a>:
|
||||
</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/ec28870926b6ed08625d942b578e6fbe.svg"
|
||||
width="132px"
|
||||
height="104px"
|
||||
src="images/latex/6db78123d4b676ffdf85d53670c77468.svg"
|
||||
width="189px"
|
||||
height="64px"
|
||||
/>
|
||||
<p>
|
||||
Done. And quadratic curves have no meaningful second derivative, so
|
||||
we're <em>really</em> done.
|
||||
And then we turn this into our solution for <code>t</code> using
|
||||
basic arithmetics:
|
||||
</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/1c0367fad2a0d6946db1f55a8520793a.svg"
|
||||
width="139px"
|
||||
height="77px"
|
||||
/>
|
||||
<p>Done.</p>
|
||||
<p>
|
||||
Although with the
|
||||
<a href="https://en.wikipedia.org/wiki/Caveat_emptor#Caveat_lector"
|
||||
>caveat</a
|
||||
>
|
||||
that if <code>b-a</code> is zero, there is no solution and we
|
||||
probably shouldn't try to perform that division.
|
||||
</p>
|
||||
<h3>Cubic curves: the quadratic formula.</h3>
|
||||
<p>
|
||||
The derivative of a cubic curve is a quadratic curve, and finding
|
||||
the roots for a quadratic Bézier curve means we can apply the
|
||||
The derivative of a cubic Bézier curve is a quadratic Bézier curve,
|
||||
and finding the roots for a quadratic polynomial means we can apply
|
||||
the
|
||||
<a href="https://en.wikipedia.org/wiki/Quadratic_formula"
|
||||
>Quadratic formula</a
|
||||
>. If you've seen it before, you'll remember it, and if you haven't,
|
||||
@@ -2614,7 +2636,7 @@ function drawCurve(points[], t):
|
||||
height="40px"
|
||||
/>
|
||||
<p>
|
||||
So, if we can express a Bézier component function as a plain
|
||||
So, if we can rewrite the Bézier component function as a plain
|
||||
polynomial, we're done: we just plug in the values into the
|
||||
quadratic formula, check if that square root is negative or not (if
|
||||
it is, there are no roots) and then just compute the two values that
|
||||
@@ -2645,11 +2667,10 @@ function drawCurve(points[], t):
|
||||
height="119px"
|
||||
/>
|
||||
<p>
|
||||
This gives us thee coefficients <em>a</em>, <em>b</em>, and
|
||||
<em>c</em> that are expressed in terms of <em>v</em> values, where
|
||||
the <em>v</em> values are just convenient expressions of our
|
||||
original <em>p</em> values, so we can do some trivial substitution
|
||||
to get:
|
||||
This gives us three coefficients {a, b, c} that are expressed in
|
||||
terms of <code>v</code> values, where the <code>v</code> values are
|
||||
expressions of our original coordinate values, so we can do some
|
||||
substitution to get:
|
||||
</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
@@ -2659,23 +2680,26 @@ function drawCurve(points[], t):
|
||||
/>
|
||||
<p>
|
||||
Easy-peasy. We can now almost trivially find the roots by plugging
|
||||
those values into the quadratic formula. We also note that the
|
||||
second derivative of a cubic curve means computing the first
|
||||
derivative of a quadratic curve, and we just saw how to do that in
|
||||
the section above.
|
||||
those values into the quadratic formula.
|
||||
</p>
|
||||
<h3>Quartic curves: Cardano's algorithm.</h3>
|
||||
<p>
|
||||
Quartic—fourth degree—curves have a cubic function as derivative.
|
||||
Now, cubic functions are a bit of a problem because they're really
|
||||
hard to solve. But, way back in the 16<sup>th</sup> century,
|
||||
We haven't really looked at them before now, but the next step up
|
||||
would be a Quartic curve, a fourth degree Bézier curve. As expected,
|
||||
these have a derivative that is a cubic function, and now things get
|
||||
much harder. Cubic functions don't have a "simple" rule to find
|
||||
their roots, like the quadratic formula, and instead require quite a
|
||||
bit of rewriting to a form that we can even start to try to solve.
|
||||
</p>
|
||||
<p>
|
||||
Back in the 16<sup>th</sup> century, before Bézier curves were a
|
||||
thing, and even before <em>calculus itself</em> was a thing,
|
||||
<a href="https://en.wikipedia.org/wiki/Gerolamo_Cardano"
|
||||
>Gerolamo Cardano</a
|
||||
>
|
||||
figured out that even if the general cubic function is really hard
|
||||
to solve, it can be rewritten to a form for which finding the roots
|
||||
is "easy", and then the only hard part is figuring out how to go
|
||||
from that form to the generic form. So:
|
||||
is "easier" (even if not "easy"):
|
||||
</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
@@ -2684,26 +2708,43 @@ function drawCurve(points[], t):
|
||||
height="44px"
|
||||
/>
|
||||
<p>
|
||||
This is easier because for the "easier formula" we can use
|
||||
We can see that the easier formula only has two constants, rather
|
||||
than four, and only two expressions involving <code>t</code>, rather
|
||||
than three: this makes things considerably easier to solve because
|
||||
it lets us use
|
||||
<a href="http://www.wolframalpha.com/input/?i=t%5E3+%2B+pt+%2B+q"
|
||||
>regular calculus</a
|
||||
>
|
||||
to find the roots. (As a cubic function, however, it can have up to
|
||||
three roots, but two of those can be complex. For the purpose of
|
||||
Bézier curve extremities, we can completely ignore those complex
|
||||
roots, since our <em>t</em> is a plain real number from 0 to 1.)
|
||||
to find the values that satisfy the equasion.
|
||||
</p>
|
||||
<p>
|
||||
So, the trick is to figure out how to turn the first formula into
|
||||
the second formula, and to then work out the maths that gives us the
|
||||
roots. This is explained in detail over at
|
||||
Now, there is one small hitch: as a cubic function, the solutions
|
||||
may be
|
||||
<a href="https://en.wikipedia.org/wiki/Complex_number"
|
||||
>complex numbers</a
|
||||
>
|
||||
rather than plain numbers... And Cardona realised this, centuries
|
||||
befor complex numbers were a well-understood and established part of
|
||||
number theory. His interpretation of them was "these numbers are
|
||||
impossible but that's okay because they disappear again in later
|
||||
steps", allowing him to not think about them too much, but we have
|
||||
it even easier: as we're trying to find the roots for display
|
||||
purposes, we don't even <em>care</em> about complex numbers: we're
|
||||
going to simplify Cardano's approach just that tiny bit further by
|
||||
throwing away any solution that's not a plain number.
|
||||
</p>
|
||||
<p>
|
||||
So, how do we rewrite the hard formula into the easier formula? This
|
||||
is explained in detail over at
|
||||
<a
|
||||
href="https://trans4mind.com/personal_development/mathematics/polynomials/cubicAlgebra.htm"
|
||||
>Ken J. Ward's page</a
|
||||
>
|
||||
for solving the cubic equation, so instead of showing the maths, I'm
|
||||
simply going to show the programming code for solving the cubic
|
||||
equation, with the complex roots getting totally ignored.
|
||||
equation, with the complex roots getting totally ignored, but if
|
||||
you're interested you should definitely head over to Ken's page and
|
||||
give the procedure a read-through.
|
||||
</p>
|
||||
<div class="howtocode">
|
||||
<h3>Implementing Cardano's algorithm for finding all real roots</h3>
|
||||
@@ -2805,24 +2846,41 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<p>
|
||||
And that's it. The maths is complicated, but the code is pretty much
|
||||
just "follow the maths, while caching as many values as we can to
|
||||
reduce recomputing things as much as possible" and now we have a way
|
||||
to find all roots for a cubic function and can just move on with
|
||||
prevent recomputing things as much as possible" and now we have a
|
||||
way to find all roots for a cubic function and can just move on with
|
||||
using that to find extremities of our curves.
|
||||
</p>
|
||||
<h3>Quintic and higher order curves: finding numerical solutions</h3>
|
||||
<p>
|
||||
The problem with this is that as the order of the curve goes up, we
|
||||
can't actually solve those equations the normal way. We can't take
|
||||
the function, and then work out what the solutions are. Not to
|
||||
mention that even solving a third order derivative (for a fourth
|
||||
order curve) is already a royal pain in the backside. We need a
|
||||
better solution. We need numerical approaches.
|
||||
And this is where thing stop, because we <em>cannot</em> find the
|
||||
roots for polynomials of degree 5 or higher using algebra (a fact
|
||||
known as
|
||||
<a href="https://en.wikipedia.org/wiki/Abel%E2%80%93Ruffini_theorem"
|
||||
>the Abel–Ruffini theorem</a
|
||||
>). Instead, for occasions like these, where algebra simply cannot
|
||||
yield an answer, we turn to
|
||||
<a href="https://en.wikipedia.org/wiki/Numerical_analysis"
|
||||
>numerical analysis</a
|
||||
>.
|
||||
</p>
|
||||
<p>
|
||||
That's a fancy word for saying "rather than solve the function,
|
||||
treat the problem as a sequence of identical operations, the
|
||||
performing of which gets us closer and closer to the real answer".
|
||||
As it turns out, there is a really nice numerical root-finding
|
||||
That's a fancy term for saying "rather than trying to find exact
|
||||
answers by manipulating symbols, find approximate answers by
|
||||
describing the underlying process as a combination of steps, each of
|
||||
which <em>can</em> be assigned a number via symbolic manipulation".
|
||||
For example, trying to mathematically compute how much water fits in
|
||||
a completely crazy three dimensional shape is very hard, even if it
|
||||
got you the perfect, precise answer. A much easier approach, which
|
||||
would be less perfect but still entirely useful, would be to just
|
||||
grab a buck and start filling the shape until it was full: just
|
||||
count the number of buckets of water you used. And if we want a more
|
||||
precise answer, we can use smaller buckets.
|
||||
</p>
|
||||
<p>
|
||||
So that's what we're going to do here, too: we're going to treat the
|
||||
problem as a sequence of steps, and the smaller we can make each
|
||||
step, the closer we'll get to that "perfect, precise" answer. And as
|
||||
it turns out, there is a really nice numerical root-finding
|
||||
algorithm, called the
|
||||
<a href="http://en.wikipedia.org/wiki/Newton-Raphson"
|
||||
>Newton-Raphson</a
|
||||
@@ -2831,56 +2889,60 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<em
|
||||
><a href="https://en.wikipedia.org/wiki/Isaac_Newton">that</a></em
|
||||
>
|
||||
Newton), which we can make use of.
|
||||
Newton), which we can make use of. The Newton-Raphson approach
|
||||
consists of taking our impossible-to-solve function
|
||||
<code>f(x)</code>, picking some intial value
|
||||
<code>x</code> (literally any value will do), and calculating
|
||||
<code>f(x)</code>. We can think of that value as the "height" of the
|
||||
function at <code>x</code>. If that height is zero, we're done, we
|
||||
have found a root. If it isn't, we calculate the tangent line at
|
||||
<code>f(x)</code> and calculate at which <code>x</code> value
|
||||
<em>its</em> height is zero (which we've already seen is very easy).
|
||||
That will give us a new <code>x</code> and we repeat the process
|
||||
until we find a root.
|
||||
</p>
|
||||
<p>
|
||||
The Newton-Raphson approach consists of picking a value
|
||||
<em>t</em> (any value will do), and getting the corresponding value
|
||||
of the function at that <em>t</em> value. For normal functions, we
|
||||
can treat that value as a height. If the height is zero, we're done,
|
||||
we have found a root. If it's not, we take the tangent of the curve
|
||||
at that point, and extend it until it passes the x-axis, which will
|
||||
be at some new point <em>t</em>. We then repeat the procedure with
|
||||
this new value, and we keep doing this until we find our root.
|
||||
</p>
|
||||
<p>
|
||||
Mathematically, this means that for some <em>t</em>, at step
|
||||
<em>n=1</em>, we perform the following calculation until
|
||||
<em>f<sub>y</sub></em
|
||||
>(<em>t</em>) is zero, so that the next <em>t</em> is the same as
|
||||
the one we already have:
|
||||
Mathematically, this means that for some <code>x</code>, at step
|
||||
<code>n=1</code>, we perform the following calculation until
|
||||
<code>f<sub>y</sub>(x)</code> is zero, so that the next
|
||||
<code>t</code> is the same as the one we already have:
|
||||
</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/04336edba7697ca91861821e32fc14be.svg"
|
||||
width="124px"
|
||||
height="45px"
|
||||
src="images/latex/c621cc41f6f22ee1beedbcb510fa5b6b.svg"
|
||||
width="139px"
|
||||
height="43px"
|
||||
/>
|
||||
<p>
|
||||
(The Wikipedia article has a decent animation for this process, so
|
||||
I'm not adding a sketch for that here unless there are requests for
|
||||
it)
|
||||
(The Wikipedia article has a decent animation for this process, so I
|
||||
will not add a graphic for that here)
|
||||
</p>
|
||||
<p>
|
||||
Now, this works well only if we can pick good starting points, and
|
||||
our curve is continuously differentiable and doesn't have
|
||||
oscillations. Glossing over the exact meaning of those terms, the
|
||||
curves we're dealing with conform to those constraints, so as long
|
||||
as we pick good starting points, this will work. So the question is:
|
||||
which starting points do we pick?
|
||||
our curve is
|
||||
<a href="https://en.wikipedia.org/wiki/Continuous_function"
|
||||
>continuously differentiable</a
|
||||
>
|
||||
and doesn't have
|
||||
<a href="https://en.wikipedia.org/wiki/Oscillation_(mathematics)"
|
||||
>oscillations</a
|
||||
>. Glossing over the exact meaning of those terms, the curves we're
|
||||
dealing with conform to those constraints, so as long as we pick
|
||||
good starting points, this will work. So the question is: which
|
||||
starting points do we pick?
|
||||
</p>
|
||||
<p>
|
||||
As it turns out, Newton-Raphson is so blindingly fast, so we could
|
||||
As it turns out, Newton-Raphson is so blindingly fast that we could
|
||||
get away with just not picking: we simply run the algorithm from
|
||||
<em>t=0</em> to <em>t=1</em> at small steps (say,
|
||||
1/200<sup>th</sup>) and the result will be all the roots we want. Of
|
||||
course, this may pose problems for high order Bézier curves: 200
|
||||
steps for a 200<sup>th</sup> order Bézier curve is going to go
|
||||
wrong, but that's okay: there is no reason, ever, to use Bézier
|
||||
curves of crazy high orders. You might use a fifth order curve to
|
||||
get the "nicest still remotely workable" approximation of a full
|
||||
circle with a single Bézier curve, that's pretty much as high as
|
||||
you'll ever need to go.
|
||||
wrong, but that's okay: there is no reason (at least, none that I
|
||||
know of) to <em>ever</em> use Bézier curves of crazy high orders.
|
||||
You might use a fifth order curve to get the "nicest still remotely
|
||||
workable" approximation of a full circle with a single Bézier curve,
|
||||
but that's pretty much as high as you'll ever need to go.
|
||||
</p>
|
||||
<h3>In conclusion:</h3>
|
||||
<p>
|
||||
@@ -2898,7 +2960,7 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<img
|
||||
width="825px"
|
||||
height="275px"
|
||||
src="images\chapters\extremities\d92d9d414c71c1917da540840c104170.png"
|
||||
src="images\chapters\extremities\4723d5fb04fe6aa379f7a73f7d251c84.png"
|
||||
loading="lazy"
|
||||
/>
|
||||
Scripts are disabled. Showing fallback image.
|
||||
@@ -3055,16 +3117,38 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
aligning our example curves to the x-axis, with the cubic case using
|
||||
the coordinates that were just used in the example formulae:
|
||||
</p>
|
||||
<Graphic
|
||||
<graphics-element
|
||||
title="Aligning a quadratic curve"
|
||||
setup="{this.setupQuadratic}"
|
||||
draw="{this.draw}"
|
||||
width="275"
|
||||
height="275"
|
||||
src="./chapters/aligning/quadratic.js"
|
||||
>
|
||||
<fallback-image>
|
||||
<img
|
||||
width="275px"
|
||||
height="275px"
|
||||
src="images\chapters\aligning\74a3ba53c0d1a79938bd2b1b8d57497d.png"
|
||||
loading="lazy"
|
||||
/>
|
||||
<Graphic
|
||||
Scripts are disabled. Showing fallback image.
|
||||
</fallback-image></graphics-element
|
||||
>
|
||||
<graphics-element
|
||||
title="Aligning a cubic curve"
|
||||
setup="{this.setupCubic}"
|
||||
draw="{this.draw}"
|
||||
width="275"
|
||||
height="275"
|
||||
src="./chapters/aligning/cubic.js"
|
||||
>
|
||||
<fallback-image>
|
||||
<img
|
||||
width="275px"
|
||||
height="275px"
|
||||
src="images\chapters\aligning\74a3ba53c0d1a79938bd2b1b8d57497d.png"
|
||||
loading="lazy"
|
||||
/>
|
||||
Scripts are disabled. Showing fallback image.
|
||||
</fallback-image></graphics-element
|
||||
>
|
||||
</section>
|
||||
<section id="tightbounds">
|
||||
<h1><a href="ja-JP/index.html#tightbounds">Tight boxes</a></h1>
|
||||
|
@@ -9,7 +9,17 @@ nunjucks.configure(".", { autoescape: false });
|
||||
* ...docs go here...
|
||||
*/
|
||||
async function convertMarkDown(chapter, localeStrings, markdown) {
|
||||
markdown = await preprocessGraphicsElement(chapter, localeStrings, markdown);
|
||||
try {
|
||||
markdown = await preprocessGraphicsElement(
|
||||
chapter,
|
||||
localeStrings,
|
||||
markdown
|
||||
);
|
||||
} catch (e) {
|
||||
console.error(`Error in ${chapter}:${localeStrings.currentLocale}.`);
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// This yields the original markdown with all LaTeX blocked replaced with
|
||||
// uniquely named templating variables, referencing keys in the `latex` array.
|
||||
|
@@ -34,7 +34,7 @@ async function preprocessGraphicsElement(chapter, localeStrings, markdown) {
|
||||
|
||||
if (updated.indexOf(`height=`) === -1)
|
||||
updated = updated.replace(
|
||||
/width="(\d+)\s*"/,
|
||||
/width="(\d+)"\s*/,
|
||||
`width="$1" height="275" `
|
||||
);
|
||||
|
||||
@@ -42,6 +42,7 @@ async function preprocessGraphicsElement(chapter, localeStrings, markdown) {
|
||||
const terms = updated.match(
|
||||
/width="([^"]+)"\s+height="([^"]+)"\s+src="([^"]+)"\s*>/
|
||||
);
|
||||
|
||||
const [original, width, height] = terms;
|
||||
|
||||
let src = terms[3];
|
||||
|
262
zh-CN/index.html
262
zh-CN/index.html
@@ -2588,30 +2588,52 @@ function drawCurve(points[], t):
|
||||
Now that we understand (well, superficially anyway) the component
|
||||
functions, we can find the extremities of our Bézier curve by
|
||||
finding maxima and minima on the component functions, by solving the
|
||||
equations B'(t) = 0 and B''(t) = 0. That said, in the case of
|
||||
quadratic curves there is no B''(t), so we only need to compute
|
||||
B'(t) = 0. So, how do we compute the first and second derivatives?
|
||||
Fairly easily, actually, until our derivatives are 4th order or
|
||||
higher... then things get really hard. But let's start simple:
|
||||
equation B'(t) = 0. We've already seen that the derivative of a
|
||||
Bézier curve is a simpler Bézier curve, but how do we solve the
|
||||
equality? Fairly easily, actually, until our derivatives are 4th
|
||||
order or higher... then things get really hard. But let's start
|
||||
simple:
|
||||
</p>
|
||||
<h3>Quadratic curves: linear derivatives.</h3>
|
||||
<p>
|
||||
Finding the solution for "where is this line 0" should be trivial:
|
||||
The derivative of a quadratic Bézier curve is a linear Bézier curve,
|
||||
interpolating between just two terms, which means finding the
|
||||
solution for "where is this line 0" is effectively trivial by
|
||||
rewriting it to a function of <code>t</code> and solving. First we
|
||||
turn our cubic Bézier function into a quadratic one, by following
|
||||
the rule mentioned at the end of the
|
||||
<a href="#derivatives">derivatives section</a>:
|
||||
</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/ec28870926b6ed08625d942b578e6fbe.svg"
|
||||
width="132px"
|
||||
height="104px"
|
||||
src="images/latex/6db78123d4b676ffdf85d53670c77468.svg"
|
||||
width="189px"
|
||||
height="64px"
|
||||
/>
|
||||
<p>
|
||||
Done. And quadratic curves have no meaningful second derivative, so
|
||||
we're <em>really</em> done.
|
||||
And then we turn this into our solution for <code>t</code> using
|
||||
basic arithmetics:
|
||||
</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/1c0367fad2a0d6946db1f55a8520793a.svg"
|
||||
width="139px"
|
||||
height="77px"
|
||||
/>
|
||||
<p>Done.</p>
|
||||
<p>
|
||||
Although with the
|
||||
<a href="https://en.wikipedia.org/wiki/Caveat_emptor#Caveat_lector"
|
||||
>caveat</a
|
||||
>
|
||||
that if <code>b-a</code> is zero, there is no solution and we
|
||||
probably shouldn't try to perform that division.
|
||||
</p>
|
||||
<h3>Cubic curves: the quadratic formula.</h3>
|
||||
<p>
|
||||
The derivative of a cubic curve is a quadratic curve, and finding
|
||||
the roots for a quadratic Bézier curve means we can apply the
|
||||
The derivative of a cubic Bézier curve is a quadratic Bézier curve,
|
||||
and finding the roots for a quadratic polynomial means we can apply
|
||||
the
|
||||
<a href="https://en.wikipedia.org/wiki/Quadratic_formula"
|
||||
>Quadratic formula</a
|
||||
>. If you've seen it before, you'll remember it, and if you haven't,
|
||||
@@ -2624,7 +2646,7 @@ function drawCurve(points[], t):
|
||||
height="40px"
|
||||
/>
|
||||
<p>
|
||||
So, if we can express a Bézier component function as a plain
|
||||
So, if we can rewrite the Bézier component function as a plain
|
||||
polynomial, we're done: we just plug in the values into the
|
||||
quadratic formula, check if that square root is negative or not (if
|
||||
it is, there are no roots) and then just compute the two values that
|
||||
@@ -2655,11 +2677,10 @@ function drawCurve(points[], t):
|
||||
height="119px"
|
||||
/>
|
||||
<p>
|
||||
This gives us thee coefficients <em>a</em>, <em>b</em>, and
|
||||
<em>c</em> that are expressed in terms of <em>v</em> values, where
|
||||
the <em>v</em> values are just convenient expressions of our
|
||||
original <em>p</em> values, so we can do some trivial substitution
|
||||
to get:
|
||||
This gives us three coefficients {a, b, c} that are expressed in
|
||||
terms of <code>v</code> values, where the <code>v</code> values are
|
||||
expressions of our original coordinate values, so we can do some
|
||||
substitution to get:
|
||||
</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
@@ -2669,23 +2690,26 @@ function drawCurve(points[], t):
|
||||
/>
|
||||
<p>
|
||||
Easy-peasy. We can now almost trivially find the roots by plugging
|
||||
those values into the quadratic formula. We also note that the
|
||||
second derivative of a cubic curve means computing the first
|
||||
derivative of a quadratic curve, and we just saw how to do that in
|
||||
the section above.
|
||||
those values into the quadratic formula.
|
||||
</p>
|
||||
<h3>Quartic curves: Cardano's algorithm.</h3>
|
||||
<p>
|
||||
Quartic—fourth degree—curves have a cubic function as derivative.
|
||||
Now, cubic functions are a bit of a problem because they're really
|
||||
hard to solve. But, way back in the 16<sup>th</sup> century,
|
||||
We haven't really looked at them before now, but the next step up
|
||||
would be a Quartic curve, a fourth degree Bézier curve. As expected,
|
||||
these have a derivative that is a cubic function, and now things get
|
||||
much harder. Cubic functions don't have a "simple" rule to find
|
||||
their roots, like the quadratic formula, and instead require quite a
|
||||
bit of rewriting to a form that we can even start to try to solve.
|
||||
</p>
|
||||
<p>
|
||||
Back in the 16<sup>th</sup> century, before Bézier curves were a
|
||||
thing, and even before <em>calculus itself</em> was a thing,
|
||||
<a href="https://en.wikipedia.org/wiki/Gerolamo_Cardano"
|
||||
>Gerolamo Cardano</a
|
||||
>
|
||||
figured out that even if the general cubic function is really hard
|
||||
to solve, it can be rewritten to a form for which finding the roots
|
||||
is "easy", and then the only hard part is figuring out how to go
|
||||
from that form to the generic form. So:
|
||||
is "easier" (even if not "easy"):
|
||||
</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
@@ -2694,26 +2718,43 @@ function drawCurve(points[], t):
|
||||
height="44px"
|
||||
/>
|
||||
<p>
|
||||
This is easier because for the "easier formula" we can use
|
||||
We can see that the easier formula only has two constants, rather
|
||||
than four, and only two expressions involving <code>t</code>, rather
|
||||
than three: this makes things considerably easier to solve because
|
||||
it lets us use
|
||||
<a href="http://www.wolframalpha.com/input/?i=t%5E3+%2B+pt+%2B+q"
|
||||
>regular calculus</a
|
||||
>
|
||||
to find the roots. (As a cubic function, however, it can have up to
|
||||
three roots, but two of those can be complex. For the purpose of
|
||||
Bézier curve extremities, we can completely ignore those complex
|
||||
roots, since our <em>t</em> is a plain real number from 0 to 1.)
|
||||
to find the values that satisfy the equasion.
|
||||
</p>
|
||||
<p>
|
||||
So, the trick is to figure out how to turn the first formula into
|
||||
the second formula, and to then work out the maths that gives us the
|
||||
roots. This is explained in detail over at
|
||||
Now, there is one small hitch: as a cubic function, the solutions
|
||||
may be
|
||||
<a href="https://en.wikipedia.org/wiki/Complex_number"
|
||||
>complex numbers</a
|
||||
>
|
||||
rather than plain numbers... And Cardona realised this, centuries
|
||||
befor complex numbers were a well-understood and established part of
|
||||
number theory. His interpretation of them was "these numbers are
|
||||
impossible but that's okay because they disappear again in later
|
||||
steps", allowing him to not think about them too much, but we have
|
||||
it even easier: as we're trying to find the roots for display
|
||||
purposes, we don't even <em>care</em> about complex numbers: we're
|
||||
going to simplify Cardano's approach just that tiny bit further by
|
||||
throwing away any solution that's not a plain number.
|
||||
</p>
|
||||
<p>
|
||||
So, how do we rewrite the hard formula into the easier formula? This
|
||||
is explained in detail over at
|
||||
<a
|
||||
href="https://trans4mind.com/personal_development/mathematics/polynomials/cubicAlgebra.htm"
|
||||
>Ken J. Ward's page</a
|
||||
>
|
||||
for solving the cubic equation, so instead of showing the maths, I'm
|
||||
simply going to show the programming code for solving the cubic
|
||||
equation, with the complex roots getting totally ignored.
|
||||
equation, with the complex roots getting totally ignored, but if
|
||||
you're interested you should definitely head over to Ken's page and
|
||||
give the procedure a read-through.
|
||||
</p>
|
||||
<div class="howtocode">
|
||||
<h3>Implementing Cardano's algorithm for finding all real roots</h3>
|
||||
@@ -2815,24 +2856,41 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<p>
|
||||
And that's it. The maths is complicated, but the code is pretty much
|
||||
just "follow the maths, while caching as many values as we can to
|
||||
reduce recomputing things as much as possible" and now we have a way
|
||||
to find all roots for a cubic function and can just move on with
|
||||
prevent recomputing things as much as possible" and now we have a
|
||||
way to find all roots for a cubic function and can just move on with
|
||||
using that to find extremities of our curves.
|
||||
</p>
|
||||
<h3>Quintic and higher order curves: finding numerical solutions</h3>
|
||||
<p>
|
||||
The problem with this is that as the order of the curve goes up, we
|
||||
can't actually solve those equations the normal way. We can't take
|
||||
the function, and then work out what the solutions are. Not to
|
||||
mention that even solving a third order derivative (for a fourth
|
||||
order curve) is already a royal pain in the backside. We need a
|
||||
better solution. We need numerical approaches.
|
||||
And this is where thing stop, because we <em>cannot</em> find the
|
||||
roots for polynomials of degree 5 or higher using algebra (a fact
|
||||
known as
|
||||
<a href="https://en.wikipedia.org/wiki/Abel%E2%80%93Ruffini_theorem"
|
||||
>the Abel–Ruffini theorem</a
|
||||
>). Instead, for occasions like these, where algebra simply cannot
|
||||
yield an answer, we turn to
|
||||
<a href="https://en.wikipedia.org/wiki/Numerical_analysis"
|
||||
>numerical analysis</a
|
||||
>.
|
||||
</p>
|
||||
<p>
|
||||
That's a fancy word for saying "rather than solve the function,
|
||||
treat the problem as a sequence of identical operations, the
|
||||
performing of which gets us closer and closer to the real answer".
|
||||
As it turns out, there is a really nice numerical root-finding
|
||||
That's a fancy term for saying "rather than trying to find exact
|
||||
answers by manipulating symbols, find approximate answers by
|
||||
describing the underlying process as a combination of steps, each of
|
||||
which <em>can</em> be assigned a number via symbolic manipulation".
|
||||
For example, trying to mathematically compute how much water fits in
|
||||
a completely crazy three dimensional shape is very hard, even if it
|
||||
got you the perfect, precise answer. A much easier approach, which
|
||||
would be less perfect but still entirely useful, would be to just
|
||||
grab a buck and start filling the shape until it was full: just
|
||||
count the number of buckets of water you used. And if we want a more
|
||||
precise answer, we can use smaller buckets.
|
||||
</p>
|
||||
<p>
|
||||
So that's what we're going to do here, too: we're going to treat the
|
||||
problem as a sequence of steps, and the smaller we can make each
|
||||
step, the closer we'll get to that "perfect, precise" answer. And as
|
||||
it turns out, there is a really nice numerical root-finding
|
||||
algorithm, called the
|
||||
<a href="http://en.wikipedia.org/wiki/Newton-Raphson"
|
||||
>Newton-Raphson</a
|
||||
@@ -2841,56 +2899,60 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<em
|
||||
><a href="https://en.wikipedia.org/wiki/Isaac_Newton">that</a></em
|
||||
>
|
||||
Newton), which we can make use of.
|
||||
Newton), which we can make use of. The Newton-Raphson approach
|
||||
consists of taking our impossible-to-solve function
|
||||
<code>f(x)</code>, picking some intial value
|
||||
<code>x</code> (literally any value will do), and calculating
|
||||
<code>f(x)</code>. We can think of that value as the "height" of the
|
||||
function at <code>x</code>. If that height is zero, we're done, we
|
||||
have found a root. If it isn't, we calculate the tangent line at
|
||||
<code>f(x)</code> and calculate at which <code>x</code> value
|
||||
<em>its</em> height is zero (which we've already seen is very easy).
|
||||
That will give us a new <code>x</code> and we repeat the process
|
||||
until we find a root.
|
||||
</p>
|
||||
<p>
|
||||
The Newton-Raphson approach consists of picking a value
|
||||
<em>t</em> (any value will do), and getting the corresponding value
|
||||
of the function at that <em>t</em> value. For normal functions, we
|
||||
can treat that value as a height. If the height is zero, we're done,
|
||||
we have found a root. If it's not, we take the tangent of the curve
|
||||
at that point, and extend it until it passes the x-axis, which will
|
||||
be at some new point <em>t</em>. We then repeat the procedure with
|
||||
this new value, and we keep doing this until we find our root.
|
||||
</p>
|
||||
<p>
|
||||
Mathematically, this means that for some <em>t</em>, at step
|
||||
<em>n=1</em>, we perform the following calculation until
|
||||
<em>f<sub>y</sub></em
|
||||
>(<em>t</em>) is zero, so that the next <em>t</em> is the same as
|
||||
the one we already have:
|
||||
Mathematically, this means that for some <code>x</code>, at step
|
||||
<code>n=1</code>, we perform the following calculation until
|
||||
<code>f<sub>y</sub>(x)</code> is zero, so that the next
|
||||
<code>t</code> is the same as the one we already have:
|
||||
</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/04336edba7697ca91861821e32fc14be.svg"
|
||||
width="124px"
|
||||
height="45px"
|
||||
src="images/latex/c621cc41f6f22ee1beedbcb510fa5b6b.svg"
|
||||
width="139px"
|
||||
height="43px"
|
||||
/>
|
||||
<p>
|
||||
(The Wikipedia article has a decent animation for this process, so
|
||||
I'm not adding a sketch for that here unless there are requests for
|
||||
it)
|
||||
(The Wikipedia article has a decent animation for this process, so I
|
||||
will not add a graphic for that here)
|
||||
</p>
|
||||
<p>
|
||||
Now, this works well only if we can pick good starting points, and
|
||||
our curve is continuously differentiable and doesn't have
|
||||
oscillations. Glossing over the exact meaning of those terms, the
|
||||
curves we're dealing with conform to those constraints, so as long
|
||||
as we pick good starting points, this will work. So the question is:
|
||||
which starting points do we pick?
|
||||
our curve is
|
||||
<a href="https://en.wikipedia.org/wiki/Continuous_function"
|
||||
>continuously differentiable</a
|
||||
>
|
||||
and doesn't have
|
||||
<a href="https://en.wikipedia.org/wiki/Oscillation_(mathematics)"
|
||||
>oscillations</a
|
||||
>. Glossing over the exact meaning of those terms, the curves we're
|
||||
dealing with conform to those constraints, so as long as we pick
|
||||
good starting points, this will work. So the question is: which
|
||||
starting points do we pick?
|
||||
</p>
|
||||
<p>
|
||||
As it turns out, Newton-Raphson is so blindingly fast, so we could
|
||||
As it turns out, Newton-Raphson is so blindingly fast that we could
|
||||
get away with just not picking: we simply run the algorithm from
|
||||
<em>t=0</em> to <em>t=1</em> at small steps (say,
|
||||
1/200<sup>th</sup>) and the result will be all the roots we want. Of
|
||||
course, this may pose problems for high order Bézier curves: 200
|
||||
steps for a 200<sup>th</sup> order Bézier curve is going to go
|
||||
wrong, but that's okay: there is no reason, ever, to use Bézier
|
||||
curves of crazy high orders. You might use a fifth order curve to
|
||||
get the "nicest still remotely workable" approximation of a full
|
||||
circle with a single Bézier curve, that's pretty much as high as
|
||||
you'll ever need to go.
|
||||
wrong, but that's okay: there is no reason (at least, none that I
|
||||
know of) to <em>ever</em> use Bézier curves of crazy high orders.
|
||||
You might use a fifth order curve to get the "nicest still remotely
|
||||
workable" approximation of a full circle with a single Bézier curve,
|
||||
but that's pretty much as high as you'll ever need to go.
|
||||
</p>
|
||||
<h3>In conclusion:</h3>
|
||||
<p>
|
||||
@@ -2908,7 +2970,7 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<img
|
||||
width="825px"
|
||||
height="275px"
|
||||
src="images\chapters\extremities\d92d9d414c71c1917da540840c104170.png"
|
||||
src="images\chapters\extremities\4723d5fb04fe6aa379f7a73f7d251c84.png"
|
||||
loading="lazy"
|
||||
/>
|
||||
Scripts are disabled. Showing fallback image.
|
||||
@@ -3065,16 +3127,38 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
aligning our example curves to the x-axis, with the cubic case using
|
||||
the coordinates that were just used in the example formulae:
|
||||
</p>
|
||||
<Graphic
|
||||
<graphics-element
|
||||
title="Aligning a quadratic curve"
|
||||
setup="{this.setupQuadratic}"
|
||||
draw="{this.draw}"
|
||||
width="275"
|
||||
height="275"
|
||||
src="./chapters/aligning/quadratic.js"
|
||||
>
|
||||
<fallback-image>
|
||||
<img
|
||||
width="275px"
|
||||
height="275px"
|
||||
src="images\chapters\aligning\74a3ba53c0d1a79938bd2b1b8d57497d.png"
|
||||
loading="lazy"
|
||||
/>
|
||||
<Graphic
|
||||
Scripts are disabled. Showing fallback image.
|
||||
</fallback-image></graphics-element
|
||||
>
|
||||
<graphics-element
|
||||
title="Aligning a cubic curve"
|
||||
setup="{this.setupCubic}"
|
||||
draw="{this.draw}"
|
||||
width="275"
|
||||
height="275"
|
||||
src="./chapters/aligning/cubic.js"
|
||||
>
|
||||
<fallback-image>
|
||||
<img
|
||||
width="275px"
|
||||
height="275px"
|
||||
src="images\chapters\aligning\74a3ba53c0d1a79938bd2b1b8d57497d.png"
|
||||
loading="lazy"
|
||||
/>
|
||||
Scripts are disabled. Showing fallback image.
|
||||
</fallback-image></graphics-element
|
||||
>
|
||||
</section>
|
||||
<section id="tightbounds">
|
||||
<h1><a href="zh-CN/index.html#tightbounds">Tight boxes</a></h1>
|
||||
|
Reference in New Issue
Block a user