1 //! A 2D size. 2 3 use std::fmt; 4 use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; 5 6 use crate::common::FloatExt; 7 use crate::{Rect, RoundedRect, Vec2}; 8 9 /// A 2D size. 10 #[derive(Clone, Copy, Default, PartialEq)] 11 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 12 pub struct Size { 13 /// The width. 14 pub width: f64, 15 /// The height. 16 pub height: f64, 17 } 18 19 impl Size { 20 /// A size with zero width or height. 21 pub const ZERO: Size = Size::new(0., 0.); 22 23 /// Create a new `Size` with the provided `width` and `height`. 24 #[inline] new(width: f64, height: f64) -> Self25 pub const fn new(width: f64, height: f64) -> Self { 26 Size { width, height } 27 } 28 29 /// Returns the max of `width` and `height`. 30 /// 31 /// # Examples 32 /// 33 /// ``` 34 /// use kurbo::Size; 35 /// let size = Size::new(-10.5, 42.0); 36 /// assert_eq!(size.max_side(), 42.0); 37 /// ``` max_side(self) -> f6438 pub fn max_side(self) -> f64 { 39 self.width.max(self.height) 40 } 41 42 /// Returns the min of `width` and `height`. 43 /// 44 /// # Examples 45 /// 46 /// ``` 47 /// use kurbo::Size; 48 /// let size = Size::new(-10.5, 42.0); 49 /// assert_eq!(size.min_side(), -10.5); 50 /// ``` min_side(self) -> f6451 pub fn min_side(self) -> f64 { 52 self.width.min(self.height) 53 } 54 55 /// Returns a new size bounded by `min` and `max.` 56 /// 57 /// # Examples 58 /// 59 /// ``` 60 /// use kurbo::Size; 61 /// 62 /// let this = Size::new(0., 100.); 63 /// let min = Size::new(10., 10.,); 64 /// let max = Size::new(50., 50.); 65 /// assert_eq!(this.clamp(min, max), Size::new(10., 50.)) 66 /// ``` clamp(self, min: Size, max: Size) -> Self67 pub fn clamp(self, min: Size, max: Size) -> Self { 68 let width = self.width.max(min.width).min(max.width); 69 let height = self.height.max(min.height).min(max.height); 70 Size { width, height } 71 } 72 73 /// Convert this size into a [`Vec2`], with `width` mapped to `x` and `height` 74 /// mapped to `y`. 75 /// 76 /// [`Vec2`]: struct.Vec2.html 77 #[inline] to_vec2(self) -> Vec278 pub const fn to_vec2(self) -> Vec2 { 79 Vec2::new(self.width, self.height) 80 } 81 82 /// Returns a new `Size`, 83 /// with `width` and `height` rounded to the nearest integer. 84 /// 85 /// # Examples 86 /// 87 /// ``` 88 /// use kurbo::Size; 89 /// let size_pos = Size::new(3.3, 3.6).round(); 90 /// assert_eq!(size_pos.width, 3.0); 91 /// assert_eq!(size_pos.height, 4.0); 92 /// let size_neg = Size::new(-3.3, -3.6).round(); 93 /// assert_eq!(size_neg.width, -3.0); 94 /// assert_eq!(size_neg.height, -4.0); 95 /// ``` 96 #[inline] round(self) -> Size97 pub fn round(self) -> Size { 98 Size::new(self.width.round(), self.height.round()) 99 } 100 101 /// Returns a new `Size`, 102 /// with `width` and `height` rounded up to the nearest integer, 103 /// unless they are already an integer. 104 /// 105 /// # Examples 106 /// 107 /// ``` 108 /// use kurbo::Size; 109 /// let size_pos = Size::new(3.3, 3.6).ceil(); 110 /// assert_eq!(size_pos.width, 4.0); 111 /// assert_eq!(size_pos.height, 4.0); 112 /// let size_neg = Size::new(-3.3, -3.6).ceil(); 113 /// assert_eq!(size_neg.width, -3.0); 114 /// assert_eq!(size_neg.height, -3.0); 115 /// ``` 116 #[inline] ceil(self) -> Size117 pub fn ceil(self) -> Size { 118 Size::new(self.width.ceil(), self.height.ceil()) 119 } 120 121 /// Returns a new `Size`, 122 /// with `width` and `height` rounded down to the nearest integer, 123 /// unless they are already an integer. 124 /// 125 /// # Examples 126 /// 127 /// ``` 128 /// use kurbo::Size; 129 /// let size_pos = Size::new(3.3, 3.6).floor(); 130 /// assert_eq!(size_pos.width, 3.0); 131 /// assert_eq!(size_pos.height, 3.0); 132 /// let size_neg = Size::new(-3.3, -3.6).floor(); 133 /// assert_eq!(size_neg.width, -4.0); 134 /// assert_eq!(size_neg.height, -4.0); 135 /// ``` 136 #[inline] floor(self) -> Size137 pub fn floor(self) -> Size { 138 Size::new(self.width.floor(), self.height.floor()) 139 } 140 141 /// Returns a new `Size`, 142 /// with `width` and `height` rounded away from zero to the nearest integer, 143 /// unless they are already an integer. 144 /// 145 /// # Examples 146 /// 147 /// ``` 148 /// use kurbo::Size; 149 /// let size_pos = Size::new(3.3, 3.6).expand(); 150 /// assert_eq!(size_pos.width, 4.0); 151 /// assert_eq!(size_pos.height, 4.0); 152 /// let size_neg = Size::new(-3.3, -3.6).expand(); 153 /// assert_eq!(size_neg.width, -4.0); 154 /// assert_eq!(size_neg.height, -4.0); 155 /// ``` 156 #[inline] expand(self) -> Size157 pub fn expand(self) -> Size { 158 Size::new(self.width.expand(), self.height.expand()) 159 } 160 161 /// Returns a new `Size`, 162 /// with `width` and `height` rounded down towards zero the nearest integer, 163 /// unless they are already an integer. 164 /// 165 /// # Examples 166 /// 167 /// ``` 168 /// use kurbo::Size; 169 /// let size_pos = Size::new(3.3, 3.6).trunc(); 170 /// assert_eq!(size_pos.width, 3.0); 171 /// assert_eq!(size_pos.height, 3.0); 172 /// let size_neg = Size::new(-3.3, -3.6).trunc(); 173 /// assert_eq!(size_neg.width, -3.0); 174 /// assert_eq!(size_neg.height, -3.0); 175 /// ``` 176 #[inline] trunc(self) -> Size177 pub fn trunc(self) -> Size { 178 Size::new(self.width.trunc(), self.height.trunc()) 179 } 180 181 /// Convert this `Size` into a [`Rect`] with origin `(0.0, 0.0)`. 182 /// 183 /// [`Rect`]: struct.Rect.html 184 #[inline] to_rect(self) -> Rect185 pub const fn to_rect(self) -> Rect { 186 Rect::new(0., 0., self.width, self.height) 187 } 188 189 /// Convert this `Size` into a [`RoundedRect`] with origin `(0.0, 0.0)` and 190 /// the provided corner radius. 191 /// 192 /// [`RoundedRect`]: struct.RoundedRect.html 193 #[inline] to_rounded_rect(self, radius: f64) -> RoundedRect194 pub fn to_rounded_rect(self, radius: f64) -> RoundedRect { 195 self.to_rect().to_rounded_rect(radius) 196 } 197 } 198 199 impl fmt::Debug for Size { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result200 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 201 write!(f, "{:?}W×{:?}H", self.width, self.height) 202 } 203 } 204 205 impl fmt::Display for Size { fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result206 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 207 write!(formatter, "(")?; 208 fmt::Display::fmt(&self.width, formatter)?; 209 write!(formatter, "×")?; 210 fmt::Display::fmt(&self.height, formatter)?; 211 write!(formatter, ")") 212 } 213 } 214 215 impl MulAssign<f64> for Size { 216 #[inline] mul_assign(&mut self, other: f64)217 fn mul_assign(&mut self, other: f64) { 218 *self = Size { 219 width: self.width * other, 220 height: self.height * other, 221 }; 222 } 223 } 224 225 impl Mul<Size> for f64 { 226 type Output = Size; 227 228 #[inline] mul(self, other: Size) -> Size229 fn mul(self, other: Size) -> Size { 230 other * self 231 } 232 } 233 234 impl Mul<f64> for Size { 235 type Output = Size; 236 237 #[inline] mul(self, other: f64) -> Size238 fn mul(self, other: f64) -> Size { 239 Size { 240 width: self.width * other, 241 height: self.height * other, 242 } 243 } 244 } 245 246 impl DivAssign<f64> for Size { 247 #[inline] div_assign(&mut self, other: f64)248 fn div_assign(&mut self, other: f64) { 249 *self = Size { 250 width: self.width / other, 251 height: self.height / other, 252 }; 253 } 254 } 255 256 impl Div<f64> for Size { 257 type Output = Size; 258 259 #[inline] div(self, other: f64) -> Size260 fn div(self, other: f64) -> Size { 261 Size { 262 width: self.width / other, 263 height: self.height / other, 264 } 265 } 266 } 267 268 impl Add<Size> for Size { 269 type Output = Size; 270 #[inline] add(self, other: Size) -> Size271 fn add(self, other: Size) -> Size { 272 Size { 273 width: self.width + other.width, 274 height: self.height + other.height, 275 } 276 } 277 } 278 279 impl AddAssign<Size> for Size { 280 #[inline] add_assign(&mut self, other: Size)281 fn add_assign(&mut self, other: Size) { 282 *self = *self + other; 283 } 284 } 285 286 impl Sub<Size> for Size { 287 type Output = Size; 288 #[inline] sub(self, other: Size) -> Size289 fn sub(self, other: Size) -> Size { 290 Size { 291 width: self.width - other.width, 292 height: self.height - other.height, 293 } 294 } 295 } 296 297 impl SubAssign<Size> for Size { 298 #[inline] sub_assign(&mut self, other: Size)299 fn sub_assign(&mut self, other: Size) { 300 *self = *self - other; 301 } 302 } 303 304 impl From<(f64, f64)> for Size { 305 #[inline] from(v: (f64, f64)) -> Size306 fn from(v: (f64, f64)) -> Size { 307 Size { 308 width: v.0, 309 height: v.1, 310 } 311 } 312 } 313 314 impl From<Size> for (f64, f64) { 315 #[inline] from(v: Size) -> (f64, f64)316 fn from(v: Size) -> (f64, f64) { 317 (v.width, v.height) 318 } 319 } 320 321 //FIXME: remove for 0.6.0 https://github.com/linebender/kurbo/issues/95 322 impl Into<Size> for Vec2 { 323 #[inline] into(self) -> Size324 fn into(self) -> Size { 325 self.to_size() 326 } 327 } 328 329 #[cfg(test)] 330 mod tests { 331 use super::*; 332 333 #[test] display()334 fn display() { 335 let s = Size::new(-0.12345, 9.87654); 336 assert_eq!(format!("{}", s), "(-0.12345×9.87654)"); 337 338 let s = Size::new(-0.12345, 9.87654); 339 assert_eq!(format!("{:+6.2}", s), "( -0.12× +9.88)"); 340 } 341 } 342