【问题标题】:Preferred means for finding common tangent to a pair of ellipses in C++ [closed]在 C++ 中找到一对椭圆的公共切线的首选方法 [关闭]
【发布时间】:2015-10-18 12:46:26
【问题描述】:

我想用 C++ 来做这件事。我有两个想法可以做到这一点:

  1. 将椭圆对视为两个不同参数的参数方程,我可以根据这两个参数得到两个方程。这对方程是非线性的,都是余切、正弦和余弦的函数。 Geant4,这是我主要使用的,只有多项式
  2. 使用几何库来解决这个问题。我查看了 Boost 几何,但文档不连贯(对我而言)。话虽如此,它似乎更针对计算几何。也许我要求它做 Y,而它本来只打算做 X。

如何解决这个问题?在 python 中,这很容易,我可以在睡梦中完成。任何见解将不胜感激。自从我学习了 C++,感觉选择要使用的库本身就是一场巨大的战斗。

【问题讨论】:

  • 一对省略号的公切线是什么? (哪一个可能不止一个)添加草图示例图像。解决方案的限制是什么椭圆你有什么(轴对齐或通用)椭圆很棘手,许多几何问题我们不知道如何代数计算,而是使用数值、图形和近似方法(因为超越方程组)看起来here 例如方法如何做到这一点

标签: c++ geometry solver


【解决方案1】:

我有一些建议。你可以试试 LibreCAD,它有一个求解两个椭圆公共切线的解算器,但我对 API 一无所知。求解器求解四次方程,如果您天真地尝试找到两个椭圆的公切线,就会得到。

如果您想自己动手:借助一点理论(“圆锥曲线的范围”),您所要求的可以用线性代数(即求 3x3 矩阵的逆)加上求解二次方程和一个三次方程。它是这样的:

你可以用矩阵方程的形式表达任何圆锥(比如椭圆)

        [m00 m01 m02] [x]
[x,y,z] [m10 m11 m12] [y] = 0
        [m20 m21 m22] [z]

其中矩阵M 是对称的,[x,y,z] 是齐次坐标;想想z=1。我们可以将该等式简写为X M X^T = 0,其中X^TX 的转置。

平面中的线可以写成lx+my+nz=0 的形式,因此具有“线坐标”(l,m,n)

上述圆锥的切线集可以用这种符号非常简单地表示。让A 是矩阵M 的逆矩阵。那么圆锥的切线集是

        [a00 a01 a02] (l)
(l,m,n) [a10 a11 a12] (m) = 0
        [a20 a21 a22] (n)

现在假设我们有第二个带有矩阵N 的圆锥曲线,而N 有逆矩阵B。公切线将满足上述方程和方程

        [b00 b01 b02] (l)
(l,m,n) [b10 b11 b12] (m) = 0
        [b20 b21 b22] (n)

事实上,我们可以将后一个方程中的矩阵乘以t,它仍然成立:

          [b00 b01 b02] (l)
(l,m,n) t [b10 b11 b12] (m) = 0
          [b20 b21 b22] (n)

将第一个二次曲线的切线方程添加到第二个二次曲线的上述方程中,我们得到矩阵方程L (A + tB) L^T = 0。因此,两个圆锥曲线的任何公切线都是“范围”A + tB 中每个圆锥曲线的公切线。

现在是大简化的想法:我们可以在该范围内找到一些非常特殊的圆锥曲线,“退化”圆锥曲线,它们只是点对。由于公切线必须通过所有二次曲线,因此它们必须通过简并二次曲线。但是很容易找到通过退化圆锥曲线的线,因为这样的圆锥曲线只是点对!

您可以通过求解三次方程 det(A + tB) = 0 来找到简并圆锥曲线,其中 det() 是 3x3 矩阵的行列式。三次可以通过卡尔达诺公式或变体以封闭形式求解,或者如果您需要,也可以通过数值求解。一旦你找到产生退化圆锥曲线的t 的值,你可以将方程L (A + tB) L^T = 0 分解为两个线性因子。每个线性因子xl + ym + zn = 0 定义齐次坐标[x,y,z] 或笛卡尔坐标(x/z,y/z) 中的一个点。您应该以这种方式获得三个点对(六分)。通过这些点对中的某些线将得到您的四个(最多)切线。

