问题描述
我在 3d 空间(x、y 和 z)中有一堆点,并且想找到点之间存在的最接近表面的点。我阅读了 this solution,但无法解决我的问题。我的表面是由四个点创建的:
PRECISION = 1e-8 # Arbitrary zero for real-world purposes
def plane_from_points(points):
centroid = np.mean(points,axis=0)
_,eigenvalues,eigenvectors = np.linalg.svd(points - centroid)
if eigenvalues[1] < PRECISION:
raise ValueError("Points are aligned,can't define a plane")
normal = eigenvectors[2]
d = -np.dot(centroid,normal)
plane = np.append(normal,d)
thickness = eigenvalues[2]
return plane,thickness
我的点中有一个倾斜的(由我的无花果中的黑点显示)和一个正常的(由黄点显示)表面。曲面的角是:
surf_corners=[np.array([[1.,1.,1.],[1.5,2.,[3.,3.],[3.5,3.]]),\
np.array([[5.,4.],[5.,[7.,2.],2.]])]
第一个阵列是倾斜的,第二个阵列是正常的。这些是我想找到表面的壁橱点的点:
surrounding_points=[np.array([[2.,3.2],\
np.array([[6.,2.5],[6.,3.5],3.5]])]
surrounding_points
的第一个数组(由蓝色方块显示)的投影应该在由 surf_corners
的第一个数组创建的表面上找到,第二个数组(由红色方块显示)也与第二个表面。我的表面应该只在它的四个角之间,而不是无穷大。我的意思是计算点的 y
值不应小于或大于角点。例如,我更喜欢保持 y
的 surrounding_points
值。我的意思是第一点,我想要创建的表面的壁橱点,它的 y
值为 1
。为简单起见,我只复制了它们的 y
值等于我平面的 brders 的数据,实际上我可能在平面的 brders 之间还有其他具有 y
值的点,但我仍然想找到投影具有固定的 y
值。我尝试了以下方法来这样做,但它只是给了我一个表面的水平投影,我无法处理两个表面(当 surf_corners
和 surrounding_points
是 numpy 数组而不是 numpy 数组列表时) :
pls=[]
for i in surf_corners:
i=i.tolist()
pl,thickness= plane_from_points(i)
pls.append(pl)
point_on_surf=[]
n_iter=1
for i in range (n_iter):
a,b,c,d = pls[i][0],pls[i][1],pls[i][2],pls[i][3]
def fun(row):
row[0] = -(d + b * row[1] + c * row[2]) / a # calculates new x
return row[0],row[1],row[2] # new x and old y and z
to_be_projected=[copy.copy(surrounding_points[i])]
new_points = np.asarray(list(map(fun,[x for point in to_be_projected for x in point])))
point_on_surf.append(new_points)
为了更清楚,我上传了一张图。绿色箭头显示我想要的投影点(具有相同 y
值的最近点)。在此之前,我非常感谢任何帮助。
解决方法
我了解您需要解决以下问题:
- 给定形成平面四边形的四个 3D 点,确定这些点所在的平面。
- 将任意 3D 点投影到平面上。
- 检查投影点是否位于四边形内。
问题1.确定平面
我了解您正在使用 this answer 中的代码,因此我不会再发表任何评论。
问题 2. 投影一个点
您可以使用
计算投影点projected_point = p - np.dot(p - p0,u) * u
哪里
-
p
是项目点 -
p0
是平面上的一个点(定义四边形的点之一,它们的质心...) -
u
是平面的单位法向量
编辑:
只要平面计算方法提供平面系数 (a,b,c,d) 其中 (a,c) 是平面的法向量,也是单位向量,就可以使用:
u = plane[:3] # Plane's normal unit vector
d = plane[3] # Signed distance plane - origin of coordinates
distance = np.dot(u,point) + d # Signed distance point - plane
projected_point = point - distance * u
问题 3. 指向四边形内
我建议使用 winding number 方法。而且,如果您知道四边形是凸的,则可以利用同一链接中描述的优化。