|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +title: "New in CGAL: Fixing Self-Intersections in Triangle Soups using Snap Rounding" |
| 4 | +description: "" |
| 5 | +category: |
| 6 | +tags: [""] |
| 7 | +--- |
| 8 | +{% include JB/setup %} |
| 9 | + |
| 10 | +<h3><a href="https://geometryfactory.com/who-we-are/">Sébastien Loriot</a> & <a href="https://geometryfactory.com/who-we-are/">Léo Valque</a></h3> |
| 11 | +<h4><a href="https://geometryfactory.com/">GeometryFactory</a></h4> |
| 12 | + |
| 13 | +<br> |
| 14 | +<p><b>The second half of the work described in this post (snap rounding strategies) |
| 15 | +will be presented at <a href="https://sgp2025.my.canva.site/">SGP 2025</a> in Bilbao (June 30 - July 4, 2025)</b></p> |
| 16 | + |
| 17 | +<br> |
| 18 | +<p>Self-intersections in triangle meshes are a common source of issues in geometry processing, simulation, |
| 19 | +and 3D printing. Such defects can arise in various ways: poor design, approximate conversions, |
| 20 | +faulty outputs of mesh processing algorithms, and so on. |
| 21 | +A particularly interesting case in the latter category is <em>Boolean operations</em>, as these |
| 22 | +turn out to be both a source of self-intersections and, as we will see, |
| 23 | +a solution to them as well. |
| 24 | +</p> |
| 25 | + |
| 26 | +<div style="text-align:center;"> |
| 27 | + <a href="../../../../images/996816-self-intersections.png"><img src="../../../../images/996816-self-intersections.png" style="max-width:95%"/></a> |
| 28 | + <br><small>The model <tt>996816</tt> from the Thingi10k dataset is riddled with thousands of self-intersections</small> |
| 29 | +</div> |
| 30 | +<br> |
| 31 | + |
| 32 | +<p> |
| 33 | +Over the years, CGAL has developed its own algorithms for Boolean operations, |
| 34 | +evolving from general and robust methods to more specialized and efficient solutions |
| 35 | +(an exhaustive history can be found at the end of this post). To perform robustly, |
| 36 | +these methods all rely on exact constructions, meaning the use of arbitrary precision numbers |
| 37 | +(see also the page <a href="https://www.cgal.org/exact.html">The Exact Computation Paradigm </a>). |
| 38 | +Unfortunately, when results are brought back to the real, double-based world, |
| 39 | +self-intersections may appear.</p> |
| 40 | + |
| 41 | +<p>Resolving self-intersections in triangle meshes can be tackled in different ways (vertex |
| 42 | +displacement, complete remeshing, etc.), but these solutions have limitations in terms of scope, |
| 43 | +computational requirements, or robustness on large datasets.</p> |
| 44 | + |
| 45 | +<p>In CGAL 6.1, we introduce a new method for resolving self-intersections in triangle meshes |
| 46 | +and triangle soups, combining a novel Boolean operation function called "autorefinement" |
| 47 | +and a new iterative snap rounding strategy. <b>This approach was evaluated on |
| 48 | +the <a href="https://ten-thousand-models.appspot.com/">Thingi10k dataset</a> |
| 49 | +(nearly 10,000 models including for non-manifold and degenerate inputs) and produced intersection-free |
| 50 | +outputs for all cases, thus providing a practical way to address self-intersections in meshes |
| 51 | +for a wide range of applications</b>.</p> |
| 52 | + |
| 53 | +<br> |
| 54 | +<h3>First half of the Solution: Autorefinement of Triangle Soups</h3> |
| 55 | + |
| 56 | +<p>A question often asked by users was whether CGAL's Boolean operations |
| 57 | +(see <a href="https://doc.cgal.org/latest/Polygon_mesh_processing/index.html#title16">Corefinement |
| 58 | +and Boolean Operations"</a>) could be used to resolve self-intersections in triangle meshes, especially in solids. |
| 59 | +This led us to modify the corefinement code to create an <em>autorefinement</em> version, |
| 60 | +which refines triangles from the same mesh that are intersecting along segments not in the input. |
| 61 | +Using those intersection edges, it is now possible to apply a self-union to resolve the self-intersections |
| 62 | +of the solid.</p> |
| 63 | + |
| 64 | +<br> |
| 65 | +<div style="text-align:center;"> |
| 66 | + <a href="../../../../images/cylinder_autorefine.png"><img src="../../../../images/cylinder_autorefine.png" style="max-width:95%"/></a> |
| 67 | + <br><small>Left: A triangle mesh generated by sweeping a circle along a spiral curve; |
| 68 | + Right: A triangle mesh free from self-intersection bounding the same volume as in the left picture; |
| 69 | + On the bottom, we see the intersection curve of a plane with the triangle meshes.</small> |
| 70 | +</div> |
| 71 | +<br> |
| 72 | + |
| 73 | +<p>Autorefinement is now available in a new function, <a href="https://doc.cgal.org/6.0/Polygon_mesh_processing/group__PMP__corefinement__grp.html#gaec85370aa0b2acc0919e5f8406cfb74c">CGAL::Polygon_mesh_processing::autorefine_triangle_soup()</a>. |
| 74 | +This function takes as input a triangle soup (that is, a range of points and a range of triples of integers representing |
| 75 | +triangles using point indices), and resolves all intersections among the triangles by refining the triangles |
| 76 | +so that no triangle intersects except along a shared edge or a shared vertex. The function operates on a triangle soup |
| 77 | +and not a triangle mesh as to handle arbitrarily complex inputs (including degenerate faces |
| 78 | +and non-manifold configurations), and also to represent non-manifold output. Indeed, |
| 79 | +even configurations as simple as two triangles whose intersection is a segment will result in |
| 80 | +four triangles sharing the same edge after refining them with their intersection. |
| 81 | +</p> |
| 82 | + |
| 83 | +<p> |
| 84 | +To demonstrate the robustness and runtime efficiency of the function, we ran it over |
| 85 | +all 10,000 models from the Thingi10k repository. |
| 86 | +The computer used for the benchmark runs x86_64 Debian GNU/Linux 6.1.0-12-amd64 and features |
| 87 | +a 2016 Intel(R) Xeon(R) CPU E5-1650 v4 @ 3.60GHz with 6 threads/12 hyperthreads. |
| 88 | +The memory values are the maximum resident set size (given using the <tt>/usr/bin/time</tt> command). |
| 89 | +</p> |
| 90 | + |
| 91 | +<div style="text-align:center;"> |
| 92 | + <a href="../../../../images/autoref_runtime.png"><img src="../../../../images/autoref_runtime.png" style="max-width:95%"/></a> |
| 93 | +</div> |
| 94 | +<div style="text-align:center;"> |
| 95 | + <a href="../../../../images/autoref_mem.png"><img src="../../../../images/autoref_mem.png" style="max-width:95%"/></a> |
| 96 | +</div> |
| 97 | + |
| 98 | +<br> |
| 99 | +<h3>Second half of the Solution: A New Snap Rounding Strategy</h3> |
| 100 | + |
| 101 | +<p>Naturally, the new autorefinement function does not suffice by itself to resolve self-intersections |
| 102 | +as it suffers from the same issues as other Boolean operations: it must be performed using |
| 103 | +exact computations, but once newly created vertices are rounded back to doubles, self-intersections |
| 104 | +may appear: out the 9997 valid input files, only 9425 were free from self-intersection |
| 105 | +after autorefine and naive rounding to double. Therefore, we are left with 572 files |
| 106 | +still featuring self-intersections.</p> |
| 107 | + |
| 108 | +<div style="text-align:center;"> |
| 109 | + <a href="../../../../images/triangle_snap_error.png"><img src="../../../../images/triangle_snap_error.png" style="max-width:95%"/></a> |
| 110 | + <br><small>Illustration of rounding issues in self-intersection resolutions. The red grid represent the grid of floating point numbers. |
| 111 | + Points with floating points coordinates must lie on a vertex of the grid. <b>From left to right:</b> input triangles with floating point |
| 112 | + numbers coordinates; Resolution of intersections of triangles using arbitrary precision; Rounding new intersection points to the nearest |
| 113 | + vertex on the grid: even if the intersection is solved with arbitrary precision, the rounding using floating point coordinates |
| 114 | + induces new intersections that cannot be solved by naively iterating the process (in addition to creating new degenerate faces). |
| 115 | +</small> |
| 116 | +</div> |
| 117 | +<br> |
| 118 | + |
| 119 | +<p>The second part of our solution is a novel snap rounding strategy: based on the work of Lazard and Valque [1], |
| 120 | +the main idea behind the method is a loop that rounds vertex coordinates of triangles involved |
| 121 | +in self-intersections to integers (up to a scaling factor), eliminates degenerate |
| 122 | +elements, and resolves self-intersections again, until all self-intersections are resolved |
| 123 | +or a user-defined maximum number of iterations is reached. Even if there is no theoretical guarantee |
| 124 | +for successful termination, it performs well in practice: using the default values of the parameters for this method, |
| 125 | +all the models but one could be rounded with one call. The single remaining model, the infamous model |
| 126 | +<tt>996816</tt> (see image at the top of the post) required a few more iterations.</p> |
| 127 | + |
| 128 | +<div style="text-align:center;"> |
| 129 | + <a href="../../../../images/996816-no-self-intersections.png"><img src="../../../../images/996816-no-self-intersections.png" style="max-width:95%"/></a> |
| 130 | + <br><small>The model <tt>996816</tt> no longer intersects and a reasonable number of new vertices was needed: the input has 75k vertices and 170k faces, and the output has 100k vertices and 245k faces.</small> |
| 131 | +</div> |
| 132 | +<br> |
| 133 | + |
| 134 | +<p>From an API point of view, the function <code>CGAL::Polygon_mesh_processing::autorefine_triangle_soup()</code> |
| 135 | +has a parameter <code>apply_iterative_snap_rounding()</code> called to the autorefine |
| 136 | +function to activate a snapping strategy in order to avoid self-intersections produced while rounding the coordinates to double.</p> |
| 137 | + |
| 138 | +<br> |
| 139 | +<h3>Status</h3> |
| 140 | + |
| 141 | +<p>The new function is already integrated in CGAL's master branch on the |
| 142 | +<a href="https://github.com/CGAL/cgal/">CGAL GitHub repository</a> and |
| 143 | +will be officially released in the upcoming version of CGAL, CGAL 6.1, scheduled for summer 2025.</p> |
| 144 | + |
| 145 | +<i class="bi bi-book"></i> |
| 146 | +<a href="https://doc.cgal.org/6.1/Polygon_mesh_processing/group__PMP__corefinement__grp.html#gaec85370aa0b2acc0919e5f8406cfb74c">Documentation of the function <em>CGAL::Polygon_mesh_processing::autorefine_triangle_soup()</em></a> |
| 147 | +<br> |
| 148 | +<i class="bi bi-arrow-down-circle"></i> |
| 149 | +<a href="https://github.com/CGAL/cgal/tree/master">CGAL master branch on GitHub</a> |
| 150 | +<br><br> |
| 151 | + |
| 152 | +<h3>Bibliography</h3> |
| 153 | + |
| 154 | +[1] Sylvain Lazard and Leo Valque. Removing self-intersections in 3D meshes while preserving floating-point coordinates. Computer Graphics Forum. Vol. XX. No. X. 2025. |
| 155 | + |
| 156 | +<br> |
| 157 | +<h3>Bonus: History of 3D Boolean Operations in CGAL</h3> |
| 158 | + |
| 159 | +<p>In December 2004, CGAL 3.1 was released with the package <a href="https://doc.cgal.org/latest/Nef_3">3D Boolean Operations on Nef Polyhedra</a> |
| 160 | +It provided a robust way to compute Boolean operations on Nef Polyhedra. In particular, it enables users to perform some Boolean operations |
| 161 | +on solids bounded by surface meshes, but also on models with non-manifold features and 1D features. Even today, this package is probably |
| 162 | +the only solution in the open source world to allow this kind of operations. Unfortunately, all this genericity comes at a price. Indeed, the algorithm |
| 163 | +relies on maintaining an arrangement of circles on a sphere at each vertex of the Nef Polyhedra in order to enable those operations. |
| 164 | +This representation also requires that intersection points are strictly coplanar with the polygonal faces they describe, implying that |
| 165 | +a Kernel providing exact constructions is mandatory. |
| 166 | +</p> |
| 167 | + |
| 168 | +<p>As this genericity is not required for all applications, we decided to work on an alternative method which would be restricted to solids |
| 169 | +bounded by triangle meshes, and such that the output is manifold. In October 2012, we released an undocumented version of a new code |
| 170 | +based on corefinement of triangle meshes. With feedback from early adopters, we officially released with CGAL 4.10 in May 2017 |
| 171 | +a rewrite of the original 3D Boolean operations through corefinement (see the manual entry <a href="https://doc.cgal.org/latest/Polygon_mesh_processing/index.html#title16">"Corefinement and Boolean Operations"</a>). |
| 172 | +One of the key features of this code is the ability to compute several types of Boolean operations in one run (union and intersection, |
| 173 | +for example), and the possibility to store the result in a new mesh or directly update one of the input meshes to avoid recopying the entire |
| 174 | +mesh if only a small portion is affected. When it comes to robustness, exact constructions are used under the hood to guarantee an output |
| 175 | +with the correct topology. To demonstrate the robustness and speed of the method, we posted a <a href="https://www.linkedin.com/pulse/benchmarking-mesh-union-using-cgal-libigl-sebastien-loriot/">benchmark</a> |
| 176 | +on the <a href="https://ten-thousand-models.appspot.com/">Thingi10k data set</a> testing the code on thousands of models. |
| 177 | +</p> |
| 178 | + |
| 179 | +<p>In CGAL 4.11 (April 2018), we released an undocumented version of the autorefinement code. The code was, however, limited to |
| 180 | +meshes where only pairs of triangles were intersecting along the same segment (as an underlying requirement of the code is |
| 181 | +a pairwise intersection). In order to officially release that code, we needed to overcome this limitation. |
| 182 | +In 2023, we found the time to start a new implementation from-scratch of autorefinement for triangle soups, |
| 183 | +which was then peer reviewed in 2024 and officially released with CGAL 6.0 in September 2024. |
| 184 | +</p> |
0 commit comments