Prusa Slicer 2.6.0
Loading...
Searching...
No Matches
igl::geodesic::Mesh Class Reference
+ Collaboration diagram for igl::geodesic::Mesh:

Public Member Functions

 Mesh ()
 
 ~Mesh ()
 
template<class Points , class Faces >
void initialize_mesh_data (unsigned num_vertices, Points &p, unsigned num_faces, Faces &tri)
 
template<class Points , class Faces >
void initialize_mesh_data (Points &p, Faces &tri)
 
std::vector< Vertex > & vertices ()
 
std::vector< Edge > & edges ()
 
std::vector< Face > & faces ()
 
unsigned closest_vertices (SurfacePoint *p, std::vector< vertex_pointer > *storage=NULL)
 

Private Types

typedef voidvoid_pointer
 

Private Member Functions

void build_adjacencies ()
 
bool verify ()
 
void_pointer allocate_pointers (unsigned n)
 

Private Attributes

std::vector< Vertexm_vertices
 
std::vector< Edgem_edges
 
std::vector< Facem_faces
 
SimlpeMemoryAllocator< void_pointerm_pointer_allocator
 

Detailed Description

Member Typedef Documentation

◆ void_pointer

Constructor & Destructor Documentation

◆ Mesh()

igl::geodesic::Mesh::Mesh ( )
inline
691 {};

◆ ~Mesh()

igl::geodesic::Mesh::~Mesh ( )
inline
693{};

Member Function Documentation

◆ allocate_pointers()

void_pointer igl::geodesic::Mesh::allocate_pointers ( unsigned  n)
inlineprivate
718 {
719 return m_pointer_allocator.allocate(n);
720 }
SimlpeMemoryAllocator< void_pointer > m_pointer_allocator
Definition exact_geodesic.cpp:726
pointer allocate(unsigned const n)
Definition exact_geodesic.cpp:122

References igl::geodesic::SimlpeMemoryAllocator< T >::allocate(), and m_pointer_allocator.

Referenced by build_adjacencies(), and initialize_mesh_data().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ build_adjacencies()

