simplify dataflow a bit in convert_osm

This commit is contained in:
Dustin Carlino 2019-08-26 15:22:03 -07:00
parent ead5593448
commit a5fc3b092f
4 changed files with 62 additions and 73 deletions

View File

@ -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();

View File

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

View File

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

View File

@ -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();