diff options
| author | Even Rouault <even.rouault@spatialys.com> | 2020-10-23 00:03:04 +0200 |
|---|---|---|
| committer | Even Rouault <even.rouault@spatialys.com> | 2020-10-23 00:03:40 +0200 |
| commit | 6351422cc2108072162f7b8cdff12916723ccc20 (patch) | |
| tree | 9394fb47beeb183279d30faba6d531035e596f0a | |
| parent | 4969076c15f73371401ee65f2e4617439239cd8b (diff) | |
| download | PROJ-6351422cc2108072162f7b8cdff12916723ccc20.tar.gz PROJ-6351422cc2108072162f7b8cdff12916723ccc20.zip | |
WKT1_ESRI export: try to export Geographic3D and Projected3D CRS when we can find a corresponding ellipsoidal vertical datum
| -rw-r--r-- | src/iso19111/crs.cpp | 69 | ||||
| -rw-r--r-- | test/unit/test_io.cpp | 41 |
2 files changed, 106 insertions, 4 deletions
diff --git a/src/iso19111/crs.cpp b/src/iso19111/crs.cpp index 4f9098f2..edc8a71f 100644 --- a/src/iso19111/crs.cpp +++ b/src/iso19111/crs.cpp @@ -1578,6 +1578,49 @@ GeodeticCRS::create(const util::PropertyMap &properties, // --------------------------------------------------------------------------- //! @cond Doxygen_Suppress + +// Try to format a Geographic/ProjectedCRS 3D CRS as a +// GEOGCS[]/PROJCS[],VERTCS[...,DATUM[],...] if we find corresponding objects +static bool exportAsESRIWktCompoundCRSWithEllipsoidalHeight( + const CRS *self, const GeodeticCRS *geodCRS, io::WKTFormatter *formatter) { + const auto &dbContext = formatter->databaseContext(); + if (!dbContext) { + return false; + } + const auto l_datum = geodCRS->datumNonNull(formatter->databaseContext()); + auto l_alias = dbContext->getAliasFromOfficialName( + l_datum->nameStr(), "geodetic_datum", "ESRI"); + if (l_alias.empty()) { + return false; + } + auto authFactory = + io::AuthorityFactory::create(NN_NO_CHECK(dbContext), std::string()); + auto list = authFactory->createObjectsFromName( + l_alias, {io::AuthorityFactory::ObjectType::GEODETIC_REFERENCE_FRAME}, + false /* approximate=false*/); + if (list.empty()) { + return false; + } + auto gdatum = util::nn_dynamic_pointer_cast<datum::Datum>(list.front()); + if (gdatum == nullptr || gdatum->identifiers().empty()) { + return false; + } + const auto &gdatum_ids = gdatum->identifiers(); + auto vertCRSList = authFactory->createVerticalCRSFromDatum( + "ESRI", "from_geogdatum_" + *gdatum_ids[0]->codeSpace() + '_' + + gdatum_ids[0]->code()); + if (vertCRSList.size() != 1) { + return false; + } + self->demoteTo2D(std::string(), dbContext)->_exportToWKT(formatter); + vertCRSList.front()->_exportToWKT(formatter); + return true; +} +//! @endcond + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress void GeodeticCRS::_exportToWKT(io::WKTFormatter *formatter) const { const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2; const bool isGeographic = @@ -1589,11 +1632,21 @@ void GeodeticCRS::_exportToWKT(io::WKTFormatter *formatter) const { auto l_name = nameStr(); const auto &dbContext = formatter->databaseContext(); - if (formatter->useESRIDialect()) { - if (axisList.size() != 2) { + if (!isWKT2 && formatter->useESRIDialect() && axisList.size() == 3) { + if (!isGeographic) { io::FormattingException::Throw( - "Only export of Geographic 2D CRS is supported in WKT1_ESRI"); + "Geocentric CRS not supported in WKT1_ESRI"); } + // Try to format the Geographic 3D CRS as a GEOGCS[],VERTCS[...,DATUM[]] + // if we find corresponding objects + if (dbContext) { + if (exportAsESRIWktCompoundCRSWithEllipsoidalHeight(this, this, + formatter)) { + return; + } + } + io::FormattingException::Throw( + "Cannot export this Geographic 3D CRS in WKT1_ESRI"); } if (!isWKT2 && formatter->isStrict() && isGeographic && @@ -3524,6 +3577,16 @@ void ProjectedCRS::_exportToWKT(io::WKTFormatter *formatter) const { } } + if (formatter->useESRIDialect() && dbContext) { + // Try to format the ProjecteD 3D CRS as a + // PROJCS[],VERTCS[...,DATUM[]] + // if we find corresponding objects + if (exportAsESRIWktCompoundCRSWithEllipsoidalHeight( + this, baseCRS().as_nullable().get(), formatter)) { + return; + } + } + if (!formatter->useESRIDialect() && CRS::getPrivate()->allowNonConformantWKT1Export_) { formatter->startNode(io::WKTConstants::COMPD_CS, false); diff --git a/test/unit/test_io.cpp b/test/unit/test_io.cpp index 93b79b67..555d1159 100644 --- a/test/unit/test_io.cpp +++ b/test/unit/test_io.cpp @@ -2764,7 +2764,7 @@ TEST(wkt_parse, VERTCS_with_ellipsoidal_height_ESRI) { // --------------------------------------------------------------------------- -TEST(wkt_parse, implicit_compound_CRS_with_ellipsoidal_height_ESRI) { +TEST(wkt_parse, implicit_compound_CRS_geographic_with_ellipsoidal_height_ESRI) { const char *wkt = "GEOGCS[\"GCS_WGS_1984\",DATUM[\"D_WGS_1984\"," "SPHEROID[\"WGS_1984\",6378137.0,298.257223563]]," @@ -2778,6 +2778,45 @@ TEST(wkt_parse, implicit_compound_CRS_with_ellipsoidal_height_ESRI) { auto crs = nn_dynamic_pointer_cast<GeographicCRS>(obj); ASSERT_TRUE(crs != nullptr); EXPECT_EQ(crs->coordinateSystem()->axisList().size(), 3U); + + EXPECT_EQ( + crs->exportToWKT( + WKTFormatter::create(WKTFormatter::Convention::WKT1_ESRI, dbContext) + .get()), + wkt); +} + +// --------------------------------------------------------------------------- + +TEST(wkt_parse, implicit_compound_CRS_projected_with_ellipsoidal_height_ESRI) { + const char *wkt = + "PROJCS[\"WGS_1984_UTM_Zone_31N\",GEOGCS[\"GCS_WGS_1984\"," + "DATUM[\"D_WGS_1984\"," + "SPHEROID[\"WGS_1984\",6378137.0,298.257223563]]," + "PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]]," + "PROJECTION[\"Transverse_Mercator\"]," + "PARAMETER[\"False_Easting\",500000.0]," + "PARAMETER[\"False_Northing\",0.0]," + "PARAMETER[\"Central_Meridian\",3.0]," + "PARAMETER[\"Scale_Factor\",0.9996]," + "PARAMETER[\"Latitude_Of_Origin\",0.0]," + "UNIT[\"Meter\",1.0]]," + "VERTCS[\"WGS_1984\"," + "DATUM[\"D_WGS_1984\",SPHEROID[\"WGS_1984\",6378137.0,298.257223563]]," + "PARAMETER[\"Vertical_Shift\",0.0]," + "PARAMETER[\"Direction\",1.0]," + "UNIT[\"Meter\",1.0]]"; + auto dbContext = DatabaseContext::create(); + auto obj = WKTParser().attachDatabaseContext(dbContext).createFromWKT(wkt); + auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj); + ASSERT_TRUE(crs != nullptr); + EXPECT_EQ(crs->coordinateSystem()->axisList().size(), 3U); + + EXPECT_EQ( + crs->exportToWKT( + WKTFormatter::create(WKTFormatter::Convention::WKT1_ESRI, dbContext) + .get()), + wkt); } // --------------------------------------------------------------------------- |
