Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Offer both 0 centered and positive hue -> float conversion #26

Merged
merged 2 commits into from
Jan 29, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/hsl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ impl<T: Float> Mix for Hsl<T> {

fn mix(&self, other: &Hsl<T>, factor: T) -> Hsl<T> {
let factor = clamp(factor, T::zero(), T::one());
let hue_diff: T = (other.hue - self.hue).to_float();
let hue_diff: T = (other.hue - self.hue).to_degrees();

Hsl {
hue: self.hue + factor * hue_diff,
Expand Down
2 changes: 1 addition & 1 deletion src/hsv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ impl<T: Float> Mix for Hsv<T> {

fn mix(&self, other: &Hsv<T>, factor: T) -> Hsv<T> {
let factor = clamp(factor, T::zero(), T::one());
let hue_diff: T = (other.hue - self.hue).to_float();
let hue_diff: T = (other.hue - self.hue).to_degrees();

Hsv {
hue: self.hue + factor * hue_diff,
Expand Down
73 changes: 59 additions & 14 deletions src/hues.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ macro_rules! make_hues {
$(#[$doc])+
///
///The hue is a circular type, where `0` and `360` is the same, and
///it's normalized to `(-180, +180]` when it's converted to a linear
///it's normalized to `(-180, 180]` when it's converted to a linear
///number (like `f32`). This makes many calculations easier, but may
///also have some surprising effects if it's expected to act as a
///linear number.
Expand All @@ -22,14 +22,24 @@ macro_rules! make_hues {
$name(radians * T::from(180.0).unwrap() / T::from(PI).unwrap())
}

///Convert the hue to radians.
///Get the hue as degrees, in the range `(-180, 180]`.
pub fn to_degrees(self) -> T {
normalize_angle(self.0)
}

///Convert the hue to radians, in the range `(-π, π]`.
pub fn to_radians(self) -> T {
normalize_angle(self.0) * T::from(PI).unwrap() / T::from(180.0).unwrap()
}

///Returns the saved Hue value
pub fn to_float(self) -> T {
normalize_angle(self.0)
///Convert the hue to positive degrees, in the range `[0, 360)`.
pub fn to_positive_degrees(self) -> T {
normalize_angle_positive(self.0)
}

///Convert the hue to positive radians, in the range `[0, 2π)`.
pub fn to_positive_radians(self) -> T {
normalize_angle_positive(self.0) * T::from(PI).unwrap() / T::from(180.0).unwrap()
}
}

Expand All @@ -41,13 +51,13 @@ macro_rules! make_hues {

impl Into<f64> for $name<f64> {
fn into(self) -> f64 {
normalize_angle(self.0) as f64
normalize_angle(self.0)
}
}

impl Into<f32> for $name<f32> {
fn into(self) -> f32 {
normalize_angle(self.0) as f32
normalize_angle(self.0)
}
}
impl Into<f32> for $name<f64> {
Expand All @@ -58,15 +68,15 @@ macro_rules! make_hues {

impl<T:Float> PartialEq for $name<T> {
fn eq(&self, other: &$name<T>) -> bool {
let hue_s: T = (*self).to_float();
let hue_o: T = (*other).to_float();
let hue_s: T = (*self).to_degrees();
let hue_o: T = (*other).to_degrees();
hue_s.eq(&hue_o)
}
}

impl<T:Float> PartialEq<T> for $name<T> {
fn eq(&self, other: &T) -> bool {
let hue: T = (*self).to_float();
let hue: T = (*self).to_degrees();
hue.eq(&normalize_angle(*other))
}
}
Expand Down Expand Up @@ -121,13 +131,48 @@ make_hues! {
}

fn normalize_angle<T: Float>(mut deg: T) -> T {
while deg > T::from(180.0).unwrap() {
deg = deg - T::from(360.0).unwrap();
let c180 = T::from(180.0).unwrap();
let c360 = T::from(360.0).unwrap();
while deg > c180 {
deg = deg - c360;
}

while deg <= -c180 {
deg = deg + c360;
}

deg
}

fn normalize_angle_positive<T: Float>(mut deg: T) -> T {
let c360 = T::from(360.0).unwrap();
while deg >= c360 {
deg = deg - c360;
}

while deg <= -T::from(180.0).unwrap() {
deg = deg + T::from(360.0).unwrap();
while deg < T::zero() {
deg = deg + c360;
}

deg
}

#[cfg(test)]
mod test {
use RgbHue;

#[test]
fn float_conversion() {
for i in -180..180 {
let hue = RgbHue::from(4.0 * i as f32);

let degs = hue.to_degrees();
assert!(degs > -180.0 && degs <= 180.0);

let pos_degs = hue.to_positive_degrees();
assert!(pos_degs >= 0.0 && pos_degs < 360.0);

assert_eq!(RgbHue::from(degs), RgbHue::from(pos_degs));
}
}
}
2 changes: 1 addition & 1 deletion src/lch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ impl<T: Float> Mix for Lch<T> {

fn mix(&self, other: &Lch<T>, factor: T) -> Lch<T> {
let factor = clamp(factor, T::zero(), T::one());
let hue_diff: T = (other.hue - self.hue).to_float();
let hue_diff: T = (other.hue - self.hue).to_degrees();
Lch {
l: self.l + factor * (other.l - self.l),
chroma: self.chroma + factor * (other.chroma - self.chroma),
Expand Down
4 changes: 2 additions & 2 deletions src/rgb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ impl<T: Float> From<Lch<T>> for Rgb<T> {
impl<T: Float> From<Hsv<T>> for Rgb<T> {
fn from(hsv: Hsv<T>) -> Rgb<T> {
let c = hsv.value * hsv.saturation;
let h = ((hsv.hue.to_float() + T::from(360.0).unwrap()) % T::from(360.0).unwrap()) / T::from(60.0).unwrap();
let h = hsv.hue.to_positive_degrees() / T::from(60.0).unwrap();
let x = c * (T::one() - (h % T::from(2.0).unwrap() - T::one()).abs());
let m = hsv.value - c;

Expand Down Expand Up @@ -355,7 +355,7 @@ impl<T: Float> From<Hsv<T>> for Rgb<T> {
impl<T: Float> From<Hsl<T>> for Rgb<T> {
fn from(hsl: Hsl<T>) -> Rgb<T> {
let c = (T::one() - (T::from(2.0).unwrap() * hsl.lightness - T::one()).abs()) * hsl.saturation;
let h = ((hsl.hue.to_float() + T::from(360.0).unwrap()) % T::from(360.0).unwrap()) / T::from(60.0).unwrap();
let h = hsl.hue.to_positive_degrees() / T::from(60.0).unwrap();
let x = c * (T::one() - (h % T::from(2.0).unwrap() - T::one()).abs());
let m = hsl.lightness - T::from(0.5).unwrap() * c;

Expand Down