Lazily generate optional route path data (#6045)
Currently route results are annotated with additional path information, such as geometries, turn-by-turn steps and other metadata. These annotations are generated if they are not requested or returned in the response. Datasets needed to generate these annotations are loaded and available to the OSRM process even when unused. This commit is a first step towards making the loading of these datasets optional. We refactor the code so that route annotations are only generated if explicitly requested and needed in the response. Specifically, we change the following annotations to be lazily generated: - Turn-by-turn steps - Route Overview geometry - Route segment metadata For example. a /route/v1 request with steps=false&overview=false&annotations=false would no longer call the following data facade methods: - GetOSMNodeIDOfNode - GetTurnInstructionForEdgeID - GetNameIndex - GetNameForID - GetRefForID - GetTurnInstructionForEdgeID - GetClassData - IsLeftHandDriving - GetTravelMode - IsSegregated - PreTurnBearing - PostTurnBearing - HasLaneData - GetLaneData - GetEntryClass Requests that include segment metadata and/or overview geometry but not turn-by-turn instructions will also benefit from this, although there is some interdependency with the step instructions - a call to GetTurnInstructionForEdgeID is still required. Requests for OSM annotations will understandably still need to call GetOSMNodeIDOfNode. Making these changes unlocks the optional loading of data contained in the following OSRM files: - osrm.names - osrm.icd - osrm.nbg_nodes (partial) - osrm.ebg_nodes (partial) - osrm.edges
This commit is contained in:
@@ -57,8 +57,7 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
|
||||
const auto source_geometry_id = facade.GetGeometryIndex(source_node_id).id;
|
||||
const auto source_geometry = facade.GetUncompressedForwardGeometry(source_geometry_id);
|
||||
|
||||
geometry.osm_node_ids.push_back(
|
||||
facade.GetOSMNodeIDOfNode(source_geometry(source_segment_start_coordinate)));
|
||||
geometry.node_ids.push_back(source_geometry(source_segment_start_coordinate));
|
||||
|
||||
auto cumulative_distance = 0.;
|
||||
auto current_distance = 0.;
|
||||
@@ -71,7 +70,10 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
|
||||
cumulative_distance += current_distance;
|
||||
|
||||
// all changes to this check have to be matched with assemble_steps
|
||||
if (path_point.turn_instruction.type != osrm::guidance::TurnType::NoTurn)
|
||||
auto turn_instruction = path_point.turn_edge
|
||||
? facade.GetTurnInstructionForEdgeID(*path_point.turn_edge)
|
||||
: osrm::guidance::TurnInstruction::NO_TURN();
|
||||
if (turn_instruction.type != osrm::guidance::TurnType::NoTurn)
|
||||
{
|
||||
geometry.segment_distances.push_back(cumulative_distance);
|
||||
geometry.segment_offsets.push_back(geometry.locations.size());
|
||||
@@ -79,11 +81,10 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
|
||||
}
|
||||
|
||||
prev_coordinate = coordinate;
|
||||
const auto node_id = path_point.turn_via_node;
|
||||
|
||||
const auto osm_node_id = facade.GetOSMNodeIDOfNode(path_point.turn_via_node);
|
||||
|
||||
if (osm_node_id != geometry.osm_node_ids.back() ||
|
||||
path_point.turn_instruction.type != osrm::guidance::TurnType::NoTurn)
|
||||
if (node_id != geometry.node_ids.back() ||
|
||||
turn_instruction.type != osrm::guidance::TurnType::NoTurn)
|
||||
{
|
||||
geometry.annotations.emplace_back(LegGeometry::Annotation{
|
||||
current_distance,
|
||||
@@ -99,7 +100,7 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
|
||||
facade.GetWeightMultiplier(),
|
||||
path_point.datasource_id});
|
||||
geometry.locations.push_back(std::move(coordinate));
|
||||
geometry.osm_node_ids.push_back(osm_node_id);
|
||||
geometry.node_ids.push_back(node_id);
|
||||
}
|
||||
}
|
||||
current_distance =
|
||||
@@ -158,8 +159,7 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
|
||||
const auto target_segment_end_coordinate =
|
||||
target_node.fwd_segment_position + (reversed_target ? 0 : 1);
|
||||
const auto target_geometry = facade.GetUncompressedForwardGeometry(target_geometry_id);
|
||||
geometry.osm_node_ids.push_back(
|
||||
facade.GetOSMNodeIDOfNode(target_geometry(target_segment_end_coordinate)));
|
||||
geometry.node_ids.push_back(target_geometry(target_segment_end_coordinate));
|
||||
|
||||
BOOST_ASSERT(geometry.segment_distances.size() == geometry.segment_offsets.size() - 1);
|
||||
BOOST_ASSERT(geometry.locations.size() > geometry.segment_distances.size());
|
||||
|
||||
@@ -75,10 +75,14 @@ std::array<std::uint32_t, SegmentNumber> summarizeRoute(const datafacade::BaseDa
|
||||
|
||||
std::vector<NamedSegment> segments(route_data.size());
|
||||
std::uint32_t index = 0;
|
||||
std::transform(
|
||||
route_data.begin(), route_data.end(), segments.begin(), [&index](const PathData &point) {
|
||||
return NamedSegment{point.duration_until_turn, index++, point.name_id};
|
||||
});
|
||||
std::transform(route_data.begin(),
|
||||
route_data.end(),
|
||||
segments.begin(),
|
||||
[&index, &facade](const PathData &point) {
|
||||
return NamedSegment{point.duration_until_turn,
|
||||
index++,
|
||||
facade.GetNameIndex(point.from_edge_based_node)};
|
||||
});
|
||||
const auto target_duration =
|
||||
target_traversed_in_reverse ? target_node.reverse_duration : target_node.forward_duration;
|
||||
const auto target_node_id = target_traversed_in_reverse ? target_node.reverse_segment_id.id
|
||||
@@ -124,21 +128,59 @@ std::array<std::uint32_t, SegmentNumber> summarizeRoute(const datafacade::BaseDa
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
inline std::string assembleSummary(const datafacade::BaseDataFacade &facade,
|
||||
const std::vector<PathData> &route_data,
|
||||
const PhantomNode &target_node,
|
||||
const bool target_traversed_in_reverse)
|
||||
{
|
||||
auto summary_array = detail::summarizeRoute<detail::MAX_USED_SEGMENTS>(
|
||||
facade, route_data, target_node, target_traversed_in_reverse);
|
||||
|
||||
BOOST_ASSERT(detail::MAX_USED_SEGMENTS > 0);
|
||||
BOOST_ASSERT(summary_array.begin() != summary_array.end());
|
||||
|
||||
// transform a name_id into a string containing either the name, or -if the name is empty-
|
||||
// the reference.
|
||||
const auto name_id_to_string = [&](const NameID name_id) {
|
||||
const auto name = facade.GetNameForID(name_id);
|
||||
if (!name.empty())
|
||||
return name.to_string();
|
||||
else
|
||||
{
|
||||
const auto ref = facade.GetRefForID(name_id);
|
||||
return ref.to_string();
|
||||
}
|
||||
};
|
||||
|
||||
const auto not_empty = [&](const std::string &name) { return !name.empty(); };
|
||||
|
||||
const auto summary_names = summary_array | boost::adaptors::transformed(name_id_to_string) |
|
||||
boost::adaptors::filtered(not_empty);
|
||||
return boost::algorithm::join(summary_names, ", ");
|
||||
}
|
||||
|
||||
inline RouteLeg assembleLeg(const datafacade::BaseDataFacade &facade,
|
||||
const std::vector<PathData> &route_data,
|
||||
const LegGeometry &leg_geometry,
|
||||
const PhantomNode &source_node,
|
||||
const PhantomNode &target_node,
|
||||
const bool target_traversed_in_reverse,
|
||||
const bool needs_summary)
|
||||
const bool target_traversed_in_reverse)
|
||||
{
|
||||
auto distance = 0.;
|
||||
auto prev_coordinate = source_node.location;
|
||||
for (const auto &path_point : route_data)
|
||||
{
|
||||
auto coordinate = facade.GetCoordinateOfNode(path_point.turn_via_node);
|
||||
distance += util::coordinate_calculation::greatCircleDistance(prev_coordinate, coordinate);
|
||||
prev_coordinate = coordinate;
|
||||
}
|
||||
distance +=
|
||||
util::coordinate_calculation::greatCircleDistance(prev_coordinate, target_node.location);
|
||||
|
||||
const auto target_duration =
|
||||
(target_traversed_in_reverse ? target_node.reverse_duration : target_node.forward_duration);
|
||||
const auto target_weight =
|
||||
(target_traversed_in_reverse ? target_node.reverse_weight : target_node.forward_weight);
|
||||
|
||||
auto distance = std::accumulate(
|
||||
leg_geometry.segment_distances.begin(), leg_geometry.segment_distances.end(), 0.);
|
||||
auto duration = std::accumulate(
|
||||
route_data.begin(), route_data.end(), 0, [](const double sum, const PathData &data) {
|
||||
return sum + data.duration_until_turn;
|
||||
@@ -182,39 +224,10 @@ inline RouteLeg assembleLeg(const datafacade::BaseDataFacade &facade,
|
||||
duration = std::max(0, duration);
|
||||
}
|
||||
|
||||
std::string summary;
|
||||
if (needs_summary)
|
||||
{
|
||||
auto summary_array = detail::summarizeRoute<detail::MAX_USED_SEGMENTS>(
|
||||
facade, route_data, target_node, target_traversed_in_reverse);
|
||||
|
||||
BOOST_ASSERT(detail::MAX_USED_SEGMENTS > 0);
|
||||
BOOST_ASSERT(summary_array.begin() != summary_array.end());
|
||||
|
||||
// transform a name_id into a string containing either the name, or -if the name is empty-
|
||||
// the reference.
|
||||
const auto name_id_to_string = [&](const NameID name_id) {
|
||||
const auto name = facade.GetNameForID(name_id);
|
||||
if (!name.empty())
|
||||
return name.to_string();
|
||||
else
|
||||
{
|
||||
const auto ref = facade.GetRefForID(name_id);
|
||||
return ref.to_string();
|
||||
}
|
||||
};
|
||||
|
||||
const auto not_empty = [&](const std::string &name) { return !name.empty(); };
|
||||
|
||||
const auto summary_names = summary_array | boost::adaptors::transformed(name_id_to_string) |
|
||||
boost::adaptors::filtered(not_empty);
|
||||
summary = boost::algorithm::join(summary_names, ", ");
|
||||
}
|
||||
|
||||
return RouteLeg{std::round(distance * 10.) / 10.,
|
||||
duration / 10.,
|
||||
weight / facade.GetWeightMultiplier(),
|
||||
summary,
|
||||
"",
|
||||
{}};
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
#include <cstddef>
|
||||
#include <guidance/turn_bearing.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
@@ -96,7 +97,7 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
||||
{},
|
||||
source_classes};
|
||||
|
||||
if (leg_data.size() > 0)
|
||||
if (!leg_data.empty())
|
||||
{
|
||||
// PathData saves the information we need of the segment _before_ the turn,
|
||||
// but a RouteStep is with regard to the segment after the turn.
|
||||
@@ -115,7 +116,10 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
||||
segment_weight += path_point.weight_until_turn;
|
||||
|
||||
// all changes to this check have to be matched with assemble_geometry
|
||||
if (path_point.turn_instruction.type != osrm::guidance::TurnType::NoTurn)
|
||||
const auto turn_instruction =
|
||||
path_point.turn_edge ? facade.GetTurnInstructionForEdgeID(*path_point.turn_edge)
|
||||
: osrm::guidance::TurnInstruction::NO_TURN();
|
||||
if (turn_instruction.type != osrm::guidance::TurnType::NoTurn)
|
||||
{
|
||||
BOOST_ASSERT(segment_weight >= 0);
|
||||
const auto name = facade.GetNameForID(step_name_id);
|
||||
@@ -125,7 +129,13 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
||||
const auto exits = facade.GetExitsForID(step_name_id);
|
||||
const auto distance = leg_geometry.segment_distances[segment_index];
|
||||
// intersections contain the classes of exiting road
|
||||
intersection.classes = facade.GetClasses(path_point.classes);
|
||||
intersection.classes =
|
||||
facade.GetClasses(facade.GetClassData(path_point.from_edge_based_node));
|
||||
|
||||
const auto is_left_hand_driving =
|
||||
facade.IsLeftHandDriving(path_point.from_edge_based_node);
|
||||
const auto travel_mode = facade.GetTravelMode(path_point.from_edge_based_node);
|
||||
BOOST_ASSERT(travel_mode > 0);
|
||||
|
||||
steps.push_back(RouteStep{path_point.from_edge_based_node,
|
||||
step_name_id,
|
||||
@@ -140,17 +150,19 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
||||
segment_duration / 10.,
|
||||
distance,
|
||||
segment_weight / weight_multiplier,
|
||||
path_point.travel_mode,
|
||||
travel_mode,
|
||||
maneuver,
|
||||
leg_geometry.FrontIndex(segment_index),
|
||||
leg_geometry.BackIndex(segment_index) + 1,
|
||||
{intersection},
|
||||
path_point.is_left_hand_driving});
|
||||
is_left_hand_driving});
|
||||
|
||||
if (leg_data_index + 1 < leg_data.size())
|
||||
{
|
||||
step_name_id = leg_data[leg_data_index + 1].name_id;
|
||||
is_segregated = leg_data[leg_data_index + 1].is_segregated;
|
||||
step_name_id =
|
||||
facade.GetNameIndex(leg_data[leg_data_index + 1].from_edge_based_node);
|
||||
is_segregated =
|
||||
facade.IsSegregated(leg_data[leg_data_index + 1].from_edge_based_node);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -159,20 +171,33 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
||||
}
|
||||
|
||||
// extract bearings
|
||||
bearings = std::make_pair<std::uint16_t, std::uint16_t>(
|
||||
path_point.pre_turn_bearing.Get(), path_point.post_turn_bearing.Get());
|
||||
auto pre_turn_bearing = path_point.turn_edge
|
||||
? facade.PreTurnBearing(*path_point.turn_edge)
|
||||
: osrm::guidance::TurnBearing(0);
|
||||
auto post_turn_bearing = path_point.turn_edge
|
||||
? facade.PostTurnBearing(*path_point.turn_edge)
|
||||
: osrm::guidance::TurnBearing(0);
|
||||
bearings = std::make_pair<std::uint16_t, std::uint16_t>(pre_turn_bearing.Get(),
|
||||
post_turn_bearing.Get());
|
||||
const auto bearing_class = facade.GetBearingClass(path_point.turn_via_node);
|
||||
auto bearing_data = bearing_class.getAvailableBearings();
|
||||
|
||||
util::guidance::LaneTupleIdPair lane_data = {{0, INVALID_LANEID},
|
||||
INVALID_LANE_DESCRIPTIONID};
|
||||
if (path_point.turn_edge && facade.HasLaneData(*path_point.turn_edge))
|
||||
{
|
||||
lane_data = facade.GetLaneData(*path_point.turn_edge);
|
||||
}
|
||||
|
||||
intersection.in = bearing_class.findMatchingBearing(bearings.first);
|
||||
intersection.out = bearing_class.findMatchingBearing(bearings.second);
|
||||
intersection.location = facade.GetCoordinateOfNode(path_point.turn_via_node);
|
||||
intersection.bearings.clear();
|
||||
intersection.bearings.reserve(bearing_data.size());
|
||||
intersection.lanes = path_point.lane_data.first;
|
||||
intersection.lane_description =
|
||||
path_point.lane_data.second != INVALID_LANE_DESCRIPTIONID
|
||||
? facade.GetTurnDescription(path_point.lane_data.second)
|
||||
: extractor::TurnLaneDescription();
|
||||
intersection.lanes = lane_data.first;
|
||||
intersection.lane_description = lane_data.second != INVALID_LANE_DESCRIPTIONID
|
||||
? facade.GetTurnDescription(lane_data.second)
|
||||
: extractor::TurnLaneDescription();
|
||||
|
||||
// Lanes in turn are bound by total number of lanes at the location
|
||||
BOOST_ASSERT(intersection.lanes.lanes_in_turn <=
|
||||
@@ -183,20 +208,23 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
||||
(!intersection.lane_description.empty() &&
|
||||
intersection.lanes.lanes_in_turn != 0));
|
||||
|
||||
auto entry_class = path_point.turn_edge
|
||||
? facade.GetEntryClass(*path_point.turn_edge)
|
||||
: EMPTY_ENTRY_CLASS;
|
||||
std::copy(bearing_data.begin(),
|
||||
bearing_data.end(),
|
||||
std::back_inserter(intersection.bearings));
|
||||
intersection.entry.clear();
|
||||
for (auto idx : util::irange<std::size_t>(0, intersection.bearings.size()))
|
||||
{
|
||||
intersection.entry.push_back(path_point.entry_class.allowsEntry(idx));
|
||||
intersection.entry.push_back(entry_class.allowsEntry(idx));
|
||||
}
|
||||
std::int16_t bearing_in_driving_direction =
|
||||
util::bearing::reverse(std::round(bearings.first));
|
||||
maneuver = {intersection.location,
|
||||
bearing_in_driving_direction,
|
||||
bearings.second,
|
||||
path_point.turn_instruction,
|
||||
turn_instruction,
|
||||
WaypointType::None,
|
||||
0};
|
||||
segment_index++;
|
||||
@@ -269,7 +297,7 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
||||
leg_geometry.segment_distances[segment_index],
|
||||
weight / weight_multiplier,
|
||||
source_mode,
|
||||
std::move(maneuver),
|
||||
maneuver,
|
||||
leg_geometry.FrontIndex(segment_index),
|
||||
leg_geometry.BackIndex(segment_index) + 1,
|
||||
{intersection},
|
||||
@@ -312,7 +340,7 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
||||
ZERO_DISTANCE,
|
||||
ZERO_WEIGHT,
|
||||
target_mode,
|
||||
std::move(maneuver),
|
||||
maneuver,
|
||||
leg_geometry.locations.size() - 1,
|
||||
leg_geometry.locations.size(),
|
||||
{intersection},
|
||||
|
||||
@@ -32,7 +32,7 @@ struct LegGeometry
|
||||
// length of the segment in meters
|
||||
std::vector<double> segment_distances;
|
||||
// original OSM node IDs for each coordinate
|
||||
std::vector<OSMNodeID> osm_node_ids;
|
||||
std::vector<NodeID> node_ids;
|
||||
|
||||
// Per-coordinate metadata
|
||||
struct Annotation
|
||||
|
||||
Reference in New Issue
Block a user