我怎么能告诉是否是一个圈子和一个矩形交叉在欧几里德2D空间?(即经典的2D几何形状)

有帮助吗?

解决方案

只有两种情况下,当圆的相交的矩形:

  • 无论是圆的中心内部的矩形,或
  • 一边形有点圆。

注意,这并不需要的矩形轴线平行的。

Some different ways a circle and rectangle may intersect

(一的方式看到这一点:如果没有边有点圆(如果所有边是完全的"外部"的圆),那么唯一的办法的圈子仍然可以相互交叉的多边形是,如果它的谎言完全的内部多边形。)

与这一见解,像以下会的工作,那里的圈子中心 P 和半径 R, 和矩形的顶点 A, B, C, D 在这一了(不完全代码):

def intersect(Circle(P, R), Rectangle(A, B, C, D)):
    S = Circle(P, R)
    return (pointInRectangle(P, Rectangle(A, B, C, D)) or
            intersectCircle(S, (A, B)) or
            intersectCircle(S, (B, C)) or
            intersectCircle(S, (C, D)) or
            intersectCircle(S, (D, A)))

如果你正在写的任何几何可能有上述功能的图书馆。否则, pointInRectangle() 可以在几种方法;任何一般 一点在多边形 方法将工作,但对一个矩你可以检查是否该工作:

0 ≤ AP·AB ≤ AB·AB and 0 ≤ AP·AD ≤ AD·AD

intersectCircle() 是容易实现的:方法之一就是检查是否足的垂直从 P 到线靠近足够的端点之间,以及检查端点。

很酷的事情是, 思想工作,不仅为长方形,但对于交叉路口的一个圆形的任何 简单的面 —甚至没有被凸!

其他提示

我将如何做到这一点:

bool intersects(CircleType circle, RectType rect)
{
    circleDistance.x = abs(circle.x - rect.x);
    circleDistance.y = abs(circle.y - rect.y);

    if (circleDistance.x > (rect.width/2 + circle.r)) { return false; }
    if (circleDistance.y > (rect.height/2 + circle.r)) { return false; }

    if (circleDistance.x <= (rect.width/2)) { return true; } 
    if (circleDistance.y <= (rect.height/2)) { return true; }

    cornerDistance_sq = (circleDistance.x - rect.width/2)^2 +
                         (circleDistance.y - rect.height/2)^2;

    return (cornerDistance_sq <= (circle.r^2));
}

以下是它的工作原理:

  1. 第一对线计算圆心和矩形中心之间的x和y差的绝对值。这将四个象限折叠成一个,因此计算不必进行四次。图像显示圆圈中心现在必须位于的区域。请注意,仅显示单个象限。矩形是灰色区域,红色边框勾勒出临界区域,该区域与矩形边缘恰好相差一个半径。圆的中心必须在红色边界内,才能发生交叉。

  2. 第二对线消除了圆形远离矩形(在任一方向上)远离任何交叉点的简单情况。这对应于图像中的绿色区域。

  3. 第三对线处理容易的情况,其中圆圈足够接近矩形(在任一方向上),保证交叉点。这对应于图像中的橙色和灰色部分。请注意,必须在步骤2之后执行此步骤才能使逻辑有意义。

  4. 剩余的线条计算圆圈可能与矩形的角相交的困难情况。要求解,请计算圆心和拐角的距离,然后验证距离是否不大于圆的半径。对于中心位于红色阴影区域内的所有圆圈,此计算返回false,对于中心位于白色阴影区域内的所有圆圈,此计算返回true。

这是另一个非常简单的解决方案(也非常快)。它将捕获所有交叉点,包括球体完全进入矩形时。

// clamp(value, min, max) - limits value to the range min..max

// Find the closest point to the circle within the rectangle
float closestX = clamp(circle.X, rectangle.Left, rectangle.Right);
float closestY = clamp(circle.Y, rectangle.Top, rectangle.Bottom);

