-
Notifications
You must be signed in to change notification settings - Fork 76
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
Disallow travel through barrier nodes #841
Conversation
fixes a problem where underground platforms at Delft station were not connected to the station stairs, but were connected to an emergency exit at the far end of the platform.
Do we know how this will effect the average OSM street network? While it seems like a positive improvement, I'm not sure what the extended effects will be. Being able to check how many more "additional disconnected components" are removed across every network used on Conveyal recently would be interesting to see. Additionally, it'd be great to see additional unit tests that are fixed or related to testing this issue (also for #838). A unit test would probably be easier to add than a creating pipeline for analyzing recently used OSM networks. Can a unit test be added within the scope of this PR? |
The immediate goal here was to get a patch in place from which we could build a new worker version in case it is needed on any projects in Delft. But coming back to this, I think the approach is only good as a stopgap so I've converted it to a draft PR. Skipping creating whole edges is the easiest thing to do but it has too many potential bad side effects. Consider two edges between three nodes Alternative approaches that I considered include: a) creating a separate r5 vertex for each time a barrier node is referenced by a way (splitting the node into N different vertices that are not connected to each other) or b) storing the barrier characteristic on the vertex in the VertexStore and refusing traversal on the fly. The latter involves checking this characteristic on every single edge traversal, though it won't take up any more space since we have plenty of unused bit flags. Option a seems like a good way to go. The "disconnected components" here are what we otherwise refer to as "islands". So it's kind of surprising that by just removing edges that are blocked at one end, 95 new small pieces of the network become inaccessible. So 95 places were only connected to the rest of the world via nodes (such as this emergency exit) that are barriers in reality. Everything points to these being genuinely disconnected islands, which means that without this patch we are routing into places that are inaccessible in the real world. The net effect of their removal may be minor though, as once such disconnected roads are removed we still allow travel through 'free space' to reach any cells inside. But it would be interesting to at least run one accessibility analysis to see the difference, and map those removed components to see what they are. I agree it makes sense to include some unit tests with the final implementation of this PR. Not just checking for collateral damage, but ensure that genuinely disconnected circuitous paths like the one in Delft are eliminated and transit stops are not linked to them. It should be straightforward to create a synthetic little OSM network to test this. |
instead of skipping the creation of segments that would lead through an impassable node.
for all edges at a vertex
i.e. number of connected vertices
My commits here implement approach a) in @abyrd's previous comment: instead of skipping the creation of segments, impassable OSM nodes are not registered as vertices, which leads to duplicate vertices when multiple ways reference an impassable node. Worth discussing:
|
Thanks @ansoncfit. I was looking at this branch again yesterday in anticipation of reviewing your commits, and noted the following:
|
Now reviewing the PR - thanks for including the test @ansoncfit. In addition to validating the fix, looking at the test fixture OSM data is helping think through the problem. The test demonstrates that creating separate vertices each time an OSM barrier node is referenced does handle this particular case in Delft, but also demonstrates why it would not handle similar problems in other places. The OSM contains several First, it seems like a method with the name Second, as you mentioned, these I think to consider this fix complete, we'll need to pre-detect the barrier nodes and fragment the ways into edges at those nodes as well as intersections. For the reasons described in my previous comment, I would like to check whether this causes any perceptible slowdown in network building and egress table construction. As long as I'm checking speed, I will also check the alternative approach using a vertex flag to block traversal during routing. Simply not putting the barrier nodes into the vertexIndexForOsmNode map is a nice trick to keep the code simple. However my gut feeling is that it's better for the data structures to reflect simple consistent relationships. If the map means "osm node X is represented by vertex Y", it follows that "absence of key X means there's no corresponding vertex", and this could become harder to reason about outside the present special case if we add the contradictory meaning "absence of key X means there are multiple corresponding vertices". Of course it may be sufficient to add a clear comment as you've done. |
Maybe what we want for
|
Agreed, given that OSM guidance is not to locate barriers at intersections (https://wiki.openstreetmap.org/wiki/Key:barrier#How_to_map_barrier_nodes)
That's also my sense -- a more substantial change would probably be worth it to keep things easier to reason about. |
I implemented vertex-flag-based barrier nodes, supporting barrier nodes at non-intersection locations. I discovered a few snags and existing problems including:
Again the Delft test data helps identify and understand the problems. In the Delft data there are only two barrier nodes on ways: the emergency exit stairs and path out of platform 3/4 start at the emergency exit node 3377954642 and contain gate node 5591069148 at a non-intersection point. The rest of the barrier nodes are free-floating gate nodes that are not on any way. It looks like someone was trying to situate the gate nodes on the platforms or paths but failed to do so topologically and left them free-floating. We can imagine what would happen if they were on the platform ways like the emergency exit is. This raises the question of what exactly it means when a barrier node is along a way. Presumably if it's a linear way, one cannot pass through that point at all. However, if it's an areal way like a platform, presumably the barrier does not block passage through that part of the area, but only passage to other ways via that point on the area's edge. To fit a graph-based routing model, R5 is treating platforms as linear features instead of true areas (we usually just route along the edge of the platform). Bocking traversal of the emergency exit node (or other nodes like gates) then erroneously prevents passing through that point on the platform (when remaining on the platform) as well as correctly preventing passage to other ways such as the emergency exit stairs. Secondly, the island pruning code contains its own separate search implementation (distinct from edge.traverse) and does not use the edge-based routing needed for handling turn restrictions and barrier nodes. So even when regular routing is modified to not pass through barrier nodes, island pruning still routes through them. Duplicating the same checks in the island pruner (besides being ugly style-wise) still does not work because the island pruning algorithm remains vertex-based, while all other routing is essentially edge-based (states are situated at the end of edges before entering the vertex, not at vertices - see Javadoc on For these reasons, even though I still see the node-based barrier approach as being more consistent with source OSM data, it becomes quite messy with our current code. I think we should keep @ansoncfit's duplicate node approach. I would like to keep some changes from my branch though:
The third item is the most disruptive and should probably not go into the current release. I'll finish checking the performance of the above. I have pushed my draft changes to another branch |
Thanks for pointing this out. I now realize that I already looked at this list when originally writing the method, and almost all the |
also add method to set flag on vertex without creating cursor object
Also set IMPASSABLE vertex flag and use it to split nodes.
I merged changes from @ansoncfit with some of my own, keeping @ansoncfit's approach of splitting OSM nodes into multiple vertices, but also flagging those vertices as I built some medium-sized networks with and without these changes, and don't see any appreciable change in the time taken to create network edges from OSM data. I did not yet update the island pruning code to be edge-based - we can do that when solving #806, perhaps using an approach like the one drafted in branch |
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.
Looks good, thanks for the follow-up changes, especially to add intersections at barrier nodes along single ways.
We should consider tags beyond Other examples showing the expected behavior with simpler tags: ✔ ✔ |
This fixes a problem where underground platforms at Delft station were not connected to the station stairs in the input OSM data, but were connected to an emergency exit at the far end of the platform. This PR checks a few tags that make a location impassable when they are present on a node. It's simplistic but a good start.
Tested locally on Delft OSM data. This seems to have no impact on network build time. R5 reports finding and removing 95 additional disconnected components after this change (out of 2596 total in this tiny area). Isochrones look much better now.