找到椭圆的所有4个法线

Tim*_*sov 5 math geometry ellipse computational-geometry

给定轴向对齐的,原点居中的椭圆E外部的点p,找到通过p的E的(最多)四个唯一法线.

这不是Mathematica的问题.直接计算太慢; 我愿意为速度牺牲精度和准确性.

我在网上搜索过,但我发现所有涉及过于复杂的计算,如果直接实现,似乎缺乏我需要的性能.有没有更"程序化"的方法来做到这一点,比如使用矩阵或将椭圆缩放成圆形?

har*_*ath 5

假设椭圆E位于"标准位置",中心位于原点,轴平行于坐标轴:

    (x/a)^2 + (y/b)^2 = 1   where a > b > 0
Run Code Online (Sandbox Code Playgroud)

边界情况a=b是圆形,其中法线简单地穿过中心(原点)并因此容易找到.所以我们省略了对这些案例的讨论.

任何点处椭圆的切线斜率(x,y)可以通过隐式微分找到:

    dy/dx = -(b^2 x)/(a^2 y)
Run Code Online (Sandbox Code Playgroud)

对于穿过(x,y)的线和p = (u,v) 不在椭圆上的指定点,E当椭圆的斜率为负倒数时,这与椭圆是垂直的dy/dx:

    (y-v)/(x-u) * (-b^2 x)/(a^2 y) = -1       (N)
Run Code Online (Sandbox Code Playgroud)

这简化为:

    (x - (1+g)u) * (y + gv) = -g(1+g)uv  where g = b^2/(a^2 - b^2)
Run Code Online (Sandbox Code Playgroud)

在这种形式中,我们认识到它是一个正确的矩形双曲线的等式.根据路口的多少分有椭圆形和双曲线(2,3,4)之间,我们有很多法线E穿过p.

通过反射对称性,如果p假设在外部E,我们可能需要p处于第一象限:

    (u/a)^2 + (v/b)^2 > 1    (exterior to E)
          u,v > 0            (1'st quadrant)
Run Code Online (Sandbox Code Playgroud)

我们可以有边界情况,u=0或者v=0,即点p位于轴上E,但是这些情况可以简化为求解二次方,因为两个法线是通过该轴的端点的(重合)线.我们暂时推迟对这些特殊情况的进一步讨论.

这是一个插图,a=u=5,b=v=3其中只有双曲线的一个分支相交E,并且只有两个法线:

椭圆与双曲线

如果将两个未知数中的两个方程的系统(x,y)简化为一个未知的一个方程,则最简单的编码寻根方法是二分法,但了解根/交叉点的可能位置将加速我们的搜索.在第一象限的交点是的最近点Ep,并且同样地在第三象限的交点是的最远点Ep.如果该点p更接近于短轴的上端点,则双曲线的分支将足够移动以在第四象限中创建多达两个交叉点.

一种方法是E通过与x轴的交点进行参数化.从p法线到椭圆的线必须与长轴相交,长轴是有限间隔[-a,+a].我们能够同时测试交叉点的上点和下点q=(x,y)穿过线p=(u,v)(z,0)作为z从扫描-a+a,寻找其中椭圆和双曲线相交的地方.

更详细:

1. Find the upper and lower points `q` of intersection of E with the
   line through `p` and `(z,0)` (amounts to solving a quadratic)

3. Check the sign of a^2 y(x-u) - b^2 x(y-v) at `q=(x,y)`, because it
   is zero if and only `q` is a point of normal intersection
Run Code Online (Sandbox Code Playgroud)

一旦检测到符号变化的子区间(上部或下部),就可以对其进行细化以获得所需的精度.如果只需要适度的准确性,则可能不需要使用更快的根查找方法,但即使需要它们,使用隔离根(或第四象限中的根对)的短子区间也是有用的.

**更多比较各种方法的收敛**