1use crate::*;
2use mech_core::*;
3use libm::{atan2,atan2f};
4use num_traits::*;
5#[cfg(feature = "matrix")]
6use mech_core::matrix::Matrix;
7
8macro_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 #[cfg(feature = $feat)]
167 (Value::$t(arg1), Value::$t(arg2)) => Ok(Box::new([<$fxn $t>]{arg1, arg2, out: Ref::new($zero_fn)})),
168
169 #[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 #[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 #[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 #[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 #[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}