mirror of
https://github.com/Pomax/BezierInfo-2.git
synced 2025-08-20 07:21:43 +02:00
source docs for [a] handlers
This commit is contained in:
@@ -1,17 +1,31 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* Setup function for a default quadratic curve.
|
||||||
|
*/
|
||||||
setupQuadratic: function(api) {
|
setupQuadratic: function(api) {
|
||||||
var curve = api.getDefaultQuadratic();
|
var curve = api.getDefaultQuadratic();
|
||||||
api.setCurve(curve);
|
api.setCurve(curve);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup function for a default cubic curve.
|
||||||
|
*/
|
||||||
setupCubic: function(api) {
|
setupCubic: function(api) {
|
||||||
var curve = api.getDefaultCubic();
|
var curve = api.getDefaultCubic();
|
||||||
api.setCurve(curve);
|
api.setCurve(curve);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A coordinate rotation function that rotates and
|
||||||
|
* translates the curve, such that the first coordinate
|
||||||
|
* of the curve is (0,0) and the last coordinate is (..., 0)
|
||||||
|
*/
|
||||||
align: function(points, line) {
|
align: function(points, line) {
|
||||||
var tx = line.p1.x,
|
var tx = line.p1.x,
|
||||||
ty = line.p1.y,
|
ty = line.p1.y,
|
||||||
|
// The atan2 function is so important to computing
|
||||||
|
// that most CPUs have a dedicated implementation
|
||||||
|
// at the hardware level for it.
|
||||||
a = -Math.atan2(line.p2.y-ty, line.p2.x-tx),
|
a = -Math.atan2(line.p2.y-ty, line.p2.x-tx),
|
||||||
cos = Math.cos,
|
cos = Math.cos,
|
||||||
sin = Math.sin,
|
sin = Math.sin,
|
||||||
@@ -24,6 +38,10 @@ module.exports = {
|
|||||||
return points.map(d);
|
return points.map(d);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw a curve and its aligned counterpart
|
||||||
|
* side by side across two panels.
|
||||||
|
*/
|
||||||
draw: function(api, curve) {
|
draw: function(api, curve) {
|
||||||
api.setPanelCount(2);
|
api.setPanelCount(2);
|
||||||
api.reset();
|
api.reset();
|
||||||
|
@@ -1,6 +1,9 @@
|
|||||||
var atan2 = Math.atan2, PI = Math.PI, TAU = 2*PI, cos = Math.cos, sin = Math.sin;
|
var atan2 = Math.atan2, PI = Math.PI, TAU = 2*PI, cos = Math.cos, sin = Math.sin;
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
// These are functions that can be called "From the page",
|
||||||
|
// rather than being internal to the sketch. This is useful
|
||||||
|
// for making on-page controls hook into the sketch code.
|
||||||
statics: {
|
statics: {
|
||||||
keyHandlingOptions: {
|
keyHandlingOptions: {
|
||||||
propName: "error",
|
propName: "error",
|
||||||
@@ -16,22 +19,39 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup up a skeleton curve that, when using its
|
||||||
|
* points for a B-spline, can form a circle.
|
||||||
|
*/
|
||||||
setupCircle: function(api) {
|
setupCircle: function(api) {
|
||||||
var curve = new api.Bezier(70,70, 140,40, 240,130);
|
var curve = new api.Bezier(70,70, 140,40, 240,130);
|
||||||
api.setCurve(curve);
|
api.setCurve(curve);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up the default quadratic curve.
|
||||||
|
*/
|
||||||
setupQuadratic: function(api) {
|
setupQuadratic: function(api) {
|
||||||
var curve = api.getDefaultQuadratic();
|
var curve = api.getDefaultQuadratic();
|
||||||
api.setCurve(curve);
|
api.setCurve(curve);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up the default cubic curve.
|
||||||
|
*/
|
||||||
setupCubic: function(api) {
|
setupCubic: function(api) {
|
||||||
var curve = api.getDefaultCubic();
|
var curve = api.getDefaultCubic();
|
||||||
api.setCurve(curve);
|
api.setCurve(curve);
|
||||||
api.error = 0.5;
|
api.error = 0.5;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given three points, find the (only!) circle
|
||||||
|
* that passes through all three points, based
|
||||||
|
* on the fact that the perpendiculars of the
|
||||||
|
* chords between the points all cross each
|
||||||
|
* other at the center of that circle.
|
||||||
|
*/
|
||||||
getCCenter: function(api, p1, p2, p3) {
|
getCCenter: function(api, p1, p2, p3) {
|
||||||
// deltas
|
// deltas
|
||||||
var dx1 = (p2.x - p1.x),
|
var dx1 = (p2.x - p1.x),
|
||||||
@@ -69,15 +89,9 @@ module.exports = {
|
|||||||
// determine arc direction (cw/ccw correction)
|
// determine arc direction (cw/ccw correction)
|
||||||
var __;
|
var __;
|
||||||
if (s<e) {
|
if (s<e) {
|
||||||
// if s<m<e, arc(s, e)
|
|
||||||
// if m<s<e, arc(e, s + TAU)
|
|
||||||
// if s<e<m, arc(e, s + TAU)
|
|
||||||
if (s>m || m>e) { s += TAU; }
|
if (s>m || m>e) { s += TAU; }
|
||||||
if (s>e) { __=e; e=s; s=__; }
|
if (s>e) { __=e; e=s; s=__; }
|
||||||
} else {
|
} else {
|
||||||
// if e<m<s, arc(e, s)
|
|
||||||
// if m<e<s, arc(s, e + TAU)
|
|
||||||
// if e<s<m, arc(s, e + TAU)
|
|
||||||
if (e<m && m<s) { __=e; e=s; s=__; } else { e += TAU; }
|
if (e<m && m<s) { __=e; e=s; s=__; } else { e += TAU; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,6 +102,9 @@ module.exports = {
|
|||||||
return i;
|
return i;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw the circle-computation sketch
|
||||||
|
*/
|
||||||
drawCircle: function(api, curve) {
|
drawCircle: function(api, curve) {
|
||||||
api.reset();
|
api.reset();
|
||||||
var pts = curve.points;
|
var pts = curve.points;
|
||||||
@@ -127,6 +144,10 @@ module.exports = {
|
|||||||
api.text("Intersection point", C, {x:-25, y:10});
|
api.text("Intersection point", C, {x:-25, y:10});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw a single arc being fit to a Bezier curve,
|
||||||
|
* to show off the general application.
|
||||||
|
*/
|
||||||
drawSingleArc: function(api, curve) {
|
drawSingleArc: function(api, curve) {
|
||||||
api.reset();
|
api.reset();
|
||||||
var arcs = curve.arcs(api.error);
|
var arcs = curve.arcs(api.error);
|
||||||
@@ -143,6 +164,9 @@ module.exports = {
|
|||||||
api.text("Arc approximation with total error " + api.utils.round(api.error,1), {x:10, y:15});
|
api.text("Arc approximation with total error " + api.utils.round(api.error,1), {x:10, y:15});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw an arc approximation for an entire Bezier curve.
|
||||||
|
*/
|
||||||
drawArcs: function(api, curve) {
|
drawArcs: function(api, curve) {
|
||||||
api.reset();
|
api.reset();
|
||||||
var arcs = curve.arcs(api.error);
|
var arcs = curve.arcs(api.error);
|
||||||
|
@@ -2,6 +2,11 @@ var sin = Math.sin;
|
|||||||
var tau = Math.PI*2;
|
var tau = Math.PI*2;
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* Set up a sinusoid generating function,
|
||||||
|
* which we'll use to draw the "progressively
|
||||||
|
* better looking" integral approximations.
|
||||||
|
*/
|
||||||
setup: function(api) {
|
setup: function(api) {
|
||||||
var w = api.getPanelWidth();
|
var w = api.getPanelWidth();
|
||||||
var h = api.getPanelHeight();
|
var h = api.getPanelHeight();
|
||||||
@@ -22,6 +27,9 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw the generator's sine function:
|
||||||
|
*/
|
||||||
drawSine: function(api, dheight) {
|
drawSine: function(api, dheight) {
|
||||||
var w = api.getPanelWidth();
|
var w = api.getPanelWidth();
|
||||||
var h = api.getPanelHeight();
|
var h = api.getPanelHeight();
|
||||||
@@ -33,6 +41,12 @@ module.exports = {
|
|||||||
api.drawFunction(generator, {x:0, 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) {
|
drawSlices: function(api, steps) {
|
||||||
var w = api.getPanelWidth();
|
var w = api.getPanelWidth();
|
||||||
var h = api.getPanelHeight();
|
var h = api.getPanelHeight();
|
||||||
@@ -44,11 +58,15 @@ module.exports = {
|
|||||||
api.setFill("rgba(150,150,255, 0.4)");
|
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) {
|
for (var step=tau/steps, i=step/2, v, p1, p2; i<tau+step/2; i+=step) {
|
||||||
v = this.generator(i);
|
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};
|
p1 = {x:v.x - f*step/2 + c, y: 0};
|
||||||
p2 = {x:v.x + f*step/2 - c, y: v.y * this.generator.scale};
|
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())+")"); }
|
if (!c) { api.setFill("rgba(150,150,255,"+(0.4 + 0.3*Math.random())+")"); }
|
||||||
api.drawRect(p1, p2, {x:0, y:h/2});
|
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);
|
area += step * Math.abs(v.y * this.generator.scale);
|
||||||
}
|
}
|
||||||
api.setFill("black");
|
api.setFill("black");
|
||||||
@@ -57,29 +75,45 @@ module.exports = {
|
|||||||
api.text("Approximating with "+steps+" strips (true area: "+trueArea+"): " + currArea, {x: 10, y: h-15});
|
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) {
|
drawCoarseIntegral: function(api) {
|
||||||
api.reset();
|
api.reset();
|
||||||
this.drawSlices(api, 10);
|
this.drawSlices(api, 10);
|
||||||
this.drawSine(api);
|
this.drawSine(api);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw the sine curve, with a 24 slice approximation:
|
||||||
|
*/
|
||||||
drawFineIntegral: function(api) {
|
drawFineIntegral: function(api) {
|
||||||
api.reset();
|
api.reset();
|
||||||
this.drawSlices(api, 24);
|
this.drawSlices(api, 24);
|
||||||
this.drawSine(api);
|
this.drawSine(api);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw the sine curve, with a 99 slice approximation:
|
||||||
|
*/
|
||||||
drawSuperFineIntegral: function(api) {
|
drawSuperFineIntegral: function(api) {
|
||||||
api.reset();
|
api.reset();
|
||||||
this.drawSlices(api, 99);
|
this.drawSlices(api, 99);
|
||||||
this.drawSine(api);
|
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) {
|
setupCurve: function(api) {
|
||||||
var curve = api.getDefaultCubic();
|
var curve = api.getDefaultCubic();
|
||||||
api.setCurve(curve);
|
api.setCurve(curve);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw our curve, and show its computed length:
|
||||||
|
*/
|
||||||
drawCurve: function(api, curve) {
|
drawCurve: function(api, curve) {
|
||||||
api.reset();
|
api.reset();
|
||||||
api.drawSkeleton(curve);
|
api.drawSkeleton(curve);
|
||||||
|
@@ -1,4 +1,7 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
|
// These are functions that can be called "From the page",
|
||||||
|
// rather than being internal to the sketch. This is useful
|
||||||
|
// for making on-page controls hook into the sketch code.
|
||||||
statics: {
|
statics: {
|
||||||
keyHandlingOptions: {
|
keyHandlingOptions: {
|
||||||
propName: "steps",
|
propName: "steps",
|
||||||
@@ -14,18 +17,29 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up the default quadratic curve.
|
||||||
|
*/
|
||||||
setupQuadratic: function(api) {
|
setupQuadratic: function(api) {
|
||||||
var curve = api.getDefaultQuadratic();
|
var curve = api.getDefaultQuadratic();
|
||||||
api.setCurve(curve);
|
api.setCurve(curve);
|
||||||
api.steps = 10;
|
api.steps = 10;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up the default cubic curve.
|
||||||
|
*/
|
||||||
setupCubic: function(api) {
|
setupCubic: function(api) {
|
||||||
var curve = api.getDefaultCubic();
|
var curve = api.getDefaultCubic();
|
||||||
api.setCurve(curve);
|
api.setCurve(curve);
|
||||||
api.steps = 16;
|
api.steps = 16;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw a curve and its polygon-approximation,
|
||||||
|
* showing the "true" length of the curve vs. the
|
||||||
|
* length based on tallying up the polygon sections.
|
||||||
|
*/
|
||||||
draw: function(api, curve) {
|
draw: function(api, curve) {
|
||||||
api.reset();
|
api.reset();
|
||||||
api.drawSkeleton(curve);
|
api.drawSkeleton(curve);
|
||||||
|
@@ -1161,19 +1161,33 @@ return {
|
|||||||
},
|
},
|
||||||
"aligning": {
|
"aligning": {
|
||||||
handler: (function() { return {
|
handler: (function() { return {
|
||||||
|
/**
|
||||||
|
* Setup function for a default quadratic curve.
|
||||||
|
*/
|
||||||
setupQuadratic: function(api) {
|
setupQuadratic: function(api) {
|
||||||
var curve = api.getDefaultQuadratic();
|
var curve = api.getDefaultQuadratic();
|
||||||
api.setCurve(curve);
|
api.setCurve(curve);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup function for a default cubic curve.
|
||||||
|
*/
|
||||||
setupCubic: function(api) {
|
setupCubic: function(api) {
|
||||||
var curve = api.getDefaultCubic();
|
var curve = api.getDefaultCubic();
|
||||||
api.setCurve(curve);
|
api.setCurve(curve);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A coordinate rotation function that rotates and
|
||||||
|
* translates the curve, such that the first coordinate
|
||||||
|
* of the curve is (0,0) and the last coordinate is (..., 0)
|
||||||
|
*/
|
||||||
align: function(points, line) {
|
align: function(points, line) {
|
||||||
var tx = line.p1.x,
|
var tx = line.p1.x,
|
||||||
ty = line.p1.y,
|
ty = line.p1.y,
|
||||||
|
// The atan2 function is so important to computing
|
||||||
|
// that most CPUs have a dedicated implementation
|
||||||
|
// at the hardware level for it.
|
||||||
a = -Math.atan2(line.p2.y-ty, line.p2.x-tx),
|
a = -Math.atan2(line.p2.y-ty, line.p2.x-tx),
|
||||||
cos = Math.cos,
|
cos = Math.cos,
|
||||||
sin = Math.sin,
|
sin = Math.sin,
|
||||||
@@ -1186,6 +1200,10 @@ return {
|
|||||||
return points.map(d);
|
return points.map(d);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw a curve and its aligned counterpart
|
||||||
|
* side by side across two panels.
|
||||||
|
*/
|
||||||
draw: function(api, curve) {
|
draw: function(api, curve) {
|
||||||
api.setPanelCount(2);
|
api.setPanelCount(2);
|
||||||
api.reset();
|
api.reset();
|
||||||
@@ -1579,6 +1597,11 @@ return sketch;
|
|||||||
var tau = Math.PI*2;
|
var tau = Math.PI*2;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
/**
|
||||||
|
* Set up a sinusoid generating function,
|
||||||
|
* which we'll use to draw the "progressively
|
||||||
|
* better looking" integral approximations.
|
||||||
|
*/
|
||||||
setup: function(api) {
|
setup: function(api) {
|
||||||
var w = api.getPanelWidth();
|
var w = api.getPanelWidth();
|
||||||
var h = api.getPanelHeight();
|
var h = api.getPanelHeight();
|
||||||
@@ -1599,6 +1622,9 @@ return {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw the generator's sine function:
|
||||||
|
*/
|
||||||
drawSine: function(api, dheight) {
|
drawSine: function(api, dheight) {
|
||||||
var w = api.getPanelWidth();
|
var w = api.getPanelWidth();
|
||||||
var h = api.getPanelHeight();
|
var h = api.getPanelHeight();
|
||||||
@@ -1610,6 +1636,12 @@ return {
|
|||||||
api.drawFunction(generator, {x:0, 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) {
|
drawSlices: function(api, steps) {
|
||||||
var w = api.getPanelWidth();
|
var w = api.getPanelWidth();
|
||||||
var h = api.getPanelHeight();
|
var h = api.getPanelHeight();
|
||||||
@@ -1621,11 +1653,15 @@ return {
|
|||||||
api.setFill("rgba(150,150,255, 0.4)");
|
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) {
|
for (var step=tau/steps, i=step/2, v, p1, p2; i<tau+step/2; i+=step) {
|
||||||
v = this.generator(i);
|
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};
|
p1 = {x:v.x - f*step/2 + c, y: 0};
|
||||||
p2 = {x:v.x + f*step/2 - c, y: v.y * this.generator.scale};
|
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())+")"); }
|
if (!c) { api.setFill("rgba(150,150,255,"+(0.4 + 0.3*Math.random())+")"); }
|
||||||
api.drawRect(p1, p2, {x:0, y:h/2});
|
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);
|
area += step * Math.abs(v.y * this.generator.scale);
|
||||||
}
|
}
|
||||||
api.setFill("black");
|
api.setFill("black");
|
||||||
@@ -1634,29 +1670,45 @@ return {
|
|||||||
api.text("Approximating with "+steps+" strips (true area: "+trueArea+"): " + currArea, {x: 10, y: h-15});
|
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) {
|
drawCoarseIntegral: function(api) {
|
||||||
api.reset();
|
api.reset();
|
||||||
this.drawSlices(api, 10);
|
this.drawSlices(api, 10);
|
||||||
this.drawSine(api);
|
this.drawSine(api);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw the sine curve, with a 24 slice approximation:
|
||||||
|
*/
|
||||||
drawFineIntegral: function(api) {
|
drawFineIntegral: function(api) {
|
||||||
api.reset();
|
api.reset();
|
||||||
this.drawSlices(api, 24);
|
this.drawSlices(api, 24);
|
||||||
this.drawSine(api);
|
this.drawSine(api);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw the sine curve, with a 99 slice approximation:
|
||||||
|
*/
|
||||||
drawSuperFineIntegral: function(api) {
|
drawSuperFineIntegral: function(api) {
|
||||||
api.reset();
|
api.reset();
|
||||||
this.drawSlices(api, 99);
|
this.drawSlices(api, 99);
|
||||||
this.drawSine(api);
|
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) {
|
setupCurve: function(api) {
|
||||||
var curve = api.getDefaultCubic();
|
var curve = api.getDefaultCubic();
|
||||||
api.setCurve(curve);
|
api.setCurve(curve);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw our curve, and show its computed length:
|
||||||
|
*/
|
||||||
drawCurve: function(api, curve) {
|
drawCurve: function(api, curve) {
|
||||||
api.reset();
|
api.reset();
|
||||||
api.drawSkeleton(curve);
|
api.drawSkeleton(curve);
|
||||||
@@ -1670,6 +1722,9 @@ return {
|
|||||||
},
|
},
|
||||||
"arclengthapprox": {
|
"arclengthapprox": {
|
||||||
handler: (function() { return {
|
handler: (function() { return {
|
||||||
|
// These are functions that can be called "From the page",
|
||||||
|
// rather than being internal to the sketch. This is useful
|
||||||
|
// for making on-page controls hook into the sketch code.
|
||||||
statics: {
|
statics: {
|
||||||
keyHandlingOptions: {
|
keyHandlingOptions: {
|
||||||
propName: "steps",
|
propName: "steps",
|
||||||
@@ -1685,18 +1740,29 @@ return {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up the default quadratic curve.
|
||||||
|
*/
|
||||||
setupQuadratic: function(api) {
|
setupQuadratic: function(api) {
|
||||||
var curve = api.getDefaultQuadratic();
|
var curve = api.getDefaultQuadratic();
|
||||||
api.setCurve(curve);
|
api.setCurve(curve);
|
||||||
api.steps = 10;
|
api.steps = 10;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up the default cubic curve.
|
||||||
|
*/
|
||||||
setupCubic: function(api) {
|
setupCubic: function(api) {
|
||||||
var curve = api.getDefaultCubic();
|
var curve = api.getDefaultCubic();
|
||||||
api.setCurve(curve);
|
api.setCurve(curve);
|
||||||
api.steps = 16;
|
api.steps = 16;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw a curve and its polygon-approximation,
|
||||||
|
* showing the "true" length of the curve vs. the
|
||||||
|
* length based on tallying up the polygon sections.
|
||||||
|
*/
|
||||||
draw: function(api, curve) {
|
draw: function(api, curve) {
|
||||||
api.reset();
|
api.reset();
|
||||||
api.drawSkeleton(curve);
|
api.drawSkeleton(curve);
|
||||||
@@ -3599,6 +3665,9 @@ return {
|
|||||||
handler: (function() { var atan2 = Math.atan2, PI = Math.PI, TAU = 2*PI, cos = Math.cos, sin = Math.sin;
|
handler: (function() { var atan2 = Math.atan2, PI = Math.PI, TAU = 2*PI, cos = Math.cos, sin = Math.sin;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
// These are functions that can be called "From the page",
|
||||||
|
// rather than being internal to the sketch. This is useful
|
||||||
|
// for making on-page controls hook into the sketch code.
|
||||||
statics: {
|
statics: {
|
||||||
keyHandlingOptions: {
|
keyHandlingOptions: {
|
||||||
propName: "error",
|
propName: "error",
|
||||||
@@ -3614,22 +3683,39 @@ return {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup up a skeleton curve that, when using its
|
||||||
|
* points for a B-spline, can form a circle.
|
||||||
|
*/
|
||||||
setupCircle: function(api) {
|
setupCircle: function(api) {
|
||||||
var curve = new api.Bezier(70,70, 140,40, 240,130);
|
var curve = new api.Bezier(70,70, 140,40, 240,130);
|
||||||
api.setCurve(curve);
|
api.setCurve(curve);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up the default quadratic curve.
|
||||||
|
*/
|
||||||
setupQuadratic: function(api) {
|
setupQuadratic: function(api) {
|
||||||
var curve = api.getDefaultQuadratic();
|
var curve = api.getDefaultQuadratic();
|
||||||
api.setCurve(curve);
|
api.setCurve(curve);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up the default cubic curve.
|
||||||
|
*/
|
||||||
setupCubic: function(api) {
|
setupCubic: function(api) {
|
||||||
var curve = api.getDefaultCubic();
|
var curve = api.getDefaultCubic();
|
||||||
api.setCurve(curve);
|
api.setCurve(curve);
|
||||||
api.error = 0.5;
|
api.error = 0.5;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given three points, find the (only!) circle
|
||||||
|
* that passes through all three points, based
|
||||||
|
* on the fact that the perpendiculars of the
|
||||||
|
* chords between the points all cross each
|
||||||
|
* other at the center of that circle.
|
||||||
|
*/
|
||||||
getCCenter: function(api, p1, p2, p3) {
|
getCCenter: function(api, p1, p2, p3) {
|
||||||
// deltas
|
// deltas
|
||||||
var dx1 = (p2.x - p1.x),
|
var dx1 = (p2.x - p1.x),
|
||||||
@@ -3667,15 +3753,9 @@ return {
|
|||||||
// determine arc direction (cw/ccw correction)
|
// determine arc direction (cw/ccw correction)
|
||||||
var __;
|
var __;
|
||||||
if (s<e) {
|
if (s<e) {
|
||||||
// if s<m<e, arc(s, e)
|
|
||||||
// if m<s<e, arc(e, s + TAU)
|
|
||||||
// if s<e<m, arc(e, s + TAU)
|
|
||||||
if (s>m || m>e) { s += TAU; }
|
if (s>m || m>e) { s += TAU; }
|
||||||
if (s>e) { __=e; e=s; s=__; }
|
if (s>e) { __=e; e=s; s=__; }
|
||||||
} else {
|
} else {
|
||||||
// if e<m<s, arc(e, s)
|
|
||||||
// if m<e<s, arc(s, e + TAU)
|
|
||||||
// if e<s<m, arc(s, e + TAU)
|
|
||||||
if (e<m && m<s) { __=e; e=s; s=__; } else { e += TAU; }
|
if (e<m && m<s) { __=e; e=s; s=__; } else { e += TAU; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3686,6 +3766,9 @@ return {
|
|||||||
return i;
|
return i;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw the circle-computation sketch
|
||||||
|
*/
|
||||||
drawCircle: function(api, curve) {
|
drawCircle: function(api, curve) {
|
||||||
api.reset();
|
api.reset();
|
||||||
var pts = curve.points;
|
var pts = curve.points;
|
||||||
@@ -3725,6 +3808,10 @@ return {
|
|||||||
api.text("Intersection point", C, {x:-25, y:10});
|
api.text("Intersection point", C, {x:-25, y:10});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw a single arc being fit to a Bezier curve,
|
||||||
|
* to show off the general application.
|
||||||
|
*/
|
||||||
drawSingleArc: function(api, curve) {
|
drawSingleArc: function(api, curve) {
|
||||||
api.reset();
|
api.reset();
|
||||||
var arcs = curve.arcs(api.error);
|
var arcs = curve.arcs(api.error);
|
||||||
@@ -3741,6 +3828,9 @@ return {
|
|||||||
api.text("Arc approximation with total error " + api.utils.round(api.error,1), {x:10, y:15});
|
api.text("Arc approximation with total error " + api.utils.round(api.error,1), {x:10, y:15});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw an arc approximation for an entire Bezier curve.
|
||||||
|
*/
|
||||||
drawArcs: function(api, curve) {
|
drawArcs: function(api, curve) {
|
||||||
api.reset();
|
api.reset();
|
||||||
var arcs = curve.arcs(api.error);
|
var arcs = curve.arcs(api.error);
|
||||||
|
Reference in New Issue
Block a user