确定矩形是否在圆内的最佳算法

时间:2012-11-28 08:51:24

标签: c# algorithm

我必须绘制具有不同填充颜色的矩形,具体取决于它与同心圆的交点。显示的图片将让您更好地了解该场景, enter image description here (仅限代表)

目前我正在通过应用毕达哥拉斯定理检查每个点状态

伪代码:

  

SquareOf Point距中心的距离(sqrOfDistance)= square(点X.    - 圆心X)+正方形(Y点 - 圆心Y)

将这些值与半径的平方(sqrOfInnerR)进行比较

if  sqrOfDistance == sqrOfInnerR
    Inline
else if sqrOfDistance > sqrOfInnerR
    Out
else 
    In

即使当前的逻辑有效;它需要对每个点(4或8次)执行这些检查,最后一起确定状态。 在我的真实世界应用程序中,将会出现大约3,000,000个矩形。

private RectState CheckTheRectangleState(Rect rect, double radius, bool firstCall = true)
        {
            double SquareOfRadius = Square(radius);
            var _x = rect.X - ControlCenter.X;
            var _y = rect.Y - ControlCenter.Y;

            var squareOfDistanceToTopLeftPoint = Square(_x) + Square(_y);
            var squareOfDistanceToTopRight = Square(_x + rect.Width) + Square(_y);
            var squareOfDistanceToBottonLeft = Square(_x) + Square(_y + rect.Height);
            var squareOfDistanceToBottonRight = Square(_x + rect.Width) + Square(_y + rect.Height);

            var topLeftStatus = squareOfDistanceToTopLeftPoint == SquareOfRadius ? PointStatus.Inline : (squareOfDistanceToTopLeftPoint > SquareOfRadius ? PointStatus.Out : PointStatus.In);
            var topRightStatus = squareOfDistanceToTopRight == SquareOfRadius ? PointStatus.Inline : (squareOfDistanceToTopRight > SquareOfRadius ? PointStatus.Out : PointStatus.In);
            var bottonLeftStatus = squareOfDistanceToBottonLeft == SquareOfRadius ? PointStatus.Inline : (squareOfDistanceToBottonLeft > SquareOfRadius ? PointStatus.Out : PointStatus.In);
            var bottonRightStatus = squareOfDistanceToBottonRight == SquareOfRadius ? PointStatus.Inline : (squareOfDistanceToBottonRight > SquareOfRadius ? PointStatus.Out : PointStatus.In);

            if ((topLeftStatus == PointStatus.In || topLeftStatus == PointStatus.Inline) &&
                (topRightStatus == PointStatus.In || topRightStatus == PointStatus.Inline) &&
                (bottonLeftStatus == PointStatus.In || bottonLeftStatus == PointStatus.Inline) &&
                (bottonRightStatus == PointStatus.In || bottonRightStatus == PointStatus.Inline))
            {
                return firstCall ? RectState.In : RectState.Partial;
            }
            else
            {
                if (firstCall)
                    CheckTheRectangleState(rect, outCircleRadius, false);
            }
            return RectState.Out;
        }
    }

其中Square()是自定义函数以获得平方。 Square(x){ return x*x;} PointStatus和RectState是枚举以确定点的状态。

4 个答案:

答案 0 :(得分:2)

如果您正在处理大量矩形,并且大部分时间大部分时间都在圈外,那么优化检查提前退出< / strong>方法是首先想象一个正方形包围圆圈,从(-r,-r)到(r,r),其中r是圆的半径,圆的中心是(0,0)并检查矩形是否在此正方形内。这应该快得多,并且只有在成功时才需要检查与的冲突

编辑:@hvd为早期退出肯定检查添加了优秀想法。如果矩形在内部正方形内,它肯定在圆圈内。

根据矩形与圆的大小,您还可以 1级更深,并在内部正方形和圆形之间设置矩形。但是你需要检查所查询的矩形的点是否都在任何矩形(+内部正方形)中,并且它们都不需要在同一个矩形中。

答案 1 :(得分:1)

因此,在大多数情况下,我们可以确定方形是一个圆,然后我们的任务可以变得更容易。它将以这种方式看待

