1 /* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
2 * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
3 * full text of the license. */
6 * @requires OpenLayers/Geometry/Collection.js
7 * @requires OpenLayers/Geometry/LinearRing.js
11 * Class: OpenLayers.Geometry.Polygon
12 * Polygon is a collection of Geometry.LinearRings.
15 * - <OpenLayers.Geometry.Collection>
16 * - <OpenLayers.Geometry>
18 OpenLayers.Geometry.Polygon = OpenLayers.Class(
19 OpenLayers.Geometry.Collection, {
22 * Property: componentTypes
23 * {Array(String)} An array of class names representing the types of
24 * components that the collection can include. A null value means the
25 * component types are not restricted.
27 componentTypes: ["OpenLayers.Geometry.LinearRing"],
30 * Constructor: OpenLayers.Geometry.Polygon
31 * Constructor for a Polygon geometry.
32 * The first ring (this.component[0])is the outer bounds of the polygon and
33 * all subsequent rings (this.component[1-n]) are internal holes.
37 * components - {Array(<OpenLayers.Geometry.LinearRing>)}
39 initialize: function(components) {
40 OpenLayers.Geometry.Collection.prototype.initialize.apply(this,
46 * Calculated by subtracting the areas of the internal holes from the
47 * area of the outer hole.
50 * {float} The area of the geometry
54 if ( this.components && (this.components.length > 0)) {
55 area += Math.abs(this.components[0].getArea());
56 for (var i=1, len=this.components.length; i<len; i++) {
57 area -= Math.abs(this.components[i].getArea());
64 * APIMethod: getGeodesicArea
65 * Calculate the approximate area of the polygon were it projected onto
69 * projection - {<OpenLayers.Projection>} The spatial reference system
70 * for the geometry coordinates. If not provided, Geographic/WGS84 is
74 * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for
75 * Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion
76 * Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409
79 * {float} The approximate geodesic area of the polygon in square meters.
81 getGeodesicArea: function(projection) {
83 if(this.components && (this.components.length > 0)) {
84 area += Math.abs(this.components[0].getGeodesicArea(projection));
85 for(var i=1, len=this.components.length; i<len; i++) {
86 area -= Math.abs(this.components[i].getGeodesicArea(projection));
93 * Method: containsPoint
94 * Test if a point is inside a polygon. Points on a polygon edge are
98 * point - {<OpenLayers.Geometry.Point>}
101 * {Boolean | Number} The point is inside the polygon. Returns 1 if the
102 * point is on an edge. Returns boolean otherwise.
104 containsPoint: function(point) {
105 var numRings = this.components.length;
106 var contained = false;
108 // check exterior ring - 1 means on edge, boolean otherwise
109 contained = this.components[0].containsPoint(point);
110 if(contained !== 1) {
111 if(contained && numRings > 1) {
112 // check interior rings
114 for(var i=1; i<numRings; ++i) {
115 hole = this.components[i].containsPoint(point);
134 * APIMethod: intersects
135 * Determine if the input geometry intersects this one.
138 * geometry - {<OpenLayers.Geometry>} Any type of geometry.
141 * {Boolean} The input geometry intersects this one.
143 intersects: function(geometry) {
144 var intersect = false;
146 if(geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
147 intersect = this.containsPoint(geometry);
148 } else if(geometry.CLASS_NAME == "OpenLayers.Geometry.LineString" ||
149 geometry.CLASS_NAME == "OpenLayers.Geometry.LinearRing") {
150 // check if rings/linestrings intersect
151 for(i=0, len=this.components.length; i<len; ++i) {
152 intersect = geometry.intersects(this.components[i]);
158 // check if this poly contains points of the ring/linestring
159 for(i=0, len=geometry.components.length; i<len; ++i) {
160 intersect = this.containsPoint(geometry.components[i]);
167 for(i=0, len=geometry.components.length; i<len; ++ i) {
168 intersect = this.intersects(geometry.components[i]);
174 // check case where this poly is wholly contained by another
175 if(!intersect && geometry.CLASS_NAME == "OpenLayers.Geometry.Polygon") {
176 // exterior ring points will be contained in the other geometry
177 var ring = this.components[0];
178 for(i=0, len=ring.components.length; i<len; ++i) {
179 intersect = geometry.containsPoint(ring.components[i]);
189 * APIMethod: distanceTo
190 * Calculate the closest distance between two geometries (on the x-y plane).
193 * geometry - {<OpenLayers.Geometry>} The target geometry.
194 * options - {Object} Optional properties for configuring the distance
198 * details - {Boolean} Return details from the distance calculation.
200 * edge - {Boolean} Calculate the distance from this geometry to the
201 * nearest edge of the target geometry. Default is true. If true,
202 * calling distanceTo from a geometry that is wholly contained within
203 * the target will result in a non-zero distance. If false, whenever
204 * geometries intersect, calling distanceTo will return 0. If false,
205 * details cannot be returned.
208 * {Number | Object} The distance between this geometry and the target.
209 * If details is true, the return will be an object with distance,
210 * x0, y0, x1, and y1 properties. The x0 and y0 properties represent
211 * the coordinates of the closest point on this geometry. The x1 and y1
212 * properties represent the coordinates of the closest point on the
215 distanceTo: function(geometry, options) {
216 var edge = !(options && options.edge === false);
218 // this is the case where we might not be looking for distance to edge
219 if(!edge && this.intersects(geometry)) {
222 result = OpenLayers.Geometry.Collection.prototype.distanceTo.apply(
223 this, [geometry, options]
229 CLASS_NAME: "OpenLayers.Geometry.Polygon"
233 * APIMethod: createRegularPolygon
234 * Create a regular polygon around a radius. Useful for creating circles
238 * origin - {<OpenLayers.Geometry.Point>} center of polygon.
239 * radius - {Float} distance to vertex, in map units.
240 * sides - {Integer} Number of sides. 20 approximates a circle.
241 * rotation - {Float} original angle of rotation, in degrees.
243 OpenLayers.Geometry.Polygon.createRegularPolygon = function(origin, radius, sides, rotation) {
244 var angle = Math.PI * ((1/sides) - (1/2));
246 angle += (rotation / 180) * Math.PI;
248 var rotatedAngle, x, y;
250 for(var i=0; i<sides; ++i) {
251 rotatedAngle = angle + (i * 2 * Math.PI / sides);
252 x = origin.x + (radius * Math.cos(rotatedAngle));
253 y = origin.y + (radius * Math.sin(rotatedAngle));
254 points.push(new OpenLayers.Geometry.Point(x, y));
256 var ring = new OpenLayers.Geometry.LinearRing(points);
257 return new OpenLayers.Geometry.Polygon([ring]);