Remove Float bound from MetricSpace and InnerSpace; move Float bound to individual methods

This makes it possible to call methods like `dot` on integers.
This commit is contained in:
Nathan Stoddard 2020-06-02 20:38:50 -07:00 committed by Dzmitry Malyshau
parent 9dcd9fc3dd
commit 8d0e3f4eae
2 changed files with 31 additions and 26 deletions

View file

@ -195,7 +195,7 @@ where
/// Examples are vectors, points, and quaternions. /// Examples are vectors, points, and quaternions.
pub trait MetricSpace: Sized { pub trait MetricSpace: Sized {
/// The metric to be returned by the `distance` function. /// The metric to be returned by the `distance` function.
type Metric: Float; type Metric;
/// Returns the squared distance. /// Returns the squared distance.
/// ///
@ -205,7 +205,7 @@ pub trait MetricSpace: Sized {
fn distance2(self, other: Self) -> Self::Metric; fn distance2(self, other: Self) -> Self::Metric;
/// The distance between two values. /// The distance between two values.
fn distance(self, other: Self) -> Self::Metric { fn distance(self, other: Self) -> Self::Metric where Self::Metric: Float {
Float::sqrt(Self::distance2(self, other)) Float::sqrt(Self::distance2(self, other))
} }
} }
@ -219,7 +219,6 @@ pub trait MetricSpace: Sized {
/// Examples include vectors and quaternions. /// Examples include vectors and quaternions.
pub trait InnerSpace: VectorSpace pub trait InnerSpace: VectorSpace
where where
Self::Scalar: Float,
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
Self: MetricSpace<Metric = <Self as VectorSpace>::Scalar> Self: MetricSpace<Metric = <Self as VectorSpace>::Scalar>
{ {
@ -242,29 +241,11 @@ where
Self::dot(self, self) Self::dot(self, self)
} }
/// The distance from the tail to the tip of the vector.
#[inline]
fn magnitude(self) -> Self::Scalar {
Float::sqrt(self.magnitude2())
}
/// Returns the angle between two vectors in radians. /// Returns the angle between two vectors in radians.
fn angle(self, other: Self) -> Rad<Self::Scalar> where Self::Scalar: BaseFloat { fn angle(self, other: Self) -> Rad<Self::Scalar> where Self::Scalar: BaseFloat {
Rad::acos(Self::dot(self, other) / (self.magnitude() * other.magnitude())) Rad::acos(Self::dot(self, other) / (self.magnitude() * other.magnitude()))
} }
/// Returns a vector with the same direction, but with a magnitude of `1`.
#[inline]
fn normalize(self) -> Self {
self.normalize_to(Self::Scalar::one())
}
/// Returns a vector with the same direction and a given magnitude.
#[inline]
fn normalize_to(self, magnitude: Self::Scalar) -> Self {
self * (magnitude / self.magnitude())
}
/// Returns the /// Returns the
/// [vector projection](https://en.wikipedia.org/wiki/Vector_projection) /// [vector projection](https://en.wikipedia.org/wiki/Vector_projection)
/// of the current inner space projected onto the supplied argument. /// of the current inner space projected onto the supplied argument.
@ -272,6 +253,24 @@ where
fn project_on(self, other: Self) -> Self { fn project_on(self, other: Self) -> Self {
other * (self.dot(other) / other.magnitude2()) other * (self.dot(other) / other.magnitude2())
} }
/// The distance from the tail to the tip of the vector.
#[inline]
fn magnitude(self) -> Self::Scalar where Self::Scalar: Float {
Float::sqrt(self.magnitude2())
}
/// Returns a vector with the same direction, but with a magnitude of `1`.
#[inline]
fn normalize(self) -> Self where Self::Scalar: Float {
self.normalize_to(Self::Scalar::one())
}
/// Returns a vector with the same direction and a given magnitude.
#[inline]
fn normalize_to(self, magnitude: Self::Scalar) -> Self where Self::Scalar: Float {
self * (magnitude / self.magnitude())
}
} }
/// Points in a [Euclidean space](https://en.wikipedia.org/wiki/Euclidean_space) /// Points in a [Euclidean space](https://en.wikipedia.org/wiki/Euclidean_space)

View file

@ -139,7 +139,7 @@ macro_rules! impl_vector {
} }
} }
impl<S: BaseNum + Float> MetricSpace for $VectorN<S> { impl<S: BaseNum> MetricSpace for $VectorN<S> {
type Metric = S; type Metric = S;
#[inline] #[inline]
@ -525,14 +525,14 @@ where
V::dot(a, b) V::dot(a, b)
} }
impl<S: BaseNum + Float> InnerSpace for Vector1<S> { impl<S: BaseNum> InnerSpace for Vector1<S> {
#[inline] #[inline]
fn dot(self, other: Vector1<S>) -> S { fn dot(self, other: Vector1<S>) -> S {
Vector1::mul_element_wise(self, other).sum() Vector1::mul_element_wise(self, other).sum()
} }
} }
impl<S: BaseNum + Float> InnerSpace for Vector2<S> { impl<S: BaseNum> InnerSpace for Vector2<S> {
#[inline] #[inline]
fn dot(self, other: Vector2<S>) -> S { fn dot(self, other: Vector2<S>) -> S {
Vector2::mul_element_wise(self, other).sum() Vector2::mul_element_wise(self, other).sum()
@ -544,7 +544,7 @@ impl<S: BaseNum + Float> InnerSpace for Vector2<S> {
} }
} }
impl<S: BaseNum + Float> InnerSpace for Vector3<S> { impl<S: BaseNum> InnerSpace for Vector3<S> {
#[inline] #[inline]
fn dot(self, other: Vector3<S>) -> S { fn dot(self, other: Vector3<S>) -> S {
Vector3::mul_element_wise(self, other).sum() Vector3::mul_element_wise(self, other).sum()
@ -556,7 +556,7 @@ impl<S: BaseNum + Float> InnerSpace for Vector3<S> {
} }
} }
impl<S: BaseNum + Float> InnerSpace for Vector4<S> { impl<S: BaseNum> InnerSpace for Vector4<S> {
#[inline] #[inline]
fn dot(self, other: Vector4<S>) -> S { fn dot(self, other: Vector4<S>) -> S {
Vector4::mul_element_wise(self, other).sum() Vector4::mul_element_wise(self, other).sum()
@ -966,5 +966,11 @@ mod tests {
Vector4::new(-2, 1, 0, 1).zip(Vector4::new(-1, -1, -1, -1), |a, b| a < b) Vector4::new(-2, 1, 0, 1).zip(Vector4::new(-1, -1, -1, -1), |a, b| a < b)
); );
} }
#[test]
fn test_dot() {
assert_eq!(vec3(1.0, 2.0, 3.0).dot(vec3(4.0, 5.0, 6.0)), 32.0);
assert_eq!(vec3(1, 2, 3).dot(vec3(4, 5, 6)), 32);
}
} }
} }