angle.rs (2706B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 4 5 //! Computed angles. 6 7 use crate::derives::*; 8 use crate::values::distance::{ComputeSquaredDistance, SquaredDistance}; 9 use crate::values::CSSFloat; 10 use crate::Zero; 11 use std::f64::consts::PI; 12 use std::fmt::{self, Write}; 13 use std::ops::Neg; 14 use std::{f32, f64}; 15 use style_traits::{CssWriter, ToCss}; 16 17 /// A computed angle in degrees. 18 #[derive( 19 Add, 20 Animate, 21 Clone, 22 Copy, 23 Debug, 24 Deserialize, 25 MallocSizeOf, 26 PartialEq, 27 PartialOrd, 28 Serialize, 29 ToAnimatedZero, 30 ToResolvedValue, 31 )] 32 #[repr(C)] 33 pub struct Angle(CSSFloat); 34 35 impl ToCss for Angle { 36 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result 37 where 38 W: Write, 39 { 40 self.degrees().to_css(dest)?; 41 dest.write_str("deg") 42 } 43 } 44 45 const RAD_PER_DEG: f64 = PI / 180.0; 46 47 impl Angle { 48 /// Creates a computed `Angle` value from a radian amount. 49 pub fn from_radians(radians: CSSFloat) -> Self { 50 Angle(radians / RAD_PER_DEG as f32) 51 } 52 53 /// Creates a computed `Angle` value from a degrees amount. 54 #[inline] 55 pub fn from_degrees(degrees: CSSFloat) -> Self { 56 Angle(degrees) 57 } 58 59 /// Returns the amount of radians this angle represents. 60 #[inline] 61 pub fn radians(&self) -> CSSFloat { 62 self.radians64().min(f32::MAX as f64).max(f32::MIN as f64) as f32 63 } 64 65 /// Returns the amount of radians this angle represents as a `f64`. 66 /// 67 /// Gecko stores angles as singles, but does this computation using doubles. 68 /// 69 /// This is significant enough to mess up rounding to the nearest 70 /// quarter-turn for 225 degrees, for example. 71 #[inline] 72 pub fn radians64(&self) -> f64 { 73 self.0 as f64 * RAD_PER_DEG 74 } 75 76 /// Return the value in degrees. 77 #[inline] 78 pub fn degrees(&self) -> CSSFloat { 79 self.0 80 } 81 } 82 83 impl Zero for Angle { 84 #[inline] 85 fn zero() -> Self { 86 Angle(0.0) 87 } 88 89 #[inline] 90 fn is_zero(&self) -> bool { 91 self.0 == 0. 92 } 93 } 94 95 impl ComputeSquaredDistance for Angle { 96 #[inline] 97 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { 98 // Use the formula for calculating the distance between angles defined in SVG: 99 // https://www.w3.org/TR/SVG/animate.html#complexDistances 100 self.radians64() 101 .compute_squared_distance(&other.radians64()) 102 } 103 } 104 105 impl Neg for Angle { 106 type Output = Angle; 107 108 #[inline] 109 fn neg(self) -> Angle { 110 Angle(-self.0) 111 } 112 }