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}