Skip to content

Commit

Permalink
improved support for multipolygons and polygons with holes
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielJDufour committed Jun 22, 2023
1 parent 3ff5cc4 commit 626041e
Show file tree
Hide file tree
Showing 21 changed files with 373 additions and 746 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,4 @@ pnpm-lock.yaml
out
data/geotiff-test-data/*.cog
data/geotiff-test-data/*.tif*
Pipfile*
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"format": "npx prettier --arrow-parens=avoid --print-width=160 --trailing-comma=none --write src/*.js src/*/*.js",
"lint": "eslint lite && eslint src",
"serve": "npx srvd --debug --port=3000 --wait=120",
"test": "for f in src/*/*test*.js; do echo \"\nrunning $f\" && node -r esm $f; done",
"test": "set -e; for f in src/*/*test*.js; do echo \"\nrunning $f\" && sleep 5 && node -r esm $f; done",
"test-loading-builds": "node test-loading-builds.js",
"setup": "bash setup.sh"
},
Expand Down Expand Up @@ -58,23 +58,24 @@
"dependencies": {
"@turf/boolean-clockwise": "^6.5.0",
"@turf/combine": "^6.5.0",
"bbox-fns": "^0.11.0",
"bbox-fns": "^0.13.0",
"calc-stats": "^2.1.0",
"cross-fetch": "^3.1.6",
"dufour-peyton-intersection": "^0.1.3",
"dufour-peyton-intersection": "0.2.0-0",
"fast-max": "^0.4.0",
"fast-min": "^0.3.0",
"faster-median": "^1.0.0",
"georaster": "^1.5.6",
"get-depth": "^0.0.3",
"mathjs": "^11.8.0",
"mpoly": "^0.2.0",
"preciso": "^0.12.0",
"proj4": "^2.9.0",
"proj4-fully-loaded": "^0.2.0",
"quick-resolve": "^0.0.1",
"reproject-bbox": "^0.12.0",
"reproject-geojson": "^0.3.0",
"snap-bbox": "^0.3.0",
"snap-bbox": "^0.4.1",
"terraformer-arcgis-parser": "^1.1.0",
"underscore": "^1.13.6",
"xdim": "^1.10.1"
Expand Down
113 changes: 45 additions & 68 deletions src/convert-geometry/convert-geometry.module.js
Original file line number Diff line number Diff line change
@@ -1,52 +1,47 @@
import calc from "bbox-fns/calc.js";
import mpoly from "mpoly";
import validate from "bbox-fns/validate.js";
import utils from "../utils";

const convertPoint = geometry => {
export function convertPoint(geom) {
if (typeof geom === "string") geom = JSON.parse(geom);

let point;
if (Array.isArray(geometry) && geometry.length === 2) {
// array
point = geometry;
} else if (typeof geometry === "string") {
// stringified geojson
const geojson = JSON.parse(geometry);
if (geojson.type === "Point") {
point = geojson.coordinates;
}
} else if (typeof geometry === "object") {
// geojson
if (geometry.type === "Point") {
point = geometry.coordinates;
if (Array.isArray(geom) && geom.length === 2 && typeof geom[0] === "number" && typeof geom[1] === "number") {
// [x, y] point
point = geom;
} else if (typeof geom === "object") {
if (/Point/i.test(geom.type)) {
point = geom.coordinates;
}
}

if (!point) {
throw `Invalid point object was used.
Please use either a [lng, lat] array or GeoJSON point.`;
throw `Invalid point object was used. Please use either a [lng, lat] array or GeoJSON point.`;

Check failure on line 20 in src/convert-geometry/convert-geometry.module.js

View workflow job for this annotation

GitHub Actions / run all tests

Strings must use doublequote
}

return point;
};
}

/**
*
* @param {convertBbox} geom
* @returns {Object} bbox in form { xmin, ymin, xmax, ymax }
*/
export function convertBbox(geom) {
if (typeof geom === "string") geom = JSON.parse(geom);

const convertBbox = geometry => {
let bbox;
if (utils.isBbox(geometry)) {
if (typeof geometry.xmin !== "undefined" && typeof geometry.ymax !== "undefined") {
bbox = geometry;
} else if (Array.isArray(geometry) && geometry.length === 4) {
// array
bbox = { xmin: geometry[0], ymin: geometry[1], xmax: geometry[2], ymax: geometry[3] };
} else if (typeof geometry === "string") {
// stringified geojson
const geojson = JSON.parse(geometry);
const coors = utils.getGeojsonCoors(geojson)[0];
const lngs = coors.map(coor => coor[0]);
const lats = coors.map(coor => coor[1]);
bbox = { xmin: Math.min(...lngs), ymin: Math.min(...lats), xmax: Math.max(...lngs), ymax: Math.max(...lats) };
} else if (typeof geometry === "object") {
// geojson
const coors = utils.getGeojsonCoors(geometry)[0];
const lngs = coors.map(coor => coor[0]);
const lats = coors.map(coor => coor[1]);
bbox = { xmin: Math.min(...lngs), ymin: Math.min(...lats), xmax: Math.max(...lngs), ymax: Math.max(...lats) };

if (utils.isBbox(geom)) {
if (typeof geom.xmin !== "undefined" && typeof geom.ymax !== "undefined") {
bbox = geom;
} else if (validate(geom)) {
const [xmin, ymin, xmax, ymax] = geom;
bbox = { xmin, ymin, xmax, ymax };
} else if (typeof geom === "object") {
const [xmin, ymin, xmax, ymax] = calc(geom);
bbox = { xmin, ymin, xmax, ymax };
}
}

Expand All @@ -56,49 +51,31 @@ const convertBbox = geometry => {
}

return bbox;
};
}

const convertPolygon = geometry => {
let polygon;
if (utils.isPolygon(geometry)) {
if (Array.isArray(geometry)) {
// array
polygon = geometry;
} else if (typeof geometry === "string") {
// stringified geojson
const parsed = JSON.parse(geometry);
const geojson = utils.convertToGeojsonIfNecessary(parsed);
polygon = utils.getGeojsonCoors(geojson);
} else if (typeof geometry === "object") {
// geojson
const geojson = utils.convertToGeojsonIfNecessary(geometry);
polygon = utils.getGeojsonCoors(geojson);
}
}
export function convertMultiPolygon(geom) {
const ERROR_MESSAGE = `Invalild polygonal object was used. Please use a GeoJSON polygon.`;

Check failure on line 57 in src/convert-geometry/convert-geometry.module.js

View workflow job for this annotation

GitHub Actions / run all tests

Strings must use doublequote

if (!polygon) {
throw `Invalild polygon object was used.
Please use either a [[[x00,y00],...,[x0n,y0n],[x00,y00]]...] array or GeoJSON polygon.`;
}
const polys = mpoly.get(geom);

return polygon;
};
if (polys.length === 0) throw new Error(ERROR_MESSAGE);

const convertGeometry = (typeOfGeometry, geometry) => {
return polys;
}

export default function convertGeometry(typeOfGeometry, geometry) {
try {
if (typeOfGeometry === "point") {
return convertPoint(geometry);
} else if (typeOfGeometry === "bbox") {
return convertBbox(geometry);
} else if (typeOfGeometry === "polygon") {
return convertPolygon(geometry);
} else if (typeOfGeometry === "multi-polygon") {
return convertMultiPolygon(geometry);
} else {
throw 'Invalid geometry type was specified. Please use either "point" or "polygon"';
throw 'Invalid geometry type was specified. Please use either "bbox", "multi-polygon", or "point".';
}
} catch (e) {
console.error(e);
throw e;
}
};

export default convertGeometry;
}
6 changes: 3 additions & 3 deletions src/convert-geometry/convert-geometry.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ const testBboxLoad = (feature, eq) => {
};

const testPolygonLoad = (feature, eq) => {
const poly = convertGeometry("polygon", feature);
const depth = getDepth(poly);
eq(depth, 3);
const multipoly = convertGeometry("multi-polygon", feature);
const depth = getDepth(multipoly);
eq(depth, 4);
};

test("Load Point from array", ({ eq }) => {
Expand Down
7 changes: 4 additions & 3 deletions src/convert-geometry/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import convertGeometry from "./convert-geometry.module";

export default convertGeometry;
export { default as convertGeometry } from "./convert-geometry.module";
export { convertBbox } from "./convert-geometry.module";
export { convertMultiPolygon } from "./convert-geometry.module";
export { convertPoint } from "./convert-geometry.module";
7 changes: 5 additions & 2 deletions src/get/get.module.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import utils from "../utils";
import convertGeometry from "../convert-geometry";
import { convertBbox } from "../convert-geometry";
import wrap from "../wrap-parse";

const get = (georaster, geom, flat) => {
Expand Down Expand Up @@ -28,7 +28,7 @@ const get = (georaster, geom, flat) => {
} else if (utils.isBbox(geom)) {
// bounding box
try {
const geometry = convertGeometry("bbox", geom);
const geometry = convertBbox(geom);

// use a utility function that converts from the lat/long coordinate
// space to the image coordinate space
Expand All @@ -42,7 +42,10 @@ const get = (georaster, geom, flat) => {
console.error(error);
throw error;
}
} else if (["bottom", "left", "right", "top"].every(k => k in geom)) {
({ bottom: cropBottom, left: cropLeft, right: cropRight, top: cropTop } = geom);
} else {
console.error(geom);
throw "Geometry is not a bounding box - please make sure to send a bounding box when using geoblaze.get";
}

Expand Down
8 changes: 4 additions & 4 deletions src/histogram/histogram.core.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import fastMax from "fast-max";
import get from "../get";
import utils from "../utils";
import wrap from "../wrap-parse";
import convertGeometry from "../convert-geometry";
import { convertBbox, convertMultiPolygon } from "../convert-geometry";
import intersectPolygon from "../intersect-polygon";

const { resolve } = utils;
Expand Down Expand Up @@ -154,14 +154,14 @@ const getHistogramsForRaster = (georaster, geom, options) => {
const values = get(georaster, null, flat);
return resolve(values).then(calc);
} else if (utils.isBbox(geom)) {
geom = convertGeometry("bbox", geom);
geom = convertBbox(geom);

// grab array of values by band
const flat = true;
const values = get(georaster, geom, flat);
return resolve(values).then(calc);
} else if (utils.isPolygon(geom)) {
geom = convertGeometry("polygon", geom);
} else if (utils.isPolygonal(geom)) {
geom = convertMultiPolygon(geom);
const { noDataValue } = georaster;

// grab array of values by band
Expand Down
Loading

0 comments on commit 626041e

Please sign in to comment.