1use std::iter::IntoIterator;
2use std::ops::Add;
3use std::ops::AddAssign;
4use std::ops::Div;
5use std::ops::DivAssign;
6use std::ops::Mul;
7use std::ops::MulAssign;
8use std::ops::Shl;
9use std::ops::ShlAssign;
10use std::ops::Shr;
11use std::ops::ShrAssign;
12use std::ops::Sub;
13use std::ops::SubAssign;
14
15use crate::num::INum;
16use crate::num::Num;
17use crate::num::ToRounded;
18
19use crate::geom::HorizontalPosition;
20use crate::geom::Line;
21use crate::geom::LinePosition;
22use crate::geom::Point;
23use crate::geom::PointPosition;
24use crate::geom::Size;
25use crate::geom::VerticalPosition;
26
27use crate::internal::macros::quick_n_div;
28use crate::internal::macros::quick_n_mul;
29
30mod rect_iterator;
31pub use self::rect_iterator::RectIterator;
32
33#[derive(Copy, Clone, Debug, PartialEq)]
34pub struct Rect<N: Num = f32>(pub Point<N>, pub Size<N>);
35
36impl<N: Num> Rect<N> {
37 pub fn new_zero_value() -> Self {
38 Rect(Point::new_zero_value(), Size::new_zero_value())
39 }
40
41 pub fn new_from_raw(bottom_left_x: N, bottom_left_y: N, width: N, height: N) -> Self {
42 Self::new(Point(bottom_left_x, bottom_left_y), Size(width, height))
43 }
44
45 pub fn new(bottom_left: Point<N>, size: Size<N>) -> Self {
46 Self(bottom_left, size)
47 }
48
49 pub fn new_from_centre(centre: Point<N>, size: Size<N>) -> Self {
50 Self(centre - size.half(), size)
51 }
52
53 pub fn new_from_top_left(position: Point<N>, size: Size<N>) -> Self {
54 Self(position - Point(N::zero(), size.height()), size)
55 }
56
57 pub fn new_from_top_right(position: Point<N>, size: Size<N>) -> Self {
58 Self(position - size.to_point(), size)
59 }
60
61 pub fn new_from_bottom_right(position: Point<N>, size: Size<N>) -> Self {
62 Self(position - Point(size.width(), N::zero()), size)
63 }
64
65 pub fn new_from_bottom_left(position: Point<N>, size: Size<N>) -> Self {
66 Self(position, size)
67 }
68
69 pub fn new_from_bottom_centre(position: Point<N>, size: Size<N>) -> Self {
70 Self(position - Point(size.width().half(), N::zero()), size)
71 }
72
73 pub fn new_from_left_centre(position: Point<N>, size: Size<N>) -> Self {
74 Self(position - Point(N::zero(), size.height().half()), size)
75 }
76
77 pub fn new_from_top_centre(position: Point<N>, size: Size<N>) -> Self {
78 Self(position - Point(size.width().half(), size.height()), size)
79 }
80
81 pub fn new_from_right_centre(position: Point<N>, size: Size<N>) -> Self {
82 Self(position - Point(size.width(), size.height().half()), size)
83 }
84
85 pub fn move_xy(&mut self, xy: Point<N>) {
86 self.0 += xy;
87 }
88
89 pub fn move_x(&mut self, x: N) {
90 self.0.move_x(x);
91 }
92
93 pub fn move_y(&mut self, y: N) {
94 self.0.move_y(y);
95 }
96
97 pub fn width(&self) -> N {
98 self.size().width()
99 }
100
101 pub fn height(&self) -> N {
102 self.size().height()
103 }
104
105 pub fn area(&self) -> N {
106 self.size().area()
107 }
108
109 pub fn size(&self) -> Size<N> {
110 self.1.abs()
111 }
112
113 pub fn bottom_left(&self) -> Point<N> {
114 self.0 + self.1.min(Size(N::zero(), N::zero()))
115 }
116
117 pub fn bottom_right(&self) -> Point<N> {
118 self.bottom_left() + Size(self.width(), N::zero())
119 }
120
121 pub fn top_left(&self) -> Point<N> {
122 self.bottom_left() + Size(N::zero(), self.height())
123 }
124
125 pub fn top_right(&self) -> Point<N> {
126 self.bottom_left() + self.size()
127 }
128
129 pub fn bottom_centre(&self) -> Point<N> {
130 let size = self.size().abs();
131 self.bottom_left() + Point(size.width().half(), N::zero())
132 }
133
134 pub fn top_centre(&self) -> Point<N> {
135 let size = self.size().abs();
136 self.top_left() + Point(size.width().half(), N::zero())
137 }
138
139 pub fn left_centre(&self) -> Point<N> {
140 let size = self.size().abs();
141 self.bottom_left() + Point(N::zero(), size.height().half())
142 }
143
144 pub fn right_centre(&self) -> Point<N> {
145 let size = self.size().abs();
146 self.bottom_right() + Point(N::zero(), size.height().half())
147 }
148
149 pub fn top_y(&self) -> N {
150 self.bottom_left().y() + self.size().height()
151 }
152
153 pub fn bottom_y(&self) -> N {
154 self.bottom_left().y()
155 }
156
157 pub fn left_x(&self) -> N {
158 self.bottom_left().x()
159 }
160
161 pub fn right_x(&self) -> N {
162 self.bottom_left().x() + self.size().width()
163 }
164
165 pub fn centre(&self) -> Point<N> {
166 self.bottom_left() + self.size().half()
167 }
168
169 pub fn set_bottom_left(&mut self, xy: Point<N>) {
170 self.0 = xy;
171 }
172
173 pub fn set_top_left(&mut self, xy: Point<N>) {
174 self.0 = Point(xy.x(), xy.y() - self.height());
175 }
176
177 pub fn set_top_right(&mut self, xy: Point<N>) {
178 self.0 = Point(xy.x() - self.width(), xy.y() - self.height());
179 }
180
181 pub fn set_bottom_right(&mut self, xy: Point<N>) {
182 self.0 = Point(xy.x() - self.width(), xy.y());
183 }
184
185 pub fn set_centre(&mut self, xy: Point<N>) {
186 self.0 = xy - self.size().half();
187 }
188
189 pub fn set_size(&mut self, size: Size<N>) {
190 self.1 = size;
191 }
192
193 pub fn overlaps(&self, other: Self) -> bool {
194 let bottom_left_a = self.bottom_left();
195 let bottom_left_b = other.bottom_left();
196
197 let top_right_a = self.top_right();
198 let top_right_b = other.top_right();
199
200 if top_right_b.x() <= bottom_left_a.x() {
201 return false;
202 }
203
204 if top_right_b.y() <= bottom_left_a.y() {
205 return false;
206 }
207
208 if top_right_a.x() <= bottom_left_b.x() {
209 return false;
210 }
211
212 if top_right_a.y() <= bottom_left_b.y() {
213 return false;
214 }
215
216 true
217 }
218
219 pub fn contains_point(&self, point: Point<N>) -> bool {
220 self.point_horizontal_position(point) == HorizontalPosition::Inside
221 && self.point_vertical_position(point) == VerticalPosition::Inside
222 }
223
224 pub fn line_position(&self, other: Line<N>) -> LinePosition {
225 LinePosition(
226 self.point_position(other.start()),
227 self.point_position(other.end()),
228 )
229 }
230
231 pub fn point_position(&self, other: Point<N>) -> PointPosition {
232 PointPosition(
233 self.point_horizontal_position(other),
234 self.point_vertical_position(other),
235 )
236 }
237
238 pub fn point_horizontal_position(&self, other: Point<N>) -> HorizontalPosition {
239 if other.x() < self.left_x() {
240 HorizontalPosition::Left
241 } else if other.x() > self.right_x() {
242 HorizontalPosition::Right
243 } else {
244 HorizontalPosition::Inside
245 }
246 }
247
248 pub fn point_vertical_position(&self, other: Point<N>) -> VerticalPosition {
249 if other.y() < self.bottom_y() {
250 VerticalPosition::Below
251 } else if other.y() > self.top_y() {
252 VerticalPosition::Above
253 } else {
254 VerticalPosition::Inside
255 }
256 }
257
258 pub fn intersect_rect(&self, other: Self) -> Option<Self> {
259 if !self.overlaps(other) {
260 return None;
261 }
262
263 let new_bottom_left = self.bottom_left().max(other.bottom_left());
264 let new_top_right = self.top_right().min(other.top_right());
265 let new_size = new_bottom_left.distance_to(new_top_right);
266 let new_rect = Rect(new_bottom_left, new_size);
267
268 Some(new_rect)
269 }
270
271 pub fn combine(&self, other: Self) -> Self {
272 let min_xy = self.bottom_left().min(other.bottom_left());
273 let max_xy = self.top_right().max(other.top_right());
274
275 min_xy.rect_to(max_xy)
276 }
277
278 pub fn get_scale_diff(&self, other: Self) -> Size<N> {
279 self.size().get_scale_diff(other.size())
280 }
281
282 pub fn to<T: Num + From<N>>(&self) -> Rect<T> {
283 Rect(self.bottom_left().to(), self.size().to())
284 }
285
286 pub fn min(self, other: Self) -> Self {
287 Self(
288 self.bottom_left().min(other.bottom_left()),
289 self.size().min(other.size()),
290 )
291 }
292
293 pub fn max(self, other: Self) -> Self {
294 Self(
295 self.bottom_left().max(other.bottom_left()),
296 self.size().max(other.size()),
297 )
298 }
299
300 pub(crate) fn to_f32(self) -> Rect<f32> {
301 self.to_rounded()
302 }
303
304 pub fn centre_to(self, other: Rect<N>) -> Line<N> {
305 Line(self.centre(), other.centre())
306 }
307
308 pub fn left_edge(self) -> Line<N> {
309 Line(self.bottom_left(), self.top_left())
310 }
311
312 pub fn right_edge(self) -> Line<N> {
313 Line(self.bottom_right(), self.top_right())
314 }
315
316 pub fn top_edge(self) -> Line<N> {
317 Line(self.top_left(), self.top_right())
318 }
319
320 pub fn bottom_edge(self) -> Line<N> {
321 Line(self.bottom_left(), self.bottom_right())
322 }
323
324 pub fn interpolate_to(self, other: Rect<N>, n: N) -> Rect<N> {
325 let new_centre = self.centre().interpolate_to(other.centre(), n);
326 let new_size = self.size().interpolate_to(other.size(), n);
327
328 Rect::new_from_centre(new_centre, new_size)
329 }
330
331 pub fn round_to_max_size(self) -> Rect<N> {
332 let self_f32 = self.to_f32();
333 let Point(bottom_left_x, bottom_left_y) = self_f32.bottom_left();
334 let Point(top_right_x, top_right_y) = self_f32.top_right();
335
336 let new_bottom_left_x;
337 let new_bottom_left_y;
338 let new_top_right_x;
339 let new_top_right_y;
340
341 if bottom_left_x < top_right_x {
342 new_bottom_left_x = bottom_left_x.floor();
343 new_top_right_x = top_right_x.ceil();
344 } else {
345 new_bottom_left_x = bottom_left_x.floor();
346 new_top_right_x = top_right_x.ceil();
347 }
348
349 if bottom_left_y < top_right_y {
350 new_bottom_left_y = bottom_left_y.floor();
351 new_top_right_y = top_right_y.ceil();
352 } else {
353 new_bottom_left_y = bottom_left_y.floor();
354 new_top_right_y = top_right_y.ceil();
355 }
356
357 let new_rect_f32 = Point(new_bottom_left_x, new_bottom_left_y)
358 .rect_to(Point(new_top_right_x, new_top_right_y));
359 new_rect_f32.from_f32()
360 }
361}
362
363impl Rect<f32> {
364 #[allow(dead_code)]
365 pub(crate) fn from_f32<N: Num>(self) -> Rect<N> {
366 Rect(self.bottom_left().from_f32(), self.size().from_f32())
367 }
368}
369
370impl<O: Num, N: Num + ToRounded<O>> ToRounded<Rect<O>> for Rect<N> {
371 fn to_rounded(self) -> Rect<O> {
372 Rect(self.bottom_left().to_rounded(), self.size().to_rounded())
373 }
374}
375
376quick_n_div!(f32, Rect<f32>);
377quick_n_div!(f64, Rect<f64>);
378
379quick_n_div!(usize, Rect<usize>);
380quick_n_div!(u8, Rect<u8>);
381quick_n_div!(u16, Rect<u16>);
382quick_n_div!(u32, Rect<u32>);
383quick_n_div!(u64, Rect<u64>);
384quick_n_div!(u128, Rect<u128>);
385
386quick_n_div!(isize, Rect<isize>);
387quick_n_div!(i8, Rect<i8>);
388quick_n_div!(i16, Rect<i16>);
389quick_n_div!(i32, Rect<i32>);
390quick_n_div!(i64, Rect<i64>);
391quick_n_div!(i128, Rect<i128>);
392
393quick_n_mul!(f32, Rect<f32>);
394quick_n_mul!(f64, Rect<f64>);
395
396quick_n_mul!(usize, Rect<usize>);
397quick_n_mul!(u8, Rect<u8>);
398quick_n_mul!(u16, Rect<u16>);
399quick_n_mul!(u32, Rect<u32>);
400quick_n_mul!(u64, Rect<u64>);
401quick_n_mul!(u128, Rect<u128>);
402
403quick_n_mul!(isize, Rect<isize>);
404quick_n_mul!(i8, Rect<i8>);
405quick_n_mul!(i16, Rect<i16>);
406quick_n_mul!(i32, Rect<i32>);
407quick_n_mul!(i64, Rect<i64>);
408quick_n_mul!(i128, Rect<i128>);
409
410impl<N: Num> Mul<N> for Rect<N> {
411 type Output = Self;
412
413 fn mul(self, other: N) -> Self {
414 Rect::new(self.0 * other, self.1 * other)
415 }
416}
417
418impl<N: Num> MulAssign<N> for Rect<N> {
419 fn mul_assign(&mut self, other: N) {
420 *self = *self * other;
421 }
422}
423
424impl<N: Num> Div<N> for Rect<N> {
425 type Output = Self;
426
427 fn div(self, other: N) -> Self {
428 Rect::new(self.0 / other, self.1 / other)
429 }
430}
431
432impl<N: Num> DivAssign<N> for Rect<N> {
433 fn div_assign(&mut self, other: N) {
434 *self = *self / other;
435 }
436}
437
438impl<N: Num> Add<Point<N>> for Rect<N> {
439 type Output = Self;
440
441 fn add(self, other: Point<N>) -> Self {
442 Rect(self.bottom_left() + other, self.size())
443 }
444}
445
446impl<N: Num> AddAssign<Point<N>> for Rect<N> {
447 fn add_assign(&mut self, other: Point<N>) {
448 self.0 += other;
449 }
450}
451
452impl<N: Num> Add<Size<N>> for Rect<N> {
453 type Output = Self;
454
455 fn add(self, other: Size<N>) -> Self {
456 Rect(self.bottom_left(), self.size() + other)
457 }
458}
459
460impl<N: Num> AddAssign<Size<N>> for Rect<N> {
461 fn add_assign(&mut self, other: Size<N>) {
462 self.1 += other;
463 }
464}
465
466impl<N: Num> Sub<Point<N>> for Rect<N> {
467 type Output = Self;
468
469 fn sub(self, other: Point<N>) -> Self {
470 Rect(self.bottom_left() - other, self.size())
471 }
472}
473
474impl<N: Num> SubAssign<Point<N>> for Rect<N> {
475 fn sub_assign(&mut self, other: Point<N>) {
476 self.0 -= other;
477 }
478}
479
480impl<N: Num> Sub<Size<N>> for Rect<N> {
481 type Output = Self;
482
483 fn sub(self, other: Size<N>) -> Self {
484 Rect(self.bottom_left(), self.size() - other)
485 }
486}
487
488impl<N: Num> SubAssign<Size<N>> for Rect<N> {
489 fn sub_assign(&mut self, other: Size<N>) {
490 self.1 -= other;
491 }
492}
493
494impl<N: INum> Shl<N> for Rect<N> {
495 type Output = Self;
496
497 fn shl(self, other: N) -> Self {
498 Self(self.0 << other, self.1 << other)
499 }
500}
501
502impl<N: INum> ShlAssign<N> for Rect<N> {
503 fn shl_assign(&mut self, other: N) {
504 *self = *self << other;
505 }
506}
507
508impl<N: INum> Shr<N> for Rect<N> {
509 type Output = Self;
510
511 fn shr(self, other: N) -> Self {
512 Self(self.0 >> other, self.1 >> other)
513 }
514}
515
516impl<N: INum> ShrAssign<N> for Rect<N> {
517 fn shr_assign(&mut self, other: N) {
518 *self = *self >> other;
519 }
520}
521
522impl<N: Num> IntoIterator for Rect<N> {
523 type Item = Point<N>;
524 type IntoIter = RectIterator<N>;
525
526 fn into_iter(self) -> Self::IntoIter {
527 RectIterator::new(self)
528 }
529}
530
531#[cfg(test)]
532mod overlaps {
533 use super::*;
534
535 #[test]
536 fn it_should_not_overlap_with_rectangles_outside_to_the_left() {
537 let a = Rect(Point(20, 0), Size(10, 10));
538 let b = Rect(Point(0, 0), Size(10, 10));
539
540 assert_eq!(a.overlaps(b), false);
541 }
542
543 #[test]
544 fn it_should_not_overlap_with_rectangles_outside_to_the_right() {
545 let a = Rect(Point(0, 0), Size(10, 10));
546 let b = Rect(Point(20, 0), Size(10, 10));
547
548 assert_eq!(a.overlaps(b), false);
549 }
550
551 #[test]
552 fn it_should_not_overlap_with_rectangles_outside_above() {
553 let a = Rect(Point(20, 20), Size(10, 10));
554 let b = Rect(Point(20, 0), Size(10, 10));
555
556 assert_eq!(a.overlaps(b), false);
557 }
558
559 #[test]
560 fn it_should_not_overlap_with_rectangles_outside_below() {
561 let a = Rect(Point(20, 20), Size(10, 10));
562 let b = Rect(Point(20, 40), Size(10, 10));
563
564 assert_eq!(a.overlaps(b), false);
565 }
566
567 #[test]
568 fn it_should_overlap_with_rectangles_intersecting_on_the_left() {
569 let a = Rect(Point(0, 0), Size(10, 10));
570 let b = Rect(Point(-5, 0), Size(10, 10));
571
572 assert_eq!(a.overlaps(b), true);
573 }
574
575 #[test]
576 fn it_should_overlap_with_rectangles_intersecting_left_above() {
577 let a = Rect(Point(0, 0), Size(10, 10));
578 let b = Rect(Point(-5, 5), Size(10, 10));
579
580 assert_eq!(a.overlaps(b), true);
581 }
582
583 #[test]
584 fn it_should_overlap_with_rectangles_intersecting_right_below() {
585 let a = Rect(Point(0, 0), Size(10, 10));
586 let b = Rect(Point(5, -5), Size(10, 10));
587
588 assert_eq!(a.overlaps(b), true);
589 }
590
591 #[test]
592 fn it_should_overlap_with_rectangles_intersecting_fully_inside() {
593 let a = Rect(Point(0, 0), Size(10, 10));
594 let b = Rect(Point(3, 3), Size(6, 6));
595
596 assert_eq!(a.overlaps(b), true);
597 }
598
599 #[test]
600 fn it_should_overlap_identical_rectangles() {
601 let a: Rect<i32> = Rect(Point(3, 2), Size(4, 5));
602 let b: Rect<i32> = Rect(Point(3, 2), Size(4, 5));
603
604 assert_eq!(a.overlaps(b), true);
605 }
606
607 #[test]
608 fn it_should_not_overlap_rectangles_next_to_each_other() {
609 let a: Rect<i32> = Rect(Point(2, 2), Size(2, 2));
610 let b: Rect<i32> = Rect(Point(4, 2), Size(2, 2));
611
612 assert_eq!(a.overlaps(b), false);
613 }
614
615 #[test]
616 fn it_should_overlap_with_negative_sizes() {
617 let a: Rect<i32> = Rect(Point(0, 0), Size(10, 10));
618 let b: Rect<i32> = Rect(Point(12, 12), Size(-10, -10));
619
620 assert_eq!(a.overlaps(b), true);
621 assert_eq!(b.overlaps(a), true);
622 }
623}
624
625#[cfg(test)]
626mod new_from_centre {
627 use super::*;
628
629 #[test]
630 fn it_should_create_a_rectangle_around_the_point_given() {
631 let rect: Rect<f32> = Rect::new_from_centre(Point(10.0, 10.0), Size(5.0, 8.0));
632 assert_eq!(rect, Rect(Point(7.5, 6.0), Size(5.0, 8.0)));
633 }
634}
635
636#[cfg(test)]
637mod new_from_top_left {
638 use super::*;
639
640 #[test]
641 fn it_should_place_rect_correctly() {
642 let rect: Rect<i32> = Rect::new_from_top_left(Point(10, 100), Size(10, 20));
643 let expected: Rect<i32> = Rect(Point(10, 80), Size(10, 20));
644
645 assert_eq!(rect, expected);
646 }
647}
648
649#[cfg(test)]
650mod new_from_top_right {
651 use super::*;
652
653 #[test]
654 fn it_should_place_rect_correctly() {
655 let rect: Rect<i32> = Rect::new_from_top_right(Point(10, 100), Size(10, 20));
656 let expected: Rect<i32> = Rect(Point(0, 80), Size(10, 20));
657
658 assert_eq!(rect, expected);
659 }
660}
661
662#[cfg(test)]
663mod new_from_bottom_left {
664 use super::*;
665
666 #[test]
667 fn it_should_place_rect_correctly() {
668 let rect: Rect<i32> = Rect::new_from_bottom_left(Point(10, 100), Size(10, 20));
669 let expected: Rect<i32> = Rect(Point(10, 100), Size(10, 20));
670
671 assert_eq!(rect, expected);
672 }
673}
674
675#[cfg(test)]
676mod new_from_bottom_right {
677 use super::*;
678
679 #[test]
680 fn it_should_place_rect_correctly() {
681 let rect: Rect<i32> = Rect::new_from_bottom_right(Point(10, 100), Size(10, 20));
682 let expected: Rect<i32> = Rect(Point(0, 100), Size(10, 20));
683
684 assert_eq!(rect, expected);
685 }
686}
687
688#[cfg(test)]
689mod new_from_bottom_centre {
690 use super::*;
691
692 #[test]
693 fn it_should_place_rect_correctly() {
694 let rect: Rect<i32> = Rect::new_from_bottom_centre(Point(10, 100), Size(10, 20));
695 let expected: Rect<i32> = Rect(Point(5, 100), Size(10, 20));
696
697 assert_eq!(rect, expected);
698 }
699}
700
701#[cfg(test)]
702mod new_from_top_centre {
703 use super::*;
704
705 #[test]
706 fn it_should_place_rect_correctly() {
707 let rect: Rect<i32> = Rect::new_from_top_centre(Point(10, 100), Size(10, 20));
708 let expected: Rect<i32> = Rect(Point(5, 80), Size(10, 20));
709
710 assert_eq!(rect, expected);
711 }
712}
713
714#[cfg(test)]
715mod new_from_left_centre {
716 use super::*;
717
718 #[test]
719 fn it_should_place_rect_correctly() {
720 let rect: Rect<i32> = Rect::new_from_left_centre(Point(10, 100), Size(10, 20));
721 let expected: Rect<i32> = Rect(Point(10, 90), Size(10, 20));
722
723 assert_eq!(rect, expected);
724 }
725}
726
727#[cfg(test)]
728mod new_from_right_centre {
729 use super::*;
730
731 #[test]
732 fn it_should_place_rect_correctly() {
733 let rect: Rect<i32> = Rect::new_from_right_centre(Point(10, 100), Size(10, 20));
734 let expected: Rect<i32> = Rect(Point(0, 90), Size(10, 20));
735
736 assert_eq!(rect, expected);
737 }
738}
739
740#[cfg(test)]
741mod bottom_left {
742 use super::*;
743
744 #[test]
745 fn it_should_return_bottom_left() {
746 let rect: Rect<u32> = Rect(Point(3, 4), Size(9, 13));
747 assert_eq!(rect.bottom_left(), Point(3, 4));
748 }
749
750 #[test]
751 fn it_should_return_bottom_left_for_positive_sizes() {
752 let rect: Rect<i32> = Rect(Point(10, 12), Size(5, 8));
753 assert_eq!(rect.bottom_left(), Point(10, 12));
754 }
755
756 #[test]
757 fn it_should_account_for_negative_sizes() {
758 let rect: Rect<i32> = Rect(Point(10, 12), Size(-5, -8));
759 assert_eq!(rect.bottom_left(), Point(5, 4));
760 }
761}
762
763#[cfg(test)]
764mod bottom_right {
765 use super::*;
766
767 #[test]
768 fn it_should_return_bottom_right() {
769 let rect: Rect<u32> = Rect(Point(3, 4), Size(9, 13));
770 assert_eq!(rect.bottom_right(), Point(12, 4));
771 }
772}
773
774#[cfg(test)]
775mod top_left {
776 use super::*;
777
778 #[test]
779 fn it_should_return_top_left() {
780 let rect: Rect<u32> = Rect(Point(3, 4), Size(9, 13));
781 assert_eq!(rect.top_left(), Point(3, 17));
782 }
783}
784
785#[cfg(test)]
786mod top_right {
787 use super::*;
788
789 #[test]
790 fn it_should_return_top_right() {
791 let rect: Rect<u32> = Rect(Point(3, 4), Size(9, 13));
792 assert_eq!(rect.top_right(), Point(12, 17));
793 }
794}
795
796#[cfg(test)]
797mod bottom_centre {
798 use super::*;
799
800 #[test]
801 fn it_should_return_bottom_centre() {
802 let rect: Rect<u32> = Rect(Point(3, 4), Size(10, 13));
803 assert_eq!(rect.bottom_centre(), Point(8, 4));
804 }
805}
806
807#[cfg(test)]
808mod top_centre {
809 use super::*;
810
811 #[test]
812 fn it_should_return_top_centre() {
813 let rect: Rect<u32> = Rect(Point(3, 4), Size(10, 13));
814 assert_eq!(rect.top_centre(), Point(8, 17));
815 }
816}
817
818#[cfg(test)]
819mod left_centre {
820 use super::*;
821
822 #[test]
823 fn it_should_return_left_centre() {
824 let rect: Rect<u32> = Rect(Point(3, 4), Size(10, 14));
825 assert_eq!(rect.left_centre(), Point(3, 11));
826 }
827}
828
829#[cfg(test)]
830mod right_centre {
831 use super::*;
832
833 #[test]
834 fn it_should_return_right_centre() {
835 let rect: Rect<u32> = Rect(Point(3, 4), Size(10, 14));
836 assert_eq!(rect.right_centre(), Point(13, 11));
837 }
838}
839
840#[cfg(test)]
841mod point_position {
842 use super::*;
843
844 #[test]
845 fn it_should_return_bottom_left() {
846 let rect: Rect<u32> = Rect(Point(10, 12), Size(10, 8));
847 assert_eq!(
848 rect.point_position(Point(3, 4)),
849 PointPosition(HorizontalPosition::Left, VerticalPosition::Below)
850 );
851 }
852
853 #[test]
854 fn it_should_return_middle_left() {
855 let rect: Rect<u32> = Rect(Point(10, 12), Size(10, 8));
856 assert_eq!(
857 rect.point_position(Point(3, 16)),
858 PointPosition(HorizontalPosition::Left, VerticalPosition::Inside)
859 );
860 }
861
862 #[test]
863 fn it_should_return_above_left() {
864 let rect: Rect<u32> = Rect(Point(10, 12), Size(10, 8));
865 assert_eq!(
866 rect.point_position(Point(3, 24)),
867 PointPosition(HorizontalPosition::Left, VerticalPosition::Above)
868 );
869 }
870
871 #[test]
872 fn it_should_return_bottom_middle() {
873 let rect: Rect<u32> = Rect(Point(10, 12), Size(10, 8));
874 assert_eq!(
875 rect.point_position(Point(13, 4)),
876 PointPosition(HorizontalPosition::Inside, VerticalPosition::Below)
877 );
878 }
879
880 #[test]
881 fn it_should_return_middle_middle() {
882 let rect: Rect<u32> = Rect(Point(10, 12), Size(10, 8));
883 assert_eq!(
884 rect.point_position(Point(13, 14)),
885 PointPosition(HorizontalPosition::Inside, VerticalPosition::Inside)
886 );
887 }
888
889 #[test]
890 fn it_should_return_above_middle() {
891 let rect: Rect<u32> = Rect(Point(10, 12), Size(10, 8));
892 assert_eq!(
893 rect.point_position(Point(13, 24)),
894 PointPosition(HorizontalPosition::Inside, VerticalPosition::Above)
895 );
896 }
897
898 #[test]
899 fn it_should_return_bottom_right() {
900 let rect: Rect<u32> = Rect(Point(10, 12), Size(10, 8));
901 assert_eq!(
902 rect.point_position(Point(30, 4)),
903 PointPosition(HorizontalPosition::Right, VerticalPosition::Below)
904 );
905 }
906
907 #[test]
908 fn it_should_return_middle_right() {
909 let rect: Rect<u32> = Rect(Point(10, 12), Size(10, 8));
910 assert_eq!(
911 rect.point_position(Point(30, 14)),
912 PointPosition(HorizontalPosition::Right, VerticalPosition::Inside)
913 );
914 }
915
916 #[test]
917 fn it_should_return_above_right() {
918 let rect: Rect<u32> = Rect(Point(10, 12), Size(10, 8));
919 assert_eq!(
920 rect.point_position(Point(30, 34)),
921 PointPosition(HorizontalPosition::Right, VerticalPosition::Above)
922 );
923 }
924}
925
926#[cfg(test)]
927mod centre_to {
928 use super::*;
929
930 #[test]
931 fn it_should_return_line_from_first_rect_to_second() {
932 let first_rect = Rect::new_from_centre(Point(24_i32, 123_i32), Size(100_i32, 200_i32));
933 let second_rect = Rect::new_from_centre(Point(999_i32, -283_i32), Size(100_i32, 200_i32));
934 let line = first_rect.centre_to(second_rect);
935
936 assert_eq!(line, Line(Point(24_i32, 123_i32), Point(999_i32, -283_i32)));
937 }
938}
939
940#[cfg(test)]
941mod interpolate_to {
942 use super::*;
943
944 #[test]
945 fn it_should_interpolate_centre() {
946 let first_rect: Rect<f32> = Rect::new_from_centre(Point(100.0, 200.0), Size(100.0, 200.0));
947 let second_rect: Rect<f32> =
948 Rect::new_from_centre(Point(1100.0, -400.0), Size(100.0, 200.0));
949 let interpolated_rect: Rect<f32> = first_rect.interpolate_to(second_rect, 0.5);
950
951 assert_eq!(
952 interpolated_rect,
953 Rect::new_from_centre(Point(600.0, -100.0), Size(100.0, 200.0))
954 );
955 }
956
957 #[test]
958 fn it_should_interpolate_size() {
959 let first_rect: Rect<f32> = Rect::new_from_centre(Point(100.0, 200.0), Size(100.0, 200.0));
960 let second_rect: Rect<f32> =
961 Rect::new_from_centre(Point(1100.0, -400.0), Size(200.0, 100.0));
962 let interpolated_rect: Rect<f32> = first_rect.interpolate_to(second_rect, 0.5);
963
964 assert_eq!(
965 interpolated_rect,
966 Rect::new_from_centre(Point(600.0, -100.0), Size(150.0, 150.0))
967 );
968 }
969}
970
971#[cfg(test)]
972mod round_to_max_size {
973 use super::*;
974 use crate::geom::testing_utils::assert_approx_rect_eq;
975 use testcat::*;
976
977 it!(
978 "should enlarge positive rectangles to make size larger",
979 test_positive_rect
980 );
981 it!(
982 "should enlarge positive rectangles with an inverse size",
983 test_positive_rect_with_negative_size
984 );
985 it!(
986 "should enlarge negative rectangles to make size larger",
987 test_negative_rect
988 );
989 it!(
990 "should enlarge negative rectangles with an inverse size",
991 test_negative_rect_with_negative_size
992 );
993 it!(
994 "should enlarge rectangles that cross zero to make size larger",
995 test_cross_zero_rect
996 );
997 it!(
998 "should enlarge rectangles that cross zero with an inverse size",
999 test_cross_zero_rect_with_negative_size
1000 );
1001
1002 fn test_positive_rect() {
1003 let rect: Rect<f32> = Point(10.2, 10.8).rect_to(Point(19.2, 19.8));
1004 let rounded = rect.round_to_max_size();
1005 let expected: Rect<f32> = Point(10.0, 10.0).rect_to(Point(20.0, 20.0));
1006
1007 assert_approx_rect_eq(expected, rounded);
1008 }
1009
1010 fn test_positive_rect_with_negative_size() {
1011 let rect: Rect<f32> = Point(19.2, 19.8).rect_to(Point(10.2, 10.8));
1012 let rounded = rect.round_to_max_size();
1013 let expected: Rect<f32> = Point(20.0, 20.0).rect_to(Point(10.0, 10.0));
1014
1015 assert_approx_rect_eq(expected, rounded);
1016 }
1017
1018 fn test_negative_rect() {
1019 let rect: Rect<f32> = Point(-10.2, -10.8).rect_to(Point(-19.2, -19.8));
1020 let rounded = rect.round_to_max_size();
1021 let expected: Rect<f32> = Point(-10.0, -10.0).rect_to(Point(-20.0, -20.0));
1022
1023 assert_approx_rect_eq(expected, rounded);
1024 }
1025
1026 fn test_negative_rect_with_negative_size() {
1027 let rect: Rect<f32> = Point(-19.2, -19.8).rect_to(Point(-10.2, -10.8));
1028 let rounded = rect.round_to_max_size();
1029 let expected: Rect<f32> = Point(-20.0, -20.0).rect_to(Point(-10.0, -10.0));
1030
1031 assert_approx_rect_eq(expected, rounded);
1032 }
1033
1034 fn test_cross_zero_rect() {
1035 let rect: Rect<f32> = Point(-10.2, -10.8).rect_to(Point(19.2, 19.8));
1036 let rounded = rect.round_to_max_size();
1037 let expected: Rect<f32> = Point(-11.0, -11.0).rect_to(Point(20.0, 20.0));
1038
1039 assert_approx_rect_eq(expected, rounded);
1040 }
1041
1042 fn test_cross_zero_rect_with_negative_size() {
1043 let rect: Rect<f32> = Point(19.2, 19.8).rect_to(Point(-10.2, -10.8));
1044 let rounded = rect.round_to_max_size();
1045 let expected: Rect<f32> = Point(20.0, 20.0).rect_to(Point(-11.0, -11.0));
1046
1047 assert_approx_rect_eq(expected, rounded);
1048 }
1049}
1050
1051#[cfg(test)]
1052mod mul_n {
1053 use super::*;
1054
1055 #[test]
1056 fn it_should_multiply_rect() {
1057 let rect: Rect<u32> = Rect::new_from_centre(Point(10, 12), Size(6, 8));
1058 let doubled = rect * 2;
1059
1060 assert_eq!(doubled, Rect::new_from_centre(Point(20, 24), Size(12, 16)));
1061 }
1062
1063 #[test]
1064 fn it_should_multiply_rect_using_left_hand() {
1065 let rect: Rect<u32> = Rect::new_from_centre(Point(10, 12), Size(6, 8));
1066 let doubled = 2 * rect;
1067
1068 assert_eq!(doubled, Rect::new_from_centre(Point(20, 24), Size(12, 16)));
1069 }
1070}
1071
1072#[cfg(test)]
1073mod div_n {
1074 use super::*;
1075
1076 #[test]
1077 fn it_should_divide_rect() {
1078 let rect: Rect<u32> = Rect::new_from_centre(Point(20, 24), Size(12, 16));
1079 let doubled = rect / 2;
1080
1081 assert_eq!(doubled, Rect::new_from_centre(Point(10, 12), Size(6, 8)));
1082 }
1083
1084 #[test]
1085 fn it_should_divide_rect_using_left_hand() {
1086 let rect: Rect<u32> = Rect::new_from_centre(Point(20, 24), Size(12, 16));
1087 let doubled = 2 / rect;
1088
1089 assert_eq!(doubled, Rect::new_from_centre(Point(10, 12), Size(6, 8)));
1090 }
1091}