Files
openlayers/src/ol/geom/polygon.js
Tim Schaub 33457c48de Add transform method to geometries
In the typical sequence of parse-transform-render the most efficient place to transform coordinate values is deep within the parser immediately after values have been read (this would avoid a second pass over whatever structure is used to back geometries).  To accomplish this transform during parsing, we could add back parser read options to pass the transform function around.

Until then, a transform method on geometries is straightforward to implement.  This means we do a second pass through coordinate structures to transform, but this is typically done only once immediately after parsing.
2013-09-27 23:18:34 +01:00

177 lines
4.8 KiB
JavaScript

goog.provide('ol.geom.Polygon');
goog.require('goog.asserts');
goog.require('ol.CoordinateArray');
goog.require('ol.extent');
goog.require('ol.geom.Geometry');
goog.require('ol.geom.GeometryType');
goog.require('ol.geom.LinearRing');
/**
* Create a polygon from an array of vertex arrays. Coordinates for the
* exterior ring will be forced to clockwise order. Coordinates for any
* interior rings will be forced to counter-clockwise order. In cases where
* the opposite winding order occurs in the passed vertex arrays, they will
* be modified in place.
*
* @constructor
* @extends {ol.geom.Geometry}
* @param {Array.<ol.CoordinateArray>} coordinates Array of rings. First
* is outer, any remaining are inner.
*/
ol.geom.Polygon = function(coordinates) {
goog.base(this);
goog.asserts.assert(goog.isArray(coordinates[0][0]));
/**
* @private
* @type {ol.Coordinate}
*/
this.labelPoint_ = null;
var numRings = coordinates.length;
/**
* @type {Array.<ol.geom.LinearRing>}
*/
this.rings = new Array(numRings);
var ringCoords;
for (var i = 0; i < numRings; ++i) {
ringCoords = coordinates[i];
if (i === 0) {
// force exterior ring to be clockwise
if (!ol.geom.LinearRing.isClockwise(ringCoords)) {
ringCoords.reverse();
}
} else {
// force interior rings to be counter-clockwise
if (ol.geom.LinearRing.isClockwise(ringCoords)) {
ringCoords.reverse();
}
}
this.rings[i] = new ol.geom.LinearRing(ringCoords);
}
/**
* @type {number}
*/
this.dimension = coordinates[0][0].length;
goog.asserts.assert(this.dimension >= 2);
};
goog.inherits(ol.geom.Polygon, ol.geom.Geometry);
/**
* @inheritDoc
*/
ol.geom.Polygon.prototype.getBounds = function() {
return this.rings[0].getBounds();
};
/**
* @return {Array.<ol.CoordinateArray>} Coordinates array.
*/
ol.geom.Polygon.prototype.getCoordinates = function() {
var count = this.rings.length;
var coordinates = new Array(count);
for (var i = 0; i < count; ++i) {
coordinates[i] = this.rings[i].getCoordinates();
}
return coordinates;
};
/**
* @inheritDoc
*/
ol.geom.Polygon.prototype.getType = function() {
return ol.geom.GeometryType.POLYGON;
};
/**
* Check whether a given coordinate is inside this polygon. Note that this is a
* fast and simple check - points on an edge or vertex of the polygon or one of
* its inner rings are either classified inside or outside.
*
* @param {ol.Coordinate} coordinate Coordinate.
* @return {boolean} Whether the coordinate is inside the polygon.
*/
ol.geom.Polygon.prototype.containsCoordinate = function(coordinate) {
var rings = this.rings;
/** @type {boolean} */
var containsCoordinate;
for (var i = 0, ii = rings.length; i < ii; ++i) {
containsCoordinate = rings[i].containsCoordinate(coordinate);
// if inner ring (i > 0) contains coordinate, polygon does not contain it
if (i > 0) {
containsCoordinate = !containsCoordinate;
}
if (!containsCoordinate) {
break;
}
}
return containsCoordinate;
};
/**
* Calculates a point that is guaranteed to lie in the interior of the polygon.
* Inspired by JTS's com.vividsolutions.jts.geom.Geometry#getInteriorPoint.
* @return {ol.Coordinate} A point which is in the interior of the polygon.
*/
ol.geom.Polygon.prototype.getInteriorPoint = function() {
if (goog.isNull(this.labelPoint_)) {
var center = ol.extent.getCenter(this.getBounds()),
resultY = center[1],
vertices = this.rings[0].getCoordinates(),
intersections = [],
maxLength = 0,
i, vertex1, vertex2, x, segmentLength, resultX;
// Calculate intersections with the horizontal bounding box center line
for (i = vertices.length - 1; i >= 1; --i) {
vertex1 = vertices[i];
vertex2 = vertices[i - 1];
if ((vertex1[1] >= resultY && vertex2[1] <= resultY) ||
(vertex1[1] <= resultY && vertex2[1] >= resultY)) {
x = (resultY - vertex1[1]) / (vertex2[1] - vertex1[1]) *
(vertex2[0] - vertex1[0]) + vertex1[0];
intersections.push(x);
}
}
// Find the longest segment of the horizontal bounding box center line that
// has its center point inside the polygon
intersections.sort();
for (i = intersections.length - 1; i >= 1; --i) {
segmentLength = Math.abs(intersections[i] - intersections[i - 1]);
if (segmentLength > maxLength) {
x = (intersections[i] + intersections[i - 1]) / 2;
if (this.containsCoordinate([x, resultY])) {
maxLength = segmentLength;
resultX = x;
}
}
}
this.labelPoint_ = [resultX, resultY];
}
return this.labelPoint_;
};
/**
* @inheritDoc
*/
ol.geom.Polygon.prototype.transform = function(transform) {
var rings = this.rings;
for (var i = 0, ii = rings.length; i < ii; ++i) {
rings[i].transform(transform);
}
};