Basis trait now uses internal iterators to avoid allocations.
This commit is contained in:
parent
6fd9696253
commit
68d601a642
|
@ -79,15 +79,13 @@ macro_rules! test_basis_impl(
|
|||
($t: ty) => (
|
||||
for 10000.times
|
||||
{
|
||||
let basis = Basis::canonical_basis::<$t>();
|
||||
do Basis::canonical_basis::<$t> |e1|
|
||||
{
|
||||
do Basis::canonical_basis::<$t> |e2|
|
||||
{ assert!(e1 == e2 || e1.dot(&e2).approx_eq(&Zero::zero())) }
|
||||
|
||||
// check vectors form an ortogonal basis
|
||||
assert!(
|
||||
do basis.iter().zip(basis.iter()).all
|
||||
|(e1, e2)| { e1 == e2 || e1.dot(e2).approx_eq(&Zero::zero()) }
|
||||
);
|
||||
// check vectors form an orthonormal basis
|
||||
assert!(basis.iter().all(|e| e.norm().approx_eq(&One::one())));
|
||||
assert!(e1.norm().approx_eq(&One::one()));
|
||||
}
|
||||
}
|
||||
);
|
||||
)
|
||||
|
@ -98,17 +96,17 @@ macro_rules! test_subspace_basis_impl(
|
|||
{
|
||||
let v : $t = random();
|
||||
let v1 = v.normalized();
|
||||
let subbasis = v1.orthogonal_subspace_basis();
|
||||
|
||||
// check vectors are orthogonal to v1
|
||||
assert!(subbasis.iter().all(|e| v1.dot(e).approx_eq(&Zero::zero())));
|
||||
// check vectors form an ortogonal basis
|
||||
assert!(
|
||||
do subbasis.iter().zip(subbasis.iter()).all
|
||||
|(e1, e2)| { e1 == e2 || e1.dot(e2).approx_eq(&Zero::zero()) }
|
||||
);
|
||||
// check vectors form an orthonormal basis
|
||||
assert!(subbasis.iter().all(|e| e.norm().approx_eq(&One::one())));
|
||||
do v1.orthonormal_subspace_basis() |e1|
|
||||
{
|
||||
// check vectors are orthogonal to v1
|
||||
assert!(v1.dot(&e1).approx_eq(&Zero::zero()));
|
||||
// check vectors form an orthonormal basis
|
||||
assert!(e1.norm().approx_eq(&One::one()));
|
||||
// check vectors form an ortogonal basis
|
||||
do v1.orthonormal_subspace_basis() |e2|
|
||||
{ assert!(e1 == e2 || e1.dot(&e2).approx_eq(&Zero::zero())) }
|
||||
}
|
||||
}
|
||||
);
|
||||
)
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
pub trait Basis
|
||||
{
|
||||
/// Computes the canonical basis of the space in which this object lives.
|
||||
// FIXME: need type-associated values
|
||||
// FIXME: this will make allocations… this is bad
|
||||
fn canonical_basis() -> ~[Self];
|
||||
fn orthogonal_subspace_basis(&self) -> ~[Self];
|
||||
// FIXME: implement the for loop protocol?
|
||||
fn canonical_basis(&fn(Self));
|
||||
fn orthonormal_subspace_basis(&self, &fn(Self));
|
||||
}
|
||||
|
|
|
@ -88,27 +88,23 @@ macro_rules! basis_impl(
|
|||
($t: ident, $dim: expr) => (
|
||||
impl<N: Copy + DivisionRing + Algebraic + ApproxEq<N>> Basis for $t<N>
|
||||
{
|
||||
pub fn canonical_basis() -> ~[$t<N>]
|
||||
pub fn canonical_basis(f: &fn($t<N>))
|
||||
{
|
||||
let mut res : ~[$t<N>] = ~[];
|
||||
|
||||
for iterate(0u, $dim) |i|
|
||||
{
|
||||
let mut basis_element : $t<N> = Zero::zero();
|
||||
|
||||
basis_element.at[i] = One::one();
|
||||
|
||||
res.push(basis_element);
|
||||
f(basis_element);
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
pub fn orthogonal_subspace_basis(&self) -> ~[$t<N>]
|
||||
pub fn orthonormal_subspace_basis(&self, f: &fn($t<N>))
|
||||
{
|
||||
// compute the basis of the orthogonal subspace using Gram-Schmidt
|
||||
// orthogonalization algorithm
|
||||
let mut res : ~[$t<N>] = ~[];
|
||||
let mut basis: ~[$t<N>] = ~[];
|
||||
|
||||
for iterate(0u, $dim) |i|
|
||||
{
|
||||
|
@ -116,21 +112,25 @@ macro_rules! basis_impl(
|
|||
|
||||
basis_element.at[i] = One::one();
|
||||
|
||||
if res.len() == $dim - 1
|
||||
if basis.len() == $dim - 1
|
||||
{ break; }
|
||||
|
||||
let mut elt = copy basis_element;
|
||||
|
||||
elt = elt - self.scalar_mul(&basis_element.dot(self));
|
||||
|
||||
for res.iter().advance |v|
|
||||
for basis.iter().advance |v|
|
||||
{ elt = elt - v.scalar_mul(&elt.dot(v)) };
|
||||
|
||||
if !elt.sqnorm().approx_eq(&Zero::zero())
|
||||
{ res.push(elt.normalized()); }
|
||||
{
|
||||
let new_element = elt.normalized();
|
||||
|
||||
f(copy new_element);
|
||||
|
||||
basis.push(new_element);
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
@ -27,44 +27,42 @@ impl<N: Mul<N, N> + Sub<N, N>> Cross<Vec3<N>> for Vec3<N>
|
|||
|
||||
impl<N: One> Basis for Vec1<N>
|
||||
{
|
||||
#[inline]
|
||||
fn canonical_basis() -> ~[Vec1<N>]
|
||||
{ ~[ Vec1::new([One::one()]) ] } // FIXME: this should be static
|
||||
#[inline(always)]
|
||||
fn canonical_basis(f: &fn(Vec1<N>))
|
||||
{ f(Vec1::new([One::one()])) }
|
||||
|
||||
#[inline]
|
||||
fn orthogonal_subspace_basis(&self) -> ~[Vec1<N>]
|
||||
{ ~[] }
|
||||
#[inline(always)]
|
||||
fn orthonormal_subspace_basis(&self, _: &fn(Vec1<N>))
|
||||
{ }
|
||||
}
|
||||
|
||||
impl<N: Copy + One + Zero + Neg<N>> Basis for Vec2<N>
|
||||
{
|
||||
#[inline]
|
||||
fn canonical_basis() -> ~[Vec2<N>]
|
||||
fn canonical_basis(f: &fn(Vec2<N>))
|
||||
{
|
||||
// FIXME: this should be static
|
||||
~[ Vec2::new([One::one(), Zero::zero()]),
|
||||
Vec2::new([Zero::zero(), One::one()]) ]
|
||||
f(Vec2::new([One::one(), Zero::zero()]));
|
||||
f(Vec2::new([Zero::zero(), One::one()]));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn orthogonal_subspace_basis(&self) -> ~[Vec2<N>]
|
||||
{ ~[ Vec2::new([-self.at[1], copy self.at[0]]) ] }
|
||||
fn orthonormal_subspace_basis(&self, f: &fn(Vec2<N>))
|
||||
{ f(Vec2::new([-self.at[1], copy self.at[0]])) }
|
||||
}
|
||||
|
||||
impl<N: Copy + DivisionRing + Ord + Algebraic>
|
||||
Basis for Vec3<N>
|
||||
{
|
||||
#[inline]
|
||||
fn canonical_basis() -> ~[Vec3<N>]
|
||||
#[inline(always)]
|
||||
fn canonical_basis(f: &fn(Vec3<N>))
|
||||
{
|
||||
// FIXME: this should be static
|
||||
~[ Vec3::new([One::one(), Zero::zero(), Zero::zero()]),
|
||||
Vec3::new([Zero::zero(), One::one(), Zero::zero()]),
|
||||
Vec3::new([Zero::zero(), Zero::zero(), One::one()]) ]
|
||||
f(Vec3::new([One::one(), Zero::zero(), Zero::zero()]));
|
||||
f(Vec3::new([Zero::zero(), One::one(), Zero::zero()]));
|
||||
f(Vec3::new([Zero::zero(), Zero::zero(), One::one()]));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn orthogonal_subspace_basis(&self) -> ~[Vec3<N>]
|
||||
#[inline(always)]
|
||||
fn orthonormal_subspace_basis(&self, f: &fn(Vec3<N>))
|
||||
{
|
||||
let a =
|
||||
if abs(copy self.at[0]) > abs(copy self.at[1])
|
||||
|
@ -72,6 +70,7 @@ Basis for Vec3<N>
|
|||
else
|
||||
{ Vec3::new([Zero::zero(), -self.at[2], copy self.at[1]]).normalized() };
|
||||
|
||||
~[ a.cross(self), a ]
|
||||
f(a.cross(self));
|
||||
f(a);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue