gpt4 book ai didi

javascript - 如何使用 p5.js 计算圆上直线的交点

转载 作者:行者123 更新时间:2023-11-29 17:34:47 31 4
gpt4 key购买 nike

我有一条线 (se),我知道它从圆圈内开始,并且知道在圆圈外结束。我正在尝试找到线与圆相交的点 l

Calculate intersection point of a line in a circle – setup

我正在使用 p5.js库并可以访问其所有 Vector 函数。

我的想法是,如果我能在线上与半径成直 Angular ,我就可以开始解决一些问题。

Calculate intersection point of a line in a circle – attempt

// Get the vector between s and c
let scVector = p5.Vector.sub(start, circleCenter);
// Get the angle between se and sc
let escAngle = this.v.angleBetween(scVector);
// Get the distance between t (where the right angle hits the center of the circle) and c
let tcDistance = Math.sin(escAngle) * scVector.mag();
// Get the distance between t and where the line intersects the circle
let tlDistance = Math.sqrt(Math.pow(hole.r, 2) - Math.pow(tcDistance, 2));
// Get the distance between the start point and t
let stDistance = Math.sqrt(Math.pow(scVector.mag(), 2) - Math.pow(tcDistance, 2));
// Add the two distances together, giving me the distance between s and l
let totalDistance = tcDistance + stDistance;
// Create a new Vector at this angle, at the totalDistance Magnitude, then add it to the current position
let point = p5.Vector.fromAngle(this.v.heading(), totalDistance).add(start);
// Mark a point (hopefully l) on the edge of the circle.
points.push({
x: point.x,
y: point.y,
fill: '#ffffff'
})

不幸的是,当我的物体穿过圆圈时,它们并没有在边缘留下点,而是远离圆圈的边缘。

enter image description here

小圆点是标记位置,彩色圆点是物体(有起点和终点)

我这里有一个演示,有问题的是从第 42 行开始: https://codepen.io/EightArmsHQ/pen/be0461014f9868e3462868776d9c8f1a

如有任何帮助,我们将不胜感激。

最佳答案

要找到点和线的交点,我建议使用现有算法,例如 WolframMathWorld - Circle-Line Intersection 中的算法。 .

算法很短,解释得很好,可以用一个简短的函数来表达。输入参数p1p2cpt的类型为p5.Vector , r 是一个标量。此参数定义了一条从 p1p2 的无限直线和一个圆心为 cpt 且半径为 r 的圆.该函数返回一个交叉点列表,可能为空:

intersectLineCircle = function(p1, p2, cpt, r) {

let sign = function(x) { return x < 0.0 ? -1 : 1; };

let x1 = p1.copy().sub(cpt);
let x2 = p2.copy().sub(cpt);

let dv = x2.copy().sub(x1)
let dr = dv.mag();
let D = x1.x*x2.y - x2.x*x1.y;

// evaluate if there is an intersection
let di = r*r*dr*dr - D*D;
if (di < 0.0)
return [];

let t = sqrt(di);

ip = [];
ip.push( new p5.Vector(D*dv.y + sign(dv.y)*dv.x * t, -D*dv.x + p.abs(dv.y) * t).div(dr*dr).add(cpt) );
if (di > 0.0) {
ip.push( new p5.Vector(D*dv.y - sign(dv.y)*dv.x * t, -D*dv.x - p.abs(dv.y) * t).div(dr*dr).add(cpt) );
}
return ip;
}

如果你想验证一个点是否在其他点的“中间”,你可以使用 Dot product .如果您知道一条直线上的 3 个点,那么计算这些点之间的距离就足够了,可以确定 1 个点是否在其他 2 个点之间。
p1p2px 的类型为 p5.Vector .这些点在同一条线上。该函数返回 true,如果 pxp1p2 之间,否则返回 false :

inBetween = function(p1, p2, px) {

let v = p2.copy().sub(p1);
let d = v.mag();
v = v.normalize();

let vx = px.copy().sub(p1);
let dx = v.dot(vx);

return dx >= 0 && dx <= d;
}

请参阅示例,我已实现该示例以测试该功能。圆由鼠标跟踪并与随机移动的线相交:

