Remove algebraic traits to simplify library

Pragmatically, according to advice from zeuxcg, I have decided to remove the algebraic traits. This has simplified the library a great deal by reducing indirection and removing redundant code.cx
This commit is contained in:
Brendan Zabarauskas 2013-09-03 13:54:03 +10:00
parent c404092879
commit 68bd70f78f
23 changed files with 374 additions and 1028 deletions

View file

@ -17,7 +17,12 @@
use std::vec::{VecIterator, VecMutIterator};
pub trait Array<T, Slice> {
pub trait Array
<
T: Clone,
Slice
>
{
fn i<'a>(&'a self, i: uint) -> &'a T;
fn mut_i<'a>(&'a mut self, i: uint) -> &'a mut T;
fn as_slice<'a>(&'a self) -> &'a Slice;
@ -27,21 +32,29 @@ pub trait Array<T, Slice> {
fn iter<'a>(&'a self) -> VecIterator<'a, T>;
fn mut_iter<'a>(&'a mut self) -> VecMutIterator<'a, T>;
/// Swap two elements of the type in place.
#[inline]
fn map<U, SliceU, UU: Array<U, SliceU>>(&self, f: &fn(&T) -> U) -> UU {
fn swap(&mut self, a: uint, b: uint) {
let tmp = self.i(a).clone();
*self.mut_i(a) = self.i(b).clone();
*self.mut_i(b) = tmp;
}
#[inline]
fn map<U: Clone, SliceU, UU: Array<U, SliceU>>(&self, f: &fn(&T) -> U) -> UU {
Array::build(|i| f(self.i(i)))
}
#[inline]
fn bimap<U, SliceU, UU: Array<U, SliceU>,
V, SliceV, VV: Array<V, SliceV>>(&self, other: &UU, f: &fn(&T, &U) -> V) -> VV {
fn bimap<U: Clone, SliceU, UU: Array<U, SliceU>,
V: Clone, SliceV, VV: Array<V, SliceV>>(&self, other: &UU, f: &fn(&T, &U) -> V) -> VV {
Array::build(|i| f(self.i(i), other.i(i)))
}
}
macro_rules! array(
(impl<$S:ident> $Self:ty -> [$T:ty, ..$n:expr]) => (
impl<$S> Array<$T, [$T,..$n]> for $Self {
impl<$S: Clone> Array<$T, [$T,..$n]> for $Self {
#[inline]
fn i<'a>(&'a self, i: uint) -> &'a $T {
&'a self.as_slice()[i]
@ -114,14 +127,3 @@ macro_rules! array_op(
(impl<$S:ident> $Self:ty / $Other:ty -> $Result:ty) => (array_op!(impl<$S> (Div, div) for ($Self, $Other) -> $Result));
(impl<$S:ident> $Self:ty % $Other:ty -> $Result:ty) => (array_op!(impl<$S> (Rem, rem) for ($Self, $Other) -> $Result));
)
/// An `Array` whose elements can be cloned
pub trait ClonableArray<T: Clone, Slice>: Array<T, Slice> {
/// Swap two elements of the type in place.
#[inline]
fn swap(&mut self, a: uint, b: uint) {
let tmp = self.i(a).clone();
*self.mut_i(a) = self.i(b).clone();
*self.mut_i(b) = tmp;
}
}

View file

@ -22,5 +22,8 @@
#[license = "ASL2"];
#[crate_type = "lib"];
pub mod traits;
pub mod types;
pub mod array;
pub mod matrix;
pub mod point;
pub mod quaternion;
pub mod vector;

View file

@ -13,18 +13,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use std::num::{One, one, zero};
use std::num::{one, zero};
use traits::alg::*;
use types::vector::*;
use array::*;
use vector::*;
#[deriving(Clone, Eq, Zero)] pub struct Mat2<S> { x: Vec2<S>, y: Vec2<S> }
#[deriving(Clone, Eq, Zero)] pub struct Mat3<S> { x: Vec3<S>, y: Vec3<S>, z: Vec3<S> }
#[deriving(Clone, Eq, Zero)] pub struct Mat4<S> { x: Vec4<S>, y: Vec4<S>, z: Vec4<S>, w: Vec4<S> }
#[deriving(Clone, Eq)] pub struct Mat2<S> { x: Vec2<S>, y: Vec2<S> }
#[deriving(Clone, Eq)] pub struct Mat3<S> { x: Vec3<S>, y: Vec3<S>, z: Vec3<S> }
#[deriving(Clone, Eq)] pub struct Mat4<S> { x: Vec4<S>, y: Vec4<S>, z: Vec4<S>, w: Vec4<S> }
// Constructors
impl<S: Clone + Field> Mat2<S> {
impl<S: Clone + Num> Mat2<S> {
#[inline]
pub fn new(c0r0: S, c0r1: S,
c1r0: S, c1r1: S) -> Mat2<S> {
@ -54,7 +54,7 @@ impl<S: Clone + Field> Mat2<S> {
}
}
impl<S: Clone + Field> Mat3<S> {
impl<S: Clone + Num> Mat3<S> {
#[inline]
pub fn new(c0r0:S, c0r1:S, c0r2:S,
c1r0:S, c1r1:S, c1r2:S,
@ -87,7 +87,7 @@ impl<S: Clone + Field> Mat3<S> {
}
}
impl<S: Clone + Field> Mat4<S> {
impl<S: Clone + Num> Mat4<S> {
#[inline]
pub fn new(c0r0: S, c0r1: S, c0r2: S, c0r3: S,
c1r0: S, c1r1: S, c1r2: S, c1r3: S,
@ -129,62 +129,80 @@ array!(impl<S> Mat2<S> -> [Vec2<S>, ..2])
array!(impl<S> Mat3<S> -> [Vec3<S>, ..3])
array!(impl<S> Mat4<S> -> [Vec4<S>, ..4])
impl<S: Clone + Field> ClonableArray<Vec2<S>, [Vec2<S>, ..2]> for Mat2<S>;
impl<S: Clone + Field> ClonableArray<Vec3<S>, [Vec3<S>, ..3]> for Mat3<S>;
impl<S: Clone + Field> ClonableArray<Vec4<S>, [Vec4<S>, ..4]> for Mat4<S>;
scalar_op!(impl Mat2<S> * S -> Mat2<S>)
scalar_op!(impl Mat3<S> * S -> Mat3<S>)
scalar_op!(impl Mat4<S> * S -> Mat4<S>)
scalar_op!(impl Mat2<S> / S -> Mat2<S>)
scalar_op!(impl Mat3<S> / S -> Mat3<S>)
scalar_op!(impl Mat4<S> / S -> Mat4<S>)
scalar_op!(impl Mat2<S> % S -> Mat2<S>)
scalar_op!(impl Mat3<S> % S -> Mat3<S>)
scalar_op!(impl Mat4<S> % S -> Mat4<S>)
impl<S: Field> ScalarMul<S> for Mat2<S>;
impl<S: Field> ScalarMul<S> for Mat3<S>;
impl<S: Field> ScalarMul<S> for Mat4<S>;
array_op!(impl<S> Mat2<S> + Mat2<S> -> Mat2<S>)
array_op!(impl<S> Mat3<S> + Mat3<S> -> Mat3<S>)
array_op!(impl<S> Mat4<S> + Mat4<S> -> Mat4<S>)
array_op!(impl<S> Mat2<S> - Mat2<S> -> Mat2<S>)
array_op!(impl<S> Mat3<S> - Mat3<S> -> Mat3<S>)
array_op!(impl<S> Mat4<S> - Mat4<S> -> Mat4<S>)
array_op!(impl<S> -Mat2<S> -> Mat2<S>)
array_op!(impl<S> -Mat3<S> -> Mat3<S>)
array_op!(impl<S> -Mat4<S> -> Mat4<S>)
impl<S: Field> Module<S> for Mat2<S>;
impl<S: Field> Module<S> for Mat3<S>;
impl<S: Field> Module<S> for Mat4<S>;
impl<S: Clone + Field> One for Mat2<S> {
#[inline] fn one() -> Mat2<S> { Mat2::ident() }
}
impl<S: Clone + Field> One for Mat3<S> {
#[inline] fn one() -> Mat3<S> { Mat3::ident() }
}
impl<S: Clone + Field> One for Mat4<S> {
#[inline] fn one() -> Mat4<S> { Mat4::ident() }
}
impl<S: Clone + Field> Ring<S> for Mat2<S>;
impl<S: Clone + Field> Ring<S> for Mat3<S>;
impl<S: Clone + Field> Ring<S> for Mat4<S>;
impl<S: Clone + Field + ApproxEq<S>>
Matrix
pub trait Matrix
<
S,
Vec2<S>, [S, ..2], [Vec2<S>, ..2],
Vec2<S>, [S, ..2], [Vec2<S>, ..2],
Mat2<S>
S: Num + Clone + ApproxEq<S>, Slice,
V: Clone + Vector<S, VSlice> + Array<S, VSlice>, VSlice
>
: Array<V, Slice>
{
#[inline]
fn c<'a>(&'a self, c: uint) -> &'a V { self.i(c) }
#[inline]
fn mut_c<'a>(&'a mut self, c: uint) -> &'a mut V { self.mut_i(c) }
#[inline]
fn swap_c(&mut self, a: uint, b: uint) {
let tmp = self.c(a).clone();
*self.mut_c(a) = self.c(b).clone();
*self.mut_c(b) = tmp;
}
fn r(&self, r: uint) -> V;
#[inline]
fn swap_r(&mut self, a: uint, b: uint) {
for c in self.mut_iter() { c.swap(a, b) }
}
#[inline]
fn cr<'a>(&'a self, c: uint, r: uint) -> &'a S { self.i(c).i(r) }
#[inline]
fn mut_cr<'a>(&'a mut self, c: uint, r: uint) -> &'a mut S {
self.mut_i(c).mut_i(r)
}
#[inline]
fn swap_cr(&mut self, a: (uint, uint), b: (uint, uint)) {
let (ca, ra) = a;
let (cb, rb) = b;
let tmp = self.cr(ca, ra).clone();
*self.mut_cr(ca, ra) = self.cr(cb, rb).clone();
*self.mut_cr(cb, rb) = tmp;
}
// fn swap_cr(&mut self, (ca, ra): (uint, uint), (cb, rb): (uint, uint)) {
// let tmp = self.cr(ca, ra).clone();
// *self.mut_cr(ca, ra) = self.cr(cb, rb).clone();
// *self.mut_cr(cb, rb) = tmp;
// }
fn transpose(&self) -> Self;
fn transpose_self(&mut self);
fn trace(&self) -> S;
fn determinant(&self) -> S;
fn invert(&self) -> Option<Self>;
#[inline]
fn invert_self(&mut self) {
*self = self.invert().expect("Attempted to invert a matrix with zero determinant.");
}
#[inline]
fn is_invertible(&self) -> bool {
!self.determinant().approx_eq(&zero::<S>())
}
// pub fn is_identity(&self) -> bool;
// pub fn is_diagonal(&self) -> bool;
// pub fn is_rotated(&self) -> bool;
// pub fn is_symmetric(&self) -> bool;
}
impl<S: Clone + Num + ApproxEq<S>>
Matrix<S, [Vec2<S>, ..2], Vec2<S>, [S, ..2]>
for Mat2<S>
{
#[inline]
@ -197,62 +215,7 @@ for Mat2<S>
Mat2::new(self.cr(0, 0).clone(), self.cr(1, 0).clone(),
self.cr(0, 1).clone(), self.cr(1, 1).clone())
}
}
impl<S: Clone + Field + ApproxEq<S>>
Matrix
<
S,
Vec3<S>, [S, ..3], [Vec3<S>, ..3],
Vec3<S>, [S, ..3], [Vec3<S>, ..3],
Mat3<S>
>
for Mat3<S>
{
#[inline]
fn r(&self, r: uint) -> Vec3<S> {
Vec3::new(self.i(0).i(r).clone(),
self.i(1).i(r).clone(),
self.i(2).i(r).clone())
}
fn transpose(&self) -> Mat3<S> {
Mat3::new(self.cr(0, 0).clone(), self.cr(1, 0).clone(), self.cr(2, 0).clone(),
self.cr(0, 1).clone(), self.cr(1, 1).clone(), self.cr(2, 1).clone(),
self.cr(0, 2).clone(), self.cr(1, 2).clone(), self.cr(2, 2).clone())
}
}
impl<S: Clone + Field + ApproxEq<S>>
Matrix
<
S,
Vec4<S>, [S, ..4], [Vec4<S>, ..4],
Vec4<S>, [S, ..4], [Vec4<S>, ..4],
Mat4<S>
>
for Mat4<S>
{
#[inline]
fn r(&self, r: uint) -> Vec4<S> {
Vec4::new(self.i(0).i(r).clone(),
self.i(1).i(r).clone(),
self.i(2).i(r).clone(),
self.i(2).i(r).clone())
}
fn transpose(&self) -> Mat4<S> {
Mat4::new(self.cr(0, 0).clone(), self.cr(1, 0).clone(), self.cr(2, 0).clone(), self.cr(3, 0).clone(),
self.cr(0, 1).clone(), self.cr(1, 1).clone(), self.cr(2, 1).clone(), self.cr(3, 1).clone(),
self.cr(0, 2).clone(), self.cr(1, 2).clone(), self.cr(2, 2).clone(), self.cr(3, 2).clone(),
self.cr(0, 3).clone(), self.cr(1, 3).clone(), self.cr(2, 3).clone(), self.cr(3, 3).clone())
}
}
impl<S: Clone + Field + ApproxEq<S>>
SquareMatrix<S, Vec2<S>, [S, ..2], [Vec2<S>, ..2]>
for Mat2<S>
{
#[inline]
fn transpose_self(&mut self) {
self.swap_cr((0, 1), (1, 0));
@ -279,10 +242,23 @@ for Mat2<S>
}
}
impl<S: Clone + Field + ApproxEq<S>>
SquareMatrix<S, Vec3<S>, [S, ..3], [Vec3<S>, ..3]>
impl<S: Clone + Num + ApproxEq<S>>
Matrix<S, [Vec3<S>, ..3], Vec3<S>, [S, ..3]>
for Mat3<S>
{
#[inline]
fn r(&self, r: uint) -> Vec3<S> {
Vec3::new(self.i(0).i(r).clone(),
self.i(1).i(r).clone(),
self.i(2).i(r).clone())
}
fn transpose(&self) -> Mat3<S> {
Mat3::new(self.cr(0, 0).clone(), self.cr(1, 0).clone(), self.cr(2, 0).clone(),
self.cr(0, 1).clone(), self.cr(1, 1).clone(), self.cr(2, 1).clone(),
self.cr(0, 2).clone(), self.cr(1, 2).clone(), self.cr(2, 2).clone())
}
#[inline]
fn transpose_self(&mut self) {
self.swap_cr((0, 1), (1, 0));
@ -306,17 +282,32 @@ for Mat3<S>
if det.approx_eq(&zero()) {
None
} else {
Some(Mat3::from_cols(self.c(1).cross(self.c(2)) / det,
self.c(2).cross(self.c(0)) / det,
self.c(0).cross(self.c(1)) / det).transpose())
Some(Mat3::from_cols(self.c(1).cross(self.c(2)).div_s(det.clone()),
self.c(2).cross(self.c(0)).div_s(det.clone()),
self.c(0).cross(self.c(1)).div_s(det.clone())).transpose())
}
}
}
impl<S: Clone + Real + Field + ApproxEq<S>>
SquareMatrix<S, Vec4<S>, [S, ..4], [Vec4<S>, ..4]>
impl<S: Clone + Real + Num + ApproxEq<S>>
Matrix<S, [Vec4<S>, ..4], Vec4<S>, [S, ..4]>
for Mat4<S>
{
#[inline]
fn r(&self, r: uint) -> Vec4<S> {
Vec4::new(self.i(0).i(r).clone(),
self.i(1).i(r).clone(),
self.i(2).i(r).clone(),
self.i(2).i(r).clone())
}
fn transpose(&self) -> Mat4<S> {
Mat4::new(self.cr(0, 0).clone(), self.cr(1, 0).clone(), self.cr(2, 0).clone(), self.cr(3, 0).clone(),
self.cr(0, 1).clone(), self.cr(1, 1).clone(), self.cr(2, 1).clone(), self.cr(3, 1).clone(),
self.cr(0, 2).clone(), self.cr(1, 2).clone(), self.cr(2, 2).clone(), self.cr(3, 2).clone(),
self.cr(0, 3).clone(), self.cr(1, 3).clone(), self.cr(2, 3).clone(), self.cr(3, 3).clone())
}
#[inline]
fn transpose_self(&mut self) {
self.swap_cr((0, 1), (1, 0));
@ -359,7 +350,7 @@ for Mat4<S>
// and essentially reduce [A|I]
let mut A = self.clone();
let mut I = one::<Mat4<S>>();
let mut I = Mat4::ident();
for j in range(0u, 4u) {
// Find largest element in col j
@ -376,17 +367,17 @@ for Mat4<S>
I.swap_c(i1, j);
// Scale col j to have a unit diagonal
*I.mut_c(j) = I.c(j) / *A.cr(j, j);
*A.mut_c(j) = A.c(j) / *A.cr(j, j);
*I.mut_c(j) = I.c(j).div_s(A.cr(j, j).clone());
*A.mut_c(j) = A.c(j).div_s(A.cr(j, j).clone());
// Eliminate off-diagonal elems in col j of A,
// doing identical ops to I
for i in range(0u, 4u) {
if i != j {
let ij_mul_aij = I.c(j) * *A.cr(i, j);
let aj_mul_aij = A.c(j) * *A.cr(i, j);
*I.mut_c(i) = I.c(i) - ij_mul_aij;
*A.mut_c(i) = A.c(i) - aj_mul_aij;
let ij_mul_aij = I.c(j).mul_s(A.cr(i, j).clone());
let aj_mul_aij = A.c(j).mul_s(A.cr(i, j).clone());
*I.mut_c(i) = I.c(i).sub_v(&ij_mul_aij);
*A.mut_c(i) = A.c(i).sub_v(&aj_mul_aij);
}
}
}
@ -396,4 +387,3 @@ for Mat4<S>
}
}
}

View file

@ -17,8 +17,10 @@
//! disinguishes them from vectors, which have a length and direction, but do
//! not have a fixed position.
use traits::alg::*;
use types::vector::{Vec2, Vec3};
use std::num::zero;
use array::*;
use vector::*;
#[deriving(Eq, Zero, Clone)]
struct Point2<S> { x: S, y: S }
@ -26,40 +28,50 @@ struct Point2<S> { x: S, y: S }
#[deriving(Eq, Zero, Clone)]
struct Point3<S> { x: S, y: S, z: S }
impl<S: Field> Point2<S> {
impl<S: Num> Point2<S> {
#[inline]
pub fn new(x: S, y: S) -> Point2<S> {
Point2 { x: x, y: y }
}
#[inline]
pub fn origin() -> Point2<S> { zero() }
}
impl<S: Field> Point3<S> {
impl<S: Num> Point3<S> {
#[inline]
pub fn new(x: S, y: S, z: S) -> Point3<S> {
Point3 { x: x, y: y, z: z }
}
#[inline]
pub fn origin() -> Point3<S> { zero() }
}
pub trait Point
<
S: Clone + Num,
V: Vector<S, Slice>,
Slice
>
: Array<S, Slice>
{
#[inline] fn mul_s(&self, s: S) -> Self { self.map(|x| x.mul(&s)) }
#[inline] fn div_s(&self, s: S) -> Self { self.map(|x| x.div(&s)) }
#[inline] fn rem_s(&self, s: S) -> Self { self.map(|x| x.rem(&s)) }
#[inline] fn add_v(&self, other: &V) -> Self { self.bimap(other, |a, b| a.add(b) ) }
#[inline] fn sub_p(&self, other: &Self) -> V { self.bimap(other, |a, b| a.sub(b) ) }
#[inline] fn mul_self_s(&mut self, s: S) { for x in self.mut_iter() { *x = x.mul(&s) } }
#[inline] fn div_self_s(&mut self, s: S) { for x in self.mut_iter() { *x = x.div(&s) } }
#[inline] fn rem_self_s(&mut self, s: S) { for x in self.mut_iter() { *x = x.rem(&s) } }
#[inline] fn add_self_v(&mut self, other: &V) { for (a, b) in self.mut_iter().zip(other.iter()) { *a = a.add(b) } }
}
array!(impl<S> Point2<S> -> [S, ..2])
array!(impl<S> Point3<S> -> [S, ..3])
impl<S: Clone + Field> ClonableArray<S, [S, ..2]> for Point2<S>;
impl<S: Clone + Field> ClonableArray<S, [S, ..3]> for Point3<S>;
scalar_op!(impl Point2<S> * S -> Point2<S>)
scalar_op!(impl Point3<S> * S -> Point3<S>)
scalar_op!(impl Point2<S> / S -> Point2<S>)
scalar_op!(impl Point3<S> / S -> Point3<S>)
scalar_op!(impl Point2<S> % S -> Point2<S>)
scalar_op!(impl Point3<S> % S -> Point3<S>)
impl<S: Field> ScalarMul<S> for Point2<S>;
impl<S: Field> ScalarMul<S> for Point3<S>;
array_op!(impl<S> Point2<S> + Vec2<S> -> Point2<S>)
array_op!(impl<S> Point3<S> + Vec3<S> -> Point3<S>)
array_op!(impl<S> Point2<S> - Point2<S> -> Vec2<S>)
array_op!(impl<S> Point3<S> - Point3<S> -> Vec3<S>)
impl<S: Field> AffineSpace<S, Vec2<S>> for Point2<S>;
impl<S: Field> AffineSpace<S, Vec3<S>> for Point3<S>;
impl<S: Clone + Num> Point<S, Vec2<S>, [S, ..2]> for Point2<S>;
impl<S: Clone + Num> Point<S, Vec3<S>, [S, ..3]> for Point3<S>;

View file

@ -13,14 +13,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use traits::alg::*;
use types::vector::Vec3;
use vector::Vec3;
/// A quaternion in scalar/vector form
#[deriving(Clone, Eq)]
pub struct Quat<T> { s: T, v: Vec3<T> }
impl<T: Field> Quat<T> {
impl<T: Clone + Num> Quat<T> {
/// Construct a new quaternion from one scalar component and three
/// imaginary components
#[inline]

View file

@ -1,34 +0,0 @@
// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::num::Zero;
use traits::alg::Field;
use traits::alg::ScalarMul;
use traits::alg::VectorSpace;
/// An affine space is a set of points closed under affine combinations.
pub trait AffineSpace
<
S: Field,
V: VectorSpace<S>
>
: Eq
+ Zero
+ Add<V, Self>
+ Sub<Self, V>
+ ScalarMul<S>
{
}

View file

@ -1,69 +0,0 @@
// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::num;
use traits::alg::Field;
use traits::alg::InnerProductSpace;
/// The Euclidean space is a vector space over the Real numbers.
pub trait EuclideanSpace
<
S:Real + Field
>
: InnerProductSpace<S>
{
fn dot(&self, other: &Self) -> S {
self.inner(other)
}
/// Returns `true` if the vector is perpendicular (at right angles to)
/// the other vector.
fn is_perpendicular(&self, other: &Self) -> bool {
self.is_orthogonal(other)
}
/// Returns the squared length of the vector. This does not perform an
/// expensive square root operation like in the `length` method and can
/// therefore be more efficient for comparing the lengths of two vectors.
fn length2(&self) -> S {
self.dot(self)
}
/// The norm of the vector.
fn length(&self) -> S {
num::sqrt(self.dot(self))
}
/// The angle between the vector and `other`.
fn angle(&self, other: &Self) -> S;
/// Returns a vector with the same direction, but with a `length` (or
/// `norm`) of `1`.
fn normalize(&self) -> Self {
self.normalize_to(num::one::<S>())
}
/// Returns a vector with the same direction and a given `length`.
fn normalize_to(&self, length: S) -> Self {
*self * (length / self.length())
}
/// Returns the result of linarly interpolating the length of the vector
/// to the length of `other` by the specified amount.
fn lerp(&self, other: &Self, amount: S) -> Self {
*self + (*other - *self) * amount
}
}

View file

@ -1,40 +0,0 @@
// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use traits::alg::Ring;
/// A commutative ring that contains a multiplicative inverse.
pub trait Field
: Ring<Self>
+ Div<Self,Self>
+ Rem<Self,Self>
{
}
// impls for concrete types
impl Field for u8;
impl Field for u16;
impl Field for u32;
impl Field for u64;
impl Field for uint;
impl Field for i8;
impl Field for i16;
impl Field for i32;
impl Field for i64;
impl Field for int;
impl Field for f32;
impl Field for f64;
impl Field for float;

View file

@ -1,29 +0,0 @@
// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use traits::alg::Field;
use traits::alg::VectorSpace;
/// A vector space with the inner product operation.
pub trait InnerProductSpace
<
S: Field
>
: VectorSpace<S>
{
fn norm(&self) -> S;
fn inner(&self, other: &Self) -> S;
fn is_orthogonal(&self, other: &Self) -> bool;
}

View file

@ -1,76 +0,0 @@
// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use traits::alg::Array;
use traits::alg::ClonableArray;
use traits::alg::Field;
use traits::alg::Ring;
use traits::alg::VectorSpace;
pub trait Matrix
<
S: Field + Clone + ApproxEq<S>,
RV: Clone + VectorSpace<S> + ClonableArray<S, RVSlice>, RVSlice, RSlice,
CV: Clone + VectorSpace<S> + ClonableArray<S, CVSlice>, CVSlice, CSlice,
MT//: Matrix<S, CV, CSlice, RV, RSlice, Self>
>
: Ring<S>
+ ClonableArray<CV, RSlice>
{
#[inline]
fn c<'a>(&'a self, c: uint) -> &'a CV { self.i(c) }
#[inline]
fn mut_c<'a>(&'a mut self, c: uint) -> &'a mut CV { self.mut_i(c) }
#[inline]
fn swap_c(&mut self, a: uint, b: uint) {
let tmp = self.c(a).clone();
*self.mut_c(a) = self.c(b).clone();
*self.mut_c(b) = tmp;
}
fn r(&self, r: uint) -> RV;
#[inline]
fn swap_r(&mut self, a: uint, b: uint) {
for c in self.mut_iter() { c.swap(a, b) }
}
#[inline]
fn cr<'a>(&'a self, c: uint, r: uint) -> &'a S { self.i(c).i(r) }
#[inline]
fn mut_cr<'a>(&'a mut self, c: uint, r: uint) -> &'a mut S {
self.mut_i(c).mut_i(r)
}
#[inline]
fn swap_cr(&mut self, a: (uint, uint), b: (uint, uint)) {
let (ca, ra) = a;
let (cb, rb) = b;
let tmp = self.cr(ca, ra).clone();
*self.mut_cr(ca, ra) = self.cr(cb, rb).clone();
*self.mut_cr(cb, rb) = tmp;
}
// fn swap_cr(&mut self, (ca, ra): (uint, uint), (cb, rb): (uint, uint)) {
// let tmp = self.cr(ca, ra).clone();
// *self.mut_cr(ca, ra) = self.cr(cb, rb).clone();
// *self.mut_cr(cb, rb) = tmp;
// }
fn transpose(&self) -> MT;
}

View file

@ -1,42 +0,0 @@
// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#[macro_escape];
pub use self::affine_space::AffineSpace;
pub use self::array::{Array, ClonableArray};
pub use self::euclidean_space::EuclideanSpace;
pub use self::field::Field;
pub use self::inner_product_space::InnerProductSpace;
pub use self::matrix::Matrix;
pub use self::module::Module;
pub use self::ordered_ring::OrderedRing;
pub use self::ring::Ring;
pub use self::scalar_mul::ScalarMul;
pub use self::square_matrix::SquareMatrix;
pub use self::vector_space::VectorSpace;
pub mod affine_space;
pub mod array;
pub mod euclidean_space;
pub mod field;
pub mod inner_product_space;
pub mod matrix;
pub mod module;
pub mod ordered_ring;
pub mod ring;
pub mod scalar_mul;
pub mod square_matrix;
pub mod vector_space;

View file

@ -1,47 +0,0 @@
// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::num::Zero;
// use traits::alg::Field;
use traits::alg::ScalarMul;
/// An algebraic structure that generalizes the notion of a vector space.
pub trait Module
<
S/*: Field*/
>
: Eq
+ Add<Self,Self>
+ ScalarMul<S>
+ Zero
{
}
// impls for concrete types
impl Module<u8> for u8;
impl Module<u16> for u16;
impl Module<u32> for u32;
impl Module<u64> for u64;
impl Module<uint> for uint;
impl Module<i8> for i8;
impl Module<i16> for i16;
impl Module<i32> for i32;
impl Module<i64> for i64;
impl Module<int> for int;
impl Module<f32> for f32;
impl Module<f64> for f64;
impl Module<float> for float;

View file

@ -1,42 +0,0 @@
// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use traits::alg::Ring;
/// A ring that can also be ordered.
pub trait OrderedRing
<
S
>
: Ring<S>
+ Orderable
{
}
// impls for concrete types
impl OrderedRing<u8> for u8;
impl OrderedRing<u16> for u16;
impl OrderedRing<u32> for u32;
impl OrderedRing<u64> for u64;
impl OrderedRing<uint> for uint;
impl OrderedRing<i8> for i8;
impl OrderedRing<i16> for i16;
impl OrderedRing<i32> for i32;
impl OrderedRing<i64> for i64;
impl OrderedRing<int> for int;
impl OrderedRing<f32> for f32;
impl OrderedRing<f64> for f64;
impl OrderedRing<float> for float;

View file

@ -1,47 +0,0 @@
// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::num::One;
use traits::alg::Module;
/// A module that also requires the additive inverse operation (subtraction)
/// and the additive inverse.
pub trait Ring
<
S
>
: Module<S>
+ Neg<Self>
+ Sub<Self,Self>
+ One
{
}
// impls for concrete types
impl Ring<u8> for u8;
impl Ring<u16> for u16;
impl Ring<u32> for u32;
impl Ring<u64> for u64;
impl Ring<uint> for uint;
impl Ring<i8> for i8;
impl Ring<i16> for i16;
impl Ring<i32> for i32;
impl Ring<i64> for i64;
impl Ring<int> for int;
impl Ring<f32> for f32;
impl Ring<f64> for f64;
impl Ring<float> for float;

View file

@ -1,59 +0,0 @@
// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#[macro_escape];
// use traits::alg::Field;
/// Enforces the multiplication of an type by a scalar.
pub trait ScalarMul
<
S//: Field
>
: Mul<S, Self>
+ Div<S, Self>
+ Rem<S, Self>
{
}
// impls for concrete types
impl ScalarMul<u8> for u8;
impl ScalarMul<u16> for u16;
impl ScalarMul<u32> for u32;
impl ScalarMul<u64> for u64;
impl ScalarMul<uint> for uint;
impl ScalarMul<i8> for i8;
impl ScalarMul<i16> for i16;
impl ScalarMul<i32> for i32;
impl ScalarMul<i64> for i64;
impl ScalarMul<int> for int;
impl ScalarMul<f32> for f32;
impl ScalarMul<f64> for f64;
impl ScalarMul<float> for float;
macro_rules! scalar_op(
(impl<$S:ident> ($Op:ident, $op:ident) for $Self:ty -> $Result:ty) => (
impl<$S: Field> $Op<$S, $Self> for $Self {
#[inline(always)]
fn $op(&self, s: &$S) -> $Result { self.map(|x| x.$op(s)) }
}
);
(impl $Self:ty + $S:ident -> $Result:ty) => (scalar_op!(impl<$S> (Add, add) for $Self -> $Result));
(impl $Self:ty - $S:ident -> $Result:ty) => (scalar_op!(impl<$S> (Sub, sub) for $Self -> $Result));
(impl $Self:ty * $S:ident -> $Result:ty) => (scalar_op!(impl<$S> (Mul, mul) for $Self -> $Result));
(impl $Self:ty / $S:ident -> $Result:ty) => (scalar_op!(impl<$S> (Div, div) for $Self -> $Result));
(impl $Self:ty % $S:ident -> $Result:ty) => (scalar_op!(impl<$S> (Rem, rem) for $Self -> $Result));
)

View file

@ -1,44 +0,0 @@
// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::num;
use traits::alg::Field;
use traits::alg::Matrix;
use traits::alg::VectorSpace;
pub trait SquareMatrix
<
S: Field + ApproxEq<S>,
V: VectorSpace<S>,
VVSlice, VSlice
>
: Matrix<S, V, VVSlice, VSlice, V, VVSlice, VSlice, Self>
{
fn transpose_self(&mut self);
fn trace(&self) -> S;
fn determinant(&self) -> S;
fn invert(&self) -> Option<Self>;
#[inline]
fn invert_self(&mut self) {
*self = self.invert().expect("Attempted to invert a matrix with zero determinant.");
}
#[inline]
fn is_invertible(&self) -> bool {
!self.determinant().approx_eq(&num::zero::<S>())
}
}

View file

@ -1,29 +0,0 @@
// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use traits::alg::Field;
use traits::alg::Module;
/// A vector space is a set that is closed under vector addition and
/// scalar multiplication.
pub trait VectorSpace
<
S: Field
>
: Module<S>
+ Neg<Self>
+ Sub<Self,Self>
{
}

View file

@ -1,18 +0,0 @@
// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
pub use self::vector_ext::VectorExt;
pub mod vector_ext;

View file

@ -1,57 +0,0 @@
// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::num::{zero, one};
use traits::alg::Field;
use traits::alg::VectorSpace;
use traits::alg::Array;
pub trait VectorExt
<
S: Field,
Slice
>
: VectorSpace<S>
+ Array<S, Slice>
{
#[inline] fn add_s(&self, s: S) -> Self { self.map(|x| x.add(&s)) }
#[inline] fn sub_s(&self, s: S) -> Self { self.map(|x| x.sub(&s)) }
#[inline] fn mul_s(&self, s: S) -> Self { self.map(|x| x.mul(&s)) }
#[inline] fn div_s(&self, s: S) -> Self { self.map(|x| x.div(&s)) }
#[inline] fn rem_s(&self, s: S) -> Self { self.map(|x| x.rem(&s)) }
#[inline] fn add_v(&self, other: &Self) -> Self { self.bimap(other, |a, b| a.add(b) ) }
#[inline] fn sub_v(&self, other: &Self) -> Self { self.bimap(other, |a, b| a.sub(b) ) }
#[inline] fn mul_v(&self, other: &Self) -> Self { self.bimap(other, |a, b| a.mul(b) ) }
#[inline] fn div_v(&self, other: &Self) -> Self { self.bimap(other, |a, b| a.div(b) ) }
#[inline] fn rem_v(&self, other: &Self) -> Self { self.bimap(other, |a, b| a.rem(b) ) }
#[inline] fn neg_self(&mut self) { for x in self.mut_iter() { *x = x.neg() } }
#[inline] fn add_self_s(&mut self, s: S) { for x in self.mut_iter() { *x = x.add(&s) } }
#[inline] fn sub_self_s(&mut self, s: S) { for x in self.mut_iter() { *x = x.sub(&s) } }
#[inline] fn mul_self_s(&mut self, s: S) { for x in self.mut_iter() { *x = x.mul(&s) } }
#[inline] fn div_self_s(&mut self, s: S) { for x in self.mut_iter() { *x = x.div(&s) } }
#[inline] fn rem_self_s(&mut self, s: S) { for x in self.mut_iter() { *x = x.rem(&s) } }
#[inline] fn add_self_v(&mut self, other: &Self) { for (a, b) in self.mut_iter().zip(other.iter()) { *a = a.add(b) } }
#[inline] fn sub_self_v(&mut self, other: &Self) { for (a, b) in self.mut_iter().zip(other.iter()) { *a = a.sub(b) } }
#[inline] fn mul_self_v(&mut self, other: &Self) { for (a, b) in self.mut_iter().zip(other.iter()) { *a = a.mul(b) } }
#[inline] fn div_self_v(&mut self, other: &Self) { for (a, b) in self.mut_iter().zip(other.iter()) { *a = a.div(b) } }
#[inline] fn rem_self_v(&mut self, other: &Self) { for (a, b) in self.mut_iter().zip(other.iter()) { *a = a.rem(b) } }
#[inline] fn comp_add(&self) -> S { self.iter().fold(zero::<S>(), |a, b| a.add(b)) }
#[inline] fn comp_mul(&self) -> S { self.iter().fold(one::<S>(), |a, b| a.mul(b)) }
}

View file

@ -1,36 +0,0 @@
// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#[macro_escape];
/// Import this module for the strict, algebraic trait heirachy.
///
/// # Example
///
/// ~~~rust
/// use lmath::traits::alg::*;
/// ~~~
pub mod alg;
/// Import this module to access utility traits that do not neccsarily match
/// up with the strict algebraic properties of the respective types, and yet
/// still may be useful for computer graphics work.
///
/// # Example
///
/// ~~~rust
/// use lmath::traits::ext::*;
/// ~~~
pub mod ext;

View file

@ -1,19 +0,0 @@
// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
pub mod matrix;
pub mod point;
pub mod quaternion;
pub mod vector;

View file

@ -1,162 +0,0 @@
// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::num::{Zero, zero};
use std::num::{sqrt, atan2};
use traits::alg::*;
#[deriving(Eq, Zero, Clone)] pub struct Vec1<S> { x: S }
#[deriving(Eq, Zero, Clone)] pub struct Vec2<S> { x: S, y: S }
#[deriving(Eq, Zero, Clone)] pub struct Vec3<S> { x: S, y: S, z: S }
#[deriving(Eq, Zero, Clone)] pub struct Vec4<S> { x: S, y: S, z: S, w: S }
#[deriving(Eq, Zero, Clone)] pub struct Vec5<S> { x: S, y: S, z: S, w: S, a: S }
#[deriving(Eq, Zero, Clone)] pub struct Vec6<S> { x: S, y: S, z: S, w: S, a: S, b: S }
macro_rules! impl_vec(
($Self:ident <$S:ident> { $($field:ident),+ }) => (
impl<$S: Field> $Self<$S> {
#[inline]
pub fn new($($field: $S),+) -> $Self<$S> {
$Self { $($field: $field),+ }
}
/// The additive identity of the vector.
#[inline]
pub fn zero() -> $Self<$S> { zero() }
}
)
)
impl_vec!(Vec1<S> { x })
impl_vec!(Vec2<S> { x, y })
impl_vec!(Vec3<S> { x, y, z })
impl_vec!(Vec4<S> { x, y, z, w })
impl_vec!(Vec5<S> { x, y, z, w, a })
impl_vec!(Vec6<S> { x, y, z, w, a, b })
macro_rules! impl_vec_clonable(
($Self:ident <$S:ident>) => (
impl<$S:Clone + Field> $Self<$S> {
/// Construct a vector from a single value.
#[inline]
pub fn from_value(value: $S) -> $Self<$S> {
Array::build(|_| value.clone())
}
}
)
)
impl_vec_clonable!(Vec1<S>)
impl_vec_clonable!(Vec2<S>)
impl_vec_clonable!(Vec3<S>)
impl_vec_clonable!(Vec4<S>)
impl_vec_clonable!(Vec5<S>)
impl_vec_clonable!(Vec6<S>)
macro_rules! impl_vec_common(
($vec_ops_mod:ident, $Self:ty, [$S:ident, ..$n:expr]) => (
pub mod $vec_ops_mod {
use super::*;
use traits::alg::*;
use traits::ext::*;
array!(impl<$S> $Self -> [$S, ..$n])
impl<$S: Clone + Field> ClonableArray<$S, [$S, ..$n]> for $Self;
scalar_op!(impl $Self * $S -> $Self)
scalar_op!(impl $Self / $S -> $Self)
scalar_op!(impl $Self % $S -> $Self)
array_op!(impl<$S> $Self + $Self -> $Self)
array_op!(impl<$S> $Self - $Self -> $Self)
array_op!(impl<$S> -$Self -> $Self)
impl<$S: Field> ScalarMul<$S> for $Self;
impl<$S: Field> Module<$S> for $Self;
impl<$S: Field> VectorSpace<$S> for $Self;
impl<$S: Clone + Field> VectorExt<$S, [$S, ..$n]> for $Self;
}
)
)
impl_vec_common!(vec1_ops, Vec1<S>, [S, ..1])
impl_vec_common!(vec2_ops, Vec2<S>, [S, ..2])
impl_vec_common!(vec3_ops, Vec3<S>, [S, ..3])
impl_vec_common!(vec4_ops, Vec4<S>, [S, ..4])
impl_vec_common!(vec5_ops, Vec5<S>, [S, ..5])
impl_vec_common!(vec6_ops, Vec6<S>, [S, ..6])
/// Operations specific to two-dimensional vectors.
impl<S: Field> Vec2<S> {
/// The perpendicular dot product of the vector and `other`.
pub fn perp_dot(&self, other: &Vec2<S>) -> S {
(self.x * other.y) - (self.y * other.x)
}
}
/// Operations specific to three-dimensional vectors.
impl<S: Field> Vec3<S> {
/// Returns the cross product of the vector and `other`.
pub fn cross(&self, other: &Vec3<S>) -> Vec3<S> {
Vec3::new((self.y * other.z) - (self.z * other.y),
(self.z * other.x) - (self.x * other.z),
(self.x * other.y) - (self.y * other.x))
}
}
macro_rules! impl_vec_inner_product(
($Self:ident <$S:ident>) => (
impl<$S:Real + Field + ApproxEq<$S>> InnerProductSpace<$S> for $Self<$S> {
#[inline]
fn norm(&self) -> $S {
sqrt(self.inner(self))
}
#[inline]
fn inner(&self, other: &$Self<$S>) -> $S {
self.iter().zip(other.iter())
.map(|(a, b)| a.mul(b))
.fold(zero::<$S>(), |a, b| a.add(&b))
}
#[inline]
fn is_orthogonal(&self, other: &$Self<$S>) -> bool {
self.inner(other).approx_eq(&zero())
}
}
)
)
impl_vec_inner_product!(Vec1<S>)
impl_vec_inner_product!(Vec2<S>)
impl_vec_inner_product!(Vec3<S>)
impl_vec_inner_product!(Vec4<S>)
impl_vec_inner_product!(Vec5<S>)
impl_vec_inner_product!(Vec6<S>)
// Euclidean spaces only really make sense for 2D and 3D vector spaces
impl<S:Real + Field + ApproxEq<S>> EuclideanSpace<S> for Vec2<S> {
fn angle(&self, other: &Vec2<S>) -> S {
atan2(self.perp_dot(other), self.dot(other))
}
}
impl<S:Real + Field + ApproxEq<S>> EuclideanSpace<S> for Vec3<S> {
fn angle(&self, other: &Vec3<S>) -> S {
atan2(self.cross(other).length(), self.dot(other))
}
}

190
src/cgmath/vector.rs Normal file
View file

@ -0,0 +1,190 @@
// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::num::{zero, one};
use std::num::{sqrt, atan2};
use array::*;
#[deriving(Eq, Clone, Zero)] pub struct Vec2<S> { x: S, y: S }
#[deriving(Eq, Clone, Zero)] pub struct Vec3<S> { x: S, y: S, z: S }
#[deriving(Eq, Clone, Zero)] pub struct Vec4<S> { x: S, y: S, z: S, w: S }
macro_rules! vec(
(impl $Self:ident <$S:ident> { $($field:ident),+ }) => (
impl<$S: Clone + Num> $Self<$S> {
#[inline]
pub fn new($($field: $S),+) -> $Self<$S> {
$Self { $($field: $field),+ }
}
/// The additive identity of the vector.
#[inline]
pub fn zero() -> $Self<$S> { $Self::from_value(zero()) }
/// The additive identity of the vector.
#[inline]
pub fn ident() -> $Self<$S> { $Self::from_value(one()) }
/// Construct a vector from a single value.
#[inline]
pub fn from_value(value: $S) -> $Self<$S> {
Array::build(|_| value.clone())
}
}
)
)
vec!(impl Vec2<S> { x, y })
vec!(impl Vec3<S> { x, y, z })
vec!(impl Vec4<S> { x, y, z, w })
array!(impl<S> Vec2<S> -> [S, ..2])
array!(impl<S> Vec3<S> -> [S, ..3])
array!(impl<S> Vec4<S> -> [S, ..4])
pub trait Vector
<
S: Clone + Num,
Slice
>
: Array<S, Slice>
{
#[inline] fn neg(&self) -> Self { self.map(|x| x.neg()) }
#[inline] fn neg_self(&mut self) { for x in self.mut_iter() { *x = x.neg() } }
#[inline] fn add_s(&self, s: S) -> Self { self.map(|x| x.add(&s)) }
#[inline] fn sub_s(&self, s: S) -> Self { self.map(|x| x.sub(&s)) }
#[inline] fn mul_s(&self, s: S) -> Self { self.map(|x| x.mul(&s)) }
#[inline] fn div_s(&self, s: S) -> Self { self.map(|x| x.div(&s)) }
#[inline] fn rem_s(&self, s: S) -> Self { self.map(|x| x.rem(&s)) }
#[inline] fn add_v(&self, other: &Self) -> Self { self.bimap(other, |a, b| a.add(b) ) }
#[inline] fn sub_v(&self, other: &Self) -> Self { self.bimap(other, |a, b| a.sub(b) ) }
#[inline] fn mul_v(&self, other: &Self) -> Self { self.bimap(other, |a, b| a.mul(b) ) }
#[inline] fn div_v(&self, other: &Self) -> Self { self.bimap(other, |a, b| a.div(b) ) }
#[inline] fn rem_v(&self, other: &Self) -> Self { self.bimap(other, |a, b| a.rem(b) ) }
#[inline] fn add_self_s(&mut self, s: S) { for x in self.mut_iter() { *x = x.add(&s) } }
#[inline] fn sub_self_s(&mut self, s: S) { for x in self.mut_iter() { *x = x.sub(&s) } }
#[inline] fn mul_self_s(&mut self, s: S) { for x in self.mut_iter() { *x = x.mul(&s) } }
#[inline] fn div_self_s(&mut self, s: S) { for x in self.mut_iter() { *x = x.div(&s) } }
#[inline] fn rem_self_s(&mut self, s: S) { for x in self.mut_iter() { *x = x.rem(&s) } }
#[inline] fn add_self_v(&mut self, other: &Self) { for (a, b) in self.mut_iter().zip(other.iter()) { *a = a.add(b) } }
#[inline] fn sub_self_v(&mut self, other: &Self) { for (a, b) in self.mut_iter().zip(other.iter()) { *a = a.sub(b) } }
#[inline] fn mul_self_v(&mut self, other: &Self) { for (a, b) in self.mut_iter().zip(other.iter()) { *a = a.mul(b) } }
#[inline] fn div_self_v(&mut self, other: &Self) { for (a, b) in self.mut_iter().zip(other.iter()) { *a = a.div(b) } }
#[inline] fn rem_self_v(&mut self, other: &Self) { for (a, b) in self.mut_iter().zip(other.iter()) { *a = a.rem(b) } }
#[inline] fn comp_add(&self) -> S { self.iter().fold(zero::<S>(), |a, b| a.add(b)) }
#[inline] fn comp_mul(&self) -> S { self.iter().fold(one::<S>(), |a, b| a.mul(b)) }
#[inline]
fn dot(&self, other: &Self) -> S {
self.iter().zip(other.iter())
.map(|(a, b)| a.mul(b))
.fold(zero::<S>(), |a, b| a.add(&b))
}
}
impl<S: Clone + Num> Vector<S, [S, ..2]> for Vec2<S>;
impl<S: Clone + Num> Vector<S, [S, ..3]> for Vec3<S>;
impl<S: Clone + Num> Vector<S, [S, ..4]> for Vec4<S>;
/// Operations specific to numeric two-dimensional vectors.
impl<S: Clone + Num> Vec2<S> {
/// The perpendicular dot product of the vector and `other`.
#[inline]
pub fn perp_dot(&self, other: &Vec2<S>) -> S {
(self.x * other.y) - (self.y * other.x)
}
}
/// Operations specific to numeric three-dimensional vectors.
impl<S: Clone + Num> Vec3<S> {
/// Returns the cross product of the vector and `other`.
#[inline]
pub fn cross(&self, other: &Vec3<S>) -> Vec3<S> {
Vec3::new((self.y * other.z) - (self.z * other.y),
(self.z * other.x) - (self.x * other.z),
(self.x * other.y) - (self.y * other.x))
}
}
pub trait EuclideanVector
<
S: Clone + Real + ApproxEq<S>,
Slice
>
: Vector<S, Slice>
{
/// Returns `true` if the vector is perpendicular (at right angles to)
/// the other vector.
fn is_perpendicular(&self, other: &Self) -> bool {
self.dot(other).approx_eq(&zero())
}
/// Returns the squared length of the vector. This does not perform an
/// expensive square root operation like in the `length` method and can
/// therefore be more efficient for comparing the lengths of two vectors.
#[inline]
fn length2(&self) -> S {
self.dot(self)
}
/// The norm of the vector.
#[inline]
fn length(&self) -> S {
sqrt(self.dot(self))
}
/// The angle between the vector and `other`.
fn angle(&self, other: &Self) -> S;
/// Returns a vector with the same direction, but with a `length` (or
/// `norm`) of `1`.
#[inline]
fn normalize(&self) -> Self {
self.normalize_to(one::<S>())
}
/// Returns a vector with the same direction and a given `length`.
#[inline]
fn normalize_to(&self, length: S) -> Self {
self.mul_s(length / self.length())
}
/// Returns the result of linarly interpolating the length of the vector
/// to the length of `other` by the specified amount.
#[inline]
fn lerp(&self, other: &Self, amount: S) -> Self {
self.add_v(&other.sub_v(self).mul_s(amount))
}
}
impl<S: Clone + Real + ApproxEq<S>> EuclideanVector<S, [S, ..2]> for Vec2<S> {
#[inline]
fn angle(&self, other: &Vec2<S>) -> S {
atan2(self.perp_dot(other), self.dot(other))
}
}
impl<S: Clone + Real + ApproxEq<S>> EuclideanVector<S, [S, ..3]> for Vec3<S> {
#[inline]
fn angle(&self, other: &Vec3<S>) -> S {
atan2(self.cross(other).length(), self.dot(other))
}
}