--- a/labs/openlayers/lib/OpenLayers/Geometry/Collection.js +++ b/labs/openlayers/lib/OpenLayers/Geometry/Collection.js @@ -1,1 +1,547 @@ - +/* 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.js + */ + +/** + * Class: OpenLayers.Geometry.Collection + * A Collection is exactly what it sounds like: A collection of different + * Geometries. These are stored in the local parameter (which + * can be passed as a parameter to the constructor). + * + * As new geometries are added to the collection, they are NOT cloned. + * When removing geometries, they need to be specified by reference (ie you + * have to pass in the *exact* geometry to be removed). + * + * The and functions here merely iterate through + * the components, summing their respective areas and lengths. + * + * Create a new instance with the constructor. + * + * Inerhits from: + * - + */ +OpenLayers.Geometry.Collection = OpenLayers.Class(OpenLayers.Geometry, { + + /** + * APIProperty: components + * {Array()} The component parts of this geometry + */ + components: null, + + /** + * 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: null, + + /** + * Constructor: OpenLayers.Geometry.Collection + * Creates a Geometry Collection -- a list of geoms. + * + * Parameters: + * components - {Array()} Optional array of geometries + * + */ + initialize: function (components) { + OpenLayers.Geometry.prototype.initialize.apply(this, arguments); + this.components = []; + if (components != null) { + this.addComponents(components); + } + }, + + /** + * APIMethod: destroy + * Destroy this geometry. + */ + destroy: function () { + this.components.length = 0; + this.components = null; + OpenLayers.Geometry.prototype.destroy.apply(this, arguments); + }, + + /** + * APIMethod: clone + * Clone this geometry. + * + * Returns: + * {} An exact clone of this collection + */ + clone: function() { + var geometry = eval("new " + this.CLASS_NAME + "()"); + for(var i=0, len=this.components.length; i 0) { + this.setBounds(this.components[0].getBounds()); + for (var i=1, len=this.components.length; i)} An array of geometries to add + */ + addComponents: function(components){ + if(!(components instanceof Array)) { + components = [components]; + } + for(var i=0, len=components.length; i} A geometry to add + * index - {int} Optional index into the array to insert the component + * + * Returns: + * {Boolean} The component geometry was successfully added + */ + addComponent: function(component, index) { + var added = false; + if(component) { + if(this.componentTypes == null || + (OpenLayers.Util.indexOf(this.componentTypes, + component.CLASS_NAME) > -1)) { + + if(index != null && (index < this.components.length)) { + var components1 = this.components.slice(0, index); + var components2 = this.components.slice(index, + this.components.length); + components1.push(component); + this.components = components1.concat(components2); + } else { + this.components.push(component); + } + component.parent = this; + this.clearBounds(); + added = true; + } + } + return added; + }, + + /** + * APIMethod: removeComponents + * Remove components from this geometry. + * + * Parameters: + * components - {Array()} The components to be removed + */ + removeComponents: function(components) { + if(!(components instanceof Array)) { + components = [components]; + } + for(var i=components.length-1; i>=0; --i) { + this.removeComponent(components[i]); + } + }, + + /** + * Method: removeComponent + * Remove a component from this geometry. + * + * Parameters: + * component - {} + */ + removeComponent: function(component) { + + OpenLayers.Util.removeItem(this.components, component); + + // clearBounds() so that it gets recalculated on the next call + // to this.getBounds(); + this.clearBounds(); + }, + + /** + * APIMethod: getLength + * Calculate the length of this geometry + * + * Returns: + * {Float} The length of the geometry + */ + getLength: function() { + var length = 0.0; + for (var i=0, len=this.components.length; i. + * + * Returns: + * {Float} The area of the collection by summing its parts + */ + getArea: function() { + var area = 0.0; + for (var i=0, len=this.components.length; i} 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 geometry in square meters. + */ + getGeodesicArea: function(projection) { + var area = 0.0; + for(var i=0, len=this.components.length; i} The centroid of the collection + */ + getCentroid: function(weighted) { + if (!weighted) { + return this.components.length && this.components[0].getCentroid(); + } + var len = this.components.length; + if (!len) { + return false; + } + + var areas = []; + var centroids = []; + var areaSum = 0; + var minArea = Number.MAX_VALUE; + var component; + for (var i=0; i 0) ? area : minArea; + centroids.push(centroid); + } + len = areas.length; + if (areaSum === 0) { + // all the components in this collection have 0 area + // probably a collection of points -- weight all the points the same + for (var i=0; i} The spatial reference system + * for the geometry coordinates. If not provided, Geographic/WGS84 is + * assumed. + * + * Returns: + * {Float} The appoximate geodesic length of the geometry in meters. + */ + getGeodesicLength: function(projection) { + var length = 0.0; + for(var i=0, len=this.components.length; i} Center point for the rotation + */ + rotate: function(angle, origin) { + for(var i=0, len=this.components.length; i} Point of origin for resizing + * ratio - {Float} Optional x:y ratio for resizing. Default ratio is 1. + * + * Returns: + * {OpenLayers.Geometry} - The current geometry. + */ + resize: function(scale, origin, ratio) { + for(var i=0; i} 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 details = edge && options && options.details; + var result, best, distance; + var min = Number.POSITIVE_INFINITY; + for(var i=0, len=this.components.length; i} The geometry to test. + * + * Returns: + * {Boolean} The supplied geometry is equivalent to this geometry. + */ + equals: function(geometry) { + var equivalent = true; + if(!geometry || !geometry.CLASS_NAME || + (this.CLASS_NAME != geometry.CLASS_NAME)) { + equivalent = false; + } else if(!(geometry.components instanceof Array) || + (geometry.components.length != this.components.length)) { + equivalent = false; + } else { + for(var i=0, len=this.components.length; i} + * dest - {} + * + * Returns: + * {} + */ + transform: function(source, dest) { + if (source && dest) { + for (var i=0, len=this.components.length; i} Any type of geometry. + * + * Returns: + * {Boolean} The input geometry intersects this one. + */ + intersects: function(geometry) { + var intersect = false; + for(var i=0, len=this.components.length; i