如何找到平面上点投影的坐标

how to find the coordinate of points projection on a planar surface

希望一切顺利。我有两个numpy数组,都是space中的一些点。使用 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]])

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

提前,我非常感谢任何帮助。

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

设点为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

我了解到您需要解决两个问题:

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

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

的确,当你明确知道你的所有点都在一个平面上时,你可能只 select 三个不对齐的点并计算平面。但是你的点可能来自带有一些噪声的真实测量,你可能希望找到最适合你点的平面。

以下函数解决了寻找最适合点集合的平面的一般问题。看评论里的解释:

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

所以,其实你的点分布并不平坦(厚度明显不为零),你不能随便select三个点来解决你的问题。