Status TripPlugin::HandleRequest(const datafacade::ContiguousInternalMemoryDataFacadeBase &facade, const RoutingAlgorithmsInterface &algorithms, const api::TripParameters ¶meters, util::json::Object &json_result) const { if (!algorithms.HasShortestPathSearch()) { return Error("NotImplemented", "Shortest path search is not implemented for the chosen search algorithm.", json_result); } if (!algorithms.HasManyToManySearch()) { return Error("NotImplemented", "Many to many search is not implemented for the chosen search algorithm.", json_result); } BOOST_ASSERT(parameters.IsValid()); const auto number_of_locations = parameters.coordinates.size(); std::size_t source_id = INVALID_INDEX; std::size_t destination_id = INVALID_INDEX; if (parameters.source == api::TripParameters::SourceType::First) { source_id = 0; } if (parameters.destination == api::TripParameters::DestinationType::Last) { BOOST_ASSERT(number_of_locations > 0); destination_id = number_of_locations - 1; } bool fixed_start = (source_id == 0); bool fixed_end = (destination_id == number_of_locations - 1); if (!IsSupportedParameterCombination(fixed_start, fixed_end, parameters.roundtrip)) { return Error("NotImplemented", "This request is not supported", json_result); } // enforce maximum number of locations for performance reasons if (max_locations_trip > 0 && static_cast<int>(number_of_locations) > 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(facade, parameters); if (phantom_node_pairs.size() != number_of_locations) { 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() == number_of_locations); if (fixed_start && fixed_end && (source_id >= parameters.coordinates.size() || destination_id >= parameters.coordinates.size())) { return Error("InvalidValue", "Invalid source or destination value.", json_result); } auto snapped_phantoms = SnapPhantomNodes(phantom_node_pairs); BOOST_ASSERT(snapped_phantoms.size() == number_of_locations); // compute the duration table of all phantom nodes auto result_table = util::DistTableWrapper<EdgeWeight>( algorithms.ManyToManySearch(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"); if (!IsStronglyConnectedComponent(result_table)) { return Error("NoTrips", "No trip visiting all destinations possible.", json_result); } if (fixed_start && fixed_end) { ManipulateTableForFSE(source_id, destination_id, result_table); } std::vector<NodeID> trip; trip.reserve(number_of_locations); // get an optimized order in which the destinations should be visited if (number_of_locations < BF_MAX_FEASABLE) { trip = trip::BruteForceTrip(number_of_locations, result_table); } else { trip = trip::FarthestInsertionTrip(number_of_locations, result_table); } // rotate result such that roundtrip starts at node with index 0 // thist first if covers scenarios: !fixed_end || fixed_start || (fixed_start && fixed_end) if (!fixed_end || fixed_start) { auto desired_start_index = std::find(std::begin(trip), std::end(trip), 0); BOOST_ASSERT(desired_start_index != std::end(trip)); std::rotate(std::begin(trip), desired_start_index, std::end(trip)); } else if (fixed_end && !fixed_start && parameters.roundtrip) { auto desired_start_index = std::find(std::begin(trip), std::end(trip), destination_id); BOOST_ASSERT(desired_start_index != std::end(trip)); std::rotate(std::begin(trip), desired_start_index, std::end(trip)); } // get the route when visiting all destinations in optimized order InternalRouteResult route = ComputeRoute(algorithms, snapped_phantoms, trip, parameters.roundtrip); // get api response const std::vector<std::vector<NodeID>> trips = {trip}; const std::vector<InternalRouteResult> routes = {route}; api::TripAPI trip_api{facade, parameters}; trip_api.MakeResponse(trips, routes, snapped_phantoms, json_result); 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; }