1 // Copyright (c) 2019 CNRS and LIRIS' Establishments (France). 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/Surface_mesh_topology/include/CGAL/Surface_mesh_topology/internal/Path_on_surface_with_rle.h $ 7 // $Id: Path_on_surface_with_rle.h 11f2b92 2021-02-25T13:43:38+01:00 Sebastien Loriot 8 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial 9 // 10 // Author(s) : Guillaume Damiand <guillaume.damiand@liris.cnrs.fr> 11 // 12 #ifndef CGAL_PATH_ON_SURFACE_WITH_RLE_H 13 #define CGAL_PATH_ON_SURFACE_WITH_RLE_H 1 14 15 #include <CGAL/license/Surface_mesh_topology.h> 16 17 #include <list> 18 #include <utility> 19 #include <iostream> 20 #include <iterator> 21 #include <vector> 22 #include <set> 23 #include <CGAL/assertions.h> 24 #include <unordered_map> 25 #include <unordered_set> 26 27 namespace CGAL { 28 namespace Surface_mesh_topology { 29 30 template<typename Map_> 31 class Path_on_surface; 32 33 template<typename Mesh_> 34 class Minimal_quadrangulation; 35 36 namespace internal { 37 38 // A flat is a sequence of darts given by its two extremities: begin and end, 39 // with +2 turns (if length>0) or -2 turns (if length<0). 40 // length==0 => begin==end. 41 template<typename Map_> 42 class CFlat 43 { 44 typedef Map_ Map; 45 typedef typename Map::Dart_const_handle Dart_const_handle; 46 typedef CFlat<Map> Self; 47 48 public: CFlat(Dart_const_handle dh)49 CFlat(Dart_const_handle dh) : begin(dh), end(dh), length(0) 50 {} 51 CFlat(Dart_const_handle dh1,Dart_const_handle dh2,int l)52 CFlat(Dart_const_handle dh1, Dart_const_handle dh2, int l) : 53 begin(dh1), end(dh2), length(l) 54 {} 55 56 bool operator==(const Self& other) const 57 { return begin==other.begin && end==other.end && length==other.length; } 58 59 bool operator!=(const Self& other) const 60 { return !(operator==(other)); } 61 62 friend std::ostream& operator<< (std::ostream& os, const Self& flat) 63 { 64 os<<"["<<&*(flat.begin)<<", "<<&*(flat.end)<<" (l="<<flat.length<<")]"; 65 return os; 66 } 67 68 Dart_const_handle begin, end; 69 int length; // Length of the flat, positive flat if >0, negative flat if <0 70 }; 71 72 // Small wrapper allowing to use directly a combinatorial map as if it is a 73 // minimal quadrangulation. 74 template<class Map_> 75 class Light_MQ // MQ for minimal quadrangulation 76 { 77 public: 78 typedef Map_ Local_map; 79 typedef Map_ Mesh; 80 typedef typename Map_::Dart_const_handle Dart_const_handle; 81 Light_MQ(const Local_map & m)82 Light_MQ(const Local_map& m): m_map(m) 83 {} 84 Light_MQ(const Light_MQ&) = default; 85 get_local_map()86 const Local_map& get_local_map() const 87 { return m_map; } 88 positive_turn(Dart_const_handle d1,Dart_const_handle d2)89 std::size_t positive_turn(Dart_const_handle d1, Dart_const_handle d2) const 90 { return m_map.positive_turn(d1, d2); } 91 negative_turn(Dart_const_handle d1,Dart_const_handle d2)92 std::size_t negative_turn(Dart_const_handle d1, Dart_const_handle d2) const 93 { return m_map.negative_turn(d1, d2); } 94 95 protected: 96 const Local_map& m_map; 97 }; 98 99 template<typename MQ> // MQ for minimal quadrangulation 100 class Path_on_surface_with_rle 101 { 102 public: 103 typedef Path_on_surface_with_rle<MQ> Self; 104 typedef typename MQ::Local_map Map; 105 typedef typename MQ::Mesh Mesh; 106 typedef typename Map::Dart_handle Dart_handle; 107 typedef typename Map::Dart_const_handle Dart_const_handle; 108 typedef CFlat<Map> Flat; 109 typedef std::list<Flat> List_of_flats; 110 typedef typename List_of_flats::iterator List_iterator; 111 // TODO typedef typename List_of_dart_length::const_iterator List_const_iterator; 112 113 friend class Path_on_surface<Map>; 114 115 struct List_iterator_hash 116 { operatorList_iterator_hash117 std::size_t operator() (const List_iterator& lit) const 118 { 119 return std::hash<const void*>()(&*lit); 120 } 121 }; 122 123 typedef std::unordered_set<List_iterator, List_iterator_hash> Set_of_it; 124 125 #ifdef CGAL_PWRLE_TURN_V2 126 typedef std::unordered_map<Dart_const_handle, std::size_t> TDartIds; 127 #endif //CGAL_PWRLE_TURN_V2 128 129 /// Constructor Path_on_surface_with_rle(const MQ & aMQ,const TDartIds & darts_ids)130 Path_on_surface_with_rle(const MQ& aMQ 131 #ifdef CGAL_PWRLE_TURN_V2 132 , const TDartIds & darts_ids 133 #endif //CGAL_PWRLE_TURN_V2 134 ) 135 : m_MQ(aMQ), 136 m_is_closed(false), 137 m_length(0), 138 m_use_only_positive(false), 139 m_use_only_negative(false) 140 #ifdef CGAL_PWRLE_TURN_V2 141 , m_darts_ids(darts_ids) 142 #endif //CGAL_PWRLE_TURN_V2 143 {} 144 145 Path_on_surface_with_rle(const Self&) = default; 146 147 /// Creates a Path_on_surface_with_rle from a Path_on_surface. 148 /// If use_only_positive, consider only positive flats and not negative ones. 149 /// If use_only_negative, consider only negative flats and not positive ones. 150 /// If both are false, consider both positive and negative flats. 151 /// Both cannot be true at the same time. 152 /// Note that for a minimal surface of genus>=2, we cannot have both -2 and 153 /// +2 as turn, and thus these parameters are useless. 154 /// However, this case can occured for our unit tests on the cube, this is 155 /// the reason of these parameters. 156 Path_on_surface_with_rle(const MQ& aMQ, const Path_on_surface<Map>& apath, 157 bool use_only_positive=false, 158 bool use_only_negative=false) m_MQ(aMQ)159 : m_MQ(aMQ), 160 m_is_closed(apath.is_closed()), 161 m_length(0), 162 m_use_only_positive(use_only_positive), 163 m_use_only_negative(use_only_negative) 164 { 165 if (apath.is_empty()) return; 166 167 std::size_t i=0, starti=0; 168 bool positive_flat=false; 169 bool negative_flat=false; 170 171 if (apath.is_closed()) 172 { 173 if (!use_only_negative && apath.prev_positive_turn(i)==2) 174 { positive_flat=true; negative_flat=false; } 175 else if (!use_only_positive && apath.prev_negative_turn(i)==2) 176 { positive_flat=false; negative_flat=true; } 177 178 while ((positive_flat && apath.prev_positive_turn(i)==2) || 179 (negative_flat && apath.prev_negative_turn(i)==2)) 180 { 181 i=apath.prev_index(i); 182 if (i==0) // Case of a closed path, made of only one flat part. 183 { 184 m_path.push_back(Flat(apath.real_front(), apath.real_back(), 185 (positive_flat?(static_cast<int>(apath.length()-1)): 186 -(static_cast<int>(apath.length()-1))))); 187 m_length=apath.length(); 188 CGAL_assertion(is_valid()); 189 return; 190 } 191 } 192 // Here i is the first dart of a flat 193 } 194 195 starti=i; 196 do 197 { 198 // Here dart i is the beginning of a flat part (maybe of length 0) 199 push_back(apath.get_ith_real_dart(i), false); 200 i=apath.next_index(i); 201 } 202 while(i<apath.length() && i!=starti); 203 204 CGAL_assertion(is_valid(true)); 205 } 206 swap(Self & p2)207 void swap(Self& p2) 208 { 209 if (this!=&p2) 210 { 211 CGAL_assertion(&get_map()==&(p2.get_map())); 212 #ifdef CGAL_PWRLE_TURN_V2 213 CGAL_assertion(&m_darts_ids==&(p2.m_darts_ids)); 214 #endif // CGAL_PWRLE_TURN_V2 215 m_path.swap(p2.m_path); 216 std::swap(m_is_closed, p2.m_is_closed); 217 std::swap(m_length, p2.m_length); 218 std::swap(m_use_only_negative, p2.m_use_only_negative); 219 std::swap(m_use_only_positive, p2.m_use_only_positive); 220 } 221 } 222 223 Self& operator=(const Self& other) 224 { 225 CGAL_assertion(&get_map()==&(other.get_map())); 226 #ifdef CGAL_PWRLE_TURN_V2 227 CGAL_assertion(&m_darts_ids==&(other.m_darts_ids)); 228 #endif // CGAL_PWRLE_TURN_V2 229 if (this!=&other) 230 { 231 m_path=other.m_path; 232 m_is_closed=other.m_is_closed; 233 m_length=other.m_length; 234 m_use_only_negative=other.m_use_only_negative; 235 m_use_only_positive=other.m_use_only_positive; 236 } 237 return *this; 238 } 239 240 Self& operator+=(Self& other) 241 { 242 // Be careful to the special case when *this==other. 243 // This is the reason of the litend computed with std::prev. 244 for (List_iterator lit=other.m_path.begin(), 245 litend=std::prev(other.m_path.end()); lit!=litend; ++lit) 246 { m_path.push_back(*lit); } 247 m_path.push_back(other.m_path.back()); // Last element 248 update_is_closed(); 249 // TODO: List of flat should be simplify when possible 250 // TODO2: what to do if different values for m_use_only_positive and m_use_only_negative ?? 251 // (probably nothing since these bools are used only for our tests) 252 return *this; 253 } 254 255 Self operator+(const Self& other) const 256 { 257 Self res=*this; 258 res+=other; 259 return res; 260 } 261 262 /// @return true if this path is equal to other path. For closed paths, test 263 /// all possible starting darts. 264 bool operator==(Self& other) 265 { 266 if (is_closed()!=other.is_closed() || 267 length()!=other.length()) 268 return false; 269 270 if (is_empty() && other.is_empty()) 271 { return true; } 272 273 // Note that we need to transform the Path_on_surface_with_rle into 274 // the correspondings Path_on_surface, because a same path can have several 275 // different rle representations. 276 Path_on_surface<Map> p1(*this); 277 Path_on_surface<Map> p2(other); 278 return p1==p2; 279 } 280 281 bool operator!=(Self& other) 282 { return !(operator==(other)); } 283 284 /// @return true iff the path is empty is_empty()285 bool is_empty() const 286 { return m_path.empty(); } 287 288 /// @return the length of the path, i.e. its number of darts length()289 std::size_t length() const 290 { return m_length; } 291 292 /// @return the number of darts in the double linked list. 293 /// note that size_of_list()<=length(). size_of_list()294 std::size_t size_of_list() const 295 { return m_path.size(); } 296 297 /// @return true iff the path is closed (update after each path modification). is_closed()298 bool is_closed() const 299 { return m_is_closed; } 300 301 /// @return the underlying map. get_map()302 const Map& get_map() const 303 { return m_MQ.get_local_map(); } 304 305 /// clear the path. clear()306 void clear() 307 { 308 m_path.clear(); 309 m_is_closed=false; 310 m_length=0; 311 } 312 313 /// @return true if the given flat is valid is_flat_valid(const List_iterator & flat)314 bool is_flat_valid(const List_iterator& flat) const 315 { 316 CGAL_assertion(is_valid_iterator(flat)); 317 Dart_const_handle dhend=flat->begin; 318 int nb=0; 319 while(nb!=flat->length) 320 { 321 if (flat->length>0) 322 { dhend=get_map().template beta<1, 2, 1>(dhend); ++nb; } 323 else 324 { dhend=get_map().template beta<2, 0, 2, 0, 2>(dhend); --nb; } 325 } 326 327 return dhend==flat->end; 328 } 329 330 /// Display the given flat display_flat(std::ostream & os,const List_iterator & flat)331 void display_flat(std::ostream& os, const List_iterator& flat) 332 { 333 CGAL_assertion(is_valid_iterator(flat)); 334 os<<"["<<get_map().darts().index(flat->begin)<<", " 335 <<get_map().darts().index(flat->end)<<" (l="<<flat->length<<")]"; 336 } 337 338 /// @return true iff the path is valid; i.e. a sequence of flats two by 339 /// two adjacent. 340 /// if test_minimal is true, test that there is no two consecutive flats 341 /// that can be merged. If test_minimal is false, this test is not done. 342 bool is_valid(bool test_minimal=true) 343 { 344 if (is_empty()) { return !is_closed(); } // an empty past is not closed 345 346 unsigned int nbdarts=0,i=0; 347 Dart_const_handle prev=(is_closed()?back():nullptr); // Last dart of the path 348 for (auto it=m_path.begin(); it!=m_path.end(); ++it) 349 { 350 if (prev!=nullptr && !get_map().template belong_to_same_cell<0> 351 (get_map().template beta<1>(prev), begin_of_flat(it))) 352 { 353 std::cerr<<"ERROR: The path is not valid: flat in position "<<i 354 <<" does not follow the previous dart."<<std::endl; 355 return false; 356 } 357 358 if (!is_flat_valid(it)) 359 { 360 display(); 361 std::cout<<"ERROR: The path is not valid: flat at position "<<i 362 <<" with length "<<flat_length(it) 363 <<" is not correct: its end does not" 364 <<" correspond to the flat."<<std::endl; 365 return false; 366 } 367 368 if (test_minimal && can_merge_with_next_flat(it)) 369 { 370 std::cout<<"ERROR: The path is not valid: flat at position "<<i 371 <<" with length "<<flat_length(it)<<" is not correct: it can be merged " 372 <<"with the next flat with length " 373 <<flat_length(next_iterator(it))<<" - turns between the two flats = +" 374 <<next_positive_turn(it)<<" -"<<next_negative_turn(it)<<std::endl; 375 return false; 376 } 377 prev=end_of_flat(it); // end of the previous flat 378 nbdarts+=std::abs(flat_length(it))+1; // Number of darts of the flat 379 ++i; 380 } 381 382 if (is_closed()) 383 { 384 if (prev==nullptr) 385 { 386 std::cout<<"ERROR: The path is not valid: it is empty and closed." 387 <<std::endl; 388 return false; 389 } 390 if (!get_map().template belong_to_same_cell<0> 391 (get_map().template beta<1>(prev), begin_of_flat(m_path.begin()))) 392 { 393 std::cerr<<"ERROR: The path is not valid: first flat " 394 <<" does not follow the last dart for a closed path."<<std::endl; 395 return false; 396 } 397 } 398 399 if (length()!=nbdarts) 400 { 401 std::cerr<<"ERROR: The path is not valid: store length=="<<length() 402 <<" different of real length=="<<nbdarts<<std::endl; 403 return false; 404 } 405 406 return true; 407 } 408 409 /// For debugging purpose, test if 'it' is a valid iterator. is_valid_iterator(const List_iterator & ittotest)410 bool is_valid_iterator(const List_iterator& ittotest) const 411 { 412 if (ittotest==m_path.end()) { return false; } 413 return true; 414 // Assert too long; uncomment in case of bug. 415 /* for (auto it=m_path.begin(); it!=m_path.end(); ++it) 416 { 417 if (it==ittotest) { return true; } 418 } 419 return false; */ 420 } 421 422 /// @return the first dart of the path 423 /// @pre !is_empty() front()424 Dart_const_handle front() 425 { 426 CGAL_assertion(!is_empty()); 427 return begin_of_flat(m_path.begin()); 428 } 429 430 /// @return the last dart of the path 431 /// @pre !is_empty() back()432 Dart_const_handle back() 433 { 434 CGAL_assertion(!is_empty()); 435 return end_of_flat(std::prev(m_path.end())); 436 } 437 438 /// @return true iff df can be added at the end of the path. can_be_pushed(Dart_const_handle dh)439 bool can_be_pushed(Dart_const_handle dh) 440 { 441 // This assert is too long 442 // CGAL_assertion(get_map().darts().owns(dh)); 443 if (is_empty()) return true; 444 445 return get_map().template belong_to_same_cell<0> 446 (get_map().template beta<1>(back()), dh); 447 } 448 449 /// Add the given dart at the end of this path. 450 /// @pre can_be_pushed(dh) 451 void push_back(Dart_const_handle dh, bool update_isclosed=true) 452 { 453 CGAL_assertion(dh!=Map::null_handle); 454 // This assert is too long, it is tested in the is_valid method. 455 // CGAL_assertion(can_be_pushed(dh)); 456 457 List_iterator itlast=m_path.end(); 458 459 bool positive_flat, negative_flat; 460 if (is_empty() || 461 !is_prev_flat_can_be_extended_at_end(itlast, dh, 462 positive_flat, negative_flat)) 463 { m_path.push_back(Flat(dh)); } // Create a new flat 464 else 465 { 466 itlast=std::prev(itlast); 467 set_end_of_flat(itlast, dh); // Move the last dart of the last flat 468 if (positive_flat && flat_length(itlast)>=0) 469 { 470 set_flat_length(itlast, flat_length(itlast)+1); // Increment the length of the flat 471 } 472 else 473 { 474 CGAL_assertion(negative_flat && flat_length(itlast)<=0); 475 set_flat_length(itlast, flat_length(itlast)-1); // Increment the length of the flat 476 } 477 } 478 479 ++m_length; 480 if (update_isclosed) { update_is_closed(); } 481 } 482 483 // Update m_is_closed to true iff the path is closed (i.e. the second 484 // extremity of the last dart of the path is the same vertex than the one 485 // of the first dart of the path). update_is_closed()486 void update_is_closed() 487 { 488 if (is_empty()) { m_is_closed=false; } 489 else 490 { 491 Dart_const_handle pend=get_map().other_extremity(back()); 492 if (pend==Map::null_handle) { m_is_closed=false; } 493 else 494 { m_is_closed=get_map().template belong_to_same_cell<0>(front(), pend); } 495 } 496 } 497 498 /// @return true iff there is a flat after it next_flat_exist(const List_iterator & it)499 bool next_flat_exist(const List_iterator& it) const 500 { 501 CGAL_assertion(it!=m_path.end()); 502 return !is_empty() && (is_closed() || std::next(it)!=m_path.end()); 503 } 504 505 /// @return true iff there is a flat before it prev_flat_exist(const List_iterator & it)506 bool prev_flat_exist(const List_iterator& it) const 507 { 508 return !is_empty() && (is_closed() || it!=m_path.begin()); 509 } 510 advance_iterator(List_iterator & it)511 void advance_iterator(List_iterator& it) 512 { 513 CGAL_assertion(it!=m_path.end()); 514 it=std::next(it); 515 if (it==m_path.end()) 516 { 517 if (is_closed()) 518 { it=m_path.begin(); } // Here the path is closed, and it is the last element of the list 519 } 520 } 521 retreat_iterator(List_iterator & it)522 void retreat_iterator(List_iterator& it) 523 { 524 if (it==m_path.begin()) 525 { 526 if (is_closed()) 527 { it=m_path.end(); } 528 else { return; } 529 } 530 it=std::prev(it); 531 } 532 next_iterator(const List_iterator & it)533 List_iterator next_iterator(const List_iterator& it) 534 { 535 List_iterator res=it; 536 advance_iterator(res); 537 return res; 538 } 539 prev_iterator(const List_iterator & it)540 List_iterator prev_iterator(const List_iterator& it) 541 { 542 List_iterator res=it; 543 retreat_iterator(res); 544 return res; 545 } 546 547 /// @return the beginning of the flat begin_of_flat(const List_iterator & it)548 Dart_const_handle begin_of_flat(const List_iterator& it) 549 { 550 CGAL_assertion(is_valid_iterator(it)); 551 return it->begin; 552 } 553 554 /// @return the end of the flat end_of_flat(const List_iterator & it)555 Dart_const_handle end_of_flat(const List_iterator& it) 556 { 557 CGAL_assertion(is_valid_iterator(it)); 558 return it->end; 559 } 560 561 /// @return the length of the flat flat_length(const List_iterator & it)562 int flat_length(const List_iterator& it) 563 { 564 CGAL_assertion(is_valid_iterator(it)); 565 return it->length; 566 } 567 set_flat_length(const List_iterator & it,int i)568 void set_flat_length(const List_iterator& it, int i) 569 { 570 CGAL_assertion(is_valid_iterator(it)); 571 it->length=i; 572 } 573 decrease_flat_length(const List_iterator & it)574 void decrease_flat_length(const List_iterator& it) 575 { 576 CGAL_assertion(is_valid_iterator(it)); 577 CGAL_assertion(flat_length(it)!=0); 578 if (flat_length(it)>0) { --(it->length); } 579 else { ++(it->length); } 580 } 581 increase_flat_length(const List_iterator & it)582 void increase_flat_length(const List_iterator& it) 583 { 584 CGAL_assertion(is_valid_iterator(it)); 585 if (flat_length(it)>=0) { ++(it->length); } 586 else { --(it->length); } 587 } 588 set_begin_of_flat(const List_iterator & it,Dart_const_handle dh)589 void set_begin_of_flat(const List_iterator& it, Dart_const_handle dh) 590 { 591 CGAL_assertion(is_valid_iterator(it)); 592 it->begin=dh; 593 } 594 set_end_of_flat(const List_iterator & it,Dart_const_handle dh)595 void set_end_of_flat(const List_iterator& it, Dart_const_handle dh) 596 { 597 CGAL_assertion(is_valid_iterator(it)); 598 it->end=dh; 599 } 600 601 /// @return the second dart of the given flat. second_dart_of_a_flat(const List_iterator & it)602 Dart_const_handle second_dart_of_a_flat(const List_iterator& it) 603 { 604 if (flat_length(it)>0) 605 { return get_map().template beta<1, 2, 1>(begin_of_flat(it)); } 606 607 CGAL_assertion(flat_length(it)<0); 608 return get_map().template beta<2, 0, 2, 0, 2>(begin_of_flat(it)); 609 } 610 611 /// @return the dart before the last dart of the given flat. before_last_dart_of_a_flat(const List_iterator & it)612 Dart_const_handle before_last_dart_of_a_flat(const List_iterator& it) 613 { 614 if (flat_length(it)>0) 615 { return get_map().template beta<0, 2, 0>(end_of_flat(it)); } 616 617 CGAL_assertion(flat_length(it)<0); 618 return get_map().template beta<2, 1, 2, 1, 2>(end_of_flat(it)); 619 } 620 621 /// @return the turn between dart it and next dart. 622 /// (turn is position of the second edge in the cyclic ordering of 623 /// edges starting from the first edge around the second extremity 624 /// of the first dart) next_positive_turn(const List_iterator & it)625 std::size_t next_positive_turn(const List_iterator& it) 626 { 627 CGAL_assertion(next_flat_exist(it)); 628 return m_MQ.positive_turn(end_of_flat(it), begin_of_flat(next_iterator(it))); 629 } 630 631 /// Same than next_positive_turn but turning in reverse orientation around vertex. next_negative_turn(const List_iterator & it)632 std::size_t next_negative_turn(const List_iterator& it) 633 { 634 CGAL_assertion(next_flat_exist(it)); 635 return m_MQ.negative_turn(end_of_flat(it), begin_of_flat(next_iterator(it))); 636 } 637 compute_positive_turns()638 std::vector<std::size_t> compute_positive_turns() 639 { 640 std::vector<std::size_t> res; 641 if (is_empty()) return res; 642 for (auto it=m_path.begin(), itend=m_path.end(); it!=itend; ++it) 643 { 644 if (next_flat_exist(it)) 645 { res.push_back(next_positive_turn(it)); } 646 } 647 return res; 648 } 649 compute_negative_turns()650 std::vector<std::size_t> compute_negative_turns() 651 { 652 std::vector<std::size_t> res; 653 if (is_empty()) return res; 654 for (auto it=m_path.begin(), itend=m_path.end(); it!=itend; ++it) 655 { 656 if (next_flat_exist(it)) 657 { res.push_back(next_negative_turn(it)); } 658 } 659 return res; 660 } 661 compute_turns(bool positive)662 std::vector<std::size_t> compute_turns(bool positive) 663 { return (positive?compute_positive_turns():compute_negative_turns()); } 664 flat_modified(const List_iterator & it,Set_of_it & modified_flats)665 void flat_modified(const List_iterator& it, 666 Set_of_it& modified_flats) 667 { 668 modified_flats.insert(it); 669 if (prev_flat_exist(it)) 670 { modified_flats.insert(prev_iterator(it)); } 671 if (next_flat_exist(it)) 672 { modified_flats.insert(next_iterator(it)); } 673 } 674 erase_flat(List_iterator & it,Set_of_it & modified_flats)675 void erase_flat(List_iterator& it, Set_of_it& modified_flats) 676 { 677 if (next_flat_exist(it)) 678 { modified_flats.insert(next_iterator(it)); } 679 if (prev_flat_exist(it)) 680 { modified_flats.insert(prev_iterator(it)); } 681 682 modified_flats.erase(it); 683 684 it=m_path.erase(it); // after the erase, it is the element after the erased one 685 if (prev_flat_exist(it)) 686 { 687 retreat_iterator(it); // this is why we move it backward here 688 } 689 } 690 merge_modified_flats_when_possible(Set_of_it & modified_flats)691 List_iterator merge_modified_flats_when_possible(Set_of_it& modified_flats) 692 { 693 if (m_path.empty()) 694 { 695 m_is_closed=false; 696 return m_path.end(); 697 } 698 699 List_iterator smallest_it=m_path.end(); 700 for (auto it=modified_flats.begin(), itend=modified_flats.end(); 701 it!=itend; ++it) 702 { 703 if (prev_flat_exist(*it) && modified_flats.count(prev_iterator(*it))==0) 704 { smallest_it=*it; } 705 } 706 707 List_iterator itcur; 708 if (smallest_it==m_path.end()) 709 { // Case of a closed path, with all paths modified 710 for (auto it=modified_flats.begin(); it!=modified_flats.end(); ++it) 711 { 712 itcur=*it; 713 while(merge_with_next_flat_if_possible(itcur, modified_flats)) 714 {} 715 } 716 return m_path.begin(); 717 } 718 719 for (auto it=modified_flats.begin(); it!=modified_flats.end(); ++it) 720 { 721 itcur=*it; 722 while(merge_with_next_flat_if_possible(itcur, modified_flats)) 723 {} 724 } 725 726 // Note that smallest is not necessarily the smallest, this is a flat 727 // such that the previous flat is not modified. 728 return smallest_it; 729 } 730 731 /// Reduce the length of the flat part starting at 'it' from its beginning 732 /// 'it' moves to the previous flat if the current flat disapeared. 733 /// The path could be not valid after this operation (consistency with next 734 /// element should be ensure, by possibly updating the next flat part). 735 /// @return true iff the flat disapeared after its reduction. reduce_flat_from_beginning(List_iterator & it,Set_of_it & modified_flats)736 bool reduce_flat_from_beginning(List_iterator& it, 737 Set_of_it& modified_flats) 738 { 739 CGAL_assertion(is_valid_iterator(it)); 740 741 CGAL_assertion(m_length>0); 742 --m_length; 743 744 flat_modified(it, modified_flats); 745 746 if (flat_length(it)==0) 747 { 748 erase_flat(it, modified_flats); 749 return true; 750 } 751 752 set_begin_of_flat(it, second_dart_of_a_flat(it)); 753 decrease_flat_length(it); 754 return false; 755 } 756 757 /// Reduce the length of the flat part starting at 'it' from its end. 758 /// 'it' moves to the previous flat if the current flat disapeared. 759 /// The path could be not valid after this operation (consistency with next 760 /// element should be ensure, by possibly updating the next flat part). 761 /// @return true iff the flat disapeared after its reduction. reduce_flat_from_end(List_iterator & it,Set_of_it & modified_flats)762 bool reduce_flat_from_end(List_iterator& it, 763 Set_of_it& modified_flats) 764 { 765 CGAL_assertion(is_valid_iterator(it)); 766 767 CGAL_assertion(m_length>0); 768 --m_length; 769 770 flat_modified(it, modified_flats); 771 772 if (flat_length(it)==0) 773 { 774 erase_flat(it, modified_flats); 775 return true; 776 } 777 778 set_end_of_flat(it, before_last_dart_of_a_flat(it)); 779 decrease_flat_length(it); 780 return false; 781 } 782 783 /// @return true iff the flat 'it' can be merged with its next flat. can_merge_with_next_flat(const List_iterator & it,bool & positive2,bool & negative2)784 bool can_merge_with_next_flat(const List_iterator& it, 785 bool& positive2, bool& negative2) 786 { 787 if (m_path.size()<=1) { return false; } 788 if (!next_flat_exist(it)) { return false; } 789 790 List_iterator it2=next_iterator(it); 791 CGAL_assertion(m_path.size()>1 || it==it2); 792 if (it==it2) { return false; } // only one flat in the path 793 794 positive2=(!m_use_only_negative && (next_positive_turn(it)==2)); 795 negative2=(!m_use_only_positive && (next_negative_turn(it)==2)); 796 CGAL_assertion(!(positive2 && negative2)); 797 798 if (!positive2 && !negative2) { return false; } // the middle turn is not a flat 799 800 bool positive1=(flat_length(it)>=0); 801 bool negative1=(flat_length(it)<=0); 802 bool positive3=(flat_length(it2)>=0); 803 bool negative3=(flat_length(it2)<=0); 804 805 return ((positive1 && positive2 && positive3) || 806 (negative1 && negative2 && negative3)); 807 } 808 809 /// @return true iff the flat 'it' can be merged with its next flat. can_merge_with_next_flat(const List_iterator & it)810 bool can_merge_with_next_flat(const List_iterator& it) 811 { 812 bool dummy1, dummy2; 813 return can_merge_with_next_flat(it, dummy1, dummy2); 814 } 815 816 /// Merge flat 'it' with its next flat if it is possible. 817 /// @return true if a merging was done. merge_with_next_flat_if_possible(const List_iterator & it,Set_of_it & modified_flats)818 bool merge_with_next_flat_if_possible(const List_iterator& it, 819 Set_of_it& modified_flats) 820 { 821 bool positive2=false, negative2=false; 822 if (!can_merge_with_next_flat(it, positive2, negative2)) 823 { return false; } 824 825 #ifdef CGAL_TRACE_PATH_TESTS 826 std::cout<<"Merge with next flat: "; 827 display_flat(std::cout, it); std::cout<<" and "; 828 display_flat(std::cout, next_iterator(it)); std::cout<<std::endl; 829 #endif 830 831 List_iterator it2=next_iterator(it); 832 set_flat_length(it, flat_length(it)+flat_length(it2)+ 833 (positive2?1:-1)); 834 set_end_of_flat(it, end_of_flat(it2)); 835 836 if (modified_flats.count(it2)==1) 837 modified_flats.erase(it2); 838 839 m_path.erase(it2); 840 841 // CGAL_assertion(is_flat_valid(it)); 842 return true; 843 } 844 845 /// Merge flat 'it' with its next flat if it is possible. 846 /// @return true if a merging was done. merge_with_next_flat_if_possible(const List_iterator & it)847 bool merge_with_next_flat_if_possible(const List_iterator& it) 848 { 849 Set_of_it dummy; 850 return merge_with_next_flat_if_possible(it, dummy); 851 } 852 853 /// Merge the last flat of this path with its next flat if it is possible. 854 /// @return true if a merging was done. merge_last_flat_with_next_if_possible()855 bool merge_last_flat_with_next_if_possible() 856 { 857 List_iterator lastit=std::prev(m_path.end()); 858 return merge_with_next_flat_if_possible(lastit); 859 } 860 861 /// Return true if it is the beginning of a spur. is_spur(const List_iterator & it)862 bool is_spur(const List_iterator& it) 863 { 864 CGAL_assertion(is_valid_iterator(it)); 865 return next_flat_exist(it) && 866 get_map().template beta<2>(end_of_flat(it))== 867 begin_of_flat(next_iterator(it)); 868 } 869 870 /// Remove the spur given by 'it'. 871 /// After the operation, either 'it' stay on the same element (if the flat 872 /// still exist), or 'it' move to the previous element if the flat containing 873 /// the spur is removed. 874 /// ('it' will be equal to m_path.end() if the path becomes empty). remove_spur(List_iterator & it)875 void remove_spur(List_iterator& it) 876 { 877 #ifdef CGAL_TRACE_PATH_TESTS 878 std::cout<<"Remove spur between flats: "; 879 display_flat(std::cout, it); std::cout<<" and "; 880 display_flat(std::cout, next_iterator(it)); std::cout<<std::endl; 881 #endif 882 883 CGAL_assertion(is_spur(it)); 884 Set_of_it modified_flats; 885 List_iterator it2=next_iterator(it); // it2 is the next flat 886 887 // We reduce the first flat 888 reduce_flat_from_end(it, modified_flats); // If flat 'it' is erased, it is moved to the previous flat 889 890 // We reduce the second flat 891 reduce_flat_from_beginning(it2, modified_flats); 892 893 // We merge adjacent flats if possible 894 it=merge_modified_flats_when_possible(modified_flats); 895 896 // CGAL_assertion(is_valid_iterator(it)); 897 // CGAL_assertion(is_valid()); 898 } 899 900 /// Move 'it' to the next spur after it. Go to m_path.end() if there is no 901 /// spur in the path. move_to_next_spur(List_iterator & it)902 void move_to_next_spur(List_iterator& it) 903 { 904 CGAL_assertion(is_valid_iterator(it)); 905 List_iterator itend=(is_closed()?it:m_path.end()); 906 do 907 { 908 advance_iterator(it); 909 if (it!=m_path.end() && is_spur(it)) { return; } 910 } 911 while(it!=itend); 912 it=m_path.end(); // Here there is no spur in the whole path 913 } 914 915 /// Simplify the path by removing all spurs, if all==true; otherwise 916 /// remove only one spur. 917 /// @return true iff at least one spur was removed 918 bool remove_spurs(bool all=true) 919 { 920 bool res=false; 921 List_iterator it=m_path.begin(); 922 while(it!=m_path.end()) 923 { 924 if (is_spur(it)) 925 { 926 remove_spur(it); res=true; 927 // CGAL_assertion(is_valid_iterator(it)); 928 // CGAL_assertion(is_valid()); 929 if (!all) { return true; } 930 } 931 else { move_to_next_spur(it); } 932 } 933 // CGAL_assertion(is_valid()); 934 return res; 935 } 936 937 /// Return true if 'it' is the beginning of a positive bracket. 938 /// If true, 'itend' is updated to be the end of the bracket is_positive_bracket(const List_iterator & it,List_iterator & itend)939 bool is_positive_bracket(const List_iterator& it, 940 List_iterator& itend) 941 { 942 CGAL_assertion(is_valid_iterator(it)); 943 if (m_use_only_negative || !next_flat_exist(it) || 944 next_positive_turn(it)!=1) 945 { return false; } 946 // Here first positive turn is 1 947 948 itend=next_iterator(it); 949 // Here itend is the beginning of the second flat 950 if (flat_length(itend)<0) 951 { return false; } // This is not a positive bracket, we have some -2 952 953 if (!next_flat_exist(itend) || next_positive_turn(itend)!=1) 954 { return false; } 955 956 // Now we move itend to the beginning of the third flat. 957 advance_iterator(itend); 958 return true; 959 } 960 961 /// Return true if it is the beginning of a negative bracket. 962 /// If true, itend is updated to be the end of the bracket is_negative_bracket(const List_iterator & it,List_iterator & itend)963 bool is_negative_bracket(const List_iterator& it, 964 List_iterator& itend) 965 { 966 CGAL_assertion(is_valid_iterator(it)); 967 if (m_use_only_positive || !next_flat_exist(it) || 968 next_negative_turn(it)!=1) 969 { return false; } 970 // Here first negative turn is 1 971 972 itend=next_iterator(it); 973 // Here itend is the beginning of the second flat 974 if (flat_length(itend)>0) 975 { return false; } // This is not a negative bracket, we have some +2 976 977 if (!next_flat_exist(itend) || next_negative_turn(itend)!=1) 978 { return false; } 979 980 // Now we move itend to the beginning of the third flat. 981 advance_iterator(itend); 982 return true; 983 } 984 985 /// Move 'it' to the next bracket after 'it'. Go to m_path.end() if there 986 /// is no bracket in the path. move_to_next_bracket(List_iterator & it)987 void move_to_next_bracket(List_iterator& it) 988 { 989 CGAL_assertion(is_valid_iterator(it)); 990 List_iterator itend=(is_closed()?it:m_path.end()); 991 List_iterator it2; 992 do 993 { 994 advance_iterator(it); 995 if (it!=m_path.end() && 996 (is_positive_bracket(it, it2) || is_negative_bracket(it, it2))) 997 { return; } 998 } 999 while(it!=itend); 1000 it=m_path.end(); // Here there is no bracket in the whole path 1001 } 1002 1003 /// Remove the given negative bracket. it1 is the flat beginning 1004 /// of the bracket; it3 is the flat end of the bracket. remove_negative_bracket(List_iterator & it1,List_iterator & it3)1005 void remove_negative_bracket(List_iterator& it1, List_iterator& it3) 1006 { 1007 #ifdef CGAL_TRACE_PATH_TESTS 1008 std::cout<<"Remove negative bracket: "; 1009 display_flat(std::cout, it1); std::cout<<", "; 1010 display_flat(std::cout, next_iterator(it1)); std::cout<<" and "; 1011 display_flat(std::cout, it3); std::cout<<std::endl; 1012 #endif 1013 1014 Set_of_it modified_flats; 1015 List_iterator it2; 1016 CGAL_assertion(is_negative_bracket(it1, it2)); // Here it2 is unused 1017 1018 if (size_of_list()==1) // it1==it3 1019 { // Case of cyclic bracket 1020 CGAL_assertion(size_of_list()==1); 1021 CGAL_assertion(flat_length(it1)<0); 1022 set_begin_of_flat(it1, get_map().template beta<2,0,2,1>(begin_of_flat(it1))); 1023 set_end_of_flat(it1, get_map().template beta<2,1,2,0>(end_of_flat(it1))); 1024 set_flat_length(it1, (-flat_length(it1))-2); 1025 flat_modified(it1, modified_flats); 1026 it1=merge_modified_flats_when_possible(modified_flats); 1027 CGAL_assertion(m_length>1); 1028 m_length-=2; 1029 return; 1030 } 1031 1032 it2=next_iterator(it1); // it2 is the next flat after it1 1033 1034 reduce_flat_from_end(it1, modified_flats); // decrease also m_length 1035 reduce_flat_from_beginning(it3, modified_flats); 1036 1037 it1=it2; // Beginning of the second flat, we are sure it still exists 1038 1039 set_begin_of_flat(it2, get_map().template beta<2,1,1>(begin_of_flat(it2))); 1040 set_end_of_flat(it2, get_map().template beta<2,1,1>(end_of_flat(it2))); 1041 set_flat_length(it2, -flat_length(it2)); 1042 1043 flat_modified(it2, modified_flats); 1044 1045 it1=merge_modified_flats_when_possible(modified_flats); 1046 1047 // CGAL_assertion(is_valid()); 1048 } 1049 1050 /// Remove the given positive bracket. 'it1' is the flat beginning 1051 /// of the bracket; 'it3' is the flat end of the bracket. remove_positive_bracket(List_iterator & it1,List_iterator & it3)1052 void remove_positive_bracket(List_iterator& it1, 1053 List_iterator& it3) 1054 { 1055 #ifdef CGAL_TRACE_PATH_TESTS 1056 std::cout<<"Remove positive bracket: "; 1057 display_flat(std::cout, it1); std::cout<<", "; 1058 display_flat(std::cout, next_iterator(it1)); std::cout<<" and "; 1059 display_flat(std::cout, it3); std::cout<<std::endl; 1060 #endif 1061 1062 Set_of_it modified_flats; 1063 List_iterator it2; 1064 CGAL_assertion(is_positive_bracket(it1, it2)); // Here it2 is unused 1065 1066 if (size_of_list()==1) // it1==it3 1067 { // Case of cyclic bracket 1068 CGAL_assertion(size_of_list()==1); 1069 CGAL_assertion(flat_length(it1)>0); 1070 set_begin_of_flat(it1, get_map().template beta<1,2,0,2>(begin_of_flat(it1))); 1071 set_end_of_flat(it1, get_map().template beta<0,2,1,2>(end_of_flat(it1))); 1072 set_flat_length(it1, -(flat_length(it1)-2)); 1073 flat_modified(it1, modified_flats); 1074 it1=merge_modified_flats_when_possible(modified_flats); 1075 CGAL_assertion(m_length>1); 1076 m_length-=2; 1077 return; 1078 } 1079 1080 it2=next_iterator(it1); // it2 is the next flat after it1 1081 1082 reduce_flat_from_end(it1, modified_flats); // decrease also m_length 1083 reduce_flat_from_beginning(it3, modified_flats); 1084 1085 it1=it2; // Beginning of the second flat, we are sure it exists 1086 1087 set_begin_of_flat(it2, get_map().template beta<1,1,2>(begin_of_flat(it2))); 1088 set_end_of_flat(it2, get_map().template beta<1,1,2>(end_of_flat(it2))); 1089 set_flat_length(it2, -flat_length(it2)); 1090 1091 flat_modified(it2, modified_flats); 1092 1093 it1=merge_modified_flats_when_possible(modified_flats); 1094 1095 // CGAL_assertion(is_valid()); 1096 } 1097 1098 /// Simplify the path by removing all brackets, if all==true (default), 1099 /// or by removing only one bracket, if all==false. 1100 /// @return true iff at least one bracket was removed 1101 bool remove_brackets(bool all=true) 1102 { 1103 // CGAL_assertion(is_valid()); 1104 bool res=false; 1105 List_iterator it1=m_path.begin(); 1106 List_iterator it2; 1107 while(it1!=m_path.end()) 1108 { 1109 // CGAL_assertion(is_valid()); 1110 if (is_positive_bracket(it1, it2)) 1111 { 1112 remove_positive_bracket(it1, it2); res=true; 1113 // CGAL_assertion(is_valid_iterator(it1)); 1114 // CGAL_assertion(is_valid()); 1115 } 1116 else if (is_negative_bracket(it1, it2)) 1117 { 1118 remove_negative_bracket(it1, it2); res=true; 1119 // CGAL_assertion(is_valid_iterator(it1)); 1120 // CGAL_assertion(is_valid()); 1121 } 1122 else { move_to_next_bracket(it1); } 1123 if (!all && res) { return true; } 1124 } 1125 // CGAL_assertion(is_valid()); 1126 return res; 1127 } 1128 1129 /// @return true iff 'it' is the beginning of a l-shape. is_l_shape(const List_iterator & it)1130 bool is_l_shape(const List_iterator& it) 1131 { 1132 CGAL_assertion(is_valid_iterator(it)); 1133 if (!next_flat_exist(it)) { return false; } 1134 std::size_t t=next_negative_turn(it); 1135 return (t==1 || 1136 (flat_length(it)<0 && size_of_list()==1 && t==2)); 1137 } 1138 1139 /// Move it to the next l_shape after it. Go to m_path.end() if there is no 1140 /// l_shape in the path. move_to_next_l_shape(List_iterator & it)1141 void move_to_next_l_shape(List_iterator& it) 1142 { 1143 // CGAL_assertion(is_valid()); 1144 CGAL_assertion(is_valid_iterator(it)); 1145 List_iterator itend=(is_closed()?it:m_path.end()); 1146 do 1147 { 1148 advance_iterator(it); 1149 if (it!=m_path.end() && is_l_shape(it)) { return; } 1150 } 1151 while(it!=itend); 1152 it=m_path.end(); // Here there is no spur in the whole path 1153 } 1154 1155 /// @return true iff the flat before flat 'it' can be extended by adding 1156 /// dart 'dh' to its end. is_prev_flat_can_be_extended_at_end(const List_iterator & it,Dart_const_handle dh,bool & positive_flat,bool & negative_flat)1157 bool is_prev_flat_can_be_extended_at_end(const List_iterator& it, 1158 Dart_const_handle dh, 1159 bool& positive_flat, 1160 bool& negative_flat) 1161 { 1162 positive_flat=false; negative_flat=false; 1163 if (!prev_flat_exist(it)) { return false; } 1164 List_iterator ittemp=prev_iterator(it); 1165 if (!m_use_only_negative && m_MQ.positive_turn(end_of_flat(ittemp), dh)==2) 1166 { positive_flat=true; } 1167 if (!m_use_only_positive && m_MQ.negative_turn(end_of_flat(ittemp), dh)==2) 1168 { negative_flat=true; } 1169 1170 if (flat_length(ittemp)==0) // Case of flat lengh 0 1171 { return positive_flat || negative_flat; } 1172 1173 return (flat_length(ittemp)>0 && positive_flat) || 1174 (flat_length(ittemp)<0 && negative_flat); 1175 } 1176 1177 /// @return true iff the flat before flat 'it' can be extended by adding 1178 /// dart 'dh' to its end. is_prev_flat_can_be_extended_at_end(const List_iterator & it,Dart_const_handle dh)1179 bool is_prev_flat_can_be_extended_at_end(const List_iterator& it, 1180 Dart_const_handle dh) 1181 { 1182 bool dummy1, dummy2; 1183 return is_prev_flat_can_be_extended_at_end(it, dh, dummy1, dummy2); 1184 } 1185 1186 /// @return true iff the flat after flat 'it' can be extended by adding 1187 /// dart 'dh' to its beginning. is_next_flat_can_be_extended_at_beginning(const List_iterator & it,Dart_const_handle dh,bool & positive_flat,bool & negative_flat)1188 bool is_next_flat_can_be_extended_at_beginning(const List_iterator& it, 1189 Dart_const_handle dh, 1190 bool& positive_flat, 1191 bool& negative_flat) 1192 { 1193 CGAL_assertion(is_valid_iterator(it)); 1194 1195 positive_flat=false; negative_flat=false; 1196 if (!next_flat_exist(it)) { return false; } 1197 List_iterator ittemp=next_iterator(it); 1198 if (!m_use_only_negative && m_MQ.positive_turn(dh, begin_of_flat(ittemp))==2) 1199 { positive_flat=true; } 1200 if (!m_use_only_positive && m_MQ.negative_turn(dh, begin_of_flat(ittemp))==2) 1201 { negative_flat=true; } 1202 1203 if (flat_length(ittemp)==0) // Case of flat lengh 0 1204 { return positive_flat || negative_flat; } 1205 1206 return (flat_length(ittemp)>0 && positive_flat) || 1207 (flat_length(ittemp)<0 && negative_flat); 1208 } 1209 1210 /// @return true iff the flat after flat 'it' can be extended by adding 1211 /// dart 'dh' to its beginning. is_next_flat_can_be_extended_at_beginning(const List_iterator & it,Dart_const_handle dh)1212 bool is_next_flat_can_be_extended_at_beginning(const List_iterator& it, 1213 Dart_const_handle dh) 1214 { 1215 bool dummy1, dummy2; 1216 return is_next_flat_can_be_extended_at_beginning(it, dh, dummy1, dummy2); 1217 } 1218 1219 /// @return true iff the flat 'it' forms a switchable subpath (aka left-L-shape) is_switchable(const List_iterator & it)1220 bool is_switchable(const List_iterator& it) 1221 { 1222 CGAL_assertion(is_valid_iterator(it)); 1223 if (it == m_path.begin() || std::next(it) == m_path.end()) { return false; } 1224 std::size_t t=next_positive_turn(it); 1225 return (t==1 && flat_length(it) >= 0); 1226 } 1227 1228 /// Add the given dart 'dh' before the flat 'it'. add_dart_before(const List_iterator & it,Dart_const_handle dh,Set_of_it & modified_flats)1229 void add_dart_before(const List_iterator& it, Dart_const_handle dh, 1230 Set_of_it& modified_flats) 1231 { 1232 CGAL_assertion(is_valid_iterator(it)); 1233 1234 bool positive_flat, negative_flat; 1235 if (is_prev_flat_can_be_extended_at_end(it, dh, 1236 positive_flat, negative_flat)) 1237 { 1238 List_iterator ittemp=prev_iterator(it); 1239 set_end_of_flat(ittemp, dh); // Move the last dart of the previous flat 1240 set_flat_length(ittemp, flat_length(ittemp)+(positive_flat?+1:-1)); // Increment the length of the flat 1241 flat_modified(ittemp, modified_flats); 1242 } 1243 else 1244 { 1245 // insert the new element before 'it' 1246 flat_modified(m_path.insert(it, Flat(dh)), modified_flats); 1247 } 1248 ++m_length; 1249 } 1250 1251 /// Add the given dart 'dh' after the flat 'it'. add_dart_after(const List_iterator & it,Dart_const_handle dh,Set_of_it & modified_flats)1252 void add_dart_after(const List_iterator& it, Dart_const_handle dh, 1253 Set_of_it& modified_flats) 1254 { 1255 CGAL_assertion(is_valid_iterator(it)); 1256 bool positive_flat, negative_flat; 1257 List_iterator ittemp=next_iterator(it); 1258 if (is_next_flat_can_be_extended_at_beginning(it, dh, 1259 positive_flat, negative_flat)) 1260 { 1261 set_begin_of_flat(ittemp, dh); // Move the first dart of the flat 1262 set_flat_length(ittemp, flat_length(ittemp)+(positive_flat?+1:-1)); // Increment the length of the flat 1263 flat_modified(ittemp, modified_flats); 1264 } 1265 else 1266 { 1267 // insert the new element before 'ittemp', thus after 'it' 1268 flat_modified(m_path.insert(ittemp, Flat(dh)), modified_flats); 1269 } 1270 ++m_length; 1271 } 1272 1273 /// Right push the given l-shape. right_push_l_shape(List_iterator & it1)1274 void right_push_l_shape(List_iterator& it1) 1275 { 1276 #ifdef CGAL_TRACE_PATH_TESTS 1277 std::cout<<"Right push l-shape: "; 1278 display_flat(std::cout, it1); std::cout<<" and "; 1279 display_flat(std::cout, next_iterator(it1)); std::cout<<std::endl; 1280 #endif 1281 1282 // it is the beginning of a flat 1283 CGAL_assertion(is_l_shape(it1)); 1284 // CGAL_assertion(is_valid()); 1285 Set_of_it modified_flats; 1286 1287 if (m_path.size()==1) 1288 { 1289 if (next_negative_turn(it1)==2) 1290 { // Special case of a global shift 1291 set_flat_length(it1, -flat_length(it1)); 1292 set_begin_of_flat(it1, get_map().template beta<2,1,1>(begin_of_flat(it1))); 1293 set_end_of_flat(it1, get_map().template beta<2,1,1>(end_of_flat(it1))); 1294 // CGAL_assertion(is_valid()); 1295 return; 1296 } 1297 else // Here negative turn is 1 1298 { 1299 if (flat_length(it1)>0) // Case where the first flat is positive 1300 { // We split the flat in two parts 1301 CGAL_assertion(flat_length(it1)>=1); 1302 Dart_const_handle dh1=begin_of_flat(it1); 1303 Dart_const_handle dh2=end_of_flat(it1); 1304 if (flat_length(it1)==1) // only one flat with two darts 1305 { 1306 reduce_flat_from_end(it1, modified_flats); 1307 it1=m_path.insert(it1, Flat(dh2)); // insert dh1 before it1 1308 flat_modified(it1, modified_flats); 1309 ++m_length; 1310 } 1311 else 1312 { 1313 reduce_flat_from_beginning(it1, modified_flats); 1314 reduce_flat_from_end(it1, modified_flats); 1315 flat_modified(m_path.insert(it1, Flat(dh1)), modified_flats); // insert dh1 before it1 1316 it1=m_path.insert(next_iterator(it1), Flat(dh2)); // insert dh2 after it1 1317 flat_modified(it1, modified_flats); 1318 m_length+=2; 1319 } 1320 // Now we can continue with the normal case because we have 3 flats 1321 CGAL_assertion(flat_length(it1)==0); 1322 CGAL_assertion(flat_length(next_iterator(it1))==0); 1323 } 1324 else 1325 { 1326 // Here we have only one flat, with some -2 1327 // This case is not supposed possible. 1328 CGAL_assertion(false); 1329 return; 1330 } 1331 } 1332 } 1333 1334 List_iterator it2=next_iterator(it1); // Beginning of the second flat 1335 CGAL_assertion(it1!=it2); 1336 1337 if (flat_length(it1)>0) // Case where the first flat is positive 1338 { // We split the flat in two parts 1339 Dart_const_handle dh=end_of_flat(it1); // last dart of the first flat 1340 reduce_flat_from_end(it1, modified_flats); 1341 it1=m_path.insert(it2, Flat(dh)); // insert dh before it2 1342 ++m_length; 1343 flat_modified(it1, modified_flats); 1344 } 1345 1346 if (flat_length(it2)>0) // Case where the second flat is positive, we need to 1347 { // split it into two parts 1348 Dart_const_handle dh=begin_of_flat(it2); // first dart of the second flat 1349 reduce_flat_from_beginning(it2, modified_flats); 1350 it2=m_path.insert(it2, Flat(dh)); // insert dh before the second flat 1351 ++m_length; 1352 flat_modified(it2, modified_flats); 1353 } 1354 1355 // CGAL_assertion(is_valid(false)); 1356 // CGAL_assertion(is_l_shape(it1)); 1357 1358 Dart_const_handle dh1=get_map().template beta<2,1>(begin_of_flat(it1)); 1359 Dart_const_handle dh2=get_map().template beta<1>(dh1); 1360 Dart_const_handle dh3=get_map().template beta<2,1,2,0>(end_of_flat(it1)); 1361 Dart_const_handle dh4=get_map().template beta<2,0,2,1>(begin_of_flat(it2)); 1362 Dart_const_handle dh5=get_map().template beta<2,0,0>(end_of_flat(it2)); 1363 Dart_const_handle dh6=get_map().template beta<1>(dh5); 1364 1365 bool first_flat_zero=(flat_length(it1)==0); 1366 bool second_flat_zero=(flat_length(it2)==0); 1367 1368 if (first_flat_zero) 1369 { 1370 if (second_flat_zero) 1371 { // Special case of a l-shape with only 2 darts 1372 set_begin_of_flat(it1, dh1); 1373 set_end_of_flat(it1, dh1); 1374 set_begin_of_flat(it2, dh6); 1375 set_end_of_flat(it2, dh6); 1376 1377 flat_modified(it1, modified_flats); 1378 flat_modified(it2, modified_flats); 1379 1380 it1=merge_modified_flats_when_possible(modified_flats); 1381 1382 // CGAL_assertion(is_valid()); 1383 return; 1384 } 1385 else 1386 { // Here first flat length is 0, while second flat not 1387 set_begin_of_flat(it1, dh1); 1388 set_end_of_flat(it1, dh5); 1389 set_begin_of_flat(it2, dh6); 1390 set_end_of_flat(it2, dh6); 1391 set_flat_length(it1, -flat_length(it2)); 1392 set_flat_length(it2, 0); 1393 1394 flat_modified(it1, modified_flats); 1395 flat_modified(it2, modified_flats); 1396 1397 it1=merge_modified_flats_when_possible(modified_flats); 1398 1399 // CGAL_assertion(is_valid()); 1400 return; 1401 } 1402 } 1403 else 1404 { 1405 if (second_flat_zero) 1406 { // Here first flat length is non zero, while second flat length is 0 1407 set_begin_of_flat(it1, dh1); 1408 set_end_of_flat(it1, dh1); 1409 set_begin_of_flat(it2, dh2); 1410 set_end_of_flat(it2, dh6); 1411 set_flat_length(it2, -flat_length(it1)); 1412 set_flat_length(it1, 0); 1413 1414 flat_modified(it1, modified_flats); 1415 flat_modified(it2, modified_flats); 1416 1417 it1=merge_modified_flats_when_possible(modified_flats); 1418 1419 // CGAL_assertion(is_valid()); 1420 return; 1421 } 1422 } 1423 1424 // General case, with two flats with non zero length 1425 if (next_iterator(it2)!=it1 || next_negative_turn(it2)!=3) 1426 { 1427 // 1) Add the first dart before flat 'it' 1428 add_dart_before(it1, dh1, modified_flats); 1429 1430 // 2) Add the last dart after flat 'it2' 1431 add_dart_after(it2, dh6, modified_flats); 1432 } 1433 else 1434 { // Case "-2^s -1 -2^t -3" is a special case 1435 dh2=get_map().template beta<2,0>(dh1); 1436 dh5=get_map().template beta<2,1>(dh6); 1437 increase_flat_length(it1); 1438 increase_flat_length(it2); 1439 m_length+=2; 1440 flat_modified(it1, modified_flats); 1441 flat_modified(it2, modified_flats); 1442 } 1443 1444 // 3) Move the first flat 1445 CGAL_assertion(flat_length(it1)<0); 1446 set_begin_of_flat(it1, dh2); 1447 set_flat_length(it1, -(flat_length(it1))-1); 1448 if (flat_length(it1)==0) { set_end_of_flat(it1, dh2); } 1449 else { set_end_of_flat(it1, dh3); } // End of the moved flat 1450 flat_modified(it1, modified_flats); 1451 1452 // 4) Move the second flat 1453 CGAL_assertion(flat_length(it2)<0); 1454 set_begin_of_flat(it2, dh4); 1455 set_flat_length(it2, -(flat_length(it2))-1); 1456 if (flat_length(it2)==0) { set_end_of_flat(it2, dh4); } 1457 else { set_end_of_flat(it2, dh5); } // End of the moved flat 1458 flat_modified(it2, modified_flats); 1459 1460 CGAL_assertion(m_length>1); 1461 m_length-=2; 1462 1463 it1=merge_modified_flats_when_possible(modified_flats); 1464 } 1465 1466 /// Right push the path, if all all l-shape are pushed, otherwise only one. 1467 /// @return true iff the path was pushed 1468 bool right_push(bool all=true) 1469 { 1470 bool res=false; 1471 List_iterator it=m_path.begin(); 1472 while(it!=m_path.end()) 1473 { 1474 if (is_l_shape(it)) 1475 { 1476 right_push_l_shape(it); res=true; 1477 // CGAL_assertion(is_valid_iterator(it)); 1478 // CGAL_assertion(is_valid()); 1479 if (!all) { return true; } 1480 } 1481 else { move_to_next_l_shape(it); } 1482 } 1483 // CGAL_assertion(is_valid()); 1484 return res; 1485 } 1486 1487 /// Canonize the path canonize()1488 void canonize() 1489 { 1490 CGAL_assertion(is_valid()); 1491 1492 if (is_empty()) { return; } 1493 1494 CGAL_assertion(is_closed()); 1495 1496 bool modified=false; 1497 remove_spurs(); 1498 1499 do 1500 { 1501 modified=remove_brackets(); 1502 modified=modified || remove_spurs(); 1503 } 1504 while(modified); 1505 1506 right_push(); 1507 1508 CGAL_assertion(remove_brackets()==false); 1509 CGAL_assertion(remove_spurs()==false); 1510 CGAL_assertion(is_valid()); 1511 } 1512 display_positive_turns()1513 void display_positive_turns() 1514 { 1515 std::cout<<"+("; 1516 for (List_iterator it=m_path.begin(), itend=m_path.end(); 1517 it!=itend; ++it) 1518 { 1519 if (next_flat_exist(it)) 1520 { std::cout<<next_positive_turn(it)<<" "; } 1521 } 1522 std::cout<<")"; 1523 } 1524 display_negative_turns()1525 void display_negative_turns() 1526 { 1527 std::cout<<"-("; 1528 for (List_iterator it=m_path.begin(), itend=m_path.end(); 1529 it!=itend; ++it) 1530 { 1531 if (next_flat_exist(it)) 1532 { std::cout<<next_negative_turn(it)<<" "; } 1533 } 1534 std::cout<<")"; 1535 } 1536 display_pos_and_neg_turns()1537 void display_pos_and_neg_turns() 1538 { 1539 display_positive_turns(); 1540 std::cout<<" "; 1541 display_negative_turns(); 1542 } 1543 display()1544 void display() 1545 { 1546 if (!is_empty()) 1547 { 1548 for (List_iterator it=m_path.begin(), itend=m_path.end(); 1549 it!=itend; ++it) 1550 { 1551 std::cout<<"[ "; 1552 std::cout<<get_map().darts().index(begin_of_flat(it)) 1553 <<", "<<get_map().darts().index(end_of_flat(it)) 1554 <<"("<<flat_length(it)<<") ] "; 1555 } 1556 if (is_closed()) 1557 { std::cout<<" c "; } 1558 std::cout<<" length("<<length()<<")"; 1559 } 1560 } 1561 1562 friend std::ostream& operator<<(std::ostream& os, const Self& p) 1563 { 1564 const_cast<Self&>(p).display(); // Problem of const correctness: todo solve 1565 return os; 1566 } 1567 set_m_use_only_positive(bool UOP)1568 void set_m_use_only_positive(bool UOP) 1569 { m_use_only_positive=UOP; } 1570 set_m_use_only_negative(bool UON)1571 void set_m_use_only_negative(bool UON) 1572 { m_use_only_negative=UON; } 1573 1574 protected: 1575 const MQ& m_MQ; // The underlying map (a minimal quadrangulation) 1576 List_of_flats m_path; // The sequence of flats (a flat part is a pair of darts 1577 // with positive or negative turn == 2). If negative value k, -k is the 1578 // length of the flat part, for negative turns (-2). 1579 bool m_is_closed; // True iff the path is a cycle 1580 std::size_t m_length; 1581 bool m_use_only_positive; 1582 bool m_use_only_negative; 1583 1584 #ifdef CGAL_PWRLE_TURN_V2 1585 const TDartIds& m_darts_ids; 1586 #endif //CGAL_PWRLE_TURN_V2 1587 }; 1588 1589 } // namespace internal 1590 } // namespace Surface_mesh_topology 1591 } // namespace CGAL 1592 1593 #endif // CGAL_PATH_ON_SURFACE_WITH_RLE_H // 1594 // EOF // 1595