mirror of
https://github.com/Pomax/BezierInfo-2.git
synced 2025-08-31 12:01:54 +02:00
.
This commit is contained in:
@@ -50,6 +50,11 @@ var Article = React.createClass({
|
||||
</navigation>
|
||||
</div>
|
||||
<div ref="sections">{ sections }</div>
|
||||
<footer class="copyright">
|
||||
This article is © 2011-2016 to me, Mike "Pomax" Kamermans, but the text, code,
|
||||
and images are <a href="https://github.com/Pomax/bezierinfo/blob/gh-pages/LICENSE.md">almost
|
||||
no rights reserved</a>. Go do something cool with it!
|
||||
</footer>
|
||||
</div>);
|
||||
}
|
||||
});
|
||||
|
@@ -118,6 +118,7 @@ var Graphic = React.createClass({
|
||||
|
||||
mouseMove: function(evt) {
|
||||
fix(evt);
|
||||
|
||||
if(!this.props.static) {
|
||||
|
||||
if (this.down) {
|
||||
@@ -165,7 +166,7 @@ var Graphic = React.createClass({
|
||||
this.props.onMouseDrag(evt, this);
|
||||
}
|
||||
|
||||
if (!this.playing && this.props.draw) {
|
||||
if (!this.props.static && !this.playing && this.props.draw) {
|
||||
this.props.draw(this, this.curve);
|
||||
}
|
||||
},
|
||||
@@ -472,7 +473,7 @@ var Graphic = React.createClass({
|
||||
drawPoints: function(points, offset) {
|
||||
offset = offset || { x:0, y:0 };
|
||||
points.forEach(function(p) {
|
||||
this.drawCircle(p, 3, offset);
|
||||
this.drawCircle(p, (offset.x!==0||offset.y!==0)? 1.5: 3, offset);
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
|
@@ -104,25 +104,37 @@ var Introduction = React.createClass({
|
||||
|
||||
// get center
|
||||
var C = this.getCCenter(api, pts[0], pts[1], pts[2]);
|
||||
// outer circle
|
||||
api.setColor("grey");
|
||||
api.drawCircle(C, api.utils.dist(C,pts[0]));
|
||||
|
||||
// controllable points
|
||||
api.setColor("black");
|
||||
pts.forEach(p => api.drawCircle(p,3));
|
||||
api.drawCircle(C, 3);
|
||||
|
||||
// chords and perpendicular lines
|
||||
var m;
|
||||
|
||||
api.setColor("blue");
|
||||
api.drawLine(pts[0], pts[1]);
|
||||
api.drawLine({x: (pts[0].x + pts[1].x)/2, y: (pts[0].y + pts[1].y)/2}, C);
|
||||
m = {x: (pts[0].x + pts[1].x)/2, y: (pts[0].y + pts[1].y)/2};
|
||||
api.drawLine(m, {x:C.x+(C.x-m.x), y:C.y+(C.y-m.y)});
|
||||
|
||||
api.setColor("red");
|
||||
api.drawLine(pts[1], pts[2]);
|
||||
api.drawLine({x: (pts[1].x + pts[2].x)/2, y: (pts[1].y + pts[2].y)/2}, C);
|
||||
m = {x: (pts[1].x + pts[2].x)/2, y: (pts[1].y + pts[2].y)/2};
|
||||
api.drawLine(m, {x:C.x+(C.x-m.x), y:C.y+(C.y-m.y)});
|
||||
|
||||
api.setColor("green");
|
||||
api.drawLine(pts[2], pts[0]);
|
||||
api.drawLine({x: (pts[2].x + pts[0].x)/2, y: (pts[2].y + pts[0].y)/2}, C);
|
||||
m = {x: (pts[2].x + pts[0].x)/2, y: (pts[2].y + pts[0].y)/2};
|
||||
api.drawLine(m, {x:C.x+(C.x-m.x), y:C.y+(C.y-m.y)});
|
||||
|
||||
api.setColor("grey");
|
||||
api.drawCircle(C, api.utils.dist(C,pts[0]));
|
||||
// center
|
||||
api.setColor("black");
|
||||
api.drawPoint(C);
|
||||
api.setFill("black");
|
||||
api.text("Intersection point", C, {x:-25, y:10});
|
||||
},
|
||||
|
||||
drawSingleArc: function(api, curve) {
|
||||
@@ -133,7 +145,7 @@ var Introduction = React.createClass({
|
||||
|
||||
var a = arcs[0];
|
||||
api.setColor("red");
|
||||
api.setFill("rgba(200,0,0,0.4)");
|
||||
api.setFill("rgba(255,0,0,0.2)");
|
||||
api.debug = true;
|
||||
api.drawArc(a);
|
||||
|
||||
@@ -161,10 +173,12 @@ var Introduction = React.createClass({
|
||||
<section>
|
||||
<SectionHeader {...this.props} />
|
||||
|
||||
<p>Let's look at converting Bézier curves into sequences of circular arcs. We already saw in the
|
||||
section on circle approximation that this will never yield a perfect equivalent, but sometimes
|
||||
you need circular arcs, such as when you're working with fabrication machinery, or simple vector
|
||||
languages that understand lines and circles, but not much else.</p>
|
||||
<p>Let's look at doing the exact opposite of the previous section: rather than approximating
|
||||
circular arc using Bézier curves, let's approximate Bézier curves using circular arcs.</p>
|
||||
|
||||
<p>We already saw in the section on circle approximation that this will never yield a perfect
|
||||
equivalent, but sometimes you need circular arcs, such as when you're working with fabrication
|
||||
machinery, or simple vector languages that understand lines and circles, but not much else.</p>
|
||||
|
||||
<p>The approach is fairly simple: pick a starting point on the curve, and pick two points that are
|
||||
further along the curve. Determine the circle that goes through those three points, and see if
|
||||
|
@@ -21,10 +21,11 @@ var BoundingBox = React.createClass({
|
||||
|
||||
draw: function(api, curve) {
|
||||
api.reset();
|
||||
api.drawSkeleton(curve);
|
||||
api.drawCurve(curve);
|
||||
api.setColor("#00FF00");
|
||||
api.drawbbox(curve.bbox());
|
||||
api.setColor("black");
|
||||
api.drawSkeleton(curve);
|
||||
api.drawCurve(curve);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
@@ -187,25 +187,14 @@ var Circles = React.createClass({
|
||||
number of ranges for the angle φ, such as a half circle, quarter circle and eighth circle?</p>
|
||||
|
||||
<table><tbody><tr><td>
|
||||
<p>
|
||||
<a href="http://www.wolframalpha.com/input/?i=plot+sqrt%28%281%2F4+*+%28sin%28x%29+%2B+2tan%28x%2F2%29%29+-+sin%28x%2F2%29%29%5E2+%2B+%282sin%5E4%28x%2F4%29%29%5E2%29+for+0+%3C%3D+x+%3C%3D+pi">
|
||||
<img src="images/arc-q-pi.gif"/>
|
||||
</a>
|
||||
</p>
|
||||
<p><img src="images/arc-q-pi.gif"/></p>
|
||||
<p>plotted for 0 ≤ φ ≤ π:</p>
|
||||
</td><td>
|
||||
<p>
|
||||
<a href="http://www.wolframalpha.com/input/?i=plot+sqrt%28%281%2F4+*+%28sin%28x%29+%2B+2tan%28x%2F2%29%29+-+sin%28x%2F2%29%29%5E2+%2B+%282sin%5E4%28x%2F4%29%29%5E2%29+for+0+%3C%3D+x+%3C%3D+pi%2F2">
|
||||
<img src="images/arc-q-pi2.gif"/>
|
||||
</a>
|
||||
</p>
|
||||
<p><img src="images/arc-q-pi2.gif"/></p>
|
||||
<p>plotted for 0 ≤ φ ≤ ½π:</p>
|
||||
</td><td>
|
||||
<p>
|
||||
<a href="http://www.wolframalpha.com/input/?i=plot+sqrt%28%281%2F4+*+%28sin%28x%29+%2B+2tan%28x%2F2%29%29+-+sin%28x%2F2%29%29%5E2+%2B+%282sin%5E4%28x%2F4%29%29%5E2%29+for+0+%3C%3D+x+%3C%3D+pi%2F4">
|
||||
<img src="images/arc-q-pi4.gif"/>
|
||||
</a>
|
||||
</p>
|
||||
{ this.props.showhref ? "http://www.wolframalpha.com/input/?i=plot+sqrt%28%281%2F4+*+%28sin%28x%29+%2B+2tan%28x%2F2%29%29+-+sin%28x%2F2%29%29%5E2+%2B+%282sin%5E4%28x%2F4%29%29%5E2%29+for+0+%3C%3D+x+%3C%3D+pi%2F4" : null }
|
||||
<p><img src="images/arc-q-pi4.gif"/></p>
|
||||
<p>plotted for 0 ≤ φ ≤ ¼π:</p>
|
||||
</td></tr></tbody></table>
|
||||
|
||||
|
@@ -140,29 +140,32 @@ var CirclesCubic = React.createClass({
|
||||
drawCircle: function(api) {
|
||||
api.setSize(325,325);
|
||||
api.reset();
|
||||
|
||||
var w = api.getPanelWidth(),
|
||||
h = api.getPanelHeight(),
|
||||
pad = 60,
|
||||
r = w/2 - pad,
|
||||
k = 0.55228,
|
||||
offset = {x: -pad/2, y:0};
|
||||
offset = {x: -pad/2, y:-pad/4};
|
||||
|
||||
var curve = new api.Bezier([
|
||||
{x:w/2 + r, y:h/2},
|
||||
{x:w/2 + r, y:h/2 + k*r},
|
||||
{x:w/2 + k*r, y:h/2 + r},
|
||||
{x:w/2, y:h/2 + r}
|
||||
]);
|
||||
|
||||
api.setColor("lightgrey");
|
||||
api.drawLine({x:0,y:h/2}, {x:w+pad,y:h/2}, offset);
|
||||
api.drawLine({x:w/2,y:0}, {x:w/2,y:h}, offset);
|
||||
api.drawLine({x:w/2,y:0}, {x:w/2,y:h+pad}, offset);
|
||||
|
||||
var pts = curve.points;
|
||||
|
||||
api.setColor("red");
|
||||
api.drawCircle(pts[0], 3, offset);
|
||||
api.drawCircle(pts[1], 3, offset);
|
||||
api.drawCircle(pts[2], 3, offset);
|
||||
api.drawCircle(pts[3], 3, offset);
|
||||
api.drawPoint(pts[0], offset);
|
||||
api.drawPoint(pts[1], offset);
|
||||
api.drawPoint(pts[2], offset);
|
||||
api.drawPoint(pts[3], offset);
|
||||
api.drawCurve(curve, offset);
|
||||
api.setColor("rgb(255,160,160)");
|
||||
api.drawLine(pts[0],pts[1],offset);
|
||||
@@ -175,23 +178,33 @@ var CirclesCubic = React.createClass({
|
||||
api.text((pts[2].x - w/2) + "," + (pts[2].y - h/2), {x: pts[2].x + 7, y: pts[2].y + 7}, offset);
|
||||
api.text((pts[3].x - w/2) + "," + (pts[3].y - h/2), {x: pts[3].x, y: pts[3].y + 13}, offset);
|
||||
|
||||
pts.forEach(p => {
|
||||
p.x = -(p.x - w);
|
||||
});
|
||||
pts.forEach(p => { p.x = -(p.x - w); });
|
||||
api.setColor("blue");
|
||||
api.drawCurve(curve, offset);
|
||||
api.drawLine(pts[2],pts[3],offset);
|
||||
api.drawPoint(pts[2],offset);
|
||||
api.setFill("blue");
|
||||
api.text("reflected", {x: pts[2].x - pad/2, y: pts[2].y + 13}, offset);
|
||||
api.setColor("rgb(200,200,255)");
|
||||
api.drawLine(pts[1],pts[0],offset);
|
||||
api.drawPoint(pts[1],offset);
|
||||
|
||||
pts.forEach(p => {
|
||||
p.y = -(p.y - h);
|
||||
});
|
||||
pts.forEach(p => { p.y = -(p.y - h); });
|
||||
api.setColor("green");
|
||||
api.drawCurve(curve, offset);
|
||||
|
||||
pts.forEach(p => {
|
||||
p.x = -(p.x - w);
|
||||
});
|
||||
pts.forEach(p => { p.x = -(p.x - w); });
|
||||
api.setColor("purple");
|
||||
api.drawCurve(curve, offset);
|
||||
api.drawLine(pts[1],pts[0],offset);
|
||||
api.drawPoint(pts[1],offset);
|
||||
api.setFill("purple");
|
||||
api.text("reflected", {x: pts[1].x + 10, y: pts[1].y + 3}, offset);
|
||||
api.setColor("rgb(200,200,255)");
|
||||
api.drawLine(pts[2],pts[3],offset);
|
||||
api.drawPoint(pts[2],offset);
|
||||
|
||||
|
||||
|
||||
api.setColor("black");
|
||||
api.setFill("black");
|
||||
|
@@ -122,7 +122,11 @@ var Extremities = React.createClass({
|
||||
|
||||
<h3>Quartic curves: Cardano's algorithm.</h3>
|
||||
|
||||
<p>Quartic—fourth degree—curves have a cubic function as derivative. Now, cubic functions are a bit of a problem because they're really hard to solve. But, way back in the 16<sup>th</sup> century, <a href="https://en.wikipedia.org/wiki/Gerolamo_Cardano">Gerolamo Cardano</a> figured out that even if the general cubic function is really hard to solve, it can be rewritten to a form for which finding the roots is "easy", and then the only hard part is figuring out how to go from that form to the generic form. So:</p>
|
||||
<p>Quartic—fourth degree—curves have a cubic function as derivative. Now, cubic functions are a bit of a problem because
|
||||
they're really hard to solve. But, way back in the 16<sup>th</sup> century, <a href="https://en.wikipedia.org/wiki/Gerolamo_Cardano">Gerolamo
|
||||
Cardano</a> figured out that even if the general cubic function is really hard to solve, it can be rewritten to a form
|
||||
for which finding the roots is "easy", and then the only hard part is figuring out how to go from that form to the
|
||||
generic form. So:</p>
|
||||
|
||||
<p>\[
|
||||
very\ hard:\ solve\ at^3 + bt^2 + ct + d = 0\\
|
||||
@@ -131,21 +135,33 @@ var Extremities = React.createClass({
|
||||
|
||||
<p>This is easier because for the "easier formula" we can use <a href="http://www.wolframalpha.com/input/?i=t^3+%2B+pt+%2B+q">regular calculus</a> to find the roots (as a cubic function, however, it can have up to three roots, but two of those can be complex. For the purpose of Bézier curve extremities, we can completely ignore those complex roots, since our <em>t</em> is a plain real number from 0 to 1).</p>
|
||||
|
||||
<p>So, the trick is to figure out how to turn the first formula into the second formula, and to then work out the maths that gives us the roots. This is explained in detail over at <a href="http://www.trans4mind.com/personal_development/mathematics/polynomials/cubicAlgebra.htm">Ken J. Ward's page</a> for solving the cubic equation, so instead of showing the maths, I'm simply going to show the programming code for solving the cubic equation, with the complex roots getting totally ignored.</p>
|
||||
<p>So, the trick is to figure out how to turn the first formula into the second formula, and to then work out the maths that gives us
|
||||
the roots. This is explained in detail over at <a href="http://www.trans4mind.com/personal_development/mathematics/polynomials/cubicAlgebra.htm">Ken
|
||||
J. Ward's page</a> for solving the cubic equation, so instead of showing the maths, I'm simply going to show the programming code for
|
||||
solving the cubic equation, with the complex roots getting totally ignored.</p>
|
||||
|
||||
<div className="note"><pre>
|
||||
// A helper function to filter for values in the [0,1] interval:
|
||||
|
||||
<div className="howtocode">
|
||||
<h3>Implementing Cardano's algorithm for finding all real roots</h3>
|
||||
|
||||
<p>The "real roots" part is fairly important, because while you cannot take a square, cube, etc. root of a
|
||||
negative number in the "real" number space (denoted with ℝ), this is perfectly fine in the <a
|
||||
href="https://en.wikipedia.org/wiki/Complex_number">"complex" number</a> space (denoted with ℂ).
|
||||
And, as it so happens, Cardano is also attributed as the first mathematician in history to have
|
||||
made use of complex numbers in his calculations. For this very algorithm!</p>
|
||||
|
||||
<pre>// A helper function to filter for values in the [0,1] interval:
|
||||
function accept(t) {
|
||||
return 0<=t && t <=1;
|
||||
}
|
||||
|
||||
// A special cuberoot function, which we can use because we don't care about complex roots:
|
||||
// A real-cuberoots-only function:
|
||||
function crt(v) {
|
||||
if(v<0) return -Math.pow(-v,1/3);
|
||||
return Math.pow(v,1/3);
|
||||
}
|
||||
|
||||
// Now then: given cubic coordinates pa, pb, pc, pd, find all roots.
|
||||
// Now then: given cubic coordinates {pa, pb, pc, pd} find all roots.
|
||||
function getCubicRoots(pa, pb, pc, pd) {
|
||||
var d = (-pa + 3*pb - 3*pc + pd),
|
||||
a = (3*pa - 6*pb + 3*pc) / d,
|
||||
@@ -193,7 +209,8 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
root1 = u1 - v1 - a/3;
|
||||
return [root1].filter(accept);
|
||||
}
|
||||
}</pre></div>
|
||||
}</pre>
|
||||
</div>
|
||||
|
||||
<p>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 reduce 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.</p>
|
||||
|
||||
@@ -206,8 +223,9 @@ function getCubicRoots(pa, pb, pc, pd) {
|
||||
|
||||
<p>That's a fancy word for saying "rather than solve the function, treat the problem as a sequence of identical
|
||||
operations, the performing of which gets us closer and closer to the real answer". As it turns out, there is a
|
||||
really nice numerical root finding algorithm, called the <a href="http://en.wikipedia.org/wiki/Newton-Raphson">Newton-Raphson</a>
|
||||
root finding method (yes, after <strong>that</strong> Newton), which we can make use of.</p>
|
||||
really nice numerical root finding algorithm, called the <a href="http://en.wikipedia.org/wiki/Newton-Raphson">Newton-Raphson</a> root
|
||||
finding method (yes, after <em><a href="https://en.wikipedia.org/wiki/Isaac_Newton">that</a></em> Newton),
|
||||
which we can make use of.</p>
|
||||
|
||||
<p>The Newton-Raphson approach consists of picking a value <i>t</i> (any will do), and getting the corresponding
|
||||
value at that <i>t</i> value. For normal functions, we can treat that value as a height. If the height is zero,
|
||||
|
@@ -222,7 +222,7 @@ var Moulding = React.createClass({
|
||||
setup={this.setupQuadratic} draw={this.drawMould}
|
||||
onClick={this.placeMouldPoint} onMouseDown={this.markQB} onMouseDrag={this.dragQB} onMouseUp={this.saveCurve}/>
|
||||
|
||||
<p>Click-dragging a point on the curve shows what we're using to compute the new coordinates: while dragging you will
|
||||
<p><strong>Click-dragging the curve itself</strong> shows what we're using to compute the new coordinates: while dragging you will
|
||||
see the original points B and its corresponding <i>t</i>-value, the original point C for that <i>t</i>-value,
|
||||
as well as the new point B' based on the mouse cursor. Since we know the <i>t</i>-value for this configuration,
|
||||
we can compute the ABC ratio for this configuration, and we know that our new point A' should like at a distance:</p>
|
||||
|
@@ -43,28 +43,28 @@ var Offsetting = React.createClass({
|
||||
reduced.forEach(c => {
|
||||
api.setRandomColor();
|
||||
api.drawCurve(c);
|
||||
api.drawCircle(c.points[0], 3);
|
||||
api.drawCircle(c.points[0], 1);
|
||||
});
|
||||
var last = reduced.slice(-1)[0];
|
||||
api.drawCircle(last.points[3] || last.points[2],3);
|
||||
api.drawPoint(last.points[3] || last.points[2]);
|
||||
|
||||
api.setColor("red");
|
||||
var offset = curve.offset(api.distance);
|
||||
offset.forEach(c => {
|
||||
api.drawCircle(c.points[0],1);
|
||||
api.drawPoint(c.points[0]);
|
||||
api.drawCurve(c);
|
||||
});
|
||||
last = offset.slice(-1)[0];
|
||||
api.drawCircle(last.points[3] || last.points[2],1);
|
||||
api.drawPoint(last.points[3] || last.points[2]);
|
||||
|
||||
api.setColor("blue");
|
||||
offset = curve.offset(-api.distance);
|
||||
offset.forEach(c => {
|
||||
api.drawCircle(c.points[0],1);
|
||||
api.drawPoint(c.points[0]);
|
||||
api.drawCurve(c);
|
||||
});
|
||||
last = offset.slice(-1)[0];
|
||||
api.drawCircle(last.points[3] || last.points[2],1);
|
||||
api.drawPoint(last.points[3] || last.points[2]);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
@@ -82,7 +82,7 @@ var PointCurves = React.createClass({
|
||||
api.drawLine(A, S);
|
||||
api.drawLine(A, E);
|
||||
api.setColor("black");
|
||||
api.drawCircle(A, 3);
|
||||
api.drawCircle(A, 1);
|
||||
api.drawCurve(curve);
|
||||
}
|
||||
},
|
||||
@@ -114,7 +114,7 @@ var PointCurves = React.createClass({
|
||||
api.setColor("blue");
|
||||
api.drawLine(S, E);
|
||||
api.drawLine(B, C);
|
||||
api.drawCircle(C, 3);
|
||||
api.drawCircle(C, 1);
|
||||
|
||||
var ratio = this.getCRatio(0.5),
|
||||
A = {
|
||||
@@ -165,9 +165,9 @@ var PointCurves = React.createClass({
|
||||
api.drawLine(E, nc2);
|
||||
api.drawLine(nc1, nc2);
|
||||
api.setColor("black");
|
||||
api.drawCircle(A, 3);
|
||||
api.drawCircle(nc1, 3);
|
||||
api.drawCircle(nc2, 3);
|
||||
api.drawCircle(A, 1);
|
||||
api.drawCircle(nc1, 1);
|
||||
api.drawCircle(nc2, 1);
|
||||
api.drawCurve(curve);
|
||||
}
|
||||
},
|
||||
|
@@ -58,9 +58,14 @@ var PolyBezier = React.createClass({
|
||||
fixed = api.lpts[fixed % api.lpts.length];
|
||||
toMove = i + 2*p;
|
||||
toMove = api.lpts[toMove % api.lpts.length];
|
||||
|
||||
toMove.x = fixed.x + (fixed.x - anchor.x);
|
||||
toMove.y = fixed.y + (fixed.y - anchor.y);
|
||||
}
|
||||
// then, the furthest point cannot be computed properly!
|
||||
toMove = i + 6;
|
||||
toMove = api.lpts[toMove % api.lpts.length];
|
||||
api.problem = toMove;
|
||||
},
|
||||
|
||||
movePointsCubicLD: function(api, i) {
|
||||
@@ -300,8 +305,11 @@ var PolyBezier = React.createClass({
|
||||
onMouseMove={this.linkDerivatives}/>
|
||||
|
||||
<p>As you can see, quadratic curves are particularly ill-suited for poly-Bézier curves, as all
|
||||
the control points are effectively linked. Move one of them, and you move all of them. This means
|
||||
that we cannot use quadratic poly-Béziers for anything other than really, really simple shapes.
|
||||
the control points are effectively linked. Move one of them, and you move all of them. Not only that,
|
||||
but if we move the on-curve points, it's possible to get a situation where a control point's positions
|
||||
is different depending on whether it's the reflection of its left or right neighbouring control
|
||||
point: we can't even form a proper rule-conforming curve! This means that we cannot use quadratic
|
||||
poly-Béziers for anything other than really, really simple shapes.
|
||||
And even then, they're probably the wrong choice. Cubic curves are pretty decent, but the fact
|
||||
that the derivatives are linked means we can't manipulate curves as well as we might if we
|
||||
relaxed the constraints a little.</p>
|
||||
@@ -317,10 +325,9 @@ var PolyBezier = React.createClass({
|
||||
<Graphic preset="poly" title="Loosely connected cubic poly-Bézier" setup={this.setupCubic} draw={this.draw} onMouseMove={this.linkDirection}/>
|
||||
|
||||
<p>Cubic curves are now better behaved when it comes to dragging control points around, but the
|
||||
quadratic poly-Bézier has a problem: in the example shape, moving one control points will move
|
||||
the control points around it properly, but they in turn define "the next" control point and they
|
||||
do so in incompatible ways! This is one of the many reasons why quadratic curves are not really
|
||||
useful to work with.</p>
|
||||
quadratic poly-Bézier still has the problem that moving one control points will move
|
||||
the control points and may ending up defining "the next" control point in a way that
|
||||
doesn't work. Quadratic curves really aren't very useful to work with...</p>
|
||||
|
||||
<p>Finally, we also want to make sure that moving the on-curve coordinates preserves the relative
|
||||
positions of the associated control points. With that, we get to the kind of curve control that you
|
||||
@@ -332,8 +339,8 @@ var PolyBezier = React.createClass({
|
||||
onMouseDown={this.bufferPoints} onMouseMove={this.modelCurve}/>
|
||||
|
||||
<p>Again, we see that cubic curves are now rather nice to work with, but quadratic curves have a
|
||||
serious problem: we can move an on-curve point in such a way that we can't compute what needs to
|
||||
"happen next". Move the top point down, below the left and right points, for instance. There
|
||||
new, very serious problem: we can move an on-curve point in such a way that we can't compute what
|
||||
needs to "happen next". Move the top point down, below the left and right points, for instance. There
|
||||
is no way to preserve correct control points without a kink at the bottom point. Quadratic curves:
|
||||
just not that good...</p>
|
||||
|
||||
|
@@ -52,7 +52,7 @@ var Preface = React.createClass({
|
||||
<p>—Pomax (or in the tweetworld, <a href="https://twitter.com/TheRealPomax">@TheRealPomax</a>)</p>
|
||||
|
||||
<div className="note">
|
||||
<h2>Note: All Bézier graphics are interactive.</h2>
|
||||
<h2>Note: virtuall 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.
|
||||
@@ -61,6 +61,16 @@ var Preface = React.createClass({
|
||||
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>This book is open source.</h2>
|
||||
|
||||
<p>This book is an open source software project, and lives on two github repositorites. The
|
||||
first is <a href="https://github.com/pomax/bezierinfo">https://github.com/pomax/bezierinfo</a> and
|
||||
is the purely-for-presentation version you are viewing right now. The other repository is
|
||||
<a href="https://github.com/pomax/BezierInfo-2">https://github.com/pomax/BezierInfo-2</a>, which
|
||||
is the development version, housing all the html, javascript, and css. You can fork either
|
||||
of these, and pretty much do with them as you please, except for passing it off as your
|
||||
own work wholesale, of course =)</p>
|
||||
|
||||
<h2>How complicated is the maths going to be?</h2>
|
||||
|
||||
<p>Most of the mathematics in this Primer are early high school maths. If you understand basic
|
||||
|
@@ -60,6 +60,7 @@ var Projections = React.createClass({
|
||||
|
||||
onMouseMove: function(evt, api) {
|
||||
api.mousePt = {x: evt.offsetX, y: evt.offsetY };
|
||||
api._lut = api.curve.getLUT();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
@@ -59,8 +59,6 @@ var TightBounds = React.createClass({
|
||||
|
||||
draw: function(api, curve) {
|
||||
api.reset();
|
||||
api.drawSkeleton(curve);
|
||||
api.drawCurve(curve);
|
||||
|
||||
var pts = curve.points;
|
||||
var line = {p1: pts[0], p2: pts[pts.length-1]};
|
||||
@@ -75,6 +73,10 @@ var TightBounds = React.createClass({
|
||||
api.drawLine(tpts[1], tpts[2]);
|
||||
api.drawLine(tpts[2], tpts[3]);
|
||||
api.drawLine(tpts[3], tpts[0]);
|
||||
|
||||
api.setColor("black");
|
||||
api.drawSkeleton(curve);
|
||||
api.drawCurve(curve);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
Reference in New Issue
Block a user