More trip planner testing with colors
[busui.git] / labs / openlayers / lib / OpenLayers / Geometry / Polygon.js
blob:a/labs/openlayers/lib/OpenLayers/Geometry/Polygon.js -> blob:b/labs/openlayers/lib/OpenLayers/Geometry/Polygon.js
  /* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
  * full list of contributors). Published under the Clear BSD license.
  * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
   
  /**
  * @requires OpenLayers/Geometry/Collection.js
  * @requires OpenLayers/Geometry/LinearRing.js
  */
   
  /**
  * Class: OpenLayers.Geometry.Polygon
  * Polygon is a collection of Geometry.LinearRings.
  *
  * Inherits from:
  * - <OpenLayers.Geometry.Collection>
  * - <OpenLayers.Geometry>
  */
  OpenLayers.Geometry.Polygon = OpenLayers.Class(
  OpenLayers.Geometry.Collection, {
   
  /**
  * Property: componentTypes
  * {Array(String)} An array of class names representing the types of
  * components that the collection can include. A null value means the
  * component types are not restricted.
  */
  componentTypes: ["OpenLayers.Geometry.LinearRing"],
   
  /**
  * Constructor: OpenLayers.Geometry.Polygon
  * Constructor for a Polygon geometry.
  * The first ring (this.component[0])is the outer bounds of the polygon and
  * all subsequent rings (this.component[1-n]) are internal holes.
  *
  *
  * Parameters:
  * components - {Array(<OpenLayers.Geometry.LinearRing>)}
  */
  initialize: function(components) {
  OpenLayers.Geometry.Collection.prototype.initialize.apply(this,
  arguments);
  },
   
  /**
  * APIMethod: getArea
  * Calculated by subtracting the areas of the internal holes from the
  * area of the outer hole.
  *
  * Returns:
  * {float} The area of the geometry
  */
  getArea: function() {
  var area = 0.0;
  if ( this.components && (this.components.length > 0)) {
  area += Math.abs(this.components[0].getArea());
  for (var i=1, len=this.components.length; i<len; i++) {
  area -= Math.abs(this.components[i].getArea());
  }
  }
  return area;
  },
   
  /**
  * APIMethod: getGeodesicArea
  * Calculate the approximate area of the polygon were it projected onto
  * the earth.
  *
  * Parameters:
  * projection - {<OpenLayers.Projection>} The spatial reference system
  * for the geometry coordinates. If not provided, Geographic/WGS84 is
  * assumed.
  *
  * Reference:
  * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for
  * Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion
  * Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409
  *
  * Returns:
  * {float} The approximate geodesic area of the polygon in square meters.
  */
  getGeodesicArea: function(projection) {
  var area = 0.0;
  if(this.components && (this.components.length > 0)) {
  area += Math.abs(this.components[0].getGeodesicArea(projection));
  for(var i=1, len=this.components.length; i<len; i++) {
  area -= Math.abs(this.components[i].getGeodesicArea(projection));
  }
  }
  return area;
  },
   
  /**
  * Method: containsPoint
  * Test if a point is inside a polygon. Points on a polygon edge are
  * considered inside.
  *
  * Parameters:
  * point - {<OpenLayers.Geometry.Point>}
  *
  * Returns:
  * {Boolean | Number} The point is inside the polygon. Returns 1 if the
  * point is on an edge. Returns boolean otherwise.
  */
  containsPoint: function(point) {
  var numRings = this.components.length;
  var contained = false;
  if(numRings > 0) {
  // check exterior ring - 1 means on edge, boolean otherwise
  contained = this.components[0].containsPoint(point);
  if(contained !== 1) {
  if(contained && numRings > 1) {
  // check interior rings
  var hole;
  for(var i=1; i<numRings; ++i) {
  hole = this.components[i].containsPoint(point);
  if(hole) {
  if(hole === 1) {
  // on edge
  contained = 1;
  } else {
  // in hole
  contained = false;
  }
  break;
  }
  }
  }
  }
  }
  return contained;
  },
   
  /**
  * APIMethod: intersects
  * Determine if the input geometry intersects this one.
  *
  * Parameters:
  * geometry - {<OpenLayers.Geometry>} Any type of geometry.
  *
  * Returns:
  * {Boolean} The input geometry intersects this one.
  */
  intersects: function(geometry) {
  var intersect = false;
  var i, len;
  if(geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
  intersect = this.containsPoint(geometry);
  } else if(geometry.CLASS_NAME == "OpenLayers.Geometry.LineString" ||
  geometry.CLASS_NAME == "OpenLayers.Geometry.LinearRing") {
  // check if rings/linestrings intersect
  for(i=0, len=this.components.length; i<len; ++i) {
  intersect = geometry.intersects(this.components[i]);
  if(intersect) {
  break;
  }
  }
  if(!intersect) {
  // check if this poly contains points of the ring/linestring
  for(i=0, len=geometry.components.length; i<len; ++i) {
  intersect = this.containsPoint(geometry.components[i]);
  if(intersect) {
  break;
  }
  }
  }
  } else {
  for(i=0, len=geometry.components.length; i<len; ++ i) {
  intersect = this.intersects(geometry.components[i]);
  if(intersect) {
  break;
  }
  }
  }
  // check case where this poly is wholly contained by another
  if(!intersect && geometry.CLASS_NAME == "OpenLayers.Geometry.Polygon") {
  // exterior ring points will be contained in the other geometry
  var ring = this.components[0];
  for(i=0, len=ring.components.length; i<len; ++i) {
  intersect = geometry.containsPoint(ring.components[i]);
  if(intersect) {
  break;
  }
  }
  }
  return intersect;
  },
   
  /**
  * APIMethod: distanceTo
  * Calculate the closest distance between two geometries (on the x-y plane).
  *
  * Parameters:
  * geometry - {<OpenLayers.Geometry>} The target geometry.
  * options - {Object} Optional properties for configuring the distance
  * calculation.
  *
  * Valid options:
  * details - {Boolean} Return details from the distance calculation.
  * Default is false.
  * edge - {Boolean} Calculate the distance from this geometry to the
  * nearest edge of the target geometry. Default is true. If true,
  * calling distanceTo from a geometry that is wholly contained within
  * the target will result in a non-zero distance. If false, whenever
  * geometries intersect, calling distanceTo will return 0. If false,
  * details cannot be returned.
  *
  * Returns:
  * {Number | Object} The distance between this geometry and the target.
  * If details is true, the return will be an object with distance,
  * x0, y0, x1, and y1 properties. The x0 and y0 properties represent
  * the coordinates of the closest point on this geometry. The x1 and y1
  * properties represent the coordinates of the closest point on the
  * target geometry.
  */
  distanceTo: function(geometry, options) {
  var edge = !(options && options.edge === false);
  var result;
  // this is the case where we might not be looking for distance to edge
  if(!edge && this.intersects(geometry)) {
  result = 0;
  } else {
  result = OpenLayers.Geometry.Collection.prototype.distanceTo.apply(
  this, [geometry, options]
  );
  }
  return result;
  },
   
  CLASS_NAME: "OpenLayers.Geometry.Polygon"
  });
   
  /**
  * APIMethod: createRegularPolygon
  * Create a regular polygon around a radius. Useful for creating circles
  * and the like.
  *
  * Parameters:
  * origin - {<OpenLayers.Geometry.Point>} center of polygon.
  * radius - {Float} distance to vertex, in map units.
  * sides - {Integer} Number of sides. 20 approximates a circle.
  * rotation - {Float} original angle of rotation, in degrees.
  */
  OpenLayers.Geometry.Polygon.createRegularPolygon = function(origin, radius, sides, rotation) {
  var angle = Math.PI * ((1/sides) - (1/2));
  if(rotation) {
  angle += (rotation / 180) * Math.PI;
  }
  var rotatedAngle, x, y;
  var points = [];
  for(var i=0; i<sides; ++i) {
  rotatedAngle = angle + (i * 2 * Math.PI / sides);
  x = origin.x + (radius * Math.cos(rotatedAngle));
  y = origin.y + (radius * Math.sin(rotatedAngle));
  points.push(new OpenLayers.Geometry.Point(x, y));
  }
  var ring = new OpenLayers.Geometry.LinearRing(points);
  return new OpenLayers.Geometry.Polygon([ring]);
  };