diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index 09437d3dcf..241accf0fb 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -5145,6 +5145,13 @@ WKTParser::Private::buildDerivedProjectedCRS(const WKTNodeNNPtr &node) { ThrowMissing(WKTConstants::CS_); } auto cs = buildCS(csNode, node, UnitOfMeasure::NONE); + + if (cs->axisList().size() == 3 && + baseProjCRS->coordinateSystem()->axisList().size() == 2) { + baseProjCRS = NN_NO_CHECK(util::nn_dynamic_pointer_cast( + baseProjCRS->promoteTo3D(std::string(), dbContext_))); + } + return DerivedProjectedCRS::create(buildProperties(node), baseProjCRS, conversion, cs); } diff --git a/test/unit/test_crs.cpp b/test/unit/test_crs.cpp index 3112cb6702..bfaa4a4d75 100644 --- a/test/unit/test_crs.cpp +++ b/test/unit/test_crs.cpp @@ -6853,6 +6853,21 @@ TEST(crs, promoteTo3D_and_demoteTo2D) { EXPECT_TRUE(crs3DAsDerivedProj->promoteTo3D(std::string(), nullptr) ->isEquivalentTo(crs3DAsDerivedProj.get())); + // Check that importing an exported DerivedProjected 3D CRS as WKT keeps + // the 3D aspect of the baseCRS (see #3340) + { + WKTFormatterNNPtr f( + WKTFormatter::create(WKTFormatter::Convention::WKT2_2019)); + crs3DAsDerivedProj->exportToWKT(f.get()); + auto obj = WKTParser().createFromWKT(f->toString()); + auto crsFromWkt = nn_dynamic_pointer_cast(obj); + ASSERT_TRUE(crsFromWkt != nullptr); + EXPECT_EQ(crsFromWkt->coordinateSystem()->axisList().size(), 3U); + EXPECT_EQ( + crsFromWkt->baseCRS()->coordinateSystem()->axisList().size(), + 3U); + } + auto demoted = crs3DAsDerivedProj->demoteTo2D(std::string(), dbContext); EXPECT_EQ(demoted->baseCRS()->coordinateSystem()->axisList().size(), 2U);