mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-26 07:52:05 +03:00
simplify dataflow a bit in convert_osm
This commit is contained in:
parent
ead5593448
commit
a5fc3b092f
@ -1,13 +1,14 @@
|
||||
use abstutil::{retain_btreemap, Timer};
|
||||
use geom::{LonLat, PolyLine, Polygon};
|
||||
use geom::PolyLine;
|
||||
use map_model::{raw_data, IntersectionType};
|
||||
|
||||
pub fn clip_map(map: &mut raw_data::Map, boundary_poly_pts: Vec<LonLat>, timer: &mut Timer) {
|
||||
pub fn clip_map(map: &mut raw_data::Map, timer: &mut Timer) {
|
||||
timer.start("clipping map to boundary");
|
||||
|
||||
let boundary_poly = Polygon::new(&map.gps_bounds.must_convert(&boundary_poly_pts));
|
||||
map.boundary_polygon = boundary_poly.clone();
|
||||
let boundary_lines: Vec<PolyLine> = boundary_poly
|
||||
// So we can use retain_btreemap without borrowing issues
|
||||
let boundary_polygon = map.boundary_polygon.clone();
|
||||
let boundary_lines: Vec<PolyLine> = map
|
||||
.boundary_polygon
|
||||
.points()
|
||||
.windows(2)
|
||||
.map(|pair| PolyLine::new(pair.to_vec()))
|
||||
@ -16,16 +17,18 @@ pub fn clip_map(map: &mut raw_data::Map, boundary_poly_pts: Vec<LonLat>, timer:
|
||||
// This is kind of indirect and slow, but first pass -- just remove roads that start or end
|
||||
// outside the boundary polygon.
|
||||
retain_btreemap(&mut map.roads, |_, r| {
|
||||
let first_in = boundary_poly.contains_pt(r.center_points[0]);
|
||||
let last_in = boundary_poly.contains_pt(*r.center_points.last().unwrap());
|
||||
let first_in = boundary_polygon.contains_pt(r.center_points[0]);
|
||||
let last_in = boundary_polygon.contains_pt(*r.center_points.last().unwrap());
|
||||
first_in || last_in
|
||||
});
|
||||
|
||||
let road_ids: Vec<raw_data::StableRoadID> = map.roads.keys().cloned().collect();
|
||||
for id in road_ids {
|
||||
let r = &map.roads[&id];
|
||||
let first_in = boundary_poly.contains_pt(r.center_points[0]);
|
||||
let last_in = boundary_poly.contains_pt(*r.center_points.last().unwrap());
|
||||
let first_in = map.boundary_polygon.contains_pt(r.center_points[0]);
|
||||
let last_in = map
|
||||
.boundary_polygon
|
||||
.contains_pt(*r.center_points.last().unwrap());
|
||||
|
||||
// Some roads start and end in-bounds, but dip out of bounds. Leave those alone for now.
|
||||
if first_in && last_in {
|
||||
@ -93,7 +96,7 @@ pub fn clip_map(map: &mut raw_data::Map, boundary_poly_pts: Vec<LonLat>, timer:
|
||||
b.polygon
|
||||
.points()
|
||||
.iter()
|
||||
.all(|pt| boundary_poly.contains_pt(*pt))
|
||||
.all(|pt| boundary_polygon.contains_pt(*pt))
|
||||
});
|
||||
|
||||
let mut result_areas = Vec::new();
|
||||
|
@ -5,7 +5,7 @@ mod remove_disconnected;
|
||||
mod split_ways;
|
||||
|
||||
use abstutil::Timer;
|
||||
use geom::{Distance, FindClosest, GPSBounds, LonLat, PolyLine, Pt2D};
|
||||
use geom::{Distance, FindClosest, GPSBounds, LonLat, PolyLine, Polygon, Pt2D};
|
||||
use kml::ExtraShapes;
|
||||
use map_model::{raw_data, OffstreetParking, LANE_THICKNESS};
|
||||
use std::fs::File;
|
||||
@ -52,18 +52,11 @@ pub fn convert(flags: &Flags, timer: &mut abstutil::Timer) -> raw_data::Map {
|
||||
if flags.clip.is_empty() {
|
||||
panic!("You must specify an Osmosis boundary polygon with --clip");
|
||||
}
|
||||
let boundary_polygon_pts = read_osmosis_polygon(&flags.clip);
|
||||
let mut gps_bounds = GPSBounds::new();
|
||||
for pt in &boundary_polygon_pts {
|
||||
gps_bounds.update(*pt);
|
||||
}
|
||||
|
||||
let mut map = split_ways::split_up_roads(
|
||||
osm::osm_to_raw_roads(&flags.osm, &gps_bounds, timer),
|
||||
gps_bounds,
|
||||
osm::extract_osm(&flags.osm, read_osmosis_polygon(&flags.clip), timer),
|
||||
timer,
|
||||
);
|
||||
clip::clip_map(&mut map, boundary_polygon_pts, timer);
|
||||
clip::clip_map(&mut map, timer);
|
||||
remove_disconnected::remove_disconnected_roads(&mut map, timer);
|
||||
|
||||
if flags.fast_dev {
|
||||
@ -143,8 +136,9 @@ fn use_parking_hints(map: &mut raw_data::Map, path: &str, timer: &mut Timer) {
|
||||
timer.stop("apply parking hints");
|
||||
}
|
||||
|
||||
fn read_osmosis_polygon(path: &str) -> Vec<LonLat> {
|
||||
fn read_osmosis_polygon(path: &str) -> raw_data::Map {
|
||||
let mut pts: Vec<LonLat> = Vec::new();
|
||||
let mut gps_bounds = GPSBounds::new();
|
||||
for (idx, maybe_line) in BufReader::new(File::open(path).unwrap())
|
||||
.lines()
|
||||
.enumerate()
|
||||
@ -158,11 +152,18 @@ fn read_osmosis_polygon(path: &str) -> Vec<LonLat> {
|
||||
}
|
||||
let parts: Vec<&str> = line.trim_start().split(" ").collect();
|
||||
assert!(parts.len() == 2);
|
||||
let lon = parts[0].parse::<f64>().unwrap();
|
||||
let lat = parts[1].parse::<f64>().unwrap();
|
||||
pts.push(LonLat::new(lon, lat));
|
||||
let pt = LonLat::new(
|
||||
parts[0].parse::<f64>().unwrap(),
|
||||
parts[1].parse::<f64>().unwrap(),
|
||||
);
|
||||
pts.push(pt);
|
||||
gps_bounds.update(pt);
|
||||
}
|
||||
pts
|
||||
|
||||
let mut map = raw_data::Map::blank();
|
||||
map.boundary_polygon = Polygon::new(&gps_bounds.must_convert(&pts));
|
||||
map.gps_bounds = gps_bounds;
|
||||
map
|
||||
}
|
||||
|
||||
fn use_offstreet_parking(map: &mut raw_data::Map, path: &str, timer: &mut Timer) {
|
||||
|
@ -1,21 +1,19 @@
|
||||
use abstutil::{FileWithProgress, Timer};
|
||||
use geom::{GPSBounds, HashablePt2D, LonLat, Polygon, Pt2D};
|
||||
use geom::{HashablePt2D, LonLat, Polygon, Pt2D};
|
||||
use map_model::{raw_data, AreaType};
|
||||
use osm_xml;
|
||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
|
||||
pub fn osm_to_raw_roads(
|
||||
pub fn extract_osm(
|
||||
osm_path: &str,
|
||||
gps_bounds: &GPSBounds,
|
||||
mut map: raw_data::Map,
|
||||
timer: &mut Timer,
|
||||
) -> (
|
||||
raw_data::Map,
|
||||
// Un-split roads
|
||||
Vec<raw_data::Road>,
|
||||
Vec<raw_data::Building>,
|
||||
Vec<raw_data::Area>,
|
||||
// traffic signals as Pt2D
|
||||
// Traffic signals
|
||||
HashSet<HashablePt2D>,
|
||||
// turn restrictions
|
||||
BTreeMap<i64, Vec<(String, i64)>>,
|
||||
) {
|
||||
let (reader, done) = FileWithProgress::new(osm_path).unwrap();
|
||||
let doc = osm_xml::OSM::parse(reader).expect("OSM parsing failed");
|
||||
@ -27,11 +25,8 @@ pub fn osm_to_raw_roads(
|
||||
);
|
||||
done(timer);
|
||||
|
||||
let mut id_to_way: HashMap<i64, Vec<LonLat>> = HashMap::new();
|
||||
let mut id_to_way: HashMap<i64, Vec<Pt2D>> = HashMap::new();
|
||||
let mut roads: Vec<raw_data::Road> = Vec::new();
|
||||
let mut buildings: Vec<raw_data::Building> = Vec::new();
|
||||
let mut areas: Vec<raw_data::Area> = Vec::new();
|
||||
let mut turn_restrictions: BTreeMap<i64, Vec<(String, i64)>> = BTreeMap::new();
|
||||
let mut traffic_signals: HashSet<HashablePt2D> = HashSet::new();
|
||||
|
||||
timer.start_iter("processing OSM nodes", doc.nodes.len());
|
||||
@ -40,7 +35,8 @@ pub fn osm_to_raw_roads(
|
||||
let tags = tags_to_map(&node.tags);
|
||||
if tags.get("highway") == Some(&"traffic_signals".to_string()) {
|
||||
traffic_signals.insert(
|
||||
Pt2D::forcibly_from_gps(LonLat::new(node.lon, node.lat), gps_bounds).to_hashable(),
|
||||
Pt2D::forcibly_from_gps(LonLat::new(node.lon, node.lat), &map.gps_bounds)
|
||||
.to_hashable(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -50,11 +46,11 @@ pub fn osm_to_raw_roads(
|
||||
timer.next();
|
||||
|
||||
let mut valid = true;
|
||||
let mut pts = Vec::new();
|
||||
let mut gps_pts = Vec::new();
|
||||
for node_ref in &way.nodes {
|
||||
match doc.resolve_reference(node_ref) {
|
||||
osm_xml::Reference::Node(node) => {
|
||||
pts.push(LonLat::new(node.lon, node.lat));
|
||||
gps_pts.push(LonLat::new(node.lon, node.lat));
|
||||
}
|
||||
// Don't handle nested ways/relations yet
|
||||
_ => {
|
||||
@ -65,14 +61,15 @@ pub fn osm_to_raw_roads(
|
||||
if !valid {
|
||||
continue;
|
||||
}
|
||||
let pts = map.gps_bounds.forcibly_convert(&gps_pts);
|
||||
let tags = tags_to_map(&way.tags);
|
||||
if is_road(&tags) {
|
||||
roads.push(raw_data::Road {
|
||||
osm_way_id: way.id,
|
||||
center_points: gps_bounds.forcibly_convert(&pts),
|
||||
center_points: pts,
|
||||
orig_id: raw_data::OriginalRoad {
|
||||
pt1: pts[0],
|
||||
pt2: *pts.last().unwrap(),
|
||||
pt1: gps_pts[0],
|
||||
pt2: *gps_pts.last().unwrap(),
|
||||
},
|
||||
osm_tags: tags,
|
||||
// We'll fill this out later
|
||||
@ -82,20 +79,17 @@ pub fn osm_to_raw_roads(
|
||||
parking_lane_back: false,
|
||||
});
|
||||
} else if is_bldg(&tags) {
|
||||
buildings.push(raw_data::Building {
|
||||
map.buildings.push(raw_data::Building {
|
||||
osm_way_id: way.id,
|
||||
polygon: Polygon::new(&Pt2D::approx_dedupe(
|
||||
gps_bounds.forcibly_convert(&pts),
|
||||
geom::EPSILON_DIST,
|
||||
)),
|
||||
polygon: Polygon::new(&Pt2D::approx_dedupe(pts, geom::EPSILON_DIST)),
|
||||
osm_tags: tags,
|
||||
parking: None,
|
||||
});
|
||||
} else if let Some(at) = get_area_type(&tags) {
|
||||
areas.push(raw_data::Area {
|
||||
map.areas.push(raw_data::Area {
|
||||
area_type: at,
|
||||
osm_id: way.id,
|
||||
polygon: Polygon::new(&gps_bounds.forcibly_convert(&pts)),
|
||||
polygon: Polygon::new(&pts),
|
||||
osm_tags: tags,
|
||||
});
|
||||
} else {
|
||||
@ -111,7 +105,7 @@ pub fn osm_to_raw_roads(
|
||||
if let Some(at) = get_area_type(&tags) {
|
||||
if tags.get("type") == Some(&"multipolygon".to_string()) {
|
||||
let mut ok = true;
|
||||
let mut pts_per_way: Vec<Vec<LonLat>> = Vec::new();
|
||||
let mut pts_per_way: Vec<Vec<Pt2D>> = Vec::new();
|
||||
for member in &rel.members {
|
||||
match member {
|
||||
osm_xml::Member::Way(osm_xml::UnresolvedReference::Way(id), ref role) => {
|
||||
@ -138,11 +132,11 @@ pub fn osm_to_raw_roads(
|
||||
if polygons.is_empty() {
|
||||
println!("Relation {} failed to glue multipolygon", rel.id);
|
||||
} else {
|
||||
for points in polygons {
|
||||
areas.push(raw_data::Area {
|
||||
for polygon in polygons {
|
||||
map.areas.push(raw_data::Area {
|
||||
area_type: at,
|
||||
osm_id: rel.id,
|
||||
polygon: Polygon::new(&gps_bounds.forcibly_convert(&points)),
|
||||
polygon,
|
||||
osm_tags: tags.clone(),
|
||||
});
|
||||
}
|
||||
@ -165,7 +159,7 @@ pub fn osm_to_raw_roads(
|
||||
}
|
||||
if let (Some(from_way_id), Some(to_way_id)) = (from_way_id, to_way_id) {
|
||||
if let Some(restriction) = tags.get("restriction") {
|
||||
turn_restrictions
|
||||
map.turn_restrictions
|
||||
.entry(from_way_id)
|
||||
.or_insert_with(Vec::new)
|
||||
.push((restriction.to_string(), to_way_id));
|
||||
@ -174,7 +168,7 @@ pub fn osm_to_raw_roads(
|
||||
}
|
||||
}
|
||||
|
||||
(roads, buildings, areas, traffic_signals, turn_restrictions)
|
||||
(map, roads, traffic_signals)
|
||||
}
|
||||
|
||||
fn tags_to_map(raw_tags: &[osm_xml::Tag]) -> BTreeMap<String, String> {
|
||||
@ -247,12 +241,12 @@ fn get_area_type(tags: &BTreeMap<String, String>) -> Option<AreaType> {
|
||||
}
|
||||
|
||||
// The result could be more than one disjoint polygon.
|
||||
fn glue_multipolygon(mut pts_per_way: Vec<Vec<LonLat>>) -> Vec<Vec<LonLat>> {
|
||||
fn glue_multipolygon(mut pts_per_way: Vec<Vec<Pt2D>>) -> Vec<Polygon> {
|
||||
// First deal with all of the closed loops.
|
||||
let mut polygons: Vec<Vec<LonLat>> = Vec::new();
|
||||
let mut polygons: Vec<Polygon> = Vec::new();
|
||||
pts_per_way.retain(|pts| {
|
||||
if pts[0] == *pts.last().unwrap() {
|
||||
polygons.push(pts.to_vec());
|
||||
polygons.push(Polygon::new(pts));
|
||||
false
|
||||
} else {
|
||||
true
|
||||
@ -294,6 +288,6 @@ fn glue_multipolygon(mut pts_per_way: Vec<Vec<LonLat>>) -> Vec<Vec<LonLat>> {
|
||||
if result[0] != *result.last().unwrap() {
|
||||
result.push(result[0]);
|
||||
}
|
||||
polygons.push(result);
|
||||
polygons.push(Polygon::new(&result));
|
||||
polygons
|
||||
}
|
||||
|
@ -1,17 +1,14 @@
|
||||
use abstutil::Timer;
|
||||
use geom::{GPSBounds, HashablePt2D, Pt2D};
|
||||
use geom::{HashablePt2D, Pt2D};
|
||||
use map_model::{raw_data, IntersectionType};
|
||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
pub fn split_up_roads(
|
||||
(mut roads, buildings, areas, traffic_signals, turn_restrictions): (
|
||||
(mut map, mut roads, traffic_signals): (
|
||||
raw_data::Map,
|
||||
Vec<raw_data::Road>,
|
||||
Vec<raw_data::Building>,
|
||||
Vec<raw_data::Area>,
|
||||
HashSet<HashablePt2D>,
|
||||
BTreeMap<i64, Vec<(String, i64)>>,
|
||||
),
|
||||
gps_bounds: GPSBounds,
|
||||
timer: &mut Timer,
|
||||
) -> raw_data::Map {
|
||||
timer.start("splitting up roads");
|
||||
@ -60,12 +57,6 @@ pub fn split_up_roads(
|
||||
}
|
||||
}
|
||||
|
||||
let mut map = raw_data::Map::blank();
|
||||
map.gps_bounds = gps_bounds;
|
||||
map.buildings = buildings;
|
||||
map.areas = areas;
|
||||
map.turn_restrictions = turn_restrictions;
|
||||
|
||||
// All of the roundabout points will just keep moving the intersection
|
||||
for (pt, id) in &pt_to_intersection {
|
||||
let point = pt.to_pt2d();
|
||||
|
Loading…
Reference in New Issue
Block a user