void igl::geodesic::Mesh::build_adjacencies ( )
inlineprivate
829{
830 // Vertex->adjacent Faces
831 std::vector<unsigned> count(m_vertices.size()); //count adjacent vertices
832 for(unsigned i=0; i<m_faces.size(); ++i)
833 {
834 Face& f = m_faces[i];
835 for(unsigned j=0; j<3; ++j)
836 {
837 unsigned vertex_id = f.adjacent_vertices()[j]->id();
838 assert(vertex_id < m_vertices.size());
839 count[vertex_id]++;
840 }
841 }
842
843 for(unsigned i=0; i<m_vertices.size(); ++i) //reserve space
844 {
845 Vertex& v = m_vertices[i];
846 unsigned num_adjacent_faces = count[i];
847
848 v.adjacent_faces().set_allocation(allocate_pointers(num_adjacent_faces), //allocate three units of memory
849 num_adjacent_faces);
850 }
851
852 std::fill(count.begin(), count.end(), 0);
853 for(unsigned i=0; i<m_faces.size(); ++i)
854 {
855 Face& f = m_faces[i];
856 for(unsigned j=0; j<3; ++j)
857 {
859 v->adjacent_faces()[count[v->id()]++] = &f;
860 }
861 }
862
863 //find all edges
864 //i.e. find all half-edges, sort and combine them into edges
865 std::vector<HalfEdge> half_edges(m_faces.size()*3);
866 unsigned k = 0;
867 for(unsigned i=0; i<m_faces.size(); ++i)
868 {
869 Face& f = m_faces[i];
870 for(unsigned j=0; j<3; ++j)
871 {
872 half_edges[k].face_id = i;
873 unsigned vertex_id_1 = f.adjacent_vertices()[j]->id();
874 unsigned vertex_id_2 = f.adjacent_vertices()[(j+1) % 3]->id();
875 half_edges[k].vertex_0 = std::min(vertex_id_1, vertex_id_2);
876 half_edges[k].vertex_1 = std::max(vertex_id_1, vertex_id_2);
877
878 k++;
879 }
880 }
881 std::sort(half_edges.begin(), half_edges.end());
882
883 unsigned number_of_edges = 1;
884 for(unsigned i=1; i<half_edges.size(); ++i)
885 {
886 if(half_edges[i] != half_edges[i-1])
887 {
888 ++number_of_edges;
889 }
890 else
891 {
892 if(i<half_edges.size()-1) //sanity check: there should be at most two equal half-edges
893 { //if it fails, most likely the input data are messed up
894 assert(half_edges[i] != half_edges[i+1]);
895 }
896 }
897 }
898
899 // Edges->adjacent Vertices and Faces
900 m_edges.resize(number_of_edges);
901 unsigned edge_id = 0;
902 for(unsigned i=0; i<half_edges.size();)
903 {
904 Edge& e = m_edges[edge_id];
905 e.id() = edge_id++;
906
907 e.adjacent_vertices().set_allocation(allocate_pointers(2),2); //allocate two units of memory
908
909 e.adjacent_vertices()[0] = &m_vertices[half_edges[i].vertex_0];
910 e.adjacent_vertices()[1] = &m_vertices[half_edges[i].vertex_1];
911
912 e.length() = e.adjacent_vertices()[0]->distance(e.adjacent_vertices()[1]);
913 assert(e.length() > 1e-100); //algorithm works well with non-degenerate meshes only
914
915 if(i != half_edges.size()-1 && half_edges[i] == half_edges[i+1]) //double edge
916 {
917 e.adjacent_faces().set_allocation(allocate_pointers(2),2);
918 e.adjacent_faces()[0] = &m_faces[half_edges[i].face_id];
919 e.adjacent_faces()[1] = &m_faces[half_edges[i+1].face_id];
920 i += 2;
921 }
922 else //single edge
923 {
924 e.adjacent_faces().set_allocation(allocate_pointers(1),1); //one adjucent faces
925 e.adjacent_faces()[0] = &m_faces[half_edges[i].face_id];
926 i += 1;
927 }
928 }
929
930 // Vertices->adjacent Edges
931 std::fill(count.begin(), count.end(), 0);
932 for(unsigned i=0; i<m_edges.size(); ++i)
933 {
934 Edge& e = m_edges[i];
935 assert(e.adjacent_vertices().size()==2);
936 count[e.adjacent_vertices()[0]->id()]++;
937 count[e.adjacent_vertices()[1]->id()]++;
938 }
939 for(unsigned i=0; i<m_vertices.size(); ++i)
940 {
941 m_vertices[i].adjacent_edges().set_allocation(allocate_pointers(count[i]),
942 count[i]);
943 }
944 std::fill(count.begin(), count.end(), 0);
945 for(unsigned i=0; i<m_edges.size(); ++i)
946 {
947 Edge& e = m_edges[i];
948 for(unsigned j=0; j<2; ++j)
949 {
951 v->adjacent_edges()[count[v->id()]++] = &e;
952 }
953 }
954
955 // Faces->adjacent Edges
956 for(unsigned i=0; i<m_faces.size(); ++i)
957 {
958 m_faces[i].adjacent_edges().set_allocation(allocate_pointers(3),3);
959 }
960
961 count.resize(m_faces.size());
962 std::fill(count.begin(), count.end(), 0);
963 for(unsigned i=0; i<m_edges.size(); ++i)
964 {
965 Edge& e = m_edges[i];
966 for(unsigned j=0; j<e.adjacent_faces().size(); ++j)
967 {
968 face_pointer f = e.adjacent_faces()[j];
969 assert(count[f->id()]<3);
970 f->adjacent_edges()[count[f->id()]++] = &e;
971 }
972 }
973
974 //compute angles for the faces
975 for(unsigned i=0; i<m_faces.size(); ++i)
976 {
977 Face& f = m_faces[i];
978 double abc[3];
979 double sum = 0;
980 for(unsigned j=0; j<3; ++j) //compute angle adjacent to the vertex j
981 {
982 for(unsigned k=0; k<3; ++k)
983 {
984 vertex_pointer v = f.adjacent_vertices()[(j + k)%3];
985 abc[k] = f.opposite_edge(v)->length();
986 }
987
988 double angle = angle_from_edges(abc[0], abc[1], abc[2]);
989 assert(angle>1e-5); //algorithm works well with non-degenerate meshes only
990
991 f.corner_angles()[j] = angle;
992 sum += angle;
993 }
994 assert(std::abs(sum - igl::PI) < 1e-5); //algorithm works well with non-degenerate meshes only
995 }
996
997 //define m_turn_around_flag for vertices
998 std::vector<double> total_vertex_angle(m_vertices.size());
999 for(unsigned i=0; i<m_faces.size(); ++i)
1000 {
1001 Face& f = m_faces[i];
1002 for(unsigned j=0; j<3; ++j)
1003 {
1005 total_vertex_angle[v->id()] += f.corner_angles()[j];
1006 }
1007 }
1008
1009 for(unsigned i=0; i<m_vertices.size(); ++i)
1010 {
1011 Vertex& v = m_vertices[i];
1012 v.saddle_or_boundary() = (total_vertex_angle[v.id()] > 2.0*igl::PI - 1e-5);
1013 }
1014
1015 for(unsigned i=0; i<m_edges.size(); ++i)
1016 {
1017 Edge& e = m_edges[i];
1018 if(e.is_boundary())
1019 {
1020 e.adjacent_vertices()[0]->saddle_or_boundary() = true;
1021 e.adjacent_vertices()[1]->saddle_or_boundary() = true;
1022 }
1023 }
1024
1025 assert(verify());
1026}
face_pointer_vector & adjacent_faces()
Definition exact_geodesic.cpp:348
vertex_pointer_vector & adjacent_vertices()
Definition exact_geodesic.cpp:346
std::vector< Vertex > m_vertices
Definition exact_geodesic.cpp:722
bool verify()
Definition exact_geodesic.cpp:1028
std::vector< Edge > m_edges
Definition exact_geodesic.cpp:723
void_pointer allocate_pointers(unsigned n)
Definition exact_geodesic.cpp:717
std::vector< Face > m_faces
Definition exact_geodesic.cpp:724
double angle(const Eigen::MatrixBase< Derived > &v1, const Eigen::MatrixBase< Derived2 > &v2)
Definition Point.hpp:112
constexpr auto size(const C &c) -> decltype(c.size())
Definition span.hpp:183
double angle_from_edges(double const a, double const b, double const c)
Definition exact_geodesic.cpp:53
Face * face_pointer
Definition exact_geodesic.cpp:282
Vertex * vertex_pointer
Definition exact_geodesic.cpp:280
IGL_INLINE void count(const Eigen::SparseMatrix< XType > &X, const int dim, Eigen::SparseVector< SType > &S)
Definition count.cpp:12
const double PI
Definition PI.h:16
IGL_INLINE void sum(const Eigen::SparseMatrix< T > &X, const int dim, Eigen::SparseVector< T > &S)
Definition sum.cpp:12

