post processing moved onto route-steps, looses sync with geometry segments
This commit is contained in:
		
							parent
							
								
									2b0a1bbb63
								
							
						
					
					
						commit
						7bf2cb1917
					
				| @ -72,7 +72,7 @@ class RouteAPI : public BaseAPI | ||||
|     } | ||||
| 
 | ||||
|     util::json::Object MakeRoute(const std::vector<PhantomNodes> &segment_end_coordinates, | ||||
|                                  std::vector<std::vector<PathData>> unpacked_path_segments, | ||||
|                                  const std::vector<std::vector<PathData>> &unpacked_path_segments, | ||||
|                                  const std::vector<bool> &source_traversed_in_reverse, | ||||
|                                  const std::vector<bool> &target_traversed_in_reverse) const | ||||
|     { | ||||
| @ -82,7 +82,6 @@ class RouteAPI : public BaseAPI | ||||
|         legs.reserve(number_of_legs); | ||||
|         leg_geometries.reserve(number_of_legs); | ||||
| 
 | ||||
|         unpacked_path_segments = guidance::postProcess(std::move(unpacked_path_segments)); | ||||
|         for (auto idx : util::irange(0UL, number_of_legs)) | ||||
|         { | ||||
|             const auto &phantoms = segment_end_coordinates[idx]; | ||||
| @ -98,14 +97,42 @@ class RouteAPI : public BaseAPI | ||||
| 
 | ||||
|             if (parameters.steps) | ||||
|             { | ||||
|                 leg.steps = guidance::assembleSteps( | ||||
|                 auto steps = guidance::assembleSteps( | ||||
|                     BaseAPI::facade, path_data, leg_geometry, phantoms.source_phantom, | ||||
|                     phantoms.target_phantom, reversed_source, reversed_target); | ||||
| 
 | ||||
|                 /* 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. | ||||
|                  */ | ||||
| 
 | ||||
|                  leg.steps = guidance::postProcess(std::move(steps)); | ||||
|             } | ||||
| 
 | ||||
|             leg_geometries.push_back(std::move(leg_geometry)); | ||||
|             legs.push_back(std::move(leg)); | ||||
|         } | ||||
| 
 | ||||
|         auto route = guidance::assembleRoute(legs); | ||||
|         boost::optional<util::json::Value> json_overview; | ||||
|         if (parameters.overview != RouteParameters::OverviewType::False) | ||||
|  | ||||
| @ -51,7 +51,7 @@ LegGeometry assembleGeometry(const DataFacadeT &facade, | ||||
|         current_distance += | ||||
|             util::coordinate_calculation::haversineDistance(prev_coordinate, coordinate); | ||||
| 
 | ||||
|         if (!isSilent(path_point.turn_instruction)) | ||||
|         if (path_point.turn_instruction.type != extractor::guidance::TurnType::NoTurn) | ||||
|         { | ||||
|             geometry.segment_distances.push_back(current_distance); | ||||
|             geometry.segment_offsets.push_back(geometry.locations.size()); | ||||
|  | ||||
| @ -27,8 +27,7 @@ namespace detail | ||||
| StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instruction, | ||||
|                                       const WaypointType waypoint_type, | ||||
|                                       const LegGeometry &leg_geometry, | ||||
|                                       const std::size_t segment_index, | ||||
|                                       const unsigned exit); | ||||
|                                       const std::size_t segment_index); | ||||
| } // ns detail
 | ||||
| 
 | ||||
| template <typename DataFacadeT> | ||||
| @ -78,7 +77,7 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade, | ||||
|         StepManeuver maneuver = detail::stepManeuverFromGeometry( | ||||
|             extractor::guidance::TurnInstruction{extractor::guidance::TurnType::NoTurn, | ||||
|                                                  initial_modifier}, | ||||
|             WaypointType::Depart, leg_geometry, segment_index, INVALID_EXIT_NR); | ||||
|             WaypointType::Depart, leg_geometry, segment_index); | ||||
| 
 | ||||
|         // PathData saves the information we need of the segment _before_ the turn,
 | ||||
