Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/397.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 确定圆和线段相交的代码是否正确?_Javascript_Math_Geometry_Collision Detection - Fatal编程技术网

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