model-converter/src/math/vector.rs

406 lines
11 KiB
Rust

//! Module containing the vector struct.
use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign, Index, IndexMut};
use std::fmt;
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> Into<[T; $number]> for $name<T> {
fn into(self) -> [T; $number] {
self.data
}
}
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]
}
/// Get a mut ref to the coordinate of the vector.
pub fn $x_mut(&mut self) -> &mut T {
&mut 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()
}
/// Divides each coordinate by the norm of the vector.
pub fn normalize(&mut self) {
*self /= self.norm()
}
/// Returns a new normalized vector.
pub fn normalized(&self) -> $name<T> {
*self / self.norm()
}
}
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: fmt::Display> fmt::Display for $name<T> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "(")?;
for i in &self.data {
write!(formatter, "{}, ", i)?;
}
write!(formatter, ")")?;
Ok(())
}
}
// 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> {
/// Returns a orthogonal vector to the one passed as parameter.
pub fn orthogonal(&self) -> Vector2<f32> {
Vector2::new(
self.y(),
self.x() * -1.0,
)
}
}
impl Vector2<i32> {
/// Returns a orthogonal vector to the one passed as parameter.
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()
}
}
type Vector2f32 = Vector2<f32>; implement_vertex!(Vector2f32, data);
type Vector2f64 = Vector2<f64>; implement_vertex!(Vector2f64, data);
type Vector3f32 = Vector3<f32>; implement_vertex!(Vector3f32, data);
type Vector3f64 = Vector3<f64>; implement_vertex!(Vector3f64, data);
type Vector4f32 = Vector4<f32>; implement_vertex!(Vector4f32, data);
type Vector4f64 = Vector4<f64>; 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);
}
}
}