2012-06-15 12:47:27 -04:00
|
|
|
/*
|
|
|
|
|
2015-02-19 03:19:51 -05:00
|
|
|
Copyright (c) 2015, Project OSRM contributors
|
2013-10-14 07:42:28 -04:00
|
|
|
All rights reserved.
|
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without modification,
|
|
|
|
are permitted provided that the following conditions are met:
|
|
|
|
|
|
|
|
Redistributions of source code must retain the above copyright notice, this list
|
|
|
|
of conditions and the following disclaimer.
|
|
|
|
Redistributions in binary form must reproduce the above copyright notice, this
|
|
|
|
list of conditions and the following disclaimer in the documentation and/or
|
|
|
|
other materials provided with the distribution.
|
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
|
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
|
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
|
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
|
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
*/
|
2012-06-15 12:47:27 -04:00
|
|
|
|
2014-11-28 09:33:08 -05:00
|
|
|
#ifndef SHORTEST_PATH_HPP
|
|
|
|
#define SHORTEST_PATH_HPP
|
2012-06-15 12:47:27 -04:00
|
|
|
|
2015-11-30 23:28:57 -05:00
|
|
|
#include "../typedefs.h"
|
2012-06-15 12:47:27 -04:00
|
|
|
|
2014-11-28 09:33:08 -05:00
|
|
|
#include "routing_base.hpp"
|
2015-11-30 23:28:57 -05:00
|
|
|
|
2014-11-28 06:13:18 -05:00
|
|
|
#include "../data_structures/search_engine_data.hpp"
|
2015-01-27 11:44:46 -05:00
|
|
|
#include "../util/integer_range.hpp"
|
2015-11-30 23:28:57 -05:00
|
|
|
|
|
|
|
#include <boost/assert.hpp>
|
2013-09-19 12:53:34 -04:00
|
|
|
|
2015-01-27 11:44:46 -05:00
|
|
|
template <class DataFacadeT>
|
2015-03-02 05:55:55 -05:00
|
|
|
class ShortestPathRouting final
|
|
|
|
: public BasicRoutingInterface<DataFacadeT, ShortestPathRouting<DataFacadeT>>
|
2014-05-08 12:04:05 -04:00
|
|
|
{
|
2015-03-02 05:55:55 -05:00
|
|
|
using super = BasicRoutingInterface<DataFacadeT, ShortestPathRouting<DataFacadeT>>;
|
2014-08-19 07:01:38 -04:00
|
|
|
using QueryHeap = SearchEngineData::QueryHeap;
|
2014-05-08 12:04:05 -04:00
|
|
|
SearchEngineData &engine_working_data;
|
|
|
|
|
|
|
|
public:
|
|
|
|
ShortestPathRouting(DataFacadeT *facade, SearchEngineData &engine_working_data)
|
|
|
|
: super(facade), engine_working_data(engine_working_data)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
~ShortestPathRouting() {}
|
|
|
|
|
2015-11-30 23:28:57 -05:00
|
|
|
// allows a uturn at the target_phantom
|
|
|
|
// searches source forward/reverse -> target forward/reverse
|
|
|
|
void SearchWithUTurn(QueryHeap &forward_heap,
|
|
|
|
QueryHeap &reverse_heap,
|
|
|
|
const bool search_from_forward_node,
|
|
|
|
const bool search_from_reverse_node,
|
|
|
|
const bool search_to_forward_node,
|
|
|
|
const bool search_to_reverse_node,
|
|
|
|
const PhantomNode &source_phantom,
|
|
|
|
const PhantomNode &target_phantom,
|
|
|
|
const int total_distance_to_forward,
|
|
|
|
const int total_distance_to_reverse,
|
|
|
|
int &new_total_distance,
|
|
|
|
std::vector<NodeID> &leg_packed_path) const
|
2014-03-25 13:06:05 -04:00
|
|
|
{
|
2015-11-30 23:28:57 -05:00
|
|
|
forward_heap.Clear();
|
|
|
|
reverse_heap.Clear();
|
|
|
|
if (search_from_forward_node)
|
|
|
|
{
|
|
|
|
forward_heap.Insert(source_phantom.forward_node_id,
|
|
|
|
total_distance_to_forward -
|
|
|
|
source_phantom.GetForwardWeightPlusOffset(),
|
|
|
|
source_phantom.forward_node_id);
|
|
|
|
}
|
|
|
|
if (search_from_reverse_node)
|
|
|
|
{
|
|
|
|
forward_heap.Insert(source_phantom.reverse_node_id,
|
|
|
|
total_distance_to_reverse -
|
|
|
|
source_phantom.GetReverseWeightPlusOffset(),
|
|
|
|
source_phantom.reverse_node_id);
|
|
|
|
}
|
|
|
|
if (search_to_forward_node)
|
|
|
|
{
|
|
|
|
reverse_heap.Insert(target_phantom.forward_node_id,
|
|
|
|
target_phantom.GetForwardWeightPlusOffset(),
|
|
|
|
target_phantom.forward_node_id);
|
|
|
|
}
|
|
|
|
if (search_to_reverse_node)
|
|
|
|
{
|
|
|
|
reverse_heap.Insert(target_phantom.reverse_node_id,
|
|
|
|
target_phantom.GetReverseWeightPlusOffset(),
|
|
|
|
target_phantom.reverse_node_id);
|
|
|
|
}
|
|
|
|
BOOST_ASSERT(forward_heap.Size() > 0);
|
|
|
|
BOOST_ASSERT(reverse_heap.Size() > 0);
|
|
|
|
super::Search(forward_heap, reverse_heap, new_total_distance, leg_packed_path);
|
|
|
|
}
|
2012-06-15 12:47:27 -04:00
|
|
|
|
2015-11-30 23:28:57 -05:00
|
|
|
// If source and target are reverse on a oneway we need to find a path
|
|
|
|
// that connects the two. This is _not_ the shortest path in our model,
|
|
|
|
// as source and target are on the same edge based node.
|
|
|
|
// We force a detour by inserting "virtaul vias", which means we search a path
|
|
|
|
// from all nodes that are connected by outgoing edges to all nodes that are connected by
|
|
|
|
// incoming edges.
|
|
|
|
// ------^
|
|
|
|
// | ^source
|
|
|
|
// | ^
|
|
|
|
// | ^target
|
|
|
|
// ------^
|
|
|
|
void SearchLoop(QueryHeap &forward_heap,
|
|
|
|
QueryHeap &reverse_heap,
|
2015-12-04 19:27:01 -05:00
|
|
|
const bool search_forward_node,
|
|
|
|
const bool search_reverse_node,
|
2015-11-30 23:28:57 -05:00
|
|
|
const PhantomNode &source_phantom,
|
|
|
|
const PhantomNode &target_phantom,
|
|
|
|
const int total_distance_to_forward,
|
|
|
|
const int total_distance_to_reverse,
|
|
|
|
int &new_total_distance_to_forward,
|
|
|
|
int &new_total_distance_to_reverse,
|
|
|
|
std::vector<NodeID> &leg_packed_path_forward,
|
|
|
|
std::vector<NodeID> &leg_packed_path_reverse) const
|
|
|
|
{
|
|
|
|
BOOST_ASSERT(source_phantom.forward_node_id == target_phantom.forward_node_id);
|
|
|
|
BOOST_ASSERT(source_phantom.reverse_node_id == target_phantom.reverse_node_id);
|
2012-06-15 12:47:27 -04:00
|
|
|
|
2015-12-04 19:27:01 -05:00
|
|
|
if (search_forward_node)
|
2014-05-07 10:17:47 -04:00
|
|
|
{
|
2015-11-30 23:28:57 -05:00
|
|
|
forward_heap.Clear();
|
|
|
|
reverse_heap.Clear();
|
2014-02-11 05:42:24 -05:00
|
|
|
|
2015-11-30 23:28:57 -05:00
|
|
|
auto node_id = source_phantom.forward_node_id;
|
2013-12-12 18:35:23 -05:00
|
|
|
|
2015-11-30 23:28:57 -05:00
|
|
|
for (const auto edge : super::facade->GetAdjacentEdgeRange(node_id))
|
2014-05-08 12:04:05 -04:00
|
|
|
{
|
2015-11-30 23:28:57 -05:00
|
|
|
const auto& data = super::facade->GetEdgeData(edge);
|
|
|
|
if (data.forward)
|
2014-05-08 12:04:05 -04:00
|
|
|
{
|
2015-11-30 23:28:57 -05:00
|
|
|
auto target = super::facade->GetTarget(edge);
|
|
|
|
auto offset = total_distance_to_forward + data.distance - source_phantom.GetForwardWeightPlusOffset();
|
|
|
|
forward_heap.Insert(target, offset, target);
|
2012-06-15 12:47:27 -04:00
|
|
|
}
|
2015-11-30 23:28:57 -05:00
|
|
|
|
|
|
|
if (data.backward)
|
2014-05-08 12:04:05 -04:00
|
|
|
{
|
2015-11-30 23:28:57 -05:00
|
|
|
auto target = super::facade->GetTarget(edge);
|
|
|
|
auto offset = data.distance + target_phantom.GetForwardWeightPlusOffset();
|
|
|
|
reverse_heap.Insert(target, offset, target);
|
2012-06-15 12:47:27 -04:00
|
|
|
}
|
|
|
|
}
|
2013-12-12 18:35:23 -05:00
|
|
|
|
2015-11-30 23:28:57 -05:00
|
|
|
BOOST_ASSERT(forward_heap.Size() > 0);
|
|
|
|
BOOST_ASSERT(reverse_heap.Size() > 0);
|
|
|
|
super::Search(forward_heap, reverse_heap, new_total_distance_to_forward,
|
|
|
|
leg_packed_path_forward);
|
|
|
|
|
|
|
|
// insert node to both endpoints to close the leg
|
|
|
|
leg_packed_path_forward.push_back(node_id);
|
|
|
|
std::reverse(leg_packed_path_forward.begin(), leg_packed_path_forward.end());
|
|
|
|
leg_packed_path_forward.push_back(node_id);
|
|
|
|
std::reverse(leg_packed_path_forward.begin(), leg_packed_path_forward.end());
|
|
|
|
}
|
|
|
|
|
2015-12-04 19:27:01 -05:00
|
|
|
if (search_reverse_node)
|
2015-11-30 23:28:57 -05:00
|
|
|
{
|
|
|
|
forward_heap.Clear();
|
|
|
|
reverse_heap.Clear();
|
|
|
|
|
|
|
|
auto node_id = source_phantom.reverse_node_id;
|
|
|
|
|
|
|
|
for (const auto edge : super::facade->GetAdjacentEdgeRange(node_id))
|
2014-05-08 12:04:05 -04:00
|
|
|
{
|
2015-11-30 23:28:57 -05:00
|
|
|
const auto& data = super::facade->GetEdgeData(edge);
|
|
|
|
if (data.forward)
|
2014-05-08 12:04:05 -04:00
|
|
|
{
|
2015-11-30 23:28:57 -05:00
|
|
|
auto target = super::facade->GetTarget(edge);
|
|
|
|
auto offset = total_distance_to_reverse + data.distance - source_phantom.GetReverseWeightPlusOffset();
|
|
|
|
forward_heap.Insert(target, offset, target);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (data.backward)
|
|
|
|
{
|
|
|
|
auto target = super::facade->GetTarget(edge);
|
|
|
|
auto offset = data.distance + target_phantom.GetReverseWeightPlusOffset();
|
|
|
|
reverse_heap.Insert(target, offset, target);
|
2012-06-15 12:47:27 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-30 23:28:57 -05:00
|
|
|
BOOST_ASSERT(forward_heap.Size() > 0);
|
|
|
|
BOOST_ASSERT(reverse_heap.Size() > 0);
|
|
|
|
super::Search(forward_heap, reverse_heap, new_total_distance_to_reverse,
|
|
|
|
leg_packed_path_reverse);
|
|
|
|
|
|
|
|
// insert node to both endpoints to close the leg
|
|
|
|
leg_packed_path_reverse.push_back(node_id);
|
|
|
|
std::reverse(leg_packed_path_reverse.begin(), leg_packed_path_reverse.end());
|
|
|
|
leg_packed_path_reverse.push_back(node_id);
|
|
|
|
std::reverse(leg_packed_path_reverse.begin(), leg_packed_path_reverse.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// searches shortest path between:
|
|
|
|
// source forward/reverse -> target forward
|
|
|
|
// source forward/reverse -> target reverse
|
|
|
|
void Search(QueryHeap &forward_heap,
|
|
|
|
QueryHeap &reverse_heap,
|
|
|
|
const bool search_from_forward_node,
|
|
|
|
const bool search_from_reverse_node,
|
|
|
|
const bool search_to_forward_node,
|
|
|
|
const bool search_to_reverse_node,
|
|
|
|
const PhantomNode &source_phantom,
|
|
|
|
const PhantomNode &target_phantom,
|
|
|
|
const int total_distance_to_forward,
|
|
|
|
const int total_distance_to_reverse,
|
|
|
|
int &new_total_distance_to_forward,
|
|
|
|
int &new_total_distance_to_reverse,
|
|
|
|
std::vector<NodeID> &leg_packed_path_forward,
|
|
|
|
std::vector<NodeID> &leg_packed_path_reverse) const
|
|
|
|
{
|
|
|
|
if (search_to_forward_node)
|
|
|
|
{
|
|
|
|
forward_heap.Clear();
|
|
|
|
reverse_heap.Clear();
|
|
|
|
reverse_heap.Insert(target_phantom.forward_node_id,
|
|
|
|
target_phantom.GetForwardWeightPlusOffset(),
|
|
|
|
target_phantom.forward_node_id);
|
|
|
|
|
|
|
|
if (search_from_forward_node)
|
2014-05-08 12:04:05 -04:00
|
|
|
{
|
2015-11-30 23:28:57 -05:00
|
|
|
forward_heap.Insert(source_phantom.forward_node_id,
|
|
|
|
total_distance_to_forward -
|
|
|
|
source_phantom.GetForwardWeightPlusOffset(),
|
|
|
|
source_phantom.forward_node_id);
|
|
|
|
}
|
|
|
|
if (search_from_reverse_node)
|
|
|
|
{
|
|
|
|
forward_heap.Insert(source_phantom.reverse_node_id,
|
|
|
|
total_distance_to_reverse -
|
|
|
|
source_phantom.GetReverseWeightPlusOffset(),
|
|
|
|
source_phantom.reverse_node_id);
|
2012-06-15 12:47:27 -04:00
|
|
|
}
|
2015-11-30 23:28:57 -05:00
|
|
|
BOOST_ASSERT(forward_heap.Size() > 0);
|
|
|
|
BOOST_ASSERT(reverse_heap.Size() > 0);
|
|
|
|
super::Search(forward_heap, reverse_heap, new_total_distance_to_forward,
|
|
|
|
leg_packed_path_forward);
|
|
|
|
}
|
2014-05-26 05:47:01 -04:00
|
|
|
|
2015-11-30 23:28:57 -05:00
|
|
|
if (search_to_reverse_node)
|
|
|
|
{
|
|
|
|
forward_heap.Clear();
|
|
|
|
reverse_heap.Clear();
|
|
|
|
reverse_heap.Insert(target_phantom.reverse_node_id,
|
|
|
|
target_phantom.GetReverseWeightPlusOffset(),
|
|
|
|
target_phantom.reverse_node_id);
|
|
|
|
if (search_from_forward_node)
|
2014-05-08 12:04:05 -04:00
|
|
|
{
|
2015-11-30 23:28:57 -05:00
|
|
|
forward_heap.Insert(source_phantom.forward_node_id,
|
|
|
|
total_distance_to_forward -
|
|
|
|
source_phantom.GetForwardWeightPlusOffset(),
|
|
|
|
source_phantom.forward_node_id);
|
2012-06-15 12:47:27 -04:00
|
|
|
}
|
2015-11-30 23:28:57 -05:00
|
|
|
if (search_from_reverse_node)
|
2014-05-08 12:04:05 -04:00
|
|
|
{
|
2015-11-30 23:28:57 -05:00
|
|
|
forward_heap.Insert(source_phantom.reverse_node_id,
|
|
|
|
total_distance_to_reverse -
|
|
|
|
source_phantom.GetReverseWeightPlusOffset(),
|
|
|
|
source_phantom.reverse_node_id);
|
2012-06-15 12:47:27 -04:00
|
|
|
}
|
2015-11-30 23:28:57 -05:00
|
|
|
BOOST_ASSERT(forward_heap.Size() > 0);
|
|
|
|
BOOST_ASSERT(reverse_heap.Size() > 0);
|
|
|
|
super::Search(forward_heap, reverse_heap, new_total_distance_to_reverse,
|
|
|
|
leg_packed_path_reverse);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void UnpackLegs(const std::vector<PhantomNodes> &phantom_nodes_vector,
|
|
|
|
const std::vector<NodeID> &total_packed_path,
|
|
|
|
const std::vector<std::size_t> &packed_leg_begin,
|
|
|
|
const int shortest_path_length,
|
|
|
|
InternalRouteResult &raw_route_data) const
|
|
|
|
{
|
|
|
|
raw_route_data.unpacked_path_segments.resize(packed_leg_begin.size() - 1);
|
|
|
|
|
|
|
|
raw_route_data.shortest_path_length = shortest_path_length;
|
|
|
|
|
|
|
|
for (const auto current_leg : osrm::irange<std::size_t>(0, packed_leg_begin.size() - 1))
|
|
|
|
{
|
|
|
|
auto leg_begin = total_packed_path.begin() + packed_leg_begin[current_leg];
|
|
|
|
auto leg_end = total_packed_path.begin() + packed_leg_begin[current_leg + 1];
|
|
|
|
const auto &unpack_phantom_node_pair = phantom_nodes_vector[current_leg];
|
|
|
|
super::UnpackPath(leg_begin, leg_end, unpack_phantom_node_pair,
|
|
|
|
raw_route_data.unpacked_path_segments[current_leg]);
|
|
|
|
|
|
|
|
raw_route_data.source_traversed_in_reverse.push_back(
|
|
|
|
(*leg_begin != phantom_nodes_vector[current_leg].source_phantom.forward_node_id));
|
|
|
|
raw_route_data.target_traversed_in_reverse.push_back(
|
|
|
|
(*std::prev(leg_end) !=
|
|
|
|
phantom_nodes_vector[current_leg].target_phantom.forward_node_id));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void operator()(const std::vector<PhantomNodes> &phantom_nodes_vector,
|
|
|
|
const std::vector<bool> &uturn_indicators,
|
|
|
|
InternalRouteResult &raw_route_data) const
|
|
|
|
{
|
2015-12-08 16:11:41 -05:00
|
|
|
BOOST_ASSERT(uturn_indicators.size() == phantom_nodes_vector.size() + 1);
|
2015-11-30 23:28:57 -05:00
|
|
|
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
|
|
|
|
super::facade->GetNumberOfNodes());
|
2012-06-15 12:47:27 -04:00
|
|
|
|
2015-11-30 23:28:57 -05:00
|
|
|
QueryHeap &forward_heap = *(engine_working_data.forward_heap_1);
|
|
|
|
QueryHeap &reverse_heap = *(engine_working_data.reverse_heap_1);
|
2012-06-15 12:47:27 -04:00
|
|
|
|
2015-11-30 23:28:57 -05:00
|
|
|
int total_distance_to_forward = 0;
|
|
|
|
int total_distance_to_reverse = 0;
|
|
|
|
bool search_from_forward_node = phantom_nodes_vector.front().source_phantom.forward_node_id != SPECIAL_NODEID;
|
|
|
|
bool search_from_reverse_node = phantom_nodes_vector.front().source_phantom.reverse_node_id != SPECIAL_NODEID;
|
2013-12-12 18:35:23 -05:00
|
|
|
|
2015-11-30 23:28:57 -05:00
|
|
|
std::vector<NodeID> prev_packed_leg_to_forward;
|
|
|
|
std::vector<NodeID> prev_packed_leg_to_reverse;
|
2013-12-12 18:35:23 -05:00
|
|
|
|
2015-11-30 23:28:57 -05:00
|
|
|
std::vector<NodeID> total_packed_path_to_forward;
|
|
|
|
std::vector<std::size_t> packed_leg_to_forward_begin;
|
|
|
|
std::vector<NodeID> total_packed_path_to_reverse;
|
|
|
|
std::vector<std::size_t> packed_leg_to_reverse_begin;
|
|
|
|
|
|
|
|
std::size_t current_leg = 0;
|
|
|
|
// this implements a dynamic program that finds the shortest route through
|
|
|
|
// a list of vias
|
|
|
|
for (const auto &phantom_node_pair : phantom_nodes_vector)
|
|
|
|
{
|
|
|
|
int new_total_distance_to_forward = INVALID_EDGE_WEIGHT;
|
|
|
|
int new_total_distance_to_reverse = INVALID_EDGE_WEIGHT;
|
|
|
|
|
|
|
|
std::vector<NodeID> packed_leg_to_forward;
|
|
|
|
std::vector<NodeID> packed_leg_to_reverse;
|
|
|
|
|
|
|
|
const auto &source_phantom = phantom_node_pair.source_phantom;
|
|
|
|
const auto &target_phantom = phantom_node_pair.target_phantom;
|
|
|
|
|
|
|
|
|
2015-12-08 16:11:41 -05:00
|
|
|
BOOST_ASSERT(current_leg + 1 < uturn_indicators.size());
|
|
|
|
const bool allow_u_turn_at_via = uturn_indicators[current_leg + 1];
|
2015-11-30 23:28:57 -05:00
|
|
|
|
|
|
|
bool search_to_forward_node = target_phantom.forward_node_id != SPECIAL_NODEID;
|
|
|
|
bool search_to_reverse_node = target_phantom.reverse_node_id != SPECIAL_NODEID;
|
|
|
|
|
|
|
|
BOOST_ASSERT(!search_from_forward_node || source_phantom.forward_node_id != SPECIAL_NODEID);
|
|
|
|
BOOST_ASSERT(!search_from_reverse_node || source_phantom.reverse_node_id != SPECIAL_NODEID);
|
|
|
|
|
|
|
|
if (source_phantom.forward_node_id == target_phantom.forward_node_id &&
|
|
|
|
source_phantom.GetForwardWeightPlusOffset() > target_phantom.GetForwardWeightPlusOffset())
|
2014-05-08 12:04:05 -04:00
|
|
|
{
|
2015-12-15 15:27:03 -05:00
|
|
|
search_to_forward_node = search_from_reverse_node;
|
2012-06-15 12:47:27 -04:00
|
|
|
}
|
2015-11-30 23:28:57 -05:00
|
|
|
if (source_phantom.reverse_node_id == target_phantom.reverse_node_id &&
|
|
|
|
source_phantom.GetReverseWeightPlusOffset() > target_phantom.GetReverseWeightPlusOffset())
|
2014-05-08 12:04:05 -04:00
|
|
|
{
|
2015-12-15 15:27:03 -05:00
|
|
|
search_to_reverse_node = search_from_forward_node;
|
2012-06-15 12:47:27 -04:00
|
|
|
}
|
|
|
|
|
2015-11-30 23:28:57 -05:00
|
|
|
BOOST_ASSERT(search_from_forward_node || search_from_reverse_node);
|
|
|
|
|
|
|
|
if(search_to_reverse_node || search_to_forward_node)
|
2014-05-08 12:04:05 -04:00
|
|
|
{
|
2015-11-30 23:28:57 -05:00
|
|
|
if (allow_u_turn_at_via)
|
|
|
|
{
|
|
|
|
SearchWithUTurn(forward_heap, reverse_heap, search_from_forward_node,
|
|
|
|
search_from_reverse_node, search_to_forward_node,
|
|
|
|
search_to_reverse_node, source_phantom, target_phantom,
|
|
|
|
total_distance_to_forward, total_distance_to_reverse,
|
|
|
|
new_total_distance_to_forward, packed_leg_to_forward);
|
2015-12-10 23:43:57 -05:00
|
|
|
// if only the reverse node is valid (e.g. when using the match plugin) we actually need to move
|
|
|
|
if (target_phantom.forward_node_id == SPECIAL_NODEID)
|
|
|
|
{
|
|
|
|
BOOST_ASSERT(target_phantom.reverse_node_id != SPECIAL_NODEID);
|
|
|
|
new_total_distance_to_reverse = new_total_distance_to_forward;
|
|
|
|
packed_leg_to_reverse = std::move(packed_leg_to_forward);
|
|
|
|
new_total_distance_to_forward = INVALID_EDGE_WEIGHT;
|
|
|
|
}
|
|
|
|
else if (target_phantom.reverse_node_id != SPECIAL_NODEID)
|
2015-11-30 23:28:57 -05:00
|
|
|
{
|
|
|
|
new_total_distance_to_reverse = new_total_distance_to_forward;
|
|
|
|
packed_leg_to_reverse = packed_leg_to_forward;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Search(forward_heap, reverse_heap, search_from_forward_node,
|
|
|
|
search_from_reverse_node, search_to_forward_node, search_to_reverse_node,
|
|
|
|
source_phantom, target_phantom, total_distance_to_forward,
|
|
|
|
total_distance_to_reverse, new_total_distance_to_forward,
|
|
|
|
new_total_distance_to_reverse, packed_leg_to_forward, packed_leg_to_reverse);
|
|
|
|
}
|
2012-06-15 12:47:27 -04:00
|
|
|
}
|
2015-11-30 23:28:57 -05:00
|
|
|
else
|
2014-05-08 12:04:05 -04:00
|
|
|
{
|
2015-11-30 23:28:57 -05:00
|
|
|
search_to_forward_node = target_phantom.forward_node_id != SPECIAL_NODEID;
|
|
|
|
search_to_reverse_node = target_phantom.reverse_node_id != SPECIAL_NODEID;
|
2015-12-04 19:27:01 -05:00
|
|
|
BOOST_ASSERT(search_from_reverse_node == search_to_reverse_node);
|
|
|
|
BOOST_ASSERT(search_from_forward_node == search_to_forward_node);
|
2015-11-30 23:28:57 -05:00
|
|
|
SearchLoop(forward_heap, reverse_heap, search_from_forward_node,
|
2015-12-04 19:27:01 -05:00
|
|
|
search_from_reverse_node, source_phantom, target_phantom, total_distance_to_forward,
|
2015-11-30 23:28:57 -05:00
|
|
|
total_distance_to_reverse, new_total_distance_to_forward,
|
|
|
|
new_total_distance_to_reverse, packed_leg_to_forward, packed_leg_to_reverse);
|
2012-06-15 12:47:27 -04:00
|
|
|
}
|
|
|
|
|
2015-11-30 23:28:57 -05:00
|
|
|
// No path found for both target nodes?
|
|
|
|
if ((INVALID_EDGE_WEIGHT == new_total_distance_to_forward) &&
|
|
|
|
(INVALID_EDGE_WEIGHT == new_total_distance_to_reverse))
|
|
|
|
{
|
|
|
|
raw_route_data.shortest_path_length = INVALID_EDGE_WEIGHT;
|
|
|
|
raw_route_data.alternative_path_length = INVALID_EDGE_WEIGHT;
|
|
|
|
return;
|
|
|
|
}
|
2014-05-08 12:04:05 -04:00
|
|
|
|
2015-11-30 23:28:57 -05:00
|
|
|
// we need to figure out how the new legs connect to the previous ones
|
|
|
|
if (current_leg > 0)
|
2014-05-08 12:04:05 -04:00
|
|
|
{
|
2015-11-30 23:28:57 -05:00
|
|
|
bool forward_to_forward =
|
|
|
|
(new_total_distance_to_forward != INVALID_EDGE_WEIGHT) &&
|
|
|
|
packed_leg_to_forward.front() == source_phantom.forward_node_id;
|
|
|
|
bool reverse_to_forward =
|
|
|
|
(new_total_distance_to_forward != INVALID_EDGE_WEIGHT) &&
|
|
|
|
packed_leg_to_forward.front() == source_phantom.reverse_node_id;
|
|
|
|
bool forward_to_reverse =
|
|
|
|
(new_total_distance_to_reverse != INVALID_EDGE_WEIGHT) &&
|
|
|
|
packed_leg_to_reverse.front() == source_phantom.forward_node_id;
|
|
|
|
bool reverse_to_reverse =
|
|
|
|
(new_total_distance_to_reverse != INVALID_EDGE_WEIGHT) &&
|
|
|
|
packed_leg_to_reverse.front() == source_phantom.reverse_node_id;
|
|
|
|
|
|
|
|
BOOST_ASSERT(!forward_to_forward || !reverse_to_forward);
|
|
|
|
BOOST_ASSERT(!forward_to_reverse || !reverse_to_reverse);
|
|
|
|
|
|
|
|
// in this case we always need to copy
|
|
|
|
if (forward_to_forward && forward_to_reverse)
|
|
|
|
{
|
|
|
|
// in this case we copy the path leading to the source forward node
|
|
|
|
// and change the case
|
|
|
|
total_packed_path_to_reverse = total_packed_path_to_forward;
|
|
|
|
packed_leg_to_reverse_begin = packed_leg_to_forward_begin;
|
|
|
|
forward_to_reverse = false;
|
|
|
|
reverse_to_reverse = true;
|
|
|
|
}
|
|
|
|
else if (reverse_to_forward && reverse_to_reverse)
|
2014-05-08 12:04:05 -04:00
|
|
|
{
|
2015-11-30 23:28:57 -05:00
|
|
|
total_packed_path_to_forward = total_packed_path_to_reverse;
|
|
|
|
packed_leg_to_forward_begin = packed_leg_to_reverse_begin;
|
|
|
|
reverse_to_forward = false;
|
|
|
|
forward_to_forward = true;
|
2013-12-12 18:35:23 -05:00
|
|
|
}
|
2015-11-30 23:28:57 -05:00
|
|
|
BOOST_ASSERT(!forward_to_forward || !forward_to_reverse);
|
|
|
|
BOOST_ASSERT(!reverse_to_forward || !reverse_to_reverse);
|
2013-09-21 16:21:33 -04:00
|
|
|
|
2015-11-30 23:28:57 -05:00
|
|
|
// in this case we just need to swap to regain the correct mapping
|
|
|
|
if (reverse_to_forward || forward_to_reverse)
|
2014-05-08 12:04:05 -04:00
|
|
|
{
|
2015-11-30 23:28:57 -05:00
|
|
|
total_packed_path_to_forward.swap(total_packed_path_to_reverse);
|
|
|
|
packed_leg_to_forward_begin.swap(packed_leg_to_reverse_begin);
|
2012-06-15 12:47:27 -04:00
|
|
|
}
|
|
|
|
}
|
2015-11-30 23:28:57 -05:00
|
|
|
|
|
|
|
if (new_total_distance_to_forward != INVALID_EDGE_WEIGHT)
|
2014-05-08 12:04:05 -04:00
|
|
|
{
|
2015-11-30 23:28:57 -05:00
|
|
|
BOOST_ASSERT(target_phantom.forward_node_id != SPECIAL_NODEID);
|
|
|
|
|
|
|
|
packed_leg_to_forward_begin.push_back(total_packed_path_to_forward.size());
|
|
|
|
total_packed_path_to_forward.insert(total_packed_path_to_forward.end(),
|
|
|
|
packed_leg_to_forward.begin(),
|
|
|
|
packed_leg_to_forward.end());
|
|
|
|
search_from_forward_node = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
total_packed_path_to_forward.clear();
|
|
|
|
packed_leg_to_forward_begin.clear();
|
|
|
|
search_from_forward_node = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (new_total_distance_to_reverse != INVALID_EDGE_WEIGHT)
|
|
|
|
{
|
|
|
|
BOOST_ASSERT(target_phantom.reverse_node_id != SPECIAL_NODEID);
|
|
|
|
|
|
|
|
packed_leg_to_reverse_begin.push_back(total_packed_path_to_reverse.size());
|
|
|
|
total_packed_path_to_reverse.insert(total_packed_path_to_reverse.end(),
|
|
|
|
packed_leg_to_reverse.begin(),
|
|
|
|
packed_leg_to_reverse.end());
|
|
|
|
search_from_reverse_node = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
total_packed_path_to_reverse.clear();
|
|
|
|
packed_leg_to_reverse_begin.clear();
|
|
|
|
search_from_reverse_node = false;
|
2012-06-15 12:47:27 -04:00
|
|
|
}
|
|
|
|
|
2015-11-30 23:28:57 -05:00
|
|
|
prev_packed_leg_to_forward = std::move(packed_leg_to_forward);
|
|
|
|
prev_packed_leg_to_reverse = std::move(packed_leg_to_reverse);
|
|
|
|
|
|
|
|
total_distance_to_forward = new_total_distance_to_forward;
|
|
|
|
total_distance_to_reverse = new_total_distance_to_reverse;
|
|
|
|
|
2013-12-12 18:35:23 -05:00
|
|
|
++current_leg;
|
2012-06-15 12:47:27 -04:00
|
|
|
}
|
|
|
|
|
2015-11-30 23:28:57 -05:00
|
|
|
BOOST_ASSERT(total_distance_to_forward != INVALID_EDGE_WEIGHT ||
|
|
|
|
total_distance_to_reverse != INVALID_EDGE_WEIGHT);
|
|
|
|
|
|
|
|
// We make sure the fastest route is always in packed_legs_to_forward
|
|
|
|
if (total_distance_to_forward > total_distance_to_reverse)
|
2014-03-28 12:13:00 -04:00
|
|
|
{
|
2015-11-30 23:28:57 -05:00
|
|
|
// insert sentinel
|
|
|
|
packed_leg_to_reverse_begin.push_back(total_packed_path_to_reverse.size());
|
|
|
|
BOOST_ASSERT(packed_leg_to_reverse_begin.size() == phantom_nodes_vector.size() + 1);
|
2014-02-26 09:55:04 -05:00
|
|
|
|
2015-11-30 23:28:57 -05:00
|
|
|
UnpackLegs(phantom_nodes_vector, total_packed_path_to_reverse,
|
|
|
|
packed_leg_to_reverse_begin, total_distance_to_reverse, raw_route_data);
|
|
|
|
}
|
|
|
|
else
|
2014-03-28 12:13:00 -04:00
|
|
|
{
|
2015-11-30 23:28:57 -05:00
|
|
|
// insert sentinel
|
|
|
|
packed_leg_to_forward_begin.push_back(total_packed_path_to_forward.size());
|
|
|
|
BOOST_ASSERT(packed_leg_to_forward_begin.size() == phantom_nodes_vector.size() + 1);
|
2014-05-27 10:54:10 -04:00
|
|
|
|
2015-11-30 23:28:57 -05:00
|
|
|
UnpackLegs(phantom_nodes_vector, total_packed_path_to_forward,
|
|
|
|
packed_leg_to_forward_begin, total_distance_to_forward, raw_route_data);
|
2012-06-15 12:47:27 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-11-28 09:33:08 -05:00
|
|
|
#endif /* SHORTEST_PATH_HPP */
|