cursive_core/vec.rs
1//! Points on the 2D character grid.
2
3use std::cmp::{max, min, Ordering};
4use std::ops::{Add, Div, Mul, Sub};
5
6use num::traits::Zero;
7
8use crate::div;
9use crate::XY;
10
11/// Simple 2D size, in cells.
12///
13/// Note: due to a bug in rustdoc ([#32077]), the documentation for `Vec2` is
14/// currently shown on the [`XY`] page.
15///
16/// [#32077]: https://github.com/rust-lang/rust/issues/32077
17/// [`XY`]: crate::XY
18pub type Vec2 = XY<usize>;
19
20/// A signed 2D quantity, in cells.
21///
22/// Usually represents an offset.
23pub type Vec2i = XY<isize>;
24
25impl<T: PartialOrd> PartialOrd for XY<T> {
26 /// `a < b` <=> `a.x < b.x && a.y < b.y`
27 fn partial_cmp(&self, other: &XY<T>) -> Option<Ordering> {
28 if self == other {
29 Some(Ordering::Equal)
30 } else if self.x < other.x && self.y < other.y {
31 Some(Ordering::Less)
32 } else if self.x > other.x && self.y > other.y {
33 Some(Ordering::Greater)
34 } else {
35 None
36 }
37 }
38}
39
40impl XY<f32> {
41 /// Returns the given vector, rotated by an angle in radians.
42 pub fn rotated(self, angle_rad: f32) -> Self {
43 let c = angle_rad.cos();
44 let s = angle_rad.sin();
45
46 Self::new(self.x * c - self.y * s, self.x * s + self.y * c)
47 }
48}
49
50impl XY<usize> {
51 /// A `Vec2` with `usize::MAX` in each axis.
52 pub const MAX: XY<usize> = XY {
53 x: usize::MAX,
54 y: usize::MAX,
55 };
56
57 /// The origin, `{ x: 0, y: 0 }`.
58 pub const ZERO: XY<usize> = XY { x: 0, y: 0 };
59
60 /// The unit X vector `{ x: 1, y: 0 }`.
61 pub const X: XY<usize> = XY::new(1, 0);
62
63 /// The unit Y vector `{ x: 0, y: 1 }`.
64 pub const Y: XY<usize> = XY::new(0, 1);
65
66 /// Returns a `Vec2` with `usize::MAX` in each axis.
67 ///
68 /// # Examples
69 ///
70 /// ```rust
71 /// # use cursive_core::Vec2;
72 /// assert!(Vec2::new(9999, 9999) < Vec2::max_value());
73 /// ```
74 #[must_use]
75 pub const fn max_value() -> Self {
76 Self::new(usize::MAX, usize::MAX)
77 }
78
79 /// Saturating subtraction. Computes `self - other`, saturating at 0.
80 ///
81 /// Never panics.
82 ///
83 /// # Examples
84 ///
85 /// ```rust
86 /// # use cursive_core::Vec2;
87 /// let u = Vec2::new(1, 2);
88 /// let v = Vec2::new(2, 1);
89 /// assert_eq!(u.saturating_sub(v), Vec2::new(0, 1));
90 /// ```
91 #[must_use]
92 pub fn saturating_sub<O: Into<Self>>(&self, other: O) -> Self {
93 let other = other.into();
94 self.zip_map(other, usize::saturating_sub)
95 }
96
97 /// Saturating addition with a signed vec.
98 ///
99 /// Any coordinates saturates to 0.
100 ///
101 /// # Examples
102 ///
103 /// ```rust
104 /// # use cursive_core::Vec2;
105 /// # use cursive_core::XY;
106 /// let u = Vec2::new(1, 2);
107 /// let v = XY::<isize>::new(-2, 1);
108 /// assert_eq!(u.saturating_add(v), Vec2::new(0, 3));
109 /// ```
110 #[must_use]
111 pub fn saturating_add<O: Into<XY<isize>>>(&self, other: O) -> Self {
112 let other = other.into();
113
114 self.zip_map(other, |s, o| {
115 if o > 0 {
116 s.saturating_add(o as usize)
117 } else {
118 s.saturating_sub((-o) as usize)
119 }
120 })
121 }
122
123 /// Checked addition with a signed vec.
124 ///
125 /// Will return `None` if any coordinates exceeds bounds.
126 pub fn checked_add<O: Into<XY<isize>>>(&self, other: O) -> Option<Self> {
127 let other = other.into();
128 self.zip_map(other, |s, o| {
129 if o > 0 {
130 s.checked_add(o as usize)
131 } else {
132 s.checked_sub((-o) as usize)
133 }
134 })
135 .both()
136 }
137
138 /// Term-by-term integer division that rounds up.
139 ///
140 /// # Examples
141 ///
142 /// ```rust
143 /// # use cursive_core::Vec2;
144 /// let u = Vec2::new(1, 6);
145 /// let v = Vec2::new(2, 3);
146 /// assert_eq!(u.div_up(v), Vec2::new(1, 2));
147 /// ```
148 #[must_use]
149 pub fn div_up<O>(&self, other: O) -> Self
150 where
151 O: Into<Self>,
152 {
153 self.zip_map(other.into(), div::div_up)
154 }
155
156 /// Checked subtraction. Computes `self - other` if possible.
157 ///
158 /// Returns `None` if `self.x < other.x || self.y < other.y`.
159 ///
160 /// Never panics.
161 ///
162 /// # Examples
163 ///
164 /// ```rust
165 /// # use cursive_core::Vec2;
166 /// let xy = Vec2::new(1, 2);
167 /// assert_eq!(xy.checked_sub((1, 1)), Some(Vec2::new(0, 1)));
168 /// assert_eq!(xy.checked_sub((2, 2)), None);
169 /// ```
170 pub fn checked_sub<O: Into<Self>>(&self, other: O) -> Option<Self> {
171 let other = other.into();
172 if self.fits(other) {
173 Some(*self - other)
174 } else {
175 None
176 }
177 }
178
179 /// Returns a `XY<isize>` from `self`.
180 ///
181 /// # Examples
182 ///
183 /// ```rust
184 /// # use cursive_core::Vec2;
185 /// # use cursive_core::XY;
186 /// let v: XY<isize> = Vec2::new(1, 2).signed().map(|i| i - 5);
187 /// assert_eq!(v, XY::new(-4, -3));
188 ///
189 /// let u = Vec2::new(3, 4);
190 /// assert_eq!(u.saturating_add(v), Vec2::new(0, 1));
191 /// ```
192 pub const fn signed(self) -> XY<isize> {
193 XY::new(self.x as isize, self.y as isize)
194 }
195
196 /// Returns the square distance between `a` and `b`.
197 pub fn sq_distance(a: Self, b: Self) -> usize {
198 (a.signed() - b.signed()).map(|x| (x * x) as usize).sum()
199 }
200}
201
202impl<T: Sub<Output = T> + Mul<Output = T> + Add<Output = T> + Copy> XY<T> {
203 /// Returns the square distance between `a` and `b`.
204 pub fn sq_norm(self) -> T {
205 self.map(|x| (x * x)).sum()
206 }
207}
208
209impl<T: Ord> XY<T> {
210 /// Returns `true` if `self` could fit inside `other`.
211 ///
212 /// Shortcut for `self.x <= other.x && self.y <= other.y`.
213 ///
214 /// If this returns `true`, then `other - self` will not underflow.
215 ///
216 /// # Examples
217 ///
218 /// ```rust
219 /// # use cursive_core::Vec2;
220 /// let v = Vec2::new(1, 2);
221 /// assert!(v.fits_in((1, 2)));
222 /// assert!(v.fits_in((3, 3)));
223 /// assert!(!v.fits_in((2, 1)));
224 /// ```
225 pub fn fits_in<O: Into<Self>>(&self, other: O) -> bool {
226 let other = other.into();
227 self.x <= other.x && self.y <= other.y
228 }
229
230 /// Returns `true` if `other` could fit inside `self`.
231 ///
232 /// Shortcut for `self.x >= other.x && self.y >= other.y`.
233 ///
234 /// If this returns `true`, then `self - other` will not underflow.
235 ///
236 /// # Examples
237 ///
238 /// ```rust
239 /// # use cursive_core::Vec2;
240 /// let v = Vec2::new(1, 2);
241 /// assert!(v.fits((1, 2)));
242 /// assert!(v.fits((0, 0)));
243 /// assert!(!v.fits((2, 1)));
244 /// ```
245 pub fn fits<O: Into<Self>>(&self, other: O) -> bool {
246 let other = other.into();
247 self.x >= other.x && self.y >= other.y
248 }
249
250 /// Returns `true` if `other` is strictly less than `self` in each axis.
251 pub fn strictly_lt<O: Into<Self>>(&self, other: O) -> bool {
252 let other = other.into();
253 self < &other
254 }
255
256 /// Returns `true` if `other` is strictly greater than `self` in each axis.
257 pub fn strictly_gt<O: Into<Self>>(&self, other: O) -> bool {
258 let other = other.into();
259 self > &other
260 }
261
262 /// Returns a new Vec2 that is a maximum per coordinate.
263 ///
264 /// # Examples
265 ///
266 /// ```rust
267 /// # use cursive_core::Vec2;
268 /// assert_eq!(Vec2::max((1, 2), (3, 1)), Vec2::new(3, 2));
269 /// ```
270 #[must_use]
271 pub fn max<A: Into<XY<T>>, B: Into<XY<T>>>(a: A, b: B) -> Self {
272 let a = a.into();
273 let b = b.into();
274 a.zip_map(b, max)
275 }
276
277 /// Returns a new Vec2 that is no larger than any input in both dimensions.
278 ///
279 /// # Examples
280 ///
281 /// ```rust
282 /// # use cursive_core::Vec2;
283 /// assert_eq!(Vec2::min((1, 2), (3, 1)), Vec2::new(1, 1));
284 /// ```
285 #[must_use]
286 pub fn min<A: Into<XY<T>>, B: Into<XY<T>>>(a: A, b: B) -> Self {
287 let a = a.into();
288 let b = b.into();
289 a.zip_map(b, min)
290 }
291
292 /// Returns the minimum of `self` and `other`.
293 ///
294 /// This is equivalent to `Vec2::min(self, other)`.
295 #[must_use]
296 pub fn or_min<O: Into<XY<T>>>(self, other: O) -> Self {
297 Self::min(self, other)
298 }
299
300 /// Returns the maximum of `self` and `other`.
301 ///
302 /// This is equivalent to `Vec2::max(self, other)`.
303 #[must_use]
304 pub fn or_max<O: Into<XY<T>>>(self, other: O) -> Self {
305 Self::max(self, other)
306 }
307}
308
309impl<T: Ord + Add<Output = T> + Clone> XY<T> {
310 /// Returns (max(self.x,other.x), self.y+other.y)
311 #[must_use]
312 pub fn stack_vertical(&self, other: &Self) -> Self {
313 Self::new(
314 max(self.x.clone(), other.x.clone()),
315 self.y.clone() + other.y.clone(),
316 )
317 }
318
319 /// Returns (self.x+other.x, max(self.y,other.y))
320 #[must_use]
321 pub fn stack_horizontal(&self, other: &Self) -> Self {
322 Self::new(
323 self.x.clone() + other.x.clone(),
324 max(self.y.clone(), other.y.clone()),
325 )
326 }
327
328 /// Returns `true` if `self` fits in the given rectangle.
329 pub fn fits_in_rect<O1, O2>(&self, top_left: O1, size: O2) -> bool
330 where
331 O1: Into<Self>,
332 O2: Into<Self>,
333 {
334 let top_left = top_left.into();
335 self.fits(top_left.clone()) && self < &(top_left + size)
336 }
337}
338
339impl<T: Add> XY<T> {
340 /// Returns `self.x + self.y`.
341 pub fn sum(self) -> T::Output {
342 self.fold(std::ops::Add::add)
343 }
344}
345
346impl<T: Mul> XY<T> {
347 /// Returns `self.x * self.y`
348 pub fn product(self) -> T::Output {
349 self.fold(std::ops::Mul::mul)
350 }
351}
352
353impl<T: Zero + Clone> XY<T> {
354 /// Returns a vector with the X component of self, and y=0.
355 ///
356 /// # Examples
357 ///
358 /// ```rust
359 /// # use cursive_core::XY;
360 /// let xy = XY::new(1, 2);
361 /// assert_eq!(xy.keep_x(), XY::new(1, 0));
362 /// ```
363 #[must_use]
364 pub fn keep_x(&self) -> Self {
365 Self::new(self.x.clone(), T::zero())
366 }
367
368 /// Returns a vector with the Y component of self, and x=0.
369 ///
370 /// # Examples
371 ///
372 /// ```rust
373 /// # use cursive_core::XY;
374 /// let xy = XY::new(1, 2);
375 /// assert_eq!(xy.keep_y(), XY::new(0, 2));
376 /// ```
377 #[must_use]
378 pub fn keep_y(&self) -> Self {
379 Self::new(T::zero(), self.y.clone())
380 }
381}
382
383impl<T: Zero> XY<T> {
384 /// Alias for `Self::new(0,0)`.
385 ///
386 /// # Examples
387 ///
388 /// ```rust
389 /// # use cursive_core::Vec2;
390 /// assert_eq!(Vec2::zero(), Vec2::new(0, 0));
391 /// ```
392 #[must_use]
393 pub fn zero() -> Self {
394 Self::new(T::zero(), T::zero())
395 }
396}
397
398impl<'a, T> From<&'a XY<T>> for XY<T>
399where
400 T: Clone,
401{
402 /// Clone a XY
403 ///
404 /// # Examples
405 ///
406 /// ```rust
407 /// # use cursive_core::XY;
408 /// let xy = XY::new(String::from("a"), String::from("ab"));
409 /// assert_eq!(XY::from(&xy), xy);
410 /// ```
411 fn from(t: &'a XY<T>) -> Self {
412 t.clone()
413 }
414}
415
416// Anything that can become XY<usize> can also become XY<isize>
417impl<T> From<T> for XY<isize>
418where
419 T: Into<XY<usize>>,
420{
421 /// # Examples
422 ///
423 /// ```rust
424 /// # use cursive_core::XY;
425 /// # use cursive_core::Vec2;
426 /// let u = Vec2::new(1, 2);
427 /// let v: XY<isize> = XY::from(u);
428 /// assert_eq!(v, XY::new(1, 2));
429 /// ```
430 fn from(t: T) -> Self {
431 let other = t.into();
432 Self::new(other.x as isize, other.y as isize)
433 }
434}
435
436impl From<(i32, i32)> for XY<usize> {
437 /// # Examples
438 ///
439 /// ```rust
440 /// # use cursive_core::XY;
441 /// let xy: XY<isize> = XY::from((-1i32, -2i32));
442 /// assert_eq!(xy, XY::new(-1, -2));
443 /// ```
444 fn from((x, y): (i32, i32)) -> Self {
445 (x as usize, y as usize).into()
446 }
447}
448
449impl From<(u32, u32)> for XY<usize> {
450 /// # Examples
451 ///
452 /// ```rust
453 /// # use cursive_core::Vec2;
454 /// let v = Vec2::from((1u32, 2u32));
455 /// assert_eq!(v, Vec2::new(1, 2));
456 /// ```
457 fn from((x, y): (u32, u32)) -> Self {
458 (x as usize, y as usize).into()
459 }
460}
461
462impl From<(u8, u8)> for XY<usize> {
463 /// # Examples
464 ///
465 /// ```rust
466 /// # use cursive_core::Vec2;
467 /// let v = Vec2::from((1u8, 2u8));
468 /// assert_eq!(v, Vec2::new(1, 2));
469 /// ```
470 fn from((x, y): (u8, u8)) -> Self {
471 (x as usize, y as usize).into()
472 }
473}
474
475impl From<(u16, u16)> for XY<usize> {
476 /// # Examples
477 ///
478 /// ```rust
479 /// # use cursive_core::Vec2;
480 /// let v = Vec2::from((1u16, 2u16));
481 /// assert_eq!(v, Vec2::new(1, 2));
482 /// ```
483 fn from((x, y): (u16, u16)) -> Self {
484 (x as usize, y as usize).into()
485 }
486}
487
488// Allow xy + (into xy)
489impl<T, O> Add<O> for XY<T>
490where
491 T: Add<Output = T>,
492 O: Into<XY<T>>,
493{
494 type Output = Self;
495
496 /// # Examples
497 ///
498 /// ```rust
499 /// # use cursive_core::XY;
500 /// let xy = XY::new(1, 2);
501 /// assert_eq!(xy + (2, 3), XY::new(3, 5));
502 /// ```
503 fn add(self, other: O) -> Self {
504 self.zip_map(other.into(), Add::add)
505 }
506}
507
508impl<T, O> Sub<O> for XY<T>
509where
510 T: Sub<Output = T>,
511 O: Into<XY<T>>,
512{
513 type Output = Self;
514
515 /// # Examples
516 ///
517 /// ```rust
518 /// # use cursive_core::XY;
519 /// let xy = XY::new(1, 2);
520 /// assert_eq!(xy - (1, 0), XY::new(0, 2));
521 /// ```
522 fn sub(self, other: O) -> Self {
523 self.zip_map(other.into(), Sub::sub)
524 }
525}
526
527impl<T: Clone + Div<Output = T>> Div<T> for XY<T> {
528 type Output = Self;
529
530 /// # Examples
531 ///
532 /// ```rust
533 /// # use cursive_core::XY;
534 /// let xy = XY::new(1, 4);
535 /// assert_eq!(xy / 2, XY::new(0, 2));
536 /// ```
537 fn div(self, other: T) -> Self {
538 self.map(|s| s / other.clone())
539 }
540}
541
542impl Mul<usize> for XY<usize> {
543 type Output = Vec2;
544
545 /// # Examples
546 ///
547 /// ```rust
548 /// # use cursive_core::Vec2;
549 /// let v = Vec2::new(1, 2);
550 /// assert_eq!(v * 2, Vec2::new(2, 4));
551 /// ```
552 fn mul(self, other: usize) -> Vec2 {
553 self.map(|s| s * other)
554 }
555}
556
557impl<T> Mul<XY<T>> for XY<T>
558where
559 T: Mul<T>,
560{
561 type Output = XY<T::Output>;
562
563 /// # Examples
564 ///
565 /// ```rust
566 /// # use cursive_core::XY;
567 /// let u = XY::new(1, 2);
568 /// let v = XY::new(2, 3);
569 /// assert_eq!(u * v, XY::new(2, 6));
570 /// ```
571 fn mul(self, other: XY<T>) -> Self::Output {
572 self.zip_map(other, |s, o| s * o)
573 }
574}
575impl<T> Div<XY<T>> for XY<T>
576where
577 T: Div<T>,
578{
579 type Output = XY<T::Output>;
580
581 /// # Examples
582 ///
583 /// ```rust
584 /// # use cursive_core::XY;
585 /// let u = XY::new(2, 3);
586 /// let v = XY::new(1, 2);
587 /// assert_eq!(u / v, XY::new(2, 1));
588 /// ```
589 fn div(self, other: XY<T>) -> Self::Output {
590 self.zip_map(other, |s, o| s / o)
591 }
592}
593
594#[cfg(test)]
595mod tests {
596 use super::Vec2;
597
598 #[test]
599 fn test_from() {
600 let vi32 = Vec2::from((4i32, 5i32));
601 let vu32 = Vec2::from((4u32, 5u32));
602
603 let vusize = Vec2::from((4usize, 5usize));
604 let vvec = Vec2::new(4, 5);
605
606 assert_eq!(vi32 - vu32, vusize - vvec);
607 }
608}