33 Commits

Author SHA1 Message Date
36c769346c use inline const constructor because it's a little bit prettier 2024-09-06 11:44:43 -07:00
5f2bec75f5 enable matrix mul test 2024-09-06 11:38:29 -07:00
7a9aaf9fe0 matrix mul 2024-09-06 11:38:22 -07:00
9ad90cea2e fix tests 2024-09-06 11:25:51 -07:00
f2fec0b3b9 implement a bunch of fixed wide stuff 2024-09-06 11:25:46 -07:00
dae72d73d5 convert to row-major 2024-09-06 10:52:17 -07:00
4a1eff40da matrix multiplication ascii art 2024-09-06 10:44:30 -07:00
d5bd82761a fix dot test 2024-09-06 10:36:34 -07:00
5cad8637cd tweak dot 2024-09-06 10:36:24 -07:00
607706ee2a nope 2024-09-05 17:56:09 -07:00
2312ee27b7 test vector and matrix (TODO: Debug trait) 2024-09-05 17:56:09 -07:00
4d2aa0b2c8 is this better? 2024-09-05 17:44:44 -07:00
34450d6a13 matrix multiplication 2024-09-05 17:37:38 -07:00
1a6ece1312 epic const generic array transpose
verified that this loop unrolls on compiler explorer
2024-09-05 17:36:45 -07:00
e95f675e91 test named fields 2024-09-05 16:56:59 -07:00
504ff37c47 write a test 2024-09-05 16:45:44 -07:00
41cdd03b1b wip fixed wide 2024-09-05 16:32:19 -07:00
e375173625 keep generic operators and only implement i64 convenience operator 2024-09-05 16:18:13 -07:00
488a6b6496 fix vector bool code 2024-09-05 16:08:53 -07:00
5cdd2c3ee1 must be less generic to avoid conflict with convenience operators 2024-09-05 16:05:47 -07:00
a0da6873c1 vector operators 2024-09-05 15:56:44 -07:00
345d5737a2 more generic Neg operator 2024-09-05 15:56:35 -07:00
f4d28dd3c3 use derive macros 2024-09-05 15:43:26 -07:00
c362081003 implement a bunch of stuff 2024-09-05 15:43:26 -07:00
990a923463 fixup tests 2024-09-05 13:53:03 -07:00
56b781fcb8 we build 2024-09-05 13:52:54 -07:00
e026f6efed wip 2024-09-05 13:36:38 -07:00
e475da5fb4 put that back 2024-09-05 13:16:02 -07:00
c3026c67e9 delete everything and start over 2024-09-05 12:49:20 -07:00
103697fbdd matrix: test det + adjugate 2024-09-04 13:55:11 -07:00
cf17460b77 special case 3d vectors and matrices 2024-09-04 13:47:50 -07:00
823a05c101 matrix: directly implement dot product to avoid a copy 2024-09-04 12:11:52 -07:00
e5f95b97ce matrix: macro mat mul 2024-09-04 12:11:52 -07:00
15 changed files with 617 additions and 749 deletions

View File

@@ -201,6 +201,15 @@ macro_rules! impl_multiplicatave_assign_operator {
} }
}; };
} }
impl<const N:usize,const F:usize> std::iter::Sum for Fixed<N,F>{
fn sum<I:Iterator<Item=Self>>(iter:I)->Self{
let mut sum=Self::ZERO;
for elem in iter{
sum+=elem;
}
sum
}
}
macro_rules! impl_operator_16 { macro_rules! impl_operator_16 {
( $macro: ident, $struct: ident, $trait: ident, $method: ident, $output: ty ) => { ( $macro: ident, $struct: ident, $trait: ident, $method: ident, $output: ty ) => {

View File

@@ -4,9 +4,10 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[features] [features]
default=["fixed_wide"] default=["fixed_wide","named-fields"]
fixed_wide=["dep:fixed_wide"] named-fields=[]
fixed_wide=["dep:fixed_wide","dep:paste"]
[dependencies] [dependencies]
fixed_wide = { version = "0.1.0", path = "../fixed_wide", optional = true } fixed_wide = { version = "0.1.0", path = "../fixed_wide", optional = true }
paste = "1.0.15" paste = { version = "1.0.15", optional = true }

View File

@@ -1,14 +1,10 @@
mod macros; mod macros;
mod vector; pub mod types;
mod matrix; pub mod vector;
pub mod matrix;
pub use vector::Vector2; #[cfg(feature="named-fields")]
pub use vector::Vector3; mod named;
pub use vector::Vector4;
pub use matrix::Matrix2;
pub use matrix::Matrix3;
pub use matrix::Matrix4;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;

View File

@@ -1,138 +1 @@
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_common {
( $struct: ident { $($field: ident), + }, $size: expr ) => {
impl<T> $struct<T> {
/// Constructs a new vector with the specified values for each field.
///
/// # Example
///
/// ```
/// use fixed_wide_vectors::Vector2;
///
/// let vec2 = Vector2::new(0, 0);
///
/// assert_eq!(vec2.x, 0);
/// assert_eq!(vec2.y, 0);
/// ```
#[inline(always)]
pub const fn new( $($field: T), + ) -> Self {
Self {
$( $field ), +
}
}
/// Consumes the vector and returns its values as an array.
///
/// # Example
///
/// ```
/// use fixed_wide_vectors::Vector2;
///
/// let vec2 = Vector2::new(0, 0);
/// let array = vec2.to_array();
///
/// assert_eq!(array, [0, 0]);
/// ```
#[inline(always)]
pub fn to_array(self) -> [T; $size] {
[ $(self.$field), + ]
}
/// Consumes the vector and returns a new vector with the given function applied on each field.
///
/// # Example
///
/// ```
/// use fixed_wide_vectors::Vector2;
///
/// let vec2 = Vector2::new(1, 2)
/// .map(|i| i * 2);
///
/// assert_eq!(vec2, Vector2::new(2, 4));
/// ```
#[inline]
pub fn map<F, U>(self, f: F) -> $struct<U>
where
F: Fn(T) -> U
{
$struct {
$( $field: f(self.$field) ), +
}
}
}
impl<T: Copy> $struct<T> {
/// Constructs a vector using the given `value` as the value for all of its fields.
///
/// # Example
///
/// ```
/// use fixed_wide_vectors::Vector2;
///
/// let vec2 = Vector2::from_value(0);
///
/// assert_eq!(vec2, Vector2::new(0, 0));
/// ```
#[inline(always)]
pub const fn from_value(value: T) -> Self {
Self {
$( $field: value ), +
}
}
}
impl<T> From<[T; $size]> for $struct<T> {
fn from(from: [T; $size]) -> Self {
let mut iterator = from.into_iter();
Self {
// SAFETY: We know the size of `from` so `iterator.next()` is always `Some(..)`
$( $field: unsafe { iterator.next().unwrap_unchecked() } ), +
}
}
}
impl<T: core::fmt::Debug> core::fmt::Debug for $struct<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let identifier = core::stringify!($struct);
f.debug_struct(identifier)
$( .field( core::stringify!($field), &self.$field ) ) +
.finish()
}
}
impl<T: PartialEq> PartialEq for $struct<T> {
fn eq(&self, other: &Self) -> bool {
$( self.$field == other.$field ) && +
}
}
impl<T: Eq> Eq for $struct<T> { }
impl<T: core::hash::Hash> core::hash::Hash for $struct<T> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
$( self.$field.hash(state); ) +
}
}
impl<T: Clone> Clone for $struct<T> {
fn clone(&self) -> Self {
Self {
$( $field: self.$field.clone() ), +
}
}
}
impl<T: Copy> Copy for $struct<T> { }
impl<T: Default> Default for $struct<T> {
fn default() -> Self {
Self {
$( $field: T::default() ), +
}
}
}
}
}

