1use fs_err::File;
2use rand::SeedableRng;
3use rand_xorshift::XorShiftRng;
4use serde::Deserialize;
5
6use abstutil::Timer;
7use geom::Ring;
8use kml::ExtraShapes;
9use map_model::BuildingType;
10use raw_map::RawMap;
11
12use crate::configuration::ImporterConfiguration;
13use crate::utils::{download, download_kml};
14
15pub async fn import_extra_data(
16 map: &RawMap,
17 config: &ImporterConfiguration,
18 timer: &mut Timer<'_>,
19) {
20 download_kml(
22 map.get_city_name().input_path("planning_areas.bin"),
23 "https://tsb-opendata.s3.eu-central-1.amazonaws.com/lor_planungsgraeume/lor_planungsraeume.kml",
24 &map.streets.gps_bounds,
25 false,
27 timer
28 ).await;
29
30 download(
33 config,
34 map.get_city_name().input_path("EWR201812E_Matrix.csv"),
35 "https://www.statistik-berlin-brandenburg.de/opendata/EWR201812E_Matrix.csv",
36 )
37 .await;
38
39 correlate_population(
41 map.get_city_name().input_path("planning_areas.bin"),
42 map.get_city_name().input_path("EWR201812E_Matrix.csv"),
43 timer,
44 );
45}
46
47fn correlate_population(kml_path: String, csv_path: String, timer: &mut Timer) {
49 let mut shapes = abstio::read_binary::<ExtraShapes>(kml_path.clone(), timer);
50 for rec in csv::ReaderBuilder::new()
51 .delimiter(b';')
52 .from_reader(File::open(csv_path).unwrap())
53 .deserialize()
54 {
55 let rec: Record = rec.unwrap();
56 for shape in &mut shapes.shapes {
57 if shape.attributes.get("spatial_name") == Some(&rec.raumid) {
58 shape
59 .attributes
60 .insert("num_residents".to_string(), rec.e_e);
61 break;
62 }
63 }
64 }
65 abstio::write_binary(kml_path, &shapes);
66}
67
68#[derive(Debug, Deserialize)]
69struct Record {
70 #[serde(rename = "RAUMID")]
72 raumid: String,
73 #[serde(rename = "E_E")]
75 e_e: String,
76}
77
78pub fn distribute_residents(map: &mut map_model::Map, timer: &mut Timer) {
79 for shape in abstio::read_binary::<ExtraShapes>(
80 "data/input/de/berlin/planning_areas.bin".to_string(),
81 timer,
82 )
83 .shapes
84 {
85 let pts = map.get_gps_bounds().convert(&shape.points);
86 if pts
87 .iter()
88 .all(|pt| !map.get_boundary_polygon().contains_pt(*pt))
89 {
90 continue;
91 }
92 let region = Ring::must_new(pts).into_polygon();
93 let mut rng =
95 XorShiftRng::seed_from_u64(shape.attributes["spatial_name"].parse::<u64>().unwrap());
96
97 for (home, n) in popdat::distribute_population_to_homes(
98 geo::Polygon::from(region),
99 shape.attributes["num_residents"].parse::<usize>().unwrap(),
100 map,
101 &mut rng,
102 ) {
103 let bldg_type = match map.get_b(home).bldg_type {
104 BuildingType::Residential {
105 num_housing_units, ..
106 } => BuildingType::Residential {
107 num_housing_units,
108 num_residents: n,
109 },
110 BuildingType::ResidentialCommercial(_, worker_cap) => {
111 BuildingType::ResidentialCommercial(n, worker_cap)
112 }
113 _ => unreachable!(),
114 };
115 map.hack_override_bldg_type(home, bldg_type);
116 }
117 }
118
119 map.save();
120}