From abf55d8d46fc7d5cfccc9f778da6fca10b33d0cd Mon Sep 17 00:00:00 2001 From: Arne Dußin Date: Sat, 21 Nov 2020 20:55:47 +0100 Subject: Move containment of points/ lines into trait --- src/gui/tool_sidebar.rs | 4 +- src/math/line_segment.rs | 6 +-- src/math/mod.rs | 10 +++++ src/math/polygon/mod.rs | 53 ++++++++++++---------- src/math/rect.rs | 112 +++++++++++++++++++++++----------------------- src/tool/deletion_tool.rs | 6 +-- 6 files changed, 105 insertions(+), 86 deletions(-) (limited to 'src') diff --git a/src/gui/tool_sidebar.rs b/src/gui/tool_sidebar.rs index 46b53ea..7674c47 100644 --- a/src/gui/tool_sidebar.rs +++ b/src/gui/tool_sidebar.rs @@ -1,4 +1,4 @@ -use crate::math::{Rect, Vec2}; +use crate::math::{Rect, Surface, Vec2}; use crate::tool::ToolType; use crate::Editor; use raylib::core::texture::Texture2D; @@ -28,7 +28,7 @@ impl ToolSidebar { /// Check if the mouse is currently being captured by this GUI-element. In that case, /// everything else that might want to access the mouse will be blocked. pub fn mouse_captured(screen_height: u16, mouse_pos: Vec2) -> bool { - Self::panel_rect(screen_height).contains(mouse_pos) + Self::panel_rect(screen_height).contains_point(&mouse_pos) } pub fn draw(&self, screen_height: u16, rld: &mut impl RaylibDrawGui, editor: &mut Editor) { diff --git a/src/math/line_segment.rs b/src/math/line_segment.rs index 244b0af..94f58b2 100644 --- a/src/math/line_segment.rs +++ b/src/math/line_segment.rs @@ -1,4 +1,4 @@ -use super::{Rect, TripletOrientation, Vec2}; +use super::{Rect, Surface, TripletOrientation, Vec2}; use alga::general::{ClosedDiv, ClosedMul, ClosedSub}; use nalgebra::{RealField, Scalar}; use num_traits::Zero; @@ -118,8 +118,8 @@ impl LineSegment { * the segments. We know it's on the lines, so checking with the lines bounding box is * faster than checking where on the line exactly it would be. */ - if Rect::bounding_rect(line_a.start, line_a.end).contains(out) - && Rect::bounding_rect(line_b.start, line_b.end).contains(out) + if Rect::bounding_rect(line_a.start, line_a.end).contains_point(&out) + && Rect::bounding_rect(line_b.start, line_b.end).contains_point(&out) { Some(out) } else { diff --git a/src/math/mod.rs b/src/math/mod.rs index e72a7a4..6f83c98 100644 --- a/src/math/mod.rs +++ b/src/math/mod.rs @@ -10,8 +10,18 @@ pub use self::rect::*; pub use self::triangle::*; pub use self::vec2::*; +use nalgebra::Scalar; use std::cmp::Ordering; +/// Trait that describes an area in the vector space on the field of T +pub trait Surface { + /// Checks if a point lies on this surface. + fn contains_point(&self, point: &Vec2) -> bool; + + /// Checks if a line segment is entirely contained by this surface. + fn contains_line_segment(&self, line_segment: &LineSegment) -> bool; +} + /// Round a floating point number to the nearest step given by the step argument. For instance, if /// the step is 0.5, then all numbers from 0.0 to 0.24999... will be 0., while all numbers from /// 0.25 to 0.74999... will be 0.5 and so on. diff --git a/src/math/polygon/mod.rs b/src/math/polygon/mod.rs index 4530857..d351ec7 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::Vec2; +use super::{LineSegment, Surface, Vec2}; use nalgebra::{ClosedDiv, ClosedMul, ClosedSub, RealField, Scalar}; use num_traits::Zero; use std::ops::Neg; @@ -24,10 +24,27 @@ impl Polygon { /// 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) -> bool + + /// 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) -> Vec> where - T: Zero + ClosedSub + ClosedMul + ClosedDiv + Neg + PartialOrd, + T: RealField, { + let mut graph = PolygonGraph::from_polygon(&self); + graph.add_all(&other); + + // TODO: Make bounding box support multiple polygons + vec![graph.bounding_polygon()] + } +} + +impl< + T: Scalar + Copy + ClosedSub + ClosedMul + ClosedDiv + Neg + PartialOrd + Zero, + > Surface for Polygon +{ + fn contains_point(&self, p: &Vec2) -> bool { let n = self.corners.len(); let a = self.corners[n - 1]; @@ -102,18 +119,8 @@ impl Polygon { (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) -> Vec> - 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()] + fn contains_line_segment(&self, line_segment: &LineSegment) -> bool { + unimplemented!() } } @@ -133,14 +140,14 @@ mod test { 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.))); + 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] diff --git a/src/math/rect.rs b/src/math/rect.rs index 6988b2c..876e728 100644 --- a/src/math/rect.rs +++ b/src/math/rect.rs @@ -1,6 +1,6 @@ -use super::Vec2; +use super::{LineSegment, Surface, Vec2}; //use alga::general::{Additive, Identity}; -use nalgebra::{RealField, Scalar}; +use nalgebra::{ClosedAdd, RealField, Scalar}; use num_traits::identities::Zero; use serde::{Deserialize, Serialize}; use std::ops::{Add, AddAssign, Sub}; @@ -18,48 +18,6 @@ pub struct Rect { pub h: T, } -// This is sad, but also sadly necessary :/ -impl + Scalar + Copy> Into for Rect { - fn into(self) -> raylib::ffi::Rectangle { - raylib::ffi::Rectangle { - x: self.x.into(), - y: self.y.into(), - width: self.w.into(), - height: self.h.into(), - } - } -} -impl + Scalar + Copy> From for Rect { - fn from(r: raylib::ffi::Rectangle) -> Self { - Self { - x: T::from(r.x), - y: T::from(r.y), - w: T::from(r.width), - h: T::from(r.height), - } - } -} -impl + Scalar + Copy> Into for Rect { - fn into(self) -> raylib::math::Rectangle { - raylib::math::Rectangle { - x: self.x.into(), - y: self.y.into(), - width: self.w.into(), - height: self.h.into(), - } - } -} -impl + Scalar + Copy> From for Rect { - fn from(r: raylib::math::Rectangle) -> Self { - Self { - x: T::from(r.x), - y: T::from(r.y), - w: T::from(r.width), - h: T::from(r.height), - } - } -} - impl Rect { pub fn new(x: T, y: T, w: T, h: T) -> Self { Self { x, y, w, h } @@ -105,17 +63,6 @@ impl Rect { || this.y + this.h < other.y) } - /// Check if the point is inside this Rect and return true if so. - pub fn contains(&self, point: Vec2) -> bool - where - T: PartialOrd + Add, - { - point.x >= self.x - && point.x <= self.x + self.w - && point.y >= self.y - && point.y <= self.y + self.h - } - /// Returns true if the entire rect is contained inside this rectangle. pub fn contains_rect(&self, rect: Rect) -> bool where @@ -181,6 +128,61 @@ impl Rect { } } +impl Surface for Rect { + fn contains_point(&self, point: &Vec2) -> bool { + point.x >= self.x + && point.x <= self.x + self.w + && point.y >= self.y + && point.y <= self.y + self.h + } + + fn contains_line_segment(&self, line_segment: &LineSegment) -> bool { + self.contains_point(&line_segment.start) && self.contains_point(&line_segment.end) + } +} + +// This is sad, but also sadly necessary :/ +impl + Scalar + Copy> Into for Rect { + fn into(self) -> raylib::ffi::Rectangle { + raylib::ffi::Rectangle { + x: self.x.into(), + y: self.y.into(), + width: self.w.into(), + height: self.h.into(), + } + } +} +impl + Scalar + Copy> From for Rect { + fn from(r: raylib::ffi::Rectangle) -> Self { + Self { + x: T::from(r.x), + y: T::from(r.y), + w: T::from(r.width), + h: T::from(r.height), + } + } +} +impl + Scalar + Copy> Into for Rect { + fn into(self) -> raylib::math::Rectangle { + raylib::math::Rectangle { + x: self.x.into(), + y: self.y.into(), + width: self.w.into(), + height: self.h.into(), + } + } +} +impl + Scalar + Copy> From for Rect { + fn from(r: raylib::math::Rectangle) -> Self { + Self { + x: T::from(r.x), + y: T::from(r.y), + w: T::from(r.width), + h: T::from(r.height), + } + } +} + #[cfg(test)] mod test { use super::*; diff --git a/src/tool/deletion_tool.rs b/src/tool/deletion_tool.rs index c313574..5031f5d 100644 --- a/src/tool/deletion_tool.rs +++ b/src/tool/deletion_tool.rs @@ -2,7 +2,7 @@ use super::Tool; use crate::button::Button; use crate::config::{DeletionToolKeybindings, ToolKeybindings}; use crate::map_data::MapData; -use crate::math::{Rect, Vec2}; +use crate::math::{Rect, Surface, Vec2}; use crate::transform::Transform; use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle}; use raylib::ffi::Color; @@ -28,10 +28,10 @@ impl DeletionTool { .retain(|&room| !rect.contains_rect(room)); map_data .walls_mut() - .retain(|&(pos1, pos2)| !rect.contains(pos1) || !rect.contains(pos2)); + .retain(|&(pos1, pos2)| !rect.contains_point(&pos1) || !rect.contains_point(&pos2)); map_data .icons_mut() - .retain(|icon| !rect.contains(icon.position)); + .retain(|icon| !rect.contains_point(&icon.position)); } } -- cgit v1.2.3-70-g09d2