| 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 | |