mesh_base.h
/*
* Software License Agreement (BSD License)
*
* Point Cloud Library (PCL) - www.pointclouds.org
* Copyright (c) 2009-2012, Willow Garage, Inc.
* Copyright (c) 2012-, Open Perception, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of the copyright holder(s) nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $Id$
*
*/
#pragma once
#include <pcl/geometry/boost.h>
#include <pcl/geometry/eigen.h>
#include <pcl/geometry/mesh_circulators.h>
#include <pcl/geometry/mesh_indices.h>
#include <pcl/geometry/mesh_elements.h>
#include <pcl/geometry/mesh_traits.h>
#include <pcl/pcl_macros.h>
#include <pcl/point_cloud.h>
#include <vector>
#include <type_traits>
////////////////////////////////////////////////////////////////////////////////
// Global variables used during testing
////////////////////////////////////////////////////////////////////////////////
#ifdef PCL_GEOMETRY_MESH_BASE_TEST_DELETE_FACE_MANIFOLD_2
namespace pcl
{
namespace geometry
{
bool g_pcl_geometry_mesh_base_test_delete_face_manifold_2_success;
} // End namespace geometry
} // End namespace pcl
#endif
////////////////////////////////////////////////////////////////////////////////
// Forward declarations
////////////////////////////////////////////////////////////////////////////////
namespace pcl
{
namespace geometry
{
template <class MeshT>
class MeshIO;
} // End namespace geometry
} // End namespace pcl
////////////////////////////////////////////////////////////////////////////////
// MeshBase
////////////////////////////////////////////////////////////////////////////////
namespace pcl
{
namespace geometry
{
/** \brief Base class for the half-edge mesh.
* \tparam DerivedT Has to implement the method 'addFaceImpl'. Please have a look at pcl::geometry::TriangleMesh, pcl::geometry::QuadMesh and pcl::geometry::PolygonMesh.
* \tparam MeshTraitsT Please have a look at pcl::geometry::DefaultMeshTraits.
* \tparam MeshTagT Tag describing the type of the mesh, e.g. TriangleMeshTag, QuadMeshTag, PolygonMeshTag.
* \author Martin Saelzle
* \ingroup geometry
* \todo Add documentation
*/
template <class DerivedT, class MeshTraitsT, class MeshTagT>
class MeshBase
{
public:
using Self = MeshBase <DerivedT, MeshTraitsT, MeshTagT>;
using Ptr = shared_ptr<Self>;
using ConstPtr = shared_ptr<const Self>;
using Derived = DerivedT;
// These have to be defined in the traits class.
using VertexData = typename MeshTraitsT::VertexData;
using HalfEdgeData = typename MeshTraitsT::HalfEdgeData;
using EdgeData = typename MeshTraitsT::EdgeData;
using FaceData = typename MeshTraitsT::FaceData;
using IsManifold = typename MeshTraitsT::IsManifold;
// Check if the mesh traits are defined correctly.
static_assert (std::is_convertible<IsManifold, bool>::value, "MeshTraitsT::IsManifold is not convertible to bool");
using MeshTag = MeshTagT;
// Data
using HasVertexData = std::integral_constant <bool, !std::is_same <VertexData , pcl::geometry::NoData>::value>;
using HasHalfEdgeData = std::integral_constant <bool, !std::is_same <HalfEdgeData, pcl::geometry::NoData>::value>;
using HasEdgeData = std::integral_constant <bool, !std::is_same <EdgeData , pcl::geometry::NoData>::value>;
using HasFaceData = std::integral_constant <bool, !std::is_same <FaceData , pcl::geometry::NoData>::value>;
using VertexDataCloud = pcl::PointCloud<VertexData>;
using HalfEdgeDataCloud = pcl::PointCloud<HalfEdgeData>;
using EdgeDataCloud = pcl::PointCloud<EdgeData>;
using FaceDataCloud = pcl::PointCloud<FaceData>;
// Indices
using VertexIndex = pcl::geometry::VertexIndex;
using HalfEdgeIndex = pcl::geometry::HalfEdgeIndex;
using EdgeIndex = pcl::geometry::EdgeIndex;
using FaceIndex = pcl::geometry::FaceIndex;
using VertexIndices = std::vector<VertexIndex>;
using HalfEdgeIndices = std::vector<HalfEdgeIndex>;
using EdgeIndices = std::vector<EdgeIndex>;
using FaceIndices = std::vector<FaceIndex>;
// Circulators
using VertexAroundVertexCirculator = pcl::geometry::VertexAroundVertexCirculator<const Self>;
using OutgoingHalfEdgeAroundVertexCirculator = pcl::geometry::OutgoingHalfEdgeAroundVertexCirculator<const Self>;
using IncomingHalfEdgeAroundVertexCirculator = pcl::geometry::IncomingHalfEdgeAroundVertexCirculator<const Self>;
using FaceAroundVertexCirculator = pcl::geometry::FaceAroundVertexCirculator<const Self>;
using VertexAroundFaceCirculator = pcl::geometry::VertexAroundFaceCirculator<const Self>;
using InnerHalfEdgeAroundFaceCirculator = pcl::geometry::InnerHalfEdgeAroundFaceCirculator<const Self>;
using OuterHalfEdgeAroundFaceCirculator = pcl::geometry::OuterHalfEdgeAroundFaceCirculator<const Self>;
using FaceAroundFaceCirculator = pcl::geometry::FaceAroundFaceCirculator<const Self>;
/** \brief Constructor. */
MeshBase ()
: vertex_data_cloud_ (),
half_edge_data_cloud_ (),
edge_data_cloud_ (),
face_data_cloud_ ()
{
}
////////////////////////////////////////////////////////////////////////
// addVertex / addFace / deleteVertex / deleteEdge / deleteFace / cleanUp
////////////////////////////////////////////////////////////////////////
/** \brief Add a vertex to the mesh.
* \param[in] vertex_data Data that is stored in the vertex. This is only added if the mesh has data associated with the vertices.
* \return Index to the new vertex.
*/
inline VertexIndex
addVertex (const VertexData& vertex_data=VertexData ())
{
vertices_.push_back (Vertex ());
this->addData (vertex_data_cloud_, vertex_data, HasVertexData ());
return (VertexIndex (static_cast <int> (this->sizeVertices () - 1)));
}
/** \brief Add a face to the mesh. Data is only added if it is associated with the elements. The last vertex is connected with the first one.
* \param[in] vertices Indices to the vertices of the new face.
* \param[in] face_data Data that is set for the face.
* \param[in] half_edge_data Data that is set for all added half-edges.
* \param[in] edge_data Data that is set for all added edges.
* \return Index to the new face. Failure is signaled by returning an invalid face index.
* \warning The vertices must be valid and unique (each vertex may be contained only once). Not complying with this requirement results in undefined behavior!
*/
inline FaceIndex
addFace (const VertexIndices& vertices,
const FaceData& face_data = FaceData (),
const EdgeData& edge_data = EdgeData (),
const HalfEdgeData& half_edge_data = HalfEdgeData ())
{
// NOTE: The derived class has to implement addFaceImpl. If needed it can use the general method addFaceImplBase.
return (static_cast <Derived*> (this)->addFaceImpl (vertices, face_data, edge_data, half_edge_data));
}
/** \brief Mark the given vertex and all connected half-edges and faces as deleted.
* \note Call cleanUp () to finally delete all mesh-elements.
*/
void
deleteVertex (const VertexIndex& idx_vertex)
{
assert (this->isValid (idx_vertex));
if (this->isDeleted (idx_vertex)) return;
delete_faces_vertex_.clear ();
FaceAroundVertexCirculator circ = this->getFaceAroundVertexCirculator (idx_vertex);
const FaceAroundVertexCirculator circ_end = circ;
do
{
if (circ.getTargetIndex ().isValid ()) // Check for boundary.
{
delete_faces_vertex_.push_back (circ.getTargetIndex ());
}
} while (++circ!=circ_end);
for (FaceIndices::const_iterator it = delete_faces_vertex_.begin (); it!=delete_faces_vertex_.end (); ++it)
{
this->deleteFace (*it);
}
}
/** \brief Mark the given half-edge, the opposite half-edge and the associated faces as deleted.
* \note Call cleanUp () to finally delete all mesh-elements.
*/
void
deleteEdge (const HalfEdgeIndex& idx_he)
{
assert (this->isValid (idx_he));
if (this->isDeleted (idx_he)) return;
HalfEdgeIndex opposite = this->getOppositeHalfEdgeIndex (idx_he);
if (this->isBoundary (idx_he)) this->markDeleted (idx_he);
else this->deleteFace (this->getFaceIndex (idx_he));
if (this->isBoundary (opposite)) this->markDeleted (opposite);
else this->deleteFace (this->getFaceIndex (opposite));
}
/** \brief Mark the given edge (both half-edges) and the associated faces as deleted.
* \note Call cleanUp () to finally delete all mesh-elements.
*/
inline void
deleteEdge (const EdgeIndex& idx_edge)
{
assert (this->isValid (idx_edge));
this->deleteEdge (pcl::geometry::toHalfEdgeIndex (idx_edge));
assert (this->isDeleted (pcl::geometry::toHalfEdgeIndex (idx_edge, false))); // Bug in this class!
}
/** \brief Mark the given face as deleted. More faces are deleted if the manifold mesh would become non-manifold.
* \note Call cleanUp () to finally delete all mesh-elements.
*/
inline void
deleteFace (const FaceIndex& idx_face)
{
assert (this->isValid (idx_face));
if (this->isDeleted (idx_face)) return;
this->deleteFace (idx_face, IsManifold ());
}
/** \brief Removes all mesh elements and data that are marked as deleted.
* \note This removes all isolated vertices as well.
*/
void
cleanUp ()
{
// Copy the non-deleted mesh elements and store the index to their new position
const VertexIndices new_vertex_indices =
this->remove <Vertices, VertexDataCloud, VertexIndices, HasVertexData>
(vertices_, vertex_data_cloud_);
const HalfEdgeIndices new_half_edge_indices =
this->remove <HalfEdges, HalfEdgeDataCloud, HalfEdgeIndices, HasHalfEdgeData>
(half_edges_, half_edge_data_cloud_);
const FaceIndices new_face_indices =
this->remove <Faces, FaceDataCloud, FaceIndices, HasFaceData>
(faces_, face_data_cloud_);
// Remove deleted edge data
if (HasEdgeData::value)
{
auto it_ed_old = edge_data_cloud_.begin ();
auto it_ed_new = edge_data_cloud_.begin ();
for (auto it_ind = new_half_edge_indices.cbegin (), it_ind_end = new_half_edge_indices.cend (); it_ind!=it_ind_end; it_ind+=2, ++it_ed_old)
{
if (it_ind->isValid ())
{
*it_ed_new++ = *it_ed_old;
}
}
edge_data_cloud_.resize (this->sizeEdges ());
}
// Adjust the indices
for (VertexIterator it = vertices_.begin (); it!=vertices_.end (); ++it)
{
if (it->idx_outgoing_half_edge_.isValid ())
{
it->idx_outgoing_half_edge_ = new_half_edge_indices [it->idx_outgoing_half_edge_.get ()];
}
}
for (HalfEdgeIterator it = half_edges_.begin (); it!=half_edges_.end (); ++it)
{
it->idx_terminating_vertex_ = new_vertex_indices [it->idx_terminating_vertex_.get ()];
it->idx_next_half_edge_ = new_half_edge_indices [it->idx_next_half_edge_.get ()];
it->idx_prev_half_edge_ = new_half_edge_indices [it->idx_prev_half_edge_.get ()];
if (it->idx_face_.isValid ())
{
it->idx_face_ = new_face_indices [it->idx_face_.get ()];
}
}
for (FaceIterator it = faces_.begin (); it!=faces_.end (); ++it)
{
it->idx_inner_half_edge_ = new_half_edge_indices [it->idx_inner_half_edge_.get ()];
}
}
////////////////////////////////////////////////////////////////////////
// Vertex connectivity
////////////////////////////////////////////////////////////////////////
/** \brief Get the outgoing half-edge index to a given vertex. */
inline HalfEdgeIndex
getOutgoingHalfEdgeIndex (const VertexIndex& idx_vertex) const
{
assert (this->isValid (idx_vertex));
return (this->getVertex (idx_vertex).idx_outgoing_half_edge_);
}
/** \brief Get the incoming half-edge index to a given vertex. */
inline HalfEdgeIndex
getIncomingHalfEdgeIndex (const VertexIndex& idx_vertex) const
{
assert (this->isValid (idx_vertex));
return (this->getOppositeHalfEdgeIndex (this->getOutgoingHalfEdgeIndex (idx_vertex)));
}
////////////////////////////////////////////////////////////////////////
// Half-edge connectivity
////////////////////////////////////////////////////////////////////////
/** \brief Get the terminating vertex index to a given half-edge. */
inline VertexIndex
getTerminatingVertexIndex (const HalfEdgeIndex& idx_half_edge) const
{
assert (this->isValid (idx_half_edge));
return (this->getHalfEdge (idx_half_edge).idx_terminating_vertex_);
}
/** \brief Get the originating vertex index to a given half-edge. */
inline VertexIndex
getOriginatingVertexIndex (const HalfEdgeIndex& idx_half_edge) const
{
assert (this->isValid (idx_half_edge));
return (this->getTerminatingVertexIndex (this->getOppositeHalfEdgeIndex (idx_half_edge)));
}
/** \brief Get the opposite half-edge index to a given half-edge. */
inline HalfEdgeIndex
getOppositeHalfEdgeIndex (const HalfEdgeIndex& idx_half_edge) const
{
assert (this->isValid (idx_half_edge));
// Check if the index is even or odd and return the other index.
return (HalfEdgeIndex (idx_half_edge.get () & 1 ? idx_half_edge.get () - 1 : idx_half_edge.get () + 1));
}
/** \brief Get the next half-edge index to a given half-edge. */
inline HalfEdgeIndex
getNextHalfEdgeIndex (const HalfEdgeIndex& idx_half_edge) const
{
assert (this->isValid (idx_half_edge));
return (this->getHalfEdge (idx_half_edge).idx_next_half_edge_);
}
/** \brief Get the previous half-edge index to a given half-edge. */
inline HalfEdgeIndex
getPrevHalfEdgeIndex (const HalfEdgeIndex& idx_half_edge) const
{
assert (this->isValid (idx_half_edge));
return (this->getHalfEdge (idx_half_edge).idx_prev_half_edge_);
}
/** \brief Get the face index to a given half-edge. */
inline FaceIndex
getFaceIndex (const HalfEdgeIndex& idx_half_edge) const
{
assert (this->isValid (idx_half_edge));
return (this->getHalfEdge (idx_half_edge).idx_face_);
}
/** \brief Get the face index to a given half-edge. */
inline FaceIndex
getOppositeFaceIndex (const HalfEdgeIndex& idx_half_edge) const
{
assert (this->isValid (idx_half_edge));
return (this->getFaceIndex (this->getOppositeHalfEdgeIndex (idx_half_edge)));
}
////////////////////////////////////////////////////////////////////////
// Face connectivity
////////////////////////////////////////////////////////////////////////
/** \brief Get the inner half-edge index to a given face. */
inline HalfEdgeIndex
getInnerHalfEdgeIndex (const FaceIndex& idx_face) const
{
assert (this->isValid (idx_face));
return (this->getFace (idx_face).idx_inner_half_edge_);
}
/** \brief Get the outer half-edge inex to a given face. */
inline HalfEdgeIndex
getOuterHalfEdgeIndex (const FaceIndex& idx_face) const
{
assert (this->isValid (idx_face));
return (this->getOppositeHalfEdgeIndex (this->getInnerHalfEdgeIndex (idx_face)));
}
////////////////////////////////////////////////////////////////////////
// Circulators
////////////////////////////////////////////////////////////////////////
/** \see pcl::geometry::VertexAroundVertexCirculator */
inline VertexAroundVertexCirculator
getVertexAroundVertexCirculator (const VertexIndex& idx_vertex) const
{
assert (this->isValid (idx_vertex));
return (VertexAroundVertexCirculator (idx_vertex, this));
}
/** \see pcl::geometry::VertexAroundVertexCirculator */
inline VertexAroundVertexCirculator
getVertexAroundVertexCirculator (const HalfEdgeIndex& idx_outgoing_half_edge) const
{
assert (this->isValid (idx_outgoing_half_edge));
return (VertexAroundVertexCirculator (idx_outgoing_half_edge, this));
}
/** \see pcl::geometry::OutgoingHalfEdgeAroundVertexCirculator */
inline OutgoingHalfEdgeAroundVertexCirculator
getOutgoingHalfEdgeAroundVertexCirculator (const VertexIndex& idx_vertex) const
{
assert (this->isValid (idx_vertex));
return (OutgoingHalfEdgeAroundVertexCirculator (idx_vertex, this));
}
/** \see pcl::geometry::OutgoingHalfEdgeAroundVertexCirculator */
inline OutgoingHalfEdgeAroundVertexCirculator
getOutgoingHalfEdgeAroundVertexCirculator (const HalfEdgeIndex& idx_outgoing_half_edge) const
{
assert (this->isValid (idx_outgoing_half_edge));
return (OutgoingHalfEdgeAroundVertexCirculator (idx_outgoing_half_edge, this));
}
/** \see pcl::geometry::IncomingHalfEdgeAroundVertexCirculator */
inline IncomingHalfEdgeAroundVertexCirculator
getIncomingHalfEdgeAroundVertexCirculator (const VertexIndex& idx_vertex) const
{
assert (this->isValid (idx_vertex));
return (IncomingHalfEdgeAroundVertexCirculator (idx_vertex, this));
}
/** \see pcl::geometry::IncomingHalfEdgeAroundVertexCirculator */
inline IncomingHalfEdgeAroundVertexCirculator
getIncomingHalfEdgeAroundVertexCirculator (const HalfEdgeIndex& idx_incoming_half_edge) const
{
assert (this->isValid (idx_incoming_half_edge));
return (IncomingHalfEdgeAroundVertexCirculator (idx_incoming_half_edge, this));
}
/** \see pcl::geometry::FaceAroundVertexCirculator */
inline FaceAroundVertexCirculator
getFaceAroundVertexCirculator (const VertexIndex& idx_vertex) const
{
assert (this->isValid (idx_vertex));
return (FaceAroundVertexCirculator (idx_vertex, this));
}
/** \see pcl::geometry::FaceAroundVertexCirculator */
inline FaceAroundVertexCirculator
getFaceAroundVertexCirculator (const HalfEdgeIndex& idx_outgoing_half_edge) const
{
assert (this->isValid (idx_outgoing_half_edge));
return (FaceAroundVertexCirculator (idx_outgoing_half_edge, this));
}
/** \see pcl::geometry::VertexAroundFaceCirculator */
inline VertexAroundFaceCirculator
getVertexAroundFaceCirculator (const FaceIndex& idx_face) const
{
assert (this->isValid (idx_face));
return (VertexAroundFaceCirculator (idx_face, this));
}
/** \see pcl::geometry::VertexAroundFaceCirculator */
inline VertexAroundFaceCirculator
getVertexAroundFaceCirculator (const HalfEdgeIndex& idx_inner_half_edge) const
{
assert (this->isValid (idx_inner_half_edge));
return (VertexAroundFaceCirculator (idx_inner_half_edge, this));
}
/** \see pcl::geometry::InnerHalfEdgeAroundFaceCirculator */
inline InnerHalfEdgeAroundFaceCirculator
getInnerHalfEdgeAroundFaceCirculator (const FaceIndex& idx_face) const
{
assert (this->isValid (idx_face));
return (InnerHalfEdgeAroundFaceCirculator (idx_face, this));
}
/** \see pcl::geometry::InnerHalfEdgeAroundFaceCirculator */
inline InnerHalfEdgeAroundFaceCirculator
getInnerHalfEdgeAroundFaceCirculator (const HalfEdgeIndex& idx_inner_half_edge) const
{
assert (this->isValid (idx_inner_half_edge));
return (InnerHalfEdgeAroundFaceCirculator (idx_inner_half_edge, this));
}
/** \see pcl::geometry::OuterHalfEdgeAroundFaceCirculator */
inline OuterHalfEdgeAroundFaceCirculator
getOuterHalfEdgeAroundFaceCirculator (const FaceIndex& idx_face) const
{
assert (this->isValid (idx_face));
return (OuterHalfEdgeAroundFaceCirculator (idx_face, this));
}
/** \see pcl::geometry::OuterHalfEdgeAroundFaceCirculator */
inline OuterHalfEdgeAroundFaceCirculator
getOuterHalfEdgeAroundFaceCirculator (const HalfEdgeIndex& idx_inner_half_edge) const
{
assert (this->isValid (idx_inner_half_edge));
return (OuterHalfEdgeAroundFaceCirculator (idx_inner_half_edge, this));
}
/** \see pcl::geometry::FaceAroundFaceCirculator */
inline FaceAroundFaceCirculator
getFaceAroundFaceCirculator (const FaceIndex& idx_face) const
{
assert (this->isValid (idx_face));
return (FaceAroundFaceCirculator (idx_face, this));
}
/** \see pcl::geometry::FaceAroundFaceCirculator */
inline FaceAroundFaceCirculator
getFaceAroundFaceCirculator (const HalfEdgeIndex& idx_inner_half_edge) const
{
assert (this->isValid (idx_inner_half_edge));
return (FaceAroundFaceCirculator (idx_inner_half_edge, this));
}
//////////////////////////////////////////////////////////////////////////
// isEqualTopology
//////////////////////////////////////////////////////////////////////////
/** \brief Check if the other mesh has the same topology as this mesh. */
bool
isEqualTopology (const Self& other) const
{
if (this->sizeVertices () != other.sizeVertices ()) return (false);
if (this->sizeHalfEdges () != other.sizeHalfEdges ()) return (false);
if (this->sizeFaces () != other.sizeFaces ()) return (false);
for (std::size_t i=0; i<this->sizeVertices (); ++i)
{
if (this->getOutgoingHalfEdgeIndex (VertexIndex (i)) !=
other.getOutgoingHalfEdgeIndex (VertexIndex (i))) return (false);
}
for (std::size_t i=0; i<this->sizeHalfEdges (); ++i)
{
if (this->getTerminatingVertexIndex (HalfEdgeIndex (i)) !=
other.getTerminatingVertexIndex (HalfEdgeIndex (i))) return (false);
if (this->getNextHalfEdgeIndex (HalfEdgeIndex (i)) !=
other.getNextHalfEdgeIndex (HalfEdgeIndex (i))) return (false);
if (this->getPrevHalfEdgeIndex (HalfEdgeIndex (i)) !=
other.getPrevHalfEdgeIndex (HalfEdgeIndex (i))) return (false);
if (this->getFaceIndex (HalfEdgeIndex (i)) !=
other.getFaceIndex (HalfEdgeIndex (i))) return (false);
}
for (std::size_t i=0; i<this->sizeFaces (); ++i)
{
if (this->getInnerHalfEdgeIndex (FaceIndex (i)) !=
other.getInnerHalfEdgeIndex (FaceIndex (i))) return (false);
}
return (true);
}
////////////////////////////////////////////////////////////////////////
// isValid
////////////////////////////////////////////////////////////////////////
/** \brief Check if the given vertex index is a valid index into the mesh. */
inline bool
isValid (const VertexIndex& idx_vertex) const
{
return (idx_vertex >= VertexIndex (0) && idx_vertex < VertexIndex (int (vertices_.size ())));
}
/** \brief Check if the given half-edge index is a valid index into the mesh. */
inline bool
isValid (const HalfEdgeIndex& idx_he) const
{
return (idx_he >= HalfEdgeIndex (0) && idx_he < HalfEdgeIndex (half_edges_.size ()));
}
/** \brief Check if the given edge index is a valid index into the mesh. */
inline bool
isValid (const EdgeIndex& idx_edge) const
{
return (idx_edge >= EdgeIndex (0) && idx_edge < EdgeIndex (half_edges_.size () / 2));
}
/** \brief Check if the given face index is a valid index into the mesh. */
inline bool
isValid (const FaceIndex& idx_face) const
{
return (idx_face >= FaceIndex (0) && idx_face < FaceIndex (faces_.size ()));
}
////////////////////////////////////////////////////////////////////////
// isDeleted
////////////////////////////////////////////////////////////////////////
/** \brief Check if the given vertex is marked as deleted. */
inline bool
isDeleted (const VertexIndex& idx_vertex) const
{
assert (this->isValid (idx_vertex));
return (!this->getOutgoingHalfEdgeIndex (idx_vertex).isValid ());
}
/** \brief Check if the given half-edge is marked as deleted. */
inline bool
isDeleted (const HalfEdgeIndex& idx_he) const
{
assert (this->isValid (idx_he));
return (!this->getTerminatingVertexIndex (idx_he).isValid ());
}
/** \brief Check if the given edge (any of the two half-edges) is marked as deleted. */
inline bool
isDeleted (const EdgeIndex& idx_edge) const
{
assert (this->isValid (idx_edge));
return (this->isDeleted (pcl::geometry::toHalfEdgeIndex (idx_edge, true)) ||
this->isDeleted (pcl::geometry::toHalfEdgeIndex (idx_edge, false)));
}
/** \brief Check if the given face is marked as deleted. */
inline bool
isDeleted (const FaceIndex& idx_face) const
{
assert (this->isValid (idx_face));
return (!this->getInnerHalfEdgeIndex (idx_face).isValid ());
}
////////////////////////////////////////////////////////////////////////
// isIsolated
////////////////////////////////////////////////////////////////////////
/** \brief Check if the given vertex is isolated (not connected to other elements). */
inline bool
isIsolated (const VertexIndex& idx_vertex) const
{
assert (this->isValid (idx_vertex));
return (!this->getOutgoingHalfEdgeIndex (idx_vertex).isValid ());
}
////////////////////////////////////////////////////////////////////////
// isBoundary
////////////////////////////////////////////////////////////////////////
/** \brief Check if the given vertex lies on the boundary. Isolated vertices are considered to be on the boundary. */
inline bool
isBoundary (const VertexIndex& idx_vertex) const
{
assert (this->isValid (idx_vertex));
if (this->isIsolated (idx_vertex)) return (true);
return (this->isBoundary (this->getOutgoingHalfEdgeIndex (idx_vertex)));
}
/** \brief Check if the given half-edge lies on the bounddary. */
inline bool
isBoundary (const HalfEdgeIndex& idx_he) const
{
assert (this->isValid (idx_he));
return (!this->getFaceIndex (idx_he).isValid ());
}
/** \brief Check if the given edge lies on the boundary (any of the two half-edges lies on the boundary. */
inline bool
isBoundary (const EdgeIndex& idx_edge) const
{
assert (this->isValid (idx_edge));
const HalfEdgeIndex& idx = pcl::geometry::toHalfEdgeIndex (idx_edge);
return (this->isBoundary (idx) || this->isBoundary (this->getOppositeHalfEdgeIndex (idx)));
}
/** \brief Check if the given face lies on the boundary. There are two versions of this method, selected by the template parameter.
* \tparam CheckVerticesT Check if any vertex lies on the boundary (true) or check if any edge lies on the boundary (false).
*/
template <bool CheckVerticesT> inline bool
isBoundary (const FaceIndex& idx_face) const
{
assert (this->isValid (idx_face));
return (this->isBoundary (idx_face, std::integral_constant <bool, CheckVerticesT> ()));
}
/** \brief Check if the given face lies on the boundary. This method uses isBoundary \c true which checks if any vertex lies on the boundary. */
inline bool
isBoundary (const FaceIndex& idx_face) const
{
assert (this->isValid (idx_face));
return (this->isBoundary (idx_face, std::true_type ()));
}
////////////////////////////////////////////////////////////////////////
// isManifold
////////////////////////////////////////////////////////////////////////
/** \brief Check if the given vertex is manifold. Isolated vertices are manifold. */
inline bool
isManifold (const VertexIndex& idx_vertex) const
{
assert (this->isValid (idx_vertex));
if (this->isIsolated (idx_vertex)) return (true);
return (this->isManifold (idx_vertex, IsManifold ()));
}
/** \brief Check if the mesh is manifold. */
inline bool
isManifold () const
{
return (this->isManifold (IsManifold ()));
}
////////////////////////////////////////////////////////////////////////
// size
////////////////////////////////////////////////////////////////////////
/** \brief Get the number of the vertices. */
inline std::size_t
sizeVertices () const
{
return (vertices_.size ());
}
/** \brief Get the number of the half-edges. */
inline std::size_t
sizeHalfEdges () const
{
assert (half_edges_.size () % 2 == 0); // This would be a bug in the mesh.
return (half_edges_.size ());
}
/** \brief Get the number of the edges. */
inline std::size_t
sizeEdges () const
{
assert (half_edges_.size () % 2 == 0); // This would be a bug in the mesh.
return (half_edges_.size () / 2);
}
/** \brief Get the number of the faces. */
inline std::size_t
sizeFaces () const
{
return (faces_.size ());
}
////////////////////////////////////////////////////////////////////////
// empty
////////////////////////////////////////////////////////////////////////
/** \brief Check if the mesh is empty. */
inline bool
empty () const
{
return (this->emptyVertices () && this->emptyEdges () && this->emptyFaces ());
}
/** \brief Check if the vertices are empty. */
inline bool
emptyVertices () const
{
return (vertices_.empty ());
}
/** \brief Check if the edges are empty. */
inline bool
emptyEdges () const
{
return (half_edges_.empty ());
}
/** \brief Check if the faces are empty. */
inline bool
emptyFaces () const
{
return (faces_.empty ());
}
////////////////////////////////////////////////////////////////////////
// reserve
////////////////////////////////////////////////////////////////////////
/** \brief Reserve storage space n vertices. */
inline void
reserveVertices (const std::size_t n)
{
vertices_.reserve (n);
this->reserveData (vertex_data_cloud_, n, HasVertexData ());
}
/** \brief Reserve storage space for n edges (2*n storage space is reserved for the half-edges). */
inline void
reserveEdges (const std::size_t n)
{
half_edges_.reserve (2*n);
this->reserveData (half_edge_data_cloud_, 2*n, HasHalfEdgeData ());
this->reserveData (edge_data_cloud_ , n, HasEdgeData ());
}
/** \brief Reserve storage space for n faces. */
inline void
reserveFaces (const std::size_t n)
{
faces_.reserve (n);
this->reserveData (face_data_cloud_, n, HasFaceData ());
}
////////////////////////////////////////////////////////////////////////
// resize
////////////////////////////////////////////////////////////////////////
/** \brief Resize the the vertices to n elements. */
inline void
resizeVertices (const std::size_t n, const VertexData& data = VertexData ())
{
vertices_.resize (n);
this->resizeData (vertex_data_cloud_, n, data, HasVertexData ());
}
/** \brief Resize the edges to n elements (half-edges will hold 2*n elements). */
inline void
resizeEdges (const std::size_t n,
const EdgeData& edge_data = EdgeData (),
const HalfEdgeData he_data = HalfEdgeData ())
{
half_edges_.resize (2*n);
this->resizeData (half_edge_data_cloud_, 2*n, he_data , HasHalfEdgeData ());
this->resizeData (edge_data_cloud_ , n, edge_data, HasEdgeData ());
}
/** \brief Resize the faces to n elements. */
inline void
resizeFaces (const std::size_t n, const FaceData& data = FaceData ())
{
faces_.resize (n);
this->resizeData (face_data_cloud_, n, data, HasFaceData ());
}
////////////////////////////////////////////////////////////////////////
// clear
////////////////////////////////////////////////////////////////////////
/** \brief Clear all mesh elements and data. */
void
clear ()
{
vertices_.clear ();
half_edges_.clear ();
faces_.clear ();
this->clearData (vertex_data_cloud_ , HasVertexData ());
this->clearData (half_edge_data_cloud_, HasHalfEdgeData ());
this->clearData (edge_data_cloud_ , HasEdgeData ());
this->clearData (face_data_cloud_ , HasFaceData ());
}
////////////////////////////////////////////////////////////////////////
// get / set the vertex data cloud
////////////////////////////////////////////////////////////////////////
/** \brief Get access to the stored vertex data.
* \warning Please make sure to NOT add or remove elements from the cloud.
*/
inline VertexDataCloud&
getVertexDataCloud ()
{
return (vertex_data_cloud_);
}
/** \brief Get the stored vertex data. */
inline VertexDataCloud
getVertexDataCloud () const
{
return (vertex_data_cloud_);
}
/** \brief Change the stored vertex data.
* \param[in] vertex_data_cloud The new vertex data. Must be the same as the current data.
* \return true if the cloud could be set.
*/
inline bool
setVertexDataCloud (const VertexDataCloud& vertex_data_cloud)
{
if (vertex_data_cloud.size () == vertex_data_cloud_.size ())
{
vertex_data_cloud_ = vertex_data_cloud;
return (true);
}
return (false);
}
////////////////////////////////////////////////////////////////////////
// get / set the half-edge data cloud
////////////////////////////////////////////////////////////////////////
/** \brief Get access to the stored half-edge data.
* \warning Please make sure to NOT add or remove elements from the cloud.
*/
inline HalfEdgeDataCloud&
getHalfEdgeDataCloud ()
{
return (half_edge_data_cloud_);
}
/** \brief Get the stored half-edge data. */
inline HalfEdgeDataCloud
getHalfEdgeDataCloud () const
{
return (half_edge_data_cloud_);
}
/** \brief Change the stored half-edge data.
* \param[in] half_edge_data_cloud The new half-edge data. Must be the same as the current data.
* \return true if the cloud could be set.
*/
inline bool
setHalfEdgeDataCloud (const HalfEdgeDataCloud& half_edge_data_cloud)
{
if (half_edge_data_cloud.size () == half_edge_data_cloud_.size ())
{
half_edge_data_cloud_ = half_edge_data_cloud;
return (true);
}
return (false);
}
////////////////////////////////////////////////////////////////////////
// get / set the edge data cloud
////////////////////////////////////////////////////////////////////////
/** \brief Get access to the stored edge data.
* \warning Please make sure to NOT add or remove elements from the cloud.
*/
inline EdgeDataCloud&
getEdgeDataCloud ()
{
return (edge_data_cloud_);
}
/** \brief Get the stored edge data. */
inline EdgeDataCloud
getEdgeDataCloud () const
{
return (edge_data_cloud_);
}
/** \brief Change the stored edge data.
* \param[in] edge_data_cloud The new edge data. Must be the same as the current data.
* \return true if the cloud could be set.
*/
inline bool
setEdgeDataCloud (const EdgeDataCloud& edge_data_cloud)
{
if (edge_data_cloud.size () == edge_data_cloud_.size ())
{
edge_data_cloud_ = edge_data_cloud;
return (true);
}
return (false);
}
////////////////////////////////////////////////////////////////////////
// get / set the face data cloud
////////////////////////////////////////////////////////////////////////
/** \brief Get access to the stored face data.
* \warning Please make sure to NOT add or remove elements from the cloud.
*/
inline FaceDataCloud&
getFaceDataCloud ()
{
return (face_data_cloud_);
}
/** \brief Get the stored face data. */
inline FaceDataCloud
getFaceDataCloud () const
{
return (face_data_cloud_);
}
/** \brief Change the stored face data.
* \param[in] face_data_cloud The new face data. Must be the same as the current data.
* \return true if the cloud could be set.
*/
inline bool
setFaceDataCloud (const FaceDataCloud& face_data_cloud)
{
if (face_data_cloud.size () == face_data_cloud_.size ())
{
face_data_cloud_ = face_data_cloud;
return (true);
}
return (false);
}
////////////////////////////////////////////////////////////////////////
// getVertexIndex / getHalfEdgeIndex / getEdgeIndex / getFaceIndex
////////////////////////////////////////////////////////////////////////
/** \brief Get the index associated to the given vertex data.
* \return Invalid index if the mesh does not have associated vertex data.
*/
inline VertexIndex
getVertexIndex (const VertexData& vertex_data) const
{
if (HasVertexData::value)
{
assert (&vertex_data >= &vertex_data_cloud_.front () && &vertex_data <= &vertex_data_cloud_.back ());
return (VertexIndex (std::distance (&vertex_data_cloud_.front (), &vertex_data)));
}
return (VertexIndex ());
}
/** \brief Get the index associated to the given half-edge data. */
inline HalfEdgeIndex
getHalfEdgeIndex (const HalfEdgeData& half_edge_data) const
{
if (HasHalfEdgeData::value)
{
assert (&half_edge_data >= &half_edge_data_cloud_.front () && &half_edge_data <= &half_edge_data_cloud_.back ());
return (HalfEdgeIndex (std::distance (&half_edge_data_cloud_.front (), &half_edge_data)));
}
return (HalfEdgeIndex ());
}
/** \brief Get the index associated to the given edge data. */
inline EdgeIndex
getEdgeIndex (const EdgeData& edge_data) const
{
if (HasEdgeData::value)
{
assert (&edge_data >= &edge_data_cloud_.front () && &edge_data <= &edge_data_cloud_.back ());
return (EdgeIndex (std::distance (&edge_data_cloud_.front (), &edge_data)));
}
return (EdgeIndex ());
}
/** \brief Get the index associated to the given face data. */
inline FaceIndex
getFaceIndex (const FaceData& face_data) const
{
if (HasFaceData::value)
{
assert (&face_data >= &face_data_cloud_.front () && &face_data <= &face_data_cloud_.back ());
return (FaceIndex (std::distance (&face_data_cloud_.front (), &face_data)));
}
return (FaceIndex ());
}
protected:
////////////////////////////////////////////////////////////////////////
// Types
////////////////////////////////////////////////////////////////////////
// Elements
using Vertex = pcl::geometry::Vertex;
using HalfEdge = pcl::geometry::HalfEdge;
using Face = pcl::geometry::Face;
using Vertices = std::vector<Vertex>;
using HalfEdges = std::vector<HalfEdge>;
using Faces = std::vector<Face>;
using VertexIterator = typename Vertices::iterator;
using HalfEdgeIterator = typename HalfEdges::iterator;
using FaceIterator = typename Faces::iterator;
using VertexConstIterator = typename Vertices::const_iterator;
using HalfEdgeConstIterator = typename HalfEdges::const_iterator;
using FaceConstIterator = typename Faces::const_iterator;
/** \brief General implementation of addFace. */
FaceIndex
addFaceImplBase (const VertexIndices& vertices,
const FaceData& face_data,
const EdgeData& edge_data,
const HalfEdgeData& half_edge_data)
{
const int n = static_cast<int> (vertices.size ());
if (n < 3) return (FaceIndex ());
// Check for topological errors
inner_he_.resize (n);
free_he_.resize (n);
is_new_.resize (n);
make_adjacent_.resize (n);
for (int i=0; i<n; ++i)
{
if (!this->checkTopology1 (vertices [i], vertices [(i+1)%n], inner_he_ [i], is_new_ [i], IsManifold ()))
{
return (FaceIndex ());
}
}
for (int i=0; i<n; ++i)
{
int j = (i+1)%n;
if (!this->checkTopology2 (inner_he_ [i], inner_he_ [j], is_new_ [i], is_new_ [j], this->isIsolated (vertices [j]), make_adjacent_ [i], free_he_ [i], IsManifold ()))
{
return (FaceIndex ());
}
}
// Reconnect the existing half-edges if needed
if (!IsManifold::value)
{
for (int i=0; i<n; ++i)
{
if (make_adjacent_ [i])
{
this->makeAdjacent (inner_he_ [i], inner_he_ [(i+1)%n], free_he_ [i]);
}
}
}
// Add new half-edges if needed
for (int i=0; i<n; ++i)
{
if (is_new_ [i])
{
inner_he_ [i] = this->addEdge (vertices [i], vertices [(i+1)%n], half_edge_data, edge_data);
}
}
// Connect
for (int i=0; i<n; ++i)
{
int j = (i+1)%n;
if ( is_new_ [i] && is_new_ [j]) this->connectNewNew (inner_he_ [i], inner_he_ [j], vertices [j], IsManifold ());
else if ( is_new_ [i] && !is_new_ [j]) this->connectNewOld (inner_he_ [i], inner_he_ [j], vertices [j]);
else if (!is_new_ [i] && is_new_ [j]) this->connectOldNew (inner_he_ [i], inner_he_ [j], vertices [j]);
else this->connectOldOld (inner_he_ [i], inner_he_ [j], vertices [j], IsManifold ());
}
return (this->connectFace (inner_he_, face_data));
}
////////////////////////////////////////////////////////////////////////
// addEdge
////////////////////////////////////////////////////////////////////////
/** \brief Add an edge between the two given vertices and connect them with the vertices.
* \param[in] idx_v_a The first vertex index
* \param[in] idx_v_b The second vertex index
* \param[in] he_data Data associated with the half-edges. This is only added if the mesh has data associated with the half-edges.
* \param[in] edge_data Data associated with the edge. This is only added if the mesh has data associated with the edges.
* \return Index to the half-edge from vertex a to vertex b.
*/
HalfEdgeIndex
addEdge (const VertexIndex& idx_v_a,
const VertexIndex& idx_v_b,
const HalfEdgeData& he_data,
const EdgeData& edge_data)
{
half_edges_.push_back (HalfEdge (idx_v_b));
half_edges_.push_back (HalfEdge (idx_v_a));
this->addData (half_edge_data_cloud_, he_data , HasHalfEdgeData ());
this->addData (half_edge_data_cloud_, he_data , HasHalfEdgeData ());
this->addData (edge_data_cloud_ , edge_data, HasEdgeData ());
return (HalfEdgeIndex (static_cast <int> (half_edges_.size () - 2)));
}
////////////////////////////////////////////////////////////////////////
// topology checks
////////////////////////////////////////////////////////////////////////
/** \brief Check if the edge between the two vertices can be added.
* \param[in] idx_v_a Index to the first vertex.
* \param[in] idx_v_b Index to the second vertex.
* \param[out] idx_he_ab Index to the half-edge ab if is_new_ab=false.
* \param[out] is_new_ab true if the edge between the vertices exists already. Must be initialized with true!
* \return true if the half-edge may be added.
*/
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 /*is_manifold*/) const
{
is_new_ab = true;
if (this->isIsolated (idx_v_a)) return (true);
idx_he_ab = this->getOutgoingHalfEdgeIndex (idx_v_a);
if (!this->isBoundary (idx_he_ab)) return (false);
if (this->getTerminatingVertexIndex (idx_he_ab) == idx_v_b) is_new_ab = false;
return (true);
}
/** \brief Non manifold version of checkTopology1 */
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 /*is_manifold*/) const
{
is_new_ab = true;
if (this->isIsolated (idx_v_a)) return (true);
if (!this->isBoundary (this->getOutgoingHalfEdgeIndex (idx_v_a))) return (false);
VertexAroundVertexCirculator circ = this->getVertexAroundVertexCirculator (this->getOutgoingHalfEdgeIndex (idx_v_a));
const VertexAroundVertexCirculator circ_end = circ;
do
{
if (circ.getTargetIndex () == idx_v_b)
{
idx_he_ab = circ.getCurrentHalfEdgeIndex ();
if (!this->isBoundary (idx_he_ab)) return (false);
is_new_ab = false;
return (true);
}
} while (++circ!=circ_end);
return (true);
}
/** \brief Check if the face may be added (mesh does not become non-manifold). */
inline bool
checkTopology2 (const HalfEdgeIndex& /*idx_he_ab*/,
const HalfEdgeIndex& /*idx_he_bc*/,
const bool is_new_ab,
const bool is_new_bc,
const bool is_isolated_b,
std::vector <bool>::reference /*make_adjacent_ab_bc*/,
HalfEdgeIndex& /*idx_free_half_edge*/,
std::true_type /*is_manifold*/) const
{
return !(is_new_ab && is_new_bc && !is_isolated_b);
}
/** \brief Check if the half-edge bc is the next half-edge of ab.
* \param[in] idx_he_ab Index to the half-edge between the vertices a and b.
* \param[in] idx_he_bc Index to the half-edge between the vertices b and c.
* \param[in] is_new_ab Half-edge ab is new.
* \param[in] is_new_bc Half-edge bc is new.
* \param[out] make_adjacent_ab_bc Half-edges ab and bc need to be made adjacent.
* \param[out] idx_free_half_edge Free half-edge (needed for makeAdjacent)
* \return true if addFace may be continued.
*/
inline bool
checkTopology2 (const HalfEdgeIndex& idx_he_ab,
const HalfEdgeIndex& idx_he_bc,
const bool is_new_ab,
const bool is_new_bc,
const bool /*is_isolated_b*/,
std::vector <bool>::reference make_adjacent_ab_bc,
HalfEdgeIndex& idx_free_half_edge,
std::false_type /*is_manifold*/) const
{
if (is_new_ab || is_new_bc)
{
make_adjacent_ab_bc = false;
return (true); // Make adjacent is only needed for two old half-edges
}
if (this->getNextHalfEdgeIndex (idx_he_ab) == idx_he_bc)
{
make_adjacent_ab_bc = false;
return (true); // already adjacent
}
make_adjacent_ab_bc = true;
// Find the next boundary half edge
IncomingHalfEdgeAroundVertexCirculator circ = this->getIncomingHalfEdgeAroundVertexCirculator (this->getOppositeHalfEdgeIndex (idx_he_bc));
do ++circ; while (!this->isBoundary (circ.getTargetIndex ()));
idx_free_half_edge = circ.getTargetIndex ();
// This would detach the faces around the vertex from each other.
return (circ.getTargetIndex () != idx_he_ab);
}
/** \brief Make the half-edges bc the next half-edge of ab.
* \param[in] idx_he_ab Index to the half-edge between the vertices a and b.
* \param[in] idx_he_bc Index to the half-edge between the vertices b and c.
* \param[in, out] idx_free_half_edge Free half-edge needed to re-connect the half-edges around vertex b.
*/
void
makeAdjacent (const HalfEdgeIndex& idx_he_ab,
const HalfEdgeIndex& idx_he_bc,
HalfEdgeIndex& idx_free_half_edge)
{
// Re-link. No references!
const HalfEdgeIndex idx_he_ab_next = this->getNextHalfEdgeIndex (idx_he_ab);
const HalfEdgeIndex idx_he_bc_prev = this->getPrevHalfEdgeIndex (idx_he_bc);
const HalfEdgeIndex idx_he_free_next = this->getNextHalfEdgeIndex (idx_free_half_edge);
this->connectPrevNext (idx_he_ab, idx_he_bc);
this->connectPrevNext (idx_free_half_edge, idx_he_ab_next);
this->connectPrevNext (idx_he_bc_prev, idx_he_free_next);
}
////////////////////////////////////////////////////////////////////////
// connect
////////////////////////////////////////////////////////////////////////
/** \brief Add a face to the mesh and connect it to the half-edges.
* \param[in] inner_he Inner half-edges of the face.
* \param[in] face_data Data that is stored in the face. This is only added if the mesh has data associated with the faces.
* \return Index to the new face.
*/
FaceIndex
connectFace (const HalfEdgeIndices& inner_he,
const FaceData& face_data)
{
faces_.push_back (Face (inner_he.back ()));
this->addData (face_data_cloud_, face_data, HasFaceData ());
const FaceIndex idx_face (static_cast <int> (this->sizeFaces () - 1));
for (const auto &idx_half_edge : inner_he)
{
this->setFaceIndex (idx_half_edge, idx_face);
}
return (idx_face);
}
/** \brief Connect the next and prev indices of the two half-edges with each other. */
inline void
connectPrevNext (const HalfEdgeIndex& idx_he_ab,
const HalfEdgeIndex& idx_he_bc)
{
this->setNextHalfEdgeIndex (idx_he_ab, idx_he_bc);
this->setPrevHalfEdgeIndex (idx_he_bc, idx_he_ab);
}
/** \brief Both half-edges are new (manifold version). */
void
connectNewNew (const HalfEdgeIndex& idx_he_ab,
const HalfEdgeIndex& idx_he_bc,
const VertexIndex& idx_v_b,
std::true_type /*is_manifold*/)
{
const HalfEdgeIndex idx_he_ba = this->getOppositeHalfEdgeIndex (idx_he_ab);
const HalfEdgeIndex idx_he_cb = this->getOppositeHalfEdgeIndex (idx_he_bc);
this->connectPrevNext (idx_he_ab, idx_he_bc);
this->connectPrevNext (idx_he_cb, idx_he_ba);
this->setOutgoingHalfEdgeIndex (idx_v_b, idx_he_ba);
}
/** \brief Both half-edges are new (non-manifold version). */
void
connectNewNew (const HalfEdgeIndex& idx_he_ab,
const HalfEdgeIndex& idx_he_bc,
const VertexIndex& idx_v_b,
std::false_type /*is_manifold*/)
{
if (this->isIsolated (idx_v_b))
{
this->connectNewNew (idx_he_ab, idx_he_bc, idx_v_b, std::true_type ());
}
else
{
const HalfEdgeIndex idx_he_ba = this->getOppositeHalfEdgeIndex (idx_he_ab);
const HalfEdgeIndex idx_he_cb = this->getOppositeHalfEdgeIndex (idx_he_bc);
// No references!
const HalfEdgeIndex idx_he_b_out = this->getOutgoingHalfEdgeIndex (idx_v_b);
const HalfEdgeIndex idx_he_b_out_prev = this->getPrevHalfEdgeIndex (idx_he_b_out);
this->connectPrevNext (idx_he_ab, idx_he_bc);
this->connectPrevNext (idx_he_cb, idx_he_b_out);
this->connectPrevNext (idx_he_b_out_prev, idx_he_ba);
}
}
/** \brief The first half-edge is new. */
void
connectNewOld (const HalfEdgeIndex& idx_he_ab,
const HalfEdgeIndex& idx_he_bc,
const VertexIndex& idx_v_b)
{
const HalfEdgeIndex idx_he_ba = this->getOppositeHalfEdgeIndex (idx_he_ab);
const HalfEdgeIndex idx_he_bc_prev = this->getPrevHalfEdgeIndex (idx_he_bc); // No reference!
this->connectPrevNext (idx_he_ab, idx_he_bc);
this->connectPrevNext (idx_he_bc_prev, idx_he_ba);
this->setOutgoingHalfEdgeIndex (idx_v_b, idx_he_ba);
}
/** \brief The second half-edge is new. */
void
connectOldNew (const HalfEdgeIndex& idx_he_ab,
const HalfEdgeIndex& idx_he_bc,
const VertexIndex& idx_v_b)
{
const HalfEdgeIndex idx_he_cb = this->getOppositeHalfEdgeIndex (idx_he_bc);
const HalfEdgeIndex idx_he_ab_next = this->getNextHalfEdgeIndex (idx_he_ab); // No reference!
this->connectPrevNext (idx_he_ab, idx_he_bc);
this->connectPrevNext (idx_he_cb, idx_he_ab_next);
this->setOutgoingHalfEdgeIndex (idx_v_b, idx_he_ab_next);
}
/** \brief Both half-edges are old (manifold version). */
void
connectOldOld (const HalfEdgeIndex& /*idx_he_ab*/,
const HalfEdgeIndex& /*idx_he_bc*/,
const VertexIndex& /*idx_v_b*/,
std::true_type /*is_manifold*/)
{
}
/** \brief Both half-edges are old (non-manifold version). */
void
connectOldOld (const HalfEdgeIndex& /*idx_he_ab*/,
const HalfEdgeIndex& idx_he_bc,
const VertexIndex& idx_v_b,
std::false_type /*is_manifold*/)
{
const HalfEdgeIndex& idx_he_b_out = this->getOutgoingHalfEdgeIndex (idx_v_b);
// The outgoing half edge MUST be a boundary half-edge (if there is one)
if (idx_he_b_out == idx_he_bc) // he_bc is no longer on the boundary
{
OutgoingHalfEdgeAroundVertexCirculator circ = this->getOutgoingHalfEdgeAroundVertexCirculator (idx_he_b_out);
const OutgoingHalfEdgeAroundVertexCirculator circ_end = circ;
while (++circ!=circ_end)
{
if (this->isBoundary (circ.getTargetIndex ()))
{
this->setOutgoingHalfEdgeIndex (idx_v_b, circ.getTargetIndex ());
return;
}
}
}
}
////////////////////////////////////////////////////////////////////////
// addData
////////////////////////////////////////////////////////////////////////
/** \brief Add mesh data. */
template <class DataT>
inline void
addData (pcl::PointCloud <DataT>& cloud, const DataT& data, std::true_type /*has_data*/)
{
cloud.push_back (data);
}
/** \brief Does nothing. */
template <class DataT>
inline void
addData (pcl::PointCloud <DataT>& /*cloud*/, const DataT& /*data*/, std::false_type /*has_data*/)
{
}
////////////////////////////////////////////////////////////////////////
// deleteFace
////////////////////////////////////////////////////////////////////////
/** \brief Manifold version of deleteFace. If the mesh becomes non-manifold due to the delete operation the faces around the non-manifold vertex are deleted until the mesh becomes manifold again. */
void
deleteFace (const FaceIndex& idx_face,
std::true_type /*is_manifold*/)
{
assert (this->isValid (idx_face));
delete_faces_face_.clear ();
delete_faces_face_.push_back (idx_face);
while (!delete_faces_face_.empty ())
{
const FaceIndex idx_face_cur = delete_faces_face_.back ();
delete_faces_face_.pop_back ();
// This calls the non-manifold version of deleteFace, which will call the manifold version of reconnect.
this->deleteFace (idx_face_cur, std::false_type ());
}
}
/** \brief Non-manifold version of deleteFace. */
void
deleteFace (const FaceIndex& idx_face,
std::false_type /*is_manifold*/)
{
assert (this->isValid (idx_face));
if (this->isDeleted (idx_face)) return;
// Store all half-edges in the face
inner_he_.clear ();
is_boundary_.clear ();
InnerHalfEdgeAroundFaceCirculator circ = this->getInnerHalfEdgeAroundFaceCirculator (idx_face);
const InnerHalfEdgeAroundFaceCirculator circ_end = circ;
do
{
inner_he_.push_back (circ.getTargetIndex ());
is_boundary_.push_back (this->isBoundary (this->getOppositeHalfEdgeIndex (circ.getTargetIndex ())));
} while (++circ != circ_end);
assert (inner_he_.size () >= 3); // Minimum should be a triangle.
const int n = static_cast <int> (inner_he_.size ());
int j;
if (IsManifold::value)
{
for (int i=0; i<n; ++i)
{
j = (i+1)%n;
this->reconnect (inner_he_ [i], inner_he_ [j], is_boundary_ [i], is_boundary_ [j]);
}
for (int i=0; i<n; ++i)
{
this->getHalfEdge (inner_he_ [i]).idx_face_.invalidate ();
}
}
else
{
for (int i=0; i<n; ++i)
{
j = (i+1)%n;
this->reconnect (inner_he_ [i], inner_he_ [j], is_boundary_ [i], is_boundary_ [j]);
this->getHalfEdge (inner_he_ [i]).idx_face_.invalidate ();
}
}
this->markDeleted (idx_face);
}
////////////////////////////////////////////////////////////////////////
// reconnect
////////////////////////////////////////////////////////////////////////
/** \brief Deconnect the input half-edges from the mesh and adjust the indices of the connected half-edges. */
void
reconnect (const HalfEdgeIndex& idx_he_ab,
const HalfEdgeIndex& idx_he_bc,
const bool is_boundary_ba,
const bool is_boundary_cb)
{
const HalfEdgeIndex idx_he_ba = this->getOppositeHalfEdgeIndex (idx_he_ab);
const HalfEdgeIndex idx_he_cb = this->getOppositeHalfEdgeIndex (idx_he_bc);
const VertexIndex idx_v_b = this->getTerminatingVertexIndex (idx_he_ab);
if (is_boundary_ba && is_boundary_cb) // boundary - boundary
{
const HalfEdgeIndex& idx_he_cb_next = this->getNextHalfEdgeIndex (idx_he_cb);
if (idx_he_cb_next == idx_he_ba) // Vertex b is isolated
{
this->markDeleted (idx_v_b);
}
else
{
this->connectPrevNext (this->getPrevHalfEdgeIndex (idx_he_ba), idx_he_cb_next);
this->setOutgoingHalfEdgeIndex (idx_v_b, idx_he_cb_next);
}
this->markDeleted (idx_he_ab);
this->markDeleted (idx_he_ba);
}
else if (is_boundary_ba && !is_boundary_cb) // boundary - no boundary
{
this->connectPrevNext (this->getPrevHalfEdgeIndex (idx_he_ba), idx_he_bc);
this->setOutgoingHalfEdgeIndex (idx_v_b, idx_he_bc);
this->markDeleted (idx_he_ab);
this->markDeleted (idx_he_ba);
}
else if (!is_boundary_ba && is_boundary_cb) // no boundary - boundary
{
const HalfEdgeIndex& idx_he_cb_next = this->getNextHalfEdgeIndex (idx_he_cb);
this->connectPrevNext (idx_he_ab, idx_he_cb_next);
this->setOutgoingHalfEdgeIndex (idx_v_b, idx_he_cb_next);
}
else // no boundary - no boundary
{
this->reconnectNBNB (idx_he_bc, idx_he_cb, idx_v_b, IsManifold ());
}
}
/** \brief Both edges are not on the boundary. Manifold version. */
void
reconnectNBNB (const HalfEdgeIndex& idx_he_bc,
const HalfEdgeIndex& idx_he_cb,
const VertexIndex& idx_v_b,
std::true_type /*is_manifold*/)
{
if (this->isBoundary (idx_v_b))
{
// Deletion of this face makes the mesh non-manifold
// -> delete the neighboring faces until it is manifold again
IncomingHalfEdgeAroundVertexCirculator circ = this->getIncomingHalfEdgeAroundVertexCirculator (idx_he_cb);
while (!this->isBoundary (circ.getTargetIndex ()))
{
delete_faces_face_.push_back (this->getFaceIndex ((circ++).getTargetIndex ()));
#ifdef PCL_GEOMETRY_MESH_BASE_TEST_DELETE_FACE_MANIFOLD_2
if (circ == this->getIncomingHalfEdgeAroundVertexCirculator (idx_he_cb)) // Abort infinity loop
{
// In a manifold mesh we can't invalidate the face while reconnecting!
// See the implementation of
// deleteFace (const FaceIndex& idx_face,
// std::false_type /*is_manifold*/)
pcl::geometry::g_pcl_geometry_mesh_base_test_delete_face_manifold_2_success = false;
return;
}
#endif
}
}
else
{
this->setOutgoingHalfEdgeIndex (idx_v_b, idx_he_bc);
}
}
/** \brief Both edges are not on the boundary. Non-manifold version. */
void
reconnectNBNB (const HalfEdgeIndex& idx_he_bc,
const HalfEdgeIndex& /*idx_he_cb*/,
const VertexIndex& idx_v_b,
std::false_type /*is_manifold*/)
{
if (!this->isBoundary (idx_v_b))
{
this->setOutgoingHalfEdgeIndex (idx_v_b, idx_he_bc);
}
}
////////////////////////////////////////////////////////////////////////
// markDeleted
////////////////////////////////////////////////////////////////////////
/** \brief Mark the given vertex as deleted. */
inline void
markDeleted (const VertexIndex& idx_vertex)
{
assert (this->isValid (idx_vertex));
this->getVertex (idx_vertex).idx_outgoing_half_edge_.invalidate ();
}
/** \brief Mark the given half-edge as deleted. */
inline void
markDeleted (const HalfEdgeIndex& idx_he)
{
assert (this->isValid (idx_he));
this->getHalfEdge (idx_he).idx_terminating_vertex_.invalidate ();
}
/** \brief Mark the given edge (both half-edges) as deleted. */
inline void
markDeleted (const EdgeIndex& idx_edge)
{
assert (this->isValid (idx_edge));
this->markDeleted (pcl::geometry::toHalfEdgeIndex (idx_edge, true));
this->markDeleted (pcl::geometry::toHalfEdgeIndex (idx_edge, false));
}
/** \brief Mark the given face as deleted. */
inline void
markDeleted (const FaceIndex& idx_face)
{
assert (this->isValid (idx_face));
this->getFace (idx_face).idx_inner_half_edge_.invalidate ();
}
////////////////////////////////////////////////////////////////////////
// For cleanUp
////////////////////////////////////////////////////////////////////////
/** \brief Removes mesh elements and data that are marked as deleted from the container.
* \tparam ElementContainerT e.g. std::vector <Vertex>
* \tparam DataContainerT e.g. std::vector <VertexData>
* \tparam IndexContainerT e.g. std::vector <VertexIndex>
* \tparam HasDataT Integral constant specifying if the mesh has data associated with the elements.
*
* \param[in, out] elements Container for the mesh elements. Resized to the new size.
* \param[in, out] data_cloud Container for the mesh data. Resized to the new size.
* \return Container with the same size as the old input data. Holds the indices to the new elements for each non-deleted element and an invalid index if it is deleted.
*/
template <class ElementContainerT, class DataContainerT, class IndexContainerT, class HasDataT> IndexContainerT
remove (ElementContainerT& elements, DataContainerT& data_cloud)
{
using Index = typename IndexContainerT::value_type;
using Element = typename ElementContainerT::value_type;
if (HasDataT::value) assert (elements.size () == data_cloud.size ());
else assert (data_cloud.empty ()); // Bug in this class!
IndexContainerT new_indices (elements.size (), typename IndexContainerT::value_type ());
Index ind_old (0), ind_new (0);
typename ElementContainerT::const_iterator it_e_old = elements.begin ();
typename ElementContainerT::iterator it_e_new = elements.begin ();
typename DataContainerT::const_iterator it_d_old = data_cloud.begin ();
typename DataContainerT::iterator it_d_new = data_cloud.begin ();
typename IndexContainerT::iterator it_ind_new = new_indices.begin ();
typename IndexContainerT::const_iterator it_ind_new_end = new_indices.end ();
while (it_ind_new!=it_ind_new_end)
{
if (!this->isDeleted (ind_old))
{
*it_ind_new = ind_new++;
// TODO: Test for self assignment?
*it_e_new++ = *it_e_old;
this->assignIf (it_d_old, it_d_new, HasDataT ());
this->incrementIf ( it_d_new, HasDataT ());
}
++ind_old;
++it_e_old;
this->incrementIf (it_d_old, HasDataT ());
++it_ind_new;
}
elements.resize (ind_new.get (), Element ());
if (HasDataT::value)
{
data_cloud.resize (ind_new.get ());
}
else if (it_d_old != data_cloud.begin () || it_d_new != data_cloud.begin ())
{
std::cerr << "TODO: Bug in MeshBase::remove!\n";
assert (false);
exit (EXIT_FAILURE);
}
return (new_indices);
}
/** \brief Increment the iterator. */
template <class IteratorT> inline void
incrementIf (IteratorT& it, std::true_type /*has_data*/) const
{
++it;
}
/** \brief Does nothing. */
template <class IteratorT> inline void
incrementIf (IteratorT& /*it*/, std::false_type /*has_data*/) const
{
}
/** \brief Assign the source iterator to the target iterator. */
template <class ConstIteratorT, class IteratorT> inline void
assignIf (const ConstIteratorT source, IteratorT target, std::true_type /*has_data*/) const
{
*target = *source;
}
/** \brief Does nothing. */
template <class ConstIteratorT, class IteratorT> inline void
assignIf (const ConstIteratorT /*source*/, IteratorT /*target*/, std::false_type /*has_data*/) const
{
}
////////////////////////////////////////////////////////////////////////
// Vertex / Half-edge / Face connectivity
////////////////////////////////////////////////////////////////////////
/** \brief Set the outgoing half-edge index to a given vertex. */
inline void
setOutgoingHalfEdgeIndex (const VertexIndex& idx_vertex, const HalfEdgeIndex& idx_outgoing_half_edge)
{
assert (this->isValid (idx_vertex));
this->getVertex (idx_vertex).idx_outgoing_half_edge_ = idx_outgoing_half_edge;
}
/** \brief Set the terminating vertex index to a given half-edge. */
inline void
setTerminatingVertexIndex (const HalfEdgeIndex& idx_half_edge, const VertexIndex& idx_terminating_vertex)
{
assert (this->isValid (idx_half_edge));
this->getHalfEdge (idx_half_edge).idx_terminating_vertex_ = idx_terminating_vertex;
}
/** \brief Set the next half_edge index to a given half-edge. */
inline void
setNextHalfEdgeIndex (const HalfEdgeIndex& idx_half_edge, const HalfEdgeIndex& idx_next_half_edge)
{
assert (this->isValid (idx_half_edge));
this->getHalfEdge (idx_half_edge).idx_next_half_edge_ = idx_next_half_edge;
}
/** \brief Set the previous half-edge index to a given half-edge. */
inline void
setPrevHalfEdgeIndex (const HalfEdgeIndex& idx_half_edge,
const HalfEdgeIndex& idx_prev_half_edge)
{
assert (this->isValid (idx_half_edge));
this->getHalfEdge (idx_half_edge).idx_prev_half_edge_ = idx_prev_half_edge;
}
/** \brief Set the face index to a given half-edge. */
inline void
setFaceIndex (const HalfEdgeIndex& idx_half_edge, const FaceIndex& idx_face)
{
assert (this->isValid (idx_half_edge));
this->getHalfEdge (idx_half_edge).idx_face_ = idx_face;
}
/** \brief Set the inner half-edge index to a given face. */
inline void
setInnerHalfEdgeIndex (const FaceIndex& idx_face, const HalfEdgeIndex& idx_inner_half_edge)
{
assert (this->isValid (idx_face));
this->getFace (idx_face).idx_inner_half_edge_ = idx_inner_half_edge;
}
////////////////////////////////////////////////////////////////////////
// isBoundary / isManifold
////////////////////////////////////////////////////////////////////////
/** \brief Check if any vertex of the face lies on the boundary. */
bool
isBoundary (const FaceIndex& idx_face, std::true_type /*check_vertices*/) const
{
VertexAroundFaceCirculator circ = this->getVertexAroundFaceCirculator (idx_face);
const VertexAroundFaceCirculator circ_end = circ;
do
{
if (this->isBoundary (circ.getTargetIndex ()))
{
return (true);
}
} while (++circ!=circ_end);
return (false);
}
/** \brief Check if any edge of the face lies on the boundary. */
bool
isBoundary (const FaceIndex& idx_face, std::false_type /*check_vertices*/) const
{
OuterHalfEdgeAroundFaceCirculator circ = this->getOuterHalfEdgeAroundFaceCirculator (idx_face);
const OuterHalfEdgeAroundFaceCirculator circ_end = circ;
do
{
if (this->isBoundary (circ.getTargetIndex ()))
{
return (true);
}
} while (++circ!=circ_end);
return (false);
}
/** \brief Always manifold. */
inline bool
isManifold (const VertexIndex&, std::true_type /*is_manifold*/) const
{
return (true);
}
/** \brief Check if the given vertex is manifold. */
bool
isManifold (const VertexIndex& idx_vertex, std::false_type /*is_manifold*/) const
{
OutgoingHalfEdgeAroundVertexCirculator circ = this->getOutgoingHalfEdgeAroundVertexCirculator (idx_vertex);
const OutgoingHalfEdgeAroundVertexCirculator circ_end = circ;
if (!this->isBoundary ((circ++).getTargetIndex ())) return (true);
do
{
if (this->isBoundary (circ.getTargetIndex ())) return (false);
} while (++circ != circ_end);
return (true);
}
/** \brief Always manifold. */
inline bool
isManifold (std::true_type /*is_manifold*/) const
{
return (true);
}
/** \brief Check if all vertices in the mesh are manifold. */
bool
isManifold (std::false_type /*is_manifold*/) const
{
for (std::size_t i=0; i<this->sizeVertices (); ++i)
{
if (!this->isManifold (VertexIndex (i))) return (false);
}
return (true);
}
////////////////////////////////////////////////////////////////////////
// reserveData / resizeData / clearData
////////////////////////////////////////////////////////////////////////
/** \brief Reserve storage space for the mesh data. */
template <class DataCloudT> inline void
reserveData (DataCloudT& cloud, const std::size_t n, std::true_type /*has_data*/) const
{
cloud.reserve (n);
}
/** \brief Does nothing */
template <class DataCloudT> inline void
reserveData (DataCloudT& /*cloud*/, const std::size_t /*n*/, std::false_type /*has_data*/) const
{
}
/** \brief Resize the mesh data. */
template <class DataCloudT> inline void
resizeData (DataCloudT& /*data_cloud*/, const std::size_t n, const typename DataCloudT::value_type& data, std::true_type /*has_data*/) const
{
data.resize (n, data);
}
/** \brief Does nothing. */
template <class DataCloudT> inline void
resizeData (DataCloudT& /*data_cloud*/, const std::size_t /*n*/, const typename DataCloudT::value_type& /*data*/, std::false_type /*has_data*/) const
{
}
/** \brief Clear the mesh data. */
template <class DataCloudT> inline void
clearData (DataCloudT& cloud, std::true_type /*has_data*/) const
{
cloud.clear ();
}
/** \brief Does nothing. */
template <class DataCloudT> inline void
clearData (DataCloudT& /*cloud*/, std::false_type /*has_data*/) const
{
}
////////////////////////////////////////////////////////////////////////
// get / set Vertex
////////////////////////////////////////////////////////////////////////
/** \brief Get the vertex for the given index. */
inline Vertex&
getVertex (const VertexIndex& idx_vertex)
{
assert (this->isValid (idx_vertex));
return (vertices_ [idx_vertex.get ()]);
}
/** \brief Get the vertex for the given index. */
inline Vertex
getVertex (const VertexIndex& idx_vertex) const
{
assert (this->isValid (idx_vertex));
return (vertices_ [idx_vertex.get ()]);
}
/** \brief Set the vertex at the given index. */
inline void
setVertex (const VertexIndex& idx_vertex, const Vertex& vertex)
{
assert (this->isValid (idx_vertex));
vertices_ [idx_vertex.get ()] = vertex;
}
////////////////////////////////////////////////////////////////////////
// get / set HalfEdge
////////////////////////////////////////////////////////////////////////
/** \brief Get the half-edge for the given index. */
inline HalfEdge&
getHalfEdge (const HalfEdgeIndex& idx_he)
{
assert (this->isValid (idx_he));
return (half_edges_ [idx_he.get ()]);
}
/** \brief Get the half-edge for the given index. */
inline HalfEdge
getHalfEdge (const HalfEdgeIndex& idx_he) const
{
assert (this->isValid (idx_he));
return (half_edges_ [idx_he.get ()]);
}
/** \brief Set the half-edge at the given index. */
inline void
setHalfEdge (const HalfEdgeIndex& idx_he, const HalfEdge& half_edge)
{
assert (this->isValid (idx_he));
half_edges_ [idx_he.get ()] = half_edge;
}
////////////////////////////////////////////////////////////////////////
// get / set Face
////////////////////////////////////////////////////////////////////////
/** \brief Get the face for the given index. */
inline Face&
getFace (const FaceIndex& idx_face)
{
assert (this->isValid (idx_face));
return (faces_ [idx_face.get ()]);
}
/** \brief Get the face for the given index. */
inline Face
getFace (const FaceIndex& idx_face) const
{
assert (this->isValid (idx_face));
return (faces_ [idx_face.get ()]);
}
/** \brief Set the face at the given index. */
inline void
setFace (const FaceIndex& idx_face, const Face& face)
{
assert (this->isValid (idx_face));
faces_ [idx_face.get ()] = face;
}
private:
////////////////////////////////////////////////////////////////////////
// Members
////////////////////////////////////////////////////////////////////////
/** \brief Data stored for the vertices. */
VertexDataCloud vertex_data_cloud_;
/** \brief Data stored for the half-edges. */
HalfEdgeDataCloud half_edge_data_cloud_;
/** \brief Data stored for the edges. */
EdgeDataCloud edge_data_cloud_;
/** \brief Data stored for the faces. */
FaceDataCloud face_data_cloud_;
/** \brief Connectivity information for the vertices. */
Vertices vertices_;
/** \brief Connectivity information for the half-edges. */
HalfEdges half_edges_;
/** \brief Connectivity information for the faces. */
Faces faces_;
// NOTE: It is MUCH faster to store these variables permamently.
/** \brief Storage for addFaceImplBase and deleteFace. */
HalfEdgeIndices inner_he_;
/** \brief Storage for addFaceImplBase. */
HalfEdgeIndices free_he_;
/** \brief Storage for addFaceImplBase. */
std::vector <bool> is_new_;
/** \brief Storage for addFaceImplBase. */
std::vector <bool> make_adjacent_;
/** \brief Storage for deleteFace. */
std::vector <bool> is_boundary_;
/** \brief Storage for deleteVertex. */
FaceIndices delete_faces_vertex_;
/** \brief Storage for deleteFace. */
FaceIndices delete_faces_face_;
public:
template <class MeshT>
friend class pcl::geometry::MeshIO;
PCL_MAKE_ALIGNED_OPERATOR_NEW
};
} // End namespace geometry
} // End namespace pcl
pcl::geometry::MeshBase::getIncomingHalfEdgeIndex
HalfEdgeIndex getIncomingHalfEdgeIndex(const VertexIndex &idx_vertex) const
Get the incoming half-edge index to a given vertex.
Definition: mesh_base.h:335
pcl::geometry::MeshBase::getVertexIndex
VertexIndex getVertexIndex(const VertexData &vertex_data) const
Get the index associated to the given vertex data.
Definition: mesh_base.h:1037
pcl::geometry::MeshBase::emptyEdges
bool emptyEdges() const
Check if the edges are empty.
Definition: mesh_base.h:799
pcl::geometry::MeshBase::setVertex
void setVertex(const VertexIndex &idx_vertex, const Vertex &vertex)
Set the vertex at the given index.
Definition: mesh_base.h:1994
pcl_macros.h
Defines all the PCL and non-PCL macros used.
pcl::geometry::MeshBase::isBoundary
bool isBoundary(const HalfEdgeIndex &idx_he) const
Check if the given half-edge lies on the bounddary.
Definition: mesh_base.h:692
pcl
This file defines compatibility wrappers for low level I/O functions.
Definition: convolution.h:45
pcl::geometry::MeshBase::connectOldNew
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:1426
pcl::geometry::HalfEdge
An edge is a connection between two vertices.
Definition: mesh_elements.h:106
pcl::geometry::MeshBase::getPrevHalfEdgeIndex
HalfEdgeIndex getPrevHalfEdgeIndex(const HalfEdgeIndex &idx_half_edge) const
Get the previous half-edge index to a given half-edge.
Definition: mesh_base.h:380
pcl::geometry::MeshBase::isDeleted
bool isDeleted(const VertexIndex &idx_vertex) const
Check if the given vertex is marked as deleted.
Definition: mesh_base.h:634
pcl::geometry::MeshBase::setVertexDataCloud
bool setVertexDataCloud(const VertexDataCloud &vertex_data_cloud)
Change the stored vertex data.
Definition: mesh_base.h:914
pcl::geometry::MeshBase::getOppositeHalfEdgeIndex
HalfEdgeIndex getOppositeHalfEdgeIndex(const HalfEdgeIndex &idx_half_edge) const
Get the opposite half-edge index to a given half-edge.
Definition: mesh_base.h:363
pcl::geometry::distance
float distance(const PointT &p1, const PointT &p2)
Definition: geometry.h:60
pcl::geometry::MeshBase::getOutgoingHalfEdgeIndex
HalfEdgeIndex getOutgoingHalfEdgeIndex(const VertexIndex &idx_vertex) const
Get the outgoing half-edge index to a given vertex.
Definition: mesh_base.h:327
pcl::geometry::MeshBase< QuadMesh< MeshTraitsT >, MeshTraitsT, QuadMeshTag >::HalfEdgeIterator
typename HalfEdges::iterator HalfEdgeIterator
Definition: mesh_base.h:1099
pcl::geometry::MeshBase::setPrevHalfEdgeIndex
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:1825
pcl::geometry::MeshBase::getIncomingHalfEdgeAroundVertexCirculator
IncomingHalfEdgeAroundVertexCirculator getIncomingHalfEdgeAroundVertexCirculator(const VertexIndex &idx_vertex) const
Definition: mesh_base.h:460
pcl::geometry::MeshBase::getFaceDataCloud
FaceDataCloud getFaceDataCloud() const
Get the stored face data.
Definition: mesh_base.h:1009
pcl::geometry::MeshBase::deleteEdge
void deleteEdge(const EdgeIndex &idx_edge)
Mark the given edge (both half-edges) and the associated faces as deleted.
Definition: mesh_base.h:243
pcl::geometry::MeshBase::empty
bool empty() const
Check if the mesh is empty.
Definition: mesh_base.h:785
pcl::geometry::MeshBase< QuadMesh< MeshTraitsT >, MeshTraitsT, QuadMeshTag >::EdgeIndices
std::vector< EdgeIndex > EdgeIndices
Definition: mesh_base.h:140
pcl::geometry::MeshBase::isValid
bool isValid(const EdgeIndex &idx_edge) const
Check if the given edge index is a valid index into the mesh.
Definition: mesh_base.h:616
pcl::geometry::MeshBase::resizeVertices
void resizeVertices(const std::size_t n, const VertexData &data=VertexData())
Resize the the vertices to n elements.
Definition: mesh_base.h:846
pcl::geometry::MeshBase::checkTopology2
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:1257
pcl::geometry::MeshBase::getOutgoingHalfEdgeAroundVertexCirculator
OutgoingHalfEdgeAroundVertexCirculator getOutgoingHalfEdgeAroundVertexCirculator(const HalfEdgeIndex &idx_outgoing_half_edge) const
Definition: mesh_base.h:452
pcl::geometry::OutgoingHalfEdgeAroundVertexCirculator::getTargetIndex
HalfEdgeIndex getTargetIndex() const
Get the index to the outgoing half-edge.
Definition: mesh_circulators.h:243
pcl::geometry::MeshBase::isIsolated
bool isIsolated(const VertexIndex &idx_vertex) const
Check if the given vertex is isolated (not connected to other elements).
Definition: mesh_base.h:671
pcl::geometry::MeshBase::emptyFaces
bool emptyFaces() const
Check if the faces are empty.
Definition: mesh_base.h:806
pcl::geometry::MeshBase::setInnerHalfEdgeIndex
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:1842
pcl::geometry::MeshBase::addData
void addData(pcl::PointCloud< DataT > &cloud, const DataT &data, std::true_type)
Add mesh data.
Definition: mesh_base.h:1481
pcl::geometry::MeshBase::isManifold
bool isManifold(std::false_type) const
Check if all vertices in the mesh are manifold.
Definition: mesh_base.h:1920
pcl::geometry::MeshBase::getFaceAroundFaceCirculator
FaceAroundFaceCirculator getFaceAroundFaceCirculator(const FaceIndex &idx_face) const
Definition: mesh_base.h:540
pcl::PointCloud::resize
void resize(std::size_t n)
Resize the cloud.
Definition: point_cloud.h:442
pcl::geometry::MeshBase::getOriginatingVertexIndex
VertexIndex getOriginatingVertexIndex(const HalfEdgeIndex &idx_half_edge) const
Get the originating vertex index to a given half-edge.
Definition: mesh_base.h:355
pcl::geometry::MeshBase::isDeleted
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:650
pcl::geometry::MeshBase::getVertexDataCloud
VertexDataCloud getVertexDataCloud() const
Get the stored vertex data.
Definition: mesh_base.h:904
pcl::geometry::MeshBase::getFaceDataCloud
FaceDataCloud & getFaceDataCloud()
Get access to the stored face data.
Definition: mesh_base.h:1002
pcl::geometry::MeshBase::clearData
void clearData(DataCloudT &cloud, std::true_type) const
Clear the mesh data.
Definition: mesh_base.h:1961
pcl::geometry::MeshBase::emptyVertices
bool emptyVertices() const
Check if the vertices are empty.
Definition: mesh_base.h:792
pcl::geometry::InnerHalfEdgeAroundFaceCirculator
Circulates clockwise around a face and returns an index to the inner half-edge (the target).
Definition: mesh_circulators.h:605
pcl::geometry::MeshBase::VertexDataCloud
pcl::PointCloud< VertexData > VertexDataCloud
Definition: mesh_base.h:127
pcl::geometry::MeshBase::checkTopology1
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:1227
pcl::geometry::MeshBase::getNextHalfEdgeIndex
HalfEdgeIndex getNextHalfEdgeIndex(const HalfEdgeIndex &idx_half_edge) const
Get the next half-edge index to a given half-edge.
Definition: mesh_base.h:372
pcl::geometry::MeshBase::setHalfEdgeDataCloud
bool setHalfEdgeDataCloud(const HalfEdgeDataCloud &half_edge_data_cloud)
Change the stored half-edge data.
Definition: mesh_base.h:949
pcl::geometry::Vertex
A vertex is a node in the mesh.
Definition: mesh_elements.h:69
pcl::geometry::MeshBase::MeshBase
MeshBase()
Constructor.
Definition: mesh_base.h:154
pcl::geometry::MeshBase::getVertexAroundVertexCirculator
VertexAroundVertexCirculator getVertexAroundVertexCirculator(const VertexIndex &idx_vertex) const
Definition: mesh_base.h:428
pcl::geometry::MeshBase< QuadMesh< MeshTraitsT >, MeshTraitsT, QuadMeshTag >::VertexData
typename MeshTraitsT::VertexData VertexData
Definition: mesh_base.h:110
pcl::geometry::MeshBase::setHalfEdge
void setHalfEdge(const HalfEdgeIndex &idx_he, const HalfEdge &half_edge)
Set the half-edge at the given index.
Definition: mesh_base.h:2022
pcl::geometry::MeshBase::resizeData
void resizeData(DataCloudT &, const std::size_t, const typename DataCloudT::value_type &, std::false_type) const
Does nothing.
Definition: mesh_base.h:1955
pcl::geometry::MeshBase::sizeVertices
std::size_t sizeVertices() const
Get the number of the vertices.
Definition: mesh_base.h:751
pcl::geometry::OuterHalfEdgeAroundFaceCirculator
Circulates clockwise around a face and returns an index to the outer half-edge (the target).
Definition: mesh_circulators.h:713
pcl::geometry::MeshBase::deleteEdge
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:226
pcl::geometry::MeshBase::connectPrevNext
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:1360
pcl::geometry::MeshBase::reconnectNBNB
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:1618
pcl::geometry::MeshBase< QuadMesh< MeshTraitsT >, MeshTraitsT, QuadMeshTag >::FaceIterator
typename Faces::iterator FaceIterator
Definition: mesh_base.h:1100
pcl::geometry::MeshBase< QuadMesh< MeshTraitsT >, MeshTraitsT, QuadMeshTag >::IsManifold
typename MeshTraitsT::IsManifold IsManifold
Definition: mesh_base.h:114
pcl::geometry::IncomingHalfEdgeAroundVertexCirculator
Circulates counter-clockwise around a vertex and returns an index to the incoming half-edge (the targ...
Definition: mesh_circulators.h:279
pcl::geometry::MeshBase::setNextHalfEdgeIndex
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:1817
pcl::geometry::MeshBase::connectOldOld
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:1450
pcl::geometry::MeshBase::getVertex
Vertex getVertex(const VertexIndex &idx_vertex) const
Get the vertex for the given index.
Definition: mesh_base.h:1986
pcl::geometry::MeshBase::getOuterHalfEdgeIndex
HalfEdgeIndex getOuterHalfEdgeIndex(const FaceIndex &idx_face) const
Get the outer half-edge inex to a given face.
Definition: mesh_base.h:416
pcl::geometry::MeshBase::getEdgeIndex
EdgeIndex getEdgeIndex(const EdgeData &edge_data) const
Get the index associated to the given edge data.
Definition: mesh_base.h:1061
pcl::PointCloud< VertexData >
pcl::geometry::MeshBase::getEdgeDataCloud
EdgeDataCloud getEdgeDataCloud() const
Get the stored edge data.
Definition: mesh_base.h:974
pcl::geometry::MeshBase< QuadMesh< MeshTraitsT >, MeshTraitsT, QuadMeshTag >::HalfEdges
std::vector< HalfEdge > HalfEdges
Definition: mesh_base.h:1095
pcl::geometry::MeshBase< QuadMesh< MeshTraitsT >, MeshTraitsT, QuadMeshTag >::FaceData
typename MeshTraitsT::FaceData FaceData
Definition: mesh_base.h:113
pcl::geometry::MeshBase::isManifold
bool isManifold(std::true_type) const
Always manifold.
Definition: mesh_base.h:1913
pcl::geometry::MeshBase::isValid
bool isValid(const VertexIndex &idx_vertex) const
Check if the given vertex index is a valid index into the mesh.
Definition: mesh_base.h:602
pcl::geometry::MeshBase::getFaceAroundFaceCirculator
FaceAroundFaceCirculator getFaceAroundFaceCirculator(const HalfEdgeIndex &idx_inner_half_edge) const
Definition: mesh_base.h:548
pcl::geometry::MeshBase::connectNewNew
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:1385
pcl::geometry::MeshBase::getHalfEdgeDataCloud
HalfEdgeDataCloud getHalfEdgeDataCloud() const
Get the stored half-edge data.
Definition: mesh_base.h:939
pcl::geometry::MeshBase::isDeleted
bool isDeleted(const HalfEdgeIndex &idx_he) const
Check if the given half-edge is marked as deleted.
Definition: mesh_base.h:642
pcl::geometry::MeshBase::resizeEdges
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:854
pcl::geometry::MeshBase::resizeFaces
void resizeFaces(const std::size_t n, const FaceData &data=FaceData())
Resize the faces to n elements.
Definition: mesh_base.h:865
pcl::geometry::VertexAroundFaceCirculator
Circulates clockwise around a face and returns an index to the terminating vertex of the inner half-e...
Definition: mesh_circulators.h:496
pcl::geometry::MeshBase::getHalfEdge
HalfEdge & getHalfEdge(const HalfEdgeIndex &idx_he)
Get the half-edge for the given index.
Definition: mesh_base.h:2006
pcl::geometry::MeshBase::isBoundary
bool isBoundary(const FaceIndex &idx_face) const
Check if the given face lies on the boundary.
Definition: mesh_base.h:711
pcl::geometry::MeshBase::reserveFaces
void reserveFaces(const std::size_t n)
Reserve storage space for n faces.
Definition: mesh_base.h:834
pcl::geometry::MeshBase::getHalfEdgeIndex
HalfEdgeIndex getHalfEdgeIndex(const HalfEdgeData &half_edge_data) const
Get the index associated to the given half-edge data.
Definition: mesh_base.h:1049
pcl::geometry::HalfEdgeIndex
Index used to access elements in the half-edge mesh.
Definition: mesh_indices.h:200
pcl::geometry::FaceAroundFaceCirculator
Circulates clockwise around a face and returns an index to the face of the outer half-edge (the targe...
Definition: mesh_circulators.h:821
pcl::geometry::MeshBase::deleteFace
void deleteFace(const FaceIndex &idx_face, std::false_type)
Non-manifold version of deleteFace.
Definition: mesh_base.h:1518
pcl::geometry::VertexIndex
Index used to access elements in the half-edge mesh.
Definition: mesh_indices.h:61
pcl::geometry::MeshBase::setOutgoingHalfEdgeIndex
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:1801
pcl::geometry::MeshBase< QuadMesh< MeshTraitsT >, MeshTraitsT, QuadMeshTag >::HalfEdgeData
typename MeshTraitsT::HalfEdgeData HalfEdgeData
Definition: mesh_base.h:111
pcl::geometry::OutgoingHalfEdgeAroundVertexCirculator
Circulates counter-clockwise around a vertex and returns an index to the outgoing half-edge (the targ...
Definition: mesh_circulators.h:171
pcl::geometry::MeshBase::addVertex
VertexIndex addVertex(const VertexData &vertex_data=VertexData())
Add a vertex to the mesh.
Definition: mesh_base.h:171
pcl::geometry::MeshBase::incrementIf
void incrementIf(IteratorT &, std::false_type) const
Does nothing.
Definition: mesh_base.h:1778
pcl::geometry::MeshBase::markDeleted
void markDeleted(const EdgeIndex &idx_edge)
Mark the given edge (both half-edges) as deleted.
Definition: mesh_base.h:1687
pcl::geometry::MeshBase::getInnerHalfEdgeAroundFaceCirculator
InnerHalfEdgeAroundFaceCirculator getInnerHalfEdgeAroundFaceCirculator(const FaceIndex &idx_face) const
Definition: mesh_base.h:508
pcl::geometry::MeshBase< QuadMesh< MeshTraitsT >, MeshTraitsT, QuadMeshTag >::HalfEdgeIndices
std::vector< HalfEdgeIndex > HalfEdgeIndices
Definition: mesh_base.h:139
pcl::geometry::MeshBase::sizeEdges
std::size_t sizeEdges() const
Get the number of the edges.
Definition: mesh_base.h:766
pcl::geometry::MeshBase::setTerminatingVertexIndex
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:1809
pcl::geometry::OuterHalfEdgeAroundFaceCirculator::getTargetIndex
HalfEdgeIndex getTargetIndex() const
Get the index to the outer half-edge.
Definition: mesh_circulators.h:785
pcl::geometry::MeshBase::makeAdjacent
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:1318
pcl::geometry::MeshBase::addEdge
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:1182
pcl::geometry::VertexAroundVertexCirculator::getTargetIndex
VertexIndex getTargetIndex() const
Get the index to the target vertex.
Definition: mesh_circulators.h:135
pcl::geometry::MeshBase::getFace
Face & getFace(const FaceIndex &idx_face)
Get the face for the given index.
Definition: mesh_base.h:2034
pcl::geometry::MeshBase::isBoundary
bool isBoundary(const VertexIndex &idx_vertex) const
Check if the given vertex lies on the boundary.
Definition: mesh_base.h:683
pcl::geometry::MeshBase::reconnect
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:1570
pcl::geometry::MeshBase::addFaceImplBase
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:1108
pcl::geometry::Face
A face is a closed loop of edges.
Definition: mesh_elements.h:164
pcl::geometry::MeshBase::connectFace
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:1342
pcl::geometry::MeshBase::reserveData
void reserveData(DataCloudT &cloud, const std::size_t n, std::true_type) const
Reserve storage space for the mesh data.
Definition: mesh_base.h:1935
pcl::geometry::MeshBase::setFace
void setFace(const FaceIndex &idx_face, const Face &face)
Set the face at the given index.
Definition: mesh_base.h:2050
pcl::geometry::MeshBase::clear
void clear()
Clear all mesh elements and data.
Definition: mesh_base.h:877
pcl::geometry::MeshBase::clearData
void clearData(DataCloudT &, std::false_type) const
Does nothing.
Definition: mesh_base.h:1968
pcl::geometry::MeshBase::getInnerHalfEdgeAroundFaceCirculator
InnerHalfEdgeAroundFaceCirculator getInnerHalfEdgeAroundFaceCirculator(const HalfEdgeIndex &idx_inner_half_edge) const
Definition: mesh_base.h:516
pcl::geometry::MeshBase::isManifold
bool isManifold(const VertexIndex &, std::true_type) const
Always manifold.
Definition: mesh_base.h:1890
pcl::PointCloud::back
const PointT & back() const
Definition: point_cloud.h:459
pcl::geometry::MeshBase::getVertex
Vertex & getVertex(const VertexIndex &idx_vertex)
Get the vertex for the given index.
Definition: mesh_base.h:1978
pcl::geometry::MeshBase::getFace
Face getFace(const FaceIndex &idx_face) const
Get the face for the given index.
Definition: mesh_base.h:2042
pcl::geometry::MeshBase::FaceDataCloud
pcl::PointCloud< FaceData > FaceDataCloud
Definition: mesh_base.h:130
pcl::geometry::MeshBase::assignIf
void assignIf(const ConstIteratorT source, IteratorT target, std::true_type) const
Assign the source iterator to the target iterator.
Definition: mesh_base.h:1784
PCL_MAKE_ALIGNED_OPERATOR_NEW
#define PCL_MAKE_ALIGNED_OPERATOR_NEW
Macro to signal a class requires a custom allocator.
Definition: pcl_macros.h:371
pcl::geometry::MeshBase::getHalfEdge
HalfEdge getHalfEdge(const HalfEdgeIndex &idx_he) const
Get the half-edge for the given index.
Definition: mesh_base.h:2014
pcl::geometry::MeshBase::deleteFace
void deleteFace(const FaceIndex &idx_face, std::true_type)
Manifold version of deleteFace.
Definition: mesh_base.h:1499
pcl::geometry::MeshBase< QuadMesh< MeshTraitsT >, MeshTraitsT, QuadMeshTag >::HasFaceData
std::integral_constant< bool, !std::is_same< FaceData, pcl::geometry::NoData >::value > HasFaceData
Definition: mesh_base.h:125
pcl::geometry::MeshBase::getVertexAroundFaceCirculator
VertexAroundFaceCirculator getVertexAroundFaceCirculator(const HalfEdgeIndex &idx_inner_half_edge) const
Definition: mesh_base.h:500
pcl::geometry::EdgeIndex
Index used to access elements in the half-edge mesh.
Definition: mesh_indices.h:339
pcl::geometry::MeshBase::reserveEdges
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:825
pcl::geometry::MeshBase< QuadMesh< MeshTraitsT >, MeshTraitsT, QuadMeshTag >::VertexIterator
typename Vertices::iterator VertexIterator
Definition: mesh_base.h:1098
pcl::geometry::QuadMeshTag
Tag describing the type of the mesh.
Definition: quad_mesh.h:51
pcl::geometry::MeshBase::isBoundary
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:1872
pcl::geometry::MeshBase::getFaceIndex
FaceIndex getFaceIndex(const HalfEdgeIndex &idx_half_edge) const
Get the face index to a given half-edge.
Definition: mesh_base.h:388
pcl::geometry::MeshBase::reconnectNBNB
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:1654
pcl::geometry::VertexAroundFaceCirculator::getTargetIndex
VertexIndex getTargetIndex() const
Get the index to the target vertex.
Definition: mesh_circulators.h:569
pcl::geometry::MeshBase::getOutgoingHalfEdgeAroundVertexCirculator
OutgoingHalfEdgeAroundVertexCirculator getOutgoingHalfEdgeAroundVertexCirculator(const VertexIndex &idx_vertex) const
Definition: mesh_base.h:444
pcl::geometry::MeshBase::getEdgeDataCloud
EdgeDataCloud & getEdgeDataCloud()
Get access to the stored edge data.
Definition: mesh_base.h:967
pcl::geometry::MeshBase::getFaceAroundVertexCirculator
FaceAroundVertexCirculator getFaceAroundVertexCirculator(const HalfEdgeIndex &idx_outgoing_half_edge) const
Definition: mesh_base.h:484
pcl::geometry::MeshBase::getOppositeFaceIndex
FaceIndex getOppositeFaceIndex(const HalfEdgeIndex &idx_half_edge) const
Get the face index to a given half-edge.
Definition: mesh_base.h:396
pcl::geometry::VertexIndex::invalidate
void invalidate()
Invalidate the index.
Definition: mesh_indices.h:97
pcl::geometry::IncomingHalfEdgeAroundVertexCirculator::getTargetIndex
HalfEdgeIndex getTargetIndex() const
Get the index to the incoming half-edge.
Definition: mesh_circulators.h:351
pcl::geometry::HalfEdgeIndex::get
int get() const
Get the index.
Definition: mesh_indices.h:243
pcl::geometry::MeshBase::HalfEdgeDataCloud
pcl::PointCloud< HalfEdgeData > HalfEdgeDataCloud
Definition: mesh_base.h:128
pcl::geometry::FaceAroundVertexCirculator
Circulates counter-clockwise around a vertex and returns an index to the face of the outgoing half-ed...
Definition: mesh_circulators.h:387
pcl::geometry::MeshBase::getFaceIndex
FaceIndex getFaceIndex(const FaceData &face_data) const
Get the index associated to the given face data.
Definition: mesh_base.h:1073
pcl::PointCloud::size
std::size_t size() const
Definition: point_cloud.h:435
pcl::geometry::MeshBase< QuadMesh< MeshTraitsT >, MeshTraitsT, QuadMeshTag >::EdgeData
typename MeshTraitsT::EdgeData EdgeData
Definition: mesh_base.h:112
pcl::geometry::HalfEdgeIndex::invalidate
void invalidate()
Invalidate the index.
Definition: mesh_indices.h:236
pcl::geometry::InnerHalfEdgeAroundFaceCirculator::getTargetIndex
HalfEdgeIndex getTargetIndex() const
Get the index to the inner half-edge.
Definition: mesh_circulators.h:677
pcl::geometry::MeshBase::isValid
bool isValid(const FaceIndex &idx_face) const
Check if the given face index is a valid index into the mesh.
Definition: mesh_base.h:623
pcl::geometry::MeshBase::getInnerHalfEdgeIndex
HalfEdgeIndex getInnerHalfEdgeIndex(const FaceIndex &idx_face) const
Get the inner half-edge index to a given face.
Definition: mesh_base.h:408
pcl::geometry::MeshBase::setEdgeDataCloud
bool setEdgeDataCloud(const EdgeDataCloud &edge_data_cloud)
Change the stored edge data.
Definition: mesh_base.h:984
pcl::geometry::MeshBase::getOuterHalfEdgeAroundFaceCirculator
OuterHalfEdgeAroundFaceCirculator getOuterHalfEdgeAroundFaceCirculator(const FaceIndex &idx_face) const
Definition: mesh_base.h:524
pcl::geometry::MeshBase::isManifold
bool isManifold() const
Check if the mesh is manifold.
Definition: mesh_base.h:740
pcl::geometry::MeshBase::addData
void addData(pcl::PointCloud< DataT > &, const DataT &, std::false_type)
Does nothing.
Definition: mesh_base.h:1489
pcl::geometry::MeshBase::getHalfEdgeDataCloud
HalfEdgeDataCloud & getHalfEdgeDataCloud()
Get access to the stored half-edge data.
Definition: mesh_base.h:932
pcl::geometry::MeshBase::isManifold
bool isManifold(const VertexIndex &idx_vertex, std::false_type) const
Check if the given vertex is manifold.
Definition: mesh_base.h:1897
pcl::geometry::QuadMesh
Half-edge mesh that can only store quads.
Definition: quad_mesh.h:59
pcl::geometry::MeshBase< QuadMesh< MeshTraitsT >, MeshTraitsT, QuadMeshTag >::HasVertexData
std::integral_constant< bool, !std::is_same< VertexData, pcl::geometry::NoData >::value > HasVertexData
Definition: mesh_base.h:122
pcl::geometry::MeshBase< QuadMesh< MeshTraitsT >, MeshTraitsT, QuadMeshTag >::HalfEdgeConstIterator
typename HalfEdges::const_iterator HalfEdgeConstIterator
Definition: mesh_base.h:1103
pcl::geometry::MeshBase::getVertexDataCloud
VertexDataCloud & getVertexDataCloud()
Get access to the stored vertex data.
Definition: mesh_base.h:897
pcl::geometry::MeshIO
Read / write the half-edge mesh from / to a file.
Definition: mesh_base.h:78
pcl::geometry::MeshBase::setFaceIndex
void setFaceIndex(const HalfEdgeIndex &idx_half_edge, const FaceIndex &idx_face)
Set the face index to a given half-edge.
Definition: mesh_base.h:1834
pcl::geometry::MeshBase::getTerminatingVertexIndex
VertexIndex getTerminatingVertexIndex(const HalfEdgeIndex &idx_half_edge) const
Get the terminating vertex index to a given half-edge.
Definition: mesh_base.h:347
pcl::geometry::MeshBase< QuadMesh< MeshTraitsT >, MeshTraitsT, QuadMeshTag >::Vertices
std::vector< Vertex > Vertices
Definition: mesh_base.h:1094
pcl::geometry::FaceIndex
Index used to access elements in the half-edge mesh.
Definition: mesh_indices.h:478
pcl::geometry::MeshBase::isEqualTopology
bool isEqualTopology(const Self &other) const
Check if the other mesh has the same topology as this mesh.
Definition: mesh_base.h:560
pcl::geometry::MeshBase::EdgeDataCloud
pcl::PointCloud< EdgeData > EdgeDataCloud
Definition: mesh_base.h:129
pcl::PointCloud::front
const PointT & front() const
Definition: point_cloud.h:457
pcl::geometry::MeshBase::resizeData
void resizeData(DataCloudT &, const std::size_t n, const typename DataCloudT::value_type &data, std::true_type) const
Resize the mesh data.
Definition: mesh_base.h:1948
pcl::geometry::MeshBase< QuadMesh< MeshTraitsT >, MeshTraitsT, QuadMeshTag >::Ptr
shared_ptr< Self > Ptr
Definition: mesh_base.h:104
pcl::geometry::toHalfEdgeIndex
pcl::geometry::HalfEdgeIndex toHalfEdgeIndex(const EdgeIndex &index, const bool get_first=true)
Convert the given edge index to a half-edge index.
Definition: mesh_indices.h:625
pcl::geometry::MeshBase< QuadMesh< MeshTraitsT >, MeshTraitsT, QuadMeshTag >::VertexConstIterator
typename Vertices::const_iterator VertexConstIterator
Definition: mesh_base.h:1102
pcl::Vertices
Describes a set of vertices in a polygon mesh, by basically storing an array of indices.
Definition: Vertices.h:14
pcl::geometry::MeshBase::getVertexAroundVertexCirculator
VertexAroundVertexCirculator getVertexAroundVertexCirculator(const HalfEdgeIndex &idx_outgoing_half_edge) const
Definition: mesh_base.h:436
pcl::geometry::MeshBase< QuadMesh< MeshTraitsT >, MeshTraitsT, QuadMeshTag >::HasHalfEdgeData
std::integral_constant< bool, !std::is_same< HalfEdgeData, pcl::geometry::NoData >::value > HasHalfEdgeData
Definition: mesh_base.h:123
pcl::geometry::FaceIndex::isValid
bool isValid() const
Returns true if the index is valid.
Definition: mesh_indices.h:507
pcl::geometry::MeshBase< QuadMesh< MeshTraitsT >, MeshTraitsT, QuadMeshTag >::FaceIndices
std::vector< FaceIndex > FaceIndices
Definition: mesh_base.h:141
pcl::geometry::MeshBase::reserveVertices
void reserveVertices(const std::size_t n)
Reserve storage space n vertices.
Definition: mesh_base.h:817
pcl::geometry::FaceIndex::invalidate
void invalidate()
Invalidate the index.
Definition: mesh_indices.h:514
pcl::geometry::MeshBase< QuadMesh< MeshTraitsT >, MeshTraitsT, QuadMeshTag >::HasEdgeData
std::integral_constant< bool, !std::is_same< EdgeData, pcl::geometry::NoData >::value > HasEdgeData
Definition: mesh_base.h:124
pcl::geometry::MeshBase::cleanUp
void cleanUp()
Removes all mesh elements and data that are marked as deleted.
Definition: mesh_base.h:266
pcl::geometry::MeshBase::addFace
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:187
pcl::geometry::MeshBase::isManifold
bool isManifold(const VertexIndex &idx_vertex) const
Check if the given vertex is manifold.
Definition: mesh_base.h:731
pcl::geometry::MeshBase::sizeHalfEdges
std::size_t sizeHalfEdges() const
Get the number of the half-edges.
Definition: mesh_base.h:758
pcl::PointCloud::begin
iterator begin()
Definition: point_cloud.h:429
pcl::geometry::MeshBase::checkTopology1
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:1209
pcl::geometry::MeshBase::isDeleted
bool isDeleted(const FaceIndex &idx_face) const
Check if the given face is marked as deleted.
Definition: mesh_base.h:659
pcl::geometry::VertexAroundVertexCirculator::getCurrentHalfEdgeIndex
HalfEdgeIndex getCurrentHalfEdgeIndex() const
Get the half-edge that is currently stored in the circulator.
Definition: mesh_circulators.h:142
pcl::geometry::MeshBase::getOuterHalfEdgeAroundFaceCirculator
OuterHalfEdgeAroundFaceCirculator getOuterHalfEdgeAroundFaceCirculator(const HalfEdgeIndex &idx_inner_half_edge) const
Definition: mesh_base.h:532
pcl::geometry::MeshBase< QuadMesh< MeshTraitsT >, MeshTraitsT, QuadMeshTag >::ConstPtr
shared_ptr< const Self > ConstPtr
Definition: mesh_base.h:105
pcl::geometry::MeshBase::deleteVertex
void deleteVertex(const VertexIndex &idx_vertex)
Mark the given vertex and all connected half-edges and faces as deleted.
Definition: mesh_base.h:200
pcl::geometry::MeshBase::isValid
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:609
pcl::geometry::MeshBase::connectOldOld
void connectOldOld(const HalfEdgeIndex &, const HalfEdgeIndex &, const VertexIndex &, std::true_type)
Both half-edges are old (manifold version).
Definition: mesh_base.h:1441
pcl::geometry::MeshBase::getFaceAroundVertexCirculator
FaceAroundVertexCirculator getFaceAroundVertexCirculator(const VertexIndex &idx_vertex) const
Definition: mesh_base.h:476
pcl::geometry::MeshBase::deleteFace
void deleteFace(const FaceIndex &idx_face)
Mark the given face as deleted.
Definition: mesh_base.h:254
pcl::geometry::MeshBase::isBoundary
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:700
pcl::geometry::MeshBase::markDeleted
void markDeleted(const FaceIndex &idx_face)
Mark the given face as deleted.
Definition: mesh_base.h:1696
pcl::geometry::MeshBase::connectNewOld
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:1411
pcl::geometry::MeshBase::reserveData
void reserveData(DataCloudT &, const std::size_t, std::false_type) const
Does nothing.
Definition: mesh_base.h:1942
pcl::geometry::MeshBase::remove
IndexContainerT remove(ElementContainerT &elements, DataContainerT &data_cloud)
Removes mesh elements and data that are marked as deleted from the container.
Definition: mesh_base.h:1717
pcl::geometry::MeshBase::isBoundary
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:1854
pcl::geometry::MeshBase::sizeFaces
std::size_t sizeFaces() const
Get the number of the faces.
Definition: mesh_base.h:774
pcl::geometry::MeshBase::setFaceDataCloud
bool setFaceDataCloud(const FaceDataCloud &face_data_cloud)
Change the stored face data.
Definition: mesh_base.h:1019
pcl::geometry::MeshBase::getIncomingHalfEdgeAroundVertexCirculator
IncomingHalfEdgeAroundVertexCirculator getIncomingHalfEdgeAroundVertexCirculator(const HalfEdgeIndex &idx_incoming_half_edge) const
Definition: mesh_base.h:468
pcl::geometry::VertexIndex::get
int get() const
Get the index.
Definition: mesh_indices.h:104
pcl::PointCloud::push_back
void push_back(const PointT &pt)
Insert a new point in the cloud, at the end of the container.
Definition: point_cloud.h:467
pcl::geometry::MeshBase::getVertexAroundFaceCirculator
VertexAroundFaceCirculator getVertexAroundFaceCirculator(const FaceIndex &idx_face) const
Definition: mesh_base.h:492
pcl::geometry::MeshBase< QuadMesh< MeshTraitsT >, MeshTraitsT, QuadMeshTag >::FaceConstIterator
typename Faces::const_iterator FaceConstIterator
Definition: mesh_base.h:1104
pcl::geometry::MeshBase::checkTopology2
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:1279
pcl::geometry::MeshBase::assignIf
void assignIf(const ConstIteratorT, IteratorT, std::false_type) const
Does nothing.
Definition: mesh_base.h:1791
pcl::geometry::FaceAroundVertexCirculator::getTargetIndex
FaceIndex getTargetIndex() const
Get the index to the target face.
Definition: mesh_circulators.h:460
pcl::geometry::MeshBase::markDeleted
void markDeleted(const VertexIndex &idx_vertex)
Mark the given vertex as deleted.
Definition: mesh_base.h:1671
pcl::geometry::MeshBase< QuadMesh< MeshTraitsT >, MeshTraitsT, QuadMeshTag >::Faces
std::vector< Face > Faces
Definition: mesh_base.h:1096
pcl::geometry::FaceIndex::get
int get() const
Get the index.
Definition: mesh_indices.h:521
pcl::shared_ptr
boost::shared_ptr< T > shared_ptr
Alias for boost::shared_ptr.
Definition: pcl_macros.h:90
pcl::geometry::MeshBase::connectNewNew
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:1369
pcl::geometry::MeshBase::markDeleted
void markDeleted(const HalfEdgeIndex &idx_he)
Mark the given half-edge as deleted.
Definition: mesh_base.h:1679
pcl::geometry::MeshBase::isBoundary
bool isBoundary(const FaceIndex &idx_face) const
Check if the given face lies on the boundary.
Definition: mesh_base.h:719
pcl::geometry::MeshBase::incrementIf
void incrementIf(IteratorT &it, std::true_type) const
Increment the iterator.
Definition: mesh_base.h:1771
pcl::geometry::MeshBase< QuadMesh< MeshTraitsT >, MeshTraitsT, QuadMeshTag >::VertexIndices
std::vector< VertexIndex > VertexIndices
Definition: mesh_base.h:138
pcl::geometry::MeshBase
Base class for the half-edge mesh.
Definition: mesh_base.h:99
pcl::geometry::VertexAroundVertexCirculator
Circulates counter-clockwise around a vertex and returns an index to the terminating vertex of the ou...
Definition: mesh_circulators.h:63