-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support snapping to multiple ways at an input location #5953
Conversation
6d9b13e
to
0169963
Compare
This will fix #4465, and possibly a bunch of tickets linked to that one. @mjjbell I think you don't need to consider the Amazing contribution, thank you, this has been an issue for a very long time. |
5eab0d2
to
d34f21e
Compare
Performance AnalysisPreparationOSRMI used germany-latest.osm.pbf as input, Test CoordinatesI created a collection of test coordinates for use as request parameters in the performance tests. We then randomly generate waypoint lists (represented by the truncated coordinates of the selected nodes). For testing, we create five sets of waypoint lists to test performance against a variety of input sizes.
The coordinate sets are available in this gist Test RequestsThe test coordinates are used to run the following requests via libosrm:
In the case of Route and Trip requests, the waypoint lists act as waypoints in the returned route. Tests are performed using libosrm versions of The request duration and route weight/duration response values are recorded and used to compare the performance of both branches. Machine specsLenovo Thinkpad X1 Librariesgcc 9 |
Results - RouteCoordinate set 1Request Duration
Smallest Route Weight
Coordinate set 2Request Duration
Smallest Route Weight
Coordinate set 3Request Duration
Smallest Route Weight
Coordinate set 4Request Duration
Smallest Route Weight
Coordinate set 5Request Duration
Smallest Route Weight
|
Results - Route
|
Percentile | master (μs) | snap_candidates (μs) | diff (μs) | % diff |
---|---|---|---|---|
0 | 2223 | 2299 | 76 | 3.42% |
10 | 18161 | 18016 | -145 | -0.80% |
20 | 19383 | 19090 | -293 | -1.51% |
30 | 20340 | 19963 | -377 | -1.85% |
40 | 21160 | 20749 | -411 | -1.94% |
50 | 21929 | 21511 | -418 | -1.91% |
60 | 22739 | 22281 | -458 | -2.01% |
70 | 23601 | 23127 | -474 | -2.01% |
80 | 24658 | 24142 | -516 | -2.09% |
90 | 26242 | 25603 | -639 | -2.44% |
99 | 65394 | 29350 | -36044 | -55.12% |
100 | 78483 | 78273 | -210 | -0.27% |
Smallest Route Weight
master | same | snap_candidates |
---|---|---|
0 | 15990 | 1397 |
Coordinate set 4
Request Duration
Percentile | master (μs) | snap_candidates (μs) | diff (μs) | % diff |
---|---|---|---|---|
0 | 7559 | 7843 | 284 | 3.76% |
10 | 190380 | 193361 | 2981 | 1.57% |
20 | 194161 | 197038 | 2877 | 1.48% |
30 | 196893 | 199942 | 3049 | 1.55% |
40 | 199394 | 202247 | 2853 | 1.43% |
50 | 201640 | 204357 | 2717 | 1.35% |
60 | 203800 | 206534 | 2734 | 1.34% |
70 | 206402 | 208995 | 2593 | 1.26% |
80 | 209833 | 211817 | 1984 | 0.95% |
90 | 215237 | 216509 | 1272 | 0.59% |
99 | 250923 | 241023 | -9900 | -3.95% |
100 | 323250 | 326410 | 3160 | 0.98% |
Smallest Route Weight
master | same | snap_candidates |
---|---|---|
0 | 3465 | 4092 |
Coordinate set 5
Request Duration
Percentile | master (μs) | snap_candidates (μs) | diff (μs) | % diff |
---|---|---|---|---|
0 | 74904 | 63922 | -10982 | -14.66% |
10 | 1953409 | 1993940 | 40531 | 2.07% |
20 | 1971011 | 2010467 | 39456 | 2.00% |
30 | 1983935 | 2024351 | 40416 | 2.04% |
40 | 1992464 | 2037172 | 44708 | 2.24% |
50 | 2003905 | 2057112 | 53207 | 2.66% |
60 | 2017461 | 2074207 | 56746 | 2.81% |
70 | 2035575 | 2091534 | 55959 | 2.75% |
80 | 2053559 | 2106061 | 52502 | 2.56% |
90 | 2072882 | 2122799 | 49917 | 2.41% |
99 | 2112569 | 2162705 | 50136 | 2.37% |
100 | 2414390 | 2423875 | 9485 | 0.39% |
Smallest Route Weight
master | same | snap_candidates |
---|---|---|
0 | 15 | 747 |
Results - TableN.B. Here we are not able to compare route weights, as the table response does not contain them. Instead we compare route durations. In some cases we do get shorter duration results with Coordinate set 1Request Duration
Smallest Route Duration
Coordinate set 2Request Duration
Smallest Route Duration
Coordinate set 3Request Duration
Smallest Route Duration
Coordinate set 4Request Duration
Smallest Route Duration
Coordinate set 5Request Duration
Smallest Route Duration
|
Results - TripRunning Coordinate set 1Request Duration
Smallest Route Weight
Coordinate set 2Request Duration
Smallest Route Weight
Coordinate set 3Request Duration
Smallest Route Weight
Coordinate set 4Request Duration
Smallest Route Weight
Coordinate set 5Request Duration
Smallest Route Weight
|
ReviewIn summary, with this change we are able to find better results, especially when the inputs snap to locations with multiple ways. In the cases where we can compare optimal route weights, it does not produce any worse results. The performance effect on request duration appears to differ on each service.
|
Thanks @mjjbell for this comprehensive impact study!
Things are a bit fuzzy for the
The expected changes are probably rather on the solving side than on internal |
Ah yes, that actually does explain it. Thanks! |
When routing from Segregated Road MergingWith this PR there are now two possible start candidates on a Looking at the merging logic for combining segregated roads:
This explains why the merging logic creates different results given the selected start edge, but doesn’t explain why different start edges are selected on different platforms. Contraction OrderI extracted the contraction hierarchy forward and backward graphs for both platforms. Clearly, the ordering is different. My understanding of the contraction logic is that when there are no criteria that indicate one node has higher rank than the other, one of the nodes is (deterministically) chosen at random. I discovered this when looking at an edge case from a more trivial example, which I will discuss in a separate issue, but I expect this difference in randomness between the platforms is what creates the different contraction order here too. CH search chooses the first route it finds when there are multiple routes of equal weight. So this explains the difference. To fix this, I explicitly added a numbered input location so that it only snaps to one edge. Other tests also required explicit inputs to continue to pass - it’s possible some of these will have displayed these platform differences too. I expect this is one of many subtle differences that can occur from snapping to multiple candidates. |
@@ -438,7 +438,7 @@ Feature: Car - Turn restrictions | |||
When I route I should get | |||
| from | to | route | | |||
| e | f | ae,xa,bx,fb,fb | | |||
| c | f | dc,da,ae,ge,hg,hg,ge,ae,xa,bx,fb,fb | | |||
| 1 | f | dc,da,ae,ge,hg,hg,ge,ae,xa,bx,fb,fb | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| restriction | cb | bx | b | only_right_turn |
This turn restriction routes you into a one-way road going in the other direction. I'm not sure if this was intended, but with the start location now snapping to both cb
and dc
, it was creating a different shortest route. I added a numbered input location to ensure it snaps only to dc
as it did previously.
@@ -47,7 +47,7 @@ Feature: Traffic - turn penalties applied to turn onto which a phantom node snap | |||
| 1 | e | ab,be,be | 36 km/h | 30s +-1 | | |||
| b | f | bc,cf,cf | 36 km/h | 40s +-1 | | |||
| 2 | f | bc,cf,cf | 36 km/h | 30s +-1 | | |||
| c | g | cd,dg,dg | 144 km/h | 10s +-1 | | |||
| c | g | cd,dg,dg | 72 km/h | 20s +-1 | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use of negative turn penalties is the cause of the increase in speed/time here.
Previously, the start would snap to cf
(which would be combined with cd
in the route result annotation).
Now with multiple intersection candidates to choose from, the route does actually start from cd
.
There is special case logic for preventing negative weights/durations on the first turn. It didn't apply previously when starting at cf
as the negative duration was on the second turn, but it does now.
This leads to the shortest route for this PR actually having larger duration than previously.
I can see historical discussions about the value of negative turn penalty weights, but I'm not sure if that also applies for negative durations. In any case, I've just updated the expected value to reflect this turn clamping logic.
Also worth mentioning - this PR will enable a fix for snapping target locations to via ways used in turn restrictions, discussed here. The fix is quite simple once this change is made: mjjbell@3771e99 |
I've completed the same analysis for the MLD algorithm. The relative performance change is very similar to the CH result detailed above, so to save some scrolling I've put the MLD results in this gist. |
d34f21e
to
8df78f4
Compare
Hi @mjjbell |
Cool, I am not very familiar with this part, but I will try to do a review in the nearest days. Do you think we will need someone from OSRM maintainers to approve it too? I guess it can be difficult taking into account that you are the only one active recently :) |
Yes it will need a maintainer to approve for it to be mergeable. Repo ownership still resides with (ex-) Mapbox folk, so I can't change the situation myself. |
Hey @mjjbell
Do you mean breaking change from libosrm point of view? Can we may be leave BaseParameters::hints parameters as is and add new one(may be In general I had a chance to just briefly look through PR and it seems it is LGTM, but I think I will need to spend a bit more time on review, but just want to ask do you have time to rebase it? Or I can help you with it if you want? The same question is about other your PRs which seems to be open for a while: |
@@ -77,7 +77,7 @@ struct BaseParameters | |||
}; | |||
|
|||
std::vector<util::Coordinate> coordinates; | |||
std::vector<boost::optional<Hint>> hints; | |||
std::vector<std::vector<Hint>> hints; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mjjbell
It is a breaking change you mentioned, right? Is it possible to support both old and new version of API? I mean do not touch existing field and just add std::vector<std::vector<Hint>> extended_hints;
? I would even make it std::vector<WaypointHints> extended_hints
and put this vector of hints to WaypointHints
structure to be able to extend this structure in the future if needed without breaking changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 I like this idea. This would make it backwards compatible with existing API users getting the existing (sub-optimal) behaviour, new users get the improved behaviour. Most people who use the HTTP API (such as osrm-frontend) will get the improvement for free.
Thanks, I'll rebase. The previous plan included a proposal to remove hints (#4741) as it exposes internal data structures, so I think a lightweight backwards compatible solution makes sense for now, and we can reserve the breaking change for when we have a hints replacement. |
7c385f8
to
f113add
Compare
This |
04143d5
to
480287d
Compare
So having tried to implement an additional field for hints in the request and response fields, I can see it complicates a lot of the code. What I have realised however, is both the HTTP and libosrm responses contain the base64 encoding of hints. Therefore, I've inverted the change slightly. From the If the user happens to edit some of the internals of In summary, I think this is good to go now 👍 |
480287d
to
e4f6e10
Compare
"ENCODED_HINT_SIZE does not match size of Hint"); | ||
// Hint represents the suggested segment positions that could be used | ||
// as the waypoint for a given input location | ||
struct Hint |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if it is not breaking change too - as I understand API of Hint class is part of public API too, BUT tbh I don’t think it is a big problem: even though someone uses it for something(I doubt it) it will be quite easy to migrate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry didn’t notice comment #5953 (comment)
This PR improves routing results by adding support for snapping to multiple ways at input locations. This means all edges at the snapped location can act as source/target candidates for routing search, ensuring we always find the best route, and not the one dependent on the edge selected.
e4f6e10
to
d96960f
Compare
Thanks everyone for your work on this, this has simplified something I'm doing significantly :) |
v5.27.0 - Changes from 5.26.0 - API: - ADDED: Add Flatbuffers support to NodeJS bindings. [Project-OSRM#6338](Project-OSRM#6338) - CHANGED: Add `data_version` field to responses of all services. [Project-OSRM#5387](Project-OSRM#5387) - FIXED: Use Boost.Beast to parse HTTP request. [Project-OSRM#6294](Project-OSRM#6294) - FIXED: Fix inefficient osrm-routed connection handling [Project-OSRM#6113](https://gihub.com/Project-OSRM/osrm-backend/pull/6113) - FIXED: Fix HTTP compression precedence [Project-OSRM#6113](Project-OSRM#6113) - NodeJS: - FIXED: Support `skip_waypoints` in Node bindings [Project-OSRM#6060](Project-OSRM#6060) - Misc: - ADDED: conanbuildinfo.json for easy reading of dependencies [Project-OSRM#6388](Project-OSRM#6388) - CHANGED: Improve performance of JSON rendering. Fix undefined behaviour in JSON numbers formatting. [Project-OSRM#6380](Project-OSRM#6380) - ADDED: Add timestamps for logs. [Project-OSRM#6375](Project-OSRM#6375) - CHANGED: Improve performance of map matching via getPathDistance optimization. [Project-OSRM#6378](Project-OSRM#6378) - CHANGED: Optimize RestrictionParser performance. [Project-OSRM#6344](Project-OSRM#6344) - ADDED: Support floats for speed value in traffic updates CSV. [Project-OSRM#6327](Project-OSRM#6327) - CHANGED: Use Lua 5.4 in Docker image. [Project-OSRM#6346](Project-OSRM#6346) - CHANGED: Remove redundant nullptr check. [Project-OSRM#6326](Project-OSRM#6326) - CHANGED: missing files list is included in exception message. [Project-OSRM#5360](Project-OSRM#5360) - CHANGED: Do not use deprecated Callback::Call overload in Node bindings. [Project-OSRM#6318](Project-OSRM#6318) - FIXED: Fix distance calculation consistency. [Project-OSRM#6315](Project-OSRM#6315) - FIXED: Fix performance issue after migration to sol2 3.3.0. [Project-OSRM#6304](Project-OSRM#6304) - CHANGED: Pass osm_node_ids by reference in osrm::updater::Updater class. [Project-OSRM#6298](Project-OSRM#6298) - FIXED: Fix bug with reading Set values from Lua scripts. [Project-OSRM#6285](Project-OSRM#6285) - FIXED: Bug in bicycle profile that caused exceptions if there is a highway=bicycle in the data. [Project-OSRM#6296](Project-OSRM#6296) - FIXED: Internal refactoring of identifier types used in data facade [Project-OSRM#6044](Project-OSRM#6044) - CHANGED: Update docs to reflect recent build and dependency changes [Project-OSRM#6383](Project-OSRM#6383) - Build: - REMOVED: Get rid of Mason. [Project-OSRM#6387](Project-OSRM#6387) - CHANGED: Use clang-format from CI base image. [Project-OSRM#6391](Project-OSRM#6391) - ADDED: Build Node bindings on Windows. [Project-OSRM#6334](Project-OSRM#6334) - ADDED: Configure cross-compilation for Apple Silicon. [Project-OSRM#6360](Project-OSRM#6360) - CHANGED: Use apt-get to install Clang on CI. [Project-OSRM#6345](Project-OSRM#6345) - CHANGED: Fix TBB in case of Conan + NodeJS build. [Project-OSRM#6333](Project-OSRM#6333) - CHANGED: Migrate to modern TBB version. [Project-OSRM#6300](Project-OSRM#6300) - CHANGED: Enable performance-move-const-arg clang-tidy check. [Project-OSRM#6319](Project-OSRM#6319) - CHANGED: Use the latest node on CI. [Project-OSRM#6317](Project-OSRM#6317) - CHANGED: Migrate Windows CI to GitHub Actions. [Project-OSRM#6312](Project-OSRM#6312) - ADDED: Add smoke test for Docker image. [Project-OSRM#6313](Project-OSRM#6313) - CHANGED: Update libosmium to version 2.18.0. [Project-OSRM#6303](Project-OSRM#6303) - CHANGED: Remove EXACT from find_package if using Conan. [Project-OSRM#6299](Project-OSRM#6299) - CHANGED: Configure Undefined Behaviour Sanitizer. [Project-OSRM#6290](Project-OSRM#6290) - CHANGED: Use Conan instead of Mason to install code dependencies. [Project-OSRM#6284](Project-OSRM#6284) - CHANGED: Migrate to C++17. Update sol2 to 3.3.0. [Project-OSRM#6279](Project-OSRM#6279) - CHANGED: Update macOS CI image to macos-11. [Project-OSRM#6286](Project-OSRM#6286) - CHANGED: Enable even more clang-tidy checks. [Project-OSRM#6273](Project-OSRM#6273) - CHANGED: Configure CMake to not build flatbuffers tests and samples. [Project-OSRM#6274](Project-OSRM#6274) - CHANGED: Enable more clang-tidy checks. [Project-OSRM#6270](Project-OSRM#6270) - CHANGED: Configure clang-tidy job on CI. [Project-OSRM#6261](Project-OSRM#6261) - CHANGED: Use Github Actions for building container images [Project-OSRM#6138](Project-OSRM#6138) - CHANGED: Upgrade Boost dependency to 1.70 [Project-OSRM#6113](Project-OSRM#6113) - CHANGED: Upgrade Ubuntu CI builds to 20.04 [Project-OSRM#6119](Project-OSRM#6119) - CHANGED: Make building osrm-routed optional [Project-OSRM#6144](Project-OSRM#6144) - FIXED: Run all unit tests in CI [Project-OSRM#5248](Project-OSRM#5248) - FIXED: Fix installation of Mason CMake and 32 bit CI build [Project-OSRM#6170](Project-OSRM#6170) - FIXED: Fixed Node docs generation check in CI. [Project-OSRM#6058](Project-OSRM#6058) - CHANGED: Docker build, enabled arm64 build layer [Project-OSRM#6172](Project-OSRM#6172) - CHANGED: Docker build, enabled apt-get update/install caching in separate layer for build phase [Project-OSRM#6175](Project-OSRM#6175) - FIXED: Bump CI complete meta job to ubuntu-20.04 [Project-OSRM#6323](Project-OSRM#6323) - CHANGED: Node packages are now scoped by @Project-OSRM [Project-OSRM#6386](Project-OSRM#6386) - Routing: - CHANGED: Lazily generate optional route path data [Project-OSRM#6045](Project-OSRM#6045) - FIXED: Completed support for no_entry and no_exit turn restrictions. [Project-OSRM#5988](Project-OSRM#5988) - ADDED: Add support for non-round-trips with a single fixed endpoint. [Project-OSRM#6050](Project-OSRM#6050) - FIXED: Improvements to maneuver override processing [Project-OSRM#6125](Project-OSRM#6125) - ADDED: Support snapping to multiple ways at an input location. [Project-OSRM#5953](Project-OSRM#5953) - FIXED: Fix snapping target locations to ways used in turn restrictions. [Project-OSRM#6339](Project-OSRM#6339) - ADDED: Support OSM traffic signal directions. [Project-OSRM#6153](Project-OSRM#6153) - FIXED: Ensure u-turn exists in intersection view. [Project-OSRM#6376](Project-OSRM#6376) - FIXED: Gracefully handle no-turn intersections in guidance processing. [Project-OSRM#6382](Project-OSRM#6382) - Profile: - CHANGED: Bicycle surface speeds [Project-OSRM#6212](Project-OSRM#6212) - Tools: - CHANGED: Do not generate intermediate .osrm file in osrm-extract. [Project-OSRM#6354](Project-OSRM#6354)
v5.27.0 - Changes from 5.26.0 - API: - ADDED: Add Flatbuffers support to NodeJS bindings. [Project-OSRM#6338](Project-OSRM#6338) - CHANGED: Add `data_version` field to responses of all services. [Project-OSRM#5387](Project-OSRM#5387) - FIXED: Use Boost.Beast to parse HTTP request. [Project-OSRM#6294](Project-OSRM#6294) - FIXED: Fix inefficient osrm-routed connection handling [Project-OSRM#6113](https://gihub.com/Project-OSRM/osrm-backend/pull/6113) - FIXED: Fix HTTP compression precedence [Project-OSRM#6113](Project-OSRM#6113) - NodeJS: - FIXED: Support `skip_waypoints` in Node bindings [Project-OSRM#6060](Project-OSRM#6060) - Misc: - ADDED: conanbuildinfo.json for easy reading of dependencies [Project-OSRM#6388](Project-OSRM#6388) - CHANGED: Improve performance of JSON rendering. Fix undefined behaviour in JSON numbers formatting. [Project-OSRM#6380](Project-OSRM#6380) - ADDED: Add timestamps for logs. [Project-OSRM#6375](Project-OSRM#6375) - CHANGED: Improve performance of map matching via getPathDistance optimization. [Project-OSRM#6378](Project-OSRM#6378) - CHANGED: Optimize RestrictionParser performance. [Project-OSRM#6344](Project-OSRM#6344) - ADDED: Support floats for speed value in traffic updates CSV. [Project-OSRM#6327](Project-OSRM#6327) - CHANGED: Use Lua 5.4 in Docker image. [Project-OSRM#6346](Project-OSRM#6346) - CHANGED: Remove redundant nullptr check. [Project-OSRM#6326](Project-OSRM#6326) - CHANGED: missing files list is included in exception message. [Project-OSRM#5360](Project-OSRM#5360) - CHANGED: Do not use deprecated Callback::Call overload in Node bindings. [Project-OSRM#6318](Project-OSRM#6318) - FIXED: Fix distance calculation consistency. [Project-OSRM#6315](Project-OSRM#6315) - FIXED: Fix performance issue after migration to sol2 3.3.0. [Project-OSRM#6304](Project-OSRM#6304) - CHANGED: Pass osm_node_ids by reference in osrm::updater::Updater class. [Project-OSRM#6298](Project-OSRM#6298) - FIXED: Fix bug with reading Set values from Lua scripts. [Project-OSRM#6285](Project-OSRM#6285) - FIXED: Bug in bicycle profile that caused exceptions if there is a highway=bicycle in the data. [Project-OSRM#6296](Project-OSRM#6296) - FIXED: Internal refactoring of identifier types used in data facade [Project-OSRM#6044](Project-OSRM#6044) - CHANGED: Update docs to reflect recent build and dependency changes [Project-OSRM#6383](Project-OSRM#6383) - Build: - REMOVED: Get rid of Mason. [Project-OSRM#6387](Project-OSRM#6387) - CHANGED: Use clang-format from CI base image. [Project-OSRM#6391](Project-OSRM#6391) - ADDED: Build Node bindings on Windows. [Project-OSRM#6334](Project-OSRM#6334) - ADDED: Configure cross-compilation for Apple Silicon. [Project-OSRM#6360](Project-OSRM#6360) - CHANGED: Use apt-get to install Clang on CI. [Project-OSRM#6345](Project-OSRM#6345) - CHANGED: Fix TBB in case of Conan + NodeJS build. [Project-OSRM#6333](Project-OSRM#6333) - CHANGED: Migrate to modern TBB version. [Project-OSRM#6300](Project-OSRM#6300) - CHANGED: Enable performance-move-const-arg clang-tidy check. [Project-OSRM#6319](Project-OSRM#6319) - CHANGED: Use the latest node on CI. [Project-OSRM#6317](Project-OSRM#6317) - CHANGED: Migrate Windows CI to GitHub Actions. [Project-OSRM#6312](Project-OSRM#6312) - ADDED: Add smoke test for Docker image. [Project-OSRM#6313](Project-OSRM#6313) - CHANGED: Update libosmium to version 2.18.0. [Project-OSRM#6303](Project-OSRM#6303) - CHANGED: Remove EXACT from find_package if using Conan. [Project-OSRM#6299](Project-OSRM#6299) - CHANGED: Configure Undefined Behaviour Sanitizer. [Project-OSRM#6290](Project-OSRM#6290) - CHANGED: Use Conan instead of Mason to install code dependencies. [Project-OSRM#6284](Project-OSRM#6284) - CHANGED: Migrate to C++17. Update sol2 to 3.3.0. [Project-OSRM#6279](Project-OSRM#6279) - CHANGED: Update macOS CI image to macos-11. [Project-OSRM#6286](Project-OSRM#6286) - CHANGED: Enable even more clang-tidy checks. [Project-OSRM#6273](Project-OSRM#6273) - CHANGED: Configure CMake to not build flatbuffers tests and samples. [Project-OSRM#6274](Project-OSRM#6274) - CHANGED: Enable more clang-tidy checks. [Project-OSRM#6270](Project-OSRM#6270) - CHANGED: Configure clang-tidy job on CI. [Project-OSRM#6261](Project-OSRM#6261) - CHANGED: Use Github Actions for building container images [Project-OSRM#6138](Project-OSRM#6138) - CHANGED: Upgrade Boost dependency to 1.70 [Project-OSRM#6113](Project-OSRM#6113) - CHANGED: Upgrade Ubuntu CI builds to 20.04 [Project-OSRM#6119](Project-OSRM#6119) - CHANGED: Make building osrm-routed optional [Project-OSRM#6144](Project-OSRM#6144) - FIXED: Run all unit tests in CI [Project-OSRM#5248](Project-OSRM#5248) - FIXED: Fix installation of Mason CMake and 32 bit CI build [Project-OSRM#6170](Project-OSRM#6170) - FIXED: Fixed Node docs generation check in CI. [Project-OSRM#6058](Project-OSRM#6058) - CHANGED: Docker build, enabled arm64 build layer [Project-OSRM#6172](Project-OSRM#6172) - CHANGED: Docker build, enabled apt-get update/install caching in separate layer for build phase [Project-OSRM#6175](Project-OSRM#6175) - FIXED: Bump CI complete meta job to ubuntu-20.04 [Project-OSRM#6323](Project-OSRM#6323) - CHANGED: Node packages are now scoped by @Project-OSRM [Project-OSRM#6386](Project-OSRM#6386) - Routing: - CHANGED: Lazily generate optional route path data [Project-OSRM#6045](Project-OSRM#6045) - FIXED: Completed support for no_entry and no_exit turn restrictions. [Project-OSRM#5988](Project-OSRM#5988) - ADDED: Add support for non-round-trips with a single fixed endpoint. [Project-OSRM#6050](Project-OSRM#6050) - FIXED: Improvements to maneuver override processing [Project-OSRM#6125](Project-OSRM#6125) - ADDED: Support snapping to multiple ways at an input location. [Project-OSRM#5953](Project-OSRM#5953) - FIXED: Fix snapping target locations to ways used in turn restrictions. [Project-OSRM#6339](Project-OSRM#6339) - ADDED: Support OSM traffic signal directions. [Project-OSRM#6153](Project-OSRM#6153) - FIXED: Ensure u-turn exists in intersection view. [Project-OSRM#6376](Project-OSRM#6376) - FIXED: Gracefully handle no-turn intersections in guidance processing. [Project-OSRM#6382](Project-OSRM#6382) - Profile: - CHANGED: Bicycle surface speeds [Project-OSRM#6212](Project-OSRM#6212) - Tools: - CHANGED: Do not generate intermediate .osrm file in osrm-extract. [Project-OSRM#6354](Project-OSRM#6354)
…5953) This PR improves routing results by adding support for snapping to multiple ways at input locations. This means all edges at the snapped location can act as source/target candidates for routing search, ensuring we always find the best route, and not the one dependent on the edge selected.
Issue
link
This PR improves routing results by adding support for snapping to multiple ways at input locations.
Context
Input locations are snapped to positions on ways, which act as the source, target or via waypoint positions on the route.
Currently, OSRM only snaps an input location to one way. In certain scenarios, there are multiple ways to choose from:
The choice of selected way can impact the discovered route. Some good examples of the effect this has are discussed in #4465
This PR makes the change to use all ways at the snapped location as source/target candidates for routing search, ensuring we always find the best route, and not the one dependent on the way selected.
Design Choice
The decision to support multiple candidates for a snapped location was chosen for a few reasons:
The downside of this approach is that using multiple source/target candidates increases the routing search space. However, in practice this has minimal effect on performance, given:
Implementation
PhantomNodeCandidates
We extend the
PhantomNode
representation for a snapped location toPhantomNodeCandidates
, a vector of snapped locations.Algorithms that snap large numbers of locations, such as
table
requests, will generate many small vectors. The implementation reuses the vectors fetched from the geospatial query result throughout the whole request. The performance hit appears to be minimal.Snapping to connection between two edges of a way segment
All the routing algorithms assume a way segment only appears once in the search.
When snapping to the connection between two edges of a segment, we have to decide which edge will represent the segment in the search.
Segment edges are compressed and include forward and reverse directions. To decide which compressed edge to choose, we consider which is most likely to be useful as a source/target for a route. This can depend on edge traffic updates, approach parameters, etc.)
The implementation makes the choice between two compressed edges of a way segment in a consistent way. In very rare situations, it’s possible that some potential routes will not be found by having to select one over the other.
Nearest vs Big SCC
The existing snapping logic considers whether the snapped way is part of a tiny strongly connected component with other snapped locations, and fallbacks to the nearest candidate from the big SCC if this is not the case. This PR keeps and extends this logic for snapping to multiple candidates.
Geospatial Queries
The geospatial API for finding graph segments nearest to the location had many similar functions which represented permutations of parameter combinations. Given the logic for filtering is now more complex, I’ve consolidated the API functions and moved the parameter selection into one place.
Routing Algorithms
trip
,table
, androute
now use the multiple candidate snapping. I did not includematch
, as my depth of understanding of the map matching algorithm is insufficient to figure out how “nearest candidates at the same location” would be represented in the output. Maybe a good follow-up task.Shortest Path
Internally, the shortest path search function was passed in a list of endpoint candidates for each leg of the route. I have changed this to be a list of waypoint candidates instead, which makes it clear that the target candidates of the previous leg are the source candidates of the next leg. Now that candidates are vectors of
PhantomNodes
, it also avoids making a copy of each vector.Not surprisingly, the dynamic programming approach for the shortest path search is made more complicated with multiple source/target nodes. I’ve tried as much as possible to avoid unnecessary vector allocations when tracking state between the legs.
Libosrm / HTTP API changes
Returning waypoint information in API results is now trickier as we have multiple
PhantomNodes
representing each waypoint.To avoid a breaking change, the solution I went with is to:
len(candidates)*HINT_SIZE
. I'm assuming changing the hint size is not an API break?For hints in particular, this allows the hint string to contain all the information for multiple candidates. If we only returned the hint for the
PhantomNode
selected for the particular API call, it could lead to suboptimal results as a hint for future requests.EDIT: This is a breaking change in the request parameters.
hints
are nowvector<vector<hint>>
Tests
The changes to existing test values should be self explanatory. A couple of them have weird properties that might need cleaning up:
only_*
restriction into a one-way street going the other wayIn both cases, they have been changed to the point that they still succeed as before, although they might need revisiting to question the assumptions being made.
Whilst creating new tests, I also noticed some weird behaviours when combining zero speed traffic updates with a source and target on the same segment. It’s quite a niche scenario though, so I omitted tests for this in the PR and will create an issue with details if anyone is interested.
Performance
I’ll provide a full analysis for the effect on query performance in another comment. The initial findings show a small performance hit, at the expense of finding shorter routes, especially when many waypoints snap to intersections.
Tasklist