inline std::vector<RouteStep> assembleSteps(const datafacade::BaseDataFacade &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, util::guidance::LaneTuple(), {}}; 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 ref = facade.GetRefForID(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(ref), std::move(pronunciation), std::move(destinations), NO_ROTARY_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, {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; } // extract bearings bearings = std::make_pair<std::uint16_t, std::uint16_t>( path_point.pre_turn_bearing.Get(), path_point.post_turn_bearing.Get()); const auto entry_class = facade.GetEntryClass(path_point.entry_classid); const auto bearing_class = facade.GetBearingClass(facade.GetBearingClassID(path_point.turn_via_node)); auto bearing_data = bearing_class.getAvailableBearings(); intersection.in = bearing_class.findMatchingBearing(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()); intersection.lanes = path_point.lane_data.first; intersection.lane_description = path_point.lane_data.second != INVALID_LANE_DESCRIPTIONID ? facade.GetTurnDescription(path_point.lane_data.second) : extractor::guidance::TurnLaneDescription(); 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)); } std::int16_t bearing_in_driving_direction = util::bearing::reverseBearing(std::round(bearings.first)); maneuver = {intersection.location, bearing_in_driving_direction, 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.GetRefForID(step_name_id), facade.GetPronunciationForID(step_name_id), facade.GetDestinationsForID(step_name_id), NO_ROTARY_NAME, 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.GetRefForID(source_node.name_id), facade.GetPronunciationForID(source_node.name_id), facade.GetDestinationsForID(source_node.name_id), NO_ROTARY_NAME, 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); intersection = { target_node.location, std::vector<short>({static_cast<short>(util::bearing::reverseBearing(bearings.first))}), std::vector<bool>({true}), 0, Intersection::NO_INDEX, util::guidance::LaneTuple(), {}}; // 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}; BOOST_ASSERT(!leg_geometry.locations.empty()); steps.push_back(RouteStep{target_node.name_id, facade.GetNameForID(target_node.name_id), facade.GetRefForID(target_node.name_id), facade.GetPronunciationForID(target_node.name_id), facade.GetDestinationsForID(target_node.name_id), NO_ROTARY_NAME, 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); BOOST_ASSERT(steps.back().intersections.front().lanes.lanes_in_turn == 0); BOOST_ASSERT(steps.back().intersections.front().lanes.first_lane_from_the_right == INVALID_LANEID); BOOST_ASSERT(steps.back().intersections.front().lane_description.empty()); return steps; }
// Extracts the geometry for each segment and calculates the traveled distance // Combines the geometry form the phantom node with the PathData // to the full route geometry. // // turn 0 1 2 3 4 // s...x...y...z...t // |---|segment 0 // |---| segment 1 // |---| segment 2 // |---| segment 3 inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade, const std::vector<PathData> &leg_data, const PhantomNode &source_node, const PhantomNode &target_node) { LegGeometry geometry; // segment 0 first and last geometry.segment_offsets.push_back(0); geometry.locations.push_back(source_node.location); // Need to get the node ID preceding the source phantom node // TODO: check if this was traversed in reverse? std::vector<NodeID> reverse_geometry; facade.GetUncompressedGeometry(source_node.reverse_packed_geometry_id, reverse_geometry); geometry.osm_node_ids.push_back(facade.GetOSMNodeIDOfNode( reverse_geometry[reverse_geometry.size() - source_node.fwd_segment_position - 1])); std::vector<uint8_t> forward_datasource_vector; facade.GetUncompressedDatasources(source_node.forward_packed_geometry_id, forward_datasource_vector); auto cumulative_distance = 0.; auto current_distance = 0.; auto prev_coordinate = geometry.locations.front(); for (const auto &path_point : leg_data) { auto coordinate = facade.GetCoordinateOfNode(path_point.turn_via_node); current_distance = util::coordinate_calculation::haversineDistance(prev_coordinate, coordinate); cumulative_distance += current_distance; // all changes to this check have to be matched with assemble_steps if (path_point.turn_instruction.type != extractor::guidance::TurnType::NoTurn) { geometry.segment_distances.push_back(cumulative_distance); geometry.segment_offsets.push_back(geometry.locations.size()); cumulative_distance = 0.; } prev_coordinate = coordinate; geometry.annotations.emplace_back(LegGeometry::Annotation{ current_distance, path_point.duration_until_turn / 10., path_point.datasource_id}); geometry.locations.push_back(std::move(coordinate)); geometry.osm_node_ids.push_back(facade.GetOSMNodeIDOfNode(path_point.turn_via_node)); } current_distance = util::coordinate_calculation::haversineDistance(prev_coordinate, target_node.location); cumulative_distance += current_distance; // segment leading to the target node geometry.segment_distances.push_back(cumulative_distance); std::vector<DatasourceID> forward_datasources; facade.GetUncompressedDatasources(target_node.forward_packed_geometry_id, forward_datasources); geometry.annotations.emplace_back( LegGeometry::Annotation{current_distance, target_node.forward_weight / 10., forward_datasources[target_node.fwd_segment_position]}); geometry.segment_offsets.push_back(geometry.locations.size()); geometry.locations.push_back(target_node.location); // Need to get the node ID following the destination phantom node // TODO: check if this was traversed in reverse?? std::vector<NodeID> forward_geometry; facade.GetUncompressedGeometry(target_node.forward_packed_geometry_id, forward_geometry); geometry.osm_node_ids.push_back( facade.GetOSMNodeIDOfNode(forward_geometry[target_node.fwd_segment_position])); BOOST_ASSERT(geometry.segment_distances.size() == geometry.segment_offsets.size() - 1); BOOST_ASSERT(geometry.locations.size() > geometry.segment_distances.size()); BOOST_ASSERT(geometry.annotations.size() == geometry.locations.size() - 1); return geometry; }
// Extracts the geometry for each segment and calculates the traveled distance // Combines the geometry form the phantom node with the PathData // to the full route geometry. // // turn 0 1 2 3 4 // s...x...y...z...t // |---|segment 0 // |---| segment 1 // |---| segment 2 // |---| segment 3 inline LegGeometry assembleGeometry(const datafacade::BaseDataFacade &facade, const std::vector<PathData> &leg_data, const PhantomNode &source_node, const PhantomNode &target_node, const bool reversed_source, const bool reversed_target) { LegGeometry geometry; // segment 0 first and last geometry.segment_offsets.push_back(0); geometry.locations.push_back(source_node.location); // u * v // 0 -- 1 -- 2 -- 3 // fwd_segment_position: 1 // source node fwd: 1 1 -> 2 -> 3 // source node rev: 2 0 <- 1 <- 2 const auto source_segment_start_coordinate = source_node.fwd_segment_position + (reversed_source ? 1 : 0); const auto source_node_id = reversed_source ? source_node.reverse_segment_id.id : source_node.forward_segment_id.id; const auto source_gemetry_id = facade.GetGeometryIndex(source_node_id).id; const std::vector<NodeID> source_geometry = facade.GetUncompressedForwardGeometry(source_gemetry_id); geometry.osm_node_ids.push_back( facade.GetOSMNodeIDOfNode(source_geometry[source_segment_start_coordinate])); auto cumulative_distance = 0.; auto current_distance = 0.; auto prev_coordinate = geometry.locations.front(); for (const auto &path_point : leg_data) { auto coordinate = facade.GetCoordinateOfNode(path_point.turn_via_node); current_distance = util::coordinate_calculation::haversineDistance(prev_coordinate, coordinate); cumulative_distance += current_distance; // all changes to this check have to be matched with assemble_steps if (path_point.turn_instruction.type != extractor::guidance::TurnType::NoTurn) { geometry.segment_distances.push_back(cumulative_distance); geometry.segment_offsets.push_back(geometry.locations.size()); cumulative_distance = 0.; } prev_coordinate = coordinate; geometry.annotations.emplace_back( LegGeometry::Annotation{current_distance, path_point.duration_until_turn / 10., path_point.weight_until_turn / facade.GetWeightMultiplier(), path_point.datasource_id}); geometry.locations.push_back(std::move(coordinate)); geometry.osm_node_ids.push_back(facade.GetOSMNodeIDOfNode(path_point.turn_via_node)); } current_distance = util::coordinate_calculation::haversineDistance(prev_coordinate, target_node.location); cumulative_distance += current_distance; // segment leading to the target node geometry.segment_distances.push_back(cumulative_distance); const auto target_node_id = reversed_target ? target_node.reverse_segment_id.id : target_node.forward_segment_id.id; const auto target_gemetry_id = facade.GetGeometryIndex(target_node_id).id; const std::vector<DatasourceID> forward_datasources = facade.GetUncompressedForwardDatasources(target_gemetry_id); // FIXME if source and target phantoms are on the same segment then duration and weight // will be from one projected point till end of segment // testbot/weight.feature:Start and target on the same and adjacent edge geometry.annotations.emplace_back(LegGeometry::Annotation{ current_distance, (reversed_target ? target_node.reverse_duration : target_node.forward_duration) / 10., (reversed_target ? target_node.reverse_weight : target_node.forward_weight) / facade.GetWeightMultiplier(), forward_datasources[target_node.fwd_segment_position]}); geometry.segment_offsets.push_back(geometry.locations.size()); geometry.locations.push_back(target_node.location); // u * v // 0 -- 1 -- 2 -- 3 // fwd_segment_position: 1 // target node fwd: 2 0 -> 1 -> 2 // target node rev: 1 1 <- 2 <- 3 const auto target_segment_end_coordinate = target_node.fwd_segment_position + (reversed_target ? 0 : 1); const std::vector<NodeID> target_geometry = facade.GetUncompressedForwardGeometry(target_gemetry_id); geometry.osm_node_ids.push_back( facade.GetOSMNodeIDOfNode(target_geometry[target_segment_end_coordinate])); BOOST_ASSERT(geometry.segment_distances.size() == geometry.segment_offsets.size() - 1); BOOST_ASSERT(geometry.locations.size() > geometry.segment_distances.size()); BOOST_ASSERT(geometry.annotations.size() == geometry.locations.size() - 1); return geometry; }