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; }
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 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; }