std::vector<RouteStep> assembleSteps(const DataFacadeT &facade, const std::vector<PathData> &leg_data, const LegGeometry &leg_geometry, const PhantomNode &source_node, const PhantomNode &target_node, const bool source_traversed_in_reverse, const bool target_traversed_in_reverse) { const double constexpr ZERO_DURATION = 0., ZERO_DISTANCE = 0.; const constexpr char *NO_ROTARY_NAME = ""; 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 : source_node.forward_travel_mode; const EdgeWeight target_duration = target_traversed_in_reverse ? target_node.reverse_weight : target_node.forward_weight; const auto target_mode = target_traversed_in_reverse ? target_node.backward_travel_mode : target_node.forward_travel_mode; const auto number_of_segments = leg_geometry.GetNumberOfSegments(); std::vector<RouteStep> steps; steps.reserve(number_of_segments); std::size_t segment_index = 0; BOOST_ASSERT(leg_geometry.locations.size() >= 2); auto bearings = detail::getDepartBearings(leg_geometry); StepManeuver maneuver{source_node.location, bearings.first, bearings.second, extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::Depart, 0}; Intersection intersection{source_node.location, std::vector<short>({bearings.second}), std::vector<bool>({true}), Intersection::NO_INDEX, 0}; if (leg_data.size() > 0) { // PathData saves the information we need of the segment _before_ the turn, // but a RouteStep is with regard to the segment after the turn. // We need to skip the first segment because it is already covered by the // initial start of a route int segment_duration = 0; // some name changes are not announced in our processing. For these, we have to keep the // first name on the segment auto step_name_id = source_node.name_id; for (std::size_t leg_data_index = 0; leg_data_index < leg_data.size(); ++leg_data_index) { const auto &path_point = leg_data[leg_data_index]; segment_duration += path_point.duration_until_turn; // all changes to this check have to be matched with assemble_geometry if (path_point.turn_instruction.type != extractor::guidance::TurnType::NoTurn) { BOOST_ASSERT(segment_duration >= 0); const auto name = facade.GetNameForID(step_name_id); const auto pronunciation = facade.GetPronunciationForID(step_name_id); const auto destinations = facade.GetDestinationsForID(step_name_id); const auto distance = leg_geometry.segment_distances[segment_index]; steps.push_back(RouteStep{step_name_id, std::move(name), std::move(pronunciation), std::move(destinations), NO_ROTARY_NAME, segment_duration / 10.0, distance, path_point.travel_mode, maneuver, leg_geometry.FrontIndex(segment_index), leg_geometry.BackIndex(segment_index) + 1, {intersection}}); if (leg_data_index + 1 < leg_data.size()) { step_name_id = leg_data[leg_data_index + 1].name_id; } else { step_name_id = target_node.name_id; } bearings = detail::getIntermediateBearings(leg_geometry, segment_index); const auto entry_class = facade.GetEntryClass(path_point.entry_classid); const auto bearing_class = facade.GetBearingClass(facade.GetBearingClassID(path_point.turn_via_node)); intersection.in = bearing_class.findMatchingBearing( util::bearing::reverseBearing(bearings.first)); intersection.out = bearing_class.findMatchingBearing(bearings.second); intersection.location = facade.GetCoordinateOfNode(path_point.turn_via_node); intersection.bearings.clear(); intersection.bearings.reserve(bearing_class.getAvailableBearings().size()); std::copy(bearing_class.getAvailableBearings().begin(), bearing_class.getAvailableBearings().end(), std::back_inserter(intersection.bearings)); intersection.entry.clear(); for (auto idx : util::irange<std::size_t>(0, intersection.bearings.size())) { intersection.entry.push_back(entry_class.allowsEntry(idx)); } maneuver = {intersection.location, bearings.first, bearings.second, path_point.turn_instruction, WaypointType::None, 0}; segment_index++; segment_duration = 0; } } const auto distance = leg_geometry.segment_distances[segment_index]; const int duration = segment_duration + target_duration; BOOST_ASSERT(duration >= 0); steps.push_back(RouteStep{step_name_id, facade.GetNameForID(step_name_id), facade.GetPronunciationForID(step_name_id), facade.GetDestinationsForID(step_name_id), NO_ROTARY_NAME, duration / 10., distance, target_mode, maneuver, leg_geometry.FrontIndex(segment_index), leg_geometry.BackIndex(segment_index) + 1, {intersection}}); } // In this case the source + target are on the same edge segment else { BOOST_ASSERT(source_node.fwd_segment_position == target_node.fwd_segment_position); // s t // u-------------v // |---| source_duration // |---------| target_duration int duration = target_duration - source_duration; BOOST_ASSERT(duration >= 0); steps.push_back(RouteStep{source_node.name_id, facade.GetNameForID(source_node.name_id), facade.GetPronunciationForID(source_node.name_id), facade.GetDestinationsForID(source_node.name_id), NO_ROTARY_NAME, duration / 10., leg_geometry.segment_distances[segment_index], source_mode, std::move(maneuver), leg_geometry.FrontIndex(segment_index), leg_geometry.BackIndex(segment_index) + 1, {intersection}}); } BOOST_ASSERT(segment_index == number_of_segments - 1); bearings = detail::getArriveBearings(leg_geometry); // This step has length zero, the only reason we need it is the target location maneuver = {intersection.location, bearings.first, bearings.second, extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::Arrive, 0}; intersection = { target_node.location, std::vector<short>({static_cast<short>(util::bearing::reverseBearing(bearings.first))}), std::vector<bool>({true}), 0, Intersection::NO_INDEX}; BOOST_ASSERT(!leg_geometry.locations.empty()); steps.push_back(RouteStep{target_node.name_id, facade.GetNameForID(target_node.name_id), facade.GetPronunciationForID(target_node.name_id), facade.GetDestinationsForID(target_node.name_id), NO_ROTARY_NAME, ZERO_DURATION, ZERO_DISTANCE, target_mode, std::move(maneuver), leg_geometry.locations.size() - 1, leg_geometry.locations.size(), {intersection}}); BOOST_ASSERT(steps.front().intersections.size() == 1); BOOST_ASSERT(steps.front().intersections.front().bearings.size() == 1); BOOST_ASSERT(steps.front().intersections.front().entry.size() == 1); BOOST_ASSERT(steps.front().maneuver.waypoint_type == WaypointType::Depart); BOOST_ASSERT(steps.back().intersections.size() == 1); BOOST_ASSERT(steps.back().intersections.front().bearings.size() == 1); BOOST_ASSERT(steps.back().intersections.front().entry.size() == 1); BOOST_ASSERT(steps.back().maneuver.waypoint_type == WaypointType::Arrive); return steps; }
std::vector<RouteStep> assembleSteps(const DataFacadeT &facade, const std::vector<PathData> &leg_data, const LegGeometry &leg_geometry, const PhantomNode &source_node, const PhantomNode &target_node, const bool source_traversed_in_reverse, const bool target_traversed_in_reverse) { const double constexpr ZERO_DURATION = 0., ZERO_DISTANCE = 0.; const constexpr char *NO_ROTARY_NAME = ""; 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 : source_node.forward_travel_mode; const EdgeWeight target_duration = target_traversed_in_reverse ? target_node.reverse_weight : target_node.forward_weight; const auto target_mode = target_traversed_in_reverse ? target_node.backward_travel_mode : target_node.forward_travel_mode; const auto number_of_segments = leg_geometry.GetNumberOfSegments(); std::vector<RouteStep> steps; steps.reserve(number_of_segments); std::size_t segment_index = 0; BOOST_ASSERT(leg_geometry.locations.size() >= 2); if (leg_data.size() > 0) { StepManeuver maneuver = detail::stepManeuverFromGeometry( extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::Depart, leg_geometry); maneuver.location = source_node.location; // PathData saves the information we need of the segment _before_ the turn, // but a RouteStep is with regard to the segment after the turn. // We need to skip the first segment because it is already covered by the // initial start of a route int segment_duration = 0; for (const auto &path_point : leg_data) { segment_duration += path_point.duration_until_turn; // all changes to this check have to be matched with assemble_geometry if (path_point.turn_instruction.type != extractor::guidance::TurnType::NoTurn) { BOOST_ASSERT(segment_duration >= 0); const auto name = facade.GetNameForID(path_point.name_id); const auto distance = leg_geometry.segment_distances[segment_index]; steps.push_back(RouteStep{path_point.name_id, name, NO_ROTARY_NAME, segment_duration / 10.0, distance, path_point.travel_mode, maneuver, leg_geometry.FrontIndex(segment_index), leg_geometry.BackIndex(segment_index) + 1}); maneuver = detail::stepManeuverFromGeometry(path_point.turn_instruction, leg_geometry, segment_index); segment_index++; segment_duration = 0; } } const auto distance = leg_geometry.segment_distances[segment_index]; const int duration = segment_duration + target_duration; BOOST_ASSERT(duration >= 0); steps.push_back(RouteStep{target_node.name_id, facade.GetNameForID(target_node.name_id), NO_ROTARY_NAME, duration / 10., distance, target_mode, maneuver, leg_geometry.FrontIndex(segment_index), leg_geometry.BackIndex(segment_index) + 1}); } // In this case the source + target are on the same edge segment else { BOOST_ASSERT(source_node.fwd_segment_position == target_node.fwd_segment_position); // s t // u-------------v // |---| source_duration // |---------| target_duration StepManeuver maneuver = detail::stepManeuverFromGeometry( extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::Depart, leg_geometry); int duration = target_duration - source_duration; BOOST_ASSERT(duration >= 0); steps.push_back(RouteStep{source_node.name_id, facade.GetNameForID(source_node.name_id), NO_ROTARY_NAME, duration / 10., leg_geometry.segment_distances[segment_index], source_mode, std::move(maneuver), leg_geometry.FrontIndex(segment_index), leg_geometry.BackIndex(segment_index) + 1}); } BOOST_ASSERT(segment_index == number_of_segments - 1); // This step has length zero, the only reason we need it is the target location auto final_maneuver = detail::stepManeuverFromGeometry( extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::Arrive, leg_geometry); BOOST_ASSERT(!leg_geometry.locations.empty()); steps.push_back(RouteStep{target_node.name_id, facade.GetNameForID(target_node.name_id), NO_ROTARY_NAME, ZERO_DURATION, ZERO_DISTANCE, target_mode, final_maneuver, leg_geometry.locations.size()-1, leg_geometry.locations.size()}); return steps; }