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>
47 #include <pcl/exceptions.h>
50 #include <pcl/point_cloud.h>
53 #include <type_traits>
60 #ifdef PCL_GEOMETRY_MESH_BASE_TEST_DELETE_FACE_MANIFOLD_2
63 bool g_pcl_geometry_mesh_base_test_delete_face_manifold_2_success;
74 template <
class MeshT>
96 template <
class DerivedT,
class MeshTraitsT,
class MeshTagT>
100 using Ptr = shared_ptr<Self>;
113 static_assert(std::is_convertible<IsManifold, bool>::value,
114 "MeshTraitsT::IsManifold is not convertible to bool");
120 std::integral_constant<bool,
121 !std::is_same<VertexData, pcl::geometry::NoData>::value>;
123 std::integral_constant<bool,
124 !std::is_same<HalfEdgeData, pcl::geometry::NoData>::value>;
126 std::integral_constant<bool,
127 !std::is_same<EdgeData, pcl::geometry::NoData>::value>;
129 std::integral_constant<bool,
130 !std::is_same<FaceData, pcl::geometry::NoData>::value>;
167 : vertex_data_cloud_()
168 , half_edge_data_cloud_()
186 vertices_.push_back(
Vertex());
211 return (
static_cast<Derived*
>(
this)->addFaceImpl(
212 vertices, face_data, edge_data, half_edge_data));
222 assert(this->
isValid(idx_vertex));
226 delete_faces_vertex_.clear();
234 }
while (++circ != circ_end);
236 for (
const auto& delete_me : delete_faces_vertex_) {
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 (
auto& vertex : vertices_) {
329 if (vertex.idx_outgoing_half_edge_.isValid()) {
330 vertex.idx_outgoing_half_edge_ =
331 new_half_edge_indices[vertex.idx_outgoing_half_edge_.get()];
335 for (
auto& half_edge : half_edges_) {
336 half_edge.idx_terminating_vertex_ =
337 new_vertex_indices[half_edge.idx_terminating_vertex_.get()];
338 half_edge.idx_next_half_edge_ =
339 new_half_edge_indices[half_edge.idx_next_half_edge_.get()];
340 half_edge.idx_prev_half_edge_ =
341 new_half_edge_indices[half_edge.idx_prev_half_edge_.get()];
342 if (half_edge.idx_face_.isValid()) {
343 half_edge.idx_face_ = new_face_indices[half_edge.idx_face_.get()];
347 for (
auto& face : faces_) {
348 face.idx_inner_half_edge_ =
349 new_half_edge_indices[face.idx_inner_half_edge_.get()];
361 assert(this->
isValid(idx_vertex));
362 return (this->
getVertex(idx_vertex).idx_outgoing_half_edge_);
369 assert(this->
isValid(idx_vertex));
381 assert(this->
isValid(idx_half_edge));
382 return (this->
getHalfEdge(idx_half_edge).idx_terminating_vertex_);
389 assert(this->
isValid(idx_half_edge));
398 assert(this->
isValid(idx_half_edge));
401 : idx_half_edge.
get() + 1));
408 assert(this->
isValid(idx_half_edge));
409 return (this->
getHalfEdge(idx_half_edge).idx_next_half_edge_);
416 assert(this->
isValid(idx_half_edge));
417 return (this->
getHalfEdge(idx_half_edge).idx_prev_half_edge_);
424 assert(this->
isValid(idx_half_edge));
425 return (this->
getHalfEdge(idx_half_edge).idx_face_);
432 assert(this->
isValid(idx_half_edge));
444 assert(this->
isValid(idx_face));
445 return (this->
getFace(idx_face).idx_inner_half_edge_);
452 assert(this->
isValid(idx_face));
464 assert(this->
isValid(idx_vertex));
472 assert(this->
isValid(idx_outgoing_half_edge));
480 assert(this->
isValid(idx_vertex));
489 assert(this->
isValid(idx_outgoing_half_edge));
497 assert(this->
isValid(idx_vertex));
506 assert(this->
isValid(idx_incoming_half_edge));
514 assert(this->
isValid(idx_vertex));
522 assert(this->
isValid(idx_outgoing_half_edge));
530 assert(this->
isValid(idx_face));
538 assert(this->
isValid(idx_inner_half_edge));
546 assert(this->
isValid(idx_face));
554 assert(this->
isValid(idx_inner_half_edge));
562 assert(this->
isValid(idx_face));
570 assert(this->
isValid(idx_inner_half_edge));
578 assert(this->
isValid(idx_face));
586 assert(this->
isValid(idx_inner_half_edge));
605 for (std::size_t i = 0; i < this->
sizeVertices(); ++i) {
628 for (std::size_t i = 0; i < this->
sizeFaces(); ++i) {
645 return (idx_vertex >=
static_cast<VertexIndex>(0) &&
646 idx_vertex <
static_cast<VertexIndex>(vertices_.size()));
661 return (idx_edge >=
static_cast<EdgeIndex>(0) &&
662 idx_edge <
static_cast<EdgeIndex>(half_edges_.size() / 2));
669 return (idx_face >=
static_cast<FaceIndex>(0) &&
670 idx_face <
static_cast<FaceIndex>(faces_.size()));
681 assert(this->
isValid(idx_vertex));
698 assert(this->
isValid(idx_edge));
707 assert(this->
isValid(idx_face));
719 assert(this->
isValid(idx_vertex));
732 assert(this->
isValid(idx_vertex));
751 assert(this->
isValid(idx_edge));
763 template <
bool CheckVerticesT>
767 assert(this->
isValid(idx_face));
768 return (this->
isBoundary(idx_face, std::integral_constant<bool, CheckVerticesT>()));
776 assert(this->
isValid(idx_face));
777 return (this->
isBoundary(idx_face, std::true_type()));
788 assert(this->
isValid(idx_vertex));
809 return (vertices_.size());
816 assert(half_edges_.size() % 2 == 0);
817 return (half_edges_.size());
824 assert(half_edges_.size() % 2 == 0);
825 return (half_edges_.size() / 2);
832 return (faces_.size());
850 return (vertices_.empty());
857 return (half_edges_.empty());
864 return (faces_.empty());
875 vertices_.reserve(n);
884 half_edges_.reserve(2 * n);
905 vertices_.resize(n,
Vertex());
915 half_edges_.resize(2 * n,
HalfEdge());
924 faces_.resize(n,
Face());
956 return (vertex_data_cloud_);
963 return (vertex_data_cloud_);
974 if (vertex_data_cloud.
size() == vertex_data_cloud_.
size()) {
975 vertex_data_cloud_ = vertex_data_cloud;
991 return (half_edge_data_cloud_);
998 return (half_edge_data_cloud_);
1009 if (half_edge_data_cloud.
size() == half_edge_data_cloud_.
size()) {
1010 half_edge_data_cloud_ = half_edge_data_cloud;
1026 return (edge_data_cloud_);
1033 return (edge_data_cloud_);
1043 if (edge_data_cloud.
size() == edge_data_cloud_.
size()) {
1044 edge_data_cloud_ = edge_data_cloud;
1060 return (face_data_cloud_);
1067 return (face_data_cloud_);
1077 if (face_data_cloud.
size() == face_data_cloud_.
size()) {
1078 face_data_cloud_ = face_data_cloud;
1094 if (HasVertexData::value) {
1095 assert(&vertex_data >= &vertex_data_cloud_.
front() &&
1096 &vertex_data <= &vertex_data_cloud_.
back());
1106 if (HasHalfEdgeData::value) {
1107 assert(&half_edge_data >= &half_edge_data_cloud_.
front() &&
1108 &half_edge_data <= &half_edge_data_cloud_.
back());
1119 if (HasEdgeData::value) {
1120 assert(&edge_data >= &edge_data_cloud_.
front() &&
1121 &edge_data <= &edge_data_cloud_.
back());
1131 if (HasFaceData::value) {
1132 assert(&face_data >= &face_data_cloud_.
front() &&
1133 &face_data <= &face_data_cloud_.
back());
1168 const int n =
static_cast<int>(vertices.size());
1173 inner_he_.resize(n);
1176 make_adjacent_.resize(n);
1177 for (
int i = 0; i < n; ++i) {
1179 vertices[(i + 1) % n],
1186 for (
int i = 0; i < n; ++i) {
1187 int j = (i + 1) % n;
1201 if (!IsManifold::value) {
1202 for (
int i = 0; i < n; ++i) {
1203 if (make_adjacent_[i]) {
1204 this->
makeAdjacent(inner_he_[i], inner_he_[(i + 1) % n], free_he_[i]);
1210 for (
int i = 0; i < n; ++i) {
1213 vertices[i], vertices[(i + 1) % n], half_edge_data, edge_data);
1218 for (
int i = 0; i < n; ++i) {
1219 int j = (i + 1) % n;
1220 if (is_new_[i] && is_new_[j])
1222 else if (is_new_[i] && !is_new_[j])
1223 this->
connectNewOld(inner_he_[i], inner_he_[j], vertices[j]);
1224 else if (!is_new_[i] && is_new_[j])
1225 this->
connectOldNew(inner_he_[i], inner_he_[j], vertices[j]);
1252 half_edges_.push_back(
HalfEdge(idx_v_b));
1253 half_edges_.push_back(
HalfEdge(idx_v_a));
1259 return (
static_cast<HalfEdgeIndex>(half_edges_.size() - 2));
1278 std::vector<bool>::reference is_new_ab,
1279 std::true_type )
const
1299 std::vector<bool>::reference is_new_ab,
1300 std::false_type )
const
1321 }
while (++circ != circ_end);
1330 const bool is_new_ab,
1331 const bool is_new_bc,
1332 const bool is_isolated_b,
1333 std::vector<bool>::reference ,
1335 std::true_type )
const
1337 return (!is_new_ab || !is_new_bc || is_isolated_b);
1352 const bool is_new_ab,
1353 const bool is_new_bc,
1355 std::vector<bool>::reference make_adjacent_ab_bc,
1357 std::false_type )
const
1359 if (is_new_ab || is_new_bc) {
1360 make_adjacent_ab_bc =
false;
1365 make_adjacent_ab_bc =
false;
1369 make_adjacent_ab_bc =
true;
1422 faces_.push_back(
Face(inner_he.back()));
1427 for (
const auto& idx_half_edge : inner_he) {
1466 this->
connectNewNew(idx_he_ab, idx_he_bc, idx_v_b, std::true_type());
1532 if (idx_he_b_out == idx_he_bc)
1538 while (++circ != circ_end) {
1552 template <
class DataT>
1560 template <
class DataT>
1577 assert(this->
isValid(idx_face));
1578 delete_faces_face_.clear();
1579 delete_faces_face_.push_back(idx_face);
1581 while (!delete_faces_face_.empty()) {
1582 const FaceIndex idx_face_cur = delete_faces_face_.back();
1583 delete_faces_face_.pop_back();
1587 this->
deleteFace(idx_face_cur, std::false_type());
1595 assert(this->
isValid(idx_face));
1601 is_boundary_.clear();
1607 is_boundary_.push_back(
1609 }
while (++circ != circ_end);
1610 assert(inner_he_.size() >= 3);
1612 const int n =
static_cast<int>(inner_he_.size());
1615 if (IsManifold::value) {
1616 for (
int i = 0; i < n; ++i) {
1618 this->
reconnect(inner_he_[i], inner_he_[j], is_boundary_[i], is_boundary_[j]);
1620 for (
int i = 0; i < n; ++i) {
1625 for (
int i = 0; i < n; ++i) {
1627 this->
reconnect(inner_he_[i], inner_he_[j], is_boundary_[i], is_boundary_[j]);
1644 const bool is_boundary_ba,
1645 const bool is_boundary_cb)
1651 if (is_boundary_ba && is_boundary_cb)
1655 if (idx_he_cb_next == idx_he_ba)
1667 else if (is_boundary_ba && !is_boundary_cb)
1675 else if (!is_boundary_ba && is_boundary_cb)
1701 delete_faces_face_.push_back(this->
getFaceIndex((circ++).getTargetIndex()));
1703 #ifdef PCL_GEOMETRY_MESH_BASE_TEST_DELETE_FACE_MANIFOLD_2
1711 pcl::geometry::g_pcl_geometry_mesh_base_test_delete_face_manifold_2_success =
1743 assert(this->
isValid(idx_vertex));
1751 assert(this->
isValid(idx_he));
1759 assert(this->
isValid(idx_edge));
1768 assert(this->
isValid(idx_face));
1789 template <
class ElementContainerT,
1790 class DataContainerT,
1791 class IndexContainerT,
1794 remove(ElementContainerT& elements, DataContainerT& data_cloud)
1796 using Index =
typename IndexContainerT::value_type;
1797 using Element =
typename ElementContainerT::value_type;
1799 if (HasDataT::value)
1800 assert(elements.size() == data_cloud.size());
1802 assert(data_cloud.empty());
1804 IndexContainerT new_indices(elements.size(),
1805 typename IndexContainerT::value_type());
1806 Index ind_old(0), ind_new(0);
1808 auto it_e_old = elements.cbegin();
1809 auto it_e_new = elements.begin();
1811 auto it_d_old = data_cloud.cbegin();
1812 auto it_d_new = data_cloud.begin();
1814 auto it_ind_new = new_indices.begin();
1815 auto it_ind_new_end = new_indices.cend();
1817 while (it_ind_new != it_ind_new_end) {
1819 *it_ind_new = ind_new++;
1822 *it_e_new++ = *it_e_old;
1823 this->
assignIf(it_d_old, it_d_new, HasDataT());
1832 elements.resize(ind_new.get(), Element());
1833 if (HasDataT::value) {
1834 data_cloud.resize(ind_new.get());
1836 else if (it_d_old != data_cloud.begin() || it_d_new != data_cloud.begin()) {
1838 PCL_THROW_EXCEPTION(
PCLException,
"TODO: Bug in MeshBase::remove!")
1841 return (new_indices);
1845 template <
class IteratorT>
1853 template <
class IteratorT>
1859 template <
class ConstIteratorT,
class IteratorT>
1863 std::true_type )
const
1869 template <
class ConstIteratorT,
class IteratorT>
1873 std::false_type )
const
1885 assert(this->
isValid(idx_vertex));
1886 this->
getVertex(idx_vertex).idx_outgoing_half_edge_ = idx_outgoing_half_edge;
1894 assert(this->
isValid(idx_half_edge));
1895 this->
getHalfEdge(idx_half_edge).idx_terminating_vertex_ = idx_terminating_vertex;
1903 assert(this->
isValid(idx_half_edge));
1904 this->
getHalfEdge(idx_half_edge).idx_next_half_edge_ = idx_next_half_edge;
1912 assert(this->
isValid(idx_half_edge));
1913 this->
getHalfEdge(idx_half_edge).idx_prev_half_edge_ = idx_prev_half_edge;
1920 assert(this->
isValid(idx_half_edge));
1921 this->
getHalfEdge(idx_half_edge).idx_face_ = idx_face;
1929 assert(this->
isValid(idx_face));
1930 this->
getFace(idx_face).idx_inner_half_edge_ = idx_inner_half_edge;
1948 }
while (++circ != circ_end);
1965 }
while (++circ != circ_end);
1985 if (!this->
isBoundary((circ++).getTargetIndex()))
1990 }
while (++circ != circ_end);
2006 for (std::size_t i = 0; i < this->
sizeVertices(); ++i) {
2018 template <
class DataCloudT>
2020 reserveData(DataCloudT& cloud,
const std::size_t n, std::true_type )
const
2026 template <
class DataCloudT>
2030 std::false_type )
const
2034 template <
class DataCloudT>
2037 const std::size_t n,
2038 const typename DataCloudT::value_type& data,
2039 std::true_type )
const
2041 data_cloud.resize(n, data);
2045 template <
class DataCloudT>
2049 const typename DataCloudT::value_type& ,
2050 std::false_type )
const
2054 template <
class DataCloudT>
2062 template <
class DataCloudT>
2075 assert(this->
isValid(idx_vertex));
2076 return (vertices_[idx_vertex.
get()]);
2083 assert(this->
isValid(idx_vertex));
2084 return (vertices_[idx_vertex.
get()]);
2091 assert(this->
isValid(idx_vertex));
2092 vertices_[idx_vertex.
get()] = vertex;
2103 assert(this->
isValid(idx_he));
2104 return (half_edges_[idx_he.
get()]);
2111 assert(this->
isValid(idx_he));
2112 return (half_edges_[idx_he.
get()]);
2119 assert(this->
isValid(idx_he));
2120 half_edges_[idx_he.
get()] = half_edge;
2131 assert(this->
isValid(idx_face));
2132 return (faces_[idx_face.
get()]);
2139 assert(this->
isValid(idx_face));
2140 return (faces_[idx_face.
get()]);
2147 assert(this->
isValid(idx_face));
2148 faces_[idx_face.
get()] = face;
2186 std::vector<bool> is_new_;
2189 std::vector<bool> make_adjacent_;
2192 std::vector<bool> is_boundary_;
2201 template <
class MeshT>
A base class for all pcl exceptions which inherits from std::runtime_error.
void push_back(const PointT &pt)
Insert a new point in the cloud, at the end of the container.
const PointT & front() const
void resize(std::size_t count)
Resizes the container to contain count elements.
const PointT & back() const
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
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.
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.
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.
EdgeDataCloud & getEdgeDataCloud()
Get access to the stored edge data.
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
Vertex & getVertex(const VertexIndex &idx_vertex)
Get the vertex for the given index.
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
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).
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
pcl::geometry::InnerHalfEdgeAroundFaceCirculator< const Self > InnerHalfEdgeAroundFaceCirculator
HalfEdgeDataCloud & getHalfEdgeDataCloud()
Get access to the stored half-edge data.
void connectOldOld(const HalfEdgeIndex &, const HalfEdgeIndex &, const VertexIndex &, std::true_type)
Both half-edges are old (manifold version).
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.
VertexDataCloud & getVertexDataCloud()
Get access to the stored vertex 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.
FaceDataCloud & getFaceDataCloud()
Get access to the stored face data.
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)
Get the half-edge for the given index.
Face & getFace(const FaceIndex &idx_face)
Get the face for the given index.
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.