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