|         // but a RouteStep is with regard to the segment after the turn.
 | ||||
| @ -89,7 +88,7 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade, | ||||
|         { | ||||
|             segment_duration += path_point.duration_until_turn; | ||||
| 
 | ||||
|             if (path_point.turn_instruction != extractor::guidance::TurnInstruction::NO_TURN()) | ||||
|             if (path_point.turn_instruction.type != extractor::guidance::TurnType::NoTurn) | ||||
|             { | ||||
|                 BOOST_ASSERT(segment_duration >= 0); | ||||
|                 const auto name = facade.GetNameForID(path_point.name_id); | ||||
| @ -104,7 +103,7 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade, | ||||
|                                           leg_geometry.BackIndex(segment_index) + 1}); | ||||
|                 maneuver = detail::stepManeuverFromGeometry(path_point.turn_instruction, | ||||
|                                                             WaypointType::None, leg_geometry, | ||||
|                                                             segment_index, path_point.exit); | ||||
|                                                             segment_index); | ||||
|                 segment_index++; | ||||
|                 segment_duration = 0; | ||||
|             } | ||||
| @ -136,6 +135,7 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade, | ||||
|                                  extractor::guidance::TurnInstruction{ | ||||
|                                      extractor::guidance::TurnType::NoTurn, initial_modifier}, | ||||
|                                  WaypointType::Depart, | ||||
|                                  INVALID_EXIT_NR, | ||||
|                                  INVALID_EXIT_NR}; | ||||
|         int duration = target_duration - source_duration; | ||||
|         BOOST_ASSERT(duration >= 0); | ||||
| @ -174,6 +174,7 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade, | ||||
|                                extractor::guidance::TurnInstruction{ | ||||
|                                    extractor::guidance::TurnType::NoTurn, final_modifier}, | ||||
|                                WaypointType::Arrive, | ||||
|                                INVALID_EXIT_NR, | ||||
|                                INVALID_EXIT_NR}, | ||||
|                   leg_geometry.locations.size(), | ||||
|                   leg_geometry.locations.size()}); | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| #ifndef ENGINE_GUIDANCE_POST_PROCESSING_HPP | ||||
| #define ENGINE_GUIDANCE_POST_PROCESSING_HPP | ||||
| 
 | ||||
| #include "engine/internal_route_result.hpp" | ||||
| #include "engine/guidance/route_step.hpp" | ||||
| 
 | ||||
| #include <vector> | ||||
| 
 | ||||
| @ -12,7 +12,8 @@ namespace engine | ||||
| namespace guidance | ||||
| { | ||||
| 
 | ||||
| std::vector<std::vector<PathData>> postProcess(std::vector<std::vector<PathData>> path_data); | ||||
| //passed as none-reference to modify in-place and move out again
 | ||||
| std::vector<RouteStep> postProcess(std::vector<RouteStep> steps); | ||||
| 
 | ||||
| } // namespace guidance
 | ||||
| } // namespace engine
 | ||||
|  | ||||
| @ -28,6 +28,7 @@ struct StepManeuver | ||||
|     extractor::guidance::TurnInstruction instruction; | ||||
|     WaypointType waypoint_type; | ||||
|     unsigned exit; | ||||
|     unsigned intersection; | ||||
| }; | ||||
| } // namespace guidance
 | ||||
| } // namespace engine
 | ||||
|  | ||||
| @ -29,8 +29,6 @@ struct PathData | ||||
|     extractor::guidance::TurnInstruction turn_instruction; | ||||
|     // travel mode of the street that leads to the turn
 | ||||
|     extractor::TravelMode travel_mode : 4; | ||||
|     // exit ID of highway exit, roundabout exit, intersection nr
 | ||||
|     unsigned exit; | ||||
| }; | ||||
| 
 | ||||
