如何计算椭圆的轴对齐边界框?
如果椭圆的主轴是垂直或者水平,则很容易计算边界框,但是旋转椭圆时会怎样呢?
到目前为止,我唯一想到的方法是计算周长周围的所有点,并找到最大/最小x和y值。似乎应该有一个更简单的方法。
如果有一个函数(在数学意义上)以任意角度描述椭圆,那么我可以使用其导数来找到斜率为零或者未定义的点,但是我似乎找不到一个。
编辑:为澄清起见,我需要与轴对齐的边界框,即它不应与椭圆一起旋转,但应与x轴保持对齐,因此变换边界框将不起作用。
解决方案
回答
我认为最有用的公式就是这个。从原点以phi角度旋转的省略号具有以下公式:
其中(h,k)是中心,a和b的长轴和短轴的大小以及t在-pi到pi之间变化。
由此,我们应该能够得出t dx / dt或者dy / dt变为0的原因。
回答
我们可以对以任意角度旋转的椭圆尝试使用参数化方程:
x = h + a*cos(t)*cos(phi) - b*sin(t)*sin(phi) [1] y = k + b*sin(t)*cos(phi) + a*cos(t)*sin(phi) [2]
...椭圆具有中心(h,k)半长轴a和半短轴b,并旋转角度phi。
然后可以区分并求解梯度= 0:
0 = dx/dt = -a*sin(t)*cos(phi) - b*cos(t)*sin(phi)
=>
tan(t) = -b*tan(phi)/a [3]
哪个应该为我们提供许多t的解决方案(我们感兴趣的两个),然后将其重新插入[1]以获取max和min x。
重复[2]:
0 = dy/dt = b*cos(t)*cos(phi) - a*sin(t)*sin(phi)
=>
tan(t) = b*cot(phi)/a [4]
让我们尝试一个例子:
考虑一个椭圆(0,0)且a = 2,b = 1的椭圆,旋转了PI / 4:
[1] =>
x = 2*cos(t)*cos(PI/4) - sin(t)*sin(PI/4)
[3] =>
tan(t) = -tan(PI/4)/2 = -1/2
=>
t = -0.4636 + n*PI
我们对t = -0.4636和t = -3.6052有兴趣
这样我们得到:
x = 2*cos(-0.4636)*cos(PI/4) - sin(-0.4636)*sin(PI/4) = 1.5811
和
x = 2*cos(-3.6052)*cos(PI/4) - sin(-3.6052)*sin(PI/4) = -1.5811
回答
这相对简单,但由于我们没有给我们提供椭圆的表示方式,因此很难解释。有很多方法可以做到这一点。
无论如何,一般原理是这样的:我们无法直接计算轴对齐的边界框。但是,我们可以将x和y中的椭圆的极值计算为2D空间中的点。
为此,将等式x(t)= ellipse_equation(t)和y(t)= ellipse_equation(t)就足够了。得到它的一阶导数并为它的根求解。由于我们要处理的是基于三角学的椭圆,这很简单。我们应该以一个方程式结束,该方程式可以通过atan,acos或者asin求根。
提示:要检查代码,请尝试使用未旋转的椭圆:根应该为0,Pi / 2,Pi和3 * Pi / 2.
对每个轴(x和y)执行此操作。我们最多将获得四个根(如果椭圆退化了则更少,例如半径之一为零)。求出根部的位置,即可得到椭圆的所有极限点。
现在我们快到了。获取椭圆的边界框就像扫描这四个点的xmin,xmax,ymin和ymax一样简单。
顺便说一句,如果我们在查找椭圆方程时遇到问题:请尝试将其简化为具有中心,两个半径和围绕中心的旋转角度的椭圆对齐的轴。
如果这样做,则等式变为:
// the ellipse unrotated: temp_x (t) = radius.x * cos(t); temp_y (t) = radius.y = sin(t); // the ellipse with rotation applied: x(t) = temp_x(t) * cos(angle) - temp_y(t) * sin(angle) + center.x; y(t) = temp_x(t) * sin(angle) + temp_y(t) * cos(angle) + center.y;