1use geometry_coords::CoordinateScalar;
10use geometry_strategy::{CartesianIntersects, IntersectsStrategy};
11use geometry_trait::{Box as BoxTrait, Geometry, Point as PointTrait};
12
13#[inline]
18#[must_use]
19pub fn disjoint<A, B>(a: &A, b: &B) -> bool
20where
21 CartesianIntersects: IntersectsStrategy<A, B>,
22{
23 !CartesianIntersects.intersects(a, b)
24}
25
26#[inline]
54#[must_use]
55pub fn disjoint_box_box<A, B, T>(a: &A, b: &B) -> bool
56where
57 A: BoxTrait,
58 B: BoxTrait,
59 <A as Geometry>::Point: PointTrait<Scalar = T>,
60 <B as Geometry>::Point: PointTrait<Scalar = T>,
61 T: CoordinateScalar,
62{
63 (0..<A as Geometry>::Point::DIM).any(|d| separated_on_axis(a, b, d))
64}
65
66fn separated_on_axis<A, B, T>(a: &A, b: &B, d: usize) -> bool
70where
71 A: BoxTrait,
72 B: BoxTrait,
73 <A as Geometry>::Point: PointTrait<Scalar = T>,
74 <B as Geometry>::Point: PointTrait<Scalar = T>,
75 T: CoordinateScalar,
76{
77 let (a_min, a_max, b_min, b_max) = match d {
78 0 => (
79 a.get_indexed::<0, 0>(),
80 a.get_indexed::<1, 0>(),
81 b.get_indexed::<0, 0>(),
82 b.get_indexed::<1, 0>(),
83 ),
84 1 => (
85 a.get_indexed::<0, 1>(),
86 a.get_indexed::<1, 1>(),
87 b.get_indexed::<0, 1>(),
88 b.get_indexed::<1, 1>(),
89 ),
90 2 => (
91 a.get_indexed::<0, 2>(),
92 a.get_indexed::<1, 2>(),
93 b.get_indexed::<0, 2>(),
94 b.get_indexed::<1, 2>(),
95 ),
96 3 => (
97 a.get_indexed::<0, 3>(),
98 a.get_indexed::<1, 3>(),
99 b.get_indexed::<0, 3>(),
100 b.get_indexed::<1, 3>(),
101 ),
102 _ => panic!("disjoint_box_box: DIM exceeds MAX_DIM (4)"),
103 };
104 a_max < b_min || b_max < a_min
105}
106
107#[cfg(test)]
108mod tests {
109 use super::disjoint;
110 use crate::intersects::intersects;
111 use geometry_cs::Cartesian;
112 use geometry_model::{Linestring, Point2D, linestring};
113
114 type P = Point2D<f64, Cartesian>;
115 type LS = Linestring<P>;
116
117 #[test]
118 fn disjoint_matches_negated_intersects() {
119 let a: LS = linestring![(0.0, 0.0), (2.0, 0.0)];
120 let b: LS = linestring![(10.0, 10.0), (11.0, 11.0)];
121 assert!(disjoint(&a, &b));
122 assert!(!intersects(&a, &b));
123 }
124
125 #[test]
126 fn disjoint_false_when_intersecting() {
127 let a: LS = linestring![(0.0, 0.0), (2.0, 0.0)];
128 let b: LS = linestring![(1.0, -1.0), (1.0, 1.0)];
129 assert!(!disjoint(&a, &b));
130 assert!(intersects(&a, &b));
131 }
132
133 #[test]
136 fn polygon_pair_disjointness() {
137 use geometry_model::{Polygon, polygon};
138 let a: Polygon<P> = polygon![[(0.0, 0.0), (4.0, 0.0), (4.0, 4.0), (0.0, 4.0), (0.0, 0.0)]];
139 let apart: Polygon<P> = polygon![[
140 (10.0, 10.0),
141 (14.0, 10.0),
142 (14.0, 14.0),
143 (10.0, 14.0),
144 (10.0, 10.0)
145 ]];
146 let overlapping: Polygon<P> =
147 polygon![[(2.0, 2.0), (6.0, 2.0), (6.0, 6.0), (2.0, 6.0), (2.0, 2.0)]];
148 assert!(disjoint(&a, &apart));
149 assert!(!disjoint(&a, &overlapping));
150 }
151
152 #[test]
153 fn box_box_fast_path() {
154 use crate::disjoint::disjoint_box_box;
155 use geometry_model::Box;
156
157 let a = Box::from_corners(P::new(0.0, 0.0), P::new(2.0, 2.0));
158 let right = Box::from_corners(P::new(5.0, 0.0), P::new(6.0, 2.0));
160 assert!(disjoint_box_box(&a, &right));
161 let above = Box::from_corners(P::new(0.0, 5.0), P::new(2.0, 6.0));
163 assert!(disjoint_box_box(&a, &above));
164 let over = Box::from_corners(P::new(1.0, 1.0), P::new(3.0, 3.0));
166 assert!(!disjoint_box_box(&a, &over));
167 let touch = Box::from_corners(P::new(2.0, 0.0), P::new(4.0, 2.0));
169 assert!(!disjoint_box_box(&a, &touch));
170 }
171
172 #[test]
175 fn box_box_three_d_separated_along_z_is_disjoint() {
176 use crate::disjoint::disjoint_box_box;
177 use geometry_model::{Box, Point3D};
178 type P3 = Point3D<f64, Cartesian>;
179 let a = Box::from_corners(P3::new(0.0, 0.0, 0.0), P3::new(1.0, 1.0, 1.0));
180 let b = Box::from_corners(P3::new(0.0, 0.0, 5.0), P3::new(1.0, 1.0, 6.0));
181 let c = Box::from_corners(P3::new(0.5, 0.5, 0.5), P3::new(2.0, 2.0, 2.0));
182 assert!(disjoint_box_box(&a, &b));
183 assert!(disjoint_box_box(&b, &a));
184 assert!(!disjoint_box_box(&a, &c));
185 }
186
187 fn box4(min: [f64; 4], max: [f64; 4]) -> geometry_model::Box<geometry_model::Point<f64, 4>> {
190 use geometry_trait::set_ordinate;
191 let corner = |v: [f64; 4]| {
192 let mut p = geometry_model::Point::<f64, 4>::default();
193 for (d, value) in v.into_iter().enumerate() {
194 set_ordinate(&mut p, d, value);
195 }
196 p
197 };
198 geometry_model::Box::from_corners(corner(min), corner(max))
199 }
200
201 #[test]
207 fn box_box_four_d_separated_along_the_last_axis_is_disjoint() {
208 use crate::disjoint::disjoint_box_box;
209
210 let a = box4([0.0; 4], [1.0, 1.0, 1.0, 1.0]);
211 let past_w = box4([0.0, 0.0, 0.0, 5.0], [1.0, 1.0, 1.0, 6.0]);
212 let overlapping = box4([0.5; 4], [2.0; 4]);
213
214 assert!(disjoint_box_box(&a, &past_w));
215 assert!(disjoint_box_box(&past_w, &a));
216 assert!(!disjoint_box_box(&a, &overlapping));
217
218 let touching_w = box4([0.0, 0.0, 0.0, 1.0], [1.0, 1.0, 1.0, 2.0]);
220 assert!(!disjoint_box_box(&a, &touching_w));
221 }
222
223 #[test]
227 #[should_panic(expected = "disjoint_box_box: DIM exceeds MAX_DIM")]
228 fn separated_on_axis_panics_past_max_dim() {
229 let a = box4([0.0; 4], [1.0; 4]);
230 let b = box4([5.0; 4], [6.0; 4]);
231 let _ = super::separated_on_axis(&a, &b, 4);
232 }
233}