diff --git a/src/geometry_reprojection.cpp b/src/geometry_reprojection.cpp index 4ec0eb1cb..3772d48b4 100644 --- a/src/geometry_reprojection.cpp +++ b/src/geometry_reprojection.cpp @@ -60,9 +60,9 @@ polygon reproject_internal(polygon const & poly, proj_transform const& proj_tran { polygon new_poly; linear_ring new_ext(poly.exterior_ring); - int err = proj_trans.forward(new_ext); + unsigned int err = proj_trans.forward(new_ext); // If the exterior ring doesn't transform don't bother with the holes. - if (err > 0) + if (err > 0 || new_ext.empty()) { n_err += err; } @@ -75,7 +75,7 @@ polygon reproject_internal(polygon const & poly, proj_transform const& proj_tran { linear_ring new_lr(lr); err = proj_trans.forward(new_lr); - if (err > 0) + if (err > 0 || new_lr.empty()) { n_err += err; // If there is an error in interior ring drop @@ -175,7 +175,7 @@ struct geom_reproj_copy_visitor { geometry operator() (point const& p) { - int intial_err = n_err_; + unsigned int intial_err = n_err_; point new_p = reproject_internal(p, proj_trans_, n_err_); if (n_err_ > intial_err) { @@ -188,7 +188,7 @@ struct geom_reproj_copy_visitor { { int intial_err = n_err_; line_string new_ls = reproject_internal(ls, proj_trans_, n_err_); - if (n_err_ > intial_err) + if (n_err_ > intial_err || new_ls.empty()) { return std::move(geometry_empty()); } diff --git a/tests/cxx/geometry_equal.hpp b/tests/cxx/geometry_equal.hpp index b03fdc441..764f6ebf7 100644 --- a/tests/cxx/geometry_equal.hpp +++ b/tests/cxx/geometry_equal.hpp @@ -79,6 +79,8 @@ auto zip_crange(Conts&... conts) using namespace mapnik::geometry; +void assert_g_equal(geometry const& g1, geometry const& g2); + struct geometry_equal_visitor { template @@ -130,7 +132,46 @@ struct geometry_equal_visitor void operator() (multi_point const& mp1, multi_point const& mp2) { - (*this)(static_cast(mp1), static_cast(mp2)); + (*this)(static_cast(mp1), static_cast(mp2)); + } + + void operator() (multi_line_string const& mls1, multi_line_string const& mls2) + { + if (mls1.size() != mls2.size()) + { + REQUIRE(false); + } + + for (auto const& ls : zip_crange(mls1, mls2)) + { + (*this)(ls.get<0>(),ls.get<1>()); + } + } + + void operator() (multi_polygon const& mpoly1, multi_polygon const& mpoly2) + { + if (mpoly1.size() != mpoly2.size()) + { + REQUIRE(false); + } + + for (auto const& poly : zip_crange(mpoly1, mpoly2)) + { + (*this)(poly.get<0>(),poly.get<1>()); + } + } + + void operator() (geometry_collection const& c1, geometry_collection const& c2) + { + if (c1.size() != c2.size()) + { + REQUIRE(false); + } + + for (auto const& g : zip_crange(c1, c2)) + { + (*this)(g.get<0>(),g.get<1>()); + } } }; diff --git a/tests/cxx/geometry_reprojection.cpp b/tests/cxx/geometry_reprojection.cpp index 3cf2a50d3..2552adbb2 100644 --- a/tests/cxx/geometry_reprojection.cpp +++ b/tests/cxx/geometry_reprojection.cpp @@ -242,6 +242,81 @@ SECTION("test_projection_4326_3857 - Line_String Geometry Object") { assert_g_equal(geom3, geom1); } } // End Section + +SECTION("test_projection_4326_3857 - Line_String Geometry Variant Object") { + using namespace mapnik::geometry; + mapnik::projection source("+init=epsg:4326"); + mapnik::projection dest("+init=epsg:3857"); + mapnik::proj_transform proj_trans1(source, dest); + mapnik::proj_transform proj_trans2(dest, source); + line_string geom1_; + geom1_.emplace_back(point(-97.48872756958008, 35.360286150765084)); + geom1_.emplace_back(point(-97.48065948486328, 35.34894577151337)); + geom1_.emplace_back(point(-97.47267723083496, 35.36224605490395)); + geom1_.emplace_back(point(-97.46323585510252, 35.34523530173256)); + geom1_.emplace_back(point(-97.45963096618651, 35.36329598397908)); + geom1_.emplace_back(point(-97.47550964355469, 35.369245324153866)); + line_string geom2_; + geom2_.emplace_back(point(-10852395.511130, 4212951.024108)); + geom2_.emplace_back(point(-10851497.376047, 4211403.174286)); + geom2_.emplace_back(point(-10850608.795594, 4213218.553707)); + geom2_.emplace_back(point(-10849557.786455, 4210896.778973)); + geom2_.emplace_back(point(-10849156.492056, 4213361.873135)); + geom2_.emplace_back(point(-10850924.098335, 4214174.016561)); + line_string geom0_; + geometry geom0(geom0_); + geometry geom1(geom1_); + geometry geom2(geom2_); + unsigned int err = 0; + { + // Reprojecting empty line string will return a geometry_empty + geometry new_geom = reproject_copy(geom0, proj_trans1, err); + REQUIRE(err == 0); + REQUIRE(new_geom.is()); + } + { + // Test Standard Transform + geometry new_geom = reproject_copy(geom1, proj_trans1, err); + REQUIRE(err == 0); + assert_g_equal(new_geom, geom2); + } + { + // Transform in reverse + geometry new_geom = reproject_copy(geom2, proj_trans2, err); + REQUIRE(err == 0); + assert_g_equal(new_geom, geom1); + } + { + // Transform providing projections not transfrom + geometry new_geom = reproject_copy(geom1, source, dest, err); + REQUIRE(err == 0); + assert_g_equal(new_geom, geom2); + } + { + // Transform providing projections in reverse + geometry new_geom = reproject_copy(geom2, dest, source, err); + REQUIRE(err == 0); + assert_g_equal(new_geom, geom1); + } + { + // Transform in place + geometry geom3(geom1); + REQUIRE(reproject(geom3, proj_trans1)); + assert_g_equal(geom3, geom2); + // Transform in place reverse + REQUIRE(reproject(geom3, proj_trans2)); + assert_g_equal(geom3, geom1); + } + { + // Transform in place providing projections + geometry geom3(geom1); + REQUIRE(reproject(geom3, source, dest)); + assert_g_equal(geom3, geom2); + // Transform in place provoding projections reversed + REQUIRE(reproject(geom3, dest, source)); + assert_g_equal(geom3, geom1); + } +} // End Section SECTION("test_projection_4326_3857 - Polygon Geometry Object") { using namespace mapnik::geometry; @@ -276,9 +351,17 @@ SECTION("test_projection_4326_3857 - Polygon Geometry Object") { unsigned int err = 0; { // Test Standard Transform + // Add extra vector to outer ring. + geom1.interior_rings.emplace_back(); + REQUIRE(geom1.interior_rings.size() == 2); polygon new_geom = reproject_copy(geom1, proj_trans1, err); REQUIRE(err == 0); + // Should remove the empty ring added to back of geom1 + REQUIRE(new_geom.interior_rings.size() == 1); assert_g_equal(new_geom, geom2); + // Remove extra ring for future validity tests. + geom1.interior_rings.pop_back(); + REQUIRE(geom1.interior_rings.size() == 1); } { // Transform in reverse @@ -301,7 +384,13 @@ SECTION("test_projection_4326_3857 - Polygon Geometry Object") { { // Transform in place polygon geom3(geom1); + geom3.interior_rings.emplace_back(); REQUIRE(reproject(geom3, proj_trans1)); + // Should NOT remove the empty ring added to back of geom1 + REQUIRE(geom3.interior_rings.size() == 2); + // Remove so asserts that geometries are the same + geom3.interior_rings.pop_back(); + REQUIRE(geom3.interior_rings.size() == 1); assert_g_equal(geom3, geom2); // Transform in place reverse REQUIRE(reproject(geom3, proj_trans2)); @@ -317,6 +406,233 @@ SECTION("test_projection_4326_3857 - Polygon Geometry Object") { assert_g_equal(geom3, geom1); } } // End Section + +SECTION("test_projection_4326_3857 - Polygon Geometry Variant Object") { + using namespace mapnik::geometry; + mapnik::projection source("+init=epsg:4326"); + mapnik::projection dest("+init=epsg:3857"); + mapnik::proj_transform proj_trans1(source, dest); + mapnik::proj_transform proj_trans2(dest, source); + polygon geom1_; + geom1_.exterior_ring.emplace_back(point(-97.62588500976562, 35.62939577711732)); + geom1_.exterior_ring.emplace_back(point(-97.79067993164062, 35.43941441533686)); + geom1_.exterior_ring.emplace_back(point(-97.60391235351562, 35.34425514918409)); + geom1_.exterior_ring.emplace_back(point(-97.42813110351562, 35.48191987272801)); + geom1_.exterior_ring.emplace_back(point(-97.62588500976562, 35.62939577711732)); + geom1_.interior_rings.emplace_back(); + geom1_.interior_rings.back().emplace_back(point(-97.66571044921875, 35.46849952318069)); + geom1_.interior_rings.back().emplace_back(point(-97.61489868164062, 35.54116627999813)); + geom1_.interior_rings.back().emplace_back(point(-97.53799438476562, 35.459551379037606)); + geom1_.interior_rings.back().emplace_back(point(-97.62451171875, 35.42598697382711)); + geom1_.interior_rings.back().emplace_back(point(-97.66571044921875, 35.46849952318069)); + polygon geom2_; + geom2_.exterior_ring.emplace_back(point(-10867663.807530, 4249745.898599)); + geom2_.exterior_ring.emplace_back(point(-10886008.694318, 4223757.308982)); + geom2_.exterior_ring.emplace_back(point(-10865217.822625, 4210763.014174)); + geom2_.exterior_ring.emplace_back(point(-10845649.943384, 4229566.523132)); + geom2_.exterior_ring.emplace_back(point(-10867663.807530, 4249745.898599)); + geom2_.interior_rings.emplace_back(); + geom2_.interior_rings.back().emplace_back(point(-10872097.155170, 4227732.034453)); + geom2_.interior_rings.back().emplace_back(point(-10866440.815077, 4237668.848130)); + geom2_.interior_rings.back().emplace_back(point(-10857879.867909, 4226509.042001)); + geom2_.interior_rings.back().emplace_back(point(-10867510.933473, 4221922.820303)); + geom2_.interior_rings.back().emplace_back(point(-10872097.155170, 4227732.034453)); + polygon geom0_; + geometry geom0(geom0_); + geometry geom1(geom1_); + geometry geom2(geom2_); + unsigned int err = 0; + { + // Reprojecting empty poly will return a geometry_empty + geometry new_geom = reproject_copy(geom0, proj_trans1, err); + REQUIRE(err == 0); + REQUIRE(new_geom.is()); + } + { + // Test Standard Transform + geometry new_geom = reproject_copy(geom1, proj_trans1, err); + REQUIRE(err == 0); + assert_g_equal(new_geom, geom2); + } + { + // Transform in reverse + geometry new_geom = reproject_copy(geom2, proj_trans2, err); + REQUIRE(err == 0); + assert_g_equal(new_geom, geom1); + } + { + // Transform providing projections not transfrom + geometry new_geom = reproject_copy(geom1, source, dest, err); + REQUIRE(err == 0); + assert_g_equal(new_geom, geom2); + } + { + // Transform providing projections in reverse + geometry new_geom = reproject_copy(geom2, dest, source, err); + REQUIRE(err == 0); + assert_g_equal(new_geom, geom1); + } + { + // Transform in place + geometry geom3(geom1); + REQUIRE(reproject(geom3, proj_trans1)); + assert_g_equal(geom3, geom2); + // Transform in place reverse + REQUIRE(reproject(geom3, proj_trans2)); + assert_g_equal(geom3, geom1); + } + { + // Transform in place providing projections + geometry geom3(geom1); + REQUIRE(reproject(geom3, source, dest)); + assert_g_equal(geom3, geom2); + // Transform in place provoding projections reversed + REQUIRE(reproject(geom3, dest, source)); + assert_g_equal(geom3, geom1); + } +} // END SECTION + +SECTION("test_projection_4326_3857 - Multi_Point Geometry Object") { + using namespace mapnik::geometry; + mapnik::projection source("+init=epsg:4326"); + mapnik::projection dest("+init=epsg:3857"); + mapnik::proj_transform proj_trans1(source, dest); + mapnik::proj_transform proj_trans2(dest, source); + multi_point geom1; + geom1.emplace_back(point(-97.48872756958008, 35.360286150765084)); + geom1.emplace_back(point(-97.48065948486328, 35.34894577151337)); + geom1.emplace_back(point(-97.47267723083496, 35.36224605490395)); + geom1.emplace_back(point(-97.46323585510252, 35.34523530173256)); + geom1.emplace_back(point(-97.45963096618651, 35.36329598397908)); + geom1.emplace_back(point(-97.47550964355469, 35.369245324153866)); + multi_point geom2; + geom2.emplace_back(point(-10852395.511130, 4212951.024108)); + geom2.emplace_back(point(-10851497.376047, 4211403.174286)); + geom2.emplace_back(point(-10850608.795594, 4213218.553707)); + geom2.emplace_back(point(-10849557.786455, 4210896.778973)); + geom2.emplace_back(point(-10849156.492056, 4213361.873135)); + geom2.emplace_back(point(-10850924.098335, 4214174.016561)); + unsigned int err = 0; + { + // Test Standard Transform + multi_point new_geom = reproject_copy(geom1, proj_trans1, err); + REQUIRE(err == 0); + assert_g_equal(new_geom, geom2); + } + { + // Transform in reverse + multi_point new_geom = reproject_copy(geom2, proj_trans2, err); + REQUIRE(err == 0); + assert_g_equal(new_geom, geom1); + } + { + // Transform providing projections not transfrom + multi_point new_geom = reproject_copy(geom1, source, dest, err); + REQUIRE(err == 0); + assert_g_equal(new_geom, geom2); + } + { + // Transform providing projections in reverse + multi_point new_geom = reproject_copy(geom2, dest, source, err); + REQUIRE(err == 0); + assert_g_equal(new_geom, geom1); + } + { + // Transform in place + multi_point geom3(geom1); + REQUIRE(reproject(geom3, proj_trans1)); + assert_g_equal(geom3, geom2); + // Transform in place reverse + REQUIRE(reproject(geom3, proj_trans2)); + assert_g_equal(geom3, geom1); + } + { + // Transform in place providing projections + multi_point geom3(geom1); + REQUIRE(reproject(geom3, source, dest)); + assert_g_equal(geom3, geom2); + // Transform in place provoding projections reversed + REQUIRE(reproject(geom3, dest, source)); + assert_g_equal(geom3, geom1); + } +} // End Section + +SECTION("test_projection_4326_3857 - Multi_Point Geometry Variant Object") { + using namespace mapnik::geometry; + mapnik::projection source("+init=epsg:4326"); + mapnik::projection dest("+init=epsg:3857"); + mapnik::proj_transform proj_trans1(source, dest); + mapnik::proj_transform proj_trans2(dest, source); + multi_point geom1_; + geom1_.emplace_back(point(-97.48872756958008, 35.360286150765084)); + geom1_.emplace_back(point(-97.48065948486328, 35.34894577151337)); + geom1_.emplace_back(point(-97.47267723083496, 35.36224605490395)); + geom1_.emplace_back(point(-97.46323585510252, 35.34523530173256)); + geom1_.emplace_back(point(-97.45963096618651, 35.36329598397908)); + geom1_.emplace_back(point(-97.47550964355469, 35.369245324153866)); + multi_point geom2_; + geom2_.emplace_back(point(-10852395.511130, 4212951.024108)); + geom2_.emplace_back(point(-10851497.376047, 4211403.174286)); + geom2_.emplace_back(point(-10850608.795594, 4213218.553707)); + geom2_.emplace_back(point(-10849557.786455, 4210896.778973)); + geom2_.emplace_back(point(-10849156.492056, 4213361.873135)); + geom2_.emplace_back(point(-10850924.098335, 4214174.016561)); + multi_point geom0_; + geometry geom0(geom0_); + geometry geom1(geom1_); + geometry geom2(geom2_); + unsigned int err = 0; + { + // Reprojecting empty multi point will return a geometry_empty + geometry new_geom = reproject_copy(geom0, proj_trans1, err); + REQUIRE(err == 0); + REQUIRE(new_geom.is()); + } + { + // Test Standard Transform + geometry new_geom = reproject_copy(geom1, proj_trans1, err); + REQUIRE(err == 0); + assert_g_equal(new_geom, geom2); + } + { + // Transform in reverse + geometry new_geom = reproject_copy(geom2, proj_trans2, err); + REQUIRE(err == 0); + assert_g_equal(new_geom, geom1); + } + { + // Transform providing projections not transfrom + geometry new_geom = reproject_copy(geom1, source, dest, err); + REQUIRE(err == 0); + assert_g_equal(new_geom, geom2); + } + { + // Transform providing projections in reverse + geometry new_geom = reproject_copy(geom2, dest, source, err); + REQUIRE(err == 0); + assert_g_equal(new_geom, geom1); + } + { + // Transform in place + geometry geom3(geom1); + REQUIRE(reproject(geom3, proj_trans1)); + assert_g_equal(geom3, geom2); + // Transform in place reverse + REQUIRE(reproject(geom3, proj_trans2)); + assert_g_equal(geom3, geom1); + } + { + // Transform in place providing projections + geometry geom3(geom1); + REQUIRE(reproject(geom3, source, dest)); + assert_g_equal(geom3, geom2); + // Transform in place provoding projections reversed + REQUIRE(reproject(geom3, dest, source)); + assert_g_equal(geom3, geom1); + } +} // End Section + + /* for (auto const& p : new_geom) {