43#include <pcl/geometry/mesh_circulators.h>
44#include <pcl/geometry/mesh_elements.h>
45#include <pcl/geometry/mesh_indices.h>
46#include <pcl/geometry/mesh_traits.h>
49#include <pcl/point_cloud.h>
59#ifdef PCL_GEOMETRY_MESH_BASE_TEST_DELETE_FACE_MANIFOLD_2
62bool g_pcl_geometry_mesh_base_test_delete_face_manifold_2_success;
95template <
class DerivedT,
class MeshTraitsT,
class MeshTagT>
99 using Ptr = shared_ptr<Self>;
112 static_assert(std::is_convertible<IsManifold, bool>::value,
113 "MeshTraitsT::IsManifold is not convertible to bool");
119 std::integral_constant<bool,
120 !std::is_same<VertexData, pcl::geometry::NoData>::value>;
122 std::integral_constant<bool,
123 !std::is_same<HalfEdgeData, pcl::geometry::NoData>::value>;
125 std::integral_constant<bool,
126 !std::is_same<EdgeData, pcl::geometry::NoData>::value>;
128 std::integral_constant<bool,
129 !std::is_same<FaceData, pcl::geometry::NoData>::value>;
166 : vertex_data_cloud_()
167 , half_edge_data_cloud_()
185 vertices_.push_back(
Vertex());
210 return (
static_cast<Derived*
>(
this)->addFaceImpl(
211 vertices, face_data, edge_data, half_edge_data));
221 assert(this->
isValid(idx_vertex));
225 delete_faces_vertex_.clear();
233 }
while (++circ != circ_end);
235 for (
const auto& delete_me : delete_faces_vertex_) {
271 assert(this->
isValid(idx_edge));
272 this->
deleteEdge(pcl::geometry::toHalfEdgeIndex(idx_edge));
274 pcl::geometry::toHalfEdgeIndex(idx_edge,
false)));
285 assert(this->
isValid(idx_face));
301 this->remove<Vertices, VertexDataCloud, VertexIndices, HasVertexData>(
302 vertices_, vertex_data_cloud_);
304 this->remove<HalfEdges, HalfEdgeDataCloud, HalfEdgeIndices, HasHalfEdgeData>(
305 half_edges_, half_edge_data_cloud_);
307 this->remove<Faces, FaceDataCloud, FaceIndices, HasFaceData>(faces_,
311 if (HasEdgeData::value) {
312 auto it_ed_old = edge_data_cloud_.
begin();
313 auto it_ed_new = edge_data_cloud_.
begin();
315 for (
auto it_ind = new_half_edge_indices.cbegin(),
316 it_ind_end = new_half_edge_indices.cend();
317 it_ind != it_ind_end;
318 it_ind += 2, ++it_ed_old) {
319 if (it_ind->isValid()) {
320 *it_ed_new++ = *it_ed_old;
327 for (
auto& vertex : vertices_) {
328 if (vertex.idx_outgoing_half_edge_.isValid()) {
329 vertex.idx_outgoing_half_edge_ =
330 new_half_edge_indices[vertex.idx_outgoing_half_edge_.get()];
334 for (
auto& half_edge : half_edges_) {
335 half_edge.idx_terminating_vertex_ =
336 new_vertex_indices[half_edge.idx_terminating_vertex_.get()];
337 half_edge.idx_next_half_edge_ =
338 new_half_edge_indices[half_edge.idx_next_half_edge_.get()];
339 half_edge.idx_prev_half_edge_ =
340 new_half_edge_indices[half_edge.idx_prev_half_edge_.get()];
341 if (half_edge.idx_face_.isValid()) {
342 half_edge.idx_face_ = new_face_indices[half_edge.idx_face_.get()];
346 for (
auto& face : faces_) {
347 face.idx_inner_half_edge_ =
348 new_half_edge_indices[face.idx_inner_half_edge_.get()];
360 assert(this->
isValid(idx_vertex));
361 return (this->
getVertex(idx_vertex).idx_outgoing_half_edge_);
368 assert(this->
isValid(idx_vertex));
380 assert(this->
isValid(idx_half_edge));
381 return (this->
getHalfEdge(idx_half_edge).idx_terminating_vertex_);
388 assert(this->
isValid(idx_half_edge));
397 assert(this->
isValid(idx_half_edge));
400 : idx_half_edge.
get() + 1));
407 assert(this->
isValid(idx_half_edge));
408 return (this->
getHalfEdge(idx_half_edge).idx_next_half_edge_);
415 assert(this->
isValid(idx_half_edge));
416 return (this->
getHalfEdge(idx_half_edge).idx_prev_half_edge_);
423 assert(this->
isValid(idx_half_edge));
424 return (this->
getHalfEdge(idx_half_edge).idx_face_);
431 assert(this->
isValid(idx_half_edge));
443 assert(this->
isValid(idx_face));
444 return (this->
getFace(idx_face).idx_inner_half_edge_);
451 assert(this->
isValid(idx_face));
463 assert(this->
isValid(idx_vertex));
471 assert(this->
isValid(idx_outgoing_half_edge));
479 assert(this->
isValid(idx_vertex));
488 assert(this->
isValid(idx_outgoing_half_edge));
496 assert(this->
isValid(idx_vertex));
505 assert(this->
isValid(idx_incoming_half_edge));
513 assert(this->
isValid(idx_vertex));
521 assert(this->
isValid(idx_outgoing_half_edge));
529 assert(this->
isValid(idx_face));
537 assert(this->
isValid(idx_inner_half_edge));
545 assert(this->
isValid(idx_face));
553 assert(this->
isValid(idx_inner_half_edge));
561 assert(this->
isValid(idx_face));
569 assert(this->
isValid(idx_inner_half_edge));
577 assert(this->
isValid(idx_face));
585 assert(this->
isValid(idx_inner_half_edge));
601 if (this->
sizeFaces() != other.sizeFaces())
604 for (std::size_t i = 0; i < this->
sizeVertices(); ++i) {
627 for (std::size_t i = 0; i < this->
sizeFaces(); ++i) {
629 other.getInnerHalfEdgeIndex(
FaceIndex(i)))
644 return (idx_vertex >=
static_cast<VertexIndex>(0) &&
645 idx_vertex <
static_cast<VertexIndex>(vertices_.size()));
660 return (idx_edge >=
static_cast<EdgeIndex>(0) &&
661 idx_edge <
static_cast<EdgeIndex>(half_edges_.size() / 2));
668 return (idx_face >=
static_cast<FaceIndex>(0) &&
669 idx_face <
static_cast<FaceIndex>(faces_.size()));
680 assert(this->
isValid(idx_vertex));
697 assert(this->
isValid(idx_edge));
698 return (this->
isDeleted(pcl::geometry::toHalfEdgeIndex(idx_edge,
true)) ||
699 this->
isDeleted(pcl::geometry::toHalfEdgeIndex(idx_edge,
false)));
706 assert(this->
isValid(idx_face));
718 assert(this->
isValid(idx_vertex));
731 assert(this->
isValid(idx_vertex));
750 assert(this->
isValid(idx_edge));
751 const HalfEdgeIndex& idx = pcl::geometry::toHalfEdgeIndex(idx_edge);
762 template <
bool CheckVerticesT>
766 assert(this->
isValid(idx_face));
767 return (this->
isBoundary(idx_face, std::integral_constant<bool, CheckVerticesT>()));
775 assert(this->
isValid(idx_face));
776 return (this->
isBoundary(idx_face, std::true_type()));
787 assert(this->
isValid(idx_vertex));
808 return (vertices_.size());
815 assert(half_edges_.size() % 2 == 0);
816 return (half_edges_.size());
823 assert(half_edges_.size() % 2 == 0);
824 return (half_edges_.size() / 2);
831 return (faces_.size());
849 return (vertices_.empty());
856 return (half_edges_.empty());
863 return (faces_.empty());
874 vertices_.reserve(n);
883 half_edges_.reserve(2 * n);
904 vertices_.resize(n,
Vertex());
914 half_edges_.resize(2 * n,
HalfEdge());
923 faces_.resize(n,
Face());
955 return (vertex_data_cloud_);
962 return (vertex_data_cloud_);
973 if (vertex_data_cloud.
size() == vertex_data_cloud_.
size()) {
974 vertex_data_cloud_ = vertex_data_cloud;
990 return (half_edge_data_cloud_);
997 return (half_edge_data_cloud_);
1008 if (half_edge_data_cloud.
size() == half_edge_data_cloud_.
size()) {
1009 half_edge_data_cloud_ = half_edge_data_cloud;
1025 return (edge_data_cloud_);
1032 return (edge_data_cloud_);
1042 if (edge_data_cloud.
size() == edge_data_cloud_.
size()) {
1043 edge_data_cloud_ = edge_data_cloud;
1059 return (face_data_cloud_);
1066 return (face_data_cloud_);
1076 if (face_data_cloud.
size() == face_data_cloud_.
size()) {
1077 face_data_cloud_ = face_data_cloud;
1093 if (HasVertexData::value) {
1094 assert(&vertex_data >= &vertex_data_cloud_.
front() &&
1095 &vertex_data <= &vertex_data_cloud_.
back());
1096 return (
VertexIndex(std::distance(&vertex_data_cloud_.
front(), &vertex_data)));
1105 if (HasHalfEdgeData::value) {
1106 assert(&half_edge_data >= &half_edge_data_cloud_.
front() &&
1107 &half_edge_data <= &half_edge_data_cloud_.
back());
1109 std::distance(&half_edge_data_cloud_.
front(), &half_edge_data)));
1118 if (HasEdgeData::value) {
1119 assert(&edge_data >= &edge_data_cloud_.
front() &&
1120 &edge_data <= &edge_data_cloud_.
back());
1121 return (
EdgeIndex(std::distance(&edge_data_cloud_.
front(), &edge_data)));
1130 if (HasFaceData::value) {
1131 assert(&face_data >= &face_data_cloud_.
front() &&
1132 &face_data <= &face_data_cloud_.
back());
1133 return (
FaceIndex(std::distance(&face_data_cloud_.
front(), &face_data)));
1167 const int n =
static_cast<int>(vertices.size());
1172 inner_he_.resize(n);
1175 make_adjacent_.resize(n);
1176 for (
int i = 0; i < n; ++i) {
1178 vertices[(i + 1) % n],
1185 for (
int i = 0; i < n; ++i) {
1186 int j = (i + 1) % n;
1200 if (!IsManifold::value) {
1201 for (
int i = 0; i < n; ++i) {
1202 if (make_adjacent_[i]) {
1203 this->
makeAdjacent(inner_he_[i], inner_he_[(i + 1) % n], free_he_[i]);
1209 for (
int i = 0; i < n; ++i) {
1212 vertices[i], vertices[(i + 1) % n], half_edge_data, edge_data);
1217 for (
int i = 0; i < n; ++i) {
1218 int j = (i + 1) % n;
1219 if (is_new_[i] && is_new_[j])
1221 else if (is_new_[i] && !is_new_[j])
1222 this->
connectNewOld(inner_he_[i], inner_he_[j], vertices[j]);
1223 else if (!is_new_[i] && is_new_[j])
1224 this->
connectOldNew(inner_he_[i], inner_he_[j], vertices[j]);
1251 half_edges_.push_back(
HalfEdge(idx_v_b));
1252 half_edges_.push_back(
HalfEdge(idx_v_a));
1258 return (
static_cast<HalfEdgeIndex>(half_edges_.size() - 2));
1277 std::vector<bool>::reference is_new_ab,
1278 std::true_type )
const
1298 std::vector<bool>::reference is_new_ab,
1299 std::false_type )
const
1320 }
while (++circ != circ_end);
1329 const bool is_new_ab,
1330 const bool is_new_bc,
1331 const bool is_isolated_b,
1332 std::vector<bool>::reference ,
1334 std::true_type )
const
1336 return !(is_new_ab && is_new_bc && !is_isolated_b);
1351 const bool is_new_ab,
1352 const bool is_new_bc,
1354 std::vector<bool>::reference make_adjacent_ab_bc,
1356 std::false_type )
const
1358 if (is_new_ab || is_new_bc) {
1359 make_adjacent_ab_bc =
false;
1364 make_adjacent_ab_bc =
false;
1368 make_adjacent_ab_bc =
true;
1421 faces_.push_back(
Face(inner_he.back()));
1426 for (
const auto& idx_half_edge : inner_he) {
1465 this->
connectNewNew(idx_he_ab, idx_he_bc, idx_v_b, std::true_type());
1531 if (idx_he_b_out == idx_he_bc)
1537 while (++circ != circ_end) {
1551 template <
class DataT>
1559 template <
class DataT>
1576 assert(this->
isValid(idx_face));
1577 delete_faces_face_.clear();
1578 delete_faces_face_.push_back(idx_face);
1580 while (!delete_faces_face_.empty()) {
1581 const FaceIndex idx_face_cur = delete_faces_face_.back();
1582 delete_faces_face_.pop_back();
1586 this->
deleteFace(idx_face_cur, std::false_type());
1594 assert(this->
isValid(idx_face));
1600 is_boundary_.clear();
1606 is_boundary_.push_back(
1608 }
while (++circ != circ_end);
1609 assert(inner_he_.size() >= 3);
1611 const int n =
static_cast<int>(inner_he_.size());
1614 if (IsManifold::value) {
1615 for (
int i = 0; i < n; ++i) {
1617 this->
reconnect(inner_he_[i], inner_he_[j], is_boundary_[i], is_boundary_[j]);
1619 for (
int i = 0; i < n; ++i) {
1620 this->
getHalfEdge(inner_he_[i]).idx_face_.invalidate();
1624 for (
int i = 0; i < n; ++i) {
1626 this->
reconnect(inner_he_[i], inner_he_[j], is_boundary_[i], is_boundary_[j]);
1627 this->
getHalfEdge(inner_he_[i]).idx_face_.invalidate();
1643 const bool is_boundary_ba,
1644 const bool is_boundary_cb)
1650 if (is_boundary_ba && is_boundary_cb)
1654 if (idx_he_cb_next == idx_he_ba)
1666 else if (is_boundary_ba && !is_boundary_cb)
1674 else if (!is_boundary_ba && is_boundary_cb)
1700 delete_faces_face_.push_back(this->
getFaceIndex((circ++).getTargetIndex()));
1702#ifdef PCL_GEOMETRY_MESH_BASE_TEST_DELETE_FACE_MANIFOLD_2
1710 pcl::geometry::g_pcl_geometry_mesh_base_test_delete_face_manifold_2_success =
1742 assert(this->
isValid(idx_vertex));
1750 assert(this->
isValid(idx_he));
1751 this->
getHalfEdge(idx_he).idx_terminating_vertex_.invalidate();
1758 assert(this->
isValid(idx_edge));
1759 this->
markDeleted(pcl::geometry::toHalfEdgeIndex(idx_edge,
true));
1760 this->
markDeleted(pcl::geometry::toHalfEdgeIndex(idx_edge,
false));
1767 assert(this->
isValid(idx_face));
1768 this->
getFace(idx_face).idx_inner_half_edge_.invalidate();
1788 template <
class ElementContainerT,
1789 class DataContainerT,
1790 class IndexContainerT,
1793 remove(ElementContainerT& elements, DataContainerT& data_cloud)
1795 using Index =
typename IndexContainerT::value_type;
1796 using Element =
typename ElementContainerT::value_type;
1798 if (HasDataT::value)
1799 assert(elements.size() == data_cloud.size());
1801 assert(data_cloud.empty());
1803 IndexContainerT new_indices(elements.size(),
1804 typename IndexContainerT::value_type());
1805 Index ind_old(0), ind_new(0);
1807 typename ElementContainerT::const_iterator it_e_old = elements.begin();
1808 auto it_e_new = elements.begin();
1810 typename DataContainerT::const_iterator it_d_old = data_cloud.begin();
1811 auto it_d_new = data_cloud.begin();
1813 auto it_ind_new = new_indices.begin();
1814 typename IndexContainerT::const_iterator it_ind_new_end = new_indices.end();
1816 while (it_ind_new != it_ind_new_end) {
1818 *it_ind_new = ind_new++;
1821 *it_e_new++ = *it_e_old;
1822 this->
assignIf(it_d_old, it_d_new, HasDataT());
1831 elements.resize(ind_new.get(), Element());
1832 if (HasDataT::value) {
1833 data_cloud.resize(ind_new.get());
1835 else if (it_d_old != data_cloud.begin() || it_d_new != data_cloud.begin()) {
1836 std::cerr <<
"TODO: Bug in MeshBase::remove!\n";
1841 return (new_indices);
1845 template <
class IteratorT>
1853 template <
class IteratorT>
1859 template <
class ConstIteratorT,
class IteratorT>
1863 std::true_type )
const
1869 template <
class ConstIteratorT,
class IteratorT>
1873 std::false_type )
const
1885 assert(this->
isValid(idx_vertex));
1886 this->
getVertex(idx_vertex).idx_outgoing_half_edge_ = idx_outgoing_half_edge;
1894 assert(this->
isValid(idx_half_edge));
1895 this->
getHalfEdge(idx_half_edge).idx_terminating_vertex_ = idx_terminating_vertex;
1903 assert(this->
isValid(idx_half_edge));
1904 this->
getHalfEdge(idx_half_edge).idx_next_half_edge_ = idx_next_half_edge;
1912 assert(this->
isValid(idx_half_edge));
1913 this->
getHalfEdge(idx_half_edge).idx_prev_half_edge_ = idx_prev_half_edge;
1920 assert(this->
isValid(idx_half_edge));
1921 this->
getHalfEdge(idx_half_edge).idx_face_ = idx_face;
1929 assert(this->
isValid(idx_face));
1930 this->
getFace(idx_face).idx_inner_half_edge_ = idx_inner_half_edge;
1948 }
while (++circ != circ_end);
1965 }
while (++circ != circ_end);
1985 if (!this->
isBoundary((circ++).getTargetIndex()))
1990 }
while (++circ != circ_end);
2006 for (std::size_t i = 0; i < this->
sizeVertices(); ++i) {
2018 template <
class DataCloudT>
2020 reserveData(DataCloudT& cloud,
const std::size_t n, std::true_type )
const
2026 template <
class DataCloudT>
2030 std::false_type )
const
2034 template <
class DataCloudT>
2037 const std::size_t n,
2038 const typename DataCloudT::value_type& data,
2039 std::true_type )
const
2041 data_cloud.resize(n, data);
2045 template <
class DataCloudT>
2049 const typename DataCloudT::value_type& ,
2050 std::false_type )
const
2054 template <
class DataCloudT>
2062 template <
class DataCloudT>
2075 assert(this->
isValid(idx_vertex));
2076 return (vertices_[idx_vertex.
get()]);
2083 assert(this->
isValid(idx_vertex));
2084 return (vertices_[idx_vertex.
get()]);
2091 assert(this->
isValid(idx_vertex));
2092 vertices_[idx_vertex.
get()] = vertex;
2103 assert(this->
isValid(idx_he));
2104 return (half_edges_[idx_he.
get()]);
2111 assert(this->
isValid(idx_he));
2112 return (half_edges_[idx_he.
get()]);
2119 assert(this->
isValid(idx_he));
2120 half_edges_[idx_he.
get()] = half_edge;
2131 assert(this->
isValid(idx_face));
2132 return (faces_[idx_face.
get()]);
2139 assert(this->
isValid(idx_face));
2140 return (faces_[idx_face.
get()]);
2147 assert(this->
isValid(idx_face));
2148 faces_[idx_face.
get()] = face;
2186 std::vector<bool> is_new_;
2189 std::vector<bool> make_adjacent_;
2192 std::vector<bool> is_boundary_;
2201 template <
class MeshT>
void push_back(const PointT &pt)
Insert a new point in the cloud, at the end of the container.
const PointT & back() const
const PointT & front() const
void resize(std::size_t count)
Resizes the container to contain count elements.
iterator begin() noexcept
void invalidate()
Invalidate the index.
bool isValid() const
Returns true if the index is valid.
int get() const
Get the index.
Circulates clockwise around a face and returns an index to the face of the outer half-edge (the targe...
Circulates counter-clockwise around a vertex and returns an index to the face of the outgoing half-ed...
FaceIndex getTargetIndex() const
Get the index to the target face.
Circulates counter-clockwise around a vertex and returns an index to the incoming half-edge (the targ...
HalfEdgeIndex getTargetIndex() const
Get the index to the incoming half-edge.
Circulates clockwise around a face and returns an index to the inner half-edge (the target).
HalfEdgeIndex getTargetIndex() const
Get the index to the inner half-edge.
Base class for the half-edge mesh.
void setOutgoingHalfEdgeIndex(const VertexIndex &idx_vertex, const HalfEdgeIndex &idx_outgoing_half_edge)
Set the outgoing half-edge index to a given vertex.
HalfEdgeIndex getNextHalfEdgeIndex(const HalfEdgeIndex &idx_half_edge) const
Get the next half-edge index to a given half-edge.
std::vector< Face > Faces
shared_ptr< const Self > ConstPtr
VertexDataCloud & getVertexDataCloud()
Get access to the stored vertex data.
bool isDeleted(const FaceIndex &idx_face) const
Check if the given face is marked as deleted.
void setNextHalfEdgeIndex(const HalfEdgeIndex &idx_half_edge, const HalfEdgeIndex &idx_next_half_edge)
Set the next half_edge index to a given half-edge.
bool emptyVertices() const
Check if the vertices are empty.
FaceDataCloud getFaceDataCloud() const
Get the stored face data.
std::integral_constant< bool, !std::is_same< VertexData, pcl::geometry::NoData >::value > HasVertexData
bool isBoundary(const VertexIndex &idx_vertex) const
Check if the given vertex lies on the boundary.
VertexAroundVertexCirculator getVertexAroundVertexCirculator(const HalfEdgeIndex &idx_outgoing_half_edge) const
pcl::geometry::IncomingHalfEdgeAroundVertexCirculator< const Self > IncomingHalfEdgeAroundVertexCirculator
InnerHalfEdgeAroundFaceCirculator getInnerHalfEdgeAroundFaceCirculator(const HalfEdgeIndex &idx_inner_half_edge) const
bool isBoundary(const FaceIndex &idx_face, std::true_type) const
Check if any vertex of the face lies on the boundary.
void deleteEdge(const EdgeIndex &idx_edge)
Mark the given edge (both half-edges) and the associated faces as deleted.
VertexAroundVertexCirculator getVertexAroundVertexCirculator(const VertexIndex &idx_vertex) const
pcl::geometry::OuterHalfEdgeAroundFaceCirculator< const Self > OuterHalfEdgeAroundFaceCirculator
void deleteFace(const FaceIndex &idx_face)
Mark the given face as deleted.
Face & getFace(const FaceIndex &idx_face)
Get the face for the given index.
std::vector< Vertex > Vertices
EdgeIndex getEdgeIndex(const EdgeData &edge_data) const
Get the index associated to the given edge data.
HalfEdgeIndex getOppositeHalfEdgeIndex(const HalfEdgeIndex &idx_half_edge) const
Get the opposite half-edge index to a given half-edge.
HalfEdgeIndex getOuterHalfEdgeIndex(const FaceIndex &idx_face) const
Get the outer half-edge inex to a given face.
std::vector< EdgeIndex > EdgeIndices
bool emptyEdges() const
Check if the edges are empty.
VertexAroundFaceCirculator getVertexAroundFaceCirculator(const HalfEdgeIndex &idx_inner_half_edge) const
void setHalfEdge(const HalfEdgeIndex &idx_he, const HalfEdge &half_edge)
Set the half-edge at the given index.
FaceIndex connectFace(const HalfEdgeIndices &inner_he, const FaceData &face_data)
Add a face to the mesh and connect it to the half-edges.
HalfEdgeIndex getHalfEdgeIndex(const HalfEdgeData &half_edge_data) const
Get the index associated to the given half-edge data.
void resizeData(DataCloudT &data_cloud, const std::size_t n, const typename DataCloudT::value_type &data, std::true_type) const
Resize the mesh data.
HalfEdgeDataCloud getHalfEdgeDataCloud() const
Get the stored half-edge data.
pcl::geometry::Vertex Vertex
bool isBoundary(const HalfEdgeIndex &idx_he) const
Check if the given half-edge lies on the boundary.
IncomingHalfEdgeAroundVertexCirculator getIncomingHalfEdgeAroundVertexCirculator(const VertexIndex &idx_vertex) const
std::size_t sizeVertices() const
Get the number of the vertices.
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.
void resizeVertices(const std::size_t n, const VertexData &data=VertexData())
Resize the the vertices to n elements.
HalfEdgeDataCloud & getHalfEdgeDataCloud()
Get access to the stored half-edge data.
bool setEdgeDataCloud(const EdgeDataCloud &edge_data_cloud)
Change the stored edge data.
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.
std::size_t sizeEdges() const
Get the number of the edges.
pcl::geometry::FaceIndex FaceIndex
InnerHalfEdgeAroundFaceCirculator getInnerHalfEdgeAroundFaceCirculator(const FaceIndex &idx_face) const
typename MeshTraitsT::EdgeData EdgeData
bool emptyFaces() const
Check if the faces are empty.
bool empty() const
Check if the mesh is empty.
IncomingHalfEdgeAroundVertexCirculator getIncomingHalfEdgeAroundVertexCirculator(const HalfEdgeIndex &idx_incoming_half_edge) const
void deleteVertex(const VertexIndex &idx_vertex)
Mark the given vertex and all connected half-edges and faces as deleted.
std::vector< FaceIndex > FaceIndices
void reserveData(DataCloudT &, const std::size_t, std::false_type) const
Does nothing.
void connectOldNew(const HalfEdgeIndex &idx_he_ab, const HalfEdgeIndex &idx_he_bc, const VertexIndex &idx_v_b)
The second half-edge is new.
bool setHalfEdgeDataCloud(const HalfEdgeDataCloud &half_edge_data_cloud)
Change the stored half-edge data.
VertexIndex getOriginatingVertexIndex(const HalfEdgeIndex &idx_half_edge) const
Get the originating vertex index to a given half-edge.
std::size_t sizeFaces() const
Get the number of the faces.
void deleteEdge(const HalfEdgeIndex &idx_he)
Mark the given half-edge, the opposite half-edge and the associated faces as deleted.
void resizeData(DataCloudT &, const std::size_t, const typename DataCloudT::value_type &, std::false_type) const
Does nothing.
typename HalfEdges::iterator HalfEdgeIterator
typename MeshTraitsT::HalfEdgeData HalfEdgeData
void markDeleted(const FaceIndex &idx_face)
Mark the given face as deleted.
OutgoingHalfEdgeAroundVertexCirculator getOutgoingHalfEdgeAroundVertexCirculator(const HalfEdgeIndex &idx_outgoing_half_edge) const
HalfEdgeIndex getInnerHalfEdgeIndex(const FaceIndex &idx_face) const
Get the inner half-edge index to a given face.
void addData(pcl::PointCloud< DataT > &, const DataT &, std::false_type)
Does nothing.
pcl::PointCloud< VertexData > VertexDataCloud
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.
HalfEdgeIndex getPrevHalfEdgeIndex(const HalfEdgeIndex &idx_half_edge) const
Get the previous half-edge index to a given half-edge.
bool setFaceDataCloud(const FaceDataCloud &face_data_cloud)
Change the stored face data.
OuterHalfEdgeAroundFaceCirculator getOuterHalfEdgeAroundFaceCirculator(const HalfEdgeIndex &idx_inner_half_edge) const
void clearData(DataCloudT &, std::false_type) const
Does nothing.
Vertex getVertex(const VertexIndex &idx_vertex) const
Get the vertex for the given index.
pcl::geometry::FaceAroundFaceCirculator< const Self > FaceAroundFaceCirculator
FaceIndex addFaceImplBase(const VertexIndices &vertices, const FaceData &face_data, const EdgeData &edge_data, const HalfEdgeData &half_edge_data)
General implementation of addFace.
typename Faces::const_iterator FaceConstIterator
typename MeshTraitsT::VertexData VertexData
void markDeleted(const VertexIndex &idx_vertex)
Mark the given vertex as deleted.
bool setVertexDataCloud(const VertexDataCloud &vertex_data_cloud)
Change the stored vertex data.
pcl::geometry::FaceAroundVertexCirculator< const Self > FaceAroundVertexCirculator
std::vector< HalfEdgeIndex > HalfEdgeIndices
void reserveFaces(const std::size_t n)
Reserve storage space for n faces.
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).
bool isValid(const HalfEdgeIndex &idx_he) const
Check if the given half-edge index is a valid index into the mesh.
void markDeleted(const HalfEdgeIndex &idx_he)
Mark the given half-edge as deleted.
std::size_t sizeHalfEdges() const
Get the number of the half-edges.
std::integral_constant< bool, !std::is_same< EdgeData, pcl::geometry::NoData >::value > HasEdgeData
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).
void setVertex(const VertexIndex &idx_vertex, const Vertex &vertex)
Set the vertex at the given index.
OutgoingHalfEdgeAroundVertexCirculator getOutgoingHalfEdgeAroundVertexCirculator(const VertexIndex &idx_vertex) const
std::integral_constant< bool, !std::is_same< FaceData, pcl::geometry::NoData >::value > HasFaceData
VertexIndex getVertexIndex(const VertexData &vertex_data) const
Get the index associated to the given vertex data.
void assignIf(const ConstIteratorT, IteratorT, std::false_type) const
Does nothing.
void addData(pcl::PointCloud< DataT > &cloud, const DataT &data, std::true_type)
Add mesh data.
pcl::PointCloud< FaceData > FaceDataCloud
bool isManifold(std::true_type) const
Always manifold.
bool isValid(const EdgeIndex &idx_edge) const
Check if the given edge index is a valid index into the mesh.
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).
VertexAroundFaceCirculator getVertexAroundFaceCirculator(const FaceIndex &idx_face) const
pcl::geometry::VertexIndex VertexIndex
void setTerminatingVertexIndex(const HalfEdgeIndex &idx_half_edge, const VertexIndex &idx_terminating_vertex)
Set the terminating vertex index to a given half-edge.
bool isValid(const FaceIndex &idx_face) const
Check if the given face index is a valid index into the mesh.
void reserveData(DataCloudT &cloud, const std::size_t n, std::true_type) const
Reserve storage space for the mesh data.
void reserveEdges(const std::size_t n)
Reserve storage space for n edges (2*n storage space is reserved for the half-edges).
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.
pcl::geometry::HalfEdge HalfEdge
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.
bool isBoundary(const FaceIndex &idx_face) const
Check if the given face lies on the boundary.
bool isDeleted(const HalfEdgeIndex &idx_he) const
Check if the given half-edge is marked as deleted.
std::vector< HalfEdge > HalfEdges
bool isIsolated(const VertexIndex &idx_vertex) const
Check if the given vertex is isolated (not connected to other elements).
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.
Face getFace(const FaceIndex &idx_face) const
Get the face for the given index.
void assignIf(const ConstIteratorT source, IteratorT target, std::true_type) const
Assign the source iterator to the target iterator.
FaceAroundFaceCirculator getFaceAroundFaceCirculator(const FaceIndex &idx_face) const
bool isDeleted(const VertexIndex &idx_vertex) const
Check if the given vertex is marked as deleted.
HalfEdgeIndex getOutgoingHalfEdgeIndex(const VertexIndex &idx_vertex) const
Get the outgoing half-edge index to a given vertex.
typename Vertices::const_iterator VertexConstIterator
EdgeDataCloud & getEdgeDataCloud()
Get access to the stored edge data.
bool isManifold(const VertexIndex &idx_vertex, std::false_type) const
Check if the given vertex is manifold.
bool isBoundary(const FaceIndex &idx_face) const
Check if the given face lies on the boundary.
void setFace(const FaceIndex &idx_face, const Face &face)
Set the face at the given index.
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).
HalfEdge & getHalfEdge(const HalfEdgeIndex &idx_he)
Get the half-edge for the given index.
bool isEqualTopology(const Self &other) const
Check if the other mesh has the same topology as this mesh.
VertexIndex addVertex(const VertexData &vertex_data=VertexData())
Add a vertex to the mesh.
FaceAroundVertexCirculator getFaceAroundVertexCirculator(const HalfEdgeIndex &idx_outgoing_half_edge) const
VertexDataCloud getVertexDataCloud() const
Get the stored vertex data.
void setPrevHalfEdgeIndex(const HalfEdgeIndex &idx_half_edge, const HalfEdgeIndex &idx_prev_half_edge)
Set the previous half-edge index to a given half-edge.
void reserveVertices(const std::size_t n)
Reserve storage space n vertices.
typename HalfEdges::const_iterator HalfEdgeConstIterator
void resizeFaces(const std::size_t n, const FaceData &data=FaceData())
Resize the faces to n elements.
pcl::geometry::VertexAroundFaceCirculator< const Self > VertexAroundFaceCirculator
FaceIndex getOppositeFaceIndex(const HalfEdgeIndex &idx_half_edge) const
Get the face index to a given half-edge.
typename MeshTraitsT::IsManifold IsManifold
pcl::PointCloud< HalfEdgeData > HalfEdgeDataCloud
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.
typename MeshTraitsT::FaceData FaceData
Vertex & getVertex(const VertexIndex &idx_vertex)
Get the vertex for the given index.
pcl::geometry::InnerHalfEdgeAroundFaceCirculator< const Self > InnerHalfEdgeAroundFaceCirculator
void connectOldOld(const HalfEdgeIndex &, const HalfEdgeIndex &, const VertexIndex &, std::true_type)
Both half-edges are old (manifold version).
FaceDataCloud & getFaceDataCloud()
Get access to the stored face data.
void markDeleted(const EdgeIndex &idx_edge)
Mark the given edge (both half-edges) as deleted.
std::vector< VertexIndex > VertexIndices
void connectNewOld(const HalfEdgeIndex &idx_he_ab, const HalfEdgeIndex &idx_he_bc, const VertexIndex &idx_v_b)
The first half-edge is new.
FaceAroundVertexCirculator getFaceAroundVertexCirculator(const VertexIndex &idx_vertex) const
pcl::geometry::VertexAroundVertexCirculator< const Self > VertexAroundVertexCirculator
pcl::geometry::EdgeIndex EdgeIndex
bool isValid(const VertexIndex &idx_vertex) const
Check if the given vertex index is a valid index into the mesh.
VertexIndex getTerminatingVertexIndex(const HalfEdgeIndex &idx_half_edge) const
Get the terminating vertex index to a given half-edge.
EdgeDataCloud getEdgeDataCloud() const
Get the stored edge data.
void deleteFace(const FaceIndex &idx_face, std::false_type)
Non-manifold version of deleteFace.
void cleanUp()
Removes all mesh elements and data that are marked as deleted.
bool isManifold(std::false_type) const
Check if all vertices in the mesh are manifold.
void clearData(DataCloudT &cloud, std::true_type) const
Clear the mesh data.
FaceIndex getFaceIndex(const FaceData &face_data) const
Get the index associated to the given face data.
void setFaceIndex(const HalfEdgeIndex &idx_half_edge, const FaceIndex &idx_face)
Set the face index to a given half-edge.
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.
std::integral_constant< bool, !std::is_same< HalfEdgeData, pcl::geometry::NoData >::value > HasHalfEdgeData
void setInnerHalfEdgeIndex(const FaceIndex &idx_face, const HalfEdgeIndex &idx_inner_half_edge)
Set the inner half-edge index to a given face.
FaceIndex getFaceIndex(const HalfEdgeIndex &idx_half_edge) const
Get the face index to a given half-edge.
void incrementIf(IteratorT &, std::false_type) const
Does nothing.
bool isBoundary(const FaceIndex &idx_face, std::false_type) const
Check if any edge of the face lies on the boundary.
MeshBase< DerivedT, MeshTraitsT, MeshTagT > Self
bool isDeleted(const EdgeIndex &idx_edge) const
Check if the given edge (any of the two half-edges) is marked as deleted.
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).
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.
void reconnectNBNB(const HalfEdgeIndex &idx_he_bc, const HalfEdgeIndex &, const VertexIndex &idx_v_b, std::false_type)
Both edges are not on the boundary.
bool isManifold() const
Check if the mesh is manifold.
void deleteFace(const FaceIndex &idx_face, std::true_type)
Manifold version of deleteFace.
bool isManifold(const VertexIndex &idx_vertex) const
Check if the given vertex is manifold.
OuterHalfEdgeAroundFaceCirculator getOuterHalfEdgeAroundFaceCirculator(const FaceIndex &idx_face) const
typename Vertices::iterator VertexIterator
void clear()
Clear all mesh elements and data.
void incrementIf(IteratorT &it, std::true_type) const
Increment the iterator.
pcl::geometry::OutgoingHalfEdgeAroundVertexCirculator< const Self > OutgoingHalfEdgeAroundVertexCirculator
IndexContainerT remove(ElementContainerT &elements, DataContainerT &data_cloud)
Removes mesh elements and data that are marked as deleted from the container.
typename Faces::iterator FaceIterator
pcl::geometry::HalfEdgeIndex HalfEdgeIndex
FaceAroundFaceCirculator getFaceAroundFaceCirculator(const HalfEdgeIndex &idx_inner_half_edge) const
HalfEdgeIndex getIncomingHalfEdgeIndex(const VertexIndex &idx_vertex) const
Get the incoming half-edge index to a given vertex.
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.
pcl::PointCloud< EdgeData > EdgeDataCloud
HalfEdge getHalfEdge(const HalfEdgeIndex &idx_he) const
Get the half-edge for the given index.
bool isManifold(const VertexIndex &, std::true_type) const
Always manifold.
Read / write the half-edge mesh from / to a file.
Circulates clockwise around a face and returns an index to the outer half-edge (the target).
HalfEdgeIndex getTargetIndex() const
Get the index to the outer half-edge.
Circulates counter-clockwise around a vertex and returns an index to the outgoing half-edge (the targ...
HalfEdgeIndex getTargetIndex() const
Get the index to the outgoing half-edge.
Circulates clockwise around a face and returns an index to the terminating vertex of the inner half-e...
VertexIndex getTargetIndex() const
Get the index to the target vertex.
Circulates counter-clockwise around a vertex and returns an index to the terminating vertex of the ou...
VertexIndex getTargetIndex() const
Get the index to the target vertex.
HalfEdgeIndex getCurrentHalfEdgeIndex() const
Get the half-edge that is currently stored in the circulator.
A vertex is a node in the mesh.
#define PCL_MAKE_ALIGNED_OPERATOR_NEW
Macro to signal a class requires a custom allocator.
Defines functions, macros and traits for allocating and using memory.
Defines all the PCL and non-PCL macros used.
Describes a set of vertices in a polygon mesh, by basically storing an array of indices.