mapbox-gl-js icon indicating copy to clipboard operation
mapbox-gl-js copied to clipboard

Symbols on bottom or right edge of vector tile edge are not drawn

Open tjcaverly opened this issue 1 year ago • 4 comments

This is due to code to prevent double drawing symbols, such as https://github.com/mapbox/mapbox-gl-js/blob/b73229ccfc93aa792090425fd484f3150d72330f/src/symbol/symbol_layout.js#L422 which includes symbols on the top and left edges, but not the bottom and right ones. This point geom is only being returned in one vector tile however, since it only intersects one tile, so it is not drawn at all. I think this is fairly normal behavior for a vector tile server, so it seems like a bug.

mapbox-gl-js version: 2.9.2, 1.13.2

browser: Any

Steps to Trigger Behavior

  1. Create point data that will be included in a vector tile and that will have geometry with x or y coordinates of EXTENT at some zoom in mapbox. For example, an mvt tile containing a point geom of (10, 4096) and default extent. (example for tile 17/22840/52786, {"type":"Point","coordinates":[-117.266871679,33.020179249]} in EPSG:4326 encoded in a vector tile with extent 4096).
  2. Have mapbox render this vector tile source as a symbol layer.
  3. View map at zoom level 17 where the point is.

Link to Demonstration

https://user-images.githubusercontent.com/1109069/180867648-921e6a7b-396a-4523-b4a1-a5470def0b96.mov

Expected Behavior

Point is visible.

Actual Behavior

Point is not visible at this zoom level.

tjcaverly avatar Jul 25 '22 20:07 tjcaverly

Can you tell which tile server you are using to generate these tiles?

I think this is fairly normal behavior for a vector tile server, so it seems like a bug.

Mapbox tile servers treat any points on the edge of the tile extent as belonging to tiles on both sides. This is implied by the vector tile specification:

For example, if a tile has an extent of 4096, coordinate units within the tile refer to 1/4096th of its square dimensions. A coordinate of 0 is on the top or left edge of the tile, and a coordinate of 4096 is on the bottom or right edge. Coordinates from 1 through 4095 inclusive are fully within the extent of the tile, and coordinates less than 0 or greater than 4096 are fully outside the extent of the tile. A point at (1,10) or (4095,10) is within the extent of the tile. A point at (0,10) or (4096,10) is on the edge of the extent. A point at (-1,10) or (4097,10) is outside the extent of the tile.

If a tile has extent of 4096 (covering 0..4095), a point at 4096 is physically in the same location as the next tile with 0, but it will be still considered at the edge of the extent and so included in both.

mourner avatar Jul 26 '22 17:07 mourner

@mourner We create the mvt geom with postgis st_asmvtgeom. The geoms to encode in a tile are determined by whether the feature geometry intersects the tile, so a point will only ever be returned in one tile (unless possibly if it's literally on the edge of the tile in original coordinates). So a point that is in within 1/8192 of the right edge of the tile but not actually on the edge will only be returned in one tile, and the mvt coordinate will be rounded up to 4096 by st_asmvtgeom.

tjcaverly avatar Jul 26 '22 18:07 tjcaverly

@tjcaverly is there any way to address this on the PostGIS side, e.g. intersect with the tile after rounding the coordinates?

mourner avatar Jul 27 '22 13:07 mourner

We're planning on addressing it by using the margin parameter in st_tileenvelope, to include the point in both tiles if it's near the edge (also helps for line geometries near an edge that don't intersect both tiles). I don't think rounding would work since it would still likely only intersect with one tile.

Thanks for the quick response. Not sure how common it is for vector tile servers to work this way, most will have a buffer around the tile, but might not include geometries that only intersect the buffer and not the original tile.

tjcaverly avatar Jul 27 '22 16:07 tjcaverly