From 0160780bd1df0766e945c6f656c0fb3831273a06 Mon Sep 17 00:00:00 2001 From: Jason Travis Smith Date: Sun, 4 Oct 2015 02:59:26 -0400 Subject: [PATCH] Created a new math library. This library will e the math library of the magic game engine. Currently, it defines basic numerical types that can be used in generic programming and a set of generic Vector structures. Tests can be added to the "tests" crate. --- .gitignore | 2 + Cargo.toml | 4 + src/integer.rs | 29 ++++ src/lib.rs | 13 ++ src/number.rs | 63 ++++++++ src/real.rs | 28 ++++ src/vector.rs | 388 ++++++++++++++++++++++++++++++++++++++++++++++++ src/whole.rs | 28 ++++ tests/lib.rs | 3 + tests/vector.rs | 13 ++ 10 files changed, 571 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/integer.rs create mode 100644 src/lib.rs create mode 100644 src/number.rs create mode 100644 src/real.rs create mode 100644 src/vector.rs create mode 100644 src/whole.rs create mode 100644 tests/lib.rs create mode 100644 tests/vector.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a9d37c5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..8022d88 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "sigils" +version = "0.1.0" +authors = ["Jason Travis Smith "] diff --git a/src/integer.rs b/src/integer.rs new file mode 100644 index 0000000..0559da4 --- /dev/null +++ b/src/integer.rs @@ -0,0 +1,29 @@ +use super::number::Number; + + +/// A trait that defines what is required to be considered +/// an Integer. [List of types of numbers][1] +/// +/// [1]: https://en.wikipedia.org/wiki/List_of_types_of_numbers +pub trait Integer : Number +{ +} + + +// Create a macro to ease typing and reading. +/// A macro to make implementing the trait easier for all the +/// base integer types in rust. +macro_rules! integer_trait_impl +{ + ($traitName: ident for $($varType: ty)*) => + ($( + impl $traitName for $varType + { + } + )*) +} + + +// Implement the trait for the types that are Integers. +integer_trait_impl!(Integer for u8 u16 u32 u64 usize); +integer_trait_impl!(Integer for i8 i16 i32 i64 isize); diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..789eecc --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,13 @@ +#![feature(zero_one)] +#![feature(float_from_str_radix)] + + +mod number; +mod whole; +mod integer; +mod real; + +pub mod vector; + + +pub use self::vector::Vector; diff --git a/src/number.rs b/src/number.rs new file mode 100644 index 0000000..7f9c2c2 --- /dev/null +++ b/src/number.rs @@ -0,0 +1,63 @@ +use std::cmp::PartialEq; +use std::num::{Zero, One}; +use std::ops::{Add, Sub, Mul, Div, Rem}; + + +/// A trait that defines what is required to be considered +/// a number. +pub trait Number : Zero + One + Add + Sub + + Mul + Div + Rem + + PartialEq + Copy + Clone +{ + type StrRadixError; + + /// Create a number from a given string and base radix. + fn from_str_radix(src: &str, radix: u32) -> + Result; +} + + +// Create some macros to ease typing and reading. +/// A macro to make implementing the trait easier for all the +/// base integer types in rust. +macro_rules! int_trait_impl +{ + ($traitName: ident for $($varType: ty)*) => + ($( + impl Number for $varType + { + type StrRadixError = ::std::num::ParseIntError; + + fn from_str_radix(src: &str, radix: u32) -> + Result + { + <$varType>::from_str_radix(src, radix) + } + } + )*) +} + +/// A macro to make implementing the trait easier for all the +/// base float types in rust. +macro_rules! float_trait_impl +{ + ($traitName: ident for $($varType: ty)*) => + ($( + impl $traitName for $varType + { + type StrRadixError = ::std::num::ParseFloatError; + + fn from_str_radix(src: &str, radix: u32) -> + Result + { + <$varType>::from_str_radix(src, radix) + } + } + )*) +} + + +// Implement the trait for the types that are Numbers. +int_trait_impl!(Number for u8 u16 u32 u64 usize); +int_trait_impl!(Number for i8 i16 i32 i64 isize); +float_trait_impl!(Number for f32 f64); diff --git a/src/real.rs b/src/real.rs new file mode 100644 index 0000000..93ab240 --- /dev/null +++ b/src/real.rs @@ -0,0 +1,28 @@ +use super::number::Number; + + +/// A trait that defines what is required to be considered +/// a Real number. [List of types of numbers][1] +/// +/// [1]: https://en.wikipedia.org/wiki/List_of_types_of_numbers +trait Real : Number +{ +} + + +// Create a macro to ease typing and reading. +/// A macro to make implementing the trait easier for all the +/// base float types in rust. +macro_rules! real_trait_impl +{ + ($traitName: ident for $($varType: ty)*) => + ($( + impl Real for $varType + { + } + )*) +} + + +// Implement the trait for the types that are Real numbers. +real_trait_impl!(Real for f32 f64); diff --git a/src/vector.rs b/src/vector.rs new file mode 100644 index 0000000..58cf4c1 --- /dev/null +++ b/src/vector.rs @@ -0,0 +1,388 @@ +use std::num::{Zero, One}; +use std::ops::{Add, Sub, Mul, Div, Rem}; + +use super::number::Number; + + +/// A trait that defines the minimum set of +/// functions a Vector must implement. +pub trait Vector : Clone where T: Number +{ + // Creation functions. + /// Create a Vector from a single value. + fn from_value(val: T) -> Self; + + /// Create a zero Vector. All components will be set to zero. + fn zero() -> Self + { + Self::from_value(T::zero()) + } + + /// Create an identity Vector. All components will be set to one. + fn identity() -> Self + { + Self::from_value(T::one()) + } + + + // Scalar operations that result in a new Vector. + /// Add a scalar value to this Vector and return a new Vector. + fn add_scalar(&self, scalar: T) -> Self; + + /// Subtract a scalar value from this Vector and return a new Vector. + fn sub_scalar(&self, scalar: T) -> Self; + + /// Multiply this Vector by a scalar value and return a new Vector. + fn mul_scalar(&self, scalar: T) -> Self; + + /// Divide this Vector by a scalar value and return a new Vector. + fn div_scalar(&self, scalar: T) -> Self; + + /// Divide this Vector by a scalar value, take the remainder, + /// and return a new Vector. + fn rem_scalar(&self, scalar: T) -> Self; + + + // Vector operations that result in a new Vector. + /// Add a Vector to this Vector and return a new Vector. + fn add_vector(&self, vector: &Self) -> Self; + + /// Subtract a Vector from this Vector and return a new Vector. + fn sub_vector(&self, vector: &Self) -> Self; + + /// Multiply this Vector by a Vector and return a new Vector. + fn mul_vector(&self, vector: &Self) -> Self; + + /// Divide this Vector by a Vector and return a new Vector. + fn div_vector(&self, vector: &Self) -> Self; + + /// Divide this Vector by a Vector, take the remainder, + /// and return a new Vector. + fn rem_vector(&self, vector: &Self) -> Self; + + + // Scalar operations that change this Vector. + /// Add a scalar value to this Vector. + fn add_scalar_self(&mut self, scalar: T); + + /// Subtract a scalar value from this Vector. + fn sub_scalar_self(&mut self, scalar: T); + + /// Multiply this Vector by a scalar value. + fn mul_scalar_self(&mut self, scalar: T); + + /// Divide this Vector by a scalar value. + fn div_scalar_self(&mut self, scalar: T); + + /// Divide this Vector by a scalar value and take the remainder. + fn rem_scalar_self(&mut self, scalar: T); + + + // Vector operations that change this Vector. + /// Add a Vector to this Vector. + fn add_vector_self(&mut self, vector: &Self); + + /// Subtract a Vector from this Vector. + fn sub_vector_self(&mut self, vector: &Self); + + /// Multiply this Vector by a Vector. + fn mul_vector_self(&mut self, vector: &Self); + + /// Divide this Vector by a Vector. + fn div_vector_self(&mut self, vector: &Self); + + /// Divide this Vector by a Vector and take the remainder. + fn rem_vector_self(&mut self, vector: &Self); + + + // Basic Vector functions. + /// Get the sum of all the components of the Vector. + fn get_sum(&self) -> T; + + /// Get the product of all the components of the Vector. + fn get_product(&self) -> T; + + /// Get the dot product between this and another Vector. + fn dot(&self, vector: &Self) -> T + { + self.mul_vector(vector).get_sum() + } +} + + +// Create a few macros to define the three Vector +// structs: Vector2, Vector3, and Vector4. +/// A macro that will help with adding and +/// multiplying components of a vector. +macro_rules! perform_method_on_components +{ + ($method: ident, {$x: expr, $y: expr}) => + { + $x.$method($y) + }; + + ($method: ident, {$x: expr, $y: expr, $z: expr}) => + { + $x.$method($y).$method($z) + }; + + ($method: ident, {$x: expr, $y: expr, $z: expr, $w: expr}) => + { + $x.$method($y).$method($z).$method($w) + }; +} + +/// A macro that will define a binary operation +/// a Vector and its components. +macro_rules! binary_operator_impl +{ + ($traitName: ident :: $funcName: ident, + $structName: ident {$($field: ident),+}) => + { + impl<'a, T> $traitName for &'a $structName where T: Number + { + type Output = $structName; + + fn $funcName(self, scalar: T) -> $structName + { + $structName::new($(self.$field.$funcName(scalar)),+) + } + } + + impl<'a, 'b, T> $traitName<&'a $structName> for &'b $structName + where T: Number + { + type Output = $structName; + + fn $funcName(self, vector: &'a $structName) -> $structName + { + $structName::new($(self.$field.$funcName(vector.$field)),+) + } + } + } +} + +/// A macro that defines a Vector structure +/// that implements the Vector trait. +macro_rules! define_vector +{ + ($structName: ident <$T: ident> {$($field: ident),+}) => + { + #[derive(PartialEq, Eq, Copy, Clone, Hash)] + pub struct $structName where T: Number + { + $(pub $field: T),+ + } + + impl<$T> $structName<$T> where T: Number + { + pub fn new($($field: $T),+) -> $structName<$T> + { + $structName {$($field: $field),+} + } + } + + impl Vector for $structName where T: Number + { + fn from_value(val: T) -> $structName + { + $structName {$($field: val),+} + } + + fn add_scalar(&self, scalar: T) -> $structName + { + self + scalar + } + + fn sub_scalar(&self, scalar: T) -> $structName + { + self - scalar + } + + fn mul_scalar(&self, scalar: T) -> $structName + { + self * scalar + } + + fn div_scalar(&self, scalar: T) -> $structName + { + self / scalar + } + + fn rem_scalar(&self, scalar: T) -> $structName + { + self % scalar + } + + + fn add_vector(&self, vector: &$structName) -> $structName + { + self + vector + } + + fn sub_vector(&self, vector: &$structName) -> $structName + { + self - vector + } + + fn mul_vector(&self, vector: &$structName) -> $structName + { + self * vector + } + + fn div_vector(&self, vector: &$structName) -> $structName + { + self / vector + } + + fn rem_vector(&self, vector: &$structName) -> $structName + { + self % vector + } + + + fn add_scalar_self(&mut self, scalar: T) + { + *self = &*self + scalar; + } + + fn sub_scalar_self(&mut self, scalar: T) + { + *self = &*self - scalar; + } + + fn mul_scalar_self(&mut self, scalar: T) + { + *self = &*self * scalar; + } + + fn div_scalar_self(&mut self, scalar: T) + { + *self = &*self / scalar; + } + + fn rem_scalar_self(&mut self, scalar: T) + { + *self = &*self % scalar; + } + + + fn add_vector_self(&mut self, vector: &$structName) + { + *self = &*self + vector; + } + + fn sub_vector_self(&mut self, vector: &$structName) + { + *self = &*self - vector; + } + + fn mul_vector_self(&mut self, vector: &$structName) + { + *self = &*self * vector; + } + + fn div_vector_self(&mut self, vector: &$structName) + { + *self = &*self / vector; + } + + fn rem_vector_self(&mut self, vector: &$structName) + { + *self = &*self % vector; + } + + + fn get_sum(&self) -> T + { + perform_method_on_components!(add, {$(self.$field),+}) + } + + fn get_product(&self) -> T + { + perform_method_on_components!(mul, {$(self.$field),+}) + } + } + + binary_operator_impl!(Add::add, $structName {$($field),+}); + binary_operator_impl!(Sub::sub, $structName {$($field),+}); + binary_operator_impl!(Mul::mul, $structName {$($field),+}); + binary_operator_impl!(Div::div, $structName {$($field),+}); + binary_operator_impl!(Rem::rem, $structName {$($field),+}); + } +} + + +// Define the Vector2, Vector3, and Vector4 structures. +define_vector!(Vector2 {x, y}); +define_vector!(Vector3 {x, y, z}); +define_vector!(Vector4 {x, y, z, w}); + + +// Implements operations specific to the different +// Vector structure sizes. +impl Vector2 where T: Number +{ + pub fn unit_x() -> Vector2 + { + Vector2::new(T::one(), T::zero()) + } + + pub fn unit_y() -> Vector2 + { + Vector2::new(T::zero(), T::one()) + } + + pub fn perpendicular_dot(&self, vector: &Vector2) -> T + { + (self.x * vector.y) - (self.y * vector.x) + } +} + +impl Vector3 where T: Number +{ + pub fn unit_x() -> Vector3 + { + Vector3::new(T::one(), T::zero(), T::zero()) + } + + pub fn unit_y() -> Vector3 + { + Vector3::new(T::zero(), T::one(), T::zero()) + } + + pub fn unit_z() -> Vector3 + { + Vector3::new(T::zero(), T::zero(), T::one()) + } + + pub fn cross(&self, vector: &Vector3) -> Vector3 + { + Vector3::new((self.y * vector.z) - (self.z * vector.y), + (self.z * vector.x) - (self.x * vector.z), + (self.x * vector.y) - (self.y * vector.x)) + } +} + +impl Vector4 where T: Number +{ + pub fn unit_x() -> Vector4 + { + Vector4::new(T::one(), T::zero(), T::zero(), T::zero()) + } + + pub fn unit_y() -> Vector4 + { + Vector4::new(T::zero(), T::one(), T::zero(), T::zero()) + } + + pub fn unit_z() -> Vector4 + { + Vector4::new(T::zero(), T::zero(), T::one(), T::zero()) + } + + pub fn unit_w() -> Vector4 + { + Vector4::new(T::zero(), T::zero(), T::zero(), T::one()) + } +} diff --git a/src/whole.rs b/src/whole.rs new file mode 100644 index 0000000..f0de073 --- /dev/null +++ b/src/whole.rs @@ -0,0 +1,28 @@ +use super::number::Number; + + +/// A trait that defines what is required to be considered +/// a Whole number. [List of types of numbers][1] +/// +/// [1]: https://en.wikipedia.org/wiki/List_of_types_of_numbers +trait Whole : Number +{ +} + + +// Create a macro to ease typing and reading. +/// A macro to make implementing the trait easier for all the +/// base integer types in rust. +macro_rules! whole_trait_impl +{ + ($traitName: ident for $($varType: ty)*) => + ($( + impl $traitName for $varType + { + } + )*) +} + + +// Implement the trait for the types that are Whole numbers. +whole_trait_impl!(Whole for u8 u16 u32 u64 usize); diff --git a/tests/lib.rs b/tests/lib.rs new file mode 100644 index 0000000..253aac6 --- /dev/null +++ b/tests/lib.rs @@ -0,0 +1,3 @@ +extern crate sigils; + +mod vector; diff --git a/tests/vector.rs b/tests/vector.rs new file mode 100644 index 0000000..ab7ef59 --- /dev/null +++ b/tests/vector.rs @@ -0,0 +1,13 @@ +extern crate sigils; + +use sigils::Vector; + + +#[test] +fn vector_creation() +{ + let v: Vector; + + v = Vector::new(); + assert_eq!(v.x, 1.0f32); +}