View File

@@ -2,22 +2,18 @@
#[macro_export(local_inner_macros)] #[macro_export(local_inner_macros)]
macro_rules! impl_wide_vector_operations_2arg_not_const_generic { macro_rules! impl_wide_vector_operations_2arg_not_const_generic {
( (
($struct: ident { $($field: ident), + }, $size: expr), (),
($lhs:expr, $rhs:expr) ($lhs:expr, $rhs:expr)
) => { ) => {
impl $struct<fixed_wide::fixed::Fixed<{$lhs},{$lhs*32}>>{ impl<const N:usize> Vector<N,fixed_wide::fixed::Fixed<{$lhs},{$lhs*32}>>{
paste::item!{ paste::item!{
#[inline] #[inline]
pub fn [<wide_mul_ $lhs _ $rhs>](self,rhs:$struct<fixed_wide::fixed::Fixed<{$rhs},{$rhs*32}>>)->$struct<fixed_wide::fixed::Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>>{ pub fn [<wide_mul_ $lhs _ $rhs>](self,rhs:Vector<N,fixed_wide::fixed::Fixed<{$rhs},{$rhs*32}>>)->Vector<N,fixed_wide::fixed::Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>>{
$struct{ self.map_zip(rhs,|(a,b)|a.[<wide_mul_ $lhs _ $rhs>](b))
$( $field: self.$field.[<wide_mul_ $lhs _ $rhs>](rhs.$field) ), +
}
} }
#[inline] #[inline]
pub fn [<wide_dot_ $lhs _ $rhs>](self,rhs:$struct<fixed_wide::fixed::Fixed<{$rhs},{$rhs*32}>>)->fixed_wide::fixed::Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>{ pub fn [<wide_dot_ $lhs _ $rhs>](self,rhs:Vector<N,fixed_wide::fixed::Fixed<{$rhs},{$rhs*32}>>)->fixed_wide::fixed::Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>{
$crate::sum_repeating!( self.array.into_iter().zip(rhs.array).map(|(a,b)|a.[<wide_mul_ $lhs _ $rhs>](b)).sum()
$( + (self.$field.[<wide_mul_ $lhs _ $rhs>](rhs.$field)) ) +
)
} }
} }
} }
@@ -27,16 +23,14 @@ macro_rules! impl_wide_vector_operations_2arg_not_const_generic {
#[macro_export(local_inner_macros)] #[macro_export(local_inner_macros)]
macro_rules! impl_wide_vector_operations_1arg_not_const_generic { macro_rules! impl_wide_vector_operations_1arg_not_const_generic {
( (
($struct: ident { $($field: ident), + }, $size: expr), (),
$n:expr $n:expr
) => { ) => {
impl $struct<fixed_wide::fixed::Fixed<{$n},{$n*32}>>{ impl<const N:usize> Vector<N,fixed_wide::fixed::Fixed<{$n},{$n*32}>>{
paste::item!{ paste::item!{
#[inline] #[inline]
pub fn wide_length_squared(&self)->fixed_wide::fixed::Fixed<{$n*2},{$n*2*32}>{ pub fn wide_length_squared(&self)->fixed_wide::fixed::Fixed<{$n*2},{$n*2*32}>{
$crate::sum_repeating!( self.array.into_iter().map(|t|t.[<wide_mul_ $n _ $n>](t)).sum()
$( + self.$field.[<wide_mul_ $n _ $n>](self.$field) ) +
)
} }
} }
} }
@@ -77,116 +71,28 @@ macro_rules! do_macro_8{
#[doc(hidden)] #[doc(hidden)]
#[macro_export(local_inner_macros)] #[macro_export(local_inner_macros)]
macro_rules! impl_wide_vector_operations { macro_rules! impl_wide_vector_operations {
( $struct: ident { $($field: ident), + }, $size: expr ) => { () => {
$crate::do_macro_8!(impl_wide_vector_operations_1arg_not_const_generic,($struct { $($field), + }, $size)); $crate::do_macro_8!(impl_wide_vector_operations_1arg_not_const_generic,());
$crate::do_macro_8x8!(impl_wide_vector_operations_2arg_not_const_generic,($struct { $($field), + }, $size)); $crate::do_macro_8x8!(impl_wide_vector_operations_2arg_not_const_generic,());
}; };
} }
#[doc(hidden)] #[doc(hidden)]
#[macro_export(local_inner_macros)] #[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_mul_transpose_helper { macro_rules! impl_vector_3_wide_cross {
( (
$lhs_axis:expr, $wide_mul:ident, $rhs:ident, (),
($struct: ident { $($field: ident), + }), ($lhs:expr, $rhs:expr)
($from_struct: ident { $($from_field: ident), + }), )=>{
$static_field: ident impl Vector<3,fixed_wide::fixed::Fixed<{$lhs},{$lhs*32}>>{
) => {
$crate::sum_repeating!(
$( + $lhs_axis.$field.$wide_mul($rhs.$from_field.$static_field) ) +
)
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_mul_inner {
(
// MatY<VecX>.MatX<VecZ> = MatY<VecZ>
$lhs:ident, $lhs_field_outer:ident, $wide_mul:ident, $rhs:ident,
$struct_inner_thru: tt, //VecX
($struct_inner: ident { $($field_inner: ident), + }), //VecX
($rhs_struct_inner: ident { $($rhs_field_inner: ident), + }), //VecZ
$rhs_outer: tt //MatX
) => {
$rhs_struct_inner {
$(
//directly dot product to avoid a copy
$rhs_field_inner: $crate::impl_matrix_wide_mul_transpose_helper!{
//lhs_axis
$lhs.$lhs_field_outer,$wide_mul,$rhs,
$struct_inner_thru, //VecZ
$rhs_outer, //MatX
$rhs_field_inner
}
), +
}
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_mul_outer {
(
// MatY<VecX>.MatX<VecZ> = MatY<VecZ>
$lhs:ident, $wide_mul:ident, $rhs:ident,
//result matrix shape
($struct_outer: ident { $($field_outer: ident), + }),//MatY
$rhs_struct_inner: tt,//VecZ
//inner loop shape
$struct_inner: tt,//VecX
$rhs_matrix: tt//MatX
) => {
$struct_outer {
$(
$field_outer: $crate::impl_matrix_wide_mul_inner!{
$lhs, $field_outer, $wide_mul, $rhs,
$struct_inner, //VecX
$struct_inner, //VecX
$rhs_struct_inner, //VecZ
$rhs_matrix //MatX
}
), +
}
}
}
// Notes:
// Mat3<Vec2>.dot(Vec2) -> Vec3
// lhs.dot(rhs) -> out
// lhs = Mat3<Vec4>
// rhs = Mat4<Vec2>
// out = Mat3<Vec2>
// Mat3<Vec4>.dot(Mat4<Vec2>) -> Mat3<Vec2>
// how to matrix multiply:
// RHS TRANSPOSE
// Mat4<Vec2> -> Mat2<Vec4>
// rhs_t = Mat2<Vec4>
// inner loop:
// out[y][x] = lhs[y].dot(rhs_t[x])
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_mul {
(
($struct_outer: ident { $($field_outer: ident), + }, $vector_outer: ident { $($vector_field_outer: ident), + }, $size_outer: expr),
($struct_inner: ident { $($field_inner: ident), + }, $matrix_inner: ident { $($matrix_field_inner: ident), + }, $size_inner: expr),
($rhs_struct_inner: ident { $($rhs_field_inner: ident), + }, $rhs_matrix_inner: ident { $($rhs_matrix_field_inner: ident), + }, $rhs_size_inner: expr),
($lhs: expr, $rhs: expr)
) => {
impl $struct_outer<$struct_inner<fixed_wide::fixed::Fixed<{$lhs},{$lhs*32}>>>{
paste::item!{ paste::item!{
#[inline] #[inline]
pub fn [<wide_dot_ $size_outer x $size_inner _ $size_inner x $rhs_size_inner _ $lhs _ $rhs>](self,rhs:$matrix_inner<$rhs_struct_inner<fixed_wide::fixed::Fixed<{$rhs},{$rhs*32}>>>)->$struct_outer<$rhs_struct_inner<fixed_wide::fixed::Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>>>{ pub fn [<wide_cross_ $lhs _ $rhs>](self,rhs:Vector<3,fixed_wide::fixed::Fixed<{$rhs},{$rhs*32}>>)->Vector<3,fixed_wide::fixed::Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>>{
$crate::impl_matrix_wide_mul_outer!( Vector::new([
//constituent idents self.y.[<wide_mul_ $lhs _ $rhs>](rhs.z)-self.z.[<wide_mul_ $lhs _ $rhs>](rhs.y),
self,[<wide_mul_ $lhs _ $rhs>],rhs, self.z.[<wide_mul_ $lhs _ $rhs>](rhs.x)-self.x.[<wide_mul_ $lhs _ $rhs>](rhs.z),
//result matrix shape self.x.[<wide_mul_ $lhs _ $rhs>](rhs.y)-self.y.[<wide_mul_ $lhs _ $rhs>](rhs.x),
($struct_outer { $($field_outer), + }), ])
($rhs_struct_inner { $($rhs_field_inner), + }),
//inner loop shape
($struct_inner { $($field_inner), + }),
($matrix_inner { $($matrix_field_inner), + })
)
} }
} }
} }
@@ -195,80 +101,112 @@ macro_rules! impl_matrix_wide_mul {
#[doc(hidden)] #[doc(hidden)]
#[macro_export(local_inner_macros)] #[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_mul_shim { macro_rules! impl_vector_wide_3 {
()=>{
$crate::do_macro_8x8!(impl_vector_3_wide_cross,());
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! do_macro_4_dumb{
( (
($outer_info:tt,$inner_info:tt,$rhs_info:tt), $macro:ident,
$any:tt
)=>{
$crate::macro_repeated!($macro, $any, (1,2),(2,4),(3,6),(4,8));
};
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_dot {
(
(),
($lhs: expr, $rhs: expr) ($lhs: expr, $rhs: expr)
) => { ) => {
$crate::impl_matrix_wide_mul!($outer_info,$inner_info,$rhs_info,($lhs,$rhs)); impl<const X:usize,const Y:usize> Matrix<X,Y,fixed_wide::fixed::Fixed<{$lhs},{$lhs*32}>>{
} paste::item!{
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_mul_8x8 {
(
($outer_info:tt,$inner_info:tt),
$rhs_info:tt
) => {
$crate::do_macro_8x8!(impl_matrix_wide_mul_shim,($outer_info,$inner_info,$rhs_info));
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_mul_repeat_rhs {
(
($outer_info:tt,($($rhs_info:tt),+)),
$inner_info:tt
) => {
$crate::macro_repeated!(impl_matrix_wide_mul_8x8,($outer_info,$inner_info),$($rhs_info),+);
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_wide_matrix_operations_2arg_not_const_generic {
(
$lhs: expr, $rhs: expr,
($struct_outer: ident { $($field_outer: ident), + }, $vector_outer: ident { $($vector_field_outer: ident), + }, $size_outer: expr),
($struct_inner: ident { $($field_inner: ident), + }, $matrix_inner: ident { $($matrix_field_inner: ident), + }, $size_inner: expr)
) => {
/* TODO: nasty determinant macro
impl<U:std::ops::Add<Output=U>,T:Copy+fixed_wide_traits::wide::WideMul<Output=U>> $struct<T> {
#[inline] #[inline]
pub fn wide_dot(&self) -> U { pub fn [<wide_dot_ $lhs _ $rhs>]<const Z:usize>(self,rhs:Matrix<Z,X,fixed_wide::fixed::Fixed<{$rhs},{$rhs*32}>>)->Matrix<Z,Y,fixed_wide::fixed::Fixed<{$lhs+$rhs},{($lhs+$rhs)*32}>>{
$crate::sum_repeating!( let mut array_of_iterators=rhs.array.map(|axis|axis.into_iter().cycle());
$( + self.$field.wide_mul(self.$field) ) + Matrix::new(
) self.array.map(|axis|
core::array::from_fn(|_|
// axis dot product with transposed rhs array
axis.iter().zip(
array_of_iterators.iter_mut()
).map(|(&lhs_value,rhs_iter)|
lhs_value.[<wide_mul_ $lhs _ $rhs>](rhs_iter.next().unwrap())
).sum()
)
)
)
}
} }
} }
*/ }
};
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_wide_matrix_operations_1arg_not_const_generic {
(
$n: expr,
($struct_outer: ident { $($field_outer: ident), + }, $vector_outer: ident { $($vector_field_outer: ident), + }, $size_outer: expr),
) => {
/* TODO: nasty determinant macro
impl<U:std::ops::Add<Output=U>,T:Copy+fixed_wide_traits::wide::WideMul<Output=U>> $struct<T> {
#[inline]
pub fn wide_det(&self) -> U {
$crate::sum_repeating!(
$( + self.$field.wide_mul(self.$field) ) +
)
}
}
*/
};
} }
// HACK: Allows us to sum repeating tokens in macros.
// See: https://stackoverflow.com/a/60187870/17452730
#[doc(hidden)] #[doc(hidden)]
#[macro_export(local_inner_macros)] #[macro_export(local_inner_macros)]
macro_rules! sum_repeating { macro_rules! impl_matrix_wide_dot_8x8 {
( + $($item: tt) * ) => { () => {
$($item) * $crate::do_macro_8x8!(impl_matrix_wide_dot,());
}; }
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_3x3_det_not_const_generic {
(
$n: expr,
$_2n: expr
)=>{
impl Matrix<3,3,fixed_wide::fixed::Fixed<$n,{$n*32}>>{
paste::item!{
pub fn [<wide_det_3x3_ $n>](self)->fixed_wide::fixed::Fixed<{$n*3},{$n*3*32}>{
//[<wide_dot_ $n _ $n*2>] will not compile, so the doubles are hardcoded above
self.x_axis.[<wide_dot_ $n _ $_2n>](self.y_axis.[<wide_cross_ $n _ $n>](self.z_axis))
}
}
}
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_3x3_det_not_const_generic_shim {
(
(),($n: expr,$_2n: expr)
)=>{
$crate::impl_matrix_wide_3x3_det_not_const_generic!($n,$_2n);
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_3x3_adjugate_not_const_generic {
(
(),
$n: expr
)=>{
impl Matrix<3,3,fixed_wide::fixed::Fixed<$n,{$n*32}>>{
paste::item!{
pub fn [<wide_adjugate_3x3_ $n>](self)->Matrix<3,3,fixed_wide::fixed::Fixed<{$n*2},{$n*2*32}>>{
Matrix::new([
[self.y_axis.y.[<wide_mul_ $n _ $n>](self.z_axis.z)-self.y_axis.z.[<wide_mul_ $n _ $n>](self.z_axis.y),self.x_axis.z.[<wide_mul_ $n _ $n>](self.z_axis.y)-self.x_axis.y.[<wide_mul_ $n _ $n>](self.z_axis.z),self.x_axis.y.[<wide_mul_ $n _ $n>](self.y_axis.z)-self.x_axis.z.[<wide_mul_ $n _ $n>](self.y_axis.y)],
[self.y_axis.z.[<wide_mul_ $n _ $n>](self.z_axis.x)-self.y_axis.x.[<wide_mul_ $n _ $n>](self.z_axis.z),self.x_axis.x.[<wide_mul_ $n _ $n>](self.z_axis.z)-self.x_axis.z.[<wide_mul_ $n _ $n>](self.z_axis.x),self.x_axis.z.[<wide_mul_ $n _ $n>](self.y_axis.x)-self.x_axis.x.[<wide_mul_ $n _ $n>](self.y_axis.z)],
[self.y_axis.x.[<wide_mul_ $n _ $n>](self.z_axis.y)-self.y_axis.y.[<wide_mul_ $n _ $n>](self.z_axis.x),self.x_axis.y.[<wide_mul_ $n _ $n>](self.z_axis.x)-self.x_axis.x.[<wide_mul_ $n _ $n>](self.z_axis.y),self.x_axis.x.[<wide_mul_ $n _ $n>](self.y_axis.y)-self.x_axis.y.[<wide_mul_ $n _ $n>](self.y_axis.x)],
])
}
}
}
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_wide_3x3 {
()=>{
$crate::do_macro_4_dumb!(impl_matrix_wide_3x3_det_not_const_generic_shim,());
$crate::do_macro_8!(impl_matrix_wide_3x3_adjugate_not_const_generic,());
}
} }

View File

@@ -1,192 +1,129 @@
// Stolen from https://github.com/c1m50c/fixed-vectors (MIT license)
#[doc(hidden)] #[doc(hidden)]
#[macro_export(local_inner_macros)] #[macro_export(local_inner_macros)]
macro_rules! impl_matrix { macro_rules! impl_matrix {
( () => {
($struct_outer: ident { $($field_outer: ident), + }, $vector_outer: ident { $($vector_field_outer: ident), + }, $size_outer: expr) impl<const X:usize,const Y:usize,T> Matrix<X,Y,T>{
) => {
$crate::impl_common!($struct_outer { $($field_outer), + }, $size_outer);
impl<U> $struct_outer<U> {
#[inline(always)] #[inline(always)]
pub fn to_vector(self) -> $vector_outer<U> { pub const fn new(array:[[T;X];Y])->Self{
$vector_outer { Self{array}
$( }
$vector_field_outer: self.$field_outer #[inline(always)]
), + pub fn to_array(self)->[[T;X];Y]{
} self.array
}
#[inline]
pub fn map<F,U>(self,f:F)->Matrix<X,Y,U>
where
F:Fn(T)->U
{
Matrix::new(
self.array.map(|inner|inner.map(&f)),
)
}
#[inline]
pub fn transpose(self)->Matrix<Y,X,T>{
//how did I think of this
let mut array_of_iterators=self.array.map(|axis|axis.into_iter());
Matrix::new(
core::array::from_fn(|_|
array_of_iterators.each_mut().map(|iter|
iter.next().unwrap()
)
)
)
}
#[inline]
// MatY<VecX>.MatX<VecZ> = MatY<VecZ>
pub fn dot<const Z:usize,U,V>(self,rhs:Matrix<Z,X,U>)->Matrix<Z,Y,V>
where
T:core::ops::Mul<U,Output=V>+Copy,
V:core::iter::Sum,
U:Copy,
{
let mut array_of_iterators=rhs.array.map(|axis|axis.into_iter().cycle());
Matrix::new(
self.array.map(|axis|
core::array::from_fn(|_|
// axis dot product with transposed rhs array
axis.iter().zip(
array_of_iterators.iter_mut()
).map(|(&lhs_value,rhs_iter)|
lhs_value*rhs_iter.next().unwrap()
).sum()
)
)
)
}
}
impl<const X:usize,const Y:usize,T> Matrix<X,Y,T>
where
T:Copy
{
pub const fn from_value(value:T)->Self{
Self::new([[value;X];Y])
}
}
impl<const X:usize,const Y:usize,T:Default> Default for Matrix<X,Y,T>{
fn default()->Self{
Self::new(
core::array::from_fn(|_|core::array::from_fn(|_|Default::default()))
)
}
}
#[cfg(feature="fixed_wide")]
$crate::impl_matrix_wide_dot_8x8!();
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_named_fields_shape {
(
($struct_outer:ident, $size_outer: expr),
($size_inner: expr)
) => {
impl<T> core::ops::Deref for Matrix<$size_outer,$size_inner,T>{
type Target=$struct_outer<Vector<$size_inner,T>>;
fn deref(&self)->&Self::Target{
unsafe{core::mem::transmute(&self.array)}
}
}
impl<T> core::ops::DerefMut for Matrix<$size_outer,$size_inner,T>{
fn deref_mut(&mut self)->&mut Self::Target{
unsafe{core::mem::transmute(&mut self.array)}
} }
} }
} }
} }
#[doc(hidden)] #[doc(hidden)]
#[macro_export(local_inner_macros)] #[macro_export(local_inner_macros)]
macro_rules! impl_matrix_shim { macro_rules! impl_matrix_named_fields_shape_shim {
(
(),
$matrix_info:tt
) => {
$crate::impl_matrix!($matrix_info);
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrices {
(
($($matrix_info:tt),+),
$vector_infos:tt
) => {
$crate::macro_repeated!(impl_matrix_shim,(),$($matrix_info),+);
$crate::macro_repeated!(impl_matrix_inner_shim,$vector_infos,$($matrix_info),+);
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_inner_shim {
( (
($($vector_info:tt),+), ($($vector_info:tt),+),
$matrix_info:tt $matrix_info:tt
) => { ) => {
$crate::macro_repeated!(impl_matrix_inner,$matrix_info,$($vector_info),+); $crate::macro_repeated!(impl_matrix_named_fields_shape,$matrix_info,$($vector_info),+);
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_named_fields {
(
($($matrix_info:tt),+),
$vector_infos:tt
) => {
$crate::macro_repeated!(impl_matrix_named_fields_shape_shim,$vector_infos,$($matrix_info),+);
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_3x3 {
()=>{
#[cfg(feature="fixed_wide")] #[cfg(feature="fixed_wide")]
$crate::macro_repeated!(impl_matrix_wide_mul_repeat_rhs,($matrix_info,($($vector_info),+)),$($vector_info),+); $crate::impl_matrix_wide_3x3!();
} }
} }
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_inner {
(
($struct_outer: ident { $($field_outer: ident), + }, $vector_outer: ident { $($vector_field_outer: ident), + }, $size_outer: expr),
($struct_inner: ident { $($field_inner: ident), + }, $matrix_inner: ident { $($matrix_field_inner: ident), + }, $size_inner: expr)
) => {
impl<T> $struct_outer<$struct_inner<T>> {
#[inline(always)]
pub fn to_array_2d(self) -> [[T; $size_inner]; $size_outer] {
[ $(self.$field_outer.to_array()), + ]
}
#[inline]
pub fn map_2d<F, U>(self, f: F) -> $struct_outer<$struct_inner<U>>
where
F: Fn(T) -> U
{
$crate::matrix_map2d_outer!{f,self,($struct_outer { $($field_outer), + }),($struct_inner { $($field_inner), + })}
}
#[inline]
pub fn transpose(self) -> $matrix_inner<$vector_outer<T>>{
$crate::matrix_transpose_outer!{self,
($matrix_inner { $($matrix_field_inner), + }),($struct_inner { $($field_inner), + }),
($vector_outer { $($vector_field_outer), + }),($struct_outer { $($field_outer), + })
}
}
}
impl<T: Copy> $struct_outer<$struct_inner<T>> {
#[inline(always)]
pub const fn from_value_2d(value: T) -> Self {
Self {
$( $field_outer: $struct_inner::from_value(value) ), +
}
}
//TODO: diagonal
}
// Impl floating-point based methods
//#[cfg(feature="fixed_wide_traits")]
//$crate::impl_wide_matrix_operations!( ($struct_outer { $($field_outer), + }, $size_outer), ($struct_inner, $size_inner), $fields_inner );
};
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! matrix_map2d_outer {
( $f:ident, $value:ident, ($struct_outer: ident { $($field_outer: ident), + }), $unparsed_inner:tt ) => {
$struct_outer {
$(
$field_outer: $crate::matrix_map2d_inner!{$f,$value,$field_outer,$unparsed_inner}
), +
}
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! matrix_map2d_inner {
( $f:ident, $value:ident, $field_outer:ident, ($struct_inner: ident { $($field_inner: ident), + }) ) => {
$struct_inner {
$(
$field_inner: $f($value.$field_outer.$field_inner)
), +
}
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! matrix_transpose_outer {
(
$value:ident,
($struct_outer: ident { $($field_outer: ident), + }),
($old_outer: ident { $($old_field_outer: ident), + }),
$fields_inner:tt,
$old_fields_inner:tt
) => {
$struct_outer {
$(
$field_outer: $crate::matrix_transpose_inner!{$value,$old_field_outer,$fields_inner,$old_fields_inner}
), +
}
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! matrix_transpose_inner {
( $value:ident, $field_outer:ident,
($struct_inner: ident { $($field_inner: ident), + }),
($old_struct_inner: ident { $($old_field_inner: ident), + })
) => {
$struct_inner {
$(
$field_inner: $value.$old_field_inner.$field_outer
), +
}
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_matrix_operator {
( $struct: ident { $($field: ident), + }, $trait: ident, $method: ident, $output: ty ) => {
impl<T:core::ops::$trait<Output=T>> core::ops::$trait for $struct<T> {
type Output = $output;
fn $method(self, other: Self) -> Self::Output {
Self {
$( $field: self.$field.$method(other.$field) ), +
}
}
}
impl<T:core::ops::$trait<Output=T>+Copy> core::ops::$trait<T> for $struct<T>{
type Output = $output;
fn $method(self, other: T) -> Self::Output {
$struct {
$( $field: self.$field.$method(other) ), +
}
}
}
};
( $struct: ident { $($field: ident), + }, $trait: ident, $method: ident ) => {
impl<T: core::ops::$trait> core::ops::$trait for $struct<T> {
fn $method(&mut self, other: Self) {
$( self.$field.$method(other.$field) ); +
}
}
impl<T: core::ops::$trait + Copy> core::ops::$trait<T> for $struct<T> {
fn $method(&mut self, other: T) {
$( self.$field.$method(other) ); +
}
}
};
}

View File

@@ -1,146 +1,187 @@
// Stolen from https://github.com/c1m50c/fixed-vectors (MIT license)
#[doc(hidden)] #[doc(hidden)]
#[macro_export(local_inner_macros)] #[macro_export(local_inner_macros)]
macro_rules! impl_vector { macro_rules! impl_vector {
( $struct: ident { $($field: ident), + }, $size: expr ) => { () => {
$crate::impl_common!($struct { $($field), + }, $size); impl<const N:usize,T> Vector<N,T>{
#[inline(always)]
impl<T: Ord> $struct<T> { pub const fn new(array:[T;N])->Self{
pub fn min(self, rhs: Self) -> $struct<T> { Self{array}
$struct{
$( $field: self.$field.min(rhs.$field) ), +
}
} }
pub fn max(self, rhs: Self) -> $struct<T> { #[inline(always)]
$struct{ pub fn to_array(self)->[T;N]{
$( $field: self.$field.max(rhs.$field) ), + self.array
}
} }
pub fn cmp(self, rhs: Self) -> $struct<core::cmp::Ordering> { #[inline]
$struct{ pub fn map<F,U>(self,f:F)->Vector<N,U>
$( $field: self.$field.cmp(&rhs.$field) ), + where
} F:Fn(T)->U
{
Vector::new(
self.array.map(f)
)
} }
pub fn lt(self, rhs: Self) -> $struct<bool> { #[inline]
$struct{ pub fn map_zip<F,U,V>(self,other:Vector<N,U>,f:F)->Vector<N,V>
$( $field: self.$field.lt(&rhs.$field) ), + where
} F:Fn((T,U))->V,
{
let mut iter=self.array.into_iter().zip(other.array);
Vector::new(
core::array::from_fn(|_|f(iter.next().unwrap())),
)
} }
pub fn gt(self, rhs: Self) -> $struct<bool> { }
$struct{ impl<const N:usize,T:Copy> Vector<N,T>{
$( $field: self.$field.gt(&rhs.$field) ), + #[inline(always)]
} pub const fn from_value(value:T)->Self{
} Self::new([value;N])
pub fn ge(self, rhs: Self) -> $struct<bool> {
$struct{
$( $field: self.$field.ge(&rhs.$field) ), +
}
}
pub fn le(self, rhs: Self) -> $struct<bool> {
$struct{
$( $field: self.$field.le(&rhs.$field) ), +
}
} }
} }
impl $struct<bool>{ impl<const N:usize,T:Default> Default for Vector<N,T>{
fn default()->Self{
Self::new(
core::array::from_fn(|_|Default::default())
)
}
}
impl<const N:usize,T:Ord> Vector<N,T>{
#[inline]
pub fn min(self,rhs:Self)->Self{
self.map_zip(rhs,|(a,b)|a.min(b))
}
#[inline]
pub fn max(self,rhs:Self)->Self{
self.map_zip(rhs,|(a,b)|a.max(b))
}
#[inline]
pub fn cmp(self,rhs:Self)->Vector<N,core::cmp::Ordering>{
self.map_zip(rhs,|(a,b)|a.cmp(&b))
}
#[inline]
pub fn lt(self,rhs:Self)->Vector<N,bool>{
self.map_zip(rhs,|(a,b)|a.lt(&b))
}
#[inline]
pub fn gt(self,rhs:Self)->Vector<N,bool>{
self.map_zip(rhs,|(a,b)|a.gt(&b))
}
#[inline]
pub fn ge(self,rhs:Self)->Vector<N,bool>{
self.map_zip(rhs,|(a,b)|a.ge(&b))
}
#[inline]
pub fn le(self,rhs:Self)->Vector<N,bool>{
self.map_zip(rhs,|(a,b)|a.le(&b))
}
}
impl<const N:usize> Vector<N,bool>{
#[inline]
pub fn all(&self)->bool{ pub fn all(&self)->bool{
const ALL:[bool;$size]=[true;$size]; self.array==[true;N]
core::matches!(self.to_array(),ALL)
} }
#[inline]
pub fn any(&self)->bool{ pub fn any(&self)->bool{
$( self.$field )|| + self.array!=[false;N]
} }
} }
impl<T: core::ops::Neg<Output = T>> core::ops::Neg for $struct<T> { impl<const N:usize,T:core::ops::Neg<Output=V>,V> core::ops::Neg for Vector<N,T>{
type Output = Self; type Output=Vector<N,V>;
fn neg(self)->Self::Output{
fn neg(self) -> Self::Output { Vector::new(
Self { self.array.map(|t|-t)
$( $field: -self.$field ), + )
}
} }
} }
// Impl arithmetic pperators // Impl arithmetic operators
$crate::impl_vector_operator!( $struct { $($field), + }, AddAssign, add_assign ); $crate::impl_vector_assign_operator!(AddAssign, add_assign );
$crate::impl_vector_operator!( $struct { $($field), + }, Add, add, Self ); $crate::impl_vector_operator!(Add, add );
$crate::impl_vector_operator!( $struct { $($field), + }, SubAssign, sub_assign ); $crate::impl_vector_assign_operator!(SubAssign, sub_assign );
$crate::impl_vector_operator!( $struct { $($field), + }, Sub, sub, Self ); $crate::impl_vector_operator!(Sub, sub );
$crate::impl_vector_operator!( $struct { $($field), + }, MulAssign, mul_assign ); $crate::impl_vector_assign_operator!(MulAssign, mul_assign );
$crate::impl_vector_operator!( $struct { $($field), + }, Mul, mul, Self ); $crate::impl_vector_operator!(Mul, mul );
$crate::impl_vector_operator!( $struct { $($field), + }, DivAssign, div_assign ); $crate::impl_vector_assign_operator!(DivAssign, div_assign );
$crate::impl_vector_operator!( $struct { $($field), + }, Div, div, Self ); $crate::impl_vector_operator!(Div, div );
$crate::impl_vector_operator!( $struct { $($field), + }, RemAssign, rem_assign ); $crate::impl_vector_assign_operator!(RemAssign, rem_assign );
$crate::impl_vector_operator!( $struct { $($field), + }, Rem, rem, Self ); $crate::impl_vector_operator!(Rem, rem );
// Impl bitwise operators // Impl bitwise operators
$crate::impl_vector_operator!( $struct { $($field), + }, BitAndAssign, bitand_assign ); $crate::impl_vector_assign_operator!(BitAndAssign, bitand_assign );
$crate::impl_vector_operator!( $struct { $($field), + }, BitAnd, bitand, Self ); $crate::impl_vector_operator!(BitAnd, bitand );
$crate::impl_vector_operator!( $struct { $($field), + }, BitOrAssign, bitor_assign ); $crate::impl_vector_assign_operator!(BitOrAssign, bitor_assign );
$crate::impl_vector_operator!( $struct { $($field), + }, BitOr, bitor, Self ); $crate::impl_vector_operator!(BitOr, bitor );
$crate::impl_vector_operator!( $struct { $($field), + }, BitXorAssign, bitxor_assign ); $crate::impl_vector_assign_operator!(BitXorAssign, bitxor_assign );
$crate::impl_vector_operator!( $struct { $($field), + }, BitXor, bitxor, Self ); $crate::impl_vector_operator!(BitXor, bitxor );
// Impl floating-point based methods // Impl floating-point based methods
#[cfg(feature="fixed_wide")] #[cfg(feature="fixed_wide")]
$crate::impl_wide_vector_operations!( $struct { $($field), + }, $size ); $crate::impl_wide_vector_operations!();
}; }
} }
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_extend {
( $struct: ident { $($field: ident), + }, $struct_extended: ident, $field_extended: ident ) => {
impl<T> $struct<T> {
#[inline(always)]
pub fn extend(self,value:T) -> $struct_extended<T> {
$struct_extended {
$( $field:self.$field, ) +
$field_extended:value
}
}
}
};
}
#[doc(hidden)] #[doc(hidden)]
#[macro_export(local_inner_macros)] #[macro_export(local_inner_macros)]
macro_rules! impl_vector_operator { macro_rules! impl_vector_operator {
( $struct: ident { $($field: ident), + }, $trait: ident, $method: ident, $output: ty ) => { ($trait: ident, $method: ident ) => {
impl<T:core::ops::$trait<Output=T>> core::ops::$trait for $struct<T> { impl<const N:usize,T:core::ops::$trait<U,Output=V>,U,V> core::ops::$trait<Vector<N,U>> for Vector<N,T>{
type Output = $output; type Output=Vector<N,V>;
fn $method(self,rhs:Vector<N,U>)->Self::Output{
fn $method(self, other: Self) -> Self::Output { self.map_zip(rhs,|(a,b)|a.$method(b))
Self {
$( $field: self.$field.$method(other.$field) ), +
}
} }
} }
impl<T:core::ops::$trait<Output=T>+Copy> core::ops::$trait<T> for $struct<T>{ impl<const N:usize,T:core::ops::$trait<i64,Output=T>> core::ops::$trait<i64> for Vector<N,T>{
type Output = $output; type Output=Self;
fn $method(self,rhs:i64)->Self::Output{
fn $method(self, other: T) -> Self::Output { self.map(|t|t.$method(rhs))
$struct {
$( $field: self.$field.$method(other) ), +
}
} }
} }
}; }
}
( $struct: ident { $($field: ident), + }, $trait: ident, $method: ident ) => { #[doc(hidden)]
impl<T: core::ops::$trait> core::ops::$trait for $struct<T> { #[macro_export(local_inner_macros)]
fn $method(&mut self, other: Self) { macro_rules! impl_vector_assign_operator {
$( self.$field.$method(other.$field) ); + ($trait: ident, $method: ident ) => {
} impl<const N:usize,T:core::ops::$trait<U>,U> core::ops::$trait<Vector<N,U>> for Vector<N,T>{
} fn $method(&mut self,rhs:Vector<N,U>){
self.array.iter_mut().zip(rhs.array)
impl<T: core::ops::$trait + Copy> core::ops::$trait<T> for $struct<T> { .for_each(|(a,b)|a.$method(b))
fn $method(&mut self, other: T) { }
$( self.$field.$method(other) ); + }
} impl<const N:usize,T:core::ops::$trait<i64>> core::ops::$trait<i64> for Vector<N,T>{
} fn $method(&mut self,rhs:i64){
}; self.array.iter_mut()
.for_each(|t|t.$method(rhs))
}
}
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_vector_named_fields {
( $struct:ident, $size: expr ) => {
impl<T> core::ops::Deref for Vector<$size,T>{
type Target=$struct<T>;
fn deref(&self)->&Self::Target{
unsafe{core::mem::transmute(&self.array)}
}
}
impl<T> core::ops::DerefMut for Vector<$size,T>{
fn deref_mut(&mut self)->&mut Self::Target{
unsafe{core::mem::transmute(&mut self.array)}
}
}
}
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_vector_3 {
()=>{
#[cfg(feature="fixed_wide")]
$crate::impl_vector_wide_3!();
}
} }

View File

@@ -1,36 +1,9 @@
use crate::{Vector2,Vector3,Vector4}; #[derive(Clone,Copy,Hash,Eq,PartialEq)]
pub struct Matrix<const X:usize,const Y:usize,T>{
pub struct Matrix2<T> { pub(crate) array:[[T;X];Y],
pub x_axis: T,
pub y_axis: T,
}
pub struct Matrix3<T> {
pub x_axis: T,
pub y_axis: T,
pub z_axis: T,
}
pub struct Matrix4<T> {
pub x_axis: T,
pub y_axis: T,
pub z_axis: T,
pub w_axis: T,
} }
crate::impl_extend!(Matrix2 { x_axis, y_axis }, Matrix3, z_axis); crate::impl_matrix!();
crate::impl_extend!(Matrix3 { x_axis, y_axis, z_axis }, Matrix4, w_axis);
//TODO: extend vertically
crate::impl_matrices!( //Special case 3x3 matrix operations because I cba to write macros for the arbitrary cases
//outer struct and equivalent vector crate::impl_matrix_3x3!();
(
(Matrix2 { x_axis, y_axis }, Vector2 { x, y }, 2),
(Matrix3 { x_axis, y_axis, z_axis }, Vector3 { x, y, z }, 3),
(Matrix4 { x_axis, y_axis, z_axis, w_axis }, Vector4 { x, y, z, w }, 4)
),
//inner struct and equivalent matrix
(
(Vector2 { x, y }, Matrix2 { x_axis, y_axis }, 2),
(Vector3 { x, y, z }, Matrix3 { x_axis, y_axis, z_axis }, 3),
(Vector4 { x, y, z, w }, Matrix4 { x_axis, y_axis, z_axis, w_axis }, 4)
)
);

View File

@@ -0,0 +1,59 @@
use crate::vector::Vector;
use crate::matrix::Matrix;
#[repr(C)]
pub struct Vector2<T> {
pub x: T,
pub y: T,
}
#[repr(C)]
pub struct Vector3<T> {
pub x: T,
pub y: T,
pub z: T,
}
#[repr(C)]
pub struct Vector4<T> {
pub x: T,
pub y: T,
pub z: T,
pub w: T,
}
crate::impl_vector_named_fields!(Vector2, 2);
crate::impl_vector_named_fields!(Vector3, 3);
crate::impl_vector_named_fields!(Vector4, 4);
#[repr(C)]
pub struct Matrix2<T> {
pub x_axis: T,
pub y_axis: T,
}
#[repr(C)]
pub struct Matrix3<T> {
pub x_axis: T,
pub y_axis: T,
pub z_axis: T,
}
#[repr(C)]
pub struct Matrix4<T> {
pub x_axis: T,
pub y_axis: T,
pub z_axis: T,
pub w_axis: T,
}
crate::impl_matrix_named_fields!(
//outer struct
(
(Matrix2, 2),
(Matrix3, 3),
(Matrix4, 4)
),
//inner struct
(
(2),
(3),
(4)
)
);

View File

@@ -1,4 +1,4 @@
use crate::{Vector2,Vector3,Vector4,Matrix3,Matrix4}; use crate::types::{Matrix3,Matrix2x3,Matrix4x3,Matrix2x4,Vector3};
type Planar64=fixed_wide::types::I32F32; type Planar64=fixed_wide::types::I32F32;
type Planar64Wide1=fixed_wide::types::I64F64; type Planar64Wide1=fixed_wide::types::I64F64;
@@ -12,7 +12,7 @@ fn wide_vec3(){
let v2=v1.wide_mul_2_2(v1); let v2=v1.wide_mul_2_2(v1);
let v3=v2.wide_mul_4_4(v2); let v3=v2.wide_mul_4_4(v2);
assert_eq!(v3,Vector3::from_value(Planar64Wide3::from(3i128.pow(8)))); assert_eq!(v3.array,Vector3::from_value(Planar64Wide3::from(3i128.pow(8))).array);
} }
#[test] #[test]
@@ -37,27 +37,58 @@ fn wide_vec3_length_squared(){
#[test] #[test]
fn wide_matrix_dot(){ fn wide_matrix_dot(){
let lhs=Matrix3::from([ let lhs=Matrix4x3::new([
Vector4::from([Planar64::from(1),Planar64::from(2),Planar64::from(3),Planar64::from(4)]), [Planar64::from(1),Planar64::from(2),Planar64::from(3),Planar64::from(4)],
Vector4::from([Planar64::from(5),Planar64::from(6),Planar64::from(7),Planar64::from(8)]), [Planar64::from(5),Planar64::from(6),Planar64::from(7),Planar64::from(8)],
Vector4::from([Planar64::from(9),Planar64::from(10),Planar64::from(11),Planar64::from(12)]), [Planar64::from(9),Planar64::from(10),Planar64::from(11),Planar64::from(12)],
]); ]);
let rhs=Matrix4::from([ let rhs=Matrix2x4::new([
Vector2::from([Planar64::from(1),Planar64::from(2)]), [Planar64::from(1),Planar64::from(2)],
Vector2::from([Planar64::from(3),Planar64::from(4)]), [Planar64::from(3),Planar64::from(4)],
Vector2::from([Planar64::from(5),Planar64::from(6)]), [Planar64::from(5),Planar64::from(6)],
Vector2::from([Planar64::from(7),Planar64::from(8)]), [Planar64::from(7),Planar64::from(8)],
]); ]);
// Mat3<Vec4>.dot(Mat4<Vec2>) -> Mat3<Vec2> // Mat3<Vec4>.dot(Mat4<Vec2>) -> Mat3<Vec2>
let m_dot=lhs.wide_dot_3x4_4x2_1_1(rhs); let m_dot=lhs.wide_dot_1_1(rhs);
//In[1]:= {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}} . {{1, 2}, {3, 4}, {5, 6}, {7, 8}} //In[1]:= {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}} . {{1, 2}, {3, 4}, {5, 6}, {7, 8}}
//Out[1]= {{50, 60}, {114, 140}, {178, 220}} //Out[1]= {{50, 60}, {114, 140}, {178, 220}}
assert_eq!( assert_eq!(
m_dot, m_dot.array,
Matrix3::from([ Matrix2x3::new([
Vector2::from([Planar64Wide1::from(50),Planar64Wide1::from(60)]), [Planar64Wide1::from(50),Planar64Wide1::from(60)],
Vector2::from([Planar64Wide1::from(114),Planar64Wide1::from(140)]), [Planar64Wide1::from(114),Planar64Wide1::from(140)],
Vector2::from([Planar64Wide1::from(178),Planar64Wide1::from(220)]), [Planar64Wide1::from(178),Planar64Wide1::from(220)],
]) ]).array
);
}
#[test]
fn wide_matrix_det(){
let m=Matrix3::new([
[Planar64::from(1),Planar64::from(2),Planar64::from(3)],
[Planar64::from(4),Planar64::from(5),Planar64::from(7)],
[Planar64::from(6),Planar64::from(8),Planar64::from(9)],
]);
// In[2]:= Det[{{1, 2, 3}, {4, 5, 7}, {6, 8, 9}}]
// Out[2]= 7
assert_eq!(m.wide_det_3x3_1(),fixed_wide::fixed::Fixed::<3,96>::from(7));
}
#[test]
fn wide_matrix_adjugate(){
let m=Matrix3::new([
[Planar64::from(1),Planar64::from(2),Planar64::from(3)],
[Planar64::from(4),Planar64::from(5),Planar64::from(7)],
[Planar64::from(6),Planar64::from(8),Planar64::from(9)],
]);
// In[6]:= Adjugate[{{1, 2, 3}, {4, 5, 7}, {6, 8, 9}}]
// Out[6]= {{-11, 6, -1}, {6, -9, 5}, {2, 4, -3}}
assert_eq!(
m.wide_adjugate_3x3_1().array,
Matrix3::new([
[Planar64Wide1::from(-11),Planar64Wide1::from(6),Planar64Wide1::from(-1)],
[Planar64Wide1::from(6),Planar64Wide1::from(-9),Planar64Wide1::from(5)],
[Planar64Wide1::from(2),Planar64Wide1::from(4),Planar64Wide1::from(-3)],
]).array
); );
} }

View File

@@ -1,5 +1,7 @@
mod tests; mod tests;
#[cfg(feature="named-fields")]
mod named;
#[cfg(feature="fixed_wide")] #[cfg(feature="fixed_wide")]
mod fixed_wide; mod fixed_wide;

View File

@@ -0,0 +1,30 @@
use crate::types::{Vector3,Matrix3};
#[test]
fn test_vector(){
let mut v=Vector3::new([1,2,3]);
assert_eq!(v.x,1);
assert_eq!(v.y,2);
assert_eq!(v.z,3);
v.x=5;
assert_eq!(v.x,5);
v.y*=v.x;
assert_eq!(v.y,10);
}
#[test]
fn test_matrix(){
let mut v=Matrix3::from_value(2);
assert_eq!(v.x_axis.x,2);
assert_eq!(v.y_axis.y,2);
assert_eq!(v.z_axis.z,2);
v.x_axis.x=5;
assert_eq!(v.x_axis.x,5);
v.y_axis.z*=v.x_axis.x;
assert_eq!(v.y_axis.z,10);
}

View File

@@ -1 +1,43 @@
use crate::types::{Vector3,Matrix4x3,Matrix2x4,Matrix2x3};
#[test]
fn test_bool(){
assert_eq!(Vector3::new([false,false,false]).any(),false);
assert_eq!(Vector3::new([false,false,true]).any(),true);
assert_eq!(Vector3::new([false,false,true]).all(),false);
assert_eq!(Vector3::new([true,true,true]).all(),true);
}
#[test]
fn test_arithmetic(){
let a=Vector3::new([1,2,3]);
assert_eq!((a+a*2).array,Vector3::new([1*3,2*3,3*3]).array);
}
#[test]
fn matrix_dot(){
let rhs=Matrix2x4::new([
[ 1.0, 2.0],
[ 3.0, 4.0],
[ 5.0, 6.0],
[ 7.0, 8.0],
]); // | | |
let lhs=Matrix4x3::new([ // | | |
[1.0, 2.0, 3.0, 4.0],// [ 50.0, 60.0],
[5.0, 6.0, 7.0, 8.0],// [114.0,140.0],
[9.0,10.0,11.0,12.0],// [178.0,220.0],
]);
// Mat3<Vec4>.dot(Mat4<Vec2>) -> Mat3<Vec2>
let m_dot=lhs.dot(rhs);
//In[1]:= {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}} . {{1, 2}, {3, 4}, {5, 6}, {7, 8}}
//Out[1]= {{50, 60}, {114, 140}, {178, 220}}
assert_eq!(
m_dot.array,
Matrix2x3::new([
[50.0,60.0],
[114.0,140.0],
[178.0,220.0],
]).array
);
}

View File

@@ -0,0 +1,18 @@
use crate::vector::Vector;
use crate::matrix::Matrix;
pub type Vector2<T>=Vector<2,T>;
pub type Vector3<T>=Vector<3,T>;
pub type Vector4<T>=Vector<4,T>;
pub type Matrix2<T>=Matrix<2,2,T>;
pub type Matrix2x3<T>=Matrix<2,3,T>;
pub type Matrix2x4<T>=Matrix<2,4,T>;
pub type Matrix3x2<T>=Matrix<3,2,T>;
pub type Matrix3<T>=Matrix<3,3,T>;
pub type Matrix3x4<T>=Matrix<3,4,T>;
pub type Matrix4x2<T>=Matrix<4,2,T>;
pub type Matrix4x3<T>=Matrix<4,3,T>;
pub type Matrix4<T>=Matrix<4,4,T>;

View File

@@ -1,81 +1,9 @@
// Stolen from https://github.com/c1m50c/fixed-vectors (MIT license) #[derive(Clone,Copy,Hash,Eq,PartialEq)]
pub struct Vector<const N:usize,T>{
/// Vector for holding two-dimensional values. pub(crate) array:[T;N],
///
/// # Example
///
/// ```
/// use fixed_wide_vectors::Vector2;
///
/// let mut vec2 = Vector2::new(1, 2);
/// vec2 += Vector2::new(1, 2);
///
/// assert_eq!(vec2.x, 2);
/// assert_eq!(vec2.y, 4);
/// ```
pub struct Vector2<T> {
pub x: T,
pub y: T,
} }
crate::impl_vector!();
/// Vector for holding three-dimensional values. //cross product
/// crate::impl_vector_3!();
/// # Example
///
/// ```
/// use fixed_wide_vectors::Vector3;
///
/// let mut vec3 = Vector3::new(1, 2, 3);
/// vec3 += Vector3::new(1, 2, 3);
///
/// assert_eq!(vec3.x, 2);
/// assert_eq!(vec3.y, 4);
/// assert_eq!(vec3.z, 6);
/// ```
pub struct Vector3<T> {
pub x: T,
pub y: T,
pub z: T,
}
/// Vector for holding four-dimensional values.
///
/// # Example
///
/// ```
/// use fixed_wide_vectors::Vector4;
///
/// let mut vec4 = Vector4::new(1, 2, 3, 4);
/// vec4 += Vector4::new(1, 2, 3, 4);
///
/// assert_eq!(vec4.x, 2);
/// assert_eq!(vec4.y, 4);
/// assert_eq!(vec4.z, 6);
/// assert_eq!(vec4.w, 8);
/// ```
pub struct Vector4<T> {
pub x: T,
pub y: T,
pub z: T,
pub w: T,
}
crate::impl_vector!(Vector2 { x, y }, 2);
crate::impl_vector!(Vector3 { x, y, z }, 3);
crate::impl_vector!(Vector4 { x, y, z, w }, 4);
crate::impl_extend!(Vector2 { x, y }, Vector3, z);
crate::impl_extend!(Vector3 { x, y, z }, Vector4, w);
crate::impl_matrix_inner!((Vector2 { x, y }, Vector2 { x, y }, 2), (Vector2 { x, y }, Vector2 { x, y }, 2) );
crate::impl_matrix_inner!((Vector2 { x, y }, Vector2 { x, y }, 2), (Vector3 { x, y, z }, Vector3 { x, y, z }, 3) );
crate::impl_matrix_inner!((Vector2 { x, y }, Vector2 { x, y }, 2), (Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4) );
crate::impl_matrix_inner!((Vector3 { x, y, z }, Vector3 { x, y, z }, 3), (Vector2 { x, y }, Vector2 { x, y }, 2) );
crate::impl_matrix_inner!((Vector3 { x, y, z }, Vector3 { x, y, z }, 3), (Vector3 { x, y, z }, Vector3 { x, y, z }, 3) );
crate::impl_matrix_inner!((Vector3 { x, y, z }, Vector3 { x, y, z }, 3), (Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4) );
crate::impl_matrix_inner!((Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4), (Vector2 { x, y }, Vector2 { x, y }, 2) );
crate::impl_matrix_inner!((Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4), (Vector3 { x, y, z }, Vector3 { x, y, z }, 3) );
crate::impl_matrix_inner!((Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4), (Vector4 { x, y, z, w }, Vector4 { x, y, z, w }, 4) );