一个扇区的2D边界框?

时间:2009-08-26 18:34:32

标签: algorithm geometry

我用谷歌搜索直到我脸色发青,除非我遗漏了一些非常明显的东西,否则我找不到任何算法来计算2D扇区的边界框。

考虑到封闭圆的中心点,半径和扇区范围的角度,计算该扇区的轴对齐边界矩形的最佳算法是什么?

4 个答案:

答案 0 :(得分:15)

  • 生成以下几点:
    • 圈子的中心
    • 圆上两个半径的位置
    • 两个之间每个角度的圆上的点除以90 o (最多4个点)
  • 从上述点计算最小值和最大值x和y。这是你的边界框

答案 1 :(得分:8)

我要改写yairchu的答案,以便更清楚(对我来说,无论如何)。

暂时忽略中心坐标并在原点绘制圆。说服自己以下内容:

  1. 弧与轴相交的任何地方都是最大值或最小值。
  2. 如果圆弧不与轴相交,那么中心将是边界矩形的一个角,这是唯一的情况。
  3. 该行业唯一需要考虑的其他极端点是半径的终点。
  4. 您现在最多可以找到4 + 1 + 2个点。找到绘制矩形的坐标的最大值和最小值。

    通过将原始圆心的坐标添加到矩形的坐标,可以很容易地将矩形平移到原始圆。

答案 2 :(得分:3)

首先,如果我犯了错误,我会道歉但英语不是我的第一语言,实际上是西班牙语!

我遇到了这个问题,我认为我找到了一个有效的解决方案。

首先让我们看一下情况的图像

Graphical situation

所以我们有一个椭圆(实际上是一个圆圈)和两个点(CD),表示我们的扇区。 我们还有圆圈的中心(B)和圆弧alpha的角度。

现在,在这种情况下,我让它通过porpouse上的360º来查看它是否有效。

让我们说alpha -> -251.1º(它导致它的顺时针方向为负),让它转换为正值360º - 251.1º = 108.9º现在我们的目标是找到该角度的二分角,这样我们就能找到最大点对于边界框(图像中的E),实际上你可能已经意识到,段BE的长度等于圆的半径但我们必须有角度来获得实际的坐标E点。

所以108.9º / 2 -> 54.45º现在我们有了角度。

要找到E的坐标,我们使用极坐标

x = r * Cos(theta)
y = r * Sin(theta)

我们有rtheta,因此我们可以计算x和y

在我的例子中r = 2.82 ...(实际上它是理性的,但我把前两个十进制数字视为一个简单的问题)

我们知道我们的第一个半径为87.1º,因此θ为87.1 - 54.45º -> 32.65º

我们知道* theta *是32.65º所以让我们做一些数学

x = 2.82 * Cos(32.65º) -> 2.37552
y = 2.82 * Sin(32.65º) -> 1.52213

现在我们需要将这些值调整到圆的实际中心,以便

x = x + centerX
y = y + centerY 

在示例中,圆圈以(1.86, 4.24)

为中心
x -> 4.23552
y -> 5.76213

在这个阶段我们应该使用一些微积分。我们知道边界框的一个边缘将是穿过我们刚刚计算的点的弧的切线,所以让我们找到切线(红线)。

我们知道切线穿过我们的点(4.23, 5.76),现在我们需要一个斜率。

如您所见,斜率与通过我们的半径的矩形的斜率相同,因此我们必须找到斜率。

为此,我们需要获取半径的坐标(从极坐标快速转换为卡西斯坐标)。

x = r * Cos(theta)
y = r * Sin(theta)

所以

p0 = (centerX + 2.82 * Cos(87.1º), centerY + 2.82 * Sin(87.1º))
p1 = (centerX + 2.82 * Cos(-21.8º), centerY + 2.82 * Sin(-21.8º))

21.8º是从水平轴到它下面的半径顺时针测量的角度,因此我将其置为负值。

p0 (2, 7.06)
p1 (4.48, 3.19)

现在让我们找到斜率:

m = (y - y0) / (x - x0)
...
m = (3.19 - 7.06) / (4.48-2) = -3.87 / 2.48 = -1.56048
...
m = -1.56 

