07_b_graph_route_example.cpp

    //Boost.Geometry(akaGGL,GenericGeometryLibrary)

    //Copyright(c)2007-2012BarendGehrels,Amsterdam,theNetherlands.
    //Copyright(c)2008-2012BrunoLalande,Paris,France.
    //Copyright(c)2009-2012MateuszLoskot,London,UK.

    //Use,modificationanddistributionissubjecttotheBoostSoftwareLicense,
    //Version1.0.(SeeaccompanyingfileLICENSE_1_0.txtorcopyat
    //http://www.boost.org/LICENSE_1_0.txt)
    //
    //ExampleshowingBoost.GeometrycombinedwithBoost.Graph,calculatingshortestroutes
    //input:twoWKT's,providedinsubfolderdata
    //output:text,+anSVG,displayableine.g.Firefox)

    //Secondvariant,withbundledproperties

    #include<iostream>
    #include<fstream>
    #include<iomanip>
    #include<limits>

    #include<boost/tuple/tuple.hpp>
    #include<boost/foreach.hpp>

    #include<boost/graph/adjacency_list.hpp>
    #include<boost/graph/dijkstra_shortest_paths.hpp>

    #include<boost/geometry/geometry.hpp>
    #include<boost/geometry/geometries/linestring.hpp>
    #include<boost/geometry/io/wkt/read.hpp>

    //Foroutput:
    #include<boost/geometry/io/svg/svg_mapper.hpp>

    //Fordistance-calculationsovertheEarth:
    //#include<boost/geometry/extensions/gis/geographic/strategies/andoyer.hpp>

    //ReadanASCIIfilecontainingWKT's,fillavectoroftuples
    //Thetuplesconsistofatleast<0>ageometryand<1>anidentifyingstring
    template<typenameGeometry,typenameTuple,typenameBox>
    voidread_wkt(std::stringconst&filename,std::vector<Tuple>&tuples,Box&box)
    {
    std::ifstreamcpp_file(filename.c_str());
    if(cpp_file.is_open())
    {
    while(!cpp_file.eof())
    {
    std::stringline;
    std::getline(cpp_file,line);
    Geometrygeometry;
    boost::trim(line);
    if(!line.empty()&&!boost::starts_with(line,"#"))
    {
    std::stringname;

    //Splitat';',ifany
    std::string::size_typepos=line.find(";");
    if(pos!=std::string::npos)
    {
    name=line.substr(pos+1);
    line.erase(pos);

    boost::trim(line);
    boost::trim(name);
    }

    Geometrygeometry;
    boost::geometry::read_wkt(line,geometry);

    Tupletuple(geometry,name);

    tuples.push_back(tuple);
    boost::geometry::expand(box,boost::geometry::return_envelope<Box>(geometry));
    }
    }
    }
    }

    //Tocalculatedistance,declareandconstructastrategywithaverageearthradius
    boost::geometry::strategy::distance::haversine<double>consthaversine(6372795.0);

    //Definepropertiesforvertex
    template<typenamePoint>
    structbg_vertex_property
    {
    bg_vertex_property()
    {
    boost::geometry::assign_zero(location);
    }
    bg_vertex_property(Pointconst&loc)
    :location(loc)
    {
    }

    Pointlocation;
    };

    //Definepropertiesforedge
    template<typenameLinestring>
    structbg_edge_property
    {
    bg_edge_property(Linestringconst&line)
    :length(boost::geometry::length(line,haversine))
    ,m_line(line)
    {
    }

    inlineLinestringconst&line()const
    {
    returnm_line;
    }

    doublelength;
    private:
    Linestringm_line;
    };

    //Utilityfunctiontoaddavertextoagraph.Itmightexistalready.Thendonotinsert,
    //butreturnvertexdescriptorback.Itmightnotexist.Thenaddit(andreturn).
    //Toefficientlyhandlethis,astd::mapisused.
    template<typenameM,typenameK,typenameG>
    inlinetypenameboost::graph_traits<G>::vertex_descriptorfind_or_insert(M&map,Kconst&key,G&graph)
    {
    typenameM::const_iteratorit=map.find(key);
    if(it==map.end())
    {
    //Addavertextothegraph
    typenameboost::graph_traits<G>::vertex_descriptornew_vertex
    =boost::add_vertex(bg_vertex_property<typenameM::key_type>(key),graph);

    //Addtothemap,usingPOINTaskey
    map[key]=new_vertex;
    returnnew_vertex;
    }
    returnit->second;
    }

    template
    <
    typenameGraph,
    typenameRoadTupleVector,
    typenameCityTupleVector
    >
    voidadd_roads_and_connect_cities(Graph&graph,
    RoadTupleVectorconst&roads,
    CityTupleVector&cities)
    {
    typedeftypenameboost::range_value<RoadTupleVector>::typeroad_type;
    typedeftypenameboost::tuples::element<0,road_type>::typeline_type;
    typedeftypenameboost::geometry::point_type<line_type>::typepoint_type;

    typedeftypenameboost::graph_traits<Graph>::vertex_descriptorvertex_type;

    //Defineamaptobeusedduringgraphfilling
    //Mapsfrompointtovertex-id's
    typedefstd::map<point_type,vertex_type,boost::geometry::less<point_type>>map_type;
    map_typemap;

    //Fillthegraph
    BOOST_FOREACH(road_typeconst&road,roads)
    {
    line_typeconst&line=road.templateget<0>();
    //Findoraddbegin/endpointoftheseline
    vertex_typefrom=find_or_insert(map,line.front(),graph);
    vertex_typeto=find_or_insert(map,line.back(),graph);
    boost::add_edge(from,to,bg_edge_property<line_type>(line),graph);
    }

    //Findnearestgraphvertexforeachcity,usingthemap
    typedeftypenameboost::range_value<CityTupleVector>::typecity_type;
    BOOST_FOREACH(city_type&city,cities)
    {
    doublemin_distance=1e300;
    for(typenamemap_type::const_iteratorit=map.begin();it!=map.end();++it)
    {
    doubledist=boost::geometry::distance(it->first,city.templateget<0>());
    if(dist<min_distance)
    {
    min_distance=dist;
    //Setthevertex
    city.templateget<2>()=it->second;
    }
    }
    }
    }

    template<typenameGraph,typenameRoute>
    inlinevoidadd_edge_to_route(Graphconst&graph,
    typenameboost::graph_traits<Graph>::vertex_descriptorvertex1,
    typenameboost::graph_traits<Graph>::vertex_descriptorvertex2,
    Route&route)
    {
    std::pair
    <
    typenameboost::graph_traits<Graph>::edge_descriptor,
    bool
    >opt_edge=boost::edge(vertex1,vertex2,graph);
    if(opt_edge.second)
    {
    //Getpropertiesofedgeandofvertex
    bg_edge_property<Route>const&edge_prop=graph[opt_edge.first];
    bg_vertex_property
    <
    typenameboost::geometry::point_type<Route>::type
    >const&vertex_prop=graph[vertex2];

    //Dependingonhowedgeconnectstovertex,copyitforwardorbackward
    if(boost::geometry::equals(edge_prop.line().front(),vertex_prop.location))
    {
    std::copy(edge_prop.line().begin(),edge_prop.line().end(),
    std::back_inserter(route));
    }
    else
    {
    std::reverse_copy(edge_prop.line().begin(),edge_prop.line().end(),
    std::back_inserter(route));
    }
    }
    }

    template<typenameGraph,typenameRoute>
    inlinevoidbuild_route(Graphconst&graph,
    std::vector<typenameboost::graph_traits<Graph>::vertex_descriptor>const&predecessors,
    typenameboost::graph_traits<Graph>::vertex_descriptorvertex1,
    typenameboost::graph_traits<Graph>::vertex_descriptorvertex2,
    Route&route)
    {
    typedeftypenameboost::graph_traits<Graph>::vertex_descriptorvertex_type;
    vertex_typepred=predecessors[vertex2];

    add_edge_to_route(graph,vertex2,pred,route);
    while(pred!=vertex1)
    {
    add_edge_to_route(graph,predecessors[pred],pred,route);
    pred=predecessors[pred];
    }
    }

    intmain()
    {
    //DefineapointintheGeographiccoordinatesystem(currentlyspherical-equatorial)
    //(geographiccalculationsareinanextension;forsampleitmakesnodifference)
    typedefboost::geometry::model::point
    <
    double,2,boost::geometry::cs::spherical_equatorial<boost::geometry::degree>
    >point_type;

    typedefboost::geometry::model::linestring<point_type>line_type;

    //Definethegraph,lateroncontainingtheroadnetwork
    //Withthis,specifybundledpropertiesforvertexandedge,
    //asinhttp://www.boost.org/doc/libs/1_43_0/libs/graph/doc/bundles.html
    typedefboost::adjacency_list
    <
    boost::vecS,boost::vecS,boost::undirectedS
    ,bg_vertex_property<point_type>//bundled
    ,bg_edge_property<line_type>
    >graph_type;

    typedefboost::graph_traits<graph_type>::vertex_descriptorvertex_type;

    //Initaboundingbox,lateronusedtodefineSVGmap
    boost::geometry::model::box<point_type>box;
    boost::geometry::assign_inverse(box);

    graph_typegraph;

    //Readthecities
    typedefboost::tuple<point_type,std::string,vertex_type>city_type;
    std::vector<city_type>cities;
    read_wkt<point_type>("data/cities.wkt",cities,box);

    //Readtheroadnetwork
    typedefboost::tuple<line_type,std::string>road_type;
    std::vector<road_type>roads;
    read_wkt<line_type>("data/roads.wkt",roads,box);

    //Addroadsandconnectcities
    add_roads_and_connect_cities(graph,roads,cities);

    doubleconstkm=1000.0;
    std::cout<<"distances,allinKM"<<std::endl
    <<std::fixed<<std::setprecision(0);

    //Mainfunctionality:calculateshortestroutesfrom/toallcities

    //Forthefirstone,thecompleterouteisstoredasalinestring
    boolfirst=true;
    line_typeroute;

    intconstn=boost::num_vertices(graph);
    BOOST_FOREACH(city_typeconst&city1,cities)
    {
    std::vector<vertex_type>predecessors(n);
    std::vector<double>costs(n);

    //CallDijkstra(withoutnamed-parametertobecompatiblewithallVC)
    boost::dijkstra_shortest_paths(graph,city1.get<2>(),
    &predecessors[0],&costs[0],
    boost::get(&bg_edge_property<line_type>::length,graph),
    boost::get(boost::vertex_index,graph),
    std::less<double>(),std::plus<double>(),
    (std::numeric_limits<double>::max)(),double(),
    boost::dijkstra_visitor<boost::null_visitor>());

    BOOST_FOREACH(city_typeconst&city2,cities)
    {
    if(!boost::equals(city1.get<1>(),city2.get<1>()))
    {
    doubledistance=costs[city2.get<2>()]/km;
    doubleacof=boost::geometry::distance(city1.get<0>(),city2.get<0>(),haversine)/km;

    std::cout
    <<std::setiosflags(std::ios_base::left)<<std::setw(15)
    <<city1.get<1>()<<"-"
    <<std::setiosflags(std::ios_base::left)<<std::setw(15)
    <<city2.get<1>()
    <<"->throughtheair:"<<std::setw(4)<<acof
    <<",overtheroad:"<<std::setw(4)<<distance
    <<std::endl;

    if(first)
    {
    build_route(graph,predecessors,
    city1.get<2>(),city2.get<2>(),
    route);
    first=false;
    }
    }
    }
    }

    #ifdefined(HAVE_SVG)
    //CreatetheSVG
    std::ofstreamstream("routes.svg");
    boost::geometry::svg_mapper<point_type>mapper(stream,600,600);

    //Maproads
    BOOST_FOREACH(road_typeconst&road,roads)
    {
    mapper.add(road.get<0>());
    }

    BOOST_FOREACH(road_typeconst&road,roads)
    {
    mapper.map(road.get<0>(),
    "stroke:rgb(128,128,128);stroke-width:1");
    }

    mapper.map(route,
    "stroke:rgb(0,255,0);stroke-width:6;opacity:0.5");

    //Mapcities
    BOOST_FOREACH(city_typeconst&city,cities)
    {
    mapper.map(city.get<0>(),
    "fill:rgb(255,255,0);stroke:rgb(0,0,0);stroke-width:1");
    mapper.text(city.get<0>(),city.get<1>(),
    "fill:rgb(0,0,0);font-family:Arial;font-size:10px",5,5);
    }
    #endif

    return0;
    }