Skip to content

feat: Web Mercator axis-aligned cutline support#424

Merged
kylebarron merged 19 commits intomainfrom
feat/cutline-bbox-module
Apr 15, 2026
Merged

feat: Web Mercator axis-aligned cutline support#424
kylebarron merged 19 commits intomainfrom
feat/cutline-bbox-module

Conversation

@kylebarron
Copy link
Copy Markdown
Member

@kylebarron kylebarron commented Apr 15, 2026

Change list

  • Add cutline bbox support in web mercator meters, allowing for avoiding rendering a portion of the image outside of a specific bbox. (The data outside of the bbox still loads)
  • New example to visualize USGS Historical Topographic maps, with and without their collar

Full image:

image

Map collar stripped:

image

Closes #421

kylebarron and others added 12 commits April 14, 2026 19:11
Discards fragments outside a WGS84 axis-aligned bbox for rendering USGS
historical topographic maps and other rasters with a "map collar".
Mercator-only, opt-in via a custom renderTile callback on COGLayer.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Discards fragments outside a WGS84 axis-aligned bbox. Intended for
rendering rasters with a "map collar" (e.g. USGS historical topos) where
the valid data area is described as a lat/lng bbox but the raw pixels
include surrounding metadata. Mercator-only; caller must enforce
WebMercatorViewport.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
DECKGL_FILTER_COLOR is generated as a separate hook function whose body
is assembled before the main FS source. Top-level FS varyings like
position_commonspace are therefore out of scope inside it, producing
"undeclared identifier" at compile time. Injecting at fs:#main-start
places the discard test inside main() where the varying is visible.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Expose inferRenderPipeline and TextureDataT so users can wrap the
default COGLayer pipeline with additional modules (e.g. CutlineBbox)
without reimplementing tile fetching. Also update the spec to document
the fs:#main-start hook choice.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Renders the Emigrant Gap, CA 1:62,500 USGS historical topo (1955) with
an optional CutlineBbox module that discards the map collar. Wires the
module into a custom renderTile callback on COGLayer by wrapping the
inferred default pipeline.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Explains the distinction between hook-function injections (like
fs:DECKGL_FILTER_COLOR) and source injections (fs:#main-start,
fs:#main-end, fs:#decl), including why top-level FS varyings are
visible in the latter but not the former. Captured after debugging
an "undeclared identifier" error on position_commonspace while
implementing CutlineBbox.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The earlier approach read position_commonspace from fs:#main-start and
compared against a uniform computed via lngLatToWorld. That worked at
low zoom but broke visibly at higher zoom: deck.gl applies a
viewport-dependent precision translation to common-space positions to
maintain f32 precision, so the FS varying and the CPU-computed uniform
ended up in different coordinate frames and the test evaluated every
fragment as "outside", discarding the whole tile.

This commit sidesteps common space entirely. The VS captures
`positions.xy` (raw 3857 meters, per RasterLayer's mesh construction)
into a module-owned varying `v_cutlineBboxMercator`, and the FS
compares it against a uniform also in raw 3857 meters computed via a
hand-rolled spherical mercator forward. Both sides of the comparison
live in the same absolute coordinate frame at every zoom level.

Known precision ceiling: at |10M| mercator values, float32 gives ~1.2m
quantization, which becomes visible as "wiggle" at the bbox edges
around z=17-18. Acceptable for the USGS historical topo use case
(typical viewing z=11-17). A future fix for sharper edges at z=18+
would require POSITION64LOW mesh attributes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The usgs-topo-cutline example originally needed inferRenderPipeline to
wrap the default pipeline with an extra module, but it now uses an
explicit two-module pipeline (CreateTexture + CutlineBbox) with its
own minimal getTileData. No remaining consumer of the export, so we
drop it rather than ship unused public API.

This reverts the export added in a65e000.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Match the naip-mosaic example pattern: a minimal inline getTileData
that decodes a 3-band uint8 RGB COG tile and uploads it as rgba8unorm,
plus a two-module renderTile that chains CreateTexture and CutlineBbox.
No dependency on inferRenderPipeline — the example reads as a direct
demonstration of how the two modules compose.

Also adds a zoom display in the info panel to help eyeball the
float32 precision ceiling around z=17-18.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rewrite the spec's "coordinate space for the test" section to
describe the raw-EPSG:3857-meters approach and explain why the earlier
common-space attempt failed at high zoom. Add a float32 precision
ceiling note covering the z=17-18 quantization behavior.

Update the gpu-modules injection-hooks guide to use the final
VS-injection + fs:#main-start pattern as the worked example, with the
full narrative of the two-step diagnosis (undeclared identifier →
common-space precision drift → raw mercator varying).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the feat label Apr 15, 2026
kylebarron and others added 7 commits April 15, 2026 12:12
Plans under dev-docs/plans/ are one-shot TDD scaffolds that mirror
what ends up in the spec, tests, and git log — and they rot as
implementation evolves away from them. Specs in dev-docs/specs/
capture design decisions worth versioning; plans do not.

Removes both existing plans and gitignores the directory.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…or helper

Previously CutlineBbox accepted a WGS84 bbox and did the WGS84 → 3857
projection inside getUniforms. That ran on every frame per visible tile
because luma.gl's ShaderInputs.setProps calls getUniforms
unconditionally — the cost was negligible in absolute terms but
conceptually wasteful work on the hot render path.

Split into:

- CutlineBbox: now accepts the bbox in EPSG:3857 meters directly. Its
  getUniforms is a pure pass-through, zero math in the render loop.
  Matches the pattern the rest of this repo uses (FilterNoDataVal,
  MaskTexture, LinearRescale, CompositeBands, CreateTexture) where
  getUniforms maps props 1:1 to uniforms without CPU-side transformations.

- lngLatToMercator(lng, lat): a new exported point-level helper. Takes a
  WGS84 point and returns [x, y] in 3857 meters. Callers invoke it once
  at bbox definition time and pack two corners into the bbox vec4
  themselves. Validates the Web Mercator latitude limit per point; bbox
  packing concerns (antimeridian, axis alignment) are left to the caller.

The example composes lngLatToMercator twice per USGS quad via a local
`topoBbox` wrapper.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@kylebarron kylebarron changed the title feat: WGS84 axis-aligned cutline support feat: Web Mercator axis-aligned cutline support Apr 15, 2026
@kylebarron kylebarron marked this pull request as ready for review April 15, 2026 17:33
@kylebarron kylebarron merged commit 138cba2 into main Apr 15, 2026
8 checks passed
@kylebarron kylebarron deleted the feat/cutline-bbox-module branch April 15, 2026 17:43
@ds-release-bot ds-release-bot Bot mentioned this pull request Apr 15, 2026
@kylebarron kylebarron mentioned this pull request Apr 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cutline/crop support

1 participant