1use crate::cmp;
9use crate::point::Point;
10use crate::rect::Rect;
11use crate::vector::Vector;
12
13use crate::CoordinateType;
14
15use num_traits::cast::NumCast;
16
17pub use crate::traits::{BoundingBox, RotateOrtho, TryBoundingBox, TryCastCoord};
18pub use crate::types::Angle;
19
20use super::prelude::{Edge, EdgeIntersection};
21pub use super::types::{ContainsResult, Side};
22use crate::prelude::{EdgeEndpoints, EdgeIntersect};
23use std::convert::TryFrom;
24use std::ops::Sub;
25
26pub type REdgeIntersection<T> = EdgeIntersection<T, T, REdge<T>>;
29
30#[derive(Clone, Copy, PartialEq, Eq, Debug)]
33pub enum RLineIntersection<T: CoordinateType> {
34 None,
36 Point(Point<T>),
44 Collinear,
46}
47
48impl<T: Copy> From<REdge<T>> for (Point<T>, Point<T>) {
49 fn from(e: REdge<T>) -> Self {
50 (e.start(), e.end())
51 }
52}
53
54impl<T: Copy> From<&REdge<T>> for (Point<T>, Point<T>) {
55 fn from(e: &REdge<T>) -> Self {
56 (e.start(), e.end())
57 }
58}
59
60impl<T: Copy> From<REdge<T>> for Edge<T> {
61 fn from(e: REdge<T>) -> Self {
62 Edge::new(e.start(), e.end())
63 }
64}
65
66impl<T: Copy> From<&REdge<T>> for Edge<T> {
67 fn from(e: &REdge<T>) -> Self {
68 Edge::new(e.start(), e.end())
69 }
70}
71
72impl<T: CoordinateType> TryFrom<&Edge<T>> for REdge<T> {
73 type Error = ();
74
75 fn try_from(value: &Edge<T>) -> Result<Self, Self::Error> {
78 match REdge::try_from_points(value.start, value.end) {
79 None => Err(()),
80 Some(e) => Ok(e),
81 }
82 }
83}
84
85#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
99#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
100pub enum REdgeOrientation {
101 Horizontal,
103 Vertical,
105}
106
107impl REdgeOrientation {
108 pub fn other(&self) -> Self {
110 match self {
111 Self::Horizontal => Self::Vertical,
112 Self::Vertical => Self::Horizontal,
113 }
114 }
115
116 pub fn is_horizontal(self) -> bool {
118 self == Self::Horizontal
119 }
120
121 pub fn is_vertical(self) -> bool {
123 self == Self::Vertical
124 }
125}
126
127#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq)]
129#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
130pub struct REdge<T> {
131 pub start: T,
133 pub end: T,
135 pub offset: T,
137 pub orientation: REdgeOrientation,
139}
140
141impl<T: Copy> EdgeEndpoints<T> for REdge<T> {
142 fn start(&self) -> Point<T> {
143 self.start()
144 }
145
146 fn end(&self) -> Point<T> {
147 self.end()
148 }
149}
150
151impl<T: CoordinateType> EdgeIntersect for REdge<T> {
152 type Coord = T;
153 type IntersectionCoord = T;
154
155 fn edge_intersection(
156 &self,
157 other: &Self,
158 ) -> EdgeIntersection<Self::Coord, Self::IntersectionCoord, REdge<T>> {
159 REdge::edge_intersection(self, other)
160 }
161}
162
163impl<T> REdge<T> {
164 pub fn new_raw(start: T, end: T, offset: T, orientation: REdgeOrientation) -> Self {
173 Self {
174 start,
175 end,
176 offset,
177 orientation,
178 }
179 }
180}
181
182impl<T: Copy> REdge<T> {
183 pub fn start(&self) -> Point<T> {
185 match self.orientation {
186 REdgeOrientation::Horizontal => Point::new(self.start, self.offset),
187 REdgeOrientation::Vertical => Point::new(self.offset, self.start),
188 }
189 }
190
191 pub fn end(&self) -> Point<T> {
193 match self.orientation {
194 REdgeOrientation::Horizontal => Point::new(self.end, self.offset),
195 REdgeOrientation::Vertical => Point::new(self.offset, self.end),
196 }
197 }
198
199 pub fn reversed(&self) -> Self {
201 Self {
202 start: self.end,
203 end: self.start,
204 offset: self.offset,
205 orientation: self.orientation,
206 }
207 }
208}
209
210impl<T: PartialEq> REdge<T> {
211 #[inline]
214 pub fn is_degenerate(&self) -> bool {
215 self.start == self.end
216 }
217
218 #[inline]
220 pub fn is_ortho(&self) -> bool {
221 !self.is_degenerate()
222 }
223
224 #[inline]
226 pub fn is_horizontal(&self) -> bool {
227 !self.is_degenerate() && self.orientation == REdgeOrientation::Horizontal
228 }
229
230 #[inline]
232 pub fn is_vertical(&self) -> bool {
233 !self.is_degenerate() && self.orientation == REdgeOrientation::Vertical
234 }
235}
236
237impl<T: PartialOrd + Sub<Output = T> + Copy> REdge<T> {
238 pub fn length(&self) -> T {
240 if self.start < self.end {
241 self.end - self.start
242 } else {
243 self.start - self.end
244 }
245 }
246}
247
248impl<T: CoordinateType> REdge<T> {
249 pub fn new<C>(start: C, end: C) -> Self
255 where
256 C: Into<Point<T>>,
257 {
258 Self::try_from_points(start, end).expect("Points must be on a vertical or horizontal line.")
259 }
260
261 pub fn try_from_points<C>(start: C, end: C) -> Option<Self>
264 where
265 C: Into<Point<T>>,
266 {
267 let s = start.into();
268 let e = end.into();
269
270 if s.x == e.x {
271 Some(REdge {
273 start: s.y,
274 end: e.y,
275 offset: s.x,
276 orientation: REdgeOrientation::Vertical,
277 })
278 } else if s.y == e.y {
279 Some(REdge {
281 start: s.x,
282 end: e.x,
283 offset: s.y,
284 orientation: REdgeOrientation::Horizontal,
285 })
286 } else {
287 None
289 }
290 }
291
292 pub fn vector(&self) -> Vector<T> {
294 match self.orientation {
295 REdgeOrientation::Horizontal => Vector::new(self.end - self.start, T::zero()),
296 REdgeOrientation::Vertical => Vector::new(T::zero(), self.end - self.start),
297 }
298 }
299
300 pub fn direction(&self) -> Option<Vector<T>> {
303 #![allow(clippy::just_underscores_and_digits)]
304 let _0 = T::zero();
305 let _1 = T::one();
306 let _1_minus = _0 - _1;
307
308 let d = if self.start < self.end {
309 Some(Vector::new(_1, _0))
310 } else if self.start > self.end {
311 Some(Vector::new(_1_minus, _0))
312 } else {
313 None
314 };
315
316 if self.orientation.is_vertical() {
317 d.map(|d| d.rotate_ortho(Angle::R90))
318 } else {
319 d
320 }
321 }
322
323 pub fn side_of(&self, point: Point<T>) -> Side {
332 assert!(!self.is_degenerate(), "Edge is degenerate.");
333
334 let p_offset = match self.orientation {
335 REdgeOrientation::Horizontal => T::zero() - point.y,
336 REdgeOrientation::Vertical => point.x,
337 };
338
339 if p_offset < self.offset {
340 if self.start < self.end {
341 Side::Left
342 } else {
343 Side::Right
344 }
345 } else if p_offset > self.offset {
346 if self.start < self.end {
347 Side::Right
348 } else {
349 Side::Left
350 }
351 } else {
352 debug_assert!(p_offset == self.offset);
353 Side::Center
354 }
355 }
356
357 pub fn manhattan_distance_to_point(self, p: Point<T>) -> T {
374 let projected = self.projection(p);
375
376 if self.contains_point(projected).inclusive_bounds() {
377 self.distance_to_line(p)
378 } else {
379 let dist_to_point1 = (self.start() - p).norm1();
380 let dist_to_point2 = (self.end() - p).norm1();
381 if dist_to_point1 < dist_to_point2 {
382 dist_to_point1
383 } else {
384 dist_to_point2
385 }
386 }
387 }
388
389 pub fn contains_point(&self, point: Point<T>) -> ContainsResult {
392 let (p_offset, p_projected) = match self.orientation {
393 REdgeOrientation::Horizontal => (point.y, point.x),
394 REdgeOrientation::Vertical => (point.x, point.y),
395 };
396
397 if p_offset != self.offset || self.is_degenerate() {
398 ContainsResult::No
399 } else if p_projected == self.start || p_projected == self.end {
400 ContainsResult::OnBounds
401 } else if (p_projected >= self.start && p_projected <= self.end)
402 || (p_projected >= self.end && p_projected <= self.start)
403 {
404 ContainsResult::WithinBounds
405 } else {
406 ContainsResult::No
407 }
408 }
409
410 pub fn line_contains_point(&self, point: Point<T>) -> bool {
412 let p_offset = match self.orientation {
413 REdgeOrientation::Horizontal => point.y,
414 REdgeOrientation::Vertical => point.x,
415 };
416 p_offset == self.offset
417 }
418
419 pub fn is_parallel(&self, other: &REdge<T>) -> bool {
421 self.orientation == other.orientation
422 }
423
424 pub fn is_collinear(&self, other: &REdge<T>) -> bool
426 where
427 T: CoordinateType,
428 {
429 self.is_parallel(other) && self.offset == other.offset
430 }
431
432 pub fn is_coincident(&self, other: &REdge<T>) -> bool {
436 self.is_collinear(other)
442 && (self.start <= other.start && other.start <= self.end
443 || self.start <= other.end && other.end <= self.end
444 || self.end <= other.start && other.start <= self.start
445 || self.end <= other.end && other.end <= self.start
446 || other.start <= self.start && self.start <= other.end
447 || other.start <= self.end && self.end <= other.end
448 || other.end <= self.start && self.start <= other.start
449 || other.end <= self.end && self.end <= other.start)
450 }
451
452 pub fn crossed_by_line(&self, line: &REdge<T>) -> ContainsResult {
458 let side1 = line.side_of(self.start());
460
461 if side1 == Side::Center {
462 ContainsResult::OnBounds
463 } else {
464 let side2 = line.side_of(self.end());
465
466 if side2 == Side::Center {
467 ContainsResult::OnBounds
468 } else if side1 == side2 {
469 ContainsResult::No
470 } else {
471 ContainsResult::WithinBounds
472 }
473 }
474 }
475
476 pub fn lines_intersect(&self, other: &REdge<T>) -> bool {
479 !self.is_parallel(other) || self.is_collinear(other)
480 }
481
482 pub fn edges_intersect(&self, other: &REdge<T>) -> ContainsResult {
485 match self.edge_intersection(other) {
489 REdgeIntersection::None => ContainsResult::No,
490 REdgeIntersection::Overlap(_) => ContainsResult::WithinBounds,
491 REdgeIntersection::Point(_) => ContainsResult::WithinBounds,
492 REdgeIntersection::EndPoint(_) => ContainsResult::OnBounds,
493 }
494 }
495
496 pub fn oriented_distance_to_line(&self, point: Point<T>) -> T {
501 assert!(!self.is_degenerate());
502
503 let diff = match self.orientation {
504 REdgeOrientation::Horizontal => self.offset - point.y,
505 REdgeOrientation::Vertical => point.x - self.offset,
506 };
507
508 if self.start > self.end {
509 T::zero() - diff
510 } else {
511 diff
512 }
513 }
514
515 pub fn distance_to_line(&self, point: Point<T>) -> T {
517 let diff = self.oriented_distance_to_line(point);
518 if diff < T::zero() {
519 T::zero() - diff
520 } else {
521 diff
522 }
523 }
524
525 pub fn projection(&self, point: Point<T>) -> Point<T> {
527 assert!(!self.is_degenerate());
528
529 match self.orientation {
530 REdgeOrientation::Horizontal => (point.x, self.offset),
531 REdgeOrientation::Vertical => (self.offset, point.y),
532 }
533 .into()
534 }
535
536 pub fn line_intersection(&self, other: &REdge<T>) -> RLineIntersection<T> {
538 match (self.orientation, other.orientation) {
539 (REdgeOrientation::Horizontal, REdgeOrientation::Horizontal)
540 | (REdgeOrientation::Vertical, REdgeOrientation::Vertical) => {
541 if self.offset == other.offset {
542 RLineIntersection::Collinear
543 } else {
544 RLineIntersection::None
545 }
546 }
547 (REdgeOrientation::Horizontal, REdgeOrientation::Vertical) => {
548 RLineIntersection::Point(Point::new(other.offset, self.offset))
549 }
550 (REdgeOrientation::Vertical, REdgeOrientation::Horizontal) => {
551 RLineIntersection::Point(Point::new(self.offset, other.offset))
552 }
553 }
554 }
555
556 pub fn edge_intersection(&self, other: &REdge<T>) -> REdgeIntersection<T> {
558 match (self.orientation, other.orientation) {
559 (REdgeOrientation::Horizontal, REdgeOrientation::Horizontal)
560 | (REdgeOrientation::Vertical, REdgeOrientation::Vertical) => {
561 if self.offset == other.offset {
562 let (s1, e1) = if self.start < self.end {
564 (self.start, self.end)
565 } else {
566 (self.end, self.start)
567 };
568 let (s2, e2) = if other.start < other.end {
569 (other.start, other.end)
570 } else {
571 (other.end, other.start)
572 };
573 debug_assert!(s1 <= e1);
574 debug_assert!(s2 <= e2);
575
576 let s = cmp::max(s1, s2);
578 let e = cmp::min(e1, e2);
579
580 if s > e {
581 REdgeIntersection::None
582 } else if s < e {
583 let (s, e) = if self.start < self.end {
585 (s, e)
586 } else {
587 (e, s)
588 };
589 REdgeIntersection::Overlap(REdge {
590 start: s,
591 end: e,
592 offset: self.offset,
593 orientation: self.orientation,
594 })
595 } else {
596 debug_assert!(s == e);
597 let p = match self.orientation {
599 REdgeOrientation::Vertical => Point::new(self.offset, s),
600 REdgeOrientation::Horizontal => Point::new(s, self.offset),
601 };
602 debug_assert!(
603 p == self.start()
604 || p == self.end()
605 || p == other.start()
606 || p == other.end(),
607 "`p` must be an end point."
608 );
609 REdgeIntersection::EndPoint(p)
610 }
611 } else {
612 REdgeIntersection::None
613 }
614 }
615 (o1, o2) => {
616 let (horizontal, vertical) = match (o1, o2) {
617 (REdgeOrientation::Horizontal, REdgeOrientation::Vertical) => (self, other),
618 (REdgeOrientation::Vertical, REdgeOrientation::Horizontal) => (other, self),
619 _ => panic!(),
620 };
621 let p = Point::new(vertical.offset, horizontal.offset);
622 let is_on_horizontal = (horizontal.start <= p.x && p.x <= horizontal.end)
623 || (horizontal.end <= p.x && p.x <= horizontal.start);
624 let is_on_vertical = (vertical.start <= p.y && p.y <= vertical.end)
625 || (vertical.end <= p.y && p.y <= vertical.start);
626 if is_on_horizontal && is_on_vertical {
627 let is_endpoint_horizontal = p.x == horizontal.start || p.x == horizontal.end;
628 let is_endpoint_vertical = p.y == vertical.start || p.y == vertical.end;
629 if is_endpoint_horizontal || is_endpoint_vertical {
630 debug_assert!(
631 p == self.start()
632 || p == self.end()
633 || p == other.start()
634 || p == other.end(),
635 "`p` must be an end point."
636 );
637 REdgeIntersection::EndPoint(p)
638 } else {
639 REdgeIntersection::Point(p)
640 }
641 } else {
642 REdgeIntersection::None
643 }
644 }
645 }
646 }
647
648 pub fn rotate_ortho(&self, a: Angle) -> Self {
650 let (p1, p2) = (self.start(), self.end());
651
652 let new_p1 = p1.rotate_ortho(a);
653 let new_p2 = p2.rotate_ortho(a);
654
655 Self::new(new_p1, new_p2)
656 }
657}
658
659#[test]
660fn test_rotate_ortho() {
661 let e = REdge::new((1, 0), (1, 2));
662 assert_eq!(e.rotate_ortho(Angle::R0), e);
663 assert_eq!(e.rotate_ortho(Angle::R90), REdge::new((0, 1), (-2, 1)));
664 assert_eq!(e.rotate_ortho(Angle::R180), REdge::new((-1, 0), (-1, -2)));
665 assert_eq!(e.rotate_ortho(Angle::R270), REdge::new((0, -1), (2, -1)));
666}
667
668impl<T: CoordinateType> BoundingBox<T> for REdge<T> {
669 fn bounding_box(&self) -> Rect<T> {
670 Rect::new(self.start(), self.end())
671 }
672}
673
674impl<T: CoordinateType> TryBoundingBox<T> for REdge<T> {
675 fn try_bounding_box(&self) -> Option<Rect<T>> {
676 Some(self.bounding_box())
677 }
678}
679
680impl<T: CoordinateType + NumCast, Dst: CoordinateType + NumCast> TryCastCoord<T, Dst> for REdge<T> {
681 type Output = REdge<Dst>;
682
683 fn try_cast(&self) -> Option<Self::Output> {
684 match (
685 Dst::from(self.start),
686 Dst::from(self.end),
687 Dst::from(self.offset),
688 ) {
689 (Some(s), Some(e), Some(o)) => Some(REdge {
690 start: s,
691 end: e,
692 offset: o,
693 orientation: self.orientation,
694 }),
695 _ => None,
696 }
697 }
698}
699
700#[cfg(test)]
701mod tests {
702 use crate::point::Point;
703 use crate::redge::{REdge, REdgeIntersection, RLineIntersection};
704 use crate::types::*;
705 use crate::vector::Vector;
706
707 #[test]
708 fn test_is_parallel() {
709 let e1 = REdge::new((0, 0), (1, 0));
710 let e2 = REdge::new((100, 200), (101, 200));
711 let e3 = REdge::new((1000, 2000), (1000, 2001));
712
713 assert!(e1.is_parallel(&e2));
714 assert!(!e1.is_parallel(&e3));
715 }
716
717 #[test]
718 fn test_is_collinear() {
719 let e1 = REdge::new((0, 0), (1, 0));
720 let e2 = REdge::new((3, 0), (4, 0));
721 assert!(e1.is_collinear(&e2));
722 assert!(e2.is_collinear(&e1));
723
724 let e1 = REdge::new((0, 0), (1, 0));
726 let e2 = REdge::new((3, 1), (4, 1));
727 assert!(!e1.is_collinear(&e2));
728 assert!(!e2.is_collinear(&e1));
729
730 let e1 = REdge::new((0, 0), (1, 0));
732 let e2 = REdge::new((0, 0), (0, 1));
733 assert!(!e1.is_collinear(&e2));
734 assert!(!e2.is_collinear(&e1));
735 }
736
737 #[test]
738 fn test_oriented_distance_to_line() {
739 let xaxis = REdge::new((0, 0), (1, 0));
740 let xaxis_neg = REdge::new((0, 0), (-1, 0));
741 let yaxis = REdge::new((0, 0), (0, 1));
742 let yaxis_neg = REdge::new((0, 0), (0, -1));
743
744 let p = Point::new(2, 3);
745
746 assert_eq!(xaxis.oriented_distance_to_line(p), -p.y);
747 assert_eq!(xaxis_neg.oriented_distance_to_line(p), p.y);
748 assert_eq!(yaxis.oriented_distance_to_line(p), p.x);
749 assert_eq!(yaxis_neg.oriented_distance_to_line(p), -p.x);
750 }
751
752 #[test]
753 fn test_distance_to_line() {
754 let xaxis = REdge::new((0, 0), (1, 0));
755 let yaxis = REdge::new((0, 0), (0, 1));
756 let p = Point::new(2, 3);
757
758 assert_eq!(xaxis.distance_to_line(p), p.y);
759 assert_eq!(yaxis.distance_to_line(p), p.x);
760 }
761
762 #[test]
763 fn test_manhattan_distance_to_edge() {
764 let e = REdge::new((0, 0), (10, 0));
765
766 assert_eq!(e.manhattan_distance_to_point(Point::new(5, 0)), 0);
767 assert_eq!(e.manhattan_distance_to_point(Point::new(5, 1)), 1);
768 assert_eq!(e.manhattan_distance_to_point(Point::new(5, -1)), 1);
769 assert_eq!(e.manhattan_distance_to_point(Point::new(-1, 0)), 1);
770 assert_eq!(e.manhattan_distance_to_point(Point::new(-1, -1)), 2);
771 assert_eq!(e.manhattan_distance_to_point(Point::new(11, 1)), 2);
772 assert_eq!(e.manhattan_distance_to_point(Point::new(11, -1)), 2);
773 }
774
775 #[test]
776 fn test_line_contains_point() {
777 let xaxis = REdge::new((0, 0), (1, 0));
778 let yaxis = REdge::new((0, 0), (0, 1));
779 let p0 = Point::new(2, 0);
780 let p1 = Point::new(2, 3);
781 let p2 = Point::new(0, 3);
782
783 assert!(xaxis.line_contains_point(p0));
784 assert!(!yaxis.line_contains_point(p0));
785 assert!(!xaxis.line_contains_point(p1));
786 assert!(yaxis.line_contains_point(p2));
787 assert!(!xaxis.line_contains_point(p2));
788 }
789
790 #[test]
791 fn test_contains() {
792 let e1 = REdge::new((0, 0), (10, 0));
793 let p0 = Point::new(0, 0);
794 let p1 = Point::new(1, 0);
795 let p2 = Point::new(0, 1);
796 let p3 = Point::new(10, 0);
797 let p4 = Point::new(11, 0);
798
799 assert!(e1.contains_point(p0).inclusive_bounds());
800 assert!(!e1.contains_point(p0).is_within_bounds());
801 assert!(e1.contains_point(p1).inclusive_bounds());
802 assert!(e1.contains_point(p2).is_no());
803 assert!(e1.contains_point(p3).inclusive_bounds());
804 assert!(e1.contains_point(p4).is_no());
805 }
806
807 #[test]
808 fn test_projection() {
809 let horizontal = REdge::new((0, 0), (1, 0));
810 let vertical = REdge::new((0, 0), (0, 1));
811 let p = Point::new(1, 2);
812
813 assert_eq!(horizontal.projection(p), Point::new(p.x, 0));
814 assert_eq!(vertical.projection(p), Point::new(0, p.y));
815 }
816
817 #[test]
818 fn test_side_of() {
819 let xaxis = REdge::new((0, 0), (1, 0));
820 let yaxis = REdge::new((0, 0), (0, 1));
821
822 let p1 = Point::new(-10, 0);
823 let p2 = Point::new(10, -10);
824 let p3 = Point::new(0, 10);
825
826 assert_eq!(yaxis.side_of(p1), Side::Left);
827 assert_eq!(yaxis.side_of(p2), Side::Right);
828 assert_eq!(yaxis.side_of(p3), Side::Center);
829
830 assert_eq!(xaxis.side_of(p1), Side::Center);
831 assert_eq!(xaxis.side_of(p2), Side::Right);
832 assert_eq!(xaxis.side_of(p3), Side::Left);
833 }
834
835 #[test]
836 fn test_crossed_by() {
837 let e1 = REdge::new((1, 0), (3, 0));
838 let e2 = REdge::new((1, 1), (3, 1));
839
840 let e3 = REdge::new((2, -1), (2, 1));
841 let e4 = REdge::new((2, 100), (2, 101));
842
843 assert!(e1.crossed_by_line(&e1).inclusive_bounds());
845
846 assert!(e1.is_parallel(&e2));
848 assert!(!e1.crossed_by_line(&e2).inclusive_bounds());
849
850 assert!(e1.crossed_by_line(&e3).inclusive_bounds());
852 assert!(e3.crossed_by_line(&e1).inclusive_bounds());
853
854 assert!(e1.crossed_by_line(&e4).inclusive_bounds());
856 assert!(!e4.crossed_by_line(&e1).inclusive_bounds());
857 }
858
859 #[test]
860 fn test_intersect() {
861 let e1 = REdge::new((0, 0), (2, 0));
862 let e2 = REdge::new((1, -1), (1, 1));
863 let e3 = REdge::new((1, 100), (1, 101));
864
865 assert!(e1.edges_intersect(&e1).inclusive_bounds());
867
868 assert!(e1.edges_intersect(&e2).inclusive_bounds());
869 assert!(e2.edges_intersect(&e1).inclusive_bounds());
870
871 assert_eq!(e3.side_of(e1.start()), Side::Left);
872 assert_eq!(e3.side_of(e1.end()), Side::Right);
873 assert!(e1.crossed_by_line(&e3).inclusive_bounds());
874 assert!(!e1.edges_intersect(&e3).inclusive_bounds());
875
876 let e1 = REdge::new((0, 0), (0, 1));
878 let e2 = REdge::new((0, 1), (2, 1));
879 assert_eq!(e1.edges_intersect(&e2), ContainsResult::OnBounds);
880 assert_eq!(e2.edges_intersect(&e1), ContainsResult::OnBounds);
881 }
882
883 #[test]
884 fn test_line_intersection() {
885 let v = REdge::new((7, 1), (7, 2));
886 let h = REdge::new((100, 77), (101, 77));
887
888 assert_eq!(
889 v.line_intersection(&h),
890 RLineIntersection::Point(Point::new(7, 77))
891 );
892
893 assert_eq!(v.line_intersection(&v), RLineIntersection::Collinear);
894 assert_eq!(h.line_intersection(&h), RLineIntersection::Collinear);
895
896 let v1 = REdge::new((0, 1), (0, 2));
897 let v2 = REdge::new((1, 1), (1, 2));
898 assert_eq!(v1.line_intersection(&v2), RLineIntersection::None);
899 }
900
901 #[test]
902 fn test_edge_intersection() {
903 let e1 = REdge::new((0, 0), (0, 2));
905 let e2 = REdge::new((-1, 1), (1, 1));
906 assert_eq!(
907 e1.edge_intersection(&e2),
908 REdgeIntersection::Point(Point::new(0, 1))
909 );
910 assert_eq!(
911 e2.edge_intersection(&e1),
912 REdgeIntersection::Point(Point::new(0, 1))
913 );
914
915 let e1 = REdge::new((0, 0), (0, 1));
917 let e2 = REdge::new((-1, 0), (1, 0));
918 assert_eq!(
919 e1.edge_intersection(&e2),
920 REdgeIntersection::EndPoint(Point::new(0, 0))
921 );
922 assert_eq!(
923 e2.edge_intersection(&e1),
924 REdgeIntersection::EndPoint(Point::new(0, 0))
925 );
926
927 let e1 = REdge::new((0, 0), (0, 1));
929 let e2 = REdge::new((0, 2), (0, 3));
930 assert_eq!(e1.edge_intersection(&e2), REdgeIntersection::None);
931 assert_eq!(e2.edge_intersection(&e1), REdgeIntersection::None);
932
933 let e1 = REdge::new((0, 0), (0, 1));
934 let e2 = REdge::new((1, 0), (2, 0));
935 assert_eq!(e1.edge_intersection(&e2), REdgeIntersection::None);
936 assert_eq!(e2.edge_intersection(&e1), REdgeIntersection::None);
937 }
938
939 #[test]
940 fn test_edge_intersection_overlap() {
941 let e1 = REdge::new((1, 1), (1, 3));
943 let e2 = REdge::new((1, 1), (1, 2));
944 assert!(e1.edges_intersect(&e2).inclusive_bounds());
945 assert!(e1.is_collinear(&e2));
946
947 assert_eq!(e1.edge_intersection(&e2), REdgeIntersection::Overlap(e2));
948 assert_eq!(e2.edge_intersection(&e1), REdgeIntersection::Overlap(e2));
949
950 let e1 = REdge::new((1, 1), (1, 3));
952 let e2 = REdge::new((1, 2), (1, 1));
953 assert!(e1.edges_intersect(&e2).inclusive_bounds());
954 assert!(e1.is_collinear(&e2));
955
956 assert_eq!(
957 e1.edge_intersection(&e2),
958 REdgeIntersection::Overlap(e2.reversed())
959 );
960 assert_eq!(e2.edge_intersection(&e1), REdgeIntersection::Overlap(e2));
961
962 let e1 = REdge::new((1, 1), (1, 100));
964 let e2 = REdge::new((1, 2), (1, 3));
965 assert!(e1.edges_intersect(&e2).inclusive_bounds());
966 assert!(e1.is_collinear(&e2));
967
968 assert_eq!(e1.edge_intersection(&e2), REdgeIntersection::Overlap(e2));
969 assert_eq!(e2.edge_intersection(&e1), REdgeIntersection::Overlap(e2));
970
971 let e1 = REdge::new((1, 1), (1, 100));
973 let e2 = REdge::new((1, 3), (1, 2));
974 assert!(e1.edges_intersect(&e2).inclusive_bounds());
975 assert!(e1.is_collinear(&e2));
976
977 assert_eq!(
978 e1.edge_intersection(&e2),
979 REdgeIntersection::Overlap(e2.reversed())
980 );
981 assert_eq!(e2.edge_intersection(&e1), REdgeIntersection::Overlap(e2));
982
983 let e1 = REdge::new((0, 0), (0, 1));
985 let e2 = REdge::new((0, 1), (0, 2));
986 assert!(e1.edges_intersect(&e2).inclusive_bounds());
987 assert!(e1.is_collinear(&e2));
988
989 assert_eq!(
990 e1.edge_intersection(&e2),
991 REdgeIntersection::EndPoint(Point::new(0, 1))
992 );
993 assert_eq!(
994 e2.edge_intersection(&e1),
995 REdgeIntersection::EndPoint(Point::new(0, 1))
996 );
997 }
998
999 #[test]
1000 fn test_coincident() {
1001 let e1 = REdge::new((0, 0), (0, 2));
1002 let e2 = REdge::new((0, 1), (0, 3));
1003 assert!(e1.is_coincident(&e2));
1004 assert!(e2.is_coincident(&e1));
1005
1006 let e1 = REdge::new((0, 0), (0, 1));
1007 let e2 = REdge::new((0, 1), (0, 3));
1008 assert!(e1.is_coincident(&e2));
1009 assert!(e2.is_coincident(&e1));
1010
1011 let e1 = REdge::new((0, 0), (2, 0));
1012 let e2 = REdge::new((1, 0), (3, 0));
1013 assert!(e1.is_coincident(&e2));
1014 assert!(e2.is_coincident(&e1));
1015
1016 let e1 = REdge::new((0, 0), (0, 1));
1017 let e2 = REdge::new((0, 0), (1, 0));
1018 assert!(!e1.is_coincident(&e2));
1019 assert!(!e2.is_coincident(&e1));
1020 }
1021
1022 #[test]
1023 fn test_direction() {
1024 let e_up = REdge::new((0, 0), (0, 2));
1025 assert_eq!(e_up.direction(), Some(Vector::new(0, 1)));
1026
1027 let e_down = REdge::new((0, 0), (0, -2));
1028 assert_eq!(e_down.direction(), Some(Vector::new(0, -1)));
1029
1030 let e_right = REdge::new((0, 0), (2, 0));
1031 assert_eq!(e_right.direction(), Some(Vector::new(1, 0)));
1032
1033 let e_left = REdge::new((0, 0), (-2, 0));
1034 assert_eq!(e_left.direction(), Some(Vector::new(-1, 0)));
1035 }
1036
1037 }