2 #ifndef GEODESIC_ALGORITHM_EXACT_20071231
3 #define GEODESIC_ALGORITHM_EXACT_20071231
24 m_memory_allocator(
mesh->edges().size(),
mesh->edges().size()),
25 m_edge_interval_lists(
mesh->edges().size())
29 for(
unsigned i=0; i<m_edge_interval_lists.size(); ++i)
31 m_edge_interval_lists[i].initialize(&
mesh->
edges()[i]);
37 void propagate(std::vector<SurfacePoint>& sources,
39 std::vector<SurfacePoint>* stop_points = NULL);
42 std::vector<SurfacePoint>& path);
46 std::vector<SurfacePoint>& path,std::vector<unsigned>& indexVertex);
49 double& best_source_distance);
54 typedef std::set<interval_pointer, Interval> IntervalQueue;
58 unsigned num_candidates);
60 unsigned compute_propagated_parameters(
double pseudo_x,
73 void construct_propagated_intervals(
bool invert,
77 unsigned& num_candidates,
80 double compute_positive_intersection(
double start,
90 double& best_total_distance,
91 double& best_interval_position,
92 unsigned& best_source_index);
94 bool check_stop_conditions(
unsigned& index);
98 m_memory_allocator.clear();
100 for(
unsigned i=0; i<m_edge_interval_lists.size(); ++i)
102 m_edge_interval_lists[i].clear();
109 return &m_edge_interval_lists[e->id()];
112 void set_sources(std::vector<SurfacePoint>& sources)
117 void initialize_propagation_data();
119 void list_edges_visible_from_source(MeshElementBase* p,
120 std::vector<edge_pointer>& storage);
122 long visible_from_source(SurfacePoint& point);
124 void best_point_on_the_edge_set(SurfacePoint& point,
125 std::vector<edge_pointer>
const& storage,
127 double& best_total_distance,
128 double& best_interval_position);
130 void possible_traceback_edges(SurfacePoint& point,
131 std::vector<edge_pointer>& storage);
135 IntervalQueue m_queue;
137 MemoryAllocator<Interval> m_memory_allocator;
138 std::vector<IntervalList> m_edge_interval_lists;
140 enum MapType {OLD, NEW};
145 size_t m_queue_max_size;
146 unsigned m_iterations;
148 SortedSources m_sources;
151 inline void GeodesicAlgorithmExact::best_point_on_the_edge_set(SurfacePoint& point,
152 std::vector<edge_pointer>
const& storage,
154 double& best_total_distance,
155 double& best_interval_position)
157 best_total_distance = 1e100;
158 for(
unsigned i=0; i<storage.size(); ++i)
164 double distance = 0.0;
172 if(distance < best_total_distance)
174 best_interval = interval;
175 best_total_distance = distance;
176 best_interval_position = offset;
181 inline void GeodesicAlgorithmExact::possible_traceback_edges(SurfacePoint& point,
182 std::vector<edge_pointer>& storage)
186 if(point.type() ==
VERTEX)
189 for(
unsigned i=0; i<v->adjacent_faces().size(); ++i)
192 storage.push_back(f->opposite_edge(v));
195 else if(point.type() ==
EDGE)
198 for(
unsigned i=0; i<e->adjacent_faces().size(); ++i)
202 storage.push_back(f->next_edge(e,e->v0()));
203 storage.push_back(f->next_edge(e,e->v1()));
209 storage.push_back(f->adjacent_edges()[0]);
210 storage.push_back(f->adjacent_edges()[1]);
211 storage.push_back(f->adjacent_edges()[2]);
216 inline long GeodesicAlgorithmExact::visible_from_source(SurfacePoint& point)
220 if(point.type() ==
EDGE)
224 double position =
std::min(point.distance(e->v0()), e->length());
227 if(interval && interval->visible_from_source())
236 else if(point.type() ==
FACE)
240 else if(point.type() ==
VERTEX)
243 for(
unsigned i=0; i<v->adjacent_edges().size(); ++i)
248 double position = e->v0()->id() == v->id() ? 0.0 : e->length();
250 if(interval && interval->visible_from_source())
263 inline double GeodesicAlgorithmExact::compute_positive_intersection(
double start,
269 assert(pseudo_y < 0);
271 double denominator = sin_alpha*(pseudo_x - start) - cos_alpha*pseudo_y;
277 double numerator = -pseudo_y*start;
279 if(numerator < 1e-30)
284 if(denominator < 1e-30)
289 return numerator/denominator;
292 inline void GeodesicAlgorithmExact::list_edges_visible_from_source(MeshElementBase* p,
293 std::vector<edge_pointer>& storage)
297 if(p->type() ==
FACE)
300 for(
unsigned i=0; i<3; ++i)
302 storage.push_back(f->adjacent_edges()[i]);
305 else if(p->type() ==
EDGE)
308 storage.push_back(e);
313 for(
unsigned i=0; i<v->adjacent_edges().size(); ++i)
315 storage.push_back(v->adjacent_edges()[i]);
325 assert(m_queue.count(p)<=1);
327 IntervalQueue::iterator it = m_queue.find(p);
329 if(it != m_queue.end())
339 inline unsigned GeodesicAlgorithmExact::intersect_intervals(
interval_pointer zero,
340 IntervalWithStop* one)
342 assert(zero->edge()->id() == one->edge()->id());
343 assert(zero->stop() > one->start() && zero->start() < one->stop());
351 start[0] = zero->start();
352 if(zero->start() < one->start() - local_epsilon)
355 start[1] = one->start();
365 if(zero->stop() > one->stop() + local_epsilon)
368 start[N++] = one->stop();
371 start[N+1] = zero->stop();
375 double const local_small_epsilon = 1e-8*one->edge()->length();
377 double D = zero->d() - one->d();
378 double x0 = zero->pseudo_x();
379 double x1 = one->pseudo_x();
380 double R0 = x0*x0 + zero->pseudo_y()*zero->pseudo_y();
381 double R1 = x1*x1 + one->pseudo_y()*one->pseudo_y();
386 if(std::abs(D)<local_epsilon)
388 double denom = x1 - x0;
389 if(std::abs(denom)>local_small_epsilon)
391 inter[0] = (R1 - R0)/(2.*denom);
398 double Q = 0.5*(R1-R0-D2);
402 double B = Q*X + D2*x0;
403 double C = Q*Q - D2*R0;
405 if (std::abs(A)<local_small_epsilon)
407 if(std::abs(B)>local_small_epsilon)
415 double det = B*B-A*C;
416 if(det>local_small_epsilon*local_small_epsilon)
421 inter[0] = (-B - det)/A;
422 inter[1] = (-B + det)/A;
426 inter[0] = (-B + det)/A;
427 inter[1] = (-B - det)/A;
430 if(inter[1] - inter[0] > local_small_epsilon)
447 double left =
std::max(zero->start(), one->start());
448 double right =
std::min(zero->stop(), one->stop());
450 double good_start[4];
451 good_start[0] = left;
452 unsigned char Ngood_start=1;
454 for(
unsigned char i=0; i<Ninter; ++i)
457 if(x > left + local_epsilon && x < right - local_epsilon)
459 good_start[Ngood_start++] = x;
462 good_start[Ngood_start++] = right;
465 for(
unsigned char i=0; i<Ngood_start-1; ++i)
467 double mid = (good_start[i] + good_start[i+1])*0.5;
468 mid_map[i] = zero->signal(mid) <= one->signal(mid) ? OLD : NEW;
473 if(zero->start() < left - local_epsilon)
475 if(mid_map[0] == OLD)
477 good_start[0] = zero->start();
482 start[N++] = zero->start();
486 for(
long i=0;i<Ngood_start-1;++i)
488 MapType current_map = mid_map[i];
489 if(N==0 || map[N-1] != current_map)
491 map[N] = current_map;
492 start[N++] = good_start[i];
496 if(zero->stop() > one->stop() + local_epsilon)
498 if(N==0 || map[N-1] == NEW)
501 start[N++] = one->stop();
505 start[0] = zero->start();
511 inline void GeodesicAlgorithmExact::initialize_propagation_data()
515 IntervalWithStop candidate;
516 std::vector<edge_pointer> edges_visible_from_source;
517 for(
unsigned i=0; i<m_sources.size(); ++i)
519 SurfacePoint* source = &m_sources[i];
521 edges_visible_from_source.clear();
522 list_edges_visible_from_source(source->base_element(),
523 edges_visible_from_source);
525 for(
unsigned j=0; j<edges_visible_from_source.size(); ++j)
528 candidate.initialize(e, source, i);
529 candidate.stop() = e->
length();
530 candidate.compute_min_distance(candidate.stop());
533 update_list_and_queue(interval_list(e), &candidate, 1);
539 double max_propagation_distance,
540 std::vector<SurfacePoint>* stop_points)
543 set_sources(sources);
544 initialize_propagation_data();
546 clock_t start = clock();
548 unsigned satisfied_index = 0;
551 m_queue_max_size = 0;
555 while(!m_queue.empty())
557 m_queue_max_size =
std::max(m_queue.size(), m_queue_max_size);
559 unsigned const check_period = 10;
560 if(++m_iterations % check_period == 0)
562 if (check_stop_conditions(satisfied_index))
569 m_queue.erase(m_queue.begin());
575 bool const first_interval = min_interval->
start() == 0.0;
577 bool const last_interval = min_interval->
next() == NULL;
596 unsigned num_propagated = compute_propagated_parameters(min_interval->
pseudo_x(),
599 min_interval->
start(),
600 min_interval->
stop(),
608 bool propagate_to_right =
true;
612 if(candidates[num_propagated-1].stop() != next_edge->
length())
614 propagate_to_right =
false;
617 bool const invert = next_edge->
v0()->
id() != edge->
v0()->
id();
619 construct_propagated_intervals(invert,
626 update_list_and_queue(interval_list(next_edge),
631 if(propagate_to_right)
637 num_propagated = compute_propagated_parameters(
length - min_interval->
pseudo_x(),
652 bool const invert = next_edge->
v0()->
id() != edge->
v1()->
id();
654 construct_propagated_intervals(invert,
661 update_list_and_queue(interval_list(next_edge),
670 clock_t stop = clock();
671 m_time_consumed = (
static_cast<double>(stop)-
static_cast<double>(start))/CLOCKS_PER_SEC;
688 inline bool GeodesicAlgorithmExact::check_stop_conditions(
unsigned& index)
690 double queue_distance = (*m_queue.begin())->
min();
701 double distance = edge->v0()->id() == v->id() ?
702 interval_list(edge)->
signal(0.0) :
703 interval_list(edge)->
signal(edge->length());
716 inline void GeodesicAlgorithmExact::update_list_and_queue(
list_pointer list,
717 IntervalWithStop* candidates,
718 unsigned num_candidates)
720 assert(num_candidates <= 2);
725 if(list->first() == NULL)
728 IntervalWithStop* first;
729 IntervalWithStop* second;
731 if(num_candidates == 1)
739 if(candidates->start() <= (candidates+1)->start())
742 second = candidates+1;
746 first = candidates+1;
749 assert(first->stop() == second->start());
751 first->compute_min_distance(first->stop());
752 second->compute_min_distance(second->stop());
755 if(first->start() > 0.0)
757 *p = m_memory_allocator.allocate();
758 (*p)->initialize(edge);
762 *p = m_memory_allocator.allocate();
763 memcpy(*p,first,
sizeof(Interval));
766 if(num_candidates == 2)
769 *p = m_memory_allocator.allocate();
770 memcpy(*p,second,
sizeof(Interval));
774 if(second->stop() < edge->length())
777 *p = m_memory_allocator.allocate();
778 (*p)->initialize(edge);
779 (*p)->start() = second->stop();
790 for(
unsigned i=0; i<num_candidates; ++i)
792 IntervalWithStop* q = &candidates[i];
797 assert(p->start() == 0.0);
799 while(p != NULL && p->stop() - local_epsilon < q->start())
804 while(p != NULL && p->start() < q->stop() - local_epsilon)
806 unsigned const N = intersect_intervals(p, q);
814 previous->next() = p;
815 previous->compute_min_distance(p->start());
816 m_queue.insert(previous);
825 previous->next() = p->next();
827 m_memory_allocator.deallocate(p);
829 p = previous->next();
837 memcpy(previous,q,
sizeof(Interval));
839 previous->start() = start[0];
840 previous->next() = next;
850 propagate_flag = erase_from_queue(p);
852 for(
unsigned j=1; j<N; ++j)
854 i_new[j] = m_memory_allocator.allocate();
861 previous->next() = p;
862 previous->compute_min_distance(previous->stop());
863 m_queue.insert(previous);
867 p->
next() = i_new[1];
868 p->
start() = start[0];
873 previous->
next() = i_new[1];
874 m_memory_allocator.deallocate(p);
880 memcpy(p,q,
sizeof(Interval));
882 p->next() = i_new[1];
883 p->
start() = start[0];
888 for(
unsigned j=1; j<N; ++j)
894 memcpy(current_interval,&swap,
sizeof(Interval));
898 memcpy(current_interval,q,
sizeof(Interval));
903 current_interval->next() =
swap.next();
907 current_interval->next() = i_new[j+1];
910 current_interval->
start() = start[j];
913 for(
unsigned j=0; j<N; ++j)
915 if(j==N-1 && map[j]==NEW)
925 if(map[j]==NEW || (map[j]==OLD && propagate_flag))
927 m_queue.insert(current_interval);
937 previous->compute_min_distance(previous->stop());
938 m_queue.insert(previous);
944 inline unsigned GeodesicAlgorithmExact::compute_propagated_parameters(
double pseudo_x,
955 IntervalWithStop* candidates)
957 assert(pseudo_y<=0.0);
960 assert(first_interval ? (begin == 0.0) :
true);
962 IntervalWithStop* p = candidates;
964 if(std::abs(pseudo_y) <= 1e-30)
966 if(first_interval && pseudo_x <= 0.0)
970 p->d() = d - pseudo_x;
975 else if(last_interval && pseudo_x >= end)
979 p->d() = d + pseudo_x-end;
980 p->pseudo_x() = end*cos(alpha);
981 p->pseudo_y() = -end*sin(alpha);
984 else if(pseudo_x >= begin && pseudo_x <= end)
989 p->pseudo_x() = pseudo_x*cos(alpha);
990 p->pseudo_y() = -pseudo_x*sin(alpha);
999 double sin_alpha = sin(alpha);
1000 double cos_alpha = cos(alpha);
1004 double L1 = compute_positive_intersection(begin,
1010 if(L1 < 0 || L1 >= L)
1012 if(first_interval && turn_left)
1016 p->d() = d + sqrt(pseudo_x*pseudo_x + pseudo_y*pseudo_y);
1017 p->pseudo_y() = 0.0;
1018 p->pseudo_x() = 0.0;
1027 double L2 = compute_positive_intersection(end,
1033 if(L2 < 0 || L2 >= L)
1038 p->pseudo_x() = cos_alpha*pseudo_x + sin_alpha*pseudo_y;
1039 p->pseudo_y() = -sin_alpha*pseudo_x + cos_alpha*pseudo_y;
1047 p->pseudo_x() = cos_alpha*pseudo_x + sin_alpha*pseudo_y;
1048 p->pseudo_y() = -sin_alpha*pseudo_x + cos_alpha*pseudo_y;
1049 assert(p->pseudo_y() <= 0.0);
1051 if(!(last_interval && turn_right))
1061 double dx = pseudo_x - end;
1062 p->d() = d + sqrt(dx*dx + pseudo_y*pseudo_y);
1063 p->pseudo_x() = end*cos_alpha;
1064 p->pseudo_y() = -end*sin_alpha;
1070 inline void GeodesicAlgorithmExact::construct_propagated_intervals(
bool invert,
1073 IntervalWithStop* candidates,
1074 unsigned& num_candidates,
1077 double edge_length = edge->length();
1081 if(num_candidates == 2)
1083 double start =
std::min(candidates->start(), (candidates+1)->start());
1084 double stop =
std::max(candidates->stop(), (candidates+1)->stop());
1085 if(candidates->stop()-candidates->start() < local_epsilon)
1087 *candidates = *(candidates+1);
1089 candidates->start() = start;
1090 candidates->stop() = stop;
1092 else if ((candidates+1)->stop() - (candidates+1)->start() < local_epsilon)
1095 candidates->start() = start;
1096 candidates->stop() = stop;
1100 IntervalWithStop* first;
1101 IntervalWithStop* second;
1102 if(num_candidates == 1)
1105 second = candidates;
1109 if(candidates->start() <= (candidates+1)->start())
1112 second = candidates+1;
1116 first = candidates+1;
1117 second = candidates;
1119 assert(first->stop() == second->start());
1122 if(first->start() < local_epsilon)
1124 first->start() = 0.0;
1126 if(edge_length - second->stop() < local_epsilon)
1128 second->stop() = edge_length;
1138 for(
unsigned i=0; i<num_candidates; ++i)
1140 IntervalWithStop* p = candidates + i;
1142 p->next() = (i == num_candidates - 1) ? NULL : candidates + i + 1;
1144 p->direction() = direction;
1145 p->source_index() = source_interval->source_index();
1149 assert(p->start() < p->stop());
1154 for(
unsigned i=0; i<num_candidates; ++i)
1156 IntervalWithStop* p = candidates + i;
1158 p->next() = (i == 0) ? NULL : candidates + i - 1;
1160 p->direction() = direction;
1161 p->source_index() = source_interval->source_index();
1163 double length = edge_length;
1164 p->pseudo_x() =
length - p->pseudo_x();
1166 double start =
length - p->stop();
1167 p->stop() =
length - p->start();
1173 assert(p->start() >= 0.0);
1174 assert(p->stop() <= edge->length());
1181 double& best_source_distance)
1183 double best_interval_position;
1184 unsigned best_source_index;
1186 best_first_interval(point,
1187 best_source_distance,
1188 best_interval_position,
1191 return best_source_index;
1195 double& best_total_distance,
1196 double& best_interval_position,
1197 unsigned& best_source_index)
1209 best_interval_position = point.
distance(e->
v0());
1214 best_total_distance = best_interval->
signal(best_interval_position);
1221 for(
unsigned i=0; i<3; ++i)
1226 double offset = 0.0;
1227 double distance = 0.0;
1235 if(interval && distance < best_total_distance)
1237 best_interval = interval;
1238 best_total_distance = distance;
1239 best_interval_position = offset;
1248 SurfacePointWithIndex* source = *it;
1249 double distance = point.
distance(source);
1250 if(distance < best_total_distance)
1252 best_interval = NULL;
1253 best_total_distance = distance;
1254 best_interval_position = 0.0;
1255 best_source_index = source->index();
1262 for(
unsigned i=0; i<v->adjacent_edges().size(); ++i)
1267 double position = e->v0()->id() == v->id() ? 0.0 : e->length();
1271 double distance = interval->
signal(position);
1273 if(distance < best_total_distance)
1275 best_interval = interval;
1276 best_total_distance = distance;
1277 best_interval_position = position;
1291 return best_interval;
1296 std::vector<SurfacePoint>& path,std::vector<unsigned>& )
1302 std::vector<SurfacePoint>& path)
1305 double best_total_distance;
1306 double best_interval_position;
1309 best_total_distance,
1310 best_interval_position,
1318 path.push_back(destination);
1322 std::vector<edge_pointer> possible_edges;
1323 possible_edges.reserve(10);
1325 while(visible_from_source(path.back()) < 0)
1329 possible_traceback_edges(q, possible_edges);
1332 double total_distance;
1333 double position = 0.0;
1335 best_point_on_the_edge_set(q,
1347 if(position < local_epsilon)
1351 else if(position > e->
length()-local_epsilon)
1357 double normalized_position = position/e->
length();
1364 if(path.back().distance(&source) > 0)
1366 path.push_back(source);
1374 unsigned interval_counter = 0;
1375 for(
unsigned i=0; i<m_edge_interval_lists.size(); ++i)
1377 interval_counter += m_edge_interval_lists[i].number_of_intervals();
1379 double intervals_per_edge = (double)interval_counter/(
double)m_edge_interval_lists.size();
1381 double memory = m_edge_interval_lists.size()*
sizeof(
IntervalList) +
1384 std::cout <<
"uses about " << memory/1e6 <<
"Mb of memory" <<std::endl;
1385 std::cout << interval_counter <<
" total intervals, or "
1386 << intervals_per_edge <<
" intervals per edge"
1388 std::cout <<
"maximum interval queue size is " << m_queue_max_size << std::endl;
1389 std::cout <<
"number of interval propagations is " << m_iterations << std::endl;
edge_pointer next_edge(edge_pointer e, vertex_pointer v)
double vertex_angle(vertex_pointer v)
virtual void print_statistics()
void set_stop_conditions(std::vector< SurfacePoint > *stop_points, double stop_distance)
double length(std::vector< SurfacePoint > &path)
double m_propagation_distance_stopped
std::vector< stop_vertex_with_distace_type > m_stop_vertices
void trace_back_with_index(SurfacePoint &destination, std::vector< SurfacePoint > &path, std::vector< unsigned > &indexVertex)
unsigned best_source(SurfacePoint &point, double &best_source_distance)
void trace_back(SurfacePoint &destination, std::vector< SurfacePoint > &path)
GeodesicAlgorithmExact(geodesic::Mesh *mesh)
~GeodesicAlgorithmExact()
void propagate(std::vector< SurfacePoint > &sources, double max_propagation_distance=GEODESIC_INF, std::vector< SurfacePoint > *stop_points=NULL)
interval_pointer covering_interval(double offset)
DirectionType & direction()
void compute_min_distance(double stop)
interval_pointer & next()
unsigned & source_index()
void find_closest_point(double const x, double const y, double &offset, double &distance)
edge_pointer_vector & adjacent_edges()
face_pointer_vector & adjacent_faces()
std::vector< Edge > & edges()
double distance(double *v)
std::pair< sorted_iterator, sorted_iterator > sorted_iterator_pair
sorted_iterator_pair sources(base_pointer mesh_element)
sorted_vector_type::iterator sorted_iterator
void initialize(std::vector< SurfacePoint > &sources)
base_pointer & base_element()
bool & saddle_or_boundary()
float min(float x, float y)
float max(float x, float y)
void swap(scoped_ptr< T > &x, scoped_ptr< T > &y)
double const GEODESIC_INF
double const SMALLEST_INTERVAL_RATIO
Interval * interval_pointer
IntervalList * list_pointer