Source: tools/services/intersects.js

import Geometry from 'ol/geom/Geometry'

import {
  point as turfPoint,
  lineString as turfLineString,
  polygon as turfPolygon,
  multiPoint as turfMultiPoint,
  multiLineString as turfMultiLineString,
  multiPolygon as turfMultiPolygon,
  geometryCollection as turfGeometryCollection,
} from '@turf/helpers'
import turfBooleanCrosses from '@turf/boolean-crosses'
import turfBooleanContains from '@turf/boolean-contains'
import turfIntersect from '@turf/intersect'

function getGeometryType (geometry) {
  return geometry instanceof Geometry
    ? geometry.getType()
    : geometry.type || 'Polygon'
}

function getGeometryCoordinates (geometry) {
  return geometry instanceof Geometry
    ? geometry.getCoordinates()
    : geometry.coordinates || geometry
}

const TURF_CONSTRUCTORS = {
  Point: turfPoint,
  LineString: turfLineString,
  Polygon: turfPolygon,
  MultiPoint: turfMultiPoint,
  MultiLineString: turfMultiLineString,
  MultiPolygon: turfMultiPolygon,
  GeometryCollection: turfGeometryCollection,
}

function toTurfGeometry (geometry) {
  const geometryType = getGeometryType(geometry)
  const coordinates = getGeometryCoordinates(geometry)
  const turfConstructor = TURF_CONSTRUCTORS[geometryType]

  return turfConstructor(coordinates)
}

function getGeometries (geometry) {
  const type = getGeometryType(geometry)
  const isOlGeom = geometry instanceof Geometry
  switch (type) {
    case 'GeometryCollection':
      return isOlGeom ? geometry.getGeometries() : geometry.geometries
    case 'MultiPolygon':
      return isOlGeom ? geometry.getPolygons() : geometry.coordinates
    case 'MultiLineString':
      return isOlGeom ? geometry.getLineStrings() : geometry.coordinates
    default:
      throw new Error(type + ' geometry not supported')
  }
}

/**
 * Permet de savoir si une géométrie est partiellement
 * ou totalement inclue dans une autre
 *
 * @param {Geometry} container Géométrie contenante
 * @param {Geometry} geometry Géométrie contenue
 * @param {Object} options Options
 * @param {boolean} options.fullyInside Doit être intégralement dans le conteneur
 */
export function intersectsGeometry (container, geometry, { fullyInside } = {}) {
  const geometryType = getGeometryType(geometry)

  // Cas des groupements de géométries
  if (['GeometryCollection', 'MultiPolygon', 'MultiLineString'].includes(geometryType)) {
    const geometries = getGeometries(geometry)

    const recursiveCall = item => intersectsGeometry(container, item, { fullyInside })
    return fullyInside
      ? geometries.every(recursiveCall)
      : geometries.some(recursiveCall)
  }

  if (geometryType === 'Point') {
    return container.intersectsCoordinate(getGeometryCoordinates(geometry))
  }

  const turfContainer = toTurfGeometry(container)
  const turfGeometry = toTurfGeometry(geometry)
  const contained = turfBooleanContains(turfContainer, turfGeometry)

  // Si la géométrie doit-être ou est totalement dedans
  if (fullyInside || contained) {
    return contained
  }

  // Cas particulier de croisement de polygon (non compatible turfBooleanCrosses)
  if (geometryType === 'Polygon') {
    return !!turfIntersect(turfContainer, turfGeometry)
  }

  // Cas d'un croisement de géométries simple
  return turfBooleanCrosses(turfContainer, turfGeometry)
}