Inital commit coming from dash-3d
This commit is contained in:
@@ -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);
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user