簡體   English   中英

確定矩形是否在圓內的最佳算法

[英]Best Algorithms to determine the whether a rectangle is inside a circle

我必須根據矩形與同心圓的交點繪制具有不同填充顏色的矩形。 顯示的圖片將使您對場景有更好的了解, 在此處輸入圖片說明 (僅用於表示目的)

目前,我正在通過應用畢達哥拉斯定理檢查每個點的狀態

偽代碼:

SquareOf Point距中心的距離(sqrOfDistance)=正方形(點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是確定點狀態的枚舉。

如果您要處理許多矩形,並且大多數情況下大多數矩形大部分時間都將不在圓的外面,則一種以較早退出方式優化檢查的方法是首先想象一個將圓括起來的正方形 ,由(- r,-r)到(r,r),其中r是圓的半徑,圓的中心是(0,0),並檢查矩形是否在此正方形內。 這應該更快 ,並且只有成功的情況下需要檢查與圓的碰撞。

編輯:@hvd為提前退出積極檢查添加了一個絕妙的主意 如果矩形在內部正方形內 ,則一定在圓形內。

根據矩形與圓形的大小,您還可以再深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
}

希望對你有幫助

只需評論@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()));
        }
    }

}

順便說一句:考慮在四叉樹中設置矩形

如果您檢查4個角(x,y)是否更靠近球體中心,然后再確定半徑,則快得多?

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

並在沒有通過條件的情況下中斷對每個平方角的計算。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM