aboutsummaryrefslogtreecommitdiff
path: root/src/math/polygon.rs
diff options
context:
space:
mode:
authorArne Dußin2020-11-21 11:23:16 +0100
committerArne Dußin2020-11-21 11:23:16 +0100
commit58ca374fab6dd90c4d7415bdcc98add002274894 (patch)
tree94ec5f6c49f9c7e4e812550c82ad21110b02c2ce /src/math/polygon.rs
parent32aec90d0fac637e165913f194422e5b3d96de36 (diff)
downloadgraf_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.rs169
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());
- }
-}