deck.gl: TileLayer Inconsistent Z Calculation

Description

Tile-layer uses tileset-2d, which in turn uses the getTilesIndices function within tile-layer’s util.js. GetTileIndices calculates the z value from the viewport zoom, which ends up getting passed into the getTileData({x, y, z}) prop for retreiving images: const TILE_SIZE = 512; let z = Math.round(viewport.zoom + Math.log2(TILE_SIZE / tileSize));

Because of this, I ran into a confusing and inconsistent problem with tiled layers behaving differently with tileSizes such as 256 (as in using two separate tiled image sources that use different tile image dimensions, e.g. one has images of 256x256, and the other has images of 512x512), being given the wrong z value to fetch data at, whereas other tiled layer sources would work properly.

For example, if the TileLayer view initialises with a zoom of -1.4 (0 being fully zoomed in & max-resolution), with a tileSize of 256, z will be calculated as Math.round(1.4 + Math.log2(512/256)) => 0. Then the TileLayer will fetch from z 0 at a zoom of -1.4, when it should instead be fetching from z -1 - displaying incorrect/stretched tiles on screen.

Conversely, with a tileSize of 512, the TileLayer would fetch the correct level tiles for the zoom as the z calculated from a -1.4 zoom would be -1, not 0.

My work around now involves applying an offset to the z value: const decimals = Math.floor(this.viewStates.main.zoom) - this.viewStates.main.zoom; const offset = decimals < -0.5 ? 1 : 0; const DZIResolutionLevelAtZoomZero = DZIMaxLevel - offset;

getTileData(DZIResolutionLevelAtZoomZero + z, x, y)

Expected Behavior

Unless I’m missing something, TileLayers should be able to consistently calculate and pass the correct z value regardless of tileSize, without needing to correct with an offset.

Repro Steps

Use TileLayer data sources with tileSizes of 256 and 512 to see the difference in how z get’s calculated.

Environment

Framework Version: 8.4.16 Browser Version: Chrome 90.0.4430.212 OS: Windows 10.0.19042 Build 19042

Logs

None

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 17 (1 by maintainers)

Most upvoted comments

@mcost45 You are correct in your analysis if I understand you correctly. In order to calculate the offset correctly you can use something like: https://github.com/hms-dbmi/viv/blob/master/src/layers/MultiscaleImageLayer/MultiscaleImageLayer.js#L108-L112 There is a comment there about why it works and a link to the line of code here that necessitates it.

@Pessimistress I can add some docs for this if you’d like, or add a fix - either way. What @mcost45 is saying is similar to what I was saying in #4616 about the zoom-level being a little wonky. The reason I that I made the change that necessitated #4616 was because previously the tile fetching mechanism was doing what @mcost45 described but in the geospatial context. That is, it used to chronically underfetch tiles resulting in a blurry map. However my fix resulted in fetching too aggressively.

So I see a few options here:

  1. Change https://github.com/visgl/deck.gl/blob/26635d301171387c5c0509b5a099e151cf3de6f9/modules/geo-layers/src/tile-layer/utils.js#L183 based on the type of viewport (geospatial or not), which would be a “breaking change” of sorts, although it’s extremely possible I am the only consumer of this feature/fix/change besides now @mcost45.
  2. Add documentation about this to TileLayer explaining how to get the correct zooming mechanism.
  3. Something else?

Hope this helps!