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>
60#ifdef PCL_GEOMETRY_MESH_BASE_TEST_DELETE_FACE_MANIFOLD_2
63bool g_pcl_geometry_mesh_base_test_delete_face_manifold_2_success;
96template <
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));
273 this->
deleteEdge(pcl::geometry::toHalfEdgeIndex(idx_edge));
275 pcl::geometry::toHalfEdgeIndex(idx_edge,
false)));
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));
602 if (this->
sizeFaces() != other.sizeFaces())
605 for (std::size_t i = 0; i < this->
sizeVertices(); ++i) {
628 for (std::size_t i = 0; i < this->
sizeFaces(); ++i) {
630 other.getInnerHalfEdgeIndex(
FaceIndex(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));
699 return (this->
isDeleted(pcl::geometry::toHalfEdgeIndex(idx_edge,
true)) ||
700 this->
isDeleted(pcl::geometry::toHalfEdgeIndex(idx_edge,
false)));
707 assert(this->
isValid(idx_face));
719 assert(this->
isValid(idx_vertex));
732 assert(this->
isValid(idx_vertex));
751 assert(this->
isValid(idx_edge));
752 const HalfEdgeIndex& idx = pcl::geometry::toHalfEdgeIndex(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());
1097 return (
VertexIndex(std::distance(&vertex_data_cloud_.
front(), &vertex_data)));
1106 if (HasHalfEdgeData::value) {
1107 assert(&half_edge_data >= &half_edge_data_cloud_.
front() &&
1108 &half_edge_data <= &half_edge_data_cloud_.
back());
1110 std::distance(&half_edge_data_cloud_.
front(), &half_edge_data)));
1119 if (HasEdgeData::value) {
1120 assert(&edge_data >= &edge_data_cloud_.
front() &&
1121 &edge_data <= &edge_data_cloud_.
back());
1122 return (
EdgeIndex(std::distance(&edge_data_cloud_.
front(), &edge_data)));
1131 if (HasFaceData::value) {
1132 assert(&face_data >= &face_data_cloud_.
front() &&
1133 &face_data <= &face_data_cloud_.
back());
1134 return (
FaceIndex(std::distance(&face_data_cloud_.
front(), &face_data)));
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) {
1621 this->
getHalfEdge(inner_he_[i]).idx_face_.invalidate();
1625 for (
int i = 0; i < n; ++i) {
1627 this->
reconnect(inner_he_[i], inner_he_[j], is_boundary_[i], is_boundary_[j]);
1628 this->
getHalfEdge(inner_he_[i]).idx_face_.invalidate();
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));
1752 this->
getHalfEdge(idx_he).idx_terminating_vertex_.invalidate();
1759 assert(this->
isValid(idx_edge));
1760 this->
markDeleted(pcl::geometry::toHalfEdgeIndex(idx_edge,
true));
1761 this->
markDeleted(pcl::geometry::toHalfEdgeIndex(idx_edge,
false));
1768 assert(this->
isValid(idx_face));
1769 this->
getFace(idx_face).idx_inner_half_edge_.invalidate();
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 & back() const
const PointT & front() const
void resize(std::size_t count)
Resizes the container to contain count elements.
iterator begin() noexcept
void invalidate()
Invalidate the index.
bool isValid() const
Returns true if the index is valid.
int get() const
Get the index.
Circulates clockwise around a face and returns an index to the face of the outer half-edge (the targe...
Circulates counter-clockwise around a vertex and returns an index to the face of the outgoing half-ed...
FaceIndex getTargetIndex() const
Get the index to the target face.
Circulates counter-clockwise around a vertex and returns an index to the incoming half-edge (the targ...
HalfEdgeIndex getTargetIndex() const
Get the index to the incoming half-edge.
Circulates clockwise around a face and returns an index to the inner half-edge (the target).
HalfEdgeIndex getTargetIndex() const
Get the index to the inner half-edge.
Base class for the half-edge mesh.
void setOutgoingHalfEdgeIndex(const VertexIndex &idx_vertex, const HalfEdgeIndex &idx_outgoing_half_edge)
Set the outgoing half-edge index to a given vertex.
HalfEdgeIndex getNextHalfEdgeIndex(const HalfEdgeIndex &idx_half_edge) const
Get the next half-edge index to a given half-edge.
std::vector< Face > Faces
shared_ptr< const Self > ConstPtr
VertexDataCloud & getVertexDataCloud()
Get access to the stored vertex data.
bool isDeleted(const FaceIndex &idx_face) const
Check if the given face is marked as deleted.
void setNextHalfEdgeIndex(const HalfEdgeIndex &idx_half_edge, const HalfEdgeIndex &idx_next_half_edge)
Set the next half_edge index to a given half-edge.
bool emptyVertices() const
Check if the vertices are empty.
FaceDataCloud getFaceDataCloud() const
Get the stored face data.
std::integral_constant< bool, !std::is_same< VertexData, pcl::geometry::NoData >::value > HasVertexData
bool isBoundary(const VertexIndex &idx_vertex) const
Check if the given vertex lies on the boundary.
VertexAroundVertexCirculator getVertexAroundVertexCirculator(const HalfEdgeIndex &idx_outgoing_half_edge) const
pcl::geometry::IncomingHalfEdgeAroundVertexCirculator< const Self > IncomingHalfEdgeAroundVertexCirculator
InnerHalfEdgeAroundFaceCirculator getInnerHalfEdgeAroundFaceCirculator(const HalfEdgeIndex &idx_inner_half_edge) const
bool isBoundary(const FaceIndex &idx_face, std::true_type) const
Check if any vertex of the face lies on the boundary.
void deleteEdge(const EdgeIndex &idx_edge)
Mark the given edge (both half-edges) and the associated faces as deleted.
VertexAroundVertexCirculator getVertexAroundVertexCirculator(const VertexIndex &idx_vertex) const
pcl::geometry::OuterHalfEdgeAroundFaceCirculator< const Self > OuterHalfEdgeAroundFaceCirculator
void deleteFace(const FaceIndex &idx_face)
Mark the given face as deleted.
Face & getFace(const FaceIndex &idx_face)
Get the face for the given index.
std::vector< Vertex > Vertices
EdgeIndex getEdgeIndex(const EdgeData &edge_data) const
Get the index associated to the given edge data.
HalfEdgeIndex getOppositeHalfEdgeIndex(const HalfEdgeIndex &idx_half_edge) const
Get the opposite half-edge index to a given half-edge.
HalfEdgeIndex getOuterHalfEdgeIndex(const FaceIndex &idx_face) const
Get the outer half-edge inex to a given face.
std::vector< EdgeIndex > EdgeIndices
bool emptyEdges() const
Check if the edges are empty.
VertexAroundFaceCirculator getVertexAroundFaceCirculator(const HalfEdgeIndex &idx_inner_half_edge) const
void setHalfEdge(const HalfEdgeIndex &idx_he, const HalfEdge &half_edge)
Set the half-edge at the given index.
FaceIndex connectFace(const HalfEdgeIndices &inner_he, const FaceData &face_data)
Add a face to the mesh and connect it to the half-edges.
HalfEdgeIndex getHalfEdgeIndex(const HalfEdgeData &half_edge_data) const
Get the index associated to the given half-edge data.
void resizeData(DataCloudT &data_cloud, const std::size_t n, const typename DataCloudT::value_type &data, std::true_type) const
Resize the mesh data.
HalfEdgeDataCloud getHalfEdgeDataCloud() const
Get the stored half-edge data.
pcl::geometry::Vertex Vertex
bool isBoundary(const HalfEdgeIndex &idx_he) const
Check if the given half-edge lies on the boundary.
IncomingHalfEdgeAroundVertexCirculator getIncomingHalfEdgeAroundVertexCirculator(const VertexIndex &idx_vertex) const
std::size_t sizeVertices() const
Get the number of the vertices.
void reconnect(const HalfEdgeIndex &idx_he_ab, const HalfEdgeIndex &idx_he_bc, const bool is_boundary_ba, const bool is_boundary_cb)
Deconnect the input half-edges from the mesh and adjust the indices of the connected half-edges.
void resizeVertices(const std::size_t n, const VertexData &data=VertexData())
Resize the the vertices to n elements.
HalfEdgeDataCloud & getHalfEdgeDataCloud()
Get access to the stored half-edge data.
bool setEdgeDataCloud(const EdgeDataCloud &edge_data_cloud)
Change the stored edge data.
bool checkTopology1(const VertexIndex &idx_v_a, const VertexIndex &idx_v_b, HalfEdgeIndex &idx_he_ab, std::vector< bool >::reference is_new_ab, std::true_type) const
Check if the edge between the two vertices can be added.
std::size_t sizeEdges() const
Get the number of the edges.
pcl::geometry::FaceIndex FaceIndex
InnerHalfEdgeAroundFaceCirculator getInnerHalfEdgeAroundFaceCirculator(const FaceIndex &idx_face) const
typename MeshTraitsT::EdgeData EdgeData
bool emptyFaces() const
Check if the faces are empty.
bool empty() const
Check if the mesh is empty.
IncomingHalfEdgeAroundVertexCirculator getIncomingHalfEdgeAroundVertexCirculator(const HalfEdgeIndex &idx_incoming_half_edge) const
void deleteVertex(const VertexIndex &idx_vertex)
Mark the given vertex and all connected half-edges and faces as deleted.
std::vector< FaceIndex > FaceIndices
void reserveData(DataCloudT &, const std::size_t, std::false_type) const
Does nothing.
void connectOldNew(const HalfEdgeIndex &idx_he_ab, const HalfEdgeIndex &idx_he_bc, const VertexIndex &idx_v_b)
The second half-edge is new.
bool setHalfEdgeDataCloud(const HalfEdgeDataCloud &half_edge_data_cloud)
Change the stored half-edge data.
VertexIndex getOriginatingVertexIndex(const HalfEdgeIndex &idx_half_edge) const
Get the originating vertex index to a given half-edge.
std::size_t sizeFaces() const
Get the number of the faces.
void deleteEdge(const HalfEdgeIndex &idx_he)
Mark the given half-edge, the opposite half-edge and the associated faces as deleted.
void resizeData(DataCloudT &, const std::size_t, const typename DataCloudT::value_type &, std::false_type) const
Does nothing.
typename HalfEdges::iterator HalfEdgeIterator
typename MeshTraitsT::HalfEdgeData HalfEdgeData
void markDeleted(const FaceIndex &idx_face)
Mark the given face as deleted.
OutgoingHalfEdgeAroundVertexCirculator getOutgoingHalfEdgeAroundVertexCirculator(const HalfEdgeIndex &idx_outgoing_half_edge) const
HalfEdgeIndex getInnerHalfEdgeIndex(const FaceIndex &idx_face) const
Get the inner half-edge index to a given face.
void addData(pcl::PointCloud< DataT > &, const DataT &, std::false_type)
Does nothing.
pcl::PointCloud< VertexData > VertexDataCloud
void reconnectNBNB(const HalfEdgeIndex &idx_he_bc, const HalfEdgeIndex &idx_he_cb, const VertexIndex &idx_v_b, std::true_type)
Both edges are not on the boundary.
HalfEdgeIndex getPrevHalfEdgeIndex(const HalfEdgeIndex &idx_half_edge) const
Get the previous half-edge index to a given half-edge.
bool setFaceDataCloud(const FaceDataCloud &face_data_cloud)
Change the stored face data.
OuterHalfEdgeAroundFaceCirculator getOuterHalfEdgeAroundFaceCirculator(const HalfEdgeIndex &idx_inner_half_edge) const
void clearData(DataCloudT &, std::false_type) const
Does nothing.
Vertex getVertex(const VertexIndex &idx_vertex) const
Get the vertex for the given index.
pcl::geometry::FaceAroundFaceCirculator< const Self > FaceAroundFaceCirculator
FaceIndex addFaceImplBase(const VertexIndices &vertices, const FaceData &face_data, const EdgeData &edge_data, const HalfEdgeData &half_edge_data)
General implementation of addFace.
typename Faces::const_iterator FaceConstIterator
typename MeshTraitsT::VertexData VertexData
void markDeleted(const VertexIndex &idx_vertex)
Mark the given vertex as deleted.
bool setVertexDataCloud(const VertexDataCloud &vertex_data_cloud)
Change the stored vertex data.
pcl::geometry::FaceAroundVertexCirculator< const Self > FaceAroundVertexCirculator
std::vector< HalfEdgeIndex > HalfEdgeIndices
void reserveFaces(const std::size_t n)
Reserve storage space for n faces.
bool checkTopology2(const HalfEdgeIndex &, const HalfEdgeIndex &, const bool is_new_ab, const bool is_new_bc, const bool is_isolated_b, std::vector< bool >::reference, HalfEdgeIndex &, std::true_type) const
Check if the face may be added (mesh does not become non-manifold).
bool isValid(const HalfEdgeIndex &idx_he) const
Check if the given half-edge index is a valid index into the mesh.
void markDeleted(const HalfEdgeIndex &idx_he)
Mark the given half-edge as deleted.
std::size_t sizeHalfEdges() const
Get the number of the half-edges.
std::integral_constant< bool, !std::is_same< EdgeData, pcl::geometry::NoData >::value > HasEdgeData
void resizeEdges(const std::size_t n, const EdgeData &edge_data=EdgeData(), const HalfEdgeData he_data=HalfEdgeData())
Resize the edges to n elements (half-edges will hold 2*n elements).
void setVertex(const VertexIndex &idx_vertex, const Vertex &vertex)
Set the vertex at the given index.
OutgoingHalfEdgeAroundVertexCirculator getOutgoingHalfEdgeAroundVertexCirculator(const VertexIndex &idx_vertex) const
std::integral_constant< bool, !std::is_same< FaceData, pcl::geometry::NoData >::value > HasFaceData
VertexIndex getVertexIndex(const VertexData &vertex_data) const
Get the index associated to the given vertex data.
void assignIf(const ConstIteratorT, IteratorT, std::false_type) const
Does nothing.
void addData(pcl::PointCloud< DataT > &cloud, const DataT &data, std::true_type)
Add mesh data.
pcl::PointCloud< FaceData > FaceDataCloud
bool isManifold(std::true_type) const
Always manifold.
bool isValid(const EdgeIndex &idx_edge) const
Check if the given edge index is a valid index into the mesh.
void connectNewNew(const HalfEdgeIndex &idx_he_ab, const HalfEdgeIndex &idx_he_bc, const VertexIndex &idx_v_b, std::false_type)
Both half-edges are new (non-manifold version).
VertexAroundFaceCirculator getVertexAroundFaceCirculator(const FaceIndex &idx_face) const
pcl::geometry::VertexIndex VertexIndex
void setTerminatingVertexIndex(const HalfEdgeIndex &idx_half_edge, const VertexIndex &idx_terminating_vertex)
Set the terminating vertex index to a given half-edge.
bool isValid(const FaceIndex &idx_face) const
Check if the given face index is a valid index into the mesh.
void reserveData(DataCloudT &cloud, const std::size_t n, std::true_type) const
Reserve storage space for the mesh data.
void reserveEdges(const std::size_t n)
Reserve storage space for n edges (2*n storage space is reserved for the half-edges).
FaceIndex addFace(const VertexIndices &vertices, const FaceData &face_data=FaceData(), const EdgeData &edge_data=EdgeData(), const HalfEdgeData &half_edge_data=HalfEdgeData())
Add a face to the mesh.
pcl::geometry::HalfEdge HalfEdge
void connectPrevNext(const HalfEdgeIndex &idx_he_ab, const HalfEdgeIndex &idx_he_bc)
Connect the next and prev indices of the two half-edges with each other.
bool isBoundary(const FaceIndex &idx_face) const
Check if the given face lies on the boundary.
bool isDeleted(const HalfEdgeIndex &idx_he) const
Check if the given half-edge is marked as deleted.
std::vector< HalfEdge > HalfEdges
bool isIsolated(const VertexIndex &idx_vertex) const
Check if the given vertex is isolated (not connected to other elements).
void makeAdjacent(const HalfEdgeIndex &idx_he_ab, const HalfEdgeIndex &idx_he_bc, HalfEdgeIndex &idx_free_half_edge)
Make the half-edges bc the next half-edge of ab.
Face getFace(const FaceIndex &idx_face) const
Get the face for the given index.
void assignIf(const ConstIteratorT source, IteratorT target, std::true_type) const
Assign the source iterator to the target iterator.
FaceAroundFaceCirculator getFaceAroundFaceCirculator(const FaceIndex &idx_face) const
bool isDeleted(const VertexIndex &idx_vertex) const
Check if the given vertex is marked as deleted.
HalfEdgeIndex getOutgoingHalfEdgeIndex(const VertexIndex &idx_vertex) const
Get the outgoing half-edge index to a given vertex.
typename Vertices::const_iterator VertexConstIterator
EdgeDataCloud & getEdgeDataCloud()
Get access to the stored edge data.
bool isManifold(const VertexIndex &idx_vertex, std::false_type) const
Check if the given vertex is manifold.
bool isBoundary(const FaceIndex &idx_face) const
Check if the given face lies on the boundary.
void setFace(const FaceIndex &idx_face, const Face &face)
Set the face at the given index.
void connectNewNew(const HalfEdgeIndex &idx_he_ab, const HalfEdgeIndex &idx_he_bc, const VertexIndex &idx_v_b, std::true_type)
Both half-edges are new (manifold version).
HalfEdge & getHalfEdge(const HalfEdgeIndex &idx_he)
Get the half-edge for the given index.
bool isEqualTopology(const Self &other) const
Check if the other mesh has the same topology as this mesh.
VertexIndex addVertex(const VertexData &vertex_data=VertexData())
Add a vertex to the mesh.
FaceAroundVertexCirculator getFaceAroundVertexCirculator(const HalfEdgeIndex &idx_outgoing_half_edge) const
VertexDataCloud getVertexDataCloud() const
Get the stored vertex data.
void setPrevHalfEdgeIndex(const HalfEdgeIndex &idx_half_edge, const HalfEdgeIndex &idx_prev_half_edge)
Set the previous half-edge index to a given half-edge.
void reserveVertices(const std::size_t n)
Reserve storage space n vertices.
typename HalfEdges::const_iterator HalfEdgeConstIterator
void resizeFaces(const std::size_t n, const FaceData &data=FaceData())
Resize the faces to n elements.
pcl::geometry::VertexAroundFaceCirculator< const Self > VertexAroundFaceCirculator
FaceIndex getOppositeFaceIndex(const HalfEdgeIndex &idx_half_edge) const
Get the face index to a given half-edge.
typename MeshTraitsT::IsManifold IsManifold
pcl::PointCloud< HalfEdgeData > HalfEdgeDataCloud
bool checkTopology2(const HalfEdgeIndex &idx_he_ab, const HalfEdgeIndex &idx_he_bc, const bool is_new_ab, const bool is_new_bc, const bool, std::vector< bool >::reference make_adjacent_ab_bc, HalfEdgeIndex &idx_free_half_edge, std::false_type) const
Check if the half-edge bc is the next half-edge of ab.
typename MeshTraitsT::FaceData FaceData
Vertex & getVertex(const VertexIndex &idx_vertex)
Get the vertex for the given index.
pcl::geometry::InnerHalfEdgeAroundFaceCirculator< const Self > InnerHalfEdgeAroundFaceCirculator
void connectOldOld(const HalfEdgeIndex &, const HalfEdgeIndex &, const VertexIndex &, std::true_type)
Both half-edges are old (manifold version).
FaceDataCloud & getFaceDataCloud()
Get access to the stored face data.
void markDeleted(const EdgeIndex &idx_edge)
Mark the given edge (both half-edges) as deleted.
std::vector< VertexIndex > VertexIndices
void connectNewOld(const HalfEdgeIndex &idx_he_ab, const HalfEdgeIndex &idx_he_bc, const VertexIndex &idx_v_b)
The first half-edge is new.
FaceAroundVertexCirculator getFaceAroundVertexCirculator(const VertexIndex &idx_vertex) const
pcl::geometry::VertexAroundVertexCirculator< const Self > VertexAroundVertexCirculator
pcl::geometry::EdgeIndex EdgeIndex
bool isValid(const VertexIndex &idx_vertex) const
Check if the given vertex index is a valid index into the mesh.
VertexIndex getTerminatingVertexIndex(const HalfEdgeIndex &idx_half_edge) const
Get the terminating vertex index to a given half-edge.
EdgeDataCloud getEdgeDataCloud() const
Get the stored edge data.
void deleteFace(const FaceIndex &idx_face, std::false_type)
Non-manifold version of deleteFace.
void cleanUp()
Removes all mesh elements and data that are marked as deleted.
bool isManifold(std::false_type) const
Check if all vertices in the mesh are manifold.
void clearData(DataCloudT &cloud, std::true_type) const
Clear the mesh data.
FaceIndex getFaceIndex(const FaceData &face_data) const
Get the index associated to the given face data.
void setFaceIndex(const HalfEdgeIndex &idx_half_edge, const FaceIndex &idx_face)
Set the face index to a given half-edge.
HalfEdgeIndex addEdge(const VertexIndex &idx_v_a, const VertexIndex &idx_v_b, const HalfEdgeData &he_data, const EdgeData &edge_data)
Add an edge between the two given vertices and connect them with the vertices.
std::integral_constant< bool, !std::is_same< HalfEdgeData, pcl::geometry::NoData >::value > HasHalfEdgeData
void setInnerHalfEdgeIndex(const FaceIndex &idx_face, const HalfEdgeIndex &idx_inner_half_edge)
Set the inner half-edge index to a given face.
FaceIndex getFaceIndex(const HalfEdgeIndex &idx_half_edge) const
Get the face index to a given half-edge.
void incrementIf(IteratorT &, std::false_type) const
Does nothing.
bool isBoundary(const FaceIndex &idx_face, std::false_type) const
Check if any edge of the face lies on the boundary.
MeshBase< DerivedT, MeshTraitsT, MeshTagT > Self
bool isDeleted(const EdgeIndex &idx_edge) const
Check if the given edge (any of the two half-edges) is marked as deleted.
void connectOldOld(const HalfEdgeIndex &, const HalfEdgeIndex &idx_he_bc, const VertexIndex &idx_v_b, std::false_type)
Both half-edges are old (non-manifold version).
bool isBoundary(const EdgeIndex &idx_edge) const
Check if the given edge lies on the boundary (any of the two half-edges lies on the boundary.
void reconnectNBNB(const HalfEdgeIndex &idx_he_bc, const HalfEdgeIndex &, const VertexIndex &idx_v_b, std::false_type)
Both edges are not on the boundary.
bool isManifold() const
Check if the mesh is manifold.
void deleteFace(const FaceIndex &idx_face, std::true_type)
Manifold version of deleteFace.
bool isManifold(const VertexIndex &idx_vertex) const
Check if the given vertex is manifold.
OuterHalfEdgeAroundFaceCirculator getOuterHalfEdgeAroundFaceCirculator(const FaceIndex &idx_face) const
typename Vertices::iterator VertexIterator
void clear()
Clear all mesh elements and data.
void incrementIf(IteratorT &it, std::true_type) const
Increment the iterator.
pcl::geometry::OutgoingHalfEdgeAroundVertexCirculator< const Self > OutgoingHalfEdgeAroundVertexCirculator
IndexContainerT remove(ElementContainerT &elements, DataContainerT &data_cloud)
Removes mesh elements and data that are marked as deleted from the container.
typename Faces::iterator FaceIterator
pcl::geometry::HalfEdgeIndex HalfEdgeIndex
FaceAroundFaceCirculator getFaceAroundFaceCirculator(const HalfEdgeIndex &idx_inner_half_edge) const
HalfEdgeIndex getIncomingHalfEdgeIndex(const VertexIndex &idx_vertex) const
Get the incoming half-edge index to a given vertex.
bool checkTopology1(const VertexIndex &idx_v_a, const VertexIndex &idx_v_b, HalfEdgeIndex &idx_he_ab, std::vector< bool >::reference is_new_ab, std::false_type) const
Non manifold version of checkTopology1.
pcl::PointCloud< EdgeData > EdgeDataCloud
HalfEdge getHalfEdge(const HalfEdgeIndex &idx_he) const
Get the half-edge for the given index.
bool isManifold(const VertexIndex &, std::true_type) const
Always manifold.
Read / write the half-edge mesh from / to a file.
Circulates clockwise around a face and returns an index to the outer half-edge (the target).
HalfEdgeIndex getTargetIndex() const
Get the index to the outer half-edge.
Circulates counter-clockwise around a vertex and returns an index to the outgoing half-edge (the targ...
HalfEdgeIndex getTargetIndex() const
Get the index to the outgoing half-edge.
Circulates clockwise around a face and returns an index to the terminating vertex of the inner half-e...
VertexIndex getTargetIndex() const
Get the index to the target vertex.
Circulates counter-clockwise around a vertex and returns an index to the terminating vertex of the ou...
VertexIndex getTargetIndex() const
Get the index to the target vertex.
HalfEdgeIndex getCurrentHalfEdgeIndex() const
Get the half-edge that is currently stored in the circulator.
A vertex is a node in the mesh.
#define PCL_MAKE_ALIGNED_OPERATOR_NEW
Macro to signal a class requires a custom allocator.
Defines functions, macros and traits for allocating and using memory.
Defines all the PCL and non-PCL macros used.
Describes a set of vertices in a polygon mesh, by basically storing an array of indices.