Skip to content

Commit

Permalink
DerivedProjetedCRS WKT export: emit a BASEPROJCRS.CS node in situatio…
Browse files Browse the repository at this point in the history
…ns where there's ambiguity

Cf OSGeo/gdal#9732 (comment)
  • Loading branch information
rouault authored and github-actions[bot] committed May 7, 2024
1 parent 7673547 commit ee6a519
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 7 deletions.
31 changes: 31 additions & 0 deletions src/iso19111/crs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6740,6 +6740,37 @@ void DerivedProjectedCRS::_exportToWKT(io::WKTFormatter *formatter) const {
formatter->endNode();

l_baseProjCRS->derivingConversionRef()->_exportToWKT(formatter);

const auto &baseCSAxisList =
l_baseProjCRS->coordinateSystem()->axisList();
// Current WKT grammar (as of WKT2 18-010r11) does not allow a
// BASEPROJCRS.CS node, but in situations where this is ambiguous, emit
// one. Cf WKTParser::Private::buildProjectedCRS() for more details
if (!baseCSAxisList.empty() &&
baseCSAxisList[0]->unit() != common::UnitOfMeasure::METRE &&
l_baseProjCRS->identifiers().empty()) {
bool knownBaseCRS = false;
auto &dbContext = formatter->databaseContext();
if (dbContext) {
auto authFactory = io::AuthorityFactory::create(
NN_NO_CHECK(dbContext), std::string());
auto res = authFactory->createObjectsFromName(
l_baseProjCRS->nameStr(),
{io::AuthorityFactory::ObjectType::PROJECTED_CRS}, false,
2);
if (res.size() == 1) {
knownBaseCRS = true;
}
}
if (!knownBaseCRS) {
l_baseProjCRS->coordinateSystem()->_exportToWKT(formatter);
}
}

if (identifiers().empty() && !l_baseProjCRS->identifiers().empty()) {
l_baseProjCRS->formatID(formatter);
}

formatter->endNode();
}

