Add Math.atan2 to the inbuilt math function

Math.atan2(y, x) -> angle
This commit is contained in:
Nigel Breslaw 2024-08-30 10:55:10 +03:00 committed by GitHub
parent 4d585279b0
commit 482308f5da
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 73 additions and 3 deletions

View file

@ -16,6 +16,10 @@ All notable changes to this project are documented in this file.
- Do not trigger `current-item-changed` on `StandardListView` if `current-item` is set on the same value.
- Fixed `TimePickerPopup` does not open minute view by click on selected hour.
### Slint Language
- Added math function `atan2`.
## [1.7.2] - 2024-08-14
### General

View file

@ -94,7 +94,7 @@ These functions are available both in the global scope and in the `Math` namespa
Return the absolute value, where T is a numeric type.
### `acos(float) -> angle`, `asin(float) -> angle`, `atan(float) -> angle`, `cos(angle) -> float`, `sin(angle) -> float`, `tan(angle) -> float`
### `acos(float) -> angle`, `asin(float) -> angle`, `atan(float) -> angle`, `atan2(float, float) -> angle`, `cos(angle) -> float`, `sin(angle) -> float`, `tan(angle) -> float`
The trigonometry function. Note that the should be typed with `deg` or `rad` unit
(for example `cos(90deg)` or `sin(slider.value * 1deg)`).

View file

