1use std::ops::Mul;
2
3#[allow(non_camel_case_types)]
4pub type scalar = skia_bindings::SkScalar;
5
6// TODO: wrap more core/SkScalar.h functions / macros.
7
8pub 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
18pub trait Scalars {
19 fn are_finite(&self) -> bool;
20}
21
22impl 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
41impl<T> Scalars for [T]
42where
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
52pub fn radians_to_degrees(radians: scalar) -> scalar {
53 radians * (180.0 / std::f32::consts::PI)
54}
55