362 lines
9.0 KiB
Rust
362 lines
9.0 KiB
Rust
|
//! 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<T> {
|
||
|
data: [T; $number],
|
||
|
}
|
||
|
|
||
|
impl<T> $name<T> {
|
||
|
/// Creates a vector from its coordinates.
|
||
|
pub fn new( $( $x: T ) , *) -> $name<T> {
|
||
|
$name::<T> {
|
||
|
data: [ $( $x ) , *],
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Returns the length of the vector.
|
||
|
pub fn len(&self) -> usize {
|
||
|
return $number;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T: Copy + Clone> Into<($( $t ) ,* )> for $name<T> {
|
||
|
fn into(self) -> ($( $t ) ,* ) {
|
||
|
( $( self.data[$y] ), *)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T: Number> Zero for $name<T> {
|
||
|
fn zero() -> $name<T> {
|
||
|
$name::<T> {
|
||
|
data: [ T::zero(); $number ],
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn is_zero(&self) -> bool {
|
||
|
for x in &self.data {
|
||
|
if ! x.is_zero() {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
true
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T: Copy + Clone> $name<T> {
|
||
|
$(
|
||
|
/// Get the coordinate of the vector.
|
||
|
pub fn $x(&self) -> T {
|
||
|
self.data[$y]
|
||
|
}
|
||
|
)*
|
||
|
}
|
||
|
|
||
|
impl<T: Number> $name<T> {
|
||
|
/// Computes the dot product between two vectors.
|
||
|
pub fn dot(&self, rhs: $name<T>) -> T {
|
||
|
$( self.data[$y] * rhs.data[$y] + )* T::zero()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T: Number> $name<T> {
|
||
|
|
||
|
/// Computes the iso barycenter of a list of vectors.
|
||
|
pub fn barycenter(vectors: &[&$name<T>]) -> $name<T> {
|
||
|
use num::Zero;
|
||
|
let mut sum = $name::<T>::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<T: Number + Float> $name<T> {
|
||
|
/// Computes the 2-norm of the vector
|
||
|
pub fn norm(&self) -> T {
|
||
|
self.norm2().sqrt()
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
impl<T: Number> Add for $name<T> {
|
||
|
type Output = $name<T>;
|
||
|
|
||
|
fn add(self, rhs: $name<T>) -> Self::Output {
|
||
|
$name::<T>::new( $( self.data[$y] + rhs.data[$y] ) , *)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T: Number> AddAssign for $name<T> {
|
||
|
fn add_assign(&mut self, rhs: $name<T>) {
|
||
|
$(
|
||
|
self.data[$y] += rhs.data[$y];
|
||
|
)*
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T: Number> Sub for $name<T> {
|
||
|
type Output = $name<T>;
|
||
|
|
||
|
fn sub(self, rhs: $name<T>) -> Self::Output {
|
||
|
$name::<T>::new( $( self.data[$y] - rhs.data[$y] ) , *)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T: Number> SubAssign for $name<T> {
|
||
|
fn sub_assign(&mut self, rhs: $name<T>) {
|
||
|
$(
|
||
|
self.data[$y] -= rhs.data[$y];
|
||
|
)*
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T: Number> Mul<T> for $name<T> {
|
||
|
type Output = $name<T>;
|
||
|
|
||
|
fn mul(self, rhs: T) -> Self::Output {
|
||
|
$name::<T>::new( $( self.data[$y] * rhs ), *)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T: Number> MulAssign<T> for $name<T> {
|
||
|
fn mul_assign(&mut self, rhs: T) {
|
||
|
$(
|
||
|
self.data[$y] *= rhs;
|
||
|
)*
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T: Number> Div<T> for $name<T> {
|
||
|
type Output = $name<T>;
|
||
|
|
||
|
fn div(self, rhs: T) -> Self::Output {
|
||
|
$name::<T>::new( $( self.data[$y] / rhs ), *)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T: Number> DivAssign<T> for $name<T> {
|
||
|
fn div_assign(&mut self, rhs: T) {
|
||
|
$(
|
||
|
self.data[$y] /= rhs;
|
||
|
)*
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T> Index<usize> for $name<T> {
|
||
|
type Output = T;
|
||
|
|
||
|
fn index(&self, index: usize) -> &T {
|
||
|
&self.data[index]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<T> IndexMut<usize> for $name<T> {
|
||
|
fn index_mut(&mut self, index: usize) -> &mut T {
|
||
|
&mut self.data[index]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// impl<T: PartialEq> PartialEq for $name<T> {
|
||
|
// fn eq(&self, other: &$name<T>) -> 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<f32> {
|
||
|
pub fn orthogonal(&self) -> Vector2<f32> {
|
||
|
Vector2::new(
|
||
|
self.y(),
|
||
|
self.x() * -1.0,
|
||
|
)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl Vector2<i32> {
|
||
|
pub fn orthogonal(&self) -> Vector2<i32> {
|
||
|
Vector2::new(
|
||
|
self.y(),
|
||
|
self.x() * -1,
|
||
|
)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
impl<T: Number> Vector3<T> {
|
||
|
/// Computes the cross product between two vectors.
|
||
|
pub fn cross_product(&self, rhs: Vector3<T>) -> Vector3<T> {
|
||
|
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<f64> {
|
||
|
/// Computes the area of a triangle in 3 dimensions.
|
||
|
pub fn area(a: Vector3<f64>, b: Vector3<f64>, c: Vector3<f64>) -> f64 {
|
||
|
let v1 = b - a;
|
||
|
let v2 = c - a;
|
||
|
let cross = v1.cross_product(v2);
|
||
|
0.5 * cross.norm()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[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);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|