mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-26 07:52:05 +03:00
better selection polygons for polyline-based things
This commit is contained in:
parent
2454704b6b
commit
9b848c894a
@ -1,11 +1,12 @@
|
||||
use crate::helpers::{ColorScheme, ID};
|
||||
use crate::render::{DrawCtx, DrawOptions, Renderable};
|
||||
use crate::render::{DrawCtx, DrawOptions, Renderable, OUTLINE_THICKNESS};
|
||||
use ezgui::{Color, Drawable, GfxCtx, Prerender};
|
||||
use geom::{Distance, Polygon};
|
||||
use geom::{Distance, PolyLine, Polygon, Pt2D};
|
||||
use map_model::{BusStop, BusStopID, Map, LANE_THICKNESS};
|
||||
|
||||
pub struct DrawBusStop {
|
||||
pub id: BusStopID,
|
||||
polyline: PolyLine,
|
||||
polygon: Polygon,
|
||||
zorder: isize,
|
||||
|
||||
@ -18,13 +19,11 @@ impl DrawBusStop {
|
||||
// Kinda sad that bus stops might be very close to the start of the lane, but it's
|
||||
// happening.
|
||||
let lane = map.get_l(stop.id.sidewalk);
|
||||
let polygon = lane
|
||||
.lane_center_pts
|
||||
.exact_slice(
|
||||
Distance::ZERO.max(stop.sidewalk_pos.dist_along() - radius),
|
||||
lane.length().min(stop.sidewalk_pos.dist_along() + radius),
|
||||
)
|
||||
.make_polygons(LANE_THICKNESS * 0.8);
|
||||
let polyline = lane.lane_center_pts.exact_slice(
|
||||
Distance::ZERO.max(stop.sidewalk_pos.dist_along() - radius),
|
||||
lane.length().min(stop.sidewalk_pos.dist_along() + radius),
|
||||
);
|
||||
let polygon = polyline.make_polygons(LANE_THICKNESS * 0.8);
|
||||
let draw_default = prerender.upload_borrowed(vec![(
|
||||
cs.get_def("bus stop marking", Color::rgba(220, 160, 220, 0.8)),
|
||||
&polygon,
|
||||
@ -32,6 +31,7 @@ impl DrawBusStop {
|
||||
|
||||
DrawBusStop {
|
||||
id: stop.id,
|
||||
polyline,
|
||||
polygon,
|
||||
zorder: map.get_parent(lane.id).get_zorder(),
|
||||
draw_default,
|
||||
@ -53,8 +53,13 @@ impl Renderable for DrawBusStop {
|
||||
}
|
||||
|
||||
fn get_outline(&self, _: &Map) -> Polygon {
|
||||
// TODO need PolyLine->boundary
|
||||
self.polygon.clone()
|
||||
self.polyline
|
||||
.to_thick_boundary(LANE_THICKNESS * 0.8, OUTLINE_THICKNESS)
|
||||
.unwrap_or_else(|| self.polygon.clone())
|
||||
}
|
||||
|
||||
fn contains_pt(&self, pt: Pt2D, _: &Map) -> bool {
|
||||
self.polygon.contains_pt(pt)
|
||||
}
|
||||
|
||||
fn get_zorder(&self) -> isize {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::helpers::{ColorScheme, ID};
|
||||
use crate::render::{should_draw_blinkers, DrawCtx, DrawOptions, Renderable};
|
||||
use crate::render::{should_draw_blinkers, DrawCtx, DrawOptions, Renderable, OUTLINE_THICKNESS};
|
||||
use ezgui::{Color, Drawable, GfxCtx, Prerender};
|
||||
use geom::{Angle, Circle, Distance, PolyLine, Polygon, Pt2D};
|
||||
use map_model::{Map, TurnType};
|
||||
@ -9,6 +9,7 @@ const CAR_WIDTH: Distance = Distance::const_meters(2.0);
|
||||
|
||||
pub struct DrawCar {
|
||||
pub id: CarID,
|
||||
body: PolyLine,
|
||||
body_polygon: Polygon,
|
||||
// Optional and could be empty for super short cars near borders.
|
||||
window_polygons: Vec<Polygon>,
|
||||
@ -90,6 +91,7 @@ impl DrawCar {
|
||||
|
||||
DrawCar {
|
||||
id: input.id,
|
||||
body: input.body,
|
||||
body_polygon,
|
||||
window_polygons: vec![front_window, back_window],
|
||||
left_blinkers: Some((
|
||||
@ -177,8 +179,13 @@ impl Renderable for DrawCar {
|
||||
}
|
||||
|
||||
fn get_outline(&self, _: &Map) -> Polygon {
|
||||
// TODO need PolyLine->boundary
|
||||
self.body_polygon.clone()
|
||||
self.body
|
||||
.to_thick_boundary(CAR_WIDTH, OUTLINE_THICKNESS)
|
||||
.unwrap_or_else(|| self.body_polygon.clone())
|
||||
}
|
||||
|
||||
fn contains_pt(&self, pt: Pt2D, _: &Map) -> bool {
|
||||
self.body_polygon.contains_pt(pt)
|
||||
}
|
||||
|
||||
fn get_zorder(&self) -> isize {
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::helpers::{ColorScheme, ID};
|
||||
use crate::render::{DrawCtx, DrawOptions, Renderable, BIG_ARROW_THICKNESS};
|
||||
use crate::render::{DrawCtx, DrawOptions, Renderable, BIG_ARROW_THICKNESS, OUTLINE_THICKNESS};
|
||||
use abstutil::Timer;
|
||||
use ezgui::{Color, Drawable, GfxCtx, Prerender};
|
||||
use geom::{Circle, Distance, Line, PolyLine, Polygon};
|
||||
use geom::{Circle, Distance, Line, PolyLine, Polygon, Pt2D};
|
||||
use map_model::{
|
||||
IntersectionType, Lane, LaneID, LaneType, Map, Road, LANE_THICKNESS, PARKING_SPOT_LENGTH,
|
||||
};
|
||||
@ -100,9 +100,15 @@ impl Renderable for DrawLane {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_outline(&self, _: &Map) -> Polygon {
|
||||
// TODO need PolyLine->boundary
|
||||
self.polygon.clone()
|
||||
fn get_outline(&self, map: &Map) -> Polygon {
|
||||
map.get_l(self.id)
|
||||
.lane_center_pts
|
||||
.to_thick_boundary(LANE_THICKNESS, OUTLINE_THICKNESS)
|
||||
.unwrap_or_else(|| self.polygon.clone())
|
||||
}
|
||||
|
||||
fn contains_pt(&self, pt: Pt2D, _: &Map) -> bool {
|
||||
self.polygon.contains_pt(pt)
|
||||
}
|
||||
|
||||
fn get_zorder(&self) -> isize {
|
||||
|
@ -39,7 +39,7 @@ const TURN_ICON_ARROW_THICKNESS: Distance = Distance::const_meters(0.15);
|
||||
const TURN_ICON_ARROW_LENGTH: Distance = Distance::const_meters(2.0);
|
||||
pub const CROSSWALK_LINE_THICKNESS: Distance = Distance::const_meters(0.25);
|
||||
|
||||
pub const OUTLINE_THICKNESS: Distance = Distance::const_meters(1.5);
|
||||
pub const OUTLINE_THICKNESS: Distance = Distance::const_meters(0.5);
|
||||
|
||||
// Does something belong here or as a method on ID? If it ONLY applies to renderable things, then
|
||||
// here. For example, trips aren't drawn, so it's meaningless to ask what their bounding box is.
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::helpers::{ColorScheme, ID};
|
||||
use crate::render::{DrawCtx, DrawOptions, Renderable, BIG_ARROW_THICKNESS};
|
||||
use crate::render::{DrawCtx, DrawOptions, Renderable, BIG_ARROW_THICKNESS, OUTLINE_THICKNESS};
|
||||
use ezgui::{Color, Drawable, GfxCtx, Prerender};
|
||||
use geom::Polygon;
|
||||
use geom::{Polygon, Pt2D};
|
||||
use map_model::{Map, Road, RoadID};
|
||||
|
||||
pub struct DrawRoad {
|
||||
@ -34,8 +34,16 @@ impl Renderable for DrawRoad {
|
||||
}
|
||||
|
||||
fn get_outline(&self, map: &Map) -> Polygon {
|
||||
// TODO need PolyLine->boundary
|
||||
map.get_r(self.id).get_thick_polygon().unwrap()
|
||||
let (pl, width) = map.get_r(self.id).get_thick_polyline().unwrap();
|
||||
pl.to_thick_boundary(width, OUTLINE_THICKNESS)
|
||||
.unwrap_or_else(|| map.get_r(self.id).get_thick_polygon().unwrap())
|
||||
}
|
||||
|
||||
fn contains_pt(&self, pt: Pt2D, map: &Map) -> bool {
|
||||
map.get_r(self.id)
|
||||
.get_thick_polygon()
|
||||
.unwrap()
|
||||
.contains_pt(pt)
|
||||
}
|
||||
|
||||
fn get_zorder(&self) -> isize {
|
||||
|
@ -121,7 +121,7 @@ impl UI {
|
||||
|
||||
if self.primary.current_selection == Some(obj.get_id()) {
|
||||
g.draw_polygon(
|
||||
self.cs.get_def("selected", Color::YELLOW.alpha(0.4)),
|
||||
self.cs.get_def("selected", Color::RED.alpha(0.7)),
|
||||
&obj.get_outline(&ctx.map),
|
||||
);
|
||||
}
|
||||
|
@ -59,6 +59,27 @@ impl PolyLine {
|
||||
pl.make_polygons(thickness)
|
||||
}
|
||||
|
||||
pub fn to_thick_boundary(
|
||||
&self,
|
||||
self_width: Distance,
|
||||
boundary_width: Distance,
|
||||
) -> Option<Polygon> {
|
||||
assert!(self_width > boundary_width);
|
||||
if self.length() <= boundary_width {
|
||||
return None;
|
||||
}
|
||||
let slice = self.exact_slice(boundary_width / 2.0, self.length() - boundary_width / 2.0);
|
||||
let mut side1 = slice.shift_with_sharp_angles((self_width - boundary_width) / 2.0);
|
||||
let mut side2 = slice.shift_with_sharp_angles(-(self_width - boundary_width) / 2.0);
|
||||
side2.reverse();
|
||||
side1.extend(side2);
|
||||
side1.push(side1[0]);
|
||||
Some(PolyLine::make_polygons_for_boundary(
|
||||
Pt2D::approx_dedupe(side1, EPSILON_DIST),
|
||||
boundary_width,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn reversed(&self) -> PolyLine {
|
||||
let mut pts = self.pts.clone();
|
||||
pts.reverse();
|
||||
|
@ -291,21 +291,26 @@ impl Road {
|
||||
search.iter().find(|(_, t)| lt == *t).map(|(id, _)| *id)
|
||||
}
|
||||
|
||||
pub fn get_thick_polygon(&self) -> Warn<Polygon> {
|
||||
pub fn get_thick_polyline(&self) -> Warn<(PolyLine, Distance)> {
|
||||
let width_right = (self.children_forwards.len() as f64) * LANE_THICKNESS;
|
||||
let width_left = (self.children_backwards.len() as f64) * LANE_THICKNESS;
|
||||
let total_width = width_right + width_left;
|
||||
if width_right >= width_left {
|
||||
self.center_pts
|
||||
.shift_right((width_right - width_left) / 2.0)
|
||||
.map(|pl| pl.make_polygons(total_width))
|
||||
.map(|pl| (pl, total_width))
|
||||
} else {
|
||||
self.center_pts
|
||||
.shift_left((width_left - width_right) / 2.0)
|
||||
.map(|pl| pl.make_polygons(total_width))
|
||||
.map(|pl| (pl, total_width))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_thick_polygon(&self) -> Warn<Polygon> {
|
||||
self.get_thick_polyline()
|
||||
.map(|(pl, width)| pl.make_polygons(width))
|
||||
}
|
||||
|
||||
// Also returns width. The polyline points the correct direction. None if no lanes that
|
||||
// direction.
|
||||
pub fn get_center_for_side(&self, fwds: bool) -> Option<Warn<(PolyLine, Distance)>> {
|
||||
|
Loading…
Reference in New Issue
Block a user