Ejemplo n.º 1
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;
    }
Ejemplo n.º 2
0
    Status HandleRequest(const RouteParameters &route_parameters,
                      osrm::json::Object &json_result) override final
    {
        if (max_locations_trip > 0 &&
            (static_cast<int>(route_parameters.coordinates.size()) > max_locations_trip))
        {
            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_trip) + ")";
            return Status::Error;
        }

        // check if all inputs are coordinates
        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 coordinates";
            return Status::Error;
        }

        // get phantom nodes
        auto phantom_node_list = GetPhantomNodes(route_parameters);
        if (phantom_node_list.size() != route_parameters.coordinates.size())
        {
            BOOST_ASSERT(phantom_node_list.size() < route_parameters.coordinates.size());
            json_result.values["status_message"] =
                std::string("Could not find a matching segment for coordinate ") +
                std::to_string(phantom_node_list.size());
            return Status::NoSegment;
        }

        const auto number_of_locations = phantom_node_list.size();

        // compute the distance table of all phantom nodes
        const auto result_table = DistTableWrapper<EdgeWeight>(
            *search_engine_ptr->distance_table(phantom_node_list, phantom_node_list),
            number_of_locations);

        if (result_table.size() == 0)
        {
            return Status::Error;
        }

        const constexpr std::size_t BF_MAX_FEASABLE = 10;
        BOOST_ASSERT_MSG(result_table.size() == number_of_locations * number_of_locations,
                         "Distance Table has wrong size");

        // get scc components
        SCC_Component scc = SplitUnaccessibleLocations(number_of_locations, result_table);

        using NodeIDIterator = typename std::vector<NodeID>::const_iterator;

        std::vector<std::vector<NodeID>> route_result;
        route_result.reserve(scc.GetNumberOfComponents());
        TIMER_START(TRIP_TIMER);
        // run Trip computation for every SCC
        for (std::size_t k = 0; k < scc.GetNumberOfComponents(); ++k)
        {
            const auto component_size = scc.range[k + 1] - scc.range[k];

            BOOST_ASSERT_MSG(component_size > 0, "invalid component size");

            std::vector<NodeID> scc_route;
            NodeIDIterator start = std::begin(scc.component) + scc.range[k];
            NodeIDIterator end = std::begin(scc.component) + scc.range[k + 1];

            if (component_size > 1)
            {

                if (component_size < BF_MAX_FEASABLE)
                {
                    scc_route =
                        osrm::trip::BruteForceTrip(start, end, number_of_locations, result_table);
                }
                else
                {
                    scc_route = osrm::trip::FarthestInsertionTrip(start, end, number_of_locations,
                                                                  result_table);
                }

                // use this output if debugging of route is needed:
                // SimpleLogger().Write() << "Route #" << k << ": " << [&scc_route]()
                // {
                //     std::string s = "";
                //     for (auto x : scc_route)
                //     {
                //         s += std::to_string(x) + " ";
                //     }
                //     return s;
                // }();

            }
            else
            {
                scc_route = std::vector<NodeID>(start, end);
            }

            route_result.push_back(std::move(scc_route));
        }

        // compute all round trip routes
        std::vector<InternalRouteResult> comp_route;
        comp_route.reserve(route_result.size());
        for (auto &elem : route_result)
        {
            comp_route.push_back(ComputeRoute(phantom_node_list, route_parameters, elem));
        }

        TIMER_STOP(TRIP_TIMER);

        // prepare JSON output
        // create a json object for every trip
        osrm::json::Array trip;
        for (std::size_t i = 0; i < route_result.size(); ++i)
        {
            std::unique_ptr<BaseDescriptor<DataFacadeT>> descriptor =
                osrm::make_unique<JSONDescriptor<DataFacadeT>>(facade);
            descriptor->SetConfig(route_parameters);

            osrm::json::Object scc_trip;

            // set permutation output
            SetLocPermutationOutput(route_result[i], scc_trip);
            // set viaroute output
            descriptor->Run(comp_route[i], scc_trip);

            trip.values.push_back(std::move(scc_trip));
        }


        if (trip.values.empty())
        {
            json_result.values["status_message"] = "Cannot find trips";
            return Status::EmptyResult;
        }

        json_result.values["trips"] = std::move(trip);
        json_result.values["status_message"] = "Found trips";
        return Status::Ok;
    }
