Polygon.js 9.2 KB

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