diff --git a/src/ol/geom/flat/containsflatgeom.js b/src/ol/geom/flat/containsflatgeom.js new file mode 100644 index 0000000000..e0d43c4da4 --- /dev/null +++ b/src/ol/geom/flat/containsflatgeom.js @@ -0,0 +1,92 @@ +goog.provide('ol.geom.flat.contains'); + +goog.require('goog.asserts'); +goog.require('ol.geom.flat'); + + +/** + * @param {Array.} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @param {number} x X. + * @param {number} y Y. + * @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; + 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; + } + x1 = x2; + y1 = y2; + } + return contains; +}; + + +/** + * @param {Array.} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.} ends Ends. + * @param {number} stride Stride. + * @param {number} x X. + * @param {number} y Y. + * @return {boolean} Contains (x, y). + */ +ol.geom.flat.contains.linearRingsContainsXY = + function(flatCoordinates, offset, ends, stride, x, y) { + goog.asserts.assert(ends.length > 0); + if (ends.length === 0) { + return false; + } + if (!ol.geom.flat.contains.linearRingContainsXY( + flatCoordinates, offset, ends[0], stride, x, y)) { + return false; + } + var i, ii; + for (i = 1, ii = ends.length; i < ii; ++i) { + if (ol.geom.flat.contains.linearRingContainsXY( + flatCoordinates, ends[i - 1], ends[i], stride, x, y)) { + return false; + } + } + return true; +}; + + +/** + * @param {Array.} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.>} endss Endss. + * @param {number} stride Stride. + * @param {number} x X. + * @param {number} y Y. + * @return {boolean} Contains (x, y). + */ +ol.geom.flat.contains.linearRingssContainsXY = + function(flatCoordinates, offset, endss, stride, x, y) { + goog.asserts.assert(endss.length > 0); + if (endss.length === 0) { + return false; + } + var i, ii; + for (i = 0, ii = endss.length; i < ii; ++i) { + var ends = endss[i]; + if (ol.geom.flat.contains.linearRingsContainsXY( + flatCoordinates, offset, ends, stride, x, y)) { + return true; + } + offset = ends[ends.length - 1]; + } + return false; +}; diff --git a/src/ol/geom/flat/interiorpointflatgeom.js b/src/ol/geom/flat/interiorpointflatgeom.js new file mode 100644 index 0000000000..cf7144c6dd --- /dev/null +++ b/src/ol/geom/flat/interiorpointflatgeom.js @@ -0,0 +1,93 @@ +goog.provide('ol.geom.flat.interiorpoint'); + +goog.require('goog.asserts'); +goog.require('ol.geom.flat'); +goog.require('ol.geom.flat.contains'); + + +/** + * 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 {Array.} flatCenters Flat centers. + * @param {number} flatCentersOffset Flat center offset. + * @param {Array.=} opt_dest Destination. + * @return {Array.} Destination. + */ +ol.geom.flat.interiorpoint.linearRings = 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 + var end = ends[0]; + x1 = flatCoordinates[end - stride]; + y1 = flatCoordinates[end - stride + 1]; + for (i = offset; i < end; i += stride) { + x2 = flatCoordinates[i]; + y2 = flatCoordinates[i + 1]; + if ((y <= y1 && y2 <= y) || (y1 <= y && y <= y2)) { + x = (y - y1) / (y2 - y1) * (x2 - x1) + x1; + intersections.push(x); + } + x1 = x2; + y1 = y2; + } + // Find the longest segment of the horizontal line that has its center point + // inside the linear ring. + var pointX = NaN; + var maxSegmentLength = -Infinity; + intersections.sort(); + x1 = intersections[0]; + for (i = 1, ii = intersections.length; i < ii; ++i) { + x2 = intersections[i]; + var segmentLength = Math.abs(x2 - x1); + if (segmentLength > maxSegmentLength) { + x = (x1 + x2) / 2; + if (ol.geom.flat.contains.linearRingsContainsXY( + flatCoordinates, offset, ends, stride, x, y)) { + pointX = x; + maxSegmentLength = segmentLength; + } + } + x1 = x2; + } + 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; + } else { + return [pointX, y]; + } +}; + + +/** + * @param {Array.} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {Array.>} endss Endss. + * @param {number} stride Stride. + * @param {Array.} flatCenters Flat centers. + * @return {Array.} Interior points. + */ +ol.geom.flat.interiorpoint.linearRingss = + 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.interiorpoint.linearRings(flatCoordinates, + offset, ends, stride, flatCenters, 2 * i, interiorPoints); + offset = ends[ends.length - 1]; + } + return interiorPoints; +}; diff --git a/src/ol/geom/flatgeom.js b/src/ol/geom/flatgeom.js index 917f4b6b3d..bdcdb53f03 100644 --- a/src/ol/geom/flatgeom.js +++ b/src/ol/geom/flatgeom.js @@ -198,182 +198,6 @@ ol.geom.flat.inflateCoordinatesss = }; -/** - * @param {Array.} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {number} end End. - * @param {number} stride Stride. - * @param {number} x X. - * @param {number} y Y. - * @return {boolean} Contains (x, y). - */ -ol.geom.flat.linearRingContainsXY = - function(flatCoordinates, offset, end, stride, x, y) { - // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html - var contains = false; - 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; - } - x1 = x2; - y1 = y2; - } - return contains; -}; - - -/** - * @param {Array.} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.} ends Ends. - * @param {number} stride Stride. - * @param {number} x X. - * @param {number} y Y. - * @return {boolean} Contains (x, y). - */ -ol.geom.flat.linearRingsContainsXY = - function(flatCoordinates, offset, ends, stride, x, y) { - goog.asserts.assert(ends.length > 0); - if (ends.length === 0) { - return false; - } - if (!ol.geom.flat.linearRingContainsXY( - flatCoordinates, offset, ends[0], stride, x, y)) { - return false; - } - var i, ii; - for (i = 1, ii = ends.length; i < ii; ++i) { - if (ol.geom.flat.linearRingContainsXY( - flatCoordinates, ends[i - 1], ends[i], stride, x, y)) { - return false; - } - } - return true; -}; - - -/** - * 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 {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, 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 - var end = ends[0]; - x1 = flatCoordinates[end - stride]; - y1 = flatCoordinates[end - stride + 1]; - for (i = offset; i < end; i += stride) { - x2 = flatCoordinates[i]; - y2 = flatCoordinates[i + 1]; - if ((y <= y1 && y2 <= y) || (y1 <= y && y <= y2)) { - x = (y - y1) / (y2 - y1) * (x2 - x1) + x1; - intersections.push(x); - } - x1 = x2; - y1 = y2; - } - // Find the longest segment of the horizontal line that has its center point - // inside the linear ring. - var pointX = NaN; - var maxSegmentLength = -Infinity; - intersections.sort(); - x1 = intersections[0]; - for (i = 1, ii = intersections.length; i < ii; ++i) { - x2 = intersections[i]; - var segmentLength = Math.abs(x2 - x1); - if (segmentLength > maxSegmentLength) { - x = (x1 + x2) / 2; - if (ol.geom.flat.linearRingsContainsXY( - flatCoordinates, offset, ends, stride, x, y)) { - pointX = x; - maxSegmentLength = segmentLength; - } - } - x1 = x2; - } - 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; - } else { - return [pointX, y]; - } -}; - - -/** - * @param {Array.} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.>} endss Endss. - * @param {number} stride Stride. - * @param {number} x X. - * @param {number} y Y. - * @return {boolean} Contains (x, y). - */ -ol.geom.flat.linearRingssContainsXY = - function(flatCoordinates, offset, endss, stride, x, y) { - goog.asserts.assert(endss.length > 0); - if (endss.length === 0) { - return false; - } - var i, ii; - for (i = 0, ii = endss.length; i < ii; ++i) { - var ends = endss[i]; - if (ol.geom.flat.linearRingsContainsXY( - flatCoordinates, offset, ends, stride, x, y)) { - return true; - } - offset = ends[ends.length - 1]; - } - return false; -}; - - -/** - * @param {Array.} flatCoordinates Flat coordinates. - * @param {number} offset Offset. - * @param {Array.>} endss Endss. - * @param {number} stride Stride. - * @param {Array.} flatCenters Flat centers. - * @return {Array.} Interior points. - */ -ol.geom.flat.linearRingssGetInteriorPoints = - 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, flatCenters, 2 * i, interiorPoints); - offset = ends[ends.length - 1]; - } - return interiorPoints; -}; - - /** * @param {Array.} flatCoordinates Flat coordinates. * @param {number} offset Offset. diff --git a/src/ol/geom/multipolygon.js b/src/ol/geom/multipolygon.js index 7000aef599..4d4343c033 100644 --- a/src/ol/geom/multipolygon.js +++ b/src/ol/geom/multipolygon.js @@ -10,6 +10,8 @@ goog.require('ol.geom.SimpleGeometry'); goog.require('ol.geom.flat'); goog.require('ol.geom.flat.area'); goog.require('ol.geom.flat.closest'); +goog.require('ol.geom.flat.contains'); +goog.require('ol.geom.flat.interiorpoint'); goog.require('ol.geom.flat.orient'); goog.require('ol.geom.flat.simplify'); @@ -134,7 +136,7 @@ ol.geom.MultiPolygon.prototype.closestPointXY = * @inheritDoc */ ol.geom.MultiPolygon.prototype.containsXY = function(x, y) { - return ol.geom.flat.linearRingssContainsXY( + return ol.geom.flat.contains.linearRingssContainsXY( this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, x, y); }; @@ -174,7 +176,7 @@ ol.geom.MultiPolygon.prototype.getFlatInteriorPoints = function() { if (this.flatInteriorPointsRevision_ != this.getRevision()) { var flatCenters = ol.geom.flat.linearRingssGetFlatCenters( this.flatCoordinates, 0, this.endss_, this.stride); - this.flatInteriorPoints_ = ol.geom.flat.linearRingssGetInteriorPoints( + this.flatInteriorPoints_ = ol.geom.flat.interiorpoint.linearRingss( this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, flatCenters); this.flatInteriorPointsRevision_ = this.getRevision(); diff --git a/src/ol/geom/polygon.js b/src/ol/geom/polygon.js index 5966f850bb..6c5b95b871 100644 --- a/src/ol/geom/polygon.js +++ b/src/ol/geom/polygon.js @@ -10,6 +10,8 @@ goog.require('ol.geom.SimpleGeometry'); goog.require('ol.geom.flat'); goog.require('ol.geom.flat.area'); goog.require('ol.geom.flat.closest'); +goog.require('ol.geom.flat.contains'); +goog.require('ol.geom.flat.interiorpoint'); goog.require('ol.geom.flat.orient'); goog.require('ol.geom.flat.simplify'); @@ -124,7 +126,7 @@ ol.geom.Polygon.prototype.closestPointXY = * @inheritDoc */ ol.geom.Polygon.prototype.containsXY = function(x, y) { - return ol.geom.flat.linearRingsContainsXY( + return ol.geom.flat.contains.linearRingsContainsXY( this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, x, y); }; @@ -163,7 +165,7 @@ ol.geom.Polygon.prototype.getEnds = function() { ol.geom.Polygon.prototype.getFlatInteriorPoint = function() { if (this.flatInteriorPointRevision_ != this.getRevision()) { var flatCenter = ol.extent.getCenter(this.getExtent()); - this.flatInteriorPoint_ = ol.geom.flat.linearRingsGetInteriorPoint( + this.flatInteriorPoint_ = ol.geom.flat.interiorpoint.linearRings( this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, flatCenter, 0); this.flatInteriorPointRevision_ = this.getRevision();