// Calculate the distance between the circle's center and this closest point
float distanceX = circle.X - closestX;
float distanceY = circle.Y - closestY;

// If the distance is less than the circle's radius, an intersection occurs
float distanceSquared = (distanceX * distanceX) + (distanceY * distanceY);
return distanceSquared < (circle.Radius * circle.Radius);

任何体面的数学库,可以缩短为3或4行。

你的球体和矩形相交IIF
圆心与矩形的一个顶点之间的距离小于球体的半径 或者
圆心与矩形的一条边之间的距离小于球体的半径([点线距离])
或者
圆心位于矩形内 搜索结果 点 - 点距离:

P1 = [x1,y1]
P2 = [x2,y2]
Distance = sqrt(abs(x1 - x2)+abs(y1-y2))

点线距离:

L1 = [x1,y1],L2 = [x2,y2] (two points of your line, ie the vertex points)
P1 = [px,py] some point

Distance d =  abs( (x2-x1)(y1-py)-(x1-px)(y2-y1) ) / Distance(L1,L2)


圈内中心:
采取分离轴方法:如果在一条线上有一个投影,从该点分隔矩形,它们就不相交

将点投影在平行于矩形边的线上,然后可以轻松确定它们是否相交。如果它们不与所有4个投影相交,则它们(点和矩形)不能相交。

你只需要内积(x = [x1,x2],y = [y1,y2],x * y = x1 * y1 + x2 * y2)

你的测试看起来像那样:

//rectangle edges: TL (top left), TR (top right), BL (bottom left), BR (bottom right)
//point to test: POI

seperated = false
for egde in { {TL,TR}, {BL,BR}, {TL,BL},{TR-BR} }:  // the edges
    D = edge[0] - edge[1]
    innerProd =  D * POI
    Interval_min = min(D*edge[0],D*edge[1])
    Interval_max = max(D*edge[0],D*edge[1])
    if not (  Interval_min ≤ innerProd ≤  Interval_max ) 
           seperated = true
           break  // end for loop 
    end if
end for
if (seperated is true)    
      return "no intersection"
else 
      return "intersection"
end if

这不假设是一个轴对齐的矩形,并且可以很容易地扩展以测试凸集之间的交叉点。

这是最快的解决方案:

public static boolean intersect(Rectangle r, Circle c)
{
    float cx = Math.abs(c.x - r.x - r.halfWidth);
    float xDist = r.halfWidth + c.radius;
    if (cx > xDist)
        return false;
    float cy = Math.abs(c.y - r.y - r.halfHeight);
    float yDist = r.halfHeight + c.radius;
    if (cy > yDist)
        return false;
    if (cx <= r.halfWidth || cy <= r.halfHeight)
        return true;
    float xCornerDist = cx - r.halfWidth;
    float yCornerDist = cy - r.halfHeight;
    float xCornerDistSq = xCornerDist * xCornerDist;
    float yCornerDistSq = yCornerDist * yCornerDist;
    float maxCornerDistSq = c.radius * c.radius;
    return xCornerDistSq + yCornerDistSq <= maxCornerDistSq;
}

请注意执行顺序,预先计算宽度/高度的一半。平行也是“手动”完成的。节省一些时钟周期。

这是我的C代码,用于解决球体和非轴对齐框之间的碰撞。它依赖于我自己的几个库例程,但它可能对某些人有用。我在游戏中使用它并且效果很好。

