Context
PR #349 (merged as 6adddc4) introduces CARTESIAN/EPSG:3857 rendering for WebMercator viewports. This works great for regional COGs but produces rendering artifacts on large global EPSG:4326 datasets where tiles span ±180° longitude.
Test file
gdalinfo /vsicurl/https://s3.us-west-2.amazonaws.com/us-west-2.opendata.source.coop/walkthru-earth/dem-terrain/GEDTM30/gedtm30.tif
1440010×600010 pixels, EPSG:4326, Int32, Deflate, 2048×2048 tiles, 10 overviews, bbox [-180.00125, -65.00125, 180.00125, 85.00125].
Issues found
1. inverseFrom3857 returns +180° at the antimeridian → 360° round-trip error
For tiles touching lon=-180°, the mesh refinement round-trip CRS → 3857 → CRS can flip longitude from -180° to +180° due to floating-point ambiguity in proj4. This causes a round-trip error equal to the full image width (5625 pixels for this file), and the mesh never converges.
Workaround: Normalize longitude in inverseFrom3857/inverseFrom4326:
if (r[0] >= 180) r[0] -= 360;
else if (r[0] < -180) r[0] += 360;
2. sampleReferencePointsInEPSG3857 receives NaN from oversized tile matrices
When tileHeight > imageHeight in a COG overview (e.g. 2048px tile for a 2343px overview), the tile matrix bounds extend far beyond the data bbox (lat=-177° for this file). projectTo3857 returns NaN for these out-of-domain coordinates, which propagates through tile traversal → "Invalid number null" crash in TileLayer initialization.
Workaround: Clamp non-finite values in sampleReferencePointsInEPSG3857:
if (!Number.isFinite(projected[0])) projected[0] = 0;
if (!Number.isFinite(projected[1])) projected[1] = geoY > 0
? EPSG_3857_HALF_CIRCUMFERENCE : -EPSG_3857_HALF_CIRCUMFERENCE;
3. RasterReprojector.run() has no iteration limit → browser hang
For tiles with extreme Mercator non-linearity (partial tiles spanning -65° to -177° latitude), the Delatin mesh refinement while (getMaxError() > maxError) { refine() } loop never converges and hangs the browser.
Workaround: Add iteration cap in delatin.js:
const MAX_ITERATIONS = 5000;
while (this.getMaxError() > maxError) {
this.refine();
if (++iterations >= MAX_ITERATIONS) break;
}
4. Partial edge tiles produce distorted meshes
At z=0, tiles where actual data height is <25% of tile matrix height (e.g. 295px data in 2048px tile) have forwardTransform mapping UV [0,1] to CRS coordinates far beyond the data bbox. The mesh is built for the full UV range, creating distorted geometry.
Workaround: Skip rendering tiles where data.height / tileMatrix.tileHeight < 0.25.
5. Bbox slightly beyond ±180° wraps easting sign
The test file has bbox lon=±180.00125°. forwardTo3857(-180.00125, lat) wraps to positive easting (+20037369 instead of -20037647), placing the tile on the wrong side of the world.
Workaround: Clamp EPSG:4326 bbox to exactly [-180, lat_min, 180, lat_max] before calling generateTileMatrixSet.
Environment

Context
PR #349 (merged as 6adddc4) introduces CARTESIAN/EPSG:3857 rendering for WebMercator viewports. This works great for regional COGs but produces rendering artifacts on large global EPSG:4326 datasets where tiles span ±180° longitude.
Test file
1440010×600010 pixels, EPSG:4326, Int32, Deflate, 2048×2048 tiles, 10 overviews, bbox [-180.00125, -65.00125, 180.00125, 85.00125].
Issues found
1.
inverseFrom3857returns +180° at the antimeridian → 360° round-trip errorFor tiles touching lon=-180°, the mesh refinement round-trip
CRS → 3857 → CRScan flip longitude from -180° to +180° due to floating-point ambiguity in proj4. This causes a round-trip error equal to the full image width (5625 pixels for this file), and the mesh never converges.Workaround: Normalize longitude in
inverseFrom3857/inverseFrom4326:2.
sampleReferencePointsInEPSG3857receives NaN from oversized tile matricesWhen
tileHeight > imageHeightin a COG overview (e.g. 2048px tile for a 2343px overview), the tile matrix bounds extend far beyond the data bbox (lat=-177° for this file).projectTo3857returns NaN for these out-of-domain coordinates, which propagates through tile traversal →"Invalid number null"crash in TileLayer initialization.Workaround: Clamp non-finite values in
sampleReferencePointsInEPSG3857:3.
RasterReprojector.run()has no iteration limit → browser hangFor tiles with extreme Mercator non-linearity (partial tiles spanning -65° to -177° latitude), the Delatin mesh refinement
while (getMaxError() > maxError) { refine() }loop never converges and hangs the browser.Workaround: Add iteration cap in
delatin.js:4. Partial edge tiles produce distorted meshes
At z=0, tiles where actual data height is <25% of tile matrix height (e.g. 295px data in 2048px tile) have
forwardTransformmapping UV [0,1] to CRS coordinates far beyond the data bbox. The mesh is built for the full UV range, creating distorted geometry.Workaround: Skip rendering tiles where
data.height / tileMatrix.tileHeight < 0.25.5. Bbox slightly beyond ±180° wraps easting sign
The test file has bbox lon=±180.00125°.
forwardTo3857(-180.00125, lat)wraps to positive easting (+20037369 instead of -20037647), placing the tile on the wrong side of the world.Workaround: Clamp EPSG:4326 bbox to exactly [-180, lat_min, 180, lat_max] before calling
generateTileMatrixSet.Environment
@developmentseed/deck.gl-geotiff@0.3.0+ PR fix: Render mesh from Web Mercator coordinates #349 backport@developmentseed/deck.gl-raster@0.3.0@developmentseed/raster-reproject@0.3.0