1 // Copyright (c) 2014 GeometryFactory (France). All rights reserved.
2 // All rights reserved.
3 //
4 // This file is part of CGAL (www.cgal.org)
5 //
6 // $URL: https://github.com/CGAL/cgal/blob/v5.3/BGL/include/CGAL/boost/graph/helpers.h $
7 // $Id: helpers.h 5bd28b4 2020-07-29T10:24:02+02:00 Mael Rouxel-Labbé
8 // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
9 //
10 // Author(s) : Andreas Fabri
11
12 #ifndef CGAL_BOOST_GRAPH_HELPERS_H
13 #define CGAL_BOOST_GRAPH_HELPERS_H
14
15 #include <CGAL/boost/graph/iterator.h>
16 #include <CGAL/boost/graph/properties.h>
17 #include <CGAL/boost/graph/internal/Has_member_clear.h>
18 #include <CGAL/function_objects.h>
19 #include <CGAL/IO/Verbose_ostream.h>
20
21 #include <boost/range/empty.hpp>
22
23 namespace CGAL {
24
25 /*!
26 \ingroup PkgBGLHelperFct
27 returns `true` if the halfedge `hd` is on a border.
28 */
29 template <typename FaceGraph>
is_border(typename boost::graph_traits<FaceGraph>::halfedge_descriptor hd,const FaceGraph & g)30 bool is_border(typename boost::graph_traits<FaceGraph>::halfedge_descriptor hd, const FaceGraph& g)
31 {
32 return face(hd,g) == boost::graph_traits<FaceGraph>::null_face();
33 }
34
35 /*!
36 \ingroup PkgBGLHelperFct
37 returns `true` if the halfedge `hd` or the opposite halfedge is on a border.
38 */
39 template <typename FaceGraph>
is_border_edge(typename boost::graph_traits<FaceGraph>::halfedge_descriptor hd,const FaceGraph & g)40 bool is_border_edge(typename boost::graph_traits<FaceGraph>::halfedge_descriptor hd, const FaceGraph& g)
41 {
42 return is_border(hd, g) || is_border(opposite(hd,g), g);
43 }
44
45 /*!
46 \ingroup PkgBGLHelperFct
47 returns `true` if the edge `e` is on a border.
48 */
49 template <typename FaceGraph>
is_border(typename boost::graph_traits<FaceGraph>::edge_descriptor ed,const FaceGraph & g)50 bool is_border(typename boost::graph_traits<FaceGraph>::edge_descriptor ed, const FaceGraph& g)
51 {
52 return is_border_edge(halfedge(ed,g), g);
53 }
54
55 /*!
56 \ingroup PkgBGLHelperFct
57 returns a halfedge which is on a border and whose target vertex is `vd`, if such a halfedge exists.
58 */
59 template <typename FaceGraph>
60 boost::optional<typename boost::graph_traits<FaceGraph>::halfedge_descriptor>
is_border(typename boost::graph_traits<FaceGraph>::vertex_descriptor vd,const FaceGraph & g)61 is_border(typename boost::graph_traits<FaceGraph>::vertex_descriptor vd,
62 const FaceGraph& g)
63 {
64 CGAL::Halfedge_around_target_iterator<FaceGraph> havib, havie;
65 for(boost::tie(havib, havie) = halfedges_around_target(halfedge(vd, g), g); havib != havie; ++havib) {
66 if(is_border(*havib,g)) {
67 typename boost::graph_traits<FaceGraph>::halfedge_descriptor h = *havib;
68 return h;
69 }
70 }
71 // empty
72 return boost::optional<typename boost::graph_traits<FaceGraph>::halfedge_descriptor>();
73 }
74
75
76 /*!
77 \ingroup PkgBGLHelperFct
78 returns `true` if there are no border edges.
79 */
80 template <typename FaceGraph>
is_closed(const FaceGraph & g)81 bool is_closed(const FaceGraph& g)
82 {
83 typedef typename boost::graph_traits<FaceGraph>::halfedge_descriptor halfedge_descriptor;
84 for(halfedge_descriptor hd : halfedges(g)){
85 if(is_border(hd,g)){
86 return false;
87 }
88 }
89 return true;
90 }
91
92 /*!
93 \ingroup PkgBGLHelperFct
94 returns `true` if the target of `hd` has exactly two incident edges.
95 */
96 template <typename FaceGraph>
is_bivalent(typename boost::graph_traits<FaceGraph>::halfedge_descriptor hd,const FaceGraph & g)97 bool is_bivalent(typename boost::graph_traits<FaceGraph>::halfedge_descriptor hd, const FaceGraph& g)
98 {
99 return hd == opposite(next(opposite(next(hd,g),g),g),g);
100 }
101
102 /*!
103 \ingroup PkgBGLHelperFct
104 returns `true` if all vertices have exactly two incident edges.
105 */
106 template <typename FaceGraph>
is_bivalent_mesh(const FaceGraph & g)107 bool is_bivalent_mesh(const FaceGraph& g)
108 {
109 typedef typename boost::graph_traits<FaceGraph>::vertex_descriptor vertex_descriptor;
110 typedef typename boost::graph_traits<FaceGraph>::halfedge_descriptor halfedge_descriptor;
111 for(vertex_descriptor vd : vertices(g)){
112 halfedge_descriptor hd = halfedge(vd,g);
113 if((hd == boost::graph_traits<FaceGraph>::null_halfedge()) ||
114 (! is_bivalent(hd,g))){
115 return false;
116 }
117 }
118 return true;
119 }
120
121 /*!
122 \ingroup PkgBGLHelperFct
123 returns `true` if the target of `hd` has exactly three incident edges.
124 */
125 template <typename FaceGraph>
is_trivalent(typename boost::graph_traits<FaceGraph>::halfedge_descriptor hd,const FaceGraph & g)126 bool is_trivalent(typename boost::graph_traits<FaceGraph>::halfedge_descriptor hd, const FaceGraph& g)
127 {
128 return hd == opposite(next(opposite(next(opposite(next(hd,g),g),g),g),g),g);
129 }
130
131 /*!
132 \ingroup PkgBGLHelperFct
133 returns `true` if all
134 vertices have exactly three incident edges.
135 */
136 template <typename FaceGraph>
is_trivalent_mesh(const FaceGraph & g)137 bool is_trivalent_mesh(const FaceGraph& g)
138 {
139 typedef typename boost::graph_traits<FaceGraph>::vertex_descriptor vertex_descriptor;
140 typedef typename boost::graph_traits<FaceGraph>::halfedge_descriptor halfedge_descriptor;
141 for(vertex_descriptor vd : vertices(g)){
142 halfedge_descriptor hd = halfedge(vd,g);
143 if((hd == boost::graph_traits<FaceGraph>::null_halfedge()) ||
144 (! is_trivalent(halfedge(hd,g),g))){
145 return false;
146 }
147 }
148 return true;
149 }
150
151 /*!
152 \ingroup PkgBGLHelperFct
153 returns `true` iff the connected component denoted by `hd` is a triangle.
154 \pre `g` must be valid.
155 */
156 template <typename FaceGraph>
is_isolated_triangle(typename boost::graph_traits<FaceGraph>::halfedge_descriptor hd,const FaceGraph & g)157 bool is_isolated_triangle(typename boost::graph_traits<FaceGraph>::halfedge_descriptor hd, const FaceGraph& g)
158 {
159 typedef typename boost::graph_traits<FaceGraph>::halfedge_descriptor halfedge_descriptor;
160 halfedge_descriptor beg = hd;
161 if(is_border(hd,g)) return false;
162 for(int i=0; i<3;i++){
163 if(! is_border(opposite(hd,g),g)) return false;
164 hd = next(hd,g);
165 }
166 return hd == beg;
167 }
168
169 /*!
170 \ingroup PkgBGLHelperFct
171 returns `true` iff the face denoted by `hd` is a triangle, that is it has three incident halfedges.
172 */
173 template <typename FaceGraph>
is_triangle(typename boost::graph_traits<FaceGraph>::halfedge_descriptor hd,const FaceGraph & g)174 bool is_triangle(typename boost::graph_traits<FaceGraph>::halfedge_descriptor hd, const FaceGraph& g)
175 {
176 return hd == next(next(next(hd,g),g),g);
177 }
178
179 /*!
180 \ingroup PkgBGLHelperFct
181 returns `true` if all faces are triangles.
182 */
183 template <typename FaceGraph>
is_triangle_mesh(const FaceGraph & g)184 bool is_triangle_mesh(const FaceGraph& g)
185 {
186 typedef typename boost::graph_traits<FaceGraph>::face_descriptor face_descriptor;
187 for(face_descriptor fd : faces(g)){
188 if(! is_triangle(halfedge(fd,g),g)){
189 return false;
190 }
191 }
192 return true;
193 }
194
195 /*!
196 \ingroup PkgBGLHelperFct
197 returns `true` iff the connected component denoted by `hd` is a quadrilateral.
198 */
199 template <typename FaceGraph>
is_isolated_quad(typename boost::graph_traits<FaceGraph>::halfedge_descriptor hd,const FaceGraph & g)200 bool is_isolated_quad(typename boost::graph_traits<FaceGraph>::halfedge_descriptor hd, const FaceGraph& g)
201 {
202 typedef typename boost::graph_traits<FaceGraph>::halfedge_descriptor halfedge_descriptor;
203 halfedge_descriptor beg = hd;
204 if(is_border(hd,g)) return false;
205 for(int i=0; i<4;i++){
206 if(! is_border(opposite(hd,g),g)) return false;
207 hd = next(hd,g);
208 }
209 return hd == beg;
210 }
211
212
213 /*!
214 \ingroup PkgBGLHelperFct
215 returns `true` iff the face denoted by `hd` is a quad, that is it has four incident halfedges.
216 */
217 template <typename FaceGraph>
is_quad(typename boost::graph_traits<FaceGraph>::halfedge_descriptor hd,const FaceGraph & g)218 bool is_quad(typename boost::graph_traits<FaceGraph>::halfedge_descriptor hd, const FaceGraph& g)
219 {
220 return hd == next(next(next(next(hd,g),g),g),g);
221 }
222
223 /*!
224 \ingroup PkgBGLHelperFct
225 returns `true` if all faces are quadrilaterals.
226 */
227 template <typename FaceGraph>
is_quad_mesh(const FaceGraph & g)228 bool is_quad_mesh(const FaceGraph& g)
229 {
230 typedef typename boost::graph_traits<FaceGraph>::face_descriptor face_descriptor;
231 for(face_descriptor fd : faces(g)){
232 if(! is_quad(halfedge(fd,g),g)){
233 return false;
234 }
235 }
236 return true;
237 }
238
239 /*!
240 \ingroup PkgBGLHelperFct
241 returns `true` iff the connected component denoted by `hd` is a tetrahedron.
242 */
243 template <typename FaceGraph>
is_tetrahedron(typename boost::graph_traits<FaceGraph>::halfedge_descriptor hd,const FaceGraph & g)244 bool is_tetrahedron( typename boost::graph_traits<FaceGraph>::halfedge_descriptor hd, const FaceGraph& g)
245 {
246 typedef typename boost::graph_traits<FaceGraph>::halfedge_descriptor halfedge_descriptor;
247
248 halfedge_descriptor h1 = hd;
249 if(is_border(h1,g)) return false;
250 typedef typename boost::graph_traits<FaceGraph>::halfedge_descriptor halfedge_descriptor;
251 halfedge_descriptor h2 = next(h1,g);
252 halfedge_descriptor h3 = next(h2,g);
253 halfedge_descriptor h4 = next(opposite(h1,g),g );
254 halfedge_descriptor h5 = next(opposite(h2,g),g );
255 halfedge_descriptor h6 = next(opposite(h3,g),g );
256 // check halfedge combinatorics.
257 // at least three edges at vertices 1, 2, 3.
258 if ( h4 == opposite(h3,g) ) return false;
259 if ( h5 == opposite(h1,g) ) return false;
260 if ( h6 == opposite(h2,g) ) return false;
261 // exact three edges at vertices 1, 2, 3.
262 if ( next(opposite(h4,g),g) != opposite(h3,g) ) return false;
263 if ( next(opposite(h5,g),g) != opposite(h1,g) ) return false;
264 if ( next(opposite(h6,g),g) != opposite(h2,g) ) return false;
265 // three edges at v4.
266 if ( opposite(next(h4,g),g) != h5 ) return false;
267 if ( opposite(next(h5,g),g) != h6 ) return false;
268 if ( opposite(next(h6,g),g) != h4 ) return false;
269 // All facets are triangles.
270 if ( next(next(next(h1,g),g),g) != h1 ) return false;
271 if ( next(next(next(h4,g),g),g) != h4 ) return false;
272 if ( next(next(next(h5,g),g),g) != h5 ) return false;
273 if ( next(next(next(h6,g),g),g) != h6 ) return false;
274 // all edges are non-border edges.
275 if ( is_border(h1,g) ) return false; // implies h2 and h3
276 if ( is_border(h4,g) ) return false;
277 if ( is_border(h5,g) ) return false;
278 if ( is_border(h6,g) ) return false;
279 return true;
280 }
281
282 template <typename FaceGraph>
is_valid_halfedge_descriptor(typename boost::graph_traits<FaceGraph>::halfedge_descriptor h,const FaceGraph & g)283 bool is_valid_halfedge_descriptor( typename boost::graph_traits<FaceGraph>::halfedge_descriptor h, const FaceGraph& g)
284 {
285 typedef typename boost::graph_traits<FaceGraph>::halfedge_descriptor halfedge_descriptor;
286 typedef typename boost::graph_traits<FaceGraph>::face_descriptor face_descriptor;
287 face_descriptor f = face(h,g);
288 halfedge_descriptor done(h);
289 do{
290 if(face(h,g) != f){
291 std::cerr << "halfedge " << h << " is invalid\n";
292 return false;
293 }
294 halfedge_descriptor hn = h;
295 hn = next(h,g);
296 if(prev(hn,g) != h){
297 std::cerr << "halfedge " << h << " is invalid\n";
298 return false;
299 }
300 h = hn;
301 } while(h != done);
302 return true;
303 }
304
305 template <typename FaceGraph>
is_valid_vertex_descriptor(typename boost::graph_traits<FaceGraph>::vertex_descriptor v,const FaceGraph & g)306 bool is_valid_vertex_descriptor( typename boost::graph_traits<FaceGraph>::vertex_descriptor v, const FaceGraph& g)
307 {
308 typedef typename boost::graph_traits<FaceGraph>::halfedge_descriptor halfedge_descriptor;
309 halfedge_descriptor h = halfedge(v,g), done(h);
310 if(h == boost::graph_traits<FaceGraph>::null_halfedge()){
311 return true;
312 }
313 do{
314 if(target(h,g) != v){
315 std::cerr << "vertex " << v << " is invalid\n";
316 return false;
317 }
318 h = opposite(next(h,g),g);
319 }while(h != done);
320 return true;
321 }
322
323 template <typename FaceGraph>
is_valid_face_descriptor(typename boost::graph_traits<FaceGraph>::face_descriptor f,const FaceGraph & g)324 bool is_valid_face_descriptor( typename boost::graph_traits<FaceGraph>::face_descriptor f, const FaceGraph& g)
325 {
326 typedef typename boost::graph_traits<FaceGraph>::halfedge_descriptor halfedge_descriptor;
327
328 halfedge_descriptor h = halfedge(f,g);
329 if(face(h,g) != f){
330 std::cerr << "face " << f << " is invalid\n";
331 return false;
332 }
333 return true;
334 }
335
336 /*!
337 \ingroup PkgBGLHelperFct
338 * \brief checks the integrity of `g`.
339 *
340 * `g` is valid if it follows the rules of the `HalfedgeListGraph` concept,
341 * and all of its associations are reciprocal.
342 * For example, `prev(next(h, g), g)` must be `h`,
343 * and `next(prev(h, g), g)` must be `h`.
344 *
345 * \param g the `Graph` to test.
346 * \param verb if `true`, the details of the check will be written in the standard output.
347 *
348 * \tparam Graph a model of `HalfedgeListGraph`
349 *
350 * \return `true` if `g` is valid, `false` otherwise.
351 *
352 */
353 template<typename Graph>
354 bool is_valid_halfedge_graph(const Graph& g, bool verb = false)
355 {
356 typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
357 typedef typename boost::graph_traits<Graph>::vertices_size_type vertex_size_type;
358 typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
359 typedef typename boost::graph_traits<Graph>::halfedges_size_type halfedges_size_type;
360
361 Verbose_ostream verr(verb);
362 std::size_t num_v(std::distance(boost::begin(vertices(g)), boost::end(vertices(g)))),
363 num_e(std::distance(boost::begin(edges(g)), boost::end(edges(g)))),
364 num_h(std::distance(boost::begin(halfedges(g)), boost::end(halfedges(g))));
365
366 bool valid = (1 != (num_h&1) && (2*num_e == num_h));
367 if(!valid)
368 {
369 verr << "number of halfedges is odd." << std::endl;
370 verr << "Halfedge Graph Structure is NOT VALID." << std::endl;
371 return false;
372 }
373
374 // All halfedges.
375 halfedges_size_type n = 0;
376 for(halfedge_descriptor begin : halfedges(g))
377 {
378 // Pointer integrity.
379 valid = (next(begin, g) != boost::graph_traits<Graph>::null_halfedge());
380 valid = valid && (opposite(begin, g) != boost::graph_traits<Graph>::null_halfedge());
381 if(!valid)
382 {
383 verr << "halfedge " << n << " next / opposite halfedges are null." << std::endl;
384 verr << "Halfedge Graph Structure is NOT VALID." << std::endl;
385 return false;
386 }
387
388 // edge integrity
389 valid = (halfedge(edge(begin, g), g) == begin);
390
391 // opposite integrity.
392 valid = valid && (opposite(begin, g) != begin);
393 valid = valid && (opposite(opposite(begin, g), g) == begin);
394 if(!valid)
395 {
396 verr << "halfedge " << n << " invalid halfedge opposite()." << std::endl;
397 verr << "Halfedge Graph Structure is NOT VALID." << std::endl;
398 return false;
399 }
400
401 // previous integrity.
402 valid = (prev(next(begin, g), g) == begin);
403 valid = valid && (next(prev(begin, g), g) == begin);
404 if(!valid)
405 {
406 verr << "halfedge " << n << " prev(next(hd)) != hd OR next(prev(hd)) != hd" << std::endl;
407 verr << "Halfedge Graph Structure is NOT VALID." << std::endl;
408 return false;
409 }
410
411 // vertex integrity.
412 valid = (target(begin, g) != boost::graph_traits<Graph>::null_vertex());
413 if(!valid)
414 {
415 verr << "halfedge " << n << " target of halfedge is the null vertex." << std::endl;
416 verr << "Halfedge Graph Structure is NOT VALID." << std::endl;
417 return false;
418 }
419
420 valid = (target(begin, g) == target(opposite(next(begin, g), g), g));
421 if(!valid)
422 {
423 verr << "halfedge " << n << " target(hd) != source(next(hd))." << std::endl;
424 verr << "Halfedge Graph Structure is NOT VALID." << std::endl;
425 return false;
426 }
427
428 ++n;
429 }
430
431 valid = (n == num_h);
432 if(!valid)
433 {
434 verr << "counting halfedges failed." << std::endl;
435 verr << "Halfedge Graph Structure is NOT VALID." << std::endl;
436 return false;
437 }
438
439 // All vertices.
440 vertex_size_type v = 0;
441 n = 0;
442 for(vertex_descriptor vbegin : vertices(g))
443 {
444 // Pointer integrity.
445 if(halfedge(vbegin, g) != boost::graph_traits<Graph>::null_halfedge())
446 valid = (target(halfedge(vbegin, g), g) == vbegin);
447 else
448 valid = false;
449
450 if(!valid)
451 {
452 verr << "vertex " << v << " halfedge incident to vertex is the null halfedge." << std::endl;
453 verr << "Halfedge Graph Structure is NOT VALID." << std::endl;
454 return false;
455 }
456
457 // cycle-around-vertex test.
458 halfedge_descriptor h = halfedge(vbegin, g);
459 if(h != boost::graph_traits<Graph>::null_halfedge())
460 {
461 halfedge_descriptor ge = h;
462 do
463 {
464 ++n;
465 h = opposite(next(h, g), g);
466 valid = (n <= num_h && n != 0);
467 if(!valid)
468 {
469 verr << "vertex " << v << " too many halfedges around vertex." << std::endl;
470 verr << "Halfedge Graph Structure is NOT VALID." << std::endl;
471 return false;
472 }
473 }
474 while(h != ge);
475 }
476
477 ++v;
478 }
479
480 valid = (v == num_v);
481 if(!valid)
482 {
483 verr << "counting vertices failed." << std::endl;
484 verr << "Halfedge Graph Structure is NOT VALID." << std::endl;
485 return false;
486 }
487
488 valid = (n == num_h);
489 if(!valid)
490 {
491 verr << "counting halfedges via vertices failed." << std::endl;
492 verr << "Halfedge Graph Structure is NOT VALID." << std::endl;
493 return false;
494 }
495
496 // All halfedges.
497 n = 0;
498 for(halfedge_descriptor i : halfedges(g))
499 {
500 // At least triangular facets and distinct geometry.
501 valid = (next(i, g) != i) && (target(i, g) != target(opposite(i, g), g));
502 if(!valid)
503 {
504 verr << "halfedge " << n << " pointer validity corrupted." << std::endl;
505 verr << "Halfedge Graph Structure is NOT VALID." << std::endl;
506 return false;
507 }
508
509 ++n;
510 }
511
512 valid = (n == num_h);
513 if(!valid)
514 verr << "counting halfedges failed." << std::endl;
515
516 verr << "Halfedge Graph Structure is " << (valid ? "valid." : "NOT VALID.") << std::endl;
517
518 return valid;
519 }
520
521 /*!
522 \ingroup PkgBGLHelperFct
523 * \brief checks the integrity of `g`.
524 *
525 * `g` is valid if it is a valid `HalfedgeListGraph`, if it follows the rules
526 * of the `FaceListGraph` concept, and all of its associations are reciprocal.
527 * For example, `face(halfedge(f,g),g)` must be `f`.
528 * calls `is_valid_halfedge_graph()`
529 *
530 * \param g the `Graph` to test.
531 * \param verb if `true`, the details of the check will be written in the standard output.
532 *
533 * \tparam Graph a model of `FaceListGraph`
534 *
535 * \return `true` if `g` is valid, `false` otherwise.
536 *
537 * \see `is_valid_halfedge_graph()`
538 */
539 template<typename Graph>
540 bool is_valid_face_graph(const Graph& g, bool verb = false)
541 {
542 typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
543 typedef typename boost::graph_traits<Graph>::halfedges_size_type halfedges_size_type;
544 typedef typename boost::graph_traits<Graph>::face_descriptor face_descriptor;
545 typedef typename boost::graph_traits<Graph>::faces_size_type faces_size_type;
546
547 Verbose_ostream verr(verb);
548
549 std::size_t num_f(std::distance(boost::begin(faces(g)), boost::end(faces(g)))),
550 num_h(std::distance(boost::begin(halfedges(g)), boost::end(halfedges(g))));
551
552 faces_size_type f = 0;
553 std::size_t n = 0;
554 std::size_t hn = 0;
555 halfedges_size_type nb = 0;
556
557 //is valid halfedge_graph ?
558 bool valid = is_valid_halfedge_graph(g, verb);
559 if(!valid)
560 return false;
561
562 // All faces.
563 for(face_descriptor fbegin : faces(g))
564 {
565 // Pointer integrity.
566 if(halfedge(fbegin, g) != boost::graph_traits<Graph>::null_halfedge())
567 valid = (face(halfedge(fbegin, g), g) == fbegin);
568 else
569 valid = false;
570
571 if(!valid)
572 {
573 verr << "face " << f << " halfedge incident to face is the null halfedge." << std::endl;
574 verr << "Face Graph Structure is NOT VALID." << std::endl;
575 return false;
576 }
577
578 // cycle-around-face test.
579 halfedge_descriptor h = halfedge( fbegin, g);
580 if(h != boost::graph_traits<Graph>::null_halfedge())
581 {
582 halfedge_descriptor ge = h;
583 do
584 {
585 ++n;
586 h = next(h, g);
587 valid = (n <= num_h && n != 0);
588 if(!valid)
589 {
590 verr << "face " << f << " too many halfedges around face." << std::endl;
591 verr << "Face Graph Structure is NOT VALID." << std::endl;
592 return false;
593 }
594 }
595 while(h != ge);
596 }
597
598 ++f;
599 }
600
601 valid = (f == num_f);
602 if(!valid)
603 {
604 verr << "counting faces failed." << std::endl;
605 verr << "Face Graph Structure is NOT VALID." << std::endl;
606 return false;
607 }
608
609 for(halfedge_descriptor i : halfedges(g))
610 {
611 ++hn;
612
613 //counting borders
614 if(is_border(i, g))
615 ++nb;
616
617 // face integrity.
618 valid = (face(i, g) == face(next(i, g), g));
619 if(!valid)
620 {
621 verr << "halfedge " << hn << " face(hd) != face(next(hd))." << std::endl;
622 verr << "Face Graph Structure is NOT VALID." << std::endl;
623 return false;
624 }
625 }
626
627 valid = (n + nb == num_h);
628 if(!valid)
629 {
630 verr << "sum border halfedges (2*nb) = " << 2 * nb << std::endl;
631 verr << "counting halfedges via faces failed." << std::endl;
632 verr << "Face Graph Structure is NOT VALID." << std::endl;
633 return false;
634 }
635
636 valid = (f == num_f);
637 if(!valid)
638 verr << "counting faces failed." << std::endl;
639
640 verr << "Face Graph Structure is " << (valid ? "valid." : "NOT VALID.") << std::endl;
641
642 return valid;
643 }
644
645 /*!
646 \ingroup PkgBGLHelperFct
647 * \brief checks the integrity of `g`.
648 *
649 * `g` is valid if it is a valid `FaceListGraph` and it has distinct faces on each side of an edge.
650 * calls `is_valid_face_graph()`.
651 *
652 * \param g the `Mesh` to test.
653 * \param verb : if `true`, the details of the check will be written in the standard output.
654 *
655 * \tparam Mesh a model of `FaceListGraph` and `HalfedgeListGraph`, and follows
656 * the definition of a \ref PMPDef "PolygonMesh"
657 * \return `true` if `g` is valid, `false` otherwise.
658 *
659 * \see `is_valid_face_graph()`
660 * \see `is_valid_halfedge_graph()`
661 *
662 */
663 template <typename Mesh>
664 bool is_valid_polygon_mesh(const Mesh& g, bool verb = false)
665 {
666 typedef typename boost::graph_traits<Mesh>::halfedge_descriptor halfedge_descriptor;
667
668 Verbose_ostream verr(verb);
669 bool valid = is_valid_face_graph(g, verb);
670 if(!valid)
671 return false;
672
673 // test for 2-manifoldness
674 // Distinct facets on each side of an halfedge.
675 for(halfedge_descriptor i : halfedges(g))
676 {
677 valid = (face(i, g) != face(opposite(i, g), g));
678 if(!valid)
679 {
680 verr << "both incident facets are equal." << std::endl;
681 verr << "Polygon Mesh Structure is NOT VALID." << std::endl;
682 return false;
683 }
684
685 valid = (next(next(i, g), g) != i);
686 valid = valid && (target(i, g) != target(next(i, g), g));
687 valid = valid && (target(i, g) != target(next(next(i, g), g), g));
688 if(!valid)
689 {
690 verr << "incident facet is not at least a triangle." << std::endl;
691 verr << "Polygon Mesh Structure is NOT VALID." << std::endl;
692 return false;
693 }
694 }
695
696 verr << "Polygon Mesh Structure is valid." << std::endl;
697 return true;
698 }
699
700 /*!
701 \ingroup PkgBGLHelperFct
702 returns `true` iff the connected component denoted by `hd` is a hexahedron.
703 */
704 template <typename FaceGraph>
is_hexahedron(typename boost::graph_traits<FaceGraph>::halfedge_descriptor hd,const FaceGraph & g)705 bool is_hexahedron( typename boost::graph_traits<FaceGraph>::halfedge_descriptor hd, const FaceGraph& g)
706 {
707 typedef typename boost::graph_traits<FaceGraph>::halfedge_descriptor halfedge_descriptor;
708
709 halfedge_descriptor h1 = hd;
710 if(is_border(h1,g)) return false;
711 typedef typename boost::graph_traits<FaceGraph>::halfedge_descriptor halfedge_descriptor;
712 halfedge_descriptor h2 = next(h1,g);
713 halfedge_descriptor h3 = next(h2,g);
714 halfedge_descriptor h4 = next(h3,g);
715 halfedge_descriptor h1o = opposite(h1,g);
716 halfedge_descriptor h2o = opposite(h2,g);
717 halfedge_descriptor h3o = opposite(h3,g);
718 halfedge_descriptor h4o = opposite(h4,g);
719 if(opposite(next(h2o,g),g) != prev(h1o,g)) return false;
720 if(opposite(next(h3o,g),g) != prev(h2o,g)) return false;
721 if(opposite(next(h4o,g),g) != prev(h3o,g)) return false;
722 if(opposite(next(h1o,g),g) != prev(h4o,g)) return false;
723 if(! is_quad(h1,g)) return false;
724 if(! is_quad(h1o,g)) return false;
725 if(! is_quad(h2o,g)) return false;
726 if(! is_quad(h3o,g)) return false;
727 if(! is_quad(h4o,g)) return false;
728 h1o =next(next(h1o,g),g);
729 h2o =next(next(h2o,g),g);
730 h3o =next(next(h3o,g),g);
731 h4o =next(next(h4o,g),g);
732 if(next(opposite(h2o,g),g) != opposite(h1o,g)) return false;
733 if(next(opposite(h3o,g),g) != opposite(h2o,g)) return false;
734 if(next(opposite(h4o,g),g) != opposite(h3o,g)) return false;
735 if(next(opposite(h1o,g),g) != opposite(h4o,g)) return false;
736
737 if(! is_quad(opposite(h4o,g),g)) return false;
738 return true;
739 }
740
741 namespace internal {
742
743 template<typename FaceGraph>
744 inline
745 typename boost::enable_if<Has_member_clear<FaceGraph>, void>::type
clear_impl(FaceGraph & g)746 clear_impl(FaceGraph& g)
747 { g.clear(); }
748
749 template<typename FaceGraph>
750 inline
751 typename boost::disable_if<Has_member_clear<FaceGraph>, void>::type
clear_impl(FaceGraph & g)752 clear_impl(FaceGraph& g)
753 {
754 while(boost::begin(edges(g))!=boost::end(edges(g)))
755 remove_edge(*boost::begin(edges(g)), g);
756 while(boost::begin(faces(g))!=boost::end(faces(g)))
757 remove_face(*boost::begin(faces(g)), g);
758 while(boost::begin(vertices(g))!=boost::end(vertices(g)))
759 remove_vertex(*boost::begin(vertices(g)), g);
760 }
761
762 template <class FaceGraph>
swap_vertices(typename boost::graph_traits<FaceGraph>::vertex_descriptor & p,typename boost::graph_traits<FaceGraph>::vertex_descriptor & q,FaceGraph & g)763 void swap_vertices(
764 typename boost::graph_traits<FaceGraph>::vertex_descriptor& p,
765 typename boost::graph_traits<FaceGraph>::vertex_descriptor& q,
766 FaceGraph& g)
767 {
768 typedef typename boost::graph_traits<FaceGraph>::halfedge_descriptor halfedge_descriptor;
769
770 halfedge_descriptor hq=halfedge(q, g);
771 halfedge_descriptor hp=halfedge(p, g);
772 for(halfedge_descriptor h : halfedges_around_target(hq, g))
773 set_target(h, p, g);
774 for(halfedge_descriptor h : halfedges_around_target(hp, g))
775 set_target(h, q, g);
776 set_halfedge(p, hq, g);
777 set_halfedge(q, hp, g);
778 }
779
780 template <class FaceGraph>
swap_edges(const typename boost::graph_traits<FaceGraph>::halfedge_descriptor & h1,const typename boost::graph_traits<FaceGraph>::halfedge_descriptor & h2,FaceGraph & g)781 void swap_edges(
782 const typename boost::graph_traits<FaceGraph>::halfedge_descriptor& h1,
783 const typename boost::graph_traits<FaceGraph>::halfedge_descriptor& h2,
784 FaceGraph& g)
785 {
786 typedef typename boost::graph_traits<FaceGraph>::halfedge_descriptor halfedge_descriptor;
787 typedef typename boost::graph_traits<FaceGraph>::face_descriptor face_descriptor;
788 typedef typename boost::graph_traits<FaceGraph>::vertex_descriptor vertex_descriptor;
789 const halfedge_descriptor oh1 = opposite(h1, g), oh2 = opposite(h2, g);
790
791 // backup vertex pointers
792 vertex_descriptor s1 = target(oh1, g), s2 = target(oh2, g);
793 vertex_descriptor t1 = target(h1, g), t2 = target(h2, g);
794
795 // backup face pointers
796 face_descriptor f1 = face(h1, g), f2 = face(h2, g);
797 face_descriptor fo1 = face(oh1, g), fo2 = face(oh2, g);
798
799 // backup next prev pointers
800 halfedge_descriptor nh1 = next(h1, g), nh2 = next(h2, g);
801 halfedge_descriptor ph1 = prev(h1, g), ph2 = prev(h2, g);
802 halfedge_descriptor noh1 = next(oh1, g), noh2 = next(oh2, g);
803 halfedge_descriptor poh1 = prev(oh1, g), poh2 = prev(oh2, g);
804
805 // handle particular cases where next/prev are halfedges to be swapt
806 if (nh1 == oh2) nh1 = oh1;
807 if (nh1 == h2) nh1 = h1;
808 if (nh2 == oh1) nh2 = oh2;
809 if (nh2 == h1) nh2 = h2;
810 if (ph1 == oh2) ph1 = oh1;
811 if (ph1 == h2) ph1 = h1;
812 if (ph2 == oh1) ph2 = oh2;
813 if (ph2 == h1) ph2 = h2;
814 if (noh1 == oh2) noh1 = oh1;
815 if (noh1 == h2) noh1 = h1;
816 if (noh2 == oh1) noh2 = oh2;
817 if (noh2 == h1) noh2 = h2;
818 if (poh1 == oh2) poh1 = oh1;
819 if (poh1 == h2) poh1 = h1;
820 if (poh2 == oh1) poh2 = oh2;
821 if (poh2 == h1) poh2 = h2;
822
823 // (1) exchange next pointers
824 set_next(h1, nh2, g);
825 set_next(h2, nh1, g);
826 set_next(ph1, h2, g);
827 set_next(ph2, h1, g);
828 set_next(oh1, noh2, g);
829 set_next(oh2, noh1, g);
830 set_next(poh1, oh2, g);
831 set_next(poh2, oh1, g);
832
833 // (2) exchange vertex-halfedge pointers
834 set_target(h1, t2, g);
835 set_target(h2, t1, g);
836 set_target(oh1, s2, g);
837 set_target(oh2, s1, g);
838 if (halfedge(t1, g)==h1) set_halfedge(t1, h2, g);
839 if (halfedge(t2, g)==h2) set_halfedge(t2, h1, g);
840 if (halfedge(s1, g)==oh1) set_halfedge(s1, oh2, g);
841 if (halfedge(s2, g)==oh2) set_halfedge(s2, oh1, g);
842
843 // (3) exchange face-halfedge pointers
844 set_face(h1, f2, g);
845 set_face(h2, f1, g);
846 set_face(oh1, fo2, g);
847 set_face(oh2, fo1, g);
848
849 face_descriptor nf = boost::graph_traits<FaceGraph>::null_face();
850 if (f1 != nf && halfedge(f1, g)==h1) set_halfedge(f1, h2, g);
851 if (f2 != nf && halfedge(f2, g)==h2) set_halfedge(f2, h1, g);
852 if (fo1 != nf && halfedge(fo1, g)==oh1) set_halfedge(fo1, oh2, g);
853 if (fo2 != nf && halfedge(fo2, g)==oh2) set_halfedge(fo2, oh1, g);
854 }
855
856
857 } //end of internal namespace
858
859 /**
860 * \ingroup PkgBGLHelperFct
861 *
862 * removes all vertices, faces and halfedges from a graph. Calls
863 * `remove_edge()`, `remove_vertex()`, and `remove_face()` for each
864 * edge, vertex or face.
865 *
866 * If the graph has a member function `clear()`, it will be called
867 * instead.
868 *
869 * @tparam FaceGraph model of `MutableHalfedgeGraph` and `MutableFaceGraph`
870 *
871 * @param g the graph to clear
872 *
873 **/
874 template<typename FaceGraph>
clear(FaceGraph & g)875 void clear(FaceGraph& g)
876 {
877 internal::clear_impl(g);
878 CGAL_postcondition(std::distance(boost::begin(edges(g)),boost::end(edges(g))) == 0);
879 CGAL_postcondition(std::distance(boost::begin(vertices(g)),boost::end(vertices(g))) == 0);
880 CGAL_postcondition(std::distance(boost::begin(faces(g)),boost::end(faces(g))) == 0);
881 }
882
883 /**
884 * \ingroup PkgBGLHelperFct
885 *
886 * checks whether the graph is empty, by checking that it does not contain any vertex.
887 *
888 * @tparam FaceGraph model of `FaceGraph`
889 *
890 * @param g the graph to test
891 *
892 **/
893 template<typename FaceGraph>
is_empty(const FaceGraph & g)894 bool is_empty(const FaceGraph& g)
895 {
896 return boost::empty(vertices(g));
897 }
898
899 /// \ingroup PkgBGLHelperFct
900 ///
901 /// \brief returns the number of calls to `next()` one has to apply to the halfedge `hd`
902 /// for `source(hd, mesh) == vd` to be true, starting from `hd = halfedge(fd, tm)`.
903 ///
904 /// \tparam Graph a model of `FaceGraph`
905 ///
906 /// \param vd a vertex of `g` whose index is sought
907 /// \param fd a face of `g` in which the index of `vd` is sought
908 /// \param g a mesh of type `Graph`
909 ///
910 /// \pre `vd` is a vertex of `fd`.
911 template <typename Graph>
vertex_index_in_face(const typename boost::graph_traits<Graph>::vertex_descriptor vd,const typename boost::graph_traits<Graph>::face_descriptor fd,const Graph & g)912 int vertex_index_in_face(const typename boost::graph_traits<Graph>::vertex_descriptor vd,
913 const typename boost::graph_traits<Graph>::face_descriptor fd,
914 const Graph& g)
915 {
916 typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
917
918 halfedge_descriptor start = halfedge(fd, g);
919 halfedge_descriptor current = start;
920 int counter = 0;
921
922 do
923 {
924 if(source(current, g) == vd)
925 break;
926
927 ++counter;
928 current = next(current, g);
929 }
930 while(current != start);
931
932 if(counter != 0 && current == start)
933 {
934 CGAL_assertion_msg(false, "Could not find vertex in face");
935 return -1;
936 }
937
938 return counter;
939 }
940
941 /// \ingroup PkgBGLHelperFct
942 ///
943 /// \brief returns the number of calls to `next(hd, tm)` one has to apply to `hd` for `hd == he`
944 /// to be true, starting from `hd = halfedge(face(he, tm), tm)`.
945 ///
946 /// \tparam Graph a model of `FaceGraph`.
947 ///
948 /// \param he a halfedge of `g` whose index in `face(he, tm)` is sought
949 /// \param g an object of type `Graph`
950 ///
951 template <typename Graph>
halfedge_index_in_face(typename boost::graph_traits<Graph>::halfedge_descriptor he,const Graph & g)952 int halfedge_index_in_face(typename boost::graph_traits<Graph>::halfedge_descriptor he,
953 const Graph& g)
954 {
955 typedef typename boost::graph_traits<Graph>::halfedge_descriptor halfedge_descriptor;
956 typedef typename boost::graph_traits<Graph>::face_descriptor face_descriptor;
957
958 CGAL_precondition(he != boost::graph_traits<Graph>::null_halfedge());
959 CGAL_precondition(!is_border(he, g));
960
961 face_descriptor f = face(he, g);
962 halfedge_descriptor start = halfedge(f, g);
963 halfedge_descriptor current = start;
964 int count = 0;
965
966 while(current != he)
967 {
968 current = next(current, g);
969 ++count;
970 }
971
972 return count;
973 }
974
975 } // namespace CGAL
976
977 // Here at the bottom because helpers.h must include generators (for backward compatibility reasons),
978 // and Euler_operations.h needs helpers.h
979 #include <CGAL/boost/graph/generators.h>
980
981 #endif // CGAL_BOOST_GRAPH_HELPERS_H
982