float physicsProcessCollisionBetweenSelfAndActorRect(SPhysics *self, SPhysics *actor)
{
    float diff = 99999;

    SVector relative_position_of_circle = getDifference2DBetweenVectors(&self->worldPosition, &actor->worldPosition);
    rotateVector2DBy(&relative_position_of_circle, -actor->axis.angleZ); // This aligns the coord system so the rect becomes an AABB

    float x_clamped_within_rectangle = relative_position_of_circle.x;
    float y_clamped_within_rectangle = relative_position_of_circle.y;
    LIMIT(x_clamped_within_rectangle, actor->physicsRect.l, actor->physicsRect.r);
    LIMIT(y_clamped_within_rectangle, actor->physicsRect.b, actor->physicsRect.t);

    // Calculate the distance between the circle's center and this closest point
    float distance_to_nearest_edge_x = relative_position_of_circle.x - x_clamped_within_rectangle;
    float distance_to_nearest_edge_y = relative_position_of_circle.y - y_clamped_within_rectangle;

    // If the distance is less than the circle's radius, an intersection occurs
    float distance_sq_x = SQUARE(distance_to_nearest_edge_x);
    float distance_sq_y = SQUARE(distance_to_nearest_edge_y);
    float radius_sq = SQUARE(self->physicsRadius);
    if(distance_sq_x + distance_sq_y < radius_sq)   
    {
        float half_rect_w = (actor->physicsRect.r - actor->physicsRect.l) * 0.5f;
        float half_rect_h = (actor->physicsRect.t - actor->physicsRect.b) * 0.5f;

        CREATE_VECTOR(push_vector);         

        // If we're at one of the corners of this object, treat this as a circular/circular collision
        if(fabs(relative_position_of_circle.x) > half_rect_w && fabs(relative_position_of_circle.y) > half_rect_h)
        {
            SVector edges;
            if(relative_position_of_circle.x > 0) edges.x = half_rect_w; else edges.x = -half_rect_w;
            if(relative_position_of_circle.y > 0) edges.y = half_rect_h; else edges.y = -half_rect_h;   

            push_vector = relative_position_of_circle;
            moveVectorByInverseVector2D(&push_vector, &edges);

            // We now have the vector from the corner of the rect to the point.
            float delta_length = getVector2DMagnitude(&push_vector);
            float diff = self->physicsRadius - delta_length; // Find out how far away we are from our ideal distance

            // Normalise the vector
            push_vector.x /= delta_length;
            push_vector.y /= delta_length;
            scaleVector2DBy(&push_vector, diff); // Now multiply it by the difference
            push_vector.z = 0;
        }
        else // Nope - just bouncing against one of the edges
        {
            if(relative_position_of_circle.x > 0) // Ball is to the right
                push_vector.x = (half_rect_w + self->physicsRadius) - relative_position_of_circle.x;
            else
                push_vector.x = -((half_rect_w + self->physicsRadius) + relative_position_of_circle.x);

            if(relative_position_of_circle.y > 0) // Ball is above
                push_vector.y = (half_rect_h + self->physicsRadius) - relative_position_of_circle.y;
            else
                push_vector.y = -((half_rect_h + self->physicsRadius) + relative_position_of_circle.y);

            if(fabs(push_vector.x) < fabs(push_vector.y))
                push_vector.y = 0;
            else
                push_vector.x = 0;
        }

        diff = 0; // Cheat, since we don't do anything with the value anyway
        rotateVector2DBy(&push_vector, actor->axis.angleZ);
        SVector *from = &self->worldPosition;       
        moveVectorBy2D(from, push_vector.x, push_vector.y);
    }   
    return diff;
}

实际上,这要简单得多。你只需要两件事。

首先,您需要找到从圆心到矩形每条线的四个正交距离。如果它们中的任何三个大于圆半径,则圆圈将不会与矩形相交。

其次,你需要找到圆心和矩形中心之间的距离,如果距离大于矩形对角线长度的一半,你就不会在圆形内部。

祝你好运!

我提出的最简单的解决方案非常简单。

它的工作原理是找到距离圆最近的矩形点,然后比较距离。

您可以通过一些操作完成所有这些操作,甚至可以避免使用sqrt功能。

public boolean intersects(float cx, float cy, float radius, float left, float top, float right, float bottom)
{
   float closestX = (cx < left ? left : (cx > right ? right : cx));
   float closestY = (cy < top ? top : (cy > bottom ? bottom : cy));
   float dx = closestX - cx;
   float dy = closestY - cy;

   return ( dx * dx + dy * dy ) <= radius * radius;
}

