|
/* 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/Format/WKT.js |
|
* @requires OpenLayers/Feature/Vector.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. |
|
*/ |
|
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(); |
|
}, |
|
|
|
/** |
|
* Set the bounds for this Geometry. |
|
* |
|
* Parameters: |
|
* object - {<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>} |
|
* 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 the Well-Known Text representation of a geometry |
|
* |
|
* Returns: |
|
* {String} Well-Known Text |
|
*/ |
|
toString: function() { |
|
return OpenLayers.Format.WKT.prototype.write( |
|
new OpenLayers.Feature.Vector(this) |
|
); |
|
}, |
|
|
|
CLASS_NAME: "OpenLayers.Geometry" |
|
}); |
|
|
|
/** |
|
* Function: OpenLayers.Geometry.fromWKT |
|
* Generate a geometry given a Well-Known Text string. |
|
* |
|
* 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 format = arguments.callee.format; |
|
if(!format) { |
|
format = new OpenLayers.Format.WKT(); |
|
arguments.callee.format = format; |
|
} |
|
var geom; |
|
var result = format.read(wkt); |
|
if(result instanceof OpenLayers.Feature.Vector) { |
|
geom = result.geometry; |
|
} else if(result instanceof Array) { |
|
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; |
|