Merge branch 'master' into pr-6611
This commit is contained in:
@@ -375,7 +375,7 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
|
||||
BOOST_ASSERT(m_geospatial_query.get());
|
||||
|
||||
return m_geospatial_query->NearestPhantomNodes(
|
||||
input_coordinate, approach, boost::none, max_distance, bearing, use_all_edges);
|
||||
input_coordinate, approach, max_distance, bearing, use_all_edges);
|
||||
}
|
||||
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
|
||||
@@ -47,12 +47,42 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
return rtree.SearchInBox(bbox);
|
||||
}
|
||||
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
||||
const Approach approach,
|
||||
const double max_distance,
|
||||
const boost::optional<Bearing> bearing_with_range,
|
||||
const boost::optional<bool> use_all_edges) const
|
||||
{
|
||||
auto results = rtree.SearchInRange(
|
||||
input_coordinate,
|
||||
max_distance,
|
||||
[this, approach, &input_coordinate, &bearing_with_range, &use_all_edges, max_distance](
|
||||
const CandidateSegment &segment)
|
||||
{
|
||||
auto invalidDistance =
|
||||
CheckSegmentDistance(input_coordinate, segment, max_distance);
|
||||
if (invalidDistance)
|
||||
{
|
||||
return std::make_pair(false, false);
|
||||
}
|
||||
auto valid = CheckSegmentExclude(segment) &&
|
||||
CheckApproach(input_coordinate, segment, approach) &&
|
||||
(use_all_edges ? HasValidEdge(segment, *use_all_edges)
|
||||
: HasValidEdge(segment)) &&
|
||||
(bearing_with_range ? CheckSegmentBearing(segment, *bearing_with_range)
|
||||
: std::make_pair(true, true));
|
||||
return valid;
|
||||
});
|
||||
return MakePhantomNodes(input_coordinate, results);
|
||||
}
|
||||
|
||||
// Returns max_results nearest PhantomNodes that are valid within the provided parameters.
|
||||
// Does not filter by small/big component!
|
||||
std::vector<PhantomNodeWithDistance>
|
||||
NearestPhantomNodes(const util::Coordinate input_coordinate,
|
||||
const Approach approach,
|
||||
const boost::optional<size_t> max_results,
|
||||
const size_t max_results,
|
||||
const boost::optional<double> max_distance,
|
||||
const boost::optional<Bearing> bearing_with_range,
|
||||
const boost::optional<bool> use_all_edges) const
|
||||
@@ -70,10 +100,10 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
|
||||
: std::make_pair(true, true));
|
||||
return valid;
|
||||
},
|
||||
[this, &max_distance, &max_results, input_coordinate](const std::size_t num_results,
|
||||
const CandidateSegment &segment)
|
||||
[this, &max_distance, max_results, input_coordinate](const std::size_t num_results,
|
||||
const CandidateSegment &segment)
|
||||
{
|
||||
return (max_results && num_results >= *max_results) ||
|
||||
return (num_results >= max_results) ||
|
||||
(max_distance && max_distance != -1.0 &&
|
||||
CheckSegmentDistance(input_coordinate, segment, *max_distance));
|
||||
});
|
||||
|
||||
@@ -71,24 +71,27 @@ void insertTargetInReverseHeap(Heap &reverse_heap, const PhantomNode &target)
|
||||
static constexpr bool FORWARD_DIRECTION = true;
|
||||
static constexpr bool REVERSE_DIRECTION = false;
|
||||
|
||||
// Identify nodes in the forward(reverse) search direction that will require loop forcing
|
||||
// Identify nodes in the forward(reverse) search direction that will require step forcing
|
||||
// e.g. if source and destination nodes are on the same segment.
|
||||
std::vector<NodeID> getForwardLoopNodes(const PhantomEndpointCandidates &candidates);
|
||||
std::vector<NodeID> getForwardLoopNodes(const PhantomCandidatesToTarget &candidates);
|
||||
std::vector<NodeID> getBackwardLoopNodes(const PhantomEndpointCandidates &candidates);
|
||||
std::vector<NodeID> getBackwardLoopNodes(const PhantomCandidatesToTarget &candidates);
|
||||
std::vector<NodeID> getForwardForceNodes(const PhantomEndpointCandidates &candidates);
|
||||
std::vector<NodeID> getForwardForceNodes(const PhantomCandidatesToTarget &candidates);
|
||||
std::vector<NodeID> getBackwardForceNodes(const PhantomEndpointCandidates &candidates);
|
||||
std::vector<NodeID> getBackwardForceNodes(const PhantomCandidatesToTarget &candidates);
|
||||
|
||||
// Find the specific phantom node endpoints for a given path from a list of candidates.
|
||||
PhantomEndpoints endpointsFromCandidates(const PhantomEndpointCandidates &candidates,
|
||||
const std::vector<NodeID> &path);
|
||||
|
||||
template <typename HeapNodeT>
|
||||
inline bool force_loop(const std::vector<NodeID> &force_nodes, const HeapNodeT &heap_node)
|
||||
inline bool shouldForceStep(const std::vector<NodeID> &force_nodes,
|
||||
const HeapNodeT &forward_heap_node,
|
||||
const HeapNodeT &reverse_heap_node)
|
||||
{
|
||||
// if loops are forced, they are so at the source
|
||||
return !force_nodes.empty() &&
|
||||
std::find(force_nodes.begin(), force_nodes.end(), heap_node.node) != force_nodes.end() &&
|
||||
heap_node.data.parent == heap_node.node;
|
||||
// routing steps are forced when the node is a source of both forward and reverse search heaps.
|
||||
return forward_heap_node.data.parent == forward_heap_node.node &&
|
||||
reverse_heap_node.data.parent == reverse_heap_node.node &&
|
||||
std::find(force_nodes.begin(), force_nodes.end(), forward_heap_node.node) !=
|
||||
force_nodes.end();
|
||||
}
|
||||
|
||||
template <typename Heap>
|
||||
|
||||
@@ -112,8 +112,7 @@ void routingStep(const DataFacade<Algorithm> &facade,
|
||||
NodeID &middle_node_id,
|
||||
EdgeWeight &upper_bound,
|
||||
EdgeWeight min_edge_offset,
|
||||
const std::vector<NodeID> &force_loop_forward_nodes,
|
||||
const std::vector<NodeID> &force_loop_reverse_nodes)
|
||||
const std::vector<NodeID> &force_step_nodes)
|
||||
{
|
||||
auto heapNode = forward_heap.DeleteMinGetHeapNode();
|
||||
const auto reverseHeapNode = reverse_heap.GetHeapNodeIfWasInserted(heapNode.node);
|
||||
@@ -123,13 +122,13 @@ void routingStep(const DataFacade<Algorithm> &facade,
|
||||
const EdgeWeight new_weight = reverseHeapNode->weight + heapNode.weight;
|
||||
if (new_weight < upper_bound)
|
||||
{
|
||||
if (force_loop(force_loop_forward_nodes, heapNode) ||
|
||||
force_loop(force_loop_reverse_nodes, heapNode) ||
|
||||
if (shouldForceStep(force_step_nodes, heapNode, reverseHeapNode.get()) ||
|
||||
// in this case we are looking at a bi-directional way where the source
|
||||
// and target phantom are on the same edge based node
|
||||
new_weight < EdgeWeight{0})
|
||||
{
|
||||
// check whether there is a loop present at the node
|
||||
// Before forcing step, check whether there is a loop present at the node.
|
||||
// We may find a valid weight path by following the loop.
|
||||
for (const auto edge : facade.GetAdjacentEdgeRange(heapNode.node))
|
||||
{
|
||||
const auto &data = facade.GetEdgeData(edge);
|
||||
@@ -421,23 +420,22 @@ void retrievePackedPathFromSingleManyToManyHeap(
|
||||
// assumes that heaps are already setup correctly.
|
||||
// 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.
|
||||
// In case additional offsets are supplied, you might have to force a routing step first.
|
||||
// A forced step 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
|
||||
// then a force loop is required (e.g. source_phantom.forward_segment_id ==
|
||||
// then a force step is required (e.g. source_phantom.forward_segment_id ==
|
||||
// target_phantom.forward_segment_id
|
||||
// && source_phantom.GetForwardWeightPlusOffset() > target_phantom.GetForwardWeightPlusOffset())
|
||||
// requires
|
||||
// a force loop, if the heaps have been initialized with positive offsets.
|
||||
// a force step, if the heaps have been initialized with positive offsets.
|
||||
void search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||
SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
EdgeWeight &weight,
|
||||
std::vector<NodeID> &packed_leg,
|
||||
const std::vector<NodeID> &force_loop_forward_node,
|
||||
const std::vector<NodeID> &force_loop_reverse_node,
|
||||
const std::vector<NodeID> &force_step_nodes,
|
||||
const EdgeWeight duration_upper_bound = INVALID_EDGE_WEIGHT);
|
||||
|
||||
template <typename PhantomEndpointT>
|
||||
@@ -447,8 +445,7 @@ void search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
EdgeWeight &weight,
|
||||
std::vector<NodeID> &packed_leg,
|
||||
const std::vector<NodeID> &force_loop_forward_node,
|
||||
const std::vector<NodeID> &force_loop_reverse_node,
|
||||
const std::vector<NodeID> &force_step_nodes,
|
||||
const PhantomEndpointT & /*endpoints*/,
|
||||
const EdgeWeight duration_upper_bound = INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
@@ -459,14 +456,13 @@ void search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
reverse_heap,
|
||||
weight,
|
||||
packed_leg,
|
||||
force_loop_forward_node,
|
||||
force_loop_reverse_node,
|
||||
force_step_nodes,
|
||||
duration_upper_bound);
|
||||
}
|
||||
|
||||
// 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
|
||||
// the addition of force_step parameters might be required
|
||||
double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<ch::Algorithm> &facade,
|
||||
SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||
|
||||
@@ -389,8 +389,7 @@ void routingStep(const DataFacade<Algorithm> &facade,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
NodeID &middle_node,
|
||||
EdgeWeight &path_upper_bound,
|
||||
const std::vector<NodeID> &force_loop_forward_nodes,
|
||||
const std::vector<NodeID> &force_loop_reverse_nodes,
|
||||
const std::vector<NodeID> &force_step_nodes,
|
||||
const Args &...args)
|
||||
{
|
||||
const auto heapNode = forward_heap.DeleteMinGetHeapNode();
|
||||
@@ -409,11 +408,8 @@ void routingStep(const DataFacade<Algorithm> &facade,
|
||||
auto reverse_weight = reverseHeapNode->weight;
|
||||
auto path_weight = weight + reverse_weight;
|
||||
|
||||
// MLD uses loops forcing only to prune single node paths in forward and/or
|
||||
// backward direction (there is no need to force loops in MLD but in CH)
|
||||
if (!force_loop(force_loop_forward_nodes, heapNode) &&
|
||||
!force_loop(force_loop_reverse_nodes, heapNode) && (path_weight >= EdgeWeight{0}) &&
|
||||
(path_weight < path_upper_bound))
|
||||
if (!shouldForceStep(force_step_nodes, heapNode, reverseHeapNode.get()) &&
|
||||
(path_weight >= EdgeWeight{0}) && (path_weight < path_upper_bound))
|
||||
{
|
||||
middle_node = heapNode.node;
|
||||
path_upper_bound = path_weight;
|
||||
@@ -438,8 +434,7 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
const std::vector<NodeID> &force_loop_forward_nodes,
|
||||
const std::vector<NodeID> &force_loop_reverse_nodes,
|
||||
const std::vector<NodeID> &force_step_nodes,
|
||||
EdgeWeight weight_upper_bound,
|
||||
const Args &...args)
|
||||
{
|
||||
@@ -463,27 +458,15 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
{
|
||||
if (!forward_heap.Empty())
|
||||
{
|
||||
routingStep<FORWARD_DIRECTION>(facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
middle,
|
||||
weight,
|
||||
force_loop_forward_nodes,
|
||||
force_loop_reverse_nodes,
|
||||
args...);
|
||||
routingStep<FORWARD_DIRECTION>(
|
||||
facade, forward_heap, reverse_heap, middle, weight, force_step_nodes, args...);
|
||||
if (!forward_heap.Empty())
|
||||
forward_heap_min = forward_heap.MinKey();
|
||||
}
|
||||
if (!reverse_heap.Empty())
|
||||
{
|
||||
routingStep<REVERSE_DIRECTION>(facade,
|
||||
reverse_heap,
|
||||
forward_heap,
|
||||
middle,
|
||||
weight,
|
||||
force_loop_reverse_nodes,
|
||||
force_loop_forward_nodes,
|
||||
args...);
|
||||
routingStep<REVERSE_DIRECTION>(
|
||||
facade, reverse_heap, forward_heap, middle, weight, force_step_nodes, args...);
|
||||
if (!reverse_heap.Empty())
|
||||
reverse_heap_min = reverse_heap.MinKey();
|
||||
}
|
||||
@@ -512,9 +495,7 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
|
||||
for (auto const &packed_edge : packed_path)
|
||||
{
|
||||
NodeID source, target;
|
||||
bool overlay_edge;
|
||||
std::tie(source, target, overlay_edge) = packed_edge;
|
||||
auto [source, target, overlay_edge] = packed_edge;
|
||||
if (!overlay_edge)
|
||||
{ // a base graph edge
|
||||
unpacked_nodes.push_back(target);
|
||||
@@ -534,21 +515,14 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
forward_heap.Insert(source, {0}, {source});
|
||||
reverse_heap.Insert(target, {0}, {target});
|
||||
|
||||
// TODO: when structured bindings will be allowed change to
|
||||
// auto [subpath_weight, subpath_source, subpath_target, subpath] = ...
|
||||
EdgeWeight subpath_weight;
|
||||
std::vector<NodeID> subpath_nodes;
|
||||
std::vector<EdgeID> subpath_edges;
|
||||
std::tie(subpath_weight, subpath_nodes, subpath_edges) =
|
||||
search(engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
force_loop_forward_nodes,
|
||||
force_loop_reverse_nodes,
|
||||
INVALID_EDGE_WEIGHT,
|
||||
sublevel,
|
||||
parent_cell_id);
|
||||
auto [subpath_weight, subpath_nodes, subpath_edges] = search(engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
force_step_nodes,
|
||||
INVALID_EDGE_WEIGHT,
|
||||
sublevel,
|
||||
parent_cell_id);
|
||||
BOOST_ASSERT(!subpath_edges.empty());
|
||||
BOOST_ASSERT(subpath_nodes.size() > 1);
|
||||
BOOST_ASSERT(subpath_nodes.front() == source);
|
||||
@@ -570,8 +544,7 @@ inline void search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
EdgeWeight &weight,
|
||||
std::vector<NodeID> &unpacked_nodes,
|
||||
const std::vector<NodeID> &force_loop_forward_node,
|
||||
const std::vector<NodeID> &force_loop_reverse_node,
|
||||
const std::vector<NodeID> &force_step_nodes,
|
||||
const PhantomEndpointT &endpoints,
|
||||
const EdgeWeight weight_upper_bound = INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
@@ -580,8 +553,7 @@ inline void search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
force_loop_forward_node,
|
||||
force_loop_reverse_node,
|
||||
force_step_nodes,
|
||||
weight_upper_bound,
|
||||
endpoints);
|
||||
}
|
||||
@@ -633,28 +605,46 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const PhantomEndpoints endpoints{source_phantom, target_phantom};
|
||||
insertNodesInHeaps(forward_heap, reverse_heap, endpoints);
|
||||
|
||||
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
||||
std::vector<NodeID> unpacked_nodes;
|
||||
std::vector<EdgeID> unpacked_edges;
|
||||
std::tie(weight, unpacked_nodes, unpacked_edges) = search(engine_working_data,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
{},
|
||||
{},
|
||||
weight_upper_bound,
|
||||
endpoints);
|
||||
auto [weight, unpacked_nodes, unpacked_edges] = search(
|
||||
engine_working_data, facade, forward_heap, reverse_heap, {}, weight_upper_bound, endpoints);
|
||||
|
||||
if (weight == INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
return std::numeric_limits<double>::max();
|
||||
}
|
||||
|
||||
std::vector<PathData> unpacked_path;
|
||||
BOOST_ASSERT(unpacked_nodes.size() >= 1);
|
||||
|
||||
annotatePath(facade, endpoints, unpacked_nodes, unpacked_edges, unpacked_path);
|
||||
EdgeDistance distance = {0.0};
|
||||
|
||||
return getPathDistance(facade, unpacked_path, source_phantom, target_phantom);
|
||||
if (source_phantom.forward_segment_id.id == unpacked_nodes.front())
|
||||
{
|
||||
BOOST_ASSERT(source_phantom.forward_segment_id.enabled);
|
||||
distance = EdgeDistance{0} - source_phantom.GetForwardDistance();
|
||||
}
|
||||
else if (source_phantom.reverse_segment_id.id == unpacked_nodes.front())
|
||||
{
|
||||
BOOST_ASSERT(source_phantom.reverse_segment_id.enabled);
|
||||
distance = EdgeDistance{0} - source_phantom.GetReverseDistance();
|
||||
}
|
||||
|
||||
for (size_t index = 0; index < unpacked_nodes.size() - 1; ++index)
|
||||
{
|
||||
distance += facade.GetNodeDistance(unpacked_nodes[index]);
|
||||
}
|
||||
|
||||
if (target_phantom.forward_segment_id.id == unpacked_nodes.back())
|
||||
{
|
||||
BOOST_ASSERT(target_phantom.forward_segment_id.enabled);
|
||||
distance += target_phantom.GetForwardDistance();
|
||||
}
|
||||
else if (target_phantom.reverse_segment_id.id == unpacked_nodes.back())
|
||||
{
|
||||
BOOST_ASSERT(target_phantom.reverse_segment_id.enabled);
|
||||
distance += target_phantom.GetReverseDistance();
|
||||
}
|
||||
|
||||
return from_alias<double>(distance);
|
||||
}
|
||||
|
||||
} // namespace osrm::engine::routing_algorithms::mld
|
||||
|
||||
@@ -64,7 +64,6 @@ void searchWithUTurn(SearchEngineData<Algorithm> &engine_working_data,
|
||||
leg_weight,
|
||||
leg_packed_path,
|
||||
{},
|
||||
{},
|
||||
candidates);
|
||||
}
|
||||
|
||||
@@ -124,8 +123,7 @@ void search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
reverse_heap,
|
||||
new_total_weight_to_forward,
|
||||
leg_packed_path_forward,
|
||||
getForwardLoopNodes(candidates),
|
||||
{},
|
||||
getForwardForceNodes(candidates),
|
||||
candidates);
|
||||
}
|
||||
|
||||
@@ -164,8 +162,7 @@ void search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
reverse_heap,
|
||||
new_total_weight_to_reverse,
|
||||
leg_packed_path_reverse,
|
||||
{},
|
||||
getBackwardLoopNodes(candidates),
|
||||
getBackwardForceNodes(candidates),
|
||||
candidates);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ trimLaneString(std::string lane_string, std::int32_t count_left, std::int32_t co
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
inline std::string applyAccessTokens(std::string lane_string, const std::string &access_tokens)
|
||||
{
|
||||
typedef boost::tokenizer<boost::char_separator<char>> tokenizer;
|
||||
using tokenizer = boost::tokenizer<boost::char_separator<char>>;
|
||||
boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
|
||||
tokenizer tokens(lane_string, sep);
|
||||
tokenizer access(access_tokens, sep);
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
#ifndef OSRM_GUIDANCE_TURN_INSTRUCTION_HPP_
|
||||
#define OSRM_GUIDANCE_TURN_INSTRUCTION_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
|
||||
#include "guidance/roundabout_type.hpp"
|
||||
#include "util/attributes.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
namespace osrm::guidance
|
||||
{
|
||||
|
||||
@@ -154,24 +155,23 @@ inline bool operator==(const TurnInstruction lhs, const TurnInstruction rhs)
|
||||
inline bool hasRoundaboutType(const TurnInstruction instruction)
|
||||
{
|
||||
using namespace guidance::TurnType;
|
||||
const constexpr TurnType::Enum valid_types[] = {TurnType::EnterRoundabout,
|
||||
TurnType::EnterAndExitRoundabout,
|
||||
TurnType::EnterRotary,
|
||||
TurnType::EnterAndExitRotary,
|
||||
TurnType::EnterRoundaboutIntersection,
|
||||
TurnType::EnterAndExitRoundaboutIntersection,
|
||||
TurnType::EnterRoundaboutAtExit,
|
||||
TurnType::ExitRoundabout,
|
||||
TurnType::EnterRotaryAtExit,
|
||||
TurnType::ExitRotary,
|
||||
TurnType::EnterRoundaboutIntersectionAtExit,
|
||||
TurnType::ExitRoundaboutIntersection,
|
||||
TurnType::StayOnRoundabout};
|
||||
const constexpr std::array<TurnType::Enum, 13> valid_types = {
|
||||
TurnType::EnterRoundabout,
|
||||
TurnType::EnterAndExitRoundabout,
|
||||
TurnType::EnterRotary,
|
||||
TurnType::EnterAndExitRotary,
|
||||
TurnType::EnterRoundaboutIntersection,
|
||||
TurnType::EnterAndExitRoundaboutIntersection,
|
||||
TurnType::EnterRoundaboutAtExit,
|
||||
TurnType::ExitRoundabout,
|
||||
TurnType::EnterRotaryAtExit,
|
||||
TurnType::ExitRotary,
|
||||
TurnType::EnterRoundaboutIntersectionAtExit,
|
||||
TurnType::ExitRoundaboutIntersection,
|
||||
TurnType::StayOnRoundabout};
|
||||
|
||||
const auto *first = valid_types;
|
||||
const auto *last = first + sizeof(valid_types) / sizeof(valid_types[0]);
|
||||
|
||||
return std::find(first, last, instruction.type) != last;
|
||||
return std::find(valid_types.cbegin(), valid_types.cend(), instruction.type) !=
|
||||
valid_types.cend();
|
||||
}
|
||||
|
||||
inline bool entersRoundabout(const guidance::TurnInstruction instruction)
|
||||
|
||||
@@ -14,18 +14,6 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
// workaround for incomplete std::shared_ptr compatibility in old boost versions
|
||||
#if BOOST_VERSION < 105300 || defined BOOST_NO_CXX11_SMART_PTR
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <class T> const T *get_pointer(std::shared_ptr<T> const &p) { return p.get(); }
|
||||
|
||||
template <class T> T *get_pointer(std::shared_ptr<T> &p) { return p.get(); }
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
|
||||
namespace osrm::server
|
||||
{
|
||||
|
||||
|
||||
@@ -36,6 +36,13 @@ inline double radToDeg(const double radian)
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
const constexpr static double METERS_PER_DEGREE_LAT = 110567.0;
|
||||
|
||||
inline double metersPerLngDegree(const FixedLatitude lat)
|
||||
{
|
||||
return std::cos(detail::degToRad(static_cast<double>(toFloating(lat)))) * METERS_PER_DEGREE_LAT;
|
||||
}
|
||||
|
||||
//! Takes the squared euclidean distance of the input coordinates. Does not return meters!
|
||||
std::uint64_t squaredEuclideanDistance(const Coordinate lhs, const Coordinate rhs);
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ extern "C"
|
||||
#include <lualib.h>
|
||||
}
|
||||
|
||||
#include <boost/filesystem/convenience.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <limits>
|
||||
@@ -168,6 +167,18 @@ struct RectangleInt2D
|
||||
min_lat != FixedLatitude{std::numeric_limits<std::int32_t>::max()} &&
|
||||
max_lat != FixedLatitude{std::numeric_limits<std::int32_t>::min()};
|
||||
}
|
||||
|
||||
static RectangleInt2D ExpandMeters(const Coordinate &coordinate, const double meters)
|
||||
{
|
||||
const double lat_offset = meters / coordinate_calculation::METERS_PER_DEGREE_LAT;
|
||||
const double lon_offset =
|
||||
meters / coordinate_calculation::metersPerLngDegree(coordinate.lat);
|
||||
|
||||
return RectangleInt2D{coordinate.lon - toFixed(FloatLongitude{lon_offset}),
|
||||
coordinate.lon + toFixed(FloatLongitude{lon_offset}),
|
||||
coordinate.lat - toFixed(FloatLatitude{lat_offset}),
|
||||
coordinate.lat + toFixed(FloatLatitude{lat_offset})};
|
||||
}
|
||||
};
|
||||
} // namespace osrm::util
|
||||
|
||||
|
||||
+111
-64
@@ -2,7 +2,6 @@
|
||||
#define STATIC_RTREE_HPP
|
||||
|
||||
#include "storage/tar_fwd.hpp"
|
||||
|
||||
#include "util/bearing.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
#include "util/deallocating_vector.hpp"
|
||||
@@ -11,6 +10,7 @@
|
||||
#include "util/integer_range.hpp"
|
||||
#include "util/mmap_file.hpp"
|
||||
#include "util/rectangle.hpp"
|
||||
#include "util/timing_util.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
#include "util/vector_view.hpp"
|
||||
#include "util/web_mercator.hpp"
|
||||
@@ -487,70 +487,9 @@ class StaticRTree
|
||||
Rectangle needs to be projected!*/
|
||||
std::vector<EdgeDataT> SearchInBox(const Rectangle &search_rectangle) const
|
||||
{
|
||||
const Rectangle projected_rectangle{
|
||||
search_rectangle.min_lon,
|
||||
search_rectangle.max_lon,
|
||||
toFixed(FloatLatitude{
|
||||
web_mercator::latToY(toFloating(FixedLatitude(search_rectangle.min_lat)))}),
|
||||
toFixed(FloatLatitude{
|
||||
web_mercator::latToY(toFloating(FixedLatitude(search_rectangle.max_lat)))})};
|
||||
std::vector<EdgeDataT> results;
|
||||
|
||||
std::queue<TreeIndex> traversal_queue;
|
||||
traversal_queue.push(TreeIndex{});
|
||||
|
||||
while (!traversal_queue.empty())
|
||||
{
|
||||
auto const current_tree_index = traversal_queue.front();
|
||||
traversal_queue.pop();
|
||||
|
||||
// If we're at the bottom of the tree, we need to explore the
|
||||
// element array
|
||||
if (is_leaf(current_tree_index))
|
||||
{
|
||||
|
||||
// Note: irange is [start,finish), so we need to +1 to make sure we visit the
|
||||
// last
|
||||
for (const auto current_child_index : child_indexes(current_tree_index))
|
||||
{
|
||||
const auto ¤t_edge = m_objects[current_child_index];
|
||||
|
||||
// we don't need to project the coordinates here,
|
||||
// because we use the unprojected rectangle to test against
|
||||
const Rectangle bbox{std::min(m_coordinate_list[current_edge.u].lon,
|
||||
m_coordinate_list[current_edge.v].lon),
|
||||
std::max(m_coordinate_list[current_edge.u].lon,
|
||||
m_coordinate_list[current_edge.v].lon),
|
||||
std::min(m_coordinate_list[current_edge.u].lat,
|
||||
m_coordinate_list[current_edge.v].lat),
|
||||
std::max(m_coordinate_list[current_edge.u].lat,
|
||||
m_coordinate_list[current_edge.v].lat)};
|
||||
|
||||
// use the _unprojected_ input rectangle here
|
||||
if (bbox.Intersects(search_rectangle))
|
||||
{
|
||||
results.push_back(current_edge);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(current_tree_index.level + 1 < m_tree_level_starts.size());
|
||||
|
||||
for (const auto child_index : child_indexes(current_tree_index))
|
||||
{
|
||||
const auto &child_rectangle =
|
||||
m_search_tree[child_index].minimum_bounding_rectangle;
|
||||
|
||||
if (child_rectangle.Intersects(projected_rectangle))
|
||||
{
|
||||
traversal_queue.push(TreeIndex(
|
||||
current_tree_index.level + 1,
|
||||
child_index - m_tree_level_starts[current_tree_index.level + 1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SearchInBox(search_rectangle,
|
||||
[&results](const auto &edge_data) { results.push_back(edge_data); });
|
||||
return results;
|
||||
}
|
||||
|
||||
@@ -565,6 +504,45 @@ class StaticRTree
|
||||
{ return num_results >= max_results; });
|
||||
}
|
||||
|
||||
// NB 1: results are not guaranteed to be sorted by distance
|
||||
// NB 2: maxDistanceMeters is not a hard limit, it's just a way to reduce the number of edges
|
||||
// returned
|
||||
template <typename FilterT>
|
||||
std::vector<CandidateSegment> SearchInRange(const Coordinate input_coordinate,
|
||||
double maxDistanceMeters,
|
||||
const FilterT filter) const
|
||||
{
|
||||
auto projected_coordinate = web_mercator::fromWGS84(input_coordinate);
|
||||
Coordinate fixed_projected_coordinate{projected_coordinate};
|
||||
|
||||
auto bbox = Rectangle::ExpandMeters(input_coordinate, maxDistanceMeters);
|
||||
std::vector<CandidateSegment> results;
|
||||
|
||||
SearchInBox(
|
||||
bbox,
|
||||
[&results, &filter, fixed_projected_coordinate, this](const EdgeDataT ¤t_edge)
|
||||
{
|
||||
const auto projected_u = web_mercator::fromWGS84(m_coordinate_list[current_edge.u]);
|
||||
const auto projected_v = web_mercator::fromWGS84(m_coordinate_list[current_edge.v]);
|
||||
|
||||
auto [_, projected_nearest] = coordinate_calculation::projectPointOnSegment(
|
||||
projected_u, projected_v, fixed_projected_coordinate);
|
||||
|
||||
CandidateSegment current_candidate{projected_nearest, current_edge};
|
||||
auto use_segment = filter(current_candidate);
|
||||
if (!use_segment.first && !use_segment.second)
|
||||
{
|
||||
return;
|
||||
}
|
||||
current_candidate.data.forward_segment_id.enabled &= use_segment.first;
|
||||
current_candidate.data.reverse_segment_id.enabled &= use_segment.second;
|
||||
|
||||
results.push_back(current_candidate);
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
// Return edges in distance order with the coordinate of the closest point on the edge.
|
||||
template <typename FilterT, typename TerminationT>
|
||||
std::vector<CandidateSegment> Nearest(const Coordinate input_coordinate,
|
||||
@@ -572,8 +550,10 @@ class StaticRTree
|
||||
const TerminationT terminate) const
|
||||
{
|
||||
std::vector<CandidateSegment> results;
|
||||
|
||||
auto projected_coordinate = web_mercator::fromWGS84(input_coordinate);
|
||||
Coordinate fixed_projected_coordinate{projected_coordinate};
|
||||
|
||||
// initialize queue with root element
|
||||
std::priority_queue<QueryCandidate> traversal_queue;
|
||||
traversal_queue.push(QueryCandidate{0, TreeIndex{}});
|
||||
@@ -631,6 +611,73 @@ class StaticRTree
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Callback>
|
||||
void SearchInBox(const Rectangle &search_rectangle, Callback &&callback) const
|
||||
{
|
||||
const Rectangle projected_rectangle{
|
||||
search_rectangle.min_lon,
|
||||
search_rectangle.max_lon,
|
||||
toFixed(FloatLatitude{
|
||||
web_mercator::latToY(toFloating(FixedLatitude(search_rectangle.min_lat)))}),
|
||||
toFixed(FloatLatitude{
|
||||
web_mercator::latToY(toFloating(FixedLatitude(search_rectangle.max_lat)))})};
|
||||
std::queue<TreeIndex> traversal_queue;
|
||||
traversal_queue.push(TreeIndex{});
|
||||
|
||||
while (!traversal_queue.empty())
|
||||
{
|
||||
auto const current_tree_index = traversal_queue.front();
|
||||
traversal_queue.pop();
|
||||
|
||||
// If we're at the bottom of the tree, we need to explore the
|
||||
// element array
|
||||
if (is_leaf(current_tree_index))
|
||||
{
|
||||
|
||||
// Note: irange is [start,finish), so we need to +1 to make sure we visit the
|
||||
// last
|
||||
for (const auto current_child_index : child_indexes(current_tree_index))
|
||||
{
|
||||
const auto ¤t_edge = m_objects[current_child_index];
|
||||
|
||||
// we don't need to project the coordinates here,
|
||||
// because we use the unprojected rectangle to test against
|
||||
const Rectangle bbox{std::min(m_coordinate_list[current_edge.u].lon,
|
||||
m_coordinate_list[current_edge.v].lon),
|
||||
std::max(m_coordinate_list[current_edge.u].lon,
|
||||
m_coordinate_list[current_edge.v].lon),
|
||||
std::min(m_coordinate_list[current_edge.u].lat,
|
||||
m_coordinate_list[current_edge.v].lat),
|
||||
std::max(m_coordinate_list[current_edge.u].lat,
|
||||
m_coordinate_list[current_edge.v].lat)};
|
||||
|
||||
// use the _unprojected_ input rectangle here
|
||||
if (bbox.Intersects(search_rectangle))
|
||||
{
|
||||
callback(current_edge);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(current_tree_index.level + 1 < m_tree_level_starts.size());
|
||||
|
||||
for (const auto child_index : child_indexes(current_tree_index))
|
||||
{
|
||||
const auto &child_rectangle =
|
||||
m_search_tree[child_index].minimum_bounding_rectangle;
|
||||
|
||||
if (child_rectangle.Intersects(projected_rectangle))
|
||||
{
|
||||
traversal_queue.push(TreeIndex(
|
||||
current_tree_index.level + 1,
|
||||
child_index - m_tree_level_starts[current_tree_index.level + 1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over all the objects in a leaf node and inserts them into our
|
||||
* search priority queue. The speed of this function is very much governed
|
||||
|
||||
Reference in New Issue
Block a user