mirror of
https://github.com/Pomax/BezierInfo-2.git
synced 2025-08-19 06:52:02 +02:00
let's deploy this.
This commit is contained in:
@@ -1,10 +1,25 @@
|
||||
var React = require("react");
|
||||
var Graphic = require("../../Graphic.jsx");
|
||||
var SectionHeader = require("../../SectionHeader.jsx");
|
||||
|
||||
var keyHandling = require("../../decorators/keyhandling-decorator.jsx");
|
||||
var atan2 = Math.atan2, PI = Math.PI, TAU = 2*PI, cos = Math.cos, sin = Math.sin;
|
||||
|
||||
var Introduction = React.createClass({
|
||||
statics: {
|
||||
keyHandlingOptions: {
|
||||
propName: "error",
|
||||
values: {
|
||||
"38": 0.1, // up arrow
|
||||
"40": -0.1 // down arrow
|
||||
},
|
||||
controller: function(api) {
|
||||
if (api.error < 0.1) {
|
||||
api.error = 0.1;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
title: "Approximating Bézier curves with circular arcs"
|
||||
@@ -27,22 +42,6 @@ var Introduction = React.createClass({
|
||||
api.error = 0.5;
|
||||
},
|
||||
|
||||
values: {
|
||||
"38": 0.1, // up arrow
|
||||
"40": -0.1 // down arrow
|
||||
},
|
||||
|
||||
onKeyDown: function(e, api) {
|
||||
var v = this.values[e.keyCode];
|
||||
if(v) {
|
||||
e.preventDefault();
|
||||
api.error += v;
|
||||
if (api.error < 0.1) {
|
||||
api.error = 0.1;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getCCenter: function(api, p1, p2, p3) {
|
||||
// deltas
|
||||
var dx1 = (p2.x - p1.x),
|
||||
@@ -237,7 +236,7 @@ var Introduction = React.createClass({
|
||||
interactive, and you can use your up and down cursor keys keys to increase or decrease the error threshold,
|
||||
to see what the effect of a smaller or larger error threshold is.</p>
|
||||
|
||||
<Graphic preset="simple" title="Arc approximation of a Bézier curve" setup={this.setupCubic} draw={this.drawSingleArc} onKeyDown={this.onKeyDown} />
|
||||
<Graphic preset="simple" title="Arc approximation of a Bézier curve" setup={this.setupCubic} draw={this.drawSingleArc} onKeyDown={this.props.onKeyDown} />
|
||||
|
||||
<p>With that in place, all that's left now is to "restart" the procedure by treating the found arc's
|
||||
end point as the new to-be-determined arc's starting point, and using points further down the curve. We
|
||||
@@ -246,7 +245,7 @@ var Introduction = React.createClass({
|
||||
so you can see how picking a different threshold changes the number of arcs that are necessary to
|
||||
reasonably approximate a curve:</p>
|
||||
|
||||
<Graphic preset="simple" title="Arc approximation of a Bézier curve" setup={this.setupCubic} draw={this.drawArcs} onKeyDown={this.onKeyDown} />
|
||||
<Graphic preset="simple" title="Arc approximation of a Bézier curve" setup={this.setupCubic} draw={this.drawArcs} onKeyDown={this.props.onKeyDown} />
|
||||
|
||||
<p>So... what is this good for? Obviously, If you're working with technologies that can't do curves,
|
||||
but can do lines and circles, then the answer is pretty straight-forward, but what else? There are
|
||||
@@ -265,4 +264,4 @@ var Introduction = React.createClass({
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Introduction;
|
||||
module.exports = keyHandling(Introduction);
|
||||
|
@@ -1,8 +1,24 @@
|
||||
var React = require("react");
|
||||
var Graphic = require("../../Graphic.jsx");
|
||||
var SectionHeader = require("../../SectionHeader.jsx");
|
||||
var keyHandling = require("../../decorators/keyhandling-decorator.jsx");
|
||||
|
||||
var ArclengthApprox = React.createClass({
|
||||
statics: {
|
||||
keyHandlingOptions: {
|
||||
propName: "steps",
|
||||
values: {
|
||||
"38": 1, // up arrow
|
||||
"40": -1 // down arrow
|
||||
},
|
||||
controller: function(api) {
|
||||
if (api.steps < 1) {
|
||||
api.steps = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
title: "Approximated arc length"
|
||||
@@ -51,23 +67,6 @@ var ArclengthApprox = React.createClass({
|
||||
api.text("Approximate length, "+api.steps+" steps: "+alen+" (true: "+len+")", {x:10, y: 15});
|
||||
},
|
||||
|
||||
values: {
|
||||
"38": 1, // up arrow
|
||||
"40": -1 // down arrow
|
||||
},
|
||||
|
||||
onKeyDown: function(e, api) {
|
||||
var v = this.values[e.keyCode];
|
||||
if(v) {
|
||||
e.preventDefault();
|
||||
api.steps += v;
|
||||
if (api.steps < 1) {
|
||||
api.steps = 1;
|
||||
}
|
||||
console.log(api.steps);
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<section>
|
||||
@@ -81,8 +80,8 @@ var ArclengthApprox = React.createClass({
|
||||
<p>If we combine the work done in the previous sections on curve flattening and arc length computation, we can
|
||||
implement these with minimal effort:</p>
|
||||
|
||||
<Graphic preset="twopanel" title="Approximate quadratic curve arc length" setup={this.setupQuadratic} draw={this.draw} onKeyDown={this.onKeyDown} />
|
||||
<Graphic preset="twopanel" title="Approximate cubic curve arc length" setup={this.setupCubic} draw={this.draw} onKeyDown={this.onKeyDown} />
|
||||
<Graphic preset="twopanel" title="Approximate quadratic curve arc length" setup={this.setupQuadratic} draw={this.draw} onKeyDown={this.props.onKeyDown} />
|
||||
<Graphic preset="twopanel" title="Approximate cubic curve arc length" setup={this.setupCubic} draw={this.draw} onKeyDown={this.props.onKeyDown} />
|
||||
|
||||
<p>Try clicking on the sketch and using your up and down arrow keys to lower the number of segments for both
|
||||
the quadratic and cubic curve. You may notice that the error in length is actually pretty significant, even if
|
||||
@@ -94,87 +93,4 @@ var ArclengthApprox = React.createClass({
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = ArclengthApprox;
|
||||
|
||||
/*
|
||||
|
||||
void setupCurve() {
|
||||
setupDefaultQuadratic();
|
||||
offsetting();
|
||||
offset = 16;
|
||||
}
|
||||
|
||||
void drawCurve(BezierCurve curve) {
|
||||
additionals();
|
||||
curve.draw();
|
||||
|
||||
nextPanel();
|
||||
stroke(0);
|
||||
float x = curve.getXValue(0),
|
||||
y = curve.getYValue(0),
|
||||
x2, y2, step = 1/offset, t,
|
||||
length=0;
|
||||
for(int i=1; i<=offset; i++) {
|
||||
t = i*step;
|
||||
x2 = curve.getXValue(t);
|
||||
y2 = curve.getYValue(t);
|
||||
line(x,y,x2,y2);
|
||||
length += dist(x,y,x2,y2);
|
||||
x = x2;
|
||||
y = y2;
|
||||
}
|
||||
|
||||
float arclength = curve.getCurveLength();
|
||||
float error = 100 * (arclength - length) / arclength;
|
||||
|
||||
length = nfc(length, 3, 3);
|
||||
arclength = nfc(arclength, 3, 3);
|
||||
error = nfc(error, 3, 3);
|
||||
if(error.indexOf(".")===0) { error = "0" + error; }
|
||||
|
||||
fill(0);
|
||||
text("Approximate arc length based on "+offset+" segments: " + length, -dim/4, dim-20);
|
||||
text("True length: " + arclength + ", error: " + error + "%", -dim/4, dim-5);
|
||||
}</textarea>
|
||||
|
||||
|
||||
void setupCurve() {
|
||||
setupDefaultCubic();
|
||||
offsetting();
|
||||
offset = 24;
|
||||
}
|
||||
|
||||
void drawCurve(BezierCurve curve) {
|
||||
additionals();
|
||||
curve.draw();
|
||||
|
||||
nextPanel();
|
||||
stroke(0);
|
||||
float x = curve.getXValue(0),
|
||||
y = curve.getYValue(0),
|
||||
x2, y2, step = 1/offset, t,
|
||||
length=0;
|
||||
for(int i=1; i<=offset; i++) {
|
||||
t = i*step;
|
||||
x2 = curve.getXValue(t);
|
||||
y2 = curve.getYValue(t);
|
||||
line(x,y,x2,y2);
|
||||
length += dist(x,y,x2,y2);
|
||||
x = x2;
|
||||
y = y2;
|
||||
}
|
||||
|
||||
float arclength = curve.getCurveLength();
|
||||
float error = 100 * (arclength - length) / arclength;
|
||||
|
||||
length = nfc(length, 3, 3);
|
||||
arclength = nfc(arclength, 3, 3);
|
||||
error = nfc(error, 3, 3);
|
||||
if(error.indexOf(".")===0) { error = "0" + error; }
|
||||
|
||||
fill(0);
|
||||
text("Approximate arc length based on "+offset+" segments: " + length, -dim/4, dim-20);
|
||||
text("True length: " + arclength + ", error: " + error + "%", -dim/4, dim-5);
|
||||
}</textarea>
|
||||
|
||||
*/
|
||||
module.exports = keyHandling(ArclengthApprox);
|
@@ -1,8 +1,19 @@
|
||||
var React = require("react");
|
||||
var Graphic = require("../../Graphic.jsx");
|
||||
var SectionHeader = require("../../SectionHeader.jsx");
|
||||
var keyHandling = require("../../decorators/keyhandling-decorator.jsx");
|
||||
|
||||
var CatmullRomMoulding = React.createClass({
|
||||
statics: {
|
||||
keyHandlingOptions: {
|
||||
propName: "distance",
|
||||
values: {
|
||||
"38": 1, // up arrow
|
||||
"40": -1 // down arrow
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
title: "Creating a Catmull-Rom curve from three points"
|
||||
@@ -19,16 +30,6 @@ var CatmullRomMoulding = React.createClass({
|
||||
api.distance = 0;
|
||||
},
|
||||
|
||||
onKeyDown: function(evt, api) {
|
||||
if (evt.key === "ArrowUp") {
|
||||
evt.preventDefault();
|
||||
api.distance += 1;
|
||||
} else if (evt.key === "ArrowDown") {
|
||||
evt.preventDefault();
|
||||
api.distance -= 1;
|
||||
}
|
||||
},
|
||||
|
||||
convert: function(p1, p2, p3, p4) {
|
||||
var t = 0.5;
|
||||
return [
|
||||
@@ -167,7 +168,7 @@ var CatmullRomMoulding = React.createClass({
|
||||
we want to do this? Because the line p0--p2 acts as departure tangent at p1, and the line p2--p4 acts as
|
||||
arrival tangent at p3. Play around with the graphic a bit to get an idea of what all of that meant:</p>
|
||||
|
||||
<Graphic preset="threepanel" title="Catmull-Rom curve fitting" setup={this.setup} draw={this.draw} onKeyDown={this.onKeyDown}/>
|
||||
<Graphic preset="threepanel" title="Catmull-Rom curve fitting" setup={this.setup} draw={this.draw} onKeyDown={this.props.onKeyDown}/>
|
||||
|
||||
<p>As should be obvious by now, Catmull-Rom curves are great for "fitting a curvature to some points", but if we want
|
||||
to convert that curve to Bézier form we're going to end up with a lot of separate (but visually joined) Bézier curves.
|
||||
@@ -178,4 +179,4 @@ var CatmullRomMoulding = React.createClass({
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = CatmullRomMoulding;
|
||||
module.exports = keyHandling(CatmullRomMoulding);
|
||||
|
@@ -1,30 +1,30 @@
|
||||
var React = require("react");
|
||||
var Graphic = require("../../Graphic.jsx");
|
||||
var SectionHeader = require("../../SectionHeader.jsx");
|
||||
var keyHandling = require("../../decorators/keyhandling-decorator.jsx");
|
||||
|
||||
var Explanation = React.createClass({
|
||||
statics: {
|
||||
keyHandlingOptions: {
|
||||
propName: "step",
|
||||
values: {
|
||||
"38": 0.1, // up arrow
|
||||
"40": -0.1 // down arrow
|
||||
},
|
||||
controller: function(api) {
|
||||
if (api.step < 0.1) {
|
||||
api.step = 0.1;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
title: "The mathematics of Bézier curves"
|
||||
};
|
||||
},
|
||||
|
||||
values: {
|
||||
"38": 0.1, // up arrow
|
||||
"40": -0.1 // down arrow
|
||||
},
|
||||
|
||||
onKeyDown: function(e, api) {
|
||||
var v = this.values[e.keyCode];
|
||||
if(v) {
|
||||
e.preventDefault();
|
||||
api.step += v;
|
||||
if (api.step < 0.1) {
|
||||
api.step = 0.1;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
setup: function(api) {
|
||||
api.step = 5;
|
||||
},
|
||||
@@ -126,7 +126,7 @@ var Explanation = React.createClass({
|
||||
radius 1 around the origin (0,0). If we plot it for <i>t</i> from 0 to 5, we get this (use
|
||||
your up and down cursor keys to change the plot end value):</p>
|
||||
|
||||
<Graphic preset="empty" title="A (partial) circle: x=sin(t), y=cos(t)" static={true} setup={this.setup} draw={this.draw} onKeyDown={this.onKeyDown}/>
|
||||
<Graphic preset="empty" title="A (partial) circle: x=sin(t), y=cos(t)" static={true} setup={this.setup} draw={this.draw} onKeyDown={this.props.onKeyDown}/>
|
||||
|
||||
<p>Bézier curves are (one in many classes of) parametric functions, and are characterised
|
||||
by using the same base function for all its dimensions. Unlike the above example,
|
||||
@@ -277,4 +277,4 @@ function Bezier(3,t):
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Explanation;
|
||||
module.exports = keyHandling(Explanation);
|
||||
|
@@ -1,8 +1,24 @@
|
||||
var React = require("react");
|
||||
var Graphic = require("../../Graphic.jsx");
|
||||
var SectionHeader = require("../../SectionHeader.jsx");
|
||||
var keyHandling = require("../../decorators/keyhandling-decorator.jsx");
|
||||
|
||||
var Flattening = React.createClass({
|
||||
statics: {
|
||||
keyHandlingOptions: {
|
||||
propName: "steps",
|
||||
values: {
|
||||
"38": 1, // up arrow
|
||||
"40": -1 // down arrow
|
||||
},
|
||||
controller: function(api) {
|
||||
if (api.steps < 1) {
|
||||
api.steps = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
title: "Simplified drawing"
|
||||
@@ -106,4 +122,4 @@ var Flattening = React.createClass({
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Flattening;
|
||||
module.exports = keyHandling(Flattening);
|
||||
|
@@ -1,8 +1,19 @@
|
||||
var React = require("react");
|
||||
var Graphic = require("../../Graphic.jsx");
|
||||
var SectionHeader = require("../../SectionHeader.jsx");
|
||||
var keyHandling = require("../../decorators/keyhandling-decorator.jsx");
|
||||
|
||||
var GraduatedOffsetting = React.createClass({
|
||||
statics: {
|
||||
keyHandlingOptions: {
|
||||
propName: "distance",
|
||||
values: {
|
||||
"38": 1, // up arrow
|
||||
"40": -1 // down arrow
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
title: "Graduated curve offsetting"
|
||||
@@ -35,19 +46,6 @@ var GraduatedOffsetting = React.createClass({
|
||||
outline.curves.forEach(c => api.drawCurve(c));
|
||||
},
|
||||
|
||||
values: {
|
||||
"38": 1, // up arrow
|
||||
"40": -1 // down arrow
|
||||
},
|
||||
|
||||
onKeyDown: function(e, api) {
|
||||
var v = this.values[e.keyCode];
|
||||
if(v) {
|
||||
e.preventDefault();
|
||||
api.distance += v;
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<section>
|
||||
@@ -82,12 +80,11 @@ var GraduatedOffsetting = React.createClass({
|
||||
will give us the following result (these have with a starting width of 0, and an end width
|
||||
of 40 pixels, but can be controlled with your up and down cursor keys):</p>
|
||||
|
||||
<Graphic preset="simple" title="Offsetting a quadratic Bézier curve" setup={this.setupQuadratic} draw={this.draw} onKeyDown={this.onKeyDown}/>
|
||||
<Graphic preset="simple" title="Offsetting a cubic Bézier curve" setup={this.setupCubic} draw={this.draw} onKeyDown={this.onKeyDown}/>
|
||||
|
||||
<Graphic preset="simple" title="Offsetting a quadratic Bézier curve" setup={this.setupQuadratic} draw={this.draw} onKeyDown={this.props.onKeyDown}/>
|
||||
<Graphic preset="simple" title="Offsetting a cubic Bézier curve" setup={this.setupCubic} draw={this.draw} onKeyDown={this.props.onKeyDown}/>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = GraduatedOffsetting;
|
||||
module.exports = keyHandling(GraduatedOffsetting);
|
||||
|
@@ -1,8 +1,19 @@
|
||||
var React = require("react");
|
||||
var Graphic = require("../../Graphic.jsx");
|
||||
var SectionHeader = require("../../SectionHeader.jsx");
|
||||
var keyHandling = require("../../decorators/keyhandling-decorator.jsx");
|
||||
|
||||
var Offsetting = React.createClass({
|
||||
statics: {
|
||||
keyHandlingOptions: {
|
||||
propName: "distance",
|
||||
values: {
|
||||
"38": 1, // up arrow
|
||||
"40": -1 // down arrow
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
title: "Curve offsetting"
|
||||
@@ -56,19 +67,6 @@ var Offsetting = React.createClass({
|
||||
api.drawCircle(last.points[3] || last.points[2],1);
|
||||
},
|
||||
|
||||
values: {
|
||||
"38": 1, // up arrow
|
||||
"40": -1 // down arrow
|
||||
},
|
||||
|
||||
onKeyDown: function(e, api) {
|
||||
var v = this.values[e.keyCode];
|
||||
if(v) {
|
||||
e.preventDefault();
|
||||
api.distance += v;
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<section>
|
||||
@@ -183,8 +181,8 @@ var Offsetting = React.createClass({
|
||||
curves, no reduction is necessary, but the more twisty the curve gets, the more the curve needs to be reduced
|
||||
in order to get segments that can safely be scaled.</p>
|
||||
|
||||
<Graphic preset="simple" title="Offsetting a quadratic Bézier curve" setup={this.setupQuadratic} draw={this.draw} onKeyDown={this.onKeyDown} />
|
||||
<Graphic preset="simple" title="Offsetting a cubic Bézier curve" setup={this.setupCubic} draw={this.draw} onKeyDown={this.onKeyDown} />
|
||||
<Graphic preset="simple" title="Offsetting a quadratic Bézier curve" setup={this.setupQuadratic} draw={this.draw} onKeyDown={this.props.onKeyDown} />
|
||||
<Graphic preset="simple" title="Offsetting a cubic Bézier curve" setup={this.setupCubic} draw={this.draw} onKeyDown={this.props.onKeyDown} />
|
||||
|
||||
<p>You may notice that this may still lead to small 'jumps' in the sub-curves when moving the
|
||||
curve around. This is caused by the fact that we're still performing a naive form of offsetting,
|
||||
@@ -196,4 +194,4 @@ var Offsetting = React.createClass({
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Offsetting;
|
||||
module.exports = keyHandling(Offsetting);
|
||||
|
@@ -47,15 +47,19 @@ var Preface = React.createClass({
|
||||
<p>So, what if you need to program them yourself? What are the pitfalls? How do you draw them?
|
||||
What are the bounding boxes, how do you determine intersections, how can you extrude a curve,
|
||||
in short: how do you do everything that you might want when you do with these curves? That's
|
||||
what this page is for. Prepare to be mathed.</p>
|
||||
what this page is for. Prepare to be mathed!</p>
|
||||
|
||||
<div>
|
||||
<h2>All Bézier graphics are interactive.</h2>
|
||||
<p>—Pomax (or in the tweetworld, <a href="https://twitter.com/TheRealPomax">@TheRealPomax</a>)</p>
|
||||
|
||||
<p>This page uses interactive examples, as well as "real" maths (in LaTeX form) which
|
||||
is typeset using the most excellent <a href="http://MathJax.org">MathJax</a> library.
|
||||
This page is still in rewriting, but once done, all examples will also have a "view source"
|
||||
option, which lets you see how things were implemented using the Bezier.js library.</p>
|
||||
<div className="note">
|
||||
<h2>Note: All Bézier graphics are interactive.</h2>
|
||||
|
||||
<p>This page uses interactive examples, relying heavily on <a href="http://pomax.github.io/bezierjs/">Bezier.js</a>,
|
||||
as well as "real" maths (in LaTeX form) which is typeset using the most excellent <a href="http://MathJax.org">MathJax</a> library.
|
||||
The page is generated offline as a React application, using Webpack, which has made adding
|
||||
"view source" options considerably more challenging. I'm still trying to figure out how to
|
||||
add them back in, but it didn't feel like it should hold up deploying this update compared
|
||||
to the previous years' version.</p>
|
||||
|
||||
<h2>How complicated is the maths going to be?</h2>
|
||||
|
||||
@@ -74,8 +78,6 @@ var Preface = React.createClass({
|
||||
but you can use the issue tracker for that as well. Once the rewrite is done, I'll add a general
|
||||
comment section back in, and maybe a more topical "select this section of text and hit the
|
||||
'question' button to ask a question about it" system. We'll see.
|
||||
|
||||
<p>—Pomax (or in the tweetworld, <a href="https://twitter.com/TheRealPomax">@TheRealPomax</a>)</p>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
@@ -1,8 +1,39 @@
|
||||
var React = require("react");
|
||||
var Graphic = require("../../Graphic.jsx");
|
||||
var SectionHeader = require("../../SectionHeader.jsx");
|
||||
var keyHandling = require("../../decorators/keyhandling-decorator.jsx");
|
||||
|
||||
var Reordering = React.createClass({
|
||||
statics: {
|
||||
// Improve this based on http://www.sirver.net/blog/2011/08/23/degree-reduction-of-bezier-curves/
|
||||
lower: function(curve) {
|
||||
var pts = curve.points, q=[], n = pts.length;
|
||||
pts.forEach((p,k) => {
|
||||
if (!k) { return (q[k] = p); }
|
||||
var f1 = k/n, f2 = 1 - f1;
|
||||
q[k] = {
|
||||
x: f1 * p.x + f2 * pts[k-1].x,
|
||||
y: f1 * p.y + f2 * pts[k-1].y
|
||||
};
|
||||
});
|
||||
q.splice(n-1,1);
|
||||
q[n-2] = pts[n-1];
|
||||
curve.points = q;
|
||||
return curve;
|
||||
},
|
||||
|
||||
keyHandlingOptions: {
|
||||
values: {
|
||||
"38": function(api) {
|
||||
api.setCurve(api.curve.raise());
|
||||
},
|
||||
"40": function(api) {
|
||||
api.setCurve(Reordering.lower(api.curve));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
title: "Lowering and elevating curve order"
|
||||
@@ -69,32 +100,6 @@ var Reordering = React.createClass({
|
||||
});
|
||||
},
|
||||
|
||||
// Improve this based on http://www.sirver.net/blog/2011/08/23/degree-reduction-of-bezier-curves/
|
||||
lower: function(curve) {
|
||||
var pts = curve.points, q=[], n = pts.length;
|
||||
pts.forEach((p,k) => {
|
||||
if (!k) { return (q[k] = p); }
|
||||
var f1 = k/n, f2 = 1 - f1;
|
||||
q[k] = {
|
||||
x: f1 * p.x + f2 * pts[k-1].x,
|
||||
y: f1 * p.y + f2 * pts[k-1].y
|
||||
};
|
||||
});
|
||||
q.splice(n-1,1);
|
||||
q[n-2] = pts[n-1];
|
||||
curve.points = q;
|
||||
return curve;
|
||||
},
|
||||
|
||||
onKeyDown: function(evt, api) {
|
||||
evt.preventDefault();
|
||||
if(evt.key === "ArrowUp") {
|
||||
api.setCurve(api.curve.raise());
|
||||
} else if(evt.key === "ArrowDown") {
|
||||
api.setCurve(this.lower(api.curve));
|
||||
}
|
||||
},
|
||||
|
||||
getOrder: function() {
|
||||
var order = this.state.order;
|
||||
if (order%10 === 1 && order !== 11) {
|
||||
@@ -146,7 +151,7 @@ var Reordering = React.createClass({
|
||||
<p>We can apply this to a (semi) random curve, as is done in the following graphic. Select the sketch
|
||||
and press your up and down cursor keys to elevate or lower the curve order.</p>
|
||||
|
||||
<Graphic preset="simple" title={"A " + this.getOrder() + " order Bézier curve"} setup={this.setup} draw={this.draw} onKeyDown={this.onKeyDown} />
|
||||
<Graphic preset="simple" title={"A " + this.getOrder() + " order Bézier curve"} setup={this.setup} draw={this.draw} onKeyDown={this.props.onKeyDown} />
|
||||
|
||||
<p>There is a good, if mathematical, explanation on the matrices necessary for optimal reduction
|
||||
over on <a href="http://www.sirver.net/blog/2011/08/23/degree-reduction-of-bezier-curves/">Sirver's Castle</a>,
|
||||
@@ -157,4 +162,4 @@ var Reordering = React.createClass({
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Reordering;
|
||||
module.exports = keyHandling(Reordering);
|
||||
|
@@ -1,8 +1,24 @@
|
||||
var React = require("react");
|
||||
var Graphic = require("../../Graphic.jsx");
|
||||
var SectionHeader = require("../../SectionHeader.jsx");
|
||||
var keyHandling = require("../../decorators/keyhandling-decorator.jsx");
|
||||
|
||||
var Tracing = React.createClass({
|
||||
statics: {
|
||||
keyHandlingOptions: {
|
||||
propName: "steps",
|
||||
values: {
|
||||
"38": 1, // up arrow
|
||||
"40": -1 // down arrow
|
||||
},
|
||||
controller: function(api) {
|
||||
if (api.steps < 1) {
|
||||
api.steps = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
title: "Tracing a curve at fixed distance intervals"
|
||||
@@ -60,23 +76,6 @@ var Tracing = React.createClass({
|
||||
}
|
||||
},
|
||||
|
||||
values: {
|
||||
"38": 1, // up arrow
|
||||
"40": -1 // down arrow
|
||||
},
|
||||
|
||||
onKeyDown: function(e, api) {
|
||||
var v = this.values[e.keyCode];
|
||||
if(v) {
|
||||
e.preventDefault();
|
||||
api.steps += v;
|
||||
if (api.steps < 1) {
|
||||
api.steps = 1;
|
||||
}
|
||||
console.log(api.steps);
|
||||
}
|
||||
},
|
||||
|
||||
drawColoured: function(api, curve) {
|
||||
api.setPanelCount(3);
|
||||
var w = api.getPanelWidth();
|
||||
@@ -155,11 +154,11 @@ var Tracing = React.createClass({
|
||||
apart. In fact, let's look at the relation between "distance long a curve" and
|
||||
"<i>t</i> value", by plotting them against one another.</p>
|
||||
|
||||
<p>The following graphic shows a particularly illustrative curve, and it's length-to-<i>t</i> plot.
|
||||
<p>The following graphic shows a particularly illustrative curve, and it's length-to-t plot.
|
||||
For linear traversal, this line needs to be straight, running from (0,0) to (length,1). This is,
|
||||
it's safe to say, not what we'll see, we'll see something wobbly instead. To make matters even
|
||||
worse, the length-to-<i>t</i> function is also of a much higher order than our curve is: while
|
||||
the curve we're using for this exercise is a cubic curve, able to switch concave/convex form twice
|
||||
the curve we're using for this exercise is a cubic curve, which can switch concave/convex form once
|
||||
at best, the plot shows that the distance function along the curve is able to switch forms three
|
||||
times (to see this, try creating an S curve with the start/end close together, but the control
|
||||
points far apart).</p>
|
||||
@@ -183,7 +182,7 @@ var Tracing = React.createClass({
|
||||
along the horizontal axis. It also shows the curve in an alternating colouring based on the
|
||||
t-for-distance values we find our LUT:</p>
|
||||
|
||||
<Graphic preset="threepanel" title="Fixed-interval coloring a curve" setup={this.setup} draw={this.drawColoured} onKeyDown={this.onKeyDown}/>
|
||||
<Graphic preset="threepanel" title="Fixed-interval coloring a curve" setup={this.setup} draw={this.drawColoured} onKeyDown={this.props.onKeyDown}/>
|
||||
|
||||
<p>Use your up and down arrow keys to increase or decrease the number of equidistant segments
|
||||
used to colour the curve.</p>
|
||||
@@ -199,4 +198,4 @@ var Tracing = React.createClass({
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Tracing;
|
||||
module.exports = keyHandling(Tracing);
|
||||
|
Reference in New Issue
Block a user