diff --git a/AUTHORS b/AUTHORS index cfeaae2..e834dec 100644 --- a/AUTHORS +++ b/AUTHORS @@ -11,3 +11,8 @@ Erick Tryzelaar Luqman Aden Maik Klein Mikko Perttunen + +With thanks to: + +sebcrozet and his nalgebra library for providing the inspiration for the +algebraic traits: https://github.com/sebcrozet/nalgebra diff --git a/Makefile b/Makefile deleted file mode 100644 index 87cf752..0000000 --- a/Makefile +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2013 The Lmath 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. - -TARGET = lmath - -ROOT_DIR = . - -SRC_DIR = $(ROOT_DIR)/src -SRC_CRATE = $(TARGET).rs -EXTERN_DIR = $(ROOT_DIR)/extern -BUILD_DIR = $(ROOT_DIR)/lib - -CFG = --cfg=bounds --cfg=transform --cfg=space - -TEST = $(TARGET) -TEST_BUILD_DIR = $(ROOT_DIR)/test - -.PHONY: test - -$(TARGET): - @echo "Building $(TARGET)..." - @mkdir -p $(BUILD_DIR) - @rustc $(CFG) $(SRC_DIR)/$(SRC_CRATE) --out-dir=$(BUILD_DIR) - @echo "Success" - -all: $(TARGET) - -test: - @echo "Building unit tests for $(TARGET)..." - @mkdir -p $(TEST_BUILD_DIR) - @rustc $(CFG) $(SRC_DIR)/$(SRC_CRATE) --test --out-dir=$(TEST_BUILD_DIR) - @echo "Success" - @$(TEST_BUILD_DIR)/$(TARGET) - -clean: - rm -R -f $(BUILD_DIR) - rm -R -f $(TEST_BUILD_DIR) \ No newline at end of file diff --git a/README.md b/README.md index 8cde705..de9a331 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,3 @@ -# Lmath-rs +# cgmath-rs -A mathematics library for computer graphics. - - -## Examples - -- [luqmana/rray](https://github.com/luqmana/rray) - Raytracer written in rust. - - -~B☼ \ No newline at end of file +A linear algebra and mathematics library for computer graphics. diff --git a/src/bounds/aabb.rs b/src-old/bounds/aabb.rs similarity index 96% rename from src/bounds/aabb.rs rename to src-old/bounds/aabb.rs index ac1a5fa..5dec48d 100644 --- a/src/bounds/aabb.rs +++ b/src-old/bounds/aabb.rs @@ -67,4 +67,6 @@ impl AABB3 { size: mx - mn, } } + + // pub fn intersects_aabb3(&self, other: &AABB3) -> bool {} } diff --git a/src/bounds/bounds.rs b/src-old/bounds/bounds.rs similarity index 95% rename from src/bounds/bounds.rs rename to src-old/bounds/bounds.rs index 884e4f2..ad44fd1 100644 --- a/src/bounds/bounds.rs +++ b/src-old/bounds/bounds.rs @@ -17,10 +17,11 @@ pub use self::aabb::{AABB2, AABB3}; pub use self::frustum::{Frustum, FrustumPoints}; +pub use self::obb::{OBB2, OBB3}; pub use self::sphere::Sphere; pub mod aabb; -pub mod box; pub mod cylinder; pub mod frustum; +pub mod obb; pub mod sphere; diff --git a/src/bounds/cylinder.rs b/src-old/bounds/cylinder.rs similarity index 100% rename from src/bounds/cylinder.rs rename to src-old/bounds/cylinder.rs diff --git a/src/bounds/frustum.rs b/src-old/bounds/frustum.rs similarity index 100% rename from src/bounds/frustum.rs rename to src-old/bounds/frustum.rs diff --git a/src/bounds/box.rs b/src-old/bounds/obb.rs similarity index 95% rename from src/bounds/box.rs rename to src-old/bounds/obb.rs index 842e335..fabbd7c 100644 --- a/src/bounds/box.rs +++ b/src-old/bounds/obb.rs @@ -18,14 +18,14 @@ use math::*; #[deriving(Clone, Eq)] -pub struct Box2 { +pub struct OBB2 { center: Point2, axis: Vec2, extents: Vec2, } #[deriving(Clone, Eq)] -pub struct Box3 { +pub struct OBB3 { center: Point3, axis: Vec3, extents: Vec3, diff --git a/src/bounds/sphere.rs b/src-old/bounds/sphere.rs similarity index 100% rename from src/bounds/sphere.rs rename to src-old/bounds/sphere.rs diff --git a/src/lmath.rs b/src-old/lmath.rs similarity index 100% rename from src/lmath.rs rename to src-old/lmath.rs diff --git a/src/macros.rs b/src-old/macros.rs similarity index 100% rename from src/macros.rs rename to src-old/macros.rs diff --git a/src/math/macros.rs b/src-old/math/macros.rs similarity index 100% rename from src/math/macros.rs rename to src-old/math/macros.rs diff --git a/src/math/mat.rs b/src-old/math/mat.rs similarity index 99% rename from src/math/mat.rs rename to src-old/math/mat.rs index 6dd8f78..c2e0f77 100644 --- a/src/math/mat.rs +++ b/src-old/math/mat.rs @@ -75,6 +75,7 @@ pub type Mat2f32 = Mat2; pub type Mat2f64 = Mat2; impl_dimensioned!(Mat2, Vec2, 2) +impl_swap_components!(Mat2) impl_approx!(Mat3 { x, y, z }) pub trait ToMat2 { @@ -288,7 +289,7 @@ impl Mat2 { } } -impl FloatMat,[Vec3,..3]> for Mat2 { +impl FloatMat,[Vec2,..2]> for Mat2 { #[inline] pub fn inverse(&self) -> Option> { let d = self.determinant(); @@ -539,6 +540,7 @@ pub type Mat3f32 = Mat3; pub type Mat3f64 = Mat3; impl_dimensioned!(Mat3, Vec3, 3) +impl_swap_components!(Mat3) impl_approx!(Mat2 { x, y }) pub trait ToMat3 { @@ -761,7 +763,7 @@ impl Neg> for Mat3 { } } -impl Mat3 { +impl Mat3 { pub fn look_at(dir: &Vec3, up: &Vec3) -> Mat3 { let dir_ = dir.normalize(); let side = dir_.cross(&up.normalize()); @@ -823,7 +825,7 @@ impl ToQuat for Mat3 { } } -impl FloatMat,[Vec4,..4]> for Mat3 { +impl FloatMat,[Vec3,..3]> for Mat3 { #[inline] pub fn inverse(&self) -> Option> { let d = self.determinant(); @@ -1111,6 +1113,7 @@ pub type Mat4f32 = Mat4; pub type Mat4f64 = Mat4; impl_dimensioned!(Mat4, Vec4, 4) +impl_swap_components!(Mat4) impl_approx!(Mat4 { x, y, z, w }) pub trait ToMat4 { diff --git a/src/math/math.rs b/src-old/math/math.rs similarity index 100% rename from src/math/math.rs rename to src-old/math/math.rs diff --git a/src/math/plane.rs b/src-old/math/plane.rs similarity index 100% rename from src/math/plane.rs rename to src-old/math/plane.rs diff --git a/src/math/point.rs b/src-old/math/point.rs similarity index 100% rename from src/math/point.rs rename to src-old/math/point.rs diff --git a/src/math/quat.rs b/src-old/math/quat.rs similarity index 100% rename from src/math/quat.rs rename to src-old/math/quat.rs diff --git a/src/math/ray.rs b/src-old/math/ray.rs similarity index 100% rename from src/math/ray.rs rename to src-old/math/ray.rs diff --git a/src/math/vec.rs b/src-old/math/vec.rs similarity index 98% rename from src/math/vec.rs rename to src-old/math/vec.rs index 7746cb5..c643bcf 100644 --- a/src/math/vec.rs +++ b/src-old/math/vec.rs @@ -22,7 +22,7 @@ pub trait Vec: Dimensioned + SwapComponents {} /// Vectors with numeric components -pub trait NumVec: Neg { +pub trait NumVec: Neg { pub fn add_s(&self, value: T) -> Self; pub fn sub_s(&self, value: T) -> Self; pub fn mul_s(&self, value: T) -> Self; @@ -209,9 +209,9 @@ impl Vec2 { } } -impl Vec for Vec2 {} +impl Vec for Vec2 {} -impl NumVec for Vec2 { +impl NumVec for Vec2 { /// Returns a new vector with `value` added to each component. #[inline] pub fn add_s(&self, value: T) -> Vec2 { @@ -371,7 +371,7 @@ impl NumVec for Vec2 { } } -impl Neg> for Vec2 { +impl Neg> for Vec2 { /// Returns the vector with each component negated. #[inline] pub fn neg(&self) -> Vec2 { @@ -380,7 +380,7 @@ impl Neg> for Vec2 { } } -impl FloatVec for Vec2 { +impl FloatVec for Vec2 { /// Returns the squared magnitude of the vector. This does not perform a /// square root operation like in the `magnitude` method and can therefore /// be more efficient for comparing the magnitudes of two vectors. @@ -442,7 +442,7 @@ impl FloatVec for Vec2 { } } -impl OrdVec> for Vec2 { +impl OrdVec> for Vec2 { #[inline] pub fn lt_s(&self, value: T) -> Vec2 { Vec2::new(*self.i(0) < value, @@ -857,9 +857,9 @@ impl Vec3 { } } -impl Vec for Vec3 {} +impl Vec for Vec3 {} -impl NumVec for Vec3 { +impl NumVec for Vec3 { /// Returns a new vector with `value` added to each component. #[inline] pub fn add_s(&self, value: T) -> Vec3 { @@ -1041,7 +1041,7 @@ impl NumVec for Vec3 { } } -impl Neg> for Vec3 { +impl Neg> for Vec3 { /// Returns the vector with each component negated. #[inline] pub fn neg(&self) -> Vec3 { @@ -1051,7 +1051,7 @@ impl Neg> for Vec3 { } } -impl FloatVec for Vec3 { +impl FloatVec for Vec3 { /// Returns the squared magnitude of the vector. This does not perform a /// square root operation like in the `magnitude` method and can therefore /// be more efficient for comparing the magnitudes of two vectors. @@ -1113,7 +1113,7 @@ impl FloatVec for Vec3 { } } -impl OrdVec> for Vec3 { +impl OrdVec> for Vec3 { #[inline] pub fn lt_s(&self, value: T) -> Vec3 { Vec3::new(*self.i(0) < value, @@ -1541,9 +1541,9 @@ impl Vec4 { } } -impl Vec for Vec4 {} +impl Vec for Vec4 {} -impl NumVec for Vec4 { +impl NumVec for Vec4 { /// Returns a new vector with `value` added to each component. #[inline] pub fn add_s(&self, value: T) -> Vec4 { @@ -1747,7 +1747,7 @@ impl NumVec for Vec4 { } } -impl Neg> for Vec4 { +impl Neg> for Vec4 { /// Returns the vector with each component negated. #[inline] pub fn neg(&self) -> Vec4 { @@ -1758,7 +1758,7 @@ impl Neg> for Vec4 { } } -impl FloatVec for Vec4 { +impl FloatVec for Vec4 { /// Returns the squared magnitude of the vector. This does not perform a /// square root operation like in the `magnitude` method and can therefore /// be more efficient for comparing the magnitudes of two vectors. @@ -1820,7 +1820,7 @@ impl FloatVec for Vec4 { } } -impl OrdVec> for Vec4 { +impl OrdVec> for Vec4 { #[inline] pub fn lt_s(&self, value: T) -> Vec4 { Vec4::new(*self.i(0) < value, diff --git a/src/space/bsp.rs b/src-old/space/bsp.rs similarity index 100% rename from src/space/bsp.rs rename to src-old/space/bsp.rs diff --git a/src/space/octree.rs b/src-old/space/octree.rs similarity index 86% rename from src/space/octree.rs rename to src-old/space/octree.rs index f567e2a..0aabc95 100644 --- a/src/space/octree.rs +++ b/src-old/space/octree.rs @@ -15,4 +15,9 @@ // http://gameprogrammingpatterns.com/spatial-partition.html -pub struct Octree; +use bounds::AABB3; + +pub struct Octree { + bounds: AABB3, + octants: [Option<~Octree>, ..8], +} diff --git a/src/space/quadtree.rs b/src-old/space/quadtree.rs similarity index 100% rename from src/space/quadtree.rs rename to src-old/space/quadtree.rs diff --git a/src/space/space.rs b/src-old/space/space.rs similarity index 100% rename from src/space/space.rs rename to src-old/space/space.rs diff --git a/src/transform/projection.rs b/src-old/transform/projection.rs similarity index 100% rename from src/transform/projection.rs rename to src-old/transform/projection.rs diff --git a/src/transform/rotation.rs b/src-old/transform/rotation.rs similarity index 93% rename from src/transform/rotation.rs rename to src-old/transform/rotation.rs index e70f5d7..0957b90 100644 --- a/src/transform/rotation.rs +++ b/src-old/transform/rotation.rs @@ -52,7 +52,7 @@ pub trait Rotation3: Eq + ToMat3 + ToMat4 + ToQuat { - pub fn rotate_point3(&self, point: Point3) -> Point3; + pub fn rotate_point3(&self, point: &Point3) -> Point3; pub fn rotate_vec3(&self, vec: &Vec3) -> Vec3; pub fn rotate_ray3(&self, ray: &Ray3) -> Ray3; pub fn to_rotation_mat3(&self) -> RotationMat3; @@ -80,7 +80,7 @@ impl RotationMat2 { impl Rotation2 for RotationMat2 { pub fn rotate_point2(&self, point: Point2) -> Point2 { - Point2::from_vec2(self.mat.mul_v(point.as_vec2())) + point.with_vec2(|vec| self.rotate_vec2(vec)) } pub fn rotate_vec2(&self, vec: &Vec2) -> Vec2 { @@ -121,8 +121,8 @@ impl Neg> for RotationMat2 { } impl Rotation3 for Quat { - pub fn rotate_point3(&self, point: Point3) -> Point3 { - Point3::from_vec3(self.mul_v(point.as_vec3())) + pub fn rotate_point3(&self, point: &Point3) -> Point3 { + point.with_vec3(|vec| self.rotate_vec3(vec)) } pub fn rotate_vec3(&self, vec: &Vec3) -> Vec3 { @@ -160,8 +160,8 @@ impl RotationMat3 { } impl Rotation3 for RotationMat3 { - pub fn rotate_point3(&self, point: Point3) -> Point3 { - Point3::from_vec3(self.mat.mul_v(point.as_vec3())) + pub fn rotate_point3(&self, point: &Point3) -> Point3 { + point.with_vec3(|vec| self.rotate_vec3(vec)) } pub fn rotate_vec3(&self, vec: &Vec3) -> Vec3 { @@ -243,7 +243,7 @@ impl Euler { } impl Rotation3 for Euler { - pub fn rotate_point3(&self, _point: Point3) -> Point3 { + pub fn rotate_point3(&self, _point: &Point3) -> Point3 { fail!("Not yet implemented.") } @@ -337,12 +337,27 @@ impl AxisAngle { } impl Rotation3 for AxisAngle { - pub fn rotate_point3(&self, _point: Point3) -> Point3 { - fail!("Not yet implemented.") + pub fn rotate_point3(&self, point: &Point3) -> Point3 { + point.with_vec3(|vec| self.rotate_vec3(vec)) } - pub fn rotate_vec3(&self, _vec: &Vec3) -> Vec3 { - fail!("Not yet implemented.") + pub fn rotate_vec3(&self, vec: &Vec3) -> Vec3 { + // Rodrigues' rotation formula + // http://en.wikipedia.org/wiki/Rodrigues%27_rotation_formula + // + // ~~~ + // v cos θ + (k × v) sin θ + k(k ⋅ v)(1 - cos θ) + // ~~~ + // + // Where: + // - `v` = vec + // - `k` = self.axis + // - `θ` = self.angle + + vec.mul_s(self.angle.cos()) + .add_v(&self.axis.cross(vec)).mul_s(self.angle.sin()) + .add_v(&self.axis.mul_s(self.axis.dot(vec)) + .mul_s(one!(T) - self.angle.cos())) } pub fn rotate_ray3(&self, _ray: &Ray3) -> Ray3 { @@ -434,7 +449,7 @@ pub struct AngleX(T); impl_approx!(AngleX) impl Rotation3 for AngleX { - pub fn rotate_point3(&self, _point: Point3) -> Point3 { + pub fn rotate_point3(&self, _point: &Point3) -> Point3 { fail!("Not yet implemented.") } @@ -495,7 +510,7 @@ pub struct AngleY(T); impl_approx!(AngleY) impl Rotation3 for AngleY { - pub fn rotate_point3(&self, _point: Point3) -> Point3 { + pub fn rotate_point3(&self, _point: &Point3) -> Point3 { fail!("Not yet implemented.") } @@ -575,7 +590,7 @@ impl Rotation2 for AngleZ { } impl Rotation3 for AngleZ { - pub fn rotate_point3(&self, _point: Point3) -> Point3 { + pub fn rotate_point3(&self, _point: &Point3) -> Point3 { fail!("Not yet implemented.") } diff --git a/src/transform/transform.rs b/src-old/transform/transform.rs similarity index 100% rename from src/transform/transform.rs rename to src-old/transform/transform.rs diff --git a/src/cgmath.rs b/src/cgmath.rs new file mode 100644 index 0000000..1f2cd91 --- /dev/null +++ b/src/cgmath.rs @@ -0,0 +1,26 @@ +// 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. + +#[link(name = "cgmath", + vers = "0.1", + author = "Brendan Zabarauskas", + url = "https://github.com/bjz/cgmath-rs")]; + +#[comment = "A mathematics library for computer graphics."]; +#[license = "ASL2"]; +#[crate_type = "lib"]; + +pub mod traits; +pub mod types; diff --git a/src/traits/alg/affine_space.rs b/src/traits/alg/affine_space.rs new file mode 100644 index 0000000..0e75751 --- /dev/null +++ b/src/traits/alg/affine_space.rs @@ -0,0 +1,25 @@ +// Copyright 2013 The OMath 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::ScalarMul; + +/// An affine space is a set of points closed under affine combinations. +pub trait AffineSpace: Eq + + Zero + + ScalarMul + + Add + + Sub {} diff --git a/src/traits/alg/coordinate.rs b/src/traits/alg/coordinate.rs new file mode 100644 index 0000000..3f134de --- /dev/null +++ b/src/traits/alg/coordinate.rs @@ -0,0 +1,20 @@ +// Copyright 2013 The OMath 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 traits::util::Indexable; +pub use traits::util::Swappable; + +pub trait Coordinate: Indexable + + Swappable {} diff --git a/src/traits/alg/division_ring.rs b/src/traits/alg/division_ring.rs new file mode 100644 index 0000000..5799d32 --- /dev/null +++ b/src/traits/alg/division_ring.rs @@ -0,0 +1,37 @@ +// Copyright 2013 The Lmath 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 also requires the multiplicative inverse operation (division). +pub trait DivisionRing: 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; diff --git a/src/traits/alg/euclidean_space.rs b/src/traits/alg/euclidean_space.rs new file mode 100644 index 0000000..a66e7be --- /dev/null +++ b/src/traits/alg/euclidean_space.rs @@ -0,0 +1,64 @@ +// Copyright 2013 The OMath 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::Ring; +use traits::alg::InnerProductSpace; + +/// The Euclidean space is a vector space over the Real numbers. +pub trait EuclideanSpace: InnerProductSpace { + 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::()) + } + + /// 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 + } +} diff --git a/src/traits/alg/inner_product_space.rs b/src/traits/alg/inner_product_space.rs new file mode 100644 index 0000000..0996590 --- /dev/null +++ b/src/traits/alg/inner_product_space.rs @@ -0,0 +1,24 @@ +// Copyright 2013 The OMath 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; +use traits::alg::VectorSpace; + +/// A vector space with the inner product operation. +pub trait InnerProductSpace: VectorSpace { + fn norm(&self) -> S; + fn inner(&self, other: &Self) -> S; + fn is_orthogonal(&self, other: &Self) -> bool; +} diff --git a/src/traits/alg/mod.rs b/src/traits/alg/mod.rs new file mode 100644 index 0000000..6fd8f25 --- /dev/null +++ b/src/traits/alg/mod.rs @@ -0,0 +1,36 @@ +// Copyright 2013 The OMath 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::affine_space::AffineSpace; +pub use self::coordinate::Coordinate; +pub use self::division_ring::DivisionRing; +pub use self::euclidean_space::EuclideanSpace; +pub use self::inner_product_space::InnerProductSpace; +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::vector_space::VectorSpace; + +pub mod affine_space; +pub mod coordinate; +pub mod division_ring; +pub mod euclidean_space; +pub mod inner_product_space; +pub mod module; +pub mod ordered_ring; +pub mod ring; +pub mod scalar_mul; +pub mod vector_space; diff --git a/src/traits/alg/module.rs b/src/traits/alg/module.rs new file mode 100644 index 0000000..6810020 --- /dev/null +++ b/src/traits/alg/module.rs @@ -0,0 +1,40 @@ +// Copyright 2013 The Lmath 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::ScalarMul; + +/// An algebraic structure that generalizes the notion of a vector space. +pub trait Module: Eq + + Add + + ScalarMul + + Zero {} + +// impls for concrete types + +impl Module for u8; +impl Module for u16; +impl Module for u32; +impl Module for u64; +impl Module for uint; +impl Module for i8; +impl Module for i16; +impl Module for i32; +impl Module for i64; +impl Module for int; +impl Module for f32; +impl Module for f64; +impl Module for float; diff --git a/src/traits/alg/ordered_ring.rs b/src/traits/alg/ordered_ring.rs new file mode 100644 index 0000000..96c3d9c --- /dev/null +++ b/src/traits/alg/ordered_ring.rs @@ -0,0 +1,36 @@ +// Copyright 2013 The Lmath 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: Ring + + Orderable {} + +// impls for concrete types + +impl OrderedRing for u8; +impl OrderedRing for u16; +impl OrderedRing for u32; +impl OrderedRing for u64; +impl OrderedRing for uint; +impl OrderedRing for i8; +impl OrderedRing for i16; +impl OrderedRing for i32; +impl OrderedRing for i64; +impl OrderedRing for int; +impl OrderedRing for f32; +impl OrderedRing for f64; +impl OrderedRing for float; diff --git a/src/traits/alg/ring.rs b/src/traits/alg/ring.rs new file mode 100644 index 0000000..c9d0b50 --- /dev/null +++ b/src/traits/alg/ring.rs @@ -0,0 +1,41 @@ +// Copyright 2013 The Lmath 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: Module + + Neg + + Sub + + One {} + +// impls for concrete types + +impl Ring for u8; +impl Ring for u16; +impl Ring for u32; +impl Ring for u64; +impl Ring for uint; +impl Ring for i8; +impl Ring for i16; +impl Ring for i32; +impl Ring for i64; +impl Ring for int; +impl Ring for f32; +impl Ring for f64; +impl Ring for float; diff --git a/src/traits/alg/scalar_mul.rs b/src/traits/alg/scalar_mul.rs new file mode 100644 index 0000000..32f8114 --- /dev/null +++ b/src/traits/alg/scalar_mul.rs @@ -0,0 +1,35 @@ +// Copyright 2013 The Lmath 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. + +/// Enforces the multiplication of an type by a scalar. +pub trait ScalarMul: Mul + + Div + + Rem {} + +// impls for concrete types + +impl ScalarMul for u8; +impl ScalarMul for u16; +impl ScalarMul for u32; +impl ScalarMul for u64; +impl ScalarMul for uint; +impl ScalarMul for i8; +impl ScalarMul for i16; +impl ScalarMul for i32; +impl ScalarMul for i64; +impl ScalarMul for int; +impl ScalarMul for f32; +impl ScalarMul for f64; +impl ScalarMul for float; diff --git a/src/traits/alg/vector_space.rs b/src/traits/alg/vector_space.rs new file mode 100644 index 0000000..92a379f --- /dev/null +++ b/src/traits/alg/vector_space.rs @@ -0,0 +1,22 @@ +// Copyright 2013 The OMath 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::Module; + +/// A vector space is a set that is closed under vector addition and +/// scalar multiplication. +pub trait VectorSpace: Module + + Neg + + Sub {} diff --git a/pkg.rs b/src/traits/ext/mod.rs similarity index 77% rename from pkg.rs rename to src/traits/ext/mod.rs index c45f8b6..d7f2e4a 100644 --- a/pkg.rs +++ b/src/traits/ext/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Lmath Developers. For a full listing of the authors, +// Copyright 2013 The OMath 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"); @@ -13,6 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#[pkg_crate(file = "src/lmath.rs")]; -#[pkg(id = "lmath", vers = "0.1.0")]; -#[pkg_dep(url = "git://github.com/bjz/numeric-rs")]; \ No newline at end of file +pub use self::vector_ext::VectorExt; + +pub mod vector_ext; diff --git a/src/traits/ext/vector_ext.rs b/src/traits/ext/vector_ext.rs new file mode 100644 index 0000000..36cc2f3 --- /dev/null +++ b/src/traits/ext/vector_ext.rs @@ -0,0 +1,49 @@ +// Copyright 2013 The OMath 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; +use traits::alg::VectorSpace; +use traits::util::Indexable; + +pub trait VectorExt: 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)) } + #[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) { self.map_mut(|x| *x = -*x); } + #[inline] fn add_self_s(&mut self, s: S) { self.map_mut(|x| *x = x.add(&s)); } + #[inline] fn sub_self_s(&mut self, s: S) { self.map_mut(|x| *x = x.sub(&s)); } + #[inline] fn mul_self_s(&mut self, s: S) { self.map_mut(|x| *x = x.mul(&s)); } + #[inline] fn div_self_s(&mut self, s: S) { self.map_mut(|x| *x = x.div(&s)); } + #[inline] fn rem_self_s(&mut self, s: S) { self.map_mut(|x| *x = x.rem(&s)); } + + #[inline] fn add_self_v(&mut self, other: &Self) { self.bimap_mut::(other, |a, b| *a = a.add(b)) } + #[inline] fn sub_self_v(&mut self, other: &Self) { self.bimap_mut::(other, |a, b| *a = a.sub(b)) } + #[inline] fn mul_self_v(&mut self, other: &Self) { self.bimap_mut::(other, |a, b| *a = a.mul(b)) } + #[inline] fn div_self_v(&mut self, other: &Self) { self.bimap_mut::(other, |a, b| *a = a.div(b)) } + #[inline] fn rem_self_v(&mut self, other: &Self) { self.bimap_mut::(other, |a, b| *a = a.rem(b)) } + + #[inline] fn comp_add(&self) -> S { fail!() } + #[inline] fn comp_mul(&self) -> S { fail!() } +} diff --git a/src/traits/mod.rs b/src/traits/mod.rs new file mode 100644 index 0000000..f9d5b00 --- /dev/null +++ b/src/traits/mod.rs @@ -0,0 +1,45 @@ +// Copyright 2013 The OMath 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; + +/// TODO +/// +/// # Example +/// +/// ~~~rust +/// use lmath::traits::util::*; +/// ~~~ +pub mod util; diff --git a/src/traits/util/indexable.rs b/src/traits/util/indexable.rs new file mode 100644 index 0000000..e40dc42 --- /dev/null +++ b/src/traits/util/indexable.rs @@ -0,0 +1,105 @@ +// Copyright 2013 The OMath 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]; + +/// Types that can be accessed via an unsigned index. +pub trait Indexable { + fn len(&self) -> uint; + 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; + fn as_mut_slice<'a>(&'a mut self) -> &'a mut Slice; + fn from_slice(slice: Slice) -> Self; + fn build(builder: &fn(i: uint) -> T) -> Self; + + #[inline] + fn map>(&self, f: &fn(&T) -> U) -> UU { + Indexable::build(|i| f(self.i(i))) + } + + #[inline] + fn map_mut(&mut self, f: &fn(&mut T)) { + for i in range(0, self.len()) { + f(self.mut_i(i)); + } + } + + #[inline] + fn bimap, + V, SliceV, VV: Indexable>(&self, other: &UU, f: &fn(&T, &U) -> V) -> VV { + Indexable::build(|i| f(self.i(i), other.i(i))) + } + + #[inline] + fn bimap_mut>(&mut self, other: &UU, f: &fn(&mut T, &U)) { + for i in range(0, self.len()) { + f(self.mut_i(i), other.i(i)); + } + } + + #[inline] + fn fold(&self, init: U, f: &fn(acc: &U, x: &T) -> U) -> U { + let mut acc = init; + for i in range(0, self.len()) { + acc = f(&acc, self.i(i)); + } + acc + } +} + +macro_rules! impl_indexable( + ($Self:ty, [$T:ident, ..$n:expr]) => ( + impl<$T> Indexable<$T, [$T,..$n]> for $Self { + #[inline] + fn len(&self) -> uint { $n } + + #[inline] + fn i<'a>(&'a self, i: uint) -> &'a $T { + &'a self.as_slice()[i] + } + + #[inline] + fn mut_i<'a>(&'a mut self, i: uint) -> &'a mut $T { + &'a mut self.as_mut_slice()[i] + } + + #[inline] + fn as_slice<'a>(&'a self) -> &'a [$T,..$n] { + unsafe { ::std::cast::transmute(self) } + } + + #[inline] + fn as_mut_slice<'a>(&'a mut self) -> &'a mut [$T,..$n] { + unsafe { ::std::cast::transmute(self) } + } + + #[inline] + fn from_slice(slice: [$T,..$n]) -> $Self { + unsafe { ::std::cast::transmute(slice) } + } + + #[inline] + fn build(builder: &fn(i: uint) -> $T) -> $Self { + use std::unstable::intrinsics; + let mut s: [$T,..$n] = unsafe { intrinsics::uninit() }; + for i in range::(0, $n) { + s[i] = builder(i); + } + Indexable::from_slice(s) + } + } + ) +) diff --git a/src/traits/util/mod.rs b/src/traits/util/mod.rs new file mode 100644 index 0000000..ead05d2 --- /dev/null +++ b/src/traits/util/mod.rs @@ -0,0 +1,22 @@ +// Copyright 2013 The OMath 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::indexable::Indexable; +pub use self::swappable::Swappable; + +pub mod indexable; +pub mod swappable; diff --git a/src/traits/util/swappable.rs b/src/traits/util/swappable.rs new file mode 100644 index 0000000..8b0d62c --- /dev/null +++ b/src/traits/util/swappable.rs @@ -0,0 +1,26 @@ +// Copyright 2013 The OMath 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::util::Indexable; + +pub trait Swappable: Indexable { + /// 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; + } +} diff --git a/src/types/matrix.rs b/src/types/matrix.rs new file mode 100644 index 0000000..123161d --- /dev/null +++ b/src/types/matrix.rs @@ -0,0 +1,14 @@ +// Copyright 2013 The OMath 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. diff --git a/src/types/mod.rs b/src/types/mod.rs new file mode 100644 index 0000000..db4e659 --- /dev/null +++ b/src/types/mod.rs @@ -0,0 +1,19 @@ +// Copyright 2013 The OMath 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; diff --git a/src/types/point.rs b/src/types/point.rs new file mode 100644 index 0000000..1bfc527 --- /dev/null +++ b/src/types/point.rs @@ -0,0 +1,76 @@ +// Copyright 2013 The OMath 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. + +//! Points are fixed positions in affine space with no length or direction. This +//! disinguishes them from vectors, which have a length and direction, but do +//! not have a fixed position. + +use traits::alg::*; +use traits::util::*; +use types::vector::{Vec2, Vec3}; + +#[deriving(Eq, Zero, Clone)] +struct Point2 { x: S, y: S } + +#[deriving(Eq, Zero, Clone)] +struct Point3 { x: S, y: S, z: S } + +impl Point2 { + #[inline] + pub fn new(x: S, y: S) -> Point2 { + Point2 { x: x, y: y } + } +} + +impl Point3 { + #[inline] + pub fn new(x: S, y: S, z: S) -> Point3 { + Point3 { x: x, y: y, z: z } + } +} + +// 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 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 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)) } } + +// Trait impls + +impl_indexable!(Point2, [T, ..2]) +impl_indexable!(Point3, [T, ..3]) + +impl Swappable for Point2; +impl Swappable for Point3; + +impl Coordinate for Point2; +impl Coordinate for Point3; + +impl ScalarMul for Point2; +impl ScalarMul for Point3; + +impl AffineSpace> for Point2; +impl AffineSpace> for Point3; diff --git a/src/types/quaternion.rs b/src/types/quaternion.rs new file mode 100644 index 0000000..51ec002 --- /dev/null +++ b/src/types/quaternion.rs @@ -0,0 +1,36 @@ +// Copyright 2013 The OMath 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::*; +use types::vector::Vec3; + +/// A quaternion in scalar/vector form +#[deriving(Clone, Eq)] +pub struct Quat { s: T, v: Vec3 } + +impl Quat { + /// Construct a new quaternion from one scalar component and three + /// imaginary components + #[inline] + pub fn new(w: T, xi: T, yj: T, zk: T) -> Quat { + Quat::from_sv(w, Vec3::new(xi, yj, zk)) + } + + /// Construct a new quaternion from a scalar and a vector + #[inline] + pub fn from_sv(s: T, v: Vec3) -> Quat { + Quat { s: s, v: v } + } +} diff --git a/src/types/vector.rs b/src/types/vector.rs new file mode 100644 index 0000000..67fc34c --- /dev/null +++ b/src/types/vector.rs @@ -0,0 +1,240 @@ +// Copyright 2013 The OMath 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 std::num::{Zero, zero}; +use std::num::{sqrt, atan2}; + +use traits::alg::*; +use traits::ext::*; +use traits::util::*; + +#[deriving(Eq, Zero, Clone)] pub struct Vec1 { x: S } +#[deriving(Eq, Zero, Clone)] pub struct Vec2 { x: S, y: S } +#[deriving(Eq, Zero, Clone)] pub struct Vec3 { x: S, y: S, z: S } +#[deriving(Eq, Zero, Clone)] pub struct Vec4 { x: S, y: S, z: S, w: S } +#[deriving(Eq, Zero, Clone)] pub struct Vec5 { x: S, y: S, z: S, w: S, a: S } +#[deriving(Eq, Zero, Clone)] pub struct Vec6 { x: S, y: S, z: S, w: S, a: S, b: S } + +macro_rules! impl_vec( + ($Self:ident <$S:ident> { $($field:ident),+ }) => ( + impl<$S> $Self<$S> { + #[inline] + pub fn new($($field: $S),+) -> $Self<$S> { + $Self { $($field: $field),+ } + } + } + ) +) + +impl_vec!(Vec1 { x }) +impl_vec!(Vec2 { x, y }) +impl_vec!(Vec3 { x, y, z }) +impl_vec!(Vec4 { x, y, z, w }) +impl_vec!(Vec5 { x, y, z, w, a }) +impl_vec!(Vec6 { x, y, z, w, a, b }) + +macro_rules! impl_vec_clonable( + ($Self:ident <$S:ident>) => ( + impl<$S:Clone> $Self<$S> { + /// Construct a vector from a single value. + #[inline] + pub fn from_value(value: $S) -> $Self<$S> { + Indexable::build(|_| value.clone()) + } + } + ) +) + +impl_vec_clonable!(Vec1) +impl_vec_clonable!(Vec2) +impl_vec_clonable!(Vec3) +impl_vec_clonable!(Vec4) +impl_vec_clonable!(Vec5) +impl_vec_clonable!(Vec6) + +macro_rules! impl_vec_ring( + ($Self:ident <$S:ident>) => ( + impl<$S:Ring> $Self<$S> { + /// The additive identity of the vector. + #[inline] + pub fn zero() -> $Self<$S> { zero() } + } + ) +) + +impl_vec_ring!(Vec1) +impl_vec_ring!(Vec2) +impl_vec_ring!(Vec3) +impl_vec_ring!(Vec4) +impl_vec_ring!(Vec5) +impl_vec_ring!(Vec6) + +// Operator impls + +macro_rules! impl_vec_ops( + ($vec_ops_mod:ident, $Self:ident <$S:ident>) => ( + pub mod $vec_ops_mod { + use super::*; + use super::super::super::traits::alg::*; + + impl<$S:Ring> 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> { + #[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> { + #[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> { + #[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> { + #[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> { + #[inline(always)] + fn neg(&self) -> $Self<$S> { self.map(|x| x.neg()) } + } + } + ) +) + +impl_vec_ops!(vec1_ops, Vec1) +impl_vec_ops!(vec2_ops, Vec2) +impl_vec_ops!(vec3_ops, Vec3) +impl_vec_ops!(vec4_ops, Vec4) +impl_vec_ops!(vec5_ops, Vec5) +impl_vec_ops!(vec6_ops, Vec6) + +/// Operations specific to two-dimensional vectors. +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) + } +} + +/// Operations specific to three-dimensional vectors. +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), + (self.z * other.x) - (self.x * other.z), + (self.x * other.y) - (self.y * other.x)) + } +} + +// Trait impls + +impl_indexable!(Vec1, [S, ..1]) +impl_indexable!(Vec2, [S, ..2]) +impl_indexable!(Vec3, [S, ..3]) +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 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 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; + +macro_rules! impl_vec_inner_product( + ($Self:ident <$S:ident>) => ( + impl<$S:Real + Ring + ApproxEq<$S>> InnerProductSpace<$S> for $Self<$S> { + fn norm(&self) -> $S { + num::sqrt(self.inner(self)) + } + + fn inner(&self, other: &$Self<$S>) -> $S { + let comp_sum: $Self<$S> = self.bimap(other, |a, b| a.mul(b)); + comp_sum.fold(num::zero::<$S>(), |a, b| a.add(b)) + } + + fn is_orthogonal(&self, other: &$Self<$S>) -> bool { + self.inner(other).approx_eq(&num::zero()) + } + } + ) +) + +impl_vec_inner_product!(Vec1) +impl_vec_inner_product!(Vec2) +impl_vec_inner_product!(Vec3) +impl_vec_inner_product!(Vec4) +impl_vec_inner_product!(Vec5) +impl_vec_inner_product!(Vec6) + +// Euclidean spaces only really make sense for 2D and 3D vector spaces + +impl> EuclideanSpace for Vec2 { + fn angle(&self, other: &Vec2) -> S { + atan2(self.perp_dot(other), self.dot(other)) + } +} + +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;