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",
"size_bytes": 8485994
},
"data/system/paris/city.bin": {
"checksum": "0fd1914ef16ad3797ccfaf14c36c3a17",
"size_bytes": 2279409
},
"data/system/paris/maps/center.bin": {
"checksum": "5ed145aee161a464011fb4bc16d3110a",
"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=krakow
./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=xian

View File

@ -25,6 +25,7 @@ struct Job {
raw_to_map: bool,
scenario: bool,
scenario_everyone: bool,
city_overview: bool,
skip_ch: bool,
keep_bldg_tags: bool,
@ -49,6 +50,8 @@ fn main() {
scenario: args.enabled("--scenario"),
// Produce a variation of the weekday scenario including off-map trips.
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
// will use a slower method to pathfind.
skip_ch: args.enabled("--skip_ch"),
@ -70,11 +73,12 @@ fn main() {
&& !job.raw_to_map
&& !job.scenario
&& !job.scenario_everyone
&& !job.city_overview
&& job.oneshot.is_none()
{
println!(
"Nothing to do! Pass some combination of --raw, --map, --scenario, \
--scenario_everyone or --oneshot"
--scenario_everyone, --city_overview, or --oneshot"
);
std::process::exit(1);
}
@ -221,6 +225,15 @@ fn main() {
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(

View File

@ -142,7 +142,7 @@ pub fn raw_to_map(
timer.start("generating city manifest");
abstutil::write_binary(
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");
}

View File

@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize};
use abstutil::MapName;
use geom::{LonLat, Polygon, Ring};
use abstutil::{MapName, Timer};
use geom::{GPSBounds, LonLat, Polygon, Ring};
use crate::{AreaType, Map};
@ -12,13 +12,14 @@ pub struct City {
pub name: String,
pub boundary: Polygon,
pub areas: Vec<(AreaType, Polygon)>,
// The individual maps
/// The individual maps
pub regions: Vec<(MapName, Polygon)>,
// TODO Move nice_map_name from game into here?
}
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 mut regions = abstutil::list_dir(format!("importer/config/{}", city_name))
.into_iter()
@ -46,4 +47,53 @@ impl City {
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,
}
}
}