如何分辨圆和矩形在二维欧几里得空间中是否相交?(即经典二维几何)
当前回答
我为处理形状创建了类 希望你喜欢
public class Geomethry {
public static boolean intersectionCircleAndRectangle(int circleX, int circleY, int circleR, int rectangleX, int rectangleY, int rectangleWidth, int rectangleHeight){
boolean result = false;
float rectHalfWidth = rectangleWidth/2.0f;
float rectHalfHeight = rectangleHeight/2.0f;
float rectCenterX = rectangleX + rectHalfWidth;
float rectCenterY = rectangleY + rectHalfHeight;
float deltax = Math.abs(rectCenterX - circleX);
float deltay = Math.abs(rectCenterY - circleY);
float lengthHypotenuseSqure = deltax*deltax + deltay*deltay;
do{
// check that distance between the centerse is more than the distance between the circumcircle of rectangle and circle
if(lengthHypotenuseSqure > ((rectHalfWidth+circleR)*(rectHalfWidth+circleR) + (rectHalfHeight+circleR)*(rectHalfHeight+circleR))){
//System.out.println("distance between the centerse is more than the distance between the circumcircle of rectangle and circle");
break;
}
// check that distance between the centerse is less than the distance between the inscribed circle
float rectMinHalfSide = Math.min(rectHalfWidth, rectHalfHeight);
if(lengthHypotenuseSqure < ((rectMinHalfSide+circleR)*(rectMinHalfSide+circleR))){
//System.out.println("distance between the centerse is less than the distance between the inscribed circle");
result=true;
break;
}
// check that the squares relate to angles
if((deltax > (rectHalfWidth+circleR)*0.9) && (deltay > (rectHalfHeight+circleR)*0.9)){
//System.out.println("squares relate to angles");
result=true;
}
}while(false);
return result;
}
public static boolean intersectionRectangleAndRectangle(int rectangleX, int rectangleY, int rectangleWidth, int rectangleHeight, int rectangleX2, int rectangleY2, int rectangleWidth2, int rectangleHeight2){
boolean result = false;
float rectHalfWidth = rectangleWidth/2.0f;
float rectHalfHeight = rectangleHeight/2.0f;
float rectHalfWidth2 = rectangleWidth2/2.0f;
float rectHalfHeight2 = rectangleHeight2/2.0f;
float deltax = Math.abs((rectangleX + rectHalfWidth) - (rectangleX2 + rectHalfWidth2));
float deltay = Math.abs((rectangleY + rectHalfHeight) - (rectangleY2 + rectHalfHeight2));
float lengthHypotenuseSqure = deltax*deltax + deltay*deltay;
do{
// check that distance between the centerse is more than the distance between the circumcircle
if(lengthHypotenuseSqure > ((rectHalfWidth+rectHalfWidth2)*(rectHalfWidth+rectHalfWidth2) + (rectHalfHeight+rectHalfHeight2)*(rectHalfHeight+rectHalfHeight2))){
//System.out.println("distance between the centerse is more than the distance between the circumcircle");
break;
}
// check that distance between the centerse is less than the distance between the inscribed circle
float rectMinHalfSide = Math.min(rectHalfWidth, rectHalfHeight);
float rectMinHalfSide2 = Math.min(rectHalfWidth2, rectHalfHeight2);
if(lengthHypotenuseSqure < ((rectMinHalfSide+rectMinHalfSide2)*(rectMinHalfSide+rectMinHalfSide2))){
//System.out.println("distance between the centerse is less than the distance between the inscribed circle");
result=true;
break;
}
// check that the squares relate to angles
if((deltax > (rectHalfWidth+rectHalfWidth2)*0.9) && (deltay > (rectHalfHeight+rectHalfHeight2)*0.9)){
//System.out.println("squares relate to angles");
result=true;
}
}while(false);
return result;
}
}
其他回答
假设你有矩形的四条边,检查从这些边到圆心的距离,如果小于半径,那么这些形状是相交的。
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
首先检查矩形和与圆相切的正方形是否重叠(简单)。如果它们不重叠,就不会碰撞。 检查圆的中心是否在矩形内(简单)。如果它在里面,它们就会碰撞。 计算矩形边到圆中心的最小平方距离(略硬)。如果小于半径的平方,它们就会碰撞,否则不会。
它是有效的,因为:
首先,它用一个便宜的算法检查最常见的场景,当它确定它们没有碰撞时,它就结束了。 然后它用一个廉价的算法检查下一个最常见的场景(不要计算平方根,使用平方值),当它确定它们碰撞时,它就结束了。 然后它执行更昂贵的算法来检查与矩形边框的碰撞。
有一种非常简单的方法来做到这一点,你必须在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;
}
为了可视化,拿你的键盘的numpad。如果键“5”代表你的矩形,那么所有的键1-9代表空间的9个象限除以构成矩形的线(5是里面的线)。
1)如果圆的中心在象限5(即在矩形内),则两个形状相交。
这里有两种可能的情况: a)圆与矩形的两条或多条相邻边相交。 b)圆与矩形的一条边相交。
第一种情况很简单。如果圆与矩形的两条相邻边相交,则它必须包含连接这两条边的角。(或者说它的中心在象限5,我们已经讲过了。还要注意,圆只与矩形的两条相对边相交的情况也被覆盖了。)
2)如果矩形的任意角A、B、C、D在圆内,则这两个形状相交。
第二种情况比较棘手。我们应该注意到,只有当圆的中心位于2、4、6或8象限中的一个象限时,才会发生这种情况。(事实上,如果中心在1、3、7、8象限中的任何一个象限上,则相应的角将是离它最近的点。)
现在我们有了圆的中心在一个“边”象限内的情况,它只与相应的边相交。那么,边缘上最接近圆中心的点必须在圆内。
3)对于每条直线AB, BC, CD, DA,构造经过圆中心p的垂直线p(AB, p), p(BC, p), p(CD, p), p(DA, p),对于每条垂直线,如果与原边的交点在圆内,则两个图形相交。
最后一步有一个捷径。如果圆的圆心在象限8,边AB是上边,交点的y坐标是A和B, x坐标是P。
你可以构造四条线的交点并检查它们是否在相应的边上,或者找出P在哪个象限并检查相应的交点。两者都应该化简为相同的布尔方程。要注意的是,上面的步骤2并没有排除P位于“角落”象限之一;它只是在寻找一个十字路口。
编辑:事实证明,我忽略了一个简单的事实,即#2是#3的子情况。毕竟,角也是边缘上的点。请看下面@ShreevatsaR的回答,你会得到很好的解释。与此同时,忘记上面的第二条,除非你想要一个快速但冗余的检查。
为我工作(只工作时,矩形的角度是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;
}