From 548754290358cd2e994bb7cad59c7146d2e97b60 Mon Sep 17 00:00:00 2001 From: Moritz Kobitzsch Date: Tue, 22 Mar 2016 14:17:17 +0100 Subject: [PATCH] added list of intersections to the step-maneuver, not in api so far --- include/engine/guidance/assemble_steps.hpp | 4 +- include/engine/guidance/step_maneuver.hpp | 11 +- src/engine/api/json_factory.cpp | 4 +- src/engine/guidance/assemble_steps.cpp | 32 ++- src/engine/guidance/post_processing.cpp | 291 ++++++++++++--------- 5 files changed, 200 insertions(+), 142 deletions(-) diff --git a/include/engine/guidance/assemble_steps.hpp b/include/engine/guidance/assemble_steps.hpp index c7d4902c153..13ff4c965fe 100644 --- a/include/engine/guidance/assemble_steps.hpp +++ b/include/engine/guidance/assemble_steps.hpp @@ -43,7 +43,7 @@ std::vector assembleSteps(const DataFacadeT &facade, const bool source_traversed_in_reverse, const bool target_traversed_in_reverse) { - const double constexpr ZERO_DURACTION = 0., ZERO_DISTANCE = 0.; + const double constexpr ZERO_DURATION = 0., ZERO_DISTANCE = 0.; const EdgeWeight source_duration = source_traversed_in_reverse ? source_node.reverse_weight : source_node.forward_weight; const auto source_mode = source_traversed_in_reverse ? source_node.backward_travel_mode @@ -167,7 +167,7 @@ std::vector assembleSteps(const DataFacadeT &facade, WaypointType::Arrive, leg_geometry); steps.push_back(RouteStep{target_node.name_id, facade.GetNameForID(target_node.name_id), - ZERO_DURACTION, + ZERO_DURATION, ZERO_DISTANCE, target_mode, final_maneuver, diff --git a/include/engine/guidance/step_maneuver.hpp b/include/engine/guidance/step_maneuver.hpp index 1a2bb02faad..5ae70f9f6ba 100644 --- a/include/engine/guidance/step_maneuver.hpp +++ b/include/engine/guidance/step_maneuver.hpp @@ -5,6 +5,7 @@ #include "extractor/guidance/turn_instruction.hpp" #include +#include namespace osrm { @@ -20,6 +21,14 @@ enum class WaypointType : std::uint8_t Depart, }; +//A represenetation of intermediate intersections +struct IntermediateIntersection +{ + double duration; + double distance; + util::Coordinate location; +}; + struct StepManeuver { util::Coordinate location; @@ -28,7 +37,7 @@ struct StepManeuver extractor::guidance::TurnInstruction instruction; WaypointType waypoint_type; unsigned exit; - unsigned intersection; + std::vector intersections; }; } // namespace guidance } // namespace engine diff --git a/src/engine/api/json_factory.cpp b/src/engine/api/json_factory.cpp index 56d6d3008bd..123ded8016e 100644 --- a/src/engine/api/json_factory.cpp +++ b/src/engine/api/json_factory.cpp @@ -153,8 +153,8 @@ util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver) //TODO currently we need this to comply with the api. //We should move this to an additional entry, the moment we //actually compute the correct locations of the intersections - if (maneuver.intersection != 0 && maneuver.exit == 0 ) - step_maneuver.values["exit"] = maneuver.intersection; + if (!maneuver.intersections.empty() && maneuver.exit == 0 ) + step_maneuver.values["exit"] = maneuver.intersections.size(); return step_maneuver; } diff --git a/src/engine/guidance/assemble_steps.cpp b/src/engine/guidance/assemble_steps.cpp index 84b5fa61999..9b701e18faa 100644 --- a/src/engine/guidance/assemble_steps.cpp +++ b/src/engine/guidance/assemble_steps.cpp @@ -37,13 +37,15 @@ StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instr pre_turn_bearing = util::coordinate_calculation::bearing(pre_turn_coordinate, turn_coordinate); } - return StepManeuver{turn_coordinate, - pre_turn_bearing, - post_turn_bearing, - instruction, - waypoint_type, - INVALID_EXIT_NR, - INVALID_EXIT_NR}; + return StepManeuver{ + std::move(turn_coordinate), + pre_turn_bearing, + post_turn_bearing, + std::move(instruction), + waypoint_type, + INVALID_EXIT_NR, + {} // no intermediate intersections + }; } StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instruction, @@ -64,13 +66,15 @@ StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instr const double post_turn_bearing = util::coordinate_calculation::bearing(turn_coordinate, post_turn_coordinate); - return StepManeuver{turn_coordinate, - pre_turn_bearing, - post_turn_bearing, - instruction, - WaypointType::None, - INVALID_EXIT_NR, - INVALID_EXIT_NR}; + return StepManeuver{ + std::move(turn_coordinate), + pre_turn_bearing, + post_turn_bearing, + std::move(instruction), + WaypointType::None, + INVALID_EXIT_NR, + {} // no intermediate intersections + }; } } // ns detail } // ns engine diff --git a/src/engine/guidance/post_processing.cpp b/src/engine/guidance/post_processing.cpp index 2ecbce477d6..e4d9380b877 100644 --- a/src/engine/guidance/post_processing.cpp +++ b/src/engine/guidance/post_processing.cpp @@ -4,8 +4,11 @@ #include "engine/guidance/toolkit.hpp" #include +#include + #include -#include +#include +#include using TurnInstruction = osrm::extractor::guidance::TurnInstruction; using TurnType = osrm::extractor::guidance::TurnType; @@ -32,11 +35,126 @@ RouteStep forwardInto(RouteStep destination, const RouteStep &source) // Overwrites turn instruction and increases exit NR destination.duration += source.duration; destination.distance += source.distance; - destination.geometry_begin = std::min( destination.geometry_begin, source.geometry_begin ); - destination.geometry_end = std::max( destination.geometry_end, source.geometry_end ); + destination.geometry_begin = std::min(destination.geometry_begin, source.geometry_begin); + destination.geometry_end = std::max(destination.geometry_end, source.geometry_end); return destination; } +void fixFinalRoundabout(std::vector &steps) +{ + for (std::size_t propagation_index = steps.size() - 1; propagation_index > 0; + --propagation_index) + { + auto &propagation_step = steps[propagation_index]; + if (entersRoundabout(propagation_step.maneuver.instruction)) + { + propagation_step.maneuver.exit = 0; + propagation_step.geometry_end = steps.back().geometry_begin; + break; + } + else if (propagation_step.maneuver.instruction.type == TurnType::StayOnRoundabout) + { + //TODO this operates on the data that is in the instructions. + //We are missing out on the final segment after the last stay-on-roundabout + //instruction though. it is not contained somewhere until now + steps[propagation_index - 1] = + forwardInto(std::move(steps[propagation_index - 1]), propagation_step); + propagation_step.maneuver.instruction = + TurnInstruction::NO_TURN(); // mark intermediate instructions invalid + } + } +} + +bool setUpRoundabout(RouteStep &step) +{ + // basic entry into a roundabout + // Special case handling, if an entry is directly tied to an exit + const auto instruction = step.maneuver.instruction; + if (instruction.type == TurnType::EnterRotaryAtExit || + instruction.type == TurnType::EnterRoundaboutAtExit) + { + step.maneuver.exit = 1; + // prevent futher special case handling of these two. + if (instruction.type == TurnType::EnterRotaryAtExit) + step.maneuver.instruction = TurnType::EnterRotary; + else + step.maneuver.instruction = TurnType::EnterRoundabout; + } + + if (leavesRoundabout(instruction)) + { + step.maneuver.exit = 1; // count the otherwise missing exit + if (instruction.type == TurnType::EnterRotaryAtExit) + step.maneuver.instruction = TurnType::EnterRotary; + else + step.maneuver.instruction = TurnType::EnterRoundabout; + return false; + } + else + { + return true; + } +} + +void closeOffRoundabout(const bool on_roundabout, + std::vector &steps, + const std::size_t step_index) +{ + auto &step = steps[step_index]; + step.maneuver.exit += 1; + if (!on_roundabout) + { + + // We reached a special case that requires the addition of a special route step in + // the beginning. + // We started in a roundabout, so to announce the exit, we move use the exit + // instruction and + // move it right to the beginning to make sure to immediately announce the exit. + BOOST_ASSERT(leavesRoundabout(steps[1].maneuver.instruction) || + steps[1].maneuver.instruction.type == TurnType::StayOnRoundabout); + steps[0].geometry_end = 1; + steps[1] = detail::forwardInto(steps[1], steps[0]); + steps[0].duration = 0; + steps[0].distance = 0; + steps[1].maneuver.instruction.type = step.maneuver.instruction.type == TurnType::ExitRotary + ? TurnType::EnterRotary + : TurnType::EnterRoundabout; + } + + // Normal exit from the roundabout, or exit from a previously fixed roundabout. + // Propagate the index back to the entering + // location and + // prepare the current silent set of instructions for removal. + if (step_index > 1) + { + // The very first route-step is head, so we cannot iterate past that one + for (std::size_t propagation_index = step_index - 1; propagation_index > 0; + --propagation_index) + { + auto &propagation_step = steps[propagation_index]; + propagation_step = detail::forwardInto(propagation_step, steps[propagation_index + 1]); + if (entersRoundabout(propagation_step.maneuver.instruction)) + { + // TODO at this point, we can remember the additional name for a rotary + // This requires some initial thought on the data format, though + propagation_step.maneuver.exit = step.maneuver.exit; + propagation_step.geometry_end = step.geometry_end; + propagation_step.name = step.name; + propagation_step.name_id = step.name_id; + break; + } + else + { + BOOST_ASSERT(propagation_step.maneuver.instruction.type = + TurnType::StayOnRoundabout); + propagation_step.maneuver.instruction = + TurnInstruction::NO_TURN(); // mark intermediate instructions invalid + } + } + // remove exit + step.maneuver.instruction = TurnInstruction::NO_TURN(); + } +} } // namespace detail void print(const std::vector &steps) @@ -51,8 +169,13 @@ void print(const std::vector &steps) std::cout << "\t[" << ++segment << "]: " << type << " " << modifier << " Duration: " << step.duration << " Distance: " << step.distance << " Geometry: " << step.geometry_begin << " " << step.geometry_end - << " exit: " << step.maneuver.exit << " Intersection: " << step.maneuver.intersection << " name[" << step.name_id - << "]: " << step.name << std::endl; + << " exit: " << step.maneuver.exit + << " Intersections: " << step.maneuver.intersections.size() << " ["; + + for (auto intersection : step.maneuver.intersections) + std::cout << "(" << intersection.duration << " " << intersection.distance << ")"; + + std::cout << "] name[" << step.name_id << "]: " << step.name << std::endl; } } @@ -70,8 +193,8 @@ std::vector postProcess(std::vector steps) if (steps.size() == 2) return steps; -#define PRINT_DEBUG 0 -#if PRINT_DEBUG +#define OSRM_POST_PROCESSING_PRINT_DEBUG 0 +#if OSRM_POST_PROCESSING_PRINT_DEBUG std::cout << "[POSTPROCESSING ITERATION]" << std::endl; std::cout << "Input\n"; print(steps); @@ -79,6 +202,18 @@ std::vector postProcess(std::vector steps) // Count Street Exits forward bool on_roundabout = false; + // adds an intersection to the initial route step + // It includes the length of the last step, until the intersection + // Also updates the length of the respective segment + auto addIntersection = + [](RouteStep into, const RouteStep &last_step, const RouteStep &intersection) + { + into.maneuver.intersections.push_back( + {last_step.duration, last_step.distance, intersection.maneuver.location}); + + return detail::forwardInto(std::move(into), intersection); + }; + // count the exits forward. if enter/exit roundabout happen both, no further treatment is // required. We might end up with only one of them (e.g. starting within a roundabout) // or having a via-point in the roundabout. @@ -91,33 +226,9 @@ std::vector postProcess(std::vector steps) if (entersRoundabout(instruction)) { last_valid_instruction = step_index; - // basic entry into a roundabout - // Special case handling, if an entry is directly tied to an exit - if (instruction.type == TurnType::EnterRotaryAtExit || - instruction.type == TurnType::EnterRoundaboutAtExit) - { - step.maneuver.exit = 1; - // prevent futher special case handling of these two. - if (instruction.type == TurnType::EnterRotaryAtExit) - step.maneuver.instruction = TurnType::EnterRotary; - else - step.maneuver.instruction = TurnType::EnterRoundabout; - } - - if (leavesRoundabout(instruction)) - { - step.maneuver.exit = 1; // count the otherwise missing exit - if (instruction.type == TurnType::EnterRotaryAtExit) - step.maneuver.instruction = TurnType::EnterRotary; - else - step.maneuver.instruction = TurnType::EnterRoundabout; - } - else - { - on_roundabout = true; - if (step_index + 1 < steps.size()) - steps[step_index + 1].maneuver.exit = step.maneuver.exit; - } + on_roundabout = detail::setUpRoundabout(step); + if (on_roundabout && step_index + 1 < steps.size()) + steps[step_index + 1].maneuver.exit = step.maneuver.exit; } else if (instruction.type == TurnType::StayOnRoundabout) { @@ -128,77 +239,25 @@ std::vector postProcess(std::vector steps) } else if (leavesRoundabout(instruction)) { - // count the exit (0 based vs 1 based counting) - step.maneuver.exit += 1; if (!on_roundabout) { - - // We reached a special case that requires the addition of a special route step in - // the beginning. - // We started in a roundabout, so to announce the exit, we move use the exit - // instruction and - // move it right to the beginning to make sure to immediately announce the exit. - BOOST_ASSERT(leavesRoundabout(steps[1].maneuver.instruction) || - steps[1].maneuver.instruction.type == TurnType::StayOnRoundabout); - steps[0].geometry_end = 1; - steps[1] = detail::forwardInto(steps[1], steps[0]); - steps[0].duration = 0; - steps[0].distance = 0; - steps[1].maneuver.instruction.type = - step.maneuver.instruction.type == TurnType::ExitRotary - ? TurnType::EnterRotary - : TurnType::EnterRoundabout; - - //remember the now enter-instruction as valid + // in case the we are not on a roundabout, the very first instruction + // after the depart will be transformed into a roundabout and become + // the first valid instruction last_valid_instruction = 1; } - - // Normal exit from the roundabout, or exit from a previously fixed roundabout. - // Propagate the index back to the entering - // location and - // prepare the current silent set of instructions for removal. - if (step_index > 1) - { - // The very first route-step is head, so we cannot iterate past that one - for (std::size_t propagation_index = step_index - 1; propagation_index > 0; - --propagation_index) - { - auto &propagation_step = steps[propagation_index]; - propagation_step = - detail::forwardInto(propagation_step, steps[propagation_index + 1]); - if (entersRoundabout(propagation_step.maneuver.instruction)) - { - // TODO at this point, we can remember the additional name for a rotary - // This requires some initial thought on the data format, though - propagation_step.maneuver.exit = step.maneuver.exit; - propagation_step.geometry_end = step.geometry_end; - propagation_step.name = step.name; - propagation_step.name_id = step.name_id; - break; - } - else - { - BOOST_ASSERT(propagation_step.maneuver.instruction.type = - TurnType::StayOnRoundabout); - propagation_step.maneuver.instruction = - TurnInstruction::NO_TURN(); // mark intermediate instructions invalid - } - } - // remove exit - step.maneuver.instruction = TurnInstruction::NO_TURN(); - } + detail::closeOffRoundabout(on_roundabout, steps, step_index); on_roundabout = false; } else if (instruction.type == TurnType::Suppressed) { - // count intersections. We cannot use exit, since intersections can follow directly after a roundabout - steps[last_valid_instruction].maneuver.intersection += 1; - - steps[last_valid_instruction] = - detail::forwardInto(steps[last_valid_instruction], step); + // count intersections. We cannot use exit, since intersections can follow directly + // after a roundabout + steps[last_valid_instruction] = addIntersection( + std::move(steps[last_valid_instruction]), steps[step_index - 1], step); step.maneuver.instruction = TurnInstruction::NO_TURN(); } - else if( !isSilent(instruction) ) + else if (!isSilent(instruction)) { // Remember the last non silent instruction last_valid_instruction = step_index; @@ -209,38 +268,24 @@ std::vector postProcess(std::vector steps) // A roundabout without exit translates to enter-roundabout. if (on_roundabout) { - for (std::size_t propagation_index = steps.size() - 1; propagation_index > 0; - --propagation_index) - { - auto &propagation_step = steps[propagation_index]; - if (entersRoundabout(propagation_step.maneuver.instruction)) - { - propagation_step.maneuver.exit = 0; - break; - } - else if (propagation_step.maneuver.instruction == TurnType::StayOnRoundabout) - { - propagation_step.maneuver.instruction = - TurnInstruction::NO_TURN(); // mark intermediate instructions invalid - } - } + detail::fixFinalRoundabout(steps); } // finally clean up the post-processed instructions. - // Remove all, now NO_TURN instructions for the set of steps - auto pos = steps.begin(); - for (auto check = steps.begin(); check != steps.end(); ++check) + // Remove all invalid instructions from the set of instructions. + // An instruction is invalid, if its NO_TURN and has WaypointType::None. + // Two valid NO_TURNs exist in each leg in the form of Depart/Arrive + + // keep valid instructions + const auto not_is_valid = [](const RouteStep &step) { - // keep valid instrucstions - if (check->maneuver.instruction != TurnInstruction::NO_TURN() || - check->maneuver.waypoint_type != WaypointType::None) - { - *pos = *check; - ++pos; - } - } - steps.erase(pos, steps.end()); -#if PRINT_DEBUG + return step.maneuver.instruction == TurnInstruction::NO_TURN() && + step.maneuver.waypoint_type == WaypointType::None; + }; + + boost::remove_erase_if(steps, not_is_valid); + +#if OSRM_POST_PROCESSING_PRINT_DEBUG std::cout << "Merged\n"; print(steps); #endif