mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-25 15:33:44 +03:00
render individual points from extra KML, and refactor some circle helpers
This commit is contained in:
parent
f141329e85
commit
f36c94c730
@ -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
|
||||
|
5
docs/references.md
Normal file
5
docs/references.md
Normal file
@ -0,0 +1,5 @@
|
||||
# References
|
||||
|
||||
## Groups that may be eventually interested
|
||||
|
||||
- Seattle Times Traffic Lab
|
@ -175,9 +175,9 @@
|
||||
1.0
|
||||
],
|
||||
"ExtraShape": [
|
||||
0.0,
|
||||
1.0,
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0
|
||||
],
|
||||
"MatchClassification": [
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<String, String>,
|
||||
pub geom: ExtraShapeGeom,
|
||||
pub attributes: BTreeMap<String, String>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ExtraShapeGeom {
|
||||
Point(Pt2D),
|
||||
Points(PolyLine),
|
||||
}
|
||||
|
||||
pub fn load(path: &String, gps_bounds: &Bounds) -> Result<Vec<ExtraShape>, io::Error> {
|
||||
@ -33,7 +39,7 @@ pub fn load(path: &String, gps_bounds: &Bounds) -> Result<Vec<ExtraShape>, io::E
|
||||
// TODO uncomfortably stateful
|
||||
let mut shapes = Vec::new();
|
||||
let mut scanned_schema = false;
|
||||
let mut attributes: HashMap<String, String> = HashMap::new();
|
||||
let mut attributes: BTreeMap<String, String> = BTreeMap::new();
|
||||
let mut attrib_key: Option<String> = None;
|
||||
|
||||
let mut skipped_count = 0;
|
||||
@ -75,11 +81,15 @@ pub fn load(path: &String, gps_bounds: &Bounds) -> Result<Vec<ExtraShape>, 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<Pt2D> {
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
|
||||
// TODO only for Street_Signs.kml; this is temporary to explore stuff
|
||||
fn is_interesting_sign(attributes: &BTreeMap<String, String>) -> bool {
|
||||
attributes.get("CATEGORY") == Some(&"REGMIS".to_string())
|
||||
}
|
||||
|
@ -2,43 +2,71 @@ 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<String, String>,
|
||||
shape: Shape,
|
||||
attributes: BTreeMap<String, String>,
|
||||
}
|
||||
|
||||
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<String> {
|
||||
let mut lines = Vec::new();
|
||||
for (k, v) in &self.attributes {
|
||||
// Make interesting atributes easier to spot
|
||||
if k == "TEXT" {
|
||||
lines.push(format!("*** {} = {}", k, v));
|
||||
} else {
|
||||
lines.push(format!("{} = {}", k, v));
|
||||
}
|
||||
}
|
||||
lines
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
|
@ -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"
|
||||
|
@ -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,
|
||||
]
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user