Skip to content

raster-dem: let inline minzoom/maxzoom override the TileJSON - #4557

Open
AndrewN81 wants to merge 2 commits into
maplibre:feature/terrain-3dfrom
AndrewN81:pr/raster-dem-inline-zoom
Open

raster-dem: let inline minzoom/maxzoom override the TileJSON#4557
AndrewN81 wants to merge 2 commits into
maplibre:feature/terrain-3dfrom
AndrewN81:pr/raster-dem-inline-zoom

Conversation

@AndrewN81

Copy link
Copy Markdown

What

A raster-dem source's inline minzoom / maxzoom are ignored on native when the source also has a TileJSON (url, or a PMTiles archive header): the TileJSON's zoom range replaces them. maplibre-gl-js lets the inline values win. The practical effect on this branch: a Terrarium PMTiles archive with a z12 header pins the terrain mesh and the drape cover at z12, so every road and building goes soft as soon as the map is tilted at z14+, even though the style asked for maxzoom: 16 (overzoom).

RasterDEMSource now records inline minzoom / maxzoom from the style (SourceOptions) and reapplies them over the loaded tileset's zoom range, matching gl-js precedence.

How it was verified

  • Simulator A/B at z14.3, pitched: with the style's inline maxzoom: 16 honoured, the drape is rendered from z14 tiles and roads stay crisp; before, identical output for maxzoom 14 and 16 (both ignored, cover stuck at the archive's z12).
  • Shipped in an iOS app since 2026-09-05.

Notes

Written with AI assistance (Claude), reviewed and tested by me before opening this PR, per MapLibre's AI policy.

A raster-dem source given by `url` replaced its tileset with the fetched TileJSON,
dropping any inline `minzoom`/`maxzoom` from the style. maplibre-gl-js does the
opposite (`extend(tileJSON, options)` in load_tilejson.ts), so a style that declares
a higher `maxzoom` than an archive's stored ceiling works on the web and not here.

With 3D terrain this matters: the mesh and its drape targets go no deeper than the
DEM source's declared maxzoom, so a PMTiles DEM that stops at z12 pinned the whole
draped map to z12 textures and every road blurred past z13. Declaring `maxzoom: 16`
inline now takes effect and the DEM overzooms from its z12 ancestors.

SourceOptions gains minzoom/maxzoom, parsed alongside `encoding`, and
RasterDEMSource::setTilesetOverrides applies them after the TileJSON.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions github-actions Bot added the core Changes that affect the C++ core of MapLibre Native label Sep 5, 2026
@AndrewN81
AndrewN81 marked this pull request as ready for review September 5, 2026 10:24
struct SourceOptions {
std::optional<Tileset::RasterEncoding> rasterEncoding = std::nullopt;
std::optional<Tileset::VectorEncoding> vectorEncoding = std::nullopt;
// Inline style overrides applied on top of a fetched TileJSON, matching maplibre-gl-js

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to reference a source file in another repo, it better be a permalink.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, it now links the gl-js line by commit permalink.

@louwers louwers left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs tests.

…s reference

- SourceOptions conversion: zoom range parsed alone and alongside encoding,
  wrong type and out-of-range values rejected with 'invalid minzoom/maxzoom'.
- RasterDEMSource: the inline maxzoom replaces the TileJSON's after
  loadDescription while an unset minzoom keeps the TileJSON value; without
  inline options the TileJSON range is kept unchanged.
- Point the comment in raster_dem_source.hpp at a maplibre-gl-js permalink.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@AndrewN81

Copy link
Copy Markdown
Author

Added unit tests in ce4876b:

  • SourceOptions conversion (test/style/conversion/source_options.test.cpp): minzoom/maxzoom parsed alone and alongside encoding; a non-numeric or out-of-range value is rejected with an invalid minzoom/invalid maxzoom error.
  • RasterDEMSource (test/style/source.test.cpp): after loadDescription an inline maxzoom replaces the TileJSON's while an unset minzoom keeps the TileJSON value, and with no inline options the TileJSON range is kept as-is.

Checked that the override test fails against the previous code (max stays at the TileJSON's 12) and passes with the change. All 17 SourceOptions.* / Source.RasterDEM* tests pass locally on macOS Metal.

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

Labels

core Changes that affect the C++ core of MapLibre Native js-parity

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants