mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-24 09:24:26 +03:00
using blockface kml in convert_osm to prescribe parking lanes
This commit is contained in:
parent
9e91332b58
commit
5bc9992fc0
@ -25,7 +25,10 @@ mod split_ways;
|
||||
mod srtm;
|
||||
mod traffic_signals;
|
||||
|
||||
use map_model::raw_data;
|
||||
use dimensioned::si;
|
||||
use geom::{GPSBounds, PolyLine, Pt2D};
|
||||
use kml::ExtraShapes;
|
||||
use map_model::{raw_data, FindClosest, LANE_THICKNESS};
|
||||
use ordered_float::NotNaN;
|
||||
use srtm::Elevation;
|
||||
use std::path::Path;
|
||||
@ -51,6 +54,10 @@ pub struct Flags {
|
||||
#[structopt(long = "parcels")]
|
||||
pub parcels: String,
|
||||
|
||||
/// ExtraShapes file with blockface, produced using the kml crate
|
||||
#[structopt(long = "parking_shapes")]
|
||||
pub parking_shapes: String,
|
||||
|
||||
/// GTFS directory
|
||||
#[structopt(long = "gtfs")]
|
||||
pub gtfs: String,
|
||||
@ -71,8 +78,13 @@ pub fn convert(flags: &Flags, timer: &mut abstutil::Timer) -> raw_data::Map {
|
||||
remove_disconnected::remove_disconnected_roads(&mut map, timer);
|
||||
let gps_bounds = map.get_gps_bounds();
|
||||
|
||||
println!("Loading blockface shapes from {}", flags.parking_shapes);
|
||||
let parking_shapes: ExtraShapes =
|
||||
abstutil::read_binary(&flags.parking_shapes, timer).expect("loading blockface failed");
|
||||
use_parking_hints(&mut map, parking_shapes, &gps_bounds);
|
||||
|
||||
println!("Loading parcels from {}", flags.parcels);
|
||||
let parcels: kml::ExtraShapes =
|
||||
let parcels: ExtraShapes =
|
||||
abstutil::read_binary(&flags.parcels, timer).expect("loading parcels failed");
|
||||
println!(
|
||||
"Finding matching parcels from {} candidates",
|
||||
@ -91,7 +103,7 @@ pub fn convert(flags: &Flags, timer: &mut abstutil::Timer) -> raw_data::Map {
|
||||
});
|
||||
}
|
||||
}
|
||||
group_parcels::group_parcels(gps_bounds, &mut map.parcels);
|
||||
group_parcels::group_parcels(&gps_bounds, &mut map.parcels);
|
||||
|
||||
for pt in traffic_signals::extract(&flags.traffic_signals)
|
||||
.expect("loading traffic signals failed")
|
||||
@ -125,7 +137,52 @@ pub fn convert(flags: &Flags, timer: &mut abstutil::Timer) -> raw_data::Map {
|
||||
.to_os_string()
|
||||
.into_string()
|
||||
.unwrap();
|
||||
neighborhoods::convert(&flags.neighborhoods, map_name, gps_bounds);
|
||||
neighborhoods::convert(&flags.neighborhoods, map_name, &gps_bounds);
|
||||
|
||||
map
|
||||
}
|
||||
|
||||
fn use_parking_hints(map: &mut raw_data::Map, shapes: ExtraShapes, gps_bounds: &GPSBounds) {
|
||||
// Match shapes with the nearest road + direction (true for forwards)
|
||||
let mut closest: FindClosest<(usize, bool)> = FindClosest::new(&gps_bounds.to_bounds());
|
||||
for (idx, r) in map.roads.iter().enumerate() {
|
||||
let pts = PolyLine::new(
|
||||
r.points
|
||||
.iter()
|
||||
.map(|pt| Pt2D::from_gps(*pt, gps_bounds).unwrap())
|
||||
.collect(),
|
||||
);
|
||||
|
||||
closest.add((idx, true), &pts.shift_blindly(LANE_THICKNESS));
|
||||
closest.add((idx, false), &pts.reversed().shift_blindly(LANE_THICKNESS));
|
||||
}
|
||||
|
||||
'SHAPE: for s in shapes.shapes.into_iter() {
|
||||
let mut pts: Vec<Pt2D> = Vec::new();
|
||||
for pt in s.points.into_iter() {
|
||||
if let Some(pt) = Pt2D::from_gps(pt, gps_bounds) {
|
||||
pts.push(pt);
|
||||
} else {
|
||||
continue 'SHAPE;
|
||||
}
|
||||
}
|
||||
if pts.len() > 1 {
|
||||
// The blockface line endpoints will be close to other roads, so match based on the
|
||||
// middle of the blockface.
|
||||
// TODO Long blockfaces sometimes cover two roads. Should maybe find ALL matches within
|
||||
// the threshold distance?
|
||||
let middle = PolyLine::new(pts).middle();
|
||||
if let Some(((r, fwds), _)) = closest.closest_pt(middle, 5.0 * LANE_THICKNESS * si::M) {
|
||||
let category = s.attributes.get("PARKING_CATEGORY");
|
||||
let has_parking = category != Some(&"None".to_string())
|
||||
&& category != Some(&"No Parking Allowed".to_string());
|
||||
// Blindly override prior values.
|
||||
if fwds {
|
||||
map.roads[r].parking_lane_fwd = has_parking;
|
||||
} else {
|
||||
map.roads[r].parking_lane_back = has_parking;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -61,6 +61,9 @@ pub fn osm_to_raw_roads(osm_path: &str, timer: &mut Timer) -> raw_data::Map {
|
||||
osm_way_id: way.id,
|
||||
points: pts,
|
||||
osm_tags: tags,
|
||||
// We'll fill this out later
|
||||
parking_lane_fwd: false,
|
||||
parking_lane_back: false,
|
||||
});
|
||||
} else if is_bldg(&tags) {
|
||||
map.buildings.push(raw_data::Building {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use aabb_quadtree::geom::{Point, Rect};
|
||||
use std::f64;
|
||||
use std::fmt;
|
||||
use {HashablePt2D, Pt2D};
|
||||
use {Bounds, HashablePt2D, Pt2D};
|
||||
|
||||
// longitude is x, latitude is y
|
||||
#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||
@ -104,4 +104,11 @@ impl GPSBounds {
|
||||
.gps_dist_meters(LonLat::new(self.min_lon, self.max_lat));
|
||||
Pt2D::new(width, height)
|
||||
}
|
||||
|
||||
pub fn to_bounds(&self) -> Bounds {
|
||||
let mut b = Bounds::new();
|
||||
b.update(Pt2D::new(0.0, 0.0));
|
||||
b.update(self.get_max_world_pt());
|
||||
b
|
||||
}
|
||||
}
|
||||
|
12
import.sh
12
import.sh
@ -74,6 +74,17 @@ if [ ! -f data/shapes/parcels ]; then
|
||||
cd ..
|
||||
fi
|
||||
|
||||
if [ ! -f data/shapes/blockface ]; then
|
||||
# From http://data-seattlecitygis.opendata.arcgis.com/datasets/blockface
|
||||
get_if_needed https://opendata.arcgis.com/datasets/a1458ad1abca41869b81f7c0db0cd777_0.kml data/input/blockface.kml;
|
||||
|
||||
cd kml
|
||||
time cargo run --release -- \
|
||||
--input=../data/input/blockface.kml \
|
||||
--output=../data/shapes/blockface
|
||||
cd ..
|
||||
fi
|
||||
|
||||
cd convert_osm
|
||||
for poly in `ls ../data/polygons/`; do
|
||||
name=`basename -s .poly $poly`;
|
||||
@ -82,6 +93,7 @@ for poly in `ls ../data/polygons/`; do
|
||||
--elevation=../data/input/N47W122.hgt \
|
||||
--traffic_signals=../data/input/TrafficSignals.shp \
|
||||
--parcels=../data/shapes/parcels \
|
||||
--parking_shapes=../data/shapes/blockface \
|
||||
--gtfs=../data/input/google_transit_2018_18_08 \
|
||||
--neighborhoods=../data/input/neighborhoods.geojson \
|
||||
--output=../data/raw_maps/$name.abst
|
||||
|
@ -56,33 +56,48 @@ fn get_lanes(r: &raw_data::Road) -> (Vec<LaneType>, Vec<LaneType>) {
|
||||
&& r.osm_tags.get("highway") != Some(&"motorway_link".to_string());
|
||||
// TODO Bus/bike and parking lanes can coexist, but then we have to make sure cars are fine
|
||||
// with merging in/out of the bus/bike lane to park. ><
|
||||
let has_parking = has_sidewalk && !has_bus_lane && !has_bike_lane;
|
||||
//let has_parking = has_sidewalk && !has_bus_lane && !has_bike_lane;
|
||||
|
||||
let mut full_side = driving_lanes_per_side;
|
||||
let mut fwd_side = driving_lanes_per_side.clone();
|
||||
if has_bus_lane {
|
||||
full_side.push(LaneType::Bus);
|
||||
fwd_side.push(LaneType::Bus);
|
||||
}
|
||||
if has_bike_lane {
|
||||
full_side.push(LaneType::Biking);
|
||||
fwd_side.push(LaneType::Biking);
|
||||
}
|
||||
if has_parking {
|
||||
full_side.push(LaneType::Parking);
|
||||
if r.parking_lane_fwd {
|
||||
fwd_side.push(LaneType::Parking);
|
||||
}
|
||||
if has_sidewalk {
|
||||
full_side.push(LaneType::Sidewalk);
|
||||
fwd_side.push(LaneType::Sidewalk);
|
||||
}
|
||||
|
||||
if oneway {
|
||||
// Only residential highways have a sidewalk on the other side of a highway.
|
||||
let other_side =
|
||||
// Only residential streets have a sidewalk on the other side of a one-way.
|
||||
// Ignore off-side parking, since cars don't know how to park on lanes without a driving
|
||||
// lane in that direction too.
|
||||
let back_side =
|
||||
if has_sidewalk && r.osm_tags.get("highway") == Some(&"residential".to_string()) {
|
||||
vec![LaneType::Sidewalk]
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
(full_side, other_side)
|
||||
(fwd_side, back_side)
|
||||
} else {
|
||||
(full_side.clone(), full_side)
|
||||
let mut back_side = driving_lanes_per_side;
|
||||
if has_bus_lane {
|
||||
back_side.push(LaneType::Bus);
|
||||
}
|
||||
if has_bike_lane {
|
||||
back_side.push(LaneType::Biking);
|
||||
}
|
||||
if r.parking_lane_back {
|
||||
back_side.push(LaneType::Parking);
|
||||
}
|
||||
if has_sidewalk {
|
||||
back_side.push(LaneType::Sidewalk);
|
||||
}
|
||||
(fwd_side, back_side)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,13 +58,7 @@ impl Map {
|
||||
) -> Map {
|
||||
timer.start("raw_map to Map");
|
||||
let gps_bounds = data.get_gps_bounds();
|
||||
|
||||
let bounds = {
|
||||
let mut b = Bounds::new();
|
||||
b.update(Pt2D::new(0.0, 0.0));
|
||||
b.update(gps_bounds.get_max_world_pt());
|
||||
b
|
||||
};
|
||||
let bounds = gps_bounds.to_bounds();
|
||||
|
||||
let mut m = Map {
|
||||
name,
|
||||
|
@ -67,6 +67,8 @@ pub struct Road {
|
||||
pub points: Vec<LonLat>,
|
||||
pub osm_tags: BTreeMap<String, String>,
|
||||
pub osm_way_id: i64,
|
||||
pub parking_lane_fwd: bool,
|
||||
pub parking_lane_back: bool,
|
||||
}
|
||||
|
||||
impl Road {
|
||||
|
@ -176,6 +176,8 @@ impl Model {
|
||||
],
|
||||
osm_tags,
|
||||
osm_way_id: idx as i64,
|
||||
parking_lane_fwd: r.lanes.fwd.contains(&LaneType::Parking),
|
||||
parking_lane_back: r.lanes.back.contains(&LaneType::Parking),
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user