git-svn-id: http://svn.openlayers.org/trunk/openlayers@9074 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
433 lines
14 KiB
JavaScript
433 lines
14 KiB
JavaScript
/* Copyright (c) 2006-2008 MetaCarta, Inc., 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 <components> (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 <getArea> and <getLength> functions here merely iterate through
|
|
* the components, summing their respective areas and lengths.
|
|
*
|
|
* Create a new instance with the <OpenLayers.Geometry.Collection> constructor.
|
|
*
|
|
* Inerhits from:
|
|
* - <OpenLayers.Geometry>
|
|
*/
|
|
OpenLayers.Geometry.Collection = OpenLayers.Class(OpenLayers.Geometry, {
|
|
|
|
/**
|
|
* APIProperty: components
|
|
* {Array(<OpenLayers.Geometry>)} 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(<OpenLayers.Geometry>)} 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;
|
|
},
|
|
|
|
/**
|
|
* APIMethod: clone
|
|
* Clone this geometry.
|
|
*
|
|
* Returns:
|
|
* {<OpenLayers.Geometry.Collection>} An exact clone of this collection
|
|
*/
|
|
clone: function() {
|
|
var geometry = eval("new " + this.CLASS_NAME + "()");
|
|
for(var i=0, len=this.components.length; i<len; i++) {
|
|
geometry.addComponent(this.components[i].clone());
|
|
}
|
|
|
|
// catch any randomly tagged-on properties
|
|
OpenLayers.Util.applyDefaults(geometry, this);
|
|
|
|
return geometry;
|
|
},
|
|
|
|
/**
|
|
* Method: getComponentsString
|
|
* Get a string representing the components for this collection
|
|
*
|
|
* Returns:
|
|
* {String} A string representation of the components of this geometry
|
|
*/
|
|
getComponentsString: function(){
|
|
var strings = [];
|
|
for(var i=0, len=this.components.length; i<len; i++) {
|
|
strings.push(this.components[i].toShortString());
|
|
}
|
|
return strings.join(",");
|
|
},
|
|
|
|
/**
|
|
* APIMethod: calculateBounds
|
|
* Recalculate the bounds by iterating through the components and
|
|
* calling calling extendBounds() on each item.
|
|
*/
|
|
calculateBounds: function() {
|
|
this.bounds = null;
|
|
if ( this.components && this.components.length > 0) {
|
|
this.setBounds(this.components[0].getBounds());
|
|
for (var i=1, len=this.components.length; i<len; i++) {
|
|
this.extendBounds(this.components[i].getBounds());
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* APIMethod: addComponents
|
|
* Add components to this geometry.
|
|
*
|
|
* Parameters:
|
|
* components - {Array(<OpenLayers.Geometry>)} An array of geometries to add
|
|
*/
|
|
addComponents: function(components){
|
|
if(!(components instanceof Array)) {
|
|
components = [components];
|
|
}
|
|
for(var i=0, len=components.length; i<len; i++) {
|
|
this.addComponent(components[i]);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Method: addComponent
|
|
* Add a new component (geometry) to the collection. If this.componentTypes
|
|
* is set, then the component class name must be in the componentTypes array.
|
|
*
|
|
* The bounds cache is reset.
|
|
*
|
|
* Parameters:
|
|
* component - {<OpenLayers.Geometry>} 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(<OpenLayers.Geometry>)} 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 - {<OpenLayers.Geometry>}
|
|
*/
|
|
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<len; i++) {
|
|
length += this.components[i].getLength();
|
|
}
|
|
return length;
|
|
},
|
|
|
|
/**
|
|
* APIMethod: getArea
|
|
* Calculate the area of this geometry. Note how this function is overridden
|
|
* in <OpenLayers.Geometry.Polygon>.
|
|
*
|
|
* 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<len; i++) {
|
|
area += this.components[i].getArea();
|
|
}
|
|
return area;
|
|
},
|
|
|
|
/**
|
|
* APIMethod: move
|
|
* Moves a geometry by the given displacement along positive x and y axes.
|
|
* This modifies the position of the geometry and clears the cached
|
|
* bounds.
|
|
*
|
|
* Parameters:
|
|
* x - {Float} Distance to move geometry in positive x direction.
|
|
* y - {Float} Distance to move geometry in positive y direction.
|
|
*/
|
|
move: function(x, y) {
|
|
for(var i=0, len=this.components.length; i<len; i++) {
|
|
this.components[i].move(x, y);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* APIMethod: rotate
|
|
* Rotate a geometry around some origin
|
|
*
|
|
* Parameters:
|
|
* angle - {Float} Rotation angle in degrees (measured counterclockwise
|
|
* from the positive x-axis)
|
|
* origin - {<OpenLayers.Geometry.Point>} Center point for the rotation
|
|
*/
|
|
rotate: function(angle, origin) {
|
|
for(var i=0, len=this.components.length; i<len; ++i) {
|
|
this.components[i].rotate(angle, origin);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* APIMethod: resize
|
|
* Resize a geometry relative to some origin. Use this method to apply
|
|
* a uniform scaling to a geometry.
|
|
*
|
|
* Parameters:
|
|
* scale - {Float} Factor by which to scale the geometry. A scale of 2
|
|
* doubles the size of the geometry in each dimension
|
|
* (lines, for example, will be twice as long, and polygons
|
|
* will have four times the area).
|
|
* origin - {<OpenLayers.Geometry.Point>} 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<this.components.length; ++i) {
|
|
this.components[i].resize(scale, origin, ratio);
|
|
}
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 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 details = edge && options && options.details;
|
|
var result, best;
|
|
var min = Number.POSITIVE_INFINITY;
|
|
for(var i=0, len=this.components.length; i<len; ++i) {
|
|
result = this.components[i].distanceTo(geometry, options);
|
|
distance = details ? result.distance : result;
|
|
if(distance < min) {
|
|
min = distance;
|
|
best = result;
|
|
if(min == 0) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return best;
|
|
},
|
|
|
|
/**
|
|
* APIMethod: equals
|
|
* Determine whether another geometry is equivalent to this one. Geometries
|
|
* are considered equivalent if all components have the same coordinates.
|
|
*
|
|
* Parameters:
|
|
* geom - {<OpenLayers.Geometry>} 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<len; ++i) {
|
|
if(!this.components[i].equals(geometry.components[i])) {
|
|
equivalent = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return equivalent;
|
|
},
|
|
|
|
/**
|
|
* APIMethod: transform
|
|
* Reproject the components geometry from source to dest.
|
|
*
|
|
* Parameters:
|
|
* source - {<OpenLayers.Projection>}
|
|
* dest - {<OpenLayers.Projection>}
|
|
*
|
|
* Returns:
|
|
* {<OpenLayers.Geometry>}
|
|
*/
|
|
transform: function(source, dest) {
|
|
if (source && dest) {
|
|
for (var i=0, len=this.components.length; i<len; i++) {
|
|
var component = this.components[i];
|
|
component.transform(source, dest);
|
|
}
|
|
this.bounds = null;
|
|
}
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* 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;
|
|
for(var i=0, len=this.components.length; i<len; ++ i) {
|
|
intersect = geometry.intersects(this.components[i]);
|
|
if(intersect) {
|
|
break;
|
|
}
|
|
}
|
|
return intersect;
|
|
},
|
|
|
|
/**
|
|
* 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) {
|
|
var vertices = [];
|
|
for(var i=0, len=this.components.length; i<len; ++i) {
|
|
Array.prototype.push.apply(
|
|
vertices, this.components[i].getVertices(nodes)
|
|
);
|
|
}
|
|
return vertices;
|
|
},
|
|
|
|
|
|
CLASS_NAME: "OpenLayers.Geometry.Collection"
|
|
});
|