diff --git a/codegen/README.md b/codegen/README.md index d9055792..d1d299db 100644 --- a/codegen/README.md +++ b/codegen/README.md @@ -77,6 +77,7 @@ Each template starts with setting up a number of common variables based on the inputs from the `codegen` program. Commonly used variables are: * `self_t` - the name of the type being generated +* `unsigned_scalar_t` - the unsigned version of `scalar_t` (e.g. `u8`, `u16`, `u32`) * `inner_t` - the inner storage type used by this type (e.g. `__m128` or `core::storage::XYZ`) * `deref_t` - the type used by the `Deref` and `DerefMut` implementation - not diff --git a/codegen/templates/vec.rs.tera b/codegen/templates/vec.rs.tera index 468cf321..83f1bd79 100644 --- a/codegen/templates/vec.rs.tera +++ b/codegen/templates/vec.rs.tera @@ -44,6 +44,7 @@ {% elif scalar_t == "i8" %} {% set is_signed = true %} {% set is_float = false %} + {% set unsigned_scalar_t = "u8" %} {% set self_t = "I8Vec" ~ dim %} {% set opposite_signedness_t = "U8Vec" ~ dim %} {% set vec2_t = "I8Vec2" %} @@ -53,6 +54,7 @@ {% elif scalar_t == "u8" %} {% set is_signed = false %} {% set is_float = false %} + {% set unsigned_scalar_t = "u8" %} {% set self_t = "U8Vec" ~ dim %} {% set opposite_signedness_t = "I8Vec" ~ dim %} {% set vec2_t = "U8Vec2" %} @@ -62,6 +64,7 @@ {% elif scalar_t == "i16" %} {% set is_signed = true %} {% set is_float = false %} + {% set unsigned_scalar_t = "u16" %} {% set self_t = "I16Vec" ~ dim %} {% set opposite_signedness_t = "U16Vec" ~ dim %} {% set vec2_t = "I16Vec2" %} @@ -72,6 +75,7 @@ {% elif scalar_t == "u16" %} {% set is_signed = false %} {% set is_float = false %} + {% set unsigned_scalar_t = "u16" %} {% set self_t = "U16Vec" ~ dim %} {% set opposite_signedness_t = "I16Vec" ~ dim %} {% set vec2_t = "U16Vec2" %} @@ -82,6 +86,7 @@ {% elif scalar_t == "i32" %} {% set is_signed = true %} {% set is_float = false %} + {% set unsigned_scalar_t = "u32" %} {% set self_t = "IVec" ~ dim %} {% set opposite_signedness_t = "UVec" ~ dim %} {% set vec2_t = "IVec2" %} @@ -92,6 +97,7 @@ {% elif scalar_t == "u32" %} {% set is_signed = false %} {% set is_float = false %} + {% set unsigned_scalar_t = "u32" %} {% set self_t = "UVec" ~ dim %} {% set opposite_signedness_t = "IVec" ~ dim %} {% set vec2_t = "UVec2" %} @@ -102,6 +108,7 @@ {% elif scalar_t == "i64" %} {% set is_signed = true %} {% set is_float = false %} + {% set unsigned_scalar_t = "u64" %} {% set self_t = "I64Vec" ~ dim %} {% set opposite_signedness_t = "U64Vec" ~ dim %} {% set vec2_t = "I64Vec2" %} @@ -112,6 +119,7 @@ {% elif scalar_t == "u64" %} {% set is_signed = false %} {% set is_float = false %} + {% set unsigned_scalar_t = "u64" %} {% set self_t = "U64Vec" ~ dim %} {% set opposite_signedness_t = "I64Vec" ~ dim %} {% set vec2_t = "U64Vec2" %} @@ -2166,6 +2174,61 @@ impl {{ self_t }} { {% endif %} {% endif %} +{% if not is_float %} + + /// Computes the [manhattan distance] between two points. + /// + /// # Overflow + /// This method may overflow if the result is greater than [`{{ unsigned_scalar_t }}::MAX`]. + /// + /// See also [`checked_manhattan_distance`][{{ self_t }}::checked_manhattan_distance]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn manhattan_distance(self, other: Self) -> {{ unsigned_scalar_t }} { + {% for c in components %} + {% if not loop.first %} + {% endif %} + self.{{c}}.abs_diff(other.{{c}}) + {% endfor %} + } + + /// Computes the [manhattan distance] between two points. + /// + /// This will returns [`None`] if the result is greater than [`{{ unsigned_scalar_t }}::MAX`]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn checked_manhattan_distance(self, other: Self) -> Option<{{ unsigned_scalar_t }}> { + {% for c in components %} + {%- if loop.first -%} + let d = self.{{c}}.abs_diff(other.{{c}}); + {%- elif loop.last -%} + d.checked_add(self.{{c}}.abs_diff(other.{{c}})) + {%- else -%} + let d = d.checked_add(self.{{c}}.abs_diff(other.{{c}}))?; + {%- endif -%} + {% endfor %} + } + + /// Computes the [chebyshev distance] between two points. + /// + /// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance + #[inline] + #[must_use] + pub fn chebyshev_distance(self, other: Self) -> {{ unsigned_scalar_t }} { + // Note: the compiler will eventually optimize out the loop + [ + {% for c in components %} + self.{{c}}.abs_diff(other.{{c}}), + {% endfor %} + ].into_iter().max().unwrap() + } + +{% endif %} + + {% if is_signed and dim == 2 %} /// Returns a vector that is equal to `self` rotated by 90 degrees. #[inline] diff --git a/src/i16/i16vec2.rs b/src/i16/i16vec2.rs index 0e58cfe3..45160836 100644 --- a/src/i16/i16vec2.rs +++ b/src/i16/i16vec2.rs @@ -377,6 +377,45 @@ impl I16Vec2 { Self::new(self.x.rem_euclid(rhs.x), self.y.rem_euclid(rhs.y)) } + /// Computes the [manhattan distance] between two points. + /// + /// # Overflow + /// This method may overflow if the result is greater than [`u16::MAX`]. + /// + /// See also [`checked_manhattan_distance`][I16Vec2::checked_manhattan_distance]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn manhattan_distance(self, other: Self) -> u16 { + self.x.abs_diff(other.x) + self.y.abs_diff(other.y) + } + + /// Computes the [manhattan distance] between two points. + /// + /// This will returns [`None`] if the result is greater than [`u16::MAX`]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn checked_manhattan_distance(self, other: Self) -> Option { + let d = self.x.abs_diff(other.x); + d.checked_add(self.y.abs_diff(other.y)) + } + + /// Computes the [chebyshev distance] between two points. + /// + /// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance + #[inline] + #[must_use] + pub fn chebyshev_distance(self, other: Self) -> u16 { + // Note: the compiler will eventually optimize out the loop + [self.x.abs_diff(other.x), self.y.abs_diff(other.y)] + .into_iter() + .max() + .unwrap() + } + /// Returns a vector that is equal to `self` rotated by 90 degrees. #[inline] #[must_use] diff --git a/src/i16/i16vec3.rs b/src/i16/i16vec3.rs index b435754f..b29a2146 100644 --- a/src/i16/i16vec3.rs +++ b/src/i16/i16vec3.rs @@ -441,6 +441,50 @@ impl I16Vec3 { ) } + /// Computes the [manhattan distance] between two points. + /// + /// # Overflow + /// This method may overflow if the result is greater than [`u16::MAX`]. + /// + /// See also [`checked_manhattan_distance`][I16Vec3::checked_manhattan_distance]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn manhattan_distance(self, other: Self) -> u16 { + self.x.abs_diff(other.x) + self.y.abs_diff(other.y) + self.z.abs_diff(other.z) + } + + /// Computes the [manhattan distance] between two points. + /// + /// This will returns [`None`] if the result is greater than [`u16::MAX`]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn checked_manhattan_distance(self, other: Self) -> Option { + let d = self.x.abs_diff(other.x); + let d = d.checked_add(self.y.abs_diff(other.y))?; + d.checked_add(self.z.abs_diff(other.z)) + } + + /// Computes the [chebyshev distance] between two points. + /// + /// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance + #[inline] + #[must_use] + pub fn chebyshev_distance(self, other: Self) -> u16 { + // Note: the compiler will eventually optimize out the loop + [ + self.x.abs_diff(other.x), + self.y.abs_diff(other.y), + self.z.abs_diff(other.z), + ] + .into_iter() + .max() + .unwrap() + } + /// Casts all elements of `self` to `f32`. #[inline] #[must_use] diff --git a/src/i16/i16vec4.rs b/src/i16/i16vec4.rs index 5b2bfa4f..de137d66 100644 --- a/src/i16/i16vec4.rs +++ b/src/i16/i16vec4.rs @@ -473,6 +473,55 @@ impl I16Vec4 { ) } + /// Computes the [manhattan distance] between two points. + /// + /// # Overflow + /// This method may overflow if the result is greater than [`u16::MAX`]. + /// + /// See also [`checked_manhattan_distance`][I16Vec4::checked_manhattan_distance]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn manhattan_distance(self, other: Self) -> u16 { + self.x.abs_diff(other.x) + + self.y.abs_diff(other.y) + + self.z.abs_diff(other.z) + + self.w.abs_diff(other.w) + } + + /// Computes the [manhattan distance] between two points. + /// + /// This will returns [`None`] if the result is greater than [`u16::MAX`]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn checked_manhattan_distance(self, other: Self) -> Option { + let d = self.x.abs_diff(other.x); + let d = d.checked_add(self.y.abs_diff(other.y))?; + let d = d.checked_add(self.z.abs_diff(other.z))?; + d.checked_add(self.w.abs_diff(other.w)) + } + + /// Computes the [chebyshev distance] between two points. + /// + /// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance + #[inline] + #[must_use] + pub fn chebyshev_distance(self, other: Self) -> u16 { + // Note: the compiler will eventually optimize out the loop + [ + self.x.abs_diff(other.x), + self.y.abs_diff(other.y), + self.z.abs_diff(other.z), + self.w.abs_diff(other.w), + ] + .into_iter() + .max() + .unwrap() + } + /// Casts all elements of `self` to `f32`. #[inline] #[must_use] diff --git a/src/i32/ivec2.rs b/src/i32/ivec2.rs index 90f45cfb..5743abb8 100644 --- a/src/i32/ivec2.rs +++ b/src/i32/ivec2.rs @@ -377,6 +377,45 @@ impl IVec2 { Self::new(self.x.rem_euclid(rhs.x), self.y.rem_euclid(rhs.y)) } + /// Computes the [manhattan distance] between two points. + /// + /// # Overflow + /// This method may overflow if the result is greater than [`u32::MAX`]. + /// + /// See also [`checked_manhattan_distance`][IVec2::checked_manhattan_distance]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn manhattan_distance(self, other: Self) -> u32 { + self.x.abs_diff(other.x) + self.y.abs_diff(other.y) + } + + /// Computes the [manhattan distance] between two points. + /// + /// This will returns [`None`] if the result is greater than [`u32::MAX`]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn checked_manhattan_distance(self, other: Self) -> Option { + let d = self.x.abs_diff(other.x); + d.checked_add(self.y.abs_diff(other.y)) + } + + /// Computes the [chebyshev distance] between two points. + /// + /// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance + #[inline] + #[must_use] + pub fn chebyshev_distance(self, other: Self) -> u32 { + // Note: the compiler will eventually optimize out the loop + [self.x.abs_diff(other.x), self.y.abs_diff(other.y)] + .into_iter() + .max() + .unwrap() + } + /// Returns a vector that is equal to `self` rotated by 90 degrees. #[inline] #[must_use] diff --git a/src/i32/ivec3.rs b/src/i32/ivec3.rs index 2c171029..e89ef0bb 100644 --- a/src/i32/ivec3.rs +++ b/src/i32/ivec3.rs @@ -441,6 +441,50 @@ impl IVec3 { ) } + /// Computes the [manhattan distance] between two points. + /// + /// # Overflow + /// This method may overflow if the result is greater than [`u32::MAX`]. + /// + /// See also [`checked_manhattan_distance`][IVec3::checked_manhattan_distance]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn manhattan_distance(self, other: Self) -> u32 { + self.x.abs_diff(other.x) + self.y.abs_diff(other.y) + self.z.abs_diff(other.z) + } + + /// Computes the [manhattan distance] between two points. + /// + /// This will returns [`None`] if the result is greater than [`u32::MAX`]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn checked_manhattan_distance(self, other: Self) -> Option { + let d = self.x.abs_diff(other.x); + let d = d.checked_add(self.y.abs_diff(other.y))?; + d.checked_add(self.z.abs_diff(other.z)) + } + + /// Computes the [chebyshev distance] between two points. + /// + /// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance + #[inline] + #[must_use] + pub fn chebyshev_distance(self, other: Self) -> u32 { + // Note: the compiler will eventually optimize out the loop + [ + self.x.abs_diff(other.x), + self.y.abs_diff(other.y), + self.z.abs_diff(other.z), + ] + .into_iter() + .max() + .unwrap() + } + /// Casts all elements of `self` to `f32`. #[inline] #[must_use] diff --git a/src/i32/ivec4.rs b/src/i32/ivec4.rs index a69f6ca0..1da0f928 100644 --- a/src/i32/ivec4.rs +++ b/src/i32/ivec4.rs @@ -473,6 +473,55 @@ impl IVec4 { ) } + /// Computes the [manhattan distance] between two points. + /// + /// # Overflow + /// This method may overflow if the result is greater than [`u32::MAX`]. + /// + /// See also [`checked_manhattan_distance`][IVec4::checked_manhattan_distance]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn manhattan_distance(self, other: Self) -> u32 { + self.x.abs_diff(other.x) + + self.y.abs_diff(other.y) + + self.z.abs_diff(other.z) + + self.w.abs_diff(other.w) + } + + /// Computes the [manhattan distance] between two points. + /// + /// This will returns [`None`] if the result is greater than [`u32::MAX`]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn checked_manhattan_distance(self, other: Self) -> Option { + let d = self.x.abs_diff(other.x); + let d = d.checked_add(self.y.abs_diff(other.y))?; + let d = d.checked_add(self.z.abs_diff(other.z))?; + d.checked_add(self.w.abs_diff(other.w)) + } + + /// Computes the [chebyshev distance] between two points. + /// + /// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance + #[inline] + #[must_use] + pub fn chebyshev_distance(self, other: Self) -> u32 { + // Note: the compiler will eventually optimize out the loop + [ + self.x.abs_diff(other.x), + self.y.abs_diff(other.y), + self.z.abs_diff(other.z), + self.w.abs_diff(other.w), + ] + .into_iter() + .max() + .unwrap() + } + /// Casts all elements of `self` to `f32`. #[inline] #[must_use] diff --git a/src/i64/i64vec2.rs b/src/i64/i64vec2.rs index 9a4c554b..8c110460 100644 --- a/src/i64/i64vec2.rs +++ b/src/i64/i64vec2.rs @@ -377,6 +377,45 @@ impl I64Vec2 { Self::new(self.x.rem_euclid(rhs.x), self.y.rem_euclid(rhs.y)) } + /// Computes the [manhattan distance] between two points. + /// + /// # Overflow + /// This method may overflow if the result is greater than [`u64::MAX`]. + /// + /// See also [`checked_manhattan_distance`][I64Vec2::checked_manhattan_distance]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn manhattan_distance(self, other: Self) -> u64 { + self.x.abs_diff(other.x) + self.y.abs_diff(other.y) + } + + /// Computes the [manhattan distance] between two points. + /// + /// This will returns [`None`] if the result is greater than [`u64::MAX`]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn checked_manhattan_distance(self, other: Self) -> Option { + let d = self.x.abs_diff(other.x); + d.checked_add(self.y.abs_diff(other.y)) + } + + /// Computes the [chebyshev distance] between two points. + /// + /// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance + #[inline] + #[must_use] + pub fn chebyshev_distance(self, other: Self) -> u64 { + // Note: the compiler will eventually optimize out the loop + [self.x.abs_diff(other.x), self.y.abs_diff(other.y)] + .into_iter() + .max() + .unwrap() + } + /// Returns a vector that is equal to `self` rotated by 90 degrees. #[inline] #[must_use] diff --git a/src/i64/i64vec3.rs b/src/i64/i64vec3.rs index dc46af03..86188699 100644 --- a/src/i64/i64vec3.rs +++ b/src/i64/i64vec3.rs @@ -441,6 +441,50 @@ impl I64Vec3 { ) } + /// Computes the [manhattan distance] between two points. + /// + /// # Overflow + /// This method may overflow if the result is greater than [`u64::MAX`]. + /// + /// See also [`checked_manhattan_distance`][I64Vec3::checked_manhattan_distance]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn manhattan_distance(self, other: Self) -> u64 { + self.x.abs_diff(other.x) + self.y.abs_diff(other.y) + self.z.abs_diff(other.z) + } + + /// Computes the [manhattan distance] between two points. + /// + /// This will returns [`None`] if the result is greater than [`u64::MAX`]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn checked_manhattan_distance(self, other: Self) -> Option { + let d = self.x.abs_diff(other.x); + let d = d.checked_add(self.y.abs_diff(other.y))?; + d.checked_add(self.z.abs_diff(other.z)) + } + + /// Computes the [chebyshev distance] between two points. + /// + /// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance + #[inline] + #[must_use] + pub fn chebyshev_distance(self, other: Self) -> u64 { + // Note: the compiler will eventually optimize out the loop + [ + self.x.abs_diff(other.x), + self.y.abs_diff(other.y), + self.z.abs_diff(other.z), + ] + .into_iter() + .max() + .unwrap() + } + /// Casts all elements of `self` to `f32`. #[inline] #[must_use] diff --git a/src/i64/i64vec4.rs b/src/i64/i64vec4.rs index ce35d831..bb78b6b1 100644 --- a/src/i64/i64vec4.rs +++ b/src/i64/i64vec4.rs @@ -473,6 +473,55 @@ impl I64Vec4 { ) } + /// Computes the [manhattan distance] between two points. + /// + /// # Overflow + /// This method may overflow if the result is greater than [`u64::MAX`]. + /// + /// See also [`checked_manhattan_distance`][I64Vec4::checked_manhattan_distance]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn manhattan_distance(self, other: Self) -> u64 { + self.x.abs_diff(other.x) + + self.y.abs_diff(other.y) + + self.z.abs_diff(other.z) + + self.w.abs_diff(other.w) + } + + /// Computes the [manhattan distance] between two points. + /// + /// This will returns [`None`] if the result is greater than [`u64::MAX`]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn checked_manhattan_distance(self, other: Self) -> Option { + let d = self.x.abs_diff(other.x); + let d = d.checked_add(self.y.abs_diff(other.y))?; + let d = d.checked_add(self.z.abs_diff(other.z))?; + d.checked_add(self.w.abs_diff(other.w)) + } + + /// Computes the [chebyshev distance] between two points. + /// + /// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance + #[inline] + #[must_use] + pub fn chebyshev_distance(self, other: Self) -> u64 { + // Note: the compiler will eventually optimize out the loop + [ + self.x.abs_diff(other.x), + self.y.abs_diff(other.y), + self.z.abs_diff(other.z), + self.w.abs_diff(other.w), + ] + .into_iter() + .max() + .unwrap() + } + /// Casts all elements of `self` to `f32`. #[inline] #[must_use] diff --git a/src/i8/i8vec2.rs b/src/i8/i8vec2.rs index 398760c5..284aac0f 100644 --- a/src/i8/i8vec2.rs +++ b/src/i8/i8vec2.rs @@ -377,6 +377,45 @@ impl I8Vec2 { Self::new(self.x.rem_euclid(rhs.x), self.y.rem_euclid(rhs.y)) } + /// Computes the [manhattan distance] between two points. + /// + /// # Overflow + /// This method may overflow if the result is greater than [`u8::MAX`]. + /// + /// See also [`checked_manhattan_distance`][I8Vec2::checked_manhattan_distance]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn manhattan_distance(self, other: Self) -> u8 { + self.x.abs_diff(other.x) + self.y.abs_diff(other.y) + } + + /// Computes the [manhattan distance] between two points. + /// + /// This will returns [`None`] if the result is greater than [`u8::MAX`]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn checked_manhattan_distance(self, other: Self) -> Option { + let d = self.x.abs_diff(other.x); + d.checked_add(self.y.abs_diff(other.y)) + } + + /// Computes the [chebyshev distance] between two points. + /// + /// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance + #[inline] + #[must_use] + pub fn chebyshev_distance(self, other: Self) -> u8 { + // Note: the compiler will eventually optimize out the loop + [self.x.abs_diff(other.x), self.y.abs_diff(other.y)] + .into_iter() + .max() + .unwrap() + } + /// Returns a vector that is equal to `self` rotated by 90 degrees. #[inline] #[must_use] diff --git a/src/i8/i8vec3.rs b/src/i8/i8vec3.rs index 382b9a85..400ac933 100644 --- a/src/i8/i8vec3.rs +++ b/src/i8/i8vec3.rs @@ -441,6 +441,50 @@ impl I8Vec3 { ) } + /// Computes the [manhattan distance] between two points. + /// + /// # Overflow + /// This method may overflow if the result is greater than [`u8::MAX`]. + /// + /// See also [`checked_manhattan_distance`][I8Vec3::checked_manhattan_distance]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn manhattan_distance(self, other: Self) -> u8 { + self.x.abs_diff(other.x) + self.y.abs_diff(other.y) + self.z.abs_diff(other.z) + } + + /// Computes the [manhattan distance] between two points. + /// + /// This will returns [`None`] if the result is greater than [`u8::MAX`]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn checked_manhattan_distance(self, other: Self) -> Option { + let d = self.x.abs_diff(other.x); + let d = d.checked_add(self.y.abs_diff(other.y))?; + d.checked_add(self.z.abs_diff(other.z)) + } + + /// Computes the [chebyshev distance] between two points. + /// + /// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance + #[inline] + #[must_use] + pub fn chebyshev_distance(self, other: Self) -> u8 { + // Note: the compiler will eventually optimize out the loop + [ + self.x.abs_diff(other.x), + self.y.abs_diff(other.y), + self.z.abs_diff(other.z), + ] + .into_iter() + .max() + .unwrap() + } + /// Casts all elements of `self` to `f32`. #[inline] #[must_use] diff --git a/src/i8/i8vec4.rs b/src/i8/i8vec4.rs index 2eb4531c..5ba0ce76 100644 --- a/src/i8/i8vec4.rs +++ b/src/i8/i8vec4.rs @@ -473,6 +473,55 @@ impl I8Vec4 { ) } + /// Computes the [manhattan distance] between two points. + /// + /// # Overflow + /// This method may overflow if the result is greater than [`u8::MAX`]. + /// + /// See also [`checked_manhattan_distance`][I8Vec4::checked_manhattan_distance]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn manhattan_distance(self, other: Self) -> u8 { + self.x.abs_diff(other.x) + + self.y.abs_diff(other.y) + + self.z.abs_diff(other.z) + + self.w.abs_diff(other.w) + } + + /// Computes the [manhattan distance] between two points. + /// + /// This will returns [`None`] if the result is greater than [`u8::MAX`]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn checked_manhattan_distance(self, other: Self) -> Option { + let d = self.x.abs_diff(other.x); + let d = d.checked_add(self.y.abs_diff(other.y))?; + let d = d.checked_add(self.z.abs_diff(other.z))?; + d.checked_add(self.w.abs_diff(other.w)) + } + + /// Computes the [chebyshev distance] between two points. + /// + /// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance + #[inline] + #[must_use] + pub fn chebyshev_distance(self, other: Self) -> u8 { + // Note: the compiler will eventually optimize out the loop + [ + self.x.abs_diff(other.x), + self.y.abs_diff(other.y), + self.z.abs_diff(other.z), + self.w.abs_diff(other.w), + ] + .into_iter() + .max() + .unwrap() + } + /// Casts all elements of `self` to `f32`. #[inline] #[must_use] diff --git a/src/u16/u16vec2.rs b/src/u16/u16vec2.rs index 67d74bef..47987c96 100644 --- a/src/u16/u16vec2.rs +++ b/src/u16/u16vec2.rs @@ -305,6 +305,45 @@ impl U16Vec2 { self.dot(self) } + /// Computes the [manhattan distance] between two points. + /// + /// # Overflow + /// This method may overflow if the result is greater than [`u16::MAX`]. + /// + /// See also [`checked_manhattan_distance`][U16Vec2::checked_manhattan_distance]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn manhattan_distance(self, other: Self) -> u16 { + self.x.abs_diff(other.x) + self.y.abs_diff(other.y) + } + + /// Computes the [manhattan distance] between two points. + /// + /// This will returns [`None`] if the result is greater than [`u16::MAX`]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn checked_manhattan_distance(self, other: Self) -> Option { + let d = self.x.abs_diff(other.x); + d.checked_add(self.y.abs_diff(other.y)) + } + + /// Computes the [chebyshev distance] between two points. + /// + /// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance + #[inline] + #[must_use] + pub fn chebyshev_distance(self, other: Self) -> u16 { + // Note: the compiler will eventually optimize out the loop + [self.x.abs_diff(other.x), self.y.abs_diff(other.y)] + .into_iter() + .max() + .unwrap() + } + /// Casts all elements of `self` to `f32`. #[inline] #[must_use] diff --git a/src/u16/u16vec3.rs b/src/u16/u16vec3.rs index 43e00234..5632671b 100644 --- a/src/u16/u16vec3.rs +++ b/src/u16/u16vec3.rs @@ -354,6 +354,50 @@ impl U16Vec3 { self.dot(self) } + /// Computes the [manhattan distance] between two points. + /// + /// # Overflow + /// This method may overflow if the result is greater than [`u16::MAX`]. + /// + /// See also [`checked_manhattan_distance`][U16Vec3::checked_manhattan_distance]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn manhattan_distance(self, other: Self) -> u16 { + self.x.abs_diff(other.x) + self.y.abs_diff(other.y) + self.z.abs_diff(other.z) + } + + /// Computes the [manhattan distance] between two points. + /// + /// This will returns [`None`] if the result is greater than [`u16::MAX`]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn checked_manhattan_distance(self, other: Self) -> Option { + let d = self.x.abs_diff(other.x); + let d = d.checked_add(self.y.abs_diff(other.y))?; + d.checked_add(self.z.abs_diff(other.z)) + } + + /// Computes the [chebyshev distance] between two points. + /// + /// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance + #[inline] + #[must_use] + pub fn chebyshev_distance(self, other: Self) -> u16 { + // Note: the compiler will eventually optimize out the loop + [ + self.x.abs_diff(other.x), + self.y.abs_diff(other.y), + self.z.abs_diff(other.z), + ] + .into_iter() + .max() + .unwrap() + } + /// Casts all elements of `self` to `f32`. #[inline] #[must_use] diff --git a/src/u16/u16vec4.rs b/src/u16/u16vec4.rs index 84121fde..60c94aea 100644 --- a/src/u16/u16vec4.rs +++ b/src/u16/u16vec4.rs @@ -378,6 +378,55 @@ impl U16Vec4 { self.dot(self) } + /// Computes the [manhattan distance] between two points. + /// + /// # Overflow + /// This method may overflow if the result is greater than [`u16::MAX`]. + /// + /// See also [`checked_manhattan_distance`][U16Vec4::checked_manhattan_distance]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn manhattan_distance(self, other: Self) -> u16 { + self.x.abs_diff(other.x) + + self.y.abs_diff(other.y) + + self.z.abs_diff(other.z) + + self.w.abs_diff(other.w) + } + + /// Computes the [manhattan distance] between two points. + /// + /// This will returns [`None`] if the result is greater than [`u16::MAX`]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn checked_manhattan_distance(self, other: Self) -> Option { + let d = self.x.abs_diff(other.x); + let d = d.checked_add(self.y.abs_diff(other.y))?; + let d = d.checked_add(self.z.abs_diff(other.z))?; + d.checked_add(self.w.abs_diff(other.w)) + } + + /// Computes the [chebyshev distance] between two points. + /// + /// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance + #[inline] + #[must_use] + pub fn chebyshev_distance(self, other: Self) -> u16 { + // Note: the compiler will eventually optimize out the loop + [ + self.x.abs_diff(other.x), + self.y.abs_diff(other.y), + self.z.abs_diff(other.z), + self.w.abs_diff(other.w), + ] + .into_iter() + .max() + .unwrap() + } + /// Casts all elements of `self` to `f32`. #[inline] #[must_use] diff --git a/src/u32/uvec2.rs b/src/u32/uvec2.rs index ca91ef06..1752654d 100644 --- a/src/u32/uvec2.rs +++ b/src/u32/uvec2.rs @@ -305,6 +305,45 @@ impl UVec2 { self.dot(self) } + /// Computes the [manhattan distance] between two points. + /// + /// # Overflow + /// This method may overflow if the result is greater than [`u32::MAX`]. + /// + /// See also [`checked_manhattan_distance`][UVec2::checked_manhattan_distance]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn manhattan_distance(self, other: Self) -> u32 { + self.x.abs_diff(other.x) + self.y.abs_diff(other.y) + } + + /// Computes the [manhattan distance] between two points. + /// + /// This will returns [`None`] if the result is greater than [`u32::MAX`]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn checked_manhattan_distance(self, other: Self) -> Option { + let d = self.x.abs_diff(other.x); + d.checked_add(self.y.abs_diff(other.y)) + } + + /// Computes the [chebyshev distance] between two points. + /// + /// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance + #[inline] + #[must_use] + pub fn chebyshev_distance(self, other: Self) -> u32 { + // Note: the compiler will eventually optimize out the loop + [self.x.abs_diff(other.x), self.y.abs_diff(other.y)] + .into_iter() + .max() + .unwrap() + } + /// Casts all elements of `self` to `f32`. #[inline] #[must_use] diff --git a/src/u32/uvec3.rs b/src/u32/uvec3.rs index 28fe407a..98b5c9b2 100644 --- a/src/u32/uvec3.rs +++ b/src/u32/uvec3.rs @@ -354,6 +354,50 @@ impl UVec3 { self.dot(self) } + /// Computes the [manhattan distance] between two points. + /// + /// # Overflow + /// This method may overflow if the result is greater than [`u32::MAX`]. + /// + /// See also [`checked_manhattan_distance`][UVec3::checked_manhattan_distance]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn manhattan_distance(self, other: Self) -> u32 { + self.x.abs_diff(other.x) + self.y.abs_diff(other.y) + self.z.abs_diff(other.z) + } + + /// Computes the [manhattan distance] between two points. + /// + /// This will returns [`None`] if the result is greater than [`u32::MAX`]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn checked_manhattan_distance(self, other: Self) -> Option { + let d = self.x.abs_diff(other.x); + let d = d.checked_add(self.y.abs_diff(other.y))?; + d.checked_add(self.z.abs_diff(other.z)) + } + + /// Computes the [chebyshev distance] between two points. + /// + /// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance + #[inline] + #[must_use] + pub fn chebyshev_distance(self, other: Self) -> u32 { + // Note: the compiler will eventually optimize out the loop + [ + self.x.abs_diff(other.x), + self.y.abs_diff(other.y), + self.z.abs_diff(other.z), + ] + .into_iter() + .max() + .unwrap() + } + /// Casts all elements of `self` to `f32`. #[inline] #[must_use] diff --git a/src/u32/uvec4.rs b/src/u32/uvec4.rs index d997f5b5..077d4aff 100644 --- a/src/u32/uvec4.rs +++ b/src/u32/uvec4.rs @@ -378,6 +378,55 @@ impl UVec4 { self.dot(self) } + /// Computes the [manhattan distance] between two points. + /// + /// # Overflow + /// This method may overflow if the result is greater than [`u32::MAX`]. + /// + /// See also [`checked_manhattan_distance`][UVec4::checked_manhattan_distance]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn manhattan_distance(self, other: Self) -> u32 { + self.x.abs_diff(other.x) + + self.y.abs_diff(other.y) + + self.z.abs_diff(other.z) + + self.w.abs_diff(other.w) + } + + /// Computes the [manhattan distance] between two points. + /// + /// This will returns [`None`] if the result is greater than [`u32::MAX`]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn checked_manhattan_distance(self, other: Self) -> Option { + let d = self.x.abs_diff(other.x); + let d = d.checked_add(self.y.abs_diff(other.y))?; + let d = d.checked_add(self.z.abs_diff(other.z))?; + d.checked_add(self.w.abs_diff(other.w)) + } + + /// Computes the [chebyshev distance] between two points. + /// + /// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance + #[inline] + #[must_use] + pub fn chebyshev_distance(self, other: Self) -> u32 { + // Note: the compiler will eventually optimize out the loop + [ + self.x.abs_diff(other.x), + self.y.abs_diff(other.y), + self.z.abs_diff(other.z), + self.w.abs_diff(other.w), + ] + .into_iter() + .max() + .unwrap() + } + /// Casts all elements of `self` to `f32`. #[inline] #[must_use] diff --git a/src/u64/u64vec2.rs b/src/u64/u64vec2.rs index fba69e0c..5461fc9d 100644 --- a/src/u64/u64vec2.rs +++ b/src/u64/u64vec2.rs @@ -305,6 +305,45 @@ impl U64Vec2 { self.dot(self) } + /// Computes the [manhattan distance] between two points. + /// + /// # Overflow + /// This method may overflow if the result is greater than [`u64::MAX`]. + /// + /// See also [`checked_manhattan_distance`][U64Vec2::checked_manhattan_distance]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn manhattan_distance(self, other: Self) -> u64 { + self.x.abs_diff(other.x) + self.y.abs_diff(other.y) + } + + /// Computes the [manhattan distance] between two points. + /// + /// This will returns [`None`] if the result is greater than [`u64::MAX`]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn checked_manhattan_distance(self, other: Self) -> Option { + let d = self.x.abs_diff(other.x); + d.checked_add(self.y.abs_diff(other.y)) + } + + /// Computes the [chebyshev distance] between two points. + /// + /// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance + #[inline] + #[must_use] + pub fn chebyshev_distance(self, other: Self) -> u64 { + // Note: the compiler will eventually optimize out the loop + [self.x.abs_diff(other.x), self.y.abs_diff(other.y)] + .into_iter() + .max() + .unwrap() + } + /// Casts all elements of `self` to `f32`. #[inline] #[must_use] diff --git a/src/u64/u64vec3.rs b/src/u64/u64vec3.rs index 3607882a..92391ff4 100644 --- a/src/u64/u64vec3.rs +++ b/src/u64/u64vec3.rs @@ -354,6 +354,50 @@ impl U64Vec3 { self.dot(self) } + /// Computes the [manhattan distance] between two points. + /// + /// # Overflow + /// This method may overflow if the result is greater than [`u64::MAX`]. + /// + /// See also [`checked_manhattan_distance`][U64Vec3::checked_manhattan_distance]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn manhattan_distance(self, other: Self) -> u64 { + self.x.abs_diff(other.x) + self.y.abs_diff(other.y) + self.z.abs_diff(other.z) + } + + /// Computes the [manhattan distance] between two points. + /// + /// This will returns [`None`] if the result is greater than [`u64::MAX`]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn checked_manhattan_distance(self, other: Self) -> Option { + let d = self.x.abs_diff(other.x); + let d = d.checked_add(self.y.abs_diff(other.y))?; + d.checked_add(self.z.abs_diff(other.z)) + } + + /// Computes the [chebyshev distance] between two points. + /// + /// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance + #[inline] + #[must_use] + pub fn chebyshev_distance(self, other: Self) -> u64 { + // Note: the compiler will eventually optimize out the loop + [ + self.x.abs_diff(other.x), + self.y.abs_diff(other.y), + self.z.abs_diff(other.z), + ] + .into_iter() + .max() + .unwrap() + } + /// Casts all elements of `self` to `f32`. #[inline] #[must_use] diff --git a/src/u64/u64vec4.rs b/src/u64/u64vec4.rs index 0772b525..3f3ebb22 100644 --- a/src/u64/u64vec4.rs +++ b/src/u64/u64vec4.rs @@ -378,6 +378,55 @@ impl U64Vec4 { self.dot(self) } + /// Computes the [manhattan distance] between two points. + /// + /// # Overflow + /// This method may overflow if the result is greater than [`u64::MAX`]. + /// + /// See also [`checked_manhattan_distance`][U64Vec4::checked_manhattan_distance]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn manhattan_distance(self, other: Self) -> u64 { + self.x.abs_diff(other.x) + + self.y.abs_diff(other.y) + + self.z.abs_diff(other.z) + + self.w.abs_diff(other.w) + } + + /// Computes the [manhattan distance] between two points. + /// + /// This will returns [`None`] if the result is greater than [`u64::MAX`]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn checked_manhattan_distance(self, other: Self) -> Option { + let d = self.x.abs_diff(other.x); + let d = d.checked_add(self.y.abs_diff(other.y))?; + let d = d.checked_add(self.z.abs_diff(other.z))?; + d.checked_add(self.w.abs_diff(other.w)) + } + + /// Computes the [chebyshev distance] between two points. + /// + /// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance + #[inline] + #[must_use] + pub fn chebyshev_distance(self, other: Self) -> u64 { + // Note: the compiler will eventually optimize out the loop + [ + self.x.abs_diff(other.x), + self.y.abs_diff(other.y), + self.z.abs_diff(other.z), + self.w.abs_diff(other.w), + ] + .into_iter() + .max() + .unwrap() + } + /// Casts all elements of `self` to `f32`. #[inline] #[must_use] diff --git a/src/u8/u8vec2.rs b/src/u8/u8vec2.rs index cc6decff..4a93faa4 100644 --- a/src/u8/u8vec2.rs +++ b/src/u8/u8vec2.rs @@ -305,6 +305,45 @@ impl U8Vec2 { self.dot(self) } + /// Computes the [manhattan distance] between two points. + /// + /// # Overflow + /// This method may overflow if the result is greater than [`u8::MAX`]. + /// + /// See also [`checked_manhattan_distance`][U8Vec2::checked_manhattan_distance]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn manhattan_distance(self, other: Self) -> u8 { + self.x.abs_diff(other.x) + self.y.abs_diff(other.y) + } + + /// Computes the [manhattan distance] between two points. + /// + /// This will returns [`None`] if the result is greater than [`u8::MAX`]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn checked_manhattan_distance(self, other: Self) -> Option { + let d = self.x.abs_diff(other.x); + d.checked_add(self.y.abs_diff(other.y)) + } + + /// Computes the [chebyshev distance] between two points. + /// + /// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance + #[inline] + #[must_use] + pub fn chebyshev_distance(self, other: Self) -> u8 { + // Note: the compiler will eventually optimize out the loop + [self.x.abs_diff(other.x), self.y.abs_diff(other.y)] + .into_iter() + .max() + .unwrap() + } + /// Casts all elements of `self` to `f32`. #[inline] #[must_use] diff --git a/src/u8/u8vec3.rs b/src/u8/u8vec3.rs index 752c12fa..ecaa95a0 100644 --- a/src/u8/u8vec3.rs +++ b/src/u8/u8vec3.rs @@ -354,6 +354,50 @@ impl U8Vec3 { self.dot(self) } + /// Computes the [manhattan distance] between two points. + /// + /// # Overflow + /// This method may overflow if the result is greater than [`u8::MAX`]. + /// + /// See also [`checked_manhattan_distance`][U8Vec3::checked_manhattan_distance]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn manhattan_distance(self, other: Self) -> u8 { + self.x.abs_diff(other.x) + self.y.abs_diff(other.y) + self.z.abs_diff(other.z) + } + + /// Computes the [manhattan distance] between two points. + /// + /// This will returns [`None`] if the result is greater than [`u8::MAX`]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn checked_manhattan_distance(self, other: Self) -> Option { + let d = self.x.abs_diff(other.x); + let d = d.checked_add(self.y.abs_diff(other.y))?; + d.checked_add(self.z.abs_diff(other.z)) + } + + /// Computes the [chebyshev distance] between two points. + /// + /// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance + #[inline] + #[must_use] + pub fn chebyshev_distance(self, other: Self) -> u8 { + // Note: the compiler will eventually optimize out the loop + [ + self.x.abs_diff(other.x), + self.y.abs_diff(other.y), + self.z.abs_diff(other.z), + ] + .into_iter() + .max() + .unwrap() + } + /// Casts all elements of `self` to `f32`. #[inline] #[must_use] diff --git a/src/u8/u8vec4.rs b/src/u8/u8vec4.rs index 8dbe4fc8..7593e3a9 100644 --- a/src/u8/u8vec4.rs +++ b/src/u8/u8vec4.rs @@ -378,6 +378,55 @@ impl U8Vec4 { self.dot(self) } + /// Computes the [manhattan distance] between two points. + /// + /// # Overflow + /// This method may overflow if the result is greater than [`u8::MAX`]. + /// + /// See also [`checked_manhattan_distance`][U8Vec4::checked_manhattan_distance]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn manhattan_distance(self, other: Self) -> u8 { + self.x.abs_diff(other.x) + + self.y.abs_diff(other.y) + + self.z.abs_diff(other.z) + + self.w.abs_diff(other.w) + } + + /// Computes the [manhattan distance] between two points. + /// + /// This will returns [`None`] if the result is greater than [`u8::MAX`]. + /// + /// [manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry + #[inline] + #[must_use] + pub fn checked_manhattan_distance(self, other: Self) -> Option { + let d = self.x.abs_diff(other.x); + let d = d.checked_add(self.y.abs_diff(other.y))?; + let d = d.checked_add(self.z.abs_diff(other.z))?; + d.checked_add(self.w.abs_diff(other.w)) + } + + /// Computes the [chebyshev distance] between two points. + /// + /// [chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance + #[inline] + #[must_use] + pub fn chebyshev_distance(self, other: Self) -> u8 { + // Note: the compiler will eventually optimize out the loop + [ + self.x.abs_diff(other.x), + self.y.abs_diff(other.y), + self.z.abs_diff(other.z), + self.w.abs_diff(other.w), + ] + .into_iter() + .max() + .unwrap() + } + /// Casts all elements of `self` to `f32`. #[inline] #[must_use] diff --git a/tests/vec2.rs b/tests/vec2.rs index e97e308e..9c4a63b4 100644 --- a/tests/vec2.rs +++ b/tests/vec2.rs @@ -734,6 +734,74 @@ macro_rules! impl_vec2_signed_integer_tests { assert_eq!($vec3::ONE.signum(), $vec3::ONE); assert_eq!((-$vec3::ONE).signum(), -$vec3::ONE); }); + + glam_test!(test_manhattan_distance, { + assert_eq!($vec2::new(5, 2).manhattan_distance($vec2::new(23, 16)), 32); + assert_eq!($vec2::new(30, 11).manhattan_distance($vec2::new(30, 11)), 0); + assert_eq!( + $vec2::new(-8, -23).manhattan_distance($vec2::new(12, 7)), + 50 + ); + + assert_eq!( + $vec2::new(5, 2).checked_manhattan_distance($vec2::new(23, 16)), + Some(32) + ); + assert_eq!( + $vec2::new(30, 11).checked_manhattan_distance($vec2::new(30, 11)), + Some(0) + ); + assert_eq!( + $vec2::new(-8, -23).checked_manhattan_distance($vec2::new(12, 7)), + Some(50) + ); + + assert_eq!( + $vec2::new($t::MIN, $t::MIN) + .checked_manhattan_distance($vec2::new($t::MAX, $t::MAX)), + None + ); + }); + + glam_test!(test_chebyshev_distance, { + assert_eq!($vec2::new(5, 2).chebyshev_distance($vec2::new(23, 16)), 18); + assert_eq!($vec2::new(30, 11).chebyshev_distance($vec2::new(30, 11)), 0); + assert_eq!( + $vec2::new(-8, -23).chebyshev_distance($vec2::new(12, 7)), + 30 + ); + }); + }; +} + +macro_rules! impl_vec2_unsigned_integer_tests { + ($t:ident, $new:ident, $vec2:ident, $vec3:ident, $mask:ident, $masknew:ident) => { + impl_vec2_tests!($t, $new, $vec2, $vec3, $mask, $masknew); + + glam_test!(test_manhattan_distance, { + assert_eq!($vec2::new(5, 2).manhattan_distance($vec2::new(23, 16)), 32); + assert_eq!($vec2::new(30, 11).manhattan_distance($vec2::new(30, 11)), 0); + + assert_eq!( + $vec2::new(5, 2).checked_manhattan_distance($vec2::new(23, 16)), + Some(32) + ); + assert_eq!( + $vec2::new(30, 11).checked_manhattan_distance($vec2::new(30, 11)), + Some(0) + ); + + assert_eq!( + $vec2::new($t::MIN, $t::MIN) + .checked_manhattan_distance($vec2::new($t::MAX, $t::MAX)), + None + ); + }); + + glam_test!(test_chebyshev_distance, { + assert_eq!($vec2::new(5, 2).chebyshev_distance($vec2::new(23, 16)), 18); + assert_eq!($vec2::new(30, 11).chebyshev_distance($vec2::new(30, 11)), 0); + }); }; } @@ -1727,7 +1795,7 @@ mod u8vec2 { ); }); - impl_vec2_tests!(u8, u8vec2, U8Vec2, U8Vec3, BVec2, bvec2); + impl_vec2_unsigned_integer_tests!(u8, u8vec2, U8Vec2, U8Vec3, BVec2, bvec2); impl_vec2_eq_hash_tests!(u8, u8vec2); impl_vec2_scalar_shift_op_tests!(U8Vec2, 0, 2); @@ -2020,7 +2088,7 @@ mod u16vec2 { ); }); - impl_vec2_tests!(u16, u16vec2, U16Vec2, U16Vec3, BVec2, bvec2); + impl_vec2_unsigned_integer_tests!(u16, u16vec2, U16Vec2, U16Vec3, BVec2, bvec2); impl_vec2_eq_hash_tests!(u16, u16vec2); impl_vec2_scalar_shift_op_tests!(U16Vec2, 0, 2); @@ -2295,7 +2363,7 @@ mod uvec2 { ); }); - impl_vec2_tests!(u32, uvec2, UVec2, UVec3, BVec2, bvec2); + impl_vec2_unsigned_integer_tests!(u32, uvec2, UVec2, UVec3, BVec2, bvec2); impl_vec2_eq_hash_tests!(u32, uvec2); impl_vec2_scalar_shift_op_tests!(UVec2, 0, 2); @@ -2443,7 +2511,7 @@ mod u64vec2 { ); }); - impl_vec2_tests!(u64, u64vec2, U64Vec2, U64Vec3, BVec2, bvec2); + impl_vec2_unsigned_integer_tests!(u64, u64vec2, U64Vec2, U64Vec3, BVec2, bvec2); impl_vec2_eq_hash_tests!(u64, u64vec2); impl_vec2_scalar_shift_op_tests!(U64Vec2, 0, 2); diff --git a/tests/vec3.rs b/tests/vec3.rs index 4f4ad052..05cbc95b 100644 --- a/tests/vec3.rs +++ b/tests/vec3.rs @@ -849,6 +849,104 @@ macro_rules! impl_vec3_signed_integer_tests { assert_eq!($vec3::ONE.signum(), $vec3::ONE); assert_eq!((-$vec3::ONE).signum(), -$vec3::ONE); }); + + glam_test!(test_manhattan_distance, { + assert_eq!( + $vec3::new(3, 27, 98).manhattan_distance($vec3::new(20, 65, 97)), + 56 + ); + assert_eq!( + $vec3::new(8, 12, 12).manhattan_distance($vec3::new(24, 56, 2)), + 70 + ); + assert_eq!( + $vec3::new(-23, 2, -99).manhattan_distance($vec3::new(22, -12, 24)), + 182 + ); + + assert_eq!( + $vec3::new(3, 27, 98).checked_manhattan_distance($vec3::new(20, 65, 97)), + Some(56) + ); + assert_eq!( + $vec3::new(8, 12, 12).checked_manhattan_distance($vec3::new(24, 56, 2)), + Some(70) + ); + assert_eq!( + $vec3::new(-23, 2, -99).checked_manhattan_distance($vec3::new(22, -12, 24)), + Some(182) + ); + + assert_eq!( + $vec3::new($t::MIN, $t::MIN, $t::MIN).checked_manhattan_distance($vec3::new( + $t::MAX, + $t::MAX, + $t::MAX + )), + None + ); + }); + + glam_test!(test_chebyshev_distance, { + assert_eq!( + $vec3::new(3, 27, 98).chebyshev_distance($vec3::new(20, 65, 97)), + 38 + ); + assert_eq!( + $vec3::new(8, 12, 12).chebyshev_distance($vec3::new(24, 56, 2)), + 44 + ); + assert_eq!( + $vec3::new(-23, 2, -99).chebyshev_distance($vec3::new(22, -12, 24)), + 123 + ); + }); + }; +} + +macro_rules! impl_vec3_unsigned_integer_tests { + ($t:ident, $new:ident, $vec3:ident, $mask:ident, $masknew:ident) => { + impl_vec3_tests!($t, $new, $vec3, $mask, $masknew); + + glam_test!(test_manhattan_distance, { + assert_eq!( + $vec3::new(3, 27, 98).manhattan_distance($vec3::new(20, 65, 97)), + 56 + ); + assert_eq!( + $vec3::new(8, 12, 12).manhattan_distance($vec3::new(24, 56, 2)), + 70 + ); + + assert_eq!( + $vec3::new(3, 27, 98).checked_manhattan_distance($vec3::new(20, 65, 97)), + Some(56) + ); + assert_eq!( + $vec3::new(8, 12, 12).checked_manhattan_distance($vec3::new(24, 56, 2)), + Some(70) + ); + + assert_eq!( + $vec3::new($t::MIN, $t::MIN, $t::MIN).checked_manhattan_distance($vec3::new( + $t::MAX, + $t::MAX, + $t::MAX + )), + None + ); + }); + + glam_test!(test_chebyshev_distance, { + assert_eq!( + $vec3::new(3, 27, 98).chebyshev_distance($vec3::new(20, 65, 97)), + 38 + ); + assert_eq!( + $vec3::new(8, 12, 12).chebyshev_distance($vec3::new(24, 56, 2)), + 44 + ); + }); }; } @@ -2073,7 +2171,7 @@ mod u8vec3 { ); }); - impl_vec3_tests!(u8, u8vec3, U8Vec3, BVec3, bvec3); + impl_vec3_unsigned_integer_tests!(u8, u8vec3, U8Vec3, BVec3, bvec3); impl_vec3_eq_hash_tests!(u8, u8vec3); impl_vec3_scalar_shift_op_tests!(U8Vec3, 0, 2); @@ -2376,7 +2474,7 @@ mod u16vec3 { ); }); - impl_vec3_tests!(u16, u16vec3, U16Vec3, BVec3, bvec3); + impl_vec3_unsigned_integer_tests!(u16, u16vec3, U16Vec3, BVec3, bvec3); impl_vec3_eq_hash_tests!(u16, u16vec3); impl_vec3_scalar_shift_op_tests!(U16Vec3, 0, 2); @@ -2658,7 +2756,7 @@ mod uvec3 { ); }); - impl_vec3_tests!(u32, uvec3, UVec3, BVec3, bvec3); + impl_vec3_unsigned_integer_tests!(u32, uvec3, UVec3, BVec3, bvec3); impl_vec3_eq_hash_tests!(u32, uvec3); impl_vec3_scalar_shift_op_tests!(UVec3, 0, 2); @@ -2805,7 +2903,7 @@ mod u64vec3 { ); }); - impl_vec3_tests!(u64, u64vec3, U64Vec3, BVec3, bvec3); + impl_vec3_unsigned_integer_tests!(u64, u64vec3, U64Vec3, BVec3, bvec3); impl_vec3_eq_hash_tests!(u64, u64vec3); impl_vec3_scalar_shift_op_tests!(U64Vec3, 0, 2); diff --git a/tests/vec4.rs b/tests/vec4.rs index 1abdaf21..75227516 100644 --- a/tests/vec4.rs +++ b/tests/vec4.rs @@ -967,6 +967,101 @@ macro_rules! impl_vec4_signed_integer_tests { assert_eq!($vec4::ONE.signum(), $vec4::ONE); assert_eq!((-$vec4::ONE).signum(), -$vec4::ONE); }); + + glam_test!(test_manhattan_distance, { + assert_eq!( + $vec4::new(41, 8, 21, 87).manhattan_distance($vec4::new(49, 48, 28, 40)), + 102 + ); + assert_eq!( + $vec4::new(19, 16, 100, 74).manhattan_distance($vec4::new(14, 55, 115, 48)), + 85 + ); + + assert_eq!( + $vec4::new(26, 2, 24, -22).manhattan_distance($vec4::new(26, 23, 6, 23)), + 84 + ); + + assert_eq!( + $vec4::new(41, 8, 21, 87).checked_manhattan_distance($vec4::new(49, 48, 28, 40)), + Some(102) + ); + assert_eq!( + $vec4::new(19, 16, 100, 74).checked_manhattan_distance($vec4::new(14, 55, 115, 48)), + Some(85) + ); + + assert_eq!( + $vec4::new(26, 2, 24, -22).checked_manhattan_distance($vec4::new(26, 23, 6, 23)), + Some(84) + ); + + assert_eq!( + $vec4::new($t::MIN, $t::MIN, $t::MIN, $t::MIN) + .checked_manhattan_distance($vec4::new($t::MAX, $t::MAX, $t::MAX, $t::MAX)), + None + ); + }); + + glam_test!(test_chebyshev_distance, { + assert_eq!( + $vec4::new(41, 8, 21, 87).chebyshev_distance($vec4::new(49, 48, 28, 40)), + 47 + ); + assert_eq!( + $vec4::new(119, 16, 100, 74).chebyshev_distance($vec4::new(14, 55, 115, 48)), + 105 + ); + assert_eq!( + $vec4::new(26, 2, 24, -22).chebyshev_distance($vec4::new(26, 23, 6, 23)), + 45 + ); + }); + }; +} + +macro_rules! impl_vec4_unsigned_integer_tests { + ($t:ident, $new:ident, $vec4:ident, $vec3:ident, $vec2:ident, $mask:ident, $masknew:ident) => { + impl_vec4_tests!($t, $new, $vec4, $vec3, $vec2, $mask, $masknew); + + glam_test!(test_manhattan_distance, { + assert_eq!( + $vec4::new(41, 8, 21, 87).manhattan_distance($vec4::new(49, 48, 128, 40)), + 202 + ); + assert_eq!( + $vec4::new(19, 16, 179, 174).manhattan_distance($vec4::new(14, 55, 115, 148)), + 134 + ); + + assert_eq!( + $vec4::new(41, 8, 21, 87).checked_manhattan_distance($vec4::new(49, 48, 128, 40)), + Some(202) + ); + assert_eq!( + $vec4::new(19, 16, 179, 174) + .checked_manhattan_distance($vec4::new(14, 55, 115, 148)), + Some(134) + ); + + assert_eq!( + $vec4::new($t::MIN, $t::MIN, $t::MIN, $t::MIN) + .checked_manhattan_distance($vec4::new($t::MAX, $t::MAX, $t::MAX, $t::MAX)), + None + ); + }); + + glam_test!(test_chebyshev_distance, { + assert_eq!( + $vec4::new(41, 8, 21, 87).chebyshev_distance($vec4::new(49, 48, 128, 40)), + 107 + ); + assert_eq!( + $vec4::new(119, 16, 179, 174).chebyshev_distance($vec4::new(14, 55, 115, 148)), + 105 + ); + }); }; } @@ -2324,7 +2419,7 @@ mod u8vec4 { ); }); - impl_vec4_tests!(u8, u8vec4, U8Vec4, U8Vec3, U8Vec2, BVec4, bvec4); + impl_vec4_unsigned_integer_tests!(u8, u8vec4, U8Vec4, U8Vec3, U8Vec2, BVec4, bvec4); impl_vec4_eq_hash_tests!(u8, u8vec4); impl_vec4_scalar_shift_op_tests!(U8Vec4, 0, 2); @@ -2666,7 +2761,7 @@ mod u16vec4 { ); }); - impl_vec4_tests!(u16, u16vec4, U16Vec4, U16Vec3, U16Vec2, BVec4, bvec4); + impl_vec4_unsigned_integer_tests!(u16, u16vec4, U16Vec4, U16Vec3, U16Vec2, BVec4, bvec4); impl_vec4_eq_hash_tests!(u16, u16vec4); impl_vec4_scalar_shift_op_tests!(U16Vec4, 0, 2); @@ -2980,7 +3075,7 @@ mod uvec4 { ); }); - impl_vec4_tests!(u32, uvec4, UVec4, UVec3, UVec2, BVec4, bvec4); + impl_vec4_unsigned_integer_tests!(u32, uvec4, UVec4, UVec3, UVec2, BVec4, bvec4); impl_vec4_eq_hash_tests!(u32, uvec4); impl_vec4_scalar_shift_op_tests!(UVec4, 0, 2); @@ -3171,7 +3266,7 @@ mod u64vec4 { ); }); - impl_vec4_tests!(u64, u64vec4, U64Vec4, U64Vec3, U64Vec2, BVec4, bvec4); + impl_vec4_unsigned_integer_tests!(u64, u64vec4, U64Vec4, U64Vec3, U64Vec2, BVec4, bvec4); impl_vec4_eq_hash_tests!(u64, u64vec4); impl_vec4_scalar_shift_op_tests!(U64Vec4, 0, 2);