Skip to content

Commit 13af586

Browse files
authored
Merge pull request #2143 from joto/fix-expire-off-by-one
Fix off-by-one error in expire code generating out of bounds tiles
2 parents d58a6c4 + 76ba82c commit 13af586

File tree

3 files changed

+105
-4
lines changed

3 files changed

+105
-4
lines changed

src/expire-tiles.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -243,15 +243,15 @@ int expire_tiles::from_bbox(geom::box_t const &box,
243243
/* Convert the box's Mercator coordinates into tile coordinates */
244244
auto const tmp_min = coords_to_tile({box.min_x(), box.max_y()});
245245
int const min_tile_x =
246-
std::clamp(int(tmp_min.x() - expire_config.buffer), 0, m_map_width);
246+
std::clamp(int(tmp_min.x() - expire_config.buffer), 0, m_map_width - 1);
247247
int const min_tile_y =
248-
std::clamp(int(tmp_min.y() - expire_config.buffer), 0, m_map_width);
248+
std::clamp(int(tmp_min.y() - expire_config.buffer), 0, m_map_width - 1);
249249

250250
auto const tmp_max = coords_to_tile({box.max_x(), box.min_y()});
251251
int const max_tile_x =
252-
std::clamp(int(tmp_max.x() + expire_config.buffer), 0, m_map_width);
252+
std::clamp(int(tmp_max.x() + expire_config.buffer), 0, m_map_width - 1);
253253
int const max_tile_y =
254-
std::clamp(int(tmp_max.y() + expire_config.buffer), 0, m_map_width);
254+
std::clamp(int(tmp_max.y() + expire_config.buffer), 0, m_map_width - 1);
255255

256256
for (int iterator_x = min_tile_x; iterator_x <= max_tile_x; ++iterator_x) {
257257
uint32_t const norm_x = normalise_tile_x_coord(iterator_x);

tests/test-expire-tiles.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,70 @@ TEST_CASE("simple expire z18", "[NoDB]")
144144
CHECK(*(itr++) == tile_t(18, 131072, 131072));
145145
}
146146

147+
TEST_CASE("simple expire z10 bounds 0, 0", "[NoDB]")
148+
{
149+
uint32_t const minzoom = 10;
150+
uint32_t const maxzoom = 10;
151+
expire_tiles et{minzoom, defproj};
152+
153+
et.from_geometry(geom::point_t{-20037508.34, 20037508.34},
154+
expire_config_t{});
155+
156+
auto const tiles = get_tiles_ordered(&et, minzoom, maxzoom);
157+
CHECK(tiles.size() == 1);
158+
159+
auto itr = tiles.begin();
160+
CHECK(*(itr++) == tile_t(10, 0, 0));
161+
}
162+
163+
TEST_CASE("simple expire z10 bounds 0, 1023", "[NoDB]")
164+
{
165+
uint32_t const minzoom = 10;
166+
uint32_t const maxzoom = 10;
167+
expire_tiles et{minzoom, defproj};
168+
169+
et.from_geometry(geom::point_t{-20037508.34, -20037508.34},
170+
expire_config_t{});
171+
172+
auto const tiles = get_tiles_ordered(&et, minzoom, maxzoom);
173+
CHECK(tiles.size() == 1);
174+
175+
auto itr = tiles.begin();
176+
CHECK(*(itr++) == tile_t(10, 0, 1023));
177+
}
178+
179+
TEST_CASE("simple expire z10 bounds 1023, 0", "[NoDB]")
180+
{
181+
uint32_t const minzoom = 10;
182+
uint32_t const maxzoom = 10;
183+
expire_tiles et{minzoom, defproj};
184+
185+
et.from_geometry(geom::point_t{20037508.34, 20037508.34},
186+
expire_config_t{});
187+
188+
auto const tiles = get_tiles_ordered(&et, minzoom, maxzoom);
189+
CHECK(tiles.size() == 1);
190+
191+
auto itr = tiles.begin();
192+
CHECK(*(itr++) == tile_t(10, 1023, 0));
193+
}
194+
195+
TEST_CASE("simple expire z10 bounds 1023, 1023", "[NoDB]")
196+
{
197+
uint32_t const minzoom = 10;
198+
uint32_t const maxzoom = 10;
199+
expire_tiles et{minzoom, defproj};
200+
201+
et.from_geometry(geom::point_t{20037508.34, -20037508.34},
202+
expire_config_t{});
203+
204+
auto const tiles = get_tiles_ordered(&et, minzoom, maxzoom);
205+
CHECK(tiles.size() == 1);
206+
207+
auto itr = tiles.begin();
208+
CHECK(*(itr++) == tile_t(10, 1023, 1023));
209+
}
210+
147211
TEST_CASE("expire a simple line", "[NoDB]")
148212
{
149213
uint32_t const zoom = 18;

tests/test-reprojection.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,43 @@ TEST_CASE("projection 3857", "[NoDB]")
4747
REQUIRE(ct.y() == Approx(6982997.92));
4848
}
4949

50+
TEST_CASE("projection 3857 bounds", "[NoDB]")
51+
{
52+
osmium::Location const loc1{0.0, 0.0};
53+
osmium::Location const loc2{-180.0, -85.0511288};
54+
osmium::Location const loc3{180.0, 85.0511288};
55+
int const srs = 3857;
56+
auto const reprojection = reprojection::create_projection(srs);
57+
58+
{
59+
auto const c = reprojection->reproject(geom::point_t{loc1});
60+
REQUIRE(c.x() == Approx(0.0));
61+
REQUIRE(c.y() == Approx(0.0));
62+
63+
auto const ct = reprojection->target_to_tile(c);
64+
REQUIRE(ct.x() == Approx(0.0));
65+
REQUIRE(ct.y() == Approx(0.0));
66+
}
67+
{
68+
auto const c = reprojection->reproject(geom::point_t{loc2});
69+
REQUIRE(c.x() == Approx(-20037508.34));
70+
REQUIRE(c.y() == Approx(-20037508.34));
71+
72+
auto const ct = reprojection->target_to_tile(c);
73+
REQUIRE(ct.x() == Approx(-20037508.34));
74+
REQUIRE(ct.y() == Approx(-20037508.34));
75+
}
76+
{
77+
auto const c = reprojection->reproject(geom::point_t{loc3});
78+
REQUIRE(c.x() == Approx(20037508.34));
79+
REQUIRE(c.y() == Approx(20037508.34));
80+
81+
auto const ct = reprojection->target_to_tile(c);
82+
REQUIRE(ct.x() == Approx(20037508.34));
83+
REQUIRE(ct.y() == Approx(20037508.34));
84+
}
85+
}
86+
5087
#ifdef HAVE_GENERIC_PROJ
5188
TEST_CASE("projection 5651", "[NoDB]")
5289
{

0 commit comments

Comments
 (0)