From d645b60af4a417a34135b2515874c3e5bf2c7bb0 Mon Sep 17 00:00:00 2001 From: Michael Bell Date: Tue, 1 Jun 2021 23:42:26 +0100 Subject: [PATCH] Lazily generate optional route path data 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 --- CHANGELOG.md | 1 + include/engine/api/route_api.hpp | 170 ++++++++++-------- include/engine/guidance/assemble_geometry.hpp | 20 +-- include/engine/guidance/assemble_leg.hpp | 91 ++++++---- include/engine/guidance/assemble_steps.hpp | 64 +++++-- include/engine/guidance/leg_geometry.hpp | 2 +- include/engine/internal_route_result.hpp | 32 +--- .../routing_algorithms/routing_base.hpp | 44 +---- src/engine/guidance/post_processing.cpp | 11 +- src/extractor/edge_based_graph_factory.cpp | 2 +- .../engine/collapse_internal_route_result.cpp | 32 ++-- unit_tests/engine/guidance_assembly.cpp | 4 +- 12 files changed, 236 insertions(+), 237 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bcf36c0af3..0c2f4da3697 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - FIXED: Fixed Boost link flags in pkg-config file. [#6083](https://github.com/Project-OSRM/osrm-backend/pull/6083) - Routing: - FIXED: Fix generation of inefficient MLD partitions [#6084](https://github.com/Project-OSRM/osrm-backend/pull/6084) + - CHANGED: Lazily generate optional route path data [#6045](https://github.com/Project-OSRM/osrm-backend/pull/6045) # 5.25.0 - Changes from 5.24.0 diff --git a/include/engine/api/route_api.hpp b/include/engine/api/route_api.hpp index 4990d37c974..8e3b9d3a357 100644 --- a/include/engine/api/route_api.hpp +++ b/include/engine/api/route_api.hpp @@ -367,7 +367,7 @@ class RouteAPI : public BaseAPI // To maintain support for uses of the old default constructors, we check // if annotations property was set manually after default construction auto requested_annotations = parameters.annotations_type; - if ((parameters.annotations == true) && + if (parameters.annotations && (parameters.annotations_type == RouteParameters::AnnotationsType::None)) { requested_annotations = RouteParameters::AnnotationsType::All; @@ -497,10 +497,10 @@ class RouteAPI : public BaseAPI std::vector nodes; if (requested_annotations & RouteParameters::AnnotationsType::Nodes) { - nodes.reserve(leg_geometry.osm_node_ids.size()); - for (const auto node_id : leg_geometry.osm_node_ids) + nodes.reserve(leg_geometry.node_ids.size()); + for (const auto node_id : leg_geometry.node_ids) { - nodes.emplace_back(static_cast(node_id)); + nodes.emplace_back(static_cast(facade.GetOSMNodeIDOfNode(node_id))); } } auto nodes_vector = fb_result.CreateVector(nodes); @@ -515,7 +515,7 @@ class RouteAPI : public BaseAPI { const auto name = facade.GetDatasourceName(i); // Length of 0 indicates the first empty name, so we can stop here - if (name.size() == 0) + if (name.empty()) break; names.emplace_back( fb_result.CreateString(std::string(facade.GetDatasourceName(i)))); @@ -763,7 +763,7 @@ class RouteAPI : public BaseAPI // To maintain support for uses of the old default constructors, we check // if annotations property was set manually after default construction auto requested_annotations = parameters.annotations_type; - if ((parameters.annotations == true) && + if (parameters.annotations && (parameters.annotations_type == RouteParameters::AnnotationsType::None)) { requested_annotations = RouteParameters::AnnotationsType::All; @@ -825,10 +825,11 @@ class RouteAPI : public BaseAPI if (requested_annotations & RouteParameters::AnnotationsType::Nodes) { util::json::Array nodes; - nodes.values.reserve(leg_geometry.osm_node_ids.size()); - for (const auto node_id : leg_geometry.osm_node_ids) + nodes.values.reserve(leg_geometry.node_ids.size()); + for (const auto node_id : leg_geometry.node_ids) { - nodes.values.push_back(static_cast(node_id)); + nodes.values.push_back( + static_cast(facade.GetOSMNodeIDOfNode(node_id))); } annotation.values["nodes"] = std::move(nodes); } @@ -842,7 +843,7 @@ class RouteAPI : public BaseAPI { const auto name = facade.GetDatasourceName(i); // Length of 0 indicates the first empty name, so we can stop here - if (name.size() == 0) + if (name.empty()) break; datasource_names.values.push_back(std::string(facade.GetDatasourceName(i))); } @@ -888,81 +889,92 @@ class RouteAPI : public BaseAPI const bool reversed_source = source_traversed_in_reverse[idx]; const bool reversed_target = target_traversed_in_reverse[idx]; - auto leg_geometry = guidance::assembleGeometry(BaseAPI::facade, - path_data, - phantoms.source_phantom, - phantoms.target_phantom, - reversed_source, - reversed_target); auto leg = guidance::assembleLeg(facade, path_data, - leg_geometry, phantoms.source_phantom, phantoms.target_phantom, - reversed_target, - parameters.steps); + reversed_target); - util::Log(logDEBUG) << "Assembling steps " << std::endl; - if (parameters.steps) + guidance::LegGeometry leg_geometry; + + // Generate additional geometry data if request includes turn-by-turn steps, + // overview geometry or route geometry annotations. + // Note that overview geometry and route geometry annotations can return different + // results depending on whether turn-by-turn steps are also requested. + if (parameters.steps || parameters.annotations || + parameters.overview != RouteParameters::OverviewType::False) { - auto steps = guidance::assembleSteps(BaseAPI::facade, - path_data, - leg_geometry, - phantoms.source_phantom, - phantoms.target_phantom, - reversed_source, - reversed_target); - - // Apply maneuver overrides before any other post - // processing is performed - guidance::applyOverrides(BaseAPI::facade, steps, leg_geometry); - - // Collapse segregated steps before others - steps = guidance::collapseSegregatedTurnInstructions(std::move(steps)); - - /* Perform step-based post-processing. - * - * Using post-processing on basis of route-steps for a single leg at a time - * comes at the cost that we cannot count the correct exit for roundabouts. - * We can only emit the exit nr/intersections up to/starting at a part of the leg. - * If a roundabout is not terminated in a leg, we will end up with a - *enter-roundabout - * and exit-roundabout-nr where the exit nr is out of sync with the previous enter. - * - * | S | - * * * - * ----* * ---- - * T - * ----* * ---- - * V * * - * | | - * | | - * - * Coming from S via V to T, we end up with the legs S->V and V->T. V-T will say to - *take - * the second exit, even though counting from S it would be the third. - * For S, we only emit `roundabout` without an exit number, showing that we enter a - *roundabout - * to find a via point. - * The same exit will be emitted, though, if we should start routing at S, making - * the overall response consistent. - * - * ⚠ CAUTION: order of post-processing steps is important - * - handleRoundabouts must be called before collapseTurnInstructions that - * expects post-processed roundabouts - */ - - guidance::trimShortSegments(steps, leg_geometry); - leg.steps = guidance::handleRoundabouts(std::move(steps)); - leg.steps = guidance::collapseTurnInstructions(std::move(leg.steps)); - leg.steps = guidance::anticipateLaneChange(std::move(leg.steps)); - leg.steps = guidance::buildIntersections(std::move(leg.steps)); - leg.steps = guidance::suppressShortNameSegments(std::move(leg.steps)); - leg.steps = guidance::assignRelativeLocations(std::move(leg.steps), - leg_geometry, - phantoms.source_phantom, - phantoms.target_phantom); - leg_geometry = guidance::resyncGeometry(std::move(leg_geometry), leg.steps); + + leg_geometry = guidance::assembleGeometry(BaseAPI::facade, + path_data, + phantoms.source_phantom, + phantoms.target_phantom, + reversed_source, + reversed_target); + + util::Log(logDEBUG) << "Assembling steps " << std::endl; + if (parameters.steps) + { + leg.summary = guidance::assembleSummary( + facade, path_data, phantoms.target_phantom, reversed_target); + + auto steps = guidance::assembleSteps(BaseAPI::facade, + path_data, + leg_geometry, + phantoms.source_phantom, + phantoms.target_phantom, + reversed_source, + reversed_target); + + // Apply maneuver overrides before any other post + // processing is performed + guidance::applyOverrides(BaseAPI::facade, steps, leg_geometry); + + // Collapse segregated steps before others + steps = guidance::collapseSegregatedTurnInstructions(std::move(steps)); + + /* Perform step-based post-processing. + * + * Using post-processing on basis of route-steps for a single leg at a time + * comes at the cost that we cannot count the correct exit for roundabouts. + * We can only emit the exit nr/intersections up to/starting at a part of the + *leg. If a roundabout is not terminated in a leg, we will end up with a + *enter-roundabout + * and exit-roundabout-nr where the exit nr is out of sync with the previous + *enter. + * + * | S | + * * * + * ----* * ---- + * T + * ----* * ---- + * V * * + * | | + * | | + * + * Coming from S via V to T, we end up with the legs S->V and V->T. V-T will say + *to take the second exit, even though counting from S it would be the third. + * For S, we only emit `roundabout` without an exit number, showing that we + *enter a roundabout to find a via point. The same exit will be emitted, though, + *if we should start routing at S, making the overall response consistent. + * + * ⚠ CAUTION: order of post-processing steps is important + * - handleRoundabouts must be called before collapseTurnInstructions that + * expects post-processed roundabouts + */ + + guidance::trimShortSegments(steps, leg_geometry); + leg.steps = guidance::handleRoundabouts(std::move(steps)); + leg.steps = guidance::collapseTurnInstructions(std::move(leg.steps)); + leg.steps = guidance::anticipateLaneChange(std::move(leg.steps)); + leg.steps = guidance::buildIntersections(std::move(leg.steps)); + leg.steps = guidance::suppressShortNameSegments(std::move(leg.steps)); + leg.steps = guidance::assignRelativeLocations(std::move(leg.steps), + leg_geometry, + phantoms.source_phantom, + phantoms.target_phantom); + leg_geometry = guidance::resyncGeometry(std::move(leg_geometry), leg.steps); + } } leg_geometries.push_back(std::move(leg_geometry)); diff --git a/include/engine/guidance/assemble_geometry.hpp b/include/engine/guidance/assemble_geometry.hpp index 9e3a0deafc5..1478edf6f65 100644 --- a/include/engine/guidance/assemble_geometry.hpp +++ b/include/engine/guidance/assemble_geometry.hpp @@ -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()); diff --git a/include/engine/guidance/assemble_leg.hpp b/include/engine/guidance/assemble_leg.hpp index 0a49ae81ec6..ae6fac725a4 100644 --- a/include/engine/guidance/assemble_leg.hpp +++ b/include/engine/guidance/assemble_leg.hpp @@ -75,10 +75,14 @@ std::array summarizeRoute(const datafacade::BaseDa std::vector 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 summarizeRoute(const datafacade::BaseDa } } // namespace detail +inline std::string assembleSummary(const datafacade::BaseDataFacade &facade, + const std::vector &route_data, + const PhantomNode &target_node, + const bool target_traversed_in_reverse) +{ + auto summary_array = detail::summarizeRoute( + 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 &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::haversineDistance(prev_coordinate, coordinate); + prev_coordinate = coordinate; + } + distance += + util::coordinate_calculation::haversineDistance(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( - 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, + "", {}}; } diff --git a/include/engine/guidance/assemble_steps.hpp b/include/engine/guidance/assemble_steps.hpp index ac65a539f22..97d527c7b91 100644 --- a/include/engine/guidance/assemble_steps.hpp +++ b/include/engine/guidance/assemble_steps.hpp @@ -19,6 +19,7 @@ #include #include +#include #include namespace osrm @@ -96,7 +97,7 @@ inline std::vector 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 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 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 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 assembleSteps(const datafacade::BaseDataFacade &fa } // extract bearings - bearings = std::make_pair( - 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(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 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(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 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 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}, diff --git a/include/engine/guidance/leg_geometry.hpp b/include/engine/guidance/leg_geometry.hpp index 8374bb99261..78ebd42ad84 100644 --- a/include/engine/guidance/leg_geometry.hpp +++ b/include/engine/guidance/leg_geometry.hpp @@ -32,7 +32,7 @@ struct LegGeometry // length of the segment in meters std::vector segment_distances; // original OSM node IDs for each coordinate - std::vector osm_node_ids; + std::vector node_ids; // Per-coordinate metadata struct Annotation diff --git a/include/engine/internal_route_result.hpp b/include/engine/internal_route_result.hpp index 9f5443ffa0f..4ee80ab6a35 100644 --- a/include/engine/internal_route_result.hpp +++ b/include/engine/internal_route_result.hpp @@ -15,6 +15,7 @@ #include "util/integer_range.hpp" #include "util/typedefs.hpp" +#include #include namespace osrm @@ -28,43 +29,22 @@ struct PathData NodeID from_edge_based_node; // the internal OSRM id of the OSM node id that is the via node of the turn NodeID turn_via_node; - // name of the street that leads to the turn - unsigned name_id; - // segregated edge-based node that leads to the turn - bool is_segregated; // weight that is traveled on the segment until the turn is reached // including the turn weight, if one exists EdgeWeight weight_until_turn; - // If this segment immediately preceeds a turn, then duration_of_turn + // If this segment immediately precedes a turn, then duration_of_turn // will contain the weight of the turn. Otherwise it will be 0. EdgeWeight weight_of_turn; // duration that is traveled on the segment until the turn is reached, - // including a turn if the segment preceeds one. + // including a turn if the segment precedes one. EdgeWeight duration_until_turn; - // If this segment immediately preceeds a turn, then duration_of_turn + // If this segment immediately precedes a turn, then duration_of_turn // will contain the duration of the turn. Otherwise it will be 0. EdgeWeight duration_of_turn; - // instruction to execute at the turn - osrm::guidance::TurnInstruction turn_instruction; - // turn lane data - util::guidance::LaneTupleIdPair lane_data; - // travel mode of the street that leads to the turn - extractor::TravelMode travel_mode : 4; - // user defined classed of the street that leads to the turn - extractor::ClassData classes; - // entry class of the turn, indicating possibility of turns - util::guidance::EntryClass entry_class; - // Source of the speed value on this road segment DatasourceID datasource_id; - - // bearing (as seen from the intersection) pre-turn - osrm::guidance::TurnBearing pre_turn_bearing; - // bearing (as seen from the intersection) post-turn - osrm::guidance::TurnBearing post_turn_bearing; - - // Driving side of the turn - bool is_left_hand_driving; + // If segment precedes a turn, ID of the turn itself + boost::optional turn_edge; }; struct InternalRouteResult diff --git a/include/engine/routing_algorithms/routing_base.hpp b/include/engine/routing_algorithms/routing_base.hpp index ee564afe207..a03e7993600 100644 --- a/include/engine/routing_algorithms/routing_base.hpp +++ b/include/engine/routing_algorithms/routing_base.hpp @@ -176,11 +176,6 @@ void annotatePath(const FacadeT &facade, const auto &edge_data = facade.GetEdgeData(*edge); const auto turn_id = edge_data.turn_id; // edge-based graph edge index const auto node_id = *node_from; // edge-based graph node index - const auto name_index = facade.GetNameIndex(node_id); - const bool is_segregated = facade.IsSegregated(node_id); - const auto turn_instruction = facade.GetTurnInstructionForEdgeID(turn_id); - const extractor::TravelMode travel_mode = facade.GetTravelMode(node_id); - const auto classes = facade.GetClassData(node_id); const auto geometry_index = facade.GetGeometryIndex(node_id); get_segment_geometry(geometry_index); @@ -206,45 +201,29 @@ void annotatePath(const FacadeT &facade, } const std::size_t end_index = weight_vector.size(); - bool is_left_hand_driving = facade.IsLeftHandDriving(node_id); - BOOST_ASSERT(start_index < end_index); for (std::size_t segment_idx = start_index; segment_idx < end_index; ++segment_idx) { unpacked_path.push_back( - PathData{*node_from, + PathData{node_id, id_vector[segment_idx + 1], - name_index, - is_segregated, static_cast(weight_vector[segment_idx]), 0, static_cast(duration_vector[segment_idx]), 0, - guidance::TurnInstruction::NO_TURN(), - {{0, INVALID_LANEID}, INVALID_LANE_DESCRIPTIONID}, - travel_mode, - classes, - EMPTY_ENTRY_CLASS, datasource_vector[segment_idx], - osrm::guidance::TurnBearing(0), - osrm::guidance::TurnBearing(0), - is_left_hand_driving}); + boost::none}); } BOOST_ASSERT(unpacked_path.size() > 0); - if (facade.HasLaneData(turn_id)) - unpacked_path.back().lane_data = facade.GetLaneData(turn_id); const auto turn_duration = facade.GetDurationPenaltyForEdgeID(turn_id); const auto turn_weight = facade.GetWeightPenaltyForEdgeID(turn_id); - unpacked_path.back().entry_class = facade.GetEntryClass(turn_id); - unpacked_path.back().turn_instruction = turn_instruction; unpacked_path.back().duration_until_turn += turn_duration; unpacked_path.back().duration_of_turn = turn_duration; unpacked_path.back().weight_until_turn += turn_weight; unpacked_path.back().weight_of_turn = turn_weight; - unpacked_path.back().pre_turn_bearing = facade.PreTurnBearing(turn_id); - unpacked_path.back().post_turn_bearing = facade.PostTurnBearing(turn_id); + unpacked_path.back().turn_edge = turn_id; } std::size_t start_index = 0, end_index = 0; @@ -280,33 +259,22 @@ void annotatePath(const FacadeT &facade, // t: fwd_segment 3 // -> (U, v), (v, w), (w, x) // note that (x, t) is _not_ included but needs to be added later. - bool is_target_left_hand_driving = facade.IsLeftHandDriving(target_node_id); for (std::size_t segment_idx = start_index; segment_idx != end_index; (start_index < end_index ? ++segment_idx : --segment_idx)) { BOOST_ASSERT(segment_idx < static_cast(id_vector.size() - 1)); - BOOST_ASSERT(facade.GetTravelMode(target_node_id) > 0); unpacked_path.push_back( PathData{target_node_id, id_vector[start_index < end_index ? segment_idx + 1 : segment_idx - 1], - facade.GetNameIndex(target_node_id), - facade.IsSegregated(target_node_id), static_cast(weight_vector[segment_idx]), 0, static_cast(duration_vector[segment_idx]), 0, - guidance::TurnInstruction::NO_TURN(), - {{0, INVALID_LANEID}, INVALID_LANE_DESCRIPTIONID}, - facade.GetTravelMode(target_node_id), - facade.GetClassData(target_node_id), - EMPTY_ENTRY_CLASS, datasource_vector[segment_idx], - guidance::TurnBearing(0), - guidance::TurnBearing(0), - is_target_left_hand_driving}); + boost::none}); } - if (unpacked_path.size() > 0) + if (!unpacked_path.empty()) { const auto source_weight = start_traversed_in_reverse ? phantom_node_pair.source_phantom.reverse_weight @@ -336,7 +304,7 @@ void annotatePath(const FacadeT &facade, template double getPathDistance(const DataFacade &facade, - const std::vector unpacked_path, + const std::vector &unpacked_path, const PhantomNode &source_phantom, const PhantomNode &target_phantom) { diff --git a/src/engine/guidance/post_processing.cpp b/src/engine/guidance/post_processing.cpp index b5a28047210..5d0b17e44f9 100644 --- a/src/engine/guidance/post_processing.cpp +++ b/src/engine/guidance/post_processing.cpp @@ -279,8 +279,7 @@ void trimShortSegments(std::vector &steps, LegGeometry &geometry) geometry.locations.begin() + offset); geometry.annotations.erase(geometry.annotations.begin(), geometry.annotations.begin() + offset); - geometry.osm_node_ids.erase(geometry.osm_node_ids.begin(), - geometry.osm_node_ids.begin() + offset); + geometry.node_ids.erase(geometry.node_ids.begin(), geometry.node_ids.begin() + offset); } auto const first_bearing = steps.front().maneuver.bearing_after; @@ -377,7 +376,7 @@ void trimShortSegments(std::vector &steps, LegGeometry &geometry) // remove all the last coordinates from the geometry geometry.locations.resize(geometry.segment_offsets.back() + 1); geometry.annotations.resize(geometry.segment_offsets.back()); - geometry.osm_node_ids.resize(geometry.segment_offsets.back() + 1); + geometry.node_ids.resize(geometry.segment_offsets.back() + 1); BOOST_ASSERT(geometry.segment_distances.back() <= 1); geometry.segment_distances.pop_back(); @@ -414,7 +413,7 @@ void trimShortSegments(std::vector &steps, LegGeometry &geometry) // This can happen if the last coordinate snaps to a node in the unpacked geometry geometry.locations.pop_back(); geometry.annotations.pop_back(); - geometry.osm_node_ids.pop_back(); + geometry.node_ids.pop_back(); geometry.segment_offsets.back()--; // since the last geometry includes the location of arrival, the arrival instruction // geometry overlaps with the previous segment @@ -436,7 +435,7 @@ void trimShortSegments(std::vector &steps, LegGeometry &geometry) } BOOST_ASSERT(geometry.segment_offsets.back() + 1 == geometry.locations.size()); - BOOST_ASSERT(geometry.segment_offsets.back() + 1 == geometry.osm_node_ids.size()); + BOOST_ASSERT(geometry.segment_offsets.back() + 1 == geometry.node_ids.size()); BOOST_ASSERT(geometry.segment_offsets.back() == geometry.annotations.size()); BOOST_ASSERT(steps.back().geometry_end == geometry.locations.size()); @@ -541,7 +540,7 @@ std::vector buildIntersections(std::vector steps) { // End of road is a turn that helps to identify the location of a turn. If the turn does - // not pass by any oter intersections, the end-of-road characteristic does not improve + // not pass by any other intersections, the end-of-road characteristic does not improve // the instructions. // Here we reduce the verbosity of our output by reducing end-of-road emissions in cases // where no intersections have been passed in between. diff --git a/src/extractor/edge_based_graph_factory.cpp b/src/extractor/edge_based_graph_factory.cpp index edef3d58951..b1f94a7b63b 100644 --- a/src/extractor/edge_based_graph_factory.cpp +++ b/src/extractor/edge_based_graph_factory.cpp @@ -71,7 +71,7 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory( const extractor::LaneDescriptionMap &lane_description_map) : m_edge_based_node_container(node_data_container), m_connectivity_checksum(0), m_number_of_edge_based_nodes(0), m_coordinates(coordinates), - m_node_based_graph(std::move(node_based_graph)), m_barrier_nodes(barrier_nodes), + m_node_based_graph(node_based_graph), m_barrier_nodes(barrier_nodes), m_traffic_lights(traffic_lights), m_compressed_edge_container(compressed_edge_container), name_table(name_table), segregated_edges(segregated_edges), lane_description_map(lane_description_map) diff --git a/unit_tests/engine/collapse_internal_route_result.cpp b/unit_tests/engine/collapse_internal_route_result.cpp index fc989ba5714..c14fa3967c8 100644 --- a/unit_tests/engine/collapse_internal_route_result.cpp +++ b/unit_tests/engine/collapse_internal_route_result.cpp @@ -19,8 +19,8 @@ BOOST_AUTO_TEST_CASE(unchanged_collapse_route_result) PhantomNode target; source.forward_segment_id = {1, true}; target.forward_segment_id = {6, true}; - PathData pathy{0, 2, 17, false, 2, 3, 4, 5, 0, {}, 4, 2, {}, 2, {1.0}, {1.0}, false}; - PathData kathy{0, 1, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false}; + PathData pathy{0, 2, 2, 3, 4, 5, 2, boost::none}; + PathData kathy{0, 1, 1, 2, 3, 4, 1, boost::none}; InternalRouteResult one_leg_result; one_leg_result.unpacked_path_segments = {{pathy, kathy}}; one_leg_result.segment_end_coordinates = {PhantomNodes{source, target}}; @@ -37,13 +37,11 @@ BOOST_AUTO_TEST_CASE(unchanged_collapse_route_result) BOOST_AUTO_TEST_CASE(two_legs_to_one_leg) { - // from_edge_based_node, turn_via_node, name_id, is_segregated, weight_until_turn, - // weight_of_turn, - // duration_until_turn, duration_of_turn, turn_instruction, lane_data, travel_mode, classes, - // entry_class, datasource_id, pre_turn_bearing, post_turn_bearing, left_hand - PathData pathy{0, 2, 17, false, 2, 3, 4, 5, 0, {}, 4, 2, {}, 2, {1.0}, {1.0}, false}; - PathData kathy{0, 1, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false}; - PathData cathy{0, 3, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false}; + // from_edge_based_node, turn_via_node, weight_until_turn, weight_of_turn, + // duration_until_turn, duration_of_turn, datasource_id, turn_edge + PathData pathy{0, 2, 2, 3, 4, 5, 2, boost::none}; + PathData kathy{0, 1, 1, 2, 3, 4, 1, boost::none}; + PathData cathy{0, 3, 1, 2, 3, 4, 1, boost::none}; PhantomNode node_1; PhantomNode node_2; PhantomNode node_3; @@ -73,11 +71,11 @@ BOOST_AUTO_TEST_CASE(two_legs_to_one_leg) BOOST_AUTO_TEST_CASE(three_legs_to_two_legs) { - PathData pathy{0, 2, 17, false, 2, 3, 4, 5, 0, {}, 4, 2, {}, 2, {1.0}, {1.0}, false}; - PathData kathy{0, 1, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false}; - PathData qathy{0, 5, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false}; - PathData cathy{0, 3, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false}; - PathData mathy{0, 4, 18, false, 8, 9, 13, 4, 2, {}, 4, 2, {}, 2, {3.0}, {1.0}, false}; + PathData pathy{0, 2, 2, 3, 4, 5, 2, boost::none}; + PathData kathy{0, 1, 1, 2, 3, 4, 1, boost::none}; + PathData qathy{0, 5, 1, 2, 3, 4, 1, boost::none}; + PathData cathy{0, 3, 1, 2, 3, 4, 1, boost::none}; + PathData mathy{0, 4, 8, 9, 13, 4, 2, boost::none}; PhantomNode node_1; PhantomNode node_2; PhantomNode node_3; @@ -117,9 +115,9 @@ BOOST_AUTO_TEST_CASE(three_legs_to_two_legs) BOOST_AUTO_TEST_CASE(two_legs_to_two_legs) { - PathData pathy{0, 2, 17, false, 2, 3, 4, 5, 0, {}, 4, 2, {}, 2, {1.0}, {1.0}, false}; - PathData kathy{0, 1, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false}; - PathData cathy{0, 3, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false}; + PathData pathy{0, 2, 2, 3, 4, 5, 2, boost::none}; + PathData kathy{0, 1, 1, 2, 3, 4, 1, boost::none}; + PathData cathy{0, 3, 1, 2, 3, 4, 1, boost::none}; PhantomNode node_1; PhantomNode node_2; PhantomNode node_3; diff --git a/unit_tests/engine/guidance_assembly.cpp b/unit_tests/engine/guidance_assembly.cpp index 2560fb0466b..10ba1821dd6 100644 --- a/unit_tests/engine/guidance_assembly.cpp +++ b/unit_tests/engine/guidance_assembly.cpp @@ -92,7 +92,7 @@ BOOST_AUTO_TEST_CASE(trim_short_segments) {FloatLongitude{-73.981495}, FloatLatitude{40.768275}}}; geometry.segment_offsets = {0, 2}; geometry.segment_distances = {1.9076601161280742}; - geometry.osm_node_ids = {OSMNodeID{0}, OSMNodeID{1}, OSMNodeID{2}}; + geometry.node_ids = {NodeID{0}, NodeID{1}, NodeID{2}}; geometry.annotations = {{1.9076601161280742, 0.2, 0.2, 0}, {0, 0, 0, 0}}; trimShortSegments(steps, geometry); @@ -102,7 +102,7 @@ BOOST_AUTO_TEST_CASE(trim_short_segments) BOOST_CHECK_EQUAL(geometry.segment_offsets.back(), 1); BOOST_CHECK_EQUAL(geometry.annotations.size(), 1); BOOST_CHECK_EQUAL(geometry.locations.size(), 2); - BOOST_CHECK_EQUAL(geometry.osm_node_ids.size(), 2); + BOOST_CHECK_EQUAL(geometry.node_ids.size(), 2); } BOOST_AUTO_TEST_SUITE_END()