inline bool StallAtNode(const DataFacadeT &facade,
                         const NodeID node,
                         const EdgeWeight weight,
                         QueryHeap &query_heap) const
 {
     for (auto edge : facade.GetAdjacentEdgeRange(node))
     {
         const auto &data = facade.GetEdgeData(edge);
         const bool reverse_flag = ((!forward_direction) ? data.forward : data.backward);
         if (reverse_flag)
         {
             const NodeID to = facade.GetTarget(edge);
             const int edge_weight = data.weight;
             BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
             if (query_heap.WasInserted(to))
             {
                 if (query_heap.GetKey(to) + edge_weight < weight)
                 {
                     return true;
                 }
             }
         }
     }
     return false;
 }
    inline void RelaxOutgoingEdges(const DataFacadeT &facade,
                                   const NodeID node,
                                   const EdgeWeight weight,
                                   QueryHeap &query_heap) const
    {
        for (auto edge : facade.GetAdjacentEdgeRange(node))
        {
            const auto &data = facade.GetEdgeData(edge);
            const bool direction_flag = (forward_direction ? data.forward : data.backward);
            if (direction_flag)
            {
                const NodeID to = facade.GetTarget(edge);
                const int edge_weight = data.weight;

                BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
                const int to_weight = weight + edge_weight;

                // New Node discovered -> Add to Heap + Node Info Storage
                if (!query_heap.WasInserted(to))
                {
                    query_heap.Insert(to, to_weight, node);
                }
                // Found a shorter Path -> Update weight
                else if (to_weight < query_heap.GetKey(to))
                {
                    // new parent
                    query_heap.GetData(to).parent = node;
                    query_heap.DecreaseKey(to, to_weight);
                }
            }
        }
    }
Example #3
0
    std::vector<PhantomNode> GetPhantomNodes(const RouteParameters &route_parameters)
    {
        const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());
        const auto &input_bearings = route_parameters.bearings;

        std::vector<PhantomNode> phantom_node_list;
        phantom_node_list.reserve(route_parameters.coordinates.size());

        // find phantom nodes for all input coords
        for (const auto i : osrm::irange<std::size_t>(0, route_parameters.coordinates.size()))
        {
            // if client hints are helpful, encode hints
            if (checksum_OK && i < route_parameters.hints.size() &&
                !route_parameters.hints[i].empty())
            {
                PhantomNode current_phantom_node;
                ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], current_phantom_node);
                if (current_phantom_node.is_valid(facade->GetNumberOfNodes()))
                {
                    phantom_node_list.push_back(std::move(current_phantom_node));
                    continue;
                }
            }
            const int bearing = input_bearings.size() > 0 ? input_bearings[i].first : 0;
            const int range = input_bearings.size() > 0
                                  ? (input_bearings[i].second ? *input_bearings[i].second : 10)
                                  : 180;
            auto results = facade->NearestPhantomNodes(route_parameters.coordinates[i], 1, bearing, range);
            if (results.empty())
            {
                break;
            }
            phantom_node_list.push_back(std::move(results.front().phantom_node));
            BOOST_ASSERT(phantom_node_list.back().is_valid(facade->GetNumberOfNodes()));
        }

        return phantom_node_list;
    }
Example #4
0
    inline osrm::json::Object BuildHintData(const InternalRouteResult& raw_route) const
    {
        osrm::json::Object json_hint_object;
        json_hint_object.values["checksum"] = facade->GetCheckSum();
        osrm::json::Array json_location_hint_array;
        std::string hint;
        for (const auto i : osrm::irange<std::size_t>(0, raw_route.segment_end_coordinates.size()))
        {
            ObjectEncoder::EncodeToBase64(raw_route.segment_end_coordinates[i].source_phantom,
                                          hint);
            json_location_hint_array.values.push_back(hint);
        }
        ObjectEncoder::EncodeToBase64(raw_route.segment_end_coordinates.back().target_phantom,
                                      hint);
        json_location_hint_array.values.push_back(hint);
        json_hint_object.values["locations"] = json_location_hint_array;

        return json_hint_object;
    }
