From 739bb76a542922ea2e571525c9ee1e4ada477a0b Mon Sep 17 00:00:00 2001 From: Erik Hedvall Date: Fri, 1 Jan 2021 16:16:08 +0100 Subject: [PATCH] Add uniformity tests for random colors and fix mistakes --- palette/Cargo.toml | 7 +- palette/src/alpha/alpha.rs | 12 +++ palette/src/hsl.rs | 51 ++++++++++- palette/src/hsv.rs | 17 +++- palette/src/hues.rs | 52 ++++++++---- palette/src/hwb.rs | 54 +++++++++--- palette/src/lab.rs | 17 +++- palette/src/lch.rs | 17 +++- palette/src/luma/luma.rs | 15 +++- palette/src/macros.rs | 132 +++++++++++++++++++++++++++++ palette/src/random_sampling/mod.rs | 78 +++++++++++++++++ palette/src/rgb/rgb.rs | 17 +++- palette/src/xyz.rs | 21 ++++- palette/src/yxy.rs | 17 +++- 14 files changed, 453 insertions(+), 54 deletions(-) diff --git a/palette/Cargo.toml b/palette/Cargo.toml index 3981bf7ca..1392b8c8f 100644 --- a/palette/Cargo.toml +++ b/palette/Cargo.toml @@ -38,7 +38,7 @@ version = "0.8" optional = true [dependencies.rand] -version = "0.7" +version = "0.8" default-features = false optional = true @@ -67,6 +67,11 @@ version = "0.23" default-features = false features = ["png"] +[dev-dependencies.rand_mt] +version = "4" +default-features = false +features = ["rand-traits"] + [build-dependencies.phf_codegen] version = "0.8" optional = true diff --git a/palette/src/alpha/alpha.rs b/palette/src/alpha/alpha.rs index 006e38a0f..ce7a9bb4e 100644 --- a/palette/src/alpha/alpha.rs +++ b/palette/src/alpha/alpha.rs @@ -678,4 +678,16 @@ mod test { assert_eq!(deserialized, Rgba::::new(0.3, 0.8, 0.1, 0.5)); } + + #[cfg(feature = "random")] + test_uniform_distribution! { + Rgba { + red: (0.0, 1.0), + green: (0.0, 1.0), + blue: (0.0, 1.0), + alpha: (0.0, 1.0) + }, + min: Rgba::new(0.0f32, 0.0, 0.0, 0.0), + max: Rgba::new(1.0, 1.0, 1.0, 1.0) + } } diff --git a/palette/src/hsl.rs b/palette/src/hsl.rs index 52e3da22e..017941b81 100644 --- a/palette/src/hsl.rs +++ b/palette/src/hsl.rs @@ -682,7 +682,7 @@ where pub struct UniformHsl where T: FloatComponent + SampleUniform, - S: RgbStandard + SampleUniform, + S: RgbStandard, { hue: crate::hues::UniformRgbHue, u1: Uniform, @@ -694,7 +694,7 @@ where impl SampleUniform for Hsl where T: FloatComponent + SampleUniform, - S: RgbStandard + SampleUniform, + S: RgbStandard, { type Sampler = UniformHsl; } @@ -703,7 +703,7 @@ where impl UniformSampler for UniformHsl where T: FloatComponent + SampleUniform, - S: RgbStandard + SampleUniform, + S: RgbStandard, { type X = Hsl; @@ -860,4 +860,49 @@ mod test { assert_eq!(deserialized, Hsl::new(0.3, 0.8, 0.1)); } + + #[cfg(feature = "random")] + test_uniform_distribution! { + Hsl as crate::rgb::Rgb { + red: (0.0, 1.0), + green: (0.0, 1.0), + blue: (0.0, 1.0) + }, + min: Hsl::new(0.0f32, 0.0, 0.0), + max: Hsl::new(360.0, 1.0, 1.0) + } + + /// Sanity check to make sure the test doesn't start accepting known + /// non-uniform distributions. + #[cfg(feature = "random")] + #[test] + #[should_panic(expected = "is not uniform enough")] + fn uniform_distribution_fail() { + use rand::Rng; + + const BINS: usize = crate::random_sampling::test_utils::BINS; + const SAMPLES: usize = crate::random_sampling::test_utils::SAMPLES; + + let mut red = [0; BINS]; + let mut green = [0; BINS]; + let mut blue = [0; BINS]; + + let mut rng = rand_mt::Mt::new(1234); // We want the same seed on every run to avoid random fails + + for _ in 0..SAMPLES { + let color = Hsl::::new( + rng.gen::() * 360.0, + rng.gen(), + rng.gen(), + ); + let color: crate::rgb::Rgb = crate::IntoColor::into_color(color); + red[((color.red * BINS as f32) as usize).min(9)] += 1; + green[((color.green * BINS as f32) as usize).min(9)] += 1; + blue[((color.blue * BINS as f32) as usize).min(9)] += 1; + } + + assert_uniform_distribution!(red); + assert_uniform_distribution!(green); + assert_uniform_distribution!(blue); + } } diff --git a/palette/src/hsv.rs b/palette/src/hsv.rs index 39965150f..e54ec223e 100644 --- a/palette/src/hsv.rs +++ b/palette/src/hsv.rs @@ -689,7 +689,7 @@ where pub struct UniformHsv where T: FloatComponent + SampleUniform, - S: RgbStandard + SampleUniform, + S: RgbStandard, { hue: crate::hues::UniformRgbHue, u1: Uniform, @@ -701,7 +701,7 @@ where impl SampleUniform for Hsv where T: FloatComponent + SampleUniform, - S: RgbStandard + SampleUniform, + S: RgbStandard, { type Sampler = UniformHsv; } @@ -710,7 +710,7 @@ where impl UniformSampler for UniformHsv where T: FloatComponent + SampleUniform, - S: RgbStandard + SampleUniform, + S: RgbStandard, { type X = Hsv; @@ -872,4 +872,15 @@ mod test { assert_eq!(deserialized, Hsv::new(0.3, 0.8, 0.1)); } + + #[cfg(feature = "random")] + test_uniform_distribution! { + Hsv as crate::rgb::Rgb { + red: (0.0, 1.0), + green: (0.0, 1.0), + blue: (0.0, 1.0) + }, + min: Hsv::new(0.0f32, 0.0, 0.0), + max: Hsv::new(360.0, 1.0, 1.0) + } } diff --git a/palette/src/hues.rs b/palette/src/hues.rs index dc2ba3cce..c116e5767 100644 --- a/palette/src/hues.rs +++ b/palette/src/hues.rs @@ -317,13 +317,18 @@ where B2: SampleBorrow + Sized, { let low = *low_b.borrow(); + let normalized_low = LabHue::to_positive_degrees(low); let high = *high_b.borrow(); + let normalized_high = LabHue::to_positive_degrees(high); + + let normalized_high = if normalized_low >= normalized_high && low.0 < high.0 { + normalized_high + from_f64(360.0) + } else { + normalized_high + }; UniformLabHue { - hue: Uniform::new( - LabHue::to_positive_degrees(low), - LabHue::to_positive_degrees(high), - ), + hue: Uniform::new(normalized_low, normalized_high), } } @@ -333,13 +338,18 @@ where B2: SampleBorrow + Sized, { let low = *low_b.borrow(); + let normalized_low = LabHue::to_positive_degrees(low); let high = *high_b.borrow(); + let normalized_high = LabHue::to_positive_degrees(high); + + let normalized_high = if normalized_low >= normalized_high && low.0 < high.0 { + normalized_high + from_f64(360.0) + } else { + normalized_high + }; UniformLabHue { - hue: Uniform::new_inclusive( - LabHue::to_positive_degrees(low), - LabHue::to_positive_degrees(high), - ), + hue: Uniform::new_inclusive(normalized_low, normalized_high), } } @@ -377,13 +387,18 @@ where B2: SampleBorrow + Sized, { let low = *low_b.borrow(); + let normalized_low = RgbHue::to_positive_degrees(low); let high = *high_b.borrow(); + let normalized_high = RgbHue::to_positive_degrees(high); + + let normalized_high = if normalized_low >= normalized_high && low.0 < high.0 { + normalized_high + from_f64(360.0) + } else { + normalized_high + }; UniformRgbHue { - hue: Uniform::new( - RgbHue::to_positive_degrees(low), - RgbHue::to_positive_degrees(high), - ), + hue: Uniform::new(normalized_low, normalized_high), } } @@ -393,13 +408,18 @@ where B2: SampleBorrow + Sized, { let low = *low_b.borrow(); + let normalized_low = RgbHue::to_positive_degrees(low); let high = *high_b.borrow(); + let normalized_high = RgbHue::to_positive_degrees(high); + + let normalized_high = if normalized_low >= normalized_high && low.0 < high.0 { + normalized_high + from_f64(360.0) + } else { + normalized_high + }; UniformRgbHue { - hue: Uniform::new_inclusive( - RgbHue::to_positive_degrees(low), - RgbHue::to_positive_degrees(high), - ), + hue: Uniform::new_inclusive(normalized_low, normalized_high), } } diff --git a/palette/src/hwb.rs b/palette/src/hwb.rs index 64f3605a7..6ff3c41e5 100644 --- a/palette/src/hwb.rs +++ b/palette/src/hwb.rs @@ -641,7 +641,7 @@ where pub struct UniformHwb where T: FloatComponent + SampleUniform, - S: RgbStandard + SampleUniform, + S: RgbStandard, { sampler: crate::hsv::UniformHsv, space: PhantomData, @@ -651,7 +651,7 @@ where impl SampleUniform for Hwb where T: FloatComponent + SampleUniform, - S: RgbStandard + SampleUniform, + S: RgbStandard, { type Sampler = UniformHwb; } @@ -660,7 +660,7 @@ where impl UniformSampler for UniformHwb where T: FloatComponent + SampleUniform, - S: RgbStandard + SampleUniform, + S: RgbStandard, { type X = Hwb; @@ -669,12 +669,20 @@ where B1: SampleBorrow + Sized, B2: SampleBorrow + Sized, { - let low = *low_b.borrow(); - let high = *high_b.borrow(); - let sampler = crate::hsv::UniformHsv::::new( - Hsv::from_color_unclamped(low), - Hsv::from_color_unclamped(high), + let low_input = Hsv::from_color_unclamped(*low_b.borrow()); + let high_input = Hsv::from_color_unclamped(*high_b.borrow()); + + let low = Hsv::with_wp( + low_input.hue, + low_input.saturation.min(high_input.saturation), + low_input.value.min(high_input.value), + ); + let high = Hsv::with_wp( + high_input.hue, + low_input.saturation.max(high_input.saturation), + low_input.value.max(high_input.value), ); + let sampler = crate::hsv::UniformHsv::::new(low, high); UniformHwb { sampler, @@ -687,13 +695,22 @@ where B1: SampleBorrow + Sized, B2: SampleBorrow + Sized, { - let low = *low_b.borrow(); - let high = *high_b.borrow(); - let sampler = crate::hsv::UniformHsv::::new_inclusive( - Hsv::from_color_unclamped(low), - Hsv::from_color_unclamped(high), + let low_input = Hsv::from_color_unclamped(*low_b.borrow()); + let high_input = Hsv::from_color_unclamped(*high_b.borrow()); + + let low = Hsv::with_wp( + low_input.hue, + low_input.saturation.min(high_input.saturation), + low_input.value.min(high_input.value), + ); + let high = Hsv::with_wp( + high_input.hue, + low_input.saturation.max(high_input.saturation), + low_input.value.max(high_input.value), ); + let sampler = crate::hsv::UniformHsv::::new_inclusive(low, high); + UniformHwb { sampler, space: PhantomData, @@ -808,4 +825,15 @@ mod test { assert_eq!(deserialized, Hwb::new(0.3, 0.8, 0.1)); } + + #[cfg(feature = "random")] + test_uniform_distribution! { + Hwb as crate::rgb::Rgb { + red: (0.0, 1.0), + green: (0.0, 1.0), + blue: (0.0, 1.0) + }, + min: Hwb::new(0.0f32, 0.0, 0.0), + max: Hwb::new(360.0, 1.0, 1.0) + } } diff --git a/palette/src/lab.rs b/palette/src/lab.rs index c587757b0..f047083ab 100644 --- a/palette/src/lab.rs +++ b/palette/src/lab.rs @@ -713,7 +713,7 @@ where pub struct UniformLab where T: FloatComponent + SampleUniform, - Wp: WhitePoint + SampleUniform, + Wp: WhitePoint, { l: Uniform, a: Uniform, @@ -725,7 +725,7 @@ where impl SampleUniform for Lab where T: FloatComponent + SampleUniform, - Wp: WhitePoint + SampleUniform, + Wp: WhitePoint, { type Sampler = UniformLab; } @@ -734,7 +734,7 @@ where impl UniformSampler for UniformLab where T: FloatComponent + SampleUniform, - Wp: WhitePoint + SampleUniform, + Wp: WhitePoint, { type X = Lab; @@ -849,4 +849,15 @@ mod test { assert_eq!(deserialized, Lab::new(0.3, 0.8, 0.1)); } + + #[cfg(feature = "random")] + test_uniform_distribution! { + Lab { + l: (0.0, 100.0), + a: (-128.0, 127.0), + b: (-128.0, 127.0) + }, + min: Lab::new(0.0f32, -128.0, -128.0), + max: Lab::new(100.0, 127.0, 127.0) + } } diff --git a/palette/src/lch.rs b/palette/src/lch.rs index 541c60468..11ee491e3 100644 --- a/palette/src/lch.rs +++ b/palette/src/lch.rs @@ -601,7 +601,7 @@ where pub struct UniformLch where T: FloatComponent + SampleUniform, - Wp: WhitePoint + SampleUniform, + Wp: WhitePoint, { l: Uniform, chroma: Uniform, @@ -613,7 +613,7 @@ where impl SampleUniform for Lch where T: FloatComponent + SampleUniform, - Wp: WhitePoint + SampleUniform, + Wp: WhitePoint, { type Sampler = UniformLch; } @@ -622,7 +622,7 @@ where impl UniformSampler for UniformLch where T: FloatComponent + SampleUniform, - Wp: WhitePoint + SampleUniform, + Wp: WhitePoint, { type X = Lch; @@ -720,4 +720,15 @@ mod test { assert_eq!(deserialized, Lch::new(0.3, 0.8, 0.1)); } + + #[cfg(feature = "random")] + test_uniform_distribution! { + Lch as crate::Lab { + l: (0.0, 100.0), + a: (-89.0, 89.0), + b: (-89.0, 89.0), + }, + min: Lch::new(0.0f32, 0.0, 0.0), + max: Lch::new(100.0, 128.0, 360.0) + } } diff --git a/palette/src/luma/luma.rs b/palette/src/luma/luma.rs index 5c32f260e..c78fe7bb5 100644 --- a/palette/src/luma/luma.rs +++ b/palette/src/luma/luma.rs @@ -783,7 +783,7 @@ where pub struct UniformLuma where T: Component + SampleUniform, - S: LumaStandard + SampleUniform, + S: LumaStandard, { luma: Uniform, standard: PhantomData, @@ -793,7 +793,7 @@ where impl SampleUniform for Luma where T: Component + SampleUniform, - S: LumaStandard + SampleUniform, + S: LumaStandard, { type Sampler = UniformLuma; } @@ -802,7 +802,7 @@ where impl UniformSampler for UniformLuma where T: Component + SampleUniform, - S: LumaStandard + SampleUniform, + S: LumaStandard, { type X = Luma; @@ -930,4 +930,13 @@ mod test { assert_eq!(deserialized, Luma::::new(0.3)); } + + #[cfg(feature = "random")] + test_uniform_distribution! { + Luma { + luma: (0.0, 1.0) + }, + min: Luma::new(0.0f32), + max: Luma::new(1.0) + } } diff --git a/palette/src/macros.rs b/palette/src/macros.rs index 5c40836dd..a97b877da 100644 --- a/palette/src/macros.rs +++ b/palette/src/macros.rs @@ -124,3 +124,135 @@ macro_rules! raw_pixel_conversion_fail_tests { let _: $name<$($ty_param,)+ $float> = *$name::from_raw(raw); }; } + +#[cfg(all(test, feature = "random"))] +macro_rules! assert_uniform_distribution { + ($bins:expr) => {{ + let bins = &$bins; + + for (i, &bin) in bins.iter().enumerate() { + if bin < 5 { + panic!("{}[{}] < 5: {:?}", stringify!($bins), i, bins); + } + } + const P_LIMIT: f64 = 0.01; // Keeping it low to account for the RNG noise + let p_value = crate::random_sampling::test_utils::uniform_distribution_test(bins); + if p_value < P_LIMIT { + panic!( + "distribution of {} is not uniform enough (p-value {} < {}): {:?}", + stringify!($bins), + p_value, + P_LIMIT, + bins + ); + } + }}; +} + +#[cfg(all(test, feature = "random"))] +macro_rules! test_uniform_distribution { + ( + $ty:path $(as $base_ty:path)? { + $($component:ident: ($component_min:expr, $component_max:expr)),+$(,)? + }, + min: $min:expr, + max: $max:expr$(,)? + ) => { + #[cfg(feature = "random")] + #[test] + fn uniform_distribution_rng_gen() { + use rand::Rng; + + const BINS: usize = crate::random_sampling::test_utils::BINS; + const SAMPLES: usize = crate::random_sampling::test_utils::SAMPLES; + + $(let mut $component = [0; BINS];)+ + + let mut rng = rand_mt::Mt::new(1234); // We want the same seed on every run to avoid random fails + + for _ in 0..SAMPLES { + let color: $ty = rng.gen(); + $(let color: $base_ty = crate::convert::IntoColorUnclamped::into_color_unclamped(color);)? + + if $(color.$component < $component_min || color.$component > $component_max)||+ { + continue; + } + + $({ + let min = $component_min; + let range = $component_max - min; + let normalized = (color.$component - min) / range; + $component[((normalized * BINS as f32) as usize).min(BINS - 1)] += 1; + })+ + } + + $(assert_uniform_distribution!($component);)+ + } + + #[cfg(feature = "random")] + #[test] + fn uniform_distribution_uniform_sample() { + use rand::distributions::uniform::Uniform; + use rand::Rng; + + const BINS: usize = crate::random_sampling::test_utils::BINS; + const SAMPLES: usize = crate::random_sampling::test_utils::SAMPLES; + + $(let mut $component = [0; BINS];)+ + + let mut rng = rand_mt::Mt::new(1234); // We want the same seed on every run to avoid random fails + let uniform_sampler = Uniform::new($min, $max); + + for _ in 0..SAMPLES { + let color: $ty = rng.sample(&uniform_sampler); + $(let color: $base_ty = crate::convert::IntoColorUnclamped::into_color_unclamped(color);)? + + if $(color.$component < $component_min || color.$component > $component_max)||+ { + continue; + } + + $({ + let min = $component_min; + let range = $component_max - min; + let normalized = (color.$component - min) / range; + $component[((normalized * BINS as f32) as usize).min(BINS - 1)] += 1; + })+ + } + + $(assert_uniform_distribution!($component);)+ + } + + #[cfg(feature = "random")] + #[test] + fn uniform_distribution_uniform_sample_inclusive() { + use rand::distributions::uniform::Uniform; + use rand::Rng; + + const BINS: usize = crate::random_sampling::test_utils::BINS; + const SAMPLES: usize = crate::random_sampling::test_utils::SAMPLES; + + $(let mut $component = [0; BINS];)+ + + let mut rng = rand_mt::Mt::new(1234); // We want the same seed on every run to avoid random fails + let uniform_sampler = Uniform::new_inclusive($min, $max); + + for _ in 0..SAMPLES { + let color: $ty = rng.sample(&uniform_sampler); + $(let color: $base_ty = crate::convert::IntoColorUnclamped::into_color_unclamped(color);)? + + if $(color.$component < $component_min || color.$component > $component_max)||+ { + continue; + } + + $({ + let min = $component_min; + let range = $component_max - min; + let normalized = (color.$component - min) / range; + $component[((normalized * BINS as f32) as usize).min(BINS - 1)] += 1; + })+ + } + + $(assert_uniform_distribution!($component);)+ + } + }; +} diff --git a/palette/src/random_sampling/mod.rs b/palette/src/random_sampling/mod.rs index 61f0e2b12..7d5f3c02e 100644 --- a/palette/src/random_sampling/mod.rs +++ b/palette/src/random_sampling/mod.rs @@ -1,3 +1,81 @@ mod cone; pub use self::cone::*; + +#[cfg(test)] +pub(crate) mod test_utils { + pub(crate) const BINS: usize = 10; + pub(crate) const SAMPLES: usize = 20_000; + + /// Perform a Chi-squared goodness-of-fit test to check if the bins are + /// uniformly distributed. Returns the p-value. + pub(crate) fn uniform_distribution_test(bins: &[usize]) -> f64 { + let sum = bins.iter().sum::() as f64; + let expected = sum / bins.len() as f64; + let critical_value = bins + .iter() + .map(|&bin| { + let difference = bin as f64 - expected; + difference * difference / expected + }) + .sum::(); + + chi_square(bins.len() - 1, critical_value) + } + + // Shamelessly taken from https://www.codeproject.com/Articles/432194/How-to-Calculate-the-Chi-Squared-P-Value + fn chi_square(dof: usize, critical_value: f64) -> f64 { + if critical_value < 0.0 || dof < 1 { + return 0.0; + } + let k = dof as f64 * 0.5; + let x = critical_value * 0.5; + if dof == 2 { + return (-x).exp(); + } + + let mut p_value = incomplete_gamma_function(k, x); + if p_value.is_nan() || p_value.is_infinite() || p_value <= 1e-8 { + return 1e-14; + } + + p_value /= approximate_gamma(k); + + 1.0 - p_value + } + + fn incomplete_gamma_function(mut s: f64, z: f64) -> f64 { + if z < 0.0 { + return 0.0; + } + let mut sc = 1.0 / s; + sc *= z.powf(s); + sc *= (-z).exp(); + + let mut sum = 1.0; + let mut nom = 1.0; + let mut denom = 1.0; + + for _ in 0..200 { + nom *= z; + s += 1.0; + denom *= s; + sum += nom / denom; + } + + sum * sc + } + + fn approximate_gamma(z: f64) -> f64 { + const RECIP_E: f64 = 0.36787944117144232159552377016147; // RECIP_E = (E^-1) = (1.0 / E) + const TWOPI: f64 = core::f64::consts::TAU; + + let mut d = 1.0 / (10.0 * z); + d = 1.0 / ((12.0 * z) - d); + d = (d + z) * RECIP_E; + d = d.powf(z); + d *= (TWOPI / z).sqrt(); + + d + } +} diff --git a/palette/src/rgb/rgb.rs b/palette/src/rgb/rgb.rs index 9ea8134d7..ead922041 100644 --- a/palette/src/rgb/rgb.rs +++ b/palette/src/rgb/rgb.rs @@ -1119,7 +1119,7 @@ where pub struct UniformRgb where T: Component + SampleUniform, - S: RgbStandard + SampleUniform, + S: RgbStandard, { red: Uniform, green: Uniform, @@ -1131,7 +1131,7 @@ where impl SampleUniform for Rgb where T: Component + SampleUniform, - S: RgbStandard + SampleUniform, + S: RgbStandard, { type Sampler = UniformRgb; } @@ -1140,7 +1140,7 @@ where impl UniformSampler for UniformRgb where T: Component + SampleUniform, - S: RgbStandard + SampleUniform, + S: RgbStandard, { type X = Rgb; @@ -1397,4 +1397,15 @@ mod test { assert_relative_eq!(Rgb::::max_green(), 1.0); assert_relative_eq!(Rgb::::max_blue(), 1.0); } + + #[cfg(feature = "random")] + test_uniform_distribution! { + Rgb { + red: (0.0, 1.0), + green: (0.0, 1.0), + blue: (0.0, 1.0) + }, + min: Rgb::new(0.0f32, 0.0, 0.0), + max: Rgb::new(1.0, 1.0, 1.0) + } } diff --git a/palette/src/xyz.rs b/palette/src/xyz.rs index eecf67918..854499484 100644 --- a/palette/src/xyz.rs +++ b/palette/src/xyz.rs @@ -689,7 +689,7 @@ where pub struct UniformXyz where T: FloatComponent + SampleUniform, - Wp: WhitePoint + SampleUniform, + Wp: WhitePoint, { x: Uniform, y: Uniform, @@ -701,7 +701,7 @@ where impl SampleUniform for Xyz where T: FloatComponent + SampleUniform, - Wp: WhitePoint + SampleUniform, + Wp: WhitePoint, { type Sampler = UniformXyz; } @@ -710,7 +710,7 @@ where impl UniformSampler for UniformXyz where T: FloatComponent + SampleUniform, - Wp: WhitePoint + SampleUniform, + Wp: WhitePoint, { type X = Xyz; @@ -761,6 +761,10 @@ mod test { use super::Xyz; use crate::white_point::D65; use crate::{FromColor, LinLuma, LinSrgb}; + + #[cfg(feature = "random")] + use crate::white_point::WhitePoint; + const X_N: f64 = 0.95047; const Y_N: f64 = 1.0; const Z_N: f64 = 1.08883; @@ -835,4 +839,15 @@ mod test { assert_eq!(deserialized, Xyz::new(0.3, 0.8, 0.1)); } + + #[cfg(feature = "random")] + test_uniform_distribution! { + Xyz { + x: (0.0, D65::get_xyz::().x), + y: (0.0, D65::get_xyz::().y), + z: (0.0, D65::get_xyz::().z) + }, + min: Xyz::new(0.0f32, 0.0, 0.0), + max: D65::get_xyz::() + } } diff --git a/palette/src/yxy.rs b/palette/src/yxy.rs index 6563eaefc..357b5a262 100644 --- a/palette/src/yxy.rs +++ b/palette/src/yxy.rs @@ -650,7 +650,7 @@ where pub struct UniformYxy where T: FloatComponent + SampleUniform, - Wp: WhitePoint + SampleUniform, + Wp: WhitePoint, { x: Uniform, y: Uniform, @@ -662,7 +662,7 @@ where impl SampleUniform for Yxy where T: FloatComponent + SampleUniform, - Wp: WhitePoint + SampleUniform, + Wp: WhitePoint, { type Sampler = UniformYxy; } @@ -671,7 +671,7 @@ where impl UniformSampler for UniformYxy where T: FloatComponent + SampleUniform, - Wp: WhitePoint + SampleUniform, + Wp: WhitePoint, { type X = Yxy; @@ -793,4 +793,15 @@ mod test { assert_eq!(deserialized, Yxy::new(0.3, 0.8, 0.1)); } + + #[cfg(feature = "random")] + test_uniform_distribution! { + Yxy { + x: (0.0, 1.0), + y: (0.0, 1.0), + luma: (0.0, 1.0) + }, + min: Yxy::new(0.0f32, 0.0, 0.0), + max: Yxy::new(1.0, 1.0, 1.0), + } }