From 65800f6b105d127c09e569afd4059aacf3c29aa5 Mon Sep 17 00:00:00 2001 From: yharby Date: Thu, 19 Mar 2026 01:04:44 +0200 Subject: [PATCH] fix: use proj4 +over flag to prevent antimeridian longitude wrapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit proj4's `adjust_lon` normalizes longitude to (-π, π], which causes 360° round-trip errors for coordinates at the antimeridian (±180°): - `forward(-180.001°, lat)` wraps to positive easting (wrong sign) - `inverse(-WM_HALF, northing)` returns +180° instead of -180° These errors make the Delatin mesh refinement unconvergeable for tiles touching the antimeridian on global EPSG:4326 COGs (e.g. a 1.4M×600K pixel DEM spanning ±180° longitude). The round-trip error equals the full image width, producing visibly distorted tile meshes at low zoom. Fix: Add `+over` to the target projection definitions for both the 4326 and 3857 converters. The `+over` flag disables `adjust_lon`, allowing coordinates to pass through unwrapped. This is safe for longlat and Mercator projections where the 180° meridian is a straight line. The `+over` flag is supported since proj4js v2.20.0 (PR proj4js#530). Fixes https://github.com/developmentseed/deck.gl-raster/issues/352 --- packages/deck.gl-geotiff/src/cog-layer.ts | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/packages/deck.gl-geotiff/src/cog-layer.ts b/packages/deck.gl-geotiff/src/cog-layer.ts index 8eb1f998..92c7daa3 100644 --- a/packages/deck.gl-geotiff/src/cog-layer.ts +++ b/packages/deck.gl-geotiff/src/cog-layer.ts @@ -284,9 +284,27 @@ export class COGLayer< const tms = generateTileMatrixSet(geotiff, sourceProjection); + // Use +over to disable proj4's adjust_lon longitude normalization. + // Without +over, proj4 wraps longitude at ±180° causing: + // - forward(-180.001°) → positive easting (wrong sign) + // - inverse(-WM_HALF) → +180° instead of -180° + // These 360° round-trip errors make mesh refinement (Delatin) + // unconvergeable for tiles touching the antimeridian on global COGs. + // +over is safe for longlat and Mercator targets where the 180° + // meridian projects to a straight line. + // Ref: https://proj.org/en/latest/usage/projections.html + // Ref: https://github.com/proj4js/proj4js/pull/530 + // Register target projections with +over via proj4.defs so they are + // referenced by name (avoids ts-expect-error for wkt-parser input). + proj4.defs("__WGS84_OVER", "+proj=longlat +datum=WGS84 +over"); + proj4.defs( + "__MERC_OVER", + "+proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +over", + ); + // @ts-expect-error - proj4 typings are incomplete and don't support // wkt-parser input - const converter4326 = proj4(sourceProjection, "EPSG:4326"); + const converter4326 = proj4(sourceProjection, "__WGS84_OVER"); const forwardTo4326 = (x: number, y: number) => converter4326.forward<[number, number]>([x, y], false); const inverseFrom4326 = (x: number, y: number) => @@ -294,7 +312,7 @@ export class COGLayer< // @ts-expect-error - proj4 typings are incomplete and don't support // wkt-parser input - const converter3857 = proj4(sourceProjection, "EPSG:3857"); + const converter3857 = proj4(sourceProjection, "__MERC_OVER"); const forwardTo3857 = makeClampedForwardTo3857( (x: number, y: number) => converter3857.forward<[number, number]>([x, y], false),