geometry/dims.rs
1//! A horizontal and vertical rectangular dimension with no specified location.
2
3use std::cmp::Ordering;
4
5use serde::{Deserialize, Serialize};
6
7use crate::dir::Dir;
8use crate::point::Point;
9use crate::rect::Rect;
10
11/// A horizontal and vertical rectangular dimension with no specified location.
12#[derive(
13 Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default, Serialize, Deserialize,
14)]
15pub struct Dims {
16 /// The width dimension.
17 w: i64,
18 /// The height dimension.
19 h: i64,
20}
21
22impl Dims {
23 /// Creates a new [`Dims`] from a width and height.
24 pub fn new(w: i64, h: i64) -> Self {
25 Self { w, h }
26 }
27 /// Creates a new [`Dims`] with width and height equal to `value`.
28 ///
29 /// # Example
30 ///
31 /// ```
32 /// # use geometry::prelude::*;
33 /// assert_eq!(Dims::square(100), Dims::new(100, 100));
34 /// ```
35 pub fn square(value: i64) -> Self {
36 Self { w: value, h: value }
37 }
38
39 /// Returns the dimension in the specified direction.
40 ///
41 /// # Example
42 ///
43 /// ```
44 /// # use geometry::prelude::*;
45 /// let dims = Dims::new(100, 200);
46 /// assert_eq!(dims.dim(Dir::Vert), 200);
47 /// assert_eq!(dims.dim(Dir::Horiz), 100);
48 /// ```
49 pub fn dim(&self, dir: Dir) -> i64 {
50 match dir {
51 Dir::Vert => self.h,
52 Dir::Horiz => self.w,
53 }
54 }
55
56 /// Returns the direction of the longer dimension.
57 ///
58 /// If the width and height are equal, returns [`Dir::Horiz`].
59 ///
60 /// # Example
61 ///
62 /// ```
63 /// # use geometry::prelude::*;
64 /// let dims = Dims::new(100, 200);
65 /// assert_eq!(dims.longer_dir(), Dir::Vert);
66 /// let dims = Dims::new(200, 100);
67 /// assert_eq!(dims.longer_dir(), Dir::Horiz);
68 /// let dims = Dims::new(100, 100);
69 /// assert_eq!(dims.longer_dir(), Dir::Horiz);
70 /// ```
71 pub fn longer_dir(&self) -> Dir {
72 if self.w >= self.h {
73 Dir::Horiz
74 } else {
75 Dir::Vert
76 }
77 }
78
79 /// Returns the direction of the longer dimension.
80 ///
81 /// If the width and height are equal, returns [`None`].
82 /// Otherwise, returns a `Some` variant containing the longer direction.
83 pub fn longer_dir_strict(&self) -> Option<Dir> {
84 match self.w.cmp(&self.h) {
85 Ordering::Greater => Some(Dir::Horiz),
86 Ordering::Equal => None,
87 Ordering::Less => Some(Dir::Vert),
88 }
89 }
90
91 /// Returns a new [`Dims`] object with the horizontal and vertical dimensions flipped.
92 pub fn transpose(self) -> Self {
93 Self {
94 w: self.h,
95 h: self.w,
96 }
97 }
98
99 /// Returns the width (i.e. the horizontal dimension).
100 #[inline]
101 pub fn width(&self) -> i64 {
102 self.w
103 }
104
105 /// Returns the height (i.e. the vertical dimension).
106 #[inline]
107 pub fn height(&self) -> i64 {
108 self.h
109 }
110
111 /// Returns the width (i.e. the horizontal dimension).
112 ///
113 /// A shorthand for [`Dims::width`].
114 #[inline]
115 pub fn w(&self) -> i64 {
116 self.width()
117 }
118
119 /// Returns the height (i.e. the vertical dimension).
120 ///
121 /// A shorthand for [`Dims::height`].
122 #[inline]
123 pub fn h(&self) -> i64 {
124 self.height()
125 }
126
127 /// Converts this dimension object into a [`Rect`].
128 ///
129 /// See [`Rect::from_dims`] for more information.
130 #[inline]
131 pub fn into_rect(self) -> Rect {
132 Rect::from_dims(self)
133 }
134
135 /// Converts this dimension object into a [`Point`] with coordinates `(self.w(), self.h())`.
136 #[inline]
137 pub fn into_point(self) -> Point {
138 Point::new(self.w(), self.h())
139 }
140}
141
142impl std::ops::Add<Dims> for Dims {
143 type Output = Self;
144 fn add(self, rhs: Dims) -> Self::Output {
145 Self {
146 w: self.w + rhs.w,
147 h: self.h + rhs.h,
148 }
149 }
150}
151
152impl std::ops::Sub<Dims> for Dims {
153 type Output = Self;
154 fn sub(self, rhs: Dims) -> Self::Output {
155 Self {
156 w: self.w - rhs.w,
157 h: self.h - rhs.h,
158 }
159 }
160}
161
162impl std::ops::Mul<i64> for Dims {
163 type Output = Self;
164 fn mul(self, rhs: i64) -> Self::Output {
165 Self {
166 w: self.w * rhs,
167 h: self.h * rhs,
168 }
169 }
170}
171
172impl std::ops::Mul<(usize, usize)> for Dims {
173 type Output = Self;
174 fn mul(self, rhs: (usize, usize)) -> Self::Output {
175 Self {
176 w: self.w * rhs.0 as i64,
177 h: self.h * rhs.1 as i64,
178 }
179 }
180}
181
182impl std::ops::AddAssign<Dims> for Dims {
183 fn add_assign(&mut self, rhs: Dims) {
184 self.w += rhs.w;
185 self.h += rhs.h;
186 }
187}
188
189impl std::ops::SubAssign<Dims> for Dims {
190 fn sub_assign(&mut self, rhs: Dims) {
191 self.w -= rhs.w;
192 self.h -= rhs.h;
193 }
194}
195
196impl std::ops::MulAssign<i64> for Dims {
197 fn mul_assign(&mut self, rhs: i64) {
198 self.w *= rhs;
199 self.h *= rhs;
200 }
201}
202
203impl From<Rect> for Dims {
204 /// Obtains [`Dims`] from the given [`Rect`] using [`Rect::dims`].
205 #[inline]
206 fn from(value: Rect) -> Self {
207 value.dims()
208 }
209}
210
211impl From<Point> for Dims {
212 /// Create a new dimension object from a point.
213 ///
214 /// The width field of the resulting [`Dims`] will be the point's x-coordinate.
215 /// The height field of the resulting [`Dims`] will be the point's y-coordinate.
216 #[inline]
217 fn from(value: Point) -> Self {
218 Self::new(value.x, value.y)
219 }
220}