Don't use phantom node pairs as input for distance table
This commit is contained in:
parent
648a62112e
commit
0b1c9d33a5
@ -181,11 +181,11 @@ template <class DataFacadeT> class DistanceTablePlugin final : public BasePlugin
|
||||
BOOST_ASSERT((phantom_node_target_out_iter - phantom_node_target_vector.begin()) ==
|
||||
number_of_destination);
|
||||
|
||||
snapPhantomNodes(phantom_node_source_vector);
|
||||
snapPhantomNodes(phantom_node_target_vector);
|
||||
// FIXME we should clear phantom_node_source_vector and phantom_node_target_vector after this
|
||||
auto snapped_source_phantoms = snapPhantomNodes(phantom_node_source_vector);
|
||||
auto snapped_target_phantoms = snapPhantomNodes(phantom_node_target_vector);
|
||||
|
||||
std::shared_ptr<std::vector<EdgeWeight>> result_table = search_engine_ptr->distance_table(
|
||||
phantom_node_source_vector, phantom_node_target_vector);
|
||||
auto result_table = search_engine_ptr->distance_table(snapped_source_phantoms, snapped_target_phantoms);
|
||||
|
||||
if (!result_table)
|
||||
{
|
||||
@ -203,23 +203,22 @@ template <class DataFacadeT> class DistanceTablePlugin final : public BasePlugin
|
||||
matrix_json_array.values.push_back(json_row);
|
||||
}
|
||||
json_result.values["distance_table"] = matrix_json_array;
|
||||
|
||||
osrm::json::Array target_coord_json_array;
|
||||
for (const auto &pair : phantom_node_target_vector)
|
||||
for (const auto &phantom : snapped_target_phantoms)
|
||||
{
|
||||
osrm::json::Array json_coord;
|
||||
FixedPointCoordinate coord = pair.first.location;
|
||||
json_coord.values.push_back(coord.lat / COORDINATE_PRECISION);
|
||||
json_coord.values.push_back(coord.lon / COORDINATE_PRECISION);
|
||||
json_coord.values.push_back(phantom.location.lat / COORDINATE_PRECISION);
|
||||
json_coord.values.push_back(phantom.location.lon / COORDINATE_PRECISION);
|
||||
target_coord_json_array.values.push_back(json_coord);
|
||||
}
|
||||
json_result.values["destination_coordinates"] = target_coord_json_array;
|
||||
osrm::json::Array source_coord_json_array;
|
||||
for (const auto &pair : phantom_node_source_vector)
|
||||
for (const auto &phantom : snapped_source_phantoms)
|
||||
{
|
||||
osrm::json::Array json_coord;
|
||||
FixedPointCoordinate coord = pair.first.location;
|
||||
json_coord.values.push_back(coord.lat / COORDINATE_PRECISION);
|
||||
json_coord.values.push_back(coord.lon / COORDINATE_PRECISION);
|
||||
json_coord.values.push_back(phantom.location.lat / COORDINATE_PRECISION);
|
||||
json_coord.values.push_back(phantom.location.lon / COORDINATE_PRECISION);
|
||||
source_coord_json_array.values.push_back(json_coord);
|
||||
}
|
||||
json_result.values["source_coordinates"] = source_coord_json_array;
|
||||
|
@ -46,8 +46,8 @@ class BasePlugin
|
||||
virtual ~BasePlugin() {}
|
||||
virtual const std::string GetDescriptor() const = 0;
|
||||
virtual int HandleRequest(const RouteParameters &, osrm::json::Object &) = 0;
|
||||
virtual bool
|
||||
check_all_coordinates(const std::vector<FixedPointCoordinate> &coordinates, const unsigned min = 2) const final
|
||||
virtual bool check_all_coordinates(const std::vector<FixedPointCoordinate> &coordinates,
|
||||
const unsigned min = 2) const final
|
||||
{
|
||||
if (min > coordinates.size() || std::any_of(std::begin(coordinates), std::end(coordinates),
|
||||
[](const FixedPointCoordinate &coordinate)
|
||||
@ -62,16 +62,18 @@ class BasePlugin
|
||||
|
||||
// Decides whether to use the phantom node from a big or small component if both are found.
|
||||
// Returns true if all phantom nodes are in the same component after snapping.
|
||||
bool snapPhantomNodes(std::vector<std::pair<PhantomNode, PhantomNode>> &phantom_node_pair_list) const
|
||||
std::vector<PhantomNode> snapPhantomNodes(
|
||||
const std::vector<std::pair<PhantomNode, PhantomNode>> &phantom_node_pair_list) const
|
||||
{
|
||||
const auto check_component_id_is_tiny = [](const std::pair<PhantomNode, PhantomNode> &phantom_pair)
|
||||
const auto check_component_id_is_tiny =
|
||||
[](const std::pair<PhantomNode, PhantomNode> &phantom_pair)
|
||||
{
|
||||
return phantom_pair.first.component.is_tiny;
|
||||
};
|
||||
|
||||
|
||||
// are all phantoms from a tiny cc?
|
||||
const auto check_all_in_same_component = [](const std::vector<std::pair<PhantomNode, PhantomNode>> &nodes)
|
||||
const auto check_all_in_same_component =
|
||||
[](const std::vector<std::pair<PhantomNode, PhantomNode>> &nodes)
|
||||
{
|
||||
const auto component_id = nodes.front().first.component.id;
|
||||
|
||||
@ -82,13 +84,20 @@ class BasePlugin
|
||||
});
|
||||
};
|
||||
|
||||
const auto swap_phantom_from_big_cc_into_front = [](std::pair<PhantomNode, PhantomNode> &phantom_pair)
|
||||
const auto fallback_to_big_component =
|
||||
[](const std::pair<PhantomNode, PhantomNode> &phantom_pair)
|
||||
{
|
||||
if (phantom_pair.first.component.is_tiny && phantom_pair.second.is_valid() && !phantom_pair.second.component.is_tiny)
|
||||
if (phantom_pair.first.component.is_tiny && phantom_pair.second.is_valid() &&
|
||||
!phantom_pair.second.component.is_tiny)
|
||||
{
|
||||
using std::swap;
|
||||
swap(phantom_pair.first, phantom_pair.second);
|
||||
return phantom_pair.second;
|
||||
}
|
||||
return phantom_pair.first;
|
||||
};
|
||||
|
||||
const auto use_closed_phantom = [](const std::pair<PhantomNode, PhantomNode> &phantom_pair)
|
||||
{
|
||||
return phantom_pair.first;
|
||||
};
|
||||
|
||||
const bool every_phantom_is_in_tiny_cc =
|
||||
@ -96,17 +105,23 @@ class BasePlugin
|
||||
check_component_id_is_tiny);
|
||||
auto all_in_same_component = check_all_in_same_component(phantom_node_pair_list);
|
||||
|
||||
// The only case we don't snap to the big component if all phantoms are in the same small component
|
||||
if (!every_phantom_is_in_tiny_cc || !all_in_same_component)
|
||||
{
|
||||
std::for_each(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
|
||||
swap_phantom_from_big_cc_into_front);
|
||||
std::vector<PhantomNode> snapped_phantoms;
|
||||
snapped_phantoms.reserve(phantom_node_pair_list.size());
|
||||
|
||||
// update check with new component ids
|
||||
all_in_same_component = check_all_in_same_component(phantom_node_pair_list);
|
||||
// The only case we don't snap to the big component if all phantoms are in the same small
|
||||
// component
|
||||
if (every_phantom_is_in_tiny_cc && all_in_same_component)
|
||||
{
|
||||
std::transform(phantom_node_pair_list.begin(), phantom_node_pair_list.end(),
|
||||
std::back_inserter(snapped_phantoms), use_closed_phantom);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::transform(phantom_node_pair_list.begin(), phantom_node_pair_list.end(),
|
||||
std::back_inserter(snapped_phantoms), fallback_to_big_component);
|
||||
}
|
||||
|
||||
return all_in_same_component;
|
||||
return snapped_phantoms;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -72,12 +72,14 @@ template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin
|
||||
|
||||
const std::string GetDescriptor() const override final { return descriptor_string; }
|
||||
|
||||
void GetPhantomNodes(const RouteParameters &route_parameters,
|
||||
std::vector<PhantomNodePair> &phantom_node_pair_list)
|
||||
std::vector<PhantomNode> GetPhantomNodes(const RouteParameters &route_parameters)
|
||||
{
|
||||
const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());
|
||||
const auto &input_bearings = route_parameters.bearings;
|
||||
|
||||
std::vector<PhantomNode> phantom_node_list;
|
||||
phantom_node_list.reserve(route_parameters.coordinates.size());
|
||||
|
||||
// find phantom nodes for all input coords
|
||||
for (const auto i : osrm::irange<std::size_t>(0, route_parameters.coordinates.size()))
|
||||
{
|
||||
@ -89,17 +91,17 @@ template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin
|
||||
ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], current_phantom_node);
|
||||
if (current_phantom_node.is_valid(facade->GetNumberOfNodes()))
|
||||
{
|
||||
phantom_node_pair_list[i] = std::make_pair(current_phantom_node, current_phantom_node);
|
||||
phantom_node_list.push_back(std::move(current_phantom_node));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const int bearing = input_bearings.size() > 0 ? input_bearings[i].first : 0;
|
||||
const int range = input_bearings.size() > 0 ? (input_bearings[i].second?*input_bearings[i].second:10) : 180;
|
||||
auto phantom_nodes = facade->NearestPhantomNodes(route_parameters.coordinates[i], 1, bearing, range);
|
||||
// FIXME we only use the pair because that is what DistanceTable expects
|
||||
phantom_node_pair_list[i] = std::make_pair(phantom_nodes.front().phantom_node, phantom_nodes.front().phantom_node);
|
||||
BOOST_ASSERT(phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes()));
|
||||
phantom_node_list.push_back(facade->NearestPhantomNodes(route_parameters.coordinates[i], 1, bearing, range).front().phantom_node);
|
||||
BOOST_ASSERT(phantom_node_list.back().is_valid(facade->GetNumberOfNodes()));
|
||||
}
|
||||
|
||||
return phantom_node_list;
|
||||
}
|
||||
|
||||
// Object to hold all strongly connected components (scc) of a graph
|
||||
@ -203,7 +205,7 @@ template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin
|
||||
json_result.values["permutation"] = json_permutation;
|
||||
}
|
||||
|
||||
InternalRouteResult ComputeRoute(const std::vector<PhantomNodePair> &phantom_node_pair_list,
|
||||
InternalRouteResult ComputeRoute(const std::vector<PhantomNode> &phantom_node_list,
|
||||
const RouteParameters &route_parameters,
|
||||
const std::vector<NodeID> &trip)
|
||||
{
|
||||
@ -220,7 +222,7 @@ template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin
|
||||
const auto to_node = std::next(it) != end ? *std::next(it) : *start;
|
||||
|
||||
viapoint =
|
||||
PhantomNodes{phantom_node_pair_list[from_node].first, phantom_node_pair_list[to_node].first};
|
||||
PhantomNodes{phantom_node_list[from_node], phantom_node_list[to_node]};
|
||||
min_route.segment_end_coordinates.emplace_back(viapoint);
|
||||
}
|
||||
BOOST_ASSERT(min_route.segment_end_coordinates.size() == trip.size());
|
||||
@ -243,24 +245,24 @@ template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin
|
||||
// check if all inputs are coordinates
|
||||
if (!check_all_coordinates(route_parameters.coordinates))
|
||||
{
|
||||
json_result.values["status_message"] = "Invalid coordinates.";
|
||||
return 400;
|
||||
}
|
||||
|
||||
const auto &input_bearings = route_parameters.bearings;
|
||||
if (input_bearings.size() > 0 && route_parameters.coordinates.size() != input_bearings.size())
|
||||
{
|
||||
json_result.values["status"] = "Number of bearings does not match number of coordinates .";
|
||||
json_result.values["status_message"] = "Number of bearings does not match number of coordinates.";
|
||||
return 400;
|
||||
}
|
||||
|
||||
// get phantom nodes
|
||||
std::vector<PhantomNodePair> phantom_node_pair_list(route_parameters.coordinates.size());
|
||||
GetPhantomNodes(route_parameters, phantom_node_pair_list);
|
||||
const auto number_of_locations = phantom_node_pair_list.size();
|
||||
auto phantom_node_list = GetPhantomNodes(route_parameters);
|
||||
const auto number_of_locations = phantom_node_list.size();
|
||||
|
||||
// compute the distance table of all phantom nodes
|
||||
const auto result_table = DistTableWrapper<EdgeWeight>(
|
||||
*search_engine_ptr->distance_table(phantom_node_pair_list, phantom_node_pair_list), number_of_locations);
|
||||
*search_engine_ptr->distance_table(phantom_node_list, phantom_node_list), number_of_locations);
|
||||
|
||||
if (result_table.size() == 0)
|
||||
{
|
||||
@ -328,7 +330,7 @@ template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin
|
||||
comp_route.reserve(route_result.size());
|
||||
for (auto &elem : route_result)
|
||||
{
|
||||
comp_route.push_back(ComputeRoute(phantom_node_pair_list, route_parameters, elem));
|
||||
comp_route.push_back(ComputeRoute(phantom_node_list, route_parameters, elem));
|
||||
}
|
||||
|
||||
TIMER_STOP(TRIP_TIMER);
|
||||
|
@ -77,13 +77,16 @@ template <class DataFacadeT> class ViaRoutePlugin final : public BasePlugin
|
||||
{
|
||||
if (!check_all_coordinates(route_parameters.coordinates))
|
||||
{
|
||||
json_result.values["status_message"] = "Invalid coordinates.";
|
||||
return 400;
|
||||
}
|
||||
|
||||
const auto &input_bearings = route_parameters.bearings;
|
||||
if (input_bearings.size() > 0 && route_parameters.coordinates.size() != input_bearings.size())
|
||||
if (input_bearings.size() > 0 &&
|
||||
route_parameters.coordinates.size() != input_bearings.size())
|
||||
{
|
||||
json_result.values["status"] = "Number of bearings does not match number of coordinates .";
|
||||
json_result.values["status_message"] =
|
||||
"Number of bearings does not match number of coordinates.";
|
||||
return 400;
|
||||
}
|
||||
|
||||
@ -103,28 +106,32 @@ template <class DataFacadeT> class ViaRoutePlugin final : public BasePlugin
|
||||
}
|
||||
}
|
||||
const int bearing = input_bearings.size() > 0 ? input_bearings[i].first : 0;
|
||||
const int range = input_bearings.size() > 0 ? (input_bearings[i].second?*input_bearings[i].second:10) : 180;
|
||||
phantom_node_pair_list[i] = facade->NearestPhantomNodeWithAlternativeFromBigComponent(route_parameters.coordinates[i], bearing, range);
|
||||
const int range = input_bearings.size() > 0
|
||||
? (input_bearings[i].second ? *input_bearings[i].second : 10)
|
||||
: 180;
|
||||
phantom_node_pair_list[i] = facade->NearestPhantomNodeWithAlternativeFromBigComponent(
|
||||
route_parameters.coordinates[i], bearing, range);
|
||||
// we didn't found a fitting node, return error
|
||||
if (!phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes()))
|
||||
{
|
||||
json_result.values["status_message"] = std::string("Could not find a matching segment for coordinate ") + std::to_string(i);
|
||||
json_result.values["status_message"] =
|
||||
std::string("Could not find a matching segment for coordinate ") +
|
||||
std::to_string(i);
|
||||
return 400;
|
||||
}
|
||||
BOOST_ASSERT(phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes()));
|
||||
BOOST_ASSERT(phantom_node_pair_list[i].second.is_valid(facade->GetNumberOfNodes()));
|
||||
}
|
||||
|
||||
auto all_in_same_component = snapPhantomNodes(phantom_node_pair_list);
|
||||
auto snapped_phantoms = snapPhantomNodes(phantom_node_pair_list);
|
||||
|
||||
InternalRouteResult raw_route;
|
||||
auto build_phantom_pairs =
|
||||
[&raw_route](const PhantomNodePair &first_pair, const PhantomNodePair &second_pair)
|
||||
auto build_phantom_pairs = [&raw_route](const PhantomNode &first_node,
|
||||
const PhantomNode &second_node)
|
||||
{
|
||||
raw_route.segment_end_coordinates.emplace_back(
|
||||
PhantomNodes{first_pair.first, second_pair.first});
|
||||
raw_route.segment_end_coordinates.push_back(PhantomNodes{first_node, second_node});
|
||||
};
|
||||
osrm::for_each_pair(phantom_node_pair_list, build_phantom_pairs);
|
||||
osrm::for_each_pair(snapped_phantoms, build_phantom_pairs);
|
||||
|
||||
if (1 == raw_route.segment_end_coordinates.size())
|
||||
{
|
||||
@ -171,11 +178,21 @@ template <class DataFacadeT> class ViaRoutePlugin final : public BasePlugin
|
||||
|
||||
// we can only know this after the fact, different SCC ids still
|
||||
// allow for connection in one direction.
|
||||
if (!all_in_same_component && no_route)
|
||||
if (no_route)
|
||||
{
|
||||
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;
|
||||
});
|
||||
if (not_in_same_component)
|
||||
{
|
||||
json_result.values["status_message"] = "Impossible route between points.";
|
||||
return 400;
|
||||
}
|
||||
}
|
||||
|
||||
return 200;
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ class ManyToManyRouting final
|
||||
~ManyToManyRouting() {}
|
||||
|
||||
std::shared_ptr<std::vector<EdgeWeight>>
|
||||
operator()(const std::vector<PhantomNodePair> &phantom_sources_array, const std::vector<PhantomNodePair> &phantom_targets_array) const
|
||||
operator()(const std::vector<PhantomNode> &phantom_sources_array, const std::vector<PhantomNode> &phantom_targets_array) const
|
||||
{
|
||||
const auto number_of_sources = phantom_sources_array.size();
|
||||
const auto number_of_targets = phantom_targets_array.size();
|
||||
@ -83,35 +83,22 @@ class ManyToManyRouting final
|
||||
SearchSpaceWithBuckets search_space_with_buckets;
|
||||
|
||||
unsigned target_id = 0;
|
||||
for (const auto &pair : phantom_targets_array)
|
||||
for (const auto &phantom : phantom_targets_array)
|
||||
{
|
||||
query_heap.Clear();
|
||||
// insert target(s) at distance 0
|
||||
|
||||
if (SPECIAL_NODEID != pair.first.forward_node_id)
|
||||
if (SPECIAL_NODEID != phantom.forward_node_id)
|
||||
{
|
||||
query_heap.Insert(pair.first.forward_node_id,
|
||||
pair.first.GetForwardWeightPlusOffset(),
|
||||
pair.first.forward_node_id);
|
||||
query_heap.Insert(phantom.forward_node_id,
|
||||
phantom.GetForwardWeightPlusOffset(),
|
||||
phantom.forward_node_id);
|
||||
}
|
||||
if (SPECIAL_NODEID != pair.first.reverse_node_id)
|
||||
if (SPECIAL_NODEID != phantom.reverse_node_id)
|
||||
{
|
||||
query_heap.Insert(pair.first.reverse_node_id,
|
||||
pair.first.GetReverseWeightPlusOffset(),
|
||||
pair.first.reverse_node_id);
|
||||
}
|
||||
|
||||
if (SPECIAL_NODEID != pair.second.forward_node_id)
|
||||
{
|
||||
query_heap.Insert(pair.second.forward_node_id,
|
||||
pair.second.GetForwardWeightPlusOffset(),
|
||||
pair.second.forward_node_id);
|
||||
}
|
||||
if (SPECIAL_NODEID != pair.second.reverse_node_id)
|
||||
{
|
||||
query_heap.Insert(pair.second.reverse_node_id,
|
||||
pair.second.GetReverseWeightPlusOffset(),
|
||||
pair.second.reverse_node_id);
|
||||
query_heap.Insert(phantom.reverse_node_id,
|
||||
phantom.GetReverseWeightPlusOffset(),
|
||||
phantom.reverse_node_id);
|
||||
}
|
||||
|
||||
// explore search space
|
||||
@ -124,35 +111,22 @@ class ManyToManyRouting final
|
||||
|
||||
// for each source do forward search
|
||||
unsigned source_id = 0;
|
||||
for (const auto &pair : phantom_sources_array)
|
||||
for (const auto &phantom : phantom_sources_array)
|
||||
{
|
||||
query_heap.Clear();
|
||||
// insert target(s) at distance 0
|
||||
|
||||
if (SPECIAL_NODEID != pair.first.forward_node_id)
|
||||
if (SPECIAL_NODEID != phantom.forward_node_id)
|
||||
{
|
||||
query_heap.Insert(pair.first.forward_node_id,
|
||||
-pair.first.GetForwardWeightPlusOffset(),
|
||||
pair.first.forward_node_id);
|
||||
query_heap.Insert(phantom.forward_node_id,
|
||||
-phantom.GetForwardWeightPlusOffset(),
|
||||
phantom.forward_node_id);
|
||||
}
|
||||
if (SPECIAL_NODEID != pair.first.reverse_node_id)
|
||||
if (SPECIAL_NODEID != phantom.reverse_node_id)
|
||||
{
|
||||
query_heap.Insert(pair.first.reverse_node_id,
|
||||
-pair.first.GetReverseWeightPlusOffset(),
|
||||
pair.first.reverse_node_id);
|
||||
}
|
||||
|
||||
if (SPECIAL_NODEID != pair.second.forward_node_id)
|
||||
{
|
||||
query_heap.Insert(pair.second.forward_node_id,
|
||||
-pair.second.GetForwardWeightPlusOffset(),
|
||||
pair.second.forward_node_id);
|
||||
}
|
||||
if (SPECIAL_NODEID != pair.second.reverse_node_id)
|
||||
{
|
||||
query_heap.Insert(pair.second.reverse_node_id,
|
||||
-pair.second.GetReverseWeightPlusOffset(),
|
||||
pair.second.reverse_node_id);
|
||||
query_heap.Insert(phantom.reverse_node_id,
|
||||
-phantom.GetReverseWeightPlusOffset(),
|
||||
phantom.reverse_node_id);
|
||||
}
|
||||
|
||||
// explore search space
|
||||
|
Loading…
Reference in New Issue
Block a user