PaperRead - Efficient Booleans algorithms for triangulated meshes of geometric modeling

Paper - Efficient Booleans algorithms for triangulated meshes of geometric modeling

https://www.researchgate.net/publication/290466350_Efficient_Booleans_algorithms_for_triangulated_meshes_of_geometric_modeling

Jiang X, Peng Q, Cheng X, et al. Efficient Booleans algorithms for triangulated meshes of geometric modeling[J]. Computer-aided Design and Applications, 2016, 13(4): 419-430.

更多introduction的介绍可以直接看原文,这里主要介绍文中使用的具体实现。

2. Methods

更个过程分为两个阶段:两个mesh之间的相交检测和布尔运算。如下图Fig2。

这篇文章的主要贡献点如下:

  1. 利用八叉树对两个网格的公共空间进行划分,以加快交叉点检测的速度,减少内存占用;
  2. 分析了浮点运算误差和交叉口奇异性,提高了算法的稳定性;
  3. 为了实现并、交、差运算,提出了基于相交三角形的稳定技术。该方法对封闭网格和开放网格都是快速的;
  4. 该算法具有较强的鲁棒性,可用于含有大量布尔差分运算的铣削仿真系统中;

2.1 相交检测

相交检测在布尔运算中是很重要的一布。

2.1.1 Building Octree of the common space

对于两个相交的mesh而言,相交部分的空间的大小是小的。octree能够利用空间划分加速相交测试。

给定两个网格\(S_A\)\(S_B\)\(Box_A\)\(Box_B\)分别为\(S_A\)\(S_B\)的最小AABB。公式如下:

\[Box_A = \bigg ( \begin{array}{l} x_{Amax},y_{Amax},z_{Amax} \\ x_{Amin}, y_{Amin}, z_{Amin} \end{array} \bigg ) \]

\(Box_B\)可以用相同方式计算。两个的交集如下:

\[Box_A \cap Box_B = \bigg ( \begin{array}{l} min(x_{Amax}, x_{Bmax}), min(y_{Amax}, y_{Bmax}), min(z_{Amax}, z_{Bmax}) \\ max(x_{Amin}, x_{Bmin}), max(y_{Amin}, y_{Bmin}), max(z_{Amin}, z_{Bmin}) \end{array} \bigg ) \]

为了保证能够把相交三角形都包含在内部,对上面的式子进行了扩展,如下:

\[Box_A \cap Box_B = \bigg ( \begin{array}{l} min(x_{Amax}, x_{Bmax}) + l, min(y_{Amax}, y_{Bmax}) + l, min(z_{Amax}, z_{Bmax}) + l \\ max(x_{Amin}, x_{Bmin}) - l, max(y_{Amin}, y_{Bmin}) - l, max(z_{Amin}, z_{Bmin}) - l \end{array}\bigg ) \]

其中\(l\)\(S_A\)\(S_B\)中的最长边。

2.1.2 Floating point arithmetic errors and singularity of intersections

浮点运算在计算几何中是不可避免的。尤其是布尔运算,在计算相交性的时候会经常用到。浮点运算会导致求交的不连续性,从而进一步导致布尔运算的失败。

布尔运算相关的相交计算,可以认为是很多的ray-triangle之间的测试。将一条射线与一个三角形相交比普通的“解决方案”问题要大得多。

上图说明了为什么浮点运算会引起最后结果计算失败。也展示了如何进行鲁棒性更强的计算。图4a所示,一条射线与\(\triangle abc\)\(\triangle abd\)的公共边ab相交。由于浮点计算误差的存在,可能出现这种情况,在计算\(\triangle abc\)和射线R的交点的时候,计算出点p稍微在ab的右边,在计算\(\triangle abd\)和射线R的交点的时候,计算出点p稍微在ab的左边。这样判断的结果是射线和\(\triangle abc\)\(\triangle abd\)都不相交。为了使得检测具有更高的鲁棒性,将射线认为是“fat”点的几何体。图4d所示。

