Loading [MathJax]/extensions/tex2jax.js
Free Electron
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
geodesic_cpp_mod/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  FEASSERT(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  FEASSERT(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  FEASSERT(p.size() % 3 == 0);
116  unsigned const num_vertices = p.size() / 3;
117  FEASSERT(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  FEASSERT(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  FEASSERT(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 // FEASSERT(half_edges[i] != half_edges[i+1]);
232  if(half_edges[i] == half_edges[i+1])
233  {
234  feX("::geodesic::Mesh::build_adjacencies",
235  "duplicate half edge");
236  }
237  }
238  }
239  }
240 
241  // Edges->adjacent Vertices and Faces
242  m_edges.resize(number_of_edges);
243  unsigned edge_id = 0;
244  for(unsigned i=0; i<half_edges.size();)
245  {
246  Edge& e = m_edges[edge_id];
247  e.id() = edge_id++;
248 
249  e.adjacent_vertices().set_allocation(allocate_pointers(2),2); //allocate two units of memory
250 
251  e.adjacent_vertices()[0] = &m_vertices[half_edges[i].vertex_0];
252  e.adjacent_vertices()[1] = &m_vertices[half_edges[i].vertex_1];
253 
254  e.length() = e.adjacent_vertices()[0]->distance(e.adjacent_vertices()[1]);
255  FEASSERT(e.length() > 1e-100); //algorithm works well with non-degenerate meshes only
256 
257  if(i != half_edges.size()-1 && half_edges[i] == half_edges[i+1]) //double edge
258  {
259  e.adjacent_faces().set_allocation(allocate_pointers(2),2);
260  e.adjacent_faces()[0] = &m_faces[half_edges[i].face_id];
261  e.adjacent_faces()[1] = &m_faces[half_edges[i+1].face_id];
262  i += 2;
263  }
264  else //single edge
265  {
266  e.adjacent_faces().set_allocation(allocate_pointers(1),1); //one adjucent faces
267  e.adjacent_faces()[0] = &m_faces[half_edges[i].face_id];
268  i += 1;
269  }
270  }
271 
272  // Vertices->adjacent Edges
273  std::fill(count.begin(), count.end(), 0);
274  for(unsigned i=0; i<m_edges.size(); ++i)
275  {
276  Edge& e = m_edges[i];
277  FEASSERT(e.adjacent_vertices().size()==2);
278  count[e.adjacent_vertices()[0]->id()]++;
279  count[e.adjacent_vertices()[1]->id()]++;
280  }
281  for(unsigned i=0; i<m_vertices.size(); ++i)
282  {
283  m_vertices[i].adjacent_edges().set_allocation(allocate_pointers(count[i]),
284  count[i]);
285  }
286  std::fill(count.begin(), count.end(), 0);
287  for(unsigned i=0; i<m_edges.size(); ++i)
288  {
289  Edge& e = m_edges[i];
290  for(unsigned j=0; j<2; ++j)
291  {
292  vertex_pointer v = e.adjacent_vertices()[j];
293  v->adjacent_edges()[count[v->id()]++] = &e;
294  }
295  }
296 
297  // Faces->adjacent Edges
298  for(unsigned i=0; i<m_faces.size(); ++i)
299  {
300  m_faces[i].adjacent_edges().set_allocation(allocate_pointers(3),3);
301  }
302 
303  count.resize(m_faces.size());
304  std::fill(count.begin(), count.end(), 0);
305  for(unsigned i=0; i<m_edges.size(); ++i)
306  {
307  Edge& e = m_edges[i];
308  for(unsigned j=0; j<e.adjacent_faces().size(); ++j)
309  {
310  face_pointer f = e.adjacent_faces()[j];
311  FEASSERT(count[f->id()]<3);
312  f->adjacent_edges()[count[f->id()]++] = &e;
313  }
314  }
315 
316  //compute angles for the faces
317  for(unsigned i=0; i<m_faces.size(); ++i)
318  {
319  Face& f = m_faces[i];
320  double abc[3];
321  double sum = 0;
322  for(unsigned j=0; j<3; ++j) //compute angle adjacent to the vertex j
323  {
324  for(unsigned k=0; k<3; ++k)
325  {
326  vertex_pointer v = f.adjacent_vertices()[(j + k)%3];
327  abc[k] = f.opposite_edge(v)->length();
328  }
329 
330  double angle = angle_from_edges(abc[0], abc[1], abc[2]);
331  FEASSERT(angle>1e-5); //algorithm works well with non-degenerate meshes only
332 
333  f.corner_angles()[j] = angle;
334  sum += angle;
335  }
336  FEASSERT(std::abs(sum - M_PI) < 1e-5); //algorithm works well with non-degenerate meshes only
337  }
338 
339  //define m_turn_around_flag for vertices
340  std::vector<double> total_vertex_angle(m_vertices.size());
341  for(unsigned i=0; i<m_faces.size(); ++i)
342  {
343  Face& f = m_faces[i];
344  for(unsigned j=0; j<3; ++j)
345  {
346  vertex_pointer v = f.adjacent_vertices()[j];
347  total_vertex_angle[v->id()] += f.corner_angles()[j];
348  }
349  }
350 
351  for(unsigned i=0; i<m_vertices.size(); ++i)
352  {
353  Vertex& v = m_vertices[i];
354  v.saddle_or_boundary() = (total_vertex_angle[v.id()] > 2.0*M_PI - 1e-5);
355  }
356 
357  for(unsigned i=0; i<m_edges.size(); ++i)
358  {
359  Edge& e = m_edges[i];
360  if(e.is_boundary())
361  {
362  e.adjacent_vertices()[0]->saddle_or_boundary() = true;
363  e.adjacent_vertices()[1]->saddle_or_boundary() = true;
364  }
365  }
366 
367 #if FE_CODEGEN<=FE_DEBUG
368  FEASSERT(verify());
369 #endif
370 }
371 
372 inline bool Mesh::verify() //verifies connectivity of the mesh and prints some debug info
373 {
374  std::cout << std::endl;
375  // make sure that all vertices are mentioned at least once.
376  // though the loose vertex is not a bug, it most likely indicates that something is wrong with the mesh
377  std::vector<bool> map(m_vertices.size(), false);
378  for(unsigned i=0; i<m_edges.size(); ++i)
379  {
380  edge_pointer e = &m_edges[i];
381  map[e->adjacent_vertices()[0]->id()] = true;
382  map[e->adjacent_vertices()[1]->id()] = true;
383  }
384  FEASSERT(std::find(map.begin(), map.end(), false) == map.end());
385 
386  //make sure that the mesh is connected trough its edges
387  //if mesh has more than one connected component, it is most likely a bug
388  std::vector<face_pointer> stack(1,&m_faces[0]);
389  stack.reserve(m_faces.size());
390 
391  map.resize(m_faces.size());
392  std::fill(map.begin(), map.end(), false);
393  map[0] = true;
394 
395  while(!stack.empty())
396  {
397  face_pointer f = stack.back();
398  stack.pop_back();
399 
400  for(unsigned i=0; i<3; ++i)
401  {
402  edge_pointer e = f->adjacent_edges()[i];
403  face_pointer f_adjacent = e->opposite_face(f);
404  if(f_adjacent && !map[f_adjacent->id()])
405  {
406  map[f_adjacent->id()] = true;
407  stack.push_back(f_adjacent);
408  }
409  }
410  }
411 
412 // FEASSERT(std::find(map.begin(), map.end(), false) == map.end());
413 // if(std::find(map.begin(), map.end(), false) != map.end());
414 // {
415 // feX("::geodesic::Mesh::verify","open edge?");
416 // }
417 
418  //print some mesh statistics that can be useful in debugging
419  std::cout << "::geodesic::Mesh::verify()\n";
420 
421  std::cout << "mesh has " << m_vertices.size()
422  << " vertices, " << m_faces.size()
423  << " faces, " << m_edges.size()
424  << " edges\n";
425 
426  unsigned total_boundary_edges = 0;
427  double longest_edge = 0;
428  double shortest_edge = 1e100;
429  for(unsigned i=0; i<m_edges.size(); ++i)
430  {
431  Edge& e = m_edges[i];
432  total_boundary_edges += e.is_boundary() ? 1 : 0;
433  longest_edge = std::max(longest_edge, e.length());
434  shortest_edge = std::min(shortest_edge, e.length());
435  }
436  std::cout << total_boundary_edges << " edges are boundary edges\n";
437  std::cout << "shortest/longest edges are "
438  << shortest_edge << "/"
439  << longest_edge << " = "
440  << shortest_edge/longest_edge
441  << std::endl;
442 
443  double minx = 1e100;
444  double maxx = -1e100;
445  double miny = 1e100;
446  double maxy = -1e100;
447  double minz = 1e100;
448  double maxz = -1e100;
449  for(unsigned i=0; i<m_vertices.size(); ++i)
450  {
451  Vertex& v = m_vertices[i];
452  minx = std::min(minx, v.x());
453  maxx = std::max(maxx, v.x());
454  miny = std::min(miny, v.y());
455  maxy = std::max(maxy, v.y());
456  minz = std::min(minz, v.z());
457  maxz = std::max(maxz, v.z());
458  }
459  std::cout << "enclosing XYZ box:"
460  <<" X[" << minx << "," << maxx << "]"
461  <<" Y[" << miny << "," << maxy << "]"
462  <<" Z[" << minz << "," << maxz << "]"
463  << std::endl;
464 
465  double dx = maxx - minx;
466  double dy = maxy - miny;
467  double dz = maxz - minz;
468  std::cout << "approximate diameter of the mesh is "
469  << sqrt(dx*dx + dy*dy + dz*dz)
470  << std::endl;
471 
472  double min_angle = 1e100;
473  double max_angle = -1e100;
474  for(unsigned i=0; i<m_faces.size(); ++i)
475  {
476  Face& f = m_faces[i];
477  for(unsigned j=0; j<3; ++j)
478  {
479  double angle = f.corner_angles()[j];
480  min_angle = std::min(min_angle, angle);
481  max_angle = std::max(max_angle, angle);
482  }
483  }
484  std::cout << "min/max face angles are "
485  << min_angle/M_PI*180.0 << "/"
486  << max_angle/M_PI*180.0
487  << " degrees\n";
488 
489  std::cout << std::endl;
490  return true;
491 }
492 
493 inline void fill_surface_point_structure(geodesic::SurfacePoint* point,
494  double* data,
495  Mesh* mesh)
496 {
497  point->set(data);
498  unsigned type = (unsigned) data[3];
499  unsigned id = (unsigned) data[4];
500 
501 
502  if(type == 0) //vertex
503  {
504  point->base_element() = &mesh->vertices()[id];
505  }
506  else if(type == 1) //edge
507  {
508  point->base_element() = &mesh->edges()[id];
509  }
510  else //face
511  {
512  point->base_element() = &mesh->faces()[id];
513  }
514 }
515 
516 inline void fill_surface_point_double(geodesic::SurfacePoint* point,
517  double* data,
518  long mesh_id)
519 {
520  data[0] = point->x();
521  data[1] = point->y();
522  data[2] = point->z();
523  data[4] = point->base_element()->id();
524 
525  if(point->type() == VERTEX) //vertex
526  {
527  data[3] = 0;
528  }
529  else if(point->type() == EDGE) //edge
530  {
531  data[3] = 1;
532  }
533  else //face
534  {
535  data[3] = 2;
536  }
537 }
538 
539 } //geodesic
540 
541 #endif
Definition: geodesic_cpp_03_02_2008/geodesic_algorithm_base.h:11