GCC Code Coverage Report


Directory: ./
File: lib/geogram/mesh/triangle_intersection.h
Date: 2026-09-07 02:28:19
Exec Total Coverage
Lines: 10 10 100.0%
Functions: 1 1 100.0%
Branches: 5 12 41.7%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2000-2022 Inria
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the ALICE Project-Team nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Contact: Bruno Levy
30 *
31 * https://www.inria.fr/fr/bruno-levy
32 *
33 * Inria,
34 * Domaine de Voluceau,
35 * 78150 Le Chesnay - Rocquencourt
36 * FRANCE
37 *
38 */
39
40 #ifndef GEOGRAM_MESH_TRIANGLE_INTERSECTION
41 #define GEOGRAM_MESH_TRIANGLE_INTERSECTION
42
43 #include <geogram/basic/common.h>
44 #include <geogram/basic/geometry.h>
45 #include <geogram/basic/memory.h>
46 #include <utility>
47
48 /**
49 * \file geogram/mesh/triangle_intersection.h
50 * \brief Symbolic computation of triangle-triangle intersection
51 */
52
53 namespace GEO {
54
55 /**
56 * \brief Encodes the location of a point within a triangle.
57 * \details A point can be located in 6 different regions, that
58 * correspond to the three vertices, three edges and interior
59 * of a triangle.
60 * - RGN_P0, RGN_P1, RGN_P2 when point is exactly on a vertex
61 * - RGN_E0, RGN_E1, RGN_E2 when point is on an edge
62 * - RGN_T when point is on the interior of the triangle
63 */
64 enum TriangleRegion {
65 T1_RGN_P0 = 0,
66 T1_RGN_P1 = 1,
67 T1_RGN_P2 = 2,
68
69 T2_RGN_P0 = 3,
70 T2_RGN_P1 = 4,
71 T2_RGN_P2 = 5,
72
73 T1_RGN_E0 = 6,
74 T1_RGN_E1 = 7,
75 T1_RGN_E2 = 8,
76
77 T2_RGN_E0 = 9,
78 T2_RGN_E1 = 10,
79 T2_RGN_E2 = 11,
80
81 T1_RGN_T = 12,
82 T2_RGN_T = 13,
83
84 T_RGN_NB = 14
85 };
86
87
88 /**
89 * \brief Tests whether a region belongs to triangle T1
90 * \retval true if region belongs to T1
91 * \retval false if region belongs to T2
92 */
93 inline bool is_in_T1(TriangleRegion R) {
94 return (R == T1_RGN_P0) ||
95 (R == T1_RGN_P1) ||
96 (R == T1_RGN_P2) ||
97 (R == T1_RGN_E0) ||
98 (R == T1_RGN_E1) ||
99 (R == T1_RGN_E2) ||
100 (R == T1_RGN_T ) ;
101 }
102
103 /**
104 * \brief Replaces T1 with T2 or T2 with T1 in a region code
105 * \param[in] R a region
106 * \return the region in T2 corresponding to a region in T1,
107 * or the region in T1 corresponding to a region in T2.
108 */
109 TriangleRegion GEOGRAM_API swap_T1_T2(TriangleRegion R);
110
111 /**
112 * \brief Encodes the symbolic representation of a triangle intersection,
113 * as a pair of TriangleRegion.
114 */
115 typedef std::pair<TriangleRegion, TriangleRegion> TriangleIsect;
116
117
118 /**
119 * \brief A small vector of TriangleIsect stored in an array with static
120 * size.
121 * \details Used to return the symbolic information of triangle-triangle
122 * intersections. It is interesting to have a specialized class that avoids
123 * dynamic allocations for cases where triangle-triangle intersection is
124 * called in concurrent threads.
125 */
126 class TriangleIsects {
127 public:
128
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
1007411 TriangleIsects() : size_(0) {
129 }
130
131 typedef TriangleIsect* iterator;
132 typedef const TriangleIsect* const_iterator;
133
134 iterator begin() {
135 291694 return data_;
136 }
137
138 iterator end() {
139 291694 return begin()+size_;
140 }
141
142 const_iterator begin() const {
143 return data_;
144 }
145
146 const_iterator end() const {
147 return begin()+size_;
148 }
149
150 809799 void push_back(const TriangleIsect& I) {
151
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 809799 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
809799 geo_assert(size_ < capacity_);
152 data_[size_] = I;
153 809799 ++size_;
154 809799 }
155
156 void clear() {
157 size_ = 0;
158 }
159
160 index_t size() const {
161
4/4
✓ Branch 0 taken 10907 times.
✓ Branch 1 taken 25894 times.
✓ Branch 2 taken 41988 times.
✓ Branch 3 taken 10907 times.
78789 return size_;
162 }
163
164 void resize(index_t new_size) {
165 geo_debug_assert(new_size <= capacity_);
166 1007411 size_ = new_size;
167 1299105 }
168
169 TriangleIsect& operator[](index_t i) {
170 geo_debug_assert(i<size());
171 return data_[i];
172 }
173
174 const TriangleIsect& operator[](index_t i) const {
175 geo_debug_assert(i<size());
176 return data_[i];
177 }
178
179 private:
180 /**
181 * \brief The maximum capacity used internally to store the
182 * symbolic vertices of a triangle-triangle
183 * intersection. Note that in the transient state of triangle-triangle
184 * intersection there can be more than 6 vertices. The duplicated
185 * vertices are eliminated at the end of triangle-triangle
186 * intersection,using sort-uniq.
187 */
188 static constexpr int capacity_ = 20;
189 index_t size_;
190 TriangleIsect data_[capacity_];
191 };
192
193
194 /**
195 * \brief Triangle-triangle intersection with symbolic information
196 * \details The input triangles are supposed to be non-degenerate
197 * (their three vertices are supposed to be distinct and not co-linear).
198 * For now, when intersection is surfacic (overlapping pair
199 * of co-planar triangles), the vertices of the intersection are
200 * not sorted. One can order them by computing their convex hull.
201 * \param[in] p0 , p1 , p2 first triangle
202 * \param[in] q0 , q1 , q2 second triangle
203 * \param[out] result the intersection in symbolic
204 * form, as TriangleRegion pairs. There can be
205 * between 0 and 6 intersection pairs in the result.
206 * \retval true if there is a non-degenerate intersection
207 * \retval false otherwise. Degenerate intersection cases are:
208 * - one vertex in common
209 * - two vertices (an edge) in common
210 * - or duplicated triangles.
211 */
212 bool GEOGRAM_API triangles_intersections(
213 const vec3& p0, const vec3& p1, const vec3& p2,
214 const vec3& q0, const vec3& q1, const vec3& q2,
215 TriangleIsects& result
216 );
217
218
219 [[deprecated("use TriangleIsects instead of vector<TriangleIsect>")]]
220 inline bool triangles_intersections(
221 const vec3& p0, const vec3& p1, const vec3& p2,
222 const vec3& q0, const vec3& q1, const vec3& q2,
223 vector<TriangleIsect>& result
224 ) {
225 TriangleIsects result_;
226 bool r = triangles_intersections(p0,p1,p2,q0,q1,q2,result_);
227 result.clear();
228 for(TriangleIsect I : result_) {
229 result.push_back(I);
230 }
231 return r;
232 }
233
234
235 /**
236 * \brief Triangle-triangle intersection with symbolic information
237 * \details The input triangles are supposed to be non-degenerate
238 * (their three vertices are supposed to be distinct and not co-linear).
239 * For now, when intersection is surfacic (overlapping pair
240 * of co-planar triangles), the vertices of the intersection are
241 * not sorted. One can order them by computing their convex hull.
242 * \param[in] p0 , p1 , p2 first triangle
243 * \param[in] q0 , q1 , q2 second triangle
244 * \param[in] p0_index , p1_index , p2_index global indices of p0 , p1 , p2
245 * \param[in] q0_index , q1_index , q2_index global indices of q0 , q1 , q2
246 * indicating whether q0 (resp q1, q2) correspond to p0 , p1 , p2
247 * \param[out] result the intersection in symbolic
248 * form, as TriangleRegion pairs. There can be
249 * between 0 and 6 intersection pairs in the result.
250 * \retval true if there is a non-degenerate intersection
251 * \retval false otherwise. Degenerate intersection cases are:
252 * - one vertex in common
253 * - two vertices (an edge) in common
254 * - or duplicated triangles.
255 */
256 bool GEOGRAM_API triangles_intersections(
257 const vec3& p0, const vec3& p1, const vec3& p2,
258 const vec3& q0, const vec3& q1, const vec3& q2,
259 index_t p0_index,
260 index_t p1_index,
261 index_t p2_index,
262 index_t q0_index,
263 index_t q1_index,
264 index_t q2_index,
265 TriangleIsects& result
266 );
267
268
269 /**
270 * \brief Triangle-triangle intersection predicate
271 * \param[in] p0 , p1 , p2 first triangle
272 * \param[in] q0 , q1 , q2 second triangle
273 * \retval true if there is a non-degenerate intersection
274 * \retval false otherwise. Degenerate intersection cases are:
275 * - one vertex in common
276 * - two vertices (an edge) in common
277 * - or duplicated triangles.
278 */
279 bool triangles_intersections(
280 const vec3& p0, const vec3& p1, const vec3& p2,
281 const vec3& q0, const vec3& q1, const vec3& q2
282 );
283
284 /**
285 * \brief Converts a triangle region code to a string.
286 * \param[in] rgn the triangle region code.
287 * \return the string representation of \p rgn.
288 */
289 std::string GEOGRAM_API region_to_string(TriangleRegion rgn);
290
291 /**
292 * \brief Gets the dimension of a triangle region
293 * \param[in] r a triangle region
294 * \retval 0 for vertices
295 * \retval 1 for edges
296 * \retval 2 for the interior
297 */
298 coord_index_t GEOGRAM_API region_dim(TriangleRegion r);
299
300 /**
301 * \brief Gets the vertices of a triangle
302 * \param[in] T one of T1_RGN_T, T2_RGN_T
303 * \param[out] p0 , p1 , p2 the region codes of the
304 * three vertices of the triangle
305 */
306 void GEOGRAM_API get_triangle_vertices(
307 TriangleRegion T,
308 TriangleRegion& p0, TriangleRegion& p1, TriangleRegion& p2
309 );
310
311 /**
312 * \brief Gets the edges of a triangle
313 * \param[in] T one of T1_RGN_T, T2_RGN_T
314 * \param[out] e0 , e1 , e2 the region codes of the
315 * three edges of the triangle
316 */
317 void GEOGRAM_API get_triangle_edges(
318 TriangleRegion T,
319 TriangleRegion& e0, TriangleRegion& e1, TriangleRegion& e2
320 );
321
322 /**
323 * \brief Gets the vertices of an edge
324 * \param[in] E the region code of an edge
325 * \param[out] q0 , q1 the region codes of the two vertices
326 * of the edge
327 */
328 void GEOGRAM_API get_edge_vertices(
329 TriangleRegion E, TriangleRegion& q0, TriangleRegion& q1
330 );
331
332
333 /**
334 * \brief Computes the convex hull of two regions
335 * \details The function is purely combinatorial.
336 * - The convex hull of twice the same region is
337 * that region
338 * - the convex hull of an edge and a vertex this edge
339 * is incident to is that edge
340 * - the convex hull of two vertices is the edge incident
341 * to the vertices
342 * - in all other cases, the convex hull is the triangle
343 * \pre \p R1 and \p R2 are in the same triangle (they
344 * both start with T1_ or they both start with T2_).
345 * \param[in] R1 , R2 the two regions
346 * \return The convex hull of R1 and R2
347 */
348 TriangleRegion GEOGRAM_API regions_convex_hull(
349 TriangleRegion R1, TriangleRegion R2
350 );
351
352 /**
353 * \brief Prints a triangle intersection element to a stream.
354 * \details Used for debugging purposes.
355 * \param[in] out the stream.
356 * \param[in] I the intersection element to be printed.
357 */
358 inline std::ostream& operator<<(
359 std::ostream& out, const TriangleIsect& I
360 ) {
361 return (
362 out << "("
363 << region_to_string(I.first) << ","
364 << region_to_string(I.second)
365 << ")"
366 );
367 }
368
369 /**
370 * \brief Prints the result of a triangle intersection to a stream.
371 * \details Used for debugging purposes.
372 * \param[in] out the stream.
373 * \param[in] II the intersections to be printed.
374 */
375 inline std::ostream& operator<<(
376 std::ostream& out, TriangleIsects& II
377 ) {
378 for(const TriangleIsect& I : II) {
379 out << I << " ";
380 }
381 return out;
382 }
383
384 [[deprecated("use TriangleIsects instead of vector<TriangleIsect>")]]
385 inline std::ostream& operator<<(
386 std::ostream& out, const vector<TriangleIsect>& II
387 ) {
388 for(const TriangleIsect& I : II) {
389 out << I << " ";
390 }
391 return out;
392 }
393
394
395 }
396
397 #endif
398