mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-28 12:12:00 +03:00
making a proper polygon type, finally. using it in a few places, not all
yet
This commit is contained in:
parent
5d2a4f3ac4
commit
1b610aa708
@ -1,8 +1,7 @@
|
|||||||
use ezgui::canvas::Canvas;
|
use ezgui::canvas::Canvas;
|
||||||
use ezgui::input::UserInput;
|
use ezgui::input::UserInput;
|
||||||
use ezgui::GfxCtx;
|
use ezgui::GfxCtx;
|
||||||
use geom;
|
use geom::{PolyLine, Polygon, Pt2D};
|
||||||
use geom::{PolyLine, Pt2D};
|
|
||||||
use graphics;
|
use graphics;
|
||||||
use graphics::types::Color;
|
use graphics::types::Color;
|
||||||
use gui;
|
use gui;
|
||||||
@ -307,7 +306,7 @@ impl UI {
|
|||||||
Pt2D::new(947.7612927256201, 765.1100512564725), // 5
|
Pt2D::new(947.7612927256201, 765.1100512564725), // 5
|
||||||
];
|
];
|
||||||
//draw_polyline(g, &PolyLine::new(pts.clone()), 0.25, RED);
|
//draw_polyline(g, &PolyLine::new(pts.clone()), 0.25, RED);
|
||||||
for tri in geom::triangulate(&pts).iter() {
|
for tri in Polygon::new(&pts).for_drawing().iter() {
|
||||||
g.draw_polygon(BLUE, tri);
|
g.draw_polygon(BLUE, tri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ use ezgui::input::UserInput;
|
|||||||
use generator;
|
use generator;
|
||||||
use geo;
|
use geo;
|
||||||
use geo::prelude::Intersects;
|
use geo::prelude::Intersects;
|
||||||
use geom::Pt2D;
|
use geom::{Polygon, Pt2D};
|
||||||
use graphics::math::Vec2d;
|
use graphics::math::Vec2d;
|
||||||
use map_model::{geometry, BuildingID, IntersectionID, LaneID, Map, ParcelID};
|
use map_model::{geometry, BuildingID, IntersectionID, LaneID, Map, ParcelID};
|
||||||
use piston::input::Key;
|
use piston::input::Key;
|
||||||
@ -42,13 +42,13 @@ impl Validator {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
for i in &draw_map.intersections {
|
for i in &draw_map.intersections {
|
||||||
objects.push((ID::Intersection(i.id), vec![make_poly(&i.polygon)]));
|
objects.push((ID::Intersection(i.id), vec![make_new_poly(&i.polygon)]));
|
||||||
}
|
}
|
||||||
for b in &draw_map.buildings {
|
for b in &draw_map.buildings {
|
||||||
objects.push((ID::Building(b.id), vec![make_poly(&b.fill_polygon)]));
|
objects.push((ID::Building(b.id), vec![make_new_poly(&b.fill_polygon)]));
|
||||||
}
|
}
|
||||||
for p in &draw_map.parcels {
|
for p in &draw_map.parcels {
|
||||||
objects.push((ID::Parcel(p.id), vec![make_poly(&p.fill_polygon)]));
|
objects.push((ID::Parcel(p.id), vec![make_new_poly(&p.fill_polygon)]));
|
||||||
}
|
}
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
@ -139,6 +139,14 @@ fn make_poly(points: &Vec<Vec2d>) -> geo::Polygon<f64> {
|
|||||||
geo::Polygon::new(exterior.into(), Vec::new())
|
geo::Polygon::new(exterior.into(), Vec::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_new_poly(p: &Polygon) -> geo::Polygon<f64> {
|
||||||
|
let exterior: Vec<geo::Point<f64>> = p.pts
|
||||||
|
.iter()
|
||||||
|
.map(|pt| geo::Point::new(pt.x(), pt.y()))
|
||||||
|
.collect();
|
||||||
|
geo::Polygon::new(exterior.into(), Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
// TODO duplicated with warp. generic handling of object types?
|
// TODO duplicated with warp. generic handling of object types?
|
||||||
fn get_pt(map: &Map, id: ID) -> Pt2D {
|
fn get_pt(map: &Map, id: ID) -> Pt2D {
|
||||||
match id {
|
match id {
|
||||||
|
@ -2,15 +2,12 @@
|
|||||||
|
|
||||||
use aabb_quadtree::geom::Rect;
|
use aabb_quadtree::geom::Rect;
|
||||||
use ezgui::GfxCtx;
|
use ezgui::GfxCtx;
|
||||||
use geom;
|
use geom::{PolyLine, Polygon, Pt2D};
|
||||||
use geom::PolyLine;
|
|
||||||
use graphics;
|
use graphics;
|
||||||
use graphics::math::Vec2d;
|
use graphics::math::Vec2d;
|
||||||
use graphics::types::Color;
|
use graphics::types::Color;
|
||||||
use map_model;
|
use map_model::{Building, BuildingID, Map};
|
||||||
use map_model::geometry;
|
use render::{get_bbox, PARCEL_BOUNDARY_THICKNESS};
|
||||||
use map_model::{BuildingID, Map};
|
|
||||||
use render::PARCEL_BOUNDARY_THICKNESS;
|
|
||||||
use std::f64;
|
use std::f64;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -18,22 +15,19 @@ pub struct DrawBuilding {
|
|||||||
pub id: BuildingID,
|
pub id: BuildingID,
|
||||||
// TODO should just have one. use graphics::Line for now.
|
// TODO should just have one. use graphics::Line for now.
|
||||||
boundary_polygons: Vec<Vec<Vec2d>>,
|
boundary_polygons: Vec<Vec<Vec2d>>,
|
||||||
// TODO rm the other one
|
pub fill_polygon: Polygon,
|
||||||
pub fill_polygon: Vec<Vec2d>,
|
|
||||||
fill_triangles: Vec<Vec<Vec2d>>,
|
|
||||||
front_path: Option<[f64; 4]>,
|
front_path: Option<[f64; 4]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DrawBuilding {
|
impl DrawBuilding {
|
||||||
pub fn new(bldg: &map_model::Building) -> DrawBuilding {
|
pub fn new(bldg: &Building) -> DrawBuilding {
|
||||||
DrawBuilding {
|
DrawBuilding {
|
||||||
id: bldg.id,
|
id: bldg.id,
|
||||||
fill_polygon: bldg.points.iter().map(|pt| [pt.x(), pt.y()]).collect(),
|
|
||||||
// TODO ideally start the path on a side of the building
|
// TODO ideally start the path on a side of the building
|
||||||
front_path: bldg.front_path
|
front_path: bldg.front_path
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|l| [l.pt1().x(), l.pt1().y(), l.pt2().x(), l.pt2().y()]),
|
.map(|l| [l.pt1().x(), l.pt1().y(), l.pt2().x(), l.pt2().y()]),
|
||||||
fill_triangles: geom::triangulate(&bldg.points),
|
fill_polygon: Polygon::new(&bldg.points),
|
||||||
boundary_polygons: PolyLine::new(bldg.points.clone())
|
boundary_polygons: PolyLine::new(bldg.points.clone())
|
||||||
.make_polygons_blindly(PARCEL_BOUNDARY_THICKNESS),
|
.make_polygons_blindly(PARCEL_BOUNDARY_THICKNESS),
|
||||||
}
|
}
|
||||||
@ -54,13 +48,13 @@ impl DrawBuilding {
|
|||||||
for p in &self.boundary_polygons {
|
for p in &self.boundary_polygons {
|
||||||
g.draw_polygon(boundary_color, p);
|
g.draw_polygon(boundary_color, p);
|
||||||
}
|
}
|
||||||
for p in &self.fill_triangles {
|
for p in &self.fill_polygon.for_drawing() {
|
||||||
g.draw_polygon(fill_color, p);
|
g.draw_polygon(fill_color, p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn contains_pt(&self, x: f64, y: f64) -> bool {
|
pub fn contains_pt(&self, x: f64, y: f64) -> bool {
|
||||||
geometry::point_in_polygon(x, y, &self.fill_polygon)
|
self.fill_polygon.contains_pt(Pt2D::new(x, y))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tooltip_lines(&self, map: &Map) -> Vec<String> {
|
pub fn tooltip_lines(&self, map: &Map) -> Vec<String> {
|
||||||
@ -76,10 +70,11 @@ impl DrawBuilding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_bbox(&self) -> Rect {
|
pub fn get_bbox(&self) -> Rect {
|
||||||
let mut polygons = vec![self.fill_polygon.clone()];
|
let mut b = self.fill_polygon.get_bounds();
|
||||||
if let Some(line) = self.front_path {
|
if let Some(line) = self.front_path {
|
||||||
polygons.push(vec![[line[0], line[1]], [line[2], line[3]]]);
|
b.update(line[0], line[1]);
|
||||||
|
b.update(line[2], line[3]);
|
||||||
}
|
}
|
||||||
geometry::get_bbox_for_polygons(&polygons)
|
get_bbox(&b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,19 +4,19 @@ use aabb_quadtree::geom::Rect;
|
|||||||
use colors::{ColorScheme, Colors};
|
use colors::{ColorScheme, Colors};
|
||||||
use dimensioned::si;
|
use dimensioned::si;
|
||||||
use ezgui::GfxCtx;
|
use ezgui::GfxCtx;
|
||||||
use geom::{Line, Pt2D};
|
use geom::{Line, Polygon, Pt2D};
|
||||||
use graphics;
|
use graphics;
|
||||||
use graphics::math::Vec2d;
|
use graphics::math::Vec2d;
|
||||||
use graphics::types::Color;
|
use graphics::types::Color;
|
||||||
use map_model;
|
use map_model;
|
||||||
use map_model::geometry;
|
use map_model::geometry;
|
||||||
use render::DrawLane;
|
use render::{get_bbox, DrawLane};
|
||||||
use std::f64;
|
use std::f64;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DrawIntersection {
|
pub struct DrawIntersection {
|
||||||
pub id: map_model::IntersectionID,
|
pub id: map_model::IntersectionID,
|
||||||
pub polygon: Vec<Vec2d>,
|
pub polygon: Polygon,
|
||||||
crosswalks: Vec<Vec<(Vec2d, Vec2d)>>,
|
crosswalks: Vec<Vec<(Vec2d, Vec2d)>>,
|
||||||
center: Pt2D,
|
center: Pt2D,
|
||||||
has_traffic_signal: bool,
|
has_traffic_signal: bool,
|
||||||
@ -28,39 +28,37 @@ impl DrawIntersection {
|
|||||||
map: &map_model::Map,
|
map: &map_model::Map,
|
||||||
lanes: &Vec<DrawLane>,
|
lanes: &Vec<DrawLane>,
|
||||||
) -> DrawIntersection {
|
) -> DrawIntersection {
|
||||||
let mut pts: Vec<Vec2d> = Vec::new();
|
let mut pts: Vec<Pt2D> = Vec::new();
|
||||||
for l in &inter.incoming_lanes {
|
for l in &inter.incoming_lanes {
|
||||||
let (pt1, pt2) = lanes[l.0].get_end_crossing();
|
let line = lanes[l.0].get_end_crossing();
|
||||||
pts.push(pt1);
|
pts.push(line.pt1());
|
||||||
pts.push(pt2);
|
pts.push(line.pt2());
|
||||||
}
|
}
|
||||||
for l in &inter.outgoing_lanes {
|
for l in &inter.outgoing_lanes {
|
||||||
let (pt1, pt2) = lanes[l.0].get_start_crossing();
|
let line = lanes[l.0].get_start_crossing();
|
||||||
pts.push(pt1);
|
pts.push(line.pt1());
|
||||||
pts.push(pt2);
|
pts.push(line.pt2());
|
||||||
}
|
}
|
||||||
|
|
||||||
let center = geometry::center(&pts.iter().map(|pt| Pt2D::new(pt[0], pt[1])).collect());
|
let center = geometry::center(&pts);
|
||||||
// Sort points by angle from the center
|
// Sort points by angle from the center
|
||||||
pts.sort_by_key(|pt| {
|
pts.sort_by_key(|pt| center.angle_to(*pt).normalized_degrees() as i64);
|
||||||
center
|
|
||||||
.angle_to(Pt2D::new(pt[0], pt[1]))
|
|
||||||
.normalized_degrees() as i64
|
|
||||||
});
|
|
||||||
let first_pt = pts[0].clone();
|
let first_pt = pts[0].clone();
|
||||||
pts.push(first_pt);
|
pts.push(first_pt);
|
||||||
|
|
||||||
DrawIntersection {
|
DrawIntersection {
|
||||||
center,
|
center,
|
||||||
id: inter.id,
|
id: inter.id,
|
||||||
polygon: pts,
|
polygon: Polygon::new(&pts),
|
||||||
crosswalks: calculate_crosswalks(inter, map),
|
crosswalks: calculate_crosswalks(inter, map),
|
||||||
has_traffic_signal: inter.has_traffic_signal,
|
has_traffic_signal: inter.has_traffic_signal,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(&self, g: &mut GfxCtx, color: Color, cs: &ColorScheme) {
|
pub fn draw(&self, g: &mut GfxCtx, color: Color, cs: &ColorScheme) {
|
||||||
g.draw_polygon(color, &self.polygon);
|
for p in &self.polygon.for_drawing() {
|
||||||
|
g.draw_polygon(color, p);
|
||||||
|
}
|
||||||
|
|
||||||
let crosswalk_marking = graphics::Line::new(
|
let crosswalk_marking = graphics::Line::new(
|
||||||
cs.get(Colors::Crosswalk),
|
cs.get(Colors::Crosswalk),
|
||||||
@ -84,11 +82,11 @@ impl DrawIntersection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn contains_pt(&self, x: f64, y: f64) -> bool {
|
pub fn contains_pt(&self, x: f64, y: f64) -> bool {
|
||||||
geometry::point_in_polygon(x, y, &self.polygon)
|
self.polygon.contains_pt(Pt2D::new(x, y))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_bbox(&self) -> Rect {
|
pub fn get_bbox(&self) -> Rect {
|
||||||
geometry::get_bbox_for_polygons(&[self.polygon.clone()])
|
get_bbox(&self.polygon.get_bounds())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_stop_sign(&self, g: &mut GfxCtx, cs: &ColorScheme) {
|
fn draw_stop_sign(&self, g: &mut GfxCtx, cs: &ColorScheme) {
|
||||||
|
@ -25,8 +25,8 @@ struct Marking {
|
|||||||
pub struct DrawLane {
|
pub struct DrawLane {
|
||||||
pub id: LaneID,
|
pub id: LaneID,
|
||||||
pub polygons: Vec<Vec<Vec2d>>,
|
pub polygons: Vec<Vec<Vec2d>>,
|
||||||
start_crossing: (Vec2d, Vec2d),
|
start_crossing: Line,
|
||||||
end_crossing: (Vec2d, Vec2d),
|
end_crossing: Line,
|
||||||
markings: Vec<Marking>,
|
markings: Vec<Marking>,
|
||||||
|
|
||||||
// TODO pretty temporary
|
// TODO pretty temporary
|
||||||
@ -36,9 +36,8 @@ pub struct DrawLane {
|
|||||||
impl DrawLane {
|
impl DrawLane {
|
||||||
pub fn new(lane: &map_model::Lane, map: &map_model::Map) -> DrawLane {
|
pub fn new(lane: &map_model::Lane, map: &map_model::Map) -> DrawLane {
|
||||||
let road = map.get_r(lane.parent);
|
let road = map.get_r(lane.parent);
|
||||||
let start = perp_line(lane.first_line(), geometry::LANE_THICKNESS);
|
let start = new_perp_line(lane.first_line(), geometry::LANE_THICKNESS);
|
||||||
let end = perp_line(lane.last_line().reverse(), geometry::LANE_THICKNESS);
|
let end = new_perp_line(lane.last_line().reverse(), geometry::LANE_THICKNESS);
|
||||||
|
|
||||||
let polygons = lane.lane_center_pts
|
let polygons = lane.lane_center_pts
|
||||||
.make_polygons_blindly(geometry::LANE_THICKNESS);
|
.make_polygons_blindly(geometry::LANE_THICKNESS);
|
||||||
|
|
||||||
@ -76,8 +75,8 @@ impl DrawLane {
|
|||||||
id: lane.id,
|
id: lane.id,
|
||||||
polygons,
|
polygons,
|
||||||
markings,
|
markings,
|
||||||
start_crossing: ([start[0], start[1]], [start[2], start[3]]),
|
start_crossing: start,
|
||||||
end_crossing: ([end[0], end[1]], [end[2], end[3]]),
|
end_crossing: end,
|
||||||
draw_id_at: calculate_id_positions(lane).unwrap_or(Vec::new()),
|
draw_id_at: calculate_id_positions(lane).unwrap_or(Vec::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -161,12 +160,12 @@ impl DrawLane {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the line marking the end of the lane, perpendicular to the direction of the lane
|
// Get the line marking the end of the lane, perpendicular to the direction of the lane
|
||||||
pub(crate) fn get_end_crossing(&self) -> (Vec2d, Vec2d) {
|
pub(crate) fn get_end_crossing(&self) -> &Line {
|
||||||
self.end_crossing
|
&self.end_crossing
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_start_crossing(&self) -> (Vec2d, Vec2d) {
|
pub(crate) fn get_start_crossing(&self) -> &Line {
|
||||||
self.start_crossing
|
&self.start_crossing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,6 +177,12 @@ fn perp_line(l: Line, length: f64) -> [f64; 4] {
|
|||||||
[pt1.x(), pt1.y(), pt2.x(), pt2.y()]
|
[pt1.x(), pt1.y(), pt2.x(), pt2.y()]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_perp_line(l: Line, length: f64) -> Line {
|
||||||
|
let pt1 = l.shift(length / 2.0).pt1();
|
||||||
|
let pt2 = l.reverse().shift(length / 2.0).pt2();
|
||||||
|
Line::new(pt1, pt2)
|
||||||
|
}
|
||||||
|
|
||||||
fn calculate_sidewalk_lines(lane: &map_model::Lane) -> Marking {
|
fn calculate_sidewalk_lines(lane: &map_model::Lane) -> Marking {
|
||||||
let tile_every = geometry::LANE_THICKNESS * si::M;
|
let tile_every = geometry::LANE_THICKNESS * si::M;
|
||||||
|
|
||||||
|
@ -7,6 +7,8 @@ mod map;
|
|||||||
mod parcel;
|
mod parcel;
|
||||||
mod turn;
|
mod turn;
|
||||||
|
|
||||||
|
use aabb_quadtree::geom::{Point, Rect};
|
||||||
|
use geom::Bounds;
|
||||||
use map_model::geometry;
|
use map_model::geometry;
|
||||||
pub use render::lane::DrawLane;
|
pub use render::lane::DrawLane;
|
||||||
pub use render::map::DrawMap;
|
pub use render::map::DrawMap;
|
||||||
@ -20,3 +22,16 @@ const TURN_ICON_ARROW_THICKNESS: f64 = geometry::BIG_ARROW_THICKNESS / 3.0;
|
|||||||
const BIG_ARROW_TIP_LENGTH: f64 = 1.0;
|
const BIG_ARROW_TIP_LENGTH: f64 = 1.0;
|
||||||
const TURN_ICON_ARROW_TIP_LENGTH: f64 = BIG_ARROW_TIP_LENGTH * 0.8;
|
const TURN_ICON_ARROW_TIP_LENGTH: f64 = BIG_ARROW_TIP_LENGTH * 0.8;
|
||||||
const TURN_ICON_ARROW_LENGTH: f64 = 2.0;
|
const TURN_ICON_ARROW_LENGTH: f64 = 2.0;
|
||||||
|
|
||||||
|
pub fn get_bbox(b: &Bounds) -> Rect {
|
||||||
|
Rect {
|
||||||
|
top_left: Point {
|
||||||
|
x: b.min_x as f32,
|
||||||
|
y: b.min_y as f32,
|
||||||
|
},
|
||||||
|
bottom_right: Point {
|
||||||
|
x: b.max_x as f32,
|
||||||
|
y: b.max_y as f32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,22 +2,18 @@
|
|||||||
|
|
||||||
use aabb_quadtree::geom::Rect;
|
use aabb_quadtree::geom::Rect;
|
||||||
use ezgui::GfxCtx;
|
use ezgui::GfxCtx;
|
||||||
use geom;
|
use geom::{PolyLine, Polygon};
|
||||||
use geom::PolyLine;
|
|
||||||
use graphics::math::Vec2d;
|
use graphics::math::Vec2d;
|
||||||
use graphics::types::Color;
|
use graphics::types::Color;
|
||||||
use map_model;
|
use map_model;
|
||||||
use map_model::geometry;
|
use render::{get_bbox, PARCEL_BOUNDARY_THICKNESS};
|
||||||
use render::PARCEL_BOUNDARY_THICKNESS;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DrawParcel {
|
pub struct DrawParcel {
|
||||||
pub id: map_model::ParcelID,
|
pub id: map_model::ParcelID,
|
||||||
// TODO should just have one. use graphics::Line for now.
|
// TODO should just have one. use graphics::Line for now.
|
||||||
boundary_polygons: Vec<Vec<Vec2d>>,
|
boundary_polygons: Vec<Vec<Vec2d>>,
|
||||||
// TODO clean this up
|
pub fill_polygon: Polygon,
|
||||||
pub fill_polygon: Vec<Vec2d>,
|
|
||||||
fill_triangles: Vec<Vec<Vec2d>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DrawParcel {
|
impl DrawParcel {
|
||||||
@ -26,8 +22,7 @@ impl DrawParcel {
|
|||||||
id: p.id,
|
id: p.id,
|
||||||
boundary_polygons: PolyLine::new(p.points.clone())
|
boundary_polygons: PolyLine::new(p.points.clone())
|
||||||
.make_polygons_blindly(PARCEL_BOUNDARY_THICKNESS),
|
.make_polygons_blindly(PARCEL_BOUNDARY_THICKNESS),
|
||||||
fill_polygon: p.points.iter().map(|pt| [pt.x(), pt.y()]).collect(),
|
fill_polygon: Polygon::new(&p.points),
|
||||||
fill_triangles: geom::triangulate(&p.points),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,7 +30,7 @@ impl DrawParcel {
|
|||||||
for p in &self.boundary_polygons {
|
for p in &self.boundary_polygons {
|
||||||
g.draw_polygon(boundary_color, p);
|
g.draw_polygon(boundary_color, p);
|
||||||
}
|
}
|
||||||
for p in &self.fill_triangles {
|
for p in &self.fill_polygon.for_drawing() {
|
||||||
g.draw_polygon(fill_color, p);
|
g.draw_polygon(fill_color, p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -43,6 +38,6 @@ impl DrawParcel {
|
|||||||
//pub fn contains_pt(&self, x: f64, y: f64) -> bool {}
|
//pub fn contains_pt(&self, x: f64, y: f64) -> bool {}
|
||||||
|
|
||||||
pub fn get_bbox(&self) -> Rect {
|
pub fn get_bbox(&self) -> Rect {
|
||||||
geometry::get_bbox_for_polygons(&vec![self.fill_polygon.clone()])
|
get_bbox(&self.fill_polygon.get_bounds())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ pub use bounds::Bounds;
|
|||||||
use dimensioned::si;
|
use dimensioned::si;
|
||||||
pub use gps::LonLat;
|
pub use gps::LonLat;
|
||||||
pub use line::Line;
|
pub use line::Line;
|
||||||
pub use polygon::triangulate;
|
pub use polygon::Polygon;
|
||||||
pub use polyline::PolyLine;
|
pub use polyline::PolyLine;
|
||||||
pub use pt::{HashablePt2D, Pt2D};
|
pub use pt::{HashablePt2D, Pt2D};
|
||||||
use std::marker;
|
use std::marker;
|
||||||
|
@ -1,97 +1,144 @@
|
|||||||
use graphics::math::Vec2d;
|
use graphics::math::Vec2d;
|
||||||
use Pt2D;
|
use {Bounds, Pt2D};
|
||||||
|
|
||||||
// Adapted from https://crates.io/crates/polygon2; couldn't use the crate directly because it
|
#[derive(Debug)]
|
||||||
// depends on nightly.
|
pub struct Polygon {
|
||||||
|
// TODO urgh, just storing for geom validation. :P
|
||||||
|
pub pts: Vec<Pt2D>,
|
||||||
|
|
||||||
pub fn triangulate(pts: &Vec<Pt2D>) -> Vec<Vec<Vec2d>> {
|
// This could be stored more efficiently, but worry about it later when switching to gfx-rs.
|
||||||
assert!(pts.len() >= 3);
|
triangles: Vec<Triangle>,
|
||||||
|
}
|
||||||
|
|
||||||
let mut tgs = Vec::new();
|
impl Polygon {
|
||||||
let mut avl = Vec::with_capacity(pts.len());
|
// Adapted from https://crates.io/crates/polygon2; couldn't use the crate directly because it
|
||||||
for i in 0..pts.len() {
|
// depends on nightly.
|
||||||
avl.push(i);
|
pub fn new(pts: &Vec<Pt2D>) -> Polygon {
|
||||||
}
|
assert!(pts.len() >= 3);
|
||||||
|
|
||||||
let mut i = 0;
|
let mut tgs = Vec::new();
|
||||||
let mut al = pts.len();
|
let mut avl = Vec::with_capacity(pts.len());
|
||||||
while al > 3 {
|
for i in 0..pts.len() {
|
||||||
let i0 = avl[i % al];
|
avl.push(i);
|
||||||
let i1 = avl[(i + 1) % al];
|
}
|
||||||
let i2 = avl[(i + 2) % al];
|
|
||||||
|
|
||||||
let a = pts[i0];
|
let mut i = 0;
|
||||||
let b = pts[i1];
|
let mut al = pts.len();
|
||||||
let c = pts[i2];
|
while al > 3 {
|
||||||
|
let i0 = avl[i % al];
|
||||||
|
let i1 = avl[(i + 1) % al];
|
||||||
|
let i2 = avl[(i + 2) % al];
|
||||||
|
|
||||||
let mut ear_found = false;
|
let a = pts[i0];
|
||||||
if is_triangle_convex(a, b, c) {
|
let b = pts[i1];
|
||||||
ear_found = true;
|
let c = pts[i2];
|
||||||
|
let tri = Triangle::new(a, b, c);
|
||||||
|
|
||||||
for j in 0..al {
|
let mut ear_found = false;
|
||||||
let vi = avl[j];
|
if tri.is_convex() {
|
||||||
|
ear_found = true;
|
||||||
|
|
||||||
if vi != i0 && vi != i1 && vi != i2 {
|
for j in 0..al {
|
||||||
if point_in_triangle(pts[vi], a, b, c) {
|
let vi = avl[j];
|
||||||
ear_found = false;
|
|
||||||
break;
|
if vi != i0 && vi != i1 && vi != i2 {
|
||||||
|
if tri.contains_pt(pts[vi]) {
|
||||||
|
ear_found = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ear_found {
|
||||||
|
tgs.push(i0);
|
||||||
|
tgs.push(i1);
|
||||||
|
tgs.push(i2);
|
||||||
|
avl.remove((i + 1) % al);
|
||||||
|
al -= 1;
|
||||||
|
i = 0;
|
||||||
|
} else if i > 3 * al {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ear_found {
|
tgs.push(avl[0]);
|
||||||
tgs.push(i0);
|
tgs.push(avl[1]);
|
||||||
tgs.push(i1);
|
tgs.push(avl[2]);
|
||||||
tgs.push(i2);
|
|
||||||
avl.remove((i + 1) % al);
|
let mut triangles = Vec::new();
|
||||||
al -= 1;
|
assert!(tgs.len() % 3 == 0);
|
||||||
i = 0;
|
for tri in tgs.chunks(3) {
|
||||||
} else if i > 3 * al {
|
triangles.push(Triangle::new(pts[tri[0]], pts[tri[1]], pts[tri[2]]));
|
||||||
break;
|
}
|
||||||
} else {
|
Polygon {
|
||||||
i += 1;
|
pts: pts.clone(),
|
||||||
|
triangles,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tgs.push(avl[0]);
|
pub fn for_drawing(&self) -> Vec<Vec<Vec2d>> {
|
||||||
tgs.push(avl[1]);
|
self.triangles
|
||||||
tgs.push(avl[2]);
|
.iter()
|
||||||
|
.map(|tri| vec![tri.pt1.to_vec(), tri.pt2.to_vec(), tri.pt3.to_vec()])
|
||||||
let mut result = Vec::new();
|
.collect()
|
||||||
assert!(tgs.len() % 3 == 0);
|
|
||||||
for tri in tgs.chunks(3) {
|
|
||||||
result.push(vec![
|
|
||||||
pts[tri[0]].to_vec(),
|
|
||||||
pts[tri[1]].to_vec(),
|
|
||||||
pts[tri[2]].to_vec(),
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
pub fn contains_pt(&self, pt: Pt2D) -> bool {
|
||||||
|
self.triangles
|
||||||
|
.iter()
|
||||||
|
.find(|tri| tri.contains_pt(pt))
|
||||||
|
.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_triangle_convex(a: Pt2D, b: Pt2D, c: Pt2D) -> bool {
|
#[derive(Debug)]
|
||||||
((a.y() - b.y()) * (c.x() - b.x()) + (b.x() - a.x()) * (c.y() - b.y())) >= 0.0
|
struct Triangle {
|
||||||
|
pt1: Pt2D,
|
||||||
|
pt2: Pt2D,
|
||||||
|
pt3: Pt2D,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn point_in_triangle(p: Pt2D, a: Pt2D, b: Pt2D, c: Pt2D) -> bool {
|
impl Triangle {
|
||||||
let v0x = c.x() - a.x();
|
fn new(pt1: Pt2D, pt2: Pt2D, pt3: Pt2D) -> Triangle {
|
||||||
let v0y = c.y() - a.y();
|
Triangle { pt1, pt2, pt3 }
|
||||||
let v1x = b.x() - a.x();
|
}
|
||||||
let v1y = b.y() - a.y();
|
|
||||||
let v2x = p.x() - a.x();
|
|
||||||
let v2y = p.y() - a.y();
|
|
||||||
|
|
||||||
let dot00 = v0x * v0x + v0y * v0y;
|
fn is_convex(&self) -> bool {
|
||||||
let dot01 = v0x * v1x + v0y * v1y;
|
((self.pt1.y() - self.pt2.y()) * (self.pt3.x() - self.pt2.x())
|
||||||
let dot02 = v0x * v2x + v0y * v2y;
|
+ (self.pt2.x() - self.pt1.x()) * (self.pt3.y() - self.pt2.y())) >= 0.0
|
||||||
let dot11 = v1x * v1x + v1y * v1y;
|
}
|
||||||
let dot12 = v1x * v2x + v1y * v2y;
|
|
||||||
|
|
||||||
let denom = dot00 * dot11 - dot01 * dot01;
|
fn contains_pt(&self, pt: Pt2D) -> bool {
|
||||||
let u = (dot11 * dot02 - dot01 * dot12) / denom;
|
let v0x = self.pt3.x() - self.pt1.x();
|
||||||
let v = (dot00 * dot12 - dot01 * dot02) / denom;
|
let v0y = self.pt3.y() - self.pt1.y();
|
||||||
|
let v1x = self.pt2.x() - self.pt1.x();
|
||||||
|
let v1y = self.pt2.y() - self.pt1.y();
|
||||||
|
let v2x = pt.x() - self.pt1.x();
|
||||||
|
let v2y = pt.y() - self.pt1.y();
|
||||||
|
|
||||||
(u >= 0.0) && (v >= 0.0) && (u + v < 1.0)
|
let dot00 = v0x * v0x + v0y * v0y;
|
||||||
|
let dot01 = v0x * v1x + v0y * v1y;
|
||||||
|
let dot02 = v0x * v2x + v0y * v2y;
|
||||||
|
let dot11 = v1x * v1x + v1y * v1y;
|
||||||
|
let dot12 = v1x * v2x + v1y * v2y;
|
||||||
|
|
||||||
|
let denom = dot00 * dot11 - dot01 * dot01;
|
||||||
|
let u = (dot11 * dot02 - dot01 * dot12) / denom;
|
||||||
|
let v = (dot00 * dot12 - dot01 * dot02) / denom;
|
||||||
|
|
||||||
|
(u >= 0.0) && (v >= 0.0) && (u + v < 1.0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user