UNPKG

@seasketch/geoprocessing

Version:

Geoprocessing and reporting framework for SeaSketch 2.0

99 lines 4.8 kB
import { toSketchArray, isSketchCollection, roundDecimal, } from "../helpers/index.js"; import { clip } from "./clip.js"; import { createMetric } from "../metrics/index.js"; import { featureCollection, truncate as truncateGeom } from "@turf/turf"; /** * Calculates area overlap between sketch(es) and an array of polygon features. * Truncates input geometry coordinates down to 6 decimal places (~1m accuracy) before intersection to avoid floating point precision issues. * If sketch collection, then calculates area per sketch and for sketch collection * @param metricId unique metric identifier to assign to each metric * @param features to intersect and get overlap metrics * @param sketch the sketches. If empty will return 0 result. * @param options.truncate truncate results to 6 digits after decimal point, defaults to true * @param options.includeChildMetrics if false and sketch is collection, child sketch metrics will not be included in results, defaults to true * @param options.sumProperty Property in features with value to sum, if not defined each feature will count as 1 * @returns array of Metric objects */ export async function overlapPolygonSum(metricId, features, sketch, options = {}) { const { includeChildMetrics = true, truncate = true, sumProperty } = options; // Collect indices of features that intersect with sketch(es) for later calculation of collection level sum const featureIndices = new Set(); const truncatedSketches = (Array.isArray(sketch) ? sketch : toSketchArray(sketch)).map((s) => truncateGeom(s)); const truncatedFeatures = features.map((f) => truncateGeom(f)); // Individual sketch metrics const sketchMetrics = truncatedSketches.map((curSketch) => { const intersections = intersectSum(curSketch, truncatedFeatures, sumProperty); // Accumulate feature indices that intersect with collection for (const index of intersections.indices) featureIndices.add(index); return createMetric({ metricId, sketchId: curSketch.properties.id, value: truncate ? roundDecimal(intersections.sum, 6, { keepSmallValues: true }) : intersections.sum, extra: { sketchName: curSketch.properties.name, }, }); }); const metrics = includeChildMetrics ? sketchMetrics : []; // Collection level metrics if (isSketchCollection(sketch)) { let collValue = 0; // Iterate through feature indices and accumulate collection level sum value for (const index of featureIndices) { const feature = features[index]; if (sumProperty && feature.properties && feature.properties[sumProperty]) { collValue += feature.properties[sumProperty]; } else { collValue += 1; } } metrics.push(createMetric({ metricId, sketchId: sketch.properties.id, value: truncate ? roundDecimal(collValue, 6, { keepSmallValues: true }) : collValue, extra: { sketchName: sketch.properties.name, isCollection: true, }, })); } return metrics; } /** * Returns an object containing the sum value of features in B that intersect with featureA, * and the indices of the features in B that intersect with featureA * No support for partial overlap, counts the whole feature if it intersects. * @param featureA single feature to intersect with featuresB * @param featuresB array of features * @param sumProperty Property in featuresB with value to sum, if not defined each feature will count as 1 * @returns Sum of features/feature property which overlap with the sketch, and a list of * indices for features that overlap with the sketch to be used in calculating total sum of * the sketch collection */ export const intersectSum = (featureA, featuresB, sumProperty) => { const indices = []; // intersect and get sum of remainder const sketchValue = featuresB .map((curFeature, index) => { // Optimization: can this be done with turf.booleanIntersects? const rem = clip(featureCollection([featureA, curFeature]), "intersection"); if (!rem) return 0; indices.push(index); let featureValue = 1; if (sumProperty && curFeature.properties[sumProperty] >= 0) featureValue = curFeature.properties[sumProperty]; return featureValue; }) .reduce((valueSoFar, curValue) => valueSoFar + curValue, 0); return { sum: sketchValue, indices: indices }; }; //# sourceMappingURL=overlapPolygonSum.js.map