点和椭圆(旋转)位置测试:算法
Posted
技术标签:
【中文标题】点和椭圆(旋转)位置测试:算法【英文标题】:Point and ellipse (rotated) position test: algorithm 【发布时间】:2011-12-18 06:32:42 【问题描述】:如何测试点 P = [xp,yp] 是否在中心 C=[x,y]、a、b 和 phi(旋转角度)给定的某个旋转椭圆的内部/外部?
此时我正在使用以下解决方案:将椭圆和点旋转角度 -phi,然后对点和“未旋转”椭圆的位置进行通用测试。
但是有很多测试点(数千个),我发现这个解决方案很慢。有没有直接更有效的方法来获取旋转椭圆和点的位置?
我不需要代码而是算法。感谢您的帮助。
【问题讨论】:
向我们展示您到目前为止所做的事情。我们可以为您提供帮助。 【参考方案1】:Matplotlib 在 patch 类中有一个 Ellipse 方法,它允许您询问一个点是在补丁内部还是外部。检查here 并查找方法 contains_point()。您将需要使用 Ellipse 类创建椭圆,然后就好像里面有一个点。 顺便说一句,matplotlib 是 python 的一个包。
【讨论】:
【参考方案2】:您只需将数据输入上述公式即可。这是我根据 Ajasja 的建议所做的 python 实现:
def pointInEllipse(x,y,xp,yp,d,D,angle):
#tests if a point[xp,yp] is within
#boundaries defined by the ellipse
#of center[x,y], diameter d D, and tilted at angle
cosa=math.cos(angle)
sina=math.sin(angle)
dd=d/2*d/2
DD=D/2*D/2
a =math.pow(cosa*(xp-x)+sina*(yp-y),2)
b =math.pow(sina*(xp-x)-cosa*(yp-y),2)
ellipse=(a/dd)+(b/DD)
if ellipse <= 1:
return True
else:
return False
【讨论】:
不要使用math.pow(val, 2)
来解决问题。这真的很慢。 (将其分配给一个变量并自行相乘)。
math.sin
和 math.cos
期望它们的参数以弧度为单位,因此请确保以弧度传递角度。您可以使用math.radians
函数将度数转换为弧度。【参考方案3】:
另一种选择是将所有内容都放入二维旋转椭圆的方程中,看看结果是否小于一个。
如果以下不等式为真,则点在椭圆内
其中 (xp,yp) 是点坐标,(x0, y0) 是椭圆的中心。
我实现了一个小型 Mathematica 程序,证明这确实有效:
它在行动:
这里是代码:
ellipse[x_, y_, a_, b_, \[Alpha]_, x0_: 0, y0_: 0] :=
(((x - x0)*Cos[\[Alpha]] + (y - y0)*Sin[\[Alpha]])/a)^2
+ (((x - x0)*Sin[\[Alpha]] - (y - y0)*Cos[\[Alpha]])/b)^2;
Manipulate[
RegionPlot[
ellipse[x, y, a, b, \[Alpha] \[Degree], Sequence @@ pos] < 1, x, -5, 5, y, -5, 5,
PlotStyle -> If[ellipse[Sequence @@ p, a, b, \[Alpha] \[Degree], Sequence @@ pos] <= 1, Orange, LightBlue],
PlotPoints -> 25]
, a, 2, 1, 5, Appearance -> "Labeled"
, b, 4, 2, 5, Appearance -> "Labeled"
, \[Alpha], 0, 180, Appearance -> "Labeled"
, p, 3, 1, Automatic, ControlType -> Locator
, pos, 0, 0, Automatic, ControlType -> Locator]
【讨论】:
【参考方案4】:这里是算法,我让你开发代码:
-
确定椭圆中心与您的点之间的向量 v1
确定矢量 v1 与世界坐标中 x 轴之间的角度 a1
从 a1 中减去 phi 得到 a2,即我们在局部坐标中的矢量角
在局部坐标中以角度 a2 确定椭圆上的点 P2,不偏移 (x, y)
计算 L1 和 L2,a1 和 a2 的向量长度
评价:
-
如果 L1
如果 L1 = L2(加/减一个小公差),则该点位于椭圆上
如果 L2 > L2 点在外面
椭圆参数公式:
x = a*cos(u) y = b*sin(u)
在 -pi 和 +pi 之间对 u 有效。将 phi 添加到 u 以旋转椭圆。
上面的算法可以通过椭圆方程进行简化和优化。
祝你好运!
【讨论】:
【参考方案5】:为了处理椭圆,我更喜欢将它们转换到另一个坐标系,其中椭圆是以原点为中心的单位圆。
如果您将椭圆视为单位圆(半径 1),按 (a,b) 缩放,按 phi 旋转并按 (x,y) 变换,那么生活会变得容易得多。 如果你有那个变换矩阵,你可以用它来做一个更简单的包含查询。如果您将点变换到椭圆为单位圆的坐标系中,那么您所要做的就是进行微不足道的单位圆测试。 如果“变换”是将单位圆变换为椭圆的矩阵,那么
transformedPoint = transform.Invert().Transform(point);
pointInEllipse = transformedPoint.DistanceTo(0,0) < 1.0;
【讨论】:
以上是关于点和椭圆(旋转)位置测试:算法的主要内容,如果未能解决你的问题,请参考以下文章
dotnet C# 根据椭圆长度和宽度和旋转角计算出椭圆中心点的方法