From b67b31b633b696f59044772368102951716c02b4 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Tue, 27 Aug 2013 08:59:18 +1000 Subject: [PATCH] Add matrix traits, do lots of reorganisation/re-formatting --- src/traits/alg/affine_space.rs | 19 +++- src/traits/alg/coordinate.rs | 16 ++- src/traits/alg/euclidean_space.rs | 9 +- src/traits/alg/{division_ring.rs => field.rs} | 37 ++++--- src/traits/alg/inner_product_space.rs | 9 +- src/traits/alg/matrix.rs | 30 ++++++ src/traits/alg/mod.rs | 8 +- src/traits/alg/module.rs | 15 ++- src/traits/alg/ordered_ring.rs | 7 +- src/traits/alg/ring.rs | 11 +- src/traits/alg/scalar_mul.rs | 14 ++- src/traits/alg/square_matrix.rs | 33 ++++++ src/traits/alg/vector_space.rs | 13 ++- src/traits/ext/vector_ext.rs | 12 ++- src/types/matrix.rs | 6 ++ src/types/point.rs | 40 +++---- src/types/quaternion.rs | 2 +- src/types/vector.rs | 100 +++++++++--------- 18 files changed, 259 insertions(+), 122 deletions(-) rename src/traits/alg/{division_ring.rs => field.rs} (58%) create mode 100644 src/traits/alg/matrix.rs create mode 100644 src/traits/alg/square_matrix.rs diff --git a/src/traits/alg/affine_space.rs b/src/traits/alg/affine_space.rs index d79fc31..f0ce511 100644 --- a/src/traits/alg/affine_space.rs +++ b/src/traits/alg/affine_space.rs @@ -15,11 +15,20 @@ 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: Eq - + Zero - + ScalarMul - + Add - + Sub {} +pub trait AffineSpace +< + S: Field, + V: VectorSpace +> +: Eq ++ Zero ++ Add ++ Sub ++ ScalarMul +{ +} diff --git a/src/traits/alg/coordinate.rs b/src/traits/alg/coordinate.rs index f783555..f813bbb 100644 --- a/src/traits/alg/coordinate.rs +++ b/src/traits/alg/coordinate.rs @@ -13,8 +13,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub use traits::util::Indexable; -pub use traits::util::Swappable; +use traits::alg::Field; +use traits::util::Indexable; +use traits::util::Swappable; -pub trait Coordinate: Indexable - + Swappable {} +pub trait Coordinate +< + S: Field, + Slice +> +: Indexable ++ Swappable +{ +} diff --git a/src/traits/alg/euclidean_space.rs b/src/traits/alg/euclidean_space.rs index e24d69b..f123a7b 100644 --- a/src/traits/alg/euclidean_space.rs +++ b/src/traits/alg/euclidean_space.rs @@ -15,11 +15,16 @@ use std::num; -use traits::alg::Ring; +use traits::alg::Field; use traits::alg::InnerProductSpace; /// The Euclidean space is a vector space over the Real numbers. -pub trait EuclideanSpace: InnerProductSpace { +pub trait EuclideanSpace +< + S:Real + Field +> +: InnerProductSpace +{ fn dot(&self, other: &Self) -> S { self.inner(other) } diff --git a/src/traits/alg/division_ring.rs b/src/traits/alg/field.rs similarity index 58% rename from src/traits/alg/division_ring.rs rename to src/traits/alg/field.rs index 94396ce..a1fcaa7 100644 --- a/src/traits/alg/division_ring.rs +++ b/src/traits/alg/field.rs @@ -15,23 +15,26 @@ use traits::alg::Ring; -/// A ring that also requires the multiplicative inverse operation (division). -pub trait DivisionRing: Ring - + Div - + Rem {} +/// A commutative ring that contains a multiplicative inverse. +pub trait Field +: Ring ++ Div ++ Rem +{ +} // impls for concrete types -impl DivisionRing for u8; -impl DivisionRing for u16; -impl DivisionRing for u32; -impl DivisionRing for u64; -impl DivisionRing for uint; -impl DivisionRing for i8; -impl DivisionRing for i16; -impl DivisionRing for i32; -impl DivisionRing for i64; -impl DivisionRing for int; -impl DivisionRing for f32; -impl DivisionRing for f64; -impl DivisionRing for float; +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; diff --git a/src/traits/alg/inner_product_space.rs b/src/traits/alg/inner_product_space.rs index c20b835..9d3ed8a 100644 --- a/src/traits/alg/inner_product_space.rs +++ b/src/traits/alg/inner_product_space.rs @@ -13,11 +13,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -use traits::alg::Ring; +use traits::alg::Field; use traits::alg::VectorSpace; /// A vector space with the inner product operation. -pub trait InnerProductSpace: VectorSpace { +pub trait InnerProductSpace +< + S: Field +> +: VectorSpace +{ fn norm(&self) -> S; fn inner(&self, other: &Self) -> S; fn is_orthogonal(&self, other: &Self) -> bool; diff --git a/src/traits/alg/matrix.rs b/src/traits/alg/matrix.rs new file mode 100644 index 0000000..3865536 --- /dev/null +++ b/src/traits/alg/matrix.rs @@ -0,0 +1,30 @@ +// 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::Ring; +use traits::alg::VectorSpace; + +pub trait Matrix +< + S: Field, + RV: VectorSpace, + CV: VectorSpace, + MT//: Matrix +> +: Ring +{ + fn transpose(&self) -> MT; +} \ No newline at end of file diff --git a/src/traits/alg/mod.rs b/src/traits/alg/mod.rs index 33444be..c6d891b 100644 --- a/src/traits/alg/mod.rs +++ b/src/traits/alg/mod.rs @@ -15,22 +15,26 @@ pub use self::affine_space::AffineSpace; pub use self::coordinate::Coordinate; -pub use self::division_ring::DivisionRing; 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 coordinate; -pub mod division_ring; 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; diff --git a/src/traits/alg/module.rs b/src/traits/alg/module.rs index c0df90a..5534d40 100644 --- a/src/traits/alg/module.rs +++ b/src/traits/alg/module.rs @@ -15,13 +15,20 @@ 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: Eq - + Add - + ScalarMul - + Zero {} +pub trait Module +< + S/*: Field*/ +> +: Eq ++ Add ++ ScalarMul ++ Zero +{ +} // impls for concrete types diff --git a/src/traits/alg/ordered_ring.rs b/src/traits/alg/ordered_ring.rs index ddee8e3..4507d5a 100644 --- a/src/traits/alg/ordered_ring.rs +++ b/src/traits/alg/ordered_ring.rs @@ -16,8 +16,11 @@ use traits::alg::Ring; /// A ring that can also be ordered. -pub trait OrderedRing: Ring - + Orderable {} +pub trait OrderedRing +: Ring ++ Orderable +{ +} // impls for concrete types diff --git a/src/traits/alg/ring.rs b/src/traits/alg/ring.rs index f1cedda..ba1de55 100644 --- a/src/traits/alg/ring.rs +++ b/src/traits/alg/ring.rs @@ -19,10 +19,13 @@ use traits::alg::Module; /// A module that also requires the additive inverse operation (subtraction) /// and the additive inverse. -pub trait Ring: Module - + Neg - + Sub - + One {} +pub trait Ring +: Module ++ Neg ++ Sub ++ One +{ +} // impls for concrete types diff --git a/src/traits/alg/scalar_mul.rs b/src/traits/alg/scalar_mul.rs index 55178f0..8dd3c08 100644 --- a/src/traits/alg/scalar_mul.rs +++ b/src/traits/alg/scalar_mul.rs @@ -13,10 +13,18 @@ // See the License for the specific language governing permissions and // limitations under the License. +// use traits::alg::Field; + /// Enforces the multiplication of an type by a scalar. -pub trait ScalarMul: Mul - + Div - + Rem {} +pub trait ScalarMul +< + S/*: Field*/ +> +: Mul ++ Div ++ Rem +{ +} // impls for concrete types diff --git a/src/traits/alg/square_matrix.rs b/src/traits/alg/square_matrix.rs new file mode 100644 index 0000000..263059c --- /dev/null +++ b/src/traits/alg/square_matrix.rs @@ -0,0 +1,33 @@ +// 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::Matrix; +use traits::alg::VectorSpace; + +pub trait SquareMatrix +< + S: Field, + V: VectorSpace +> +: Matrix +{ + fn transpose_self(&mut self); + fn trace(&self) -> S; + fn det(&self) -> S; + fn invert(&self) -> Option; + fn invert_self(&mut self) -> Self; + fn eigenvalue(&self, v: V) -> Option; +} \ No newline at end of file diff --git a/src/traits/alg/vector_space.rs b/src/traits/alg/vector_space.rs index 20a8044..dd92228 100644 --- a/src/traits/alg/vector_space.rs +++ b/src/traits/alg/vector_space.rs @@ -13,10 +13,17 @@ // 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: Module - + Neg - + Sub {} +pub trait VectorSpace +< + S: Field +> +: Module ++ Neg ++ Sub +{ +} diff --git a/src/traits/ext/vector_ext.rs b/src/traits/ext/vector_ext.rs index 9da2bc0..cee534e 100644 --- a/src/traits/ext/vector_ext.rs +++ b/src/traits/ext/vector_ext.rs @@ -13,12 +13,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -use traits::alg::Ring; +use traits::alg::Field; use traits::alg::VectorSpace; use traits::util::Indexable; -pub trait VectorExt: VectorSpace - + Indexable { +pub trait VectorExt +< + S: Field, + Slice +> +: VectorSpace ++ Indexable +{ #[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)) } diff --git a/src/types/matrix.rs b/src/types/matrix.rs index 0a0d38c..e815306 100644 --- a/src/types/matrix.rs +++ b/src/types/matrix.rs @@ -12,3 +12,9 @@ // 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 types::vector::{Vec2, Vec3, Vec4}; + +#[deriving(Clone, Eq)] pub struct Mat2 { x: Vec2, y: Vec2 } +#[deriving(Clone, Eq)] pub struct Mat3 { x: Vec3, y: Vec3, z: Vec3 } +#[deriving(Clone, Eq)] pub struct Mat4 { x: Vec4, y: Vec4, z: Vec4, w: Vec4 } diff --git a/src/types/point.rs b/src/types/point.rs index f4fb37e..1c879b4 100644 --- a/src/types/point.rs +++ b/src/types/point.rs @@ -27,14 +27,14 @@ struct Point2 { x: S, y: S } #[deriving(Eq, Zero, Clone)] struct Point3 { x: S, y: S, z: S } -impl Point2 { +impl Point2 { #[inline] pub fn new(x: S, y: S) -> Point2 { Point2 { x: x, y: y } } } -impl Point3 { +impl Point3 { #[inline] pub fn new(x: S, y: S, z: S) -> Point3 { Point3 { x: x, y: y, z: z } @@ -43,34 +43,34 @@ impl Point3 { // Operator impls -impl Mul> for Point2 { #[inline(always)] fn mul(&self, s: &S) -> Point2 { self.map(|x| x.mul(s)) } } -impl Mul> for Point3 { #[inline(always)] fn mul(&self, s: &S) -> Point3 { self.map(|x| x.mul(s)) } } +impl Mul> for Point2 { #[inline(always)] fn mul(&self, s: &S) -> Point2 { self.map(|x| x.mul(s)) } } +impl Mul> for Point3 { #[inline(always)] fn mul(&self, s: &S) -> Point3 { self.map(|x| x.mul(s)) } } -impl Div> for Point2 { #[inline(always)] fn div(&self, s: &S) -> Point2 { self.map(|x| x.div(s)) } } -impl Div> for Point3 { #[inline(always)] fn div(&self, s: &S) -> Point3 { self.map(|x| x.div(s)) } } +impl Div> for Point2 { #[inline(always)] fn div(&self, s: &S) -> Point2 { self.map(|x| x.div(s)) } } +impl Div> for Point3 { #[inline(always)] fn div(&self, s: &S) -> Point3 { self.map(|x| x.div(s)) } } -impl Rem> for Point2 { #[inline(always)] fn rem(&self, s: &S) -> Point2 { self.map(|x| x.rem(s)) } } -impl Rem> for Point3 { #[inline(always)] fn rem(&self, s: &S) -> Point3 { self.map(|x| x.rem(s)) } } +impl Rem> for Point2 { #[inline(always)] fn rem(&self, s: &S) -> Point2 { self.map(|x| x.rem(s)) } } +impl Rem> for Point3 { #[inline(always)] fn rem(&self, s: &S) -> Point3 { self.map(|x| x.rem(s)) } } -impl Add, Point2> for Point2 { #[inline(always)] fn add(&self, other: &Vec2) -> Point2 { self.bimap(other, |a, b| a.add(b)) } } -impl Add, Point3> for Point3 { #[inline(always)] fn add(&self, other: &Vec3) -> Point3 { self.bimap(other, |a, b| a.add(b)) } } +impl Add, Point2> for Point2 { #[inline(always)] fn add(&self, other: &Vec2) -> Point2 { self.bimap(other, |a, b| a.add(b)) } } +impl Add, Point3> for Point3 { #[inline(always)] fn add(&self, other: &Vec3) -> Point3 { self.bimap(other, |a, b| a.add(b)) } } -impl Sub, Vec2> for Point2 { #[inline(always)] fn sub(&self, other: &Point2) -> Vec2 { self.bimap(other, |a, b| a.sub(b)) } } -impl Sub, Vec3> for Point3 { #[inline(always)] fn sub(&self, other: &Point3) -> Vec3 { self.bimap(other, |a, b| a.sub(b)) } } +impl Sub, Vec2> for Point2 { #[inline(always)] fn sub(&self, other: &Point2) -> Vec2 { self.bimap(other, |a, b| a.sub(b)) } } +impl Sub, Vec3> for Point3 { #[inline(always)] fn sub(&self, other: &Point3) -> Vec3 { self.bimap(other, |a, b| a.sub(b)) } } // Trait impls impl_indexable!(Point2, [T, ..2]) impl_indexable!(Point3, [T, ..3]) -impl Swappable for Point2; -impl Swappable for Point3; +impl Swappable for Point2; +impl Swappable for Point3; -impl Coordinate for Point2; -impl Coordinate for Point3; +impl Coordinate for Point2; +impl Coordinate for Point3; -impl ScalarMul for Point2; -impl ScalarMul for Point3; +impl ScalarMul for Point2; +impl ScalarMul for Point3; -impl AffineSpace> for Point2; -impl AffineSpace> for Point3; +impl AffineSpace> for Point2; +impl AffineSpace> for Point3; diff --git a/src/types/quaternion.rs b/src/types/quaternion.rs index c52e98e..8b1c044 100644 --- a/src/types/quaternion.rs +++ b/src/types/quaternion.rs @@ -20,7 +20,7 @@ use types::vector::Vec3; #[deriving(Clone, Eq)] pub struct Quat { s: T, v: Vec3 } -impl Quat { +impl Quat { /// Construct a new quaternion from one scalar component and three /// imaginary components #[inline] diff --git a/src/types/vector.rs b/src/types/vector.rs index 070d4db..6ff925d 100644 --- a/src/types/vector.rs +++ b/src/types/vector.rs @@ -30,7 +30,7 @@ use traits::util::*; macro_rules! impl_vec( ($Self:ident <$S:ident> { $($field:ident),+ }) => ( - impl<$S> $Self<$S> { + impl<$S: Field> $Self<$S> { #[inline] pub fn new($($field: $S),+) -> $Self<$S> { $Self { $($field: $field),+ } @@ -48,7 +48,7 @@ impl_vec!(Vec6 { x, y, z, w, a, b }) macro_rules! impl_vec_clonable( ($Self:ident <$S:ident>) => ( - impl<$S:Clone> $Self<$S> { + impl<$S:Clone + Field> $Self<$S> { /// Construct a vector from a single value. #[inline] pub fn from_value(value: $S) -> $Self<$S> { @@ -67,7 +67,7 @@ impl_vec_clonable!(Vec6) macro_rules! impl_vec_ring( ($Self:ident <$S:ident>) => ( - impl<$S:Ring> $Self<$S> { + impl<$S:Field> $Self<$S> { /// The additive identity of the vector. #[inline] pub fn zero() -> $Self<$S> { zero() } @@ -90,32 +90,32 @@ macro_rules! impl_vec_ops( use super::*; use super::super::super::traits::alg::*; - impl<$S:Ring> Mul<$S, $Self<$S>> for $Self<$S> { + impl<$S:Field> Mul<$S, $Self<$S>> for $Self<$S> { #[inline(always)] fn mul(&self, s: &$S) -> $Self<$S> { self.map(|x| x.mul(s)) } } - impl<$S:Ring> Div<$S, $Self<$S>> for $Self<$S> { + impl<$S:Field> Div<$S, $Self<$S>> for $Self<$S> { #[inline(always)] fn div(&self, s: &$S) -> $Self<$S> { self.map(|x| x.div(s)) } } - impl<$S:Ring> Rem<$S, $Self<$S>> for $Self<$S> { + impl<$S:Field> Rem<$S, $Self<$S>> for $Self<$S> { #[inline(always)] fn rem(&self, s: &$S) -> $Self<$S> { self.map(|x| x.rem(s)) } } - impl<$S:Ring> Add<$Self<$S>, $Self<$S>> for $Self<$S> { + impl<$S:Field> Add<$Self<$S>, $Self<$S>> for $Self<$S> { #[inline(always)] fn add(&self, other: &$Self<$S>) -> $Self<$S> { self.bimap(other, |a, b| a.add(b)) } } - impl<$S:Ring> Sub<$Self<$S>, $Self<$S>> for $Self<$S> { + impl<$S:Field> Sub<$Self<$S>, $Self<$S>> for $Self<$S> { #[inline(always)] fn sub(&self, other: &$Self<$S>) -> $Self<$S> { self.bimap(other, |a, b| a.sub(b)) } } - impl<$S:Ring> Neg<$Self<$S>> for $Self<$S> { + impl<$S:Field> Neg<$Self<$S>> for $Self<$S> { #[inline(always)] fn neg(&self) -> $Self<$S> { self.map(|x| x.neg()) } } @@ -131,7 +131,7 @@ impl_vec_ops!(vec5_ops, Vec5) impl_vec_ops!(vec6_ops, Vec6) /// Operations specific to two-dimensional vectors. -impl Vec2 { +impl Vec2 { /// The perpendicular dot product of the vector and `other`. pub fn perp_dot(&self, other: &Vec2) -> S { (self.x * other.y) - (self.y * other.x) @@ -139,7 +139,7 @@ impl Vec2 { } /// Operations specific to three-dimensional vectors. -impl Vec3 { +impl Vec3 { /// Returns the cross product of the vector and `other`. pub fn cross(&self, other: &Vec3) -> Vec3 { Vec3::new((self.y * other.z) - (self.z * other.y), @@ -157,44 +157,44 @@ impl_indexable!(Vec4, [S, ..4]) impl_indexable!(Vec5, [S, ..5]) impl_indexable!(Vec6, [S, ..6]) -impl Swappable for Vec1; -impl Swappable for Vec2; -impl Swappable for Vec3; -impl Swappable for Vec4; -impl Swappable for Vec5; -impl Swappable for Vec6; +impl Swappable for Vec1; +impl Swappable for Vec2; +impl Swappable for Vec3; +impl Swappable for Vec4; +impl Swappable for Vec5; +impl Swappable for Vec6; -impl Coordinate for Vec1; -impl Coordinate for Vec2; -impl Coordinate for Vec3; -impl Coordinate for Vec4; -impl Coordinate for Vec5; -impl Coordinate for Vec6; +impl Coordinate for Vec1; +impl Coordinate for Vec2; +impl Coordinate for Vec3; +impl Coordinate for Vec4; +impl Coordinate for Vec5; +impl Coordinate for Vec6; -impl ScalarMul for Vec1; -impl ScalarMul for Vec2; -impl ScalarMul for Vec3; -impl ScalarMul for Vec4; -impl ScalarMul for Vec5; -impl ScalarMul for Vec6; +impl ScalarMul for Vec1; +impl ScalarMul for Vec2; +impl ScalarMul for Vec3; +impl ScalarMul for Vec4; +impl ScalarMul for Vec5; +impl ScalarMul for Vec6; -impl Module for Vec1; -impl Module for Vec2; -impl Module for Vec3; -impl Module for Vec4; -impl Module for Vec5; -impl Module for Vec6; +impl Module for Vec1; +impl Module for Vec2; +impl Module for Vec3; +impl Module for Vec4; +impl Module for Vec5; +impl Module for Vec6; -impl VectorSpace for Vec1; -impl VectorSpace for Vec2; -impl VectorSpace for Vec3; -impl VectorSpace for Vec4; -impl VectorSpace for Vec5; -impl VectorSpace for Vec6; +impl VectorSpace for Vec1; +impl VectorSpace for Vec2; +impl VectorSpace for Vec3; +impl VectorSpace for Vec4; +impl VectorSpace for Vec5; +impl VectorSpace for Vec6; macro_rules! impl_vec_inner_product( ($Self:ident <$S:ident>) => ( - impl<$S:Real + Ring + ApproxEq<$S>> InnerProductSpace<$S> for $Self<$S> { + impl<$S:Real + Field + ApproxEq<$S>> InnerProductSpace<$S> for $Self<$S> { fn norm(&self) -> $S { num::sqrt(self.inner(self)) } @@ -220,21 +220,21 @@ impl_vec_inner_product!(Vec6) // Euclidean spaces only really make sense for 2D and 3D vector spaces -impl> EuclideanSpace for Vec2 { +impl> EuclideanSpace for Vec2 { fn angle(&self, other: &Vec2) -> S { atan2(self.perp_dot(other), self.dot(other)) } } -impl> EuclideanSpace for Vec3 { +impl> EuclideanSpace for Vec3 { fn angle(&self, other: &Vec3) -> S { atan2(self.cross(other).length(), self.dot(other)) } } -impl VectorExt for Vec1; -impl VectorExt for Vec2; -impl VectorExt for Vec3; -impl VectorExt for Vec4; -impl VectorExt for Vec5; -impl VectorExt for Vec6; +impl VectorExt for Vec1; +impl VectorExt for Vec2; +impl VectorExt for Vec3; +impl VectorExt for Vec4; +impl VectorExt for Vec5; +impl VectorExt for Vec6;