Ejemplo n.º 3
0
    Status HandleRequest(const RouteParameters &route_parameters,
                         osrm::json::Object &json_result) final override
    {
        // enforce maximum number of locations for performance reasons
        if (max_locations_map_matching > 0 &&
            static_cast<int>(route_parameters.coordinates.size()) > max_locations_map_matching)
        {
            json_result.values["status_message"] = "Too many coodindates";
            return Status::Error;
        }

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

        std::vector<double> sub_trace_lengths;
        const auto &input_coords = route_parameters.coordinates;
        const auto &input_timestamps = route_parameters.timestamps;
        const auto &input_bearings = route_parameters.bearings;
        if (input_timestamps.size() > 0 && input_coords.size() != input_timestamps.size())
        {
            json_result.values["status_message"] =
                "Number of timestamps does not match number of coordinates";
            return Status::Error;
        }

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

        // enforce maximum number of locations for performance reasons
        if (static_cast<int>(input_coords.size()) < 2)
        {
            json_result.values["status_message"] = "At least two coordinates needed";
            return Status::Error;
        }

        const auto candidates_lists = getCandidates(
            input_coords, input_bearings, route_parameters.gps_precision, sub_trace_lengths);
        if (candidates_lists.size() != input_coords.size())
        {
            BOOST_ASSERT(candidates_lists.size() < input_coords.size());
            json_result.values["status_message"] =
                std::string("Could not find a matching segment for coordinate ") +
                std::to_string(candidates_lists.size());
            return Status::NoSegment;
        }

        // setup logging if enabled
        if (osrm::json::Logger::get())
            osrm::json::Logger::get()->initialize("matching");

        // call the actual map matching
        osrm::matching::SubMatchingList sub_matchings;
        search_engine_ptr->map_matching(candidates_lists, input_coords, input_timestamps,
                                        route_parameters.matching_beta,
                                        route_parameters.gps_precision, sub_matchings);

        osrm::json::Array matchings;
        for (auto &sub : sub_matchings)
        {
            // classify result
            if (route_parameters.classify)
            {
                double trace_length =
                    sub_trace_lengths[sub.indices.back()] - sub_trace_lengths[sub.indices.front()];
                TraceClassification classification =
                    classify(trace_length, sub.length,
                             (sub.indices.back() - sub.indices.front() + 1) - sub.nodes.size());
                if (classification.first == ClassifierT::ClassLabel::POSITIVE)
                {
                    sub.confidence = classification.second;
                }
                else
                {
                    sub.confidence = 1 - classification.second;
                }
            }

            BOOST_ASSERT(sub.nodes.size() > 1);

            // FIXME we only run this to obtain the geometry
            // The clean way would be to get this directly from the map matching plugin
            InternalRouteResult raw_route;
            PhantomNodes current_phantom_node_pair;
            for (unsigned i = 0; i < sub.nodes.size() - 1; ++i)
            {
                current_phantom_node_pair.source_phantom = sub.nodes[i];
                current_phantom_node_pair.target_phantom = sub.nodes[i + 1];
                BOOST_ASSERT(current_phantom_node_pair.source_phantom.is_valid());
                BOOST_ASSERT(current_phantom_node_pair.target_phantom.is_valid());
                raw_route.segment_end_coordinates.emplace_back(current_phantom_node_pair);
            }
            search_engine_ptr->shortest_path(
                raw_route.segment_end_coordinates,
                std::vector<bool>(raw_route.segment_end_coordinates.size() + 1, true), raw_route);

            BOOST_ASSERT(raw_route.shortest_path_length != INVALID_EDGE_WEIGHT);

            matchings.values.emplace_back(submatchingToJSON(sub, route_parameters, raw_route));
        }

        if (osrm::json::Logger::get())
            osrm::json::Logger::get()->render("matching", json_result);
        json_result.values["matchings"] = matchings;

        if (sub_matchings.empty())
        {
            json_result.values["status_message"] = "Cannot find matchings";
            return Status::EmptyResult;
        }

        json_result.values["status_message"] = "Found matchings";
        return Status::Ok;
    }