I am looking for a way to include turn restrictions and/or turn penalties in my application of Boost Graph Library, using a directed graph. I need to restrict for instance U-turns (which can be a very high penalty if that is the best way).
I cannot find an explicit mechanism in Boost Graph to add such penalties / restrictions, what would be the best way to deal with turn restrictions?
The only solution I see so far is expanding the graph with 'internal edges' for each possible turn in vertices, omitting 'internal edges' for restricted turns. This seems very brute force to me, is there a better way?
Assume there are two sources A and E, and the shortest path to each of the vertices is calculated using Dijkstra (see code example below).
The two shortest path trees are (output of printShortestPath() ):
Shortest path from A to all vertices:
distances and parents:
distance(A) = 0, parent(A) = A
distance(B) = 100, parent(B) = A
distance(C) = 200, parent(C) = B
distance(D) = 200, parent(D) = B
distance(E) = 1.79769e+308, parent(E) = E
-------------
Shortest path from E to all vertices:
distances and parents:
distance(A) = 1.79769e+308, parent(A) = A
distance(B) = 100, parent(B) = E
distance(C) = 200, parent(C) = B
distance(D) = 200, parent(D) = B
distance(E) = 0, parent(E) = E
What is an elegant way to prohibit this turning (e1 to e4) in Boost::Graph?
A straightforward solution would be expanding the graph to have additional edges representing turning movements (with high cost for prohibited ones), but I hope there is a more elegant way.
Code:
#include <boost/config.hpp>
#include <iostream>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <QString>
#include <vector>
using namespace boost;
struct GraphNode
{
GraphNode() {}
GraphNode(const QString& name_):name(name_) {}
QString name;
};
struct GraphLink
{
GraphLink() {}
GraphLink(const QString& name_, double length_, double travelTime_):name(name_),length(length_), travelTime(travelTime_) {}
QString name;
double length; // in meters
double travelTime; // in seconds
};
typedef boost::adjacency_list<boost::listS, boost::vecS, boost::directedS, GraphNode, GraphLink> NetworkGraph;
typedef graph_traits < NetworkGraph >::vertex_descriptor vertex_descriptor;
typedef std::vector<decltype (GraphLink::length)> distancesT;
void printShortestPath (const NetworkGraph& map, distancesT distances,std::vector<vertex_descriptor> p )
{
std::cout << "distances and parents:" << std::endl;
graph_traits < NetworkGraph >::vertex_iterator vi, vend;
for (auto vs=vertices(map); vs.first!=vs.second;++vs.first)
{
auto currEdge=map[*vs.first];
auto parent=p[*vs.first];
QString parentName=map[parent].name;
QString name =currEdge.name;
std::cout << "distance(" << name.toStdString() << ") = " << distances[*vs.first] << ", ";
std::cout << "parent(" << name.toStdString() << ") = " << parentName.toStdString() << std::
endl;
}
}
int main(int, char *[])
{
//Create the vertices
NetworkGraph map;
NetworkGraph::vertex_descriptor vertexA = add_vertex(map);
map[vertexA].name ="A";
NetworkGraph::vertex_descriptor vertexB = add_vertex(map);
map[vertexB].name ="B";
NetworkGraph::vertex_descriptor vertexC = add_vertex(map);
map[vertexC].name ="C";
NetworkGraph::vertex_descriptor vertexD = add_vertex(map);
map[vertexD].name ="D";
NetworkGraph::vertex_descriptor vertexE = add_vertex(map);
map[vertexE].name ="E";
// Create the edges
NetworkGraph::edge_descriptor e1 = add_edge(vertexA,vertexB,map).first;
map[e1].name ="e1";
map[e1].length =100.0;
NetworkGraph::edge_descriptor e2 = add_edge(vertexB,vertexC,map).first;
map[e2].name ="e2";
map[e2].length =100.0;
NetworkGraph::edge_descriptor e3 = add_edge(vertexC,vertexD,map).first;
map[e3].name ="e3";
map[e3].length =100.0;
NetworkGraph::edge_descriptor e4 = add_edge(vertexB,vertexD,map).first;
map[e4].name ="e4";
map[e4].length =100.0;
NetworkGraph::edge_descriptor e5 = add_edge(vertexE,vertexB,map).first;
map[e5].name ="e5";
map[e5].length =100.0;
distancesT distances (num_vertices(map)); // distances
std::vector<vertex_descriptor> p (num_vertices(map)); // parents
//calculate shortest paths from vertex A using Dijkstra, based on GraphLink::length as edge cost
dijkstra_shortest_paths (map,
vertexA,
weight_map (get(&GraphLink::length, map))
.distance_map (make_iterator_property_map(distances.begin(), get(vertex_index, map)))
.predecessor_map (make_iterator_property_map(p.begin(), get(vertex_index, map))) );
std::cout << "Shortest path from A to all vertices: " << std::endl;
printShortestPath (map, distances, p);
//calculate shortest paths from vertex E using Dijkstra, based on GraphLink::length as edge cost
dijkstra_shortest_paths (map,
vertexE,
weight_map (get(&GraphLink::length, map))
.distance_map (make_iterator_property_map(distances.begin(), get(vertex_index, map)))
.predecessor_map (make_iterator_property_map(p.begin(), get(vertex_index, map))) );
std::cout << "-------------" << std::endl;
std::cout << "Shortest path from E to all vertices: " << std::endl;
printShortestPath (map, distances, p);
return EXIT_SUCCESS;
}