Free Electron
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
geodesic_cpp_03_02_2008/geodesic_mesh.h
1 //Copyright (C) 2008 Danil Kirsanov, MIT License
2 #ifndef GEODESIC_MESH_20071231
3 #define GEODESIC_MESH_20071231
4 
5 #include <cstddef>
6 #include <vector>
7 #include <cmath>
8 #include <iostream>
9 #include <algorithm>
10 #include <fstream>
11 
12 #include "geodesic_mesh_elements.h"
13 #include "geodesic_memory.h"
14 #include "geodesic_constants_and_simple_functions.h"
15 
16 namespace geodesic{
17 
18 struct edge_visible_from_source
19 {
20  unsigned source;
21  edge_pointer edge;
22 };
23 
24 class Mesh
25 {
26 public:
27  Mesh()
28  {};
29 
30  ~Mesh(){};
31 
32  template<class Points, class Faces>
33  void initialize_mesh_data(unsigned num_vertices,
34  Points& p,
35  unsigned num_faces,
36  Faces& tri); //build mesh from regular point-triangle representation
37 
38  template<class Points, class Faces>
39  void initialize_mesh_data(Points& p, Faces& tri); //build mesh from regular point-triangle representation
40 
41  std::vector<Vertex>& vertices(){return m_vertices;};
42  std::vector<Edge>& edges(){return m_edges;};
43  std::vector<Face>& faces(){return m_faces;};
44 
45  unsigned closest_vertices(SurfacePoint* p,
46  std::vector<vertex_pointer>* storage = NULL); //list vertices closest to the point
47 
48 private:
49 
50  void build_adjacencies(); //build internal structure of the mesh
51  bool verify(); //verifies connectivity of the mesh and prints some debug info
52 
53  typedef void* void_pointer;
54  void_pointer allocate_pointers(unsigned n)
55  {
56  return m_pointer_allocator.allocate(n);
57  }
58 
59  std::vector<Vertex> m_vertices;
60  std::vector<Edge> m_edges;
61  std::vector<Face> m_faces;
62 
63  SimlpeMemoryAllocator<void_pointer> m_pointer_allocator; //fast memory allocating for Face/Vertex/Edge cross-references
64 };
65 
66 inline unsigned Mesh::closest_vertices(SurfacePoint* p,
67  std::vector<vertex_pointer>* storage)
68 {
69  assert(p->type() != UNDEFINED_POINT);
70 
71  if(p->type() == VERTEX)
72  {
73  if(storage)
74  {
75  storage->push_back(static_cast<vertex_pointer>(p->base_element()));
76  }
77  return 1;
78  }
79  else if(p->type() == FACE)
80  {
81  if(storage)
82  {
83  vertex_pointer* vp= p->base_element()->adjacent_vertices().begin();
84  storage->push_back(*vp);
85  storage->push_back(*(vp+1));
86  storage->push_back(*(vp+2));
87  }
88  return 2;
89  }
90  else if(p->type() == EDGE) //for edge include all 4 adjacent vertices
91  {
92  edge_pointer edge = static_cast<edge_pointer>(p->base_element());
93 
94  if(storage)
95  {
96  storage->push_back(edge->adjacent_vertices()[0]);
97  storage->push_back(edge->adjacent_vertices()[1]);
98 
99  for(unsigned i = 0; i < edge->adjacent_faces().size(); ++i)
100  {
101  face_pointer face = edge->adjacent_faces()[i];
102  storage->push_back(face->opposite_vertex(edge));
103  }
104  }
105  return 2 + edge->adjacent_faces().size();
106  }
107 
108  assert(0);
109  return 0;
110 }
111 
112 template<class Points, class Faces>
113 void Mesh::initialize_mesh_data(Points& p, Faces& tri) //build mesh from regular point-triangle representation
114 {
115  assert(p.size() % 3 == 0);
116  unsigned const num_vertices = p.size() / 3;
117  assert(tri.size() % 3 == 0);
118  unsigned const num_faces = tri.size() / 3;
119 
120  initialize_mesh_data(num_vertices, p, num_faces, tri);
121 }
122 
123 template<class Points, class Faces>
124 void Mesh::initialize_mesh_data(unsigned num_vertices,
125  Points& p,
126  unsigned num_faces,
127  Faces& tri)
128 {
129  unsigned const approximate_number_of_internal_pointers = (num_vertices + num_faces)*4;
130  unsigned const max_number_of_pointer_blocks = 100;
131  m_pointer_allocator.reset(approximate_number_of_internal_pointers,
132  max_number_of_pointer_blocks);
133 
134  m_vertices.resize(num_vertices);
135  for(unsigned i=0; i<num_vertices; ++i) //copy coordinates to vertices
136  {
137  Vertex& v = m_vertices[i];
138  v.id() = i;
139 
140  unsigned shift = 3*i;
141  v.x() = p[shift];
142  v.y() = p[shift + 1];
143  v.z() = p[shift + 2];
144  }
145 
146  m_faces.resize(num_faces);
147  for(unsigned i=0; i<num_faces; ++i) //copy adjacent vertices to polygons/faces
148  {
149  Face& f = m_faces[i];
150  f.id() = i;
151  f.adjacent_vertices().set_allocation(allocate_pointers(3),3); //allocate three units of memory
152 
153  unsigned shift = 3*i;
154  for(unsigned j=0; j<3; ++j)
155  {
156  unsigned vertex_index = tri[shift + j];
157  assert(vertex_index < num_vertices);
158  f.adjacent_vertices()[j] = &m_vertices[vertex_index];
159  }
160  }
161 
162  build_adjacencies(); //build the structure of the mesh
163 }
164 
165 inline void Mesh::build_adjacencies()
166 {
167  // Vertex->adjacent Faces
168  std::vector<unsigned> count(m_vertices.size()); //count adjacent vertices
169  for(unsigned i=0; i<m_faces.size(); ++i)
170  {
171  Face& f = m_faces[i];
172  for(unsigned j=0; j<3; ++j)
173  {
174  unsigned vertex_id = f.adjacent_vertices()[j]->id();
175  assert(vertex_id < m_vertices.size());
176  count[vertex_id]++;
177  }
178  }
179 
180  for(unsigned i=0; i<m_vertices.size(); ++i) //reserve space
181  {
182  Vertex& v = m_vertices[i];
183  unsigned num_adjacent_faces = count[i];
184 
185  v.adjacent_faces().set_allocation(allocate_pointers(num_adjacent_faces), //allocate three units of memory
186  num_adjacent_faces);
187  }
188 
189  std::fill(count.begin(), count.end(), 0);
190  for(unsigned i=0; i<m_faces.size(); ++i)
191  {
192  Face& f = m_faces[i];
193  for(unsigned j=0; j<3; ++j)
194  {
195  vertex_pointer v = f.adjacent_vertices()[j];
196  v->adjacent_faces()[count[v->id()]++] = &f;
197  }
198  }
199 
200  //find all edges
201  //i.e. find all half-edges, sort and combine them into edges
202  std::vector<HalfEdge> half_edges(m_faces.size()*3);
203  unsigned k = 0;
204  for(unsigned i=0; i<m_faces.size(); ++i)
205  {
206  Face& f = m_faces[i];
207  for(unsigned j=0; j<3; ++j)
208  {
209  half_edges[k].face_id = i;
210  unsigned vertex_id_1 = f.adjacent_vertices()[j]->id();
211  unsigned vertex_id_2 = f.adjacent_vertices()[(j+1) % 3]->id();
212  half_edges[k].vertex_0 = std::min(vertex_id_1, vertex_id_2);
213  half_edges[k].vertex_1 = std::max(vertex_id_1, vertex_id_2);
214 
215  k++;
216  }
217  }
218  std::sort(half_edges.begin(), half_edges.end());
219 
220  unsigned number_of_edges = 1;
221  for(unsigned i=1; i<half_edges.size(); ++i)
222  {
223  if(half_edges[i] != half_edges[i-1])
224  {
225  ++number_of_edges;
226  }
227  else
228  {
229  if(i<half_edges.size()-1) //sanity check: there should be at most two equal half-edges
230  { //if it fails, most likely the input data are messed up
231  assert(half_edges[i] != half_edges[i+1]);
232  }
233  }
234  }
235 
236  // Edges->adjacent Vertices and Faces
237  m_edges.resize(number_of_edges);
238  unsigned edge_id = 0;
239  for(unsigned i=0; i<half_edges.size();)
240  {
241  Edge& e = m_edges[edge_id];
242  e.id() = edge_id++;
243 
244  e.adjacent_vertices().set_allocation(allocate_pointers(2),2); //allocate two units of memory
245 
246  e.adjacent_vertices()[0] = &m_vertices[half_edges[i].vertex_0];
247  e.adjacent_vertices()[1] = &m_vertices[half_edges[i].vertex_1];
248 
249  e.length() = e.adjacent_vertices()[0]->distance(e.adjacent_vertices()[1]);
250  assert(e.length() > 1e-100); //algorithm works well with non-degenerate meshes only
251 
252  if(i != half_edges.size()-1 && half_edges[i] == half_edges[i+1]) //double edge
253  {
254  e.adjacent_faces().set_allocation(allocate_pointers(2),2);
255  e.adjacent_faces()[0] = &m_faces[half_edges[i].face_id];
256  e.adjacent_faces()[1] = &m_faces[half_edges[i+1].face_id];
257  i += 2;
258  }
259  else //single edge
260  {
261  e.adjacent_faces().set_allocation(allocate_pointers(1),1); //one adjucent faces
262  e.adjacent_faces()[0] = &m_faces[half_edges[i].face_id];
263  i += 1;
264  }
265  }
266 
267  // Vertices->adjacent Edges
268  std::fill(count.begin(), count.end(), 0);
269  for(unsigned i=0; i<m_edges.size(); ++i)
270  {
271  Edge& e = m_edges[i];
272  assert(e.adjacent_vertices().size()==2);
273  count[e.adjacent_vertices()[0]->id()]++;
274  count[e.adjacent_vertices()[1]->id()]++;
275  }
276  for(unsigned i=0; i<m_vertices.size(); ++i)
277  {
278  m_vertices[i].adjacent_edges().set_allocation(allocate_pointers(count[i]),
279  count[i]);
280  }
281  std::fill(count.begin(), count.end(), 0);
282  for(unsigned i=0; i<m_edges.size(); ++i)
283  {
284  Edge& e = m_edges[i];
285  for(unsigned j=0; j<2; ++j)
286  {
287  vertex_pointer v = e.adjacent_vertices()[j];
288  v->adjacent_edges()[count[v->id()]++] = &e;
289  }
290  }
291 
292  // Faces->adjacent Edges
293  for(unsigned i=0; i<m_faces.size(); ++i)
294  {
295  m_faces[i].adjacent_edges().set_allocation(allocate_pointers(3),3);
296  }
297 
298  count.resize(m_faces.size());
299  std::fill(count.begin(), count.end(), 0);
300  for(unsigned i=0; i<m_edges.size(); ++i)
301  {
302  Edge& e = m_edges[i];
303  for(unsigned j=0; j<e.adjacent_faces().size(); ++j)
304  {
305  face_pointer f = e.adjacent_faces()[j];
306  assert(count[f->id()]<3);
307  f->adjacent_edges()[count[f->id()]++] = &e;
308  }
309  }
310 
311  //compute angles for the faces
312  for(unsigned i=0; i<m_faces.size(); ++i)
313  {
314  Face& f = m_faces[i];
315  double abc[3];
316  double sum = 0;
317  for(unsigned j=0; j<3; ++j) //compute angle adjacent to the vertex j
318  {
319  for(unsigned k=0; k<3; ++k)
320  {
321  vertex_pointer v = f.adjacent_vertices()[(j + k)%3];
322  abc[k] = f.opposite_edge(v)->length();
323  }
324 
325  double angle = angle_from_edges(abc[0], abc[1], abc[2]);
326  assert(angle>1e-5); //algorithm works well with non-degenerate meshes only
327 
328  f.corner_angles()[j] = angle;
329  sum += angle;
330  }
331  assert(std::abs(sum - M_PI) < 1e-5); //algorithm works well with non-degenerate meshes only
332  }
333 
334  //define m_turn_around_flag for vertices
335  std::vector<double> total_vertex_angle(m_vertices.size());
336  for(unsigned i=0; i<m_faces.size(); ++i)
337  {
338  Face& f = m_faces[i];
339  for(unsigned j=0; j<3; ++j)
340  {
341  vertex_pointer v = f.adjacent_vertices()[j];
342  total_vertex_angle[v->id()] += f.corner_angles()[j];
343  }
344  }
345 
346  for(unsigned i=0; i<m_vertices.size(); ++i)
347  {
348  Vertex& v = m_vertices[i];
349  v.saddle_or_boundary() = (total_vertex_angle[v.id()] > 2.0*M_PI - 1e-5);
350  }
351 
352  for(unsigned i=0; i<m_edges.size(); ++i)
353  {
354  Edge& e = m_edges[i];
355  if(e.is_boundary())
356  {
357  e.adjacent_vertices()[0]->saddle_or_boundary() = true;
358  e.adjacent_vertices()[1]->saddle_or_boundary() = true;
359  }
360  }
361 
362  assert(verify());
363 }
364 
365 inline bool Mesh::verify() //verifies connectivity of the mesh and prints some debug info
366 {
367  std::cout << std::endl;
368  // make sure that all vertices are mentioned at least once.
369  // though the loose vertex is not a bug, it most likely indicates that something is wrong with the mesh
370  std::vector<bool> map(m_vertices.size(), false);
371  for(unsigned i=0; i<m_edges.size(); ++i)
372  {
373  edge_pointer e = &m_edges[i];
374  map[e->adjacent_vertices()[0]->id()] = true;
375  map[e->adjacent_vertices()[1]->id()] = true;
376  }
377  assert(std::find(map.begin(), map.end(), false) == map.end());
378 
379  //make sure that the mesh is connected trough its edges
380  //if mesh has more than one connected component, it is most likely a bug
381  std::vector<face_pointer> stack(1,&m_faces[0]);
382  stack.reserve(m_faces.size());
383 
384  map.resize(m_faces.size());
385  std::fill(map.begin(), map.end(), false);
386  map[0] = true;
387 
388  while(!stack.empty())
389  {
390  face_pointer f = stack.back();
391  stack.pop_back();
392 
393  for(unsigned i=0; i<3; ++i)
394  {
395  edge_pointer e = f->adjacent_edges()[i];
396  face_pointer f_adjacent = e->opposite_face(f);
397  if(f_adjacent && !map[f_adjacent->id()])
398  {
399  map[f_adjacent->id()] = true;
400  stack.push_back(f_adjacent);
401  }
402  }
403  }
404  assert(std::find(map.begin(), map.end(), false) == map.end());
405 
406  //print some mesh statistics that can be useful in debugging
407  std::cout << "mesh has " << m_vertices.size()
408  << " vertices, " << m_faces.size()
409  << " faces, " << m_edges.size()
410  << " edges\n";
411 
412  unsigned total_boundary_edges = 0;
413  double longest_edge = 0;
414  double shortest_edge = 1e100;
415  for(unsigned i=0; i<m_edges.size(); ++i)
416  {
417  Edge& e = m_edges[i];
418  total_boundary_edges += e.is_boundary() ? 1 : 0;
419  longest_edge = std::max(longest_edge, e.length());
420  shortest_edge = std::min(shortest_edge, e.length());
421  }
422  std::cout << total_boundary_edges << " edges are boundary edges\n";
423  std::cout << "shortest/longest edges are "
424  << shortest_edge << "/"
425  << longest_edge << " = "
426  << shortest_edge/longest_edge
427  << std::endl;
428 
429  double minx = 1e100;
430  double maxx = -1e100;
431  double miny = 1e100;
432  double maxy = -1e100;
433  double minz = 1e100;
434  double maxz = -1e100;
435  for(unsigned i=0; i<m_vertices.size(); ++i)
436  {
437  Vertex& v = m_vertices[i];
438  minx = std::min(minx, v.x());
439  maxx = std::max(maxx, v.x());
440  miny = std::min(miny, v.y());
441  maxy = std::max(maxy, v.y());
442  minz = std::min(minz, v.z());
443  maxz = std::max(maxz, v.z());
444  }
445  std::cout << "enclosing XYZ box:"
446  <<" X[" << minx << "," << maxx << "]"
447  <<" Y[" << miny << "," << maxy << "]"
448  <<" Z[" << minz << "," << maxz << "]"
449  << std::endl;
450 
451  double dx = maxx - minx;
452  double dy = maxy - miny;
453  double dz = maxz - minz;
454  std::cout << "approximate diameter of the mesh is "
455  << sqrt(dx*dx + dy*dy + dz*dz)
456  << std::endl;
457 
458  double min_angle = 1e100;
459  double max_angle = -1e100;
460  for(unsigned i=0; i<m_faces.size(); ++i)
461  {
462  Face& f = m_faces[i];
463  for(unsigned j=0; j<3; ++j)
464  {
465  double angle = f.corner_angles()[j];
466  min_angle = std::min(min_angle, angle);
467  max_angle = std::max(max_angle, angle);
468  }
469  }
470  std::cout << "min/max face angles are "
471  << min_angle/M_PI*180.0 << "/"
472  << max_angle/M_PI*180.0
473  << " degrees\n";
474 
475  std::cout << std::endl;
476  return true;
477 }
478 
479 inline void fill_surface_point_structure(geodesic::SurfacePoint* point,
480  double* data,
481  Mesh* mesh)
482 {
483  point->set(data);
484  unsigned type = (unsigned) data[3];
485  unsigned id = (unsigned) data[4];
486 
487 
488  if(type == 0) //vertex
489  {
490  point->base_element() = &mesh->vertices()[id];
491  }
492  else if(type == 1) //edge
493  {
494  point->base_element() = &mesh->edges()[id];
495  }
496  else //face
497  {
498  point->base_element() = &mesh->faces()[id];
499  }
500 }
501 
502 inline void fill_surface_point_double(geodesic::SurfacePoint* point,
503  double* data,
504  long mesh_id)
505 {
506  data[0] = point->x();
507  data[1] = point->y();
508  data[2] = point->z();
509  data[4] = point->base_element()->id();
510 
511  if(point->type() == VERTEX) //vertex
512  {
513  data[3] = 0;
514  }
515  else if(point->type() == EDGE) //edge
516  {
517  data[3] = 1;
518  }
519  else //face
520  {
521  data[3] = 2;
522  }
523 }
524 
525 } //geodesic
526 
527 #endif
Definition: geodesic_cpp_03_02_2008/geodesic_algorithm_base.h:11