首页 > 解决方案 > 如何根据python中的一些平面分割3D中的一些点

问题描述

在 3D 空间中,我有一些点 (和) x,并希望通过重建一些现有平面来拆分它们。这些是我的简化点:yz

points=[[np.array([[20., 20., 60.], [20., 30., 65.], [55., 30., 80.], [80., 10., 60.]]),\
         np.array([[20., 10., 55.], [60., 30., 70.], [70., 15., 20.]])]]

大列表有一个包含两个数组的子列表。我现实points有更多的子列表,每个子列表也可能有几个数组。然后,在这个简化的例子中,我在点之间有两个平面。我有两个表面的四个角:

four_corners= [[np.array([[50., 5., 5.],
                          [50., 45., 5.],
                          [70., 45., 95.],
                          [70., 5., 95.]]),
                np.array([[30., 5., 95.],
                          [30., 45., 95.],
                          [60., 5., 5.],
                          [60., 45., 5.]])]]

four_corners有一个子列表,这个子列表也有两个数组,即两个表面。然后,第一个子列表的每个数组points应该分为三个部分,因为有两个表面正在穿过它们。如果有一个平面,我将对每个阵列进行两次拆分。我想根据曲面拆分我的观点。我试图修改这个解决方案,但我无法达到我想要的。我尝试了以下代码,但没有成功:

splitted_arr=[]
for m in points:
    for surfaces in four_corners:
        for i, j in zip (m, surfaces):
            j=np.array(j)
            corners = [j[0], j[1], j[2]]
            v1 = np.subtract(corners[1], corners[0])
            v1 = v1 / np.linalg.norm(v1)
            v2 = np.subtract(corners[-1], corners[0])
            v2 = v2 / np.linalg.norm(v2)
            orth = np.cross(v1, v2)
            for p in i:
                p_moved = np.subtract(p, corners[0])
                d = np.dot(orth, p_moved)
                if d < 0:
                    splitted_arr.append (p)
                else:
                    splitted_arr.append (p)

我想得到:

[[np.array([[20., 20., 60.], [20., 30., 65.]]), np.array([[55., 30., 80.]]), np.array([[80., 10., 60.]]),\
  np.array([[20., 10., 55.]]), np.array([[60., 30., 70.]]), np.array([[70., 15., 20.]])]]

关键规则是我想总是使用现有的平面来分割我的点。在此之前,我非常感谢任何帮助和贡献。

标签: pythonarraysalgorithmgeometryplane

解决方案


你的方法的一般原则似乎是合理的。您在案例区分的每个分支中都调用了这一事实,这一事实splitted_arr.append (p)几乎没有实际意义。所以说这是你的主要问题。

一些观察:

  • 请注意,您从未使用过j[3]. 因此,您可以通过仅使用三个点而不是四个点来定义平面来简化事情,这样做可以消除 for 点不位于单个平面上的不一致的可能性。

  • 您可能希望计算ortho循环外的每个表面点,以减少重复计算并提高性能。

  • 您的应用程序不需要将每个v1,除以长度的标准化步骤,因此您可以省略它。v2这将影响结果的大小,但不会影响符号。

  • 与其corners[0]在 for 乘积之前进行减法,不如从 for 乘积的结果中减去该乘积的 for 和p(ie np.dot(orth, corners[0]))。这用标量减法代替向量减法。或者,更好的是,与其减去该数字并与零进行比较,不如立即与该数字进行比较。同样,拐角的点积是您可以在所有点的循环之外计算的东西。所有这些都将有助于提高性能而不改变结果(除了可能的舍入差异)。

为每个平面预先计算ortho矢量和角点积在概念上与将其转换为标准形式相同,即为平面上的每个点找到a, b, c, d这样的。a*x+b*y+c*z=d对于那些没有在 numpy 库上构建的读者来说,这种表述可能特别有吸引力。

在您的问题中,您写下(我的重新格式化除外)您想得到

[[np.array([[20., 20., 60.], [20., 30., 65.]]),
  np.array([[55., 30., 80.]]),
  np.array([[80., 10., 60.]]),
  np.array([[20., 10., 55.]]),
  np.array([[60., 30., 70.]]),
  np.array([[70., 15., 20.]])]]

为什么?为什么前两个点在一个组中,而其他所有点都是分开的?你真的想再次将多个点组合成一个二维数组吗?

在下面的评论中,您写道,表达相对于多个平面的关系是使这变得困难的部分原因。本质上,给定一个点和一个(定向的)平面列表,您可以决定该点是在这些平面中的每一个的正侧还是负侧(忽略完全在平面上的情况,由于舍入原因应该无论如何都不要依赖)。因此,对于每个点和平面,您会获得一些相关信息,对于此类平面的列表,您会获得这些比较结果的列表。您可以将它们用作键来对未被任何平面相互分离的点进行分组。选择每个平面的哪一侧是正面的,哪一侧是负面的并不重要,只要它始终如一地完成,即每个ortho只计算一次或至少总是以相同的方式计算。

https://ideone.com/oo5GFg有一个将所有内容组合在一起的工作示例。


推荐阅读