References igl::geodesic::MeshElementBase::adjacent_edges(), igl::geodesic::MeshElementBase::adjacent_faces(), igl::geodesic::MeshElementBase::adjacent_vertices(), allocate_pointers(), igl::geodesic::angle_from_edges(), igl::geodesic::Face::corner_angles(), igl::count(), igl::geodesic::MeshElementBase::id(), igl::geodesic::Edge::is_boundary(), igl::geodesic::Edge::length(), m_edges, m_faces, m_vertices, igl::geodesic::Face::opposite_edge(), igl::PI, igl::geodesic::Vertex::saddle_or_boundary(), igl::geodesic::SimpleVector< Data >::set_allocation(), igl::geodesic::SimpleVector< Data >::size(), igl::sum(), and verify().

Referenced by initialize_mesh_data().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ closest_vertices()

unsigned igl::geodesic::Mesh::closest_vertices ( SurfacePoint p,
std::vector< vertex_pointer > *  storage = NULL 
)
inline
731{
732 assert(p->type() != UNDEFINED_POINT);
733
734 if(p->type() == VERTEX)
735 {
736 if(storage)
737 {
738 storage->push_back(static_cast<vertex_pointer>(p->base_element()));
739 }
740 return 1;
741 }
742 else if(p->type() == FACE)
743 {
744 if(storage)
745 {
746 vertex_pointer* vp= p->base_element()->adjacent_vertices().begin();
747 storage->push_back(*vp);
748 storage->push_back(*(vp+1));
749 storage->push_back(*(vp+2));
750 }
751 return 2;
752 }
753 else if(p->type() == EDGE) //for edge include all 4 adjacent vertices
754 {
755 edge_pointer edge = static_cast<edge_pointer>(p->base_element());
756
757 if(storage)
758 {
759 storage->push_back(edge->adjacent_vertices()[0]);
760 storage->push_back(edge->adjacent_vertices()[1]);
761
762 for(unsigned i = 0; i < edge->adjacent_faces().size(); ++i)
763 {
764 face_pointer face = edge->adjacent_faces()[i];
765 storage->push_back(face->opposite_vertex(edge));
766 }
767 }
768 return 2 + edge->adjacent_faces().size();
769 }
770
771 assert(0);
772 return 0;
773}
unsigned size()
Definition exact_geodesic.cpp:297
iterator begin()
Definition exact_geodesic.cpp:298
Edge * edge_pointer
Definition exact_geodesic.cpp:281
@ UNDEFINED_POINT
Definition exact_geodesic.cpp:331
@ VERTEX
Definition exact_geodesic.cpp:328
@ FACE
Definition exact_geodesic.cpp:330
@ EDGE
Definition exact_geodesic.cpp:329

