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>
58#ifdef PCL_GEOMETRY_MESH_BASE_TEST_DELETE_FACE_MANIFOLD_2
61bool g_pcl_geometry_mesh_base_test_delete_face_manifold_2_success;
94template <
class DerivedT,
class MeshTraitsT,
class MeshTagT>
98 using Ptr = shared_ptr<Self>;
111 static_assert(std::is_convertible<IsManifold, bool>::value,
112 "MeshTraitsT::IsManifold is not convertible to bool");
118 std::integral_constant<bool,
119 !std::is_same<VertexData, pcl::geometry::NoData>::value>;
121 std::integral_constant<bool,
122 !std::is_same<HalfEdgeData, pcl::geometry::NoData>::value>;
124 std::integral_constant<bool,
125 !std::is_same<EdgeData, pcl::geometry::NoData>::value>;
127 std::integral_constant<bool,
128 !std::is_same<FaceData, pcl::geometry::NoData>::value>;
165 : vertex_data_cloud_()
166 , half_edge_data_cloud_()
184 vertices_.push_back(
Vertex());
209 return (
static_cast<Derived*
>(
this)->addFaceImpl(
210 vertices, face_data, edge_data, half_edge_data));
220 assert(this->
isValid(idx_vertex));
224 delete_faces_vertex_.clear();
232 }
while (++circ != circ_end);
234 for (
const auto& delete_me : delete_faces_vertex_) {
270 assert(this->
isValid(idx_edge));
271 this->
deleteEdge(pcl::geometry::toHalfEdgeIndex(idx_edge));
273 pcl::geometry::toHalfEdgeIndex(idx_edge,
false)));
284 assert(this->
isValid(idx_face));
300 this->remove<Vertices, VertexDataCloud, VertexIndices, HasVertexData>(
301 vertices_, vertex_data_cloud_);
303 this->remove<HalfEdges, HalfEdgeDataCloud, HalfEdgeIndices, HasHalfEdgeData>(
304 half_edges_, half_edge_data_cloud_);
306 this->remove<Faces, FaceDataCloud, FaceIndices, HasFaceData>(faces_,
310 if (HasEdgeData::value) {
311 auto it_ed_old = edge_data_cloud_.
begin();
312 auto it_ed_new = edge_data_cloud_.
begin();
314 for (
auto it_ind = new_half_edge_indices.cbegin(),
315 it_ind_end = new_half_edge_indices.cend();
316 it_ind != it_ind_end;
317 it_ind += 2, ++it_ed_old) {
318 if (it_ind->isValid()) {
319 *it_ed_new++ = *it_ed_old;
326 for (
auto& vertex : vertices_) {
327 if (vertex.idx_outgoing_half_edge_.isValid()) {
328 vertex.idx_outgoing_half_edge_ =
329 new_half_edge_indices[vertex.idx_outgoing_half_edge_.get()];
333 for (
auto& half_edge : half_edges_) {
334 half_edge.idx_terminating_vertex_ =
335 new_vertex_indices[half_edge.idx_terminating_vertex_.get()];
336 half_edge.idx_next_half_edge_ =
337 new_half_edge_indices[half_edge.idx_next_half_edge_.get()];
338 half_edge.idx_prev_half_edge_ =
339 new_half_edge_indices[half_edge.idx_prev_half_edge_.get()];
340 if (half_edge.idx_face_.isValid()) {
341 half_edge.idx_face_ = new_face_indices[half_edge.idx_face_.get()];
345 for (
auto& face : faces_) {
346 face.idx_inner_half_edge_ =
347 new_half_edge_indices[face.idx_inner_half_edge_.get()];
359 assert(this->
isValid(idx_vertex));
360 return (this->
getVertex(idx_vertex).idx_outgoing_half_edge_);
367 assert(this->
isValid(idx_vertex));
379 assert(this->
isValid(idx_half_edge));
380 return (this->
getHalfEdge(idx_half_edge).idx_terminating_vertex_);
387 assert(this->
isValid(idx_half_edge));
396 assert(this->
isValid(idx_half_edge));
399 : idx_half_edge.
get() + 1));
406 assert(this->
isValid(idx_half_edge));
407 return (this->
getHalfEdge(idx_half_edge).idx_next_half_edge_);
414 assert(this->
isValid(idx_half_edge));
415 return (this->
getHalfEdge(idx_half_edge).idx_prev_half_edge_);
422 assert(this->
isValid(idx_half_edge));
423 return (this->
getHalfEdge(idx_half_edge).idx_face_);
430 assert(this->
isValid(idx_half_edge));
442 assert(this->
isValid(idx_face));
443 return (this->
getFace(idx_face).idx_inner_half_edge_);
450 assert(this->
isValid(idx_face));
462 assert(this->
isValid(idx_vertex));
470 assert(this->
isValid(idx_outgoing_half_edge));
478 assert(this->
isValid(idx_vertex));
487 assert(this->
isValid(idx_outgoing_half_edge));
495 assert(this->
isValid(idx_vertex));
504 assert(this->
isValid(idx_incoming_half_edge));
512 assert(this->
isValid(idx_vertex));
520 assert(this->
isValid(idx_outgoing_half_edge));
528 assert(this->
isValid(idx_face));
536 assert(this->
isValid(idx_inner_half_edge));
544 assert(this->
isValid(idx_face));
552 assert(this->
isValid(idx_inner_half_edge));
560 assert(this->
isValid(idx_face));
568 assert(this->
isValid(idx_inner_half_edge));
576 assert(this->
isValid(idx_face));
584 assert(this->
isValid(idx_inner_half_edge));
600 if (this->
sizeFaces() != other.sizeFaces())
603 for (std::size_t i = 0; i < this->
sizeVertices(); ++i) {
626 for (std::size_t i = 0; i < this->
sizeFaces(); ++i) {
628 other.getInnerHalfEdgeIndex(
FaceIndex(i)))
643 return (idx_vertex >=
static_cast<VertexIndex>(0) &&
644 idx_vertex <
static_cast<VertexIndex>(vertices_.size()));
659 return (idx_edge >=
static_cast<EdgeIndex>(0) &&
660 idx_edge <
static_cast<EdgeIndex>(half_edges_.size() / 2));
667 return (idx_face >=
static_cast<FaceIndex>(0) &&
668 idx_face <
static_cast<FaceIndex>(faces_.size()));
679 assert(this->
isValid(idx_vertex));
696 assert(this->
isValid(idx_edge));
697 return (this->
isDeleted(pcl::geometry::toHalfEdgeIndex(idx_edge,
true)) ||
698 this->
isDeleted(pcl::geometry::toHalfEdgeIndex(idx_edge,
false)));
705 assert(this->
isValid(idx_face));
717 assert(this->
isValid(idx_vertex));
730 assert(this->
isValid(idx_vertex));
749 assert(this->
isValid(idx_edge));
750 const HalfEdgeIndex& idx = pcl::geometry::toHalfEdgeIndex(idx_edge);
761 template <
bool CheckVerticesT>
765 assert(this->
isValid(idx_face));
766 return (this->
isBoundary(idx_face, std::integral_constant<bool, CheckVerticesT>()));
774 assert(this->
isValid(idx_face));
775 return (this->
isBoundary(idx_face, std::true_type()));
786 assert(this->
isValid(idx_vertex));
807 return (vertices_.size());
814 assert(half_edges_.size() % 2 == 0);
815 return (half_edges_.size());
822 assert(half_edges_.size() % 2 == 0);
823 return (half_edges_.size() / 2);
830 return (faces_.size());
848 return (vertices_.empty());
855 return (half_edges_.empty());
862 return (faces_.empty());
873 vertices_.reserve(n);
882 half_edges_.reserve(2 * n);
903 vertices_.resize(n,
Vertex());
913 half_edges_.resize(2 * n,
HalfEdge());
922 faces_.resize(n,
Face());
954 return (vertex_data_cloud_);
961 return (vertex_data_cloud_);
972 if (vertex_data_cloud.
size() == vertex_data_cloud_.
size()) {
973 vertex_data_cloud_ = vertex_data_cloud;
989 return (half_edge_data_cloud_);
996 return (half_edge_data_cloud_);
1007 if (half_edge_data_cloud.
size() == half_edge_data_cloud_.
size()) {
1008 half_edge_data_cloud_ = half_edge_data_cloud;
1024 return (edge_data_cloud_);
1031 return (edge_data_cloud_);
1041 if (edge_data_cloud.
size() == edge_data_cloud_.
size()) {
1042 edge_data_cloud_ = edge_data_cloud;
1058 return (face_data_cloud_);
1065 return (face_data_cloud_);
1075 if (face_data_cloud.
size() == face_data_cloud_.
size()) {
1076 face_data_cloud_ = face_data_cloud;
1092 if (HasVertexData::value) {
1093 assert(&vertex_data >= &vertex_data_cloud_.
front() &&
1094 &vertex_data <= &vertex_data_cloud_.
back());
1095 return (
VertexIndex(std::distance(&vertex_data_cloud_.
front(), &vertex_data)));
1104 if (HasHalfEdgeData::value) {
1105 assert(&half_edge_data >= &half_edge_data_cloud_.
front() &&
1106 &half_edge_data <= &half_edge_data_cloud_.
back());
1108 std::distance(&half_edge_data_cloud_.
front(), &half_edge_data)));
1117 if (HasEdgeData::value) {
1118 assert(&edge_data >= &edge_data_cloud_.
front() &&
1119 &edge_data <= &edge_data_cloud_.
back());
1120 return (
EdgeIndex(std::distance(&edge_data_cloud_.
front(), &edge_data)));
1129 if (HasFaceData::value) {
1130 assert(&face_data >= &face_data_cloud_.
front() &&
1131 &face_data <= &face_data_cloud_.
back());
1132 return (
FaceIndex(std::distance(&face_data_cloud_.
front(), &face_data)));
1166 const int n =
static_cast<int>(vertices.size());
1171 inner_he_.resize(n);
1174 make_adjacent_.resize(n);
1175 for (
int i = 0; i < n; ++i) {
1177 vertices[(i + 1) % n],
1184 for (
int i = 0; i < n; ++i) {
1185 int j = (i + 1) % n;
1199 if (!IsManifold::value) {
1200 for (
int i = 0; i < n; ++i) {
1201 if (make_adjacent_[i]) {
1202 this->
makeAdjacent(inner_he_[i], inner_he_[(i + 1) % n], free_he_[i]);
1208 for (
int i = 0; i < n; ++i) {
1211 vertices[i], vertices[(i + 1) % n], half_edge_data, edge_data);
1216 for (
int i = 0; i < n; ++i) {
1217 int j = (i + 1) % n;
1218 if (is_new_[i] && is_new_[j])
1220 else if (is_new_[i] && !is_new_[j])
1221 this->
connectNewOld(inner_he_[i], inner_he_[j], vertices[j]);
1222 else if (!is_new_[i] && is_new_[j])
1223 this->
connectOldNew(inner_he_[i], inner_he_[j], vertices[j]);
1250 half_edges_.push_back(
HalfEdge(idx_v_b));
1251 half_edges_.push_back(
HalfEdge(idx_v_a));
1257 return (
static_cast<HalfEdgeIndex>(half_edges_.size() - 2));
1276 std::vector<bool>::reference is_new_ab,
1277 std::true_type )
const
1297 std::vector<bool>::reference is_new_ab,
1298 std::false_type )
const
1319 }
while (++circ != circ_end);
1328 const bool is_new_ab,
1329 const bool is_new_bc,
1330 const bool is_isolated_b,
1331 std::vector<bool>::reference ,
1333 std::true_type )
const
1335 return !(is_new_ab && is_new_bc && !is_isolated_b);
1350 const bool is_new_ab,
1351 const bool is_new_bc,
1353 std::vector<bool>::reference make_adjacent_ab_bc,
1355 std::false_type )
const
1357 if (is_new_ab || is_new_bc) {
1358 make_adjacent_ab_bc =
false;
1363 make_adjacent_ab_bc =
false;
1367 make_adjacent_ab_bc =
true;
1420 faces_.push_back(
Face(inner_he.back()));
1425 for (
const auto& idx_half_edge : inner_he) {
1464 this->
connectNewNew(idx_he_ab, idx_he_bc, idx_v_b, std::true_type());
1530 if (idx_he_b_out == idx_he_bc)
1536 while (++circ != circ_end) {
1550 template <
class DataT>
1558 template <
class DataT>
1575 assert(this->
isValid(idx_face));
1576 delete_faces_face_.clear();
1577 delete_faces_face_.push_back(idx_face);
1579 while (!delete_faces_face_.empty()) {
1580 const FaceIndex idx_face_cur = delete_faces_face_.back();
1581 delete_faces_face_.pop_back();
1585 this->
deleteFace(idx_face_cur, std::false_type());
1593 assert(this->
isValid(idx_face));
1599 is_boundary_.clear();
1605 is_boundary_.push_back(
1607 }
while (++circ != circ_end);
1608 assert(inner_he_.size() >= 3);
1610 const int n =
static_cast<int>(inner_he_.size());
1613 if (IsManifold::value) {
1614 for (
int i = 0; i < n; ++i) {
1616 this->
reconnect(inner_he_[i], inner_he_[j], is_boundary_[i], is_boundary_[j]);
1618 for (
int i = 0; i < n; ++i) {
1619 this->
getHalfEdge(inner_he_[i]).idx_face_.invalidate();
1623 for (
int i = 0; i < n; ++i) {
1625 this->
reconnect(inner_he_[i], inner_he_[j], is_boundary_[i], is_boundary_[j]);
1626 this->
getHalfEdge(inner_he_[i]).idx_face_.invalidate();
1642 const bool is_boundary_ba,
1643 const bool is_boundary_cb)
1649 if (is_boundary_ba && is_boundary_cb)
1653 if (idx_he_cb_next == idx_he_ba)
1665 else if (is_boundary_ba && !is_boundary_cb)
1673 else if (!is_boundary_ba && is_boundary_cb)
1699 delete_faces_face_.push_back(this->
getFaceIndex((circ++).getTargetIndex()));
1701#ifdef PCL_GEOMETRY_MESH_BASE_TEST_DELETE_FACE_MANIFOLD_2
1709 pcl::geometry::g_pcl_geometry_mesh_base_test_delete_face_manifold_2_success =
1741 assert(this->
isValid(idx_vertex));
1749 assert(this->
isValid(idx_he));
1750 this->
getHalfEdge(idx_he).idx_terminating_vertex_.invalidate();
1757 assert(this->
isValid(idx_edge));
1758 this->
markDeleted(pcl::geometry::toHalfEdgeIndex(idx_edge,
true));
1759 this->
markDeleted(pcl::geometry::toHalfEdgeIndex(idx_edge,
false));
1766 assert(this->
isValid(idx_face));
1767 this->
getFace(idx_face).idx_inner_half_edge_.invalidate();
1787 template <
class ElementContainerT,
1788 class DataContainerT,
1789 class IndexContainerT,
1792 remove(ElementContainerT& elements, DataContainerT& data_cloud)
1794 using Index =
typename IndexContainerT::value_type;
1795 using Element =
typename ElementContainerT::value_type;
1797 if (HasDataT::value)
1798 assert(elements.size() == data_cloud.size());
1800 assert(data_cloud.empty());
1802 IndexContainerT new_indices(elements.size(),
1803 typename IndexContainerT::value_type());
1804 Index ind_old(0), ind_new(0);
1806 typename ElementContainerT::const_iterator it_e_old = elements.begin();
1807 auto it_e_new = elements.begin();
1809 typename DataContainerT::const_iterator it_d_old = data_cloud.begin();
1810 auto it_d_new = data_cloud.begin();
1812 auto it_ind_new = new_indices.begin();
1813 typename IndexContainerT::const_iterator it_ind_new_end = new_indices.end();
1815 while (it_ind_new != it_ind_new_end) {
1817 *it_ind_new = ind_new++;
1820 *it_e_new++ = *it_e_old;
1821 this->
assignIf(it_d_old, it_d_new, HasDataT());
1830 elements.resize(ind_new.get(), Element());
1831 if (HasDataT::value) {
1832 data_cloud.resize(ind_new.get());
1834 else if (it_d_old != data_cloud.begin() || it_d_new != data_cloud.begin()) {
1835 std::cerr <<
"TODO: Bug in MeshBase::remove!\n";
1840 return (new_indices);
1844 template <
class IteratorT>
1852 template <
class IteratorT>
1858 template <
class ConstIteratorT,
class IteratorT>
1862 std::true_type )
const
1868 template <
class ConstIteratorT,
class IteratorT>
1872 std::false_type )
const
1884 assert(this->
isValid(idx_vertex));
1885 this->
getVertex(idx_vertex).idx_outgoing_half_edge_ = idx_outgoing_half_edge;
1893 assert(this->
isValid(idx_half_edge));
1894 this->
getHalfEdge(idx_half_edge).idx_terminating_vertex_ = idx_terminating_vertex;
1902 assert(this->
isValid(idx_half_edge));
1903 this->
getHalfEdge(idx_half_edge).idx_next_half_edge_ = idx_next_half_edge;
1911 assert(this->
isValid(idx_half_edge));
1912 this->
getHalfEdge(idx_half_edge).idx_prev_half_edge_ = idx_prev_half_edge;
1919 assert(this->
isValid(idx_half_edge));
1920 this->
getHalfEdge(idx_half_edge).idx_face_ = idx_face;
1928 assert(this->
isValid(idx_face));
1929 this->
getFace(idx_face).idx_inner_half_edge_ = idx_inner_half_edge;
1947 }
while (++circ != circ_end);
1964 }
while (++circ != circ_end);
1984 if (!this->
isBoundary((circ++).getTargetIndex()))
1989 }
while (++circ != circ_end);
2005 for (std::size_t i = 0; i < this->
sizeVertices(); ++i) {
2017 template <
class DataCloudT>
2019 reserveData(DataCloudT& cloud,
const std::size_t n, std::true_type )
const
2025 template <
class DataCloudT>
2029 std::false_type )
const
2033 template <
class DataCloudT>
2036 const std::size_t n,
2037 const typename DataCloudT::value_type& data,
2038 std::true_type )
const
2040 data_cloud.resize(n, data);
2044 template <
class DataCloudT>
2048 const typename DataCloudT::value_type& ,
2049 std::false_type )
const
2053 template <
class DataCloudT>
2061 template <
class DataCloudT>
2074 assert(this->
isValid(idx_vertex));
2075 return (vertices_[idx_vertex.
get()]);
2082 assert(this->
isValid(idx_vertex));
2083 return (vertices_[idx_vertex.
get()]);
2090 assert(this->
isValid(idx_vertex));
2091 vertices_[idx_vertex.
get()] = vertex;
2102 assert(this->
isValid(idx_he));
2103 return (half_edges_[idx_he.
get()]);
2110 assert(this->
isValid(idx_he));
2111 return (half_edges_[idx_he.
get()]);
2118 assert(this->
isValid(idx_he));
2119 half_edges_[idx_he.
get()] = half_edge;
2130 assert(this->
isValid(idx_face));
2131 return (faces_[idx_face.
get()]);
2138 assert(this->
isValid(idx_face));
2139 return (faces_[idx_face.
get()]);
2146 assert(this->
isValid(idx_face));
2147 faces_[idx_face.
get()] = face;
2185 std::vector<bool> is_new_;
2188 std::vector<bool> make_adjacent_;
2191 std::vector<bool> is_boundary_;
2200 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.