@terrestris/ol-util
Version:
A set of helper classes for working with openLayers
358 lines • 15.4 kB
JavaScript
import buffer from '@turf/buffer';
import difference from '@turf/difference';
import intersect from '@turf/intersect';
import { featureCollection, flatten } from '@turf/turf';
import union from '@turf/union';
import isNil from 'lodash/isNil';
import OlFeature from 'ol/Feature';
import OlFormatGeoJSON from 'ol/format/GeoJSON';
import OlGeomLineString from 'ol/geom/LineString';
import OlGeomMultiLineString from 'ol/geom/MultiLineString';
import OlGeomMultiPoint from 'ol/geom/MultiPoint';
import OlGeomMultiPolygon from 'ol/geom/MultiPolygon';
import OlGeomPolygon from 'ol/geom/Polygon';
import polygonSplitter from 'polygon-splitter';
/**
* @template {OlGeomGeometry} T
* @param {OlFeature<T>|T} featureOrGeom
*/
function toGeom(featureOrGeom) {
if (featureOrGeom instanceof OlFeature) {
const geom = featureOrGeom.getGeometry();
if (geom === undefined) {
throw new Error('Feature has no geometry.');
}
return geom;
}
else {
return featureOrGeom;
}
}
/**
* Helper class for the geospatial analysis. Makes use of
* [Turf.js](http://turfjs.org/).
*
* @class GeometryUtil
*/
class GeometryUtil {
/**
* The prefix used to detect multi geometries.
* @ignore
*/
static MULTI_GEOM_PREFIX = 'Multi';
/**
* Splits an OlFeature with/or ol.geom.Polygon by an OlFeature with/or ol.geom.LineString
* into an array of instances of OlFeature with/or ol.geom.Polygon.
* If the target polygon (first param) is of type ol.Feature it will return an
* array with ol.Feature. If the target polygon (first param) is of type
* ol.geom.Geometry it will return an array with ol.geom.Geometry.
*
* @param {OlFeature<OlGeomPolygon> | OlGeomPolygon} polygon The polygon geometry to split.
* @param {OlFeature<OlGeomLineString> | OlGeomLineString} line The line geometry to split the polygon
* geometry with.
* @param {import("ol/proj").ProjectionLike} projection The EPSG code of the input features.
* Default is to EPSG:3857.
* @returns {OlFeature[] | OlGeomPolygon[]} An array of instances of OlFeature
* with/or ol.geom.Polygon
*/
static splitByLine(polygon, line, projection = 'EPSG:3857') {
const returnFeature = polygon instanceof OlFeature;
const geometries = GeometryUtil.splitGeometryByLine(toGeom(polygon), toGeom(line), projection);
if (returnFeature) {
return geometries.map(geom => new OlFeature(geom));
}
else {
return geometries;
}
}
/**
* Splits an ol.geom.Polygon by an ol.geom.LineString
* into an array of instances of ol.geom.Polygon.
*
* @param {OlGeomPolygon} polygon The polygon geometry to split.
* @param {OlGeomLineString} line The line geometry to split the polygon
* geometry with.
* @param {ProjectionLike} projection The EPSG code of the input features.
* Default is to EPSG:3857.
* @returns {OlGeomPolygon[]} An array of instances of ol.geom.Polygon
*/
static splitGeometryByLine(polygon, line, projection = 'EPSG:3857') {
const geoJsonFormat = new OlFormatGeoJSON({
dataProjection: 'EPSG:4326',
featureProjection: projection
});
const polyJson = geoJsonFormat.writeGeometryObject(polygon);
const lineJson = geoJsonFormat.writeGeometryObject(line);
const result = polygonSplitter(polyJson, lineJson);
const flattened = flatten(result);
return flattened.features.map((geojsonFeature) => {
return geoJsonFormat.readGeometry(geojsonFeature.geometry);
});
}
/**
* Adds a buffer to a given geometry.
*
* If the target is of type ol.Feature it will return an ol.Feature.
* If the target is of type ol.geom.Geometry it will return ol.geom.Geometry.
*
* @param {OlGeometry | OlFeature} geometryOrFeature The geometry.
* @param {number} radius The buffer to add in meters.
* @param {string} projection The projection of the input geometry as EPSG code.
* Default is to EPSG:3857.
*
* @returns {OlGeometry | OlFeature} The geometry or feature with the added buffer.
*/
static addBuffer(geometryOrFeature, radius = 0, projection = 'EPSG:3857') {
if (geometryOrFeature instanceof OlFeature) {
return new OlFeature(GeometryUtil.addGeometryBuffer(toGeom(geometryOrFeature), radius, projection));
}
else {
return GeometryUtil.addGeometryBuffer(geometryOrFeature, radius, projection);
}
}
/**
* Adds a buffer to a given geometry.
*
* @param {OlGeometry} geometry The geometry.
* @param {number} radius The buffer to add in meters.
* @param {string} projection The projection of the input geometry as EPSG code.
* Default is to EPSG:3857.
*
* @returns {OlGeometry} The geometry with the added buffer.
*/
static addGeometryBuffer(geometry, radius = 0, projection = 'EPSG:3857') {
if (radius === 0) {
return geometry;
}
const geoJsonFormat = new OlFormatGeoJSON({
dataProjection: 'EPSG:4326',
featureProjection: projection
});
const geoJson = geoJsonFormat.writeGeometryObject(geometry);
if (geoJson.type === 'GeometryCollection') {
return;
}
const buffered = buffer(geoJson, radius, {
units: 'meters'
});
return geoJsonFormat.readGeometry(buffered?.geometry);
}
/**
* Merges multiple geometries into one MultiGeometry.
*
* @param {(OlGeomMultiPoint|OlGeomPoint)[]|(OlGeomMultiPolygon|OlGeomPolygon)[]|
* (OlGeomMultiLineString|OlGeomLineString)[]} geometries An array of ol.geom.geometries;
* @returns {OlGeomMultiPoint|OlGeomMultiPolygon|OlGeomMultiLineString} A Multigeometry.
*/
static mergeGeometries(geometries) {
// split all multi-geometries to simple ones if passed geometries are
// multi-geometries
const separateGeometries = GeometryUtil.separateGeometries(geometries);
if (separateGeometries[0] instanceof OlGeomPolygon) {
const multiGeom = new OlGeomMultiPolygon([]);
for (const geom of separateGeometries) {
multiGeom.appendPolygon(geom);
}
return multiGeom;
}
else if (separateGeometries[0] instanceof OlGeomLineString) {
const multiGeom = new OlGeomMultiLineString([]);
for (const geom of separateGeometries) {
multiGeom.appendLineString(geom);
}
return multiGeom;
}
else {
const multiGeom = new OlGeomMultiPoint([]);
for (const geom of separateGeometries) {
multiGeom.appendPoint(geom);
}
return multiGeom;
}
}
/**
* Splits an array of geometries (and multi geometries) or a single MultiGeom
* into an array of single geometries.
*
* @param {} geometry An (array of) ol.geom.geometries;
* @returns {(OlGeomPoint|OlGeomLineString|OlGeomPolygon)[]} An array of geometries.
*/
static separateGeometries(geometry) {
if (Array.isArray(geometry)) {
return geometry.flatMap(geom => GeometryUtil.separateGeometries(geom));
}
if (geometry instanceof OlGeomMultiPolygon) {
return geometry.getPolygons();
}
if (geometry instanceof OlGeomMultiLineString) {
return geometry.getLineStrings();
}
if (geometry instanceof OlGeomMultiPoint) {
return geometry.getPoints();
}
return [geometry]; // Return simple geometry as array
}
/**
* Takes two or more polygons and returns a combined (Multi-)polygon.
*
* @param {OlFeature<OlGeomPolygon>[] | OlFeature<OlGeomPolygon | OlGeomMultiPolygon>>[]} inputPolygonalObjects An
* array of ol.Feature or ol.geom.Geometry instances of type (Multi)-Polygon.
* @param {ProjectionLike} projection The projection of the input polygons as EPSG code.
* Default is to EPSG:3857.
* @returns {OlGeomMultiPolygon|OlGeomPolygon|OlFeature<OlGeomMultiPolygon|OlGeomPolygon>} A Feature or Geometry with
* the combined area of the (Multi-)polygons.
*/
static union(inputPolygonalObjects, projection = 'EPSG:3857') {
const geometries = inputPolygonalObjects.map(toGeom);
const unionGeometry = GeometryUtil.unionGeometries(geometries, projection);
if (inputPolygonalObjects[0] instanceof OlFeature) {
return new OlFeature(unionGeometry);
}
else {
return unionGeometry;
}
}
/**
* Takes two or more polygons and returns a combined (Multi-)polygon.
*
* @param {OlGeomPolygon[]} polygons An array of ol.geom.Geometry instances of type (Multi-)polygon.
* @param {string} projection The projection of the input polygons as EPSG code.
* Default is to EPSG:3857.
* @returns {OlGeomMultiPolygon|OlGeomPolygon} A FGeometry with the combined area of the (Multi-)polygons.
*/
static unionGeometries(polygons, projection = 'EPSG:3857') {
const geoJsonFormat = new OlFormatGeoJSON({
dataProjection: 'EPSG:4326',
featureProjection: projection
});
const pp = polygons
.map((p) => {
if (p instanceof OlGeomMultiPolygon) {
return geoJsonFormat.writeFeatureObject(new OlFeature(p));
}
else {
return geoJsonFormat.writeFeatureObject(new OlFeature(p));
}
});
const unionGeometry = union(featureCollection(pp));
return geoJsonFormat.readFeature(unionGeometry).getGeometry();
}
/**
* Finds the difference between two polygons by clipping the second polygon from the first.
*
* If both polygons are of type ol.Feature it will return an ol.Feature.
* Else it will return an ol.geom.Geometry.
*
* @param {OlGeomPolygon|OlGeomMultiPolygon|OlFeature<OlGeomPolygon|OlGeomMultiPolygon>} polygon1
* @param {OlGeomPolygon|OlGeomMultiPolygon|OlFeature<OlGeomPolygon|OlGeomMultiPolygon>} polygon2
* @param {string} projection The projection of the input polygons as EPSG code.
* Default is to EPSG:3857.
*
* @returns {OlGeomPolygon|OlGeomMultiPolygon|OlFeature<OlGeomPolygon|OlGeomMultiPolygon>} A Feature or geometry
* with the area of polygon1 excluding the area of polygon2.
*/
static difference(polygon1, polygon2, projection = 'EPSG:3857') {
const differenceGeometry = GeometryUtil.geometryDifference(toGeom(polygon1), toGeom(polygon2), projection);
if (polygon1 instanceof OlFeature && polygon2 instanceof OlFeature) {
return new OlFeature(differenceGeometry);
}
else {
return differenceGeometry;
}
}
/**
* Finds the difference between two polygons by clipping the second polygon from the first.
*
* @param {OlGeomPolygon|OlGeomMultiPolygon} polygon1 An ol.geom.Geometry
* @param {OlGeomPolygon|OlGeomMultiPolygon} polygon2 An ol.geom.Geometry
* @param {string} projection The projection of the input polygons as EPSG code.
* Default is to EPSG:3857.
*
* @returns {OlGeomPolygon|OlGeomMultiPolygon} A with the area
* of polygon1 excluding the area of polygon2.
*/
static geometryDifference(polygon1, polygon2, projection = 'EPSG:3857') {
const geoJsonFormat = new OlFormatGeoJSON({
dataProjection: 'EPSG:4326',
featureProjection: projection
});
const geojson1 = geoJsonFormat.writeFeatureObject(new OlFeature(polygon1));
const geojson2 = geoJsonFormat.writeFeatureObject(new OlFeature(polygon2));
const coll = featureCollection([geojson1, geojson2]);
const intersection = difference(coll);
const feature = geoJsonFormat.readFeature(intersection);
return feature.getGeometry();
}
/**
* Takes two polygons and finds their intersection.
*
* If both polygons are of type ol.Feature it will return an ol.Feature.
* Else it will return an ol.geom.Geometry.
*
* @param {OlGeomPolygon|OlGeomMultiPolygon|OlFeature<OlGeomPolygon|OlGeomMultiPolygon>} polygon1
* @param {OlGeomPolygon|OlGeomMultiPolygon|OlFeature<OlGeomPolygon|OlGeomMultiPolygon>} polygon2
* @param {string} projection The projection of the input polygons as EPSG code.
* Default is to EPSG:3857.
*
* @returns {OlGeomPolygon|OlGeomMultiPolygon|OlFeature<OlGeomPolygon|OlGeomMultiPolygon>|null} A Feature or Geometry
* with the shared area of the two polygons or null if the polygons don't intersect.
*/
static intersection(polygon1, polygon2, projection = 'EPSG:3857') {
const intersectionGeometry = GeometryUtil.geometryIntersection(toGeom(polygon1), toGeom(polygon2), projection);
if (isNil(intersectionGeometry)) {
return undefined;
}
if (polygon1 instanceof OlFeature && polygon2 instanceof OlFeature) {
return new OlFeature(intersectionGeometry);
}
else {
return intersectionGeometry;
}
}
/**
* Takes two polygons and finds their intersection.
*
* @param {OlGeomPolygon|OlGeomMultiPolygon} polygon1 An ol.geom.Geometry
* @param {OlGeomPolygon|OlGeomMultiPolygon} polygon2 An ol.geom.Geometry
* @param {string} projection The projection of the input polygons as EPSG code.
* Default is to EPSG:3857.
*
* @returns {OlGeomPolygon|OlGeomMultiPolygon|null} A Geometry with the
* shared area of the two polygons or null if the polygons don't intersect.
*/
static geometryIntersection(polygon1, polygon2, projection = 'EPSG:3857') {
const geoJsonFormat = new OlFormatGeoJSON({
dataProjection: 'EPSG:4326',
featureProjection: projection
});
const geojson1 = polygon1 instanceof OlGeomMultiPolygon ?
geoJsonFormat.writeFeatureObject(new OlFeature(polygon1)) :
geoJsonFormat.writeFeatureObject(new OlFeature(polygon1));
const geojson2 = polygon2 instanceof OlGeomMultiPolygon ?
geoJsonFormat.writeFeatureObject(new OlFeature(polygon2)) :
geoJsonFormat.writeFeatureObject(new OlFeature(polygon2));
const intersection = intersect(featureCollection([geojson1, geojson2]));
if (!intersection) {
return undefined;
}
const feature = geoJsonFormat.readFeature(intersection);
return feature.getGeometry();
}
static getPolygonFromExtent(extent) {
if (isNil(extent) || extent?.length !== 4) {
return;
}
const [minX, minY, maxX, maxY] = extent;
return new OlGeomPolygon([
[
[minX, minY],
[minX, maxY],
[maxX, maxY],
[maxX, minY],
[minX, minY]
]
]);
}
}
export default GeometryUtil;
//# sourceMappingURL=GeometryUtil.js.map