diff --git a/book/src/trafficsim/travel_demand.md b/book/src/trafficsim/travel_demand.md index ee2f39b464..98718b7763 100644 --- a/book/src/trafficsim/travel_demand.md +++ b/book/src/trafficsim/travel_demand.md @@ -113,12 +113,13 @@ Run the tool: cargo run --bin import_traffic -- --map=data/system/seattle/maps/montlake.bin --input=/path/to/input.json ``` -The tool matches input positions to the nearest building or border intersection, -within 100 meters. The `departure` time is seconds since midnight. The tool will -fail if any point doesn't match to a building, or if any of the specified trips -can't be created (due to graph connectivity problems, for example). If your -requirements are different or you have any trouble using this format/tool, -please file a Github issue -- just consider this tool and format a prototype. +The tool matches input positions to the nearest building, within 100 meters. If +the point lies outside the map boundary, it's snapped to the nearest map border. +The `departure` time is seconds since midnight. The tool will fail if any point +doesn't match to a building, or if any of the specified trips can't be created +(due to graph connectivity problems, for example). If your requirements are +different or you have any trouble using this format/tool, please file a Github +issue -- just consider this tool and format a prototype. ## Modifying demand diff --git a/data/MANIFEST.json b/data/MANIFEST.json index 8f239a1f5f..b508bbb09a 100644 --- a/data/MANIFEST.json +++ b/data/MANIFEST.json @@ -41,9 +41,9 @@ "compressed_size_bytes": 2845017 }, "data/input/cambridge/desire_lines_disag.geojson": { - "checksum": "37020c1232b357b8f5753157eaf6b95f", - "uncompressed_size_bytes": 66601, - "compressed_size_bytes": 6385 + "checksum": "1cb0f5fc91626099dca6582c97f49c43", + "uncompressed_size_bytes": 80600, + "compressed_size_bytes": 11174 }, "data/input/cambridge/osm/cambridgeshire-latest.osm.pbf": { "checksum": "e7ac328f5b13c1a90da861abc84ae08d", @@ -645,6 +645,16 @@ "uncompressed_size_bytes": 28191229, "compressed_size_bytes": 9988667 }, + "data/system/cambridge/scenarios/trumpington/baseline.bin": { + "checksum": "661ce8362a2854023d24822b9f2bb8fe", + "uncompressed_size_bytes": 71752, + "compressed_size_bytes": 18953 + }, + "data/system/cambridge/scenarios/trumpington/go_dutch.bin": { + "checksum": "b87b56638974c3ca6b88b498ac655a35", + "uncompressed_size_bytes": 71752, + "compressed_size_bytes": 18791 + }, "data/system/krakow/maps/center.bin": { "checksum": "6b39b2b5a2066603cbe5e4dc087e7071", "uncompressed_size_bytes": 36111431, diff --git a/data/regen.sh b/data/regen.sh index 4b22ed7d45..4014d9363d 100755 --- a/data/regen.sh +++ b/data/regen.sh @@ -7,7 +7,7 @@ rm -fv data/system/seattle/maps/huge_seattle.bin data/input/raw_maps/huge_seattl ./import.sh --raw --map --scenario ./import.sh --raw --map --city=bellevue ./import.sh --raw --map --city=berlin -./import.sh --raw --map --city=cambridge # TODO Enable --scenario +./import.sh --raw --map --city=cambridge --scenario ./import.sh --raw --map --city=krakow ./import.sh --raw --map --city=leeds ./import.sh --raw --map --city=london diff --git a/sim/src/make/external.rs b/sim/src/make/external.rs index ee50c60845..4d5e377cf4 100644 --- a/sim/src/make/external.rs +++ b/sim/src/make/external.rs @@ -29,23 +29,39 @@ pub enum ExternalTripEndpoint { } impl ExternalPerson { + /// Import external scenario data. The main difference between `ExternalPerson` and + /// `PersonSpec` is a way to specify endpoints by a `LonLat`. This is snapped to the nearest + /// building. If the point is outside of the map boundary, it's snapped to the nearest border + /// (by Euclidean distance -- the network outside the given map isn't known). Failure happens + /// if a point is within the map, but not close enough to any buildings. pub fn import(map: &Map, input: Vec) -> Result> { let mut closest: FindClosest = FindClosest::new(map.get_bounds()); for b in map.all_buildings() { closest.add(TripEndpoint::Bldg(b.id), b.polygon.points()); } + let mut borders = Vec::new(); for i in map.all_intersections() { - closest.add(TripEndpoint::Border(i.id), i.polygon.points()); + if i.is_border() { + borders.push((TripEndpoint::Border(i.id), i.polygon.center())); + } } + let lookup_pt = |endpt| match endpt { ExternalTripEndpoint::TripEndpoint(endpt) => Ok(endpt), ExternalTripEndpoint::Position(gps) => { - match closest.closest_pt(gps.to_pt(map.get_gps_bounds()), Distance::meters(100.0)) { - Some((x, _)) => Ok(x), - None => Err(anyhow!( - "No building or border intersection within 100m of {}", - gps - )), + let pt = gps.to_pt(map.get_gps_bounds()); + if map.get_boundary_polygon().contains_pt(pt) { + match closest.closest_pt(pt, Distance::meters(100.0)) { + Some((x, _)) => Ok(x), + None => Err(anyhow!("No building within 100m of {}", gps)), + } + } else { + Ok(borders + .iter() + .min_by_key(|(_, border)| border.fast_dist(pt)) + .unwrap() + .0 + .clone()) } } };