@ -35,6 +35,7 @@ pub enum BuiltinFunction {
ACos,
ASin,
ATan,
ATan2,
Log,
Pow,
SetFocusItem,
@ -136,6 +137,10 @@ impl BuiltinFunction {
BuiltinFunction::ACos | BuiltinFunction::ASin | BuiltinFunction::ATan => {
Type::Function { return_type: Box::new(Type::Angle), args: vec![Type::Float32] }
}
BuiltinFunction::ATan2 => Type::Function {
return_type: Box::new(Type::Angle),
args: vec![Type::Float32, Type::Float32],
},
BuiltinFunction::Log | BuiltinFunction::Pow => Type::Function {
return_type: Box::new(Type::Float32),
args: vec![Type::Float32, Type::Float32],
@ -342,7 +347,8 @@ impl BuiltinFunction {
| BuiltinFunction::ASin
| BuiltinFunction::Log
| BuiltinFunction::Pow
| BuiltinFunction::ATan => true,
| BuiltinFunction::ATan
| BuiltinFunction::ATan2 => true,
BuiltinFunction::SetFocusItem | BuiltinFunction::ClearFocusItem => false,
BuiltinFunction::ShowPopupWindow | BuiltinFunction::ClosePopupWindow => false,
BuiltinFunction::SetSelectionOffsets => false,
@ -407,7 +413,8 @@ impl BuiltinFunction {
| BuiltinFunction::ASin
| BuiltinFunction::Log
| BuiltinFunction::Pow
| BuiltinFunction::ATan => true,
| BuiltinFunction::ATan
| BuiltinFunction::ATan2 => true,
BuiltinFunction::SetFocusItem | BuiltinFunction::ClearFocusItem => false,
BuiltinFunction::ShowPopupWindow | BuiltinFunction::ClosePopupWindow => false,
BuiltinFunction::SetSelectionOffsets => false,

View file

@ -3351,6 +3351,10 @@ fn compile_builtin_function_call(
ctx.generator_state.conditional_includes.cmath.set(true);
format!("std::atan({}) / {}", a.next().unwrap(), pi_180)
}
BuiltinFunction::ATan2 => {
ctx.generator_state.conditional_includes.cmath.set(true);
format!("std::atan2({}, {}) / {}", a.next().unwrap(), a.next().unwrap(), pi_180)
}
BuiltinFunction::SetFocusItem => {
if let [llr::Expression::PropertyReference(pr)] = arguments {
let window = access_window_field(ctx);

View file

@ -2725,6 +2725,10 @@ fn compile_builtin_function_call(
BuiltinFunction::ASin => quote!((#(#a)* as f64).asin().to_degrees()),
BuiltinFunction::ACos => quote!((#(#a)* as f64).acos().to_degrees()),
BuiltinFunction::ATan => quote!((#(#a)* as f64).atan().to_degrees()),
BuiltinFunction::ATan2 => {
let (a1, a2) = (a.next().unwrap(), a.next().unwrap());
quote!((#a1 as f64).atan2(#a2 as f64).to_degrees())
}
BuiltinFunction::Log => {
let (a1, a2) = (a.next().unwrap(), a.next().unwrap());
quote!((#a1 as f64).log(#a2 as f64))

View file

@ -92,6 +92,7 @@ fn builtin_function_cost(function: &BuiltinFunction) -> isize {
BuiltinFunction::ACos => 10,
BuiltinFunction::ASin => 10,
BuiltinFunction::ATan => 10,
BuiltinFunction::ATan2 => 10,
BuiltinFunction::Log => 10,
BuiltinFunction::Pow => 10,
BuiltinFunction::SetFocusItem | BuiltinFunction::ClearFocusItem => isize::MAX,

View file

@ -802,6 +802,7 @@ impl LookupObject for MathFunctions {
.or_else(|| f("asin", BuiltinFunctionReference(BuiltinFunction::ASin, sl())))
.or_else(|| f("acos", BuiltinFunctionReference(BuiltinFunction::ACos, sl())))
.or_else(|| f("atan", BuiltinFunctionReference(BuiltinFunction::ATan, sl())))
.or_else(|| f("atan2", BuiltinFunctionReference(BuiltinFunction::ATan2, sl())))
.or_else(|| f("log", BuiltinFunctionReference(BuiltinFunction::Log, sl())))
.or_else(|| f("pow", BuiltinFunctionReference(BuiltinFunction::Pow, sl())))
}

View file

@ -479,6 +479,11 @@ fn call_builtin_function(
let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
Value::Number(x.atan().to_degrees())
}
BuiltinFunction::ATan2 => {
let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
let y: f64 = eval_expression(&arguments[1], local_context).try_into().unwrap();
Value::Number(x.atan2(y).to_degrees())
}
BuiltinFunction::Log => {
let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
let y: f64 = eval_expression(&arguments[1], local_context).try_into().unwrap();

View file

@ -0,0 +1,35 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
TestCase := Rectangle {
property<angle> t1: atan2(0, 0);
property<angle> t2: atan2(10, 10);
property<angle> t3: atan2(10, -10);
property<angle> t4: atan2(-10, 10);
}
/*
```cpp
auto handle = TestCase::create();
const TestCase &instance = *handle;
assert(std::abs(instance.get_t1()) < 0.0001);
assert(std::abs(instance.get_t2() - 45.0) < 0.0001);
assert(std::abs(instance.get_t3() - 135.0) < 0.0001);
assert(std::abs(instance.get_t4() - -45.0) < 0.0001);
```
```rust
let instance = TestCase::new().unwrap();
assert!(instance.get_t1().abs() < 0.0001);
assert!((instance.get_t2() - 45.0).abs() < 0.0001);
assert!((instance.get_t3() - 135.0).abs() < 0.0001);
assert!((instance.get_t4() - -45.0).abs() < 0.0001);
```
```js
var instance = new slint.TestCase({});
assert.equal(instance.t1, 0);
assert.equal(instance.t2, 45);
assert.equal(instance.t3, 135);
assert.equal(instance.t4, -45);
```
*/

View file

@ -11,6 +11,15 @@
round(atan(tan(45deg))/0.1deg) == 450 &&
round(asin(sin(45deg))/0.1deg) == 450 &&
round(acos(cos(45deg))/0.1deg) == 450 &&
atan2(0, 0) == 0 &&
atan2(0, 10) == 0deg &&
atan2(10, 10) == 45deg &&
atan2(10, 0) == 90deg &&
atan2(10, -10) == 135deg &&
atan2(0, -10) == 180deg &&
atan2(-10, -10) == -135deg &&
atan2(-10, 0) == -90deg &&
atan2(-10, 10) == -45deg &&
true;
property <bool> test: verify;
}