UNPKG

@seasketch/geoprocessing

Version:

Geoprocessing and reporting framework for SeaSketch 2.0

80 lines (67 loc) 3.22 kB
import fs from "fs-extra"; import { area, bbox, featureCollection as fc } from "@turf/turf"; import { $ } from "zx"; import { getDatasourceFeatures } from "../../../src/dataproviders/index.js"; import { chunk, roundDecimal } from "../../../src/helpers/index.js"; import project from "./ProjectClientGlobal.js"; import { clip } from "../../../src/toolbox/clip.js"; const outfile = "./mr-eez-land-union-precalc.json"; const infile = "/mnt/c/data/EEZ_land_union_v3_202003/EEZ_Land_v3_202030.shp"; // THIS SCRIPT IS NOT VIABLE AS-IS // Problem - turf falling over on large eez and/or land features, even when chunking // Suggest solutions // Option 1 - In QGIS, subtract whole OSM land from EEZ // Option 2 - crosswalk eez to osm land, fetch land features, filter to one country, calc with each land feature, then area, sum the result // start fresh await $`rm -f ${outfile}`; // calculate equal area 6933 using sqlite, and strip unneeded properties //const query = `SELECT "UNION", GEOMETRY, round(ST_Area(ST_Transform(GEOMETRY, 6933)), 0) as area_6933 FROM EEZ_Land_v3_202030 ORDER BY "UNION"`; // Convert shapefile to geojson and pare down attributes const query = `SELECT "UNION", GEOMETRY FROM EEZ_Land_v3_202030 ORDER BY "UNION"`; await $`ogr2ogr -f GeoJSON -dialect sqlite -sql ${query} ${outfile} ${infile}`; // Calculate turf area (after subtracting osm land) and bbox, strip geometry to save space const eezFeatures = fs.readJSONSync(outfile); // calculate turf area = eez - osm land const landDs = project.getExternalVectorDatasourceById( "global-clipping-osm-land", ); const landUrl = project.getDatasourceUrl(landDs); for (const eezFeat of eezFeatures.features) { // Get land features that overlap with eez const eezBbox = bbox(eezFeat); const landFeatures = await getDatasourceFeatures(landDs, landUrl, { unionProperty: "gid", // gid is assigned per country bbox: eezBbox, }); const eezNoLandArea = area(eezFeat); let remEezArea = 0; console.log(eezFeat.properties.UNION); console.log("eezNoLandArea:", eezNoLandArea); console.log("numLandFeatures:", landFeatures.length); const featToChunkSize = (numFeatures) => { if (numFeatures > 8000) return 100; else if (numFeatures > 6000) return 500; else if (numFeatures > 4000) return 4000; else return numFeatures; }; const chunkSize = featToChunkSize(landFeatures.length); const chunks = chunk(landFeatures, chunkSize); console.log(`${chunks.length} chunks, ${chunkSize} features each`); // Start with whole eezFeat and subtract one chunk of land features at a time to not blow up clip let remainder = eezFeat; for (const [idx, curChunk] of chunks.entries()) { console.log(`chunk ${idx + 1} of ${chunks.length}`); remainder = clip(fc([remainder, ...curChunk]), "difference"); } remEezArea = remainder ? area(remainder) : remEezArea; console.log("remEezArea:", eezNoLandArea); console.log( `${roundDecimal((remEezArea / eezNoLandArea) * 100, 1)}% decrease`, ); console.log(" "); console.log(" "); eezFeat.area_turf = remEezArea; eezFeat.bbox = bbox(eezFeat); eezFeat.geometry = null; // remove geometry to save space fs.writeJsonSync(outfile, eezFeatures); }