| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457 |
- /* Copyright (c) 2006-2011 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/BaseTypes/Class.js
- * @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(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, 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.
- */
- OpenLayers.Geometry.distanceToSegment = 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.sqrt(Math.pow(x - x0, 2) + Math.pow(y - y0, 2)),
- x: x, y: y
- };
- };
|