Developer Documentation
CirculatorsT.hh
1 /* ========================================================================= *
2  * *
3  * OpenMesh *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openmesh.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenMesh. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39  * *
40  * ========================================================================= */
41 
42 /*===========================================================================*\
43  * *
44  * $Revision$ *
45  * $Date$ *
46  * *
47 \*===========================================================================*/
48 
49 #ifndef OPENMESH_CIRCULATORS_HH
50 #define OPENMESH_CIRCULATORS_HH
51 //=============================================================================
52 //
53 // Vertex and Face circulators for PolyMesh/TriMesh
54 //
55 //=============================================================================
56 
57 
58 
59 //== INCLUDES =================================================================
60 
62 #include <cassert>
63 #include <cstddef>
64 #include <iterator>
65 
66 //== NAMESPACES ===============================================================
67 
68 namespace OpenMesh {
69 namespace Iterators {
70 
71 template<class Mesh, class CenterEntityHandle, bool CW>
73  public:
74  static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter);
75  static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter);
76 };
77 
78 template<class Mesh>
80  public:
81  inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
82  heh = mesh->cw_rotated_halfedge_handle(heh);
83  if (heh == start) ++lap_counter;
84  }
85  inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
86  if (heh == start) --lap_counter;
87  heh = mesh->ccw_rotated_halfedge_handle(heh);
88  }
89 };
90 
91 template<class Mesh>
93  public:
94  inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
95  heh = mesh->next_halfedge_handle(heh);
96  if (heh == start) ++lap_counter;
97  }
98  inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
99  if (heh == start) --lap_counter;
100  heh = mesh->prev_halfedge_handle(heh);
101  }
102 };
103 
105 // CCW
106 
107 template<class Mesh>
109  public:
110  inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
111  heh = mesh->ccw_rotated_halfedge_handle(heh);
112  if (heh == start) ++lap_counter;
113  }
114  inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
115  if (heh == start) --lap_counter;
116  heh = mesh->cw_rotated_halfedge_handle(heh);
117  }
118 };
119 
120 template<class Mesh>
122  public:
123  inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
124  heh = mesh->prev_halfedge_handle(heh);
125  if (heh == start) ++lap_counter;
126  }
127  inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
128  if (heh == start) --lap_counter;
129  heh = mesh->next_halfedge_handle(heh);
130  }
131 };
133 
134 template<class Mesh, class CenterEntityHandle, class ValueHandle>
136  public:
137  //inline static bool isDereferenciable(const Mesh *mesh, const typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, const int &lap_counter);
138 };
139 
140 template<class Mesh>
141 class GenericCirculator_DereferenciabilityCheckT<Mesh, typename Mesh::FaceHandle, typename Mesh::FaceHandle> {
142  public:
143  inline static bool isDereferenciable(const Mesh *mesh, const typename Mesh::HalfedgeHandle &heh) {
144  return mesh->face_handle(mesh->opposite_halfedge_handle(heh)).is_valid();
145  }
146 };
147 
148 template<class Mesh>
149 class GenericCirculator_DereferenciabilityCheckT<Mesh, typename Mesh::VertexHandle, typename Mesh::FaceHandle> {
150  public:
151  inline static bool isDereferenciable(const Mesh *mesh, const typename Mesh::HalfedgeHandle &heh) {
152  return mesh->face_handle(heh).is_valid();
153  }
154 };
155 
156 template<class Mesh, class CenterEntityHandle, class ValueHandle, bool CW = true>
158  public:
159  inline static bool is_valid(const typename Mesh::HalfedgeHandle &heh, const int lap_counter) {
160  return ( heh.is_valid() && (lap_counter == 0 ) );
161  }
162  inline static void init(const Mesh*, typename Mesh::HalfedgeHandle&, typename Mesh::HalfedgeHandle&, int&) {};
163  inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
165  }
166  inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
168  }
169 };
170 
171 template<class Mesh, class CenterEntityHandle, bool CW>
172 class GenericCirculator_ValueHandleFnsT<Mesh, CenterEntityHandle, typename Mesh::FaceHandle, CW> {
173  public:
175 
176  inline static bool is_valid(const typename Mesh::HalfedgeHandle &heh, const int lap_counter) {
177  return ( heh.is_valid() && (lap_counter == 0));
178  }
179  inline static void init(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
180  if (heh.is_valid() && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh) && lap_counter == 0 )
181  increment(mesh, heh, start, lap_counter);
182  };
183  inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
184  do {
186  } while (is_valid(heh, lap_counter) && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh));
187  }
188  inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
189  do {
191  } while (is_valid(heh, lap_counter) && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh));
192  }
193 };
194 
195 template<class Mesh>
197  public:
198  typedef const Mesh* mesh_ptr;
199  typedef const Mesh& mesh_ref;
200 
201  public:
202  GenericCirculatorBaseT() : mesh_(0), lap_counter_(0) {}
203 
204  GenericCirculatorBaseT(mesh_ref mesh, HalfedgeHandle heh, bool end = false) :
205  mesh_(&mesh), start_(heh), heh_(heh), lap_counter_(static_cast<int>(end && heh.is_valid())) {}
206 
208  mesh_(rhs.mesh_), start_(rhs.start_), heh_(rhs.heh_), lap_counter_(rhs.lap_counter_) {}
209 
210  inline typename Mesh::FaceHandle toFaceHandle() const {
211  return mesh_->face_handle(heh_);
212  }
213 
214  inline typename Mesh::FaceHandle toOppositeFaceHandle() const {
215  return mesh_->face_handle(toOppositeHalfedgeHandle());
216  }
217 
218  inline typename Mesh::EdgeHandle toEdgeHandle() const {
219  return mesh_->edge_handle(heh_);
220  }
221 
222  inline typename Mesh::HalfedgeHandle toHalfedgeHandle() const {
223  return heh_;
224  }
225 
226  inline typename Mesh::HalfedgeHandle toOppositeHalfedgeHandle() const {
227  return mesh_->opposite_halfedge_handle(heh_);
228  }
229 
230  inline typename Mesh::VertexHandle toVertexHandle() const {
231  return mesh_->to_vertex_handle(heh_);
232  }
233 
234  inline GenericCirculatorBaseT &operator=(const GenericCirculatorBaseT &rhs) {
235  mesh_ = rhs.mesh_;
236  start_ = rhs.start_;
237  heh_ = rhs.heh_;
238  lap_counter_ = rhs.lap_counter_;
239  return *this;
240  }
241 
242  inline bool operator==(const GenericCirculatorBaseT &rhs) const {
243  return mesh_ == rhs.mesh_ && start_ == rhs.start_ && heh_ == rhs.heh_ && lap_counter_ == rhs.lap_counter_;
244  }
245 
246  inline bool operator!=(const GenericCirculatorBaseT &rhs) const {
247  return !operator==(rhs);
248  }
249 
250  protected:
251  mesh_ptr mesh_;
252  typename Mesh::HalfedgeHandle start_, heh_;
253  int lap_counter_;
254 };
255 
256 template<class Mesh, class CenterEntityHandle, class ValueHandle,
257  ValueHandle (GenericCirculatorBaseT<Mesh>::*Handle2Value)() const, bool CW = true >
259  public:
260  typedef std::ptrdiff_t difference_type;
261  typedef ValueHandle value_type;
262  typedef const value_type& reference;
263  typedef const value_type* pointer;
264  typedef std::bidirectional_iterator_tag iterator_category;
265 
269 
270  public:
271  GenericCirculatorT() {}
272  GenericCirculatorT(mesh_ref mesh, CenterEntityHandle start, bool end = false) :
273  GenericCirculatorBaseT<Mesh>(mesh, mesh.halfedge_handle(start), end) {
274 
275  GenericCirculator_ValueHandleFns::init(this->mesh_, this->heh_, this->start_, this->lap_counter_);
276  }
277  GenericCirculatorT(mesh_ref mesh, HalfedgeHandle heh, bool end = false) :
278  GenericCirculatorBaseT<Mesh>(mesh, heh, end) {
279 
280  GenericCirculator_ValueHandleFns::init(this->mesh_, this->heh_, this->start_, this->lap_counter_);
281  }
283 
287 
288  GenericCirculatorT& operator++() {
289  assert(this->mesh_);
290  GenericCirculator_ValueHandleFns::increment(this->mesh_, this->heh_, this->start_, this->lap_counter_);
291  return *this;
292  }
293  GenericCirculatorT& operator--() {
294  assert(this->mesh_);
295  GenericCirculator_ValueHandleFns::decrement(this->mesh_, this->heh_, this->start_, this->lap_counter_);
296  return *this;
297  }
298 
301  assert(this->mesh_);
302  GenericCirculatorT cpy(*this);
303  ++(*this);
304  return cpy;
305  }
306 
309  assert(this->mesh_);
310  GenericCirculatorT cpy(*this);
311  --(*this);
312  return cpy;
313  }
314 
316  value_type operator*() const {
317  // We can't use this due to a GCC6 compiler bug
318  const GenericCirculatorBaseT<Mesh>* self = this;
319 #ifndef NDEBUG
320  assert(this->heh_.is_valid());
321  value_type res = (self->*Handle2Value)();
322  assert(res.is_valid());
323  return res;
324 #else
325  return (self->*Handle2Value)();
326 #endif
327  }
328 
337  pointer operator->() const {
338  pointer_deref_value = **this;
339  return &pointer_deref_value;
340  }
341 
342  GenericCirculatorT &operator=(const GenericCirculatorT &rhs) {
344  return *this;
345  };
346 
347  bool operator==(const GenericCirculatorT &rhs) const {
349  }
350 
351  bool operator!=(const GenericCirculatorT &rhs) const {
353  }
354 
355  bool is_valid() const {
356  return GenericCirculator_ValueHandleFns::is_valid(this->heh_, this->lap_counter_);
357  }
358 
359  template<typename STREAM>
360  friend STREAM &operator<< (STREAM &s, const GenericCirculatorT &self) {
361  return s << self.mesh_ << ", " << self.start_.idx() << ", " << self.heh_.idx() << ", " << self.lap_counter_;
362  }
363 
364  private:
365  mutable value_type pointer_deref_value;
366 };
367 
372 // OLD CIRCULATORS
373 // deprecated circulators, will be removed soon
374 // if you remove these circulators and go to the old ones, PLEASE ENABLE FOLLOWING UNITTESTS:
375 //
376 // OpenMeshTrimeshCirculatorVertexIHalfEdge.VertexIHalfEdgeIterCheckInvalidationAtEnds
377 // OpenMeshTrimeshCirculatorVertexEdge.VertexEdgeIterCheckInvalidationAtEnds
378 // OpenMeshTrimeshCirculatorVertexVertex.VertexVertexIterCheckInvalidationAtEnds
379 // OpenMeshTrimeshCirculatorVertexOHalfEdge.VertexOHalfEdgeIterCheckInvalidationAtEnds
380 // OpenMeshTrimeshCirculatorVertexFace.VertexFaceIterCheckInvalidationAtEnds
381 // OpenMeshTrimeshCirculatorVertexFace.VertexFaceIterWithoutHolesDecrement
382 // OpenMeshTrimeshCirculatorFaceEdge.FaceEdgeIterCheckInvalidationAtEnds
383 // OpenMeshTrimeshCirculatorFaceFace.FaceFaceIterCheckInvalidationAtEnds
384 // OpenMeshTrimeshCirculatorFaceHalfEdge.FaceHalfedgeIterWithoutHolesIncrement
385 // OpenMeshTrimeshCirculatorFaceVertex.FaceVertexIterCheckInvalidationAtEnds
386 // OpenMeshTrimeshCirculatorFaceHalfEdge.FaceHalfedgeIterCheckInvalidationAtEnds
387 //
388 
389 template<class Mesh, class CenterEntityHandle, class ValueHandle>
391  public:
392  inline static bool is_valid(const typename Mesh::HalfedgeHandle &heh,const typename Mesh::HalfedgeHandle &start, const int lap_counter) {
393  return ( heh.is_valid() && ((start != heh) || (lap_counter == 0 )) );
394  }
395  inline static void init(const Mesh*, typename Mesh::HalfedgeHandle&, typename Mesh::HalfedgeHandle&, int&) {};
396  inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
398  }
399  inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
401  }
402 };
403 
404 template<class Mesh, class CenterEntityHandle>
406  public:
408 
409  inline static bool is_valid(const typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, const int lap_counter) {
410  return ( heh.is_valid() && ((start != heh) || (lap_counter == 0 )));
411  }
412  inline static void init(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
413  if (heh.is_valid() && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh) && lap_counter == 0 )
414  increment(mesh, heh, start, lap_counter);
415  };
416  inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
417  do {
419  } while (is_valid(heh, start, lap_counter) && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh));
420  }
421  inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
422  do {
424  } while (is_valid(heh, start, lap_counter) && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh));
425  }
426 };
427 
428 template<class Mesh, class CenterEntityHandle, class ValueHandle,
429  ValueHandle (GenericCirculatorBaseT<Mesh>::*Handle2Value)() const>
431  public:
432  typedef std::ptrdiff_t difference_type;
433  typedef ValueHandle value_type;
434  typedef const value_type& reference;
435  typedef const value_type* pointer;
436  typedef std::bidirectional_iterator_tag iterator_category;
437 
441 
442  public:
444  GenericCirculatorT_DEPRECATED(mesh_ref mesh, CenterEntityHandle start, bool end = false) :
445  GenericCirculatorBaseT<Mesh>(mesh, mesh.halfedge_handle(start), end) {
446 
447  GenericCirculator_ValueHandleFns::init(this->mesh_, this->heh_, this->start_, this->lap_counter_);
448  }
449  GenericCirculatorT_DEPRECATED(mesh_ref mesh, HalfedgeHandle heh, bool end = false) :
450  GenericCirculatorBaseT<Mesh>(mesh, heh, end) {
451 
452  GenericCirculator_ValueHandleFns::init(this->mesh_, this->heh_, this->start_, this->lap_counter_);
453  }
455 
456  GenericCirculatorT_DEPRECATED& operator++() {
457  assert(this->mesh_);
458  GenericCirculator_ValueHandleFns::increment(this->mesh_, this->heh_, this->start_, this->lap_counter_);
459  return *this;
460  }
461 #ifndef NO_DECREMENT_DEPRECATED_WARNINGS
462 #define DECREMENT_DEPRECATED_WARNINGS_TEXT "The current decrement operator has the unintended behavior that it stays\
463  valid when iterating below the start and will visit the first entity\
464  twice before getting invalid. Furthermore it gets valid again, if you\
465  increment at the end.\
466  When you are sure that you don't iterate below the start anywhere in\
467  your code or rely on this behaviour, you can disable this warning by\
468  setting the define NO_DECREMENT_DEPRECATED_WARNINGS at the command line (or enable it via the\
469  cmake flags).\
470  To be save, you can use the CW/CCW circulator definitions, which behave\
471  the same as the original ones, without the previously mentioned issues."
472 
473  DEPRECATED( DECREMENT_DEPRECATED_WARNINGS_TEXT )
474 #endif // NO_DECREMENT_DEPRECATED_WARNINGS
475  GenericCirculatorT_DEPRECATED& operator--() {
476  assert(this->mesh_);
477  GenericCirculator_ValueHandleFns::decrement(this->mesh_, this->heh_, this->start_, this->lap_counter_);
478  return *this;
479  }
480 
483  assert(this->mesh_);
485  ++(*this);
486  return cpy;
487  }
488 
490 #ifndef NO_DECREMENT_DEPRECATED_WARNINGS
491  DEPRECATED( DECREMENT_DEPRECATED_WARNINGS_TEXT )
492 #undef DECREMENT_DEPRECATED_WARNINGS_TEXT
493 #endif //NO_DECREMENT_DEPRECATED_WARNINGS
495  assert(this->mesh_);
497  --(*this);
498  return cpy;
499  }
500 
502  value_type operator*() const {
503  // We can't use this due to a GCC6 compiler bug
504  const GenericCirculatorBaseT<Mesh>* self = this;
505 #ifndef NDEBUG
506  assert(this->heh_.is_valid());
507  value_type res = (self->*Handle2Value)();
508  assert(res.is_valid());
509  return res;
510 #else
511  return (self->*Handle2Value)();
512 #endif
513  }
514 
523  pointer operator->() const {
524  pointer_deref_value = **this;
525  return &pointer_deref_value;
526  }
527 
530  return *this;
531  };
532 
533  bool operator==(const GenericCirculatorT_DEPRECATED &rhs) const {
535  }
536 
537  bool operator!=(const GenericCirculatorT_DEPRECATED &rhs) const {
539  }
540 
541  bool is_valid() const {
542  return GenericCirculator_ValueHandleFns::is_valid(this->heh_,this->start_, this->lap_counter_);
543  }
544 
545  DEPRECATED("current_halfedge_handle() is an implementation detail and should not be accessed from outside the iterator class.")
551  const HalfedgeHandle &current_halfedge_handle() const {
552  return this->heh_;
553  }
554 
555  DEPRECATED("Do not use this error prone implicit cast. Compare to end-iterator or use is_valid(), instead.")
561  operator bool() const {
562  return is_valid();
563  }
564 
570  DEPRECATED("This function clutters your code. Use dereferencing operators -> and * instead.")
571  value_type handle() const {
572  return **this;
573  }
574 
581  DEPRECATED("Implicit casts of iterators are unsafe. Use dereferencing operators -> and * instead.")
582  operator value_type() const {
583  return **this;
584  }
585 
586  template<typename STREAM>
587  friend STREAM &operator<< (STREAM &s, const GenericCirculatorT_DEPRECATED &self) {
588  return s << self.mesh_ << ", " << self.start_.idx() << ", " << self.heh_.idx() << ", " << self.lap_counter_;
589  }
590 
591  private:
592  mutable value_type pointer_deref_value;
593 };
594 
595 } // namespace Iterators
596 } // namespace OpenMesh
597 
598 #endif
GenericCirculatorT_DEPRECATED operator--(int)
Post-decrement.
value_type operator*() const
Standard dereferencing operator.
auto operator<<(std::ostream &os, const VectorT< Scalar, DIM > &_vec) -> typename std::enable_if< sizeof(decltype(os<< _vec[0])) >=0
output a vector by printing its space-separated compontens
Definition: VectorT.hh:652
value_type operator*() const
Standard dereferencing operator.
bool is_valid() const
The handle is valid iff the index is not equal to -1.
Definition: Handles.hh:77
Handle for a halfedge entity.
Definition: Handles.hh:132
Handle for a vertex entity.
Definition: Handles.hh:125
Kernel::VertexHandle VertexHandle
Handle for referencing the corresponding item.
Definition: PolyMeshT.hh:139
Handle for a face entity.
Definition: Handles.hh:146
GenericCirculatorT_DEPRECATED operator++(int)
Post-increment.
pointer operator->() const
Pointer dereferentiation.
GenericCirculatorT operator++(int)
Post-increment.
pointer operator->() const
Pointer dereferentiation.
GenericCirculatorT operator--(int)
Post-decrement.