Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

MVT-postgresql: zoomed-out tiles miss features when storage_crs is projected (e.g. UTM)

Đang mở
#2,466 0 bình luận 0 reaction 1 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

@doublebyte1 đang làm issue này rồi.

Từ ngày 28/10/2026.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
58/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
postgresql, python

Hướng nghiên cứu

Read pygeoapi/provider/mvt_postgresql.py, especially get_tiles() and its geom_filter transform; the issue also links a downstream implementation for comparison. Reproduce with EPSG:25833 data and zoom 0–4 WebMercatorQuad tiles, comparing returned features with geometries intersecting each tile. Done means all intersecting features appear across zoom levels, with a regression test using projected CRS data.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

bug OGC API - Tiles

Description
With the MVT-postgresql provider and a table stored in a projected CRS (here EPSG:25833, UTM 33N), the most zoomed-out WebMercatorQuad tiles leave out features that lie inside them.

The cause is in pygeoapi/provider/mvt_postgresql.py, get_tiles() (same in 0.24.0 and master):

geom_filter = geom_column.intersects(
    ST_Transform(envelope, self.storage_crs.to_string())
)

ST_TileEnvelope returns a rectangle with only four corners. ST_Transform converts those four points, and the straight lines between them stand in for the tile's edges. In a projected CRS like UTM, a tile's edges are curved, more so the bigger the tile. The straight-line polygon misses slivers of the real tile, and features in those slivers fail the intersects filter.

At zoom 0 it breaks down entirely, because the corners sit at ±180°. With pyproj 3.8.0 (PROJ 9.8.1), EPSG:3857 → EPSG:25833:

(-20037508, -20037508) → (642850, -10531751)
( 20037508, -20037508) → (642850, -10531751)
( 20037508,  20037508) → (642850,  10531751)
(-20037508,  20037508) → (642850,  10531751)

The envelope collapses to the line x = 642850.

Data stored in EPSG:4326 or EPSG:3857 shouldn't be affected, because a WebMercatorQuad tile's edges stay straight in those CRSs.

Steps to Reproduce

  1. Publish a table stored in EPSG:25833 with the MVT-postgresql provider, e.g. Norway's 357 municipalities. A public pygeoapi 0.24.0 service with exactly this (Kartverket's demo):
    https://api.datadeling-ogcapi.atgcp1-dev.kartverket.cloud/collections/kommuner/tiles/WebMercatorQuad/{z}/{y}/{x}?f=mvt
    
  2. Request zoomed-out tiles, e.g. 0/0/0, 2/0/2 and 3/1/4, and decode them.
  3. Compare each tile with the features from /collections/kommuner/items that intersect it (transformed to EPSG:3857).
Tile Should contain Contains Missing
0/0/0 357 5 (765 bytes) all but Balsfjord, Bardu, Karlsøy, Målselv, Tromsø
1/0/1 357 357
2/0/2 66 60 Beiarn, Lurøy, Rana, Rødøy, Saltdal, Træna
3/1/4 66 60 Beiarn, Lurøy, Rana, Rødøy, Saltdal, Træna
4/3/8 53 52 Lurøy
5/6/17, 5/7/17 4, 52 4, 52

The five municipalities in the zoom 0 tile are exactly the five that the line x = 642850 crosses. The ones missing at zoom 2–4 all lie between 66.1°N and 67.2°N, along the southern edge of those tiles (66.5°N).

Expected behavior
Every tile contains all the features that intersect it, at every zoom level, whatever the storage CRS.

Screenshots/Tracebacks
No traceback: the tiles are returned with HTTP 200, just with features missing. In QGIS, the zoom 0 tile draws only the five municipalities above, and the zoom 2 tiles leave a gap along 66.5°N.

Environment

  • OS: Ubuntu 24.04 (the official geopython/pygeoapi:0.24.0 image, which Kartverket's image builds on)
  • Python version: 3.12
  • pygeoapi version: 0.24.0 (the code is the same on master)

Additional context
A possible fix: add points along the envelope's edges before transforming it (e.g. ST_Segmentize), so the transformed polygon follows the tile's real outline. For tiles too large for that (our patch draws the line at 90° wide, so zoom 0–1), or ones the storage CRS can't express, skip the spatial filter. That's still correct, because ST_AsMVTGeom clips every geometry to the tile and returns NULL for those outside it, and ST_AsMVT skips rows with a NULL geometry.

We patch the provider this way in a downstream image, doing the transform in Python with pyproj so out-of-domain tiles can be caught: https://github.com/henrik716/ogc-api-frontend-workshop/blob/main/backend/mvt_postgresql.py

With the same municipalities in EPSG:25833 and the patch, every tile over Norway from zoom 0 to 7 (207 tiles) contains all the features it should, checked the same way as the table above.

Happy to open a PR with this approach (or another you prefer), including a test with data in a projected CRS.

Ngôn ngữ chính
Python
Star
628
Fork
339
Merge trung bình
4 ngày 3 giờ
Pull request đã merge (30 ngày)
11

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của geopython/pygeoapi

Tất cả issue của geopython/pygeoapi

Issue tương tự

Thêm issue về Python

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.