From ce9dd44c2e82f855fa4ddbc31a4778e0ce0a2ca5 Mon Sep 17 00:00:00 2001 From: Aleksandrs Saveljevs Date: Fri, 6 Jan 2023 14:31:32 +0000 Subject: [PATCH 1/3] Added approach on the opposite side of the road (main C++ files only). --- include/engine/api/base_parameters.hpp | 3 ++- include/engine/approach.hpp | 3 ++- include/engine/geospatial_query.hpp | 5 ++++- include/nodejs/node_osrm_support.hpp | 8 ++++++-- include/server/api/base_parameters_grammar.hpp | 3 ++- src/nodejs/node_osrm.cpp | 8 ++++---- 6 files changed, 20 insertions(+), 10 deletions(-) diff --git a/include/engine/api/base_parameters.hpp b/include/engine/api/base_parameters.hpp index 9cc13ae017d..56b8604ed1f 100644 --- a/include/engine/api/base_parameters.hpp +++ b/include/engine/api/base_parameters.hpp @@ -52,7 +52,8 @@ namespace osrm::engine::api * optional per coordinate * - bearings: limits the search for segments in the road network to given bearing(s) in degree * towards true north in clockwise direction, optional per coordinate - * - approaches: force the phantom node to start towards the node with the road country side. + * - approaches: force the phantom node to start towards the node with the road country side or + * its opposite * * \see OSRM, Coordinate, Hint, Bearing, RouteParameters, TableParameters, * NearestParameters, TripParameters, MatchParameters and TileParameters diff --git a/include/engine/approach.hpp b/include/engine/approach.hpp index 185dcfcf529..abd35bd9d95 100644 --- a/include/engine/approach.hpp +++ b/include/engine/approach.hpp @@ -36,7 +36,8 @@ namespace osrm::engine enum class Approach : std::uint8_t { CURB = 0, - UNRESTRICTED = 1 + OPPOSITE = 1, + UNRESTRICTED = 2 }; } // namespace osrm::engine diff --git a/include/engine/geospatial_query.hpp b/include/engine/geospatial_query.hpp index 7ea666c4eaa..f25122afbbf 100644 --- a/include/engine/geospatial_query.hpp +++ b/include/engine/geospatial_query.hpp @@ -558,7 +558,7 @@ template class GeospatialQuery { bool isOnewaySegment = !(segment.data.forward_segment_id.enabled && segment.data.reverse_segment_id.enabled); - if (!isOnewaySegment && approach == Approach::CURB) + if (!isOnewaySegment && (approach == Approach::CURB || approach == Approach::OPPOSITE)) { // Check the counter clockwise // @@ -573,6 +573,9 @@ template class GeospatialQuery if (datafacade.IsLeftHandDriving(segment.data.forward_segment_id.id)) input_coordinate_is_at_right = !input_coordinate_is_at_right; + if (approach == Approach::OPPOSITE) + input_coordinate_is_at_right = !input_coordinate_is_at_right; + return std::make_pair(input_coordinate_is_at_right, (!input_coordinate_is_at_right)); } return std::make_pair(true, true); diff --git a/include/nodejs/node_osrm_support.hpp b/include/nodejs/node_osrm_support.hpp index d321bb4a098..f698374b534 100644 --- a/include/nodejs/node_osrm_support.hpp +++ b/include/nodejs/node_osrm_support.hpp @@ -560,6 +560,10 @@ inline bool argumentsToParameter(const Napi::CallbackInfo &args, { params->approaches.push_back(osrm::Approach::CURB); } + else if (approach_str == "opposite") + { + params->approaches.push_back(osrm::Approach::OPPOSITE); + } else if (approach_str == "unrestricted") { params->approaches.push_back(osrm::Approach::UNRESTRICTED); @@ -567,13 +571,13 @@ inline bool argumentsToParameter(const Napi::CallbackInfo &args, else { ThrowError(args.Env(), - "'approaches' param must be one of [curb, unrestricted]"); + "'approaches' param must be one of [curb, opposite, unrestricted]"); return false; } } else { - ThrowError(args.Env(), "Approach must be a string: [curb, unrestricted] or null"); + ThrowError(args.Env(), "Approach must be a string: [curb, opposite, unrestricted] or null"); return false; } } diff --git a/include/server/api/base_parameters_grammar.hpp b/include/server/api/base_parameters_grammar.hpp index dfc99c0373c..a303c6a806d 100644 --- a/include/server/api/base_parameters_grammar.hpp +++ b/include/server/api/base_parameters_grammar.hpp @@ -167,7 +167,8 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar (-(qi::short_ > ',' > qi::short_))[ph::bind(add_bearing, qi::_r1, qi::_1)] % ';'; approach_type.add("unrestricted", engine::Approach::UNRESTRICTED)("curb", - engine::Approach::CURB); + engine::Approach::CURB)("opposite", engine::Approach::OPPOSITE); + approach_rule = qi::lit("approaches=") > (-approach_type % ';')[ph::bind(&engine::api::BaseParameters::approaches, qi::_r1) = qi::_1]; diff --git a/src/nodejs/node_osrm.cpp b/src/nodejs/node_osrm.cpp index 9ff5db22fc2..02cef8422ac 100644 --- a/src/nodejs/node_osrm.cpp +++ b/src/nodejs/node_osrm.cpp @@ -292,7 +292,7 @@ inline void asyncForTiles(const Napi::CallbackInfo &info, * @param {String} [options.geometries=polyline] Returned route geometry format (influences overview and per step). Can also be `geojson`. * @param {String} [options.overview=simplified] Add overview geometry either `full`, `simplified` according to highest zoom level it could be display on, or not at all (`false`). * @param {Boolean} [options.continue_straight] Forces the route to keep going straight at waypoints and don't do a uturn even if it would be faster. Default value depends on the profile. - * @param {Array} [options.approaches] Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`. + * @param {Array} [options.approaches] Keep waypoints on curb or opposite side of the road. Can be `null` (unrestricted, default), `curb` or `opposite`. * `null`/`true`/`false` * @param {Array} [options.waypoints] Indices to coordinates to treat as waypoints. If not supplied, all coordinates are waypoints. Must include first and last coordinate index. * @param {String} [options.format] Which output format to use, either `json`, or [`flatbuffers`](https://github.com/Project-OSRM/osrm-backend/tree/master/include/engine/api/flatbuffers). @@ -337,7 +337,7 @@ Napi::Value Engine::route(const Napi::CallbackInfo &info) * @param {Boolean} [options.generate_hints=true] Whether or not adds a Hint to the response which can be used in subsequent requests. * @param {Number} [options.number=1] Number of nearest segments that should be returned. * Must be an integer greater than or equal to `1`. - * @param {Array} [options.approaches] Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`. + * @param {Array} [options.approaches] Keep waypoints on curb or opposite side of the road. Can be `null` (unrestricted, default), `curb` or `opposite`. * @param {String} [options.format] Which output format to use, either `json`, or [`flatbuffers`](https://github.com/Project-OSRM/osrm-backend/tree/master/include/engine/api/flatbuffers). * @param {String} [options.snapping] Which edges can be snapped to, either `default`, or `any`. `default` only snaps to edges marked by the profile as `is_startpoint`, `any` will allow snapping to any edge in the routing graph. * @param {Function} callback @@ -384,7 +384,7 @@ Napi::Value Engine::nearest(const Napi::CallbackInfo &info) * @param {Array} [options.sources] An array of `index` elements (`0 <= integer < #coordinates`) to use * location with given index as source. Default is to use all. * @param {Array} [options.destinations] An array of `index` elements (`0 <= integer < #coordinates`) to use location with given index as destination. Default is to use all. - * @param {Array} [options.approaches] Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`. + * @param {Array} [options.approaches] Keep waypoints on curb or opposite side of the road. Can be `null` (unrestricted, default), `curb` or `opposite`. * @param {Number} [options.fallback_speed] Replace `null` responses in result with as-the-crow-flies estimates based on `fallback_speed`. Value is in metres/second. * @param {String} [options.fallback_coordinate] Either `input` (default) or `snapped`. If using a `fallback_speed`, use either the user-supplied coordinate (`input`), or the snapped coordinate (`snapped`) for calculating the as-the-crow-flies distance between two points. * @param {Number} [options.scale_factor] Multiply the table duration values in the table by this number for more controlled input into a route optimization solver. @@ -565,7 +565,7 @@ Napi::Value Engine::match(const Napi::CallbackInfo &info) * @param {Boolean} [options.roundtrip=true] Return route is a roundtrip. * @param {String} [options.source=any] Return route starts at `any` or `first` coordinate. * @param {String} [options.destination=any] Return route ends at `any` or `last` coordinate. - * @param {Array} [options.approaches] Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`. + * @param {Array} [options.approaches] Keep waypoints on curb or opposite side of the road. Can be `null` (unrestricted, default), `curb` or `opposite`. * @param {String} [options.snapping] Which edges can be snapped to, either `default`, or `any`. `default` only snaps to edges marked by the profile as `is_startpoint`, `any` will allow snapping to any edge in the routing graph. * * @returns {Object} containing `waypoints` and `trips`. From 1d285ade25625201c1d954ff687db33bb46eb5f0 Mon Sep 17 00:00:00 2001 From: Michael Bell Date: Tue, 2 Apr 2024 22:50:24 +0100 Subject: [PATCH 2/3] Additional test and docs coverage for opposite approach --- CHANGELOG.md | 1 + docs/http.md | 4 +- docs/nodejs/api.md | 8 +- features/testbot/approaches.feature | 378 +++++++++++++++++- include/nodejs/node_osrm_support.hpp | 3 +- .../server/api/base_parameters_grammar.hpp | 4 +- src/nodejs/node_osrm.cpp | 8 +- test/nodejs/route.js | 10 +- unit_tests/server/parameters_parser.cpp | 4 +- 9 files changed, 386 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5414c892390..51ea1635960 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - ADDED: Add support for a keepalive_timeout flag. [#6674](https://github.com/Project-OSRM/osrm-backend/pull/6674) - ADDED: Add support for a default_radius flag. [#6575](https://github.com/Project-OSRM/osrm-backend/pull/6575) - ADDED: Add support for disabling feature datasets. [#6666](https://github.com/Project-OSRM/osrm-backend/pull/6666) + - ADDED: Add support for opposite approach request parameter. [#6842](https://github.com/Project-OSRM/osrm-backend/pull/6842) - Build: - ADDED: Add CI job which builds OSRM with gcc 12. [#6455](https://github.com/Project-OSRM/osrm-backend/pull/6455) - CHANGED: Upgrade to clang-tidy 15. [#6439](https://github.com/Project-OSRM/osrm-backend/pull/6439) diff --git a/docs/http.md b/docs/http.md index bbfb03d6e88..9e6649d7317 100644 --- a/docs/http.md +++ b/docs/http.md @@ -35,7 +35,7 @@ To pass parameters to each location some options support an array-like encoding: |radiuses |`{radius};{radius}[;{radius} ...]` |Limits the search to given radius in meters. | |generate\_hints |`true` (default), `false` |Adds a Hint to the response which can be used in subsequent requests, see `hints` parameter. | |hints |`{hint};{hint}[;{hint} ...]` |Hint from previous request to derive position in street network. | -|approaches |`{approach};{approach}[;{approach} ...]` |Keep waypoints on curbside. | +|approaches |`{approach};{approach}[;{approach} ...]` |Restrict the direction on the road network at a waypoint, relative to the input coordinate. | |exclude |`{class}[,{class}]` |Additive list of classes to avoid, the order does not matter. | |snapping |`default` (default), `any` |Default snapping avoids is_startpoint (see profile) edges, `any` will snap to any edge in the graph | |skip_waypoints |`true`, `false` (default) |Removes waypoints from the response. Waypoints are still calculated, but not serialized. Could be useful in case you are interested in some other part of the response and do not want to transfer waste data. | @@ -47,7 +47,7 @@ Where the elements follow the following format: |bearing |`{value},{range}` `integer 0 .. 360,integer 0 .. 180` | |radius |`double >= 0` or `unlimited` (default) | |hint |Base64 `string` | -|approach |`curb` or `unrestricted` (default) | +|approach |`curb`, `opposite` or `unrestricted` (default) | |class |A class name determined by the profile or `none`. | ``` diff --git a/docs/nodejs/api.md b/docs/nodejs/api.md index faaf83d6481..9dbfe912c52 100644 --- a/docs/nodejs/api.md +++ b/docs/nodejs/api.md @@ -63,7 +63,7 @@ Returns the fastest route between two or more coordinates while visiting the way - `options.geometries` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** Returned route geometry format (influences overview and per step). Can also be `geojson`. (optional, default `polyline`) - `options.overview` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** Add overview geometry either `full`, `simplified` according to highest zoom level it could be display on, or not at all (`false`). (optional, default `simplified`) - `options.continue_straight` **[Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** Forces the route to keep going straight at waypoints and don't do a uturn even if it would be faster. Default value depends on the profile. - - `options.approaches` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`. + - `options.approaches` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Restrict the direction on the road network at a waypoint, relative to the input coordinate. Can be `null` (unrestricted, default), `curb` or `opposite`. `null`/`true`/`false` - `options.waypoints` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Indices to coordinates to treat as waypoints. If not supplied, all coordinates are waypoints. Must include first and last coordinate index. - `options.format` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** Which output format to use, either `json`, or [`flatbuffers`](https://github.com/Project-OSRM/osrm-backend/tree/master/include/engine/api/flatbuffers). @@ -101,7 +101,7 @@ Note: `coordinates` in the general options only supports a single `{longitude},{ - `options.generate_hints` **[Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Whether or not adds a Hint to the response which can be used in subsequent requests. (optional, default `true`) - `options.number` **[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)** Number of nearest segments that should be returned. Must be an integer greater than or equal to `1`. (optional, default `1`) - - `options.approaches` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`. + - `options.approaches` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Restrict the direction on the road network at a waypoint, relative to the input coordinate. Can be `null` (unrestricted, default), `curb` or `opposite`. - `options.format` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** Which output format to use, either `json`, or [`flatbuffers`](https://github.com/Project-OSRM/osrm-backend/tree/master/include/engine/api/flatbuffers). - `options.snapping` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** Which edges can be snapped to, either `default`, or `any`. `default` only snaps to edges marked by the profile as `is_startpoint`, `any` will allow snapping to any edge in the routing graph. - `callback` **[Function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)** @@ -141,7 +141,7 @@ Optionally returns distance table. - `options.sources` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** An array of `index` elements (`0 <= integer < #coordinates`) to use location with given index as source. Default is to use all. - `options.destinations` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** An array of `index` elements (`0 <= integer < #coordinates`) to use location with given index as destination. Default is to use all. - - `options.approaches` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`. + - `options.approaches` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Restrict the direction on the road network at a waypoint, relative to the input coordinate.. Can be `null` (unrestricted, default), `curb` or `opposite`. - `options.fallback_speed` **[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Replace `null` responses in result with as-the-crow-flies estimates based on `fallback_speed`. Value is in metres/second. - `options.fallback_coordinate` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** Either `input` (default) or `snapped`. If using a `fallback_speed`, use either the user-supplied coordinate (`input`), or the snapped coordinate (`snapped`) for calculating the as-the-crow-flies distance between two points. - `options.scale_factor` **[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Multiply the table duration values in the table by this number for more controlled input into a route optimization solver. @@ -298,7 +298,7 @@ Right now, the following combinations are possible: - `options.roundtrip` **[Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Return route is a roundtrip. (optional, default `true`) - `options.source` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** Return route starts at `any` or `first` coordinate. (optional, default `any`) - `options.destination` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** Return route ends at `any` or `last` coordinate. (optional, default `any`) - - `options.approaches` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`. + - `options.approaches` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Restrict the direction on the road network at a waypoint, relative to the input coordinate. Can be `null` (unrestricted, default), `curb` or `opposite`. - `options.snapping` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** Which edges can be snapped to, either `default`, or `any`. `default` only snaps to edges marked by the profile as `is_startpoint`, `any` will allow snapping to any edge in the routing graph. - `callback` **[Function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)** diff --git a/features/testbot/approaches.feature b/features/testbot/approaches.feature index d3e0c463006..fb3f008616d 100644 --- a/features/testbot/approaches.feature +++ b/features/testbot/approaches.feature @@ -38,7 +38,41 @@ Feature: Approach parameter | from | to | approaches | route | | s | e | unrestricted curb | ab,bc,bc | - Scenario: Start End opposite approach, option unrestricted for Start and End + Scenario: Start End same approach, option unrestricted for Start and opposite for End + Given the profile "testbot" + And the node map + """ + s e + a------b------c + """ + + And the ways + | nodes | + | ab | + | bc | + + When I route I should get + | from | to | approaches | route | + | s | e | unrestricted opposite | ab,bc | + + Scenario: Start End same approach, option opposite for Start and curb for End + Given the profile "testbot" + And the node map + """ + s e + a------b------c + """ + + And the ways + | nodes | + | ab | + | bc | + + When I route I should get + | from | to | approaches | route | + | s | e | opposite curb | ab,bc,bc | + + Scenario: Start End different approach, option unrestricted for Start and End Given the profile "testbot" And the node map """ @@ -56,7 +90,7 @@ Feature: Approach parameter | from | to | approaches | route | | s | e | unrestricted unrestricted | ab,bc | - Scenario: Start End opposite approach, option unrestricted for Start and curb for End + Scenario: Start End different approach, option unrestricted for Start and curb for End Given the profile "testbot" And the node map """ @@ -74,6 +108,43 @@ Feature: Approach parameter | from | to | approaches | route | | s | e | unrestricted curb | ab,bc | + Scenario: Start End different approach, option unrestricted for Start and opposite for End + Given the profile "testbot" + And the node map + """ + s + a------b------c + e + """ + + And the ways + | nodes | + | ab | + | bc | + + When I route I should get + | from | to | approaches | route | + | s | e | unrestricted opposite | ab,bc,bc | + + Scenario: Start End different approach, option curb for Start and opposite for End + Given the profile "testbot" + And the node map + """ + e + a------b------c-----------d + s + """ + + And the ways + | nodes | + | ab | + | bc | + | cd | + + When I route I should get + | from | to | approaches | route | + | s | e | curb opposite | cd,cd,ab,ab | + ############### # Oneway Test # @@ -111,10 +182,44 @@ Feature: Approach parameter | bc | yes | When I route I should get - | from | to | approaches | route | + | from | to | approaches | route | | s | e | unrestricted curb | ab,bc | - Scenario: Test on oneway segment, Start End opposite approach, option unrestricted for Start and End + Scenario: Test on oneway segment, Start End same approach, option unrestricted for Start and opposite for End + Given the profile "testbot" + And the node map + """ + s e + a------b------c + """ + + And the ways + | nodes | oneway | + | ab | yes | + | bc | yes | + + When I route I should get + | from | to | approaches | route | + | s | e | unrestricted opposite | ab,bc | + + Scenario: Test on oneway segment, Start End same approach, option opposite for Start and curb for End + Given the profile "testbot" + And the node map + """ + s e + a------b------c + """ + + And the ways + | nodes | oneway | + | ab | yes | + | bc | yes | + + When I route I should get + | from | to | approaches | route | + | s | e | opposite curb | ab,bc | + + Scenario: Test on oneway segment, Start End different approach, option unrestricted for Start and End Given the profile "testbot" And the node map """ @@ -132,7 +237,7 @@ Feature: Approach parameter | from | to | approaches | route | | s | e | unrestricted unrestricted | ab,bc | - Scenario: Test on oneway segment, Start End opposite approach, option unrestricted for Start and curb for End + Scenario: Test on oneway segment, Start End different approach, option unrestricted for Start and curb for End Given the profile "testbot" And the node map """ @@ -150,6 +255,42 @@ Feature: Approach parameter | from | to | approaches | route | | s | e | unrestricted curb | ab,bc | + Scenario: Test on oneway segment, Start End different approach, option unrestricted for Start and opposite for End + Given the profile "testbot" + And the node map + """ + s + a------b------c + e + """ + + And the ways + | nodes | oneway | + | ab | yes | + | bc | yes | + + When I route I should get + | from | to | approaches | route | + | s | e | unrestricted opposite | ab,bc | + + Scenario: Test on oneway segment, Start End different approach, option curb for Start and opposite for End + Given the profile "testbot" + And the node map + """ + s + a------b------c + e + """ + + And the ways + | nodes | oneway | + | ab | yes | + | bc | yes | + + When I route I should get + | from | to | approaches | route | + | s | e | curb opposite | ab,bc | + ############## # UTurn Test # ############## @@ -175,6 +316,27 @@ Feature: Approach parameter | from | to | approaches | route | | s | e | unrestricted curb | | + Scenario: UTurn test, router can find a route because uturn authorized to reach opposite side + Given the profile "testbot" + And the node map + """ + e s + a------b------c + """ + + And the ways + | nodes | + | ab | + | bc | + + And the relations + | type | way:from | way:to | node:via | restriction | + | restriction | bc | bc | c | no_u_turn | + + When I route I should get + | from | to | approaches | route | + | s | e | curb opposite | bc,ab,ab | + Scenario: UTurn test, router can find a route because he can use the roundabout Given the profile "testbot" @@ -198,8 +360,9 @@ Feature: Approach parameter | restriction | bc | bc | c | no_u_turn | When I route I should get - | from | to | approaches | route | - | s | e | unrestricted curb | ab,bc,bc | + | from | to | approaches | route | + | s | e | unrestricted curb | ab,bc,bc | + | s | e | opposite curb | ab,bc,bc | Scenario: Start End same approach, option unrestricted for Start and curb for End, left-hand driving @@ -228,6 +391,32 @@ Feature: Approach parameter | from | to | approaches | route | | s | e | unrestricted curb | ab,bc | + Scenario: Start End same approach, option unrestricted for Start and opposite for End, left-hand driving + Given the profile file + """ + local functions = require('testbot') + local testbot_process_way = functions.process_way + functions.process_way = function(profile, way, result) + testbot_process_way(profile, way, result) + result.is_left_hand_driving = true + end + return functions + """ + And the node map + """ + s e + a------b------c + """ + + And the ways + | nodes | + | ab | + | bc | + + When I route I should get + | from | to | approaches | route | + | s | e | unrestricted opposite | ab,bc,bc | + ####################### # Left-side countries # @@ -260,9 +449,8 @@ Feature: Approach parameter """ And the node map """ - s + s e a------b------c - e """ And the ways @@ -271,10 +459,50 @@ Feature: Approach parameter | bc | When I route I should get - | from | to | approaches | route | - | s | e | unrestricted curb | ab,bc,bc | + | from | to | approaches | route | + | s | e | unrestricted curb | ab,bc | + + Scenario: [Left-hand-side] Start End same approach, option unrestricted for Start and opposite for End + Given the profile file "car" initialized with + """ + profile.properties.left_hand_driving = true + """ + And the node map + """ + s e + a------b------c + """ - Scenario: [Left-hand-side] Start End opposite approach, option unrestricted for Start and End + And the ways + | nodes | + | ab | + | bc | + + When I route I should get + | from | to | approaches | route | + | s | e | unrestricted opposite | ab,bc,bc | + + Scenario: [Left-hand-side] Start End same approach, option opposite for Start and curb for End + Given the profile file "car" initialized with + """ + profile.properties.left_hand_driving = true + """ + And the node map + """ + e s + a------b------c + """ + + And the ways + | nodes | + | ab | + | bc | + + When I route I should get + | from | to | approaches | route | + | s | e | opposite curb | bc,ab,ab | + + Scenario: [Left-hand-side] Start End different approach, option unrestricted for Start and End Given the profile file "car" initialized with """ profile.properties.left_hand_driving = true @@ -295,15 +523,16 @@ Feature: Approach parameter | from | to | approaches | route | | s | e | unrestricted unrestricted | ab,bc | - Scenario: [Left-hand-side] Start End opposite approach, option unrestricted for Start and curb for End + Scenario: [Left-hand-side] Start End different approach, option unrestricted for Start and curb for End Given the profile file "car" initialized with """ profile.properties.left_hand_driving = true """ And the node map """ - s e + s a------b------c + e """ And the ways @@ -312,5 +541,122 @@ Feature: Approach parameter | bc | When I route I should get - | from | to | approaches | route | - | s | e | unrestricted curb | ab,bc | \ No newline at end of file + | from | to | approaches | route | + | s | e | unrestricted curb | ab,bc,bc | + + Scenario: [Left-hand-side] Start End different approach, option unrestricted for Start and opposite for End + Given the profile file "car" initialized with + """ + profile.properties.left_hand_driving = true + """ + And the node map + """ + s + a------b------c + e + """ + + And the ways + | nodes | + | ab | + | bc | + + When I route I should get + | from | to | approaches | route | + | s | e | unrestricted opposite | ab,bc | + + Scenario: [Left-hand-side] Start End different approach, option curb for Start and opposite for End + Given the profile file "car" initialized with + """ + profile.properties.left_hand_driving = true + """ + And the node map + """ + s + a------b------c + e + """ + + And the ways + | nodes | + | ab | + | bc | + + When I route I should get + | from | to | approaches | route | + | s | e | curb opposite | ab,bc | + + + + Scenario: Routes with more than two waypoints - uturns allowed + Given the profile "testbot" + And the node map + """ + 2 1 + a------b------c-----------d + | + 3 | 4 + e------f------g-----------h + | + | + i + + """ + + And the ways + | nodes | + | ab | + | bc | + | cd | + | bf | + | ef | + | fg | + | gh | + | ei | + + And the query options + | continue_straight | false | + + When I route I should get + | waypoints | approaches | locations | # | + | 1,2,3,4 | curb curb curb curb | _,_,_,a,b,f,_,_,i,h,_ | 1,2,2,a,b,f,3,3,i,h,4 (Only u-turn at end of roads) | + | 1,2,3,4 | curb unrestricted unrestricted curb | _,_,_,b,f,_,_,h,_ | 1,2,2,b,f,3,3,h,4 (Can u-turn at 2 and 3) | + | 1,2,3,4 | opposite opposite opposite opposite | _,d,a,_,_,b,f,i,_,_,_ | 1,d,a,2,2,b,f,i,3,3,4 (Only u-turn at end of roads) | + | 1,2,3,4 | opposite unrestricted unrestricted opposite | _,d,_,_,b,f,_,_,_ | 1,d,2,2,b,f,3,3,4 (Can u-turn at 2 and 3) | + + + Scenario: Routes with more than two waypoints - uturns forbidden + Given the profile "testbot" + And the node map + """ + 2 1 + a------b------c-----------d + | + 3 | 4 + e------f------g-----------h + | + | + i + + """ + + And the ways + | nodes | + | ab | + | bc | + | cd | + | bf | + | ef | + | fg | + | gh | + | ei | + + And the query options + | continue_straight | true | + + When I route I should get + | waypoints | approaches | locations | # | + | 1,2,3,4 | curb curb curb curb | _,_,_,a,b,f,_,_,i,h,_ | 1,2,2,a,b,f,3,3,i,h,4 (Only u-turn at end of roads) | + | 1,2,3,4 | curb opposite opposite curb | _,a,_,_,b,f,i,_,_,h,_ | 1,a,2,2,b,f,i,3,3,h,4 (switches stops with u-turns) | + | 1,2,3,4 | opposite opposite opposite opposite | _,d,a,_,_,b,f,i,_,_,_ | 1,d,a,2,2,b,f,i,3,3,4 (Only u-turn at end of roads) | + | 1,2,3,4 | opposite curb curb opposite | _,d,_,_,a,b,f,_,_,i,_ | 1,d,2,2,a,b,f,3,3,i,4 (switches stops with u-turns) | diff --git a/include/nodejs/node_osrm_support.hpp b/include/nodejs/node_osrm_support.hpp index f698374b534..24af5f1b152 100644 --- a/include/nodejs/node_osrm_support.hpp +++ b/include/nodejs/node_osrm_support.hpp @@ -577,7 +577,8 @@ inline bool argumentsToParameter(const Napi::CallbackInfo &args, } else { - ThrowError(args.Env(), "Approach must be a string: [curb, opposite, unrestricted] or null"); + ThrowError(args.Env(), + "Approach must be a string: [curb, opposite, unrestricted] or null"); return false; } } diff --git a/include/server/api/base_parameters_grammar.hpp b/include/server/api/base_parameters_grammar.hpp index a303c6a806d..d9f429ba8bc 100644 --- a/include/server/api/base_parameters_grammar.hpp +++ b/include/server/api/base_parameters_grammar.hpp @@ -166,8 +166,8 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar qi::lit("bearings=") > (-(qi::short_ > ',' > qi::short_))[ph::bind(add_bearing, qi::_r1, qi::_1)] % ';'; - approach_type.add("unrestricted", engine::Approach::UNRESTRICTED)("curb", - engine::Approach::CURB)("opposite", engine::Approach::OPPOSITE); + approach_type.add("unrestricted", engine::Approach::UNRESTRICTED)( + "curb", engine::Approach::CURB)("opposite", engine::Approach::OPPOSITE); approach_rule = qi::lit("approaches=") > (-approach_type % diff --git a/src/nodejs/node_osrm.cpp b/src/nodejs/node_osrm.cpp index 02cef8422ac..320aaa84941 100644 --- a/src/nodejs/node_osrm.cpp +++ b/src/nodejs/node_osrm.cpp @@ -292,7 +292,7 @@ inline void asyncForTiles(const Napi::CallbackInfo &info, * @param {String} [options.geometries=polyline] Returned route geometry format (influences overview and per step). Can also be `geojson`. * @param {String} [options.overview=simplified] Add overview geometry either `full`, `simplified` according to highest zoom level it could be display on, or not at all (`false`). * @param {Boolean} [options.continue_straight] Forces the route to keep going straight at waypoints and don't do a uturn even if it would be faster. Default value depends on the profile. - * @param {Array} [options.approaches] Keep waypoints on curb or opposite side of the road. Can be `null` (unrestricted, default), `curb` or `opposite`. + * @param {Array} [options.approaches] Restrict the direction on the road network at a waypoint, relative to the input coordinate. Can be `null` (unrestricted, default), `curb` or `opposite`. * `null`/`true`/`false` * @param {Array} [options.waypoints] Indices to coordinates to treat as waypoints. If not supplied, all coordinates are waypoints. Must include first and last coordinate index. * @param {String} [options.format] Which output format to use, either `json`, or [`flatbuffers`](https://github.com/Project-OSRM/osrm-backend/tree/master/include/engine/api/flatbuffers). @@ -337,7 +337,7 @@ Napi::Value Engine::route(const Napi::CallbackInfo &info) * @param {Boolean} [options.generate_hints=true] Whether or not adds a Hint to the response which can be used in subsequent requests. * @param {Number} [options.number=1] Number of nearest segments that should be returned. * Must be an integer greater than or equal to `1`. - * @param {Array} [options.approaches] Keep waypoints on curb or opposite side of the road. Can be `null` (unrestricted, default), `curb` or `opposite`. + * @param {Array} [options.approaches] Restrict the direction on the road network at a waypoint, relative to the input coordinate. Can be `null` (unrestricted, default), `curb` or `opposite`. * @param {String} [options.format] Which output format to use, either `json`, or [`flatbuffers`](https://github.com/Project-OSRM/osrm-backend/tree/master/include/engine/api/flatbuffers). * @param {String} [options.snapping] Which edges can be snapped to, either `default`, or `any`. `default` only snaps to edges marked by the profile as `is_startpoint`, `any` will allow snapping to any edge in the routing graph. * @param {Function} callback @@ -384,7 +384,7 @@ Napi::Value Engine::nearest(const Napi::CallbackInfo &info) * @param {Array} [options.sources] An array of `index` elements (`0 <= integer < #coordinates`) to use * location with given index as source. Default is to use all. * @param {Array} [options.destinations] An array of `index` elements (`0 <= integer < #coordinates`) to use location with given index as destination. Default is to use all. - * @param {Array} [options.approaches] Keep waypoints on curb or opposite side of the road. Can be `null` (unrestricted, default), `curb` or `opposite`. + * @param {Array} [options.approaches] Restrict the direction on the road network at a waypoint, relative to the input coordinate.. Can be `null` (unrestricted, default), `curb` or `opposite`. * @param {Number} [options.fallback_speed] Replace `null` responses in result with as-the-crow-flies estimates based on `fallback_speed`. Value is in metres/second. * @param {String} [options.fallback_coordinate] Either `input` (default) or `snapped`. If using a `fallback_speed`, use either the user-supplied coordinate (`input`), or the snapped coordinate (`snapped`) for calculating the as-the-crow-flies distance between two points. * @param {Number} [options.scale_factor] Multiply the table duration values in the table by this number for more controlled input into a route optimization solver. @@ -565,7 +565,7 @@ Napi::Value Engine::match(const Napi::CallbackInfo &info) * @param {Boolean} [options.roundtrip=true] Return route is a roundtrip. * @param {String} [options.source=any] Return route starts at `any` or `first` coordinate. * @param {String} [options.destination=any] Return route ends at `any` or `last` coordinate. - * @param {Array} [options.approaches] Keep waypoints on curb or opposite side of the road. Can be `null` (unrestricted, default), `curb` or `opposite`. + * @param {Array} [options.approaches] Restrict the direction on the road network at a waypoint, relative to the input coordinate. Can be `null` (unrestricted, default), `curb` or `opposite`. * @param {String} [options.snapping] Which edges can be snapped to, either `default`, or `any`. `default` only snaps to edges marked by the profile as `is_startpoint`, `any` will allow snapping to any edge in the routing graph. * * @returns {Object} containing `waypoints` and `trips`. diff --git a/test/nodejs/route.js b/test/nodejs/route.js index 29c7d417a49..f84ced4e0b2 100644 --- a/test/nodejs/route.js +++ b/test/nodejs/route.js @@ -573,7 +573,7 @@ test('route: throws on bad radiuses', function(assert) { }); test('route: routes Monaco with valid approaches values', function(assert) { - assert.plan(3); + assert.plan(4); var osrm = new OSRM(monaco_path); var options = { coordinates: two_test_coordinates, @@ -586,6 +586,10 @@ test('route: routes Monaco with valid approaches values', function(assert) { osrm.route(options, function(err, route) { assert.ifError(err); }); + options.approaches = ['opposite', 'opposite']; + osrm.route(options, function(err, route) { + assert.ifError(err); + }); options.approaches = ['unrestricted', null]; osrm.route(options, function(err, route) { assert.ifError(err); @@ -609,12 +613,12 @@ test('route: throws on bad approaches', function(assert) { coordinates: two_test_coordinates, approaches: ['curb', 'test'] }, function(err, route) {}) }, - /'approaches' param must be one of \[curb, unrestricted\]/); + /'approaches' param must be one of \[curb, opposite, unrestricted\]/); assert.throws(function() { osrm.route({ coordinates: two_test_coordinates, approaches: [10, 15] }, function(err, route) {}) }, - /Approach must be a string: \[curb, unrestricted\] or null/); + /Approach must be a string: \[curb, opposite, unrestricted\] or null/); }); test('route: routes Monaco with custom limits on MLD', function(assert) { diff --git a/unit_tests/server/parameters_parser.cpp b/unit_tests/server/parameters_parser.cpp index c28825a6801..22b03f6fd15 100644 --- a/unit_tests/server/parameters_parser.cpp +++ b/unit_tests/server/parameters_parser.cpp @@ -451,7 +451,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls) boost::none, engine::Approach::CURB, engine::Approach::UNRESTRICTED, - engine::Approach::CURB, + engine::Approach::OPPOSITE, }; RouteParameters reference_18{false, false, @@ -466,7 +466,7 @@ BOOST_AUTO_TEST_CASE(valid_route_urls) approaches_18}; auto result_18 = parseParameters( - "1,2;3,4;5,6;7,8?steps=false&approaches=;curb;unrestricted;curb"); + "1,2;3,4;5,6;7,8?steps=false&approaches=;curb;unrestricted;opposite"); BOOST_CHECK(result_18); BOOST_CHECK_EQUAL(reference_18.steps, result_18->steps); BOOST_CHECK_EQUAL(reference_18.alternatives, result_18->alternatives); From 52dcb00563d0cad7b15b0598fd09345b06b00102 Mon Sep 17 00:00:00 2001 From: Michael Bell Date: Wed, 3 Apr 2024 18:29:22 +0100 Subject: [PATCH 3/3] Update approach.hpp --- include/engine/approach.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/engine/approach.hpp b/include/engine/approach.hpp index abd35bd9d95..60fd68a463b 100644 --- a/include/engine/approach.hpp +++ b/include/engine/approach.hpp @@ -36,8 +36,8 @@ namespace osrm::engine enum class Approach : std::uint8_t { CURB = 0, - OPPOSITE = 1, - UNRESTRICTED = 2 + UNRESTRICTED = 1, + OPPOSITE = 2 }; } // namespace osrm::engine