Example #5
0
 unsigned DescribeLeg(const std::vector<PathData> &route_leg,
                      const PhantomNodes &leg_phantoms,
                      const bool target_traversed_in_reverse,
                      const bool is_via_leg)
 {
     unsigned added_element_count = 0;
     // Get all the coordinates for the computed route
     FixedPointCoordinate current_coordinate;
     for (const PathData &path_data : route_leg)
     {
         current_coordinate = facade->GetCoordinateOfNode(path_data.node);
         description_factory.AppendSegment(current_coordinate, path_data);
         ++added_element_count;
     }
     description_factory.SetEndSegment(leg_phantoms.target_phantom, target_traversed_in_reverse,
                                       is_via_leg);
     ++added_element_count;
     BOOST_ASSERT((route_leg.size() + 1) == added_element_count);
     return added_element_count;
 }
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;
}
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;
}
Example #8
0
    Status HandleRequest(const RouteParameters &route_parameters,
                      osrm::json::Object &json_result) override final
    {
        if (max_locations_viaroute > 0 &&
            (static_cast<int>(route_parameters.coordinates.size()) > max_locations_viaroute))
        {
            json_result.values["status_message"] =
                "Number of entries " + std::to_string(route_parameters.coordinates.size()) +
                " is higher than current maximum (" + std::to_string(max_locations_viaroute) + ")";
            return Status::Error;
        }

        if (!check_all_coordinates(route_parameters.coordinates))
        {
            json_result.values["status_message"] = "Invalid coordinates";
            return Status::Error;
        }

        const auto &input_bearings = route_parameters.bearings;
        if (input_bearings.size() > 0 &&
            route_parameters.coordinates.size() != input_bearings.size())
        {
            json_result.values["status_message"] =
                "Number of bearings does not match number of coordinate";
            return Status::Error;
        }

        std::vector<PhantomNodePair> phantom_node_pair_list(route_parameters.coordinates.size());
        const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());

        for (const auto i : osrm::irange<std::size_t>(0, route_parameters.coordinates.size()))
        {
            if (checksum_OK && i < route_parameters.hints.size() &&
                !route_parameters.hints[i].empty())
            {
                ObjectEncoder::DecodeFromBase64(route_parameters.hints[i],
                                                phantom_node_pair_list[i].first);
                if (phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes()))
                {
                    continue;
                }
            }
            const int bearing = input_bearings.size() > 0 ? input_bearings[i].first : 0;
            const int range = input_bearings.size() > 0
                                  ? (input_bearings[i].second ? *input_bearings[i].second : 10)
                                  : 180;
            phantom_node_pair_list[i] = facade->NearestPhantomNodeWithAlternativeFromBigComponent(
                route_parameters.coordinates[i], bearing, range);
            // we didn't found a fitting node, return error
            if (!phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes()))
            {
                json_result.values["status_message"] =
                    std::string("Could not find a matching segment for coordinate ") +
                    std::to_string(i);
                return Status::NoSegment;
            }
            BOOST_ASSERT(phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes()));
            BOOST_ASSERT(phantom_node_pair_list[i].second.is_valid(facade->GetNumberOfNodes()));
        }

        auto snapped_phantoms = snapPhantomNodes(phantom_node_pair_list);

        InternalRouteResult raw_route;
        auto build_phantom_pairs = [&raw_route](const PhantomNode &first_node,
                                                const PhantomNode &second_node)
        {
            raw_route.segment_end_coordinates.push_back(PhantomNodes{first_node, second_node});
        };
        osrm::for_each_pair(snapped_phantoms, build_phantom_pairs);

        if (1 == raw_route.segment_end_coordinates.size())
        {
            if (route_parameters.alternate_route)
            {
                search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(),
                                                    raw_route);
            }
            else
            {
                search_engine_ptr->direct_shortest_path(raw_route.segment_end_coordinates,
                                                        route_parameters.uturns, raw_route);
            }
        }
        else
        {
            search_engine_ptr->shortest_path(raw_route.segment_end_coordinates,
                                             route_parameters.uturns, raw_route);
        }

        bool no_route = INVALID_EDGE_WEIGHT == raw_route.shortest_path_length;

        std::unique_ptr<BaseDescriptor<DataFacadeT>> descriptor;
        switch (descriptor_table.get_id(route_parameters.output_format))
        {
        case 1:
            descriptor = osrm::make_unique<GPXDescriptor<DataFacadeT>>(facade);
            break;
        // case 2:
        //      descriptor = osrm::make_unique<GEOJSONDescriptor<DataFacadeT>>();
        //      break;
        default:
            descriptor = osrm::make_unique<JSONDescriptor<DataFacadeT>>(facade);
            break;
        }

        descriptor->SetConfig(route_parameters);
        descriptor->Run(raw_route, json_result);

        // we can only know this after the fact, different SCC ids still
        // allow for connection in one direction.
        if (no_route)
        {
            auto first_component_id = snapped_phantoms.front().component.id;
            auto not_in_same_component =
                std::any_of(snapped_phantoms.begin(), snapped_phantoms.end(),
                            [first_component_id](const PhantomNode &node)
                            {
                                return node.component.id != first_component_id;
                            });
            if (not_in_same_component)
            {
                json_result.values["status_message"] = "Impossible route between points";
                return Status::EmptyResult;
            }
        }
        else
        {
            json_result.values["status_message"] = "Found route between points";
        }

        return Status::Ok;
    }
Example #9
0
    int HandleRequest(const RouteParameters &route_parameters,
                      osrm::json::Object &json_result) override final
    {
        if (!check_all_coordinates(route_parameters.coordinates))
        {
            return 400;
        }

        std::vector<phantom_node_pair> phantom_node_pair_list(route_parameters.coordinates.size());
        const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());

        for (const auto i : osrm::irange<std::size_t>(0, route_parameters.coordinates.size()))
        {
            if (checksum_OK && i < route_parameters.hints.size() &&
                !route_parameters.hints[i].empty())
            {
                ObjectEncoder::DecodeFromBase64(route_parameters.hints[i],
                                                phantom_node_pair_list[i]);
                if (phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes()))
                {
                    continue;
                }
            }
            std::vector<PhantomNode> phantom_node_vector;
            if (facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates[i],
                                                                phantom_node_vector, 1))
            {
                BOOST_ASSERT(!phantom_node_vector.empty());
                phantom_node_pair_list[i].first = phantom_node_vector.front();
                if (phantom_node_vector.size() > 1)
                {
                    phantom_node_pair_list[i].second = phantom_node_vector.back();
                }
            }
        }

        auto check_component_id_is_tiny = [](const phantom_node_pair &phantom_pair)
        {
            return phantom_pair.first.component_id != 0;
        };

        const bool every_phantom_is_in_tiny_cc =
            std::all_of(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
                        check_component_id_is_tiny);

        // are all phantoms from a tiny cc?
        const auto component_id = phantom_node_pair_list.front().first.component_id;

        auto check_component_id_is_equal = [component_id](const phantom_node_pair &phantom_pair)
        {
            return component_id == phantom_pair.first.component_id;
        };

        const bool every_phantom_has_equal_id =
            std::all_of(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
                        check_component_id_is_equal);

        auto swap_phantom_from_big_cc_into_front = [](phantom_node_pair &phantom_pair)
        {
            if (0 != phantom_pair.first.component_id)
            {
                using namespace std;
                swap(phantom_pair.first, phantom_pair.second);
            }
        };

        // this case is true if we take phantoms from the big CC
        if (!every_phantom_is_in_tiny_cc || !every_phantom_has_equal_id)
        {
            std::for_each(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
                          swap_phantom_from_big_cc_into_front);
        }

        InternalRouteResult raw_route;
        auto build_phantom_pairs =
            [&raw_route](const phantom_node_pair &first_pair, const phantom_node_pair &second_pair)
        {
            raw_route.segment_end_coordinates.emplace_back(
                PhantomNodes{first_pair.first, second_pair.first});
        };
        osrm::for_each_pair(phantom_node_pair_list, build_phantom_pairs);

        if (route_parameters.alternate_route && 1 == raw_route.segment_end_coordinates.size())
        {
            search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(),
                                                raw_route);
        }
        else
        {
            search_engine_ptr->shortest_path(raw_route.segment_end_coordinates,
                                             route_parameters.uturns, raw_route);
        }

        if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
        {
            SimpleLogger().Write(logDEBUG) << "Error occurred, single path not found";
        }

        std::unique_ptr<BaseDescriptor<DataFacadeT>> descriptor;
        switch (descriptor_table.get_id(route_parameters.output_format))
        {
        case 1:
            descriptor = osrm::make_unique<GPXDescriptor<DataFacadeT>>(facade);
            break;
        // case 2:
        //      descriptor = osrm::make_unique<GEOJSONDescriptor<DataFacadeT>>();
        //      break;
        default:
            descriptor = osrm::make_unique<JSONDescriptor<DataFacadeT>>(facade);
            break;
        }

        DescriptorConfig config = route_parameters;
        descriptor->SetConfig(config);
        descriptor->Run(raw_route, json_result);
        return 200;
    }
