Lifts restriction to only provide zero or one alternative routes

This commit is contained in:
Daniel J. Hofmann 2017-05-11 18:44:48 +02:00
parent e12c7756d9
commit e064a9334b
6 changed files with 76 additions and 54 deletions

View File

@ -41,27 +41,33 @@ class RouteAPI : public BaseAPI
{ {
} }
void MakeResponse(const InternalManyRoutesResult &raw_routes,
util::json::Object &response) const
{
BOOST_ASSERT(!raw_routes.routes.empty());
util::json::Array jsRoutes;
for (const auto &route : raw_routes.routes)
{
if (!route.is_valid())
continue;
jsRoutes.values.push_back(MakeRoute(route.segment_end_coordinates,
route.unpacked_path_segments,
route.source_traversed_in_reverse,
route.target_traversed_in_reverse));
}
response.values["waypoints"] =
BaseAPI::MakeWaypoints(raw_routes.routes[0].segment_end_coordinates);
response.values["routes"] = std::move(jsRoutes);
response.values["code"] = "Ok";
}
void MakeResponse(const InternalRouteResult &raw_route, util::json::Object &response) const void MakeResponse(const InternalRouteResult &raw_route, util::json::Object &response) const
{ {
auto number_of_routes = raw_route.has_alternative() ? 2UL : 1UL; return MakeResponse(raw_route, response);
util::json::Array routes;
routes.values.resize(number_of_routes);
routes.values[0] = MakeRoute(raw_route.segment_end_coordinates,
raw_route.unpacked_path_segments,
raw_route.source_traversed_in_reverse,
raw_route.target_traversed_in_reverse);
if (raw_route.has_alternative())
{
std::vector<std::vector<PathData>> wrapped_leg(1);
wrapped_leg.front() = std::move(raw_route.unpacked_alternative);
routes.values[1] = MakeRoute(raw_route.segment_end_coordinates,
wrapped_leg,
raw_route.alt_source_traversed_in_reverse,
raw_route.alt_target_traversed_in_reverse);
}
response.values["waypoints"] = BaseAPI::MakeWaypoints(raw_route.segment_end_coordinates);
response.values["routes"] = std::move(routes);
response.values["code"] = "Ok";
} }
protected: protected:

View File

@ -47,24 +47,29 @@ struct PathData
struct InternalRouteResult struct InternalRouteResult
{ {
std::vector<std::vector<PathData>> unpacked_path_segments; std::vector<std::vector<PathData>> unpacked_path_segments;
std::vector<PathData> unpacked_alternative;
std::vector<PhantomNodes> segment_end_coordinates; std::vector<PhantomNodes> segment_end_coordinates;
std::vector<bool> source_traversed_in_reverse; std::vector<bool> source_traversed_in_reverse;
std::vector<bool> target_traversed_in_reverse; std::vector<bool> target_traversed_in_reverse;
std::vector<bool> alt_source_traversed_in_reverse;
std::vector<bool> alt_target_traversed_in_reverse;
EdgeWeight shortest_path_weight = INVALID_EDGE_WEIGHT; EdgeWeight shortest_path_weight = INVALID_EDGE_WEIGHT;
EdgeWeight alternative_path_weight = INVALID_EDGE_WEIGHT;
bool is_valid() const { return INVALID_EDGE_WEIGHT != shortest_path_weight; } bool is_valid() const { return INVALID_EDGE_WEIGHT != shortest_path_weight; }
bool has_alternative() const { return INVALID_EDGE_WEIGHT != alternative_path_weight; }
bool is_via_leg(const std::size_t leg) const bool is_via_leg(const std::size_t leg) const
{ {
return (leg != unpacked_path_segments.size() - 1); return (leg != unpacked_path_segments.size() - 1);
} }
}; };
struct InternalManyRoutesResult
{
InternalManyRoutesResult() = default;
InternalManyRoutesResult(InternalRouteResult route) : routes{std::move(route)} {}
InternalManyRoutesResult(std::vector<InternalRouteResult> routes_) : routes{std::move(routes_)}
{
}
std::vector<InternalRouteResult> routes;
};
} }
} }

View File

