Skip to content
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

Add turn lanes support to navigate endpoint #2997

Conversation

IAbderrahmane
Copy link

Please read our contributing guide and note that also your contribution falls under the Apache License 2.0 as outlined there.

Your first contribution should include a change where you add yourself to the CONTRIBUTORS.md file.

Copy link
Author

@IAbderrahmane IAbderrahmane left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to add some tests but the problem is the Andorra file used for the navigate endpoint tests doesn't have any turn:lanes I exported to postgres and checked it. same with the latest Andorra file.

Comment on lines +179 to +182
InstructionDetails lastDetail = instruction.getInstructionDetails().stream()
.sorted(Comparator.comparingDouble(InstructionDetails::getBeforeTurn))
.findFirst()
.get();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I chose the last lane information because in intersections we can't have more than one lane info. I checked the docs and the mapbox API and it had similar results

Comment on lines +344 to +360
for (InstructionDetails details: instructions.get(index + 1).getInstructionDetails()) {
ObjectNode subBannerInstruction = bannerInstructions.addObject();
subBannerInstruction.put("distanceAlongGeometry", details.getBeforeTurn());

ObjectNode subPrimary = subBannerInstruction.putObject("primary");
putSingleBannerInstruction(instructions.get(index + 1), locale, translationMap, subPrimary);

ObjectNode sub = subBannerInstruction.putObject("sub");
sub.put("text", "");
ArrayNode components = sub.putArray("components");
for (LaneInfo lane : details.getLanes()) {
ObjectNode component = components.addObject();
component.put("text", "");
component.put("type", "lane");
component.put("active", lane.isValid());
ArrayNode directions = component.putArray("directions");
putDirections(instructions.get(index + 1), lane, directions, primary, "active_direction");
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This requires some explanation, I checked the mapbox navigation API and how it works is:
when there's lane information to show it creates a bannerInstruction with the primary turn only, then it creates a second bannerInstruction with the same primary and a sub that contains the lane information.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, makes sense then. Were you able to test your changes with the mapbox or maplibre SDK?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not yet, but I'll certainly do. I'll set up the environment and try it out.

@karussell
Copy link
Member

karussell commented May 1, 2024

Thanks!

@boldtrn do you have some time to try it out?

I want to add some tests but the problem is the Andorra file used for the navigate endpoint tests doesn't have any turn:lanes

Can you check map-matching/files/leipzig_germany.osm.pbf and the OSM files in core/files/ ? E.g. it seems the file bautzen.osm has turn lane information like for this way it is <tag k="turn:lanes:backward" v="left|through"/>.

@IAbderrahmane IAbderrahmane changed the title added lanes support to navigate endpoint Add turn lanes support to navigate endpoint May 1, 2024
@IAbderrahmane
Copy link
Author

@karussell I added some tests. I chose to create a new test class for the following reasons:

  • The initialization logic is different from NavigateResponseConverterTest and I didn't want to slow down the tests by adding Before/AfterEach.
  • It's was a bit challenging to use bautzen.osm for the whole test suite since I couldn't get it to cover all the test cases.

Let me know what you think and if I should change something!

@@ -85,6 +85,7 @@ Here is an overview:
* thehereward, code cleanups like #620
* vvikas, ideas for many to many improvements and #616
* zstadler, multiple fixes and car4wd
* abderrahmane, added turn lane information to navigate endpoint
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: as the list has lexicographical order can you move it a bit up :) ?

(btw: will hopefully be able to get some time to test your PR out in the next days)

@IAbderrahmane
Copy link
Author

Here's a simulation that worked well but I still have some doubts that I want to share with you:
https://www.youtube.com/watch?v=OJOTlY8zPSc

  1. The turn lanes are shown when we reach the "distanceAlongGeometry" and this distance can be very short like 20 meters. Although this is not documented Mapbox announce turns earlier, for eg if a banner instruction has a distance of 200 the turn lanes are announced at the start of the primary instruction. We can do this but unlink Mapbox we can have multiple "subs" for a given turn. How should we handle this ? Do we keep it as is and announce the turn lanes when the "arrows" are actually reached or do we do something like Mapbox, in the second case how should we handle multiple turn lanes that are too close ?
  2. Some turn lanes don't have a valid direction, I checked the /route endpoint and it had the same results, is this ok or is something wrong ? for eg if we have 2 lanes is it ok to have the two of them marked as valid/active: false ?

@karussell
Copy link
Member

Nice, thanks a lot! Will merge your PR then!

Do we keep it as is and announce the turn lanes when the "arrows" are actually reached
or do we do something like Mapbox, in the second case how should we handle multiple turn lanes that are too close ?

These are good question! This is indeed a problem I also stumbled over. The problem of announcing them earlier is that we have to ensure that no turn lanes are in-between the current position and next turn lanes as it would be very confusing otherwise. But how can we be 100% sure? Even if there are no turn lanes in-between in the data it might still be that these turn lanes are just missing because they are not mapped. (turn lane data is still very often missing)

Some turn lanes don't have a valid direction, I checked the /route endpoint and it had the same results, is this ok or is something wrong ? for eg if we have 2 lanes is it ok to have the two of them marked as valid/active: false ?

Yes, this is a known limitation in certain "tricky" situations. Every improvement is greatly appreciated :)
Do you have a link to GraphHopper Maps where this occurs?