就是这样!上述解决方案假定世界左上角有一个原点,x轴指向下方。

如果你想要一个解决方案来处理移动的圆圈和矩形之间的碰撞,那么它就会变得更加复杂和覆盖在我的另一个答案中。

要想象,请拿出键盘的小键盘。如果键'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(AB,P),p(BC,P),p(CD,P),p(DA,P) P.对于每条垂直线,如果与原始边缘的交点位于圆内,则两个形状相交。

最后一步有一个快捷方式。如果圆的中心位于象限8并且边AB是顶边,则交点将具有A和B的y坐标以及中心P的x坐标。

您可以构造四个线交叉点并检查它们是否位于相应的边缘,或找出P所在的象限并检查相应的交叉点。两者都应简化为相同的布尔方程。要小心,上面的第2步并不排除P在一个“角落”象限中;它只是寻找一个交叉点。

编辑:事实证明,我忽略了一个简单的事实,#2是上面#3的子句。毕竟,角落也是边缘上的点。请参阅下面的@ ShreevatsaR的答案,以获得很好的解释。同时,除非您想要快速但冗余的检查,否则请忘记上面的#2。

此功能检测圆形和矩形之间的碰撞(交叉点)。他在答案中的工作方式与e.James方法类似,但是这个方法可以检测所有矩形角度(不仅是右上角)的碰撞。

注意:

aRect.origin.x aRect.origin.y 是矩形左下角的坐标!

aCircle.x aCircle.y 是Circle Center的坐标!

static inline BOOL RectIntersectsCircle(CGRect aRect, Circle aCircle) {

    float testX = aCircle.x;
    float testY = aCircle.y;

    if (testX < aRect.origin.x)
        testX = aRect.origin.x;
    if (testX > (aRect.origin.x + aRect.size.width))
        testX = (aRect.origin.x + aRect.size.width);
    if (testY < aRect.origin.y)
        testY = aRect.origin.y;
    if (testY > (aRect.origin.y + aRect.size.height))
        testY = (aRect.origin.y + aRect.size.height);

    return ((aCircle.x - testX) * (aCircle.x - testX) + (aCircle.y - testY) * (aCircle.y - testY)) < aCircle.radius * aCircle.radius;
}

我创建了用于处理形状的类 希望你喜欢

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;
  } 
}

这是100%工作的修改代码:

public static bool IsIntersected(PointF circle, float radius, RectangleF rectangle)
{
    var rectangleCenter = new PointF((rectangle.X +  rectangle.Width / 2),
                                     (rectangle.Y + rectangle.Height / 2));

    var w = rectangle.Width  / 2;
    var h = rectangle.Height / 2;

    var dx = Math.Abs(circle.X - rectangleCenter.X);
    var dy = Math.Abs(circle.Y - rectangleCenter.Y);

    if (dx > (radius + w) || dy > (radius + h)) return false;

    var circleDistance = new PointF
                             {
                                 X = Math.Abs(circle.X - rectangle.X - w),
                                 Y = Math.Abs(circle.Y - rectangle.Y - h)
                             };

    if (circleDistance.X <= (w))
    {
        return true;
    }

    if (circleDistance.Y <= (h))
    {
        return true;
    }

    var cornerDistanceSq = Math.Pow(circleDistance.X - w, 2) + 
                                    Math.Pow(circleDistance.Y - h, 2);

    return (cornerDistanceSq <= (Math.Pow(radius, 2)));
}

Bassam Alugili

这是一个快速的单行测试:

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

