From c2473828a615a1fdeff765646e9adbb890cb2ee7 Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Wed, 20 Jun 2018 12:51:11 -0700 Subject: [PATCH] finding paths between buildings and nearest sidewalk --- TODO.md | 14 +++--- editor/Cargo.toml | 1 + editor/src/main.rs | 1 + editor/src/plugins/selection.rs | 1 + editor/src/render/building.rs | 78 +++++++++++++++++++++++++++++++++ editor/src/render/parcel.rs | 6 +-- map_model/src/lib.rs | 4 ++ 7 files changed, 97 insertions(+), 8 deletions(-) diff --git a/TODO.md b/TODO.md index 3aa8ee53de..2151c82c22 100644 --- a/TODO.md +++ b/TODO.md @@ -45,17 +45,20 @@ - https://gis-kingcounty.opendata.arcgis.com/datasets/traffic-signs--sign-point/ - multiple lanes - - model cars parking - - maybe render numbers on the cars to distinguish them - - document the FSM (on lane driving, waiting, turning, parking, etc) + - always draw building to sidewalk paths + - move colors to config, have interactive picker + - model bikes in driving lanes (as slow cars) - add random bike lanes, figure out how turns would work - be able to convert between parking and bike lanes, recompute the turns + + - model cars parking + - maybe render numbers on the cars to distinguish them + - document the FSM (on lane driving, waiting, turning, parking, etc) + - model pdestrians - maybe draw crosswalks? - - when rendering sidewalks, have an option for a grass buffer - - regression testing - goldenfile approach for map_model, geom, and render layer from a small OSM chunk - or maybe a visual demo approach with a list of things to manually check @@ -63,6 +66,7 @@ ## Code cleanup +- where does 'extern crate' belong? only in main / mod? - clean up code - master Map struct - line type / ditch vec2d / settle on types diff --git a/editor/Cargo.toml b/editor/Cargo.toml index 06bf672d08..5dec4bde7a 100644 --- a/editor/Cargo.toml +++ b/editor/Cargo.toml @@ -6,6 +6,7 @@ authors = ["Dustin Carlino "] [dependencies] aabb-quadtree = "0.1.0" control = { path = "../control" } +geo = "0.9.1" geom = { path = "../geom" } ezgui = { path = "../ezgui" } map_model = { path = "../map_model" } diff --git a/editor/src/main.rs b/editor/src/main.rs index 6653d41250..5162aeff20 100644 --- a/editor/src/main.rs +++ b/editor/src/main.rs @@ -3,6 +3,7 @@ extern crate aabb_quadtree; extern crate control; extern crate ezgui; +extern crate geo; extern crate geom; extern crate glutin_window; extern crate graphics; diff --git a/editor/src/plugins/selection.rs b/editor/src/plugins/selection.rs index 7db5269c61..492c452fc8 100644 --- a/editor/src/plugins/selection.rs +++ b/editor/src/plugins/selection.rs @@ -182,6 +182,7 @@ impl SelectionState { } SelectionState::SelectedBuilding(id) => { canvas.draw_mouse_tooltip(g, &draw_map.get_b(id).tooltip_lines(map)); + draw_map.get_b(id).draw_sidewalk_path(g, map, geom_map); } SelectionState::SelectedCar(id) => { canvas.draw_mouse_tooltip(g, &sim.car_tooltip(id)); diff --git a/editor/src/render/building.rs b/editor/src/render/building.rs index 3a2f52b119..5893095c1e 100644 --- a/editor/src/render/building.rs +++ b/editor/src/render/building.rs @@ -1,15 +1,19 @@ // Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0 extern crate aabb_quadtree; +extern crate geo; extern crate map_model; use aabb_quadtree::geom::Rect; use ezgui::canvas::GfxCtx; +use geom::GeomMap; use geom::geometry; use graphics; use graphics::math::Vec2d; use graphics::types::Color; use map_model::{Bounds, BuildingID}; +use ordered_float::NotNaN; +use render; use std::f64; #[derive(Debug)] @@ -54,4 +58,78 @@ impl DrawBuilding { pub fn get_bbox(&self) -> Rect { geometry::get_bbox_for_polygons(&[self.polygon.clone()]) } + + // TODO compute these once, and draw them always + // TODO ideally start the path on a side of the building + pub fn draw_sidewalk_path(&self, g: &mut GfxCtx, map: &map_model::Map, geom_map: &GeomMap) { + use geo::prelude::{ClosestPoint, EuclideanDistance}; + + if let Some(tag) = map.get_b(self.id) + .osm_tags + .iter() + .find(|kv| kv.starts_with("addr:street=")) + { + let (_, street_name) = tag.split_at("addr:street=".len()); + + let bldg_center = self.center(); + let center_pt = geo::Point::new(bldg_center[0], bldg_center[1]); + + // Find all matching sidewalks with that street name, then find the closest point on + // that sidewalk + let candidates: Vec<(map_model::RoadID, geo::Point)> = map.all_roads() + .iter() + .filter_map(|r| { + if r.lane_type == map_model::LaneType::Sidewalk + && map_model::has_osm_tag(&r.osm_tags, "name", street_name) + { + if let geo::Closest::SinglePoint(pt) = + road_to_line_string(r.id, geom_map).closest_point(¢er_pt) + { + return Some((r.id, pt)); + } + } + None + }) + .collect(); + + if let Some(closest) = candidates + .iter() + .min_by_key(|pair| NotNaN::new(pair.1.euclidean_distance(¢er_pt)).unwrap()) + { + let path = graphics::Line::new_round(render::DEBUG_COLOR, 1.0); + path.draw( + [center_pt.x(), center_pt.y(), closest.1.x(), closest.1.y()], + &g.ctx.draw_state, + g.ctx.transform, + g.gfx, + ); + } + } + } + + fn center(&self) -> Vec2d { + let mut x = 0.0; + let mut y = 0.0; + for pt in &self.polygon { + x += pt[0]; + y += pt[1]; + } + let len = self.polygon.len() as f64; + [x / len, y / len] + } +} + +fn road_to_line_string(r: map_model::RoadID, geom_map: &GeomMap) -> geo::LineString { + let pts: Vec> = geom_map + .get_r(r) + .lane_center_lines + .iter() + .flat_map(|pair| { + vec![ + geo::Point::new(pair.0.x(), pair.0.y()), + geo::Point::new(pair.1.x(), pair.1.y()), + ] + }) + .collect(); + pts.into() } diff --git a/editor/src/render/parcel.rs b/editor/src/render/parcel.rs index 864a0e12f4..1c2f039f31 100644 --- a/editor/src/render/parcel.rs +++ b/editor/src/render/parcel.rs @@ -35,18 +35,18 @@ impl DrawParcel { } } - pub fn draw(&self, g: &mut GfxCtx, (boundary_color, fill_color): (Color, Color)) { + pub fn draw(&self, g: &mut GfxCtx, (boundary_color, _fill_color): (Color, Color)) { let boundary_poly = graphics::Polygon::new(boundary_color); for p in &self.boundary_polygons { boundary_poly.draw(p, &g.ctx.draw_state, g.ctx.transform, g.gfx); } - let fill_poly = graphics::Polygon::new(fill_color); + /*let fill_poly = graphics::Polygon::new(fill_color); fill_poly.draw( &self.fill_polygon, &g.ctx.draw_state, g.ctx.transform, g.gfx, - ); + );*/ } //pub fn contains_pt(&self, x: f64, y: f64) -> bool {} diff --git a/map_model/src/lib.rs b/map_model/src/lib.rs index 724c8f487b..6eb769607b 100644 --- a/map_model/src/lib.rs +++ b/map_model/src/lib.rs @@ -505,3 +505,7 @@ impl Map { b } } + +pub fn has_osm_tag(tags: &Vec, key: &str, value: &str) -> bool { + tags.contains(&format!("{}={}", key, value)) +}