diff --git a/lib/tdeck_ui/UI/LXMF/MapProjection.cpp b/lib/tdeck_ui/UI/LXMF/MapProjection.cpp index 247a0027..21c5d8ad 100644 --- a/lib/tdeck_ui/UI/LXMF/MapProjection.cpp +++ b/lib/tdeck_ui/UI/LXMF/MapProjection.cpp @@ -76,7 +76,13 @@ double normalizeLongitude(double longitude) { if (!finite(longitude)) { return longitude; } - return wrap(longitude + 180.0, 360.0) - 180.0; + double result = std::fmod(longitude, 360.0); + if (result >= 180.0) { + result -= 360.0; + } else if (result < -180.0) { + result += 360.0; + } + return result; } bool isValidZoom(std::uint32_t zoom) { @@ -195,10 +201,17 @@ Status viewportTiles(const Viewport& viewport, return Status::INVALID_ARGUMENT; } + const double world = worldPixels(zoom); + const double clipped_top = viewport.top < 0.0 ? 0.0 : viewport.top; + const double clipped_bottom = bottom > world ? world : bottom; + if (clipped_top >= clipped_bottom) { + return Status::OK; + } + double first_x_value = std::floor(viewport.left / tile_size); double last_x_value = std::ceil(right / tile_size) - 1.0; - double first_y_value = std::floor(viewport.top / tile_size); - double last_y_value = std::ceil(bottom / tile_size) - 1.0; + double first_y_value = std::floor(clipped_top / tile_size); + double last_y_value = std::ceil(clipped_bottom / tile_size) - 1.0; if (include_border) { first_x_value -= 1.0; last_x_value += 1.0; diff --git a/tests/native/test_map_projection.cpp b/tests/native/test_map_projection.cpp index 71dcc95e..ce87c21d 100644 --- a/tests/native/test_map_projection.cpp +++ b/tests/native/test_map_projection.cpp @@ -60,6 +60,10 @@ void testLongitudeNormalization() { CHECK(near(Pyxis::MapProjection::normalizeLongitude(-540.0), -180.0)); CHECK(near(Pyxis::MapProjection::normalizeLongitude(181.0), -179.0)); CHECK(near(Pyxis::MapProjection::normalizeLongitude(-181.0), 179.0)); + const double east_inside = std::nextafter(180.0, -std::numeric_limits::infinity()); + const double west_outside = std::nextafter(-180.0, -std::numeric_limits::infinity()); + CHECK(Pyxis::MapProjection::normalizeLongitude(east_inside) == east_inside); + CHECK(Pyxis::MapProjection::normalizeLongitude(west_outside) == east_inside); } void testEquatorPrimeMeridian() { @@ -134,6 +138,19 @@ void testExactViewportEdgesAreExclusive() { CHECK(tiles[0].tile.y == 1U); CHECK(near(tiles[0].screen_x, 0.0)); CHECK(near(tiles[0].screen_y, 0.0)); + + tiles[0].tile.x = 77U; + CHECK(Pyxis::MapProjection::viewportTiles(Viewport{0.0, -256.0, 256U, 256U}, 2U, false, tiles, + Pyxis::MapProjection::MAX_VIEWPORT_TILES, count) == Status::OK); + CHECK(count == 0U); + CHECK(tiles[0].tile.x == 77U); + CHECK(Pyxis::MapProjection::viewportTiles(Viewport{0.0, 1024.0, 256U, 256U}, 2U, false, tiles, + Pyxis::MapProjection::MAX_VIEWPORT_TILES, count) == Status::OK); + CHECK(count == 0U); + CHECK(tiles[0].tile.x == 77U); + CHECK(Pyxis::MapProjection::viewportTiles(Viewport{0.0, -1024.0, 256U, 100U}, 2U, true, tiles, + Pyxis::MapProjection::MAX_VIEWPORT_TILES, count) == Status::OK); + CHECK(count == 0U); } void testViewportTwoToThreeTileTransition() {