Loading [MathJax]/extensions/tex2jax.js
Free Electron
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
geodesic_cpp_03_02_2008/geodesic_algorithm_exact.h
1 //Copyright (C) 2008 Danil Kirsanov, MIT License
2 #ifndef GEODESIC_ALGORITHM_EXACT_20071231
3 #define GEODESIC_ALGORITHM_EXACT_20071231
4 
5 #include "geodesic_memory.h"
6 #include "geodesic_algorithm_base.h"
7 #include "geodesic_algorithm_exact_elements.h"
8 #include <vector>
9 #include <cmath>
10 #include <assert.h>
11 #include <set>
12 
13 namespace geodesic{
14 
15 class GeodesicAlgorithmExact : public GeodesicAlgorithmBase
16 {
17 public:
18  GeodesicAlgorithmExact(geodesic::Mesh* mesh):
19  GeodesicAlgorithmBase(mesh),
20  m_memory_allocator(mesh->edges().size(), mesh->edges().size()),
21  m_edge_interval_lists(mesh->edges().size())
22  {
23  m_type = EXACT;
24 
25  for(unsigned i=0; i<m_edge_interval_lists.size(); ++i)
26  {
27  m_edge_interval_lists[i].initialize(&mesh->edges()[i]);
28  }
29  };
30 
31  ~GeodesicAlgorithmExact(){};
32 
33  void propagate(std::vector<SurfacePoint>& sources,
34  double max_propagation_distance = GEODESIC_INF, //propagation algorithm stops after reaching the certain distance from the source
35  std::vector<SurfacePoint>* stop_points = NULL); //or after ensuring that all the stop_points are covered
36 
37  void trace_back(SurfacePoint& destination, //trace back piecewise-linear path
38  std::vector<SurfacePoint>& path);
39 
40  unsigned best_source(SurfacePoint& point, //quickly find what source this point belongs to and what is the distance to this source
41  double& best_source_distance);
42 
43  void print_statistics();
44 
45 private:
46  typedef std::set<interval_pointer, Interval> IntervalQueue;
47 
48  void update_list_and_queue(list_pointer list,
49  IntervalWithStop* candidates, //up to two candidates
50  unsigned num_candidates);
51 
52  unsigned compute_propagated_parameters(double pseudo_x,
53  double pseudo_y,
54  double d, //parameters of the interval
55  double start,
56  double end, //start/end of the interval
57  double alpha, //corner angle
58  double L, //length of the new edge
59  bool first_interval, //if it is the first interval on the edge
60  bool last_interval,
61  bool turn_left,
62  bool turn_right,
63  IntervalWithStop* candidates); //if it is the last interval on the edge
64 
65  void construct_propagated_intervals(bool invert,
66  edge_pointer edge,
67  face_pointer face, //constructs iNew from the rest of the data
68  IntervalWithStop* candidates,
69  unsigned& num_candidates,
70  interval_pointer source_interval);
71 
72  double compute_positive_intersection(double start,
73  double pseudo_x,
74  double pseudo_y,
75  double sin_alpha,
76  double cos_alpha); //used in construct_propagated_intervals
77 
78  unsigned intersect_intervals(interval_pointer zero,
79  IntervalWithStop* one); //intersecting two intervals with up to three intervals in the end
80 
81  interval_pointer best_first_interval(SurfacePoint& point,
82  double& best_total_distance,
83  double& best_interval_position,
84  unsigned& best_source_index);
85 
86  bool check_stop_conditions(unsigned& index);
87 
88  void clear()
89  {
90  m_memory_allocator.clear();
91  m_queue.clear();
92  for(unsigned i=0; i<m_edge_interval_lists.size(); ++i)
93  {
94  m_edge_interval_lists[i].clear();
95  }
96  m_propagation_distance_stopped = GEODESIC_INF;
97  };
98 
99  list_pointer interval_list(edge_pointer e)
100  {
101  return &m_edge_interval_lists[e->id()];
102  };
103 
104  void set_sources(std::vector<SurfacePoint>& sources)
105  {
106  m_sources.initialize(sources);
107  }
108 
109  void initialize_propagation_data();
110 
111  void list_edges_visible_from_source(MeshElementBase* p,
112  std::vector<edge_pointer>& storage); //used in initialization
113 
114  long visible_from_source(SurfacePoint& point); //used in backtracing
115 
116  void best_point_on_the_edge_set(SurfacePoint& point,
117  std::vector<edge_pointer> const& storage,
118  interval_pointer& best_interval,
119  double& best_total_distance,
120  double& best_interval_position);
121 
122  void possible_traceback_edges(SurfacePoint& point,
123  std::vector<edge_pointer>& storage);
124 
125  bool erase_from_queue(interval_pointer p);
126 
127  IntervalQueue m_queue; //interval queue
128 
129  MemoryAllocator<Interval> m_memory_allocator; //quickly allocate and deallocate intervals
130  std::vector<IntervalList> m_edge_interval_lists; //every edge has its interval data
131 
132  enum MapType {OLD, NEW}; //used for interval intersection
133  MapType map[5];
134  double start[6];
135  interval_pointer i_new[5];
136 
137  unsigned m_queue_max_size; //used for statistics
138  unsigned m_iterations; //used for statistics
139 
140  SortedSources m_sources;
141 };
142 
143 inline void GeodesicAlgorithmExact::best_point_on_the_edge_set(SurfacePoint& point,
144  std::vector<edge_pointer> const& storage,
145  interval_pointer& best_interval,
146  double& best_total_distance,
147  double& best_interval_position)
148 {
149  best_total_distance = 1e100;
150  for(unsigned i=0; i<storage.size(); ++i)
151  {
152  edge_pointer e = storage[i];
153  list_pointer list = interval_list(e);
154 
155  double offset;
156  double distance;
157  interval_pointer interval;
158 
159  list->find_closest_point(&point,
160  offset,
161  distance,
162  interval);
163 
164  if(distance < best_total_distance)
165  {
166  best_interval = interval;
167  best_total_distance = distance;
168  best_interval_position = offset;
169  }
170  }
171 }
172 
173 inline void GeodesicAlgorithmExact::possible_traceback_edges(SurfacePoint& point,
174  std::vector<edge_pointer>& storage)
175 {
176  storage.clear();
177 
178  if(point.type() == VERTEX)
179  {
180  vertex_pointer v = static_cast<vertex_pointer>(point.base_element());
181  for(unsigned i=0; i<v->adjacent_faces().size(); ++i)
182  {
183  face_pointer f = v->adjacent_faces()[i];
184  storage.push_back(f->opposite_edge(v));
185  }
186  }
187  else if(point.type() == EDGE)
188  {
189  edge_pointer e = static_cast<edge_pointer>(point.base_element());
190  for(unsigned i=0; i<e->adjacent_faces().size(); ++i)
191  {
192  face_pointer f = e->adjacent_faces()[i];
193 
194  storage.push_back(f->next_edge(e,e->v0()));
195  storage.push_back(f->next_edge(e,e->v1()));
196  }
197  }
198  else
199  {
200  face_pointer f = static_cast<face_pointer>(point.base_element());
201  storage.push_back(f->adjacent_edges()[0]);
202  storage.push_back(f->adjacent_edges()[1]);
203  storage.push_back(f->adjacent_edges()[2]);
204  }
205 }
206 
207 
208 inline long GeodesicAlgorithmExact::visible_from_source(SurfacePoint& point) //negative if not visible
209 {
210  assert(point.type() != UNDEFINED_POINT);
211 
212  if(point.type() == EDGE)
213  {
214  edge_pointer e = static_cast<edge_pointer>(point.base_element());
215  list_pointer list = interval_list(e);
216  double position = std::min(point.distance(e->v0()), e->length());
217  interval_pointer interval = list->covering_interval(position);
218  //assert(interval);
219  if(interval && interval->visible_from_source())
220  {
221  return (long)interval->source_index();
222  }
223  else
224  {
225  return -1;
226  }
227  }
228  else if(point.type() == FACE)
229  {
230  return -1;
231  }
232  else if(point.type() == VERTEX)
233  {
234  vertex_pointer v = static_cast<vertex_pointer>(point.base_element());
235  for(unsigned i=0; i<v->adjacent_edges().size(); ++i)
236  {
237  edge_pointer e = v->adjacent_edges()[i];
238  list_pointer list = interval_list(e);
239 
240  double position = e->v0()->id() == v->id() ? 0.0 : e->length();
241  interval_pointer interval = list->covering_interval(position);
242  if(interval && interval->visible_from_source())
243  {
244  return (long)interval->source_index();
245  }
246  }
247 
248  return -1;
249  }
250 
251  assert(0);
252  return 0;
253 }
254 
255 inline double GeodesicAlgorithmExact::compute_positive_intersection(double start,
256  double pseudo_x,
257  double pseudo_y,
258  double sin_alpha,
259  double cos_alpha)
260 {
261  assert(pseudo_y < 0);
262 
263  double denominator = sin_alpha*(pseudo_x - start) - cos_alpha*pseudo_y;
264  if(denominator<0.0)
265  {
266  return -1.0;
267  }
268 
269  double numerator = -pseudo_y*start;
270 
271  if(numerator < 1e-30)
272  {
273  return 0.0;
274  }
275 
276  if(denominator < 1e-30)
277  {
278  return -1.0;
279  }
280 
281  return numerator/denominator;
282 }
283 
284 inline void GeodesicAlgorithmExact::list_edges_visible_from_source(MeshElementBase* p,
285  std::vector<edge_pointer>& storage)
286 {
287  assert(p->type() != UNDEFINED_POINT);
288 
289  if(p->type() == FACE)
290  {
291  face_pointer f = static_cast<face_pointer>(p);
292  for(unsigned i=0; i<3; ++i)
293  {
294  storage.push_back(f->adjacent_edges()[i]);
295  }
296  }
297  else if(p->type() == EDGE)
298  {
299  edge_pointer e = static_cast<edge_pointer>(p);
300  storage.push_back(e);
301  }
302  else //VERTEX
303  {
304  vertex_pointer v = static_cast<vertex_pointer>(p);
305  for(unsigned i=0; i<v->adjacent_edges().size(); ++i)
306  {
307  storage.push_back(v->adjacent_edges()[i]);
308  }
309 
310  }
311 }
312 
313 inline bool GeodesicAlgorithmExact::erase_from_queue(interval_pointer p)
314 {
315  if(p->min() < GEODESIC_INF/10.0)// && p->min >= queue->begin()->first)
316  {
317  assert(m_queue.count(p)<=1); //the set is unique
318 
319  IntervalQueue::iterator it = m_queue.find(p);
320 
321  if(it != m_queue.end())
322  {
323  m_queue.erase(it);
324  return true;
325  }
326  }
327 
328  return false;
329 }
330 
331 inline unsigned GeodesicAlgorithmExact::intersect_intervals(interval_pointer zero,
332  IntervalWithStop* one) //intersecting two intervals with up to three intervals in the end
333 {
334  assert(zero->edge()->id() == one->edge()->id());
335  assert(zero->stop() > one->start() && zero->start() < one->stop());
336  assert(one->min() < GEODESIC_INF/10.0);
337 
338  double const local_epsilon = SMALLEST_INTERVAL_RATIO*one->edge()->length();
339 
340  unsigned N=0;
341  if(zero->min() > GEODESIC_INF/10.0)
342  {
343  start[0] = zero->start();
344  if(zero->start() < one->start() - local_epsilon)
345  {
346  map[0] = OLD;
347  start[1] = one->start();
348  map[1] = NEW;
349  N = 2;
350  }
351  else
352  {
353  map[0] = NEW;
354  N = 1;
355  }
356 
357  if(zero->stop() > one->stop() + local_epsilon)
358  {
359  map[N] = OLD; //"zero" interval
360  start[N++] = one->stop();
361  }
362 
363  start[N+1] = zero->stop();
364  return N;
365  }
366 
367  double const local_small_epsilon = 1e-8*one->edge()->length();
368 
369  double D = zero->d() - one->d();
370  double x0 = zero->pseudo_x();
371  double x1 = one->pseudo_x();
372  double R0 = x0*x0 + zero->pseudo_y()*zero->pseudo_y();
373  double R1 = x1*x1 + one->pseudo_y()*one->pseudo_y();
374 
375  double inter[2]; //points of intersection
376  char Ninter=0; //number of the points of the intersection
377 
378  if(std::abs(D)<local_epsilon) //if d1 == d0, equation is linear
379  {
380  double denom = x1 - x0;
381  if(std::abs(denom)>local_small_epsilon)
382  {
383  inter[0] = (R1 - R0)/(2.*denom); //one solution
384  Ninter = 1;
385  }
386  }
387  else
388  {
389  double D2 = D*D;
390  double Q = 0.5*(R1-R0-D2);
391  double X = x0 - x1;
392 
393  double A = X*X - D2;
394  double B = Q*X + D2*x0;
395  double C = Q*Q - D2*R0;
396 
397  if (std::abs(A)<local_small_epsilon) //if A == 0, linear equation
398  {
399  if(std::abs(B)>local_small_epsilon)
400  {
401  inter[0] = -C/B; //one solution
402  Ninter = 1;
403  }
404  }
405  else
406  {
407  double det = B*B-A*C;
408  if(det>local_small_epsilon*local_small_epsilon) //two roots
409  {
410  det = sqrt(det);
411  if(A>0.0) //make sure that the roots are ordered
412  {
413  inter[0] = (-B - det)/A;
414  inter[1] = (-B + det)/A;
415  }
416  else
417  {
418  inter[0] = (-B + det)/A;
419  inter[1] = (-B - det)/A;
420  }
421 
422  if(inter[1] - inter[0] > local_small_epsilon)
423  {
424  Ninter = 2;
425  }
426  else
427  {
428  Ninter = 1;
429  }
430  }
431  else if(det>=0.0) //single root
432  {
433  inter[0] = -B/A;
434  Ninter = 1;
435  }
436  }
437  }
438  //---------------------------find possible intervals---------------------------------------
439  double left = std::max(zero->start(), one->start()); //define left and right boundaries of the intersection of the intervals
440  double right = std::min(zero->stop(), one->stop());
441 
442  double good_start[4]; //points of intersection within the (left, right) limits +"left" + "right"
443  good_start[0] = left;
444  char Ngood_start=1; //number of the points of the intersection
445 
446  for(char i=0; i<Ninter; ++i) //for all points of intersection
447  {
448  double x = inter[i];
449  if(x > left + local_epsilon && x < right - local_epsilon)
450  {
451  good_start[Ngood_start++] = x;
452  }
453  }
454  good_start[Ngood_start++] = right;
455 
456  MapType mid_map[3];
457  for(char i=0; i<Ngood_start-1; ++i)
458  {
459  double mid = (good_start[i] + good_start[i+1])*0.5;
460  mid_map[i] = zero->signal(mid) <= one->signal(mid) ? OLD : NEW;
461  }
462 
463  //-----------------------------------output----------------------------------
464  N = 0;
465  if(zero->start() < left - local_epsilon) //additional "zero" interval
466  {
467  if(mid_map[0] == OLD) //first interval in the map is already the old one
468  {
469  good_start[0] = zero->start();
470  }
471  else
472  {
473  map[N] = OLD; //"zero" interval
474  start[N++] = zero->start();
475  }
476  }
477 
478  for(long i=0;i<Ngood_start-1;++i) //for all intervals
479  {
480  MapType current_map = mid_map[i];
481  if(N==0 || map[N-1] != current_map)
482  {
483  map[N] = current_map;
484  start[N++] = good_start[i];
485  }
486  }
487 
488  if(zero->stop() > one->stop() + local_epsilon)
489  {
490  if(N==0 || map[N-1] == NEW)
491  {
492  map[N] = OLD; //"zero" interval
493  start[N++] = one->stop();
494  }
495  }
496 
497  start[0] = zero->start(); // just to make sure that epsilons do not damage anything
498  //start[N] = zero->stop();
499 
500  return N;
501 }
502 
503 inline void GeodesicAlgorithmExact::initialize_propagation_data()
504 {
505  clear();
506 
507  IntervalWithStop candidate;
508  std::vector<edge_pointer> edges_visible_from_source;
509  for(unsigned i=0; i<m_sources.size(); ++i) //for all edges adjacent to the starting vertex
510  {
511  SurfacePoint* source = &m_sources[i];
512 
513  edges_visible_from_source.clear();
514  list_edges_visible_from_source(source->base_element(),
515  edges_visible_from_source);
516 
517  for(unsigned j=0; j<edges_visible_from_source.size(); ++j)
518  {
519  edge_pointer e = edges_visible_from_source[j];
520  candidate.initialize(e, source, i);
521  candidate.stop() = e->length();
522  candidate.compute_min_distance(candidate.stop());
523  candidate.direction() = Interval::FROM_SOURCE;
524 
525  update_list_and_queue(interval_list(e), &candidate, 1);
526  }
527  }
528 }
529 
530 inline void GeodesicAlgorithmExact::propagate(std::vector<SurfacePoint>& sources,
531  double max_propagation_distance, //propagation algorithm stops after reaching the certain distance from the source
532  std::vector<SurfacePoint>* stop_points)
533 {
534  set_stop_conditions(stop_points, max_propagation_distance);
535  set_sources(sources);
536  initialize_propagation_data();
537 
538  clock_t start = clock();
539 
540  unsigned satisfied_index = 0;
541 
542  m_iterations = 0; //for statistics
543  m_queue_max_size = 0;
544 
545  IntervalWithStop candidates[2];
546 
547  while(!m_queue.empty())
548  {
549  m_queue_max_size = std::max(m_queue.size(), m_queue_max_size);
550 
551  unsigned const check_period = 10;
552  if(++m_iterations % check_period == 0) //check if we covered all required vertices
553  {
554  if (check_stop_conditions(satisfied_index))
555  {
556  break;
557  }
558  }
559 
560  interval_pointer min_interval = *m_queue.begin();
561  m_queue.erase(m_queue.begin());
562  edge_pointer edge = min_interval->edge();
563  list_pointer list = interval_list(edge);
564 
565  assert(min_interval->d() < GEODESIC_INF);
566 
567  bool const first_interval = min_interval->start() == 0.0;
568  //bool const last_interval = min_interval->stop() == edge->length();
569  bool const last_interval = min_interval->next() == NULL;
570 
571  bool const turn_left = edge->v0()->saddle_or_boundary();
572  bool const turn_right = edge->v1()->saddle_or_boundary();
573 
574  for(unsigned i=0; i<edge->adjacent_faces().size(); ++i) //two possible faces to propagate
575  {
576  if(!edge->is_boundary()) //just in case, always propagate boundary edges
577  {
578  if((i == 0 && min_interval->direction() == Interval::FROM_FACE_0) ||
579  (i == 1 && min_interval->direction() == Interval::FROM_FACE_1))
580  {
581  continue;
582  }
583  }
584 
585  face_pointer face = edge->adjacent_faces()[i]; //if we come from 1, go to 2
586  edge_pointer next_edge = face->next_edge(edge,edge->v0());
587 
588  unsigned num_propagated = compute_propagated_parameters(min_interval->pseudo_x(),
589  min_interval->pseudo_y(),
590  min_interval->d(), //parameters of the interval
591  min_interval->start(),
592  min_interval->stop(), //start/end of the interval
593  face->vertex_angle(edge->v0()), //corner angle
594  next_edge->length(), //length of the new edge
595  first_interval, //if it is the first interval on the edge
596  last_interval,
597  turn_left,
598  turn_right,
599  candidates); //if it is the last interval on the edge
600  bool propagate_to_right = true;
601 
602  if(num_propagated)
603  {
604  if(candidates[num_propagated-1].stop() != next_edge->length())
605  {
606  propagate_to_right = false;
607  }
608 
609  bool const invert = next_edge->v0()->id() != edge->v0()->id(); //if the origins coinside, do not invert intervals
610 
611  construct_propagated_intervals(invert, //do not inverse
612  next_edge,
613  face,
614  candidates,
615  num_propagated,
616  min_interval);
617 
618  update_list_and_queue(interval_list(next_edge),
619  candidates,
620  num_propagated);
621  }
622 
623  if(propagate_to_right)
624  {
625  //propogation to the right edge
626  double length = edge->length();
627  next_edge = face->next_edge(edge,edge->v1());
628 
629  num_propagated = compute_propagated_parameters(length - min_interval->pseudo_x(),
630  min_interval->pseudo_y(),
631  min_interval->d(), //parameters of the interval
632  length - min_interval->stop(),
633  length - min_interval->start(), //start/end of the interval
634  face->vertex_angle(edge->v1()), //corner angle
635  next_edge->length(), //length of the new edge
636  last_interval, //if it is the first interval on the edge
637  first_interval,
638  turn_right,
639  turn_left,
640  candidates); //if it is the last interval on the edge
641 
642  if(num_propagated)
643  {
644  bool const invert = next_edge->v0()->id() != edge->v1()->id(); //if the origins coinside, do not invert intervals
645 
646  construct_propagated_intervals(invert, //do not inverse
647  next_edge,
648  face,
649  candidates,
650  num_propagated,
651  min_interval);
652 
653  update_list_and_queue(interval_list(next_edge),
654  candidates,
655  num_propagated);
656  }
657  }
658  }
659  }
660 
661  m_propagation_distance_stopped = m_queue.empty() ? GEODESIC_INF : (*m_queue.begin())->min();
662  clock_t stop = clock();
663  m_time_consumed = (static_cast<double>(stop)-static_cast<double>(start))/CLOCKS_PER_SEC;
664 
665 /* for(unsigned i=0; i<m_edge_interval_lists.size(); ++i)
666  {
667  list_pointer list = &m_edge_interval_lists[i];
668  interval_pointer p = list->first();
669  assert(p->start() == 0.0);
670  while(p->next())
671  {
672  assert(p->stop() == p->next()->start());
673  assert(p->d() < GEODESIC_INF);
674  p = p->next();
675  }
676  }*/
677 }
678 
679 
680 inline bool GeodesicAlgorithmExact::check_stop_conditions(unsigned& index)
681 {
682  double queue_distance = (*m_queue.begin())->min();
683  if(queue_distance < stop_distance())
684  {
685  return false;
686  }
687 
688  while(index < m_stop_vertices.size())
689  {
690  vertex_pointer v = m_stop_vertices[index].first;
691  edge_pointer edge = v->adjacent_edges()[0]; //take any edge
692 
693  double distance = edge->v0()->id() == v->id() ?
694  interval_list(edge)->signal(0.0) :
695  interval_list(edge)->signal(edge->length());
696 
697  if(queue_distance < distance + m_stop_vertices[index].second)
698  {
699  return false;
700  }
701 
702  ++index;
703  }
704  return true;
705 }
706 
707 
708 inline void GeodesicAlgorithmExact::update_list_and_queue(list_pointer list,
709  IntervalWithStop* candidates, //up to two candidates
710  unsigned num_candidates)
711 {
712  assert(num_candidates <= 2);
713  //assert(list->first() != NULL);
714  edge_pointer edge = list->edge();
715  double const local_epsilon = SMALLEST_INTERVAL_RATIO * edge->length();
716 
717  if(list->first() == NULL)
718  {
719  interval_pointer* p = &list->first();
720  IntervalWithStop* first;
721  IntervalWithStop* second;
722 
723  if(num_candidates == 1)
724  {
725  first = candidates;
726  second = candidates;
727  first->compute_min_distance(first->stop());
728  }
729  else
730  {
731  if(candidates->start() <= (candidates+1)->start())
732  {
733  first = candidates;
734  second = candidates+1;
735  }
736  else
737  {
738  first = candidates+1;
739  second = candidates;
740  }
741  assert(first->stop() == second->start());
742 
743  first->compute_min_distance(first->stop());
744  second->compute_min_distance(second->stop());
745  }
746 
747  if(first->start() > 0.0)
748  {
749  *p = m_memory_allocator.allocate();
750  (*p)->initialize(edge);
751  p = &(*p)->next();
752  }
753 
754  *p = m_memory_allocator.allocate();
755  memcpy(*p,first,sizeof(Interval));
756  m_queue.insert(*p);
757 
758  if(num_candidates == 2)
759  {
760  p = &(*p)->next();
761  *p = m_memory_allocator.allocate();
762  memcpy(*p,second,sizeof(Interval));
763  m_queue.insert(*p);
764  }
765 
766  if(second->stop() < edge->length())
767  {
768  p = &(*p)->next();
769  *p = m_memory_allocator.allocate();
770  (*p)->initialize(edge);
771  (*p)->start() = second->stop();
772  }
773  else
774  {
775  (*p)->next() = NULL;
776  }
777  return;
778  }
779 
780  bool propagate_flag;
781 
782  for(unsigned i=0; i<num_candidates; ++i) //for all new intervals
783  {
784  IntervalWithStop* q = &candidates[i];
785 
786  interval_pointer previous = NULL;
787 
788  interval_pointer p = list->first();
789  assert(p->start() == 0.0);
790 
791  while(p != NULL && p->stop() - local_epsilon < q->start())
792  {
793  p = p->next();
794  }
795 
796  while(p != NULL && p->start() < q->stop() - local_epsilon) //go through all old intervals
797  {
798  unsigned const N = intersect_intervals(p, q); //interset two intervals
799 
800  if(N == 1)
801  {
802  if(map[0]==OLD) //if "p" is always better, we do not need to update anything)
803  {
804  if(previous) //close previous interval and put in into the queue
805  {
806  previous->next() = p;
807  previous->compute_min_distance(p->start());
808  m_queue.insert(previous);
809  previous = NULL;
810  }
811 
812  p = p->next();
813 
814  }
815  else if(previous) //extend previous interval to cover everything; remove p
816  {
817  previous->next() = p->next();
818  erase_from_queue(p);
819  m_memory_allocator.deallocate(p);
820 
821  p = previous->next();
822  }
823  else //p becomes "previous"
824  {
825  previous = p;
826  interval_pointer next = p->next();
827  erase_from_queue(p);
828 
829  memcpy(previous,q,sizeof(Interval));
830 
831  previous->start() = start[0];
832  previous->next() = next;
833 
834  p = next;
835  }
836  continue;
837  }
838 
839  //update_flag = true;
840 
841  Interval swap(*p); //used for swapping information
842  propagate_flag = erase_from_queue(p);
843 
844  for(unsigned j=1; j<N; ++j) //no memory is needed for the first one
845  {
846  i_new[j] = m_memory_allocator.allocate(); //create new intervals
847  }
848 
849  if(map[0]==OLD) //finish previous, if any
850  {
851  if(previous)
852  {
853  previous->next() = p;
854  previous->compute_min_distance(previous->stop());
855  m_queue.insert(previous);
856  previous = NULL;
857  }
858  i_new[0] = p;
859  p->next() = i_new[1];
860  p->start() = start[0];
861  }
862  else if(previous) //extend previous interval to cover everything; remove p
863  {
864  i_new[0] = previous;
865  previous->next() = i_new[1];
866  m_memory_allocator.deallocate(p);
867  previous = NULL;
868  }
869  else //p becomes "previous"
870  {
871  i_new[0] = p;
872  memcpy(p,q,sizeof(Interval));
873 
874  p->next() = i_new[1];
875  p->start() = start[0];
876  }
877 
878  assert(!previous);
879 
880  for(unsigned j=1; j<N; ++j)
881  {
882  interval_pointer current_interval = i_new[j];
883 
884  if(map[j] == OLD)
885  {
886  memcpy(current_interval,&swap,sizeof(Interval));
887  }
888  else
889  {
890  memcpy(current_interval,q,sizeof(Interval));
891  }
892 
893  if(j == N-1)
894  {
895  current_interval->next() = swap.next();
896  }
897  else
898  {
899  current_interval->next() = i_new[j+1];
900  }
901 
902  current_interval->start() = start[j];
903  }
904 
905  for(unsigned j=0; j<N; ++j) //find "min" and add the intervals to the queue
906  {
907  if(j==N-1 && map[j]==NEW)
908  {
909  previous = i_new[j];
910  }
911  else
912  {
913  interval_pointer current_interval = i_new[j];
914 
915  current_interval->compute_min_distance(current_interval->stop()); //compute minimal distance
916 
917  if(map[j]==NEW || (map[j]==OLD && propagate_flag))
918  {
919  m_queue.insert(current_interval);
920  }
921  }
922  }
923 
924  p = swap.next();
925  }
926 
927  if(previous) //close previous interval and put in into the queue
928  {
929  previous->compute_min_distance(previous->stop());
930  m_queue.insert(previous);
931  previous = NULL;
932  }
933  }
934 }
935 
936 inline unsigned GeodesicAlgorithmExact::compute_propagated_parameters(double pseudo_x,
937  double pseudo_y,
938  double d, //parameters of the interval
939  double begin,
940  double end, //start/end of the interval
941  double alpha, //corner angle
942  double L, //length of the new edge
943  bool first_interval, //if it is the first interval on the edge
944  bool last_interval,
945  bool turn_left,
946  bool turn_right,
947  IntervalWithStop* candidates) //if it is the last interval on the edge
948 {
949  assert(pseudo_y<=0.0);
950  assert(d<GEODESIC_INF/10.0);
951  assert(begin<=end);
952  assert(first_interval ? (begin == 0.0) : true);
953 
954  IntervalWithStop* p = candidates;
955 
956  if(std::abs(pseudo_y) <= 1e-30) //pseudo-source is on the edge
957  {
958  if(first_interval && pseudo_x <= 0.0)
959  {
960  p->start() = 0.0;
961  p->stop() = L;
962  p->d() = d - pseudo_x;
963  p->pseudo_x() = 0.0;
964  p->pseudo_y() = 0.0;
965  return 1;
966  }
967  else if(last_interval && pseudo_x >= end)
968  {
969  p->start() = 0.0;
970  p->stop() = L;
971  p->d() = d + pseudo_x-end;
972  p->pseudo_x() = end*cos(alpha);
973  p->pseudo_y() = -end*sin(alpha);
974  return 1;
975  }
976  else if(pseudo_x >= begin && pseudo_x <= end)
977  {
978  p->start() = 0.0;
979  p->stop() = L;
980  p->d() = d;
981  p->pseudo_x() = pseudo_x*cos(alpha);
982  p->pseudo_y() = -pseudo_x*sin(alpha);
983  return 1;
984  }
985  else
986  {
987  return 0;
988  }
989  }
990 
991  double sin_alpha = sin(alpha);
992  double cos_alpha = cos(alpha);
993 
994  //important: for the first_interval, this function returns zero only if the new edge is "visible" from the source
995  //if the new edge can be covered only after turn_over, the value is negative (-1.0)
996  double L1 = compute_positive_intersection(begin,
997  pseudo_x,
998  pseudo_y,
999  sin_alpha,
1000  cos_alpha);
1001 
1002  if(L1 < 0 || L1 >= L)
1003  {
1004  if(first_interval && turn_left)
1005  {
1006  p->start() = 0.0;
1007  p->stop() = L;
1008  p->d() = d + sqrt(pseudo_x*pseudo_x + pseudo_y*pseudo_y);
1009  p->pseudo_y() = 0.0;
1010  p->pseudo_x() = 0.0;
1011  return 1;
1012  }
1013  else
1014  {
1015  return 0;
1016  }
1017  }
1018 
1019  double L2 = compute_positive_intersection(end,
1020  pseudo_x,
1021  pseudo_y,
1022  sin_alpha,
1023  cos_alpha);
1024 
1025  if(L2 < 0 || L2 >= L)
1026  {
1027  p->start() = L1;
1028  p->stop() = L;
1029  p->d() = d;
1030  p->pseudo_x() = cos_alpha*pseudo_x + sin_alpha*pseudo_y;
1031  p->pseudo_y() = -sin_alpha*pseudo_x + cos_alpha*pseudo_y;
1032 
1033  return 1;
1034  }
1035 
1036  p->start() = L1;
1037  p->stop() = L2;
1038  p->d() = d;
1039  p->pseudo_x() = cos_alpha*pseudo_x + sin_alpha*pseudo_y;
1040  p->pseudo_y() = -sin_alpha*pseudo_x + cos_alpha*pseudo_y;
1041  assert(p->pseudo_y() <= 0.0);
1042 
1043  if(!(last_interval && turn_right))
1044  {
1045  return 1;
1046  }
1047  else
1048  {
1049  p = candidates + 1;
1050 
1051  p->start() = L2;
1052  p->stop() = L;
1053  double dx = pseudo_x - end;
1054  p->d() = d + sqrt(dx*dx + pseudo_y*pseudo_y);
1055  p->pseudo_x() = end*cos_alpha;
1056  p->pseudo_y() = -end*sin_alpha;
1057 
1058  return 2;
1059  }
1060 }
1061 
1062 inline void GeodesicAlgorithmExact::construct_propagated_intervals(bool invert,
1063  edge_pointer edge,
1064  face_pointer face, //constructs iNew from the rest of the data
1065  IntervalWithStop* candidates,
1066  unsigned& num_candidates,
1067  interval_pointer source_interval) //up to two candidates
1068 {
1069  double edge_length = edge->length();
1070  double local_epsilon = SMALLEST_INTERVAL_RATIO * edge_length;
1071 
1072  //kill very small intervals in order to avoid precision problems
1073  if(num_candidates == 2)
1074  {
1075  double start = std::min(candidates->start(), (candidates+1)->start());
1076  double stop = std::max(candidates->stop(), (candidates+1)->stop());
1077  if(candidates->stop()-candidates->start() < local_epsilon) // kill interval 0
1078  {
1079  *candidates = *(candidates+1);
1080  num_candidates = 1;
1081  candidates->start() = start;
1082  candidates->stop() = stop;
1083  }
1084  else if ((candidates+1)->stop() - (candidates+1)->start() < local_epsilon)
1085  {
1086  num_candidates = 1;
1087  candidates->start() = start;
1088  candidates->stop() = stop;
1089  }
1090  }
1091 
1092  IntervalWithStop* first;
1093  IntervalWithStop* second;
1094  if(num_candidates == 1)
1095  {
1096  first = candidates;
1097  second = candidates;
1098  }
1099  else
1100  {
1101  if(candidates->start() <= (candidates+1)->start())
1102  {
1103  first = candidates;
1104  second = candidates+1;
1105  }
1106  else
1107  {
1108  first = candidates+1;
1109  second = candidates;
1110  }
1111  assert(first->stop() == second->start());
1112  }
1113 
1114  if(first->start() < local_epsilon)
1115  {
1116  first->start() = 0.0;
1117  }
1118  if(edge_length - second->stop() < local_epsilon)
1119  {
1120  second->stop() = edge_length;
1121  }
1122 
1123  //invert intervals if necessary; fill missing data and set pointers correctly
1124  Interval::DirectionType direction = edge->adjacent_faces()[0]->id() == face->id() ?
1125  Interval::FROM_FACE_0 :
1126  Interval::FROM_FACE_1;
1127 
1128  if(!invert) //in this case everything is straighforward, we do not have to invert the intervals
1129  {
1130  for(unsigned i=0; i<num_candidates; ++i)
1131  {
1132  IntervalWithStop* p = candidates + i;
1133 
1134  p->next() = (i == num_candidates - 1) ? NULL : candidates + i + 1;
1135  p->edge() = edge;
1136  p->direction() = direction;
1137  p->source_index() = source_interval->source_index();
1138 
1139  p->min() = 0.0; //it will be changed later on
1140 
1141  assert(p->start() < p->stop());
1142  }
1143  }
1144  else //now we have to invert the intervals
1145  {
1146  for(unsigned i=0; i<num_candidates; ++i)
1147  {
1148  IntervalWithStop* p = candidates + i;
1149 
1150  p->next() = (i == 0) ? NULL : candidates + i - 1;
1151  p->edge() = edge;
1152  p->direction() = direction;
1153  p->source_index() = source_interval->source_index();
1154 
1155  double length = edge_length;
1156  p->pseudo_x() = length - p->pseudo_x();
1157 
1158  double start = length - p->stop();
1159  p->stop() = length - p->start();
1160  p->start() = start;
1161 
1162  p->min() = 0;
1163 
1164  assert(p->start() < p->stop());
1165  assert(p->start() >= 0.0);
1166  assert(p->stop() <= edge->length());
1167  }
1168  }
1169 }
1170 
1171 
1172 inline unsigned GeodesicAlgorithmExact::best_source(SurfacePoint& point, //quickly find what source this point belongs to and what is the distance to this source
1173  double& best_source_distance)
1174 {
1175  double best_interval_position;
1176  unsigned best_source_index;
1177 
1178  best_first_interval(point,
1179  best_source_distance,
1180  best_interval_position,
1181  best_source_index);
1182 
1183  return best_source_index;
1184 }
1185 
1186 inline interval_pointer GeodesicAlgorithmExact::best_first_interval(SurfacePoint& point,
1187  double& best_total_distance,
1188  double& best_interval_position,
1189  unsigned& best_source_index)
1190 {
1191  assert(point.type() != UNDEFINED_POINT);
1192 
1193  interval_pointer best_interval = NULL;
1194  best_total_distance = GEODESIC_INF;
1195 
1196  if(point.type() == EDGE)
1197  {
1198  edge_pointer e = static_cast<edge_pointer>(point.base_element());
1199  list_pointer list = interval_list(e);
1200 
1201  best_interval_position = point.distance(e->v0());
1202  best_interval = list->covering_interval(best_interval_position);
1203  if(best_interval)
1204  {
1205  //assert(best_interval && best_interval->d() < GEODESIC_INF);
1206  best_total_distance = best_interval->signal(best_interval_position);
1207  best_source_index = best_interval->source_index();
1208  }
1209  }
1210  else if(point.type() == FACE)
1211  {
1212  face_pointer f = static_cast<face_pointer>(point.base_element());
1213  for(unsigned i=0; i<3; ++i)
1214  {
1215  edge_pointer e = f->adjacent_edges()[i];
1216  list_pointer list = interval_list(e);
1217 
1218  double offset;
1219  double distance;
1220  interval_pointer interval;
1221 
1222  list->find_closest_point(&point,
1223  offset,
1224  distance,
1225  interval);
1226 
1227  if(interval && distance < best_total_distance)
1228  {
1229  best_interval = interval;
1230  best_total_distance = distance;
1231  best_interval_position = offset;
1232  best_source_index = interval->source_index();
1233  }
1234  }
1235 
1236  //check for all sources that might be located inside this face
1237  SortedSources::sorted_iterator_pair local_sources = m_sources.sources(f);
1238  for(SortedSources::sorted_iterator it=local_sources.first; it != local_sources.second; ++it)
1239  {
1240  SurfacePointWithIndex* source = *it;
1241  double distance = point.distance(source);
1242  if(distance < best_total_distance)
1243  {
1244  best_interval = NULL;
1245  best_total_distance = distance;
1246  best_interval_position = 0.0;
1247  best_source_index = source->index();
1248  }
1249  }
1250  }
1251  else if(point.type() == VERTEX)
1252  {
1253  vertex_pointer v = static_cast<vertex_pointer>(point.base_element());
1254  for(unsigned i=0; i<v->adjacent_edges().size(); ++i)
1255  {
1256  edge_pointer e = v->adjacent_edges()[i];
1257  list_pointer list = interval_list(e);
1258 
1259  double position = e->v0()->id() == v->id() ? 0.0 : e->length();
1260  interval_pointer interval = list->covering_interval(position);
1261  if(interval)
1262  {
1263  double distance = interval->signal(position);
1264 
1265  if(distance < best_total_distance)
1266  {
1267  best_interval = interval;
1268  best_total_distance = distance;
1269  best_interval_position = position;
1270  best_source_index = interval->source_index();
1271  }
1272  }
1273  }
1274  }
1275 
1276  if(best_total_distance > m_propagation_distance_stopped) //result is unreliable
1277  {
1278  best_total_distance = GEODESIC_INF;
1279  return NULL;
1280  }
1281  else
1282  {
1283  return best_interval;
1284  }
1285 }
1286 
1287 inline void GeodesicAlgorithmExact::trace_back(SurfacePoint& destination, //trace back piecewise-linear path
1288  std::vector<SurfacePoint>& path)
1289 {
1290  path.clear();
1291  double best_total_distance;
1292  double best_interval_position;
1293  unsigned source_index = std::numeric_limits<unsigned>::max();
1294  interval_pointer best_interval = best_first_interval(destination,
1295  best_total_distance,
1296  best_interval_position,
1297  source_index);
1298 
1299  if(best_total_distance >= GEODESIC_INF/2.0) //unable to find the right path
1300  {
1301  return;
1302  }
1303 
1304  path.push_back(destination);
1305 
1306  if(best_interval) //if we did not hit the face source immediately
1307  {
1308  std::vector<edge_pointer> possible_edges;
1309  possible_edges.reserve(10);
1310 
1311  while(visible_from_source(path.back()) < 0) //while this point is not in the direct visibility of some source (if we are inside the FACE, we obviously hit the source)
1312  {
1313  SurfacePoint& q = path.back();
1314 
1315  possible_traceback_edges(q, possible_edges);
1316 
1317  interval_pointer interval;
1318  double total_distance;
1319  double position;
1320 
1321  best_point_on_the_edge_set(q,
1322  possible_edges,
1323  interval,
1324  total_distance,
1325  position);
1326 
1327  //std::cout << total_distance + length(path) << std::endl;
1328  assert(total_distance<GEODESIC_INF);
1329  source_index = interval->source_index();
1330 
1331  edge_pointer e = interval->edge();
1332  double local_epsilon = SMALLEST_INTERVAL_RATIO*e->length();
1333  if(position < local_epsilon)
1334  {
1335  path.push_back(SurfacePoint(e->v0()));
1336  }
1337  else if(position > e->length()-local_epsilon)
1338  {
1339  path.push_back(SurfacePoint(e->v1()));
1340  }
1341  else
1342  {
1343  double normalized_position = position/e->length();
1344  path.push_back(SurfacePoint(e, normalized_position));
1345  }
1346  }
1347  }
1348 
1349  SurfacePoint& source = static_cast<SurfacePoint&>(m_sources[source_index]);
1350  if(path.back().distance(&source) > 0)
1351  {
1352  path.push_back(source);
1353  }
1354 }
1355 
1356 inline void GeodesicAlgorithmExact::print_statistics()
1357 {
1358  GeodesicAlgorithmBase::print_statistics();
1359 
1360  unsigned interval_counter = 0;
1361  for(unsigned i=0; i<m_edge_interval_lists.size(); ++i)
1362  {
1363  interval_counter += m_edge_interval_lists[i].number_of_intervals();
1364  }
1365  double intervals_per_edge = (double)interval_counter/(double)m_edge_interval_lists.size();
1366 
1367  double memory = m_edge_interval_lists.size()*sizeof(IntervalList) +
1368  interval_counter*sizeof(Interval);
1369 
1370  std::cout << "uses about " << memory/1e6 << "Mb of memory" <<std::endl;
1371  std::cout << interval_counter << " total intervals, or "
1372  << intervals_per_edge << " intervals per edge"
1373  << std::endl;
1374  std::cout << "maximum interval queue size is " << m_queue_max_size << std::endl;
1375  std::cout << "number of interval propagations is " << m_iterations << std::endl;
1376 }
1377 
1378 } //geodesic
1379 
1380 #endif //GEODESIC_ALGORITHM_EXACT_20071231
Matrix< 4, 4, T > & invert(Matrix< 4, 4, T > &a_inverted, const Matrix< 4, 4, T > &a_matrix)
4x4 full matrix inversion
Definition: Matrix.h:1033
Definition: geodesic_cpp_03_02_2008/geodesic_algorithm_base.h:11