some of the pieces to render smart arrows in front of agents

This commit is contained in:
Dustin Carlino 2018-10-09 08:38:58 -07:00
parent df927c5829
commit d7a36889b2
8 changed files with 115 additions and 23 deletions

View File

@ -1,5 +1,4 @@
use colors::Colors;
use dimensioned::si;
use ezgui::{shift_color, GfxCtx};
use geom::{Angle, Bounds, Line, PolyLine, Polygon, Pt2D};
use map_model::Map;
@ -16,9 +15,7 @@ pub struct DrawCar {
// TODO ideally, draw the turn icon inside the car quad. how can we do that easily?
turn_arrow: Option<Line>,
// TODO maybe also draw lookahead buffer to know what the car is considering
// TODO it would be really neat to project the stopping buffer onto the actual route that'll be
// taken
stopping_buffer_arrow: Option<Line>,
stopping_buffer: Option<Polygon>,
}
impl DrawCar {
@ -33,14 +30,9 @@ impl DrawCar {
None
};
let stopping_buffer_arrow = if input.stopping_dist == 0.0 * si::M {
None
} else {
let arrow_pt = input
.front
.project_away(input.stopping_dist.value_unsafe, input.angle);
Some(Line::new(input.front, arrow_pt))
};
let stopping_buffer = input
.stopping_trace
.map(|t| t.polyline.make_polygons_blindly(CAR_WIDTH));
let front_window_length_gap = 0.2;
let front_window_thickness = 0.3;
@ -85,7 +77,7 @@ impl DrawCar {
input.angle.rotate_degs(90.0),
),
],
stopping_buffer_arrow,
stopping_buffer,
}
}
}
@ -115,8 +107,8 @@ impl Renderable for DrawCar {
g.draw_arrow([0.0, 1.0, 1.0, 1.0], 0.25, 1.0, a);
}
if let Some(ref a) = self.stopping_buffer_arrow {
g.draw_arrow([1.0, 0.0, 0.0, 0.7], 0.25, 1.0, a);
if let Some(ref t) = self.stopping_buffer {
g.draw_polygon([1.0, 0.0, 0.0, 0.7], t);
}
}

View File