| struct InternalRouteResult | ||||
|  | ||||
| @ -321,8 +321,7 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface | ||||
|                 { | ||||
|                     unpacked_path.push_back( | ||||
|                         PathData{id_vector[i], name_index, weight_vector[i], | ||||
|                                  extractor::guidance::TurnInstruction::NO_TURN(), travel_mode, | ||||
|                                  INVALID_EXIT_NR}); | ||||
|                                  extractor::guidance::TurnInstruction::NO_TURN(), travel_mode}); | ||||
|                 } | ||||
|                 BOOST_ASSERT(unpacked_path.size() > 0); | ||||
|                 unpacked_path.back().turn_instruction = turn_instruction; | ||||
| @ -396,8 +395,7 @@ template <class DataFacadeT, class Derived> class BasicRoutingInterface | ||||
|                 id_vector[i], phantom_node_pair.target_phantom.name_id, weight_vector[i], | ||||
|                 extractor::guidance::TurnInstruction::NO_TURN(), | ||||
|                 target_traversed_in_reverse ? phantom_node_pair.target_phantom.backward_travel_mode | ||||
|                                             : phantom_node_pair.target_phantom.forward_travel_mode, | ||||
|                 INVALID_EXIT_NR}); | ||||
|                                             : phantom_node_pair.target_phantom.forward_travel_mode}); | ||||
|         } | ||||
| 
 | ||||
|         if (is_local_path && unpacked_path.size() > 0) | ||||
|  | ||||
| @ -149,6 +149,12 @@ util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver) | ||||
|     step_maneuver.values["bearing_after"] = maneuver.bearing_after; | ||||
|     if (maneuver.exit != 0) | ||||
|         step_maneuver.values["exit"] = maneuver.exit; | ||||
| 
 | ||||
|     //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; | ||||
|     return step_maneuver; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -15,12 +15,11 @@ namespace detail | ||||
| StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instruction, | ||||
|                                       const WaypointType waypoint_type, | ||||
|                                       const LegGeometry &leg_geometry, | ||||
|                                       const std::size_t segment_index, | ||||
|                                       const unsigned exit) | ||||
|                                       const std::size_t segment_index) | ||||
| { | ||||
|     auto turn_index = leg_geometry.BackIndex(segment_index); | ||||
|     BOOST_ASSERT(turn_index > 0); | ||||
|     BOOST_ASSERT(turn_index < leg_geometry.locations.size()); | ||||
|     BOOST_ASSERT(turn_index + 1 < leg_geometry.locations.size()); | ||||
| 
 | ||||
|     // TODO chose a bigger look-a-head to smooth complex geometry
 | ||||
|     const auto pre_turn_coordinate = leg_geometry.locations[turn_index - 1]; | ||||
| @ -32,7 +31,13 @@ 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, waypoint_type, exit}; | ||||
|     return StepManeuver{turn_coordinate, | ||||
|                         pre_turn_bearing, | ||||
|                         post_turn_bearing, | ||||
|                         instruction, | ||||
|                         waypoint_type, | ||||
|                         INVALID_EXIT_NR, | ||||
|                         INVALID_EXIT_NR}; | ||||
| } | ||||
| } // ns detail
 | ||||
| } // ns engine
 | ||||
|  | ||||
| @ -20,194 +20,231 @@ namespace guidance | ||||
| 
 | ||||
