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:
parent
3cfd0e8334
commit
972a848094
@ -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 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)
|
- 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:
|
- 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)
|
- 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)
|
- ADDED: Add support for non-round-trips with a single fixed endpoint. [#6050](https://github.com/Project-OSRM/osrm-backend/pull/6050)
|
||||||
|
|
||||||
|
@ -367,7 +367,7 @@ class RouteAPI : public BaseAPI
|
|||||||
// To maintain support for uses of the old default constructors, we check
|
// To maintain support for uses of the old default constructors, we check
|
||||||
// if annotations property was set manually after default construction
|
// if annotations property was set manually after default construction
|
||||||
auto requested_annotations = parameters.annotations_type;
|
auto requested_annotations = parameters.annotations_type;
|
||||||
if ((parameters.annotations == true) &&
|
if (parameters.annotations &&
|
||||||
(parameters.annotations_type == RouteParameters::AnnotationsType::None))
|
(parameters.annotations_type == RouteParameters::AnnotationsType::None))
|
||||||
{
|
{
|
||||||
requested_annotations = RouteParameters::AnnotationsType::All;
|
requested_annotations = RouteParameters::AnnotationsType::All;
|
||||||
@ -497,10 +497,10 @@ class RouteAPI : public BaseAPI
|
|||||||
std::vector<uint32_t> nodes;
|
std::vector<uint32_t> nodes;
|
||||||
if (requested_annotations & RouteParameters::AnnotationsType::Nodes)
|
if (requested_annotations & RouteParameters::AnnotationsType::Nodes)
|
||||||
{
|
{
|
||||||
nodes.reserve(leg_geometry.osm_node_ids.size());
|
nodes.reserve(leg_geometry.node_ids.size());
|
||||||
for (const auto node_id : leg_geometry.osm_node_ids)
|
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);
|
auto nodes_vector = fb_result.CreateVector(nodes);
|
||||||
@ -515,7 +515,7 @@ class RouteAPI : public BaseAPI
|
|||||||
{
|
{
|
||||||
const auto name = facade.GetDatasourceName(i);
|
const auto name = facade.GetDatasourceName(i);
|
||||||
// Length of 0 indicates the first empty name, so we can stop here
|
// Length of 0 indicates the first empty name, so we can stop here
|
||||||
if (name.size() == 0)
|
if (name.empty())
|
||||||
break;
|
break;
|
||||||
names.emplace_back(
|
names.emplace_back(
|
||||||
fb_result.CreateString(std::string(facade.GetDatasourceName(i))));
|
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
|
// To maintain support for uses of the old default constructors, we check
|
||||||
// if annotations property was set manually after default construction
|
// if annotations property was set manually after default construction
|
||||||
auto requested_annotations = parameters.annotations_type;
|
auto requested_annotations = parameters.annotations_type;
|
||||||
if ((parameters.annotations == true) &&
|
if (parameters.annotations &&
|
||||||
(parameters.annotations_type == RouteParameters::AnnotationsType::None))
|
(parameters.annotations_type == RouteParameters::AnnotationsType::None))
|
||||||
{
|
{
|
||||||
requested_annotations = RouteParameters::AnnotationsType::All;
|
requested_annotations = RouteParameters::AnnotationsType::All;
|
||||||
@ -825,10 +825,11 @@ class RouteAPI : public BaseAPI
|
|||||||
if (requested_annotations & RouteParameters::AnnotationsType::Nodes)
|
if (requested_annotations & RouteParameters::AnnotationsType::Nodes)
|
||||||
{
|
{
|
||||||
util::json::Array nodes;
|
util::json::Array nodes;
|
||||||
nodes.values.reserve(leg_geometry.osm_node_ids.size());
|
nodes.values.reserve(leg_geometry.node_ids.size());
|
||||||
for (const auto node_id : leg_geometry.osm_node_ids)
|
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);
|
annotation.values["nodes"] = std::move(nodes);
|
||||||
}
|
}
|
||||||
@ -842,7 +843,7 @@ class RouteAPI : public BaseAPI
|
|||||||
{
|
{
|
||||||
const auto name = facade.GetDatasourceName(i);
|
const auto name = facade.GetDatasourceName(i);
|
||||||
// Length of 0 indicates the first empty name, so we can stop here
|
// Length of 0 indicates the first empty name, so we can stop here
|
||||||
if (name.size() == 0)
|
if (name.empty())
|
||||||
break;
|
break;
|
||||||
datasource_names.values.push_back(std::string(facade.GetDatasourceName(i)));
|
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_source = source_traversed_in_reverse[idx];
|
||||||
const bool reversed_target = target_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,
|
auto leg = guidance::assembleLeg(facade,
|
||||||
path_data,
|
path_data,
|
||||||
leg_geometry,
|
|
||||||
phantoms.source_phantom,
|
phantoms.source_phantom,
|
||||||
phantoms.target_phantom,
|
phantoms.target_phantom,
|
||||||
reversed_target,
|
reversed_target);
|
||||||
parameters.steps);
|
|
||||||
|
|
||||||
util::Log(logDEBUG) << "Assembling steps " << std::endl;
|
guidance::LegGeometry leg_geometry;
|
||||||
if (parameters.steps)
|
|
||||||
|
// 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
|
leg_geometry = guidance::assembleGeometry(BaseAPI::facade,
|
||||||
// processing is performed
|
path_data,
|
||||||
guidance::applyOverrides(BaseAPI::facade, steps, leg_geometry);
|
phantoms.source_phantom,
|
||||||
|
phantoms.target_phantom,
|
||||||
|
reversed_source,
|
||||||
|
reversed_target);
|
||||||
|
|
||||||
// Collapse segregated steps before others
|
util::Log(logDEBUG) << "Assembling steps " << std::endl;
|
||||||
steps = guidance::collapseSegregatedTurnInstructions(std::move(steps));
|
if (parameters.steps)
|
||||||
|
{
|
||||||
|
leg.summary = guidance::assembleSummary(
|
||||||
|
facade, path_data, phantoms.target_phantom, reversed_target);
|
||||||
|
|
||||||
/* Perform step-based post-processing.
|
auto steps = guidance::assembleSteps(BaseAPI::facade,
|
||||||
*
|
path_data,
|
||||||
* Using post-processing on basis of route-steps for a single leg at a time
|
leg_geometry,
|
||||||
* comes at the cost that we cannot count the correct exit for roundabouts.
|
phantoms.source_phantom,
|
||||||
* We can only emit the exit nr/intersections up to/starting at a part of the leg.
|
phantoms.target_phantom,
|
||||||
* If a roundabout is not terminated in a leg, we will end up with a
|
reversed_source,
|
||||||
*enter-roundabout
|
reversed_target);
|
||||||
* 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);
|
// Apply maneuver overrides before any other post
|
||||||
leg.steps = guidance::handleRoundabouts(std::move(steps));
|
// processing is performed
|
||||||
leg.steps = guidance::collapseTurnInstructions(std::move(leg.steps));
|
guidance::applyOverrides(BaseAPI::facade, steps, leg_geometry);
|
||||||
leg.steps = guidance::anticipateLaneChange(std::move(leg.steps));
|
|
||||||
leg.steps = guidance::buildIntersections(std::move(leg.steps));
|
// Collapse segregated steps before others
|
||||||
leg.steps = guidance::suppressShortNameSegments(std::move(leg.steps));
|
steps = guidance::collapseSegregatedTurnInstructions(std::move(steps));
|
||||||
leg.steps = guidance::assignRelativeLocations(std::move(leg.steps),
|
|
||||||
leg_geometry,
|
/* Perform step-based post-processing.
|
||||||
phantoms.source_phantom,
|
*
|
||||||
phantoms.target_phantom);
|
* Using post-processing on basis of route-steps for a single leg at a time
|
||||||
leg_geometry = guidance::resyncGeometry(std::move(leg_geometry), leg.steps);
|
* 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));
|
leg_geometries.push_back(std::move(leg_geometry));
|
||||||
|
@ -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_id = facade.GetGeometryIndex(source_node_id).id;
|
||||||
const auto source_geometry = facade.GetUncompressedForwardGeometry(source_geometry_id);
|
const auto source_geometry = facade.GetUncompressedForwardGeometry(source_geometry_id);
|
||||||
|
|
||||||
geometry.osm_node_ids.push_back(
|
geometry.node_ids.push_back(source_geometry(source_segment_start_coordinate));
|
||||||
facade.GetOSMNodeIDOfNode(source_geometry(source_segment_start_coordinate)));
|
|
||||||
|
|
||||||
auto cumulative_distance = 0.;
|
auto cumulative_distance = 0.;
|
||||||
auto current_distance = 0.;
|
auto current_distance = 0.;
|
||||||
@ -71,7 +70,10 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
|
|||||||
cumulative_distance += current_distance;
|
cumulative_distance += current_distance;
|
||||||
|
|
||||||
// all changes to this check have to be matched with assemble_steps
|
// 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_distances.push_back(cumulative_distance);
|
||||||
geometry.segment_offsets.push_back(geometry.locations.size());
|
geometry.segment_offsets.push_back(geometry.locations.size());
|
||||||
@ -79,11 +81,10 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
|
|||||||
}
|
}
|
||||||
|
|
||||||
prev_coordinate = coordinate;
|
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 (node_id != geometry.node_ids.back() ||
|
||||||
|
turn_instruction.type != osrm::guidance::TurnType::NoTurn)
|
||||||
if (osm_node_id != geometry.osm_node_ids.back() ||
|
|
||||||
path_point.turn_instruction.type != osrm::guidance::TurnType::NoTurn)
|
|
||||||
{
|
{
|
||||||
geometry.annotations.emplace_back(LegGeometry::Annotation{
|
geometry.annotations.emplace_back(LegGeometry::Annotation{
|
||||||
current_distance,
|
current_distance,
|
||||||
@ -99,7 +100,7 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
|
|||||||
facade.GetWeightMultiplier(),
|
facade.GetWeightMultiplier(),
|
||||||
path_point.datasource_id});
|
path_point.datasource_id});
|
||||||
geometry.locations.push_back(std::move(coordinate));
|
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 =
|
current_distance =
|
||||||
@ -158,8 +159,7 @@ inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade,
|
|||||||
const auto target_segment_end_coordinate =
|
const auto target_segment_end_coordinate =
|
||||||
target_node.fwd_segment_position + (reversed_target ? 0 : 1);
|
target_node.fwd_segment_position + (reversed_target ? 0 : 1);
|
||||||
const auto target_geometry = facade.GetUncompressedForwardGeometry(target_geometry_id);
|
const auto target_geometry = facade.GetUncompressedForwardGeometry(target_geometry_id);
|
||||||
geometry.osm_node_ids.push_back(
|
geometry.node_ids.push_back(target_geometry(target_segment_end_coordinate));
|
||||||
facade.GetOSMNodeIDOfNode(target_geometry(target_segment_end_coordinate)));
|
|
||||||
|
|
||||||
BOOST_ASSERT(geometry.segment_distances.size() == geometry.segment_offsets.size() - 1);
|
BOOST_ASSERT(geometry.segment_distances.size() == geometry.segment_offsets.size() - 1);
|
||||||
BOOST_ASSERT(geometry.locations.size() > geometry.segment_distances.size());
|
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::vector<NamedSegment> segments(route_data.size());
|
||||||
std::uint32_t index = 0;
|
std::uint32_t index = 0;
|
||||||
std::transform(
|
std::transform(route_data.begin(),
|
||||||
route_data.begin(), route_data.end(), segments.begin(), [&index](const PathData &point) {
|
route_data.end(),
|
||||||
return NamedSegment{point.duration_until_turn, index++, point.name_id};
|
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 =
|
const auto target_duration =
|
||||||
target_traversed_in_reverse ? target_node.reverse_duration : target_node.forward_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
|
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
|
} // 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,
|
inline RouteLeg assembleLeg(const datafacade::BaseDataFacade &facade,
|
||||||
const std::vector<PathData> &route_data,
|
const std::vector<PathData> &route_data,
|
||||||
const LegGeometry &leg_geometry,
|
|
||||||
const PhantomNode &source_node,
|
const PhantomNode &source_node,
|
||||||
const PhantomNode &target_node,
|
const PhantomNode &target_node,
|
||||||
const bool target_traversed_in_reverse,
|
const bool target_traversed_in_reverse)
|
||||||
const bool needs_summary)
|
|
||||||
{
|
{
|
||||||
|
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 =
|
const auto target_duration =
|
||||||
(target_traversed_in_reverse ? target_node.reverse_duration : target_node.forward_duration);
|
(target_traversed_in_reverse ? target_node.reverse_duration : target_node.forward_duration);
|
||||||
const auto target_weight =
|
const auto target_weight =
|
||||||
(target_traversed_in_reverse ? target_node.reverse_weight : target_node.forward_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(
|
auto duration = std::accumulate(
|
||||||
route_data.begin(), route_data.end(), 0, [](const double sum, const PathData &data) {
|
route_data.begin(), route_data.end(), 0, [](const double sum, const PathData &data) {
|
||||||
return sum + data.duration_until_turn;
|
return sum + data.duration_until_turn;
|
||||||
@ -182,39 +224,10 @@ inline RouteLeg assembleLeg(const datafacade::BaseDataFacade &facade,
|
|||||||
duration = std::max(0, duration);
|
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.,
|
return RouteLeg{std::round(distance * 10.) / 10.,
|
||||||
duration / 10.,
|
duration / 10.,
|
||||||
weight / facade.GetWeightMultiplier(),
|
weight / facade.GetWeightMultiplier(),
|
||||||
summary,
|
"",
|
||||||
{}};
|
{}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <guidance/turn_bearing.hpp>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
@ -96,7 +97,7 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
|||||||
{},
|
{},
|
||||||
source_classes};
|
source_classes};
|
||||||
|
|
||||||
if (leg_data.size() > 0)
|
if (!leg_data.empty())
|
||||||
{
|
{
|
||||||
// PathData saves the information we need of the segment _before_ the turn,
|
// PathData saves the information we need of the segment _before_ the turn,
|
||||||
// but a RouteStep is with regard to the segment after 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;
|
segment_weight += path_point.weight_until_turn;
|
||||||
|
|
||||||
// all changes to this check have to be matched with assemble_geometry
|
// 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);
|
BOOST_ASSERT(segment_weight >= 0);
|
||||||
const auto name = facade.GetNameForID(step_name_id);
|
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 exits = facade.GetExitsForID(step_name_id);
|
||||||
const auto distance = leg_geometry.segment_distances[segment_index];
|
const auto distance = leg_geometry.segment_distances[segment_index];
|
||||||
// intersections contain the classes of exiting road
|
// 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,
|
steps.push_back(RouteStep{path_point.from_edge_based_node,
|
||||||
step_name_id,
|
step_name_id,
|
||||||
@ -140,17 +150,19 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
|||||||
segment_duration / 10.,
|
segment_duration / 10.,
|
||||||
distance,
|
distance,
|
||||||
segment_weight / weight_multiplier,
|
segment_weight / weight_multiplier,
|
||||||
path_point.travel_mode,
|
travel_mode,
|
||||||
maneuver,
|
maneuver,
|
||||||
leg_geometry.FrontIndex(segment_index),
|
leg_geometry.FrontIndex(segment_index),
|
||||||
leg_geometry.BackIndex(segment_index) + 1,
|
leg_geometry.BackIndex(segment_index) + 1,
|
||||||
{intersection},
|
{intersection},
|
||||||
path_point.is_left_hand_driving});
|
is_left_hand_driving});
|
||||||
|
|
||||||
if (leg_data_index + 1 < leg_data.size())
|
if (leg_data_index + 1 < leg_data.size())
|
||||||
{
|
{
|
||||||
step_name_id = leg_data[leg_data_index + 1].name_id;
|
step_name_id =
|
||||||
is_segregated = leg_data[leg_data_index + 1].is_segregated;
|
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
|
else
|
||||||
{
|
{
|
||||||
@ -159,20 +171,33 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
|||||||
}
|
}
|
||||||
|
|
||||||
// extract bearings
|
// extract bearings
|
||||||
bearings = std::make_pair<std::uint16_t, std::uint16_t>(
|
auto pre_turn_bearing = path_point.turn_edge
|
||||||
path_point.pre_turn_bearing.Get(), path_point.post_turn_bearing.Get());
|
? 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);
|
const auto bearing_class = facade.GetBearingClass(path_point.turn_via_node);
|
||||||
auto bearing_data = bearing_class.getAvailableBearings();
|
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.in = bearing_class.findMatchingBearing(bearings.first);
|
||||||
intersection.out = bearing_class.findMatchingBearing(bearings.second);
|
intersection.out = bearing_class.findMatchingBearing(bearings.second);
|
||||||
intersection.location = facade.GetCoordinateOfNode(path_point.turn_via_node);
|
intersection.location = facade.GetCoordinateOfNode(path_point.turn_via_node);
|
||||||
intersection.bearings.clear();
|
intersection.bearings.clear();
|
||||||
intersection.bearings.reserve(bearing_data.size());
|
intersection.bearings.reserve(bearing_data.size());
|
||||||
intersection.lanes = path_point.lane_data.first;
|
intersection.lanes = lane_data.first;
|
||||||
intersection.lane_description =
|
intersection.lane_description = lane_data.second != INVALID_LANE_DESCRIPTIONID
|
||||||
path_point.lane_data.second != INVALID_LANE_DESCRIPTIONID
|
? facade.GetTurnDescription(lane_data.second)
|
||||||
? facade.GetTurnDescription(path_point.lane_data.second)
|
: extractor::TurnLaneDescription();
|
||||||
: extractor::TurnLaneDescription();
|
|
||||||
|
|
||||||
// Lanes in turn are bound by total number of lanes at the location
|
// Lanes in turn are bound by total number of lanes at the location
|
||||||
BOOST_ASSERT(intersection.lanes.lanes_in_turn <=
|
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.lane_description.empty() &&
|
||||||
intersection.lanes.lanes_in_turn != 0));
|
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(),
|
std::copy(bearing_data.begin(),
|
||||||
bearing_data.end(),
|
bearing_data.end(),
|
||||||
std::back_inserter(intersection.bearings));
|
std::back_inserter(intersection.bearings));
|
||||||
intersection.entry.clear();
|
intersection.entry.clear();
|
||||||
for (auto idx : util::irange<std::size_t>(0, intersection.bearings.size()))
|
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 =
|
std::int16_t bearing_in_driving_direction =
|
||||||
util::bearing::reverse(std::round(bearings.first));
|
util::bearing::reverse(std::round(bearings.first));
|
||||||
maneuver = {intersection.location,
|
maneuver = {intersection.location,
|
||||||
bearing_in_driving_direction,
|
bearing_in_driving_direction,
|
||||||
bearings.second,
|
bearings.second,
|
||||||
path_point.turn_instruction,
|
turn_instruction,
|
||||||
WaypointType::None,
|
WaypointType::None,
|
||||||
0};
|
0};
|
||||||
segment_index++;
|
segment_index++;
|
||||||
@ -269,7 +297,7 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
|||||||
leg_geometry.segment_distances[segment_index],
|
leg_geometry.segment_distances[segment_index],
|
||||||
weight / weight_multiplier,
|
weight / weight_multiplier,
|
||||||
source_mode,
|
source_mode,
|
||||||
std::move(maneuver),
|
maneuver,
|
||||||
leg_geometry.FrontIndex(segment_index),
|
leg_geometry.FrontIndex(segment_index),
|
||||||
leg_geometry.BackIndex(segment_index) + 1,
|
leg_geometry.BackIndex(segment_index) + 1,
|
||||||
{intersection},
|
{intersection},
|
||||||
@ -312,7 +340,7 @@ inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &fa
|
|||||||
ZERO_DISTANCE,
|
ZERO_DISTANCE,
|
||||||
ZERO_WEIGHT,
|
ZERO_WEIGHT,
|
||||||
target_mode,
|
target_mode,
|
||||||
std::move(maneuver),
|
maneuver,
|
||||||
leg_geometry.locations.size() - 1,
|
leg_geometry.locations.size() - 1,
|
||||||
leg_geometry.locations.size(),
|
leg_geometry.locations.size(),
|
||||||
{intersection},
|
{intersection},
|
||||||
|
@ -32,7 +32,7 @@ struct LegGeometry
|
|||||||
// length of the segment in meters
|
// length of the segment in meters
|
||||||
std::vector<double> segment_distances;
|
std::vector<double> segment_distances;
|
||||||
// original OSM node IDs for each coordinate
|
// original OSM node IDs for each coordinate
|
||||||
std::vector<OSMNodeID> osm_node_ids;
|
std::vector<NodeID> node_ids;
|
||||||
|
|
||||||
// Per-coordinate metadata
|
// Per-coordinate metadata
|
||||||
struct Annotation
|
struct Annotation
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "util/integer_range.hpp"
|
#include "util/integer_range.hpp"
|
||||||
#include "util/typedefs.hpp"
|
#include "util/typedefs.hpp"
|
||||||
|
|
||||||
|
#include <boost/optional.hpp>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
@ -28,43 +29,22 @@ struct PathData
|
|||||||
NodeID from_edge_based_node;
|
NodeID from_edge_based_node;
|
||||||
// the internal OSRM id of the OSM node id that is the via node of the turn
|
// the internal OSRM id of the OSM node id that is the via node of the turn
|
||||||
NodeID turn_via_node;
|
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
|
// weight that is traveled on the segment until the turn is reached
|
||||||
// including the turn weight, if one exists
|
// including the turn weight, if one exists
|
||||||
EdgeWeight weight_until_turn;
|
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.
|
// will contain the weight of the turn. Otherwise it will be 0.
|
||||||
EdgeWeight weight_of_turn;
|
EdgeWeight weight_of_turn;
|
||||||
// duration that is traveled on the segment until the turn is reached,
|
// 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;
|
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.
|
// will contain the duration of the turn. Otherwise it will be 0.
|
||||||
EdgeWeight duration_of_turn;
|
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
|
// Source of the speed value on this road segment
|
||||||
DatasourceID datasource_id;
|
DatasourceID datasource_id;
|
||||||
|
// If segment precedes a turn, ID of the turn itself
|
||||||
// bearing (as seen from the intersection) pre-turn
|
boost::optional<EdgeID> turn_edge;
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct InternalRouteResult
|
struct InternalRouteResult
|
||||||
|
@ -176,11 +176,6 @@ void annotatePath(const FacadeT &facade,
|
|||||||
const auto &edge_data = facade.GetEdgeData(*edge);
|
const auto &edge_data = facade.GetEdgeData(*edge);
|
||||||
const auto turn_id = edge_data.turn_id; // edge-based graph edge index
|
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 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);
|
const auto geometry_index = facade.GetGeometryIndex(node_id);
|
||||||
get_segment_geometry(geometry_index);
|
get_segment_geometry(geometry_index);
|
||||||
@ -206,45 +201,29 @@ void annotatePath(const FacadeT &facade,
|
|||||||
}
|
}
|
||||||
const std::size_t end_index = weight_vector.size();
|
const std::size_t end_index = weight_vector.size();
|
||||||
|
|
||||||
bool is_left_hand_driving = facade.IsLeftHandDriving(node_id);
|
|
||||||
|
|
||||||
BOOST_ASSERT(start_index < end_index);
|
BOOST_ASSERT(start_index < end_index);
|
||||||
for (std::size_t segment_idx = start_index; segment_idx < end_index; ++segment_idx)
|
for (std::size_t segment_idx = start_index; segment_idx < end_index; ++segment_idx)
|
||||||
{
|
{
|
||||||
unpacked_path.push_back(
|
unpacked_path.push_back(
|
||||||
PathData{*node_from,
|
PathData{node_id,
|
||||||
id_vector[segment_idx + 1],
|
id_vector[segment_idx + 1],
|
||||||
name_index,
|
|
||||||
is_segregated,
|
|
||||||
static_cast<EdgeWeight>(weight_vector[segment_idx]),
|
static_cast<EdgeWeight>(weight_vector[segment_idx]),
|
||||||
0,
|
0,
|
||||||
static_cast<EdgeDuration>(duration_vector[segment_idx]),
|
static_cast<EdgeDuration>(duration_vector[segment_idx]),
|
||||||
0,
|
0,
|
||||||
guidance::TurnInstruction::NO_TURN(),
|
|
||||||
{{0, INVALID_LANEID}, INVALID_LANE_DESCRIPTIONID},
|
|
||||||
travel_mode,
|
|
||||||
classes,
|
|
||||||
EMPTY_ENTRY_CLASS,
|
|
||||||
datasource_vector[segment_idx],
|
datasource_vector[segment_idx],
|
||||||
osrm::guidance::TurnBearing(0),
|
boost::none});
|
||||||
osrm::guidance::TurnBearing(0),
|
|
||||||
is_left_hand_driving});
|
|
||||||
}
|
}
|
||||||
BOOST_ASSERT(unpacked_path.size() > 0);
|
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_duration = facade.GetDurationPenaltyForEdgeID(turn_id);
|
||||||
const auto turn_weight = facade.GetWeightPenaltyForEdgeID(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_until_turn += turn_duration;
|
||||||
unpacked_path.back().duration_of_turn = turn_duration;
|
unpacked_path.back().duration_of_turn = turn_duration;
|
||||||
unpacked_path.back().weight_until_turn += turn_weight;
|
unpacked_path.back().weight_until_turn += turn_weight;
|
||||||
unpacked_path.back().weight_of_turn = turn_weight;
|
unpacked_path.back().weight_of_turn = turn_weight;
|
||||||
unpacked_path.back().pre_turn_bearing = facade.PreTurnBearing(turn_id);
|
unpacked_path.back().turn_edge = turn_id;
|
||||||
unpacked_path.back().post_turn_bearing = facade.PostTurnBearing(turn_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t start_index = 0, end_index = 0;
|
std::size_t start_index = 0, end_index = 0;
|
||||||
@ -280,33 +259,22 @@ void annotatePath(const FacadeT &facade,
|
|||||||
// t: fwd_segment 3
|
// t: fwd_segment 3
|
||||||
// -> (U, v), (v, w), (w, x)
|
// -> (U, v), (v, w), (w, x)
|
||||||
// note that (x, t) is _not_ included but needs to be added later.
|
// 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;
|
for (std::size_t segment_idx = start_index; segment_idx != end_index;
|
||||||
(start_index < end_index ? ++segment_idx : --segment_idx))
|
(start_index < end_index ? ++segment_idx : --segment_idx))
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(segment_idx < static_cast<std::size_t>(id_vector.size() - 1));
|
BOOST_ASSERT(segment_idx < static_cast<std::size_t>(id_vector.size() - 1));
|
||||||
BOOST_ASSERT(facade.GetTravelMode(target_node_id) > 0);
|
|
||||||
unpacked_path.push_back(
|
unpacked_path.push_back(
|
||||||
PathData{target_node_id,
|
PathData{target_node_id,
|
||||||
id_vector[start_index < end_index ? segment_idx + 1 : segment_idx - 1],
|
id_vector[start_index < end_index ? segment_idx + 1 : segment_idx - 1],
|
||||||
facade.GetNameIndex(target_node_id),
|
|
||||||
facade.IsSegregated(target_node_id),
|
|
||||||
static_cast<EdgeWeight>(weight_vector[segment_idx]),
|
static_cast<EdgeWeight>(weight_vector[segment_idx]),
|
||||||
0,
|
0,
|
||||||
static_cast<EdgeDuration>(duration_vector[segment_idx]),
|
static_cast<EdgeDuration>(duration_vector[segment_idx]),
|
||||||
0,
|
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],
|
datasource_vector[segment_idx],
|
||||||
guidance::TurnBearing(0),
|
boost::none});
|
||||||
guidance::TurnBearing(0),
|
|
||||||
is_target_left_hand_driving});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unpacked_path.size() > 0)
|
if (!unpacked_path.empty())
|
||||||
{
|
{
|
||||||
const auto source_weight = start_traversed_in_reverse
|
const auto source_weight = start_traversed_in_reverse
|
||||||
? phantom_node_pair.source_phantom.reverse_weight
|
? phantom_node_pair.source_phantom.reverse_weight
|
||||||
|
@ -279,8 +279,7 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
|
|||||||
geometry.locations.begin() + offset);
|
geometry.locations.begin() + offset);
|
||||||
geometry.annotations.erase(geometry.annotations.begin(),
|
geometry.annotations.erase(geometry.annotations.begin(),
|
||||||
geometry.annotations.begin() + offset);
|
geometry.annotations.begin() + offset);
|
||||||
geometry.osm_node_ids.erase(geometry.osm_node_ids.begin(),
|
geometry.node_ids.erase(geometry.node_ids.begin(), geometry.node_ids.begin() + offset);
|
||||||
geometry.osm_node_ids.begin() + offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const first_bearing = steps.front().maneuver.bearing_after;
|
auto const first_bearing = steps.front().maneuver.bearing_after;
|
||||||
@ -377,7 +376,7 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
|
|||||||
// remove all the last coordinates from the geometry
|
// remove all the last coordinates from the geometry
|
||||||
geometry.locations.resize(geometry.segment_offsets.back() + 1);
|
geometry.locations.resize(geometry.segment_offsets.back() + 1);
|
||||||
geometry.annotations.resize(geometry.segment_offsets.back());
|
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);
|
BOOST_ASSERT(geometry.segment_distances.back() <= 1);
|
||||||
geometry.segment_distances.pop_back();
|
geometry.segment_distances.pop_back();
|
||||||
@ -414,7 +413,7 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
|
|||||||
// This can happen if the last coordinate snaps to a node in the unpacked geometry
|
// This can happen if the last coordinate snaps to a node in the unpacked geometry
|
||||||
geometry.locations.pop_back();
|
geometry.locations.pop_back();
|
||||||
geometry.annotations.pop_back();
|
geometry.annotations.pop_back();
|
||||||
geometry.osm_node_ids.pop_back();
|
geometry.node_ids.pop_back();
|
||||||
geometry.segment_offsets.back()--;
|
geometry.segment_offsets.back()--;
|
||||||
// since the last geometry includes the location of arrival, the arrival instruction
|
// since the last geometry includes the location of arrival, the arrival instruction
|
||||||
// geometry overlaps with the previous segment
|
// geometry overlaps with the previous segment
|
||||||
@ -436,7 +435,7 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
|
|||||||
}
|
}
|
||||||
|
|
||||||
BOOST_ASSERT(geometry.segment_offsets.back() + 1 == geometry.locations.size());
|
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(geometry.segment_offsets.back() == geometry.annotations.size());
|
||||||
|
|
||||||
BOOST_ASSERT(steps.back().geometry_end == geometry.locations.size());
|
BOOST_ASSERT(steps.back().geometry_end == geometry.locations.size());
|
||||||
@ -541,7 +540,7 @@ std::vector<RouteStep> buildIntersections(std::vector<RouteStep> steps)
|
|||||||
{
|
{
|
||||||
|
|
||||||
// End of road is a turn that helps to identify the location of a turn. If the turn does
|
// 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.
|
// the instructions.
|
||||||
// Here we reduce the verbosity of our output by reducing end-of-road emissions in cases
|
// Here we reduce the verbosity of our output by reducing end-of-road emissions in cases
|
||||||
// where no intersections have been passed in between.
|
// where no intersections have been passed in between.
|
||||||
|
@ -71,7 +71,7 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory(
|
|||||||
const extractor::LaneDescriptionMap &lane_description_map)
|
const extractor::LaneDescriptionMap &lane_description_map)
|
||||||
: m_edge_based_node_container(node_data_container), m_connectivity_checksum(0),
|
: m_edge_based_node_container(node_data_container), m_connectivity_checksum(0),
|
||||||
m_number_of_edge_based_nodes(0), m_coordinates(coordinates),
|
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),
|
m_traffic_lights(traffic_lights), m_compressed_edge_container(compressed_edge_container),
|
||||||
name_table(name_table), segregated_edges(segregated_edges),
|
name_table(name_table), segregated_edges(segregated_edges),
|
||||||
lane_description_map(lane_description_map)
|
lane_description_map(lane_description_map)
|
||||||
|
@ -19,8 +19,8 @@ BOOST_AUTO_TEST_CASE(unchanged_collapse_route_result)
|
|||||||
PhantomNode target;
|
PhantomNode target;
|
||||||
source.forward_segment_id = {1, true};
|
source.forward_segment_id = {1, true};
|
||||||
target.forward_segment_id = {6, 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 pathy{0, 2, 2, 3, 4, 5, 2, boost::none};
|
||||||
PathData kathy{0, 1, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
|
PathData kathy{0, 1, 1, 2, 3, 4, 1, boost::none};
|
||||||
InternalRouteResult one_leg_result;
|
InternalRouteResult one_leg_result;
|
||||||
one_leg_result.unpacked_path_segments = {{pathy, kathy}};
|
one_leg_result.unpacked_path_segments = {{pathy, kathy}};
|
||||||
one_leg_result.segment_end_coordinates = {PhantomNodes{source, target}};
|
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)
|
BOOST_AUTO_TEST_CASE(two_legs_to_one_leg)
|
||||||
{
|
{
|
||||||
// from_edge_based_node, turn_via_node, name_id, is_segregated, weight_until_turn,
|
// from_edge_based_node, turn_via_node, weight_until_turn, weight_of_turn,
|
||||||
// weight_of_turn,
|
// duration_until_turn, duration_of_turn, datasource_id, turn_edge
|
||||||
// duration_until_turn, duration_of_turn, turn_instruction, lane_data, travel_mode, classes,
|
PathData pathy{0, 2, 2, 3, 4, 5, 2, boost::none};
|
||||||
// entry_class, datasource_id, pre_turn_bearing, post_turn_bearing, left_hand
|
PathData kathy{0, 1, 1, 2, 3, 4, 1, boost::none};
|
||||||
PathData pathy{0, 2, 17, false, 2, 3, 4, 5, 0, {}, 4, 2, {}, 2, {1.0}, {1.0}, false};
|
PathData cathy{0, 3, 1, 2, 3, 4, 1, boost::none};
|
||||||
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};
|
|
||||||
PhantomNode node_1;
|
PhantomNode node_1;
|
||||||
PhantomNode node_2;
|
PhantomNode node_2;
|
||||||
PhantomNode node_3;
|
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)
|
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 pathy{0, 2, 2, 3, 4, 5, 2, boost::none};
|
||||||
PathData kathy{0, 1, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
|
PathData kathy{0, 1, 1, 2, 3, 4, 1, boost::none};
|
||||||
PathData qathy{0, 5, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
|
PathData qathy{0, 5, 1, 2, 3, 4, 1, boost::none};
|
||||||
PathData cathy{0, 3, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
|
PathData cathy{0, 3, 1, 2, 3, 4, 1, boost::none};
|
||||||
PathData mathy{0, 4, 18, false, 8, 9, 13, 4, 2, {}, 4, 2, {}, 2, {3.0}, {1.0}, false};
|
PathData mathy{0, 4, 8, 9, 13, 4, 2, boost::none};
|
||||||
PhantomNode node_1;
|
PhantomNode node_1;
|
||||||
PhantomNode node_2;
|
PhantomNode node_2;
|
||||||
PhantomNode node_3;
|
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)
|
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 pathy{0, 2, 2, 3, 4, 5, 2, boost::none};
|
||||||
PathData kathy{0, 1, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
|
PathData kathy{0, 1, 1, 2, 3, 4, 1, boost::none};
|
||||||
PathData cathy{0, 3, 16, false, 1, 2, 3, 4, 1, {}, 3, 1, {}, 1, {2.0}, {3.0}, false};
|
PathData cathy{0, 3, 1, 2, 3, 4, 1, boost::none};
|
||||||
PhantomNode node_1;
|
PhantomNode node_1;
|
||||||
PhantomNode node_2;
|
PhantomNode node_2;
|
||||||
PhantomNode node_3;
|
PhantomNode node_3;
|
||||||
|
@ -92,7 +92,7 @@ BOOST_AUTO_TEST_CASE(trim_short_segments)
|
|||||||
{FloatLongitude{-73.981495}, FloatLatitude{40.768275}}};
|
{FloatLongitude{-73.981495}, FloatLatitude{40.768275}}};
|
||||||
geometry.segment_offsets = {0, 2};
|
geometry.segment_offsets = {0, 2};
|
||||||
geometry.segment_distances = {1.9076601161280742};
|
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}};
|
geometry.annotations = {{1.9076601161280742, 0.2, 0.2, 0}, {0, 0, 0, 0}};
|
||||||
|
|
||||||
trimShortSegments(steps, geometry);
|
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.segment_offsets.back(), 1);
|
||||||
BOOST_CHECK_EQUAL(geometry.annotations.size(), 1);
|
BOOST_CHECK_EQUAL(geometry.annotations.size(), 1);
|
||||||
BOOST_CHECK_EQUAL(geometry.locations.size(), 2);
|
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()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
Loading…
Reference in New Issue
Block a user