Algorithm 垂直线和水平线的线-圆交点

Algorithm 垂直线和水平线的线-圆交点,algorithm,line,geometry,intersection,Algorithm,Line,Geometry,Intersection,我试图在javascript中检测一条线何时与一个圆相交。我发现了一个几乎完美的函数,但我最近注意到,当相交线完全水平或垂直时,它就不起作用了。因为我不太了解这个函数的实际工作原理,所以我不确定如何编辑它以获得我想要的结果 function lineCircleCollision(circleX,circleY,radius,lineX1,lineY1,lineX2,lineY2) { var d1 = pDist(lineX1,lineY1,circleX,circleY);

我试图在javascript中检测一条线何时与一个圆相交。我发现了一个几乎完美的函数,但我最近注意到,当相交线完全水平或垂直时,它就不起作用了。因为我不太了解这个函数的实际工作原理,所以我不确定如何编辑它以获得我想要的结果

function lineCircleCollision(circleX,circleY,radius,lineX1,lineY1,lineX2,lineY2) {
    var d1 = pDist(lineX1,lineY1,circleX,circleY);
    var d2 = pDist(lineX2,lineY2,circleX,circleY);
    if (d1<=radius || d2<=radius) {
            return true;
    }

    var k1 = ((lineY2-lineY1)/(lineX2-lineX1));
    var k2 = lineY1;
    var k3 = -1/k1;
    var k4 = circleY;

    var xx = (k1*lineX1-k2-k3*circleX+k4)/(k1-k3);
    var yy = k1*(xx-lineX1)+lineY1;

    var allow = true;
    if (lineX2>lineX1) {
        if (xx>=lineX1 && xx<=lineX2) {}
        else {allow = false;}
    } else {
        if (xx>=lineX2 && xx<=lineX1) {}
        else {allow = false;}
    }

    if (lineY2>lineY1) {
        if (yy>=lineY1 && yy<=lineY2) {}
        else {allow = false;}
    } else {
        if (yy>=lineY2 && yy<=lineY1) {}
        else {allow = false;}
    }
    if (allow) {
        if (pDist(circleX,circleY,xx,yy)<radius) {
            return true;
        }
        else {
            return false;
        }
    } else {
        return false;
    }
}

function pDist(x1,y1,x2,y2) {
    var xd = x2-x1;
    var yd = y2-y1;
    return Math.sqrt(xd*xd+yd*yd);
}
函数lineCircleCollision(circleX、circleY、radius、lineX1、lineY1、lineX2、lineY2){
变量d1=pList(lineX1、lineY1、circleX、circleY);
var d2=pList(lineX2、lineY2、circleX、circleY);
如果(d1=lineX1&&xx=lineX2&&xxlineY1){

如果(yy>=lineY1&&yy=lineY2&&yy如果不需要点,只想知道线是否相交,那么:

  • 计算圆心P0(x0,y0)和直线端点P1(x1,y1)、P2(x2,y2)之间的距离

    • double d1=| P1-P0 |=sqrt((x1-x0)*(x1-x0)+(y1-x0)*(y1-x0));
    • double d2=| P2-P0 |=sqrt((x2-x0)*(x2-x0)+(y2-x0)*(y2-x0));
  • d1、d2级升序

    • if(d1>d2){double d=d1;d1=d2;d2=d;}
  • 检查交叉口

    • if((d1=r))返回true;else返回false;
    • r
      是圆半径
  • [附注]

    • 您不需要sqrt距离
    • 如果您未对它们进行排序,则只需将它们与
      r*r
      进行比较,而不是与
      r

    查看交点检查的另一种方法是,我们在线段上找到离圆心最近的点,然后确定它是否足够近。由于到圆心的距离是一个凸函数,因此有三种可能性:线段的两个端点,以及直线上最近的点,假设至少,这是一个片段

    为了找到直线上最近的点,我们有一个超定线性系统

    (1 - t) lineX1 + t lineX2 = circleX
    (1 - t) lineY1 + t lineY2 = circleY,
    
    以矩阵表示:

    [lineX2 - lineX1] [t] = [circleX - lineX1]
    [lineY2 - lineY1]       [circleY - lineY1].
    
    通过解正规方程可以找到最近点

    [(lineX2 - lineX1) (lineY2 - lineY1)] [lineX2 - lineX1] [t] =
                                          [lineY2 - lineY1]
    [(lineX2 - lineX1) (lineY2 - lineY1)] [circleX - lineX1]
                                          [circleY - lineY1],
    
    交替表示为

    ((lineX2 - lineX1)^2 + (lineY2 - lineY1)^2) t =
    (lineX2 - lineX1) (circleX - lineX1) + (lineY2 - lineY1) (circleY - lineY1),
    
    并解决了
    t

        (lineX2 - lineX1) (circleX - lineX1) + (lineY2 - lineY1) (circleY - lineY1)
    t = ---------------------------------------------------------------------------.
                        ((lineX2 - lineX1)^2 + (lineY2 - lineY1)^2)
    
    假设
    t
    介于
    0
    1
    之间,我们可以插入它并检查距离。当
    t
    超出范围时,我们可以夹紧它并仅检查该端点

    未测试代码:

    function lineCircleCollision(circleX, circleY, radius, lineX1, lineY1, lineX2, lineY2) {
        circleX -= lineX1;
        circleY -= lineY1;
        lineX2 -= lineX1;
        lineY2 -= lineY1;
        var t = (lineX2 * circleX + lineY2 * circleY) / (lineX2 * lineX2 + lineY2 * lineY2);
        if (t < 0) t = 0;
        else if (t > 1) t = 1;
        var deltaX = lineX2 * t - circleX;
        var deltaY = lineY2 * t - circleY;
        return deltaX * deltaX + deltaY * deltaY <= radius * radius;
    }
    
    函数lineCircleCollision(circleX、circleY、radius、lineX1、lineY1、lineX2、lineY2){
    circleX-=lineX1;
    圆圈-=第1行;
    lineX2-=lineX1;
    lineY2-=lineY1;
    变量t=(lineX2*circleX+lineY2*circleY)/(lineX2*lineX2+lineY2*lineY2);
    如果(t<0)t=0;
    否则,如果(t>1)t=1;
    var deltaX=lineX2*t-圈;
    var deltaY=lineY2*t-圈;
    
    return deltaX*deltaX+deltaY*deltaY您可以将该行表示为两个关系:

    x = x1 + k * (x2 - x1) = x1 + k * dx
    y = y1 + k * (y2 - y1) = y1 + k * dy
    
    0
    时。圆上的一点满足以下等式:

    (x - Cx)² + (y - Cy)² = r²
    
    a*k² + b*k + c = 0
    
    a = dx² + dy²
    b = 2*dx*(x1 - Cx) + s*dy*(y1 - Cy)
    c = (x1 - Cx)² + (y1 - Cy)² - r²
    
    用直线方程替换
    x
    y
    ,得到一个二次方程:

    (x - Cx)² + (y - Cy)² = r²
    
    a*k² + b*k + c = 0
    
    a = dx² + dy²
    b = 2*dx*(x1 - Cx) + s*dy*(y1 - Cy)
    c = (x1 - Cx)² + (y1 - Cy)² - r²
    
    解决这个问题,如果
    k
    的两个可能的解决方案中的任何一个在0到1之间,您就成功了。此方法检查实际交点,并忽略线完全包含在圆中的情况,因此需要额外检查线的端点是否位于圆内

    代码如下:

    function collision_circle_line(Cx, Cy, r, x1, y1, x2, y2) {
        var dx = x2 - x1;
        var dy = y2 - y1;
    
        var sx = x1 - Cx;
        var sy = y1 - Cy;
    
        var tx = x2 - Cx;
        var ty = y2 - Cy;
    
        if (tx*tx + ty*ty < r*r) return true;
    
        var c = sx*sx + sy*sy - r*r;
        if (c < 0) return true;
    
        var b = 2 * (dx * sx + dy * sy);
        var a = dx*dx + dy*dy;
    
        if (Math.abs(a) < 1.0e-12) return false;
    
        var discr = b*b - 4*a*c;
        if (discr < 0) return false;
        discr = Math.sqrt(discr);
    
        var k1 = (-b - discr) / (2 * a);
        if (k1 >= 0 && k1 <= 1) return true;
    
        var k2 = (-b + discr) / (2 * a);
        if (k2 >= 0 && k2 <= 1) return true;
    
        return false;
    }
    
    函数碰撞圆线(Cx、Cy、r、x1、y1、x2、y2){
    var dx=x2-x1;
    var dy=y2-y1;
    var sx=x1-Cx;
    var sy=y1-Cy;
    var tx=x2-Cx;
    var-ty=y2-Cy;
    如果(tx*tx+ty*ty如果(k1>=0&&k1=0&&k2对于初学者,
    k1
    计算直线的斜率。但是垂直直线没有斜率;试图计算它需要除以零。而
    k3
    ,斜率的负反比,对于水平直线将除以零。@Kevin这是有意义的。在这种情况下,我能做些什么来检查呢on?你知道xx和yy代表什么吗?谢谢。好主意,但是原始代码会检查碰撞,这样一条完全包含在圆中的线就会被视为碰撞;检查应该是
    d1
    。这也不会捕捉到两点都位于圆外的双交点,或者我遗漏了什么?@MOehm yep你是对的,对于p1,p2在圆外的直线,应该使用p1,p2 tp P0的垂直距离。这可以很好地处理OP代码无法正常工作时的边缘情况。这可能是该问题的最佳解决方案;它不需要满足两个点都在圆内的特殊情况。