optionally detect when a path violates one of these complicated TRs

This commit is contained in:
Dustin Carlino 2020-05-03 11:43:21 -07:00
parent 7d2fa77323
commit 3a8e56f16b
7 changed files with 100 additions and 43 deletions

View File

@ -23,8 +23,8 @@ pub fn extract_osm(
HashMap<HashablePt2D, i64>, HashMap<HashablePt2D, i64>,
// Simple turn restrictions: (restriction type, from way ID, via node ID, to way ID) // Simple turn restrictions: (restriction type, from way ID, via node ID, to way ID)
Vec<(RestrictionType, i64, i64, i64)>, Vec<(RestrictionType, i64, i64, i64)>,
// Complicated turn restrictions: (restriction type, from way ID, via way ID, to way ID) // Complicated turn restrictions: (from way ID, via way ID, to way ID)
Vec<(RestrictionType, i64, i64, i64)>, Vec<(i64, i64, i64)>,
// Amenities (location, name, amenity type) // Amenities (location, name, amenity type)
Vec<(Pt2D, String, String)>, Vec<(Pt2D, String, String)>,
) { ) {
@ -143,6 +143,7 @@ pub fn extract_osm(
center_points: pts, center_points: pts,
osm_tags: tags, osm_tags: tags,
turn_restrictions: Vec::new(), turn_restrictions: Vec::new(),
complicated_turn_restrictions: Vec::new(),
}, },
)); ));
} else if is_bldg(&tags) { } else if is_bldg(&tags) {
@ -256,7 +257,14 @@ pub fn extract_osm(
} else if let (Some(from), Some(via), Some(to)) = } else if let (Some(from), Some(via), Some(to)) =
(from_way_id, via_way_id, to_way_id) (from_way_id, via_way_id, to_way_id)
{ {
complicated_turn_restrictions.push((rt, from, via, to)); if rt == RestrictionType::BanTurns {
complicated_turn_restrictions.push((from, via, to));
} else {
timer.warn(format!(
"Weird complicated turn restriction from {} to {} via {}: {}",
from, to, via, restriction
));
}
} }
} }
} }

View File

