2011-10-30 131 views
10

如何测试点P = [xp,yp]是在由中心C = [x,y],a,b和phi(旋转角度)?点和椭圆(旋转)位置测试:算法

此时我正在使用以下解决方案:旋转椭圆并指向角度-phi,然后对点和“非旋转”椭圆进行常规测试。

但有很多测试点(数千),我觉得这个解决方案很慢。有没有直接和更有效的方法来获得旋转的椭圆和点的位置?

我不需要代码,但算法。谢谢你的帮助。

+0

向我们展示迄今为止所做的一切。一些我们可以帮助你的东西。 – sjngm

回答

18

另一种选择是将所有内容都放入2D旋转椭圆的公式中,并查看结果是否小于1。

因此,一个点是椭圆内,如果下面的不等式是真

ellipse equation

凡(XP,YP)是点坐标和(X0,Y0)是椭圆的中心。

我实现了一个小数学程序证明这确实是工作原理: Manipulate screen shot

这是在行动:

Animation

这里是代码:

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}] 
6

要处理椭圆,我宁愿将它们转换为椭圆是以原点为中心的单位圆的另一个坐标系。

如果您看到椭圆为单位圆(半径1),由(a,b)缩放,由φ旋转并由(x,y)转换,则生活变得更容易。 如果您有该变换矩阵,则可以使用它来执行更容易的遏制查询。如果您将点转换为椭圆为单位圆的坐标系,则您只需要进行单位点圆测试,这是微不足道的。 如果“改造”是是一种把单位圆到您的椭圆所描述的矩阵,那么

transformedPoint = transform.Invert().Transform(point); 
pointInEllipse = transformedPoint.DistanceTo(0,0) < 1.0; 
1

这里的算法,我让你开发的代码:

  1. 确定的矢量v椭圆形的中心,你的观点
  2. 确定角度A1矢量V1与x轴之间的世界,从A1坐标
  3. 披。减去拿到A2,我们在本地坐标矢量角
  4. 在本地坐标角α2确定椭圆点P2,而不是由(X,Y)偏移
  5. 计算L1和L2,A1的矢量长度和a2

评价为:

  1. 如果L1 < L2的点是内部
  2. 如果L1 = L2(加/减小公差)的点在椭圆
  3. 如果L2> L2的点是外

椭圆参数的公式:

X = A * COS(U)
Y = B * SIN(U)

有效Ü-pi和+ PI之间。将phi添加到u以旋转您的椭圆。

上面的算法可以从椭圆方程简化和优化。

祝你好运!

9

您可以简单地将数据提供给上述公式。这里是一个Python实现我的Ajasja的建议提出:

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 
+0

Thx为更正! – Raoul

+0

请勿使用'math.pow(val,2)'来表示一些东西。这真的很慢。 (将其分配给一个变量并自行乘以)。 –

0

Matplotlib有补丁的类内的椭圆方法,它允许你要问的问题,如果一个点是在室内还是室外的补丁。检查here并查找contains_point()方法。你将需要用Ellipse类创建椭圆,然后好像里面有一个点。 顺便说一下,matplotlib是一个python包。