Skip to content

Commit

Permalink
Merge pull request #4237 from rouault/fix_4236
Browse files Browse the repository at this point in the history
GeographicBoundingBox::create(): accept degenerate bounding box reduced to a point or a line
  • Loading branch information
rouault authored Aug 27, 2024
2 parents 58fca6d + 903cfff commit 298f7f6
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 16 deletions.
21 changes: 18 additions & 3 deletions src/apps/cs2cs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <string.h>

#include <cassert>
#include <cmath>
#include <cstdint>
#include <iostream>
#include <string>
Expand Down Expand Up @@ -448,9 +449,23 @@ int main(int argc, char **argv) {
std::exit(1);
}
try {
bboxFilter = Extent::createFromBBOX(
c_locale_stod(bbox[0]), c_locale_stod(bbox[1]),
c_locale_stod(bbox[2]), c_locale_stod(bbox[3]))
std::vector<double> bboxValues = {
c_locale_stod(bbox[0]), c_locale_stod(bbox[1]),
c_locale_stod(bbox[2]), c_locale_stod(bbox[3])};
const double west = bboxValues[0];
const double south = bboxValues[1];
const double east = bboxValues[2];
const double north = bboxValues[3];
constexpr double SOME_MARGIN = 10;
if (south < -90 - SOME_MARGIN && std::fabs(west) <= 90 &&
std::fabs(east) <= 90)
std::cerr << "Warning: suspicious south latitude: " << south
<< std::endl;
if (north > 90 + SOME_MARGIN && std::fabs(west) <= 90 &&
std::fabs(east) <= 90)
std::cerr << "Warning: suspicious north latitude: " << north
<< std::endl;
bboxFilter = Extent::createFromBBOX(west, south, east, north)
.as_nullable();
} catch (const std::exception &e) {
std::cerr << "Invalid value for option --bbox: " << bboxStr
Expand Down
19 changes: 16 additions & 3 deletions src/apps/projinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#define FROM_PROJ_CPP

#include <cmath>
#include <cstdlib>
#include <fstream> // std::ifstream
#include <iostream>
Expand Down Expand Up @@ -187,9 +188,21 @@ static ExtentPtr makeBboxFilter(DatabaseContextPtr dbContext,
std::vector<double> bboxValues = {
c_locale_stod(bbox[0]), c_locale_stod(bbox[1]),
c_locale_stod(bbox[2]), c_locale_stod(bbox[3])};
bboxFilter = Extent::createFromBBOX(bboxValues[0], bboxValues[1],
bboxValues[2], bboxValues[3])
.as_nullable();
const double west = bboxValues[0];
const double south = bboxValues[1];
const double east = bboxValues[2];
const double north = bboxValues[3];
constexpr double SOME_MARGIN = 10;
if (south < -90 - SOME_MARGIN && std::fabs(west) <= 90 &&
std::fabs(east) <= 90)
std::cerr << "Warning: suspicious south latitude: " << south
<< std::endl;
if (north > 90 + SOME_MARGIN && std::fabs(west) <= 90 &&
std::fabs(east) <= 90)
std::cerr << "Warning: suspicious north latitude: " << north
<< std::endl;
bboxFilter =
Extent::createFromBBOX(west, south, east, north).as_nullable();
} catch (const std::exception &e) {
std::cerr << "Invalid value for option --bbox: " << bboxStr << ", "
<< e.what() << std::endl;
Expand Down
21 changes: 21 additions & 0 deletions src/iso19111/metadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,27 @@ GeographicBoundingBoxNNPtr GeographicBoundingBox::create(double west,
throw InvalidValueTypeException(
"GeographicBoundingBox::create() does not accept NaN values");
}
if (south > north) {
throw InvalidValueTypeException(
"GeographicBoundingBox::create() does not accept south > north");
}
// Avoid creating a degenerate bounding box if reduced to a point or a line
if (west == east) {
if (west > -180)
west =
std::nextafter(west, -std::numeric_limits<double>::infinity());
if (east < 180)
east =
std::nextafter(east, std::numeric_limits<double>::infinity());
}
if (south == north) {
if (south > -90)
south =
std::nextafter(south, -std::numeric_limits<double>::infinity());
if (north < 90)
north =
std::nextafter(north, std::numeric_limits<double>::infinity());
}
return GeographicBoundingBox::nn_make_shared<GeographicBoundingBox>(
west, south, east, north);
}
Expand Down
74 changes: 64 additions & 10 deletions test/unit/test_metadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,16 +284,6 @@ TEST(metadata, extent_edge_cases) {
optional<std::string>(), std::vector<GeographicExtentNNPtr>(),
std::vector<VerticalExtentNNPtr>(), std::vector<TemporalExtentNNPtr>());

{
auto A = Extent::createFromBBOX(-180, -90, 180, 90);
auto B = Extent::createFromBBOX(180, -90, 180, 90);
EXPECT_FALSE(A->intersects(B));
EXPECT_FALSE(B->intersects(A));
EXPECT_FALSE(A->contains(B));
EXPECT_TRUE(A->intersection(B) == nullptr);
EXPECT_TRUE(B->intersection(A) == nullptr);
}

EXPECT_THROW(Extent::createFromBBOX(
std::numeric_limits<double>::quiet_NaN(), -90, 180, 90),
InvalidValueTypeException);
Expand All @@ -307,6 +297,10 @@ TEST(metadata, extent_edge_cases) {
-180, -90, 180, std::numeric_limits<double>::quiet_NaN()),
InvalidValueTypeException);

