2014-11-28 09:33:08 -05:00
|
|
|
#ifndef ROUTING_BASE_HPP
|
|
|
|
#define ROUTING_BASE_HPP
|
2012-06-15 12:47:27 -04:00
|
|
|
|
2016-05-27 15:05:04 -04:00
|
|
|
#include "extractor/guidance/turn_instruction.hpp"
|
2016-10-05 19:05:03 -04:00
|
|
|
#include "engine/edge_unpacker.hpp"
|
2016-01-02 11:13:44 -05:00
|
|
|
#include "engine/internal_route_result.hpp"
|
|
|
|
#include "engine/search_engine_data.hpp"
|
2016-04-26 07:27:40 -04:00
|
|
|
#include "util/coordinate_calculation.hpp"
|
2016-08-17 03:49:19 -04:00
|
|
|
#include "util/guidance/turn_bearing.hpp"
|
2016-01-07 04:33:47 -05:00
|
|
|
#include "util/typedefs.hpp"
|
2013-06-24 14:12:34 -04:00
|
|
|
|
2013-09-20 05:35:59 -04:00
|
|
|
#include <boost/assert.hpp>
|
2013-02-03 10:47:32 -05:00
|
|
|
|
2016-01-07 04:33:47 -05:00
|
|
|
#include <cstddef>
|
|
|
|
#include <cstdint>
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <iterator>
|
2016-04-26 07:27:40 -04:00
|
|
|
#include <numeric>
|
|
|
|
#include <stack>
|
2016-01-07 04:33:47 -05:00
|
|
|
#include <utility>
|
|
|
|
#include <vector>
|
2012-06-19 11:26:34 -04:00
|
|
|
|
2016-01-05 10:51:13 -05:00
|
|
|
namespace osrm
|
|
|
|
{
|
|
|
|
namespace engine
|
|
|
|
{
|
|
|
|
|
|
|
|
namespace routing_algorithms
|
|
|
|
{
|
|
|
|
|
2015-03-02 05:55:55 -05:00
|
|
|
template <class DataFacadeT, class Derived> class BasicRoutingInterface
|
2014-05-08 12:04:05 -04:00
|
|
|
{
|
|
|
|
private:
|
2015-03-02 05:55:55 -05:00
|
|
|
using EdgeData = typename DataFacadeT::EdgeData;
|
2014-05-08 12:04:05 -04:00
|
|
|
|
|
|
|
public:
|
2016-01-05 05:19:18 -05:00
|
|
|
/*
|
|
|
|
min_edge_offset is needed in case we use multiple
|
|
|
|
nodes as start/target nodes with different (even negative) offsets.
|
|
|
|
In that case the termination criterion is not correct
|
|
|
|
anymore.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
forward heap: a(-100), b(0),
|
|
|
|
reverse heap: c(0), d(100)
|
|
|
|
|
|
|
|
a --- d
|
|
|
|
\ /
|
|
|
|
/ \
|
|
|
|
b --- c
|
|
|
|
|
|
|
|
This is equivalent to running a bi-directional Dijkstra on the following graph:
|
|
|
|
|
|
|
|
a --- d
|
|
|
|
/ \ / \
|
|
|
|
y x z
|
|
|
|
\ / \ /
|
|
|
|
b --- c
|
|
|
|
|
|
|
|
The graph is constructed by inserting nodes y and z that are connected to the initial nodes
|
|
|
|
using edges (y, a) with weight -100, (y, b) with weight 0 and,
|
|
|
|
(d, z) with weight 100, (c, z) with weight 0 corresponding.
|
|
|
|
Since we are dealing with a graph that contains _negative_ edges,
|
|
|
|
we need to add an offset to the termination criterion.
|
|
|
|
*/
|
2016-10-05 19:05:03 -04:00
|
|
|
void RoutingStep(const DataFacadeT &facade,
|
|
|
|
SearchEngineData::QueryHeap &forward_heap,
|
2015-03-02 05:55:55 -05:00
|
|
|
SearchEngineData::QueryHeap &reverse_heap,
|
2015-11-30 23:28:57 -05:00
|
|
|
NodeID &middle_node_id,
|
2016-01-07 04:33:47 -05:00
|
|
|
std::int32_t &upper_bound,
|
|
|
|
std::int32_t min_edge_offset,
|
2015-10-08 16:11:34 -04:00
|
|
|
const bool forward_direction,
|
2016-01-07 04:33:47 -05:00
|
|
|
const bool stalling,
|
|
|
|
const bool force_loop_forward,
|
|
|
|
const bool force_loop_reverse) const
|
2014-04-08 19:47:52 -04:00
|
|
|
{
|
2013-09-20 07:08:18 -04:00
|
|
|
const NodeID node = forward_heap.DeleteMin();
|
2016-05-12 12:50:10 -04:00
|
|
|
const std::int32_t weight = forward_heap.GetKey(node);
|
2014-07-10 07:56:36 -04:00
|
|
|
|
2014-04-08 19:47:52 -04:00
|
|
|
if (reverse_heap.WasInserted(node))
|
|
|
|
{
|
2016-05-12 12:50:10 -04:00
|
|
|
const std::int32_t new_weight = reverse_heap.GetKey(node) + weight;
|
|
|
|
if (new_weight < upper_bound)
|
2014-04-08 19:47:52 -04:00
|
|
|
{
|
2016-03-30 07:14:48 -04:00
|
|
|
// if loops are forced, they are so at the source
|
2016-08-09 12:21:23 -04:00
|
|
|
if ((force_loop_forward && forward_heap.GetData(node).parent == node) ||
|
|
|
|
(force_loop_reverse && reverse_heap.GetData(node).parent == node) ||
|
|
|
|
// in this case we are looking at a bi-directional way where the source
|
|
|
|
// and target phantom are on the same edge based node
|
2016-05-12 12:50:10 -04:00
|
|
|
new_weight < 0)
|
2016-01-07 04:33:47 -05:00
|
|
|
{
|
|
|
|
// check whether there is a loop present at the node
|
2016-10-05 19:05:03 -04:00
|
|
|
for (const auto edge : facade.GetAdjacentEdgeRange(node))
|
2016-01-07 04:33:47 -05:00
|
|
|
{
|
2016-10-05 19:05:03 -04:00
|
|
|
const EdgeData &data = facade.GetEdgeData(edge);
|
2016-01-07 04:33:47 -05:00
|
|
|
bool forward_directionFlag =
|
|
|
|
(forward_direction ? data.forward : data.backward);
|
|
|
|
if (forward_directionFlag)
|
|
|
|
{
|
2016-10-05 19:05:03 -04:00
|
|
|
const NodeID to = facade.GetTarget(edge);
|
2016-01-07 04:33:47 -05:00
|
|
|
if (to == node)
|
|
|
|
{
|
2016-05-12 12:50:10 -04:00
|
|
|
const EdgeWeight edge_weight = data.weight;
|
|
|
|
const std::int32_t loop_weight = new_weight + edge_weight;
|
|
|
|
if (loop_weight >= 0 && loop_weight < upper_bound)
|
2016-01-07 04:33:47 -05:00
|
|
|
{
|
|
|
|
middle_node_id = node;
|
2016-05-12 12:50:10 -04:00
|
|
|
upper_bound = loop_weight;
|
2016-01-07 04:33:47 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-08-09 12:21:23 -04:00
|
|
|
else
|
|
|
|
{
|
2016-05-12 12:50:10 -04:00
|
|
|
BOOST_ASSERT(new_weight >= 0);
|
2016-08-09 12:21:23 -04:00
|
|
|
|
|
|
|
middle_node_id = node;
|
2016-05-12 12:50:10 -04:00
|
|
|
upper_bound = new_weight;
|
2016-08-09 12:21:23 -04:00
|
|
|
}
|
2012-06-15 12:47:27 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-12 12:50:10 -04:00
|
|
|
// make sure we don't terminate too early if we initialize the weight
|
2015-11-30 23:28:57 -05:00
|
|
|
// for the nodes in the forward heap with the forward/reverse offset
|
|
|
|
BOOST_ASSERT(min_edge_offset <= 0);
|
2016-05-12 12:50:10 -04:00
|
|
|
if (weight + min_edge_offset > upper_bound)
|
2014-04-08 19:47:52 -04:00
|
|
|
{
|
2013-09-20 07:08:18 -04:00
|
|
|
forward_heap.DeleteAll();
|
2012-06-15 12:47:27 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-05-08 12:04:05 -04:00
|
|
|
// Stalling
|
2015-10-08 16:11:34 -04:00
|
|
|
if (stalling)
|
2014-04-25 10:00:39 -04:00
|
|
|
{
|
2016-10-05 19:05:03 -04:00
|
|
|
for (const auto edge : facade.GetAdjacentEdgeRange(node))
|
2015-11-30 23:28:57 -05:00
|
|
|
{
|
2016-10-05 19:05:03 -04:00
|
|
|
const EdgeData &data = facade.GetEdgeData(edge);
|
2015-11-30 23:28:57 -05:00
|
|
|
const bool reverse_flag = ((!forward_direction) ? data.forward : data.backward);
|
|
|
|
if (reverse_flag)
|
|
|
|
{
|
2016-10-05 19:05:03 -04:00
|
|
|
const NodeID to = facade.GetTarget(edge);
|
2016-05-12 12:50:10 -04:00
|
|
|
const EdgeWeight edge_weight = data.weight;
|
2015-11-30 23:28:57 -05:00
|
|
|
|
|
|
|
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
|
|
|
|
|
|
|
if (forward_heap.WasInserted(to))
|
|
|
|
{
|
2016-05-12 12:50:10 -04:00
|
|
|
if (forward_heap.GetKey(to) + edge_weight < weight)
|
2015-11-30 23:28:57 -05:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-06-15 12:47:27 -04:00
|
|
|
}
|
2014-04-22 10:15:38 -04:00
|
|
|
|
2016-10-05 19:05:03 -04:00
|
|
|
for (const auto edge : facade.GetAdjacentEdgeRange(node))
|
2014-04-25 10:00:39 -04:00
|
|
|
{
|
2016-10-05 19:05:03 -04:00
|
|
|
const EdgeData &data = facade.GetEdgeData(edge);
|
2014-04-25 10:00:39 -04:00
|
|
|
bool forward_directionFlag = (forward_direction ? data.forward : data.backward);
|
|
|
|
if (forward_directionFlag)
|
|
|
|
{
|
2016-10-05 19:05:03 -04:00
|
|
|
const NodeID to = facade.GetTarget(edge);
|
2016-05-12 12:50:10 -04:00
|
|
|
const EdgeWeight edge_weight = data.weight;
|
2012-06-15 12:47:27 -04:00
|
|
|
|
2014-05-08 12:04:05 -04:00
|
|
|
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
|
2016-05-12 12:50:10 -04:00
|
|
|
const int to_weight = weight + edge_weight;
|
2012-06-15 12:47:27 -04:00
|
|
|
|
2014-05-08 12:04:05 -04:00
|
|
|
// New Node discovered -> Add to Heap + Node Info Storage
|
|
|
|
if (!forward_heap.WasInserted(to))
|
|
|
|
{
|
2016-05-12 12:50:10 -04:00
|
|
|
forward_heap.Insert(to, to_weight, node);
|
2012-06-15 12:47:27 -04:00
|
|
|
}
|
2016-05-12 12:50:10 -04:00
|
|
|
// Found a shorter Path -> Update weight
|
|
|
|
else if (to_weight < forward_heap.GetKey(to))
|
2014-05-08 12:04:05 -04:00
|
|
|
{
|
|
|
|
// new parent
|
|
|
|
forward_heap.GetData(to).parent = node;
|
2016-05-12 12:50:10 -04:00
|
|
|
forward_heap.DecreaseKey(to, to_weight);
|
2012-06-15 12:47:27 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-05 19:05:03 -04:00
|
|
|
inline EdgeWeight GetLoopWeight(const DataFacadeT &facade, NodeID node) const
|
2016-01-07 04:33:47 -05:00
|
|
|
{
|
|
|
|
EdgeWeight loop_weight = INVALID_EDGE_WEIGHT;
|
2016-10-05 19:05:03 -04:00
|
|
|
for (auto edge : facade.GetAdjacentEdgeRange(node))
|
2016-01-07 04:33:47 -05:00
|
|
|
{
|
2016-10-05 19:05:03 -04:00
|
|
|
const auto &data = facade.GetEdgeData(edge);
|
2016-01-07 04:33:47 -05:00
|
|
|
if (data.forward)
|
|
|
|
{
|
2016-10-05 19:05:03 -04:00
|
|
|
const NodeID to = facade.GetTarget(edge);
|
2016-01-07 04:33:47 -05:00
|
|
|
if (to == node)
|
|
|
|
{
|
2016-05-12 12:50:10 -04:00
|
|
|
loop_weight = std::min(loop_weight, data.weight);
|
2016-01-07 04:33:47 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return loop_weight;
|
|
|
|
}
|
|
|
|
|
2015-11-30 23:28:57 -05:00
|
|
|
template <typename RandomIter>
|
2016-10-05 19:05:03 -04:00
|
|
|
void UnpackPath(const DataFacadeT &facade,
|
|
|
|
RandomIter packed_path_begin,
|
2015-11-30 23:28:57 -05:00
|
|
|
RandomIter packed_path_end,
|
2015-03-02 05:55:55 -05:00
|
|
|
const PhantomNodes &phantom_node_pair,
|
|
|
|
std::vector<PathData> &unpacked_path) const
|
2014-04-25 10:00:39 -04:00
|
|
|
{
|
2016-10-24 22:15:45 -04:00
|
|
|
BOOST_ASSERT(std::distance(packed_path_begin, packed_path_end) > 0);
|
|
|
|
|
2014-05-08 12:04:05 -04:00
|
|
|
const bool start_traversed_in_reverse =
|
2016-03-28 11:06:51 -04:00
|
|
|
(*packed_path_begin != phantom_node_pair.source_phantom.forward_segment_id.id);
|
2014-05-08 12:04:05 -04:00
|
|
|
const bool target_traversed_in_reverse =
|
2016-03-28 11:06:51 -04:00
|
|
|
(*std::prev(packed_path_end) != phantom_node_pair.target_phantom.forward_segment_id.id);
|
2014-03-10 10:36:58 -04:00
|
|
|
|
2016-05-20 16:11:05 -04:00
|
|
|
BOOST_ASSERT(*packed_path_begin == phantom_node_pair.source_phantom.forward_segment_id.id ||
|
|
|
|
*packed_path_begin == phantom_node_pair.source_phantom.reverse_segment_id.id);
|
2016-05-27 15:05:04 -04:00
|
|
|
BOOST_ASSERT(
|
|
|
|
*std::prev(packed_path_end) == phantom_node_pair.target_phantom.forward_segment_id.id ||
|
|
|
|
*std::prev(packed_path_end) == phantom_node_pair.target_phantom.reverse_segment_id.id);
|
2016-05-20 16:11:05 -04:00
|
|
|
|
2016-09-30 08:33:43 -04:00
|
|
|
UnpackCHPath(
|
2016-10-05 19:05:03 -04:00
|
|
|
facade,
|
2016-08-23 02:26:48 -04:00
|
|
|
packed_path_begin,
|
|
|
|
packed_path_end,
|
|
|
|
[this,
|
2016-10-05 19:05:03 -04:00
|
|
|
&facade,
|
2016-08-23 02:26:48 -04:00
|
|
|
&unpacked_path,
|
|
|
|
&phantom_node_pair,
|
|
|
|
&start_traversed_in_reverse,
|
|
|
|
&target_traversed_in_reverse](std::pair<NodeID, NodeID> & /* edge */,
|
2016-09-30 08:33:43 -04:00
|
|
|
const EdgeData &edge_data) {
|
2016-08-23 02:26:48 -04:00
|
|
|
|
2016-09-30 08:33:43 -04:00
|
|
|
BOOST_ASSERT_MSG(!edge_data.shortcut, "original edge flagged as shortcut");
|
2016-10-05 19:05:03 -04:00
|
|
|
const auto name_index = facade.GetNameIndexFromEdgeID(edge_data.id);
|
|
|
|
const auto turn_instruction = facade.GetTurnInstructionForEdgeID(edge_data.id);
|
2016-02-13 13:17:30 -05:00
|
|
|
const extractor::TravelMode travel_mode =
|
|
|
|
(unpacked_path.empty() && start_traversed_in_reverse)
|
|
|
|
? phantom_node_pair.source_phantom.backward_travel_mode
|
2016-10-05 19:05:03 -04:00
|
|
|
: facade.GetTravelModeForEdgeID(edge_data.id);
|
2014-08-12 04:02:29 -04:00
|
|
|
|
2016-10-05 19:05:03 -04:00
|
|
|
const auto geometry_index = facade.GetGeometryIndexForEdgeID(edge_data.id);
|
2016-03-17 11:40:08 -04:00
|
|
|
std::vector<NodeID> id_vector;
|
|
|
|
std::vector<EdgeWeight> weight_vector;
|
2016-07-20 08:59:16 -04:00
|
|
|
std::vector<DatasourceID> datasource_vector;
|
2016-07-22 12:23:54 -04:00
|
|
|
if (geometry_index.forward)
|
2014-04-25 09:48:10 -04:00
|
|
|
{
|
2016-07-22 12:23:54 -04:00
|
|
|
id_vector = facade.GetUncompressedForwardGeometry(geometry_index.id);
|
|
|
|
weight_vector = facade.GetUncompressedForwardWeights(geometry_index.id);
|
2016-08-17 03:49:19 -04:00
|
|
|
datasource_vector = facade.GetUncompressedForwardDatasources(geometry_index.id);
|
2014-02-11 05:42:24 -05:00
|
|
|
}
|
2016-07-22 12:23:54 -04:00
|
|
|
else
|
|
|
|
{
|
|
|
|
id_vector = facade.GetUncompressedReverseGeometry(geometry_index.id);
|
|
|
|
weight_vector = facade.GetUncompressedReverseWeights(geometry_index.id);
|
2016-08-17 03:49:19 -04:00
|
|
|
datasource_vector = facade.GetUncompressedReverseDatasources(geometry_index.id);
|
2016-07-22 12:23:54 -04:00
|
|
|
}
|
|
|
|
BOOST_ASSERT(id_vector.size() > 0);
|
|
|
|
BOOST_ASSERT(weight_vector.size() > 0);
|
|
|
|
BOOST_ASSERT(datasource_vector.size() > 0);
|
|
|
|
|
2016-08-17 03:49:19 -04:00
|
|
|
const auto total_weight =
|
|
|
|
std::accumulate(weight_vector.begin(), weight_vector.end(), 0);
|
|
|
|
|
|
|
|
BOOST_ASSERT(weight_vector.size() == id_vector.size() - 1);
|
|
|
|
const bool is_first_segment = unpacked_path.empty();
|
|
|
|
|
|
|
|
const std::size_t start_index =
|
|
|
|
(is_first_segment
|
|
|
|
? ((start_traversed_in_reverse)
|
|
|
|
? weight_vector.size() -
|
|
|
|
phantom_node_pair.source_phantom.fwd_segment_position - 1
|
|
|
|
: phantom_node_pair.source_phantom.fwd_segment_position)
|
|
|
|
: 0);
|
|
|
|
const std::size_t end_index = weight_vector.size();
|
|
|
|
|
|
|
|
BOOST_ASSERT(start_index >= 0);
|
|
|
|
BOOST_ASSERT(start_index < end_index);
|
|
|
|
for (std::size_t segment_idx = start_index; segment_idx < end_index; ++segment_idx)
|
|
|
|
{
|
|
|
|
unpacked_path.push_back(
|
|
|
|
PathData{id_vector[segment_idx + 1],
|
|
|
|
name_index,
|
|
|
|
weight_vector[segment_idx],
|
|
|
|
extractor::guidance::TurnInstruction::NO_TURN(),
|
|
|
|
{{0, INVALID_LANEID}, INVALID_LANE_DESCRIPTIONID},
|
|
|
|
travel_mode,
|
|
|
|
INVALID_ENTRY_CLASSID,
|
|
|
|
datasource_vector[segment_idx],
|
|
|
|
util::guidance::TurnBearing(0),
|
|
|
|
util::guidance::TurnBearing(0)});
|
|
|
|
}
|
|
|
|
BOOST_ASSERT(unpacked_path.size() > 0);
|
|
|
|
if (facade.hasLaneData(edge_data.id))
|
|
|
|
unpacked_path.back().lane_data = facade.GetLaneData(edge_data.id);
|
|
|
|
|
|
|
|
unpacked_path.back().entry_classid = facade.GetEntryClassID(edge_data.id);
|
|
|
|
unpacked_path.back().turn_instruction = turn_instruction;
|
2016-05-12 12:50:10 -04:00
|
|
|
unpacked_path.back().duration_until_turn += (edge_data.weight - total_weight);
|
2016-08-17 03:49:19 -04:00
|
|
|
unpacked_path.back().pre_turn_bearing = facade.PreTurnBearing(edge_data.id);
|
|
|
|
unpacked_path.back().post_turn_bearing = facade.PostTurnBearing(edge_data.id);
|
|
|
|
});
|
|
|
|
|
|
|
|
std::size_t start_index = 0, end_index = 0;
|
|
|
|
std::vector<unsigned> id_vector;
|
|
|
|
std::vector<EdgeWeight> weight_vector;
|
|
|
|
std::vector<DatasourceID> datasource_vector;
|
|
|
|
const bool is_local_path = (phantom_node_pair.source_phantom.packed_geometry_id ==
|
|
|
|
phantom_node_pair.target_phantom.packed_geometry_id) &&
|
|
|
|
unpacked_path.empty();
|
|
|
|
|
|
|
|
if (target_traversed_in_reverse)
|
|
|
|
{
|
|
|
|
id_vector = facade.GetUncompressedReverseGeometry(
|
|
|
|
phantom_node_pair.target_phantom.packed_geometry_id);
|
|
|
|
|
|
|
|
weight_vector = facade.GetUncompressedReverseWeights(
|
|
|
|
phantom_node_pair.target_phantom.packed_geometry_id);
|
|
|
|
|
|
|
|
datasource_vector = facade.GetUncompressedReverseDatasources(
|
|
|
|
phantom_node_pair.target_phantom.packed_geometry_id);
|
2016-07-20 08:59:16 -04:00
|
|
|
|
2016-04-01 05:39:47 -04:00
|
|
|
if (is_local_path)
|
2014-07-22 05:59:31 -04:00
|
|
|
{
|
2016-08-17 03:49:19 -04:00
|
|
|
start_index = weight_vector.size() -
|
|
|
|
phantom_node_pair.source_phantom.fwd_segment_position - 1;
|
2014-07-22 05:59:31 -04:00
|
|
|
}
|
2016-04-29 03:48:13 -04:00
|
|
|
end_index =
|
2016-07-22 12:23:54 -04:00
|
|
|
weight_vector.size() - phantom_node_pair.target_phantom.fwd_segment_position - 1;
|
2016-04-01 05:39:47 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (is_local_path)
|
2016-03-17 15:38:57 -04:00
|
|
|
{
|
|
|
|
start_index = phantom_node_pair.source_phantom.fwd_segment_position;
|
|
|
|
}
|
2016-04-01 05:39:47 -04:00
|
|
|
end_index = phantom_node_pair.target_phantom.fwd_segment_position;
|
2014-07-22 05:59:31 -04:00
|
|
|
|
2016-07-22 12:23:54 -04:00
|
|
|
id_vector = facade.GetUncompressedForwardGeometry(
|
|
|
|
phantom_node_pair.target_phantom.packed_geometry_id);
|
|
|
|
|
|
|
|
weight_vector = facade.GetUncompressedForwardWeights(
|
|
|
|
phantom_node_pair.target_phantom.packed_geometry_id);
|
2016-07-20 08:59:16 -04:00
|
|
|
|
2016-07-22 12:23:54 -04:00
|
|
|
datasource_vector = facade.GetUncompressedForwardDatasources(
|
|
|
|
phantom_node_pair.target_phantom.packed_geometry_id);
|
2016-01-29 20:52:20 -05:00
|
|
|
}
|
|
|
|
|
2016-03-17 15:38:57 -04:00
|
|
|
// Given the following compressed geometry:
|
|
|
|
// U---v---w---x---y---Z
|
|
|
|
// s t
|
|
|
|
// s: fwd_segment 0
|
|
|
|
// t: fwd_segment 3
|
|
|
|
// -> (U, v), (v, w), (w, x)
|
2016-03-18 11:14:48 -04:00
|
|
|
// note that (x, t) is _not_ included but needs to be added later.
|
2016-08-17 03:49:19 -04:00
|
|
|
for (std::size_t segment_idx = start_index; segment_idx != end_index;
|
|
|
|
(start_index < end_index ? ++segment_idx : --segment_idx))
|
2016-01-29 20:52:20 -05:00
|
|
|
{
|
2016-07-22 12:23:54 -04:00
|
|
|
BOOST_ASSERT(segment_idx < id_vector.size() - 1);
|
2016-01-29 20:52:20 -05:00
|
|
|
BOOST_ASSERT(phantom_node_pair.target_phantom.forward_travel_mode > 0);
|
2016-04-26 07:27:40 -04:00
|
|
|
unpacked_path.push_back(PathData{
|
2016-07-22 12:23:54 -04:00
|
|
|
id_vector[start_index < end_index ? segment_idx + 1 : segment_idx - 1],
|
2016-05-27 15:05:04 -04:00
|
|
|
phantom_node_pair.target_phantom.name_id,
|
2016-07-22 12:23:54 -04:00
|
|
|
weight_vector[segment_idx],
|
2016-04-26 07:27:40 -04:00
|
|
|
extractor::guidance::TurnInstruction::NO_TURN(),
|
2016-06-21 04:41:08 -04:00
|
|
|
{{0, INVALID_LANEID}, INVALID_LANE_DESCRIPTIONID},
|
2016-04-26 07:27:40 -04:00
|
|
|
target_traversed_in_reverse ? phantom_node_pair.target_phantom.backward_travel_mode
|
|
|
|
: phantom_node_pair.target_phantom.forward_travel_mode,
|
2016-07-20 08:59:16 -04:00
|
|
|
INVALID_ENTRY_CLASSID,
|
2016-08-17 03:49:19 -04:00
|
|
|
datasource_vector[segment_idx],
|
|
|
|
util::guidance::TurnBearing(0),
|
|
|
|
util::guidance::TurnBearing(0)});
|
2014-02-28 11:14:38 -05:00
|
|
|
}
|
2014-03-28 13:25:35 -04:00
|
|
|
|
2016-04-01 05:39:47 -04:00
|
|
|
if (unpacked_path.size() > 0)
|
2016-03-17 15:38:57 -04:00
|
|
|
{
|
2016-03-30 07:14:48 -04:00
|
|
|
const auto source_weight = start_traversed_in_reverse
|
|
|
|
? phantom_node_pair.source_phantom.reverse_weight
|
|
|
|
: phantom_node_pair.source_phantom.forward_weight;
|
2016-03-17 15:38:57 -04:00
|
|
|
// The above code will create segments for (v, w), (w,x), (x, y) and (y, Z).
|
|
|
|
// However the first segment duration needs to be adjusted to the fact that the source
|
2016-03-18 11:14:48 -04:00
|
|
|
// phantom is in the middle of the segment. We do this by subtracting v--s from the
|
|
|
|
// duration.
|
2016-04-29 03:48:13 -04:00
|
|
|
|
|
|
|
// Since it's possible duration_until_turn can be less than source_weight here if
|
|
|
|
// a negative enough turn penalty is used to modify this edge weight during
|
2016-05-02 11:00:27 -04:00
|
|
|
// osrm-contract, we clamp to 0 here so as not to return a negative duration
|
2016-04-29 03:48:13 -04:00
|
|
|
// for this segment.
|
|
|
|
|
|
|
|
// TODO this creates a scenario where it's possible the duration from a phantom
|
|
|
|
// node to the first turn would be the same as from end to end of a segment,
|
|
|
|
// which is obviously incorrect and not ideal...
|
|
|
|
unpacked_path.front().duration_until_turn =
|
|
|
|
std::max(unpacked_path.front().duration_until_turn - source_weight, 0);
|
2016-03-17 15:38:57 -04:00
|
|
|
}
|
|
|
|
|
2014-03-28 13:25:35 -04:00
|
|
|
// there is no equivalent to a node-based node in an edge-expanded graph.
|
|
|
|
// two equivalent routes may start (or end) at different node-based edges
|
2016-05-12 12:50:10 -04:00
|
|
|
// as they are added with the offset how much "weight" on the edge
|
2014-03-28 13:25:35 -04:00
|
|
|
// has already been traversed. Depending on offset one needs to remove
|
|
|
|
// the last node.
|
|
|
|
if (unpacked_path.size() > 1)
|
|
|
|
{
|
2014-07-22 06:56:24 -04:00
|
|
|
const std::size_t last_index = unpacked_path.size() - 1;
|
|
|
|
const std::size_t second_to_last_index = last_index - 1;
|
2014-03-28 13:25:35 -04:00
|
|
|
|
2016-02-23 15:23:13 -05:00
|
|
|
if (unpacked_path[last_index].turn_via_node ==
|
|
|
|
unpacked_path[second_to_last_index].turn_via_node)
|
2014-03-28 13:25:35 -04:00
|
|
|
{
|
|
|
|
unpacked_path.pop_back();
|
|
|
|
}
|
|
|
|
BOOST_ASSERT(!unpacked_path.empty());
|
2014-03-28 12:13:00 -04:00
|
|
|
}
|
2012-06-15 12:47:27 -04:00
|
|
|
}
|
|
|
|
|
2016-05-09 19:20:47 -04:00
|
|
|
/**
|
2016-08-23 02:26:48 -04:00
|
|
|
* Unpacks a single edge (NodeID->NodeID) from the CH graph down to it's original non-shortcut
|
|
|
|
* route.
|
|
|
|
* @param from the node the CH edge starts at
|
|
|
|
* @param to the node the CH edge finishes at
|
|
|
|
* @param unpacked_path the sequence of original NodeIDs that make up the expanded CH edge
|
2016-05-09 19:20:47 -04:00
|
|
|
*/
|
2016-10-05 19:05:03 -04:00
|
|
|
void UnpackEdge(const DataFacadeT &facade,
|
|
|
|
const NodeID from,
|
|
|
|
const NodeID to,
|
|
|
|
std::vector<NodeID> &unpacked_path) const
|
2016-05-09 19:20:47 -04:00
|
|
|
{
|
2016-08-23 02:26:48 -04:00
|
|
|
std::array<NodeID, 2> path{{from, to}};
|
2016-09-30 08:33:43 -04:00
|
|
|
UnpackCHPath(
|
2016-10-05 19:05:03 -04:00
|
|
|
facade,
|
2016-08-23 02:26:48 -04:00
|
|
|
path.begin(),
|
|
|
|
path.end(),
|
|
|
|
[&unpacked_path](const std::pair<NodeID, NodeID> &edge, const EdgeData & /* data */) {
|
|
|
|
unpacked_path.emplace_back(edge.first);
|
|
|
|
});
|
|
|
|
unpacked_path.emplace_back(to);
|
2016-05-09 19:20:47 -04:00
|
|
|
}
|
|
|
|
|
2015-03-02 05:55:55 -05:00
|
|
|
void RetrievePackedPathFromHeap(const SearchEngineData::QueryHeap &forward_heap,
|
|
|
|
const SearchEngineData::QueryHeap &reverse_heap,
|
|
|
|
const NodeID middle_node_id,
|
|
|
|
std::vector<NodeID> &packed_path) const
|
2014-04-25 09:48:10 -04:00
|
|
|
{
|
2014-07-24 03:56:20 -04:00
|
|
|
RetrievePackedPathFromSingleHeap(forward_heap, middle_node_id, packed_path);
|
2013-09-20 07:08:18 -04:00
|
|
|
std::reverse(packed_path.begin(), packed_path.end());
|
2014-05-08 12:04:05 -04:00
|
|
|
packed_path.emplace_back(middle_node_id);
|
2014-07-24 03:56:20 -04:00
|
|
|
RetrievePackedPathFromSingleHeap(reverse_heap, middle_node_id, packed_path);
|
2012-06-15 12:47:27 -04:00
|
|
|
}
|
2013-02-03 10:47:32 -05:00
|
|
|
|
2015-03-02 05:55:55 -05:00
|
|
|
void RetrievePackedPathFromSingleHeap(const SearchEngineData::QueryHeap &search_heap,
|
|
|
|
const NodeID middle_node_id,
|
|
|
|
std::vector<NodeID> &packed_path) const
|
2014-04-25 09:48:10 -04:00
|
|
|
{
|
2013-09-20 07:08:18 -04:00
|
|
|
NodeID current_node_id = middle_node_id;
|
2016-08-09 12:21:23 -04:00
|
|
|
// all initial nodes will have itself as parent, or a node not in the heap
|
|
|
|
// in case of a core search heap. We need a distinction between core entry nodes
|
|
|
|
// and start nodes since otherwise start node specific code that assumes
|
|
|
|
// node == node.parent (e.g. the loop code) might get actived.
|
|
|
|
while (current_node_id != search_heap.GetData(current_node_id).parent &&
|
|
|
|
search_heap.WasInserted(search_heap.GetData(current_node_id).parent))
|
2014-04-25 09:48:10 -04:00
|
|
|
{
|
2013-09-20 07:08:18 -04:00
|
|
|
current_node_id = search_heap.GetData(current_node_id).parent;
|
2014-05-08 12:04:05 -04:00
|
|
|
packed_path.emplace_back(current_node_id);
|
2013-02-03 10:47:32 -05:00
|
|
|
}
|
|
|
|
}
|
2015-03-03 08:22:52 -05:00
|
|
|
|
2015-11-25 15:45:09 -05:00
|
|
|
// assumes that heaps are already setup correctly.
|
2016-01-07 04:33:47 -05:00
|
|
|
// ATTENTION: This only works if no additional offset is supplied next to the Phantom Node
|
|
|
|
// Offsets.
|
|
|
|
// In case additional offsets are supplied, you might have to force a loop first.
|
|
|
|
// A forced loop might be necessary, if source and target are on the same segment.
|
|
|
|
// If this is the case and the offsets of the respective direction are larger for the source
|
|
|
|
// than the target
|
2016-03-28 11:06:51 -04:00
|
|
|
// then a force loop is required (e.g. source_phantom.forward_segment_id ==
|
|
|
|
// target_phantom.forward_segment_id
|
2016-01-07 04:33:47 -05:00
|
|
|
// && source_phantom.GetForwardWeightPlusOffset() > target_phantom.GetForwardWeightPlusOffset())
|
|
|
|
// requires
|
|
|
|
// a force loop, if the heaps have been initialized with positive offsets.
|
2016-10-05 19:05:03 -04:00
|
|
|
void Search(const DataFacadeT &facade,
|
|
|
|
SearchEngineData::QueryHeap &forward_heap,
|
2015-11-25 15:45:09 -05:00
|
|
|
SearchEngineData::QueryHeap &reverse_heap,
|
2016-05-12 12:50:10 -04:00
|
|
|
std::int32_t &weight,
|
2016-01-07 04:33:47 -05:00
|
|
|
std::vector<NodeID> &packed_leg,
|
|
|
|
const bool force_loop_forward,
|
2016-03-07 18:11:35 -05:00
|
|
|
const bool force_loop_reverse,
|
2016-03-14 05:14:23 -04:00
|
|
|
const int duration_upper_bound = INVALID_EDGE_WEIGHT) const
|
2015-11-25 15:45:09 -05:00
|
|
|
{
|
|
|
|
NodeID middle = SPECIAL_NODEID;
|
2016-05-12 12:50:10 -04:00
|
|
|
weight = duration_upper_bound;
|
2015-11-25 15:45:09 -05:00
|
|
|
|
2015-11-30 23:28:57 -05:00
|
|
|
// get offset to account for offsets on phantom nodes on compressed edges
|
|
|
|
const auto min_edge_offset = std::min(0, forward_heap.MinKey());
|
|
|
|
BOOST_ASSERT(min_edge_offset <= 0);
|
|
|
|
// we only every insert negative offsets for nodes in the forward heap
|
|
|
|
BOOST_ASSERT(reverse_heap.MinKey() >= 0);
|
2015-11-25 15:45:09 -05:00
|
|
|
|
|
|
|
// run two-Target Dijkstra routing step.
|
2016-01-07 04:33:47 -05:00
|
|
|
const constexpr bool STALLING_ENABLED = true;
|
2015-11-25 15:45:09 -05:00
|
|
|
while (0 < (forward_heap.Size() + reverse_heap.Size()))
|
|
|
|
{
|
|
|
|
if (!forward_heap.Empty())
|
|
|
|
{
|
2016-10-05 19:05:03 -04:00
|
|
|
RoutingStep(facade,
|
|
|
|
forward_heap,
|
2016-05-27 15:05:04 -04:00
|
|
|
reverse_heap,
|
|
|
|
middle,
|
2016-05-12 12:50:10 -04:00
|
|
|
weight,
|
2016-05-27 15:05:04 -04:00
|
|
|
min_edge_offset,
|
|
|
|
true,
|
|
|
|
STALLING_ENABLED,
|
|
|
|
force_loop_forward,
|
|
|
|
force_loop_reverse);
|
2015-11-25 15:45:09 -05:00
|
|
|
}
|
|
|
|
if (!reverse_heap.Empty())
|
|
|
|
{
|
2016-10-05 19:05:03 -04:00
|
|
|
RoutingStep(facade,
|
|
|
|
reverse_heap,
|
2016-05-27 15:05:04 -04:00
|
|
|
forward_heap,
|
|
|
|
middle,
|
2016-05-12 12:50:10 -04:00
|
|
|
weight,
|
2016-05-27 15:05:04 -04:00
|
|
|
min_edge_offset,
|
|
|
|
false,
|
|
|
|
STALLING_ENABLED,
|
|
|
|
force_loop_reverse,
|
|
|
|
force_loop_forward);
|
2015-11-25 15:45:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// No path found for both target nodes?
|
2016-05-12 12:50:10 -04:00
|
|
|
if (duration_upper_bound <= weight || SPECIAL_NODEID == middle)
|
2015-11-25 15:45:09 -05:00
|
|
|
{
|
2016-05-12 12:50:10 -04:00
|
|
|
weight = INVALID_EDGE_WEIGHT;
|
2015-11-25 15:45:09 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Was a paths over one of the forward/reverse nodes not found?
|
2016-05-12 12:50:10 -04:00
|
|
|
BOOST_ASSERT_MSG((SPECIAL_NODEID != middle && INVALID_EDGE_WEIGHT != weight),
|
2015-11-25 15:45:09 -05:00
|
|
|
"no path found");
|
|
|
|
|
2016-01-07 04:33:47 -05:00
|
|
|
// make sure to correctly unpack loops
|
2016-05-12 12:50:10 -04:00
|
|
|
if (weight != forward_heap.GetKey(middle) + reverse_heap.GetKey(middle))
|
2016-01-07 04:33:47 -05:00
|
|
|
{
|
2016-04-25 07:11:23 -04:00
|
|
|
// self loop makes up the full path
|
2016-01-07 04:33:47 -05:00
|
|
|
packed_leg.push_back(middle);
|
|
|
|
packed_leg.push_back(middle);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle, packed_leg);
|
|
|
|
}
|
2015-11-25 15:45:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// assumes that heaps are already setup correctly.
|
2016-01-07 04:33:47 -05:00
|
|
|
// A forced loop might be necessary, if source and target are on the same segment.
|
|
|
|
// If this is the case and the offsets of the respective direction are larger for the source
|
|
|
|
// than the target
|
2016-03-28 11:06:51 -04:00
|
|
|
// then a force loop is required (e.g. source_phantom.forward_segment_id ==
|
|
|
|
// target_phantom.forward_segment_id
|
2016-01-07 04:33:47 -05:00
|
|
|
// && source_phantom.GetForwardWeightPlusOffset() > target_phantom.GetForwardWeightPlusOffset())
|
|
|
|
// requires
|
|
|
|
// a force loop, if the heaps have been initialized with positive offsets.
|
2016-10-05 19:05:03 -04:00
|
|
|
void SearchWithCore(const DataFacadeT &facade,
|
|
|
|
SearchEngineData::QueryHeap &forward_heap,
|
2015-11-25 15:45:09 -05:00
|
|
|
SearchEngineData::QueryHeap &reverse_heap,
|
|
|
|
SearchEngineData::QueryHeap &forward_core_heap,
|
|
|
|
SearchEngineData::QueryHeap &reverse_core_heap,
|
2016-05-12 12:50:10 -04:00
|
|
|
int &weight,
|
2016-01-07 04:33:47 -05:00
|
|
|
std::vector<NodeID> &packed_leg,
|
|
|
|
const bool force_loop_forward,
|
2016-03-07 18:11:35 -05:00
|
|
|
const bool force_loop_reverse,
|
2016-03-14 05:14:23 -04:00
|
|
|
int duration_upper_bound = INVALID_EDGE_WEIGHT) const
|
2015-11-25 15:45:09 -05:00
|
|
|
{
|
|
|
|
NodeID middle = SPECIAL_NODEID;
|
2016-05-12 12:50:10 -04:00
|
|
|
weight = duration_upper_bound;
|
2015-11-25 15:45:09 -05:00
|
|
|
|
2016-08-09 12:21:23 -04:00
|
|
|
using CoreEntryPoint = std::tuple<NodeID, EdgeWeight, NodeID>;
|
|
|
|
std::vector<CoreEntryPoint> forward_entry_points;
|
|
|
|
std::vector<CoreEntryPoint> reverse_entry_points;
|
2015-11-25 15:45:09 -05:00
|
|
|
|
2015-11-30 23:28:57 -05:00
|
|
|
// get offset to account for offsets on phantom nodes on compressed edges
|
|
|
|
const auto min_edge_offset = std::min(0, forward_heap.MinKey());
|
|
|
|
// we only every insert negative offsets for nodes in the forward heap
|
|
|
|
BOOST_ASSERT(reverse_heap.MinKey() >= 0);
|
|
|
|
|
2016-01-07 04:33:47 -05:00
|
|
|
const constexpr bool STALLING_ENABLED = true;
|
2015-11-25 15:45:09 -05:00
|
|
|
// run two-Target Dijkstra routing step.
|
|
|
|
while (0 < (forward_heap.Size() + reverse_heap.Size()))
|
|
|
|
{
|
|
|
|
if (!forward_heap.Empty())
|
|
|
|
{
|
2016-10-05 19:05:03 -04:00
|
|
|
if (facade.IsCoreNode(forward_heap.Min()))
|
2015-11-25 15:45:09 -05:00
|
|
|
{
|
|
|
|
const NodeID node = forward_heap.DeleteMin();
|
|
|
|
const int key = forward_heap.GetKey(node);
|
2016-08-09 12:21:23 -04:00
|
|
|
forward_entry_points.emplace_back(node, key, forward_heap.GetData(node).parent);
|
2015-11-25 15:45:09 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-10-05 19:05:03 -04:00
|
|
|
RoutingStep(facade,
|
|
|
|
forward_heap,
|
2016-05-27 15:05:04 -04:00
|
|
|
reverse_heap,
|
|
|
|
middle,
|
2016-05-12 12:50:10 -04:00
|
|
|
weight,
|
2016-05-27 15:05:04 -04:00
|
|
|
min_edge_offset,
|
|
|
|
true,
|
|
|
|
STALLING_ENABLED,
|
|
|
|
force_loop_forward,
|
|
|
|
force_loop_reverse);
|
2015-11-25 15:45:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!reverse_heap.Empty())
|
|
|
|
{
|
2016-10-05 19:05:03 -04:00
|
|
|
if (facade.IsCoreNode(reverse_heap.Min()))
|
2015-11-25 15:45:09 -05:00
|
|
|
{
|
|
|
|
const NodeID node = reverse_heap.DeleteMin();
|
|
|
|
const int key = reverse_heap.GetKey(node);
|
2016-08-09 12:21:23 -04:00
|
|
|
reverse_entry_points.emplace_back(node, key, reverse_heap.GetData(node).parent);
|
2015-11-25 15:45:09 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-10-05 19:05:03 -04:00
|
|
|
RoutingStep(facade,
|
|
|
|
reverse_heap,
|
2016-05-27 15:05:04 -04:00
|
|
|
forward_heap,
|
|
|
|
middle,
|
2016-05-12 12:50:10 -04:00
|
|
|
weight,
|
2016-05-27 15:05:04 -04:00
|
|
|
min_edge_offset,
|
|
|
|
false,
|
|
|
|
STALLING_ENABLED,
|
|
|
|
force_loop_reverse,
|
|
|
|
force_loop_forward);
|
2015-11-25 15:45:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-08-09 12:21:23 -04:00
|
|
|
|
2016-09-06 09:47:03 -04:00
|
|
|
const auto insertInCoreHeap = [](const CoreEntryPoint &p,
|
|
|
|
SearchEngineData::QueryHeap &core_heap) {
|
|
|
|
NodeID id;
|
|
|
|
EdgeWeight weight;
|
|
|
|
NodeID parent;
|
|
|
|
// TODO this should use std::apply when we get c++17 support
|
|
|
|
std::tie(id, weight, parent) = p;
|
|
|
|
core_heap.Insert(id, weight, parent);
|
|
|
|
};
|
2016-08-09 12:21:23 -04:00
|
|
|
|
2016-02-13 13:17:30 -05:00
|
|
|
forward_core_heap.Clear();
|
2016-03-15 06:47:14 -04:00
|
|
|
for (const auto &p : forward_entry_points)
|
2015-11-25 15:45:09 -05:00
|
|
|
{
|
2016-08-09 12:21:23 -04:00
|
|
|
insertInCoreHeap(p, forward_core_heap);
|
2015-11-25 15:45:09 -05:00
|
|
|
}
|
2016-08-09 12:21:23 -04:00
|
|
|
|
|
|
|
reverse_core_heap.Clear();
|
2016-03-15 06:47:14 -04:00
|
|
|
for (const auto &p : reverse_entry_points)
|
2015-11-25 15:45:09 -05:00
|
|
|
{
|
2016-08-09 12:21:23 -04:00
|
|
|
insertInCoreHeap(p, reverse_core_heap);
|
2015-11-25 15:45:09 -05:00
|
|
|
}
|
|
|
|
|
2015-11-30 23:28:57 -05:00
|
|
|
// get offset to account for offsets on phantom nodes on compressed edges
|
|
|
|
int min_core_edge_offset = 0;
|
|
|
|
if (forward_core_heap.Size() > 0)
|
|
|
|
{
|
|
|
|
min_core_edge_offset = std::min(min_core_edge_offset, forward_core_heap.MinKey());
|
|
|
|
}
|
|
|
|
if (reverse_core_heap.Size() > 0 && reverse_core_heap.MinKey() < 0)
|
|
|
|
{
|
|
|
|
min_core_edge_offset = std::min(min_core_edge_offset, reverse_core_heap.MinKey());
|
|
|
|
}
|
|
|
|
BOOST_ASSERT(min_core_edge_offset <= 0);
|
|
|
|
|
2015-11-25 15:45:09 -05:00
|
|
|
// run two-target Dijkstra routing step on core with termination criterion
|
2016-01-07 04:33:47 -05:00
|
|
|
const constexpr bool STALLING_DISABLED = false;
|
2016-03-14 05:14:23 -04:00
|
|
|
while (0 < forward_core_heap.Size() && 0 < reverse_core_heap.Size() &&
|
2016-05-12 12:50:10 -04:00
|
|
|
weight > (forward_core_heap.MinKey() + reverse_core_heap.MinKey()))
|
2015-11-25 15:45:09 -05:00
|
|
|
{
|
2016-10-05 19:05:03 -04:00
|
|
|
RoutingStep(facade,
|
|
|
|
forward_core_heap,
|
2016-05-27 15:05:04 -04:00
|
|
|
reverse_core_heap,
|
|
|
|
middle,
|
2016-05-12 12:50:10 -04:00
|
|
|
weight,
|
2016-05-27 15:05:04 -04:00
|
|
|
min_core_edge_offset,
|
|
|
|
true,
|
|
|
|
STALLING_DISABLED,
|
|
|
|
force_loop_forward,
|
2016-03-14 05:14:23 -04:00
|
|
|
force_loop_reverse);
|
|
|
|
|
2016-10-05 19:05:03 -04:00
|
|
|
RoutingStep(facade,
|
|
|
|
reverse_core_heap,
|
2016-05-27 15:05:04 -04:00
|
|
|
forward_core_heap,
|
|
|
|
middle,
|
2016-05-12 12:50:10 -04:00
|
|
|
weight,
|
2016-05-27 15:05:04 -04:00
|
|
|
min_core_edge_offset,
|
|
|
|
false,
|
|
|
|
STALLING_DISABLED,
|
|
|
|
force_loop_reverse,
|
2016-03-14 05:14:23 -04:00
|
|
|
force_loop_forward);
|
2015-11-25 15:45:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// No path found for both target nodes?
|
2016-05-12 12:50:10 -04:00
|
|
|
if (duration_upper_bound <= weight || SPECIAL_NODEID == middle)
|
2015-11-25 15:45:09 -05:00
|
|
|
{
|
2016-05-12 12:50:10 -04:00
|
|
|
weight = INVALID_EDGE_WEIGHT;
|
2015-11-25 15:45:09 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Was a paths over one of the forward/reverse nodes not found?
|
2016-05-12 12:50:10 -04:00
|
|
|
BOOST_ASSERT_MSG((SPECIAL_NODEID != middle && INVALID_EDGE_WEIGHT != weight),
|
2015-11-25 15:45:09 -05:00
|
|
|
"no path found");
|
|
|
|
|
2016-02-20 19:38:06 -05:00
|
|
|
// we need to unpack sub path from core heaps
|
2016-10-05 19:05:03 -04:00
|
|
|
if (facade.IsCoreNode(middle))
|
2015-11-25 15:45:09 -05:00
|
|
|
{
|
2016-05-12 12:50:10 -04:00
|
|
|
if (weight != forward_core_heap.GetKey(middle) + reverse_core_heap.GetKey(middle))
|
2016-02-20 19:38:06 -05:00
|
|
|
{
|
|
|
|
// self loop
|
|
|
|
BOOST_ASSERT(forward_core_heap.GetData(middle).parent == middle &&
|
|
|
|
reverse_core_heap.GetData(middle).parent == middle);
|
|
|
|
packed_leg.push_back(middle);
|
|
|
|
packed_leg.push_back(middle);
|
|
|
|
}
|
|
|
|
else
|
2016-01-07 04:33:47 -05:00
|
|
|
{
|
|
|
|
std::vector<NodeID> packed_core_leg;
|
2016-05-27 15:05:04 -04:00
|
|
|
RetrievePackedPathFromHeap(
|
|
|
|
forward_core_heap, reverse_core_heap, middle, packed_core_leg);
|
2016-01-07 04:33:47 -05:00
|
|
|
BOOST_ASSERT(packed_core_leg.size() > 0);
|
|
|
|
RetrievePackedPathFromSingleHeap(forward_heap, packed_core_leg.front(), packed_leg);
|
|
|
|
std::reverse(packed_leg.begin(), packed_leg.end());
|
|
|
|
packed_leg.insert(packed_leg.end(), packed_core_leg.begin(), packed_core_leg.end());
|
|
|
|
RetrievePackedPathFromSingleHeap(reverse_heap, packed_core_leg.back(), packed_leg);
|
|
|
|
}
|
2016-02-20 19:38:06 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-05-12 12:50:10 -04:00
|
|
|
if (weight != forward_heap.GetKey(middle) + reverse_heap.GetKey(middle))
|
2016-02-20 19:38:06 -05:00
|
|
|
{
|
|
|
|
// self loop
|
|
|
|
BOOST_ASSERT(forward_heap.GetData(middle).parent == middle &&
|
|
|
|
reverse_heap.GetData(middle).parent == middle);
|
|
|
|
packed_leg.push_back(middle);
|
|
|
|
packed_leg.push_back(middle);
|
|
|
|
}
|
2016-01-07 04:33:47 -05:00
|
|
|
else
|
|
|
|
{
|
|
|
|
RetrievePackedPathFromHeap(forward_heap, reverse_heap, middle, packed_leg);
|
|
|
|
}
|
2015-11-25 15:45:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-07 15:26:12 -05:00
|
|
|
bool NeedsLoopForward(const PhantomNode &source_phantom,
|
|
|
|
const PhantomNode &target_phantom) const
|
|
|
|
{
|
2016-03-28 11:06:51 -04:00
|
|
|
return source_phantom.forward_segment_id.enabled &&
|
|
|
|
target_phantom.forward_segment_id.enabled &&
|
|
|
|
source_phantom.forward_segment_id.id == target_phantom.forward_segment_id.id &&
|
2016-03-07 15:26:12 -05:00
|
|
|
source_phantom.GetForwardWeightPlusOffset() >
|
|
|
|
target_phantom.GetForwardWeightPlusOffset();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool NeedsLoopBackwards(const PhantomNode &source_phantom,
|
|
|
|
const PhantomNode &target_phantom) const
|
|
|
|
{
|
2016-03-28 11:06:51 -04:00
|
|
|
return source_phantom.reverse_segment_id.enabled &&
|
|
|
|
target_phantom.reverse_segment_id.enabled &&
|
|
|
|
source_phantom.reverse_segment_id.id == target_phantom.reverse_segment_id.id &&
|
2016-03-07 15:26:12 -05:00
|
|
|
source_phantom.GetReverseWeightPlusOffset() >
|
|
|
|
target_phantom.GetReverseWeightPlusOffset();
|
|
|
|
}
|
|
|
|
|
2016-10-05 19:05:03 -04:00
|
|
|
double GetPathDistance(const DataFacadeT &facade,
|
|
|
|
const std::vector<NodeID> &packed_path,
|
2016-03-07 15:26:12 -05:00
|
|
|
const PhantomNode &source_phantom,
|
|
|
|
const PhantomNode &target_phantom) const
|
|
|
|
{
|
|
|
|
std::vector<PathData> unpacked_path;
|
|
|
|
PhantomNodes nodes;
|
|
|
|
nodes.source_phantom = source_phantom;
|
|
|
|
nodes.target_phantom = target_phantom;
|
2016-10-05 19:05:03 -04:00
|
|
|
UnpackPath(facade, packed_path.begin(), packed_path.end(), nodes, unpacked_path);
|
2016-03-07 15:26:12 -05:00
|
|
|
|
2016-04-30 18:41:33 -04:00
|
|
|
using util::coordinate_calculation::detail::DEGREE_TO_RAD;
|
|
|
|
using util::coordinate_calculation::detail::EARTH_RADIUS;
|
|
|
|
|
2016-03-07 15:26:12 -05:00
|
|
|
double distance = 0;
|
2016-04-30 18:41:33 -04:00
|
|
|
double prev_lat =
|
|
|
|
static_cast<double>(toFloating(source_phantom.location.lat)) * DEGREE_TO_RAD;
|
|
|
|
double prev_lon =
|
|
|
|
static_cast<double>(toFloating(source_phantom.location.lon)) * DEGREE_TO_RAD;
|
|
|
|
double prev_cos = std::cos(prev_lat);
|
2016-03-07 15:26:12 -05:00
|
|
|
for (const auto &p : unpacked_path)
|
|
|
|
{
|
2016-10-05 19:05:03 -04:00
|
|
|
const auto current_coordinate = facade.GetCoordinateOfNode(p.turn_via_node);
|
2016-04-30 18:41:33 -04:00
|
|
|
|
|
|
|
const double current_lat =
|
|
|
|
static_cast<double>(toFloating(current_coordinate.lat)) * DEGREE_TO_RAD;
|
|
|
|
const double current_lon =
|
|
|
|
static_cast<double>(toFloating(current_coordinate.lon)) * DEGREE_TO_RAD;
|
|
|
|
const double current_cos = std::cos(current_lat);
|
|
|
|
|
|
|
|
const double sin_dlon = std::sin((prev_lon - current_lon) / 2.0);
|
|
|
|
const double sin_dlat = std::sin((prev_lat - current_lat) / 2.0);
|
|
|
|
|
|
|
|
const double aharv = sin_dlat * sin_dlat + prev_cos * current_cos * sin_dlon * sin_dlon;
|
|
|
|
const double charv = 2. * std::atan2(std::sqrt(aharv), std::sqrt(1.0 - aharv));
|
|
|
|
distance += EARTH_RADIUS * charv;
|
|
|
|
|
|
|
|
prev_lat = current_lat;
|
|
|
|
prev_lon = current_lon;
|
|
|
|
prev_cos = current_cos;
|
2016-03-07 15:26:12 -05:00
|
|
|
}
|
2016-04-30 18:41:33 -04:00
|
|
|
|
|
|
|
const double current_lat =
|
|
|
|
static_cast<double>(toFloating(target_phantom.location.lat)) * DEGREE_TO_RAD;
|
|
|
|
const double current_lon =
|
|
|
|
static_cast<double>(toFloating(target_phantom.location.lon)) * DEGREE_TO_RAD;
|
|
|
|
const double current_cos = std::cos(current_lat);
|
|
|
|
|
|
|
|
const double sin_dlon = std::sin((prev_lon - current_lon) / 2.0);
|
|
|
|
const double sin_dlat = std::sin((prev_lat - current_lat) / 2.0);
|
|
|
|
|
|
|
|
const double aharv = sin_dlat * sin_dlat + prev_cos * current_cos * sin_dlon * sin_dlon;
|
|
|
|
const double charv = 2. * std::atan2(std::sqrt(aharv), std::sqrt(1.0 - aharv));
|
|
|
|
distance += EARTH_RADIUS * charv;
|
|
|
|
|
2016-03-07 15:26:12 -05:00
|
|
|
return distance;
|
|
|
|
}
|
|
|
|
|
2016-01-07 04:33:47 -05:00
|
|
|
// Requires the heaps for be empty
|
|
|
|
// If heaps should be adjusted to be initialized outside of this function,
|
|
|
|
// the addition of force_loop parameters might be required
|
2016-10-05 19:05:03 -04:00
|
|
|
double GetNetworkDistanceWithCore(const DataFacadeT &facade,
|
|
|
|
SearchEngineData::QueryHeap &forward_heap,
|
2016-03-07 15:26:12 -05:00
|
|
|
SearchEngineData::QueryHeap &reverse_heap,
|
|
|
|
SearchEngineData::QueryHeap &forward_core_heap,
|
|
|
|
SearchEngineData::QueryHeap &reverse_core_heap,
|
|
|
|
const PhantomNode &source_phantom,
|
2016-03-07 18:11:35 -05:00
|
|
|
const PhantomNode &target_phantom,
|
2016-03-03 08:26:13 -05:00
|
|
|
int duration_upper_bound = INVALID_EDGE_WEIGHT) const
|
2015-03-03 08:22:52 -05:00
|
|
|
{
|
2016-01-07 04:33:47 -05:00
|
|
|
BOOST_ASSERT(forward_heap.Empty());
|
|
|
|
BOOST_ASSERT(reverse_heap.Empty());
|
2015-03-03 08:22:52 -05:00
|
|
|
|
2016-03-28 11:06:51 -04:00
|
|
|
if (source_phantom.forward_segment_id.enabled)
|
2015-03-03 08:22:52 -05:00
|
|
|
{
|
2016-03-28 11:06:51 -04:00
|
|
|
forward_heap.Insert(source_phantom.forward_segment_id.id,
|
2015-03-03 08:22:52 -05:00
|
|
|
-source_phantom.GetForwardWeightPlusOffset(),
|
2016-03-28 11:06:51 -04:00
|
|
|
source_phantom.forward_segment_id.id);
|
2015-03-03 08:22:52 -05:00
|
|
|
}
|
2016-03-28 11:06:51 -04:00
|
|
|
if (source_phantom.reverse_segment_id.enabled)
|
2015-03-03 08:22:52 -05:00
|
|
|
{
|
2016-03-28 11:06:51 -04:00
|
|
|
forward_heap.Insert(source_phantom.reverse_segment_id.id,
|
2015-03-03 08:22:52 -05:00
|
|
|
-source_phantom.GetReverseWeightPlusOffset(),
|
2016-03-28 11:06:51 -04:00
|
|
|
source_phantom.reverse_segment_id.id);
|
2015-03-03 08:22:52 -05:00
|
|
|
}
|
|
|
|
|
2016-03-28 11:06:51 -04:00
|
|
|
if (target_phantom.forward_segment_id.enabled)
|
2015-03-03 08:22:52 -05:00
|
|
|
{
|
2016-03-28 11:06:51 -04:00
|
|
|
reverse_heap.Insert(target_phantom.forward_segment_id.id,
|
2015-03-03 08:22:52 -05:00
|
|
|
target_phantom.GetForwardWeightPlusOffset(),
|
2016-03-28 11:06:51 -04:00
|
|
|
target_phantom.forward_segment_id.id);
|
2015-03-03 08:22:52 -05:00
|
|
|
}
|
2016-03-28 11:06:51 -04:00
|
|
|
if (target_phantom.reverse_segment_id.enabled)
|
2015-03-03 08:22:52 -05:00
|
|
|
{
|
2016-03-28 11:06:51 -04:00
|
|
|
reverse_heap.Insert(target_phantom.reverse_segment_id.id,
|
2015-03-03 08:22:52 -05:00
|
|
|
target_phantom.GetReverseWeightPlusOffset(),
|
2016-03-28 11:06:51 -04:00
|
|
|
target_phantom.reverse_segment_id.id);
|
2015-03-03 08:22:52 -05:00
|
|
|
}
|
|
|
|
|
2016-03-07 15:26:12 -05:00
|
|
|
const bool constexpr DO_NOT_FORCE_LOOPS =
|
|
|
|
false; // prevents forcing of loops, since offsets are set correctly
|
|
|
|
|
|
|
|
int duration = INVALID_EDGE_WEIGHT;
|
|
|
|
std::vector<NodeID> packed_path;
|
2016-10-05 19:05:03 -04:00
|
|
|
SearchWithCore(facade,
|
|
|
|
forward_heap,
|
2016-05-27 15:05:04 -04:00
|
|
|
reverse_heap,
|
|
|
|
forward_core_heap,
|
|
|
|
reverse_core_heap,
|
|
|
|
duration,
|
|
|
|
packed_path,
|
|
|
|
DO_NOT_FORCE_LOOPS,
|
|
|
|
DO_NOT_FORCE_LOOPS,
|
|
|
|
duration_upper_bound);
|
2016-03-07 15:26:12 -05:00
|
|
|
|
|
|
|
double distance = std::numeric_limits<double>::max();
|
|
|
|
if (duration != INVALID_EDGE_WEIGHT)
|
2015-03-03 08:22:52 -05:00
|
|
|
{
|
2016-10-05 19:05:03 -04:00
|
|
|
return GetPathDistance(facade, packed_path, source_phantom, target_phantom);
|
2015-03-03 08:22:52 -05:00
|
|
|
}
|
2016-03-07 15:26:12 -05:00
|
|
|
return distance;
|
|
|
|
}
|
2015-03-03 08:22:52 -05:00
|
|
|
|
2016-03-07 15:26:12 -05:00
|
|
|
// Requires the heaps for be empty
|
|
|
|
// If heaps should be adjusted to be initialized outside of this function,
|
|
|
|
// the addition of force_loop parameters might be required
|
2016-10-05 19:05:03 -04:00
|
|
|
double GetNetworkDistance(const DataFacadeT &facade,
|
|
|
|
SearchEngineData::QueryHeap &forward_heap,
|
2016-03-07 15:26:12 -05:00
|
|
|
SearchEngineData::QueryHeap &reverse_heap,
|
|
|
|
const PhantomNode &source_phantom,
|
2016-03-07 18:11:35 -05:00
|
|
|
const PhantomNode &target_phantom,
|
2016-03-03 08:26:13 -05:00
|
|
|
int duration_upper_bound = INVALID_EDGE_WEIGHT) const
|
2016-03-07 15:26:12 -05:00
|
|
|
{
|
|
|
|
BOOST_ASSERT(forward_heap.Empty());
|
|
|
|
BOOST_ASSERT(reverse_heap.Empty());
|
|
|
|
|
2016-03-28 11:06:51 -04:00
|
|
|
if (source_phantom.forward_segment_id.enabled)
|
2015-03-03 08:22:52 -05:00
|
|
|
{
|
2016-03-28 11:06:51 -04:00
|
|
|
forward_heap.Insert(source_phantom.forward_segment_id.id,
|
2016-03-07 15:26:12 -05:00
|
|
|
-source_phantom.GetForwardWeightPlusOffset(),
|
2016-03-28 11:06:51 -04:00
|
|
|
source_phantom.forward_segment_id.id);
|
2016-03-07 15:26:12 -05:00
|
|
|
}
|
2016-03-28 11:06:51 -04:00
|
|
|
if (source_phantom.reverse_segment_id.enabled)
|
2016-03-07 15:26:12 -05:00
|
|
|
{
|
2016-03-28 11:06:51 -04:00
|
|
|
forward_heap.Insert(source_phantom.reverse_segment_id.id,
|
2016-03-07 15:26:12 -05:00
|
|
|
-source_phantom.GetReverseWeightPlusOffset(),
|
2016-03-28 11:06:51 -04:00
|
|
|
source_phantom.reverse_segment_id.id);
|
2016-03-07 15:26:12 -05:00
|
|
|
}
|
|
|
|
|
2016-03-28 11:06:51 -04:00
|
|
|
if (target_phantom.forward_segment_id.enabled)
|
2016-03-07 15:26:12 -05:00
|
|
|
{
|
2016-03-28 11:06:51 -04:00
|
|
|
reverse_heap.Insert(target_phantom.forward_segment_id.id,
|
2016-03-07 15:26:12 -05:00
|
|
|
target_phantom.GetForwardWeightPlusOffset(),
|
2016-03-28 11:06:51 -04:00
|
|
|
target_phantom.forward_segment_id.id);
|
2016-03-07 15:26:12 -05:00
|
|
|
}
|
2016-03-28 11:06:51 -04:00
|
|
|
if (target_phantom.reverse_segment_id.enabled)
|
2016-03-07 15:26:12 -05:00
|
|
|
{
|
2016-03-28 11:06:51 -04:00
|
|
|
reverse_heap.Insert(target_phantom.reverse_segment_id.id,
|
2016-03-07 15:26:12 -05:00
|
|
|
target_phantom.GetReverseWeightPlusOffset(),
|
2016-03-28 11:06:51 -04:00
|
|
|
target_phantom.reverse_segment_id.id);
|
2016-03-07 15:26:12 -05:00
|
|
|
}
|
2016-01-07 04:33:47 -05:00
|
|
|
|
2016-03-07 15:26:12 -05:00
|
|
|
const bool constexpr DO_NOT_FORCE_LOOPS =
|
|
|
|
false; // prevents forcing of loops, since offsets are set correctly
|
2015-03-03 08:22:52 -05:00
|
|
|
|
2016-03-07 15:26:12 -05:00
|
|
|
int duration = INVALID_EDGE_WEIGHT;
|
|
|
|
std::vector<NodeID> packed_path;
|
2016-10-05 19:05:03 -04:00
|
|
|
Search(facade,
|
|
|
|
forward_heap,
|
2016-05-27 15:05:04 -04:00
|
|
|
reverse_heap,
|
|
|
|
duration,
|
|
|
|
packed_path,
|
|
|
|
DO_NOT_FORCE_LOOPS,
|
|
|
|
DO_NOT_FORCE_LOOPS,
|
|
|
|
duration_upper_bound);
|
2016-03-07 15:26:12 -05:00
|
|
|
|
|
|
|
if (duration == INVALID_EDGE_WEIGHT)
|
|
|
|
{
|
|
|
|
return std::numeric_limits<double>::max();
|
2015-03-03 08:22:52 -05:00
|
|
|
}
|
2016-03-07 15:26:12 -05:00
|
|
|
|
2016-10-05 19:05:03 -04:00
|
|
|
return GetPathDistance(facade, packed_path, source_phantom, target_phantom);
|
2015-03-03 08:22:52 -05:00
|
|
|
}
|
2012-06-15 12:47:27 -04:00
|
|
|
};
|
2016-01-05 10:51:13 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-28 09:33:08 -05:00
|
|
|
#endif // ROUTING_BASE_HPP
|