1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
use std::collections::{HashMap, HashSet};

use aabb_quadtree::QuadTree;
use abstutil::Timer;

use crate::{osm, RawMap};

/// Look for roads that physically overlap, but aren't connected by an intersection. Shrink their
/// width.
pub fn shrink(raw: &mut RawMap, timer: &mut Timer) {
    let mut road_centers = HashMap::new();
    let mut road_polygons = HashMap::new();
    let mut overlapping = Vec::new();
    let mut quadtree = QuadTree::default(raw.gps_bounds.to_bounds().as_bbox());
    timer.start_iter("find overlapping roads", raw.roads.len());
    for (id, road) in &raw.roads {
        timer.next();
        if road.is_light_rail() {
            continue;
        }
        // Only attempt this fix for dual carriageways
        if road.oneway_for_driving().is_none() {
            continue;
        }

        let (center, total_width) = road.untrimmed_road_geometry();
        let polygon = center.make_polygons(total_width);

        // Any conflicts with existing?
        for (other_id, _, _) in quadtree.query(polygon.get_bounds().as_bbox()) {
            // Only dual carriageways
            if road.osm_tags.get(osm::NAME) != raw.roads[other_id].osm_tags.get(osm::NAME) {
                continue;
            }
            if !id.has_common_endpoint(*other_id) && polygon.intersects(&road_polygons[other_id]) {
                // If the polylines don't overlap, then it's probably just a bridge/tunnel
                if center.intersection(&road_centers[other_id]).is_none() {
                    overlapping.push((*id, *other_id));
                }
            }
        }

        quadtree.insert_with_box(*id, polygon.get_bounds().as_bbox());
        road_centers.insert(*id, center);
        road_polygons.insert(*id, polygon);
    }

    timer.start_iter("shrink overlapping roads", overlapping.len());
    let mut shrunk = HashSet::new();
    for (r1, r2) in overlapping {
        timer.next();
        // TODO It'd be better to gradually shrink each road until they stop touching. I got that
        // working in some maps, but it crashes in others (downstream in intersection polygon code)
        // for unknown reasons. Just do the simple thing for now.
        for id in [r1, r2] {
            // Don't shrink any road twice!
            if shrunk.contains(&id) {
                continue;
            }
            shrunk.insert(id);
            // Anything derived from lane_specs_ltr will need to be changed. When we store
            // untrimmed and trimmed center points instead of calculating them dynamically, that'll
            // have to happen here.
            for spec in &mut raw.roads.get_mut(&id).unwrap().lane_specs_ltr {
                spec.width *= 0.5;
            }
        }
    }
}