@seasketch/geoprocessing
Version:
Geoprocessing and reporting framework for SeaSketch 2.0
92 lines (83 loc) • 2.81 kB
text/typescript
import {
Sketch,
SketchCollection,
Polygon,
MultiPolygon,
GeoprocessingHandler,
getFirstFromParam,
DefaultExtraParams,
rasterMetrics,
isRasterDatasource,
loadCog,
} 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";
/**
* rasterFunction: A geoprocessing function that calculates overlap metrics for raster datasources
* @param sketch - A sketch or collection of sketches
* @param extraParams
* @returns Calculated metrics and a null sketch
*/
export async function rasterFunction(
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);
// Calculate overlap metrics for each class in metric group
const metricGroup = project.getMetricGroup("rasterFunction");
const metrics: Metric[] = (
await Promise.all(
metricGroup.classes.map(async (curClass) => {
const ds = project.getMetricGroupDatasource(metricGroup, {
classId: curClass.classId,
});
if (!isRasterDatasource(ds))
throw new Error(`Expected raster datasource for ${ds.datasourceId}`);
const url = project.getDatasourceUrl(ds);
// Load raster metadata
const raster = await loadCog(url);
// Run raster analysis
const overlapResult = await rasterMetrics(raster, {
metricId: metricGroup.metricId,
feature: clippedSketch,
...(ds.measurementType === "quantitative" && { stats: ["sum"] }),
...(ds.measurementType === "categorical" && {
categorical: true,
categoryMetricValues: [curClass.classId],
}),
});
return overlapResult.map(
(metrics): Metric => ({
...metrics,
classId: curClass.classId,
geographyId: curGeography.geographyId,
}),
);
}),
)
).flat();
return {
metrics: sortMetrics(rekeyMetrics(metrics)),
};
}
export default new GeoprocessingHandler(rasterFunction, {
title: "rasterFunction",
description: "Function description",
timeout: 500, // seconds
memory: 1024, // megabytes
executionMode: "async",
});