iron_shapes/
redge.rs

1// Copyright (c) 2018-2020 Thomas Kramer.
2// SPDX-FileCopyrightText: 2018-2022 Thomas Kramer
3//
4// SPDX-License-Identifier: AGPL-3.0-or-later
5
6//! An `REdge` is 'rectilinear' edge which is either horizontal or vertical.
7
8use 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
26/// Return type for the edge-edge intersection functions.
27/// Stores all possible results of a edge to edge intersection.
28pub type REdgeIntersection<T> = EdgeIntersection<T, T, REdge<T>>;
29
30/// Return type for the line-line intersection functions.
31/// Stores all possible results of a line to line intersection.
32#[derive(Clone, Copy, PartialEq, Eq, Debug)]
33pub enum RLineIntersection<T: CoordinateType> {
34    /// No intersection at all.
35    None,
36    /// Intersection in a single point.
37    /// Besides the intersection point also an other expression for the intersection point is given.
38    /// The three values `(a, b, c)` describe the intersection point in terms of a starting point (the starting point
39    /// of the edge which defines the line) and the direction of the edge multiplied by a fraction.
40    ///
41    /// `edge.start + edge.vector()*a/c == p` and
42    /// `other_edge.start + other_edge.vector()*b/c == p`.
43    Point(Point<T>),
44    /// Lines are collinear.
45    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    /// Try to convert an edge into a rectilinear edge.
76    /// Returns none if the edge is not rectilinear.
77    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// impl<T: CoordinateType> From<(Point<T>, Point<T>)> for REdge<T> {
86//     fn from(points: (Point<T>, Point<T>)) -> Self {
87//         REdge::new(points.0, points.1)
88//     }
89// }
90//
91// impl<T: CoordinateType> From<[Point<T>; 2]> for REdge<T> {
92//     fn from(points: [Point<T>; 2]) -> Self {
93//         REdge::new(points[0], points[1])
94//     }
95// }
96
97/// Orientation of a rectilinear edge.
98#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
99#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
100pub enum REdgeOrientation {
101    /// Horizontal edge.
102    Horizontal,
103    /// Vertical edge.
104    Vertical,
105}
106
107impl REdgeOrientation {
108    /// Return the other orientation then `self`.
109    pub fn other(&self) -> Self {
110        match self {
111            Self::Horizontal => Self::Vertical,
112            Self::Vertical => Self::Horizontal,
113        }
114    }
115
116    /// Check if the orientation is horizontal.
117    pub fn is_horizontal(self) -> bool {
118        self == Self::Horizontal
119    }
120
121    /// Check if the orientation is vertical.
122    pub fn is_vertical(self) -> bool {
123        self == Self::Vertical
124    }
125}
126
127/// An rectilinear edge (horizontal or vertical line segment) is represented by its starting point and end point.
128#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq)]
129#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
130pub struct REdge<T> {
131    /// Start-coordinate of the edge.
132    pub start: T,
133    /// End-coordinate of the edge.
134    pub end: T,
135    /// Distance to to the origin (0, 0).
136    pub offset: T,
137    /// Orientation: Either horizontal or vertical.
138    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    /// Create a new rectilinear edge.
165    ///
166    /// # Parameters
167    ///
168    /// * `start`: Start-coordinate of the edge.
169    /// * `end`: End-coordinate of the edge.
170    /// * `offset`: Distance to to the origin (0, 0).
171    /// * `orientation`: Orientation: Either horizontal or vertical.
172    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    /// Get the start point of the edge.
184    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    /// Get the end point of the edge.
192    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    /// Return the same edge but with the two points swapped.
200    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    /// Check if edge is degenerate.
212    /// An edge is degenerate if start point and end point are equal.
213    #[inline]
214    pub fn is_degenerate(&self) -> bool {
215        self.start == self.end
216    }
217
218    /// Test if this edge is either horizontal or vertical.
219    #[inline]
220    pub fn is_ortho(&self) -> bool {
221        !self.is_degenerate()
222    }
223
224    /// Test if this edge is horizontal.
225    #[inline]
226    pub fn is_horizontal(&self) -> bool {
227        !self.is_degenerate() && self.orientation == REdgeOrientation::Horizontal
228    }
229
230    /// Test if this edge is vertical.
231    #[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    /// Get the length of the edge.
239    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    /// Create a new `REdge` from two arguments that implement `Into<Point>`.
250    /// The two points must lie either on a vertical or horizontal line, otherwise `None` is returned.
251    ///
252    /// # Panics
253    /// Panics if the two points are not on the same horizontal or vertical line.
254    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    /// Create a new `REdge` from two arguments that implement `Into<Point>`.
262    /// The two points must lie either on a vertical or horizontal line, otherwise `None` is returned.
263    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            // Vertical edge.
272            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            // Horizontal edge.
280            Some(REdge {
281                start: s.x,
282                end: e.x,
283                offset: s.y,
284                orientation: REdgeOrientation::Horizontal,
285            })
286        } else {
287            // Edge is neither horizontal nor vertical.
288            None
289        }
290    }
291
292    /// Returns the vector from `self.start()` to `self.end()`.
293    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    /// Get a vector of unit length pointing in the same direction as the edge.
301    /// Returns `None` if the length of the edge is zero.
302    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    /// Tells on which side of the edge a point is.
324    ///
325    /// # Panics
326    /// Panics if the edge is degenerate.
327    ///
328    /// Returns `Side::Left` if the point is on the left side,
329    /// `Side::Right` if the point is on the right side
330    /// or `Side::Center` if the point lies exactly on the line.
331    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    //    /// Find minimal distance between two edges.
358    //    pub fn distance_to_edge(self, other: Edge<T>) -> f64 {
359    //        let d1 = self.distance(other.start);
360    //        let d2 = self.distance(other.end);
361    //        let d3 = other.distance(self.start);
362    //        let d4 = other.distance(self.end);
363    //
364    //        let min1 = d1.min(d2);
365    //        let min2 = d3.min(d4);
366    //
367    //        // TODO: if intersects
368    //
369    //        min1.min(min2)
370    //    }
371
372    /// Compute the manhattan distance of a point to the edge.
373    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    /// Test if point lies on the edge.
390    /// Includes start and end points of edge.
391    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    /// Test if point lies on the line defined by the edge.
411    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    /// Test if two edges are parallel.
420    pub fn is_parallel(&self, other: &REdge<T>) -> bool {
421        self.orientation == other.orientation
422    }
423
424    /// Test if two edges are collinear, i.e. are on the same line.
425    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    /// Test edges for coincidence.
433    /// Two edges are coincident if they are oriented the same way
434    /// and share more than one point (implies that they must be parallel).
435    pub fn is_coincident(&self, other: &REdge<T>) -> bool {
436        // self.is_collinear(other) &&
437        //     !Interval::new(self.start, self.end)
438        //         .intersection(&zInterval::new(other.start, other.end))
439        //         .is_empty()
440
441        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    /// Test if this edge is crossed by the line defined by the other edge.
453    ///
454    /// Returns `WithinBounds` if start and end point of this edge lie on different sides
455    /// of the line defined by the `other` edge or `OnBounds` if at least one of the points
456    /// lies on the line.
457    pub fn crossed_by_line(&self, line: &REdge<T>) -> ContainsResult {
458        // TODO: Handle degenerate cases.
459        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    /// Test if lines defined by the edges intersect.
477    /// If the lines are collinear they are also considered intersecting.
478    pub fn lines_intersect(&self, other: &REdge<T>) -> bool {
479        !self.is_parallel(other) || self.is_collinear(other)
480    }
481
482    /// Test if two edges intersect.
483    /// If the edges coincide, they also intersect.
484    pub fn edges_intersect(&self, other: &REdge<T>) -> ContainsResult {
485        // Two edges intersect if the start and end point of one edge
486        // lie on opposite sides of the other edge.
487
488        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    /// Calculate the distance from the point to the line given by the edge.
497    ///
498    /// Distance will be positive if the point lies on the right side of the edge and negative
499    /// if the point is on the left side.
500    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    /// Calculate the distance from the point to the line given by the edge.
516    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    /// Find the perpendicular projection of a point onto the line of the edge.
526    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    /// Compute the intersection of the two lines defined by the edges.
537    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    /// Compute the intersection between two edges.
557    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                    // Sort start and end such that start comes first.
563                    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                    // Compute the intersection of the two intervals.
577                    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                        // Make sure the orientation is the same as for `self`.
584                        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                        // Intersection in an endpoint.
598                        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    /// Rotate the edge by a multiple of 90 degrees around `(0, 0)`.
649    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        // Not collinear.
725        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        // Not collinear.
731        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        // Coincident lines
844        assert!(e1.crossed_by_line(&e1).inclusive_bounds());
845
846        // Parallel but not coincident.
847        assert!(e1.is_parallel(&e2));
848        assert!(!e1.crossed_by_line(&e2).inclusive_bounds());
849
850        // Crossing lines.
851        assert!(e1.crossed_by_line(&e3).inclusive_bounds());
852        assert!(e3.crossed_by_line(&e1).inclusive_bounds());
853
854        // crossed_by is not commutative
855        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        // Self intersection.
866        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        // Intersection at an endpoint.
877        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        // Point intersection inside both edges.
904        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        // Point intersection on the end of one edge.
916        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        // No intersection
928        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        // Overlapping edges. Same orientations.
942        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        // Overlapping edges. Opposing orientations.
951        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        // Overlapping edges. One is fully contained in the other. Same orientations.
963        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        // Overlapping edges. One is fully contained in the other. Opposing orientations.
972        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        // Collinear edge, touch in exactly one point.
984        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    // #[test]
1038    // fn test_intersection_of_random_edges() {
1039    //     let tol = 1e-12;
1040    //     let seed1 = [1u8; 32];
1041    //     let seed2 = [2u8; 32];
1042    //
1043    //     let between = Uniform::from(-1.0..1.0);
1044    //     let mut rng = StdRng::from_sed(seed1);
1045    //
1046    //     let mut rand_edge = || -> Edge<f64> {
1047    //         let points: Vec<(f64, f64)> = (0..2).into_iter()
1048    //             .map(|_| (between.sample(&mut rng), between.sample(&mut rng)))
1049    //             .collect();
1050    //
1051    //         REdge::new(points[0], points[1])
1052    //     };
1053    //
1054    //
1055    //     let bernoulli_rare = Bernoulli::new(0.05).unwrap();
1056    //     let bernoulli_50 = Bernoulli::new(0.5).unwrap();
1057    //     let mut rng = StdRng::from_seed(seed2);
1058    //
1059    //     for _i in 0..1000 {
1060    //
1061    //         // Create a random pair of edges. 5% of the edge pairs share an endpoint.
1062    //         let (a, b) = {
1063    //             let a = rand_edge();
1064    //
1065    //             let b = {
1066    //                 let b = rand_edge();
1067    //
1068    //                 if bernoulli_rare.sample(&mut rng) {
1069    //                     // Share a point with the other edge.
1070    //                     let shared = if bernoulli_50.sample(&mut rng) {
1071    //                         a.start
1072    //                     } else {
1073    //                         a.end
1074    //                     };
1075    //
1076    //                     let result = REdge::new(b.start, shared);
1077    //                     if bernoulli_50.sample(&mut rng) {
1078    //                         result
1079    //                     } else {
1080    //                         result.reversed()
1081    //                     }
1082    //                 } else {
1083    //                     b
1084    //                 }
1085    //             };
1086    //             (a, b)
1087    //         };
1088    //
1089    //         let intersection_ab = a.edge_intersection_approx(&b, tol);
1090    //         assert_eq!(intersection_ab != EdgeIntersection::None, a.edges_intersect(&b).inclusive_bounds());
1091    //
1092    //         let intersection_ba = b.edge_intersection_approx(&a, tol);
1093    //         assert_eq!(intersection_ba != EdgeIntersection::None, b.edges_intersect(&a).inclusive_bounds());
1094    //     }
1095    // }
1096}