use geometry_coords::CoordinateScalar;
use geometry_strategy::{CartesianIntersects, IntersectsStrategy};
use geometry_trait::{Box as BoxTrait, Geometry, Point as PointTrait};
#[inline]
#[must_use]
pub fn disjoint<A, B>(a: &A, b: &B) -> bool
where
CartesianIntersects: IntersectsStrategy<A, B>,
{
!CartesianIntersects.intersects(a, b)
}
#[inline]
#[must_use]
pub fn disjoint_box_box<A, B, T>(a: &A, b: &B) -> bool
where
A: BoxTrait,
B: BoxTrait,
<A as Geometry>::Point: PointTrait<Scalar = T>,
<B as Geometry>::Point: PointTrait<Scalar = T>,
T: CoordinateScalar,
{
(0..<A as Geometry>::Point::DIM).any(|d| separated_on_axis(a, b, d))
}
fn separated_on_axis<A, B, T>(a: &A, b: &B, d: usize) -> bool
where
A: BoxTrait,
B: BoxTrait,
<A as Geometry>::Point: PointTrait<Scalar = T>,
<B as Geometry>::Point: PointTrait<Scalar = T>,
T: CoordinateScalar,
{
let (a_min, a_max, b_min, b_max) = match d {
0 => (
a.get_indexed::<0, 0>(),
a.get_indexed::<1, 0>(),
b.get_indexed::<0, 0>(),
b.get_indexed::<1, 0>(),
),
1 => (
a.get_indexed::<0, 1>(),
a.get_indexed::<1, 1>(),
b.get_indexed::<0, 1>(),
b.get_indexed::<1, 1>(),
),
2 => (
a.get_indexed::<0, 2>(),
a.get_indexed::<1, 2>(),
b.get_indexed::<0, 2>(),
b.get_indexed::<1, 2>(),
),
3 => (
a.get_indexed::<0, 3>(),
a.get_indexed::<1, 3>(),
b.get_indexed::<0, 3>(),
b.get_indexed::<1, 3>(),
),
_ => panic!("disjoint_box_box: DIM exceeds MAX_DIM (4)"),
};
a_max < b_min || b_max < a_min
}
#[cfg(test)]
mod tests {
use super::disjoint;
use crate::intersects::intersects;
use geometry_cs::Cartesian;
use geometry_model::{Linestring, Point2D, linestring};
type P = Point2D<f64, Cartesian>;
type LS = Linestring<P>;
#[test]
fn disjoint_matches_negated_intersects() {
let a: LS = linestring![(0.0, 0.0), (2.0, 0.0)];
let b: LS = linestring![(10.0, 10.0), (11.0, 11.0)];
assert!(disjoint(&a, &b));
assert!(!intersects(&a, &b));
}
#[test]
fn disjoint_false_when_intersecting() {
let a: LS = linestring![(0.0, 0.0), (2.0, 0.0)];
let b: LS = linestring![(1.0, -1.0), (1.0, 1.0)];
assert!(!disjoint(&a, &b));
assert!(intersects(&a, &b));
}
#[test]
fn polygon_pair_disjointness() {
use geometry_model::{Polygon, polygon};
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)]];
let apart: Polygon<P> = polygon![[
(10.0, 10.0),
(14.0, 10.0),
(14.0, 14.0),
(10.0, 14.0),
(10.0, 10.0)
]];
let overlapping: Polygon<P> =
polygon![[(2.0, 2.0), (6.0, 2.0), (6.0, 6.0), (2.0, 6.0), (2.0, 2.0)]];
assert!(disjoint(&a, &apart));
assert!(!disjoint(&a, &overlapping));
}
#[test]
fn box_box_fast_path() {
use crate::disjoint::disjoint_box_box;
use geometry_model::Box;
let a = Box::from_corners(P::new(0.0, 0.0), P::new(2.0, 2.0));
let right = Box::from_corners(P::new(5.0, 0.0), P::new(6.0, 2.0));
assert!(disjoint_box_box(&a, &right));
let above = Box::from_corners(P::new(0.0, 5.0), P::new(2.0, 6.0));
assert!(disjoint_box_box(&a, &above));
let over = Box::from_corners(P::new(1.0, 1.0), P::new(3.0, 3.0));
assert!(!disjoint_box_box(&a, &over));
let touch = Box::from_corners(P::new(2.0, 0.0), P::new(4.0, 2.0));
assert!(!disjoint_box_box(&a, &touch));
}
#[test]
fn box_box_three_d_separated_along_z_is_disjoint() {
use crate::disjoint::disjoint_box_box;
use geometry_model::{Box, Point3D};
type P3 = Point3D<f64, Cartesian>;
let a = Box::from_corners(P3::new(0.0, 0.0, 0.0), P3::new(1.0, 1.0, 1.0));
let b = Box::from_corners(P3::new(0.0, 0.0, 5.0), P3::new(1.0, 1.0, 6.0));
let c = Box::from_corners(P3::new(0.5, 0.5, 0.5), P3::new(2.0, 2.0, 2.0));
assert!(disjoint_box_box(&a, &b));
assert!(disjoint_box_box(&b, &a));
assert!(!disjoint_box_box(&a, &c));
}
fn box4(min: [f64; 4], max: [f64; 4]) -> geometry_model::Box<geometry_model::Point<f64, 4>> {
use geometry_trait::set_ordinate;
let corner = |v: [f64; 4]| {
let mut p = geometry_model::Point::<f64, 4>::default();
for (d, value) in v.into_iter().enumerate() {
set_ordinate(&mut p, d, value);
}
p
};
geometry_model::Box::from_corners(corner(min), corner(max))
}
#[test]
fn box_box_four_d_separated_along_the_last_axis_is_disjoint() {
use crate::disjoint::disjoint_box_box;
let a = box4([0.0; 4], [1.0, 1.0, 1.0, 1.0]);
let past_w = box4([0.0, 0.0, 0.0, 5.0], [1.0, 1.0, 1.0, 6.0]);
let overlapping = box4([0.5; 4], [2.0; 4]);
assert!(disjoint_box_box(&a, &past_w));
assert!(disjoint_box_box(&past_w, &a));
assert!(!disjoint_box_box(&a, &overlapping));
let touching_w = box4([0.0, 0.0, 0.0, 1.0], [1.0, 1.0, 1.0, 2.0]);
assert!(!disjoint_box_box(&a, &touching_w));
}
#[test]
#[should_panic(expected = "disjoint_box_box: DIM exceeds MAX_DIM")]
fn separated_on_axis_panics_past_max_dim() {
let a = box4([0.0; 4], [1.0; 4]);
let b = box4([5.0; 4], [6.0; 4]);
let _ = super::separated_on_axis(&a, &b, 4);
}
}