这是轴对齐的情况,其中 rect_halves 是从矩形中间指向角的正向量。 length()中的表达式是从 center 到矩形中最近点的delta矢量。这适用于任何方面。

  • 第一次检查,如果矩形和平相切的圆重叠(简单).如果他们不相重叠,他们不碰撞。
  • 检查是否圆的中心内部的长方形(简单).如果它是在里面,他们会发生碰撞。
  • 计算出的最低平方距离的矩形面至圆的中心(小硬)。如果它是较低的,方径,然后他们发生冲突,否则他们不会。

它是有效的,因为:

  • 第一次检查的最常见的情况与一个廉价的算法和它确保他们不碰撞,它结束。
  • 然后检查的下一个最常见的情况与一个廉价的算法(不计算的平方根,使用的方价值)和确保他们碰撞它结束。
  • 然后执行更加昂贵的算法,以检查碰撞的矩形的边界。

我其中的一种方法避免了昂贵的毕达哥拉斯,如果没有必要的-ie。当边界框矩形的圈子不相交叉。

它会工作的非欧几里德太:

class Circle {
 // create the bounding box of the circle only once
 BBox bbox;

 public boolean intersect(BBox b) {
    // test top intersect
    if (lat > b.maxLat) {
        if (lon < b.minLon)
            return normDist(b.maxLat, b.minLon) <= normedDist;
        if (lon > b.maxLon)
            return normDist(b.maxLat, b.maxLon) <= normedDist;
        return b.maxLat - bbox.minLat > 0;
    }

    // test bottom intersect
    if (lat < b.minLat) {
        if (lon < b.minLon)
            return normDist(b.minLat, b.minLon) <= normedDist;
        if (lon > b.maxLon)
            return normDist(b.minLat, b.maxLon) <= normedDist;
        return bbox.maxLat - b.minLat > 0;
    }

    // test middle intersect
    if (lon < b.minLon)
        return bbox.maxLon - b.minLon > 0;
    if (lon > b.maxLon)
        return b.maxLon - bbox.minLon > 0;
    return true;
  }
}
  • minLat,maxLat可以被替换为minY,maxY和相同minLon,maxLon:换疯丫头,麦克斯
  • normDist ist只是有点快的方法那么全距离计算的。E.g。没有的平方根是在欧空间(或者没有很多其他的东西半正矢): dLat=(lat-circleY); dLon=(lon-circleX); normed=dLat*dLat+dLon*dLon.当然如果你用那normDist方法则需要创建一个 normedDist = dist*dist; 对于圆

看到完整的 BBox圆圈 我的代码 GraphHopper 的项目。

对于那些必须使用SQL计算地理坐标中的圆/矩形碰撞,
这是我在 e.James建议的算法的oracle 11中的实现。

在输入中,它需要圆坐标,以km为单位的圆半径和矩形的两个顶点坐标:

CREATE OR REPLACE FUNCTION "DETECT_CIRC_RECT_COLLISION"
(
    circleCenterLat     IN NUMBER,      -- circle Center Latitude
    circleCenterLon     IN NUMBER,      -- circle Center Longitude
    circleRadius        IN NUMBER,      -- circle Radius in KM
    rectSWLat           IN NUMBER,      -- rectangle South West Latitude
    rectSWLon           IN NUMBER,      -- rectangle South West Longitude
    rectNELat           IN NUMBER,      -- rectangle North Est Latitude
    rectNELon           IN NUMBER       -- rectangle North Est Longitude
)
RETURN NUMBER
AS
    -- converts km to degrees (use 69 if miles)
    kmToDegreeConst     NUMBER := 111.045;

    -- Remaining rectangle vertices 
    rectNWLat   NUMBER;
    rectNWLon   NUMBER;
    rectSELat   NUMBER;
    rectSELon   NUMBER;

    rectHeight  NUMBER;
    rectWIdth   NUMBER;

    circleDistanceLat   NUMBER;
    circleDistanceLon   NUMBER;
    cornerDistanceSQ    NUMBER;

