Skip to content

Commit 459bf99

Browse files
Merge pull request #28 from DanielJDufour/trimming
trim bbox reprojection, enabling global reprojection over projection bounds
2 parents 408ae2c + 2e52a1c commit 459bf99

File tree

3 files changed

+82
-8
lines changed

3 files changed

+82
-8
lines changed

geowarp.js

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,7 @@ const geowarp = function geowarp({
549549
let forward_turbocharged, inverse_turbocharged;
550550
if (turbo) {
551551
if (forward) {
552-
out_bbox_in_srs ??= reprojectBoundingBox(out_bbox, inverse, { density: 100 });
552+
out_bbox_in_srs ??= reprojectBoundingBox(out_bbox, inverse, { density: 100, nan_strategy: "skip" });
553553
intersect_bbox_in_srs ??= intersect(in_bbox, out_bbox_in_srs);
554554
forward_turbocharged = turbocharge({
555555
bbox: intersect_bbox_in_srs,
@@ -583,8 +583,9 @@ const geowarp = function geowarp({
583583
if (method === "near-vectorize" || method === "nearest-vectorize") {
584584
if (debug_level >= 2) console.log('[geowarp] choosing between "near" and "vectorize" for best speed');
585585

586-
out_bbox_in_srs ??= same_srs ? out_bbox : reprojectBoundingBox(out_bbox, inverse, { density: 100 });
586+
out_bbox_in_srs ??= same_srs ? out_bbox : reprojectBoundingBox(out_bbox, inverse, { density: 100, nan_strategy: "skip" });
587587

588+
// average of how large each output pixel is in the input spatial reference system
588589
out_sample_height_in_srs = (out_bbox_in_srs[3] - out_bbox_in_srs[1]) / out_height_in_samples;
589590
out_sample_width_in_srs = (out_bbox_in_srs[2] - out_bbox_in_srs[0]) / out_width_in_samples;
590591

@@ -613,7 +614,8 @@ const geowarp = function geowarp({
613614
// const [cfwd, clear_forward_cache] = cacheFunction(fwd);
614615

615616
// reproject bounding box of output (e.g. a tile) into the spatial reference system of the input data
616-
out_bbox_in_srs ??= same_srs ? out_bbox : reprojectBoundingBox(out_bbox, inverse, { density: 100 });
617+
// setting nan_strategy to skip trims the box in case the output bbox extends over the bounds of the input projection
618+
out_bbox_in_srs ??= same_srs ? out_bbox : reprojectBoundingBox(out_bbox, inverse, { density: 100, nan_strategy: "skip" });
617619
let [left, bottom, right, top] = out_bbox_in_srs;
618620

619621
out_sample_height_in_srs ??= (top - bottom) / out_height_in_samples;
@@ -888,11 +890,18 @@ const geowarp = function geowarp({
888890
// combing srs reprojection and srs-to-image mapping, ensures that bounding box corners
889891
// are reprojected fully before calculating containing bbox
890892
// (prevents drift in increasing bbox twice if image is warped)
891-
const [leftInRasterPixels, topInRasterPixels, rightInRasterPixels, bottomInRasterPixels] = reprojectBoundingBox(
892-
[left, bottom, right, top],
893-
out_srs_pt_to_in_img_pt
894-
);
895-
893+
let leftInRasterPixels, topInRasterPixels, rightInRasterPixels, bottomInRasterPixels;
894+
try {
895+
[leftInRasterPixels, topInRasterPixels, rightInRasterPixels, bottomInRasterPixels] = reprojectBoundingBox(
896+
[left, bottom, right, top],
897+
out_srs_pt_to_in_img_pt,
898+
{ nan_strategy: "throw" }
899+
);
900+
} catch (error) {
901+
// if only one pixel (or row of pixels) extends over the edge of the projection's bounds, we probably don't want to fail the whole thing
902+
// an example would be warping the globe from 3857 to 4326
903+
continue;
904+
}
896905
if (debug_level >= 4) console.log("[geowarp] leftInRasterPixels:", leftInRasterPixels);
897906
if (debug_level >= 4) console.log("[geowarp] rightInRasterPixels:", rightInRasterPixels);
898907
if (debug_level >= 4) console.log("[geowarp] topInRasterPixels:", topInRasterPixels);

test.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,3 +860,67 @@ test("antarctica with NaN", async ({ eq }) => {
860860
}
861861
}
862862
});
863+
864+
test("issue 27: globe 3857 to 4326", async ({ eq }) => {
865+
const filename = "gadas-world.tif";
866+
const filepath = path.resolve(__dirname, "./test-data", filename);
867+
const geotiff = await GeoTIFF.fromFile(filepath);
868+
const image = await geotiff.getImage(0);
869+
const in_data = await image.readRasters();
870+
const bbox = getBoundingBox(image);
871+
const in_height = image.getHeight();
872+
const in_width = image.getWidth();
873+
const out_height = 180 * 2;
874+
const out_width = 360 * 2;
875+
876+
const { forward, inverse } = proj4("EPSG:3857", "EPSG:4326");
877+
878+
const methods = ["near-vectorize", "near", "bilinear", "median"];
879+
const turbos = [true, false];
880+
for (let i = 0; i < methods.length; i++) {
881+
const method = methods[i];
882+
for (let ii = 0; ii < 2; ii++) {
883+
const turbo = turbos[ii];
884+
const result = await geowarp({
885+
debug_level: 0,
886+
in_bbox: bbox,
887+
in_geotransform: [-20057076.25595305, 39135.75848200009, 0, 12640208.839021027, 0, -39135.75848200009],
888+
in_data,
889+
in_layout: "[band][row,column]",
890+
in_srs: 3857,
891+
in_height,
892+
in_width,
893+
out_bbox: [-180, -90, 180, 90],
894+
out_height,
895+
out_no_data: null,
896+
out_width,
897+
out_layout: "[band][row][column]",
898+
out_srs: 4326,
899+
forward,
900+
inverse,
901+
method,
902+
round: true,
903+
theoretical_max: 255,
904+
theoretical_min: 0,
905+
turbo
906+
});
907+
// console.log(method + " warped");
908+
// console.dir(result.data, { maxArrayLength: 3 });
909+
910+
// console.dir(
911+
// result.data.map(band => band.map(row => row[0])),
912+
// { maxArrayLength: 500 }
913+
// );
914+
915+
// check that no NaN values in output
916+
eq(
917+
result.data.flat(3).findIndex(it => isNaN(it)),
918+
-1
919+
);
920+
921+
if (process.env.WRITE) {
922+
writePNGSync({ h: out_height, w: out_width, data: result.data, filepath: `./test-output/gadas-whole-4326-${method}${turbo ? "-turbo" : ""}` });
923+
}
924+
}
925+
}
926+
});

test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ const runTileTests = async ({
377377
"25,33,20",
378378
"27,35,22",
379379
"28,30,17",
380+
"32,34,21",
380381
"33,43,34",
381382
"36,46,45",
382383
"40,49,47",

0 commit comments

Comments
 (0)