Support snapping to multiple ways at an input location (#5953)
This PR improves routing results by adding support for snapping to multiple ways at input locations. This means all edges at the snapped location can act as source/target candidates for routing search, ensuring we always find the best route, and not the one dependent on the edge selected.
This commit is contained in:
@@ -239,10 +239,10 @@ makeWaypoint(const util::Coordinate &location, const double &distance, std::stri
|
||||
util::json::Object makeWaypoint(const util::Coordinate &location,
|
||||
const double &distance,
|
||||
std::string name,
|
||||
const Hint &hint)
|
||||
const Hint &location_hints)
|
||||
{
|
||||
auto waypoint = makeWaypoint(location, distance, std::move(name));
|
||||
waypoint.values["hint"] = hint.ToBase64();
|
||||
waypoint.values["hint"] = location_hints.ToBase64();
|
||||
return waypoint;
|
||||
}
|
||||
|
||||
|
||||
+76
-9
@@ -3,10 +3,10 @@
|
||||
#include "engine/datafacade/datafacade_base.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <ostream>
|
||||
#include <tuple>
|
||||
|
||||
namespace osrm
|
||||
@@ -14,8 +14,8 @@ namespace osrm
|
||||
namespace engine
|
||||
{
|
||||
|
||||
bool Hint::IsValid(const util::Coordinate new_input_coordinates,
|
||||
const datafacade::BaseDataFacade &facade) const
|
||||
bool SegmentHint::IsValid(const util::Coordinate new_input_coordinates,
|
||||
const datafacade::BaseDataFacade &facade) const
|
||||
{
|
||||
auto is_same_input_coordinate = new_input_coordinates.lon == phantom.input_location.lon &&
|
||||
new_input_coordinates.lat == phantom.input_location.lat;
|
||||
@@ -25,7 +25,7 @@ bool Hint::IsValid(const util::Coordinate new_input_coordinates,
|
||||
return is_same_input_coordinate && phantom.IsValid() && facade.GetCheckSum() == data_checksum;
|
||||
}
|
||||
|
||||
std::string Hint::ToBase64() const
|
||||
std::string SegmentHint::ToBase64() const
|
||||
{
|
||||
auto base64 = encodeBase64Bytewise(*this);
|
||||
|
||||
@@ -36,9 +36,9 @@ std::string Hint::ToBase64() const
|
||||
return base64;
|
||||
}
|
||||
|
||||
Hint Hint::FromBase64(const std::string &base64Hint)
|
||||
SegmentHint SegmentHint::FromBase64(const std::string &base64Hint)
|
||||
{
|
||||
BOOST_ASSERT_MSG(base64Hint.size() == ENCODED_HINT_SIZE, "Hint has invalid size");
|
||||
BOOST_ASSERT_MSG(base64Hint.size() == ENCODED_SEGMENT_HINT_SIZE, "Hint has invalid size");
|
||||
|
||||
// We need mutability but don't want to change the API
|
||||
auto encoded = base64Hint;
|
||||
@@ -47,15 +47,82 @@ Hint Hint::FromBase64(const std::string &base64Hint)
|
||||
std::replace(begin(encoded), end(encoded), '-', '+');
|
||||
std::replace(begin(encoded), end(encoded), '_', '/');
|
||||
|
||||
return decodeBase64Bytewise<Hint>(encoded);
|
||||
return decodeBase64Bytewise<SegmentHint>(encoded);
|
||||
}
|
||||
|
||||
bool operator==(const Hint &lhs, const Hint &rhs)
|
||||
bool operator==(const SegmentHint &lhs, const SegmentHint &rhs)
|
||||
{
|
||||
return std::tie(lhs.phantom, lhs.data_checksum) == std::tie(rhs.phantom, rhs.data_checksum);
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const Hint &hint) { return out << hint.ToBase64(); }
|
||||
bool operator!=(const SegmentHint &lhs, const SegmentHint &rhs) { return !(lhs == rhs); }
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const SegmentHint &hint)
|
||||
{
|
||||
return out << hint.ToBase64();
|
||||
}
|
||||
|
||||
std::string Hint::ToBase64() const
|
||||
{
|
||||
std::string res;
|
||||
for (const auto &hint : segment_hints)
|
||||
{
|
||||
res += hint.ToBase64();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
Hint Hint::FromBase64(const std::string &base64Hint)
|
||||
{
|
||||
|
||||
BOOST_ASSERT_MSG(base64Hint.size() % ENCODED_SEGMENT_HINT_SIZE == 0,
|
||||
"SegmentHint has invalid size");
|
||||
|
||||
auto num_hints = base64Hint.size() / ENCODED_SEGMENT_HINT_SIZE;
|
||||
std::vector<SegmentHint> res(num_hints);
|
||||
|
||||
for (const auto i : util::irange<std::size_t>(0UL, num_hints))
|
||||
{
|
||||
auto start_offset = i * ENCODED_SEGMENT_HINT_SIZE;
|
||||
auto end_offset = start_offset + ENCODED_SEGMENT_HINT_SIZE;
|
||||
res[i] = SegmentHint::FromBase64(
|
||||
std::string(base64Hint.begin() + start_offset, base64Hint.begin() + end_offset));
|
||||
}
|
||||
|
||||
return {std::move(res)};
|
||||
}
|
||||
|
||||
bool Hint::IsValid(const util::Coordinate new_input_coordinates,
|
||||
const datafacade::BaseDataFacade &facade) const
|
||||
{
|
||||
const auto all_valid =
|
||||
std::all_of(segment_hints.begin(), segment_hints.end(), [&](const auto &seg_hint) {
|
||||
return seg_hint.IsValid(new_input_coordinates, facade);
|
||||
});
|
||||
if (!all_valid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check hints do not contain duplicate segment pairs
|
||||
// We can't allow duplicates as search heaps do not support it.
|
||||
boost::unordered_set<NodeID> forward_segments;
|
||||
boost::unordered_set<NodeID> reverse_segments;
|
||||
for (const auto &seg_hint : segment_hints)
|
||||
{
|
||||
const auto forward_res = forward_segments.insert(seg_hint.phantom.forward_segment_id.id);
|
||||
if (!forward_res.second)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const auto backward_res = reverse_segments.insert(seg_hint.phantom.reverse_segment_id.id);
|
||||
if (!backward_res.second)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace engine
|
||||
} // namespace osrm
|
||||
|
||||
@@ -4,21 +4,16 @@
|
||||
#include "engine/api/match_api.hpp"
|
||||
#include "engine/api/match_parameters.hpp"
|
||||
#include "engine/api/match_parameters_tidy.hpp"
|
||||
#include "engine/map_matching/bayes_classifier.hpp"
|
||||
#include "engine/map_matching/sub_matching.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
#include "util/integer_range.hpp"
|
||||
#include "util/json_util.hpp"
|
||||
#include "util/string_util.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
@@ -28,7 +23,7 @@ namespace engine
|
||||
namespace plugins
|
||||
{
|
||||
|
||||
// Filters PhantomNodes to obtain a set of viable candiates
|
||||
// Filters PhantomNodes to obtain a set of viable candidates
|
||||
void filterCandidates(const std::vector<util::Coordinate> &coordinates,
|
||||
MatchPlugin::CandidateLists &candidates_lists)
|
||||
{
|
||||
@@ -272,20 +267,26 @@ Status MatchPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
||||
|
||||
// FIXME we only run this to obtain the geometry
|
||||
// The clean way would be to get this directly from the map matching plugin
|
||||
PhantomNodes current_phantom_node_pair;
|
||||
for (unsigned i = 0; i < sub_matchings[index].nodes.size() - 1; ++i)
|
||||
{
|
||||
current_phantom_node_pair.source_phantom = sub_matchings[index].nodes[i];
|
||||
current_phantom_node_pair.target_phantom = sub_matchings[index].nodes[i + 1];
|
||||
BOOST_ASSERT(current_phantom_node_pair.source_phantom.IsValid());
|
||||
BOOST_ASSERT(current_phantom_node_pair.target_phantom.IsValid());
|
||||
sub_routes[index].segment_end_coordinates.emplace_back(current_phantom_node_pair);
|
||||
PhantomEndpoints current_endpoints{sub_matchings[index].nodes[i],
|
||||
sub_matchings[index].nodes[i + 1]};
|
||||
BOOST_ASSERT(current_endpoints.source_phantom.IsValid());
|
||||
BOOST_ASSERT(current_endpoints.target_phantom.IsValid());
|
||||
sub_routes[index].leg_endpoints.push_back(current_endpoints);
|
||||
}
|
||||
|
||||
std::vector<PhantomNodeCandidates> waypoint_candidates;
|
||||
waypoint_candidates.reserve(sub_matchings[index].nodes.size());
|
||||
std::transform(sub_matchings[index].nodes.begin(),
|
||||
sub_matchings[index].nodes.end(),
|
||||
std::back_inserter(waypoint_candidates),
|
||||
[](const auto &phantom) { return PhantomNodeCandidates{phantom}; });
|
||||
|
||||
// force uturns to be on
|
||||
// we split the phantom nodes anyway and only have bi-directional phantom nodes for
|
||||
// possible uturns
|
||||
sub_routes[index] =
|
||||
algorithms.ShortestPathSearch(sub_routes[index].segment_end_coordinates, {false});
|
||||
sub_routes[index] = algorithms.ShortestPathSearch(waypoint_candidates, {false});
|
||||
BOOST_ASSERT(sub_routes[index].shortest_path_weight != INVALID_EDGE_WEIGHT);
|
||||
if (collapse_legs)
|
||||
{
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
#include "engine/plugins/nearest.hpp"
|
||||
#include "engine/api/nearest_api.hpp"
|
||||
#include "engine/api/nearest_parameters.hpp"
|
||||
#include "engine/phantom_node.hpp"
|
||||
#include "util/integer_range.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
@@ -2,17 +2,11 @@
|
||||
|
||||
#include "engine/api/table_api.hpp"
|
||||
#include "engine/api/table_parameters.hpp"
|
||||
#include "engine/routing_algorithms/many_to_many.hpp"
|
||||
#include "engine/search_engine_data.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
#include "util/json_container.hpp"
|
||||
#include "util/string_util.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
@@ -47,7 +41,7 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
||||
return Error("InvalidOptions", "Coordinates are invalid", result);
|
||||
}
|
||||
|
||||
if (params.bearings.size() > 0 && params.coordinates.size() != params.bearings.size())
|
||||
if (!params.bearings.empty() && params.coordinates.size() != params.bearings.size())
|
||||
{
|
||||
return Error(
|
||||
"InvalidOptions", "Number of bearings does not match number of coordinates", result);
|
||||
@@ -79,7 +73,7 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
||||
"NoSegment", MissingPhantomErrorMessage(phantom_nodes, params.coordinates), result);
|
||||
}
|
||||
|
||||
auto snapped_phantoms = SnapPhantomNodes(phantom_nodes);
|
||||
auto snapped_phantoms = SnapPhantomNodes(std::move(phantom_nodes));
|
||||
|
||||
bool request_distance = params.annotations & api::TableParameters::AnnotationsType::Distance;
|
||||
bool request_duration = params.annotations & api::TableParameters::AnnotationsType::Duration;
|
||||
@@ -117,9 +111,11 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
||||
params.fallback_coordinate_type ==
|
||||
api::TableParameters::FallbackCoordinateType::Input
|
||||
? util::coordinate_calculation::greatCircleDistance(
|
||||
source.input_location, destination.input_location)
|
||||
candidatesInputLocation(source),
|
||||
candidatesInputLocation(destination))
|
||||
: util::coordinate_calculation::greatCircleDistance(
|
||||
source.location, destination.location);
|
||||
candidatesSnappedLocation(source),
|
||||
candidatesSnappedLocation(destination));
|
||||
|
||||
result_tables_pair.first[table_index] =
|
||||
distance_estimate / (double)params.fallback_speed;
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
|
||||
+17
-30
@@ -4,18 +4,12 @@
|
||||
#include "engine/api/trip_parameters.hpp"
|
||||
#include "engine/trip/trip_brute_force.hpp"
|
||||
#include "engine/trip/trip_farthest_insertion.hpp"
|
||||
#include "engine/trip/trip_nearest_neighbour.hpp"
|
||||
#include "util/dist_table_wrapper.hpp" // to access the dist table more easily
|
||||
#include "util/json_container.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -41,40 +35,33 @@ bool IsSupportedParameterCombination(const bool fixed_start,
|
||||
|
||||
// given the node order in which to visit, compute the actual route (with geometry, travel time and
|
||||
// so on) and return the result
|
||||
InternalRouteResult TripPlugin::ComputeRoute(const RoutingAlgorithmsInterface &algorithms,
|
||||
const std::vector<PhantomNode> &snapped_phantoms,
|
||||
const std::vector<NodeID> &trip,
|
||||
const bool roundtrip) const
|
||||
InternalRouteResult
|
||||
TripPlugin::ComputeRoute(const RoutingAlgorithmsInterface &algorithms,
|
||||
const std::vector<PhantomNodeCandidates> &waypoint_candidates,
|
||||
const std::vector<NodeID> &trip,
|
||||
const bool roundtrip) const
|
||||
{
|
||||
InternalRouteResult min_route;
|
||||
// given the final trip, compute total duration and return the route and location permutation
|
||||
PhantomNodes viapoint;
|
||||
|
||||
// computes a roundtrip from the nodes in trip
|
||||
for (auto node = trip.begin(); node < trip.end() - 1; ++node)
|
||||
{
|
||||
const auto from_node = *node;
|
||||
const auto to_node = *std::next(node);
|
||||
|
||||
viapoint = PhantomNodes{snapped_phantoms[from_node], snapped_phantoms[to_node]};
|
||||
min_route.segment_end_coordinates.emplace_back(viapoint);
|
||||
}
|
||||
|
||||
// TODO make a more efficient solution that doesn't require copying all the waypoints vectors.
|
||||
std::vector<PhantomNodeCandidates> trip_candidates;
|
||||
std::transform(trip.begin(),
|
||||
trip.end(),
|
||||
std::back_inserter(trip_candidates),
|
||||
[&](const auto &node) { return waypoint_candidates[node]; });
|
||||
// return back to the first node if it is a round trip
|
||||
if (roundtrip)
|
||||
{
|
||||
viapoint = PhantomNodes{snapped_phantoms[trip.back()], snapped_phantoms[trip.front()]};
|
||||
min_route.segment_end_coordinates.emplace_back(viapoint);
|
||||
trip_candidates.push_back(waypoint_candidates[trip.front()]);
|
||||
// trip comes out to be something like 0 1 4 3 2 0
|
||||
BOOST_ASSERT(min_route.segment_end_coordinates.size() == trip.size());
|
||||
BOOST_ASSERT(trip_candidates.size() == trip.size() + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// trip comes out to be something like 0 1 4 3 2, so the sizes don't match
|
||||
BOOST_ASSERT(min_route.segment_end_coordinates.size() == trip.size() - 1);
|
||||
// trip comes out to be something like 0 1 4 3 2
|
||||
BOOST_ASSERT(trip_candidates.size() == trip.size());
|
||||
}
|
||||
|
||||
min_route = algorithms.ShortestPathSearch(min_route.segment_end_coordinates, {false});
|
||||
auto min_route = algorithms.ShortestPathSearch(trip_candidates, {false});
|
||||
BOOST_ASSERT_MSG(min_route.shortest_path_weight < INVALID_EDGE_WEIGHT, "unroutable route");
|
||||
return min_route;
|
||||
}
|
||||
@@ -226,7 +213,7 @@ Status TripPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
|
||||
return Error("InvalidValue", "Invalid source or destination value.", result);
|
||||
}
|
||||
|
||||
auto snapped_phantoms = SnapPhantomNodes(phantom_node_pairs);
|
||||
auto snapped_phantoms = SnapPhantomNodes(std::move(phantom_node_pairs));
|
||||
|
||||
BOOST_ASSERT(snapped_phantoms.size() == number_of_locations);
|
||||
|
||||
|
||||
@@ -5,12 +5,10 @@
|
||||
|
||||
#include "util/for_each_pair.hpp"
|
||||
#include "util/integer_range.hpp"
|
||||
#include "util/json_container.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -95,19 +93,10 @@ Status ViaRoutePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithm
|
||||
}
|
||||
BOOST_ASSERT(phantom_node_pairs.size() == route_parameters.coordinates.size());
|
||||
|
||||
auto snapped_phantoms = SnapPhantomNodes(phantom_node_pairs);
|
||||
|
||||
std::vector<PhantomNodes> start_end_nodes;
|
||||
auto build_phantom_pairs = [&start_end_nodes](const PhantomNode &first_node,
|
||||
const PhantomNode &second_node) {
|
||||
start_end_nodes.push_back(PhantomNodes{first_node, second_node});
|
||||
};
|
||||
util::for_each_pair(snapped_phantoms, build_phantom_pairs);
|
||||
auto snapped_phantoms = SnapPhantomNodes(std::move(phantom_node_pairs));
|
||||
|
||||
api::RouteAPI route_api{facade, route_parameters};
|
||||
|
||||
InternalManyRoutesResult routes;
|
||||
|
||||
// TODO: in v6 we should remove the boolean and only keep the number parameter.
|
||||
// For now just force them to be in sync. and keep backwards compatibility.
|
||||
const auto wants_alternatives =
|
||||
@@ -115,20 +104,23 @@ Status ViaRoutePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithm
|
||||
(route_parameters.alternatives || route_parameters.number_of_alternatives > 0);
|
||||
const auto number_of_alternatives = std::max(1u, route_parameters.number_of_alternatives);
|
||||
|
||||
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() && wants_alternatives)
|
||||
if (2 == snapped_phantoms.size() && algorithms.HasAlternativePathSearch() && wants_alternatives)
|
||||
{
|
||||
routes = algorithms.AlternativePathSearch(start_end_nodes.front(), number_of_alternatives);
|
||||
routes = algorithms.AlternativePathSearch({snapped_phantoms[0], snapped_phantoms[1]},
|
||||
number_of_alternatives);
|
||||
}
|
||||
else if (1 == start_end_nodes.size() && algorithms.HasDirectShortestPathSearch())
|
||||
else if (2 == snapped_phantoms.size() && algorithms.HasDirectShortestPathSearch())
|
||||
{
|
||||
routes = algorithms.DirectShortestPathSearch(start_end_nodes.front());
|
||||
routes = algorithms.DirectShortestPathSearch({snapped_phantoms[0], snapped_phantoms[1]});
|
||||
}
|
||||
else
|
||||
{
|
||||
routes = algorithms.ShortestPathSearch(start_end_nodes, route_parameters.continue_straight);
|
||||
routes =
|
||||
algorithms.ShortestPathSearch(snapped_phantoms, route_parameters.continue_straight);
|
||||
}
|
||||
|
||||
// The post condition for all path searches is we have at least one route in our result.
|
||||
@@ -160,18 +152,29 @@ Status ViaRoutePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithm
|
||||
}
|
||||
}
|
||||
|
||||
route_api.MakeResponse(routes, start_end_nodes, result);
|
||||
route_api.MakeResponse(routes, snapped_phantoms, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto first_component_id = snapped_phantoms.front().component.id;
|
||||
auto not_in_same_component = std::any_of(snapped_phantoms.begin(),
|
||||
snapped_phantoms.end(),
|
||||
[first_component_id](const PhantomNode &node) {
|
||||
return node.component.id != first_component_id;
|
||||
});
|
||||
const auto all_in_same_component =
|
||||
[](const std::vector<PhantomNodeCandidates> &waypoint_candidates) {
|
||||
return std::any_of(waypoint_candidates.front().begin(),
|
||||
waypoint_candidates.front().end(),
|
||||
// For each of the first possible phantoms, check if all other
|
||||
// positions in the list have a phantom from the same component.
|
||||
[&](const PhantomNode &phantom) {
|
||||
const auto component_id = phantom.component.id;
|
||||
return std::all_of(
|
||||
std::next(waypoint_candidates.begin()),
|
||||
std::end(waypoint_candidates),
|
||||
[component_id](const PhantomNodeCandidates &candidates) {
|
||||
return candidatesHaveComponent(candidates,
|
||||
component_id);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
if (not_in_same_component)
|
||||
if (!all_in_same_component(snapped_phantoms))
|
||||
{
|
||||
return Error("NoRoute", "Impossible route between points", result);
|
||||
}
|
||||
|
||||
@@ -190,8 +190,8 @@ void computeWeightAndSharingOfViaPath(SearchEngineData<Algorithm> &engine_workin
|
||||
s_v_middle,
|
||||
upper_bound_s_v_path_weight,
|
||||
min_edge_offset,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS);
|
||||
{},
|
||||
{});
|
||||
}
|
||||
// compute path <v,..,t> by reusing backward search from node t
|
||||
NodeID v_t_middle = SPECIAL_NODEID;
|
||||
@@ -205,8 +205,8 @@ void computeWeightAndSharingOfViaPath(SearchEngineData<Algorithm> &engine_workin
|
||||
v_t_middle,
|
||||
upper_bound_of_v_t_path_weight,
|
||||
min_edge_offset,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS);
|
||||
{},
|
||||
{});
|
||||
}
|
||||
*real_weight_of_via_path = upper_bound_s_v_path_weight + upper_bound_of_v_t_path_weight;
|
||||
|
||||
@@ -351,8 +351,8 @@ bool viaNodeCandidatePassesTTest(SearchEngineData<Algorithm> &engine_working_dat
|
||||
*s_v_middle,
|
||||
upper_bound_s_v_path_weight,
|
||||
min_edge_offset,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS);
|
||||
{},
|
||||
{});
|
||||
}
|
||||
|
||||
if (INVALID_EDGE_WEIGHT == upper_bound_s_v_path_weight)
|
||||
@@ -372,8 +372,8 @@ bool viaNodeCandidatePassesTTest(SearchEngineData<Algorithm> &engine_working_dat
|
||||
*v_t_middle,
|
||||
upper_bound_of_v_t_path_weight,
|
||||
min_edge_offset,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS);
|
||||
{},
|
||||
{});
|
||||
}
|
||||
|
||||
if (INVALID_EDGE_WEIGHT == upper_bound_of_v_t_path_weight)
|
||||
@@ -539,25 +539,13 @@ bool viaNodeCandidatePassesTTest(SearchEngineData<Algorithm> &engine_working_dat
|
||||
{
|
||||
if (!forward_heap3.Empty())
|
||||
{
|
||||
routingStep<FORWARD_DIRECTION>(facade,
|
||||
forward_heap3,
|
||||
reverse_heap3,
|
||||
middle,
|
||||
upper_bound,
|
||||
min_edge_offset,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS);
|
||||
routingStep<FORWARD_DIRECTION>(
|
||||
facade, forward_heap3, reverse_heap3, middle, upper_bound, min_edge_offset, {}, {});
|
||||
}
|
||||
if (!reverse_heap3.Empty())
|
||||
{
|
||||
routingStep<REVERSE_DIRECTION>(facade,
|
||||
reverse_heap3,
|
||||
forward_heap3,
|
||||
middle,
|
||||
upper_bound,
|
||||
min_edge_offset,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS);
|
||||
routingStep<REVERSE_DIRECTION>(
|
||||
facade, reverse_heap3, forward_heap3, middle, upper_bound, min_edge_offset, {}, {});
|
||||
}
|
||||
}
|
||||
return (upper_bound <= t_test_path_weight);
|
||||
@@ -566,15 +554,12 @@ bool viaNodeCandidatePassesTTest(SearchEngineData<Algorithm> &engine_working_dat
|
||||
|
||||
InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
const PhantomNodes &phantom_node_pair,
|
||||
const PhantomEndpointCandidates &endpoint_candidates,
|
||||
unsigned /*number_of_alternatives*/)
|
||||
{
|
||||
InternalRouteResult primary_route;
|
||||
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> via_node_candidate_list;
|
||||
std::vector<SearchSpaceEdge> forward_search_space;
|
||||
@@ -592,15 +577,13 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engi
|
||||
|
||||
EdgeWeight upper_bound_to_shortest_path_weight = INVALID_EDGE_WEIGHT;
|
||||
NodeID middle_node = SPECIAL_NODEID;
|
||||
const EdgeWeight min_edge_offset =
|
||||
std::min(phantom_node_pair.source_phantom.forward_segment_id.enabled
|
||||
? -phantom_node_pair.source_phantom.GetForwardWeightPlusOffset()
|
||||
: 0,
|
||||
phantom_node_pair.source_phantom.reverse_segment_id.enabled
|
||||
? -phantom_node_pair.source_phantom.GetReverseWeightPlusOffset()
|
||||
: 0);
|
||||
|
||||
insertNodesInHeaps(forward_heap1, reverse_heap1, phantom_node_pair);
|
||||
insertNodesInHeaps(forward_heap1, reverse_heap1, endpoint_candidates);
|
||||
// get offset to account for offsets on phantom nodes on compressed edges
|
||||
EdgeWeight min_edge_offset = forward_heap1.Empty() ? 0 : std::min(0, forward_heap1.MinKey());
|
||||
BOOST_ASSERT(min_edge_offset <= 0);
|
||||
// we only every insert negative offsets for nodes in the forward heap
|
||||
BOOST_ASSERT(reverse_heap1.Empty() || reverse_heap1.MinKey() >= 0);
|
||||
|
||||
// search from s and t till new_min/(1+epsilon) > weight_of_shortest_path
|
||||
while (0 < (forward_heap1.Size() + reverse_heap1.Size()))
|
||||
@@ -790,7 +773,7 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engi
|
||||
&v_t_middle,
|
||||
min_edge_offset))
|
||||
{
|
||||
// select first admissable
|
||||
// select first admissible
|
||||
selected_via_node = candidate.node;
|
||||
break;
|
||||
}
|
||||
@@ -799,20 +782,23 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engi
|
||||
// Unpack shortest path and alternative, if they exist
|
||||
if (INVALID_EDGE_WEIGHT != upper_bound_to_shortest_path_weight)
|
||||
{
|
||||
auto phantom_endpoints = endpointsFromCandidates(endpoint_candidates, packed_shortest_path);
|
||||
primary_route.leg_endpoints = {phantom_endpoints};
|
||||
|
||||
BOOST_ASSERT(!packed_shortest_path.empty());
|
||||
primary_route.unpacked_path_segments.resize(1);
|
||||
primary_route.source_traversed_in_reverse.push_back(
|
||||
(packed_shortest_path.front() !=
|
||||
phantom_node_pair.source_phantom.forward_segment_id.id));
|
||||
phantom_endpoints.source_phantom.forward_segment_id.id));
|
||||
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_endpoints.target_phantom.forward_segment_id.id));
|
||||
|
||||
unpackPath(facade,
|
||||
// -- packed input
|
||||
packed_shortest_path.begin(),
|
||||
packed_shortest_path.end(),
|
||||
// -- start of route
|
||||
phantom_node_pair,
|
||||
phantom_endpoints,
|
||||
// -- unpacked output
|
||||
primary_route.unpacked_path_segments.front());
|
||||
primary_route.shortest_path_weight = upper_bound_to_shortest_path_weight;
|
||||
@@ -830,19 +816,23 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &engi
|
||||
v_t_middle,
|
||||
packed_alternate_path);
|
||||
|
||||
auto phantom_endpoints =
|
||||
endpointsFromCandidates(endpoint_candidates, packed_alternate_path);
|
||||
secondary_route.leg_endpoints = {phantom_endpoints};
|
||||
|
||||
secondary_route.unpacked_path_segments.resize(1);
|
||||
secondary_route.source_traversed_in_reverse.push_back(
|
||||
(packed_alternate_path.front() !=
|
||||
phantom_node_pair.source_phantom.forward_segment_id.id));
|
||||
phantom_endpoints.source_phantom.forward_segment_id.id));
|
||||
secondary_route.target_traversed_in_reverse.push_back(
|
||||
(packed_alternate_path.back() !=
|
||||
phantom_node_pair.target_phantom.forward_segment_id.id));
|
||||
phantom_endpoints.target_phantom.forward_segment_id.id));
|
||||
|
||||
// unpack the alternate path
|
||||
unpackPath(facade,
|
||||
packed_alternate_path.begin(),
|
||||
packed_alternate_path.end(),
|
||||
phantom_node_pair,
|
||||
phantom_endpoints,
|
||||
secondary_route.unpacked_path_segments.front());
|
||||
|
||||
secondary_route.shortest_path_weight = weight_of_via_path;
|
||||
|
||||
@@ -133,12 +133,13 @@ double getLongerByFactorBasedOnDuration(const EdgeWeight duration)
|
||||
return a + b / (duration - d) + c / std::pow(duration - d, 3);
|
||||
}
|
||||
|
||||
Parameters parametersFromRequest(const PhantomNodes &phantom_node_pair)
|
||||
Parameters parametersFromRequest(const PhantomEndpointCandidates &endpoint_candidates)
|
||||
{
|
||||
Parameters parameters;
|
||||
|
||||
const auto distance = util::coordinate_calculation::greatCircleDistance(
|
||||
phantom_node_pair.source_phantom.location, phantom_node_pair.target_phantom.location);
|
||||
candidatesSnappedLocation(endpoint_candidates.source_phantoms),
|
||||
candidatesSnappedLocation(endpoint_candidates.target_phantoms));
|
||||
|
||||
// 10km
|
||||
if (distance < 10000.)
|
||||
@@ -547,7 +548,7 @@ void unpackPackedPaths(InputIt first,
|
||||
OutIt out,
|
||||
SearchEngineData<Algorithm> &search_engine_data,
|
||||
const Facade &facade,
|
||||
const PhantomNodes &phantom_node_pair)
|
||||
const PhantomEndpointCandidates &endpoint_candidates)
|
||||
{
|
||||
util::static_assert_iter_category<InputIt, std::input_iterator_tag>();
|
||||
util::static_assert_iter_category<OutIt, std::output_iterator_tag>();
|
||||
@@ -600,7 +601,7 @@ void unpackPackedPaths(InputIt first,
|
||||
}
|
||||
else
|
||||
{ // an overlay graph edge
|
||||
LevelID level = getNodeQueryLevel(partition, source, phantom_node_pair); // XXX
|
||||
LevelID level = getNodeQueryLevel(partition, source, endpoint_candidates); // XXX
|
||||
CellID parent_cell_id = partition.GetCell(level, source);
|
||||
BOOST_ASSERT(parent_cell_id == partition.GetCell(level, target));
|
||||
|
||||
@@ -624,8 +625,8 @@ void unpackPackedPaths(InputIt first,
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
{},
|
||||
{},
|
||||
INVALID_EDGE_WEIGHT,
|
||||
sublevel,
|
||||
parent_cell_id);
|
||||
@@ -656,13 +657,13 @@ void unpackPackedPaths(InputIt first,
|
||||
inline std::vector<WeightedViaNode>
|
||||
makeCandidateVias(SearchEngineData<Algorithm> &search_engine_data,
|
||||
const Facade &facade,
|
||||
const PhantomNodes &phantom_node_pair,
|
||||
const PhantomEndpointCandidates &endpoint_candidates,
|
||||
const Parameters ¶meters)
|
||||
{
|
||||
Heap &forward_heap = *search_engine_data.forward_heap_1;
|
||||
Heap &reverse_heap = *search_engine_data.reverse_heap_1;
|
||||
|
||||
insertNodesInHeaps(forward_heap, reverse_heap, phantom_node_pair);
|
||||
insertNodesInHeaps(forward_heap, reverse_heap, endpoint_candidates);
|
||||
if (forward_heap.Empty() || reverse_heap.Empty())
|
||||
{
|
||||
return {};
|
||||
@@ -712,9 +713,9 @@ makeCandidateVias(SearchEngineData<Algorithm> &search_engine_data,
|
||||
reverse_heap,
|
||||
overlap_via,
|
||||
overlap_weight,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
phantom_node_pair);
|
||||
{},
|
||||
{},
|
||||
endpoint_candidates);
|
||||
|
||||
if (!forward_heap.Empty())
|
||||
forward_heap_min = forward_heap.MinKey();
|
||||
@@ -738,9 +739,9 @@ makeCandidateVias(SearchEngineData<Algorithm> &search_engine_data,
|
||||
forward_heap,
|
||||
overlap_via,
|
||||
overlap_weight,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
phantom_node_pair);
|
||||
{},
|
||||
{},
|
||||
endpoint_candidates);
|
||||
|
||||
if (!reverse_heap.Empty())
|
||||
reverse_heap_min = reverse_heap.MinKey();
|
||||
@@ -776,10 +777,10 @@ makeCandidateVias(SearchEngineData<Algorithm> &search_engine_data,
|
||||
// https://github.com/Project-OSRM/osrm-backend/issues/3905
|
||||
InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &search_engine_data,
|
||||
const Facade &facade,
|
||||
const PhantomNodes &phantom_node_pair,
|
||||
const PhantomEndpointCandidates &endpoint_candidates,
|
||||
unsigned number_of_alternatives)
|
||||
{
|
||||
Parameters parameters = parametersFromRequest(phantom_node_pair);
|
||||
Parameters parameters = parametersFromRequest(endpoint_candidates);
|
||||
|
||||
const auto max_number_of_alternatives = number_of_alternatives;
|
||||
const auto max_number_of_alternatives_to_unpack =
|
||||
@@ -798,7 +799,7 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
|
||||
|
||||
// Do forward and backward search, save search space overlap as via candidates.
|
||||
auto candidate_vias =
|
||||
makeCandidateVias(search_engine_data, facade, phantom_node_pair, parameters);
|
||||
makeCandidateVias(search_engine_data, facade, endpoint_candidates, parameters);
|
||||
|
||||
const auto by_weight = [](const auto &lhs, const auto &rhs) { return lhs.weight < rhs.weight; };
|
||||
auto shortest_path_via_it =
|
||||
@@ -813,8 +814,6 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
|
||||
if (!has_shortest_path)
|
||||
{
|
||||
InternalRouteResult invalid;
|
||||
invalid.shortest_path_weight = INVALID_EDGE_WEIGHT;
|
||||
invalid.segment_end_coordinates = {phantom_node_pair};
|
||||
return invalid;
|
||||
}
|
||||
|
||||
@@ -900,7 +899,7 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
|
||||
std::back_inserter(unpacked_paths),
|
||||
search_engine_data,
|
||||
facade,
|
||||
phantom_node_pair);
|
||||
endpoint_candidates);
|
||||
|
||||
//
|
||||
// Filter and rank a second time. This time instead of being fast and doing
|
||||
@@ -927,7 +926,7 @@ InternalManyRoutesResult alternativePathSearch(SearchEngineData<Algorithm> &sear
|
||||
routes.reserve(number_of_unpacked_paths);
|
||||
|
||||
const auto unpacked_path_to_route = [&](const WeightedViaNodeUnpackedPath &path) {
|
||||
return extractRoute(facade, path.via.weight, phantom_node_pair, path.nodes, path.edges);
|
||||
return extractRoute(facade, path.via.weight, endpoint_candidates, path.nodes, path.edges);
|
||||
};
|
||||
|
||||
std::transform(unpacked_paths_first,
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace routing_algorithms
|
||||
template <>
|
||||
InternalRouteResult directShortestPathSearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
||||
const DataFacade<ch::Algorithm> &facade,
|
||||
const PhantomNodes &phantom_nodes)
|
||||
const PhantomEndpointCandidates &endpoint_candidates)
|
||||
{
|
||||
engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes());
|
||||
auto &forward_heap = *engine_working_data.forward_heap_1;
|
||||
@@ -29,7 +29,7 @@ InternalRouteResult directShortestPathSearch(SearchEngineData<ch::Algorithm> &en
|
||||
|
||||
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
||||
std::vector<NodeID> packed_leg;
|
||||
insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes);
|
||||
insertNodesInHeaps(forward_heap, reverse_heap, endpoint_candidates);
|
||||
|
||||
search(engine_working_data,
|
||||
facade,
|
||||
@@ -37,9 +37,9 @@ InternalRouteResult directShortestPathSearch(SearchEngineData<ch::Algorithm> &en
|
||||
reverse_heap,
|
||||
weight,
|
||||
packed_leg,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
phantom_nodes);
|
||||
{},
|
||||
{},
|
||||
endpoint_candidates);
|
||||
|
||||
std::vector<NodeID> unpacked_nodes;
|
||||
std::vector<EdgeID> unpacked_edges;
|
||||
@@ -60,19 +60,19 @@ InternalRouteResult directShortestPathSearch(SearchEngineData<ch::Algorithm> &en
|
||||
});
|
||||
}
|
||||
|
||||
return extractRoute(facade, weight, phantom_nodes, unpacked_nodes, unpacked_edges);
|
||||
return extractRoute(facade, weight, endpoint_candidates, unpacked_nodes, unpacked_edges);
|
||||
}
|
||||
|
||||
template <>
|
||||
InternalRouteResult directShortestPathSearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
||||
const DataFacade<mld::Algorithm> &facade,
|
||||
const PhantomNodes &phantom_nodes)
|
||||
const PhantomEndpointCandidates &endpoint_candidates)
|
||||
{
|
||||
engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes(),
|
||||
facade.GetMaxBorderNodeID() + 1);
|
||||
auto &forward_heap = *engine_working_data.forward_heap_1;
|
||||
auto &reverse_heap = *engine_working_data.reverse_heap_1;
|
||||
insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes);
|
||||
insertNodesInHeaps(forward_heap, reverse_heap, endpoint_candidates);
|
||||
|
||||
// TODO: when structured bindings will be allowed change to
|
||||
// auto [weight, source_node, target_node, unpacked_edges] = ...
|
||||
@@ -83,12 +83,12 @@ InternalRouteResult directShortestPathSearch(SearchEngineData<mld::Algorithm> &e
|
||||
facade,
|
||||
forward_heap,
|
||||
reverse_heap,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
{},
|
||||
{},
|
||||
INVALID_EDGE_WEIGHT,
|
||||
phantom_nodes);
|
||||
endpoint_candidates);
|
||||
|
||||
return extractRoute(facade, weight, phantom_nodes, unpacked_nodes, unpacked_edges);
|
||||
return extractRoute(facade, weight, endpoint_candidates, unpacked_nodes, unpacked_edges);
|
||||
}
|
||||
|
||||
} // namespace routing_algorithms
|
||||
|
||||
@@ -49,7 +49,7 @@ void relaxOutgoingEdges(
|
||||
const DataFacade<Algorithm> &facade,
|
||||
const typename SearchEngineData<Algorithm>::ManyToManyQueryHeap::HeapNode &heapNode,
|
||||
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
|
||||
const PhantomNode &)
|
||||
const PhantomNodeCandidates &)
|
||||
{
|
||||
if (stallAtNode<DIRECTION>(facade, heapNode, query_heap))
|
||||
{
|
||||
@@ -99,7 +99,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
std::vector<EdgeDuration> &durations_table,
|
||||
std::vector<EdgeDistance> &distances_table,
|
||||
std::vector<NodeID> &middle_nodes_table,
|
||||
const PhantomNode &phantom_node)
|
||||
const PhantomNodeCandidates &candidates)
|
||||
{
|
||||
// Take a copy of the extracted node because otherwise could be modified later if toHeapNode is
|
||||
// the same
|
||||
@@ -151,14 +151,14 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
}
|
||||
}
|
||||
|
||||
relaxOutgoingEdges<FORWARD_DIRECTION>(facade, heapNode, query_heap, phantom_node);
|
||||
relaxOutgoingEdges<FORWARD_DIRECTION>(facade, heapNode, query_heap, candidates);
|
||||
}
|
||||
|
||||
void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
const unsigned column_index,
|
||||
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
|
||||
std::vector<NodeBucket> &search_space_with_buckets,
|
||||
const PhantomNode &phantom_node)
|
||||
const PhantomNodeCandidates &candidates)
|
||||
{
|
||||
// Take a copy (no ref &) of the extracted node because otherwise could be modified later if
|
||||
// toHeapNode is the same
|
||||
@@ -172,7 +172,7 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
heapNode.data.duration,
|
||||
heapNode.data.distance);
|
||||
|
||||
relaxOutgoingEdges<REVERSE_DIRECTION>(facade, heapNode, query_heap, phantom_node);
|
||||
relaxOutgoingEdges<REVERSE_DIRECTION>(facade, heapNode, query_heap, candidates);
|
||||
}
|
||||
|
||||
} // namespace ch
|
||||
@@ -181,7 +181,7 @@ template <>
|
||||
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||
manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
||||
const DataFacade<ch::Algorithm> &facade,
|
||||
const std::vector<PhantomNode> &phantom_nodes,
|
||||
const std::vector<PhantomNodeCandidates> &candidates_list,
|
||||
const std::vector<std::size_t> &source_indices,
|
||||
const std::vector<std::size_t> &target_indices,
|
||||
const bool calculate_distance)
|
||||
@@ -202,18 +202,18 @@ manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
||||
for (std::uint32_t column_index = 0; column_index < target_indices.size(); ++column_index)
|
||||
{
|
||||
const auto index = target_indices[column_index];
|
||||
const auto &phantom = phantom_nodes[index];
|
||||
const auto &target_candidates = candidates_list[index];
|
||||
|
||||
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
|
||||
facade.GetNumberOfNodes());
|
||||
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
||||
insertTargetInHeap(query_heap, phantom);
|
||||
insertTargetInHeap(query_heap, target_candidates);
|
||||
|
||||
// Explore search space
|
||||
while (!query_heap.Empty())
|
||||
{
|
||||
backwardRoutingStep(
|
||||
facade, column_index, query_heap, search_space_with_buckets, phantom);
|
||||
facade, column_index, query_heap, search_space_with_buckets, target_candidates);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,13 +224,13 @@ manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
||||
for (std::uint32_t row_index = 0; row_index < source_indices.size(); ++row_index)
|
||||
{
|
||||
const auto source_index = source_indices[row_index];
|
||||
const auto &source_phantom = phantom_nodes[source_index];
|
||||
const auto &source_candidates = candidates_list[source_index];
|
||||
|
||||
// Clear heap and insert source nodes
|
||||
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
|
||||
facade.GetNumberOfNodes());
|
||||
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
||||
insertSourceInHeap(query_heap, source_phantom);
|
||||
insertSourceInHeap(query_heap, source_candidates);
|
||||
|
||||
// Explore search space
|
||||
while (!query_heap.Empty())
|
||||
@@ -244,7 +244,7 @@ manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
||||
durations_table,
|
||||
distances_table,
|
||||
middle_nodes_table,
|
||||
source_phantom);
|
||||
source_candidates);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ using PackedPath = std::vector<PackedEdge>;
|
||||
template <typename MultiLevelPartition>
|
||||
inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
|
||||
const NodeID node,
|
||||
const PhantomNode &phantom_node,
|
||||
const PhantomNodeCandidates &phantom_node,
|
||||
const LevelID maximal_level)
|
||||
{
|
||||
const auto node_level = getNodeQueryLevel(partition, node, phantom_node);
|
||||
@@ -96,7 +96,7 @@ void relaxOutgoingEdges(
|
||||
const DataFacade<mld::Algorithm> &facade,
|
||||
const typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap::HeapNode &heapNode,
|
||||
typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &query_heap,
|
||||
Args... args)
|
||||
const Args &... args)
|
||||
{
|
||||
BOOST_ASSERT(!facade.ExcludeNode(heapNode.node));
|
||||
|
||||
@@ -214,59 +214,63 @@ template <bool DIRECTION>
|
||||
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||
oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
const std::vector<PhantomNode> &phantom_nodes,
|
||||
std::size_t phantom_index,
|
||||
const std::vector<std::size_t> &phantom_indices,
|
||||
const std::vector<PhantomNodeCandidates> &candidates_list,
|
||||
std::size_t source_index,
|
||||
const std::vector<std::size_t> &target_indices,
|
||||
const bool calculate_distance)
|
||||
{
|
||||
std::vector<EdgeWeight> weights_table(phantom_indices.size(), INVALID_EDGE_WEIGHT);
|
||||
std::vector<EdgeDuration> durations_table(phantom_indices.size(), MAXIMAL_EDGE_DURATION);
|
||||
std::vector<EdgeDistance> distances_table(calculate_distance ? phantom_indices.size() : 0,
|
||||
std::vector<EdgeWeight> weights_table(target_indices.size(), INVALID_EDGE_WEIGHT);
|
||||
std::vector<EdgeDuration> durations_table(target_indices.size(), MAXIMAL_EDGE_DURATION);
|
||||
std::vector<EdgeDistance> distances_table(calculate_distance ? target_indices.size() : 0,
|
||||
MAXIMAL_EDGE_DISTANCE);
|
||||
std::vector<NodeID> middle_nodes_table(phantom_indices.size(), SPECIAL_NODEID);
|
||||
std::vector<NodeID> middle_nodes_table(target_indices.size(), SPECIAL_NODEID);
|
||||
|
||||
// Collect destination (source) nodes into a map
|
||||
std::unordered_multimap<NodeID, std::tuple<std::size_t, EdgeWeight, EdgeDuration, EdgeDistance>>
|
||||
target_nodes_index;
|
||||
target_nodes_index.reserve(phantom_indices.size());
|
||||
for (std::size_t index = 0; index < phantom_indices.size(); ++index)
|
||||
target_nodes_index.reserve(target_indices.size());
|
||||
for (std::size_t index = 0; index < target_indices.size(); ++index)
|
||||
{
|
||||
const auto &phantom_index = phantom_indices[index];
|
||||
const auto &phantom_node = phantom_nodes[phantom_index];
|
||||
const auto &target_candidates = candidates_list[target_indices[index]];
|
||||
|
||||
if (DIRECTION == FORWARD_DIRECTION)
|
||||
for (const auto &phantom_node : target_candidates)
|
||||
{
|
||||
if (phantom_node.IsValidForwardTarget())
|
||||
target_nodes_index.insert(
|
||||
{phantom_node.forward_segment_id.id,
|
||||
std::make_tuple(index,
|
||||
phantom_node.GetForwardWeightPlusOffset(),
|
||||
phantom_node.GetForwardDuration(),
|
||||
phantom_node.GetForwardDistance())});
|
||||
if (phantom_node.IsValidReverseTarget())
|
||||
target_nodes_index.insert(
|
||||
{phantom_node.reverse_segment_id.id,
|
||||
std::make_tuple(index,
|
||||
phantom_node.GetReverseWeightPlusOffset(),
|
||||
phantom_node.GetReverseDuration(),
|
||||
phantom_node.GetReverseDistance())});
|
||||
}
|
||||
else if (DIRECTION == REVERSE_DIRECTION)
|
||||
{
|
||||
if (phantom_node.IsValidForwardSource())
|
||||
target_nodes_index.insert(
|
||||
{phantom_node.forward_segment_id.id,
|
||||
std::make_tuple(index,
|
||||
-phantom_node.GetForwardWeightPlusOffset(),
|
||||
-phantom_node.GetForwardDuration(),
|
||||
-phantom_node.GetForwardDistance())});
|
||||
if (phantom_node.IsValidReverseSource())
|
||||
target_nodes_index.insert(
|
||||
{phantom_node.reverse_segment_id.id,
|
||||
std::make_tuple(index,
|
||||
-phantom_node.GetReverseWeightPlusOffset(),
|
||||
-phantom_node.GetReverseDuration(),
|
||||
-phantom_node.GetReverseDistance())});
|
||||
if (DIRECTION == FORWARD_DIRECTION)
|
||||
{
|
||||
if (phantom_node.IsValidForwardTarget())
|
||||
target_nodes_index.insert(
|
||||
{phantom_node.forward_segment_id.id,
|
||||
std::make_tuple(index,
|
||||
phantom_node.GetForwardWeightPlusOffset(),
|
||||
phantom_node.GetForwardDuration(),
|
||||
phantom_node.GetForwardDistance())});
|
||||
|
||||
if (phantom_node.IsValidReverseTarget())
|
||||
target_nodes_index.insert(
|
||||
{phantom_node.reverse_segment_id.id,
|
||||
std::make_tuple(index,
|
||||
phantom_node.GetReverseWeightPlusOffset(),
|
||||
phantom_node.GetReverseDuration(),
|
||||
phantom_node.GetReverseDistance())});
|
||||
}
|
||||
else if (DIRECTION == REVERSE_DIRECTION)
|
||||
{
|
||||
if (phantom_node.IsValidForwardSource())
|
||||
target_nodes_index.insert(
|
||||
{phantom_node.forward_segment_id.id,
|
||||
std::make_tuple(index,
|
||||
-phantom_node.GetForwardWeightPlusOffset(),
|
||||
-phantom_node.GetForwardDuration(),
|
||||
-phantom_node.GetForwardDistance())});
|
||||
|
||||
if (phantom_node.IsValidReverseSource())
|
||||
target_nodes_index.insert(
|
||||
{phantom_node.reverse_segment_id.id,
|
||||
std::make_tuple(index,
|
||||
-phantom_node.GetReverseWeightPlusOffset(),
|
||||
-phantom_node.GetReverseDuration(),
|
||||
-phantom_node.GetReverseDistance())});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,42 +341,45 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
};
|
||||
|
||||
{ // Place source (destination) adjacent nodes into the heap
|
||||
const auto &phantom_node = phantom_nodes[phantom_index];
|
||||
const auto &source_candidates = candidates_list[source_index];
|
||||
|
||||
if (DIRECTION == FORWARD_DIRECTION)
|
||||
for (const auto &phantom_node : source_candidates)
|
||||
{
|
||||
if (phantom_node.IsValidForwardSource())
|
||||
if (DIRECTION == FORWARD_DIRECTION)
|
||||
{
|
||||
insert_node(phantom_node.forward_segment_id.id,
|
||||
-phantom_node.GetForwardWeightPlusOffset(),
|
||||
-phantom_node.GetForwardDuration(),
|
||||
-phantom_node.GetForwardDistance());
|
||||
}
|
||||
if (phantom_node.IsValidForwardSource())
|
||||
{
|
||||
insert_node(phantom_node.forward_segment_id.id,
|
||||
-phantom_node.GetForwardWeightPlusOffset(),
|
||||
-phantom_node.GetForwardDuration(),
|
||||
-phantom_node.GetForwardDistance());
|
||||
}
|
||||
|
||||
if (phantom_node.IsValidReverseSource())
|
||||
{
|
||||
insert_node(phantom_node.reverse_segment_id.id,
|
||||
-phantom_node.GetReverseWeightPlusOffset(),
|
||||
-phantom_node.GetReverseDuration(),
|
||||
-phantom_node.GetReverseDistance());
|
||||
if (phantom_node.IsValidReverseSource())
|
||||
{
|
||||
insert_node(phantom_node.reverse_segment_id.id,
|
||||
-phantom_node.GetReverseWeightPlusOffset(),
|
||||
-phantom_node.GetReverseDuration(),
|
||||
-phantom_node.GetReverseDistance());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (DIRECTION == REVERSE_DIRECTION)
|
||||
{
|
||||
if (phantom_node.IsValidForwardTarget())
|
||||
else if (DIRECTION == REVERSE_DIRECTION)
|
||||
{
|
||||
insert_node(phantom_node.forward_segment_id.id,
|
||||
phantom_node.GetForwardWeightPlusOffset(),
|
||||
phantom_node.GetForwardDuration(),
|
||||
phantom_node.GetForwardDistance());
|
||||
}
|
||||
if (phantom_node.IsValidForwardTarget())
|
||||
{
|
||||
insert_node(phantom_node.forward_segment_id.id,
|
||||
phantom_node.GetForwardWeightPlusOffset(),
|
||||
phantom_node.GetForwardDuration(),
|
||||
phantom_node.GetForwardDistance());
|
||||
}
|
||||
|
||||
if (phantom_node.IsValidReverseTarget())
|
||||
{
|
||||
insert_node(phantom_node.reverse_segment_id.id,
|
||||
phantom_node.GetReverseWeightPlusOffset(),
|
||||
phantom_node.GetReverseDuration(),
|
||||
phantom_node.GetReverseDistance());
|
||||
if (phantom_node.IsValidReverseTarget())
|
||||
{
|
||||
insert_node(phantom_node.reverse_segment_id.id,
|
||||
phantom_node.GetReverseWeightPlusOffset(),
|
||||
phantom_node.GetReverseDuration(),
|
||||
phantom_node.GetReverseDistance());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -389,7 +396,7 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
|
||||
// Relax outgoing edges
|
||||
relaxOutgoingEdges<DIRECTION>(
|
||||
facade, heapNode, query_heap, phantom_nodes, phantom_index, phantom_indices);
|
||||
facade, heapNode, query_heap, candidates_list, source_index, target_indices);
|
||||
}
|
||||
|
||||
return std::make_pair(std::move(durations_table), std::move(distances_table));
|
||||
@@ -409,7 +416,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
std::vector<EdgeDuration> &durations_table,
|
||||
std::vector<EdgeDistance> &distances_table,
|
||||
std::vector<NodeID> &middle_nodes_table,
|
||||
const PhantomNode &phantom_node)
|
||||
const PhantomNodeCandidates &candidates)
|
||||
{
|
||||
// Take a copy of the extracted node because otherwise could be modified later if toHeapNode is
|
||||
// the same
|
||||
@@ -455,7 +462,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
}
|
||||
}
|
||||
|
||||
relaxOutgoingEdges<DIRECTION>(facade, heapNode, query_heap, phantom_node);
|
||||
relaxOutgoingEdges<DIRECTION>(facade, heapNode, query_heap, candidates);
|
||||
}
|
||||
|
||||
template <bool DIRECTION>
|
||||
@@ -463,7 +470,7 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
const unsigned column_idx,
|
||||
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
|
||||
std::vector<NodeBucket> &search_space_with_buckets,
|
||||
const PhantomNode &phantom_node)
|
||||
const PhantomNodeCandidates &candidates)
|
||||
{
|
||||
// Take a copy of the extracted node because otherwise could be modified later if toHeapNode is
|
||||
// the same
|
||||
@@ -481,7 +488,7 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
|
||||
const auto &partition = facade.GetMultiLevelPartition();
|
||||
const auto maximal_level = partition.GetNumberOfLevels() - 1;
|
||||
|
||||
relaxOutgoingEdges<!DIRECTION>(facade, heapNode, query_heap, phantom_node, maximal_level);
|
||||
relaxOutgoingEdges<!DIRECTION>(facade, heapNode, query_heap, candidates, maximal_level);
|
||||
}
|
||||
|
||||
template <bool DIRECTION>
|
||||
@@ -524,7 +531,7 @@ template <bool DIRECTION>
|
||||
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||
manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
const DataFacade<Algorithm> &facade,
|
||||
const std::vector<PhantomNode> &phantom_nodes,
|
||||
const std::vector<PhantomNodeCandidates> &candidates_list,
|
||||
const std::vector<std::size_t> &source_indices,
|
||||
const std::vector<std::size_t> &target_indices,
|
||||
const bool calculate_distance)
|
||||
@@ -545,22 +552,22 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
for (std::uint32_t column_idx = 0; column_idx < target_indices.size(); ++column_idx)
|
||||
{
|
||||
const auto index = target_indices[column_idx];
|
||||
const auto &target_phantom = phantom_nodes[index];
|
||||
const auto &target_candidates = candidates_list[index];
|
||||
|
||||
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
|
||||
facade.GetNumberOfNodes(), facade.GetMaxBorderNodeID() + 1);
|
||||
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
||||
|
||||
if (DIRECTION == FORWARD_DIRECTION)
|
||||
insertTargetInHeap(query_heap, target_phantom);
|
||||
insertTargetInHeap(query_heap, target_candidates);
|
||||
else
|
||||
insertSourceInHeap(query_heap, target_phantom);
|
||||
insertSourceInHeap(query_heap, target_candidates);
|
||||
|
||||
// explore search space
|
||||
while (!query_heap.Empty())
|
||||
{
|
||||
backwardRoutingStep<DIRECTION>(
|
||||
facade, column_idx, query_heap, search_space_with_buckets, target_phantom);
|
||||
facade, column_idx, query_heap, search_space_with_buckets, target_candidates);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -571,7 +578,7 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
for (std::uint32_t row_idx = 0; row_idx < source_indices.size(); ++row_idx)
|
||||
{
|
||||
const auto source_index = source_indices[row_idx];
|
||||
const auto &source_phantom = phantom_nodes[source_index];
|
||||
const auto &source_candidates = candidates_list[source_index];
|
||||
|
||||
// Clear heap and insert source nodes
|
||||
engine_working_data.InitializeOrClearManyToManyThreadLocalStorage(
|
||||
@@ -580,9 +587,9 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
auto &query_heap = *(engine_working_data.many_to_many_heap);
|
||||
|
||||
if (DIRECTION == FORWARD_DIRECTION)
|
||||
insertSourceInHeap(query_heap, source_phantom);
|
||||
insertSourceInHeap(query_heap, source_candidates);
|
||||
else
|
||||
insertTargetInHeap(query_heap, source_phantom);
|
||||
insertTargetInHeap(query_heap, source_candidates);
|
||||
|
||||
// Explore search space
|
||||
while (!query_heap.Empty())
|
||||
@@ -597,7 +604,7 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
|
||||
durations_table,
|
||||
distances_table,
|
||||
middle_nodes_table,
|
||||
source_phantom);
|
||||
source_candidates);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -622,7 +629,7 @@ template <>
|
||||
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
|
||||
manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
||||
const DataFacade<mld::Algorithm> &facade,
|
||||
const std::vector<PhantomNode> &phantom_nodes,
|
||||
const std::vector<PhantomNodeCandidates> &candidates_list,
|
||||
const std::vector<std::size_t> &source_indices,
|
||||
const std::vector<std::size_t> &target_indices,
|
||||
const bool calculate_distance)
|
||||
@@ -631,7 +638,7 @@ manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
||||
{ // TODO: check if target_indices.size() == 1 and do a bi-directional search
|
||||
return mld::oneToManySearch<FORWARD_DIRECTION>(engine_working_data,
|
||||
facade,
|
||||
phantom_nodes,
|
||||
candidates_list,
|
||||
source_indices.front(),
|
||||
target_indices,
|
||||
calculate_distance);
|
||||
@@ -641,7 +648,7 @@ manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
||||
{
|
||||
return mld::oneToManySearch<REVERSE_DIRECTION>(engine_working_data,
|
||||
facade,
|
||||
phantom_nodes,
|
||||
candidates_list,
|
||||
target_indices.front(),
|
||||
source_indices,
|
||||
calculate_distance);
|
||||
@@ -651,7 +658,7 @@ manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
||||
{
|
||||
return mld::manyToManySearch<REVERSE_DIRECTION>(engine_working_data,
|
||||
facade,
|
||||
phantom_nodes,
|
||||
candidates_list,
|
||||
target_indices,
|
||||
source_indices,
|
||||
calculate_distance);
|
||||
@@ -659,7 +666,7 @@ manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
||||
|
||||
return mld::manyToManySearch<FORWARD_DIRECTION>(engine_working_data,
|
||||
facade,
|
||||
phantom_nodes,
|
||||
candidates_list,
|
||||
source_indices,
|
||||
target_indices,
|
||||
calculate_distance);
|
||||
|
||||
@@ -7,30 +7,104 @@ namespace engine
|
||||
namespace routing_algorithms
|
||||
{
|
||||
|
||||
bool needsLoopForward(const PhantomNode &source_phantom, const PhantomNode &target_phantom)
|
||||
bool requiresForwardLoop(const PhantomNode &source, const PhantomNode &target)
|
||||
{
|
||||
return source_phantom.IsValidForwardSource() && target_phantom.IsValidForwardTarget() &&
|
||||
source_phantom.forward_segment_id.id == target_phantom.forward_segment_id.id &&
|
||||
source_phantom.GetForwardWeightPlusOffset() >
|
||||
target_phantom.GetForwardWeightPlusOffset();
|
||||
return source.IsValidForwardSource() && target.IsValidForwardTarget() &&
|
||||
source.forward_segment_id.id == target.forward_segment_id.id &&
|
||||
source.GetForwardWeightPlusOffset() > target.GetForwardWeightPlusOffset();
|
||||
}
|
||||
|
||||
bool needsLoopBackwards(const PhantomNode &source_phantom, const PhantomNode &target_phantom)
|
||||
bool requiresBackwardLoop(const PhantomNode &source, const PhantomNode &target)
|
||||
{
|
||||
return source_phantom.IsValidReverseSource() && target_phantom.IsValidReverseTarget() &&
|
||||
source_phantom.reverse_segment_id.id == target_phantom.reverse_segment_id.id &&
|
||||
source_phantom.GetReverseWeightPlusOffset() >
|
||||
target_phantom.GetReverseWeightPlusOffset();
|
||||
return source.IsValidReverseSource() && target.IsValidReverseTarget() &&
|
||||
source.reverse_segment_id.id == target.reverse_segment_id.id &&
|
||||
source.GetReverseWeightPlusOffset() > target.GetReverseWeightPlusOffset();
|
||||
}
|
||||
|
||||
bool needsLoopForward(const PhantomNodes &phantoms)
|
||||
std::vector<NodeID> getForwardLoopNodes(const PhantomEndpointCandidates &endpoint_candidates)
|
||||
{
|
||||
return needsLoopForward(phantoms.source_phantom, phantoms.target_phantom);
|
||||
std::vector<NodeID> res;
|
||||
for (const auto &source_phantom : endpoint_candidates.source_phantoms)
|
||||
{
|
||||
auto requires_loop =
|
||||
std::any_of(endpoint_candidates.target_phantoms.begin(),
|
||||
endpoint_candidates.target_phantoms.end(),
|
||||
[&](const auto &target_phantom) {
|
||||
return requiresForwardLoop(source_phantom, target_phantom);
|
||||
});
|
||||
if (requires_loop)
|
||||
{
|
||||
res.push_back(source_phantom.forward_segment_id.id);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool needsLoopBackwards(const PhantomNodes &phantoms)
|
||||
std::vector<NodeID> getForwardLoopNodes(const PhantomCandidatesToTarget &endpoint_candidates)
|
||||
{
|
||||
return needsLoopBackwards(phantoms.source_phantom, phantoms.target_phantom);
|
||||
std::vector<NodeID> res;
|
||||
for (const auto &source_phantom : endpoint_candidates.source_phantoms)
|
||||
{
|
||||
if (requiresForwardLoop(source_phantom, endpoint_candidates.target_phantom))
|
||||
{
|
||||
res.push_back(source_phantom.forward_segment_id.id);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<NodeID> getBackwardLoopNodes(const PhantomEndpointCandidates &endpoint_candidates)
|
||||
{
|
||||
std::vector<NodeID> res;
|
||||
for (const auto &source_phantom : endpoint_candidates.source_phantoms)
|
||||
{
|
||||
auto requires_loop =
|
||||
std::any_of(endpoint_candidates.target_phantoms.begin(),
|
||||
endpoint_candidates.target_phantoms.end(),
|
||||
[&](const auto &target_phantom) {
|
||||
return requiresBackwardLoop(source_phantom, target_phantom);
|
||||
});
|
||||
if (requires_loop)
|
||||
{
|
||||
res.push_back(source_phantom.reverse_segment_id.id);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<NodeID> getBackwardLoopNodes(const PhantomCandidatesToTarget &endpoint_candidates)
|
||||
{
|
||||
std::vector<NodeID> res;
|
||||
for (const auto &source_phantom : endpoint_candidates.source_phantoms)
|
||||
{
|
||||
if (requiresBackwardLoop(source_phantom, endpoint_candidates.target_phantom))
|
||||
{
|
||||
res.push_back(source_phantom.reverse_segment_id.id);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
PhantomEndpoints endpointsFromCandidates(const PhantomEndpointCandidates &candidates,
|
||||
const std::vector<NodeID> &path)
|
||||
{
|
||||
auto source_it = std::find_if(candidates.source_phantoms.begin(),
|
||||
candidates.source_phantoms.end(),
|
||||
[&path](const auto &source_phantom) {
|
||||
return path.front() == source_phantom.forward_segment_id.id ||
|
||||
path.front() == source_phantom.reverse_segment_id.id;
|
||||
});
|
||||
BOOST_ASSERT(source_it != candidates.source_phantoms.end());
|
||||
|
||||
auto target_it = std::find_if(candidates.target_phantoms.begin(),
|
||||
candidates.target_phantoms.end(),
|
||||
[&path](const auto &target_phantom) {
|
||||
return path.back() == target_phantom.forward_segment_id.id ||
|
||||
path.back() == target_phantom.reverse_segment_id.id;
|
||||
});
|
||||
BOOST_ASSERT(target_it != candidates.target_phantoms.end());
|
||||
|
||||
return PhantomEndpoints{*source_it, *target_it};
|
||||
}
|
||||
|
||||
} // namespace routing_algorithms
|
||||
|
||||
@@ -95,9 +95,8 @@ void search(SearchEngineData<Algorithm> & /*engine_working_data*/,
|
||||
SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
|
||||
EdgeWeight &weight,
|
||||
std::vector<NodeID> &packed_leg,
|
||||
const bool force_loop_forward,
|
||||
const bool force_loop_reverse,
|
||||
const PhantomNodes & /*phantom_nodes*/,
|
||||
const std::vector<NodeID> &force_loop_forward_nodes,
|
||||
const std::vector<NodeID> &force_loop_reverse_nodes,
|
||||
const EdgeWeight weight_upper_bound)
|
||||
{
|
||||
if (forward_heap.Empty() || reverse_heap.Empty())
|
||||
@@ -126,8 +125,8 @@ void search(SearchEngineData<Algorithm> & /*engine_working_data*/,
|
||||
middle,
|
||||
weight,
|
||||
min_edge_offset,
|
||||
force_loop_forward,
|
||||
force_loop_reverse);
|
||||
force_loop_forward_nodes,
|
||||
force_loop_reverse_nodes);
|
||||
}
|
||||
if (!reverse_heap.Empty())
|
||||
{
|
||||
@@ -137,8 +136,8 @@ void search(SearchEngineData<Algorithm> & /*engine_working_data*/,
|
||||
middle,
|
||||
weight,
|
||||
min_edge_offset,
|
||||
force_loop_reverse,
|
||||
force_loop_forward);
|
||||
force_loop_reverse_nodes,
|
||||
force_loop_forward_nodes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,7 +178,8 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
|
||||
forward_heap.Clear();
|
||||
reverse_heap.Clear();
|
||||
|
||||
insertNodesInHeaps(forward_heap, reverse_heap, {source_phantom, target_phantom});
|
||||
PhantomEndpoints endpoints{source_phantom, target_phantom};
|
||||
insertNodesInHeaps(forward_heap, reverse_heap, endpoints);
|
||||
|
||||
EdgeWeight weight = INVALID_EDGE_WEIGHT;
|
||||
std::vector<NodeID> packed_path;
|
||||
@@ -189,9 +189,9 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
|
||||
reverse_heap,
|
||||
weight,
|
||||
packed_path,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
DO_NOT_FORCE_LOOPS,
|
||||
{source_phantom, target_phantom},
|
||||
{},
|
||||
{},
|
||||
endpoints,
|
||||
weight_upper_bound);
|
||||
|
||||
if (weight == INVALID_EDGE_WEIGHT)
|
||||
|
||||
@@ -12,13 +12,13 @@ namespace routing_algorithms
|
||||
template InternalRouteResult
|
||||
shortestPathSearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
||||
const DataFacade<ch::Algorithm> &facade,
|
||||
const std::vector<PhantomNodes> &phantom_nodes_vector,
|
||||
const std::vector<PhantomNodeCandidates> &waypoint_candidates,
|
||||
const boost::optional<bool> continue_straight_at_waypoint);
|
||||
|
||||
template InternalRouteResult
|
||||
shortestPathSearch(SearchEngineData<mld::Algorithm> &engine_working_data,
|
||||
const DataFacade<mld::Algorithm> &facade,
|
||||
const std::vector<PhantomNodes> &phantom_nodes_vector,
|
||||
const std::vector<PhantomNodeCandidates> &waypoint_candidates,
|
||||
const boost::optional<bool> continue_straight_at_waypoint);
|
||||
|
||||
} // namespace routing_algorithms
|
||||
|
||||
Reference in New Issue
Block a user