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 #ifndef OPENMESH_CIRCULATORS_HH
45 #define OPENMESH_CIRCULATORS_HH
46 //=============================================================================
47 //
48 // Vertex and Face circulators for PolyMesh/TriMesh
49 //
50 //=============================================================================
51 
52 
53 
54 //== INCLUDES =================================================================
55 
57 #include <cassert>
58 #include <cstddef>
59 #include <iterator>
60 
61 //== NAMESPACES ===============================================================
62 
63 namespace OpenMesh {
64 namespace Iterators {
65 
66 template<class Mesh, class CenterEntityHandle, bool CW>
68  public:
69  static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter);
70  static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter);
71 };
72 
73 template<class Mesh>
75  public:
76  inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
77  heh = mesh->cw_rotated_halfedge_handle(heh);
78  if (heh == start) ++lap_counter;
79  }
80  inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
81  if (heh == start) --lap_counter;
82  heh = mesh->ccw_rotated_halfedge_handle(heh);
83  }
84 };
85 
86 template<class Mesh>
88  public:
89  inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
90  heh = mesh->next_halfedge_handle(heh);
91  if (heh == start) ++lap_counter;
92  }
93  inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
94  if (heh == start) --lap_counter;
95  heh = mesh->prev_halfedge_handle(heh);
96  }
97 };
98 
100 // CCW
101 
102 template<class Mesh>
104  public:
105  inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
106  heh = mesh->ccw_rotated_halfedge_handle(heh);
107  if (heh == start) ++lap_counter;
108  }
109  inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
110  if (heh == start) --lap_counter;
111  heh = mesh->cw_rotated_halfedge_handle(heh);
112  }
113 };
114 
115 template<class Mesh>
117  public:
118  inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
119  heh = mesh->prev_halfedge_handle(heh);
120  if (heh == start) ++lap_counter;
121  }
122  inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
123  if (heh == start) --lap_counter;
124  heh = mesh->next_halfedge_handle(heh);
125  }
126 };
128 
129 template<class Mesh, class CenterEntityHandle, class ValueHandle>
131  public:
132  //inline static bool isDereferenciable(const Mesh *mesh, const typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, const int &lap_counter);
133 };
134 
135 template<class Mesh>
136 class GenericCirculator_DereferenciabilityCheckT<Mesh, typename Mesh::FaceHandle, typename Mesh::FaceHandle> {
137  public:
138  inline static bool isDereferenciable(const Mesh *mesh, const typename Mesh::HalfedgeHandle &heh) {
139  return mesh->face_handle(mesh->opposite_halfedge_handle(heh)).is_valid();
140  }
141 };
142 
143 template<class Mesh>
144 class GenericCirculator_DereferenciabilityCheckT<Mesh, typename Mesh::VertexHandle, typename Mesh::FaceHandle> {
145  public:
146  inline static bool isDereferenciable(const Mesh *mesh, const typename Mesh::HalfedgeHandle &heh) {
147  return mesh->face_handle(heh).is_valid();
148  }
149 };
150 
151 template<class Mesh, class CenterEntityHandle, class ValueHandle, bool CW = true>
153  public:
154  inline static bool is_valid(const typename Mesh::HalfedgeHandle &heh, const int lap_counter) {
155  return ( heh.is_valid() && (lap_counter == 0 ) );
156  }
157  inline static void init(const Mesh*, typename Mesh::HalfedgeHandle&, typename Mesh::HalfedgeHandle&, int&) {};
158  inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
160  }
161  inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
163  }
164 };
165 
166 template<class Mesh, class CenterEntityHandle, bool CW>
167 class GenericCirculator_ValueHandleFnsT<Mesh, CenterEntityHandle, typename Mesh::FaceHandle, CW> {
168  public:
170 
171  inline static bool is_valid(const typename Mesh::HalfedgeHandle &heh, const int lap_counter) {
172  return ( heh.is_valid() && (lap_counter == 0));
173  }
174  inline static void init(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
175  if (heh.is_valid() && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh) && lap_counter == 0 )
176  increment(mesh, heh, start, lap_counter);
177  };
178  inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
179  do {
181  } while (is_valid(heh, lap_counter) && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh));
182  }
183  inline static void decrement(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 };
189 
190 template<class Mesh>
192  public:
193  typedef const Mesh* mesh_ptr;
194  typedef const Mesh& mesh_ref;
195 
196  public:
197  GenericCirculatorBaseT() : mesh_(0), lap_counter_(0) {}
198 
199  GenericCirculatorBaseT(mesh_ref mesh, HalfedgeHandle heh, bool end = false) :
200  mesh_(&mesh), start_(heh), heh_(heh), lap_counter_(static_cast<int>(end && heh.is_valid())) {}
201 
203  mesh_(rhs.mesh_), start_(rhs.start_), heh_(rhs.heh_), lap_counter_(rhs.lap_counter_) {}
204 
205  inline typename Mesh::FaceHandle toFaceHandle() const {
206  return mesh_->face_handle(heh_);
207  }
208 
209  inline typename Mesh::FaceHandle toOppositeFaceHandle() const {
210  return mesh_->face_handle(toOppositeHalfedgeHandle());
211  }
212 
213  inline typename Mesh::EdgeHandle toEdgeHandle() const {
214  return mesh_->edge_handle(heh_);
215  }
216 
217  inline typename Mesh::HalfedgeHandle toHalfedgeHandle() const {
218  return heh_;
219  }
220 
221  inline typename Mesh::HalfedgeHandle toOppositeHalfedgeHandle() const {
222  return mesh_->opposite_halfedge_handle(heh_);
223  }
224 
225  inline typename Mesh::VertexHandle toVertexHandle() const {
226  return mesh_->to_vertex_handle(heh_);
227  }
228 
229  inline GenericCirculatorBaseT &operator=(const GenericCirculatorBaseT &rhs) {
230  mesh_ = rhs.mesh_;
231  start_ = rhs.start_;
232  heh_ = rhs.heh_;
233  lap_counter_ = rhs.lap_counter_;
234  return *this;
235  }
236 
237  inline bool operator==(const GenericCirculatorBaseT &rhs) const {
238  return mesh_ == rhs.mesh_ && start_ == rhs.start_ && heh_ == rhs.heh_ && lap_counter_ == rhs.lap_counter_;
239  }
240 
241  inline bool operator!=(const GenericCirculatorBaseT &rhs) const {
242  return !operator==(rhs);
243  }
244 
245  protected:
246  mesh_ptr mesh_;
247  typename Mesh::HalfedgeHandle start_, heh_;
248  int lap_counter_;
249 };
250 
251 template<class Mesh, class CenterEntityHandle, class ValueHandle,
252  ValueHandle (GenericCirculatorBaseT<Mesh>::*Handle2Value)() const, bool CW = true >
254  public:
255  typedef std::ptrdiff_t difference_type;
256  typedef ValueHandle value_type;
257  typedef const value_type& reference;
258  typedef const value_type* pointer;
259  typedef std::bidirectional_iterator_tag iterator_category;
260 
264 
265  public:
266  GenericCirculatorT() {}
267  GenericCirculatorT(mesh_ref mesh, CenterEntityHandle start, bool end = false) :
268  GenericCirculatorBaseT<Mesh>(mesh, mesh.halfedge_handle(start), end) {
269 
270  GenericCirculator_ValueHandleFns::init(this->mesh_, this->heh_, this->start_, this->lap_counter_);
271  }
272  GenericCirculatorT(mesh_ref mesh, HalfedgeHandle heh, bool end = false) :
273  GenericCirculatorBaseT<Mesh>(mesh, heh, end) {
274 
275  GenericCirculator_ValueHandleFns::init(this->mesh_, this->heh_, this->start_, this->lap_counter_);
276  }
278 
282 
283  GenericCirculatorT& operator++() {
284  assert(this->mesh_);
285  GenericCirculator_ValueHandleFns::increment(this->mesh_, this->heh_, this->start_, this->lap_counter_);
286  return *this;
287  }
288  GenericCirculatorT& operator--() {
289  assert(this->mesh_);
290  GenericCirculator_ValueHandleFns::decrement(this->mesh_, this->heh_, this->start_, this->lap_counter_);
291  return *this;
292  }
293 
296  assert(this->mesh_);
297  GenericCirculatorT cpy(*this);
298  ++(*this);
299  return cpy;
300  }
301 
304  assert(this->mesh_);
305  GenericCirculatorT cpy(*this);
306  --(*this);
307  return cpy;
308  }
309 
311  value_type operator*() const {
312  // We can't use this due to a GCC6 compiler bug
313  const GenericCirculatorBaseT<Mesh>* self = this;
314 #ifndef NDEBUG
315  assert(this->heh_.is_valid());
316  value_type res = (self->*Handle2Value)();
317  assert(res.is_valid());
318  return res;
319 #else
320  return (self->*Handle2Value)();
321 #endif
322  }
323 
332  pointer operator->() const {
333  pointer_deref_value = **this;
334  return &pointer_deref_value;
335  }
336 
337  GenericCirculatorT &operator=(const GenericCirculatorT &rhs) {
339  return *this;
340  };
341 
342  bool operator==(const GenericCirculatorT &rhs) const {
344  }
345 
346  bool operator!=(const GenericCirculatorT &rhs) const {
348  }
349 
350  bool is_valid() const {
351  return GenericCirculator_ValueHandleFns::is_valid(this->heh_, this->lap_counter_);
352  }
353 
354  template<typename STREAM>
355  friend STREAM &operator<< (STREAM &s, const GenericCirculatorT &self) {
356  return s << self.mesh_ << ", " << self.start_.idx() << ", " << self.heh_.idx() << ", " << self.lap_counter_;
357  }
358 
359  private:
360  mutable value_type pointer_deref_value;
361 };
362 
367 // OLD CIRCULATORS
368 // deprecated circulators, will be removed soon
369 // if you remove these circulators and go to the old ones, PLEASE ENABLE FOLLOWING UNITTESTS:
370 //
371 // OpenMeshTrimeshCirculatorVertexIHalfEdge.VertexIHalfEdgeIterCheckInvalidationAtEnds
372 // OpenMeshTrimeshCirculatorVertexEdge.VertexEdgeIterCheckInvalidationAtEnds
373 // OpenMeshTrimeshCirculatorVertexVertex.VertexVertexIterCheckInvalidationAtEnds
374 // OpenMeshTrimeshCirculatorVertexOHalfEdge.VertexOHalfEdgeIterCheckInvalidationAtEnds
375 // OpenMeshTrimeshCirculatorVertexFace.VertexFaceIterCheckInvalidationAtEnds
376 // OpenMeshTrimeshCirculatorVertexFace.VertexFaceIterWithoutHolesDecrement
377 // OpenMeshTrimeshCirculatorFaceEdge.FaceEdgeIterCheckInvalidationAtEnds
378 // OpenMeshTrimeshCirculatorFaceFace.FaceFaceIterCheckInvalidationAtEnds
379 // OpenMeshTrimeshCirculatorFaceHalfEdge.FaceHalfedgeIterWithoutHolesIncrement
380 // OpenMeshTrimeshCirculatorFaceVertex.FaceVertexIterCheckInvalidationAtEnds
381 // OpenMeshTrimeshCirculatorFaceHalfEdge.FaceHalfedgeIterCheckInvalidationAtEnds
382 //
383 
384 template<class Mesh, class CenterEntityHandle, class ValueHandle>
386  public:
387  inline static bool is_valid(const typename Mesh::HalfedgeHandle &heh,const typename Mesh::HalfedgeHandle &start, const int lap_counter) {
388  return ( heh.is_valid() && ((start != heh) || (lap_counter == 0 )) );
389  }
390  inline static void init(const Mesh*, typename Mesh::HalfedgeHandle&, typename Mesh::HalfedgeHandle&, int&) {};
391  inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
393  }
394  inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
396  }
397 };
398 
399 template<class Mesh, class CenterEntityHandle>
401  public:
403 
404  inline static bool is_valid(const typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, const int lap_counter) {
405  return ( heh.is_valid() && ((start != heh) || (lap_counter == 0 )));
406  }
407  inline static void init(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
408  if (heh.is_valid() && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh) && lap_counter == 0 )
409  increment(mesh, heh, start, lap_counter);
410  };
411  inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
412  do {
414  } while (is_valid(heh, start, lap_counter) && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh));
415  }
416  inline static void decrement(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 };
422 
423 template<class Mesh, class CenterEntityHandle, class ValueHandle,
424  ValueHandle (GenericCirculatorBaseT<Mesh>::*Handle2Value)() const>
426  public:
427  typedef std::ptrdiff_t difference_type;
428  typedef ValueHandle value_type;
429  typedef const value_type& reference;
430  typedef const value_type* pointer;
431  typedef std::bidirectional_iterator_tag iterator_category;
432 
436 
437  public:
439  GenericCirculatorT_DEPRECATED(mesh_ref mesh, CenterEntityHandle start, bool end = false) :
440  GenericCirculatorBaseT<Mesh>(mesh, mesh.halfedge_handle(start), end) {
441 
442  GenericCirculator_ValueHandleFns::init(this->mesh_, this->heh_, this->start_, this->lap_counter_);
443  }
444  GenericCirculatorT_DEPRECATED(mesh_ref mesh, HalfedgeHandle heh, bool end = false) :
445  GenericCirculatorBaseT<Mesh>(mesh, heh, end) {
446 
447  GenericCirculator_ValueHandleFns::init(this->mesh_, this->heh_, this->start_, this->lap_counter_);
448  }
450 
451  GenericCirculatorT_DEPRECATED& operator++() {
452  assert(this->mesh_);
453  GenericCirculator_ValueHandleFns::increment(this->mesh_, this->heh_, this->start_, this->lap_counter_);
454  return *this;
455  }
456 #ifndef NO_DECREMENT_DEPRECATED_WARNINGS
457 #define DECREMENT_DEPRECATED_WARNINGS_TEXT "The current decrement operator has the unintended behavior that it stays\
458  valid when iterating below the start and will visit the first entity\
459  twice before getting invalid. Furthermore it gets valid again, if you\
460  increment at the end.\
461  When you are sure that you don't iterate below the start anywhere in\
462  your code or rely on this behaviour, you can disable this warning by\
463  setting the define NO_DECREMENT_DEPRECATED_WARNINGS at the command line (or enable it via the\
464  cmake flags).\
465  To be save, you can use the CW/CCW circulator definitions, which behave\
466  the same as the original ones, without the previously mentioned issues."
467 
468  OM_DEPRECATED( DECREMENT_DEPRECATED_WARNINGS_TEXT )
469 #endif // NO_DECREMENT_DEPRECATED_WARNINGS
470  GenericCirculatorT_DEPRECATED& operator--() {
471  assert(this->mesh_);
472  GenericCirculator_ValueHandleFns::decrement(this->mesh_, this->heh_, this->start_, this->lap_counter_);
473  return *this;
474  }
475 
478  assert(this->mesh_);
480  ++(*this);
481  return cpy;
482  }
483 
485 #ifndef NO_DECREMENT_DEPRECATED_WARNINGS
486  OM_DEPRECATED( DECREMENT_DEPRECATED_WARNINGS_TEXT )
487 #undef DECREMENT_DEPRECATED_WARNINGS_TEXT
488 #endif //NO_DECREMENT_DEPRECATED_WARNINGS
490  assert(this->mesh_);
492  --(*this);
493  return cpy;
494  }
495 
497  value_type operator*() const {
498  // We can't use this due to a GCC6 compiler bug
499  const GenericCirculatorBaseT<Mesh>* self = this;
500 #ifndef NDEBUG
501  assert(this->heh_.is_valid());
502  value_type res = (self->*Handle2Value)();
503  assert(res.is_valid());
504  return res;
505 #else
506  return (self->*Handle2Value)();
507 #endif
508  }
509 
518  pointer operator->() const {
519  pointer_deref_value = **this;
520  return &pointer_deref_value;
521  }
522 
525  return *this;
526  };
527 
528  bool operator==(const GenericCirculatorT_DEPRECATED &rhs) const {
530  }
531 
532  bool operator!=(const GenericCirculatorT_DEPRECATED &rhs) const {
534  }
535 
536  bool is_valid() const {
537  return GenericCirculator_ValueHandleFns::is_valid(this->heh_,this->start_, this->lap_counter_);
538  }
539 
540  OM_DEPRECATED("current_halfedge_handle() is an implementation detail and should not be accessed from outside the iterator class.")
546  const HalfedgeHandle &current_halfedge_handle() const {
547  return this->heh_;
548  }
549 
550  OM_DEPRECATED("Do not use this error prone implicit cast. Compare to end-iterator or use is_valid(), instead.")
556  operator bool() const {
557  return is_valid();
558  }
559 
565  OM_DEPRECATED("This function clutters your code. Use dereferencing operators -> and * instead.")
566  value_type handle() const {
567  return **this;
568  }
569 
576  OM_DEPRECATED("Implicit casts of iterators are unsafe. Use dereferencing operators -> and * instead.")
577  operator value_type() const {
578  return **this;
579  }
580 
581  template<typename STREAM>
582  friend STREAM &operator<< (STREAM &s, const GenericCirculatorT_DEPRECATED &self) {
583  return s << self.mesh_ << ", " << self.start_.idx() << ", " << self.heh_.idx() << ", " << self.lap_counter_;
584  }
585 
586  private:
587  mutable value_type pointer_deref_value;
588 };
589 
590 } // namespace Iterators
591 } // namespace OpenMesh
592 
593 #endif
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:647
value_type operator*() const
Standard dereferencing operator.
Handle for a vertex entity.
Definition: Handles.hh:120
pointer operator->() const
Pointer dereferentiation.
Handle for a halfedge entity.
Definition: Handles.hh:127
GenericCirculatorT_DEPRECATED operator--(int)
Post-decrement.
Kernel::VertexHandle VertexHandle
Handle for referencing the corresponding item.
Definition: PolyMeshT.hh:136
GenericCirculatorT operator--(int)
Post-decrement.
pointer operator->() const
Pointer dereferentiation.
value_type operator*() const
Standard dereferencing operator.
GenericCirculatorT_DEPRECATED operator++(int)
Post-increment.
Handle for a face entity.
Definition: Handles.hh:141
bool is_valid() const
The handle is valid iff the index is not negative.
Definition: Handles.hh:72
GenericCirculatorT operator++(int)
Post-increment.