/Src/Dependencies/Boost/libs/geometry/example/07_a_graph_route_example.cpp

http://hadesmem.googlecode.com/ · C++ · 393 lines · 274 code · 70 blank · 49 comment · 17 complexity · 69bacf9ce2b5c90fe3c318fcf035baef MD5 · raw file

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