modeling border nodes in map, control, sim, editor layers

This commit is contained in:
Dustin Carlino 2018-11-11 14:33:01 -08:00
parent f243048c45
commit 474d92f5db
11 changed files with 106 additions and 45 deletions

View File

@ -14,7 +14,7 @@ mod macros;
mod stop_signs; mod stop_signs;
mod traffic_signals; mod traffic_signals;
use map_model::{IntersectionID, Map}; use map_model::{IntersectionID, IntersectionType, Map};
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
pub use stop_signs::{ControlStopSign, TurnPriority}; pub use stop_signs::{ControlStopSign, TurnPriority};
pub use traffic_signals::ControlTrafficSignal; pub use traffic_signals::ControlTrafficSignal;
@ -23,6 +23,7 @@ pub use traffic_signals::ControlTrafficSignal;
pub struct ControlMap { pub struct ControlMap {
pub traffic_signals: HashMap<IntersectionID, ControlTrafficSignal>, pub traffic_signals: HashMap<IntersectionID, ControlTrafficSignal>,
pub stop_signs: HashMap<IntersectionID, ControlStopSign>, pub stop_signs: HashMap<IntersectionID, ControlStopSign>,
// Note that border nodes belong in neither!
} }
impl ControlMap { impl ControlMap {
@ -37,13 +38,17 @@ impl ControlMap {
}; };
for i in map.all_intersections() { for i in map.all_intersections() {
if i.has_traffic_signal { match i.intersection_type {
ctrl.traffic_signals IntersectionType::StopSign => {
.insert(i.id, ControlTrafficSignal::new(map, i.id));
} else {
ctrl.stop_signs ctrl.stop_signs
.insert(i.id, ControlStopSign::new(map, i.id)); .insert(i.id, ControlStopSign::new(map, i.id));
} }
IntersectionType::TrafficSignal => {
ctrl.traffic_signals
.insert(i.id, ControlTrafficSignal::new(map, i.id));
}
IntersectionType::Border => {}
};
} }
for (i, s) in stop_signs.into_iter() { for (i, s) in stop_signs.into_iter() {

View File

@ -31,7 +31,6 @@ pub struct ControlStopSign {
impl ControlStopSign { impl ControlStopSign {
pub fn new(map: &Map, intersection: IntersectionID) -> ControlStopSign { pub fn new(map: &Map, intersection: IntersectionID) -> ControlStopSign {
assert!(!map.get_i(intersection).has_traffic_signal);
let ss = ControlStopSign::smart_assignment(map, intersection); let ss = ControlStopSign::smart_assignment(map, intersection);
ss.validate(map, intersection).unwrap(); ss.validate(map, intersection).unwrap();
ss ss

View File

@ -17,7 +17,6 @@ pub struct ControlTrafficSignal {
impl ControlTrafficSignal { impl ControlTrafficSignal {
pub fn new(map: &Map, intersection: IntersectionID) -> ControlTrafficSignal { pub fn new(map: &Map, intersection: IntersectionID) -> ControlTrafficSignal {
assert!(map.get_i(intersection).has_traffic_signal);
ControlTrafficSignal { ControlTrafficSignal {
intersection, intersection,
cycles: greedy_assignment(map, intersection), cycles: greedy_assignment(map, intersection),

View File

@ -283,4 +283,12 @@ can begin or end.
- draw the FSM for cars/peds - draw the FSM for cars/peds
- trips starting/ending at border nodes short-circuit some steps - trips starting/ending at border nodes short-circuit some steps
What about border nodes where the sidewalk can cross over, but the driving lane leads nowhere? What about border nodes where the sidewalk can cross over, but the driving lane
leads nowhere? Maybe instead of having a special intersection policy, we have
turns to nowhere? Sort of depends how the border node is defined -- do we have
long skinny things jutting out, or not?
- don't add any turns, even if we could
OK, now adapt the control and sim layers to handle border nodes...
Adapt trips / pathfinding. It has to be an explicit origin/goal.

View File

@ -3,7 +3,7 @@
use dimensioned::si; use dimensioned::si;
use ezgui::{Color, GfxCtx}; use ezgui::{Color, GfxCtx};
use geom::{Angle, Bounds, Circle, Line, Polygon, Pt2D}; use geom::{Angle, Bounds, Circle, Line, Polygon, Pt2D};
use map_model::{Intersection, IntersectionID, Map, TurnType, LANE_THICKNESS}; use map_model::{Intersection, IntersectionID, IntersectionType, Map, TurnType, LANE_THICKNESS};
use objects::{Ctx, ID}; use objects::{Ctx, ID};
use render::{RenderOptions, Renderable}; use render::{RenderOptions, Renderable};
use sim::Sim; use sim::Sim;
@ -18,8 +18,7 @@ pub struct DrawIntersection {
crosswalks: Vec<Vec<Line>>, crosswalks: Vec<Vec<Line>>,
sidewalk_corners: Vec<Polygon>, sidewalk_corners: Vec<Polygon>,
center: Pt2D, center: Pt2D,
has_traffic_signal: bool, intersection_type: IntersectionType,
is_border: bool,
should_draw_stop_sign: bool, should_draw_stop_sign: bool,
} }
@ -36,9 +35,9 @@ impl DrawIntersection {
polygon: Polygon::new(&inter.polygon), polygon: Polygon::new(&inter.polygon),
crosswalks: calculate_crosswalks(inter.id, map), crosswalks: calculate_crosswalks(inter.id, map),
sidewalk_corners: calculate_corners(inter.id, map), sidewalk_corners: calculate_corners(inter.id, map),
has_traffic_signal: inter.has_traffic_signal, intersection_type: inter.intersection_type,
is_border: inter.is_border(map), should_draw_stop_sign: inter.intersection_type == IntersectionType::StopSign
should_draw_stop_sign: !inter.has_traffic_signal && !inter.is_degenerate(), && !inter.is_degenerate(),
} }
} }
@ -87,7 +86,7 @@ impl Renderable for DrawIntersection {
fn draw(&self, g: &mut GfxCtx, opts: RenderOptions, ctx: Ctx) { fn draw(&self, g: &mut GfxCtx, opts: RenderOptions, ctx: Ctx) {
let color = opts.color.unwrap_or_else(|| { let color = opts.color.unwrap_or_else(|| {
if self.is_border { if self.intersection_type == IntersectionType::Border {
return ctx.cs.get("border intersection", Color::rgb(50, 205, 50)); return ctx.cs.get("border intersection", Color::rgb(50, 205, 50));
} }
@ -121,7 +120,7 @@ impl Renderable for DrawIntersection {
g.draw_polygon(ctx.cs.get("sidewalk corner", Color::grey(0.7)), corner); g.draw_polygon(ctx.cs.get("sidewalk corner", Color::grey(0.7)), corner);
} }
if self.has_traffic_signal { if self.intersection_type == IntersectionType::TrafficSignal {
self.draw_traffic_signal(g, ctx); self.draw_traffic_signal(g, ctx);
} else if self.should_draw_stop_sign { } else if self.should_draw_stop_sign {
self.draw_stop_sign(g, ctx); self.draw_stop_sign(g, ctx);

View File

@ -5,7 +5,9 @@ use control::ControlMap;
use dimensioned::si; use dimensioned::si;
use ezgui::{Color, GfxCtx, Text}; use ezgui::{Color, GfxCtx, Text};
use geom::{Bounds, Circle, Line, Polygon, Pt2D}; use geom::{Bounds, Circle, Line, Polygon, Pt2D};
use map_model::{Lane, LaneID, LaneType, Map, Road, LANE_THICKNESS, PARKING_SPOT_LENGTH}; use map_model::{
IntersectionType, Lane, LaneID, LaneType, Map, Road, LANE_THICKNESS, PARKING_SPOT_LENGTH,
};
use objects::{Ctx, ID}; use objects::{Ctx, ID};
use render::{RenderOptions, Renderable, BIG_ARROW_THICKNESS, PARCEL_BOUNDARY_THICKNESS}; use render::{RenderOptions, Renderable, BIG_ARROW_THICKNESS, PARCEL_BOUNDARY_THICKNESS};
use sim::Sim; use sim::Sim;
@ -63,7 +65,9 @@ impl DrawLane {
} }
LaneType::Biking => {} LaneType::Biking => {}
}; };
if lane.is_driving() && !map.get_i(lane.dst_i).has_traffic_signal { if lane.is_driving()
&& map.get_i(lane.dst_i).intersection_type == IntersectionType::StopSign
{
if let Some(m) = calculate_stop_sign_line(lane, control_map) { if let Some(m) = calculate_stop_sign_line(lane, control_map) {
markings.push(m); markings.push(m);
} }

View File

@ -5,7 +5,7 @@ use dimensioned::si;
use geom::Pt2D; use geom::Pt2D;
use std::collections::BTreeSet; use std::collections::BTreeSet;
use std::fmt; use std::fmt;
use {LaneID, Map, RoadID, TurnID}; use {LaneID, RoadID, TurnID};
// TODO reconsider pub usize. maybe outside world shouldnt know. // TODO reconsider pub usize. maybe outside world shouldnt know.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
@ -17,6 +17,13 @@ impl fmt::Display for IntersectionID {
} }
} }
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum IntersectionType {
StopSign,
TrafficSignal,
Border,
}
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct Intersection { pub struct Intersection {
pub id: IntersectionID, pub id: IntersectionID,
@ -26,7 +33,8 @@ pub struct Intersection {
pub polygon: Vec<Pt2D>, pub polygon: Vec<Pt2D>,
pub turns: Vec<TurnID>, pub turns: Vec<TurnID>,
pub elevation: si::Meter<f64>, pub elevation: si::Meter<f64>,
pub has_traffic_signal: bool,
pub intersection_type: IntersectionType,
// 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?
@ -51,16 +59,6 @@ impl Intersection {
self.roads.len() == 2 self.roads.len() == 2
} }
pub fn is_border(&self, map: &Map) -> bool {
// Bias for driving
if !self.is_dead_end() {
return false;
}
let has_driving_in = self.incoming_lanes.iter().find(|l| map.get_l(**l).is_driving()).is_some();
let has_driving_out = self.outgoing_lanes.iter().find(|l| map.get_l(**l).is_driving()).is_some();
has_driving_in != has_driving_out
}
pub fn dump_debug(&self) { pub fn dump_debug(&self) {
println!("{}", abstutil::to_json(self)); println!("{}", abstutil::to_json(self));
} }

View File

@ -38,7 +38,7 @@ pub use area::{Area, AreaID, AreaType};
pub use building::{Building, BuildingID, FrontPath}; pub use building::{Building, BuildingID, FrontPath};
pub use bus_stop::{BusRoute, BusStop, BusStopID}; pub use bus_stop::{BusRoute, BusStop, BusStopID};
pub use edits::{EditReason, RoadEdits}; pub use edits::{EditReason, RoadEdits};
pub use intersection::{Intersection, IntersectionID}; pub use intersection::{Intersection, IntersectionID, IntersectionType};
pub use lane::{Lane, LaneID, LaneType, PARKING_SPOT_LENGTH}; pub use lane::{Lane, LaneID, LaneType, PARKING_SPOT_LENGTH};
pub use map::Map; pub use map::Map;
pub use parcel::{Parcel, ParcelID}; pub use parcel::{Parcel, ParcelID};

View File

@ -3,10 +3,15 @@ use geom::{Angle, Line};
use std::collections::{BTreeSet, HashSet}; use std::collections::{BTreeSet, HashSet};
use std::iter; use std::iter;
use { use {
Intersection, IntersectionID, Lane, LaneID, LaneType, Map, Road, RoadID, Turn, TurnID, TurnType, Intersection, IntersectionID, IntersectionType, Lane, LaneID, LaneType, Map, Road, RoadID,
Turn, TurnID, TurnType,
}; };
pub fn make_all_turns(i: &Intersection, map: &Map) -> Vec<Turn> { pub fn make_all_turns(i: &Intersection, map: &Map) -> Vec<Turn> {
if i.intersection_type == IntersectionType::Border {
return Vec::new();
}
let mut turns: Vec<Turn> = Vec::new(); let mut turns: Vec<Turn> = Vec::new();
turns.extend(make_vehicle_turns(i, map)); turns.extend(make_vehicle_turns(i, map));
turns.extend(make_walking_turns(i, map)); turns.extend(make_walking_turns(i, map));

View File

@ -11,7 +11,8 @@ use std::io;
use std::path; use std::path;
use { use {
Area, AreaID, Building, BuildingID, BusRoute, BusStop, BusStopID, Intersection, IntersectionID, Area, AreaID, Building, BuildingID, BusRoute, BusStop, BusStopID, Intersection, IntersectionID,
Lane, LaneID, LaneType, Parcel, ParcelID, Road, RoadID, Turn, TurnID, LANE_THICKNESS, IntersectionType, Lane, LaneID, LaneType, Parcel, ParcelID, Road, RoadID, Turn, TurnID,
LANE_THICKNESS,
}; };
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@ -92,7 +93,12 @@ impl Map {
polygon: Vec::new(), polygon: Vec::new(),
turns: Vec::new(), turns: Vec::new(),
elevation: i.elevation, elevation: i.elevation,
has_traffic_signal: i.has_traffic_signal, // Might change later
intersection_type: if i.has_traffic_signal {
IntersectionType::TrafficSignal
} else {
IntersectionType::StopSign
},
incoming_lanes: Vec::new(), incoming_lanes: Vec::new(),
outgoing_lanes: Vec::new(), outgoing_lanes: Vec::new(),
roads: BTreeSet::new(), roads: BTreeSet::new(),
@ -196,6 +202,13 @@ impl Map {
make::trim_lines(&mut m.lanes, i); make::trim_lines(&mut m.lanes, i);
} }
for i in 0..m.intersections.len() {
// Is the intersection a border?
if is_border(&m.intersections[i], &m) {
m.intersections[i].intersection_type = IntersectionType::Border;
}
}
let (stops, routes) = make::make_bus_stops( let (stops, routes) = make::make_bus_stops(
&mut m.lanes, &mut m.lanes,
&m.roads, &m.roads,
@ -516,3 +529,21 @@ impl Map {
info!("Saved {}", path); info!("Saved {}", path);
} }
} }
fn is_border(intersection: &Intersection, map: &Map) -> bool {
// Bias for driving
if !intersection.is_dead_end() {
return false;
}
let has_driving_in = intersection
.incoming_lanes
.iter()
.find(|l| map.get_l(**l).is_driving())
.is_some();
let has_driving_out = intersection
.outgoing_lanes
.iter()
.find(|l| map.get_l(**l).is_driving())
.is_some();
has_driving_in != has_driving_out
}

View File

@ -5,7 +5,7 @@ use abstutil::{deserialize_btreemap, serialize_btreemap, Error};
use control::{ControlMap, ControlStopSign, TurnPriority}; use control::{ControlMap, ControlStopSign, TurnPriority};
use dimensioned::si; use dimensioned::si;
use kinematics; use kinematics;
use map_model::{IntersectionID, Map, TurnID}; use map_model::{IntersectionID, IntersectionType, Map, TurnID};
use std::collections::{BTreeMap, BTreeSet}; use std::collections::{BTreeMap, BTreeSet};
use view::WorldView; use view::WorldView;
use {AgentID, CarID, Event, PedestrianID, Tick, Time}; use {AgentID, CarID, Event, PedestrianID, Tick, Time};
@ -50,13 +50,15 @@ impl IntersectionSimState {
pub fn new(map: &Map) -> IntersectionSimState { pub fn new(map: &Map) -> IntersectionSimState {
let mut intersections: Vec<IntersectionPolicy> = Vec::new(); let mut intersections: Vec<IntersectionPolicy> = Vec::new();
for i in map.all_intersections() { for i in map.all_intersections() {
if i.has_traffic_signal { intersections.push(match i.intersection_type {
intersections.push(IntersectionPolicy::TrafficSignalPolicy(TrafficSignal::new( IntersectionType::StopSign => {
i.id, IntersectionPolicy::StopSignPolicy(StopSign::new(i.id))
)));
} else {
intersections.push(IntersectionPolicy::StopSignPolicy(StopSign::new(i.id)));
} }
IntersectionType::TrafficSignal => {
IntersectionPolicy::TrafficSignalPolicy(TrafficSignal::new(i.id))
}
IntersectionType::Border => IntersectionPolicy::BorderPolicy,
});
} }
IntersectionSimState { IntersectionSimState {
intersections, intersections,
@ -89,6 +91,7 @@ impl IntersectionSimState {
IntersectionPolicy::TrafficSignalPolicy(ref mut p) => { IntersectionPolicy::TrafficSignalPolicy(ref mut p) => {
p.requests.insert(req); p.requests.insert(req);
} }
IntersectionPolicy::BorderPolicy => {}
} }
} }
@ -108,6 +111,7 @@ impl IntersectionSimState {
IntersectionPolicy::TrafficSignalPolicy(ref mut p) => { IntersectionPolicy::TrafficSignalPolicy(ref mut p) => {
p.step(events, time, control_map, view) p.step(events, time, control_map, view)
} }
IntersectionPolicy::BorderPolicy => {}
} }
} }
} }
@ -147,6 +151,7 @@ impl IntersectionSimState {
IntersectionPolicy::TrafficSignalPolicy(ref mut p) => { IntersectionPolicy::TrafficSignalPolicy(ref mut p) => {
p.debug = false; p.debug = false;
} }
IntersectionPolicy::BorderPolicy => {}
}; };
} }
@ -160,6 +165,9 @@ impl IntersectionSimState {
p.debug = true; p.debug = true;
println!("{}", abstutil::to_json(&control_map.traffic_signals[&id])); println!("{}", abstutil::to_json(&control_map.traffic_signals[&id]));
} }
IntersectionPolicy::BorderPolicy => {
println!("{} is a border", id);
}
}; };
} }
} }
@ -169,6 +177,7 @@ impl IntersectionSimState {
enum IntersectionPolicy { enum IntersectionPolicy {
StopSignPolicy(StopSign), StopSignPolicy(StopSign),
TrafficSignalPolicy(TrafficSignal), TrafficSignalPolicy(TrafficSignal),
BorderPolicy,
} }
impl IntersectionPolicy { impl IntersectionPolicy {
@ -176,6 +185,7 @@ impl IntersectionPolicy {
match self { match self {
IntersectionPolicy::StopSignPolicy(ref p) => p.accepted.contains(req), IntersectionPolicy::StopSignPolicy(ref p) => p.accepted.contains(req),
IntersectionPolicy::TrafficSignalPolicy(ref p) => p.accepted.contains(req), IntersectionPolicy::TrafficSignalPolicy(ref p) => p.accepted.contains(req),
IntersectionPolicy::BorderPolicy => true,
} }
} }
@ -183,6 +193,9 @@ impl IntersectionPolicy {
match self { match self {
IntersectionPolicy::StopSignPolicy(ref mut p) => p.accepted.remove(&req), IntersectionPolicy::StopSignPolicy(ref mut p) => p.accepted.remove(&req),
IntersectionPolicy::TrafficSignalPolicy(ref mut p) => p.accepted.remove(&req), IntersectionPolicy::TrafficSignalPolicy(ref mut p) => p.accepted.remove(&req),
IntersectionPolicy::BorderPolicy => {
panic!("{:?} called on_exit for a border node; how?!", req);
}
}; };
} }
} }