diff --git a/data_structures/route_parameters.cpp b/data_structures/route_parameters.cpp index 51ac9f23f..e63ecab1c 100644 --- a/data_structures/route_parameters.cpp +++ b/data_structures/route_parameters.cpp @@ -36,7 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. RouteParameters::RouteParameters() : zoom_level(18), print_instructions(false), alternate_route(true), geometry(true), - compression(true), deprecatedAPI(false), uturn_default(false), classify(false), + compression(true), deprecatedAPI(false), uturn_default(false), classify(false), mapped_points(true), matching_beta(5), gps_precision(5), check_sum(-1), num_results(1) { } @@ -148,6 +148,14 @@ void RouteParameters::addCoordinate( static_cast(COORDINATE_PRECISION * boost::fusion::at_c<1>(received_coordinates))); } +void RouteParameters::addDestination( + const boost::fusion::vector &received_coordinates) +{ + destinations.emplace_back( + static_cast(COORDINATE_PRECISION * boost::fusion::at_c<0>(received_coordinates)), + static_cast(COORDINATE_PRECISION * boost::fusion::at_c<1>(received_coordinates))); +} + void RouteParameters::addSource( const boost::fusion::vector &received_coordinates) { diff --git a/features/step_definitions/distance_matrix.rb b/features/step_definitions/distance_matrix.rb index f51fec238..51aaa64d7 100644 --- a/features/step_definitions/distance_matrix.rb +++ b/features/step_definitions/distance_matrix.rb @@ -4,16 +4,21 @@ When /^I request a travel time matrix I should get$/ do |table| raise "*** Top-left cell of matrix table must be empty" unless table.headers[0]=="" nodes = [] + sources = [] column_headers = table.headers[1..-1] row_headers = table.rows.map { |h| h.first } - unless column_headers==row_headers || @query_params['src'] - raise "*** Column and row headers must match in matrix table, got #{column_headers.inspect} and #{row_headers.inspect}" - end column_headers.each do |node_name| node = find_node_by_name(node_name) raise "*** unknown node '#{node_name}" unless node nodes << node end + if column_headers!=row_headers + row_headers.each do |node_name| + node = find_node_by_name(node_name) + raise "*** unknown node '#{node_name}" unless node + sources << node + end + end reprocess actual = [] @@ -22,11 +27,7 @@ When /^I request a travel time matrix I should get$/ do |table| # compute matrix params = @query_params - if params['src'] - node = find_node_by_name(params['src']) - params['src'] = node.lat + ',' + node.lon - end - response = request_table nodes, params + response = request_table nodes, sources, params if response.body.empty? == false json = JSON.parse response.body result = json['distance_table'] diff --git a/features/support/route.rb b/features/support/route.rb index ca353d6e6..fa69fa67d 100644 --- a/features/support/route.rb +++ b/features/support/route.rb @@ -41,9 +41,13 @@ def request_route waypoints, params={} request_path "viaroute", waypoints, defaults.merge(params) end -def request_table waypoints, params={} +def request_table waypoints, sources, params={} defaults = { 'output' => 'json' } - request_path "table", waypoints, defaults.merge(params) + options = defaults.merge(params) + locs = (sources.size > 0) ? (waypoints.compact.map { |w| "dst=#{w.lat},#{w.lon}" } + sources.compact.map { |w| "src=#{w.lat},#{w.lon}" }) : waypoints.compact.map { |w| "loc=#{w.lat},#{w.lon}" } + params = (locs + options.to_param).join('&') + uri = generate_request_url ("table" + '?' + params) + response = send_request uri, waypoints, options, sources end def got_route? response diff --git a/features/testbot/distance_matrix.feature b/features/testbot/distance_matrix.feature index 0a41530d4..6305aa825 100644 --- a/features/testbot/distance_matrix.feature +++ b/features/testbot/distance_matrix.feature @@ -116,8 +116,25 @@ Feature: Basic Distance Matrix And the query options | mapped_points | true | - | src | a | When I request a travel time matrix I should get | | a | b | e | f | | a | 0 | 100 | 200 | 300 | + + Scenario: Testbot - Travel time 3x2 matrix + Given the node map + | a | b | c | + | d | e | f | + + And the ways + | nodes | + | abc | + | def | + | ad | + | be | + | cf | + + When I request a travel time matrix I should get + | | b | e | f | + | a | 100 | 200 | 300 | + | b | 0 | 100 | 200 | diff --git a/include/osrm/route_parameters.hpp b/include/osrm/route_parameters.hpp index 092a2e9be..a91a3d6fb 100644 --- a/include/osrm/route_parameters.hpp +++ b/include/osrm/route_parameters.hpp @@ -82,6 +82,8 @@ struct RouteParameters void addCoordinate(const boost::fusion::vector &received_coordinates); + void addDestination(const boost::fusion::vector &received_coordinates); + void addSource(const boost::fusion::vector &received_coordinates); void getCoordinatesFromGeometry(const std::string &geometry_string); @@ -110,6 +112,7 @@ struct RouteParameters std::vector>> bearings; std::vector uturns; std::vector coordinates; + std::vector destinations; std::vector sources; }; diff --git a/plugins/distance_table.hpp b/plugins/distance_table.hpp index 6eed9f6c6..c5d4a7f3b 100644 --- a/plugins/distance_table.hpp +++ b/plugins/distance_table.hpp @@ -70,23 +70,32 @@ template class DistanceTablePlugin final : public BasePlugin int HandleRequest(const RouteParameters &route_parameters, osrm::json::Object &json_result) override final { - if (!check_all_coordinates(route_parameters.coordinates) || - (route_parameters.sources.size() && !check_all_coordinates(route_parameters.sources, 1))) + const bool useSameTgtSrc = route_parameters.coordinates.size() ? true : false; + if ((useSameTgtSrc && route_parameters.destinations.size()) || (useSameTgtSrc && route_parameters.sources.size())) + { + return 400; + } + + if ((useSameTgtSrc && !check_all_coordinates(route_parameters.coordinates)) || + (!useSameTgtSrc && !check_all_coordinates(route_parameters.destinations, 2) && !check_all_coordinates(route_parameters.sources, 1))) { return 400; } const auto &input_bearings = route_parameters.bearings; - if (input_bearings.size() > 0 && route_parameters.coordinates.size() + route_parameters.sources.size() != input_bearings.size()) + unsigned nb_coordinates = useSameTgtSrc ? route_parameters.coordinates.size() : (route_parameters.destinations.size() + route_parameters.sources.size()); + if (input_bearings.size() > 0 && nb_coordinates != input_bearings.size()) { json_result.values["status"] = "Number of bearings does not match number of coordinates ."; return 400; } const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum()); - unsigned max_locations = + unsigned max_locations = useSameTgtSrc ? std::min(static_cast(max_locations_distance_table), - static_cast(route_parameters.coordinates.size())); + static_cast(route_parameters.coordinates.size())) : + std::min(static_cast(max_locations_distance_table), + static_cast(route_parameters.destinations.size())); PhantomNodeArray phantom_node_target_vector(max_locations); for (const auto i : osrm::irange(0u, max_locations)) @@ -104,14 +113,14 @@ template class DistanceTablePlugin final : public BasePlugin } 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; - facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates[i], + facade->IncrementalFindPhantomNodeForCoordinate(useSameTgtSrc ? route_parameters.coordinates[i] : route_parameters.destinations[i], phantom_node_target_vector[i], 1, bearing, range); BOOST_ASSERT(phantom_node_target_vector[i].front().is_valid(facade->GetNumberOfNodes())); } - unsigned nb_coordinates = route_parameters.coordinates.size(); + unsigned shift_coordinates = (useSameTgtSrc) ? 0 : route_parameters.destinations.size(); max_locations = 0; - if (route_parameters.sources.size()) + if (!useSameTgtSrc) { max_locations = std::min(static_cast(max_locations_distance_table), static_cast(route_parameters.sources.size())); @@ -119,19 +128,19 @@ template class DistanceTablePlugin final : public BasePlugin PhantomNodeArray phantom_node_source_vector(max_locations); for (const auto i : osrm::irange(0u, max_locations)) { - if (checksum_OK && i < route_parameters.hints.size() - route_parameters.coordinates.size() && - !route_parameters.hints[i+route_parameters.coordinates.size()].empty()) + if (checksum_OK && i < route_parameters.hints.size() - shift_coordinates && + !route_parameters.hints[i + shift_coordinates].empty()) { PhantomNode current_phantom_node; - ObjectEncoder::DecodeFromBase64(route_parameters.hints[i+route_parameters.coordinates.size()], current_phantom_node); + ObjectEncoder::DecodeFromBase64(route_parameters.hints[i + shift_coordinates], current_phantom_node); if (current_phantom_node.is_valid(facade->GetNumberOfNodes())) { phantom_node_source_vector[i].emplace_back(std::move(current_phantom_node)); continue; } } - const int bearing = input_bearings.size() > 0 ? input_bearings[nb_coordinates + i].first : 0; - const int range = input_bearings.size() > 0 ? (input_bearings[nb_coordinates + i].second?*input_bearings[nb_coordinates + i].second:10) : 180; + const int bearing = input_bearings.size() > 0 ? input_bearings[i + shift_coordinates].first : 0; + const int range = input_bearings.size() > 0 ? (input_bearings[i + shift_coordinates].second?*input_bearings[i + shift_coordinates].second:10) : 180; facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.sources[i], phantom_node_source_vector[i], 1, bearing, range); diff --git a/server/api_grammar.hpp b/server/api_grammar.hpp index 2006cda84..618dfb2b5 100644 --- a/server/api_grammar.hpp +++ b/server/api_grammar.hpp @@ -40,7 +40,7 @@ template struct APIGrammar : qi::grammar> string[boost::bind(&HandlerT::setService, handler, ::_1)] >> *(query) >> -(uturns); - query = ('?') >> (+(zoom | output | jsonp | checksum | location | source | hint | timestamp | bearing | u | cmp | + query = ('?') >> (+(zoom | output | jsonp | checksum | location | destination | source | hint | timestamp | bearing | u | cmp | language | instruction | geometry | alt_route | old_API | num_results | matching_beta | gps_precision | classify | locs | mapped_points)); @@ -61,6 +61,9 @@ template struct APIGrammar : qi::grammar> qi::lit("loc") >> '=' >> (qi::double_ >> qi::lit(',') >> qi::double_)[boost::bind(&HandlerT::addCoordinate, handler, ::_1)]; + destination = (-qi::lit('&')) >> qi::lit("dst") >> '=' >> + (qi::double_ >> qi::lit(',') >> + qi::double_)[boost::bind(&HandlerT::addDestination, handler, ::_1)]; source = (-qi::lit('&')) >> qi::lit("src") >> '=' >> (qi::double_ >> qi::lit(',') >> qi::double_)[boost::bind(&HandlerT::addSource, handler, ::_1)]; @@ -101,7 +104,7 @@ template struct APIGrammar : qi::grammar api_call, query; - qi::rule service, zoom, output, string, jsonp, checksum, location, source, + qi::rule service, zoom, output, string, jsonp, checksum, location, destination, source, hint, timestamp, bearing, stringwithDot, stringwithPercent, language, instruction, geometry, cmp, alt_route, u, uturns, old_API, num_results, matching_beta, gps_precision, classify, locs, mapped_points, stringforPolyline;