| 1 |  | 
|---|
| 2 |  | 
|---|
| 3 | // | 
|---|
| 4 | //======================================================================= | 
|---|
| 5 | // Copyright (c) 2004 Kristopher Beevers | 
|---|
| 6 | // | 
|---|
| 7 | // Distributed under the Boost Software License, Version 1.0. (See | 
|---|
| 8 | // accompanying file LICENSE_1_0.txt or copy at | 
|---|
| 9 | // http://www.boost.org/LICENSE_1_0.txt) | 
|---|
| 10 | //======================================================================= | 
|---|
| 11 | // | 
|---|
| 12 |  | 
|---|
| 13 |  | 
|---|
| 14 | #include <boost/graph/astar_search.hpp> | 
|---|
| 15 | #include <boost/graph/adjacency_list.hpp> | 
|---|
| 16 | #include <boost/graph/random.hpp> | 
|---|
| 17 | #include <boost/random.hpp> | 
|---|
| 18 | #include <boost/graph/graphviz.hpp> | 
|---|
| 19 | #include <sys/time.h> | 
|---|
| 20 | #include <vector> | 
|---|
| 21 | #include <list> | 
|---|
| 22 | #include <iostream> | 
|---|
| 23 | #include <fstream> | 
|---|
| 24 | #include <math.h>    // for sqrt | 
|---|
| 25 |  | 
|---|
| 26 | using namespace boost; | 
|---|
| 27 | using namespace std; | 
|---|
| 28 |  | 
|---|
| 29 |  | 
|---|
| 30 | // auxiliary types | 
|---|
| 31 | struct location | 
|---|
| 32 | { | 
|---|
| 33 |   float y, x; // lat, long | 
|---|
| 34 | }; | 
|---|
| 35 | typedef float cost; | 
|---|
| 36 |  | 
|---|
| 37 | template <class Name, class LocMap> | 
|---|
| 38 | class city_writer { | 
|---|
| 39 | public: | 
|---|
| 40 |   city_writer(Name n, LocMap l, float _minx, float _maxx, | 
|---|
| 41 |               float _miny, float _maxy, | 
|---|
| 42 |               unsigned int _ptx, unsigned int _pty) | 
|---|
| 43 |     : name(n), loc(l), minx(_minx), maxx(_maxx), miny(_miny), | 
|---|
| 44 |       maxy(_maxy), ptx(_ptx), pty(_pty) {} | 
|---|
| 45 |   template <class Vertex> | 
|---|
| 46 |   void operator()(ostream& out, const Vertex& v) const { | 
|---|
| 47 |     float px = 1 - (loc[v].x - minx) / (maxx - minx); | 
|---|
| 48 |     float py = (loc[v].y - miny) / (maxy - miny); | 
|---|
| 49 |     out << "[label=\"" << name[v] << "\", pos=\"" | 
|---|
| 50 |         << static_cast<unsigned int>(ptx * px) << "," | 
|---|
| 51 |         << static_cast<unsigned int>(pty * py) | 
|---|
| 52 |         << "\", fontsize=\"11\"]"; | 
|---|
| 53 |   } | 
|---|
| 54 | private: | 
|---|
| 55 |   Name name; | 
|---|
| 56 |   LocMap loc; | 
|---|
| 57 |   float minx, maxx, miny, maxy; | 
|---|
| 58 |   unsigned int ptx, pty; | 
|---|
| 59 | }; | 
|---|
| 60 |  | 
|---|
| 61 | template <class WeightMap> | 
|---|
| 62 | class time_writer { | 
|---|
| 63 | public: | 
|---|
| 64 |   time_writer(WeightMap w) : wm(w) {} | 
|---|
| 65 |   template <class Edge> | 
|---|
| 66 |   void operator()(ostream &out, const Edge& e) const { | 
|---|
| 67 |     out << "[label=\"" << wm[e] << "\", fontsize=\"11\"]"; | 
|---|
| 68 |   } | 
|---|
| 69 | private: | 
|---|
| 70 |   WeightMap wm; | 
|---|
| 71 | }; | 
|---|
| 72 |  | 
|---|
| 73 |  | 
|---|
| 74 | // euclidean distance heuristic | 
|---|
| 75 | template <class Graph, class CostType, class LocMap> | 
|---|
| 76 | class distance_heuristic : public astar_heuristic<Graph, CostType> | 
|---|
| 77 | { | 
|---|
| 78 | public: | 
|---|
| 79 |   typedef typename graph_traits<Graph>::vertex_descriptor Vertex; | 
|---|
| 80 |   distance_heuristic(LocMap l, Vertex goal) | 
|---|
| 81 |     : m_location(l), m_goal(goal) {} | 
|---|
| 82 |   CostType operator()(Vertex u) | 
|---|
| 83 |   { | 
|---|
| 84 |     CostType dx = m_location[m_goal].x - m_location[u].x; | 
|---|
| 85 |     CostType dy = m_location[m_goal].y - m_location[u].y; | 
|---|
| 86 |     return ::sqrt(dx * dx + dy * dy); | 
|---|
| 87 |   } | 
|---|
| 88 | private: | 
|---|
| 89 |   LocMap m_location; | 
|---|
| 90 |   Vertex m_goal; | 
|---|
| 91 | }; | 
|---|
| 92 |  | 
|---|
| 93 |  | 
|---|
| 94 | struct found_goal {}; // exception for termination | 
|---|
| 95 |  | 
|---|
| 96 | // visitor that terminates when we find the goal | 
|---|
| 97 | template <class Vertex> | 
|---|
| 98 | class astar_goal_visitor : public boost::default_astar_visitor | 
|---|
| 99 | { | 
|---|
| 100 | public: | 
|---|
| 101 |   astar_goal_visitor(Vertex goal) : m_goal(goal) {} | 
|---|
| 102 |   template <class Graph> | 
|---|
| 103 |   void examine_vertex(Vertex u, Graph& g) { | 
|---|
| 104 |     if(u == m_goal) | 
|---|
| 105 |       throw found_goal(); | 
|---|
| 106 |   } | 
|---|
| 107 | private: | 
|---|
| 108 |   Vertex m_goal; | 
|---|
| 109 | }; | 
|---|
| 110 |  | 
|---|
| 111 |  | 
|---|
| 112 | int main(int argc, char **argv) | 
|---|
| 113 | { | 
|---|
| 114 |    | 
|---|
| 115 |   // specify some types | 
|---|
| 116 |   typedef adjacency_list<listS, vecS, undirectedS, no_property, | 
|---|
| 117 |     property<edge_weight_t, cost> > mygraph_t; | 
|---|
| 118 |   typedef property_map<mygraph_t, edge_weight_t>::type WeightMap; | 
|---|
| 119 |   typedef mygraph_t::vertex_descriptor vertex; | 
|---|
| 120 |   typedef mygraph_t::edge_descriptor edge_descriptor; | 
|---|
| 121 |   typedef mygraph_t::vertex_iterator vertex_iterator; | 
|---|
| 122 |   typedef std::pair<int, int> edge; | 
|---|
| 123 |    | 
|---|
| 124 |   // specify data | 
|---|
| 125 |   enum nodes { | 
|---|
| 126 |     Troy, LakePlacid, Plattsburgh, Massena, Watertown, Utica, | 
|---|
| 127 |     Syracuse, Rochester, Buffalo, Ithaca, Binghamton, Woodstock, | 
|---|
| 128 |     NewYork, N | 
|---|
| 129 |   }; | 
|---|
| 130 |   const char *name[] = { | 
|---|
| 131 |     "Troy", "Lake Placid", "Plattsburgh", "Massena", | 
|---|
| 132 |     "Watertown", "Utica", "Syracuse", "Rochester", "Buffalo", | 
|---|
| 133 |     "Ithaca", "Binghamton", "Woodstock", "New York" | 
|---|
| 134 |   }; | 
|---|
| 135 |   location locations[] = { // lat/long | 
|---|
| 136 |     {42.73, 73.68}, {44.28, 73.99}, {44.70, 73.46}, | 
|---|
| 137 |     {44.93, 74.89}, {43.97, 75.91}, {43.10, 75.23}, | 
|---|
| 138 |     {43.04, 76.14}, {43.17, 77.61}, {42.89, 78.86}, | 
|---|
| 139 |     {42.44, 76.50}, {42.10, 75.91}, {42.04, 74.11}, | 
|---|
| 140 |     {40.67, 73.94} | 
|---|
| 141 |   }; | 
|---|
| 142 |   edge edge_array[] = { | 
|---|
| 143 |     edge(Troy,Utica), edge(Troy,LakePlacid), | 
|---|
| 144 |     edge(Troy,Plattsburgh), edge(LakePlacid,Plattsburgh), | 
|---|
| 145 |     edge(Plattsburgh,Massena), edge(LakePlacid,Massena), | 
|---|
| 146 |     edge(Massena,Watertown), edge(Watertown,Utica), | 
|---|
| 147 |     edge(Watertown,Syracuse), edge(Utica,Syracuse), | 
|---|
| 148 |     edge(Syracuse,Rochester), edge(Rochester,Buffalo), | 
|---|
| 149 |     edge(Syracuse,Ithaca), edge(Ithaca,Binghamton), | 
|---|
| 150 |     edge(Ithaca,Rochester), edge(Binghamton,Troy), | 
|---|
| 151 |     edge(Binghamton,Woodstock), edge(Binghamton,NewYork), | 
|---|
| 152 |     edge(Syracuse,Binghamton), edge(Woodstock,Troy), | 
|---|
| 153 |     edge(Woodstock,NewYork) | 
|---|
| 154 |   }; | 
|---|
| 155 |   unsigned int num_edges = sizeof(edge_array) / sizeof(edge); | 
|---|
| 156 |   cost weights[] = { // estimated travel time (mins) | 
|---|
| 157 |     96, 134, 143, 65, 115, 133, 117, 116, 74, 56, | 
|---|
| 158 |     84, 73, 69, 70, 116, 147, 173, 183, 74, 71, 124 | 
|---|
| 159 |   }; | 
|---|
| 160 |    | 
|---|
| 161 |    | 
|---|
| 162 |   // create graph | 
|---|
| 163 |   mygraph_t g(N); | 
|---|
| 164 |   WeightMap weightmap = get(edge_weight, g); | 
|---|
| 165 |   for(std::size_t j = 0; j < num_edges; ++j) { | 
|---|
| 166 |     edge_descriptor e; bool inserted; | 
|---|
| 167 |     tie(e, inserted) = add_edge(edge_array[j].first, | 
|---|
| 168 |                                 edge_array[j].second, g); | 
|---|
| 169 |     weightmap[e] = weights[j]; | 
|---|
| 170 |   } | 
|---|
| 171 |    | 
|---|
| 172 |    | 
|---|
| 173 |   // pick random start/goal | 
|---|
| 174 |   mt19937 gen(time(0)); | 
|---|
| 175 |   vertex start = random_vertex(g, gen); | 
|---|
| 176 |   vertex goal = random_vertex(g, gen); | 
|---|
| 177 |    | 
|---|
| 178 |    | 
|---|
| 179 |   cout << "Start vertex: " << name[start] << endl; | 
|---|
| 180 |   cout << "Goal vertex: " << name[goal] << endl; | 
|---|
| 181 |    | 
|---|
| 182 |   ofstream dotfile; | 
|---|
| 183 |   dotfile.open("test-astar-cities.dot"); | 
|---|
| 184 |   write_graphviz(dotfile, g, | 
|---|
| 185 |                  city_writer<const char **, location*> | 
|---|
| 186 |                   (name, locations, 73.46, 78.86, 40.67, 44.93, | 
|---|
| 187 |                    480, 400), | 
|---|
| 188 |                  time_writer<WeightMap>(weightmap)); | 
|---|
| 189 |    | 
|---|
| 190 |    | 
|---|
| 191 |   vector<mygraph_t::vertex_descriptor> p(num_vertices(g)); | 
|---|
| 192 |   vector<cost> d(num_vertices(g)); | 
|---|
| 193 |   try { | 
|---|
| 194 |     // call astar named parameter interface | 
|---|
| 195 |     astar_search | 
|---|
| 196 |       (g, start, | 
|---|
| 197 |        distance_heuristic<mygraph_t, cost, location*> | 
|---|
| 198 |         (locations, goal), | 
|---|
| 199 |        predecessor_map(&p[0]).distance_map(&d[0]). | 
|---|
| 200 |        visitor(astar_goal_visitor<vertex>(goal))); | 
|---|
| 201 |    | 
|---|
| 202 |    | 
|---|
| 203 |   } catch(found_goal fg) { // found a path to the goal | 
|---|
| 204 |     list<vertex> shortest_path; | 
|---|
| 205 |     for(vertex v = goal;; v = p[v]) { | 
|---|
| 206 |       shortest_path.push_front(v); | 
|---|
| 207 |       if(p[v] == v) | 
|---|
| 208 |         break; | 
|---|
| 209 |     } | 
|---|
| 210 |     cout << "Shortest path from " << name[start] << " to " | 
|---|
| 211 |          << name[goal] << ": "; | 
|---|
| 212 |     list<vertex>::iterator spi = shortest_path.begin(); | 
|---|
| 213 |     cout << name[start]; | 
|---|
| 214 |     for(++spi; spi != shortest_path.end(); ++spi) | 
|---|
| 215 |       cout << " -> " << name[*spi]; | 
|---|
| 216 |     cout << endl << "Total travel time: " << d[goal] << endl; | 
|---|
| 217 |     return 0; | 
|---|
| 218 |   } | 
|---|
| 219 |    | 
|---|
| 220 |   cout << "Didn't find a path from " << name[start] << "to" | 
|---|
| 221 |        << name[goal] << "!" << endl; | 
|---|
| 222 |   return 0; | 
|---|
| 223 |    | 
|---|
| 224 | } | 
|---|