References igl::geodesic::MeshElementBase::adjacent_faces(), igl::geodesic::MeshElementBase::adjacent_vertices(), igl::geodesic::SurfacePoint::base_element(), igl::geodesic::SimpleVector< Data >::begin(), igl::geodesic::EDGE, igl::geodesic::FACE, igl::geodesic::Face::opposite_vertex(), igl::geodesic::SimpleVector< Data >::size(), igl::geodesic::SurfacePoint::type(), igl::geodesic::UNDEFINED_POINT, and igl::geodesic::VERTEX.

Referenced by igl::geodesic::GeodesicAlgorithmBase::set_stop_conditions().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ edges()

std::vector< Edge > & igl::geodesic::Mesh::edges ( )
inline
705{return m_edges;};

References m_edges.

Referenced by igl::geodesic::GeodesicAlgorithmExact::GeodesicAlgorithmExact(), and igl::geodesic::fill_surface_point_structure().

+ Here is the caller graph for this function:

◆ faces()

std::vector< Face > & igl::geodesic::Mesh::faces ( )
inline
706{return m_faces;};

References m_faces.

Referenced by igl::exact_geodesic(), and igl::geodesic::fill_surface_point_structure().

+ Here is the caller graph for this function:

◆ initialize_mesh_data() [1/2]

template<class Points , class Faces >
void igl::geodesic::Mesh::initialize_mesh_data ( Points &  p,
Faces &  tri 
)
777{
778 assert(p.size() % 3 == 0);
779 unsigned const num_vertices = p.size() / 3;
780 assert(tri.size() % 3 == 0);
781 unsigned const num_faces = tri.size() / 3;
782
783 initialize_mesh_data(num_vertices, p, num_faces, tri);
784}
void initialize_mesh_data(unsigned num_vertices, Points &p, unsigned num_faces, Faces &tri)
Definition exact_geodesic.cpp:787

References initialize_mesh_data().

+ Here is the call graph for this function:

◆ initialize_mesh_data() [2/2]

