Implements Alternatives for MLD
This commit is contained in:
committed by
Patrick Niklaus
parent
fef0344be0
commit
54ceb05420
@@ -93,6 +93,9 @@ template <> struct HasGetTileTurns<corech::Algorithm> final : std::true_type
|
||||
};
|
||||
|
||||
// Algorithms supported by Multi-Level Dijkstra
|
||||
template <> struct HasAlternativePathSearch<mld::Algorithm> final : std::true_type
|
||||
{
|
||||
};
|
||||
template <> struct HasDirectShortestPathSearch<mld::Algorithm> final : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
@@ -89,8 +89,9 @@ struct RouteParameters : public BaseParameters
|
||||
const boost::optional<bool> continue_straight_,
|
||||
Args... args_)
|
||||
: BaseParameters{std::forward<Args>(args_)...}, steps{steps_}, alternatives{alternatives_},
|
||||
annotations{false}, annotations_type{AnnotationsType::None}, geometries{geometries_},
|
||||
overview{overview_}, continue_straight{continue_straight_}
|
||||
number_of_alternatives{alternatives_ ? 1u : 0u}, annotations{false},
|
||||
annotations_type{AnnotationsType::None}, geometries{geometries_}, overview{overview_},
|
||||
continue_straight{continue_straight_}
|
||||
// Once we perfectly-forward `args` (see #2990) this constructor can delegate to the one below.
|
||||
{
|
||||
}
|
||||
@@ -105,7 +106,7 @@ struct RouteParameters : public BaseParameters
|
||||
const boost::optional<bool> continue_straight_,
|
||||
Args... args_)
|
||||
: BaseParameters{std::forward<Args>(args_)...}, steps{steps_}, alternatives{alternatives_},
|
||||
annotations{annotations_},
|
||||
number_of_alternatives{alternatives_ ? 1u : 0u}, annotations{annotations_},
|
||||
annotations_type{annotations_ ? AnnotationsType::All : AnnotationsType::None},
|
||||
geometries{geometries_}, overview{overview_}, continue_straight{continue_straight_}
|
||||
{
|
||||
@@ -121,6 +122,7 @@ struct RouteParameters : public BaseParameters
|
||||
const boost::optional<bool> continue_straight_,
|
||||
Args... args_)
|
||||
: BaseParameters{std::forward<Args>(args_)...}, steps{steps_}, alternatives{alternatives_},
|
||||
number_of_alternatives{alternatives_ ? 1u : 0u},
|
||||
annotations{annotations_ == AnnotationsType::None ? false : true},
|
||||
annotations_type{annotations_}, geometries{geometries_}, overview{overview_},
|
||||
continue_straight{continue_straight_}
|
||||
@@ -128,14 +130,21 @@ struct RouteParameters : public BaseParameters
|
||||
}
|
||||
|
||||
bool steps = false;
|
||||
// TODO: in v6 we should remove the boolean and only keep the number parameter; for compat.
|
||||
bool alternatives = false;
|
||||
unsigned number_of_alternatives = 0;
|
||||
bool annotations = false;
|
||||
AnnotationsType annotations_type = AnnotationsType::None;
|
||||
GeometriesType geometries = GeometriesType::Polyline;
|
||||
OverviewType overview = OverviewType::Simplified;
|
||||
boost::optional<bool> continue_straight;
|
||||
|
||||
bool IsValid() const { return coordinates.size() >= 2 && BaseParameters::IsValid(); }
|
||||
bool IsValid() const
|
||||
{
|
||||
const auto coordinates_ok = coordinates.size() >= 2;
|
||||
const auto base_params_ok = BaseParameters::IsValid();
|
||||
return coordinates_ok && base_params_ok;
|
||||
}
|
||||
};
|
||||
|
||||
inline bool operator&(RouteParameters::AnnotationsType lhs, RouteParameters::AnnotationsType rhs)
|
||||
|
||||
@@ -53,12 +53,12 @@ template <typename Algorithm> class Engine final : public EngineInterface
|
||||
{
|
||||
public:
|
||||
explicit Engine(const EngineConfig &config)
|
||||
: route_plugin(config.max_locations_viaroute), //
|
||||
table_plugin(config.max_locations_distance_table), //
|
||||
nearest_plugin(config.max_results_nearest), //
|
||||
trip_plugin(config.max_locations_trip), //
|
||||
match_plugin(config.max_locations_map_matching), //
|
||||
tile_plugin() //
|
||||
: route_plugin(config.max_locations_viaroute, config.max_alternatives), //
|
||||
table_plugin(config.max_locations_distance_table), //
|
||||
nearest_plugin(config.max_results_nearest), //
|
||||
trip_plugin(config.max_locations_trip), //
|
||||
match_plugin(config.max_locations_map_matching), //
|
||||
tile_plugin() //
|
||||
|
||||
{
|
||||
if (config.use_shared_memory)
|
||||
|
||||
@@ -87,6 +87,7 @@ struct EngineConfig final
|
||||
int max_locations_distance_table = -1;
|
||||
int max_locations_map_matching = -1;
|
||||
int max_results_nearest = -1;
|
||||
int max_alternatives = 3; // set an arbitrary upper bound; can be adjusted by user
|
||||
bool use_shared_memory = true;
|
||||
Algorithm algorithm = Algorithm::CH;
|
||||
};
|
||||
|
||||
@@ -61,6 +61,18 @@ struct InternalRouteResult
|
||||
{
|
||||
return (leg != unpacked_path_segments.size() - 1);
|
||||
}
|
||||
|
||||
// Note: includes duration for turns, except for at start and end node.
|
||||
EdgeWeight duration() const
|
||||
{
|
||||
EdgeWeight ret{0};
|
||||
|
||||
for (const auto &leg : unpacked_path_segments)
|
||||
for (const auto &segment : leg)
|
||||
ret += segment.duration_until_turn;
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
struct InternalManyRoutesResult
|
||||
|
||||
@@ -27,9 +27,10 @@ class ViaRoutePlugin final : public BasePlugin
|
||||
{
|
||||
private:
|
||||
const int max_locations_viaroute;
|
||||
const int max_alternatives;
|
||||
|
||||
public:
|
||||
explicit ViaRoutePlugin(int max_locations_viaroute);
|
||||
explicit ViaRoutePlugin(int max_locations_viaroute, int max_alternatives);
|
||||
|
||||
Status HandleRequest(const datafacade::ContiguousInternalMemoryDataFacadeBase &facade,
|
||||
const RoutingAlgorithmsInterface &algorithms,
|
||||
|
||||
@@ -20,7 +20,8 @@ class RoutingAlgorithmsInterface
|
||||
{
|
||||
public:
|
||||
virtual InternalManyRoutesResult
|
||||
AlternativePathSearch(const PhantomNodes &phantom_node_pair) const = 0;
|
||||
AlternativePathSearch(const PhantomNodes &phantom_node_pair,
|
||||
unsigned number_of_alternatives) const = 0;
|
||||
|
||||
virtual InternalRouteResult
|
||||
ShortestPathSearch(const std::vector<PhantomNodes> &phantom_node_pair,
|
||||
@@ -66,7 +67,8 @@ template <typename Algorithm> class RoutingAlgorithms final : public RoutingAlgo
|
||||
virtual ~RoutingAlgorithms() = default;
|
||||
|
||||
InternalManyRoutesResult
|
||||
AlternativePathSearch(const PhantomNodes &phantom_node_pair) const final override;
|
||||
AlternativePathSearch(const PhantomNodes &phantom_node_pair,
|
||||
unsigned number_of_alternatives) const final override;
|
||||
|
||||
InternalRouteResult ShortestPathSearch(
|
||||
const std::vector<PhantomNodes> &phantom_node_pair,
|
||||
@@ -130,9 +132,11 @@ template <typename Algorithm> class RoutingAlgorithms final : public RoutingAlgo
|
||||
|
||||
template <typename Algorithm>
|
||||
InternalManyRoutesResult
|
||||
RoutingAlgorithms<Algorithm>::AlternativePathSearch(const PhantomNodes &phantom_node_pair) const
|
||||
RoutingAlgorithms<Algorithm>::AlternativePathSearch(const PhantomNodes &phantom_node_pair,
|
||||
unsigned number_of_alternatives) const
|
||||
{
|
||||
return routing_algorithms::ch::alternativePathSearch(heaps, facade, phantom_node_pair);
|
||||
return routing_algorithms::alternativePathSearch(
|
||||
heaps, facade, phantom_node_pair, number_of_alternatives);
|
||||
}
|
||||
|
||||
template <typename Algorithm>
|
||||
@@ -189,7 +193,8 @@ inline std::vector<routing_algorithms::TurnData> RoutingAlgorithms<Algorithm>::G
|
||||
// CoreCH overrides
|
||||
template <>
|
||||
InternalManyRoutesResult inline RoutingAlgorithms<
|
||||
routing_algorithms::corech::Algorithm>::AlternativePathSearch(const PhantomNodes &) const
|
||||
routing_algorithms::corech::Algorithm>::AlternativePathSearch(const PhantomNodes &,
|
||||
unsigned) const
|
||||
{
|
||||
throw util::exception("AlternativePathSearch is disabled due to performance reasons");
|
||||
}
|
||||
@@ -203,15 +208,7 @@ RoutingAlgorithms<routing_algorithms::corech::Algorithm>::ManyToManySearch(
|
||||
{
|
||||
throw util::exception("ManyToManySearch is disabled due to performance reasons");
|
||||
}
|
||||
|
||||
// MLD overrides for not implemented
|
||||
template <>
|
||||
InternalManyRoutesResult inline RoutingAlgorithms<
|
||||
routing_algorithms::mld::Algorithm>::AlternativePathSearch(const PhantomNodes &) const
|
||||
{
|
||||
throw util::exception("AlternativePathSearch is not implemented");
|
||||
}
|
||||
}
|
||||
}
|
||||
} // ns engine
|
||||
} // ns osrm
|
||||
|
||||
#endif
|
||||
|
||||
@@ -15,13 +15,19 @@ namespace engine
|
||||
{
|
||||
namespace routing_algorithms
|
||||
{
|
||||
namespace ch
|
||||
{
|
||||
|
||||
InternalManyRoutesResult
|
||||
alternativePathSearch(SearchEngineData<Algorithm> &search_engine_data,
|
||||
const datafacade::ContiguousInternalMemoryDataFacade<Algorithm> &facade,
|
||||
const PhantomNodes &phantom_node_pair);
|
||||
} // namespace ch
|
||||
alternativePathSearch(SearchEngineData<ch::Algorithm> &search_engine_data,
|
||||
const datafacade::ContiguousInternalMemoryDataFacade<ch::Algorithm> &facade,
|
||||
const PhantomNodes &phantom_node_pair,
|
||||
unsigned number_of_alternatives);
|
||||
|
||||
InternalManyRoutesResult
|
||||
alternativePathSearch(SearchEngineData<mld::Algorithm> &search_engine_data,
|
||||
const datafacade::ContiguousInternalMemoryDataFacade<mld::Algorithm> &facade,
|
||||
const PhantomNodes &phantom_node_pair,
|
||||
unsigned number_of_alternatives);
|
||||
|
||||
} // namespace routing_algorithms
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "engine/algorithm.hpp"
|
||||
#include "engine/datafacade/contiguous_internalmem_datafacade.hpp"
|
||||
#include "engine/internal_route_result.hpp"
|
||||
#include "engine/phantom_node.hpp"
|
||||
#include "engine/search_engine_data.hpp"
|
||||
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
@@ -38,9 +39,11 @@ static constexpr bool REVERSE_DIRECTION = false;
|
||||
static constexpr bool DO_NOT_FORCE_LOOPS = false;
|
||||
|
||||
bool needsLoopForward(const PhantomNode &source_phantom, const PhantomNode &target_phantom);
|
||||
|
||||
bool needsLoopBackwards(const PhantomNode &source_phantom, const PhantomNode &target_phantom);
|
||||
|
||||
bool needsLoopForward(const PhantomNodes &phantoms);
|
||||
bool needsLoopBackwards(const PhantomNodes &phantoms);
|
||||
|
||||
template <typename Heap>
|
||||
void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomNodes &nodes)
|
||||
{
|
||||
@@ -369,6 +372,39 @@ double getPathDistance(const datafacade::ContiguousInternalMemoryDataFacade<Algo
|
||||
return distance;
|
||||
}
|
||||
|
||||
template <typename AlgorithmT>
|
||||
InternalRouteResult
|
||||
extractRoute(const datafacade::ContiguousInternalMemoryDataFacade<AlgorithmT> &facade,
|
||||
const EdgeWeight weight,
|
||||
const PhantomNodes &phantom_nodes,
|
||||
const std::vector<NodeID> &unpacked_nodes,
|
||||
const std::vector<EdgeID> &unpacked_edges)
|
||||
{
|
||||
InternalRouteResult raw_route_data;
|
||||
raw_route_data.segment_end_coordinates = {phantom_nodes};
|
||||
|
||||
// No path found for both target nodes?
|
||||
if (INVALID_EDGE_WEIGHT == weight)
|
||||
{
|
||||
return raw_route_data;
|
||||
}
|
||||
|
||||
raw_route_data.shortest_path_weight = weight;
|
||||
raw_route_data.unpacked_path_segments.resize(1);
|
||||
raw_route_data.source_traversed_in_reverse.push_back(
|
||||
(unpacked_nodes.front() != phantom_nodes.source_phantom.forward_segment_id.id));
|
||||
raw_route_data.target_traversed_in_reverse.push_back(
|
||||
(unpacked_nodes.back() != phantom_nodes.target_phantom.forward_segment_id.id));
|
||||
|
||||
annotatePath(facade,
|
||||
phantom_nodes,
|
||||
unpacked_nodes,
|
||||
unpacked_edges,
|
||||
raw_route_data.unpacked_path_segments.front());
|
||||
|
||||
return raw_route_data;
|
||||
}
|
||||
|
||||
} // namespace routing_algorithms
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace engine
|
||||
@@ -24,7 +30,7 @@ namespace
|
||||
// Unrestricted search (Args is const PhantomNodes &):
|
||||
// * use partition.GetQueryLevel to find the node query level based on source and target phantoms
|
||||
// * allow to traverse all cells
|
||||
inline LevelID getNodeQureyLevel(const partition::MultiLevelPartitionView &partition,
|
||||
inline LevelID getNodeQueryLevel(const partition::MultiLevelPartitionView &partition,
|
||||
NodeID node,
|
||||
const PhantomNodes &phantom_nodes)
|
||||
{
|
||||
@@ -49,7 +55,7 @@ inline bool checkParentCellRestriction(CellID, const PhantomNodes &) { return tr
|
||||
// * use the fixed level for queries
|
||||
// * check if the node cell is the same as the specified parent onr
|
||||
inline LevelID
|
||||
getNodeQureyLevel(const partition::MultiLevelPartitionView &, NodeID, LevelID level, CellID)
|
||||
getNodeQueryLevel(const partition::MultiLevelPartitionView &, NodeID, LevelID level, CellID)
|
||||
{
|
||||
return level;
|
||||
}
|
||||
@@ -60,6 +66,70 @@ inline bool checkParentCellRestriction(CellID cell, LevelID, CellID parent)
|
||||
}
|
||||
}
|
||||
|
||||
// Heaps only record for each node its predecessor ("parent") on the shortest path.
|
||||
// For re-constructing the actual path we need to trace back all parent "pointers".
|
||||
// In contrast to the CH code MLD needs to know the edges (with clique arc property).
|
||||
|
||||
using PackedEdge = std::tuple</*from*/ NodeID, /*to*/ NodeID, /*from_clique_arc*/ bool>;
|
||||
using PackedPath = std::vector<PackedEdge>;
|
||||
|
||||
template <bool DIRECTION, typename OutIter>
|
||||
inline void retrievePackedPathFromSingleHeap(const SearchEngineData<Algorithm>::QueryHeap &heap,
|
||||
const NodeID middle,
|
||||
OutIter out)
|
||||
{
|
||||
NodeID current = middle;
|
||||
NodeID parent = heap.GetData(current).parent;
|
||||
|
||||
while (current != parent)
|
||||
{
|
||||
const auto &data = heap.GetData(current);
|
||||
|
||||
if (DIRECTION == FORWARD_DIRECTION)
|
||||
{
|
||||
*out = std::make_tuple(parent, current, data.from_clique_arc);
|
||||
++out;
|
||||
}
|
||||
else if (DIRECTION == REVERSE_DIRECTION)
|
||||
{
|
||||
*out = std::make_tuple(current, parent, data.from_clique_arc);
|
||||
++out;
|
||||
}
|
||||
|
||||
current = parent;
|
||||
parent = heap.GetData(parent).parent;
|
||||
}
|
||||
}
|
||||
|
||||
template <bool DIRECTION>
|
||||
inline PackedPath
|
||||
retrievePackedPathFromSingleHeap(const SearchEngineData<Algorithm>::QueryHeap &heap,
|
||||
const NodeID middle)
|
||||
{
|
||||
PackedPath packed_path;
|
||||
retrievePackedPathFromSingleHeap<DIRECTION>(heap, middle, std::back_inserter(packed_path));
|
||||
return packed_path;
|
||||
}
|
||||
|
||||
// Trace path from middle to start in the forward search space (in reverse)
|
||||
// and from middle to end in the reverse search space. Middle connects paths.
|
||||
|
||||
inline PackedPath
|
||||
retrievePackedPathFromHeap(const SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||
const SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
const NodeID middle)
|
||||
{
|
||||
// Retrieve start -> middle. Is in reverse order since tracing back starts from middle.
|
||||
auto packed_path = retrievePackedPathFromSingleHeap<FORWARD_DIRECTION>(forward_heap, middle);
|
||||
std::reverse(begin(packed_path), end(packed_path));
|
||||
|
||||
// Retrieve middle -> end. Is already in correct order, tracing starts from middle.
|
||||
auto into = std::back_inserter(packed_path);
|
||||
retrievePackedPathFromSingleHeap<REVERSE_DIRECTION>(reverse_heap, middle, into);
|
||||
|
||||
return packed_path;
|
||||
}
|
||||
|
||||
template <bool DIRECTION, typename... Args>
|
||||
void routingStep(const datafacade::ContiguousInternalMemoryDataFacade<Algorithm> &facade,
|
||||
SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||
@@ -96,7 +166,7 @@ void routingStep(const datafacade::ContiguousInternalMemoryDataFacade<Algorithm>
|
||||
}
|
||||
}
|
||||
|
||||
const auto level = getNodeQureyLevel(partition, node, args...);
|
||||
const auto level = getNodeQueryLevel(partition, node, args...);
|
||||
|
||||
if (level >= 1 && !forward_heap.GetData(node).from_clique_arc)
|
||||
{
|
||||
@@ -112,6 +182,7 @@ void routingStep(const datafacade::ContiguousInternalMemoryDataFacade<Algorithm>
|
||||
if (shortcut_weight != INVALID_EDGE_WEIGHT && node != to)
|
||||
{
|
||||
const EdgeWeight to_weight = weight + shortcut_weight;
|
||||
BOOST_ASSERT(to_weight >= weight);
|
||||
if (!forward_heap.WasInserted(to))
|
||||
{
|
||||
forward_heap.Insert(to, to_weight, {node, true});
|
||||
@@ -137,6 +208,7 @@ void routingStep(const datafacade::ContiguousInternalMemoryDataFacade<Algorithm>
|
||||
if (shortcut_weight != INVALID_EDGE_WEIGHT && node != to)
|
||||
{
|
||||
const EdgeWeight to_weight = weight + shortcut_weight;
|
||||
BOOST_ASSERT(to_weight >= weight);
|
||||
if (!forward_heap.WasInserted(to))
|
||||
{
|
||||
forward_heap.Insert(to, to_weight, {node, true});
|
||||
@@ -179,16 +251,24 @@ void routingStep(const datafacade::ContiguousInternalMemoryDataFacade<Algorithm>
|
||||
}
|
||||
}
|
||||
|
||||
// With (s, middle, t) we trace back the paths middle -> s and middle -> t.
|
||||
// This gives us a packed path (node ids) from the base graph around s and t,
|
||||
// and overlay node ids otherwise. We then have to unpack the overlay clique
|
||||
// edges by recursively descending unpacking the path down to the base graph.
|
||||
|
||||
using UnpackedNodes = std::vector<NodeID>;
|
||||
using UnpackedEdges = std::vector<EdgeID>;
|
||||
using UnpackedPath = std::tuple<EdgeWeight, UnpackedNodes, UnpackedEdges>;
|
||||
|
||||
template <typename... Args>
|
||||
std::tuple<EdgeWeight, std::vector<NodeID>, std::vector<EdgeID>>
|
||||
search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const datafacade::ContiguousInternalMemoryDataFacade<Algorithm> &facade,
|
||||
SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||
SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
const bool force_loop_forward,
|
||||
const bool force_loop_reverse,
|
||||
EdgeWeight weight_upper_bound,
|
||||
Args... args)
|
||||
UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const datafacade::ContiguousInternalMemoryDataFacade<Algorithm> &facade,
|
||||
SearchEngineData<Algorithm>::QueryHeap &forward_heap,
|
||||
SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
const bool force_loop_forward,
|
||||
const bool force_loop_reverse,
|
||||
EdgeWeight weight_upper_bound,
|
||||
Args... args)
|
||||
{
|
||||
if (forward_heap.Empty() || reverse_heap.Empty())
|
||||
{
|
||||
@@ -242,27 +322,12 @@ search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
return std::make_tuple(INVALID_EDGE_WEIGHT, std::vector<NodeID>(), std::vector<EdgeID>());
|
||||
}
|
||||
|
||||
// Get packed path as edges {from node ID, to node ID, edge ID}
|
||||
std::vector<std::tuple<NodeID, NodeID, bool>> packed_path;
|
||||
NodeID current_node = middle, parent_node = forward_heap.GetData(middle).parent;
|
||||
while (parent_node != current_node)
|
||||
{
|
||||
const auto &data = forward_heap.GetData(current_node);
|
||||
packed_path.push_back(std::make_tuple(parent_node, current_node, data.from_clique_arc));
|
||||
current_node = parent_node;
|
||||
parent_node = forward_heap.GetData(parent_node).parent;
|
||||
}
|
||||
std::reverse(std::begin(packed_path), std::end(packed_path));
|
||||
const NodeID source_node = current_node;
|
||||
// Get packed path as edges {from node ID, to node ID, from_clique_arc}
|
||||
auto packed_path = retrievePackedPathFromHeap(forward_heap, reverse_heap, middle);
|
||||
|
||||
current_node = middle, parent_node = reverse_heap.GetData(middle).parent;
|
||||
while (parent_node != current_node)
|
||||
{
|
||||
const auto &data = reverse_heap.GetData(current_node);
|
||||
packed_path.push_back(std::make_tuple(current_node, parent_node, data.from_clique_arc));
|
||||
current_node = parent_node;
|
||||
parent_node = reverse_heap.GetData(parent_node).parent;
|
||||
}
|
||||
// Beware the edge case when start, middle, end are all the same.
|
||||
// In this case we return a single node, no edges. We also don't unpack.
|
||||
const NodeID source_node = !packed_path.empty() ? std::get<0>(packed_path.front()) : middle;
|
||||
|
||||
// Unpack path
|
||||
std::vector<NodeID> unpacked_nodes;
|
||||
@@ -271,6 +336,7 @@ search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
unpacked_edges.reserve(packed_path.size());
|
||||
|
||||
unpacked_nodes.push_back(source_node);
|
||||
|
||||
for (auto const &packed_edge : packed_path)
|
||||
{
|
||||
NodeID source, target;
|
||||
@@ -283,7 +349,7 @@ search(SearchEngineData<Algorithm> &engine_working_data,
|
||||
}
|
||||
else
|
||||
{ // an overlay graph edge
|
||||
LevelID level = getNodeQureyLevel(partition, source, args...);
|
||||
LevelID level = getNodeQueryLevel(partition, source, args...);
|
||||
CellID parent_cell_id = partition.GetCell(level, source);
|
||||
BOOST_ASSERT(parent_cell_id == partition.GetCell(level, target));
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <algorithm>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/numeric/conversion/cast.hpp>
|
||||
#include <cstdint>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@@ -109,7 +110,6 @@ struct ProfileProperties
|
||||
std::array<char[MAX_CLASS_NAME_LENGTH + 1], MAX_CLASS_INDEX + 1> class_names;
|
||||
unsigned weight_precision = 1;
|
||||
bool force_split_edges = false;
|
||||
|
||||
bool call_tagless_node_function = true;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -703,7 +703,7 @@ argumentsToRouteParameter(const Nan::FunctionCallbackInfo<v8::Value> &args,
|
||||
|
||||
if (!value->IsBoolean() && !value->IsNull())
|
||||
{
|
||||
Nan::ThrowError("'continue_straight' parama must be boolean or null");
|
||||
Nan::ThrowError("'continue_straight' param must be boolean or null");
|
||||
return route_parameters_ptr();
|
||||
}
|
||||
if (value->IsBoolean())
|
||||
@@ -718,12 +718,21 @@ argumentsToRouteParameter(const Nan::FunctionCallbackInfo<v8::Value> &args,
|
||||
if (value.IsEmpty())
|
||||
return route_parameters_ptr();
|
||||
|
||||
if (!value->IsBoolean())
|
||||
if (value->IsBoolean())
|
||||
{
|
||||
Nan::ThrowError("'alternatives' parama must be boolean");
|
||||
params->alternatives = value->BooleanValue();
|
||||
params->number_of_alternatives = 1u;
|
||||
}
|
||||
else if (value->IsNumber())
|
||||
{
|
||||
params->alternatives = value->BooleanValue();
|
||||
params->number_of_alternatives = static_cast<unsigned>(value->NumberValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
Nan::ThrowError("'alternatives' param must be boolean or number");
|
||||
return route_parameters_ptr();
|
||||
}
|
||||
params->alternatives = value->BooleanValue();
|
||||
}
|
||||
|
||||
bool parsedSuccessfully = parseCommonParameters(obj, params);
|
||||
|
||||
@@ -30,7 +30,13 @@ struct RouteParametersGrammar : public BaseParametersGrammar<Iterator, Signature
|
||||
{
|
||||
route_rule =
|
||||
(qi::lit("alternatives=") >
|
||||
qi::bool_[ph::bind(&engine::api::RouteParameters::alternatives, qi::_r1) = qi::_1]) |
|
||||
(qi::uint_[ph::bind(&engine::api::RouteParameters::number_of_alternatives, qi::_r1) =
|
||||
qi::_1,
|
||||
ph::bind(&engine::api::RouteParameters::alternatives, qi::_r1) =
|
||||
qi::_1 > 0] |
|
||||
qi::bool_[ph::bind(&engine::api::RouteParameters::number_of_alternatives, qi::_r1) =
|
||||
qi::_1,
|
||||
ph::bind(&engine::api::RouteParameters::alternatives, qi::_r1) = qi::_1])) |
|
||||
(qi::lit("continue_straight=") >
|
||||
(qi::lit("default") |
|
||||
qi::bool_[ph::bind(&engine::api::RouteParameters::continue_straight, qi::_r1) =
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef OSRM_STATIC_ASSERT_HPP
|
||||
#define OSRM_STATIC_ASSERT_HPP
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
|
||||
template <typename It, typename Value> inline void static_assert_iter_value()
|
||||
{
|
||||
using IterValueType = typename std::iterator_traits<It>::value_type;
|
||||
static_assert(std::is_same<IterValueType, Value>::value, "");
|
||||
}
|
||||
|
||||
template <typename It, typename Category> inline void static_assert_iter_category()
|
||||
{
|
||||
using IterCategoryType = typename std::iterator_traits<It>::iterator_category;
|
||||
static_assert(std::is_base_of<Category, IterCategoryType>::value, "");
|
||||
}
|
||||
|
||||
} // ns util
|
||||
} // ns osrm
|
||||
|
||||
#endif // OSRM_STATIC_ASSERT_HPP
|
||||
Reference in New Issue
Block a user