// //======================================================================= // Copyright (c) 2004 Kristopher Beevers // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // #include #include #include #include #include #include #include #include #include // for sqrt #include using namespace boost; using namespace std; // auxiliary types struct location { float y, x; // lat, long }; struct my_float { float v; explicit my_float(float v = float()) : v(v) {} }; typedef my_float cost; ostream& operator<<(ostream& o, my_float f) { return o << f.v; } my_float operator+(my_float a, my_float b) { return my_float(a.v + b.v); } bool operator==(my_float a, my_float b) { return a.v == b.v; } bool operator<(my_float a, my_float b) { return a.v < b.v; } template < class Name, class LocMap > class city_writer { public: city_writer(Name n, LocMap l, float _minx, float _maxx, float _miny, float _maxy, unsigned int _ptx, unsigned int _pty) : name(n) , loc(l) , minx(_minx) , maxx(_maxx) , miny(_miny) , maxy(_maxy) , ptx(_ptx) , pty(_pty) { } template < class Vertex > void operator()(ostream& out, const Vertex& v) const { float px = 1 - (loc[v].x - minx) / (maxx - minx); float py = (loc[v].y - miny) / (maxy - miny); out << "[label=\"" << name[v] << "\", pos=\"" << static_cast< unsigned int >(ptx * px) << "," << static_cast< unsigned int >(pty * py) << "\", fontsize=\"11\"]"; } private: Name name; LocMap loc; float minx, maxx, miny, maxy; unsigned int ptx, pty; }; template < class WeightMap > class time_writer { public: time_writer(WeightMap w) : wm(w) {} template < class Edge > void operator()(ostream& out, const Edge& e) const { out << "[label=\"" << wm[e] << "\", fontsize=\"11\"]"; } private: WeightMap wm; }; // euclidean distance heuristic template < class Graph, class CostType, class LocMap > class distance_heuristic : public astar_heuristic< Graph, CostType > { public: typedef typename graph_traits< Graph >::vertex_descriptor Vertex; distance_heuristic(LocMap l, Vertex goal) : m_location(l), m_goal(goal) {} CostType operator()(Vertex u) { float dx = m_location[m_goal].x - m_location[u].x; float dy = m_location[m_goal].y - m_location[u].y; return CostType(::sqrt(dx * dx + dy * dy)); } private: LocMap m_location; Vertex m_goal; }; struct found_goal { }; // exception for termination // visitor that terminates when we find the goal template < class Vertex > class astar_goal_visitor : public boost::default_astar_visitor { public: astar_goal_visitor(Vertex goal) : m_goal(goal) {} template < class Graph > void examine_vertex(Vertex u, Graph&) { if (u == m_goal) throw found_goal(); } private: Vertex m_goal; }; int main(int, char**) { // specify some types typedef adjacency_list< listS, vecS, undirectedS, no_property, property< edge_weight_t, cost > > mygraph_t; typedef property_map< mygraph_t, edge_weight_t >::type WeightMap; typedef mygraph_t::vertex_descriptor vertex; typedef mygraph_t::edge_descriptor edge_descriptor; typedef std::pair< int, int > edge; // specify data enum nodes { Troy, LakePlacid, Plattsburgh, Massena, Watertown, Utica, Syracuse, Rochester, Buffalo, Ithaca, Binghamton, Woodstock, NewYork, N }; const char* name[] = { "Troy", "Lake Placid", "Plattsburgh", "Massena", "Watertown", "Utica", "Syracuse", "Rochester", "Buffalo", "Ithaca", "Binghamton", "Woodstock", "New York" }; location locations[] = { // lat/long { 42.73, 73.68 }, { 44.28, 73.99 }, { 44.70, 73.46 }, { 44.93, 74.89 }, { 43.97, 75.91 }, { 43.10, 75.23 }, { 43.04, 76.14 }, { 43.17, 77.61 }, { 42.89, 78.86 }, { 42.44, 76.50 }, { 42.10, 75.91 }, { 42.04, 74.11 }, { 40.67, 73.94 } }; edge edge_array[] = { edge(Troy, Utica), edge(Troy, LakePlacid), edge(Troy, Plattsburgh), edge(LakePlacid, Plattsburgh), edge(Plattsburgh, Massena), edge(LakePlacid, Massena), edge(Massena, Watertown), edge(Watertown, Utica), edge(Watertown, Syracuse), edge(Utica, Syracuse), edge(Syracuse, Rochester), edge(Rochester, Buffalo), edge(Syracuse, Ithaca), edge(Ithaca, Binghamton), edge(Ithaca, Rochester), edge(Binghamton, Troy), edge(Binghamton, Woodstock), edge(Binghamton, NewYork), edge(Syracuse, Binghamton), edge(Woodstock, Troy), edge(Woodstock, NewYork) }; unsigned int num_edges = sizeof(edge_array) / sizeof(edge); cost weights[] = { // estimated travel time (mins) my_float(96), my_float(134), my_float(143), my_float(65), my_float(115), my_float(133), my_float(117), my_float(116), my_float(74), my_float(56), my_float(84), my_float(73), my_float(69), my_float(70), my_float(116), my_float(147), my_float(173), my_float(183), my_float(74), my_float(71), my_float(124) }; // create graph mygraph_t g(N); WeightMap weightmap = get(edge_weight, g); for (std::size_t j = 0; j < num_edges; ++j) { edge_descriptor e; bool inserted; boost::tie(e, inserted) = add_edge(edge_array[j].first, edge_array[j].second, g); weightmap[e] = weights[j]; } // pick random start/goal boost::minstd_rand gen(time(0)); vertex start = gen() % num_vertices(g); vertex goal = gen() % num_vertices(g); cout << "Start vertex: " << name[start] << endl; cout << "Goal vertex: " << name[goal] << endl; vector< mygraph_t::vertex_descriptor > p(num_vertices(g)); vector< cost > d(num_vertices(g)); boost::property_map< mygraph_t, boost::vertex_index_t >::const_type idx = get(boost::vertex_index, g); try { // call astar named parameter interface astar_search(g, start, distance_heuristic< mygraph_t, cost, location* >(locations, goal), predecessor_map(make_iterator_property_map(p.begin(), idx)) .distance_map(make_iterator_property_map(d.begin(), idx)) .visitor(astar_goal_visitor< vertex >(goal)) .distance_inf(my_float((std::numeric_limits< float >::max)()))); } catch (found_goal fg) { // found a path to the goal list< vertex > shortest_path; for (vertex v = goal;; v = p[v]) { shortest_path.push_front(v); if (p[v] == v) break; } cout << "Shortest path from " << name[start] << " to " << name[goal] << ": "; list< vertex >::iterator spi = shortest_path.begin(); cout << name[start]; for (++spi; spi != shortest_path.end(); ++spi) cout << " -> " << name[*spi]; cout << endl << "Total travel time: " << d[goal] << endl; return 0; } cout << "Didn't find a path from " << name[start] << "to" << name[goal] << "!" << endl; return 0; }