adding a stable ID for raw roads and intersections. way easier to refer to things in the midst of deletions.

This commit is contained in:
Dustin Carlino 2019-01-17 08:46:31 -08:00
parent dfe50dcee4
commit 3422877d3d
13 changed files with 138 additions and 95 deletions

View File

@ -58,8 +58,7 @@ pub struct Flags {
pub fn convert(flags: &Flags, timer: &mut abstutil::Timer) -> raw_data::Map { pub fn convert(flags: &Flags, timer: &mut abstutil::Timer) -> raw_data::Map {
let elevation = Elevation::new(&flags.elevation).expect("loading .hgt failed"); let elevation = Elevation::new(&flags.elevation).expect("loading .hgt failed");
let raw_map = osm::osm_to_raw_roads(&flags.osm, timer); let mut map = split_ways::split_up_roads(osm::osm_to_raw_roads(&flags.osm, timer), &elevation);
let mut map = split_ways::split_up_roads(raw_map, &elevation);
remove_disconnected::remove_disconnected_roads(&mut map, timer); remove_disconnected::remove_disconnected_roads(&mut map, timer);
let gps_bounds = map.get_gps_bounds(); let gps_bounds = map.get_gps_bounds();
@ -111,7 +110,7 @@ pub fn convert(flags: &Flags, timer: &mut abstutil::Timer) -> raw_data::Map {
// intersection // intersection
let closest_intersection = map let closest_intersection = map
.intersections .intersections
.iter_mut() .values_mut()
.min_by_key(|i| NotNan::new(distance(i)).unwrap()) .min_by_key(|i| NotNan::new(distance(i)).unwrap())
.unwrap(); .unwrap();
let dist = distance(closest_intersection); let dist = distance(closest_intersection);
@ -139,8 +138,9 @@ pub fn convert(flags: &Flags, timer: &mut abstutil::Timer) -> raw_data::Map {
fn use_parking_hints(map: &mut raw_data::Map, shapes: ExtraShapes, gps_bounds: &GPSBounds) { fn use_parking_hints(map: &mut raw_data::Map, shapes: ExtraShapes, gps_bounds: &GPSBounds) {
// Match shapes with the nearest road + direction (true for forwards) // Match shapes with the nearest road + direction (true for forwards)
let mut closest: FindClosest<(usize, bool)> = FindClosest::new(&gps_bounds.to_bounds()); let mut closest: FindClosest<(raw_data::StableRoadID, bool)> =
for (idx, r) in map.roads.iter().enumerate() { FindClosest::new(&gps_bounds.to_bounds());
for (id, r) in &map.roads {
let pts = PolyLine::new( let pts = PolyLine::new(
r.points r.points
.iter() .iter()
@ -148,8 +148,8 @@ fn use_parking_hints(map: &mut raw_data::Map, shapes: ExtraShapes, gps_bounds: &
.collect(), .collect(),
); );
closest.add((idx, true), &pts.shift_right(LANE_THICKNESS)); closest.add((*id, true), &pts.shift_right(LANE_THICKNESS));
closest.add((idx, false), &pts.shift_left(LANE_THICKNESS)); closest.add((*id, false), &pts.shift_left(LANE_THICKNESS));
} }
'SHAPE: for s in shapes.shapes.into_iter() { 'SHAPE: for s in shapes.shapes.into_iter() {
@ -173,9 +173,9 @@ fn use_parking_hints(map: &mut raw_data::Map, shapes: ExtraShapes, gps_bounds: &
&& category != Some(&"No Parking Allowed".to_string()); && category != Some(&"No Parking Allowed".to_string());
// Blindly override prior values. // Blindly override prior values.
if fwds { if fwds {
map.roads[r].parking_lane_fwd = has_parking; map.roads.get_mut(&r).unwrap().parking_lane_fwd = has_parking;
} else { } else {
map.roads[r].parking_lane_back = has_parking; map.roads.get_mut(&r).unwrap().parking_lane_back = has_parking;
} }
} }
} }

View File

@ -6,8 +6,14 @@ use map_model::{raw_data, AreaType};
use osm_xml; use osm_xml;
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
// TODO Result, but is there an easy way to say io error or osm xml error? pub fn osm_to_raw_roads(
pub fn osm_to_raw_roads(osm_path: &str, timer: &mut Timer) -> raw_data::Map { osm_path: &str,
timer: &mut Timer,
) -> (
Vec<raw_data::Road>,
Vec<raw_data::Building>,
Vec<raw_data::Area>,
) {
let (reader, done) = FileWithProgress::new(osm_path).unwrap(); let (reader, done) = FileWithProgress::new(osm_path).unwrap();
let doc = osm_xml::OSM::parse(reader).expect("OSM parsing failed"); let doc = osm_xml::OSM::parse(reader).expect("OSM parsing failed");
println!( println!(
@ -19,7 +25,9 @@ pub fn osm_to_raw_roads(osm_path: &str, timer: &mut Timer) -> raw_data::Map {
done(timer); done(timer);
let mut id_to_way: HashMap<i64, Vec<LonLat>> = HashMap::new(); let mut id_to_way: HashMap<i64, Vec<LonLat>> = HashMap::new();
let mut map = raw_data::Map::blank(); 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();
timer.start_iter("processing OSM ways", doc.ways.len()); timer.start_iter("processing OSM ways", doc.ways.len());
for way in doc.ways.values() { for way in doc.ways.values() {
timer.next(); timer.next();
@ -42,7 +50,7 @@ pub fn osm_to_raw_roads(osm_path: &str, timer: &mut Timer) -> raw_data::Map {
} }
let tags = tags_to_map(&way.tags); let tags = tags_to_map(&way.tags);
if is_road(&tags) { if is_road(&tags) {
map.roads.push(raw_data::Road { roads.push(raw_data::Road {
osm_way_id: way.id, osm_way_id: way.id,
points: pts, points: pts,
osm_tags: tags, osm_tags: tags,
@ -51,13 +59,13 @@ pub fn osm_to_raw_roads(osm_path: &str, timer: &mut Timer) -> raw_data::Map {
parking_lane_back: false, parking_lane_back: false,
}); });
} else if is_bldg(&tags) { } else if is_bldg(&tags) {
map.buildings.push(raw_data::Building { buildings.push(raw_data::Building {
osm_way_id: way.id, osm_way_id: way.id,
points: pts, points: pts,
osm_tags: tags, osm_tags: tags,
}); });
} else if let Some(at) = get_area_type(&tags) { } else if let Some(at) = get_area_type(&tags) {
map.areas.push(raw_data::Area { areas.push(raw_data::Area {
area_type: at, area_type: at,
osm_way_id: way.id, osm_way_id: way.id,
points: pts, points: pts,
@ -81,7 +89,7 @@ pub fn osm_to_raw_roads(osm_path: &str, timer: &mut Timer) -> raw_data::Map {
match id_to_way.get(&id) { match id_to_way.get(&id) {
Some(pts) => { Some(pts) => {
if role == "outer" { if role == "outer" {
map.areas.push(raw_data::Area { areas.push(raw_data::Area {
area_type: at, area_type: at,
osm_way_id: id, osm_way_id: id,
points: pts.to_vec(), points: pts.to_vec(),
@ -108,7 +116,7 @@ pub fn osm_to_raw_roads(osm_path: &str, timer: &mut Timer) -> raw_data::Map {
} }
} }
map (roads, buildings, areas)
} }
fn tags_to_map(raw_tags: &[osm_xml::Tag]) -> BTreeMap<String, String> { fn tags_to_map(raw_tags: &[osm_xml::Tag]) -> BTreeMap<String, String> {

View File

@ -8,21 +8,19 @@ pub fn remove_disconnected_roads(map: &mut raw_data::Map, timer: &mut Timer) {
// This is a simple floodfill, not Tarjan's. Assumes all roads bidirectional. // This is a simple floodfill, not Tarjan's. Assumes all roads bidirectional.
// All the usizes are indices into the original list of roads // All the usizes are indices into the original list of roads
let mut next_roads: MultiMap<HashablePt2D, usize> = MultiMap::new(); let mut next_roads: MultiMap<HashablePt2D, raw_data::StableRoadID> = MultiMap::new();
for (idx, r) in map.roads.iter().enumerate() { for (id, r) in &map.roads {
next_roads.insert(r.first_pt().to_hashable(), idx); next_roads.insert(r.first_pt().to_hashable(), *id);
next_roads.insert(r.last_pt().to_hashable(), idx); next_roads.insert(r.last_pt().to_hashable(), *id);
} }
let mut partitions: Vec<Vec<usize>> = Vec::new(); let mut partitions: Vec<Vec<raw_data::StableRoadID>> = Vec::new();
let mut unvisited_roads: HashSet<usize> = HashSet::new(); let mut unvisited_roads: HashSet<raw_data::StableRoadID> = map.roads.keys().cloned().collect();
for i in 0..map.roads.len() {
unvisited_roads.insert(i);
}
while !unvisited_roads.is_empty() { while !unvisited_roads.is_empty() {
let mut queue_roads: Vec<usize> = vec![*unvisited_roads.iter().next().unwrap()]; let mut queue_roads: Vec<raw_data::StableRoadID> =
let mut current_partition: Vec<usize> = Vec::new(); vec![*unvisited_roads.iter().next().unwrap()];
let mut current_partition: Vec<raw_data::StableRoadID> = Vec::new();
while !queue_roads.is_empty() { while !queue_roads.is_empty() {
let current = queue_roads.pop().unwrap(); let current = queue_roads.pop().unwrap();
if !unvisited_roads.contains(&current) { if !unvisited_roads.contains(&current) {
@ -31,7 +29,7 @@ pub fn remove_disconnected_roads(map: &mut raw_data::Map, timer: &mut Timer) {
unvisited_roads.remove(&current); unvisited_roads.remove(&current);
current_partition.push(current); current_partition.push(current);
let current_r = &map.roads[current]; let current_r = &map.roads[&current];
for other_r in next_roads.get(current_r.first_pt().to_hashable()).iter() { for other_r in next_roads.get(current_r.first_pt().to_hashable()).iter() {
queue_roads.push(*other_r); queue_roads.push(*other_r);
} }
@ -45,26 +43,30 @@ pub fn remove_disconnected_roads(map: &mut raw_data::Map, timer: &mut Timer) {
partitions.sort_by_key(|roads| roads.len()); partitions.sort_by_key(|roads| roads.len());
partitions.reverse(); partitions.reverse();
println!("Main partition has {} roads", partitions[0].len()); println!("Main partition has {} roads", partitions[0].len());
let mut remove_roads = HashSet::new();
for p in partitions.iter().skip(1) { for p in partitions.iter().skip(1) {
println!("Removing disconnected partition with {} roads", p.len()); println!("Removing disconnected partition with {} roads", p.len());
for idx in p { for id in p {
remove_roads.insert(idx); let r = map.roads.remove(id).unwrap();
next_roads.remove(r.first_pt().to_hashable(), *id);
next_roads.remove(r.last_pt().to_hashable(), *id);
} }
} }
let mut roads: Vec<raw_data::Road> = Vec::new();
for (idx, r) in map.roads.iter().enumerate() {
if remove_roads.contains(&idx) {
next_roads.remove(r.first_pt().to_hashable(), idx);
next_roads.remove(r.last_pt().to_hashable(), idx);
} else {
roads.push(r.clone());
}
}
map.roads = roads;
// Remove intersections without any roads // Remove intersections without any roads
map.intersections // TODO retain for BTreeMap, please!
.retain(|i| !next_roads.get(i.point.to_hashable()).is_empty()); let remove_intersections: Vec<raw_data::StableIntersectionID> = map
.intersections
.iter()
.filter_map(|(id, i)| {
if next_roads.get(i.point.to_hashable()).is_empty() {
Some(*id)
} else {
None
}
})
.collect();
for id in remove_intersections {
map.intersections.remove(&id);
}
timer.stop("removing disconnected roads"); timer.stop("removing disconnected roads");
} }

View File

@ -6,14 +6,21 @@ use geom::{HashablePt2D, LonLat};
use map_model::{raw_data, IntersectionType}; use map_model::{raw_data, IntersectionType};
use std::collections::{BTreeSet, HashMap}; use std::collections::{BTreeSet, HashMap};
pub fn split_up_roads(mut input: raw_data::Map, elevation: &srtm::Elevation) -> raw_data::Map { pub fn split_up_roads(
println!("splitting up {} roads", input.roads.len()); (mut roads, buildings, areas): (
Vec<raw_data::Road>,
Vec<raw_data::Building>,
Vec<raw_data::Area>,
),
elevation: &srtm::Elevation,
) -> raw_data::Map {
println!("splitting up {} roads", roads.len());
// Look for roundabout ways. Map all points on the roundabout to a new point in the center. // Look for roundabout ways. Map all points on the roundabout to a new point in the center.
// When we process ways that touch any point on the roundabout, make them instead point to the // When we process ways that touch any point on the roundabout, make them instead point to the
// roundabout's center, so that the roundabout winds up looking like a single intersection. // roundabout's center, so that the roundabout winds up looking like a single intersection.
let mut remap_roundabouts: HashMap<HashablePt2D, LonLat> = HashMap::new(); let mut remap_roundabouts: HashMap<HashablePt2D, LonLat> = HashMap::new();
input.roads.retain(|r| { roads.retain(|r| {
if r.osm_tags.get("junction") == Some(&"roundabout".to_string()) { if r.osm_tags.get("junction") == Some(&"roundabout".to_string()) {
let center = LonLat::center(&r.points); let center = LonLat::center(&r.points);
for pt in &r.points { for pt in &r.points {
@ -27,7 +34,7 @@ pub fn split_up_roads(mut input: raw_data::Map, elevation: &srtm::Elevation) ->
let mut counts_per_pt: HashMap<HashablePt2D, usize> = HashMap::new(); let mut counts_per_pt: HashMap<HashablePt2D, usize> = HashMap::new();
let mut intersections: BTreeSet<HashablePt2D> = BTreeSet::new(); let mut intersections: BTreeSet<HashablePt2D> = BTreeSet::new();
for r in input.roads.iter_mut() { for r in roads.iter_mut() {
let added_to_start = if let Some(center) = remap_roundabouts.get(&r.points[0].to_hashable()) let added_to_start = if let Some(center) = remap_roundabouts.get(&r.points[0].to_hashable())
{ {
r.points.insert(0, *center); r.points.insert(0, *center);
@ -74,20 +81,23 @@ pub fn split_up_roads(mut input: raw_data::Map, elevation: &srtm::Elevation) ->
} }
let mut map = raw_data::Map::blank(); let mut map = raw_data::Map::blank();
map.buildings.extend(input.buildings.clone()); map.buildings = buildings;
map.areas.extend(input.areas.clone()); map.areas = areas;
for pt in &intersections { for (idx, pt) in intersections.iter().enumerate() {
map.intersections.push(raw_data::Intersection { map.intersections.insert(
point: LonLat::new(pt.x(), pt.y()), raw_data::StableIntersectionID(idx),
elevation: elevation.get(pt.x(), pt.y()) * si::M, raw_data::Intersection {
intersection_type: IntersectionType::StopSign, point: LonLat::new(pt.x(), pt.y()),
label: None, elevation: elevation.get(pt.x(), pt.y()) * si::M,
}); intersection_type: IntersectionType::StopSign,
label: None,
},
);
} }
// Now actually split up the roads based on the intersections // Now actually split up the roads based on the intersections
for orig_road in &input.roads { for orig_road in &roads {
let mut r = orig_road.clone(); let mut r = orig_road.clone();
r.points.clear(); r.points.clear();
@ -95,7 +105,8 @@ pub fn split_up_roads(mut input: raw_data::Map, elevation: &srtm::Elevation) ->
r.points.push(pt.clone()); r.points.push(pt.clone());
if r.points.len() > 1 && intersections.contains(&pt.to_hashable()) { if r.points.len() > 1 && intersections.contains(&pt.to_hashable()) {
// Start a new road // Start a new road
map.roads.push(r.clone()); map.roads
.insert(raw_data::StableRoadID(map.roads.len()), r.clone());
r.points.clear(); r.points.clear();
r.points.push(pt.clone()); r.points.push(pt.clone());
} }
@ -103,7 +114,5 @@ pub fn split_up_roads(mut input: raw_data::Map, elevation: &srtm::Elevation) ->
assert!(r.points.len() == 1); assert!(r.points.len() == 1);
} }
// TODO we're somehow returning an intersection here with no roads. figure that out.
map map
} }

View File

@ -70,7 +70,10 @@ fn tooltip_lines(obj: ID, ctx: &Ctx) -> Text {
None, None,
); );
txt.add_line(format!("From OSM way {}", r.osm_way_id)); txt.add_line(format!("From OSM way {}", r.osm_way_id));
txt.add_line(format!("Parent {} points to {}", r.id, r.dst_i)); txt.add_line(format!(
"Parent {} (stable ID {}) points to {}",
r.id, r.stable_id.0, r.dst_i
));
txt.add_line(format!( txt.add_line(format!(
"Lane goes from {} to {}", "Lane goes from {} to {}",
i1.elevation, i2.elevation i1.elevation, i2.elevation
@ -88,7 +91,9 @@ fn tooltip_lines(obj: ID, ctx: &Ctx) -> Text {
} }
ID::Intersection(id) => { ID::Intersection(id) => {
txt.add_line(id.to_string()); txt.add_line(id.to_string());
txt.add_line(format!("Roads: {:?}", map.get_i(id).roads)); let i = map.get_i(id);
txt.add_line(format!("Roads: {:?}", i.roads));
txt.add_line(format!("Stable ID {}", i.stable_id.0));
} }
ID::Turn(id) => { ID::Turn(id) => {
let t = map.get_t(id); let t = map.get_t(id);

View File

@ -304,8 +304,8 @@ impl ScreenCaptureState {
args.push("full.png".to_string()); args.push("full.png".to_string());
let mut file = fs::File::create("screencap/combine.sh").unwrap(); let mut file = fs::File::create("screencap/combine.sh").unwrap();
write!(file, "#!/bin/bash\n\n").unwrap(); writeln!(file, "#!/bin/bash\n").unwrap();
write!(file, "montage {}\n", args.join(" ")).unwrap(); writeln!(file, "montage {}", args.join(" ")).unwrap();
write!(file, "rm -f combine.sh\n").unwrap(); writeln!(file, "rm -f combine.sh").unwrap();
} }
} }

View File

@ -1,6 +1,6 @@
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0 // Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
use crate::{LaneID, LaneType, Map, RoadID, TurnID}; use crate::{raw_data, LaneID, LaneType, Map, RoadID, TurnID};
use abstutil; use abstutil;
use dimensioned::si; use dimensioned::si;
use geom::Pt2D; use geom::Pt2D;
@ -38,6 +38,7 @@ pub struct Intersection {
pub intersection_type: IntersectionType, pub intersection_type: IntersectionType,
pub label: Option<String>, pub label: Option<String>,
pub stable_id: raw_data::StableIntersectionID,
// Note that a lane may belong to both incoming_lanes and outgoing_lanes. // Note that a lane may belong to both incoming_lanes and outgoing_lanes.
// TODO narrow down when and why. is it just sidewalks in weird cases? // TODO narrow down when and why. is it just sidewalks in weird cases?

View File

@ -29,7 +29,7 @@ pub fn make_half_map(
let mut pt_to_intersection: HashMap<HashablePt2D, IntersectionID> = HashMap::new(); let mut pt_to_intersection: HashMap<HashablePt2D, IntersectionID> = HashMap::new();
for (idx, i) in data.intersections.iter().enumerate() { for (idx, (stable_id, i)) in data.intersections.iter().enumerate() {
let id = IntersectionID(idx); let id = IntersectionID(idx);
let pt = Pt2D::from_gps(i.point, &gps_bounds).unwrap(); let pt = Pt2D::from_gps(i.point, &gps_bounds).unwrap();
m.intersections.push(Intersection { m.intersections.push(Intersection {
@ -41,6 +41,7 @@ pub fn make_half_map(
// Might change later // Might change later
intersection_type: i.intersection_type, intersection_type: i.intersection_type,
label: i.label.clone(), label: i.label.clone(),
stable_id: *stable_id,
incoming_lanes: Vec::new(), incoming_lanes: Vec::new(),
outgoing_lanes: Vec::new(), outgoing_lanes: Vec::new(),
roads: BTreeSet::new(), roads: BTreeSet::new(),
@ -50,7 +51,7 @@ pub fn make_half_map(
let mut counter = 0; let mut counter = 0;
timer.start_iter("expand roads to lanes", data.roads.len()); timer.start_iter("expand roads to lanes", data.roads.len());
for (_, r) in data.roads.iter().enumerate() { for (stable_id, r) in &data.roads {
timer.next(); timer.next();
let road_id = RoadID(m.roads.len()); let road_id = RoadID(m.roads.len());
let road_center_pts = PolyLine::new( let road_center_pts = PolyLine::new(
@ -75,6 +76,7 @@ pub fn make_half_map(
id: road_id, id: road_id,
osm_tags: r.osm_tags.clone(), osm_tags: r.osm_tags.clone(),
osm_way_id: r.osm_way_id, osm_way_id: r.osm_way_id,
stable_id: *stable_id,
children_forwards: Vec::new(), children_forwards: Vec::new(),
children_backwards: Vec::new(), children_backwards: Vec::new(),
center_pts: road_center_pts.clone(), center_pts: road_center_pts.clone(),

View File

@ -72,6 +72,7 @@ fn merge(delete_r: RoadID, mut m: HalfMap) -> HalfMap {
elevation: m.intersections[old_i1.0].elevation, elevation: m.intersections[old_i1.0].elevation,
intersection_type: m.intersections[old_i1.0].intersection_type, intersection_type: m.intersections[old_i1.0].intersection_type,
label: m.intersections[old_i1.0].label.clone(), label: m.intersections[old_i1.0].label.clone(),
stable_id: m.intersections[old_i1.0].stable_id,
incoming_lanes: Vec::new(), incoming_lanes: Vec::new(),
outgoing_lanes: Vec::new(), outgoing_lanes: Vec::new(),
roads: BTreeSet::new(), roads: BTreeSet::new(),

View File

@ -6,10 +6,17 @@ use gtfs::Route;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::collections::BTreeMap; use std::collections::BTreeMap;
// Stable IDs don't get compacted as we merge and delete things.
//#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, PartialOrd, Ord, Clone, Copy, Hash)]
pub struct StableRoadID(pub usize);
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, PartialOrd, Ord, Clone, Copy, Hash)]
pub struct StableIntersectionID(pub usize);
#[derive(PartialEq, Debug, Serialize, Deserialize)] #[derive(PartialEq, Debug, Serialize, Deserialize)]
pub struct Map { pub struct Map {
pub roads: Vec<Road>, pub roads: BTreeMap<StableRoadID, Road>,
pub intersections: Vec<Intersection>, pub intersections: BTreeMap<StableIntersectionID, Intersection>,
pub buildings: Vec<Building>, pub buildings: Vec<Building>,
pub parcels: Vec<Parcel>, pub parcels: Vec<Parcel>,
pub bus_routes: Vec<Route>, pub bus_routes: Vec<Route>,
@ -21,8 +28,8 @@ pub struct Map {
impl Map { impl Map {
pub fn blank() -> Map { pub fn blank() -> Map {
Map { Map {
roads: Vec::new(), roads: BTreeMap::new(),
intersections: Vec::new(), intersections: BTreeMap::new(),
buildings: Vec::new(), buildings: Vec::new(),
parcels: Vec::new(), parcels: Vec::new(),
bus_routes: Vec::new(), bus_routes: Vec::new(),
@ -34,12 +41,12 @@ impl Map {
pub fn get_gps_bounds(&self) -> GPSBounds { pub fn get_gps_bounds(&self) -> GPSBounds {
let mut bounds = GPSBounds::new(); let mut bounds = GPSBounds::new();
for r in &self.roads { for r in self.roads.values() {
for pt in &r.points { for pt in &r.points {
bounds.update(*pt); bounds.update(*pt);
} }
} }
for i in &self.intersections { for i in self.intersections.values() {
bounds.update(i.point); bounds.update(i.point);
} }
for b in &self.buildings { for b in &self.buildings {

View File

@ -1,4 +1,4 @@
use crate::{IntersectionID, LaneID, LaneType}; use crate::{raw_data, IntersectionID, LaneID, LaneType};
use abstutil::Error; use abstutil::Error;
use dimensioned::si; use dimensioned::si;
use geom::PolyLine; use geom::PolyLine;
@ -22,6 +22,7 @@ pub struct Road {
pub id: RoadID, pub id: RoadID,
pub osm_tags: BTreeMap<String, String>, pub osm_tags: BTreeMap<String, String>,
pub osm_way_id: i64, pub osm_way_id: i64,
pub stable_id: raw_data::StableRoadID,
// Invariant: A road must contain at least one child // Invariant: A road must contain at least one child
pub children_forwards: Vec<(LaneID, LaneType)>, pub children_forwards: Vec<(LaneID, LaneType)>,

View File

@ -336,25 +336,31 @@ impl Model {
if let Some(ref label) = r.back_label { if let Some(ref label) = r.back_label {
osm_tags.insert("back_label".to_string(), label.to_string()); osm_tags.insert("back_label".to_string(), label.to_string());
} }
map.roads.push(raw_data::Road { map.roads.insert(
points: vec![ raw_data::StableRoadID(idx),
pt(self.intersections[&r.i1].center), raw_data::Road {
pt(self.intersections[&r.i2].center), points: vec![
], pt(self.intersections[&r.i1].center),
osm_tags, pt(self.intersections[&r.i2].center),
osm_way_id: idx as i64, ],
parking_lane_fwd: r.lanes.fwd.contains(&LaneType::Parking), osm_tags,
parking_lane_back: r.lanes.back.contains(&LaneType::Parking), osm_way_id: idx as i64,
}); parking_lane_fwd: r.lanes.fwd.contains(&LaneType::Parking),
parking_lane_back: r.lanes.back.contains(&LaneType::Parking),
},
);
} }
for i in self.intersections.values() { for (idx, i) in self.intersections.values().enumerate() {
map.intersections.push(raw_data::Intersection { map.intersections.insert(
point: pt(i.center), raw_data::StableIntersectionID(idx),
elevation: 0.0 * si::M, raw_data::Intersection {
intersection_type: i.intersection_type, point: pt(i.center),
label: i.label.clone(), elevation: 0.0 * si::M,
}); intersection_type: i.intersection_type,
label: i.label.clone(),
},
);
} }
for (idx, b) in self.buildings.values().enumerate() { for (idx, b) in self.buildings.values().enumerate() {
@ -387,7 +393,7 @@ impl Model {
let mut pt_to_intersection: HashMap<HashablePt2D, IntersectionID> = HashMap::new(); let mut pt_to_intersection: HashMap<HashablePt2D, IntersectionID> = HashMap::new();
let mut quadtree = QuadTree::default(gps_bounds.to_bounds().as_bbox()); let mut quadtree = QuadTree::default(gps_bounds.to_bounds().as_bbox());
for (idx, i) in data.intersections.iter().enumerate() { for (idx, i) in data.intersections.values().enumerate() {
let center = Pt2D::from_gps(i.point, &gps_bounds).unwrap(); let center = Pt2D::from_gps(i.point, &gps_bounds).unwrap();
let i = Intersection { let i = Intersection {
center, center,
@ -399,7 +405,7 @@ impl Model {
pt_to_intersection.insert(center.into(), idx); pt_to_intersection.insert(center.into(), idx);
} }
for r in &data.roads { for r in data.roads.values() {
let i1 = pt_to_intersection[&Pt2D::from_gps(r.points[0], &gps_bounds).unwrap().into()]; let i1 = pt_to_intersection[&Pt2D::from_gps(r.points[0], &gps_bounds).unwrap().into()];
let i2 = pt_to_intersection[&Pt2D::from_gps(*r.points.last().unwrap(), &gps_bounds) let i2 = pt_to_intersection[&Pt2D::from_gps(*r.points.last().unwrap(), &gps_bounds)
.unwrap() .unwrap()

View File

@ -16,6 +16,7 @@ pub fn run(t: &mut TestRunner) {
gtfs: "../data/input/google_transit_2018_18_08".to_string(), gtfs: "../data/input/google_transit_2018_18_08".to_string(),
neighborhoods: "../data/input/neighborhoods.geojson".to_string(), neighborhoods: "../data/input/neighborhoods.geojson".to_string(),
output: "convert_osm_twice".to_string(), output: "convert_osm_twice".to_string(),
fast_dev: false,
}; };
let map1 = convert_osm::convert(&flags, &mut abstutil::Timer::new("convert map")); let map1 = convert_osm::convert(&flags, &mut abstutil::Timer::new("convert map"));