use color::{Color, RGBColor};
use colorpoint::ColorPoint;
use coord::Coord;
pub trait Bound: Color + ColorPoint {
fn bounds() -> [(f64, f64); 3];
fn clamp_coord(point: Coord) -> Coord {
let ranges = Self::bounds();
let mut point_vals = [0.; 3];
for i in 0..3 {
let component = [point.x, point.y, point.z][i];
let (min, max) = ranges[i];
point_vals[i] = if component < min {
min
} else if component > max {
max
} else {
component
};
}
Coord {
x: point_vals[0],
y: point_vals[1],
z: point_vals[2],
}
}
fn clamp<T: ColorPoint>(color: T) -> T {
let converted_color: Self = color.convert();
let point: Coord = converted_color.into();
Self::from(Self::clamp_coord(point)).convert()
}
}
impl Bound for RGBColor {
fn bounds() -> [(f64, f64); 3] {
[(0., 1.), (0., 1.), (0., 1.)]
}
}
#[cfg(test)]
mod tests {
use super::Bound;
use color::Color;
use color::RGBColor;
use colors::hslcolor::HSLColor;
use colors::hsvcolor::HSVColor;
#[test]
fn test_zero_one_bounds() {
let color1 = RGBColor {
r: 0.1,
g: -0.2,
b: 1.2,
};
assert!(
RGBColor::clamp(color1).visually_indistinguishable(&RGBColor {
r: 0.1,
g: 0.,
b: 1.,
},)
);
}
#[test]
fn test_hue_bounds() {
let color1 = HSLColor {
h: -24.0,
s: -0.2,
l: 1.1,
};
let color2 = HSVColor {
h: 375.0,
s: 0.2,
v: 0.5,
};
let color3 = HSVColor {
h: 255.0,
s: 0.6,
v: 0.7,
};
assert!(color3.visually_indistinguishable(&HSVColor::clamp(color3)));
assert!(
HSVColor::clamp(color2).visually_indistinguishable(&HSVColor {
h: 360.,
s: 0.2,
v: 0.5,
},)
);
assert!(
HSLColor::clamp(color1).visually_indistinguishable(&HSLColor {
h: 0.,
s: 0.,
l: 1.,
},)
);
}
}