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 (FaceIndices::const_iterator it = delete_faces_vertex_.begin();
236 it != delete_faces_vertex_.end();
273 assert(this->
isValid(idx_edge));
287 assert(this->
isValid(idx_face));
303 this->remove<Vertices, VertexDataCloud, VertexIndices, HasVertexData>(
304 vertices_, vertex_data_cloud_);
306 this->remove<HalfEdges, HalfEdgeDataCloud, HalfEdgeIndices, HasHalfEdgeData>(
307 half_edges_, half_edge_data_cloud_);
309 this->remove<Faces, FaceDataCloud, FaceIndices, HasFaceData>(faces_,
313 if (HasEdgeData::value) {
314 auto it_ed_old = edge_data_cloud_.
begin();
315 auto it_ed_new = edge_data_cloud_.
begin();
317 for (
auto it_ind = new_half_edge_indices.cbegin(),
318 it_ind_end = new_half_edge_indices.cend();
319 it_ind != it_ind_end;
320 it_ind += 2, ++it_ed_old) {
321 if (it_ind->isValid()) {
322 *it_ed_new++ = *it_ed_old;
329 for (
VertexIterator it = vertices_.begin(); it != vertices_.end(); ++it) {
330 if (it->idx_outgoing_half_edge_.isValid()) {
331 it->idx_outgoing_half_edge_ =
332 new_half_edge_indices[it->idx_outgoing_half_edge_.get()];
336 for (
HalfEdgeIterator it = half_edges_.begin(); it != half_edges_.end(); ++it) {
337 it->idx_terminating_vertex_ =
338 new_vertex_indices[it->idx_terminating_vertex_.get()];
339 it->idx_next_half_edge_ = new_half_edge_indices[it->idx_next_half_edge_.get()];
340 it->idx_prev_half_edge_ = new_half_edge_indices[it->idx_prev_half_edge_.get()];
341 if (it->idx_face_.isValid()) {
342 it->idx_face_ = new_face_indices[it->idx_face_.get()];
346 for (
FaceIterator it = faces_.begin(); it != faces_.end(); ++it) {
347 it->idx_inner_half_edge_ = new_half_edge_indices[it->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));
603 for (std::size_t i = 0; i < this->
sizeVertices(); ++i) {
626 for (std::size_t i = 0; i < this->
sizeFaces(); ++i) {
676 assert(this->
isValid(idx_vertex));
693 assert(this->
isValid(idx_edge));
702 assert(this->
isValid(idx_face));
714 assert(this->
isValid(idx_vertex));
727 assert(this->
isValid(idx_vertex));
746 assert(this->
isValid(idx_edge));
758 template <
bool CheckVerticesT>
762 assert(this->
isValid(idx_face));
763 return (this->
isBoundary(idx_face, std::integral_constant<bool, CheckVerticesT>()));
771 assert(this->
isValid(idx_face));
772 return (this->
isBoundary(idx_face, std::true_type()));
783 assert(this->
isValid(idx_vertex));
804 return (vertices_.size());
811 assert(half_edges_.size() % 2 == 0);
812 return (half_edges_.size());
819 assert(half_edges_.size() % 2 == 0);
820 return (half_edges_.size() / 2);
827 return (faces_.size());
845 return (vertices_.empty());
852 return (half_edges_.empty());
859 return (faces_.empty());
870 vertices_.reserve(n);
879 half_edges_.reserve(2 * n);
910 half_edges_.resize(2 * n);
951 return (vertex_data_cloud_);
958 return (vertex_data_cloud_);
969 if (vertex_data_cloud.
size() == vertex_data_cloud_.
size()) {
970 vertex_data_cloud_ = vertex_data_cloud;
986 return (half_edge_data_cloud_);
993 return (half_edge_data_cloud_);
1004 if (half_edge_data_cloud.
size() == half_edge_data_cloud_.
size()) {
1005 half_edge_data_cloud_ = half_edge_data_cloud;
1021 return (edge_data_cloud_);
1028 return (edge_data_cloud_);
1038 if (edge_data_cloud.
size() == edge_data_cloud_.
size()) {
1039 edge_data_cloud_ = edge_data_cloud;
1055 return (face_data_cloud_);
1062 return (face_data_cloud_);
1072 if (face_data_cloud.
size() == face_data_cloud_.
size()) {
1073 face_data_cloud_ = face_data_cloud;
1089 if (HasVertexData::value) {
1090 assert(&vertex_data >= &vertex_data_cloud_.
front() &&
1091 &vertex_data <= &vertex_data_cloud_.
back());
1092 return (
VertexIndex(std::distance(&vertex_data_cloud_.
front(), &vertex_data)));
1101 if (HasHalfEdgeData::value) {
1102 assert(&half_edge_data >= &half_edge_data_cloud_.
front() &&
1103 &half_edge_data <= &half_edge_data_cloud_.
back());
1105 std::distance(&half_edge_data_cloud_.
front(), &half_edge_data)));
1114 if (HasEdgeData::value) {
1115 assert(&edge_data >= &edge_data_cloud_.
front() &&
1116 &edge_data <= &edge_data_cloud_.
back());
1117 return (
EdgeIndex(std::distance(&edge_data_cloud_.
front(), &edge_data)));
1126 if (HasFaceData::value) {
1127 assert(&face_data >= &face_data_cloud_.
front() &&
1128 &face_data <= &face_data_cloud_.
back());
1129 return (
FaceIndex(std::distance(&face_data_cloud_.
front(), &face_data)));
1163 const int n =
static_cast<int>(vertices.size());
1168 inner_he_.resize(n);
1171 make_adjacent_.resize(n);
1172 for (
int i = 0; i < n; ++i) {
1174 vertices[(i + 1) % n],
1181 for (
int i = 0; i < n; ++i) {
1182 int j = (i + 1) % n;
1196 if (!IsManifold::value) {
1197 for (
int i = 0; i < n; ++i) {
1198 if (make_adjacent_[i]) {
1199 this->
makeAdjacent(inner_he_[i], inner_he_[(i + 1) % n], free_he_[i]);
1205 for (
int i = 0; i < n; ++i) {
1208 vertices[i], vertices[(i + 1) % n], half_edge_data, edge_data);
1213 for (
int i = 0; i < n; ++i) {
1214 int j = (i + 1) % n;
1215 if (is_new_[i] && is_new_[j])
1217 else if (is_new_[i] && !is_new_[j])
1218 this->
connectNewOld(inner_he_[i], inner_he_[j], vertices[j]);
1219 else if (!is_new_[i] && is_new_[j])
1220 this->
connectOldNew(inner_he_[i], inner_he_[j], vertices[j]);
1247 half_edges_.push_back(
HalfEdge(idx_v_b));
1248 half_edges_.push_back(
HalfEdge(idx_v_a));
1254 return (
HalfEdgeIndex(
static_cast<int>(half_edges_.size() - 2)));
1273 std::vector<bool>::reference is_new_ab,
1274 std::true_type )
const
1294 std::vector<bool>::reference is_new_ab,
1295 std::false_type )
const
1316 }
while (++circ != circ_end);
1325 const bool is_new_ab,
1326 const bool is_new_bc,
1327 const bool is_isolated_b,
1328 std::vector<bool>::reference ,
1330 std::true_type )
const
1332 return !(is_new_ab && is_new_bc && !is_isolated_b);
1347 const bool is_new_ab,
1348 const bool is_new_bc,
1350 std::vector<bool>::reference make_adjacent_ab_bc,
1352 std::false_type )
const
1354 if (is_new_ab || is_new_bc) {
1355 make_adjacent_ab_bc =
false;
1360 make_adjacent_ab_bc =
false;
1364 make_adjacent_ab_bc =
true;
1417 faces_.push_back(
Face(inner_he.back()));
1422 for (
const auto& idx_half_edge : inner_he) {
1461 this->
connectNewNew(idx_he_ab, idx_he_bc, idx_v_b, std::true_type());
1527 if (idx_he_b_out == idx_he_bc)
1533 while (++circ != circ_end) {
1547 template <
class DataT>
1555 template <
class DataT>
1572 assert(this->
isValid(idx_face));
1573 delete_faces_face_.clear();
1574 delete_faces_face_.push_back(idx_face);
1576 while (!delete_faces_face_.empty()) {
1577 const FaceIndex idx_face_cur = delete_faces_face_.back();
1578 delete_faces_face_.pop_back();
1582 this->
deleteFace(idx_face_cur, std::false_type());
1590 assert(this->
isValid(idx_face));
1596 is_boundary_.clear();
1602 is_boundary_.push_back(
1604 }
while (++circ != circ_end);
1605 assert(inner_he_.size() >= 3);
1607 const int n =
static_cast<int>(inner_he_.size());
1610 if (IsManifold::value) {
1611 for (
int i = 0; i < n; ++i) {
1613 this->
reconnect(inner_he_[i], inner_he_[j], is_boundary_[i], is_boundary_[j]);
1615 for (
int i = 0; i < n; ++i) {
1620 for (
int i = 0; i < n; ++i) {
1622 this->
reconnect(inner_he_[i], inner_he_[j], is_boundary_[i], is_boundary_[j]);
1639 const bool is_boundary_ba,
1640 const bool is_boundary_cb)
1646 if (is_boundary_ba && is_boundary_cb)
1650 if (idx_he_cb_next == idx_he_ba)
1662 else if (is_boundary_ba && !is_boundary_cb)
1670 else if (!is_boundary_ba && is_boundary_cb)
1696 delete_faces_face_.push_back(this->
getFaceIndex((circ++).getTargetIndex()));
1698#ifdef PCL_GEOMETRY_MESH_BASE_TEST_DELETE_FACE_MANIFOLD_2
1706 pcl::geometry::g_pcl_geometry_mesh_base_test_delete_face_manifold_2_success =
1738 assert(this->
isValid(idx_vertex));
1746 assert(this->
isValid(idx_he));
1754 assert(this->
isValid(idx_edge));
1763 assert(this->
isValid(idx_face));
1784 template <
class ElementContainerT,
1785 class DataContainerT,
1786 class IndexContainerT,
1789 remove(ElementContainerT& elements, DataContainerT& data_cloud)
1791 using Index =
typename IndexContainerT::value_type;
1792 using Element =
typename ElementContainerT::value_type;
1794 if (HasDataT::value)
1795 assert(elements.size() == data_cloud.size());
1797 assert(data_cloud.empty());
1799 IndexContainerT new_indices(elements.size(),
1800 typename IndexContainerT::value_type());
1801 Index ind_old(0), ind_new(0);
1803 typename ElementContainerT::const_iterator it_e_old = elements.begin();
1804 typename ElementContainerT::iterator it_e_new = elements.begin();
1806 typename DataContainerT::const_iterator it_d_old = data_cloud.begin();
1807 typename DataContainerT::iterator it_d_new = data_cloud.begin();
1809 typename IndexContainerT::iterator it_ind_new = new_indices.begin();
1810 typename IndexContainerT::const_iterator it_ind_new_end = new_indices.end();
1812 while (it_ind_new != it_ind_new_end) {
1814 *it_ind_new = ind_new++;
1817 *it_e_new++ = *it_e_old;
1818 this->
assignIf(it_d_old, it_d_new, HasDataT());
1827 elements.resize(ind_new.get(), Element());
1828 if (HasDataT::value) {
1829 data_cloud.resize(ind_new.get());
1831 else if (it_d_old != data_cloud.begin() || it_d_new != data_cloud.begin()) {
1832 std::cerr <<
"TODO: Bug in MeshBase::remove!\n";
1837 return (new_indices);
1841 template <
class IteratorT>
1849 template <
class IteratorT>
1855 template <
class ConstIteratorT,
class IteratorT>
1859 std::true_type )
const
1865 template <
class ConstIteratorT,
class IteratorT>
1869 std::false_type )
const
1881 assert(this->
isValid(idx_vertex));
1882 this->
getVertex(idx_vertex).idx_outgoing_half_edge_ = idx_outgoing_half_edge;
1890 assert(this->
isValid(idx_half_edge));
1891 this->
getHalfEdge(idx_half_edge).idx_terminating_vertex_ = idx_terminating_vertex;
1899 assert(this->
isValid(idx_half_edge));
1900 this->
getHalfEdge(idx_half_edge).idx_next_half_edge_ = idx_next_half_edge;
1908 assert(this->
isValid(idx_half_edge));
1909 this->
getHalfEdge(idx_half_edge).idx_prev_half_edge_ = idx_prev_half_edge;
1916 assert(this->
isValid(idx_half_edge));
1917 this->
getHalfEdge(idx_half_edge).idx_face_ = idx_face;
1925 assert(this->
isValid(idx_face));
1926 this->
getFace(idx_face).idx_inner_half_edge_ = idx_inner_half_edge;
1944 }
while (++circ != circ_end);
1961 }
while (++circ != circ_end);
1981 if (!this->
isBoundary((circ++).getTargetIndex()))
1986 }
while (++circ != circ_end);
1997 for (std::size_t i = 0; i < this->
sizeVertices(); ++i) {
2009 template <
class DataCloudT>
2011 reserveData(DataCloudT& cloud,
const std::size_t n, std::true_type )
const
2017 template <
class DataCloudT>
2021 std::false_type )
const
2025 template <
class DataCloudT>
2028 const std::size_t n,
2029 const typename DataCloudT::value_type& data,
2030 std::true_type )
const
2032 data.resize(n, data);
2036 template <
class DataCloudT>
2040 const typename DataCloudT::value_type& ,
2041 std::false_type )
const
2045 template <
class DataCloudT>
2053 template <
class DataCloudT>
2066 assert(this->
isValid(idx_vertex));
2067 return (vertices_[idx_vertex.
get()]);
2074 assert(this->
isValid(idx_vertex));
2075 return (vertices_[idx_vertex.
get()]);
2082 assert(this->
isValid(idx_vertex));
2083 vertices_[idx_vertex.
get()] = vertex;
2094 assert(this->
isValid(idx_he));
2095 return (half_edges_[idx_he.
get()]);
2102 assert(this->
isValid(idx_he));
2103 return (half_edges_[idx_he.
get()]);
2110 assert(this->
isValid(idx_he));
2111 half_edges_[idx_he.
get()] = half_edge;
2122 assert(this->
isValid(idx_face));
2123 return (faces_[idx_face.
get()]);
2130 assert(this->
isValid(idx_face));
2131 return (faces_[idx_face.
get()]);
2138 assert(this->
isValid(idx_face));
2139 faces_[idx_face.
get()] = face;
2177 std::vector<bool> is_new_;
2180 std::vector<bool> make_adjacent_;
2183 std::vector<bool> is_boundary_;
2192 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.
A face is a closed loop of edges.
An edge is a connection between two vertices.
Circulates counter-clockwise around a vertex and returns an index to the incoming half-edge (the targ...
HalfEdgeIndex getTargetIndex() const
Get the index to the incoming half-edge.
Circulates clockwise around a face and returns an index to the inner half-edge (the target).
HalfEdgeIndex getTargetIndex() const
Get the index to the inner half-edge.
Base class for the half-edge mesh.
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.
std::integral_constant< bool, !std::is_same< FaceData, pcl::geometry::NoData >::value > HasFaceData
bool emptyVertices() const
Check if the vertices are empty.
FaceDataCloud getFaceDataCloud() const
Get the stored face data.
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
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
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.
std::integral_constant< bool, !std::is_same< EdgeData, pcl::geometry::NoData >::value > HasEdgeData
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.
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 bounddary.
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.
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.
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
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
void resizeData(DataCloudT &, const std::size_t n, const typename DataCloudT::value_type &data, std::true_type) const
Resize the mesh data.
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.
pcl::geometry::FaceAroundVertexCirculator< const Self > FaceAroundVertexCirculator
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.
pcl::geometry::InnerHalfEdgeAroundFaceCirculator< const Self > InnerHalfEdgeAroundFaceCirculator
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.
std::integral_constant< bool, !std::is_same< VertexData, pcl::geometry::NoData >::value > HasVertexData
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::IncomingHalfEdgeAroundVertexCirculator< const Self > IncomingHalfEdgeAroundVertexCirculator
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
pcl::geometry::OutgoingHalfEdgeAroundVertexCirculator< const Self > OutgoingHalfEdgeAroundVertexCirculator
Vertex & getVertex(const VertexIndex &idx_vertex)
Get the vertex for the given index.
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::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.
pcl::geometry::VertexAroundVertexCirculator< const Self > VertexAroundVertexCirculator
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.
pcl::geometry::VertexAroundFaceCirculator< const Self > VertexAroundFaceCirculator
pcl::geometry::OuterHalfEdgeAroundFaceCirculator< const Self > OuterHalfEdgeAroundFaceCirculator
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.
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.
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.
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
std::integral_constant< bool, !std::is_same< HalfEdgeData, pcl::geometry::NoData >::value > HasHalfEdgeData
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.
pcl::detail::MeshIndex< struct HalfEdgeIndexTag > HalfEdgeIndex
Index used to access elements in the half-edge mesh.
pcl::detail::MeshIndex< struct EdgeIndexTag > EdgeIndex
Index used to access elements in the half-edge mesh.
pcl::detail::MeshIndex< struct FaceIndexTag > FaceIndex
Index used to access elements in the half-edge mesh.
pcl::detail::MeshIndex< struct VertexIndexTag > VertexIndex
Index used to access elements in the half-edge mesh.
Defines functions, macros and traits for allocating and using memory.
HalfEdgeIndex toHalfEdgeIndex(const EdgeIndex &index, const bool get_first=true)
Convert the given edge index to a half-edge index.
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.