float distance = Distance(LargeCircle.center, square.center);
if (distance > LargeCircle.radius){
    //two cases here, we can be outside of circle, or intersect it
} else {
    //two cases again. We can be inside a circle, or intersect it
}

希望它会有所帮助

答案 2 :(得分:0)

只评论@Karthik T建议的内容。使用矩形表示圆圈,您可以使用以下方法进行检查:

  • 忽略顶部上限为圆形界限的矩形
  • 忽略底边低于圆底边界的矩形
  • 忽略左边界前左边界的矩形
  • 忽略右边界后右边界的矩形
  • 休息是里面的一个

因此,您只有4次检查,而不是8次。

之后,您可以在象限中拆分圆圈并将矩形分类为案例:

  • 如果右下角位于左上象限 - 请仅检查左上角(按距离)
  • 如果左下角位于右上象限 - 请仅检查右上角
  • 如果右上角位于左下象限 - 请仅检查左下角
  • 如果左上角位于右下角 - 请仅检查右下角
  • 如果右下角和左下角位于正方形的上半部分 - 请仅检查左上角和右上角
  • ...
  • 休息(每个角落在其自己的象限中)按距离检查所有角落。

更新:实际上,在第一轮中对矩形进行分类然后在正方形外过滤掉然后根据情况过滤出来要好得多。

代码示例:

struct Vec {
    public double X, Y;
    public Vec Offset(Vec d) { return new Vec { X = X + d.X, Y = Y + d.Y }; }
    public Vec Negate() { return new Vec { X = -X, Y = -Y }; }
    public Vec OrthX() { return new Vec { X = X }; }
    public Vec OrthY() { return new Vec { Y = Y }; }
}
struct Rect { public Vec TopLeft, Size; }

Vec NextVec(Random rng)
{ return new Vec { X = rng.Next(), Y = rng.Next() }; }

Rect NextRect(Random rng)
{
    var topLeft = NextVec(rng);
    return new Rect { TopLeft = NextVec(rng), Size = NextVec(rng) };
}

Vec Center;
double R, SqR;

private static double Square(double X) { return X*X; }
private bool Contains(Vec point)
{ return (Square(point.X - Center.X) + Square(point.Y - Center.Y)) < SqR; }

private bool Contains(Rect rect)
{
    var a = rect.TopLeft;
    var c = rect.TopLeft.Offset(rect.Size);
    if (c.Y < Center.Y) // in upper half
    {
        if (c.X < Center.X) // in upper-left quadrant
        {
            return Contains(a);
        }
        else if (a.X > Center.X) // in upper-right quadrant
        {
            return Contains(rect.TopLeft.Offset(rect.Size.OrthX()));
        }
        else // spans over upper half
        {
            return Contains(a) &&
                Contains(rect.TopLeft.Offset(rect.Size.OrthX()));
        }
    }
    else if (a.Y > Center.Y) // in lower half
    {
        if (c.X < Center.X) // in lower-left quadrant
        {
            return Contains(rect.TopLeft.Offset(rect.Size.OrthY()));
        }
        else if (a.X > Center.X) // in lower-right quadrant
        {
            return Contains(c);
        }
        else // spans over lower half
        {
            return Contains(c) &&
                Contains(rect.TopLeft.Offset(rect.Size.OrthY()));
        }
    }
    else // rect spans over upper and lower halfs
    {
        if (c.X < Center.X) // spans over left half
        {
            return Contains(a) &&
                Contains(rect.TopLeft.Offset(rect.Size.OrthY()));
        }
        else if (a.X > Center.X) // spans over right half
        {
            return Contains(rect.TopLeft.Offset(rect.Size.OrthX())) &&
                Contains(c);
        }
        else // rect spans over all quadrants
        {
            return Contains(a) &&
                Contains(c) &&
                Contains(rect.TopLeft.Offset(rect.Size.OrthX())) &&
                Contains(rect.TopLeft.Offset(rect.Size.OrthY()));
        }
    }

}

BTW:考虑在Quadtree

中设置orrangizing矩形

答案 3 :(得分:-1)

如果你检查4个角(x,y)是否更接近球体的中心然后是半径的长度,会快得多吗? 示例

sqrt((Xcorner - Xcenter)^2 + (Ycorner - Ycenter)^2) <= R

如果没有通过条件,则打破方块每个角的计算。