root/sandbox/sigis/christian.gonzalez/trunk/core/src/shooting_star_boost_wrapper.cpp

Revision 333, 10.1 KB (checked in by christian.gonzalez, 18 months ago)

added "#include <climits>", for solve problem with Boost Library

Line 
1/*
2 * Shooting* Shortest path algorithm for PostgreSQL
3 *
4 * Copyright (c) 2007 Anton A. Patrushev, Orkney, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 *
20 */
21
22#include <boost/config.hpp>
23
24#include <boost/graph/graph_traits.hpp>
25#include <boost/graph/adjacency_list.hpp>
26#include <boost/vector_property_map.hpp>
27#include "shooting_star_search.hpp"
28
29#include <climits>
30
31#include "shooting_star.h"
32
33#include <cmath>    // for sqrt
34
35using namespace std;
36using namespace boost;
37
38struct Edge
39{
40  int id;
41  int source;
42  int target;
43  float8 cost;
44  float distance;
45  float rank;
46  std::map< int, vector< std::pair<float, std::vector<int> > >, std::less<int> > adjacent_edges;
47  default_color_type color;
48
49  std::size_t index;
50};
51
52struct Vertex
53{
54  int id;
55  float8 x;
56  float8 y;
57};
58
59// exception for termination
60template <class Edge>
61class found_goal
62{
63  public:
64    found_goal() {}
65    found_goal(Edge target) : target_edge(target) {}
66    found_goal(const found_goal &fg) {}
67    ~found_goal() {}
68    Edge get_target()
69    {
70      return target_edge;
71    }
72  private:
73    Edge target_edge;
74};
75
76
77// visitor that terminates when we find the goal
78template <class Edge>
79class shooting_star_goal_visitor : public boost::default_shooting_star_visitor
80{
81public:
82  shooting_star_goal_visitor(Edge goal, int max_id) : m_goal(goal){}
83  shooting_star_goal_visitor(const shooting_star_goal_visitor &gv) : m_goal(gv.m_goal){}
84  ~shooting_star_goal_visitor(){}
85
86  template <class Graph>
87  void examine_edge(Edge e, Graph& g, int e_max_id)
88  {
89    if( g[e].id == g[m_goal].id || g[e].id == g[m_goal].id + e_max_id )
90    {
91      throw found_goal<Edge>(e);
92    }
93  }
94  template <class Graph>
95  void finish_edge(Edge e, Graph& g) {}
96private:
97  Edge m_goal;
98  int e_max_id;
99};
100
101// Heuristic function
102template <class Graph, class CostType>
103class distance_heuristic
104{
105public:
106  typedef typename graph_traits<Graph>::edge_descriptor Edge;
107  distance_heuristic(Graph& g, Edge goal):m_g(g), m_goal(goal){}
108  CostType operator()(Edge e)
109  {
110    CostType dx = m_g[source(m_goal, m_g)].x - m_g[source(e, m_g)].x;
111    CostType dxt = m_g[target(m_goal, m_g)].x - m_g[target(e, m_g)].x;
112    CostType dy = m_g[source(m_goal, m_g)].y - m_g[source(e, m_g)].y;
113    CostType dyt = m_g[target(m_goal, m_g)].y - m_g[target(e, m_g)].y;
114    //You can choose any heuristical function from below
115    //return ::max(dx, dy);
116    //return ::sqrt(dx * dx + dy * dy)/2;
117    //return 0;
118    //return (min(::fabs(dx),::fabs(dxt))+min(::fabs(dy),::fabs(dyt)))/2;
119    return sqrt(pow(min(::fabs(dx),::fabs(dxt)),2)+pow(min(::fabs(dy),::fabs(dyt)),2))/2;
120  }
121private:
122  Graph& m_g;
123  Edge m_goal;
124};
125
126
127// Adds an edge to the graph
128// Also copies all attributes and adjacent edges
129template <class G, class E>
130static void
131graph_add_edge(G &graph, int index,
132               int id, int source, int target,
133               float8 cost, float8 s_x, float8 s_y, float8 t_x, float8 t_y,
134               std::map< int, vector< std::pair<float, vector<int> > >, std::less<int> > adjacent_edges)
135{
136
137  E e;
138  bool inserted;
139
140  if (cost < 0) // edges are inserted as unpassable if cost is negative
141    cost = MAX_COST;
142
143  tie(e, inserted) = add_edge(source, target, graph);
144
145  graph[e].cost = cost;
146  graph[e].id = id;
147
148  graph[e].source = source;
149  graph[e].target = target;
150
151  graph[e].adjacent_edges = adjacent_edges;
152
153  graph[e].rank = 0;
154  graph[e].distance = 0;
155
156  graph[e].index = index;
157
158
159  typedef typename graph_traits<G>::vertex_descriptor Vertex;
160  Vertex s = vertex(source, graph);
161  Vertex t = vertex(target, graph);
162
163  graph[s].id=source;
164  graph[t].id=target;
165
166  graph[s].x=s_x;
167  graph[s].y=s_y;
168  graph[t].x=t_x;
169  graph[t].y=t_y;
170
171}
172
173// Main Shooting* function.
174// It renumbers vertices, fills the graph with edges,
175// calculates a route and return a result.
176int
177boost_shooting_star(edge_shooting_star_t *edges_array, unsigned int count,
178            int source_edge_id, int target_edge_id,
179            bool directed, bool has_reverse_cost,
180            path_element_t **path, int *path_count, char **err_msg, int e_max_id)
181{
182
183  typedef adjacency_list<vecS, vecS, directedS, Vertex, Edge> graph_t;
184
185  typedef graph_traits < graph_t >::vertex_descriptor vertex_descriptor;
186  typedef graph_traits < graph_t >::edge_descriptor edge_descriptor;
187
188  const unsigned int num_nodes = count*2;
189
190  int z;
191  int src, trg, offset, rule_num;
192
193  graph_t graph(num_nodes);
194
195  std::map< int, vector< std::pair<float, vector<int> > >, std::less<int> > adjacent_edges;
196
197  std::map< int, int, std::less<int> > vertices;
198
199  vector<int> rule;
200
201  offset = 1;
202  rule_num = 0;
203
204  for (std::size_t j = 0; j < count; ++j)
205  {
206    //Vertex ids renumbering moved here
207    src = edges_array[j].source;
208    trg = edges_array[j].target;
209
210    if(vertices[src]==0)
211    {
212      vertices[src]=j+offset;
213    }
214    edges_array[j].source=vertices[src];
215
216    if(vertices[trg]==0)
217    {
218      offset++;
219      vertices[trg]=j+offset;
220    }
221    edges_array[j].target=vertices[trg];
222
223    for(z=0; z<MAX_RULE_LENGTH;++z)
224    {
225      if(edges_array[j].rule[z] > 0)
226      {
227        rule.push_back(edges_array[j].rule[z]);
228      }
229    }
230
231    if(edges_array[j].to_cost > 0)
232    {
233      adjacent_edges[edges_array[j].id].push_back(std::pair<float8, vector<int> > (edges_array[j].to_cost, rule) );
234      rule.clear();
235    }
236
237    if((j < count-1 && edges_array[j].id != edges_array[j+1].id)||(j==count-1))
238    {
239      graph_add_edge<graph_t, edge_descriptor>(graph, j,
240                                               edges_array[j].id, edges_array[j].source,
241                                               edges_array[j].target, edges_array[j].cost,
242                                               edges_array[j].s_x, edges_array[j].s_y,
243                                               edges_array[j].t_x, edges_array[j].t_y, adjacent_edges);
244
245      // if the edge is not directed or if it is directed and has reverse cost
246      if (!directed || (directed && has_reverse_cost))
247      {
248        float8 cost;
249
250        if (has_reverse_cost)
251        {
252          cost = edges_array[j].reverse_cost;
253        }
254        else
255        {
256          cost = edges_array[j].cost;
257        }
258
259
260      if(adjacent_edges[edges_array[j].id].size() > 0)
261      {
262        adjacent_edges[edges_array[j].id+e_max_id].assign( adjacent_edges[edges_array[j].id].begin(), adjacent_edges[edges_array[j].id].end() );
263        adjacent_edges.erase(edges_array[j].id);
264      }
265
266
267        graph_add_edge<graph_t, edge_descriptor>(graph, j,
268                                               edges_array[j].id+e_max_id, edges_array[j].target,
269                                               edges_array[j].source, cost,
270                                               edges_array[j].s_x, edges_array[j].s_y,
271                                               edges_array[j].t_x, edges_array[j].t_y, adjacent_edges);
272      }
273
274    adjacent_edges.clear();
275    rule_num = 0;
276    }
277    else
278    {
279      rule_num++;
280    }
281  }
282
283
284  edge_descriptor source_edge;
285  edge_descriptor target_edge;
286
287  bool source_found = false, target_found = false;
288
289  graph_traits<graph_t>::edge_iterator ei, ei_end;
290
291  for(tie(ei, ei_end) = edges(graph); ei != ei_end; ++ei)
292  {
293    if(graph[*ei].id == source_edge_id)
294    {
295      source_edge = *ei;
296      source_found = true;
297      break;
298    }
299
300  }
301
302  if (!source_found)
303  {
304    *err_msg = (char *) "Source edge not found";
305    return -2;
306  }
307
308
309  for(tie(ei, ei_end) = edges(graph); ei != ei_end; ++ei)
310  {
311    if(graph[*ei].id == target_edge_id)
312    {
313      target_edge = *ei;
314      target_found = true;
315      break;
316    }
317  }
318
319
320  if (!target_found)
321  {
322    *err_msg = (char *) "Target edge not found";
323    return -3;
324  }
325
326  property_map<graph_t, std::size_t Edge::*>::type edge_index = get(&Edge::index, graph);
327
328  std::map< int, edge_descriptor, std::less<int> > predecessors;
329
330  property_map<graph_t, float Edge::*>::type rank = get(&Edge::rank, graph);
331  property_map<graph_t, float Edge::*>::type distance = get(&Edge::distance, graph);
332
333  try
334  {
335    //calling Shooting* search
336    shooting_star_search
337      (graph, source_edge,
338       distance_heuristic<graph_t, float>(graph, target_edge),
339       weight_map(get(&Edge::cost, graph)).
340       weight_map2(get(&Edge::adjacent_edges, graph)).
341       edge_color_map(get(&Edge::color, graph)).
342       visitor(shooting_star_goal_visitor<edge_descriptor>(target_edge, e_max_id)),
343       edge_index,
344       distance, rank,
345       predecessors, e_max_id
346       );
347
348  }
349  catch(found_goal<edge_descriptor> &fg)
350  {
351
352    vector<edge_descriptor> path_vect;
353    int max = MAX_NODES;
354
355    target_edge = fg.get_target();
356
357    path_vect.push_back(target_edge);
358
359    while (target_edge != source_edge)
360      {
361
362        if ((target_edge == predecessors[graph[target_edge].id]) && (predecessors[graph[target_edge].id] != source_edge))
363        {
364          *err_msg = (char *) "No path found";
365          return -1;
366
367        }
368
369        target_edge = predecessors[graph[target_edge].id];
370
371        path_vect.push_back(target_edge);
372
373        // This check was made to be sure that we can
374        // restore the path from the target edge within
375        // MAX_NODE iterations.
376        // Sometimes it doesn't work properly and search exits here
377        // even if the target edge was reached.
378
379        if (!max--)
380          {
381            *err_msg = (char *) "No path found";
382            return -1;
383          }
384      }
385
386    *path = (path_element_t *) malloc(sizeof(path_element_t) *
387                                      (path_vect.size() + 1));
388    *path_count = path_vect.size();
389
390    for(int i = path_vect.size() - 1, j = 0; i >= 0; i--, j++)
391    {
392      graph_traits < graph_t >::edge_descriptor e;
393
394      e = path_vect.at(i);
395
396      if(graph[e].id > e_max_id)
397      {
398        graph[e].id -= e_max_id;
399      }
400
401      (*path)[j].edge_id = graph[e].id;
402      (*path)[j].cost = graph[e].cost;
403      (*path)[j].vertex_id = source(e, graph);
404    }
405
406    return EXIT_SUCCESS;
407  }
408
409  *err_msg = (char *) "Target was not reached";
410  return 0;
411
412}
413
Note: See TracBrowser for help on using the browser.