1 use crate::raw::{DrivingSide, OriginalRoad, RawMap}; 2 use crate::{ 3 osm, Area, AreaID, Building, BuildingID, BuildingType, BusRoute, BusRouteID, BusStop, 4 BusStopID, ControlStopSign, ControlTrafficSignal, Intersection, IntersectionID, Lane, LaneID, 5 LaneType, Map, MapEdits, MovementID, OffstreetParking, ParkingLot, ParkingLotID, Path, 6 PathConstraints, PathRequest, Pathfinder, Position, Road, RoadID, Turn, TurnID, TurnType, Zone, 7 }; 8 use abstutil::Timer; 9 use geom::{Angle, Bounds, Distance, GPSBounds, Line, PolyLine, Polygon, Pt2D, Ring, Time}; 10 use serde::{Deserialize, Serialize}; 11 use std::collections::{BTreeMap, BTreeSet, HashSet, VecDeque}; 12 13 #[derive(Clone, Debug, Serialize, Deserialize)] 14 pub struct MapConfig { 15 // If true, driving happens on the right side of the road (USA). If false, on the left 16 // (Australia). 17 pub driving_side: DrivingSide, 18 pub bikes_can_use_bus_lanes: bool, 19 } 20 21 impl Map { new(path: String, timer: &mut Timer) -> Map22 pub fn new(path: String, timer: &mut Timer) -> Map { 23 if path.starts_with(&abstutil::path_all_maps()) { 24 match abstutil::maybe_read_binary(path.clone(), timer) { 25 Ok(map) => { 26 let map: Map = map; 27 28 if false { 29 use abstutil::{prettyprint_usize, serialized_size_bytes}; 30 println!( 31 "- {} roads: {} bytes", 32 prettyprint_usize(map.roads.len()), 33 prettyprint_usize(serialized_size_bytes(&map.roads)) 34 ); 35 println!( 36 "- {} lanes: {} bytes", 37 prettyprint_usize(map.lanes.len()), 38 prettyprint_usize(serialized_size_bytes(&map.lanes)) 39 ); 40 println!( 41 "- {} intersections: {} bytes", 42 prettyprint_usize(map.intersections.len()), 43 prettyprint_usize(serialized_size_bytes(&map.intersections)) 44 ); 45 println!( 46 "- {} turns: {} bytes", 47 prettyprint_usize(map.turns.len()), 48 prettyprint_usize(serialized_size_bytes(&map.turns)) 49 ); 50 println!( 51 "- {} buildings: {} bytes", 52 prettyprint_usize(map.buildings.len()), 53 prettyprint_usize(serialized_size_bytes(&map.buildings)) 54 ); 55 println!( 56 "- {} areas: {} bytes", 57 prettyprint_usize(map.areas.len()), 58 prettyprint_usize(serialized_size_bytes(&map.areas)) 59 ); 60 println!( 61 "- {} parking lots: {} bytes", 62 prettyprint_usize(map.parking_lots.len()), 63 prettyprint_usize(serialized_size_bytes(&map.parking_lots)) 64 ); 65 println!( 66 "- {} zones: {} bytes", 67 prettyprint_usize(map.zones.len()), 68 prettyprint_usize(serialized_size_bytes(&map.zones)) 69 ); 70 // This is the partridge in the pear tree, I suppose 71 println!( 72 "- pathfinder: {} bytes", 73 prettyprint_usize(serialized_size_bytes(&map.pathfinder)) 74 ); 75 } 76 77 return map; 78 } 79 Err(err) => { 80 Map::corrupt_err(path, err); 81 std::process::exit(1); 82 } 83 } 84 } 85 86 let raw: RawMap = if path.starts_with(&abstutil::path_all_raw_maps()) { 87 abstutil::read_binary(path, timer) 88 } else { 89 // Synthetic 90 abstutil::read_json(path, timer) 91 }; 92 Map::create_from_raw(raw, true, timer) 93 } 94 corrupt_err(path: String, err: std::io::Error)95 pub fn corrupt_err(path: String, err: std::io::Error) { 96 println!("\nError loading {}: {}\n", path, err); 97 if err.to_string().contains("No such file") { 98 println!( 99 "{} is missing. You may need to do: cargo run --bin updater", 100 path 101 ); 102 } else { 103 println!( 104 "{} is out-of-date. You may need to update your build (git pull) or download new \ 105 data (cargo run --bin updater). If this is a custom map, you need to import it \ 106 again.", 107 path 108 ); 109 } 110 println!( 111 "Check https://dabreegster.github.io/abstreet/howto/dev.html and file an issue if you \ 112 have trouble." 113 ); 114 } 115 116 // Just for temporary std::mem::replace tricks. blank() -> Map117 pub fn blank() -> Map { 118 Map { 119 roads: Vec::new(), 120 lanes: Vec::new(), 121 intersections: Vec::new(), 122 turns: BTreeMap::new(), 123 buildings: Vec::new(), 124 bus_stops: BTreeMap::new(), 125 bus_routes: Vec::new(), 126 areas: Vec::new(), 127 parking_lots: Vec::new(), 128 zones: Vec::new(), 129 boundary_polygon: Ring::must_new(vec![ 130 Pt2D::new(0.0, 0.0), 131 Pt2D::new(1.0, 0.0), 132 Pt2D::new(1.0, 1.0), 133 Pt2D::new(0.0, 0.0), 134 ]) 135 .to_polygon(), 136 stop_signs: BTreeMap::new(), 137 traffic_signals: BTreeMap::new(), 138 gps_bounds: GPSBounds::new(), 139 bounds: Bounds::new(), 140 config: MapConfig { 141 driving_side: DrivingSide::Right, 142 bikes_can_use_bus_lanes: true, 143 }, 144 pathfinder: Pathfinder::Dijkstra, 145 pathfinder_dirty: false, 146 city_name: "blank city".to_string(), 147 name: "blank".to_string(), 148 edits: MapEdits::new(), 149 } 150 } 151 all_roads(&self) -> &Vec<Road>152 pub fn all_roads(&self) -> &Vec<Road> { 153 &self.roads 154 } 155 all_lanes(&self) -> &Vec<Lane>156 pub fn all_lanes(&self) -> &Vec<Lane> { 157 &self.lanes 158 } 159 all_intersections(&self) -> &Vec<Intersection>160 pub fn all_intersections(&self) -> &Vec<Intersection> { 161 &self.intersections 162 } 163 all_turns(&self) -> &BTreeMap<TurnID, Turn>164 pub fn all_turns(&self) -> &BTreeMap<TurnID, Turn> { 165 &self.turns 166 } 167 all_buildings(&self) -> &Vec<Building>168 pub fn all_buildings(&self) -> &Vec<Building> { 169 &self.buildings 170 } 171 all_areas(&self) -> &Vec<Area>172 pub fn all_areas(&self) -> &Vec<Area> { 173 &self.areas 174 } 175 all_parking_lots(&self) -> &Vec<ParkingLot>176 pub fn all_parking_lots(&self) -> &Vec<ParkingLot> { 177 &self.parking_lots 178 } 179 all_zones(&self) -> &Vec<Zone>180 pub fn all_zones(&self) -> &Vec<Zone> { 181 &self.zones 182 } 183 maybe_get_r(&self, id: RoadID) -> Option<&Road>184 pub fn maybe_get_r(&self, id: RoadID) -> Option<&Road> { 185 self.roads.get(id.0) 186 } 187 maybe_get_l(&self, id: LaneID) -> Option<&Lane>188 pub fn maybe_get_l(&self, id: LaneID) -> Option<&Lane> { 189 self.lanes.get(id.0) 190 } 191 maybe_get_i(&self, id: IntersectionID) -> Option<&Intersection>192 pub fn maybe_get_i(&self, id: IntersectionID) -> Option<&Intersection> { 193 self.intersections.get(id.0) 194 } 195 maybe_get_t(&self, id: TurnID) -> Option<&Turn>196 pub fn maybe_get_t(&self, id: TurnID) -> Option<&Turn> { 197 self.turns.get(&id) 198 } 199 maybe_get_b(&self, id: BuildingID) -> Option<&Building>200 pub fn maybe_get_b(&self, id: BuildingID) -> Option<&Building> { 201 self.buildings.get(id.0) 202 } 203 maybe_get_pl(&self, id: ParkingLotID) -> Option<&ParkingLot>204 pub fn maybe_get_pl(&self, id: ParkingLotID) -> Option<&ParkingLot> { 205 self.parking_lots.get(id.0) 206 } 207 maybe_get_a(&self, id: AreaID) -> Option<&Area>208 pub fn maybe_get_a(&self, id: AreaID) -> Option<&Area> { 209 self.areas.get(id.0) 210 } 211 maybe_get_bs(&self, id: BusStopID) -> Option<&BusStop>212 pub fn maybe_get_bs(&self, id: BusStopID) -> Option<&BusStop> { 213 self.bus_stops.get(&id) 214 } 215 maybe_get_stop_sign(&self, id: IntersectionID) -> Option<&ControlStopSign>216 pub fn maybe_get_stop_sign(&self, id: IntersectionID) -> Option<&ControlStopSign> { 217 self.stop_signs.get(&id) 218 } 219 maybe_get_traffic_signal(&self, id: IntersectionID) -> Option<&ControlTrafficSignal>220 pub fn maybe_get_traffic_signal(&self, id: IntersectionID) -> Option<&ControlTrafficSignal> { 221 self.traffic_signals.get(&id) 222 } 223 maybe_get_br(&self, route: BusRouteID) -> Option<&BusRoute>224 pub fn maybe_get_br(&self, route: BusRouteID) -> Option<&BusRoute> { 225 self.bus_routes.get(route.0) 226 } 227 get_r(&self, id: RoadID) -> &Road228 pub fn get_r(&self, id: RoadID) -> &Road { 229 &self.roads[id.0] 230 } 231 get_l(&self, id: LaneID) -> &Lane232 pub fn get_l(&self, id: LaneID) -> &Lane { 233 &self.lanes[id.0] 234 } 235 get_i(&self, id: IntersectionID) -> &Intersection236 pub fn get_i(&self, id: IntersectionID) -> &Intersection { 237 &self.intersections[id.0] 238 } 239 get_t(&self, id: TurnID) -> &Turn240 pub fn get_t(&self, id: TurnID) -> &Turn { 241 // When pathfinding breaks, seeing this TurnID is useful. 242 if let Some(ref t) = self.turns.get(&id) { 243 t 244 } else { 245 panic!("Can't get_t({})", id); 246 } 247 } 248 get_b(&self, id: BuildingID) -> &Building249 pub fn get_b(&self, id: BuildingID) -> &Building { 250 &self.buildings[id.0] 251 } 252 get_a(&self, id: AreaID) -> &Area253 pub fn get_a(&self, id: AreaID) -> &Area { 254 &self.areas[id.0] 255 } 256 get_pl(&self, id: ParkingLotID) -> &ParkingLot257 pub fn get_pl(&self, id: ParkingLotID) -> &ParkingLot { 258 &self.parking_lots[id.0] 259 } 260 get_stop_sign(&self, id: IntersectionID) -> &ControlStopSign261 pub fn get_stop_sign(&self, id: IntersectionID) -> &ControlStopSign { 262 &self.stop_signs[&id] 263 } 264 get_traffic_signal(&self, id: IntersectionID) -> &ControlTrafficSignal265 pub fn get_traffic_signal(&self, id: IntersectionID) -> &ControlTrafficSignal { 266 &self.traffic_signals[&id] 267 } 268 269 // All these helpers should take IDs and return objects. 270 get_turns_in_intersection<'a>( &'a self, id: IntersectionID, ) -> impl Iterator<Item = &'a Turn> + 'a271 pub fn get_turns_in_intersection<'a>( 272 &'a self, 273 id: IntersectionID, 274 ) -> impl Iterator<Item = &'a Turn> + 'a { 275 self.get_i(id).turns.iter().map(move |t| self.get_t(*t)) 276 } 277 278 // The turns may belong to two different intersections! get_turns_from_lane(&self, l: LaneID) -> Vec<&Turn>279 pub fn get_turns_from_lane(&self, l: LaneID) -> Vec<&Turn> { 280 let lane = self.get_l(l); 281 let mut turns: Vec<&Turn> = self 282 .get_i(lane.dst_i) 283 .turns 284 .iter() 285 .map(|t| self.get_t(*t)) 286 .filter(|t| t.id.src == l) 287 .collect(); 288 // Sidewalks/shoulders are bidirectional 289 if lane.is_walkable() { 290 for t in &self.get_i(lane.src_i).turns { 291 if t.src == l { 292 turns.push(self.get_t(*t)); 293 } 294 } 295 } 296 turns 297 } 298 get_turns_to_lane(&self, l: LaneID) -> Vec<&Turn>299 pub fn get_turns_to_lane(&self, l: LaneID) -> Vec<&Turn> { 300 let lane = self.get_l(l); 301 let mut turns: Vec<&Turn> = self 302 .get_i(lane.src_i) 303 .turns 304 .iter() 305 .map(|t| self.get_t(*t)) 306 .filter(|t| t.id.dst == l) 307 .collect(); 308 // Sidewalks/shoulders are bidirectional 309 if lane.is_walkable() { 310 for t in &self.get_i(lane.dst_i).turns { 311 if t.dst == l { 312 turns.push(self.get_t(*t)); 313 } 314 } 315 } 316 turns 317 } 318 get_turn_between( &self, from: LaneID, to: LaneID, parent: IntersectionID, ) -> Option<TurnID>319 pub fn get_turn_between( 320 &self, 321 from: LaneID, 322 to: LaneID, 323 parent: IntersectionID, 324 ) -> Option<TurnID> { 325 self.get_i(parent) 326 .turns 327 .iter() 328 .find(|t| t.src == from && t.dst == to) 329 .cloned() 330 } 331 get_next_turns_and_lanes<'a>( &'a self, from: LaneID, parent: IntersectionID, ) -> impl Iterator<Item = (&'a Turn, &'a Lane)> + 'a332 pub fn get_next_turns_and_lanes<'a>( 333 &'a self, 334 from: LaneID, 335 parent: IntersectionID, 336 ) -> impl Iterator<Item = (&'a Turn, &'a Lane)> + 'a { 337 self.get_i(parent) 338 .turns 339 .iter() 340 .filter(move |t| t.src == from) 341 .map(move |t| (self.get_t(*t), self.get_l(t.dst))) 342 } 343 get_turns_for(&self, from: LaneID, constraints: PathConstraints) -> Vec<&Turn>344 pub fn get_turns_for(&self, from: LaneID, constraints: PathConstraints) -> Vec<&Turn> { 345 let mut turns: Vec<&Turn> = self 346 .get_next_turns_and_lanes(from, self.get_l(from).dst_i) 347 .into_iter() 348 .filter(|(_, l)| constraints.can_use(l, self)) 349 .map(|(t, _)| t) 350 .collect(); 351 // Sidewalks are bidirectional 352 if constraints == PathConstraints::Pedestrian { 353 turns.extend( 354 self.get_next_turns_and_lanes(from, self.get_l(from).src_i) 355 .into_iter() 356 .filter(|(_, l)| constraints.can_use(l, self)) 357 .map(|(t, _)| t), 358 ); 359 } 360 turns 361 } 362 363 // These come back sorted get_next_roads(&self, from: RoadID) -> impl Iterator<Item = RoadID>364 pub fn get_next_roads(&self, from: RoadID) -> impl Iterator<Item = RoadID> { 365 let mut roads: BTreeSet<RoadID> = BTreeSet::new(); 366 367 let r = self.get_r(from); 368 for id in vec![r.src_i, r.dst_i].into_iter() { 369 roads.extend(self.get_i(id).roads.clone()); 370 } 371 372 roads.into_iter() 373 } 374 get_parent(&self, id: LaneID) -> &Road375 pub fn get_parent(&self, id: LaneID) -> &Road { 376 let l = self.get_l(id); 377 self.get_r(l.parent) 378 } 379 get_gps_bounds(&self) -> &GPSBounds380 pub fn get_gps_bounds(&self) -> &GPSBounds { 381 &self.gps_bounds 382 } 383 get_bounds(&self) -> &Bounds384 pub fn get_bounds(&self) -> &Bounds { 385 &self.bounds 386 } 387 get_city_name(&self) -> &String388 pub fn get_city_name(&self) -> &String { 389 &self.city_name 390 } 391 get_name(&self) -> &String392 pub fn get_name(&self) -> &String { 393 &self.name 394 } 395 all_bus_stops(&self) -> &BTreeMap<BusStopID, BusStop>396 pub fn all_bus_stops(&self) -> &BTreeMap<BusStopID, BusStop> { 397 &self.bus_stops 398 } 399 get_bs(&self, stop: BusStopID) -> &BusStop400 pub fn get_bs(&self, stop: BusStopID) -> &BusStop { 401 &self.bus_stops[&stop] 402 } 403 get_br(&self, route: BusRouteID) -> &BusRoute404 pub fn get_br(&self, route: BusRouteID) -> &BusRoute { 405 &self.bus_routes[route.0] 406 } 407 all_bus_routes(&self) -> &Vec<BusRoute>408 pub fn all_bus_routes(&self) -> &Vec<BusRoute> { 409 &self.bus_routes 410 } 411 get_bus_route(&self, name: &str) -> Option<&BusRoute>412 pub fn get_bus_route(&self, name: &str) -> Option<&BusRoute> { 413 self.bus_routes.iter().find(|r| r.full_name == name) 414 } 415 get_routes_serving_stop(&self, stop: BusStopID) -> Vec<&BusRoute>416 pub fn get_routes_serving_stop(&self, stop: BusStopID) -> Vec<&BusRoute> { 417 let mut routes = Vec::new(); 418 for r in &self.bus_routes { 419 if r.stops.contains(&stop) { 420 routes.push(r); 421 } 422 } 423 routes 424 } 425 building_to_road(&self, id: BuildingID) -> &Road426 pub fn building_to_road(&self, id: BuildingID) -> &Road { 427 self.get_parent(self.get_b(id).sidewalk()) 428 } 429 430 // This and all_outgoing_borders are expensive to constantly repeat all_incoming_borders(&self) -> Vec<&Intersection>431 pub fn all_incoming_borders(&self) -> Vec<&Intersection> { 432 let mut result: Vec<&Intersection> = Vec::new(); 433 for i in &self.intersections { 434 if i.is_incoming_border() { 435 result.push(i); 436 } 437 } 438 result 439 } 440 all_outgoing_borders(&self) -> Vec<&Intersection>441 pub fn all_outgoing_borders(&self) -> Vec<&Intersection> { 442 let mut result: Vec<&Intersection> = Vec::new(); 443 for i in &self.intersections { 444 if i.is_outgoing_border() { 445 result.push(i); 446 } 447 } 448 result 449 } 450 unsaved_edits(&self) -> bool451 pub fn unsaved_edits(&self) -> bool { 452 self.edits.edits_name == "untitled edits" && !self.edits.commands.is_empty() 453 } 454 save(&self)455 pub fn save(&self) { 456 assert_eq!(self.edits.edits_name, "untitled edits"); 457 assert!(self.edits.commands.is_empty()); 458 assert!(!self.pathfinder_dirty); 459 abstutil::write_binary(abstutil::path_map(&self.name), self); 460 } 461 462 // Cars trying to park near this building should head for the driving lane returned here, then 463 // start their search. Some parking lanes are connected to driving lanes that're "parking 464 // blackholes" -- if there are no free spots on that lane, then the roads force cars to a 465 // border. 466 // TODO Making driving_connection do this. find_driving_lane_near_building(&self, b: BuildingID) -> LaneID467 pub fn find_driving_lane_near_building(&self, b: BuildingID) -> LaneID { 468 let sidewalk = self.get_b(b).sidewalk(); 469 if let Some(l) = self.get_parent(sidewalk).find_closest_lane( 470 sidewalk, 471 |l| PathConstraints::Car.can_use(l, self), 472 self, 473 ) { 474 if !self.get_l(l).driving_blackhole { 475 return l; 476 } 477 } 478 479 let mut roads_queue: VecDeque<RoadID> = VecDeque::new(); 480 let mut visited: HashSet<RoadID> = HashSet::new(); 481 { 482 let start = self.building_to_road(b).id; 483 roads_queue.push_back(start); 484 visited.insert(start); 485 } 486 487 loop { 488 if roads_queue.is_empty() { 489 panic!( 490 "Giving up looking for a driving lane near {}, searched {} roads: {:?}", 491 b, 492 visited.len(), 493 visited 494 ); 495 } 496 let r = self.get_r(roads_queue.pop_front().unwrap()); 497 498 for (l, lt) in r 499 .children_forwards() 500 .into_iter() 501 .chain(r.children_backwards().into_iter()) 502 { 503 if lt == LaneType::Driving { 504 if !self.get_l(l).driving_blackhole { 505 return l; 506 } 507 } 508 } 509 510 for next_r in self.get_next_roads(r.id).into_iter() { 511 if !visited.contains(&next_r) { 512 roads_queue.push_back(next_r); 513 visited.insert(next_r); 514 } 515 } 516 } 517 } 518 get_boundary_polygon(&self) -> &Polygon519 pub fn get_boundary_polygon(&self) -> &Polygon { 520 &self.boundary_polygon 521 } 522 pathfind(&self, req: PathRequest) -> Option<Path>523 pub fn pathfind(&self, req: PathRequest) -> Option<Path> { 524 assert!(!self.pathfinder_dirty); 525 self.pathfinder.pathfind(req, self) 526 } 527 should_use_transit( &self, start: Position, end: Position, ) -> Option<(BusStopID, Option<BusStopID>, BusRouteID)>528 pub fn should_use_transit( 529 &self, 530 start: Position, 531 end: Position, 532 ) -> Option<(BusStopID, Option<BusStopID>, BusRouteID)> { 533 self.pathfinder.should_use_transit(self, start, end) 534 } 535 536 // None for SharedSidewalkCorners get_movement(&self, t: TurnID) -> Option<MovementID>537 pub fn get_movement(&self, t: TurnID) -> Option<MovementID> { 538 if let Some(ref ts) = self.maybe_get_traffic_signal(t.parent) { 539 if self.get_t(t).turn_type == TurnType::SharedSidewalkCorner { 540 return None; 541 } 542 for m in ts.movements.values() { 543 if m.members.contains(&t) { 544 return Some(m.id); 545 } 546 } 547 panic!("{} doesn't belong to any movements", t); 548 } 549 None 550 } 551 find_r_by_osm_id(&self, id: OriginalRoad) -> Result<RoadID, String>552 pub fn find_r_by_osm_id(&self, id: OriginalRoad) -> Result<RoadID, String> { 553 for r in self.all_roads() { 554 if r.orig_id == id { 555 return Ok(r.id); 556 } 557 } 558 Err(format!("Can't find {}", id)) 559 } 560 find_i_by_osm_id(&self, id: osm::NodeID) -> Result<IntersectionID, String>561 pub fn find_i_by_osm_id(&self, id: osm::NodeID) -> Result<IntersectionID, String> { 562 for i in self.all_intersections() { 563 if i.orig_id == id { 564 return Ok(i.id); 565 } 566 } 567 Err(format!("Can't find {}", id)) 568 } 569 find_b_by_osm_id(&self, id: osm::OsmID) -> Option<BuildingID>570 pub fn find_b_by_osm_id(&self, id: osm::OsmID) -> Option<BuildingID> { 571 for b in self.all_buildings() { 572 if b.orig_id == id { 573 return Some(b.id); 574 } 575 } 576 None 577 } 578 find_br(&self, id: osm::RelationID) -> Option<BusRouteID>579 pub fn find_br(&self, id: osm::RelationID) -> Option<BusRouteID> { 580 for br in self.all_bus_routes() { 581 if br.osm_rel_id == id { 582 return Some(br.id); 583 } 584 } 585 None 586 } 587 right_shift(&self, pl: PolyLine, width: Distance) -> Result<PolyLine, String>588 pub fn right_shift(&self, pl: PolyLine, width: Distance) -> Result<PolyLine, String> { 589 self.config.driving_side.right_shift(pl, width) 590 } must_right_shift(&self, pl: PolyLine, width: Distance) -> PolyLine591 pub fn must_right_shift(&self, pl: PolyLine, width: Distance) -> PolyLine { 592 self.right_shift(pl, width).unwrap() 593 } left_shift(&self, pl: PolyLine, width: Distance) -> Result<PolyLine, String>594 pub fn left_shift(&self, pl: PolyLine, width: Distance) -> Result<PolyLine, String> { 595 self.config.driving_side.left_shift(pl, width) 596 } must_left_shift(&self, pl: PolyLine, width: Distance) -> PolyLine597 pub fn must_left_shift(&self, pl: PolyLine, width: Distance) -> PolyLine { 598 self.left_shift(pl, width).unwrap() 599 } right_shift_line(&self, line: Line, width: Distance) -> Line600 pub fn right_shift_line(&self, line: Line, width: Distance) -> Line { 601 self.config.driving_side.right_shift_line(line, width) 602 } left_shift_line(&self, line: Line, width: Distance) -> Line603 pub fn left_shift_line(&self, line: Line, width: Distance) -> Line { 604 self.config.driving_side.left_shift_line(line, width) 605 } driving_side_angle(&self, a: Angle) -> Angle606 pub fn driving_side_angle(&self, a: Angle) -> Angle { 607 self.config.driving_side.angle_offset(a) 608 } 609 // Last resort get_driving_side(&self) -> DrivingSide610 pub fn get_driving_side(&self) -> DrivingSide { 611 self.config.driving_side 612 } 613 614 // TODO Sort of a temporary hack hack_override_offstreet_spots(&mut self, spots_per_bldg: usize)615 pub fn hack_override_offstreet_spots(&mut self, spots_per_bldg: usize) { 616 for b in &mut self.buildings { 617 if let OffstreetParking::Private(ref mut num_spots, _) = b.parking { 618 *num_spots = spots_per_bldg; 619 } 620 } 621 } hack_override_offstreet_spots_individ(&mut self, b: BuildingID, spots: usize)622 pub fn hack_override_offstreet_spots_individ(&mut self, b: BuildingID, spots: usize) { 623 let b = &mut self.buildings[b.0]; 624 if let OffstreetParking::Private(ref mut num_spots, _) = b.parking { 625 *num_spots = spots; 626 } 627 } 628 hack_override_bldg_type(&mut self, b: BuildingID, bldg_type: BuildingType)629 pub fn hack_override_bldg_type(&mut self, b: BuildingID, bldg_type: BuildingType) { 630 self.buildings[b.0].bldg_type = bldg_type; 631 } 632 hack_override_orig_spawn_times(&mut self, br: BusRouteID, times: Vec<Time>)633 pub fn hack_override_orig_spawn_times(&mut self, br: BusRouteID, times: Vec<Time>) { 634 self.bus_routes[br.0].orig_spawn_times = times.clone(); 635 self.bus_routes[br.0].spawn_times = times; 636 } 637 get_languages(&self) -> BTreeSet<&str>638 pub fn get_languages(&self) -> BTreeSet<&str> { 639 let mut languages = BTreeSet::new(); 640 for r in self.all_roads() { 641 for key in r.osm_tags.inner().keys() { 642 if let Some(x) = key.strip_prefix("name:") { 643 languages.insert(x); 644 } 645 } 646 } 647 for b in self.all_buildings() { 648 for (names, _) in &b.amenities { 649 for key in names.0.keys() { 650 if let Some(lang) = key { 651 languages.insert(lang); 652 } 653 } 654 } 655 } 656 languages 657 } 658 } 659