diff options
| author | Even Rouault <even.rouault@spatialys.com> | 2020-01-17 00:24:03 +0100 |
|---|---|---|
| committer | Even Rouault <even.rouault@spatialys.com> | 2020-01-17 00:52:19 +0100 |
| commit | 4724025e6c817761052fc0dc8810fd489a9e0104 (patch) | |
| tree | 21117e52f95b8f36880efef8cd71c1fcec21242c /test/unit | |
| parent | 66fd99a8831955034cb25c8468ecfe1f9d3a7d62 (diff) | |
| parent | d76e6202d27c730b4dcbf16b8c1575c11b703485 (diff) | |
| download | PROJ-4724025e6c817761052fc0dc8810fd489a9e0104.tar.gz PROJ-4724025e6c817761052fc0dc8810fd489a9e0104.zip | |
Merge branch 'master' into rfc4_merge_back_master
Diffstat (limited to 'test/unit')
| -rw-r--r-- | test/unit/CMakeLists.txt | 30 | ||||
| -rw-r--r-- | test/unit/Makefile.am | 2 | ||||
| -rw-r--r-- | test/unit/pj_transform_test.cpp | 32 | ||||
| -rw-r--r-- | test/unit/test_c_api.cpp | 62 | ||||
| -rw-r--r-- | test/unit/test_crs.cpp | 184 | ||||
| -rw-r--r-- | test/unit/test_datum.cpp | 3 | ||||
| -rw-r--r-- | test/unit/test_factory.cpp | 10 | ||||
| -rw-r--r-- | test/unit/test_io.cpp | 98 | ||||
| -rw-r--r-- | test/unit/test_operation.cpp | 138 |
9 files changed, 517 insertions, 42 deletions
diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index e14d4c70..f5890f1a 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -71,7 +71,7 @@ target_link_libraries(proj_pj_transform_test ${PROJ_LIBRARIES}) add_test(NAME proj_pj_transform_test COMMAND proj_pj_transform_test) set_property(TEST proj_pj_transform_test - PROPERTY ENVIRONMENT "PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES;PROJ_LIB=${PROJECT_BINARY_DIR}/data") + PROPERTY ENVIRONMENT "PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES;PROJ_LIB=${PROJECT_BINARY_DIR}/data/for_tests") add_executable(proj_errno_string_test @@ -82,7 +82,7 @@ target_link_libraries(proj_errno_string_test ${PROJ_LIBRARIES}) add_test(NAME proj_errno_string_test COMMAND proj_errno_string_test) set_property(TEST proj_errno_string_test - PROPERTY ENVIRONMENT "PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES;PROJ_LIB=${PROJECT_BINARY_DIR}/data") + PROPERTY ENVIRONMENT "PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES;PROJ_LIB=${PROJECT_BINARY_DIR}/data/for_tests") add_executable(proj_angular_io_test main.cpp @@ -92,7 +92,7 @@ target_link_libraries(proj_angular_io_test ${PROJ_LIBRARIES}) add_test(NAME proj_angular_io_test COMMAND proj_angular_io_test) set_property(TEST proj_angular_io_test - PROPERTY ENVIRONMENT "PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES;PROJ_LIB=${PROJECT_BINARY_DIR}/data") + PROPERTY ENVIRONMENT "PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES;PROJ_LIB=${PROJECT_BINARY_DIR}/data/for_tests") add_executable(proj_context_test main.cpp @@ -102,7 +102,7 @@ target_link_libraries(proj_context_test ${PROJ_LIBRARIES}) add_test(NAME proj_context_test COMMAND proj_context_test) set_property(TEST proj_context_test - PROPERTY ENVIRONMENT "PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES;PROJ_LIB=${PROJECT_BINARY_DIR}/data") + PROPERTY ENVIRONMENT "PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES;PROJ_LIB=${PROJECT_BINARY_DIR}/data/for_tests") if(MSVC AND BUILD_LIBPROJ_SHARED) # ph_phi2_test not compatible of a .dll build @@ -115,7 +115,7 @@ else() ${PROJ_LIBRARIES}) add_test(NAME pj_phi2_test COMMAND pj_phi2_test) set_property(TEST pj_phi2_test - PROPERTY ENVIRONMENT "PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES;PROJ_LIB=${PROJECT_BINARY_DIR}/data") + PROPERTY ENVIRONMENT "PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES;PROJ_LIB=${PROJECT_BINARY_DIR}/data/for_tests") endif() add_executable(proj_test_cpp_api @@ -135,13 +135,8 @@ target_link_libraries(proj_test_cpp_api ${PROJ_LIBRARIES} ${SQLITE3_LIBRARY}) add_test(NAME proj_test_cpp_api COMMAND proj_test_cpp_api) -if(MSVC) - set_property(TEST proj_test_cpp_api - PROPERTY ENVIRONMENT "PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES;PROJ_LIB=${PROJECT_BINARY_DIR}/data\\;${PROJECT_SOURCE_DIR}/data") -else() - set_property(TEST proj_test_cpp_api - PROPERTY ENVIRONMENT "PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES;PROJ_LIB=${PROJECT_BINARY_DIR}/data:${PROJECT_SOURCE_DIR}/data") -endif() +set_property(TEST proj_test_cpp_api + PROPERTY ENVIRONMENT "PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES;PROJ_LIB=${PROJECT_BINARY_DIR}/data/for_tests") add_executable(gie_self_tests @@ -152,7 +147,7 @@ target_link_libraries(gie_self_tests ${PROJ_LIBRARIES}) add_test(NAME gie_self_tests COMMAND gie_self_tests) set_property(TEST gie_self_tests - PROPERTY ENVIRONMENT "PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES;PROJ_LIB=${PROJECT_BINARY_DIR}/data") + PROPERTY ENVIRONMENT "PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES;PROJ_LIB=${PROJECT_BINARY_DIR}/data/for_tests") add_executable(test_network @@ -167,10 +162,5 @@ target_link_libraries(test_network ${PROJ_LIBRARIES} ${SQLITE3_LIBRARY}) add_test(NAME test_network COMMAND test_network) -if(MSVC) - set_property(TEST test_network - PROPERTY ENVIRONMENT "PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES;PROJ_LIB=${PROJECT_BINARY_DIR}/data\\;${PROJECT_SOURCE_DIR}/data;PROJ_SOURCE_DATA=${PROJECT_SOURCE_DIR}/data") -else() - set_property(TEST test_network - PROPERTY ENVIRONMENT "PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES;PROJ_LIB=${PROJECT_BINARY_DIR}/data:${PROJECT_SOURCE_DIR}/data;PROJ_SOURCE_DATA=${PROJECT_SOURCE_DIR}/data") -endif() +set_property(TEST test_network + PROPERTY ENVIRONMENT "PROJ_IGNORE_USER_WRITABLE_DIRECTORY=YES;PROJ_LIB=${PROJECT_BINARY_DIR}/data/for_tests;PROJ_SOURCE_DATA=${PROJECT_SOURCE_DIR}/data") diff --git a/test/unit/Makefile.am b/test/unit/Makefile.am index b7a26d4e..86ed383a 100644 --- a/test/unit/Makefile.am +++ b/test/unit/Makefile.am @@ -7,7 +7,7 @@ noinst_HEADERS = gtest_include.h test_primitives.hpp AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/include -I$(top_srcdir)/test @GTEST_CFLAGS@ @SQLITE3_CFLAGS@ AM_CXXFLAGS = @CXX_WFLAGS@ @NO_ZERO_AS_NULL_POINTER_CONSTANT_FLAG@ -PROJ_LIB ?= ../../data +PROJ_LIB ?= ../../data/for_tests noinst_PROGRAMS = pj_transform_test noinst_PROGRAMS += pj_phi2_test diff --git a/test/unit/pj_transform_test.cpp b/test/unit/pj_transform_test.cpp index 5ca8dcce..ddb054f0 100644 --- a/test/unit/pj_transform_test.cpp +++ b/test/unit/pj_transform_test.cpp @@ -632,6 +632,23 @@ TEST(proj_api_h, default_fileapi) { // --------------------------------------------------------------------------- +TEST(pj_transform_test, ob_tran_to_meter_as_dest) { + auto src = pj_init_plus( + "+ellps=WGS84 +a=57.29577951308232 +proj=eqc +lon_0=0.0 +no_defs"); + auto dst = pj_init_plus("+ellps=WGS84 +proj=ob_tran +o_proj=latlon " + "+o_lon_p=0.0 +o_lat_p=90.0 +lon_0=360.0 " + "+to_meter=0.0174532925199433 +no_defs"); + double x = 2 * DEG_TO_RAD; + double y = 49 * DEG_TO_RAD; + EXPECT_EQ(pj_transform(src, dst, 1, 0, &x, &y, nullptr), 0); + EXPECT_NEAR(x, 2 * DEG_TO_RAD, 1e-12) << x / DEG_TO_RAD; + EXPECT_NEAR(y, 49 * DEG_TO_RAD, 1e-12) << y / DEG_TO_RAD; + pj_free(src); + pj_free(dst); +} + +// --------------------------------------------------------------------------- + struct Spy { bool gotInMyFOpen = false; bool gotInMyFRead = false; @@ -705,4 +722,19 @@ TEST(proj_api_h, custom_fileapi) { EXPECT_TRUE(spy.gotInMyFClose); } +TEST(pj_transform_test, ob_tran_to_meter_as_srouce) { + auto src = pj_init_plus("+ellps=WGS84 +proj=ob_tran +o_proj=latlon " + "+o_lon_p=0.0 +o_lat_p=90.0 +lon_0=360.0 " + "+to_meter=0.0174532925199433 +no_defs"); + auto dst = pj_init_plus( + "+ellps=WGS84 +a=57.29577951308232 +proj=eqc +lon_0=0.0 +no_defs"); + double x = 2 * DEG_TO_RAD; + double y = 49 * DEG_TO_RAD; + EXPECT_EQ(pj_transform(src, dst, 1, 0, &x, &y, nullptr), 0); + EXPECT_NEAR(x, 2 * DEG_TO_RAD, 1e-12) << x / DEG_TO_RAD; + EXPECT_NEAR(y, 49 * DEG_TO_RAD, 1e-12) << y / DEG_TO_RAD; + pj_free(src); + pj_free(dst); +} + } // namespace diff --git a/test/unit/test_c_api.cpp b/test/unit/test_c_api.cpp index 8871f679..5c6dabba 100644 --- a/test/unit/test_c_api.cpp +++ b/test/unit/test_c_api.cpp @@ -1668,7 +1668,7 @@ TEST_F(CApi, proj_create_from_name) { false, 0, nullptr); ASSERT_NE(res, nullptr); ObjListKeeper keeper_res(res); - EXPECT_EQ(proj_list_get_count(res), 4); + EXPECT_EQ(proj_list_get_count(res), 5); } { auto res = proj_create_from_name(m_ctxt, "xx", "WGS 84", nullptr, 0, @@ -3486,6 +3486,36 @@ TEST_F(CApi, proj_normalize_for_visualization_on_crs) { // --------------------------------------------------------------------------- +TEST_F(CApi, proj_coordoperation_create_inverse) { + + auto P = proj_create( + m_ctxt, "+proj=pipeline +step +proj=axisswap +order=2,1 +step " + "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push " + "+v_3 +step +proj=cart +ellps=evrst30 +step +proj=helmert " + "+x=293 +y=836 +z=318 +rx=0.5 +ry=1.6 +rz=-2.8 +s=2.1 " + "+convention=position_vector +step +inv +proj=cart " + "+ellps=WGS84 +step +proj=pop +v_3 +step +proj=unitconvert " + "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1"); + ObjectKeeper keeper_P(P); + ASSERT_NE(P, nullptr); + auto Pinversed = proj_coordoperation_create_inverse(m_ctxt, P); + ObjectKeeper keeper_Pinversed(Pinversed); + ASSERT_NE(Pinversed, nullptr); + + auto projstr = proj_as_proj_string(m_ctxt, Pinversed, PJ_PROJ_5, nullptr); + ASSERT_NE(projstr, nullptr); + EXPECT_EQ(std::string(projstr), + "+proj=pipeline +step +proj=axisswap +order=2,1 +step " + "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 " + "+step +proj=cart +ellps=WGS84 +step +inv +proj=helmert +x=293 " + "+y=836 +z=318 +rx=0.5 +ry=1.6 +rz=-2.8 +s=2.1 " + "+convention=position_vector +step +inv +proj=cart " + "+ellps=evrst30 +step +proj=pop +v_3 +step +proj=unitconvert " + "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1"); +} + +// --------------------------------------------------------------------------- + TEST_F(CApi, proj_get_remarks) { auto co = proj_create_from_database(m_ctxt, "EPSG", "8048", PJ_CATEGORY_COORDINATE_OPERATION, false, @@ -4456,4 +4486,34 @@ TEST_F(CApi, proj_context_set_sqlite3_vfs_name) { proj_context_destroy(ctx); } +// --------------------------------------------------------------------------- + +TEST_F(CApi, proj_is_equivalent_to_with_ctx) { + auto from_epsg = proj_create_from_database(m_ctxt, "EPSG", "7844", + PJ_CATEGORY_CRS, false, nullptr); + ObjectKeeper keeper_from_epsg(from_epsg); + ASSERT_NE(from_epsg, nullptr); + + auto wkt = "GEOGCRS[\"GDA2020\",\n" + " DATUM[\"GDA2020\",\n" + " ELLIPSOID[\"GRS_1980\",6378137,298.257222101,\n" + " LENGTHUNIT[\"metre\",1]]],\n" + " PRIMEM[\"Greenwich\",0,\n" + " ANGLEUNIT[\"Degree\",0.0174532925199433]],\n" + " CS[ellipsoidal,2],\n" + " AXIS[\"geodetic latitude (Lat)\",north,\n" + " ORDER[1],\n" + " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" + " AXIS[\"geodetic longitude (Lon)\",east,\n" + " ORDER[2],\n" + " ANGLEUNIT[\"degree\",0.0174532925199433]]]"; + auto from_wkt = + proj_create_from_wkt(m_ctxt, wkt, nullptr, nullptr, nullptr); + ObjectKeeper keeper_from_wkt(from_wkt); + EXPECT_NE(from_wkt, nullptr); + + EXPECT_TRUE(proj_is_equivalent_to_with_ctx(m_ctxt, from_epsg, from_wkt, + PJ_COMP_EQUIVALENT)); +} + } // namespace diff --git a/test/unit/test_crs.cpp b/test/unit/test_crs.cpp index 427fd741..e6189a97 100644 --- a/test/unit/test_crs.cpp +++ b/test/unit/test_crs.cpp @@ -57,7 +57,8 @@ namespace { struct UnrelatedObject : public IComparable { UnrelatedObject() = default; - bool _isEquivalentTo(const IComparable *, Criterion) const override { + bool _isEquivalentTo(const IComparable *, Criterion, + const DatabaseContextPtr &) const override { assert(false); return false; } @@ -755,7 +756,9 @@ TEST(crs, EPSG_27561_projected_with_geodetic_in_grad_as_PROJ_string_and_WKT1) { nn_crs->DerivedCRS::isEquivalentTo(createUnrelatedObject().get())); auto wkt1 = crs->exportToWKT( - WKTFormatter::create(WKTFormatter::Convention::WKT1_GDAL).get()); + WKTFormatter::create(WKTFormatter::Convention::WKT1_GDAL, + DatabaseContext::create()) + .get()); EXPECT_EQ( wkt1, "PROJCS[\"NTF (Paris) / Lambert Nord France\",\n" @@ -856,7 +859,9 @@ TEST(crs, EPSG_2222_projected_unit_foot_as_PROJ_string_and_WKT1) { "+x_0=213360 +y_0=0 +datum=NAD83 +units=ft +no_defs +type=crs"); auto wkt1 = crs->exportToWKT( - WKTFormatter::create(WKTFormatter::Convention::WKT1_GDAL).get()); + WKTFormatter::create(WKTFormatter::Convention::WKT1_GDAL, + DatabaseContext::create()) + .get()); EXPECT_EQ(wkt1, "PROJCS[\"NAD83 / Arizona East (ft)\",\n" " GEOGCS[\"NAD83\",\n" @@ -903,11 +908,13 @@ TEST(crs, projected_with_parameter_unit_different_than_cs_unit_as_WKT1) { ASSERT_TRUE(crs != nullptr); auto wkt1 = crs->exportToWKT( - WKTFormatter::create(WKTFormatter::Convention::WKT1_GDAL).get()); + WKTFormatter::create(WKTFormatter::Convention::WKT1_GDAL, + DatabaseContext::create()) + .get()); EXPECT_EQ(wkt1, "PROJCS[\"unknown\",\n" " GEOGCS[\"unknown\",\n" - " DATUM[\"Unknown_based_on_GRS80_ellipsoid\",\n" + " DATUM[\"Unknown based on GRS80 ellipsoid\",\n" " SPHEROID[\"GRS 1980\",6378137,298.257222101]],\n" " PRIMEM[\"Greenwich\",0],\n" " UNIT[\"degree\",0.0174532925199433,\n" @@ -943,6 +950,16 @@ TEST(crs, EPSG_32661_projected_north_pole_north_east) { ASSERT_TRUE(op != nullptr); EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), proj_string); + + auto opNormalized = op->normalizeForVisualization(); + auto proj_string_normalized = + "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad " + "+step " + "+proj=stere +lat_0=90 +lon_0=0 +k=0.994 +x_0=2000000 +y_0=2000000 " + "+ellps=WGS84"; + EXPECT_EQ( + opNormalized->exportToPROJString(PROJStringFormatter::create().get()), + proj_string_normalized); } // --------------------------------------------------------------------------- @@ -964,6 +981,16 @@ TEST(crs, EPSG_5041_projected_north_pole_east_north) { ASSERT_TRUE(op != nullptr); EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), proj_string); + + auto opNormalized = op->normalizeForVisualization(); + auto proj_string_normalized = + "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad " + "+step " + "+proj=stere +lat_0=90 +lon_0=0 +k=0.994 +x_0=2000000 +y_0=2000000 " + "+ellps=WGS84"; + EXPECT_EQ( + opNormalized->exportToPROJString(PROJStringFormatter::create().get()), + proj_string_normalized); } // --------------------------------------------------------------------------- @@ -985,6 +1012,16 @@ TEST(crs, EPSG_32761_projected_south_pole_north_east) { ASSERT_TRUE(op != nullptr); EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), proj_string); + + auto opNormalized = op->normalizeForVisualization(); + auto proj_string_normalized = + "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad " + "+step " + "+proj=stere +lat_0=-90 +lon_0=0 +k=0.994 +x_0=2000000 +y_0=2000000 " + "+ellps=WGS84"; + EXPECT_EQ( + opNormalized->exportToPROJString(PROJStringFormatter::create().get()), + proj_string_normalized); } // --------------------------------------------------------------------------- @@ -1006,6 +1043,16 @@ TEST(crs, EPSG_5042_projected_south_pole_east_north) { ASSERT_TRUE(op != nullptr); EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), proj_string); + + auto opNormalized = op->normalizeForVisualization(); + auto proj_string_normalized = + "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad " + "+step " + "+proj=stere +lat_0=-90 +lon_0=0 +k=0.994 +x_0=2000000 +y_0=2000000 " + "+ellps=WGS84"; + EXPECT_EQ( + opNormalized->exportToPROJString(PROJStringFormatter::create().get()), + proj_string_normalized); } // --------------------------------------------------------------------------- @@ -1511,6 +1558,75 @@ TEST(crs, geodeticcrs_identify_db) { EXPECT_EQ(res.front().first->identifiers()[0]->code(), "4326"); EXPECT_EQ(res.front().second, 70); } + + { + // Identify by code, but datum name is an alias of the official one + auto wkt = "GEOGCRS[\"GDA2020\",\n" + " DATUM[\"GDA2020\",\n" + " ELLIPSOID[\"GRS_1980\",6378137,298.257222101,\n" + " LENGTHUNIT[\"metre\",1]]],\n" + " PRIMEM[\"Greenwich\",0,\n" + " ANGLEUNIT[\"Degree\",0.0174532925199433]],\n" + " CS[ellipsoidal,2],\n" + " AXIS[\"geodetic latitude (Lat)\",north,\n" + " ORDER[1],\n" + " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" + " AXIS[\"geodetic longitude (Lon)\",east,\n" + " ORDER[2],\n" + " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" + " ID[\"EPSG\",7844]]"; + auto obj = WKTParser().createFromWKT(wkt); + auto crs = nn_dynamic_pointer_cast<GeodeticCRS>(obj); + ASSERT_TRUE(crs != nullptr); + + auto allFactory = AuthorityFactory::create(dbContext, std::string()); + auto res = crs->identify(allFactory); + ASSERT_EQ(res.size(), 1U); + ASSERT_TRUE(!res.front().first->identifiers().empty()); + EXPECT_EQ(*res.front().first->identifiers()[0]->codeSpace(), "EPSG"); + EXPECT_EQ(res.front().first->identifiers()[0]->code(), "7844"); + EXPECT_EQ(res.front().second, 100); + + EXPECT_TRUE(crs->_isEquivalentTo(res.front().first.get(), + IComparable::Criterion::EQUIVALENT, + dbContext)); + EXPECT_TRUE(res.front().first->_isEquivalentTo( + crs.get(), IComparable::Criterion::EQUIVALENT, dbContext)); + } + + { + // Identify by name, but datum name is an alias of the official one + auto wkt = "GEOGCRS[\"GDA2020\",\n" + " DATUM[\"GDA2020\",\n" + " ELLIPSOID[\"GRS_1980\",6378137,298.257222101,\n" + " LENGTHUNIT[\"metre\",1]]],\n" + " PRIMEM[\"Greenwich\",0,\n" + " ANGLEUNIT[\"Degree\",0.0174532925199433]],\n" + " CS[ellipsoidal,2],\n" + " AXIS[\"geodetic latitude (Lat)\",north,\n" + " ORDER[1],\n" + " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" + " AXIS[\"geodetic longitude (Lon)\",east,\n" + " ORDER[2],\n" + " ANGLEUNIT[\"degree\",0.0174532925199433]]]"; + auto obj = WKTParser().createFromWKT(wkt); + auto crs = nn_dynamic_pointer_cast<GeodeticCRS>(obj); + ASSERT_TRUE(crs != nullptr); + + auto allFactory = AuthorityFactory::create(dbContext, std::string()); + auto res = crs->identify(allFactory); + ASSERT_EQ(res.size(), 1U); + ASSERT_TRUE(!res.front().first->identifiers().empty()); + EXPECT_EQ(*res.front().first->identifiers()[0]->codeSpace(), "EPSG"); + EXPECT_EQ(res.front().first->identifiers()[0]->code(), "7844"); + EXPECT_EQ(res.front().second, 100); + + EXPECT_TRUE(crs->_isEquivalentTo(res.front().first.get(), + IComparable::Criterion::EQUIVALENT, + dbContext)); + EXPECT_TRUE(res.front().first->_isEquivalentTo( + crs.get(), IComparable::Criterion::EQUIVALENT, dbContext)); + } } // --------------------------------------------------------------------------- @@ -2281,6 +2397,38 @@ TEST(crs, projectedCRS_identify_db) { // --------------------------------------------------------------------------- +TEST(crs, projectedCRS_identify_wrong_auth_name_case) { + auto dbContext = DatabaseContext::create(); + auto factoryAnonymous = AuthorityFactory::create(dbContext, std::string()); + auto obj = + WKTParser() + .attachDatabaseContext(dbContext) + .setStrict(false) + .createFromWKT( + "PROJCS[\"World_Cylindrical_Equal_Area\"," + "GEOGCS[\"GCS_WGS_1984\"," + "DATUM[\"D_WGS_1984\",SPHEROID[\"WGS_1984\"," + "6378137.0,298.257223563]]," + "PRIMEM[\"Greenwich\",0.0]," + "UNIT[\"Degree\",0.0174532925199433]]," + "PROJECTION[\"Cylindrical_Equal_Area\"]," + "PARAMETER[\"False_Easting\",0.0]," + "PARAMETER[\"False_Northing\",0.0]," + "PARAMETER[\"Central_Meridian\",0.0]," + "PARAMETER[\"Standard_Parallel_1\",0.0],UNIT[\"Meter\",1.0]," + "AUTHORITY[\"Esri\",54034]]"); // should be ESRI all caps + auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj); + ASSERT_TRUE(crs != nullptr); + auto res = crs->identify(factoryAnonymous); + ASSERT_EQ(res.size(), 1U); + const auto &ids = res.front().first->identifiers(); + ASSERT_EQ(ids.size(), 1U); + EXPECT_EQ(*(ids.front()->codeSpace()), "ESRI"); + EXPECT_EQ(ids.front()->code(), "54034"); +} + +// --------------------------------------------------------------------------- + TEST(crs, mercator_1SP_as_WKT1_ESRI) { auto obj = PROJStringParser().createFromPROJString( @@ -3351,6 +3499,17 @@ TEST(crs, compoundCRS_identify_db) { EXPECT_EQ(res.front().first->getEPSGCode(), 8769); EXPECT_EQ(res.front().second, 70); } + { + auto obj = PROJStringParser().createFromPROJString( + "+proj=tmerc +lat_0=0 +lon_0=72.05 +k=1 +x_0=3500000 " + "+y_0=-5811057.63 +ellps=krass " + "+towgs84=23.57,-140.95,-79.8,0,-0.35,-0.79,-0.22 " + "+geoidgrids=egm08_25.gtx +units=m +no_defs +type=crs"); + auto crs = nn_dynamic_pointer_cast<CompoundCRS>(obj); + ASSERT_TRUE(crs != nullptr); + // Just check we don't get an exception + crs->identify(factory); + } } // --------------------------------------------------------------------------- @@ -3753,6 +3912,21 @@ TEST(crs, boundCRS_identify_db) { WKTFormatter::create(WKTFormatter::Convention::WKT1_GDAL).get()); EXPECT_TRUE(wkt.find("32122") != std::string::npos) << wkt; } + + { + // Identify from a PROJ string with +towgs84 + auto obj = PROJStringParser().createFromPROJString( + "+proj=utm +zone=48 +a=6377276.345 +b=6356075.41314024 " + "+towgs84=198,881,317,0,0,0,0 +units=m +no_defs +type=crs"); + auto crs = nn_dynamic_pointer_cast<BoundCRS>(obj); + ASSERT_TRUE(crs != nullptr); + auto res = crs->identify(factoryEPSG); + ASSERT_EQ(res.size(), 1U); + auto boundCRS = dynamic_cast<const BoundCRS *>(res.front().first.get()); + ASSERT_TRUE(boundCRS != nullptr); + EXPECT_EQ(boundCRS->baseCRS()->getEPSGCode(), 3148); + EXPECT_EQ(res.front().second, 70); + } } // --------------------------------------------------------------------------- diff --git a/test/unit/test_datum.cpp b/test/unit/test_datum.cpp index 8a5d67cf..adf0ae4b 100644 --- a/test/unit/test_datum.cpp +++ b/test/unit/test_datum.cpp @@ -44,7 +44,8 @@ namespace { struct UnrelatedObject : public IComparable { UnrelatedObject() = default; - bool _isEquivalentTo(const IComparable *, Criterion) const override { + bool _isEquivalentTo(const IComparable *, Criterion, + const DatabaseContextPtr &) const override { assert(false); return false; } diff --git a/test/unit/test_factory.cpp b/test/unit/test_factory.cpp index e342dad9..6a88e2b6 100644 --- a/test/unit/test_factory.cpp +++ b/test/unit/test_factory.cpp @@ -2737,8 +2737,8 @@ TEST(factory, createObjectsFromName) { EXPECT_EQ(factory->createObjectsFromName("").size(), 0U); - // ellipsoid + 3 geodeticCRS - EXPECT_EQ(factory->createObjectsFromName("WGS 84", {}, false).size(), 4U); + // ellipsoid + datum + 3 geodeticCRS + EXPECT_EQ(factory->createObjectsFromName("WGS 84", {}, false).size(), 5U); EXPECT_EQ(factory->createObjectsFromName("WGS 84", {}, true, 10).size(), 10U); @@ -2753,7 +2753,9 @@ TEST(factory, createObjectsFromName) { auto res = factoryEPSG->createObjectsFromName( "WGS84", {AuthorityFactory::ObjectType::GEOGRAPHIC_2D_CRS}, true); EXPECT_EQ(res.size(), - 8U); // EPSG:4326 and EPSG:4030 and the 6 WGS84 realizations + 9U); // EPSG:4326 and EPSG:4030 and the 6 WGS84 realizations + // and EPSG:7881 'Tritan St. Helena'' whose alias is + // 'WGS 84 Tritan St. Helena' if (!res.empty()) { EXPECT_EQ(res.front()->getEPSGCode(), 4326); } @@ -2876,7 +2878,7 @@ TEST(factory, getMetadata) { EXPECT_EQ(ctxt->getMetadata("i_do_not_exist"), nullptr); const char *IGNF_VERSION = ctxt->getMetadata("IGNF.VERSION"); ASSERT_TRUE(IGNF_VERSION != nullptr); - EXPECT_EQ(std::string(IGNF_VERSION), "3.0.3"); + EXPECT_EQ(std::string(IGNF_VERSION), "3.1.0"); } // --------------------------------------------------------------------------- diff --git a/test/unit/test_io.cpp b/test/unit/test_io.cpp index 38dfc2b4..fd38847c 100644 --- a/test/unit/test_io.cpp +++ b/test/unit/test_io.cpp @@ -493,18 +493,14 @@ TEST(wkt_parse, wkt1_geographic_old_datum_name_from_EPSG_code) { // --------------------------------------------------------------------------- -TEST(wkt_parse, wkt1_geographic_old_datum_name_witout_EPSG_code) { +TEST(wkt_parse, wkt1_geographic_old_datum_name_without_EPSG_code) { auto wkt = "GEOGCS[\"S-JTSK (Ferro)\",\n" " " "DATUM[\"System_Jednotne_Trigonometricke_Site_Katastralni_Ferro\",\n" - " SPHEROID[\"Bessel 1841\",6377397.155,299.1528128,\n" - " AUTHORITY[\"EPSG\",\"7004\"]]],\n" - " PRIMEM[\"Ferro\",-17.66666666666667,\n" - " AUTHORITY[\"EPSG\",\"8909\"]],\n" - " UNIT[\"degree\",0.0174532925199433,\n" - " AUTHORITY[\"EPSG\",\"9122\"]],\n" - " AUTHORITY[\"EPSG\",\"4818\"]]"; + " SPHEROID[\"Bessel 1841\",6377397.155,299.1528128]],\n" + " PRIMEM[\"Ferro\",-17.66666666666667],\n" + " UNIT[\"degree\",0.0174532925199433]]"; auto obj = WKTParser() .attachDatabaseContext(DatabaseContext::create()) .createFromWKT(wkt); @@ -5577,6 +5573,17 @@ TEST(wkt_parse, invalid_GEOCCS) { "NORTH],AXIS[\"longitude\",EAST]]"), ParsingException); + // ellipsoidal CS is invalid in a GEOCCS + EXPECT_THROW(WKTParser().createFromWKT( + "GEOCCS[\"WGS 84\",DATUM[\"World Geodetic System 1984\"," + "ELLIPSOID[\"WGS 84\",6378274,298.257223564," + "LENGTHUNIT[\"metre\",1]]]," + "CS[ellipsoidal,2],AXIS[\"geodetic latitude (Lat)\",north," + "ANGLEUNIT[\"degree\",0.0174532925199433]]," + "AXIS[\"geodetic longitude (Lon)\",east," + "ANGLEUNIT[\"degree\",0.0174532925199433]]]"), + ParsingException); + // 3 axis required EXPECT_THROW(WKTParser().createFromWKT( "GEOCCS[\"x\",DATUM[\"x\",SPHEROID[\"x\",1,0.5]],PRIMEM[" @@ -6856,6 +6863,30 @@ TEST(io, projstringformatter_optim_hgridshift_vgridshift_hgridshift_inv) { "+step +proj=pop +v_1 +v_2"); } + // Test omit_fwd->omit_inv when inversing the pipeline + { + auto fmt = PROJStringFormatter::create(); + fmt->startInversion(); + fmt->ingestPROJString("+proj=hgridshift +grids=foo +omit_fwd"); + fmt->stopInversion(); + + EXPECT_EQ(fmt->toString(), + "+proj=pipeline " + "+step +inv +proj=hgridshift +grids=foo +omit_inv"); + } + + // Test omit_inv->omit_fwd when inversing the pipeline + { + auto fmt = PROJStringFormatter::create(); + fmt->startInversion(); + fmt->ingestPROJString("+proj=hgridshift +grids=foo +omit_inv"); + fmt->stopInversion(); + + EXPECT_EQ(fmt->toString(), + "+proj=pipeline " + "+step +inv +proj=hgridshift +grids=foo +omit_fwd"); + } + // Variant with first hgridshift inverted, and second forward { auto fmt = PROJStringFormatter::create(); @@ -9324,6 +9355,20 @@ TEST(io, createFromUserInput) { // --------------------------------------------------------------------------- +TEST(io, createFromUserInput_hack_EPSG_102100) { + auto dbContext = DatabaseContext::create(); + auto obj = createFromUserInput("EPSG:102100", dbContext); + auto crs = nn_dynamic_pointer_cast<CRS>(obj); + ASSERT_TRUE(crs != nullptr); + const auto &ids = crs->identifiers(); + ASSERT_EQ(ids.size(), 1U); + // we do not lie on the real authority + EXPECT_EQ(*ids[0]->codeSpace(), "ESRI"); + EXPECT_EQ(ids[0]->code(), "102100"); +} + +// --------------------------------------------------------------------------- + TEST(io, guessDialect) { EXPECT_EQ(WKTParser().guessDialect("LOCAL_CS[\"foo\"]"), WKTParser::WKTGuessedDialect::WKT1_GDAL); @@ -11866,3 +11911,40 @@ TEST(json_import, multiple_ids) { EXPECT_EQ(ellps->exportToJSON(&(JSONFormatter::create()->setSchema("foo"))), json); } + +// --------------------------------------------------------------------------- + +TEST(json_export, coordinate_system_id) { + auto json = "{\n" + " \"$schema\": \"foo\",\n" + " \"type\": \"CoordinateSystem\",\n" + " \"subtype\": \"ellipsoidal\",\n" + " \"axis\": [\n" + " {\n" + " \"name\": \"Geodetic latitude\",\n" + " \"abbreviation\": \"Lat\",\n" + " \"direction\": \"north\",\n" + " \"unit\": \"degree\"\n" + " },\n" + " {\n" + " \"name\": \"Geodetic longitude\",\n" + " \"abbreviation\": \"Lon\",\n" + " \"direction\": \"east\",\n" + " \"unit\": \"degree\"\n" + " }\n" + " ],\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 6422\n" + " }\n" + "}"; + + auto dbContext = DatabaseContext::create(); + auto obj = createFromUserInput("EPSG:4326", dbContext); + auto crs = nn_dynamic_pointer_cast<GeographicCRS>(obj); + ASSERT_TRUE(crs != nullptr); + auto cs = crs->coordinateSystem(); + ASSERT_TRUE(cs != nullptr); + EXPECT_EQ(cs->exportToJSON(&(JSONFormatter::create()->setSchema("foo"))), + json); +} diff --git a/test/unit/test_operation.cpp b/test/unit/test_operation.cpp index 753878c5..8ee5814b 100644 --- a/test/unit/test_operation.cpp +++ b/test/unit/test_operation.cpp @@ -65,7 +65,8 @@ namespace { struct UnrelatedObject : public IComparable { UnrelatedObject() = default; - bool _isEquivalentTo(const IComparable *, Criterion) const override { + bool _isEquivalentTo(const IComparable *, Criterion, + const DatabaseContextPtr &) const override { assert(false); return false; } @@ -3257,7 +3258,9 @@ TEST(operation, webmerc_import_from_WKT2_EPSG_3785_deprecated) { EXPECT_EQ( crs->exportToWKT( - WKTFormatter::create(WKTFormatter::Convention::WKT1_GDAL).get()), + WKTFormatter::create(WKTFormatter::Convention::WKT1_GDAL, + DatabaseContext::create()) + .get()), "PROJCS[\"Popular Visualisation CRS / Mercator\",\n" " GEOGCS[\"Popular Visualisation CRS\",\n" " DATUM[\"Popular_Visualisation_Datum\",\n" @@ -4628,6 +4631,33 @@ TEST(operation, geogCRS_to_geogCRS_context_WGS84_G1674_to_WGS84_G1762) { // --------------------------------------------------------------------------- +TEST(operation, geogCRS_to_geogCRS_context_EPSG_4240_Indian1975_to_EPSG_4326) { + auto authFactory = + AuthorityFactory::create(DatabaseContext::create(), "EPSG"); + auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0); + ctxt->setSpatialCriterion( + CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION); + + auto list = CoordinateOperationFactory::create()->createOperations( + authFactory->createCoordinateReferenceSystem("4240"), // Indian 1975 + authFactory->createCoordinateReferenceSystem("4326"), ctxt); + ASSERT_EQ(list.size(), 3U); + + // Indian 1975 to WGS 84 (4), 3.0 m, Thailand - onshore + EXPECT_EQ(list[0]->getEPSGCode(), 1812); + + // The following is the one we want to see. It has a lesser accuracy than + // the above one and the same bbox, but the name of its area of use is + // slightly different + // Indian 1975 to WGS 84 (2), 5.0 m, Thailand - onshore and Gulf of Thailand + EXPECT_EQ(list[1]->getEPSGCode(), 1304); + + // Indian 1975 to WGS 84 (3), 1.0 m, Thailand - Bongkot field + EXPECT_EQ(list[2]->getEPSGCode(), 1537); +} + +// --------------------------------------------------------------------------- + TEST(operation, vertCRS_to_geogCRS_context) { auto authFactory = AuthorityFactory::create(DatabaseContext::create(), "EPSG"); @@ -4687,6 +4717,19 @@ TEST(operation, vertCRS_to_geogCRS_context) { list[0]->exportToPROJString(PROJStringFormatter::create().get()), "+proj=affine +s33=-0.304800609601219"); } + { + auto ctxt = + CoordinateOperationContext::create(authFactory, nullptr, 0.0); + auto list = CoordinateOperationFactory::create()->createOperations( + // NZVD2016 height + authFactory->createCoordinateReferenceSystem("7839"), + // NZGD2000 + authFactory->createCoordinateReferenceSystem("4959"), ctxt); + ASSERT_EQ(list.size(), 1U); + EXPECT_EQ( + list[0]->exportToPROJString(PROJStringFormatter::create().get()), + "+proj=vgridshift +grids=nzgeoid2016.gtx +multiplier=1"); + } } // --------------------------------------------------------------------------- @@ -5576,6 +5619,69 @@ TEST(operation, projCRS_no_id_to_geogCRS_context) { // --------------------------------------------------------------------------- +TEST(operation, projCRS_3D_to_geogCRS_3D_context) { + auto authFactory = + AuthorityFactory::create(DatabaseContext::create(), "EPSG"); + auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0); + ctxt->setSpatialCriterion( + CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION); + auto wkt = "PROJCRS[\"NAD83(HARN) / Oregon GIC Lambert (ft)\",\n" + " BASEGEOGCRS[\"NAD83(HARN)\",\n" + " DATUM[\"NAD83 (High Accuracy Reference Network)\",\n" + " ELLIPSOID[\"GRS 1980\",6378137,298.257222101,\n" + " LENGTHUNIT[\"metre\",1]]],\n" + " PRIMEM[\"Greenwich\",0,\n" + " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" + " ID[\"EPSG\",4957]],\n" + " CONVERSION[\"unnamed\",\n" + " METHOD[\"Lambert Conic Conformal (2SP)\",\n" + " ID[\"EPSG\",9802]],\n" + " PARAMETER[\"Latitude of false origin\",41.75,\n" + " ANGLEUNIT[\"degree\",0.0174532925199433],\n" + " ID[\"EPSG\",8821]],\n" + " PARAMETER[\"Longitude of false origin\",-120.5,\n" + " ANGLEUNIT[\"degree\",0.0174532925199433],\n" + " ID[\"EPSG\",8822]],\n" + " PARAMETER[\"Latitude of 1st standard parallel\",43,\n" + " ANGLEUNIT[\"degree\",0.0174532925199433],\n" + " ID[\"EPSG\",8823]],\n" + " PARAMETER[\"Latitude of 2nd standard parallel\",45.5,\n" + " ANGLEUNIT[\"degree\",0.0174532925199433],\n" + " ID[\"EPSG\",8824]],\n" + " PARAMETER[\"Easting at false origin\",1312335.958,\n" + " LENGTHUNIT[\"foot\",0.3048],\n" + " ID[\"EPSG\",8826]],\n" + " PARAMETER[\"Northing at false origin\",0,\n" + " LENGTHUNIT[\"foot\",0.3048],\n" + " ID[\"EPSG\",8827]]],\n" + " CS[Cartesian,3],\n" + " AXIS[\"easting\",east,\n" + " ORDER[1],\n" + " LENGTHUNIT[\"foot\",0.3048]],\n" + " AXIS[\"northing\",north,\n" + " ORDER[2],\n" + " LENGTHUNIT[\"foot\",0.3048]],\n" + " AXIS[\"ellipsoidal height (h)\",up,\n" + " ORDER[3],\n" + " LENGTHUNIT[\"foot\",0.3048]]]"; + auto obj = WKTParser().createFromWKT(wkt); + auto src = NN_CHECK_ASSERT(nn_dynamic_pointer_cast<CRS>(obj)); + auto dst = authFactory->createCoordinateReferenceSystem( + "4957"); // NAD83(HARN) (3D) + auto list = + CoordinateOperationFactory::create()->createOperations(src, dst, ctxt); + ASSERT_EQ(list.size(), 1U); + EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()), + "+proj=pipeline " + // Check that z ft->m conversion is done (and just once) + "+step +proj=unitconvert +xy_in=ft +z_in=ft +xy_out=m +z_out=m " + "+step +inv +proj=lcc +lat_0=41.75 +lon_0=-120.5 +lat_1=43 " + "+lat_2=45.5 +x_0=399999.9999984 +y_0=0 +ellps=GRS80 " + "+step +proj=unitconvert +xy_in=rad +z_in=m +xy_out=deg +z_out=m " + "+step +proj=axisswap +order=2,1"); +} +// --------------------------------------------------------------------------- + TEST(operation, projCRS_3D_to_projCRS_2D_context) { auto authFactory = AuthorityFactory::create(DatabaseContext::create(), "EPSG"); @@ -6509,6 +6615,18 @@ TEST(operation, transformation_VERTCON_to_PROJ_string) { PROJStringFormatter::create().get()), "+proj=vgridshift +grids=bla.gtx +multiplier=0.001"); } +// --------------------------------------------------------------------------- + +TEST(operation, transformation_NZLVD_to_PROJ_string) { + auto dbContext = DatabaseContext::create(); + auto factory = AuthorityFactory::create(dbContext, "EPSG"); + auto op = factory->createCoordinateOperation("7860", false); + EXPECT_EQ(op->exportToPROJString( + PROJStringFormatter::create( + PROJStringFormatter::Convention::PROJ_5, dbContext) + .get()), + "+proj=vgridshift +grids=auckht1946-nzvd2016.gtx +multiplier=1"); +} // --------------------------------------------------------------------------- @@ -7134,6 +7252,22 @@ TEST(operation, vertCRS_to_vertCRS_context) { // --------------------------------------------------------------------------- +TEST(operation, vertCRS_to_vertCRS_New_Zealand_context) { + auto authFactory = + AuthorityFactory::create(DatabaseContext::create(), "EPSG"); + auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0); + auto list = CoordinateOperationFactory::create()->createOperations( + // NZVD2016 height + authFactory->createCoordinateReferenceSystem("7839"), + // Auckland 1946 height + authFactory->createCoordinateReferenceSystem("5759"), ctxt); + ASSERT_EQ(list.size(), 1U); + EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()), + "+proj=vgridshift +grids=auckht1946-nzvd2016.gtx +multiplier=1"); +} + +// --------------------------------------------------------------------------- + TEST(operation, compoundCRS_to_geogCRS_3D) { auto compoundcrs_ft_obj = PROJStringParser().createFromPROJString( |
