When importing external scenario data, snap points outside the map boundary to the nearest border.

Now the desire lines for cyipt/actdev#32 import without errors.
This commit is contained in:
Dustin Carlino 2021-01-14 17:32:44 -08:00
parent a7f3e998b7
commit 3143b57b19
4 changed files with 44 additions and 17 deletions

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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<ExternalPerson>) -> Result<Vec<PersonSpec>> {
let mut closest: FindClosest<TripEndpoint> = 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())
}
}
};