Example #10
0
inline void UnpackCHPath(const DataFacadeT &facade,
                         BidirectionalIterator packed_path_begin,
                         BidirectionalIterator packed_path_end,
                         Callback &&callback)
{
    // make sure we have at least something to unpack
    if (packed_path_begin == packed_path_end)
        return;

    using EdgeData = typename DataFacadeT::EdgeData;

    std::stack<std::pair<NodeID, NodeID>> recursion_stack;

    // We have to push the path in reverse order onto the stack because it's LIFO.
    for (auto current = std::prev(packed_path_end); current != packed_path_begin;
         current = std::prev(current))
    {
        recursion_stack.emplace(*std::prev(current), *current);
    }

    std::pair<NodeID, NodeID> edge;
    while (!recursion_stack.empty())
    {
        edge = recursion_stack.top();
        recursion_stack.pop();

        // Look for an edge on the forward CH graph (.forward)
        EdgeID smaller_edge_id = facade.FindSmallestEdge(
            edge.first, edge.second, [](const EdgeData &data) { return data.forward; });

        // If we didn't find one there, the we might be looking at a part of the path that
        // was found using the backward search.  Here, we flip the node order (.second, .first)
        // and only consider edges with the `.backward` flag.
        if (SPECIAL_EDGEID == smaller_edge_id)
        {
            smaller_edge_id = facade.FindSmallestEdge(
                edge.second, edge.first, [](const EdgeData &data) { return data.backward; });
        }

        // If we didn't find anything *still*, then something is broken and someone has
        // called this function with bad values.
        BOOST_ASSERT_MSG(smaller_edge_id != SPECIAL_EDGEID, "Invalid smaller edge ID");

        const auto &data = facade.GetEdgeData(smaller_edge_id);
        BOOST_ASSERT_MSG(data.distance != std::numeric_limits<EdgeWeight>::max(),
                         "edge weight invalid");

        // If the edge is a shortcut, we need to add the two halfs to the stack.
        if (data.shortcut)
        { // unpack
            const NodeID middle_node_id = data.id;
            // Note the order here - we're adding these to a stack, so we
            // want the first->middle to get visited before middle->second
            recursion_stack.emplace(middle_node_id, edge.second);
            recursion_stack.emplace(edge.first, middle_node_id);
        }
        else
        {
            // We found an original edge, call our callback.
            std::forward<Callback>(callback)(edge, data);
        }
    }
}
    void operator()(const DataFacadeT &facade,
                    const std::vector<PhantomNodes> &phantom_nodes_vector,
                    InternalRouteResult &raw_route_data) const
    {
        // Get weight to next pair of target nodes.
        BOOST_ASSERT_MSG(1 == phantom_nodes_vector.size(),
                         "Direct Shortest Path Query only accepts a single source and target pair. "
                         "Multiple ones have been specified.");
        const auto &phantom_node_pair = phantom_nodes_vector.front();
        const auto &source_phantom = phantom_node_pair.source_phantom;
        const auto &target_phantom = phantom_node_pair.target_phantom;

        engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes());
        QueryHeap &forward_heap = *(engine_working_data.forward_heap_1);
        QueryHeap &reverse_heap = *(engine_working_data.reverse_heap_1);
        forward_heap.Clear();
        reverse_heap.Clear();

        BOOST_ASSERT(source_phantom.IsValid());
        BOOST_ASSERT(target_phantom.IsValid());

        if (source_phantom.forward_segment_id.enabled)
        {
            forward_heap.Insert(source_phantom.forward_segment_id.id,
                                -source_phantom.GetForwardWeightPlusOffset(),
                                source_phantom.forward_segment_id.id);
        }
        if (source_phantom.reverse_segment_id.enabled)
        {
            forward_heap.Insert(source_phantom.reverse_segment_id.id,
                                -source_phantom.GetReverseWeightPlusOffset(),
                                source_phantom.reverse_segment_id.id);
        }

        if (target_phantom.forward_segment_id.enabled)
        {
            reverse_heap.Insert(target_phantom.forward_segment_id.id,
                                target_phantom.GetForwardWeightPlusOffset(),
                                target_phantom.forward_segment_id.id);
        }

        if (target_phantom.reverse_segment_id.enabled)
        {
            reverse_heap.Insert(target_phantom.reverse_segment_id.id,
                                target_phantom.GetReverseWeightPlusOffset(),
                                target_phantom.reverse_segment_id.id);
        }

        int weight = INVALID_EDGE_WEIGHT;
        std::vector<NodeID> packed_leg;

        const bool constexpr DO_NOT_FORCE_LOOPS =
            false; // prevents forcing of loops, since offsets are set correctly

        if (facade.GetCoreSize() > 0)
        {
            engine_working_data.InitializeOrClearSecondThreadLocalStorage(
                facade.GetNumberOfNodes());
            QueryHeap &forward_core_heap = *(engine_working_data.forward_heap_2);
            QueryHeap &reverse_core_heap = *(engine_working_data.reverse_heap_2);
            forward_core_heap.Clear();
            reverse_core_heap.Clear();

            super::SearchWithCore(facade,
                                  forward_heap,
                                  reverse_heap,
                                  forward_core_heap,
                                  reverse_core_heap,
                                  weight,
                                  packed_leg,
                                  DO_NOT_FORCE_LOOPS,
                                  DO_NOT_FORCE_LOOPS);
        }
        else
        {
            super::Search(facade,
                          forward_heap,
                          reverse_heap,
                          weight,
                          packed_leg,
                          DO_NOT_FORCE_LOOPS,
                          DO_NOT_FORCE_LOOPS);
        }

        // No path found for both target nodes?
        if (INVALID_EDGE_WEIGHT == weight)
        {
            raw_route_data.shortest_path_length = INVALID_EDGE_WEIGHT;
            raw_route_data.alternative_path_length = INVALID_EDGE_WEIGHT;
            return;
        }

        BOOST_ASSERT_MSG(!packed_leg.empty(), "packed path empty");

        raw_route_data.shortest_path_length = weight;
        raw_route_data.unpacked_path_segments.resize(1);
        raw_route_data.source_traversed_in_reverse.push_back(
            (packed_leg.front() != phantom_node_pair.source_phantom.forward_segment_id.id));
        raw_route_data.target_traversed_in_reverse.push_back(
            (packed_leg.back() != phantom_node_pair.target_phantom.forward_segment_id.id));

        super::UnpackPath(facade,
                          packed_leg.begin(),
                          packed_leg.end(),
                          phantom_node_pair,
                          raw_route_data.unpacked_path_segments.front());
    }
    std::vector<EdgeWeight> operator()(const DataFacadeT &facade,
                                       const std::vector<PhantomNode> &phantom_nodes,
                                       const std::vector<std::size_t> &source_indices,
                                       const std::vector<std::size_t> &target_indices) const
    {
        const auto number_of_sources =
            source_indices.empty() ? phantom_nodes.size() : source_indices.size();
        const auto number_of_targets =
            target_indices.empty() ? phantom_nodes.size() : target_indices.size();
        const auto number_of_entries = number_of_sources * number_of_targets;
        std::vector<EdgeWeight> result_table(number_of_entries,
                                             std::numeric_limits<EdgeWeight>::max());

        engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes());

        QueryHeap &query_heap = *(engine_working_data.forward_heap_1);

        SearchSpaceWithBuckets search_space_with_buckets;

        unsigned column_idx = 0;
        const auto search_target_phantom = [&](const PhantomNode &phantom) {
            query_heap.Clear();
            // insert target(s) at weight 0

            if (phantom.forward_segment_id.enabled)
            {
                query_heap.Insert(phantom.forward_segment_id.id,
                                  phantom.GetForwardWeightPlusOffset(),
                                  phantom.forward_segment_id.id);
            }
            if (phantom.reverse_segment_id.enabled)
            {
                query_heap.Insert(phantom.reverse_segment_id.id,
                                  phantom.GetReverseWeightPlusOffset(),
                                  phantom.reverse_segment_id.id);
            }

            // explore search space
            while (!query_heap.Empty())
            {
                BackwardRoutingStep(facade, column_idx, query_heap, search_space_with_buckets);
            }
            ++column_idx;
        };

        // for each source do forward search
        unsigned row_idx = 0;
        const auto search_source_phantom = [&](const PhantomNode &phantom) {
            query_heap.Clear();
            // insert target(s) at weight 0

            if (phantom.forward_segment_id.enabled)
            {
                query_heap.Insert(phantom.forward_segment_id.id,
                                  -phantom.GetForwardWeightPlusOffset(),
                                  phantom.forward_segment_id.id);
            }
            if (phantom.reverse_segment_id.enabled)
            {
                query_heap.Insert(phantom.reverse_segment_id.id,
                                  -phantom.GetReverseWeightPlusOffset(),
                                  phantom.reverse_segment_id.id);
            }

            // explore search space
            while (!query_heap.Empty())
            {
                ForwardRoutingStep(facade,
                                   row_idx,
                                   number_of_targets,
                                   query_heap,
                                   search_space_with_buckets,
                                   result_table);
            }
            ++row_idx;
        };

        if (target_indices.empty())
        {
            for (const auto &phantom : phantom_nodes)
            {
                search_target_phantom(phantom);
            }
        }
        else
        {
            for (const auto index : target_indices)
            {
                const auto &phantom = phantom_nodes[index];
                search_target_phantom(phantom);
            }
        }

        if (source_indices.empty())
        {
            for (const auto &phantom : phantom_nodes)
            {
                search_source_phantom(phantom);
            }
        }
        else
        {
            for (const auto index : source_indices)
            {
                const auto &phantom = phantom_nodes[index];
                search_source_phantom(phantom);
            }
        }

        return result_table;
    }
