aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2021-04-24 19:07:55 +0200
committerGitHub <noreply@github.com>2021-04-24 19:07:55 +0200
commitea196217fd575a3a4bdc2fb8a094ffcd358f3980 (patch)
tree7d796b52ce2ca6ffa6ca3d584fecdab4d70965e0
parent01a5c03c052be14f731b1e96ca3c0005f110aad8 (diff)
parent7898eaba1160631405e8d4eccd73254f453bd3d4 (diff)
downloadPROJ-ea196217fd575a3a4bdc2fb8a094ffcd358f3980.tar.gz
PROJ-ea196217fd575a3a4bdc2fb8a094ffcd358f3980.zip
Merge pull request #2696 from rouault/derived_vertical_crs_unit_height_depth
Improvements related to DerivedVerticalCRS using Change Unit and Height/Depth reversal methods
-rw-r--r--src/iso19111/crs.cpp27
-rw-r--r--src/iso19111/io.cpp69
-rw-r--r--test/unit/test_crs.cpp26
-rw-r--r--test/unit/test_io.cpp61
4 files changed, 172 insertions, 11 deletions
diff --git a/src/iso19111/crs.cpp b/src/iso19111/crs.cpp
index 2d589ad1..51317c18 100644
--- a/src/iso19111/crs.cpp
+++ b/src/iso19111/crs.cpp
@@ -6506,6 +6506,33 @@ DerivedVerticalCRSNNPtr DerivedVerticalCRS::create(
void DerivedVerticalCRS::_exportToWKT(io::WKTFormatter *formatter) const {
const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2;
if (!isWKT2) {
+
+ bool useBaseMethod = true;
+ const DerivedVerticalCRS *dvcrs = this;
+ while (true) {
+ // If the derived vertical CRS is obtained through simple conversion
+ // methods that just do unit change or height/depth reversal, export
+ // it as a regular VerticalCRS
+ const int methodCode =
+ dvcrs->derivingConversionRef()->method()->getEPSGCode();
+ if (methodCode == EPSG_CODE_METHOD_CHANGE_VERTICAL_UNIT ||
+ methodCode ==
+ EPSG_CODE_METHOD_CHANGE_VERTICAL_UNIT_NO_CONV_FACTOR ||
+ methodCode == EPSG_CODE_METHOD_HEIGHT_DEPTH_REVERSAL) {
+ dvcrs = dynamic_cast<DerivedVerticalCRS *>(baseCRS().get());
+ if (dvcrs == nullptr) {
+ break;
+ }
+ } else {
+ useBaseMethod = false;
+ break;
+ }
+ }
+ if (useBaseMethod) {
+ VerticalCRS::_exportToWKT(formatter);
+ return;
+ }
+
io::FormattingException::Throw(
"DerivedVerticalCRS can only be exported to WKT2");
}
diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp
index e3da80e0..6ddeed7a 100644
--- a/src/iso19111/io.cpp
+++ b/src/iso19111/io.cpp
@@ -6491,12 +6491,13 @@ static BaseObjectNNPtr createFromUserInput(const std::string &text,
AuthorityFactory::create(NN_NO_CHECK(dbContext), tokensOp[1]);
auto op = factoryOp->createCoordinateOperation(tokensOp[3], true);
- std::string name(baseCRS->nameStr());
+ const auto &baseName = baseCRS->nameStr();
+ std::string name(baseName);
auto geogCRS =
util::nn_dynamic_pointer_cast<GeographicCRS>(baseCRS);
if (geogCRS &&
geogCRS->coordinateSystem()->axisList().size() == 3 &&
- baseCRS->nameStr().find("3D") == std::string::npos) {
+ baseName.find("3D") == std::string::npos) {
name += " (3D)";
}
name += " / ";
@@ -6532,15 +6533,61 @@ static BaseObjectNNPtr createFromUserInput(const std::string &text,
baseCRS)) {
return DerivedProjectedCRS::create(props, NN_NO_CHECK(pcrs),
convNN, cs);
- } else if (dynamic_cast<VerticalCRS *>(baseCRS.get()) &&
- dynamic_cast<VerticalCS *>(cs.get())) {
- return DerivedVerticalCRS::create(
- props,
- NN_NO_CHECK(util::nn_dynamic_pointer_cast<VerticalCRS>(
- baseCRS)),
- convNN,
- NN_NO_CHECK(
- util::nn_dynamic_pointer_cast<VerticalCS>(cs)));
+ } else if (auto vertBaseCRS =
+ util::nn_dynamic_pointer_cast<VerticalCRS>(
+ baseCRS)) {
+ if (auto vertCS =
+ util::nn_dynamic_pointer_cast<VerticalCS>(cs)) {
+ const int methodCode = convNN->method()->getEPSGCode();
+ std::string newName(baseName);
+ std::string unitNameSuffix;
+ for (const char *suffix : {" (ft)", " (ftUS)"}) {
+ if (ends_with(newName, suffix)) {
+ unitNameSuffix = suffix;
+ newName.resize(newName.size() - strlen(suffix));
+ break;
+ }
+ }
+ bool newNameOk = false;
+ if (methodCode ==
+ EPSG_CODE_METHOD_CHANGE_VERTICAL_UNIT_NO_CONV_FACTOR ||
+ methodCode ==
+ EPSG_CODE_METHOD_CHANGE_VERTICAL_UNIT) {
+ const auto &unitName =
+ vertCS->axisList()[0]->unit().name();
+ if (unitName == UnitOfMeasure::METRE.name()) {
+ newNameOk = true;
+ } else if (unitName == UnitOfMeasure::FOOT.name()) {
+ newName += " (ft)";
+ newNameOk = true;
+ } else if (unitName ==
+ UnitOfMeasure::US_FOOT.name()) {
+ newName += " (ftUS)";
+ newNameOk = true;
+ }
+ } else if (methodCode ==
+ EPSG_CODE_METHOD_HEIGHT_DEPTH_REVERSAL) {
+ if (ends_with(newName, " height")) {
+ newName.resize(newName.size() -
+ strlen(" height"));
+ newName += " depth";
+ newName += unitNameSuffix;
+ newNameOk = true;
+ } else if (ends_with(newName, " depth")) {
+ newName.resize(newName.size() -
+ strlen(" depth"));
+ newName += " height";
+ newName += unitNameSuffix;
+ newNameOk = true;
+ }
+ }
+ if (newNameOk) {
+ props.set(IdentifiedObject::NAME_KEY, newName);
+ }
+ return DerivedVerticalCRS::create(
+ props, NN_NO_CHECK(vertBaseCRS), convNN,
+ NN_NO_CHECK(vertCS));
+ }
}
}
diff --git a/test/unit/test_crs.cpp b/test/unit/test_crs.cpp
index 719cd125..614580f2 100644
--- a/test/unit/test_crs.cpp
+++ b/test/unit/test_crs.cpp
@@ -5620,6 +5620,32 @@ TEST(crs, DerivedVerticalCRS_WKT1) {
// ---------------------------------------------------------------------------
+TEST(crs, DerivedVerticalCRS_WKT1_when_simple_derivation) {
+
+ auto derivingConversion =
+ Conversion::createChangeVerticalUnit(PropertyMap().set(
+ IdentifiedObject::NAME_KEY, "Vertical Axis Unit Conversion"));
+
+ auto crs = DerivedVerticalCRS::create(
+ PropertyMap().set(IdentifiedObject::NAME_KEY, "Derived vertCRS"),
+ createVerticalCRS(), derivingConversion,
+ VerticalCS::createGravityRelatedHeight(UnitOfMeasure::FOOT));
+
+ auto expected = "VERT_CS[\"Derived vertCRS\",\n"
+ " VERT_DATUM[\"Ordnance Datum Newlyn\",2005,\n"
+ " AUTHORITY[\"EPSG\",\"5101\"]],\n"
+ " UNIT[\"foot\",0.3048,\n"
+ " AUTHORITY[\"EPSG\",\"9002\"]],\n"
+ " AXIS[\"Gravity-related height\",UP]]";
+
+ EXPECT_EQ(
+ crs->exportToWKT(
+ WKTFormatter::create(WKTFormatter::Convention::WKT1_GDAL).get()),
+ expected);
+}
+
+// ---------------------------------------------------------------------------
+
static DerivedEngineeringCRSNNPtr createDerivedEngineeringCRS() {
auto derivingConversion = Conversion::create(
diff --git a/test/unit/test_io.cpp b/test/unit/test_io.cpp
index 97cdca11..7775416f 100644
--- a/test/unit/test_io.cpp
+++ b/test/unit/test_io.cpp
@@ -10585,6 +10585,7 @@ TEST(io, createFromUserInput) {
EXPECT_EQ(crs->coordinateSystem()->getEPSGCode(), 4400);
EXPECT_EQ(crs->derivingConversion()->getEPSGCode(), 16031);
}
+
{
// DerivedVerticalCRS based on "NAVD88 height", using a foot UP axis,
// and EPSG:7813 "Vertical Axis Unit Conversion" conversion
@@ -10594,12 +10595,72 @@ TEST(io, createFromUserInput) {
dbContext);
auto crs = nn_dynamic_pointer_cast<DerivedVerticalCRS>(obj);
ASSERT_TRUE(crs != nullptr);
+ EXPECT_EQ(crs->nameStr(), "NAVD88 height (ft)");
EXPECT_EQ(crs->baseCRS()->getEPSGCode(), 5703);
EXPECT_EQ(crs->coordinateSystem()->getEPSGCode(), 1030);
EXPECT_EQ(crs->derivingConversion()->getEPSGCode(), 7813);
}
{
+ // DerivedVerticalCRS based on "NAVD88 height", using a ftUS UP axis,
+ // and EPSG:7813 "Vertical Axis Unit Conversion" conversion
+ auto obj = createFromUserInput("urn:ogc:def:crs,crs:EPSG::5703,"
+ "cs:EPSG::6497,"
+ "coordinateOperation:EPSG::7813",
+ dbContext);
+ auto crs = nn_dynamic_pointer_cast<DerivedVerticalCRS>(obj);
+ ASSERT_TRUE(crs != nullptr);
+ EXPECT_EQ(crs->nameStr(), "NAVD88 height (ftUS)");
+ }
+
+ {
+ // DerivedVerticalCRS based on "NAVD88 height (ftUS)", using a metre UP
+ // axis, and EPSG:7813 "Vertical Axis Unit Conversion" conversion
+ auto obj = createFromUserInput("urn:ogc:def:crs,crs:EPSG::6360,"
+ "cs:EPSG::6499,"
+ "coordinateOperation:EPSG::7813",
+ dbContext);
+ auto crs = nn_dynamic_pointer_cast<DerivedVerticalCRS>(obj);
+ ASSERT_TRUE(crs != nullptr);
+ EXPECT_EQ(crs->nameStr(), "NAVD88 height");
+ }
+ {
+ // DerivedVerticalCRS based on "NAVD88 height", using a metre DOWN axis,
+ // and EPSG:7812 "Height / Depth reversal" conversion
+ auto obj = createFromUserInput("urn:ogc:def:crs,crs:EPSG::5703,"
+ "cs:EPSG::6498,"
+ "coordinateOperation:EPSG::7812",
+ dbContext);
+ auto crs = nn_dynamic_pointer_cast<DerivedVerticalCRS>(obj);
+ ASSERT_TRUE(crs != nullptr);
+ EXPECT_EQ(crs->nameStr(), "NAVD88 depth");
+ }
+
+ {
+ // DerivedVerticalCRS based on "NAVD88 height (ftUS)", using a ftUS DOWN
+ // axis, and EPSG:7812 "Height / Depth reversal" conversion
+ auto obj = createFromUserInput("urn:ogc:def:crs,crs:EPSG::6360,"
+ "cs:EPSG::1043,"
+ "coordinateOperation:EPSG::7812",
+ dbContext);
+ auto crs = nn_dynamic_pointer_cast<DerivedVerticalCRS>(obj);
+ ASSERT_TRUE(crs != nullptr);
+ EXPECT_EQ(crs->nameStr(), "NAVD88 depth (ftUS)");
+ }
+
+ {
+ // DerivedVerticalCRS based on "NAVD88 depth (ftUS)", using a ftUS UP
+ // axis, and EPSG:7812 "Height / Depth reversal" conversion
+ auto obj = createFromUserInput("urn:ogc:def:crs,crs:EPSG::6358,"
+ "cs:EPSG::6497,"
+ "coordinateOperation:EPSG::7812",
+ dbContext);
+ auto crs = nn_dynamic_pointer_cast<DerivedVerticalCRS>(obj);
+ ASSERT_TRUE(crs != nullptr);
+ EXPECT_EQ(crs->nameStr(), "NAVD88 height (ftUS)");
+ }
+
+ {
auto obj = createFromUserInput("urn:ogc:def:coordinateOperation,"
"coordinateOperation:EPSG::3895,"
"coordinateOperation:EPSG::1618",