1use crate::color::Color;
2use serde::{Deserialize, Serialize};
3use std::cmp::Ordering;
4use std::f32::consts;
5use std::fmt;
6use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
7
8#[derive(Debug, Copy, Clone, Eq, PartialEq)]
9pub enum Dir {
10 North,
11 East,
12 South,
13 West,
14}
15
16impl Dir {
17 pub fn opposite(self) -> Dir {
18 match self {
19 Dir::North => Dir::South,
20 Dir::South => Dir::North,
21 Dir::East => Dir::West,
22 Dir::West => Dir::East,
23 }
24 }
25
26 pub fn axis(self) -> Axis {
27 match self {
28 Dir::North | Dir::South => Axis::Vertical,
29 Dir::East | Dir::West => Axis::Horizontal,
30 }
31 }
32}
33
34impl fmt::Display for Dir {
35 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
36 match self {
37 Dir::North => write!(f, "north"),
38 Dir::East => write!(f, "east"),
39 Dir::South => write!(f, "south"),
40 Dir::West => write!(f, "west"),
41 }
42 }
43}
44
45#[derive(Debug, Copy, Clone, Eq, PartialEq)]
46pub enum DiagDir {
47 NorthWest,
48 NorthEast,
49 SouthEast,
50 SouthWest,
51}
52
53impl DiagDir {
54 pub fn opposite(self) -> DiagDir {
55 match self {
56 DiagDir::NorthWest => DiagDir::SouthEast,
57 DiagDir::NorthEast => DiagDir::SouthWest,
58 DiagDir::SouthEast => DiagDir::NorthWest,
59 DiagDir::SouthWest => DiagDir::NorthEast,
60 }
61 }
62}
63
64impl fmt::Display for DiagDir {
65 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
66 match self {
67 DiagDir::NorthWest => write!(f, "northwest"),
68 DiagDir::NorthEast => write!(f, "northeast"),
69 DiagDir::SouthEast => write!(f, "southeast"),
70 DiagDir::SouthWest => write!(f, "southwest"),
71 }
72 }
73}
74
75#[derive(Debug, Copy, Clone, Eq, PartialEq)]
76pub enum Axis {
77 Horizontal,
78 Vertical,
79 Diagonal,
80}
81
82impl fmt::Display for Axis {
83 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
84 match self {
85 Axis::Horizontal => write!(f, "horizontal"),
86 Axis::Vertical => write!(f, "vertical"),
87 Axis::Diagonal => write!(f, "diagonal"),
88 }
89 }
90}
91
92#[derive(Debug, Copy, Clone, Eq, PartialEq)]
93pub enum CycleDir {
94 Next,
95 Previous,
96}
97
98#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
99pub enum LinearDir {
100 Backward,
101 Forward,
102}
103
104impl LinearDir {
105 pub fn opposite(self) -> LinearDir {
106 match self {
107 LinearDir::Backward => LinearDir::Forward,
108 LinearDir::Forward => LinearDir::Backward,
109 }
110 }
111}
112
113#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
114pub struct Point {
115 pub x: i32,
116 pub y: i32,
117}
118
119#[macro_export]
120macro_rules! pt {
121 ($x:expr, $y:expr $(,)* ) => {
122 $crate::geom::Point::new($x, $y)
123 };
124 ($a:expr) => {
125 $crate::geom::Point::new($a, $a)
126 };
127}
128
129impl fmt::Display for Point {
130 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
131 write!(f, "({}, {})", self.x, self.y)
132 }
133}
134
135#[derive(Debug, Copy, Clone)]
136pub struct Edge {
137 pub top: i32,
138 pub right: i32,
139 pub bottom: i32,
140 pub left: i32,
141}
142
143impl Edge {
144 pub fn uniform(value: i32) -> Edge {
145 Edge {
146 top: value,
147 right: value,
148 bottom: value,
149 left: value,
150 }
151 }
152}
153
154impl Default for Edge {
155 fn default() -> Self {
156 Edge {
157 top: 0,
158 right: 0,
159 bottom: 0,
160 left: 0,
161 }
162 }
163}
164
165impl Add for Edge {
166 type Output = Edge;
167 fn add(self, rhs: Edge) -> Edge {
168 Edge {
169 top: self.top + rhs.top,
170 right: self.right + rhs.right,
171 bottom: self.bottom + rhs.bottom,
172 left: self.left + rhs.left,
173 }
174 }
175}
176
177impl AddAssign for Edge {
178 fn add_assign(&mut self, rhs: Edge) {
179 self.top += rhs.top;
180 self.right += rhs.right;
181 self.bottom += rhs.bottom;
182 self.left += rhs.left;
183 }
184}
185
186impl Sub for Edge {
187 type Output = Edge;
188 fn sub(self, rhs: Edge) -> Edge {
189 Edge {
190 top: self.top - rhs.top,
191 right: self.right - rhs.right,
192 bottom: self.bottom - rhs.bottom,
193 left: self.left - rhs.left,
194 }
195 }
196}
197
198impl SubAssign for Edge {
199 fn sub_assign(&mut self, rhs: Edge) {
200 self.top -= rhs.top;
201 self.right -= rhs.right;
202 self.bottom -= rhs.bottom;
203 self.left -= rhs.left;
204 }
205}
206
207#[derive(Debug, Copy, Clone)]
208pub enum CornerSpec {
209 Uniform(i32),
210 North(i32),
211 East(i32),
212 South(i32),
213 West(i32),
214 Detailed {
215 north_west: i32,
216 north_east: i32,
217 south_east: i32,
218 south_west: i32,
219 },
220}
221
222pub trait ColorSource {
223 fn color(&self, x: i32, y: i32) -> Color;
224}
225
226impl<F> ColorSource for F
227where
228 F: Fn(i32, i32) -> Color,
229{
230 #[inline]
231 fn color(&self, x: i32, y: i32) -> Color {
232 (self)(x, y)
233 }
234}
235
236impl ColorSource for Color {
237 #[inline]
238 fn color(&self, _: i32, _: i32) -> Color {
239 *self
240 }
241}
242
243#[derive(Debug, Copy, Clone)]
244pub struct BorderSpec {
245 pub thickness: u16,
246 pub color: Color,
247}
248
249const HALF_PIXEL_DIAGONAL: f32 = consts::SQRT_2 / 2.0;
250
251pub fn surface_area(dist: f32, angle: f32) -> f32 {
255 if dist.abs() > HALF_PIXEL_DIAGONAL {
257 if dist.is_sign_positive() {
258 return 0.0;
259 } else {
260 return 1.0;
261 }
262 }
263 let expo = 0.5 * (3.0 - (4.0 * angle).cos());
267 let radius = 0.5 * expo.sqrt();
269 if dist.is_sign_positive() {
270 (radius - dist).max(0.0).powf(expo)
271 } else {
272 1.0 - (radius + dist).max(0.0).powf(expo)
273 }
274}
275
276pub fn nearest_segment_point(p: Vec2, a: Vec2, b: Vec2) -> (Vec2, f32) {
278 let ab = b - a;
279 let ap = p - a;
280 let l2 = ab.dot(ab);
281
282 if l2 < ::std::f32::EPSILON {
284 return (a, 0.0);
285 }
286
287 let t = (ap.dot(ab) / l2).clamp(0.0, 1.0);
288 (a + t * ab, t)
289}
290
291pub fn elbow(sp: &[Point]) -> usize {
292 let len = sp.len();
293 let a: Vec2 = sp[0].into();
294 let b: Vec2 = sp[len - 1].into();
295 let i1 = len / 3;
296 let i2 = 2 * len / 3;
297 let p1: Vec2 = sp[i1].into();
298 let p2: Vec2 = sp[i2].into();
299 let (n1, _) = nearest_segment_point(p1, a, b);
300 let (n2, _) = nearest_segment_point(p2, a, b);
301 let d1 = (p1 - n1).length();
302 let d2 = (p2 - n2).length();
303 if d1 > f32::EPSILON || d2 > f32::EPSILON {
304 ((d1 * i1 as f32 + d2 * i2 as f32) / (d1 + d2)) as usize
305 } else {
306 len / 2
307 }
308}
309
310#[inline]
311pub fn halves(n: i32) -> (i32, i32) {
312 let small_half = n / 2;
313 let big_half = n - small_half;
314 (small_half, big_half)
315}
316
317#[inline]
318pub fn small_half(n: i32) -> i32 {
319 n / 2
320}
321
322#[inline]
323pub fn big_half(n: i32) -> i32 {
324 n - small_half(n)
325}
326
327pub fn divide(n: i32, p: i32) -> Vec<i32> {
330 let size = n.checked_div(p).unwrap_or(0);
331 let mut rem = n - p * size;
332 let tick = p.checked_div(rem).unwrap_or(0);
333 let mut vec = Vec::with_capacity(p as usize);
334 for i in 0..p {
335 if rem > 0 && (i + 1) % tick == 0 {
336 vec.push(size + 1);
337 rem -= 1;
338 } else {
339 vec.push(size);
340 }
341 }
342 vec
343}
344
345#[inline]
346pub fn lerp(a: f32, b: f32, t: f32) -> f32 {
347 (1.0 - t) * a + t * b
348}
349
350#[inline]
352pub fn circular_distances(a: u16, mut b: u16, p: u16) -> (u16, u16) {
353 if b < a {
354 b += p;
355 }
356 let d0 = b - a;
357 let d1 = p - d0;
358 (d0, d1)
359}
360
361impl Point {
362 pub fn new(x: i32, y: i32) -> Point {
363 Point { x, y }
364 }
365
366 pub fn dist2(self, pt: Point) -> u32 {
367 ((pt.x - self.x).pow(2) + (pt.y - self.y).pow(2)) as u32
368 }
369
370 pub fn rdist2(self, rect: &Rectangle) -> u32 {
371 if rect.includes(self) {
372 0
373 } else if self.y >= rect.min.y && self.y < rect.max.y {
374 if self.x < rect.min.x {
375 (rect.min.x - self.x).pow(2) as u32
376 } else {
377 (self.x - rect.max.x + 1).pow(2) as u32
378 }
379 } else if self.x >= rect.min.x && self.x < rect.max.x {
380 if self.y < rect.min.y {
381 (rect.min.y - self.y).pow(2) as u32
382 } else {
383 (self.y - rect.max.y + 1).pow(2) as u32
384 }
385 } else if self.x < rect.min.x {
386 if self.y < rect.min.y {
387 self.dist2(rect.min)
388 } else {
389 self.dist2(Point::new(rect.min.x, rect.max.y - 1))
390 }
391 } else {
392 if self.y < rect.min.y {
393 self.dist2(Point::new(rect.max.x - 1, rect.min.y))
394 } else {
395 self.dist2(Point::new(rect.max.x - 1, rect.max.y - 1))
396 }
397 }
398 }
399
400 pub fn length(self) -> f32 {
401 ((self.x.pow(2) + self.y.pow(2)) as f32).sqrt()
402 }
403
404 pub fn angle(self) -> f32 {
405 (-self.y as f32).atan2(self.x as f32)
406 }
407
408 pub fn dir(self) -> Dir {
409 if self.x.abs() > self.y.abs() {
410 if self.x.is_positive() {
411 Dir::East
412 } else {
413 Dir::West
414 }
415 } else {
416 if self.y.is_positive() {
417 Dir::South
418 } else {
419 Dir::North
420 }
421 }
422 }
423
424 pub fn diag_dir(self) -> DiagDir {
425 if self.x.is_positive() {
426 if self.y.is_positive() {
427 DiagDir::SouthEast
428 } else {
429 DiagDir::NorthEast
430 }
431 } else {
432 if self.y.is_positive() {
433 DiagDir::SouthWest
434 } else {
435 DiagDir::NorthWest
436 }
437 }
438 }
439}
440
441impl Default for Point {
442 fn default() -> Self {
443 Point::new(0, 0)
444 }
445}
446
447impl Into<(f32, f32)> for Point {
448 fn into(self) -> (f32, f32) {
449 (self.x as f32, self.y as f32)
450 }
451}
452
453impl From<Point> for Vec2 {
454 fn from(pt: Point) -> Self {
455 Vec2::new(pt.x as f32, pt.y as f32)
456 }
457}
458
459impl From<Vec2> for Point {
460 fn from(pt: Vec2) -> Self {
461 Point::new(pt.x as i32, pt.y as i32)
462 }
463}
464
465#[derive(Debug, Copy, Clone)]
466pub struct Vec2 {
467 pub x: f32,
468 pub y: f32,
469}
470
471#[macro_export]
472macro_rules! vec2 {
473 ($x:expr, $y:expr $(,)* ) => {
474 $crate::geom::Vec2::new($x, $y)
475 };
476 ($a:expr) => {
477 $crate::geom::Vec2::new($a, $a)
478 };
479}
480
481impl Vec2 {
482 pub fn new(x: f32, y: f32) -> Vec2 {
483 Vec2 { x, y }
484 }
485
486 pub fn dot(self, other: Vec2) -> f32 {
487 self.x * other.x + self.y * other.y
488 }
489
490 pub fn cross(self, other: Vec2) -> f32 {
491 self.x * other.y - self.y * other.x
492 }
493
494 pub fn length(self) -> f32 {
495 self.x.hypot(self.y)
496 }
497
498 pub fn angle(self) -> f32 {
499 (-self.y).atan2(self.x)
500 }
501
502 pub fn dir(self) -> Dir {
503 if self.x.abs() > self.y.abs() {
504 if self.x.is_sign_positive() {
505 Dir::East
506 } else {
507 Dir::West
508 }
509 } else {
510 if self.y.is_sign_positive() {
511 Dir::South
512 } else {
513 Dir::North
514 }
515 }
516 }
517
518 pub fn diag_dir(self) -> DiagDir {
519 if self.x.is_sign_positive() {
520 if self.y.is_sign_positive() {
521 DiagDir::SouthEast
522 } else {
523 DiagDir::NorthEast
524 }
525 } else {
526 if self.y.is_sign_positive() {
527 DiagDir::SouthWest
528 } else {
529 DiagDir::NorthWest
530 }
531 }
532 }
533}
534
535#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
537pub struct Rectangle {
538 pub min: Point,
539 pub max: Point,
540}
541
542#[macro_export]
543macro_rules! rect {
544 ($x0:expr, $y0:expr, $x1:expr, $y1:expr $(,)* ) => {
545 $crate::geom::Rectangle::new(
546 $crate::geom::Point::new($x0, $y0),
547 $crate::geom::Point::new($x1, $y1),
548 )
549 };
550 ($min:expr, $max:expr $(,)* ) => {
551 $crate::geom::Rectangle::new($min, $max)
552 };
553}
554
555impl fmt::Display for Rectangle {
556 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
557 write!(
558 f,
559 "[{}, {}, {}, {}]",
560 self.min.x, self.min.y, self.max.x, self.max.y
561 )
562 }
563}
564
565impl Rectangle {
566 pub fn new(min: Point, max: Point) -> Rectangle {
567 Rectangle { min, max }
568 }
569
570 pub fn from_point(pt: Point) -> Rectangle {
571 Rectangle {
572 min: pt,
573 max: pt + 1,
574 }
575 }
576
577 pub fn from_disk(center: Point, radius: i32) -> Rectangle {
578 Rectangle {
579 min: center - radius,
580 max: center + radius,
581 }
582 }
583
584 pub fn from_segment(start: Point, end: Point, start_radius: i32, end_radius: i32) -> Rectangle {
585 let x_min = (start.x - start_radius).min(end.x - end_radius);
586 let x_max = (start.x + start_radius).max(end.x + end_radius);
587 let y_min = (start.y - start_radius).min(end.y - end_radius);
588 let y_max = (start.y + start_radius).max(end.y + end_radius);
589 Rectangle {
590 min: pt!(x_min, y_min),
591 max: pt!(x_max, y_max),
592 }
593 }
594
595 pub fn to_boundary(&self) -> Boundary {
596 Boundary {
597 min: Vec2::new(self.min.x as f32, self.min.y as f32),
598 max: Vec2::new(self.max.x as f32, self.max.y as f32),
599 }
600 }
601
602 pub fn diag2(&self) -> u32 {
603 self.min.dist2(self.max)
604 }
605
606 pub fn includes(&self, pt: Point) -> bool {
607 self.min.x <= pt.x && pt.x < self.max.x && self.min.y <= pt.y && pt.y < self.max.y
608 }
609
610 pub fn contains(&self, rect: &Rectangle) -> bool {
611 rect.min.x >= self.min.x
612 && rect.max.x <= self.max.x
613 && rect.min.y >= self.min.y
614 && rect.max.y <= self.max.y
615 }
616
617 pub fn overlaps(&self, rect: &Rectangle) -> bool {
618 self.min.x < rect.max.x
619 && rect.min.x < self.max.x
620 && self.min.y < rect.max.y
621 && rect.min.y < self.max.y
622 }
623
624 pub fn extends(&self, rect: &Rectangle) -> bool {
625 let dmin = [self.width(), self.height(), rect.width(), rect.height()]
626 .into_iter()
627 .min()
628 .unwrap() as i32
629 / 3;
630
631 if self.min.y >= rect.max.y && self.min.x < rect.max.x && rect.min.x < self.max.x {
633 (self.min.y - rect.max.y) <= dmin
634 } else if rect.min.x >= self.max.x && self.min.y < rect.max.y && rect.min.y < self.max.y {
636 (rect.min.x - self.max.x) <= dmin
637 } else if rect.min.y >= self.max.y && self.min.x < rect.max.x && rect.min.x < self.max.x {
639 (rect.min.y - self.max.y) <= dmin
640 } else if self.min.x >= rect.max.x && self.min.y < rect.max.y && rect.min.y < self.max.y {
642 (self.min.x - rect.max.x) <= dmin
643 } else {
644 false
645 }
646 }
647
648 pub fn touches(&self, rect: &Rectangle) -> bool {
649 ((self.min.x == rect.max.x
650 || self.max.x == rect.min.x
651 || self.min.x == rect.min.x
652 || self.max.x == rect.max.x)
653 && (self.max.y >= rect.min.y && self.min.y <= rect.max.y))
654 || ((self.min.y == rect.max.y
655 || self.max.y == rect.min.y
656 || self.min.y == rect.min.y
657 || self.max.y == rect.max.y)
658 && (self.max.x >= rect.min.x && self.min.x <= rect.max.x))
659 }
660
661 pub fn merge(&mut self, pt: Point) {
662 if pt.x < self.min.x {
663 self.min.x = pt.x;
664 }
665 if pt.x >= self.max.x {
666 self.max.x = pt.x + 1;
667 }
668 if pt.y < self.min.y {
669 self.min.y = pt.y;
670 }
671 if pt.y >= self.max.y {
672 self.max.y = pt.y + 1;
673 }
674 }
675
676 pub fn absorb(&mut self, rect: &Rectangle) {
677 if self.min.x > rect.min.x {
678 self.min.x = rect.min.x;
679 }
680 if self.max.x < rect.max.x {
681 self.max.x = rect.max.x;
682 }
683 if self.min.y > rect.min.y {
684 self.min.y = rect.min.y;
685 }
686 if self.max.y < rect.max.y {
687 self.max.y = rect.max.y;
688 }
689 }
690
691 pub fn intersection(&self, rect: &Rectangle) -> Option<Rectangle> {
692 if self.overlaps(rect) {
693 Some(Rectangle::new(
694 Point::new(self.min.x.max(rect.min.x), self.min.y.max(rect.min.y)),
695 Point::new(self.max.x.min(rect.max.x), self.max.y.min(rect.max.y)),
696 ))
697 } else {
698 None
699 }
700 }
701
702 pub fn is_empty(&self) -> bool {
703 self.max.x <= self.min.x || self.max.y <= self.min.y
704 }
705
706 #[inline]
707 pub fn width(&self) -> u32 {
708 (self.max.x - self.min.x) as u32
709 }
710
711 #[inline]
712 pub fn height(&self) -> u32 {
713 (self.max.y - self.min.y) as u32
714 }
715
716 #[inline]
717 pub fn ratio(&self) -> f32 {
718 self.width() as f32 / self.height() as f32
719 }
720
721 #[inline]
722 pub fn area(&self) -> u32 {
723 self.width() * self.height()
724 }
725
726 #[inline]
727 pub fn center(&self) -> Point {
728 (self.min + self.max) / 2
729 }
730
731 pub fn grow(&mut self, edges: &Edge) {
732 self.min.x -= edges.left;
733 self.min.y -= edges.top;
734 self.max.x += edges.right;
735 self.max.y += edges.bottom;
736 }
737
738 pub fn shrink(&mut self, edges: &Edge) {
739 self.min.x += edges.left;
740 self.min.y += edges.top;
741 self.max.x -= edges.right;
742 self.max.y -= edges.bottom;
743 }
744}
745
746impl Default for Rectangle {
747 fn default() -> Self {
748 Rectangle::new(Point::default(), Point::default())
749 }
750}
751
752impl From<(u32, u32)> for Rectangle {
753 fn from(dims: (u32, u32)) -> Rectangle {
754 Rectangle::new(Point::new(0, 0), Point::new(dims.0 as i32, dims.1 as i32))
755 }
756}
757
758impl PartialOrd for Rectangle {
759 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
760 Some(self.cmp(other))
761 }
762}
763
764impl Ord for Rectangle {
765 fn cmp(&self, other: &Self) -> Ordering {
766 if self.min.y >= other.max.y {
767 Ordering::Greater
768 } else if self.max.y <= other.min.y {
769 Ordering::Less
770 } else {
771 if self.min.x >= other.max.x {
772 Ordering::Greater
773 } else if self.max.x <= other.min.x {
774 Ordering::Less
775 } else {
776 Ordering::Equal
777 }
778 }
779 }
780}
781
782impl Add for Point {
783 type Output = Point;
784 fn add(self, rhs: Point) -> Point {
785 Point {
786 x: self.x + rhs.x,
787 y: self.y + rhs.y,
788 }
789 }
790}
791
792impl AddAssign for Point {
793 fn add_assign(&mut self, rhs: Point) {
794 self.x += rhs.x;
795 self.y += rhs.y;
796 }
797}
798
799impl Sub for Point {
800 type Output = Point;
801 fn sub(self, rhs: Point) -> Point {
802 Point {
803 x: self.x - rhs.x,
804 y: self.y - rhs.y,
805 }
806 }
807}
808
809impl SubAssign for Point {
810 fn sub_assign(&mut self, rhs: Point) {
811 self.x -= rhs.x;
812 self.y -= rhs.y;
813 }
814}
815
816impl Mul<Point> for Point {
817 type Output = Point;
818 fn mul(self, rhs: Point) -> Point {
819 Point {
820 x: self.x * rhs.x,
821 y: self.y * rhs.y,
822 }
823 }
824}
825
826impl MulAssign<Point> for Point {
827 fn mul_assign(&mut self, rhs: Point) {
828 self.x *= rhs.x;
829 self.y *= rhs.y;
830 }
831}
832
833impl Div<Point> for Point {
834 type Output = Point;
835 fn div(self, rhs: Point) -> Point {
836 Point {
837 x: self.x / rhs.x,
838 y: self.y / rhs.y,
839 }
840 }
841}
842
843impl DivAssign<Point> for Point {
844 fn div_assign(&mut self, rhs: Point) {
845 self.x /= rhs.x;
846 self.y /= rhs.y;
847 }
848}
849
850impl Add<i32> for Point {
851 type Output = Point;
852 fn add(self, rhs: i32) -> Point {
853 Point {
854 x: self.x + rhs,
855 y: self.y + rhs,
856 }
857 }
858}
859
860impl Add<Point> for i32 {
861 type Output = Point;
862 fn add(self, rhs: Point) -> Point {
863 Point {
864 x: self + rhs.x,
865 y: self + rhs.y,
866 }
867 }
868}
869
870impl AddAssign<i32> for Point {
871 fn add_assign(&mut self, rhs: i32) {
872 self.x += rhs;
873 self.y += rhs;
874 }
875}
876
877impl Sub<i32> for Point {
878 type Output = Point;
879 fn sub(self, rhs: i32) -> Point {
880 Point {
881 x: self.x - rhs,
882 y: self.y - rhs,
883 }
884 }
885}
886
887impl Sub<Point> for i32 {
888 type Output = Point;
889 fn sub(self, rhs: Point) -> Point {
890 Point {
891 x: self - rhs.x,
892 y: self - rhs.y,
893 }
894 }
895}
896
897impl SubAssign<i32> for Point {
898 fn sub_assign(&mut self, rhs: i32) {
899 self.x -= rhs;
900 self.y -= rhs;
901 }
902}
903
904impl Mul<i32> for Point {
905 type Output = Point;
906 fn mul(self, rhs: i32) -> Point {
907 Point {
908 x: self.x * rhs,
909 y: self.y * rhs,
910 }
911 }
912}
913
914impl Mul<Point> for i32 {
915 type Output = Point;
916 fn mul(self, rhs: Point) -> Point {
917 Point {
918 x: self * rhs.x,
919 y: self * rhs.y,
920 }
921 }
922}
923
924impl MulAssign<i32> for Point {
925 fn mul_assign(&mut self, rhs: i32) {
926 self.x *= rhs;
927 self.y *= rhs;
928 }
929}
930
931impl Div<i32> for Point {
932 type Output = Point;
933 fn div(self, rhs: i32) -> Point {
934 Point {
935 x: self.x / rhs,
936 y: self.y / rhs,
937 }
938 }
939}
940
941impl Div<Point> for i32 {
942 type Output = Point;
943 fn div(self, rhs: Point) -> Point {
944 Point {
945 x: self / rhs.x,
946 y: self / rhs.y,
947 }
948 }
949}
950
951impl DivAssign<i32> for Point {
952 fn div_assign(&mut self, rhs: i32) {
953 self.x /= rhs;
954 self.y /= rhs;
955 }
956}
957
958impl Add<Point> for Rectangle {
959 type Output = Rectangle;
960 fn add(self, rhs: Point) -> Rectangle {
961 Rectangle {
962 min: self.min + rhs,
963 max: self.max + rhs,
964 }
965 }
966}
967
968impl AddAssign<Point> for Rectangle {
969 fn add_assign(&mut self, rhs: Point) {
970 self.min += rhs;
971 self.max += rhs;
972 }
973}
974
975impl Sub<Point> for Rectangle {
976 type Output = Rectangle;
977 fn sub(self, rhs: Point) -> Rectangle {
978 Rectangle {
979 min: self.min - rhs,
980 max: self.max - rhs,
981 }
982 }
983}
984
985impl SubAssign<Point> for Rectangle {
986 fn sub_assign(&mut self, rhs: Point) {
987 self.min -= rhs;
988 self.max -= rhs;
989 }
990}
991
992impl Add for Vec2 {
993 type Output = Vec2;
994 fn add(self, rhs: Vec2) -> Vec2 {
995 Vec2 {
996 x: self.x + rhs.x,
997 y: self.y + rhs.y,
998 }
999 }
1000}
1001
1002impl AddAssign for Vec2 {
1003 fn add_assign(&mut self, rhs: Vec2) {
1004 self.x += rhs.x;
1005 self.y += rhs.y;
1006 }
1007}
1008
1009impl Sub for Vec2 {
1010 type Output = Vec2;
1011 fn sub(self, rhs: Vec2) -> Vec2 {
1012 Vec2 {
1013 x: self.x - rhs.x,
1014 y: self.y - rhs.y,
1015 }
1016 }
1017}
1018
1019impl SubAssign for Vec2 {
1020 fn sub_assign(&mut self, rhs: Vec2) {
1021 self.x -= rhs.x;
1022 self.y -= rhs.y;
1023 }
1024}
1025
1026impl Mul<Vec2> for Vec2 {
1027 type Output = Vec2;
1028 fn mul(self, rhs: Vec2) -> Vec2 {
1029 Vec2 {
1030 x: self.x * rhs.x,
1031 y: self.y * rhs.y,
1032 }
1033 }
1034}
1035
1036impl MulAssign<Vec2> for Vec2 {
1037 fn mul_assign(&mut self, rhs: Vec2) {
1038 self.x *= rhs.x;
1039 self.y *= rhs.y;
1040 }
1041}
1042
1043impl Div<Vec2> for Vec2 {
1044 type Output = Vec2;
1045 fn div(self, rhs: Vec2) -> Vec2 {
1046 Vec2 {
1047 x: self.x / rhs.x,
1048 y: self.y / rhs.y,
1049 }
1050 }
1051}
1052
1053impl DivAssign<Vec2> for Vec2 {
1054 fn div_assign(&mut self, rhs: Vec2) {
1055 self.x /= rhs.x;
1056 self.y /= rhs.y;
1057 }
1058}
1059
1060impl Add<f32> for Vec2 {
1061 type Output = Vec2;
1062 fn add(self, rhs: f32) -> Vec2 {
1063 Vec2 {
1064 x: self.x + rhs,
1065 y: self.y + rhs,
1066 }
1067 }
1068}
1069
1070impl Add<Vec2> for f32 {
1071 type Output = Vec2;
1072 fn add(self, rhs: Vec2) -> Vec2 {
1073 Vec2 {
1074 x: self + rhs.x,
1075 y: self + rhs.y,
1076 }
1077 }
1078}
1079
1080impl AddAssign<f32> for Vec2 {
1081 fn add_assign(&mut self, rhs: f32) {
1082 self.x += rhs;
1083 self.y += rhs;
1084 }
1085}
1086
1087impl Sub<f32> for Vec2 {
1088 type Output = Vec2;
1089 fn sub(self, rhs: f32) -> Vec2 {
1090 Vec2 {
1091 x: self.x - rhs,
1092 y: self.y - rhs,
1093 }
1094 }
1095}
1096
1097impl Sub<Vec2> for f32 {
1098 type Output = Vec2;
1099 fn sub(self, rhs: Vec2) -> Vec2 {
1100 Vec2 {
1101 x: self - rhs.x,
1102 y: self - rhs.y,
1103 }
1104 }
1105}
1106
1107impl SubAssign<f32> for Vec2 {
1108 fn sub_assign(&mut self, rhs: f32) {
1109 self.x -= rhs;
1110 self.y -= rhs;
1111 }
1112}
1113
1114impl Mul<f32> for Vec2 {
1115 type Output = Vec2;
1116 fn mul(self, rhs: f32) -> Vec2 {
1117 Vec2 {
1118 x: self.x * rhs,
1119 y: self.y * rhs,
1120 }
1121 }
1122}
1123
1124impl Mul<Vec2> for f32 {
1125 type Output = Vec2;
1126 fn mul(self, rhs: Vec2) -> Vec2 {
1127 Vec2 {
1128 x: self * rhs.x,
1129 y: self * rhs.y,
1130 }
1131 }
1132}
1133
1134impl MulAssign<f32> for Vec2 {
1135 fn mul_assign(&mut self, rhs: f32) {
1136 self.x *= rhs;
1137 self.y *= rhs;
1138 }
1139}
1140
1141impl Div<f32> for Vec2 {
1142 type Output = Vec2;
1143 fn div(self, rhs: f32) -> Vec2 {
1144 Vec2 {
1145 x: self.x / rhs,
1146 y: self.y / rhs,
1147 }
1148 }
1149}
1150
1151impl Div<Vec2> for f32 {
1152 type Output = Vec2;
1153 fn div(self, rhs: Vec2) -> Vec2 {
1154 Vec2 {
1155 x: self / rhs.x,
1156 y: self / rhs.y,
1157 }
1158 }
1159}
1160
1161impl DivAssign<f32> for Vec2 {
1162 fn div_assign(&mut self, rhs: f32) {
1163 self.x /= rhs;
1164 self.y /= rhs;
1165 }
1166}
1167
1168#[derive(Debug, Copy, Clone)]
1169pub struct Boundary {
1170 pub min: Vec2,
1171 pub max: Vec2,
1172}
1173
1174impl Boundary {
1175 pub fn new(min: Vec2, max: Vec2) -> Boundary {
1176 Boundary { min, max }
1177 }
1178
1179 pub fn to_rect(&self) -> Rectangle {
1180 Rectangle {
1181 min: Point::new(self.min.x.floor() as i32, self.min.y.floor() as i32),
1182 max: Point::new(self.max.x.ceil() as i32, self.max.y.ceil() as i32),
1183 }
1184 }
1185
1186 pub fn overlaps(&self, rect: &Boundary) -> bool {
1187 self.min.x < rect.max.x
1188 && rect.min.x < self.max.x
1189 && self.min.y < rect.max.y
1190 && rect.min.y < self.max.y
1191 }
1192
1193 pub fn contains(&self, rect: &Boundary) -> bool {
1194 rect.min.x >= self.min.x
1195 && rect.max.x <= self.max.x
1196 && rect.min.y >= self.min.y
1197 && rect.max.y <= self.max.y
1198 }
1199
1200 pub fn width(&self) -> f32 {
1201 self.max.x - self.min.x
1202 }
1203
1204 pub fn height(&self) -> f32 {
1205 self.max.y - self.min.y
1206 }
1207}
1208
1209#[macro_export]
1210macro_rules! bndr {
1211 ($x0:expr, $y0:expr, $x1:expr, $y1:expr $(,)* ) => {
1212 $crate::geom::Boundary::new(
1213 $crate::geom::Vec2::new($x0, $y0),
1214 $crate::geom::Vec2::new($x1, $y1),
1215 )
1216 };
1217 ($min:expr, $max:expr $(,)* ) => {
1218 $crate::geom::Boundary::new($min, $max)
1219 };
1220}
1221
1222impl Into<Rectangle> for Boundary {
1223 fn into(self) -> Rectangle {
1224 Rectangle {
1225 min: Point::new(self.min.x.floor() as i32, self.min.y.floor() as i32),
1226 max: Point::new(self.max.x.ceil() as i32, self.max.y.ceil() as i32),
1227 }
1228 }
1229}
1230
1231impl Into<Boundary> for Rectangle {
1232 fn into(self) -> Boundary {
1233 Boundary {
1234 min: Vec2::new(self.min.x as f32, self.min.y as f32),
1235 max: Vec2::new(self.max.x as f32, self.max.y as f32),
1236 }
1237 }
1238}
1239
1240impl Mul<f32> for Boundary {
1241 type Output = Boundary;
1242 fn mul(self, rhs: f32) -> Boundary {
1243 Boundary {
1244 min: self.min * rhs,
1245 max: self.max * rhs,
1246 }
1247 }
1248}
1249
1250impl Mul<Boundary> for f32 {
1251 type Output = Boundary;
1252 fn mul(self, rhs: Boundary) -> Boundary {
1253 Boundary {
1254 min: self * rhs.min,
1255 max: self * rhs.max,
1256 }
1257 }
1258}
1259
1260impl MulAssign<f32> for Boundary {
1261 fn mul_assign(&mut self, rhs: f32) {
1262 self.min *= rhs;
1263 self.max *= rhs;
1264 }
1265}
1266
1267impl Div<f32> for Boundary {
1268 type Output = Boundary;
1269 fn div(self, rhs: f32) -> Boundary {
1270 Boundary {
1271 min: self.min / rhs,
1272 max: self.max / rhs,
1273 }
1274 }
1275}
1276
1277impl Div<Boundary> for f32 {
1278 type Output = Boundary;
1279 fn div(self, rhs: Boundary) -> Boundary {
1280 Boundary {
1281 min: rhs.min / self,
1282 max: rhs.max / self,
1283 }
1284 }
1285}
1286
1287impl DivAssign<f32> for Boundary {
1288 fn div_assign(&mut self, rhs: f32) {
1289 self.min /= rhs;
1290 self.max /= rhs;
1291 }
1292}
1293
1294#[derive(Debug, Copy, Clone)]
1295pub enum Region {
1296 Corner(DiagDir),
1297 Strip(Dir),
1298 Center,
1299}
1300
1301impl Region {
1302 pub fn from_point(pt: Point, rect: Rectangle, strip_width: f32, corner_width: f32) -> Region {
1305 let w = rect.width() as i32;
1306 let h = rect.height() as i32;
1307 let m = w.min(h) as f32 / 2.0;
1308
1309 let d = (m * corner_width).max(1.0) as i32;
1310 let x1 = rect.min.x + d - 1;
1311 let x2 = rect.max.x - d;
1312
1313 if pt.x <= x1 {
1315 let dx = x1 - pt.x;
1316 if pt.y <= rect.min.y + dx {
1317 return Region::Corner(DiagDir::NorthWest);
1318 } else if pt.y >= rect.max.y - 1 - dx {
1319 return Region::Corner(DiagDir::SouthWest);
1320 }
1321 } else if pt.x >= x2 {
1322 let dx = pt.x - x2;
1323 if pt.y <= rect.min.y + dx {
1324 return Region::Corner(DiagDir::NorthEast);
1325 } else if pt.y >= rect.max.y - 1 - dx {
1326 return Region::Corner(DiagDir::SouthEast);
1327 }
1328 }
1329
1330 let d = (m * strip_width).max(1.0) as i32;
1331 let x1 = rect.min.x + d - 1;
1332 let x2 = rect.max.x - d;
1333 let y1 = rect.min.y + d - 1;
1334 let y2 = rect.max.y - d;
1335
1336 if pt.x <= x1 {
1339 let dx = pt.x - rect.min.x;
1340 if pt.y >= rect.min.y + dx && pt.y < rect.max.y - 1 - dx {
1341 return Region::Strip(Dir::West);
1342 }
1343 } else if pt.x >= x2 {
1344 let dx = rect.max.x - 1 - pt.x;
1345 if pt.y > rect.min.y + dx && pt.y <= rect.max.y - 1 - dx {
1346 return Region::Strip(Dir::East);
1347 }
1348 }
1349
1350 if pt.y <= y1 {
1351 let dy = pt.y - rect.min.y;
1352 if pt.x > rect.min.x + dy && pt.y <= rect.max.x - 1 - dy {
1353 return Region::Strip(Dir::North);
1354 }
1355 } else if pt.y >= y2 {
1356 let dy = rect.max.y - 1 - pt.y;
1357 if pt.x >= rect.min.x + dy && pt.x < rect.max.x - 1 - dy {
1358 return Region::Strip(Dir::South);
1359 }
1360 }
1361
1362 Region::Center
1364 }
1365}
1366
1367#[cfg(test)]
1368mod tests {
1369 use super::{divide, LinearDir};
1370
1371 #[test]
1372 fn test_linear_dir_opposite() {
1373 assert_eq!(LinearDir::Forward.opposite(), LinearDir::Backward);
1374 assert_eq!(LinearDir::Backward.opposite(), LinearDir::Forward);
1375 }
1376
1377 #[test]
1378 fn overlaping_rectangles() {
1379 let a = rect![2, 2, 10, 10];
1380 let b = rect![2, 5, 3, 6];
1381 let c = rect![1, 3, 2, 7];
1382 let d = rect![9, 9, 12, 12];
1383 let e = rect![4, 3, 5, 6];
1384 assert!(b.overlaps(&a));
1385 assert!(!c.overlaps(&a));
1386 assert!(d.overlaps(&a));
1387 assert!(e.overlaps(&a));
1388 assert!(a.overlaps(&e));
1389 }
1390
1391 #[test]
1392 fn contained_rectangles() {
1393 let a = rect![2, 2, 10, 10];
1394 let b = rect![4, 3, 5, 6];
1395 let c = rect![4, 3, 12, 9];
1396 assert!(a.contains(&b));
1397 assert!(!b.contains(&a));
1398 assert!(!a.contains(&c));
1399 assert!(c.contains(&b));
1400 }
1401
1402 #[test]
1403 fn extended_rectangles() {
1404 let a = rect![30, 30, 60, 60];
1405 let b = rect![23, 0, 67, 28];
1406 let c = rect![60, 40, 110, 80];
1407 let d = rect![26, 62, 55, 96];
1408 let e = rect![0, 25, 29, 60];
1409 assert!(b.extends(&a));
1410 assert!(c.extends(&a));
1411 assert!(d.extends(&a));
1412 assert!(e.extends(&a));
1413 assert!(!b.extends(&d));
1414 assert!(!c.extends(&e));
1415 assert!(!e.extends(&b));
1416 }
1417
1418 #[test]
1419 fn divide_integers() {
1420 let a: i32 = 73;
1421 let b: i32 = 23;
1422 let v = divide(a, b);
1423 let s: i32 = v.iter().sum();
1424 assert_eq!(v.len(), b as usize);
1425 assert_eq!(s, a);
1426 assert_eq!(v.iter().max(), Some(&4));
1427 assert_eq!(v.iter().min(), Some(&3));
1428 }
1429
1430 #[test]
1431 fn point_rectangle_distance() {
1432 let pt1 = pt!(4, 5);
1433 let pt2 = pt!(1, 2);
1434 let pt3 = pt!(3, 8);
1435 let pt4 = pt!(8, 6);
1436 let pt5 = pt!(7, 4);
1437 let rect = rect![2, 3, 7, 6];
1438 assert_eq!(pt1.rdist2(&rect), 0);
1439 assert_eq!(pt2.rdist2(&rect), 2);
1440 assert_eq!(pt3.rdist2(&rect), 9);
1441 assert_eq!(pt4.rdist2(&rect), 5);
1442 assert_eq!(pt5.rdist2(&rect), 1);
1443 }
1444}