Example #13
0
    void AlternativeRoutingStep(QueryHeap &heap1,
                                QueryHeap &heap2,
                                NodeID *middle_node,
                                int *upper_bound_to_shortest_path_distance,
                                std::vector<NodeID> &search_space_intersection,
                                std::vector<SearchSpaceEdge> &search_space,
                                const EdgeWeight min_edge_offset) const
    {
        QueryHeap &forward_heap = (is_forward_directed ? heap1 : heap2);
        QueryHeap &reverse_heap = (is_forward_directed ? heap2 : heap1);

        const NodeID node = forward_heap.DeleteMin();
        const int distance = forward_heap.GetKey(node);
        // const NodeID parentnode = forward_heap.GetData(node).parent;
        // SimpleLogger().Write() << (is_forward_directed ? "[fwd] " : "[rev] ") << "settled edge ("
        // << parentnode << "," << node << "), dist: " << distance;

        const int scaled_distance =
            static_cast<int>((distance + min_edge_offset) / (1. + VIAPATH_EPSILON));
        if ((INVALID_EDGE_WEIGHT != *upper_bound_to_shortest_path_distance) &&
                (scaled_distance > *upper_bound_to_shortest_path_distance))
        {
            forward_heap.DeleteAll();
            return;
        }

        search_space.emplace_back(forward_heap.GetData(node).parent, node);

        if (reverse_heap.WasInserted(node))
        {
            search_space_intersection.emplace_back(node);
            const int new_distance = reverse_heap.GetKey(node) + distance;
            if (new_distance < *upper_bound_to_shortest_path_distance)
            {
                if (new_distance >= 0)
                {
                    *middle_node = node;
                    *upper_bound_to_shortest_path_distance = new_distance;
                    //     SimpleLogger().Write() << "accepted middle_node " << *middle_node << " at
                    //     distance " << new_distance;
                    // } else {
                    //     SimpleLogger().Write() << "discarded middle_node " << *middle_node << "
                    //     at distance " << new_distance;
                }
            }
        }

        for (auto edge : facade->GetAdjacentEdgeRange(node))
        {
            const EdgeData &data = facade->GetEdgeData(edge);
            const bool edge_is_forward_directed =
                (is_forward_directed ? data.forward : data.backward);
            if (edge_is_forward_directed)
            {

                const NodeID to = facade->GetTarget(edge);
                const int edge_weight = data.distance;

                BOOST_ASSERT(edge_weight > 0);
                const int to_distance = distance + edge_weight;

                // New Node discovered -> Add to Heap + Node Info Storage
                if (!forward_heap.WasInserted(to))
                {
                    forward_heap.Insert(to, to_distance, node);
                }
                // Found a shorter Path -> Update distance
                else if (to_distance < forward_heap.GetKey(to))
                {
                    // new parent
                    forward_heap.GetData(to).parent = node;
                    // decreased distance
                    forward_heap.DecreaseKey(to, to_distance);
                }
            }
        }
    }
