drawing groups of parcels with different colors. very slow, since it's

done without a quadtree and every load
This commit is contained in:
Dustin Carlino 2018-08-06 11:33:06 -07:00
parent b1c74157d9
commit e31061860b
8 changed files with 106 additions and 9 deletions

View File

@ -132,12 +132,6 @@
0.3,
1.0
],
"ParcelInterior": [
0.694,
0.941,
0.725,
1.0
],
"RoadOrientation": [
1.0,
1.0,

View File

@ -34,7 +34,6 @@ pub enum Colors {
BuildingPath,
BuildingBoundary,
ParcelBoundary,
ParcelInterior,
RoadOrientation,
SearchResult,
Visited,

View File

@ -310,10 +310,27 @@ impl UI {
// Returns (boundary, fill) color
fn color_parcel(&self, id: map_model::ParcelID) -> (Color, Color) {
let _p = self.map.get_p(id);
const COLORS: [Color; 14] = [
// TODO these are awful choices
[1.0, 1.0, 0.0, 1.0],
[1.0, 0.0, 1.0, 1.0],
[0.0, 1.0, 1.0, 1.0],
[0.5, 0.2, 0.7, 1.0],
[0.5, 0.5, 0.0, 0.5],
[0.5, 0.0, 0.5, 0.5],
[0.0, 0.5, 0.5, 0.5],
[0.0, 0.0, 0.5, 0.5],
[0.3, 0.2, 0.5, 0.5],
[0.4, 0.2, 0.5, 0.5],
[0.5, 0.2, 0.5, 0.5],
[0.6, 0.2, 0.5, 0.5],
[0.7, 0.2, 0.5, 0.5],
[0.8, 0.2, 0.5, 0.5],
];
let p = self.map.get_p(id);
(
self.cs.get(Colors::ParcelBoundary),
self.cs.get(Colors::ParcelInterior),
COLORS[p.block % COLORS.len()],
)
}

View File

@ -1,6 +1,7 @@
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
use aabb_quadtree::geom::{Point, Rect};
use geo;
use geom::{Angle, Bounds, PolyLine, Pt2D};
use graphics::math::Vec2d;
use std::f64;
@ -114,3 +115,19 @@ pub fn regular_polygon(center: Pt2D, sides: usize, length: f64) -> Vec<Pt2D> {
pts.push(first_pt);
pts
}
pub fn polygons_intersect(pts1: &Vec<Pt2D>, pts2: &Vec<Pt2D>) -> bool {
use geo::prelude::Intersects;
let poly1 = geo::Polygon::new(
pts1.iter()
.map(|pt| geo::Point::new(pt.x(), pt.y()))
.collect(),
Vec::new());
let poly2 = geo::Polygon::new(
pts2.iter()
.map(|pt| geo::Point::new(pt.x(), pt.y()))
.collect(),
Vec::new());
poly1.intersects(&poly2)
}

View File

@ -1,5 +1,6 @@
mod buildings;
mod lanes;
mod parcels;
mod trim_lines;
mod turns;
@ -7,3 +8,4 @@ pub(crate) use self::buildings::make_building;
pub(crate) use self::lanes::get_lane_specs;
pub(crate) use self::trim_lines::trim_lines;
pub(crate) use self::turns::make_all_turns;
pub(crate) use self::parcels::group_parcels;

View File

@ -0,0 +1,64 @@
use {Parcel, ParcelID, geometry};
use std::collections::BTreeSet;
use abstutil::MultiMap;
pub fn group_parcels(parcels: &mut Vec<Parcel>) {
// First compute which parcels intersect
let mut adjacency: MultiMap<ParcelID, ParcelID> = MultiMap::new();
// TODO could use quadtree to prune
println!("Precomputing adjacency between {} parcels...", parcels.len());
let mut adj_counter = 0;
for p1 in parcels.iter() {
for p2 in parcels.iter() {
if p1.id < p2.id && geometry::polygons_intersect(&p1.points, &p2.points) {
// TODO could do something more clever later to avoid double memory
adjacency.insert(p1.id, p2.id);
adjacency.insert(p2.id, p1.id);
adj_counter += 1;
}
}
}
println!("{} adjacencies, now doing floodfilling to group them", adj_counter);
// Union-find might also be good inspiration.
fn floodfill(from: ParcelID, adj: &MultiMap<ParcelID, ParcelID>) -> BTreeSet<ParcelID> {
let mut visited: BTreeSet<ParcelID> = BTreeSet::new();
let mut queue: Vec<ParcelID> = vec![from];
while !queue.is_empty() {
let current = queue.pop().unwrap();
if visited.contains(&current) {
continue;
}
visited.insert(current);
for next in adj.get(current).iter() {
queue.push(*next);
}
}
visited
}
let mut block_per_parcel: Vec<Option<usize>> = Vec::new();
for _ in parcels.iter() {
block_per_parcel.push(None);
}
let mut block_counter = 0;
for base_p in parcels.iter() {
// A previous iteration might have filled it out
if block_per_parcel[base_p.id.0].is_some() {
continue;
}
let new_block = Some(block_counter);
block_counter += 1;
for p in floodfill(base_p.id, &adjacency).iter() {
assert!(!block_per_parcel[p.0].is_some());
block_per_parcel[p.0] = new_block;
}
}
println!("{} parcels grouped into {} blocks", parcels.len(), block_counter);
for (idx, block) in block_per_parcel.iter().enumerate() {
parcels[idx].block = block.unwrap();
}
}

View File

@ -161,8 +161,10 @@ impl Map {
.iter()
.map(|coord| Pt2D::from_gps(coord, &bounds))
.collect(),
block: 0,
});
}
make::group_parcels(&mut m.parcels);
Ok(m)
}

View File

@ -17,6 +17,8 @@ impl fmt::Display for ParcelID {
pub struct Parcel {
pub id: ParcelID,
pub points: Vec<Pt2D>,
// All parcels of the same block have the same number.
pub block: usize,
}
impl PartialEq for Parcel {