重叠分裂三角形

时间:2011-04-13 19:54:13

标签: geometry 2d

我有一个三角形(红色,下面)。 (或二维网格的三角形)

如何计算从第一个三角形中减去第二个三角形(绿色)所产生的多边形(并进而细分它们)?

enter image description here

(我正在使用Python,我正在寻找可以采用的方法的解释和伪代码,而不是针对不透明库的建议。(我目前使用gluTess*()来进行多边形的镶嵌,但是如何自己进行测试的解释会很有趣;我迫切的问题实际上是布尔操作本身。)学习和理解解决方案会很令人兴奋。我的三角形总是逆时针缠绕,如果这样做的话任何差异。)

4 个答案:

答案 0 :(得分:3)

我确信你可以找到可以应用的通用多边形减法,裁剪和三角剖分算法,但由于你只限于三角形,所以应用更简单的方法。

基本方法是扩展第二个(绿色)三角形的边缘,将它们视为无限的线条,然后将原始(红色)三角形分割三次,每个绿色边缘与红色三角形相交一个,保持不变红色三角形外的部分。算法:

resultSet := {}   // set of triangles
currentPoly := originalTriangle
for each edge E of secondTriangle:
    if E intersects currentPoly (*):
        Extend edge E to line L
        Split currentPoly by L into outerPoly and otherPoly (**)
        // outerPoly is on the side corresponding to the outside
        // of secondTriangle (right side if going CCW)
        resultSet += triangulatation of outerPoly (***)
        currentPoly := otherPoly
if resultSet is empty:
    resultSet := originalTriangle // no intersections

(*)如果线段与任何多边形边相交或者它完全包含在多边形中,则线段与多边形相交。对于此算法,最好将重合线视为不相交(因为不会发生分割)。

(**)用线分割凸多边形的算法

result := [[],[]]   // two empty lists of points
intersectionCount = 0
for each point P in the polygon:
    // each point is added to one of the result polygons
    result[intersectionCount % 2] += P
    E := edge between P and the next point Q
    if E intersects L at R:
       // each intersection point is added to both result polygons
       if R is not equal to P:
           result[intersectionCount % 2] += R
       intersectionCount += 1
       if R is not equal to Q:
           result[intersectionCount % 2] += R

(***) outerPoly将始终是一个三角形或四边形,因而无法进行三角测量。

答案 1 :(得分:3)

让我们来看看一些场景......

案例1 :三角形不重叠(或者它们相切但不重叠) Case 1

使用point-in-polygon algorithm测试这种情况,以查看其中一个三角形的三个顶点中是否有任何一个位于另一个之内或之中。

如果我们在案例1中,我们不需要做任何事情。

案例2 :绿色三角形位于红色三角形内部。

Case 2

通过使用多边形点算法来测试这种情况,以查看所有三个绿色顶点是否都在红色三角形内。另一种测试方法是查看绿色三角形的3个线段中的任何一个是否与红色三角形的3个线段中的任何一个相交;使用这样的algorithm进行交叉(另外你还要检查以确保多边形内部至少有一个绿色顶点 - 只是为了确保你没有相交的线不是因为你实际上遇到了Case 1)。

现在,对于这种情况,从每个绿色顶点到每个红色顶点(总共9个新线段)绘制一个线段。如果这些新线段中的任何一个穿过绿色三角形然后将其移除(您可以通过对每个绿色三角形边使用线段交叉方法来检查)。现在,测试是否有任何剩余的新线段相互交叉;如果有任何两个,那么消除一个,然后重新测试,直到你没有更多的新线段相互交叉。

Case 2 - Solving

案例3 :绿色三角形与红色三角形重叠,绿色三角形的两边进入红色三角形,并留下红色三角形。

Case 3

通过检查确切的两个绿色边与两个红色边相交来测试这种情况。再次使用线段交叉算法。

