From a780936805e900990ff5631a3b032cdffac65155 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Thu, 23 Jan 2014 14:19:19 +0100 Subject: [PATCH] Fix getInteriorPoint calculation to always return a point --- src/ol/geom/flatgeom.js | 63 +++++++++++++++---------------------- src/ol/geom/multipolygon.js | 5 +-- src/ol/geom/polygon.js | 6 ++-- 3 files changed, 32 insertions(+), 42 deletions(-) diff --git a/src/ol/geom/flatgeom.js b/src/ol/geom/flatgeom.js index faf765d3ae..9e35919857 100644 --- a/src/ol/geom/flatgeom.js +++ b/src/ol/geom/flatgeom.js @@ -4,6 +4,7 @@ goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.math'); goog.require('goog.vec.Mat4'); +goog.require('ol.extent'); /** @@ -404,25 +405,6 @@ ol.geom.flat.linearRingIsClockwise = }; -/** - * @param {Array.} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @return {number} Mid Y. - */ -ol.geom.flat.linearRingMidY = function(flatCoordinates, offset, end, stride) { - var minY = Infinity; - var maxY = -Infinity; - for (; offset < end; offset += stride) { - var y = flatCoordinates[offset + 1]; - minY = Math.min(minY, y); - maxY = Math.max(maxY, y); - } - return (minY + maxY) / 2; -}; - - /** * @param {Array.} flatCoordinates Flat coordinates. * @param {number} offset Offset. @@ -491,20 +473,21 @@ ol.geom.flat.linearRingsContainsXY = /** - * Calculates a point that is guaranteed to lie in the interior of the linear - * rings. + * Calculates a point that is likely to lie in the interior of the linear rings. * Inspired by JTS's com.vividsolutions.jts.geom.Geometry#getInteriorPoint. * @param {Array.} flatCoordinates Flat coordinates. * @param {number} offset Offset. * @param {Array.} ends Ends. * @param {number} stride Stride. - * @param {number} y Y. + * @param {Array.} flatCenters Flat centers. + * @param {number} flatCentersOffset Flat center offset. * @param {Array.=} opt_dest Destination. * @return {Array.} Destination. */ -ol.geom.flat.linearRingsGetInteriorPoint = - function(flatCoordinates, offset, ends, stride, y, opt_dest) { +ol.geom.flat.linearRingsGetInteriorPoint = function(flatCoordinates, offset, + ends, stride, flatCenters, flatCentersOffset, opt_dest) { var i, ii, x, x1, x2, y1, y2; + var y = flatCenters[flatCentersOffset + 1]; /** @type {Array.} */ var intersections = []; // Calculate intersections with the horizontal line @@ -522,7 +505,7 @@ ol.geom.flat.linearRingsGetInteriorPoint = y1 = y2; } // Find the longest segment of the horizontal line that has its center point - // inside the polygon + // inside the linear ring. var pointX = NaN; var maxSegmentLength = -Infinity; intersections.sort(); @@ -540,7 +523,11 @@ ol.geom.flat.linearRingsGetInteriorPoint = } x1 = x2; } - goog.asserts.assert(!isNaN(pointX)); + if (isNaN(pointX)) { + // There is no horizontal line that has its center point inside the linear + // ring. Use the center of the the linear ring's extent. + pointX = flatCenters[flatCentersOffset]; + } if (goog.isDef(opt_dest)) { opt_dest.push(pointX, y); return opt_dest; @@ -648,18 +635,18 @@ ol.geom.flat.linearRingssContainsXY = * @param {number} offset Offset. * @param {Array.>} endss Endss. * @param {number} stride Stride. - * @param {Array.} ys Ys. + * @param {Array.} flatCenters Flat centers. * @return {Array.} Interior points. */ ol.geom.flat.linearRingssGetInteriorPoints = - function(flatCoordinates, offset, endss, stride, ys) { - goog.asserts.assert(endss.length == ys.length); + function(flatCoordinates, offset, endss, stride, flatCenters) { + goog.asserts.assert(2 * endss.length == flatCenters.length); var interiorPoints = []; var i, ii; for (i = 0, ii = endss.length; i < ii; ++i) { var ends = endss[i]; - interiorPoints = ol.geom.flat.linearRingsGetInteriorPoint( - flatCoordinates, offset, ends, stride, ys[i], interiorPoints); + interiorPoints = ol.geom.flat.linearRingsGetInteriorPoint(flatCoordinates, + offset, ends, stride, flatCenters, 2 * i, interiorPoints); offset = ends[ends.length - 1]; } return interiorPoints; @@ -671,19 +658,21 @@ ol.geom.flat.linearRingssGetInteriorPoints = * @param {number} offset Offset. * @param {Array.>} endss Endss. * @param {number} stride Stride. - * @return {Array.} Mid Ys. + * @return {Array.} Flat centers. */ -ol.geom.flat.linearRingssMidYs = +ol.geom.flat.linearRingssGetFlatCenters = function(flatCoordinates, offset, endss, stride) { - var midYs = []; + var flatCenters = []; var i, ii; + var extent = ol.extent.createEmpty(); for (i = 0, ii = endss.length; i < ii; ++i) { var ends = endss[i]; - midYs.push( - ol.geom.flat.linearRingMidY(flatCoordinates, offset, ends[0], stride)); + extent = ol.extent.createOrUpdateFromFlatCoordinates( + flatCoordinates, offset, ends[0], stride); + flatCenters.push((extent[0] + extent[2]) / 2, (extent[1] + extent[3]) / 2); offset = ends[ends.length - 1]; } - return midYs; + return flatCenters; }; diff --git a/src/ol/geom/multipolygon.js b/src/ol/geom/multipolygon.js index ffb8089491..21d2ce6049 100644 --- a/src/ol/geom/multipolygon.js +++ b/src/ol/geom/multipolygon.js @@ -142,10 +142,11 @@ ol.geom.MultiPolygon.prototype.getEndss = function() { */ ol.geom.MultiPolygon.prototype.getFlatInteriorPoints = function() { if (this.flatInteriorPointsRevision_ != this.getRevision()) { - var ys = ol.geom.flat.linearRingssMidYs( + var flatCenters = ol.geom.flat.linearRingssGetFlatCenters( this.flatCoordinates, 0, this.endss_, this.stride); this.flatInteriorPoints_ = ol.geom.flat.linearRingssGetInteriorPoints( - this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, ys); + this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, + flatCenters); this.flatInteriorPointsRevision_ = this.getRevision(); } return this.flatInteriorPoints_; diff --git a/src/ol/geom/polygon.js b/src/ol/geom/polygon.js index d60b25fc7d..02431cb60e 100644 --- a/src/ol/geom/polygon.js +++ b/src/ol/geom/polygon.js @@ -142,10 +142,10 @@ ol.geom.Polygon.prototype.getEnds = function() { */ ol.geom.Polygon.prototype.getFlatInteriorPoint = function() { if (this.flatInteriorPointRevision_ != this.getRevision()) { - var extent = this.getExtent(); - var y = (extent[1] + extent[3]) / 2; + var flatCenter = ol.extent.getCenter(this.getExtent()); this.flatInteriorPoint_ = ol.geom.flat.linearRingsGetInteriorPoint( - this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, y); + this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, + flatCenter, 0); this.flatInteriorPointRevision_ = this.getRevision(); } return this.flatInteriorPoint_;