Finished vector/point/normal/matrix code.
Sans bugs, optimization, and possibly convenience functions down the line.
This commit is contained in:
parent
aa6b72493b
commit
ff10e696c8
|
@ -16,7 +16,8 @@ pub fn lerp<T: Lerp>(a: T, b: T, alpha: f32) -> T {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Interpolates a slice of Lerp data.
|
/// Interpolates a slice of data as if each adjecent pair of elements
|
||||||
|
/// represent a linear segment.
|
||||||
pub fn lerp_slice<T: Lerp + Copy>(s: &[T], alpha: f32) -> T {
|
pub fn lerp_slice<T: Lerp + Copy>(s: &[T], alpha: f32) -> T {
|
||||||
debug_assert!(s.len() > 0);
|
debug_assert!(s.len() > 0);
|
||||||
debug_assert!(alpha >= 0.0);
|
debug_assert!(alpha >= 0.0);
|
||||||
|
@ -37,13 +38,13 @@ pub fn lerp_slice<T: Lerp + Copy>(s: &[T], alpha: f32) -> T {
|
||||||
|
|
||||||
impl Lerp for f32 {
|
impl Lerp for f32 {
|
||||||
fn lerp(self, other: f32, alpha: f32) -> f32 {
|
fn lerp(self, other: f32, alpha: f32) -> f32 {
|
||||||
self + ((other - self) * alpha)
|
(self * (1.0 - alpha)) + (other * alpha)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Lerp for f64 {
|
impl Lerp for f64 {
|
||||||
fn lerp(self, other: f64, alpha: f32) -> f64 {
|
fn lerp(self, other: f64, alpha: f32) -> f64 {
|
||||||
self + ((other - self) * (alpha as f64))
|
(self * (1.0 - alpha as f64)) + (other * alpha as f64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,9 @@ mod math;
|
||||||
mod lerp;
|
mod lerp;
|
||||||
mod float4;
|
mod float4;
|
||||||
mod vector;
|
mod vector;
|
||||||
|
mod point;
|
||||||
|
mod normal;
|
||||||
|
mod matrix;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("Hello, world!");
|
println!("Hello, world!");
|
||||||
|
|
537
src/matrix.rs
Normal file
537
src/matrix.rs
Normal file
|
@ -0,0 +1,537 @@
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use std;
|
||||||
|
use std::ops::{Index, IndexMut, Mul};
|
||||||
|
|
||||||
|
use float4::Float4;
|
||||||
|
use lerp::Lerp;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// A 4x4 matrix, used for transforms
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct Matrix4x4 {
|
||||||
|
values: [Float4; 4],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Matrix4x4 {
|
||||||
|
/// Creates a new identity matrix
|
||||||
|
pub fn new() -> Matrix4x4 {
|
||||||
|
Matrix4x4 {
|
||||||
|
values: [Float4::new(1.0, 0.0, 0.0, 0.0),
|
||||||
|
Float4::new(0.0, 1.0, 0.0, 0.0),
|
||||||
|
Float4::new(0.0, 0.0, 1.0, 0.0),
|
||||||
|
Float4::new(0.0, 0.0, 0.0, 1.0)],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new matrix with the specified values:
|
||||||
|
/// a b c d
|
||||||
|
/// e f g h
|
||||||
|
/// i j k l
|
||||||
|
/// m n o p
|
||||||
|
pub fn new_from_values(a: f32,
|
||||||
|
b: f32,
|
||||||
|
c: f32,
|
||||||
|
d: f32,
|
||||||
|
e: f32,
|
||||||
|
f: f32,
|
||||||
|
g: f32,
|
||||||
|
h: f32,
|
||||||
|
i: f32,
|
||||||
|
j: f32,
|
||||||
|
k: f32,
|
||||||
|
l: f32,
|
||||||
|
m: f32,
|
||||||
|
n: f32,
|
||||||
|
o: f32,
|
||||||
|
p: f32)
|
||||||
|
-> Matrix4x4 {
|
||||||
|
Matrix4x4 {
|
||||||
|
values: [Float4::new(a, b, c, d),
|
||||||
|
Float4::new(e, f, g, h),
|
||||||
|
Float4::new(i, j, k, l),
|
||||||
|
Float4::new(m, n, o, p)],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether the matrices are approximately equal to each other.
|
||||||
|
/// Each corresponding element in the matrices cannot have a relative error
|
||||||
|
/// exceeding `epsilon`.
|
||||||
|
pub fn aprx_eq(&self, other: Matrix4x4, epsilon: f32) -> bool {
|
||||||
|
let mut result = true;
|
||||||
|
|
||||||
|
for y in 0..4 {
|
||||||
|
for x in 0..4 {
|
||||||
|
// All of this stuff is just an approximate comparison
|
||||||
|
// of floating point numbers. See:
|
||||||
|
// http://floating-point-gui.de/errors/comparison/
|
||||||
|
// It might be worth breaking this out into a separate funcion,
|
||||||
|
// but I'm not entirely sure where to put it.
|
||||||
|
let a = self[y][x];
|
||||||
|
let b = other[y][x];
|
||||||
|
let aabs = a.abs();
|
||||||
|
let babs = b.abs();
|
||||||
|
let diff = (a - b).abs();
|
||||||
|
if a == b {
|
||||||
|
} else if (aabs <= std::f32::EPSILON) || (babs <= std::f32::EPSILON) {
|
||||||
|
result = result && (diff < std::f32::EPSILON);
|
||||||
|
} else {
|
||||||
|
let rel = 2.0 * diff / (aabs + babs);
|
||||||
|
println!("{}", rel);
|
||||||
|
result = result && (rel < epsilon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the transpose of the matrix
|
||||||
|
pub fn transposed(&self) -> Matrix4x4 {
|
||||||
|
Matrix4x4 {
|
||||||
|
values: {
|
||||||
|
[Float4::new(self[0][0], self[1][0], self[2][0], self[3][0]),
|
||||||
|
Float4::new(self[0][1], self[1][1], self[2][1], self[3][1]),
|
||||||
|
Float4::new(self[0][2], self[1][2], self[2][2], self[3][2]),
|
||||||
|
Float4::new(self[0][3], self[1][3], self[2][3], self[3][3])]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Returns the inverse of the Matrix
|
||||||
|
pub fn inverse(&self) -> Matrix4x4 {
|
||||||
|
let s0 = (self[0][0] * self[1][1]) - (self[1][0] * self[0][1]);
|
||||||
|
let s1 = (self[0][0] * self[1][2]) - (self[1][0] * self[0][2]);
|
||||||
|
let s2 = (self[0][0] * self[1][3]) - (self[1][0] * self[0][3]);
|
||||||
|
let s3 = (self[0][1] * self[1][2]) - (self[1][1] * self[0][2]);
|
||||||
|
let s4 = (self[0][1] * self[1][3]) - (self[1][1] * self[0][3]);
|
||||||
|
let s5 = (self[0][2] * self[1][3]) - (self[1][2] * self[0][3]);
|
||||||
|
|
||||||
|
let c5 = (self[2][2] * self[3][3]) - (self[3][2] * self[2][3]);
|
||||||
|
let c4 = (self[2][1] * self[3][3]) - (self[3][1] * self[2][3]);
|
||||||
|
let c3 = (self[2][1] * self[3][2]) - (self[3][1] * self[2][2]);
|
||||||
|
let c2 = (self[2][0] * self[3][3]) - (self[3][0] * self[2][3]);
|
||||||
|
let c1 = (self[2][0] * self[3][2]) - (self[3][0] * self[2][2]);
|
||||||
|
let c0 = (self[2][0] * self[3][1]) - (self[3][0] * self[2][1]);
|
||||||
|
|
||||||
|
// TODO: handle 0.0 determinant
|
||||||
|
let det = (s0 * c5) - (s1 * c4) + (s2 * c3) + (s3 * c2) - (s4 * c1) + (s5 * c0);
|
||||||
|
let invdet = 1.0 / det;
|
||||||
|
|
||||||
|
Matrix4x4 {
|
||||||
|
values: {
|
||||||
|
[Float4::new(((self[1][1] * c5) - (self[1][2] * c4) + (self[1][3] * c3)) * invdet,
|
||||||
|
((-self[0][1] * c5) + (self[0][2] * c4) - (self[0][3] * c3)) * invdet,
|
||||||
|
((self[3][1] * s5) - (self[3][2] * s4) + (self[3][3] * s3)) * invdet,
|
||||||
|
((-self[2][1] * s5) + (self[2][2] * s4) - (self[2][3] * s3)) * invdet),
|
||||||
|
|
||||||
|
Float4::new(((-self[1][0] * c5) + (self[1][2] * c2) - (self[1][3] * c1)) * invdet,
|
||||||
|
((self[0][0] * c5) - (self[0][2] * c2) + (self[0][3] * c1)) * invdet,
|
||||||
|
((-self[3][0] * s5) + (self[3][2] * s2) - (self[3][3] * s1)) * invdet,
|
||||||
|
((self[2][0] * s5) - (self[2][2] * s2) + (self[2][3] * s1)) * invdet),
|
||||||
|
|
||||||
|
Float4::new(((self[1][0] * c4) - (self[1][1] * c2) + (self[1][3] * c0)) * invdet,
|
||||||
|
((-self[0][0] * c4) + (self[0][1] * c2) - (self[0][3] * c0)) * invdet,
|
||||||
|
((self[3][0] * s4) - (self[3][1] * s2) + (self[3][3] * s0)) * invdet,
|
||||||
|
((-self[2][0] * s4) + (self[2][1] * s2) - (self[2][3] * s0)) * invdet),
|
||||||
|
|
||||||
|
Float4::new(((-self[1][0] * c3) + (self[1][1] * c1) - (self[1][2] * c0)) * invdet,
|
||||||
|
((self[0][0] * c3) - (self[0][1] * c1) + (self[0][2] * c0)) * invdet,
|
||||||
|
((-self[3][0] * s3) + (self[3][1] * s1) - (self[3][2] * s0)) * invdet,
|
||||||
|
((self[2][0] * s3) - (self[2][1] * s1) + (self[2][2] * s0)) * invdet)]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Index<usize> for Matrix4x4 {
|
||||||
|
type Output = Float4;
|
||||||
|
|
||||||
|
fn index<'a>(&'a self, _index: usize) -> &'a Float4 {
|
||||||
|
&self.values[_index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl IndexMut<usize> for Matrix4x4 {
|
||||||
|
fn index_mut<'a>(&'a mut self, _index: usize) -> &'a mut Float4 {
|
||||||
|
&mut self.values[_index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl PartialEq for Matrix4x4 {
|
||||||
|
fn eq(&self, other: &Matrix4x4) -> bool {
|
||||||
|
let mut result = true;
|
||||||
|
|
||||||
|
for y in 0..4 {
|
||||||
|
for x in 0..4 {
|
||||||
|
result = result && (self[y][x] == other[y][x]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Multiply two matrices together
|
||||||
|
impl Mul<Matrix4x4> for Matrix4x4 {
|
||||||
|
type Output = Matrix4x4;
|
||||||
|
|
||||||
|
fn mul(self, other: Matrix4x4) -> Matrix4x4 {
|
||||||
|
let m = self.transposed();
|
||||||
|
Matrix4x4 {
|
||||||
|
values: [Float4::new((m[0] * other[0]).h_sum(),
|
||||||
|
(m[1] * other[0]).h_sum(),
|
||||||
|
(m[2] * other[0]).h_sum(),
|
||||||
|
(m[3] * other[0]).h_sum()),
|
||||||
|
|
||||||
|
Float4::new((m[0] * other[1]).h_sum(),
|
||||||
|
(m[1] * other[1]).h_sum(),
|
||||||
|
(m[2] * other[1]).h_sum(),
|
||||||
|
(m[3] * other[1]).h_sum()),
|
||||||
|
|
||||||
|
Float4::new((m[0] * other[2]).h_sum(),
|
||||||
|
(m[1] * other[2]).h_sum(),
|
||||||
|
(m[2] * other[2]).h_sum(),
|
||||||
|
(m[3] * other[2]).h_sum()),
|
||||||
|
|
||||||
|
Float4::new((m[0] * other[3]).h_sum(),
|
||||||
|
(m[1] * other[3]).h_sum(),
|
||||||
|
(m[2] * other[3]).h_sum(),
|
||||||
|
(m[3] * other[3]).h_sum())],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Lerp for Matrix4x4 {
|
||||||
|
fn lerp(self, other: Matrix4x4, alpha: f32) -> Matrix4x4 {
|
||||||
|
let alpha_minus = 1.0 - alpha;
|
||||||
|
Matrix4x4 {
|
||||||
|
values: [Float4::new((self[0][0] * alpha_minus) + (other[0][0] * alpha),
|
||||||
|
(self[0][1] * alpha_minus) + (other[0][1] * alpha),
|
||||||
|
(self[0][2] * alpha_minus) + (other[0][2] * alpha),
|
||||||
|
(self[0][3] * alpha_minus) + (other[0][3] * alpha)),
|
||||||
|
|
||||||
|
Float4::new((self[1][0] * alpha_minus) + (other[1][0] * alpha),
|
||||||
|
(self[1][1] * alpha_minus) + (other[1][1] * alpha),
|
||||||
|
(self[1][2] * alpha_minus) + (other[1][2] * alpha),
|
||||||
|
(self[1][3] * alpha_minus) + (other[1][3] * alpha)),
|
||||||
|
|
||||||
|
Float4::new((self[2][0] * alpha_minus) + (other[2][0] * alpha),
|
||||||
|
(self[2][1] * alpha_minus) + (other[2][1] * alpha),
|
||||||
|
(self[2][2] * alpha_minus) + (other[2][2] * alpha),
|
||||||
|
(self[2][3] * alpha_minus) + (other[2][3] * alpha)),
|
||||||
|
|
||||||
|
Float4::new((self[3][0] * alpha_minus) + (other[3][0] * alpha),
|
||||||
|
(self[3][1] * alpha_minus) + (other[3][1] * alpha),
|
||||||
|
(self[3][2] * alpha_minus) + (other[3][2] * alpha),
|
||||||
|
(self[3][3] * alpha_minus) + (other[3][3] * alpha))],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use lerp::Lerp;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn equality_test() {
|
||||||
|
let a = Matrix4x4::new();
|
||||||
|
let b = Matrix4x4::new();
|
||||||
|
let c = Matrix4x4::new_from_values(1.1,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
1.1,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
1.1,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
1.1);
|
||||||
|
|
||||||
|
assert_eq!(a, b);
|
||||||
|
assert!(a != c);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn aproximate_equality_test() {
|
||||||
|
let a = Matrix4x4::new();
|
||||||
|
let b = Matrix4x4::new_from_values(1.001,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
1.001,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
1.001,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
1.001);
|
||||||
|
let c = Matrix4x4::new_from_values(1.003,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
1.003,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
1.003,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
1.003);
|
||||||
|
let d = Matrix4x4::new_from_values(-1.001,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
-1.001,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
-1.001,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
-1.001);
|
||||||
|
|
||||||
|
assert!(a.aprx_eq(b, 0.002));
|
||||||
|
assert!(!a.aprx_eq(c, 0.002));
|
||||||
|
assert!(!a.aprx_eq(d, 0.002));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn multiply_test() {
|
||||||
|
let a = Matrix4x4::new_from_values(1.0,
|
||||||
|
2.0,
|
||||||
|
2.0,
|
||||||
|
1.5,
|
||||||
|
3.0,
|
||||||
|
6.0,
|
||||||
|
7.0,
|
||||||
|
8.0,
|
||||||
|
9.0,
|
||||||
|
2.0,
|
||||||
|
11.0,
|
||||||
|
12.0,
|
||||||
|
13.0,
|
||||||
|
7.0,
|
||||||
|
15.0,
|
||||||
|
3.0);
|
||||||
|
let b = Matrix4x4::new_from_values(1.0,
|
||||||
|
5.0,
|
||||||
|
9.0,
|
||||||
|
13.0,
|
||||||
|
2.0,
|
||||||
|
6.0,
|
||||||
|
10.0,
|
||||||
|
14.0,
|
||||||
|
3.0,
|
||||||
|
7.0,
|
||||||
|
11.0,
|
||||||
|
15.0,
|
||||||
|
4.0,
|
||||||
|
8.0,
|
||||||
|
12.0,
|
||||||
|
16.0);
|
||||||
|
let c = Matrix4x4::new_from_values(266.0,
|
||||||
|
141.0,
|
||||||
|
331.0,
|
||||||
|
188.5,
|
||||||
|
292.0,
|
||||||
|
158.0,
|
||||||
|
366.0,
|
||||||
|
213.0,
|
||||||
|
318.0,
|
||||||
|
175.0,
|
||||||
|
401.0,
|
||||||
|
237.5,
|
||||||
|
344.0,
|
||||||
|
192.0,
|
||||||
|
436.0,
|
||||||
|
262.0);
|
||||||
|
|
||||||
|
assert_eq!(a * b, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn inverse_test() {
|
||||||
|
let a = Matrix4x4::new_from_values(1.0,
|
||||||
|
0.33,
|
||||||
|
0.0,
|
||||||
|
-2.0,
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
2.1,
|
||||||
|
0.7,
|
||||||
|
1.3,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
-1.0);
|
||||||
|
let b = a.inverse();
|
||||||
|
let c = Matrix4x4::new();
|
||||||
|
|
||||||
|
assert!((a * b).aprx_eq(c, 0.00001));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn transpose_test() {
|
||||||
|
let a = Matrix4x4::new_from_values(1.0,
|
||||||
|
2.0,
|
||||||
|
3.0,
|
||||||
|
4.0,
|
||||||
|
5.0,
|
||||||
|
6.0,
|
||||||
|
7.0,
|
||||||
|
8.0,
|
||||||
|
9.0,
|
||||||
|
10.0,
|
||||||
|
11.0,
|
||||||
|
12.0,
|
||||||
|
13.0,
|
||||||
|
14.0,
|
||||||
|
15.0,
|
||||||
|
16.0);
|
||||||
|
let b = Matrix4x4::new_from_values(1.0,
|
||||||
|
5.0,
|
||||||
|
9.0,
|
||||||
|
13.0,
|
||||||
|
2.0,
|
||||||
|
6.0,
|
||||||
|
10.0,
|
||||||
|
14.0,
|
||||||
|
3.0,
|
||||||
|
7.0,
|
||||||
|
11.0,
|
||||||
|
15.0,
|
||||||
|
4.0,
|
||||||
|
8.0,
|
||||||
|
12.0,
|
||||||
|
16.0);
|
||||||
|
let c = a.transposed();
|
||||||
|
|
||||||
|
assert_eq!(b, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lerp_test() {
|
||||||
|
let a = Matrix4x4::new_from_values(0.0,
|
||||||
|
2.0,
|
||||||
|
2.0,
|
||||||
|
3.0,
|
||||||
|
4.0,
|
||||||
|
5.0,
|
||||||
|
6.0,
|
||||||
|
7.0,
|
||||||
|
8.0,
|
||||||
|
9.0,
|
||||||
|
10.0,
|
||||||
|
11.0,
|
||||||
|
12.0,
|
||||||
|
13.0,
|
||||||
|
14.0,
|
||||||
|
15.0);
|
||||||
|
let b = Matrix4x4::new_from_values(-1.0,
|
||||||
|
1.0,
|
||||||
|
3.0,
|
||||||
|
4.0,
|
||||||
|
5.0,
|
||||||
|
6.0,
|
||||||
|
7.0,
|
||||||
|
8.0,
|
||||||
|
9.0,
|
||||||
|
10.0,
|
||||||
|
11.0,
|
||||||
|
12.0,
|
||||||
|
13.0,
|
||||||
|
14.0,
|
||||||
|
15.0,
|
||||||
|
16.0);
|
||||||
|
|
||||||
|
let c1 = Matrix4x4::new_from_values(-0.25,
|
||||||
|
1.75,
|
||||||
|
2.25,
|
||||||
|
3.25,
|
||||||
|
4.25,
|
||||||
|
5.25,
|
||||||
|
6.25,
|
||||||
|
7.25,
|
||||||
|
8.25,
|
||||||
|
9.25,
|
||||||
|
10.25,
|
||||||
|
11.25,
|
||||||
|
12.25,
|
||||||
|
13.25,
|
||||||
|
14.25,
|
||||||
|
15.25);
|
||||||
|
let c2 = Matrix4x4::new_from_values(-0.5,
|
||||||
|
1.5,
|
||||||
|
2.5,
|
||||||
|
3.5,
|
||||||
|
4.5,
|
||||||
|
5.5,
|
||||||
|
6.5,
|
||||||
|
7.5,
|
||||||
|
8.5,
|
||||||
|
9.5,
|
||||||
|
10.5,
|
||||||
|
11.5,
|
||||||
|
12.5,
|
||||||
|
13.5,
|
||||||
|
14.5,
|
||||||
|
15.5);
|
||||||
|
let c3 = Matrix4x4::new_from_values(-0.75,
|
||||||
|
1.25,
|
||||||
|
2.75,
|
||||||
|
3.75,
|
||||||
|
4.75,
|
||||||
|
5.75,
|
||||||
|
6.75,
|
||||||
|
7.75,
|
||||||
|
8.75,
|
||||||
|
9.75,
|
||||||
|
10.75,
|
||||||
|
11.75,
|
||||||
|
12.75,
|
||||||
|
13.75,
|
||||||
|
14.75,
|
||||||
|
15.75);
|
||||||
|
|
||||||
|
assert_eq!(a.lerp(b, 0.0), a);
|
||||||
|
assert_eq!(a.lerp(b, 0.25), c1);
|
||||||
|
assert_eq!(a.lerp(b, 0.5), c2);
|
||||||
|
assert_eq!(a.lerp(b, 0.75), c3);
|
||||||
|
assert_eq!(a.lerp(b, 1.0), b);
|
||||||
|
}
|
||||||
|
}
|
270
src/normal.rs
Normal file
270
src/normal.rs
Normal file
|
@ -0,0 +1,270 @@
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use std::ops::{Index, IndexMut, Add, Sub, Mul, Div};
|
||||||
|
use std::cmp::PartialEq;
|
||||||
|
|
||||||
|
use lerp::Lerp;
|
||||||
|
use math::{DotProduct, CrossProduct};
|
||||||
|
use float4::Float4;
|
||||||
|
use matrix::Matrix4x4;
|
||||||
|
|
||||||
|
/// A surface normal in 3d homogeneous space.
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct Normal {
|
||||||
|
pub co: Float4,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Normal {
|
||||||
|
pub fn new(x: f32, y: f32, z: f32) -> Normal {
|
||||||
|
Normal { co: Float4::new(x, y, z, 0.0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn length(&self) -> f32 {
|
||||||
|
(self.co * self.co).h_sum().sqrt()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn length2(&self) -> f32 {
|
||||||
|
(self.co * self.co).h_sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn normalized(&self) -> Normal {
|
||||||
|
*self / self.length()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Index<usize> for Normal {
|
||||||
|
type Output = f32;
|
||||||
|
|
||||||
|
fn index(&self, index: usize) -> &f32 {
|
||||||
|
debug_assert!(index < 3);
|
||||||
|
|
||||||
|
&self.co[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<usize> for Normal {
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut f32 {
|
||||||
|
debug_assert!(index < 3);
|
||||||
|
|
||||||
|
&mut self.co[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl PartialEq for Normal {
|
||||||
|
fn eq(&self, other: &Normal) -> bool {
|
||||||
|
self.co == other.co
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Add for Normal {
|
||||||
|
type Output = Normal;
|
||||||
|
|
||||||
|
fn add(self, other: Normal) -> Normal {
|
||||||
|
Normal { co: self.co + other.co }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Sub for Normal {
|
||||||
|
type Output = Normal;
|
||||||
|
|
||||||
|
fn sub(self, other: Normal) -> Normal {
|
||||||
|
Normal { co: self.co - other.co }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Mul<f32> for Normal {
|
||||||
|
type Output = Normal;
|
||||||
|
|
||||||
|
fn mul(self, other: f32) -> Normal {
|
||||||
|
Normal { co: self.co * other }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<Matrix4x4> for Normal {
|
||||||
|
type Output = Normal;
|
||||||
|
|
||||||
|
fn mul(self, other: Matrix4x4) -> Normal {
|
||||||
|
let mat = other.inverse().transposed();
|
||||||
|
Normal {
|
||||||
|
co: Float4::new((self[0] * mat[0][0]) + (self[1] * mat[0][1]) + (self[2] * mat[0][2]),
|
||||||
|
(self[0] * mat[1][0]) + (self[1] * mat[1][1]) + (self[2] * mat[1][2]),
|
||||||
|
(self[0] * mat[2][0]) + (self[1] * mat[2][1]) + (self[2] * mat[2][2]),
|
||||||
|
0.0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Div<f32> for Normal {
|
||||||
|
type Output = Normal;
|
||||||
|
|
||||||
|
fn div(self, other: f32) -> Normal {
|
||||||
|
Normal { co: self.co / other }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Lerp for Normal {
|
||||||
|
fn lerp(self, other: Normal, alpha: f32) -> Normal {
|
||||||
|
(self * (1.0 - alpha)) + (other * alpha)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl DotProduct for Normal {
|
||||||
|
fn dot(self, other: Normal) -> f32 {
|
||||||
|
(self.co * other.co).h_sum()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl CrossProduct for Normal {
|
||||||
|
fn cross(self, other: Normal) -> Normal {
|
||||||
|
Normal {
|
||||||
|
co: Float4::new((self[1] * other[2]) - (self[2] * other[1]),
|
||||||
|
(self[2] * other[0]) - (self[0] * other[2]),
|
||||||
|
(self[0] * other[1]) - (self[1] * other[0]),
|
||||||
|
0.0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use math::*;
|
||||||
|
use lerp::Lerp;
|
||||||
|
use matrix::Matrix4x4;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add() {
|
||||||
|
let v1 = Normal::new(1.0, 2.0, 3.0);
|
||||||
|
let v2 = Normal::new(1.5, 4.5, 2.5);
|
||||||
|
let v3 = Normal::new(2.5, 6.5, 5.5);
|
||||||
|
|
||||||
|
assert_eq!(v3, v1 + v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sub() {
|
||||||
|
let v1 = Normal::new(1.0, 2.0, 3.0);
|
||||||
|
let v2 = Normal::new(1.5, 4.5, 2.5);
|
||||||
|
let v3 = Normal::new(-0.5, -2.5, 0.5);
|
||||||
|
|
||||||
|
assert_eq!(v3, v1 - v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mul_scalar() {
|
||||||
|
let v1 = Normal::new(1.0, 2.0, 3.0);
|
||||||
|
let v2 = 2.0;
|
||||||
|
let v3 = Normal::new(2.0, 4.0, 6.0);
|
||||||
|
|
||||||
|
assert_eq!(v3, v1 * v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mul_matrix_1() {
|
||||||
|
let n = Normal::new(1.0, 2.5, 4.0);
|
||||||
|
let m = Matrix4x4::new_from_values(1.0,
|
||||||
|
2.0,
|
||||||
|
2.0,
|
||||||
|
1.5,
|
||||||
|
3.0,
|
||||||
|
6.0,
|
||||||
|
7.0,
|
||||||
|
8.0,
|
||||||
|
9.0,
|
||||||
|
2.0,
|
||||||
|
11.0,
|
||||||
|
12.0,
|
||||||
|
13.0,
|
||||||
|
7.0,
|
||||||
|
15.0,
|
||||||
|
3.0);
|
||||||
|
let nm = Normal::new(-19.258825, 5.717648, -1.770588);
|
||||||
|
assert!(((n * m) - nm).length2() < 0.00001);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn div() {
|
||||||
|
let v1 = Normal::new(1.0, 2.0, 3.0);
|
||||||
|
let v2 = 2.0;
|
||||||
|
let v3 = Normal::new(0.5, 1.0, 1.5);
|
||||||
|
|
||||||
|
assert_eq!(v3, v1 / v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn length() {
|
||||||
|
let n = Normal::new(1.0, 2.0, 3.0);
|
||||||
|
assert!((n.length() - 3.7416573867739413).abs() < 0.000001);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn length2() {
|
||||||
|
let n = Normal::new(1.0, 2.0, 3.0);
|
||||||
|
assert_eq!(n.length2(), 14.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn normalized() {
|
||||||
|
let n1 = Normal::new(1.0, 2.0, 3.0);
|
||||||
|
let n2 = Normal::new(0.2672612419124244, 0.5345224838248488, 0.8017837257372732);
|
||||||
|
let n3 = n1.normalized();
|
||||||
|
assert!((n3[0] - n2[0]).abs() < 0.000001);
|
||||||
|
assert!((n3[1] - n2[1]).abs() < 0.000001);
|
||||||
|
assert!((n3[2] - n2[2]).abs() < 0.000001);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dot_test() {
|
||||||
|
let v1 = Normal::new(1.0, 2.0, 3.0);
|
||||||
|
let v2 = Normal::new(1.5, 4.5, 2.5);
|
||||||
|
let v3 = 18.0f32;
|
||||||
|
|
||||||
|
assert_eq!(v3, v1.dot(v2));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cross_test() {
|
||||||
|
let v1 = Normal::new(1.0, 0.0, 0.0);
|
||||||
|
let v2 = Normal::new(0.0, 1.0, 0.0);
|
||||||
|
let v3 = Normal::new(0.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
assert_eq!(v3, v1.cross(v2));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lerp1() {
|
||||||
|
let n1 = Normal::new(1.0, 2.0, 1.0);
|
||||||
|
let n2 = Normal::new(-2.0, 1.0, -1.0);
|
||||||
|
let n3 = Normal::new(1.0, 2.0, 1.0);
|
||||||
|
|
||||||
|
assert_eq!(n3, n1.lerp(n2, 0.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lerp2() {
|
||||||
|
let n1 = Normal::new(1.0, 2.0, 1.0);
|
||||||
|
let n2 = Normal::new(-2.0, 1.0, -1.0);
|
||||||
|
let n3 = Normal::new(-2.0, 1.0, -1.0);
|
||||||
|
|
||||||
|
assert_eq!(n3, n1.lerp(n2, 1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lerp3() {
|
||||||
|
let n1 = Normal::new(1.0, 2.0, 1.0);
|
||||||
|
let n2 = Normal::new(-2.0, 1.0, -1.0);
|
||||||
|
let n3 = Normal::new(-0.5, 1.5, 0.0);
|
||||||
|
|
||||||
|
assert_eq!(n3, n1.lerp(n2, 0.5));
|
||||||
|
}
|
||||||
|
}
|
247
src/point.rs
Normal file
247
src/point.rs
Normal file
|
@ -0,0 +1,247 @@
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use std::ops::{Index, IndexMut, Add, Sub, Mul};
|
||||||
|
use std::cmp::PartialEq;
|
||||||
|
|
||||||
|
use lerp::Lerp;
|
||||||
|
use float4::Float4;
|
||||||
|
use vector::Vector;
|
||||||
|
use matrix::Matrix4x4;
|
||||||
|
|
||||||
|
/// A position in 3d homogeneous space.
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct Point {
|
||||||
|
pub co: Float4,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Point {
|
||||||
|
pub fn new(x: f32, y: f32, z: f32) -> Point {
|
||||||
|
Point { co: Float4::new(x, y, z, 1.0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the point in standardized coordinates, where the
|
||||||
|
/// fourth homogeneous component has been normalized to 1.0.
|
||||||
|
pub fn norm(&self) -> Point {
|
||||||
|
Point { co: self.co / self.co[3] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Index<usize> for Point {
|
||||||
|
type Output = f32;
|
||||||
|
|
||||||
|
fn index(&self, index: usize) -> &f32 {
|
||||||
|
debug_assert!(index < 3);
|
||||||
|
|
||||||
|
&self.co[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<usize> for Point {
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut f32 {
|
||||||
|
debug_assert!(index < 3);
|
||||||
|
|
||||||
|
&mut self.co[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl PartialEq for Point {
|
||||||
|
fn eq(&self, other: &Point) -> bool {
|
||||||
|
self.co == other.co
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Add<Vector> for Point {
|
||||||
|
type Output = Point;
|
||||||
|
|
||||||
|
fn add(self, other: Vector) -> Point {
|
||||||
|
Point { co: self.co + other.co }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Sub for Point {
|
||||||
|
type Output = Vector;
|
||||||
|
|
||||||
|
fn sub(self, other: Point) -> Vector {
|
||||||
|
Vector { co: self.norm().co - other.norm().co }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<Matrix4x4> for Point {
|
||||||
|
type Output = Point;
|
||||||
|
|
||||||
|
fn mul(self, other: Matrix4x4) -> Point {
|
||||||
|
Point {
|
||||||
|
co: Float4::new((self.co * other[0]).h_sum(),
|
||||||
|
(self.co * other[1]).h_sum(),
|
||||||
|
(self.co * other[2]).h_sum(),
|
||||||
|
(self.co * other[3]).h_sum()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Lerp for Point {
|
||||||
|
fn lerp(self, other: Point, alpha: f32) -> Point {
|
||||||
|
let s = self.norm();
|
||||||
|
let o = other.norm();
|
||||||
|
Point { co: (s.co * (1.0 - alpha)) + (o.co * alpha) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use vector::Vector;
|
||||||
|
use lerp::Lerp;
|
||||||
|
use matrix::Matrix4x4;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn norm() {
|
||||||
|
let mut p1 = Point::new(1.0, 2.0, 3.0);
|
||||||
|
let p2 = Point::new(2.0, 4.0, 6.0);
|
||||||
|
p1.co[3] = 0.5;
|
||||||
|
|
||||||
|
assert_eq!(p2, p1.norm());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add() {
|
||||||
|
let p1 = Point::new(1.0, 2.0, 3.0);
|
||||||
|
let v1 = Vector::new(1.5, 4.5, 2.5);
|
||||||
|
let p2 = Point::new(2.5, 6.5, 5.5);
|
||||||
|
|
||||||
|
assert_eq!(p2, p1 + v1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sub() {
|
||||||
|
let p1 = Point::new(1.0, 2.0, 3.0);
|
||||||
|
let p2 = Point::new(1.5, 4.5, 2.5);
|
||||||
|
let v1 = Vector::new(-0.5, -2.5, 0.5);
|
||||||
|
|
||||||
|
assert_eq!(v1, p1 - p2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mul_matrix_1() {
|
||||||
|
let p = Point::new(1.0, 2.5, 4.0);
|
||||||
|
let m = Matrix4x4::new_from_values(1.0,
|
||||||
|
2.0,
|
||||||
|
2.0,
|
||||||
|
1.5,
|
||||||
|
3.0,
|
||||||
|
6.0,
|
||||||
|
7.0,
|
||||||
|
8.0,
|
||||||
|
9.0,
|
||||||
|
2.0,
|
||||||
|
11.0,
|
||||||
|
12.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
1.0);
|
||||||
|
let pm = Point::new(15.5, 54.0, 70.0);
|
||||||
|
assert_eq!(p * m, pm);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mul_matrix_2() {
|
||||||
|
let p = Point::new(1.0, 2.5, 4.0);
|
||||||
|
let m = Matrix4x4::new_from_values(1.0,
|
||||||
|
2.0,
|
||||||
|
2.0,
|
||||||
|
1.5,
|
||||||
|
3.0,
|
||||||
|
6.0,
|
||||||
|
7.0,
|
||||||
|
8.0,
|
||||||
|
9.0,
|
||||||
|
2.0,
|
||||||
|
11.0,
|
||||||
|
12.0,
|
||||||
|
2.0,
|
||||||
|
3.0,
|
||||||
|
1.0,
|
||||||
|
5.0);
|
||||||
|
let mut pm = Point::new(15.5, 54.0, 70.0);
|
||||||
|
pm.co[3] = 18.5;
|
||||||
|
assert_eq!(p * m, pm);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mul_matrix_3() {
|
||||||
|
// Make sure matrix multiplication composes the way one would expect
|
||||||
|
let p = Point::new(1.0, 2.5, 4.0);
|
||||||
|
let m1 = Matrix4x4::new_from_values(1.0,
|
||||||
|
2.0,
|
||||||
|
2.0,
|
||||||
|
1.5,
|
||||||
|
3.0,
|
||||||
|
6.0,
|
||||||
|
7.0,
|
||||||
|
8.0,
|
||||||
|
9.0,
|
||||||
|
2.0,
|
||||||
|
11.0,
|
||||||
|
12.0,
|
||||||
|
13.0,
|
||||||
|
7.0,
|
||||||
|
15.0,
|
||||||
|
3.0);
|
||||||
|
let m2 = Matrix4x4::new_from_values(4.0,
|
||||||
|
1.0,
|
||||||
|
2.0,
|
||||||
|
3.5,
|
||||||
|
3.0,
|
||||||
|
6.0,
|
||||||
|
5.0,
|
||||||
|
2.0,
|
||||||
|
2.0,
|
||||||
|
2.0,
|
||||||
|
4.0,
|
||||||
|
12.0,
|
||||||
|
5.0,
|
||||||
|
7.0,
|
||||||
|
8.0,
|
||||||
|
11.0);
|
||||||
|
println!("{:?}", m1 * m2);
|
||||||
|
|
||||||
|
let pmm1 = p * (m1 * m2);
|
||||||
|
let pmm2 = (p * m1) * m2;
|
||||||
|
|
||||||
|
assert!((pmm1 - pmm2).length2() <= 0.00001); // Assert pmm1 and pmm2 are roughly equal
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lerp1() {
|
||||||
|
let p1 = Point::new(1.0, 2.0, 1.0);
|
||||||
|
let p2 = Point::new(-2.0, 1.0, -1.0);
|
||||||
|
let p3 = Point::new(1.0, 2.0, 1.0);
|
||||||
|
|
||||||
|
assert_eq!(p3, p1.lerp(p2, 0.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lerp2() {
|
||||||
|
let p1 = Point::new(1.0, 2.0, 1.0);
|
||||||
|
let p2 = Point::new(-2.0, 1.0, -1.0);
|
||||||
|
let p3 = Point::new(-2.0, 1.0, -1.0);
|
||||||
|
|
||||||
|
assert_eq!(p3, p1.lerp(p2, 1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lerp3() {
|
||||||
|
let p1 = Point::new(1.0, 2.0, 1.0);
|
||||||
|
let p2 = Point::new(-2.0, 1.0, -1.0);
|
||||||
|
let p3 = Point::new(-0.5, 1.5, 0.0);
|
||||||
|
|
||||||
|
assert_eq!(p3, p1.lerp(p2, 0.5));
|
||||||
|
}
|
||||||
|
}
|
131
src/vector.rs
131
src/vector.rs
|
@ -6,17 +6,30 @@ use std::cmp::PartialEq;
|
||||||
use lerp::Lerp;
|
use lerp::Lerp;
|
||||||
use math::{DotProduct, CrossProduct};
|
use math::{DotProduct, CrossProduct};
|
||||||
use float4::Float4;
|
use float4::Float4;
|
||||||
|
use matrix::Matrix4x4;
|
||||||
|
|
||||||
/// A direction vector in 3d homogeneous space.
|
/// A direction vector in 3d homogeneous space.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct Vector {
|
pub struct Vector {
|
||||||
co: Float4,
|
pub co: Float4,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vector {
|
impl Vector {
|
||||||
pub fn new(x: f32, y: f32, z: f32) -> Vector {
|
pub fn new(x: f32, y: f32, z: f32) -> Vector {
|
||||||
Vector { co: Float4::new(x, y, z, 0.0) }
|
Vector { co: Float4::new(x, y, z, 0.0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn length(&self) -> f32 {
|
||||||
|
(self.co * self.co).h_sum().sqrt()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn length2(&self) -> f32 {
|
||||||
|
(self.co * self.co).h_sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn normalized(&self) -> Vector {
|
||||||
|
*self / self.length()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,6 +86,20 @@ impl Mul<f32> for Vector {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Mul<Matrix4x4> for Vector {
|
||||||
|
type Output = Vector;
|
||||||
|
|
||||||
|
fn mul(self, other: Matrix4x4) -> Vector {
|
||||||
|
Vector {
|
||||||
|
co: Float4::new((self.co * other[0]).h_sum(),
|
||||||
|
(self.co * other[1]).h_sum(),
|
||||||
|
(self.co * other[2]).h_sum(),
|
||||||
|
(self.co * other[3]).h_sum()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Div<f32> for Vector {
|
impl Div<f32> for Vector {
|
||||||
type Output = Vector;
|
type Output = Vector;
|
||||||
|
|
||||||
|
@ -84,7 +111,7 @@ impl Div<f32> for Vector {
|
||||||
|
|
||||||
impl Lerp for Vector {
|
impl Lerp for Vector {
|
||||||
fn lerp(self, other: Vector, alpha: f32) -> Vector {
|
fn lerp(self, other: Vector, alpha: f32) -> Vector {
|
||||||
self + ((other - self) * alpha)
|
(self * (1.0 - alpha)) + (other * alpha)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,6 +139,8 @@ impl CrossProduct for Vector {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use math::*;
|
use math::*;
|
||||||
|
use lerp::Lerp;
|
||||||
|
use matrix::Matrix4x4;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn add() {
|
fn add() {
|
||||||
|
@ -132,7 +161,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn mul() {
|
fn mul_scalar() {
|
||||||
let v1 = Vector::new(1.0, 2.0, 3.0);
|
let v1 = Vector::new(1.0, 2.0, 3.0);
|
||||||
let v2 = 2.0;
|
let v2 = 2.0;
|
||||||
let v3 = Vector::new(2.0, 4.0, 6.0);
|
let v3 = Vector::new(2.0, 4.0, 6.0);
|
||||||
|
@ -140,6 +169,53 @@ mod tests {
|
||||||
assert_eq!(v3, v1 * v2);
|
assert_eq!(v3, v1 * v2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mul_matrix_1() {
|
||||||
|
let v = Vector::new(1.0, 2.5, 4.0);
|
||||||
|
let m = Matrix4x4::new_from_values(1.0,
|
||||||
|
2.0,
|
||||||
|
2.0,
|
||||||
|
1.5,
|
||||||
|
3.0,
|
||||||
|
6.0,
|
||||||
|
7.0,
|
||||||
|
8.0,
|
||||||
|
9.0,
|
||||||
|
2.0,
|
||||||
|
11.0,
|
||||||
|
12.0,
|
||||||
|
13.0,
|
||||||
|
7.0,
|
||||||
|
15.0,
|
||||||
|
3.0);
|
||||||
|
let mut vm = Vector::new(14.0, 46.0, 58.0);
|
||||||
|
vm.co[3] = 90.5;
|
||||||
|
assert_eq!(v * m, vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mul_matrix_2() {
|
||||||
|
let v = Vector::new(1.0, 2.5, 4.0);
|
||||||
|
let m = Matrix4x4::new_from_values(1.0,
|
||||||
|
2.0,
|
||||||
|
2.0,
|
||||||
|
1.5,
|
||||||
|
3.0,
|
||||||
|
6.0,
|
||||||
|
7.0,
|
||||||
|
8.0,
|
||||||
|
9.0,
|
||||||
|
2.0,
|
||||||
|
11.0,
|
||||||
|
12.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
1.0);
|
||||||
|
let vm = Vector::new(14.0, 46.0, 58.0);
|
||||||
|
assert_eq!(v * m, vm);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn div() {
|
fn div() {
|
||||||
let v1 = Vector::new(1.0, 2.0, 3.0);
|
let v1 = Vector::new(1.0, 2.0, 3.0);
|
||||||
|
@ -149,6 +225,28 @@ mod tests {
|
||||||
assert_eq!(v3, v1 / v2);
|
assert_eq!(v3, v1 / v2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn length() {
|
||||||
|
let v = Vector::new(1.0, 2.0, 3.0);
|
||||||
|
assert!((v.length() - 3.7416573867739413).abs() < 0.000001);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn length2() {
|
||||||
|
let v = Vector::new(1.0, 2.0, 3.0);
|
||||||
|
assert_eq!(v.length2(), 14.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn normalized() {
|
||||||
|
let v1 = Vector::new(1.0, 2.0, 3.0);
|
||||||
|
let v2 = Vector::new(0.2672612419124244, 0.5345224838248488, 0.8017837257372732);
|
||||||
|
let v3 = v1.normalized();
|
||||||
|
assert!((v3[0] - v2[0]).abs() < 0.000001);
|
||||||
|
assert!((v3[1] - v2[1]).abs() < 0.000001);
|
||||||
|
assert!((v3[2] - v2[2]).abs() < 0.000001);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn dot_test() {
|
fn dot_test() {
|
||||||
let v1 = Vector::new(1.0, 2.0, 3.0);
|
let v1 = Vector::new(1.0, 2.0, 3.0);
|
||||||
|
@ -166,4 +264,31 @@ mod tests {
|
||||||
|
|
||||||
assert_eq!(v3, v1.cross(v2));
|
assert_eq!(v3, v1.cross(v2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lerp1() {
|
||||||
|
let v1 = Vector::new(1.0, 2.0, 1.0);
|
||||||
|
let v2 = Vector::new(-2.0, 1.0, -1.0);
|
||||||
|
let v3 = Vector::new(1.0, 2.0, 1.0);
|
||||||
|
|
||||||
|
assert_eq!(v3, v1.lerp(v2, 0.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lerp2() {
|
||||||
|
let v1 = Vector::new(1.0, 2.0, 1.0);
|
||||||
|
let v2 = Vector::new(-2.0, 1.0, -1.0);
|
||||||
|
let v3 = Vector::new(-2.0, 1.0, -1.0);
|
||||||
|
|
||||||
|
assert_eq!(v3, v1.lerp(v2, 1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lerp3() {
|
||||||
|
let v1 = Vector::new(1.0, 2.0, 1.0);
|
||||||
|
let v2 = Vector::new(-2.0, 1.0, -1.0);
|
||||||
|
let v3 = Vector::new(-0.5, 1.5, 0.0);
|
||||||
|
|
||||||
|
assert_eq!(v3, v1.lerp(v2, 0.5));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user