如何分辨圆和矩形在二维欧几里得空间中是否相交?(即经典二维几何)


当前回答

这里有一个快速的单行测试:

if (length(max(abs(center - rect_mid) - rect_halves, 0)) <= radius ) {
  // They intersect.
}

这是轴对齐的情况,其中rect_二分之一是一个正向量,从矩形的中间指向一个角。length()中的表达式是一个从矩形中心到最近点的增量向量。这适用于任何维度。

其他回答

这里有一个快速的单行测试:

if (length(max(abs(center - rect_mid) - rect_halves, 0)) <= radius ) {
  // They intersect.
}

这是轴对齐的情况,其中rect_二分之一是一个正向量,从矩形的中间指向一个角。length()中的表达式是一个从矩形中心到最近点的增量向量。这适用于任何维度。

假设你有矩形的四条边,检查从这些边到圆心的距离,如果小于半径,那么这些形状是相交的。

if sqrt((rectangleRight.x - circleCenter.x)^2 +
        (rectangleBottom.y - circleCenter.y)^2) < radius
// then they intersect

if sqrt((rectangleRight.x - circleCenter.x)^2 +
        (rectangleTop.y - circleCenter.y)^2) < radius
// then they intersect

if sqrt((rectangleLeft.x - circleCenter.x)^2 +
        (rectangleTop.y - circleCenter.y)^2) < radius
// then they intersect

if sqrt((rectangleLeft.x - circleCenter.x)^2 +
        (rectangleBottom.y - circleCenter.y)^2) < radius
// then they intersect

如果你对一个更图形化的解决方案感兴趣,甚至在(平面上)旋转的矩形..

演示:https://jsfiddle.net/exodus4d/94mxLvqh/2691/

这个想法是:

将场景转换为原点[0,0] 如果矩形不在平面上,则旋转中心应在 (0,0) 将场景旋转回平面 计算交点

const hasIntersection = ({x: cx, y: cy, r: cr}, {x, y, width, height}) => { const distX = Math.abs(cx - x - width / 2); const distY = Math.abs(cy - y - height / 2); if (distX > (width / 2 + cr)) { return false; } if (distY > (height / 2 + cr)) { return false; } if (distX <= (width / 2)) { return true; } if (distY <= (height / 2)) { return true; } const Δx = distX - width / 2; const Δy = distY - height / 2; return Δx * Δx + Δy * Δy <= cr * cr; }; const rect = new DOMRect(50, 20, 100, 50); const circ1 = new DOMPoint(160, 80); circ1.r = 20; const circ2 = new DOMPoint(80, 95); circ2.r = 20; const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); ctx.strokeRect(rect.x, rect.y, rect.width, rect.height); ctx.beginPath(); ctx.strokeStyle = hasIntersection(circ1, rect) ? 'red' : 'green'; ctx.arc(circ1.x, circ1.y, circ1.r, 0, 2 * Math.PI); ctx.stroke(); ctx.beginPath(); ctx.strokeStyle = hasIntersection(circ2, rect) ? 'red' : 'green'; ctx.arc(circ2.x, circ2.y, circ2.r, 0, 2 * Math.PI); ctx.stroke(); <canvas id="canvas"></canvas>

提示:而不是旋转矩形(4点)。你可以向相反的方向旋转圆(1点)。

为我工作(只工作时,矩形的角度是180)

function intersects(circle, rect) {
  let left = rect.x + rect.width > circle.x - circle.radius;
  let right = rect.x < circle.x + circle.radius;
  let top = rect.y < circle.y + circle.radius;
  let bottom = rect.y + rect.height > circle.y - circle.radius;
  return left && right && bottom && top;
}

有一种非常简单的方法来做到这一点,你必须在x和y上夹住一个点,但在正方形内部,当圆心在一个垂直轴上的两个正方形边界点之间时,你需要将这些坐标夹到平行轴上,只是要确保夹住的坐标不超过正方形的限制。 然后只需得到圆心与夹紧坐标之间的距离,并检查距离是否小于圆的半径。

以下是我是如何做到的(前4个点是方坐标,其余是圆点):

bool DoesCircleImpactBox(float x, float y, float x1, float y1, float xc, float yc, float radius){
    float ClampedX=0;
    float ClampedY=0;
    
    if(xc>=x and xc<=x1){
    ClampedX=xc;
    }
    
    if(yc>=y and yc<=y1){
    ClampedY=yc;
    }
    
    radius = radius+1;
    
    if(xc<x) ClampedX=x;
    if(xc>x1) ClampedX=x1-1;
    if(yc<y) ClampedY=y;
    if(yc>y1) ClampedY=y1-1;
    
    float XDif=ClampedX-xc;
    XDif=XDif*XDif;
    float YDif=ClampedY-yc;
    YDif=YDif*YDif;
    
    if(XDif+YDif<=radius*radius) return true;
    
    return false;
}