better selection polygons for polyline-based things

This commit is contained in:
Dustin Carlino 2019-05-11 15:15:03 -07:00
parent 2454704b6b
commit 9b848c894a
8 changed files with 80 additions and 28 deletions

View File

@ -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(
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),
)
.make_polygons(LANE_THICKNESS * 0.8);
);
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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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.

View File

@ -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 {

View File

@ -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),
);
}

View File

@ -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();

View File

@ -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)>> {