popdat/
distribute_people.rs1use geo::{Area, BooleanOps, Contains};
2use rand::Rng;
3use rand_xorshift::XorShiftRng;
4
5use abstutil::prettyprint_usize;
6use map_model::{BuildingID, Map};
7
8use crate::{CensusArea, CensusPerson, Config};
9
10pub fn assign_people_to_houses(
11 areas: Vec<CensusArea>,
12 map: &Map,
13 rng: &mut XorShiftRng,
14 _config: &Config,
15) -> Vec<CensusPerson> {
16 let mut people = Vec::new();
17 for area in areas {
18 for (home, n) in distribute_population_to_homes(area.polygon, area.population, map, rng) {
19 for _ in 0..n {
20 people.push(CensusPerson {
21 home,
22 age: rng.gen_range(5..95),
26 employed: rng.gen_bool(0.7),
27 owns_car: rng.gen_bool(0.5),
28 });
29 }
30 }
31 }
32 people
33}
34
35pub fn distribute_population_to_homes(
39 polygon: geo::Polygon,
40 population: usize,
41 map: &Map,
42 rng: &mut XorShiftRng,
43) -> Vec<(BuildingID, usize)> {
44 let map_boundary = geo::Polygon::from(map.get_boundary_polygon().clone());
45 let bldgs: Vec<map_model::BuildingID> = map
46 .all_buildings()
47 .iter()
48 .filter(|b| {
49 polygon.contains(&geo::Point::from(b.label_center)) && b.bldg_type.has_residents()
50 })
51 .map(|b| b.id)
52 .collect();
53
54 let pct_overlap = polygon.intersection(&map_boundary).unsigned_area() / polygon.unsigned_area();
57 let num_residents = (pct_overlap * (population as f64)) as usize;
58 debug!(
59 "Distributing {} residents to {} buildings. {}% of this area overlapped with the map, \
60 scaled residents accordingly.",
61 prettyprint_usize(num_residents),
62 prettyprint_usize(bldgs.len()),
63 (pct_overlap * 100.0) as usize
64 );
65
66 let mut count_per_home = Vec::new();
74 let mut rand_nums: Vec<f64> = (0..bldgs.len()).map(|_| rng.gen_range(0.0..1.0)).collect();
75 let sum: f64 = rand_nums.iter().sum();
76 for b in bldgs {
77 let n = (rand_nums.pop().unwrap() / sum * (num_residents as f64)) as usize;
78 count_per_home.push((b, n));
79 }
80 count_per_home
81}