Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lazily generate optional route path data #6045

Merged
merged 2 commits into from
Aug 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
- CHANGED: Docker build, enabled arm64 build layer [#6172](https://github.com/Project-OSRM/osrm-backend/pull/6172)
- CHANGED: Docker build, enabled apt-get update/install caching in separate layer for build phase [#6175](https://github.com/Project-OSRM/osrm-backend/pull/6175)
- Routing:
- CHANGED: Lazily generate optional route path data [#6045](https://github.com/Project-OSRM/osrm-backend/pull/6045)
- FIXED: Completed support for no_entry and no_exit turn restrictions. [#5988](https://github.com/Project-OSRM/osrm-backend/pull/5988)
- ADDED: Add support for non-round-trips with a single fixed endpoint. [#6050](https://github.com/Project-OSRM/osrm-backend/pull/6050)

Expand Down
170 changes: 91 additions & 79 deletions include/engine/api/route_api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -497,10 +497,10 @@ class RouteAPI : public BaseAPI
std::vector<uint32_t> 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<uint64_t>(node_id));
nodes.emplace_back(static_cast<uint64_t>(facade.GetOSMNodeIDOfNode(node_id)));
}
}
auto nodes_vector = fb_result.CreateVector(nodes);
Expand All @@ -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))));
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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<std::uint64_t>(node_id));
nodes.values.push_back(
static_cast<std::uint64_t>(facade.GetOSMNodeIDOfNode(node_id)));
}
annotation.values["nodes"] = std::move(nodes);
}
Expand All @@ -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)));
}
Expand Down Expand Up @@ -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));
Expand Down
20 changes: 10 additions & 10 deletions include/engine/guidance/assemble_geometry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.;
Expand All @@ -71,19 +70,21 @@ 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());
cumulative_distance = 0.;
}

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,
Expand All @@ -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 =
Expand Down Expand Up @@ -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());
Expand Down
Loading