Skip to content

Commit

Permalink
added shrink and shrink_density
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielJDufour committed Jan 16, 2024
1 parent 6229e9e commit b706f40
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 28 deletions.
9 changes: 9 additions & 0 deletions docs/functions/reproj.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,13 @@ extent.reproj(4326, {
// which is passed to https://github.com/danieljdufour/bbox-fns#densepolygon
density: [100, 125]
});
```

## shrinking
Sometimes reprojecting a bounding box extends pass the valid bounds of the new projection, leading to NaN values. You can effectively shrink the bounding box, so it fits into the new projection's bounds, by pasing `shrink: true` and a `shrink_density` number. This works by essentially densifying the edges and disregarding points on the edges reprojected as NaN values.
```js
const northPole = new GeoExtent([-180, 85, 180, 90], { srs: 4326 });

northPole.reproj(3857, { shrink: true, shrink_density: 100 }).bbox;
[-20037508.342789244, 19971868.880408563, 20037508.342789244, 49411788.9015311]
```
14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,22 +54,22 @@
"homepage": "https://github.com/DanielJDufour/geo-extent#readme",
"devDependencies": {
"@babel/cli": "^7.23.4",
"@babel/core": "^7.23.6",
"@babel/core": "^7.23.7",
"@babel/helper-compilation-targets": "^7.23.6",
"@babel/helper-validator-option": "^7.23.5",
"@babel/plugin-transform-modules-commonjs": "^7.23.3",
"esbuild": "^0.19.10",
"flug": "^2.7.1",
"esbuild": "^0.19.11",
"flug": "^2.7.2",
"global-jsdom": "^9.2.0",
"jsdom": "^23.0.1",
"jsdom": "^23.2.0",
"leaflet": "^1.9.4"
},
"dependencies": {
"bbox-fns": "^0.19.0",
"bbox-fns": "^0.20.2",
"geography-markup-language": "^0.2.0",
"get-epsg-code": "1.2.0",
"preciso": "^0.12.0",
"reproject-bbox": "^0.12.0",
"preciso": "^0.12.2",
"reproject-bbox": "^0.13.1",
"reproject-geojson": "^0.5.0"
}
}
52 changes: 48 additions & 4 deletions src/geo-extent.js
Original file line number Diff line number Diff line change
Expand Up @@ -458,10 +458,20 @@ export class GeoExtent {

reproj(
to,
{ allow_infinity = false, debug_level = 0, density = "high", quiet = false } = {
{
allow_infinity = false,
debug_level = 0,
density = "high",
shrink = false,
shrink_density = 100,
split = true,
quiet = false
} = {
allow_infinity: false,
debug_level: 0,
density: "high",
shrink: false,
split: true,
quiet: false
}
) {
Expand Down Expand Up @@ -497,19 +507,22 @@ export class GeoExtent {

let reprojected;
try {
reprojected = reprojectBoundingBox({
const options = {
bbox: this.bbox,
density,
from: this.srs,
split,
to
});
};
reprojected = reprojectBoundingBox(options);
} catch (error) {
if (debug_level) console.error(error);
}

if (reprojected?.every(isFinite)) {
return new GeoExtent(reprojected, { srs: to });
}

// as a fallback, try reprojecting to EPSG:4326 then to the desired srs
if (to !== 4326) {
let bbox_4326;
Expand All @@ -518,6 +531,7 @@ export class GeoExtent {
bbox: this.bbox,
density,
from: this.srs,
split,
to: 4326
});
} catch (error) {
Expand All @@ -530,6 +544,7 @@ export class GeoExtent {
bbox: bbox_4326,
density,
from: 4326,
split,
to
});
} catch (err) {
Expand All @@ -538,7 +553,36 @@ export class GeoExtent {
}
}

if (allow_infinity || reprojected?.every(isFinite)) {
if (reprojected && (allow_infinity || reprojected?.every(isFinite))) {
return new GeoExtent(reprojected, { srs: to });
}

// if really haven't gotten a solution yet,
// such as when reprojecting globe into Web Mercator
// reproject with shrinking and highest density
if (shrink) {
try {
if (shrink_density === "lowest") shrink_density = 1;
else if (shrink_density === "low") shrink_density = 2;
else if (shrink_density === "medium") shrink_density = 10;
else if (shrink_density === "high") shrink_density = 100;
else if (shrink_density === "higher") shrink_density = 1000;
else if (shrink_density === "highest") shrink_density = 10000;

reprojected = reprojectBoundingBox({
bbox: this.bbox,
density: shrink_density,
from: this.srs,
nan_strategy: "skip",
split: true,
to
});
} catch (err) {
if (debug_level) console.error(`failed to reproject from bbox ${this.bbox} with shrinking to ${to}`);
}
}

if (reprojected && (allow_infinity || reprojected?.every(isFinite))) {
return new GeoExtent(reprojected, { srs: to });
} else if (quiet) {
return;
Expand Down
59 changes: 42 additions & 17 deletions test/test.reproj.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,23 @@ test("reproj error", ({ eq }) => {

test("north pole", ({ eq }) => {
const northPole = new GeoExtent([-180, 85, 180, 90], { srs: 4326 });
let msg;
try {
northPole.reproj(3857);
} catch (error) {
msg = error.message;
}
eq(msg.includes("failed to reproject"), true);

eq(northPole.reproj(3857, { quiet: true }), undefined);
eq(
northPole.reproj(3857, { shrink: true }).bbox,
[-20037508.342789244, 19971868.880408563, 20037508.342789244, 49411788.9015311]
);
eq(
northPole.reproj(3857, { shrink: true, shrink_density: 100 }).bbox,
[-20037508.342789244, 19971868.880408563, 20037508.342789244, 49411788.9015311]
);
eq(northPole.reproj(3857, { split: false, quiet: true })?.js, undefined);
});

test("reproject extent that crosses 180th meridian", ({ eq }) => {
// technically this layer is self-overlapping
const lyr = new GeoExtent([-180.00092731781535, 15.563268747733936, 179.99907268220255, 74.71076874773686], {
srs: 4326
});
const result = lyr.reproj(3857);
const result = lyr.reproj(3857, { debug_level: 0 });
eq(result.bbox, [-20037508.342789244, 1754201.542789432, 20037508.342789244, 12808999.953599941]);
});

Expand Down Expand Up @@ -73,38 +73,43 @@ test("reproject extent that bends out", ({ eq }) => {
const srs = 6623;
const extent = new GeoExtent(bbox, { srs });
eq(
extent.reproj(4326, { density: "lowest" }).bbox,
extent.reproj(4326, { density: "lowest", split: false }).bbox,
[-104.15783650020958, 22.33428366410961, -51.769705847928805, 56.48158793780131]
);
eq(
extent.reproj(4326, { density: "low" }).bbox,
extent.reproj(4326, { density: "low", split: false }).bbox,
[-104.15783650020958, 22.33428366410961, -51.769705847928805, 57.099578714450445]
);
eq(
extent.reproj(4326, { density: "medium" }).bbox,
extent.reproj(4326, { density: "medium", split: false }).bbox,
[-104.15783650020958, 22.33428366410961, -51.769705847928805, 57.52407399197629]
);
eq(
extent.reproj(4326, { density: "high" }).bbox,
extent.reproj(4326, { density: "high", split: false }).bbox,
[-104.15783650020958, 22.33428366410961, -51.769705847928805, 57.53583071204875]
);
eq(
extent.reproj(4326, { density: "higher" }).bbox,
extent.reproj(4326, { density: "higher", split: false }).bbox,
[-104.15783650020958, 22.33428366410961, -51.769705847928805, 57.53588499736936]
);
eq(
extent.reproj(4326, { density: "highest" }).bbox,
extent.reproj(4326, { density: "highest", split: false }).bbox,
[-104.15783650020958, 22.33428366410961, -51.769705847928805, 57.535885041786784]
);
eq(
extent.reproj(4326, { density: "highest", split: true }).bbox,
[-104.15783650020958, 22.33428366410961, -51.769705847928805, 57.53588504321043]
);
});

test("reproj to inf", ({ eq }) => {
const bbox = [-10018754.171394622, -7.081154551613622e-10, 0, 10018754.171394624];
const srs = "EPSG:3857";

let msg;
let result;
try {
new GeoExtent(bbox, { srs }).reproj(26916, { debug: false, density: 100 });
result = new GeoExtent(bbox, { srs }).reproj(26916, { debug: false, density: 100 });
} catch (error) {
msg = error.message;
}
Expand All @@ -120,3 +125,23 @@ test("reproj to inf", ({ eq }) => {
Infinity
]);
});

test("south pole", ({ eq }) => {
const ext = new GeoExtent([-3950000, -3943750, 3950000, 4350000], { srs: "EPSG:3031" });
eq(
ext.reproj(4326, { debug_level: 10, density: "highest", split: true }).bbox,
[-179.9942619157211, -90, 180, -39.36335491661697]
);
});

test("split", ({ eq }) => {
const ext = new GeoExtent([-180, -85.0511287798066, 179.99856, 85.0511287798066], { srs: "EPSG:4326" });
const reprojected = ext.reproj(3857).bbox;
eq(reprojected, [-20037508.342789244, -20037508.342789255, 20037348.0427225, 20037508.342789244]);
});

test("split again", ({ eq }) => {
const ext = new GeoExtent([-180, -89.99928, 179.99856, 90], { srs: "EPSG:4326" });
const reprojected = ext.reproj("EPSG:3857", { debug_level: 0, shrink: true });
eq(reprojected.bbox, [-20037508.342789244, -76394987.3448674, 20037348.0427225, 30976473.682611432]);
});

0 comments on commit b706f40

Please sign in to comment.