inflections
@@ -71,6 +71,8 @@ This gives us three coefficients {a, b, c} that are expressed in terms of `v` va
|
||||
|
||||
Easy-peasy. We can now almost trivially find the roots by plugging those values into the quadratic formula.
|
||||
|
||||
And as a cubic curve, there is also a meaningful second derivative, which we can compute by simple taking the derivative of the derivative.
|
||||
|
||||
### Quartic curves: Cardano's algorithm.
|
||||
|
||||
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.
|
||||
@@ -185,6 +187,9 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
|
||||
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.
|
||||
|
||||
And of course, as a quartic curve also has meaningful second and third derivatives, we can quite easily compute those by using the derivative of the derivative (of the derivative), just as for cubic cuvers.
|
||||
|
||||
|
||||
### Quintic and higher order curves: finding numerical solutions
|
||||
|
||||
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).
|
||||
@@ -207,7 +212,10 @@ As it turns out, Newton-Raphson is so blindingly fast that we could get away wit
|
||||
|
||||
### In conclusion:
|
||||
|
||||
So now that we know how to do root finding, we can determine the first and second derivative roots for our Bézier curves, and show those roots overlaid on the previous graphics:
|
||||
So now that we know how to do root finding, we can determine the first and second derivative roots for our Bézier curves, and show those roots overlaid on the previous graphics. For the quadratic curve, that means just the first derivative, in red:
|
||||
|
||||
<graphics-element title="Quadratic Bézier curve extremities" width="825" src="./quadratic.js"></graphics-element>
|
||||
|
||||
And for cubic curves, that means first and second derivatives, in red and purple respectively:
|
||||
|
||||
<graphics-element title="Cubic Bézier curve extremities" width="825" src="./cubic.js"></graphics-element>
|
||||
|
@@ -46,7 +46,7 @@ plotDimension(dim, dimension) {
|
||||
dimension.drawCurve();
|
||||
|
||||
setFill(`red`);
|
||||
setStroke(`red)`);
|
||||
setStroke(`red`);
|
||||
|
||||
// There are four possible extrema: t=0, t=1, and
|
||||
// up to two t values that solves B'(t)=0, provided
|
||||
@@ -80,15 +80,31 @@ plotDimension(dim, dimension) {
|
||||
}
|
||||
});
|
||||
|
||||
// Done, show our extrema:
|
||||
// Done, show our derivative-based extrema:
|
||||
circle(t1 * dim, y1, 3);
|
||||
text(`t = ${t1.toFixed(2)}`, map(t1, 0,1, 15,dim-15), y1 + 25);
|
||||
circle(t2 * dim, y2, 3);
|
||||
text(`t = ${t2.toFixed(2)}`, map(t2, 0,1, 15,dim-15), y2 + 25);
|
||||
|
||||
// And then show the second derivate inflection, if there is one
|
||||
setFill(`purple`);
|
||||
setStroke(`purple`);
|
||||
this.getRoots(...dimension.dpoints[1].map(p => p.y)).forEach(t =>{
|
||||
if (t > 0 && t < 1) {
|
||||
let d = dimension.get(t);
|
||||
circle(t * dim, d.y, 3);
|
||||
text(`t = ${t.toFixed(2)}`, map(t, 0,1, 15,dim-15), d.y + 25);
|
||||
}
|
||||
});
|
||||
|
||||
restoreStyle();
|
||||
}
|
||||
|
||||
getRoots(v1, v2, v3) {
|
||||
if (v3 === undefined) {
|
||||
return [-v1 / (v2 - v1)];
|
||||
}
|
||||
|
||||
const a = v1 - 2*v2 + v3,
|
||||
b = 2 * (v2 - v1),
|
||||
c = v1,
|
||||
|
@@ -60,10 +60,10 @@ That is... unwieldy. So, we note that there are a lot of terms that involve mult
|
||||
|
||||
</div>
|
||||
|
||||
Aligning our curve so that three of the eight coefficients become zero, we end up with the following simple term function for *C(t)*:
|
||||
Aligning our curve so that three of the eight coefficients become zero, and observing that scale does not affect finding `t` values, we end up with the following simple term function for *C(t)*:
|
||||
|
||||
\[
|
||||
18 \left ( (3 x_3 y_2+2 x_4 y_2+3 x_2 y_3-x_4 y_3)t^2 + (3 x_3 y_2-x_4 y_2-3 x_2 y_3)t + (x_2 y_3-x_3 y_2) \right )
|
||||
\left ( 3 x_3 y_2+2 x_4 y_2+3 x_2 y_3-x_4 y_3 \right ) t^2 + \left ( 3 x_3 y_2-x_4 y_2-3 x_2 y_3 \right ) t + \left ( x_2 y_3-x_3 y_2 \right )
|
||||
\]
|
||||
|
||||
That's a lot easier to work with: we see a fair number of terms that we can compute and then cache, giving us the following simplification:
|
||||
@@ -75,16 +75,16 @@ That's a lot easier to work with: we see a fair number of terms that we can comp
|
||||
c = x_2 \cdot y_3 \\
|
||||
d = x_4 \cdot y_3
|
||||
\end{matrix}\right\}
|
||||
\ C(t) = 18 \cdot \left ( (-3a + 2b + 3c - d)t^2 + (3a - b - 3c)t + (c - a) \right )
|
||||
\ C(t) = (-3a + 2b + 3c - d)t^2 + (3a - b - 3c)t + (c - a)
|
||||
\]
|
||||
|
||||
This is a plain quadratic curve, and we know how to solve *C(t) = 0*; we use the quadratic formula:
|
||||
|
||||
\[
|
||||
\left.\begin{matrix}
|
||||
x =& 18(-3a + 2b + 3c - d) \\
|
||||
y =& 18(3a - b - 3c) \\
|
||||
z =& 18(c - a)
|
||||
x =& -3a + 2b + 3c - d \\
|
||||
y =& 3a - b - 3c \\
|
||||
z =& c - a
|
||||
\end{matrix}\right\}
|
||||
\ C(t) = 0 \ \Rightarrow\ t = \frac{-y \pm \sqrt{y^2 - 4 x z}}{2x}
|
||||
\]
|
||||
@@ -93,4 +93,4 @@ We can easily compute this value *if* the discriminator isn't a negative number
|
||||
|
||||
Taking that into account, we compute *t*, we disregard any *t* value that isn't in the Bézier interval [0,1], and we now know at which *t* value(s) our curve will inflect.
|
||||
|
||||
<Graphic title="Finding cubic Bézier curve inflections" setup={this.setupCubic} draw={this.draw}/>
|
||||
<graphics-element title="Finding cubic Bézier curve inflections" src="./inflection.js"></graphics-element>
|
||||
|
@@ -1,17 +0,0 @@
|
||||
module.exports = {
|
||||
setupCubic: function(api) {
|
||||
var curve = new api.Bezier(135,25, 25, 135, 215,75, 215,240);
|
||||
api.setCurve(curve);
|
||||
},
|
||||
|
||||
draw: function(api, curve) {
|
||||
api.reset();
|
||||
api.drawSkeleton(curve);
|
||||
api.drawCurve(curve);
|
||||
|
||||
api.setColor("red");
|
||||
curve.inflections().forEach(function(t) {
|
||||
api.drawCircle(curve.get(t), 5);
|
||||
});
|
||||
}
|
||||
};
|
62
chapters/inflections/inflection.js
Normal file
@@ -0,0 +1,62 @@
|
||||
setup() {
|
||||
const curve = this.curve = new Bezier(this, 70,250, 120,15, 20,95, 225,80);
|
||||
setMovable(curve.points);
|
||||
}
|
||||
|
||||
draw() {
|
||||
clear();
|
||||
|
||||
const curve = this.curve;
|
||||
curve.drawSkeleton();
|
||||
curve.drawCurve();
|
||||
curve.drawPoints();
|
||||
|
||||
const p = curve.align().points,
|
||||
|
||||
a = p[2].x * p[1].y,
|
||||
b = p[3].x * p[1].y,
|
||||
c = p[1].x * p[2].y,
|
||||
d = p[3].x * p[2].y,
|
||||
|
||||
x = -3*a + 2*b + 3*c - d,
|
||||
y = 3*a - b - 3*c,
|
||||
z = c - a,
|
||||
|
||||
roots = [];
|
||||
|
||||
if (this.almost(x, 0) ) {
|
||||
if (!this.almost(y, 0) ) {
|
||||
roots.push(-z / y);
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
const det = y * y - 4 * x * z,
|
||||
sq = sqrt(det),
|
||||
d2 = 2 * x;
|
||||
|
||||
if (!this.almost(d2, 0) ) {
|
||||
roots.push(-(y+sq) / d2);
|
||||
roots.push((sq-y) / d2);
|
||||
}
|
||||
}
|
||||
|
||||
setStroke(`red`);
|
||||
setFill(`red`);
|
||||
|
||||
roots.forEach(t => {
|
||||
if (0 <= t && t <= 1) {
|
||||
let p = curve.get(t);
|
||||
circle(p.x, p.y, 3);
|
||||
text(`t=${t.toFixed(2)}`, p.x + 5, p.y + 15);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
almost(v1, v2, epsilon=0.00001) {
|
||||
return abs(v1 - v2) < epsilon;
|
||||
}
|
||||
|
||||
onMouseMove() {
|
||||
redraw();
|
||||
}
|
BIN
images/chapters/extremities/1440c49b9192919163dc44d6b0cf156b.png
Normal file
After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 23 KiB |
BIN
images/chapters/inflections/e81a6573cf3ea31045eb7e8dca3eecb3.png
Normal file
After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 14 KiB |
1
images/latex/1679090a942a43d27f886f236fc8d62b.svg
Normal file
After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 10 KiB |
1
images/latex/4b5c7d0bf0fcd769db007dd98d4a024d.svg
Normal file
After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 9.6 KiB |
1
images/latex/7c9762c0e04693eb743905cdc0487f8b.svg
Normal file
After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 14 KiB |
@@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="44pt" height="16" viewBox="0 0 44 12"><defs><symbol overflow="visible" id="a"><path d="M7.781-8.219c-.922-.344-1.593-.484-2.328-.484-.984 0-2.078.344-2.906.89C1.14-6.859.39-5.358.39-3.53c0 2.328 1.421 3.75 3.703 3.75C5.25.219 6.187-.094 7.28-.844l.157-.578-.266-.187c-1.234.765-1.75.921-2.672.921-1.89 0-2.781-1.015-2.781-3.14 0-1.328.375-2.406 1.11-3.156.546-.563 1.218-.829 2.171-.829.86 0 1.36.141 2 .547v1.063h.578c.078-.813.172-1.328.36-1.953zm0 0"/></symbol><symbol overflow="visible" id="b"><path d="M4.203-7.828a.735.735 0 01-.187-.14c-.063-.063-.11-.126-.22-.329-1.593 1.61-2.5 3.266-2.5 4.781v.797c0 1.516.907 3.172 2.5 4.781.11-.203.157-.265.22-.328.062-.062.125-.109.312-.203C2.875.063 2.281-1.344 2.281-2.719v-.797c0-1.39.594-2.78 2.047-4.25zm0 0"/></symbol><symbol overflow="visible" id="c"><path d="M3.703-5.516c-.453.047-.86.063-1.156.063.172-.984.297-1.578.531-2.25l-.25-.328a7.16 7.16 0 01-1.094.531l-.296 2.031c-.391.203-.704.328-1.063.407l-.047.406h1l-.64 3.25C.625-1.11.53-.813.53-.5c0 .297.266.61.5.61.422 0 .922-.282 1.86-1.032.218-.172.14-.125.437-.36l-.25-.437-.672.469c-.36.25-.484.313-.625.313-.093 0-.031.046-.031-.11 0-.297.156-1.234.516-3l.14-.61h1.266l.203-.89zm0 0"/></symbol><symbol overflow="visible" id="d"><path d="M3.766-2.719v-.797c0-1.515-.907-3.171-2.516-4.78-.11.202-.156.265-.203.327-.063.063-.125.11-.313.203 1.438 1.47 2.032 2.86 2.032 4.25v.797c0 1.375-.594 2.781-2.032 4.25.188.094.25.14.313.203.047.063.094.125.203.329C2.86.452 3.766-1.204 3.766-2.72zm0 0"/></symbol><symbol overflow="visible" id="e"><path d="M8.266-4.078a1.419 1.419 0 01-.047-.36c0-.109.015-.234.062-.484h-7.5c.063.25.063.375.063.484 0 .125 0 .235-.063.5h7.5zm0 2.625a1.332 1.332 0 01-.047-.36c0-.109.015-.234.062-.484h-7.5c.063.25.063.375.063.485 0 .125 0 .25-.063.5h7.5zm0 0"/></symbol><symbol overflow="visible" id="f"><path d="M5.688-4.5c0-2.625-.907-4-2.547-4C1.297-8.5.203-6.89.203-4c0 1.39.281 2.703.703 3.281.422.594 1.203.953 1.938.953 1.812 0 2.844-1.687 2.844-4.734zm-1.282.594C4.406-1.36 4.094-.437 3-.437c-1.156 0-1.516-1.079-1.516-4 0-2.516.313-3.375 1.438-3.375 1.172 0 1.484 1.03 1.484 3.906zm0 0"/></symbol></defs><use xlink:href="#a" x="-.001" y="9.082"/><use xlink:href="#b" x="8.105" y="9.082"/><use xlink:href="#c" x="13.174" y="9.082"/><use xlink:href="#d" x="17.214" y="9.082"/><use xlink:href="#e" x="25.607" y="9.082"/><g><use xlink:href="#f" x="38.017" y="9.082"/></g></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="44pt" height="13pt" viewBox="0 0 44 13"><defs><symbol overflow="visible" id="a"><path d="M9.281-8.438c0-.03-.219-.25-.328-.25a.701.701 0 00-.328.172l-.672.75c0 .016-.672-.921-2-.921-2.672 0-5.562 2.765-5.562 5.546C.39-1.17 2.016.266 3.844.266c1.031 0 2.078-.516 2.703-1.063C7.657-1.78 7.922-2.969 7.922-3c0-.125-.203-.031-.203-.031l-.125-.219c-.078 0-.344.156-.36.25-.109.344-.328 1.094-1.156 1.797-.812.672-1.422.828-2.047.828-1.078 0-2.156-.484-2.156-2.344 0-.687.188-2.531 1.39-3.922C4-7.5 4.986-8.062 6.048-8.062c1.219 0 1.719.796 1.719 2.187 0 .469-.032.484-.032.61 0 .109.329.25.375.25.157 0 .36-.157.407-.376zm0 0"/></symbol><symbol overflow="visible" id="b"><path d="M4.156 2.719c0-.047-.078-.172-.11-.203-1.234-.922-2-3.22-2-5.141v-1c0-1.906.767-4.203 2-5.14a.457.457 0 00.11-.188c0-.063-.25-.25-.312-.25a1.01 1.01 0 00-.203.062C2.312-8.156 1-5.67 1-3.625v1C1-.578 2.313 1.906 3.64 2.906c.016.016.188.063.204.063.062 0 .312-.203.312-.25zm0 0"/></symbol><symbol overflow="visible" id="c"><path d="M4.14-5.156c0-.125-.312-.266-.53-.266H2.78c.39-1.562.453-1.797.453-1.875 0-.203-.328-.453-.53-.453-.032 0-.579.14-.688.563l-.422 1.765H.64c-.25 0-.563.14-.563.36 0 .156.297.28.531.28h.813C.594-1.515.547-1.311.547-1.093c0 .64.656 1.219 1.312 1.219 1.22 0 2.079-1.875 2.079-1.969 0-.11-.282-.25-.329-.25-.109 0-.328.172-.375.297C2.72-.547 2.281-.39 1.875-.39c-.25 0-.172-.03-.172-.421 0-.282.016-.375.063-.579l.859-3.39h.953c.25 0 .563-.125.563-.375zm0 0"/></symbol><symbol overflow="visible" id="d"><path d="M3.64-2.625v-1c0-2.047-1.328-4.531-2.64-5.516a.774.774 0 00-.203-.062c-.063 0-.313.187-.313.25 0 .031.079.172.094.187 1.25.938 2.016 3.235 2.016 5.141v1c0 1.922-.766 4.219-2.016 5.14-.015.032-.094.157-.094.204 0 .047.25.25.313.25A.774.774 0 001 2.906c1.313-1 2.64-3.484 2.64-5.531zm0 0"/></symbol><symbol overflow="visible" id="e"><path d="M8.828-4.281c0-.125-.312-.375-.437-.375H.906c-.125 0-.437.25-.437.375 0 .14.312.375.437.375h7.485c.125 0 .437-.235.437-.375zm0 2.328c0-.14-.312-.375-.437-.375H.906c-.125 0-.437.234-.437.375 0 .125.312.36.437.36h7.485c.125 0 .437-.235.437-.36zm0 0"/></symbol><symbol overflow="visible" id="f"><path d="M5.688-3.953c0-.953-.063-1.922-.47-2.797-.562-1.156-1.734-1.469-2.234-1.469-.718 0-1.796.438-2.28 1.547-.376.828-.438 1.766-.438 2.719 0 .89.109 2.062.593 2.969.516.968 1.532 1.25 2.11 1.25.656 0 1.75-.391 2.281-1.516.375-.828.438-1.766.438-2.703zm-1.391-.14c0 .89 0 1.702-.125 2.468C4-.485 3.516-.265 2.969-.265 2.516-.266 2-.438 1.78-1.579c-.125-.719-.125-1.813-.125-2.516 0-.765 0-1.562.094-2.203.219-1.422.922-1.406 1.219-1.406.406 0 .984.094 1.219 1.266.109.671.109 1.578.109 2.343zm0 0"/></symbol></defs><use xlink:href="#a" x="-.479" y="9.082"/><use xlink:href="#b" x="8.93" y="9.082"/><use xlink:href="#c" x="13.58" y="9.082"/><use xlink:href="#d" x="17.896" y="9.082"/><g><use xlink:href="#e" x="25.87" y="9.082"/></g><g><use xlink:href="#f" x="38.495" y="9.082"/></g></svg>
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 5.7 KiB |
93
index.html
@@ -2962,8 +2962,8 @@ function drawCurve(points[], t):
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/0ec5cc72a428d75defb480530b50d720.svg"
|
||||
width="411px"
|
||||
height="40px"
|
||||
width="433px"
|
||||
height="37px"
|
||||
/>
|
||||
<p>
|
||||
So, if we can rewrite the Bézier component function as a plain
|
||||
@@ -2983,8 +2983,8 @@ function drawCurve(points[], t):
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/e06ec558d99b53e559d24524f4201951.svg"
|
||||
width="537px"
|
||||
height="36px"
|
||||
width="553px"
|
||||
height="37px"
|
||||
/>
|
||||
<p>
|
||||
And then, using these <em>v</em> values, we can find out what our
|
||||
@@ -2993,8 +2993,8 @@ function drawCurve(points[], t):
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/ddc6f99a543afad25c55cf16b9deeed9.svg"
|
||||
width="315px"
|
||||
height="119px"
|
||||
width="317px"
|
||||
height="112px"
|
||||
/>
|
||||
<p>
|
||||
This gives us three coefficients {a, b, c} that are expressed in
|
||||
@@ -3006,12 +3006,17 @@ function drawCurve(points[], t):
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/d9e66caeb45b6643112ce3d971b17e5b.svg"
|
||||
width="308px"
|
||||
height="63px"
|
||||
height="64px"
|
||||
/>
|
||||
<p>
|
||||
Easy-peasy. We can now almost trivially find the roots by plugging
|
||||
those values into the quadratic formula.
|
||||
</p>
|
||||
<p>
|
||||
And as a cubic curve, there is also a meaningful second derivative,
|
||||
which we can compute by simple taking the derivative of the
|
||||
derivative.
|
||||
</p>
|
||||
<h3>Quartic curves: Cardano's algorithm.</h3>
|
||||
<p>
|
||||
We haven't really looked at them before now, but the next step up
|
||||
@@ -3034,8 +3039,8 @@ function drawCurve(points[], t):
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/997a8cc704c0ab0e364cb8b532df90b0.svg"
|
||||
width="253px"
|
||||
height="44px"
|
||||
width="264px"
|
||||
height="41px"
|
||||
/>
|
||||
<p>
|
||||
We can see that the easier formula only has two constants, rather
|
||||
@@ -3180,6 +3185,12 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
way to find all roots for a cubic function and can just move on with
|
||||
using that to find extremities of our curves.
|
||||
</p>
|
||||
<p>
|
||||
And of course, as a quartic curve also has meaningful second and
|
||||
third derivatives, we can quite easily compute those by using the
|
||||
derivative of the derivative (of the derivative), just as for cubic
|
||||
cuvers.
|
||||
</p>
|
||||
<h3>Quintic and higher order curves: finding numerical solutions</h3>
|
||||
<p>
|
||||
And this is where thing stop, because we <em>cannot</em> find the
|
||||
@@ -3278,7 +3289,8 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<p>
|
||||
So now that we know how to do root finding, we can determine the
|
||||
first and second derivative roots for our Bézier curves, and show
|
||||
those roots overlaid on the previous graphics:
|
||||
those roots overlaid on the previous graphics. For the quadratic
|
||||
curve, that means just the first derivative, in red:
|
||||
</p>
|
||||
<graphics-element
|
||||
title="Quadratic Bézier curve extremities"
|
||||
@@ -3296,6 +3308,11 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
Scripts are disabled. Showing fallback image.
|
||||
</fallback-image></graphics-element
|
||||
>
|
||||
|
||||
<p>
|
||||
And for cubic curves, that means first and second derivatives, in
|
||||
red and purple respectively:
|
||||
</p>
|
||||
<graphics-element
|
||||
title="Cubic Bézier curve extremities"
|
||||
width="825"
|
||||
@@ -3306,7 +3323,7 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<img
|
||||
width="825px"
|
||||
height="275px"
|
||||
src="images\chapters\extremities\68ed7f964bbfad946506cad184feb1b2.png"
|
||||
src="images\chapters\extremities\1440c49b9192919163dc44d6b0cf156b.png"
|
||||
loading="lazy"
|
||||
/>
|
||||
Scripts are disabled. Showing fallback image.
|
||||
@@ -3562,7 +3579,7 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/bafdb6583323bda71d9a15c02d1fdec2.svg"
|
||||
width="59px"
|
||||
height="16px"
|
||||
height="17px"
|
||||
/>
|
||||
<p>
|
||||
What we're saying here is that given the curvature function
|
||||
@@ -3576,8 +3593,8 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/2029bca9f4fa15739553636af99b70a8.svg"
|
||||
width="385px"
|
||||
height="21px"
|
||||
width="399px"
|
||||
height="19px"
|
||||
/>
|
||||
<p>
|
||||
The function <em>C(t)</em> is the cross product between the first
|
||||
@@ -3607,14 +3624,14 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/4d78ebcf8626f777725d67d3672fa480.svg"
|
||||
width="601px"
|
||||
width="613px"
|
||||
height="71px"
|
||||
/>
|
||||
<p>And of course the same functions for <em>y</em>:</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/97b34ad5920612574d1b2a1a9d22d571.svg"
|
||||
width="399px"
|
||||
width="397px"
|
||||
height="69px"
|
||||
/>
|
||||
<p>
|
||||
@@ -3625,8 +3642,8 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/b2433959e1f451fa3bf238fc37e04527.svg"
|
||||
width="552px"
|
||||
height="97px"
|
||||
width="557px"
|
||||
height="96px"
|
||||
/>
|
||||
<p>
|
||||
That is... unwieldy. So, we note that there are a lot of terms
|
||||
@@ -3638,14 +3655,15 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
|
||||
<p>
|
||||
Aligning our curve so that three of the eight coefficients become
|
||||
zero, we end up with the following simple term function for
|
||||
<em>C(t)</em>:
|
||||
zero, and observing that scale does not affect finding
|
||||
<code>t</code> values, we end up with the following simple term
|
||||
function for <em>C(t)</em>:
|
||||
</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/4dbe6398d0075b5b9ef39458ef620616.svg"
|
||||
width="560px"
|
||||
height="21px"
|
||||
src="images/latex/1679090a942a43d27f886f236fc8d62b.svg"
|
||||
width="533px"
|
||||
height="19px"
|
||||
/>
|
||||
<p>
|
||||
That's a lot easier to work with: we see a fair number of terms that
|
||||
@@ -3654,8 +3672,8 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/d7a657089da19f032dd3b3e1d9ed1d89.svg"
|
||||
width="509px"
|
||||
src="images/latex/4b5c7d0bf0fcd769db007dd98d4a024d.svg"
|
||||
width="480px"
|
||||
height="73px"
|
||||
/>
|
||||
<p>
|
||||
@@ -3664,9 +3682,9 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/b94df866222bed63d123df6b839a4d14.svg"
|
||||
width="435px"
|
||||
height="55px"
|
||||
src="images/latex/7c9762c0e04693eb743905cdc0487f8b.svg"
|
||||
width="428px"
|
||||
height="53px"
|
||||
/>
|
||||
<p>
|
||||
We can easily compute this value <em>if</em> the discriminator isn't
|
||||
@@ -3679,11 +3697,22 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<em>t</em> value that isn't in the Bézier interval [0,1], and we now
|
||||
know at which <em>t</em> value(s) our curve will inflect.
|
||||
</p>
|
||||
<Graphic
|
||||
<graphics-element
|
||||
title="Finding cubic Bézier curve inflections"
|
||||
setup="{this.setupCubic}"
|
||||
draw="{this.draw}"
|
||||
/>
|
||||
width="275"
|
||||
height="275"
|
||||
src="./chapters/inflections/inflection.js"
|
||||
>
|
||||
<fallback-image>
|
||||
<img
|
||||
width="275px"
|
||||
height="275px"
|
||||
src="images\chapters\inflections\e81a6573cf3ea31045eb7e8dca3eecb3.png"
|
||||
loading="lazy"
|
||||
/>
|
||||
Scripts are disabled. Showing fallback image.
|
||||
</fallback-image></graphics-element
|
||||
>
|
||||
</section>
|
||||
<section id="canonical">
|
||||
<h1><a href="#canonical">Canonical form (for cubic curves)</a></h1>
|
||||
|
@@ -2634,8 +2634,8 @@ function drawCurve(points[], t):
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/0ec5cc72a428d75defb480530b50d720.svg"
|
||||
width="411px"
|
||||
height="40px"
|
||||
width="433px"
|
||||
height="37px"
|
||||
/>
|
||||
<p>
|
||||
So, if we can rewrite the Bézier component function as a plain
|
||||
@@ -2655,8 +2655,8 @@ function drawCurve(points[], t):
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/e06ec558d99b53e559d24524f4201951.svg"
|
||||
width="537px"
|
||||
height="36px"
|
||||
width="553px"
|
||||
height="37px"
|
||||
/>
|
||||
<p>
|
||||
And then, using these <em>v</em> values, we can find out what our
|
||||
@@ -2665,8 +2665,8 @@ function drawCurve(points[], t):
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/ddc6f99a543afad25c55cf16b9deeed9.svg"
|
||||
width="315px"
|
||||
height="119px"
|
||||
width="317px"
|
||||
height="112px"
|
||||
/>
|
||||
<p>
|
||||
This gives us three coefficients {a, b, c} that are expressed in
|
||||
@@ -2678,12 +2678,17 @@ function drawCurve(points[], t):
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/d9e66caeb45b6643112ce3d971b17e5b.svg"
|
||||
width="308px"
|
||||
height="63px"
|
||||
height="64px"
|
||||
/>
|
||||
<p>
|
||||
Easy-peasy. We can now almost trivially find the roots by plugging
|
||||
those values into the quadratic formula.
|
||||
</p>
|
||||
<p>
|
||||
And as a cubic curve, there is also a meaningful second derivative,
|
||||
which we can compute by simple taking the derivative of the
|
||||
derivative.
|
||||
</p>
|
||||
<h3>Quartic curves: Cardano's algorithm.</h3>
|
||||
<p>
|
||||
We haven't really looked at them before now, but the next step up
|
||||
@@ -2706,8 +2711,8 @@ function drawCurve(points[], t):
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/997a8cc704c0ab0e364cb8b532df90b0.svg"
|
||||
width="253px"
|
||||
height="44px"
|
||||
width="264px"
|
||||
height="41px"
|
||||
/>
|
||||
<p>
|
||||
We can see that the easier formula only has two constants, rather
|
||||
@@ -2852,6 +2857,12 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
way to find all roots for a cubic function and can just move on with
|
||||
using that to find extremities of our curves.
|
||||
</p>
|
||||
<p>
|
||||
And of course, as a quartic curve also has meaningful second and
|
||||
third derivatives, we can quite easily compute those by using the
|
||||
derivative of the derivative (of the derivative), just as for cubic
|
||||
cuvers.
|
||||
</p>
|
||||
<h3>Quintic and higher order curves: finding numerical solutions</h3>
|
||||
<p>
|
||||
And this is where thing stop, because we <em>cannot</em> find the
|
||||
@@ -2950,7 +2961,8 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<p>
|
||||
So now that we know how to do root finding, we can determine the
|
||||
first and second derivative roots for our Bézier curves, and show
|
||||
those roots overlaid on the previous graphics:
|
||||
those roots overlaid on the previous graphics. For the quadratic
|
||||
curve, that means just the first derivative, in red:
|
||||
</p>
|
||||
<graphics-element
|
||||
title="Quadratic Bézier curve extremities"
|
||||
@@ -2968,6 +2980,11 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
Scripts are disabled. Showing fallback image.
|
||||
</fallback-image></graphics-element
|
||||
>
|
||||
|
||||
<p>
|
||||
And for cubic curves, that means first and second derivatives, in
|
||||
red and purple respectively:
|
||||
</p>
|
||||
<graphics-element
|
||||
title="Cubic Bézier curve extremities"
|
||||
width="825"
|
||||
@@ -2978,7 +2995,7 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<img
|
||||
width="825px"
|
||||
height="275px"
|
||||
src="images\chapters\extremities\68ed7f964bbfad946506cad184feb1b2.png"
|
||||
src="images\chapters\extremities\1440c49b9192919163dc44d6b0cf156b.png"
|
||||
loading="lazy"
|
||||
/>
|
||||
Scripts are disabled. Showing fallback image.
|
||||
@@ -3236,7 +3253,7 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/bafdb6583323bda71d9a15c02d1fdec2.svg"
|
||||
width="59px"
|
||||
height="16px"
|
||||
height="17px"
|
||||
/>
|
||||
<p>
|
||||
What we're saying here is that given the curvature function
|
||||
@@ -3250,8 +3267,8 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/2029bca9f4fa15739553636af99b70a8.svg"
|
||||
width="385px"
|
||||
height="21px"
|
||||
width="399px"
|
||||
height="19px"
|
||||
/>
|
||||
<p>
|
||||
The function <em>C(t)</em> is the cross product between the first
|
||||
@@ -3281,14 +3298,14 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/4d78ebcf8626f777725d67d3672fa480.svg"
|
||||
width="601px"
|
||||
width="613px"
|
||||
height="71px"
|
||||
/>
|
||||
<p>And of course the same functions for <em>y</em>:</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/97b34ad5920612574d1b2a1a9d22d571.svg"
|
||||
width="399px"
|
||||
width="397px"
|
||||
height="69px"
|
||||
/>
|
||||
<p>
|
||||
@@ -3299,8 +3316,8 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/b2433959e1f451fa3bf238fc37e04527.svg"
|
||||
width="552px"
|
||||
height="97px"
|
||||
width="557px"
|
||||
height="96px"
|
||||
/>
|
||||
<p>
|
||||
That is... unwieldy. So, we note that there are a lot of terms
|
||||
@@ -3312,14 +3329,15 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
|
||||
<p>
|
||||
Aligning our curve so that three of the eight coefficients become
|
||||
zero, we end up with the following simple term function for
|
||||
<em>C(t)</em>:
|
||||
zero, and observing that scale does not affect finding
|
||||
<code>t</code> values, we end up with the following simple term
|
||||
function for <em>C(t)</em>:
|
||||
</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/4dbe6398d0075b5b9ef39458ef620616.svg"
|
||||
width="560px"
|
||||
height="21px"
|
||||
src="images/latex/1679090a942a43d27f886f236fc8d62b.svg"
|
||||
width="533px"
|
||||
height="19px"
|
||||
/>
|
||||
<p>
|
||||
That's a lot easier to work with: we see a fair number of terms that
|
||||
@@ -3328,8 +3346,8 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/d7a657089da19f032dd3b3e1d9ed1d89.svg"
|
||||
width="509px"
|
||||
src="images/latex/4b5c7d0bf0fcd769db007dd98d4a024d.svg"
|
||||
width="480px"
|
||||
height="73px"
|
||||
/>
|
||||
<p>
|
||||
@@ -3338,9 +3356,9 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/b94df866222bed63d123df6b839a4d14.svg"
|
||||
width="435px"
|
||||
height="55px"
|
||||
src="images/latex/7c9762c0e04693eb743905cdc0487f8b.svg"
|
||||
width="428px"
|
||||
height="53px"
|
||||
/>
|
||||
<p>
|
||||
We can easily compute this value <em>if</em> the discriminator isn't
|
||||
@@ -3353,11 +3371,22 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<em>t</em> value that isn't in the Bézier interval [0,1], and we now
|
||||
know at which <em>t</em> value(s) our curve will inflect.
|
||||
</p>
|
||||
<Graphic
|
||||
<graphics-element
|
||||
title="Finding cubic Bézier curve inflections"
|
||||
setup="{this.setupCubic}"
|
||||
draw="{this.draw}"
|
||||
/>
|
||||
width="275"
|
||||
height="275"
|
||||
src="./chapters/inflections/inflection.js"
|
||||
>
|
||||
<fallback-image>
|
||||
<img
|
||||
width="275px"
|
||||
height="275px"
|
||||
src="images\chapters\inflections\e81a6573cf3ea31045eb7e8dca3eecb3.png"
|
||||
loading="lazy"
|
||||
/>
|
||||
Scripts are disabled. Showing fallback image.
|
||||
</fallback-image></graphics-element
|
||||
>
|
||||
</section>
|
||||
<section id="canonical">
|
||||
<h1>
|
||||
|
@@ -356,6 +356,11 @@ class Bezier {
|
||||
return ret;
|
||||
}
|
||||
|
||||
align() {
|
||||
let p = this.points;
|
||||
return new Bezier(utils.align(p, { p1: p[0], p2: p[p.length - 1] }));
|
||||
}
|
||||
|
||||
curvature(t) {
|
||||
return utils.curvature(t, this.points, this._3d);
|
||||
}
|
||||
|
@@ -643,6 +643,8 @@ const utils = {
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
return [];
|
||||
},
|
||||
|
||||
curvature: function (t, points, _3d, kOnly) {
|
||||
|
@@ -2644,8 +2644,8 @@ function drawCurve(points[], t):
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/0ec5cc72a428d75defb480530b50d720.svg"
|
||||
width="411px"
|
||||
height="40px"
|
||||
width="433px"
|
||||
height="37px"
|
||||
/>
|
||||
<p>
|
||||
So, if we can rewrite the Bézier component function as a plain
|
||||
@@ -2665,8 +2665,8 @@ function drawCurve(points[], t):
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/e06ec558d99b53e559d24524f4201951.svg"
|
||||
width="537px"
|
||||
height="36px"
|
||||
width="553px"
|
||||
height="37px"
|
||||
/>
|
||||
<p>
|
||||
And then, using these <em>v</em> values, we can find out what our
|
||||
@@ -2675,8 +2675,8 @@ function drawCurve(points[], t):
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/ddc6f99a543afad25c55cf16b9deeed9.svg"
|
||||
width="315px"
|
||||
height="119px"
|
||||
width="317px"
|
||||
height="112px"
|
||||
/>
|
||||
<p>
|
||||
This gives us three coefficients {a, b, c} that are expressed in
|
||||
@@ -2688,12 +2688,17 @@ function drawCurve(points[], t):
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/d9e66caeb45b6643112ce3d971b17e5b.svg"
|
||||
width="308px"
|
||||
height="63px"
|
||||
height="64px"
|
||||
/>
|
||||
<p>
|
||||
Easy-peasy. We can now almost trivially find the roots by plugging
|
||||
those values into the quadratic formula.
|
||||
</p>
|
||||
<p>
|
||||
And as a cubic curve, there is also a meaningful second derivative,
|
||||
which we can compute by simple taking the derivative of the
|
||||
derivative.
|
||||
</p>
|
||||
<h3>Quartic curves: Cardano's algorithm.</h3>
|
||||
<p>
|
||||
We haven't really looked at them before now, but the next step up
|
||||
@@ -2716,8 +2721,8 @@ function drawCurve(points[], t):
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/997a8cc704c0ab0e364cb8b532df90b0.svg"
|
||||
width="253px"
|
||||
height="44px"
|
||||
width="264px"
|
||||
height="41px"
|
||||
/>
|
||||
<p>
|
||||
We can see that the easier formula only has two constants, rather
|
||||
@@ -2862,6 +2867,12 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
way to find all roots for a cubic function and can just move on with
|
||||
using that to find extremities of our curves.
|
||||
</p>
|
||||
<p>
|
||||
And of course, as a quartic curve also has meaningful second and
|
||||
third derivatives, we can quite easily compute those by using the
|
||||
derivative of the derivative (of the derivative), just as for cubic
|
||||
cuvers.
|
||||
</p>
|
||||
<h3>Quintic and higher order curves: finding numerical solutions</h3>
|
||||
<p>
|
||||
And this is where thing stop, because we <em>cannot</em> find the
|
||||
@@ -2960,7 +2971,8 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<p>
|
||||
So now that we know how to do root finding, we can determine the
|
||||
first and second derivative roots for our Bézier curves, and show
|
||||
those roots overlaid on the previous graphics:
|
||||
those roots overlaid on the previous graphics. For the quadratic
|
||||
curve, that means just the first derivative, in red:
|
||||
</p>
|
||||
<graphics-element
|
||||
title="Quadratic Bézier curve extremities"
|
||||
@@ -2978,6 +2990,11 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
Scripts are disabled. Showing fallback image.
|
||||
</fallback-image></graphics-element
|
||||
>
|
||||
|
||||
<p>
|
||||
And for cubic curves, that means first and second derivatives, in
|
||||
red and purple respectively:
|
||||
</p>
|
||||
<graphics-element
|
||||
title="Cubic Bézier curve extremities"
|
||||
width="825"
|
||||
@@ -2988,7 +3005,7 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<img
|
||||
width="825px"
|
||||
height="275px"
|
||||
src="images\chapters\extremities\68ed7f964bbfad946506cad184feb1b2.png"
|
||||
src="images\chapters\extremities\1440c49b9192919163dc44d6b0cf156b.png"
|
||||
loading="lazy"
|
||||
/>
|
||||
Scripts are disabled. Showing fallback image.
|
||||
@@ -3246,7 +3263,7 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/bafdb6583323bda71d9a15c02d1fdec2.svg"
|
||||
width="59px"
|
||||
height="16px"
|
||||
height="17px"
|
||||
/>
|
||||
<p>
|
||||
What we're saying here is that given the curvature function
|
||||
@@ -3260,8 +3277,8 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/2029bca9f4fa15739553636af99b70a8.svg"
|
||||
width="385px"
|
||||
height="21px"
|
||||
width="399px"
|
||||
height="19px"
|
||||
/>
|
||||
<p>
|
||||
The function <em>C(t)</em> is the cross product between the first
|
||||
@@ -3291,14 +3308,14 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/4d78ebcf8626f777725d67d3672fa480.svg"
|
||||
width="601px"
|
||||
width="613px"
|
||||
height="71px"
|
||||
/>
|
||||
<p>And of course the same functions for <em>y</em>:</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/97b34ad5920612574d1b2a1a9d22d571.svg"
|
||||
width="399px"
|
||||
width="397px"
|
||||
height="69px"
|
||||
/>
|
||||
<p>
|
||||
@@ -3309,8 +3326,8 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/b2433959e1f451fa3bf238fc37e04527.svg"
|
||||
width="552px"
|
||||
height="97px"
|
||||
width="557px"
|
||||
height="96px"
|
||||
/>
|
||||
<p>
|
||||
That is... unwieldy. So, we note that there are a lot of terms
|
||||
@@ -3322,14 +3339,15 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
|
||||
<p>
|
||||
Aligning our curve so that three of the eight coefficients become
|
||||
zero, we end up with the following simple term function for
|
||||
<em>C(t)</em>:
|
||||
zero, and observing that scale does not affect finding
|
||||
<code>t</code> values, we end up with the following simple term
|
||||
function for <em>C(t)</em>:
|
||||
</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/4dbe6398d0075b5b9ef39458ef620616.svg"
|
||||
width="560px"
|
||||
height="21px"
|
||||
src="images/latex/1679090a942a43d27f886f236fc8d62b.svg"
|
||||
width="533px"
|
||||
height="19px"
|
||||
/>
|
||||
<p>
|
||||
That's a lot easier to work with: we see a fair number of terms that
|
||||
@@ -3338,8 +3356,8 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/d7a657089da19f032dd3b3e1d9ed1d89.svg"
|
||||
width="509px"
|
||||
src="images/latex/4b5c7d0bf0fcd769db007dd98d4a024d.svg"
|
||||
width="480px"
|
||||
height="73px"
|
||||
/>
|
||||
<p>
|
||||
@@ -3348,9 +3366,9 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
</p>
|
||||
<img
|
||||
class="LaTeX SVG"
|
||||
src="images/latex/b94df866222bed63d123df6b839a4d14.svg"
|
||||
width="435px"
|
||||
height="55px"
|
||||
src="images/latex/7c9762c0e04693eb743905cdc0487f8b.svg"
|
||||
width="428px"
|
||||
height="53px"
|
||||
/>
|
||||
<p>
|
||||
We can easily compute this value <em>if</em> the discriminator isn't
|
||||
@@ -3363,11 +3381,22 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
<em>t</em> value that isn't in the Bézier interval [0,1], and we now
|
||||
know at which <em>t</em> value(s) our curve will inflect.
|
||||
</p>
|
||||
<Graphic
|
||||
<graphics-element
|
||||
title="Finding cubic Bézier curve inflections"
|
||||
setup="{this.setupCubic}"
|
||||
draw="{this.draw}"
|
||||
/>
|
||||
width="275"
|
||||
height="275"
|
||||
src="./chapters/inflections/inflection.js"
|
||||
>
|
||||
<fallback-image>
|
||||
<img
|
||||
width="275px"
|
||||
height="275px"
|
||||
src="images\chapters\inflections\e81a6573cf3ea31045eb7e8dca3eecb3.png"
|
||||
loading="lazy"
|
||||
/>
|
||||
Scripts are disabled. Showing fallback image.
|
||||
</fallback-image></graphics-element
|
||||
>
|
||||
</section>
|
||||
<section id="canonical">
|
||||
<h1>
|
||||
|