// South > north
EXPECT_THROW(Extent::createFromBBOX(-100, 10, 100, 0),
InvalidValueTypeException);

// Scenario of https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=57328
// and https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=60084
{
Expand All @@ -325,6 +319,66 @@ TEST(metadata, extent_edge_cases) {
EXPECT_TRUE(A->intersection(B) == nullptr);
EXPECT_TRUE(B->intersection(A) == nullptr);
}

// Test degenerate bounding box on a point
{
auto A = Extent::createFromBBOX(1, 2, 1, 2);
auto B = Extent::createFromBBOX(-10, -10, 10, 10);
EXPECT_TRUE(A->intersects(B));
EXPECT_TRUE(B->intersects(A));
EXPECT_FALSE(A->contains(B));
EXPECT_TRUE(B->contains(A));
EXPECT_TRUE(A->intersection(B) != nullptr);
EXPECT_TRUE(B->intersection(A) != nullptr);
}

// Test degenerate bounding box on a line at long=-180
{
auto A = Extent::createFromBBOX(-180, 2, -180, 3);
auto B = Extent::createFromBBOX(-180, -90, 180, 90);
EXPECT_TRUE(A->intersects(B));
EXPECT_TRUE(B->intersects(A));
EXPECT_FALSE(A->contains(B));
EXPECT_TRUE(B->contains(A));
EXPECT_TRUE(A->intersection(B) != nullptr);
EXPECT_TRUE(B->intersection(A) != nullptr);
}

// Test degenerate bounding box on a line at long=180
{
auto A = Extent::createFromBBOX(180, 2, 180, 3);
auto B = Extent::createFromBBOX(-180, -90, 180, 90);
EXPECT_TRUE(A->intersects(B));
EXPECT_TRUE(B->intersects(A));
EXPECT_FALSE(A->contains(B));
EXPECT_TRUE(B->contains(A));
EXPECT_TRUE(A->intersection(B) != nullptr);
EXPECT_TRUE(B->intersection(A) != nullptr);
}

// Test degenerate bounding box on a line at lat=90
{
auto A = Extent::createFromBBOX(2, 90, 3, 90);
auto B = Extent::createFromBBOX(-180, -90, 180, 90);
EXPECT_TRUE(A->intersects(B));
EXPECT_TRUE(B->intersects(A));
EXPECT_FALSE(A->contains(B));
EXPECT_TRUE(B->contains(A));
EXPECT_TRUE(A->intersection(B) != nullptr);
EXPECT_TRUE(B->intersection(A) != nullptr);
}

// Test degenerate bounding box on a line at lat=-90
{
auto A = Extent::createFromBBOX(2, -90, 3, -90);
auto B = Extent::createFromBBOX(-180, -90, 180, 90);
EXPECT_TRUE(A->intersects(B));
EXPECT_TRUE(B->intersects(A));
EXPECT_FALSE(A->contains(B));
EXPECT_TRUE(B->contains(A));
EXPECT_TRUE(A->intersection(B) != nullptr);
EXPECT_TRUE(B->intersection(A) != nullptr);
}
}

// ---------------------------------------------------------------------------
Expand Down

0 comments on commit 298f7f6

Please sign in to comment.