这是一个简单的例子(两个椭圆的中心都在原点):找到x^2+2y^2=3x^2+14y^2=7 的公共切线。矩阵形式的圆锥是

        [1 0  0] [x]               [1  0  0] [x]
[x,y,z] [0 2  0] [y] = 0,  [x,y,z] [0 14  0] [y] = 0
        [0 0 -3] [z]               [0  0 -7] [z]

切线由下式给出

        [6 0  0] (l)               [14 0  0] (l)
(l,m,n) [0 3  0] (m) = 0,  (l,m,n) [ 0 1  0] (m) = 0
        [0 0 -2] (n)               [ 0 0 -2] (n)

注意我将逆矩阵乘以一个标量只是为了使条目成为整数而不是有理数。您不必这样做,但它使手工计算更容易。将第二个矩阵乘以一个额外的标量 t 得到

        [6+14t 0    0   ] (l)
(l,m,n) [0     3+t  0   ] (m) = 0
        [0     0   -2-2t] (n)

(6+14t)(3+t)(-2-2t)=0,即t=-3/7, -3, -1,圆锥是退化的。当t=-3/7 我们得到 ​​p>

18/7 m^2 - 8/7 n^2 = 2/7 (9 m^2 - 4 n^2) = 2/7 (3m - 2n)(3m + 2n) = 0

这对应于齐次坐标[x,y,z] = [0,3,-2][0,3,2]的点,即笛卡尔坐标(0,-3/2)(0,3/2)的点。

t=-3 时,我们得到-36l^2 + 4n^2 = (6l+2n)(-6l+2n) = 0,点[6,0,2][-6,0,2] 或在笛卡尔坐标中(3,0)(-3,0)。最后,当t=1 时,我们得到-8l^2 + 2m^2 = 2(2l+m)(-2l+m) = 0 对应于点[2,1,0][-2,1,0],它们是无穷远处的点。

暂时避开无穷远点,只是因为它们更难处理,我们通过以下点对得到四行:

{(0,-3/2),(-3,0)}, {(0,-3/2),(3,0)}, {(0,3/2),(-3,0)}, {(0,3/2),(3,0)}

这给了我们两个椭圆的四个公切线。

从图中可以看出,公切线也通过无穷远点[2,1,0][-2,1,0],即平行线对有斜率1/2-1/2

是不是很漂亮?

【讨论】:

  • 我有一个关于倒数第二步的问题:一旦你找到产生退化圆锥的 t 值,你可以分解方程 L (A + tB) L^T = 0 成两个线性因子。 你这是什么意思?抱歉,如果这对您来说似乎微不足道,但是我的线性代数游戏有点生疏。在此之后,就是将两个单独的点相互连接起来,其中最多有 4 个是公切线,对吗?不过谢谢,我喜欢这个解决方案的优雅(当然,一旦我完全理解它!)
  • 嗨,我已经考虑了更多,似乎在您的建议示例中由 det(A+Bt)=0 生成的圆锥曲线当然是退化的,但没有一个是点。两对是平行线,一对是相交线。我想我一定错过了什么。谢谢。
  • 方程 L (A + tB) L^T = 0 是包含项 l^2, m^2, n^2, lm 的二次形式, mn, nl。通常(当二次形式的图形是非退化二次曲线时)该形式不会分解为两个线性因子。当形式退化(矩阵的行列式消失)时,形式因子。您可以考虑的一种方法是使用二次公式:例如,将 l 视为变量,将 m,n 视为常数。您对连接点是正确的; 6 个点给出 15 对,其中 3 个是不相关的(来自同一个 t 的点)。其他 12 个中有 4 个给出公切线。
  • @rooms:关于退化的线圆锥曲线如何定义点:您正在考虑退化的点圆锥曲线是如何成对的线。我们这里有退化的线圆锥曲线,它们是点对。情况是双重的。这可能会让人感到困惑,因为人们似乎忘记了对偶、线圆锥和射影几何中的其他美丽想法。我什至找不到过去 100 年出版的单一综合参考资料,尽管我确实从 Google 图书的一本旧书中提取了示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-02
  • 1970-01-01
  • 2015-08-18
  • 1970-01-01
  • 1970-01-01
  • 2018-11-07
  • 1970-01-01
相关资源
最近更新 更多