lighthouse_protocol/utils/
rect.rs1use std::{fmt::Debug, ops::{Add, Mul, Range, Sub}};
2
3use rand::{Rng, seq::IteratorRandom, thread_rng};
4
5use crate::{Vec2, LIGHTHOUSE_COLS};
6
7use super::{RemEuclid, Zero};
8
9#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
11pub struct Rect<T> {
12 pub origin: Vec2<T>,
13 pub size: Vec2<T>,
14}
15
16impl<T> Rect<T> {
17 pub const fn new(origin: Vec2<T>, size: Vec2<T>) -> Self {
19 Self { origin, size }
20 }
21}
22
23impl<T> Rect<T> where T: Copy {
24 pub const fn width(self) -> T {
26 self.size.x
27 }
28
29 pub const fn height(self) -> T {
31 self.size.y
32 }
33}
34
35impl<T> Rect<T> where T: Mul<Output = T> + Copy {
36 pub fn area(self) -> T {
38 self.width() * self.height()
39 }
40}
41
42impl<T> Rect<T> where T: RemEuclid + Copy {
43 pub fn wrap(self, pos: Vec2<T>) -> Vec2<T> {
45 Vec2::new(
46 pos.x.rem_euclid(self.width()),
47 pos.y.rem_euclid(self.height()),
48 )
49 }
50}
51
52impl<T> Rect<T> where T: Zero + Eq + Copy {
53 pub fn is_empty(self) -> bool {
55 self.size.x == T::ZERO && self.size.y == T::ZERO
56 }
57}
58
59impl<T> Rect<T> where T: Add<Output = T> + Copy {
60 pub fn x_range(self) -> Range<T> {
62 self.origin.x..(self.origin.x + self.size.x)
63 }
64
65 pub fn y_range(self) -> Range<T> {
67 self.origin.y..(self.origin.y + self.size.y)
68 }
69}
70
71impl<T> Rect<T> where T: Add<Output = T> + Copy, Range<T>: IteratorRandom<Item = T> {
72 pub fn sample_random_with(self, rng: &mut impl Rng) -> Option<Vec2<T>> {
74 let x = self.x_range().choose(rng)?;
75 let y = self.y_range().choose(rng)?;
76 Some(Vec2::<T>::new(x, y))
77 }
78
79 pub fn sample_random(self) -> Option<Vec2<T>> {
81 self.sample_random_with(&mut thread_rng())
82 }
83}
84
85impl<T> Rect<T> where T: Add<Output = T> + Ord + Copy {
86 pub fn contains(self, pos: Vec2<T>) -> bool {
88 pos.x >= self.origin.x && pos.x < self.origin.x + self.width()
89 && pos.y >= self.origin.y && pos.y < self.origin.y + self.height()
90 }
91}
92
93impl<T> Rect<T> where T: Add<Output = T> + Sub<Output = T> + TryInto<usize> + Ord + Copy, T::Error: Debug {
94 pub fn index_of(self, pos: Vec2<T>) -> usize {
96 debug_assert!(self.contains(pos));
97 let relative = pos - self.origin;
98 relative.y.try_into().unwrap() * LIGHTHOUSE_COLS + relative.x.try_into().unwrap()
99 }
100}