mirror of
https://github.com/Pomax/BezierInfo-2.git
synced 2025-09-25 07:41:30 +02:00
extremeties
This commit is contained in:
107
chapters/extremities/cubic.js
Normal file
107
chapters/extremities/cubic.js
Normal file
@@ -0,0 +1,107 @@
|
||||
setup() {
|
||||
const curve = this.curve = Bezier.defaultCubic(this);
|
||||
curve.points[2].x = 210;
|
||||
curve.update();
|
||||
setMovable(curve.points);
|
||||
}
|
||||
|
||||
draw() {
|
||||
resetTransform();
|
||||
clear();
|
||||
const dim = this.height;
|
||||
const curve = this.curve;
|
||||
curve.drawSkeleton();
|
||||
curve.drawCurve();
|
||||
curve.drawPoints();
|
||||
|
||||
translate(dim, 0);
|
||||
setStroke(`black`);
|
||||
line(0,0,0,dim);
|
||||
|
||||
scale(0.8, 0.9);
|
||||
translate(40,20);
|
||||
drawAxes(`t`, 0, 1, `X`, 0, dim, dim, dim);
|
||||
|
||||
this.plotDimension(dim, new Bezier(this, curve.points.map((p,i) => ({
|
||||
x: (i/3) * dim,
|
||||
y: p.x
|
||||
}))));
|
||||
|
||||
resetTransform();
|
||||
translate(2*dim, 0);
|
||||
setStroke(`black`);
|
||||
line(0,0,0,dim);
|
||||
|
||||
scale(0.8, 0.9);
|
||||
translate(40,20);
|
||||
drawAxes(`t`, 0,1, `Y`, 0, dim, dim, dim);
|
||||
|
||||
this.plotDimension(dim, new Bezier(this, curve.points.map((p,i) => ({
|
||||
x: (i/3) * dim,
|
||||
y: p.y
|
||||
}))));
|
||||
}
|
||||
|
||||
plotDimension(dim, dimension) {
|
||||
cacheStyle();
|
||||
dimension.drawCurve();
|
||||
|
||||
setFill(`red`);
|
||||
setStroke(`red)`);
|
||||
|
||||
// There are four possible extrema: t=0, t=1, and
|
||||
// up to two t values that solves B'(t)=0, provided
|
||||
// that they lie between 0 and 1. But of those four,
|
||||
// only two will be real extrema (one minimum value,
|
||||
// and one maximum value)
|
||||
|
||||
// First we compute the "simple" cases:
|
||||
let t1 = 0; let y1 = dimension.get(t1).y;
|
||||
let t2 = 1; let y2 = dimension.get(t2).y;
|
||||
|
||||
// We assume y1 < y2, but is that actually true?
|
||||
let reverse = (y2 < y1);
|
||||
|
||||
// Are there a solution for B'(t) = 0?
|
||||
let roots = this.getRoots(...dimension.dpoints[0].map(p => p.y));
|
||||
|
||||
roots.forEach(t =>{
|
||||
// Is that solution a value in [0,1]?
|
||||
if (t > 0 && t < 1) {
|
||||
// It is, so we have either a new minimum value
|
||||
// or new maximum value:
|
||||
let dp = dimension.get(t);
|
||||
if (reverse) {
|
||||
if (dp.y < y2) { t2 = t; y2 = dp.y; }
|
||||
if (dp.y > y1) { t1 = t; y1 = dp.y; }
|
||||
} else {
|
||||
if (dp.y < y1) { t1 = t; y1 = dp.y; }
|
||||
if (dp.y > y2) { t2 = t; y2 = dp.y; }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Done, show our 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);
|
||||
restoreStyle();
|
||||
}
|
||||
|
||||
getRoots(v1, v2, v3) {
|
||||
const a = v1 - 2*v2 + v3,
|
||||
b = 2 * (v2 - v1),
|
||||
c = v1,
|
||||
d = b*b - 4*a*c;
|
||||
if (a === 0) return [];
|
||||
if (d < 0) return [];
|
||||
const f = -b / (2*a);
|
||||
if (d === 0) return [f]
|
||||
const l = sqrt(d) / (2*a);
|
||||
return [f-l, f+l];
|
||||
}
|
||||
|
||||
onMouseMove() {
|
||||
redraw();
|
||||
}
|
@@ -1,53 +0,0 @@
|
||||
module.exports = {
|
||||
setupQuadratic: function(api) {
|
||||
var curve = api.getDefaultQuadratic();
|
||||
curve.points[2].x = 210;
|
||||
api.setCurve(curve);
|
||||
},
|
||||
|
||||
setupCubic: function(api) {
|
||||
var curve = api.getDefaultCubic();
|
||||
api.setCurve(curve);
|
||||
},
|
||||
|
||||
draw: function(api, curve) {
|
||||
api.setPanelCount(3);
|
||||
api.reset();
|
||||
api.drawSkeleton(curve);
|
||||
api.drawCurve(curve);
|
||||
|
||||
var tf = curve.order + 1,
|
||||
pad = 20,
|
||||
pts = curve.points,
|
||||
w = api.getPanelWidth(),
|
||||
h = api.getPanelHeight(),
|
||||
offset = { x: w, y: 0 };
|
||||
|
||||
var x_pts = JSON.parse(JSON.stringify(pts)).map((p,t) => { return {x:w*t/tf, y:p.x}; });
|
||||
api.setColor("black");
|
||||
api.drawLine({x:0,y:0}, {x:0,y:h}, offset);
|
||||
api.drawAxes(pad, "t",0,1, "x",0,w, offset);
|
||||
offset.x += pad;
|
||||
var xcurve = new api.Bezier(x_pts);
|
||||
api.drawCurve(xcurve, offset);
|
||||
api.setColor("red");
|
||||
xcurve.extrema().y.forEach(t => {
|
||||
var p = xcurve.get(t);
|
||||
api.drawCircle(p, 3, offset);
|
||||
});
|
||||
|
||||
offset.x += w-pad;
|
||||
var y_pts = JSON.parse(JSON.stringify(pts)).map((p,t) => { return {x:w*t/tf, y:p.y}; });
|
||||
api.setColor("black");
|
||||
api.drawLine({x:0,y:0}, {x:0,y:h}, offset);
|
||||
api.drawAxes(pad, "t",0,1, "y",0,w, offset);
|
||||
offset.x += pad;
|
||||
var ycurve = new api.Bezier(y_pts);
|
||||
api.drawCurve(ycurve, offset);
|
||||
api.setColor("red");
|
||||
ycurve.extrema().y.forEach(t => {
|
||||
var p = ycurve.get(t);
|
||||
api.drawCircle(p, 3, offset);
|
||||
});
|
||||
}
|
||||
};
|
@@ -20,7 +20,7 @@ draw() {
|
||||
translate(40,20);
|
||||
drawAxes(`t`, 0, 1, `X`, 0, dim, dim, dim);
|
||||
|
||||
plot(new Bezier(this, curve.points.map((p,i) => ({
|
||||
this.plotDimension(dim, new Bezier(this, curve.points.map((p,i) => ({
|
||||
x: (i/2) * dim,
|
||||
y: p.x
|
||||
}))));
|
||||
@@ -34,17 +34,59 @@ draw() {
|
||||
translate(40,20);
|
||||
drawAxes(`t`, 0,1, `Y`, 0, dim, dim, dim);
|
||||
|
||||
plot(new Bezier(this, curve.points.map((p,i) => ({
|
||||
this.plotDimension(dim, new Bezier(this, curve.points.map((p,i) => ({
|
||||
x: (i/2) * dim,
|
||||
y: p.y
|
||||
}))))
|
||||
}
|
||||
|
||||
plot(dimension) {
|
||||
plotDimension(dim, dimension) {
|
||||
cacheStyle();
|
||||
dimension.drawCurve();
|
||||
|
||||
}
|
||||
setFill(`red`);
|
||||
setStroke(`red)`);
|
||||
|
||||
// There are three possible extrema: t=0, t=1, and
|
||||
// the t value that solves B'(t)=0, provided that
|
||||
// value is between 0 and 1. But of those three,
|
||||
// only two will be real extrema (one minimum value,
|
||||
// and one maximum value)
|
||||
|
||||
// First we compute the "simple" cases:
|
||||
let t1 = 0; let y1 = dimension.get(t1).y;
|
||||
let t2 = 1; let y2 = dimension.get(t2).y;
|
||||
|
||||
// We assume y1 < y2, but is that actually true?
|
||||
let reverse = (y2 < y1);
|
||||
|
||||
// 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;
|
||||
|
||||
// Is that solution a value in [0,1]?
|
||||
if (t3 > 0 && t3 < 1) {
|
||||
// It is, so we have either a new minimum value
|
||||
// or new maximum value:
|
||||
let dp = dimension.get(t3);
|
||||
if (reverse) {
|
||||
if (dp.y < y2) { t2 = t3; y2 = dp.y; }
|
||||
if (dp.y > y1) { t1 = t3; y1 = dp.y; }
|
||||
} else {
|
||||
if (dp.y < y1) { t1 = t3; y1 = dp.y; }
|
||||
if (dp.y > y2) { t2 = t3; y2 = dp.y; }
|
||||
}
|
||||
}
|
||||
|
||||
// Done, show our 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);
|
||||
restoreStyle();
|
||||
}
|
||||
|
||||
onMouseMove() {
|
||||
redraw();
|
||||
|
BIN
images/chapters/extremities/48ae22b5da60547a71de1d4036f86cfc.png
Normal file
BIN
images/chapters/extremities/48ae22b5da60547a71de1d4036f86cfc.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
BIN
images/chapters/extremities/d92d9d414c71c1917da540840c104170.png
Normal file
BIN
images/chapters/extremities/d92d9d414c71c1917da540840c104170.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
38
index.html
38
index.html
@@ -3218,16 +3218,38 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
first and second derivative roots for our Bézier curves, and show
|
||||
those roots overlaid on the previous graphics:
|
||||
</p>
|
||||
<Graphic
|
||||
<graphics-element
|
||||
title="Quadratic Bézier curve extremities"
|
||||
setup="{this.setupQuadratic}"
|
||||
draw="{this.draw}"
|
||||
/>
|
||||
<Graphic
|
||||
width="825"
|
||||
height="275"
|
||||
src="./chapters/extremities/quadratic.js"
|
||||
>
|
||||
<fallback-image>
|
||||
<img
|
||||
width="825px"
|
||||
height="275px"
|
||||
src="images\chapters\extremities\d92d9d414c71c1917da540840c104170.png"
|
||||
loading="lazy"
|
||||
/>
|
||||
Scripts are disabled. Showing fallback image.
|
||||
</fallback-image></graphics-element
|
||||
>
|
||||
<graphics-element
|
||||
title="Cubic Bézier curve extremities"
|
||||
setup="{this.setupCubic}"
|
||||
draw="{this.draw}"
|
||||
/>
|
||||
width="825"
|
||||
height="275"
|
||||
src="./chapters/extremities/cubic.js"
|
||||
>
|
||||
<fallback-image>
|
||||
<img
|
||||
width="825px"
|
||||
height="275px"
|
||||
src="images\chapters\extremities\48ae22b5da60547a71de1d4036f86cfc.png"
|
||||
loading="lazy"
|
||||
/>
|
||||
Scripts are disabled. Showing fallback image.
|
||||
</fallback-image></graphics-element
|
||||
>
|
||||
</section>
|
||||
<section id="boundingbox">
|
||||
<h1><a href="#boundingbox">Bounding boxes</a></h1>
|
||||
|
@@ -2888,16 +2888,38 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
first and second derivative roots for our Bézier curves, and show
|
||||
those roots overlaid on the previous graphics:
|
||||
</p>
|
||||
<Graphic
|
||||
<graphics-element
|
||||
title="Quadratic Bézier curve extremities"
|
||||
setup="{this.setupQuadratic}"
|
||||
draw="{this.draw}"
|
||||
/>
|
||||
<Graphic
|
||||
width="825"
|
||||
height="275"
|
||||
src="./chapters/extremities/quadratic.js"
|
||||
>
|
||||
<fallback-image>
|
||||
<img
|
||||
width="825px"
|
||||
height="275px"
|
||||
src="images\chapters\extremities\d92d9d414c71c1917da540840c104170.png"
|
||||
loading="lazy"
|
||||
/>
|
||||
Scripts are disabled. Showing fallback image.
|
||||
</fallback-image></graphics-element
|
||||
>
|
||||
<graphics-element
|
||||
title="Cubic Bézier curve extremities"
|
||||
setup="{this.setupCubic}"
|
||||
draw="{this.draw}"
|
||||
/>
|
||||
width="825"
|
||||
height="275"
|
||||
src="./chapters/extremities/cubic.js"
|
||||
>
|
||||
<fallback-image>
|
||||
<img
|
||||
width="825px"
|
||||
height="275px"
|
||||
src="images\chapters\extremities\48ae22b5da60547a71de1d4036f86cfc.png"
|
||||
loading="lazy"
|
||||
/>
|
||||
Scripts are disabled. Showing fallback image.
|
||||
</fallback-image></graphics-element
|
||||
>
|
||||
</section>
|
||||
<section id="boundingbox">
|
||||
<h1><a href="ja-JP/index.html#boundingbox">Bounding boxes</a></h1>
|
||||
|
@@ -258,6 +258,20 @@ class GraphicsAPI extends BaseAPI {
|
||||
this.ctx.lineWidth = `${width}px`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache all styling values
|
||||
*/
|
||||
cacheStyle() {
|
||||
this.ctx.cacheStyle();
|
||||
}
|
||||
|
||||
/**
|
||||
* restore all previous styling values
|
||||
*/
|
||||
restoreStyle() {
|
||||
this.ctx.restoreStyle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the canvas bitmap to a uniform color.
|
||||
*/
|
||||
@@ -493,6 +507,14 @@ class GraphicsAPI extends BaseAPI {
|
||||
return Math.abs(v);
|
||||
}
|
||||
|
||||
min(...v) {
|
||||
return Math.min(...v);
|
||||
}
|
||||
|
||||
max(...v) {
|
||||
return Math.max(...v);
|
||||
}
|
||||
|
||||
sin(v) {
|
||||
return Math.sin(v);
|
||||
}
|
||||
|
@@ -22,7 +22,9 @@
|
||||
"lint:tools": "prettier ./tools --write",
|
||||
"lint:lib": "prettier ./lib --write",
|
||||
"server": "http-server -p 8000 --cors",
|
||||
"watch": "chokidar \"**/*.md\" -c \"npm start\"",
|
||||
"watch": "run-p watch:*",
|
||||
"watch:markdown": "chokidar \"./chapters/**/*.md\" -c \"npm start\"",
|
||||
"watch:sketches": "chokidar \"./chapters/**/*.js\" -c \"npm start\"",
|
||||
"time": "node ./mark.js"
|
||||
},
|
||||
"keywords": [
|
||||
|
@@ -2898,16 +2898,38 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
first and second derivative roots for our Bézier curves, and show
|
||||
those roots overlaid on the previous graphics:
|
||||
</p>
|
||||
<Graphic
|
||||
<graphics-element
|
||||
title="Quadratic Bézier curve extremities"
|
||||
setup="{this.setupQuadratic}"
|
||||
draw="{this.draw}"
|
||||
/>
|
||||
<Graphic
|
||||
width="825"
|
||||
height="275"
|
||||
src="./chapters/extremities/quadratic.js"
|
||||
>
|
||||
<fallback-image>
|
||||
<img
|
||||
width="825px"
|
||||
height="275px"
|
||||
src="images\chapters\extremities\d92d9d414c71c1917da540840c104170.png"
|
||||
loading="lazy"
|
||||
/>
|
||||
Scripts are disabled. Showing fallback image.
|
||||
</fallback-image></graphics-element
|
||||
>
|
||||
<graphics-element
|
||||
title="Cubic Bézier curve extremities"
|
||||
setup="{this.setupCubic}"
|
||||
draw="{this.draw}"
|
||||
/>
|
||||
width="825"
|
||||
height="275"
|
||||
src="./chapters/extremities/cubic.js"
|
||||
>
|
||||
<fallback-image>
|
||||
<img
|
||||
width="825px"
|
||||
height="275px"
|
||||
src="images\chapters\extremities\48ae22b5da60547a71de1d4036f86cfc.png"
|
||||
loading="lazy"
|
||||
/>
|
||||
Scripts are disabled. Showing fallback image.
|
||||
</fallback-image></graphics-element
|
||||
>
|
||||
</section>
|
||||
<section id="boundingbox">
|
||||
<h1><a href="zh-CN/index.html#boundingbox">Bounding boxes</a></h1>
|
||||
|
Reference in New Issue
Block a user