use super::{Intersects, has_disjoint_bboxes};
use crate::BoundingRect;
use crate::*;
macro_rules! intersects_line_string_impl {
($t:ty) => {
impl<T> $crate::Intersects<$t> for LineString<T>
where
T: GeoNum,
{
fn intersects(&self, rhs: &$t) -> bool {
if has_disjoint_bboxes(self, rhs) {
return false;
}
if self.0.len() == 1 {
return self.0[0].intersects(rhs);
}
self.lines().any(|l| l.intersects(rhs))
}
}
};
(area: $t:ty) => {
impl<T> $crate::Intersects<$t> for LineString<T>
where
T: GeoNum,
{
fn intersects(&self, rhs: &$t) -> bool {
if has_disjoint_bboxes(self, rhs) {
return false;
}
let Some(coord) = self.0.first() else {
return false;
};
coord.intersects(rhs)
|| self
.lines()
.any(|l| rhs.lines_iter().any(|other| l.intersects(&other)))
}
}
};
}
intersects_line_string_impl!(Coord<T>);
intersects_line_string_impl!(Point<T>);
intersects_line_string_impl!(MultiPoint<T>);
intersects_line_string_impl!(Line<T>);
intersects_line_string_impl!(LineString<T>);
symmetric_intersects_impl!(LineString<T>, MultiLineString<T>);
intersects_line_string_impl!(area: Polygon<T>);
impl<T> Intersects<MultiPolygon<T>> for LineString<T>
where
T: GeoNum,
{
fn intersects(&self, rhs: &MultiPolygon<T>) -> bool {
if has_disjoint_bboxes(self, rhs) {
return false;
}
rhs.iter().any(|poly| self.intersects(poly))
}
}
impl<T> Intersects<Rect<T>> for LineString<T>
where
T: GeoNum,
{
fn intersects(&self, rhs: &Rect<T>) -> bool {
if has_disjoint_bboxes(self, rhs) {
return false;
}
self.lines_iter().any(|ln| ln.intersects(rhs))
}
}
intersects_line_string_impl!(area: Triangle<T>);
impl<T, G> Intersects<G> for MultiLineString<T>
where
T: CoordNum,
LineString<T>: Intersects<G>,
G: BoundingRect<T>,
{
fn intersects(&self, rhs: &G) -> bool {
if has_disjoint_bboxes(self, rhs) {
return false;
}
self.iter().any(|p| p.intersects(rhs))
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::wkt;
#[test]
fn test_degenerate_linestring() {
let pt: Point<f64> = wkt! {POINT(1 1)}.convert();
let poly: Polygon<f64> = wkt! {RECT(0 0, 1 1)}.to_polygon().convert();
let ls1: LineString<f64> = wkt! {LINESTRING(1 1)}.convert();
let ls2: LineString<f64> = wkt! {LINESTRING(1 1, 1 1)}.convert();
assert_eq!(ls1.intersects(&pt), ls1.relate(&pt).is_intersects());
assert_eq!(ls2.intersects(&pt), ls2.relate(&pt).is_intersects());
assert!(ls1.intersects(&poly));
assert_eq!(ls1.intersects(&poly), ls1.relate(&poly).is_intersects());
assert_eq!(ls2.intersects(&poly), ls2.relate(&poly).is_intersects());
}
#[test]
fn test_linestring_inside_polygon() {
let ls: LineString<f64> = wkt! {LINESTRING(1 1, 2 2)}.convert();
let poly: Polygon<f64> = Rect::new((0, 0), (10, 10)).to_polygon().convert();
assert!(ls.intersects(&poly));
}
#[test]
fn test_linestring_partial_polygon() {
let ls: LineString<f64> = wkt! {LINESTRING(-1 -1, 2 2)}.convert();
let poly: Polygon<f64> = Rect::new((0, 0), (10, 10)).to_polygon().convert();
assert!(ls.intersects(&poly));
}
#[test]
fn test_linestring_disjoint_polygon() {
let ls: LineString<f64> = wkt! {LINESTRING(-1 -1, -2 -2)}.convert();
let poly: Polygon<f64> = Rect::new((0, 0), (10, 10)).to_polygon().convert();
assert!(!ls.intersects(&poly));
}
#[test]
fn test_linestring_in_polygon_hole() {
let ls: LineString<f64> = wkt! {LINESTRING(4 4, 6 6)}.convert();
let bound = Rect::new((0, 0), (10, 10)).convert();
let hole = Rect::new((1, 1), (9, 9)).convert();
let poly = Polygon::new(
bound.exterior_coords_iter().collect(),
vec![hole.exterior_coords_iter().collect()],
);
assert!(!ls.intersects(&poly));
}
#[test]
fn test_linestring_inside_rect() {
let ls: LineString<f64> = wkt! {LINESTRING(1 1, 2 2)}.convert();
let poly: Rect<f64> = Rect::new((0, 0), (10, 10)).convert();
assert!(ls.intersects(&poly));
}
#[test]
fn test_linestring_partial_rect() {
let ls: LineString<f64> = wkt! {LINESTRING(-1 -1, 2 2)}.convert();
let poly: Rect<f64> = Rect::new((0, 0), (10, 10)).convert();
assert!(ls.intersects(&poly));
}
#[test]
fn test_linestring_disjoint_rect() {
let ls: LineString<f64> = wkt! {LINESTRING(-1 -1, -2 -2)}.convert();
let poly: Rect<f64> = Rect::new((0, 0), (10, 10)).convert();
assert!(!ls.intersects(&poly));
}
#[test]
fn test_linestring_inside_triangle() {
let ls: LineString<f64> = wkt! {LINESTRING(5 5, 5 4)}.convert();
let poly: Triangle<f64> = wkt! {TRIANGLE(0 0, 10 0, 5 10)}.convert();
assert!(ls.intersects(&poly));
}
#[test]
fn test_linestring_partial_triangle() {
let ls: LineString<f64> = wkt! {LINESTRING(5 5, 5 -4)}.convert();
let poly: Triangle<f64> = wkt! {TRIANGLE(0 0, 10 0, 5 10)}.convert();
assert!(ls.intersects(&poly));
}
#[test]
fn test_linestring_disjoint_triangle() {
let ls: LineString<f64> = wkt! {LINESTRING(5 -5, 5 -4)}.convert();
let poly: Triangle<f64> = wkt! {TRIANGLE(0 0, 10 0, 5 10)}.convert();
assert!(!ls.intersects(&poly));
}
}