fat test就是容忍度的问题。如图e所示,计算的时候得到两条线的交点为\(P(x',y')\),给定容忍度\(\epsilon\),P左边的直线的距离小于容忍度,就认为点在左边的直线上。

交叉点的奇异性也会破坏相交计算。奇异性通常发生在边和面之间具有不同的角度的时候。四面体的一条边和top面以很大的角度相交,而和front面以较小的角度相交。这两个面共享ef边。在相交检测的时候,m点到ef边的距离为d1小于容忍度,m*和ef边的距离d2大于容忍度,但对于上表面而言,点m位于ef边上,这样就产生了奇异性。这样四面体就和front面相交了两次,这将破坏交叉循环(???),因此算法将失败。

2.1.3 计算相交线

相交线计算的时候需要考虑两种情况,共面还是不共面,针对共面问题,可以转换为2D 三角形相交问题(注意:此处需要注意的是,针对共面的情况,有两种,一种是两个三角形共面,另一种是一个三角形的边和另一个三角形共面)。这里主要介绍不共面时候相交线的计算。为了保证交叉点的连续性,提出了一种改进的交叉点检测策略。

通常情况下,有三种相交情况(如下图所示):

  • 交点为边的顶点,EndP;
  • 在边上有一个交点,EdgeP;
  • 面内有一个交点,FaceP;

注意:下图对论文中的相交的场景,额外补充了两种场景。此时对应的相交情况如下(其中边是一个三角形的,面是另一个三角形的,令EdgeV的权重为2,EdgeP的权重为1,FaceP的权重为0):

  • 边的顶点,面内的点;EdgeVFaceP, EdgeVFaceP (2+0 = 2)
  • 边的顶点,面的顶点;EdgeVFaceV, EdgeVEdgeV (2+2=4)
  • 边的顶点,面的边上的点;EdgeVFaceE, EdgeVEdgeP (2+1=3)
  • 边上的点,面内的点;EdgePFaceP, EdgePFaceP (1+0=1)
  • 边上的点,面的顶点;EdgePFaceV, EdgePEdgeV (1+2=3)
  • 边上的点,面的边上的点;EdgePFaceE, EdgePEdgeP (1+1=2 )

同时考虑到一个边和一个面最多有一个交点相同的一个点可能被不同的相交对共享

三种交点的权重比为:EndP > EdgeP > FaceP

在上面的场景中,计算得到两个交点m和m*。他的相交计算过程可以描述如下(假设top和front都是三角形):

  • 计算边和三角形Top的交点,得到交点位于边和三角形Top的边ef上面;
  • 计算边和三角形Front的交点,得到交点位于边和三角形Front的面上;
  • 然后发现,这条边已经和三角形Front的边ef有交点了
  • 那么就需要通过交点的权重,对交点进行取舍,保留交点m;

根据相交类型m为EdgeP,m*为FaceP。因此m的权重比m*大,m*的坐标和特点被认为和m是一致的。算法的详细伪代码如下(TODO:伪代码应该需要修正):

Algorithm 1 Calculate intersection lines
for each pair of triangles (T1, T2) do
    for each edge e \in T1 do
        m = Intersection(e, T2);
		// 1.如果e和T2的交点类型为EndP,需要将e和交点周边的其他三角形的也要进行记录该交点
        // 2.如果e和T2的交点的类型为EdgeP,需要将e和边相邻的其他三角形的也需要记录该交点
		// 3.存储<edge,triangle>对应的交点
		// 4.判断e和三角形T2是不是还有其他的交点
		// 5.如果有则按照优先级,对点的特性和坐标值进行修正
        if (exist_intersection(e, T2) && m* = Intersection(e, T2))
            Properties(m) = Properties(m*) = Priority(m,m*)
            Coordinate(m*) = Coordinate(m)
    end for
    for each edge e \in T2 do
        m = Intersection(e, T1)
        if (exist_intersection(e, T1) && m* = Intersection(e, T1))
            Properties(m) = Properties(m*) = Priority(m,m*)
            Coordinate(m*) = Coordinate(m)
    end for
end for

需要对伪代码进行修正,修正后如下:

