1use std::{
4 collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque},
5 sync::{Arc, RwLock},
6};
7
8use anyhow::{Context, Result};
9use petgraph::graphmap::{DiGraphMap, UnGraphMap};
10use popgetter::CensusZone;
11
12use abstio::{CityName, MapName};
13use abstutil::{prettyprint_usize, serialized_size_bytes, MultiMap, Tags, Timer};
14use geom::{
15 Angle, Bounds, Distance, Duration, FindClosest, GPSBounds, LonLat, PolyLine, Polygon, Pt2D,
16 Ring, Time,
17};
18use raw_map::{RawBuilding, RawMap};
19
20use crate::{
21 osm, AmenityType, Area, AreaID, AreaType, Building, BuildingID, BuildingType, CommonEndpoint,
22 CompressedMovementID, ControlStopSign, ControlTrafficSignal, DirectedRoadID, Direction,
23 DrivingSide, ExtraPOI, Intersection, IntersectionControl, IntersectionID, IntersectionKind,
24 Lane, LaneID, LaneType, Map, MapConfig, MapEdits, Movement, MovementID, OffstreetParking,
25 OriginalRoad, ParkingLot, ParkingLotID, Path, PathConstraints, PathRequest, PathV2, Pathfinder,
26 PathfinderCaching, Position, Road, RoadFilter, RoadID, RoutingParams, TransitRoute,
27 TransitRouteID, TransitStop, TransitStopID, Turn, TurnID, TurnType, Zone,
28};
29
30impl Map {
31 pub fn load_synchronously(path: String, timer: &mut Timer) -> Map {
34 if path.contains("/maps/") {
35 match abstio::maybe_read_binary(path.clone(), timer) {
36 Ok(map) => {
37 let mut map: Map = map;
38 map.map_loaded_directly(timer);
39 return map;
40 }
41 Err(err) => {
42 error!("\nError loading {}: {}\n", path, err);
43 if err.to_string().contains("No such file") {
44 error!(
45 "{} is missing. You may need to do: cargo run --bin updater",
46 path
47 );
48 } else {
49 error!(
50 "{} is out-of-date. You may need to update your build (git pull) or \
51 download new data (cargo run --bin updater). If this is a custom \
52 map, you need to import it again.",
53 path
54 );
55 }
56 error!(
57 "Check https://a-b-street.github.io/docs/tech/dev/index.html and file an issue \
58 if you have trouble."
59 );
60
61 std::process::exit(1);
62 }
63 }
64 }
65
66 let raw: RawMap = abstio::read_binary(path, timer);
67 Map::create_from_raw(raw, crate::RawToMapOptions::default(), timer)
68 }
69
70 pub fn map_loaded_directly(&mut self, timer: &mut Timer) {
72 #![allow(clippy::logic_bug)]
73 self.edits = self.new_edits();
76 self.recalculate_road_to_buildings();
77 self.recalculate_all_movements(timer);
78
79 if cfg!(not(target_arch = "wasm32")) && false {
83 let mut costs = vec![
84 (
85 "roads",
86 self.roads.len(),
87 serialized_size_bytes(&self.roads),
88 ),
89 (
90 "intersections",
91 self.intersections.len(),
92 serialized_size_bytes(&self.intersections),
93 ),
94 (
95 "buildings",
96 self.buildings.len(),
97 serialized_size_bytes(&self.buildings),
98 ),
99 (
100 "areas",
101 self.areas.len(),
102 serialized_size_bytes(&self.areas),
103 ),
104 (
105 "parking lots",
106 self.parking_lots.len(),
107 serialized_size_bytes(&self.parking_lots),
108 ),
109 (
110 "zones",
111 self.zones.len(),
112 serialized_size_bytes(&self.zones),
113 ),
114 (
115 "census_zones",
116 self.census_zones.len(),
117 serialized_size_bytes(&self.census_zones),
118 ),
119 (
120 "extra_pois",
121 self.extra_pois.len(),
122 serialized_size_bytes(&self.extra_pois),
123 ),
124 ("pathfinder", 1, serialized_size_bytes(&self.pathfinder)),
125 ];
126 costs.sort_by_key(|(_, _, bytes)| *bytes);
127 costs.reverse();
128
129 info!(
130 "Total map size: {} bytes",
131 prettyprint_usize(serialized_size_bytes(self))
132 );
133 for (name, number, bytes) in costs {
134 info!(
135 "- {} {}: {} bytes",
136 prettyprint_usize(number),
137 name,
138 prettyprint_usize(bytes)
139 );
140 }
141 }
142 }
143
144 pub fn blank() -> Map {
146 Map {
147 roads: Vec::new(),
148 intersections: Vec::new(),
149 intersection_quad_tree: Arc::new(RwLock::new(None)),
150 buildings: Vec::new(),
151 transit_stops: BTreeMap::new(),
152 transit_routes: Vec::new(),
153 areas: Vec::new(),
154 parking_lots: Vec::new(),
155 zones: Vec::new(),
156 census_zones: Vec::new(),
157 extra_pois: Vec::new(),
158 boundary_polygon: Ring::must_new(vec![
159 Pt2D::new(0.0, 0.0),
160 Pt2D::new(1.0, 0.0),
161 Pt2D::new(1.0, 1.0),
162 Pt2D::new(0.0, 0.0),
163 ])
164 .into_polygon(),
165 stop_signs: BTreeMap::new(),
166 traffic_signals: BTreeMap::new(),
167 bus_routes_on_roads: MultiMap::new(),
168 gps_bounds: GPSBounds::new(),
169 bounds: Bounds::new(),
170 config: MapConfig::default(),
171 pathfinder: Pathfinder::empty(),
172 pathfinder_dirty: false,
173 routing_params: RoutingParams::default(),
174 name: MapName::blank(),
175 edits: MapEdits::new(),
176 edits_generation: 0,
177 road_to_buildings: MultiMap::new(),
178 }
179 }
180
181 pub fn almost_blank() -> Self {
183 let mut raw = RawMap::blank(MapName::blank());
186
187 raw.streets.boundary_polygon = Polygon::rectangle(100.0, 100.0);
188 raw.streets
189 .gps_bounds
190 .update(LonLat::new(-122.453224, 47.723277));
191 raw.streets
192 .gps_bounds
193 .update(LonLat::new(-122.240505, 47.495342));
194
195 let i1 = raw.streets.insert_intersection(
196 Vec::new(),
197 Pt2D::new(30.0, 30.0),
198 IntersectionKind::MapEdge,
199 IntersectionControl::Uncontrolled,
200 );
201 let i2 = raw.streets.insert_intersection(
202 Vec::new(),
203 Pt2D::new(70.0, 70.0),
204 IntersectionKind::MapEdge,
205 IntersectionControl::Uncontrolled,
206 );
207 raw.elevation_per_intersection.insert(i1, Distance::ZERO);
208 raw.elevation_per_intersection.insert(i2, Distance::ZERO);
209
210 let mut tags = Tags::empty();
211 tags.insert("highway", "residential");
212 tags.insert("lanes", "2");
213 let road_id = raw.streets.next_road_id();
214 raw.streets.insert_road(osm2streets::Road::new(
215 road_id,
216 Vec::new(),
217 i1,
218 i2,
219 PolyLine::must_new(vec![Pt2D::new(30.0, 30.0), Pt2D::new(70.0, 70.0)]),
220 tags,
221 &raw.streets.config,
222 ));
223 raw.extra_road_data
224 .insert(road_id, raw_map::ExtraRoadData::default());
225
226 raw.buildings.insert(
227 osm::OsmID::Way(osm::WayID(3)),
228 RawBuilding {
229 polygon: Polygon::rectangle_centered(
230 Pt2D::new(50.0, 20.0),
231 Distance::meters(30.0),
232 Distance::meters(10.0),
233 ),
234 osm_tags: Tags::empty(),
235 public_garage_name: None,
236 num_parking_spots: 0,
237 amenities: Vec::new(),
238 },
239 );
240
241 Self::create_from_raw(
242 raw,
243 crate::RawToMapOptions::default(),
244 &mut Timer::throwaway(),
245 )
246 }
247
248 pub fn all_roads(&self) -> &Vec<Road> {
249 &self.roads
250 }
251
252 pub fn all_roads_with_modal_filter(&self) -> impl Iterator<Item = (&Road, &RoadFilter)> {
253 self.roads.iter().filter_map(|r| {
254 if let Some(ref filter) = r.modal_filter {
255 Some((r, filter))
256 } else {
257 None
258 }
259 })
260 }
261
262 pub fn all_lanes(&self) -> impl Iterator<Item = &Lane> {
263 self.roads.iter().flat_map(|r| r.lanes.iter())
264 }
265
266 pub fn all_intersections(&self) -> &Vec<Intersection> {
267 &self.intersections
268 }
269
270 pub fn all_turns(&self) -> impl Iterator<Item = &Turn> {
271 self.intersections.iter().flat_map(|i| i.turns.iter())
272 }
273
274 pub fn all_buildings(&self) -> &Vec<Building> {
275 &self.buildings
276 }
277
278 pub fn all_areas(&self) -> &Vec<Area> {
279 &self.areas
280 }
281
282 pub fn all_parking_lots(&self) -> &Vec<ParkingLot> {
283 &self.parking_lots
284 }
285
286 pub fn all_zones(&self) -> &Vec<Zone> {
287 &self.zones
288 }
289
290 pub fn all_census_zones(&self) -> &Vec<(Polygon, CensusZone)> {
291 &self.census_zones
292 }
293
294 pub fn all_extra_pois(&self) -> &Vec<ExtraPOI> {
295 &self.extra_pois
296 }
297
298 pub fn maybe_get_r(&self, id: RoadID) -> Option<&Road> {
299 self.roads.get(id.0)
300 }
301
302 pub fn maybe_get_l(&self, id: LaneID) -> Option<&Lane> {
303 self.maybe_get_r(id.road)?.lanes.get(id.offset)
304 }
305
306 pub fn maybe_get_i(&self, id: IntersectionID) -> Option<&Intersection> {
307 self.intersections.get(id.0)
308 }
309
310 pub fn maybe_get_t(&self, id: TurnID) -> Option<&Turn> {
311 for turn in &self.intersections[id.parent.0].turns {
314 if turn.id == id {
315 return Some(turn);
316 }
317 }
318 None
319 }
320
321 pub fn maybe_get_b(&self, id: BuildingID) -> Option<&Building> {
322 self.buildings.get(id.0)
323 }
324
325 pub fn maybe_get_pl(&self, id: ParkingLotID) -> Option<&ParkingLot> {
326 self.parking_lots.get(id.0)
327 }
328
329 pub fn maybe_get_a(&self, id: AreaID) -> Option<&Area> {
330 self.areas.get(id.0)
331 }
332
333 pub fn maybe_get_ts(&self, id: TransitStopID) -> Option<&TransitStop> {
334 self.transit_stops.get(&id)
335 }
336
337 pub fn maybe_get_stop_sign(&self, id: IntersectionID) -> Option<&ControlStopSign> {
338 self.stop_signs.get(&id)
339 }
340
341 pub fn maybe_get_traffic_signal(&self, id: IntersectionID) -> Option<&ControlTrafficSignal> {
342 self.traffic_signals.get(&id)
343 }
344
345 pub fn maybe_get_tr(&self, route: TransitRouteID) -> Option<&TransitRoute> {
346 self.transit_routes.get(route.0)
347 }
348
349 pub fn get_r(&self, id: RoadID) -> &Road {
350 &self.roads[id.0]
351 }
352
353 pub fn get_l(&self, id: LaneID) -> &Lane {
354 &self.roads[id.road.0].lanes[id.offset]
355 }
356
357 pub(crate) fn mut_lane(&mut self, id: LaneID) -> &mut Lane {
358 &mut self.roads[id.road.0].lanes[id.offset]
359 }
360 pub fn mut_road(&mut self, id: RoadID) -> &mut Road {
362 &mut self.roads[id.0]
363 }
364 pub(crate) fn mut_turn(&mut self, id: TurnID) -> &mut Turn {
365 for turn in &mut self.intersections[id.parent.0].turns {
366 if turn.id == id {
367 return turn;
368 }
369 }
370 panic!("Couldn't find {id}");
371 }
372
373 pub fn get_i(&self, id: IntersectionID) -> &Intersection {
374 &self.intersections[id.0]
375 }
376
377 pub fn get_t(&self, id: TurnID) -> &Turn {
378 if let Some(turn) = self.maybe_get_t(id) {
380 turn
381 } else {
382 panic!("Can't get_t({})", id);
383 }
384 }
385
386 pub fn get_b(&self, id: BuildingID) -> &Building {
387 &self.buildings[id.0]
388 }
389
390 pub fn get_a(&self, id: AreaID) -> &Area {
391 &self.areas[id.0]
392 }
393
394 pub fn get_pl(&self, id: ParkingLotID) -> &ParkingLot {
395 &self.parking_lots[id.0]
396 }
397
398 pub fn get_stop_sign(&self, id: IntersectionID) -> &ControlStopSign {
399 &self.stop_signs[&id]
400 }
401
402 pub fn get_traffic_signal(&self, id: IntersectionID) -> &ControlTrafficSignal {
403 &self.traffic_signals[&id]
404 }
405
406 pub fn get_movement(&self, id: MovementID) -> Option<&Movement> {
408 self.get_i(id.parent).movements.get(&id)
409 }
410
411 pub fn get_turns_from_lane(&self, l: LaneID) -> Vec<&Turn> {
415 let lane = self.get_l(l);
416 self.get_i(lane.dst_i)
417 .turns
418 .iter()
419 .chain(
421 self.get_i(lane.src_i)
422 .turns
423 .iter()
424 .take_while(|_| lane.is_walkable()),
426 )
427 .filter(|t| t.id.src == l || (lane.is_walkable() && t.id.dst == l))
428 .collect()
429 }
430
431 pub fn get_turns_to_lane(&self, l: LaneID) -> Vec<&Turn> {
432 let lane = self.get_l(l);
433
434 if lane.is_walkable() {
436 return self.get_turns_from_lane(l);
437 }
438
439 let turns: Vec<&Turn> = self
440 .get_i(lane.src_i)
441 .turns
442 .iter()
443 .filter(|t| t.id.dst == l)
444 .collect();
445 turns
446 }
447
448 pub fn get_turn_between(
449 &self,
450 from: LaneID,
451 to: LaneID,
452 parent: IntersectionID,
453 ) -> Option<&Turn> {
454 self.get_i(parent)
455 .turns
456 .iter()
457 .find(|t| t.id.src == from && t.id.dst == to)
458 }
459
460 pub fn get_next_turns_and_lanes(&self, from: LaneID) -> Vec<(&Turn, &Lane)> {
461 self.get_turns_from_lane(from)
462 .into_iter()
463 .map(|t| {
464 (
465 t,
466 self.get_l(if t.id.src == from { t.id.dst } else { t.id.src }),
467 )
468 })
469 .collect()
470 }
471
472 pub fn get_next_turns_and_lanes_for(
473 &self,
474 from: LaneID,
475 constraints: PathConstraints,
476 ) -> Vec<(&Turn, &Lane)> {
477 self.get_next_turns_and_lanes(from)
478 .into_iter()
479 .filter(|(_, l)| constraints.can_use(l, self))
480 .collect()
481 }
482
483 pub fn get_turns_for(&self, from: LaneID, constraints: PathConstraints) -> Vec<&Turn> {
484 self.get_next_turns_and_lanes_for(from, constraints)
485 .into_iter()
486 .map(|(t, _)| t)
487 .collect()
488 }
489
490 pub fn get_movements_for(
492 &self,
493 from: DirectedRoadID,
494 constraints: PathConstraints,
495 ) -> Vec<MovementID> {
496 let mut result = BTreeSet::new();
497 for t in &self.get_i(from.dst_i(self)).turns {
498 let src = self.get_l(t.id.src);
499 if src.get_directed_parent() == from
500 && constraints.can_use(src, self)
501 && constraints.can_use(self.get_l(t.id.dst), self)
502 {
503 result.insert(t.id.to_movement(self));
504 }
505 }
506 assert!(constraints != PathConstraints::Pedestrian);
508 result.into_iter().collect()
509 }
510
511 pub fn get_next_roads(&self, from: RoadID) -> BTreeSet<RoadID> {
512 let mut roads: BTreeSet<RoadID> = BTreeSet::new();
513 let r = self.get_r(from);
514 for id in vec![r.src_i, r.dst_i].into_iter() {
515 roads.extend(self.get_i(id).roads.clone());
516 }
517 roads
518 }
519
520 pub fn get_parent(&self, id: LaneID) -> &Road {
521 self.get_r(id.road)
522 }
523
524 pub fn get_gps_bounds(&self) -> &GPSBounds {
525 &self.gps_bounds
526 }
527
528 pub fn get_bounds(&self) -> &Bounds {
529 &self.bounds
530 }
531
532 pub fn get_city_name(&self) -> &CityName {
533 &self.name.city
534 }
535
536 pub fn get_name(&self) -> &MapName {
537 &self.name
538 }
539
540 pub fn all_transit_stops(&self) -> &BTreeMap<TransitStopID, TransitStop> {
541 &self.transit_stops
542 }
543
544 pub fn get_ts(&self, stop: TransitStopID) -> &TransitStop {
545 &self.transit_stops[&stop]
546 }
547
548 pub fn get_tr(&self, route: TransitRouteID) -> &TransitRoute {
549 &self.transit_routes[route.0]
550 }
551
552 pub fn all_transit_routes(&self) -> &Vec<TransitRoute> {
553 &self.transit_routes
554 }
555
556 pub fn get_transit_route(&self, name: &str) -> Option<&TransitRoute> {
557 self.transit_routes.iter().find(|r| r.long_name == name)
558 }
559
560 pub fn get_routes_serving_stop(&self, stop: TransitStopID) -> Vec<&TransitRoute> {
561 let mut routes = Vec::new();
562 for r in &self.transit_routes {
563 if r.stops.contains(&stop) {
564 routes.push(r);
565 }
566 }
567 routes
568 }
569
570 pub fn building_to_road(&self, id: BuildingID) -> &Road {
571 self.get_parent(self.get_b(id).sidewalk())
572 }
573
574 pub fn all_incoming_borders(&self) -> Vec<&Intersection> {
576 let mut result: Vec<&Intersection> = Vec::new();
577 for i in &self.intersections {
578 if i.is_incoming_border() {
579 result.push(i);
580 }
581 }
582 result
583 }
584
585 pub fn all_outgoing_borders(&self) -> Vec<&Intersection> {
586 let mut result: Vec<&Intersection> = Vec::new();
587 for i in &self.intersections {
588 if i.is_outgoing_border() {
589 result.push(i);
590 }
591 }
592 result
593 }
594
595 pub fn save(&self) {
596 assert!(self.edits.edits_name.starts_with("Untitled Proposal"));
597 assert!(self.edits.commands.is_empty());
598 assert!(!self.pathfinder_dirty);
599 abstio::write_binary(self.name.path(), self);
600 }
601
602 pub fn find_driving_lane_near_building(&self, b: BuildingID) -> LaneID {
608 let sidewalk = self.get_b(b).sidewalk();
609 if let Some(l) = self
610 .get_parent(sidewalk)
611 .find_closest_lane(sidewalk, |l| PathConstraints::Car.can_use(l, self))
612 {
613 if !self.get_l(l).driving_blackhole {
614 return l;
615 }
616 }
617
618 let mut roads_queue: VecDeque<RoadID> = VecDeque::new();
619 let mut visited: HashSet<RoadID> = HashSet::new();
620 {
621 let start = self.building_to_road(b).id;
622 roads_queue.push_back(start);
623 visited.insert(start);
624 }
625
626 loop {
627 if roads_queue.is_empty() {
628 panic!(
629 "Giving up looking for a driving lane near {}, searched {} roads: {:?}",
630 b,
631 visited.len(),
632 visited
633 );
634 }
635 let r = self.get_r(roads_queue.pop_front().unwrap());
636
637 for (l, lt) in r
638 .children_forwards()
639 .into_iter()
640 .chain(r.children_backwards().into_iter())
641 {
642 if lt == LaneType::Driving && !self.get_l(l).driving_blackhole {
643 return l;
644 }
645 }
646
647 for next_r in self.get_next_roads(r.id).into_iter() {
648 if !visited.contains(&next_r) {
649 roads_queue.push_back(next_r);
650 visited.insert(next_r);
651 }
652 }
653 }
654 }
655
656 pub fn get_boundary_polygon(&self) -> &Polygon {
657 &self.boundary_polygon
658 }
659
660 pub fn get_pathfinder(&self) -> &Pathfinder {
661 &self.pathfinder
662 }
663
664 pub fn pathfind(&self, req: PathRequest) -> Result<Path> {
665 self.pathfind_v2(req)?.into_v1(self)
666 }
667 pub fn pathfind_with_params(
668 &self,
669 req: PathRequest,
670 params: &RoutingParams,
671 cache_custom: PathfinderCaching,
672 ) -> Result<Path> {
673 self.pathfind_v2_with_params(req, params, cache_custom)?
674 .into_v1(self)
675 }
676 pub fn pathfind_v2(&self, req: PathRequest) -> Result<PathV2> {
677 assert!(!self.pathfinder_dirty);
678 self.pathfinder
679 .pathfind(req.clone(), self)
680 .ok_or_else(|| anyhow!("can't fulfill {}", req))
681 }
682 pub fn pathfind_v2_with_params(
683 &self,
684 req: PathRequest,
685 params: &RoutingParams,
686 cache_custom: PathfinderCaching,
687 ) -> Result<PathV2> {
688 assert!(!self.pathfinder_dirty);
689 self.pathfinder
690 .pathfind_with_params(req.clone(), params, cache_custom, self)
691 .ok_or_else(|| anyhow!("can't fulfill {}", req))
692 }
693 pub fn should_use_transit(
694 &self,
695 start: Position,
696 end: Position,
697 ) -> Option<(TransitStopID, Option<TransitStopID>, TransitRouteID)> {
698 assert!(!self.pathfinder_dirty);
699 self.pathfinder.should_use_transit(self, start, end)
700 }
701
702 pub fn all_costs_from(
706 &self,
707 req: PathRequest,
708 ) -> Option<(Duration, HashMap<DirectedRoadID, Duration>)> {
709 assert!(!self.pathfinder_dirty);
710 self.pathfinder.all_costs_from(req, self)
711 }
712
713 pub fn get_movement_for_traffic_signal(
715 &self,
716 t: TurnID,
717 ) -> Option<(MovementID, CompressedMovementID)> {
718 let i = self.get_i(t.parent);
719 if !i.is_traffic_signal() || self.get_t(t).turn_type == TurnType::SharedSidewalkCorner {
720 return None;
721 }
722 Some(i.turn_to_movement(t))
723 }
724
725 pub fn find_r_by_osm_id(&self, id: OriginalRoad) -> Result<RoadID> {
726 for r in self.all_roads() {
727 if r.orig_id == id {
728 return Ok(r.id);
729 }
730 }
731 bail!("Can't find {}", id)
732 }
733
734 pub fn find_i_by_osm_id(&self, id: osm::NodeID) -> Result<IntersectionID> {
735 for i in self.all_intersections() {
736 if i.orig_id == id {
737 return Ok(i.id);
738 }
739 }
740 bail!("Can't find {}", id)
741 }
742
743 fn populate_intersection_quad_tree(&self) {
744 let quad_tree_lock = Arc::clone(&self.intersection_quad_tree);
745 let mut quad_tree = quad_tree_lock.write().unwrap();
746
747 if quad_tree.is_some() {
748 return;
749 }
750
751 let mut quad: FindClosest<IntersectionID> = FindClosest::new();
752
753 for intersection in self.all_intersections() {
754 quad.add_polygon(intersection.id, &intersection.polygon);
755 }
756 *quad_tree = Some(quad);
757 }
758
759 pub fn localise_lon_lat_to_map(&self, point: LonLat) -> Pt2D {
760 point.to_pt(&self.gps_bounds)
761 }
762
763 pub fn find_i_by_pt2d(&self, pnt: Pt2D) -> Result<IntersectionID> {
764 self.populate_intersection_quad_tree();
765 let quad_tree_lock = Arc::clone(&self.intersection_quad_tree);
766 let quad_tree = quad_tree_lock.read().unwrap();
767
768 if let Some(tree) = &*quad_tree {
769 let (intersection_id, _) = tree
770 .closest_pt(pnt, Distance::meters(100.0))
771 .context("Failed to find intersection within 100m of specified point")?;
772 Ok(intersection_id)
773 } else {
774 unreachable!("Intersection Quad tree was somehow blank even after generation")
775 }
776 }
777
778 pub fn find_b_by_osm_id(&self, id: osm::OsmID) -> Option<BuildingID> {
779 for b in self.all_buildings() {
780 if b.orig_id == id {
781 return Some(b.id);
782 }
783 }
784 None
785 }
786
787 pub fn find_tr_by_gtfs(&self, gtfs_id: &str) -> Option<TransitRouteID> {
788 for tr in self.all_transit_routes() {
789 if tr.gtfs_id == gtfs_id {
790 return Some(tr.id);
791 }
792 }
793 None
794 }
795
796 pub fn hack_override_offstreet_spots(&mut self, spots_per_bldg: usize) {
798 for b in &mut self.buildings {
799 if let OffstreetParking::Private(ref mut num_spots, _) = b.parking {
800 *num_spots = spots_per_bldg;
801 }
802 }
803 }
804 pub fn hack_override_offstreet_spots_individ(&mut self, b: BuildingID, spots: usize) {
805 let b = &mut self.buildings[b.0];
806 if let OffstreetParking::Private(ref mut num_spots, _) = b.parking {
807 *num_spots = spots;
808 }
809 }
810
811 pub fn hack_override_bldg_type(&mut self, b: BuildingID, bldg_type: BuildingType) {
812 self.buildings[b.0].bldg_type = bldg_type;
813 }
814
815 pub fn hack_override_orig_spawn_times(&mut self, br: TransitRouteID, times: Vec<Time>) {
816 self.transit_routes[br.0].orig_spawn_times = times.clone();
817 self.transit_routes[br.0].spawn_times = times;
818 }
819
820 pub fn hack_add_area(&mut self, area_type: AreaType, polygon: Polygon, osm_tags: Tags) {
821 self.areas.push(Area {
822 id: AreaID(self.areas.len()),
823 area_type,
824 polygon,
825 osm_tags,
826 osm_id: None,
827 });
828 }
829
830 pub fn keep_pathfinder_despite_edits(&mut self) {
834 self.pathfinder_dirty = false;
835 }
836
837 pub fn get_languages(&self) -> BTreeSet<String> {
838 let mut languages = BTreeSet::new();
839 for r in self.all_roads() {
840 for key in r.osm_tags.inner().keys() {
841 if let Some(x) = key.strip_prefix("name:") {
842 languages.insert(x.to_string());
843 }
844 }
845 }
846 for b in self.all_buildings() {
847 for a in &b.amenities {
848 for lang in a.names.languages() {
849 languages.insert(lang.to_string());
850 }
851 }
852 }
853 languages
854 }
855
856 pub fn get_config(&self) -> &MapConfig {
857 &self.config
858 }
859
860 pub fn simple_path_btwn(
863 &self,
864 i1: IntersectionID,
865 i2: IntersectionID,
866 ) -> Option<(Vec<RoadID>, Vec<IntersectionID>)> {
867 let mut graph: UnGraphMap<IntersectionID, RoadID> = UnGraphMap::new();
868 for r in self.all_roads() {
869 if !r.is_light_rail() {
870 graph.add_edge(r.src_i, r.dst_i, r.id);
871 }
872 }
873 let (_, path) = petgraph::algo::astar(
874 &graph,
875 i1,
876 |i| i == i2,
877 |(_, _, r)| self.get_r(*r).length(),
878 |_| Distance::ZERO,
879 )?;
880 let roads: Vec<RoadID> = path
881 .windows(2)
882 .map(|pair| *graph.edge_weight(pair[0], pair[1]).unwrap())
883 .collect();
884 Some((roads, path))
885 }
886
887 pub fn simple_path_btwn_v2(
894 &self,
895 i1: IntersectionID,
896 i2: IntersectionID,
897 constraints: PathConstraints,
898 ) -> Option<(Vec<RoadID>, Vec<IntersectionID>)> {
899 let mut graph: DiGraphMap<IntersectionID, RoadID> = DiGraphMap::new();
900 for r in self.all_roads() {
901 let mut fwd = false;
902 let mut back = false;
903 for lane in &r.lanes {
904 if constraints.can_use(lane, self) {
905 if lane.dir == Direction::Fwd {
906 fwd = true;
907 } else {
908 back = true;
909 }
910 }
911 }
912 if fwd {
913 graph.add_edge(r.src_i, r.dst_i, r.id);
914 }
915 if back {
916 graph.add_edge(r.dst_i, r.src_i, r.id);
917 }
918 }
919 let (_, path) = petgraph::algo::astar(
920 &graph,
921 i1,
922 |i| i == i2,
923 |(_, _, r)| self.get_r(*r).length(),
924 |_| Distance::ZERO,
925 )?;
926 let roads: Vec<RoadID> = path
927 .windows(2)
928 .map(|pair| *graph.edge_weight(pair[0], pair[1]).unwrap())
929 .collect();
930 Some((roads, path))
931 }
932
933 pub fn routing_params(&self) -> &RoutingParams {
937 &self.routing_params
938 }
939
940 pub fn routing_params_respecting_modal_filters(&self) -> RoutingParams {
944 let mut params = self.routing_params.clone();
945 for r in &self.roads {
946 if r.modal_filter.is_some() {
947 params.avoid_roads.insert(r.id);
948 }
949 }
950 for i in &self.intersections {
951 if let Some(ref filter) = i.modal_filter {
952 params
953 .avoid_movements_between
954 .extend(filter.avoid_movements_between_roads());
955 }
956 }
957 params
958 }
959
960 pub fn road_to_buildings(&self, r: RoadID) -> &BTreeSet<BuildingID> {
961 self.road_to_buildings.get(r)
962 }
963
964 pub(crate) fn recalculate_road_to_buildings(&mut self) {
965 let mut mapping = MultiMap::new();
966 for b in self.all_buildings() {
967 mapping.insert(b.sidewalk_pos.lane().road, b.id);
968 }
969 self.road_to_buildings = mapping;
970 }
971
972 pub(crate) fn recalculate_all_movements(&mut self, timer: &mut Timer) {
973 let movements = timer.parallelize(
974 "generate movements",
975 self.intersections.iter().map(|i| i.id).collect(),
976 |i| Movement::for_i(i, self),
977 );
978 for (i, movements) in self.intersections.iter_mut().zip(movements.into_iter()) {
979 i.movements = movements;
980 }
981 }
982
983 pub fn find_road_between(&self, i1: IntersectionID, i2: IntersectionID) -> Option<RoadID> {
985 for r in &self.get_i(i1).roads {
986 let road = self.get_r(*r);
987 if road.src_i == i2 || road.dst_i == i2 {
988 return Some(road.id);
989 }
990 }
991 None
992 }
993
994 pub fn max_elevation(&self) -> Distance {
996 self.all_intersections()
998 .iter()
999 .max_by_key(|i| i.elevation)
1000 .unwrap()
1001 .elevation
1002 }
1003
1004 pub fn is_unprotected_turn(&self, from: RoadID, to: RoadID, turn_type: TurnType) -> bool {
1008 let unprotected_turn_type = if self.get_config().driving_side == DrivingSide::Right {
1009 TurnType::Left
1010 } else {
1011 TurnType::Right
1012 };
1013 let from = self.get_r(from);
1014 let to = self.get_r(to);
1015 turn_type == unprotected_turn_type
1016 && from.get_detailed_rank() < to.get_detailed_rank()
1017 && match from.common_endpoint(to) {
1018 CommonEndpoint::One(i) => self.get_i(i).is_stop_sign(),
1019 _ => false,
1020 }
1021 }
1022
1023 pub fn minify(&mut self, timer: &mut Timer) {
1025 self.pathfinder = Pathfinder::new_limited(
1027 self,
1028 self.routing_params().clone(),
1029 crate::pathfind::CreateEngine::CH,
1030 vec![PathConstraints::Car, PathConstraints::Bike],
1031 timer,
1032 );
1033
1034 self.transit_stops.clear();
1036 self.transit_routes.clear();
1037 for r in &mut self.roads {
1038 r.transit_stops.clear();
1039 }
1040 }
1041
1042 pub fn minify_buildings(&mut self, timer: &mut Timer) {
1044 self.buildings.clear();
1045
1046 self.pathfinder = Pathfinder::new_limited(
1048 self,
1049 self.routing_params().clone(),
1050 crate::pathfind::CreateEngine::CH,
1051 vec![PathConstraints::Car],
1052 timer,
1053 );
1054
1055 self.transit_stops.clear();
1057 self.transit_routes.clear();
1058 for r in &mut self.roads {
1059 r.transit_stops.clear();
1060 }
1061 }
1062
1063 pub fn export_geometry(&self) -> geojson::GeoJson {
1065 let mut pairs = Vec::new();
1066 let gps_bounds = Some(self.get_gps_bounds());
1067
1068 for i in self.all_intersections() {
1069 let mut props = serde_json::Map::new();
1070 props.insert("type".to_string(), "intersection".into());
1071 props.insert("id".to_string(), i.orig_id.to_string().into());
1072 pairs.push((i.polygon.get_outer_ring().to_geojson(gps_bounds), props));
1073 }
1074 for r in self.all_roads() {
1075 let mut props = serde_json::Map::new();
1076 props.insert("type".to_string(), "road".into());
1077 props.insert("id".to_string(), r.orig_id.osm_way_id.to_string().into());
1078 pairs.push((
1079 r.center_pts
1080 .to_thick_ring(r.get_width())
1081 .to_geojson(gps_bounds),
1082 props,
1083 ));
1084 }
1085
1086 geom::geometries_with_properties_to_geojson(pairs)
1087 }
1088
1089 pub fn get_bus_routes_on_road(&self, r: RoadID) -> &BTreeSet<String> {
1092 let way = self.get_r(r).orig_id.osm_way_id;
1093 self.bus_routes_on_roads.get(way)
1094 }
1095
1096 pub fn get_available_amenity_types(&self) -> BTreeSet<AmenityType> {
1098 let mut result = BTreeSet::new();
1099 for b in self.all_buildings() {
1100 for amenity in &b.amenities {
1101 if let Some(t) = AmenityType::categorize(&amenity.amenity_type) {
1102 result.insert(t);
1103 }
1104 }
1105 }
1106 result
1107 }
1108
1109 pub fn get_ban_turn_info(
1112 &self,
1113 r1: &Road,
1114 r2: &Road,
1115 icon_counter: &HashMap<IntersectionID, i32>,
1116 ) -> (TurnType, Pt2D, Angle, IntersectionID) {
1117 let i = match r1.common_endpoint(r2) {
1119 CommonEndpoint::One(i) => i,
1120 CommonEndpoint::Both => r1.src_i,
1122 CommonEndpoint::None => {
1123 r1.dst_i
1127 }
1128 };
1129
1130 let sign_count = *icon_counter.get(&i).unwrap_or(&1);
1132 let mut ideal_dist_from_intersection = sign_count as f64 * 1.1 * r1.get_width();
1133 if 2.0 * ideal_dist_from_intersection > r1.center_pts.length() {
1134 ideal_dist_from_intersection = 0.5 * (r1.center_pts.length() - r1.get_width());
1137 if ideal_dist_from_intersection < Distance::ZERO {
1138 ideal_dist_from_intersection = 0.3 * r1.center_pts.length();
1140 }
1141 }
1142
1143 let dist_from_intersection = if r1.src_i == i {
1145 ideal_dist_from_intersection
1146 } else {
1147 r1.center_pts.length() - ideal_dist_from_intersection
1148 };
1149
1150 let (sign_pt, mut r1_angle) = r1.center_pts.must_dist_along(dist_from_intersection);
1151
1152 r1_angle = if r1.src_i == i {
1155 r1_angle.rotate_degs(180.0)
1156 } else {
1157 r1_angle
1158 };
1159
1160 let (_, mut r2_angle) = r2
1161 .center_pts
1162 .must_dist_along((if r2.src_i == i { 0.2 } else { 0.8 }) * r2.center_pts.length());
1163
1164 r2_angle = if r2.dst_i == i {
1166 r2_angle.rotate_degs(180.0)
1167 } else {
1168 r2_angle
1169 };
1170
1171 let t_type = turn_type_from_road_geom(r1, r1_angle, r2, r2_angle, self.get_i(i), self);
1172 (t_type, sign_pt, r1_angle, i)
1173 }
1174}
1175
1176pub fn turn_type_from_road_geom(
1177 r1: &Road,
1178 r1_angle: Angle,
1179 r2: &Road,
1180 r2_angle: Angle,
1181 i: &Intersection,
1182 map: &Map,
1183) -> TurnType {
1184 let expected_turn_types = expected_turn_types_for_four_way(i, map);
1185
1186 let mut turn_type = turn_type_from_angles(r1_angle, r2_angle);
1187 if turn_type == TurnType::UTurn {
1188 if r1.get_name(None) != r2.get_name(None) {
1192 if r1_angle.simple_shortest_rotation_towards(r2_angle) < 0.0 {
1194 turn_type = TurnType::Right;
1195 } else {
1196 turn_type = TurnType::Left;
1197 }
1198 }
1199 } else if let Some(expected_type) = expected_turn_types
1200 .as_ref()
1201 .and_then(|e| e.get(&(r1.id, r2.id)))
1202 {
1203 if turn_type != *expected_type {
1206 warn!(
1207 "Turn from {} to {} looks like {:?} by angle, but is {:?} by ordering",
1208 r1.orig_id, r2.orig_id, turn_type, expected_type
1209 );
1210 turn_type = *expected_type;
1211 }
1212 }
1213 turn_type
1214}
1215
1216pub fn turn_type_from_angles(from: Angle, to: Angle) -> TurnType {
1217 let diff = from.simple_shortest_rotation_towards(to);
1218 if diff.abs() < 30.0 {
1221 TurnType::Straight
1222 } else if diff.abs() > 135.0 {
1223 TurnType::UTurn
1224 } else if diff < 0.0 {
1225 TurnType::Right
1227 } else {
1228 TurnType::Left
1230 }
1231}
1232
1233fn expected_turn_types_for_four_way(
1234 i: &Intersection,
1235 map: &Map,
1236) -> Option<HashMap<(RoadID, RoadID), TurnType>> {
1237 let roads = i.get_sorted_incoming_roads(map);
1238 if roads.len() != 4 {
1239 return None;
1240 }
1241
1242 let mut expected_turn_types: HashMap<(RoadID, RoadID), TurnType> = HashMap::new();
1245 for (offset, turn_type) in [
1246 (1, TurnType::Left),
1247 (2, TurnType::Straight),
1248 (3, TurnType::Right),
1249 ] {
1250 for from_idx in 0..roads.len() {
1251 let to = *abstutil::wraparound_get(&roads, (from_idx as isize) + offset);
1252 expected_turn_types.insert((roads[from_idx], to), turn_type);
1253 }
1254 }
1255 Some(expected_turn_types)
1256}