`render_list --all` with a lon/lat bbox silently skips metatiles at the range edges
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 2/5
- Thời gian dự kiến
- 1-3 giờ
- Mức phù hợp với người mới
- 76/100
Hướng nghiên cứu
Bắt đầu với các phép tính phạm vi bounding box và các vòng lặp render trong src/render_list.c, đặc biệt là hai nguyên nhân được mô tả trong issue. Chạy lệnh render_list được cung cấp và so sánh các metatile được đưa vào hàng đợi với các metatile riêng biệt cần thiết để bao phủ từng phạm vi zoom. Công việc được xem là hoàn tất khi bounding box được yêu cầu được bao phủ đầy đủ, bao gồm cả các khối ở rìa, mà không có metatile nào bị âm thầm bỏ qua.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Summary
When render_list --all is given --min-lon/--max-lon/--min-lat/--max-lat, it enqueues fewer
metatiles than the bounding box covers. Tiles in the skipped blocks are never rendered, and
render_list exits 0 with no warning.
On one real run over the continental USA at z0-8 it enqueued 32 metatiles where the box needs
41 — a 22% shortfall, concentrated at the south and east edges of the box.
Two independent causes, both in the same block of src/render_list.c. They are separable; the
first accounts for most of the loss.
Version: 0.8.0 (also reproduced by inspection in v0.8.1 and master — the relevant lines
are unchanged).
Cause 1 — the render loop starts at an unaligned coordinate
for (x = min_x; x <= current_max_x; x += METATILE) {
for (y = min_y; y <= current_max_y; y += METATILE) {
src/render_list.c, v0.8.0 lines 468-469 / master lines 469-470
min_x and min_y come straight from lon2tilex() / lat2tiley() and are arbitrary tile
coordinates, not metatile-aligned. enqueue() is then called with them, and the coordinate is
rounded down to the containing metatile downstream — which is why rendering works at all, and why
the problem is invisible rather than an error.
Because the walk starts unaligned, stepping by METATILE can step past the final block. The loop
runs floor((max - min) / METATILE) + 1 times, but the box spans
floor((max - align(min)) / METATILE) + 1 blocks. When min % METATILE is large enough that the
remainder crosses a boundary, the last row or column is never enqueued.
Worked example, z8, y axis, min_y = 87, max_y = 110:
iterations: 87, 95, 103 (111 > 110, stop)
blocks hit: 80, 88, 96
blocks needed: 80, 88, 96, 104 <-- 104 covers rows 104-110, never enqueued
Suggested fix
for (x = min_x - (min_x % METATILE); x <= current_max_x; x += METATILE) {
for (y = min_y - (min_y % METATILE); y <= current_max_y; y += METATILE) {
Both values are non-negative here, so % is well defined. This only ever adds the partial edge
blocks; no currently-rendered tile changes.
Cause 2 — current_max_x is decremented but current_max_y is not
current_max_x = max_x_tmp ? max_x_tmp - 1 : max_x_tmp;
current_max_y = max_y_tmp;
src/render_list.c, v0.8.0 lines 460-461 / master lines 461-462
With lon2tilex() defined as floor((lon + 180) / 360 * 2^z), max_x_tmp is the tile containing
max_lon, so it is part of the box and the - 1 drops it. The decrement is only correct in the
special case where max_lon falls exactly on a tile boundary. The latitude axis gets no equivalent
adjustment, so the two axes disagree about whether the maximum is inclusive.
Worked example, z8, max_lon = -66.9:
lon2tilex(-66.9, 8) = floor(80.42) = 80 tile 80 spans lon [-67.5, -66.09], contains -66.9
current_max_x = 79 tile column 80 excluded
Suggested fix
current_max_x = max_x_tmp;, matching the y axis. Where max_lon does sit exactly on a boundary
this renders one extra column, which seems clearly preferable to dropping a needed one — and it
makes the two axes consistent.
Reproduction
render_list --all --map default --num-threads 4 \
--min-zoom 0 --max-zoom 8 \
--min-lon -125.0 --max-lon -66.9 --min-lat 24.4 --max-lat 49.4
render_list's own log lines give the declared ranges. "Blocks needed" is the count of distinct
metatiles covering that range; "enqueued" is what the loop above produces:
| zoom | declared range | blocks needed | enqueued | short |
|---|---|---|---|---|
| 0 | (0, 0) → (0, 0) | 1 | 1 | — |
| 1 | (0, 0) → (0, 0) | 1 | 1 | — |
| 2 | (0, 1) → (0, 1) | 1 | 1 | — |
| 3 | (1, 2) → (1, 3) | 1 | 1 | — |
| 4 | (2, 5) → (4, 6) | 1 | 1 | — |
| 5 | (4, 10) → (9, 13) | 2 | 1 | 1 |
| 6 | (9, 21) → (19, 27) | 4 | 2 | 2 |
| 7 | (19, 43) → (39, 55) | 6 | 6 | — |
| 8 | (39, 87) → (79, 110) | 24 | 18 | 6 |
| 41 | 32 | 9 |
render_list then reports:
** Message: Metatiles rendered:
** Message: 32 in 2314.60 seconds (0.01/s)
The enqueued column is not measured — it is what Cause 1 predicts — and it matches the reported
total of 32 exactly, as well as the per-zoom request counts in the timing summary. Counting .meta
files on disk afterwards confirms the same gaps.
z7 is unaffected because its remainders happen not to cross a block boundary; that is luck, not
correctness.
Note the table understates the total loss, because the declared ranges it is computed from are
themselves already clipped by Cause 2 — the z8 row is missing column 80 before the loop even runs.
Impact
The skipped blocks lie along the edges of the requested box, so a pre-render pass appears to
succeed while leaving holes exactly where a user panning to the edge of their region will land.
With ModTileMissingRequestTimeout set, those requests return 404 while the render is queued, so
the gap surfaces as intermittent missing tiles well after the pre-render was declared complete.
- Ngôn ngữ chính
- C++
- Star
- 318
- Fork
- 200
- Merge trung bình
- 3 ngày 18 giờ
- Pull request đã merge (30 ngày)
- 35
Chuẩn bị môi trường
Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- 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.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của openstreetmap/mod_tile
-
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 65/100
openstreetmap/mod_tile#292 · 4 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 35/100
openstreetmap/mod_tile#477 · 7 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 45/100
openstreetmap/mod_tile#466 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 35/100
openstreetmap/mod_tile#462 · 7 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 30/100
openstreetmap/mod_tile#447 · 3 bình luận · 1 reaction ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của openstreetmap/mod_tile
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 80/100
-
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 82/100
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
eclipse-score/lifecycle#929 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
colbymchenry/codegraph#3223 ·
Maintainer thường phản hồi trong vòng 1 ngày