@ -19,7 +19,7 @@ namespace engine
class RoutingAlgorithmsInterface class RoutingAlgorithmsInterface
{ {
public: public:
virtual InternalRouteResult virtual InternalManyRoutesResult
AlternativePathSearch(const PhantomNodes &phantom_node_pair) const = 0; AlternativePathSearch(const PhantomNodes &phantom_node_pair) const = 0;
virtual InternalRouteResult virtual InternalRouteResult
@ -65,7 +65,7 @@ template <typename Algorithm> class RoutingAlgorithms final : public RoutingAlgo
virtual ~RoutingAlgorithms() = default; virtual ~RoutingAlgorithms() = default;
InternalRouteResult InternalManyRoutesResult
AlternativePathSearch(const PhantomNodes &phantom_node_pair) const final override; AlternativePathSearch(const PhantomNodes &phantom_node_pair) const final override;
InternalRouteResult ShortestPathSearch( InternalRouteResult ShortestPathSearch(
@ -129,7 +129,7 @@ template <typename Algorithm> class RoutingAlgorithms final : public RoutingAlgo
}; };
template <typename Algorithm> template <typename Algorithm>
InternalRouteResult InternalManyRoutesResult
RoutingAlgorithms<Algorithm>::AlternativePathSearch(const PhantomNodes &phantom_node_pair) const RoutingAlgorithms<Algorithm>::AlternativePathSearch(const PhantomNodes &phantom_node_pair) const
{ {
return routing_algorithms::ch::alternativePathSearch(heaps, facade, phantom_node_pair); return routing_algorithms::ch::alternativePathSearch(heaps, facade, phantom_node_pair);
@ -188,7 +188,7 @@ inline std::vector<routing_algorithms::TurnData> RoutingAlgorithms<Algorithm>::G
// CoreCH overrides // CoreCH overrides
template <> template <>
InternalRouteResult inline RoutingAlgorithms< InternalManyRoutesResult inline RoutingAlgorithms<
routing_algorithms::corech::Algorithm>::AlternativePathSearch(const PhantomNodes &) const routing_algorithms::corech::Algorithm>::AlternativePathSearch(const PhantomNodes &) const
{ {
throw util::exception("AlternativePathSearch is disabled due to performance reasons"); throw util::exception("AlternativePathSearch is disabled due to performance reasons");
@ -206,7 +206,7 @@ RoutingAlgorithms<routing_algorithms::corech::Algorithm>::ManyToManySearch(
// MLD overrides for not implemented // MLD overrides for not implemented
template <> template <>
InternalRouteResult inline RoutingAlgorithms< InternalManyRoutesResult inline RoutingAlgorithms<
routing_algorithms::mld::Algorithm>::AlternativePathSearch(const PhantomNodes &) const routing_algorithms::mld::Algorithm>::AlternativePathSearch(const PhantomNodes &) const
{ {
throw util::exception("AlternativePathSearch is not implemented"); throw util::exception("AlternativePathSearch is not implemented");

View File

@ -17,7 +17,7 @@ namespace routing_algorithms
{ {
namespace ch namespace ch
{ {
InternalRouteResult InternalManyRoutesResult
alternativePathSearch(SearchEngineData<Algorithm> &search_engine_data, alternativePathSearch(SearchEngineData<Algorithm> &search_engine_data,
const datafacade::ContiguousInternalMemoryDataFacade<Algorithm> &facade, const datafacade::ContiguousInternalMemoryDataFacade<Algorithm> &facade,
const PhantomNodes &phantom_node_pair); const PhantomNodes &phantom_node_pair);

View File

@ -84,28 +84,34 @@ ViaRoutePlugin::HandleRequest(const datafacade::ContiguousInternalMemoryDataFaca
}; };
util::for_each_pair(snapped_phantoms, build_phantom_pairs); util::for_each_pair(snapped_phantoms, build_phantom_pairs);
InternalRouteResult raw_route; api::RouteAPI route_api{facade, route_parameters};
InternalManyRoutesResult routes;
// Alternatives do not support vias, only direct s,t queries supported
// See the implementation notes and high-level outline.
// https://github.com/Project-OSRM/osrm-backend/issues/3905
if (1 == start_end_nodes.size() && algorithms.HasAlternativePathSearch() && if (1 == start_end_nodes.size() && algorithms.HasAlternativePathSearch() &&
route_parameters.alternatives) route_parameters.alternatives)
{ {
raw_route = algorithms.AlternativePathSearch(start_end_nodes.front()); routes = algorithms.AlternativePathSearch(start_end_nodes.front());
} }
else if (1 == start_end_nodes.size() && algorithms.HasDirectShortestPathSearch()) else if (1 == start_end_nodes.size() && algorithms.HasDirectShortestPathSearch())
{ {
raw_route = algorithms.DirectShortestPathSearch(start_end_nodes.front()); routes = algorithms.DirectShortestPathSearch(start_end_nodes.front());
} }
else else
{ {
raw_route = routes = algorithms.ShortestPathSearch(start_end_nodes, route_parameters.continue_straight);
algorithms.ShortestPathSearch(start_end_nodes, route_parameters.continue_straight);
} }
// we can only know this after the fact, different SCC ids still // we can only know this after the fact, different SCC ids still
// allow for connection in one direction. // allow for connection in one direction.
if (raw_route.is_valid()) BOOST_ASSERT(!routes.routes.empty());
if (routes.routes[0].is_valid())
{ {
api::RouteAPI route_api{facade, route_parameters}; route_api.MakeResponse(routes, json_result);
route_api.MakeResponse(raw_route, json_result);
} }
else else
{ {

View File

@ -563,13 +563,17 @@ bool viaNodeCandidatePassesTTest(
} }
} }
InternalRouteResult InternalManyRoutesResult
alternativePathSearch(SearchEngineData<Algorithm> &engine_working_data, alternativePathSearch(SearchEngineData<Algorithm> &engine_working_data,
const datafacade::ContiguousInternalMemoryDataFacade<Algorithm> &facade, const datafacade::ContiguousInternalMemoryDataFacade<Algorithm> &facade,
const PhantomNodes &phantom_node_pair) const PhantomNodes &phantom_node_pair)
{ {
InternalRouteResult raw_route_data; InternalRouteResult primary_route;
raw_route_data.segment_end_coordinates = {phantom_node_pair}; InternalRouteResult secondary_route;
primary_route.segment_end_coordinates = {phantom_node_pair};
secondary_route.segment_end_coordinates = {phantom_node_pair};
std::vector<NodeID> alternative_path; std::vector<NodeID> alternative_path;
std::vector<NodeID> via_node_candidate_list; std::vector<NodeID> via_node_candidate_list;
std::vector<SearchSpaceEdge> forward_search_space; std::vector<SearchSpaceEdge> forward_search_space;
@ -626,7 +630,7 @@ alternativePathSearch(SearchEngineData<Algorithm> &engine_working_data,
if (INVALID_EDGE_WEIGHT == upper_bound_to_shortest_path_weight) if (INVALID_EDGE_WEIGHT == upper_bound_to_shortest_path_weight)
{ {
return raw_route_data; return InternalManyRoutesResult{std::move(primary_route)};
} }
std::sort(begin(via_node_candidate_list), end(via_node_candidate_list)); std::sort(begin(via_node_candidate_list), end(via_node_candidate_list));
@ -795,11 +799,11 @@ alternativePathSearch(SearchEngineData<Algorithm> &engine_working_data,
if (INVALID_EDGE_WEIGHT != upper_bound_to_shortest_path_weight) if (INVALID_EDGE_WEIGHT != upper_bound_to_shortest_path_weight)
{ {
BOOST_ASSERT(!packed_shortest_path.empty()); BOOST_ASSERT(!packed_shortest_path.empty());
raw_route_data.unpacked_path_segments.resize(1); primary_route.unpacked_path_segments.resize(1);
raw_route_data.source_traversed_in_reverse.push_back( primary_route.source_traversed_in_reverse.push_back(
(packed_shortest_path.front() != (packed_shortest_path.front() !=
phantom_node_pair.source_phantom.forward_segment_id.id)); phantom_node_pair.source_phantom.forward_segment_id.id));
raw_route_data.target_traversed_in_reverse.push_back(( primary_route.target_traversed_in_reverse.push_back((
packed_shortest_path.back() != phantom_node_pair.target_phantom.forward_segment_id.id)); packed_shortest_path.back() != phantom_node_pair.target_phantom.forward_segment_id.id));
ch::unpackPath(facade, ch::unpackPath(facade,
@ -809,8 +813,8 @@ alternativePathSearch(SearchEngineData<Algorithm> &engine_working_data,
// -- start of route // -- start of route
phantom_node_pair, phantom_node_pair,
// -- unpacked output // -- unpacked output
raw_route_data.unpacked_path_segments.front()); primary_route.unpacked_path_segments.front());
raw_route_data.shortest_path_weight = upper_bound_to_shortest_path_weight; primary_route.shortest_path_weight = upper_bound_to_shortest_path_weight;
} }
if (SPECIAL_NODEID != selected_via_node) if (SPECIAL_NODEID != selected_via_node)
@ -825,10 +829,11 @@ alternativePathSearch(SearchEngineData<Algorithm> &engine_working_data,
v_t_middle, v_t_middle,
packed_alternate_path); packed_alternate_path);
raw_route_data.alt_source_traversed_in_reverse.push_back( secondary_route.unpacked_path_segments.resize(1);
secondary_route.source_traversed_in_reverse.push_back(
(packed_alternate_path.front() != (packed_alternate_path.front() !=
phantom_node_pair.source_phantom.forward_segment_id.id)); phantom_node_pair.source_phantom.forward_segment_id.id));
raw_route_data.alt_target_traversed_in_reverse.push_back( secondary_route.target_traversed_in_reverse.push_back(
(packed_alternate_path.back() != (packed_alternate_path.back() !=
phantom_node_pair.target_phantom.forward_segment_id.id)); phantom_node_pair.target_phantom.forward_segment_id.id));
@ -837,16 +842,16 @@ alternativePathSearch(SearchEngineData<Algorithm> &engine_working_data,
packed_alternate_path.begin(), packed_alternate_path.begin(),
packed_alternate_path.end(), packed_alternate_path.end(),
phantom_node_pair, phantom_node_pair,
raw_route_data.unpacked_alternative); secondary_route.unpacked_path_segments.front());
raw_route_data.alternative_path_weight = weight_of_via_path; secondary_route.shortest_path_weight = weight_of_via_path;
} }
else else
{ {
BOOST_ASSERT(raw_route_data.alternative_path_weight == INVALID_EDGE_WEIGHT); BOOST_ASSERT(secondary_route.shortest_path_weight == INVALID_EDGE_WEIGHT);
} }
return raw_route_data; return InternalManyRoutesResult{{std::move(primary_route), std::move(secondary_route)}};
} }
} // namespace ch } // namespace ch