UNPKG

@turf/boolean-contains

Version:

Determines whether the second geometry is completely within the first geometry.

245 lines 7.32 kB
// index.ts import { bbox as calcBbox } from "@turf/bbox"; import { booleanPointInPolygon } from "@turf/boolean-point-in-polygon"; import { booleanPointOnLine as isPointOnLine } from "@turf/boolean-point-on-line"; import { getGeom } from "@turf/invariant"; import { feature, featureCollection, lineString } from "@turf/helpers"; import { lineSplit } from "@turf/line-split"; function booleanContains(feature1, feature2) { const geom1 = getGeom(feature1); const geom2 = getGeom(feature2); const type1 = geom1.type; const type2 = geom2.type; const coords1 = geom1.coordinates; const coords2 = geom2.coordinates; switch (type1) { case "Point": switch (type2) { case "Point": return compareCoords(coords1, coords2); default: throw new Error("feature2 " + type2 + " geometry not supported"); } case "MultiPoint": switch (type2) { case "Point": return isPointInMultiPoint(geom1, geom2); case "MultiPoint": return isMultiPointInMultiPoint(geom1, geom2); default: throw new Error("feature2 " + type2 + " geometry not supported"); } case "LineString": switch (type2) { case "Point": return isPointOnLine(geom2, geom1, { ignoreEndVertices: true }); case "LineString": return isLineOnLine(geom1, geom2); case "MultiPoint": return isMultiPointOnLine(geom1, geom2); default: throw new Error("feature2 " + type2 + " geometry not supported"); } case "Polygon": switch (type2) { case "Point": return booleanPointInPolygon(geom2, geom1, { ignoreBoundary: true }); case "LineString": return isLineInPoly(geom1, geom2); case "Polygon": return isPolyInPoly(geom1, geom2); case "MultiPoint": return isMultiPointInPoly(geom1, geom2); case "MultiPolygon": return isMultiPolyInPoly(geom1, geom2); default: throw new Error("feature2 " + type2 + " geometry not supported"); } case "MultiPolygon": switch (type2) { case "Polygon": return isPolygonInMultiPolygon(geom1, geom2); default: throw new Error("feature2 " + type2 + " geometry not supported"); } default: throw new Error("feature1 " + type1 + " geometry not supported"); } } function isPolygonInMultiPolygon(multiPolygon, polygon) { return multiPolygon.coordinates.some( (coords) => isPolyInPoly({ type: "Polygon", coordinates: coords }, polygon) ); } function isMultiPolyInPoly(polygon, multiPolygon) { return multiPolygon.coordinates.every( (coords) => isPolyInPoly(polygon, { type: "Polygon", coordinates: coords }) ); } function isPointInMultiPoint(multiPoint, pt) { let i; let output = false; for (i = 0; i < multiPoint.coordinates.length; i++) { if (compareCoords(multiPoint.coordinates[i], pt.coordinates)) { output = true; break; } } return output; } function isMultiPointInMultiPoint(multiPoint1, multiPoint2) { for (const coord2 of multiPoint2.coordinates) { let matchFound = false; for (const coord1 of multiPoint1.coordinates) { if (compareCoords(coord2, coord1)) { matchFound = true; break; } } if (!matchFound) { return false; } } return true; } function isMultiPointOnLine(lineString2, multiPoint) { let haveFoundInteriorPoint = false; for (const coord of multiPoint.coordinates) { if (isPointOnLine(coord, lineString2, { ignoreEndVertices: true })) { haveFoundInteriorPoint = true; } if (!isPointOnLine(coord, lineString2)) { return false; } } if (haveFoundInteriorPoint) { return true; } return false; } function isMultiPointInPoly(polygon, multiPoint) { for (const coord of multiPoint.coordinates) { if (!booleanPointInPolygon(coord, polygon, { ignoreBoundary: true })) { return false; } } return true; } function isLineOnLine(lineString1, lineString2) { let haveFoundInteriorPoint = false; for (const coords of lineString2.coordinates) { if (isPointOnLine({ type: "Point", coordinates: coords }, lineString1, { ignoreEndVertices: true })) { haveFoundInteriorPoint = true; } if (!isPointOnLine({ type: "Point", coordinates: coords }, lineString1, { ignoreEndVertices: false })) { return false; } } return haveFoundInteriorPoint; } function splitLineIntoSegmentsOnPolygon(linestring, polygon) { const coords = linestring.coordinates; const outputSegments = []; for (let i = 0; i < coords.length - 1; i++) { const seg = lineString([coords[i], coords[i + 1]]); const split = lineSplit(seg, feature(polygon)); if (split.features.length === 0) { outputSegments.push(seg); } else { outputSegments.push(...split.features); } } return featureCollection(outputSegments); } function isLineInPoly(polygon, linestring) { const polyBbox = calcBbox(polygon); const lineBbox = calcBbox(linestring); if (!doBBoxOverlap(polyBbox, lineBbox)) { return false; } for (const coord of linestring.coordinates) { if (!booleanPointInPolygon(coord, polygon)) { return false; } } let isContainedByPolygonBoundary = false; const lineSegments = splitLineIntoSegmentsOnPolygon(linestring, polygon); for (const lineSegment of lineSegments.features) { const midpoint = getMidpoint( lineSegment.geometry.coordinates[0], lineSegment.geometry.coordinates[1] ); if (!booleanPointInPolygon(midpoint, polygon)) { return false; } if (!isContainedByPolygonBoundary && booleanPointInPolygon(midpoint, polygon, { ignoreBoundary: true })) { isContainedByPolygonBoundary = true; } } return isContainedByPolygonBoundary; } function isPolyInPoly(feature1, feature2) { if (feature1.type === "Feature" && feature1.geometry === null) { return false; } if (feature2.type === "Feature" && feature2.geometry === null) { return false; } const poly1Bbox = calcBbox(feature1); const poly2Bbox = calcBbox(feature2); if (!doBBoxOverlap(poly1Bbox, poly2Bbox)) { return false; } const coords = getGeom(feature2).coordinates; for (const ring of coords) { for (const coord of ring) { if (!booleanPointInPolygon(coord, feature1)) { return false; } } } return true; } function doBBoxOverlap(bbox1, bbox2) { if (bbox1[0] > bbox2[0]) { return false; } if (bbox1[2] < bbox2[2]) { return false; } if (bbox1[1] > bbox2[1]) { return false; } if (bbox1[3] < bbox2[3]) { return false; } return true; } function compareCoords(pair1, pair2) { return pair1[0] === pair2[0] && pair1[1] === pair2[1]; } function getMidpoint(pair1, pair2) { return [(pair1[0] + pair2[0]) / 2, (pair1[1] + pair2[1]) / 2]; } var index_default = booleanContains; export { booleanContains, compareCoords, index_default as default, doBBoxOverlap, getMidpoint, isLineInPoly, isLineOnLine, isMultiPointInMultiPoint, isMultiPointInPoly, isMultiPointOnLine, isMultiPolyInPoly, isPointInMultiPoint, isPolyInPoly, isPolygonInMultiPolygon }; //# sourceMappingURL=index.js.map