refactoring helpers to draw lines

This commit is contained in:
Dustin Carlino 2018-09-18 08:35:07 -07:00
parent aaa681a527
commit 7dc192b0c9
14 changed files with 143 additions and 138 deletions

View File

@ -1,5 +1,5 @@
use ezgui::{Canvas, GfxCtx, TextBox, UserInput};
use geom::{Polygon, Pt2D};
use geom::{Line, Polygon, Pt2D};
use map_model::geometry;
use piston::input::Key;
use plugins::Colorizer;
@ -78,16 +78,17 @@ impl SelectPolygonState {
let green = [0.0, 1.0, 0.0, 1.0];
let blue = [0.0, 0.0, 1.0, 1.0];
let radius = 2.0;
for pt in pts {
g.draw_ellipse(red, geometry::make_circle(*pt, radius));
}
g.draw_ellipse(green, geometry::make_circle(*pts.last().unwrap(), radius));
if pts.len() == 2 {
// TODO draw line
g.draw_line(red, radius / 2.0, &Line::new(pts[0], pts[1]));
}
if pts.len() >= 3 {
g.draw_polygon(blue, &Polygon::new(pts));
}
for pt in pts {
g.draw_ellipse(red, geometry::make_circle(*pt, radius));
}
g.draw_ellipse(green, geometry::make_circle(*pts.last().unwrap(), radius));
}
}

View File

