This is an automated email from the git hooks/post-receive script. sebastic pushed a commit to branch master in repository osrm.
commit f42bc40499a2591351d12e73ffd9a40844c188f5 Author: Bas Couwenberg <[email protected]> Date: Fri Apr 29 23:13:17 2016 +0200 Imported Upstream version 5.0.0+ds --- CHANGELOG.md | 46 +++ appveyor-build.bat | 13 +- features/bicycle/bridge.feature | 26 +- features/car/bridge.feature | 26 +- features/guidance/end-of-road.feature | 19 +- features/guidance/fork.feature | 71 ++++ features/guidance/turn.feature | 529 +++++++++++++++++++++++++ features/testbot/continue_straight.feature | 92 +++++ include/engine/api/json_factory.hpp | 22 +- include/engine/api/route_api.hpp | 8 +- include/engine/guidance/assemble_leg.hpp | 100 ++++- include/engine/guidance/route_leg.hpp | 4 + include/extractor/travel_mode.hpp | 1 - include/server/api/table_parameter_grammar.hpp | 12 +- include/util/static_rtree.hpp | 14 +- include/util/vector_tile.hpp | 37 ++ profiles/bicycle.lua | 2 - profiles/car.lua | 2 - src/engine/api/json_factory.cpp | 4 +- src/engine/plugins/tile.cpp | 66 +-- src/extractor/extractor.cpp | 5 + src/extractor/scripting_environment.cpp | 1 - unit_tests/library/coordinates.hpp | 7 + unit_tests/library/match.cpp | 7 +- unit_tests/library/route.cpp | 80 +++- unit_tests/library/table.cpp | 131 +++++- unit_tests/library/tile.cpp | 106 ++++- unit_tests/library/trip.cpp | 132 +++++- unit_tests/library/waypoint_check.hpp | 24 ++ unit_tests/server/parameters_io.hpp | 59 +++ unit_tests/server/parameters_parser.cpp | 236 +++++------ unit_tests/util/static_rtree.cpp | 36 +- 32 files changed, 1670 insertions(+), 248 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4430ff0..b324d15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,49 @@ +# 5.0.0 + Changes with regard 5.0.0 RC2: + - API: + - if `geometry=geojson` is passed the resulting geometry can be a LineString or Point + depending on how many coordinates are present. + - the removal of the summary field was revered. for `steps=flase` the field will always be an empty string. + + Changes with regard to 4.9.1: + - API: + - BREAKING: Complete rewrite of the HTTP and library API. See detailed documentation in the wiki. + - BREAKING: The default coordinate order is now `longitude, latidue`. Exception: Polyline geometry + which follow the original Google specification of `latitdue, longitude`. + - BREAKING: Polyline geometries now use precision 5, instead of previously 6 + - BREAKING: Removed GPX support + - New service `tile` which serves debug vector tiles of the road network + - Completely new engine for guidance generation: + - Support for highway ramps + - Support for different intersection types (end of street, forks, merges) + - Instruction post-processing to merge unimportant instructions + - Improved handling of roundabouts + + - Tools: + - BREAKING: Renamed osrm-prepare to osrm-contract + - BREAKING: Removes profiles from osrm-contract, only needed in osrm-extract. + - Abort processing in osrm-extract if there are no snappable edges remaining. + - Added .properties file to osrm-extract ouput. + - Enables the use of multiple segment-speed-files on the osrm-contract command line + + - Profile changes: + - Remove movable bridge mode + - Add `maxspeed=none` tag to car profile. + - A `side_road` tag support for the OSRM car profile. + + - Fixes: + - Issue #2150: Prevents routing over delivery ways and nodes + - Issue #1972: Provide uninstall target + - Issue #2072: Disable alternatives by default and if core factor < 1.0 + - Issue #1999: Fix unpacking for self-loop nodes not in core. + + - Infrastructure: + - Cucumber test suit is now based on cucumber-js, removes Ruby as dependency + - Updated to mapbox/variant v1.1 + - Updated to libosmium v2.6.1 + - Remove GeoJSON based debugging output, replaced by debug tiles + + # 5.0.0 RC2 - Profiles: - `properties.allow_uturns_at_via` -> `properties.continue_straight_at_waypoint` (value is inverted!) diff --git a/appveyor-build.bat b/appveyor-build.bat index 5dbdfa2..3ef305d 100644 --- a/appveyor-build.bat +++ b/appveyor-build.bat @@ -116,14 +116,17 @@ IF %ERRORLEVEL% NEQ 0 GOTO ERROR SET PATH=%PROJECT_DIR%\osrm-deps\libs\bin;%PATH% -ECHO running engine-tests.exe ... -%Configuration%\unit_tests\engine-tests.exe -IF %ERRORLEVEL% NEQ 0 GOTO ERROR ECHO running extractor-tests.exe ... -%Configuration%\unit_tests\extractor-tests.exe +unit_tests\%Configuration%\extractor-tests.exe +IF %ERRORLEVEL% NEQ 0 GOTO ERROR +ECHO running engine-tests.exe ... +unit_tests\%Configuration%\engine-tests.exe IF %ERRORLEVEL% NEQ 0 GOTO ERROR ECHO running util-tests.exe ... -%Configuration%\unit_tests\util-tests.exe +unit_tests\%Configuration%\util-tests.exe +IF %ERRORLEVEL% NEQ 0 GOTO ERROR +ECHO running server-tests.exe ... +unit_tests\%Configuration%\server-tests.exe IF %ERRORLEVEL% NEQ 0 GOTO ERROR IF NOT "%APPVEYOR_REPO_BRANCH%"=="develop" GOTO DONE diff --git a/features/bicycle/bridge.feature b/features/bicycle/bridge.feature index e691ae1..9e3873f 100644 --- a/features/bicycle/bridge.feature +++ b/features/bicycle/bridge.feature @@ -1,5 +1,5 @@ @routing @bicycle @bridge -Feature: Bicycle - Handle movable bridge +Feature: Bicycle - Handle cycling Background: Given the profile "bicycle" @@ -18,14 +18,14 @@ Feature: Bicycle - Handle movable bridge When I route I should get | from | to | route | modes | - | a | g | abc,cde,efg,efg | cycling,movable bridge,cycling,cycling | - | b | f | abc,cde,efg,efg | cycling,movable bridge,cycling,cycling | - | e | c | cde,cde | movable bridge,movable bridge | - | e | b | cde,abc,abc | movable bridge,cycling,cycling | - | e | a | cde,abc,abc | movable bridge,cycling,cycling | - | c | e | cde,cde | movable bridge,movable bridge | - | c | f | cde,efg,efg | movable bridge,cycling,cycling | - | c | g | cde,efg,efg | movable bridge,cycling,cycling | + | a | g | abc,cde,efg,efg | cycling,cycling,cycling,cycling | + | b | f | abc,cde,efg,efg | cycling,cycling,cycling,cycling | + | e | c | cde,cde | cycling,cycling | + | e | b | cde,abc,abc | cycling,cycling,cycling | + | e | a | cde,abc,abc | cycling,cycling,cycling | + | c | e | cde,cde | cycling,cycling | + | c | f | cde,efg,efg | cycling,cycling,cycling | + | c | g | cde,efg,efg | cycling,cycling,cycling | Scenario: Bicycle - Properly handle durations Given the node map @@ -41,7 +41,7 @@ Feature: Bicycle - Handle movable bridge When I route I should get | from | to | route | modes | speed | - | a | g | abc,cde,efg,efg | cycling,movable bridge,cycling,cycling | 5 km/h | - | b | f | abc,cde,efg,efg | cycling,movable bridge,cycling,cycling | 4 km/h | - | c | e | cde,cde | movable bridge,movable bridge | 2 km/h | - | e | c | cde,cde | movable bridge,movable bridge | 2 km/h | + | a | g | abc,cde,efg,efg | cycling,cycling,cycling,cycling | 5 km/h | + | b | f | abc,cde,efg,efg | cycling,cycling,cycling,cycling | 4 km/h | + | c | e | cde,cde | cycling,cycling | 2 km/h | + | e | c | cde,cde | cycling,cycling | 2 km/h | diff --git a/features/car/bridge.feature b/features/car/bridge.feature index 931f1d9..c1cb506 100644 --- a/features/car/bridge.feature +++ b/features/car/bridge.feature @@ -1,5 +1,5 @@ @routing @car @bridge -Feature: Car - Handle movable bridge +Feature: Car - Handle driving Background: Given the profile "car" @@ -18,14 +18,14 @@ Feature: Car - Handle movable bridge When I route I should get | from | to | route | modes | - | a | g | abc,cde,efg,efg | driving,movable bridge,driving,driving | - | b | f | abc,cde,efg,efg | driving,movable bridge,driving,driving | - | e | c | cde,cde | movable bridge,movable bridge | - | e | b | cde,abc,abc | movable bridge,driving,driving | - | e | a | cde,abc,abc | movable bridge,driving,driving | - | c | e | cde,cde | movable bridge,movable bridge | - | c | f | cde,efg,efg | movable bridge,driving,driving | - | c | g | cde,efg,efg | movable bridge,driving,driving | + | a | g | abc,cde,efg,efg | driving,driving,driving,driving | + | b | f | abc,cde,efg,efg | driving,driving,driving,driving | + | e | c | cde,cde | driving,driving | + | e | b | cde,abc,abc | driving,driving,driving | + | e | a | cde,abc,abc | driving,driving,driving | + | c | e | cde,cde | driving,driving | + | c | f | cde,efg,efg | driving,driving,driving | + | c | g | cde,efg,efg | driving,driving,driving | Scenario: Car - Properly handle durations Given the node map @@ -41,7 +41,7 @@ Feature: Car - Handle movable bridge When I route I should get | from | to | route | modes | speed | - | a | g | abc,cde,efg,efg | driving,movable bridge,driving,driving | 7 km/h | - | b | f | abc,cde,efg,efg | driving,movable bridge,driving,driving | 5 km/h | - | c | e | cde,cde | movable bridge,movable bridge | 2 km/h | - | e | c | cde,cde | movable bridge,movable bridge | 2 km/h | + | a | g | abc,cde,efg,efg | driving,driving,driving,driving | 7 km/h | + | b | f | abc,cde,efg,efg | driving,driving,driving,driving | 5 km/h | + | c | e | cde,cde | driving,driving | 2 km/h | + | e | c | cde,cde | driving,driving | 2 km/h | diff --git a/features/guidance/end-of-road.feature b/features/guidance/end-of-road.feature index 7f8231b..323f5df 100644 --- a/features/guidance/end-of-road.feature +++ b/features/guidance/end-of-road.feature @@ -21,7 +21,6 @@ Feature: End Of Road Instructions | a,c | ab,cbd,cbd | depart,end of road left,arrive | | a,d | ab,cbd,cbd | depart,end of road right,arrive | - Scenario: End of Road with three streets Given the node map | | | c | @@ -104,3 +103,21 @@ Feature: End Of Road Instructions | waypoints | route | turns | | a,c | ab,cbd,cbd | depart,end of road left,arrive | | a,d | ab,cbd,cbd | depart,end of road right,arrive | + + Scenario: End of Road with two ramps - prefer ramp over end of road + Given the node map + | | | c | + | a | | b | + | | | d | + + And the ways + | nodes | highway | + | ab | primary | + | bc | motorway_link | + | bd | motorway_link | + + When I route I should get + | waypoints | route | turns | + | a,c | ab,bc,bc | depart,ramp left,arrive | + | a,d | ab,bd,bd | depart,ramp right,arrive | + diff --git a/features/guidance/fork.feature b/features/guidance/fork.feature index 7b78a28..916799e 100644 --- a/features/guidance/fork.feature +++ b/features/guidance/fork.feature @@ -211,3 +211,74 @@ Feature: Fork Instructions | a,c | ,, | depart,fork slight left,arrive | | a,d | ,, | depart,fork slight right,arrive | + Scenario: Non-Fork on complex intersection - left + Given the node map + | | | | | c | + | a | | b | | | + | | e | | | d | + + And the ways + | nodes | highway | + | abc | secondary | + | bd | tertiary | + | eb | tertiary | + + When I route I should get + | waypoints | route | turns | + | a,c | abc,abc | depart,arrive | + | a,d | abc,bd,bd | depart,turn slight right,arrive | + + Scenario: Non-Fork on complex intersection - right + Given the node map + | | e | | | c | + | a | | b | | | + | | | | | d | + + And the ways + | nodes | highway | + | abd | secondary | + | bc | tertiary | + | eb | tertiary | + + When I route I should get + | waypoints | route | turns | + | a,c | abd,bc,bc | depart,turn slight left,arrive | + | a,d | abd,abd | depart,arrive | + + @pr2275 @bug + Scenario: Tripple fork + Given the node map + | | | | | | | | | c | + | a | | b | | d | | | | | + | | | | | | | | | e | + + And the ways + | nodes | highway | + | ab | secondary | + | bc | secondary | + | bd | secondary | + | be | secondary | + + When I route I should get + | waypoints | route | turns | + | a,c | ab,bc,bc | depart,fork slight left,arrive | + | a,d | ab,bd,bd | depart,fork straight,arrive | + | a,e | ab,be,be | depart,fork slight right,arrive | + + Scenario: Tripple fork -- middle obvious + Given the node map + | | | | | c | + | a | | b | | d | + | | | | | e | + + And the ways + | nodes | highway | + | abd | secondary | + | bc | secondary | + | be | secondary | + + When I route I should get + | waypoints | route | turns | + | a,c | abd,bc,bc | depart,turn slight left,arrive | + | a,d | abd,abd | depart,arrive | + | a,e | abd,be,be | depart,turn slight right,arrive | diff --git a/features/guidance/turn.feature b/features/guidance/turn.feature index 3eb5fc3..20f4226 100644 --- a/features/guidance/turn.feature +++ b/features/guidance/turn.feature @@ -282,3 +282,532 @@ Feature: Simple Turns | h,c | first,second,second | depart,turn left,arrive | | h,i | first,first,first | depart,continue uturn,arrive | + Scenario: Three Way Similar Sharp Turns + Given the node map + | a | | | | b | + | c | | | | | + | | d | | | | + + And the ways + | nodes | highway | + | ab | primary | + | bc | primary | + | bd | primary | + + When I route I should get + | waypoints | route | turns | + | a,c | ab,bc,bc | depart,turn sharp right,arrive | + | a,d | ab,bd,bd | depart,turn sharp right,arrive | + | d,c | bd,bc,bc | depart,turn sharp left,arrive | + | d,a | bd,ab,ab | depart,turn sharp left,arrive | + + Scenario: Left Turn Assignment (1) + Given the node map + | | | | | d | + | a | | b | | c | + | | | e | | | + + And the ways + | nodes | highway | + | abc | primary | + | bd | primary | + | be | primary | + + When I route I should get + | waypoints | route | turns | + | a,d | abc,bd,bd | depart,turn slight left,arrive | + + Scenario: Left Turn Assignment (2) + Given the node map + | | | | | d | + | | | | | | + | a | | b | | c | + | | | e | | | + + And the ways + | nodes | highway | + | abc | primary | + | bd | primary | + | be | primary | + + When I route I should get + | waypoints | route | turns | + | a,d | abc,bd,bd | depart,turn left,arrive | + + Scenario: Left Turn Assignment (3) + Given the node map + | | | | d | | + | | | | | | + | | | | | | + | a | | b | | c | + | | | e | | | + + And the ways + | nodes | highway | + | abc | primary | + | bd | primary | + | be | primary | + + When I route I should get + | waypoints | route | turns | + | a,d | abc,bd,bd | depart,turn left,arrive | + + Scenario: Left Turn Assignment (4) + Given the node map + | | | d | | | + | | | | | | + | | | | | | + | | | | | | + | a | | b | | c | + | | | e | | | + + And the ways + | nodes | highway | + | abc | primary | + | bd | primary | + | be | primary | + + When I route I should get + | waypoints | route | turns | + | a,d | abc,bd,bd | depart,turn left,arrive | + + Scenario: Left Turn Assignment (5) + Given the node map + | | d | | | | + | | | | | | + | | | | | | + | a | | b | | c | + | | | e | | | + + And the ways + | nodes | highway | + | abc | primary | + | bd | primary | + | be | primary | + + When I route I should get + | waypoints | route | turns | + | a,d | abc,bd,bd | depart,turn left,arrive | + + @bug @pr2275 + Scenario: Left Turn Assignment (6) + Given the node map + | d | | | | | + | | | | | | + | a | | b | | c | + | | | e | | | + + And the ways + | nodes | highway | + | abc | primary | + | bd | primary | + | be | primary | + + When I route I should get + | waypoints | route | turns | + | a,d | abc,bd,bd | depart,turn sharp left,arrive | + + Scenario: Left Turn Assignment (7) + Given the node map + | d | | | | | + | a | | b | | c | + | | | e | | | + + And the ways + | nodes | highway | + | abc | primary | + | bd | primary | + | be | primary | + + When I route I should get + | waypoints | route | turns | + | a,d | abc,bd,bd | depart,turn sharp left,arrive | + + Scenario: Right Turn Assignment (1) + Given the node map + | | | e | | | + | a | | b | | c | + | | | | | d | + + And the ways + | nodes | highway | + | abc | primary | + | bd | primary | + | be | primary | + + When I route I should get + | waypoints | route | turns | + | a,d | abc,bd,bd | depart,turn slight right,arrive | + + Scenario: Right Turn Assignment (2) + Given the node map + | | | e | | | + | a | | b | | c | + | | | | | | + | | | | | d | + + And the ways + | nodes | highway | + | abc | primary | + | bd | primary | + | be | primary | + + When I route I should get + | waypoints | route | turns | + | a,d | abc,bd,bd | depart,turn right,arrive | + + Scenario: Right Turn Assignment (3) + Given the node map + | | | e | | | + | a | | b | | c | + | | | | | | + | | | | | | + | | | | d | | + + And the ways + | nodes | highway | + | abc | primary | + | bd | primary | + | be | primary | + + When I route I should get + | waypoints | route | turns | + | a,d | abc,bd,bd | depart,turn right,arrive | + + Scenario: Right Turn Assignment (4) + Given the node map + | | | e | | | + | a | | b | | c | + | | | | | | + | | | | | | + | | | | | | + | | | d | | | + + And the ways + | nodes | highway | + | abc | primary | + | bd | primary | + | be | primary | + + When I route I should get + | waypoints | route | turns | + | a,d | abc,bd,bd | depart,turn right,arrive | + + Scenario: Right Turn Assignment (5) + Given the node map + | | | e | | | + | a | | b | | c | + | | | | | | + | | | | | | + | | d | | | | + + And the ways + | nodes | highway | + | abc | primary | + | bd | primary | + | be | primary | + + When I route I should get + | waypoints | route | turns | + | a,d | abc,bd,bd | depart,turn right,arrive | + + @bug @pr2275 + Scenario: Right Turn Assignment (6) + Given the node map + | | | e | | | + | a | | b | | c | + | | | | | | + | d | | | | | + + + And the ways + | nodes | highway | + | abc | primary | + | bd | primary | + | be | primary | + + When I route I should get + | waypoints | route | turns | + | a,d | abc,bd,bd | depart,turn sharp right,arrive | + + Scenario: Right Turn Assignment (7) + Given the node map + | | | e | | | + | a | | b | | c | + | d | | | | | + + + And the ways + | nodes | highway | + | abc | primary | + | bd | primary | + | be | primary | + + When I route I should get + | waypoints | route | turns | + | a,d | abc,bd,bd | depart,turn sharp right,arrive | + + Scenario: Right Turn Assignment Two Turns + Given the node map + | | | f | | | + | a | | b | | c | + | | | | | | + | d | e | | | | + + + And the ways + | nodes | highway | + | abc | primary | + | bd | primary | + | be | primary | + | bf | primary | + + When I route I should get + | waypoints | route | turns | + | a,d | abc,bd,bd | depart,turn sharp right,arrive | + | a,e | abc,be,be | depart,turn right,arrive | + + Scenario: Right Turn Assignment Two Turns (2) + Given the node map + | | | f | c | | + | a | | b | | | + | | | | | e | + | | | | d | | + + + And the ways + | nodes | highway | + | abc | primary | + | bd | primary | + | be | primary | + | bf | primary | + + When I route I should get + | waypoints | route | turns | + | a,d | abc,bd,bd | depart,turn right,arrive | + | a,e | abc,be,be | depart,turn slight right,arrive | + + Scenario: Right Turn Assignment Two Turns (3) + Given the node map + | | | f | | | + | a | | b | | c | + | | | | | e | + | | | | d | | + + + And the ways + | nodes | highway | + | abc | primary | + | bd | primary | + | be | primary | + | bf | primary | + + When I route I should get + | waypoints | route | turns | + | a,d | abc,bd,bd | depart,turn right,arrive | + | a,e | abc,be,be | depart,turn slight right,arrive | + + Scenario: Right Turn Assignment Two Turns (4) + Given the node map + | | | f | | | + | a | | b | | c | + | | | | | | + | | | d | | e | + + + And the ways + | nodes | highway | + | abc | primary | + | bd | primary | + | be | primary | + | bf | primary | + + When I route I should get + | waypoints | route | turns | + | a,d | abc,bd,bd | depart,turn right,arrive | + | a,e | abc,be,be | depart,turn slight right,arrive | + + Scenario: Right Turn Assignment Three Turns + Given the node map + | | | g | | | + | a | | b | | c | + | | d | | f | | + | | | e | | | + + And the ways + | nodes | highway | + | abc | primary | + | bd | primary | + | be | primary | + | bf | primary | + | bg | primary | + + When I route I should get + | waypoints | route | turns | + | a,d | abc,bd,bd | depart,turn sharp right,arrive | + | a,e | abc,be,be | depart,turn right,arrive | + | a,f | abc,bf,bf | depart,turn slight right,arrive | + + Scenario: Slight Turn involving Oneways + Given the node map + | | | a | | | + | | | | | | + | | | b | | e | + | d | | | | | + | | | c | | | + + And the ways + | nodes | highway | oneway | + | abc | primary | yes | + | dbe | primary | no | + + When I route I should get + | waypoints | route | turns | + | a,c | abc,abc | depart,arrive | + | d,e | dbe,dbe | depart,arrive | + | e,d | dbe,dbe | depart,arrive | + + @bug @pr2275 + Scenario: Slight Turn involving Oneways + Given the node map + | | | | a | | + | | | | | | + | | | | | | + | | | b | | e | + | d | | | | | + | | | c | | | + + And the ways + | nodes | highway | oneway | + | abc | primary | yes | + | dbe | primary | no | + + When I route I should get + | waypoints | route | turns | + | a,c | abc,abc | depart,arrive | + | d,e | dbe,dbe | depart,arrive | + | e,d | dbe,dbe | depart,arrive | + + + Scenario: Slight Turn involving Oneways - Name Change + Given the node map + | | | a | | | + | | | | | | + | | | b | | e | + | d | | | | | + | | | c | | | + + And the ways + | nodes | highway | oneway | + | abc | primary | yes | + | db | primary | no | + | be | primary | no | + + When I route I should get + | waypoints | route | turns | + | a,c | abc,abc | depart,arrive | + | d,e | db,be,be | depart,new name slight right,arrive | + | e,d | be,db,db | depart,new name slight left,arrive | + + Scenario: Right Turn Assignment Three Conflicting Turns with invalid - 1 + Given the node map + | | | g | | | + | a | | b | | c | + | | | | | | + | | d | e | f | | + + And the ways + | nodes | highway | oneway | + | abc | primary | no | + | db | primary | yes | + | eb | primary | no | + | fb | primary | no | + | bg | primary | no | + + When I route I should get + | waypoints | route | turns | + | a,e | abc,eb,eb | depart,turn right,arrive | + | a,f | abc,fb,fb | depart,turn slight right,arrive | + + @bug @pr2275 + Scenario: Right Turn Assignment Three Conflicting Turns with invalid - 2 + Given the node map + | | | g | | | + | a | | b | | c | + | | | | | | + | | d | e | f | | + + And the ways + | nodes | highway | oneway | + | abc | primary | no | + | db | primary | no | + | eb | primary | yes | + | fb | primary | no | + | bg | primary | no | + + When I route I should get + | waypoints | route | turns | + | a,d | abc,db,db | depart,turn sharp right,arrive | + | a,f | abc,fb,fb | depart,turn right,arrive | + + Scenario: Right Turn Assignment Three Conflicting Turns with invalid - 3 + Given the node map + | | | g | | | + | a | | b | | c | + | | | | | | + | | d | e | f | | + + And the ways + | nodes | highway | oneway | + | abc | primary | no | + | db | primary | no | + | be | primary | no | + | fb | primary | yes | + | bg | primary | no | + + When I route I should get + | waypoints | route | turns | + | a,d | abc,db,db | depart,turn sharp right,arrive | + | a,e | abc,be,be | depart,turn right,arrive | + + Scenario: Conflicting Turns with well distinguished turn + Given the node map + | a | | | b | | | c | + | | | | | | | | + | f | | | | | | d | + | | | | | | | e | + + And the ways + | nodes | highway | + | abc | primary | + | bd | primary | + | be | primary | + | bf | primary | + + When I route I should get + | waypoints | route | turns | + | a,d | abc,bd,bd | depart,turn slight right,arrive | + | a,e | abc,be,be | depart,turn right,arrive | + | a,f | abc,bf,bf | depart,turn sharp right,arrive | + + @bug @pr2275 + Scenario: Conflicting Turns with well distinguished turn (back) + Given the node map + | a | | | b | | | c | + | | | | | | | | + | d | | | | | | f | + | | e | | | | | | + + And the ways + | nodes | highway | + | abc | primary | + | bd | primary | + | be | primary | + | bf | primary | + + When I route I should get + | waypoints | route | turns | + | a,d | abc,bd,bd | depart,turn sharp right,arrive | + | a,e | abc,be,be | depart,turn right,arrive | + | a,f | abc,bf,bf | depart,turn slight right,arrive | + diff --git a/features/testbot/continue_straight.feature b/features/testbot/continue_straight.feature new file mode 100644 index 0000000..40fcbb4 --- /dev/null +++ b/features/testbot/continue_straight.feature @@ -0,0 +1,92 @@ +@routing @continue_straight @via @testbot +Feature: U-turns at via points + + Background: + Given the profile "testbot" + + Scenario: Continue straight at waypoints enabled by default + Given the node map + | a | b | c | d | + | | e | f | g | + + And the ways + | nodes | + | ab | + | bc | + | cd | + | be | + | dg | + | ef | + | fg | + + When I route I should get + | waypoints | route | + | a,e,c | ab,be,be,ef,fg,dg,cd,cd | + + Scenario: Query parameter to disallow changing direction at all waypoints + Given the node map + | a | b | c | d | + | | e | f | g | + + And the query options + | continue_straight | false | + + And the ways + | nodes | + | ab | + | bc | + | cd | + | be | + | dg | + | ef | + | fg | + + When I route I should get + | waypoints | route | + | a,e,c | ab,be,be,be,bc,bc | + + Scenario: Instructions at waypoints at u-turns + Given the node map + | a | b | c | d | + | | e | f | g | + + And the query options + | continue_straight | false | + + And the ways + | nodes | + | ab | + | bc | + | cd | + | be | + | dg | + | ef | + | fg | + + When I route I should get + | waypoints | route | + | a,e,c | ab,be,be,be,bc,bc | + + Scenario: u-turn mixed with non-uturn vias + Given the node map + | a | 1 | b | 3 | c | 5 | d | + | | | 2 | | | | 4 | + | | | e | | f | | g | + + And the query options + | continue_straight | false | + + And the ways + | nodes | oneway | + | ab | no | + | bc | no | + | cd | no | + | be | yes | + | dg | no | + | ef | no | + | fg | no | + + When I route I should get + | waypoints | route | + | 1,2,3,4,5 | ab,be,be,be,ef,fg,dg,cd,bc,bc,bc,cd,dg,dg,dg,cd,cd | + diff --git a/include/engine/api/json_factory.hpp b/include/engine/api/json_factory.hpp index 0b1e5f3..398fb68 100644 --- a/include/engine/api/json_factory.hpp +++ b/include/engine/api/json_factory.hpp @@ -48,13 +48,25 @@ template <typename ForwardIter> util::json::String makePolyline(ForwardIter begi } template <typename ForwardIter> -util::json::Object makeGeoJSONLineString(ForwardIter begin, ForwardIter end) +util::json::Object makeGeoJSONGeometry(ForwardIter begin, ForwardIter end) { + auto num_coordinates = std::distance(begin, end); + BOOST_ASSERT(num_coordinates != 0); util::json::Object geojson; - geojson.values["type"] = "LineString"; - util::json::Array coordinates; - std::transform(begin, end, std::back_inserter(coordinates.values), &detail::coordinateToLonLat); - geojson.values["coordinates"] = std::move(coordinates); + if (num_coordinates > 1) + { + geojson.values["type"] = "LineString"; + util::json::Array coordinates; + std::transform(begin, end, std::back_inserter(coordinates.values), &detail::coordinateToLonLat); + geojson.values["coordinates"] = std::move(coordinates); + } + else if (num_coordinates > 0) + { + geojson.values["type"] = "Point"; + util::json::Array coordinates; + coordinates.values.push_back(detail::coordinateToLonLat(*begin)); + geojson.values["coordinates"] = std::move(coordinates); + } return geojson; } diff --git a/include/engine/api/route_api.hpp b/include/engine/api/route_api.hpp index f2b7a73..1907bee 100644 --- a/include/engine/api/route_api.hpp +++ b/include/engine/api/route_api.hpp @@ -69,7 +69,7 @@ class RouteAPI : public BaseAPI } BOOST_ASSERT(parameters.geometries == RouteParameters::GeometriesType::GeoJSON); - return json::makeGeoJSONLineString(begin, end); + return json::makeGeoJSONGeometry(begin, end); } util::json::Object MakeRoute(const std::vector<PhantomNodes> &segment_end_coordinates, @@ -93,8 +93,8 @@ class RouteAPI : public BaseAPI auto leg_geometry = guidance::assembleGeometry( BaseAPI::facade, path_data, phantoms.source_phantom, phantoms.target_phantom); - auto leg = guidance::assembleLeg(path_data, leg_geometry, phantoms.source_phantom, - phantoms.target_phantom, reversed_target); + auto leg = guidance::assembleLeg(facade, path_data, leg_geometry, phantoms.source_phantom, + phantoms.target_phantom, reversed_target, parameters.steps); if (parameters.steps) { @@ -169,7 +169,7 @@ class RouteAPI : public BaseAPI leg_geometry.locations.begin() + step.geometry_end)); } BOOST_ASSERT(parameters.geometries == RouteParameters::GeometriesType::GeoJSON); - return static_cast<util::json::Value>(json::makeGeoJSONLineString( + return static_cast<util::json::Value>(json::makeGeoJSONGeometry( leg_geometry.locations.begin() + step.geometry_begin, leg_geometry.locations.begin() + step.geometry_end)); }); diff --git a/include/engine/guidance/assemble_leg.hpp b/include/engine/guidance/assemble_leg.hpp index b8d3dfe..6f8e6cb 100644 --- a/include/engine/guidance/assemble_leg.hpp +++ b/include/engine/guidance/assemble_leg.hpp @@ -1,6 +1,7 @@ #ifndef ENGINE_GUIDANCE_ASSEMBLE_LEG_HPP_ #define ENGINE_GUIDANCE_ASSEMBLE_LEG_HPP_ +#include "engine/datafacade/datafacade_base.hpp" #include "engine/guidance/leg_geometry.hpp" #include "engine/guidance/route_leg.hpp" #include "engine/guidance/route_step.hpp" @@ -22,12 +23,86 @@ namespace engine { namespace guidance { +namespace detail +{ +const constexpr std::size_t MAX_USED_SEGMENTS = 2; +struct NamedSegment +{ + EdgeWeight duration; + std::uint32_t position; + std::uint32_t name_id; +}; + +template <std::size_t SegmentNumber> +std::array<std::uint32_t, SegmentNumber> summarizeRoute(const std::vector<PathData> &route_data) +{ + // merges segments with same name id + const auto collapse_segments = [](std::vector<NamedSegment> &segments) + { + auto out = segments.begin(); + auto end = segments.end(); + for (auto in = segments.begin(); in != end; ++in) + { + if (in->name_id == out->name_id) + { + out->duration += in->duration; + } + else + { + ++out; + BOOST_ASSERT(out != end); + *out = *in; + } + } + return out; + }; + + std::vector<NamedSegment> segments(route_data.size()); + std::uint32_t index = 0; + std::transform( + route_data.begin(), route_data.end(), segments.begin(), [&index](const PathData &point) + { + return NamedSegment{point.duration_until_turn, index++, point.name_id}; + }); + // this makes sure that the segment with the lowest position comes first + std::sort(segments.begin(), segments.end(), [](const NamedSegment &lhs, const NamedSegment &rhs) + { + return lhs.name_id < rhs.name_id || + (lhs.name_id == rhs.name_id && lhs.position < rhs.position); + }); + auto new_end = collapse_segments(segments); + segments.resize(new_end - segments.begin()); + // sort descending + std::sort(segments.begin(), segments.end(), [](const NamedSegment &lhs, const NamedSegment &rhs) + { + return lhs.duration > rhs.duration; + }); + + // make sure the segments are sorted by position + segments.resize(std::min(segments.size(), SegmentNumber)); + std::sort(segments.begin(), segments.end(), [](const NamedSegment &lhs, const NamedSegment &rhs) + { + return lhs.position < rhs.position; + }); -inline RouteLeg assembleLeg(const std::vector<PathData> &route_data, + std::array<std::uint32_t, SegmentNumber> summary; + std::fill(summary.begin(), summary.end(), 0); + std::transform(segments.begin(), segments.end(), summary.begin(), + [](const NamedSegment &segment) + { + return segment.name_id; + }); + return summary; +} +} + +inline RouteLeg assembleLeg(const datafacade::BaseDataFacade &facade, + const std::vector<PathData> &route_data, const LegGeometry &leg_geometry, const PhantomNode &source_node, const PhantomNode &target_node, - const bool target_traversed_in_reverse) + const bool target_traversed_in_reverse, + const bool needs_summary) { const auto target_duration = (target_traversed_in_reverse ? target_node.reverse_weight : target_node.forward_weight) / @@ -70,7 +145,26 @@ inline RouteLeg assembleLeg(const std::vector<PathData> &route_data, 10.0; } - return RouteLeg{duration, distance, {}}; + std::string summary; + if (needs_summary) + { + auto summary_array = detail::summarizeRoute<detail::MAX_USED_SEGMENTS>(route_data); + + BOOST_ASSERT(detail::MAX_USED_SEGMENTS > 0); + BOOST_ASSERT(summary_array.begin() != summary_array.end()); + summary = std::accumulate(std::next(summary_array.begin()), summary_array.end(), + facade.GetNameForID(summary_array.front()), + [&facade](std::string previous, const std::uint32_t name_id) + { + if (name_id != 0) + { + previous += ", " + facade.GetNameForID(name_id); + } + return previous; + }); + } + + return RouteLeg{duration, distance, summary, {}}; } } // namespace guidance diff --git a/include/engine/guidance/route_leg.hpp b/include/engine/guidance/route_leg.hpp index f3b8de1..5ecca4f 100644 --- a/include/engine/guidance/route_leg.hpp +++ b/include/engine/guidance/route_leg.hpp @@ -3,6 +3,9 @@ #include "engine/guidance/route_step.hpp" +#include <boost/optional.hpp> + +#include <string> #include <vector> namespace osrm @@ -16,6 +19,7 @@ struct RouteLeg { double duration; double distance; + std::string summary; std::vector<RouteStep> steps; }; } diff --git a/include/extractor/travel_mode.hpp b/include/extractor/travel_mode.hpp index 7ec7bec..fa75c37 100644 --- a/include/extractor/travel_mode.hpp +++ b/include/extractor/travel_mode.hpp @@ -46,7 +46,6 @@ const constexpr osrm::extractor::TravelMode TRAVEL_MODE_WALKING = 3; const constexpr osrm::extractor::TravelMode TRAVEL_MODE_FERRY = 4; const constexpr osrm::extractor::TravelMode TRAVEL_MODE_TRAIN = 5; const constexpr osrm::extractor::TravelMode TRAVEL_MODE_PUSHING_BIKE = 6; -const constexpr osrm::extractor::TravelMode TRAVEL_MODE_MOVABLE_BRIDGE = 7; // FIXME only for testbot.lua const constexpr osrm::extractor::TravelMode TRAVEL_MODE_STEPS_UP = 8; const constexpr osrm::extractor::TravelMode TRAVEL_MODE_STEPS_DOWN = 9; diff --git a/include/server/api/table_parameter_grammar.hpp b/include/server/api/table_parameter_grammar.hpp index 00fe703..b95b1b8 100644 --- a/include/server/api/table_parameter_grammar.hpp +++ b/include/server/api/table_parameter_grammar.hpp @@ -32,15 +32,11 @@ struct TableParametersGrammar final : public BaseParametersGrammar }; // TODO: ulonglong -> size_t not only on Windows but on all 32 bit platforms; unsupported anyway as of now #ifdef WIN32 - destinations_rule = (qi::lit("destinations=") > (qi::ulong_long % ";")[set_destiantions]) | - qi::lit("destinations=all"); - sources_rule = - (qi::lit("sources=") > (qi::ulong_long % ";")[set_sources]) | qi::lit("sources=all"); + destinations_rule = qi::lit("destinations=all") | (qi::lit("destinations=") > (qi::ulong_long % ";")[set_destiantions]); + sources_rule = qi::lit("sources=all") | (qi::lit("sources=") > (qi::ulong_long % ";")[set_sources]); #else - destinations_rule = (qi::lit("destinations=") > (qi::ulong_ % ";")[set_destiantions]) | - qi::lit("destinations=all"); - sources_rule = - (qi::lit("sources=") > (qi::ulong_ % ";")[set_sources]) | qi::lit("sources=all"); + destinations_rule = qi::lit("destinations=all") | (qi::lit("destinations=") > (qi::ulong_ % ";")[set_destiantions]); + sources_rule = qi::lit("sources=all") | (qi::lit("sources=") > (qi::ulong_ % ";")[set_sources]); #endif table_rule = destinations_rule | sources_rule; diff --git a/include/util/static_rtree.hpp b/include/util/static_rtree.hpp index 32bd60b..2e5a988 100644 --- a/include/util/static_rtree.hpp +++ b/include/util/static_rtree.hpp @@ -441,6 +441,14 @@ class StaticRTree // inspecting an actual road segment auto ¤t_candidate = current_query_node.node.template get<CandidateSegment>(); + // to allow returns of no-results if too restrictive filtering, this needs to be done here + // even though performance would indicate that we want to stop after adding the first candidate + if (terminate(results.size(), current_candidate)) + { + traversal_queue = std::priority_queue<QueryCandidate>{}; + break; + } + auto use_segment = filter(current_candidate); if (!use_segment.first && !use_segment.second) { @@ -451,12 +459,6 @@ class StaticRTree // store phantom node in result vector results.push_back(std::move(current_candidate.data)); - - if (terminate(results.size(), current_candidate)) - { - traversal_queue = std::priority_queue<QueryCandidate>{}; - break; - } } } diff --git a/include/util/vector_tile.hpp b/include/util/vector_tile.hpp new file mode 100644 index 0000000..8d816da --- /dev/null +++ b/include/util/vector_tile.hpp @@ -0,0 +1,37 @@ +#ifndef OSRM_UTIL_VECTOR_TILE_HPP +#define OSRM_UTIL_VECTOR_TILE_HPP + +#include <cstdint> + +namespace osrm +{ +namespace util +{ +namespace vector_tile +{ + +const constexpr std::uint32_t LAYER_TAG = 3; +const constexpr std::uint32_t NAME_TAG = 1; +const constexpr std::uint32_t VERSION_TAG = 15; +const constexpr std::uint32_t EXTEND_TAG = 5; +const constexpr std::uint32_t FEATURE_TAG = 2; +const constexpr std::uint32_t GEOMETRY_TAG = 3; +const constexpr std::uint32_t VARIANT_TAG = 4; +const constexpr std::uint32_t KEY_TAG = 3; +const constexpr std::uint32_t ID_TAG = 1; +const constexpr std::uint32_t GEOMETRY_TYPE_LINE = 2; +const constexpr std::uint32_t FEATURE_ATTRIBUTES_TAG = 2; +const constexpr std::uint32_t FEATURE_GEOMETRIES_TAG = 4; +const constexpr std::uint32_t VARIANT_TYPE_UINT32 = 5; +const constexpr std::uint32_t VARIANT_TYPE_BOOL = 7; +const constexpr std::uint32_t VARIANT_TYPE_STRING = 1; +const constexpr std::uint32_t VARIANT_TYPE_DOUBLE = 3; + +// Vector tiles are 4096 virtual pixels on each side +const constexpr double EXTENT = 4096.0; +const constexpr double BUFFER = 128.0; + +} +} +} +#endif diff --git a/profiles/bicycle.lua b/profiles/bicycle.lua index 84e02d8..644a254 100644 --- a/profiles/bicycle.lua +++ b/profiles/bicycle.lua @@ -234,8 +234,6 @@ function way_function (way, result) if duration and durationIsValid(duration) then result.duration = math.max( parseDuration(duration), 1 ) end - result.forward_mode = mode.movable_bridge - result.backward_mode = mode.movable_bridge result.forward_speed = bridge_speed result.backward_speed = bridge_speed elseif route_speeds[route] then diff --git a/profiles/car.lua b/profiles/car.lua index 4033f31..ffe62ca 100644 --- a/profiles/car.lua +++ b/profiles/car.lua @@ -270,8 +270,6 @@ function way_function (way, result) if duration and durationIsValid(duration) then result.duration = max( parseDuration(duration), 1 ) end - result.forward_mode = mode.movable_bridge - result.backward_mode = mode.movable_bridge result.forward_speed = bridge_speed result.backward_speed = bridge_speed end diff --git a/src/engine/api/json_factory.cpp b/src/engine/api/json_factory.cpp index b1f5da5..4d5ff9b 100644 --- a/src/engine/api/json_factory.cpp +++ b/src/engine/api/json_factory.cpp @@ -100,9 +100,6 @@ std::string modeToString(const extractor::TravelMode mode) case TRAVEL_MODE_PUSHING_BIKE: token = "pushing bike"; break; - case TRAVEL_MODE_MOVABLE_BRIDGE: - token = "movable bridge"; - break; case TRAVEL_MODE_STEPS_UP: token = "steps up"; break; @@ -197,6 +194,7 @@ util::json::Object makeRouteLeg(guidance::RouteLeg leg, util::json::Array steps) util::json::Object route_leg; route_leg.values["distance"] = std::round(leg.distance * 10) / 10.; route_leg.values["duration"] = std::round(leg.duration * 10) / 10.; + route_leg.values["summary"] = std::move(leg.summary); route_leg.values["steps"] = std::move(steps); return route_leg; } diff --git a/src/engine/plugins/tile.cpp b/src/engine/plugins/tile.cpp index 87586ea..6ce85c7 100644 --- a/src/engine/plugins/tile.cpp +++ b/src/engine/plugins/tile.cpp @@ -3,6 +3,7 @@ #include "util/coordinate_calculation.hpp" #include "util/web_mercator.hpp" +#include "util/vector_tile.hpp" #include <boost/geometry.hpp> #include <boost/geometry/geometries/point_xy.hpp> @@ -27,10 +28,6 @@ namespace plugins { namespace detail { -// Vector tiles are 4096 virtual pixels on each side -const constexpr double VECTOR_TILE_EXTENT = 4096.0; -const constexpr double VECTOR_TILE_BUFFER = 128.0; - // Simple container class for WGS84 coordinates template <typename T> struct Point final { @@ -78,9 +75,9 @@ typedef boost::geometry::model::point<double, 2, boost::geometry::cs::cartesian> typedef boost::geometry::model::linestring<point_t> linestring_t; typedef boost::geometry::model::box<point_t> box_t; typedef boost::geometry::model::multi_linestring<linestring_t> multi_linestring_t; -const static box_t clip_box(point_t(-detail::VECTOR_TILE_BUFFER, -detail::VECTOR_TILE_BUFFER), - point_t(detail::VECTOR_TILE_EXTENT + detail::VECTOR_TILE_BUFFER, - detail::VECTOR_TILE_EXTENT + detail::VECTOR_TILE_BUFFER)); +const static box_t clip_box(point_t(-util::vector_tile::BUFFER, -util::vector_tile::BUFFER), + point_t(util::vector_tile::EXTENT + util::vector_tile::BUFFER, + util::vector_tile::EXTENT + util::vector_tile::BUFFER)); // from mapnik-vector-tile // Encodes a linestring using protobuf zigzag encoding @@ -136,10 +133,10 @@ FixedLine coordinatesToTileLine(const util::Coordinate start, // convert lon/lat to tile coordinates const auto px = std::round( ((px_merc - tile_bbox.minx) * util::web_mercator::TILE_SIZE / tile_bbox.width()) * - detail::VECTOR_TILE_EXTENT / util::web_mercator::TILE_SIZE); + util::vector_tile::EXTENT / util::web_mercator::TILE_SIZE); const auto py = std::round( ((tile_bbox.maxy - py_merc) * util::web_mercator::TILE_SIZE / tile_bbox.height()) * - detail::VECTOR_TILE_EXTENT / util::web_mercator::TILE_SIZE); + util::vector_tile::EXTENT / util::web_mercator::TILE_SIZE); boost::geometry::append(unclipped_line, point_t(px, py)); } @@ -254,15 +251,15 @@ Status TilePlugin::HandleRequest(const api::TileParameters ¶meters, std::str protozero::pbf_writer tile_writer{pbf_buffer}; { // Add a layer object to the PBF stream. 3=='layer' from the vector tile spec (2.1) - protozero::pbf_writer layer_writer(tile_writer, 3); + protozero::pbf_writer layer_writer(tile_writer, util::vector_tile::LAYER_TAG); // TODO: don't write a layer if there are no features - layer_writer.add_uint32(15, 2); // version + layer_writer.add_uint32(util::vector_tile::VERSION_TAG, 2); // version // Field 1 is the "layer name" field, it's a string - layer_writer.add_string(1, "speeds"); // name + layer_writer.add_string(util::vector_tile::NAME_TAG, "speeds"); // name // Field 5 is the tile extent. It's a uint32 and should be set to 4096 // for normal vector tiles. - layer_writer.add_uint32(5, 4096); // extent + layer_writer.add_uint32(util::vector_tile::EXTEND_TAG, util::vector_tile::EXTENT); // extent // Begin the layer features block { @@ -328,11 +325,13 @@ Status TilePlugin::HandleRequest(const api::TileParameters ¶meters, std::str // is_small // boolean. We onl serve up speeds from 0-139, so all we do is save the // first - protozero::pbf_writer feature_writer(layer_writer, 2); + protozero::pbf_writer feature_writer(layer_writer, + util::vector_tile::FEATURE_TAG); // Field 3 is the "geometry type" field. Value 2 is "line" - feature_writer.add_enum(3, 2); // geometry type + feature_writer.add_enum(util::vector_tile::GEOMETRY_TAG, + util::vector_tile::GEOMETRY_TYPE_LINE); // geometry type // Field 1 for the feature is the "id" field. - feature_writer.add_uint64(1, id++); // id + feature_writer.add_uint64(util::vector_tile::ID_TAG, id++); // id { // When adding attributes to a feature, we have to write // pairs of numbers. The first value is the index in the @@ -341,7 +340,8 @@ Status TilePlugin::HandleRequest(const api::TileParameters ¶meters, std::str // not writing the actual speed or bool value here, we're saving // an index into the "values" array. This means many features // can share the same value data, leading to smaller tiles. - protozero::packed_field_uint32 field(feature_writer, 2); + protozero::packed_field_uint32 field( + feature_writer, util::vector_tile::FEATURE_ATTRIBUTES_TAG); field.add_element(0); // "speed" tag key offset field.add_element( @@ -358,7 +358,8 @@ Status TilePlugin::HandleRequest(const api::TileParameters ¶meters, std::str { // Encode the geometry for the feature - protozero::packed_field_uint32 geometry(feature_writer, 4); + protozero::packed_field_uint32 geometry( + feature_writer, util::vector_tile::FEATURE_GEOMETRIES_TAG); encodeLinestring(tile_line, geometry, start_x, start_y); } }; @@ -405,10 +406,10 @@ Status TilePlugin::HandleRequest(const api::TileParameters ¶meters, std::str // Field id 3 is the "keys" attribute // We need two "key" fields, these are referred to with 0 and 1 (their array indexes) // earlier - layer_writer.add_string(3, "speed"); - layer_writer.add_string(3, "is_small"); - layer_writer.add_string(3, "datasource"); - layer_writer.add_string(3, "duration"); + layer_writer.add_string(util::vector_tile::KEY_TAG, "speed"); + layer_writer.add_string(util::vector_tile::KEY_TAG, "is_small"); + layer_writer.add_string(util::vector_tile::KEY_TAG, "datasource"); + layer_writer.add_string(util::vector_tile::KEY_TAG, "duration"); // Now, we write out the possible speed value arrays and possible is_tiny // values. Field type 4 is the "values" field. It's a variable type field, @@ -416,35 +417,36 @@ Status TilePlugin::HandleRequest(const api::TileParameters ¶meters, std::str for (std::size_t i = 0; i < 128; i++) { // Writing field type 4 == variant type - protozero::pbf_writer values_writer(layer_writer, 4); + protozero::pbf_writer values_writer(layer_writer, util::vector_tile::VARIANT_TAG); // Attribute value 5 == uin64 type - values_writer.add_uint64(5, i); + values_writer.add_uint64(util::vector_tile::VARIANT_TYPE_UINT32, i); } { - protozero::pbf_writer values_writer(layer_writer, 4); + protozero::pbf_writer values_writer(layer_writer, util::vector_tile::VARIANT_TAG); // Attribute value 7 == bool type - values_writer.add_bool(7, true); + values_writer.add_bool(util::vector_tile::VARIANT_TYPE_BOOL, true); } { - protozero::pbf_writer values_writer(layer_writer, 4); + protozero::pbf_writer values_writer(layer_writer, util::vector_tile::VARIANT_TAG); // Attribute value 7 == bool type - values_writer.add_bool(7, false); + values_writer.add_bool(util::vector_tile::VARIANT_TYPE_BOOL, false); } for (std::size_t i = 0; i <= max_datasource_id; i++) { // Writing field type 4 == variant type - protozero::pbf_writer values_writer(layer_writer, 4); + protozero::pbf_writer values_writer(layer_writer, util::vector_tile::VARIANT_TAG); // Attribute value 1 == string type - values_writer.add_string(1, facade.GetDatasourceName(i)); + values_writer.add_string(util::vector_tile::VARIANT_TYPE_STRING, + facade.GetDatasourceName(i)); } for (auto weight : used_weights) { // Writing field type 4 == variant type - protozero::pbf_writer values_writer(layer_writer, 4); + protozero::pbf_writer values_writer(layer_writer, util::vector_tile::VARIANT_TAG); // Attribute value 2 == float type // Durations come out of OSRM in integer deciseconds, so we convert them // to seconds with a simple /10 for display - values_writer.add_double(3, weight / 10.); + values_writer.add_double(util::vector_tile::VARIANT_TYPE_DOUBLE, weight / 10.); } } diff --git a/src/extractor/extractor.cpp b/src/extractor/extractor.cpp index 99f25ae..977a59c 100644 --- a/src/extractor/extractor.cpp +++ b/src/extractor/extractor.cpp @@ -555,6 +555,11 @@ void Extractor::BuildRTree(std::vector<EdgeBasedNode> node_based_edge_list, in_iter++; } auto new_size = out_iter - node_based_edge_list.begin(); + if (new_size == 0) + { + throw util::exception("There are no snappable edges left after processing. Are you " + "setting travel modes correctly in the profile? Cannot continue."); + } node_based_edge_list.resize(new_size); TIMER_START(construction); diff --git a/src/extractor/scripting_environment.cpp b/src/extractor/scripting_environment.cpp index e3f9b6e..0840f7d 100644 --- a/src/extractor/scripting_environment.cpp +++ b/src/extractor/scripting_environment.cpp @@ -80,7 +80,6 @@ void ScriptingEnvironment::InitContext(ScriptingEnvironment::Context &context) luabind::value("ferry", TRAVEL_MODE_FERRY), luabind::value("train", TRAVEL_MODE_TRAIN), luabind::value("pushing_bike", TRAVEL_MODE_PUSHING_BIKE), - luabind::value("movable_bridge", TRAVEL_MODE_MOVABLE_BRIDGE), luabind::value("steps_up", TRAVEL_MODE_STEPS_UP), luabind::value("steps_down", TRAVEL_MODE_STEPS_DOWN), luabind::value("river_up", TRAVEL_MODE_RIVER_UP), diff --git a/unit_tests/library/coordinates.hpp b/unit_tests/library/coordinates.hpp index 2ccc689..e2cb7e8 100644 --- a/unit_tests/library/coordinates.hpp +++ b/unit_tests/library/coordinates.hpp @@ -25,4 +25,11 @@ inline Locations get_locations_in_small_component() {Longitude{7.438190}, Latitude{43.747560}}}; } +inline Locations get_locations_in_big_component() +{ + return {{Longitude{7.415800}, Latitude{43.734132}}, + {Longitude{7.417710}, Latitude{43.736721}}, + {Longitude{7.421315}, Latitude{43.738814}}}; +} + #endif diff --git a/unit_tests/library/match.cpp b/unit_tests/library/match.cpp index 37d36c2..b6b01ab 100644 --- a/unit_tests/library/match.cpp +++ b/unit_tests/library/match.cpp @@ -4,6 +4,7 @@ #include "args.hpp" #include "fixture.hpp" #include "coordinates.hpp" +#include "waypoint_check.hpp" #include "osrm/match_parameters.hpp" @@ -46,12 +47,8 @@ BOOST_AUTO_TEST_CASE(test_match) { if (waypoint.is<mapbox::util::recursive_wrapper<util::json::Object>>()) { + BOOST_CHECK(waypoint_check(waypoint)); const auto &waypoint_object = waypoint.get<json::Object>(); - const auto &waypoint_object_location = waypoint_object.values.at("location").get<json::Array>().values; - util::FloatLongitude lon(waypoint_object_location[0].get<json::Number>().value); - util::FloatLatitude lat(waypoint_object_location[1].get<json::Number>().value); - util::Coordinate location_coordinate(lon, lat); - BOOST_CHECK(location_coordinate.IsValid()); const auto matchings_index = waypoint_object.values.at("matchings_index").get<json::Number>().value; const auto waypoint_index = waypoint_object.values.at("waypoint_index").get<json::Number>().value; const auto &route_legs = matchings[matchings_index].get<json::Object>().values.at("legs").get<json::Array>().values; diff --git a/unit_tests/library/route.cpp b/unit_tests/library/route.cpp index f9aaae9..a090208 100644 --- a/unit_tests/library/route.cpp +++ b/unit_tests/library/route.cpp @@ -55,6 +55,7 @@ BOOST_AUTO_TEST_CASE(test_route_same_coordinates_fixture) json::Array{{json::Object{ {{"distance", 0.}, {"duration", 0.}, + {"summary", ""}, {"steps", json::Array{{json::Object{{{"duration", 0.}, {"distance", 0.}, {"geometry", "yw_jGupkl@??"}, @@ -153,6 +154,10 @@ BOOST_AUTO_TEST_CASE(test_route_same_coordinates) const auto duration = leg_object.values.at("duration").get<json::Number>().value; BOOST_CHECK_EQUAL(duration, 0); + // nothing can be said about summary, empty or contains human readable summary + const auto summary = leg_object.values.at("summary").get<json::String>().value; + BOOST_CHECK(((void)summary, true)); + const auto &steps = leg_object.values.at("steps").get<json::Array>().values; BOOST_CHECK(!steps.empty()); @@ -237,9 +242,80 @@ BOOST_AUTO_TEST_CASE(test_route_response_for_locations_in_small_component) const auto latitude = location[1].get<json::Number>().value; BOOST_CHECK(longitude >= -180. && longitude <= 180.); BOOST_CHECK(latitude >= -90. && latitude <= 90.); + } +} + +BOOST_AUTO_TEST_CASE(test_route_response_for_locations_in_big_component) +{ + const auto args = get_args(); + auto osrm = getOSRM(args.at(0)); + + using namespace osrm; - // TODO(daniel-j-h): we could do a Nearest request for each waypoint, verifying - // that we did indeed not snap to the input locations inside the small component. + const auto locations = get_locations_in_big_component(); + + RouteParameters params; + params.coordinates.push_back(locations.at(0)); + params.coordinates.push_back(locations.at(1)); + params.coordinates.push_back(locations.at(2)); + + json::Object result; + const auto rc = osrm.Route(params, result); + BOOST_CHECK(rc == Status::Ok); + + const auto code = result.values.at("code").get<json::String>().value; + BOOST_CHECK_EQUAL(code, "Ok"); + + const auto &waypoints = result.values.at("waypoints").get<json::Array>().values; + BOOST_CHECK_EQUAL(waypoints.size(), params.coordinates.size()); + + for (const auto &waypoint : waypoints) + { + const auto &waypoint_object = waypoint.get<json::Object>(); + + const auto location = waypoint_object.values.at("location").get<json::Array>().values; + const auto longitude = location[0].get<json::Number>().value; + const auto latitude = location[1].get<json::Number>().value; + BOOST_CHECK(longitude >= -180. && longitude <= 180.); + BOOST_CHECK(latitude >= -90. && latitude <= 90.); + } +} + +BOOST_AUTO_TEST_CASE(test_route_response_for_locations_across_components) +{ + const auto args = get_args(); + auto osrm = getOSRM(args.at(0)); + + using namespace osrm; + + const auto big_component = get_locations_in_big_component(); + const auto small_component = get_locations_in_small_component(); + + RouteParameters params; + params.coordinates.push_back(small_component.at(0)); + params.coordinates.push_back(big_component.at(0)); + params.coordinates.push_back(small_component.at(1)); + params.coordinates.push_back(big_component.at(1)); + + json::Object result; + const auto rc = osrm.Route(params, result); + BOOST_CHECK(rc == Status::Ok); + + const auto code = result.values.at("code").get<json::String>().value; + BOOST_CHECK_EQUAL(code, "Ok"); + + const auto &waypoints = result.values.at("waypoints").get<json::Array>().values; + BOOST_CHECK_EQUAL(waypoints.size(), params.coordinates.size()); + + for (const auto &waypoint : waypoints) + { + const auto &waypoint_object = waypoint.get<json::Object>(); + + const auto location = waypoint_object.values.at("location").get<json::Array>().values; + const auto longitude = location[0].get<json::Number>().value; + const auto latitude = location[1].get<json::Number>().value; + BOOST_CHECK(longitude >= -180. && longitude <= 180.); + BOOST_CHECK(latitude >= -90. && latitude <= 90.); } } diff --git a/unit_tests/library/table.cpp b/unit_tests/library/table.cpp index bab5312..43b44a8 100644 --- a/unit_tests/library/table.cpp +++ b/unit_tests/library/table.cpp @@ -2,7 +2,9 @@ #include <boost/test/test_case_template.hpp> #include "args.hpp" +#include "coordinates.hpp" #include "fixture.hpp" +#include "waypoint_check.hpp" #include "osrm/table_parameters.hpp" @@ -14,7 +16,7 @@ BOOST_AUTO_TEST_SUITE(table) -BOOST_AUTO_TEST_CASE(test_table) +BOOST_AUTO_TEST_CASE(test_table_three_coords_one_source_one_dest_matrix) { const auto args = get_args(); BOOST_REQUIRE_EQUAL(args.size(), 1); @@ -23,15 +25,138 @@ BOOST_AUTO_TEST_CASE(test_table) auto osrm = getOSRM(args[0]); - /* TableParameters params; + params.coordinates.push_back(get_dummy_location()); + params.coordinates.push_back(get_dummy_location()); + params.coordinates.push_back(get_dummy_location()); + params.sources.push_back(0); + params.destinations.push_back(2); json::Object result; const auto rc = osrm.Table(params, result); BOOST_CHECK(rc == Status::Ok || rc == Status::Error); - */ + const auto code = result.values.at("code").get<json::String>().value; + BOOST_CHECK_EQUAL(code, "Ok"); + + // check that returned durations error is expected size and proportions + // this test expects a 1x1 matrix + const auto &durations_array = result.values.at("durations").get<json::Array>().values; + BOOST_CHECK_EQUAL(durations_array.size(), params.sources.size()); + for (unsigned int i = 0; i < durations_array.size(); i++) + { + const auto durations_matrix = durations_array[i].get<json::Array>().values; + BOOST_CHECK_EQUAL(durations_matrix.size(), params.sources.size()*params.destinations.size()); + } + // check destinations array of waypoint objects + const auto &destinations_array = result.values.at("destinations").get<json::Array>().values; + BOOST_CHECK_EQUAL(destinations_array.size(), params.destinations.size()); + for (const auto &destination : destinations_array) + { + BOOST_CHECK(waypoint_check(destination)); + } + // check sources array of waypoint objects + const auto &sources_array = result.values.at("sources").get<json::Array>().values; + BOOST_CHECK_EQUAL(sources_array.size(), params.sources.size()); + for (const auto &source : sources_array) + { + BOOST_CHECK(waypoint_check(source)); + } +} + +BOOST_AUTO_TEST_CASE(test_table_three_coords_one_source_matrix) +{ + const auto args = get_args(); + BOOST_REQUIRE_EQUAL(args.size(), 1); + + using namespace osrm; + + auto osrm = getOSRM(args[0]); + + TableParameters params; + params.coordinates.push_back(get_dummy_location()); + params.coordinates.push_back(get_dummy_location()); + params.coordinates.push_back(get_dummy_location()); + params.sources.push_back(0); + + json::Object result; + + const auto rc = osrm.Table(params, result); + + BOOST_CHECK(rc == Status::Ok || rc == Status::Error); + const auto code = result.values.at("code").get<json::String>().value; + BOOST_CHECK_EQUAL(code, "Ok"); + + // check that returned durations error is expected size and proportions + // this test expects a 1x3 matrix + const auto &durations_array = result.values.at("durations").get<json::Array>().values; + BOOST_CHECK_EQUAL(durations_array.size(), params.sources.size()); + for (unsigned int i = 0; i < durations_array.size(); i++) + { + const auto durations_matrix = durations_array[i].get<json::Array>().values; + BOOST_CHECK_EQUAL(durations_matrix[i].get<json::Number>().value, 0); + BOOST_CHECK_EQUAL(durations_matrix.size(), params.sources.size()*params.coordinates.size()); + } + // check destinations array of waypoint objects + const auto &destinations_array = result.values.at("destinations").get<json::Array>().values; + BOOST_CHECK_EQUAL(destinations_array.size(), params.coordinates.size()); + for (const auto &destination : destinations_array) + { + BOOST_CHECK(waypoint_check(destination)); + } + // check sources array of waypoint objects + const auto &sources_array = result.values.at("sources").get<json::Array>().values; + BOOST_CHECK_EQUAL(sources_array.size(), params.sources.size()); + for (const auto &source : sources_array) + { + BOOST_CHECK(waypoint_check(source)); + } +} + +BOOST_AUTO_TEST_CASE(test_table_three_coordinates_matrix) +{ + const auto args = get_args(); + BOOST_REQUIRE_EQUAL(args.size(), 1); + + using namespace osrm; + + auto osrm = getOSRM(args[0]); + + TableParameters params; + params.coordinates.push_back(get_dummy_location()); + params.coordinates.push_back(get_dummy_location()); + params.coordinates.push_back(get_dummy_location()); + + json::Object result; + + const auto rc = osrm.Table(params, result); + + BOOST_CHECK(rc == Status::Ok || rc == Status::Error); + const auto code = result.values.at("code").get<json::String>().value; + BOOST_CHECK_EQUAL(code, "Ok"); + + // check that returned durations error is expected size and proportions + // this test expects a 3x3 matrix + const auto &durations_array = result.values.at("durations").get<json::Array>().values; + BOOST_CHECK_EQUAL(durations_array.size(), params.coordinates.size()); + for (unsigned int i = 0; i < durations_array.size(); i++) + { + const auto durations_matrix = durations_array[i].get<json::Array>().values; + BOOST_CHECK_EQUAL(durations_matrix[i].get<json::Number>().value, 0); + BOOST_CHECK_EQUAL(durations_matrix.size(), params.coordinates.size()); + } + const auto &destinations_array = result.values.at("destinations").get<json::Array>().values; + for (const auto &destination : destinations_array) + { + BOOST_CHECK(waypoint_check(destination)); + } + const auto &sources_array = result.values.at("sources").get<json::Array>().values; + BOOST_CHECK_EQUAL(sources_array.size(), params.coordinates.size()); + for (const auto &source : sources_array) + { + BOOST_CHECK(waypoint_check(source)); + } } BOOST_AUTO_TEST_SUITE_END() diff --git a/unit_tests/library/tile.cpp b/unit_tests/library/tile.cpp index 2ca674b..6cacc30 100644 --- a/unit_tests/library/tile.cpp +++ b/unit_tests/library/tile.cpp @@ -12,6 +12,10 @@ #include "osrm/status.hpp" #include "osrm/osrm.hpp" +#include "util/vector_tile.hpp" + +#include <protozero/pbf_reader.hpp> + BOOST_AUTO_TEST_SUITE(tile) BOOST_AUTO_TEST_CASE(test_tile) @@ -21,11 +25,111 @@ BOOST_AUTO_TEST_CASE(test_tile) using namespace osrm; - TileParameters params{0, 0, 1}; + // This tile should contain most of monaco + TileParameters params{17059, 11948, 15}; std::string result; const auto rc = osrm.Tile(params, result); BOOST_CHECK(rc == Status::Ok); + + BOOST_CHECK_GT(result.size(), 128); + + protozero::pbf_reader tile_message(result); + tile_message.next(); + BOOST_CHECK_EQUAL(tile_message.tag(), util::vector_tile::LAYER_TAG); // must be a layer + protozero::pbf_reader layer_message = tile_message.get_message(); + + const auto check_feature = [](protozero::pbf_reader feature_message) { + protozero::pbf_reader::const_uint32_iterator value_begin; + protozero::pbf_reader::const_uint32_iterator value_end; + feature_message.next(); // advance parser to first entry + BOOST_CHECK_EQUAL(feature_message.tag(), util::vector_tile::GEOMETRY_TAG); + BOOST_CHECK_EQUAL(feature_message.get_enum(), util::vector_tile::GEOMETRY_TYPE_LINE); + + feature_message.next(); // advance to next entry + BOOST_CHECK_EQUAL(feature_message.tag(), util::vector_tile::ID_TAG); + feature_message.get_uint64(); // id + + feature_message.next(); // advance to next entry + BOOST_CHECK_EQUAL(feature_message.tag(), util::vector_tile::FEATURE_ATTRIBUTES_TAG); + // properties + std::tie(value_begin, value_end) = feature_message.get_packed_uint32(); + BOOST_CHECK_EQUAL(std::distance(value_begin, value_end), 8); + auto iter = value_begin; + BOOST_CHECK_EQUAL(*iter++, 0); // speed key + BOOST_CHECK_LT(*iter++, 128); // speed value + BOOST_CHECK_EQUAL(*iter++, 1); // component key + // component value + BOOST_CHECK_GE(*iter, 128); + BOOST_CHECK_LE(*iter, 129); + iter++; + BOOST_CHECK_EQUAL(*iter++, 2); // data source key + *iter++; // skip value check, can be valud uint32 + BOOST_CHECK_EQUAL(*iter++, 3); // duration key + BOOST_CHECK_GT(*iter++, 130); // duration value + BOOST_CHECK(iter == value_end); + // geometry + feature_message.next(); + std::tie(value_begin, value_end) = feature_message.get_packed_uint32(); + BOOST_CHECK_GT(std::distance(value_begin, value_end), 1); + }; + + const auto check_value = [](protozero::pbf_reader value) { + while (value.next()) + { + switch(value.tag()) + { + case util::vector_tile::VARIANT_TYPE_BOOL: + value.get_bool(); + break; + case util::vector_tile::VARIANT_TYPE_DOUBLE: + value.get_double(); + break; + case util::vector_tile::VARIANT_TYPE_STRING: + value.get_string(); + break; + case util::vector_tile::VARIANT_TYPE_UINT32: + value.get_uint32(); + break; + } + } + }; + + auto number_of_keys = 0u; + auto number_of_values = 0u; + + while (layer_message.next()) + { + switch(layer_message.tag()) + { + case util::vector_tile::VERSION_TAG: + BOOST_CHECK_EQUAL(layer_message.get_uint32(), 2); + break; + case util::vector_tile::NAME_TAG: + BOOST_CHECK_EQUAL(layer_message.get_string(), "speeds"); + break; + case util::vector_tile::EXTEND_TAG: + BOOST_CHECK_EQUAL(layer_message.get_uint32(), util::vector_tile::EXTENT); + break; + case util::vector_tile::FEATURE_TAG: + check_feature(layer_message.get_message()); + break; + case util::vector_tile::KEY_TAG: + layer_message.get_string(); + number_of_keys++; + break; + case util::vector_tile::VARIANT_TAG: + check_value(layer_message.get_message()); + number_of_values++; + break; + default: + BOOST_CHECK(false); // invalid tag + break; + } + } + + BOOST_CHECK_EQUAL(number_of_keys, 4); + BOOST_CHECK_GT(number_of_values, 128); // speed value resolution } BOOST_AUTO_TEST_SUITE_END() diff --git a/unit_tests/library/trip.cpp b/unit_tests/library/trip.cpp index 7bfd1c2..e630706 100644 --- a/unit_tests/library/trip.cpp +++ b/unit_tests/library/trip.cpp @@ -1,7 +1,8 @@ -#include <boost/test/unit_test.hpp> #include <boost/test/test_case_template.hpp> +#include <boost/test/unit_test.hpp> #include "args.hpp" +#include "coordinates.hpp" #include "fixture.hpp" #include "osrm/trip_parameters.hpp" @@ -9,29 +10,144 @@ #include "osrm/coordinate.hpp" #include "osrm/engine_config.hpp" #include "osrm/json_container.hpp" -#include "osrm/status.hpp" #include "osrm/osrm.hpp" +#include "osrm/status.hpp" BOOST_AUTO_TEST_SUITE(trip) -BOOST_AUTO_TEST_CASE(test_trip) +BOOST_AUTO_TEST_CASE(test_trip_response_for_locations_in_small_component) +{ + const auto args = get_args(); + auto osrm = getOSRM(args.at(0)); + + using namespace osrm; + + const auto locations = get_locations_in_small_component(); + + TripParameters params; + params.coordinates.push_back(locations.at(0)); + params.coordinates.push_back(locations.at(1)); + params.coordinates.push_back(locations.at(2)); + + json::Object result; + const auto rc = osrm.Trip(params, result); + BOOST_CHECK(rc == Status::Ok); + + const auto code = result.values.at("code").get<json::String>().value; + BOOST_CHECK_EQUAL(code, "Ok"); + + const auto &waypoints = result.values.at("waypoints").get<json::Array>().values; + BOOST_CHECK_EQUAL(waypoints.size(), params.coordinates.size()); + + const auto &trips = result.values.at("trips").get<json::Array>().values; + BOOST_CHECK_EQUAL(trips.size(), 1); + + for (const auto &waypoint : waypoints) + { + const auto &waypoint_object = waypoint.get<json::Object>(); + + const auto location = waypoint_object.values.at("location").get<json::Array>().values; + const auto longitude = location[0].get<json::Number>().value; + const auto latitude = location[1].get<json::Number>().value; + BOOST_CHECK(longitude >= -180. && longitude <= 180.); + BOOST_CHECK(latitude >= -90. && latitude <= 90.); + + const auto trip = waypoint_object.values.at("trips_index").get<json::Number>().value; + const auto pos = waypoint_object.values.at("waypoint_index").get<json::Number>().value; + BOOST_CHECK(trip >= 0 && trip < trips.size()); + BOOST_CHECK(pos >= 0 && pos < waypoints.size()); + } +} + +BOOST_AUTO_TEST_CASE(test_trip_response_for_locations_in_big_component) { const auto args = get_args(); - BOOST_REQUIRE_EQUAL(args.size(), 1); + auto osrm = getOSRM(args.at(0)); using namespace osrm; - auto osrm = getOSRM(args[0]); + const auto locations = get_locations_in_big_component(); - /* TripParameters params; + params.coordinates.push_back(locations.at(0)); + params.coordinates.push_back(locations.at(1)); + params.coordinates.push_back(locations.at(2)); json::Object result; + const auto rc = osrm.Trip(params, result); + BOOST_CHECK(rc == Status::Ok); + + const auto code = result.values.at("code").get<json::String>().value; + BOOST_CHECK_EQUAL(code, "Ok"); + + const auto &waypoints = result.values.at("waypoints").get<json::Array>().values; + BOOST_CHECK_EQUAL(waypoints.size(), params.coordinates.size()); + + const auto &trips = result.values.at("trips").get<json::Array>().values; + BOOST_CHECK_EQUAL(trips.size(), 1); + + for (const auto &waypoint : waypoints) + { + const auto &waypoint_object = waypoint.get<json::Object>(); + + const auto location = waypoint_object.values.at("location").get<json::Array>().values; + const auto longitude = location[0].get<json::Number>().value; + const auto latitude = location[1].get<json::Number>().value; + BOOST_CHECK(longitude >= -180. && longitude <= 180.); + BOOST_CHECK(latitude >= -90. && latitude <= 90.); + + const auto trip = waypoint_object.values.at("trips_index").get<json::Number>().value; + const auto pos = waypoint_object.values.at("waypoint_index").get<json::Number>().value; + BOOST_CHECK(trip >= 0 && trip < trips.size()); + BOOST_CHECK(pos >= 0 && pos < waypoints.size()); + } +} + +BOOST_AUTO_TEST_CASE(test_trip_response_for_locations_across_components) +{ + const auto args = get_args(); + auto osrm = getOSRM(args.at(0)); + using namespace osrm; + + const auto small = get_locations_in_small_component(); + const auto big = get_locations_in_big_component(); + + TripParameters params; + params.coordinates.push_back(small.at(0)); + params.coordinates.push_back(big.at(0)); + params.coordinates.push_back(small.at(1)); + params.coordinates.push_back(big.at(1)); + + json::Object result; const auto rc = osrm.Trip(params, result); + BOOST_CHECK(rc == Status::Ok); + + const auto code = result.values.at("code").get<json::String>().value; + BOOST_CHECK_EQUAL(code, "Ok"); + + const auto &waypoints = result.values.at("waypoints").get<json::Array>().values; + BOOST_CHECK_EQUAL(waypoints.size(), params.coordinates.size()); + + const auto &trips = result.values.at("trips").get<json::Array>().values; + BOOST_CHECK_EQUAL(trips.size(), 1); + // ^ First snapping, then SCC decomposition (see plugins/trip.cpp). Therefore only a single trip. + + for (const auto &waypoint : waypoints) + { + const auto &waypoint_object = waypoint.get<json::Object>(); + + const auto location = waypoint_object.values.at("location").get<json::Array>().values; + const auto longitude = location[0].get<json::Number>().value; + const auto latitude = location[1].get<json::Number>().value; + BOOST_CHECK(longitude >= -180. && longitude <= 180.); + BOOST_CHECK(latitude >= -90. && latitude <= 90.); - BOOST_CHECK(rc == Status::Ok || rc == Status::Error); - */ + const auto trip = waypoint_object.values.at("trips_index").get<json::Number>().value; + const auto pos = waypoint_object.values.at("waypoint_index").get<json::Number>().value; + BOOST_CHECK(trip >= 0 && trip < trips.size()); + BOOST_CHECK(pos >= 0 && pos < waypoints.size()); + } } BOOST_AUTO_TEST_SUITE_END() diff --git a/unit_tests/library/waypoint_check.hpp b/unit_tests/library/waypoint_check.hpp new file mode 100644 index 0000000..7bf1797 --- /dev/null +++ b/unit_tests/library/waypoint_check.hpp @@ -0,0 +1,24 @@ +#ifndef OSRM_UNIT_TEST_WAYPOINT_CHECK +#define OSRM_UNIT_TEST_WAYPOINT_CHECK + +#include "osrm/coordinate.hpp" +#include "osrm/json_container.hpp" +#include "util/exception.hpp" + +using namespace osrm; + +inline bool waypoint_check(json::Value waypoint) +{ + if (!waypoint.is<mapbox::util::recursive_wrapper<util::json::Object>>()) + { + throw util::exception("Must pass in a waypoint object"); + } + const auto waypoint_object = waypoint.get<json::Object>(); + const auto waypoint_location = waypoint_object.values.at("location").get<json::Array>().values; + util::FloatLongitude lon(waypoint_location[0].get<json::Number>().value); + util::FloatLatitude lat(waypoint_location[1].get<json::Number>().value); + util::Coordinate location_coordinate(lon, lat); + return location_coordinate.IsValid(); +} + +#endif diff --git a/unit_tests/server/parameters_io.hpp b/unit_tests/server/parameters_io.hpp new file mode 100644 index 0000000..dd2bd6c --- /dev/null +++ b/unit_tests/server/parameters_io.hpp @@ -0,0 +1,59 @@ +#ifndef OSRM_TEST_SERVER_PARAMETERS_IO +#define OSRM_TEST_SERVER_PARAMETERS_IO + +#include "engine/api/route_parameters.hpp" +#include "engine/bearing.hpp" + +#include <ostream> + +namespace osrm +{ +namespace engine +{ +namespace api +{ +inline std::ostream &operator<<(std::ostream &out, api::RouteParameters::GeometriesType geometries) +{ + switch (geometries) + { + case api::RouteParameters::GeometriesType::GeoJSON: + out << "GeoJSON"; + break; + case api::RouteParameters::GeometriesType::Polyline: + out << "Polyline"; + break; + default: + BOOST_ASSERT_MSG(false, "GeometriesType not fully captured"); + } + return out; +} + +inline std::ostream &operator<<(std::ostream &out, api::RouteParameters::OverviewType overview) +{ + switch (overview) + { + case api::RouteParameters::OverviewType::False: + out << "False"; + break; + case api::RouteParameters::OverviewType::Full: + out << "Full"; + break; + case api::RouteParameters::OverviewType::Simplified: + out << "Simplified"; + break; + default: + BOOST_ASSERT_MSG(false, "OverviewType not fully captured"); + } + return out; +} +} + +inline std::ostream &operator<<(std::ostream &out, Bearing bearing) +{ + out << bearing.bearing << "," << bearing.range; + return out; +} +} +} + +#endif diff --git a/unit_tests/server/parameters_parser.cpp b/unit_tests/server/parameters_parser.cpp index 1b5161f..ecf98f2 100644 --- a/unit_tests/server/parameters_parser.cpp +++ b/unit_tests/server/parameters_parser.cpp @@ -1,5 +1,7 @@ #include "server/api/parameters_parser.hpp" +#include "parameters_io.hpp" + #include "engine/api/base_parameters.hpp" #include "engine/api/match_parameters.hpp" #include "engine/api/nearest_parameters.hpp" @@ -8,56 +10,6 @@ #include "engine/api/tile_parameters.hpp" #include "engine/api/trip_parameters.hpp" -#include <fstream> - -namespace osrm -{ -namespace engine -{ -namespace api -{ -std::ostream &operator<<(std::ostream &out, api::RouteParameters::GeometriesType geometries) -{ - switch (geometries) - { - case api::RouteParameters::GeometriesType::GeoJSON: - out << "GeoJSON"; - break; - case api::RouteParameters::GeometriesType::Polyline: - out << "Polyline"; - break; - default: - BOOST_ASSERT_MSG(false, "GeometriesType not fully captured"); - } - return out; -} -std::ostream &operator<<(std::ostream &out, api::RouteParameters::OverviewType overview) -{ - switch (overview) - { - case api::RouteParameters::OverviewType::False: - out << "False"; - break; - case api::RouteParameters::OverviewType::Full: - out << "Full"; - break; - case api::RouteParameters::OverviewType::Simplified: - out << "Simplified"; - break; - default: - BOOST_ASSERT_MSG(false, "OverviewType not fully captured"); - } - return out; -} -} -std::ostream &operator<<(std::ostream &out, Bearing bearing) -{ - out << bearing.bearing << "," << bearing.range; - return out; -} -} -} - #include <boost/optional/optional_io.hpp> #include <boost/test/test_tools.hpp> #include <boost/test/unit_test.hpp> @@ -69,55 +21,54 @@ BOOST_AUTO_TEST_SUITE(api_parameters_parser) using namespace osrm; using namespace osrm::server; +using namespace osrm::server::api; +using namespace osrm::engine::api; // returns distance to front template <typename ParameterT> std::size_t testInvalidOptions(std::string options) { auto iter = options.begin(); - auto result = api::parseParameters<ParameterT>(iter, options.end()); + auto result = parseParameters<ParameterT>(iter, options.end()); BOOST_CHECK(!result); return std::distance(options.begin(), iter); } BOOST_AUTO_TEST_CASE(invalid_route_urls) { + BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4?overview=false&bla=foo"), 22UL); + BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4?overview=false&bearings=foo"), + 32UL); BOOST_CHECK_EQUAL( - testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&bla=foo"), 22UL); - BOOST_CHECK_EQUAL( - testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&bearings=foo"), - 32UL); - BOOST_CHECK_EQUAL( - testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&continue_straight=foo"), - 41UL); - BOOST_CHECK_EQUAL( - testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&radiuses=foo"), - 32UL); - BOOST_CHECK_EQUAL( - testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&hints=foo"), 29UL); - BOOST_CHECK_EQUAL( - testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&geometries=foo"), - 22UL); - BOOST_CHECK_EQUAL( - testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&overview=foo"), - 22L); + testInvalidOptions<RouteParameters>("1,2;3,4?overview=false&continue_straight=foo"), 41UL); + BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4?overview=false&radiuses=foo"), + 32UL); + BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4?overview=false&hints=foo"), + 29UL); + BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4?overview=false&geometries=foo"), + 22UL); + BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4?overview=false&overview=foo"), + 22L); BOOST_CHECK_EQUAL( - testInvalidOptions<engine::api::RouteParameters>("1,2;3,4?overview=false&alternatives=foo"), - 36UL); + testInvalidOptions<RouteParameters>("1,2;3,4?overview=false&alternatives=foo"), 36UL); + BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>(""), 0); + BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3.4.unsupported"), 7); + BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4.json?nooptions"), 13); + BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4..json?nooptions"), 14); + BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>("1,2;3,4.0.json?nooptions"), 15); + BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>(std::string{"1,2;3,4"} + '\0' + ".json"), 7); + BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>(std::string{"1,2;3,"} + '\0'), 6); + + //BOOST_CHECK_EQUAL(testInvalidOptions<RouteParameters>(), ); } BOOST_AUTO_TEST_CASE(invalid_table_urls) { - BOOST_CHECK_EQUAL(testInvalidOptions<engine::api::TableParameters>("1,2;3,4?sources=1&bla=foo"), - 17UL); + BOOST_CHECK_EQUAL(testInvalidOptions<TableParameters>("1,2;3,4?sources=1&bla=foo"), 17UL); + BOOST_CHECK_EQUAL(testInvalidOptions<TableParameters>("1,2;3,4?destinations=1&bla=foo"), 22UL); BOOST_CHECK_EQUAL( - testInvalidOptions<engine::api::TableParameters>("1,2;3,4?destinations=1&bla=foo"), 22UL); - BOOST_CHECK_EQUAL(testInvalidOptions<engine::api::TableParameters>( - "1,2;3,4?sources=1&destinations=1&bla=foo"), - 32UL); - BOOST_CHECK_EQUAL(testInvalidOptions<engine::api::TableParameters>("1,2;3,4?sources=foo"), - 16UL); - BOOST_CHECK_EQUAL(testInvalidOptions<engine::api::TableParameters>("1,2;3,4?destinations=foo"), - 21UL); + testInvalidOptions<TableParameters>("1,2;3,4?sources=1&destinations=1&bla=foo"), 32UL); + BOOST_CHECK_EQUAL(testInvalidOptions<TableParameters>("1,2;3,4?sources=foo"), 16UL); + BOOST_CHECK_EQUAL(testInvalidOptions<TableParameters>("1,2;3,4?destinations=foo"), 21UL); } BOOST_AUTO_TEST_CASE(valid_route_urls) @@ -125,9 +76,9 @@ BOOST_AUTO_TEST_CASE(valid_route_urls) std::vector<util::Coordinate> coords_1 = {{util::FloatLongitude(1), util::FloatLatitude(2)}, {util::FloatLongitude(3), util::FloatLatitude(4)}}; - engine::api::RouteParameters reference_1{}; + RouteParameters reference_1{}; reference_1.coordinates = coords_1; - auto result_1 = api::parseParameters<engine::api::RouteParameters>("1,2;3,4"); + auto result_1 = parseParameters<RouteParameters>("1,2;3,4"); BOOST_CHECK(result_1); BOOST_CHECK_EQUAL(reference_1.steps, result_1->steps); BOOST_CHECK_EQUAL(reference_1.alternatives, result_1->alternatives); @@ -138,11 +89,11 @@ BOOST_AUTO_TEST_CASE(valid_route_urls) CHECK_EQUAL_RANGE(reference_1.radiuses, result_1->radiuses); CHECK_EQUAL_RANGE(reference_1.coordinates, result_1->coordinates); - engine::api::RouteParameters reference_2{}; + RouteParameters reference_2{}; reference_2.alternatives = true; reference_2.steps = true; reference_2.coordinates = coords_1; - auto result_2 = api::parseParameters<engine::api::RouteParameters>( + auto result_2 = parseParameters<RouteParameters>( "1,2;3,4?steps=true&alternatives=true&geometries=polyline&overview=simplified"); BOOST_CHECK(result_2); BOOST_CHECK_EQUAL(reference_2.steps, result_2->steps); @@ -154,12 +105,12 @@ BOOST_AUTO_TEST_CASE(valid_route_urls) CHECK_EQUAL_RANGE(reference_2.radiuses, result_2->radiuses); CHECK_EQUAL_RANGE(reference_2.coordinates, result_2->coordinates); - engine::api::RouteParameters reference_3{ - false, false, engine::api::RouteParameters::GeometriesType::GeoJSON, - engine::api::RouteParameters::OverviewType::False, true}; + RouteParameters reference_3{false, false, RouteParameters::GeometriesType::GeoJSON, + RouteParameters::OverviewType::False, true}; reference_3.coordinates = coords_1; auto result_3 = api::parseParameters<engine::api::RouteParameters>( - "1,2;3,4?steps=false&alternatives=false&geometries=geojson&overview=false&continue_straight=true"); + "1,2;3,4?steps=false&alternatives=false&geometries=geojson&overview=false&continue_" + "straight=true"); BOOST_CHECK(result_3); BOOST_CHECK_EQUAL(reference_3.steps, result_3->steps); BOOST_CHECK_EQUAL(reference_3.alternatives, result_3->alternatives); @@ -180,16 +131,16 @@ BOOST_AUTO_TEST_CASE(valid_route_urls) engine::Hint::FromBase64("3gAAgP___" "39KAAAAHgAAACEAAAAAAAAAGAAAAE0BAABOAQAAGwAAAIAzcQBkUJsC1zNxAHBQmw" "IAAAEBl-Umfg==")}; - engine::api::RouteParameters reference_4{false, - false, - engine::api::RouteParameters::GeometriesType::Polyline, - engine::api::RouteParameters::OverviewType::Simplified, - boost::optional<bool>{}, - coords_1, - hints_4, - std::vector<boost::optional<double>>{}, - std::vector<boost::optional<engine::Bearing>>{}}; - auto result_4 = api::parseParameters<engine::api::RouteParameters>( + RouteParameters reference_4{false, + false, + RouteParameters::GeometriesType::Polyline, + RouteParameters::OverviewType::Simplified, + boost::optional<bool>{}, + coords_1, + hints_4, + std::vector<boost::optional<double>>{}, + std::vector<boost::optional<engine::Bearing>>{}}; + auto result_4 = parseParameters<RouteParameters>( "1,2;3,4?steps=false&hints=" "DAIAgP___38AAAAAAAAAAAIAAAAAAAAAEAAAAOgDAAD0AwAAGwAAAOUacQBQP5sCshpxAB0_mwIAAAEBl-Umfg==;" "cgAAgP___39jAAAADgAAACIAAABeAAAAkQAAANoDAABOAgAAGwAAAFVGcQCiRJsCR0VxAOZFmwIFAAEBl-Umfg==;" @@ -207,17 +158,16 @@ BOOST_AUTO_TEST_CASE(valid_route_urls) std::vector<boost::optional<engine::Bearing>> bearings_4 = { boost::none, engine::Bearing{200, 10}, engine::Bearing{100, 5}, }; - engine::api::RouteParameters reference_5{false, - false, - engine::api::RouteParameters::GeometriesType::Polyline, - engine::api::RouteParameters::OverviewType::Simplified, - boost::optional<bool>{}, - coords_1, - std::vector<boost::optional<engine::Hint>>{}, - std::vector<boost::optional<double>>{}, - bearings_4}; - auto result_5 = api::parseParameters<engine::api::RouteParameters>( - "1,2;3,4?steps=false&bearings=;200,10;100,5"); + RouteParameters reference_5{false, + false, + RouteParameters::GeometriesType::Polyline, + RouteParameters::OverviewType::Simplified, + boost::optional<bool>{}, + coords_1, + std::vector<boost::optional<engine::Hint>>{}, + std::vector<boost::optional<double>>{}, + bearings_4}; + auto result_5 = parseParameters<RouteParameters>("1,2;3,4?steps=false&bearings=;200,10;100,5"); BOOST_CHECK(result_5); BOOST_CHECK_EQUAL(reference_5.steps, result_5->steps); BOOST_CHECK_EQUAL(reference_5.alternatives, result_5->alternatives); @@ -232,10 +182,9 @@ BOOST_AUTO_TEST_CASE(valid_route_urls) {util::FloatLongitude(2), util::FloatLatitude(3)}, {util::FloatLongitude(4), util::FloatLatitude(5)}}; - engine::api::RouteParameters reference_6{}; + RouteParameters reference_6{}; reference_6.coordinates = coords_2; - auto result_6 = - api::parseParameters<engine::api::RouteParameters>("polyline(_ibE?_seK_seK_seK_seK)"); + auto result_6 = parseParameters<RouteParameters>("polyline(_ibE?_seK_seK_seK_seK)"); BOOST_CHECK(result_6); BOOST_CHECK_EQUAL(reference_6.steps, result_6->steps); BOOST_CHECK_EQUAL(reference_6.alternatives, result_6->alternatives); @@ -245,6 +194,34 @@ BOOST_AUTO_TEST_CASE(valid_route_urls) CHECK_EQUAL_RANGE(reference_6.bearings, result_6->bearings); CHECK_EQUAL_RANGE(reference_6.radiuses, result_6->radiuses); CHECK_EQUAL_RANGE(reference_6.coordinates, result_6->coordinates); + + auto result_7 = parseParameters<RouteParameters>("1,2;3,4?radiuses=;unlimited"); + RouteParameters reference_7{}; + reference_7.coordinates = coords_1; + reference_7.radiuses = {boost::none, boost::make_optional(std::numeric_limits<double>::infinity())}; + BOOST_CHECK(result_7); + BOOST_CHECK_EQUAL(reference_7.steps, result_7->steps); + BOOST_CHECK_EQUAL(reference_7.alternatives, result_7->alternatives); + BOOST_CHECK_EQUAL(reference_7.geometries, result_7->geometries); + BOOST_CHECK_EQUAL(reference_7.overview, result_7->overview); + BOOST_CHECK_EQUAL(reference_7.continue_straight, result_7->continue_straight); + CHECK_EQUAL_RANGE(reference_7.bearings, result_7->bearings); + CHECK_EQUAL_RANGE(reference_7.radiuses, result_7->radiuses); + CHECK_EQUAL_RANGE(reference_7.coordinates, result_7->coordinates); + + auto result_8 = parseParameters<RouteParameters>("1,2;3,4?radiuses=;"); + RouteParameters reference_8{}; + reference_8.coordinates = coords_1; + reference_8.radiuses = {boost::none, boost::none}; + BOOST_CHECK(result_8); + CHECK_EQUAL_RANGE(reference_8.radiuses, result_8->radiuses); + + auto result_9 = parseParameters<RouteParameters>("1,2?radiuses="); + RouteParameters reference_9{}; + reference_9.coordinates = coords_1; + reference_9.radiuses = {boost::none}; + BOOST_CHECK(result_9); + CHECK_EQUAL_RANGE(reference_9.radiuses, result_9->radiuses); } BOOST_AUTO_TEST_CASE(valid_table_urls) @@ -252,9 +229,9 @@ BOOST_AUTO_TEST_CASE(valid_table_urls) std::vector<util::Coordinate> coords_1 = {{util::FloatLongitude(1), util::FloatLatitude(2)}, {util::FloatLongitude(3), util::FloatLatitude(4)}}; - engine::api::TableParameters reference_1{}; + TableParameters reference_1{}; reference_1.coordinates = coords_1; - auto result_1 = api::parseParameters<engine::api::TableParameters>("1,2;3,4"); + auto result_1 = parseParameters<TableParameters>("1,2;3,4"); BOOST_CHECK(result_1); CHECK_EQUAL_RANGE(reference_1.sources, result_1->sources); CHECK_EQUAL_RANGE(reference_1.destinations, result_1->destinations); @@ -264,16 +241,23 @@ BOOST_AUTO_TEST_CASE(valid_table_urls) std::vector<std::size_t> sources_2 = {1, 2, 3}; std::vector<std::size_t> destinations_2 = {4, 5}; - engine::api::TableParameters reference_2{sources_2, destinations_2}; + TableParameters reference_2{sources_2, destinations_2}; reference_2.coordinates = coords_1; - auto result_2 = api::parseParameters<engine::api::TableParameters>( - "1,2;3,4?sources=1;2;3&destinations=4;5"); + auto result_2 = parseParameters<TableParameters>("1,2;3,4?sources=1;2;3&destinations=4;5"); BOOST_CHECK(result_2); CHECK_EQUAL_RANGE(reference_2.sources, result_2->sources); CHECK_EQUAL_RANGE(reference_2.destinations, result_2->destinations); CHECK_EQUAL_RANGE(reference_2.bearings, result_2->bearings); CHECK_EQUAL_RANGE(reference_2.radiuses, result_2->radiuses); CHECK_EQUAL_RANGE(reference_2.coordinates, result_2->coordinates); + + auto result_3 = parseParameters<TableParameters>("1,2;3,4?sources=all&destinations=all"); + BOOST_CHECK(result_3); + CHECK_EQUAL_RANGE(reference_1.sources, result_3->sources); + CHECK_EQUAL_RANGE(reference_1.destinations, result_3->destinations); + CHECK_EQUAL_RANGE(reference_1.bearings, result_3->bearings); + CHECK_EQUAL_RANGE(reference_1.radiuses, result_3->radiuses); + CHECK_EQUAL_RANGE(reference_1.coordinates, result_3->coordinates); } BOOST_AUTO_TEST_CASE(valid_match_urls) @@ -281,9 +265,9 @@ BOOST_AUTO_TEST_CASE(valid_match_urls) std::vector<util::Coordinate> coords_1 = {{util::FloatLongitude(1), util::FloatLatitude(2)}, {util::FloatLongitude(3), util::FloatLatitude(4)}}; - engine::api::MatchParameters reference_1{}; + MatchParameters reference_1{}; reference_1.coordinates = coords_1; - auto result_1 = api::parseParameters<engine::api::MatchParameters>("1,2;3,4"); + auto result_1 = parseParameters<MatchParameters>("1,2;3,4"); BOOST_CHECK(result_1); CHECK_EQUAL_RANGE(reference_1.timestamps, result_1->timestamps); CHECK_EQUAL_RANGE(reference_1.bearings, result_1->bearings); @@ -295,9 +279,9 @@ BOOST_AUTO_TEST_CASE(valid_nearest_urls) { std::vector<util::Coordinate> coords_1 = {{util::FloatLongitude(1), util::FloatLatitude(2)}}; - engine::api::NearestParameters reference_1{}; + NearestParameters reference_1{}; reference_1.coordinates = coords_1; - auto result_1 = api::parseParameters<engine::api::NearestParameters>("1,2"); + auto result_1 = parseParameters<NearestParameters>("1,2"); BOOST_CHECK(result_1); BOOST_CHECK_EQUAL(reference_1.number_of_results, result_1->number_of_results); CHECK_EQUAL_RANGE(reference_1.bearings, result_1->bearings); @@ -307,8 +291,8 @@ BOOST_AUTO_TEST_CASE(valid_nearest_urls) BOOST_AUTO_TEST_CASE(valid_tile_urls) { - engine::api::TileParameters reference_1{1, 2, 3}; - auto result_1 = api::parseParameters<engine::api::TileParameters>("tile(1,2,3).mvt"); + TileParameters reference_1{1, 2, 3}; + auto result_1 = parseParameters<TileParameters>("tile(1,2,3).mvt"); BOOST_CHECK(result_1); BOOST_CHECK_EQUAL(reference_1.x, result_1->x); BOOST_CHECK_EQUAL(reference_1.y, result_1->y); @@ -320,9 +304,9 @@ BOOST_AUTO_TEST_CASE(valid_trip_urls) std::vector<util::Coordinate> coords_1 = {{util::FloatLongitude(1), util::FloatLatitude(2)}, {util::FloatLongitude(3), util::FloatLatitude(4)}}; - engine::api::TripParameters reference_1{}; + TripParameters reference_1{}; reference_1.coordinates = coords_1; - auto result_1 = api::parseParameters<engine::api::TripParameters>("1,2;3,4"); + auto result_1 = parseParameters<TripParameters>("1,2;3,4"); BOOST_CHECK(result_1); CHECK_EQUAL_RANGE(reference_1.bearings, result_1->bearings); CHECK_EQUAL_RANGE(reference_1.radiuses, result_1->radiuses); diff --git a/unit_tests/util/static_rtree.cpp b/unit_tests/util/static_rtree.cpp index b3c2c9e..f8be130 100644 --- a/unit_tests/util/static_rtree.cpp +++ b/unit_tests/util/static_rtree.cpp @@ -230,10 +230,10 @@ void sampling_verify_rtree(RTreeT &rtree, auto lsnn_u = result_lsnn.back().u; auto lsnn_v = result_lsnn.back().v; - const double rtree_dist = coordinate_calculation::perpendicularDistance( - coords[rtree_u], coords[rtree_v], q); - const double lsnn_dist = coordinate_calculation::perpendicularDistance( - coords[lsnn_u], coords[lsnn_v], q); + const double rtree_dist = + coordinate_calculation::perpendicularDistance(coords[rtree_u], coords[rtree_v], q); + const double lsnn_dist = + coordinate_calculation::perpendicularDistance(coords[lsnn_u], coords[lsnn_v], q); BOOST_CHECK_CLOSE(rtree_dist, lsnn_dist, 0.0001); } @@ -335,6 +335,34 @@ BOOST_AUTO_TEST_CASE(regression_test) BOOST_CHECK_EQUAL(result_ls.front().v, result_rtree.front().v); } +// Bug: If you querry a point with a narrow radius, no result should be returned +BOOST_AUTO_TEST_CASE(radius_regression_test) +{ + using Coord = std::pair<FloatLongitude, FloatLatitude>; + using Edge = std::pair<unsigned, unsigned>; + GraphFixture fixture( + { + Coord(FloatLongitude(0.0), FloatLatitude(0.0)), + Coord(FloatLongitude(10.0), FloatLatitude(10.0)), + }, + {Edge(0, 1), Edge(1, 0)}); + + std::string leaves_path; + std::string nodes_path; + build_rtree<GraphFixture, MiniStaticRTree>("test_angle", &fixture, leaves_path, nodes_path); + MiniStaticRTree rtree(nodes_path, leaves_path, fixture.coords); + MockDataFacade mockfacade; + engine::GeospatialQuery<MiniStaticRTree, MockDataFacade> query(rtree, fixture.coords, + mockfacade); + + Coordinate input(FloatLongitude(5.2), FloatLatitude(5.0)); + + { + auto results = query.NearestPhantomNodesInRange(input, 0.01); + BOOST_CHECK_EQUAL(results.size(), 0); + } +} + BOOST_AUTO_TEST_CASE(bearing_tests) { using Coord = std::pair<FloatLongitude, FloatLatitude>; -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/osrm.git _______________________________________________ Pkg-grass-devel mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-grass-devel