现在,对于这种情况,从每个交叉点(绿色边与红色边相交的每个位置)绘制一个线段到每个红色顶点。如果这些线段中的任何一个基本上复制了红色边缘,则将其删除。如果这些新线段中的任何一个穿过绿色三角形然后将其移除(您可以通过对每个绿色三角形边使用线段交叉方法来检查)。现在,测试是否有任何剩余的新线段相互交叉;如果有任何两个,那么消除一个,然后重新测试,直到你没有更多的新线段相互交叉。

Case 3 - Solving

案例4 :绿色三角形与红色三角形重叠,绿色三角形的两边进入红色三角形,但不会将红色三角形留在另一边。

Case 4

通过检查确切的两个绿色边与正好一个红色边相交来测试这种情况(每个边不一定必须是相同的边)。再次使用线段交叉算法。

现在对于这种情况,从红色三角形内部的绿色顶点绘制线段(使用多边形点算法确定三角形内部的哪个绿色顶点)到每个红色三角形顶点。

enter image description here

案例5 :绿色三角形与红色三角形重叠,只有绿色三角形的一边进入红色三角形,同一绿色边出现红色三角形的另一边。

enter image description here

通过检查确切的一个绿色边与正好两个红色边相交来测试这种情况。再次使用线段交叉算法。

现在,对于这种情况,从每个交叉点(绿色边与红色边相交的每个位置)绘制一个线段到每个红色顶点。如果这些线段中的任何一个基本上复制了红色边缘,则将其删除。如果这些新线段中的任何一个穿过绿色三角形然后将其移除(您可以通过对每个绿色三角形边使用线段交叉方法来检查)。现在,测试是否有任何剩余的新线段相互交叉;如果有两个,那么消除一个,然后重新测试,直到你没有更多的新线段相互交叉。

Case 5 = Solving

希望此时你已经完成了!

答案 2 :(得分:2)

这个问题的第一步是在将绿色三角形放在上面之后隔离红色三角形的区域。

一旦你有了这些不同的形状(在上面的例子中,一个4面形状和一个3面形状),你将从你的“需要计算”列表中删除所有3面的形状(因为它们已经是三角形)。

接下来,你应该留下一个形状或没有形状(你可以在一个三角形重叠在另一个之上时只有一个或两个形状)但实际上,如果你想要一个更通用的方法,你可以应用这个你剩下的所有形状(三角形之后)。现在隔离每个形状的顶点,并顺时针或逆时针给它们一个顺序。从顶点1开始,然后转到顶点1 + 2并尝试绘制一条线以生成三角形(检查边界问题,例如在原始三角形的边界外绘制一条线)。如果遇到边界问题,请向上移动并尝试下一个顶点,尝试将线绘制到顶点1 + 3。关键是你要跳过最邻近的顶点并在紧跟在那个顶点之后的顶点绘制一条直线,然后再尝试所有顶点,直到再次碰到邻接。根据定义,您正在构建三角形(因为它们必须使用此方法有3个边)。

一旦你产生了一个三角形(通过成功地从一个顶点到另一个顶点画一条线),重新计算你必须分成三角形的区域的其余部分并重复这个过程,直到你只留下三角形。

这是一个(无可否认的)动画gif我用来显示方法: Animated gif of method

答案 3 :(得分:2)

也许是一种愚蠢的方法,但是已经很晚了,经过10个小时的工作后我的大脑就超载了:

  1. 将所有三角形合并为多​​边形(可能有孔)。
  2. 对多边形进行三角测量。
  3. 对于每个生成的三角形,检查它是否仅属于 到红色三角形。
  4. 合并和三角形多边形的示例: Merged triangles

    当其中一个三角形完全位于另一个三角形内时的示例: enter image description here

    在进行三角测量时,诀窍是重用完全封闭三角形中的任何点。您还将拥有一组“硬”线(绘制实线),它们代表现有三角形边的线段和“软”线(绘制的虚线),您必须通过三角测量来确定它们。

    我很确定有更好的方法可以做到这一点,但你去了......