Point Cloud Library (PCL) 1.14.0
Loading...
Searching...
No Matches
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
60namespace pcl {
61namespace geometry {
62bool 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
71namespace pcl {
72namespace geometry {
73template <class MeshT>
74class MeshIO;
75} // End namespace geometry
76} // End namespace pcl
77
78////////////////////////////////////////////////////////////////////////////////
79// MeshBase
80////////////////////////////////////////////////////////////////////////////////
81
82namespace pcl {
83namespace 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 */
95template <class DerivedT, class MeshTraitsT, class MeshTagT>
96class MeshBase {
97public:
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>;
125 std::integral_constant<bool,
126 !std::is_same<EdgeData, pcl::geometry::NoData>::value>;
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
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));
272 this->deleteEdge(pcl::geometry::toHalfEdgeIndex(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 */
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) {
606 other.getOutgoingHalfEdgeIndex(VertexIndex(i)))
607 return (false);
608 }
609
610 for (std::size_t i = 0; i < this->sizeHalfEdges(); ++i) {
612 other.getTerminatingVertexIndex(HalfEdgeIndex(i)))
613 return (false);
614
615 if (this->getNextHalfEdgeIndex(HalfEdgeIndex(i)) !=
616 other.getNextHalfEdgeIndex(HalfEdgeIndex(i)))
617 return (false);
618
619 if (this->getPrevHalfEdgeIndex(HalfEdgeIndex(i)) !=
620 other.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)) !=
629 other.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
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
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
855 {
856 return (half_edges_.empty());
857 }
858
859 /** \brief Check if the faces are empty. */
860 inline bool
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
1138protected:
1139 ////////////////////////////////////////////////////////////////////////
1140 // Types
1141 ////////////////////////////////////////////////////////////////////////
1142
1143 // Elements
1145 using HalfEdge = pcl::geometry::HalfEdge;
1146 using Face = pcl::geometry::Face;
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
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
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
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
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
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
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
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 {
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();
1603 const InnerHalfEdgeAroundFaceCirculator circ_end = circ;
1604 do {
1605 inner_he_.push_back(circ.getTargetIndex());
1606 is_boundary_.push_back(
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
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
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 typename ElementContainerT::const_iterator it_e_old = elements.begin();
1808 auto it_e_new = elements.begin();
1809
1810 typename DataContainerT::const_iterator it_d_old = data_cloud.begin();
1811 auto it_d_new = data_cloud.begin();
1812
1813 auto it_ind_new = new_indices.begin();
1814 typename IndexContainerT::const_iterator it_ind_new_end = new_indices.end();
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
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
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 {
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
2151private:
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
2200public:
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.
const PointT & back() const
const PointT & front() const
void resize(std::size_t count)
Resizes the container to contain count elements.
std::size_t size() const
iterator begin() noexcept
void invalidate()
Invalidate the index.
bool isValid() const
Returns true if the index is valid.
int get() const
Get the index.
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.
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
VertexDataCloud & getVertexDataCloud()
Get access to the stored vertex data.
Definition mesh_base.h:953
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
Face & getFace(const FaceIndex &idx_face)
Get the face for the given index.
Definition mesh_base.h:2129
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
HalfEdgeDataCloud & getHalfEdgeDataCloud()
Get access to the stored half-edge data.
Definition mesh_base.h:988
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
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
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
EdgeDataCloud & getEdgeDataCloud()
Get access to the stored edge data.
Definition mesh_base.h:1023
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
HalfEdge & getHalfEdge(const HalfEdgeIndex &idx_he)
Get the half-edge for the given index.
Definition mesh_base.h:2101
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
Vertex & getVertex(const VertexIndex &idx_vertex)
Get the vertex for the given index.
Definition mesh_base.h:2073
pcl::geometry::InnerHalfEdgeAroundFaceCirculator< const Self > InnerHalfEdgeAroundFaceCirculator
Definition mesh_base.h:159
void connectOldOld(const HalfEdgeIndex &, const HalfEdgeIndex &, const VertexIndex &, std::true_type)
Both half-edges are old (manifold version).
Definition mesh_base.h:1515
FaceDataCloud & getFaceDataCloud()
Get access to the stored face data.
Definition mesh_base.h:1057
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
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
MeshBase< DerivedT, MeshTraitsT, MeshTagT > Self
Definition mesh_base.h:98
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
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) 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.
#define PCL_MAKE_ALIGNED_OPERATOR_NEW
Macro to signal a class requires a custom allocator.
Definition memory.h:63
Defines functions, macros and traits for allocating and using memory.
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