@ -3,30 +3,25 @@
use aabb_quadtree::geom::Rect;
use colors::Colors;
use ezgui::GfxCtx;
use geom::{PolyLine, Polygon, Pt2D};
use graphics;
use geom::{Line, PolyLine, Polygon, Pt2D};
use map_model::{Building, BuildingID, Map};
use objects::{Ctx, ID};
use render::{get_bbox, RenderOptions, Renderable, BUILDING_BOUNDARY_THICKNESS};
use std::f64;
#[derive(Debug)]
pub struct DrawBuilding {
pub id: BuildingID,
// TODO should just have one. use graphics::Line for now.
// TODO bit wasteful to keep both
boundary_polygon: Polygon,
pub fill_polygon: Polygon,
front_path: [f64; 4],
front_path: Line,
}
impl DrawBuilding {
pub fn new(bldg: &Building) -> DrawBuilding {
DrawBuilding {
id: bldg.id,
front_path: {
let l = &bldg.front_path.line;
[l.pt1().x(), l.pt1().y(), l.pt2().x(), l.pt2().y()]
},
front_path: bldg.front_path.line.clone(),
fill_polygon: Polygon::new(&bldg.points),
boundary_polygon: PolyLine::new(bldg.points.clone())
.make_polygons_blindly(BUILDING_BOUNDARY_THICKNESS),
@ -48,16 +43,13 @@ impl Renderable for DrawBuilding {
);
// TODO tune width
g.draw_line(
&graphics::Line::new_round(ctx.cs.get(Colors::BuildingPath), 1.0),
self.front_path,
);
g.draw_rounded_line(ctx.cs.get(Colors::BuildingPath), 1.0, &self.front_path);
}
fn get_bbox(&self) -> Rect {
let mut b = self.fill_polygon.get_bounds();
b.update(self.front_path[0], self.front_path[1]);
b.update(self.front_path[2], self.front_path[3]);
b.update_pt(self.front_path.pt1());
b.update_pt(self.front_path.pt2());
get_bbox(&b)
}

View File

@ -2,8 +2,7 @@ use aabb_quadtree::geom::Rect;
use colors::Colors;
use dimensioned::si;
use ezgui::{shift_color, GfxCtx};
use geom::{Polygon, Pt2D};
use graphics;
use geom::{Line, Polygon, Pt2D};
use map_model::{geometry, Map};
use objects::{Ctx, ID};
use render::{get_bbox, RenderOptions, Renderable};
@ -16,11 +15,11 @@ pub struct DrawCar {
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]>,
turn_arrow: Option<Line>,
// 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
stopping_buffer_arrow: Option<[f64; 4]>,
stopping_buffer_arrow: Option<Line>,
}
impl DrawCar {
@ -30,7 +29,7 @@ impl DrawCar {
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()])
Some(Line::new(arrow_pt, input.front))
} else {
None
};
@ -41,7 +40,7 @@ impl DrawCar {
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()])
Some(Line::new(input.front, arrow_pt))
};
let front_window_length_gap = 0.2;
@ -50,7 +49,6 @@ impl DrawCar {
DrawCar {
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,
input.vehicle_length.value_unsafe,
@ -114,20 +112,12 @@ impl Renderable for DrawCar {
}
// TODO tune color, sizes
if let Some(a) = self.turn_arrow {
g.draw_arrow(
&graphics::Line::new_round([0.0, 1.0, 1.0, 1.0], 0.25),
a,
1.0,
);
if let Some(ref a) = self.turn_arrow {
g.draw_arrow([0.0, 1.0, 1.0, 1.0], 0.25, 1.0, a);
}
if let Some(a) = self.stopping_buffer_arrow {
g.draw_arrow(
&graphics::Line::new_round([1.0, 0.0, 0.0, 0.7], 0.25),
a,
1.0,
);
if let Some(ref a) = self.stopping_buffer_arrow {
g.draw_arrow([1.0, 0.0, 0.0, 0.7], 0.25, 1.0, a);
}
}

View File

@ -5,8 +5,6 @@ use colors::Colors;
use dimensioned::si;
use ezgui::GfxCtx;
use geom::{Line, Polygon, Pt2D};
use graphics;
use graphics::math::Vec2d;
use map_model::{geometry, Intersection, IntersectionID, LaneType, Map};
use objects::{Ctx, ID};
use render::{get_bbox, DrawLane, RenderOptions, Renderable};
@ -16,7 +14,7 @@ use std::f64;
pub struct DrawIntersection {
pub id: IntersectionID,
pub polygon: Polygon,
crosswalks: Vec<Vec<(Vec2d, Vec2d)>>,
crosswalks: Vec<Vec<Line>>,
center: Pt2D,
has_traffic_signal: bool,
}
@ -111,16 +109,13 @@ impl Renderable for DrawIntersection {
});
g.draw_polygon(color, &self.polygon);
let crosswalk_marking = graphics::Line::new(
ctx.cs.get(Colors::Crosswalk),
// TODO move this somewhere
0.25,
);
for crosswalk in &self.crosswalks {
for pair in crosswalk {
for line in crosswalk {
g.draw_line(
&crosswalk_marking,
[pair.0[0], pair.0[1], pair.1[0], pair.1[1]],
ctx.cs.get(Colors::Crosswalk),
// TODO move this somewhere
0.25,
line,
);
}
}
@ -145,7 +140,7 @@ impl Renderable for DrawIntersection {
}
}
fn calculate_crosswalks(inter: &Intersection, map: &Map) -> Vec<Vec<(Vec2d, Vec2d)>> {
fn calculate_crosswalks(inter: &Intersection, map: &Map) -> Vec<Vec<Line>> {
let mut crosswalks = Vec::new();
for id in inter
@ -192,8 +187,8 @@ fn calculate_crosswalks(inter: &Intersection, map: &Map) -> Vec<Vec<(Vec2d, Vec2
}
// TODO copied from DrawLane
fn perp_line(l: Line, length: f64) -> (Vec2d, Vec2d) {
fn perp_line(l: Line, length: f64) -> Line {
let pt1 = l.shift(length / 2.0).pt1();
let pt2 = l.reverse().shift(length / 2.0).pt2();
(pt1.to_vec(), pt2.to_vec())
Line::new(pt1, pt2)
}

View File

@ -6,7 +6,6 @@ use control::ControlMap;
use dimensioned::si;
use ezgui::GfxCtx;
use geom::{Line, Polygon, Pt2D};
use graphics;
use map_model;
use map_model::{geometry, LaneID};
use objects::{Ctx, ID};
@ -16,7 +15,7 @@ const MIN_ZOOM_FOR_LANE_MARKERS: f64 = 5.0;
#[derive(Debug)]
struct Marking {
lines: Vec<[f64; 4]>,
lines: Vec<Line>,
color: Colors,
thickness: f64,
round: bool,
@ -50,7 +49,7 @@ impl DrawLane {
.center_pts
.points()
.windows(2)
.map(|pair| [pair[0].x(), pair[0].y(), pair[1].x(), pair[1].y()])
.map(|pair| Line::new(pair[0], pair[1]))
.collect(),
color: Colors::RoadOrientation,
thickness: geometry::BIG_ARROW_THICKNESS,
@ -88,13 +87,15 @@ impl DrawLane {
}
fn draw_debug(&self, g: &mut GfxCtx, ctx: Ctx) {
let line =
graphics::Line::new_round(ctx.cs.get(Colors::Debug), PARCEL_BOUNDARY_THICKNESS / 2.0);
let circle_color = ctx.cs.get(Colors::BrightDebug);
for pair in ctx.map.get_l(self.id).lane_center_pts.points().windows(2) {
let (pt1, pt2) = (pair[0], pair[1]);
g.draw_line(&line, [pt1.x(), pt1.y(), pt2.x(), pt2.y()]);
g.draw_line(
ctx.cs.get(Colors::Debug),
PARCEL_BOUNDARY_THICKNESS / 2.0,
&Line::new(pt1, pt2),
);
g.draw_ellipse(circle_color, geometry::make_circle(pt1, 0.4));
g.draw_ellipse(circle_color, geometry::make_circle(pt2, 0.8));
}
@ -138,13 +139,12 @@ impl Renderable for DrawLane {
if opts.cam_zoom >= MIN_ZOOM_FOR_LANE_MARKERS {
for m in &self.markings {
let line = if m.round {
graphics::Line::new_round(ctx.cs.get(m.color), m.thickness)
} else {
graphics::Line::new(ctx.cs.get(m.color), m.thickness)
};
for pts in &m.lines {
g.draw_line(&line, *pts);
for line in &m.lines {
if m.round {
g.draw_rounded_line(ctx.cs.get(m.color), m.thickness, line);
} else {
g.draw_line(ctx.cs.get(m.color), m.thickness, line);
}
}
}
}
@ -187,11 +187,10 @@ impl Renderable for DrawLane {
}
// TODO this always does it at pt1
// TODO move to Line or reimplement differently
fn perp_line(l: Line, length: f64) -> [f64; 4] {
fn perp_line(l: Line, length: f64) -> Line {
let pt1 = l.shift(length / 2.0).pt1();
let pt2 = l.reverse().shift(length / 2.0).pt2();
[pt1.x(), pt1.y(), pt2.x(), pt2.y()]
Line::new(pt1, pt2)
}
fn new_perp_line(l: Line, length: f64) -> Line {
@ -241,13 +240,13 @@ fn calculate_parking_lines(lane: &map_model::Lane) -> Marking {
let t_pt = pt.project_away(geometry::LANE_THICKNESS * 0.4, perp_angle);
// The perp leg
let p1 = t_pt.project_away(leg_length, perp_angle.opposite());
lines.push([t_pt.x(), t_pt.y(), p1.x(), p1.y()]);
lines.push(Line::new(t_pt, p1));
// Upper leg
let p2 = t_pt.project_away(leg_length, lane_angle);
lines.push([t_pt.x(), t_pt.y(), p2.x(), p2.y()]);
lines.push(Line::new(t_pt, p2));
// Lower leg
let p3 = t_pt.project_away(leg_length, lane_angle.opposite());
lines.push([t_pt.x(), t_pt.y(), p3.x(), p3.y()]);
lines.push(Line::new(t_pt, p3));
}
}
@ -284,7 +283,7 @@ fn calculate_driving_lines(lane: &map_model::Lane, parent: &map_model::Road) ->
let (pt1, _) = lane_edge_pts.dist_along(start);
let (pt2, _) = lane_edge_pts.dist_along(start + dash_len);
lines.push([pt1.x(), pt1.y(), pt2.x(), pt2.y()]);
lines.push(Line::new(pt1, pt2));
start += dash_len + dash_separation;
}

View File

@ -30,7 +30,7 @@ const COLORS: [Color; 14] = [
#[derive(Debug)]
pub struct DrawParcel {
pub id: ParcelID,
// TODO should just have one. use graphics::Line for now.
// TODO bit wasteful to keep both
boundary_polygon: Polygon,
pub fill_polygon: Polygon,
}

View File

@ -1,8 +1,7 @@
use aabb_quadtree::geom::Rect;
use colors::Colors;
use ezgui::{shift_color, GfxCtx};
use geom::Pt2D;
use graphics;
use geom::{Line, Pt2D};
use map_model::{geometry, Map};
use objects::{Ctx, ID};
use render::{RenderOptions, Renderable};
@ -14,7 +13,7 @@ const RADIUS: f64 = 1.0;
pub struct DrawPedestrian {
pub id: PedestrianID,
circle: [f64; 4],
turn_arrow: Option<[f64; 4]>,
turn_arrow: Option<Line>,
}
impl DrawPedestrian {
@ -23,7 +22,7 @@ impl DrawPedestrian {
// TODO this isn't quite right, but good enough for now
let angle = map.get_t(t).line.angle();
let arrow_pt = input.pos.project_away(RADIUS, angle.opposite());
Some([arrow_pt.x(), arrow_pt.y(), input.pos.x(), input.pos.y()])
Some(Line::new(arrow_pt, input.pos))
} else {
None
};
@ -48,12 +47,8 @@ impl Renderable for DrawPedestrian {
g.draw_ellipse(color, self.circle);
// TODO tune color, sizes
if let Some(a) = self.turn_arrow {
g.draw_arrow(
&graphics::Line::new_round([0.0, 1.0, 1.0, 1.0], 0.25),
a,
0.3,
);
if let Some(ref a) = self.turn_arrow {
g.draw_rounded_arrow([0.0, 1.0, 1.0, 1.0], 0.25, 0.3, a);
}
}

View File

@ -4,9 +4,7 @@ use aabb_quadtree::geom::Rect;
use colors::Colors;
use dimensioned::si;
use ezgui::GfxCtx;
use geom::Pt2D;
use graphics;
use graphics::math::Vec2d;
use geom::{Line, Pt2D};
use graphics::types::Color;
use map_model::{geometry, Map, Turn, TurnID};
use objects::{Ctx, ID};
@ -19,10 +17,10 @@ use std::f64;
#[derive(Debug)]
pub struct DrawTurn {
pub id: TurnID,
src_pt: Vec2d,
pub dst_pt: Vec2d,
src_pt: Pt2D,
dst_pt: Pt2D,
icon_circle: [f64; 4],
icon_arrow: [f64; 4],
icon_arrow: Line,
}
impl DrawTurn {
@ -38,36 +36,27 @@ impl DrawTurn {
.reverse()
.unbounded_dist_along((offset_along_lane + 0.5) * TURN_ICON_ARROW_LENGTH * si::M);
let icon_src = icon_center
.project_away(TURN_ICON_ARROW_LENGTH / 2.0, angle.opposite())
.to_vec();
let icon_dst = icon_center
.project_away(TURN_ICON_ARROW_LENGTH / 2.0, angle)
.to_vec();
let icon_circle = geometry::make_circle(icon_center, TURN_ICON_ARROW_LENGTH / 2.0);
let icon_arrow = [icon_src[0], icon_src[1], icon_dst[0], icon_dst[1]];
let icon_src = icon_center.project_away(TURN_ICON_ARROW_LENGTH / 2.0, angle.opposite());
let icon_dst = icon_center.project_away(TURN_ICON_ARROW_LENGTH / 2.0, angle);
let icon_arrow = Line::new(icon_src, icon_dst);
DrawTurn {
id: turn.id,
src_pt: src_pt.to_vec(),
dst_pt: dst_pt.to_vec(),
src_pt,
dst_pt,
icon_circle,
icon_arrow,
}
}
pub fn draw_full(&self, g: &mut GfxCtx, color: Color) {
g.draw_arrow(
&graphics::Line::new_round(color, geometry::BIG_ARROW_THICKNESS),
[
self.src_pt[0],
self.src_pt[1],
self.dst_pt[0],
self.dst_pt[1],
],
g.draw_rounded_arrow(
color,
geometry::BIG_ARROW_THICKNESS,
BIG_ARROW_TIP_LENGTH,
&Line::new(self.src_pt, self.dst_pt),
);
}
}
@ -82,12 +71,10 @@ impl Renderable for DrawTurn {
g.draw_ellipse(ctx.cs.get(Colors::TurnIconCircle), self.icon_circle);
g.draw_arrow(
&graphics::Line::new_round(
opts.color.unwrap_or(ctx.cs.get(Colors::TurnIconInactive)),
TURN_ICON_ARROW_THICKNESS,
),
self.icon_arrow,
opts.color.unwrap_or(ctx.cs.get(Colors::TurnIconInactive)),
TURN_ICON_ARROW_THICKNESS,
TURN_ICON_ARROW_TIP_LENGTH,
&self.icon_arrow,
);
}

View File

@ -52,13 +52,66 @@ impl<'a> GfxCtx<'a> {
graphics::clear(color, self.gfx);
}
pub fn draw_line(&mut self, style: &graphics::Line, pts: [f64; 4]) {
style.draw(pts, &self.ctx.draw_state, self.ctx.transform, self.gfx);
// Use graphics::Line internally for now, but make it easy to switch to something else by
// picking this API now.
// TODO refactor line -> coordinates
pub fn draw_line(&mut self, color: Color, thickness: f64, line: &geom::Line) {
graphics::Line::new(color, thickness).draw(
[
line.pt1().x(),
line.pt1().y(),
line.pt2().x(),
line.pt2().y(),
],
&self.ctx.draw_state,
self.ctx.transform,
self.gfx,
);
}
pub fn draw_arrow(&mut self, style: &graphics::Line, pts: [f64; 4], head_size: f64) {
style.draw_arrow(
pts,
pub fn draw_rounded_line(&mut self, color: Color, thickness: f64, line: &geom::Line) {
graphics::Line::new_round(color, thickness).draw(
[
line.pt1().x(),
line.pt1().y(),
line.pt2().x(),
line.pt2().y(),
],
&self.ctx.draw_state,
self.ctx.transform,
self.gfx,
);
}
pub fn draw_arrow(&mut self, color: Color, thickness: f64, head_size: f64, line: &geom::Line) {
graphics::Line::new(color, thickness).draw_arrow(
[
line.pt1().x(),
line.pt1().y(),
line.pt2().x(),
line.pt2().y(),
],
head_size,
&self.ctx.draw_state,
self.ctx.transform,
self.gfx,
);
}
pub fn draw_rounded_arrow(
&mut self,
color: Color,
thickness: f64,
head_size: f64,
line: &geom::Line,
) {
graphics::Line::new_round(color, thickness).draw_arrow(
[
line.pt1().x(),
line.pt1().y(),
line.pt2().x(),
line.pt2().y(),
],
head_size,
&self.ctx.draw_state,
self.ctx.transform,

View File

@ -32,11 +32,11 @@ impl Bounds {
self.max_y = self.max_y.max(y);
}
pub fn update_pt(&mut self, pt: &Pt2D) {
pub fn update_pt(&mut self, pt: Pt2D) {
self.update(pt.x(), pt.y());
}
pub fn update_coord(&mut self, coord: &LonLat) {
pub fn update_coord(&mut self, coord: LonLat) {
self.update(coord.longitude, coord.latitude);
}

View File

@ -3,7 +3,7 @@ use std::fmt;
use {line_intersection, Angle, Pt2D, EPSILON_DIST};
// Segment, technically
#[derive(Serialize, Deserialize, Debug)]
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Line(Pt2D, Pt2D);
impl Line {

View File

@ -102,9 +102,9 @@ impl Polygon {
pub fn get_bounds(&self) -> Bounds {
let mut b = Bounds::new();
for tri in &self.triangles {
b.update_pt(&tri.pt1);
b.update_pt(&tri.pt2);
b.update_pt(&tri.pt3);
b.update_pt(tri.pt1);
b.update_pt(tri.pt2);
b.update_pt(tri.pt3);
}
b
}

View File

@ -34,25 +34,25 @@ impl Map {
for r in &self.roads {
for pt in &r.points {
bounds.update_coord(pt);
bounds.update_coord(*pt);
}
}
for i in &self.intersections {
bounds.update_coord(&i.point);
bounds.update_coord(i.point);
}
for b in &self.buildings {
for pt in &b.points {
bounds.update_coord(pt);
bounds.update_coord(*pt);
}
}
for a in &self.areas {
for pt in &a.points {
bounds.update_coord(pt);
bounds.update_coord(*pt);
}
}
for p in &self.parcels {
for pt in &p.points {
bounds.update_coord(pt);
bounds.update_coord(*pt);
}
}

View File

@ -311,18 +311,11 @@ impl UI {
}
}
fn draw_line(g: &mut GfxCtx, pt1: Pt2D, pt2: Pt2D, thickness: f64, color: Color) {
g.draw_line(
&graphics::Line::new(color, thickness),
[pt1.x(), pt1.y(), pt2.x(), pt2.y()],
);
}
fn draw_polyline(g: &mut GfxCtx, pl: &PolyLine, thickness: f64, color: Color) {
let pts = pl.points();
assert!(pts.len() >= 2);
for pair in pts.windows(2) {
draw_line(g, pair[0], pair[1], thickness, color);
g.draw_line(color, thickness, Line::new(pair[0], pair[1]));
}
let radius = 0.5;
for pt in pts {