var sketch = function( p ) {

p.setup = function() {
let sketchCanvas = p.createCanvas(p.windowWidth, p.windowHeight);
sketchCanvas.parent('p5js_canvas')
}

let points = [];
let move = []

// Circle-Line Intersection
// http://mathworld.wolfram.com/Circle-LineIntersection.html
p.intersectLineCircle = function(p1, p2, cpt, r) {

let sign = function(x) { return x < 0.0 ? -1 : 1; };

let x1 = p1.copy().sub(cpt);
let x2 = p2.copy().sub(cpt);

let dv = x2.copy().sub(x1)
let dr = dv.mag();
let D = x1.x*x2.y - x2.x*x1.y;

// evaluate if there is an intersection
let di = r*r*dr*dr - D*D;
if (di < 0.0)
return [];

let t = p.sqrt(di);

ip = [];
ip.push( new p5.Vector(D*dv.y + sign(dv.y)*dv.x * t, -D*dv.x + p.abs(dv.y) * t).div(dr*dr).add(cpt) );
if (di > 0.0) {
ip.push( new p5.Vector(D*dv.y - sign(dv.y)*dv.x * t, -D*dv.x - p.abs(dv.y) * t).div(dr*dr).add(cpt) );
}
return ip;
}

p.inBetween = function(p1, p2, px) {

let v = p2.copy().sub(p1);
let d = v.mag();
v = v.normalize();

let vx = px.copy().sub(p1);
let dx = v.dot(vx);

return dx >= 0 && dx <= d;
}

p.endlessLine = function(x1, y1, x2, y2) {

p1 = new p5.Vector(x1, y1);
p2 = new p5.Vector(x2, y2);

let dia_len = new p5.Vector(p.windowWidth, p.windowHeight).mag();
let dir_v = p5.Vector.sub(p2, p1).setMag(dia_len);
let lp1 = p5.Vector.add(p1, dir_v);
let lp2 = p5.Vector.sub(p1, dir_v);

p.line(lp1.x, lp1.y, lp2.x, lp2.y);
}

p.draw = function() {

if (points.length == 0) {

points = [];
move = [];
for (let i=0; i < 2; ++i ) {
points.push( new p5.Vector(p.random(p.windowWidth-20)+10, p.random(p.windowHeight-20)+10));
move.push( new p5.Vector(p.random(2)-1, p.random(2)-1) );
}
points.push( new p5.Vector(p.mouseX, p.mouseY));
}
else
{
for (let i=0; i < 2; ++i ) {
points[i] = points[i].add(move[i]);
if (points[i].x < 10 || points[i].x > p.windowWidth-10)
move[i].x *= -1;
if (points[i].y < 10 || points[i].y > p.windowHeight-10)
move[i].y *= -1;
move[i].x = Math.max(-1, Math.min(1, move[i].x+p.random(0.2)-0.1))
move[i].y = Math.max(-1, Math.min(1, move[i].y+p.random(0.2)-0.1))
}
points[2].x = p.mouseX;
points[2].y = p.mouseY;
}
let circle_diameter = p.min(p.windowWidth, p.windowHeight) / 2.0;

let isectP = p.intersectLineCircle(...points, circle_diameter/2.0);

// draw the scene

p.background(192);

p.stroke(0, 0, 255);
p.fill(128, 128, 255);
for (let i=0; i < points.length; ++i ) {
p.ellipse(points[i].x, points[i].y, 10, 10);
}

for (let i=0; i < isectP.length; ++i ) {
if (p.inBetween(points[0], points[1], isectP[i])) {
p.stroke(255, 0, 0);
p.fill(255, 128, 0);
} else {
p.stroke(255, 128, 0);
p.fill(255, 255, 0);
}

p.ellipse(isectP[i].x, isectP[i].y, 10, 10);
}

p.stroke(0, 255, 0);
p.noFill();
p.endlessLine(points[0].x, points[0].y, points[1].x, points[1].y)
p.ellipse(points[2].x, points[2].y, circle_diameter, circle_diameter);
}

p.windowResized = function() {
p.resizeCanvas(p.windowWidth, p.windowHeight);
points = [];
}

p.mouseClicked = function() {
points = [];
}

p.keyPressed = function() {
points = []
}

};

var circle_line = new p5(sketch);
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>
<div id="p5js_canvas"></div>

Demo

关于javascript - 如何使用 p5.js 计算圆上直线的交点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57891494/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com