1use std::collections::{BTreeMap, BTreeSet};
2
3use anyhow::Result;
4use serde::{Deserialize, Serialize};
5
6use abstio::MapName;
7use abstutil::Timer;
8use blockfinding::{Block, Perimeter};
9use geom::Polygon;
10use map_model::osm::RoadRank;
11use map_model::{IntersectionID, Map, RoadID, RoadSideID};
12
13#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
15pub struct NeighbourhoodID(pub usize);
16
17#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
19pub struct BlockID(usize);
20
21impl widgetry::mapspace::ObjectID for NeighbourhoodID {}
23impl widgetry::mapspace::ObjectID for BlockID {}
24
25#[derive(Clone, Serialize, Deserialize)]
26pub struct Partitioning {
27 pub map: MapName,
28 neighbourhoods: BTreeMap<NeighbourhoodID, NeighbourhoodInfo>,
29 single_blocks: Vec<Block>,
31
32 neighbourhood_id_counter: usize,
33
34 block_to_neighbourhood: BTreeMap<BlockID, NeighbourhoodID>,
36
37 pub broken: bool,
39
40 #[serde(skip_serializing, skip_deserializing)]
41 pub custom_boundaries: BTreeMap<NeighbourhoodID, CustomBoundary>,
42}
43
44#[derive(Clone, Serialize, Deserialize)]
45pub struct NeighbourhoodInfo {
46 pub block: Block,
47 pub override_drawing_boundary: Option<Polygon>,
50}
51
52impl NeighbourhoodInfo {
53 fn new(block: Block) -> Self {
54 Self {
55 block,
56 override_drawing_boundary: None,
57 }
58 }
59}
60
61#[derive(Clone)]
62pub struct CustomBoundary {
63 pub name: String,
64 pub boundary_polygon: Polygon,
65 pub borders: BTreeSet<IntersectionID>,
66 pub interior_roads: BTreeSet<RoadID>,
67}
68
69impl Partitioning {
70 pub fn empty() -> Partitioning {
72 Partitioning {
73 map: MapName::new("zz", "temp", "orary"),
74 neighbourhoods: BTreeMap::new(),
75 single_blocks: Vec::new(),
76
77 neighbourhood_id_counter: 0,
78
79 block_to_neighbourhood: BTreeMap::new(),
80
81 broken: false,
82 custom_boundaries: BTreeMap::new(),
83 }
84 }
85
86 pub fn is_empty(&self) -> bool {
87 self.neighbourhoods.is_empty()
88 }
89
90 pub fn seed_using_heuristics(map: &Map, timer: &mut Timer) -> Partitioning {
91 timer.start("seed partitioning with heuristics");
92
93 timer.start("find single blocks");
94 let input_single_blocks = Perimeter::find_all_single_blocks(map);
95 timer.stop("find single blocks");
96
97 timer.start("merge holes");
101 let input = Perimeter::merge_holes(map, input_single_blocks);
102 timer.stop("merge holes");
103
104 let mut single_blocks = Vec::new();
105 let mut single_block_perims = Vec::new();
106 timer.start_iter("fix deadends and blockify", input.len());
107 for mut perim in input {
108 timer.next();
109 perim.collapse_deadends();
113 if let Ok(block) = perim.to_block(map) {
114 single_block_perims.push(block.perimeter.clone());
115 single_blocks.push(block);
116 }
117 }
118
119 timer.start("partition");
120 let partitions = Perimeter::partition_by_predicate(single_block_perims, |r| {
121 map.get_r(r).get_rank() == RoadRank::Local
123 });
124
125 let mut merged = Vec::new();
126 for perimeters in partitions {
127 let stepwise_debug = false;
129 merged.extend(Perimeter::merge_all(map, perimeters, stepwise_debug));
130 }
131 timer.stop("partition");
132
133 timer.start_iter("blockify merged", merged.len());
134 let mut blocks = Vec::new();
135 for perimeter in merged {
136 timer.next();
137 match perimeter.to_block(map) {
138 Ok(block) => {
139 blocks.push(block);
140 }
141 Err(err) => {
142 warn!("Failed to make a block from a merged perimeter: {}", err);
143 }
144 }
145 }
146
147 let mut neighbourhoods = BTreeMap::new();
148 for block in blocks {
149 neighbourhoods.insert(
150 NeighbourhoodID(neighbourhoods.len()),
151 NeighbourhoodInfo::new(block),
152 );
153 }
154 let neighbourhood_id_counter = neighbourhoods.len();
155 let mut p = Partitioning {
156 map: map.get_name().clone(),
157 neighbourhoods,
158 single_blocks,
159
160 neighbourhood_id_counter,
161 block_to_neighbourhood: BTreeMap::new(),
162 broken: false,
163 custom_boundaries: BTreeMap::new(),
164 };
165
166 for id in p.all_block_ids() {
168 if let Some(neighbourhood) = p.neighbourhood_containing(id) {
169 p.block_to_neighbourhood.insert(id, neighbourhood);
170 } else {
171 error!(
172 "Block doesn't belong to any neighbourhood. Continuing without boundary adjustment. {:?}",
173 p.get_block(id).perimeter
174 );
175 p.broken = true;
176 }
177 }
178
179 timer.stop("seed partitioning with heuristics");
180 p
181 }
182
183 pub fn transfer_blocks(
188 &mut self,
189 map: &Map,
190 add_all: Vec<BlockID>,
191 new_owner: NeighbourhoodID,
192 ) -> Result<Option<NeighbourhoodID>> {
193 let mut new_owner_blocks = self.neighbourhood_to_blocks(new_owner);
195 new_owner_blocks.extend(add_all.clone());
196 let mut new_neighbourhood_blocks = self.make_merged_blocks(map, new_owner_blocks)?;
197 if new_neighbourhood_blocks.len() != 1 {
198 bail!("Couldn't add block -- you may need to add an intermediate block first to avoid a hole, or there's a bug you can't workaround yet. Try adding pink blocks first.");
201 }
202 let new_neighbourhood_block = new_neighbourhood_blocks.pop().unwrap();
203
204 let old_owners: BTreeSet<NeighbourhoodID> = add_all
205 .iter()
206 .map(|block| self.block_to_neighbourhood[block])
207 .collect();
208 let mut return_value = None;
210 for old_owner in old_owners {
211 let mut old_owner_blocks = self.neighbourhood_to_blocks(old_owner);
212 for x in &add_all {
213 old_owner_blocks.remove(x);
214 }
215 if old_owner_blocks.is_empty() {
216 self.neighbourhoods.remove(&old_owner).unwrap();
217 return_value = Some(new_owner);
218 continue;
219 }
220
221 let mut old_neighbourhood_blocks =
222 self.make_merged_blocks(map, old_owner_blocks.clone())?;
223 old_neighbourhood_blocks.sort_by_key(|block| block.perimeter.interior.len());
227 self.neighbourhoods.get_mut(&old_owner).unwrap().block =
228 old_neighbourhood_blocks.pop().unwrap();
229 let new_splits = !old_neighbourhood_blocks.is_empty();
230 for split_piece in old_neighbourhood_blocks {
231 let new_neighbourhood = NeighbourhoodID(self.neighbourhood_id_counter);
232 self.neighbourhood_id_counter += 1;
233 self.neighbourhoods
234 .insert(new_neighbourhood, NeighbourhoodInfo::new(split_piece));
235 }
236 if new_splits {
237 for id in old_owner_blocks {
239 self.block_to_neighbourhood
240 .insert(id, self.neighbourhood_containing(id).unwrap());
241 }
242 }
243 }
244
245 self.neighbourhoods.get_mut(&new_owner).unwrap().block = new_neighbourhood_block;
247 for id in add_all {
248 self.block_to_neighbourhood.insert(id, new_owner);
249 }
250 Ok(return_value)
251 }
252
253 pub fn remove_block_from_neighbourhood(
255 &mut self,
256 map: &Map,
257 id: BlockID,
258 ) -> Result<Option<NeighbourhoodID>> {
259 let old_owner = self.block_to_neighbourhood(id);
260 let current_perim_set: BTreeSet<RoadSideID> = self.neighbourhoods[&old_owner]
265 .block
266 .perimeter
267 .roads
268 .iter()
269 .cloned()
270 .collect();
271 for road_side in &self.get_block(id).perimeter.roads {
272 if !current_perim_set.contains(road_side) {
273 continue;
274 }
275 let other_side = road_side.other_side();
278 if let Some((new_owner, _)) = self
279 .neighbourhoods
280 .iter()
281 .find(|(_, info)| info.block.perimeter.roads.contains(&other_side))
282 {
283 return self.transfer_blocks(map, vec![id], *new_owner);
284 }
285 }
286
287 let new_owner = NeighbourhoodID(self.neighbourhood_id_counter);
290 self.neighbourhood_id_counter += 1;
291 self.neighbourhoods.insert(
292 new_owner,
293 NeighbourhoodInfo::new(self.get_block(id).clone()),
294 );
295 let result = self.transfer_blocks(map, vec![id], new_owner);
296 if result.is_err() {
297 self.neighbourhoods.remove(&new_owner).unwrap();
299 }
300 result
301 }
302}
303
304impl Partitioning {
306 pub fn neighbourhood_block(&self, id: NeighbourhoodID) -> &Block {
307 &self.neighbourhoods[&id].block
308 }
309
310 pub fn neighbourhood_area_km2(&self, id: NeighbourhoodID) -> String {
311 let area = if let Some(ref custom) = self.custom_boundaries.get(&id) {
313 custom.boundary_polygon.area()
314 } else {
315 self.neighbourhood_block(id).polygon.area()
316 };
317
318 let area = area / 1_000_000.0;
320 format!("~{:.1} km²", area)
321 }
322
323 pub fn get_info(&self, id: NeighbourhoodID) -> &NeighbourhoodInfo {
324 &self.neighbourhoods[&id]
325 }
326
327 pub fn override_neighbourhood_boundary_polygon(
328 &mut self,
329 id: NeighbourhoodID,
330 polygon: Polygon,
331 ) {
332 self.neighbourhoods
333 .get_mut(&id)
334 .unwrap()
335 .override_drawing_boundary = Some(polygon);
336 }
337
338 pub fn add_custom_boundary(&mut self, custom: CustomBoundary) -> NeighbourhoodID {
339 let id = NeighbourhoodID(self.neighbourhood_id_counter);
340 self.neighbourhood_id_counter += 1;
341 self.custom_boundaries.insert(id, custom);
342 id
343 }
344
345 pub fn all_neighbourhoods(&self) -> &BTreeMap<NeighbourhoodID, NeighbourhoodInfo> {
346 &self.neighbourhoods
347 }
348
349 fn neighbourhood_containing(&self, find_block: BlockID) -> Option<NeighbourhoodID> {
351 let find_block = self.get_block(find_block);
353 for (id, info) in &self.neighbourhoods {
354 if info.block.perimeter.contains(&find_block.perimeter) {
355 return Some(*id);
356 }
357 }
358 None
359 }
360
361 pub fn all_single_blocks(&self) -> Vec<(BlockID, &Block)> {
362 self.single_blocks
363 .iter()
364 .enumerate()
365 .map(|(idx, block)| (BlockID(idx), block))
366 .collect()
367 }
368
369 pub fn all_block_ids(&self) -> Vec<BlockID> {
370 (0..self.single_blocks.len()).map(BlockID).collect()
371 }
372
373 pub fn get_block(&self, id: BlockID) -> &Block {
374 &self.single_blocks[id.0]
375 }
376
377 pub fn block_to_neighbourhood(&self, id: BlockID) -> NeighbourhoodID {
378 self.block_to_neighbourhood[&id]
379 }
380
381 pub fn neighbourhood_to_blocks(&self, id: NeighbourhoodID) -> BTreeSet<BlockID> {
382 let mut result = BTreeSet::new();
383 for (block, n) in &self.block_to_neighbourhood {
384 if *n == id {
385 result.insert(*block);
386 }
387 }
388 result
389 }
390
391 pub fn some_block_in_neighbourhood(&self, id: NeighbourhoodID) -> BlockID {
392 for (block, neighbourhood) in &self.block_to_neighbourhood {
393 if id == *neighbourhood {
394 return *block;
395 }
396 }
397 unreachable!("{:?} has no blocks", id);
398 }
399
400 pub fn calculate_frontier(&self, perim: &Perimeter) -> BTreeSet<BlockID> {
402 let perim_roads: BTreeSet<RoadID> = perim.roads.iter().map(|id| id.road).collect();
403
404 let mut frontier = BTreeSet::new();
405 for (block_id, block) in self.all_single_blocks() {
406 for road_side_id in &block.perimeter.roads {
407 if perim_roads.contains(&road_side_id.road) {
410 frontier.insert(block_id);
411 break;
412 }
413 }
414 }
415 frontier
416 }
417
418 fn adjacent_blocks(&self, id: BlockID) -> BTreeSet<BlockID> {
419 let mut blocks = self.calculate_frontier(&self.get_block(id).perimeter);
420 blocks.retain(|x| *x != id);
421 blocks
422 }
423
424 fn make_merged_blocks(&self, map: &Map, input: BTreeSet<BlockID>) -> Result<Vec<Block>> {
427 let mut perimeters = Vec::new();
428 for id in input {
429 perimeters.push(self.get_block(id).perimeter.clone());
430 }
431 let mut blocks = Vec::new();
432 let stepwise_debug = false;
433 for perim in Perimeter::merge_all(map, perimeters, stepwise_debug) {
434 blocks.push(perim.to_block(map)?);
435 }
436 Ok(blocks)
437 }
438
439 pub fn find_intermediate_blocks(
442 &self,
443 new_owner: NeighbourhoodID,
444 target_block: BlockID,
445 ) -> Vec<BlockID> {
446 let adjacent_to_target_block = self.adjacent_blocks(target_block);
447 let _new_owner_frontier =
448 self.calculate_frontier(&self.neighbourhood_block(new_owner).perimeter);
449
450 let mut result = Vec::new();
451 for id in adjacent_to_target_block.clone() {
452 if self.block_to_neighbourhood[&id] == new_owner {
454 continue;
455 }
456
457 if self
466 .adjacent_blocks(id)
467 .into_iter()
468 .all(|x| x == target_block || adjacent_to_target_block.contains(&x))
469 {
470 result.push(id);
471 }
472 }
473
474 result
475 }
476}