From 945ed8327214a8bcf04e1926c78ae1a5a14cd5ec Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Wed, 27 Sep 2023 10:52:27 -0700 Subject: [PATCH] Add `map()` and `zip()` to point and vector types. These methods may be used to conveniently perform component-wise operations that aren't already provided as other methods. --- src/point.rs | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/vector.rs | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+) diff --git a/src/point.rs b/src/point.rs index b3fcd8e..e406e12 100644 --- a/src/point.rs +++ b/src/point.rs @@ -192,6 +192,41 @@ impl Point2D { pub fn from_untyped(p: Point2D) -> Self { point2(p.x, p.y) } + + /// Apply the function `f` to each component of this point. + /// + /// # Example + /// + /// This may be used to perform unusual arithmetic which is not already offered as methods. + /// + /// ``` + /// use euclid::default::Point2D; + /// + /// let p = Point2D::::new(5, 15); + /// assert_eq!(p.map(|coord| coord.saturating_sub(10)), Point2D::new(0, 5)); + /// ``` + #[inline] + pub fn map V>(self, mut f: F) -> Point2D { + point2(f(self.x), f(self.y)) + } + + /// Apply the function `f` to each pair of components of this point and `rhs`. + /// + /// # Example + /// + /// This may be used to perform unusual arithmetic which is not already offered as methods. + /// + /// ``` + /// use euclid::{default::{Point2D, Vector2D}, point2}; + /// + /// let a: Point2D = point2(50, 200); + /// let b: Point2D = point2(100, 100); + /// assert_eq!(a.zip(b, u32::saturating_sub), Vector2D::new(0, 100)); + /// ``` + #[inline] + pub fn zip V>(self, rhs: Self, mut f: F) -> Vector2D { + vec2(f(self.x, rhs.x), f(self.y, rhs.y)) + } } impl Point2D { @@ -933,6 +968,41 @@ impl Point3D { pub fn from_untyped(p: Point3D) -> Self { point3(p.x, p.y, p.z) } + + /// Apply the function `f` to each component of this point. + /// + /// # Example + /// + /// This may be used to perform unusual arithmetic which is not already offered as methods. + /// + /// ``` + /// use euclid::default::Point3D; + /// + /// let p = Point3D::::new(5, 11, 15); + /// assert_eq!(p.map(|coord| coord.saturating_sub(10)), Point3D::new(0, 1, 5)); + /// ``` + #[inline] + pub fn map V>(self, mut f: F) -> Point3D { + point3(f(self.x), f(self.y), f(self.z)) + } + + /// Apply the function `f` to each pair of components of this point and `rhs`. + /// + /// # Example + /// + /// This may be used to perform unusual arithmetic which is not already offered as methods. + /// + /// ``` + /// use euclid::{default::{Point3D, Vector3D}, point2}; + /// + /// let a: Point3D = Point3D::new(50, 200, 400); + /// let b: Point3D = Point3D::new(100, 100, 150); + /// assert_eq!(a.zip(b, u32::saturating_sub), Vector3D::new(0, 100, 250)); + /// ``` + #[inline] + pub fn zip V>(self, rhs: Self, mut f: F) -> Vector3D { + vec3(f(self.x, rhs.x), f(self.y, rhs.y), f(self.z, rhs.z)) + } } impl Point3D { diff --git a/src/vector.rs b/src/vector.rs index 2a06d7e..d6c00e8 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -210,6 +210,41 @@ impl Vector2D { vec2(p.x, p.y) } + /// Apply the function `f` to each component of this vector. + /// + /// # Example + /// + /// This may be used to perform unusual arithmetic which is not already offered as methods. + /// + /// ``` + /// use euclid::default::Vector2D; + /// + /// let p = Vector2D::::new(5, 11); + /// assert_eq!(p.map(|coord| coord.saturating_sub(10)), Vector2D::new(0, 1)); + /// ``` + #[inline] + pub fn map V>(self, mut f: F) -> Vector2D { + vec2(f(self.x), f(self.y)) + } + + /// Apply the function `f` to each pair of components of this point and `rhs`. + /// + /// # Example + /// + /// This may be used to perform unusual arithmetic which is not already offered as methods. + /// + /// ``` + /// use euclid::default::Vector2D; + /// + /// let a: Vector2D = Vector2D::new(50, 200); + /// let b: Vector2D = Vector2D::new(100, 100); + /// assert_eq!(a.zip(b, u8::saturating_add), Vector2D::new(150, 255)); + /// ``` + #[inline] + pub fn zip V>(self, rhs: Self, mut f: F) -> Vector2D { + vec2(f(self.x, rhs.x), f(self.y, rhs.y)) + } + /// Computes the vector with absolute values of each component. /// /// # Example @@ -1067,6 +1102,41 @@ impl Vector3D { vec3(p.x, p.y, p.z) } + /// Apply the function `f` to each component of this vector. + /// + /// # Example + /// + /// This may be used to perform unusual arithmetic which is not already offered as methods. + /// + /// ``` + /// use euclid::default::Vector3D; + /// + /// let p = Vector3D::::new(5, 11, 15); + /// assert_eq!(p.map(|coord| coord.saturating_sub(10)), Vector3D::new(0, 1, 5)); + /// ``` + #[inline] + pub fn map V>(self, mut f: F) -> Vector3D { + vec3(f(self.x), f(self.y), f(self.z)) + } + + /// Apply the function `f` to each pair of components of this point and `rhs`. + /// + /// # Example + /// + /// This may be used to perform unusual arithmetic which is not already offered as methods. + /// + /// ``` + /// use euclid::default::Vector3D; + /// + /// let a: Vector3D = Vector3D::new(50, 200, 10); + /// let b: Vector3D = Vector3D::new(100, 100, 0); + /// assert_eq!(a.zip(b, u8::saturating_add), Vector3D::new(150, 255, 10)); + /// ``` + #[inline] + pub fn zip V>(self, rhs: Self, mut f: F) -> Vector3D { + vec3(f(self.x, rhs.x), f(self.y, rhs.y), f(self.z, rhs.z)) + } + /// Computes the vector with absolute values of each component. /// /// # Example