Inital commit coming from dash-3d

This commit is contained in:
Thomas Forgione
2018-02-23 12:04:26 +01:00
commit bccb83b538
10 changed files with 1402 additions and 0 deletions
+65
View File
@@ -0,0 +1,65 @@
//! Module containing the bounding box struct.
use math::Number;
macro_rules! make_bounding_box {
($name: ident, $vector: ident, $size: expr) => {
use math::vector::$vector;
/// Represents a bounding box.
pub struct $name<T> {
min: $vector<T>,
max: $vector<T>,
}
impl<T: PartialOrd + Copy + Clone> $name<T> {
/// Creates a bounding box from its min and max coordinates.
pub fn new(min: $vector<T>, max: $vector<T>) -> $name<T> {
$name {
min: min,
max: max,
}
}
/// Enlarges the bounding box so it contains the point passed as parameter.
pub fn add_point(&mut self, point: &$vector<T>) {
for i in 0..$size {
if point[i] < self.min[i] {
self.min[i] = point[i];
}
if point[i] > self.max[i] {
self.max[i] = point[i];
}
}
}
/// Returns the minimum value of the bounding box.
pub fn min(&self) -> $vector<T> {
self.min
}
/// Returns the maximum value of the bounding box.
pub fn max(&self) -> $vector<T> {
self.max
}
}
impl<T: Number> $name<T> {
/// Scales a bounding box from its center.
pub fn scale(&mut self, factor: T) {
let diag = self.max - self.min;
self.min -= diag * factor;
self.max += diag * factor;
}
}
}
}
make_bounding_box!(BoundingBox2, Vector2, 2);
make_bounding_box!(BoundingBox3, Vector3, 3);
make_bounding_box!(BoundingBox4, Vector4, 4);
+33
View File
@@ -0,0 +1,33 @@
//! Module containing all the math structs and functions.
pub mod vector;
pub mod bounding_box;
use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign};
use num::{Zero, One};
/// A number.
///
/// This trait is used to implement the operator traits on the vector struct.
pub trait Number: Copy + Clone + PartialOrd + Zero + One
+ Add<Output = Self> + AddAssign
+ Sub<Output = Self> + SubAssign
+ Mul<Output = Self> + MulAssign
+ Div<Output = Self> + DivAssign
{
}
impl Number for i16 {}
impl Number for i32 {}
impl Number for i64 {}
impl Number for isize {}
impl Number for u16 {}
impl Number for u32 {}
impl Number for u64 {}
impl Number for usize {}
impl Number for f32 {}
impl Number for f64 {}
+361
View File
@@ -0,0 +1,361 @@
//! 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);
}
}
}