@karussell karussell merged commit 3032233 into graphhopper:issue_1131 May 12, 2024
@IAbderrahmane
Copy link
Author

Nice, thanks a lot! Will merge your PR then!

Do we keep it as is and announce the turn lanes when the "arrows" are actually reached
or do we do something like Mapbox, in the second case how should we handle multiple turn lanes that are too close ?

These are good question! This is indeed a problem I also stumbled over. The problem of announcing them earlier is that we have to ensure that no turn lanes are in-between the current position and next turn lanes as it would be very confusing otherwise. But how can we be 100% sure? Even if there are no turn lanes in-between in the data it might still be that these turn lanes are just missing because they are not mapped. (turn lane data is still very often missing)

Some turn lanes don't have a valid direction, I checked the /route endpoint and it had the same results, is this ok or is something wrong ? for eg if we have 2 lanes is it ok to have the two of them marked as valid/active: false ?

Yes, this is a known limitation in certain "tricky" situations. Every improvement is greatly appreciated :) Do you have a link to GraphHopper Maps where this occurs?

Of course I had it locally so this is the request body:
{
"points": [
[
13.404917232692242,
52.52001684233737
],
[
13.310509,
52.6201995
]
],
"profile": "car"
}
and this is the response body:
I encountered this in body["paths"][0]["instructions"][5]["details"][0] We have 2 false directions.
Also in body["paths"][0]["instructions"][9]["details"][0]
In body["paths"][0]["instructions"][10]["details"][1]
body["paths"][0]["instructions"][12]["details"][1]

