【问题标题】:how to find the coordinate of points projection on a planar surface如何找到平面上点投影的坐标
【发布时间】:2023-04-05 16:49:02
【问题描述】:

希望一切顺利。我有两个 numpy 数组,都是空间中的一些点。使用 python,我想首先找到通过第一个数据集 (surface_maker) 的曲面,然后在创建的曲面上找到第二个数组 (contact_maker) 的投影相邻点的 x、y 和 z。 surface_maker 总是创建平面。对于投影,我只想要从相邻点到表面的垂直方向。实际上,我在这两组中都有很多要点,但我在这里复制一个简单的案例:

surface_maker=np.array([[50., 15., 46.04750574],
                        [50., 5., 45.56400925],
                        [44.83018398, 5., 25.],
                        [44.76296902, 15., 25.],
                        [50., 25., 45.56400925],
                        [44.83018398, 25., 25.],
                        [59.8336792, 5., 75.],
                        [59.71483707, 15., 75.],
                        [59.8336792, 25., 75.]])
contact_maker=np.array([[10.,  5., 70.00014782],
                        [10., 15., 70.00018358],
                        [10., 25., 70.0001955 ],
                        [30.,  5., 69.99981105],
                        [30., 15., 69.99982297],
                        [30., 25., 69.99985874],
                        [70., 5., 50.00000298],
                        [70., 15., 50.00002682],
                        [70., 25., 50.00005066],
                        [90., 5., 49.99996871],
                        [90., 15., 49.99999255],
                        [90., 25., 50.00001788]])

我尝试了几种解决方案,例如12 等。但我成功地解决了我的问题。 对我来说,将投影位置设置为 x、y 和 z 很重要。该图还显示了我想要的(如图所示,我只需要在surface_maker 创建的表面上投影contact_maker 的六个相邻点):

在此先感谢您的帮助。

【问题讨论】:

  • 所有第一个设定点是否都属于同一个平面(完全正确)?
  • @MBo,是的,他们创造了一个表面。

标签: python numpy geometry surface


【解决方案1】:

我们可以使用第一组中的任意三个非共线点来构建平面。

设点为A、B、C。首先计算向量

AB = B - A  (ab.x = b.x - a.x and so on)
AC = C - A

现在使用叉积计算法向量

N = AB x AC

如果N是零向量,那么点是共线的,我们需要选择另一个三元组

(我确信 numpy 包含所有这些向量操作的现成函数)

现在我们有了平面方程的三个分量(法向分量)

N.x * x +  N.y * y + N.z * z + D = 0

要得到第四个分量 D,只需将 A 点代入该方程

D = - (N.x * A.x +  Ny * A.y + Nz * A.z)

似乎您的投影是沿 OX 轴进行的。在这种情况下,对于任何点 Q,我们可以很容易地 求投影到平面求解

N.x * x +  N.y * Q.y + N.z * Q.z + D = 0
x = -(N.y * Q.y + N.z * Q.z + D) / N.x

对于未知的x,而投影的y和z坐标等于Q.y和Q.z

import numpy as np

S = np.array([[50., 15., 46.04750574], [50., 5., 45.56400925], [44.83018398, 5., 25.]])
AB = S[1] - S[0]
AC = S[2] - S[0]
N = np.cross(AB, AC)
D = - (N[0] * S[0][0] +  N[1] * S[0][1] + N[2] * S[0][2])
Q = np.array([10.,  5., 70.00014782])
x = -(N[1] * Q[1] + N[2] * Q[2] + D) / N[0]
print(x,Q[1],Q[2])

>>> 56.143273867965505 5.0 70.00014782

【讨论】:

  • 亲爱的@MBo,我非常感谢您提供的信息提示。你知道有什么方法可以将你的方法翻译成 python 吗?我是 python 的大佬。
  • @Ali_d 我对 numpy 不熟悉,所以只是用谷歌搜索了numpy cross product 并为您的一个观点画了一个草图 - 我上面的描述的字面实现(不要忘记检查零等等开)
  • 感谢您的示例。我很感激。我将此结果与另一个应用程序一起使用。在那个应用程序中,我只使用surface_maker 的四个角来创建一个表面。我在那个应用程序中需要这个投影。我可以用四个角制作我的表面吗?因为我想模仿精确的表面。对不起这个问题。它现在就出现在我的脑海里。你问我这件事,我说了所有要点。
  • 使用三个点足以定义一个平面。第四个角不能帮助更好
  • 是的,您可以连接角 - 用于绘图目的,但要计算坐标,您需要平面方程。我给出了非常简单的方法来找到这个方程。
【解决方案2】:

我知道您需要解决两个问题:

  • 找到适合点集合的平面
  • 将第二组点沿特定方向投影到该平面上

第二个问题已在另一个答案中得到充分解决,因此我正在为第一个问题提供更通用的方法。

确实,当您确定所有点都位于一个平面上时,您可以只选择三个未对齐的点并计算平面。但是您的分数可能来自带有一些噪音的真实测量结果,您可能希望找到最适合您的分数的平面。

以下函数解决了寻找最适合点集合的平面的一般问题。参见 cmets 中的解释:

import numpy as np
PRECISION = 1e-8    # Arbitrary zero for real-world purposes

def plane_from_points(points):
    # The adjusted plane crosses the centroid of the point collection
    centroid = np.mean(points, axis=0)

    # Use SVD to calculate the principal axes of the point collection
    # (eigenvectors) and their relative size (eigenvalues)
    _, values, vectors = np.linalg.svd(points - centroid)

    # Each singular value is paired with its vector and they are sorted from
    # largest to smallest value.
    # The adjusted plane plane must contain the eigenvectors corresponding to
    # the two largest eigenvalues. If only one eigenvector is different
    # from zero, then points are aligned and they don't define a plane.
    if values[1] < PRECISION:
        raise ValueError("Points are aligned, can't define a plane")

    # So the plane normal is the eigenvector with the smallest eigenvalue
    normal = vectors[2]

    # Calculate the coefficients (a,b,c,d) of the plane's equation ax+by+cz+d=0.
    # The first three coefficients are given by the normal, and the fourth
    # one (d) is the plane's signed distance to the origin of coordinates
    d = -np.dot(centroid, normal)
    plane = np.append(normal, d)

    # If the smallest eigenvector is close to zero, the collection of
    # points is perfectly flat. The larger the eigenvector, the less flat.
    # You may wish to know this.
    thickness = values[2]

    return plane, thickness

你可以检查一下:

>>> surface_maker=np.array([[50., 15., 46.04750574], [50., 5., 45.56400925], [44.83018398, 5., 25.], [44.76296902, 15., 25.], [50., 25., 45.56400925], [44.83018398, 25., 25.], [59.8336792, 5., 75.], [59.71483707, 15., 75.], [59.8336792, 25., 75.]])
>>> plane, thickness = plane_from_points(surface_maker)
>>> print(plane)
[-0.95725318  0.          0.28925136 35.2806339 ]
>>> print(thickness)
1.3825669490602308

所以,事实上,你的点分布并不平坦(厚度明显不同于零),你不能随便选择三个任意点来解决你的问题。

【讨论】:

  • 亲爱的@aerobiomat,我非常感谢您的解决方案。很抱歉,我答复晚了。我看到很晚。如果我只对四个角而不是所有点使用你的方法会发生什么?当我使用四个角时,我应该保持厚度还是必须为零?再次对我迟到的反馈表示歉意。
  • 在很少的点上使用这种方法似乎有点矫枉过正,但它适用于任意数量的点(它会在小于 3 点或对齐点时引发 ValueError)。有四个点它也会给你一个“厚度”值。但是,仅从原始集合中选择几个点将产生具有更高可变性的结果。但是,如果您只想使用四个点,您可以使用三个点计算平面,然后检查从第四个点到平面的距离,以确保它们都位于平面上。
  • 亲爱的@aerobiomat,非常感谢您的帮助。您的解决方案是给我平面方程,我只需要替换生成平面方程上的 y 和相邻点即可找到投影。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-27
  • 1970-01-01
  • 2020-11-04
  • 2010-10-12
  • 2018-06-13
  • 2022-11-28
相关资源
最近更新 更多