-
Notifications
You must be signed in to change notification settings - Fork 12
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
Cache roads per intersection. #93 #98
Conversation
/// All roads connected to this intersection. They may be incoming or outgoing relative to this | ||
/// intersection. | ||
/// TODO: Guarantee they're sorted clockwise | ||
pub roads: Vec<OriginalRoad>, |
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.
Is there a good type that has an insert_at
to take advantage of the fact that roads is already sorted?
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.
Like https://doc.rust-lang.org/std/vec/struct.Vec.html#method.insert ? When we're adding a new road, we could calculate its position in the list and add it, or just recalculate the ordering for the intersection. It'll depend on the sorting algorithm
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.
Right. Performance doesn't really matter, so Vec
works if we want to do it the "find and insert" way.
Great to see! Sorted roads on all intersections will unlock movements in #96, so this progress is exciting. |
No more crashes, but lots of test diffs. From a quick spot check, no visible difference, but will dig in later.
…one use right now, in clip If later transformations need something like this, we could reintroduce. But I suspect we'd always just re-use a real OSM ID from something being merged / transformed.
OK @BudgieInWA, this is ready for review! The changes:
There are lots of test diffs. Internal IDs change a bit, especially the negative ones that're created by clipping. Some coordinates also change. I visually diffed all of the cases and they all look identical, except for northgate, where a long disconnected piece of light rail gets clipped a bit differently. The clockwise sorting is probably imperfect, but all the cases I've looked at are fine: I wanted to simplify the logic in |
|
||
// Restore the invariant that an intersection's roads are ordered clockwise | ||
// | ||
// TODO This doesn't handle trim_roads_for_merging |
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.
In cases where we remove a short road and merge intersections, sorting around a "center" point gets kind of funny. geometry/algorithm.rs
takes care to try and handle that. I didn't port the same logic here yet.
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 think the best way to determine the order of roads in those multi-node intersections from scratch is to use the OSM graph structure. First sorting the nodes (that are the Road endpoints) then by bearing of the first OSM segment. #98 (comment)
This would require keeping the OSM graph around in some capacity, at least within multi-node intersections.
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 agree with keeping the graph structure around somehow. Preserving turn restrictions when we merge gets very complex, and a possibly simpler approach is to use the original graph and just ask questions about it. Keeping the graph also means we can map back to objects in OSM more directly.
I don't know how this would work, so shelving the idea for the moment, but you've definitely got me thinking...
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 "Asking questions about it". In fact, load and leave the osm graph completely in place. Every road should get it's own copy of the geom (like when you merge similar ways currently) which can be promptly offset to account for placement. Then further tweaked if needed (like sausage links). (Think of an editor, where the graph is literally drawn on the map. One could point at a lane to edit the way.)
(Roads and intersections need to have IDs independant of the OSM ids they reference, [and they need to know their own ID, so we don't need to pass pairs eveywhere])
Asking questions about roads is how I'm thinking about movements too. It's like I want to iterate flows of traffic clockwise around the intersection. A way could yield a single (oneway
) flow, or commonly two. An intersection provides an iter_cw_flows() -> Flow
, where Flow is a view onto a subset of lanes on a Road (that all go in the same direction).
I think that's how the type system helps me out here: There exists a whole lot of data about a whole lot of lanes, laid out in memory in one way or another, I want to slice it up differently, with differently typed structs, for different tasks. It's like the HashMap Entry type.
Keeping an immutable copy of the OSM graph and making the Street graph independent will no doubt become GH Issues to discuss and target soon.
let mut road2 = streets.roads.remove(&r2).unwrap(); | ||
let mut new_road = streets.remove_road(&r1); | ||
let mut road2 = streets.remove_road(&r2); | ||
streets.intersections.remove(&i).unwrap(); |
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.
Order matters! remove_road
cleans up the two intersections, so they need to both exist until the end
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 results look good. I like the idea of merging this, even if the order isn't correct all of the time. Definitely good enough to start experimenting with.
I've only had a cursory look over the code, and wont have much time for movement calculations this week, so I'm happy to see this go ahead!
Cool, then I'll merge! Based on approaching timelines for some work stuff, I'm about to start an issue and some experimentation with pedestrian/bike crossings. Not sure yet how things will fit into the movement PR that's started, but we'll find out I guess |
… Detected when trying to import larger areas in A/B Street, where turn restrictions happened to cross a boundary
Since inserting or removing a road in the graph now requires maintaining state in intersections, we have to be careful and use the new methods that keep everything correct. I hit a few hard-to-debug problems where the order of operations in some transformations matters... you have to delete the road first, then the intersection. Otherwise,
remove_road
will be upset that one of the intersections doesn't exist.This is still broken -- two tests still failing for reasons I'm having trouble debugging. The complexity of the code and transformations increases a bit with this change, but I think it's a bit necessary. The previous brute-force
roads_per_intersection
search was really inefficient.Once I fix the last bug, I plan to add clockwise ordering using the original OSM center line. When we merge short roads, this'll have some occasional brokenness maybe, but will see