1 | use std::ops::Mul; |
2 | |
3 | #[allow (non_camel_case_types)] |
4 | pub type scalar = skia_bindings::SkScalar; |
5 | |
6 | // TODO: wrap more core/SkScalar.h functions / macros. |
7 | |
8 | pub trait Scalar: Copy { |
9 | const ZERO: Self; |
10 | const NEARLY_ZERO: Self; |
11 | const ONE: Self; |
12 | const HALF: Self; |
13 | |
14 | fn nearly_equal(x: scalar, y: scalar, tolerance: impl Into<Option<scalar>>) -> bool; |
15 | fn nearly_zero(&self, tolerance: impl Into<Option<scalar>>) -> bool; |
16 | } |
17 | |
18 | pub trait Scalars { |
19 | fn are_finite(&self) -> bool; |
20 | } |
21 | |
22 | impl Scalar for scalar { |
23 | const ZERO: Self = 0.0; |
24 | const NEARLY_ZERO: Self = 1.0 / ((1 << 12) as Self); |
25 | const ONE: Self = 1.0; |
26 | const HALF: Self = 0.5; |
27 | |
28 | fn nearly_equal(x: scalar, y: scalar, tolerance: impl Into<Option<scalar>>) -> bool { |
29 | let tolerance: f32 = tolerance.into().unwrap_or(Self::NEARLY_ZERO); |
30 | debug_assert!(tolerance >= 0.0); |
31 | (x - y).abs() <= tolerance |
32 | } |
33 | |
34 | fn nearly_zero(&self, tolerance: impl Into<Option<scalar>>) -> bool { |
35 | let tolerance: f32 = tolerance.into().unwrap_or(Self::NEARLY_ZERO); |
36 | debug_assert!(tolerance >= 0.0); |
37 | self.abs() <= tolerance |
38 | } |
39 | } |
40 | |
41 | impl<T> Scalars for [T] |
42 | where |
43 | T: Scalar, |
44 | T: Mul<Output = T>, |
45 | T: PartialEq, |
46 | { |
47 | fn are_finite(&self) -> bool { |
48 | self.iter().fold(T::ZERO, |prod: T, value: &T| prod * *value) == T::ZERO |
49 | } |
50 | } |
51 | |
52 | pub fn radians_to_degrees(radians: scalar) -> scalar { |
53 | radians * (180.0 / std::f32::consts::PI) |
54 | } |
55 | |