mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-25 07:25:47 +03:00
splitting map model into more modules
This commit is contained in:
parent
2b9eb66ba1
commit
d9e46c5960
@ -83,3 +83,20 @@ the transition is hard:
|
||||
so really do this in two parts:
|
||||
1) current structure with weird intermediate stuff, but new geometry libs
|
||||
2) careful reorg
|
||||
|
||||
wait slow down even more -- before any of this change, lanes on adjacent roads smoosh into each other. main road doesnt, but other parts do.
|
||||
- at every intersection, find corresponding lanes and trim back center lines
|
||||
- do we need to do this at the level of the polygons?!
|
||||
|
||||
|
||||
|
||||
- follow aorta's multi phase map construction better.
|
||||
- FIRST: move geom things into the Map structs directly. get rid of that crate.
|
||||
---> option 1: module per object type, geometry and graph squished together
|
||||
- option 2: try to separate the graph/geom stuff within map model.
|
||||
- THEN: express the proto -> runtime map loading as a sequence of phases
|
||||
- keep doing the current road trimming for the moment
|
||||
- later, this could be the same as the OSM conversion. just
|
||||
like aorta's map make. but instead, be able to restart from
|
||||
any point, by the magic of easy serialization.
|
||||
- get rid of the protobuf
|
||||
|
21
map_model/src/building.rs
Normal file
21
map_model/src/building.rs
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
use Pt2D;
|
||||
|
||||
// TODO reconsider pub usize. maybe outside world shouldnt know.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct BuildingID(pub usize);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Building {
|
||||
pub id: BuildingID,
|
||||
pub points: Vec<Pt2D>,
|
||||
pub osm_tags: Vec<String>,
|
||||
pub osm_way_id: i64,
|
||||
}
|
||||
|
||||
impl PartialEq for Building {
|
||||
fn eq(&self, other: &Building) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
23
map_model/src/intersection.rs
Normal file
23
map_model/src/intersection.rs
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
use Pt2D;
|
||||
use TurnID;
|
||||
|
||||
// TODO reconsider pub usize. maybe outside world shouldnt know.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct IntersectionID(pub usize);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Intersection {
|
||||
pub id: IntersectionID,
|
||||
pub point: Pt2D,
|
||||
pub turns: Vec<TurnID>,
|
||||
pub elevation_meters: f64,
|
||||
pub has_traffic_signal: bool,
|
||||
}
|
||||
|
||||
impl PartialEq for Intersection {
|
||||
fn eq(&self, other: &Intersection) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
@ -7,16 +7,27 @@ extern crate serde;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
mod building;
|
||||
mod intersection;
|
||||
mod map;
|
||||
mod parcel;
|
||||
pub mod pb;
|
||||
mod polyline;
|
||||
mod road;
|
||||
mod turn;
|
||||
|
||||
pub use building::{Building, BuildingID};
|
||||
pub use intersection::{Intersection, IntersectionID};
|
||||
pub use map::Map;
|
||||
use ordered_float::NotNaN;
|
||||
pub use parcel::{Parcel, ParcelID};
|
||||
pub use polyline::{polygons_for_polyline, shift_polyline};
|
||||
use protobuf::error::ProtobufError;
|
||||
use protobuf::{CodedInputStream, CodedOutputStream, Message};
|
||||
use std::collections::HashMap;
|
||||
pub use road::{LaneType, Road, RoadID};
|
||||
use std::f64;
|
||||
use std::fs::File;
|
||||
pub use turn::{Turn, TurnID};
|
||||
|
||||
pub fn write_pb(map: &pb::Map, path: &str) -> Result<(), ProtobufError> {
|
||||
let mut file = File::create(path)?;
|
||||
@ -128,387 +139,6 @@ impl Bounds {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO reconsider pub usize. maybe outside world shouldnt know.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct RoadID(pub usize);
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct IntersectionID(pub usize);
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct TurnID(pub usize);
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct BuildingID(pub usize);
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ParcelID(pub usize);
|
||||
|
||||
pub struct Map {
|
||||
roads: Vec<Road>,
|
||||
intersections: Vec<Intersection>,
|
||||
turns: Vec<Turn>,
|
||||
buildings: Vec<Building>,
|
||||
parcels: Vec<Parcel>,
|
||||
|
||||
pt_to_intersection: HashMap<Pt2D, IntersectionID>,
|
||||
intersection_to_roads: HashMap<IntersectionID, Vec<RoadID>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub enum LaneType {
|
||||
Driving,
|
||||
Parking,
|
||||
Sidewalk,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Road {
|
||||
pub id: RoadID,
|
||||
pub osm_tags: Vec<String>,
|
||||
pub osm_way_id: i64,
|
||||
pub lane_type: LaneType,
|
||||
|
||||
// Ideally all of these would just become translated center points immediately, but this is
|
||||
// hard due to the polyline problem.
|
||||
|
||||
// All roads are two-way (since even one-way streets have sidewalks on both sides). Offset 0 is
|
||||
// the centermost lane on each side, then it counts up.
|
||||
pub offset: u8,
|
||||
// The orientation is implied by the order of these points
|
||||
pub points: Vec<Pt2D>,
|
||||
// Should this lane own the drawing of the yellow center lines? For two-way roads, this is
|
||||
// arbitrarily grouped with one of the lanes. Ideally it would be owned by something else.
|
||||
pub use_yellow_center_lines: bool,
|
||||
// Need to remember this just for detecting U-turns here.
|
||||
other_side: Option<RoadID>,
|
||||
}
|
||||
|
||||
impl PartialEq for Road {
|
||||
fn eq(&self, other: &Road) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Intersection {
|
||||
pub id: IntersectionID,
|
||||
pub point: Pt2D,
|
||||
pub turns: Vec<TurnID>,
|
||||
pub elevation_meters: f64,
|
||||
pub has_traffic_signal: bool,
|
||||
}
|
||||
|
||||
impl PartialEq for Intersection {
|
||||
fn eq(&self, other: &Intersection) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Turn {
|
||||
pub id: TurnID,
|
||||
pub parent: IntersectionID,
|
||||
pub src: RoadID,
|
||||
pub dst: RoadID,
|
||||
}
|
||||
|
||||
impl PartialEq for Turn {
|
||||
fn eq(&self, other: &Turn) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Building {
|
||||
pub id: BuildingID,
|
||||
pub points: Vec<Pt2D>,
|
||||
pub osm_tags: Vec<String>,
|
||||
pub osm_way_id: i64,
|
||||
}
|
||||
|
||||
impl PartialEq for Building {
|
||||
fn eq(&self, other: &Building) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Parcel {
|
||||
pub id: ParcelID,
|
||||
pub points: Vec<Pt2D>,
|
||||
}
|
||||
|
||||
impl PartialEq for Parcel {
|
||||
fn eq(&self, other: &Parcel) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
||||
|
||||
impl Map {
|
||||
pub fn new(data: &pb::Map) -> Map {
|
||||
let mut m = Map {
|
||||
roads: Vec::new(),
|
||||
intersections: Vec::new(),
|
||||
turns: Vec::new(),
|
||||
buildings: Vec::new(),
|
||||
parcels: Vec::new(),
|
||||
pt_to_intersection: HashMap::new(),
|
||||
intersection_to_roads: HashMap::new(),
|
||||
};
|
||||
|
||||
for (idx, i) in data.get_intersections().iter().enumerate() {
|
||||
let id = IntersectionID(idx);
|
||||
let pt = Pt2D::from(i.get_point());
|
||||
m.intersections.push(Intersection {
|
||||
id,
|
||||
point: pt,
|
||||
turns: Vec::new(),
|
||||
elevation_meters: i.get_elevation_meters(),
|
||||
// TODO use the data again!
|
||||
//has_traffic_signal: i.get_has_traffic_signal(),
|
||||
has_traffic_signal: idx % 2 == 0,
|
||||
});
|
||||
m.pt_to_intersection.insert(pt, id);
|
||||
}
|
||||
|
||||
let mut counter = 0;
|
||||
for r in data.get_roads() {
|
||||
let oneway = r.get_osm_tags().contains(&String::from("oneway=yes"));
|
||||
|
||||
let orig_direction = true;
|
||||
let reverse_direction = false;
|
||||
// lane_type, offset, reverse the points or not, offset to get the other_side's ID
|
||||
let mut lanes: Vec<(LaneType, u8, bool, Option<isize>)> = vec![
|
||||
(
|
||||
LaneType::Driving,
|
||||
0,
|
||||
orig_direction,
|
||||
if oneway { None } else { Some(3) },
|
||||
),
|
||||
(LaneType::Parking, 1, orig_direction, None),
|
||||
(LaneType::Sidewalk, 2, orig_direction, None),
|
||||
];
|
||||
if oneway {
|
||||
lanes.push((LaneType::Sidewalk, 0, reverse_direction, None));
|
||||
} else {
|
||||
lanes.extend(vec![
|
||||
(LaneType::Driving, 0, reverse_direction, Some(-3)),
|
||||
(LaneType::Parking, 1, reverse_direction, None),
|
||||
(LaneType::Sidewalk, 2, reverse_direction, None),
|
||||
]);
|
||||
}
|
||||
|
||||
for lane in &lanes {
|
||||
let id = RoadID(counter);
|
||||
counter += 1;
|
||||
let other_side = lane.3
|
||||
.map(|offset| RoadID(((id.0 as isize) + offset) as usize));
|
||||
|
||||
let pts: Vec<Pt2D> = if lane.2 == orig_direction {
|
||||
r.get_points().iter().map(Pt2D::from).collect()
|
||||
} else {
|
||||
r.get_points().iter().rev().map(Pt2D::from).collect()
|
||||
};
|
||||
let i1 = m.pt_to_intersection[&pts[0]];
|
||||
let i2 = m.pt_to_intersection[pts.last().unwrap()];
|
||||
m.intersection_to_roads
|
||||
.entry(i1)
|
||||
.or_insert_with(Vec::new)
|
||||
.push(id);
|
||||
m.intersection_to_roads
|
||||
.entry(i2)
|
||||
.or_insert_with(Vec::new)
|
||||
.push(id);
|
||||
|
||||
m.roads.push(Road {
|
||||
id,
|
||||
other_side,
|
||||
osm_tags: r.get_osm_tags().to_vec(),
|
||||
osm_way_id: r.get_osm_way_id(),
|
||||
lane_type: lane.0,
|
||||
offset: lane.1,
|
||||
points: pts,
|
||||
use_yellow_center_lines: if let Some(other) = other_side {
|
||||
id.0 < other.0
|
||||
} else {
|
||||
lane.1 == 0
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for i in &m.intersections {
|
||||
// TODO: Figure out why this happens in the huge map
|
||||
if m.intersection_to_roads.get(&i.id).is_none() {
|
||||
println!("WARNING: intersection {:?} has no roads", i);
|
||||
continue;
|
||||
}
|
||||
let incident_roads: Vec<RoadID> = m.intersection_to_roads[&i.id]
|
||||
.iter()
|
||||
.filter(|id| m.roads[id.0].lane_type == LaneType::Driving)
|
||||
.map(|id| *id)
|
||||
.collect();
|
||||
for src in &incident_roads {
|
||||
let src_r = &m.roads[src.0];
|
||||
if i.point != *src_r.points.last().unwrap() {
|
||||
continue;
|
||||
}
|
||||
for dst in &incident_roads {
|
||||
let dst_r = &m.roads[dst.0];
|
||||
if i.point != dst_r.points[0] {
|
||||
continue;
|
||||
}
|
||||
// Don't create U-turns unless it's a dead-end
|
||||
if src_r.other_side == Some(dst_r.id) && incident_roads.len() > 2 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let id = TurnID(m.turns.len());
|
||||
m.turns.push(Turn {
|
||||
id,
|
||||
parent: i.id,
|
||||
src: *src,
|
||||
dst: *dst,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
for t in &m.turns {
|
||||
m.intersections[t.parent.0].turns.push(t.id);
|
||||
}
|
||||
|
||||
for (idx, b) in data.get_buildings().iter().enumerate() {
|
||||
m.buildings.push(Building {
|
||||
id: BuildingID(idx),
|
||||
points: b.get_points().iter().map(Pt2D::from).collect(),
|
||||
osm_tags: b.get_osm_tags().to_vec(),
|
||||
osm_way_id: b.get_osm_way_id(),
|
||||
});
|
||||
}
|
||||
|
||||
for (idx, p) in data.get_parcels().iter().enumerate() {
|
||||
m.parcels.push(Parcel {
|
||||
id: ParcelID(idx),
|
||||
points: p.get_points().iter().map(Pt2D::from).collect(),
|
||||
});
|
||||
}
|
||||
|
||||
m
|
||||
}
|
||||
|
||||
pub fn get_roads_to_intersection(&self, id: IntersectionID) -> Vec<&Road> {
|
||||
self.intersection_to_roads[&id]
|
||||
.iter()
|
||||
.map(|id| &self.roads[id.0])
|
||||
.filter(|r| *r.points.last().unwrap() == self.get_i(id).point)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn get_roads_from_intersection(&self, id: IntersectionID) -> Vec<&Road> {
|
||||
self.intersection_to_roads[&id]
|
||||
.iter()
|
||||
.map(|id| &self.roads[id.0])
|
||||
.filter(|r| r.points[0] == self.get_i(id).point)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn all_roads(&self) -> &Vec<Road> {
|
||||
&self.roads
|
||||
}
|
||||
|
||||
pub fn all_intersections(&self) -> &Vec<Intersection> {
|
||||
&self.intersections
|
||||
}
|
||||
|
||||
pub fn all_turns(&self) -> &Vec<Turn> {
|
||||
&self.turns
|
||||
}
|
||||
|
||||
pub fn all_buildings(&self) -> &Vec<Building> {
|
||||
&self.buildings
|
||||
}
|
||||
|
||||
pub fn all_parcels(&self) -> &Vec<Parcel> {
|
||||
&self.parcels
|
||||
}
|
||||
|
||||
pub fn get_r(&self, id: RoadID) -> &Road {
|
||||
&self.roads[id.0]
|
||||
}
|
||||
|
||||
pub fn get_i(&self, id: IntersectionID) -> &Intersection {
|
||||
&self.intersections[id.0]
|
||||
}
|
||||
|
||||
pub fn get_t(&self, id: TurnID) -> &Turn {
|
||||
&self.turns[id.0]
|
||||
}
|
||||
|
||||
pub fn get_b(&self, id: BuildingID) -> &Building {
|
||||
&self.buildings[id.0]
|
||||
}
|
||||
|
||||
pub fn get_p(&self, id: ParcelID) -> &Parcel {
|
||||
&self.parcels[id.0]
|
||||
}
|
||||
|
||||
// All these helpers should take IDs and return objects.
|
||||
|
||||
pub fn get_source_intersection(&self, r: RoadID) -> &Intersection {
|
||||
self.get_i(self.pt_to_intersection[&self.get_r(r).points[0]])
|
||||
}
|
||||
|
||||
pub fn get_destination_intersection(&self, r: RoadID) -> &Intersection {
|
||||
self.get_i(self.pt_to_intersection[self.get_r(r).points.last().unwrap()])
|
||||
}
|
||||
|
||||
pub fn get_turns_in_intersection(&self, id: IntersectionID) -> Vec<&Turn> {
|
||||
self.get_i(id)
|
||||
.turns
|
||||
.iter()
|
||||
.map(|t| self.get_t(*t))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn get_turns_from_road(&self, id: RoadID) -> Vec<&Turn> {
|
||||
let i = self.get_destination_intersection(id);
|
||||
// TODO can't filter on get_turns_in_intersection... winds up being Vec<&&Turn>
|
||||
i.turns
|
||||
.iter()
|
||||
.map(|t| self.get_t(*t))
|
||||
.filter(|t| t.src == id)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn get_next_roads(&self, from: RoadID) -> Vec<&Road> {
|
||||
// TODO assumes no duplicates
|
||||
self.get_turns_from_road(from)
|
||||
.iter()
|
||||
.map(|t| self.get_r(t.dst))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn get_gps_bounds(&self) -> Bounds {
|
||||
let mut b = Bounds::new();
|
||||
for r in &self.roads {
|
||||
for pt in &r.points {
|
||||
b.update_pt(pt);
|
||||
}
|
||||
}
|
||||
for i in &self.intersections {
|
||||
b.update_pt(&i.point);
|
||||
}
|
||||
for bldg in &self.buildings {
|
||||
for pt in &bldg.points {
|
||||
b.update_pt(pt);
|
||||
}
|
||||
}
|
||||
for p in &self.parcels {
|
||||
for pt in &p.points {
|
||||
b.update_pt(pt);
|
||||
}
|
||||
}
|
||||
b
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_osm_tag(tags: &Vec<String>, key: &str, value: &str) -> bool {
|
||||
tags.contains(&format!("{}={}", key, value))
|
||||
}
|
||||
|
290
map_model/src/map.rs
Normal file
290
map_model/src/map.rs
Normal file
@ -0,0 +1,290 @@
|
||||
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
use Bounds;
|
||||
use Pt2D;
|
||||
use building::{Building, BuildingID};
|
||||
use intersection::{Intersection, IntersectionID};
|
||||
use parcel::{Parcel, ParcelID};
|
||||
use pb;
|
||||
use road::{LaneType, Road, RoadID};
|
||||
use std::collections::HashMap;
|
||||
use turn::{Turn, TurnID};
|
||||
|
||||
pub struct Map {
|
||||
roads: Vec<Road>,
|
||||
intersections: Vec<Intersection>,
|
||||
turns: Vec<Turn>,
|
||||
buildings: Vec<Building>,
|
||||
parcels: Vec<Parcel>,
|
||||
|
||||
pt_to_intersection: HashMap<Pt2D, IntersectionID>,
|
||||
intersection_to_roads: HashMap<IntersectionID, Vec<RoadID>>,
|
||||
}
|
||||
|
||||
impl Map {
|
||||
pub fn new(data: &pb::Map) -> Map {
|
||||
let mut m = Map {
|
||||
roads: Vec::new(),
|
||||
intersections: Vec::new(),
|
||||
turns: Vec::new(),
|
||||
buildings: Vec::new(),
|
||||
parcels: Vec::new(),
|
||||
pt_to_intersection: HashMap::new(),
|
||||
intersection_to_roads: HashMap::new(),
|
||||
};
|
||||
|
||||
for (idx, i) in data.get_intersections().iter().enumerate() {
|
||||
let id = IntersectionID(idx);
|
||||
let pt = Pt2D::from(i.get_point());
|
||||
m.intersections.push(Intersection {
|
||||
id,
|
||||
point: pt,
|
||||
turns: Vec::new(),
|
||||
elevation_meters: i.get_elevation_meters(),
|
||||
// TODO use the data again!
|
||||
//has_traffic_signal: i.get_has_traffic_signal(),
|
||||
has_traffic_signal: idx % 2 == 0,
|
||||
});
|
||||
m.pt_to_intersection.insert(pt, id);
|
||||
}
|
||||
|
||||
let mut counter = 0;
|
||||
for r in data.get_roads() {
|
||||
let oneway = r.get_osm_tags().contains(&String::from("oneway=yes"));
|
||||
|
||||
let orig_direction = true;
|
||||
let reverse_direction = false;
|
||||
// lane_type, offset, reverse the points or not, offset to get the other_side's ID
|
||||
let mut lanes: Vec<(LaneType, u8, bool, Option<isize>)> = vec![
|
||||
(
|
||||
LaneType::Driving,
|
||||
0,
|
||||
orig_direction,
|
||||
if oneway { None } else { Some(3) },
|
||||
),
|
||||
(LaneType::Parking, 1, orig_direction, None),
|
||||
(LaneType::Sidewalk, 2, orig_direction, None),
|
||||
];
|
||||
if oneway {
|
||||
lanes.push((LaneType::Sidewalk, 0, reverse_direction, None));
|
||||
} else {
|
||||
lanes.extend(vec![
|
||||
(LaneType::Driving, 0, reverse_direction, Some(-3)),
|
||||
(LaneType::Parking, 1, reverse_direction, None),
|
||||
(LaneType::Sidewalk, 2, reverse_direction, None),
|
||||
]);
|
||||
}
|
||||
|
||||
for lane in &lanes {
|
||||
let id = RoadID(counter);
|
||||
counter += 1;
|
||||
let other_side = lane.3
|
||||
.map(|offset| RoadID(((id.0 as isize) + offset) as usize));
|
||||
|
||||
let pts: Vec<Pt2D> = if lane.2 == orig_direction {
|
||||
r.get_points().iter().map(Pt2D::from).collect()
|
||||
} else {
|
||||
r.get_points().iter().rev().map(Pt2D::from).collect()
|
||||
};
|
||||
let i1 = m.pt_to_intersection[&pts[0]];
|
||||
let i2 = m.pt_to_intersection[pts.last().unwrap()];
|
||||
m.intersection_to_roads
|
||||
.entry(i1)
|
||||
.or_insert_with(Vec::new)
|
||||
.push(id);
|
||||
m.intersection_to_roads
|
||||
.entry(i2)
|
||||
.or_insert_with(Vec::new)
|
||||
.push(id);
|
||||
|
||||
m.roads.push(Road {
|
||||
id,
|
||||
other_side,
|
||||
osm_tags: r.get_osm_tags().to_vec(),
|
||||
osm_way_id: r.get_osm_way_id(),
|
||||
lane_type: lane.0,
|
||||
offset: lane.1,
|
||||
points: pts,
|
||||
use_yellow_center_lines: if let Some(other) = other_side {
|
||||
id.0 < other.0
|
||||
} else {
|
||||
lane.1 == 0
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for i in &m.intersections {
|
||||
// TODO: Figure out why this happens in the huge map
|
||||
if m.intersection_to_roads.get(&i.id).is_none() {
|
||||
println!("WARNING: intersection {:?} has no roads", i);
|
||||
continue;
|
||||
}
|
||||
let incident_roads: Vec<RoadID> = m.intersection_to_roads[&i.id]
|
||||
.iter()
|
||||
.filter(|id| m.roads[id.0].lane_type == LaneType::Driving)
|
||||
.map(|id| *id)
|
||||
.collect();
|
||||
for src in &incident_roads {
|
||||
let src_r = &m.roads[src.0];
|
||||
if i.point != *src_r.points.last().unwrap() {
|
||||
continue;
|
||||
}
|
||||
for dst in &incident_roads {
|
||||
let dst_r = &m.roads[dst.0];
|
||||
if i.point != dst_r.points[0] {
|
||||
continue;
|
||||
}
|
||||
// Don't create U-turns unless it's a dead-end
|
||||
if src_r.other_side == Some(dst_r.id) && incident_roads.len() > 2 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let id = TurnID(m.turns.len());
|
||||
m.turns.push(Turn {
|
||||
id,
|
||||
parent: i.id,
|
||||
src: *src,
|
||||
dst: *dst,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
for t in &m.turns {
|
||||
m.intersections[t.parent.0].turns.push(t.id);
|
||||
}
|
||||
|
||||
for (idx, b) in data.get_buildings().iter().enumerate() {
|
||||
m.buildings.push(Building {
|
||||
id: BuildingID(idx),
|
||||
points: b.get_points().iter().map(Pt2D::from).collect(),
|
||||
osm_tags: b.get_osm_tags().to_vec(),
|
||||
osm_way_id: b.get_osm_way_id(),
|
||||
});
|
||||
}
|
||||
|
||||
for (idx, p) in data.get_parcels().iter().enumerate() {
|
||||
m.parcels.push(Parcel {
|
||||
id: ParcelID(idx),
|
||||
points: p.get_points().iter().map(Pt2D::from).collect(),
|
||||
});
|
||||
}
|
||||
|
||||
m
|
||||
}
|
||||
|
||||
pub fn get_roads_to_intersection(&self, id: IntersectionID) -> Vec<&Road> {
|
||||
self.intersection_to_roads[&id]
|
||||
.iter()
|
||||
.map(|id| &self.roads[id.0])
|
||||
.filter(|r| *r.points.last().unwrap() == self.get_i(id).point)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn get_roads_from_intersection(&self, id: IntersectionID) -> Vec<&Road> {
|
||||
self.intersection_to_roads[&id]
|
||||
.iter()
|
||||
.map(|id| &self.roads[id.0])
|
||||
.filter(|r| r.points[0] == self.get_i(id).point)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn all_roads(&self) -> &Vec<Road> {
|
||||
&self.roads
|
||||
}
|
||||
|
||||
pub fn all_intersections(&self) -> &Vec<Intersection> {
|
||||
&self.intersections
|
||||
}
|
||||
|
||||
pub fn all_turns(&self) -> &Vec<Turn> {
|
||||
&self.turns
|
||||
}
|
||||
|
||||
pub fn all_buildings(&self) -> &Vec<Building> {
|
||||
&self.buildings
|
||||
}
|
||||
|
||||
pub fn all_parcels(&self) -> &Vec<Parcel> {
|
||||
&self.parcels
|
||||
}
|
||||
|
||||
pub fn get_r(&self, id: RoadID) -> &Road {
|
||||
&self.roads[id.0]
|
||||
}
|
||||
|
||||
pub fn get_i(&self, id: IntersectionID) -> &Intersection {
|
||||
&self.intersections[id.0]
|
||||
}
|
||||
|
||||
pub fn get_t(&self, id: TurnID) -> &Turn {
|
||||
&self.turns[id.0]
|
||||
}
|
||||
|
||||
pub fn get_b(&self, id: BuildingID) -> &Building {
|
||||
&self.buildings[id.0]
|
||||
}
|
||||
|
||||
pub fn get_p(&self, id: ParcelID) -> &Parcel {
|
||||
&self.parcels[id.0]
|
||||
}
|
||||
|
||||
// All these helpers should take IDs and return objects.
|
||||
|
||||
pub fn get_source_intersection(&self, r: RoadID) -> &Intersection {
|
||||
self.get_i(self.pt_to_intersection[&self.get_r(r).points[0]])
|
||||
}
|
||||
|
||||
pub fn get_destination_intersection(&self, r: RoadID) -> &Intersection {
|
||||
self.get_i(self.pt_to_intersection[self.get_r(r).points.last().unwrap()])
|
||||
}
|
||||
|
||||
pub fn get_turns_in_intersection(&self, id: IntersectionID) -> Vec<&Turn> {
|
||||
self.get_i(id)
|
||||
.turns
|
||||
.iter()
|
||||
.map(|t| self.get_t(*t))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn get_turns_from_road(&self, id: RoadID) -> Vec<&Turn> {
|
||||
let i = self.get_destination_intersection(id);
|
||||
// TODO can't filter on get_turns_in_intersection... winds up being Vec<&&Turn>
|
||||
i.turns
|
||||
.iter()
|
||||
.map(|t| self.get_t(*t))
|
||||
.filter(|t| t.src == id)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn get_next_roads(&self, from: RoadID) -> Vec<&Road> {
|
||||
// TODO assumes no duplicates
|
||||
self.get_turns_from_road(from)
|
||||
.iter()
|
||||
.map(|t| self.get_r(t.dst))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn get_gps_bounds(&self) -> Bounds {
|
||||
let mut b = Bounds::new();
|
||||
for r in &self.roads {
|
||||
for pt in &r.points {
|
||||
b.update_pt(pt);
|
||||
}
|
||||
}
|
||||
for i in &self.intersections {
|
||||
b.update_pt(&i.point);
|
||||
}
|
||||
for bldg in &self.buildings {
|
||||
for pt in &bldg.points {
|
||||
b.update_pt(pt);
|
||||
}
|
||||
}
|
||||
for p in &self.parcels {
|
||||
for pt in &p.points {
|
||||
b.update_pt(pt);
|
||||
}
|
||||
}
|
||||
b
|
||||
}
|
||||
}
|
19
map_model/src/parcel.rs
Normal file
19
map_model/src/parcel.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
use Pt2D;
|
||||
|
||||
// TODO reconsider pub usize. maybe outside world shouldnt know.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ParcelID(pub usize);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Parcel {
|
||||
pub id: ParcelID,
|
||||
pub points: Vec<Pt2D>,
|
||||
}
|
||||
|
||||
impl PartialEq for Parcel {
|
||||
fn eq(&self, other: &Parcel) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
42
map_model/src/road.rs
Normal file
42
map_model/src/road.rs
Normal file
@ -0,0 +1,42 @@
|
||||
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
use Pt2D;
|
||||
|
||||
// TODO reconsider pub usize. maybe outside world shouldnt know.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct RoadID(pub usize);
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub enum LaneType {
|
||||
Driving,
|
||||
Parking,
|
||||
Sidewalk,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Road {
|
||||
pub id: RoadID,
|
||||
pub osm_tags: Vec<String>,
|
||||
pub osm_way_id: i64,
|
||||
pub lane_type: LaneType,
|
||||
|
||||
// Ideally all of these would just become translated center points immediately, but this is
|
||||
// hard due to the polyline problem.
|
||||
|
||||
// All roads are two-way (since even one-way streets have sidewalks on both sides). Offset 0 is
|
||||
// the centermost lane on each side, then it counts up.
|
||||
pub offset: u8,
|
||||
// The orientation is implied by the order of these points
|
||||
pub points: Vec<Pt2D>,
|
||||
// Should this lane own the drawing of the yellow center lines? For two-way roads, this is
|
||||
// arbitrarily grouped with one of the lanes. Ideally it would be owned by something else.
|
||||
pub use_yellow_center_lines: bool,
|
||||
// Need to remember this just for detecting U-turns here.
|
||||
pub(crate) other_side: Option<RoadID>,
|
||||
}
|
||||
|
||||
impl PartialEq for Road {
|
||||
fn eq(&self, other: &Road) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
22
map_model/src/turn.rs
Normal file
22
map_model/src/turn.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
use IntersectionID;
|
||||
use RoadID;
|
||||
|
||||
// TODO reconsider pub usize. maybe outside world shouldnt know.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct TurnID(pub usize);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Turn {
|
||||
pub id: TurnID,
|
||||
pub parent: IntersectionID,
|
||||
pub src: RoadID,
|
||||
pub dst: RoadID,
|
||||
}
|
||||
|
||||
impl PartialEq for Turn {
|
||||
fn eq(&self, other: &Turn) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user