text: /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
   * full list of contributors). Published under the 2-clause BSD license.
   * See license.txt in the OpenLayers distribution or repository for the
   * full text of the license. */
   
  /**
   * @requires OpenLayers/BaseTypes/Class.js
   */
  
  /**
   * Class: OpenLayers.Geometry
   * A Geometry is a description of a geographic object.  Create an instance of
   * this class with the <OpenLayers.Geometry> constructor.  This is a base class,
   * typical geometry types are described by subclasses of this class.
   *
   * Note that if you use the <OpenLayers.Geometry.fromWKT> method, you must
   * explicitly include the OpenLayers.Format.WKT in your build.
   */
  OpenLayers.Geometry = OpenLayers.Class({
  
      /**
       * Property: id
       * {String} A unique identifier for this geometry.
       */
      id: null,
  
      /**
       * Property: parent
       * {<OpenLayers.Geometry>}This is set when a Geometry is added as component
       * of another geometry
       */
      parent: null,
  
      /**
       * Property: bounds 
       * {<OpenLayers.Bounds>} The bounds of this geometry
       */
      bounds: null,
  
      /**
       * Constructor: OpenLayers.Geometry
       * Creates a geometry object.  
       */
      initialize: function() {
          this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME+ "_");
      },
      
      /**
       * Method: destroy
       * Destroy this geometry.
       */
      destroy: function() {
          this.id = null;
          this.bounds = null;
      },
      
      /**
       * APIMethod: clone
       * Create a clone of this geometry.  Does not set any non-standard
       *     properties of the cloned geometry.
       * 
       * Returns:
       * {<OpenLayers.Geometry>} An exact clone of this geometry.
       */
      clone: function() {
          return new OpenLayers.Geometry();
      },
      
      /**
       * Method: setBounds
       * Set the bounds for this Geometry.
       * 
       * Parameters:
       * bounds - {<OpenLayers.Bounds>} 
       */
      setBounds: function(bounds) {
          if (bounds) {
              this.bounds = bounds.clone();
          }
      },
      
      /**
       * Method: clearBounds
       * Nullify this components bounds and that of its parent as well.
       */
      clearBounds: function() {
          this.bounds = null;
          if (this.parent) {
              this.parent.clearBounds();
          }    
      },
      
      /**
       * Method: extendBounds
       * Extend the existing bounds to include the new bounds. 
       * If geometry's bounds is not yet set, then set a new Bounds.
       * 
       * Parameters:
       * newBounds - {<OpenLayers.Bounds>} 
       */
      extendBounds: function(newBounds){
          var bounds = this.getBounds();
          if (!bounds) {
              this.setBounds(newBounds);
          } else {
              this.bounds.extend(newBounds);
          }
      },
      
      /**
       * APIMethod: getBounds
       * Get the bounds for this Geometry. If bounds is not set, it 
       * is calculated again, this makes queries faster.
       * 
       * Returns:
       * {<OpenLayers.Bounds>}
       */
      getBounds: function() {
          if (this.bounds == null) {
              this.calculateBounds();
          }
          return this.bounds;
      },
      
      /** 
       * APIMethod: calculateBounds
       * Recalculate the bounds for the geometry. 
       */
      calculateBounds: function() {
          //
          // This should be overridden by subclasses.
          //
      },
      
      /**
       * 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 depend on the specific geometry type.
       * 
       * 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 x2 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) {
      },
      
      /**
       * APIMethod: getVertices
       * Return a list of all points in this geometry.
       *
       * Parameters:
       * nodes - {Boolean} For lines, only return vertices that are
       *     endpoints.  If false, for lines, only vertices that are not
       *     endpoints will be returned.  If not provided, all vertices will
       *     be returned.
       *
       * Returns:
       * {Array} A list of all vertices in the geometry.
       */
      getVertices: function(nodes) {
      },
  
      /**
       * Method: atPoint
       * Note - This is only an approximation based on the bounds of the 
       * geometry.
       * 
       * Parameters:
       * lonlat - {<OpenLayers.LonLat>|Object} OpenLayers.LonLat or an
       *     object with a 'lon' and 'lat' properties.
       * toleranceLon - {float} Optional tolerance in Geometric Coords
       * toleranceLat - {float} Optional tolerance in Geographic Coords
       * 
       * Returns:
       * {Boolean} Whether or not the geometry is at the specified location
       */
      atPoint: function(lonlat, toleranceLon, toleranceLat) {
          var atPoint = false;
          var bounds = this.getBounds();
          if ((bounds != null) && (lonlat != null)) {
  
              var dX = (toleranceLon != null) ? toleranceLon : 0;
              var dY = (toleranceLat != null) ? toleranceLat : 0;
      
              var toleranceBounds = 
                  new OpenLayers.Bounds(this.bounds.left - dX,
                                        this.bounds.bottom - dY,
                                        this.bounds.right + dX,
                                        this.bounds.top + dY);
  
              atPoint = toleranceBounds.containsLonLat(lonlat);
          }
          return atPoint;
      },
      
      /**
       * Method: getLength
       * Calculate the length of this geometry. This method is defined in
       * subclasses.
       * 
       * Returns:
       * {Float} The length of the collection by summing its parts
       */
      getLength: function() {
          //to be overridden by geometries that actually have a length
          //
          return 0.0;
      },
  
      /**
       * Method: getArea
       * Calculate the area of this geometry. This method is defined in subclasses.
       * 
       * Returns:
       * {Float} The area of the collection by summing its parts
       */
      getArea: function() {
          //to be overridden by geometries that actually have an area
          //
          return 0.0;
      },
      
      /**
       * APIMethod: getCentroid
       * Calculate the centroid of this geometry. This method is defined in subclasses.
       *
       * Returns:
       * {<OpenLayers.Geometry.Point>} The centroid of the collection
       */
      getCentroid: function() {
          return null;
      },
  
      /**
       * Method: toString
       * Returns a text representation of the geometry.  If the WKT format is
       *     included in a build, this will be the Well-Known Text 
       *     representation.
       *
       * Returns:
       * {String} String representation of this geometry.
       */
      toString: function() {
          var string;
          if (OpenLayers.Format && OpenLayers.Format.WKT) {
              string = OpenLayers.Format.WKT.prototype.write(
                  new OpenLayers.Feature.Vector(this)
              );
          } else {
              string = Object.prototype.toString.call(this);
          }
          return string;
      },
  
      CLASS_NAME: "OpenLayers.Geometry"
  });
  
  /**
   * Function: OpenLayers.Geometry.fromWKT
   * Generate a geometry given a Well-Known Text string.  For this method to
   *     work, you must include the OpenLayers.Format.WKT in your build 
   *     explicitly.
   *
   * Parameters:
   * wkt - {String} A string representing the geometry in Well-Known Text.
   *
   * Returns:
   * {<OpenLayers.Geometry>} A geometry of the appropriate class.
   */
  OpenLayers.Geometry.fromWKT = function(wkt) {
      var geom;
      if (OpenLayers.Format && OpenLayers.Format.WKT) {
          var format = OpenLayers.Geometry.fromWKT.format;
          if (!format) {
              format = new OpenLayers.Format.WKT();
              OpenLayers.Geometry.fromWKT.format = format;
          }
          var result = format.read(wkt);
          if (result instanceof OpenLayers.Feature.Vector) {
              geom = result.geometry;
          } else if (OpenLayers.Util.isArray(result)) {
              var len = result.length;
              var components = new Array(len);
              for (var i=0; i<len; ++i) {
                  components[i] = result[i].geometry;
              }
              geom = new OpenLayers.Geometry.Collection(components);
          }
      }
      return geom;
  };
      
  /**
   * Method: OpenLayers.Geometry.segmentsIntersect
   * Determine whether two line segments intersect.  Optionally calculates
   *     and returns the intersection point.  This function is optimized for
   *     cases where seg1.x2 >= seg2.x1 || seg2.x2 >= seg1.x1.  In those
   *     obvious cases where there is no intersection, the function should
   *     not be called.
   *
   * Parameters:
   * seg1 - {Object} Object representing a segment with properties x1, y1, x2,
   *     and y2.  The start point is represented by x1 and y1.  The end point
   *     is represented by x2 and y2.  Start and end are ordered so that x1 < x2.
   * seg2 - {Object} Object representing a segment with properties x1, y1, x2,
   *     and y2.  The start point is represented by x1 and y1.  The end point
   *     is represented by x2 and y2.  Start and end are ordered so that x1 < x2.
   * options - {Object} Optional properties for calculating the intersection.
   *
   * Valid options:
   * point - {Boolean} Return the intersection point.  If false, the actual
   *     intersection point will not be calculated.  If true and the segments
   *     intersect, the intersection point will be returned.  If true and
   *     the segments do not intersect, false will be returned.  If true and
   *     the segments are coincident, true will be returned.
   * tolerance - {Number} If a non-null value is provided, if the segments are
   *     within the tolerance distance, this will be considered an intersection.
   *     In addition, if the point option is true and the calculated intersection
   *     is within the tolerance distance of an end point, the endpoint will be
   *     returned instead of the calculated intersection.  Further, if the
   *     intersection is within the tolerance of endpoints on both segments, or
   *     if two segment endpoints are within the tolerance distance of eachother
   *     (but no intersection is otherwise calculated), an endpoint on the
   *     first segment provided will be returned.
   *
   * Returns:
   * {Boolean | <OpenLayers.Geometry.Point>}  The two segments intersect.
   *     If the point argument is true, the return will be the intersection
   *     point or false if none exists.  If point is true and the segments
   *     are coincident, return will be true (and the instersection is equal
   *     to the shorter segment).
   */
  OpenLayers.Geometry.segmentsIntersect = function(seg1, seg2, options) {
      var point = options && options.point;
      var tolerance = options && options.tolerance;
      var intersection = false;
      var x11_21 = seg1.x1 - seg2.x1;
      var y11_21 = seg1.y1 - seg2.y1;
      var x12_11 = seg1.x2 - seg1.x1;
      var y12_11 = seg1.y2 - seg1.y1;
      var y22_21 = seg2.y2 - seg2.y1;
      var x22_21 = seg2.x2 - seg2.x1;
      var d = (y22_21 * x12_11) - (x22_21 * y12_11);
      var n1 = (x22_21 * y11_21) - (y22_21 * x11_21);
      var n2 = (x12_11 * y11_21) - (y12_11 * x11_21);
      if(d == 0) {
          // parallel
          if(n1 == 0 && n2 == 0) {
              // coincident
              intersection = true;
          }
      } else {
          var along1 = n1 / d;
          var along2 = n2 / d;
          if(along1 >= 0 && along1 <= 1 && along2 >=0 && along2 <= 1) {
              // intersect
              if(!point) {
                  intersection = true;
              } else {
                  // calculate the intersection point
                  var x = seg1.x1 + (along1 * x12_11);
                  var y = seg1.y1 + (along1 * y12_11);
                  intersection = new OpenLayers.Geometry.Point(x, y);
              }
          }
      }
      if(tolerance) {
          var dist;
          if(intersection) {
              if(point) {
                  var segs = [seg1, seg2];
                  var seg, x, y;
                  // check segment endpoints for proximity to intersection
                  // set intersection to first endpoint within the tolerance
                  outer: for(var i=0; i<2; ++i) {
                      seg = segs[i];
                      for(var j=1; j<3; ++j) {
                          x = seg["x" + j];
                          y = seg["y" + j];
                          dist = Math.sqrt(
                              Math.pow(x - intersection.x, 2) +
                              Math.pow(y - intersection.y, 2)
                          );
                          if(dist < tolerance) {
                              intersection.x = x;
                              intersection.y = y;
                              break outer;
                          }
                      }
                  }
                  
              }
          } else {
              // no calculated intersection, but segments could be within
              // the tolerance of one another
              var segs = [seg1, seg2];
              var source, target, x, y, p, result;
              // check segment endpoints for proximity to intersection
              // set intersection to first endpoint within the tolerance
              outer: for(var i=0; i<2; ++i) {
                  source = segs[i];
                  target = segs[(i+1)%2];
                  for(var j=1; j<3; ++j) {
                      p = {x: source["x"+j], y: source["y"+j]};
                      result = OpenLayers.Geometry.distanceToSegment(p, target);
                      if(result.distance < tolerance) {
                          if(point) {
                              intersection = new OpenLayers.Geometry.Point(p.x, p.y);
                          } else {
                              intersection = true;
                          }
                          break outer;
                      }
                  }
              }
          }
      }
      return intersection;
  };
  
  /**
   * Function: OpenLayers.Geometry.distanceToSegment
   *
   * Parameters:
   * point - {Object} An object with x and y properties representing the
   *     point coordinates.
   * segment - {Object} An object with x1, y1, x2, and y2 properties
   *     representing endpoint coordinates.
   *
   * Returns:
   * {Object} An object with distance, along, x, and y properties.  The distance
   *     will be the shortest distance between the input point and segment.
   *     The x and y properties represent the coordinates along the segment
   *     where the shortest distance meets the segment. The along attribute
   *     describes how far between the two segment points the given point is.
   */
  OpenLayers.Geometry.distanceToSegment = function(point, segment) {
      var result = OpenLayers.Geometry.distanceSquaredToSegment(point, segment);
      result.distance = Math.sqrt(result.distance);
      return result;
  };
  
  /**
   * Function: OpenLayers.Geometry.distanceSquaredToSegment
   *
   * Usually the distanceToSegment function should be used. This variant however
   * can be used for comparisons where the exact distance is not important.
   *
   * Parameters:
   * point - {Object} An object with x and y properties representing the
   *     point coordinates.
   * segment - {Object} An object with x1, y1, x2, and y2 properties
   *     representing endpoint coordinates.
   *
   * Returns:
   * {Object} An object with squared distance, along, x, and y properties.
   *     The distance will be the shortest distance between the input point and
   *     segment. The x and y properties represent the coordinates along the
   *     segment where the shortest distance meets the segment. The along
   *     attribute describes how far between the two segment points the given
   *     point is.
   */
  OpenLayers.Geometry.distanceSquaredToSegment = function(point, segment) {
      var x0 = point.x;
      var y0 = point.y;
      var x1 = segment.x1;
      var y1 = segment.y1;
      var x2 = segment.x2;
      var y2 = segment.y2;
      var dx = x2 - x1;
      var dy = y2 - y1;
      var along = ((dx * (x0 - x1)) + (dy * (y0 - y1))) /
                  (Math.pow(dx, 2) + Math.pow(dy, 2));
      var x, y;
      if(along <= 0.0) {
          x = x1;
          y = y1;
      } else if(along >= 1.0) {
          x = x2;
          y = y2;
      } else {
          x = x1 + along * dx;
          y = y1 + along * dy;
      }
      return {
          distance: Math.pow(x - x0, 2) + Math.pow(y - y0, 2),
          x: x, y: y,
          along: along
      };
  };
  