具有我们需要计算切线方程的斜率,基本上是一个具有已知斜率(m = -1.56)的矩形,它通过已经知道的点(E -> (4.23, 5.76)

所以我们Y = mx + b m = -1.56y = 5.76x = 4.23所以b必须

b = 5.76 - (-1.56) * 4.23 = 12.36

现在我们有了切线的完整等式 - > Y = -1.56X + 12.36 我们必须知道的是将点CD投射到该矩形上。

我们需要rects CHDI的等式,所以让我们计算'em

让我们从CH开始:

我们知道(从tanget方程式)我们的方向向量是(1.56, 1)

我们需要找到一个通过点C -> (2, 7.06)

的矩形
(x - 2) / 1.56 = (y - 7.06) / 1

做一些代数 - > y = 0.64x + 5.78

我们知道有直方CH的等式,我们必须计算点H

我们必须解决线性系统如下

y = -1.56x + 12.36
y = 1.56x + 5.78

解决这个问题,我们会找到点H (3, 7.69)

我们需要对rect DI做同样的事情,所以让我们这样做

我们的方向向量再次为(1.56, 1)

D -> (4.48, 3.19)

(x - 4.48) / 1.56 = (y -3.19) / 1

做一些代数 - > y = 0.64x + 0.32

让我们解决线性系统

y = -1.56x + 12.36
y = 0.64x + 0.32

I (5.47, 3.82)

在这个阶段,我们已经有四个点使我们的边界框 - > C, H, D , I

万一你不知道或记得如何用编程语言解决线性系统,我会给你一个小例子

这是纯粹的代数

假设我们有以下系统

Ax + By = C
Dx + Ey = F

然后

Dx = F - Ey
x = (F - Ey) / D
x = F/D - (E/D)y

替换其他等式

A(F/D - (E/D)y) + By = C
AF/D - (AE/D)y + By = C
(AE/D)y + By = C - AF/D
y(-AE/D + B) = C - AF/D
y = (C - AF/D) / (-AE/D + B)
  = ( (CD - AF) / D ) / ( (-AE + BD) / D) )

所以

y = (CD - AF) / (BD - AE)

x我们做同样的事情

Dx = F - Ey
Dx - F = -Ey
Ey = F - Dx
y = F/E - (D/E)x

替换其他等式

Ax + B(F/E - (D/E)x) = C
Ax + (BF/E - (DB/E)x) = C
Ax - (DB/E)x = C - BF/E
x (A-(DB/E)) = C - BF/E
x = (C - BF/E)/(A-(DB/E))
  = ((CE - BF) / E) / ((AE-DB) / E)

x = (CE - BF) / (AE - DB)

我为答案的范围道歉,但我的意思是尽可能清楚,因此,我几乎一步一步地做到了。

答案 3 :(得分:0)

使用C#代码:

    /// <summary>
    /// The input parameters describe a circular arc going _clockwise_ from E to F.
    /// The output is the bounding box.
    /// </summary> 
    public Rect BoundingBox(Point E, Point F, Point C, double radius)
    {
        // Put the endpoints into the bounding box:
        double x1 = E.X;
        double y1 = E.Y;
        double x2 = x1, y2 = y1;
        if (F.X < x1)
            x1 = F.X;
        if (F.X > x2)
            x2 = F.X;
        if (F.Y < y1)
            y1 = F.Y;
        if (F.Y > y2)
            y2 = F.Y;

        // Now consider the top/bottom/left/right extremities of the circle:
        double thetaE = Math.Atan2(E.Y - C.Y, E.X - C.X);
        double thetaF = Math.Atan2(F.Y - C.Y, F.X - C.X);
        if (AnglesInClockwiseSequence(thetaE, 0/*right*/, thetaF))
        {
            double x = (C.X + radius);
            if (x > x2)
                x2 = x;
        }
        if (AnglesInClockwiseSequence(thetaE, Math.PI/2/*bottom*/, thetaF))
        {
            double y = (C.Y + radius);
            if (y > y2)
                y2 = y;
        }
        if (AnglesInClockwiseSequence(thetaE, Math.PI/*left*/, thetaF))
        {
            double x = (C.X - radius);
            if (x < x1)
                x1 = x;
        }
        if (AnglesInClockwiseSequence(thetaE, Math.PI*3/2/*top*/, thetaF))
        {
            double y = (C.Y - radius);
            if (y < y1)
                y1 = y;
        }
        return new Rect(x1, y1, x2 - x1, y2 - y1);
    }


    /// <summary>
    /// Do these angles go in clockwise sequence?
    /// </summary>
    private static bool AnglesInClockwiseSequence(double x, double y, double z)
    {
        return AngularDiffSigned(x, y) + AngularDiffSigned(y, z) < 2*Math.PI;
    }


    /// <summary>
    /// Returns a number between 0 and 360 degrees, as radians, representing the
    /// angle required to go clockwise from 'theta1' to 'theta2'. If 'theta2' is 
    /// 5 degrees clockwise from 'theta1' then return 5 degrees. If it's 5 degrees
    /// anticlockwise then return 360-5 degrees.
    /// </summary>
    public static double AngularDiffSigned(double theta1, double theta2)
    {
        double dif = theta2 - theta1;
        while (dif >= 2 * Math.PI)
            dif -= 2 * Math.PI;
        while (dif <= 0)
            dif += 2 * Math.PI;
        return dif;
    }