@ -21,7 +21,7 @@ pub fn split_up_roads(
HashSet<HashablePt2D>, HashSet<HashablePt2D>,
HashMap<HashablePt2D, i64>, HashMap<HashablePt2D, i64>,
Vec<(RestrictionType, i64, i64, i64)>, Vec<(RestrictionType, i64, i64, i64)>,
Vec<(RestrictionType, i64, i64, i64)>, Vec<(i64, i64, i64)>,
Vec<(Pt2D, String, String)>, Vec<(Pt2D, String, String)>,
), ),
timer: &mut Timer, timer: &mut Timer,
@ -137,7 +137,8 @@ pub fn split_up_roads(
// Resolve complicated turn restrictions (via a way). TODO Only handle via ways immediately // Resolve complicated turn restrictions (via a way). TODO Only handle via ways immediately
// connected to both roads, for now // connected to both roads, for now
for (restriction, from_osm, via_osm, to_osm) in complicated_turn_restrictions { let mut complicated_restrictions = Vec::new();
for (from_osm, via_osm, to_osm) in complicated_turn_restrictions {
let via_candidates: Vec<OriginalRoad> = map let via_candidates: Vec<OriginalRoad> = map
.roads .roads
.keys() .keys()
@ -146,8 +147,9 @@ pub fn split_up_roads(
.collect(); .collect();
if via_candidates.len() != 1 { if via_candidates.len() != 1 {
timer.warn(format!( timer.warn(format!(
"Couldn't resolve {:?} from {} to {} via way {}. Candidate roads for via: {:?}", "Couldn't resolve turn restriction from {} to {} via way {}. Candidate roads for \
restriction, from_osm, to_osm, via_osm, via_candidates via: {:?}",
from_osm, to_osm, via_osm, via_candidates
)); ));
continue; continue;
} }
@ -165,17 +167,23 @@ pub fn split_up_roads(
.find(|r| r.osm_way_id == to_osm); .find(|r| r.osm_way_id == to_osm);
match (maybe_from, maybe_to) { match (maybe_from, maybe_to) {
(Some(from), Some(to)) => { (Some(from), Some(to)) => {
map.complicated_turn_restrictions complicated_restrictions.push((from, via, to));
.push((from, via, to, restriction));
} }
_ => { _ => {
timer.warn(format!( timer.warn(format!(
"Couldn't resolve {:?} from {} to {} via {:?}", "Couldn't resolve turn restriction from {} to {} via {:?}",
restriction, from_osm, to_osm, via from_osm, to_osm, via
)); ));
} }
} }
} }
for (from, via, to) in complicated_restrictions {
map.roads
.get_mut(&from)
.unwrap()
.complicated_turn_restrictions
.push((via, to));
}
timer.stop("splitting up roads"); timer.stop("splitting up roads");
(map, amenities) (map, amenities)

View File

@ -5,18 +5,18 @@ data/input/barranquilla/osm/barranquilla.osm,ff0f301a84d21f20c87ee7fa3ae3518f,ht
data/input/barranquilla/osm/colombia.osm.pbf,31c7abfcc1ec4625e6e4fbee9e89bfd3,Couldn't get shared link: Unknown Error data/input/barranquilla/osm/colombia.osm.pbf,31c7abfcc1ec4625e6e4fbee9e89bfd3,Couldn't get shared link: Unknown Error
data/input/los_angeles/osm/downtown_la.osm,9b2c4729d3031553a477bb2e1134a6bf,https://www.dropbox.com/s/235jahht1xyulkx/downtown_la.osm.zip?dl=0 data/input/los_angeles/osm/downtown_la.osm,9b2c4729d3031553a477bb2e1134a6bf,https://www.dropbox.com/s/235jahht1xyulkx/downtown_la.osm.zip?dl=0
data/input/los_angeles/osm/socal.osm.pbf,1dd1b7d3a6d38829a8266b0b6ea60b85,https://www.dropbox.com/s/gdd7lth4fmy0fby/socal.osm.pbf.zip?dl=0 data/input/los_angeles/osm/socal.osm.pbf,1dd1b7d3a6d38829a8266b0b6ea60b85,https://www.dropbox.com/s/gdd7lth4fmy0fby/socal.osm.pbf.zip?dl=0
data/input/raw_maps/23rd.bin,3fcdd5da74ed97515058174011a63bd2,https://www.dropbox.com/s/9g5589k9swdln9y/23rd.bin.zip?dl=0 data/input/raw_maps/23rd.bin,17d20dbee81b800418dfa4b3de5c103c,https://www.dropbox.com/s/9g5589k9swdln9y/23rd.bin.zip?dl=0
data/input/raw_maps/ballard.bin,14876451715fc09af7ad412830702452,https://www.dropbox.com/s/wus0ufcnjyvcsuy/ballard.bin.zip?dl=0 data/input/raw_maps/ballard.bin,dd3e802affe057e8c5d0a4d2925831ba,https://www.dropbox.com/s/wus0ufcnjyvcsuy/ballard.bin.zip?dl=0
data/input/raw_maps/barranquilla.bin,160c3e6ba29afb1ca0981c8619b4b4f8,https://www.dropbox.com/s/5z890kpowgeftk4/barranquilla.bin.zip?dl=0 data/input/raw_maps/barranquilla.bin,ebbefc90883a56cc3090c294a245bf22,https://www.dropbox.com/s/5z890kpowgeftk4/barranquilla.bin.zip?dl=0
data/input/raw_maps/caphill.bin,39203345538e171af64bd4715df17b6e,https://www.dropbox.com/s/vybo4owf8pzuita/caphill.bin.zip?dl=0 data/input/raw_maps/caphill.bin,74863fcfb91fa97131bf3e6652c161cd,https://www.dropbox.com/s/vybo4owf8pzuita/caphill.bin.zip?dl=0
data/input/raw_maps/downtown.bin,6de1dcd371c88a3356c91008ae2bd76a,https://www.dropbox.com/s/ntqzttf25037fty/downtown.bin.zip?dl=0 data/input/raw_maps/downtown.bin,7dab9337ce4a49ab455622b65632da46,https://www.dropbox.com/s/ntqzttf25037fty/downtown.bin.zip?dl=0
data/input/raw_maps/downtown_atx.bin,d4f6ece8ef35c594c794928d651c5916,https://www.dropbox.com/s/0cs55y1jcmm2alk/downtown_atx.bin.zip?dl=0 data/input/raw_maps/downtown_atx.bin,b8bf1101d55440ccdaf6b4755a5d5701,https://www.dropbox.com/s/0cs55y1jcmm2alk/downtown_atx.bin.zip?dl=0
data/input/raw_maps/downtown_la.bin,f7ea2e3cfcd688e0effae80ec9440af0,https://www.dropbox.com/s/ca7eoxem5t9y99g/downtown_la.bin.zip?dl=0 data/input/raw_maps/downtown_la.bin,b6cd5f18c2e942413b0833476e5b4c85,https://www.dropbox.com/s/ca7eoxem5t9y99g/downtown_la.bin.zip?dl=0
data/input/raw_maps/huge_austin.bin,b50223a417508afb924252ae3ecd24ad,https://www.dropbox.com/s/we0765ym7dlcsl1/huge_austin.bin.zip?dl=0 data/input/raw_maps/huge_austin.bin,5dbd9efb15a39432b28dc6fe9003cea4,https://www.dropbox.com/s/we0765ym7dlcsl1/huge_austin.bin.zip?dl=0
data/input/raw_maps/huge_seattle.bin,15f300c8e5b0f72a1f9bf517ed438614,https://www.dropbox.com/s/jcssts861uaovva/huge_seattle.bin.zip?dl=0 data/input/raw_maps/huge_seattle.bin,eef6e00b61d85d068224c9c7e7ef1342,https://www.dropbox.com/s/jcssts861uaovva/huge_seattle.bin.zip?dl=0
data/input/raw_maps/intl_district.bin,cb3878b8911e90f6a8da72817a0ba673,https://www.dropbox.com/s/yopzq58r9t4y93v/intl_district.bin.zip?dl=0 data/input/raw_maps/intl_district.bin,715f1ed0da26cf67cf96b8516d831ac0,https://www.dropbox.com/s/yopzq58r9t4y93v/intl_district.bin.zip?dl=0
data/input/raw_maps/lakeslice.bin,93734afc9a8a8b0528983e249aabe915,https://www.dropbox.com/s/4nmdtw0mgqe7tyg/lakeslice.bin.zip?dl=0 data/input/raw_maps/lakeslice.bin,6e442fa5014d19375dc74569d5c87a91,https://www.dropbox.com/s/4nmdtw0mgqe7tyg/lakeslice.bin.zip?dl=0
data/input/raw_maps/montlake.bin,65524b250c114e9445274b488111ed19,https://www.dropbox.com/s/qk8rhwr6vdm79vz/montlake.bin.zip?dl=0 data/input/raw_maps/montlake.bin,0072937ea80224c2b8b545f9d662fb33,https://www.dropbox.com/s/qk8rhwr6vdm79vz/montlake.bin.zip?dl=0
data/input/screenshots/lakeslice/01x01_i328.gif,40b1e76bb29e46823fa52186c891578b,https://www.dropbox.com/s/64ycqgm8dvta506/01x01_i328.gif.zip?dl=0 data/input/screenshots/lakeslice/01x01_i328.gif,40b1e76bb29e46823fa52186c891578b,https://www.dropbox.com/s/64ycqgm8dvta506/01x01_i328.gif.zip?dl=0
data/input/screenshots/lakeslice/01x02_i163.gif,b5eee977fcd6e0c96654bcd18628f6b0,https://www.dropbox.com/s/6zebcdhbeirab49/01x02_i163.gif.zip?dl=0 data/input/screenshots/lakeslice/01x02_i163.gif,b5eee977fcd6e0c96654bcd18628f6b0,https://www.dropbox.com/s/6zebcdhbeirab49/01x02_i163.gif.zip?dl=0
data/input/screenshots/lakeslice/01x03_i1.gif,3a161351c6d270dd9e109b620eb476f6,https://www.dropbox.com/s/qn65mm834k8w1jr/01x03_i1.gif.zip?dl=0 data/input/screenshots/lakeslice/01x03_i1.gif,3a161351c6d270dd9e109b620eb476f6,https://www.dropbox.com/s/qn65mm834k8w1jr/01x03_i1.gif.zip?dl=0
@ -180,18 +180,18 @@ data/input/seattle/parcels_urbansim.txt,db63d7d606e8702d12f9399e87e6a00f,https:/
data/input/seattle/popdat.bin,7cbf604cb6d080292a5e69fdf0caf3b3,https://www.dropbox.com/s/wrpji7e14rdwszs/popdat.bin.zip?dl=0 data/input/seattle/popdat.bin,7cbf604cb6d080292a5e69fdf0caf3b3,https://www.dropbox.com/s/wrpji7e14rdwszs/popdat.bin.zip?dl=0
data/input/seattle/sidewalks.bin,129b460f56f5eb41cab3bfd70fb5fde9,https://www.dropbox.com/s/ma9bmisijc7v7xa/sidewalks.bin.zip?dl=0 data/input/seattle/sidewalks.bin,129b460f56f5eb41cab3bfd70fb5fde9,https://www.dropbox.com/s/ma9bmisijc7v7xa/sidewalks.bin.zip?dl=0
data/input/seattle/trips_2014.csv,d4a8e733045b28c0385fb81359d6df03,https://www.dropbox.com/s/5ppravwmk6bf20d/trips_2014.csv.zip?dl=0 data/input/seattle/trips_2014.csv,d4a8e733045b28c0385fb81359d6df03,https://www.dropbox.com/s/5ppravwmk6bf20d/trips_2014.csv.zip?dl=0
data/system/maps/23rd.bin,a9aaaaea906cc620f1710be5dc316a80,https://www.dropbox.com/s/wjl45codk6rqfg4/23rd.bin.zip?dl=0 data/system/maps/23rd.bin,631d7231637dd5503d0152e0d9ed195a,https://www.dropbox.com/s/wjl45codk6rqfg4/23rd.bin.zip?dl=0
data/system/maps/ballard.bin,32585d4a4d10b56e5d03b7bfd997e270,https://www.dropbox.com/s/u4rvz50she3yrk0/ballard.bin.zip?dl=0 data/system/maps/ballard.bin,2a4babaeccfcc0d81420999f60f36793,https://www.dropbox.com/s/u4rvz50she3yrk0/ballard.bin.zip?dl=0
data/system/maps/barranquilla.bin,2d62709cf5df6b4b0a51f1d10cf0d14f,https://www.dropbox.com/s/iuvggdfr16u6luw/barranquilla.bin.zip?dl=0 data/system/maps/barranquilla.bin,d22d70bf19aef241727aff538a6fa0c0,https://www.dropbox.com/s/iuvggdfr16u6luw/barranquilla.bin.zip?dl=0
data/system/maps/caphill.bin,868672d2b73b55c945730528b058022e,https://www.dropbox.com/s/bh20pn3wxygetw8/caphill.bin.zip?dl=0 data/system/maps/caphill.bin,e640140907d520b44d4d6a93591665cb,https://www.dropbox.com/s/bh20pn3wxygetw8/caphill.bin.zip?dl=0
data/system/maps/downtown.bin,32204ce12eecd28829f4951c1b77ae16,https://www.dropbox.com/s/4do5cg4vc17lafo/downtown.bin.zip?dl=0 data/system/maps/downtown.bin,550a14c556e75857c6ae5e3b6aa70a7b,https://www.dropbox.com/s/4do5cg4vc17lafo/downtown.bin.zip?dl=0
data/system/maps/downtown_atx.bin,94d44bfd4c5e2431c7f8555943e70709,https://www.dropbox.com/s/5avnbkd4oxby2hs/downtown_atx.bin.zip?dl=0 data/system/maps/downtown_atx.bin,3392097c04d0d0de730f02537a4c6ba8,https://www.dropbox.com/s/5avnbkd4oxby2hs/downtown_atx.bin.zip?dl=0
data/system/maps/downtown_la.bin,2857ce1b2e3b233323a04d459d533024,https://www.dropbox.com/s/gkcl982cj6kxvrz/downtown_la.bin.zip?dl=0 data/system/maps/downtown_la.bin,ca28f5a023357bb210d065d378cb63ad,https://www.dropbox.com/s/gkcl982cj6kxvrz/downtown_la.bin.zip?dl=0
data/system/maps/huge_austin.bin,4961886805fc8a5576a37cffc6adc9be,https://www.dropbox.com/s/khy0m6v9yt0gjnt/huge_austin.bin.zip?dl=0 data/system/maps/huge_austin.bin,f1104a222aab850ea2ed5a1811dc5f3e,https://www.dropbox.com/s/khy0m6v9yt0gjnt/huge_austin.bin.zip?dl=0
data/system/maps/huge_seattle.bin,e40060350ec5dcfc1049f00d3c73691c,https://www.dropbox.com/s/btvr3qajshnivhb/huge_seattle.bin.zip?dl=0 data/system/maps/huge_seattle.bin,35c210520ac854f533604b9e13d7eba9,https://www.dropbox.com/s/btvr3qajshnivhb/huge_seattle.bin.zip?dl=0
data/system/maps/intl_district.bin,919e9d01d680ffa731b771890ba8de26,https://www.dropbox.com/s/fohppni52ekc5l3/intl_district.bin.zip?dl=0 data/system/maps/intl_district.bin,e07da5b9bfa838ff32c5613ede173b61,https://www.dropbox.com/s/fohppni52ekc5l3/intl_district.bin.zip?dl=0
data/system/maps/lakeslice.bin,d92351e6246bf8052baffd4b30ab8959,https://www.dropbox.com/s/99zi0gcbyvqrkud/lakeslice.bin.zip?dl=0 data/system/maps/lakeslice.bin,32bd8e09b6a9c830e7155fc302a9acaf,https://www.dropbox.com/s/99zi0gcbyvqrkud/lakeslice.bin.zip?dl=0
data/system/maps/montlake.bin,930d7b8add199635e19a8b701a3d3d8a,https://www.dropbox.com/s/zvhm2j5lavixxcr/montlake.bin.zip?dl=0 data/system/maps/montlake.bin,ec2cfa8250d4534aa1d8ec22030d9915,https://www.dropbox.com/s/zvhm2j5lavixxcr/montlake.bin.zip?dl=0
data/system/prebaked_results/montlake/car vs bike contention.bin,84bf817c20e62c03465be72bea25b320,https://www.dropbox.com/s/jefg0ikjy9dsrdd/car%20vs%20bike%20contention.bin.zip?dl=0 data/system/prebaked_results/montlake/car vs bike contention.bin,84bf817c20e62c03465be72bea25b320,https://www.dropbox.com/s/jefg0ikjy9dsrdd/car%20vs%20bike%20contention.bin.zip?dl=0
data/system/prebaked_results/montlake/weekday.bin,18272ae5ec70de3a61826a7497174bf0,https://www.dropbox.com/s/1aq7n9ow8tfqb5d/weekday.bin.zip?dl=0 data/system/prebaked_results/montlake/weekday.bin,18272ae5ec70de3a61826a7497174bf0,https://www.dropbox.com/s/1aq7n9ow8tfqb5d/weekday.bin.zip?dl=0
data/system/scenarios/23rd/weekday.bin,d23f322d55424bdc3da93452d71a1683,https://www.dropbox.com/s/tgo7gztfodbljyi/weekday.bin.zip?dl=0 data/system/scenarios/23rd/weekday.bin,d23f322d55424bdc3da93452d71a1683,https://www.dropbox.com/s/tgo7gztfodbljyi/weekday.bin.zip?dl=0

View File

@ -893,8 +893,8 @@ fn make_half_map(
.turn_restrictions .turn_restrictions
.iter() .iter()
.filter_map(|(rt, to)| { .filter_map(|(rt, to)| {
if let Some(t) = road_id_mapping.get(to) { if let Some(to) = road_id_mapping.get(to) {
Some((*rt, *t)) Some((*rt, *to))
} else { } else {
timer.warn(format!( timer.warn(format!(
"Turn restriction from {} points to invalid dst {}", "Turn restriction from {} points to invalid dst {}",
@ -904,6 +904,23 @@ fn make_half_map(
} }
}) })
.collect(), .collect(),
complicated_turn_restrictions: raw.roads[&r.id]
.complicated_turn_restrictions
.iter()
.filter_map(|(via, to)| {
if let (Some(via), Some(to)) =
(road_id_mapping.get(via), road_id_mapping.get(to))
{
Some((*via, *to))
} else {
timer.warn(format!(
"Complicated turn restriction from {} has invalid via {} or dst {}",
r.id, via, to
));
None
}
})
.collect(),
orig_id: r.id, orig_id: r.id,
children_forwards: Vec::new(), children_forwards: Vec::new(),
children_backwards: Vec::new(), children_backwards: Vec::new(),

View File

@ -103,7 +103,10 @@ impl Path {
pub(crate) fn new(map: &Map, steps: Vec<PathStep>, end_dist: Distance) -> Path { pub(crate) fn new(map: &Map, steps: Vec<PathStep>, end_dist: Distance) -> Path {
// Haven't seen problems here in a very long time. Noticeably saves some time to skip. // Haven't seen problems here in a very long time. Noticeably saves some time to skip.
if false { if false {
validate(map, &steps); validate_continuity(map, &steps);
}
if false {
validate_restrictions(map, &steps);
} }
// Slightly expensive, but the contraction hierarchy weights aren't distances. // Slightly expensive, but the contraction hierarchy weights aren't distances.
let mut total_length = Distance::ZERO; let mut total_length = Distance::ZERO;
@ -399,7 +402,7 @@ impl fmt::Display for PathRequest {
} }
} }
fn validate(map: &Map, steps: &Vec<PathStep>) { fn validate_continuity(map: &Map, steps: &Vec<PathStep>) {
if steps.is_empty() { if steps.is_empty() {
panic!("Empty Path"); panic!("Empty Path");
} }
@ -442,6 +445,27 @@ fn validate(map: &Map, steps: &Vec<PathStep>) {
} }
} }
fn validate_restrictions(map: &Map, steps: &Vec<PathStep>) {
for triple in steps.windows(5) {
if let (PathStep::Lane(l1), PathStep::Lane(l2), PathStep::Lane(l3)) =
(triple[0], triple[2], triple[4])
{
let from = map.get_parent(l1);
let via = map.get_l(l2).parent;
let to = map.get_l(l3).parent;
for (dont_via, dont_to) in &from.complicated_turn_restrictions {
if via == *dont_via && to == *dont_to {
panic!(
"Some path does illegal uber-turn: {} -> {} -> {}",
l1, l2, l3
);
}
}
}
}
}
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct Pathfinder { pub struct Pathfinder {
car_graph: VehiclePathfinder, car_graph: VehiclePathfinder,

View File

@ -28,9 +28,6 @@ pub struct RawMap {
pub buildings: BTreeMap<OriginalBuilding, RawBuilding>, pub buildings: BTreeMap<OriginalBuilding, RawBuilding>,
pub bus_routes: Vec<Route>, pub bus_routes: Vec<Route>,
pub areas: Vec<RawArea>, pub areas: Vec<RawArea>,
// (from, via, to, type). For turn restrictions where 'via' is an entire road.
pub complicated_turn_restrictions:
Vec<(OriginalRoad, OriginalRoad, OriginalRoad, RestrictionType)>,
pub boundary_polygon: Polygon, pub boundary_polygon: Polygon,
pub gps_bounds: GPSBounds, pub gps_bounds: GPSBounds,
@ -100,7 +97,6 @@ impl RawMap {
buildings: BTreeMap::new(), buildings: BTreeMap::new(),
bus_routes: Vec::new(), bus_routes: Vec::new(),
areas: Vec::new(), areas: Vec::new(),
complicated_turn_restrictions: Vec::new(),
// Some nonsense thing // Some nonsense thing
boundary_polygon: Polygon::rectangle(1.0, 1.0), boundary_polygon: Polygon::rectangle(1.0, 1.0),
gps_bounds: GPSBounds::new(), gps_bounds: GPSBounds::new(),
@ -548,6 +544,8 @@ pub struct RawRoad {
pub center_points: Vec<Pt2D>, pub center_points: Vec<Pt2D>,
pub osm_tags: BTreeMap<String, String>, pub osm_tags: BTreeMap<String, String>,
pub turn_restrictions: Vec<(RestrictionType, OriginalRoad)>, pub turn_restrictions: Vec<(RestrictionType, OriginalRoad)>,
// (via, to). For turn restrictions where 'via' is an entire road. Only BanTurns.
pub complicated_turn_restrictions: Vec<(OriginalRoad, OriginalRoad)>,
} }
impl RawRoad { impl RawRoad {

View File

@ -94,6 +94,8 @@ pub struct Road {
pub osm_tags: BTreeMap<String, String>, pub osm_tags: BTreeMap<String, String>,
// self is 'from' // self is 'from'
pub turn_restrictions: Vec<(RestrictionType, RoadID)>, pub turn_restrictions: Vec<(RestrictionType, RoadID)>,
// self is 'from'. (via, to). Only BanTurns.
pub complicated_turn_restrictions: Vec<(RoadID, RoadID)>,
pub orig_id: OriginalRoad, pub orig_id: OriginalRoad,
// Invariant: A road must contain at least one child // Invariant: A road must contain at least one child