mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-25 11:44:25 +03:00
zorder for cars/peds too... had to rework get_objects_onscreen
This commit is contained in:
parent
1e7b8f2dfc
commit
6dee096a0e
@ -22,9 +22,6 @@
|
||||
|
||||
- model U-turns
|
||||
|
||||
- zorder for bridges/tunnels
|
||||
- apply to cars/peds too; figure out statics/dynamics plumbing
|
||||
|
||||
- degenerate-2's should only have one crosswalk
|
||||
- then make them thinner
|
||||
|
||||
|
@ -4,8 +4,6 @@
|
||||
|
||||
- interactively spawn a car/ped somewhere to test this easily
|
||||
- pathfinding or trace or something is wrong for walking; the last line sometimes has the wrong distance
|
||||
- driving OR walking goal could also be border. actually need this to spawn cars on tunnels reasonably
|
||||
- then back to zorder for cars/peds
|
||||
|
||||
- try showing traffic signals by little boxes at the end of lanes
|
||||
- red circle means right turn on red OK, red right arrow means nope, green means normal turns ok, green arrow means protected left, crosswalk hand or stick figure
|
||||
|
@ -8,6 +8,7 @@ use map_model::{BusStop, BusStopID, Map, LANE_THICKNESS};
|
||||
pub struct DrawBusStop {
|
||||
pub id: BusStopID,
|
||||
polygon: Polygon,
|
||||
zorder: isize,
|
||||
}
|
||||
|
||||
impl DrawBusStop {
|
||||
@ -31,6 +32,7 @@ impl DrawBusStop {
|
||||
DrawBusStop {
|
||||
id: stop.id,
|
||||
polygon,
|
||||
zorder: map.get_parent(lane.id).get_zorder(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -57,4 +59,8 @@ impl Renderable for DrawBusStop {
|
||||
fn contains_pt(&self, pt: Pt2D) -> bool {
|
||||
self.polygon.contains_pt(pt)
|
||||
}
|
||||
|
||||
fn get_zorder(&self) -> isize {
|
||||
self.zorder
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ pub struct DrawCar {
|
||||
// TODO maybe also draw lookahead buffer to know what the car is considering
|
||||
stopping_buffer: Option<Polygon>,
|
||||
state: CarState,
|
||||
zorder: isize,
|
||||
}
|
||||
|
||||
impl DrawCar {
|
||||
@ -49,6 +50,7 @@ impl DrawCar {
|
||||
right_blinker_on,
|
||||
stopping_buffer,
|
||||
state: input.state,
|
||||
zorder: input.on.get_zorder(map),
|
||||
};
|
||||
}
|
||||
|
||||
@ -118,6 +120,7 @@ impl DrawCar {
|
||||
right_blinker_on,
|
||||
stopping_buffer,
|
||||
state: input.state,
|
||||
zorder: input.on.get_zorder(map),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -202,6 +205,10 @@ impl Renderable for DrawCar {
|
||||
fn contains_pt(&self, pt: Pt2D) -> bool {
|
||||
self.body_polygon.contains_pt(pt)
|
||||
}
|
||||
|
||||
fn get_zorder(&self) -> isize {
|
||||
self.zorder
|
||||
}
|
||||
}
|
||||
|
||||
fn thick_line_from_angle(thickness: f64, line_length: f64, pt: Pt2D, angle: Angle) -> Polygon {
|
||||
|
@ -19,8 +19,15 @@ use map_model::{
|
||||
RoadID, Traversable, Turn, TurnID, LANE_THICKNESS,
|
||||
};
|
||||
use sim::GetDrawAgents;
|
||||
use std::borrow::Borrow;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum RenderOrder {
|
||||
BackToFront,
|
||||
FrontToBack,
|
||||
}
|
||||
|
||||
pub struct DrawMap {
|
||||
pub lanes: Vec<DrawLane>,
|
||||
pub intersections: Vec<DrawIntersection>,
|
||||
@ -210,7 +217,6 @@ impl DrawMap {
|
||||
&self.areas[id.0]
|
||||
}
|
||||
|
||||
// A greatly simplified form of get_objects_onscreen
|
||||
pub fn get_matching_lanes(&self, bounds: Bounds) -> Vec<LaneID> {
|
||||
let mut results: Vec<LaneID> = Vec::new();
|
||||
for &(id, _, _) in &self.quadtree.query(bounds.as_bbox()) {
|
||||
@ -221,25 +227,21 @@ impl DrawMap {
|
||||
results
|
||||
}
|
||||
|
||||
// Returns in back-to-front order
|
||||
// The second pair is ephemeral objects (cars, pedestrians) that we can't borrow --
|
||||
// conveniently they're the front-most layer, so the caller doesn't have to do anything strange
|
||||
// to merge. TODO no longer true with zorder
|
||||
// TODO alternatively, we could return IDs in order, then the caller could turn around and call
|
||||
// a getter... except they still have to deal with DrawCar and DrawPedestrian not being
|
||||
// borrowable. Could move contains_pt and draw calls here directly, but that might be weird?
|
||||
// But maybe not.
|
||||
pub fn get_objects_onscreen<T: ShowObjects>(
|
||||
// False from the callback means abort
|
||||
pub fn handle_objects_onscreen<T: ShowObjects, F: FnMut(Box<&Renderable>) -> bool>(
|
||||
&self,
|
||||
screen_bounds: Bounds,
|
||||
map: &Map,
|
||||
sim: &GetDrawAgents,
|
||||
show_objs: &T,
|
||||
) -> (Vec<Box<&Renderable>>, Vec<Box<Renderable>>) {
|
||||
order: RenderOrder,
|
||||
mut callback: F,
|
||||
) {
|
||||
// From background to foreground Z-order
|
||||
let mut areas: Vec<Box<&Renderable>> = Vec::new();
|
||||
let mut parcels: Vec<Box<&Renderable>> = Vec::new();
|
||||
let mut lanes_and_intersections: Vec<Box<&Renderable>> = Vec::new();
|
||||
let mut lanes: Vec<Box<&Renderable>> = Vec::new();
|
||||
let mut intersections: Vec<Box<&Renderable>> = Vec::new();
|
||||
let mut buildings: Vec<Box<&Renderable>> = Vec::new();
|
||||
let mut extra_shapes: Vec<Box<&Renderable>> = Vec::new();
|
||||
let mut bus_stops: Vec<Box<&Renderable>> = Vec::new();
|
||||
@ -254,7 +256,7 @@ impl DrawMap {
|
||||
ID::Area(id) => areas.push(Box::new(self.get_a(*id))),
|
||||
ID::Parcel(id) => parcels.push(Box::new(self.get_p(*id))),
|
||||
ID::Lane(id) => {
|
||||
lanes_and_intersections.push(Box::new(self.get_l(*id)));
|
||||
lanes.push(Box::new(self.get_l(*id)));
|
||||
if !show_objs.show_icons_for(map.get_l(*id).dst_i) {
|
||||
for c in sim.get_draw_cars(Traversable::Lane(*id), map).into_iter() {
|
||||
cars.push(draw_vehicle(c, map));
|
||||
@ -265,7 +267,7 @@ impl DrawMap {
|
||||
}
|
||||
}
|
||||
ID::Intersection(id) => {
|
||||
lanes_and_intersections.push(Box::new(self.get_i(*id)));
|
||||
intersections.push(Box::new(self.get_i(*id)));
|
||||
for t in &map.get_i(*id).turns {
|
||||
if show_objs.show_icons_for(*id) {
|
||||
turn_icons.push(Box::new(self.get_t(*t)));
|
||||
@ -296,18 +298,30 @@ impl DrawMap {
|
||||
let mut borrows: Vec<Box<&Renderable>> = Vec::new();
|
||||
borrows.extend(areas);
|
||||
borrows.extend(parcels);
|
||||
// This is a stable sort.
|
||||
lanes_and_intersections.sort_by_key(|r| r.get_zorder());
|
||||
borrows.extend(lanes_and_intersections);
|
||||
borrows.extend(lanes);
|
||||
borrows.extend(intersections);
|
||||
borrows.extend(buildings);
|
||||
borrows.extend(extra_shapes);
|
||||
borrows.extend(bus_stops);
|
||||
borrows.extend(turn_icons);
|
||||
for c in &cars {
|
||||
borrows.push(Box::new(c.borrow()));
|
||||
}
|
||||
for p in &peds {
|
||||
borrows.push(Box::new(p.borrow()));
|
||||
}
|
||||
|
||||
let mut returns: Vec<Box<Renderable>> = Vec::new();
|
||||
returns.extend(cars);
|
||||
returns.extend(peds);
|
||||
// This is a stable sort.
|
||||
borrows.sort_by_key(|r| r.get_zorder());
|
||||
|
||||
(borrows, returns)
|
||||
if order == RenderOrder::FrontToBack {
|
||||
borrows.reverse();
|
||||
}
|
||||
|
||||
for r in borrows {
|
||||
if !callback(r) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ use crate::render::car::DrawCar;
|
||||
pub use crate::render::extra_shape::ExtraShapeID;
|
||||
pub use crate::render::intersection::{draw_signal_cycle, draw_signal_diagram};
|
||||
pub use crate::render::lane::DrawLane;
|
||||
pub use crate::render::map::DrawMap;
|
||||
pub use crate::render::map::{DrawMap, RenderOrder};
|
||||
pub use crate::render::pedestrian::DrawPedestrian;
|
||||
pub use crate::render::turn::{DrawCrosswalk, DrawTurn};
|
||||
use ezgui::{Color, GfxCtx};
|
||||
|
@ -12,6 +12,7 @@ pub struct DrawPedestrian {
|
||||
circle: Circle,
|
||||
turn_arrow: Option<Line>,
|
||||
preparing_bike: bool,
|
||||
zorder: isize,
|
||||
}
|
||||
|
||||
impl DrawPedestrian {
|
||||
@ -30,6 +31,7 @@ impl DrawPedestrian {
|
||||
circle: Circle::new(input.pos, RADIUS),
|
||||
turn_arrow,
|
||||
preparing_bike: input.preparing_bike,
|
||||
zorder: input.on.get_zorder(map),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -70,4 +72,8 @@ impl Renderable for DrawPedestrian {
|
||||
fn contains_pt(&self, pt: Pt2D) -> bool {
|
||||
self.circle.contains_pt(pt)
|
||||
}
|
||||
|
||||
fn get_zorder(&self) -> isize {
|
||||
self.zorder
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use crate::colors::ColorScheme;
|
||||
use abstutil;
|
||||
//use cpuprofiler;
|
||||
use crate::objects::{Ctx, RenderingHints, ID};
|
||||
use crate::render::{RenderOptions, Renderable};
|
||||
use crate::render::{RenderOptions, RenderOrder, Renderable};
|
||||
use crate::state::UIState;
|
||||
use ezgui::{
|
||||
Canvas, Color, EventLoopMode, Folder, GfxCtx, Key, ModalMenu, Text, TopMenu, UserInput,
|
||||
@ -12,7 +12,6 @@ use kml;
|
||||
use map_model::{BuildingID, LaneID};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use sim::GetDrawAgents;
|
||||
use std::borrow::Borrow;
|
||||
use std::collections::HashSet;
|
||||
use std::process;
|
||||
|
||||
@ -265,11 +264,7 @@ impl<S: UIState> GUI<RenderingHints> for UI<S> {
|
||||
};
|
||||
|
||||
let mut sample_intersection: Option<String> = None;
|
||||
let (statics, dynamics) = self.get_objects_onscreen();
|
||||
for obj in statics
|
||||
.into_iter()
|
||||
.chain(dynamics.iter().map(|obj| Box::new(obj.borrow())))
|
||||
{
|
||||
self.handle_objects_onscreen(RenderOrder::BackToFront, |obj| {
|
||||
let opts = RenderOptions {
|
||||
color: self.state.get_state().color_obj(obj.get_id(), &ctx),
|
||||
debug_mode: self.state.get_state().layers.debug_mode.is_enabled(),
|
||||
@ -284,7 +279,9 @@ impl<S: UIState> GUI<RenderingHints> for UI<S> {
|
||||
sample_intersection = Some(format!("_i{}", id.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
});
|
||||
|
||||
if !screencap {
|
||||
self.state.draw(g, &ctx);
|
||||
@ -356,7 +353,35 @@ impl<S: UIState> UI<S> {
|
||||
ui
|
||||
}
|
||||
|
||||
fn get_objects_onscreen(&self) -> (Vec<Box<&Renderable>>, Vec<Box<Renderable>>) {
|
||||
fn mouseover_something(&self) -> Option<ID> {
|
||||
let pt = self.canvas.get_cursor_in_map_space()?;
|
||||
|
||||
let mut id: Option<ID> = None;
|
||||
|
||||
self.handle_objects_onscreen(RenderOrder::FrontToBack, |obj| {
|
||||
// Don't mouseover parcels.
|
||||
// TODO Might get fancier rules in the future, so we can't mouseover irrelevant things
|
||||
// in intersection editor mode, for example.
|
||||
match obj.get_id() {
|
||||
ID::Parcel(_) => {}
|
||||
_ => {
|
||||
if obj.contains_pt(pt) {
|
||||
id = Some(obj.get_id());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
true
|
||||
});
|
||||
|
||||
id
|
||||
}
|
||||
|
||||
fn handle_objects_onscreen<F: FnMut(Box<&Renderable>) -> bool>(
|
||||
&self,
|
||||
order: RenderOrder,
|
||||
callback: F,
|
||||
) {
|
||||
let state = self.state.get_state();
|
||||
|
||||
let draw_agent_source: &GetDrawAgents = {
|
||||
@ -368,40 +393,16 @@ impl<S: UIState> UI<S> {
|
||||
}
|
||||
};
|
||||
|
||||
state.primary.draw_map.get_objects_onscreen(
|
||||
state.primary.draw_map.handle_objects_onscreen(
|
||||
self.canvas.get_screen_bounds(),
|
||||
&state.primary.map,
|
||||
draw_agent_source,
|
||||
state,
|
||||
order,
|
||||
callback,
|
||||
)
|
||||
}
|
||||
|
||||
fn mouseover_something(&self) -> Option<ID> {
|
||||
let pt = self.canvas.get_cursor_in_map_space()?;
|
||||
|
||||
let (statics, dynamics) = self.get_objects_onscreen();
|
||||
// Check front-to-back
|
||||
for obj in dynamics
|
||||
.iter()
|
||||
.map(|obj| Box::new(obj.borrow()))
|
||||
.chain(statics.into_iter().rev())
|
||||
{
|
||||
// Don't mouseover parcels.
|
||||
// TODO Might get fancier rules in the future, so we can't mouseover irrelevant things
|
||||
// in intersection editor mode, for example.
|
||||
match obj.get_id() {
|
||||
ID::Parcel(_) => {}
|
||||
_ => {
|
||||
if obj.contains_pt(pt) {
|
||||
return Some(obj.get_id());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn save_editor_state(&self) {
|
||||
let state = EditorState {
|
||||
map_name: self.state.get_state().primary.map.get_name().clone(),
|
||||
|
@ -115,4 +115,11 @@ impl Traversable {
|
||||
Traversable::Turn(id) => map.get_parent(id.dst).get_speed_limit(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_zorder(&self, map: &Map) -> isize {
|
||||
match *self {
|
||||
Traversable::Lane(id) => map.get_parent(id).get_zorder(),
|
||||
Traversable::Turn(id) => map.get_i(id.parent).get_zorder(map),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user