template<class Points , class Faces >
void igl::geodesic::Mesh::initialize_mesh_data ( unsigned  num_vertices,
Points &  p,
unsigned  num_faces,
Faces &  tri 
)
791{
792 unsigned const approximate_number_of_internal_pointers = (num_vertices + num_faces)*4;
793 unsigned const max_number_of_pointer_blocks = 100;
794 m_pointer_allocator.reset(approximate_number_of_internal_pointers,
795 max_number_of_pointer_blocks);
796
797 m_vertices.resize(num_vertices);
798 for(unsigned i=0; i<num_vertices; ++i) //copy coordinates to vertices
799 {
800 Vertex& v = m_vertices[i];
801 v.id() = i;
802
803 unsigned shift = 3*i;
804 v.x() = p[shift];
805 v.y() = p[shift + 1];
806 v.z() = p[shift + 2];
807 }
808
809 m_faces.resize(num_faces);
810 for(unsigned i=0; i<num_faces; ++i) //copy adjacent vertices to polygons/faces
811 {
812 Face& f = m_faces[i];
813 f.id() = i;
814 f.adjacent_vertices().set_allocation(allocate_pointers(3),3); //allocate three units of memory
815
816 unsigned shift = 3*i;
817 for(unsigned j=0; j<3; ++j)
818 {
819 unsigned vertex_index = tri[shift + j];
820 assert(vertex_index < num_vertices);
821 f.adjacent_vertices()[j] = &m_vertices[vertex_index];
822 }
823 }
824
825 build_adjacencies(); //build the structure of the mesh
826}
void build_adjacencies()
Definition exact_geodesic.cpp:828
void reset(unsigned block_size, unsigned max_number_of_blocks)
Definition exact_geodesic.cpp:108

References igl::geodesic::MeshElementBase::adjacent_vertices(), allocate_pointers(), build_adjacencies(), igl::geodesic::MeshElementBase::id(), m_faces, m_pointer_allocator, m_vertices, igl::geodesic::SimlpeMemoryAllocator< T >::reset(), igl::geodesic::SimpleVector< Data >::set_allocation(), igl::geodesic::Point3D::x(), igl::geodesic::Point3D::y(), and igl::geodesic::Point3D::z().

Referenced by igl::exact_geodesic(), and initialize_mesh_data().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ verify()

