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; }
Status TripPlugin::HandleRequest(const api::TripParameters ¶meters, util::json::Object &json_result) { BOOST_ASSERT(parameters.IsValid()); // enforce maximum number of locations for performance reasons if (max_locations_trip > 0 && static_cast<int>(parameters.coordinates.size()) > max_locations_trip) { return Error("TooBig", "Too many trip coordinates", json_result); } if (!CheckAllCoordinates(parameters.coordinates)) { return Error("InvalidValue", "Invalid coordinate value.", json_result); } auto phantom_node_pairs = GetPhantomNodes(parameters); if (phantom_node_pairs.size() != parameters.coordinates.size()) { return Error("NoSegment", std::string("Could not find a matching segment for coordinate ") + std::to_string(phantom_node_pairs.size()), json_result); } BOOST_ASSERT(phantom_node_pairs.size() == parameters.coordinates.size()); auto snapped_phantoms = SnapPhantomNodes(phantom_node_pairs); const auto number_of_locations = snapped_phantoms.size(); // compute the duration table of all phantom nodes const auto result_table = util::DistTableWrapper<EdgeWeight>( duration_table(snapped_phantoms, {}, {}), 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); std::vector<std::vector<NodeID>> trips; trips.reserve(scc.GetNumberOfComponents()); // 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; auto route_begin = std::begin(scc.component) + scc.range[k]; auto route_end = std::begin(scc.component) + scc.range[k + 1]; if (component_size > 1) { if (component_size < BF_MAX_FEASABLE) { scc_route = trip::BruteForceTrip(route_begin, route_end, number_of_locations, result_table); } else { scc_route = trip::FarthestInsertionTrip(route_begin, route_end, number_of_locations, result_table); } } else { scc_route = std::vector<NodeID>(route_begin, route_end); } trips.push_back(std::move(scc_route)); } if (trips.empty()) { return Error("NoTrips", "Cannot find trips", json_result); } // compute all round trip routes std::vector<InternalRouteResult> routes; routes.reserve(trips.size()); for (const auto &trip : trips) { routes.push_back(ComputeRoute(snapped_phantoms, parameters, trip)); } api::TripAPI trip_api{BasePlugin::facade, parameters}; trip_api.MakeResponse(trips, routes, snapped_phantoms, json_result); return Status::Ok; }