root/tags/release-1.0-beta/astar_boost_wrapper.cpp

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

1.0.0b tag 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      graph_add_edge<graph_t, edge_descriptor>(graph,
145                                               edges[j].id, edges[j].source,
146                                               edges[j].target, edges[j].cost,
147                                               edges[j].s_x, edges[j].s_y,
148                                               edges[j].t_x, edges[j].t_y);
149
150      if (!directed || (directed && has_reverse_cost))
151        {
152          float8 cost;
153
154          if (has_reverse_cost)
155            {
156              cost = edges[j].reverse_cost;
157            }
158          else
159            {
160              cost = edges[j].cost;
161            }
162
163          graph_add_edge<graph_t, edge_descriptor>(graph,
164                                                   edges[j].id,
165                                                   edges[j].target,
166                                                   edges[j].source,
167                                                   cost,
168                                                   edges[j].s_x,
169                                                   edges[j].s_y,
170                                                   edges[j].t_x,
171                                                   edges[j].t_y);
172        }
173    }
174
175  std::vector<vertex_descriptor> predecessors(num_vertices(graph));
176
177  vertex_descriptor source_vertex = vertex(source_vertex_id, graph);
178
179  if (source_vertex < 0)
180    {
181      *err_msg = "Source vertex not found";
182      return -1;
183    }
184
185  vertex_descriptor target_vertex = vertex(target_vertex_id, graph);
186  if (target_vertex < 0)
187    {
188      *err_msg = "Target vertex not found";
189      return -1;
190    }
191
192  std::vector<float8> distances(num_vertices(graph));
193
194  try {
195    // call astar named parameter interface
196    astar_search
197      (graph, source_vertex,
198       distance_heuristic<graph_t, float>(graph, target_vertex),
199       predecessor_map(&predecessors[0]).
200       weight_map(get(&Edge::cost, graph)).
201       distance_map(&distances[0]).
202       visitor(astar_goal_visitor<vertex_descriptor>(target_vertex)));
203
204  }
205  catch(found_goal fg) {
206    vector<int> path_vect;
207    int max = MAX_NODES;
208    path_vect.push_back(target_vertex);
209 
210    while (target_vertex != source_vertex)
211      {
212        if (target_vertex == predecessors[target_vertex])
213          {
214            *err_msg = "No path found";
215            return 0;
216           
217          }
218        target_vertex = predecessors[target_vertex];
219
220        path_vect.push_back(target_vertex);
221        if (!max--)
222          {
223            *err_msg = "Overflow";
224            return -1;
225          }
226      }
227
228    *path = (path_element_t *) malloc(sizeof(path_element_t) *
229                                      (path_vect.size() + 1));
230    *path_count = path_vect.size();
231
232    for(int i = path_vect.size() - 1, j = 0; i >= 0; i--, j++)
233      {
234        graph_traits < graph_t >::vertex_descriptor v_src;
235        graph_traits < graph_t >::vertex_descriptor v_targ;
236        graph_traits < graph_t >::edge_descriptor e;
237        graph_traits < graph_t >::out_edge_iterator out_i, out_end;
238
239        (*path)[j].vertex_id = path_vect.at(i);
240
241        (*path)[j].edge_id = -1;
242        (*path)[j].cost = distances[target_vertex];
243       
244        if (i == 0)
245          {
246            continue;
247          }
248
249        v_src = path_vect.at(i);
250        v_targ = path_vect.at(i - 1);
251
252        for (tie(out_i, out_end) = out_edges(v_src, graph);
253             out_i != out_end; ++out_i)
254          {
255            graph_traits < graph_t >::vertex_descriptor v, targ;
256            e = *out_i;
257            v = source(e, graph);
258            targ = target(e, graph);
259                                                               
260            if (targ == v_targ)
261              {
262                (*path)[j].edge_id = graph[*out_i].id;
263                (*path)[j].cost = graph[*out_i].cost;
264                break;
265              }
266          }
267      }
268
269    return EXIT_SUCCESS;
270  }
271}
272
Note: See TracBrowser for help on using the browser.