distance.rs (4234B)
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 //! Machinery to compute distances between animatable values. 6 7 use crate::derives::*; 8 use app_units::Au; 9 use euclid::default::Size2D; 10 use std::iter::Sum; 11 use std::ops::Add; 12 13 /// A trait to compute squared distances between two animatable values. 14 /// 15 /// This trait is derivable with `#[derive(ComputeSquaredDistance)]`. The derived 16 /// implementation uses a `match` expression with identical patterns for both 17 /// `self` and `other`, calling `ComputeSquaredDistance::compute_squared_distance` 18 /// on each fields of the values. 19 /// 20 /// If a variant is annotated with `#[animation(error)]`, the corresponding 21 /// `match` arm returns an error. 22 /// 23 /// Trait bounds for type parameter `Foo` can be opted out of with 24 /// `#[animation(no_bound(Foo))]` on the type definition, trait bounds for 25 /// fields can be opted into with `#[distance(field_bound)]` on the field. 26 pub trait ComputeSquaredDistance { 27 /// Computes the squared distance between two animatable values. 28 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()>; 29 } 30 31 /// A distance between two animatable values. 32 #[derive(Add, Clone, Copy, Debug, From, PartialEq, PartialOrd)] 33 pub struct SquaredDistance { 34 value: f64, 35 } 36 37 impl SquaredDistance { 38 /// Returns a squared distance from its square root. 39 #[inline] 40 pub fn from_sqrt(sqrt: f64) -> Self { 41 Self { value: sqrt * sqrt } 42 } 43 } 44 45 impl ComputeSquaredDistance for u16 { 46 #[inline] 47 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { 48 Ok(SquaredDistance::from_sqrt( 49 ((*self as f64) - (*other as f64)).abs(), 50 )) 51 } 52 } 53 54 impl ComputeSquaredDistance for i16 { 55 #[inline] 56 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { 57 Ok(SquaredDistance::from_sqrt((*self - *other).abs() as f64)) 58 } 59 } 60 61 impl ComputeSquaredDistance for i32 { 62 #[inline] 63 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { 64 Ok(SquaredDistance::from_sqrt((*self - *other).abs() as f64)) 65 } 66 } 67 68 impl ComputeSquaredDistance for f32 { 69 #[inline] 70 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { 71 Ok(SquaredDistance::from_sqrt((*self - *other).abs() as f64)) 72 } 73 } 74 75 impl ComputeSquaredDistance for f64 { 76 #[inline] 77 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { 78 Ok(SquaredDistance::from_sqrt((*self - *other).abs())) 79 } 80 } 81 82 impl ComputeSquaredDistance for Au { 83 #[inline] 84 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { 85 self.0.compute_squared_distance(&other.0) 86 } 87 } 88 89 impl<T> ComputeSquaredDistance for Box<T> 90 where 91 T: ComputeSquaredDistance, 92 { 93 #[inline] 94 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { 95 (**self).compute_squared_distance(&**other) 96 } 97 } 98 99 impl<T> ComputeSquaredDistance for Option<T> 100 where 101 T: ComputeSquaredDistance, 102 { 103 #[inline] 104 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { 105 match (self.as_ref(), other.as_ref()) { 106 (Some(this), Some(other)) => this.compute_squared_distance(other), 107 (None, None) => Ok(SquaredDistance::from_sqrt(0.)), 108 _ => Err(()), 109 } 110 } 111 } 112 113 impl<T> ComputeSquaredDistance for Size2D<T> 114 where 115 T: ComputeSquaredDistance, 116 { 117 #[inline] 118 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { 119 Ok(self.width.compute_squared_distance(&other.width)? 120 + self.height.compute_squared_distance(&other.height)?) 121 } 122 } 123 124 impl SquaredDistance { 125 /// Returns the square root of this squared distance. 126 #[inline] 127 pub fn sqrt(self) -> f64 { 128 self.value.sqrt() 129 } 130 } 131 132 impl Sum for SquaredDistance { 133 fn sum<I>(iter: I) -> Self 134 where 135 I: Iterator<Item = Self>, 136 { 137 iter.fold(SquaredDistance::from_sqrt(0.), Add::add) 138 } 139 }