osrm-backend/RoutingAlgorithms/ShortestPathRouting.h

330 lines
13 KiB
C
Raw Normal View History

/*
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_
2013-09-21 16:18:27 -04:00
#include <boost/assert.hpp>
2013-09-21 16:18:27 -04:00
#include "BasicRoutingInterface.h"
2013-09-19 12:53:34 -04:00
#include "../DataStructures/SearchEngineData.h"
template<class DataFacadeT>
class ShortestPathRouting : public BasicRoutingInterface<DataFacadeT>{
typedef BasicRoutingInterface<DataFacadeT> super;
typedef SearchEngineData::QueryHeap QueryHeap;
2013-09-19 12:53:34 -04:00
SearchEngineData & engine_working_data;
public:
ShortestPathRouting(
DataFacadeT * facade,
SearchEngineData & engine_working_data
) :
super(facade),
engine_working_data(engine_working_data)
{}
~ShortestPathRouting() {}
void operator()(
std::vector<PhantomNodes> & phantom_nodes_vector,
RawRouteData & raw_route_data
) const {
BOOST_FOREACH(
const PhantomNodes & phantom_node_pair,
phantom_nodes_vector
){
if(!phantom_node_pair.AtLeastOnePhantomNodeIsUINTMAX()) {
raw_route_data.lengthOfShortestPath = INT_MAX;
raw_route_data.lengthOfAlternativePath = INT_MAX;
return;
}
}
int distance1 = 0;
int distance2 = 0;
bool search_from_1st_node = true;
bool search_from_2nd_node = true;
NodeID middle1 = UINT_MAX;
NodeID middle2 = UINT_MAX;
std::vector<NodeID> packed_path1;
std::vector<NodeID> packed_path2;
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
super::facade->GetNumberOfNodes()
);
engine_working_data.InitializeOrClearSecondThreadLocalStorage(
super::facade->GetNumberOfNodes()
);
engine_working_data.InitializeOrClearThirdThreadLocalStorage(
super::facade->GetNumberOfNodes()
);
QueryHeap & forward_heap1 = *(engine_working_data.forwardHeap);
QueryHeap & reverse_heap1 = *(engine_working_data.backwardHeap);
QueryHeap & forward_heap2 = *(engine_working_data.forwardHeap2);
QueryHeap & reverse_heap2 = *(engine_working_data.backwardHeap2);
//Get distance to next pair of target nodes.
BOOST_FOREACH(const PhantomNodes & phantom_node_pair, phantom_nodes_vector){
forward_heap1.Clear(); forward_heap2.Clear();
reverse_heap1.Clear(); reverse_heap2.Clear();
int local_upper_bound1 = INT_MAX;
int local_upper_bound2 = INT_MAX;
middle1 = UINT_MAX;
middle2 = UINT_MAX;
//insert new starting nodes into forward heap, adjusted by previous distances.
if(search_from_1st_node) {
forward_heap1.Insert(
phantom_node_pair.startPhantom.edgeBasedNode,
-phantom_node_pair.startPhantom.weight1,
phantom_node_pair.startPhantom.edgeBasedNode
);
// INFO("fw1: " << phantom_node_pair.startPhantom.edgeBasedNode << "´, w: " << -phantom_node_pair.startPhantom.weight1);
forward_heap2.Insert(
phantom_node_pair.startPhantom.edgeBasedNode,
-phantom_node_pair.startPhantom.weight1,
phantom_node_pair.startPhantom.edgeBasedNode
);
// INFO("fw2: " << phantom_node_pair.startPhantom.edgeBasedNode << "´, w: " << -phantom_node_pair.startPhantom.weight1);
}
if(phantom_node_pair.startPhantom.isBidirected() && search_from_2nd_node) {
forward_heap1.Insert(
phantom_node_pair.startPhantom.edgeBasedNode+1,
-phantom_node_pair.startPhantom.weight2,
phantom_node_pair.startPhantom.edgeBasedNode+1
);
// INFO("fw1: " << phantom_node_pair.startPhantom.edgeBasedNode+1 << "´, w: " << -phantom_node_pair.startPhantom.weight2);
forward_heap2.Insert(
phantom_node_pair.startPhantom.edgeBasedNode+1,
-phantom_node_pair.startPhantom.weight2,
phantom_node_pair.startPhantom.edgeBasedNode+1
);
// INFO("fw2: " << phantom_node_pair.startPhantom.edgeBasedNode+1 << "´, w: " << -phantom_node_pair.startPhantom.weight2);
}
//insert new backward nodes into backward heap, unadjusted.
reverse_heap1.Insert(
phantom_node_pair.targetPhantom.edgeBasedNode,
phantom_node_pair.targetPhantom.weight1,
phantom_node_pair.targetPhantom.edgeBasedNode
);
// INFO("rv1: " << phantom_node_pair.targetPhantom.edgeBasedNode << ", w;" << phantom_node_pair.targetPhantom.weight1 );
if(phantom_node_pair.targetPhantom.isBidirected() ) {
reverse_heap2.Insert(
phantom_node_pair.targetPhantom.edgeBasedNode+1,
phantom_node_pair.targetPhantom.weight2,
phantom_node_pair.targetPhantom.edgeBasedNode+1
);
// INFO("rv2: " << phantom_node_pair.targetPhantom.edgeBasedNode+1 << ", w;" << phantom_node_pair.targetPhantom.weight2 );
}
const int forward_offset = phantom_node_pair.startPhantom.weight1 + (phantom_node_pair.startPhantom.isBidirected() ? phantom_node_pair.startPhantom.weight2 : 0);
const int reverse_offset = phantom_node_pair.targetPhantom.weight1 + (phantom_node_pair.targetPhantom.isBidirected() ? phantom_node_pair.targetPhantom.weight2 : 0);
//run two-Target Dijkstra routing step.
while(0 < (forward_heap1.Size() + reverse_heap1.Size() )){
if( !forward_heap1.Empty()){
super::RoutingStep(
forward_heap1,
reverse_heap1,
&middle1,
&local_upper_bound1,
forward_offset,
true
);
}
if( !reverse_heap1.Empty() ){
super::RoutingStep(
reverse_heap1,
forward_heap1,
&middle1,
&local_upper_bound1,
reverse_offset,
false
);
}
}
if( !reverse_heap2.Empty() ) {
while(0 < (forward_heap2.Size() + reverse_heap2.Size() )){
if( !forward_heap2.Empty() ){
super::RoutingStep(
forward_heap2,
reverse_heap2,
&middle2,
&local_upper_bound2,
forward_offset,
true
);
}
if( !reverse_heap2.Empty() ){
super::RoutingStep(
reverse_heap2,
forward_heap2,
&middle2,
&local_upper_bound2,
reverse_offset,
false
);
}
}
}
//No path found for both target nodes?
if(
(INT_MAX == local_upper_bound1) &&
(INT_MAX == local_upper_bound2)
) {
raw_route_data.lengthOfShortestPath = INT_MAX;
raw_route_data.lengthOfAlternativePath = INT_MAX;
return;
}
if(UINT_MAX == middle1) {
search_from_1st_node = false;
}
if(UINT_MAX == middle2) {
search_from_2nd_node = false;
}
//Was at most one of the two paths not found?
2013-09-21 16:18:27 -04:00
BOOST_ASSERT_MSG(
(INT_MAX != distance1 || INT_MAX != distance2),
"no path found"
);
//Unpack paths if they exist
std::vector<NodeID> temporary_packed_path1;
std::vector<NodeID> temporary_packed_path2;
if(INT_MAX != local_upper_bound1) {
super::RetrievePackedPathFromHeap(
forward_heap1,
reverse_heap1,
middle1,
temporary_packed_path1
);
}
if(INT_MAX != local_upper_bound2) {
super::RetrievePackedPathFromHeap(
forward_heap2,
reverse_heap2,
middle2,
temporary_packed_path2
);
}
//if one of the paths was not found, replace it with the other one.
if( temporary_packed_path1.empty() ) {
temporary_packed_path1.insert(
temporary_packed_path1.end(),
temporary_packed_path2.begin(),
temporary_packed_path2.end()
);
local_upper_bound1 = local_upper_bound2;
}
if( temporary_packed_path2.empty() ) {
temporary_packed_path2.insert(
temporary_packed_path2.end(),
temporary_packed_path1.begin(),
temporary_packed_path1.end()
);
local_upper_bound2 = local_upper_bound1;
}
2013-09-21 16:18:27 -04:00
BOOST_ASSERT_MSG(
temporary_packed_path1.empty() &&
temporary_packed_path2.empty(),
"tempory packed paths not empty"
);
//Plug paths together, s.t. end of packed path is begin of temporary packed path
if( !packed_path1.empty() && !packed_path2.empty() ) {
if( temporary_packed_path1.front() == temporary_packed_path2.front() ) {
//both new route segments start with the same node, thus one of the packedPath must go.
2013-09-21 16:18:27 -04:00
BOOST_ASSERT_MSG(
(packed_path1.size() == packed_path2.size() ) ||
(packed_path1.back() != packed_path2.back() ),
"packed paths must be different"
);
if( packed_path1.back() == temporary_packed_path1.front()) {
packed_path2.clear();
packed_path2.insert(
packed_path2.end(),
packed_path1.begin(),
packed_path1.end()
);
distance2 = distance1;
} else {
packed_path1.clear();
packed_path1.insert(
packed_path1.end(),
packed_path2.begin(),
packed_path2.end()
);
distance1 = distance2;
}
} else {
//packed paths 1 and 2 may need to switch.
if(packed_path1.back() != temporary_packed_path1.front()) {
packed_path1.swap(packed_path2);
std::swap(distance1, distance2);
}
}
}
packed_path1.insert(
packed_path1.end(),
temporary_packed_path1.begin(),
temporary_packed_path1.end()
);
packed_path2.insert(
packed_path2.end(),
temporary_packed_path2.begin(),
temporary_packed_path2.end()
);
if(
(packed_path1.back() == packed_path2.back()) &&
phantom_node_pair.targetPhantom.isBidirected()
) {
NodeID last_node_id = packed_path2.back();
search_from_1st_node &= !(last_node_id == phantom_node_pair.targetPhantom.edgeBasedNode+1);
search_from_2nd_node &= !(last_node_id == phantom_node_pair.targetPhantom.edgeBasedNode);
}
distance1 += local_upper_bound1;
distance2 += local_upper_bound2;
}
if( distance1 > distance2 ){
std::swap( packed_path1, packed_path2 );
}
remove_consecutive_duplicates_from_vector(packed_path1);
super::UnpackPath(packed_path1, raw_route_data.computedShortestPath);
raw_route_data.lengthOfShortestPath = std::min(distance1, distance2);
return;
}
};
#endif /* SHORTESTPATHROUTING_H_ */