aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2021-08-16 21:08:25 +0200
committergithub-actions[bot] <github-actions[bot]@users.noreply.github.com>2021-08-16 20:07:24 +0000
commitac3b405df6c238adc50f2d19cdd188338b73ab93 (patch)
tree6cdf1fcc3dba369df7884ab7826f3381b601bba1
parent2924282425cdc953c8e1843e25f7376ece309e11 (diff)
downloadPROJ-ac3b405df6c238adc50f2d19cdd188338b73ab93.tar.gz
PROJ-ac3b405df6c238adc50f2d19cdd188338b73ab93.zip
Merge pull request #2809 from rouault/preserve_proj4_crs_string_wkt2_remarks
WKT2 import/export: preserve PROJ.4 CRS extension string in REMARKS[]…
-rw-r--r--include/proj/crs.hpp4
-rw-r--r--src/iso19111/crs.cpp67
-rw-r--r--test/unit/test_io.cpp71
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");
+}