Algorithm 1 Calculate intersection lines
for each pair of triangles (T1, T2) do
    for each edge e \in T1 do
        m = Intersection(e, T2);
        // 具体实现的时候需要区分哪些是已经通过计算了的,哪些是推导出来的,为了避免后面的重复计算
		switch Case(m)
        {
		case EdgeVFaceP:
        	add edge face pair around edge v in VecIntersectionPair;
        case EdgePFaceV:
            add edge face pair around face v in VecIntersectionPair;
        case EdgeVFaceV:
            add edge face pair around edge v in VecIntersectionPair;
            add edge face pair around face v in VecIntersectionPair;
        case EdgeVFaceE:
        	add edge face pair around edge v in VecIntersectionPair;
        	add edge face pair around face e in VecIntersectionPair;
        case EdgePFaceE:
        	add edge face pair around face e in VecIntersectionPair;
        case EdgePFaceP:
        	add edge face pair in VecIntersectionPair;        	
        }

		// 判断VecIntersectionPair中是否存在交点,如果有则取出来,并对其进行更改
        // if (exist_intersection(e, T2) && m* = Intersection(e, T2))
        //    Properties(m) = Properties(m*) = Priority(m,m*)
        //    Coordinate(m*) = Coordinate(m)
    end for
    for each edge e \in T2 do
        // similar logic as above
    end for
end for

2.1.4. 对相交三角形重新三角化

