Skip to content

Commit

Permalink
Correctly check for LineString containment in Polygon
Browse files Browse the repository at this point in the history
The [DE-9IM specification for [`containment`]
(http://docs.safe.com/fme/html/FME_Desktop_Documentation/FME_Transformers/Transformers/spatialrelations.htm#DE9IM_Matrix) states:

> The **interiors intersect** and no part of the candidate's interior
or boundary intersects the base's exterior. It is possible for the boundaries to intersect.

For `intersection`:

> The two features are not disjoint

For `disjoint`

> The boundaries and interiors do not intersect.

The current containment check deviates from this, in that it forbids
intersection (`!self.intersects(linestring)`), when in fact it should
be forbidding intersection with any _interior rings_. This PR fixes
that, and adds a test.

closes #157
  • Loading branch information
urschrei committed Sep 6, 2017
1 parent 63d54f0 commit d1ba7f4
Showing 1 changed file with 12 additions and 2 deletions.
14 changes: 12 additions & 2 deletions src/algorithm/contains.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,11 @@ impl<T> Contains<LineString<T>> for Polygon<T>
where T: Float
{
fn contains(&self, linestring: &LineString<T>) -> bool {
// All points of LineString must be in the polygon ?
// All LineString points must be inside the Polygon
if linestring.0.iter().all(|point| self.contains(point)) {
!self.intersects(linestring)
// The Polygon interior is allowed to intersect with the LineString
// but the Polygon's rings are not
!self.interiors.iter().any(|ring| ring.intersects(linestring))
} else {
false
}
Expand Down Expand Up @@ -246,6 +248,14 @@ impl<T> Contains<Bbox<T>> for Bbox<T>
mod test {
use types::{Coordinate, Point, Line, LineString, Polygon, MultiPolygon, Bbox};
use algorithm::contains::Contains;
#[test]
// LineString is fully contained
fn linestring_fully_contained_in_polygon() {
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![]);
let ls = LineString(vec![Point::new(3.0, 0.5), Point::new(3.0, 3.5)]);
assert_eq!(poly.contains(&ls), true);
}
/// Tests: Point in LineString
#[test]
fn empty_linestring_test() {
Expand Down

0 comments on commit d1ba7f4

Please sign in to comment.