diff --git a/src/lib.rs b/src/lib.rs index 4a01e8e..0d5c0fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,10 +22,11 @@ //! concern ourselves with are listed below: //! //! - `VectorSpace`: Specifies the main operators for vectors, quaternions, and -//! matrices. +//! matrices. +//! - `MetricSpace`: For types that have a distance function implemented. //! - `InnerSpace`: For types that have a dot (or inner) product - ie. vectors or -//! quaternions. This also allows for the definition of operations that are -//! based on the dot product, like finding the magnitude or normalizing. +//! quaternions. This also allows for the definition of operations that are +//! based on the dot product, like finding the magnitude or normalizing. //! - `EuclideanSpace`: Points in euclidean space, with an associated space of //! displacement vectors. //! - `Matrix`: Common operations for matrices of arbitrary dimensions. diff --git a/src/point.rs b/src/point.rs index 387e046..350e197 100644 --- a/src/point.rs +++ b/src/point.rs @@ -109,6 +109,15 @@ macro_rules! impl_point { } } + impl MetricSpace for $PointN { + type Metric = S; + + #[inline] + fn distance2(self, other: Self) -> S { + (other - self).magnitude2() + } + } + impl EuclideanSpace for $PointN { type Scalar = S; type Diff = $VectorN; diff --git a/src/quaternion.rs b/src/quaternion.rs index 1bc1054..f94df92 100644 --- a/src/quaternion.rs +++ b/src/quaternion.rs @@ -129,6 +129,15 @@ impl VectorSpace for Quaternion { } } +impl MetricSpace for Quaternion { + type Metric = S; + + #[inline] + fn distance2(self, other: Self) -> S { + (other - self).magnitude2() + } +} + impl InnerSpace for Quaternion { #[inline] fn dot(self, other: Quaternion) -> S { diff --git a/src/structure.rs b/src/structure.rs index d9f8900..c889927 100644 --- a/src/structure.rs +++ b/src/structure.rs @@ -164,6 +164,26 @@ pub trait VectorSpace: Copy + Clone where fn zero() -> Self; } +/// A type with a distance function between values. +/// +/// Examples are vectors, points, and quaternions. +pub trait MetricSpace: Sized { + /// The metric to be returned by the `distance` function. + type Metric: BaseFloat; + + /// Returns the squared distance. + /// + /// This does not perform an expensive square root operation like in + /// `MetricSpace::distance` method, and so can be used to compare distances + /// more efficiently. + fn distance2(self, other: Self) -> Self::Metric; + + /// The distance between two values. + fn distance(self, other: Self) -> Self::Metric { + Float::sqrt(Self::distance2(self, other)) + } +} + /// Vectors that also have a [dot](https://en.wikipedia.org/wiki/Dot_product) /// (or [inner](https://en.wikipedia.org/wiki/Inner_product_space)) product. /// @@ -171,9 +191,10 @@ pub trait VectorSpace: Copy + Clone where /// finding the magnitude of a vector or normalizing it. /// /// Examples include vectors and quaternions. -pub trait InnerSpace: VectorSpace + Sized where +pub trait InnerSpace: VectorSpace where // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 ::Scalar: BaseFloat, + Self: MetricSpace::Scalar>, Self: ApproxEq::Scalar>, { /// Vector dot (or inner) product. @@ -185,11 +206,11 @@ pub trait InnerSpace: VectorSpace + Sized where Self::dot(self, other).approx_eq(&Self::Scalar::zero()) } - /// Returns the squared magnitude of the vector. + /// Returns the squared magnitude. /// /// This does not perform an expensive square root operation like in - /// `Vector::magnitude` method, and so can be used to compare vectors more - /// efficiently. + /// `InnerSpace::magnitude` method, and so can be used to compare magnitudes + /// more efficiently. #[inline] fn magnitude2(self) -> Self::Scalar { Self::dot(self, self) @@ -198,9 +219,6 @@ pub trait InnerSpace: VectorSpace + Sized where /// The distance from the tail to the tip of the vector. #[inline] fn magnitude(self) -> Self::Scalar { - use num_traits::Float; - - // FIXME: Not sure why we can't use method syntax for `sqrt` here... Float::sqrt(self.magnitude2()) } diff --git a/src/vector.rs b/src/vector.rs index b504d46..17cdb60 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -69,11 +69,11 @@ pub struct Vector4 { // Utility macro for generating associated functions for the vectors macro_rules! impl_vector { - ($VectorN:ident <$S:ident> { $($field:ident),+ }, $n:expr, $constructor:ident) => { - impl<$S> $VectorN<$S> { + ($VectorN:ident { $($field:ident),+ }, $n:expr, $constructor:ident) => { + impl $VectorN { /// Construct a new vector, using the provided values. #[inline] - pub fn new($($field: $S),+) -> $VectorN<$S> { + pub fn new($($field: S),+) -> $VectorN { $VectorN { $($field: $field),+ } } } @@ -84,7 +84,7 @@ macro_rules! impl_vector { $VectorN::new($($field),+) } - impl<$S: NumCast + Copy> $VectorN<$S> { + impl $VectorN { /// Component-wise casting to another type #[inline] pub fn cast(&self) -> $VectorN { @@ -92,6 +92,15 @@ macro_rules! impl_vector { } } + impl MetricSpace for $VectorN { + type Metric = S; + + #[inline] + fn distance2(self, other: Self) -> S { + (other - self).magnitude2() + } + } + impl Array for $VectorN { type Element = S; @@ -251,9 +260,9 @@ macro_rules! impl_scalar_ops { }; } -impl_vector!(Vector2 { x, y }, 2, vec2); -impl_vector!(Vector3 { x, y, z }, 3, vec3); -impl_vector!(Vector4 { x, y, z, w }, 4, vec4); +impl_vector!(Vector2 { x, y }, 2, vec2); +impl_vector!(Vector3 { x, y, z }, 3, vec3); +impl_vector!(Vector4 { x, y, z, w }, 4, vec4); impl_fixed_array_conversions!(Vector2 { x: 0, y: 1 }, 2); impl_fixed_array_conversions!(Vector3 { x: 0, y: 1, z: 2 }, 3);