1use std::ops::{Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, Mul, Sub, SubAssign};
2
3use num_traits::{NumCast, NumOps, ToPrimitive, Zero};
4
5use crate::core::{Point_, Size_};
6use crate::opencv_type_simple_generic;
7
8#[inline(always)]
9fn partial_min<T: PartialOrd>(a: T, b: T) -> T {
10 if a <= b {
11 a
12 } else {
13 b
14 }
15}
16
17#[inline(always)]
18fn partial_max<T: PartialOrd>(a: T, b: T) -> T {
19 if b >= a {
20 b
21 } else {
22 a
23 }
24}
25
26#[repr(C)]
28#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd)]
29pub struct Rect_<T> {
30 pub x: T,
31 pub y: T,
32 pub width: T,
33 pub height: T,
34}
35
36impl<T> Rect_<T> {
37 #[inline]
38 pub const fn new(x: T, y: T, width: T, height: T) -> Self {
39 Self { x, y, width, height }
40 }
41
42 #[inline]
43 pub fn from_point_size(pt: Point_<T>, sz: Size_<T>) -> Self {
44 Self::new(pt.x, pt.y, sz.width, sz.height)
45 }
46
47 #[inline]
48 pub fn from_points(pt1: Point_<T>, pt2: Point_<T>) -> Self
49 where
50 T: PartialOrd + Sub<Output = T> + Copy,
51 {
52 let x = partial_min(pt1.x, pt2.x);
53 let y = partial_min(pt1.y, pt2.y);
54 Self::new(x, y, partial_max(pt1.x, pt2.x) - x, partial_max(pt1.y, pt2.y) - y)
55 }
56
57 #[inline]
58 pub const fn tl(&self) -> Point_<T>
59 where
60 T: Copy,
61 {
62 Point_::new(self.x, self.y)
63 }
64
65 #[inline]
66 pub fn br(&self) -> Point_<T>
67 where
68 T: Add<Output = T> + Copy,
69 {
70 Point_::new(self.x + self.width, self.y + self.height)
71 }
72
73 #[inline]
74 pub const fn size(&self) -> Size_<T>
75 where
76 T: Copy,
77 {
78 Size_::new(self.width, self.height)
79 }
80
81 #[inline]
82 pub fn area(&self) -> T
83 where
84 T: Mul<Output = T> + Copy,
85 {
86 self.width * self.height
87 }
88
89 #[inline]
90 pub fn empty(&self) -> bool
91 where
92 T: PartialOrd + Zero,
93 {
94 self.width <= T::zero() || self.height <= T::zero()
95 }
96
97 #[inline]
98 pub fn contains(&self, pt: Point_<T>) -> bool
99 where
100 T: PartialOrd + Add<Output = T> + Copy,
101 {
102 self.x <= pt.x && pt.x < self.x + self.width && self.y <= pt.y && pt.y < self.y + self.height
103 }
104
105 #[inline]
107 pub fn to<D: NumCast>(&self) -> Option<Rect_<D>>
108 where
109 T: ToPrimitive + Copy,
110 {
111 Some(Rect_ {
112 x: D::from(self.x)?,
113 y: D::from(self.y)?,
114 width: D::from(self.width)?,
115 height: D::from(self.height)?,
116 })
117 }
118}
119
120impl<T> From<(T, T, T, T)> for Rect_<T> {
121 #[inline]
122 fn from(s: (T, T, T, T)) -> Self {
123 Self::new(s.0, s.1, s.2, s.3)
124 }
125}
126
127impl<T> From<(Point_<T>, Size_<T>)> for Rect_<T> {
128 #[inline]
129 fn from(s: (Point_<T>, Size_<T>)) -> Self {
130 Self::from_point_size(s.0, s.1)
131 }
132}
133
134impl<T: PartialOrd + Sub<Output = T> + Copy> From<(Point_<T>, Point_<T>)> for Rect_<T> {
135 #[inline]
136 fn from(s: (Point_<T>, Point_<T>)) -> Self {
137 Self::from_points(s.0, s.1)
138 }
139}
140
141impl<P, R> Add<Point_<P>> for Rect_<R>
142where
143 Self: AddAssign<Point_<P>>,
144{
145 type Output = Self;
146
147 fn add(mut self, rhs: Point_<P>) -> Self::Output {
148 self += rhs;
149 self
150 }
151}
152
153impl<P, R> Sub<Point_<P>> for Rect_<R>
154where
155 Self: SubAssign<Point_<P>>,
156{
157 type Output = Self;
158
159 fn sub(mut self, rhs: Point_<P>) -> Self::Output {
160 self -= rhs;
161 self
162 }
163}
164
165impl<S, R> Add<Size_<S>> for Rect_<R>
166where
167 Self: AddAssign<Size_<S>>,
168{
169 type Output = Self;
170
171 fn add(mut self, rhs: Size_<S>) -> Self::Output {
172 self += rhs;
173 self
174 }
175}
176
177impl<S, R> Sub<Size_<S>> for Rect_<R>
178where
179 Self: SubAssign<Size_<S>>,
180{
181 type Output = Self;
182
183 fn sub(mut self, rhs: Size_<S>) -> Self::Output {
184 self -= rhs;
185 self
186 }
187}
188
189impl<T> BitOr for Rect_<T>
190where
191 Rect_<T>: BitOrAssign,
192{
193 type Output = Rect_<T>;
194
195 fn bitor(mut self, rhs: Self) -> Self::Output {
196 self |= rhs;
197 self
198 }
199}
200
201impl<T> BitAnd for Rect_<T>
202where
203 Rect_<T>: BitAndAssign,
204{
205 type Output = Rect_<T>;
206
207 fn bitand(mut self, rhs: Self) -> Self::Output {
208 self &= rhs;
209 self
210 }
211}
212
213impl<P, R: AddAssign<P>> AddAssign<Point_<P>> for Rect_<R> {
214 fn add_assign(&mut self, rhs: Point_<P>) {
215 self.x += rhs.x;
216 self.y += rhs.y;
217 }
218}
219
220impl<P, R: SubAssign<P>> SubAssign<Point_<P>> for Rect_<R> {
221 fn sub_assign(&mut self, rhs: Point_<P>) {
222 self.x -= rhs.x;
223 self.y -= rhs.y;
224 }
225}
226
227impl<S, R: AddAssign<S>> AddAssign<Size_<S>> for Rect_<R> {
228 fn add_assign(&mut self, rhs: Size_<S>) {
229 self.width += rhs.width;
230 self.height += rhs.height;
231 }
232}
233
234impl<S, R: SubAssign<S>> SubAssign<Size_<S>> for Rect_<R> {
235 fn sub_assign(&mut self, rhs: Size_<S>) {
236 self.width -= rhs.width;
237 self.height -= rhs.height;
238 }
239}
240
241impl<T: PartialOrd + NumOps + Zero + Copy> BitOrAssign for Rect_<T> {
242 fn bitor_assign(&mut self, rhs: Self) {
243 if self.empty() {
244 *self = rhs;
245 } else if !rhs.empty() {
246 let x1 = partial_min(self.x, rhs.x);
247 let y1 = partial_min(self.y, rhs.y);
248 self.width = partial_max(self.x + self.width, rhs.x + rhs.width) - x1;
249 self.height = partial_max(self.y + self.height, rhs.y + rhs.height) - y1;
250 self.x = x1;
251 self.y = y1;
252 }
253 }
254}
255
256impl<T: PartialOrd + NumOps + Zero + Copy> BitAndAssign for Rect_<T>
257where
258 Self: Default,
259{
260 fn bitand_assign(&mut self, rhs: Self) {
261 let x1 = partial_max(self.x, rhs.x);
262 let y1 = partial_max(self.y, rhs.y);
263 self.width = partial_min(self.x + self.width, rhs.x + rhs.width) - x1;
264 self.height = partial_min(self.y + self.height, rhs.y + rhs.height) - y1;
265 self.x = x1;
266 self.y = y1;
267 if self.empty() {
268 *self = Self::default();
269 }
270 }
271}
272
273#[test]
274fn test_partial() {
275 assert_eq!(1., partial_min(1., 2.));
276 assert_eq!(1., partial_min(2., 1.));
277 assert_eq!(1., partial_min(1., 1.));
278 assert_eq!(1, partial_min(1, 2));
279 assert_eq!(1, partial_min(2, 1));
280 assert_eq!(1, partial_min(1, 1));
281
282 assert_eq!(2., partial_max(1., 2.));
283 assert_eq!(2., partial_max(2., 1.));
284 assert_eq!(2., partial_max(2., 2.));
285 assert_eq!(2, partial_max(1, 2));
286 assert_eq!(2, partial_max(2, 1));
287 assert_eq!(2, partial_max(2, 2));
288}
289
290opencv_type_simple_generic! { Rect_<Copy> }