use super::{Contains, impl_contains_from_relate, impl_contains_geometry_for};
use crate::algorithm::Intersects;
use crate::geometry::*;
use crate::{GeoFloat, GeoNum};
impl<T> Contains<Coord<T>> for Line<T>
where
T: GeoNum,
{
fn contains(&self, coord: &Coord<T>) -> bool {
if self.start == self.end {
&self.start == coord
} else {
coord != &self.start && coord != &self.end && self.intersects(coord)
}
}
}
impl<T> Contains<Point<T>> for Line<T>
where
T: GeoNum,
{
fn contains(&self, p: &Point<T>) -> bool {
self.contains(&p.0)
}
}
impl<T> Contains<Line<T>> for Line<T>
where
T: GeoNum,
{
fn contains(&self, line: &Line<T>) -> bool {
if line.start == line.end {
self.contains(&line.start)
} else {
self.intersects(&line.start) && self.intersects(&line.end)
}
}
}
impl<T> Contains<LineString<T>> for Line<T>
where
T: GeoNum,
{
fn contains(&self, linestring: &LineString<T>) -> bool {
if linestring.0.is_empty() {
return false;
}
let first = linestring.0.first().unwrap();
let mut all_equal = true;
let all_intersects = linestring.0.iter().all(|c| {
if c != first {
all_equal = false;
}
self.intersects(c)
});
all_intersects && (!all_equal || self.contains(first))
}
}
impl<T> Contains<MultiPoint<T>> for Line<T>
where
T: GeoNum,
{
fn contains(&self, multi_point: &MultiPoint<T>) -> bool {
multi_point.iter().any(|point| self.contains(&point.0))
&& multi_point.iter().all(|point| self.intersects(&point.0))
}
}
impl_contains_from_relate!(Line<T>, [Polygon<T>, MultiLineString<T>, MultiPolygon<T>, GeometryCollection<T>, Rect<T>, Triangle<T>]);
impl_contains_geometry_for!(Line<T>);
#[cfg(test)]
mod test {
use super::*;
use crate::{MultiPoint, Relate, coord};
#[test]
fn test_line_contains_empty_multipoint() {
let line = Line::new(coord! {x:0.,y:0.}, coord! {x:100., y:100.});
let empty: MultiPoint<f64> = MultiPoint::empty();
assert!(!line.contains(&empty));
assert!(!line.relate(&empty).is_contains());
}
#[test]
fn test_line_contains_multipoint() {
let start = coord! {x: 0., y: 0.};
let mid = coord! {x: 50., y: 50.};
let end = coord! {x: 100., y: 100.};
let out = coord! {x: 101., y: 101.};
let line = Line::new(start, end);
let mp_ends = MultiPoint::from(vec![start, end]);
let mp_within = MultiPoint::from(vec![mid]);
let mp_merged = MultiPoint::from(vec![start, mid, end]);
let mp_out = MultiPoint::from(vec![out]);
let mp_all = MultiPoint::from(vec![start, mid, end, out]);
assert!(!line.contains(&mp_ends));
assert!(line.contains(&mp_within));
assert!(line.contains(&mp_merged));
assert!(!line.contains(&mp_out));
assert!(!line.contains(&mp_all));
let start_dupe = MultiPoint::from(vec![start, start]);
let start_dupe_within = MultiPoint::from(vec![start, start, mid]);
assert!(!line.contains(&start_dupe));
assert!(line.contains(&start_dupe_within));
}
}