@ -34,6 +34,11 @@ impl PolyLine {
self.pts[len - 1] = pt2;
}
pub fn extend(&mut self, other: PolyLine) {
assert_eq!(*self.pts.last().unwrap(), other.pts[0]);
self.pts.extend(other.pts.iter().skip(1));
}
pub fn points(&self) -> &Vec<Pt2D> {
&self.pts
}
@ -52,6 +57,49 @@ impl PolyLine {
.fold(0.0 * si::M, |so_far, l| so_far + l.length())
}
// Returns the excess distance left over from the end.
pub fn slice(&self, start: si::Meter<f64>, end: si::Meter<f64>) -> (PolyLine, si::Meter<f64>) {
if start >= end {
panic!("Can't get a polyline slice [{}, {}]", start, end);
}
let mut result: Vec<Pt2D> = Vec::new();
let mut dist_so_far = 0.0 * si::M;
for line in self.lines().iter() {
let length = line.length();
// Does this line contain the first point of the slice?
if result.is_empty() && dist_so_far + length >= start {
result.push(line.dist_along(start - dist_so_far));
}
// Does this line contain the last point of the slice?
if dist_so_far + length >= end {
result.push(line.dist_along(end - dist_so_far));
return (PolyLine::new(result), 0.0 * si::M);
}
// If we're in the middle, just collect the endpoint.
if !result.is_empty() {
result.push(line.pt2());
}
dist_so_far += length;
}
if result.is_empty() {
panic!(
"Slice [{}, {}] has a start too big for polyline of length {}",
start,
end,
self.length()
);
}
(PolyLine::new(result), end - dist_so_far)
}
// TODO return result with an error message
pub fn safe_dist_along(&self, dist_along: si::Meter<f64>) -> Option<(Pt2D, Angle)> {
if dist_along < 0.0 * si::M {

View File

@ -29,6 +29,7 @@ mod parcel;
mod pathfind;
pub mod raw_data;
mod road;
mod trace;
mod turn;
pub use area::{Area, AreaID, AreaType};
@ -41,6 +42,7 @@ pub use map::Map;
pub use parcel::{Parcel, ParcelID};
pub use pathfind::Pathfinder;
pub use road::{Road, RoadID};
pub use trace::Trace;
pub use turn::{Turn, TurnID};
pub const LANE_THICKNESS: f64 = 2.5;

40
map_model/src/trace.rs Normal file
View File

@ -0,0 +1,40 @@
use dimensioned::si;
use geom::PolyLine;
use {LaneID, Map};
pub struct Trace {
// The rendered form
pub polyline: PolyLine,
}
impl Trace {
// TODO what about when the route is empty and the caller is at the end?
// TODO what about turns?
pub fn new(
start_dist_along: si::Meter<f64>,
route: &Vec<LaneID>,
length: si::Meter<f64>,
map: &Map,
) -> Trace {
assert!(!route.is_empty());
let (mut result, mut dist_left) = map
.get_l(route[0])
.lane_center_pts
.slice(start_dist_along, start_dist_along + length);
let mut idx = 1;
while dist_left > 0.0 * si::M && idx < route.len() {
let (piece, new_dist_left) = map
.get_l(route[idx])
.lane_center_pts
.slice(0.0 * si::M, dist_left);
result.extend(piece);
dist_left = new_dist_left;
idx += 1;
}
Trace { polyline: result }
}
}

View File

@ -32,7 +32,6 @@ pub struct Turn {
pub dst: LaneID,
pub between_sidewalks: bool,
/// GeomTurn stuff
pub line: Line,
}

View File

@ -6,7 +6,7 @@ use geom::EPSILON_DIST;
use intersections::{IntersectionSimState, Request};
use kinematics;
use kinematics::Vehicle;
use map_model::{LaneID, Map, TurnID, LANE_THICKNESS};
use map_model::{LaneID, Map, Trace, TurnID, LANE_THICKNESS};
use multimap::MultiMap;
use ordered_float::NotNaN;
use parking::ParkingSimState;
@ -748,7 +748,6 @@ impl DrivingSimState {
pub fn get_draw_car(&self, id: CarID, time: Tick, map: &Map) -> Option<DrawCarInput> {
let c = self.cars.get(&id)?;
let (base_pos, angle) = c.on.dist_along(c.dist_along, map);
let stopping_dist = c.vehicle.stopping_distance(c.speed);
// TODO arguably, this math might belong in DrawCar.
let pos = if let Some(ref parking) = c.parking {
@ -766,13 +765,26 @@ impl DrivingSimState {
base_pos
};
let stopping_dist = c.vehicle.stopping_distance(c.speed);
let stopping_trace = if stopping_dist <= EPSILON_DIST {
None
} else {
// TODO amend the route?
Some(Trace::new(
c.dist_along,
&self.get_current_route(id).unwrap(),
stopping_dist,
map,
))
};
Some(DrawCarInput {
id: c.id,
vehicle_length: c.vehicle.length,
waiting_for_turn: c.waiting_for.and_then(|on| on.maybe_turn()),
front: pos,
angle,
stopping_dist,
stopping_trace,
})
}

View File

@ -60,7 +60,7 @@ pub use events::Event;
use geom::{Angle, Pt2D};
pub use helpers::{load, SimFlags};
pub use instrument::save_backtraces;
use map_model::{LaneID, Map, TurnID};
use map_model::{LaneID, Map, Trace, TurnID};
pub use scenario::{Neighborhood, Scenario, SeedParkedCars, SpawnOverTime};
pub use sim::{Benchmark, Sim};
use std::fmt;
@ -379,7 +379,7 @@ pub struct DrawCarInput {
pub waiting_for_turn: Option<TurnID>,
pub front: Pt2D,
pub angle: Angle,
pub stopping_dist: Distance,
pub stopping_trace: Option<Trace>,
}
// We have to do this in the crate where these types are defined. Bit annoying, since it's really

View File

@ -1,4 +1,3 @@
use dimensioned::si;
use geom::{Angle, Polygon, Pt2D};
use kinematics::Vehicle;
use map_model;
@ -212,7 +211,7 @@ impl ParkingLane {
waiting_for_turn: None,
front: front,
angle: angle,
stopping_dist: 0.0 * si::M,
stopping_trace: None,
})
})
}).collect()