mirror of
https://github.com/Pomax/BezierInfo-2.git
synced 2025-08-26 09:44:32 +02:00
tweaks to arc approx, offsetting, and tangents
This commit is contained in:
@@ -24,6 +24,23 @@ var Introduction = React.createClass({
|
||||
setupCubic: function(api) {
|
||||
var curve = api.getDefaultCubic();
|
||||
api.setCurve(curve);
|
||||
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) {
|
||||
@@ -111,7 +128,7 @@ var Introduction = React.createClass({
|
||||
|
||||
drawSingleArc: function(api, curve) {
|
||||
api.reset();
|
||||
var arcs = curve.arcs(0.5);
|
||||
var arcs = curve.arcs(api.error);
|
||||
api.drawSkeleton(curve);
|
||||
api.drawCurve(curve);
|
||||
|
||||
@@ -120,11 +137,14 @@ var Introduction = React.createClass({
|
||||
api.setFill("rgba(200,0,0,0.4)");
|
||||
api.debug = true;
|
||||
api.drawArc(a);
|
||||
|
||||
api.setFill("black");
|
||||
api.text("Arc approximation with total error " + api.utils.round(api.error,1), {x:10, y:15});
|
||||
},
|
||||
|
||||
drawArcs: function(api, curve) {
|
||||
api.reset();
|
||||
var arcs = curve.arcs(0.5);
|
||||
var arcs = curve.arcs(api.error);
|
||||
api.drawSkeleton(curve);
|
||||
api.drawCurve(curve);
|
||||
arcs.forEach(a => {
|
||||
@@ -132,6 +152,9 @@ var Introduction = React.createClass({
|
||||
api.setFill(api.getColor());
|
||||
api.drawArc(a);
|
||||
});
|
||||
|
||||
api.setFill("black");
|
||||
api.text("Arc approximation with total error " + api.utils.round(api.error,1) + " per arc segment", {x:10, y:15});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
@@ -210,11 +233,11 @@ var Introduction = React.createClass({
|
||||
|
||||
<p>The following graphic shows the result of this approach, with a default error threshold of 0.5, meaning that
|
||||
if an arc is off by a <em>combined</em> half pixel over both verification points, then we treat the arc as bad.
|
||||
This is an extremely simple error policy, but already works really well. Note that the graphic is still interactive,
|
||||
and you can use your '+' and '-' keys to increase to decrease the error threshold, to see what the effect
|
||||
of a smaller or larger error threshold is.</p>
|
||||
This is an extremely simple error policy, but already works really well. Note that the graphic is still
|
||||
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} />
|
||||
<Graphic preset="simple" title="Arc approximation of a Bézier curve" setup={this.setupCubic} draw={this.drawSingleArc} onKeyDown={this.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
|
||||
@@ -223,7 +246,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} />
|
||||
<Graphic preset="simple" title="Arc approximation of a Bézier curve" setup={this.setupCubic} draw={this.drawArcs} onKeyDown={this.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
|
||||
|
@@ -27,15 +27,33 @@ var Offsetting = React.createClass({
|
||||
draw: function(api, curve) {
|
||||
api.reset();
|
||||
api.drawSkeleton(curve);
|
||||
api.drawCurve(curve);
|
||||
|
||||
var reduced = curve.reduce();
|
||||
reduced.forEach(c => {
|
||||
api.setRandomColor();
|
||||
api.drawCurve(c);
|
||||
api.drawCircle(c.points[0], 3);
|
||||
});
|
||||
var last = reduced.slice(-1)[0];
|
||||
api.drawCircle(last.points[3] || last.points[2],3);
|
||||
|
||||
api.setColor("red");
|
||||
var offset = curve.offset(api.distance);
|
||||
offset.forEach(c => api.drawCurve(c));
|
||||
offset.forEach(c => {
|
||||
api.drawCircle(c.points[0],1);
|
||||
api.drawCurve(c)
|
||||
});
|
||||
last = offset.slice(-1)[0];
|
||||
api.drawCircle(last.points[3] || last.points[2],1);
|
||||
|
||||
api.setColor("blue");
|
||||
offset = curve.offset(-api.distance);
|
||||
offset.forEach(c => api.drawCurve(c));
|
||||
offset.forEach(c => {
|
||||
api.drawCircle(c.points[0],1);
|
||||
api.drawCurve(c)
|
||||
});
|
||||
last = offset.slice(-1)[0];
|
||||
api.drawCircle(last.points[3] || last.points[2],1);
|
||||
},
|
||||
|
||||
values: {
|
||||
@@ -153,8 +171,17 @@ var Offsetting = React.createClass({
|
||||
with respect to the curve's scaling origin (which is the intersection of the point normals at the start
|
||||
and end points).</p>
|
||||
|
||||
<p>A good way to do this reduction is to first find the curve's extreme points, as explained in the earlier
|
||||
section on curve extremities, and use these as initial splitting points. After this initial split, we can
|
||||
check each individual segment to see if it's "safe enough" based on where the center of the curve is. If the
|
||||
on-curve point for <i>t=0.5</i> is too far off from the center, we simply split the segment down the middle.
|
||||
Generally this is more than enough to end up with safe segments.</p>
|
||||
|
||||
<p>The following graphics show off curve offsetting, and you can use your up and down cursor keys to control
|
||||
the distance at which the curve gets offset:</p>
|
||||
the distance at which the curve gets offset. The curve first gets reduced to safe segments, each of which is
|
||||
then offset at the desired distance. Especially for simple curves, particularly easily set up for quadratic
|
||||
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} />
|
||||
|
@@ -22,16 +22,17 @@ var PointVectors = React.createClass({
|
||||
draw: function(api, curve) {
|
||||
api.reset();
|
||||
api.drawSkeleton(curve);
|
||||
api.drawCurve(curve);
|
||||
|
||||
var i,t,p,tg,n,td=0.25,nd=20;
|
||||
var i,t,p,tg,n,m,nd=20;
|
||||
for(i=0; i<=10; i++) {
|
||||
t = i/10.0;
|
||||
p = curve.get(t);
|
||||
tg = curve.derivative(t);
|
||||
m = Math.sqrt(tg.x*tg.x + tg.y*tg.y);
|
||||
tg = {x:tg.x/m, y:tg.y/m};
|
||||
n = curve.normal(t);
|
||||
api.setColor("blue");
|
||||
api.drawLine(p, {x:p.x+tg.x*td, y:p.y+tg.y*td});
|
||||
api.drawLine(p, {x:p.x+tg.x*nd, y:p.y+tg.y*nd});
|
||||
api.setColor("red");
|
||||
api.drawLine(p, {x:p.x+n.x*nd, y:p.y+n.y*nd});
|
||||
api.setColor("black");
|
||||
@@ -132,7 +133,8 @@ var PointVectors = React.createClass({
|
||||
</div>
|
||||
|
||||
<p>The following two graphics show the tangent and normal along a quadratic and cubic curve, with
|
||||
the direction vector coloured blue, and the normal vector coloured red.</p>
|
||||
the direction vector coloured blue, and the normal vector coloured red (the markers are spaced out
|
||||
evenly as <i>t</i>-intervals, not spaced equidistant).</p>
|
||||
|
||||
<div className="figure">
|
||||
<Graphic preset="simple" title="Quadratic Bézier tangents and normals" inline={true} setup={this.setupQuadratic} draw={this.draw}/>
|
||||
|
Reference in New Issue
Block a user