0

好的,我希望能够计算一条线是否穿过一个圆(至少是圆内线的一部分)。我找到了几个答案,但我认为它们太复杂了,所以我想出了这个。我不是数学家,所以我现在有点卡住了。当直线垂直对齐时,“半径 >= Math.sqrt(len * len + len * len - o);” 变为真(45°角变为0)。我不知道为什么会这样。谢谢 :)

function lineInCircle(sx, sy, x, y, cx, cy, radius) {
    cx -= sx; x -= sx; //sx is the first point's x position
    cy -= sy; y -= sy;//sy is the first point's y position
    len = Math.sqrt((cy * cy) + (cx * cx))//hypotenuse of circle (cy, cx) to (0, 0) (with offset)
    atanx = Math.atan(y / x); //angle of  (0, 0) to (x, y) in radians
    atany = atanx - Math.atan(cy / cx); //to center
    var o = 2 * len * len * Math.cos(atany);
    var o = o < 0 ? -o:o//Had to do this, at some point the value can become inverted
    return radius >= Math.sqrt(len * len + len * len - o);
}

编辑:

function lineInCircle(sx, sy, x, y, cx, cy, radius) {
    cx -= sx; x -= sx; //sx is the first point's x position
    cy -= sy; y -= sy;//sy is the first point's y position
    ctp = Math.sin(Math.atan(y / x) - Math.atan(cy / cx)) * Math.sqrt((cy * cy) + (cx * cx));
    return radius >= ctp && ctp >= -radius;
}

工作原理几乎相同,但速度更快。问题是它计算了一条无限线。我将如何解决这个问题?

编辑2:

function lineInCircle(sx, sy, x, y, cx, cy, radius) {
    cx -= sx; x -= sx;
    cy -= sy; y -= sy;
    var h = Math.sqrt(cy * cy + cx * cx)
    ctp = Math.sin(Math.atan(y / x) - Math.atan(cy / cx)) * h;
    sideb = Math.sqrt(h * h - ctp * ctp);
    line = Math.sqrt(x * x + y * y)
    if (sideb - radius > line) {return false}
    return radius >= ctp && ctp >= -radius;
}

部分修复,从线的一个方向(线端)不会继续无穷大

编辑3: 有点长,但快两倍以上,回到第一格

function lineInCircle2(sx, sy, x, y, cx, cy, radius) {
    var ysy = y - sy
    var xsx = x - sx
    var k = ((y-sy) * (cx-sx) - (x-sx) * (cy-sy)) / (ysy * ysy + xsx * xsx)
    var ncx = cx - k * (y-sy)
    var ncy = cy + k * (x-sx)
    ncx -= cx
    ncy -= cy
    var ctp = Math.sqrt(ncx * ncx + ncy * ncy)
    return radius >= ctp && ctp >= -radius;
}

编辑4: 成功!

function lineInCircle(sx, sy, x, y, cx, cy, radius) {
    if (sx > cx + radius && x > cx + radius || x < cx - radius && sx < cx - radius) {return false;}
    if (sy > cy + radius && y > cy + radius || y < cy - radius && sy < cy - radius) {return false;}
    var k = ((y - sy) * (cx - sx) - (x - sx) * (cy - sy)) / ((y - sy) * (y - sy) + (x - sx) * (x - sx))
    var ncx = k * (y - sy)
    var ncy = k * (x - sx)
    return radius >= Math.sqrt(ncx * ncx + ncy * ncy);
}

完全符合我的要求,我将 100000000 次迭代的时间优化到 4.5 - 4.6 秒,而第一个版本的迭代时间为 10 多秒,并且仍然更加准确(意味着在某些角度不再有奇怪的行为)。我很满意 :D

4

2 回答 2

0
function lineInCircle(sx, sy, x, y, cx, cy, radius) {
    if (sx > cx + radius && x > cx + radius || x < cx - radius && sx < cx - radius) {return false;}
    if (sy > cy + radius && y > cy + radius || y < cy - radius && sy < cy - radius) {return false;}
    var k = ((y - sy) * (cx - sx) - (x - sx) * (cy - sy)) / ((y - sy) * (y - sy) + (x - sx) * (x - sx))
    var ncx = k * (y - sy)
    var ncy = k * (x - sx)
    return radius >= Math.sqrt(ncx * ncx + ncy * ncy);
}

在我的机器上完成 100000000 次迭代大约需要 4.5 - 4.6 秒。

于 2012-06-02T19:51:46.197 回答
0

太多的工作。找到通过中心的法线,看看交点是否比半径更近。

于 2012-06-01T20:41:25.333 回答