mirror of
https://github.com/Pomax/BezierInfo-2.git
synced 2025-09-03 05:12:43 +02:00
bsplines
This commit is contained in:
101
docs/chapters/arcapproximation/arc.js
Normal file
101
docs/chapters/arcapproximation/arc.js
Normal file
@@ -0,0 +1,101 @@
|
||||
// setup={this.setupCubic} draw={this.drawSingleArc} onKeyDown={this.props.onKeyDown}
|
||||
|
||||
let curve, utils = Bezier.getUtils();
|
||||
|
||||
setup() {
|
||||
curve = Bezier.defaultCubic(this);
|
||||
setMovable(curve.points);
|
||||
setSlider(`.slide-control`, `error`, 0.5);
|
||||
}
|
||||
|
||||
draw() {
|
||||
clear();
|
||||
|
||||
curve.drawSkeleton();
|
||||
curve.drawCurve();
|
||||
|
||||
setColor(`#FF000040`);
|
||||
let a = this.getArc(curve);
|
||||
arc(
|
||||
a.x, a.y, a.r, a.s, a.e,
|
||||
// draw a wedge, not just the arc
|
||||
a.x, a.y
|
||||
);
|
||||
|
||||
setColor("black");
|
||||
text(`Arc approximation with total error ${this.error}`, this.width/2, 15, CENTER);
|
||||
curve.drawPoints();
|
||||
}
|
||||
|
||||
getArc(curve) {
|
||||
let ts = 0,
|
||||
te = 1,
|
||||
tm = te,
|
||||
safety = 0,
|
||||
np1 = curve.get(ts), np2, np3,
|
||||
arc,
|
||||
currGood = false,
|
||||
prevGood = false,
|
||||
done,
|
||||
prev_e = 1,
|
||||
step = 0;
|
||||
|
||||
// Find where the good/bad boundary is
|
||||
te = 1;
|
||||
|
||||
// step 2: find the best possible arc
|
||||
do {
|
||||
prevGood = currGood;
|
||||
tm = (ts + te) / 2;
|
||||
step++;
|
||||
|
||||
np2 = curve.get(tm);
|
||||
np3 = curve.get(te);
|
||||
|
||||
arc = utils.getccenter(np1, np2, np3);
|
||||
arc.interval = { start: ts, end: te, };
|
||||
|
||||
let error = this.computeError(arc, np1, ts, te);
|
||||
currGood = (error <= this.error);
|
||||
|
||||
done = prevGood && !currGood;
|
||||
if (!done) prev_e = te;
|
||||
|
||||
// this arc is fine: try a wider arc
|
||||
if (currGood) {
|
||||
// if e is already at max, then we're done for this arc.
|
||||
if (te >= 1) {
|
||||
// make sure we cap at t=1
|
||||
arc.interval.end = prev_e = 1;
|
||||
// if we capped the arc segment to t=1 we also need to make sure that
|
||||
// the arc's end angle is correct with respect to the bezier end point.
|
||||
if (te > 1) {
|
||||
let d = {
|
||||
x: arc.x + arc.r * cos(arc.e),
|
||||
y: arc.y + arc.r * sin(arc.e),
|
||||
};
|
||||
arc.e += utils.angle({ x: arc.x, y: arc.y }, d, curve.points[3]);
|
||||
}
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
// if not, move it up by half the iteration distance
|
||||
te = te + (te - ts) / 2;
|
||||
}
|
||||
|
||||
// This is a bad arc: we need to move 'e' down to find a good arc
|
||||
else { te = tm; }
|
||||
} while (!done && safety++ < 100);
|
||||
|
||||
return arc;
|
||||
}
|
||||
|
||||
computeError(pc, np1, s, e) {
|
||||
const q = (e - s) / 4,
|
||||
c1 = curve.get(s + q),
|
||||
c2 = curve.get(e - q),
|
||||
ref = dist(pc.x, pc.y, np1.x, np1.y),
|
||||
d1 = dist(pc.x, pc.y, c1.x, c1.y),
|
||||
d2 = dist(pc.x, pc.y, c2.x, c2.y);
|
||||
return abs(d1 - ref) + abs(d2 - ref);
|
||||
}
|
Reference in New Issue
Block a user