我试图在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);
}

最佳答案

可以将直线表示为两种关系:

x = x1 + k * (x2 - x1) = x1 + k * dx
y = y1 + k * (y2 - y1) = y1 + k * dy

使用0 < k < 1圆上的一点满足以下等式:
(x - Cx)² + (y - Cy)² = r²

用直线方程替换xy,得到一个二次方程:
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;
}

关于algorithm - 垂直线和水平线的线圆交点,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25810045/

10-12 13:33