1
0
mirror of https://github.com/Pomax/BezierInfo-2.git synced 2025-09-01 04:22:28 +02:00

two sections left

This commit is contained in:
Pomax
2016-01-09 18:39:09 -08:00
parent 2ee641554c
commit 9ede7b4143
47 changed files with 6520 additions and 794 deletions

View File

@@ -0,0 +1,102 @@
var React = require("react");
var Graphic = require("../../Graphic.jsx");
var SectionHeader = require("../../SectionHeader.jsx");
var Projections = React.createClass({
getDefaultProps: function() {
return {
title: "Projecting a point onto a Bézier curve"
};
},
setup: function(api) {
api.setSize(320,320);
var curve = new api.Bezier([
{x:248,y:188},
{x:218,y:294},
{x:45,y:290},
{x:12,y:236},
{x:14,y:82},
{x:186,y:177},
{x:221,y:90},
{x:18,y:156},
{x:34,y:57},
{x:198,y:18}
]);
api.setCurve(curve);
api._lut = curve.getLUT();
},
findClosest: function(LUT, p, dist) {
var i,
end = LUT.length,
d,
dd = dist(LUT[0],p),
f = 0;
for(i=1; i<end; i++) {
d = dist(LUT[i],p);
if(d<dd) {f = i;dd = d;}
}
return f/(end-1);
},
draw: function(api, curve) {
api.reset();
api.drawSkeleton(curve);
api.drawCurve(curve);
if (api.mousePt) {
api.setColor("red");
api.drawCircle(api.mousePt, 3);
// naive t value
var t = this.findClosest(api._lut, api.mousePt, api.utils.dist);
// no real point in refining for illustration purposes
var p = curve.get(t);
api.drawLine(p, api.mousePt);
api.drawCircle(p, 3);
}
},
onMouseMove: function(evt, api) {
api.mousePt = {x: evt.offsetX, y: evt.offsetY };
},
render: function() {
return (
<section>
<SectionHeader {...this.props} />
<p>Say we have a Bézier curve and some point, not on the curve, of which we want to know
which <i>t</i> value on the curve gives us an on-curve point closest to our off-curve point.
Or: say we want to find the projection of a random point onto a curve. How do we do that?</p>
<p>If the Bézier curve is of low enough order, we might be able
to <a href="http://jazzros.blogspot.ca/2011/03/projecting-point-on-bezier-curve.html">work out
the maths for how to do this</a>, and get a perfect <i>t</i> value back, but in general this is
an incredibly hard problem and the easiest solution is, really, a numerical approach again. We'll
be finding our ideal <i>t</i> value using a <a href="https://en.wikipedia.org/wiki/Binary_search_algorithm">binary
search</a>. First, we do a coarse distance-check based on <i>t</i> values associated with the
curve's "to draw" coordinates (using a lookup table, or LUT). This is pretty fast. Then we run
this algorithm:</p>
<ol>
<li>with the <i>t</i> value we found, start with some small interval around <i>t</i> (1/length_of_LUT on either side is a reasonable start),</li>
<li>if the distance to <i>t ± interval/2</i> is larger than the distance to <i>t</i>, try again with the interval reduced to half its original length.</li>
<li>if the distance to <i>t ± interval/2</i> is smaller than the distance to <i>t</i>, replace <i>t</i> with the smaller-distance value.</li>
<li>after reducing the interval, or changing <i>t</i>, go back to step 1.</li>
</ol>
<p>We keep repeating this process until the interval is small enough to claim the difference
in precision found is irrelevant for the purpose we're trying to find <i>t</i> for. In this
case, I'm arbitrarily fixing it at 0.0001.</p>
<p>The following graphic demonstrates the result of this procedure.Simply move the cursor
around, and if it does not lie on top of the curve, you will see a line that projects the
cursor onto the curve based on an iteratively found "ideal" <i>t</i> value.</p>
<Graphic preset="simple" title="Projecting a point onto a Bézier curve" setup={this.setup} draw={this.draw} onMouseMove={this.onMouseMove}/>
</section>
);
}
});
module.exports = Projections;