mech_math/trig/
atan2.rs

1use crate::*;
2use mech_core::*;
3use libm::{atan2,atan2f};
4use num_traits::*;
5#[cfg(feature = "matrix")]
6use mech_core::matrix::Matrix;
7
8// Atan2 ------------------------------------------------------------------------
9
10macro_rules! atan2_op {
11  ($arg1:expr, $arg2:expr, $out:expr) => {
12    unsafe{(*$out) = atan2((*$arg1),(*$arg2));}
13  };}
14
15macro_rules! atan2_vec_op {
16  ($arg1:expr, $arg2:expr, $out:expr) => {
17    unsafe {
18      let arg1_deref = &(*$arg1);
19      let arg2_deref = &(*$arg2);
20      let mut out_deref = (&mut *$out);
21      for i in 0..arg1_deref.len() {
22        (out_deref[i]) = atan2(arg1_deref[i],arg2_deref[i]);
23      }}};}
24
25macro_rules! atan2f_op {
26  ($arg1:expr, $arg2:expr, $out:expr) => {
27    unsafe{(*$out) = atan2f((*$arg1),(*$arg2));}
28  };}
29
30macro_rules! atan2f_vec_op {
31  ($arg1:expr, $arg2:expr, $out:expr) => {
32    unsafe {
33      let arg1_deref = &(*$arg1);
34      let arg2_deref = &(*$arg2);
35      let mut out_deref = (&mut *$out);
36      for i in 0..arg1_deref.len() {
37        (out_deref[i]) = atan2f(arg1_deref[i],arg2_deref[i]);
38      }}};}
39
40macro_rules! impl_two_arg_fxn {
41  ($struct_name:ident, $kind1:ty, $kind2:ty, $out_kind:ty, $op:ident) => {
42    #[derive(Debug)]
43    struct $struct_name {
44      arg1: Ref<$kind1>,
45      arg2: Ref<$kind2>,
46      out: Ref<$out_kind>,
47    }
48    impl MechFunctionFactory for $struct_name {
49      fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
50        match args {
51          FunctionArgs::Binary(out, arg1, arg2) => {
52            let arg1: Ref<$kind1> = unsafe{ arg1.as_unchecked().clone() };
53            let arg2: Ref<$kind2> = unsafe{ arg2.as_unchecked().clone() };
54            let out: Ref<$out_kind> = unsafe{ out.as_unchecked().clone() };
55            Ok(Box::new($struct_name {arg1, arg2, out}))
56          },
57          _ => Err(MechError2::new(
58              IncorrectNumberOfArguments { expected: 2, found: args.len() }, 
59              None
60            ).with_compiler_loc()
61          ),
62        }
63      }
64    }
65    impl MechFunctionImpl for $struct_name {
66      fn solve(&self) {
67        let arg1_ptr = self.arg1.as_ptr();
68        let arg2_ptr = self.arg2.as_ptr();
69        let out_ptr = self.out.as_mut_ptr();
70        $op!(arg1_ptr,arg2_ptr,out_ptr);
71      }
72      fn out(&self) -> Value { self.out.to_value() }
73      fn to_string(&self) -> String { format!("{:#?}", self) }
74    }
75    #[cfg(feature = "compiler")]
76    impl MechFunctionCompiler for $struct_name {
77      fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
78        let mut registers = [0,0,0];
79  
80        registers[0] = compile_register_brrw!(self.out,  ctx);
81        registers[1] = compile_register_brrw!(self.arg1, ctx);
82        registers[2] = compile_register_brrw!(self.arg2, ctx);
83
84        ctx.features.insert(FeatureFlag::Custom(hash_str("math/atan2")));
85
86        ctx.emit_binop(
87          hash_str(stringify!($struct_name)),
88          registers[0],
89          registers[1],
90          registers[2],
91        );
92
93        return Ok(registers[0])
94      }
95    }
96    register_descriptor!{
97      FunctionDescriptor {
98        name: stringify!($struct_name),
99        ptr: $struct_name::new,
100      }
101    }
102  };}
103
104macro_rules! impl_atan2 {
105  ($type:tt, $type_string:tt, $op:ident, $($struct_name:ident, $kind:ty, $feature:literal);* $(;)?) => {
106    paste!{
107      $(
108        #[cfg(all(feature = $type_string, feature = $feature))]
109        impl_two_arg_fxn!([<$struct_name $type:camel>], $kind<$type>, $kind<$type>, $kind<$type>, $op);
110      )*
111    }
112  };
113}
114
115impl_atan2!(
116  f64, "f64", atan2_vec_op,
117  Atan2M1, Matrix1, "matrix1";
118  Atan2M2, Matrix2, "matrix2";
119  Atan2M3, Matrix3, "matrix3";
120  Atan2M2x3, Matrix2x3, "matrix2x3";
121  Atan2M3x2, Matrix3x2, "matrix3";
122  Atan2M4, Matrix4, "matrix4";
123  Atan2V2, Vector2, "vector2";
124  Atan2V3, Vector3, "vector3";
125  Atan2V4, Vector4, "vector4";
126  Atan2R2, RowVector2, "row_vector2";
127  Atan2R3, RowVector3, "row_vector3";
128  Atan2R4, RowVector4, "row_vector4";
129  Atan2RD, RowDVector, "row_vectord";
130  Atan2VD, DVector, "vectord";
131  Atan2MD, DMatrix, "matrixd";
132);
133
134impl_atan2!(
135  f32, "f32", atan2f_vec_op,
136  Atan2M1, Matrix1, "matrix1";
137  Atan2M2, Matrix2, "matrix2";
138  Atan2M3, Matrix3, "matrix3";
139  Atan2M2x3, Matrix2x3, "matrix2x3";
140  Atan2M3x2, Matrix3x2, "matrix3";
141  Atan2M4, Matrix4, "matrix4";
142  Atan2V2, Vector2, "vector2";
143  Atan2V3, Vector3, "vector3";
144  Atan2V4, Vector4, "vector4";
145  Atan2R2, RowVector2, "row_vector2";
146  Atan2R3, RowVector3, "row_vector3";
147  Atan2R4, RowVector4, "row_vector4";
148  Atan2RD, RowDVector, "row_vectord";
149  Atan2VD, DVector, "vectord";
150  Atan2MD, DMatrix, "matrixd";
151);
152
153#[cfg(feature = "f32")]
154impl_two_arg_fxn!(Atan2F32, f32, f32, f32, atan2f_op);
155
156#[cfg(feature = "f64")]
157impl_two_arg_fxn!(Atan2F64, f64, f64, f64, atan2_op);
158
159#[macro_export]
160macro_rules! impl_binop_atan2 {
161  ($fxn:ident, $arg1:expr, $arg2:expr, $($t:ident, $zero_fn:expr, $feat:tt);+ $(;)?) => {
162    paste! {
163      match ($arg1, $arg2) {
164        $(
165          // Scalar
166          #[cfg(feature = $feat)]
167          (Value::$t(arg1), Value::$t(arg2)) => Ok(Box::new([<$fxn $t>]{arg1, arg2, out: Ref::new($zero_fn)})),
168
169          // Fixed matrices
170          #[cfg(all(feature = "matrix1", feature = $feat))]
171          (Value::[<Matrix $t>](Matrix::Matrix1(arg1)), Value::[<Matrix $t>](Matrix::Matrix1(arg2))) =>
172            Ok(Box::new([<$fxn M1 $t>]{arg1, arg2, out: Ref::new(Matrix1::from_element($zero_fn))})),
173          #[cfg(all(feature = "matrix2", feature = $feat))]
174          (Value::[<Matrix $t>](Matrix::Matrix2(arg1)), Value::[<Matrix $t>](Matrix::Matrix2(arg2))) =>
175            Ok(Box::new([<$fxn M2 $t>]{arg1, arg2, out: Ref::new(Matrix2::from_element($zero_fn))})),
176          #[cfg(all(feature = "matrix3", feature = $feat))]
177          (Value::[<Matrix $t>](Matrix::Matrix3(arg1)), Value::[<Matrix $t>](Matrix::Matrix3(arg2))) =>
178            Ok(Box::new([<$fxn M3 $t>]{arg1, arg2, out: Ref::new(Matrix3::from_element($zero_fn))})),
179          #[cfg(all(feature = "matrix4", feature = $feat))]
180          (Value::[<Matrix $t>](Matrix::Matrix4(arg1)), Value::[<Matrix $t>](Matrix::Matrix4(arg2))) =>
181            Ok(Box::new([<$fxn M4 $t>]{arg1, arg2, out: Ref::new(Matrix4::from_element($zero_fn))})),
182
183          // Fixed vectors
184          #[cfg(all(feature = "vector2", feature = $feat))]
185          (Value::[<Matrix $t>](Matrix::Vector2(arg1)), Value::[<Matrix $t>](Matrix::Vector2(arg2))) =>
186            Ok(Box::new([<$fxn V2 $t>]{arg1, arg2, out: Ref::new(Vector2::from_element($zero_fn))})),
187          #[cfg(all(feature = "vector3", feature = $feat))]
188          (Value::[<Matrix $t>](Matrix::Vector3(arg1)), Value::[<Matrix $t>](Matrix::Vector3(arg2))) =>
189            Ok(Box::new([<$fxn V3 $t>]{arg1, arg2, out: Ref::new(Vector3::from_element($zero_fn))})),
190          #[cfg(all(feature = "vector4", feature = $feat))]
191          (Value::[<Matrix $t>](Matrix::Vector4(arg1)), Value::[<Matrix $t>](Matrix::Vector4(arg2))) =>
192            Ok(Box::new([<$fxn V4 $t>]{arg1, arg2, out: Ref::new(Vector4::from_element($zero_fn))})),
193
194          // Fixed row vectors
195          #[cfg(all(feature = "row_vector2", feature = $feat))]
196          (Value::[<Matrix $t>](Matrix::RowVector2(arg1)), Value::[<Matrix $t>](Matrix::RowVector2(arg2))) =>
197            Ok(Box::new([<$fxn R2 $t>]{arg1, arg2, out: Ref::new(RowVector2::from_element($zero_fn))})),
198          #[cfg(all(feature = "row_vector3", feature = $feat))]
199          (Value::[<Matrix $t>](Matrix::RowVector3(arg1)), Value::[<Matrix $t>](Matrix::RowVector3(arg2))) =>
200            Ok(Box::new([<$fxn R3 $t>]{arg1, arg2, out: Ref::new(RowVector3::from_element($zero_fn))})),
201          #[cfg(all(feature = "row_vector4", feature = $feat))]
202          (Value::[<Matrix $t>](Matrix::RowVector4(arg1)), Value::[<Matrix $t>](Matrix::RowVector4(arg2))) =>
203            Ok(Box::new([<$fxn R4 $t>]{arg1, arg2, out: Ref::new(RowVector4::from_element($zero_fn))})),
204
205          // Dynamic vectors
206          #[cfg(all(feature = "vectord", feature = $feat))]
207          (Value::[<Matrix $t>](Matrix::DVector(arg1)), Value::[<Matrix $t>](Matrix::DVector(arg2))) =>
208            Ok(Box::new([<$fxn VD $t>]{arg1: arg1.clone(), arg2, out: Ref::new(DVector::from_element(arg1.borrow().nrows(), $zero_fn))})),
209          #[cfg(all(feature = "row_vectord", feature = $feat))]
210          (Value::[<Matrix $t>](Matrix::RowDVector(arg1)), Value::[<Matrix $t>](Matrix::RowDVector(arg2))) =>
211            Ok(Box::new([<$fxn RD $t>]{arg1: arg1.clone(), arg2, out: Ref::new(RowDVector::from_element(arg1.borrow().ncols(), $zero_fn))})),
212
213          // Dynamic matrices
214          #[cfg(all(feature = "matrixd", feature = $feat))]
215          (Value::[<Matrix $t>](Matrix::DMatrix(arg1)), Value::[<Matrix $t>](Matrix::DMatrix(arg2))) => {
216            let rows = arg1.borrow().nrows();
217            let cols = arg1.borrow().ncols();
218            Ok(Box::new([<$fxn MD $t>]{arg1, arg2, out: Ref::new(DMatrix::from_element(rows, cols, $zero_fn))}))
219          },
220        )+
221        (arg1,arg2) => Err(MechError2::new(
222            UnhandledFunctionArgumentKind2 { arg: (arg1.kind(),arg2.kind()), fxn_name: stringify!($fxn).to_string() },
223            None
224          ).with_compiler_loc()
225        ),
226      }
227    }
228  }
229}
230
231pub fn impl_atan2_fxn(arg1_value: Value, arg2_value: Value) -> MResult<Box<dyn MechFunction>> {
232  impl_binop_atan2!(Atan2, arg1_value, arg2_value,
233    F32, f32::default(), "f32";
234    F64, f64::default(), "f64";
235  )
236}
237
238pub struct MathAtan2 {}
239
240impl NativeFunctionCompiler for MathAtan2 {
241  fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
242    if arguments.len() != 2 {
243      return Err(MechError2::new(IncorrectNumberOfArguments { expected: 1, found: arguments.len() },None).with_compiler_loc());
244    }
245    let arg1 = arguments[0].clone();
246    let arg2 = arguments[1].clone();
247    match impl_atan2_fxn(arg1.clone(), arg2.clone()) {
248      Ok(fxn) => Ok(fxn),
249      Err(_) => {
250        match (arg1,arg2) {
251          (Value::MutableReference(arg1),Value::MutableReference(arg2)) => {impl_atan2_fxn(arg1.borrow().clone(),arg2.borrow().clone())}
252          (Value::MutableReference(arg1),arg2) => {impl_atan2_fxn(arg1.borrow().clone(),arg2.clone())}
253          (arg1,Value::MutableReference(arg2)) => {impl_atan2_fxn(arg1.clone(),arg2.borrow().clone())}
254          (arg1,arg2) => Err(MechError2::new(
255              UnhandledFunctionArgumentKind2 { arg: (arg1.kind(),arg2.kind()), fxn_name: "math/atan2".to_string() },
256              None
257            ).with_compiler_loc()
258          ),
259        }
260      }
261    }
262  }
263}
264
265register_descriptor! {
266  FunctionCompilerDescriptor {
267    name: "math/atan2",
268    ptr: &MathAtan2{},
269  }
270}