43 #include <pcl/geometry/boost.h>
44 #include <pcl/geometry/eigen.h>
45 #include <pcl/geometry/mesh_circulators.h>
46 #include <pcl/geometry/mesh_indices.h>
47 #include <pcl/geometry/mesh_elements.h>
48 #include <pcl/geometry/mesh_traits.h>
49 #include <pcl/memory.h>
50 #include <pcl/pcl_macros.h>
51 #include <pcl/point_cloud.h>
54 #include <type_traits>
60 #ifdef PCL_GEOMETRY_MESH_BASE_TEST_DELETE_FACE_MANIFOLD_2
65 bool g_pcl_geometry_mesh_base_test_delete_face_manifold_2_success;
78 template <
class MeshT>
99 template <
class DerivedT,
class MeshTraitsT,
class MeshTagT>
105 using Ptr = shared_ptr<Self>;
118 static_assert (std::is_convertible<IsManifold, bool>::value,
"MeshTraitsT::IsManifold is not convertible to bool");
120 using MeshTag = MeshTagT;
123 using HasVertexData = std::integral_constant <bool, !std::is_same <VertexData , pcl::geometry::NoData>::value>;
124 using HasHalfEdgeData = std::integral_constant <bool, !std::is_same <HalfEdgeData, pcl::geometry::NoData>::value>;
125 using HasEdgeData = std::integral_constant <bool, !std::is_same <EdgeData , pcl::geometry::NoData>::value>;
126 using HasFaceData = std::integral_constant <bool, !std::is_same <FaceData , pcl::geometry::NoData>::value>;
139 using VertexIndices = std::vector<VertexIndex>;
140 using HalfEdgeIndices = std::vector<HalfEdgeIndex>;
141 using EdgeIndices = std::vector<EdgeIndex>;
142 using FaceIndices = std::vector<FaceIndex>;
156 : vertex_data_cloud_ (),
157 half_edge_data_cloud_ (),
174 vertices_.push_back (
Vertex ());
175 this->addData (vertex_data_cloud_, vertex_data, HasVertexData ());
176 return (
VertexIndex (static_cast <int> (this->sizeVertices () - 1)));
188 addFace (
const VertexIndices& vertices,
194 return (static_cast <Derived*> (
this)->addFaceImpl (vertices, face_data, edge_data, half_edge_data));
201 deleteVertex (
const VertexIndex& idx_vertex)
203 assert (this->isValid (idx_vertex));
204 if (this->isDeleted (idx_vertex))
return;
206 delete_faces_vertex_.clear ();
207 FaceAroundVertexCirculator circ = this->getFaceAroundVertexCirculator (idx_vertex);
208 const FaceAroundVertexCirculator circ_end = circ;
211 if (circ.getTargetIndex ().isValid ())
213 delete_faces_vertex_.push_back (circ.getTargetIndex ());
215 }
while (++circ!=circ_end);
217 for (FaceIndices::const_iterator it = delete_faces_vertex_.begin (); it!=delete_faces_vertex_.end (); ++it)
219 this->deleteFace (*it);
227 deleteEdge (
const HalfEdgeIndex& idx_he)
229 assert (this->isValid (idx_he));
230 if (this->isDeleted (idx_he))
return;
232 HalfEdgeIndex opposite = this->getOppositeHalfEdgeIndex (idx_he);
234 if (this->isBoundary (idx_he)) this->markDeleted (idx_he);
235 else this->deleteFace (this->getFaceIndex (idx_he));
236 if (this->isBoundary (opposite)) this->markDeleted (opposite);
237 else this->deleteFace (this->getFaceIndex (opposite));
244 deleteEdge (
const EdgeIndex& idx_edge)
246 assert (this->isValid (idx_edge));
255 deleteFace (
const FaceIndex& idx_face)
257 assert (this->isValid (idx_face));
258 if (this->isDeleted (idx_face))
return;
270 const VertexIndices new_vertex_indices =
271 this->remove <Vertices, VertexDataCloud, VertexIndices, HasVertexData>
272 (vertices_, vertex_data_cloud_);
273 const HalfEdgeIndices new_half_edge_indices =
274 this->remove <HalfEdges, HalfEdgeDataCloud, HalfEdgeIndices, HasHalfEdgeData>
275 (half_edges_, half_edge_data_cloud_);
276 const FaceIndices new_face_indices =
277 this->remove <Faces, FaceDataCloud, FaceIndices, HasFaceData>
278 (faces_, face_data_cloud_);
281 if (HasEdgeData::value)
283 auto it_ed_old = edge_data_cloud_.begin ();
284 auto it_ed_new = edge_data_cloud_.begin ();
286 for (
auto it_ind = new_half_edge_indices.cbegin (), it_ind_end = new_half_edge_indices.cend (); it_ind!=it_ind_end; it_ind+=2, ++it_ed_old)
288 if (it_ind->isValid ())
290 *it_ed_new++ = *it_ed_old;
293 edge_data_cloud_.resize (this->sizeEdges ());
297 for (VertexIterator it = vertices_.begin (); it!=vertices_.end (); ++it)
299 if (it->idx_outgoing_half_edge_.isValid ())
301 it->idx_outgoing_half_edge_ = new_half_edge_indices [it->idx_outgoing_half_edge_.get ()];
305 for (HalfEdgeIterator it = half_edges_.begin (); it!=half_edges_.end (); ++it)
307 it->idx_terminating_vertex_ = new_vertex_indices [it->idx_terminating_vertex_.get ()];
308 it->idx_next_half_edge_ = new_half_edge_indices [it->idx_next_half_edge_.get ()];
309 it->idx_prev_half_edge_ = new_half_edge_indices [it->idx_prev_half_edge_.get ()];
310 if (it->idx_face_.isValid ())
312 it->idx_face_ = new_face_indices [it->idx_face_.get ()];
316 for (FaceIterator it = faces_.begin (); it!=faces_.end (); ++it)
318 it->idx_inner_half_edge_ = new_half_edge_indices [it->idx_inner_half_edge_.get ()];
328 getOutgoingHalfEdgeIndex (
const VertexIndex& idx_vertex)
const
330 assert (this->isValid (idx_vertex));
331 return (this->getVertex (idx_vertex).idx_outgoing_half_edge_);
336 getIncomingHalfEdgeIndex (
const VertexIndex& idx_vertex)
const
338 assert (this->isValid (idx_vertex));
339 return (this->getOppositeHalfEdgeIndex (this->getOutgoingHalfEdgeIndex (idx_vertex)));
348 getTerminatingVertexIndex (
const HalfEdgeIndex& idx_half_edge)
const
350 assert (this->isValid (idx_half_edge));
351 return (this->getHalfEdge (idx_half_edge).idx_terminating_vertex_);
356 getOriginatingVertexIndex (
const HalfEdgeIndex& idx_half_edge)
const
358 assert (this->isValid (idx_half_edge));
359 return (this->getTerminatingVertexIndex (this->getOppositeHalfEdgeIndex (idx_half_edge)));
364 getOppositeHalfEdgeIndex (
const HalfEdgeIndex& idx_half_edge)
const
366 assert (this->isValid (idx_half_edge));
368 return (HalfEdgeIndex (idx_half_edge.get () & 1 ? idx_half_edge.get () - 1 : idx_half_edge.get () + 1));
373 getNextHalfEdgeIndex (
const HalfEdgeIndex& idx_half_edge)
const
375 assert (this->isValid (idx_half_edge));
376 return (this->getHalfEdge (idx_half_edge).idx_next_half_edge_);
381 getPrevHalfEdgeIndex (
const HalfEdgeIndex& idx_half_edge)
const
383 assert (this->isValid (idx_half_edge));
384 return (this->getHalfEdge (idx_half_edge).idx_prev_half_edge_);
389 getFaceIndex (
const HalfEdgeIndex& idx_half_edge)
const
391 assert (this->isValid (idx_half_edge));
392 return (this->getHalfEdge (idx_half_edge).idx_face_);
397 getOppositeFaceIndex (
const HalfEdgeIndex& idx_half_edge)
const
399 assert (this->isValid (idx_half_edge));
400 return (this->getFaceIndex (this->getOppositeHalfEdgeIndex (idx_half_edge)));
409 getInnerHalfEdgeIndex (
const FaceIndex& idx_face)
const
411 assert (this->isValid (idx_face));
412 return (this->getFace (idx_face).idx_inner_half_edge_);
417 getOuterHalfEdgeIndex (
const FaceIndex& idx_face)
const
419 assert (this->isValid (idx_face));
420 return (this->getOppositeHalfEdgeIndex (this->getInnerHalfEdgeIndex (idx_face)));
428 inline VertexAroundVertexCirculator
429 getVertexAroundVertexCirculator (
const VertexIndex& idx_vertex)
const
431 assert (this->isValid (idx_vertex));
432 return (VertexAroundVertexCirculator (idx_vertex,
this));
436 inline VertexAroundVertexCirculator
437 getVertexAroundVertexCirculator (
const HalfEdgeIndex& idx_outgoing_half_edge)
const
439 assert (this->isValid (idx_outgoing_half_edge));
440 return (VertexAroundVertexCirculator (idx_outgoing_half_edge,
this));
444 inline OutgoingHalfEdgeAroundVertexCirculator
445 getOutgoingHalfEdgeAroundVertexCirculator (
const VertexIndex& idx_vertex)
const
447 assert (this->isValid (idx_vertex));
448 return (OutgoingHalfEdgeAroundVertexCirculator (idx_vertex,
this));
452 inline OutgoingHalfEdgeAroundVertexCirculator
453 getOutgoingHalfEdgeAroundVertexCirculator (
const HalfEdgeIndex& idx_outgoing_half_edge)
const
455 assert (this->isValid (idx_outgoing_half_edge));
456 return (OutgoingHalfEdgeAroundVertexCirculator (idx_outgoing_half_edge,
this));
460 inline IncomingHalfEdgeAroundVertexCirculator
461 getIncomingHalfEdgeAroundVertexCirculator (
const VertexIndex& idx_vertex)
const
463 assert (this->isValid (idx_vertex));
464 return (IncomingHalfEdgeAroundVertexCirculator (idx_vertex,
this));
468 inline IncomingHalfEdgeAroundVertexCirculator
469 getIncomingHalfEdgeAroundVertexCirculator (
const HalfEdgeIndex& idx_incoming_half_edge)
const
471 assert (this->isValid (idx_incoming_half_edge));
472 return (IncomingHalfEdgeAroundVertexCirculator (idx_incoming_half_edge,
this));
476 inline FaceAroundVertexCirculator
477 getFaceAroundVertexCirculator (
const VertexIndex& idx_vertex)
const
479 assert (this->isValid (idx_vertex));
480 return (FaceAroundVertexCirculator (idx_vertex,
this));
484 inline FaceAroundVertexCirculator
485 getFaceAroundVertexCirculator (
const HalfEdgeIndex& idx_outgoing_half_edge)
const
487 assert (this->isValid (idx_outgoing_half_edge));
488 return (FaceAroundVertexCirculator (idx_outgoing_half_edge,
this));
492 inline VertexAroundFaceCirculator
493 getVertexAroundFaceCirculator (
const FaceIndex& idx_face)
const
495 assert (this->isValid (idx_face));
496 return (VertexAroundFaceCirculator (idx_face,
this));
500 inline VertexAroundFaceCirculator
501 getVertexAroundFaceCirculator (
const HalfEdgeIndex& idx_inner_half_edge)
const
503 assert (this->isValid (idx_inner_half_edge));
504 return (VertexAroundFaceCirculator (idx_inner_half_edge,
this));
508 inline InnerHalfEdgeAroundFaceCirculator
509 getInnerHalfEdgeAroundFaceCirculator (
const FaceIndex& idx_face)
const
511 assert (this->isValid (idx_face));
512 return (InnerHalfEdgeAroundFaceCirculator (idx_face,
this));
516 inline InnerHalfEdgeAroundFaceCirculator
517 getInnerHalfEdgeAroundFaceCirculator (
const HalfEdgeIndex& idx_inner_half_edge)
const
519 assert (this->isValid (idx_inner_half_edge));
520 return (InnerHalfEdgeAroundFaceCirculator (idx_inner_half_edge,
this));
524 inline OuterHalfEdgeAroundFaceCirculator
525 getOuterHalfEdgeAroundFaceCirculator (
const FaceIndex& idx_face)
const
527 assert (this->isValid (idx_face));
528 return (OuterHalfEdgeAroundFaceCirculator (idx_face,
this));
532 inline OuterHalfEdgeAroundFaceCirculator
533 getOuterHalfEdgeAroundFaceCirculator (
const HalfEdgeIndex& idx_inner_half_edge)
const
535 assert (this->isValid (idx_inner_half_edge));
536 return (OuterHalfEdgeAroundFaceCirculator (idx_inner_half_edge,
this));
540 inline FaceAroundFaceCirculator
541 getFaceAroundFaceCirculator (
const FaceIndex& idx_face)
const
543 assert (this->isValid (idx_face));
544 return (FaceAroundFaceCirculator (idx_face,
this));
548 inline FaceAroundFaceCirculator
549 getFaceAroundFaceCirculator (
const HalfEdgeIndex& idx_inner_half_edge)
const
551 assert (this->isValid (idx_inner_half_edge));
552 return (FaceAroundFaceCirculator (idx_inner_half_edge,
this));
561 isEqualTopology (
const Self& other)
const
563 if (this->sizeVertices () != other.sizeVertices ())
return (
false);
564 if (this->sizeHalfEdges () != other.sizeHalfEdges ())
return (
false);
565 if (this->sizeFaces () != other.sizeFaces ())
return (
false);
567 for (std::size_t i=0; i<this->sizeVertices (); ++i)
569 if (this->getOutgoingHalfEdgeIndex (VertexIndex (i)) !=
570 other.getOutgoingHalfEdgeIndex (VertexIndex (i)))
return (
false);
573 for (std::size_t i=0; i<this->sizeHalfEdges (); ++i)
575 if (this->getTerminatingVertexIndex (HalfEdgeIndex (i)) !=
576 other.getTerminatingVertexIndex (HalfEdgeIndex (i)))
return (
false);
578 if (this->getNextHalfEdgeIndex (HalfEdgeIndex (i)) !=
579 other.getNextHalfEdgeIndex (HalfEdgeIndex (i)))
return (
false);
581 if (this->getPrevHalfEdgeIndex (HalfEdgeIndex (i)) !=
582 other.getPrevHalfEdgeIndex (HalfEdgeIndex (i)))
return (
false);
584 if (this->getFaceIndex (HalfEdgeIndex (i)) !=
585 other.getFaceIndex (HalfEdgeIndex (i)))
return (
false);
588 for (std::size_t i=0; i<this->sizeFaces (); ++i)
590 if (this->getInnerHalfEdgeIndex (FaceIndex (i)) !=
591 other.getInnerHalfEdgeIndex (FaceIndex (i)))
return (
false);
603 isValid (
const VertexIndex& idx_vertex)
const
605 return (idx_vertex >= VertexIndex (0) && idx_vertex < VertexIndex (
int (vertices_.size ())));
610 isValid (
const HalfEdgeIndex& idx_he)
const
612 return (idx_he >= HalfEdgeIndex (0) && idx_he < HalfEdgeIndex (half_edges_.size ()));
617 isValid (
const EdgeIndex& idx_edge)
const
619 return (idx_edge >= EdgeIndex (0) && idx_edge < EdgeIndex (half_edges_.size () / 2));
624 isValid (
const FaceIndex& idx_face)
const
626 return (idx_face >= FaceIndex (0) && idx_face < FaceIndex (faces_.size ()));
635 isDeleted (
const VertexIndex& idx_vertex)
const
637 assert (this->isValid (idx_vertex));
638 return (!this->getOutgoingHalfEdgeIndex (idx_vertex).isValid ());
643 isDeleted (
const HalfEdgeIndex& idx_he)
const
645 assert (this->isValid (idx_he));
646 return (!this->getTerminatingVertexIndex (idx_he).isValid ());
651 isDeleted (
const EdgeIndex& idx_edge)
const
653 assert (this->isValid (idx_edge));
660 isDeleted (
const FaceIndex& idx_face)
const
662 assert (this->isValid (idx_face));
663 return (!this->getInnerHalfEdgeIndex (idx_face).isValid ());
672 isIsolated (
const VertexIndex& idx_vertex)
const
674 assert (this->isValid (idx_vertex));
675 return (!this->getOutgoingHalfEdgeIndex (idx_vertex).isValid ());
684 isBoundary (
const VertexIndex& idx_vertex)
const
686 assert (this->isValid (idx_vertex));
687 if (this->isIsolated (idx_vertex))
return (
true);
688 return (this->isBoundary (this->getOutgoingHalfEdgeIndex (idx_vertex)));
693 isBoundary (
const HalfEdgeIndex& idx_he)
const
695 assert (this->isValid (idx_he));
696 return (!this->getFaceIndex (idx_he).isValid ());
701 isBoundary (
const EdgeIndex& idx_edge)
const
703 assert (this->isValid (idx_edge));
705 return (this->isBoundary (idx) || this->isBoundary (this->getOppositeHalfEdgeIndex (idx)));
711 template <
bool CheckVerticesT>
inline bool
712 isBoundary (
const FaceIndex& idx_face)
const
714 assert (this->isValid (idx_face));
715 return (this->isBoundary (idx_face, std::integral_constant <bool, CheckVerticesT> ()));
720 isBoundary (
const FaceIndex& idx_face)
const
722 assert (this->isValid (idx_face));
723 return (this->isBoundary (idx_face, std::true_type ()));
732 isManifold (
const VertexIndex& idx_vertex)
const
734 assert (this->isValid (idx_vertex));
735 if (this->isIsolated (idx_vertex))
return (
true);
736 return (this->isManifold (idx_vertex,
IsManifold ()));
752 sizeVertices ()
const
754 return (vertices_.size ());
759 sizeHalfEdges ()
const
761 assert (half_edges_.size () % 2 == 0);
762 return (half_edges_.size ());
769 assert (half_edges_.size () % 2 == 0);
770 return (half_edges_.size () / 2);
777 return (faces_.size ());
788 return (this->emptyVertices () && this->emptyEdges () && this->emptyFaces ());
793 emptyVertices ()
const
795 return (vertices_.empty ());
802 return (half_edges_.empty ());
809 return (faces_.empty ());
818 reserveVertices (
const std::size_t n)
820 vertices_.reserve (n);
821 this->reserveData (vertex_data_cloud_, n, HasVertexData ());
826 reserveEdges (
const std::size_t n)
828 half_edges_.reserve (2*n);
829 this->reserveData (half_edge_data_cloud_, 2*n, HasHalfEdgeData ());
830 this->reserveData (edge_data_cloud_ , n, HasEdgeData ());
835 reserveFaces (
const std::size_t n)
838 this->reserveData (face_data_cloud_, n, HasFaceData ());
849 vertices_.resize (n);
850 this->resizeData (vertex_data_cloud_, n, data, HasVertexData ());
855 resizeEdges (
const std::size_t n,
859 half_edges_.resize (2*n);
860 this->resizeData (half_edge_data_cloud_, 2*n, he_data , HasHalfEdgeData ());
861 this->resizeData (edge_data_cloud_ , n, edge_data, HasEdgeData ());
869 this->resizeData (face_data_cloud_, n, data, HasFaceData ());
881 half_edges_.clear ();
884 this->clearData (vertex_data_cloud_ , HasVertexData ());
885 this->clearData (half_edge_data_cloud_, HasHalfEdgeData ());
886 this->clearData (edge_data_cloud_ , HasEdgeData ());
887 this->clearData (face_data_cloud_ , HasFaceData ());
897 inline VertexDataCloud&
898 getVertexDataCloud ()
900 return (vertex_data_cloud_);
904 inline VertexDataCloud
905 getVertexDataCloud ()
const
907 return (vertex_data_cloud_);
915 setVertexDataCloud (
const VertexDataCloud& vertex_data_cloud)
917 if (vertex_data_cloud.size () == vertex_data_cloud_.size ())
919 vertex_data_cloud_ = vertex_data_cloud;
932 inline HalfEdgeDataCloud&
933 getHalfEdgeDataCloud ()
935 return (half_edge_data_cloud_);
939 inline HalfEdgeDataCloud
940 getHalfEdgeDataCloud ()
const
942 return (half_edge_data_cloud_);
950 setHalfEdgeDataCloud (
const HalfEdgeDataCloud& half_edge_data_cloud)
952 if (half_edge_data_cloud.size () == half_edge_data_cloud_.size ())
954 half_edge_data_cloud_ = half_edge_data_cloud;
967 inline EdgeDataCloud&
970 return (edge_data_cloud_);
975 getEdgeDataCloud ()
const
977 return (edge_data_cloud_);
985 setEdgeDataCloud (
const EdgeDataCloud& edge_data_cloud)
987 if (edge_data_cloud.size () == edge_data_cloud_.size ())
989 edge_data_cloud_ = edge_data_cloud;
1002 inline FaceDataCloud&
1005 return (face_data_cloud_);
1009 inline FaceDataCloud
1010 getFaceDataCloud ()
const
1012 return (face_data_cloud_);
1020 setFaceDataCloud (
const FaceDataCloud& face_data_cloud)
1022 if (face_data_cloud.size () == face_data_cloud_.size ())
1024 face_data_cloud_ = face_data_cloud;
1038 getVertexIndex (
const VertexData& vertex_data)
const
1040 if (HasVertexData::value)
1042 assert (&vertex_data >= &vertex_data_cloud_.front () && &vertex_data <= &vertex_data_cloud_.back ());
1043 return (VertexIndex (std::distance (&vertex_data_cloud_.front (), &vertex_data)));
1045 return (VertexIndex ());
1049 inline HalfEdgeIndex
1050 getHalfEdgeIndex (
const HalfEdgeData& half_edge_data)
const
1052 if (HasHalfEdgeData::value)
1054 assert (&half_edge_data >= &half_edge_data_cloud_.front () && &half_edge_data <= &half_edge_data_cloud_.back ());
1055 return (HalfEdgeIndex (std::distance (&half_edge_data_cloud_.front (), &half_edge_data)));
1057 return (HalfEdgeIndex ());
1062 getEdgeIndex (
const EdgeData& edge_data)
const
1064 if (HasEdgeData::value)
1066 assert (&edge_data >= &edge_data_cloud_.front () && &edge_data <= &edge_data_cloud_.back ());
1067 return (EdgeIndex (std::distance (&edge_data_cloud_.front (), &edge_data)));
1069 return (EdgeIndex ());
1074 getFaceIndex (
const FaceData& face_data)
const
1076 if (HasFaceData::value)
1078 assert (&face_data >= &face_data_cloud_.front () && &face_data <= &face_data_cloud_.back ());
1079 return (FaceIndex (std::distance (&face_data_cloud_.front (), &face_data)));
1081 return (FaceIndex ());
1095 using Vertices = std::vector<Vertex>;
1096 using HalfEdges = std::vector<HalfEdge>;
1097 using Faces = std::vector<Face>;
1099 using VertexIterator =
typename Vertices::iterator;
1100 using HalfEdgeIterator =
typename HalfEdges::iterator;
1101 using FaceIterator =
typename Faces::iterator;
1103 using VertexConstIterator =
typename Vertices::const_iterator;
1104 using HalfEdgeConstIterator =
typename HalfEdges::const_iterator;
1105 using FaceConstIterator =
typename Faces::const_iterator;
1109 addFaceImplBase (
const VertexIndices& vertices,
1114 const int n =
static_cast<int> (vertices.size ());
1115 if (n < 3)
return (FaceIndex ());
1118 inner_he_.resize (n);
1119 free_he_.resize (n);
1121 make_adjacent_.resize (n);
1122 for (
int i=0; i<n; ++i)
1124 if (!this->checkTopology1 (vertices [i], vertices [(i+1)%n], inner_he_ [i], is_new_ [i],
IsManifold ()))
1126 return (FaceIndex ());
1129 for (
int i=0; i<n; ++i)
1132 if (!this->checkTopology2 (inner_he_ [i], inner_he_ [j], is_new_ [i], is_new_ [j], this->isIsolated (vertices [j]), make_adjacent_ [i], free_he_ [i],
IsManifold ()))
1134 return (FaceIndex ());
1139 if (!IsManifold::value)
1141 for (
int i=0; i<n; ++i)
1143 if (make_adjacent_ [i])
1145 this->makeAdjacent (inner_he_ [i], inner_he_ [(i+1)%n], free_he_ [i]);
1151 for (
int i=0; i<n; ++i)
1155 inner_he_ [i] = this->addEdge (vertices [i], vertices [(i+1)%n], half_edge_data, edge_data);
1160 for (
int i=0; i<n; ++i)
1163 if ( is_new_ [i] && is_new_ [j]) this->connectNewNew (inner_he_ [i], inner_he_ [j], vertices [j],
IsManifold ());
1164 else if ( is_new_ [i] && !is_new_ [j]) this->connectNewOld (inner_he_ [i], inner_he_ [j], vertices [j]);
1165 else if (!is_new_ [i] && is_new_ [j]) this->connectOldNew (inner_he_ [i], inner_he_ [j], vertices [j]);
1166 else this->connectOldOld (inner_he_ [i], inner_he_ [j], vertices [j],
IsManifold ());
1168 return (this->connectFace (inner_he_, face_data));
1183 addEdge (
const VertexIndex& idx_v_a,
1184 const VertexIndex& idx_v_b,
1188 half_edges_.push_back (HalfEdge (idx_v_b));
1189 half_edges_.push_back (HalfEdge (idx_v_a));
1191 this->addData (half_edge_data_cloud_, he_data , HasHalfEdgeData ());
1192 this->addData (half_edge_data_cloud_, he_data , HasHalfEdgeData ());
1193 this->addData (edge_data_cloud_ , edge_data, HasEdgeData ());
1195 return (HalfEdgeIndex (static_cast <int> (half_edges_.size () - 2)));
1210 checkTopology1 (
const VertexIndex& idx_v_a,
1211 const VertexIndex& idx_v_b,
1212 HalfEdgeIndex& idx_he_ab,
1213 std::vector <bool>::reference is_new_ab,
1214 std::true_type )
const
1217 if (this->isIsolated (idx_v_a))
return (
true);
1219 idx_he_ab = this->getOutgoingHalfEdgeIndex (idx_v_a);
1221 if (!this->isBoundary (idx_he_ab))
return (
false);
1222 if (this->getTerminatingVertexIndex (idx_he_ab) == idx_v_b) is_new_ab =
false;
1228 checkTopology1 (
const VertexIndex& idx_v_a,
1229 const VertexIndex& idx_v_b,
1230 HalfEdgeIndex& idx_he_ab,
1231 std::vector <bool>::reference is_new_ab,
1232 std::false_type )
const
1235 if (this->isIsolated (idx_v_a))
return (
true);
1236 if (!this->isBoundary (this->getOutgoingHalfEdgeIndex (idx_v_a)))
return (
false);
1238 VertexAroundVertexCirculator circ = this->getVertexAroundVertexCirculator (this->getOutgoingHalfEdgeIndex (idx_v_a));
1239 const VertexAroundVertexCirculator circ_end = circ;
1243 if (circ.getTargetIndex () == idx_v_b)
1245 idx_he_ab = circ.getCurrentHalfEdgeIndex ();
1246 if (!this->isBoundary (idx_he_ab))
return (
false);
1251 }
while (++circ!=circ_end);
1258 checkTopology2 (
const HalfEdgeIndex& ,
1259 const HalfEdgeIndex& ,
1260 const bool is_new_ab,
1261 const bool is_new_bc,
1262 const bool is_isolated_b,
1263 std::vector <bool>::reference ,
1265 std::true_type )
const
1267 return !(is_new_ab && is_new_bc && !is_isolated_b);
1280 checkTopology2 (
const HalfEdgeIndex& idx_he_ab,
1281 const HalfEdgeIndex& idx_he_bc,
1282 const bool is_new_ab,
1283 const bool is_new_bc,
1285 std::vector <bool>::reference make_adjacent_ab_bc,
1286 HalfEdgeIndex& idx_free_half_edge,
1287 std::false_type )
const
1289 if (is_new_ab || is_new_bc)
1291 make_adjacent_ab_bc =
false;
1295 if (this->getNextHalfEdgeIndex (idx_he_ab) == idx_he_bc)
1297 make_adjacent_ab_bc =
false;
1301 make_adjacent_ab_bc =
true;
1304 IncomingHalfEdgeAroundVertexCirculator circ = this->getIncomingHalfEdgeAroundVertexCirculator (this->getOppositeHalfEdgeIndex (idx_he_bc));
1306 do ++circ;
while (!this->isBoundary (circ.getTargetIndex ()));
1307 idx_free_half_edge = circ.getTargetIndex ();
1310 return (circ.getTargetIndex () != idx_he_ab);
1319 makeAdjacent (
const HalfEdgeIndex& idx_he_ab,
1320 const HalfEdgeIndex& idx_he_bc,
1321 HalfEdgeIndex& idx_free_half_edge)
1324 const HalfEdgeIndex idx_he_ab_next = this->getNextHalfEdgeIndex (idx_he_ab);
1325 const HalfEdgeIndex idx_he_bc_prev = this->getPrevHalfEdgeIndex (idx_he_bc);
1326 const HalfEdgeIndex idx_he_free_next = this->getNextHalfEdgeIndex (idx_free_half_edge);
1328 this->connectPrevNext (idx_he_ab, idx_he_bc);
1329 this->connectPrevNext (idx_free_half_edge, idx_he_ab_next);
1330 this->connectPrevNext (idx_he_bc_prev, idx_he_free_next);
1343 connectFace (
const HalfEdgeIndices& inner_he,
1346 faces_.push_back (Face (inner_he.back ()));
1347 this->addData (face_data_cloud_, face_data, HasFaceData ());
1349 const FaceIndex idx_face (static_cast <int> (this->sizeFaces () - 1));
1351 for (
const auto &idx_half_edge : inner_he)
1353 this->setFaceIndex (idx_half_edge, idx_face);
1361 connectPrevNext (
const HalfEdgeIndex& idx_he_ab,
1362 const HalfEdgeIndex& idx_he_bc)
1364 this->setNextHalfEdgeIndex (idx_he_ab, idx_he_bc);
1365 this->setPrevHalfEdgeIndex (idx_he_bc, idx_he_ab);
1370 connectNewNew (
const HalfEdgeIndex& idx_he_ab,
1371 const HalfEdgeIndex& idx_he_bc,
1372 const VertexIndex& idx_v_b,
1375 const HalfEdgeIndex idx_he_ba = this->getOppositeHalfEdgeIndex (idx_he_ab);
1376 const HalfEdgeIndex idx_he_cb = this->getOppositeHalfEdgeIndex (idx_he_bc);
1378 this->connectPrevNext (idx_he_ab, idx_he_bc);
1379 this->connectPrevNext (idx_he_cb, idx_he_ba);
1381 this->setOutgoingHalfEdgeIndex (idx_v_b, idx_he_ba);
1386 connectNewNew (
const HalfEdgeIndex& idx_he_ab,
1387 const HalfEdgeIndex& idx_he_bc,
1388 const VertexIndex& idx_v_b,
1391 if (this->isIsolated (idx_v_b))
1393 this->connectNewNew (idx_he_ab, idx_he_bc, idx_v_b, std::true_type ());
1397 const HalfEdgeIndex idx_he_ba = this->getOppositeHalfEdgeIndex (idx_he_ab);
1398 const HalfEdgeIndex idx_he_cb = this->getOppositeHalfEdgeIndex (idx_he_bc);
1401 const HalfEdgeIndex idx_he_b_out = this->getOutgoingHalfEdgeIndex (idx_v_b);
1402 const HalfEdgeIndex idx_he_b_out_prev = this->getPrevHalfEdgeIndex (idx_he_b_out);
1404 this->connectPrevNext (idx_he_ab, idx_he_bc);
1405 this->connectPrevNext (idx_he_cb, idx_he_b_out);
1406 this->connectPrevNext (idx_he_b_out_prev, idx_he_ba);
1412 connectNewOld (
const HalfEdgeIndex& idx_he_ab,
1413 const HalfEdgeIndex& idx_he_bc,
1414 const VertexIndex& idx_v_b)
1416 const HalfEdgeIndex idx_he_ba = this->getOppositeHalfEdgeIndex (idx_he_ab);
1417 const HalfEdgeIndex idx_he_bc_prev = this->getPrevHalfEdgeIndex (idx_he_bc);
1419 this->connectPrevNext (idx_he_ab, idx_he_bc);
1420 this->connectPrevNext (idx_he_bc_prev, idx_he_ba);
1422 this->setOutgoingHalfEdgeIndex (idx_v_b, idx_he_ba);
1427 connectOldNew (
const HalfEdgeIndex& idx_he_ab,
1428 const HalfEdgeIndex& idx_he_bc,
1429 const VertexIndex& idx_v_b)
1431 const HalfEdgeIndex idx_he_cb = this->getOppositeHalfEdgeIndex (idx_he_bc);
1432 const HalfEdgeIndex idx_he_ab_next = this->getNextHalfEdgeIndex (idx_he_ab);
1434 this->connectPrevNext (idx_he_ab, idx_he_bc);
1435 this->connectPrevNext (idx_he_cb, idx_he_ab_next);
1437 this->setOutgoingHalfEdgeIndex (idx_v_b, idx_he_ab_next);
1442 connectOldOld (
const HalfEdgeIndex& ,
1443 const HalfEdgeIndex& ,
1444 const VertexIndex& ,
1451 connectOldOld (
const HalfEdgeIndex& ,
1452 const HalfEdgeIndex& idx_he_bc,
1453 const VertexIndex& idx_v_b,
1456 const HalfEdgeIndex& idx_he_b_out = this->getOutgoingHalfEdgeIndex (idx_v_b);
1459 if (idx_he_b_out == idx_he_bc)
1461 OutgoingHalfEdgeAroundVertexCirculator circ = this->getOutgoingHalfEdgeAroundVertexCirculator (idx_he_b_out);
1462 const OutgoingHalfEdgeAroundVertexCirculator circ_end = circ;
1464 while (++circ!=circ_end)
1466 if (this->isBoundary (circ.getTargetIndex ()))
1468 this->setOutgoingHalfEdgeIndex (idx_v_b, circ.getTargetIndex ());
1480 template <
class DataT>
1488 template <
class DataT>
1500 deleteFace (
const FaceIndex& idx_face,
1503 assert (this->isValid (idx_face));
1504 delete_faces_face_.clear ();
1505 delete_faces_face_.push_back (idx_face);
1507 while (!delete_faces_face_.empty ())
1509 const FaceIndex idx_face_cur = delete_faces_face_.back ();
1510 delete_faces_face_.pop_back ();
1513 this->deleteFace (idx_face_cur, std::false_type ());
1519 deleteFace (
const FaceIndex& idx_face,
1522 assert (this->isValid (idx_face));
1523 if (this->isDeleted (idx_face))
return;
1527 is_boundary_.clear ();
1528 InnerHalfEdgeAroundFaceCirculator circ = this->getInnerHalfEdgeAroundFaceCirculator (idx_face);
1529 const InnerHalfEdgeAroundFaceCirculator circ_end = circ;
1532 inner_he_.push_back (circ.getTargetIndex ());
1533 is_boundary_.push_back (this->isBoundary (this->getOppositeHalfEdgeIndex (circ.getTargetIndex ())));
1534 }
while (++circ != circ_end);
1535 assert (inner_he_.size () >= 3);
1537 const int n = static_cast <
int> (inner_he_.size ());
1540 if (IsManifold::value)
1542 for (
int i=0; i<n; ++i)
1545 this->reconnect (inner_he_ [i], inner_he_ [j], is_boundary_ [i], is_boundary_ [j]);
1547 for (
int i=0; i<n; ++i)
1549 this->getHalfEdge (inner_he_ [i]).idx_face_.invalidate ();
1554 for (
int i=0; i<n; ++i)
1557 this->reconnect (inner_he_ [i], inner_he_ [j], is_boundary_ [i], is_boundary_ [j]);
1558 this->getHalfEdge (inner_he_ [i]).idx_face_.invalidate ();
1562 this->markDeleted (idx_face);
1571 reconnect (
const HalfEdgeIndex& idx_he_ab,
1572 const HalfEdgeIndex& idx_he_bc,
1573 const bool is_boundary_ba,
1574 const bool is_boundary_cb)
1576 const HalfEdgeIndex idx_he_ba = this->getOppositeHalfEdgeIndex (idx_he_ab);
1577 const HalfEdgeIndex idx_he_cb = this->getOppositeHalfEdgeIndex (idx_he_bc);
1578 const VertexIndex idx_v_b = this->getTerminatingVertexIndex (idx_he_ab);
1580 if (is_boundary_ba && is_boundary_cb)
1582 const HalfEdgeIndex& idx_he_cb_next = this->getNextHalfEdgeIndex (idx_he_cb);
1584 if (idx_he_cb_next == idx_he_ba)
1586 this->markDeleted (idx_v_b);
1590 this->connectPrevNext (this->getPrevHalfEdgeIndex (idx_he_ba), idx_he_cb_next);
1591 this->setOutgoingHalfEdgeIndex (idx_v_b, idx_he_cb_next);
1594 this->markDeleted (idx_he_ab);
1595 this->markDeleted (idx_he_ba);
1597 else if (is_boundary_ba && !is_boundary_cb)
1599 this->connectPrevNext (this->getPrevHalfEdgeIndex (idx_he_ba), idx_he_bc);
1600 this->setOutgoingHalfEdgeIndex (idx_v_b, idx_he_bc);
1602 this->markDeleted (idx_he_ab);
1603 this->markDeleted (idx_he_ba);
1605 else if (!is_boundary_ba && is_boundary_cb)
1607 const HalfEdgeIndex& idx_he_cb_next = this->getNextHalfEdgeIndex (idx_he_cb);
1608 this->connectPrevNext (idx_he_ab, idx_he_cb_next);
1609 this->setOutgoingHalfEdgeIndex (idx_v_b, idx_he_cb_next);
1613 this->reconnectNBNB (idx_he_bc, idx_he_cb, idx_v_b,
IsManifold ());
1619 reconnectNBNB (
const HalfEdgeIndex& idx_he_bc,
1620 const HalfEdgeIndex& idx_he_cb,
1621 const VertexIndex& idx_v_b,
1624 if (this->isBoundary (idx_v_b))
1628 IncomingHalfEdgeAroundVertexCirculator circ = this->getIncomingHalfEdgeAroundVertexCirculator (idx_he_cb);
1630 while (!this->isBoundary (circ.getTargetIndex ()))
1632 delete_faces_face_.push_back (this->getFaceIndex ((circ++).getTargetIndex ()));
1634 #ifdef PCL_GEOMETRY_MESH_BASE_TEST_DELETE_FACE_MANIFOLD_2
1635 if (circ == this->getIncomingHalfEdgeAroundVertexCirculator (idx_he_cb))
1641 pcl::geometry::g_pcl_geometry_mesh_base_test_delete_face_manifold_2_success =
false;
1649 this->setOutgoingHalfEdgeIndex (idx_v_b, idx_he_bc);
1655 reconnectNBNB (
const HalfEdgeIndex& idx_he_bc,
1656 const HalfEdgeIndex& ,
1657 const VertexIndex& idx_v_b,
1660 if (!this->isBoundary (idx_v_b))
1662 this->setOutgoingHalfEdgeIndex (idx_v_b, idx_he_bc);
1672 markDeleted (
const VertexIndex& idx_vertex)
1674 assert (this->isValid (idx_vertex));
1675 this->getVertex (idx_vertex).idx_outgoing_half_edge_.invalidate ();
1680 markDeleted (
const HalfEdgeIndex& idx_he)
1682 assert (this->isValid (idx_he));
1683 this->getHalfEdge (idx_he).idx_terminating_vertex_.invalidate ();
1688 markDeleted (
const EdgeIndex& idx_edge)
1690 assert (this->isValid (idx_edge));
1697 markDeleted (
const FaceIndex& idx_face)
1699 assert (this->isValid (idx_face));
1700 this->getFace (idx_face).idx_inner_half_edge_.invalidate ();
1717 template <
class ElementContainerT,
class DataContainerT,
class IndexContainerT,
class HasDataT> IndexContainerT
1718 remove (ElementContainerT& elements, DataContainerT& data_cloud)
1720 using Index =
typename IndexContainerT::value_type;
1721 using Element =
typename ElementContainerT::value_type;
1723 if (HasDataT::value) assert (elements.size () == data_cloud.size ());
1724 else assert (data_cloud.empty ());
1726 IndexContainerT new_indices (elements.size (),
typename IndexContainerT::value_type ());
1727 Index ind_old (0), ind_new (0);
1729 typename ElementContainerT::const_iterator it_e_old = elements.begin ();
1730 typename ElementContainerT::iterator it_e_new = elements.begin ();
1732 typename DataContainerT::const_iterator it_d_old = data_cloud.begin ();
1733 typename DataContainerT::iterator it_d_new = data_cloud.begin ();
1735 typename IndexContainerT::iterator it_ind_new = new_indices.begin ();
1736 typename IndexContainerT::const_iterator it_ind_new_end = new_indices.end ();
1738 while (it_ind_new!=it_ind_new_end)
1740 if (!this->isDeleted (ind_old))
1742 *it_ind_new = ind_new++;
1745 *it_e_new++ = *it_e_old;
1746 this->assignIf (it_d_old, it_d_new, HasDataT ());
1747 this->incrementIf ( it_d_new, HasDataT ());
1751 this->incrementIf (it_d_old, HasDataT ());
1755 elements.resize (ind_new.get (), Element ());
1756 if (HasDataT::value)
1758 data_cloud.resize (ind_new.get ());
1760 else if (it_d_old != data_cloud.begin () || it_d_new != data_cloud.begin ())
1762 std::cerr <<
"TODO: Bug in MeshBase::remove!\n";
1764 exit (EXIT_FAILURE);
1767 return (new_indices);
1771 template <
class IteratorT>
inline void
1772 incrementIf (IteratorT& it, std::true_type )
const
1778 template <
class IteratorT>
inline void
1779 incrementIf (IteratorT& , std::false_type )
const
1784 template <
class ConstIteratorT,
class IteratorT>
inline void
1785 assignIf (
const ConstIteratorT source, IteratorT target, std::true_type )
const
1791 template <
class ConstIteratorT,
class IteratorT>
inline void
1792 assignIf (
const ConstIteratorT , IteratorT , std::false_type )
const
1802 setOutgoingHalfEdgeIndex (
const VertexIndex& idx_vertex,
const HalfEdgeIndex& idx_outgoing_half_edge)
1804 assert (this->isValid (idx_vertex));
1805 this->getVertex (idx_vertex).idx_outgoing_half_edge_ = idx_outgoing_half_edge;
1810 setTerminatingVertexIndex (
const HalfEdgeIndex& idx_half_edge,
const VertexIndex& idx_terminating_vertex)
1812 assert (this->isValid (idx_half_edge));
1813 this->getHalfEdge (idx_half_edge).idx_terminating_vertex_ = idx_terminating_vertex;
1818 setNextHalfEdgeIndex (
const HalfEdgeIndex& idx_half_edge,
const HalfEdgeIndex& idx_next_half_edge)
1820 assert (this->isValid (idx_half_edge));
1821 this->getHalfEdge (idx_half_edge).idx_next_half_edge_ = idx_next_half_edge;
1826 setPrevHalfEdgeIndex (
const HalfEdgeIndex& idx_half_edge,
1827 const HalfEdgeIndex& idx_prev_half_edge)
1829 assert (this->isValid (idx_half_edge));
1830 this->getHalfEdge (idx_half_edge).idx_prev_half_edge_ = idx_prev_half_edge;
1835 setFaceIndex (
const HalfEdgeIndex& idx_half_edge,
const FaceIndex& idx_face)
1837 assert (this->isValid (idx_half_edge));
1838 this->getHalfEdge (idx_half_edge).idx_face_ = idx_face;
1843 setInnerHalfEdgeIndex (
const FaceIndex& idx_face,
const HalfEdgeIndex& idx_inner_half_edge)
1845 assert (this->isValid (idx_face));
1846 this->getFace (idx_face).idx_inner_half_edge_ = idx_inner_half_edge;
1855 isBoundary (
const FaceIndex& idx_face, std::true_type )
const
1857 VertexAroundFaceCirculator circ = this->getVertexAroundFaceCirculator (idx_face);
1858 const VertexAroundFaceCirculator circ_end = circ;
1862 if (this->isBoundary (circ.getTargetIndex ()))
1866 }
while (++circ!=circ_end);
1873 isBoundary (
const FaceIndex& idx_face, std::false_type )
const
1875 OuterHalfEdgeAroundFaceCirculator circ = this->getOuterHalfEdgeAroundFaceCirculator (idx_face);
1876 const OuterHalfEdgeAroundFaceCirculator circ_end = circ;
1880 if (this->isBoundary (circ.getTargetIndex ()))
1884 }
while (++circ!=circ_end);
1891 isManifold (
const VertexIndex&, std::true_type )
const
1898 isManifold (
const VertexIndex& idx_vertex, std::false_type )
const
1900 OutgoingHalfEdgeAroundVertexCirculator circ = this->getOutgoingHalfEdgeAroundVertexCirculator (idx_vertex);
1901 const OutgoingHalfEdgeAroundVertexCirculator circ_end = circ;
1903 if (!this->isBoundary ((circ++).getTargetIndex ()))
return (
true);
1906 if (this->isBoundary (circ.getTargetIndex ()))
return (
false);
1907 }
while (++circ != circ_end);
1914 isManifold (std::true_type )
const
1921 isManifold (std::false_type )
const
1923 for (std::size_t i=0; i<this->sizeVertices (); ++i)
1925 if (!this->isManifold (VertexIndex (i)))
return (
false);
1935 template <
class DataCloudT>
inline void
1936 reserveData (DataCloudT& cloud,
const std::size_t n, std::true_type )
const
1942 template <
class DataCloudT>
inline void
1943 reserveData (DataCloudT& ,
const std::size_t , std::false_type )
const
1948 template <
class DataCloudT>
inline void
1949 resizeData (DataCloudT& ,
const std::size_t n,
const typename DataCloudT::value_type& data, std::true_type )
const
1951 data.resize (n, data);
1955 template <
class DataCloudT>
inline void
1956 resizeData (DataCloudT& ,
const std::size_t ,
const typename DataCloudT::value_type& , std::false_type )
const
1961 template <
class DataCloudT>
inline void
1962 clearData (DataCloudT& cloud, std::true_type )
const
1968 template <
class DataCloudT>
inline void
1969 clearData (DataCloudT& , std::false_type )
const
1979 getVertex (
const VertexIndex& idx_vertex)
1981 assert (this->isValid (idx_vertex));
1982 return (vertices_ [idx_vertex.get ()]);
1987 getVertex (
const VertexIndex& idx_vertex)
const
1989 assert (this->isValid (idx_vertex));
1990 return (vertices_ [idx_vertex.get ()]);
1995 setVertex (
const VertexIndex& idx_vertex,
const Vertex& vertex)
1997 assert (this->isValid (idx_vertex));
1998 vertices_ [idx_vertex.get ()] = vertex;
2007 getHalfEdge (
const HalfEdgeIndex& idx_he)
2009 assert (this->isValid (idx_he));
2010 return (half_edges_ [idx_he.get ()]);
2015 getHalfEdge (
const HalfEdgeIndex& idx_he)
const
2017 assert (this->isValid (idx_he));
2018 return (half_edges_ [idx_he.get ()]);
2023 setHalfEdge (
const HalfEdgeIndex& idx_he,
const HalfEdge& half_edge)
2025 assert (this->isValid (idx_he));
2026 half_edges_ [idx_he.get ()] = half_edge;
2035 getFace (
const FaceIndex& idx_face)
2037 assert (this->isValid (idx_face));
2038 return (faces_ [idx_face.get ()]);
2043 getFace (
const FaceIndex& idx_face)
const
2045 assert (this->isValid (idx_face));
2046 return (faces_ [idx_face.get ()]);
2051 setFace (
const FaceIndex& idx_face,
const Face& face)
2053 assert (this->isValid (idx_face));
2054 faces_ [idx_face.get ()] = face;
2064 VertexDataCloud vertex_data_cloud_;
2067 HalfEdgeDataCloud half_edge_data_cloud_;
2070 EdgeDataCloud edge_data_cloud_;
2073 FaceDataCloud face_data_cloud_;
2079 HalfEdges half_edges_;
2087 HalfEdgeIndices inner_he_;
2090 HalfEdgeIndices free_he_;
2093 std::vector <bool> is_new_;
2096 std::vector <bool> make_adjacent_;
2099 std::vector <bool> is_boundary_;
2102 FaceIndices delete_faces_vertex_;
2105 FaceIndices delete_faces_face_;
2109 template <
class MeshT>
A vertex is a node in the mesh.
An edge is a connection between two vertices.
typename MeshTraitsT::VertexData VertexData
Circulates clockwise around a face and returns an index to the face of the outer half-edge (the targe...
Circulates counter-clockwise around a vertex and returns an index to the incoming half-edge (the targ...
typename MeshTraitsT::IsManifold IsManifold
#define PCL_MAKE_ALIGNED_OPERATOR_NEW
Macro to signal a class requires a custom allocator.
MeshBase< DerivedT, MeshTraitsT, MeshTagT > Self
Index used to access elements in the half-edge mesh.
typename MeshTraitsT::HalfEdgeData HalfEdgeData
typename MeshTraitsT::FaceData FaceData
pcl::geometry::HalfEdgeIndex toHalfEdgeIndex(const EdgeIndex &index, const bool get_first=true)
Convert the given edge index to a half-edge index.
Half-edge mesh that can only store quads.
Circulates counter-clockwise around a vertex and returns an index to the terminating vertex of the ou...
Index used to access elements in the half-edge mesh.
Index used to access elements in the half-edge mesh.
Circulates clockwise around a face and returns an index to the terminating vertex of the inner half-e...
void push_back(const PointT &pt)
Insert a new point in the cloud, at the end of the container.
Index used to access elements in the half-edge mesh.
Circulates counter-clockwise around a vertex and returns an index to the outgoing half-edge (the targ...
PointCloud represents the base class in PCL for storing collections of 3D points. ...
typename MeshTraitsT::EdgeData EdgeData
shared_ptr< const Self > ConstPtr
A face is a closed loop of edges.
Circulates clockwise around a face and returns an index to the inner half-edge (the target)...
Read / write the half-edge mesh from / to a file.
Circulates clockwise around a face and returns an index to the outer half-edge (the target)...
Circulates counter-clockwise around a vertex and returns an index to the face of the outgoing half-ed...
Base class for the half-edge mesh.