- multiple driving lanes, with possibly individual turn restrictions
- dedicated bus lanes
- lanes with parked cars
- bike lanes
- sidewalks
Each lane needs some geometry:
- center lines to draw agents on
- for sidewalks, use center line to to draw agents on the left and right sides?
- polygons to draw the lane and mouseover
Open questions:
- Can we assume all lanes are the same width?
- Seems wrong for many sidewalks especially
- Could be wrong for bike lanes, but could just assume it's a bike lane with a buffer
- Some lanes are immutable
- Sidewalks can't be changed to other types; they're raised with a curb
Some modeling questions:
- Where should expansion of roads into lanes happen?
- initial OSM conversion, adding more stuff to the proto?
- initial map_model::new loading, at least for development convenience
- same reason that turns aren't (yet) serialized
- Is it useful to model the entire road?
- the parent/child relation may be hard to maintain
- but lanes need to know their siblings
- maintaining directional sanity could be useful
- what's the UI for changing lane types?
- it's a bit arbitrary which lane should draw the yellow center lines
Initial design:
- "Road" becomes "Lane" with a type
- don't need to know sibling lanes yet
- arbitrarily, one lane might have extra bits/geometry for yellow center line markings
- ideally, get rid of one-wayness and original center points, and plumb along pre-shifted lines
- but due to the polyline problem (affecting both geom center line layer that agents follow, and polygons for drawing), can't do this. encapsulate the messiness at least.
- so, store one way and orig points and index, but have an accessor
- as a compromise, dont interpet OSM points on a one-way road as the center, but as the edge? this is proving hard to do.
Thinking about a new design:
- Much more general "Land" primitive that's just a nice polygon boundary for drawing/selection and one (or more, for sidewalks?) center lines for how to cross the space, with a notion of turns. It's what road is now, but way simpler data.
- Maybe the GeomRoad / DrawRoad split is a little confusing after all, since the layering just isn't perfect. figure out the polygon and centerline up-front, then ditch the other intermediate gunk.
- also ideally make one polygon for the road, not a bunch of individual pieces? but then we'd have to go triangulate later for opengl anyway
- enforce that all the polygons are nonoverlapping
## Representing map edits
Two reasons for edits:
- the basemap is wrong because of bad OSM data or heuristics
- here's a possible edit to A/B test
Types of edits:
- change lane type between driving, parking, biking
- sidewalks are fixed!
- some edits are illegal... parking lane has to be in a certain side... right? well, actually, dont do that yet.
- delete a lane (because the basemap is wrong)
- modify stop sign priorities
- modify traffic signal timings
How to visually diff edits?
- highlight them
- UI to quickly jump and see them
How to encode the edits?
- "Remove lane" is weird; how about per road, list the lane types? Then it's
almost kinda obvious how to plug into part of the current map making
pipeline.
- alright, let's really first think about road vs lane
Need to work through some edits to see how they affect downstream things. What
needs to be recomputed? How do we long-term serialize things like edits? How
can they even refer to things by ID if the IDs could change? What IDs might
change?
Alright, now we can be concrete -- when we have a road edit, what can be affected?
MAP LAYER:
- the road struct state (just list of children, really)
- dont want to blindly run all the road making code, since it'd double-add stuff to intersection
- delete old lanes, make new lanes
- how would IDs work? if we try to reuse the old ones, we might wind up
with gaps, or overflowing available space.
- trim lanes
- need to recalculate original lane_center_pts for all affected lanes
in a certain direction. tricky since they're two-sided; have to
restore just the original direction on it.
- recalculate turns, for the two intersections
- same ID problem
- recalculate some building front paths, maybe
CONTROL LAYER:
- recalculate two intersections
SIM LAYER:
- creating/deleting sidewalks is pretty easy
- SimQueues are associated with turns and lanes, but easyish to create/delete later
- should probably have a way to prevent mutations; maybe need to drain a lane of agents before changing it
UI:
- make a new DrawLane, DrawIntersection, etc
- update quadtrees
- would have to maybe update a bunch of plugin state (highlighting or
floodfilling or something), but since we know road editor is active, is easy!
Strategies:
- testing via equivalence -- reload from scratch should be equal to live edits
- will IDs make this very tricky?
- for things like sim and UI that hook on and have derived state, should we
always kinda lazily grab DrawRoads, SimQueues, etc? or immediately plumb
through deletes and inserts?
- is there a way to programatically record data dependencies or kinda do FRPish stuff from the start?
- could always blindly recalculate everything live, but man, that's gotta be slow
- maybe change constructors that take full map into incremental "hey, this road exists!" mutations. then just need to introduce deletions. in other words, embrace incremental mutability.
- assume the bbox doesn't change as a result of any edit
the ID problem:
- need determinism and deep equality checks for things. if we load a map from
scratch with edits, vs do a live shuffle, the IDs wont match up if they use a
slotmap.
- can we refer to things in more stable ways; no LaneID, but
RoadID+direction+offset. no Turn, but two... effectively lane IDs?
- maybe we can combine these ideas; use nondet slotmaps, but when doing
equality checks, dont use these IDs -- treat these IDs as memory addresses.
raw_map to map is expensive -- so much that we have to precompute it. For the simple edits (change lane type and modify intersection policy), can we do a cheap live update?
MAP LAYER:
- initial Road stores lane_specs, but doesnt use the lanetypes yet
- halfmap uses lane types: is_border, make_all_turns, turn lookup idx
- stop signs and traffic signals assigned last-minute, very easy to override in map layer
- pathfinder graph
SIM LAYER (ignore for now, just ban most live edits):
- parking sim needs to know about lane types
- block some edits
- cant modify turns while intersection has any requests or accepted
- cant change lane type while anybody is on it
- or if parking spot is reserved
- paths are also affected
EDITOR LAYER:
- ooh, luckily DrawLanes aren't batched! should be relatively easy.
equivalence test...
- option 1: load a map from scratch with edits, compare to making live edits, do PartialEq and meld
- option 2: always apply edits as last step of initial map loading. always reset map to canonical form before applying edits.
So how to structure things?
- dont ask for individual changes; mutate a MapEdits object and ask map, sim, editor layer to recalculate everything needed.
- lane IDs will never change; just store LaneID -> LaneType overrides.
- might have to figure out original OSM-based lanetype by recalculating
- applying map edits always takes a BEFORE (possibly empty) and AFTER set