mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-27 15:03:20 +03:00
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:
parent
dfe50dcee4
commit
3422877d3d
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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> {
|
||||||
|
@ -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(¤t) {
|
if !unvisited_roads.contains(¤t) {
|
||||||
@ -31,7 +29,7 @@ pub fn remove_disconnected_roads(map: &mut raw_data::Map, timer: &mut Timer) {
|
|||||||
unvisited_roads.remove(¤t);
|
unvisited_roads.remove(¤t);
|
||||||
current_partition.push(current);
|
current_partition.push(current);
|
||||||
|
|
||||||
let current_r = &map.roads[current];
|
let current_r = &map.roads[¤t];
|
||||||
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");
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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?
|
||||||
|
@ -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(),
|
||||||
|
@ -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(),
|
||||||
|
@ -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 {
|
||||||
|
@ -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)>,
|
||||||
|
@ -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()
|
||||||
|
@ -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"));
|
||||||
|
Loading…
Reference in New Issue
Block a user