diff options
| author | Even Rouault <even.rouault@spatialys.com> | 2021-08-17 10:11:05 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-08-17 10:11:05 +0200 |
| commit | b8ab9150834257bcb197ca73b5a81eef7becdbdc (patch) | |
| tree | 6cdf1fcc3dba369df7884ab7826f3381b601bba1 | |
| parent | 2924282425cdc953c8e1843e25f7376ece309e11 (diff) | |
| parent | ac3b405df6c238adc50f2d19cdd188338b73ab93 (diff) | |
| download | PROJ-b8ab9150834257bcb197ca73b5a81eef7becdbdc.tar.gz PROJ-b8ab9150834257bcb197ca73b5a81eef7becdbdc.zip | |
Merge pull request #2812 from OSGeo/backport-2809-to-8.1
[Backport 8.1] WKT2 import/export: preserve PROJ.4 CRS extension string in REMARKS[]…
| -rw-r--r-- | include/proj/crs.hpp | 4 | ||||
| -rw-r--r-- | src/iso19111/crs.cpp | 67 | ||||
| -rw-r--r-- | test/unit/test_io.cpp | 71 |
3 files changed, 134 insertions, 8 deletions
diff --git a/include/proj/crs.hpp b/include/proj/crs.hpp index 44dda0c5..481667b5 100644 --- a/include/proj/crs.hpp +++ b/include/proj/crs.hpp @@ -173,6 +173,10 @@ class PROJ_GCC_DLL CRS : public common::ObjectUsage, PROJ_INTERNAL virtual std::list<std::pair<CRSNNPtr, int>> _identify(const io::AuthorityFactoryPtr &authorityFactory) const; + PROJ_INTERNAL void + setProperties(const util::PropertyMap + &properties); // throw(InvalidValueTypeException) + private: PROJ_OPAQUE_PRIVATE_DATA }; diff --git a/src/iso19111/crs.cpp b/src/iso19111/crs.cpp index 62bb24c3..942e2d43 100644 --- a/src/iso19111/crs.cpp +++ b/src/iso19111/crs.cpp @@ -825,6 +825,64 @@ bool CRS::mustAxisOrderBeSwitchedForVisualization() const { //! @cond Doxygen_Suppress +void CRS::setProperties( + const util::PropertyMap &properties) // throw(InvalidValueTypeException) +{ + std::string l_remarks; + std::string extensionProj4; + properties.getStringValue(IdentifiedObject::REMARKS_KEY, l_remarks); + properties.getStringValue("EXTENSION_PROJ4", extensionProj4); + + const char *PROJ_CRS_STRING_PREFIX = "PROJ CRS string: "; + const char *PROJ_CRS_STRING_SUFFIX = ". "; + const auto beginOfProjStringPos = l_remarks.find(PROJ_CRS_STRING_PREFIX); + if (beginOfProjStringPos == std::string::npos && extensionProj4.empty()) { + ObjectUsage::setProperties(properties); + return; + } + + util::PropertyMap newProperties(properties); + + // Parse remarks and extract EXTENSION_PROJ4 from it + if (extensionProj4.empty()) { + if (beginOfProjStringPos != std::string::npos) { + const auto endOfProjStringPos = + l_remarks.find(PROJ_CRS_STRING_SUFFIX, beginOfProjStringPos); + if (endOfProjStringPos == std::string::npos) { + extensionProj4 = l_remarks.substr( + beginOfProjStringPos + strlen(PROJ_CRS_STRING_PREFIX)); + } else { + extensionProj4 = l_remarks.substr( + beginOfProjStringPos + strlen(PROJ_CRS_STRING_PREFIX), + endOfProjStringPos - beginOfProjStringPos - + strlen(PROJ_CRS_STRING_PREFIX)); + } + } + } + + if (!extensionProj4.empty()) { + if (beginOfProjStringPos == std::string::npos) { + // Add EXTENSION_PROJ4 to remarks + l_remarks = + PROJ_CRS_STRING_PREFIX + extensionProj4 + + (l_remarks.empty() ? std::string() + : PROJ_CRS_STRING_SUFFIX + l_remarks); + } + } + + newProperties.set(IdentifiedObject::REMARKS_KEY, l_remarks); + + ObjectUsage::setProperties(newProperties); + + d->extensionProj4_ = extensionProj4; +} + +//! @endcond + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress + CRSNNPtr CRS::normalizeForVisualization() const { const auto createProperties = [this](const std::string &newName = @@ -1610,8 +1668,6 @@ GeodeticCRS::create(const util::PropertyMap &properties, GeodeticCRS::nn_make_shared<GeodeticCRS>(datum, datumEnsemble, cs)); crs->assignSelf(crs); crs->setProperties(properties); - properties.getStringValue("EXTENSION_PROJ4", - crs->CRS::getPrivate()->extensionProj4_); return crs; } @@ -1657,8 +1713,7 @@ GeodeticCRS::create(const util::PropertyMap &properties, GeodeticCRS::nn_make_shared<GeodeticCRS>(datum, datumEnsemble, cs)); crs->assignSelf(crs); crs->setProperties(properties); - properties.getStringValue("EXTENSION_PROJ4", - crs->CRS::getPrivate()->extensionProj4_); + return crs; } @@ -2574,8 +2629,6 @@ GeographicCRS::create(const util::PropertyMap &properties, GeographicCRS::nn_make_shared<GeographicCRS>(datum, datumEnsemble, cs)); crs->assignSelf(crs); crs->setProperties(properties); - properties.getStringValue("EXTENSION_PROJ4", - crs->CRS::getPrivate()->extensionProj4_); crs->CRS::getPrivate()->setImplicitCS(properties); return crs; } @@ -4049,8 +4102,6 @@ ProjectedCRS::create(const util::PropertyMap &properties, crs->assignSelf(crs); crs->setProperties(properties); crs->setDerivingConversionCRS(); - properties.getStringValue("EXTENSION_PROJ4", - crs->CRS::getPrivate()->extensionProj4_); crs->CRS::getPrivate()->setImplicitCS(properties); return crs; } diff --git a/test/unit/test_io.cpp b/test/unit/test_io.cpp index 95b9a4c3..98ac5aa0 100644 --- a/test/unit/test_io.cpp +++ b/test/unit/test_io.cpp @@ -13717,3 +13717,74 @@ TEST(json_export, coordinate_system_id) { EXPECT_EQ(cs->exportToJSON(&(JSONFormatter::create()->setSchema("foo"))), json); } + +// --------------------------------------------------------------------------- + +TEST(io, EXTENSION_PROJ4) { + // Check that the PROJ string is preserved in the remarks + auto obj = PROJStringParser().createFromPROJString( + "+proj=utm +datum=NAD27 +zone=11 +over +type=crs"); + auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj); + ASSERT_TRUE(crs != nullptr); + EXPECT_EQ(crs->remarks(), + "PROJ CRS string: +proj=utm +datum=NAD27 +zone=11 +over"); + + // Chat that the PROJ string is detected when ingesting a WKT2 with + // a REMARKS node that contains it + auto wkt2 = crs->exportToWKT(WKTFormatter::create().get()); + auto obj2 = WKTParser().createFromWKT(wkt2); + auto crs2 = nn_dynamic_pointer_cast<ProjectedCRS>(obj2); + ASSERT_TRUE(crs2 != nullptr); + EXPECT_EQ(crs2->exportToPROJString(PROJStringFormatter::create().get()), + "+proj=utm +datum=NAD27 +zone=11 +over +type=crs"); + + // Chat that the PROJ string is detected when ingesting a WKT2 with + // a REMARKS node that contains it (in the middle of the remarks) + auto wkt3 = + "PROJCRS[\"unknown\",\n" + " BASEGEOGCRS[\"unknown\",\n" + " DATUM[\"North American Datum 1927\",\n" + " ELLIPSOID[\"Clarke 1866\",6378206.4,294.978698213898,\n" + " LENGTHUNIT[\"metre\",1]],\n" + " ID[\"EPSG\",6267]],\n" + " PRIMEM[\"Greenwich\",0,\n" + " ANGLEUNIT[\"degree\",0.0174532925199433],\n" + " ID[\"EPSG\",8901]]],\n" + " CONVERSION[\"UTM zone 11N\",\n" + " METHOD[\"Transverse Mercator\",\n" + " ID[\"EPSG\",9807]],\n" + " PARAMETER[\"Latitude of natural origin\",0,\n" + " ANGLEUNIT[\"degree\",0.0174532925199433],\n" + " ID[\"EPSG\",8801]],\n" + " PARAMETER[\"Longitude of natural origin\",-117,\n" + " ANGLEUNIT[\"degree\",0.0174532925199433],\n" + " ID[\"EPSG\",8802]],\n" + " PARAMETER[\"Scale factor at natural origin\",0.9996,\n" + " SCALEUNIT[\"unity\",1],\n" + " ID[\"EPSG\",8805]],\n" + " PARAMETER[\"False easting\",500000,\n" + " LENGTHUNIT[\"metre\",1],\n" + " ID[\"EPSG\",8806]],\n" + " PARAMETER[\"False northing\",0,\n" + " LENGTHUNIT[\"metre\",1],\n" + " ID[\"EPSG\",8807]],\n" + " ID[\"EPSG\",16011]],\n" + " CS[Cartesian,2],\n" + " AXIS[\"(E)\",east,\n" + " ORDER[1],\n" + " LENGTHUNIT[\"metre\",1,\n" + " ID[\"EPSG\",9001]]],\n" + " AXIS[\"(N)\",north,\n" + " ORDER[2],\n" + " LENGTHUNIT[\"metre\",1,\n" + " ID[\"EPSG\",9001]]],\n" + " REMARK[\"Prefix. PROJ CRS string: +proj=utm +datum=NAD27 +zone=11 " + "+over. Suffix\"]]"; + auto obj3 = WKTParser().createFromWKT(wkt3); + auto crs3 = nn_dynamic_pointer_cast<ProjectedCRS>(obj3); + ASSERT_TRUE(crs3 != nullptr); + EXPECT_EQ(crs3->remarks(), "Prefix. PROJ CRS string: +proj=utm " + "+datum=NAD27 +zone=11 +over. Suffix"); + EXPECT_EQ(crs3->exportToPROJString(PROJStringFormatter::create().get()), + "+proj=utm +datum=NAD27 +zone=11 +over +type=crs"); +} |
