import Feature from 'ol/Feature'
import Point from 'ol/geom/Point'
import Circle from 'ol/geom/Circle'
import GeometryCollection from 'ol/geom/GeometryCollection'
import MultiPoint from 'ol/geom/MultiPoint'
import Polygon from 'ol/geom/Polygon'
import MultiPolygon from 'ol/geom/MultiPolygon'
import LineString from 'ol/geom/LineString'
import MultiLineString from 'ol/geom/MultiLineString'
/**
* Permet de récupérer le centroid d'une feature
* Les geometries prisent en compte sont Point, Polygon, LineString
*
* @param {ol.Feature | ol.geom.SimpleGeometry} featureOrGeom Feature ou Geometry
* @return {Array} Centroid ou false;
*/
export function getCentroid (featureOrGeom) {
let polygons, isPair, lineIndex
const geom = featureOrGeom.constructor === Feature ? featureOrGeom.getGeometry() : featureOrGeom
switch (geom.constructor) {
case Point:
return geom.getCoordinates()
case Circle:
return geom.getCenter()
case GeometryCollection:
case MultiPoint: {
const [minx, miny, maxx, maxy] = geom.getExtent()
const x = minx + ((maxx - minx) / 2)
const y = miny + ((maxy - miny) / 2)
return [x, y]
}
case Polygon:
return geom.getInteriorPoint().getCoordinates()
case MultiPolygon:
// Tri décroissant par superficie (pour utiliser le centroid du max)
polygons = geom.getPolygons().sort((a, b) => b.getArea() - a.getArea())
return polygons[0].getInteriorPoint().getCoordinates()
case LineString:
return geom.getCoordinateAt(0.5)
case MultiLineString:
// re-changement d'algo:
// si nombre de string impair on prend la moitié de la string du milieu
// si pair la coordoonné du croisement de celles du milieu
isPair = geom.getLineStrings().length % 2 === 0
lineIndex = Math.floor(geom.getLineStrings().length / 2)
return isPair ? geom.getLineString(lineIndex).getLastCoordinate() : geom.getLineString(lineIndex).getCoordinateAt(0.5)
// changement d'algo, prend une coordonnées au milieu des coordonées a plat
default:
return null
}
}
/**
* Permet de retourner uniquement un point pour une géométrie
* Si ce n'est pas possible, on ne retourne rien .
*
* @param {ol.geom.Geometry} geometry Géométrie à traiter
* @param {'centroid'| 'start' | 'end'} [position='centroid'] Position du point a retourner
* @returns {ol.geom.Point | null} Point ou null
*/
export function getPointForGeometry (geometry, position = 'centroid') {
if (!geometry) {
return null
}
const usableGeometry = geometry.getType() === 'GeometryCollection'
? geometry.getGeometriesArray()?.[0]
: geometry
// collection vide...
if (!usableGeometry) {
return null
}
// pour point ou on perd en performance a recréer une geom de type point a partir des coordonnées extraites de lui-même
if (usableGeometry.getType() === 'Point') {
return usableGeometry
}
switch (position) {
case 'start': {
const coord = usableGeometry.getFirstCoordinate()
return coord !== null ? new Point(coord) : null
}
case 'end': {
const coord = usableGeometry.getLastCoordinate()
return coord !== null ? new Point(coord) : null
}
default: {
const coord = getCentroid(usableGeometry)
return coord !== null ? new Point(coord) : null
}
}
}
export function getPointsforGeometries (geometryOrGeometryCollection, position = 'centroid') {
const geometries = geometryOrGeometryCollection.getType() === 'GeometryCollection'
? geometryOrGeometryCollection.getGeometriesArray()
: geometryOrGeometryCollection.getType() === 'MultiLineString'
? geometryOrGeometryCollection.getLineStrings()
: geometryOrGeometryCollection.getType() === 'MultiPolygon'
? geometryOrGeometryCollection.getPolygons()
: geometryOrGeometryCollection.getType() === 'MultiPoint'
? geometryOrGeometryCollection.getPoints()
: [geometryOrGeometryCollection]
const coordinates = geometries.reduce((acc, geometry) => {
if (['MultiLineString', 'MultiPolygon', 'MultiPoint'].includes(geometry.getType())) {
// pour les multi on récupère les points de chaque géométrie
const points = getPointsforGeometries(geometry, position)
return acc.concat(points.getCoordinates())
}
const point = getPointForGeometry(geometry, position)
acc.push(point.getCoordinates())
return acc
}, [])
return new MultiPoint(coordinates)
}