Javascript 确定圆和线段相交的代码是否正确?
显然很难找到线段和圆是否相交的答案。例如,如果你在谷歌上搜索,你会发现甚至前两个答案似乎都错了 被接受的答案有一条注释:Javascript 确定圆和线段相交的代码是否正确?,javascript,math,geometry,collision-detection,Javascript,Math,Geometry,Collision Detection,显然很难找到线段和圆是否相交的答案。例如,如果你在谷歌上搜索,你会发现甚至前两个答案似乎都错了 被接受的答案有一条注释:这似乎是计算一个圆与一条线的交点,而不是一个线段向下滚动到下一个答案,你会发现另一条注释说这个答案不完整吗?它查找圆和线是否相交,而不是线段 然后,我尝试搜索一个函数来确定一段是否与一个圆相交,但没有结果。我能找到的最好的是一个 我尝试过修改他的代码,虽然它似乎可以工作,但似乎过于冗长,我不确定我的实现是否正确。我在问这是否正确,如果正确,是否真的没有更好的方法来确定这一点?确
这似乎是计算一个圆与一条线的交点,而不是一个线段
向下滚动到下一个答案,你会发现另一条注释说这个答案不完整吗?它查找圆和线是否相交,而不是线段
然后,我尝试搜索一个函数来确定一段是否与一个圆相交,但没有结果。我能找到的最好的是一个
我尝试过修改他的代码,虽然它似乎可以工作,但似乎过于冗长,我不确定我的实现是否正确。我在问这是否正确,如果正确,是否真的没有更好的方法来确定这一点?确定线段和圆是否相交的理想方法是什么?请注意,我只需要知道它们是否相交,而不需要知道它们在哪里相交
我在下面提供了一个完整的演示复制,这样您也可以将其可视化
功能线段相交圆(x1、y1、x2、y2、cx、cy、r){
设deltaX=x2-x1;
设deltaY=y2-y1;
设mag=Math.sqrt(deltaX*deltaX+deltaY*deltaY);
设unitX=deltaX/mag;
让unitY=deltaY/mag;
设d=(cx-x1)*单位-(cy-y1)*单位x;
如果(d<-r | | d>r){返回false;}
设x1CXDelta=x1-cx;
设y1CYDelta=y1-cy;
设x2CXDelta=x2-cx;
设y2CYDelta=y2-cy;
设PointOne WithinCircle=x1CXDelta*x1CXDelta+y1CYDelta*y1CYDelta{
ctx.fillStyle=“#b2c7ef”;
ctx.fillRect(0,0,800,800);
ctx.fillStyle=“#ffffff”;
画圈(圈、圈、圈);
抽绳(线X1、线Y1、线X2、线Y2);
}
console.log(线段相交圆(线段X1、线段Y1、线段X2、线段Y2、线段LEX、线段LEY、线段LER))
draw()代码>
canvas{display:flex;margin:0 auto;}
我认为(1)计算线-盘交点更简单,可以是空的、点或线段(2)测试交点是否与线段相交
对于所有实t
,线的点是((1-t)x1+t2,(1-t)y1+ty2)
。设x(t)=(1-t)x1+t2-cx
和y(t)=(1-t)y1+ty2-cy
。当且仅当多项式x(t)^2+y(t)^2-r^2=0
具有实根t1=0
时,线盘交点为非空
条件t1 0
和t2-1>0
,当且仅当(t1-1)+(t2-1)>0
和(t1-1)(t2-1)>0
,这相当于-b/a-2>0
和c/a+b/a+1>0
。由于a>0
,这就简化为-b>2a
和c+b+a>0
当且仅当t1<0
和t2<0
时,条件t2>=0
为假,当且仅当t1+t2=-b/a<0
和t1 t2=c/a>0
时,条件t2>=0
为假。由于a>0
,这就简化为b>0
和c>0
用Javascript实现
function lineSegmentIntersectsCircleOptimized(x1, y1, x2, y2, cx, cy, r) {
let x_linear = x2 - x1;
let x_constant = x1 - cx;
let y_linear = y2 - y1;
let y_constant = y1 - cy;
let a = x_linear * x_linear + y_linear * y_linear;
let half_b = x_linear * x_constant + y_linear * y_constant;
let c = x_constant * x_constant + y_constant * y_constant - r * r;
return (
half_b * half_b >= a * c &&
(-half_b <= a || c + half_b + half_b + a <= 0) &&
(half_b <= 0 || c <= 0)
);
}
function lineSegmentIntersectsCircle(x1, y1, x2, y2, cx, cy, r) {
let deltaX = x2 - x1;
let deltaY = y2 - y1;
let mag = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
let unitX = deltaX / mag;
let unitY = deltaY / mag;
let d = (cx - x1) * unitY - (cy - y1) * unitX;
if (d < -r || d > r) {
return false;
}
let x1CXDelta = x1 - cx;
let y1CYDelta = y1 - cy;
let x2CXDelta = x2 - cx;
let y2CYDelta = y2 - cy;
let pointOneWithinCircle =
x1CXDelta * x1CXDelta + y1CYDelta * y1CYDelta < r * r;
if (pointOneWithinCircle) {
return true;
}
let pointTwoWithinCircle =
x2CXDelta * x2CXDelta + y2CYDelta * y2CYDelta < r * r;
if (pointTwoWithinCircle) {
return true;
}
let foo = unitX * x1 + unitY * y1;
let bar = unitX * cx + unitY * cy;
let baz = unitX * x2 + unitY * y2;
return (foo < bar && bar < baz) || (baz < bar && bar < foo);
}
function test() {
for (let i = 0; i < 10000000; i++) {
let x1 = Math.random();
let y1 = Math.random();
let x2 = Math.random();
let y2 = Math.random();
let cx = Math.random();
let cy = Math.random();
let r = Math.random();
if (
lineSegmentIntersectsCircle(x1, y1, x2, y2, cx, cy, r) !=
lineSegmentIntersectsCircleOptimized(x1, y1, x2, y2, cx, cy, r)
) {
console.log("bad");
break;
}
}
}
test();
优化了功能线段交叉点(x1、y1、x2、y2、cx、cy、r){
设x_线性=x2-x1;
设x_常数=x1-cx;
设y_线性=y2-y1;
设y_常数=y1-cy;
设a=x_线性*x_线性+y_线性*y_线性;
设half_b=x_线性*x_常数+y_线性*y_常数;
设c=x_常数*x_常数+y_常数*y_常数-r*r;
返回(
半个b*半个b>=a*c&&
(-half_b我认为(1)计算线-盘交点更简单,它可以是空的、点或线段(2)测试交点是否与线段相交
对于所有实t
,直线的点是((1-t)x1+tx2,(1-t)y1+ty2)
。让x(t)=(1-t)x1+tx2-cx
和y(t)=(1-t)y1+ty2-cy
当且仅当多项式x(t)^2+y(t)^2-r^2=0
具有实根t1
条件t1 0
和t2-1>0
,当且仅当(t1-1)+(t2-1)>0
和(t1-1)(t2-1)时才成立>0
,相当于-b/a-2>0
和c/a+b/a+1>0
。由于a>0
,这就简化为-b>2a
和c+b+a>0
当且仅当t1<0
和t2<0
时,条件t2>=0
为假;当且仅当t1+t2=-b/a<0
和t1 t2=c/a>0
时,条件t2>=0
为假。由于a>0
,这就简化为b>0
和c>0
用Javascript实现
function lineSegmentIntersectsCircleOptimized(x1, y1, x2, y2, cx, cy, r) {
let x_linear = x2 - x1;
let x_constant = x1 - cx;
let y_linear = y2 - y1;
let y_constant = y1 - cy;
let a = x_linear * x_linear + y_linear * y_linear;
let half_b = x_linear * x_constant + y_linear * y_constant;
let c = x_constant * x_constant + y_constant * y_constant - r * r;
return (
half_b * half_b >= a * c &&
(-half_b <= a || c + half_b + half_b + a <= 0) &&
(half_b <= 0 || c <= 0)
);
}
function lineSegmentIntersectsCircle(x1, y1, x2, y2, cx, cy, r) {
let deltaX = x2 - x1;
let deltaY = y2 - y1;
let mag = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
let unitX = deltaX / mag;
let unitY = deltaY / mag;
let d = (cx - x1) * unitY - (cy - y1) * unitX;
if (d < -r || d > r) {
return false;
}
let x1CXDelta = x1 - cx;
let y1CYDelta = y1 - cy;
let x2CXDelta = x2 - cx;
let y2CYDelta = y2 - cy;
let pointOneWithinCircle =
x1CXDelta * x1CXDelta + y1CYDelta * y1CYDelta < r * r;
if (pointOneWithinCircle) {
return true;
}
let pointTwoWithinCircle =
x2CXDelta * x2CXDelta + y2CYDelta * y2CYDelta < r * r;
if (pointTwoWithinCircle) {
return true;
}
let foo = unitX * x1 + unitY * y1;
let bar = unitX * cx + unitY * cy;
let baz = unitX * x2 + unitY * y2;
return (foo < bar && bar < baz) || (baz < bar && bar < foo);
}
function test() {
for (let i = 0; i < 10000000; i++) {
let x1 = Math.random();
let y1 = Math.random();
let x2 = Math.random();
let y2 = Math.random();
let cx = Math.random();
let cy = Math.random();
let r = Math.random();
if (
lineSegmentIntersectsCircle(x1, y1, x2, y2, cx, cy, r) !=
lineSegmentIntersectsCircleOptimized(x1, y1, x2, y2, cx, cy, r)
) {
console.log("bad");
break;
}
}
}
test();
优化了功能线段交叉点(x1、y1、x2、y2、cx、cy、r){
设x_线性=x2-x1;
让x_c