{
"hints": {
"visited_nodes.sum": 151,
"visited_nodes.average": 151.0
},
"info": {
"copyrights": [
"GraphHopper",
"OpenStreetMap contributors"
],
"took": 27,
"road_data_timestamp": "2024-05-08T20:21:30Z"
},
"paths": [
{
"distance": 13965.95,
"weight": 2517.76354,
"time": 1260833,
"transfers": 0,
"points_encoded": true,
"bbox": [
13.310509,
52.519994,
13.404987,
52.6202
],
"points": "}xp_I}cypACG]@cGvIuAgGEMGEOBmBvAsAv@SX[hA}@jCGFKAkGyCiCcAe@Gk@FeE~@g@R_BhAmFdEg@H{Ax@[n@aLpJqAbAcAj@aTvFSAeAX]PsAA_@l@yAbA[DaXnR{BxAuMpJsPpLgAp@gBtAs@n@yOtZm@lAo@AiBGsA|EMp@Iz@c@jFKd@Sl@]p@}@B_@f@sN|P_C|CaGlIoS|Y{FbIMZEN?^F\D^GxAKf@KL}C`@uTI}BfAySxI_JzD]PY\KTMl@A^DFCrBiAh][F}AQSEgCKgKSy@Fa@JaFCiHbFkBvAgBjA{DpCcKxGoKHoHlFUFsBrAURMPoBrA}AlA}@@uyx^sBXgBNaF|@cfn@YCOT}ANy@NEGI@IBEFkFn@m@Xy@|@iDhEI@IJGPwAdBiLjOsB|BURkLvI]Pm@b@mAfA_AtAYf@sVlf@aAzBkAtDMDSTa@Zq@JQFs@i@yCcEk@q@][{@wiek@s@CMD_@ZqPvPyBnBk@Z~@tAENeBfO",
"instructions": [
{
"street_ref": "B 2, B 5",
"distance": 3.29,
"heading": 48.42,
"sign": 0,
"details": [],
"interval": [
0,
1
],
"text": "Continue onto Karl-Liebknecht-Straße",
"time": 257,
"street_name": "Karl-Liebknecht-Straße"
},
{
"distance": 205.152,
"sign": -2,
"details": [
{
"lanes": [
{
"directions": [
"left"
],
"valid": true
},
{
"directions": [
"continue"
],
"valid": false
},
{
"directions": [
"continue"
],
"valid": false
},
{
"directions": [
"none"
],
"valid": false
}
],
"before_turn": 3.2897712452753627
}
],
"interval": [
1,
3
],
"text": "Turn left onto Spandauer Straße",
"time": 18754,
"street_name": "Spandauer Straße"
},
{
"distance": 341.433,
"sign": 2,
"details": [
{
"lanes": [
{
"directions": [
"left"
],
"valid": false
},
{
"directions": [
"right"
],
"valid": true
}
],
"before_turn": 53.644
}
],
"interval": [
3,
12
],
"text": "Turn right onto Anna-Louisa-Karsch-Straße",
"time": 43900,
"street_name": "Anna-Louisa-Karsch-Straße"
},
{
"distance": 715.697,
"sign": 7,
"details": [],
"interval": [
12,
24
],
"text": "Keep right onto Rosenthaler Straße",
"time": 92019,
"street_name": "Rosenthaler Straße"
},
{
"distance": 22.566,
"sign": -1,
"details": [
{
"lanes": [
{
"directions": [
"left"
],
"valid": true
},
{
"directions": [
"continue",
"right"
],
"valid": false
}
],
"before_turn": 73.477
}
],
"interval": [
24,
25
],
"text": "Turn slight left onto Rosenthaler Platz",
"time": 1766,
"street_name": "Rosenthaler Platz"
},
{
"distance": 3245.342,
"sign": 1,
"details": [
{
"lanes": [
{
"directions": [
"left"
],
"valid": false
},
{
"directions": [
"continue"
],
"valid": false
}
],
"before_turn": 22.566
}
],
"interval": [
25,
56
],
"text": "Turn slight right onto Brunnenstraße",
"time": 311437,
"street_name": "Brunnenstraße"
},
{
"distance": 1296.081,
"sign": -7,
"details": [
{
"lanes": [
{
"directions": [
"left"
],
"valid": true
},
{
"directions": [
"none"
],
"valid": false
},
{
"directions": [
"none"
],
"valid": false
}
],
"before_turn": 69.78
}
],
"interval": [
56,
65
],
"text": "Keep left onto Schwedenstraße",
"time": 106735,
"street_name": "Schwedenstraße"
},
{
"distance": 11.063,
"sign": 0,
"details": [],
"interval": [
65,
66
],
"text": "Continue onto Holländerstraße",
"time": 1422,
"street_name": "Holländerstraße"
},
{
"distance": 142.708,
"sign": 7,
"details": [],
"interval": [
66,
70
],
"text": "Keep right onto Holländerstraße and drive toward Frohnau, Wittenau",
"time": 11169,
"street_destination": "Frohnau, Wittenau",
"street_name": "Holländerstraße"
},
{
"street_ref": "B 96",
"distance": 1134.458,
"sign": 0,
"details": [
{
"lanes": [
{
"directions": [
"none"
],
"valid": false
},
{
"directions": [
"none"
],
"valid": false
},
{
"directions": [
"right"
],
"valid": false
},
{
"directions": [
"none"
],
"valid": false
}
],
"before_turn": 88.815
}
],
"interval": [
70,
78
],
"text": "Continue onto Residenzstraße",
"time": 125541,
"street_name": "Residenzstraße"
},
{
"street_ref": "B 96",
"distance": 767.293,
"sign": -1,
"details": [
{
"lanes": [
{
"directions": [
"none"
],
"valid": false
},
{
"directions": [
"continue"
],
"valid": true
},
{
"directions": [
"right"
],
"valid": false
}
],
"before_turn": 62.82299999999999
},
{
"lanes": [
{
"directions": [
"none"
],
"valid": false
},
{
"directions": [
"continue"
],
"valid": false
},
{
"directions": [
"right"
],
"valid": false
}
],
"before_turn": 26.843
}
],
"interval": [
78,
84
],
"text": "Turn slight left onto Lindauer Allee and drive toward Frohnau, Wittenau",
"time": 60048,
"street_destination": "Frohnau, Wittenau",
"street_name": "Lindauer Allee"
},
{
"street_ref": "B 96",
"distance": 2857.783,
"sign": 2,
"details": [
{
"lanes": [
{
"directions": [
"left"
],
"valid": false
},
{
"directions": [
"continue"
],
"valid": false
},
{
"directions": [
"continue",
"right"
],
"valid": true
},
{
"directions": [
"right"
],
"valid": true
}
],
"before_turn": 48.934
}
],
"interval": [
84,
111
],
"text": "Turn right onto Roedernallee and drive toward Frohnau, Wittenau",
"time": 223655,
"street_destination": "Frohnau, Wittenau",
"street_name": "Roedernallee"
},
{
"street_ref": "B 96",
"distance": 2122.711,
"sign": 1,
"details": [
{
"lanes": [
{
"directions": [
"left"
],
"valid": false
},
{
"directions": [
"continue"
],
"valid": true
},
{
"directions": [
"continue"
],
"valid": true
}
],
"before_turn": 70.219
},
{
"lanes": [
{
"directions": [
"continue"
],
"valid": false
},
{
"directions": [
"continue"
],
"valid": false
}
],
"before_turn": 25.883
}
],
"interval": [
111,
142
],
"text": "Turn slight right onto Oranienburger Straße",
"time": 166126,
"street_name": "Oranienburger Straße"
},
{
"street_ref": "B 96",
"distance": 864.094,
"sign": 1,
"details": [],
"interval": [
142,
154
],
"text": "Turn slight right onto Berliner Straße",
"time": 67625,
"street_name": "Berliner Straße"
},
{
"distance": 45.381,
"sign": -3,
"details": [],
"interval": [
154,
155
],
"text": "Turn sharp left onto Auguste-Viktoria-Straße",
"time": 5835,
"street_name": "Auguste-Viktoria-Straße"
},
{
"distance": 190.898,
"sign": 2,
"details": [],
"interval": [
155,
157
],
"text": "Turn right onto Silvesterweg",
"time": 24544,
"street_name": "Silvesterweg"
},
{
"distance": 0.0,
"sign": 4,
"last_heading": 287.7164864028942,
"details": [],
"interval": [
157,
157
],
"text": "Arrive at destination",
"time": 0,
"street_name": ""
}
],
"legs": [],
"details": {},
"ascend": 0.0,
"descend": 0.0,
"snapped_waypoints": "}xp_I}cypAiqRfmQ"
}
]
}

@karussell
Copy link
Member

Thanks, will investigate. Can you have a look into #2954? Unfortunately the test bannerInstructionsTest now fails somehow after I merged master. Did I make a mistake when merging?

@karussell
Copy link
Member

Ok, think I found it...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants