aboutsummaryrefslogtreecommitdiff
path: root/src/math
diff options
context:
space:
mode:
Diffstat (limited to 'src/math')
-rw-r--r--src/math/mod.rs6
-rw-r--r--src/math/polygon/mod.rs50
-rw-r--r--src/math/rect.rs43
3 files changed, 79 insertions, 20 deletions
diff --git a/src/math/mod.rs b/src/math/mod.rs
index 6f83c98..b84d270 100644
--- a/src/math/mod.rs
+++ b/src/math/mod.rs
@@ -20,6 +20,12 @@ pub trait Surface<T: Scalar + Copy> {
/// Checks if a line segment is entirely contained by this surface.
fn contains_line_segment(&self, line_segment: &LineSegment<T>) -> bool;
+
+ /// Checks if a rectangle is entirely contained inside this surface.
+ fn contains_rect(&self, rect: &Rect<T>) -> bool;
+
+ /// Checks if a polygon is contained wholly by this surface.
+ fn contains_polygon(&self, polygon: &Polygon<T>) -> bool;
}
/// Round a floating point number to the nearest step given by the step argument. For instance, if
diff --git a/src/math/polygon/mod.rs b/src/math/polygon/mod.rs
index ed48751..c9dad91 100644
--- a/src/math/polygon/mod.rs
+++ b/src/math/polygon/mod.rs
@@ -6,7 +6,7 @@ pub mod triangulate;
pub use polygon_graph::*;
pub use triangulate::*;
-use super::{LineSegment, Surface, TripletOrientation, Vec2};
+use super::{LineSegment, Rect, Surface, TripletOrientation, Vec2};
use crate::math;
use nalgebra::{ClosedDiv, ClosedMul, ClosedSub, RealField, Scalar};
use num_traits::Zero;
@@ -361,6 +361,54 @@ impl<
true
}
+
+ fn contains_rect(&self, rect: &Rect<T>) -> bool {
+ /* Turn the rectangle into a vector with its hull line segments. If all hull segments are
+ * contained in the polygon, the rectangle is contained completely.
+ */
+ let hull_edges = [
+ // Top left to bottom left.
+ LineSegment::new(
+ Vec2::new(rect.x, rect.y),
+ Vec2::new(rect.x, rect.y + rect.h),
+ ),
+ // Bottom left to bottom right.
+ LineSegment::new(
+ Vec2::new(rect.x, rect.y + rect.h),
+ Vec2::new(rect.x + rect.w, rect.y + rect.h),
+ ),
+ // Bottom right to top right.
+ LineSegment::new(
+ Vec2::new(rect.x + rect.w, rect.y + rect.h),
+ Vec2::new(rect.x + rect.w, rect.y),
+ ),
+ // Top right to top left.
+ LineSegment::new(
+ Vec2::new(rect.x + rect.w, rect.y),
+ Vec2::new(rect.x, rect.y),
+ ),
+ ];
+
+ hull_edges
+ .iter()
+ .all(|edge| self.contains_line_segment(edge))
+ }
+
+ fn contains_polygon(&self, polygon: &Polygon<T>) -> bool {
+ /* Check for all edges of the polygon that they are contained by the polygon. If they all
+ * are, then the polygon itself must also be contained.
+ */
+ for i in 0..polygon.corners.len() {
+ let next = (i + 1) % polygon.corners.len();
+ if !self
+ .contains_line_segment(&LineSegment::new(polygon.corners[i], polygon.corners[next]))
+ {
+ return false;
+ }
+ }
+
+ true
+ }
}
/* Helper function to calculate the combined angle of a set of points when connecting them one
diff --git a/src/math/rect.rs b/src/math/rect.rs
index 876e728..5f4e5f5 100644
--- a/src/math/rect.rs
+++ b/src/math/rect.rs
@@ -1,9 +1,9 @@
-use super::{LineSegment, Surface, Vec2};
+use super::{LineSegment, Polygon, Surface, Vec2};
//use alga::general::{Additive, Identity};
-use nalgebra::{ClosedAdd, RealField, Scalar};
+use nalgebra::{ClosedAdd, ClosedSub, RealField, Scalar};
use num_traits::identities::Zero;
use serde::{Deserialize, Serialize};
-use std::ops::{Add, AddAssign, Sub};
+use std::ops::{Add, AddAssign};
/// Represents a Rectangle with the value type T.
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
@@ -63,21 +63,6 @@ impl<T: Scalar + Copy> Rect<T> {
|| this.y + this.h < other.y)
}
- /// Returns true if the entire rect is contained inside this rectangle.
- pub fn contains_rect(&self, rect: Rect<T>) -> bool
- where
- T: Add<Output = T> + Sub<Output = T> + PartialOrd + Zero,
- {
- /* True, if the rightmost x-coordinate of the called rectangle is further right or the same
- * as the rightmost coordinate of the given rect.
- */
- let x_exceeds = self.x + self.w - rect.x - rect.w >= T::zero();
- // The same for the y-coordinates
- let y_exceeds = self.y + self.h - rect.y - rect.h >= T::zero();
-
- x_exceeds && y_exceeds && self.x <= rect.x && self.y <= rect.y
- }
-
/// Function to calculate the bounding rectangle that is between two vectors. The order of the
/// vectors is irrelevent for this. As long as they are diagonally opposite of each other, this
/// function will work.
@@ -128,7 +113,7 @@ impl<T: Scalar + Copy> Rect<T> {
}
}
-impl<T: Scalar + Copy + PartialOrd + ClosedAdd> Surface<T> for Rect<T> {
+impl<T: Scalar + Copy + PartialOrd + ClosedAdd + ClosedSub + Zero> Surface<T> for Rect<T> {
fn contains_point(&self, point: &Vec2<T>) -> bool {
point.x >= self.x
&& point.x <= self.x + self.w
@@ -139,6 +124,26 @@ impl<T: Scalar + Copy + PartialOrd + ClosedAdd> Surface<T> for Rect<T> {
fn contains_line_segment(&self, line_segment: &LineSegment<T>) -> bool {
self.contains_point(&line_segment.start) && self.contains_point(&line_segment.end)
}
+
+ fn contains_rect(&self, rect: &Rect<T>) -> bool {
+ /* True, if the rightmost x-coordinate of the called rectangle is further right or the same
+ * as the rightmost coordinate of the given rect.
+ */
+ let x_exceeds = self.x + self.w - rect.x - rect.w >= T::zero();
+ // The same for the y-coordinates
+ let y_exceeds = self.y + self.h - rect.y - rect.h >= T::zero();
+
+ x_exceeds && y_exceeds && self.x <= rect.x && self.y <= rect.y
+ }
+
+ fn contains_polygon(&self, polygon: &Polygon<T>) -> bool {
+ // Check if all vertices of the polygon lie inside the rectangle. If so, the polygon must
+ // be contained in its entirety.
+ polygon
+ .corners()
+ .iter()
+ .all(|&corner| self.contains_point(&corner))
+ }
}
// This is sad, but also sadly necessary :/