如何找到平面上点投影的坐标
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三个点来解决你的问题。
希望一切顺利。我有两个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, 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三个点来解决你的问题。