43#include <pcl/geometry/mesh_circulators.h>
44#include <pcl/geometry/mesh_elements.h>
45#include <pcl/geometry/mesh_indices.h>
46#include <pcl/geometry/mesh_traits.h>
49#include <pcl/point_cloud.h>
58#ifdef PCL_GEOMETRY_MESH_BASE_TEST_DELETE_FACE_MANIFOLD_2
61bool g_pcl_geometry_mesh_base_test_delete_face_manifold_2_success;
94template <
class DerivedT,
class MeshTraitsT,
class MeshTagT>
98 using Ptr = shared_ptr<Self>;
111 static_assert(std::is_convertible<IsManifold, bool>::value,
112 "MeshTraitsT::IsManifold is not convertible to bool");
118 std::integral_constant<bool,
119 !std::is_same<VertexData, pcl::geometry::NoData>::value>;
121 std::integral_constant<bool,
122 !std::is_same<HalfEdgeData, pcl::geometry::NoData>::value>;
124 std::integral_constant<bool,
125 !std::is_same<EdgeData, pcl::geometry::NoData>::value>;
127 std::integral_constant<bool,
128 !std::is_same<FaceData, pcl::geometry::NoData>::value>;
165 : vertex_data_cloud_()
166 , half_edge_data_cloud_()
184 vertices_.push_back(
Vertex());
209 return (
static_cast<Derived*
>(
this)->addFaceImpl(
210 vertices, face_data, edge_data, half_edge_data));
220 assert(this->
isValid(idx_vertex));
224 delete_faces_vertex_.clear();
232 }
while (++circ != circ_end);
234 for (
const auto& delete_me : delete_faces_vertex_) {
270 assert(this->
isValid(idx_edge));
284 assert(this->
isValid(idx_face));
300 this->remove<Vertices, VertexDataCloud, VertexIndices, HasVertexData>(
301 vertices_, vertex_data_cloud_);
303 this->remove<HalfEdges, HalfEdgeDataCloud, HalfEdgeIndices, HasHalfEdgeData>(
304 half_edges_, half_edge_data_cloud_);
306 this->remove<Faces, FaceDataCloud, FaceIndices, HasFaceData>(faces_,
310 if (HasEdgeData::value) {
311 auto it_ed_old = edge_data_cloud_.
begin();
312 auto it_ed_new = edge_data_cloud_.
begin();
314 for (
auto it_ind = new_half_edge_indices.cbegin(),
315 it_ind_end = new_half_edge_indices.cend();
316 it_ind != it_ind_end;
317 it_ind += 2, ++it_ed_old) {
318 if (it_ind->isValid()) {
319 *it_ed_new++ = *it_ed_old;
326 for (
auto it = vertices_.begin(); it != vertices_.end(); ++it) {
327 if (it->idx_outgoing_half_edge_.isValid()) {
328 it->idx_outgoing_half_edge_ =
329 new_half_edge_indices[it->idx_outgoing_half_edge_.get()];
333 for (
auto it = half_edges_.begin(); it != half_edges_.end(); ++it) {
334 it->idx_terminating_vertex_ =
335 new_vertex_indices[it->idx_terminating_vertex_.get()];
336 it->idx_next_half_edge_ = new_half_edge_indices[it->idx_next_half_edge_.get()];
337 it->idx_prev_half_edge_ = new_half_edge_indices[it->idx_prev_half_edge_.get()];
338 if (it->idx_face_.isValid()) {
339 it->idx_face_ = new_face_indices[it->idx_face_.get()];
343 for (
auto it = faces_.begin(); it != faces_.end(); ++it) {
344 it->idx_inner_half_edge_ = new_half_edge_indices[it->idx_inner_half_edge_.get()];
356 assert(this->
isValid(idx_vertex));
357 return (this->
getVertex(idx_vertex).idx_outgoing_half_edge_);
364 assert(this->
isValid(idx_vertex));
376 assert(this->
isValid(idx_half_edge));
377 return (this->
getHalfEdge(idx_half_edge).idx_terminating_vertex_);
384 assert(this->
isValid(idx_half_edge));
393 assert(this->
isValid(idx_half_edge));
396 : idx_half_edge.
get() + 1));
403 assert(this->
isValid(idx_half_edge));
404 return (this->
getHalfEdge(idx_half_edge).idx_next_half_edge_);
411 assert(this->
isValid(idx_half_edge));
412 return (this->
getHalfEdge(idx_half_edge).idx_prev_half_edge_);
419 assert(this->
isValid(idx_half_edge));
420 return (this->
getHalfEdge(idx_half_edge).idx_face_);
427 assert(this->
isValid(idx_half_edge));
439 assert(this->
isValid(idx_face));
440 return (this->
getFace(idx_face).idx_inner_half_edge_);
447 assert(this->
isValid(idx_face));
459 assert(this->
isValid(idx_vertex));
467 assert(this->
isValid(idx_outgoing_half_edge));
475 assert(this->
isValid(idx_vertex));
484 assert(this->
isValid(idx_outgoing_half_edge));
492 assert(this->
isValid(idx_vertex));
501 assert(this->
isValid(idx_incoming_half_edge));
509 assert(this->
isValid(idx_vertex));
517 assert(this->
isValid(idx_outgoing_half_edge));
525 assert(this->
isValid(idx_face));
533 assert(this->
isValid(idx_inner_half_edge));
541 assert(this->
isValid(idx_face));
549 assert(this->
isValid(idx_inner_half_edge));
557 assert(this->
isValid(idx_face));
565 assert(this->
isValid(idx_inner_half_edge));
573 assert(this->
isValid(idx_face));
581 assert(this->
isValid(idx_inner_half_edge));
600 for (std::size_t i = 0; i < this->
sizeVertices(); ++i) {
623 for (std::size_t i = 0; i < this->
sizeFaces(); ++i) {
673 assert(this->
isValid(idx_vertex));
690 assert(this->
isValid(idx_edge));
699 assert(this->
isValid(idx_face));
711 assert(this->
isValid(idx_vertex));
724 assert(this->
isValid(idx_vertex));
743 assert(this->
isValid(idx_edge));
755 template <
bool CheckVerticesT>
759 assert(this->
isValid(idx_face));
760 return (this->
isBoundary(idx_face, std::integral_constant<bool, CheckVerticesT>()));
768 assert(this->
isValid(idx_face));
769 return (this->
isBoundary(idx_face, std::true_type()));
780 assert(this->
isValid(idx_vertex));
801 return (vertices_.size());
808 assert(half_edges_.size() % 2 == 0);
809 return (half_edges_.size());
816 assert(half_edges_.size() % 2 == 0);
817 return (half_edges_.size() / 2);
824 return (faces_.size());
842 return (vertices_.empty());
849 return (half_edges_.empty());
856 return (faces_.empty());
867 vertices_.reserve(n);
876 half_edges_.reserve(2 * n);
897 vertices_.resize(n,
Vertex());
907 half_edges_.resize(2 * n,
HalfEdge());
916 faces_.resize(n,
Face());
948 return (vertex_data_cloud_);
955 return (vertex_data_cloud_);
966 if (vertex_data_cloud.
size() == vertex_data_cloud_.
size()) {
967 vertex_data_cloud_ = vertex_data_cloud;
983 return (half_edge_data_cloud_);
990 return (half_edge_data_cloud_);
1001 if (half_edge_data_cloud.
size() == half_edge_data_cloud_.
size()) {
1002 half_edge_data_cloud_ = half_edge_data_cloud;
1018 return (edge_data_cloud_);
1025 return (edge_data_cloud_);
1035 if (edge_data_cloud.
size() == edge_data_cloud_.
size()) {
1036 edge_data_cloud_ = edge_data_cloud;
1052 return (face_data_cloud_);
1059 return (face_data_cloud_);
1069 if (face_data_cloud.
size() == face_data_cloud_.
size()) {
1070 face_data_cloud_ = face_data_cloud;
1086 if (HasVertexData::value) {
1087 assert(&vertex_data >= &vertex_data_cloud_.
front() &&
1088 &vertex_data <= &vertex_data_cloud_.
back());
1098 if (HasHalfEdgeData::value) {
1099 assert(&half_edge_data >= &half_edge_data_cloud_.
front() &&
1100 &half_edge_data <= &half_edge_data_cloud_.
back());
1111 if (HasEdgeData::value) {
1112 assert(&edge_data >= &edge_data_cloud_.
front() &&
1113 &edge_data <= &edge_data_cloud_.
back());
1123 if (HasFaceData::value) {
1124 assert(&face_data >= &face_data_cloud_.
front() &&
1125 &face_data <= &face_data_cloud_.
back());
1160 const int n =
static_cast<int>(vertices.size());
1165 inner_he_.resize(n);
1168 make_adjacent_.resize(n);
1169 for (
int i = 0; i < n; ++i) {
1171 vertices[(i + 1) % n],
1178 for (
int i = 0; i < n; ++i) {
1179 int j = (i + 1) % n;
1193 if (!IsManifold::value) {
1194 for (
int i = 0; i < n; ++i) {
1195 if (make_adjacent_[i]) {
1196 this->
makeAdjacent(inner_he_[i], inner_he_[(i + 1) % n], free_he_[i]);
1202 for (
int i = 0; i < n; ++i) {
1205 vertices[i], vertices[(i + 1) % n], half_edge_data, edge_data);
1210 for (
int i = 0; i < n; ++i) {
1211 int j = (i + 1) % n;
1212 if (is_new_[i] && is_new_[j])
1214 else if (is_new_[i] && !is_new_[j])
1215 this->
connectNewOld(inner_he_[i], inner_he_[j], vertices[j]);
1216 else if (!is_new_[i] && is_new_[j])
1217 this->
connectOldNew(inner_he_[i], inner_he_[j], vertices[j]);
1244 half_edges_.push_back(
HalfEdge(idx_v_b));
1245 half_edges_.push_back(
HalfEdge(idx_v_a));
1251 return (
HalfEdgeIndex(
static_cast<int>(half_edges_.size() - 2)));
1270 std::vector<bool>::reference is_new_ab,
1271 std::true_type )
const
1291 std::vector<bool>::reference is_new_ab,
1292 std::false_type )
const
1313 }
while (++circ != circ_end);
1322 const bool is_new_ab,
1323 const bool is_new_bc,
1324 const bool is_isolated_b,
1325 std::vector<bool>::reference ,
1327 std::true_type )
const
1329 return !(is_new_ab && is_new_bc && !is_isolated_b);
1344 const bool is_new_ab,
1345 const bool is_new_bc,
1347 std::vector<bool>::reference make_adjacent_ab_bc,
1349 std::false_type )
const
1351 if (is_new_ab || is_new_bc) {
1352 make_adjacent_ab_bc =
false;
1357 make_adjacent_ab_bc =
false;
1361 make_adjacent_ab_bc =
true;
1414 faces_.push_back(
Face(inner_he.back()));
1419 for (
const auto& idx_half_edge : inner_he) {
1458 this->
connectNewNew(idx_he_ab, idx_he_bc, idx_v_b, std::true_type());
1524 if (idx_he_b_out == idx_he_bc)
1530 while (++circ != circ_end) {
1544 template <
class DataT>
1552 template <
class DataT>
1569 assert(this->
isValid(idx_face));
1570 delete_faces_face_.clear();
1571 delete_faces_face_.push_back(idx_face);
1573 while (!delete_faces_face_.empty()) {
1574 const FaceIndex idx_face_cur = delete_faces_face_.back();
1575 delete_faces_face_.pop_back();
1579 this->
deleteFace(idx_face_cur, std::false_type());
1587 assert(this->
isValid(idx_face));
1593 is_boundary_.clear();
1599 is_boundary_.push_back(
1601 }
while (++circ != circ_end);
1602 assert(inner_he_.size() >= 3);
1604 const int n =
static_cast<int>(inner_he_.size());
1607 if (IsManifold::value) {
1608 for (
int i = 0; i < n; ++i) {
1610 this->
reconnect(inner_he_[i], inner_he_[j], is_boundary_[i], is_boundary_[j]);
1612 for (
int i = 0; i < n; ++i) {
1617 for (
int i = 0; i < n; ++i) {
1619 this->
reconnect(inner_he_[i], inner_he_[j], is_boundary_[i], is_boundary_[j]);
1636 const bool is_boundary_ba,
1637 const bool is_boundary_cb)
1643 if (is_boundary_ba && is_boundary_cb)
1647 if (idx_he_cb_next == idx_he_ba)
1659 else if (is_boundary_ba && !is_boundary_cb)
1667 else if (!is_boundary_ba && is_boundary_cb)
1693 delete_faces_face_.push_back(this->
getFaceIndex((circ++).getTargetIndex()));
1695#ifdef PCL_GEOMETRY_MESH_BASE_TEST_DELETE_FACE_MANIFOLD_2
1703 pcl::geometry::g_pcl_geometry_mesh_base_test_delete_face_manifold_2_success =
1735 assert(this->
isValid(idx_vertex));
1743 assert(this->
isValid(idx_he));
1751 assert(this->
isValid(idx_edge));
1760 assert(this->
isValid(idx_face));
1781 template <
class ElementContainerT,
1782 class DataContainerT,
1783 class IndexContainerT,
1786 remove(ElementContainerT& elements, DataContainerT& data_cloud)
1788 using Index =
typename IndexContainerT::value_type;
1789 using Element =
typename ElementContainerT::value_type;
1791 if (HasDataT::value)
1792 assert(elements.size() == data_cloud.size());
1794 assert(data_cloud.empty());
1796 IndexContainerT new_indices(elements.size(),
1797 typename IndexContainerT::value_type());
1798 Index ind_old(0), ind_new(0);
1800 typename ElementContainerT::const_iterator it_e_old = elements.begin();
1801 auto it_e_new = elements.begin();
1803 typename DataContainerT::const_iterator it_d_old = data_cloud.begin();
1804 auto it_d_new = data_cloud.begin();
1806 auto it_ind_new = new_indices.begin();
1807 typename IndexContainerT::const_iterator it_ind_new_end = new_indices.end();
1809 while (it_ind_new != it_ind_new_end) {
1811 *it_ind_new = ind_new++;
1814 *it_e_new++ = *it_e_old;
1815 this->
assignIf(it_d_old, it_d_new, HasDataT());
1824 elements.resize(ind_new.get(), Element());
1825 if (HasDataT::value) {
1826 data_cloud.resize(ind_new.get());
1828 else if (it_d_old != data_cloud.begin() || it_d_new != data_cloud.begin()) {
1829 std::cerr <<
"TODO: Bug in MeshBase::remove!\n";
1834 return (new_indices);
1838 template <
class IteratorT>
1846 template <
class IteratorT>
1852 template <
class ConstIteratorT,
class IteratorT>
1856 std::true_type )
const
1862 template <
class ConstIteratorT,
class IteratorT>
1866 std::false_type )
const
1878 assert(this->
isValid(idx_vertex));
1879 this->
getVertex(idx_vertex).idx_outgoing_half_edge_ = idx_outgoing_half_edge;
1887 assert(this->
isValid(idx_half_edge));
1888 this->
getHalfEdge(idx_half_edge).idx_terminating_vertex_ = idx_terminating_vertex;
1896 assert(this->
isValid(idx_half_edge));
1897 this->
getHalfEdge(idx_half_edge).idx_next_half_edge_ = idx_next_half_edge;
1905 assert(this->
isValid(idx_half_edge));
1906 this->
getHalfEdge(idx_half_edge).idx_prev_half_edge_ = idx_prev_half_edge;
1913 assert(this->
isValid(idx_half_edge));
1914 this->
getHalfEdge(idx_half_edge).idx_face_ = idx_face;
1922 assert(this->
isValid(idx_face));
1923 this->
getFace(idx_face).idx_inner_half_edge_ = idx_inner_half_edge;
1941 }
while (++circ != circ_end);
1958 }
while (++circ != circ_end);
1978 if (!this->
isBoundary((circ++).getTargetIndex()))
1983 }
while (++circ != circ_end);
1999 for (std::size_t i = 0; i < this->
sizeVertices(); ++i) {
2011 template <
class DataCloudT>
2013 reserveData(DataCloudT& cloud,
const std::size_t n, std::true_type )
const
2019 template <
class DataCloudT>
2023 std::false_type )
const
2027 template <
class DataCloudT>
2030 const std::size_t n,
2031 const typename DataCloudT::value_type& data,
2032 std::true_type )
const
2034 data_cloud.resize(n, data);
2038 template <
class DataCloudT>
2042 const typename DataCloudT::value_type& ,
2043 std::false_type )
const
2047 template <
class DataCloudT>
2055 template <
class DataCloudT>
2068 assert(this->
isValid(idx_vertex));
2069 return (vertices_[idx_vertex.
get()]);
2076 assert(this->
isValid(idx_vertex));
2077 return (vertices_[idx_vertex.
get()]);
2084 assert(this->
isValid(idx_vertex));
2085 vertices_[idx_vertex.
get()] = vertex;
2096 assert(this->
isValid(idx_he));
2097 return (half_edges_[idx_he.
get()]);
2104 assert(this->
isValid(idx_he));
2105 return (half_edges_[idx_he.
get()]);
2112 assert(this->
isValid(idx_he));
2113 half_edges_[idx_he.
get()] = half_edge;
2124 assert(this->
isValid(idx_face));
2125 return (faces_[idx_face.
get()]);
2132 assert(this->
isValid(idx_face));
2133 return (faces_[idx_face.
get()]);
2140 assert(this->
isValid(idx_face));
2141 faces_[idx_face.
get()] = face;
2179 std::vector<bool> is_new_;
2182 std::vector<bool> make_adjacent_;
2185 std::vector<bool> is_boundary_;
2194 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.
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 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
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.