mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-26 07:52:05 +03:00
drawing groups of parcels with different colors. very slow, since it's
done without a quadtree and every load
This commit is contained in:
parent
b1c74157d9
commit
e31061860b
@ -132,12 +132,6 @@
|
||||
0.3,
|
||||
1.0
|
||||
],
|
||||
"ParcelInterior": [
|
||||
0.694,
|
||||
0.941,
|
||||
0.725,
|
||||
1.0
|
||||
],
|
||||
"RoadOrientation": [
|
||||
1.0,
|
||||
1.0,
|
||||
|
@ -34,7 +34,6 @@ pub enum Colors {
|
||||
BuildingPath,
|
||||
BuildingBoundary,
|
||||
ParcelBoundary,
|
||||
ParcelInterior,
|
||||
RoadOrientation,
|
||||
SearchResult,
|
||||
Visited,
|
||||
|
@ -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()],
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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;
|
||||
|
64
map_model/src/make/parcels.rs
Normal file
64
map_model/src/make/parcels.rs
Normal 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(¤t) {
|
||||
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();
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user