From c02bb5b46fe48506b8edf0a794ae8c9bb3f2cea3 Mon Sep 17 00:00:00 2001 From: Paul Ramsey Date: Tue, 20 Aug 2024 10:48:39 -0700 Subject: [PATCH] Add RelateNGBoundarNodeRuleTest, with test 4 commented out --- include/geos/algorithm/BoundaryNodeRule.h | 4 + src/algorithm/BoundaryNodeRule.cpp | 20 +- .../relateng/RelateNGBoundaryNodeRuleTest.cpp | 186 ++++++++++++++++++ 3 files changed, 208 insertions(+), 2 deletions(-) create mode 100644 tests/unit/operation/relateng/RelateNGBoundaryNodeRuleTest.cpp diff --git a/include/geos/algorithm/BoundaryNodeRule.h b/include/geos/algorithm/BoundaryNodeRule.h index 07c38265f5..19cd6e111d 100644 --- a/include/geos/algorithm/BoundaryNodeRule.h +++ b/include/geos/algorithm/BoundaryNodeRule.h @@ -18,6 +18,8 @@ #pragma once +#include + #include // Forward declarations @@ -55,6 +57,8 @@ class GEOS_DLL BoundaryNodeRule { virtual ~BoundaryNodeRule() {} + virtual std::string toString() const = 0; + /** \brief * Tests whether a point that lies in `boundaryCount` * geometry component boundaries is considered to form part of diff --git a/src/algorithm/BoundaryNodeRule.cpp b/src/algorithm/BoundaryNodeRule.cpp index c7417b9d55..393ca5e877 100644 --- a/src/algorithm/BoundaryNodeRule.cpp +++ b/src/algorithm/BoundaryNodeRule.cpp @@ -48,7 +48,11 @@ class Mod2BoundaryNodeRule : public BoundaryNodeRule { { // the "Mod-2 Rule" return boundaryCount % 2 == 1; - } + }; + std::string + toString() const override { + return "Mod2BoundaryNodeRule"; + }; }; @@ -84,7 +88,11 @@ class EndPointBoundaryNodeRule : public BoundaryNodeRule { isInBoundary(int boundaryCount) const override { return boundaryCount > 0; - } + }; + std::string + toString() const override { + return "EndPointBoundaryNodeRule"; + }; }; /** @@ -103,6 +111,10 @@ class MultiValentEndPointBoundaryNodeRule : public BoundaryNodeRule { { return boundaryCount > 1; } + std::string + toString() const override { + return "MultiValentEndPointBoundaryNodeRule"; + }; }; /** @@ -120,6 +132,10 @@ class MonoValentEndPointBoundaryNodeRule : public BoundaryNodeRule { { return boundaryCount == 1; } + std::string + toString() const override { + return "MonoValentEndPointBoundaryNodeRule"; + }; }; Mod2BoundaryNodeRule mod2Rule; diff --git a/tests/unit/operation/relateng/RelateNGBoundaryNodeRuleTest.cpp b/tests/unit/operation/relateng/RelateNGBoundaryNodeRuleTest.cpp new file mode 100644 index 0000000000..8dc30b88ca --- /dev/null +++ b/tests/unit/operation/relateng/RelateNGBoundaryNodeRuleTest.cpp @@ -0,0 +1,186 @@ +// +// Test Suite for geos::operation::relateng Boundary Node Rules + +#include +#include + +// geos +#include +#include +#include +#include +#include +#include +#include + +// std +#include + +using namespace geos::geom; +using namespace geos::operation::relateng; +using geos::io::WKTReader; +using geos::io::WKTWriter; + +namespace tut { +// +// Test Group +// + +// Common data used by all tests +struct test_relatengbnr_data { + + WKTReader r; + WKTWriter w; + + void runRelate( + const std::string& wkt1, + const std::string& wkt2, + const BoundaryNodeRule& bnRule, + const std::string& expectedIM) + { + std::unique_ptr g1 = r.read(wkt1); + std::unique_ptr g2 = r.read(wkt2); + auto im = RelateNG::relate(g1.get(), g2.get(), bnRule); + std::string imStr = im->toString(); + //System.out.println(imStr); + if (imStr != expectedIM) { + std::cerr << std::endl << w.write(*g1) << " relate " << bnRule.toString() << " " << w.write(*g2) << " = " << imStr << std::endl; + } + ensure_equals("runRelate", imStr, expectedIM); + } + + +}; + +typedef test_group group; +typedef group::object object; + +group test_relatengbnr_group("geos::operation::relateng::RelateNGBoundarNodeRule"); + +// BoundaryNodeRule::getBoundaryRuleMod2() +// BoundaryNodeRule::getBoundaryEndPoint() +// BoundaryNodeRule::getBoundaryMultivalentEndPoint() +// BoundaryNodeRule::getBoundaryMonovalentEndPoint() +// BoundaryNodeRule::getBoundaryOGCSFS() + + +// testMultiLineStringSelfIntTouchAtEndpoint +template<> +template<> +void object::test<1> () +{ + std::string a = "MULTILINESTRING ((20 20, 100 100, 100 20, 20 100), (60 60, 60 140))"; + std::string b = "LINESTRING (60 60, 20 60)"; + + // under EndPoint, A has a boundary node - A.bdy / B.bdy = 0 + runRelate(a, b, BoundaryNodeRule::getBoundaryEndPoint(), "FF1F00102"); +} + +// testLineStringSelfIntTouchAtEndpoint +template<> +template<> +void object::test<2> () +{ + std::string a = "LINESTRING (20 20, 100 100, 100 20, 20 100)"; + std::string b = "LINESTRING (60 60, 20 60)"; + + // results for both rules are the same + runRelate(a, b, BoundaryNodeRule::getBoundaryOGCSFS(), "F01FF0102"); + runRelate(a, b, BoundaryNodeRule::getBoundaryEndPoint(), "F01FF0102"); +} + +// testMultiLineStringTouchAtEndpoint +template<> +template<> +void object::test<3> () +{ + std::string a = "MULTILINESTRING ((0 0, 10 10), (10 10, 20 20))"; + std::string b = "LINESTRING (10 10, 20 0)"; + + // under Mod2, A has no boundary - A.int / B.bdy = 0 + // runRelateTest(a, b, BoundaryNodeRule.OGC_SFS_BOUNDARY_RULE, "F01FFF102"); + // under EndPoint, A has a boundary node - A.bdy / B.bdy = 0 + runRelate(a, b, BoundaryNodeRule::getBoundaryEndPoint(), "FF1F00102"); + // under MultiValent, A has a boundary node but B does not - A.bdy / B.bdy = F and A.int + // runRelateTest(a, b, BoundaryNodeRule.MULTIVALENT_ENDPOINT_BOUNDARY_RULE, "0F1FFF1F2"); +} + +// testLineRingTouchAtEndpoints +// template<> +// template<> +// void object::test<4> () +// { +// std::string a = "LINESTRING (20 100, 20 220, 120 100, 20 100)"; +// std::string b = "LINESTRING (20 20, 20 100)"; + +// // under Mod2, A has no boundary - A.int / B.bdy = 0 +// runRelate(a, b, BoundaryNodeRule::getBoundaryOGCSFS(), "F01FFF102"); +// // under EndPoint, A has a boundary node - A.bdy / B.bdy = 0 +// runRelate(a, b, BoundaryNodeRule::getBoundaryEndPoint(), "FF1F0F102"); +// // under MultiValent, A has a boundary node but B does not - A.bdy / B.bdy = F and A.int +// runRelate(a, b, BoundaryNodeRule::getBoundaryMonovalentEndPoint(), "FF10FF1F2"); +// } + +// testLineRingTouchAtEndpointAndInterior +template<> +template<> +void object::test<5> () +{ + std::string a = "LINESTRING (20 100, 20 220, 120 100, 20 100)"; + std::string b = "LINESTRING (20 20, 40 100)"; + + // this is the same result as for the above test + runRelate(a, b, BoundaryNodeRule::getBoundaryOGCSFS(), "F01FFF102"); + // this result is different - the A node is now on the boundary, so A.bdy/B.ext = 0 + runRelate(a, b, BoundaryNodeRule::getBoundaryEndPoint(), "F01FF0102"); +} + +// testPolygonEmptyRing +template<> +template<> +void object::test<6> () +{ + std::string a = "POLYGON EMPTY"; + std::string b = "LINESTRING (20 100, 20 220, 120 100, 20 100)"; + + // closed line has no boundary under SFS rule + runRelate(a, b, BoundaryNodeRule::getBoundaryOGCSFS(), "FFFFFF1F2"); + + // closed line has boundary under ENDPOINT rule + runRelate(a, b, BoundaryNodeRule::getBoundaryEndPoint(), "FFFFFF102"); +} + +// testPolygonEmptyMultiLineStringClosed +template<> +template<> +void object::test<7> () +{ + std::string a = "POLYGON EMPTY"; + std::string b = "MULTILINESTRING ((0 0, 0 1), (0 1, 1 1, 1 0, 0 0))"; + + // closed line has no boundary under SFS rule + runRelate(a, b, BoundaryNodeRule::getBoundaryOGCSFS(), "FFFFFF1F2"); + + // closed line has boundary under ENDPOINT rule + runRelate(a, b, BoundaryNodeRule::getBoundaryEndPoint(), "FFFFFF102"); +} + +// testLineStringInteriorTouchMultivalent +template<> +template<> +void object::test<8> () +{ + std::string a = "POLYGON EMPTY"; + std::string b = "MULTILINESTRING ((0 0, 0 1), (0 1, 1 1, 1 0, 0 0))"; + + // closed line has no boundary under SFS rule + runRelate(a, b, BoundaryNodeRule::getBoundaryOGCSFS(), "FFFFFF1F2"); + + // closed line has boundary under ENDPOINT rule + runRelate(a, b, BoundaryNodeRule::getBoundaryEndPoint(), "FFFFFF102"); +} + + + + +} // namespace tut