mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-24 06:55:40 +03:00
dismantle importing for neighborhoods. long unused. just retain a simple
osmosis polygon editor.
This commit is contained in:
parent
270c7d0712
commit
02c5b6617b
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -421,7 +421,6 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"abstutil 0.1.0",
|
||||
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"geojson 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"geom 0.1.0",
|
||||
"gtfs 0.1.0",
|
||||
"kml 0.1.0",
|
||||
@ -1070,16 +1069,6 @@ dependencies = [
|
||||
"rstar 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "geojson"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "geom"
|
||||
version = "0.1.0"
|
||||
@ -3903,7 +3892,6 @@ dependencies = [
|
||||
"checksum geo-booleanop 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "70960413106c9090485c939666475f7862fa13cef7d07f866320a5833b3ca871"
|
||||
"checksum geo-offset 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "563c564777dda10493aed3ff3d92f9a5e40b924b3d63a4c1540b47c97dbd47b2"
|
||||
"checksum geo-types 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "866e8f6dbd2218b05ea8a25daa1bfac32b0515fe7e0a37cb6a7b9ed0ed82a07e"
|
||||
"checksum geojson 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e4ac03428b3276fc7f1756eba0c76c7c0c91ef77e1c43fbdd47a460238419cb9"
|
||||
"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
||||
"checksum git2 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c1af51ea8a906616af45a4ce78eacf25860f7a13ae7bf8a814693f0f4037a26"
|
||||
"checksum gl_generator 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ca98bbde17256e02d17336a6bdb5a50f7d0ccacee502e191d3e3d0ec2f96f84a"
|
||||
|
@ -149,16 +149,6 @@ pub fn path_fixes(city: &str, map: &str) -> String {
|
||||
format!("../data/input/{}/fixes/{}.json", city, map)
|
||||
}
|
||||
|
||||
pub fn path_neighborhood(city_name: &str, map_name: &str, neighborhood: &str) -> String {
|
||||
format!(
|
||||
"../data/input/{}/neighborhoods/{}/{}.json",
|
||||
city_name, map_name, neighborhood
|
||||
)
|
||||
}
|
||||
pub fn path_all_neighborhoods(city_name: &str, map_name: &str) -> String {
|
||||
format!("../data/input/{}/neighborhoods/{}", city_name, map_name)
|
||||
}
|
||||
|
||||
pub fn path_pending_screenshots(map_name: &str) -> String {
|
||||
format!("../data/input/screenshots/pending_{}", map_name)
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ edition = "2018"
|
||||
[dependencies]
|
||||
abstutil = { path = "../abstutil" }
|
||||
byteorder = "1.3.4"
|
||||
geojson = "0.17.0"
|
||||
geom = { path = "../geom" }
|
||||
gtfs = { path = "../gtfs" }
|
||||
kml = { path = "../kml" }
|
||||
|
@ -1,5 +1,4 @@
|
||||
mod clip;
|
||||
mod neighborhoods;
|
||||
mod osm_reader;
|
||||
mod split_ways;
|
||||
mod srtm;
|
||||
@ -24,7 +23,6 @@ pub struct Options {
|
||||
pub private_offstreet_parking: PrivateOffstreetParking,
|
||||
pub sidewalks: Option<String>,
|
||||
pub gtfs: Option<String>,
|
||||
pub neighborhoods: Option<String>,
|
||||
pub elevation: Option<String>,
|
||||
pub clip: Option<String>,
|
||||
pub drive_on_right: bool,
|
||||
@ -81,17 +79,6 @@ pub fn convert(opts: Options, timer: &mut abstutil::Timer) -> RawMap {
|
||||
use_elevation(&mut map, path, timer);
|
||||
}
|
||||
|
||||
if let Some(ref path) = opts.neighborhoods {
|
||||
timer.start("convert neighborhood polygons");
|
||||
neighborhoods::convert(
|
||||
path.clone(),
|
||||
map.city_name.clone(),
|
||||
map.name.clone(),
|
||||
&map.gps_bounds,
|
||||
);
|
||||
timer.stop("convert neighborhood polygons");
|
||||
}
|
||||
|
||||
map
|
||||
}
|
||||
|
||||
|
@ -1,69 +0,0 @@
|
||||
use abstutil::Timer;
|
||||
use geojson::{GeoJson, PolygonType, Value};
|
||||
use geom::{GPSBounds, LonLat};
|
||||
use map_model::NeighborhoodBuilder;
|
||||
|
||||
pub fn convert(geojson_path: String, city_name: String, map_name: String, gps_bounds: &GPSBounds) {
|
||||
println!("Extracting neighborhoods from {}...", geojson_path);
|
||||
let document: GeoJson = abstutil::read_json(geojson_path, &mut Timer::throwaway());
|
||||
match document {
|
||||
GeoJson::FeatureCollection(c) => {
|
||||
for f in c.features.into_iter() {
|
||||
let name = f.properties.unwrap()["name"].as_str().unwrap().to_string();
|
||||
match f.geometry.unwrap().value {
|
||||
Value::Polygon(p) => {
|
||||
convert_polygon(p, name, city_name.clone(), map_name.clone(), gps_bounds);
|
||||
}
|
||||
Value::MultiPolygon(polygons) => {
|
||||
for (idx, p) in polygons.into_iter().enumerate() {
|
||||
convert_polygon(
|
||||
p,
|
||||
format!("{} portion #{}", name, idx + 1),
|
||||
city_name.clone(),
|
||||
map_name.clone(),
|
||||
gps_bounds,
|
||||
);
|
||||
}
|
||||
}
|
||||
x => panic!("Unexpected GeoJson value {:?}", x),
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => panic!("Unexpected GeoJson root {:?}", document),
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_polygon(
|
||||
input: PolygonType,
|
||||
name: String,
|
||||
city_name: String,
|
||||
map_name: String,
|
||||
gps_bounds: &GPSBounds,
|
||||
) {
|
||||
if input.len() > 1 {
|
||||
println!("{} has a polygon with an inner ring, skipping", name);
|
||||
return;
|
||||
}
|
||||
|
||||
let mut points: Vec<LonLat> = Vec::new();
|
||||
for raw_pt in &input[0] {
|
||||
assert_eq!(raw_pt.len(), 2);
|
||||
let pt = LonLat::new(raw_pt[0], raw_pt[1]);
|
||||
if gps_bounds.contains(pt) {
|
||||
points.push(pt);
|
||||
} else {
|
||||
println!(
|
||||
"Neighborhood polygon \"{}\" is out-of-bounds, skipping",
|
||||
name
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
NeighborhoodBuilder {
|
||||
city_name,
|
||||
map_name,
|
||||
name,
|
||||
points,
|
||||
}
|
||||
.save();
|
||||
}
|
@ -8,87 +8,8 @@ ab122e013e18d9bfe923162ad27deb54 data/input/seattle/osm/ballard.osm
|
||||
f17e480bd803309c92d58c96bebb0ca1 data/input/seattle/osm/caphill.osm
|
||||
c3198bbcdf00c4cdcc429d4679d68202 data/input/seattle/osm/lakeslice.osm
|
||||
0052ec465666b0c49ef1d1221c9e3a53 data/input/seattle/osm/Seattle.osm
|
||||
46d8ebc909717b5ddfe921cf487f975d data/input/seattle/neighborhoods/ballard/West Woodland.json
|
||||
ba915a6237156522eac2f380e978bb25 data/input/seattle/neighborhoods/ballard/Adams.json
|
||||
ae6e3c5801460075cebe736e56d98b01 data/input/seattle/neighborhoods/ballard/Phinney Ridge.json
|
||||
886cff1b9508af1917d76d746336c961 data/input/seattle/neighborhoods/ballard/Fremont.json
|
||||
ae8a868fe3eac6c67340f174dc24866a data/input/seattle/neighborhoods/ballard/Lawton Park.json
|
||||
1e2ff5d0083b0e5aab885d38be992ad7 data/input/seattle/neighborhoods/intl_district/International District.json
|
||||
721155dd7662b9aaaf68b222aa731560 data/input/seattle/neighborhoods/x1/Harrison - Denny-Blaine.json
|
||||
2e9dbd878640b904307dcadc1fd7334f data/input/seattle/neighborhoods/x1/Madison Park.json
|
||||
f2b26082d44df01339f30d1cc2eb4178 data/input/seattle/neighborhoods/x1/Portage Bay.json
|
||||
197ecdfed33e300e6f64275a896b2905 data/input/seattle/neighborhoods/x1/Eastlake.json
|
||||
33128005e7f6caaab5d321558965f125 data/input/seattle/neighborhoods/x1/Broadway.json
|
||||
a5dca5dd4a4b78efb17e69c2d557ab1b data/input/seattle/neighborhoods/x1/Stevens.json
|
||||
519cbc4a6c2038fab9df172f2db63085 data/input/seattle/neighborhoods/x1/Montlake.json
|
||||
ae65aaa3a0ddb7bb990972c9832369b6 data/input/seattle/neighborhoods/23rd/Mann.json
|
||||
d9e0bc911a52aa15f51cb49956d2aef5 data/input/seattle/neighborhoods/lakeslice/Leschi.json
|
||||
1ac65f96b8f4a2b2d365949032966402 data/input/seattle/neighborhoods/lakeslice/Harrison - Denny-Blaine.json
|
||||
7b5a6df2a313b997e1ac575f6cec03d6 data/input/seattle/neighborhoods/lakeslice/Mann.json
|
||||
eb073e33d652161805fd42c982856703 data/input/seattle/neighborhoods/lakeslice/Madrona.json
|
||||
e62769afe799c43dbbe73e164e6bd620 data/input/seattle/neighborhoods/downtown/Pike-Market.json
|
||||
d02cb65749922832091b18ad45a4400e data/input/seattle/neighborhoods/downtown/First Hill.json
|
||||
64073270987303abf1532e6abaaa2676 data/input/seattle/neighborhoods/downtown/Central Business District.json
|
||||
2374dd1b296f7bffa436e14ff2ddcd36 data/input/seattle/neighborhoods/downtown/Belltown.json
|
||||
796f5d8eb1a5f1bfe85b2945239e14de data/input/seattle/neighborhoods/huge_seattle/West Woodland.json
|
||||
8f586abbc7c18ee104493f7f83d88b20 data/input/seattle/neighborhoods/huge_seattle/Westlake.json
|
||||
778beb76a0f0f2c4e5f71e56f6a37076 data/input/seattle/neighborhoods/huge_seattle/North College Park.json
|
||||
21376d86306c45e82ddbbc4acd62a3ce data/input/seattle/neighborhoods/huge_seattle/Lower Queen Anne.json
|
||||
90e78679efe05bb5c51c095bd56df8db data/input/seattle/neighborhoods/huge_seattle/Adams.json
|
||||
7d2570e9728af1313c0af70b35ff7c12 data/input/seattle/neighborhoods/huge_seattle/Leschi.json
|
||||
02e25d6d76d0a9b8823e8783d01d499b data/input/seattle/neighborhoods/huge_seattle/University District.json
|
||||
4c9c0bbd2c4d30166cc82b6c9291de78 data/input/seattle/neighborhoods/huge_seattle/Pike-Market.json
|
||||
2ff1b7b76f126ed69227923d40ecdaa3 data/input/seattle/neighborhoods/huge_seattle/Harrison - Denny-Blaine.json
|
||||
a65a48ca68f15635fd86e7fdd06ddaea data/input/seattle/neighborhoods/huge_seattle/Roosevelt.json
|
||||
57103a4893df8c1667674d8de47bee0b data/input/seattle/neighborhoods/huge_seattle/Whittier Heights.json
|
||||
9cb7a0ef7a3bcdb634681e21d2f6fea3 data/input/seattle/neighborhoods/huge_seattle/Laurelhurst.json
|
||||
cb93fd55d3b42979a96dc45e5571f5ac data/input/seattle/neighborhoods/huge_seattle/International District.json
|
||||
9f04e6fa311b2274a42ee4b29f11d4e8 data/input/seattle/neighborhoods/huge_seattle/Maple Leaf.json
|
||||
a8d1df39941171daa16195cc98692907 data/input/seattle/neighborhoods/huge_seattle/First Hill.json
|
||||
b7fcb8b06ce4f571849fd33a277d21af data/input/seattle/neighborhoods/huge_seattle/Madison Park.json
|
||||
c45186b872050db02e053afcf4a7424e data/input/seattle/neighborhoods/huge_seattle/Portage Bay.json
|
||||
b4f6a4f24dab7eed34347069748ed6ce data/input/seattle/neighborhoods/huge_seattle/Central Business District.json
|
||||
ffcca5e408c97cb81d1f739816809e01 data/input/seattle/neighborhoods/huge_seattle/South Lake Union.json
|
||||
db4b1be3343681f5bcd8115181f95f08 data/input/seattle/neighborhoods/huge_seattle/Greenwood.json
|
||||
6d50b3ae6f11de62b44e6109a435d002 data/input/seattle/neighborhoods/huge_seattle/Eastlake.json
|
||||
b809cb0eb9a77a138c447d92d2a036ad data/input/seattle/neighborhoods/huge_seattle/Sunset Hill.json
|
||||
1c27ea07ae9f046e79bdd79a0dbc4863 data/input/seattle/neighborhoods/huge_seattle/Broadway.json
|
||||
a205318630171b21d3d8172c44a973d1 data/input/seattle/neighborhoods/huge_seattle/Phinney Ridge.json
|
||||
02c097d984b9e039b7b9912f03ddf717 data/input/seattle/neighborhoods/huge_seattle/Ravenna.json
|
||||
fc6dc3658c5d9cb01d778db3026731c6 data/input/seattle/neighborhoods/huge_seattle/Fremont.json
|
||||
14b37651f6259ba8ed8f7dc04a93245b data/input/seattle/neighborhoods/huge_seattle/Yesler Terrace.json
|
||||
a3b74ad210d5ae94c8fb8a23ffd7b521 data/input/seattle/neighborhoods/huge_seattle/Wedgwood.json
|
||||
f60c9d7699b39ed6d99109ff0a4b7ee9 data/input/seattle/neighborhoods/huge_seattle/Sand Point.json
|
||||
7957979d53d4a6364b9020a119c1f9e9 data/input/seattle/neighborhoods/huge_seattle/Wallingford.json
|
||||
c642b472850a444e1d436a3dc8de5c57 data/input/seattle/neighborhoods/huge_seattle/Interbay.json
|
||||
b19598d61c1301e4573edd927fb4ba38 data/input/seattle/neighborhoods/huge_seattle/West Queen Anne.json
|
||||
331b23ca4b2d94d6e38026dfd7dfc386 data/input/seattle/neighborhoods/huge_seattle/Southeast Magnolia.json
|
||||
b89543b001bc1e6f7ec5afda712a9532 data/input/seattle/neighborhoods/huge_seattle/North Beach - Blue Ridge.json
|
||||
0f8511e1759b3150d77752aa9608ddd5 data/input/seattle/neighborhoods/huge_seattle/Windermere.json
|
||||
c9fe0cec21b4506b9449f8e286707f62 data/input/seattle/neighborhoods/huge_seattle/Stevens.json
|
||||
8f1b6913ee7ddee6c3ad6762077e1940 data/input/seattle/neighborhoods/huge_seattle/East Queen Anne.json
|
||||
3f1e1d2473fcd9909ed48885156d8ad9 data/input/seattle/neighborhoods/huge_seattle/Belltown.json
|
||||
7148acd286b453d20db96ad3a8461727 data/input/seattle/neighborhoods/huge_seattle/Loyal Heights.json
|
||||
14c4caa74a3aab96b3270c9add7c8019 data/input/seattle/neighborhoods/huge_seattle/Mann.json
|
||||
af28f6e4b3ef367fed0d828a47e5208d data/input/seattle/neighborhoods/huge_seattle/View Ridge.json
|
||||
05ca8b996e144d45ae49961638e37135 data/input/seattle/neighborhoods/huge_seattle/Minor.json
|
||||
4b0347aeed2ad2e3cf3b71a07efba3e0 data/input/seattle/neighborhoods/huge_seattle/Madrona.json
|
||||
baa4ebb40bc293c6176a3239620e7183 data/input/seattle/neighborhoods/huge_seattle/Lawton Park.json
|
||||
78b4d30d5bb4e7e8a40c7728124fd890 data/input/seattle/neighborhoods/huge_seattle/Montlake.json
|
||||
271892c6453b6e0d512f948d9b7de62a data/input/seattle/neighborhoods/huge_seattle/Briarcliff.json
|
||||
92d4c74df6478e29cdb0281ba4ff7894 data/input/seattle/neighborhoods/huge_seattle/North Queen Anne.json
|
||||
9666b4689a2927797fe865becd6f61b7 data/input/seattle/neighborhoods/huge_seattle/Pioneer Square.json
|
||||
18ae58793ddede2c087dbc7f9876266a data/input/seattle/neighborhoods/huge_seattle/Crown Hill.json
|
||||
d729d8ef4f797d51dbb53096a4aac233 data/input/seattle/neighborhoods/huge_seattle/Green Lake.json
|
||||
4be236f94749a0325f9696d0ed051e85 data/input/seattle/neighborhoods/huge_seattle/Bryant.json
|
||||
1e608dafe6199b70929bb6bae84ead30 data/input/seattle/neighborhoods/caphill/Portage Bay.json
|
||||
82c31490f1c0b5f7ab2e75766c8a9e04 data/input/seattle/neighborhoods/caphill/Eastlake.json
|
||||
790ca481f2ea517acd63c97cc58b4d10 data/input/seattle/neighborhoods/caphill/Broadway.json
|
||||
2b5fe53d1566708e1484181f026a77db data/input/seattle/neighborhoods/caphill/Stevens.json
|
||||
96794d4b0d55abbacc48ff2df9941230 data/input/seattle/neighborhoods/caphill/Montlake.json
|
||||
19e8073a9f6c807b4492681b2c7570de data/input/seattle/blockface.bin
|
||||
db63d7d606e8702d12f9399e87e6a00f data/input/seattle/parcels_urbansim.txt
|
||||
2bc84e4d194d7cea6007ae3b93f3b11b data/input/seattle/neighborhoods.geojson
|
||||
7cbf604cb6d080292a5e69fdf0caf3b3 data/input/seattle/popdat.bin
|
||||
428bc2e92ea02089cedbb614ce1d8f25 data/input/seattle/polygons/caphill.poly
|
||||
4f291bbe84ac32a98d7d100be79ddc4b data/input/seattle/polygons/huge_seattle.poly
|
||||
|
@ -1,5 +1,5 @@
|
||||
mod blocks;
|
||||
mod neighborhood;
|
||||
mod polygon;
|
||||
mod scenario;
|
||||
|
||||
use crate::app::App;
|
||||
@ -19,18 +19,14 @@ impl DevToolsMode {
|
||||
"Internal dev tools",
|
||||
vec![],
|
||||
vec![
|
||||
(hotkey(Key::N), "manage neighborhoods"),
|
||||
(hotkey(Key::P), "draw a polygon"),
|
||||
(hotkey(Key::W), "load scenario"),
|
||||
],
|
||||
))
|
||||
.cb("X", Box::new(|_, _| Some(Transition::Pop)))
|
||||
.cb(
|
||||
"manage neighborhoods",
|
||||
Box::new(|_, _| {
|
||||
Some(Transition::Push(Box::new(
|
||||
neighborhood::NeighborhoodPicker::new(),
|
||||
)))
|
||||
}),
|
||||
"draw a polygon",
|
||||
Box::new(|ctx, app| Some(Transition::Push(polygon::PolygonEditor::new(ctx, app)))),
|
||||
)
|
||||
.cb(
|
||||
"load scenario",
|
||||
|
@ -1,228 +0,0 @@
|
||||
use crate::app::App;
|
||||
use crate::common::CommonState;
|
||||
use crate::game::{State, Transition};
|
||||
use crate::managed::WrappedComposite;
|
||||
use ezgui::{
|
||||
hotkey, Choice, Color, Composite, EventCtx, GfxCtx, Key, Line, Outcome, Text, Wizard,
|
||||
WrappedWizard,
|
||||
};
|
||||
use geom::{Circle, Distance, Polygon, Pt2D};
|
||||
use map_model::{Map, NeighborhoodBuilder};
|
||||
|
||||
const POINT_RADIUS: Distance = Distance::const_meters(10.0);
|
||||
// Localized and internal, so don't put in ColorScheme.
|
||||
const POINT_COLOR: Color = Color::RED;
|
||||
const POLYGON_COLOR: Color = Color::BLUE.alpha(0.6);
|
||||
const POINT_TO_MOVE: Color = Color::CYAN;
|
||||
const LAST_PLACED_POINT: Color = Color::GREEN;
|
||||
|
||||
// This shouldn't get subsumed by WizardState, since it has such an interesting draw().
|
||||
pub struct NeighborhoodPicker {
|
||||
wizard: Wizard,
|
||||
}
|
||||
|
||||
impl NeighborhoodPicker {
|
||||
pub fn new() -> NeighborhoodPicker {
|
||||
NeighborhoodPicker {
|
||||
wizard: Wizard::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl State for NeighborhoodPicker {
|
||||
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition {
|
||||
ctx.canvas_movement();
|
||||
|
||||
if let Some(n) = pick_neighborhood(&app.primary.map, self.wizard.wrap(ctx)) {
|
||||
self.wizard = Wizard::new();
|
||||
return Transition::Push(Box::new(NeighborhoodEditor {
|
||||
composite: WrappedComposite::quick_menu(
|
||||
ctx,
|
||||
app,
|
||||
format!("Neighborhood Editor for {}", n.name),
|
||||
vec![],
|
||||
vec![
|
||||
(hotkey(Key::S), "save"),
|
||||
(hotkey(Key::X), "export as an Osmosis polygon filter"),
|
||||
],
|
||||
),
|
||||
neighborhood: n,
|
||||
mouseover_pt: None,
|
||||
moving_pt: false,
|
||||
}));
|
||||
} else if self.wizard.aborted() {
|
||||
return Transition::Pop;
|
||||
}
|
||||
Transition::Keep
|
||||
}
|
||||
|
||||
fn draw(&self, g: &mut GfxCtx, app: &App) {
|
||||
// TODO is this order wrong?
|
||||
self.wizard.draw(g);
|
||||
if let Some(neighborhood) = self.wizard.current_menu_choice::<NeighborhoodBuilder>() {
|
||||
g.draw_polygon(
|
||||
POLYGON_COLOR,
|
||||
&Polygon::new(
|
||||
&app.primary
|
||||
.map
|
||||
.get_gps_bounds()
|
||||
.must_convert(&neighborhood.points),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct NeighborhoodEditor {
|
||||
composite: Composite,
|
||||
neighborhood: NeighborhoodBuilder,
|
||||
mouseover_pt: Option<usize>,
|
||||
moving_pt: bool,
|
||||
}
|
||||
|
||||
impl State for NeighborhoodEditor {
|
||||
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition {
|
||||
let gps_bounds = app.primary.map.get_gps_bounds();
|
||||
|
||||
ctx.canvas_movement();
|
||||
|
||||
if self.moving_pt {
|
||||
if let Some(pt) = ctx
|
||||
.canvas
|
||||
.get_cursor_in_map_space()
|
||||
.and_then(|c| c.to_gps(gps_bounds))
|
||||
{
|
||||
self.neighborhood.points[self.mouseover_pt.unwrap()] = pt;
|
||||
}
|
||||
if ctx.input.key_released(Key::LeftControl) {
|
||||
self.moving_pt = false;
|
||||
}
|
||||
|
||||
return Transition::Keep;
|
||||
}
|
||||
|
||||
match self.composite.event(ctx) {
|
||||
Some(Outcome::Clicked(x)) => match x.as_ref() {
|
||||
"X" => {
|
||||
return Transition::Pop;
|
||||
}
|
||||
"save" => {
|
||||
if self.neighborhood.points.len() >= 3 {
|
||||
self.neighborhood.save();
|
||||
}
|
||||
}
|
||||
"export as an Osmosis polygon filter" => {
|
||||
if self.neighborhood.points.len() >= 3 {
|
||||
self.neighborhood.save_as_osmosis().unwrap();
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
None => {}
|
||||
}
|
||||
|
||||
if let Some(cursor) = ctx.canvas.get_cursor_in_map_space() {
|
||||
self.mouseover_pt = self.neighborhood.points.iter().position(|pt| {
|
||||
Circle::new(
|
||||
Pt2D::from_gps(*pt, gps_bounds).unwrap(),
|
||||
POINT_RADIUS / ctx.canvas.cam_zoom,
|
||||
)
|
||||
.contains_pt(cursor)
|
||||
});
|
||||
} else {
|
||||
self.mouseover_pt = None;
|
||||
}
|
||||
// TODO maybe click-and-drag is more intuitive
|
||||
if self.mouseover_pt.is_some() {
|
||||
if ctx
|
||||
.input
|
||||
.key_pressed(Key::LeftControl, "hold to move this point")
|
||||
{
|
||||
self.moving_pt = true;
|
||||
}
|
||||
} else if let Some(pt) = ctx
|
||||
.canvas
|
||||
.get_cursor_in_map_space()
|
||||
.and_then(|c| c.to_gps(gps_bounds))
|
||||
{
|
||||
if app.per_obj.left_click(ctx, "add a new point") {
|
||||
self.neighborhood.points.push(pt);
|
||||
}
|
||||
}
|
||||
|
||||
Transition::Keep
|
||||
}
|
||||
|
||||
fn draw(&self, g: &mut GfxCtx, app: &App) {
|
||||
let pts: Vec<Pt2D> = app
|
||||
.primary
|
||||
.map
|
||||
.get_gps_bounds()
|
||||
.must_convert(&self.neighborhood.points);
|
||||
|
||||
if pts.len() == 2 {
|
||||
g.draw_line(
|
||||
POINT_COLOR,
|
||||
POINT_RADIUS / 2.0,
|
||||
&geom::Line::new(pts[0], pts[1]),
|
||||
);
|
||||
}
|
||||
if pts.len() >= 3 {
|
||||
g.draw_polygon(POLYGON_COLOR, &Polygon::new(&pts));
|
||||
}
|
||||
for (idx, pt) in pts.iter().enumerate() {
|
||||
let color = if Some(idx) == self.mouseover_pt {
|
||||
POINT_TO_MOVE
|
||||
} else if idx == pts.len() - 1 {
|
||||
LAST_PLACED_POINT
|
||||
} else {
|
||||
POINT_COLOR
|
||||
};
|
||||
g.draw_circle(color, &Circle::new(*pt, POINT_RADIUS / g.canvas.cam_zoom));
|
||||
}
|
||||
|
||||
self.composite.draw(g);
|
||||
if self.mouseover_pt.is_some() {
|
||||
CommonState::draw_custom_osd(
|
||||
g,
|
||||
app,
|
||||
Text::from(Line("hold left Control to move point")),
|
||||
);
|
||||
} else {
|
||||
CommonState::draw_osd(g, app, &None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn pick_neighborhood(map: &Map, mut wizard: WrappedWizard) -> Option<NeighborhoodBuilder> {
|
||||
let load_existing = "Load existing neighborhood";
|
||||
let create_new = "Create new neighborhood";
|
||||
if wizard.choose_string("What neighborhood to edit?", || {
|
||||
vec![load_existing, create_new]
|
||||
})? == load_existing
|
||||
{
|
||||
load_neighborhood_builder(map, &mut wizard, "Load which neighborhood?")
|
||||
} else {
|
||||
let name = wizard.input_string("Name the neighborhood")?;
|
||||
Some(NeighborhoodBuilder {
|
||||
city_name: map.get_city_name().to_string(),
|
||||
name,
|
||||
map_name: map.get_name().to_string(),
|
||||
points: Vec::new(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn load_neighborhood_builder(
|
||||
map: &Map,
|
||||
wizard: &mut WrappedWizard,
|
||||
query: &str,
|
||||
) -> Option<NeighborhoodBuilder> {
|
||||
wizard
|
||||
.choose(query, || {
|
||||
Choice::from(abstutil::load_all_objects(
|
||||
abstutil::path_all_neighborhoods(map.get_city_name(), map.get_name()),
|
||||
))
|
||||
})
|
||||
.map(|(_, n)| n)
|
||||
}
|
165
game/src/devtools/polygon.rs
Normal file
165
game/src/devtools/polygon.rs
Normal file
@ -0,0 +1,165 @@
|
||||
use crate::app::App;
|
||||
use crate::common::CommonState;
|
||||
use crate::game::{State, Transition};
|
||||
use crate::managed::WrappedComposite;
|
||||
use ezgui::{hotkey, Color, Composite, EventCtx, GfxCtx, Key, Line, Outcome, Text};
|
||||
use geom::{Circle, Distance, LonLat, Polygon, Pt2D};
|
||||
use std::fs::File;
|
||||
use std::io::{Error, Write};
|
||||
|
||||
const POINT_RADIUS: Distance = Distance::const_meters(10.0);
|
||||
// Localized and internal, so don't put in ColorScheme.
|
||||
const POINT_COLOR: Color = Color::RED;
|
||||
const POLYGON_COLOR: Color = Color::BLUE.alpha(0.6);
|
||||
const POINT_TO_MOVE: Color = Color::CYAN;
|
||||
const LAST_PLACED_POINT: Color = Color::GREEN;
|
||||
|
||||
pub struct PolygonEditor {
|
||||
composite: Composite,
|
||||
points: Vec<LonLat>,
|
||||
mouseover_pt: Option<usize>,
|
||||
moving_pt: bool,
|
||||
}
|
||||
|
||||
impl PolygonEditor {
|
||||
pub fn new(ctx: &mut EventCtx, app: &App) -> Box<dyn State> {
|
||||
Box::new(PolygonEditor {
|
||||
composite: WrappedComposite::quick_menu(
|
||||
ctx,
|
||||
app,
|
||||
"Polygon editor",
|
||||
vec![],
|
||||
vec![(hotkey(Key::X), "export as an Osmosis polygon filter")],
|
||||
),
|
||||
points: Vec::new(),
|
||||
mouseover_pt: None,
|
||||
moving_pt: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl State for PolygonEditor {
|
||||
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition {
|
||||
let gps_bounds = app.primary.map.get_gps_bounds();
|
||||
|
||||
ctx.canvas_movement();
|
||||
|
||||
if self.moving_pt {
|
||||
if let Some(pt) = ctx
|
||||
.canvas
|
||||
.get_cursor_in_map_space()
|
||||
.and_then(|c| c.to_gps(gps_bounds))
|
||||
{
|
||||
self.points[self.mouseover_pt.unwrap()] = pt;
|
||||
}
|
||||
if ctx.input.key_released(Key::LeftControl) {
|
||||
self.moving_pt = false;
|
||||
}
|
||||
|
||||
return Transition::Keep;
|
||||
}
|
||||
|
||||
match self.composite.event(ctx) {
|
||||
Some(Outcome::Clicked(x)) => match x.as_ref() {
|
||||
"X" => {
|
||||
return Transition::Pop;
|
||||
}
|
||||
"export as an Osmosis polygon filter" => {
|
||||
if self.points.len() >= 3 {
|
||||
save_as_osmosis(&self.points);
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
None => {}
|
||||
}
|
||||
|
||||
if let Some(cursor) = ctx.canvas.get_cursor_in_map_space() {
|
||||
self.mouseover_pt = self.points.iter().position(|pt| {
|
||||
Circle::new(
|
||||
Pt2D::from_gps(*pt, gps_bounds).unwrap(),
|
||||
POINT_RADIUS / ctx.canvas.cam_zoom,
|
||||
)
|
||||
.contains_pt(cursor)
|
||||
});
|
||||
} else {
|
||||
self.mouseover_pt = None;
|
||||
}
|
||||
// TODO maybe click-and-drag is more intuitive
|
||||
if self.mouseover_pt.is_some() {
|
||||
if ctx
|
||||
.input
|
||||
.key_pressed(Key::LeftControl, "hold to move this point")
|
||||
{
|
||||
self.moving_pt = true;
|
||||
}
|
||||
} else if let Some(pt) = ctx
|
||||
.canvas
|
||||
.get_cursor_in_map_space()
|
||||
.and_then(|c| c.to_gps(gps_bounds))
|
||||
{
|
||||
if app.per_obj.left_click(ctx, "add a new point") {
|
||||
self.points.push(pt);
|
||||
}
|
||||
}
|
||||
|
||||
Transition::Keep
|
||||
}
|
||||
|
||||
fn draw(&self, g: &mut GfxCtx, app: &App) {
|
||||
let pts: Vec<Pt2D> = app.primary.map.get_gps_bounds().must_convert(&self.points);
|
||||
|
||||
if pts.len() == 2 {
|
||||
g.draw_line(
|
||||
POINT_COLOR,
|
||||
POINT_RADIUS / 2.0,
|
||||
&geom::Line::new(pts[0], pts[1]),
|
||||
);
|
||||
}
|
||||
if pts.len() >= 3 {
|
||||
g.draw_polygon(POLYGON_COLOR, &Polygon::new(&pts));
|
||||
}
|
||||
for (idx, pt) in pts.iter().enumerate() {
|
||||
let color = if Some(idx) == self.mouseover_pt {
|
||||
POINT_TO_MOVE
|
||||
} else if idx == pts.len() - 1 {
|
||||
LAST_PLACED_POINT
|
||||
} else {
|
||||
POINT_COLOR
|
||||
};
|
||||
g.draw_circle(color, &Circle::new(*pt, POINT_RADIUS / g.canvas.cam_zoom));
|
||||
}
|
||||
|
||||
self.composite.draw(g);
|
||||
if self.mouseover_pt.is_some() {
|
||||
CommonState::draw_custom_osd(
|
||||
g,
|
||||
app,
|
||||
Text::from(Line("hold left Control to move point")),
|
||||
);
|
||||
} else {
|
||||
CommonState::draw_osd(g, app, &None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://wiki.openstreetmap.org/wiki/Osmosis/Polygon_Filter_File_Format
|
||||
fn save_as_osmosis(pts: &Vec<LonLat>) -> Result<(), Error> {
|
||||
let path = "bounding_boy.poly";
|
||||
let mut f = File::create(&path)?;
|
||||
|
||||
writeln!(f, "name goes here")?;
|
||||
writeln!(f, "1")?;
|
||||
for gps in pts {
|
||||
writeln!(f, " {} {}", gps.x(), gps.y())?;
|
||||
}
|
||||
// Have to repeat the first point
|
||||
{
|
||||
writeln!(f, " {} {}", pts[0].x(), pts[0].y())?;
|
||||
}
|
||||
writeln!(f, "END")?;
|
||||
writeln!(f, "END")?;
|
||||
|
||||
println!("Exported {}", path);
|
||||
Ok(())
|
||||
}
|
@ -30,7 +30,6 @@ pub fn osm_to_raw(name: &str) {
|
||||
private_offstreet_parking: convert_osm::PrivateOffstreetParking::OnePerBldg,
|
||||
sidewalks: None,
|
||||
gtfs: None,
|
||||
neighborhoods: None,
|
||||
elevation: None,
|
||||
clip: Some(format!("../data/input/austin/polygons/{}.poly", name)),
|
||||
drive_on_right: true,
|
||||
|
@ -30,7 +30,6 @@ pub fn osm_to_raw(name: &str) {
|
||||
private_offstreet_parking: convert_osm::PrivateOffstreetParking::OnePerBldg,
|
||||
sidewalks: None,
|
||||
gtfs: None,
|
||||
neighborhoods: None,
|
||||
elevation: None,
|
||||
clip: Some(format!("../data/input/los_angeles/polygons/{}.poly", name)),
|
||||
drive_on_right: true,
|
||||
|
@ -5,8 +5,6 @@ fn input() {
|
||||
"../data/input/seattle/google_transit/",
|
||||
"https://metro.kingcounty.gov/GTFS/google_transit.zip",
|
||||
);
|
||||
// Like https://data.seattle.gov/dataset/Neighborhoods/2mbt-aqqx, but in GeoJSON, not SHP
|
||||
download("../data/input/seattle/neighborhoods.geojson", "https://github.com/seattleio/seattle-boundaries-data/raw/master/data/neighborhoods.geojson");
|
||||
download(
|
||||
"../data/input/seattle/N47W122.hgt",
|
||||
"https://dds.cr.usgs.gov/srtm/version2_1/SRTM1/Region_01/N47W122.hgt.zip",
|
||||
@ -42,7 +40,6 @@ pub fn osm_to_raw(name: &str) {
|
||||
format!("../data/input/seattle/polygons/{}.poly", name),
|
||||
format!("../data/input/seattle/osm/{}.osm", name),
|
||||
);
|
||||
rm(format!("../data/input/seattle/neighborhoods/{}", name));
|
||||
rm(format!("../data/system/maps/{}.bin", name));
|
||||
|
||||
println!("- Running convert_osm");
|
||||
@ -62,7 +59,6 @@ pub fn osm_to_raw(name: &str) {
|
||||
// TODO These're buggy.
|
||||
sidewalks: None,
|
||||
gtfs: Some("../data/input/seattle/google_transit".to_string()),
|
||||
neighborhoods: Some("../data/input/seattle/neighborhoods.geojson".to_string()),
|
||||
elevation: Some("../data/input/seattle/N47W122.hgt".to_string()),
|
||||
clip: Some(format!("../data/input/seattle/polygons/{}.poly", name)),
|
||||
drive_on_right: true,
|
||||
|
@ -7,7 +7,6 @@ mod intersection;
|
||||
mod lane;
|
||||
mod make;
|
||||
mod map;
|
||||
mod neighborhood;
|
||||
pub mod osm;
|
||||
mod pathfind;
|
||||
pub mod raw;
|
||||
@ -25,7 +24,6 @@ pub use crate::intersection::{Intersection, IntersectionID, IntersectionType};
|
||||
pub use crate::lane::{Lane, LaneID, LaneType, PARKING_SPOT_LENGTH};
|
||||
pub use crate::make::RoadSpec;
|
||||
pub use crate::map::Map;
|
||||
pub use crate::neighborhood::{FullNeighborhoodInfo, Neighborhood, NeighborhoodBuilder};
|
||||
pub use crate::pathfind::{Path, PathConstraints, PathRequest, PathStep};
|
||||
pub use crate::road::{DirectedRoadID, Road, RoadID};
|
||||
pub use crate::stop_signs::{ControlStopSign, RoadWithStopSign};
|
||||
@ -44,6 +42,4 @@ impl Cloneable for ControlTrafficSignal {}
|
||||
impl Cloneable for IntersectionID {}
|
||||
impl Cloneable for LaneType {}
|
||||
impl Cloneable for MapEdits {}
|
||||
impl Cloneable for Neighborhood {}
|
||||
impl Cloneable for NeighborhoodBuilder {}
|
||||
impl Cloneable for raw::RestrictionType {}
|
||||
|
@ -1,157 +0,0 @@
|
||||
use crate::{BuildingID, Map, RoadID};
|
||||
use aabb_quadtree::QuadTree;
|
||||
use geom::{GPSBounds, LonLat, Polygon, Pt2D};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::collections::{BTreeSet, HashMap};
|
||||
use std::fs::File;
|
||||
use std::io::{Error, Write};
|
||||
|
||||
// This form is used by the editor plugin to edit and for serialization. Storing points in GPS is
|
||||
// more compatible with slight changes to the bounding box of a map over time.
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub struct NeighborhoodBuilder {
|
||||
pub city_name: String,
|
||||
pub map_name: String,
|
||||
pub name: String,
|
||||
pub points: Vec<LonLat>,
|
||||
}
|
||||
|
||||
impl NeighborhoodBuilder {
|
||||
pub fn finalize(&self, gps_bounds: &GPSBounds) -> Neighborhood {
|
||||
assert!(self.points.len() >= 3);
|
||||
Neighborhood {
|
||||
city_name: self.city_name.clone(),
|
||||
map_name: self.map_name.clone(),
|
||||
name: self.name.clone(),
|
||||
polygon: Polygon::new(
|
||||
&self
|
||||
.points
|
||||
.iter()
|
||||
.map(|pt| {
|
||||
Pt2D::from_gps(*pt, gps_bounds)
|
||||
.expect(&format!("Polygon {} has bad pt {}", self.name, pt))
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn save(&self) {
|
||||
abstutil::write_json(
|
||||
abstutil::path_neighborhood(&self.city_name, &self.map_name, &self.name),
|
||||
self,
|
||||
);
|
||||
}
|
||||
|
||||
// https://wiki.openstreetmap.org/wiki/Osmosis/Polygon_Filter_File_Format
|
||||
pub fn save_as_osmosis(&self) -> Result<(), Error> {
|
||||
let path = abstutil::path_polygon(&self.city_name, &self.name);
|
||||
let mut f = File::create(&path)?;
|
||||
|
||||
writeln!(f, "{}", self.name)?;
|
||||
writeln!(f, "1")?;
|
||||
for gps in &self.points {
|
||||
writeln!(f, " {} {}", gps.x(), gps.y())?;
|
||||
}
|
||||
// Have to repeat the first point
|
||||
{
|
||||
writeln!(f, " {} {}", self.points[0].x(), self.points[0].y())?;
|
||||
}
|
||||
writeln!(f, "END")?;
|
||||
writeln!(f, "END")?;
|
||||
|
||||
println!("Exported {}", path);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Neighborhood {
|
||||
pub city_name: String,
|
||||
pub map_name: String,
|
||||
pub name: String,
|
||||
pub polygon: Polygon,
|
||||
}
|
||||
|
||||
impl Neighborhood {
|
||||
pub fn load_all(
|
||||
city_name: &str,
|
||||
map_name: &str,
|
||||
gps_bounds: &GPSBounds,
|
||||
) -> Vec<(String, Neighborhood)> {
|
||||
abstutil::load_all_objects::<NeighborhoodBuilder>(abstutil::path_all_neighborhoods(
|
||||
city_name, map_name,
|
||||
))
|
||||
.into_iter()
|
||||
.map(|(name, builder)| (name, builder.finalize(gps_bounds)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn make_everywhere(map: &Map) -> Neighborhood {
|
||||
Neighborhood {
|
||||
city_name: map.get_city_name().to_string(),
|
||||
map_name: map.get_name().to_string(),
|
||||
name: "_everywhere_".to_string(),
|
||||
polygon: map.get_bounds().get_rectangle(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FullNeighborhoodInfo {
|
||||
pub name: String,
|
||||
pub buildings: Vec<BuildingID>,
|
||||
pub roads: BTreeSet<RoadID>,
|
||||
}
|
||||
|
||||
impl FullNeighborhoodInfo {
|
||||
pub fn load_all(map: &Map) -> HashMap<String, FullNeighborhoodInfo> {
|
||||
let mut neighborhoods =
|
||||
Neighborhood::load_all(map.get_city_name(), map.get_name(), map.get_gps_bounds());
|
||||
neighborhoods.push((
|
||||
"_everywhere_".to_string(),
|
||||
Neighborhood::make_everywhere(map),
|
||||
));
|
||||
|
||||
let mut bldg_quadtree = QuadTree::default(map.get_bounds().as_bbox());
|
||||
for b in map.all_buildings() {
|
||||
bldg_quadtree.insert_with_box(b.id, b.polygon.get_bounds().as_bbox());
|
||||
}
|
||||
let mut road_quadtree = QuadTree::default(map.get_bounds().as_bbox());
|
||||
for r in map.all_roads() {
|
||||
road_quadtree.insert_with_box(
|
||||
r.id,
|
||||
r.get_thick_polygon(map).unwrap().get_bounds().as_bbox(),
|
||||
);
|
||||
}
|
||||
|
||||
let mut full_info = HashMap::new();
|
||||
for (name, n) in &neighborhoods {
|
||||
let mut info = FullNeighborhoodInfo {
|
||||
name: name.to_string(),
|
||||
buildings: Vec::new(),
|
||||
roads: BTreeSet::new(),
|
||||
};
|
||||
|
||||
for &(id, _, _) in &bldg_quadtree.query(n.polygon.get_bounds().as_bbox()) {
|
||||
// TODO Polygon containment is hard; just see if the center is inside.
|
||||
if n.polygon.contains_pt(map.get_b(*id).polygon.center()) {
|
||||
info.buildings.push(*id);
|
||||
}
|
||||
}
|
||||
|
||||
for &(id, _, _) in &road_quadtree.query(n.polygon.get_bounds().as_bbox()) {
|
||||
// TODO Polygon containment is hard; just see if the "center" of each endpoint is
|
||||
// inside.
|
||||
let r = map.get_r(*id);
|
||||
let pt1 = r.center_pts.first_pt();
|
||||
let pt2 = r.center_pts.last_pt();
|
||||
if n.polygon.contains_pt(pt1) && n.polygon.contains_pt(pt2) {
|
||||
info.roads.insert(*id);
|
||||
}
|
||||
}
|
||||
|
||||
full_info.insert(name.to_string(), info);
|
||||
}
|
||||
full_info
|
||||
}
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
use crate::{DrivingGoal, IndividTrip, PersonID, PersonSpec, Scenario, SidewalkSpot, SpawnTrip};
|
||||
use abstutil::Timer;
|
||||
use geom::{Duration, Time};
|
||||
use map_model::{BuildingID, DirectedRoadID, FullNeighborhoodInfo, Map, PathConstraints};
|
||||
use map_model::{BuildingID, DirectedRoadID, Map, PathConstraints};
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::Rng;
|
||||
use rand_xorshift::XorShiftRng;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::collections::{BTreeSet, HashMap};
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
// A way to generate Scenarios
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
@ -27,7 +27,6 @@ pub struct SpawnOverTime {
|
||||
// TODO use https://docs.rs/rand/0.5.5/rand/distributions/struct.Normal.html
|
||||
pub start_time: Time,
|
||||
pub stop_time: Time,
|
||||
pub start_from_neighborhood: String,
|
||||
pub goal: OriginDestination,
|
||||
pub percent_driving: f64,
|
||||
pub percent_biking: f64,
|
||||
@ -55,32 +54,23 @@ impl ScenarioGenerator {
|
||||
|
||||
timer.start(format!("Generating scenario {}", self.scenario_name));
|
||||
|
||||
timer.start("load full neighborhood info");
|
||||
let neighborhoods = FullNeighborhoodInfo::load_all(map);
|
||||
timer.stop("load full neighborhood info");
|
||||
|
||||
for s in &self.spawn_over_time {
|
||||
if !neighborhoods.contains_key(&s.start_from_neighborhood) {
|
||||
panic!("Neighborhood {} isn't defined", s.start_from_neighborhood);
|
||||
}
|
||||
|
||||
timer.start_iter("SpawnOverTime each agent", s.num_agents);
|
||||
for _ in 0..s.num_agents {
|
||||
timer.next();
|
||||
s.spawn_agent(rng, &mut scenario, &neighborhoods, map, timer);
|
||||
s.spawn_agent(rng, &mut scenario, map, timer);
|
||||
}
|
||||
}
|
||||
|
||||
timer.start_iter("BorderSpawnOverTime", self.border_spawn_over_time.len());
|
||||
for s in &self.border_spawn_over_time {
|
||||
timer.next();
|
||||
s.spawn_peds(rng, &mut scenario, &neighborhoods, map, timer);
|
||||
s.spawn_peds(rng, &mut scenario, map, timer);
|
||||
s.spawn_vehicles(
|
||||
s.num_cars,
|
||||
PathConstraints::Car,
|
||||
rng,
|
||||
&mut scenario,
|
||||
&neighborhoods,
|
||||
map,
|
||||
timer,
|
||||
);
|
||||
@ -89,7 +79,6 @@ impl ScenarioGenerator {
|
||||
PathConstraints::Bike,
|
||||
rng,
|
||||
&mut scenario,
|
||||
&neighborhoods,
|
||||
map,
|
||||
timer,
|
||||
);
|
||||
@ -107,8 +96,7 @@ impl ScenarioGenerator {
|
||||
num_agents: 100,
|
||||
start_time: Time::START_OF_DAY,
|
||||
stop_time: Time::START_OF_DAY + Duration::seconds(5.0),
|
||||
start_from_neighborhood: "_everywhere_".to_string(),
|
||||
goal: OriginDestination::Neighborhood("_everywhere_".to_string()),
|
||||
goal: OriginDestination::Anywhere,
|
||||
percent_driving: 0.5,
|
||||
percent_biking: 0.5,
|
||||
percent_use_transit: 0.5,
|
||||
@ -125,7 +113,7 @@ impl ScenarioGenerator {
|
||||
start_time: Time::START_OF_DAY,
|
||||
stop_time: Time::START_OF_DAY + Duration::seconds(5.0),
|
||||
start_from_border: i.some_outgoing_road(map),
|
||||
goal: OriginDestination::Neighborhood("_everywhere_".to_string()),
|
||||
goal: OriginDestination::Anywhere,
|
||||
percent_use_transit: 0.5,
|
||||
})
|
||||
.collect(),
|
||||
@ -135,7 +123,6 @@ impl ScenarioGenerator {
|
||||
num_agents: 10,
|
||||
start_time: Time::START_OF_DAY,
|
||||
stop_time: Time::START_OF_DAY + Duration::seconds(5.0),
|
||||
start_from_neighborhood: "_everywhere_".to_string(),
|
||||
goal: OriginDestination::EndOfRoad(i.some_incoming_road(map)),
|
||||
percent_driving: 0.5,
|
||||
percent_biking: 0.5,
|
||||
@ -163,8 +150,7 @@ impl ScenarioGenerator {
|
||||
num_agents: num_agents,
|
||||
start_time: Time::START_OF_DAY,
|
||||
stop_time: Time::START_OF_DAY + Duration::seconds(5.0),
|
||||
start_from_neighborhood: "_everywhere_".to_string(),
|
||||
goal: OriginDestination::Neighborhood("_everywhere_".to_string()),
|
||||
goal: OriginDestination::Anywhere,
|
||||
percent_driving: 0.5,
|
||||
percent_biking: 0.5,
|
||||
percent_use_transit: 0.5,
|
||||
@ -179,23 +165,19 @@ impl SpawnOverTime {
|
||||
&self,
|
||||
rng: &mut XorShiftRng,
|
||||
scenario: &mut Scenario,
|
||||
neighborhoods: &HashMap<String, FullNeighborhoodInfo>,
|
||||
map: &Map,
|
||||
timer: &mut Timer,
|
||||
) {
|
||||
let depart = rand_time(rng, self.start_time, self.stop_time);
|
||||
// Note that it's fine for agents to start/end at the same building. Later we might
|
||||
// want a better assignment of people per household, or workers per office building.
|
||||
let from_bldg = *neighborhoods[&self.start_from_neighborhood]
|
||||
.buildings
|
||||
.choose(rng)
|
||||
.unwrap();
|
||||
let from_bldg = map.all_buildings().choose(rng).unwrap().id;
|
||||
let id = PersonID(scenario.people.len());
|
||||
|
||||
if rng.gen_bool(self.percent_driving) {
|
||||
if let Some(goal) =
|
||||
self.goal
|
||||
.pick_driving_goal(PathConstraints::Car, map, &neighborhoods, rng, timer)
|
||||
if let Some(goal) = self
|
||||
.goal
|
||||
.pick_driving_goal(PathConstraints::Car, map, rng, timer)
|
||||
{
|
||||
scenario.people.push(PersonSpec {
|
||||
id,
|
||||
@ -212,9 +194,9 @@ impl SpawnOverTime {
|
||||
let start_spot = SidewalkSpot::building(from_bldg, map);
|
||||
|
||||
if rng.gen_bool(self.percent_biking) {
|
||||
if let Some(goal) =
|
||||
self.goal
|
||||
.pick_driving_goal(PathConstraints::Bike, map, &neighborhoods, rng, timer)
|
||||
if let Some(goal) = self
|
||||
.goal
|
||||
.pick_driving_goal(PathConstraints::Bike, map, rng, timer)
|
||||
{
|
||||
scenario.people.push(PersonSpec {
|
||||
id,
|
||||
@ -228,7 +210,7 @@ impl SpawnOverTime {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(goal) = self.goal.pick_walking_goal(map, &neighborhoods, rng, timer) {
|
||||
if let Some(goal) = self.goal.pick_walking_goal(map, rng, timer) {
|
||||
if start_spot == goal {
|
||||
timer.warn("Skipping walking trip between same two buildings".to_string());
|
||||
return;
|
||||
@ -272,7 +254,6 @@ impl BorderSpawnOverTime {
|
||||
&self,
|
||||
rng: &mut XorShiftRng,
|
||||
scenario: &mut Scenario,
|
||||
neighborhoods: &HashMap<String, FullNeighborhoodInfo>,
|
||||
map: &Map,
|
||||
timer: &mut Timer,
|
||||
) {
|
||||
@ -295,7 +276,7 @@ impl BorderSpawnOverTime {
|
||||
for _ in 0..self.num_peds {
|
||||
let depart = rand_time(rng, self.start_time, self.stop_time);
|
||||
let id = PersonID(scenario.people.len());
|
||||
if let Some(goal) = self.goal.pick_walking_goal(map, &neighborhoods, rng, timer) {
|
||||
if let Some(goal) = self.goal.pick_walking_goal(map, rng, timer) {
|
||||
if rng.gen_bool(self.percent_use_transit) {
|
||||
// TODO This throws away some work. It also sequentially does expensive
|
||||
// work right here.
|
||||
@ -338,16 +319,12 @@ impl BorderSpawnOverTime {
|
||||
constraints: PathConstraints,
|
||||
rng: &mut XorShiftRng,
|
||||
scenario: &mut Scenario,
|
||||
neighborhoods: &HashMap<String, FullNeighborhoodInfo>,
|
||||
map: &Map,
|
||||
timer: &mut Timer,
|
||||
) {
|
||||
for _ in 0..num {
|
||||
let depart = rand_time(rng, self.start_time, self.stop_time);
|
||||
if let Some(goal) =
|
||||
self.goal
|
||||
.pick_driving_goal(constraints, map, &neighborhoods, rng, timer)
|
||||
{
|
||||
if let Some(goal) = self.goal.pick_driving_goal(constraints, map, rng, timer) {
|
||||
let id = PersonID(scenario.people.len());
|
||||
scenario.people.push(PersonSpec {
|
||||
id,
|
||||
@ -369,7 +346,7 @@ impl BorderSpawnOverTime {
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub enum OriginDestination {
|
||||
Neighborhood(String),
|
||||
Anywhere,
|
||||
EndOfRoad(DirectedRoadID),
|
||||
GotoBldg(BuildingID),
|
||||
}
|
||||
@ -379,13 +356,12 @@ impl OriginDestination {
|
||||
&self,
|
||||
constraints: PathConstraints,
|
||||
map: &Map,
|
||||
neighborhoods: &HashMap<String, FullNeighborhoodInfo>,
|
||||
rng: &mut XorShiftRng,
|
||||
timer: &mut Timer,
|
||||
) -> Option<DrivingGoal> {
|
||||
match self {
|
||||
OriginDestination::Neighborhood(ref n) => Some(DrivingGoal::ParkNear(
|
||||
*neighborhoods[n].buildings.choose(rng).unwrap(),
|
||||
OriginDestination::Anywhere => Some(DrivingGoal::ParkNear(
|
||||
map.all_buildings().choose(rng).unwrap().id,
|
||||
)),
|
||||
OriginDestination::GotoBldg(b) => Some(DrivingGoal::ParkNear(*b)),
|
||||
OriginDestination::EndOfRoad(dr) => {
|
||||
@ -404,13 +380,12 @@ impl OriginDestination {
|
||||
fn pick_walking_goal(
|
||||
&self,
|
||||
map: &Map,
|
||||
neighborhoods: &HashMap<String, FullNeighborhoodInfo>,
|
||||
rng: &mut XorShiftRng,
|
||||
timer: &mut Timer,
|
||||
) -> Option<SidewalkSpot> {
|
||||
match self {
|
||||
OriginDestination::Neighborhood(ref n) => Some(SidewalkSpot::building(
|
||||
*neighborhoods[n].buildings.choose(rng).unwrap(),
|
||||
OriginDestination::Anywhere => Some(SidewalkSpot::building(
|
||||
map.all_buildings().choose(rng).unwrap().id,
|
||||
map,
|
||||
)),
|
||||
OriginDestination::EndOfRoad(dr) => {
|
||||
|
Loading…
Reference in New Issue
Block a user