mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-29 04:35:51 +03:00
making DrawCar implement renderable
This commit is contained in:
parent
b3d2a5c5be
commit
5303087fa2
@ -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!
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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(
|
||||
input
|
||||
.front
|
||||
.project_away(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),
|
||||
),
|
||||
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()]
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user