选择由某个顶点子集包围的网格的所有面

时间:2018-04-06 13:48:05

标签: 3d geometry mesh connected-components

我很确定这是一个常见问题,但无论我如何改写,我都无法在互联网上找到任何答案。

我正在为用户创建一个用户界面,通过选择多个顶点来选择网格内的区域 更确切地说,给定一个三角形网格和一组顶点(它是网格顶点的一个子集),我想获得被顶点子集包围的所有面。

我查了几个算法,比如多边形中的点,Dijkstra算法等,但它们似乎没什么帮助。
非常感谢。

1 个答案:

答案 0 :(得分:1)

首先,您需要在网格上嵌入一个代表轮廓的闭合折线。一旦有了这个轮廓,就可以填充它的内部以获得相应的面。

轮廓线

有多种方法可以获得轮廓线。一种方法是使用像A *这样的路径查找算法来查找选择集中两个连续顶点之间的最短路径(即(v0 -> v1), (v1 -> v2) ... (vn -> v0))。这将为您提供一条折线,表示为网格的有向边。

根据用户选择行为的精确程度,您可能需要稍微清理轮廓。例如,如果轮廓包含在两个方向上遍历的边(例如v1 -> v2 -> v3 -> v2 -> v4 -> ...),则可以杀死此边对。如果您有自我交叉点,则需要进行类似的清理。

填充内部

一旦有了定向轮廓线,就可以通过宽度优先的遍历实现其内部的填充。我们的想法是从轮廓边开始,然后迭代地添加入射面。基本算法可概述如下:

Input:
    E: directed edges of the contour

O <- empty list of faces to examine
V <- empty list of visited faces    

// Initialization
for every e in E:
    calculate the face left of e (-> f)
    add f to O
    add f to V

// Do BFS
while O is not empty:
    take the first element out of O (-> f)
    for all faces g adjacent to f and not in V:
        add g to O
        add g to V

完成此过程后,所选面将位于V。然而,有一个关键部分:

calculate the face left of e

首先,网格本身应该清楚左边的右边的概念。面的顶点通常按逆时针或顺时针顺序排列(面缠绕顺序)。因此,每个非边界边{v1, v2}都存在于两个面中:一次为(v1 -> v2),一次为(v2 -> v1)。根据绕线顺序,您可以选择包含正确方向边缘的面。然后,如果你知道轮廓的缠绕顺序,这就是你需要做的。即如果您的轮廓始终是顺时针方向且网格面总是按顺时针顺序排列,那么就完成了。

如果轮廓可以在任一方向上,事情会变得复杂一些。然后,不清楚用户想要标记的部分(考虑轮廓为赤道的球体)。有两个简单的选项:

  1. 使用较小的区域
  2. 让用户在目标区域内选择一个点并使用该点。
  3. 对于这两个选项,您需要在轮廓的两个方向上进行BFS(准确地说,它们是两个独立的BFS)。出于性能原因,同时进行这两项操作是个好主意。然后,只要其中任何一个区域用完O中的打开面(选项1,此区域将是较小的区域)或者如果遇到附加点(选项2,仅为此继续BFS),您可以中止区域)。

    要有效地执行此BFS,您需要一种将边缘映射到网格上的相应面和/或邻域数据结构的方法。如果要使用后者,可能需要考虑半边数据结构