bool igl::geodesic::Mesh::verify ( )
inlineprivate
1029{
1030 std::cout << std::endl;
1031 // make sure that all vertices are mentioned at least once.
1032 // though the loose vertex is not a bug, it most likely indicates that something is wrong with the mesh
1033 std::vector<bool> map(m_vertices.size(), false);
1034 for(unsigned i=0; i<m_edges.size(); ++i)
1035 {
1036 edge_pointer e = &m_edges[i];
1037 map[e->adjacent_vertices()[0]->id()] = true;
1038 map[e->adjacent_vertices()[1]->id()] = true;
1039 }
1040 assert(std::find(map.begin(), map.end(), false) == map.end());
1041
1042 //make sure that the mesh is connected trough its edges
1043 //if mesh has more than one connected component, it is most likely a bug
1044 std::vector<face_pointer> stack(1,&m_faces[0]);
1045 stack.reserve(m_faces.size());
1046
1047 map.resize(m_faces.size());
1048 std::fill(map.begin(), map.end(), false);
1049 map[0] = true;
1050
1051 while(!stack.empty())
1052 {
1053 face_pointer f = stack.back();
1054 stack.pop_back();
1055
1056 for(unsigned i=0; i<3; ++i)
1057 {
1058 edge_pointer e = f->adjacent_edges()[i];
1059 face_pointer f_adjacent = e->opposite_face(f);
1060 if(f_adjacent && !map[f_adjacent->id()])
1061 {
1062 map[f_adjacent->id()] = true;
1063 stack.push_back(f_adjacent);
1064 }
1065 }
1066 }
1067 assert(std::find(map.begin(), map.end(), false) == map.end());
1068
1069 //print some mesh statistics that can be useful in debugging
1070 // std::cout << "mesh has " << m_vertices.size()
1071 // << " vertices, " << m_faces.size()
1072 // << " faces, " << m_edges.size()
1073 // << " edges\n";
1074
1075 unsigned total_boundary_edges = 0;
1076 double longest_edge = 0;
1077 double shortest_edge = 1e100;
1078 for(unsigned i=0; i<m_edges.size(); ++i)
1079 {
1080 Edge& e = m_edges[i];
1081 total_boundary_edges += e.is_boundary() ? 1 : 0;
1082 longest_edge = std::max(longest_edge, e.length());
1083 shortest_edge = std::min(shortest_edge, e.length());
1084 }
1085 // std::cout << total_boundary_edges << " edges are boundary edges\n";
1086 // std::cout << "shortest/longest edges are "
1087 // << shortest_edge << "/"
1088 // << longest_edge << " = "
1089 // << shortest_edge/longest_edge
1090 // << std::endl;
1091
1092 double minx = 1e100;
1093 double maxx = -1e100;
1094 double miny = 1e100;
1095 double maxy = -1e100;
1096 double minz = 1e100;
1097 double maxz = -1e100;
1098 for(unsigned i=0; i<m_vertices.size(); ++i)
1099 {
1100 Vertex& v = m_vertices[i];
1101 minx = std::min(minx, v.x());
1102 maxx = std::max(maxx, v.x());
1103 miny = std::min(miny, v.y());
1104 maxy = std::max(maxy, v.y());
1105 minz = std::min(minz, v.z());
1106 maxz = std::max(maxz, v.z());
1107 }
1108 // std::cout << "enclosing XYZ box:"
1109 // <<" X[" << minx << "," << maxx << "]"
1110 // <<" Y[" << miny << "," << maxy << "]"
1111 // <<" Z[" << minz << "," << maxz << "]"
1112 // << std::endl;
1113
1114 double dx = maxx - minx;
1115 double dy = maxy - miny;
1116 double dz = maxz - minz;
1117 // std::cout << "approximate diameter of the mesh is "
1118 // << sqrt(dx*dx + dy*dy + dz*dz)
1119 // << std::endl;
1120
1121 double min_angle = 1e100;
1122 double max_angle = -1e100;
1123 for(unsigned i=0; i<m_faces.size(); ++i)
1124 {
1125 Face& f = m_faces[i];
1126 for(unsigned j=0; j<3; ++j)
1127 {
1128 double angle = f.corner_angles()[j];
1129 min_angle = std::min(min_angle, angle);
1130 max_angle = std::max(max_angle, angle);
1131 }
1132 }
1133 // std::cout << "min/max face angles are "
1134 // << min_angle/igl::PI*180.0 << "/"
1135 // << max_angle/igl::PI*180.0
1136 // << " degrees\n";
1137
1138 // std::cout << std::endl;
1139 return true;
1140}
edge_pointer_vector & adjacent_edges()
Definition exact_geodesic.cpp:347

References igl::geodesic::MeshElementBase::adjacent_edges(), igl::geodesic::MeshElementBase::adjacent_vertices(), igl::geodesic::Face::corner_angles(), igl::geodesic::MeshElementBase::id(), igl::geodesic::Edge::is_boundary(), igl::geodesic::Edge::length(), m_edges, m_faces, m_vertices, igl::geodesic::Edge::opposite_face(), igl::geodesic::Point3D::x(), igl::geodesic::Point3D::y(), and igl::geodesic::Point3D::z().

Referenced by build_adjacencies().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ vertices()

std::vector< Vertex > & igl::geodesic::Mesh::vertices ( )
inline
704{return m_vertices;};

References m_vertices.

Referenced by igl::exact_geodesic(), and igl::geodesic::fill_surface_point_structure().

+ Here is the caller graph for this function:

Member Data Documentation

◆ m_edges

std::vector<Edge> igl::geodesic::Mesh::m_edges
private

Referenced by build_adjacencies(), edges(), and verify().

◆ m_faces

std::vector<Face> igl::geodesic::Mesh::m_faces
private

◆ m_pointer_allocator

SimlpeMemoryAllocator<void_pointer> igl::geodesic::Mesh::m_pointer_allocator
private

◆ m_vertices

std::vector<Vertex> igl::geodesic::Mesh::m_vertices
private

The documentation for this class was generated from the following file: