Skip to content

Commit

Permalink
Add map() and zip() to point and vector types. (#509)
Browse files Browse the repository at this point in the history
These methods may be used to conveniently perform component-wise
operations that aren't already provided as other methods.
  • Loading branch information
kpreid authored Sep 28, 2023
1 parent d99c995 commit e1c97ad
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 0 deletions.
70 changes: 70 additions & 0 deletions src/point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,41 @@ impl<T, U> Point2D<T, U> {
pub fn from_untyped(p: Point2D<T, UnknownUnit>) -> 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::<u32>::new(5, 15);
/// assert_eq!(p.map(|coord| coord.saturating_sub(10)), Point2D::new(0, 5));
/// ```
#[inline]
pub fn map<V, F: FnMut(T) -> V>(self, mut f: F) -> Point2D<V, U> {
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<u32> = point2(50, 200);
/// let b: Point2D<u32> = point2(100, 100);
/// assert_eq!(a.zip(b, u32::saturating_sub), Vector2D::new(0, 100));
/// ```
#[inline]
pub fn zip<V, F: FnMut(T, T) -> V>(self, rhs: Self, mut f: F) -> Vector2D<V, U> {
vec2(f(self.x, rhs.x), f(self.y, rhs.y))
}
}

impl<T: Copy, U> Point2D<T, U> {
Expand Down Expand Up @@ -933,6 +968,41 @@ impl<T, U> Point3D<T, U> {
pub fn from_untyped(p: Point3D<T, UnknownUnit>) -> 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::<u32>::new(5, 11, 15);
/// assert_eq!(p.map(|coord| coord.saturating_sub(10)), Point3D::new(0, 1, 5));
/// ```
#[inline]
pub fn map<V, F: FnMut(T) -> V>(self, mut f: F) -> Point3D<V, U> {
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<u32> = Point3D::new(50, 200, 400);
/// let b: Point3D<u32> = Point3D::new(100, 100, 150);
/// assert_eq!(a.zip(b, u32::saturating_sub), Vector3D::new(0, 100, 250));
/// ```
#[inline]
pub fn zip<V, F: FnMut(T, T) -> V>(self, rhs: Self, mut f: F) -> Vector3D<V, U> {
vec3(f(self.x, rhs.x), f(self.y, rhs.y), f(self.z, rhs.z))
}
}

impl<T: Copy, U> Point3D<T, U> {
Expand Down
70 changes: 70 additions & 0 deletions src/vector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,41 @@ impl<T, U> Vector2D<T, U> {
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::<u32>::new(5, 11);
/// assert_eq!(p.map(|coord| coord.saturating_sub(10)), Vector2D::new(0, 1));
/// ```
#[inline]
pub fn map<V, F: FnMut(T) -> V>(self, mut f: F) -> Vector2D<V, U> {
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<u8> = Vector2D::new(50, 200);
/// let b: Vector2D<u8> = Vector2D::new(100, 100);
/// assert_eq!(a.zip(b, u8::saturating_add), Vector2D::new(150, 255));
/// ```
#[inline]
pub fn zip<V, F: FnMut(T, T) -> V>(self, rhs: Self, mut f: F) -> Vector2D<V, U> {
vec2(f(self.x, rhs.x), f(self.y, rhs.y))
}

/// Computes the vector with absolute values of each component.
///
/// # Example
Expand Down Expand Up @@ -1067,6 +1102,41 @@ impl<T, U> Vector3D<T, U> {
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::<u32>::new(5, 11, 15);
/// assert_eq!(p.map(|coord| coord.saturating_sub(10)), Vector3D::new(0, 1, 5));
/// ```
#[inline]
pub fn map<V, F: FnMut(T) -> V>(self, mut f: F) -> Vector3D<V, U> {
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<u8> = Vector3D::new(50, 200, 10);
/// let b: Vector3D<u8> = Vector3D::new(100, 100, 0);
/// assert_eq!(a.zip(b, u8::saturating_add), Vector3D::new(150, 255, 10));
/// ```
#[inline]
pub fn zip<V, F: FnMut(T, T) -> V>(self, rhs: Self, mut f: F) -> Vector3D<V, U> {
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
Expand Down

0 comments on commit e1c97ad

Please sign in to comment.