making DrawCar implement renderable

This commit is contained in:
Dustin Carlino 2018-09-13 22:16:48 -07:00
parent b3d2a5c5be
commit 5303087fa2
10 changed files with 114 additions and 97 deletions

View File

@ -981,8 +981,8 @@ so it feels like we implicitly have a big enum of active plugin, with each of th
- deal with overlapping keys that still kinda happen (sim ctrl, escape game)
- bug: do need to recalculate current_selection whenever anything potentially changes camera, like follow
- make draw car/ped implement renderable.
- move Draw* to editor crate, and have an intermediate thing exposed from sim and do the translation in get_blah_onscreen.
= make draw car/ped implement renderable.
= move Draw* to editor crate, and have an intermediate thing exposed from sim and do the translation in get_blah_onscreen.
- then rethink colors, with simplified single plugin
= then finally try out a unified quadtree!

View File

@ -45,7 +45,7 @@ impl FollowState {
// instead
FollowState::FollowingCar(id) => {
if let Some(c) = sim.get_draw_car(*id, map) {
let pt = c.focus_pt();
let pt = c.front;
canvas.center_on_map_pt(pt.x(), pt.y());
input.key_pressed(Key::Return, "stop following")
} else {

View File

@ -133,7 +133,7 @@ fn warp(line: String, map: &Map, sim: &Sim, canvas: &mut Canvas, selected: &mut
if let Some(c) = sim.get_draw_car(id, map) {
println!("Warping to {}", id);
*selected = Some(ID::Car(id));
c.focus_pt()
c.front
} else {
println!("{} doesn't exist", id);
return;

View File

@ -1,23 +1,22 @@
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
use aabb_quadtree::geom::Rect;
use colors::ColorScheme;
use dimensioned::si;
use ezgui::GfxCtx;
use geom::{Angle, Polygon, Pt2D};
use geom::{Polygon, Pt2D};
use graphics;
use kinematics::Vehicle;
use map_model::{geometry, Map, TurnID};
use {CarID, Distance};
use graphics::types::Color;
use map_model::{geometry, Map};
use render::{get_bbox, Renderable};
use sim::{CarID, DrawCarInput};
const CAR_WIDTH: f64 = 2.0;
// TODO should this live in editor/render?
pub struct DrawCar {
pub id: CarID,
body_polygon: Polygon,
window_polygons: Vec<Polygon>,
// TODO ideally, draw the turn icon inside the car quad. how can we do that easily?
turn_arrow: Option<[f64; 4]>,
front_pt: Pt2D,
// 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
@ -25,43 +24,39 @@ pub struct DrawCar {
}
impl DrawCar {
pub fn new(
id: CarID,
vehicle: &Vehicle,
waiting_for_turn: Option<TurnID>,
map: &Map,
front: Pt2D,
angle: Angle,
stopping_dist: Distance,
) -> DrawCar {
let turn_arrow = if let Some(t) = waiting_for_turn {
pub fn new(input: DrawCarInput, map: &Map) -> DrawCar {
let turn_arrow = if let Some(t) = input.waiting_for_turn {
let angle = map.get_t(t).line.angle();
let arrow_pt = front.project_away(vehicle.length.value_unsafe / 2.0, angle.opposite());
Some([arrow_pt.x(), arrow_pt.y(), front.x(), front.y()])
let arrow_pt = input
.front
.project_away(input.vehicle_length.value_unsafe / 2.0, angle.opposite());
Some([arrow_pt.x(), arrow_pt.y(), input.front.x(), input.front.y()])
} else {
None
};
let stopping_buffer_arrow = if stopping_dist == 0.0 * si::M {
let stopping_buffer_arrow = if input.stopping_dist == 0.0 * si::M {
None
} else {
let arrow_pt = front.project_away(stopping_dist.value_unsafe, angle);
Some([front.x(), front.y(), arrow_pt.x(), arrow_pt.y()])
let arrow_pt = input
.front
.project_away(input.stopping_dist.value_unsafe, input.angle);
Some([input.front.x(), input.front.y(), arrow_pt.x(), arrow_pt.y()])
};
let front_window_length_gap = 0.2;
let front_window_thickness = 0.3;
DrawCar {
id: id,
id: input.id,
turn_arrow,
// TODO the rounded corners from graphics::Line::new_round look kind of cool though
body_polygon: geometry::thick_line_from_angle(
CAR_WIDTH,
vehicle.length.value_unsafe,
front,
input.vehicle_length.value_unsafe,
input.front,
// find the back of the car relative to the front
angle.opposite(),
input.angle.opposite(),
),
// TODO it's way too hard to understand and tune this. just wait and stick in sprites
// or something.
@ -69,30 +64,44 @@ impl DrawCar {
geometry::thick_line_from_angle(
front_window_thickness,
CAR_WIDTH - 2.0 * front_window_length_gap,
front.project_away(1.0, angle.opposite()).project_away(
CAR_WIDTH / 2.0 - front_window_length_gap,
angle.rotate_degs(-90.0),
),
angle.rotate_degs(90.0),
input
.front
.project_away(1.0, input.angle.opposite())
.project_away(
CAR_WIDTH / 2.0 - front_window_length_gap,
input.angle.rotate_degs(-90.0),
),
input.angle.rotate_degs(90.0),
),
geometry::thick_line_from_angle(
front_window_thickness * 0.8,
CAR_WIDTH - 2.0 * front_window_length_gap,
front
.project_away(vehicle.length.value_unsafe - 1.0, angle.opposite())
input
.front
.project_away(
input.vehicle_length.value_unsafe - 1.0,
input.angle.opposite(),
)
.project_away(
CAR_WIDTH / 2.0 - front_window_length_gap,
angle.rotate_degs(-90.0),
input.angle.rotate_degs(-90.0),
),
angle.rotate_degs(90.0),
input.angle.rotate_degs(90.0),
),
],
front_pt: front,
stopping_buffer_arrow,
}
}
}
pub fn draw(&self, g: &mut GfxCtx, color: graphics::types::Color) {
impl Renderable for DrawCar {
type ID = CarID;
fn get_id(&self) -> CarID {
self.id
}
fn draw(&self, g: &mut GfxCtx, color: Color, _cs: &ColorScheme) {
g.draw_polygon(color, &self.body_polygon);
for p in &self.window_polygons {
g.draw_polygon([0.0, 0.0, 0.0, 1.0], p);
@ -116,11 +125,15 @@ impl DrawCar {
}
}
pub fn contains_pt(&self, pt: Pt2D) -> bool {
fn get_bbox(&self) -> Rect {
get_bbox(&self.body_polygon.get_bounds())
}
fn contains_pt(&self, pt: Pt2D) -> bool {
self.body_polygon.contains_pt(pt)
}
pub fn focus_pt(&self) -> Pt2D {
self.front_pt
fn tooltip_lines(&self, _map: &Map) -> Vec<String> {
vec![self.id.to_string()]
}
}

View File

@ -1,6 +1,7 @@
// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0
mod building;
mod car;
mod extra_shape;
mod intersection;
mod lane;
@ -15,6 +16,7 @@ use ezgui::GfxCtx;
use geom::{Bounds, Pt2D};
use graphics::types::Color;
use map_model::{geometry, Map};
pub use render::car::DrawCar;
pub use render::lane::DrawLane;
pub use render::map::DrawMap;
pub use render::pedestrian::DrawPedestrian;

View File

@ -337,7 +337,8 @@ impl UI {
Vec::new()
};
for l in &lanes_onscreen {
for c in &self.sim.get_draw_cars_on_lane(l.id, &self.map) {
for c in self.sim.get_draw_cars_on_lane(l.id, &self.map).into_iter() {
let c = render::DrawCar::new(c, &self.map);
if c.contains_pt(pt) {
return Some(ID::Car(c.id));
}
@ -361,7 +362,8 @@ impl UI {
return Some(ID::Turn(*t));
}
for c in &self.sim.get_draw_cars_on_turn(*t, &self.map) {
for c in self.sim.get_draw_cars_on_turn(*t, &self.map).into_iter() {
let c = render::DrawCar::new(c, &self.map);
if c.contains_pt(pt) {
return Some(ID::Car(c.id));
}
@ -655,8 +657,9 @@ impl UI {
.get_t(*t)
.draw(g, self.color_turn_icon(*t), &self.cs);
}
for c in &self.sim.get_draw_cars_on_turn(*t, &self.map) {
c.draw(g, self.color_car(c.id));
for c in self.sim.get_draw_cars_on_turn(*t, &self.map).into_iter() {
let c = render::DrawCar::new(c, &self.map);
c.draw(g, self.color_car(c.id), &self.cs);
}
for p in self.sim.get_draw_peds_on_turn(*t, &self.map).into_iter() {
let p = render::DrawPedestrian::new(p, &self.map);
@ -689,8 +692,9 @@ impl UI {
}
for l in &lanes_onscreen {
for c in &self.sim.get_draw_cars_on_lane(l.id, &self.map) {
c.draw(g, self.color_car(c.id));
for c in self.sim.get_draw_cars_on_lane(l.id, &self.map).into_iter() {
let c = render::DrawCar::new(c, &self.map);
c.draw(g, self.color_car(c.id), &self.cs);
}
for p in self.sim.get_draw_peds_on_lane(l.id, &self.map).into_iter() {
let p = render::DrawPedestrian::new(p, &self.map);

View File

@ -1,7 +1,6 @@
use abstutil;
use abstutil::{deserialize_btreemap, serialize_btreemap};
use dimensioned::si;
use draw_car::DrawCar;
use failure::{Error, ResultExt};
use geom::EPSILON_DIST;
use intersections::{IntersectionSimState, Request};
@ -19,8 +18,8 @@ use std::collections::BTreeMap;
use transit::TransitSimState;
use view::{AgentView, WorldView};
use {
Acceleration, AgentID, CarID, CarState, Distance, Event, InvariantViolated, On, ParkedCar,
ParkingSpot, Speed, Tick, Time,
Acceleration, AgentID, CarID, CarState, Distance, DrawCarInput, Event, InvariantViolated, On,
ParkedCar, ParkingSpot, Speed, Tick, Time,
};
const TIME_TO_PARK_OR_DEPART: Time = si::Second {
@ -397,7 +396,7 @@ impl SimQueue {
map: &Map,
time: Tick,
properties: &BTreeMap<CarID, Vehicle>,
) -> Vec<DrawCar> {
) -> Vec<DrawCarInput> {
let mut results = Vec::new();
for (_, id) in &self.cars_queue {
results.push(sim.get_draw_car(*id, time, map, properties).unwrap())
@ -767,7 +766,7 @@ impl DrivingSimState {
time: Tick,
map: &Map,
properties: &BTreeMap<CarID, Vehicle>,
) -> Option<DrawCar> {
) -> Option<DrawCarInput> {
let c = self.cars.get(&id)?;
let (base_pos, angle) = c.on.dist_along(c.dist_along, map);
let vehicle = &properties[&id];
@ -789,15 +788,14 @@ impl DrivingSimState {
base_pos
};
Some(DrawCar::new(
c.id,
vehicle,
c.waiting_for.and_then(|on| on.maybe_turn()),
map,
pos,
Some(DrawCarInput {
id: c.id,
vehicle_length: vehicle.length,
waiting_for_turn: c.waiting_for.and_then(|on| on.maybe_turn()),
front: pos,
angle,
stopping_dist,
))
})
}
pub fn get_draw_cars_on_lane(
@ -806,7 +804,7 @@ impl DrivingSimState {
time: Tick,
map: &Map,
properties: &BTreeMap<CarID, Vehicle>,
) -> Vec<DrawCar> {
) -> Vec<DrawCarInput> {
self.lanes[lane.0].get_draw_cars(self, map, time, properties)
}
@ -816,7 +814,7 @@ impl DrivingSimState {
time: Tick,
map: &Map,
properties: &BTreeMap<CarID, Vehicle>,
) -> Vec<DrawCar> {
) -> Vec<DrawCarInput> {
if let Some(queue) = self.turns.get(&turn) {
return queue.get_draw_cars(self, map, time, properties);
}

View File

@ -27,7 +27,6 @@ extern crate serde;
#[macro_use]
extern crate serde_derive;
mod draw_car;
mod driving;
mod events;
mod helpers;
@ -352,3 +351,12 @@ pub struct DrawPedestrianInput {
pub pos: Pt2D,
pub waiting_for_turn: Option<TurnID>,
}
pub struct DrawCarInput {
pub id: CarID,
pub vehicle_length: Distance,
pub waiting_for_turn: Option<TurnID>,
pub front: Pt2D,
pub angle: Angle,
pub stopping_dist: Distance,
}

View File

@ -1,12 +1,11 @@
use dimensioned::si;
use draw_car::DrawCar;
use geom::{Angle, Pt2D};
use kinematics::Vehicle;
use map_model;
use map_model::{Lane, LaneID, LaneType, Map};
use std::collections::BTreeMap;
use std::iter;
use {CarID, Distance, ParkedCar, ParkingSpot};
use {CarID, Distance, DrawCarInput, ParkedCar, ParkingSpot};
#[derive(Serialize, Deserialize, PartialEq, Eq)]
pub struct ParkingSimState {
@ -75,24 +74,20 @@ impl ParkingSimState {
pub fn get_draw_cars(
&self,
id: LaneID,
map: &Map,
properties: &BTreeMap<CarID, Vehicle>,
) -> Vec<DrawCar> {
self.lanes[id.0].get_draw_cars(map, properties)
) -> Vec<DrawCarInput> {
self.lanes[id.0].get_draw_cars(properties)
}
pub fn get_draw_car(
&self,
id: CarID,
map: &Map,
properties: &BTreeMap<CarID, Vehicle>,
) -> Option<DrawCar> {
) -> Option<DrawCarInput> {
// TODO this is so horrendously slow :D
for l in &self.lanes {
if l.occupants.contains(&Some(id)) {
return l.get_draw_cars(map, properties)
.into_iter()
.find(|c| c.id == id);
return l.get_draw_cars(properties).into_iter().find(|c| c.id == id);
}
}
None
@ -196,7 +191,7 @@ impl ParkingLane {
self.occupants[idx] = None;
}
fn get_draw_cars(&self, map: &Map, properties: &BTreeMap<CarID, Vehicle>) -> Vec<DrawCar> {
fn get_draw_cars(&self, properties: &BTreeMap<CarID, Vehicle>) -> Vec<DrawCarInput> {
self.occupants
.iter()
.enumerate()
@ -204,15 +199,14 @@ impl ParkingLane {
maybe_id.and_then(|id| {
let vehicle = &properties[&id];
let (front, angle) = self.spots[idx].front_of_car(vehicle);
Some(DrawCar::new(
id,
vehicle,
None,
map,
front,
angle,
0.0 * si::M,
))
Some(DrawCarInput {
id: id,
vehicle_length: vehicle.length,
waiting_for_turn: None,
front: front,
angle: angle,
stopping_dist: 0.0 * si::M,
})
})
})
.collect()

View File

@ -3,7 +3,6 @@
use abstutil;
use control::ControlMap;
use dimensioned::si;
use draw_car::DrawCar;
use driving::DrivingSimState;
use failure::Error;
use instrument::capture_backtrace;
@ -22,7 +21,10 @@ use transit::TransitSimState;
use trips::TripManager;
use view::WorldView;
use walking::WalkingSimState;
use {AgentID, CarID, CarState, DrawPedestrianInput, Event, PedestrianID, Tick, TIMESTEP};
use {
AgentID, CarID, CarState, DrawCarInput, DrawPedestrianInput, Event, PedestrianID, Tick,
TIMESTEP,
};
#[derive(Serialize, Deserialize, Derivative)]
#[derivative(PartialEq, Eq)]
@ -224,13 +226,10 @@ impl Sim {
self.driving_state.get_car_state(c)
}
pub fn get_draw_car(&self, id: CarID, map: &Map) -> Option<DrawCar> {
pub fn get_draw_car(&self, id: CarID, map: &Map) -> Option<DrawCarInput> {
self.driving_state
.get_draw_car(id, self.time, map, &self.car_properties)
.or_else(|| {
self.parking_state
.get_draw_car(id, map, &self.car_properties)
})
.or_else(|| self.parking_state.get_draw_car(id, &self.car_properties))
}
pub fn get_draw_ped(&self, id: PedestrianID, map: &Map) -> Option<DrawPedestrianInput> {
@ -238,20 +237,19 @@ impl Sim {
}
// TODO maybe just DrawAgent instead? should caller care?
pub fn get_draw_cars_on_lane(&self, l: LaneID, map: &Map) -> Vec<DrawCar> {
pub fn get_draw_cars_on_lane(&self, l: LaneID, map: &Map) -> Vec<DrawCarInput> {
match map.get_l(l).lane_type {
LaneType::Driving => {
self.driving_state
.get_draw_cars_on_lane(l, self.time, map, &self.car_properties)
}
LaneType::Parking => self.parking_state
.get_draw_cars(l, map, &self.car_properties),
LaneType::Parking => self.parking_state.get_draw_cars(l, &self.car_properties),
LaneType::Sidewalk => Vec::new(),
LaneType::Biking => Vec::new(),
}
}
pub fn get_draw_cars_on_turn(&self, t: TurnID, map: &Map) -> Vec<DrawCar> {
pub fn get_draw_cars_on_turn(&self, t: TurnID, map: &Map) -> Vec<DrawCarInput> {
self.driving_state
.get_draw_cars_on_turn(t, self.time, map, &self.car_properties)
}