Example #14
0
    // TODO: reorder parameters
    // compute and unpack <s,..,v> and <v,..,t> by exploring search spaces
    // from v and intersecting against queues. only half-searches have to be
    // done at this stage
    void ComputeLengthAndSharingOfViaPath(const NodeID via_node,
                                          int *real_length_of_via_path,
                                          int *sharing_of_via_path,
                                          const std::vector<NodeID> &packed_shortest_path,
                                          const EdgeWeight min_edge_offset)
    {
        engine_working_data.InitializeOrClearSecondThreadLocalStorage(
            super::facade->GetNumberOfNodes());

        QueryHeap &existing_forward_heap = *engine_working_data.forward_heap_1;
        QueryHeap &existing_reverse_heap = *engine_working_data.reverse_heap_1;
        QueryHeap &new_forward_heap = *engine_working_data.forward_heap_2;
        QueryHeap &new_reverse_heap = *engine_working_data.reverse_heap_2;

        std::vector<NodeID> packed_s_v_path;
        std::vector<NodeID> packed_v_t_path;

        std::vector<NodeID> partially_unpacked_shortest_path;
        std::vector<NodeID> partially_unpacked_via_path;

        NodeID s_v_middle = SPECIAL_NODEID;
        int upper_bound_s_v_path_length = INVALID_EDGE_WEIGHT;
        new_reverse_heap.Insert(via_node, 0, via_node);
        // compute path <s,..,v> by reusing forward search from s
        while (!new_reverse_heap.Empty())
        {
            super::RoutingStep(new_reverse_heap, existing_forward_heap, &s_v_middle,
                               &upper_bound_s_v_path_length, min_edge_offset, false);
        }
        // compute path <v,..,t> by reusing backward search from node t
        NodeID v_t_middle = SPECIAL_NODEID;
        int upper_bound_of_v_t_path_length = INVALID_EDGE_WEIGHT;
        new_forward_heap.Insert(via_node, 0, via_node);
        while (!new_forward_heap.Empty())
        {
            super::RoutingStep(new_forward_heap, existing_reverse_heap, &v_t_middle,
                               &upper_bound_of_v_t_path_length, min_edge_offset, true);
        }
        *real_length_of_via_path = upper_bound_s_v_path_length + upper_bound_of_v_t_path_length;

        if (SPECIAL_NODEID == s_v_middle || SPECIAL_NODEID == v_t_middle)
        {
            return;
        }

        // retrieve packed paths
        super::RetrievePackedPathFromHeap(existing_forward_heap, new_reverse_heap, s_v_middle,
                                          packed_s_v_path);
        super::RetrievePackedPathFromHeap(new_forward_heap, existing_reverse_heap, v_t_middle,
                                          packed_v_t_path);

        // partial unpacking, compute sharing
        // First partially unpack s-->v until paths deviate, note length of common path.
        const int64_t s_v_min_path_size =
            std::min(packed_s_v_path.size(), packed_shortest_path.size()) - 1;
        for (const int64_t current_node : osrm::irange<int64_t>(0, s_v_min_path_size))
        {
            if (packed_s_v_path[current_node] == packed_shortest_path[current_node] &&
                    packed_s_v_path[current_node + 1] == packed_shortest_path[current_node + 1])
            {
                EdgeID edgeID = facade->FindEdgeInEitherDirection(
                                    packed_s_v_path[current_node], packed_s_v_path[current_node + 1]);
                *sharing_of_via_path += facade->GetEdgeData(edgeID).distance;
            }
            else
            {
                if (packed_s_v_path[current_node] == packed_shortest_path[current_node])
                {
                    super::UnpackEdge(packed_s_v_path[current_node],
                                      packed_s_v_path[current_node + 1],
                                      partially_unpacked_via_path);
                    super::UnpackEdge(packed_shortest_path[current_node],
                                      packed_shortest_path[current_node + 1],
                                      partially_unpacked_shortest_path);
                    break;
                }
            }
        }
        // traverse partially unpacked edge and note common prefix
        const int64_t packed_path_length =
            std::min(partially_unpacked_via_path.size(), partially_unpacked_shortest_path.size()) -
            1;
        for (int64_t current_node = 0; (current_node < packed_path_length) &&
                (partially_unpacked_via_path[current_node] ==
                 partially_unpacked_shortest_path[current_node] &&
                 partially_unpacked_via_path[current_node + 1] ==
                 partially_unpacked_shortest_path[current_node + 1]);
                ++current_node)
        {
            EdgeID selected_edge =
                facade->FindEdgeInEitherDirection(partially_unpacked_via_path[current_node],
                                                  partially_unpacked_via_path[current_node + 1]);
            *sharing_of_via_path += facade->GetEdgeData(selected_edge).distance;
        }

        // Second, partially unpack v-->t in reverse order until paths deviate and note lengths
        int64_t via_path_index = packed_v_t_path.size() - 1;
        int64_t shortest_path_index = packed_shortest_path.size() - 1;
        for (; via_path_index > 0 && shortest_path_index > 0;
                --via_path_index, --shortest_path_index)
        {
            if (packed_v_t_path[via_path_index - 1] ==
                    packed_shortest_path[shortest_path_index - 1] &&
                    packed_v_t_path[via_path_index] == packed_shortest_path[shortest_path_index])
            {
                EdgeID edgeID = facade->FindEdgeInEitherDirection(
                                    packed_v_t_path[via_path_index - 1], packed_v_t_path[via_path_index]);
                *sharing_of_via_path += facade->GetEdgeData(edgeID).distance;
            }
            else
            {
                if (packed_v_t_path[via_path_index] == packed_shortest_path[shortest_path_index])
                {
                    super::UnpackEdge(packed_v_t_path[via_path_index - 1],
                                      packed_v_t_path[via_path_index], partially_unpacked_via_path);
                    super::UnpackEdge(packed_shortest_path[shortest_path_index - 1],
                                      packed_shortest_path[shortest_path_index],
                                      partially_unpacked_shortest_path);
                    break;
                }
            }
        }

        via_path_index = partially_unpacked_via_path.size() - 1;
        shortest_path_index = partially_unpacked_shortest_path.size() - 1;
        for (; via_path_index > 0 && shortest_path_index > 0;
                --via_path_index, --shortest_path_index)
        {
            if (partially_unpacked_via_path[via_path_index - 1] ==
                    partially_unpacked_shortest_path[shortest_path_index - 1] &&
                    partially_unpacked_via_path[via_path_index] ==
                    partially_unpacked_shortest_path[shortest_path_index])
            {
                EdgeID edgeID = facade->FindEdgeInEitherDirection(
                                    partially_unpacked_via_path[via_path_index - 1],
                                    partially_unpacked_via_path[via_path_index]);
                *sharing_of_via_path += facade->GetEdgeData(edgeID).distance;
            }
            else
            {
                break;
            }
        }
        // finished partial unpacking spree! Amount of sharing is stored to appropriate pointer
        // variable
    }
