root/branches/anton/core/src/astar_boost_wrapper.cpp

Revision 28, 6.9 KB (checked in by anton, 3 years ago)

cmake branch added

Line 
1/*
2 * A* Shortest path algorithm for PostgreSQL
3 *
4 * Copyright (c) 2006 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#include <iostream>
24#include <fstream>
25
26#include <boost/graph/graph_traits.hpp>
27#include <boost/graph/adjacency_list.hpp>
28#include <boost/graph/astar_search.hpp>
29
30#include "astar.h"
31
32#include <math.h>    // for sqrt
33
34using namespace std;
35using namespace boost;
36
37// Maximal number of nodes in the path (to avoid infinite loops)
38#define MAX_NODES 1000000
39
40struct Edge
41{
42  int id;
43  float8 cost;
44  //float8 distance;
45};
46       
47struct Vertex
48{
49  int id;
50  float8 x;
51  float8 y;
52};
53
54
55struct found_goal {}; // exception for termination
56
57// visitor that terminates when we find the goal
58template <class Vertex>
59class astar_goal_visitor : public boost::default_astar_visitor
60{
61public:
62  astar_goal_visitor(Vertex goal) : m_goal(goal) {}
63  template <class Graph>
64  void examine_vertex(Vertex u, Graph& g) {
65    if(u == m_goal)
66      throw found_goal();
67  }
68private:
69  Vertex m_goal;
70};
71
72
73template <class Graph, class CostType>
74class distance_heuristic : public astar_heuristic<Graph, CostType>
75{
76public:
77  typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
78  distance_heuristic(Graph& g, Vertex goal):m_g(g), m_goal(goal){}
79  CostType operator()(Vertex u)
80  {
81    CostType dx = m_g[m_goal].x - m_g[u].x;
82    CostType dy = m_g[m_goal].y - m_g[u].y;
83    //You can choose any heuristical function from below
84    //return ::max(dx, dy);
85    //return ::sqrt(dx * dx + dy * dy)/4;
86    //return 0;
87    return (::fabs(dx)+::fabs(dy))/2;
88  }
89private:
90  Graph& m_g;
91  Vertex m_goal;
92};
93
94
95template <class G, class E>
96static void
97graph_add_edge(G &graph, int id, int source, int target,
98               float8 cost, float8 s_x, float8 s_y, float8 t_x, float8 t_y)
99{
100  E e;
101  bool inserted;
102   
103  if (cost < 0) // edges are not inserted in the graph if cost is negative
104    return;
105
106  tie(e, inserted) = add_edge(source, target, graph);
107
108  graph[e].cost = cost;
109  graph[e].id = id;
110
111  typedef typename graph_traits<G>::vertex_descriptor Vertex;
112  Vertex s = vertex(source, graph);
113  Vertex t = vertex(target, graph);
114  graph[s].x=s_x;
115  graph[s].y=s_y;
116  graph[t].x=t_x;
117  graph[t].y=t_y;
118}
119
120int
121boost_astar(edge_astar_t *edges, unsigned int count,
122            int source_vertex_id, int target_vertex_id,
123            bool directed, bool has_reverse_cost,
124            path_element_t **path, int *path_count, char **err_msg)
125{
126
127  // FIXME: use a template for the directedS parameters
128  typedef adjacency_list < listS, vecS, directedS, Vertex, Edge> graph_t;
129
130  typedef graph_traits < graph_t >::vertex_descriptor vertex_descriptor;
131  typedef graph_traits < graph_t >::edge_descriptor edge_descriptor;
132
133  // FIXME: compute this value
134  const unsigned int num_nodes = ((directed && has_reverse_cost ? 2 : 1) *
135                                  count) + 100;
136
137  graph_t graph(num_nodes);
138
139  property_map<graph_t, edge_weight_t>::type weightmap = get(edge_weight,
140                                                             graph);
141
142  for (std::size_t j = 0; j < count; ++j)
143  {
144
145      graph_add_edge<graph_t, edge_descriptor>(graph,
146                                               edges[j].id, edges[j].source,
147                                               edges[j].target, edges[j].cost,
148                                               edges[j].s_x, edges[j].s_y,
149                                               edges[j].t_x, edges[j].t_y);
150
151      if (!directed || (directed && has_reverse_cost))
152        {
153          float8 cost;
154
155          if (has_reverse_cost)
156            {
157              cost = edges[j].reverse_cost;
158            }
159          else
160            {
161              cost = edges[j].cost;
162            }
163
164          graph_add_edge<graph_t, edge_descriptor>(graph,
165                                                   edges[j].id,
166                                                   edges[j].target,
167                                                   edges[j].source,
168                                                   cost,
169                                                   edges[j].s_x,
170                                                   edges[j].s_y,
171                                                   edges[j].t_x,
172                                                   edges[j].t_y);
173        }
174    }
175
176  std::vector<vertex_descriptor> predecessors(num_vertices(graph));
177
178  vertex_descriptor source_vertex = vertex(source_vertex_id, graph);
179
180  if (source_vertex < 0)
181    {
182      *err_msg = "Source vertex not found";
183      return -1;
184    }
185
186  vertex_descriptor target_vertex = vertex(target_vertex_id, graph);
187  if (target_vertex < 0)
188    {
189      *err_msg = "Target vertex not found";
190      return -1;
191    }
192
193  std::vector<float8> distances(num_vertices(graph));
194
195  try {
196    // call astar named parameter interface
197    astar_search
198      (graph, source_vertex,
199       distance_heuristic<graph_t, float>(graph, target_vertex),
200       predecessor_map(&predecessors[0]).
201       weight_map(get(&Edge::cost, graph)).
202       distance_map(&distances[0]).
203       visitor(astar_goal_visitor<vertex_descriptor>(target_vertex)));
204
205  }
206  catch(found_goal fg) {
207    vector<int> path_vect;
208    int max = MAX_NODES;
209    path_vect.push_back(target_vertex);
210 
211    while (target_vertex != source_vertex)
212      {
213        if (target_vertex == predecessors[target_vertex])
214          {
215            *err_msg = "No path found";
216            return 0;
217           
218          }
219        target_vertex = predecessors[target_vertex];
220
221        path_vect.push_back(target_vertex);
222        if (!max--)
223          {
224            *err_msg = "Overflow";
225            return -1;
226          }
227      }
228
229    *path = (path_element_t *) malloc(sizeof(path_element_t) *
230                                      (path_vect.size() + 1));
231    *path_count = path_vect.size();
232
233    for(int i = path_vect.size() - 1, j = 0; i >= 0; i--, j++)
234      {
235        graph_traits < graph_t >::vertex_descriptor v_src;
236        graph_traits < graph_t >::vertex_descriptor v_targ;
237        graph_traits < graph_t >::edge_descriptor e;
238        graph_traits < graph_t >::out_edge_iterator out_i, out_end;
239
240        (*path)[j].vertex_id = path_vect.at(i);
241
242        (*path)[j].edge_id = -1;
243        (*path)[j].cost = distances[target_vertex];
244       
245        if (i == 0)
246          {
247            continue;
248          }
249
250        v_src = path_vect.at(i);
251        v_targ = path_vect.at(i - 1);
252
253        for (tie(out_i, out_end) = out_edges(v_src, graph);
254             out_i != out_end; ++out_i)
255          {
256            graph_traits < graph_t >::vertex_descriptor v, targ;
257            e = *out_i;
258            v = source(e, graph);
259            targ = target(e, graph);
260                                                               
261            if (targ == v_targ)
262              {
263                (*path)[j].edge_id = graph[*out_i].id;
264                (*path)[j].cost = graph[*out_i].cost;
265                break;
266              }
267          }
268      }
269
270    return EXIT_SUCCESS;
271  }
272}
273
Note: See TracBrowser for help on using the browser.