diff --git a/features/guidance/collapse.feature b/features/guidance/collapse.feature index a1723805a..f56264682 100644 --- a/features/guidance/collapse.feature +++ b/features/guidance/collapse.feature @@ -74,7 +74,7 @@ Feature: Collapse When I route I should get | waypoints | route | turns | locations | - | a,i | first,second,third,third | depart,turn left,turn slight left,arrive | a,b,e,i | + | a,i | first,third,third | depart,turn sharp left,arrive | a,b,i | Scenario: Segregated Intersection, Cross Belonging to Correct Street Given the node map diff --git a/include/engine/api/route_api.hpp b/include/engine/api/route_api.hpp index 3f278b9b6..70ce602ef 100644 --- a/include/engine/api/route_api.hpp +++ b/include/engine/api/route_api.hpp @@ -177,6 +177,7 @@ class RouteAPI : public BaseAPI 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::suppressSegregated(std::move(leg.steps)); leg.steps = guidance::assignRelativeLocations(std::move(leg.steps), leg_geometry, phantoms.source_phantom, diff --git a/include/engine/guidance/assemble_steps.hpp b/include/engine/guidance/assemble_steps.hpp index d5161433c..3a00a9c6f 100644 --- a/include/engine/guidance/assemble_steps.hpp +++ b/include/engine/guidance/assemble_steps.hpp @@ -56,6 +56,7 @@ inline std::vector assembleSteps(const datafacade::BaseDataFacade &fa const auto source_node_id = source_traversed_in_reverse ? source_node.reverse_segment_id.id : source_node.forward_segment_id.id; const auto source_name_id = facade.GetNameIndex(source_node_id); + bool is_segregated = facade.IsSegregated(source_node_id); const auto source_mode = facade.GetTravelMode(source_node_id); auto source_classes = facade.GetClasses(facade.GetClassData(source_node_id)); @@ -127,6 +128,7 @@ inline std::vector assembleSteps(const datafacade::BaseDataFacade &fa intersection.classes = facade.GetClasses(path_point.classes); steps.push_back(RouteStep{step_name_id, + is_segregated, name.to_string(), ref.to_string(), pronunciation.to_string(), @@ -147,10 +149,12 @@ inline std::vector assembleSteps(const datafacade::BaseDataFacade &fa 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; } else { step_name_id = facade.GetNameIndex(target_node_id); + is_segregated = facade.IsSegregated(target_node_id); } // extract bearings @@ -206,6 +210,7 @@ inline std::vector assembleSteps(const datafacade::BaseDataFacade &fa intersection.classes = facade.GetClasses(facade.GetClassData(target_node_id)); BOOST_ASSERT(duration >= 0); steps.push_back(RouteStep{step_name_id, + is_segregated, facade.GetNameForID(step_name_id).to_string(), facade.GetRefForID(step_name_id).to_string(), facade.GetPronunciationForID(step_name_id).to_string(), @@ -249,6 +254,7 @@ inline std::vector assembleSteps(const datafacade::BaseDataFacade &fa const EdgeWeight duration = std::max(0, target_duration - source_duration); steps.push_back(RouteStep{source_name_id, + is_segregated, facade.GetNameForID(source_name_id).to_string(), facade.GetRefForID(source_name_id).to_string(), facade.GetPronunciationForID(source_name_id).to_string(), @@ -290,6 +296,7 @@ inline std::vector assembleSteps(const datafacade::BaseDataFacade &fa BOOST_ASSERT(!leg_geometry.locations.empty()); steps.push_back(RouteStep{target_name_id, + facade.IsSegregated(target_node_id), facade.GetNameForID(target_name_id).to_string(), facade.GetRefForID(target_name_id).to_string(), facade.GetPronunciationForID(target_name_id).to_string(), diff --git a/include/engine/guidance/collapse_turns.hpp b/include/engine/guidance/collapse_turns.hpp index bcdca07d7..22015fa59 100644 --- a/include/engine/guidance/collapse_turns.hpp +++ b/include/engine/guidance/collapse_turns.hpp @@ -140,6 +140,8 @@ void combineRouteSteps(RouteStep &step_at_turn_location, // alias for suppressing a step, using CombineRouteStep with NoModificationStrategy only void suppressStep(RouteStep &step_at_turn_location, RouteStep &step_after_turn_location); +std::vector suppressSegregated(std::vector steps); + } /* namespace guidance */ } /* namespace osrm */ } /* namespace osrm */ diff --git a/include/engine/guidance/route_step.hpp b/include/engine/guidance/route_step.hpp index b64b0f559..bac26d465 100644 --- a/include/engine/guidance/route_step.hpp +++ b/include/engine/guidance/route_step.hpp @@ -60,6 +60,7 @@ inline IntermediateIntersection getInvalidIntersection() struct RouteStep { unsigned name_id; + bool is_segregated; std::string name; std::string ref; std::string pronunciation; @@ -164,6 +165,8 @@ inline RouteStep &RouteStep::ElongateBy(const RouteStep &following_step) following_step.intersections.begin(), following_step.intersections.end()); + is_segregated = false; + return *this; } diff --git a/include/engine/internal_route_result.hpp b/include/engine/internal_route_result.hpp index 68830daab..bcd4303dc 100644 --- a/include/engine/internal_route_result.hpp +++ b/include/engine/internal_route_result.hpp @@ -27,6 +27,8 @@ struct PathData 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; diff --git a/include/engine/routing_algorithms/routing_base.hpp b/include/engine/routing_algorithms/routing_base.hpp index 1af44f605..68fce4ff1 100644 --- a/include/engine/routing_algorithms/routing_base.hpp +++ b/include/engine/routing_algorithms/routing_base.hpp @@ -164,6 +164,9 @@ void annotatePath(const FacadeT &facade, 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); + if (is_segregated) + util::Log() << "111 Segregated node"; const auto turn_instruction = facade.GetTurnInstructionForEdgeID(turn_id); const extractor::TravelMode travel_mode = facade.GetTravelMode(node_id); const auto classes = facade.GetClassData(node_id); @@ -193,6 +196,7 @@ void annotatePath(const FacadeT &facade, { unpacked_path.push_back(PathData{id_vector[segment_idx + 1], name_index, + is_segregated, weight_vector[segment_idx], 0, duration_vector[segment_idx], @@ -266,6 +270,7 @@ void annotatePath(const FacadeT &facade, unpacked_path.push_back( PathData{id_vector[start_index < end_index ? segment_idx + 1 : segment_idx - 1], facade.GetNameIndex(target_node_id), + facade.IsSegregated(target_node_id), weight_vector[segment_idx], 0, duration_vector[segment_idx], diff --git a/src/engine/guidance/collapse_turns.cpp b/src/engine/guidance/collapse_turns.cpp index a0caec096..9ea5696df 100644 --- a/src/engine/guidance/collapse_turns.cpp +++ b/src/engine/guidance/collapse_turns.cpp @@ -51,15 +51,15 @@ double findTotalTurnAngle(const RouteStep &entry_step, const RouteStep &exit_ste util::bearing::angleBetween(entry_step_entry_bearing, exit_step_exit_bearing); // both angles are in the same direction, the total turn gets increased - //  + // // a ---- b - // \  + // \ // c // | // d // // Will be considered just like - //  + // // a -----b // | // c @@ -89,11 +89,11 @@ double findTotalTurnAngle(const RouteStep &entry_step, const RouteStep &exit_ste else { // to prevent ignoring angles like - //  + // // a -- b // | // c -- d - //  + // // We don't combine both turn angles here but keep the very first turn angle. // We choose the first one, since we consider the first maneuver in a merge range the // important one @@ -441,13 +441,14 @@ RouteSteps collapseTurnInstructions(RouteSteps steps) TransferSignageStrategy(), NoModificationStrategy()); } + // if the current collapsing triggers, we can check for advanced scenarios that only are // possible after an inital collapse step (e.g. name change right after a u-turn) - //  + // // f - e - d // | | // a - b - c - //  + // // In this scenario, bc and de might belong to a different road than a-b and f-e (since // there are no fix conventions how to label them in segregated intersections). These steps // might only become apparent after some initial collapsing @@ -479,6 +480,64 @@ RouteSteps collapseTurnInstructions(RouteSteps steps) return steps; } +std::vector suppressSegregated(std::vector steps) +{ + if (steps.size() <= 2) + return steps; + + // start of with no-op + for (auto current_step = steps.begin() + 1; current_step + 1 != steps.end(); ++current_step) + { + /// @todo All the prologue checks are taken from the collapseTurnInstructions function. + /// Factor out to the separate routing when changes will be approved. + + if (entersRoundabout(current_step->maneuver.instruction) || + staysOnRoundabout(current_step->maneuver.instruction)) + { + // If postProcess is called before then all corresponding leavesRoundabout steps are + // removed and the current roundabout step can be ignored by directly proceeding to + // the next step. + // If postProcess is not called before then all steps till the next leavesRoundabout + // step must be skipped to prevent incorrect roundabouts post-processing. + + // are we done for good? + if (current_step + 1 == steps.end()) + break; + else + continue; + } + + // only operate on actual turns + if (!hasTurnType(*current_step)) + continue; + + // don't collapse next step if it is a waypoint alread + const auto next_step = findNextTurn(current_step); + if (hasWaypointType(*next_step)) + break; + + const auto previous_step = findPreviousTurn(current_step); + + // don't collapse anything that does change modes + if (current_step->mode != next_step->mode) + continue; + + if (current_step->is_segregated) + { + /// @todo Need to apply correct combine strategies. + + util::Log() << "222 Segregated node"; + combineRouteSteps(*current_step, + *next_step, + AdjustToCombinedTurnStrategy(*previous_step), + TransferSignageStrategy(), + NoModificationStrategy()); + } + } + + return removeNoTurnInstructions(std::move(steps)); +} + } // namespace guidance } // namespace engine } // namespace osrm diff --git a/unit_tests/engine/guidance_assembly.cpp b/unit_tests/engine/guidance_assembly.cpp index 60a481594..d7ec39355 100644 --- a/unit_tests/engine/guidance_assembly.cpp +++ b/unit_tests/engine/guidance_assembly.cpp @@ -39,6 +39,7 @@ BOOST_AUTO_TEST_CASE(trim_short_segments) // Check that duplicated coordinate in the end is removed std::vector steps = {{324, + false, "Central Park West", "", "", @@ -60,6 +61,7 @@ BOOST_AUTO_TEST_CASE(trim_short_segments) 3, {intersection1}}, {324, + false, "Central Park West", "", "",