palette/macros/
color_theory.rs

1macro_rules! impl_lab_color_schemes {
2    ($color_ty: ident $(<$phantom_ty: ident>)? [$a: ident, $b: ident] [$($other_component: ident),+]) => {
3        impl<$($phantom_ty,)? T> crate::color_theory::Complementary for $color_ty<$($phantom_ty,)? T>
4        where
5            T: core::ops::Neg<Output = T>,
6        {
7            fn complementary(self) -> Self {
8                Self {
9                    $a: -self.$a,
10                    $b: -self.$b,
11                    $($other_component: self.$other_component,)+
12                }
13            }
14        }
15
16        impl<$($phantom_ty,)? T, A> crate::color_theory::Complementary for crate::Alpha<$color_ty<$($phantom_ty,)? T>, A>
17        where
18            $color_ty<$($phantom_ty,)? T>: crate::color_theory::Complementary,
19        {
20            fn complementary(self) -> Self {
21                crate::Alpha {
22                    color: self.color.complementary(),
23                    alpha: self.alpha
24                }
25            }
26        }
27
28        impl<$($phantom_ty,)? T> crate::color_theory::Tetradic for $color_ty<$($phantom_ty,)? T>
29        where
30            T: core::ops::Neg<Output = T> + Clone,
31        {
32            fn tetradic(self) -> (Self, Self, Self) {
33                use crate::color_theory::Complementary;
34
35                let first = Self {
36                    $a: -self.$b.clone(),
37                    $b: self.$a.clone(),
38                    $($other_component: self.$other_component.clone(),)+
39                };
40
41                let second = self.clone().complementary();
42                let third = first.clone().complementary();
43
44                (first, second, third)
45            }
46        }
47
48        impl<$($phantom_ty,)? T, A> crate::color_theory::Tetradic for crate::Alpha<$color_ty<$($phantom_ty,)? T>, A>
49        where
50            $color_ty<$($phantom_ty,)? T>: crate::color_theory::Tetradic,
51            A: Clone,
52        {
53            fn tetradic(self) -> (Self, Self, Self) {
54                let (color1, color2, color3) = self.color.tetradic();
55
56                (
57                    crate::Alpha{
58                        color: color1,
59                        alpha: self.alpha.clone(),
60                    },
61                    crate::Alpha{
62                        color: color2,
63                        alpha: self.alpha.clone(),
64                    },
65                    crate::Alpha{
66                        color: color3,
67                        alpha: self.alpha,
68                    },
69                )
70            }
71        }
72    };
73    ($color_ty: ident $(<$phantom_ty:ident>)? [$($other_component: ident),+]) => {
74        impl_lab_color_schemes!($color_ty $(<$phantom_ty>)? [a, b] [$($other_component),+]);
75    };
76}
77
78#[cfg(test)]
79macro_rules! test_lab_color_schemes {
80    ($color_ty: ident / $radial_ty: ident [$a: ident, $b: ident] [$($other_component: ident),+]) => {
81        #[cfg(feature = "approx")]
82        #[test]
83        fn complementary() {
84            use crate::{color_theory::Complementary, convert::FromColorUnclamped};
85
86            let quadrant1: $color_ty = $color_ty::new(0.5f32, 0.1, 0.3);
87            let quadrant2: $color_ty = $color_ty::new(0.5f32, 0.1, -0.3);
88            let quadrant3: $color_ty = $color_ty::new(0.5f32, -0.1, -0.3);
89            let quadrant4: $color_ty = $color_ty::new(0.5f32, -0.1, 0.3);
90
91            let quadrant1_radial = $radial_ty::from_color_unclamped(quadrant1);
92            let quadrant2_radial = $radial_ty::from_color_unclamped(quadrant2);
93            let quadrant3_radial = $radial_ty::from_color_unclamped(quadrant3);
94            let quadrant4_radial = $radial_ty::from_color_unclamped(quadrant4);
95
96            assert_relative_eq!(quadrant1.complementary(), $color_ty::from_color_unclamped(quadrant1_radial.complementary()), epsilon = 0.000001);
97            assert_relative_eq!(quadrant2.complementary(), $color_ty::from_color_unclamped(quadrant2_radial.complementary()), epsilon = 0.000001);
98            assert_relative_eq!(quadrant3.complementary(), $color_ty::from_color_unclamped(quadrant3_radial.complementary()), epsilon = 0.000001);
99            assert_relative_eq!(quadrant4.complementary(), $color_ty::from_color_unclamped(quadrant4_radial.complementary()), epsilon = 0.000001);
100        }
101
102        #[cfg(feature = "approx")]
103        #[test]
104        fn tetradic() {
105            use crate::{color_theory::Tetradic, convert::FromColorUnclamped};
106            fn convert_tuple<T, U>(input: (T, T, T)) -> (U, U, U)
107            where
108                U: FromColorUnclamped<T>,
109            {
110                (
111                    U::from_color_unclamped(input.0),
112                    U::from_color_unclamped(input.1),
113                    U::from_color_unclamped(input.2),
114                )
115            }
116
117            fn check_tuples(a: ($color_ty, $color_ty, $color_ty), b: ($color_ty, $color_ty, $color_ty)) {
118                let (a1, a2, a3) = a;
119                let (b1, b2, b3) = b;
120
121                assert_relative_eq!(a1, b1, epsilon = 0.000001);
122                assert_relative_eq!(a2, b2, epsilon = 0.000001);
123                assert_relative_eq!(a3, b3, epsilon = 0.000001);
124            }
125
126            let quadrant1 = $color_ty::new(0.5f32, 0.1, 0.3);
127            let quadrant2 = $color_ty::new(0.5f32, 0.1, -0.3);
128            let quadrant3 = $color_ty::new(0.5f32, -0.1, -0.3);
129            let quadrant4 = $color_ty::new(0.5f32, -0.1, 0.3);
130
131            let quadrant1_radial = $radial_ty::from_color_unclamped(quadrant1);
132            let quadrant2_radial = $radial_ty::from_color_unclamped(quadrant2);
133            let quadrant3_radial = $radial_ty::from_color_unclamped(quadrant3);
134            let quadrant4_radial = $radial_ty::from_color_unclamped(quadrant4);
135
136            check_tuples(quadrant1.tetradic(), convert_tuple::<_, $color_ty>(quadrant1_radial.tetradic()));
137            check_tuples(quadrant2.tetradic(), convert_tuple::<_, $color_ty>(quadrant2_radial.tetradic()));
138            check_tuples(quadrant3.tetradic(), convert_tuple::<_, $color_ty>(quadrant3_radial.tetradic()));
139            check_tuples(quadrant4.tetradic(), convert_tuple::<_, $color_ty>(quadrant4_radial.tetradic()));
140        }
141    };
142    ($color_ty: ident / $radial_ty: ident [$($other_component: ident),+]) => {
143        test_lab_color_schemes!($color_ty / $radial_ty [a, b] [$($other_component),+]);
144    };
145}