mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-27 16:36:02 +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::helpers::{ColorScheme, ID};
|
||||||
use crate::render::{DrawCtx, DrawOptions, Renderable};
|
use crate::render::{DrawCtx, DrawOptions, Renderable, OUTLINE_THICKNESS};
|
||||||
use ezgui::{Color, Drawable, GfxCtx, Prerender};
|
use ezgui::{Color, Drawable, GfxCtx, Prerender};
|
||||||
use geom::{Distance, Polygon};
|
use geom::{Distance, PolyLine, Polygon, Pt2D};
|
||||||
use map_model::{BusStop, BusStopID, Map, LANE_THICKNESS};
|
use map_model::{BusStop, BusStopID, Map, LANE_THICKNESS};
|
||||||
|
|
||||||
pub struct DrawBusStop {
|
pub struct DrawBusStop {
|
||||||
pub id: BusStopID,
|
pub id: BusStopID,
|
||||||
|
polyline: PolyLine,
|
||||||
polygon: Polygon,
|
polygon: Polygon,
|
||||||
zorder: isize,
|
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
|
// Kinda sad that bus stops might be very close to the start of the lane, but it's
|
||||||
// happening.
|
// happening.
|
||||||
let lane = map.get_l(stop.id.sidewalk);
|
let lane = map.get_l(stop.id.sidewalk);
|
||||||
let polygon = lane
|
let polyline = lane.lane_center_pts.exact_slice(
|
||||||
.lane_center_pts
|
|
||||||
.exact_slice(
|
|
||||||
Distance::ZERO.max(stop.sidewalk_pos.dist_along() - radius),
|
Distance::ZERO.max(stop.sidewalk_pos.dist_along() - radius),
|
||||||
lane.length().min(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![(
|
let draw_default = prerender.upload_borrowed(vec![(
|
||||||
cs.get_def("bus stop marking", Color::rgba(220, 160, 220, 0.8)),
|
cs.get_def("bus stop marking", Color::rgba(220, 160, 220, 0.8)),
|
||||||
&polygon,
|
&polygon,
|
||||||
@ -32,6 +31,7 @@ impl DrawBusStop {
|
|||||||
|
|
||||||
DrawBusStop {
|
DrawBusStop {
|
||||||
id: stop.id,
|
id: stop.id,
|
||||||
|
polyline,
|
||||||
polygon,
|
polygon,
|
||||||
zorder: map.get_parent(lane.id).get_zorder(),
|
zorder: map.get_parent(lane.id).get_zorder(),
|
||||||
draw_default,
|
draw_default,
|
||||||
@ -53,8 +53,13 @@ impl Renderable for DrawBusStop {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_outline(&self, _: &Map) -> Polygon {
|
fn get_outline(&self, _: &Map) -> Polygon {
|
||||||
// TODO need PolyLine->boundary
|
self.polyline
|
||||||
self.polygon.clone()
|
.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 {
|
fn get_zorder(&self) -> isize {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::helpers::{ColorScheme, ID};
|
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 ezgui::{Color, Drawable, GfxCtx, Prerender};
|
||||||
use geom::{Angle, Circle, Distance, PolyLine, Polygon, Pt2D};
|
use geom::{Angle, Circle, Distance, PolyLine, Polygon, Pt2D};
|
||||||
use map_model::{Map, TurnType};
|
use map_model::{Map, TurnType};
|
||||||
@ -9,6 +9,7 @@ const CAR_WIDTH: Distance = Distance::const_meters(2.0);
|
|||||||
|
|
||||||
pub struct DrawCar {
|
pub struct DrawCar {
|
||||||
pub id: CarID,
|
pub id: CarID,
|
||||||
|
body: PolyLine,
|
||||||
body_polygon: Polygon,
|
body_polygon: Polygon,
|
||||||
// Optional and could be empty for super short cars near borders.
|
// Optional and could be empty for super short cars near borders.
|
||||||
window_polygons: Vec<Polygon>,
|
window_polygons: Vec<Polygon>,
|
||||||
@ -90,6 +91,7 @@ impl DrawCar {
|
|||||||
|
|
||||||
DrawCar {
|
DrawCar {
|
||||||
id: input.id,
|
id: input.id,
|
||||||
|
body: input.body,
|
||||||
body_polygon,
|
body_polygon,
|
||||||
window_polygons: vec![front_window, back_window],
|
window_polygons: vec![front_window, back_window],
|
||||||
left_blinkers: Some((
|
left_blinkers: Some((
|
||||||
@ -177,8 +179,13 @@ impl Renderable for DrawCar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_outline(&self, _: &Map) -> Polygon {
|
fn get_outline(&self, _: &Map) -> Polygon {
|
||||||
// TODO need PolyLine->boundary
|
self.body
|
||||||
self.body_polygon.clone()
|
.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 {
|
fn get_zorder(&self) -> isize {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use crate::helpers::{ColorScheme, ID};
|
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 abstutil::Timer;
|
||||||
use ezgui::{Color, Drawable, GfxCtx, Prerender};
|
use ezgui::{Color, Drawable, GfxCtx, Prerender};
|
||||||
use geom::{Circle, Distance, Line, PolyLine, Polygon};
|
use geom::{Circle, Distance, Line, PolyLine, Polygon, Pt2D};
|
||||||
use map_model::{
|
use map_model::{
|
||||||
IntersectionType, Lane, LaneID, LaneType, Map, Road, LANE_THICKNESS, PARKING_SPOT_LENGTH,
|
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 {
|
fn get_outline(&self, map: &Map) -> Polygon {
|
||||||
// TODO need PolyLine->boundary
|
map.get_l(self.id)
|
||||||
self.polygon.clone()
|
.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 {
|
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);
|
const TURN_ICON_ARROW_LENGTH: Distance = Distance::const_meters(2.0);
|
||||||
pub const CROSSWALK_LINE_THICKNESS: Distance = Distance::const_meters(0.25);
|
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
|
// 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.
|
// 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::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 ezgui::{Color, Drawable, GfxCtx, Prerender};
|
||||||
use geom::Polygon;
|
use geom::{Polygon, Pt2D};
|
||||||
use map_model::{Map, Road, RoadID};
|
use map_model::{Map, Road, RoadID};
|
||||||
|
|
||||||
pub struct DrawRoad {
|
pub struct DrawRoad {
|
||||||
@ -34,8 +34,16 @@ impl Renderable for DrawRoad {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_outline(&self, map: &Map) -> Polygon {
|
fn get_outline(&self, map: &Map) -> Polygon {
|
||||||
// TODO need PolyLine->boundary
|
let (pl, width) = map.get_r(self.id).get_thick_polyline().unwrap();
|
||||||
map.get_r(self.id).get_thick_polygon().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 {
|
fn get_zorder(&self) -> isize {
|
||||||
|
@ -121,7 +121,7 @@ impl UI {
|
|||||||
|
|
||||||
if self.primary.current_selection == Some(obj.get_id()) {
|
if self.primary.current_selection == Some(obj.get_id()) {
|
||||||
g.draw_polygon(
|
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),
|
&obj.get_outline(&ctx.map),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,27 @@ impl PolyLine {
|
|||||||
pl.make_polygons(thickness)
|
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 {
|
pub fn reversed(&self) -> PolyLine {
|
||||||
let mut pts = self.pts.clone();
|
let mut pts = self.pts.clone();
|
||||||
pts.reverse();
|
pts.reverse();
|
||||||
|
@ -291,21 +291,26 @@ impl Road {
|
|||||||
search.iter().find(|(_, t)| lt == *t).map(|(id, _)| *id)
|
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_right = (self.children_forwards.len() as f64) * LANE_THICKNESS;
|
||||||
let width_left = (self.children_backwards.len() as f64) * LANE_THICKNESS;
|
let width_left = (self.children_backwards.len() as f64) * LANE_THICKNESS;
|
||||||
let total_width = width_right + width_left;
|
let total_width = width_right + width_left;
|
||||||
if width_right >= width_left {
|
if width_right >= width_left {
|
||||||
self.center_pts
|
self.center_pts
|
||||||
.shift_right((width_right - width_left) / 2.0)
|
.shift_right((width_right - width_left) / 2.0)
|
||||||
.map(|pl| pl.make_polygons(total_width))
|
.map(|pl| (pl, total_width))
|
||||||
} else {
|
} else {
|
||||||
self.center_pts
|
self.center_pts
|
||||||
.shift_left((width_left - width_right) / 2.0)
|
.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
|
// Also returns width. The polyline points the correct direction. None if no lanes that
|
||||||
// direction.
|
// direction.
|
||||||
pub fn get_center_for_side(&self, fwds: bool) -> Option<Warn<(PolyLine, Distance)>> {
|
pub fn get_center_for_side(&self, fwds: bool) -> Option<Warn<(PolyLine, Distance)>> {
|
||||||
|
Loading…
Reference in New Issue
Block a user