Merge branch 'develop/AlternativeRoutes'
This commit is contained in:
commit
176fa301d3
@ -351,7 +351,7 @@ public:
|
||||
for ( int position = firstIndependent ; position < last; ++position ) {
|
||||
NodeID x = remainingNodes[position].first;
|
||||
_Contract< false > ( data, x );
|
||||
nodePriority[x] = -1;
|
||||
//nodePriority[x] = -1;
|
||||
}
|
||||
std::sort( data->insertedEdges.begin(), data->insertedEdges.end() );
|
||||
}
|
||||
|
@ -248,7 +248,7 @@ void EdgeBasedGraphFactory::Run(const char * originalEdgeDataFilename) {
|
||||
if(turnInstruction == TurnInstructions.UTurn)
|
||||
distance += uturnPenalty;
|
||||
if(!edgeData1.isAccessRestricted && edgeData2.isAccessRestricted) {
|
||||
distance += TurnInstructions.AccessRestrictionPenaly;
|
||||
distance += TurnInstructions.AccessRestrictionPenalty;
|
||||
turnInstruction |= TurnInstructions.AccessRestrictionFlag;
|
||||
}
|
||||
|
||||
|
@ -72,6 +72,4 @@ struct QueryEdge {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* QUERYEDGE_H_ */
|
||||
|
@ -30,6 +30,10 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
||||
#include "BinaryHeap.h"
|
||||
#include "NodeInformationHelpDesk.h"
|
||||
#include "PhantomNodes.h"
|
||||
#include "../RoutingAlgorithms/AlternativePathRouting.h"
|
||||
#include "../RoutingAlgorithms/BasicRoutingInterface.h"
|
||||
#include "../RoutingAlgorithms/ShortestPathRouting.h"
|
||||
|
||||
#include "../Util/StringUtil.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
@ -38,501 +42,130 @@ struct _HeapData {
|
||||
_HeapData( NodeID p ) : parent(p) { }
|
||||
};
|
||||
|
||||
typedef boost::thread_specific_ptr<BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage<NodeID, int> > > HeapPtr;
|
||||
typedef boost::thread_specific_ptr<BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage<NodeID, int> > > SearchEngineHeapPtr;
|
||||
|
||||
template<class EdgeData, class GraphT>
|
||||
struct SearchEngineData {
|
||||
typedef SearchEngineHeapPtr HeapPtr;
|
||||
typedef GraphT Graph;
|
||||
SearchEngineData(GraphT * g, NodeInformationHelpDesk * nh, std::vector<string> & n) :graph(g), nodeHelpDesk(nh), names(n) {}
|
||||
const GraphT * graph;
|
||||
NodeInformationHelpDesk * nodeHelpDesk;
|
||||
std::vector<string> & names;
|
||||
static HeapPtr forwardHeap;
|
||||
static HeapPtr backwardHeap;
|
||||
static HeapPtr forwardHeap2;
|
||||
static HeapPtr backwardHeap2;
|
||||
static HeapPtr forwardHeap3;
|
||||
static HeapPtr backwardHeap3;
|
||||
|
||||
inline void InitializeOrClearFirstThreadLocalStorage() {
|
||||
if(!forwardHeap.get()) {
|
||||
forwardHeap.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage<NodeID, int> >(nodeHelpDesk->getNumberOfNodes()));
|
||||
}
|
||||
else
|
||||
forwardHeap->Clear();
|
||||
|
||||
if(!backwardHeap.get()) {
|
||||
backwardHeap.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage<NodeID, int> >(nodeHelpDesk->getNumberOfNodes()));
|
||||
}
|
||||
else
|
||||
backwardHeap->Clear();
|
||||
}
|
||||
|
||||
inline void InitializeOrClearSecondThreadLocalStorage() {
|
||||
if(!forwardHeap2.get()) {
|
||||
forwardHeap2.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage<NodeID, int> >(nodeHelpDesk->getNumberOfNodes()));
|
||||
}
|
||||
else
|
||||
forwardHeap2->Clear();
|
||||
|
||||
if(!backwardHeap2.get()) {
|
||||
backwardHeap2.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage<NodeID, int> >(nodeHelpDesk->getNumberOfNodes()));
|
||||
}
|
||||
else
|
||||
backwardHeap2->Clear();
|
||||
}
|
||||
|
||||
inline void InitializeOrClearThirdThreadLocalStorage() {
|
||||
if(!forwardHeap3.get()) {
|
||||
forwardHeap3.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage<NodeID, int> >(nodeHelpDesk->getNumberOfNodes()));
|
||||
}
|
||||
else
|
||||
forwardHeap3->Clear();
|
||||
|
||||
if(!backwardHeap3.get()) {
|
||||
backwardHeap3.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage<NodeID, int> >(nodeHelpDesk->getNumberOfNodes()));
|
||||
}
|
||||
else
|
||||
backwardHeap3->Clear();
|
||||
}
|
||||
};
|
||||
|
||||
template<class EdgeData, class GraphT>
|
||||
class SearchEngine {
|
||||
private:
|
||||
const GraphT * _graph;
|
||||
NodeInformationHelpDesk * nodeHelpDesk;
|
||||
std::vector<string> & _names;
|
||||
static HeapPtr _forwardHeap;
|
||||
static HeapPtr _backwardHeap;
|
||||
static HeapPtr _forwardHeap2;
|
||||
static HeapPtr _backwardHeap2;
|
||||
typedef SearchEngineData<EdgeData, GraphT> SearchEngineDataT;
|
||||
SearchEngineDataT _queryData;
|
||||
|
||||
inline double absDouble(double input) { if(input < 0) return input*(-1); else return input;}
|
||||
public:
|
||||
SearchEngine(GraphT * g, NodeInformationHelpDesk * nh, std::vector<string> & n) : _graph(g), nodeHelpDesk(nh), _names(n) {}
|
||||
ShortestPathRouting<SearchEngineDataT> shortestPath;
|
||||
AlternativeRouting<SearchEngineDataT> alternativePaths;
|
||||
|
||||
SearchEngine(GraphT * g, NodeInformationHelpDesk * nh, std::vector<string> & n) :
|
||||
_queryData(g, nh, n),
|
||||
shortestPath(_queryData),
|
||||
alternativePaths(_queryData)
|
||||
{}
|
||||
~SearchEngine() {}
|
||||
|
||||
inline const void GetCoordinatesForNodeID(NodeID id, _Coordinate& result) const {
|
||||
result.lat = nodeHelpDesk->getLatitudeOfNode(id);
|
||||
result.lon = nodeHelpDesk->getLongitudeOfNode(id);
|
||||
}
|
||||
|
||||
inline void InitializeThreadLocalStorageIfNecessary() {
|
||||
if(!_forwardHeap.get()) {
|
||||
_forwardHeap.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage<NodeID, int> >(nodeHelpDesk->getNumberOfNodes()));
|
||||
}
|
||||
else
|
||||
_forwardHeap->Clear();
|
||||
|
||||
if(!_backwardHeap.get()) {
|
||||
_backwardHeap.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage<NodeID, int> >(nodeHelpDesk->getNumberOfNodes()));
|
||||
}
|
||||
else
|
||||
_backwardHeap->Clear();
|
||||
}
|
||||
|
||||
inline void InitializeThreadLocalViaStorageIfNecessary() {
|
||||
if(!_forwardHeap2.get()) {
|
||||
_forwardHeap2.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage<NodeID, int> >(nodeHelpDesk->getNumberOfNodes()));
|
||||
}
|
||||
else
|
||||
_forwardHeap2->Clear();
|
||||
|
||||
if(!_backwardHeap2.get()) {
|
||||
_backwardHeap2.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData, UnorderedMapStorage<NodeID, int> >(nodeHelpDesk->getNumberOfNodes()));
|
||||
}
|
||||
else
|
||||
_backwardHeap2->Clear();
|
||||
}
|
||||
|
||||
template<class ContainerT>
|
||||
void _RemoveConsecutiveDuplicatesFromContainer(ContainerT & packedPath) {
|
||||
//remove consecutive duplicates
|
||||
typename ContainerT::iterator it;
|
||||
// using default comparison:
|
||||
it = std::unique(packedPath.begin(), packedPath.end());
|
||||
packedPath.resize(it - packedPath.begin());
|
||||
}
|
||||
|
||||
int ComputeViaRoute(std::vector<PhantomNodes> & phantomNodesVector, std::vector<_PathData> & unpackedPath) {
|
||||
BOOST_FOREACH(PhantomNodes & phantomNodePair, phantomNodesVector) {
|
||||
if(!phantomNodePair.AtLeastOnePhantomNodeIsUINTMAX())
|
||||
return INT_MAX;
|
||||
}
|
||||
int distance1 = 0;
|
||||
int distance2 = 0;
|
||||
|
||||
bool searchFrom1stStartNode(true);
|
||||
bool searchFrom2ndStartNode(true);
|
||||
NodeID middle1 = ( NodeID ) UINT_MAX;
|
||||
NodeID middle2 = ( NodeID ) UINT_MAX;
|
||||
std::deque<NodeID> packedPath1;
|
||||
std::deque<NodeID> packedPath2;
|
||||
//Get distance to next pair of target nodes.
|
||||
BOOST_FOREACH(PhantomNodes & phantomNodePair, phantomNodesVector) {
|
||||
InitializeThreadLocalStorageIfNecessary();
|
||||
InitializeThreadLocalViaStorageIfNecessary();
|
||||
|
||||
int _localUpperbound1 = INT_MAX;
|
||||
int _localUpperbound2 = INT_MAX;
|
||||
|
||||
_forwardHeap->Clear();
|
||||
_forwardHeap2->Clear();
|
||||
//insert new starting nodes into forward heap, adjusted by previous distances.
|
||||
if(searchFrom1stStartNode) {
|
||||
_forwardHeap->Insert(phantomNodePair.startPhantom.edgeBasedNode, -phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode);
|
||||
_forwardHeap2->Insert(phantomNodePair.startPhantom.edgeBasedNode, -phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode);
|
||||
// INFO("a 1,2)forw insert " << phantomNodePair.startPhantom.edgeBasedNode << " with weight " << phantomNodePair.startPhantom.weight1);
|
||||
// } else {
|
||||
// INFO("Skipping first start node");
|
||||
}
|
||||
if(phantomNodePair.startPhantom.isBidirected() && searchFrom2ndStartNode) {
|
||||
_forwardHeap->Insert(phantomNodePair.startPhantom.edgeBasedNode+1, -phantomNodePair.startPhantom.weight2, phantomNodePair.startPhantom.edgeBasedNode+1);
|
||||
_forwardHeap2->Insert(phantomNodePair.startPhantom.edgeBasedNode+1, -phantomNodePair.startPhantom.weight2, phantomNodePair.startPhantom.edgeBasedNode+1);
|
||||
// INFO("b 1,2)forw insert " << phantomNodePair.startPhantom.edgeBasedNode+1 << " with weight " << -phantomNodePair.startPhantom.weight1);
|
||||
// } else if(!searchFrom2ndStartNode) {
|
||||
// INFO("Skipping second start node");
|
||||
}
|
||||
|
||||
_backwardHeap->Clear();
|
||||
_backwardHeap2->Clear();
|
||||
//insert new backward nodes into backward heap, unadjusted.
|
||||
_backwardHeap->Insert(phantomNodePair.targetPhantom.edgeBasedNode, phantomNodePair.targetPhantom.weight1, phantomNodePair.targetPhantom.edgeBasedNode);
|
||||
// INFO("1) back insert " << phantomNodePair.targetPhantom.edgeBasedNode << " with weight " << phantomNodePair.targetPhantom.weight1);
|
||||
if(phantomNodePair.targetPhantom.isBidirected() ) {
|
||||
// INFO("2) back insert " << phantomNodePair.targetPhantom.edgeBasedNode+1 << " with weight " << phantomNodePair.targetPhantom.weight2);
|
||||
_backwardHeap2->Insert(phantomNodePair.targetPhantom.edgeBasedNode+1, phantomNodePair.targetPhantom.weight2, phantomNodePair.targetPhantom.edgeBasedNode+1);
|
||||
}
|
||||
int offset = (phantomNodePair.startPhantom.isBidirected() ? std::max(phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.weight2) : phantomNodePair.startPhantom.weight1) ;
|
||||
offset += (phantomNodePair.targetPhantom.isBidirected() ? std::max(phantomNodePair.targetPhantom.weight1, phantomNodePair.targetPhantom.weight2) : phantomNodePair.targetPhantom.weight1) ;
|
||||
|
||||
//run two-Target Dijkstra routing step.
|
||||
while(_forwardHeap->Size() + _backwardHeap->Size() > 0){
|
||||
if(_forwardHeap->Size() > 0){
|
||||
_RoutingStep<true>(_forwardHeap, _backwardHeap, &middle1, &_localUpperbound1, 2*offset);
|
||||
}
|
||||
if(_backwardHeap->Size() > 0){
|
||||
_RoutingStep<false>(_backwardHeap, _forwardHeap, &middle1, &_localUpperbound1, 2*offset);
|
||||
}
|
||||
}
|
||||
if(_backwardHeap2->Size() > 0) {
|
||||
while(_forwardHeap2->Size() + _backwardHeap2->Size() > 0){
|
||||
if(_forwardHeap2->Size() > 0){
|
||||
_RoutingStep<true>(_forwardHeap2, _backwardHeap2, &middle2, &_localUpperbound2, 2*offset);
|
||||
}
|
||||
if(_backwardHeap2->Size() > 0){
|
||||
_RoutingStep<false>(_backwardHeap2, _forwardHeap2, &middle2, &_localUpperbound2, 2*offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
// INFO("upperbound1: " << _localUpperbound1 << ", distance1: " << distance1);
|
||||
// INFO("upperbound2: " << _localUpperbound2 << ", distance2: " << distance2);
|
||||
|
||||
//No path found for both target nodes?
|
||||
if(INT_MAX == _localUpperbound1 && INT_MAX == _localUpperbound2) {
|
||||
return INT_MAX;
|
||||
}
|
||||
if(UINT_MAX == middle1) {
|
||||
searchFrom1stStartNode = false;
|
||||
// INFO("Next Search will not start from 1st");
|
||||
} else {
|
||||
// INFO("Next Search will start from 1st");
|
||||
searchFrom1stStartNode = true;
|
||||
}
|
||||
if(UINT_MAX == middle2) {
|
||||
searchFrom2ndStartNode = false;
|
||||
// INFO("Next Search will not start from 2nd");
|
||||
} else {
|
||||
searchFrom2ndStartNode = true;
|
||||
// INFO("Next Search will start from 2nd");
|
||||
}
|
||||
|
||||
//Was at most one of the two paths not found?
|
||||
assert(!(INT_MAX == distance1 && INT_MAX == distance2));
|
||||
|
||||
// INFO("middle1: " << middle1);
|
||||
|
||||
//Unpack paths if they exist
|
||||
std::deque<NodeID> temporaryPackedPath1;
|
||||
std::deque<NodeID> temporaryPackedPath2;
|
||||
if(INT_MAX != _localUpperbound1) {
|
||||
_RetrievePackedPathFromHeap(_forwardHeap, _backwardHeap, middle1, temporaryPackedPath1);
|
||||
// INFO("temporaryPackedPath1 ends with " << *(temporaryPackedPath1.end()-1) );
|
||||
}
|
||||
// INFO("middle2: " << middle2);
|
||||
|
||||
if(INT_MAX != _localUpperbound2) {
|
||||
_RetrievePackedPathFromHeap(_forwardHeap2, _backwardHeap2, middle2, temporaryPackedPath2);
|
||||
// INFO("temporaryPackedPath2 ends with " << *(temporaryPackedPath2.end()-1) );
|
||||
}
|
||||
|
||||
//if one of the paths was not found, replace it with the other one.
|
||||
if(0 == temporaryPackedPath1.size()) {
|
||||
// INFO("Deleting path 1");
|
||||
temporaryPackedPath1.insert(temporaryPackedPath1.end(), temporaryPackedPath2.begin(), temporaryPackedPath2.end());
|
||||
_localUpperbound1 = _localUpperbound2;
|
||||
}
|
||||
if(0 == temporaryPackedPath2.size()) {
|
||||
// INFO("Deleting path 2");
|
||||
temporaryPackedPath2.insert(temporaryPackedPath2.end(), temporaryPackedPath1.begin(), temporaryPackedPath1.end());
|
||||
_localUpperbound2 = _localUpperbound1;
|
||||
}
|
||||
|
||||
assert(0 < temporaryPackedPath1.size() && 0 < temporaryPackedPath2.size());
|
||||
|
||||
//Plug paths together, s.t. end of packed path is begin of temporary packed path
|
||||
if(0 < packedPath1.size() && 0 < packedPath2.size() ) {
|
||||
// INFO("Both paths are non-empty");
|
||||
if( *(temporaryPackedPath1.begin()) == *(temporaryPackedPath2.begin())) {
|
||||
// INFO("both paths start with the same node:" << *(temporaryPackedPath1.begin()));
|
||||
//both new route segments start with the same node, thus one of the packedPath must go.
|
||||
assert( (packedPath1.size() == packedPath2.size() ) || (*(packedPath1.end()-1) != *(packedPath2.end()-1)) );
|
||||
if( *(packedPath1.end()-1) == *(temporaryPackedPath1.begin())) {
|
||||
// INFO("Deleting packedPath2 that ends with " << *(packedPath2.end()-1) << ", other ends with " << *(packedPath1.end()-1));
|
||||
packedPath2.clear();
|
||||
packedPath2.insert(packedPath2.end(), packedPath1.begin(), packedPath1.end());
|
||||
distance2 = distance1;
|
||||
// INFO("packedPath2 now ends with " << *(packedPath2.end()-1));
|
||||
} else {
|
||||
// INFO("Deleting path1 that ends with " << *(packedPath1.end()-1) << ", other ends with " << *(packedPath2.end()-1));
|
||||
packedPath1.clear();
|
||||
packedPath1.insert(packedPath1.end(), packedPath2.begin(), packedPath2.end());
|
||||
distance1 = distance2;
|
||||
// INFO("Path1 now ends with " << *(packedPath1.end()-1));
|
||||
}
|
||||
} else {
|
||||
//packed paths 1 and 2 may need to switch.
|
||||
if(*(packedPath1.end()-1) != *(temporaryPackedPath1.begin())) {
|
||||
// INFO("Switching");
|
||||
packedPath1.swap(packedPath2);
|
||||
std::swap(distance1, distance2);
|
||||
}
|
||||
}
|
||||
}
|
||||
packedPath1.insert(packedPath1.end(), temporaryPackedPath1.begin(), temporaryPackedPath1.end());
|
||||
packedPath2.insert(packedPath2.end(), temporaryPackedPath2.begin(), temporaryPackedPath2.end());
|
||||
|
||||
if( (packedPath1.back() == packedPath2.back()) && phantomNodePair.targetPhantom.isBidirected() ) {
|
||||
// INFO("both paths end in same direction on bidirected edge, make sure start only start with : " << packedPath1.back());
|
||||
|
||||
NodeID lastNodeID = packedPath2.back();
|
||||
searchFrom1stStartNode &= !(lastNodeID == phantomNodePair.targetPhantom.edgeBasedNode+1);
|
||||
searchFrom2ndStartNode &= !(lastNodeID == phantomNodePair.targetPhantom.edgeBasedNode);
|
||||
// INFO("Next search from node " << phantomNodePair.targetPhantom.edgeBasedNode << ": " << (searchFrom1stStartNode ? "yes" : "no") );
|
||||
// INFO("Next search from node " << phantomNodePair.targetPhantom.edgeBasedNode+1 << ": " << (searchFrom2ndStartNode ? "yes" : "no") );
|
||||
}
|
||||
|
||||
distance1 += _localUpperbound1;
|
||||
distance2 += _localUpperbound2;
|
||||
}
|
||||
|
||||
// INFO("length path1: " << distance1);
|
||||
// INFO("length path2: " << distance2);
|
||||
if(distance1 <= distance2){
|
||||
//remove consecutive duplicates
|
||||
// std::cout << "unclean 1: ";
|
||||
// for(unsigned i = 0; i < packedPath1.size(); ++i)
|
||||
// std::cout << packedPath1[i] << " ";
|
||||
// std::cout << std::endl;
|
||||
_RemoveConsecutiveDuplicatesFromContainer(packedPath1);
|
||||
// std::cout << "cleaned 1: ";
|
||||
// for(unsigned i = 0; i < packedPath1.size(); ++i)
|
||||
// std::cout << packedPath1[i] << " ";
|
||||
// std::cout << std::endl;
|
||||
_UnpackPath(packedPath1, unpackedPath);
|
||||
} else {
|
||||
// std::cout << "unclean 2: ";
|
||||
// for(unsigned i = 0; i < packedPath2.size(); ++i)
|
||||
// std::cout << packedPath2[i] << " ";
|
||||
// std::cout << std::endl;
|
||||
_RemoveConsecutiveDuplicatesFromContainer(packedPath2);
|
||||
// std::cout << "cleaned 2: ";
|
||||
// for(unsigned i = 0; i < packedPath2.size(); ++i)
|
||||
// std::cout << packedPath2[i] << " ";
|
||||
// std::cout << std::endl;
|
||||
_UnpackPath(packedPath2, unpackedPath);
|
||||
}
|
||||
// INFO("Found via route with distance " << std::min(distance1, distance2));
|
||||
return std::min(distance1, distance2);
|
||||
}
|
||||
|
||||
int ComputeRoute(PhantomNodes & phantomNodes, std::vector<_PathData> & path) {
|
||||
int _upperbound = INT_MAX;
|
||||
if(!phantomNodes.AtLeastOnePhantomNodeIsUINTMAX())
|
||||
return _upperbound;
|
||||
|
||||
InitializeThreadLocalStorageIfNecessary();
|
||||
NodeID middle = ( NodeID ) UINT_MAX;
|
||||
//insert start and/or target node of start edge
|
||||
_forwardHeap->Insert(phantomNodes.startPhantom.edgeBasedNode, -phantomNodes.startPhantom.weight1, phantomNodes.startPhantom.edgeBasedNode);
|
||||
// INFO("a) forw insert " << phantomNodes.startPhantom.edgeBasedNode << ", weight: " << -phantomNodes.startPhantom.weight1);
|
||||
if(phantomNodes.startPhantom.isBidirected() ) {
|
||||
// INFO("b) forw insert " << phantomNodes.startPhantom.edgeBasedNode+1 << ", weight: " << -phantomNodes.startPhantom.weight2);
|
||||
_forwardHeap->Insert(phantomNodes.startPhantom.edgeBasedNode+1, -phantomNodes.startPhantom.weight2, phantomNodes.startPhantom.edgeBasedNode+1);
|
||||
}
|
||||
//insert start and/or target node of target edge id
|
||||
_backwardHeap->Insert(phantomNodes.targetPhantom.edgeBasedNode, phantomNodes.targetPhantom.weight1, phantomNodes.targetPhantom.edgeBasedNode);
|
||||
// INFO("c) back insert " << phantomNodes.targetPhantom.edgeBasedNode << ", weight: " << phantomNodes.targetPhantom.weight1);
|
||||
if(phantomNodes.targetPhantom.isBidirected() ) {
|
||||
_backwardHeap->Insert(phantomNodes.targetPhantom.edgeBasedNode+1, phantomNodes.targetPhantom.weight2, phantomNodes.targetPhantom.edgeBasedNode+1);
|
||||
// INFO("d) back insert " << phantomNodes.targetPhantom.edgeBasedNode+1 << ", weight: " << phantomNodes.targetPhantom.weight2);
|
||||
}
|
||||
int offset = (phantomNodes.startPhantom.isBidirected() ? std::max(phantomNodes.startPhantom.weight1, phantomNodes.startPhantom.weight2) : phantomNodes.startPhantom.weight1) ;
|
||||
offset += (phantomNodes.targetPhantom.isBidirected() ? std::max(phantomNodes.targetPhantom.weight1, phantomNodes.targetPhantom.weight2) : phantomNodes.targetPhantom.weight1) ;
|
||||
while(_forwardHeap->Size() + _backwardHeap->Size() > 0){
|
||||
if(_forwardHeap->Size() > 0){
|
||||
_RoutingStep<true>(_forwardHeap, _backwardHeap, &middle, &_upperbound, 2*offset);
|
||||
}
|
||||
if(_backwardHeap->Size() > 0){
|
||||
_RoutingStep<false>(_backwardHeap, _forwardHeap, &middle, &_upperbound, 2*offset);
|
||||
}
|
||||
}
|
||||
// INFO("dist: " << _upperbound);
|
||||
if ( _upperbound == INT_MAX ) {
|
||||
return _upperbound;
|
||||
}
|
||||
std::deque<NodeID> packedPath;
|
||||
_RetrievePackedPathFromHeap(_forwardHeap, _backwardHeap, middle, packedPath);
|
||||
|
||||
//Setting weights to correspond with that of the actual chosen path
|
||||
// if(packedPath[0] == phantomNodes.startPhantom.edgeBasedNode && phantomNodes.startPhantom.isBidirected()) {
|
||||
// INFO("Setting weight1=" << phantomNodes.startPhantom.weight1 << " to that of weight2=" << phantomNodes.startPhantom.weight2);
|
||||
// phantomNodes.startPhantom.weight1 = phantomNodes.startPhantom.weight2;
|
||||
// } else {
|
||||
// INFO("Setting weight2=" << phantomNodes.startPhantom.weight2 << " to that of weight1=" << phantomNodes.startPhantom.weight1);
|
||||
// phantomNodes.startPhantom.weight2 = phantomNodes.startPhantom.weight1;
|
||||
// }
|
||||
// std::cout << "0: ";
|
||||
// for(unsigned i = 0; i < packedPath.size(); ++i)
|
||||
// std::cout << packedPath[i] << " ";
|
||||
// std::cout << std::endl;
|
||||
|
||||
_UnpackPath(packedPath, path);
|
||||
return _upperbound;
|
||||
result.lat = _queryData.nodeHelpDesk->getLatitudeOfNode(id);
|
||||
result.lon = _queryData.nodeHelpDesk->getLongitudeOfNode(id);
|
||||
}
|
||||
|
||||
inline void FindRoutingStarts(const _Coordinate & start, const _Coordinate & target, PhantomNodes & routingStarts) const {
|
||||
nodeHelpDesk->FindRoutingStarts(start, target, routingStarts);
|
||||
_queryData.nodeHelpDesk->FindRoutingStarts(start, target, routingStarts);
|
||||
}
|
||||
|
||||
inline void FindPhantomNodeForCoordinate(const _Coordinate & location, PhantomNode & result) const {
|
||||
nodeHelpDesk->FindPhantomNodeForCoordinate(location, result);
|
||||
_queryData.nodeHelpDesk->FindPhantomNodeForCoordinate(location, result);
|
||||
}
|
||||
|
||||
inline NodeID GetNameIDForOriginDestinationNodeID(const NodeID s, const NodeID t) const {
|
||||
if(s == t)
|
||||
return 0;
|
||||
|
||||
EdgeID e = _graph->FindEdge(s, t);
|
||||
EdgeID e = _queryData.graph->FindEdge(s, t);
|
||||
if(e == UINT_MAX)
|
||||
e = _graph->FindEdge( t, s );
|
||||
e = _queryData.graph->FindEdge( t, s );
|
||||
if(UINT_MAX == e) {
|
||||
return 0;
|
||||
}
|
||||
assert(e != UINT_MAX);
|
||||
const EdgeData ed = _graph->GetEdgeData(e);
|
||||
const EdgeData ed = _queryData.graph->GetEdgeData(e);
|
||||
return ed.via;
|
||||
}
|
||||
|
||||
inline std::string GetEscapedNameForNameID(const unsigned nameID) const {
|
||||
return ((nameID >= _names.size() || nameID == 0) ? std::string("") : HTMLEntitize(_names.at(nameID)));
|
||||
return ((nameID >= _queryData.names.size() || nameID == 0) ? std::string("") : HTMLEntitize(_queryData.names.at(nameID)));
|
||||
}
|
||||
|
||||
inline std::string GetEscapedNameForEdgeBasedEdgeID(const unsigned edgeID) const {
|
||||
const unsigned nameID = _graph->GetEdgeData(edgeID).nameID1;
|
||||
const unsigned nameID = _queryData.graph->GetEdgeData(edgeID).nameID1;
|
||||
return GetEscapedNameForNameID(nameID);
|
||||
}
|
||||
private:
|
||||
inline void _RetrievePackedPathFromHeap(HeapPtr & _fHeap, HeapPtr & _bHeap, const NodeID middle, std::deque<NodeID>& packedPath) {
|
||||
NodeID pathNode = middle;
|
||||
if(_fHeap->GetData(pathNode).parent != middle) {
|
||||
do {
|
||||
pathNode = _fHeap->GetData(pathNode).parent;
|
||||
|
||||
packedPath.push_front(pathNode);
|
||||
}while(pathNode != _fHeap->GetData(pathNode).parent);
|
||||
}
|
||||
packedPath.push_back(middle);
|
||||
pathNode = middle;
|
||||
if(_bHeap->GetData(pathNode).parent != middle) {
|
||||
do{
|
||||
pathNode = _bHeap->GetData(pathNode).parent;
|
||||
packedPath.push_back(pathNode);
|
||||
} while (pathNode != _bHeap->GetData(pathNode).parent);
|
||||
}
|
||||
// std::cout << "unpacking: ";
|
||||
// for(std::deque<NodeID>::iterator it = packedPath.begin(); it != packedPath.end(); ++it)
|
||||
// std::cout << *it << " ";
|
||||
// std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<bool forwardDirection>
|
||||
inline void _RoutingStep(HeapPtr & _forwardHeap, HeapPtr & _backwardHeap, NodeID *middle, int *_upperbound, const int edgeBasedOffset) const {
|
||||
const NodeID node = _forwardHeap->DeleteMin();
|
||||
const int distance = _forwardHeap->GetKey(node);
|
||||
// INFO((forwardDirection ? "[forw]" : "[back]") << " settled node " << node << " at distance " << distance);
|
||||
if(_backwardHeap->WasInserted(node) ){
|
||||
// INFO((forwardDirection ? "[forw]" : "[back]") << " scanned node " << node << " in both directions");
|
||||
const int newDistance = _backwardHeap->GetKey(node) + distance;
|
||||
if(newDistance < *_upperbound ){
|
||||
if(newDistance>=0 ) {
|
||||
// INFO((forwardDirection ? "[forw]" : "[back]") << " -> node " << node << " is new middle at total distance " << newDistance);
|
||||
*middle = node;
|
||||
*_upperbound = newDistance;
|
||||
} else {
|
||||
// INFO((forwardDirection ? "[forw]" : "[back]") << " -> ignored " << node << " as new middle at total distance " << newDistance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(distance-edgeBasedOffset > *_upperbound){
|
||||
_forwardHeap->DeleteAll();
|
||||
return;
|
||||
}
|
||||
|
||||
for ( typename GraphT::EdgeIterator edge = _graph->BeginEdges( node ); edge < _graph->EndEdges(node); edge++ ) {
|
||||
const EdgeData & data = _graph->GetEdgeData(edge);
|
||||
bool backwardDirectionFlag = (!forwardDirection) ? data.forward : data.backward;
|
||||
if(backwardDirectionFlag) {
|
||||
const NodeID to = _graph->GetTarget(edge);
|
||||
const int edgeWeight = data.distance;
|
||||
|
||||
assert( edgeWeight > 0 );
|
||||
|
||||
//Stalling
|
||||
if(_forwardHeap->WasInserted( to )) {
|
||||
if(_forwardHeap->GetKey( to ) + edgeWeight < distance) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ( typename GraphT::EdgeIterator edge = _graph->BeginEdges( node ); edge < _graph->EndEdges(node); edge++ ) {
|
||||
const EdgeData & data = _graph->GetEdgeData(edge);
|
||||
bool forwardDirectionFlag = (forwardDirection ? data.forward : data.backward );
|
||||
if(forwardDirectionFlag) {
|
||||
|
||||
const NodeID to = _graph->GetTarget(edge);
|
||||
const int edgeWeight = data.distance;
|
||||
|
||||
assert( edgeWeight > 0 );
|
||||
const int toDistance = distance + edgeWeight;
|
||||
|
||||
//New Node discovered -> Add to Heap + Node Info Storage
|
||||
if ( !_forwardHeap->WasInserted( to ) ) {
|
||||
// INFO((forwardDirection ? "[forw]" : "[back]") << " scanning edge (" << node << "," << to << ") with distance " << toDistance << ", edge length: " << data.distance);
|
||||
_forwardHeap->Insert( to, toDistance, node );
|
||||
}
|
||||
//Found a shorter Path -> Update distance
|
||||
else if ( toDistance < _forwardHeap->GetKey( to ) ) {
|
||||
// INFO((forwardDirection ? "[forw]" : "[back]") << " decrease and scanning edge (" << node << "," << to << ") from " << _forwardHeap->GetKey(to) << "to " << toDistance << ", edge length: " << data.distance);
|
||||
_forwardHeap->GetData( to ).parent = node;
|
||||
_forwardHeap->DecreaseKey( to, toDistance );
|
||||
//new parent
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void _UnpackPath(std::deque<NodeID> & packedPath, std::vector<_PathData> & unpackedPath) const {
|
||||
const unsigned sizeOfPackedPath = packedPath.size();
|
||||
std::stack<std::pair<NodeID, NodeID> > recursionStack;
|
||||
|
||||
//We have to push the path in reverse order onto the stack because it's LIFO.
|
||||
for(unsigned i = sizeOfPackedPath-1; i > 0; --i){
|
||||
recursionStack.push(std::make_pair(packedPath[i-1], packedPath[i]));
|
||||
}
|
||||
|
||||
std::pair<NodeID, NodeID> edge;
|
||||
while(!recursionStack.empty()) {
|
||||
edge = recursionStack.top();
|
||||
recursionStack.pop();
|
||||
// INFO("Unpacking edge (" << edge.first << "," << edge.second << ")");
|
||||
|
||||
typename GraphT::EdgeIterator smallestEdge = SPECIAL_EDGEID;
|
||||
int smallestWeight = INT_MAX;
|
||||
for(typename GraphT::EdgeIterator eit = _graph->BeginEdges(edge.first);eit < _graph->EndEdges(edge.first);++eit){
|
||||
const int weight = _graph->GetEdgeData(eit).distance;
|
||||
if(_graph->GetTarget(eit) == edge.second && weight < smallestWeight && _graph->GetEdgeData(eit).forward){
|
||||
// INFO("1smallest " << eit << ", " << weight);
|
||||
smallestEdge = eit;
|
||||
smallestWeight = weight;
|
||||
}
|
||||
}
|
||||
|
||||
if(smallestEdge == SPECIAL_EDGEID){
|
||||
for(typename GraphT::EdgeIterator eit = _graph->BeginEdges(edge.second);eit < _graph->EndEdges(edge.second);++eit){
|
||||
const int weight = _graph->GetEdgeData(eit).distance;
|
||||
if(_graph->GetTarget(eit) == edge.first && weight < smallestWeight && _graph->GetEdgeData(eit).backward){
|
||||
// INFO("2smallest " << eit << ", " << weight);
|
||||
smallestEdge = eit;
|
||||
smallestWeight = weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(smallestWeight != INT_MAX);
|
||||
|
||||
const EdgeData& ed = _graph->GetEdgeData(smallestEdge);
|
||||
if(ed.shortcut) {//unpack
|
||||
const NodeID middle = ed.id;
|
||||
//again, we need to this in reversed order
|
||||
recursionStack.push(std::make_pair(middle, edge.second));
|
||||
recursionStack.push(std::make_pair(edge.first, middle));
|
||||
} else {
|
||||
assert(!ed.shortcut);
|
||||
unpackedPath.push_back(_PathData(ed.id, nodeHelpDesk->getNameIndexFromEdgeID(ed.id), nodeHelpDesk->getTurnInstructionFromEdgeID(ed.id), ed.distance) );
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
template<class EdgeData, class GraphT> HeapPtr SearchEngine<EdgeData, GraphT>::_forwardHeap;
|
||||
template<class EdgeData, class GraphT> HeapPtr SearchEngine<EdgeData, GraphT>::_backwardHeap;
|
||||
|
||||
template<class EdgeData, class GraphT> HeapPtr SearchEngine<EdgeData, GraphT>::_forwardHeap2;
|
||||
template<class EdgeData, class GraphT> HeapPtr SearchEngine<EdgeData, GraphT>::_backwardHeap2;
|
||||
template<class EdgeData, class GraphT> SearchEngineHeapPtr SearchEngineData<EdgeData, GraphT>::forwardHeap;
|
||||
template<class EdgeData, class GraphT> SearchEngineHeapPtr SearchEngineData<EdgeData, GraphT>::backwardHeap;
|
||||
|
||||
template<class EdgeData, class GraphT> SearchEngineHeapPtr SearchEngineData<EdgeData, GraphT>::forwardHeap2;
|
||||
template<class EdgeData, class GraphT> SearchEngineHeapPtr SearchEngineData<EdgeData, GraphT>::backwardHeap2;
|
||||
|
||||
template<class EdgeData, class GraphT> SearchEngineHeapPtr SearchEngineData<EdgeData, GraphT>::forwardHeap3;
|
||||
template<class EdgeData, class GraphT> SearchEngineHeapPtr SearchEngineData<EdgeData, GraphT>::backwardHeap3;
|
||||
|
||||
#endif /* SEARCHENGINE_H_ */
|
||||
|
@ -46,7 +46,7 @@ struct TurnInstructionsClass {
|
||||
const static short AccessRestrictionFlag = (1<<14);
|
||||
const static short InverseAccessRestrictionFlag = ~(1<<14);
|
||||
|
||||
const static int AccessRestrictionPenaly = 1 << 15; //unrelated to the bit set in the restriction flag
|
||||
const static int AccessRestrictionPenalty = 1 << 15; //unrelated to the bit set in the restriction flag
|
||||
|
||||
// std::string TurnStrings[16];
|
||||
// std::string Ordinals[12];
|
||||
|
@ -48,7 +48,7 @@ public:
|
||||
BaseDescriptor() { }
|
||||
//Maybe someone can explain the pure virtual destructor thing to me (dennis)
|
||||
virtual ~BaseDescriptor() { }
|
||||
virtual void Run(http::Reply & reply, RawRouteData &rawRoute, PhantomNodes &phantomNodes, SearchEngineT &sEngine, unsigned distance) = 0;
|
||||
virtual void Run(http::Reply & reply, const RawRouteData &rawRoute, PhantomNodes &phantomNodes, SearchEngineT &sEngine) = 0;
|
||||
virtual void SetConfig(const _DescriptorConfig & config) = 0;
|
||||
};
|
||||
|
||||
|
@ -33,20 +33,20 @@ private:
|
||||
std::string tmp;
|
||||
public:
|
||||
void SetConfig(const _DescriptorConfig& c) { config = c; }
|
||||
void Run(http::Reply & reply, RawRouteData &rawRoute, PhantomNodes &phantomNodes, SearchEngineT &sEngine, unsigned distance) {
|
||||
void Run(http::Reply & reply, const RawRouteData &rawRoute, PhantomNodes &phantomNodes, SearchEngineT &sEngine) {
|
||||
reply.content += ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
reply.content += "<gpx xmlns=\"http://www.topografix.com/GPX/1/1\" "
|
||||
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
|
||||
"xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 gpx.xsd"
|
||||
"\">";
|
||||
reply.content += "<rte>";
|
||||
if(distance != UINT_MAX && rawRoute.computedRouted.size()) {
|
||||
if(rawRoute.lengthOfShortestPath != INT_MAX && rawRoute.computedShortestPath.size()) {
|
||||
convertInternalLatLonToString(phantomNodes.startPhantom.location.lat, tmp);
|
||||
reply.content += "<rtept lat=\"" + tmp + "\" ";
|
||||
convertInternalLatLonToString(phantomNodes.startPhantom.location.lon, tmp);
|
||||
reply.content += "lon=\"" + tmp + "\"></rtept>";
|
||||
|
||||
BOOST_FOREACH(_PathData pathData, rawRoute.computedRouted) {
|
||||
BOOST_FOREACH(_PathData pathData, rawRoute.computedShortestPath) {
|
||||
sEngine.GetCoordinatesForNodeID(pathData.node, current);
|
||||
|
||||
convertInternalLatLonToString(current.lat, tmp);
|
||||
|
@ -36,6 +36,7 @@ class JSONDescriptor : public BaseDescriptor<SearchEngineT>{
|
||||
private:
|
||||
_DescriptorConfig config;
|
||||
DescriptionFactory descriptionFactory;
|
||||
DescriptionFactory alternateDescriptionFactory;
|
||||
_Coordinate current;
|
||||
unsigned numberOfEnteredRestrictedAreas;
|
||||
struct {
|
||||
@ -48,15 +49,15 @@ public:
|
||||
JSONDescriptor() : numberOfEnteredRestrictedAreas(0) {}
|
||||
void SetConfig(const _DescriptorConfig & c) { config = c; }
|
||||
|
||||
void Run(http::Reply & reply, RawRouteData &rawRoute, PhantomNodes &phantomNodes, SearchEngineT &sEngine, const unsigned durationOfTrip) {
|
||||
void Run(http::Reply & reply, const RawRouteData &rawRoute, PhantomNodes &phantomNodes, SearchEngineT &sEngine) {
|
||||
WriteHeaderToOutput(reply.content);
|
||||
if(durationOfTrip != INT_MAX) {
|
||||
if(rawRoute.lengthOfShortestPath != INT_MAX) {
|
||||
descriptionFactory.SetStartSegment(phantomNodes.startPhantom);
|
||||
reply.content += "0,"
|
||||
"\"status_message\": \"Found route between points\",";
|
||||
|
||||
//Get all the coordinates for the computed route
|
||||
BOOST_FOREACH(_PathData & pathData, rawRoute.computedRouted) {
|
||||
BOOST_FOREACH(const _PathData & pathData, rawRoute.computedShortestPath) {
|
||||
sEngine.GetCoordinatesForNodeID(pathData.node, current);
|
||||
descriptionFactory.AppendSegment(current, pathData );
|
||||
}
|
||||
@ -67,7 +68,7 @@ public:
|
||||
"\"status_message\": \"Cannot find route between points\",";
|
||||
}
|
||||
|
||||
descriptionFactory.Run(sEngine, config.z, durationOfTrip);
|
||||
descriptionFactory.Run(sEngine, config.z, rawRoute.lengthOfShortestPath);
|
||||
reply.content += "\"route_geometry\": ";
|
||||
if(config.geometry) {
|
||||
descriptionFactory.AppendEncodedPolylineString(reply.content, config.encodeGeometry);
|
||||
@ -77,85 +78,9 @@ public:
|
||||
|
||||
reply.content += ","
|
||||
"\"route_instructions\": [";
|
||||
numberOfEnteredRestrictedAreas = 0;
|
||||
if(config.instructions) {
|
||||
//Segment information has following format:
|
||||
//["instruction","streetname",length,position,time,"length","earth_direction",azimuth]
|
||||
//Example: ["Turn left","High Street",200,4,10,"200m","NE",22.5]
|
||||
//See also: http://developers.cloudmade.com/wiki/navengine/JSON_format
|
||||
unsigned prefixSumOfNecessarySegments = 0;
|
||||
roundAbout.leaveAtExit = 0;
|
||||
roundAbout.nameID = 0;
|
||||
std::string tmpDist, tmpLength, tmpDuration, tmpBearing, tmpInstruction;
|
||||
//Fetch data from Factory and generate a string from it.
|
||||
BOOST_FOREACH(const SegmentInformation & segment, descriptionFactory.pathDescription) {
|
||||
short currentInstruction = segment.turnInstruction & TurnInstructions.InverseAccessRestrictionFlag;
|
||||
numberOfEnteredRestrictedAreas += (currentInstruction != segment.turnInstruction);
|
||||
if(TurnInstructions.TurnIsNecessary( currentInstruction) ) {
|
||||
if(TurnInstructions.EnterRoundAbout == currentInstruction) {
|
||||
roundAbout.nameID = segment.nameID;
|
||||
roundAbout.startIndex = prefixSumOfNecessarySegments;
|
||||
} else {
|
||||
if(0 != prefixSumOfNecessarySegments){
|
||||
reply.content += ",";
|
||||
}
|
||||
reply.content += "[\"";
|
||||
if(TurnInstructions.LeaveRoundAbout == currentInstruction) {
|
||||
intToString(TurnInstructions.EnterRoundAbout, tmpInstruction);
|
||||
reply.content += tmpInstruction;
|
||||
reply.content += "-";
|
||||
intToString(roundAbout.leaveAtExit+1, tmpInstruction);
|
||||
reply.content += tmpInstruction;
|
||||
roundAbout.leaveAtExit = 0;
|
||||
} else {
|
||||
intToString(currentInstruction, tmpInstruction);
|
||||
reply.content += tmpInstruction;
|
||||
}
|
||||
reply.content += "\",\"";
|
||||
reply.content += sEngine.GetEscapedNameForNameID(segment.nameID);
|
||||
reply.content += "\",";
|
||||
intToString(segment.length, tmpDist);
|
||||
reply.content += tmpDist;
|
||||
reply.content += ",";
|
||||
intToString(prefixSumOfNecessarySegments, tmpLength);
|
||||
reply.content += tmpLength;
|
||||
reply.content += ",";
|
||||
intToString(segment.duration, tmpDuration);
|
||||
reply.content += tmpDuration;
|
||||
reply.content += ",\"";
|
||||
intToString(segment.length, tmpLength);
|
||||
reply.content += tmpLength;
|
||||
reply.content += "m\",\"";
|
||||
reply.content += Azimuth::Get(segment.bearing);
|
||||
reply.content += "\",";
|
||||
intToString(round(segment.bearing), tmpBearing);
|
||||
reply.content += tmpBearing;
|
||||
reply.content += "]";
|
||||
}
|
||||
} else if(TurnInstructions.StayOnRoundAbout == currentInstruction) {
|
||||
++roundAbout.leaveAtExit;
|
||||
}
|
||||
if(segment.necessary)
|
||||
++prefixSumOfNecessarySegments;
|
||||
}
|
||||
if(durationOfTrip != INT_MAX) {
|
||||
reply.content += ",[\"";
|
||||
intToString(TurnInstructions.ReachedYourDestination, tmpInstruction);
|
||||
reply.content += tmpInstruction;
|
||||
reply.content += "\",\"";
|
||||
reply.content += "\",";
|
||||
reply.content += "0";
|
||||
reply.content += ",";
|
||||
intToString(prefixSumOfNecessarySegments-1, tmpLength);
|
||||
reply.content += tmpLength;
|
||||
reply.content += ",";
|
||||
reply.content += "0";
|
||||
reply.content += ",\"";
|
||||
reply.content += "\",\"";
|
||||
reply.content += Azimuth::Get(0.0);
|
||||
reply.content += "\",";
|
||||
reply.content += "0.0";
|
||||
reply.content += "]";
|
||||
}
|
||||
BuildTextualDescription(descriptionFactory, reply, rawRoute.lengthOfShortestPath, sEngine);
|
||||
} else {
|
||||
BOOST_FOREACH(const SegmentInformation & segment, descriptionFactory.pathDescription) {
|
||||
short currentInstruction = segment.turnInstruction & TurnInstructions.InverseAccessRestrictionFlag;
|
||||
@ -163,11 +88,11 @@ public:
|
||||
}
|
||||
}
|
||||
reply.content += "],";
|
||||
// INFO("Entered " << numberOfEnteredRestrictedAreas << " restricted areas");
|
||||
descriptionFactory.BuildRouteSummary(descriptionFactory.entireLength, durationOfTrip - ( numberOfEnteredRestrictedAreas*TurnInstructions.AccessRestrictionPenaly));
|
||||
descriptionFactory.BuildRouteSummary(descriptionFactory.entireLength, rawRoute.lengthOfShortestPath - ( numberOfEnteredRestrictedAreas*TurnInstructions.AccessRestrictionPenalty));
|
||||
|
||||
reply.content += "\"route_summary\": {"
|
||||
"\"total_distance\":";
|
||||
reply.content += "\"route_summary\":";
|
||||
reply.content += "{";
|
||||
reply.content += "\"total_distance\":";
|
||||
reply.content += descriptionFactory.summary.lengthString;
|
||||
reply.content += ","
|
||||
"\"total_time\":";
|
||||
@ -179,12 +104,62 @@ public:
|
||||
"\"end_point\":\"";
|
||||
reply.content += sEngine.GetEscapedNameForNameID(descriptionFactory.summary.destName);
|
||||
reply.content += "\"";
|
||||
reply.content += "},";
|
||||
reply.content += "}";
|
||||
reply.content +=",";
|
||||
|
||||
//only one alternative route is computed at this time, so this is hardcoded
|
||||
|
||||
if(rawRoute.lengthOfAlternativePath != INT_MAX) {
|
||||
alternateDescriptionFactory.SetStartSegment(phantomNodes.startPhantom);
|
||||
//Get all the coordinates for the computed route
|
||||
BOOST_FOREACH(const _PathData & pathData, rawRoute.computedAlternativePath) {
|
||||
sEngine.GetCoordinatesForNodeID(pathData.node, current);
|
||||
alternateDescriptionFactory.AppendSegment(current, pathData );
|
||||
}
|
||||
alternateDescriptionFactory.SetEndSegment(phantomNodes.targetPhantom);
|
||||
}
|
||||
alternateDescriptionFactory.Run(sEngine, config.z, rawRoute.lengthOfAlternativePath);
|
||||
|
||||
//give an array of alternative routes
|
||||
reply.content += "\"alternative_geometries\": [";
|
||||
if(config.geometry && INT_MAX != rawRoute.lengthOfAlternativePath) {
|
||||
//Generate the linestrings for each alternative
|
||||
alternateDescriptionFactory.AppendEncodedPolylineString(reply.content, config.encodeGeometry);
|
||||
}
|
||||
reply.content += "],";
|
||||
reply.content += "\"alternative_instructions\":[";
|
||||
if(config.instructions && INT_MAX != rawRoute.lengthOfAlternativePath) {
|
||||
reply.content += "[";
|
||||
//Generate instructions for each alternative
|
||||
BuildTextualDescription(alternateDescriptionFactory, reply, rawRoute.lengthOfAlternativePath, sEngine);
|
||||
reply.content += "]";
|
||||
}
|
||||
reply.content += "],";
|
||||
reply.content += "\"alternative_summaries\":[";
|
||||
if(INT_MAX != rawRoute.lengthOfAlternativePath) {
|
||||
//Generate route summary (length, duration) for each alternative
|
||||
alternateDescriptionFactory.BuildRouteSummary(alternateDescriptionFactory.entireLength, rawRoute.lengthOfAlternativePath - ( numberOfEnteredRestrictedAreas*TurnInstructions.AccessRestrictionPenalty));
|
||||
reply.content += "{";
|
||||
reply.content += "\"total_distance\":";
|
||||
reply.content += alternateDescriptionFactory.summary.lengthString;
|
||||
reply.content += ","
|
||||
"\"total_time\":";
|
||||
reply.content += alternateDescriptionFactory.summary.durationString;
|
||||
reply.content += ","
|
||||
"\"start_point\":\"";
|
||||
reply.content += sEngine.GetEscapedNameForNameID(descriptionFactory.summary.startName);
|
||||
reply.content += "\","
|
||||
"\"end_point\":\"";
|
||||
reply.content += sEngine.GetEscapedNameForNameID(descriptionFactory.summary.destName);
|
||||
reply.content += "\"";
|
||||
reply.content += "}";
|
||||
}
|
||||
reply.content += "],";
|
||||
|
||||
//list all viapoints so that the client may display it
|
||||
reply.content += "\"via_points\":[";
|
||||
std::string tmp;
|
||||
if(config.geometry && INT_MAX != durationOfTrip) {
|
||||
if(config.geometry && INT_MAX != rawRoute.lengthOfShortestPath) {
|
||||
for(unsigned i = 0; i < rawRoute.segmentEndCoordinates.size(); ++i) {
|
||||
reply.content += "[";
|
||||
if(rawRoute.segmentEndCoordinates[i].startPhantom.location.isSet())
|
||||
@ -231,5 +206,88 @@ public:
|
||||
"\"version\": 0.3,"
|
||||
"\"status\":";
|
||||
}
|
||||
|
||||
inline void BuildTextualDescription(DescriptionFactory & descriptionFactory, http::Reply & reply, const int lengthOfRoute, const SearchEngineT &sEngine) {
|
||||
//Segment information has following format:
|
||||
//["instruction","streetname",length,position,time,"length","earth_direction",azimuth]
|
||||
//Example: ["Turn left","High Street",200,4,10,"200m","NE",22.5]
|
||||
//See also: http://developers.cloudmade.com/wiki/navengine/JSON_format
|
||||
unsigned prefixSumOfNecessarySegments = 0;
|
||||
roundAbout.leaveAtExit = 0;
|
||||
roundAbout.nameID = 0;
|
||||
std::string tmpDist, tmpLength, tmpDuration, tmpBearing, tmpInstruction;
|
||||
//Fetch data from Factory and generate a string from it.
|
||||
BOOST_FOREACH(const SegmentInformation & segment, descriptionFactory.pathDescription) {
|
||||
short currentInstruction = segment.turnInstruction & TurnInstructions.InverseAccessRestrictionFlag;
|
||||
numberOfEnteredRestrictedAreas += (currentInstruction != segment.turnInstruction);
|
||||
if(TurnInstructions.TurnIsNecessary( currentInstruction) ) {
|
||||
if(TurnInstructions.EnterRoundAbout == currentInstruction) {
|
||||
roundAbout.nameID = segment.nameID;
|
||||
roundAbout.startIndex = prefixSumOfNecessarySegments;
|
||||
} else {
|
||||
if(0 != prefixSumOfNecessarySegments){
|
||||
reply.content += ",";
|
||||
}
|
||||
reply.content += "[\"";
|
||||
if(TurnInstructions.LeaveRoundAbout == currentInstruction) {
|
||||
intToString(TurnInstructions.EnterRoundAbout, tmpInstruction);
|
||||
reply.content += tmpInstruction;
|
||||
reply.content += "-";
|
||||
intToString(roundAbout.leaveAtExit+1, tmpInstruction);
|
||||
reply.content += tmpInstruction;
|
||||
roundAbout.leaveAtExit = 0;
|
||||
} else {
|
||||
intToString(currentInstruction, tmpInstruction);
|
||||
reply.content += tmpInstruction;
|
||||
}
|
||||
reply.content += "\",\"";
|
||||
reply.content += sEngine.GetEscapedNameForNameID(segment.nameID);
|
||||
reply.content += "\",";
|
||||
intToString(segment.length, tmpDist);
|
||||
reply.content += tmpDist;
|
||||
reply.content += ",";
|
||||
intToString(prefixSumOfNecessarySegments, tmpLength);
|
||||
reply.content += tmpLength;
|
||||
reply.content += ",";
|
||||
intToString(segment.duration, tmpDuration);
|
||||
reply.content += tmpDuration;
|
||||
reply.content += ",\"";
|
||||
intToString(segment.length, tmpLength);
|
||||
reply.content += tmpLength;
|
||||
reply.content += "m\",\"";
|
||||
reply.content += Azimuth::Get(segment.bearing);
|
||||
reply.content += "\",";
|
||||
intToString(round(segment.bearing), tmpBearing);
|
||||
reply.content += tmpBearing;
|
||||
reply.content += "]";
|
||||
}
|
||||
} else if(TurnInstructions.StayOnRoundAbout == currentInstruction) {
|
||||
++roundAbout.leaveAtExit;
|
||||
}
|
||||
if(segment.necessary)
|
||||
++prefixSumOfNecessarySegments;
|
||||
}
|
||||
if(INT_MAX != lengthOfRoute) {
|
||||
reply.content += ",[\"";
|
||||
intToString(TurnInstructions.ReachedYourDestination, tmpInstruction);
|
||||
reply.content += tmpInstruction;
|
||||
reply.content += "\",\"";
|
||||
reply.content += "\",";
|
||||
reply.content += "0";
|
||||
reply.content += ",";
|
||||
intToString(prefixSumOfNecessarySegments-1, tmpLength);
|
||||
reply.content += tmpLength;
|
||||
reply.content += ",";
|
||||
reply.content += "0";
|
||||
reply.content += ",\"";
|
||||
reply.content += "\",\"";
|
||||
reply.content += Azimuth::Get(0.0);
|
||||
reply.content += "\",";
|
||||
reply.content += "0.0";
|
||||
reply.content += "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
#endif /* JSON_DESCRIPTOR_H_ */
|
||||
|
@ -22,10 +22,13 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
||||
#define RAWROUTEDATA_H_
|
||||
|
||||
struct RawRouteData {
|
||||
std::vector< _PathData > computedRouted;
|
||||
std::vector< _PathData > computedShortestPath;
|
||||
std::vector< _PathData > computedAlternativePath;
|
||||
std::vector< PhantomNodes > segmentEndCoordinates;
|
||||
std::vector< _Coordinate > rawViaNodeCoordinates;
|
||||
unsigned checkSum;
|
||||
int lengthOfShortestPath;
|
||||
int lengthOfAlternativePath;
|
||||
};
|
||||
|
||||
#endif /* RAWROUTEDATA_H_ */
|
||||
|
@ -82,10 +82,6 @@ public:
|
||||
RawRouteData rawRoute;
|
||||
rawRoute.checkSum = nodeHelpDesk->GetCheckSum();
|
||||
bool checksumOK = ((unsigned)atoi(routeParameters.options.Find("checksum").c_str()) == rawRoute.checkSum);
|
||||
// if(!checksumOK) {
|
||||
// INFO((unsigned)atoi(routeParameters.options.Find("checksum").c_str()) << "!=" << rawRoute.checkSum);
|
||||
// INFO("mismatching checksum");
|
||||
// }
|
||||
std::vector<std::string> textCoord;
|
||||
for(unsigned i = 0; i < routeParameters.viaPoints.size(); ++i) {
|
||||
textCoord.resize(0);
|
||||
@ -116,25 +112,39 @@ public:
|
||||
// INFO("Brute force lookup of coordinate " << i);
|
||||
searchEngine->FindPhantomNodeForCoordinate( rawRoute.rawViaNodeCoordinates[i], phantomNodeVector[i]);
|
||||
}
|
||||
unsigned distance = 0;
|
||||
//single route or via point routing
|
||||
if(2 == rawRoute.rawViaNodeCoordinates.size()) {
|
||||
//unsigned distance = 0;
|
||||
|
||||
for(unsigned i = 0; i < phantomNodeVector.size()-1; ++i) {
|
||||
PhantomNodes segmentPhantomNodes;
|
||||
segmentPhantomNodes.startPhantom = phantomNodeVector[0];
|
||||
segmentPhantomNodes.targetPhantom = phantomNodeVector[1];
|
||||
distance = searchEngine->ComputeRoute(segmentPhantomNodes, rawRoute.computedRouted);
|
||||
segmentPhantomNodes.startPhantom = phantomNodeVector[i];
|
||||
segmentPhantomNodes.targetPhantom = phantomNodeVector[i+1];
|
||||
rawRoute.segmentEndCoordinates.push_back(segmentPhantomNodes);
|
||||
} else {
|
||||
//Getting the shortest via path is a dynamic programming problem and is solved as such.
|
||||
for(unsigned i = 0; i < phantomNodeVector.size()-1; ++i) {
|
||||
PhantomNodes segmentPhantomNodes;
|
||||
segmentPhantomNodes.startPhantom = phantomNodeVector[i];
|
||||
segmentPhantomNodes.targetPhantom = phantomNodeVector[i+1];
|
||||
rawRoute.segmentEndCoordinates.push_back(segmentPhantomNodes);
|
||||
}
|
||||
distance = searchEngine->ComputeViaRoute(rawRoute.segmentEndCoordinates, rawRoute.computedRouted);
|
||||
}
|
||||
if(INT_MAX == distance ) {
|
||||
if(1 == rawRoute.segmentEndCoordinates.size()) {
|
||||
// INFO("Checking for alternative paths");
|
||||
searchEngine->alternativePaths(rawRoute.segmentEndCoordinates[0], rawRoute);
|
||||
|
||||
} else {
|
||||
searchEngine->shortestPath(rawRoute.segmentEndCoordinates, rawRoute);
|
||||
}
|
||||
// std::cout << "latitude,longitude" << std::endl;
|
||||
// for(unsigned i = 0; i < rawRoute.computedShortestPath.size(); ++i) {
|
||||
// _Coordinate current;
|
||||
// searchEngine->GetCoordinatesForNodeID(rawRoute.computedShortestPath[i].node, current);
|
||||
// std::cout << current.lat/100000. << "," << current.lon/100000. << std::endl;
|
||||
// }
|
||||
// std::cout << std::endl;
|
||||
//
|
||||
// std::cout << "latitude,longitude" << std::endl;
|
||||
// for(unsigned i = 0; i < rawRoute.computedAlternativePath.size(); ++i) {
|
||||
// _Coordinate current;
|
||||
// searchEngine->GetCoordinatesForNodeID(rawRoute.computedAlternativePath[i].node, current);
|
||||
// std::cout << current.lat/100000. << "," << current.lon/100000. << std::endl;
|
||||
// }
|
||||
// std::cout << std::endl;
|
||||
|
||||
|
||||
if(INT_MAX == rawRoute.lengthOfShortestPath ) {
|
||||
DEBUG( "Error occurred, single path not found" );
|
||||
}
|
||||
reply.status = http::Reply::ok;
|
||||
@ -188,7 +198,7 @@ public:
|
||||
// INFO("Number of segments: " << rawRoute.segmentEndCoordinates.size());
|
||||
desc->SetConfig(descriptorConfig);
|
||||
|
||||
desc->Run(reply, rawRoute, phantomNodes, *searchEngine, distance);
|
||||
desc->Run(reply, rawRoute, phantomNodes, *searchEngine);
|
||||
if("" != JSONParameter) {
|
||||
reply.content += ")\n";
|
||||
}
|
||||
|
472
RoutingAlgorithms/AlternativePathRouting.h
Normal file
472
RoutingAlgorithms/AlternativePathRouting.h
Normal file
@ -0,0 +1,472 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef ALTERNATIVEROUTES_H_
|
||||
#define ALTERNATIVEROUTES_H_
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "BasicRoutingInterface.h"
|
||||
|
||||
const double VIAPATH_ALPHA = 0.25;
|
||||
const double VIAPATH_EPSILON = 0.25;
|
||||
const double VIAPATH_GAMMA = 0.80;
|
||||
|
||||
template<class QueryDataT>
|
||||
class AlternativeRouting : private BasicRoutingInterface<QueryDataT>{
|
||||
typedef BasicRoutingInterface<QueryDataT> super;
|
||||
typedef std::pair<NodeID, int> PreselectedNode;
|
||||
typedef typename QueryDataT::HeapPtr HeapPtr;
|
||||
typedef std::pair<NodeID, NodeID> UnpackEdge;
|
||||
|
||||
struct RankedCandidateNode {
|
||||
RankedCandidateNode(NodeID n, int l, int s) : node(n), length(l), sharing(s) {}
|
||||
NodeID node;
|
||||
int length;
|
||||
int sharing;
|
||||
const bool operator<(const RankedCandidateNode& other) const {
|
||||
return (2*length + sharing) < (2*other.length + other.sharing);
|
||||
}
|
||||
};
|
||||
public:
|
||||
|
||||
AlternativeRouting(QueryDataT & qd) : super(qd) { }
|
||||
|
||||
~AlternativeRouting() {}
|
||||
|
||||
void operator()(const PhantomNodes & phantomNodePair, RawRouteData & rawRouteData) {
|
||||
if(!phantomNodePair.AtLeastOnePhantomNodeIsUINTMAX()) {
|
||||
rawRouteData.lengthOfShortestPath = rawRouteData.lengthOfAlternativePath = INT_MAX;
|
||||
return;
|
||||
}
|
||||
std::vector<NodeID> alternativePath;
|
||||
std::vector<NodeID> viaNodeCandidates;
|
||||
std::deque <NodeID> packedShortestPath;
|
||||
std::vector<PreselectedNode> nodesThatPassPreselection;
|
||||
|
||||
HeapPtr & forwardHeap = super::_queryData.forwardHeap;
|
||||
HeapPtr & backwardHeap = super::_queryData.backwardHeap;
|
||||
HeapPtr & forwardHeap2 = super::_queryData.forwardHeap2;
|
||||
HeapPtr & backwardHeap2 = super::_queryData.backwardHeap2;
|
||||
|
||||
//Initialize Queues
|
||||
super::_queryData.InitializeOrClearFirstThreadLocalStorage();
|
||||
int _upperBound = INT_MAX;
|
||||
NodeID middle = UINT_MAX;
|
||||
forwardHeap->Insert(phantomNodePair.startPhantom.edgeBasedNode, -phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode);
|
||||
if(phantomNodePair.startPhantom.isBidirected() ) {
|
||||
forwardHeap->Insert(phantomNodePair.startPhantom.edgeBasedNode+1, -phantomNodePair.startPhantom.weight2, phantomNodePair.startPhantom.edgeBasedNode+1);
|
||||
}
|
||||
backwardHeap->Insert(phantomNodePair.targetPhantom.edgeBasedNode, phantomNodePair.targetPhantom.weight1, phantomNodePair.targetPhantom.edgeBasedNode);
|
||||
if(phantomNodePair.targetPhantom.isBidirected() ) {
|
||||
backwardHeap->Insert(phantomNodePair.targetPhantom.edgeBasedNode+1, phantomNodePair.targetPhantom.weight2, phantomNodePair.targetPhantom.edgeBasedNode+1);
|
||||
}
|
||||
|
||||
const int offset = (phantomNodePair.startPhantom.isBidirected() ? std::max(phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.weight2) : phantomNodePair.startPhantom.weight1)
|
||||
+ (phantomNodePair.targetPhantom.isBidirected() ? std::max(phantomNodePair.targetPhantom.weight1, phantomNodePair.targetPhantom.weight2) : phantomNodePair.targetPhantom.weight1);
|
||||
|
||||
//exploration dijkstra from nodes s and t until deletemin/(1+epsilon) > _lengthOfShortestPath
|
||||
while(forwardHeap->Size() + backwardHeap->Size() > 0){
|
||||
if(forwardHeap->Size() > 0){
|
||||
AlternativeRoutingStep(forwardHeap, backwardHeap, &middle, &_upperBound, 2*offset, true, viaNodeCandidates);
|
||||
}
|
||||
if(backwardHeap->Size() > 0){
|
||||
AlternativeRoutingStep(backwardHeap, forwardHeap, &middle, &_upperBound, 2*offset, false, viaNodeCandidates);
|
||||
}
|
||||
}
|
||||
std::sort(viaNodeCandidates.begin(), viaNodeCandidates.end());
|
||||
int size = std::unique(viaNodeCandidates.begin(), viaNodeCandidates.end())- viaNodeCandidates.begin();
|
||||
viaNodeCandidates.resize(size);
|
||||
|
||||
//save (packed) shortest path of shortest path and keep it for later use.
|
||||
//we need it during the checks and dont want to recompute it always
|
||||
super::RetrievePackedPathFromHeap(forwardHeap, backwardHeap, middle, packedShortestPath);
|
||||
|
||||
//ch-pruning of via nodes in both search spaces
|
||||
BOOST_FOREACH(const NodeID node, viaNodeCandidates) {
|
||||
if(node == middle) //subpath optimality tells us that this case is just the shortest path
|
||||
continue;
|
||||
|
||||
int sharing = approximateAmountOfSharing(node, forwardHeap, backwardHeap, packedShortestPath);
|
||||
int length1 = forwardHeap->GetKey(node);
|
||||
int length2 = backwardHeap->GetKey(node);
|
||||
bool lengthPassed = (length1+length2 < _upperBound*(1+VIAPATH_EPSILON));
|
||||
bool sharingPassed = (sharing <= _upperBound*VIAPATH_GAMMA);
|
||||
bool stretchPassed = length1+length2 - sharing < (1.+VIAPATH_EPSILON)*(_upperBound-sharing);
|
||||
|
||||
if(lengthPassed && sharingPassed && stretchPassed)
|
||||
nodesThatPassPreselection.push_back(std::make_pair(node, length1+length2));
|
||||
}
|
||||
|
||||
std::vector<RankedCandidateNode > rankedCandidates;
|
||||
|
||||
//prioritizing via nodes for deep inspection
|
||||
BOOST_FOREACH(const PreselectedNode node, nodesThatPassPreselection) {
|
||||
int lengthOfViaPath = 0, sharingOfViaPath = 0;
|
||||
|
||||
computeLengthAndSharingOfViaPath(phantomNodePair, node, &lengthOfViaPath, &sharingOfViaPath, offset, packedShortestPath);
|
||||
if(sharingOfViaPath <= VIAPATH_GAMMA*_upperBound)
|
||||
rankedCandidates.push_back(RankedCandidateNode(node.first, lengthOfViaPath, sharingOfViaPath));
|
||||
}
|
||||
|
||||
std::sort(rankedCandidates.begin(), rankedCandidates.end());
|
||||
|
||||
NodeID selectedViaNode = UINT_MAX;
|
||||
int lengthOfViaPath = INT_MAX;
|
||||
NodeID s_v_middle, v_t_middle;
|
||||
BOOST_FOREACH(const RankedCandidateNode candidate, rankedCandidates){
|
||||
if(viaNodeCandidatePasses_T_Test(forwardHeap, backwardHeap, forwardHeap2, backwardHeap2, candidate, offset, _upperBound, &lengthOfViaPath, &s_v_middle, &v_t_middle)) {
|
||||
// select first admissable
|
||||
selectedViaNode = candidate.node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Unpack shortest path and alternative, if they exist
|
||||
if(INT_MAX != _upperBound) {
|
||||
super::UnpackPath(packedShortestPath, rawRouteData.computedShortestPath);
|
||||
rawRouteData.lengthOfShortestPath = _upperBound;
|
||||
} else {
|
||||
rawRouteData.lengthOfShortestPath = INT_MAX;
|
||||
}
|
||||
|
||||
if(selectedViaNode != UINT_MAX) {
|
||||
retrievePackedViaPath(forwardHeap, backwardHeap, forwardHeap2, backwardHeap2, s_v_middle, v_t_middle, rawRouteData.computedAlternativePath);
|
||||
rawRouteData.lengthOfAlternativePath = lengthOfViaPath;
|
||||
} else {
|
||||
rawRouteData.lengthOfAlternativePath = INT_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
//unpack <s,..,v,..,t> by exploring search spaces from v
|
||||
inline void retrievePackedViaPath(const HeapPtr & _forwardHeap1, const HeapPtr & _backwardHeap1, const HeapPtr & _forwardHeap2, const HeapPtr & _backwardHeap2,
|
||||
const NodeID s_v_middle, const NodeID v_t_middle, std::vector<_PathData> & unpackedPath) {
|
||||
//unpack [s,v)
|
||||
std::deque<NodeID> packed_s_v_path, packed_v_t_path;
|
||||
super::RetrievePackedPathFromHeap(_forwardHeap1, _backwardHeap2, s_v_middle, packed_s_v_path);
|
||||
packed_s_v_path.resize(packed_s_v_path.size()-1);
|
||||
//unpack [v,t]
|
||||
super::RetrievePackedPathFromHeap(_forwardHeap2, _backwardHeap1, v_t_middle, packed_v_t_path);
|
||||
packed_s_v_path.insert(packed_s_v_path.end(),packed_v_t_path.begin(), packed_v_t_path.end() );
|
||||
super::UnpackPath(packed_s_v_path, unpackedPath);
|
||||
}
|
||||
|
||||
inline void computeLengthAndSharingOfViaPath(const PhantomNodes & phantomNodePair, const PreselectedNode& node, int *lengthOfViaPath, int *sharingOfViaPath,
|
||||
const int offset, const std::deque<NodeID> & packedShortestPath) {
|
||||
//compute and unpack <s,..,v> and <v,..,t> by exploring search spaces from v and intersecting against queues
|
||||
//only half-searches have to be done at this stage
|
||||
super::_queryData.InitializeOrClearSecondThreadLocalStorage();
|
||||
|
||||
HeapPtr & existingForwardHeap = super::_queryData.forwardHeap;
|
||||
HeapPtr & existingBackwardHeap = super::_queryData.backwardHeap;
|
||||
HeapPtr & newForwardHeap = super::_queryData.forwardHeap2;
|
||||
HeapPtr & newBackwardHeap = super::_queryData.backwardHeap2;
|
||||
|
||||
std::deque < NodeID > packed_s_v_path;
|
||||
std::deque < NodeID > packed_v_t_path;
|
||||
|
||||
std::vector<NodeID> partiallyUnpackedShortestPath;
|
||||
std::vector<NodeID> partiallyUnpackedViaPath;
|
||||
|
||||
NodeID s_v_middle = UINT_MAX;
|
||||
int upperBoundFor_s_v_Path = INT_MAX;//compute path <s,..,v> by reusing forward search from s
|
||||
newBackwardHeap->Insert(node.first, 0, node.first);
|
||||
while (newBackwardHeap->Size() > 0) {
|
||||
super::RoutingStep(newBackwardHeap, existingForwardHeap, &s_v_middle, &upperBoundFor_s_v_Path, 2 * offset, false);
|
||||
}
|
||||
//compute path <v,..,t> by reusing backward search from node t
|
||||
NodeID v_t_middle = UINT_MAX;
|
||||
int upperBoundFor_v_t_Path = INT_MAX;
|
||||
newForwardHeap->Insert(node.first, 0, node.first);
|
||||
while (newForwardHeap->Size() > 0) {
|
||||
super::RoutingStep(newForwardHeap, existingBackwardHeap, &v_t_middle, &upperBoundFor_v_t_Path, 2 * offset, true);
|
||||
}
|
||||
*lengthOfViaPath = upperBoundFor_s_v_Path + upperBoundFor_v_t_Path;
|
||||
|
||||
//retrieve packed paths
|
||||
super::RetrievePackedPathFromHeap(existingForwardHeap, newBackwardHeap, s_v_middle, packed_s_v_path);
|
||||
super::RetrievePackedPathFromHeap(newForwardHeap, existingBackwardHeap, v_t_middle, packed_v_t_path);
|
||||
|
||||
//partial unpacking, compute sharing
|
||||
//First partially unpack s-->v until paths deviate, note length of common path.
|
||||
for (unsigned i = 0, lengthOfPackedPath = std::min( packed_s_v_path.size(), packedShortestPath.size()) - 1; (i < lengthOfPackedPath); ++i) {
|
||||
if (packed_s_v_path[i] == packedShortestPath[i] && packed_s_v_path[i + 1] == packedShortestPath[i + 1]) {
|
||||
typename QueryDataT::Graph::EdgeIterator edgeID = super::_queryData.graph->FindEdgeInEitherDirection(packed_s_v_path[i], packed_s_v_path[i + 1]);
|
||||
*sharingOfViaPath += super::_queryData.graph->GetEdgeData(edgeID).distance;
|
||||
} else {
|
||||
if (packed_s_v_path[i] == packedShortestPath[i]) {
|
||||
super::UnpackEdge(packed_s_v_path[i], packed_s_v_path[i+1], partiallyUnpackedViaPath);
|
||||
super::UnpackEdge(packedShortestPath[i], packedShortestPath[i+1], partiallyUnpackedShortestPath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//traverse partially unpacked edge and note common prefix
|
||||
for (int i = 0, lengthOfPackedPath = std::min( partiallyUnpackedViaPath.size(), partiallyUnpackedShortestPath.size()) - 1; (i < lengthOfPackedPath) && (partiallyUnpackedViaPath[i] == partiallyUnpackedShortestPath[i] && partiallyUnpackedViaPath[i+1] == partiallyUnpackedShortestPath[i+1]); ++i) {
|
||||
typename QueryDataT::Graph::EdgeIterator edgeID = super::_queryData.graph->FindEdgeInEitherDirection(partiallyUnpackedViaPath[i], partiallyUnpackedViaPath[i+1]);
|
||||
*sharingOfViaPath += super::_queryData.graph->GetEdgeData(edgeID).distance;
|
||||
}
|
||||
|
||||
//Second, partially unpack v-->t in reverse order until paths deviate and note lengths
|
||||
int viaPathIndex = packed_v_t_path.size() - 1;
|
||||
int shortestPathIndex = packedShortestPath.size() - 1;
|
||||
for (; viaPathIndex > 0 && shortestPathIndex > 0; --viaPathIndex,--shortestPathIndex ) {
|
||||
if (packed_v_t_path[viaPathIndex - 1] == packedShortestPath[shortestPathIndex - 1] && packed_v_t_path[viaPathIndex] == packedShortestPath[shortestPathIndex]) {
|
||||
typename QueryDataT::Graph::EdgeIterator edgeID = super::_queryData.graph->FindEdgeInEitherDirection( packed_v_t_path[viaPathIndex - 1], packed_v_t_path[viaPathIndex]);
|
||||
*sharingOfViaPath += super::_queryData.graph->GetEdgeData(edgeID).distance;
|
||||
} else {
|
||||
if (packed_v_t_path[viaPathIndex] == packedShortestPath[shortestPathIndex]) {
|
||||
super::UnpackEdge(packed_v_t_path[viaPathIndex-1], packed_v_t_path[viaPathIndex], partiallyUnpackedViaPath);
|
||||
super::UnpackEdge(packedShortestPath[shortestPathIndex-1] , packedShortestPath[shortestPathIndex], partiallyUnpackedShortestPath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viaPathIndex = partiallyUnpackedViaPath.size() - 1;
|
||||
shortestPathIndex = partiallyUnpackedShortestPath.size() - 1;
|
||||
for (; viaPathIndex > 0 && shortestPathIndex > 0; --viaPathIndex,--shortestPathIndex) {
|
||||
if (partiallyUnpackedViaPath[viaPathIndex - 1] == partiallyUnpackedShortestPath[shortestPathIndex - 1] && partiallyUnpackedViaPath[viaPathIndex] == partiallyUnpackedShortestPath[shortestPathIndex]) {
|
||||
typename QueryDataT::Graph::EdgeIterator edgeID = super::_queryData.graph->FindEdgeInEitherDirection( partiallyUnpackedViaPath[viaPathIndex - 1], partiallyUnpackedViaPath[viaPathIndex]);
|
||||
*sharingOfViaPath += super::_queryData.graph->GetEdgeData(edgeID).distance;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
//finished partial unpacking spree! Amount of sharing is stored to appropriate poiner variable
|
||||
}
|
||||
|
||||
inline int approximateAmountOfSharing(const NodeID middleNodeIDOfAlternativePath, HeapPtr & _forwardHeap, HeapPtr & _backwardHeap, const std::deque<NodeID> & packedShortestPath) {
|
||||
std::deque<NodeID> packedAlternativePath;
|
||||
super::RetrievePackedPathFromHeap(_forwardHeap, _backwardHeap, middleNodeIDOfAlternativePath, packedAlternativePath);
|
||||
|
||||
if(packedShortestPath.size() < 2 || packedAlternativePath.size() < 2)
|
||||
return 0;
|
||||
|
||||
int sharing = 0;
|
||||
int aindex = 0;
|
||||
//compute forward sharing
|
||||
while( (packedAlternativePath[aindex] == packedShortestPath[aindex]) && (packedAlternativePath[aindex+1] == packedShortestPath[aindex+1]) ) {
|
||||
// INFO("retrieving edge (" << packedAlternativePath[aindex] << "," << packedAlternativePath[aindex+1] << ")");
|
||||
typename QueryDataT::Graph::EdgeIterator edgeID = super::_queryData.graph->FindEdgeInEitherDirection(packedAlternativePath[aindex], packedAlternativePath[aindex+1]);
|
||||
sharing += super::_queryData.graph->GetEdgeData(edgeID).distance;
|
||||
++aindex;
|
||||
}
|
||||
|
||||
aindex = packedAlternativePath.size()-1;
|
||||
int bindex = packedShortestPath.size()-1;
|
||||
//compute backward sharing
|
||||
while( aindex > 0 && bindex > 0 && (packedAlternativePath[aindex] == packedShortestPath[bindex]) && (packedAlternativePath[aindex-1] == packedShortestPath[bindex-1]) ) {
|
||||
typename QueryDataT::Graph::EdgeIterator edgeID = super::_queryData.graph->FindEdgeInEitherDirection(packedAlternativePath[aindex], packedAlternativePath[aindex-1]);
|
||||
sharing += super::_queryData.graph->GetEdgeData(edgeID).distance;
|
||||
--aindex; --bindex;
|
||||
}
|
||||
return sharing;
|
||||
}
|
||||
|
||||
inline void AlternativeRoutingStep(HeapPtr & _forwardHeap, HeapPtr & _backwardHeap, NodeID *middle, int *_upperbound, const int edgeBasedOffset, const bool forwardDirection, std::vector<NodeID>& searchSpaceIntersection) const {
|
||||
const NodeID node = _forwardHeap->DeleteMin();
|
||||
|
||||
const int distance = _forwardHeap->GetKey(node);
|
||||
if(_backwardHeap->WasInserted(node) ){
|
||||
searchSpaceIntersection.push_back(node);
|
||||
|
||||
const int newDistance = _backwardHeap->GetKey(node) + distance;
|
||||
if(newDistance < *_upperbound ){
|
||||
if(newDistance>=0 ) {
|
||||
*middle = node;
|
||||
*_upperbound = newDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if((distance-edgeBasedOffset)*(1+VIAPATH_EPSILON) > *_upperbound){
|
||||
_forwardHeap->DeleteAll();
|
||||
return;
|
||||
}
|
||||
|
||||
for ( typename QueryDataT::Graph::EdgeIterator edge = super::_queryData.graph->BeginEdges( node ); edge < super::_queryData.graph->EndEdges(node); edge++ ) {
|
||||
const typename QueryDataT::Graph::EdgeData & data = super::_queryData.graph->GetEdgeData(edge);
|
||||
bool forwardDirectionFlag = (forwardDirection ? data.forward : data.backward );
|
||||
if(forwardDirectionFlag) {
|
||||
|
||||
const NodeID to = super::_queryData.graph->GetTarget(edge);
|
||||
const int edgeWeight = data.distance;
|
||||
|
||||
assert( edgeWeight > 0 );
|
||||
const int toDistance = distance + edgeWeight;
|
||||
|
||||
//New Node discovered -> Add to Heap + Node Info Storage
|
||||
if ( !_forwardHeap->WasInserted( to ) ) {
|
||||
_forwardHeap->Insert( to, toDistance, node );
|
||||
|
||||
}
|
||||
//Found a shorter Path -> Update distance
|
||||
else if ( toDistance < _forwardHeap->GetKey( to ) ) {
|
||||
_forwardHeap->GetData( to ).parent = node;
|
||||
_forwardHeap->DecreaseKey( to, toDistance );
|
||||
//new parent
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//conduct T-Test
|
||||
inline bool viaNodeCandidatePasses_T_Test( HeapPtr& existingForwardHeap, HeapPtr& existingBackwardHeap, HeapPtr& newForwardHeap, HeapPtr& newBackwardHeap, const RankedCandidateNode& candidate, const int offset, const int lengthOfShortestPath, int * lengthOfViaPath, NodeID * s_v_middle, NodeID * v_t_middle) {
|
||||
std::deque < NodeID > packed_s_v_path;
|
||||
std::deque < NodeID > packed_v_t_path;
|
||||
|
||||
super::_queryData.InitializeOrClearSecondThreadLocalStorage();
|
||||
*s_v_middle = UINT_MAX;
|
||||
int upperBoundFor_s_v_Path = INT_MAX;
|
||||
//compute path <s,..,v> by reusing forward search from s
|
||||
newBackwardHeap->Insert(candidate.node, 0, candidate.node);
|
||||
while (newBackwardHeap->Size() > 0) {
|
||||
super::RoutingStep(newBackwardHeap, existingForwardHeap, s_v_middle, &upperBoundFor_s_v_Path, 2*offset, false);
|
||||
}
|
||||
|
||||
if(INT_MAX == upperBoundFor_s_v_Path)
|
||||
return false;
|
||||
|
||||
//compute path <v,..,t> by reusing backward search from t
|
||||
*v_t_middle = UINT_MAX;
|
||||
int upperBoundFor_v_t_Path = INT_MAX;
|
||||
newForwardHeap->Insert(candidate.node, 0, candidate.node);
|
||||
while (newForwardHeap->Size() > 0) {
|
||||
super::RoutingStep(newForwardHeap, existingBackwardHeap, v_t_middle, &upperBoundFor_v_t_Path, 2*offset, true);
|
||||
}
|
||||
|
||||
if(INT_MAX == upperBoundFor_v_t_Path)
|
||||
return false;
|
||||
|
||||
*lengthOfViaPath = upperBoundFor_s_v_Path + upperBoundFor_v_t_Path;
|
||||
|
||||
//retrieve packed paths
|
||||
super::RetrievePackedPathFromHeap(existingForwardHeap, newBackwardHeap, *s_v_middle, packed_s_v_path);
|
||||
super::RetrievePackedPathFromHeap(newForwardHeap, existingBackwardHeap, *v_t_middle, packed_v_t_path);
|
||||
|
||||
NodeID s_P = *s_v_middle, t_P = *v_t_middle;
|
||||
const int T_threshold = VIAPATH_EPSILON * lengthOfShortestPath;
|
||||
int unpackedUntilDistance = 0;
|
||||
|
||||
std::stack<UnpackEdge> unpackStack;
|
||||
//Traverse path s-->v
|
||||
for (unsigned i = packed_s_v_path.size() - 1; (i > 0) && unpackStack.empty(); --i) {
|
||||
typename QueryDataT::Graph::EdgeIterator edgeID = super::_queryData.graph->FindEdgeInEitherDirection( packed_s_v_path[i - 1], packed_s_v_path[i]);
|
||||
int lengthOfCurrentEdge = super::_queryData.graph->GetEdgeData(edgeID).distance;
|
||||
if (lengthOfCurrentEdge + unpackedUntilDistance >= T_threshold) {
|
||||
unpackStack.push(std::make_pair(packed_s_v_path[i - 1], packed_s_v_path[i]));
|
||||
} else {
|
||||
unpackedUntilDistance += lengthOfCurrentEdge;
|
||||
s_P = packed_s_v_path[i - 1];
|
||||
}
|
||||
}
|
||||
|
||||
while (!unpackStack.empty()) {
|
||||
const UnpackEdge viaPathEdge = unpackStack.top();
|
||||
unpackStack.pop();
|
||||
typename QueryDataT::Graph::EdgeIterator edgeIDInViaPath = super::_queryData.graph->FindEdgeInEitherDirection(viaPathEdge.first, viaPathEdge.second);
|
||||
if(UINT_MAX == edgeIDInViaPath)
|
||||
return false;
|
||||
typename QueryDataT::Graph::EdgeData currentEdgeData = super::_queryData.graph->GetEdgeData(edgeIDInViaPath);
|
||||
bool IsViaEdgeShortCut = currentEdgeData.shortcut;
|
||||
if (IsViaEdgeShortCut) {
|
||||
const NodeID middleOfViaPath = currentEdgeData.id;
|
||||
typename QueryDataT::Graph::EdgeIterator edgeIDOfSecondSegment = super::_queryData.graph->FindEdgeInEitherDirection(middleOfViaPath, viaPathEdge.second);
|
||||
int lengthOfSecondSegment = super::_queryData.graph->GetEdgeData(edgeIDOfSecondSegment).distance;
|
||||
//attention: !unpacking in reverse!
|
||||
//Check if second segment is the one to go over treshold? if yes add second segment to stack, else push first segment to stack and add distance of second one.
|
||||
if (unpackedUntilDistance + lengthOfSecondSegment >= T_threshold) {
|
||||
unpackStack.push(std::make_pair(middleOfViaPath, viaPathEdge.second));
|
||||
} else {
|
||||
unpackedUntilDistance += lengthOfSecondSegment;
|
||||
unpackStack.push(std::make_pair(viaPathEdge.first, middleOfViaPath));
|
||||
}
|
||||
} else {
|
||||
// edge is not a shortcut, set the start node for T-Test to end of edge.
|
||||
unpackedUntilDistance += currentEdgeData.distance;
|
||||
s_P = viaPathEdge.first;
|
||||
}
|
||||
}
|
||||
|
||||
int lengthOfPathT_Test_Path = unpackedUntilDistance;
|
||||
unpackedUntilDistance = 0;
|
||||
//Traverse path s-->v
|
||||
for (unsigned i = 0, lengthOfPackedPath = packed_v_t_path.size() - 1; (i < lengthOfPackedPath) && unpackStack.empty(); ++i) {
|
||||
typename QueryDataT::Graph::EdgeIterator edgeID = super::_queryData.graph->FindEdgeInEitherDirection( packed_v_t_path[i], packed_v_t_path[i + 1]);
|
||||
int lengthOfCurrentEdge = super::_queryData.graph->GetEdgeData(edgeID).distance;
|
||||
if (lengthOfCurrentEdge + unpackedUntilDistance >= T_threshold) {
|
||||
unpackStack.push( std::make_pair(packed_v_t_path[i], packed_v_t_path[i + 1]));
|
||||
} else {
|
||||
unpackedUntilDistance += lengthOfCurrentEdge;
|
||||
t_P = packed_v_t_path[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
while (!unpackStack.empty()) {
|
||||
const UnpackEdge viaPathEdge = unpackStack.top();
|
||||
unpackStack.pop();
|
||||
typename QueryDataT::Graph::EdgeIterator edgeIDInViaPath = super::_queryData.graph->FindEdgeInEitherDirection(viaPathEdge.first, viaPathEdge.second);
|
||||
if(UINT_MAX == edgeIDInViaPath)
|
||||
return false;
|
||||
typename QueryDataT::Graph::EdgeData currentEdgeData = super::_queryData.graph->GetEdgeData(edgeIDInViaPath);
|
||||
const bool IsViaEdgeShortCut = currentEdgeData.shortcut;
|
||||
if (IsViaEdgeShortCut) {
|
||||
const NodeID middleOfViaPath = currentEdgeData.id;
|
||||
typename QueryDataT::Graph::EdgeIterator edgeIDOfFirstSegment = super::_queryData.graph->FindEdgeInEitherDirection(viaPathEdge.first, middleOfViaPath);
|
||||
int lengthOfFirstSegment = super::_queryData.graph->GetEdgeData( edgeIDOfFirstSegment).distance;
|
||||
//Check if first segment is the one to go over treshold? if yes first segment to stack, else push second segment to stack and add distance of first one.
|
||||
if (unpackedUntilDistance + lengthOfFirstSegment >= T_threshold) {
|
||||
unpackStack.push( std::make_pair(viaPathEdge.first, middleOfViaPath));
|
||||
} else {
|
||||
unpackedUntilDistance += lengthOfFirstSegment;
|
||||
unpackStack.push( std::make_pair(middleOfViaPath, viaPathEdge.second));
|
||||
}
|
||||
} else {
|
||||
// edge is not a shortcut, set the start node for T-Test to end of edge.
|
||||
unpackedUntilDistance += currentEdgeData.distance;
|
||||
t_P = viaPathEdge.second;
|
||||
}
|
||||
}
|
||||
|
||||
lengthOfPathT_Test_Path += unpackedUntilDistance;
|
||||
//Run actual T-Test query and compare if distances equal.
|
||||
HeapPtr& forwardHeap = super::_queryData.forwardHeap3;
|
||||
HeapPtr& backwardHeap = super::_queryData.backwardHeap3;
|
||||
super::_queryData.InitializeOrClearThirdThreadLocalStorage();
|
||||
int _upperBound = INT_MAX;
|
||||
NodeID middle = UINT_MAX;
|
||||
forwardHeap->Insert(s_P, 0, s_P);
|
||||
backwardHeap->Insert(t_P, 0, t_P);
|
||||
//exploration from s and t until deletemin/(1+epsilon) > _lengthOfShortestPath
|
||||
while (forwardHeap->Size() + backwardHeap->Size() > 0) {
|
||||
if (forwardHeap->Size() > 0) {
|
||||
super::RoutingStep(forwardHeap, backwardHeap, &middle, &_upperBound, offset, true);
|
||||
}
|
||||
if (backwardHeap->Size() > 0) {
|
||||
super::RoutingStep(backwardHeap, forwardHeap, &middle, &_upperBound, offset, false);
|
||||
}
|
||||
}
|
||||
return (_upperBound <= lengthOfPathT_Test_Path);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* ALTERNATIVEROUTES_H_ */
|
232
RoutingAlgorithms/BasicRoutingInterface.h
Normal file
232
RoutingAlgorithms/BasicRoutingInterface.h
Normal file
@ -0,0 +1,232 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef BASICROUTINGINTERFACE_H_
|
||||
#define BASICROUTINGINTERFACE_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
|
||||
#include "../Plugins/RawRouteData.h"
|
||||
|
||||
template<class QueryDataT>
|
||||
class BasicRoutingInterface {
|
||||
protected:
|
||||
QueryDataT & _queryData;
|
||||
public:
|
||||
BasicRoutingInterface(QueryDataT & qd) : _queryData(qd) { }
|
||||
virtual ~BasicRoutingInterface(){ };
|
||||
|
||||
inline void RoutingStep(typename QueryDataT::HeapPtr & _forwardHeap, typename QueryDataT::HeapPtr & _backwardHeap, NodeID *middle, int *_upperbound, const int edgeBasedOffset, const bool forwardDirection) const {
|
||||
const NodeID node = _forwardHeap->DeleteMin();
|
||||
const int distance = _forwardHeap->GetKey(node);
|
||||
// INFO((forwardDirection ? "[forw]" : "[back]") << " settled node " << node << " at distance " << distance);
|
||||
if(_backwardHeap->WasInserted(node) ){
|
||||
// INFO((forwardDirection ? "[forw]" : "[back]") << " scanned node " << node << " in both directions, upper bound: " << *_upperbound);
|
||||
const int newDistance = _backwardHeap->GetKey(node) + distance;
|
||||
if(newDistance < *_upperbound ){
|
||||
if(newDistance>=0 ) {
|
||||
// INFO((forwardDirection ? "[forw]" : "[back]") << " -> node " << node << " is new middle at total distance " << newDistance);
|
||||
*middle = node;
|
||||
*_upperbound = newDistance;
|
||||
} else {
|
||||
// INFO((forwardDirection ? "[forw]" : "[back]") << " -> ignored " << node << " as new middle at total distance " << newDistance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(distance-edgeBasedOffset > *_upperbound){
|
||||
_forwardHeap->DeleteAll();
|
||||
return;
|
||||
}
|
||||
|
||||
for ( typename QueryDataT::Graph::EdgeIterator edge = _queryData.graph->BeginEdges( node ); edge < _queryData.graph->EndEdges(node); edge++ ) {
|
||||
const typename QueryDataT::Graph::EdgeData & data = _queryData.graph->GetEdgeData(edge);
|
||||
bool backwardDirectionFlag = (!forwardDirection) ? data.forward : data.backward;
|
||||
if(backwardDirectionFlag) {
|
||||
const NodeID to = _queryData.graph->GetTarget(edge);
|
||||
const int edgeWeight = data.distance;
|
||||
|
||||
assert( edgeWeight > 0 );
|
||||
|
||||
//Stalling
|
||||
if(_forwardHeap->WasInserted( to )) {
|
||||
if(_forwardHeap->GetKey( to ) + edgeWeight < distance) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ( typename QueryDataT::Graph::EdgeIterator edge = _queryData.graph->BeginEdges( node ); edge < _queryData.graph->EndEdges(node); edge++ ) {
|
||||
const typename QueryDataT::Graph::EdgeData & data = _queryData.graph->GetEdgeData(edge);
|
||||
bool forwardDirectionFlag = (forwardDirection ? data.forward : data.backward );
|
||||
if(forwardDirectionFlag) {
|
||||
|
||||
const NodeID to = _queryData.graph->GetTarget(edge);
|
||||
const int edgeWeight = data.distance;
|
||||
|
||||
assert( edgeWeight > 0 );
|
||||
const int toDistance = distance + edgeWeight;
|
||||
|
||||
//New Node discovered -> Add to Heap + Node Info Storage
|
||||
if ( !_forwardHeap->WasInserted( to ) ) {
|
||||
// INFO((forwardDirection ? "[forw]" : "[back]") << " scanning edge (" << node << "," << to << ") with distance " << toDistance << ", edge length: " << data.distance);
|
||||
_forwardHeap->Insert( to, toDistance, node );
|
||||
}
|
||||
//Found a shorter Path -> Update distance
|
||||
else if ( toDistance < _forwardHeap->GetKey( to ) ) {
|
||||
// INFO((forwardDirection ? "[forw]" : "[back]") << " decrease and scanning edge (" << node << "," << to << ") from " << _forwardHeap->GetKey(to) << "to " << toDistance << ", edge length: " << data.distance);
|
||||
_forwardHeap->GetData( to ).parent = node;
|
||||
_forwardHeap->DecreaseKey( to, toDistance );
|
||||
//new parent
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void UnpackPath(std::deque<NodeID> & packedPath, std::vector<_PathData> & unpackedPath) const {
|
||||
|
||||
const unsigned sizeOfPackedPath = packedPath.size();
|
||||
std::stack<std::pair<NodeID, NodeID> > recursionStack;
|
||||
|
||||
//We have to push the path in reverse order onto the stack because it's LIFO.
|
||||
for(unsigned i = sizeOfPackedPath-1; i > 0; --i){
|
||||
recursionStack.push(std::make_pair(packedPath[i-1], packedPath[i]));
|
||||
}
|
||||
|
||||
std::pair<NodeID, NodeID> edge;
|
||||
while(!recursionStack.empty()) {
|
||||
edge = recursionStack.top();
|
||||
recursionStack.pop();
|
||||
// INFO("Unpacking edge (" << edge.first << "," << edge.second << ")");
|
||||
|
||||
typename QueryDataT::Graph::EdgeIterator smallestEdge = SPECIAL_EDGEID;
|
||||
int smallestWeight = INT_MAX;
|
||||
for(typename QueryDataT::Graph::EdgeIterator eit = _queryData.graph->BeginEdges(edge.first);eit < _queryData.graph->EndEdges(edge.first);++eit){
|
||||
const int weight = _queryData.graph->GetEdgeData(eit).distance;
|
||||
// INFO("Checking edge (" << edge.first << "/" << _queryData.graph->GetTarget(eit) << ")");
|
||||
if(_queryData.graph->GetTarget(eit) == edge.second && weight < smallestWeight && _queryData.graph->GetEdgeData(eit).forward){
|
||||
// INFO("1smallest " << eit << ", " << weight);
|
||||
smallestEdge = eit;
|
||||
smallestWeight = weight;
|
||||
}
|
||||
}
|
||||
|
||||
if(smallestEdge == SPECIAL_EDGEID){
|
||||
for(typename QueryDataT::Graph::EdgeIterator eit = _queryData.graph->BeginEdges(edge.second);eit < _queryData.graph->EndEdges(edge.second);++eit){
|
||||
const int weight = _queryData.graph->GetEdgeData(eit).distance;
|
||||
// INFO("Checking edge (" << edge.first << "/" << _queryData.graph->GetTarget(eit) << ")");
|
||||
if(_queryData.graph->GetTarget(eit) == edge.first && weight < smallestWeight && _queryData.graph->GetEdgeData(eit).backward){
|
||||
// INFO("2smallest " << eit << ", " << weight);
|
||||
smallestEdge = eit;
|
||||
smallestWeight = weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(smallestWeight != INT_MAX);
|
||||
|
||||
const typename QueryDataT::Graph::EdgeData& ed = _queryData.graph->GetEdgeData(smallestEdge);
|
||||
if(ed.shortcut) {//unpack
|
||||
const NodeID middle = ed.id;
|
||||
//again, we need to this in reversed order
|
||||
recursionStack.push(std::make_pair(middle, edge.second));
|
||||
recursionStack.push(std::make_pair(edge.first, middle));
|
||||
} else {
|
||||
assert(!ed.shortcut);
|
||||
unpackedPath.push_back(_PathData(ed.id, _queryData.nodeHelpDesk->getNameIndexFromEdgeID(ed.id), _queryData.nodeHelpDesk->getTurnInstructionFromEdgeID(ed.id), ed.distance) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void UnpackEdge(const NodeID s, const NodeID t, std::vector<NodeID> & unpackedPath) const {
|
||||
|
||||
std::stack<std::pair<NodeID, NodeID> > recursionStack;
|
||||
recursionStack.push(std::make_pair(s,t));
|
||||
|
||||
std::pair<NodeID, NodeID> edge;
|
||||
while(!recursionStack.empty()) {
|
||||
edge = recursionStack.top();
|
||||
recursionStack.pop();
|
||||
|
||||
typename QueryDataT::Graph::EdgeIterator smallestEdge = SPECIAL_EDGEID;
|
||||
int smallestWeight = INT_MAX;
|
||||
for(typename QueryDataT::Graph::EdgeIterator eit = _queryData.graph->BeginEdges(edge.first);eit < _queryData.graph->EndEdges(edge.first);++eit){
|
||||
const int weight = _queryData.graph->GetEdgeData(eit).distance;
|
||||
if(_queryData.graph->GetTarget(eit) == edge.second && weight < smallestWeight && _queryData.graph->GetEdgeData(eit).forward){
|
||||
smallestEdge = eit;
|
||||
smallestWeight = weight;
|
||||
}
|
||||
}
|
||||
|
||||
if(smallestEdge == SPECIAL_EDGEID){
|
||||
for(typename QueryDataT::Graph::EdgeIterator eit = _queryData.graph->BeginEdges(edge.second);eit < _queryData.graph->EndEdges(edge.second);++eit){
|
||||
const int weight = _queryData.graph->GetEdgeData(eit).distance;
|
||||
if(_queryData.graph->GetTarget(eit) == edge.first && weight < smallestWeight && _queryData.graph->GetEdgeData(eit).backward){
|
||||
smallestEdge = eit;
|
||||
smallestWeight = weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(smallestWeight != INT_MAX);
|
||||
|
||||
const typename QueryDataT::Graph::EdgeData& ed = _queryData.graph->GetEdgeData(smallestEdge);
|
||||
if(ed.shortcut) {//unpack
|
||||
const NodeID middle = ed.id;
|
||||
//again, we need to this in reversed order
|
||||
// INFO("unpacking (" << middle << "," << edge.second << ") and (" << edge.first << "," << middle << ")");
|
||||
recursionStack.push(std::make_pair(middle, edge.second));
|
||||
recursionStack.push(std::make_pair(edge.first, middle));
|
||||
} else {
|
||||
assert(!ed.shortcut);
|
||||
unpackedPath.push_back(edge.first );
|
||||
}
|
||||
}
|
||||
unpackedPath.push_back(t);
|
||||
}
|
||||
|
||||
inline void RetrievePackedPathFromHeap(const typename QueryDataT::HeapPtr & _fHeap, const typename QueryDataT::HeapPtr & _bHeap, const NodeID middle, std::deque<NodeID>& packedPath) {
|
||||
NodeID pathNode = middle;
|
||||
if(_fHeap->GetData(pathNode).parent != middle) {
|
||||
do {
|
||||
pathNode = _fHeap->GetData(pathNode).parent;
|
||||
|
||||
packedPath.push_front(pathNode);
|
||||
}while(pathNode != _fHeap->GetData(pathNode).parent);
|
||||
}
|
||||
packedPath.push_back(middle);
|
||||
pathNode = middle;
|
||||
if(_bHeap->GetData(pathNode).parent != middle) {
|
||||
do{
|
||||
pathNode = _bHeap->GetData(pathNode).parent;
|
||||
packedPath.push_back(pathNode);
|
||||
} while (pathNode != _bHeap->GetData(pathNode).parent);
|
||||
}
|
||||
// std::cout << "unpacking: ";
|
||||
// for(std::deque<NodeID>::iterator it = packedPath.begin(); it != packedPath.end(); ++it)
|
||||
// std::cout << *it << " ";
|
||||
// std::cout << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif /* BASICROUTINGINTERFACE_H_ */
|
261
RoutingAlgorithms/ShortestPathRouting.h
Normal file
261
RoutingAlgorithms/ShortestPathRouting.h
Normal file
@ -0,0 +1,261 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef SHORTESTPATHROUTING_H_
|
||||
#define SHORTESTPATHROUTING_H_
|
||||
|
||||
#include "BasicRoutingInterface.h"
|
||||
|
||||
template<class QueryDataT>
|
||||
class ShortestPathRouting : public BasicRoutingInterface<QueryDataT>{
|
||||
typedef BasicRoutingInterface<QueryDataT> super;
|
||||
public:
|
||||
ShortestPathRouting(QueryDataT & qd) : super(qd) {}
|
||||
|
||||
~ShortestPathRouting() {}
|
||||
|
||||
void operator()(std::vector<PhantomNodes> & phantomNodesVector, RawRouteData & rawRouteData) {
|
||||
BOOST_FOREACH(PhantomNodes & phantomNodePair, phantomNodesVector) {
|
||||
if(!phantomNodePair.AtLeastOnePhantomNodeIsUINTMAX()) {
|
||||
rawRouteData.lengthOfShortestPath = rawRouteData.lengthOfAlternativePath = INT_MAX;
|
||||
return;
|
||||
}
|
||||
}
|
||||
int distance1 = 0;
|
||||
int distance2 = 0;
|
||||
|
||||
bool searchFrom1stStartNode(true);
|
||||
bool searchFrom2ndStartNode(true);
|
||||
NodeID middle1 = ( NodeID ) UINT_MAX;
|
||||
NodeID middle2 = ( NodeID ) UINT_MAX;
|
||||
std::deque<NodeID> packedPath1;
|
||||
std::deque<NodeID> packedPath2;
|
||||
|
||||
typename QueryDataT::HeapPtr & forwardHeap = super::_queryData.forwardHeap;
|
||||
typename QueryDataT::HeapPtr & backwardHeap = super::_queryData.backwardHeap;
|
||||
|
||||
typename QueryDataT::HeapPtr & forwardHeap2 = super::_queryData.forwardHeap2;
|
||||
typename QueryDataT::HeapPtr & backwardHeap2 = super::_queryData.backwardHeap2;
|
||||
|
||||
|
||||
//Get distance to next pair of target nodes.
|
||||
BOOST_FOREACH(PhantomNodes & phantomNodePair, phantomNodesVector) {
|
||||
super::_queryData.InitializeOrClearFirstThreadLocalStorage();
|
||||
super::_queryData.InitializeOrClearSecondThreadLocalStorage();
|
||||
|
||||
int _localUpperbound1 = INT_MAX;
|
||||
int _localUpperbound2 = INT_MAX;
|
||||
|
||||
//insert new starting nodes into forward heap, adjusted by previous distances.
|
||||
if(searchFrom1stStartNode) {
|
||||
forwardHeap->Insert(phantomNodePair.startPhantom.edgeBasedNode, -phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode);
|
||||
forwardHeap2->Insert(phantomNodePair.startPhantom.edgeBasedNode, -phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode);
|
||||
// INFO("a 1,2)forw insert " << phantomNodePair.startPhantom.edgeBasedNode << " with weight " << phantomNodePair.startPhantom.weight1);
|
||||
// } else {
|
||||
// INFO("Skipping first start node");
|
||||
}
|
||||
if(phantomNodePair.startPhantom.isBidirected() && searchFrom2ndStartNode) {
|
||||
forwardHeap->Insert(phantomNodePair.startPhantom.edgeBasedNode+1, -phantomNodePair.startPhantom.weight2, phantomNodePair.startPhantom.edgeBasedNode+1);
|
||||
forwardHeap2->Insert(phantomNodePair.startPhantom.edgeBasedNode+1, -phantomNodePair.startPhantom.weight2, phantomNodePair.startPhantom.edgeBasedNode+1);
|
||||
// INFO("b 1,2)forw insert " << phantomNodePair.startPhantom.edgeBasedNode+1 << " with weight " << -phantomNodePair.startPhantom.weight1);
|
||||
// } else if(!searchFrom2ndStartNode) {
|
||||
// INFO("Skipping second start node");
|
||||
}
|
||||
|
||||
// backwardHeap->Clear();
|
||||
// backwardHeap2->Clear();
|
||||
//insert new backward nodes into backward heap, unadjusted.
|
||||
backwardHeap->Insert(phantomNodePair.targetPhantom.edgeBasedNode, phantomNodePair.targetPhantom.weight1, phantomNodePair.targetPhantom.edgeBasedNode);
|
||||
// INFO("1) back insert " << phantomNodePair.targetPhantom.edgeBasedNode << " with weight " << phantomNodePair.targetPhantom.weight1);
|
||||
if(phantomNodePair.targetPhantom.isBidirected() ) {
|
||||
// INFO("2) back insert " << phantomNodePair.targetPhantom.edgeBasedNode+1 << " with weight " << phantomNodePair.targetPhantom.weight2);
|
||||
backwardHeap2->Insert(phantomNodePair.targetPhantom.edgeBasedNode+1, phantomNodePair.targetPhantom.weight2, phantomNodePair.targetPhantom.edgeBasedNode+1);
|
||||
}
|
||||
int offset = (phantomNodePair.startPhantom.isBidirected() ? std::max(phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.weight2) : phantomNodePair.startPhantom.weight1) ;
|
||||
offset += (phantomNodePair.targetPhantom.isBidirected() ? std::max(phantomNodePair.targetPhantom.weight1, phantomNodePair.targetPhantom.weight2) : phantomNodePair.targetPhantom.weight1) ;
|
||||
|
||||
//run two-Target Dijkstra routing step.
|
||||
while(forwardHeap->Size() + backwardHeap->Size() > 0){
|
||||
if(forwardHeap->Size() > 0){
|
||||
super::RoutingStep(forwardHeap, backwardHeap, &middle1, &_localUpperbound1, 2*offset, true);
|
||||
}
|
||||
if(backwardHeap->Size() > 0){
|
||||
super::RoutingStep(backwardHeap, forwardHeap, &middle1, &_localUpperbound1, 2*offset, false);
|
||||
}
|
||||
}
|
||||
if(backwardHeap2->Size() > 0) {
|
||||
while(forwardHeap2->Size() + backwardHeap2->Size() > 0){
|
||||
if(forwardHeap2->Size() > 0){
|
||||
super::RoutingStep(forwardHeap2, backwardHeap2, &middle2, &_localUpperbound2, 2*offset, true);
|
||||
}
|
||||
if(backwardHeap2->Size() > 0){
|
||||
super::RoutingStep(backwardHeap2, forwardHeap2, &middle2, &_localUpperbound2, 2*offset, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
// INFO("upperbound1: " << _localUpperbound1 << ", distance1: " << distance1);
|
||||
// INFO("upperbound2: " << _localUpperbound2 << ", distance2: " << distance2);
|
||||
|
||||
//No path found for both target nodes?
|
||||
if(INT_MAX == _localUpperbound1 && INT_MAX == _localUpperbound2) {
|
||||
rawRouteData.lengthOfShortestPath = rawRouteData.lengthOfAlternativePath = INT_MAX;
|
||||
return;
|
||||
}
|
||||
if(UINT_MAX == middle1) {
|
||||
searchFrom1stStartNode = false;
|
||||
// INFO("Next Search will not start from 1st");
|
||||
} else {
|
||||
// INFO("Next Search will start from 1st");
|
||||
searchFrom1stStartNode = true;
|
||||
}
|
||||
if(UINT_MAX == middle2) {
|
||||
searchFrom2ndStartNode = false;
|
||||
// INFO("Next Search will not start from 2nd");
|
||||
} else {
|
||||
searchFrom2ndStartNode = true;
|
||||
// INFO("Next Search will start from 2nd");
|
||||
}
|
||||
|
||||
//Was at most one of the two paths not found?
|
||||
assert(!(INT_MAX == distance1 && INT_MAX == distance2));
|
||||
|
||||
// INFO("middle1: " << middle1);
|
||||
|
||||
//Unpack paths if they exist
|
||||
std::deque<NodeID> temporaryPackedPath1;
|
||||
std::deque<NodeID> temporaryPackedPath2;
|
||||
if(INT_MAX != _localUpperbound1) {
|
||||
super::RetrievePackedPathFromHeap(forwardHeap, backwardHeap, middle1, temporaryPackedPath1);
|
||||
// INFO("temporaryPackedPath1 ends with " << *(temporaryPackedPath1.end()-1) );
|
||||
}
|
||||
// INFO("middle2: " << middle2);
|
||||
|
||||
if(INT_MAX != _localUpperbound2) {
|
||||
super::RetrievePackedPathFromHeap(forwardHeap2, backwardHeap2, middle2, temporaryPackedPath2);
|
||||
// INFO("temporaryPackedPath2 ends with " << *(temporaryPackedPath2.end()-1) );
|
||||
}
|
||||
|
||||
//if one of the paths was not found, replace it with the other one.
|
||||
if(0 == temporaryPackedPath1.size()) {
|
||||
// INFO("Deleting path 1");
|
||||
temporaryPackedPath1.insert(temporaryPackedPath1.end(), temporaryPackedPath2.begin(), temporaryPackedPath2.end());
|
||||
_localUpperbound1 = _localUpperbound2;
|
||||
}
|
||||
if(0 == temporaryPackedPath2.size()) {
|
||||
// INFO("Deleting path 2");
|
||||
temporaryPackedPath2.insert(temporaryPackedPath2.end(), temporaryPackedPath1.begin(), temporaryPackedPath1.end());
|
||||
_localUpperbound2 = _localUpperbound1;
|
||||
}
|
||||
|
||||
assert(0 < temporaryPackedPath1.size() && 0 < temporaryPackedPath2.size());
|
||||
|
||||
//Plug paths together, s.t. end of packed path is begin of temporary packed path
|
||||
if(0 < packedPath1.size() && 0 < packedPath2.size() ) {
|
||||
// INFO("Both paths are non-empty");
|
||||
if( *(temporaryPackedPath1.begin()) == *(temporaryPackedPath2.begin())) {
|
||||
// INFO("both paths start with the same node:" << *(temporaryPackedPath1.begin()));
|
||||
//both new route segments start with the same node, thus one of the packedPath must go.
|
||||
assert( (packedPath1.size() == packedPath2.size() ) || (*(packedPath1.end()-1) != *(packedPath2.end()-1)) );
|
||||
if( *(packedPath1.end()-1) == *(temporaryPackedPath1.begin())) {
|
||||
// INFO("Deleting packedPath2 that ends with " << *(packedPath2.end()-1) << ", other ends with " << *(packedPath1.end()-1));
|
||||
packedPath2.clear();
|
||||
packedPath2.insert(packedPath2.end(), packedPath1.begin(), packedPath1.end());
|
||||
distance2 = distance1;
|
||||
// INFO("packedPath2 now ends with " << *(packedPath2.end()-1));
|
||||
} else {
|
||||
// INFO("Deleting path1 that ends with " << *(packedPath1.end()-1) << ", other ends with " << *(packedPath2.end()-1));
|
||||
packedPath1.clear();
|
||||
packedPath1.insert(packedPath1.end(), packedPath2.begin(), packedPath2.end());
|
||||
distance1 = distance2;
|
||||
// INFO("Path1 now ends with " << *(packedPath1.end()-1));
|
||||
}
|
||||
} else {
|
||||
//packed paths 1 and 2 may need to switch.
|
||||
if(*(packedPath1.end()-1) != *(temporaryPackedPath1.begin())) {
|
||||
// INFO("Switching");
|
||||
packedPath1.swap(packedPath2);
|
||||
std::swap(distance1, distance2);
|
||||
}
|
||||
}
|
||||
}
|
||||
packedPath1.insert(packedPath1.end(), temporaryPackedPath1.begin(), temporaryPackedPath1.end());
|
||||
packedPath2.insert(packedPath2.end(), temporaryPackedPath2.begin(), temporaryPackedPath2.end());
|
||||
|
||||
if( (packedPath1.back() == packedPath2.back()) && phantomNodePair.targetPhantom.isBidirected() ) {
|
||||
// INFO("both paths end in same direction on bidirected edge, make sure start only start with : " << packedPath1.back());
|
||||
|
||||
NodeID lastNodeID = packedPath2.back();
|
||||
searchFrom1stStartNode &= !(lastNodeID == phantomNodePair.targetPhantom.edgeBasedNode+1);
|
||||
searchFrom2ndStartNode &= !(lastNodeID == phantomNodePair.targetPhantom.edgeBasedNode);
|
||||
// INFO("Next search from node " << phantomNodePair.targetPhantom.edgeBasedNode << ": " << (searchFrom1stStartNode ? "yes" : "no") );
|
||||
// INFO("Next search from node " << phantomNodePair.targetPhantom.edgeBasedNode+1 << ": " << (searchFrom2ndStartNode ? "yes" : "no") );
|
||||
}
|
||||
|
||||
distance1 += _localUpperbound1;
|
||||
distance2 += _localUpperbound2;
|
||||
}
|
||||
|
||||
// INFO("length path1: " << distance1);
|
||||
// INFO("length path2: " << distance2);
|
||||
if(distance1 <= distance2){
|
||||
//remove consecutive duplicates
|
||||
// std::cout << "unclean 1: ";
|
||||
// for(unsigned i = 0; i < packedPath1.size(); ++i)
|
||||
// std::cout << packedPath1[i] << " ";
|
||||
// std::cout << std::endl;
|
||||
|
||||
// std::cout << "cleaned 1: ";
|
||||
// for(unsigned i = 0; i < packedPath1.size(); ++i)
|
||||
// std::cout << packedPath1[i] << " ";
|
||||
// std::cout << std::endl;
|
||||
// super::UnpackPath(packedPath1, rawRouteData.computedShortestPath);
|
||||
} else {
|
||||
std::swap(packedPath1, packedPath2);
|
||||
// std::cout << "unclean 2: ";
|
||||
// for(unsigned i = 0; i < packedPath2.size(); ++i)
|
||||
// std::cout << packedPath2[i] << " ";
|
||||
// std::cout << std::endl;
|
||||
// _RemoveConsecutiveDuplicatesFromContainer(packedPath2);
|
||||
// std::cout << "cleaned 2: ";
|
||||
// for(unsigned i = 0; i < packedPath2.size(); ++i)
|
||||
// std::cout << packedPath2[i] << " ";
|
||||
// std::cout << std::endl;
|
||||
// super::UnpackPath(packedPath2, unpackedPath);
|
||||
}
|
||||
_RemoveConsecutiveDuplicatesFromContainer(packedPath1);
|
||||
super::UnpackPath(packedPath1, rawRouteData.computedShortestPath);
|
||||
rawRouteData.lengthOfShortestPath = std::min(distance1, distance2);
|
||||
// INFO("Found via route with distance " << std::min(distance1, distance2));
|
||||
return;
|
||||
}
|
||||
private:
|
||||
template<class ContainerT>
|
||||
void _RemoveConsecutiveDuplicatesFromContainer(ContainerT & packedPath) {
|
||||
//remove consecutive duplicates
|
||||
typename ContainerT::iterator it;
|
||||
// using default comparison:
|
||||
it = std::unique(packedPath.begin(), packedPath.end());
|
||||
packedPath.resize(it - packedPath.begin());
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* SHORTESTPATHROUTING_H_ */
|
Loading…
Reference in New Issue
Block a user