mirror of
https://github.com/Pomax/BezierInfo-2.git
synced 2025-08-29 02:59:58 +02:00
circle intersection
This commit is contained in:
96
docs/chapters/circleintersection/circle.js
Normal file
96
docs/chapters/circleintersection/circle.js
Normal file
@@ -0,0 +1,96 @@
|
||||
import refineBinary from "../projections/refine-binary.js";
|
||||
|
||||
let curve;
|
||||
|
||||
setup() {
|
||||
curve = Bezier.defaultCubic(this);
|
||||
setMovable(curve.points);
|
||||
setSlider(`.slide-control`, `radius`, 102);
|
||||
}
|
||||
|
||||
draw() {
|
||||
clear();
|
||||
curve.drawSkeleton(`lightblue`);
|
||||
curve.drawCurve();
|
||||
curve.drawPoints();
|
||||
|
||||
noFill();
|
||||
let x = this.width/2;
|
||||
let y = this.height/2;
|
||||
|
||||
// Find all the circle intersections for this curve:
|
||||
let LUT = curve.getLUT(100);
|
||||
let start = 0, count = 0;
|
||||
let values = [];
|
||||
|
||||
// never use while(true)
|
||||
while(++count < 25) {
|
||||
let i = start + this.findClosest(
|
||||
x, y, LUT.slice(start),
|
||||
// We also want the previous two distances, which either don't
|
||||
// exist because we're starting at 0, or they exist because they
|
||||
// were computed in the previous findClosest() call.
|
||||
LUT[start-2]?.distance,
|
||||
LUT[start-1]?.distance
|
||||
);
|
||||
if (i < start) break;
|
||||
if (i>0 && i === start) break;
|
||||
values.push(i);
|
||||
start = i + 2; // We need to add 2, because findClosest already tells us that i+1 cannot be a viable candidate.
|
||||
}
|
||||
|
||||
// Draw a convenience marker for our circle center
|
||||
setStroke(`black`);
|
||||
line(x-10,y,x+10,y);
|
||||
line(x,y-10,x,y+10);
|
||||
|
||||
// Then draw our circle, and all intersections
|
||||
setStroke(values.length ? `green` : `red`);
|
||||
circle(x, y, this.radius);
|
||||
values.forEach(i => this.drawProjection(x, y, LUT, i));
|
||||
}
|
||||
|
||||
// We want to find the "locally closest" points, rather than
|
||||
// the globally closest point, so we don't run a blind .forEach
|
||||
// as in the projection graphic, but instead find a value of i
|
||||
// such that the distance for [i-1] and [i+1] are both bigger
|
||||
// than for [i], signalling a local minimum.
|
||||
findClosest(x, y, LUT, pd2, pd1, distanceEpsilon = 5) {
|
||||
let distance = Number.MAX_SAFE_INTEGER,
|
||||
prevDistance2 = pd2 || distance,
|
||||
prevDistance1 = pd1 || distance,
|
||||
i = -1;
|
||||
|
||||
for(let index=0, e=LUT.length; index<e; index++) {
|
||||
let p = LUT[index];
|
||||
p.distance = abs(dist(x, y, p.x, p.y) - this.radius);
|
||||
|
||||
// Realistically, there's only going to be an intersection if
|
||||
// the distance to the circle center is already approximately
|
||||
// the circle's radius.
|
||||
if (prevDistance1 < distanceEpsilon && prevDistance2 > prevDistance1 && prevDistance1 < p.distance) {
|
||||
i = index - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (p.distance < distance) {
|
||||
distance = p.distance;
|
||||
}
|
||||
|
||||
prevDistance2 = prevDistance1;
|
||||
prevDistance1 = p.distance;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
drawProjection(x, y, LUT, i) {
|
||||
let B = refineBinary(curve, x, y, LUT, i, this.radius);
|
||||
setColor(`rgba(100,100,255)`);
|
||||
circle(B.x, B.y, 3);
|
||||
line(B.x, B.y, x, y);
|
||||
}
|
||||
|
||||
onMouseMove() {
|
||||
redraw();
|
||||
}
|
Reference in New Issue
Block a user