| namespace detail | ||||
| { | ||||
| bool canMergeTrivially(const PathData &destination, const PathData &source) | ||||
| bool canMergeTrivially(const RouteStep &destination, const RouteStep &source) | ||||
| { | ||||
|     return destination.exit == 0 && destination.name_id == source.name_id && | ||||
|            destination.travel_mode == source.travel_mode && isSilent(source.turn_instruction); | ||||
|     return destination.maneuver.exit == 0 && destination.name_id == source.name_id && | ||||
|            isSilent(source.maneuver.instruction); | ||||
| } | ||||
| 
 | ||||
| PathData forwardInto(PathData destination, const PathData &source) | ||||
| RouteStep forwardInto(RouteStep destination, const RouteStep &source) | ||||
| { | ||||
|     // Merge a turn into a silent turn
 | ||||
|     // Overwrites turn instruction and increases exit NR
 | ||||
|     destination.exit = source.exit; | ||||
|     return destination; | ||||
| } | ||||
| 
 | ||||
| PathData accumulateInto(PathData destination, const PathData &source) | ||||
| { | ||||
|     // Merge a turn into a silent turn
 | ||||
|     // Overwrites turn instruction and increases exit NR
 | ||||
|     BOOST_ASSERT(canMergeTrivially(destination, source)); | ||||
|     destination.exit = source.exit + 1; | ||||
|     return destination; | ||||
| } | ||||
| 
 | ||||
| PathData mergeInto(PathData destination, const PathData &source) | ||||
| { | ||||
|     if (source.turn_instruction == TurnInstruction::NO_TURN()) | ||||
|     { | ||||
|         BOOST_ASSERT(canMergeTrivially(destination, source)); | ||||
|         return detail::forwardInto(destination, source); | ||||
|     } | ||||
|     if (source.turn_instruction.type == TurnType::Suppressed) | ||||
|     { | ||||
|         return detail::forwardInto(destination, source); | ||||
|     } | ||||
|     if (source.turn_instruction.type == TurnType::StayOnRoundabout) | ||||
|     { | ||||
|         return detail::forwardInto(destination, source); | ||||
|     } | ||||
|     if (entersRoundabout(source.turn_instruction)) | ||||
|     { | ||||
|         return detail::forwardInto(destination, source); | ||||
|     } | ||||
|     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 ); | ||||
|     return destination; | ||||
| } | ||||
| 
 | ||||
| } // namespace detail
 | ||||
| 
 | ||||
| void print(const std::vector<std::vector<PathData>> &leg_data) | ||||
| void print(const std::vector<RouteStep> &steps) | ||||
| { | ||||
|     std::cout << "Path\n"; | ||||
|     int legnr = 0; | ||||
|     for (const auto &leg : leg_data) | ||||
|     { | ||||
|         std::cout << "\tLeg: " << ++legnr << "\n"; | ||||
|     int segment = 0; | ||||
|         for (const auto &data : leg) | ||||
|     for (const auto &step : steps) | ||||
|     { | ||||
|             const auto type = static_cast<int>(data.turn_instruction.type); | ||||
|             const auto modifier = static_cast<int>(data.turn_instruction.direction_modifier); | ||||
|         const auto type = static_cast<int>(step.maneuver.instruction.type); | ||||
|         const auto modifier = static_cast<int>(step.maneuver.instruction.direction_modifier); | ||||
| 
 | ||||
|             std::cout << "\t\t[" << ++segment << "]: " << type << " " << modifier | ||||
|                       << " exit: " << data.exit << "\n"; | ||||
|         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; | ||||
|     } | ||||
| } | ||||
|     std::cout << std::endl; | ||||
| } | ||||
| 
 | ||||
| std::vector<std::vector<PathData>> postProcess(std::vector<std::vector<PathData>> leg_data) | ||||
| // Every Step Maneuver consists of the information until the turn.
 | ||||
| // This list contains a set of instructions, called silent, which should
 | ||||
| // not be part of the final output.
 | ||||
| // They are required for maintenance purposes. We can calculate the number
 | ||||
| // of exits to pass in a roundabout and the number of intersections
 | ||||
| // that we come across.
 | ||||
| 
 | ||||
