Skip to content

Commit

Permalink
WKT1 ESRI import/export: fix GCS name for EPSG:8353 S-JTSK_[JTSK03]_K…
Browse files Browse the repository at this point in the history
…rovak_East_North
  • Loading branch information
rouault committed Aug 17, 2023
1 parent c5c7e64 commit 57a1eab
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 1 deletion.
2 changes: 1 addition & 1 deletion scripts/build_db_from_esri.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ def get_old_esri_name(s):
"""Massage datum/CRS name like old ESRI software did"""

# Needed for EPSG:8353 S_JTSK_JTSK03_Krovak_East_North
# Cf https://github.com/OSGeo/gdal/issues/75054
# Cf https://github.com/OSGeo/gdal/issues/7505
if '[' in s:
s = s.replace('-', '_')
s = s.replace('[', '')
Expand Down
36 changes: 36 additions & 0 deletions src/iso19111/factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3404,6 +3404,25 @@ std::string DatabaseContext::getOldProjGridName(const std::string &gridName) {

// ---------------------------------------------------------------------------

// scripts/build_db_from_esri.py adds a second alias for
// names that have '[' in them. See get_old_esri_name()
// in scripts/build_db_from_esri.py
// So if we only have two aliases detect that situation to get the official
// new name
static std::string getUniqueEsriAlias(const std::list<std::string> &l) {
std::string first = l.front();
std::string second = *(std::next(l.begin()));
if (second.find('[') != std::string::npos)
std::swap(first, second);
if (replaceAll(replaceAll(replaceAll(first, "[", ""), "]", ""), "-", "_") ==
second) {
return first;
}
return std::string();
}

// ---------------------------------------------------------------------------

/** \brief Gets the alias name from an official name.
*
* @param officialName Official name. Mandatory
Expand Down Expand Up @@ -3452,6 +3471,14 @@ DatabaseContext::getAliasFromOfficialName(const std::string &officialName,
"auth_name = ? AND code = ? AND source = ?",
{genuineTableName, row[0], row[1], source});
if (!res2.empty()) {
if (res2.size() == 2 && source == "ESRI") {
std::list<std::string> l;
l.emplace_back(res2.front()[0]);
l.emplace_back((*(std::next(res2.begin())))[0]);
const auto uniqueEsriAlias = getUniqueEsriAlias(l);
if (!uniqueEsriAlias.empty())
return uniqueEsriAlias;
}
return res2.front()[0];
}
}
Expand Down Expand Up @@ -3527,6 +3554,15 @@ std::list<std::string> DatabaseContext::getAliases(
for (const auto &row : resSql) {
res.emplace_back(row[0]);
}

if (res.size() == 2 && source == "ESRI") {
const auto uniqueEsriAlias = getUniqueEsriAlias(res);
if (!uniqueEsriAlias.empty()) {
res.clear();
res.emplace_back(uniqueEsriAlias);
}
}

d->cacheAliasNames_.insert(key, res);
return res;
}
Expand Down
15 changes: 15 additions & 0 deletions src/iso19111/io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3125,6 +3125,21 @@ WKTParser::Private::buildGeodeticCRS(const WKTNodeNNPtr &node) {
props.set("IMPLICIT_CS", true);
}

const std::string crsName = stripQuotes(nodeP->children()[0]);
if (esriStyle_ && dbContext_) {
std::string outTableName;
std::string authNameFromAlias;
std::string codeFromAlias;
auto authFactory =
AuthorityFactory::create(NN_NO_CHECK(dbContext_), std::string());
auto officialName = authFactory->getOfficialNameFromAlias(
crsName, "geodetic_crs", "ESRI", false, outTableName,
authNameFromAlias, codeFromAlias);
if (!officialName.empty()) {
props.set(IdentifiedObject::NAME_KEY, officialName);
}
}

auto datum =
!isNull(datumNode)
? buildGeodeticReferenceFrame(datumNode, primeMeridian, dynamicNode)
Expand Down
115 changes: 115 additions & 0 deletions test/unit/test_crs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2407,6 +2407,121 @@ TEST(crs, projectedCRS_from_WKT1_ESRI_as_WKT1_ESRI) {

// ---------------------------------------------------------------------------

TEST(crs, projectedCRS_from_WKT1_ESRI_as_WKT1_ESRI_s_jtsk03_krovak_east_north) {
// EPSG:8353
auto wkt = "PROJCS[\"S-JTSK_[JTSK03]_Krovak_East_North\","
"GEOGCS[\"S-JTSK_[JTSK03]\",DATUM[\"S-JTSK_[JTSK03]\","
"SPHEROID[\"Bessel_1841\",6377397.155,299.1528128]],"
"PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],"
"PROJECTION[\"Krovak\"],"
"PARAMETER[\"False_Easting\",0.0],"
"PARAMETER[\"False_Northing\",0.0],"
"PARAMETER[\"Pseudo_Standard_Parallel_1\",78.5],"
"PARAMETER[\"Scale_Factor\",0.9999],"
"PARAMETER[\"Azimuth\",30.2881397527778],"
"PARAMETER[\"Longitude_Of_Center\",24.8333333333333],"
"PARAMETER[\"Latitude_Of_Center\",49.5],"
"PARAMETER[\"X_Scale\",-1.0],"
"PARAMETER[\"Y_Scale\",1.0],"
"PARAMETER[\"XY_Plane_Rotation\",90.0],"
"UNIT[\"Meter\",1.0]]";

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

auto expected_wkt2 =
"PROJCRS[\"S-JTSK [JTSK03] / Krovak East North\",\n"
" BASEGEOGCRS[\"S-JTSK [JTSK03]\",\n"
" DATUM[\"System of the Unified Trigonometrical Cadastral "
"Network [JTSK03]\",\n"
" ELLIPSOID[\"Bessel 1841\",6377397.155,299.1528128,\n"
" LENGTHUNIT[\"metre\",1]],\n"
" ID[\"EPSG\",1201]],\n"
" PRIMEM[\"Greenwich\",0,\n"
" ANGLEUNIT[\"Degree\",0.0174532925199433]]],\n"
" CONVERSION[\"unnamed\",\n"
" METHOD[\"Krovak (North Orientated)\",\n"
" ID[\"EPSG\",1041]],\n"
" PARAMETER[\"Latitude of projection centre\",49.5,\n"
" ANGLEUNIT[\"Degree\",0.0174532925199433],\n"
" ID[\"EPSG\",8811]],\n"
" PARAMETER[\"Longitude of origin\",24.8333333333333,\n"
" ANGLEUNIT[\"Degree\",0.0174532925199433],\n"
" ID[\"EPSG\",8833]],\n"
" PARAMETER[\"Co-latitude of cone axis\",30.2881397527778,\n"
" ANGLEUNIT[\"Degree\",0.0174532925199433],\n"
" ID[\"EPSG\",1036]],\n"
" PARAMETER[\"Latitude of pseudo standard parallel\",78.5,\n"
" ANGLEUNIT[\"Degree\",0.0174532925199433],\n"
" ID[\"EPSG\",8818]],\n"
" PARAMETER[\"Scale factor on pseudo standard "
"parallel\",0.9999,\n"
" SCALEUNIT[\"unity\",1],\n"
" ID[\"EPSG\",8819]],\n"
" PARAMETER[\"False easting\",0,\n"
" LENGTHUNIT[\"metre\",1],\n"
" ID[\"EPSG\",8806]],\n"
" PARAMETER[\"False northing\",0,\n"
" LENGTHUNIT[\"metre\",1],\n"
" ID[\"EPSG\",8807]]],\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]]]]";

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

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

// ---------------------------------------------------------------------------

TEST(crs, projectedCRS_from_EPSG_as_WKT1_ESRI_s_jtsk03_krovak_east_north) {
auto dbContext = DatabaseContext::create();
auto factoryEPSG = AuthorityFactory::create(dbContext, "EPSG");
auto crs = factoryEPSG->createProjectedCRS("8353");

auto wkt = "PROJCS[\"S-JTSK_[JTSK03]_Krovak_East_North\","
"GEOGCS[\"S-JTSK_[JTSK03]\",DATUM[\"S-JTSK_[JTSK03]\","
"SPHEROID[\"Bessel_1841\",6377397.155,299.1528128]],"
"PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],"
"PROJECTION[\"Krovak\"],"
"PARAMETER[\"False_Easting\",0.0],"
"PARAMETER[\"False_Northing\",0.0],"
"PARAMETER[\"Pseudo_Standard_Parallel_1\",78.5],"
"PARAMETER[\"Scale_Factor\",0.9999],"
"PARAMETER[\"Azimuth\",30.2881397527778],"
"PARAMETER[\"Longitude_Of_Center\",24.8333333333333],"
"PARAMETER[\"Latitude_Of_Center\",49.5],"
"PARAMETER[\"X_Scale\",-1.0],"
"PARAMETER[\"Y_Scale\",1.0],"
"PARAMETER[\"XY_Plane_Rotation\",90.0],"
"UNIT[\"Meter\",1.0]]";

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

// ---------------------------------------------------------------------------

TEST(crs, projectedCRS_as_PROJ_string) {
auto crs = createProjected();

Expand Down

0 comments on commit 57a1eab

Please sign in to comment.