bool Hint::IsValid(const util::Coordinate new_input_coordinates,
                   const datafacade::BaseDataFacade &facade) const
{
    auto is_same_input_coordinate = new_input_coordinates.lon == phantom.input_location.lon &&
                                    new_input_coordinates.lat == phantom.input_location.lat;
    return is_same_input_coordinate && phantom.IsValid(facade.GetNumberOfNodes()) &&
           facade.GetCheckSum() == data_checksum;
}
// 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;
}
inline RouteLeg assembleLeg(const datafacade::BaseDataFacade &facade,
                            const std::vector<PathData> &route_data,
                            const LegGeometry &leg_geometry,
                            const PhantomNode &source_node,
                            const PhantomNode &target_node,
                            const bool target_traversed_in_reverse,
                            const bool needs_summary)
{
    const auto target_duration =
        (target_traversed_in_reverse ? target_node.reverse_weight : target_node.forward_weight) /
        10.;

    auto distance = std::accumulate(
        leg_geometry.segment_distances.begin(), leg_geometry.segment_distances.end(), 0.);
    auto duration = std::accumulate(route_data.begin(),
                                    route_data.end(),
                                    0.,
                                    [](const double sum, const PathData &data) {
                                        return sum + data.duration_until_turn;
                                    }) /
                    10.;

    //                 s
    //                 |
    // Given a route a---b---c  where there is a right turn at c.
    //                       |
    //                       d
    //                       |--t
    //                       e
    // (a, b, c) gets compressed to (a,c)
    // (c, d, e) gets compressed to (c,e)
    // The duration of the turn (a,c) -> (c,e) will be the duration of (a,c) (e.g. the duration
    // of (a,b,c)).
    // The phantom node of s will contain:
    // `forward_weight`: duration of (a,s)
    // `forward_offset`: 0 (its the first segment)
    // The phantom node of t will contain:
    // `forward_weight`: duration of (d,t)
    // `forward_offset`: duration of (c, d)
    // path_data will have entries for (s,b), (b, c), (c, d) but (d, t) is only
    // caputed by the phantom node. So we need to add the target duration here.
    // On local segments, the target duration is already part of the duration, however.

    duration = duration + target_duration;
    if (route_data.empty())
    {
        duration -= (target_traversed_in_reverse ? source_node.reverse_weight
                                                 : source_node.forward_weight) /
                    10.0;
    }

    std::string summary;
    if (needs_summary)
    {
        auto summary_array = detail::summarizeRoute<detail::MAX_USED_SEGMENTS>(
            route_data, target_node, target_traversed_in_reverse);
        if (route_data.empty())
            summary_array[0] = source_node.name_id;

        BOOST_ASSERT(detail::MAX_USED_SEGMENTS > 0);
        BOOST_ASSERT(summary_array.begin() != summary_array.end());
        summary = std::accumulate(std::next(summary_array.begin()),
                                  summary_array.end(),
                                  facade.GetNameForID(summary_array.front()),
                                  [&facade](std::string previous, const std::uint32_t name_id) {
                                      if (name_id != 0)
                                      {
                                          previous += ", " + facade.GetNameForID(name_id);
                                      }
                                      return previous;
                                  });
    }

    return RouteLeg{duration, distance, summary, {}};
}
示例#4
0
inline RouteLeg assembleLeg(const datafacade::BaseDataFacade &facade,
                            const std::vector<PathData> &route_data,
                            const LegGeometry &leg_geometry,
                            const PhantomNode &source_node,
                            const PhantomNode &target_node,
                            const bool target_traversed_in_reverse,
                            const bool needs_summary)
{
    const auto target_duration =
        (target_traversed_in_reverse ? target_node.reverse_weight : target_node.forward_weight) /
        10.;

    auto distance = std::accumulate(
        leg_geometry.segment_distances.begin(), leg_geometry.segment_distances.end(), 0.);
    auto duration = std::accumulate(route_data.begin(),
                                    route_data.end(),
                                    0.,
                                    [](const double sum, const PathData &data) {
                                        return sum + data.duration_until_turn;
                                    }) /
                    10.;

    //                 s
    //                 |
    // Given a route a---b---c  where there is a right turn at c.
    //                       |
    //                       d
    //                       |--t
    //                       e
    // (a, b, c) gets compressed to (a,c)
    // (c, d, e) gets compressed to (c,e)
    // The duration of the turn (a,c) -> (c,e) will be the duration of (a,c) (e.g. the duration
    // of (a,b,c)).
    // The phantom node of s will contain:
    // `forward_weight`: duration of (a,s)
    // `forward_offset`: 0 (its the first segment)
    // The phantom node of t will contain:
    // `forward_weight`: duration of (d,t)
    // `forward_offset`: duration of (c, d)
    // path_data will have entries for (s,b), (b, c), (c, d) but (d, t) is only
    // caputed by the phantom node. So we need to add the target duration here.
    // On local segments, the target duration is already part of the duration, however.

    duration = duration + target_duration;
    if (route_data.empty())
    {
        duration -= (target_traversed_in_reverse ? source_node.reverse_weight
                                                 : source_node.forward_weight) /
                    10.0;
    }

    std::string summary;
    if (needs_summary)
    {
        auto summary_array = detail::summarizeRoute<detail::MAX_USED_SEGMENTS>(
            route_data, target_node, target_traversed_in_reverse);

        BOOST_ASSERT(detail::MAX_USED_SEGMENTS > 0);
        BOOST_ASSERT(summary_array.begin() != summary_array.end());

        // transform a name_id into a string containing either the name, or -if the name is empty-
        // the reference.
        const auto name_id_to_string = [&](const NameID name_id) {
            const auto name = facade.GetNameForID(name_id);
            if (!name.empty())
                return name;
            else
            {
                const auto ref = facade.GetRefForID(name_id);
                return ref;
            }
        };

        const auto not_empty = [&](const std::string &name) { return !name.empty(); };

        const auto summary_names = summary_array | boost::adaptors::transformed(name_id_to_string) |
                                   boost::adaptors::filtered(not_empty);
        summary = boost::algorithm::join(summary_names, ", ");
    }

    return RouteLeg{duration, distance, summary, {}};
}
示例#5
0
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,
                                    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;
}