Polygon.js 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. /* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
  2. * full list of contributors). Published under the Clear BSD license.
  3. * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  4. * full text of the license. */
  5. /**
  6. * @requires OpenLayers/Geometry/Collection.js
  7. * @requires OpenLayers/Geometry/LinearRing.js
  8. */
  9. /**
  10. * Class: OpenLayers.Geometry.Polygon
  11. * Polygon is a collection of Geometry.LinearRings.
  12. *
  13. * Inherits from:
  14. * - <OpenLayers.Geometry.Collection>
  15. * - <OpenLayers.Geometry>
  16. */
  17. OpenLayers.Geometry.Polygon = OpenLayers.Class(
  18. OpenLayers.Geometry.Collection, {
  19. /**
  20. * Property: componentTypes
  21. * {Array(String)} An array of class names representing the types of
  22. * components that the collection can include. A null value means the
  23. * component types are not restricted.
  24. */
  25. componentTypes: ["OpenLayers.Geometry.LinearRing"],
  26. /**
  27. * Constructor: OpenLayers.Geometry.Polygon
  28. * Constructor for a Polygon geometry.
  29. * The first ring (this.component[0])is the outer bounds of the polygon and
  30. * all subsequent rings (this.component[1-n]) are internal holes.
  31. *
  32. *
  33. * Parameters:
  34. * components - {Array(<OpenLayers.Geometry.LinearRing>)}
  35. */
  36. initialize: function(components) {
  37. OpenLayers.Geometry.Collection.prototype.initialize.apply(this,
  38. arguments);
  39. },
  40. /**
  41. * APIMethod: getArea
  42. * Calculated by subtracting the areas of the internal holes from the
  43. * area of the outer hole.
  44. *
  45. * Returns:
  46. * {float} The area of the geometry
  47. */
  48. getArea: function() {
  49. var area = 0.0;
  50. if ( this.components && (this.components.length > 0)) {
  51. area += Math.abs(this.components[0].getArea());
  52. for (var i=1, len=this.components.length; i<len; i++) {
  53. area -= Math.abs(this.components[i].getArea());
  54. }
  55. }
  56. return area;
  57. },
  58. /**
  59. * APIMethod: getGeodesicArea
  60. * Calculate the approximate area of the polygon were it projected onto
  61. * the earth.
  62. *
  63. * Parameters:
  64. * projection - {<OpenLayers.Projection>} The spatial reference system
  65. * for the geometry coordinates. If not provided, Geographic/WGS84 is
  66. * assumed.
  67. *
  68. * Reference:
  69. * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for
  70. * Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion
  71. * Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409
  72. *
  73. * Returns:
  74. * {float} The approximate geodesic area of the polygon in square meters.
  75. */
  76. getGeodesicArea: function(projection) {
  77. var area = 0.0;
  78. if(this.components && (this.components.length > 0)) {
  79. area += Math.abs(this.components[0].getGeodesicArea(projection));
  80. for(var i=1, len=this.components.length; i<len; i++) {
  81. area -= Math.abs(this.components[i].getGeodesicArea(projection));
  82. }
  83. }
  84. return area;
  85. },
  86. /**
  87. * Method: containsPoint
  88. * Test if a point is inside a polygon. Points on a polygon edge are
  89. * considered inside.
  90. *
  91. * Parameters:
  92. * point - {<OpenLayers.Geometry.Point>}
  93. *
  94. * Returns:
  95. * {Boolean | Number} The point is inside the polygon. Returns 1 if the
  96. * point is on an edge. Returns boolean otherwise.
  97. */
  98. containsPoint: function(point) {
  99. var numRings = this.components.length;
  100. var contained = false;
  101. if(numRings > 0) {
  102. // check exterior ring - 1 means on edge, boolean otherwise
  103. contained = this.components[0].containsPoint(point);
  104. if(contained !== 1) {
  105. if(contained && numRings > 1) {
  106. // check interior rings
  107. var hole;
  108. for(var i=1; i<numRings; ++i) {
  109. hole = this.components[i].containsPoint(point);
  110. if(hole) {
  111. if(hole === 1) {
  112. // on edge
  113. contained = 1;
  114. } else {
  115. // in hole
  116. contained = false;
  117. }
  118. break;
  119. }
  120. }
  121. }
  122. }
  123. }
  124. return contained;
  125. },
  126. /**
  127. * APIMethod: intersects
  128. * Determine if the input geometry intersects this one.
  129. *
  130. * Parameters:
  131. * geometry - {<OpenLayers.Geometry>} Any type of geometry.
  132. *
  133. * Returns:
  134. * {Boolean} The input geometry intersects this one.
  135. */
  136. intersects: function(geometry) {
  137. var intersect = false;
  138. var i, len;
  139. if(geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
  140. intersect = this.containsPoint(geometry);
  141. } else if(geometry.CLASS_NAME == "OpenLayers.Geometry.LineString" ||
  142. geometry.CLASS_NAME == "OpenLayers.Geometry.LinearRing") {
  143. // check if rings/linestrings intersect
  144. for(i=0, len=this.components.length; i<len; ++i) {
  145. intersect = geometry.intersects(this.components[i]);
  146. if(intersect) {
  147. break;
  148. }
  149. }
  150. if(!intersect) {
  151. // check if this poly contains points of the ring/linestring
  152. for(i=0, len=geometry.components.length; i<len; ++i) {
  153. intersect = this.containsPoint(geometry.components[i]);
  154. if(intersect) {
  155. break;
  156. }
  157. }
  158. }
  159. } else {
  160. for(i=0, len=geometry.components.length; i<len; ++ i) {
  161. intersect = this.intersects(geometry.components[i]);
  162. if(intersect) {
  163. break;
  164. }
  165. }
  166. }
  167. // check case where this poly is wholly contained by another
  168. if(!intersect && geometry.CLASS_NAME == "OpenLayers.Geometry.Polygon") {
  169. // exterior ring points will be contained in the other geometry
  170. var ring = this.components[0];
  171. for(i=0, len=ring.components.length; i<len; ++i) {
  172. intersect = geometry.containsPoint(ring.components[i]);
  173. if(intersect) {
  174. break;
  175. }
  176. }
  177. }
  178. return intersect;
  179. },
  180. /**
  181. * APIMethod: distanceTo
  182. * Calculate the closest distance between two geometries (on the x-y plane).
  183. *
  184. * Parameters:
  185. * geometry - {<OpenLayers.Geometry>} The target geometry.
  186. * options - {Object} Optional properties for configuring the distance
  187. * calculation.
  188. *
  189. * Valid options:
  190. * details - {Boolean} Return details from the distance calculation.
  191. * Default is false.
  192. * edge - {Boolean} Calculate the distance from this geometry to the
  193. * nearest edge of the target geometry. Default is true. If true,
  194. * calling distanceTo from a geometry that is wholly contained within
  195. * the target will result in a non-zero distance. If false, whenever
  196. * geometries intersect, calling distanceTo will return 0. If false,
  197. * details cannot be returned.
  198. *
  199. * Returns:
  200. * {Number | Object} The distance between this geometry and the target.
  201. * If details is true, the return will be an object with distance,
  202. * x0, y0, x1, and y1 properties. The x0 and y0 properties represent
  203. * the coordinates of the closest point on this geometry. The x1 and y1
  204. * properties represent the coordinates of the closest point on the
  205. * target geometry.
  206. */
  207. distanceTo: function(geometry, options) {
  208. var edge = !(options && options.edge === false);
  209. var result;
  210. // this is the case where we might not be looking for distance to edge
  211. if(!edge && this.intersects(geometry)) {
  212. result = 0;
  213. } else {
  214. result = OpenLayers.Geometry.Collection.prototype.distanceTo.apply(
  215. this, [geometry, options]
  216. );
  217. }
  218. return result;
  219. },
  220. CLASS_NAME: "OpenLayers.Geometry.Polygon"
  221. });
  222. /**
  223. * APIMethod: createRegularPolygon
  224. * Create a regular polygon around a radius. Useful for creating circles
  225. * and the like.
  226. *
  227. * Parameters:
  228. * origin - {<OpenLayers.Geometry.Point>} center of polygon.
  229. * radius - {Float} distance to vertex, in map units.
  230. * sides - {Integer} Number of sides. 20 approximates a circle.
  231. * rotation - {Float} original angle of rotation, in degrees.
  232. */
  233. OpenLayers.Geometry.Polygon.createRegularPolygon = function(origin, radius, sides, rotation) {
  234. var angle = Math.PI * ((1/sides) - (1/2));
  235. if(rotation) {
  236. angle += (rotation / 180) * Math.PI;
  237. }
  238. var rotatedAngle, x, y;
  239. var points = [];
  240. for(var i=0; i<sides; ++i) {
  241. rotatedAngle = angle + (i * 2 * Math.PI / sides);
  242. x = origin.x + (radius * Math.cos(rotatedAngle));
  243. y = origin.y + (radius * Math.sin(rotatedAngle));
  244. points.push(new OpenLayers.Geometry.Point(x, y));
  245. }
  246. var ring = new OpenLayers.Geometry.LinearRing(points);
  247. return new OpenLayers.Geometry.Polygon([ring]);
  248. };