Generate city picker maps from a bunch of small maps, instead of one huge map. Use for Paris. One giant map covering everything there is going to be too large.

This commit is contained in:
Dustin Carlino 2020-11-13 18:22:46 -08:00
parent d43bf2c869
commit b6be9c81d5
5 changed files with 74 additions and 6 deletions

View File

@ -408,6 +408,10 @@
"checksum": "69df8b1a1f93c5d52f872ef18eb5cde2", "checksum": "69df8b1a1f93c5d52f872ef18eb5cde2",
"size_bytes": 8485994 "size_bytes": 8485994
}, },
"data/system/paris/city.bin": {
"checksum": "0fd1914ef16ad3797ccfaf14c36c3a17",
"size_bytes": 2279409
},
"data/system/paris/maps/center.bin": { "data/system/paris/maps/center.bin": {
"checksum": "5ed145aee161a464011fb4bc16d3110a", "checksum": "5ed145aee161a464011fb4bc16d3110a",
"size_bytes": 37829561 "size_bytes": 37829561

View File

@ -8,6 +8,7 @@ rm -fv data/system/seattle/maps/huge_seattle.bin data/input/raw_maps/huge_seattl
./import.sh --raw --map --city=berlin ./import.sh --raw --map --city=berlin
./import.sh --raw --map --city=krakow ./import.sh --raw --map --city=krakow
./import.sh --raw --map --city=london ./import.sh --raw --map --city=london
./import.sh --raw --map --city_overview --city=paris
./import.sh --raw --map --city=tel_aviv ./import.sh --raw --map --city=tel_aviv
./import.sh --raw --map --city=xian ./import.sh --raw --map --city=xian

View File

@ -25,6 +25,7 @@ struct Job {
raw_to_map: bool, raw_to_map: bool,
scenario: bool, scenario: bool,
scenario_everyone: bool, scenario_everyone: bool,
city_overview: bool,
skip_ch: bool, skip_ch: bool,
keep_bldg_tags: bool, keep_bldg_tags: bool,
@ -49,6 +50,8 @@ fn main() {
scenario: args.enabled("--scenario"), scenario: args.enabled("--scenario"),
// Produce a variation of the weekday scenario including off-map trips. // Produce a variation of the weekday scenario including off-map trips.
scenario_everyone: args.enabled("--scenario_everyone"), scenario_everyone: args.enabled("--scenario_everyone"),
// Produce a city overview from all of the individual maps in a city.
city_overview: args.enabled("--city_overview"),
// Skip the most expensive step of --map, building contraction hierarchies. The simulation // Skip the most expensive step of --map, building contraction hierarchies. The simulation
// will use a slower method to pathfind. // will use a slower method to pathfind.
skip_ch: args.enabled("--skip_ch"), skip_ch: args.enabled("--skip_ch"),
@ -70,11 +73,12 @@ fn main() {
&& !job.raw_to_map && !job.raw_to_map
&& !job.scenario && !job.scenario
&& !job.scenario_everyone && !job.scenario_everyone
&& !job.city_overview
&& job.oneshot.is_none() && job.oneshot.is_none()
{ {
println!( println!(
"Nothing to do! Pass some combination of --raw, --map, --scenario, \ "Nothing to do! Pass some combination of --raw, --map, --scenario, \
--scenario_everyone or --oneshot" --scenario_everyone, --city_overview, or --oneshot"
); );
std::process::exit(1); std::process::exit(1);
} }
@ -221,6 +225,15 @@ fn main() {
timer.stop(format!("scenario_everyone for {}", name.describe())); timer.stop(format!("scenario_everyone for {}", name.describe()));
} }
} }
if job.city_overview {
timer.start(format!("generate city overview for {}", job.city));
abstutil::write_binary(
abstutil::path(format!("system/{}/city.bin", job.city)),
&map_model::City::from_individual_maps(&job.city, &mut timer),
);
timer.stop(format!("generate city overview for {}", job.city));
}
} }
fn oneshot( fn oneshot(

View File

@ -142,7 +142,7 @@ pub fn raw_to_map(
timer.start("generating city manifest"); timer.start("generating city manifest");
abstutil::write_binary( abstutil::write_binary(
abstutil::path(format!("system/{}/city.bin", map.get_city_name())), abstutil::path(format!("system/{}/city.bin", map.get_city_name())),
&map_model::City::new(&map), &map_model::City::from_huge_map(&map),
); );
timer.stop("generating city manifest"); timer.stop("generating city manifest");
} }

View File

@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use abstutil::MapName; use abstutil::{MapName, Timer};
use geom::{LonLat, Polygon, Ring}; use geom::{GPSBounds, LonLat, Polygon, Ring};
use crate::{AreaType, Map}; use crate::{AreaType, Map};
@ -12,13 +12,14 @@ pub struct City {
pub name: String, pub name: String,
pub boundary: Polygon, pub boundary: Polygon,
pub areas: Vec<(AreaType, Polygon)>, pub areas: Vec<(AreaType, Polygon)>,
// The individual maps /// The individual maps
pub regions: Vec<(MapName, Polygon)>, pub regions: Vec<(MapName, Polygon)>,
// TODO Move nice_map_name from game into here? // TODO Move nice_map_name from game into here?
} }
impl City { impl City {
pub fn new(huge_map: &Map) -> City { /// If there's a single map covering all the smaller maps, use this.
pub fn from_huge_map(huge_map: &Map) -> City {
let city_name = huge_map.get_city_name().clone(); let city_name = huge_map.get_city_name().clone();
let mut regions = abstutil::list_dir(format!("importer/config/{}", city_name)) let mut regions = abstutil::list_dir(format!("importer/config/{}", city_name))
.into_iter() .into_iter()
@ -46,4 +47,53 @@ impl City {
regions, regions,
} }
} }
/// Generate a city from a bunch of smaller, individual maps. The boundaries of those maps
/// may overlap and may have gaps between them.
pub fn from_individual_maps(city_name: &str, timer: &mut Timer) -> City {
let boundary_per_region: Vec<(MapName, Vec<LonLat>)> =
abstutil::list_dir(format!("importer/config/{}", city_name))
.into_iter()
.filter(|path| path.ends_with(".poly"))
.map(|path| {
(
MapName::new(&city_name, &abstutil::basename(&path)),
LonLat::read_osmosis_polygon(&path).unwrap(),
)
})
.collect();
// Figure out the total bounds for all the maps
let mut gps_bounds = GPSBounds::new();
for (_, pts) in &boundary_per_region {
for pt in pts {
gps_bounds.update(*pt);
}
}
let boundary = gps_bounds.to_bounds().get_rectangle();
let mut regions = Vec::new();
for (name, pts) in boundary_per_region {
regions.push((name, Ring::must_new(gps_bounds.convert(&pts)).to_polygon()));
}
// Add areas from every map. It's fine if they partly overlap.
let mut areas = Vec::new();
for path in abstutil::list_dir(abstutil::path(format!("system/{}/maps", city_name))) {
let map = Map::new(path, timer);
for area in map.all_areas() {
let pts = map.gps_bounds.convert_back(area.polygon.points());
// TODO Holes in the polygons get lost
if let Ok(ring) = Ring::new(gps_bounds.convert(&pts)) {
areas.push((area.area_type, ring.to_polygon()));
}
}
}
City {
name: city_name.to_string(),
boundary,
areas,
regions,
}
}
} }