mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-24 17:37:22 +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::input::UserInput;
|
||||
use ezgui::GfxCtx;
|
||||
use geom;
|
||||
use geom::{PolyLine, Pt2D};
|
||||
use geom::{PolyLine, Polygon, Pt2D};
|
||||
use graphics;
|
||||
use graphics::types::Color;
|
||||
use gui;
|
||||
@ -307,7 +306,7 @@ impl UI {
|
||||
Pt2D::new(947.7612927256201, 765.1100512564725), // 5
|
||||
];
|
||||
//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);
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@ use ezgui::input::UserInput;
|
||||
use generator;
|
||||
use geo;
|
||||
use geo::prelude::Intersects;
|
||||
use geom::Pt2D;
|
||||
use geom::{Polygon, Pt2D};
|
||||
use graphics::math::Vec2d;
|
||||
use map_model::{geometry, BuildingID, IntersectionID, LaneID, Map, ParcelID};
|
||||
use piston::input::Key;
|
||||
@ -42,13 +42,13 @@ impl Validator {
|
||||
));
|
||||
}
|
||||
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 {
|
||||
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 {
|
||||
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!(
|
||||
@ -139,6 +139,14 @@ fn make_poly(points: &Vec<Vec2d>) -> geo::Polygon<f64> {
|
||||
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?
|
||||
fn get_pt(map: &Map, id: ID) -> Pt2D {
|
||||
match id {
|
||||
|
@ -2,15 +2,12 @@
|
||||
|
||||
use aabb_quadtree::geom::Rect;
|
||||
use ezgui::GfxCtx;
|
||||
use geom;
|
||||
use geom::PolyLine;
|
||||
use geom::{PolyLine, Polygon, Pt2D};
|
||||
use graphics;
|
||||
use graphics::math::Vec2d;
|
||||
use graphics::types::Color;
|
||||
use map_model;
|
||||
use map_model::geometry;
|
||||
use map_model::{BuildingID, Map};
|
||||
use render::PARCEL_BOUNDARY_THICKNESS;
|
||||
use map_model::{Building, BuildingID, Map};
|
||||
use render::{get_bbox, PARCEL_BOUNDARY_THICKNESS};
|
||||
use std::f64;
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -18,22 +15,19 @@ pub struct DrawBuilding {
|
||||
pub id: BuildingID,
|
||||
// TODO should just have one. use graphics::Line for now.
|
||||
boundary_polygons: Vec<Vec<Vec2d>>,
|
||||
// TODO rm the other one
|
||||
pub fill_polygon: Vec<Vec2d>,
|
||||
fill_triangles: Vec<Vec<Vec2d>>,
|
||||
pub fill_polygon: Polygon,
|
||||
front_path: Option<[f64; 4]>,
|
||||
}
|
||||
|
||||
impl DrawBuilding {
|
||||
pub fn new(bldg: &map_model::Building) -> DrawBuilding {
|
||||
pub fn new(bldg: &Building) -> DrawBuilding {
|
||||
DrawBuilding {
|
||||
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
|
||||
front_path: bldg.front_path
|
||||
.as_ref()
|
||||
.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())
|
||||
.make_polygons_blindly(PARCEL_BOUNDARY_THICKNESS),
|
||||
}
|
||||
@ -54,13 +48,13 @@ impl DrawBuilding {
|
||||
for p in &self.boundary_polygons {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
@ -76,10 +70,11 @@ impl DrawBuilding {
|
||||
}
|
||||
|
||||
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 {
|
||||
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 dimensioned::si;
|
||||
use ezgui::GfxCtx;
|
||||
use geom::{Line, Pt2D};
|
||||
use geom::{Line, Polygon, Pt2D};
|
||||
use graphics;
|
||||
use graphics::math::Vec2d;
|
||||
use graphics::types::Color;
|
||||
use map_model;
|
||||
use map_model::geometry;
|
||||
use render::DrawLane;
|
||||
use render::{get_bbox, DrawLane};
|
||||
use std::f64;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DrawIntersection {
|
||||
pub id: map_model::IntersectionID,
|
||||
pub polygon: Vec<Vec2d>,
|
||||
pub polygon: Polygon,
|
||||
crosswalks: Vec<Vec<(Vec2d, Vec2d)>>,
|
||||
center: Pt2D,
|
||||
has_traffic_signal: bool,
|
||||
@ -28,39 +28,37 @@ impl DrawIntersection {
|
||||
map: &map_model::Map,
|
||||
lanes: &Vec<DrawLane>,
|
||||
) -> DrawIntersection {
|
||||
let mut pts: Vec<Vec2d> = Vec::new();
|
||||
let mut pts: Vec<Pt2D> = Vec::new();
|
||||
for l in &inter.incoming_lanes {
|
||||
let (pt1, pt2) = lanes[l.0].get_end_crossing();
|
||||
pts.push(pt1);
|
||||
pts.push(pt2);
|
||||
let line = lanes[l.0].get_end_crossing();
|
||||
pts.push(line.pt1());
|
||||
pts.push(line.pt2());
|
||||
}
|
||||
for l in &inter.outgoing_lanes {
|
||||
let (pt1, pt2) = lanes[l.0].get_start_crossing();
|
||||
pts.push(pt1);
|
||||
pts.push(pt2);
|
||||
let line = lanes[l.0].get_start_crossing();
|
||||
pts.push(line.pt1());
|
||||
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
|
||||
pts.sort_by_key(|pt| {
|
||||
center
|
||||
.angle_to(Pt2D::new(pt[0], pt[1]))
|
||||
.normalized_degrees() as i64
|
||||
});
|
||||
pts.sort_by_key(|pt| center.angle_to(*pt).normalized_degrees() as i64);
|
||||
let first_pt = pts[0].clone();
|
||||
pts.push(first_pt);
|
||||
|
||||
DrawIntersection {
|
||||
center,
|
||||
id: inter.id,
|
||||
polygon: pts,
|
||||
polygon: Polygon::new(&pts),
|
||||
crosswalks: calculate_crosswalks(inter, map),
|
||||
has_traffic_signal: inter.has_traffic_signal,
|
||||
}
|
||||
}
|
||||
|
||||
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(
|
||||
cs.get(Colors::Crosswalk),
|
||||
@ -84,11 +82,11 @@ impl DrawIntersection {
|
||||
}
|
||||
|
||||
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 {
|
||||
geometry::get_bbox_for_polygons(&[self.polygon.clone()])
|
||||
get_bbox(&self.polygon.get_bounds())
|
||||
}
|
||||
|
||||
fn draw_stop_sign(&self, g: &mut GfxCtx, cs: &ColorScheme) {
|
||||
|
@ -25,8 +25,8 @@ struct Marking {
|
||||
pub struct DrawLane {
|
||||
pub id: LaneID,
|
||||
pub polygons: Vec<Vec<Vec2d>>,
|
||||
start_crossing: (Vec2d, Vec2d),
|
||||
end_crossing: (Vec2d, Vec2d),
|
||||
start_crossing: Line,
|
||||
end_crossing: Line,
|
||||
markings: Vec<Marking>,
|
||||
|
||||
// TODO pretty temporary
|
||||
@ -36,9 +36,8 @@ pub struct DrawLane {
|
||||
impl DrawLane {
|
||||
pub fn new(lane: &map_model::Lane, map: &map_model::Map) -> DrawLane {
|
||||
let road = map.get_r(lane.parent);
|
||||
let start = perp_line(lane.first_line(), geometry::LANE_THICKNESS);
|
||||
let end = perp_line(lane.last_line().reverse(), geometry::LANE_THICKNESS);
|
||||
|
||||
let start = new_perp_line(lane.first_line(), geometry::LANE_THICKNESS);
|
||||
let end = new_perp_line(lane.last_line().reverse(), geometry::LANE_THICKNESS);
|
||||
let polygons = lane.lane_center_pts
|
||||
.make_polygons_blindly(geometry::LANE_THICKNESS);
|
||||
|
||||
@ -76,8 +75,8 @@ impl DrawLane {
|
||||
id: lane.id,
|
||||
polygons,
|
||||
markings,
|
||||
start_crossing: ([start[0], start[1]], [start[2], start[3]]),
|
||||
end_crossing: ([end[0], end[1]], [end[2], end[3]]),
|
||||
start_crossing: start,
|
||||
end_crossing: end,
|
||||
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
|
||||
pub(crate) fn get_end_crossing(&self) -> (Vec2d, Vec2d) {
|
||||
self.end_crossing
|
||||
pub(crate) fn get_end_crossing(&self) -> &Line {
|
||||
&self.end_crossing
|
||||
}
|
||||
|
||||
pub(crate) fn get_start_crossing(&self) -> (Vec2d, Vec2d) {
|
||||
self.start_crossing
|
||||
pub(crate) fn get_start_crossing(&self) -> &Line {
|
||||
&self.start_crossing
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,6 +177,12 @@ fn perp_line(l: Line, length: f64) -> [f64; 4] {
|
||||
[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 {
|
||||
let tile_every = geometry::LANE_THICKNESS * si::M;
|
||||
|
||||
|
@ -7,6 +7,8 @@ mod map;
|
||||
mod parcel;
|
||||
mod turn;
|
||||
|
||||
use aabb_quadtree::geom::{Point, Rect};
|
||||
use geom::Bounds;
|
||||
use map_model::geometry;
|
||||
pub use render::lane::DrawLane;
|
||||
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 TURN_ICON_ARROW_TIP_LENGTH: f64 = BIG_ARROW_TIP_LENGTH * 0.8;
|
||||
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 ezgui::GfxCtx;
|
||||
use geom;
|
||||
use geom::PolyLine;
|
||||
use geom::{PolyLine, Polygon};
|
||||
use graphics::math::Vec2d;
|
||||
use graphics::types::Color;
|
||||
use map_model;
|
||||
use map_model::geometry;
|
||||
use render::PARCEL_BOUNDARY_THICKNESS;
|
||||
use render::{get_bbox, PARCEL_BOUNDARY_THICKNESS};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DrawParcel {
|
||||
pub id: map_model::ParcelID,
|
||||
// TODO should just have one. use graphics::Line for now.
|
||||
boundary_polygons: Vec<Vec<Vec2d>>,
|
||||
// TODO clean this up
|
||||
pub fill_polygon: Vec<Vec2d>,
|
||||
fill_triangles: Vec<Vec<Vec2d>>,
|
||||
pub fill_polygon: Polygon,
|
||||
}
|
||||
|
||||
impl DrawParcel {
|
||||
@ -26,8 +22,7 @@ impl DrawParcel {
|
||||
id: p.id,
|
||||
boundary_polygons: PolyLine::new(p.points.clone())
|
||||
.make_polygons_blindly(PARCEL_BOUNDARY_THICKNESS),
|
||||
fill_polygon: p.points.iter().map(|pt| [pt.x(), pt.y()]).collect(),
|
||||
fill_triangles: geom::triangulate(&p.points),
|
||||
fill_polygon: Polygon::new(&p.points),
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,7 +30,7 @@ impl DrawParcel {
|
||||
for p in &self.boundary_polygons {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -43,6 +38,6 @@ impl DrawParcel {
|
||||
//pub fn contains_pt(&self, x: f64, y: f64) -> bool {}
|
||||
|
||||
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;
|
||||
pub use gps::LonLat;
|
||||
pub use line::Line;
|
||||
pub use polygon::triangulate;
|
||||
pub use polygon::Polygon;
|
||||
pub use polyline::PolyLine;
|
||||
pub use pt::{HashablePt2D, Pt2D};
|
||||
use std::marker;
|
||||
|
@ -1,97 +1,144 @@
|
||||
use graphics::math::Vec2d;
|
||||
use Pt2D;
|
||||
use {Bounds, Pt2D};
|
||||
|
||||
// Adapted from https://crates.io/crates/polygon2; couldn't use the crate directly because it
|
||||
// depends on nightly.
|
||||
#[derive(Debug)]
|
||||
pub struct Polygon {
|
||||
// TODO urgh, just storing for geom validation. :P
|
||||
pub pts: Vec<Pt2D>,
|
||||
|
||||
pub fn triangulate(pts: &Vec<Pt2D>) -> Vec<Vec<Vec2d>> {
|
||||
assert!(pts.len() >= 3);
|
||||
// This could be stored more efficiently, but worry about it later when switching to gfx-rs.
|
||||
triangles: Vec<Triangle>,
|
||||
}
|
||||
|
||||
let mut tgs = Vec::new();
|
||||
let mut avl = Vec::with_capacity(pts.len());
|
||||
for i in 0..pts.len() {
|
||||
avl.push(i);
|
||||
}
|
||||
impl Polygon {
|
||||
// Adapted from https://crates.io/crates/polygon2; couldn't use the crate directly because it
|
||||
// depends on nightly.
|
||||
pub fn new(pts: &Vec<Pt2D>) -> Polygon {
|
||||
assert!(pts.len() >= 3);
|
||||
|
||||
let mut i = 0;
|
||||
let mut al = pts.len();
|
||||
while al > 3 {
|
||||
let i0 = avl[i % al];
|
||||
let i1 = avl[(i + 1) % al];
|
||||
let i2 = avl[(i + 2) % al];
|
||||
let mut tgs = Vec::new();
|
||||
let mut avl = Vec::with_capacity(pts.len());
|
||||
for i in 0..pts.len() {
|
||||
avl.push(i);
|
||||
}
|
||||
|
||||
let a = pts[i0];
|
||||
let b = pts[i1];
|
||||
let c = pts[i2];
|
||||
let mut i = 0;
|
||||
let mut al = pts.len();
|
||||
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;
|
||||
if is_triangle_convex(a, b, c) {
|
||||
ear_found = true;
|
||||
let a = pts[i0];
|
||||
let b = pts[i1];
|
||||
let c = pts[i2];
|
||||
let tri = Triangle::new(a, b, c);
|
||||
|
||||
for j in 0..al {
|
||||
let vi = avl[j];
|
||||
let mut ear_found = false;
|
||||
if tri.is_convex() {
|
||||
ear_found = true;
|
||||
|
||||
if vi != i0 && vi != i1 && vi != i2 {
|
||||
if point_in_triangle(pts[vi], a, b, c) {
|
||||
ear_found = false;
|
||||
break;
|
||||
for j in 0..al {
|
||||
let vi = avl[j];
|
||||
|
||||
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(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;
|
||||
tgs.push(avl[0]);
|
||||
tgs.push(avl[1]);
|
||||
tgs.push(avl[2]);
|
||||
|
||||
let mut triangles = Vec::new();
|
||||
assert!(tgs.len() % 3 == 0);
|
||||
for tri in tgs.chunks(3) {
|
||||
triangles.push(Triangle::new(pts[tri[0]], pts[tri[1]], pts[tri[2]]));
|
||||
}
|
||||
Polygon {
|
||||
pts: pts.clone(),
|
||||
triangles,
|
||||
}
|
||||
}
|
||||
|
||||
tgs.push(avl[0]);
|
||||
tgs.push(avl[1]);
|
||||
tgs.push(avl[2]);
|
||||
|
||||
let mut result = Vec::new();
|
||||
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(),
|
||||
]);
|
||||
pub fn for_drawing(&self) -> Vec<Vec<Vec2d>> {
|
||||
self.triangles
|
||||
.iter()
|
||||
.map(|tri| vec![tri.pt1.to_vec(), tri.pt2.to_vec(), tri.pt3.to_vec()])
|
||||
.collect()
|
||||
}
|
||||
|
||||
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 {
|
||||
((a.y() - b.y()) * (c.x() - b.x()) + (b.x() - a.x()) * (c.y() - b.y())) >= 0.0
|
||||
#[derive(Debug)]
|
||||
struct Triangle {
|
||||
pt1: Pt2D,
|
||||
pt2: Pt2D,
|
||||
pt3: Pt2D,
|
||||
}
|
||||
|
||||
fn point_in_triangle(p: Pt2D, a: Pt2D, b: Pt2D, c: Pt2D) -> bool {
|
||||
let v0x = c.x() - a.x();
|
||||
let v0y = c.y() - a.y();
|
||||
let v1x = b.x() - a.x();
|
||||
let v1y = b.y() - a.y();
|
||||
let v2x = p.x() - a.x();
|
||||
let v2y = p.y() - a.y();
|
||||
impl Triangle {
|
||||
fn new(pt1: Pt2D, pt2: Pt2D, pt3: Pt2D) -> Triangle {
|
||||
Triangle { pt1, pt2, pt3 }
|
||||
}
|
||||
|
||||
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;
|
||||
fn is_convex(&self) -> bool {
|
||||
((self.pt1.y() - self.pt2.y()) * (self.pt3.x() - self.pt2.x())
|
||||
+ (self.pt2.x() - self.pt1.x()) * (self.pt3.y() - self.pt2.y())) >= 0.0
|
||||
}
|
||||
|
||||
let denom = dot00 * dot11 - dot01 * dot01;
|
||||
let u = (dot11 * dot02 - dot01 * dot12) / denom;
|
||||
let v = (dot00 * dot12 - dot01 * dot02) / denom;
|
||||
fn contains_pt(&self, pt: Pt2D) -> bool {
|
||||
let v0x = self.pt3.x() - self.pt1.x();
|
||||
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