Move element-wise operations into Array1 trait

This commit is contained in:
Brendan Zabarauskas 2015-11-14 12:03:12 +11:00
parent 137c3a7b0a
commit 25ca567060
5 changed files with 69 additions and 37 deletions

View file

@ -17,6 +17,8 @@ use std::mem;
use std::ptr;
use std::ops::*;
use num::PartialOrd;
/// An array containing elements of type `Element`
pub trait Array1 where
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
@ -47,6 +49,18 @@ pub trait Array1 where
fn replace_elem(&mut self, i: usize, src: Self::Element) -> Self::Element {
mem::replace(&mut self[i], src)
}
/// The sum of the elements of the array.
fn sum(self) -> Self::Element where Self::Element: Add<Output = <Self as Array1>::Element>;
/// The product of the elements of the array.
fn product(self) -> Self::Element where Self::Element: Mul<Output = <Self as Array1>::Element>;
/// The minimum element of the array.
fn min(self) -> Self::Element where Self::Element: PartialOrd;
/// The maximum element of the array.
fn max(self) -> Self::Element where Self::Element: PartialOrd;
}
/// A column-major array

View file

@ -132,6 +132,22 @@ pub trait Point: Copy + Clone where
impl<S: BaseNum> Array1 for Point2<S> {
type Element = S;
fn sum(self) -> S {
self.x + self.y
}
fn product(self) -> S {
self.x * self.y
}
fn min(self) -> S {
self.x.partial_min(self.y)
}
fn max(self) -> S {
self.x.partial_max(self.y)
}
}
impl<S: BaseNum> Point for Point2<S> {
@ -212,6 +228,22 @@ impl<S: BaseFloat> ApproxEq for Point2<S> {
impl<S: BaseNum> Array1 for Point3<S> {
type Element = S;
fn sum(self) -> S {
self.x + self.y + self.z
}
fn product(self) -> S {
self.x * self.y * self.z
}
fn min(self) -> S {
self.x.partial_min(self.y).partial_min(self.z)
}
fn max(self) -> S {
self.x.partial_max(self.y).partial_max(self.z)
}
}
impl<S: BaseNum> Point for Point3<S> {

View file

@ -24,7 +24,6 @@ use rust_num::traits::cast;
use angle::{Angle, Rad, acos, sin, sin_cos, rad};
use approx::ApproxEq;
use array::Array1;
use matrix::{Matrix3, Matrix4};
use num::BaseFloat;
use point::Point3;
@ -40,10 +39,6 @@ pub struct Quaternion<S> {
pub v: Vector3<S>,
}
impl<S: Copy + BaseFloat> Array1 for Quaternion<S> {
type Element = S;
}
impl<S: BaseFloat> Quaternion<S> {
/// Construct a new quaternion from one scalar component and three
/// imaginary components

View file

@ -106,7 +106,7 @@ use rust_num::{NumCast, Zero, One};
use angle::{Rad, atan2, acos};
use approx::ApproxEq;
use array::Array1;
use num::{BaseNum, BaseFloat};
use num::{BaseNum, BaseFloat, PartialOrd};
/// A trait that specifies a range of numeric operations for vectors. Not all
/// of these make sense from a linear algebra point of view, but are included
@ -196,19 +196,8 @@ pub trait Vector: Copy + Clone where
/// Take the remainder of this vector by another, in-place.
fn rem_self_v(&mut self, v: Self);
/// The sum of the components of the vector.
fn sum(self) -> Self::Scalar;
/// The product of the components of the vector.
fn product(self) -> Self::Scalar;
/// Vector dot product.
#[inline]
fn dot(self, v: Self) -> Self::Scalar { self.mul_v(v).sum() }
/// The minimum component of the vector.
fn comp_min(self) -> Self::Scalar;
/// The maximum component of the vector.
fn comp_max(self) -> Self::Scalar;
/// Vector dot product
fn dot(self, other: Self) -> Self::Scalar;
}
/// Dot product of two vectors.
@ -252,6 +241,11 @@ macro_rules! vec {
impl<S: Copy> Array1 for $VectorN<S> {
type Element = S;
#[inline] fn sum(self) -> S where S: Add<Output = S> { fold!(add, { $(self.$field),+ }) }
#[inline] fn product(self) -> S where S: Mul<Output = S> { fold!(mul, { $(self.$field),+ }) }
#[inline] fn min(self) -> S where S: PartialOrd { fold!(partial_min, { $(self.$field),+ }) }
#[inline] fn max(self) -> S where S: PartialOrd { fold!(partial_max, { $(self.$field),+ }) }
}
impl<S: BaseNum> Vector for $VectorN<S> {
@ -283,10 +277,7 @@ macro_rules! vec {
#[inline] fn div_self_v(&mut self, v: $VectorN<S>) { *self = &*self / v; }
#[inline] fn rem_self_v(&mut self, v: $VectorN<S>) { *self = &*self % v; }
#[inline] fn sum(self) -> S { fold!(add, { $(self.$field),+ }) }
#[inline] fn product(self) -> S { fold!(mul, { $(self.$field),+ }) }
#[inline] fn comp_min(self) -> S { fold!(partial_min, { $(self.$field),+ }) }
#[inline] fn comp_max(self) -> S { fold!(partial_max, { $(self.$field),+ }) }
#[inline] fn dot(self, other: $VectorN<S>) -> S { (self * other).sum() }
}
impl<S: Neg<Output = S>> Neg for $VectorN<S> {

View file

@ -63,25 +63,25 @@ fn test_product() {
}
#[test]
fn test_comp_min() {
assert_eq!(Vector2::new(1isize, 2isize).comp_min(), 1isize);
assert_eq!(Vector3::new(1isize, 2isize, 3isize).comp_min(), 1isize);
assert_eq!(Vector4::new(1isize, 2isize, 3isize, 4isize).comp_min(), 1isize);
fn test_min() {
assert_eq!(Vector2::new(1isize, 2isize).min(), 1isize);
assert_eq!(Vector3::new(1isize, 2isize, 3isize).min(), 1isize);
assert_eq!(Vector4::new(1isize, 2isize, 3isize, 4isize).min(), 1isize);
assert_eq!(Vector2::new(3.0f64, 4.0f64).comp_min(), 3.0f64);
assert_eq!(Vector3::new(4.0f64, 5.0f64, 6.0f64).comp_min(), 4.0f64);
assert_eq!(Vector4::new(5.0f64, 6.0f64, 7.0f64, 8.0f64).comp_min(), 5.0f64);
assert_eq!(Vector2::new(3.0f64, 4.0f64).min(), 3.0f64);
assert_eq!(Vector3::new(4.0f64, 5.0f64, 6.0f64).min(), 4.0f64);
assert_eq!(Vector4::new(5.0f64, 6.0f64, 7.0f64, 8.0f64).min(), 5.0f64);
}
#[test]
fn test_comp_max() {
assert_eq!(Vector2::new(1isize, 2isize).comp_max(), 2isize);
assert_eq!(Vector3::new(1isize, 2isize, 3isize).comp_max(), 3isize);
assert_eq!(Vector4::new(1isize, 2isize, 3isize, 4isize).comp_max(), 4isize);
fn test_max() {
assert_eq!(Vector2::new(1isize, 2isize).max(), 2isize);
assert_eq!(Vector3::new(1isize, 2isize, 3isize).max(), 3isize);
assert_eq!(Vector4::new(1isize, 2isize, 3isize, 4isize).max(), 4isize);
assert_eq!(Vector2::new(3.0f64, 4.0f64).comp_max(), 4.0f64);
assert_eq!(Vector3::new(4.0f64, 5.0f64, 6.0f64).comp_max(), 6.0f64);
assert_eq!(Vector4::new(5.0f64, 6.0f64, 7.0f64, 8.0f64).comp_max(), 8.0f64);
assert_eq!(Vector2::new(3.0f64, 4.0f64).max(), 4.0f64);
assert_eq!(Vector3::new(4.0f64, 5.0f64, 6.0f64).max(), 6.0f64);
assert_eq!(Vector4::new(5.0f64, 6.0f64, 7.0f64, 8.0f64).max(), 8.0f64);
}
#[test]