Example #15
0
    virtual void Run(const InternalRouteResult &raw_route,
                     osrm::json::Object &json_result) override final
    {
        if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
        {
            // We do not need to do much, if there is no route ;-)
            return;
        }

        // check if first segment is non-zero
        BOOST_ASSERT(raw_route.unpacked_path_segments.size() ==
                     raw_route.segment_end_coordinates.size());

        description_factory.SetStartSegment(
            raw_route.segment_end_coordinates.front().source_phantom,
            raw_route.source_traversed_in_reverse.front());

        // for each unpacked segment add the leg to the description
        for (const auto i : osrm::irange<std::size_t>(0, raw_route.unpacked_path_segments.size()))
        {
#ifndef NDEBUG
            const int added_segments =
#endif
                DescribeLeg(raw_route.unpacked_path_segments[i],
                            raw_route.segment_end_coordinates[i],
                            raw_route.target_traversed_in_reverse[i], raw_route.is_via_leg(i));
            BOOST_ASSERT(0 < added_segments);
        }
        description_factory.Run(config.zoom_level);

        if (config.geometry)
        {
            osrm::json::Value route_geometry =
                description_factory.AppendGeometryString(config.encode_geometry);
            json_result.values["route_geometry"] = route_geometry;
        }
        if (config.instructions)
        {
            osrm::json::Array json_route_instructions = BuildTextualDescription(description_factory, shortest_path_segments);
            json_result.values["route_instructions"] = json_route_instructions;
        }
        description_factory.BuildRouteSummary(description_factory.get_entire_length(),
                                              raw_route.shortest_path_length);
        osrm::json::Object json_route_summary;
        json_route_summary.values["total_distance"] = description_factory.summary.distance;
        json_route_summary.values["total_time"] = description_factory.summary.duration;
        json_route_summary.values["start_point"] =
            facade->get_name_for_id(description_factory.summary.source_name_id);
        json_route_summary.values["end_point"] =
            facade->get_name_for_id(description_factory.summary.target_name_id);
        json_result.values["route_summary"] = json_route_summary;

        BOOST_ASSERT(!raw_route.segment_end_coordinates.empty());

        osrm::json::Array json_via_points_array;
        osrm::json::Array json_first_coordinate;
        json_first_coordinate.values.push_back(
            raw_route.segment_end_coordinates.front().source_phantom.location.lat /
            COORDINATE_PRECISION);
        json_first_coordinate.values.push_back(
            raw_route.segment_end_coordinates.front().source_phantom.location.lon /
            COORDINATE_PRECISION);
        json_via_points_array.values.push_back(json_first_coordinate);
        for (const PhantomNodes &nodes : raw_route.segment_end_coordinates)
        {
            std::string tmp;
            osrm::json::Array json_coordinate;
            json_coordinate.values.push_back(nodes.target_phantom.location.lat /
                                             COORDINATE_PRECISION);
            json_coordinate.values.push_back(nodes.target_phantom.location.lon /
                                             COORDINATE_PRECISION);
            json_via_points_array.values.push_back(json_coordinate);
        }
        json_result.values["via_points"] = json_via_points_array;

        osrm::json::Array json_via_indices_array;

        std::vector<unsigned> const &shortest_leg_end_indices = description_factory.GetViaIndices();
        json_via_indices_array.values.insert(json_via_indices_array.values.end(),
                                             shortest_leg_end_indices.begin(),
                                             shortest_leg_end_indices.end());
        json_result.values["via_indices"] = json_via_indices_array;

        // only one alternative route is computed at this time, so this is hardcoded
        if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
        {
            json_result.values["found_alternative"] = osrm::json::True();
            BOOST_ASSERT(!raw_route.alt_source_traversed_in_reverse.empty());
            alternate_description_factory.SetStartSegment(
                raw_route.segment_end_coordinates.front().source_phantom,
                raw_route.alt_source_traversed_in_reverse.front());
            // Get all the coordinates for the computed route
            for (const PathData &path_data : raw_route.unpacked_alternative)
            {
                current = facade->GetCoordinateOfNode(path_data.node);
                alternate_description_factory.AppendSegment(current, path_data);
            }
            alternate_description_factory.SetEndSegment(
                raw_route.segment_end_coordinates.back().target_phantom,
                raw_route.alt_source_traversed_in_reverse.back());
            alternate_description_factory.Run(config.zoom_level);

            if (config.geometry)
            {
                osrm::json::Value alternate_geometry_string =
                    alternate_description_factory.AppendGeometryString(config.encode_geometry);
                osrm::json::Array json_alternate_geometries_array;
                json_alternate_geometries_array.values.push_back(alternate_geometry_string);
                json_result.values["alternative_geometries"] = json_alternate_geometries_array;
            }
            // Generate instructions for each alternative (simulated here)
            osrm::json::Array json_alt_instructions;
            osrm::json::Array json_current_alt_instructions;
            if (config.instructions)
            {
                json_current_alt_instructions = BuildTextualDescription(alternate_description_factory, alternative_path_segments);
                json_alt_instructions.values.push_back(json_current_alt_instructions);
                json_result.values["alternative_instructions"] = json_alt_instructions;
            }
            alternate_description_factory.BuildRouteSummary(
                alternate_description_factory.get_entire_length(),
                raw_route.alternative_path_length);

            osrm::json::Object json_alternate_route_summary;
            osrm::json::Array json_alternate_route_summary_array;
            json_alternate_route_summary.values["total_distance"] =
                alternate_description_factory.summary.distance;
            json_alternate_route_summary.values["total_time"] =
                alternate_description_factory.summary.duration;
            json_alternate_route_summary.values["start_point"] =
                facade->get_name_for_id(alternate_description_factory.summary.source_name_id);
            json_alternate_route_summary.values["end_point"] =
                facade->get_name_for_id(alternate_description_factory.summary.target_name_id);
            json_alternate_route_summary_array.values.push_back(json_alternate_route_summary);
            json_result.values["alternative_summaries"] = json_alternate_route_summary_array;

            std::vector<unsigned> const &alternate_leg_end_indices =
                alternate_description_factory.GetViaIndices();
            osrm::json::Array json_altenative_indices_array;
            json_altenative_indices_array.values.insert(json_altenative_indices_array.values.end(),
                                                        alternate_leg_end_indices.begin(),
                                                        alternate_leg_end_indices.end());
            json_result.values["alternative_indices"] = json_altenative_indices_array;
        }
        else
        {
            json_result.values["found_alternative"] = osrm::json::False();
        }

        // Get Names for both routes
        RouteNames route_names =
            GenerateRouteNames(shortest_path_segments, alternative_path_segments, facade);
        osrm::json::Array json_route_names;
        json_route_names.values.push_back(route_names.shortest_path_name_1);
        json_route_names.values.push_back(route_names.shortest_path_name_2);
        json_result.values["route_name"] = json_route_names;

        if (INVALID_EDGE_WEIGHT != raw_route.alternative_path_length)
        {
            osrm::json::Array json_alternate_names_array;
            osrm::json::Array json_alternate_names;
            json_alternate_names.values.push_back(route_names.alternative_path_name_1);
            json_alternate_names.values.push_back(route_names.alternative_path_name_2);
            json_alternate_names_array.values.push_back(json_alternate_names);
            json_result.values["alternative_names"] = json_alternate_names_array;
        }

        json_result.values["hint_data"] = BuildHintData(raw_route);
    }
