//! Module containing the vector struct. use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign, Index, IndexMut}; use num::Zero; use num::Float; use math::Number; macro_rules! make_vector { ( $name: ident, $number: expr, ( $( $t: ident) , * ), $( ($x: ident, $x_mut: ident, $y: expr) ), * ) => { /// The vector struct. #[derive(Debug, Copy, Clone, PartialEq)] pub struct $name { data: [T; $number], } impl $name { /// Creates a vector from its coordinates. pub fn new( $( $x: T ) , *) -> $name { $name:: { data: [ $( $x ) , *], } } /// Returns the length of the vector. pub fn len(&self) -> usize { return $number; } } impl Into<($( $t ) ,* )> for $name { fn into(self) -> ($( $t ) ,* ) { ( $( self.data[$y] ), *) } } impl Zero for $name { fn zero() -> $name { $name:: { data: [ T::zero(); $number ], } } fn is_zero(&self) -> bool { for x in &self.data { if ! x.is_zero() { return false; } } true } } impl $name { $( /// Get the coordinate of the vector. pub fn $x(&self) -> T { self.data[$y] } )* } impl $name { /// Computes the dot product between two vectors. pub fn dot(&self, rhs: $name) -> T { $( self.data[$y] * rhs.data[$y] + )* T::zero() } } impl $name { /// Computes the iso barycenter of a list of vectors. pub fn barycenter(vectors: &[&$name]) -> $name { use num::Zero; let mut sum = $name::::zero(); let mut denom = T::zero(); for v in vectors.iter() { sum += **v; denom += T::one(); } sum / denom } /// Computes the square of the 2-norm of the vector. pub fn norm2(&self) -> T { let mut res = T::zero(); for x in self.data.iter() { res += *x * *x; } res } } impl $name { /// Computes the 2-norm of the vector pub fn norm(&self) -> T { self.norm2().sqrt() } } impl Add for $name { type Output = $name; fn add(self, rhs: $name) -> Self::Output { $name::::new( $( self.data[$y] + rhs.data[$y] ) , *) } } impl AddAssign for $name { fn add_assign(&mut self, rhs: $name) { $( self.data[$y] += rhs.data[$y]; )* } } impl Sub for $name { type Output = $name; fn sub(self, rhs: $name) -> Self::Output { $name::::new( $( self.data[$y] - rhs.data[$y] ) , *) } } impl SubAssign for $name { fn sub_assign(&mut self, rhs: $name) { $( self.data[$y] -= rhs.data[$y]; )* } } impl Mul for $name { type Output = $name; fn mul(self, rhs: T) -> Self::Output { $name::::new( $( self.data[$y] * rhs ), *) } } impl MulAssign for $name { fn mul_assign(&mut self, rhs: T) { $( self.data[$y] *= rhs; )* } } impl Div for $name { type Output = $name; fn div(self, rhs: T) -> Self::Output { $name::::new( $( self.data[$y] / rhs ), *) } } impl DivAssign for $name { fn div_assign(&mut self, rhs: T) { $( self.data[$y] /= rhs; )* } } impl Index for $name { type Output = T; fn index(&self, index: usize) -> &T { &self.data[index] } } impl IndexMut for $name { fn index_mut(&mut self, index: usize) -> &mut T { &mut self.data[index] } } // impl PartialEq for $name { // fn eq(&self, other: &$name) -> bool { // for (x1, x2) in self.data.iter().zip(other.data.iter()) { // if x1 != x2 { // return false; // } // } // true // } // } }; } make_vector!(Vector2, 2, (T, T), (x, x_mut, 0), (y, y_mut, 1)); make_vector!(Vector3, 3, (T, T, T), (x, x_mut, 0), (y, y_mut, 1), (z, z_mut, 2)); make_vector!(Vector4, 4, (T, T, T, T), (x, x_mut, 0), (y, y_mut, 1), (z, z_mut, 2), (t, t_mut, 3)); impl Vector2 { pub fn orthogonal(&self) -> Vector2 { Vector2::new( self.y(), self.x() * -1.0, ) } } impl Vector2 { pub fn orthogonal(&self) -> Vector2 { Vector2::new( self.y(), self.x() * -1, ) } } impl Vector3 { /// Computes the cross product between two vectors. pub fn cross_product(&self, rhs: Vector3) -> Vector3 { Vector3::new( self.data[1] * rhs.data[2] - self.data[2] * rhs.data[1], self.data[2] * rhs.data[0] - self.data[0] * rhs.data[2], self.data[0] * rhs.data[1] - self.data[1] * rhs.data[0] ) } } impl Vector3 { /// Computes the area of a triangle in 3 dimensions. pub fn area(a: Vector3, b: Vector3, c: Vector3) -> f64 { let v1 = b - a; let v2 = c - a; let cross = v1.cross_product(v2); 0.5 * cross.norm() } } type Vector2f32 = Vector2; implement_vertex!(Vector2f32, data); type Vector2f64 = Vector2; implement_vertex!(Vector2f64, data); type Vector3f32 = Vector3; implement_vertex!(Vector3f32, data); type Vector3f64 = Vector3; implement_vertex!(Vector3f64, data); type Vector4f32 = Vector4; implement_vertex!(Vector4f32, data); type Vector4f64 = Vector4; implement_vertex!(Vector4f64, data); #[cfg(test)] mod test { macro_rules! assert_delta { ($x:expr, $y:expr, $d:expr) => { if !($x - $y < $d || $y - $x < $d) { panic!(); } } } mod vector2 { use math::vector::Vector2; #[test] fn create() { let v = Vector2::new(0, 1); assert_eq!(v.data[0], 0); assert_eq!(v.data[1], 1); } #[test] fn getters() { let v = Vector2::new(0, 1); assert_eq!(v.x(), 0); assert_eq!(v.y(), 1); } #[test] fn index() { let v = Vector2::new(0, 1); assert_eq!(v[0], 0); assert_eq!(v[1], 1); } #[test] fn index_mut() { let mut v = Vector2::new(0, 1); v[0] = 1; v[1] = 0; assert_eq!(v.data[0], 1); assert_eq!(v.data[1], 0); } #[test] fn dot_1() { let v1 = Vector2::new(0, 1); let v2 = Vector2::new(1, 0); assert_eq!(v1.dot(v2), 0); } #[test] fn dot_2() { let v1 = Vector2::new(1, 1); let v2 = Vector2::new(1, 1); assert_eq!(v1.dot(v2), 2); } #[test] fn dot_3() { let v1 = Vector2::new(1, 2); let v2 = Vector2::new(2, 2); assert_eq!(v1.dot(v2), 6); } #[test] fn add_1() { let v1 = Vector2::new(0, 1); let v2 = Vector2::new(1, 0); let v = v1 + v2; assert_eq!(v.data[0], 1); assert_eq!(v.data[1], 1); } #[test] fn add_2() { let v1 = Vector2::new(1, 1); let v2 = Vector2::new(1, 1); let v = v1 + v2; assert_eq!(v.data[0], 2); assert_eq!(v.data[1], 2); } #[test] fn add_3() { let v1 = Vector2::new(1, 2); let v2 = Vector2::new(2, 2); let v = v1 + v2; assert_eq!(v.data[0], 3); assert_eq!(v.data[1], 4); } #[test] fn norm2_1() { let v = Vector2::new(1,2); assert_eq!(v.norm2(), 5); } #[test] fn norm_1() { let v = Vector2::new(3.0, 4.0); assert_delta!(v.norm(), 5.0, 0.001); } #[test] fn norm_2() { use num::Float; let v = Vector2::new(1.0, 1.0); assert_delta!(v.norm(), 2.0.sqrt(), 0.001); } } }