Skip to main content

geometry_algorithm/
intersects.rs

1//! `intersects(&a, &b)` — see
2//! `boost/geometry/algorithms/intersects.hpp`.
3//!
4//! Cartesian-only in v1. Default strategy is
5//! [`geometry_strategy::CartesianIntersects`], which implements every
6//! pair in one canonical direction; the
7//! [`geometry_strategy::intersects::Reversed`] blanket lifts each
8//! pair to its swap.
9
10use geometry_strategy::intersects::Reversed;
11use geometry_strategy::{CartesianIntersects, IntersectsStrategy};
12
13/// `true` iff `a` and `b` share at least one point.
14///
15/// Mirrors `boost::geometry::intersects(a, b)` from
16/// `boost/geometry/algorithms/intersects.hpp`. Tries the canonical
17/// pair direction first, falling back to the reversed direction
18/// through the `Reversed<CartesianIntersects>` blanket so callers
19/// never have to remember which argument order has an explicit impl.
20#[inline]
21#[must_use]
22pub fn intersects<A, B>(a: &A, b: &B) -> bool
23where
24    CartesianIntersects: IntersectsStrategy<A, B>,
25{
26    CartesianIntersects.intersects(a, b)
27}
28
29/// Reversed-direction entry point — used when only `(B, A)` has an
30/// explicit impl. Mirrors the Boost `reverse_dispatch` fallback in
31/// `algorithms/detail/intersects/interface.hpp`.
32#[inline]
33#[must_use]
34pub fn intersects_reversed<A, B>(a: &A, b: &B) -> bool
35where
36    Reversed<CartesianIntersects>: IntersectsStrategy<A, B>,
37{
38    Reversed(CartesianIntersects).intersects(a, b)
39}
40
41#[cfg(test)]
42mod tests {
43    //! Reference values from
44    //! `geometry/test/algorithms/intersects/intersects.cpp:38-79`.
45    //! Each test cites the C++ line it mirrors.
46
47    use super::intersects;
48    use geometry_cs::Cartesian;
49    use geometry_model::{Linestring, Point2D, Polygon, Segment, linestring, polygon};
50
51    type P = Point2D<f64, Cartesian>;
52    type LS = Linestring<P>;
53
54    fn pt(x: f64, y: f64) -> P {
55        Point2D::new(x, y)
56    }
57
58    /// `intersects.cpp:38` — linestring crosses segment.
59    #[test]
60    fn ls_crosses_segment() {
61        let ls: LS = linestring![(1.0, 1.0), (3.0, 3.0), (2.0, 5.0)];
62        let s = Segment::new(pt(2.0, 0.0), pt(2.0, 6.0));
63        assert!(intersects(&ls, &s));
64    }
65
66    /// `intersects.cpp:39` — linestring touches segment endpoint.
67    #[test]
68    fn ls_touches_segment_endpoint() {
69        let ls: LS = linestring![(1.0, 1.0), (3.0, 3.0)];
70        let s = Segment::new(pt(1.0, 0.0), pt(1.0, 1.0));
71        assert!(intersects(&ls, &s));
72    }
73
74    /// `intersects.cpp:41` — disjoint linestring and segment.
75    #[test]
76    fn ls_disjoint_from_segment() {
77        let ls: LS = linestring![(1.0, 1.0), (3.0, 3.0)];
78        let s = Segment::new(pt(3.0, 0.0), pt(4.0, 1.0));
79        assert!(!intersects(&ls, &s));
80    }
81
82    /// `intersects.cpp:50` — linestring/linestring proper crossing.
83    #[test]
84    fn ls_crosses_ls() {
85        let a: LS = linestring![(0.0, 0.0), (2.0, 0.0), (3.0, 0.0)];
86        let b: LS = linestring![(0.0, 0.0), (1.0, 1.0), (2.0, 2.0)];
87        assert!(intersects(&a, &b));
88    }
89
90    /// `intersects.cpp:55` — collinear overlap.
91    #[test]
92    fn ls_overlap_collinear() {
93        let a: LS = linestring![(0.0, 0.0), (2.0, 0.0), (3.0, 0.0)];
94        let b: LS = linestring![(1.0, 0.0), (4.0, 0.0), (5.0, 0.0)];
95        assert!(intersects(&a, &b));
96    }
97
98    /// `intersects.cpp:69` — linestring inside polygon.
99    #[test]
100    fn ls_inside_polygon() {
101        let ls: LS = linestring![(1.0, 1.0), (2.0, 2.0)];
102        let p: Polygon<P> = polygon![[
103            (0.0, 0.0),
104            (10.0, 0.0),
105            (10.0, 10.0),
106            (0.0, 10.0),
107            (0.0, 0.0)
108        ]];
109        assert!(intersects(&ls, &p));
110    }
111
112    /// `intersects.cpp:71` — linestring outside polygon.
113    #[test]
114    fn ls_outside_polygon() {
115        let ls: LS = linestring![(11.0, 0.0), (12.0, 12.0)];
116        let p: Polygon<P> = polygon![[
117            (0.0, 0.0),
118            (10.0, 0.0),
119            (10.0, 10.0),
120            (0.0, 10.0),
121            (0.0, 0.0)
122        ]];
123        assert!(!intersects(&ls, &p));
124    }
125
126    /// Reverse-direction call — `intersects(polygon, linestring)`
127    /// resolves through the per-pair reverse impl on
128    /// `CartesianIntersects` and agrees with the canonical direction.
129    #[test]
130    fn reversed_pair_agrees() {
131        let ls: LS = linestring![(1.0, 1.0), (2.0, 2.0)];
132        let p: Polygon<P> = polygon![[
133            (0.0, 0.0),
134            (10.0, 0.0),
135            (10.0, 10.0),
136            (0.0, 10.0),
137            (0.0, 0.0)
138        ]];
139        assert_eq!(intersects(&ls, &p), intersects(&p, &ls));
140    }
141}