Example #16
0
    inline osrm::json::Array BuildTextualDescription(const DescriptionFactory &description_factory,
                                                     std::vector<Segment> &route_segments_list) const
    {
        osrm::json::Array json_instruction_array;
        // Segment information has following format:
        //["instruction id","streetname",length,position,time,"length","earth_direction",azimuth]
        unsigned necessary_segments_running_index = 0;

        struct RoundAbout
        {
            RoundAbout() : start_index(std::numeric_limits<int>::max()), name_id(INVALID_NAMEID), leave_at_exit(std::numeric_limits<int>::max()) {}
            int start_index;
            unsigned name_id;
            int leave_at_exit;
        } round_about;

        round_about.leave_at_exit = 0;
        round_about.name_id = 0;
        std::string temp_dist, temp_length, temp_duration, temp_bearing, temp_instruction;
        TravelMode last_travel_mode = TRAVEL_MODE_DEFAULT;

        // Fetch data from Factory and generate a string from it.
        for (const SegmentInformation &segment : description_factory.path_description)
        {
            osrm::json::Array json_instruction_row;
            TurnInstruction current_instruction = segment.turn_instruction;
            if (TurnInstructionsClass::TurnIsNecessary(current_instruction))
            {
                if (TurnInstruction::EnterRoundAbout == current_instruction)
                {
                    round_about.name_id = segment.name_id;
                    round_about.start_index = necessary_segments_running_index;
                }
                else
                {
                    std::string current_turn_instruction;
                    if (TurnInstruction::LeaveRoundAbout == current_instruction)
                    {
                        temp_instruction = std::to_string(
                            cast::enum_to_underlying(TurnInstruction::EnterRoundAbout));
                        current_turn_instruction += temp_instruction;
                        current_turn_instruction += "-";
                        temp_instruction = std::to_string(round_about.leave_at_exit + 1);
                        current_turn_instruction += temp_instruction;
                        round_about.leave_at_exit = 0;
                    }
                    else
                    {
                        temp_instruction =
                            std::to_string(cast::enum_to_underlying(current_instruction));
                        current_turn_instruction += temp_instruction;
                    }
                    json_instruction_row.values.push_back(current_turn_instruction);

                    json_instruction_row.values.push_back(facade->get_name_for_id(segment.name_id));
                    json_instruction_row.values.push_back(std::round(segment.length));
                    json_instruction_row.values.push_back(necessary_segments_running_index);
                    json_instruction_row.values.push_back(std::round(segment.duration / 10.));
                    json_instruction_row.values.push_back(
                        std::to_string(static_cast<unsigned>(segment.length)) + "m");

                    // post turn bearing
                    const double post_turn_bearing_value = (segment.post_turn_bearing / 10.);
                    json_instruction_row.values.push_back(bearing::get(post_turn_bearing_value));
                    json_instruction_row.values.push_back(
                        static_cast<unsigned>(round(post_turn_bearing_value)));

                    json_instruction_row.values.push_back(segment.travel_mode);
                    last_travel_mode = segment.travel_mode;

                    // pre turn bearing
                    const double pre_turn_bearing_value = (segment.pre_turn_bearing / 10.);
                    json_instruction_row.values.push_back(bearing::get(pre_turn_bearing_value));
                    json_instruction_row.values.push_back(
                        static_cast<unsigned>(round(pre_turn_bearing_value)));

                    json_instruction_array.values.push_back(json_instruction_row);

                    route_segments_list.emplace_back(
                        segment.name_id, static_cast<int>(segment.length),
                        static_cast<unsigned>(route_segments_list.size()));
                }
            }
            else if (TurnInstruction::StayOnRoundAbout == current_instruction)
            {
                ++round_about.leave_at_exit;
            }
            if (segment.necessary)
            {
                ++necessary_segments_running_index;
            }
        }

        osrm::json::Array json_last_instruction_row;
        temp_instruction =
            std::to_string(cast::enum_to_underlying(TurnInstruction::ReachedYourDestination));
        json_last_instruction_row.values.push_back(temp_instruction);
        json_last_instruction_row.values.push_back("");
        json_last_instruction_row.values.push_back(0);
        json_last_instruction_row.values.push_back(necessary_segments_running_index - 1);
        json_last_instruction_row.values.push_back(0);
        json_last_instruction_row.values.push_back("0m");
        json_last_instruction_row.values.push_back(bearing::get(0.0));
        json_last_instruction_row.values.push_back(0.);
        json_last_instruction_row.values.push_back(last_travel_mode);
        json_last_instruction_row.values.push_back(bearing::get(0.0));
        json_last_instruction_row.values.push_back(0.);
        json_instruction_array.values.push_back(json_last_instruction_row);

        return json_instruction_array;
    }
