1 // Copyright (C) 2013 INRIA - Sophia Antipolis (France). 2 // Copyright (c) 2017 GeometryFactory Sarl (France). 3 // 4 // This file is part of CGAL (www.cgal.org). 5 // 6 // $URL: https://github.com/CGAL/cgal/blob/v5.3/Scale_space_reconstruction_3/include/CGAL/Scale_space_reconstruction_3/Alpha_shape_mesher.h $ 7 // $Id: Alpha_shape_mesher.h e895f42 2021-01-06T14:29:37+01:00 Simon Giraudot 8 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial 9 // 10 // Author(s): Thijs van Lankveld, Simon Giraudot 11 12 13 #ifndef CGAL_SCALE_SPACE_RECONSTRUCTION_3_ALPHA_SHAPE_MESHER_H 14 #define CGAL_SCALE_SPACE_RECONSTRUCTION_3_ALPHA_SHAPE_MESHER_H 15 16 #include <CGAL/license/Scale_space_reconstruction_3.h> 17 18 #include <CGAL/Scale_space_reconstruction_3/Shape_construction_3.h> 19 20 #include <CGAL/Union_find.h> 21 22 namespace CGAL 23 { 24 25 namespace Scale_space_reconstruction_3 26 { 27 28 /** \ingroup PkgScaleSpaceReconstruction3Classes 29 * 30 * Surface mesher for scale space reconstruction based on 31 * `CGAL::Alpha_shape_3`. 32 * 33 * The surface can be constructed either for a fixed neighborhood 34 * radius, or for a dynamic radius. When constructing the surface for 35 * exactly one neighborhood radius, it is faster to set 36 * `FixedSurface` to `Tag_true`. If the correct neighborhood radius 37 * should be changed or estimated multiple times, it is faster to set 38 * `FixedSurface` to `Tag_false`. 39 * 40 * It is undefined whether a surface with fixed radius may have its radius 41 * changed, but if so, this will likely require more computation time than 42 * changing the radius of a dynamic surface. In either case, it is possible to 43 * change the point set while maintaining the same radius. 44 * 45 * The surface can be stored either as an unordered collection of triangles, 46 * or as a collection ordered by shells. A shell is a maximally connected 47 * component of the surface where connected facets are locally oriented 48 * towards the same side of the surface. 49 * 50 * \cgalModels CGAL::Scale_space_reconstruction_3::Mesher 51 * 52 * \tparam Geom_traits is the geometric traits class. It must be a 53 * model of `DelaunayTriangulationTraits_3`. It must have a 54 * `RealEmbeddable` field number type. Generally, 55 * `Exact_predicates_inexact_constructions_kernel` is preferred. 56 * \tparam FixedSurface determines whether the surface is expected to 57 * be constructed for a fixed neighborhood radius. It must be a 58 * `Boolean_tag` type. The default value is `Tag_true`. Note that the 59 * value of this parameter does not change the result but only has an 60 * impact on the run-time. 61 */ 62 template <typename Geom_traits, typename FixedSurface = Tag_true> 63 class Alpha_shape_mesher 64 { 65 public: 66 typedef typename Geom_traits::FT FT; 67 typedef typename Geom_traits::Point_3 Point; ///< defines the point type. 68 69 typedef std::array< unsigned int, 3 > Facet; ///< defines a triple of point indices indicating a triangle of the surface. 70 private: 71 typedef std::list< Facet > Facetset; ///< defines a collection of triples. 72 // Note that this is a list for two reasons: iterator validity for the shell iterators, and memory requirements for the expected huge collections. 73 74 public: 75 #ifdef DOXYGEN_RUNNING 76 typedef unspecified_type Facet_iterator; ///< defines an iterator over the triples. 77 typedef const unspecified_type Facet_const_iterator; ///< defines a constant iterator over the triples. 78 #else // DOXYGEN_RUNNING 79 typedef Facetset::iterator Facet_iterator; 80 typedef Facetset::const_iterator Facet_const_iterator; 81 #endif // DOXYGEN_RUNNING 82 83 private: 84 typedef std::vector< Facet_iterator > FacetIterSet; 85 86 private: 87 88 // Constructing the surface. 89 typedef CGAL::Shape_construction_3<Geom_traits, FixedSurface> Shape_construction_3; 90 91 typedef typename Shape_construction_3::Shape Shape; 92 typedef typename Shape_construction_3::Triangulation Triangulation; 93 94 typedef typename Shape::Vertex_handle Vertex_handle; 95 typedef typename Shape::Cell_handle Cell_handle; 96 typedef typename Shape::Facet SFacet; 97 typedef typename Shape::Edge Edge; 98 typedef std::pair<Vertex_handle, Vertex_handle> VEdge; 99 100 typedef typename Shape::Vertex_iterator Vertex_iterator; 101 typedef typename Shape::Cell_iterator Cell_iterator; 102 typedef typename Shape::Facet_iterator SFacet_iterator; 103 typedef typename Shape::Edge_iterator Edge_iterator; 104 105 typedef typename Shape::Finite_cells_iterator Finite_cells_iterator; 106 typedef typename Shape::Finite_facets_iterator Finite_facets_iterator; 107 typedef typename Shape::Finite_edges_iterator Finite_edges_iterator; 108 typedef typename Shape::Finite_vertices_iterator Finite_vertices_iterator; 109 110 typedef typename Shape::Facet_circulator SFacet_circulator; 111 112 typedef typename Shape::All_cells_iterator All_cells_iterator; 113 114 typedef typename Shape::Classification_type Classification_type; 115 116 typedef std::map<SFacet, unsigned int> Map_facet_to_shell; 117 typedef typename std::array<std::set<SFacet>, 2 > Bubble; 118 119 bool _separate_shells; 120 bool _force_manifold; 121 FT _border_angle; 122 123 // The shape must be a pointer, because the alpha of a Fixed_alpha_shape_3 124 // can only be set at construction and its assignment operator is private. 125 // We want to be able to set the alpha after constructing the scale-space 126 // reconstructer object. 127 Shape* _shape; 128 129 // The surface. If the surface is collected per shell, the triples of the 130 // same shell are stored consecutively. 131 Facetset _surface; 132 133 // The shells can be accessed through iterators to the surface. 134 FacetIterSet _shells; 135 136 // If the surface is forced to be manifold, removed facets are stored 137 Facetset _garbage; 138 139 // Map TDS facets to shells 140 Map_facet_to_shell _map_f2s; 141 unsigned int _index; 142 143 std::vector<Bubble> _bubbles; 144 std::map<SFacet, std::size_t> _map_f2b; 145 146 FT _squared_radius; 147 148 public: 149 150 /** 151 * Constructs an alpha shape mesher. 152 * 153 * \param squared_radius \f$\alpha\f$ parameter of the alpha shape algorithm. 154 * \param separate_shells determines whether to collect the surface per shell. 155 * \param force_manifold determines if the surface is forced to be 2-manifold. 156 * \param border_angle sets the maximal angle between two facets 157 * such that the edge is seen as a border. 158 * 159 * If the output is forced to be 2-manifold, some almost flat 160 * volume bubbles are detected. To do so, border edges must be 161 * estimated. 162 * 163 * An edge adjacent to 2 regular facets is considered as a border 164 * if it is also adjacent to a singular facet or if the angle 165 * between the two regular facets is lower than this parameter 166 * (set to 45° by default). 167 * 168 * \note `border_angle` is not used if `force_manifold` is set to false. 169 */ 170 Alpha_shape_mesher (FT squared_radius, 171 bool separate_shells = false, 172 bool force_manifold = false, 173 FT border_angle = 45.) _separate_shells(separate_shells)174 : _separate_shells (separate_shells), 175 _force_manifold (force_manifold), 176 _border_angle (border_angle), 177 _shape (nullptr), 178 _squared_radius (squared_radius) 179 { 180 181 } 182 ~Alpha_shape_mesher()183 ~Alpha_shape_mesher () 184 { 185 clear_surface(); 186 } 187 188 /// \cond SKIP_IN_MANUAL 189 template <typename InputIterator, typename OutputIterator> operator()190 void operator() (InputIterator begin, InputIterator end, OutputIterator output) 191 { 192 clear_surface(); 193 194 _shape = Shape_construction_3().construct (begin, end, _squared_radius); 195 196 // If shells are not separated and no manifold constraint is given, 197 // then the quick collection of facets can be applied 198 if (!_separate_shells && !_force_manifold) 199 { 200 collect_facets_quick (); 201 _shells.push_back (_surface.begin ()); 202 } 203 else 204 { 205 // Init shell index 206 _index = 0; 207 208 // Collect all surface meshes from the alpha-shape in a fashion similar to ball-pivoting. 209 // Reset the facet handled markers. 210 for( All_cells_iterator cit = _shape->all_cells_begin(); cit != _shape->all_cells_end(); ++cit ) 211 cit->info() = 0; 212 213 if (_force_manifold) 214 { 215 // If manifold surface is wanted, small volumes (bubbles) are first detected in 216 // order to know which layer to ignore when collecting facets 217 detect_bubbles(); 218 } 219 220 collect_facets (); 221 222 if (_force_manifold) 223 { 224 // Even when taking into account facets, some nonmanifold features might remain 225 fix_nonmanifold_edges(); 226 fix_nonmanifold_vertices(); 227 } 228 } 229 230 for (Facet_iterator it = _surface.begin(); it != _surface.end(); ++ it) 231 { 232 std::array<std::size_t, 3> f = {{ std::size_t((*it)[0]), std::size_t((*it)[1]), std::size_t((*it)[2]) }}; 233 *(output ++) = f; 234 } 235 } 236 /// \endcond 237 238 /// gives the number of triangles of the surface. number_of_triangles()239 std::size_t number_of_triangles() const { return _surface.size(); } 240 241 /// gives an iterator to the first triple in the surface. surface_begin()242 Facet_const_iterator surface_begin() const { return _surface.begin(); } 243 /// gives an iterator to the first triple in the surface. 244 /** \warning Changes to the surface may change its topology. 245 */ surface_begin()246 Facet_iterator surface_begin() { return _surface.begin(); } 247 248 /// gives a past-the-end iterator of the triples in the surface. surface_end()249 Facet_const_iterator surface_end() const { return _surface.end(); } 250 /// gives a past-the-end iterator of the triples in the surface. 251 /** \warning Changes to the surface may change its topology. 252 */ surface_end()253 Facet_iterator surface_end() { return _surface.end(); } 254 255 256 /// gives the number of shells of the surface. number_of_shells()257 std::size_t number_of_shells() const { 258 return _shells.size(); 259 } 260 261 /// gives an iterator to the first triple in a given shell. 262 /** \param shell is the index of the shell to access. 263 * 264 * \pre `shell` is in the range [ 0, `number_of_shells()` ). 265 */ shell_begin(std::size_t shell)266 Facet_const_iterator shell_begin( std::size_t shell ) const 267 { 268 CGAL_assertion( shell < _shells.size() ); 269 return _shells[ shell ]; 270 } 271 /// gives an iterator to the first triple in a given shell. 272 /** \param shell is the index of the shell to access. 273 * 274 * \pre `shell` is in the range [ 0, `number_of_shells()` ). 275 * 276 * \warning Changes to a shell may invalidate the topology of the surface. 277 */ shell_begin(std::size_t shell)278 Facet_iterator shell_begin( std::size_t shell ) 279 { 280 CGAL_assertion( shell < _shells.size() ); 281 return _shells[ shell ]; 282 } 283 284 /// gives a past-the-end iterator of the triples in a given shell. 285 /** \param shell is the index of the shell to access. 286 * 287 * \pre `shell` is in the range [ 0, `number_of_shells()` ). 288 */ shell_end(std::size_t shell)289 Facet_const_iterator shell_end( std::size_t shell ) const 290 { 291 CGAL_assertion( shell < _shells.size() ); 292 if( shell == _shells.size()-1 ) 293 return _surface.end(); 294 return _shells[ shell+1 ]; 295 } 296 297 /// gives a past-the-end iterator of the triples in a given shell. 298 /** \param shell is the index of the shell to access. 299 * 300 * \pre `shell` is in the range [ 0, `number_of_shells()` ). 301 * 302 * \warning Changes to a shell may invalidate the topology of the surface. 303 */ shell_end(std::size_t shell)304 Facet_iterator shell_end( std::size_t shell ) 305 { 306 CGAL_assertion( shell < _shells.size() ); 307 if( shell == _shells.size()-1 ) 308 return _surface.end(); 309 return _shells[ shell+1 ]; 310 } 311 312 /// gives an iterator to the first triple of the garbage facets 313 /// that may be discarded if 2-manifold output is required. garbage_begin()314 Facet_const_iterator garbage_begin() const { return _garbage.begin(); } 315 /// gives an iterator to the first triple of the garbage facets 316 /// that may be discarded if 2-manifold output is required. garbage_begin()317 Facet_iterator garbage_begin() { return _garbage.begin(); } 318 319 /// gives a past-the-end iterator of the triples of the garbage facets 320 /// that may be discarded if 2-manifold output is required. garbage_end()321 Facet_const_iterator garbage_end() const { return _garbage.end(); } 322 /// gives a past-the-end iterator of the triples of the garbage facets 323 /// that may be discarded if 2-manifold output is required. garbage_end()324 Facet_iterator garbage_end() { return _garbage.end(); } 325 326 private: 327 deinit_shape()328 void deinit_shape() 329 { 330 if (_shape != nullptr) 331 { 332 delete _shape; 333 _shape = nullptr; 334 } 335 } 336 clear_surface()337 void clear_surface() 338 { 339 _shells.clear(); 340 _surface.clear(); 341 _garbage.clear(); 342 deinit_shape(); 343 } 344 collect_facets()345 void collect_facets () 346 { 347 // We check each of the facets: if it is not handled and either regular or singular, 348 // we start collecting the next surface from here. 349 for (Finite_facets_iterator fit = _shape->finite_facets_begin(); fit != _shape->finite_facets_end(); ++fit) 350 { 351 switch(_shape->classify (*fit)) 352 { 353 case Shape::REGULAR: 354 // Build a surface from the outer cell. 355 if (_shape->classify(fit->first) == Shape::EXTERIOR) 356 collect_shell (*fit); 357 else 358 collect_shell (_shape->mirror_facet (*fit)); 359 break; 360 case Shape::SINGULAR: 361 // Build a surface from both incident cells. 362 collect_shell (*fit); 363 collect_shell (_shape->mirror_facet (*fit)); 364 break; 365 default: 366 break; 367 } 368 } 369 } 370 collect_facets_quick()371 void collect_facets_quick () 372 { 373 // Collect all facets from the alpha-shape in an unordered fashion. 374 for (Finite_facets_iterator fit = _shape->finite_facets_begin(); fit != _shape->finite_facets_end(); ++fit) 375 { 376 switch (_shape->classify(*fit)) 377 { 378 case Shape::REGULAR: 379 // Collect the outer cell. 380 if (_shape->classify(fit->first) == Shape::EXTERIOR) 381 _surface.push_back (ordered_facet_indices (*fit)); 382 else 383 _surface.push_back (ordered_facet_indices (_shape->mirror_facet(*fit))); 384 break; 385 case Shape::SINGULAR: 386 // Collect both incident cells. 387 _surface.push_back (ordered_facet_indices (*fit)); 388 _surface.push_back (ordered_facet_indices (_shape->mirror_facet (*fit))); 389 break; 390 default: 391 break; 392 } 393 } 394 } 395 is_handled(Cell_handle c,unsigned int li)396 inline bool is_handled( Cell_handle c, unsigned int li ) const 397 { 398 switch( li ) { 399 case 0: return ( c->info()&1 ) != 0; 400 case 1: return ( c->info()&2 ) != 0; 401 case 2: return ( c->info()&4 ) != 0; 402 case 3: return ( c->info()&8 ) != 0; 403 } 404 return false; 405 } is_handled(const SFacet & f)406 inline bool is_handled( const SFacet& f ) const { return is_handled( f.first, f.second ); } 407 mark_handled(Cell_handle c,unsigned int li)408 inline void mark_handled( Cell_handle c, unsigned int li ) 409 { 410 switch( li ) { 411 case 0: c->info() |= 1; return; 412 case 1: c->info() |= 2; return; 413 case 2: c->info() |= 4; return; 414 case 3: c->info() |= 8; return; 415 } 416 } mark_handled(SFacet f)417 inline void mark_handled( SFacet f ) { mark_handled( f.first, f.second ); } 418 mark_opposite_handled(SFacet f)419 inline void mark_opposite_handled( SFacet f ) 420 { 421 422 Classification_type cl = _shape->classify (f); 423 424 // If cell is singular, simply mark mirror facet as handled 425 if (cl == Shape::SINGULAR) 426 { 427 SFacet mirror = _shape->mirror_facet (f); 428 mark_handled (mirror); 429 } 430 // If cell is regular, get corresponding bubble and mark 431 // facets of the other layer of the bubble as handled 432 else if (cl == Shape::REGULAR) 433 { 434 SFacet fac = (_shape->classify (f.first) == Shape::EXTERIOR) 435 ? f 436 : _shape->mirror_facet (f); 437 438 typename std::map<SFacet, std::size_t>::iterator 439 search = _map_f2b.find (fac); 440 441 if (search == _map_f2b.end ()) 442 return; 443 444 unsigned int layer = (_bubbles[search->second][0].find (fac) == _bubbles[search->second][0].end ()) 445 ? 0 : 1; 446 447 typename std::set<SFacet>::iterator it = _bubbles[search->second][layer].begin (); 448 449 // If bubble has already been handled, no need to do it again 450 if (is_handled (*it)) 451 return; 452 453 for (;it != _bubbles[search->second][layer].end (); ++ it) 454 { 455 _garbage.push_back (ordered_facet_indices (*it)); 456 mark_handled (*it); 457 } 458 459 } 460 461 462 } 463 464 ordered_facet_indices(const SFacet & f)465 inline Facet ordered_facet_indices( const SFacet& f ) const 466 { 467 if( (f.second&1) == 0 ) 468 return make_array<unsigned int>( f.first->vertex( (f.second+2)&3 )->info(), 469 f.first->vertex( (f.second+1)&3 )->info(), 470 f.first->vertex( (f.second+3)&3 )->info() ); 471 else 472 return make_array<unsigned int>( f.first->vertex( (f.second+1)&3 )->info(), 473 f.first->vertex( (f.second+2)&3 )->info(), 474 f.first->vertex( (f.second+3)&3 )->info() ); 475 } 476 collect_shell(const SFacet & f)477 void collect_shell( const SFacet& f) 478 { 479 collect_shell (f.first, f.second); 480 } collect_shell(Cell_handle c,unsigned int li)481 void collect_shell( Cell_handle c, unsigned int li) 482 { 483 // Collect one surface mesh from the alpha-shape in a fashion similar to ball-pivoting. 484 // Invariant: the facet is regular or singular. 485 486 487 // To stop stack overflows: use own stack. 488 std::stack<SFacet> stack; 489 stack.push( SFacet(c, li) ); 490 491 SFacet f; 492 Cell_handle n, p; 493 int ni, pi; 494 Vertex_handle a; 495 Classification_type cl; 496 bool processed = false; 497 498 while( !stack.empty() ) { 499 f = stack.top(); 500 stack.pop(); 501 502 // Check if the cell was already handled. 503 // Note that this is an extra check that in many cases is not necessary. 504 if( is_handled(f) ) 505 continue; 506 507 // The facet is part of the surface. 508 CGAL_assertion( !_shape->is_infinite(f) ); 509 mark_handled(f); 510 // Output the facet as a triple of indices. 511 _surface.push_back( ordered_facet_indices(f) ); 512 if( !processed ) { 513 if (_separate_shells || _shells.size () == 0) 514 { 515 _shells.push_back( --_surface.end() ); 516 _index ++; 517 } 518 processed = true; 519 } 520 521 // Save in which shell the facet is stored 522 _map_f2s[f] = _index-1; 523 524 // If the surface is required to be manifold, 525 // the opposite layer should be ignored 526 if (_force_manifold) 527 mark_opposite_handled (f); 528 529 // Pivot over each of the facet's edges and continue the surface at the next regular or singular facet. 530 for( int i = 0; i < 4; ++i ) { 531 // Skip the current facet. 532 if( i == f.second || is_handled(f.first, i) ) 533 continue; 534 535 // Rotate around the edge (starting from the shared facet in the current cell) until a regular or singular facet is found. 536 n = f.first; 537 ni = i; 538 a = f.first->vertex( f.second ); 539 cl = _shape->classify( SFacet(n, ni) ); 540 541 while( cl != Shape::REGULAR && cl != Shape::SINGULAR ) { 542 p = n; 543 n = n->neighbor(ni); 544 ni = n->index(a); 545 pi = n->index(p); 546 a = n->vertex(pi); 547 cl = _shape->classify( SFacet(n, ni) ); 548 } 549 550 // Continue the surface at the next regular or singular facet. 551 stack.push( SFacet(n, ni) ); 552 } 553 554 } 555 556 } 557 detect_bubbles()558 void detect_bubbles () 559 { 560 std::set<Cell_handle> done; 561 562 unsigned int nb_facets_removed = 0; 563 564 unsigned int nb_skipped = 0; 565 for (Cell_iterator cit = _shape->cells_begin (); cit != _shape->cells_end (); ++ cit) 566 { 567 if (_shape->is_infinite (cit)) 568 continue; 569 if (_shape->classify (cit) != Shape::INTERIOR) 570 continue; 571 if (done.find (cit) != done.end ()) 572 continue; 573 574 std::set<VEdge> borders; 575 std::vector<Cell_handle> cells; 576 std::stack<Cell_handle> todo; 577 todo.push (cit); 578 579 // Get all cells of volume and all borders 580 while (!(todo.empty ())) 581 { 582 Cell_handle c = todo.top (); 583 todo.pop (); 584 585 if (!(done.insert (c).second)) 586 continue; 587 588 cells.push_back (c); 589 590 for (unsigned int i = 0; i < 4; ++ i) 591 { 592 if (_shape->classify (c->neighbor (i)) == Shape::INTERIOR) 593 todo.push (c->neighbor (i)); 594 else 595 { 596 // Test if edge is proper border 597 for (unsigned int j = 0; j < 3; ++ j) 598 { 599 unsigned int i0 = (i + j + 1)%4; 600 unsigned int i1 = (i + (j+1)%3 + 1)%4; 601 CGAL_assertion (i0 != i && i1 != i); 602 Edge edge (c, i0, i1); 603 604 if (_shape->classify (edge) != Shape::REGULAR) 605 continue; 606 607 VEdge vedge = (c->vertex (i0) < c->vertex (i1)) 608 ? std::make_pair (c->vertex (i0), c->vertex (i1)) 609 : std::make_pair (c->vertex (i1), c->vertex (i0)); 610 611 if (borders.find (vedge) != borders.end ()) 612 continue; 613 614 SFacet_circulator start = _shape->incident_facets (edge); 615 SFacet_circulator circ = start; 616 unsigned int cnt = 0; 617 do 618 { 619 if (_shape->classify (*circ) == Shape::SINGULAR 620 || _shape->classify (*circ) == Shape::REGULAR) 621 ++ cnt; 622 ++ circ; 623 } 624 while (circ != start); 625 626 // If edge is non-manifold, use as border 627 if (cnt > 2) 628 { 629 borders.insert (vedge); 630 continue; 631 } 632 633 // Else, if facets in cell are regular and angle is 634 // under _border_angle limit, use as border 635 SFacet f0 (c, i); 636 SFacet f1 (c, (i + (j+2)%3 + 1)%4); 637 638 if (_shape->classify (f0) != Shape::REGULAR 639 || _shape->classify (f1) != Shape::REGULAR) 640 continue; 641 642 double angle = Geom_traits().compute_approximate_dihedral_angle_3_object()(vedge.first->point (), 643 vedge.second->point (), 644 c->vertex (i)->point (), 645 c->vertex ((i + (j+2)%3 + 1)%4)->point ()); 646 647 if (-_border_angle < angle && angle < _border_angle) 648 { 649 borders.insert (vedge); 650 } 651 } 652 653 } 654 } 655 } 656 657 int layer = -1; 658 659 // Try to generate bubble from the volume found 660 _bubbles.push_back (Bubble()); 661 std::set<SFacet> done; 662 for (unsigned int c = 0; c < cells.size (); ++ c) 663 { 664 for (unsigned int ii = 0; ii < 4; ++ ii) 665 { 666 SFacet start = _shape->mirror_facet (SFacet (cells[c], ii)); 667 668 if (_shape->classify (start) != Shape::REGULAR) 669 continue; 670 671 if (done.find (start) != done.end ()) 672 continue; 673 674 ++ layer; 675 676 std::stack<SFacet> stack; 677 stack.push (start); 678 679 SFacet f; 680 Cell_handle n, p; 681 int ni, pi; 682 Vertex_handle a; 683 Classification_type cl; 684 685 // A bubble is well formed is the border contains one loop that 686 // separates two layers. 687 // If the number of layers is different than 2, the volume is completely ignored. 688 while( !stack.empty() ) 689 { 690 f = stack.top(); 691 stack.pop(); 692 693 if (!(done.insert (f).second)) 694 continue; 695 696 if (_shape->classify (f.first) == Shape::EXTERIOR) 697 { 698 if (layer < 2) 699 { 700 _bubbles.back ()[layer].insert (f); 701 _map_f2b[f] = _bubbles.size () - 1; 702 } 703 else 704 { 705 nb_facets_removed ++; 706 mark_handled (f); 707 _garbage.push_back (ordered_facet_indices (f)); 708 } 709 } 710 else 711 { 712 if (layer < 2) 713 { 714 _bubbles.back ()[layer].insert (_shape->mirror_facet (f)); 715 _map_f2b[_shape->mirror_facet (f)] = _bubbles.size () - 1; 716 } 717 else 718 { 719 nb_facets_removed ++; 720 mark_handled (_shape->mirror_facet (f)); 721 _garbage.push_back (ordered_facet_indices (_shape->mirror_facet (f))); 722 } 723 } 724 725 726 for( int i = 0; i < 4; ++i ) 727 { 728 // Skip the current facet. 729 if( i == f.second) 730 continue; 731 732 n = f.first; 733 ni = i; 734 a = f.first->vertex( f.second ); 735 cl = _shape->classify( SFacet(n, ni) ); 736 737 int n0 = -1, n1 = -1; 738 bool n0found = false; 739 for (int j = 0; j < 4; ++ j) 740 { 741 if (j != ni && j != f.second) 742 { 743 if (n0found) 744 { 745 n1 = j; 746 break; 747 } 748 else 749 { 750 n0 = j; 751 n0found = true; 752 } 753 } 754 } 755 756 VEdge vedge = (n->vertex (n0) < n->vertex (n1)) 757 ? std::make_pair (n->vertex (n0), n->vertex (n1)) 758 : std::make_pair (n->vertex (n1), n->vertex (n0)); 759 760 // If the edge is a border, propagation stops in this direction. 761 if (borders.find (vedge) != borders.end ()) 762 continue; 763 764 while( cl != Shape::REGULAR && cl != Shape::SINGULAR ) { 765 p = n; 766 n = n->neighbor(ni); 767 ni = n->index(a); 768 pi = n->index(p); 769 a = n->vertex(pi); 770 cl = _shape->classify( SFacet(n, ni) ); 771 } 772 773 stack.push (SFacet (n, ni)); 774 775 } 776 777 } 778 } 779 780 } 781 782 // If number of layers is != 2, ignore volume and discard bubble 783 if (layer != 1) 784 { 785 nb_skipped ++; 786 for (unsigned int i = 0; i < 2; ++ i) 787 for (typename std::set<SFacet>::iterator fit = _bubbles.back()[i].begin (); 788 fit != _bubbles.back()[i].end (); ++ fit) 789 { 790 mark_handled (*fit); 791 _map_f2b.erase (*fit); 792 _garbage.push_back (ordered_facet_indices (*fit)); 793 nb_facets_removed ++; 794 } 795 _bubbles.pop_back (); 796 } 797 798 } 799 } 800 801 fix_nonmanifold_edges()802 void fix_nonmanifold_edges() 803 { 804 805 typedef std::map<std::pair<VEdge, unsigned int>, std::set<Facet> > Edge_shell_map_triples; 806 typedef typename Edge_shell_map_triples::iterator Edge_shell_map_triples_iterator; 807 808 unsigned int nb_facets_removed = 0; 809 810 unsigned int nb_nm_edges = 0; 811 812 // Store for each pair edge/shell the incident facets 813 Edge_shell_map_triples eshell_triples; 814 std::map<Facet, SFacet> map_t2f; 815 816 for (typename Map_facet_to_shell::iterator fit = _map_f2s.begin (); 817 fit != _map_f2s.end (); ++ fit) 818 { 819 SFacet f = fit->first; 820 Facet t = ordered_facet_indices (f); 821 map_t2f[t] = f; 822 823 for (unsigned int k = 0; k < 3; ++ k) 824 { 825 Vertex_handle v0 = f.first->vertex ((f.second + k + 1)%4); 826 Vertex_handle v1 = f.first->vertex ((f.second + (k+1)%3 + 1)%4); 827 VEdge vedge = (v0 < v1) ? std::make_pair (v0, v1) : std::make_pair (v1, v0); 828 829 std::pair<Edge_shell_map_triples_iterator, bool> 830 search = eshell_triples.insert (std::make_pair (std::make_pair (vedge, fit->second), 831 std::set<Facet>())); 832 833 search.first->second.insert (t); 834 } 835 } 836 837 for (Edge_shell_map_triples_iterator eit = eshell_triples.begin (); 838 eit != eshell_triples.end (); ++ eit) 839 { 840 // If an edge has more than 2 incident facets for one shell, it is non-manifold 841 if (eit->second.size () < 3) 842 continue; 843 844 ++ nb_nm_edges; 845 846 Facet_iterator tit = _shells[eit->first.second]; 847 Facet_iterator end = (eit->first.second == _shells.size () - 1) 848 ? _surface.end () : _shells[eit->first.second + 1]; 849 850 // Remove facets until the edge is manifold in this shell 851 while (tit != end && eit->second.size () > 2) 852 { 853 Facet_iterator current = tit ++; 854 855 typename std::set<Facet>::iterator search = eit->second.find (*current); 856 857 if (search != eit->second.end ()) 858 { 859 if (current == _shells[eit->first.second]) 860 _shells[eit->first.second] = tit; 861 862 _garbage.push_back (*current); 863 _map_f2s.erase (map_t2f[*current]); 864 _surface.erase (current); 865 866 ++ nb_facets_removed; 867 eit->second.erase (search); 868 } 869 870 } 871 872 } 873 } 874 875 template <typename T> 876 struct operator_less 877 { operatoroperator_less878 bool operator() (const T& a, const T& b) const 879 { 880 return &*a < &*b; 881 } 882 }; 883 884 find_two_other_vertices(const SFacet & f,Vertex_handle v,Vertex_handle & v1,Vertex_handle & v2)885 void find_two_other_vertices(const SFacet& f, Vertex_handle v, 886 Vertex_handle& v1, Vertex_handle& v2) 887 { 888 Vertex_handle vother = f.first->vertex (f.second); 889 bool v1found = false; 890 891 for (unsigned int i = 0; i < 4; ++ i) 892 { 893 Vertex_handle vi = f.first->vertex (i); 894 if (vi != v && vi != vother) 895 { 896 if (v1found) 897 { 898 v2 = vi; 899 return; 900 } 901 else 902 { 903 v1 = vi; 904 v1found = true; 905 } 906 } 907 } 908 } 909 fix_nonmanifold_vertices()910 void fix_nonmanifold_vertices() 911 { 912 913 typedef ::CGAL::Union_find<SFacet> UF; 914 typedef typename UF::handle UF_handle; 915 916 917 typedef std::map<std::pair<Vertex_handle, unsigned int>, std::vector<SFacet> > Vertex_shell_map_facets; 918 typedef typename Vertex_shell_map_facets::iterator Vertex_shell_map_facet_iterator; 919 920 // For faster facet removal, we sort the triples of each shell as a preprocessing 921 for (unsigned int i = 0; i < _shells.size (); ++ i) 922 { 923 Facet_iterator begin = _shells[i]; 924 Facet_iterator end = (i+1 == _shells.size ()) ? _surface.end () : _shells[i+1]; 925 926 Facetset tmp; 927 tmp.splice (tmp.end(), _surface, begin, end); 928 929 tmp.sort(); 930 _shells[i] = tmp.begin (); 931 _surface.splice(end, tmp, tmp.begin(), tmp.end()); 932 } 933 934 unsigned int nb_facets_removed = 0; 935 unsigned int nb_nm_vertices = 0; 936 // Removing facets to fix non-manifold vertices might make some other vertices 937 // become non-manifold, therefore we iterate until no facet needs to be removed. 938 do 939 { 940 nb_nm_vertices = 0; 941 nb_facets_removed = 0; 942 943 // Store for each pair vertex/shell the incident facets 944 Vertex_shell_map_facets vshell_facets; 945 946 for (typename Map_facet_to_shell::iterator fit = _map_f2s.begin (); 947 fit != _map_f2s.end (); ++ fit) 948 { 949 SFacet f = fit->first; 950 951 for (unsigned int k = 0; k < 3; ++ k) 952 { 953 Vertex_handle v = f.first->vertex ((f.second+k+1)%4); 954 955 std::pair<Vertex_shell_map_facet_iterator, bool> 956 search = vshell_facets.insert (std::make_pair (std::make_pair (v, fit->second), 957 std::vector<SFacet>())); 958 search.first->second.push_back (f); 959 960 } 961 962 } 963 964 for (Vertex_shell_map_facet_iterator fit = vshell_facets.begin (); 965 fit != vshell_facets.end (); ++ fit) 966 { 967 if (fit->second.size () < 2) 968 continue; 969 970 Vertex_handle vit = fit->first.first; 971 unsigned int shell = fit->first.second; 972 973 UF uf; 974 std::map<SFacet, UF_handle> map_f2h; 975 976 for (unsigned int i = 0; i < fit->second.size (); ++ i) 977 map_f2h.insert (std::make_pair (fit->second[i], uf.make_set (fit->second[i]))); 978 979 std::map<Vertex_handle, SFacet> map_v2f; 980 981 for (unsigned int i = 0; i < fit->second.size (); ++ i) 982 { 983 Vertex_handle v1, v2; 984 find_two_other_vertices (fit->second[i], vit, v1, v2); 985 std::pair<typename std::map<Vertex_handle, SFacet>::iterator, bool> 986 insertion1 = map_v2f.insert (std::make_pair (v1, fit->second[i])); 987 if (!(insertion1.second)) 988 uf.unify_sets (map_f2h[fit->second[i]], map_f2h[insertion1.first->second]); 989 std::pair<typename std::map<Vertex_handle, SFacet>::iterator, bool> 990 insertion2 = map_v2f.insert (std::make_pair (v2, fit->second[i])); 991 if (!(insertion2.second)) 992 uf.unify_sets (map_f2h[fit->second[i]], map_f2h[insertion2.first->second]); 993 } 994 995 if (uf.number_of_sets () > 1) 996 { 997 ++ nb_nm_vertices; 998 999 typedef std::map<UF_handle, std::vector<SFacet>, operator_less<UF_handle> > Map_uf_sets; 1000 Map_uf_sets map_h2f; 1001 for (unsigned int i = 0; i < fit->second.size (); ++ i) 1002 { 1003 UF_handle handle = uf.find (map_f2h[fit->second[i]]); 1004 1005 std::pair<typename Map_uf_sets::iterator, bool> 1006 insertion = map_h2f.insert (std::make_pair (handle, std::vector<SFacet>())); 1007 1008 insertion.first->second.push_back (fit->second[i]); 1009 } 1010 1011 typename Map_uf_sets::iterator largest = map_h2f.end (); 1012 std::size_t nb_largest = 0; 1013 for (typename Map_uf_sets::iterator ufit = map_h2f.begin (); ufit != map_h2f.end (); ++ ufit) 1014 { 1015 std::size_t size = ufit->second.size (); 1016 if (size > nb_largest) 1017 { 1018 nb_largest = size; 1019 largest = ufit; 1020 } 1021 } 1022 1023 std::vector<Facet> triples; 1024 1025 for (typename Map_uf_sets::iterator ufit = map_h2f.begin (); ufit != map_h2f.end (); ++ ufit) 1026 { 1027 if (ufit == largest) 1028 continue; 1029 for (unsigned int i = 0; i < ufit->second.size (); ++ i) 1030 { 1031 _map_f2s.erase (ufit->second[i]); 1032 triples.push_back (ordered_facet_indices (ufit->second[i])); 1033 } 1034 } 1035 std::sort (triples.begin (), triples.end ()); 1036 1037 Facet_iterator tit = _shells[shell]; 1038 Facet_iterator end = (shell == _shells.size () - 1) 1039 ? _surface.end () : _shells[shell + 1]; 1040 1041 unsigned int tindex = 0; 1042 1043 while (tit != end && tindex < triples.size ()) 1044 { 1045 Facet_iterator current = tit ++; 1046 1047 if (*current == triples[tindex]) 1048 { 1049 if (current == _shells[shell]) 1050 _shells[shell] = tit; 1051 1052 _garbage.push_back (*current); 1053 _surface.erase (current); 1054 1055 ++ nb_facets_removed; 1056 ++ tindex; 1057 } 1058 1059 } 1060 } 1061 1062 } 1063 1064 } 1065 while (nb_nm_vertices != 0); 1066 1067 } 1068 1069 }; 1070 1071 1072 } // namespace Scale_space_reconstruction_3 1073 1074 } // namespace CGAL 1075 1076 #endif // CGAL_SCALE_SPACE_RECONSTRUCTION_3_ALPHA_SHAPE_MESHER_H 1077