diff options
| author | Even Rouault <even.rouault@spatialys.com> | 2021-04-24 19:07:55 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-04-24 19:07:55 +0200 |
| commit | ea196217fd575a3a4bdc2fb8a094ffcd358f3980 (patch) | |
| tree | 7d796b52ce2ca6ffa6ca3d584fecdab4d70965e0 | |
| parent | 01a5c03c052be14f731b1e96ca3c0005f110aad8 (diff) | |
| parent | 7898eaba1160631405e8d4eccd73254f453bd3d4 (diff) | |
| download | PROJ-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.cpp | 27 | ||||
| -rw-r--r-- | src/iso19111/io.cpp | 69 | ||||
| -rw-r--r-- | test/unit/test_crs.cpp | 26 | ||||
| -rw-r--r-- | test/unit/test_io.cpp | 61 |
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", |
