-
Notifications
You must be signed in to change notification settings - Fork 13
Description
Description
When rendering an EPSG:4326 COG that spans the antimeridian (±180° longitude) in a Web Mercator viewport, tiles near the dateline cause RasterReprojector mesh refinement to diverge, producing mislocated rectangles across the map.
The root cause: forwardTo3857 maps nearby source coordinates on opposite sides of ±180° to EPSG:3857 x-values ~40 million meters apart (+20M vs -20M). The mesh triangles connecting these vertices span the entire map, and the reprojection error never converges (error=43200 pixels after 10001 iterations).
Reproduction
Load a global EPSG:4326 COG (e.g. WorldPop population data):
new COGLayer({
geotiff: 's3://wherobots-examples/data/ppp_2020_1km_Aggregated.tif',
// ...
})Console shows:
RasterReprojector: mesh refinement did not converge after 10001 iterations
(maxError=0.125, currentError=43200.00017279999)
Analysis
In _renderSubLayers, for Web Mercator viewports, reprojectionFns.forwardReproject is set to forwardTo3857. For tiles at the antimeridian, this projection has a discontinuity — longitude values like +179° and -179° (which are 2° apart geographically) map to x-values ~40M meters apart in EPSG:3857. The RasterReprojector mesh subdivision cannot resolve this discontinuity no matter how many iterations it runs.
Workaround
We're patching _renderSubLayers to detect antimeridian-crossing tiles by checking if the tile's corner x-coordinates in EPSG:3857 span more than half the world circumference. When detected, forwardTo3857 is wrapped to shift negative x-values by +circumference, making the mesh continuous:
const HALF_CIRCUMFERENCE = WEB_MERCATOR_METER_CIRCUMFERENCE / 2;
const cornerXs = /* compute tile corners in EPSG:3857 */;
if (Math.max(...cornerXs) - Math.min(...cornerXs) > HALF_CIRCUMFERENCE) {
tileForwardTo3857 = (x, y) => {
const [px, py] = forwardTo3857(x, y);
return [px < 0 ? px + WEB_MERCATOR_METER_CIRCUMFERENCE : px, py];
};
tileInverseFrom3857 = (x, y) => {
const unwrapped = x > HALF_CIRCUMFERENCE ? x - WEB_MERCATOR_METER_CIRCUMFERENCE : x;
return inverseFrom3857(unwrapped, y);
};
}Environment
@developmentseed/deck.gl-geotiff: 0.4.0
@developmentseed/raster-reproject: 0.4.0