Loading [MathJax]/extensions/tex2jax.js
Free Electron
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
geodesic_cpp_mod/geodesic_algorithm_dijkstra_alternative.h
1 //Copyright (C) 2008 Danil Kirsanov, MIT License
2 #ifndef GEODESIC_ALGORITHM_DIJKSTRA_ALTERNATIVE_010506
3 #define GEODESIC_ALGORITHM_DIJKSTRA_ALTERNATIVE_010506
4 
5 #include "geodesic_algorithm_base.h"
6 #include "geodesic_mesh_elements.h"
7 #include <vector>
8 #include <set>
9 
10 namespace geodesic{
11 
12 class DijkstraNode1
13 {
14  typedef DijkstraNode1* node_pointer;
15 public:
16  DijkstraNode1(){};
17  ~DijkstraNode1(){};
18 
19  double& distance_from_source(){return m_distance;};
20  node_pointer& previous(){return m_previous;};
21  unsigned& source_index(){return m_source_index;};
22  vertex_pointer& vertex(){return m_vertex;};
23 
24  void clear()
25  {
26  m_distance = GEODESIC_INF;
27  m_previous = NULL;
28  }
29 
30  bool operator()(node_pointer const s1, node_pointer const s2) const
31  {
32  return s1->distance_from_source() != s2->distance_from_source() ?
33  s1->distance_from_source() < s2->distance_from_source() :
34  s1->vertex()->id() < s2->vertex()->id();
35  };
36 
37 private:
38  double m_distance; //distance to the closest source
39  unsigned m_source_index; //closest source index
40  node_pointer m_previous; //previous node in the geodesic path
41  vertex_pointer m_vertex; //correspoding vertex
42 };
43 
44 class GeodesicAlgorithmDijkstraAlternative: public GeodesicAlgorithmBase
45 {
46 public:
47  typedef DijkstraNode1 Node;
48  typedef Node* node_pointer;
49 
50  GeodesicAlgorithmDijkstraAlternative(geodesic::Mesh* mesh = NULL):
51  GeodesicAlgorithmBase(mesh),
52  m_nodes(mesh->vertices().size())
53  {
54  m_type = DIJKSTRA;
55  for(unsigned i=0; i<m_nodes.size(); ++i)
56  {
57  m_nodes[i].vertex() = &m_mesh->vertices()[i];
58  }
59  };
60 
61  ~GeodesicAlgorithmDijkstraAlternative(){};
62 
63  virtual void propagate(std::vector<SurfacePoint>& sources,
64  double max_propagation_distance = GEODESIC_INF, //propagation algorithm stops after reaching the certain distance from the source
65  std::vector<SurfacePoint>* stop_points = NULL); //or after ensuring that all the stop_points are covered
66 
67  virtual void trace_back(SurfacePoint& destination, //trace back piecewise-linear path
68  std::vector<SurfacePoint>& path);
69 
70  virtual unsigned best_source(SurfacePoint& point, //quickly find what source this point belongs to and what is the distance to this source
71  double& best_source_distance);
72 private:
73 
74  void set_sources(std::vector<SurfacePoint>& sources)
75  {
76  m_sources = sources;
77  }
78 
79  bool check_stop_conditions(unsigned& index);
80 
81  std::vector<Node> m_nodes; //nodes of the subdivision graph located on the vertices
82 
83  std::vector<SurfacePoint> m_sources; //for simplicity, we keep sources as they are
84 
85  typedef std::set<node_pointer, Node> queue_type;
86  queue_type m_queue;
87 };
88 
89 inline unsigned GeodesicAlgorithmDijkstraAlternative::best_source(SurfacePoint& point, //quickly find what source this point belongs to and what is the distance to this source
90  double& best_source_distance)
91 {
92  if(point.type() == VERTEX)
93  {
94  vertex_pointer v = (vertex_pointer)point.base_element();
95  node_pointer node = &m_nodes[v->id()];
96  best_source_distance = node->distance_from_source();
97  return node->source_index();
98  }
99  else
100  {
101  std::vector<vertex_pointer> possible_vertices; //initialize vertices directly visible from sources
102  m_mesh->closest_vertices(&point, &possible_vertices);
103 
104  best_source_distance = GEODESIC_INF;
105  vertex_pointer min_vertex = NULL;
106  for(unsigned i=0; i<possible_vertices.size(); ++i)
107  {
108  vertex_pointer v = possible_vertices[i];
109 
110  double distance_from_source = m_nodes[v->id()].distance_from_source();
111  double distance_from_dest = v->distance(&point);
112  if(distance_from_source + distance_from_dest < best_source_distance)
113  {
114  best_source_distance = distance_from_source + distance_from_dest;
115  min_vertex = v;
116  }
117  }
118  FEASSERT(min_vertex);
119  node_pointer node = &m_nodes[min_vertex->id()];
120  return node->source_index();
121  }
122 }
123 
124 inline void GeodesicAlgorithmDijkstraAlternative::trace_back(SurfacePoint& destination, //trace back piecewise-linear path
125  std::vector<SurfacePoint>& path)
126 {
127  path.clear();
128  path.push_back(destination);
129 
130  if(destination.type() != VERTEX) //snap to the closest vertex
131  {
132  std::vector<vertex_pointer> possible_vertices; //initialize vertices directly visible from sources
133  m_mesh->closest_vertices(&destination, &possible_vertices);
134 
135  double min_distance = GEODESIC_INF;
136  vertex_pointer min_vertex = NULL;
137  for(unsigned i=0; i<possible_vertices.size(); ++i)
138  {
139  vertex_pointer v = possible_vertices[i];
140 
141  double distance_from_source = m_nodes[v->id()].distance_from_source();
142  double distance_from_dest = v->distance(&destination);
143  if(distance_from_source + distance_from_dest < min_distance)
144  {
145  min_distance = distance_from_source + distance_from_dest;
146  min_vertex = v;
147  }
148  }
149  FEASSERT(min_vertex);
150  path.push_back(SurfacePoint(min_vertex));
151  }
152 
153  node_pointer node = &m_nodes[path.back().base_element()->id()];
154  while(node->previous()) //follow the path
155  {
156  node = node->previous();
157  path.push_back(SurfacePoint(node->vertex()));
158  }
159 
160  SurfacePoint& source = m_sources[node->source_index()]; //add source to the path if it is not already there
161  if(source.type() != VERTEX ||
162  source.base_element()->id() != node->vertex()->id())
163  {
164  path.push_back(source);
165  }
166 }
167 
168 inline void GeodesicAlgorithmDijkstraAlternative::propagate(std::vector<SurfacePoint>& sources,
169  double max_propagation_distance, //propagation algorithm stops after reaching the certain distance from the source
170  std::vector<SurfacePoint>* stop_points) //or after ensuring that all the stop_points are covered
171 {
172  set_stop_conditions(stop_points, max_propagation_distance);
173  set_sources(sources);
174 
175  m_queue.clear(); //clear everything
176  for(unsigned i=0; i<m_nodes.size(); ++i)
177  {
178  m_nodes[i].clear();
179  }
180 
181  clock_t start = clock();
182 
183  std::vector<vertex_pointer> visible_vertices; //initialize vertices directly visible from sources
184  for(unsigned i=0; i<m_sources.size(); ++i)
185  {
186  SurfacePoint* s = &m_sources[i];
187  m_mesh->closest_vertices(s, &visible_vertices);
188  for(unsigned j=0; j<visible_vertices.size(); ++j)
189  {
190  vertex_pointer v = visible_vertices[j];
191  double distance = s->distance(v);
192 
193  node_pointer node = &m_nodes[v->id()];
194  if(distance < node->distance_from_source())
195  {
196  node->distance_from_source() = distance;
197  node->source_index() = i;
198  node->previous() = NULL;
199  }
200  }
201  visible_vertices.clear();
202  }
203 
204  for(unsigned i=0; i<m_nodes.size(); ++i) //initialize the queue
205  {
206  if(m_nodes[i].distance_from_source() < GEODESIC_INF)
207  {
208  m_queue.insert(&m_nodes[i]);
209  }
210  }
211 
212  unsigned counter = 0;
213  unsigned satisfied_index = 0;
214 
215  while(!m_queue.empty()) //main cycle
216  {
217  if(counter++ % 10 == 0) //check if we covered all required vertices
218  {
219  if (check_stop_conditions(satisfied_index))
220  {
221  break;
222  }
223  //std::cout << counter << " " << m_queue.size() << " " << (*m_queue.begin())->distance_from_source()<< std::endl;
224  }
225 
226  node_pointer min_node = *m_queue.begin();
227  m_queue.erase(m_queue.begin());
228 
229  vertex_pointer v = min_node->vertex();
230 
231  for(unsigned i=0; i<v->adjacent_edges().size(); ++i) //update all the adgecent vertices
232  {
233  edge_pointer e = v->adjacent_edges()[i];
234  vertex_pointer next_v = e->opposite_vertex(v);
235  node_pointer next_node = &m_nodes[next_v->id()];
236  //double current_distance =
237  if(next_node->distance_from_source() > min_node->distance_from_source() + e->length())
238  {
239  if(next_node->distance_from_source() < GEODESIC_INF) //remove it from the queue
240  {
241  queue_type::iterator iter = m_queue.find(next_node);
242  FEASSERT(iter != m_queue.end());
243  m_queue.erase(iter);
244  }
245  next_node->distance_from_source() = min_node->distance_from_source() + e->length();
246  next_node->source_index() = min_node->source_index();
247  next_node->previous() = min_node;
248  m_queue.insert(next_node);
249  }
250  }
251  }
252  //std::cout << std::endl;
253 
254  clock_t finish = clock();
255  m_time_consumed = (static_cast<double>(finish)-static_cast<double>(start))/CLOCKS_PER_SEC;
256 }
257 
258 inline bool GeodesicAlgorithmDijkstraAlternative::check_stop_conditions(unsigned& index)
259 {
260  double queue_min_distance = (*m_queue.begin())->distance_from_source();
261 
262  if(queue_min_distance < m_max_propagation_distance)
263  {
264  return false;
265  }
266 
267  while(index < m_stop_vertices.size())
268  {
269  vertex_pointer v = m_stop_vertices[index].first;
270  Node& node = m_nodes[v->id()];
271  if(queue_min_distance < node.distance_from_source() + m_stop_vertices[index].second)
272  {
273  return false;
274  }
275  ++index;
276  }
277  return true;
278 }
279 
280 } //geodesic
281 
282 #endif //GEODESIC_ALGORITHM_DIJKSTRA_ALTERNATIVE_010506
Definition: geodesic_cpp_03_02_2008/geodesic_algorithm_base.h:11