1use core::{
2 fmt,
3 ops::{Add, AddAssign, Div, DivAssign, Index, Mul, MulAssign, Sub, SubAssign},
4};
5
6use crate::geometry::Point;
7
8/// 2D size.
9///
10/// `Size` is used to define the width and height of an object.
11///
12/// [Nalgebra] support can be enabled with the `nalgebra_support` feature. This implements
13/// `From<Vector2<N>>` and `From<&Vector2<N>>` where `N` is `Scalar + Into<u32>`. This allows use
14/// of Nalgebra's [`Vector2`] with embedded-graphics where `u32`, `u16` or `u8` is used for value
15/// storage.
16///
17/// # Examples
18///
19/// ## Create a `Size` from two integers
20///
21///
22/// ```rust
23/// use embedded_graphics::geometry::Size;
24///
25/// // Create a size using the `new` constructor method
26/// let s = Size::new(10, 20);
27/// ```
28///
29/// ## Create a `Size` from a Nalgebra `Vector2`
30///
31/// _Be sure to enable the `nalgebra_support` feature to get [Nalgebra] integration._
32///
33/// Any `Vector2<N>` can be used where `N: Into<u32> + nalgebra::Scalar`. This includes the primitive types `u32`, `u16` and `u8`.
34///
35/// ```rust
36/// # #[cfg(feature = "nalgebra_support")] {
37/// use embedded_graphics::geometry::Size;
38/// use nalgebra::Vector2;
39///
40/// assert_eq!(Size::from(Vector2::new(10u32, 20)), Size::new(10u32, 20));
41/// assert_eq!(Size::from(Vector2::new(10u16, 20)), Size::new(10u32, 20));
42/// assert_eq!(Size::from(Vector2::new(10u8, 20)), Size::new(10u32, 20));
43/// # }
44/// ```
45///
46/// `.into()` can also be used, but may require more type annotations:
47///
48/// ```rust
49/// # #[cfg(feature = "nalgebra_support")] {
50/// use embedded_graphics::geometry::Size;
51/// use nalgebra::Vector2;
52///
53/// let c: Size = Vector2::new(10u32, 20).into();
54///
55/// assert_eq!(c, Size::new(10u32, 20));
56/// # }
57/// ```
58///
59/// [`Drawable`]: super::drawable::Drawable
60/// [`Vector2<N>`]: https://docs.rs/nalgebra/0.18.0/nalgebra/base/type.Vector2.html
61/// [`Vector2`]: https://docs.rs/nalgebra/0.18.0/nalgebra/base/type.Vector2.html
62/// [Nalgebra]: https://docs.rs/nalgebra
63#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
64#[cfg_attr(feature = "defmt", derive(::defmt::Format))]
65pub struct Size {
66 /// The width.
67 pub width: u32,
68
69 /// The height.
70 pub height: u32,
71}
72
73impl Size {
74 /// Creates a size from a width and a height.
75 pub const fn new(width: u32, height: u32) -> Self {
76 Size { width, height }
77 }
78
79 /// Creates a size with width and height set to an equal value.
80 ///
81 /// ```rust
82 /// use embedded_graphics::geometry::Size;
83 ///
84 /// let size = Size::new_equal(11);
85 ///
86 /// assert_eq!(
87 /// size,
88 /// Size {
89 /// width: 11,
90 /// height: 11
91 /// }
92 /// );
93 /// ```
94 pub const fn new_equal(value: u32) -> Self {
95 Size {
96 width: value,
97 height: value,
98 }
99 }
100
101 /// Creates a size with width and height equal to zero.
102 pub const fn zero() -> Self {
103 Size {
104 width: 0,
105 height: 0,
106 }
107 }
108
109 /// Returns a size with equal `width` value and `height` set to `0`.
110 ///
111 /// # Examples
112 ///
113 /// ## Move a `Point` along the X axis.
114 ///
115 /// ```rust
116 /// use embedded_graphics::geometry::{Point, Size};
117 ///
118 /// let size = Size::new(20, 30);
119 ///
120 /// let point = Point::new(10, 15);
121 ///
122 /// let moved_x = point + size.x_axis();
123 ///
124 /// assert_eq!(moved_x, Point::new(30, 15));
125 /// ```
126 pub const fn x_axis(self) -> Self {
127 Self {
128 width: self.width,
129 height: 0,
130 }
131 }
132
133 /// Returns a size with equal `height` value and `width` set to `0`.
134 ///
135 /// # Examples
136 ///
137 /// ## Move a `Point` along the Y axis.
138 ///
139 /// ```rust
140 /// use embedded_graphics::geometry::{Point, Size};
141 ///
142 /// let size = Size::new(20, 30);
143 ///
144 /// let point = Point::new(10, 15);
145 ///
146 /// let moved_y = point + size.y_axis();
147 ///
148 /// assert_eq!(moved_y, Point::new(10, 45));
149 /// ```
150 pub const fn y_axis(self) -> Self {
151 Self {
152 width: 0,
153 height: self.height,
154 }
155 }
156
157 /// Saturating addition.
158 ///
159 /// Returns `u32::max_value()` for `width` and/or `height` instead of overflowing.
160 pub const fn saturating_add(self, other: Self) -> Self {
161 Self {
162 width: self.width.saturating_add(other.width),
163 height: self.height.saturating_add(other.height),
164 }
165 }
166
167 /// Saturating subtraction.
168 ///
169 /// Returns `0` for `width` and/or `height` instead of overflowing, if the
170 /// value in `other` is larger then in `self`.
171 pub const fn saturating_sub(self, other: Self) -> Self {
172 Self {
173 width: self.width.saturating_sub(other.width),
174 height: self.height.saturating_sub(other.height),
175 }
176 }
177
178 /// Division.
179 ///
180 /// This method provides a workaround for the `Div` trait not being usable in `const` contexts.
181 pub(crate) const fn div_u32(self, rhs: u32) -> Size {
182 Size::new(self.width / rhs, self.height / rhs)
183 }
184
185 /// Creates a size from two corner points of a bounding box.
186 pub(crate) const fn from_bounding_box(corner_1: Point, corner_2: Point) -> Self {
187 let width = (corner_1.x - corner_2.x).abs() as u32 + 1;
188 let height = (corner_1.y - corner_2.y).abs() as u32 + 1;
189
190 Self { width, height }
191 }
192
193 /// Returns the componentwise minimum of two `Size`s.
194 ///
195 /// ```rust
196 /// use embedded_graphics::geometry::Size;
197 ///
198 /// let min = Size::new(20, 30).component_min(Size::new(15, 50));
199 ///
200 /// assert_eq!(min, Size::new(15, 30));
201 /// ```
202 pub fn component_min(self, other: Self) -> Self {
203 Self::new(self.width.min(other.width), self.height.min(other.height))
204 }
205
206 /// Returns the componentwise maximum of two `Size`s.
207 ///
208 /// ```rust
209 /// use embedded_graphics::geometry::Size;
210 ///
211 /// let min = Size::new(20, 30).component_max(Size::new(15, 50));
212 ///
213 /// assert_eq!(min, Size::new(20, 50));
214 /// ```
215 pub fn component_max(self, other: Self) -> Self {
216 Self::new(self.width.max(other.width), self.height.max(other.height))
217 }
218
219 /// Returns the componentwise multiplication of two `Size`s.
220 ///
221 /// ```rust
222 /// use embedded_graphics::geometry::Size;
223 ///
224 /// let result = Size::new(20, 30).component_mul(Size::new(2, 3));
225 ///
226 /// assert_eq!(result, Size::new(40, 90));
227 /// ```
228 pub const fn component_mul(self, other: Self) -> Self {
229 Self::new(self.width * other.width, self.height * other.height)
230 }
231
232 /// Returns the componentwise division of two `Size`s.
233 ///
234 /// # Panics
235 ///
236 /// Panics if one of the components of `other` equals zero.
237 ///
238 /// ```rust
239 /// use embedded_graphics::geometry::Size;
240 ///
241 /// let result = Size::new(20, 30).component_div(Size::new(5, 10));
242 ///
243 /// assert_eq!(result, Size::new(4, 3));
244 /// ```
245 pub const fn component_div(self, other: Self) -> Self {
246 Self::new(self.width / other.width, self.height / other.height)
247 }
248}
249
250impl Add for Size {
251 type Output = Size;
252
253 fn add(self, other: Size) -> Size {
254 Size::new(self.width + other.width, self.height + other.height)
255 }
256}
257
258impl AddAssign for Size {
259 fn add_assign(&mut self, other: Size) {
260 self.width += other.width;
261 self.height += other.height;
262 }
263}
264
265impl Sub for Size {
266 type Output = Size;
267
268 fn sub(self, other: Size) -> Size {
269 Size::new(self.width - other.width, self.height - other.height)
270 }
271}
272
273impl SubAssign for Size {
274 fn sub_assign(&mut self, other: Size) {
275 self.width -= other.width;
276 self.height -= other.height;
277 }
278}
279
280impl Mul<u32> for Size {
281 type Output = Size;
282
283 fn mul(self, rhs: u32) -> Size {
284 Size::new(self.width * rhs, self.height * rhs)
285 }
286}
287
288impl MulAssign<u32> for Size {
289 fn mul_assign(&mut self, rhs: u32) {
290 self.width *= rhs;
291 self.height *= rhs;
292 }
293}
294
295impl Div<u32> for Size {
296 type Output = Size;
297
298 fn div(self, rhs: u32) -> Size {
299 self.div_u32(rhs)
300 }
301}
302
303impl DivAssign<u32> for Size {
304 fn div_assign(&mut self, rhs: u32) {
305 self.width /= rhs;
306 self.height /= rhs;
307 }
308}
309
310impl Index<usize> for Size {
311 type Output = u32;
312
313 fn index(&self, idx: usize) -> &u32 {
314 match idx {
315 0 => &self.width,
316 1 => &self.height,
317 _ => panic!("index out of bounds: the len is 2 but the index is {}", idx),
318 }
319 }
320}
321
322impl From<(u32, u32)> for Size {
323 fn from(other: (u32, u32)) -> Self {
324 Size::new(width:other.0, height:other.1)
325 }
326}
327
328impl From<[u32; 2]> for Size {
329 fn from(other: [u32; 2]) -> Self {
330 Size::new(width:other[0], height:other[1])
331 }
332}
333
334impl From<&[u32; 2]> for Size {
335 fn from(other: &[u32; 2]) -> Self {
336 Size::new(width:other[0], height:other[1])
337 }
338}
339
340impl From<Size> for (u32, u32) {
341 fn from(other: Size) -> (u32, u32) {
342 (other.width, other.height)
343 }
344}
345
346impl From<Size> for [u32; 2] {
347 fn from(other: Size) -> [u32; 2] {
348 [other.width, other.height]
349 }
350}
351
352impl From<&Size> for (u32, u32) {
353 fn from(other: &Size) -> (u32, u32) {
354 (other.width, other.height)
355 }
356}
357
358impl fmt::Display for Size {
359 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
360 write!(f, "{} x {}", self.width, self.height)
361 }
362}
363
364#[cfg(feature = "nalgebra_support")]
365use nalgebra::{base::Scalar, Vector2};
366
367#[cfg(feature = "nalgebra_support")]
368impl<N> From<Vector2<N>> for Size
369where
370 N: Into<u32> + Scalar + Copy,
371{
372 fn from(other: Vector2<N>) -> Self {
373 Self::new(other[0].into(), other[1].into())
374 }
375}
376
377#[cfg(feature = "nalgebra_support")]
378impl<N> From<&Vector2<N>> for Size
379where
380 N: Into<u32> + Scalar + Copy,
381{
382 fn from(other: &Vector2<N>) -> Self {
383 Self::new(other[0].into(), other[1].into())
384 }
385}
386
387#[cfg(test)]
388mod tests {
389 use super::*;
390
391 use core::fmt::Write;
392
393 #[test]
394 fn sizes_can_be_added() {
395 let left = Size::new(10, 20);
396 let right = Size::new(30, 40);
397
398 assert_eq!(left + right, Size::new(40, 60));
399 }
400
401 #[test]
402 fn sizes_can_be_subtracted() {
403 let left = Size::new(30, 40);
404 let right = Size::new(10, 20);
405
406 assert_eq!(left - right, Size::new(20, 20));
407 }
408
409 #[test]
410 fn saturating_sub() {
411 let p = Size::new(10, 20);
412
413 assert_eq!(p.saturating_sub(Size::new(9, 18)), Size::new(1, 2));
414 assert_eq!(p.saturating_sub(Size::new(11, 18)), Size::new(0, 2));
415 assert_eq!(p.saturating_sub(Size::new(9, 21)), Size::new(1, 0));
416 assert_eq!(p.saturating_sub(Size::new(11, 21)), Size::new(0, 0));
417 }
418
419 #[test]
420 fn sizes_can_be_multiplied_by_scalar() {
421 let s = Size::new(1, 2);
422 assert_eq!(s * 3, Size::new(3, 6));
423
424 let mut s = Size::new(2, 3);
425 s *= 4;
426 assert_eq!(s, Size::new(8, 12));
427 }
428
429 #[test]
430 fn sizes_can_be_divided_by_scalar() {
431 let s = Size::new(10, 20);
432 assert_eq!(s / 2, Size::new(5, 10));
433
434 let mut s = Size::new(20, 30);
435 s /= 5;
436 assert_eq!(s, Size::new(4, 6));
437 }
438
439 #[test]
440 fn from_tuple() {
441 assert_eq!(Size::from((20, 30)), Size::new(20, 30));
442 }
443
444 #[test]
445 fn from_array() {
446 assert_eq!(Size::from([20, 30]), Size::new(20, 30));
447 }
448
449 #[test]
450 fn to_array() {
451 let array: [u32; 2] = Size::new(20, 30).into();
452
453 assert_eq!(array, [20, 30]);
454 }
455
456 #[test]
457 fn from_array_ref() {
458 assert_eq!(Size::from(&[20, 30]), Size::new(20, 30));
459 }
460
461 #[test]
462 fn index() {
463 let size = Size::new(1, 2);
464
465 assert_eq!(size.width, size[0]);
466 assert_eq!(size.height, size[1]);
467 }
468
469 #[test]
470 #[should_panic]
471 fn index_out_of_bounds() {
472 let size = Size::new(1, 2);
473 let _ = size[2];
474 }
475
476 #[test]
477 #[cfg(feature = "nalgebra_support")]
478 fn nalgebra_support() {
479 let left = nalgebra::Vector2::new(30u32, 40);
480 let right = nalgebra::Vector2::new(10, 20);
481
482 assert_eq!(Size::from(left - right), Size::new(20, 20));
483 }
484
485 #[test]
486 fn component_min_max() {
487 let a = Size::new(20, 30);
488 let b = Size::new(15, 50);
489
490 assert_eq!(a.component_min(b), Size::new(15, 30));
491 assert_eq!(a.component_max(b), Size::new(20, 50));
492 }
493
494 #[test]
495 fn display() {
496 let mut buffer = arrayvec::ArrayString::<32>::new();
497 write!(buffer, "{}", Size::new(123, 456)).unwrap();
498
499 assert_eq!(&buffer, "123 x 456");
500 }
501}
502