diff --git a/Makefile.am b/Makefile.am index 9b835e50e..7cd3ffbb9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -96,7 +96,7 @@ common_tests_SOURCES = common.hpp common.cpp common_tests.cpp boost_unit_test.cp backtrack_tests_SOURCES = backtrack.hpp backtrack.cpp backtrack_tests.cpp boost_unit_test.cpp bg_helpers.hpp bg_helpers.cpp eulerian_paths.hpp eulerian_paths.cpp segmentize.hpp segmentize.cpp merge_near_points.hpp merge_near_points.cpp bg_operators.hpp bg_operators.cpp geos_helpers.hpp geos_helpers.cpp trim_paths_tests_SOURCES = trim_paths.hpp trim_paths.cpp trim_paths_tests.cpp boost_unit_test.cpp bg_helpers.hpp bg_helpers.cpp eulerian_paths.hpp eulerian_paths.cpp segmentize.hpp segmentize.cpp merge_near_points.hpp merge_near_points.cpp bg_operators.hpp bg_operators.cpp geos_helpers.hpp geos_helpers.cpp outline_bridges_tests_SOURCES = outline_bridges_tests.cpp outline_bridges.hpp outline_bridges.cpp bg_operators.hpp bg_operators.cpp bg_helpers.hpp bg_helpers.cpp eulerian_paths.hpp eulerian_paths.cpp segmentize.hpp segmentize.cpp boost_unit_test.cpp merge_near_points.hpp merge_near_points.cpp geos_helpers.hpp geos_helpers.cpp -geos_helpers_tests_SOURCES = geos_helpers_tests.cpp geos_helpers.cpp geos_helpers.hpp boost_unit_test.cpp +geos_helpers_tests_SOURCES = geos_helpers_tests.cpp geos_helpers.cpp geos_helpers.hpp boost_unit_test.cpp bg_operators.cpp bg_helpers.cpp eulerian_paths.cpp segmentize.cpp merge_near_points.cpp TESTS = $(check_PROGRAMS) diff --git a/bg_operators.cpp b/bg_operators.cpp index 56770d103..2d6687087 100644 --- a/bg_operators.cpp +++ b/bg_operators.cpp @@ -25,6 +25,7 @@ bg::model::multi_polygon operator-( } template multi_polygon_type_fp operator-(const multi_polygon_type_fp&, const multi_polygon_type_fp&); +template multi_polygon_type_fp operator-(const multi_polygon_type_fp&, const box_type_fp&); template multi_polygon_type_fp operator-(const box_type_fp& lhs, const rhs_t& rhs) { diff --git a/geos_helpers.cpp b/geos_helpers.cpp index 0a28ff7b7..af2cb3220 100644 --- a/geos_helpers.cpp +++ b/geos_helpers.cpp @@ -74,12 +74,12 @@ multi_linestring_type_fp from_geos(const std::unique_ptr multi_polygon_type_fp from_geos(const std::unique_ptr& g) { - auto mp = boost::dynamic_pointer_cast(g->clone()); - if (mp) { + if (dynamic_cast(g.get())) { + auto mp = boost::dynamic_pointer_cast(g->clone()); return from_geos(mp); } + if (dynamic_cast(g.get())) { auto p = boost::dynamic_pointer_cast(g->clone()); - if (p) { return multi_polygon_type_fp{from_geos(p)}; } geos::io::WKTWriter writer; diff --git a/geos_helpers_tests.cpp b/geos_helpers_tests.cpp index 5c97feb89..9999078ce 100644 --- a/geos_helpers_tests.cpp +++ b/geos_helpers_tests.cpp @@ -7,30 +7,91 @@ #ifdef GEOS_VERSION #include #endif // GEOS_VERSION +#include BOOST_AUTO_TEST_SUITE(geos_helpers_tests) -// Confirm that both geos and boost support clockwise rings. -BOOST_AUTO_TEST_CASE(direction) { +BOOST_AUTO_TEST_SUITE(boost_geometry) + +// Holes are counter-clockwise +BOOST_AUTO_TEST_CASE(polygon_with_holes_direction) { auto box = bg::return_envelope(point_type_fp(0,0)); bg::expand(box, point_type_fp(10,10)); - polygon_type_fp poly; - bg::convert(box, poly); - BOOST_CHECK_EQUAL(poly.outer()[1], point_type_fp(0,10)); - bg::reverse(poly); - bg::correct(poly); - BOOST_CHECK_EQUAL(poly.outer()[1], point_type_fp(0,10)); + auto hole = bg::return_envelope(point_type_fp(3,3)); + bg::expand(hole, point_type_fp(7,7)); + multi_polygon_type_fp mpoly; + bg::convert(box, mpoly); + mpoly = mpoly - hole; + BOOST_CHECK_EQUAL(mpoly[0].outer()[1], point_type_fp(0,10)); + BOOST_CHECK_EQUAL(mpoly[0].inners()[0][1], point_type_fp(7,3)); + bg::reverse(mpoly); + BOOST_CHECK_EQUAL(mpoly[0].outer()[1], point_type_fp(10,0)); + BOOST_CHECK_EQUAL(mpoly[0].inners()[0][1], point_type_fp(3,7)); + bg::correct(mpoly); + BOOST_CHECK_EQUAL(mpoly[0].outer()[1], point_type_fp(0,10)); + BOOST_CHECK_EQUAL(mpoly[0].inners()[0][1], point_type_fp(7,3)); +} + +BOOST_AUTO_TEST_SUITE_END() + #ifdef GEOS_VERSION + +BOOST_AUTO_TEST_SUITE(geos_geometry) + +BOOST_AUTO_TEST_CASE(polygon_with_holes_direction) { // Convert it through well-known text, which is sure to create a // valid polygon in geos. geos::io::WKTReader reader; - std::stringstream ss; - ss << bg::wkt(poly); - auto geos_geo = reader.read(ss.str()); - const auto* geos_poly = dynamic_cast(geos_geo.get()); - BOOST_CHECK_EQUAL(geos_poly->getExteriorRing()->getPointN(1)->getX(), 0); - BOOST_CHECK_EQUAL(geos_poly->getExteriorRing()->getPointN(1)->getY(), 10); -#endif // GEOS_VERSION + auto geos_geo = reader.read("MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(3 3,7 3,7 7,3 7,3 3)))"); + auto* geos_poly = dynamic_cast(geos_geo.get()); + geos_poly->normalize(); + BOOST_CHECK_EQUAL(geos_poly->getGeometryN(0)->getExteriorRing()->getPointN(1)->getX(), 0); + BOOST_CHECK_EQUAL(geos_poly->getGeometryN(0)->getExteriorRing()->getPointN(1)->getY(), 10); + BOOST_CHECK_EQUAL(geos_poly->getGeometryN(0)->getInteriorRingN(0)->getPointN(1)->getX(), 7); + BOOST_CHECK_EQUAL(geos_poly->getGeometryN(0)->getInteriorRingN(0)->getPointN(1)->getY(), 3); + + // Now convert a reversed version. + geos_geo = reader.read("MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0),(3 3,3 7,7 7,7 3,3 3)))"); + geos_poly = dynamic_cast(geos_geo.get()); + geos_poly->normalize(); + BOOST_CHECK_EQUAL(geos_poly->getGeometryN(0)->getExteriorRing()->getPointN(1)->getX(), 0); + BOOST_CHECK_EQUAL(geos_poly->getGeometryN(0)->getExteriorRing()->getPointN(1)->getY(), 10); + BOOST_CHECK_EQUAL(geos_poly->getGeometryN(0)->getInteriorRingN(0)->getPointN(1)->getX(), 7); + BOOST_CHECK_EQUAL(geos_poly->getGeometryN(0)->getInteriorRingN(0)->getPointN(1)->getY(), 3); +} + +BOOST_AUTO_TEST_SUITE(roundtrip) + +BOOST_AUTO_TEST_CASE(multi_linestring) { + multi_linestring_type_fp mls{{{0,0}, {1,1}}, {{2,2},{3,3}}}; + BOOST_CHECK_EQUAL(from_geos(to_geos(mls)), mls); +} + +BOOST_AUTO_TEST_CASE(linestring) { + linestring_type_fp ls{{0,0}, {1,1}}; + BOOST_CHECK_EQUAL(from_geos(to_geos(ls)), ls); +} + +BOOST_AUTO_TEST_CASE(polygon) { + polygon_type_fp poly{{{0,0}, {0,10}, {10,10}, {10,0}, {0,0}}}; + BOOST_CHECK(bg::equals(from_geos(to_geos(poly)), poly)); } +BOOST_AUTO_TEST_CASE(ring) { + ring_type_fp ring{{0,0}, {0,10}, {10,10}, {10,0}, {0,0}}; + BOOST_CHECK_EQUAL(from_geos(to_geos(ring)), ring); +} + +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_CASE(convert_multi_polygon_exception) { + linestring_type_fp ls{{0,0}, {1,1}}; + auto geos_ls = boost::dynamic_pointer_cast(to_geos(ls)); + BOOST_CHECK_THROW(from_geos(geos_ls), std::logic_error); +} + +BOOST_AUTO_TEST_SUITE_END() + +#endif // GEOS_VERSION + BOOST_AUTO_TEST_SUITE_END()