diff --git a/src/ol/geom/flat/contains.js b/src/ol/geom/flat/contains.js index 3e7cfea7a0..e771be89eb 100644 --- a/src/ol/geom/flat/contains.js +++ b/src/ol/geom/flat/contains.js @@ -36,22 +36,30 @@ ol.geom.flat.contains.linearRingContainsExtent = function(flatCoordinates, offse * @return {boolean} Contains (x, y). */ ol.geom.flat.contains.linearRingContainsXY = function(flatCoordinates, offset, end, stride, x, y) { - // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html - var contains = false; + // http://geomalgorithms.com/a03-_inclusion.html + // Copyright 2000 softSurfer, 2012 Dan Sunday + // This code may be freely used and modified for any purpose + // providing that this copyright notice is included with it. + // SoftSurfer makes no warranty for this code, and cannot be held + // liable for any real or imagined damage resulting from its use. + // Users of this code must verify correctness for their application. + var wn = 0; var x1 = flatCoordinates[end - stride]; var y1 = flatCoordinates[end - stride + 1]; for (; offset < end; offset += stride) { var x2 = flatCoordinates[offset]; var y2 = flatCoordinates[offset + 1]; - var intersect = ((y1 > y) != (y2 > y)) && - (x < (x2 - x1) * (y - y1) / (y2 - y1) + x1); - if (intersect) { - contains = !contains; + if (y1 <= y) { + if (y2 > y && ((x2 - x1) * (y - y1)) - ((x - x1) * (y2 - y1)) > 0) { + wn++; + } + } else if (y2 <= y && ((x2 - x1) * (y - y1)) - ((x - x1) * (y2 - y1)) < 0) { + wn--; } x1 = x2; y1 = y2; } - return contains; + return wn !== 0; }; diff --git a/test/spec/ol/geom/flat/contains.test.js b/test/spec/ol/geom/flat/contains.test.js new file mode 100644 index 0000000000..3a35a8d5e8 --- /dev/null +++ b/test/spec/ol/geom/flat/contains.test.js @@ -0,0 +1,42 @@ +goog.provide('ol.test.geom.flat.contains'); + +goog.require('ol.geom.flat.contains'); + + +describe('ol.geom.flat.contains', function() { + + describe('with simple data', function() { + + var flatCoordinatesSimple = [0, 0, 1, 0, 1, 1, 0, 1]; + var flatCoordinatesNonSimple = [0, 0, 4, 0, 4, 3, 1, 3, 1, 2, 3, 2, 3, 1, 2, 1, 2, 4, 0, 4]; + + describe('ol.geom.flat.contains.linearRingContainsXY', function() { + + it('returns true for point inside a simple polygon', function() { + expect(ol.geom.flat.contains.linearRingContainsXY( + flatCoordinatesSimple, 0, flatCoordinatesSimple.length, 2, 0.5, 0.5)).to.be(true); + }); + + it('returns false for point outside a simple polygon', function() { + expect(ol.geom.flat.contains.linearRingContainsXY( + flatCoordinatesSimple, 0, flatCoordinatesSimple.length, 2, 1.5, 1.5)).to.be(false); + }); + + it('returns true for point inside a non-simple polygon', function() { + expect(ol.geom.flat.contains.linearRingContainsXY( + flatCoordinatesNonSimple, 0, flatCoordinatesNonSimple.length, 2, 1, 1)).to.be(true); + }); + + it('returns true for point inside an overlap of a non-simple polygon', function() { + expect(ol.geom.flat.contains.linearRingContainsXY( + flatCoordinatesNonSimple, 0, flatCoordinatesNonSimple.length, 2, 1.5, 2.5)).to.be(true); + }); + + it('returns false for a point inside a hole of a non-simple polygon', function() { + expect(ol.geom.flat.contains.linearRingContainsXY( + flatCoordinatesNonSimple, 0, flatCoordinatesNonSimple.length, 2, 2.5, 1.5)).to.be(false); + }); + + }); + }); +});