Example #17
0
    // conduct T-Test
    bool ViaNodeCandidatePassesTTest(QueryHeap &existing_forward_heap,
                                     QueryHeap &existing_reverse_heap,
                                     QueryHeap &new_forward_heap,
                                     QueryHeap &new_reverse_heap,
                                     const RankedCandidateNode &candidate,
                                     const int length_of_shortest_path,
                                     int *length_of_via_path,
                                     NodeID *s_v_middle,
                                     NodeID *v_t_middle,
                                     const EdgeWeight min_edge_offset) const
    {
        new_forward_heap.Clear();
        new_reverse_heap.Clear();
        std::vector<NodeID> packed_s_v_path;
        std::vector<NodeID> packed_v_t_path;

        *s_v_middle = SPECIAL_NODEID;
        int upper_bound_s_v_path_length = INVALID_EDGE_WEIGHT;
        // compute path <s,..,v> by reusing forward search from s
        new_reverse_heap.Insert(candidate.node, 0, candidate.node);
        while (new_reverse_heap.Size() > 0)
        {
            super::RoutingStep(new_reverse_heap, existing_forward_heap, s_v_middle,
                               &upper_bound_s_v_path_length, min_edge_offset, false);
        }

        if (INVALID_EDGE_WEIGHT == upper_bound_s_v_path_length)
        {
            return false;
        }

        // compute path <v,..,t> by reusing backward search from t
        *v_t_middle = SPECIAL_NODEID;
        int upper_bound_of_v_t_path_length = INVALID_EDGE_WEIGHT;
        new_forward_heap.Insert(candidate.node, 0, candidate.node);
        while (new_forward_heap.Size() > 0)
        {
            super::RoutingStep(new_forward_heap, existing_reverse_heap, v_t_middle,
                               &upper_bound_of_v_t_path_length, min_edge_offset, true);
        }

        if (INVALID_EDGE_WEIGHT == upper_bound_of_v_t_path_length)
        {
            return false;
        }

        *length_of_via_path = upper_bound_s_v_path_length + upper_bound_of_v_t_path_length;

        // retrieve packed paths
        super::RetrievePackedPathFromHeap(existing_forward_heap, new_reverse_heap, *s_v_middle,
                                          packed_s_v_path);

        super::RetrievePackedPathFromHeap(new_forward_heap, existing_reverse_heap, *v_t_middle,
                                          packed_v_t_path);

        NodeID s_P = *s_v_middle, t_P = *v_t_middle;
        if (SPECIAL_NODEID == s_P)
        {
            return false;
        }

        if (SPECIAL_NODEID == t_P)
        {
            return false;
        }
        const int T_threshold = static_cast<int>(VIAPATH_EPSILON * length_of_shortest_path);
        int unpacked_until_distance = 0;

        std::stack<SearchSpaceEdge> unpack_stack;
        // Traverse path s-->v
        for (std::size_t i = packed_s_v_path.size() - 1; (i > 0) && unpack_stack.empty(); --i)
        {
            const EdgeID current_edge_id =
                facade->FindEdgeInEitherDirection(packed_s_v_path[i - 1], packed_s_v_path[i]);
            const int length_of_current_edge = facade->GetEdgeData(current_edge_id).distance;
            if ((length_of_current_edge + unpacked_until_distance) >= T_threshold)
            {
                unpack_stack.emplace(packed_s_v_path[i - 1], packed_s_v_path[i]);
            }
            else
            {
                unpacked_until_distance += length_of_current_edge;
                s_P = packed_s_v_path[i - 1];
            }
        }

        while (!unpack_stack.empty())
        {
            const SearchSpaceEdge via_path_edge = unpack_stack.top();
            unpack_stack.pop();
            EdgeID edge_in_via_path_id =
                facade->FindEdgeInEitherDirection(via_path_edge.first, via_path_edge.second);

            if (SPECIAL_EDGEID == edge_in_via_path_id)
            {
                return false;
            }

            const EdgeData &current_edge_data = facade->GetEdgeData(edge_in_via_path_id);
            const bool current_edge_is_shortcut = current_edge_data.shortcut;
            if (current_edge_is_shortcut)
            {
                const NodeID via_path_middle_node_id = current_edge_data.id;
                const EdgeID second_segment_edge_id = facade->FindEdgeInEitherDirection(
                        via_path_middle_node_id, via_path_edge.second);
                const int second_segment_length =
                    facade->GetEdgeData(second_segment_edge_id).distance;
                // attention: !unpacking in reverse!
                // Check if second segment is the one to go over treshold? if yes add second segment
                // to stack, else push first segment to stack and add distance of second one.
                if (unpacked_until_distance + second_segment_length >= T_threshold)
                {
                    unpack_stack.emplace(via_path_middle_node_id, via_path_edge.second);
                }
                else
                {
                    unpacked_until_distance += second_segment_length;
                    unpack_stack.emplace(via_path_edge.first, via_path_middle_node_id);
                }
            }
            else
            {
                // edge is not a shortcut, set the start node for T-Test to end of edge.
                unpacked_until_distance += current_edge_data.distance;
                s_P = via_path_edge.first;
            }
        }

        int t_test_path_length = unpacked_until_distance;
        unpacked_until_distance = 0;
        // Traverse path s-->v
        BOOST_ASSERT(!packed_v_t_path.empty());
        for (unsigned i = 0, packed_path_length = static_cast<unsigned>(packed_v_t_path.size() - 1);
                (i < packed_path_length) && unpack_stack.empty(); ++i)
        {
            const EdgeID edgeID =
                facade->FindEdgeInEitherDirection(packed_v_t_path[i], packed_v_t_path[i + 1]);
            int length_of_current_edge = facade->GetEdgeData(edgeID).distance;
            if (length_of_current_edge + unpacked_until_distance >= T_threshold)
            {
                unpack_stack.emplace(packed_v_t_path[i], packed_v_t_path[i + 1]);
            }
            else
            {
                unpacked_until_distance += length_of_current_edge;
                t_P = packed_v_t_path[i + 1];
            }
        }

        while (!unpack_stack.empty())
        {
            const SearchSpaceEdge via_path_edge = unpack_stack.top();
            unpack_stack.pop();
            EdgeID edge_in_via_path_id =
                facade->FindEdgeInEitherDirection(via_path_edge.first, via_path_edge.second);
            if (SPECIAL_EDGEID == edge_in_via_path_id)
            {
                return false;
            }

            const EdgeData &current_edge_data = facade->GetEdgeData(edge_in_via_path_id);
            const bool IsViaEdgeShortCut = current_edge_data.shortcut;
            if (IsViaEdgeShortCut)
            {
                const NodeID middleOfViaPath = current_edge_data.id;
                EdgeID edgeIDOfFirstSegment =
                    facade->FindEdgeInEitherDirection(via_path_edge.first, middleOfViaPath);
                int lengthOfFirstSegment = facade->GetEdgeData(edgeIDOfFirstSegment).distance;
                // Check if first segment is the one to go over treshold? if yes first segment to
                // stack, else push second segment to stack and add distance of first one.
                if (unpacked_until_distance + lengthOfFirstSegment >= T_threshold)
                {
                    unpack_stack.emplace(via_path_edge.first, middleOfViaPath);
                }
                else
                {
                    unpacked_until_distance += lengthOfFirstSegment;
                    unpack_stack.emplace(middleOfViaPath, via_path_edge.second);
                }
            }
            else
            {
                // edge is not a shortcut, set the start node for T-Test to end of edge.
                unpacked_until_distance += current_edge_data.distance;
                t_P = via_path_edge.second;
            }
        }

        t_test_path_length += unpacked_until_distance;
        // Run actual T-Test query and compare if distances equal.
        engine_working_data.InitializeOrClearThirdThreadLocalStorage(
            super::facade->GetNumberOfNodes());

        QueryHeap &forward_heap3 = *engine_working_data.forward_heap_3;
        QueryHeap &reverse_heap3 = *engine_working_data.reverse_heap_3;
        int upper_bound = INVALID_EDGE_WEIGHT;
        NodeID middle = SPECIAL_NODEID;

        forward_heap3.Insert(s_P, 0, s_P);
        reverse_heap3.Insert(t_P, 0, t_P);
        // exploration from s and t until deletemin/(1+epsilon) > _lengt_oO_sShortest_path
        while ((forward_heap3.Size() + reverse_heap3.Size()) > 0)
        {
            if (!forward_heap3.Empty())
            {
                super::RoutingStep(forward_heap3, reverse_heap3, &middle, &upper_bound,
                                   min_edge_offset, true);
            }
            if (!reverse_heap3.Empty())
            {
                super::RoutingStep(reverse_heap3, forward_heap3, &middle, &upper_bound,
                                   min_edge_offset, false);
            }
        }
        return (upper_bound <= t_test_path_length);
    }