Expand Down
3 changes: 2 additions & 1 deletion test/unit/test_crs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5855,7 +5855,8 @@ TEST(crs, derivedProjectedCRS_WKT2_2019) {
" ID[\"EPSG\",8806]],\n"
" PARAMETER[\"False northing\",0,\n"
" LENGTHUNIT[\"metre\",1],\n"
" ID[\"EPSG\",8807]]]],\n"
" ID[\"EPSG\",8807]]],\n"
" ID[\"EPSG\",32631]],\n"
" DERIVINGCONVERSION[\"unnamed\",\n"
" METHOD[\"PROJ unimplemented\"]],\n"
" CS[Cartesian,2],\n"
Expand Down
96 changes: 90 additions & 6 deletions test/unit/test_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5706,6 +5706,80 @@ TEST(wkt_parse, DerivedProjectedCRS_base_crs_cs_non_metre_from_conversion) {
const auto &axisList = crs->baseCRS()->coordinateSystem()->axisList();
ASSERT_EQ(axisList.size(), 2U);
EXPECT_EQ(axisList[0]->unit(), UnitOfMeasure::US_FOOT);

// Check that we emit a BASEPROJCRS.CS node
const char *expected =
"DERIVEDPROJCRS[\"Ground for NAD83(2011) / Idaho West (ftUS)\",\n"
" BASEPROJCRS[\"foo\",\n"
" BASEGEOGCRS[\"NAD83(2011)\",\n"
" DATUM[\"NAD83 (National Spatial Reference System "
"2011)\",\n"
" ELLIPSOID[\"GRS 1980\",6378137,298.257222101,\n"
" LENGTHUNIT[\"metre\",1]]],\n"
" PRIMEM[\"Greenwich\",0,\n"
" ANGLEUNIT[\"degree\",0.0174532925199433]]],\n"
" CONVERSION[\"SPCS83 Idaho West zone (US Survey feet)\",\n"
" METHOD[\"Transverse Mercator\",\n"
" ID[\"EPSG\",9807]],\n"
" PARAMETER[\"Latitude of natural "
"origin\",41.6666666666667,\n"
" ANGLEUNIT[\"degree\",0.0174532925199433],\n"
" ID[\"EPSG\",8801]],\n"
" PARAMETER[\"Longitude of natural origin\",-115.75,\n"
" ANGLEUNIT[\"degree\",0.0174532925199433],\n"
" ID[\"EPSG\",8802]],\n"
" PARAMETER[\"Scale factor at natural "
"origin\",0.999933333,\n"
" SCALEUNIT[\"unity\",1],\n"
" ID[\"EPSG\",8805]],\n"
" PARAMETER[\"False easting\",2624666.667,\n"
" LENGTHUNIT[\"US survey foot\",0.304800609601219],\n"
" ID[\"EPSG\",8806]],\n"
" PARAMETER[\"False northing\",0,\n"
" LENGTHUNIT[\"US survey foot\",0.304800609601219],\n"
" ID[\"EPSG\",8807]]],\n"
" CS[Cartesian,2],\n"
" AXIS[\"(E)\",east,\n"
" ORDER[1],\n"
" LENGTHUNIT[\"US survey foot\",0.304800609601219]],\n"
" AXIS[\"(N)\",north,\n"
" ORDER[2],\n"
" LENGTHUNIT[\"US survey foot\",0.304800609601219]]],\n"
" DERIVINGCONVERSION[\"Grid to ground\",\n"
" METHOD[\"Similarity transformation\",\n"
" ID[\"EPSG\",9621]],\n"
" PARAMETER[\"Ordinate 1 of evaluation point in target "
"CRS\",1000,\n"
" LENGTHUNIT[\"US survey foot\",0.304800609601219],\n"
" ID[\"EPSG\",8621]],\n"
" PARAMETER[\"Ordinate 2 of evaluation point in target "
"CRS\",0,\n"
" LENGTHUNIT[\"US survey foot\",0.304800609601219],\n"
" ID[\"EPSG\",8622]],\n"
" PARAMETER[\"Scale factor for source CRS axes\",1,\n"
" SCALEUNIT[\"unity\",1],\n"
" ID[\"EPSG\",1061]],\n"
" PARAMETER[\"Rotation angle of source CRS axes\",0,\n"
" ANGLEUNIT[\"degree\",0],\n"
" ID[\"EPSG\",8614]]],\n"
" CS[Cartesian,2],\n"
" AXIS[\"easting (X)\",east,\n"
" ORDER[1],\n"
" LENGTHUNIT[\"US survey foot\",0.304800609601219]],\n"
" AXIS[\"northing (Y)\",north,\n"
" ORDER[2],\n"
" LENGTHUNIT[\"US survey foot\",0.304800609601219]]]";
EXPECT_EQ(
crs->exportToWKT(
WKTFormatter::create(WKTFormatter::Convention::WKT2_2019).get()),
expected);

auto dbContext = DatabaseContext::create();
EXPECT_EQ(
crs->exportToWKT(
WKTFormatter::create(WKTFormatter::Convention::WKT2_2019, dbContext)
.get()),
expected);
}

// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -5751,15 +5825,20 @@ TEST(
" ORDER[2],\n"
" LENGTHUNIT[\"US survey foot\",0.304800609601219]]]";

auto obj = WKTParser()
.attachDatabaseContext(DatabaseContext::create())
.createFromWKT(wkt);
auto dbContext = DatabaseContext::create();
auto obj = WKTParser().attachDatabaseContext(dbContext).createFromWKT(wkt);
auto crs = nn_dynamic_pointer_cast<DerivedProjectedCRS>(obj);
ASSERT_TRUE(crs != nullptr);

const auto &axisList = crs->baseCRS()->coordinateSystem()->axisList();
ASSERT_EQ(axisList.size(), 2U);
EXPECT_EQ(axisList[0]->unit(), UnitOfMeasure::US_FOOT);

EXPECT_EQ(
crs->exportToWKT(
WKTFormatter::create(WKTFormatter::Convention::WKT2_2019, dbContext)
.get()),
wkt);
}

// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -5806,15 +5885,20 @@ TEST(
" ORDER[2],\n"
" LENGTHUNIT[\"US survey foot\",0.304800609601219]]]";

auto obj = WKTParser()
.attachDatabaseContext(DatabaseContext::create())
.createFromWKT(wkt);
auto dbContext = DatabaseContext::create();
auto obj = WKTParser().attachDatabaseContext(dbContext).createFromWKT(wkt);
auto crs = nn_dynamic_pointer_cast<DerivedProjectedCRS>(obj);
ASSERT_TRUE(crs != nullptr);

const auto &axisList = crs->baseCRS()->coordinateSystem()->axisList();
ASSERT_EQ(axisList.size(), 2U);
EXPECT_EQ(axisList[0]->unit(), UnitOfMeasure::US_FOOT);

EXPECT_EQ(
crs->exportToWKT(
WKTFormatter::create(WKTFormatter::Convention::WKT2_2019, dbContext)
.get()),
wkt);
}

// ---------------------------------------------------------------------------
Expand Down

0 comments on commit ee6a519

Please sign in to comment.