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