Skip to content

Conversation

@kylebarron
Copy link
Member

image
Screen.Recording.2025-11-06.at.6.42.57.PM.mov

(this is actually not slowed down 😅 so we have some performance improvements to do!)

This summary was drafted by claude and then I've gone through and edited it

This PR is a draft, trying to implement support for managing a TileLayer based on an arbitrary tile layout, which in this case happens to be the internal tile layout of a generic COG image in an arbitrary coordinate system.

The goal is that deck.gl will automatically fetch tiles as needed, based on the current viewport, from either internal overviews or the full resolution data. This will be generic enough that we can extend it to Zarr data later.

deck.gl exposes the Tileset2D class, which we can pass into a TileLayer to override how it fetches tiles. So we need to implement a subclass of Tileset2D with custom behavior.

The implementation tries to follow deck.gl's own traversal for OSM web mercator indexing as much as possible, and tries to infer where the important differences are between web mercator tiling and generic tiling.

COG Metadata Extraction

  • Extracts overview levels, tile dimensions, CRS information from GeoTIFF
  • Computes affine geotransforms for each overview level
  • Sets up proj4 transformation objects for coordinate reprojection

Tile Traversal

  • Implements quadtree-based tile traversal starting from coarsest overview
  • Frustum culling to only render visible tiles
  • [In progress but not working]: Distance-based Level of Detail (LOD) selection following deck.gl's OSM tile implementation
  • Handles COGs with multiple tiles at the coarsest level (unlike OSM which always has 1 tile at z=0)

Coordinate Transformations

The implementation handles a complete transformation pipeline:

  1. Pixel coordinates → Image CRS using affine geotransform
  2. Image CRS → Web Mercator (EPSG:3857) using proj4
  3. Web Mercator → deck.gl world space [0, 512] for frustum culling

Implementation Details

Tile Bounds Calculation

Tile bounds are computed using the geotransform at 9 reference points across the tile surface:

  1. Sample 9 points for each tile: corners, center, midpoints of each side
  2. Transform each point from pixel space to image CRS with geotransform
  3. Reproject from image CRS to Web Mercator (EPSG:3857) with proj4
  4. Convert to deck.gl "common space" (where the web mercator axes are normalized to [0, 512])
  5. Create an Oriented Bounding Box from common space points (which then should work with deck.gl's frustum culling implementation)

This approach handles:

  • Arbitrary CRS (not just Web Mercator)
  • Potential rotation/skew in imagery
  • Non-rectangular tiles in common space

Current Status

Working ✅

  • COG metadata extraction with proper geotransform derivation
  • Coordinate transformations (Image CRS → Web Mercator → World Space)
  • Frustum culling (tiles render in correct geographic location)
  • Tile bounds visualization via PathLayer
  • Basic tile rendering infrastructure

In Progress ⚠️

  • LOD selection: Currently always selects finest resolution tiles regardless of zoom level
  • Need to tune distance-based LOD calculation to properly account for COG scale factors
  • The algorithm needs adjustment to select coarser tiles when zoomed out

Not Yet Implemented ❌

  • Tile data loading from COG (reading pixel data from GeoTIFF)
  • Actual raster tile rendering (separate work stream)

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants