From f36c94c730fe287f76736aaa529b9be1b7474e9e Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Thu, 23 Aug 2018 14:37:13 -0700 Subject: [PATCH] render individual points from extra KML, and refactor some circle helpers --- docs/design.md | 6 ++++ docs/references.md | 5 ++++ editor/color_scheme | 4 +-- editor/src/experimental.rs | 4 +-- editor/src/kml.rs | 27 +++++++++++++---- editor/src/render/extra_shape.rs | 48 ++++++++++++++++++++++++------- editor/src/render/intersection.rs | 6 ++-- editor/src/render/lane.rs | 4 +-- editor/src/render/mod.rs | 1 + editor/src/render/turn.rs | 14 ++------- editor/src/ui.rs | 20 ++++++------- geom/src/pt.rs | 4 +++ map_model/Cargo.toml | 1 - map_model/src/geometry.rs | 20 ++++++++----- map_model/src/lib.rs | 1 - sim/src/draw_ped.rs | 12 ++------ 16 files changed, 112 insertions(+), 65 deletions(-) create mode 100644 docs/references.md diff --git a/docs/design.md b/docs/design.md index 1604f11ed7..667dbb6c57 100644 --- a/docs/design.md +++ b/docs/design.md @@ -594,3 +594,9 @@ CarParking - rename to ParkedCar SidewalkSpot - this should cache lane and distance. :) + +## Notes on King County GIS datasets + +- TODO: https://data-seattlecitygis.opendata.arcgis.com/datasets/channelization + +- https://data-seattlecitygis.opendata.arcgis.com/datasets/street-signs diff --git a/docs/references.md b/docs/references.md new file mode 100644 index 0000000000..5306af69f2 --- /dev/null +++ b/docs/references.md @@ -0,0 +1,5 @@ +# References + +## Groups that may be eventually interested + +- Seattle Times Traffic Lab diff --git a/editor/color_scheme b/editor/color_scheme index eb8c159efa..d2a70ae68a 100644 --- a/editor/color_scheme +++ b/editor/color_scheme @@ -175,9 +175,9 @@ 1.0 ], "ExtraShape": [ + 0.0, + 1.0, 1.0, - 0.0, - 0.0, 1.0 ], "MatchClassification": [ diff --git a/editor/src/experimental.rs b/editor/src/experimental.rs index 52c9ced973..6c489491ca 100644 --- a/editor/src/experimental.rs +++ b/editor/src/experimental.rs @@ -282,7 +282,7 @@ impl UI { let hit = vertical_pl.intersection(&horiz_pl).unwrap(); if false { - g.draw_ellipse(BLUE, geometry::circle(hit.x(), hit.y(), 1.0)); + g.draw_ellipse(BLUE, geometry::make_circle(hit, 1.0)); } else { vertical_pl.trim_to_pt(hit); horiz_pl.trim_to_pt(hit); @@ -325,7 +325,7 @@ fn draw_polyline(g: &mut GfxCtx, pl: &PolyLine, thickness: f64, color: Color) { } let radius = 0.5; for pt in pts { - g.draw_ellipse(BLUE, geometry::circle(pt.x(), pt.y(), radius)); + g.draw_ellipse(BLUE, geometry::make_circle(*pt, radius)); } } diff --git a/editor/src/kml.rs b/editor/src/kml.rs index e618ba48d1..5cd19b0406 100644 --- a/editor/src/kml.rs +++ b/editor/src/kml.rs @@ -1,7 +1,7 @@ use geom::{Bounds, LonLat, PolyLine, Pt2D}; use quick_xml::events::Event; use quick_xml::reader::Reader; -use std::collections::HashMap; +use std::collections::BTreeMap; use std::fs::File; use std::{f64, fmt, io}; @@ -17,8 +17,14 @@ impl fmt::Display for ExtraShapeID { #[derive(Debug)] pub struct ExtraShape { pub id: ExtraShapeID, - pub pts: PolyLine, - pub attributes: HashMap, + pub geom: ExtraShapeGeom, + pub attributes: BTreeMap, +} + +#[derive(Debug)] +pub enum ExtraShapeGeom { + Point(Pt2D), + Points(PolyLine), } pub fn load(path: &String, gps_bounds: &Bounds) -> Result, io::Error> { @@ -33,7 +39,7 @@ pub fn load(path: &String, gps_bounds: &Bounds) -> Result, io::E // TODO uncomfortably stateful let mut shapes = Vec::new(); let mut scanned_schema = false; - let mut attributes: HashMap = HashMap::new(); + let mut attributes: BTreeMap = BTreeMap::new(); let mut attrib_key: Option = None; let mut skipped_count = 0; @@ -75,11 +81,15 @@ pub fn load(path: &String, gps_bounds: &Bounds) -> Result, io::E break; } } - if ok { + if ok && is_interesting_sign(&attributes) { let id = ExtraShapeID(shapes.len()); shapes.push(ExtraShape { id, - pts: PolyLine::new(pts), + geom: if pts.len() == 1 { + ExtraShapeGeom::Point(pts[0]) + } else { + ExtraShapeGeom::Points(PolyLine::new(pts)) + }, attributes: attributes.clone(), }); } else { @@ -126,3 +136,8 @@ fn parse_pt(input: &str, gps_bounds: &Bounds) -> Option { _ => None, }; } + +// TODO only for Street_Signs.kml; this is temporary to explore stuff +fn is_interesting_sign(attributes: &BTreeMap) -> bool { + attributes.get("CATEGORY") == Some(&"REGMIS".to_string()) +} diff --git a/editor/src/render/extra_shape.rs b/editor/src/render/extra_shape.rs index 4a1d53327f..0cfb4ef846 100644 --- a/editor/src/render/extra_shape.rs +++ b/editor/src/render/extra_shape.rs @@ -2,42 +2,70 @@ use aabb_quadtree::geom::Rect; use ezgui::GfxCtx; use geom::{Polygon, Pt2D}; use graphics::types::Color; -use kml::{ExtraShape, ExtraShapeID}; -use render::{get_bbox, EXTRA_SHAPE_THICKNESS}; -use std::collections::HashMap; +use kml::{ExtraShape, ExtraShapeGeom, ExtraShapeID}; +use map_model::geometry; +use render::{get_bbox, EXTRA_SHAPE_POINT_RADIUS, EXTRA_SHAPE_THICKNESS}; +use std::collections::BTreeMap; + +#[derive(Debug)] +enum Shape { + Polygon(Polygon), + Circle([f64; 4]), +} #[derive(Debug)] pub struct DrawExtraShape { pub id: ExtraShapeID, - polygon: Polygon, - attributes: HashMap, + shape: Shape, + attributes: BTreeMap, } impl DrawExtraShape { pub fn new(s: ExtraShape) -> DrawExtraShape { DrawExtraShape { id: s.id, - polygon: s.pts.make_polygons(EXTRA_SHAPE_THICKNESS).unwrap(), + shape: match s.geom { + ExtraShapeGeom::Point(pt) => { + Shape::Circle(geometry::make_circle(pt, EXTRA_SHAPE_POINT_RADIUS)) + } + ExtraShapeGeom::Points(pl) => { + Shape::Polygon(pl.make_polygons(EXTRA_SHAPE_THICKNESS).unwrap()) + } + }, attributes: s.attributes, } } pub fn draw(&self, g: &mut GfxCtx, color: Color) { - g.draw_polygon(color, &self.polygon); + match self.shape { + Shape::Polygon(ref p) => g.draw_polygon(color, &p), + Shape::Circle(c) => g.draw_ellipse(color, c), + } } pub fn contains_pt(&self, pt: Pt2D) -> bool { - self.polygon.contains_pt(pt) + match self.shape { + Shape::Polygon(ref p) => p.contains_pt(pt), + Shape::Circle(c) => geometry::point_in_circle(&c, pt), + } } pub fn get_bbox(&self) -> Rect { - get_bbox(&self.polygon.get_bounds()) + match self.shape { + Shape::Polygon(ref p) => get_bbox(&p.get_bounds()), + Shape::Circle(c) => geometry::circle_to_bbox(&c), + } } pub fn tooltip_lines(&self) -> Vec { let mut lines = Vec::new(); for (k, v) in &self.attributes { - lines.push(format!("{} = {}", k, v)); + // Make interesting atributes easier to spot + if k == "TEXT" { + lines.push(format!("*** {} = {}", k, v)); + } else { + lines.push(format!("{} = {}", k, v)); + } } lines } diff --git a/editor/src/render/intersection.rs b/editor/src/render/intersection.rs index 2562d67b33..b6ce09021e 100644 --- a/editor/src/render/intersection.rs +++ b/editor/src/render/intersection.rs @@ -111,17 +111,17 @@ impl DrawIntersection { g.draw_ellipse( cs.get(Colors::TrafficSignalYellow), - geometry::circle(self.center.x(), self.center.y(), radius), + geometry::make_circle(self.center, radius), ); g.draw_ellipse( cs.get(Colors::TrafficSignalGreen), - geometry::circle(self.center.x(), self.center.y() + (radius * 2.0), radius), + geometry::make_circle(self.center.offset(0.0, radius * 2.0), radius), ); g.draw_ellipse( cs.get(Colors::TrafficSignalRed), - geometry::circle(self.center.x(), self.center.y() - (radius * 2.0), radius), + geometry::make_circle(self.center.offset(0.0, radius * -2.0), radius), ); } } diff --git a/editor/src/render/lane.rs b/editor/src/render/lane.rs index b76555a8da..0ce61b3c89 100644 --- a/editor/src/render/lane.rs +++ b/editor/src/render/lane.rs @@ -108,8 +108,8 @@ impl DrawLane { for pair in l.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_ellipse(circle_color, geometry::circle(pt1.x(), pt1.y(), 0.4)); - g.draw_ellipse(circle_color, geometry::circle(pt2.x(), pt2.y(), 0.8)); + g.draw_ellipse(circle_color, geometry::make_circle(pt1, 0.4)); + g.draw_ellipse(circle_color, geometry::make_circle(pt2, 0.8)); } } diff --git a/editor/src/render/mod.rs b/editor/src/render/mod.rs index dd651a2009..9c3f893738 100644 --- a/editor/src/render/mod.rs +++ b/editor/src/render/mod.rs @@ -20,6 +20,7 @@ use std::f64; const PARCEL_BOUNDARY_THICKNESS: f64 = 0.5; const BUILDING_BOUNDARY_THICKNESS: f64 = 1.5; const EXTRA_SHAPE_THICKNESS: f64 = 1.0; +const EXTRA_SHAPE_POINT_RADIUS: f64 = 1.0; const TURN_ICON_ARROW_THICKNESS: f64 = geometry::BIG_ARROW_THICKNESS / 3.0; const BIG_ARROW_TIP_LENGTH: f64 = 1.0; diff --git a/editor/src/render/turn.rs b/editor/src/render/turn.rs index 5bbdc2ab97..66cceae6a6 100644 --- a/editor/src/render/turn.rs +++ b/editor/src/render/turn.rs @@ -45,11 +45,7 @@ impl DrawTurn { .project_away(TURN_ICON_ARROW_LENGTH / 2.0, angle) .to_vec(); - let icon_circle = geometry::circle( - icon_center.x(), - icon_center.y(), - TURN_ICON_ARROW_LENGTH / 2.0, - ); + 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]]; @@ -87,12 +83,6 @@ impl DrawTurn { // for the icon pub fn contains_pt(&self, pt: Pt2D) -> bool { - let radius = self.icon_circle[2] / 2.0; - geometry::point_in_circle( - pt.x(), - pt.y(), - [self.icon_circle[0] + radius, self.icon_circle[1] + radius], - radius, - ) + geometry::point_in_circle(&self.icon_circle, pt) } } diff --git a/editor/src/ui.rs b/editor/src/ui.rs index 15a0747ab2..972beebf89 100644 --- a/editor/src/ui.rs +++ b/editor/src/ui.rs @@ -183,6 +183,16 @@ impl UI { let screen_bbox = self.canvas.get_screen_bbox(); + if self.show_extra_shapes.is_enabled() { + for s in &self.draw_map + .get_extra_shapes_onscreen(screen_bbox, &self.hider) + { + if s.contains_pt(pt) { + return Some(ID::ExtraShape(s.id)); + } + } + } + let lanes_onscreen = if self.show_lanes.is_enabled() { self.draw_map.get_loads_onscreen(screen_bbox, &self.hider) } else { @@ -230,16 +240,6 @@ impl UI { } } - if self.show_extra_shapes.is_enabled() { - for s in &self.draw_map - .get_extra_shapes_onscreen(screen_bbox, &self.hider) - { - if s.contains_pt(pt) { - return Some(ID::ExtraShape(s.id)); - } - } - } - if self.show_lanes.is_enabled() { for l in &lanes_onscreen { if l.contains_pt(pt) { diff --git a/geom/src/pt.rs b/geom/src/pt.rs index bacaa624bc..d0f07f230b 100644 --- a/geom/src/pt.rs +++ b/geom/src/pt.rs @@ -73,6 +73,10 @@ impl Pt2D { // DON'T invert y here Angle::new((to.y() - self.y()).atan2(to.x() - self.x())) } + + pub fn offset(&self, dx: f64, dy: f64) -> Pt2D { + Pt2D::new(self.x() + dx, self.y() + dy) + } } impl fmt::Display for Pt2D { diff --git a/map_model/Cargo.toml b/map_model/Cargo.toml index 2c18fe2797..49e85282d5 100644 --- a/map_model/Cargo.toml +++ b/map_model/Cargo.toml @@ -10,7 +10,6 @@ dimensioned = { git = "https://github.com/paholg/dimensioned", rev = "0e1076ebfa geo = "0.9.1" geom = { path = "../geom" } ordered-float = "0.5.0" -piston2d-graphics = "*" pretty_assertions = "0.5.1" serde = "1.0" serde_derive = "1.0" diff --git a/map_model/src/geometry.rs b/map_model/src/geometry.rs index 1c753b6e71..5009fdf2c1 100644 --- a/map_model/src/geometry.rs +++ b/map_model/src/geometry.rs @@ -2,7 +2,6 @@ use aabb_quadtree::geom::{Point, Rect}; use geom::{Angle, PolyLine, Polygon, Pt2D}; -use graphics::math::Vec2d; use std::f64; pub const LANE_THICKNESS: f64 = 2.5; @@ -14,15 +13,22 @@ pub fn thick_line_from_angle(thickness: f64, line_length: f64, pt: Pt2D, angle: PolyLine::new(vec![pt, pt2]).make_polygons_blindly(thickness) } -pub fn point_in_circle(x: f64, y: f64, center: Vec2d, radius: f64) -> bool { - // avoid sqrt by squaring radius instead - (x - center[0]).powi(2) + (y - center[1]).powi(2) < radius.powi(2) +pub fn center_of_circle(c: &[f64; 4]) -> Pt2D { + let radius = c[2] / 2.0; + Pt2D::new(c[0] + radius, c[1] + radius) } -pub fn circle(center_x: f64, center_y: f64, radius: f64) -> [f64; 4] { +pub fn point_in_circle(c: &[f64; 4], pt: Pt2D) -> bool { + let radius = c[2] / 2.0; + let center = center_of_circle(c); + // avoid sqrt by squaring radius instead + (pt.x() - center.x()).powi(2) + (pt.y() - center.y()).powi(2) < radius.powi(2) +} + +pub fn make_circle(center: Pt2D, radius: f64) -> [f64; 4] { [ - center_x - radius, - center_y - radius, + center.x() - radius, + center.y() - radius, 2.0 * radius, 2.0 * radius, ] diff --git a/map_model/src/lib.rs b/map_model/src/lib.rs index 3f2b2840d3..36f435deb1 100644 --- a/map_model/src/lib.rs +++ b/map_model/src/lib.rs @@ -3,7 +3,6 @@ extern crate abstutil; extern crate dimensioned; extern crate geo; extern crate geom; -extern crate graphics; extern crate ordered_float; #[macro_use] extern crate pretty_assertions; diff --git a/sim/src/draw_ped.rs b/sim/src/draw_ped.rs index 4e98b3d028..b248df0213 100644 --- a/sim/src/draw_ped.rs +++ b/sim/src/draw_ped.rs @@ -26,7 +26,7 @@ impl DrawPedestrian { DrawPedestrian { id, - circle: geometry::circle(pos.x(), pos.y(), RADIUS), + circle: geometry::make_circle(pos, RADIUS), turn_arrow, } } @@ -45,16 +45,10 @@ impl DrawPedestrian { } pub fn contains_pt(&self, pt: Pt2D) -> bool { - geometry::point_in_circle( - pt.x(), - pt.y(), - [self.circle[0] + RADIUS, self.circle[1] + RADIUS], - RADIUS, - ) + geometry::point_in_circle(&self.circle, pt) } pub fn focus_pt(&self) -> Pt2D { - let radius = self.circle[2] / 2.0; - Pt2D::new(self.circle[0] + radius, self.circle[1] + radius) + geometry::center_of_circle(&self.circle) } }