heli-agri
Version:
HeliAgri is a high-performance, feature-packed library for creating interactive maps on the web. It can display map tiles, vector data and markers loaded from any source on any web page. OpenLayers has been developed to further the use of geographic infor
300 lines (299 loc) • 9.96 kB
JavaScript
/**
* @module ol/geom/GeometryCollection
*/
import EventType from '../events/EventType.js';
import Geometry from './Geometry.js';
import { closestSquaredDistanceXY, createOrUpdateEmpty, extend, getCenter, } from '../extent.js';
import { listen, unlistenByKey } from '../events.js';
/**
* @classdesc
* An array of {@link module:ol/geom/Geometry~Geometry} objects.
*
* @api
*/
class GeometryCollection extends Geometry {
/**
* @param {Array<Geometry>} [geometries] Geometries.
*/
constructor(geometries) {
super();
/**
* @private
* @type {Array<Geometry>}
*/
this.geometries_ = geometries ? geometries : null;
/**
* @type {Array<import("../events.js").EventsKey>}
*/
this.changeEventsKeys_ = [];
this.listenGeometriesChange_();
}
/**
* @private
*/
unlistenGeometriesChange_() {
this.changeEventsKeys_.forEach(unlistenByKey);
this.changeEventsKeys_.length = 0;
}
/**
* @private
*/
listenGeometriesChange_() {
if (!this.geometries_) {
return;
}
for (let i = 0, ii = this.geometries_.length; i < ii; ++i) {
this.changeEventsKeys_.push(listen(this.geometries_[i], EventType.CHANGE, this.changed, this));
}
}
/**
* Make a complete copy of the geometry.
* @return {!GeometryCollection} Clone.
* @api
*/
clone() {
const geometryCollection = new GeometryCollection(null);
geometryCollection.setGeometries(this.geometries_);
geometryCollection.applyProperties(this);
return geometryCollection;
}
/**
* @param {number} x X.
* @param {number} y Y.
* @param {import("../coordinate.js").Coordinate} closestPoint Closest point.
* @param {number} minSquaredDistance Minimum squared distance.
* @return {number} Minimum squared distance.
*/
closestPointXY(x, y, closestPoint, minSquaredDistance) {
if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {
return minSquaredDistance;
}
const geometries = this.geometries_;
for (let i = 0, ii = geometries.length; i < ii; ++i) {
minSquaredDistance = geometries[i].closestPointXY(x, y, closestPoint, minSquaredDistance);
}
return minSquaredDistance;
}
/**
* @param {number} x X.
* @param {number} y Y.
* @return {boolean} Contains (x, y).
*/
containsXY(x, y) {
const geometries = this.geometries_;
for (let i = 0, ii = geometries.length; i < ii; ++i) {
if (geometries[i].containsXY(x, y)) {
return true;
}
}
return false;
}
/**
* @param {import("../extent.js").Extent} extent Extent.
* @protected
* @return {import("../extent.js").Extent} extent Extent.
*/
computeExtent(extent) {
createOrUpdateEmpty(extent);
const geometries = this.geometries_;
for (let i = 0, ii = geometries.length; i < ii; ++i) {
extend(extent, geometries[i].getExtent());
}
return extent;
}
/**
* Return the geometries that make up this geometry collection.
* @return {Array<Geometry>} Geometries.
* @api
*/
getGeometries() {
return cloneGeometries(this.geometries_);
}
/**
* @return {Array<Geometry>} Geometries.
*/
getGeometriesArray() {
return this.geometries_;
}
/**
* @return {Array<Geometry>} Geometries.
*/
getGeometriesArrayRecursive() {
/** @type {Array<Geometry>} */
let geometriesArray = [];
const geometries = this.geometries_;
for (let i = 0, ii = geometries.length; i < ii; ++i) {
if (geometries[i].getType() === this.getType()) {
geometriesArray = geometriesArray.concat(
/** @type {GeometryCollection} */ (geometries[i]).getGeometriesArrayRecursive());
}
else {
geometriesArray.push(geometries[i]);
}
}
return geometriesArray;
}
/**
* Create a simplified version of this geometry using the Douglas Peucker algorithm.
* @param {number} squaredTolerance Squared tolerance.
* @return {GeometryCollection} Simplified GeometryCollection.
*/
getSimplifiedGeometry(squaredTolerance) {
if (this.simplifiedGeometryRevision !== this.getRevision()) {
this.simplifiedGeometryMaxMinSquaredTolerance = 0;
this.simplifiedGeometryRevision = this.getRevision();
}
if (squaredTolerance < 0 ||
(this.simplifiedGeometryMaxMinSquaredTolerance !== 0 &&
squaredTolerance < this.simplifiedGeometryMaxMinSquaredTolerance)) {
return this;
}
const simplifiedGeometries = [];
const geometries = this.geometries_;
let simplified = false;
for (let i = 0, ii = geometries.length; i < ii; ++i) {
const geometry = geometries[i];
const simplifiedGeometry = geometry.getSimplifiedGeometry(squaredTolerance);
simplifiedGeometries.push(simplifiedGeometry);
if (simplifiedGeometry !== geometry) {
simplified = true;
}
}
if (simplified) {
const simplifiedGeometryCollection = new GeometryCollection(null);
simplifiedGeometryCollection.setGeometriesArray(simplifiedGeometries);
return simplifiedGeometryCollection;
}
this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance;
return this;
}
/**
* Get the type of this geometry.
* @return {import("./Geometry.js").Type} Geometry type.
* @api
*/
getType() {
return 'GeometryCollection';
}
/**
* Test if the geometry and the passed extent intersect.
* @param {import("../extent.js").Extent} extent Extent.
* @return {boolean} `true` if the geometry and the extent intersect.
* @api
*/
intersectsExtent(extent) {
const geometries = this.geometries_;
for (let i = 0, ii = geometries.length; i < ii; ++i) {
if (geometries[i].intersectsExtent(extent)) {
return true;
}
}
return false;
}
/**
* @return {boolean} Is empty.
*/
isEmpty() {
return this.geometries_.length === 0;
}
/**
* Rotate the geometry around a given coordinate. This modifies the geometry
* coordinates in place.
* @param {number} angle Rotation angle in radians.
* @param {import("../coordinate.js").Coordinate} anchor The rotation center.
* @api
*/
rotate(angle, anchor) {
const geometries = this.geometries_;
for (let i = 0, ii = geometries.length; i < ii; ++i) {
geometries[i].rotate(angle, anchor);
}
this.changed();
}
/**
* Scale the geometry (with an optional origin). This modifies the geometry
* coordinates in place.
* @abstract
* @param {number} sx The scaling factor in the x-direction.
* @param {number} [sy] The scaling factor in the y-direction (defaults to sx).
* @param {import("../coordinate.js").Coordinate} [anchor] The scale origin (defaults to the center
* of the geometry extent).
* @api
*/
scale(sx, sy, anchor) {
if (!anchor) {
anchor = getCenter(this.getExtent());
}
const geometries = this.geometries_;
for (let i = 0, ii = geometries.length; i < ii; ++i) {
geometries[i].scale(sx, sy, anchor);
}
this.changed();
}
/**
* Set the geometries that make up this geometry collection.
* @param {Array<Geometry>} geometries Geometries.
* @api
*/
setGeometries(geometries) {
this.setGeometriesArray(cloneGeometries(geometries));
}
/**
* @param {Array<Geometry>} geometries Geometries.
*/
setGeometriesArray(geometries) {
this.unlistenGeometriesChange_();
this.geometries_ = geometries;
this.listenGeometriesChange_();
this.changed();
}
/**
* Apply a transform function to the coordinates of the geometry.
* The geometry is modified in place.
* If you do not want the geometry modified in place, first `clone()` it and
* then use this function on the clone.
* @param {import("../proj.js").TransformFunction} transformFn Transform function.
* Called with a flat array of geometry coordinates.
* @api
*/
applyTransform(transformFn) {
const geometries = this.geometries_;
for (let i = 0, ii = geometries.length; i < ii; ++i) {
geometries[i].applyTransform(transformFn);
}
this.changed();
}
/**
* Translate the geometry. This modifies the geometry coordinates in place. If
* instead you want a new geometry, first `clone()` this geometry.
* @param {number} deltaX Delta X.
* @param {number} deltaY Delta Y.
* @api
*/
translate(deltaX, deltaY) {
const geometries = this.geometries_;
for (let i = 0, ii = geometries.length; i < ii; ++i) {
geometries[i].translate(deltaX, deltaY);
}
this.changed();
}
/**
* Clean up.
*/
disposeInternal() {
this.unlistenGeometriesChange_();
super.disposeInternal();
}
}
/**
* @param {Array<Geometry>} geometries Geometries.
* @return {Array<Geometry>} Cloned geometries.
*/
function cloneGeometries(geometries) {
const clonedGeometries = [];
for (let i = 0, ii = geometries.length; i < ii; ++i) {
clonedGeometries.push(geometries[i].clone());
}
return clonedGeometries;
}
export default GeometryCollection;