From cf3c8378557457363853d6795e4ddf9e70a4738e Mon Sep 17 00:00:00 2001 From: Arne Dußin Date: Thu, 26 Nov 2020 20:50:30 +0100 Subject: Make polygons deletable Before, the deletion tool was not targeting polygons. I also took the liberty to broaden the functionality of the surface trait, which now can check if a rectangle or polygon is contained. --- src/math/mod.rs | 6 ++++++ src/math/polygon/mod.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++++- src/math/rect.rs | 43 ++++++++++++++++++++++------------------ src/tool/deletion_tool.rs | 5 ++++- 4 files changed, 83 insertions(+), 21 deletions(-) (limited to 'src') 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 { /// Checks if a line segment is entirely contained by this surface. fn contains_line_segment(&self, line_segment: &LineSegment) -> bool; + + /// Checks if a rectangle is entirely contained inside this surface. + fn contains_rect(&self, rect: &Rect) -> bool; + + /// Checks if a polygon is contained wholly by this surface. + fn contains_polygon(&self, polygon: &Polygon) -> 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) -> 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) -> 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 Rect { || this.y + this.h < other.y) } - /// Returns true if the entire rect is contained inside this rectangle. - pub fn contains_rect(&self, rect: Rect) -> bool - where - T: Add + Sub + 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 Rect { } } -impl Surface for Rect { +impl Surface for Rect { fn contains_point(&self, point: &Vec2) -> bool { point.x >= self.x && point.x <= self.x + self.w @@ -139,6 +124,26 @@ impl Surface for Rect { fn contains_line_segment(&self, line_segment: &LineSegment) -> bool { self.contains_point(&line_segment.start) && self.contains_point(&line_segment.end) } + + fn contains_rect(&self, rect: &Rect) -> 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) -> 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 :/ diff --git a/src/tool/deletion_tool.rs b/src/tool/deletion_tool.rs index 5031f5d..17dd949 100644 --- a/src/tool/deletion_tool.rs +++ b/src/tool/deletion_tool.rs @@ -25,13 +25,16 @@ impl DeletionTool { pub fn delete_rect(map_data: &mut MapData, rect: Rect) { map_data .rooms_mut() - .retain(|&room| !rect.contains_rect(room)); + .retain(|&room| !rect.contains_rect(&room)); map_data .walls_mut() .retain(|&(pos1, pos2)| !rect.contains_point(&pos1) || !rect.contains_point(&pos2)); map_data .icons_mut() .retain(|icon| !rect.contains_point(&icon.position)); + map_data + .polygons_mut() + .retain(|polygon| !rect.contains_polygon(&polygon)); } } -- cgit v1.2.3-70-g09d2