diff --git a/src/ol/geom/linearring.js b/src/ol/geom/linearring.js index 8437fd8543..90bb945aa8 100644 --- a/src/ol/geom/linearring.js +++ b/src/ol/geom/linearring.js @@ -27,6 +27,42 @@ ol.geom.LinearRing = function(coordinates, opt_shared) { goog.inherits(ol.geom.LinearRing, ol.geom.LineString); +/** + * Determine of a vertex array representing a linear ring is in clockwise + * order. + * + * This method comes from Green's Theorem and was mentioned in an answer to a + * a Stack Overflow question (http://tinyurl.com/clockwise-method). + * + * Note that calculating the cross product for each pair of edges could be + * avoided by first finding the lowest, rightmost vertex. See OGR's + * implementation for an example of this. + * https://github.com/OSGeo/gdal/blob/trunk/gdal/ogr/ogrlinearring.cpp + * + * @param {ol.geom.VertexArray} coordinates Linear ring coordinates. + * @return {boolean} The coordinates are in clockwise order. + */ +ol.geom.LinearRing.isClockwise = function(coordinates) { + var length = coordinates.length; + var edge = 0; + + var last = coordinates[length - 1]; + var x1 = last[0]; + var y1 = last[1]; + + var x2, y2, coord; + for (var i = 0; i < length; ++i) { + coord = coordinates[i]; + x2 = coord[0]; + y2 = coord[1]; + edge += (x2 - x1) * (y2 + y1); + x1 = x2; + y1 = y2; + } + return edge > 0; +}; + + /** * @inheritDoc */ diff --git a/test/spec/ol/geom/linearring.test.js b/test/spec/ol/geom/linearring.test.js index 67b1da9935..8681773f7e 100644 --- a/test/spec/ol/geom/linearring.test.js +++ b/test/spec/ol/geom/linearring.test.js @@ -108,4 +108,39 @@ describe('ol.geom.LinearRing', function() { }); +describe('ol.geom.LinearRing.isClockwise()', function() { + + var isClockwise = ol.geom.LinearRing.isClockwise; + + it('returns true for clockwise coordinates', function() { + var coordinates = [ + [0, 0], [0, 1], [1, 1], [1, 0], [0, 0] + ]; + expect(isClockwise(coordinates)).to.be(true); + }); + + it('returns false for counter-clockwise coordinates', function() { + var coordinates = [ + [0, 0], [1, 0], [1, 1], [0, 1], [0, 0] + ]; + expect(isClockwise(coordinates)).to.be(false); + }); + + it('returns true for mostly clockwise, self-intersecting ring', function() { + var coordinates = [ + [0, 0], [0, 1], [1.5, 1], [1.5, 1.5], [1, 1.5], [1, 0], [0, 0] + ]; + expect(isClockwise(coordinates)).to.be(true); + }); + + it('returns false for mostly counter-clockwise, intersecting', function() { + var coordinates = [ + [0, 0], [1, 0], [1, 1.5], [1.5, 1.5], [1.5, 1], [0, 1], [0, 0] + ]; + expect(isClockwise(coordinates)).to.be(false); + }); + +}); + + goog.require('ol.geom.LinearRing');