07_b_graph_route_example.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
  4. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
  5. // Use, modification and distribution is subject to the Boost Software License,
  6. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. //
  9. // Example showing Boost.Geometry combined with Boost.Graph, calculating shortest routes
  10. // input: two WKT's, provided in subfolder data
  11. // output: text, + an SVG, displayable in e.g. Firefox)
  12. // Second variant, with bundled properties
  13. #include <iostream>
  14. #include <fstream>
  15. #include <iomanip>
  16. #include <limits>
  17. #include <boost/tuple/tuple.hpp>
  18. #include <boost/foreach.hpp>
  19. #include <boost/graph/adjacency_list.hpp>
  20. #include <boost/graph/dijkstra_shortest_paths.hpp>
  21. #include <boost/geometry/geometry.hpp>
  22. #include <boost/geometry/geometries/linestring.hpp>
  23. #include <boost/geometry/io/wkt/read.hpp>
  24. // For output:
  25. #include <boost/geometry/io/svg/svg_mapper.hpp>
  26. // For distance-calculations over the Earth:
  27. //#include <boost/geometry/extensions/gis/geographic/strategies/andoyer.hpp>
  28. // Read an ASCII file containing WKT's, fill a vector of tuples
  29. // The tuples consist of at least <0> a geometry and <1> an identifying string
  30. template <typename Geometry, typename Tuple, typename Box>
  31. void read_wkt(std::string const& filename, std::vector<Tuple>& tuples, Box& box)
  32. {
  33. std::ifstream cpp_file(filename.c_str());
  34. if (cpp_file.is_open())
  35. {
  36. while (! cpp_file.eof() )
  37. {
  38. std::string line;
  39. std::getline(cpp_file, line);
  40. Geometry geometry;
  41. boost::trim(line);
  42. if (! line.empty() && ! boost::starts_with(line, "#"))
  43. {
  44. std::string name;
  45. // Split at ';', if any
  46. std::string::size_type pos = line.find(";");
  47. if (pos != std::string::npos)
  48. {
  49. name = line.substr(pos + 1);
  50. line.erase(pos);
  51. boost::trim(line);
  52. boost::trim(name);
  53. }
  54. Geometry geometry;
  55. boost::geometry::read_wkt(line, geometry);
  56. Tuple tuple(geometry, name);
  57. tuples.push_back(tuple);
  58. boost::geometry::expand(box, boost::geometry::return_envelope<Box>(geometry));
  59. }
  60. }
  61. }
  62. }
  63. // To calculate distance, declare and construct a strategy with average earth radius
  64. boost::geometry::strategy::distance::haversine<double> const haversine(6372795.0);
  65. // Define properties for vertex
  66. template <typename Point>
  67. struct bg_vertex_property
  68. {
  69. bg_vertex_property()
  70. {
  71. boost::geometry::assign_zero(location);
  72. }
  73. bg_vertex_property(Point const& loc)
  74. : location(loc)
  75. {
  76. }
  77. Point location;
  78. };
  79. // Define properties for edge
  80. template <typename Linestring>
  81. struct bg_edge_property
  82. {
  83. bg_edge_property(Linestring const& line)
  84. : length(boost::geometry::length(line, haversine))
  85. , m_line(line)
  86. {
  87. }
  88. inline Linestring const& line() const
  89. {
  90. return m_line;
  91. }
  92. double length;
  93. private :
  94. Linestring m_line;
  95. };
  96. // Utility function to add a vertex to a graph. It might exist already. Then do not insert,
  97. // but return vertex descriptor back. It might not exist. Then add it (and return).
  98. // To efficiently handle this, a std::map is used.
  99. template <typename M, typename K, typename G>
  100. inline typename boost::graph_traits<G>::vertex_descriptor find_or_insert(M& map, K const& key, G& graph)
  101. {
  102. typename M::const_iterator it = map.find(key);
  103. if (it == map.end())
  104. {
  105. // Add a vertex to the graph
  106. typename boost::graph_traits<G>::vertex_descriptor new_vertex
  107. = boost::add_vertex(bg_vertex_property<typename M::key_type>(key), graph);
  108. // Add to the map, using POINT as key
  109. map[key] = new_vertex;
  110. return new_vertex;
  111. }
  112. return it->second;
  113. }
  114. template
  115. <
  116. typename Graph,
  117. typename RoadTupleVector,
  118. typename CityTupleVector
  119. >
  120. void add_roads_and_connect_cities(Graph& graph,
  121. RoadTupleVector const& roads,
  122. CityTupleVector& cities)
  123. {
  124. typedef typename boost::range_value<RoadTupleVector>::type road_type;
  125. typedef typename boost::tuples::element<0, road_type>::type line_type;
  126. typedef typename boost::geometry::point_type<line_type>::type point_type;
  127. typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_type;
  128. // Define a map to be used during graph filling
  129. // Maps from point to vertex-id's
  130. typedef std::map<point_type, vertex_type, boost::geometry::less<point_type> > map_type;
  131. map_type map;
  132. // Fill the graph
  133. BOOST_FOREACH(road_type const& road, roads)
  134. {
  135. line_type const& line = road.template get<0>();
  136. // Find or add begin/end point of these line
  137. vertex_type from = find_or_insert(map, line.front(), graph);
  138. vertex_type to = find_or_insert(map, line.back(), graph);
  139. boost::add_edge(from, to, bg_edge_property<line_type>(line), graph);
  140. }
  141. // Find nearest graph vertex for each city, using the map
  142. typedef typename boost::range_value<CityTupleVector>::type city_type;
  143. BOOST_FOREACH(city_type& city, cities)
  144. {
  145. double min_distance = 1e300;
  146. for(typename map_type::const_iterator it = map.begin(); it != map.end(); ++it)
  147. {
  148. double dist = boost::geometry::distance(it->first, city.template get<0>());
  149. if (dist < min_distance)
  150. {
  151. min_distance = dist;
  152. // Set the vertex
  153. city.template get<2>() = it->second;
  154. }
  155. }
  156. }
  157. }
  158. template <typename Graph, typename Route>
  159. inline void add_edge_to_route(Graph const& graph,
  160. typename boost::graph_traits<Graph>::vertex_descriptor vertex1,
  161. typename boost::graph_traits<Graph>::vertex_descriptor vertex2,
  162. Route& route)
  163. {
  164. std::pair
  165. <
  166. typename boost::graph_traits<Graph>::edge_descriptor,
  167. bool
  168. > opt_edge = boost::edge(vertex1, vertex2, graph);
  169. if (opt_edge.second)
  170. {
  171. // Get properties of edge and of vertex
  172. bg_edge_property<Route> const& edge_prop = graph[opt_edge.first];
  173. bg_vertex_property
  174. <
  175. typename boost::geometry::point_type<Route>::type
  176. > const& vertex_prop = graph[vertex2];
  177. // Depending on how edge connects to vertex, copy it forward or backward
  178. if (boost::geometry::equals(edge_prop.line().front(), vertex_prop.location))
  179. {
  180. std::copy(edge_prop.line().begin(), edge_prop.line().end(),
  181. std::back_inserter(route));
  182. }
  183. else
  184. {
  185. std::reverse_copy(edge_prop.line().begin(), edge_prop.line().end(),
  186. std::back_inserter(route));
  187. }
  188. }
  189. }
  190. template <typename Graph, typename Route>
  191. inline void build_route(Graph const& graph,
  192. std::vector<typename boost::graph_traits<Graph>::vertex_descriptor> const& predecessors,
  193. typename boost::graph_traits<Graph>::vertex_descriptor vertex1,
  194. typename boost::graph_traits<Graph>::vertex_descriptor vertex2,
  195. Route& route)
  196. {
  197. typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_type;
  198. vertex_type pred = predecessors[vertex2];
  199. add_edge_to_route(graph, vertex2, pred, route);
  200. while (pred != vertex1)
  201. {
  202. add_edge_to_route(graph, predecessors[pred], pred, route);
  203. pred = predecessors[pred];
  204. }
  205. }
  206. int main()
  207. {
  208. // Define a point in the Geographic coordinate system (currently spherical-equatorial)
  209. // (geographic calculations are in an extension; for sample it makes no difference)
  210. typedef boost::geometry::model::point
  211. <
  212. double, 2, boost::geometry::cs::spherical_equatorial<boost::geometry::degree>
  213. > point_type;
  214. typedef boost::geometry::model::linestring<point_type> line_type;
  215. // Define the graph, lateron containing the road network
  216. // With this, specify bundled properties for vertex and edge,
  217. // as in http://www.boost.org/doc/libs/1_43_0/libs/graph/doc/bundles.html
  218. typedef boost::adjacency_list
  219. <
  220. boost::vecS, boost::vecS, boost::undirectedS
  221. , bg_vertex_property<point_type> // bundled
  222. , bg_edge_property<line_type>
  223. > graph_type;
  224. typedef boost::graph_traits<graph_type>::vertex_descriptor vertex_type;
  225. // Init a bounding box, lateron used to define SVG map
  226. boost::geometry::model::box<point_type> box;
  227. boost::geometry::assign_inverse(box);
  228. graph_type graph;
  229. // Read the cities
  230. typedef boost::tuple<point_type, std::string, vertex_type> city_type;
  231. std::vector<city_type> cities;
  232. read_wkt<point_type>("data/cities.wkt", cities, box);
  233. // Read the road network
  234. typedef boost::tuple<line_type, std::string> road_type;
  235. std::vector<road_type> roads;
  236. read_wkt<line_type>("data/roads.wkt", roads, box);
  237. // Add roads and connect cities
  238. add_roads_and_connect_cities(graph, roads, cities);
  239. double const km = 1000.0;
  240. std::cout << "distances, all in KM" << std::endl
  241. << std::fixed << std::setprecision(0);
  242. // Main functionality: calculate shortest routes from/to all cities
  243. // For the first one, the complete route is stored as a linestring
  244. bool first = true;
  245. line_type route;
  246. int const n = boost::num_vertices(graph);
  247. BOOST_FOREACH(city_type const& city1, cities)
  248. {
  249. std::vector<vertex_type> predecessors(n);
  250. std::vector<double> costs(n);
  251. // Call Dijkstra (without named-parameter to be compatible with all VC)
  252. boost::dijkstra_shortest_paths(graph, city1.get<2>(),
  253. &predecessors[0], &costs[0],
  254. boost::get(&bg_edge_property<line_type>::length, graph),
  255. boost::get(boost::vertex_index, graph),
  256. std::less<double>(), std::plus<double>(),
  257. (std::numeric_limits<double>::max)(), double(),
  258. boost::dijkstra_visitor<boost::null_visitor>());
  259. BOOST_FOREACH(city_type const& city2, cities)
  260. {
  261. if (! boost::equals(city1.get<1>(), city2.get<1>()))
  262. {
  263. double distance = costs[city2.get<2>()] / km;
  264. double acof = boost::geometry::distance(city1.get<0>(), city2.get<0>(), haversine) / km;
  265. std::cout
  266. << std::setiosflags (std::ios_base::left) << std::setw(15)
  267. << city1.get<1>() << " - "
  268. << std::setiosflags (std::ios_base::left) << std::setw(15)
  269. << city2.get<1>()
  270. << " -> through the air: " << std::setw(4) << acof
  271. << " , over the road: " << std::setw(4) << distance
  272. << std::endl;
  273. if (first)
  274. {
  275. build_route(graph, predecessors,
  276. city1.get<2>(), city2.get<2>(),
  277. route);
  278. first = false;
  279. }
  280. }
  281. }
  282. }
  283. #if defined(HAVE_SVG)
  284. // Create the SVG
  285. std::ofstream stream("routes.svg");
  286. boost::geometry::svg_mapper<point_type> mapper(stream, 600, 600);
  287. // Map roads
  288. BOOST_FOREACH(road_type const& road, roads)
  289. {
  290. mapper.add(road.get<0>());
  291. }
  292. BOOST_FOREACH(road_type const& road, roads)
  293. {
  294. mapper.map(road.get<0>(),
  295. "stroke:rgb(128,128,128);stroke-width:1");
  296. }
  297. mapper.map(route,
  298. "stroke:rgb(0, 255, 0);stroke-width:6;opacity:0.5");
  299. // Map cities
  300. BOOST_FOREACH(city_type const& city, cities)
  301. {
  302. mapper.map(city.get<0>(),
  303. "fill:rgb(255,255,0);stroke:rgb(0,0,0);stroke-width:1");
  304. mapper.text(city.get<0>(), city.get<1>(),
  305. "fill:rgb(0,0,0);font-family:Arial;font-size:10px", 5, 5);
  306. }
  307. #endif
  308. return 0;
  309. }