Point Cloud Library (PCL)  1.14.1-dev
mesh_base.h
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  * Copyright (c) 2009-2012, Willow Garage, Inc.
6  * Copyright (c) 2012-, Open Perception, Inc.
7  *
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * * Redistributions of source code must retain the above copyright
15  * notice, this list of conditions and the following disclaimer.
16  * * Redistributions in binary form must reproduce the above
17  * copyright notice, this list of conditions and the following
18  * disclaimer in the documentation and/or other materials provided
19  * with the distribution.
20  * * Neither the name of the copyright holder(s) nor the names of its
21  * contributors may be used to endorse or promote products derived
22  * from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  *
37  * $Id$
38  *
39  */
40 
41 #pragma once
42 
43 #include <pcl/geometry/mesh_circulators.h>
44 #include <pcl/geometry/mesh_elements.h>
45 #include <pcl/geometry/mesh_indices.h>
46 #include <pcl/geometry/mesh_traits.h>
47 #include <pcl/memory.h>
48 #include <pcl/pcl_macros.h>
49 #include <pcl/point_cloud.h>
50 
51 #include <cassert>
52 #include <type_traits>
53 #include <vector>
54 
55 ////////////////////////////////////////////////////////////////////////////////
56 // Global variables used during testing
57 ////////////////////////////////////////////////////////////////////////////////
58 
59 #ifdef PCL_GEOMETRY_MESH_BASE_TEST_DELETE_FACE_MANIFOLD_2
60 namespace pcl {
61 namespace geometry {
62 bool g_pcl_geometry_mesh_base_test_delete_face_manifold_2_success;
63 } // End namespace geometry
64 } // End namespace pcl
65 #endif
66 
67 ////////////////////////////////////////////////////////////////////////////////
68 // Forward declarations
69 ////////////////////////////////////////////////////////////////////////////////
70 
71 namespace pcl {
72 namespace geometry {
73 template <class MeshT>
74 class MeshIO;
75 } // End namespace geometry
76 } // End namespace pcl
77 
78 ////////////////////////////////////////////////////////////////////////////////
79 // MeshBase
80 ////////////////////////////////////////////////////////////////////////////////
81 
82 namespace pcl {
83 namespace geometry {
84 /**
85  * \brief Base class for the half-edge mesh.
86  * \tparam DerivedT Has to implement the method 'addFaceImpl'. Please have a look at
87  * pcl::geometry::TriangleMesh, pcl::geometry::QuadMesh and pcl::geometry::PolygonMesh.
88  * \tparam MeshTraitsT Please have a look at pcl::geometry::DefaultMeshTraits.
89  * \tparam MeshTagT Tag describing the type of the mesh, e.g. TriangleMeshTag,
90  * QuadMeshTag, PolygonMeshTag.
91  * \author Martin Saelzle
92  * \ingroup geometry
93  * \todo Add documentation
94  */
95 template <class DerivedT, class MeshTraitsT, class MeshTagT>
96 class MeshBase {
97 public:
99  using Ptr = shared_ptr<Self>;
100  using ConstPtr = shared_ptr<const Self>;
101 
102  using Derived = DerivedT;
103 
104  // These have to be defined in the traits class.
105  using VertexData = typename MeshTraitsT::VertexData;
106  using HalfEdgeData = typename MeshTraitsT::HalfEdgeData;
107  using EdgeData = typename MeshTraitsT::EdgeData;
108  using FaceData = typename MeshTraitsT::FaceData;
109  using IsManifold = typename MeshTraitsT::IsManifold;
110 
111  // Check if the mesh traits are defined correctly.
112  static_assert(std::is_convertible<IsManifold, bool>::value,
113  "MeshTraitsT::IsManifold is not convertible to bool");
114 
115  using MeshTag = MeshTagT;
116 
117  // Data
119  std::integral_constant<bool,
120  !std::is_same<VertexData, pcl::geometry::NoData>::value>;
122  std::integral_constant<bool,
123  !std::is_same<HalfEdgeData, pcl::geometry::NoData>::value>;
124  using HasEdgeData =
125  std::integral_constant<bool,
126  !std::is_same<EdgeData, pcl::geometry::NoData>::value>;
127  using HasFaceData =
128  std::integral_constant<bool,
129  !std::is_same<FaceData, pcl::geometry::NoData>::value>;
130 
135 
136  // Indices
141 
142  using VertexIndices = std::vector<VertexIndex>;
143  using HalfEdgeIndices = std::vector<HalfEdgeIndex>;
144  using EdgeIndices = std::vector<EdgeIndex>;
145  using FaceIndices = std::vector<FaceIndex>;
146 
147  // Circulators
163 
164  /** \brief Constructor. */
166  : vertex_data_cloud_()
167  , half_edge_data_cloud_()
168  , edge_data_cloud_()
169  , face_data_cloud_()
170  {}
171 
172  ////////////////////////////////////////////////////////////////////////
173  // addVertex / addFace / deleteVertex / deleteEdge / deleteFace / cleanUp
174  ////////////////////////////////////////////////////////////////////////
175 
176  /**
177  * \brief Add a vertex to the mesh.
178  * \param[in] vertex_data Data that is stored in the vertex. This is only added if the
179  * mesh has data associated with the vertices.
180  * \return Index to the new vertex.
181  */
182  inline VertexIndex
183  addVertex(const VertexData& vertex_data = VertexData())
184  {
185  vertices_.push_back(Vertex());
186  this->addData(vertex_data_cloud_, vertex_data, HasVertexData());
187  return (static_cast<VertexIndex>(this->sizeVertices() - 1));
188  }
189 
190  /**
191  * \brief Add a face to the mesh. Data is only added if it is associated with the
192  * elements. The last vertex is connected with the first one.
193  * \param[in] vertices Indices to the vertices of the new face.
194  * \param[in] face_data Data that is set for the face.
195  * \param[in] half_edge_data Data that is set for all added half-edges.
196  * \param[in] edge_data Data that is set for all added edges.
197  * \return Index to the new face. Failure is signaled by returning an invalid face
198  * index.
199  * \warning The vertices must be valid and unique (each vertex may be contained
200  * only once). Not complying with this requirement results in undefined behavior!
201  */
202  inline FaceIndex
203  addFace(const VertexIndices& vertices,
204  const FaceData& face_data = FaceData(),
205  const EdgeData& edge_data = EdgeData(),
206  const HalfEdgeData& half_edge_data = HalfEdgeData())
207  {
208  // NOTE: The derived class has to implement addFaceImpl. If needed it can use the
209  // general method addFaceImplBase.
210  return (static_cast<Derived*>(this)->addFaceImpl(
211  vertices, face_data, edge_data, half_edge_data));
212  }
213 
214  /**
215  * \brief Mark the given vertex and all connected half-edges and faces as deleted.
216  * \note Call cleanUp () to finally delete all mesh-elements.
217  */
218  void
219  deleteVertex(const VertexIndex& idx_vertex)
220  {
221  assert(this->isValid(idx_vertex));
222  if (this->isDeleted(idx_vertex))
223  return;
224 
225  delete_faces_vertex_.clear();
227  const FaceAroundVertexCirculator circ_end = circ;
228  do {
229  if (circ.getTargetIndex().isValid()) // Check for boundary.
230  {
231  delete_faces_vertex_.push_back(circ.getTargetIndex());
232  }
233  } while (++circ != circ_end);
234 
235  for (const auto& delete_me : delete_faces_vertex_) {
236  this->deleteFace(delete_me);
237  }
238  }
239 
240  /**
241  * \brief Mark the given half-edge, the opposite half-edge and the associated faces
242  * as deleted.
243  * \note Call cleanUp () to finally delete all mesh-elements.
244  */
245  void
246  deleteEdge(const HalfEdgeIndex& idx_he)
247  {
248  assert(this->isValid(idx_he));
249  if (this->isDeleted(idx_he))
250  return;
251 
252  HalfEdgeIndex opposite = this->getOppositeHalfEdgeIndex(idx_he);
253 
254  if (this->isBoundary(idx_he))
255  this->markDeleted(idx_he);
256  else
257  this->deleteFace(this->getFaceIndex(idx_he));
258  if (this->isBoundary(opposite))
259  this->markDeleted(opposite);
260  else
261  this->deleteFace(this->getFaceIndex(opposite));
262  }
263 
264  /**
265  * \brief Mark the given edge (both half-edges) and the associated faces as deleted.
266  * \note Call cleanUp () to finally delete all mesh-elements.
267  */
268  inline void
269  deleteEdge(const EdgeIndex& idx_edge)
270  {
271  assert(this->isValid(idx_edge));
273  assert(this->isDeleted(
274  pcl::geometry::toHalfEdgeIndex(idx_edge, false))); // Bug in this class!
275  }
276 
277  /**
278  * \brief Mark the given face as deleted. More faces are deleted if the manifold mesh
279  * would become non-manifold.
280  * \note Call cleanUp () to finally delete all mesh-elements.
281  */
282  inline void
283  deleteFace(const FaceIndex& idx_face)
284  {
285  assert(this->isValid(idx_face));
286  if (this->isDeleted(idx_face))
287  return;
288 
289  this->deleteFace(idx_face, IsManifold());
290  }
291 
292  /**
293  * \brief Removes all mesh elements and data that are marked as deleted.
294  * \note This removes all isolated vertices as well.
295  */
296  void
298  {
299  // Copy the non-deleted mesh elements and store the index to their new position
300  const VertexIndices new_vertex_indices =
301  this->remove<Vertices, VertexDataCloud, VertexIndices, HasVertexData>(
302  vertices_, vertex_data_cloud_);
303  const HalfEdgeIndices new_half_edge_indices =
304  this->remove<HalfEdges, HalfEdgeDataCloud, HalfEdgeIndices, HasHalfEdgeData>(
305  half_edges_, half_edge_data_cloud_);
306  const FaceIndices new_face_indices =
307  this->remove<Faces, FaceDataCloud, FaceIndices, HasFaceData>(faces_,
308  face_data_cloud_);
309 
310  // Remove deleted edge data
311  if (HasEdgeData::value) {
312  auto it_ed_old = edge_data_cloud_.begin();
313  auto it_ed_new = edge_data_cloud_.begin();
314 
315  for (auto it_ind = new_half_edge_indices.cbegin(),
316  it_ind_end = new_half_edge_indices.cend();
317  it_ind != it_ind_end;
318  it_ind += 2, ++it_ed_old) {
319  if (it_ind->isValid()) {
320  *it_ed_new++ = *it_ed_old;
321  }
322  }
323  edge_data_cloud_.resize(this->sizeEdges());
324  }
325 
326  // Adjust the indices
327  for (auto& vertex : vertices_) {
328  if (vertex.idx_outgoing_half_edge_.isValid()) {
329  vertex.idx_outgoing_half_edge_ =
330  new_half_edge_indices[vertex.idx_outgoing_half_edge_.get()];
331  }
332  }
333 
334  for (auto& half_edge : half_edges_) {
335  half_edge.idx_terminating_vertex_ =
336  new_vertex_indices[half_edge.idx_terminating_vertex_.get()];
337  half_edge.idx_next_half_edge_ =
338  new_half_edge_indices[half_edge.idx_next_half_edge_.get()];
339  half_edge.idx_prev_half_edge_ =
340  new_half_edge_indices[half_edge.idx_prev_half_edge_.get()];
341  if (half_edge.idx_face_.isValid()) {
342  half_edge.idx_face_ = new_face_indices[half_edge.idx_face_.get()];
343  }
344  }
345 
346  for (auto& face : faces_) {
347  face.idx_inner_half_edge_ =
348  new_half_edge_indices[face.idx_inner_half_edge_.get()];
349  }
350  }
351 
352  ////////////////////////////////////////////////////////////////////////
353  // Vertex connectivity
354  ////////////////////////////////////////////////////////////////////////
355 
356  /** \brief Get the outgoing half-edge index to a given vertex. */
357  inline HalfEdgeIndex
358  getOutgoingHalfEdgeIndex(const VertexIndex& idx_vertex) const
359  {
360  assert(this->isValid(idx_vertex));
361  return (this->getVertex(idx_vertex).idx_outgoing_half_edge_);
362  }
363 
364  /** \brief Get the incoming half-edge index to a given vertex. */
365  inline HalfEdgeIndex
366  getIncomingHalfEdgeIndex(const VertexIndex& idx_vertex) const
367  {
368  assert(this->isValid(idx_vertex));
369  return (this->getOppositeHalfEdgeIndex(this->getOutgoingHalfEdgeIndex(idx_vertex)));
370  }
371 
372  ////////////////////////////////////////////////////////////////////////
373  // Half-edge connectivity
374  ////////////////////////////////////////////////////////////////////////
375 
376  /** \brief Get the terminating vertex index to a given half-edge. */
377  inline VertexIndex
378  getTerminatingVertexIndex(const HalfEdgeIndex& idx_half_edge) const
379  {
380  assert(this->isValid(idx_half_edge));
381  return (this->getHalfEdge(idx_half_edge).idx_terminating_vertex_);
382  }
383 
384  /** \brief Get the originating vertex index to a given half-edge. */
385  inline VertexIndex
386  getOriginatingVertexIndex(const HalfEdgeIndex& idx_half_edge) const
387  {
388  assert(this->isValid(idx_half_edge));
389  return (
390  this->getTerminatingVertexIndex(this->getOppositeHalfEdgeIndex(idx_half_edge)));
391  }
392 
393  /** \brief Get the opposite half-edge index to a given half-edge. */
394  inline HalfEdgeIndex
395  getOppositeHalfEdgeIndex(const HalfEdgeIndex& idx_half_edge) const
396  {
397  assert(this->isValid(idx_half_edge));
398  // Check if the index is even or odd and return the other index.
399  return (HalfEdgeIndex(idx_half_edge.get() & 1 ? idx_half_edge.get() - 1
400  : idx_half_edge.get() + 1));
401  }
402 
403  /** \brief Get the next half-edge index to a given half-edge. */
404  inline HalfEdgeIndex
405  getNextHalfEdgeIndex(const HalfEdgeIndex& idx_half_edge) const
406  {
407  assert(this->isValid(idx_half_edge));
408  return (this->getHalfEdge(idx_half_edge).idx_next_half_edge_);
409  }
410 
411  /** \brief Get the previous half-edge index to a given half-edge. */
412  inline HalfEdgeIndex
413  getPrevHalfEdgeIndex(const HalfEdgeIndex& idx_half_edge) const
414  {
415  assert(this->isValid(idx_half_edge));
416  return (this->getHalfEdge(idx_half_edge).idx_prev_half_edge_);
417  }
418 
419  /** \brief Get the face index to a given half-edge. */
420  inline FaceIndex
421  getFaceIndex(const HalfEdgeIndex& idx_half_edge) const
422  {
423  assert(this->isValid(idx_half_edge));
424  return (this->getHalfEdge(idx_half_edge).idx_face_);
425  }
426 
427  /** \brief Get the face index to a given half-edge. */
428  inline FaceIndex
429  getOppositeFaceIndex(const HalfEdgeIndex& idx_half_edge) const
430  {
431  assert(this->isValid(idx_half_edge));
432  return (this->getFaceIndex(this->getOppositeHalfEdgeIndex(idx_half_edge)));
433  }
434 
435  ////////////////////////////////////////////////////////////////////////
436  // Face connectivity
437  ////////////////////////////////////////////////////////////////////////
438 
439  /** \brief Get the inner half-edge index to a given face. */
440  inline HalfEdgeIndex
441  getInnerHalfEdgeIndex(const FaceIndex& idx_face) const
442  {
443  assert(this->isValid(idx_face));
444  return (this->getFace(idx_face).idx_inner_half_edge_);
445  }
446 
447  /** \brief Get the outer half-edge inex to a given face. */
448  inline HalfEdgeIndex
449  getOuterHalfEdgeIndex(const FaceIndex& idx_face) const
450  {
451  assert(this->isValid(idx_face));
452  return (this->getOppositeHalfEdgeIndex(this->getInnerHalfEdgeIndex(idx_face)));
453  }
454 
455  ////////////////////////////////////////////////////////////////////////
456  // Circulators
457  ////////////////////////////////////////////////////////////////////////
458 
459  /** \see pcl::geometry::VertexAroundVertexCirculator */
462  {
463  assert(this->isValid(idx_vertex));
464  return (VertexAroundVertexCirculator(idx_vertex, this));
465  }
466 
467  /** \see pcl::geometry::VertexAroundVertexCirculator */
469  getVertexAroundVertexCirculator(const HalfEdgeIndex& idx_outgoing_half_edge) const
470  {
471  assert(this->isValid(idx_outgoing_half_edge));
472  return (VertexAroundVertexCirculator(idx_outgoing_half_edge, this));
473  }
474 
475  /** \see pcl::geometry::OutgoingHalfEdgeAroundVertexCirculator */
478  {
479  assert(this->isValid(idx_vertex));
480  return (OutgoingHalfEdgeAroundVertexCirculator(idx_vertex, this));
481  }
482 
483  /** \see pcl::geometry::OutgoingHalfEdgeAroundVertexCirculator */
486  const HalfEdgeIndex& idx_outgoing_half_edge) const
487  {
488  assert(this->isValid(idx_outgoing_half_edge));
489  return (OutgoingHalfEdgeAroundVertexCirculator(idx_outgoing_half_edge, this));
490  }
491 
492  /** \see pcl::geometry::IncomingHalfEdgeAroundVertexCirculator */
495  {
496  assert(this->isValid(idx_vertex));
497  return (IncomingHalfEdgeAroundVertexCirculator(idx_vertex, this));
498  }
499 
500  /** \see pcl::geometry::IncomingHalfEdgeAroundVertexCirculator */
503  const HalfEdgeIndex& idx_incoming_half_edge) const
504  {
505  assert(this->isValid(idx_incoming_half_edge));
506  return (IncomingHalfEdgeAroundVertexCirculator(idx_incoming_half_edge, this));
507  }
508 
509  /** \see pcl::geometry::FaceAroundVertexCirculator */
512  {
513  assert(this->isValid(idx_vertex));
514  return (FaceAroundVertexCirculator(idx_vertex, this));
515  }
516 
517  /** \see pcl::geometry::FaceAroundVertexCirculator */
519  getFaceAroundVertexCirculator(const HalfEdgeIndex& idx_outgoing_half_edge) const
520  {
521  assert(this->isValid(idx_outgoing_half_edge));
522  return (FaceAroundVertexCirculator(idx_outgoing_half_edge, this));
523  }
524 
525  /** \see pcl::geometry::VertexAroundFaceCirculator */
528  {
529  assert(this->isValid(idx_face));
530  return (VertexAroundFaceCirculator(idx_face, this));
531  }
532 
533  /** \see pcl::geometry::VertexAroundFaceCirculator */
535  getVertexAroundFaceCirculator(const HalfEdgeIndex& idx_inner_half_edge) const
536  {
537  assert(this->isValid(idx_inner_half_edge));
538  return (VertexAroundFaceCirculator(idx_inner_half_edge, this));
539  }
540 
541  /** \see pcl::geometry::InnerHalfEdgeAroundFaceCirculator */
544  {
545  assert(this->isValid(idx_face));
546  return (InnerHalfEdgeAroundFaceCirculator(idx_face, this));
547  }
548 
549  /** \see pcl::geometry::InnerHalfEdgeAroundFaceCirculator */
551  getInnerHalfEdgeAroundFaceCirculator(const HalfEdgeIndex& idx_inner_half_edge) const
552  {
553  assert(this->isValid(idx_inner_half_edge));
554  return (InnerHalfEdgeAroundFaceCirculator(idx_inner_half_edge, this));
555  }
556 
557  /** \see pcl::geometry::OuterHalfEdgeAroundFaceCirculator */
560  {
561  assert(this->isValid(idx_face));
562  return (OuterHalfEdgeAroundFaceCirculator(idx_face, this));
563  }
564 
565  /** \see pcl::geometry::OuterHalfEdgeAroundFaceCirculator */
567  getOuterHalfEdgeAroundFaceCirculator(const HalfEdgeIndex& idx_inner_half_edge) const
568  {
569  assert(this->isValid(idx_inner_half_edge));
570  return (OuterHalfEdgeAroundFaceCirculator(idx_inner_half_edge, this));
571  }
572 
573  /** \see pcl::geometry::FaceAroundFaceCirculator */
575  getFaceAroundFaceCirculator(const FaceIndex& idx_face) const
576  {
577  assert(this->isValid(idx_face));
578  return (FaceAroundFaceCirculator(idx_face, this));
579  }
580 
581  /** \see pcl::geometry::FaceAroundFaceCirculator */
583  getFaceAroundFaceCirculator(const HalfEdgeIndex& idx_inner_half_edge) const
584  {
585  assert(this->isValid(idx_inner_half_edge));
586  return (FaceAroundFaceCirculator(idx_inner_half_edge, this));
587  }
588 
589  //////////////////////////////////////////////////////////////////////////
590  // isEqualTopology
591  //////////////////////////////////////////////////////////////////////////
592 
593  /** \brief Check if the other mesh has the same topology as this mesh. */
594  bool
595  isEqualTopology(const Self& other) const
596  {
597  if (this->sizeVertices() != other.sizeVertices())
598  return (false);
599  if (this->sizeHalfEdges() != other.sizeHalfEdges())
600  return (false);
601  if (this->sizeFaces() != other.sizeFaces())
602  return (false);
603 
604  for (std::size_t i = 0; i < this->sizeVertices(); ++i) {
605  if (this->getOutgoingHalfEdgeIndex(VertexIndex(i)) !=
607  return (false);
608  }
609 
610  for (std::size_t i = 0; i < this->sizeHalfEdges(); ++i) {
613  return (false);
614 
615  if (this->getNextHalfEdgeIndex(HalfEdgeIndex(i)) !=
617  return (false);
618 
619  if (this->getPrevHalfEdgeIndex(HalfEdgeIndex(i)) !=
621  return (false);
622 
623  if (this->getFaceIndex(HalfEdgeIndex(i)) != other.getFaceIndex(HalfEdgeIndex(i)))
624  return (false);
625  }
626 
627  for (std::size_t i = 0; i < this->sizeFaces(); ++i) {
628  if (this->getInnerHalfEdgeIndex(FaceIndex(i)) !=
630  return (false);
631  }
632 
633  return (true);
634  }
635 
636  ////////////////////////////////////////////////////////////////////////
637  // isValid
638  ////////////////////////////////////////////////////////////////////////
639 
640  /** \brief Check if the given vertex index is a valid index into the mesh. */
641  inline bool
642  isValid(const VertexIndex& idx_vertex) const
643  {
644  return (idx_vertex >= static_cast<VertexIndex>(0) &&
645  idx_vertex < static_cast<VertexIndex>(vertices_.size()));
646  }
647 
648  /** \brief Check if the given half-edge index is a valid index into the mesh. */
649  inline bool
650  isValid(const HalfEdgeIndex& idx_he) const
651  {
652  return (idx_he >= static_cast<HalfEdgeIndex>(0) &&
653  idx_he < static_cast<HalfEdgeIndex>(half_edges_.size()));
654  }
655 
656  /** \brief Check if the given edge index is a valid index into the mesh. */
657  inline bool
658  isValid(const EdgeIndex& idx_edge) const
659  {
660  return (idx_edge >= static_cast<EdgeIndex>(0) &&
661  idx_edge < static_cast<EdgeIndex>(half_edges_.size() / 2));
662  }
663 
664  /** \brief Check if the given face index is a valid index into the mesh. */
665  inline bool
666  isValid(const FaceIndex& idx_face) const
667  {
668  return (idx_face >= static_cast<FaceIndex>(0) &&
669  idx_face < static_cast<FaceIndex>(faces_.size()));
670  }
671 
672  ////////////////////////////////////////////////////////////////////////
673  // isDeleted
674  ////////////////////////////////////////////////////////////////////////
675 
676  /** \brief Check if the given vertex is marked as deleted. */
677  inline bool
678  isDeleted(const VertexIndex& idx_vertex) const
679  {
680  assert(this->isValid(idx_vertex));
681  return (!this->getOutgoingHalfEdgeIndex(idx_vertex).isValid());
682  }
683 
684  /** \brief Check if the given half-edge is marked as deleted. */
685  inline bool
686  isDeleted(const HalfEdgeIndex& idx_he) const
687  {
688  assert(this->isValid(idx_he));
689  return (!this->getTerminatingVertexIndex(idx_he).isValid());
690  }
691 
692  /** \brief Check if the given edge (any of the two half-edges) is marked as deleted.
693  */
694  inline bool
695  isDeleted(const EdgeIndex& idx_edge) const
696  {
697  assert(this->isValid(idx_edge));
698  return (this->isDeleted(pcl::geometry::toHalfEdgeIndex(idx_edge, true)) ||
699  this->isDeleted(pcl::geometry::toHalfEdgeIndex(idx_edge, false)));
700  }
701 
702  /** \brief Check if the given face is marked as deleted. */
703  inline bool
704  isDeleted(const FaceIndex& idx_face) const
705  {
706  assert(this->isValid(idx_face));
707  return (!this->getInnerHalfEdgeIndex(idx_face).isValid());
708  }
709 
710  ////////////////////////////////////////////////////////////////////////
711  // isIsolated
712  ////////////////////////////////////////////////////////////////////////
713 
714  /** \brief Check if the given vertex is isolated (not connected to other elements). */
715  inline bool
716  isIsolated(const VertexIndex& idx_vertex) const
717  {
718  assert(this->isValid(idx_vertex));
719  return (!this->getOutgoingHalfEdgeIndex(idx_vertex).isValid());
720  }
721 
722  ////////////////////////////////////////////////////////////////////////
723  // isBoundary
724  ////////////////////////////////////////////////////////////////////////
725 
726  /** \brief Check if the given vertex lies on the boundary. Isolated vertices are
727  * considered to be on the boundary. */
728  inline bool
729  isBoundary(const VertexIndex& idx_vertex) const
730  {
731  assert(this->isValid(idx_vertex));
732  if (this->isIsolated(idx_vertex))
733  return (true);
734  return (this->isBoundary(this->getOutgoingHalfEdgeIndex(idx_vertex)));
735  }
736 
737  /** \brief Check if the given half-edge lies on the boundary. */
738  inline bool
739  isBoundary(const HalfEdgeIndex& idx_he) const
740  {
741  assert(this->isValid(idx_he));
742  return (!this->getFaceIndex(idx_he).isValid());
743  }
744 
745  /** \brief Check if the given edge lies on the boundary (any of the two half-edges
746  * lies on the boundary. */
747  inline bool
748  isBoundary(const EdgeIndex& idx_edge) const
749  {
750  assert(this->isValid(idx_edge));
751  const HalfEdgeIndex& idx = pcl::geometry::toHalfEdgeIndex(idx_edge);
752  return (this->isBoundary(idx) ||
753  this->isBoundary(this->getOppositeHalfEdgeIndex(idx)));
754  }
755 
756  /**
757  * \brief Check if the given face lies on the boundary. There are two versions of
758  * this method, selected by the template parameter.
759  * \tparam CheckVerticesT Check if any vertex lies on the boundary (true) or
760  * check if any edge lies on the boundary (false).
761  */
762  template <bool CheckVerticesT>
763  inline bool
764  isBoundary(const FaceIndex& idx_face) const
765  {
766  assert(this->isValid(idx_face));
767  return (this->isBoundary(idx_face, std::integral_constant<bool, CheckVerticesT>()));
768  }
769 
770  /** \brief Check if the given face lies on the boundary. This method uses isBoundary
771  * \c true which checks if any vertex lies on the boundary. */
772  inline bool
773  isBoundary(const FaceIndex& idx_face) const
774  {
775  assert(this->isValid(idx_face));
776  return (this->isBoundary(idx_face, std::true_type()));
777  }
778 
779  ////////////////////////////////////////////////////////////////////////
780  // isManifold
781  ////////////////////////////////////////////////////////////////////////
782 
783  /** \brief Check if the given vertex is manifold. Isolated vertices are manifold. */
784  inline bool
785  isManifold(const VertexIndex& idx_vertex) const
786  {
787  assert(this->isValid(idx_vertex));
788  if (this->isIsolated(idx_vertex))
789  return (true);
790  return (this->isManifold(idx_vertex, IsManifold()));
791  }
792 
793  /** \brief Check if the mesh is manifold. */
794  inline bool
795  isManifold() const
796  {
797  return (this->isManifold(IsManifold()));
798  }
799 
800  ////////////////////////////////////////////////////////////////////////
801  // size
802  ////////////////////////////////////////////////////////////////////////
803 
804  /** \brief Get the number of the vertices. */
805  inline std::size_t
806  sizeVertices() const
807  {
808  return (vertices_.size());
809  }
810 
811  /** \brief Get the number of the half-edges. */
812  inline std::size_t
814  {
815  assert(half_edges_.size() % 2 == 0); // This would be a bug in the mesh.
816  return (half_edges_.size());
817  }
818 
819  /** \brief Get the number of the edges. */
820  inline std::size_t
821  sizeEdges() const
822  {
823  assert(half_edges_.size() % 2 == 0); // This would be a bug in the mesh.
824  return (half_edges_.size() / 2);
825  }
826 
827  /** \brief Get the number of the faces. */
828  inline std::size_t
829  sizeFaces() const
830  {
831  return (faces_.size());
832  }
833 
834  ////////////////////////////////////////////////////////////////////////
835  // empty
836  ////////////////////////////////////////////////////////////////////////
837 
838  /** \brief Check if the mesh is empty. */
839  inline bool
840  empty() const
841  {
842  return (this->emptyVertices() && this->emptyEdges() && this->emptyFaces());
843  }
844 
845  /** \brief Check if the vertices are empty. */
846  inline bool
848  {
849  return (vertices_.empty());
850  }
851 
852  /** \brief Check if the edges are empty. */
853  inline bool
854  emptyEdges() const
855  {
856  return (half_edges_.empty());
857  }
858 
859  /** \brief Check if the faces are empty. */
860  inline bool
861  emptyFaces() const
862  {
863  return (faces_.empty());
864  }
865 
866  ////////////////////////////////////////////////////////////////////////
867  // reserve
868  ////////////////////////////////////////////////////////////////////////
869 
870  /** \brief Reserve storage space n vertices. */
871  inline void
872  reserveVertices(const std::size_t n)
873  {
874  vertices_.reserve(n);
875  this->reserveData(vertex_data_cloud_, n, HasVertexData());
876  }
877 
878  /** \brief Reserve storage space for n edges (2*n storage space is reserved for the
879  * half-edges). */
880  inline void
881  reserveEdges(const std::size_t n)
882  {
883  half_edges_.reserve(2 * n);
884  this->reserveData(half_edge_data_cloud_, 2 * n, HasHalfEdgeData());
885  this->reserveData(edge_data_cloud_, n, HasEdgeData());
886  }
887 
888  /** \brief Reserve storage space for n faces. */
889  inline void
890  reserveFaces(const std::size_t n)
891  {
892  faces_.reserve(n);
893  this->reserveData(face_data_cloud_, n, HasFaceData());
894  }
895 
896  ////////////////////////////////////////////////////////////////////////
897  // resize
898  ////////////////////////////////////////////////////////////////////////
899 
900  /** \brief Resize the the vertices to n elements. */
901  inline void
902  resizeVertices(const std::size_t n, const VertexData& data = VertexData())
903  {
904  vertices_.resize(n, Vertex());
905  this->resizeData(vertex_data_cloud_, n, data, HasVertexData());
906  }
907 
908  /** \brief Resize the edges to n elements (half-edges will hold 2*n elements). */
909  inline void
910  resizeEdges(const std::size_t n,
911  const EdgeData& edge_data = EdgeData(),
912  const HalfEdgeData he_data = HalfEdgeData())
913  {
914  half_edges_.resize(2 * n, HalfEdge());
915  this->resizeData(half_edge_data_cloud_, 2 * n, he_data, HasHalfEdgeData());
916  this->resizeData(edge_data_cloud_, n, edge_data, HasEdgeData());
917  }
918 
919  /** \brief Resize the faces to n elements. */
920  inline void
921  resizeFaces(const std::size_t n, const FaceData& data = FaceData())
922  {
923  faces_.resize(n, Face());
924  this->resizeData(face_data_cloud_, n, data, HasFaceData());
925  }
926 
927  ////////////////////////////////////////////////////////////////////////
928  // clear
929  ////////////////////////////////////////////////////////////////////////
930 
931  /** \brief Clear all mesh elements and data. */
932  void
934  {
935  vertices_.clear();
936  half_edges_.clear();
937  faces_.clear();
938 
939  this->clearData(vertex_data_cloud_, HasVertexData());
940  this->clearData(half_edge_data_cloud_, HasHalfEdgeData());
941  this->clearData(edge_data_cloud_, HasEdgeData());
942  this->clearData(face_data_cloud_, HasFaceData());
943  }
944 
945  ////////////////////////////////////////////////////////////////////////
946  // get / set the vertex data cloud
947  ////////////////////////////////////////////////////////////////////////
948 
949  /** \brief Get access to the stored vertex data.
950  * \warning Please make sure to NOT add or remove elements from the cloud.
951  */
952  inline VertexDataCloud&
954  {
955  return (vertex_data_cloud_);
956  }
957 
958  /** \brief Get the stored vertex data. */
959  inline VertexDataCloud
961  {
962  return (vertex_data_cloud_);
963  }
964 
965  /** \brief Change the stored vertex data.
966  * \param[in] vertex_data_cloud The new vertex data. Must be the same as the current
967  * data.
968  * \return true if the cloud could be set.
969  */
970  inline bool
971  setVertexDataCloud(const VertexDataCloud& vertex_data_cloud)
972  {
973  if (vertex_data_cloud.size() == vertex_data_cloud_.size()) {
974  vertex_data_cloud_ = vertex_data_cloud;
975  return (true);
976  }
977  return (false);
978  }
979 
980  ////////////////////////////////////////////////////////////////////////
981  // get / set the half-edge data cloud
982  ////////////////////////////////////////////////////////////////////////
983 
984  /** \brief Get access to the stored half-edge data.
985  * \warning Please make sure to NOT add or remove elements from the cloud.
986  */
987  inline HalfEdgeDataCloud&
989  {
990  return (half_edge_data_cloud_);
991  }
992 
993  /** \brief Get the stored half-edge data. */
994  inline HalfEdgeDataCloud
996  {
997  return (half_edge_data_cloud_);
998  }
999 
1000  /** \brief Change the stored half-edge data.
1001  * \param[in] half_edge_data_cloud The new half-edge data. Must be the same as the
1002  * current data.
1003  * \return true if the cloud could be set.
1004  */
1005  inline bool
1006  setHalfEdgeDataCloud(const HalfEdgeDataCloud& half_edge_data_cloud)
1007  {
1008  if (half_edge_data_cloud.size() == half_edge_data_cloud_.size()) {
1009  half_edge_data_cloud_ = half_edge_data_cloud;
1010  return (true);
1011  }
1012  return (false);
1013  }
1014 
1015  ////////////////////////////////////////////////////////////////////////
1016  // get / set the edge data cloud
1017  ////////////////////////////////////////////////////////////////////////
1018 
1019  /** \brief Get access to the stored edge data.
1020  * \warning Please make sure to NOT add or remove elements from the cloud.
1021  */
1022  inline EdgeDataCloud&
1024  {
1025  return (edge_data_cloud_);
1026  }
1027 
1028  /** \brief Get the stored edge data. */
1029  inline EdgeDataCloud
1031  {
1032  return (edge_data_cloud_);
1033  }
1034 
1035  /** \brief Change the stored edge data.
1036  * \param[in] edge_data_cloud The new edge data. Must be the same as the current data.
1037  * \return true if the cloud could be set.
1038  */
1039  inline bool
1040  setEdgeDataCloud(const EdgeDataCloud& edge_data_cloud)
1041  {
1042  if (edge_data_cloud.size() == edge_data_cloud_.size()) {
1043  edge_data_cloud_ = edge_data_cloud;
1044  return (true);
1045  }
1046  return (false);
1047  }
1048 
1049  ////////////////////////////////////////////////////////////////////////
1050  // get / set the face data cloud
1051  ////////////////////////////////////////////////////////////////////////
1052 
1053  /** \brief Get access to the stored face data.
1054  * \warning Please make sure to NOT add or remove elements from the cloud.
1055  */
1056  inline FaceDataCloud&
1058  {
1059  return (face_data_cloud_);
1060  }
1061 
1062  /** \brief Get the stored face data. */
1063  inline FaceDataCloud
1065  {
1066  return (face_data_cloud_);
1067  }
1068 
1069  /** \brief Change the stored face data.
1070  * \param[in] face_data_cloud The new face data. Must be the same as the current data.
1071  * \return true if the cloud could be set.
1072  */
1073  inline bool
1074  setFaceDataCloud(const FaceDataCloud& face_data_cloud)
1075  {
1076  if (face_data_cloud.size() == face_data_cloud_.size()) {
1077  face_data_cloud_ = face_data_cloud;
1078  return (true);
1079  }
1080  return (false);
1081  }
1082 
1083  ////////////////////////////////////////////////////////////////////////
1084  // getVertexIndex / getHalfEdgeIndex / getEdgeIndex / getFaceIndex
1085  ////////////////////////////////////////////////////////////////////////
1086 
1087  /** \brief Get the index associated to the given vertex data.
1088  * \return Invalid index if the mesh does not have associated vertex data.
1089  */
1090  inline VertexIndex
1091  getVertexIndex(const VertexData& vertex_data) const
1092  {
1093  if (HasVertexData::value) {
1094  assert(&vertex_data >= &vertex_data_cloud_.front() &&
1095  &vertex_data <= &vertex_data_cloud_.back());
1096  return (VertexIndex(std::distance(&vertex_data_cloud_.front(), &vertex_data)));
1097  }
1098  return {};
1099  }
1100 
1101  /** \brief Get the index associated to the given half-edge data. */
1102  inline HalfEdgeIndex
1103  getHalfEdgeIndex(const HalfEdgeData& half_edge_data) const
1104  {
1105  if (HasHalfEdgeData::value) {
1106  assert(&half_edge_data >= &half_edge_data_cloud_.front() &&
1107  &half_edge_data <= &half_edge_data_cloud_.back());
1108  return (HalfEdgeIndex(
1109  std::distance(&half_edge_data_cloud_.front(), &half_edge_data)));
1110  }
1111  return {};
1112  }
1113 
1114  /** \brief Get the index associated to the given edge data. */
1115  inline EdgeIndex
1116  getEdgeIndex(const EdgeData& edge_data) const
1117  {
1118  if (HasEdgeData::value) {
1119  assert(&edge_data >= &edge_data_cloud_.front() &&
1120  &edge_data <= &edge_data_cloud_.back());
1121  return (EdgeIndex(std::distance(&edge_data_cloud_.front(), &edge_data)));
1122  }
1123  return {};
1124  }
1125 
1126  /** \brief Get the index associated to the given face data. */
1127  inline FaceIndex
1128  getFaceIndex(const FaceData& face_data) const
1129  {
1130  if (HasFaceData::value) {
1131  assert(&face_data >= &face_data_cloud_.front() &&
1132  &face_data <= &face_data_cloud_.back());
1133  return (FaceIndex(std::distance(&face_data_cloud_.front(), &face_data)));
1134  }
1135  return {};
1136  }
1137 
1138 protected:
1139  ////////////////////////////////////////////////////////////////////////
1140  // Types
1141  ////////////////////////////////////////////////////////////////////////
1142 
1143  // Elements
1147 
1148  using Vertices = std::vector<Vertex>;
1149  using HalfEdges = std::vector<HalfEdge>;
1150  using Faces = std::vector<Face>;
1151 
1152  using VertexIterator = typename Vertices::iterator;
1153  using HalfEdgeIterator = typename HalfEdges::iterator;
1154  using FaceIterator = typename Faces::iterator;
1155 
1156  using VertexConstIterator = typename Vertices::const_iterator;
1157  using HalfEdgeConstIterator = typename HalfEdges::const_iterator;
1158  using FaceConstIterator = typename Faces::const_iterator;
1159 
1160  /** \brief General implementation of addFace. */
1161  FaceIndex
1163  const FaceData& face_data,
1164  const EdgeData& edge_data,
1165  const HalfEdgeData& half_edge_data)
1166  {
1167  const int n = static_cast<int>(vertices.size());
1168  if (n < 3)
1169  return {};
1170 
1171  // Check for topological errors
1172  inner_he_.resize(n);
1173  free_he_.resize(n);
1174  is_new_.resize(n);
1175  make_adjacent_.resize(n);
1176  for (int i = 0; i < n; ++i) {
1177  if (!this->checkTopology1(vertices[i],
1178  vertices[(i + 1) % n],
1179  inner_he_[i],
1180  is_new_[i],
1181  IsManifold())) {
1182  return {};
1183  }
1184  }
1185  for (int i = 0; i < n; ++i) {
1186  int j = (i + 1) % n;
1187  if (!this->checkTopology2(inner_he_[i],
1188  inner_he_[j],
1189  is_new_[i],
1190  is_new_[j],
1191  this->isIsolated(vertices[j]),
1192  make_adjacent_[i],
1193  free_he_[i],
1194  IsManifold())) {
1195  return {};
1196  }
1197  }
1198 
1199  // Reconnect the existing half-edges if needed
1200  if (!IsManifold::value) {
1201  for (int i = 0; i < n; ++i) {
1202  if (make_adjacent_[i]) {
1203  this->makeAdjacent(inner_he_[i], inner_he_[(i + 1) % n], free_he_[i]);
1204  }
1205  }
1206  }
1207 
1208  // Add new half-edges if needed
1209  for (int i = 0; i < n; ++i) {
1210  if (is_new_[i]) {
1211  inner_he_[i] = this->addEdge(
1212  vertices[i], vertices[(i + 1) % n], half_edge_data, edge_data);
1213  }
1214  }
1215 
1216  // Connect
1217  for (int i = 0; i < n; ++i) {
1218  int j = (i + 1) % n;
1219  if (is_new_[i] && is_new_[j])
1220  this->connectNewNew(inner_he_[i], inner_he_[j], vertices[j], IsManifold());
1221  else if (is_new_[i] && !is_new_[j])
1222  this->connectNewOld(inner_he_[i], inner_he_[j], vertices[j]);
1223  else if (!is_new_[i] && is_new_[j])
1224  this->connectOldNew(inner_he_[i], inner_he_[j], vertices[j]);
1225  else
1226  this->connectOldOld(inner_he_[i], inner_he_[j], vertices[j], IsManifold());
1227  }
1228  return (this->connectFace(inner_he_, face_data));
1229  }
1230 
1231  ////////////////////////////////////////////////////////////////////////
1232  // addEdge
1233  ////////////////////////////////////////////////////////////////////////
1234 
1235  /** \brief Add an edge between the two given vertices and connect them with the
1236  * vertices.
1237  * \param[in] idx_v_a The first vertex index
1238  * \param[in] idx_v_b The second vertex index
1239  * \param[in] he_data Data associated with the half-edges. This is only added if
1240  * the mesh has data associated with the half-edges.
1241  * \param[in] edge_data Data associated with the edge. This is only added if the mesh
1242  * has data associated with the edges.
1243  * \return Index to the half-edge from vertex a to vertex b.
1244  */
1246  addEdge(const VertexIndex& idx_v_a,
1247  const VertexIndex& idx_v_b,
1248  const HalfEdgeData& he_data,
1249  const EdgeData& edge_data)
1250  {
1251  half_edges_.push_back(HalfEdge(idx_v_b));
1252  half_edges_.push_back(HalfEdge(idx_v_a));
1253 
1254  this->addData(half_edge_data_cloud_, he_data, HasHalfEdgeData());
1255  this->addData(half_edge_data_cloud_, he_data, HasHalfEdgeData());
1256  this->addData(edge_data_cloud_, edge_data, HasEdgeData());
1257 
1258  return (static_cast<HalfEdgeIndex>(half_edges_.size() - 2));
1259  }
1260 
1261  ////////////////////////////////////////////////////////////////////////
1262  // topology checks
1263  ////////////////////////////////////////////////////////////////////////
1264 
1265  /** \brief Check if the edge between the two vertices can be added.
1266  * \param[in] idx_v_a Index to the first vertex.
1267  * \param[in] idx_v_b Index to the second vertex.
1268  * \param[out] idx_he_ab Index to the half-edge ab if is_new_ab=false.
1269  * \param[out] is_new_ab true if the edge between the vertices exists already. Must be
1270  * initialized with true!
1271  * \return true if the half-edge may be added.
1272  */
1273  bool
1274  checkTopology1(const VertexIndex& idx_v_a,
1275  const VertexIndex& idx_v_b,
1276  HalfEdgeIndex& idx_he_ab,
1277  std::vector<bool>::reference is_new_ab,
1278  std::true_type /*is_manifold*/) const
1279  {
1280  is_new_ab = true;
1281  if (this->isIsolated(idx_v_a))
1282  return (true);
1283 
1284  idx_he_ab = this->getOutgoingHalfEdgeIndex(idx_v_a);
1285 
1286  if (!this->isBoundary(idx_he_ab))
1287  return (false);
1288  if (this->getTerminatingVertexIndex(idx_he_ab) == idx_v_b)
1289  is_new_ab = false;
1290  return (true);
1291  }
1292 
1293  /** \brief Non manifold version of checkTopology1 */
1294  bool
1295  checkTopology1(const VertexIndex& idx_v_a,
1296  const VertexIndex& idx_v_b,
1297  HalfEdgeIndex& idx_he_ab,
1298  std::vector<bool>::reference is_new_ab,
1299  std::false_type /*is_manifold*/) const
1300  {
1301  is_new_ab = true;
1302  if (this->isIsolated(idx_v_a))
1303  return (true);
1304  if (!this->isBoundary(this->getOutgoingHalfEdgeIndex(idx_v_a)))
1305  return (false);
1306 
1309  const VertexAroundVertexCirculator circ_end = circ;
1310 
1311  do {
1312  if (circ.getTargetIndex() == idx_v_b) {
1313  idx_he_ab = circ.getCurrentHalfEdgeIndex();
1314  if (!this->isBoundary(idx_he_ab))
1315  return (false);
1316 
1317  is_new_ab = false;
1318  return (true);
1319  }
1320  } while (++circ != circ_end);
1321 
1322  return (true);
1323  }
1324 
1325  /** \brief Check if the face may be added (mesh does not become non-manifold). */
1326  inline bool
1327  checkTopology2(const HalfEdgeIndex& /*idx_he_ab*/,
1328  const HalfEdgeIndex& /*idx_he_bc*/,
1329  const bool is_new_ab,
1330  const bool is_new_bc,
1331  const bool is_isolated_b,
1332  std::vector<bool>::reference /*make_adjacent_ab_bc*/,
1333  HalfEdgeIndex& /*idx_free_half_edge*/,
1334  std::true_type /*is_manifold*/) const
1335  {
1336  return (!is_new_ab || !is_new_bc || is_isolated_b);
1337  }
1338 
1339  /** \brief Check if the half-edge bc is the next half-edge of ab.
1340  * \param[in] idx_he_ab Index to the half-edge between the vertices a and b.
1341  * \param[in] idx_he_bc Index to the half-edge between the vertices b and c.
1342  * \param[in] is_new_ab Half-edge ab is new.
1343  * \param[in] is_new_bc Half-edge bc is new.
1344  * \param[out] make_adjacent_ab_bc Half-edges ab and bc need to be made adjacent.
1345  * \param[out] idx_free_half_edge Free half-edge (needed for makeAdjacent)
1346  * \return true if addFace may be continued.
1347  */
1348  inline bool
1349  checkTopology2(const HalfEdgeIndex& idx_he_ab,
1350  const HalfEdgeIndex& idx_he_bc,
1351  const bool is_new_ab,
1352  const bool is_new_bc,
1353  const bool /*is_isolated_b*/,
1354  std::vector<bool>::reference make_adjacent_ab_bc,
1355  HalfEdgeIndex& idx_free_half_edge,
1356  std::false_type /*is_manifold*/) const
1357  {
1358  if (is_new_ab || is_new_bc) {
1359  make_adjacent_ab_bc = false;
1360  return (true); // Make adjacent is only needed for two old half-edges
1361  }
1362 
1363  if (this->getNextHalfEdgeIndex(idx_he_ab) == idx_he_bc) {
1364  make_adjacent_ab_bc = false;
1365  return (true); // already adjacent
1366  }
1367 
1368  make_adjacent_ab_bc = true;
1369 
1370  // Find the next boundary half edge
1373  this->getOppositeHalfEdgeIndex(idx_he_bc));
1374 
1375  do
1376  ++circ;
1377  while (!this->isBoundary(circ.getTargetIndex()));
1378  idx_free_half_edge = circ.getTargetIndex();
1379 
1380  // This would detach the faces around the vertex from each other.
1381  return (circ.getTargetIndex() != idx_he_ab);
1382  }
1383 
1384  /** \brief Make the half-edges bc the next half-edge of ab.
1385  * \param[in] idx_he_ab Index to the half-edge between the vertices a
1386  * and b.
1387  * \param[in] idx_he_bc Index to the half-edge between the
1388  * vertices b and c.
1389  * \param[in, out] idx_free_half_edge Free half-edge needed to re-connect the
1390  * half-edges around vertex b.
1391  */
1392  void
1393  makeAdjacent(const HalfEdgeIndex& idx_he_ab,
1394  const HalfEdgeIndex& idx_he_bc,
1395  HalfEdgeIndex& idx_free_half_edge)
1396  {
1397  // Re-link. No references!
1398  const HalfEdgeIndex idx_he_ab_next = this->getNextHalfEdgeIndex(idx_he_ab);
1399  const HalfEdgeIndex idx_he_bc_prev = this->getPrevHalfEdgeIndex(idx_he_bc);
1400  const HalfEdgeIndex idx_he_free_next =
1401  this->getNextHalfEdgeIndex(idx_free_half_edge);
1402 
1403  this->connectPrevNext(idx_he_ab, idx_he_bc);
1404  this->connectPrevNext(idx_free_half_edge, idx_he_ab_next);
1405  this->connectPrevNext(idx_he_bc_prev, idx_he_free_next);
1406  }
1407 
1408  ////////////////////////////////////////////////////////////////////////
1409  // connect
1410  ////////////////////////////////////////////////////////////////////////
1411 
1412  /** \brief Add a face to the mesh and connect it to the half-edges.
1413  * \param[in] inner_he Inner half-edges of the face.
1414  * \param[in] face_data Data that is stored in the face. This is only added if the
1415  * mesh has data associated with the faces.
1416  * \return Index to the new face.
1417  */
1418  FaceIndex
1419  connectFace(const HalfEdgeIndices& inner_he, const FaceData& face_data)
1420  {
1421  faces_.push_back(Face(inner_he.back()));
1422  this->addData(face_data_cloud_, face_data, HasFaceData());
1423 
1424  const FaceIndex idx_face(static_cast<int>(this->sizeFaces() - 1));
1425 
1426  for (const auto& idx_half_edge : inner_he) {
1427  this->setFaceIndex(idx_half_edge, idx_face);
1428  }
1429 
1430  return (idx_face);
1431  }
1432 
1433  /** \brief Connect the next and prev indices of the two half-edges with each other. */
1434  inline void
1435  connectPrevNext(const HalfEdgeIndex& idx_he_ab, const HalfEdgeIndex& idx_he_bc)
1436  {
1437  this->setNextHalfEdgeIndex(idx_he_ab, idx_he_bc);
1438  this->setPrevHalfEdgeIndex(idx_he_bc, idx_he_ab);
1439  }
1440 
1441  /** \brief Both half-edges are new (manifold version). */
1442  void
1443  connectNewNew(const HalfEdgeIndex& idx_he_ab,
1444  const HalfEdgeIndex& idx_he_bc,
1445  const VertexIndex& idx_v_b,
1446  std::true_type /*is_manifold*/)
1447  {
1448  const HalfEdgeIndex idx_he_ba = this->getOppositeHalfEdgeIndex(idx_he_ab);
1449  const HalfEdgeIndex idx_he_cb = this->getOppositeHalfEdgeIndex(idx_he_bc);
1450 
1451  this->connectPrevNext(idx_he_ab, idx_he_bc);
1452  this->connectPrevNext(idx_he_cb, idx_he_ba);
1453 
1454  this->setOutgoingHalfEdgeIndex(idx_v_b, idx_he_ba);
1455  }
1456 
1457  /** \brief Both half-edges are new (non-manifold version). */
1458  void
1459  connectNewNew(const HalfEdgeIndex& idx_he_ab,
1460  const HalfEdgeIndex& idx_he_bc,
1461  const VertexIndex& idx_v_b,
1462  std::false_type /*is_manifold*/)
1463  {
1464  if (this->isIsolated(idx_v_b)) {
1465  this->connectNewNew(idx_he_ab, idx_he_bc, idx_v_b, std::true_type());
1466  }
1467  else {
1468  const HalfEdgeIndex idx_he_ba = this->getOppositeHalfEdgeIndex(idx_he_ab);
1469  const HalfEdgeIndex idx_he_cb = this->getOppositeHalfEdgeIndex(idx_he_bc);
1470 
1471  // No references!
1472  const HalfEdgeIndex idx_he_b_out = this->getOutgoingHalfEdgeIndex(idx_v_b);
1473  const HalfEdgeIndex idx_he_b_out_prev = this->getPrevHalfEdgeIndex(idx_he_b_out);
1474 
1475  this->connectPrevNext(idx_he_ab, idx_he_bc);
1476  this->connectPrevNext(idx_he_cb, idx_he_b_out);
1477  this->connectPrevNext(idx_he_b_out_prev, idx_he_ba);
1478  }
1479  }
1480 
1481  /** \brief The first half-edge is new. */
1482  void
1483  connectNewOld(const HalfEdgeIndex& idx_he_ab,
1484  const HalfEdgeIndex& idx_he_bc,
1485  const VertexIndex& idx_v_b)
1486  {
1487  const HalfEdgeIndex idx_he_ba = this->getOppositeHalfEdgeIndex(idx_he_ab);
1488  const HalfEdgeIndex idx_he_bc_prev =
1489  this->getPrevHalfEdgeIndex(idx_he_bc); // No reference!
1490 
1491  this->connectPrevNext(idx_he_ab, idx_he_bc);
1492  this->connectPrevNext(idx_he_bc_prev, idx_he_ba);
1493 
1494  this->setOutgoingHalfEdgeIndex(idx_v_b, idx_he_ba);
1495  }
1496 
1497  /** \brief The second half-edge is new. */
1498  void
1499  connectOldNew(const HalfEdgeIndex& idx_he_ab,
1500  const HalfEdgeIndex& idx_he_bc,
1501  const VertexIndex& idx_v_b)
1502  {
1503  const HalfEdgeIndex idx_he_cb = this->getOppositeHalfEdgeIndex(idx_he_bc);
1504  const HalfEdgeIndex idx_he_ab_next =
1505  this->getNextHalfEdgeIndex(idx_he_ab); // No reference!
1506 
1507  this->connectPrevNext(idx_he_ab, idx_he_bc);
1508  this->connectPrevNext(idx_he_cb, idx_he_ab_next);
1509 
1510  this->setOutgoingHalfEdgeIndex(idx_v_b, idx_he_ab_next);
1511  }
1512 
1513  /** \brief Both half-edges are old (manifold version). */
1514  void
1515  connectOldOld(const HalfEdgeIndex& /*idx_he_ab*/,
1516  const HalfEdgeIndex& /*idx_he_bc*/,
1517  const VertexIndex& /*idx_v_b*/,
1518  std::true_type /*is_manifold*/)
1519  {}
1520 
1521  /** \brief Both half-edges are old (non-manifold version). */
1522  void
1523  connectOldOld(const HalfEdgeIndex& /*idx_he_ab*/,
1524  const HalfEdgeIndex& idx_he_bc,
1525  const VertexIndex& idx_v_b,
1526  std::false_type /*is_manifold*/)
1527  {
1528  const HalfEdgeIndex& idx_he_b_out = this->getOutgoingHalfEdgeIndex(idx_v_b);
1529 
1530  // The outgoing half edge MUST be a boundary half-edge (if there is one)
1531  if (idx_he_b_out == idx_he_bc) // he_bc is no longer on the boundary
1532  {
1534  this->getOutgoingHalfEdgeAroundVertexCirculator(idx_he_b_out);
1535  const OutgoingHalfEdgeAroundVertexCirculator circ_end = circ;
1536 
1537  while (++circ != circ_end) {
1538  if (this->isBoundary(circ.getTargetIndex())) {
1539  this->setOutgoingHalfEdgeIndex(idx_v_b, circ.getTargetIndex());
1540  return;
1541  }
1542  }
1543  }
1544  }
1545 
1546  ////////////////////////////////////////////////////////////////////////
1547  // addData
1548  ////////////////////////////////////////////////////////////////////////
1549 
1550  /** \brief Add mesh data. */
1551  template <class DataT>
1552  inline void
1553  addData(pcl::PointCloud<DataT>& cloud, const DataT& data, std::true_type /*has_data*/)
1554  {
1555  cloud.push_back(data);
1556  }
1557 
1558  /** \brief Does nothing. */
1559  template <class DataT>
1560  inline void
1562  const DataT& /*data*/,
1563  std::false_type /*has_data*/)
1564  {}
1565 
1566  ////////////////////////////////////////////////////////////////////////
1567  // deleteFace
1568  ////////////////////////////////////////////////////////////////////////
1569 
1570  /** \brief Manifold version of deleteFace. If the mesh becomes non-manifold due to the
1571  * delete operation the faces around the non-manifold vertex are deleted until the
1572  * mesh becomes manifold again. */
1573  void
1574  deleteFace(const FaceIndex& idx_face, std::true_type /*is_manifold*/)
1575  {
1576  assert(this->isValid(idx_face));
1577  delete_faces_face_.clear();
1578  delete_faces_face_.push_back(idx_face);
1579 
1580  while (!delete_faces_face_.empty()) {
1581  const FaceIndex idx_face_cur = delete_faces_face_.back();
1582  delete_faces_face_.pop_back();
1583 
1584  // This calls the non-manifold version of deleteFace, which will call the manifold
1585  // version of reconnect.
1586  this->deleteFace(idx_face_cur, std::false_type());
1587  }
1588  }
1589 
1590  /** \brief Non-manifold version of deleteFace. */
1591  void
1592  deleteFace(const FaceIndex& idx_face, std::false_type /*is_manifold*/)
1593  {
1594  assert(this->isValid(idx_face));
1595  if (this->isDeleted(idx_face))
1596  return;
1597 
1598  // Store all half-edges in the face
1599  inner_he_.clear();
1600  is_boundary_.clear();
1602  this->getInnerHalfEdgeAroundFaceCirculator(idx_face);
1603  const InnerHalfEdgeAroundFaceCirculator circ_end = circ;
1604  do {
1605  inner_he_.push_back(circ.getTargetIndex());
1606  is_boundary_.push_back(
1607  this->isBoundary(this->getOppositeHalfEdgeIndex(circ.getTargetIndex())));
1608  } while (++circ != circ_end);
1609  assert(inner_he_.size() >= 3); // Minimum should be a triangle.
1610 
1611  const int n = static_cast<int>(inner_he_.size());
1612  int j;
1613 
1614  if (IsManifold::value) {
1615  for (int i = 0; i < n; ++i) {
1616  j = (i + 1) % n;
1617  this->reconnect(inner_he_[i], inner_he_[j], is_boundary_[i], is_boundary_[j]);
1618  }
1619  for (int i = 0; i < n; ++i) {
1620  this->getHalfEdge(inner_he_[i]).idx_face_.invalidate();
1621  }
1622  }
1623  else {
1624  for (int i = 0; i < n; ++i) {
1625  j = (i + 1) % n;
1626  this->reconnect(inner_he_[i], inner_he_[j], is_boundary_[i], is_boundary_[j]);
1627  this->getHalfEdge(inner_he_[i]).idx_face_.invalidate();
1628  }
1629  }
1630 
1631  this->markDeleted(idx_face);
1632  }
1633 
1634  ////////////////////////////////////////////////////////////////////////
1635  // reconnect
1636  ////////////////////////////////////////////////////////////////////////
1637 
1638  /** \brief Deconnect the input half-edges from the mesh and adjust the indices of the
1639  * connected half-edges. */
1640  void
1641  reconnect(const HalfEdgeIndex& idx_he_ab,
1642  const HalfEdgeIndex& idx_he_bc,
1643  const bool is_boundary_ba,
1644  const bool is_boundary_cb)
1645  {
1646  const HalfEdgeIndex idx_he_ba = this->getOppositeHalfEdgeIndex(idx_he_ab);
1647  const HalfEdgeIndex idx_he_cb = this->getOppositeHalfEdgeIndex(idx_he_bc);
1648  const VertexIndex idx_v_b = this->getTerminatingVertexIndex(idx_he_ab);
1649 
1650  if (is_boundary_ba && is_boundary_cb) // boundary - boundary
1651  {
1652  const HalfEdgeIndex& idx_he_cb_next = this->getNextHalfEdgeIndex(idx_he_cb);
1653 
1654  if (idx_he_cb_next == idx_he_ba) // Vertex b is isolated
1655  {
1656  this->markDeleted(idx_v_b);
1657  }
1658  else {
1659  this->connectPrevNext(this->getPrevHalfEdgeIndex(idx_he_ba), idx_he_cb_next);
1660  this->setOutgoingHalfEdgeIndex(idx_v_b, idx_he_cb_next);
1661  }
1662 
1663  this->markDeleted(idx_he_ab);
1664  this->markDeleted(idx_he_ba);
1665  }
1666  else if (is_boundary_ba && !is_boundary_cb) // boundary - no boundary
1667  {
1668  this->connectPrevNext(this->getPrevHalfEdgeIndex(idx_he_ba), idx_he_bc);
1669  this->setOutgoingHalfEdgeIndex(idx_v_b, idx_he_bc);
1670 
1671  this->markDeleted(idx_he_ab);
1672  this->markDeleted(idx_he_ba);
1673  }
1674  else if (!is_boundary_ba && is_boundary_cb) // no boundary - boundary
1675  {
1676  const HalfEdgeIndex& idx_he_cb_next = this->getNextHalfEdgeIndex(idx_he_cb);
1677  this->connectPrevNext(idx_he_ab, idx_he_cb_next);
1678  this->setOutgoingHalfEdgeIndex(idx_v_b, idx_he_cb_next);
1679  }
1680  else // no boundary - no boundary
1681  {
1682  this->reconnectNBNB(idx_he_bc, idx_he_cb, idx_v_b, IsManifold());
1683  }
1684  }
1685 
1686  /** \brief Both edges are not on the boundary. Manifold version. */
1687  void
1688  reconnectNBNB(const HalfEdgeIndex& idx_he_bc,
1689  const HalfEdgeIndex& idx_he_cb,
1690  const VertexIndex& idx_v_b,
1691  std::true_type /*is_manifold*/)
1692  {
1693  if (this->isBoundary(idx_v_b)) {
1694  // Deletion of this face makes the mesh non-manifold
1695  // -> delete the neighboring faces until it is manifold again
1698 
1699  while (!this->isBoundary(circ.getTargetIndex())) {
1700  delete_faces_face_.push_back(this->getFaceIndex((circ++).getTargetIndex()));
1701 
1702 #ifdef PCL_GEOMETRY_MESH_BASE_TEST_DELETE_FACE_MANIFOLD_2
1704  idx_he_cb)) // Abort infinity loop
1705  {
1706  // In a manifold mesh we can't invalidate the face while reconnecting!
1707  // See the implementation of
1708  // deleteFace (const FaceIndex& idx_face,
1709  // std::false_type /*is_manifold*/)
1710  pcl::geometry::g_pcl_geometry_mesh_base_test_delete_face_manifold_2_success =
1711  false;
1712  return;
1713  }
1714 #endif
1715  }
1716  }
1717  else {
1718  this->setOutgoingHalfEdgeIndex(idx_v_b, idx_he_bc);
1719  }
1720  }
1721 
1722  /** \brief Both edges are not on the boundary. Non-manifold version. */
1723  void
1724  reconnectNBNB(const HalfEdgeIndex& idx_he_bc,
1725  const HalfEdgeIndex& /*idx_he_cb*/,
1726  const VertexIndex& idx_v_b,
1727  std::false_type /*is_manifold*/)
1728  {
1729  if (!this->isBoundary(idx_v_b)) {
1730  this->setOutgoingHalfEdgeIndex(idx_v_b, idx_he_bc);
1731  }
1732  }
1733 
1734  ////////////////////////////////////////////////////////////////////////
1735  // markDeleted
1736  ////////////////////////////////////////////////////////////////////////
1737 
1738  /** \brief Mark the given vertex as deleted. */
1739  inline void
1740  markDeleted(const VertexIndex& idx_vertex)
1741  {
1742  assert(this->isValid(idx_vertex));
1743  this->getVertex(idx_vertex).idx_outgoing_half_edge_.invalidate();
1744  }
1745 
1746  /** \brief Mark the given half-edge as deleted. */
1747  inline void
1749  {
1750  assert(this->isValid(idx_he));
1751  this->getHalfEdge(idx_he).idx_terminating_vertex_.invalidate();
1752  }
1753 
1754  /** \brief Mark the given edge (both half-edges) as deleted. */
1755  inline void
1756  markDeleted(const EdgeIndex& idx_edge)
1757  {
1758  assert(this->isValid(idx_edge));
1759  this->markDeleted(pcl::geometry::toHalfEdgeIndex(idx_edge, true));
1760  this->markDeleted(pcl::geometry::toHalfEdgeIndex(idx_edge, false));
1761  }
1762 
1763  /** \brief Mark the given face as deleted. */
1764  inline void
1765  markDeleted(const FaceIndex& idx_face)
1766  {
1767  assert(this->isValid(idx_face));
1768  this->getFace(idx_face).idx_inner_half_edge_.invalidate();
1769  }
1770 
1771  ////////////////////////////////////////////////////////////////////////
1772  // For cleanUp
1773  ////////////////////////////////////////////////////////////////////////
1774 
1775  /** \brief Removes mesh elements and data that are marked as deleted from the
1776  * container.
1777  * \tparam ElementContainerT e.g. std::vector <Vertex>
1778  * \tparam DataContainerT e.g. std::vector <VertexData>
1779  * \tparam IndexContainerT e.g. std::vector <VertexIndex>
1780  * \tparam HasDataT Integral constant specifying if the mesh has data
1781  * associated with the elements.
1782  * \param[in, out] elements Container for the mesh elements. Resized to the new size.
1783  * \param[in, out] data_cloud Container for the mesh data. Resized to the new size.
1784  * \return Container with the same size as the old input data. Holds the indices to
1785  * the new elements for each non-deleted element and an invalid index if it is
1786  * deleted.
1787  */
1788  template <class ElementContainerT,
1789  class DataContainerT,
1790  class IndexContainerT,
1791  class HasDataT>
1792  IndexContainerT
1793  remove(ElementContainerT& elements, DataContainerT& data_cloud)
1794  {
1795  using Index = typename IndexContainerT::value_type;
1796  using Element = typename ElementContainerT::value_type;
1797 
1798  if (HasDataT::value)
1799  assert(elements.size() == data_cloud.size());
1800  else
1801  assert(data_cloud.empty()); // Bug in this class!
1802 
1803  IndexContainerT new_indices(elements.size(),
1804  typename IndexContainerT::value_type());
1805  Index ind_old(0), ind_new(0);
1806 
1807  auto it_e_old = elements.cbegin();
1808  auto it_e_new = elements.begin();
1809 
1810  auto it_d_old = data_cloud.cbegin();
1811  auto it_d_new = data_cloud.begin();
1812 
1813  auto it_ind_new = new_indices.begin();
1814  auto it_ind_new_end = new_indices.cend();
1815 
1816  while (it_ind_new != it_ind_new_end) {
1817  if (!this->isDeleted(ind_old)) {
1818  *it_ind_new = ind_new++;
1819 
1820  // TODO: Test for self assignment?
1821  *it_e_new++ = *it_e_old;
1822  this->assignIf(it_d_old, it_d_new, HasDataT());
1823  this->incrementIf(it_d_new, HasDataT());
1824  }
1825  ++ind_old;
1826  ++it_e_old;
1827  this->incrementIf(it_d_old, HasDataT());
1828  ++it_ind_new;
1829  }
1830 
1831  elements.resize(ind_new.get(), Element());
1832  if (HasDataT::value) {
1833  data_cloud.resize(ind_new.get());
1834  }
1835  else if (it_d_old != data_cloud.begin() || it_d_new != data_cloud.begin()) {
1836  std::cerr << "TODO: Bug in MeshBase::remove!\n";
1837  assert(false);
1838  exit(EXIT_FAILURE);
1839  }
1840 
1841  return (new_indices);
1842  }
1843 
1844  /** \brief Increment the iterator. */
1845  template <class IteratorT>
1846  inline void
1847  incrementIf(IteratorT& it, std::true_type /*has_data*/) const
1848  {
1849  ++it;
1850  }
1851 
1852  /** \brief Does nothing. */
1853  template <class IteratorT>
1854  inline void
1855  incrementIf(IteratorT& /*it*/, std::false_type /*has_data*/) const
1856  {}
1857 
1858  /** \brief Assign the source iterator to the target iterator. */
1859  template <class ConstIteratorT, class IteratorT>
1860  inline void
1861  assignIf(const ConstIteratorT source,
1862  IteratorT target,
1863  std::true_type /*has_data*/) const
1864  {
1865  *target = *source;
1866  }
1867 
1868  /** \brief Does nothing. */
1869  template <class ConstIteratorT, class IteratorT>
1870  inline void
1871  assignIf(const ConstIteratorT /*source*/,
1872  IteratorT /*target*/,
1873  std::false_type /*has_data*/) const
1874  {}
1875 
1876  ////////////////////////////////////////////////////////////////////////
1877  // Vertex / Half-edge / Face connectivity
1878  ////////////////////////////////////////////////////////////////////////
1879 
1880  /** \brief Set the outgoing half-edge index to a given vertex. */
1881  inline void
1883  const HalfEdgeIndex& idx_outgoing_half_edge)
1884  {
1885  assert(this->isValid(idx_vertex));
1886  this->getVertex(idx_vertex).idx_outgoing_half_edge_ = idx_outgoing_half_edge;
1887  }
1888 
1889  /** \brief Set the terminating vertex index to a given half-edge. */
1890  inline void
1892  const VertexIndex& idx_terminating_vertex)
1893  {
1894  assert(this->isValid(idx_half_edge));
1895  this->getHalfEdge(idx_half_edge).idx_terminating_vertex_ = idx_terminating_vertex;
1896  }
1897 
1898  /** \brief Set the next half_edge index to a given half-edge. */
1899  inline void
1900  setNextHalfEdgeIndex(const HalfEdgeIndex& idx_half_edge,
1901  const HalfEdgeIndex& idx_next_half_edge)
1902  {
1903  assert(this->isValid(idx_half_edge));
1904  this->getHalfEdge(idx_half_edge).idx_next_half_edge_ = idx_next_half_edge;
1905  }
1906 
1907  /** \brief Set the previous half-edge index to a given half-edge. */
1908  inline void
1909  setPrevHalfEdgeIndex(const HalfEdgeIndex& idx_half_edge,
1910  const HalfEdgeIndex& idx_prev_half_edge)
1911  {
1912  assert(this->isValid(idx_half_edge));
1913  this->getHalfEdge(idx_half_edge).idx_prev_half_edge_ = idx_prev_half_edge;
1914  }
1915 
1916  /** \brief Set the face index to a given half-edge. */
1917  inline void
1918  setFaceIndex(const HalfEdgeIndex& idx_half_edge, const FaceIndex& idx_face)
1919  {
1920  assert(this->isValid(idx_half_edge));
1921  this->getHalfEdge(idx_half_edge).idx_face_ = idx_face;
1922  }
1923 
1924  /** \brief Set the inner half-edge index to a given face. */
1925  inline void
1927  const HalfEdgeIndex& idx_inner_half_edge)
1928  {
1929  assert(this->isValid(idx_face));
1930  this->getFace(idx_face).idx_inner_half_edge_ = idx_inner_half_edge;
1931  }
1932 
1933  ////////////////////////////////////////////////////////////////////////
1934  // isBoundary / isManifold
1935  ////////////////////////////////////////////////////////////////////////
1936 
1937  /** \brief Check if any vertex of the face lies on the boundary. */
1938  bool
1939  isBoundary(const FaceIndex& idx_face, std::true_type /*check_vertices*/) const
1940  {
1942  const VertexAroundFaceCirculator circ_end = circ;
1943 
1944  do {
1945  if (this->isBoundary(circ.getTargetIndex())) {
1946  return (true);
1947  }
1948  } while (++circ != circ_end);
1949 
1950  return (false);
1951  }
1952 
1953  /** \brief Check if any edge of the face lies on the boundary. */
1954  bool
1955  isBoundary(const FaceIndex& idx_face, std::false_type /*check_vertices*/) const
1956  {
1958  this->getOuterHalfEdgeAroundFaceCirculator(idx_face);
1959  const OuterHalfEdgeAroundFaceCirculator circ_end = circ;
1960 
1961  do {
1962  if (this->isBoundary(circ.getTargetIndex())) {
1963  return (true);
1964  }
1965  } while (++circ != circ_end);
1966 
1967  return (false);
1968  }
1969 
1970  /** \brief Always manifold. */
1971  inline bool
1972  isManifold(const VertexIndex&, std::true_type /*is_manifold*/) const
1973  {
1974  return (true);
1975  }
1976 
1977  /** \brief Check if the given vertex is manifold. */
1978  bool
1979  isManifold(const VertexIndex& idx_vertex, std::false_type /*is_manifold*/) const
1980  {
1983  const OutgoingHalfEdgeAroundVertexCirculator circ_end = circ;
1984 
1985  if (!this->isBoundary((circ++).getTargetIndex()))
1986  return (true);
1987  do {
1988  if (this->isBoundary(circ.getTargetIndex()))
1989  return (false);
1990  } while (++circ != circ_end);
1991 
1992  return (true);
1993  }
1994 
1995  /** \brief Always manifold. */
1996  inline bool
1997  isManifold(std::true_type /*is_manifold*/) const
1998  {
1999  return (true);
2000  }
2001 
2002  /** \brief Check if all vertices in the mesh are manifold. */
2003  bool
2004  isManifold(std::false_type /*is_manifold*/) const
2005  {
2006  for (std::size_t i = 0; i < this->sizeVertices(); ++i) {
2007  if (!this->isManifold(VertexIndex(i)))
2008  return (false);
2009  }
2010  return (true);
2011  }
2012 
2013  ////////////////////////////////////////////////////////////////////////
2014  // reserveData / resizeData / clearData
2015  ////////////////////////////////////////////////////////////////////////
2016 
2017  /** \brief Reserve storage space for the mesh data. */
2018  template <class DataCloudT>
2019  inline void
2020  reserveData(DataCloudT& cloud, const std::size_t n, std::true_type /*has_data*/) const
2021  {
2022  cloud.reserve(n);
2023  }
2024 
2025  /** \brief Does nothing */
2026  template <class DataCloudT>
2027  inline void
2028  reserveData(DataCloudT& /*cloud*/,
2029  const std::size_t /*n*/,
2030  std::false_type /*has_data*/) const
2031  {}
2032 
2033  /** \brief Resize the mesh data. */
2034  template <class DataCloudT>
2035  inline void
2036  resizeData(DataCloudT& data_cloud,
2037  const std::size_t n,
2038  const typename DataCloudT::value_type& data,
2039  std::true_type /*has_data*/) const
2040  {
2041  data_cloud.resize(n, data);
2042  }
2043 
2044  /** \brief Does nothing. */
2045  template <class DataCloudT>
2046  inline void
2047  resizeData(DataCloudT& /*data_cloud*/,
2048  const std::size_t /*n*/,
2049  const typename DataCloudT::value_type& /*data*/,
2050  std::false_type /*has_data*/) const
2051  {}
2052 
2053  /** \brief Clear the mesh data. */
2054  template <class DataCloudT>
2055  inline void
2056  clearData(DataCloudT& cloud, std::true_type /*has_data*/) const
2057  {
2058  cloud.clear();
2059  }
2060 
2061  /** \brief Does nothing. */
2062  template <class DataCloudT>
2063  inline void
2064  clearData(DataCloudT& /*cloud*/, std::false_type /*has_data*/) const
2065  {}
2066 
2067  ////////////////////////////////////////////////////////////////////////
2068  // get / set Vertex
2069  ////////////////////////////////////////////////////////////////////////
2070 
2071  /** \brief Get the vertex for the given index. */
2072  inline Vertex&
2073  getVertex(const VertexIndex& idx_vertex)
2074  {
2075  assert(this->isValid(idx_vertex));
2076  return (vertices_[idx_vertex.get()]);
2077  }
2078 
2079  /** \brief Get the vertex for the given index. */
2080  inline Vertex
2081  getVertex(const VertexIndex& idx_vertex) const
2082  {
2083  assert(this->isValid(idx_vertex));
2084  return (vertices_[idx_vertex.get()]);
2085  }
2086 
2087  /** \brief Set the vertex at the given index. */
2088  inline void
2089  setVertex(const VertexIndex& idx_vertex, const Vertex& vertex)
2090  {
2091  assert(this->isValid(idx_vertex));
2092  vertices_[idx_vertex.get()] = vertex;
2093  }
2094 
2095  ////////////////////////////////////////////////////////////////////////
2096  // get / set HalfEdge
2097  ////////////////////////////////////////////////////////////////////////
2098 
2099  /** \brief Get the half-edge for the given index. */
2100  inline HalfEdge&
2102  {
2103  assert(this->isValid(idx_he));
2104  return (half_edges_[idx_he.get()]);
2105  }
2106 
2107  /** \brief Get the half-edge for the given index. */
2108  inline HalfEdge
2109  getHalfEdge(const HalfEdgeIndex& idx_he) const
2110  {
2111  assert(this->isValid(idx_he));
2112  return (half_edges_[idx_he.get()]);
2113  }
2114 
2115  /** \brief Set the half-edge at the given index. */
2116  inline void
2117  setHalfEdge(const HalfEdgeIndex& idx_he, const HalfEdge& half_edge)
2118  {
2119  assert(this->isValid(idx_he));
2120  half_edges_[idx_he.get()] = half_edge;
2121  }
2122 
2123  ////////////////////////////////////////////////////////////////////////
2124  // get / set Face
2125  ////////////////////////////////////////////////////////////////////////
2126 
2127  /** \brief Get the face for the given index. */
2128  inline Face&
2129  getFace(const FaceIndex& idx_face)
2130  {
2131  assert(this->isValid(idx_face));
2132  return (faces_[idx_face.get()]);
2133  }
2134 
2135  /** \brief Get the face for the given index. */
2136  inline Face
2137  getFace(const FaceIndex& idx_face) const
2138  {
2139  assert(this->isValid(idx_face));
2140  return (faces_[idx_face.get()]);
2141  }
2142 
2143  /** \brief Set the face at the given index. */
2144  inline void
2145  setFace(const FaceIndex& idx_face, const Face& face)
2146  {
2147  assert(this->isValid(idx_face));
2148  faces_[idx_face.get()] = face;
2149  }
2150 
2151 private:
2152  ////////////////////////////////////////////////////////////////////////
2153  // Members
2154  ////////////////////////////////////////////////////////////////////////
2155 
2156  /** \brief Data stored for the vertices. */
2157  VertexDataCloud vertex_data_cloud_;
2158 
2159  /** \brief Data stored for the half-edges. */
2160  HalfEdgeDataCloud half_edge_data_cloud_;
2161 
2162  /** \brief Data stored for the edges. */
2163  EdgeDataCloud edge_data_cloud_;
2164 
2165  /** \brief Data stored for the faces. */
2166  FaceDataCloud face_data_cloud_;
2167 
2168  /** \brief Connectivity information for the vertices. */
2169  Vertices vertices_;
2170 
2171  /** \brief Connectivity information for the half-edges. */
2172  HalfEdges half_edges_;
2173 
2174  /** \brief Connectivity information for the faces. */
2175  Faces faces_;
2176 
2177  // NOTE: It is MUCH faster to store these variables permanently.
2178 
2179  /** \brief Storage for addFaceImplBase and deleteFace. */
2180  HalfEdgeIndices inner_he_;
2181 
2182  /** \brief Storage for addFaceImplBase. */
2183  HalfEdgeIndices free_he_;
2184 
2185  /** \brief Storage for addFaceImplBase. */
2186  std::vector<bool> is_new_;
2187 
2188  /** \brief Storage for addFaceImplBase. */
2189  std::vector<bool> make_adjacent_;
2190 
2191  /** \brief Storage for deleteFace. */
2192  std::vector<bool> is_boundary_;
2193 
2194  /** \brief Storage for deleteVertex. */
2195  FaceIndices delete_faces_vertex_;
2196 
2197  /** \brief Storage for deleteFace. */
2198  FaceIndices delete_faces_face_;
2199 
2200 public:
2201  template <class MeshT>
2203 
2205 };
2206 } // End namespace geometry
2207 } // End namespace pcl
void push_back(const PointT &pt)
Insert a new point in the cloud, at the end of the container.
Definition: point_cloud.h:663
const PointT & front() const
Definition: point_cloud.h:535
void resize(std::size_t count)
Resizes the container to contain count elements.
Definition: point_cloud.h:462
const PointT & back() const
Definition: point_cloud.h:537
std::size_t size() const
Definition: point_cloud.h:443
iterator begin() noexcept
Definition: point_cloud.h:429
void invalidate()
Invalidate the index.
Definition: mesh_indices.h:94
bool isValid() const
Returns true if the index is valid.
Definition: mesh_indices.h:87
int get() const
Get the index.
Definition: mesh_indices.h:101
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 face of the outgoing half-ed...
FaceIndex getTargetIndex() const
Get the index to the target face.
A face is a closed loop of edges.
An edge is a connection between two vertices.
Circulates counter-clockwise around a vertex and returns an index to the incoming half-edge (the targ...
HalfEdgeIndex getTargetIndex() const
Get the index to the incoming half-edge.
Circulates clockwise around a face and returns an index to the inner half-edge (the target).
HalfEdgeIndex getTargetIndex() const
Get the index to the inner half-edge.
Base class for the half-edge mesh.
Definition: mesh_base.h:96
void setOutgoingHalfEdgeIndex(const VertexIndex &idx_vertex, const HalfEdgeIndex &idx_outgoing_half_edge)
Set the outgoing half-edge index to a given vertex.
Definition: mesh_base.h:1882
HalfEdgeIndex getNextHalfEdgeIndex(const HalfEdgeIndex &idx_half_edge) const
Get the next half-edge index to a given half-edge.
Definition: mesh_base.h:405
std::vector< Face > Faces
Definition: mesh_base.h:1150
shared_ptr< const Self > ConstPtr
Definition: mesh_base.h:100
bool isDeleted(const FaceIndex &idx_face) const
Check if the given face is marked as deleted.
Definition: mesh_base.h:704
void setNextHalfEdgeIndex(const HalfEdgeIndex &idx_half_edge, const HalfEdgeIndex &idx_next_half_edge)
Set the next half_edge index to a given half-edge.
Definition: mesh_base.h:1900
bool emptyVertices() const
Check if the vertices are empty.
Definition: mesh_base.h:847
FaceDataCloud getFaceDataCloud() const
Get the stored face data.
Definition: mesh_base.h:1064
std::integral_constant< bool, !std::is_same< VertexData, pcl::geometry::NoData >::value > HasVertexData
Definition: mesh_base.h:120
bool isBoundary(const VertexIndex &idx_vertex) const
Check if the given vertex lies on the boundary.
Definition: mesh_base.h:729
VertexAroundVertexCirculator getVertexAroundVertexCirculator(const HalfEdgeIndex &idx_outgoing_half_edge) const
Definition: mesh_base.h:469
pcl::geometry::IncomingHalfEdgeAroundVertexCirculator< const Self > IncomingHalfEdgeAroundVertexCirculator
Definition: mesh_base.h:153
InnerHalfEdgeAroundFaceCirculator getInnerHalfEdgeAroundFaceCirculator(const HalfEdgeIndex &idx_inner_half_edge) const
Definition: mesh_base.h:551
MeshBase()
Constructor.
Definition: mesh_base.h:165
bool isBoundary(const FaceIndex &idx_face, std::true_type) const
Check if any vertex of the face lies on the boundary.
Definition: mesh_base.h:1939
void deleteEdge(const EdgeIndex &idx_edge)
Mark the given edge (both half-edges) and the associated faces as deleted.
Definition: mesh_base.h:269
VertexAroundVertexCirculator getVertexAroundVertexCirculator(const VertexIndex &idx_vertex) const
Definition: mesh_base.h:461
pcl::geometry::OuterHalfEdgeAroundFaceCirculator< const Self > OuterHalfEdgeAroundFaceCirculator
Definition: mesh_base.h:161
void deleteFace(const FaceIndex &idx_face)
Mark the given face as deleted.
Definition: mesh_base.h:283
std::vector< Vertex > Vertices
Definition: mesh_base.h:1148
EdgeIndex getEdgeIndex(const EdgeData &edge_data) const
Get the index associated to the given edge data.
Definition: mesh_base.h:1116
HalfEdgeIndex getOppositeHalfEdgeIndex(const HalfEdgeIndex &idx_half_edge) const
Get the opposite half-edge index to a given half-edge.
Definition: mesh_base.h:395
HalfEdgeIndex getOuterHalfEdgeIndex(const FaceIndex &idx_face) const
Get the outer half-edge inex to a given face.
Definition: mesh_base.h:449
std::vector< EdgeIndex > EdgeIndices
Definition: mesh_base.h:144
bool emptyEdges() const
Check if the edges are empty.
Definition: mesh_base.h:854
VertexAroundFaceCirculator getVertexAroundFaceCirculator(const HalfEdgeIndex &idx_inner_half_edge) const
Definition: mesh_base.h:535
void setHalfEdge(const HalfEdgeIndex &idx_he, const HalfEdge &half_edge)
Set the half-edge at the given index.
Definition: mesh_base.h:2117
FaceIndex connectFace(const HalfEdgeIndices &inner_he, const FaceData &face_data)
Add a face to the mesh and connect it to the half-edges.
Definition: mesh_base.h:1419
HalfEdgeIndex getHalfEdgeIndex(const HalfEdgeData &half_edge_data) const
Get the index associated to the given half-edge data.
Definition: mesh_base.h:1103
void resizeData(DataCloudT &data_cloud, const std::size_t n, const typename DataCloudT::value_type &data, std::true_type) const
Resize the mesh data.
Definition: mesh_base.h:2036
HalfEdgeDataCloud getHalfEdgeDataCloud() const
Get the stored half-edge data.
Definition: mesh_base.h:995
pcl::geometry::Vertex Vertex
Definition: mesh_base.h:1144
bool isBoundary(const HalfEdgeIndex &idx_he) const
Check if the given half-edge lies on the boundary.
Definition: mesh_base.h:739
IncomingHalfEdgeAroundVertexCirculator getIncomingHalfEdgeAroundVertexCirculator(const VertexIndex &idx_vertex) const
Definition: mesh_base.h:494
std::size_t sizeVertices() const
Get the number of the vertices.
Definition: mesh_base.h:806
void reconnect(const HalfEdgeIndex &idx_he_ab, const HalfEdgeIndex &idx_he_bc, const bool is_boundary_ba, const bool is_boundary_cb)
Deconnect the input half-edges from the mesh and adjust the indices of the connected half-edges.
Definition: mesh_base.h:1641
void resizeVertices(const std::size_t n, const VertexData &data=VertexData())
Resize the the vertices to n elements.
Definition: mesh_base.h:902
bool setEdgeDataCloud(const EdgeDataCloud &edge_data_cloud)
Change the stored edge data.
Definition: mesh_base.h:1040
bool checkTopology1(const VertexIndex &idx_v_a, const VertexIndex &idx_v_b, HalfEdgeIndex &idx_he_ab, std::vector< bool >::reference is_new_ab, std::true_type) const
Check if the edge between the two vertices can be added.
Definition: mesh_base.h:1274
std::size_t sizeEdges() const
Get the number of the edges.
Definition: mesh_base.h:821
pcl::geometry::FaceIndex FaceIndex
Definition: mesh_base.h:140
InnerHalfEdgeAroundFaceCirculator getInnerHalfEdgeAroundFaceCirculator(const FaceIndex &idx_face) const
Definition: mesh_base.h:543
typename MeshTraitsT::EdgeData EdgeData
Definition: mesh_base.h:107
bool emptyFaces() const
Check if the faces are empty.
Definition: mesh_base.h:861
bool empty() const
Check if the mesh is empty.
Definition: mesh_base.h:840
IncomingHalfEdgeAroundVertexCirculator getIncomingHalfEdgeAroundVertexCirculator(const HalfEdgeIndex &idx_incoming_half_edge) const
Definition: mesh_base.h:502
void deleteVertex(const VertexIndex &idx_vertex)
Mark the given vertex and all connected half-edges and faces as deleted.
Definition: mesh_base.h:219
std::vector< FaceIndex > FaceIndices
Definition: mesh_base.h:145
void reserveData(DataCloudT &, const std::size_t, std::false_type) const
Does nothing.
Definition: mesh_base.h:2028
void connectOldNew(const HalfEdgeIndex &idx_he_ab, const HalfEdgeIndex &idx_he_bc, const VertexIndex &idx_v_b)
The second half-edge is new.
Definition: mesh_base.h:1499
bool setHalfEdgeDataCloud(const HalfEdgeDataCloud &half_edge_data_cloud)
Change the stored half-edge data.
Definition: mesh_base.h:1006
VertexIndex getOriginatingVertexIndex(const HalfEdgeIndex &idx_half_edge) const
Get the originating vertex index to a given half-edge.
Definition: mesh_base.h:386
std::size_t sizeFaces() const
Get the number of the faces.
Definition: mesh_base.h:829
void deleteEdge(const HalfEdgeIndex &idx_he)
Mark the given half-edge, the opposite half-edge and the associated faces as deleted.
Definition: mesh_base.h:246
void resizeData(DataCloudT &, const std::size_t, const typename DataCloudT::value_type &, std::false_type) const
Does nothing.
Definition: mesh_base.h:2047
typename HalfEdges::iterator HalfEdgeIterator
Definition: mesh_base.h:1153
typename MeshTraitsT::HalfEdgeData HalfEdgeData
Definition: mesh_base.h:106
void markDeleted(const FaceIndex &idx_face)
Mark the given face as deleted.
Definition: mesh_base.h:1765
OutgoingHalfEdgeAroundVertexCirculator getOutgoingHalfEdgeAroundVertexCirculator(const HalfEdgeIndex &idx_outgoing_half_edge) const
Definition: mesh_base.h:485
HalfEdgeIndex getInnerHalfEdgeIndex(const FaceIndex &idx_face) const
Get the inner half-edge index to a given face.
Definition: mesh_base.h:441
void addData(pcl::PointCloud< DataT > &, const DataT &, std::false_type)
Does nothing.
Definition: mesh_base.h:1561
pcl::PointCloud< VertexData > VertexDataCloud
Definition: mesh_base.h:131
void reconnectNBNB(const HalfEdgeIndex &idx_he_bc, const HalfEdgeIndex &idx_he_cb, const VertexIndex &idx_v_b, std::true_type)
Both edges are not on the boundary.
Definition: mesh_base.h:1688
HalfEdgeIndex getPrevHalfEdgeIndex(const HalfEdgeIndex &idx_half_edge) const
Get the previous half-edge index to a given half-edge.
Definition: mesh_base.h:413
bool setFaceDataCloud(const FaceDataCloud &face_data_cloud)
Change the stored face data.
Definition: mesh_base.h:1074
OuterHalfEdgeAroundFaceCirculator getOuterHalfEdgeAroundFaceCirculator(const HalfEdgeIndex &idx_inner_half_edge) const
Definition: mesh_base.h:567
void clearData(DataCloudT &, std::false_type) const
Does nothing.
Definition: mesh_base.h:2064
Vertex getVertex(const VertexIndex &idx_vertex) const
Get the vertex for the given index.
Definition: mesh_base.h:2081
pcl::geometry::FaceAroundFaceCirculator< const Self > FaceAroundFaceCirculator
Definition: mesh_base.h:162
FaceIndex addFaceImplBase(const VertexIndices &vertices, const FaceData &face_data, const EdgeData &edge_data, const HalfEdgeData &half_edge_data)
General implementation of addFace.
Definition: mesh_base.h:1162
typename Faces::const_iterator FaceConstIterator
Definition: mesh_base.h:1158
typename MeshTraitsT::VertexData VertexData
Definition: mesh_base.h:105
void markDeleted(const VertexIndex &idx_vertex)
Mark the given vertex as deleted.
Definition: mesh_base.h:1740
bool setVertexDataCloud(const VertexDataCloud &vertex_data_cloud)
Change the stored vertex data.
Definition: mesh_base.h:971
pcl::geometry::FaceAroundVertexCirculator< const Self > FaceAroundVertexCirculator
Definition: mesh_base.h:155
std::vector< HalfEdgeIndex > HalfEdgeIndices
Definition: mesh_base.h:143
void reserveFaces(const std::size_t n)
Reserve storage space for n faces.
Definition: mesh_base.h:890
EdgeDataCloud & getEdgeDataCloud()
Get access to the stored edge data.
Definition: mesh_base.h:1023
bool checkTopology2(const HalfEdgeIndex &, const HalfEdgeIndex &, const bool is_new_ab, const bool is_new_bc, const bool is_isolated_b, std::vector< bool >::reference, HalfEdgeIndex &, std::true_type) const
Check if the face may be added (mesh does not become non-manifold).
Definition: mesh_base.h:1327
bool isValid(const HalfEdgeIndex &idx_he) const
Check if the given half-edge index is a valid index into the mesh.
Definition: mesh_base.h:650
void markDeleted(const HalfEdgeIndex &idx_he)
Mark the given half-edge as deleted.
Definition: mesh_base.h:1748
std::size_t sizeHalfEdges() const
Get the number of the half-edges.
Definition: mesh_base.h:813
std::integral_constant< bool, !std::is_same< EdgeData, pcl::geometry::NoData >::value > HasEdgeData
Definition: mesh_base.h:126
void resizeEdges(const std::size_t n, const EdgeData &edge_data=EdgeData(), const HalfEdgeData he_data=HalfEdgeData())
Resize the edges to n elements (half-edges will hold 2*n elements).
Definition: mesh_base.h:910
void setVertex(const VertexIndex &idx_vertex, const Vertex &vertex)
Set the vertex at the given index.
Definition: mesh_base.h:2089
OutgoingHalfEdgeAroundVertexCirculator getOutgoingHalfEdgeAroundVertexCirculator(const VertexIndex &idx_vertex) const
Definition: mesh_base.h:477
std::integral_constant< bool, !std::is_same< FaceData, pcl::geometry::NoData >::value > HasFaceData
Definition: mesh_base.h:129
VertexIndex getVertexIndex(const VertexData &vertex_data) const
Get the index associated to the given vertex data.
Definition: mesh_base.h:1091
void assignIf(const ConstIteratorT, IteratorT, std::false_type) const
Does nothing.
Definition: mesh_base.h:1871
void addData(pcl::PointCloud< DataT > &cloud, const DataT &data, std::true_type)
Add mesh data.
Definition: mesh_base.h:1553
pcl::PointCloud< FaceData > FaceDataCloud
Definition: mesh_base.h:134
bool isManifold(std::true_type) const
Always manifold.
Definition: mesh_base.h:1997
bool isValid(const EdgeIndex &idx_edge) const
Check if the given edge index is a valid index into the mesh.
Definition: mesh_base.h:658
void connectNewNew(const HalfEdgeIndex &idx_he_ab, const HalfEdgeIndex &idx_he_bc, const VertexIndex &idx_v_b, std::false_type)
Both half-edges are new (non-manifold version).
Definition: mesh_base.h:1459
VertexAroundFaceCirculator getVertexAroundFaceCirculator(const FaceIndex &idx_face) const
Definition: mesh_base.h:527
pcl::geometry::VertexIndex VertexIndex
Definition: mesh_base.h:137
void setTerminatingVertexIndex(const HalfEdgeIndex &idx_half_edge, const VertexIndex &idx_terminating_vertex)
Set the terminating vertex index to a given half-edge.
Definition: mesh_base.h:1891
bool isValid(const FaceIndex &idx_face) const
Check if the given face index is a valid index into the mesh.
Definition: mesh_base.h:666
void reserveData(DataCloudT &cloud, const std::size_t n, std::true_type) const
Reserve storage space for the mesh data.
Definition: mesh_base.h:2020
void reserveEdges(const std::size_t n)
Reserve storage space for n edges (2*n storage space is reserved for the half-edges).
Definition: mesh_base.h:881
FaceIndex addFace(const VertexIndices &vertices, const FaceData &face_data=FaceData(), const EdgeData &edge_data=EdgeData(), const HalfEdgeData &half_edge_data=HalfEdgeData())
Add a face to the mesh.
Definition: mesh_base.h:203
pcl::geometry::HalfEdge HalfEdge
Definition: mesh_base.h:1145
Vertex & getVertex(const VertexIndex &idx_vertex)
Get the vertex for the given index.
Definition: mesh_base.h:2073
void connectPrevNext(const HalfEdgeIndex &idx_he_ab, const HalfEdgeIndex &idx_he_bc)
Connect the next and prev indices of the two half-edges with each other.
Definition: mesh_base.h:1435
bool isBoundary(const FaceIndex &idx_face) const
Check if the given face lies on the boundary.
Definition: mesh_base.h:773
bool isDeleted(const HalfEdgeIndex &idx_he) const
Check if the given half-edge is marked as deleted.
Definition: mesh_base.h:686
std::vector< HalfEdge > HalfEdges
Definition: mesh_base.h:1149
bool isIsolated(const VertexIndex &idx_vertex) const
Check if the given vertex is isolated (not connected to other elements).
Definition: mesh_base.h:716
void makeAdjacent(const HalfEdgeIndex &idx_he_ab, const HalfEdgeIndex &idx_he_bc, HalfEdgeIndex &idx_free_half_edge)
Make the half-edges bc the next half-edge of ab.
Definition: mesh_base.h:1393
Face getFace(const FaceIndex &idx_face) const
Get the face for the given index.
Definition: mesh_base.h:2137
void assignIf(const ConstIteratorT source, IteratorT target, std::true_type) const
Assign the source iterator to the target iterator.
Definition: mesh_base.h:1861
FaceAroundFaceCirculator getFaceAroundFaceCirculator(const FaceIndex &idx_face) const
Definition: mesh_base.h:575
bool isDeleted(const VertexIndex &idx_vertex) const
Check if the given vertex is marked as deleted.
Definition: mesh_base.h:678
HalfEdgeIndex getOutgoingHalfEdgeIndex(const VertexIndex &idx_vertex) const
Get the outgoing half-edge index to a given vertex.
Definition: mesh_base.h:358
typename Vertices::const_iterator VertexConstIterator
Definition: mesh_base.h:1156
bool isManifold(const VertexIndex &idx_vertex, std::false_type) const
Check if the given vertex is manifold.
Definition: mesh_base.h:1979
bool isBoundary(const FaceIndex &idx_face) const
Check if the given face lies on the boundary.
Definition: mesh_base.h:764
void setFace(const FaceIndex &idx_face, const Face &face)
Set the face at the given index.
Definition: mesh_base.h:2145
void connectNewNew(const HalfEdgeIndex &idx_he_ab, const HalfEdgeIndex &idx_he_bc, const VertexIndex &idx_v_b, std::true_type)
Both half-edges are new (manifold version).
Definition: mesh_base.h:1443
pcl::geometry::Face Face
Definition: mesh_base.h:1146
bool isEqualTopology(const Self &other) const
Check if the other mesh has the same topology as this mesh.
Definition: mesh_base.h:595
VertexIndex addVertex(const VertexData &vertex_data=VertexData())
Add a vertex to the mesh.
Definition: mesh_base.h:183
FaceAroundVertexCirculator getFaceAroundVertexCirculator(const HalfEdgeIndex &idx_outgoing_half_edge) const
Definition: mesh_base.h:519
VertexDataCloud getVertexDataCloud() const
Get the stored vertex data.
Definition: mesh_base.h:960
void setPrevHalfEdgeIndex(const HalfEdgeIndex &idx_half_edge, const HalfEdgeIndex &idx_prev_half_edge)
Set the previous half-edge index to a given half-edge.
Definition: mesh_base.h:1909
void reserveVertices(const std::size_t n)
Reserve storage space n vertices.
Definition: mesh_base.h:872
typename HalfEdges::const_iterator HalfEdgeConstIterator
Definition: mesh_base.h:1157
void resizeFaces(const std::size_t n, const FaceData &data=FaceData())
Resize the faces to n elements.
Definition: mesh_base.h:921
pcl::geometry::VertexAroundFaceCirculator< const Self > VertexAroundFaceCirculator
Definition: mesh_base.h:157
FaceIndex getOppositeFaceIndex(const HalfEdgeIndex &idx_half_edge) const
Get the face index to a given half-edge.
Definition: mesh_base.h:429
typename MeshTraitsT::IsManifold IsManifold
Definition: mesh_base.h:109
pcl::PointCloud< HalfEdgeData > HalfEdgeDataCloud
Definition: mesh_base.h:132
bool checkTopology2(const HalfEdgeIndex &idx_he_ab, const HalfEdgeIndex &idx_he_bc, const bool is_new_ab, const bool is_new_bc, const bool, std::vector< bool >::reference make_adjacent_ab_bc, HalfEdgeIndex &idx_free_half_edge, std::false_type) const
Check if the half-edge bc is the next half-edge of ab.
Definition: mesh_base.h:1349
typename MeshTraitsT::FaceData FaceData
Definition: mesh_base.h:108
pcl::geometry::InnerHalfEdgeAroundFaceCirculator< const Self > InnerHalfEdgeAroundFaceCirculator
Definition: mesh_base.h:159
HalfEdgeDataCloud & getHalfEdgeDataCloud()
Get access to the stored half-edge data.
Definition: mesh_base.h:988
void connectOldOld(const HalfEdgeIndex &, const HalfEdgeIndex &, const VertexIndex &, std::true_type)
Both half-edges are old (manifold version).
Definition: mesh_base.h:1515
void markDeleted(const EdgeIndex &idx_edge)
Mark the given edge (both half-edges) as deleted.
Definition: mesh_base.h:1756
std::vector< VertexIndex > VertexIndices
Definition: mesh_base.h:142
shared_ptr< Self > Ptr
Definition: mesh_base.h:99
void connectNewOld(const HalfEdgeIndex &idx_he_ab, const HalfEdgeIndex &idx_he_bc, const VertexIndex &idx_v_b)
The first half-edge is new.
Definition: mesh_base.h:1483
FaceAroundVertexCirculator getFaceAroundVertexCirculator(const VertexIndex &idx_vertex) const
Definition: mesh_base.h:511
pcl::geometry::VertexAroundVertexCirculator< const Self > VertexAroundVertexCirculator
Definition: mesh_base.h:149
pcl::geometry::EdgeIndex EdgeIndex
Definition: mesh_base.h:139
bool isValid(const VertexIndex &idx_vertex) const
Check if the given vertex index is a valid index into the mesh.
Definition: mesh_base.h:642
VertexIndex getTerminatingVertexIndex(const HalfEdgeIndex &idx_half_edge) const
Get the terminating vertex index to a given half-edge.
Definition: mesh_base.h:378
EdgeDataCloud getEdgeDataCloud() const
Get the stored edge data.
Definition: mesh_base.h:1030
VertexDataCloud & getVertexDataCloud()
Get access to the stored vertex data.
Definition: mesh_base.h:953
void deleteFace(const FaceIndex &idx_face, std::false_type)
Non-manifold version of deleteFace.
Definition: mesh_base.h:1592
void cleanUp()
Removes all mesh elements and data that are marked as deleted.
Definition: mesh_base.h:297
bool isManifold(std::false_type) const
Check if all vertices in the mesh are manifold.
Definition: mesh_base.h:2004
void clearData(DataCloudT &cloud, std::true_type) const
Clear the mesh data.
Definition: mesh_base.h:2056
FaceIndex getFaceIndex(const FaceData &face_data) const
Get the index associated to the given face data.
Definition: mesh_base.h:1128
void setFaceIndex(const HalfEdgeIndex &idx_half_edge, const FaceIndex &idx_face)
Set the face index to a given half-edge.
Definition: mesh_base.h:1918
HalfEdgeIndex addEdge(const VertexIndex &idx_v_a, const VertexIndex &idx_v_b, const HalfEdgeData &he_data, const EdgeData &edge_data)
Add an edge between the two given vertices and connect them with the vertices.
Definition: mesh_base.h:1246
std::integral_constant< bool, !std::is_same< HalfEdgeData, pcl::geometry::NoData >::value > HasHalfEdgeData
Definition: mesh_base.h:123
void setInnerHalfEdgeIndex(const FaceIndex &idx_face, const HalfEdgeIndex &idx_inner_half_edge)
Set the inner half-edge index to a given face.
Definition: mesh_base.h:1926
FaceIndex getFaceIndex(const HalfEdgeIndex &idx_half_edge) const
Get the face index to a given half-edge.
Definition: mesh_base.h:421
void incrementIf(IteratorT &, std::false_type) const
Does nothing.
Definition: mesh_base.h:1855
bool isBoundary(const FaceIndex &idx_face, std::false_type) const
Check if any edge of the face lies on the boundary.
Definition: mesh_base.h:1955
bool isDeleted(const EdgeIndex &idx_edge) const
Check if the given edge (any of the two half-edges) is marked as deleted.
Definition: mesh_base.h:695
void connectOldOld(const HalfEdgeIndex &, const HalfEdgeIndex &idx_he_bc, const VertexIndex &idx_v_b, std::false_type)
Both half-edges are old (non-manifold version).
Definition: mesh_base.h:1523
bool isBoundary(const EdgeIndex &idx_edge) const
Check if the given edge lies on the boundary (any of the two half-edges lies on the boundary.
Definition: mesh_base.h:748
void reconnectNBNB(const HalfEdgeIndex &idx_he_bc, const HalfEdgeIndex &, const VertexIndex &idx_v_b, std::false_type)
Both edges are not on the boundary.
Definition: mesh_base.h:1724
bool isManifold() const
Check if the mesh is manifold.
Definition: mesh_base.h:795
void deleteFace(const FaceIndex &idx_face, std::true_type)
Manifold version of deleteFace.
Definition: mesh_base.h:1574
bool isManifold(const VertexIndex &idx_vertex) const
Check if the given vertex is manifold.
Definition: mesh_base.h:785
OuterHalfEdgeAroundFaceCirculator getOuterHalfEdgeAroundFaceCirculator(const FaceIndex &idx_face) const
Definition: mesh_base.h:559
typename Vertices::iterator VertexIterator
Definition: mesh_base.h:1152
void clear()
Clear all mesh elements and data.
Definition: mesh_base.h:933
void incrementIf(IteratorT &it, std::true_type) const
Increment the iterator.
Definition: mesh_base.h:1847
FaceDataCloud & getFaceDataCloud()
Get access to the stored face data.
Definition: mesh_base.h:1057
pcl::geometry::OutgoingHalfEdgeAroundVertexCirculator< const Self > OutgoingHalfEdgeAroundVertexCirculator
Definition: mesh_base.h:151
IndexContainerT remove(ElementContainerT &elements, DataContainerT &data_cloud)
Removes mesh elements and data that are marked as deleted from the container.
Definition: mesh_base.h:1793
typename Faces::iterator FaceIterator
Definition: mesh_base.h:1154
pcl::geometry::HalfEdgeIndex HalfEdgeIndex
Definition: mesh_base.h:138
FaceAroundFaceCirculator getFaceAroundFaceCirculator(const HalfEdgeIndex &idx_inner_half_edge) const
Definition: mesh_base.h:583
HalfEdgeIndex getIncomingHalfEdgeIndex(const VertexIndex &idx_vertex) const
Get the incoming half-edge index to a given vertex.
Definition: mesh_base.h:366
bool checkTopology1(const VertexIndex &idx_v_a, const VertexIndex &idx_v_b, HalfEdgeIndex &idx_he_ab, std::vector< bool >::reference is_new_ab, std::false_type) const
Non manifold version of checkTopology1.
Definition: mesh_base.h:1295
pcl::PointCloud< EdgeData > EdgeDataCloud
Definition: mesh_base.h:133
HalfEdge & getHalfEdge(const HalfEdgeIndex &idx_he)
Get the half-edge for the given index.
Definition: mesh_base.h:2101
Face & getFace(const FaceIndex &idx_face)
Get the face for the given index.
Definition: mesh_base.h:2129
HalfEdge getHalfEdge(const HalfEdgeIndex &idx_he) const
Get the half-edge for the given index.
Definition: mesh_base.h:2109
bool isManifold(const VertexIndex &, std::true_type) const
Always manifold.
Definition: mesh_base.h:1972
Read / write the half-edge mesh from / to a file.
Definition: mesh_io.h:60
Circulates clockwise around a face and returns an index to the outer half-edge (the target).
HalfEdgeIndex getTargetIndex() const
Get the index to the outer half-edge.
Circulates counter-clockwise around a vertex and returns an index to the outgoing half-edge (the targ...
HalfEdgeIndex getTargetIndex() const
Get the index to the outgoing half-edge.
Circulates clockwise around a face and returns an index to the terminating vertex of the inner half-e...
VertexIndex getTargetIndex() const
Get the index to the target vertex.
Circulates counter-clockwise around a vertex and returns an index to the terminating vertex of the ou...
VertexIndex getTargetIndex() const
Get the index to the target vertex.
HalfEdgeIndex getCurrentHalfEdgeIndex() const
Get the half-edge that is currently stored in the circulator.
A vertex is a node in the mesh.
Definition: mesh_elements.h:65
#define PCL_MAKE_ALIGNED_OPERATOR_NEW
Macro to signal a class requires a custom allocator.
Definition: memory.h:86
pcl::detail::MeshIndex< struct FaceIndexTag > FaceIndex
Index used to access elements in the half-edge mesh.
Definition: mesh_indices.h:211
pcl::detail::MeshIndex< struct EdgeIndexTag > EdgeIndex
Index used to access elements in the half-edge mesh.
Definition: mesh_indices.h:205
pcl::detail::MeshIndex< struct HalfEdgeIndexTag > HalfEdgeIndex
Index used to access elements in the half-edge mesh.
Definition: mesh_indices.h:199
pcl::detail::MeshIndex< struct VertexIndexTag > VertexIndex
Index used to access elements in the half-edge mesh.
Definition: mesh_indices.h:193
Defines functions, macros and traits for allocating and using memory.
float distance(const PointT &p1, const PointT &p2)
Definition: geometry.h:60
HalfEdgeIndex toHalfEdgeIndex(const EdgeIndex &index, const bool get_first=true)
Convert the given edge index to a half-edge index.
Definition: mesh_indices.h:235
Defines all the PCL and non-PCL macros used.
Describes a set of vertices in a polygon mesh, by basically storing an array of indices.
Definition: Vertices.h:15