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 (FaceIndices::const_iterator it = delete_faces_vertex_.begin();
235 it != delete_faces_vertex_.end();
272 assert(this->
isValid(idx_edge));
286 assert(this->
isValid(idx_face));
302 this->remove<Vertices, VertexDataCloud, VertexIndices, HasVertexData>(
303 vertices_, vertex_data_cloud_);
305 this->remove<HalfEdges, HalfEdgeDataCloud, HalfEdgeIndices, HasHalfEdgeData>(
306 half_edges_, half_edge_data_cloud_);
308 this->remove<Faces, FaceDataCloud, FaceIndices, HasFaceData>(faces_,
312 if (HasEdgeData::value) {
313 auto it_ed_old = edge_data_cloud_.
begin();
314 auto it_ed_new = edge_data_cloud_.
begin();
316 for (
auto it_ind = new_half_edge_indices.cbegin(),
317 it_ind_end = new_half_edge_indices.cend();
318 it_ind != it_ind_end;
319 it_ind += 2, ++it_ed_old) {
320 if (it_ind->isValid()) {
321 *it_ed_new++ = *it_ed_old;
328 for (
VertexIterator it = vertices_.begin(); it != vertices_.end(); ++it) {
329 if (it->idx_outgoing_half_edge_.isValid()) {
330 it->idx_outgoing_half_edge_ =
331 new_half_edge_indices[it->idx_outgoing_half_edge_.get()];
335 for (
HalfEdgeIterator it = half_edges_.begin(); it != half_edges_.end(); ++it) {
336 it->idx_terminating_vertex_ =
337 new_vertex_indices[it->idx_terminating_vertex_.get()];
338 it->idx_next_half_edge_ = new_half_edge_indices[it->idx_next_half_edge_.get()];
339 it->idx_prev_half_edge_ = new_half_edge_indices[it->idx_prev_half_edge_.get()];
340 if (it->idx_face_.isValid()) {
341 it->idx_face_ = new_face_indices[it->idx_face_.get()];
345 for (
FaceIterator it = faces_.begin(); it != faces_.end(); ++it) {
346 it->idx_inner_half_edge_ = new_half_edge_indices[it->idx_inner_half_edge_.get()];
358 assert(this->
isValid(idx_vertex));
359 return (this->
getVertex(idx_vertex).idx_outgoing_half_edge_);
366 assert(this->
isValid(idx_vertex));
378 assert(this->
isValid(idx_half_edge));
379 return (this->
getHalfEdge(idx_half_edge).idx_terminating_vertex_);
386 assert(this->
isValid(idx_half_edge));
395 assert(this->
isValid(idx_half_edge));
398 : idx_half_edge.
get() + 1));
405 assert(this->
isValid(idx_half_edge));
406 return (this->
getHalfEdge(idx_half_edge).idx_next_half_edge_);
413 assert(this->
isValid(idx_half_edge));
414 return (this->
getHalfEdge(idx_half_edge).idx_prev_half_edge_);
421 assert(this->
isValid(idx_half_edge));
422 return (this->
getHalfEdge(idx_half_edge).idx_face_);
429 assert(this->
isValid(idx_half_edge));
441 assert(this->
isValid(idx_face));
442 return (this->
getFace(idx_face).idx_inner_half_edge_);
449 assert(this->
isValid(idx_face));
461 assert(this->
isValid(idx_vertex));
469 assert(this->
isValid(idx_outgoing_half_edge));
477 assert(this->
isValid(idx_vertex));
486 assert(this->
isValid(idx_outgoing_half_edge));
494 assert(this->
isValid(idx_vertex));
503 assert(this->
isValid(idx_incoming_half_edge));
511 assert(this->
isValid(idx_vertex));
519 assert(this->
isValid(idx_outgoing_half_edge));
527 assert(this->
isValid(idx_face));
535 assert(this->
isValid(idx_inner_half_edge));
543 assert(this->
isValid(idx_face));
551 assert(this->
isValid(idx_inner_half_edge));
559 assert(this->
isValid(idx_face));
567 assert(this->
isValid(idx_inner_half_edge));
575 assert(this->
isValid(idx_face));
583 assert(this->
isValid(idx_inner_half_edge));
602 for (std::size_t i = 0; i < this->
sizeVertices(); ++i) {
625 for (std::size_t i = 0; i < this->
sizeFaces(); ++i) {
675 assert(this->
isValid(idx_vertex));
692 assert(this->
isValid(idx_edge));
701 assert(this->
isValid(idx_face));
713 assert(this->
isValid(idx_vertex));
726 assert(this->
isValid(idx_vertex));
745 assert(this->
isValid(idx_edge));
757 template <
bool CheckVerticesT>
761 assert(this->
isValid(idx_face));
762 return (this->
isBoundary(idx_face, std::integral_constant<bool, CheckVerticesT>()));
770 assert(this->
isValid(idx_face));
771 return (this->
isBoundary(idx_face, std::true_type()));
782 assert(this->
isValid(idx_vertex));
803 return (vertices_.size());
810 assert(half_edges_.size() % 2 == 0);
811 return (half_edges_.size());
818 assert(half_edges_.size() % 2 == 0);
819 return (half_edges_.size() / 2);
826 return (faces_.size());
844 return (vertices_.empty());
851 return (half_edges_.empty());
858 return (faces_.empty());
869 vertices_.reserve(n);
878 half_edges_.reserve(2 * n);
909 half_edges_.resize(2 * n);
950 return (vertex_data_cloud_);
957 return (vertex_data_cloud_);
968 if (vertex_data_cloud.
size() == vertex_data_cloud_.
size()) {
969 vertex_data_cloud_ = vertex_data_cloud;
985 return (half_edge_data_cloud_);
992 return (half_edge_data_cloud_);
1003 if (half_edge_data_cloud.
size() == half_edge_data_cloud_.
size()) {
1004 half_edge_data_cloud_ = half_edge_data_cloud;
1020 return (edge_data_cloud_);
1027 return (edge_data_cloud_);
1037 if (edge_data_cloud.
size() == edge_data_cloud_.
size()) {
1038 edge_data_cloud_ = edge_data_cloud;
1054 return (face_data_cloud_);
1061 return (face_data_cloud_);
1071 if (face_data_cloud.
size() == face_data_cloud_.
size()) {
1072 face_data_cloud_ = face_data_cloud;
1088 if (HasVertexData::value) {
1089 assert(&vertex_data >= &vertex_data_cloud_.
front() &&
1090 &vertex_data <= &vertex_data_cloud_.
back());
1100 if (HasHalfEdgeData::value) {
1101 assert(&half_edge_data >= &half_edge_data_cloud_.
front() &&
1102 &half_edge_data <= &half_edge_data_cloud_.
back());
1113 if (HasEdgeData::value) {
1114 assert(&edge_data >= &edge_data_cloud_.
front() &&
1115 &edge_data <= &edge_data_cloud_.
back());
1125 if (HasFaceData::value) {
1126 assert(&face_data >= &face_data_cloud_.
front() &&
1127 &face_data <= &face_data_cloud_.
back());
1162 const int n =
static_cast<int>(vertices.size());
1167 inner_he_.resize(n);
1170 make_adjacent_.resize(n);
1171 for (
int i = 0; i < n; ++i) {
1173 vertices[(i + 1) % n],
1180 for (
int i = 0; i < n; ++i) {
1181 int j = (i + 1) % n;
1195 if (!IsManifold::value) {
1196 for (
int i = 0; i < n; ++i) {
1197 if (make_adjacent_[i]) {
1198 this->
makeAdjacent(inner_he_[i], inner_he_[(i + 1) % n], free_he_[i]);
1204 for (
int i = 0; i < n; ++i) {
1207 vertices[i], vertices[(i + 1) % n], half_edge_data, edge_data);
1212 for (
int i = 0; i < n; ++i) {
1213 int j = (i + 1) % n;
1214 if (is_new_[i] && is_new_[j])
1216 else if (is_new_[i] && !is_new_[j])
1217 this->
connectNewOld(inner_he_[i], inner_he_[j], vertices[j]);
1218 else if (!is_new_[i] && is_new_[j])
1219 this->
connectOldNew(inner_he_[i], inner_he_[j], vertices[j]);
1246 half_edges_.push_back(
HalfEdge(idx_v_b));
1247 half_edges_.push_back(
HalfEdge(idx_v_a));
1253 return (
HalfEdgeIndex(
static_cast<int>(half_edges_.size() - 2)));
1272 std::vector<bool>::reference is_new_ab,
1273 std::true_type )
const
1293 std::vector<bool>::reference is_new_ab,
1294 std::false_type )
const
1315 }
while (++circ != circ_end);
1324 const bool is_new_ab,
1325 const bool is_new_bc,
1326 const bool is_isolated_b,
1327 std::vector<bool>::reference ,
1329 std::true_type )
const
1331 return !(is_new_ab && is_new_bc && !is_isolated_b);
1346 const bool is_new_ab,
1347 const bool is_new_bc,
1349 std::vector<bool>::reference make_adjacent_ab_bc,
1351 std::false_type )
const
1353 if (is_new_ab || is_new_bc) {
1354 make_adjacent_ab_bc =
false;
1359 make_adjacent_ab_bc =
false;
1363 make_adjacent_ab_bc =
true;
1416 faces_.push_back(
Face(inner_he.back()));
1421 for (
const auto& idx_half_edge : inner_he) {
1460 this->
connectNewNew(idx_he_ab, idx_he_bc, idx_v_b, std::true_type());
1526 if (idx_he_b_out == idx_he_bc)
1532 while (++circ != circ_end) {
1546 template <
class DataT>
1554 template <
class DataT>
1571 assert(this->
isValid(idx_face));
1572 delete_faces_face_.clear();
1573 delete_faces_face_.push_back(idx_face);
1575 while (!delete_faces_face_.empty()) {
1576 const FaceIndex idx_face_cur = delete_faces_face_.back();
1577 delete_faces_face_.pop_back();
1581 this->
deleteFace(idx_face_cur, std::false_type());
1589 assert(this->
isValid(idx_face));
1595 is_boundary_.clear();
1601 is_boundary_.push_back(
1603 }
while (++circ != circ_end);
1604 assert(inner_he_.size() >= 3);
1606 const int n =
static_cast<int>(inner_he_.size());
1609 if (IsManifold::value) {
1610 for (
int i = 0; i < n; ++i) {
1612 this->
reconnect(inner_he_[i], inner_he_[j], is_boundary_[i], is_boundary_[j]);
1614 for (
int i = 0; i < n; ++i) {
1619 for (
int i = 0; i < n; ++i) {
1621 this->
reconnect(inner_he_[i], inner_he_[j], is_boundary_[i], is_boundary_[j]);
1638 const bool is_boundary_ba,
1639 const bool is_boundary_cb)
1645 if (is_boundary_ba && is_boundary_cb)
1649 if (idx_he_cb_next == idx_he_ba)
1661 else if (is_boundary_ba && !is_boundary_cb)
1669 else if (!is_boundary_ba && is_boundary_cb)
1695 delete_faces_face_.push_back(this->
getFaceIndex((circ++).getTargetIndex()));
1697#ifdef PCL_GEOMETRY_MESH_BASE_TEST_DELETE_FACE_MANIFOLD_2
1705 pcl::geometry::g_pcl_geometry_mesh_base_test_delete_face_manifold_2_success =
1737 assert(this->
isValid(idx_vertex));
1745 assert(this->
isValid(idx_he));
1753 assert(this->
isValid(idx_edge));
1762 assert(this->
isValid(idx_face));
1783 template <
class ElementContainerT,
1784 class DataContainerT,
1785 class IndexContainerT,
1788 remove(ElementContainerT& elements, DataContainerT& data_cloud)
1790 using Index =
typename IndexContainerT::value_type;
1791 using Element =
typename ElementContainerT::value_type;
1793 if (HasDataT::value)
1794 assert(elements.size() == data_cloud.size());
1796 assert(data_cloud.empty());
1798 IndexContainerT new_indices(elements.size(),
1799 typename IndexContainerT::value_type());
1800 Index ind_old(0), ind_new(0);
1802 typename ElementContainerT::const_iterator it_e_old = elements.begin();
1803 typename ElementContainerT::iterator it_e_new = elements.begin();
1805 typename DataContainerT::const_iterator it_d_old = data_cloud.begin();
1806 typename DataContainerT::iterator it_d_new = data_cloud.begin();
1808 typename IndexContainerT::iterator it_ind_new = new_indices.begin();
1809 typename IndexContainerT::const_iterator it_ind_new_end = new_indices.end();
1811 while (it_ind_new != it_ind_new_end) {
1813 *it_ind_new = ind_new++;
1816 *it_e_new++ = *it_e_old;
1817 this->
assignIf(it_d_old, it_d_new, HasDataT());
1826 elements.resize(ind_new.get(), Element());
1827 if (HasDataT::value) {
1828 data_cloud.resize(ind_new.get());
1830 else if (it_d_old != data_cloud.begin() || it_d_new != data_cloud.begin()) {
1831 std::cerr <<
"TODO: Bug in MeshBase::remove!\n";
1836 return (new_indices);
1840 template <
class IteratorT>
1848 template <
class IteratorT>
1854 template <
class ConstIteratorT,
class IteratorT>
1858 std::true_type )
const
1864 template <
class ConstIteratorT,
class IteratorT>
1868 std::false_type )
const
1880 assert(this->
isValid(idx_vertex));
1881 this->
getVertex(idx_vertex).idx_outgoing_half_edge_ = idx_outgoing_half_edge;
1889 assert(this->
isValid(idx_half_edge));
1890 this->
getHalfEdge(idx_half_edge).idx_terminating_vertex_ = idx_terminating_vertex;
1898 assert(this->
isValid(idx_half_edge));
1899 this->
getHalfEdge(idx_half_edge).idx_next_half_edge_ = idx_next_half_edge;
1907 assert(this->
isValid(idx_half_edge));
1908 this->
getHalfEdge(idx_half_edge).idx_prev_half_edge_ = idx_prev_half_edge;
1915 assert(this->
isValid(idx_half_edge));
1916 this->
getHalfEdge(idx_half_edge).idx_face_ = idx_face;
1924 assert(this->
isValid(idx_face));
1925 this->
getFace(idx_face).idx_inner_half_edge_ = idx_inner_half_edge;
1943 }
while (++circ != circ_end);
1960 }
while (++circ != circ_end);
1980 if (!this->
isBoundary((circ++).getTargetIndex()))
1985 }
while (++circ != circ_end);
1996 for (std::size_t i = 0; i < this->
sizeVertices(); ++i) {
2008 template <
class DataCloudT>
2010 reserveData(DataCloudT& cloud,
const std::size_t n, std::true_type )
const
2016 template <
class DataCloudT>
2020 std::false_type )
const
2024 template <
class DataCloudT>
2027 const std::size_t n,
2028 const typename DataCloudT::value_type& data,
2029 std::true_type )
const
2031 data.resize(n, data);
2035 template <
class DataCloudT>
2039 const typename DataCloudT::value_type& ,
2040 std::false_type )
const
2044 template <
class DataCloudT>
2052 template <
class DataCloudT>
2065 assert(this->
isValid(idx_vertex));
2066 return (vertices_[idx_vertex.
get()]);
2073 assert(this->
isValid(idx_vertex));
2074 return (vertices_[idx_vertex.
get()]);
2081 assert(this->
isValid(idx_vertex));
2082 vertices_[idx_vertex.
get()] = vertex;
2093 assert(this->
isValid(idx_he));
2094 return (half_edges_[idx_he.
get()]);
2101 assert(this->
isValid(idx_he));
2102 return (half_edges_[idx_he.
get()]);
2109 assert(this->
isValid(idx_he));
2110 half_edges_[idx_he.
get()] = half_edge;
2121 assert(this->
isValid(idx_face));
2122 return (faces_[idx_face.
get()]);
2129 assert(this->
isValid(idx_face));
2130 return (faces_[idx_face.
get()]);
2137 assert(this->
isValid(idx_face));
2138 faces_[idx_face.
get()] = face;
2176 std::vector<bool> is_new_;
2179 std::vector<bool> make_adjacent_;
2182 std::vector<bool> is_boundary_;
2191 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.
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.
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.
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
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.
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.
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.
pcl::detail::MeshIndex< struct FaceIndexTag > FaceIndex
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 HalfEdgeIndexTag > HalfEdgeIndex
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.
float distance(const PointT &p1, const PointT &p2)
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.