diff options
| author | Arne Dußin | 2020-11-21 11:23:16 +0100 |
|---|---|---|
| committer | Arne Dußin | 2020-11-21 11:23:16 +0100 |
| commit | 58ca374fab6dd90c4d7415bdcc98add002274894 (patch) | |
| tree | 94ec5f6c49f9c7e4e812550c82ad21110b02c2ce /src/math/polygon.rs | |
| parent | 32aec90d0fac637e165913f194422e5b3d96de36 (diff) | |
| download | graf_karto-58ca374fab6dd90c4d7415bdcc98add002274894.tar.gz graf_karto-58ca374fab6dd90c4d7415bdcc98add002274894.zip | |
Move polygon functions into own mod
The math module was starting to be mostly polygon files and functions,
so those got their own subfolder to make the math module less of a mess.
Diffstat (limited to 'src/math/polygon.rs')
| -rw-r--r-- | src/math/polygon.rs | 169 |
1 files changed, 0 insertions, 169 deletions
diff --git a/src/math/polygon.rs b/src/math/polygon.rs deleted file mode 100644 index 5711049..0000000 --- a/src/math/polygon.rs +++ /dev/null @@ -1,169 +0,0 @@ -use super::{PolygonGraph, Vec2}; -use nalgebra::{ClosedDiv, ClosedMul, ClosedSub, RealField, Scalar}; -use num_traits::Zero; -use std::ops::Neg; - -#[derive(Debug)] -// TODO: Support polygons with holes -pub struct Polygon<T: Scalar + Copy> { - pub corners: Vec<Vec2<T>>, -} - -impl<T: Scalar + Copy> Polygon<T> { - pub fn new(corners: Vec<Vec2<T>>) -> Self { - Self { corners } - } - - /// Check whether a point is inside a polygon or not. If a point lies on an edge, it also - /// counts as inside the polygon. - pub fn contains_point(&self, p: Vec2<T>) -> bool - where - T: Zero + ClosedSub + ClosedMul + ClosedDiv + Neg<Output = T> + PartialOrd, - { - let n = self.corners.len(); - - let a = self.corners[n - 1]; - let mut b = self.corners[n - 2]; - let mut ax; - let mut ay = a.y - p.y; - let mut bx = b.x - p.x; - let mut by = b.y - p.y; - - let mut lup = by > ay; - for i in 0..n { - // ax = bx; - ay = by; - b = self.corners[i]; - bx = b.x - p.x; - by = b.y - p.y; - - if ay == by { - continue; - } - lup = by > ay; - } - - let mut depth = 0; - for i in 0..n { - ax = bx; - ay = by; - let b = &self.corners[i]; - bx = b.x - p.x; - by = b.y - p.y; - - if ay < T::zero() && by < T::zero() { - // both "up" or both "down" - continue; - } - if ay > T::zero() && by > T::zero() { - // both "up" or both "down" - continue; - } - if ax < T::zero() && bx < T::zero() { - // both points on the left - continue; - } - - if ay == by && (if ax < bx { ax } else { bx }) <= T::zero() { - return true; - } - if ay == by { - continue; - } - - let lx = ax + (((bx - ax) * -ay) / (by - ay)); - if lx == T::zero() { - // point on edge - return true; - } - if lx > T::zero() { - depth += 1; - } - if ay == T::zero() && lup && by > ay { - // hit vertex, both up - depth -= 1; - } - if ay == T::zero() && !lup && by < ay { - // hit vertex, both down - depth -= 1; - } - - lup = by > ay; - } - - (depth & 1) == 1 - } - - /// Join this polygon with another, ensuring the area of the two stays the same, but the - /// overlap is not doubled, but instead joined into one. - /// Returns the Polygons themselves, if there is no overlap - pub fn unite(self, other: Polygon<T>) -> Vec<Polygon<T>> - where - T: RealField, - { - let mut graph = PolygonGraph::from_polygon(&self); - graph.add_all(&other); - - // TODO: Make bounding box support multiple polygons - vec![graph.bounding_polygon()] - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn polygon_contains() { - let polygon = Polygon::new(vec![ - Vec2::new(0., 0.), - Vec2::new(-1., 1.), - Vec2::new(0., 2.), - Vec2::new(1., 3.), - Vec2::new(3., 1.5), - Vec2::new(2., 0.), - Vec2::new(1., 1.), - ]); - - assert!(!polygon.contains_point(Vec2::new(1., -2.))); - assert!(!polygon.contains_point(Vec2::new(-1., 0.5))); - assert!(polygon.contains_point(Vec2::new(0., 0.5))); - assert!(polygon.contains_point(Vec2::new(0.5, 1.))); - assert!(polygon.contains_point(Vec2::new(0.5, 1.5))); - assert!(!polygon.contains_point(Vec2::new(-2., 1.9))); - assert!(!polygon.contains_point(Vec2::new(0., 3.))); - assert!(polygon.contains_point(Vec2::new(1., 3.))); - } - - #[test] - fn polygon_union() { - let first = Polygon::new(vec![ - Vec2::new(-2., 1.), - Vec2::new(-0.5, 2.5), - Vec2::new(2., 2.), - Vec2::new(0.5, 1.5), - Vec2::new(1., 0.), - Vec2::new(-0.5, 1.), - ]); - - let second = Polygon::new(vec![ - Vec2::new(0., 0.), - Vec2::new(-2., 2.), - Vec2::new(3., 2.), - Vec2::new(1.5, 0.), - ]); - - let union = first.unite(second); - assert_eq!(union.len(), 1); - let union = &union[0]; - - println!("Union of the two polygons: {:?}", union); - - assert_eq!(union.corners.len(), 11); - assert!(union - .corners - .iter() - .find(|&p| p.x == 0. && p.y == 0.) - .is_some()); - } -} |
