diff --git a/include/geos/algorithm/locate/SimplePointInAreaLocator.h b/include/geos/algorithm/locate/SimplePointInAreaLocator.h index be77ff9d61..11fe95d7d5 100644 --- a/include/geos/algorithm/locate/SimplePointInAreaLocator.h +++ b/include/geos/algorithm/locate/SimplePointInAreaLocator.h @@ -87,6 +87,10 @@ class GEOS_DLL SimplePointInAreaLocator : public PointOnGeometryLocator { static bool isContained(const geom::CoordinateXY& p, const geom::Geometry* geom); + static bool isAnyPointContained(const geom::Geometry& pt, const geom::Geometry& areaGeom); + + static bool isEveryPointContained(const geom::Geometry& pt, const geom::Geometry& areaGeom); + SimplePointInAreaLocator(const geom::Geometry* p_g) : g(p_g) { } diff --git a/src/algorithm/locate/SimplePointInAreaLocator.cpp b/src/algorithm/locate/SimplePointInAreaLocator.cpp index 0a7b8e3437..d0894ec4d9 100644 --- a/src/algorithm/locate/SimplePointInAreaLocator.cpp +++ b/src/algorithm/locate/SimplePointInAreaLocator.cpp @@ -46,6 +46,36 @@ SimplePointInAreaLocator::isContained(const CoordinateXY& p, const Geometry* geo return Location::EXTERIOR != locate(p, geom); } +bool +SimplePointInAreaLocator::isAnyPointContained(const geom::Geometry& pt, const geom::Geometry& area) +{ + if (pt.getNumGeometries() > 1) { + for (size_t i = 0; i < pt.getNumGeometries(); i++ ) { + if (isAnyPointContained(*pt.getGeometryN(i), area)) { + return true; + } + } + return false; + } + + return isContained(*pt.getCoordinate(), &area); +} + +bool +SimplePointInAreaLocator::isEveryPointContained(const geom::Geometry &pt, const geom::Geometry &area) +{ + if (pt.getNumGeometries() > 1) { + for (size_t i = 0; i < pt.getNumGeometries(); i++ ) { + if (!isEveryPointContained(*pt.getGeometryN(i), area)) { + return false; + } + } + return true; + } + + return isContained(*pt.getCoordinate(), &area); +} + geom::Location SimplePointInAreaLocator::locateInGeometry(const CoordinateXY& p, const Geometry* geom) { diff --git a/src/geom/Geometry.cpp b/src/geom/Geometry.cpp index a34c7bf352..ceaba5db69 100644 --- a/src/geom/Geometry.cpp +++ b/src/geom/Geometry.cpp @@ -261,6 +261,10 @@ Geometry::getEnvelope() const bool Geometry::disjoint(const Geometry* g) const { + if (hasCurvedComponents() || g->hasCurvedComponents()) { + return !intersects(g); + } + #if USE_RELATENG return operation::relateng::RelateNG::disjoint(this, g); #else @@ -323,13 +327,13 @@ Geometry::intersects(const Geometry* g) const return predicate::RectangleIntersects::intersects(*p, *this); } - auto typ = getGeometryTypeId(); - if (typ == GEOS_CURVEPOLYGON && g->getGeometryTypeId() == GEOS_POINT) { - auto loc = locate::SimplePointInAreaLocator::locatePointInSurface(*g->getCoordinate(), *detail::down_cast(this)); - return loc != Location::EXTERIOR; - } else if (typ == GEOS_POINT && g->getGeometryTypeId() == GEOS_CURVEPOLYGON) { - auto loc = locate::SimplePointInAreaLocator::locatePointInSurface(*getCoordinate(), *detail::down_cast(g)); - return loc != Location::EXTERIOR; + if (hasCurvedComponents() || g->hasCurvedComponents()) { + if (getDimension() == Dimension::A && g->getDimension() == Dimension::P) { + return locate::SimplePointInAreaLocator::isAnyPointContained(*g, *this); + } + if (g->getDimension() == Dimension::A && getDimension() == Dimension::P) { + return locate::SimplePointInAreaLocator::isAnyPointContained(*this, *g); + } } #if USE_RELATENG @@ -426,6 +430,15 @@ Geometry::within(const Geometry* g) const bool Geometry::contains(const Geometry* g) const { + if (hasCurvedComponents() || g->hasCurvedComponents()) { + if (getDimension() == Dimension::A && g->getDimension() == Dimension::P) { + return locate::SimplePointInAreaLocator::isEveryPointContained(*g, *this); + } + if (g->getDimension() == Dimension::A && getDimension() == Dimension::P) { + return locate::SimplePointInAreaLocator::isEveryPointContained(*this, *g); + } + } + #if USE_RELATENG return operation::relateng::RelateNG::contains(this, g); #else diff --git a/tests/unit/capi/GEOSContainsTest.cpp b/tests/unit/capi/GEOSContainsTest.cpp index 3d377e8295..9d7b2f96a6 100644 --- a/tests/unit/capi/GEOSContainsTest.cpp +++ b/tests/unit/capi/GEOSContainsTest.cpp @@ -201,6 +201,41 @@ void object::test<6>() ensure_equals("curved geometry not supported", GEOSContains(geom1_, geom2_), 2); } +template<> +template<> +void object::test<7>() +{ + set_test_name("Single-point multipoint contained by MultiSurface"); + + geom1_ = fromWKT("MULTISURFACE(POLYGON ((100 100, 200 100, 200 200, 100 100)), CURVEPOLYGON (COMPOUNDCURVE(CIRCULARSTRING(0 0, 1 1, 2 0), (2 0, 0 0))))"); + geom2_ = fromWKT("MULTIPOINT ((0.1556955 0.5355459))"); + + ensure_equals(GEOSContains(geom1_, geom2_), 1); +} + +template<> +template<> +void object::test<8>() +{ + set_test_name("Only 1 part of 2-point MultiPoint contained by MultiSurface"); + + geom1_ = fromWKT("MULTISURFACE(POLYGON ((100 100, 200 100, 200 200, 100 100)), CURVEPOLYGON (COMPOUNDCURVE(CIRCULARSTRING(0 0, 1 1, 2 0), (2 0, 0 0))))"); + geom2_ = fromWKT("MULTIPOINT ((0.1556955 0.5355459), (500 500))"); + + ensure_equals(GEOSContains(geom1_, geom2_), 0); +} + +template<> +template<> +void object::test<9>() +{ + set_test_name("MultiPoint contained by MultiSurface"); + + geom1_ = fromWKT("MULTISURFACE(POLYGON ((100 100, 200 100, 200 200, 100 100)), CURVEPOLYGON (COMPOUNDCURVE(CIRCULARSTRING(0 0, 1 1, 2 0), (2 0, 0 0))))"); + geom2_ = fromWKT("MULTIPOINT ((0.1556955 0.5355459), (199 101))"); + + ensure_equals(GEOSContains(geom1_, geom2_), 1); +} } // namespace tut diff --git a/tests/unit/capi/GEOSDisjointTest.cpp b/tests/unit/capi/GEOSDisjointTest.cpp index f17faca3aa..469b757923 100644 --- a/tests/unit/capi/GEOSDisjointTest.cpp +++ b/tests/unit/capi/GEOSDisjointTest.cpp @@ -42,5 +42,19 @@ void object::test<2>() ensure_equals("curved geometry not supported", GEOSDisjoint(geom2_, geom1_), 2); } +template<> +template<> +void object::test<3>() +{ + set_test_name("MultiSurface / MultiPoint PIP"); + + geom1_ = fromWKT("MULTISURFACE(POLYGON ((100 100, 200 100, 200 200, 100 100)), CURVEPOLYGON (COMPOUNDCURVE(CIRCULARSTRING(0 0, 1 1, 2 0), (2 0, 0 0))))"); + geom2_ = fromWKT("MULTIPOINT ((5000 5000), (0.1556955 0.5355459))"); + + ensure_equals(GEOSDisjoint(geom1_, geom2_), 0); + ensure_equals(GEOSDisjoint(geom2_, geom1_), 0); +} + + } // namespace tut diff --git a/tests/unit/capi/GEOSIntersectsTest.cpp b/tests/unit/capi/GEOSIntersectsTest.cpp index fe11fd70e5..e4f6d12562 100644 --- a/tests/unit/capi/GEOSIntersectsTest.cpp +++ b/tests/unit/capi/GEOSIntersectsTest.cpp @@ -236,8 +236,8 @@ template<> template<> void object::test<12>() { - geom1_ = fromWKT("CURVEPOLYGON (COMPOUNDCURVE(CIRCULARSTRING(0 0, 1 1, 2 0), (2 0, 0 0)))"); - geom2_ = fromWKT("POINT (0.1556955 0.5355459)"); + geom1_ = fromWKT("MULTISURFACE(POLYGON ((100 100, 200 100, 200 200, 100 100)), CURVEPOLYGON (COMPOUNDCURVE(CIRCULARSTRING(0 0, 1 1, 2 0), (2 0, 0 0))))"); + geom2_ = fromWKT("MULTIPOINT ((5000 5000), (0.1556955 0.5355459))"); // PostGIS would return false here because geom2 is inside geom1 // but outside the linearized form of geom1 @@ -256,5 +256,18 @@ void object::test<13>() ensure_equals(GEOSIntersects(geom2_, geom1_), 0); } +template<> +template<> +void object::test<14>() +{ + set_test_name("PostGIS ticket 5832"); + + geom1_ = fromWKT("MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE((25492739.7449 6677441.1816,25492771.1213 6677416.7832),CIRCULARSTRING(25492771.1213 6677416.7832,25492832.3384 6677400.8583,25492885.9851 6677434.3719),(25492885.9851 6677434.3719,25492900.7986 6677455.7498),CIRCULARSTRING(25492900.7986 6677455.7498,25492901.1068 6677457.3233,25492900.1601 6677458.6175,25492822.2626 6677477.2365,25492747.0232 6677449.7828),(25492747.0232 6677449.7828,25492739.7748 6677444.3615),CIRCULARSTRING(25492739.7748 6677444.3615,25492738.9731 6677442.7789,25492739.7449 6677441.1816))))"); + geom2_ = fromWKT("POINT (25492818 6677399.98)"); + + ensure_equals(GEOSIntersects(geom1_, geom2_), 1); + ensure_equals(GEOSIntersects(geom2_, geom1_), 1); +} + } // namespace tut