BEGIN
    -- Initialization of remaining rectangle vertices  
    rectNWLat := rectNELat;
    rectNWLon := rectSWLon;
    rectSELat := rectSWLat;
    rectSELon := rectNELon;

    -- Rectangle sides length calculation
    rectHeight := calc_distance(rectSWLat, rectSWLon, rectNWLat, rectNWLon);
    rectWidth := calc_distance(rectSWLat, rectSWLon, rectSELat, rectSELon);

    circleDistanceLat := abs( (circleCenterLat * kmToDegreeConst) - ((rectSWLat * kmToDegreeConst) + (rectHeight/2)) );
    circleDistanceLon := abs( (circleCenterLon * kmToDegreeConst) - ((rectSWLon * kmToDegreeConst) + (rectWidth/2)) );

    IF circleDistanceLon > ((rectWidth/2) + circleRadius) THEN
        RETURN -1;   --  -1 => NO Collision ; 0 => Collision Detected
    END IF;

    IF circleDistanceLat > ((rectHeight/2) + circleRadius) THEN
        RETURN -1;   --  -1 => NO Collision ; 0 => Collision Detected
    END IF;

    IF circleDistanceLon <= (rectWidth/2) THEN
        RETURN 0;   --  -1 => NO Collision ; 0 => Collision Detected
    END IF;

    IF circleDistanceLat <= (rectHeight/2) THEN
        RETURN 0;   --  -1 => NO Collision ; 0 => Collision Detected
    END IF;


    cornerDistanceSQ := POWER(circleDistanceLon - (rectWidth/2), 2) + POWER(circleDistanceLat - (rectHeight/2), 2);

    IF cornerDistanceSQ <=  POWER(circleRadius, 2) THEN
        RETURN 0;  --  -1 => NO Collision ; 0 => Collision Detected
    ELSE
        RETURN -1;  --  -1 => NO Collision ; 0 => Collision Detected
    END IF;

    RETURN -1;  --  -1 => NO Collision ; 0 => Collision Detected
END;    

工作,一周前刚想出来,现在才开始测试。

double theta = Math.atan2(cir.getX()-sqr.getX()*1.0,
                          cir.getY()-sqr.getY()*1.0); //radians of the angle
double dBox; //distance from box to edge of box in direction of the circle

if((theta >  Math.PI/4 && theta <  3*Math.PI / 4) ||
   (theta < -Math.PI/4 && theta > -3*Math.PI / 4)) {
    dBox = sqr.getS() / (2*Math.sin(theta));
} else {
    dBox = sqr.getS() / (2*Math.cos(theta));
}
boolean touching = (Math.abs(dBox) >=
                    Math.sqrt(Math.pow(sqr.getX()-cir.getX(), 2) +
                              Math.pow(sqr.getY()-cir.getY(), 2)));
def colision(rect, circle):
dx = rect.x - circle.x
dy = rect.y - circle.y
distance = (dy**2 + dx**2)**0.5
angle_to = (rect.angle + math.atan2(dx, dy)/3.1415*180.0) % 360
if((angle_to>135 and angle_to<225) or (angle_to>0 and angle_to<45) or (angle_to>315 and angle_to<360)):
    if distance <= circle.rad/2.+((rect.height/2.0)*(1.+0.5*abs(math.sin(angle_to*math.pi/180.)))):
        return True
else:
    if distance <= circle.rad/2.+((rect.width/2.0)*(1.+0.5*abs(math.cos(angle_to*math.pi/180.)))):
        return True
return False

假设您有矩形的四个边缘,检查从边缘到圆心的距离,如果它小于半径,则形状相交。

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

如果矩形与圆相交,则矩形的一个或多个角点应位于圆内。假设矩形的四个点是A,B,C,D。其中至少有一个应与圆相交。因此,如果从一个点到圆心的距离小于圆的半径,它应该与圆相交。为了获得距离,你可以使用毕达哥拉斯定理,

H^2 = A^2 + B^2

这种技术有一些限制。但它对游戏开发者来说会更好。特别是碰撞检测

这是对Arvo算法的一个很好的更新

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top