Skip to content

Commit fa96be1

Browse files
committed
feat: intersect trait and implementations for polygon and grid line
1 parent f222858 commit fa96be1

File tree

3 files changed

+357
-1
lines changed

3 files changed

+357
-1
lines changed

src/utils/grid_line.rs

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::utils::direction::Direction;
22
use crate::utils::point::Point;
33
use crate::utils::range::Range;
4+
use crate::utils::traits::Intersect;
45

56
/// Represents a line on a grid that can only be horizontal or vertical
67
#[derive(Debug, Copy, Clone, PartialEq)]
@@ -90,6 +91,7 @@ impl GridLine {
9091
}
9192

9293
/// It extends its size by 1 in the direction of orientation
94+
#[allow(dead_code)]
9395
pub fn extend(&self) -> Self {
9496
match self {
9597
GridLine::Horizontal {
@@ -118,6 +120,7 @@ impl GridLine {
118120
}
119121

120122
/// Move line in direction by 1
123+
#[allow(dead_code)]
121124
pub fn moved(&self, direction: Direction) -> Self {
122125
let start = self.start();
123126
let end = self.end();
@@ -131,16 +134,64 @@ impl GridLine {
131134
}
132135
}
133136

137+
#[allow(dead_code)]
134138
pub fn direction(&self) -> Direction {
135139
self.start().direction(&self.end())
136140
}
137141
}
138142

143+
impl Intersect<GridLine> for GridLine {
144+
fn intersect(&self, value: &GridLine) -> bool {
145+
match (self, value) {
146+
// Two horizontal lines intersect if they're on the same y and their x ranges overlap
147+
(
148+
Self::Horizontal { y, x_start, x_end },
149+
Self::Horizontal {
150+
y: y2,
151+
x_start: x_start2,
152+
x_end: x_end2,
153+
},
154+
) => {
155+
if y != y2 {
156+
return false;
157+
}
158+
let my_x = Range::from_unordered(*x_start, *x_end);
159+
let other_x = Range::from_unordered(*x_start2, *x_end2);
160+
my_x.collide(&other_x)
161+
}
162+
// Two vertical lines intersect if they're on the same x and their y ranges overlap
163+
(
164+
Self::Vertical { x, y_start, y_end },
165+
Self::Vertical {
166+
x: x2,
167+
y_start: y_start2,
168+
y_end: y_end2,
169+
},
170+
) => {
171+
if x != x2 {
172+
return false;
173+
}
174+
let my_y = Range::from_unordered(*y_start, *y_end);
175+
let other_y = Range::from_unordered(*y_start2, *y_end2);
176+
my_y.collide(&other_y)
177+
}
178+
// Horizontal and vertical lines intersect if they cross
179+
(Self::Horizontal { y, x_start, x_end }, Self::Vertical { x, y_start, y_end })
180+
| (Self::Vertical { x, y_start, y_end }, Self::Horizontal { y, x_start, x_end }) => {
181+
let x_range = Range::from_unordered(*x_start, *x_end);
182+
let y_range = Range::from_unordered(*y_start, *y_end);
183+
x_range.contains(*x) && y_range.contains(*y)
184+
}
185+
}
186+
}
187+
}
188+
139189
#[cfg(test)]
140190
mod tests {
141191
use crate::utils::direction::Direction;
142192
use crate::utils::grid_line::GridLine;
143193
use crate::utils::point::Point;
194+
use crate::utils::traits::Intersect;
144195

145196
#[test]
146197
fn new_horizontal() {
@@ -325,4 +376,174 @@ mod tests {
325376
let line = GridLine::new(Point::new(2, 4), Point::new(2, 1)).unwrap();
326377
assert_eq!(Direction::North, line.direction());
327378
}
379+
380+
#[test]
381+
fn intersect_two_horizontal() {
382+
let line = GridLine::new(Point::new(2, 3), Point::new(5, 3)).unwrap();
383+
384+
//above
385+
let other = GridLine::new(Point::new(2, 4), Point::new(5, 4)).unwrap();
386+
assert!(!line.intersect(&other));
387+
assert!(!other.intersect(&line));
388+
389+
//below
390+
let other = GridLine::new(Point::new(2, 5), Point::new(5, 5)).unwrap();
391+
assert!(!line.intersect(&other));
392+
assert!(!other.intersect(&line));
393+
394+
//same y, before
395+
let other = GridLine::new(Point::new(0, 3), Point::new(1, 3)).unwrap();
396+
assert!(!line.intersect(&other));
397+
assert!(!other.intersect(&line));
398+
399+
//same y, intersect before
400+
let other = GridLine::new(Point::new(0, 3), Point::new(2, 3)).unwrap();
401+
assert!(line.intersect(&other));
402+
assert!(other.intersect(&line));
403+
404+
//same y, inside
405+
let other = GridLine::new(Point::new(3, 3), Point::new(4, 3)).unwrap();
406+
assert!(line.intersect(&other));
407+
assert!(other.intersect(&line));
408+
409+
// //same y, intersect after
410+
let other = GridLine::new(Point::new(5, 3), Point::new(9, 3)).unwrap();
411+
assert!(line.intersect(&other));
412+
assert!(other.intersect(&line));
413+
414+
// //same y, after
415+
let other = GridLine::new(Point::new(6, 3), Point::new(10, 3)).unwrap();
416+
assert!(!line.intersect(&other));
417+
assert!(!other.intersect(&line));
418+
}
419+
420+
#[test]
421+
fn intersect_two_vertical() {
422+
let line = GridLine::new(Point::new(3, 2), Point::new(3, 5)).unwrap();
423+
424+
// Different x, to the left
425+
let other = GridLine::new(Point::new(2, 2), Point::new(2, 5)).unwrap();
426+
assert!(!line.intersect(&other));
427+
assert!(!other.intersect(&line));
428+
429+
// Different x, to the right
430+
let other = GridLine::new(Point::new(4, 2), Point::new(4, 5)).unwrap();
431+
assert!(!line.intersect(&other));
432+
assert!(!other.intersect(&line));
433+
434+
// Same x, above
435+
let other = GridLine::new(Point::new(3, 0), Point::new(3, 1)).unwrap();
436+
assert!(!line.intersect(&other));
437+
assert!(!other.intersect(&line));
438+
439+
// Same x, intersect above
440+
let other = GridLine::new(Point::new(3, 0), Point::new(3, 2)).unwrap();
441+
assert!(line.intersect(&other));
442+
assert!(other.intersect(&line));
443+
444+
// Same x, inside
445+
let other = GridLine::new(Point::new(3, 3), Point::new(3, 4)).unwrap();
446+
assert!(line.intersect(&other));
447+
assert!(other.intersect(&line));
448+
449+
// Same x, intersect below
450+
let other = GridLine::new(Point::new(3, 5), Point::new(3, 9)).unwrap();
451+
assert!(line.intersect(&other));
452+
assert!(other.intersect(&line));
453+
454+
// Same x, below
455+
let other = GridLine::new(Point::new(3, 6), Point::new(3, 10)).unwrap();
456+
assert!(!line.intersect(&other));
457+
assert!(!other.intersect(&line));
458+
459+
// Same x, completely overlapping
460+
let other = GridLine::new(Point::new(3, 1), Point::new(3, 6)).unwrap();
461+
assert!(line.intersect(&other));
462+
assert!(other.intersect(&line));
463+
}
464+
465+
#[test]
466+
fn intersect_horizontal_vertical() {
467+
let horizontal = GridLine::new(Point::new(2, 3), Point::new(6, 3)).unwrap();
468+
469+
// Vertical line crosses through horizontal
470+
let vertical = GridLine::new(Point::new(4, 1), Point::new(4, 5)).unwrap();
471+
assert!(horizontal.intersect(&vertical));
472+
assert!(vertical.intersect(&horizontal));
473+
474+
// Vertical line at start of horizontal
475+
let vertical = GridLine::new(Point::new(2, 1), Point::new(2, 5)).unwrap();
476+
assert!(horizontal.intersect(&vertical));
477+
assert!(vertical.intersect(&horizontal));
478+
479+
// Vertical line at end of horizontal
480+
let vertical = GridLine::new(Point::new(6, 1), Point::new(6, 5)).unwrap();
481+
assert!(horizontal.intersect(&vertical));
482+
assert!(vertical.intersect(&horizontal));
483+
484+
// Vertical line before horizontal (x too small)
485+
let vertical = GridLine::new(Point::new(1, 1), Point::new(1, 5)).unwrap();
486+
assert!(!horizontal.intersect(&vertical));
487+
assert!(!vertical.intersect(&horizontal));
488+
489+
// Vertical line after horizontal (x too large)
490+
let vertical = GridLine::new(Point::new(7, 1), Point::new(7, 5)).unwrap();
491+
assert!(!horizontal.intersect(&vertical));
492+
assert!(!vertical.intersect(&horizontal));
493+
494+
// Vertical line above horizontal (y too small)
495+
let vertical = GridLine::new(Point::new(4, 0), Point::new(4, 2)).unwrap();
496+
assert!(!horizontal.intersect(&vertical));
497+
assert!(!vertical.intersect(&horizontal));
498+
499+
// Vertical line below horizontal (y too large)
500+
let vertical = GridLine::new(Point::new(4, 4), Point::new(4, 6)).unwrap();
501+
assert!(!horizontal.intersect(&vertical));
502+
assert!(!vertical.intersect(&horizontal));
503+
504+
// Vertical line touches horizontal at endpoint
505+
let vertical = GridLine::new(Point::new(4, 3), Point::new(4, 6)).unwrap();
506+
assert!(horizontal.intersect(&vertical));
507+
assert!(vertical.intersect(&horizontal));
508+
}
509+
510+
#[test]
511+
fn intersect_vertical_horizontal() {
512+
let vertical = GridLine::new(Point::new(4, 2), Point::new(4, 6)).unwrap();
513+
514+
// Horizontal line crosses through vertical
515+
let horizontal = GridLine::new(Point::new(1, 4), Point::new(7, 4)).unwrap();
516+
assert!(vertical.intersect(&horizontal));
517+
assert!(horizontal.intersect(&vertical));
518+
519+
// Horizontal line at start of vertical
520+
let horizontal = GridLine::new(Point::new(1, 2), Point::new(7, 2)).unwrap();
521+
assert!(vertical.intersect(&horizontal));
522+
assert!(horizontal.intersect(&vertical));
523+
524+
// Horizontal line at end of vertical
525+
let horizontal = GridLine::new(Point::new(1, 6), Point::new(7, 6)).unwrap();
526+
assert!(vertical.intersect(&horizontal));
527+
assert!(horizontal.intersect(&vertical));
528+
529+
// Horizontal line above vertical (y too small)
530+
let horizontal = GridLine::new(Point::new(1, 1), Point::new(7, 1)).unwrap();
531+
assert!(!vertical.intersect(&horizontal));
532+
assert!(!horizontal.intersect(&vertical));
533+
534+
// Horizontal line below vertical (y too large)
535+
let horizontal = GridLine::new(Point::new(1, 7), Point::new(7, 7)).unwrap();
536+
assert!(!vertical.intersect(&horizontal));
537+
assert!(!horizontal.intersect(&vertical));
538+
539+
// Horizontal line to the left of vertical (x too small)
540+
let horizontal = GridLine::new(Point::new(1, 4), Point::new(3, 4)).unwrap();
541+
assert!(!vertical.intersect(&horizontal));
542+
assert!(!horizontal.intersect(&vertical));
543+
544+
// Horizontal line to the right of vertical (x too large)
545+
let horizontal = GridLine::new(Point::new(5, 4), Point::new(7, 4)).unwrap();
546+
assert!(!vertical.intersect(&horizontal));
547+
assert!(!horizontal.intersect(&vertical));
548+
}
328549
}

0 commit comments

Comments
 (0)