相交的三角形上,通常会有多个相交线段,这些相交线段将三角形划分为多个多边形面。(如何划分??)接下来这些多边形需要被三角化。

  • Recursive ear cutting algorithm很简单容易实现,但是性能比较差,不容易扩展处理空洞的情况;
  • incremental randomized算法,性能不错,但不容易实现;
  • sweep line算法是当前使用最广泛的实现,文中采用了Poly2Tri(Wu L.: Poly2Tri: Fast and Robust Simple Polygon Trian-gulation With/ Without Holes by Sweep Line Algorithm,http://sites-final.uclouvain.be/mema/Poly2Tri/, 2005.),相关代码实现:https://github.com/greenm01/poly2tri

文中并没有指出,该如何去获取三角形之间的相交线段,该如何获取呢?

像图中的多边形,可以将其划分为多个区域然后分别采用,greenm01/poly2tri: Automatically exported from code.google.com/p/poly2tri (github.com)进行剖分。

对应的论文解析,可以参见:PaperRead - Sweep-line algorithm for constrained Delaunay triangulation - grassofsky - 博客园 (cnblogs.com)

2.2 布尔运算

文中的方法分为两部分:

  • 区分一个点是mesh内部的还是外部的;
  • 创建sub-meshes,然后进行merge;

本文中仅对属于相交三角形的点进行了区分。

2.2.1. Point classify(对相交三角形的顶点进行判断)

假设mn为\(\Delta abc\)\(\Delta def\)的交线。这两个三角形分别属于不同的mesh。\(n_{abc}\)\(n_{def}\)分别是\(\Delta abc\)\(\Delta def\)的法向量,具体为\((x_{n1}, y_{n1}, z_{n1})\), \((x_{n2}, y_{n2}, z_{n2})\)\(p(x_1,y_1,z_1)\)\(q(x_2,y_2,z_2)\)分别是\(\Delta abc\)\(\Delta def\)的上面的一个点。那么平面方程如下:

\[F_{abc}(x,y,z) = (x-x_1)x_{n1} + (y-y_1)y_{n1} + (z-z_1)z_{n1} = 0 \\ F_{def}(x,y,z) = (x-x_2)x_{n2} + (y-y_2)y_{n2} + (z-z_2)z_{n2} = 0 \]

上图中,两个三角形相交于m,n点,对a,c,e,d点的内外位置进行判断。a位于包含\(\Delta def\)的mesh的内部,d位于包含\(\Delta abc\)的mesh的内部。c,e点位于外部。对于退化的相交场景,至少一个三角形的一个点在另一个三角形对应的mesh上。当相交三角形的所有顶点都进行了判断,分别标记了“in”,“out”,“on”,下面就要进行sub-meshes的创建。

注意:此处对于点in out的判断会存在误判的情况,特别是当点位于边界的情况,针对这种情况,在计算位置的时候考虑第四种情况,UNKNOW。

2.2.2. create sub-meshes and merging them

不同类型的mesh定义:

  • \(M_A\), \(M_B\)待处理的两个mesh;
  • \(M_{AinB}\),来自\(M_A\)位于\(M_B\)内部的三角形集合;
  • \(M_{AoutB}\),来自\(M_A\)位于\(M_B\)外部的三角形集合;
  • 同理定义:\(M_{BinA}, M_{BoutA}\);
  • \(M_{onAB}\):同时属于\(M_A\), \(M_B\)的网格(共面相交的时候);

那么不同布尔操作的结果如下:

  • \(M_A \cup M_B (union):\ M_{AoutB} + M_{BoutA} + M_{onAB}\)
  • \(M_A \cap M_B (intersection): \ M_{AinB} + M_{BinA} + M_{onAB}\)
  • \(M_A - M_B(difference):\ M_{AoutB} + M_{BinA}\)

具体伪代码类似如下:

// M_new: 新的空的网格
// V'_new: the set of intersected points 交点的集合
// for each V labeled "in" && V not in M_new do  遍历网格A中标记为in的顶点V && 顶点V不在新的网格内
//   add V into a contain Ver_C 将顶点V添加到container Ver_C中
//   for each V_c in Ver_C do 遍历Ver_C中的每个点Vc
//     search all neighbouring vertexes V_nei_C and triangles T_nei_C of V_c 找到V_c的相邻的顶点和相邻的三角形
//     for each V' in V_nei_C && V' not in V'_new && V' not in M_new do
//     遍历邻域中的每个点,并且这个点不是相交点,没有被包含到新的mesh中
//       add V' into M_new; 将这个邻近点添加到新的网格中
//       add V' into Ver_C; 将这个点添加到container Ver_C中
//     end for
//     for each T' in T_nei_C && T' not in M_new do
//       add T' into M_new
//     end for
//     remove V_c from Ver_C;
//   end for
// end for

计算过程示意图如下:

注意:按照上述方法计算的时候,还需要额外考虑,部分三角形会由所有的交点组成的情况。类似如下:

绿色标记部分为交点组成的三角形,那么利用上述的生长的方法进行三角形生长的时候,并不会包含绿色区域。因此,对算法进行了改进:

M_new: 新的空的网格
V'_new: the set of intersected points 交点的集合
E'_new: 相交线段的集合
for each V labeled "in" && V not in M_new do  遍历网格A中标记为in的顶点V && 顶点V不在新的网格内
   add V into a contain Ver_C 将顶点V添加到container Ver_C中
   for each V_c in Ver_C do 遍历Ver_C中的每个点Vc
     search all neighbouring vertexes V_nei_C and triangles T_nei_C of V_c 找到V_c的相邻的顶点和相邻的三角形
     for each V' in V_nei_C do 
       if V' not in V'_new && V' not in M_new do
          遍历邻域中的每个点,并且这个点不是相交点,没有被包含到新的mesh中
          add V' into M_new; 将这个邻近点添加到新的网格中
          add V' into Ver_C; 将这个点添加到container Ver_C中
     end for
     for each T' in T_nei_C && T' not in M_new do
       add T' into M_new
       获取三角形T'中V_c的对边E_V_c
       将对边E_V_c添加到容器中E_V_c_c
       while E_V_c_c 还有值
       	  get E_V_c from E_V_c_c
          if  E_V_c有效 && E_V_c的两个顶点都是交点 && E_V_c不是相交线段 do
             add E_V_c的相邻三角形 T'' into M_new
             找到T''三角形不是相交线段的其他边**可能存在不是相交线的两条边**)赋值给 E_V_c_c
          endif
     end for
     remove V_c from Ver_C;
   end for
end for
posted @ 2020-07-23 19:32  grassofsky  阅读(386)  评论(0编辑  收藏  举报