| std::vector<RouteStep> postProcess(std::vector<RouteStep> steps) | ||||
| { | ||||
|     if (leg_data.empty()) | ||||
|         return leg_data; | ||||
|     // the steps should always include the first/last step in form of a location
 | ||||
|     BOOST_ASSERT(steps.size() >= 2); | ||||
|     if (steps.size() == 2) | ||||
|         return steps; | ||||
| 
 | ||||
| #define PRINT_DEBUG 0 | ||||
|     unsigned carry_exit = 0; | ||||
| #if PRINT_DEBUG | ||||
|     std::cout << "[POSTPROCESSING ITERATION]" << std::endl; | ||||
|     std::cout << "Input\n"; | ||||
|     print(leg_data); | ||||
|     print(steps); | ||||
| #endif | ||||
|     // Count Street Exits forward
 | ||||
|     bool on_roundabout = false; | ||||
|     for (auto &path_data : leg_data) | ||||
|     { | ||||
|         if (not path_data.empty()) | ||||
|             path_data[0].exit = carry_exit; | ||||
| 
 | ||||
|         for (std::size_t data_index = 0; data_index + 1 < path_data.size(); ++data_index) | ||||
|     // 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.
 | ||||
|     // In this case, exits are numbered from the start of the lag.
 | ||||
|     std::size_t last_valid_instruction = 0; | ||||
|     for (std::size_t step_index = 0; step_index < steps.size(); ++step_index) | ||||
|     { | ||||
|             if (entersRoundabout(path_data[data_index].turn_instruction)) | ||||
|         auto &step = steps[step_index]; | ||||
|         const auto instruction = step.maneuver.instruction; | ||||
|         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 | ||||
|             { | ||||
|                 path_data[data_index].exit += 1; | ||||
|                 on_roundabout = true; | ||||
|                 if (step_index + 1 < steps.size()) | ||||
|                     steps[step_index + 1].maneuver.exit = step.maneuver.exit; | ||||
|             } | ||||
| 
 | ||||
|             if (isSilent(path_data[data_index].turn_instruction) && | ||||
|                 path_data[data_index].turn_instruction != TurnInstruction::NO_TURN()) | ||||
|             { | ||||
|                 path_data[data_index].exit += 1; | ||||
|         } | ||||
|             if (leavesRoundabout(path_data[data_index].turn_instruction)) | ||||
|         else if (instruction.type == TurnType::StayOnRoundabout) | ||||
|         { | ||||
|             // increase the exit number we require passing the exit
 | ||||
|             step.maneuver.exit += 1; | ||||
|             if (step_index + 1 < steps.size()) | ||||
|                 steps[step_index + 1].maneuver.exit = step.maneuver.exit; | ||||
|         } | ||||
|         else if (leavesRoundabout(instruction)) | ||||
|         { | ||||
|             // count the exit (0 based vs 1 based counting)
 | ||||
|             step.maneuver.exit += 1; | ||||
|             if (!on_roundabout) | ||||
|             { | ||||
|                     BOOST_ASSERT(leg_data[0][0].turn_instruction.type == | ||||
|                                  TurnInstruction::NO_TURN()); | ||||
|                     if (path_data[data_index].turn_instruction.type == TurnType::ExitRoundabout) | ||||
|                         leg_data[0][0].turn_instruction.type = TurnType::EnterRoundabout; | ||||
|                     if (path_data[data_index].turn_instruction.type == TurnType::ExitRotary) | ||||
|                         leg_data[0][0].turn_instruction.type = TurnType::EnterRotary; | ||||
|                     path_data[data_index].exit += 1; | ||||
|                 } | ||||
|                 on_roundabout = false; | ||||
|             } | ||||
|             if (path_data[data_index].turn_instruction.type == TurnType::EnterRoundaboutAtExit) | ||||
|             { | ||||
|                 path_data[data_index].exit += 1; | ||||
|                 path_data[data_index].turn_instruction.type = TurnType::EnterRoundabout; | ||||
|             } | ||||
|             else if (path_data[data_index].turn_instruction.type == TurnType::EnterRotaryAtExit) | ||||
|             { | ||||
|                 path_data[data_index].exit += 1; | ||||
|                 path_data[data_index].turn_instruction.type = TurnType::EnterRotary; | ||||
| 
 | ||||
|                 // 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
 | ||||
|                 last_valid_instruction = 1; | ||||
|             } | ||||
| 
 | ||||
|             if (isSilent(path_data[data_index].turn_instruction) || | ||||
|                 entersRoundabout(path_data[data_index].turn_instruction)) | ||||
|             // 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) | ||||
|             { | ||||
|                 path_data[data_index + 1] = | ||||
|                     detail::mergeInto(path_data[data_index + 1], path_data[data_index]); | ||||
|                 // 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; | ||||
|                     } | ||||
|             carry_exit = path_data[data_index].exit; | ||||
|                     else | ||||
|                     { | ||||
|                         BOOST_ASSERT(propagation_step.maneuver.instruction.type = | ||||
|                                          TurnType::StayOnRoundabout); | ||||
|                         propagation_step.maneuver.instruction = | ||||
|                             TurnInstruction::NO_TURN(); // mark intermediate instructions invalid
 | ||||
|                     } | ||||
|                 } | ||||
| #if PRINT_DEBUG | ||||
|     std::cout << "Merged\n"; | ||||
|     print(leg_data); | ||||
| #endif | ||||
|     on_roundabout = false; | ||||
|     // Move Roundabout exit numbers to front
 | ||||
|     for (auto rev_itr = leg_data.rbegin(); rev_itr != leg_data.rend(); ++rev_itr) | ||||
|     { | ||||
|         auto &path_data = *rev_itr; | ||||
|         for (std::size_t data_index = path_data.size(); data_index > 1; --data_index) | ||||
|         { | ||||
|             if (entersRoundabout(path_data[data_index - 1].turn_instruction)) | ||||
|             { | ||||
|                 if (!on_roundabout && !leavesRoundabout(path_data[data_index - 1].turn_instruction)) | ||||
|                     path_data[data_index - 1].exit = 0; | ||||
|                 // remove exit
 | ||||
|                 step.maneuver.instruction = TurnInstruction::NO_TURN(); | ||||
|             } | ||||
|             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); | ||||
|             step.maneuver.instruction = TurnInstruction::NO_TURN(); | ||||
|         } | ||||
|         else if( !isSilent(instruction) ) | ||||
|         { | ||||
|             // Remember the last non silent instruction
 | ||||
|             last_valid_instruction = step_index; | ||||
|         } | ||||
|     } | ||||
|     // unterminated roundabout
 | ||||
|     // Move backwards through the instructions until the start and remove the exit number
 | ||||
|     // A roundabout without exit translates to enter-roundabout.
 | ||||
|     if (on_roundabout) | ||||
|     { | ||||
|                 path_data[data_index - 2].exit = path_data[data_index - 1].exit; | ||||
|             } | ||||
|             if (leavesRoundabout(path_data[data_index - 1].turn_instruction) && | ||||
|                 !entersRoundabout(path_data[data_index - 1].turn_instruction)) | ||||
|         for (std::size_t propagation_index = steps.size() - 1; propagation_index > 0; | ||||
|              --propagation_index) | ||||
|         { | ||||
|                 path_data[data_index - 2].exit = path_data[data_index - 1].exit; | ||||
|                 on_roundabout = true; | ||||
|             } | ||||
|         } | ||||
|         auto prev_leg = std::next(rev_itr); | ||||
|         if (!path_data.empty() && prev_leg != leg_data.rend()) | ||||
|             auto &propagation_step = steps[propagation_index]; | ||||
|             if (entersRoundabout(propagation_step.maneuver.instruction)) | ||||
|             { | ||||
|             if (on_roundabout && path_data[0].exit) | ||||
|                 prev_leg->back().exit = path_data[0].exit; | ||||
|                 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
 | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // 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) | ||||
|     { | ||||
|         // 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 | ||||
|     std::cout << "Move To Front\n"; | ||||
|     print(leg_data); | ||||
|     std::cout << "Merged\n"; | ||||
|     print(steps); | ||||
| #endif | ||||
|     // silence silent turns for good
 | ||||
|     for (auto &path_data : leg_data) | ||||
|     { | ||||
|         for (auto &data : path_data) | ||||
|         { | ||||
|             if (isSilent(data.turn_instruction) || (leavesRoundabout(data.turn_instruction) && | ||||
|                                                     !entersRoundabout(data.turn_instruction))) | ||||
|             { | ||||
|                 data.turn_instruction = TurnInstruction::NO_TURN(); | ||||
|                 data.exit = 0; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return leg_data; | ||||
|     return steps; | ||||
| } | ||||
| 
 | ||||
| } // namespace guidance
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user