use num_traits::Float;
use types::{LineString, Polygon, Bbox, Point};
use algorithm::contains::Contains;
pub trait Intersects<Rhs = Self> {
fn intersects(&self, rhs: &Rhs) -> bool;
}
impl<T> Intersects<LineString<T>> for LineString<T>
where T: Float
{
fn intersects(&self, linestring: &LineString<T>) -> bool {
let vect0 = &self.0;
let vect1 = &linestring.0;
if vect0.is_empty() || vect1.is_empty() {
return false;
}
for a in vect0.windows(2) {
for b in vect1.windows(2) {
let u_b = (b[1].y() - b[0].y()) * (a[1].x() - a[0].x()) -
(b[1].x() - b[0].x()) * (a[1].y() - a[0].y());
if u_b == T::zero() {
continue;
}
let ua_t = (b[1].x() - b[0].x()) * (a[0].y() - b[0].y()) -
(b[1].y() - b[0].y()) * (a[0].x() - b[0].x());
let ub_t = (a[1].x() - a[0].x()) * (a[0].y() - b[0].y()) -
(a[1].y() - a[0].y()) * (a[0].x() - b[0].x());
let u_a = ua_t / u_b;
let u_b = ub_t / u_b;
if (T::zero() <= u_a) && (u_a <= T::one()) && (T::zero() <= u_b) && (u_b <= T::one()) {
return true;
}
}
}
false
}
}
impl<T> Intersects<LineString<T>> for Polygon<T>
where T: Float
{
fn intersects(&self, linestring: &LineString<T>) -> bool {
if self.exterior.intersects(linestring) || self.interiors.iter().any(|inner| inner.intersects(linestring)) {
return true;
} else {
return linestring.0.iter().any(|point| self.contains(point))
}
}
}
impl<T> Intersects<Bbox<T>> for Bbox<T>
where T: Float
{
fn intersects(&self, bbox: &Bbox<T>) -> bool {
if bbox.contains(&self) {
return false
} else {
(self.xmin >= bbox.xmin && self.xmin <= bbox.xmax || self.xmax >= bbox.xmin && self.xmax <= bbox.xmax) &&
(self.ymin >= bbox.ymin && self.ymin <= bbox.ymax || self.ymax >= bbox.ymin && self.ymax <= bbox.ymax)
}
}
}
impl<T> Intersects<Polygon<T>> for Bbox<T>
where T: Float
{
fn intersects(&self, polygon: &Polygon<T>) -> bool {
polygon.intersects(self)
}
}
impl<T> Intersects<Bbox<T>> for Polygon<T>
where T: Float
{
fn intersects(&self, bbox: &Bbox<T>) -> bool {
let p = Polygon::new(LineString(vec![Point::new(bbox.xmin, bbox.ymin),
Point::new(bbox.xmin, bbox.ymax),
Point::new(bbox.xmax, bbox.ymax),
Point::new(bbox.xmax, bbox.ymin),
Point::new(bbox.xmin, bbox.ymin)]),
vec![]);
self.intersects(&p)
}
}
impl<T> Intersects<Polygon<T>> for Polygon<T>
where T: Float
{
fn intersects(&self, polygon: &Polygon<T>) -> bool {
self.intersects(&polygon.exterior) ||
polygon.interiors.iter().any(|inner_line_string| self.intersects(inner_line_string)) ||
polygon.intersects(&self.exterior)
}
}
#[cfg(test)]
mod test {
use types::{Coordinate, Point, LineString, Polygon, Bbox};
use algorithm::intersects::Intersects;
#[test]
fn empty_linestring1_test() {
let p = |x, y| Point(Coordinate { x: x, y: y });
let linestring = LineString(vec![p(3., 2.), p(7., 6.)]);
assert!(!LineString(Vec::new()).intersects(&linestring));
}
#[test]
fn empty_linestring2_test() {
let p = |x, y| Point(Coordinate { x: x, y: y });
let linestring = LineString(vec![p(3., 2.), p(7., 6.)]);
assert!(!linestring.intersects(&LineString(Vec::new())));
}
#[test]
fn empty_all_linestring_test() {
assert!(!LineString::<f64>(Vec::new()).intersects(&LineString(Vec::new())));
}
#[test]
fn intersect_linestring_test() {
let p = |x, y| Point(Coordinate { x: x, y: y });
let linestring = LineString(vec![p(3., 2.), p(7., 6.)]);
assert!(linestring.intersects(&LineString(vec![p(3., 4.), p(8., 4.)])));
}
#[test]
fn parallel_linestrings_test() {
let p = |x, y| Point(Coordinate { x: x, y: y });
let linestring = LineString(vec![p(3., 2.), p(7., 6.)]);
assert!(!linestring.intersects(&LineString(vec![p(3., 1.), p(7., 5.)])));
}
#[test]
fn linestring_in_polygon_test() {
let p = |x, y| Point(Coordinate { x: x, y: y });
let linestring = LineString(vec![p(0., 0.), p(5., 0.), p(5., 6.), p(0., 6.), p(0., 0.)]);
let poly = Polygon::new(linestring, Vec::new());
assert!(poly.intersects(&LineString(vec![p(2., 2.), p(3., 3.)])));
}
#[test]
fn linestring_on_boundary_polygon_test() {
let p = |x, y| Point(Coordinate { x: x, y: y });
let poly = Polygon::new(LineString(vec![p(0., 0.), p(5., 0.), p(5., 6.), p(0., 6.), p(0., 0.)]),
Vec::new());
assert!(poly.intersects(&LineString(vec![p(0., 0.), p(5., 0.)])));
assert!(poly.intersects(&LineString(vec![p(5., 0.), p(5., 6.)])));
assert!(poly.intersects(&LineString(vec![p(5., 6.), p(0., 6.)])));
assert!(poly.intersects(&LineString(vec![p(0., 6.), p(0., 0.)])));
}
#[test]
fn intersect_linestring_polygon_test() {
let p = |x, y| Point(Coordinate { x: x, y: y });
let poly = Polygon::new(LineString(vec![p(0., 0.), p(5., 0.), p(5., 6.), p(0., 6.), p(0., 0.)]),
Vec::new());
assert!(poly.intersects(&LineString(vec![p(2., 2.), p(6., 6.)])));
}
#[test]
fn linestring_outside_polygon_test() {
let p = |x, y| Point(Coordinate { x: x, y: y });
let poly = Polygon::new(LineString(vec![p(0., 0.), p(5., 0.), p(5., 6.), p(0., 6.), p(0., 0.)]),
Vec::new());
assert!(!poly.intersects(&LineString(vec![p(7., 2.), p(9., 4.)])));
}
#[test]
fn linestring_in_inner_polygon_test() {
let p = |x, y| Point(Coordinate { x: x, y: y });
let e = LineString(vec![p(0., 0.), p(5., 0.), p(5., 6.), p(0., 6.), p(0., 0.)]);
let v = vec![LineString(vec![p(1., 1.), p(4., 1.), p(4., 4.), p(1., 4.), p(1., 1.)])];
let poly = Polygon::new(e, v);
assert!(!poly.intersects(&LineString(vec![p(2., 2.), p(3., 3.)])));
assert!(poly.intersects(&LineString(vec![p(2., 2.), p(4., 4.)])));
}
#[test]
fn linestring_traverse_polygon_test() {
let p = |x, y| Point(Coordinate { x: x, y: y });
let e = LineString(vec![p(0., 0.), p(5., 0.), p(5., 6.), p(0., 6.), p(0., 0.)]);
let v = vec![LineString(vec![p(1., 1.), p(4., 1.), p(4., 4.), p(1., 4.), p(1., 1.)])];
let poly = Polygon::new(e, v);
assert!(poly.intersects(&LineString(vec![p(2., 0.5), p(2., 5.)])));
}
#[test]
fn linestring_in_inner_with_2_inner_polygon_test() {
let p = |x, y| Point(Coordinate { x: x, y: y });
let e = LineString(vec![p(2., 2.), p(14., 2.), p(14., 8.), p(2., 8.), p(2., 2.)]);
let v = vec![LineString(vec![p(4., 3.), p(7., 3.), p(7., 6.), p(4., 6.), p(4., 3.)]),
LineString(vec![p(9., 3.), p(12., 3.), p(12., 6.), p(9., 6.), p(9., 3.)])];
let poly = Polygon::new(e, v);
assert!(!poly.intersects(&LineString(vec![p(5., 4.), p(6., 5.)])));
assert!(poly.intersects(&LineString(vec![p(11., 2.5), p(11., 7.)])));
assert!(poly.intersects(&LineString(vec![p(4., 7.), p(6., 7.)])));
assert!(poly.intersects(&LineString(vec![p(8., 1.), p(8., 9.)])));
}
#[test]
fn polygons_do_not_intersect() {
let p = |x, y| Point(Coordinate { x: x, y: y });
let p1 = Polygon::new(LineString(vec![p(1., 3.), p(3., 3.), p(3., 5.), p(1., 5.), p(1., 3.)]),
Vec::new());
let p2 = Polygon::new(LineString(vec![p(10., 30.), p(30., 30.), p(30., 50.), p(10., 50.), p(10., 30.)]),
Vec::new());
assert!(!p1.intersects(&p2));
assert!(!p2.intersects(&p1));
}
#[test]
fn polygons_overlap() {
let p = |x, y| Point(Coordinate { x: x, y: y });
let p1 = Polygon::new(LineString(vec![p(1., 3.), p(3., 3.), p(3., 5.), p(1., 5.), p(1., 3.)]),
Vec::new());
let p2 = Polygon::new(LineString(vec![p(2., 3.), p(4., 3.), p(4., 7.), p(2., 7.), p(2., 3.)]),
Vec::new());
assert!(p1.intersects(&p2));
assert!(p2.intersects(&p1));
}
#[test]
fn polygon_contained() {
let p = |x, y| Point(Coordinate { x: x, y: y });
let p1 = Polygon::new(LineString(vec![p(1., 3.), p(4., 3.), p(4., 6.), p(1., 6.), p(1., 3.)]),
Vec::new());
let p2 = Polygon::new(LineString(vec![p(2., 4.), p(3., 4.), p(3., 5.), p(2., 5.), p(2., 4.)]),
Vec::new());
assert!(p1.intersects(&p2));
assert!(p2.intersects(&p1));
}
#[test]
fn polygons_conincident() {
let p = |x, y| Point(Coordinate { x: x, y: y });
let p1 = Polygon::new(LineString(vec![p(1., 3.), p(4., 3.), p(4., 6.), p(1., 6.), p(1., 3.)]),
Vec::new());
let p2 = Polygon::new(LineString(vec![p(1., 3.), p(4., 3.), p(4., 6.), p(1., 6.), p(1., 3.)]),
Vec::new());
assert!(p1.intersects(&p2));
assert!(p2.intersects(&p1));
}
#[test]
fn polygon_intersects_bbox_test() {
let p = |x, y| Point(Coordinate { x: x, y: y });
let poly = Polygon::new(LineString(vec![p(0., 0.), p(12., 0.), p(12., 8.), p(0., 8.), p(0., 0.)]),
vec![LineString(vec![p(7., 4.), p(11., 4.), p(11., 7.), p(7., 7.), p(7., 4.)])]);
let b1 = Bbox { xmin: 11.0, xmax: 13.0, ymin: 1.0, ymax: 2.0 };
let b2 = Bbox { xmin: 2.0, xmax: 8.0, ymin: 2.0, ymax: 5.0 };
let b3 = Bbox { xmin: 8.0, xmax: 10.0, ymin: 5.0, ymax: 6.0 };
let b4 = Bbox { xmin: 1.0, xmax: 3.0, ymin: 1.0, ymax: 3.0 };
assert!(poly.intersects(&b1));
assert!(poly.intersects(&b2));
assert!(!poly.intersects(&b3));
assert!(poly.intersects(&b4));
assert!(b1.intersects(&poly));
assert!(b2.intersects(&poly));
assert!(!b3.intersects(&poly));
assert!(b4.intersects(&poly));
}
#[test]
fn bbox_test() {
let bbox_xl = Bbox { xmin: -100., xmax: 100., ymin: -200., ymax: 200.};
let bbox_sm = Bbox { xmin: -10., xmax: 10., ymin: -20., ymax: 20.};
let bbox_s2 = Bbox { xmin: 0., xmax: 20., ymin: 0., ymax: 30.};
assert_eq!(false, bbox_xl.intersects(&bbox_sm));
assert_eq!(false, bbox_sm.intersects(&bbox_xl));
assert_eq!(true, bbox_sm.intersects(&bbox_s2));
assert_eq!(true, bbox_s2.intersects(&bbox_sm));
}
}