UNPKG

gis-tools-ts

Version:

A collection of geospatial tools primarily designed for WGS84, Web Mercator, and S2.

100 lines 4.68 kB
import { clampWGS84Point, cleanLineString, dekinkPolygon, equalPoints, mergeBBoxes, polygonRingArea, } from '../../../index.js'; /** * Ensures the collection of polygon ring order is correct, removes duplicate points, * and runs a dekink to be thorough. * * NOTE: This will not remove/reduce points that follow a path angle like [[0, 0], [0, 1], [0, 2], ...]. * The decision to leave this to the user is due to the fact that not all projections are guaranteed * to support a linear relationship. Also sometimes the user want's to have these extra points for * future/cleaner projection changes. For example, having higher precision works well when * translating to spherical projections for instance. If you do want to remove these points, pass * in true to `removeCollinearPoints` * @param polygons - the collection of polygon as either a VectorFeature, VectorMultiPolygonGeometry, or raw VectorMultiPolygon * @param removeCollinearPoints - if true, remove superfluous points * @param cleanWGS84 - if true, clean WGS84 points to be in bounds * @returns - the cleaned polygon */ export function cleanPolygons(polygons, removeCollinearPoints = false, cleanWGS84 = false) { const vectorPolygons = 'geometry' in polygons ? polygons.geometry.coordinates : 'coordinates' in polygons ? polygons.coordinates : polygons; const res = { type: 'MultiPolygon', coordinates: [], is3D: false }; for (const vectorPoly in vectorPolygons) { const cleaned = cleanPolygon(vectorPolygons[vectorPoly], removeCollinearPoints, cleanWGS84); if (cleaned !== undefined) { if (cleaned.bbox !== undefined) res.bbox = mergeBBoxes(res.bbox, cleaned.bbox); res.coordinates.push(...cleaned.coordinates); } } return res; } /** * Ensures the polygon ring order is correct, removes duplicate points, and runs a dekink to be * thorough. * * NOTE: This will not remove/reduce points that follow a path angle like [[0, 0], [0, 1], [0, 2], ...]. * The decision to leave this to the user is due to the fact that not all projections are guaranteed * to support a linear relationship. Also sometimes the user want's to have these extra points for * future/cleaner projection changes. For example, having higher precision works well when * translating to spherical projections for instance. If you do want to remove these points, pass * in true to `removeCollinearPoints` * @param polygon - the polygon as either a VectorFeature, VectorPolygonGeometry, or raw VectorPolygon * @param removeCollinearPoints - if true, remove superfluous points * @param cleanWGS84 - if true, clean WGS84 points to be in bounds * @returns - the cleaned polygon */ export function cleanPolygon(polygon, removeCollinearPoints = false, cleanWGS84 = false) { const vectorPolygon = 'geometry' in polygon ? polygon.geometry.coordinates : 'coordinates' in polygon ? polygon.coordinates : polygon; // clone vectorPolygon so we can return a new object const cloned = vectorPolygon.map((ring) => ring.map((p) => { const dup = { ...p }; return cleanWGS84 ? clampWGS84Point(dup) : dup; })); // remove duplicates from the rings (and optionally remove superfluous/collinear points) // If outer ring is dropped, we kill the polygon const res = []; for (let i = 0; i < cloned.length; i++) { const ring = cloned[i]; let lastPoint; if (removeCollinearPoints) { const line = cleanLineString(ring, true); if (line === undefined) { if (i === 0) return; continue; } else res.push(line); } else { const newRing = []; for (const point of ring) { if (lastPoint === undefined || !equalPoints(point, lastPoint)) { newRing.push(point); lastPoint = point; } } if (newRing.length >= 4) res.push(newRing); else if (i === 0) return; } } // run polygonRingArea for each ring and invert if it's direction is wrong for the ring type for (let i = 0; i < res.length; i++) { const ring = res[i]; const area = polygonRingArea(ring, 1); // flip the ring if outer-ring and area is negative OR inner-ring and area is positive if (i === 0 ? area < 0 : area > 0) res[i] = ring.reverse(); } return dekinkPolygon(res); } //# sourceMappingURL=clean.js.map