arc length
@@ -57,7 +57,3 @@ drawRTCurve(points) {
|
|||||||
text(`(0,0)`, 5,15);
|
text(`(0,0)`, 5,15);
|
||||||
text(`(${points[3].x|0},0)`, points[3].x, -5, CENTER);
|
text(`(${points[3].x|0},0)`, points[3].x, -5, CENTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseMove() {
|
|
||||||
redraw();
|
|
||||||
}
|
|
||||||
|
@@ -57,7 +57,3 @@ drawRTCurve(points) {
|
|||||||
text(`(0,0)`, 5,15);
|
text(`(0,0)`, 5,15);
|
||||||
text(`(${points[2].x|0},0)`, points[2].x, 15, CENTER);
|
text(`(${points[2].x|0},0)`, points[2].x, 15, CENTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseMove() {
|
|
||||||
redraw();
|
|
||||||
}
|
|
||||||
|
@@ -1,6 +1,88 @@
|
|||||||
|
const Tvalues24 = [
|
||||||
|
-0.0640568928626056260850430826247450385909,
|
||||||
|
0.0640568928626056260850430826247450385909,
|
||||||
|
-0.1911188674736163091586398207570696318404,
|
||||||
|
0.1911188674736163091586398207570696318404,
|
||||||
|
-0.3150426796961633743867932913198102407864,
|
||||||
|
0.3150426796961633743867932913198102407864,
|
||||||
|
-0.4337935076260451384870842319133497124524,
|
||||||
|
0.4337935076260451384870842319133497124524,
|
||||||
|
-0.5454214713888395356583756172183723700107,
|
||||||
|
0.5454214713888395356583756172183723700107,
|
||||||
|
-0.6480936519369755692524957869107476266696,
|
||||||
|
0.6480936519369755692524957869107476266696,
|
||||||
|
-0.7401241915785543642438281030999784255232,
|
||||||
|
0.7401241915785543642438281030999784255232,
|
||||||
|
-0.8200019859739029219539498726697452080761,
|
||||||
|
0.8200019859739029219539498726697452080761,
|
||||||
|
-0.8864155270044010342131543419821967550873,
|
||||||
|
0.8864155270044010342131543419821967550873,
|
||||||
|
-0.9382745520027327585236490017087214496548,
|
||||||
|
0.9382745520027327585236490017087214496548,
|
||||||
|
-0.9747285559713094981983919930081690617411,
|
||||||
|
0.9747285559713094981983919930081690617411,
|
||||||
|
-0.9951872199970213601799974097007368118745,
|
||||||
|
0.9951872199970213601799974097007368118745,
|
||||||
|
];
|
||||||
|
|
||||||
|
const Cvalues24 = [
|
||||||
|
0.1279381953467521569740561652246953718517,
|
||||||
|
0.1279381953467521569740561652246953718517,
|
||||||
|
0.1258374563468282961213753825111836887264,
|
||||||
|
0.1258374563468282961213753825111836887264,
|
||||||
|
0.121670472927803391204463153476262425607,
|
||||||
|
0.121670472927803391204463153476262425607,
|
||||||
|
0.1155056680537256013533444839067835598622,
|
||||||
|
0.1155056680537256013533444839067835598622,
|
||||||
|
0.1074442701159656347825773424466062227946,
|
||||||
|
0.1074442701159656347825773424466062227946,
|
||||||
|
0.0976186521041138882698806644642471544279,
|
||||||
|
0.0976186521041138882698806644642471544279,
|
||||||
|
0.086190161531953275917185202983742667185,
|
||||||
|
0.086190161531953275917185202983742667185,
|
||||||
|
0.0733464814110803057340336152531165181193,
|
||||||
|
0.0733464814110803057340336152531165181193,
|
||||||
|
0.0592985849154367807463677585001085845412,
|
||||||
|
0.0592985849154367807463677585001085845412,
|
||||||
|
0.0442774388174198061686027482113382288593,
|
||||||
|
0.0442774388174198061686027482113382288593,
|
||||||
|
0.0285313886289336631813078159518782864491,
|
||||||
|
0.0285313886289336631813078159518782864491,
|
||||||
|
0.0123412297999871995468056670700372915759,
|
||||||
|
0.0123412297999871995468056670700372915759,
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
|
this.curve = Bezier.defaultCubic(this);
|
||||||
|
setMovable(this.curve.points);
|
||||||
}
|
}
|
||||||
|
|
||||||
draw() {
|
draw() {
|
||||||
clear();
|
clear();
|
||||||
|
const curve = this.curve;
|
||||||
|
curve.drawSkeleton();
|
||||||
|
curve.drawCurve();
|
||||||
|
curve.drawPoints();
|
||||||
|
|
||||||
|
const len = this.computeLength(curve);
|
||||||
|
setFill("black");
|
||||||
|
text(`Curve length: ${len.toFixed(2)} pixels`, 10, 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
computeLength(curve) {
|
||||||
|
const z = 0.5,
|
||||||
|
len = Tvalues24.length;
|
||||||
|
|
||||||
|
let sum = 0;
|
||||||
|
|
||||||
|
for (let i = 0, t; i < len; i++) {
|
||||||
|
t = z * Tvalues24[i] + z;
|
||||||
|
sum += Cvalues24[i] * this.arcfn(t, curve.derivative(t));
|
||||||
|
}
|
||||||
|
return z * sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
arcfn(t, d) {
|
||||||
|
return sqrt(d.x * d.x + d.y * d.y);
|
||||||
}
|
}
|
||||||
|
@@ -1,125 +0,0 @@
|
|||||||
var sin = Math.sin;
|
|
||||||
var tau = Math.PI*2;
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
/**
|
|
||||||
* Set up a sinusoid generating function,
|
|
||||||
* which we'll use to draw the "progressively
|
|
||||||
* better looking" integral approximations.
|
|
||||||
*/
|
|
||||||
setup: function(api) {
|
|
||||||
var w = api.getPanelWidth();
|
|
||||||
var h = api.getPanelHeight();
|
|
||||||
var generator;
|
|
||||||
if (!this.generator) {
|
|
||||||
generator = ((v,scale) => {
|
|
||||||
scale = scale || 1;
|
|
||||||
return {
|
|
||||||
x: v*w/tau,
|
|
||||||
y: scale * sin(v)
|
|
||||||
};
|
|
||||||
});
|
|
||||||
generator.start = 0;
|
|
||||||
generator.end = tau;
|
|
||||||
generator.step = 0.1;
|
|
||||||
generator.scale = h/3;
|
|
||||||
this.generator = generator;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draw the generator's sine function:
|
|
||||||
*/
|
|
||||||
drawSine: function(api, dheight) {
|
|
||||||
var w = api.getPanelWidth();
|
|
||||||
var h = api.getPanelHeight();
|
|
||||||
var generator = this.generator;
|
|
||||||
generator.dheight = dheight;
|
|
||||||
|
|
||||||
api.setColor("black");
|
|
||||||
api.drawLine({x:0,y:h/2}, {x:w,y:h/2});
|
|
||||||
api.drawFunction(generator, {x:0, y:h/2});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draw the sliced between the sine curve and
|
|
||||||
* the x-axis, with a variable number of steps so
|
|
||||||
* we can show the approximation becoming better
|
|
||||||
* and better as we increase the step count.
|
|
||||||
*/
|
|
||||||
drawSlices: function(api, steps) {
|
|
||||||
var w = api.getPanelWidth();
|
|
||||||
var h = api.getPanelHeight();
|
|
||||||
var f = w/tau;
|
|
||||||
var area = 0;
|
|
||||||
var c = steps <= 25 ? 1 : 0;
|
|
||||||
api.reset();
|
|
||||||
api.setColor("transparent");
|
|
||||||
api.setFill("rgba(150,150,255, 0.4)");
|
|
||||||
for (var step=tau/steps, i=step/2, v, p1, p2; i<tau+step/2; i+=step) {
|
|
||||||
v = this.generator(i);
|
|
||||||
|
|
||||||
// draw a rectangular strip between the curve and the x-axis:
|
|
||||||
p1 = {x:v.x - f*step/2 + c, y: 0};
|
|
||||||
p2 = {x:v.x + f*step/2 - c, y: v.y * this.generator.scale};
|
|
||||||
|
|
||||||
if (!c) { api.setFill("rgba(150,150,255,"+(0.4 + 0.3*Math.random())+")"); }
|
|
||||||
api.drawRect(p1, p2, {x:0, y:h/2});
|
|
||||||
|
|
||||||
// and keep track of the (much simpler to compute) approximated area under the curve so far:
|
|
||||||
area += step * Math.abs(v.y * this.generator.scale);
|
|
||||||
}
|
|
||||||
api.setFill("black");
|
|
||||||
var trueArea = ((100 * 4 * h/3)|0)/100;
|
|
||||||
var currArea = ((100 * area)|0)/100;
|
|
||||||
api.text("Approximating with "+steps+" strips (true area: "+trueArea+"): " + currArea, {x: 10, y: h-15});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draw the sine curve, with a 10 slice approximation:
|
|
||||||
*/
|
|
||||||
drawCoarseIntegral: function(api) {
|
|
||||||
api.reset();
|
|
||||||
this.drawSlices(api, 10);
|
|
||||||
this.drawSine(api);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draw the sine curve, with a 24 slice approximation:
|
|
||||||
*/
|
|
||||||
drawFineIntegral: function(api) {
|
|
||||||
api.reset();
|
|
||||||
this.drawSlices(api, 24);
|
|
||||||
this.drawSine(api);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draw the sine curve, with a 99 slice approximation:
|
|
||||||
*/
|
|
||||||
drawSuperFineIntegral: function(api) {
|
|
||||||
api.reset();
|
|
||||||
this.drawSlices(api, 99);
|
|
||||||
this.drawSine(api);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set up a default cubic curve for which we'll be determining
|
|
||||||
* its length, using the iterative integral approach:
|
|
||||||
*/
|
|
||||||
setupCurve: function(api) {
|
|
||||||
var curve = api.getDefaultCubic();
|
|
||||||
api.setCurve(curve);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draw our curve, and show its computed length:
|
|
||||||
*/
|
|
||||||
drawCurve: function(api, curve) {
|
|
||||||
api.reset();
|
|
||||||
api.drawSkeleton(curve);
|
|
||||||
api.drawCurve(curve);
|
|
||||||
var len = curve.length();
|
|
||||||
api.setFill("black");
|
|
||||||
api.text("Curve length: "+len+" pixels", {x:10, y:15});
|
|
||||||
}
|
|
||||||
};
|
|
@@ -33,7 +33,3 @@ draw() {
|
|||||||
setStroke(`#0F0`);
|
setStroke(`#0F0`);
|
||||||
rect(minx, miny, maxx - minx, maxy - miny);
|
rect(minx, miny, maxx - minx, maxy - miny);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseMove() {
|
|
||||||
redraw();
|
|
||||||
}
|
|
||||||
|
@@ -224,7 +224,3 @@ forwardTransform(points, s=1) {
|
|||||||
|
|
||||||
return {x:np4x, y:np4y};
|
return {x:np4x, y:np4y};
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseMove() {
|
|
||||||
redraw();
|
|
||||||
}
|
|
||||||
|
@@ -30,7 +30,3 @@ draw() {
|
|||||||
|
|
||||||
curve.drawPoints();
|
curve.drawPoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseMove() {
|
|
||||||
redraw();
|
|
||||||
}
|
|
||||||
|
@@ -30,7 +30,3 @@ draw() {
|
|||||||
|
|
||||||
curve.drawPoints();
|
curve.drawPoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseMove() {
|
|
||||||
redraw();
|
|
||||||
}
|
|
||||||
|
@@ -85,7 +85,3 @@ plotDimension(dim, dimension) {
|
|||||||
text(`t = ${t2.toFixed(2)}`, map(t2, 0,1, 15,dim-15), y2 + 25);
|
text(`t = ${t2.toFixed(2)}`, map(t2, 0,1, 15,dim-15), y2 + 25);
|
||||||
restoreStyle();
|
restoreStyle();
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseMove() {
|
|
||||||
redraw();
|
|
||||||
}
|
|
||||||
|
@@ -56,7 +56,3 @@ draw() {
|
|||||||
almost(v1, v2, epsilon=0.00001) {
|
almost(v1, v2, epsilon=0.00001) {
|
||||||
return abs(v1 - v2) < epsilon;
|
return abs(v1 - v2) < epsilon;
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseMove() {
|
|
||||||
redraw();
|
|
||||||
}
|
|
||||||
|
@@ -61,7 +61,3 @@ getNormal(t, d) {
|
|||||||
const q = sqrt(d.x * d.x + d.y * d.y);
|
const q = sqrt(d.x * d.x + d.y * d.y);
|
||||||
return { x: -d.y / q, y: d.x / q };
|
return { x: -d.y / q, y: d.x / q };
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseMove() {
|
|
||||||
redraw();
|
|
||||||
}
|
|
||||||
|
@@ -57,7 +57,3 @@ getNormal(t, d) {
|
|||||||
const q = sqrt(d.x * d.x + d.y * d.y);
|
const q = sqrt(d.x * d.x + d.y * d.y);
|
||||||
return { x: -d.y / q, y: d.x / q };
|
return { x: -d.y / q, y: d.x / q };
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseMove() {
|
|
||||||
redraw();
|
|
||||||
}
|
|
||||||
|
@@ -55,7 +55,3 @@ drawSegment(c, p, halfLabel) {
|
|||||||
setFill(`black`)
|
setFill(`black`)
|
||||||
text(`The ${halfLabel} half`, 10, 15);
|
text(`The ${halfLabel} half`, 10, 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseMove() {
|
|
||||||
redraw();
|
|
||||||
}
|
|
||||||
|
@@ -73,7 +73,3 @@ rotatePoints(points) {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseMove() {
|
|
||||||
redraw();
|
|
||||||
}
|
|
||||||
|
@@ -72,7 +72,3 @@ rotatePoints(points) {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseMove() {
|
|
||||||
redraw();
|
|
||||||
}
|
|
||||||
|
@@ -100,7 +100,3 @@ drawCurveCoordinates() {
|
|||||||
translate(this.height, 0);
|
translate(this.height, 0);
|
||||||
this.curve.drawPoints();
|
this.curve.drawPoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseMove() {
|
|
||||||
redraw();
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 9.6 KiB |
After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 967 B |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 9.8 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
9392
docs/index.html
@@ -68,6 +68,7 @@ class BaseAPI {
|
|||||||
this.HATCHING = hatch(canvasBuildFunction);
|
this.HATCHING = hatch(canvasBuildFunction);
|
||||||
this.addListeners();
|
this.addListeners();
|
||||||
this.setSize(width, height);
|
this.setSize(width, height);
|
||||||
|
this.currentPoint = false;
|
||||||
this.setup();
|
this.setup();
|
||||||
this.draw();
|
this.draw();
|
||||||
}
|
}
|
||||||
@@ -91,7 +92,17 @@ class BaseAPI {
|
|||||||
);
|
);
|
||||||
|
|
||||||
[`touchmove`, `mousemove`].forEach((evtName) =>
|
[`touchmove`, `mousemove`].forEach((evtName) =>
|
||||||
canvas.addEventListener(evtName, (evt) => this.onMouseMove(evt))
|
canvas.addEventListener(evtName, (evt) => {
|
||||||
|
this.onMouseMove(evt);
|
||||||
|
// Force a redraw only if there are movable points,
|
||||||
|
// and there is a current point bound, but only if
|
||||||
|
// the subclass didn't already call redraw() as part
|
||||||
|
// of its own mouseMove handling.
|
||||||
|
if (this.movable.length && this.currentPoint && !this.redrawing) {
|
||||||
|
this.redraw();
|
||||||
|
this.redrawing = false;
|
||||||
|
}
|
||||||
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
[`touchend`, `mouseup`].forEach((evtName) =>
|
[`touchend`, `mouseup`].forEach((evtName) =>
|
||||||
@@ -243,6 +254,7 @@ class BaseAPI {
|
|||||||
* disappear.
|
* disappear.
|
||||||
*/
|
*/
|
||||||
redraw() {
|
redraw() {
|
||||||
|
this.redrawing = true;
|
||||||
this.draw();
|
this.draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -126,7 +126,7 @@ class GraphicsAPI extends BaseAPI {
|
|||||||
|
|
||||||
onMouseUp(evt) {
|
onMouseUp(evt) {
|
||||||
super.onMouseUp(evt);
|
super.onMouseUp(evt);
|
||||||
this.currentPoint = undefined;
|
this.currentPoint = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
resetMovable(points) {
|
resetMovable(points) {
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "run-s clean time lint:* build pretty time && rm -f .timing",
|
"start": "run-s clean time lint:* build pretty time && rm -f .timing",
|
||||||
"test": "run-s start && run-p watch server browser",
|
"test": "run-s start -- --pretty&& run-p watch server browser",
|
||||||
"------": "--- note that due to github's naming policy, the public dir is called 'docs' rather than 'public' ---",
|
"------": "--- note that due to github's naming policy, the public dir is called 'docs' rather than 'public' ---",
|
||||||
"browser": "open-cli http://localhost:8000",
|
"browser": "open-cli http://localhost:8000",
|
||||||
"build": "node ./src/build.js",
|
"build": "node ./src/build.js",
|
||||||
|
@@ -62,7 +62,13 @@ async function createIndexPages(locale, localeStrings, chapters) {
|
|||||||
// And inject all the relevant locale strings
|
// And inject all the relevant locale strings
|
||||||
localeStrings.extendContext(context);
|
localeStrings.extendContext(context);
|
||||||
|
|
||||||
const index = nunjucks.render(`index.template.html`, context);
|
let index = nunjucks.render(`index.template.html`, context);
|
||||||
|
|
||||||
|
if (typeof process !== "undefined") {
|
||||||
|
if (process.argv.indexOf(`--pretty`) !== 0) {
|
||||||
|
index = prettier.format(index, { parser: `html` });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Prettification happens as an npm script action
|
// Prettification happens as an npm script action
|
||||||
|
|
||||||
|