Repository navigation
Car loops caused by turn restrictions - #3399
Conversation
| } | ||
| } | ||
|
|
||
| public static Graph buildGraph(String path) { |
There was a problem hiding this comment.
This code was unused.
| return instance; | ||
| } | ||
|
|
||
| public GtfsContext getPortlandContext() { |
There was a problem hiding this comment.
This code was unused.
52bcbb2 to
b9ae55f
Compare
a8d7c7b to
514d197
Compare
|
After our conversation today at the OTP2 meeting I reworked this PR a little and have some results so share. Test graph building speedI reduced the size of the test graph by both using a smaller area and stripping out anything that is not a road. Building the graph is now reported to take 0 seconds, so presumably it's only a few hundred milliseconds. I would say @t2gran's concerns are addressed. Performance impactThe good news is that I could generate a trip from Oslo to Trondheim which is a 480km trip. Sadly the performance hit is quite significant: before the change it would take 2.5 seconds to calculate and after removing the turn restrictions check it takes around 4 seconds. 😿 I'm not sure if this is an acceptable slowdown. |
|
I've taken a more scientific approach and benchmarked the various implementations more thoroughly. To do this, I've used apache bench ( CommandsWarm up Measuring ResultsNo loops allowed (current
|
9f84369 to
1b0d737
Compare
| * The following variable determines how close you have to be to the start or the end point for it to be | ||
| * considered "close enough for a loop". | ||
| */ | ||
| if (a.backEdge != b.getBackEdge() |
There was a problem hiding this comment.
Should there be a check for car mode here?
There was a problem hiding this comment.
Well, technically turn restrictions also apply to cycling, however you can always get off and push the bike. Maybe this is a good idea.
There was a problem hiding this comment.
So I checked my test case and if I only allow the loop for cars the bike will take a route like this: https://leonard.io/polyline-visualiser/?base64=b3VxZ0h9bWN1QGdBRV1VfUJhQV1RfUBddUFzQFtTQW1ARWVAQVVHQkFIS0Y_SFNIR3hA
That's ok, I guess.
There was a problem hiding this comment.
I see your point that it may be relevant to biking too. I will leave it up to you whether to include biking or. not, as you have worked more on bike routing than me
|
I discussed this a little bit with @flaktack in the chat window of the last OTP meeting. I think for one-to-many searches we would need to check for loop edges for the entire search, as we do not know if we are close to one of the acceptable destinations. |
415775c to
bb6fef7
Compare
How would you address this issue? |
7d2a8f1 to
c3438f9
Compare
I think the This would require a check on all from/to vertices, to see whether they are inside the envelopes, but that should not be too expensive. |
c3438f9 to
79cee39
Compare
t2gran
left a comment
There was a problem hiding this comment.
This is almost good to go from a technical point, I have not looked at the functionality.
The addition of the dev-doc is great.
| if (backEdgeHasTurnRestrictions(a) | ||
| /** | ||
| * {@link DominanceFunction.MAX_METERS_ROUTE_LOOPS} | ||
| */ | ||
| || a.getBackMode() != TraverseMode.WALK && isCloseToStartOrEnd(a.getVertex(), a.getOptions())) { |
There was a problem hiding this comment.
I think you commented on an outdated version, right?
| @DisplayName("car routes can contain loops (traversing the same edge twice)") | ||
| public void shouldAllowLoopCausedByTurnRestrictions() { | ||
| var hindenburgStrUnderConstruction = ConstantsForTests.buildOsmGraph( | ||
| ConstantsForTests.HERRENBERG_HINDENBURG_STR_UNDER_CONSTRUCTION_OSM); |
There was a problem hiding this comment.
I used the Intellij code style supplied by you to automatically format this file. Is this not the result you were expecting?
| computePolyline(hindenburgStrUnderConstruction, gueltsteinerStr, aufDemGraben); | ||
|
|
||
| assertThatPolylinesAreEqual( | ||
| polyline, "ouqgH}mcu@gAE]U}BaA]Q}@]uAs@[SAm@Ee@AUEi@XEQkBQ?Bz@Dt@Dh@@TGBC@KBSHGx@"); |
| var itineraries = GraphPathToItineraryMapper.mapItineraries(paths, request); | ||
| // make sure that we only get CAR legs | ||
| itineraries.forEach( | ||
| i -> i.legs.forEach(l -> Assertions.assertEquals(l.mode, TraverseMode.CAR))); |
f93eb3c to
06d779b
Compare
|
@t2gran I've reimported the Intellij style but it didn't autoformat to Egyptian brackets so I did it manually. |
|
@gmellemstrand I've changed the JavaDoc to take the limitations of this approach into account: 23ee8a6 Can you check that I understood everything ok? |
t2gran
left a comment
There was a problem hiding this comment.
Thank you for doing this. I reviewed the two last commits, which complete what we talked about in todays developer meeting.
I think what you wrote is sufficient. It gets the point across that the check will have to be expanded if these limitations are not acceptable. |
23ee8a6 to
ab68e75
Compare
gmellemstrand
left a comment
There was a problem hiding this comment.
Since only documentation and merging adjustments have been done after @t2gran 's review, I will approve this.


Summary
This problem has been discussed in the OTP2 dev meeting and is described in #3393.
Short recap: (Car) routes with required loops (example) lead to an error.
Our solution is to allow those loops close to the start or end of the route by adding a check in the dominance function. This is the actual change of the PR: 88f28d0
It also updates Junit to the latest version.
Alternative solutions
Both @flaktack and @gmellemstrand have made suggestions how the problem could be solved:
Stateso that would need to be added.Lets discuss in the next dev meeting.
Issue
Fixes #3393
Fixes #3402
Unit tests
The bulk of the PR actually consists of unit tests. It introduces a technique not used a lot in current OTP tests: It builds a graph from actual OSM data, runs queries on it and uses the resulting polyline for assertions.
For tricky situations like the one we are discussing here I find it hard to reproduce the issues by building up individual edges manually and therefore opted for this approach. It also helps to build up a corpus of routes that make it easier to tell if an algorithm change has unintended side effects.
The downside is that building the graph takes longer than the ordinary test setup: building the graph for a small city like Herrenberg takes around 3-4 seconds. We should discuss if this is too high a price to pay or if restructuring these tests (perhaps by running them in a separate integration test phase) is worth doing.
In order to achieve this I introduced an interface for the graph sources so that it's easier to specify the exact OSM and GTFS files in a test graph.
This PR also introduces a new helper tool to give you a nice error message when two polylines are not the same. It links you to a website where you can see the lines visualised on a map.
Code style
✅
Documentation
✅
Changelog
✅