UNPKG

@seasketch/geoprocessing

Version:

Geoprocessing and reporting framework for SeaSketch 2.0

115 lines (104 loc) 3.53 kB
import { Sketch, SketchCollection, Polygon, MultiPolygon, GeoprocessingHandler, getFirstFromParam, DefaultExtraParams, Feature, isVectorDatasource, overlapFeatures, getFeaturesForSketchBBoxes, } from "@seasketch/geoprocessing"; import project from "../../project/projectClient.js"; import { Metric, ReportResult, rekeyMetrics, sortMetrics, } from "@seasketch/geoprocessing/client-core"; import { clipToGeography } from "../util/clipToGeography.js"; /** * vectorFunction: A geoprocessing function that calculates overlap metrics for vector datasources * @param sketch - A sketch or collection of sketches * @param extraParams * @returns Calculated metrics and a null sketch */ export async function vectorFunction( sketch: | Sketch<Polygon | MultiPolygon> | SketchCollection<Polygon | MultiPolygon>, extraParams: DefaultExtraParams = {}, ): Promise<ReportResult> { // Check for client-provided geography, fallback to first geography assigned as default-boundary in metrics.json const geographyId = getFirstFromParam("geographyIds", extraParams); const curGeography = project.getGeographyById(geographyId, { fallbackGroup: "default-boundary", }); // Clip portion of sketch outside geography features const clippedSketch = await clipToGeography(sketch, curGeography); const featuresByDatasource: Record< string, Feature<Polygon | MultiPolygon>[] > = {}; // Calculate overlap metrics for each class in metric group const metricGroup = project.getMetricGroup("vectorFunction"); const metrics = ( await Promise.all( metricGroup.classes.map(async (curClass) => { const ds = project.getMetricGroupDatasource(metricGroup, { classId: curClass.classId, }); if (!isVectorDatasource(ds)) throw new Error(`Expected vector datasource for ${ds.datasourceId}`); const url = project.getDatasourceUrl(ds); // Fetch features overlapping with sketch, if not already fetched const features = featuresByDatasource[ds.datasourceId] || (await getFeaturesForSketchBBoxes(sketch, url)); featuresByDatasource[ds.datasourceId] = features; // Get classKey for current data class const classKey = project.getMetricGroupClassKey(metricGroup, { classId: curClass.classId, }); let finalFeatures: Feature<Polygon | MultiPolygon>[] = []; if (classKey === undefined) // Use all features finalFeatures = features; else { // Filter to features that are a member of this class finalFeatures = features.filter( (feat) => feat.geometry && feat.properties && feat.properties[classKey] === curClass.classId, ); } // Calculate overlap metrics const overlapResult = await overlapFeatures( metricGroup.metricId, finalFeatures, clippedSketch, ); return overlapResult.map( (metric): Metric => ({ ...metric, classId: curClass.classId, geographyId: curGeography.geographyId, }), ); }), ) ).flat(); return { metrics: sortMetrics(rekeyMetrics(metrics)), }; } export default new GeoprocessingHandler(vectorFunction, { title: "vectorFunction", description: "Function description", timeout: 500, // seconds memory: 1024, // megabytes executionMode: "async", });