1use std::ops::{Deref, DerefMut};
26
27use crate::core::algebra::Vector2;
28
29#[derive(Copy, Clone, Debug, PartialEq, Eq)]
40pub struct TileRect {
41 pub position: Vector2<i32>,
43 pub size: Vector2<i32>,
45}
46
47#[derive(Default, Copy, Clone, Debug, PartialEq, Eq)]
49pub struct OptionTileRect(Option<TileRect>);
50
51#[derive(Debug, Clone)]
52pub struct RectIter(Vector2<i32>, TileRect);
54#[derive(Debug, Clone)]
56pub struct OptionRectIter(Option<RectIter>);
57
58impl Iterator for RectIter {
59 type Item = Vector2<i32>;
60
61 fn next(&mut self) -> Option<Self::Item> {
62 if self.0.y >= self.1.h() {
63 return None;
64 }
65 let result = self.0 + self.1.position;
66 self.0.x += 1;
67 if self.0.x >= self.1.w() {
68 self.0.x = 0;
69 self.0.y += 1;
70 }
71 Some(result)
72 }
73}
74
75impl Iterator for OptionRectIter {
76 type Item = Vector2<i32>;
77
78 fn next(&mut self) -> Option<Self::Item> {
79 self.0.as_mut()?.next()
80 }
81}
82
83impl From<RectIter> for OptionRectIter {
84 fn from(value: RectIter) -> Self {
85 Self(Some(value))
86 }
87}
88
89impl From<TileRect> for OptionTileRect {
90 fn from(source: TileRect) -> Self {
91 Self(Some(source))
92 }
93}
94impl From<Option<TileRect>> for OptionTileRect {
95 fn from(source: Option<TileRect>) -> Self {
96 Self(source)
97 }
98}
99impl Deref for OptionTileRect {
100 type Target = Option<TileRect>;
101
102 fn deref(&self) -> &Self::Target {
103 &self.0
104 }
105}
106
107impl DerefMut for OptionTileRect {
108 fn deref_mut(&mut self) -> &mut Self::Target {
109 &mut self.0
110 }
111}
112
113impl IntoIterator for OptionTileRect {
114 type Item = Vector2<i32>;
115
116 type IntoIter = OptionRectIter;
117
118 fn into_iter(self) -> Self::IntoIter {
119 self.iter()
120 }
121}
122
123impl OptionTileRect {
124 pub fn from_points(p0: Vector2<i32>, p1: Vector2<i32>) -> Self {
127 TileRect::from_points(p0, p1).into()
128 }
129
130 pub fn iter(&self) -> OptionRectIter {
132 OptionRectIter(self.0.map(|x| x.iter()))
133 }
134
135 #[inline]
138 #[must_use = "this method creates new instance of OptionTileRect"]
139 pub fn deflate(&self, dw: i32, dh: i32) -> Self {
140 if let Some(rect) = &self.0 {
141 rect.deflate(dw, dh)
142 } else {
143 Self(None)
144 }
145 }
146
147 #[inline]
149 pub fn clip(&mut self, bounds: TileRect) {
150 if let Some(rect) = &self.0 {
151 *self = rect.clip_by(bounds);
152 }
153 }
154 #[inline]
156 pub fn push(&mut self, p: Vector2<i32>) {
157 if let Some(rect) = &mut self.0 {
158 rect.push(p);
159 } else {
160 self.0 = Some(TileRect::new(p.x, p.y, 1, 1));
161 }
162 }
163 #[inline]
165 pub fn contains(&self, p: Vector2<i32>) -> bool {
166 if let Some(rect) = &self.0 {
167 rect.contains(p)
168 } else {
169 false
170 }
171 }
172 #[inline]
174 pub fn intersects(&self, other: TileRect) -> bool {
175 if let Some(rect) = &self.0 {
176 rect.intersects(other)
177 } else {
178 false
179 }
180 }
181
182 #[inline]
184 pub fn extend_to_contain(&mut self, other: TileRect) {
185 if let Some(rect) = &mut self.0 {
186 rect.extend_to_contain(other);
187 } else {
188 self.0 = Some(other);
189 }
190 }
191 #[inline(always)]
193 pub fn w(&self) -> i32 {
194 if let Some(rect) = &self.0 {
195 rect.size.x
196 } else {
197 0
198 }
199 }
200
201 #[inline(always)]
203 pub fn h(&self) -> i32 {
204 if let Some(rect) = &self.0 {
205 rect.size.y
206 } else {
207 0
208 }
209 }
210}
211
212impl IntoIterator for TileRect {
213 type Item = Vector2<i32>;
214
215 type IntoIter = RectIter;
216
217 fn into_iter(self) -> Self::IntoIter {
218 self.iter()
219 }
220}
221
222impl TileRect {
223 #[inline]
225 pub fn new(x: i32, y: i32, w: i32, h: i32) -> Self {
226 Self {
227 position: Vector2::new(x, y),
228 size: Vector2::new(w, h),
229 }
230 }
231
232 #[inline]
234 pub fn iter(&self) -> RectIter {
235 RectIter(Vector2::new(0, 0), *self)
236 }
237
238 pub fn from_points(p0: Vector2<i32>, p1: Vector2<i32>) -> Self {
241 let inf = p0.inf(&p1);
242 let sup = p0.sup(&p1);
243 Self {
244 position: inf,
245 size: sup - inf + Vector2::new(1, 1),
246 }
247 }
248
249 #[inline]
251 pub fn with_position(mut self, position: Vector2<i32>) -> Self {
252 self.position = position;
253 self
254 }
255
256 #[inline]
258 pub fn with_size(mut self, size: Vector2<i32>) -> Self {
259 self.size = size;
260 self
261 }
262
263 #[inline]
266 #[must_use = "this method creates new instance of TileRect"]
267 pub fn inflate(&self, dw: i32, dh: i32) -> Self {
268 Self {
269 position: Vector2::new(self.position.x - dw, self.position.y - dh),
270 size: Vector2::new(self.size.x + dw + dw, self.size.y + dh + dh),
271 }
272 }
273
274 #[inline]
277 #[must_use = "this method creates new instance of OptionTileRect"]
278 pub fn deflate(&self, dw: i32, dh: i32) -> OptionTileRect {
279 if self.size.x > dw + dw && self.size.y > dh + dh {
280 OptionTileRect(Some(TileRect {
281 position: Vector2::new(self.position.x + dw, self.position.y + dh),
282 size: Vector2::new(self.size.x - (dw + dw), self.size.y - (dh + dh)),
283 }))
284 } else {
285 OptionTileRect(None)
286 }
287 }
288
289 #[inline]
291 pub fn contains(&self, pt: Vector2<i32>) -> bool {
292 pt.x >= self.position.x
293 && pt.x < self.position.x + self.size.x
294 && pt.y >= self.position.y
295 && pt.y < self.position.y + self.size.y
296 }
297
298 #[inline]
300 pub fn center(&self) -> Vector2<i32> {
301 self.position + Vector2::new(self.size.x / 2, self.size.y / 2)
302 }
303
304 #[inline]
306 pub fn push(&mut self, p: Vector2<i32>) {
307 let p0 = self.left_bottom_corner();
308 let p1 = self.right_top_corner();
309 *self = Self::from_points(p.inf(&p0), p.sup(&p1));
310 }
311
312 #[inline]
316 #[must_use = "this method creates new instance of OptionTileRect"]
317 pub fn clip_by(&self, other: TileRect) -> OptionTileRect {
318 let mut clipped = *self;
319
320 if other.x() + other.w() <= self.x()
321 || other.x() >= self.x() + self.w()
322 || other.y() + other.h() <= self.y()
323 || other.y() >= self.y() + self.h()
324 {
325 return OptionTileRect::default();
326 }
327
328 if clipped.position.x < other.position.x {
329 clipped.size.x -= other.position.x - clipped.position.x;
330 clipped.position.x = other.position.x;
331 }
332
333 if clipped.position.y < other.position.y {
334 clipped.size.y -= other.position.y - clipped.position.y;
335 clipped.position.y = other.position.y;
336 }
337
338 let clipped_right_top = clipped.right_top_corner();
339 let other_right_top = other.right_top_corner();
340
341 if clipped_right_top.x > other_right_top.x {
342 clipped.size.x -= clipped_right_top.x - other_right_top.x;
343 }
344 if clipped_right_top.y > other_right_top.y {
345 clipped.size.y -= clipped_right_top.y - other_right_top.y;
346 }
347
348 clipped.into()
349 }
350
351 #[inline]
353 pub fn intersects(&self, other: TileRect) -> bool {
354 if other.position.x < self.position.x + self.size.x
355 && self.position.x < other.position.x + other.size.x
356 && other.position.y < self.position.y + self.size.y
357 {
358 self.position.y < other.position.y + other.size.y
359 } else {
360 false
361 }
362 }
363
364 #[inline]
366 #[must_use = "this method creates new instance of TileRect"]
367 pub fn translate(&self, translation: Vector2<i32>) -> Self {
368 Self {
369 position: Vector2::new(
370 self.position.x + translation.x,
371 self.position.y + translation.y,
372 ),
373 size: self.size,
374 }
375 }
376
377 #[inline]
379 pub fn extend_to_contain(&mut self, other: TileRect) {
380 let p0 = self.left_bottom_corner();
381 let p1 = self.right_top_corner();
382 let o0 = other.left_bottom_corner();
383 let o1 = other.right_top_corner();
384 *self = Self::from_points(p0.inf(&o0), p1.sup(&o1));
385 }
386
387 #[inline(always)]
389 pub fn left_top_corner(&self) -> Vector2<i32> {
390 Vector2::new(self.position.x, self.position.y + self.size.y - 1)
391 }
392
393 #[inline(always)]
395 pub fn right_top_corner(&self) -> Vector2<i32> {
396 Vector2::new(
397 self.position.x + self.size.x - 1,
398 self.position.y + self.size.y - 1,
399 )
400 }
401
402 #[inline(always)]
404 pub fn right_bottom_corner(&self) -> Vector2<i32> {
405 Vector2::new(self.position.x + self.size.x - 1, self.position.y)
406 }
407
408 #[inline(always)]
410 pub fn left_bottom_corner(&self) -> Vector2<i32> {
411 self.position
412 }
413
414 #[inline(always)]
416 pub fn w(&self) -> i32 {
417 self.size.x
418 }
419
420 #[inline(always)]
422 pub fn h(&self) -> i32 {
423 self.size.y
424 }
425
426 #[inline(always)]
428 pub fn x(&self) -> i32 {
429 self.position.x
430 }
431
432 #[inline(always)]
434 pub fn y(&self) -> i32 {
435 self.position.y
436 }
437}
438
439#[cfg(test)]
440mod tests {
441 use super::*;
442 #[test]
443 fn iter() {
444 let mut iter = TileRect::new(2, 3, 3, 2).iter();
445 assert_eq!(iter.next(), Some(Vector2::new(2, 3)));
446 assert_eq!(iter.next(), Some(Vector2::new(3, 3)));
447 assert_eq!(iter.next(), Some(Vector2::new(4, 3)));
448 assert_eq!(iter.next(), Some(Vector2::new(2, 4)));
449 assert_eq!(iter.next(), Some(Vector2::new(3, 4)));
450 assert_eq!(iter.next(), Some(Vector2::new(4, 4)));
451 assert_eq!(iter.next(), None);
452 }
453 #[test]
454 fn intersects1() {
455 let rect1 = TileRect::new(-1, -2, 4, 6);
456 let rect2 = TileRect::new(2, 3, 2, 2);
457 assert!(rect1.intersects(rect2));
458 }
459 #[test]
460 fn intersects2() {
461 let rect1 = TileRect::new(0, 0, 4, 6);
462 let rect2 = TileRect::new(-1, -2, 2, 3);
463 assert!(rect1.intersects(rect2));
464 }
465 #[test]
466 fn not_intersects1() {
467 let rect1 = TileRect::new(-1, -2, 3, 4);
468 let rect2 = TileRect::new(3, 3, 2, 2);
469 assert!(!rect1.intersects(rect2));
470 }
471 #[test]
472 fn not_intersects2() {
473 let rect1 = TileRect::new(-1, -2, 3, 4);
474 let rect2 = TileRect::new(2, 1, 2, 2);
475 assert!(!rect1.intersects(rect2));
476 }
477 #[test]
478 fn from_points1() {
479 let rect = TileRect::from_points(Vector2::new(-1, -2), Vector2::new(2, 1));
480 assert_eq!(rect, TileRect::new(-1, -2, 4, 4));
481 }
482 #[test]
483 fn from_points2() {
484 let rect = TileRect::from_points(Vector2::new(-1, 1), Vector2::new(2, -2));
485 assert_eq!(rect, TileRect::new(-1, -2, 4, 4));
486 }
487 #[test]
488 fn rect_extend_to_contain() {
489 let mut rect = TileRect::new(0, 0, 1, 1);
490
491 rect.extend_to_contain(TileRect::new(1, 1, 1, 1));
492 assert_eq!(rect, TileRect::new(0, 0, 2, 2));
493
494 rect.extend_to_contain(TileRect::new(-1, -1, 1, 1));
495 assert_eq!(rect, TileRect::new(-1, -1, 3, 3));
496
497 rect.extend_to_contain(TileRect::new(10, -1, 1, 15));
498 assert_eq!(rect, TileRect::new(-1, -1, 12, 15));
499 }
500 #[test]
501 fn rect_push2() {
502 let mut rect = TileRect::new(0, 0, 1, 1);
503
504 rect.push(Vector2::new(1, 1));
505 assert_eq!(rect, TileRect::new(0, 0, 2, 2));
506
507 rect.push(Vector2::new(-1, -1));
508 assert_eq!(rect, TileRect::new(-1, -1, 3, 3));
509
510 rect.push(Vector2::new(10, -1));
511 assert_eq!(rect, TileRect::new(-1, -1, 12, 3));
512 }
513 #[test]
514 fn option_rect_extend_to_contain() {
515 let mut rect = OptionTileRect::default();
516
517 rect.extend_to_contain(TileRect::new(1, 1, 1, 1));
518 assert_eq!(rect.unwrap(), TileRect::new(1, 1, 1, 1));
519
520 rect.extend_to_contain(TileRect::new(-1, -1, 1, 1));
521 assert_eq!(rect.unwrap(), TileRect::new(-1, -1, 3, 3));
522
523 rect.extend_to_contain(TileRect::new(10, -1, 1, 15));
524 assert_eq!(rect.unwrap(), TileRect::new(-1, -1, 12, 15));
525 }
526 #[test]
527 fn option_rect_push() {
528 let mut rect = OptionTileRect::default();
529
530 rect.push(Vector2::new(1, 1));
531 assert_eq!(rect.unwrap(), TileRect::new(1, 1, 1, 1));
532
533 rect.push(Vector2::new(-1, -1));
534 assert_eq!(rect.unwrap(), TileRect::new(-1, -1, 3, 3));
535
536 rect.push(Vector2::new(10, -1));
537 assert_eq!(rect.unwrap(), TileRect::new(-1, -1, 12, 3));
538 }
539 #[test]
540 fn option_rect_clip() {
541 let rect = OptionTileRect::from(TileRect::new(0, 0, 10, 10));
542
543 let mut r = rect;
544 r.clip(TileRect::new(2, 2, 1, 1));
545 assert_eq!(r.unwrap(), TileRect::new(2, 2, 1, 1));
546
547 let mut r = rect;
548 r.clip(TileRect::new(0, 0, 15, 15));
549 assert_eq!(r.unwrap(), TileRect::new(0, 0, 10, 10));
550
551 let mut r = OptionTileRect::default();
553 r.clip(TileRect::new(0, 0, 10, 10));
554 assert!(r.is_none());
555 let mut r = rect;
556 r.clip(TileRect::new(-2, 1, 1, 1));
557 assert!(r.is_none());
558 let mut r = rect;
559 r.clip(TileRect::new(11, 1, 1, 1));
560 assert!(r.is_none());
561 let mut r = rect;
562 r.clip(TileRect::new(1, -2, 1, 1));
563 assert!(r.is_none());
564 let mut r = rect;
565 r.clip(TileRect::new(1, 11, 1, 1));
566 assert!(r.is_none());
567 }
568
569 #[test]
570 fn rect_with_position() {
571 let rect = TileRect::new(0, 0, 1, 1);
572
573 assert_eq!(
574 rect.with_position(Vector2::new(1, 1)),
575 TileRect::new(1, 1, 1, 1)
576 );
577 }
578
579 #[test]
580 fn rect_with_size() {
581 let rect = TileRect::new(0, 0, 1, 1);
582
583 assert_eq!(
584 rect.with_size(Vector2::new(10, 10)),
585 TileRect::new(0, 0, 10, 10)
586 );
587 }
588
589 #[test]
590 fn rect_inflate() {
591 let rect = TileRect::new(0, 0, 1, 1);
592
593 assert_eq!(rect.inflate(5, 5), TileRect::new(-5, -5, 11, 11));
594 }
595
596 #[test]
597 fn rect_deflate() {
598 let rect = TileRect::new(-5, -5, 11, 11);
599
600 assert_eq!(rect.deflate(5, 5), TileRect::new(0, 0, 1, 1).into());
601 assert_eq!(rect.deflate(6, 5), OptionTileRect::default());
602 }
603
604 #[test]
605 fn rect_contains() {
606 let rect = TileRect::new(0, 0, 10, 10);
607
608 assert!(rect.contains(Vector2::new(0, 0)));
609 assert!(rect.contains(Vector2::new(0, 9)));
610 assert!(rect.contains(Vector2::new(9, 0)));
611 assert!(rect.contains(Vector2::new(9, 9)));
612 assert!(rect.contains(Vector2::new(5, 5)));
613
614 assert!(!rect.contains(Vector2::new(0, 10)));
615 }
616
617 #[test]
618 fn rect_center() {
619 let rect = TileRect::new(0, 0, 10, 10);
620
621 assert_eq!(rect.center(), Vector2::new(5, 5));
622 }
623
624 #[test]
625 fn rect_push() {
626 let mut rect = TileRect::new(10, 10, 10, 10);
627
628 rect.push(Vector2::new(0, 0));
629 assert_eq!(rect, TileRect::new(0, 0, 20, 20));
630
631 rect.push(Vector2::new(0, 20));
632 assert_eq!(rect, TileRect::new(0, 0, 20, 21));
633
634 rect.push(Vector2::new(20, 20));
635 assert_eq!(rect, TileRect::new(0, 0, 21, 21));
636
637 rect.push(Vector2::new(30, 30));
638 assert_eq!(rect, TileRect::new(0, 0, 31, 31));
639 }
640
641 #[test]
642 fn rect_getters() {
643 let rect = TileRect::new(0, 0, 2, 2);
644
645 assert_eq!(rect.left_bottom_corner(), Vector2::new(0, 0));
646 assert_eq!(rect.left_top_corner(), Vector2::new(0, 1));
647 assert_eq!(rect.right_bottom_corner(), Vector2::new(1, 0));
648 assert_eq!(rect.right_top_corner(), Vector2::new(1, 1));
649
650 assert_eq!(rect.x(), 0);
651 assert_eq!(rect.y(), 0);
652 assert_eq!(rect.w(), 2);
653 assert_eq!(rect.h(), 2);
654 }
655
656 #[test]
657 fn rect_clip_by() {
658 let rect = TileRect::new(0, 0, 10, 10);
659
660 assert_eq!(
661 rect.clip_by(TileRect::new(2, 2, 1, 1)).unwrap(),
662 TileRect::new(2, 2, 1, 1)
663 );
664 assert_eq!(
665 rect.clip_by(TileRect::new(0, 0, 15, 15)).unwrap(),
666 TileRect::new(0, 0, 10, 10)
667 );
668
669 assert!(rect.clip_by(TileRect::new(-2, 1, 1, 1)).is_none());
671 assert!(rect.clip_by(TileRect::new(11, 1, 1, 1)).is_none());
672 assert!(rect.clip_by(TileRect::new(1, -2, 1, 1)).is_none());
673 assert!(rect.clip_by(TileRect::new(1, 11, 1, 1)).is_none());
674 }
675
676 #[test]
677 fn rect_translate() {
678 let rect = TileRect::new(0, 0, 10, 10);
679
680 assert_eq!(
681 rect.translate(Vector2::new(5, 5)),
682 TileRect::new(5, 5, 10, 10)
683 );
684 }
685}