Skip to content

Commit 03fac0e

Browse files
authored
Merge pull request OSGeo#3720 from rouault/esri_polar_stereographic
ESRI WKT: improve roundtrip of name and definition for UPS WGS84 CRS
2 parents ab15a81 + aab4742 commit 03fac0e

File tree

5 files changed

+137
-17
lines changed

5 files changed

+137
-17
lines changed

scripts/build_esri_projection_mapping.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,15 @@
289289
- Scale_Factor: EPSG_NAME_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN
290290
- Latitude_Of_Origin: EPSG_NAME_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN
291291
292+
- Polar_Stereographic_Variant_A:
293+
WKT2_name: EPSG_NAME_METHOD_POLAR_STEREOGRAPHIC_VARIANT_A
294+
Params:
295+
- False_Easting: EPSG_NAME_PARAMETER_FALSE_EASTING
296+
- False_Northing: EPSG_NAME_PARAMETER_FALSE_NORTHING
297+
- Central_Meridian: EPSG_NAME_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN
298+
- Scale_Factor: EPSG_NAME_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN
299+
- Latitude_Of_Origin: EPSG_NAME_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN
300+
292301
- Equidistant_Conic:
293302
WKT2_name: PROJ_WKT2_NAME_METHOD_EQUIDISTANT_CONIC
294303
Params:
@@ -740,7 +749,6 @@
740749
# Missing mappings
741750
742751
# Transverse_Mercator_NGA_2014: utm -- tricky mapping from Central_Meridian to zone
743-
# Polar_Stereographic_Variant_A: ups -- tricky mapping from Latitude_Of_Origin to "+south" when required
744752
# Transverse Mercator: alias for Transverse_Mercator, as seen in ESRI:102470 - ESRI:102489
745753
746754

src/iso19111/io.cpp

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4388,15 +4388,7 @@ WKTParser::Private::buildProjectedCRS(const WKTNodeNNPtr &node) {
43884388

43894389
const std::string projCRSName = stripQuotes(nodeP->children()[0]);
43904390
if (esriStyle_ && dbContext_) {
4391-
// It is likely that the ESRI definition of EPSG:32661 (UPS North) &
4392-
// EPSG:32761 (UPS South) uses the easting-northing order, instead
4393-
// of the EPSG northing-easting order
4394-
// so don't substitute names to avoid confusion.
4395-
if (projCRSName == "UPS_North") {
4396-
props.set(IdentifiedObject::NAME_KEY, "WGS 84 / UPS North (E,N)");
4397-
} else if (projCRSName == "UPS_South") {
4398-
props.set(IdentifiedObject::NAME_KEY, "WGS 84 / UPS South (E,N)");
4399-
} else if (cartesianCS) {
4391+
if (cartesianCS) {
44004392
std::string outTableName;
44014393
std::string authNameFromAlias;
44024394
std::string codeFromAlias;

src/iso19111/operation/conversion.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3085,6 +3085,19 @@ static void getESRIMethodNameAndParams(const Conversion *conv,
30853085
esriParams = paramsESRI_Rectified_Skew_Orthomorphic_Center;
30863086
esriMethodName = "Rectified_Skew_Orthomorphic_Center";
30873087
}
3088+
} else if (esriMapping->epsg_code ==
3089+
EPSG_CODE_METHOD_POLAR_STEREOGRAPHIC_VARIANT_A) {
3090+
// Quite empiric, but looking at pe_list_projcs.csv, the only
3091+
// CRS that use Polar_Stereographic_Variant_A are EPSG:5041 and 5042
3092+
if (l_targetCRS &&
3093+
// EPSG:5041
3094+
(l_targetCRS->nameStr() == "WGS 84 / UPS North (E,N)" ||
3095+
// EPSG:5042
3096+
l_targetCRS->nameStr() == "WGS 84 / UPS South (E,N)")) {
3097+
esriMethodName = "Polar_Stereographic_Variant_A";
3098+
} else {
3099+
esriMethodName = "Stereographic";
3100+
}
30883101
} else if (esriMapping->epsg_code ==
30893102
EPSG_CODE_METHOD_POLAR_STEREOGRAPHIC_VARIANT_B) {
30903103
if (conv->parameterValueNumericAsSI(

src/iso19111/operation/esriparammappings.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,19 @@ static const ESRIParamMapping paramsESRI_Stereographic[] = {
385385
EPSG_CODE_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN, "0.0", false},
386386
{nullptr, nullptr, 0, "0.0", false}};
387387

388+
static const ESRIParamMapping paramsESRI_Polar_Stereographic_Variant_A[] = {
389+
{"False_Easting", EPSG_NAME_PARAMETER_FALSE_EASTING,
390+
EPSG_CODE_PARAMETER_FALSE_EASTING, "0.0", false},
391+
{"False_Northing", EPSG_NAME_PARAMETER_FALSE_NORTHING,
392+
EPSG_CODE_PARAMETER_FALSE_NORTHING, "0.0", false},
393+
{"Central_Meridian", EPSG_NAME_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN,
394+
EPSG_CODE_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN, "0.0", false},
395+
{"Scale_Factor", EPSG_NAME_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN,
396+
EPSG_CODE_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN, "0.0", false},
397+
{"Latitude_Of_Origin", EPSG_NAME_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN,
398+
EPSG_CODE_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN, "0.0", false},
399+
{nullptr, nullptr, 0, "0.0", false}};
400+
388401
static const ESRIParamMapping paramsESRI_Equidistant_Conic[] = {
389402
{"False_Easting", EPSG_NAME_PARAMETER_FALSE_EASTING,
390403
EPSG_CODE_PARAMETER_FALSE_EASTING, "0.0", false},
@@ -1033,6 +1046,10 @@ static const ESRIMethodMapping esriMappings[] = {
10331046
paramsESRI_Hotine_Oblique_Mercator_Two_Point_Natural_Origin},
10341047
{"Stereographic", PROJ_WKT2_NAME_METHOD_STEREOGRAPHIC, 0,
10351048
paramsESRI_Stereographic},
1049+
{"Polar_Stereographic_Variant_A",
1050+
EPSG_NAME_METHOD_POLAR_STEREOGRAPHIC_VARIANT_A,
1051+
EPSG_CODE_METHOD_POLAR_STEREOGRAPHIC_VARIANT_A,
1052+
paramsESRI_Polar_Stereographic_Variant_A},
10361053
{"Equidistant_Conic", PROJ_WKT2_NAME_METHOD_EQUIDISTANT_CONIC, 0,
10371054
paramsESRI_Equidistant_Conic},
10381055
{"Cassini", EPSG_NAME_METHOD_CASSINI_SOLDNER,

test/unit/test_io.cpp

Lines changed: 97 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7307,6 +7307,7 @@ TEST(wkt_parse, wkt1_esri_normalize_unit) {
73077307
// ---------------------------------------------------------------------------
73087308

73097309
TEST(wkt_parse, wkt1_esri_ups_north) {
7310+
// EPSG:32661
73107311
auto wkt = "PROJCS[\"UPS_North\",GEOGCS[\"GCS_WGS_1984\","
73117312
"DATUM[\"D_WGS_1984\","
73127313
"SPHEROID[\"WGS_1984\",6378137.0,298.257223563]],"
@@ -7319,24 +7320,32 @@ TEST(wkt_parse, wkt1_esri_ups_north) {
73197320
"PARAMETER[\"Latitude_Of_Origin\",90.0],"
73207321
"UNIT[\"Meter\",1.0]]";
73217322

7322-
auto obj = WKTParser()
7323-
.attachDatabaseContext(DatabaseContext::create())
7324-
.createFromWKT(wkt);
7323+
auto dbContext = DatabaseContext::create();
7324+
auto obj = WKTParser().attachDatabaseContext(dbContext).createFromWKT(wkt);
73257325
auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj);
73267326
ASSERT_TRUE(crs != nullptr);
73277327

7328-
EXPECT_EQ(crs->nameStr(), "WGS 84 / UPS North (E,N)");
7328+
EXPECT_EQ(crs->nameStr(), "WGS 84 / UPS North (N,E)");
73297329
EXPECT_EQ(crs->coordinateSystem()->axisList()[0]->direction(),
73307330
AxisDirection::SOUTH);
7331+
// Yes, inconsistency between the name (coming from EPSG) and the fact
7332+
// that with ESRI CRS, we always output E, N axis order
73317333
EXPECT_EQ(crs->coordinateSystem()->axisList()[0]->abbreviation(), "E");
73327334
EXPECT_EQ(crs->coordinateSystem()->axisList()[1]->direction(),
73337335
AxisDirection::SOUTH);
73347336
EXPECT_EQ(crs->coordinateSystem()->axisList()[1]->abbreviation(), "N");
7337+
7338+
EXPECT_EQ(
7339+
crs->exportToWKT(
7340+
WKTFormatter::create(WKTFormatter::Convention::WKT1_ESRI, dbContext)
7341+
.get()),
7342+
wkt);
73357343
}
73367344

73377345
// ---------------------------------------------------------------------------
73387346

73397347
TEST(wkt_parse, wkt1_esri_ups_south) {
7348+
// EPSG:32671
73407349
auto wkt = "PROJCS[\"UPS_South\",GEOGCS[\"GCS_WGS_1984\","
73417350
"DATUM[\"D_WGS_1984\","
73427351
"SPHEROID[\"WGS_1984\",6378137.0,298.257223563]],"
@@ -7349,9 +7358,84 @@ TEST(wkt_parse, wkt1_esri_ups_south) {
73497358
"PARAMETER[\"Latitude_Of_Origin\",-90.0],"
73507359
"UNIT[\"Meter\",1.0]]";
73517360

7352-
auto obj = WKTParser()
7353-
.attachDatabaseContext(DatabaseContext::create())
7354-
.createFromWKT(wkt);
7361+
auto dbContext = DatabaseContext::create();
7362+
auto obj = WKTParser().attachDatabaseContext(dbContext).createFromWKT(wkt);
7363+
auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj);
7364+
ASSERT_TRUE(crs != nullptr);
7365+
7366+
EXPECT_EQ(crs->nameStr(), "WGS 84 / UPS South (N,E)");
7367+
EXPECT_EQ(crs->coordinateSystem()->axisList()[0]->direction(),
7368+
AxisDirection::NORTH);
7369+
// Yes, inconsistency between the name (coming from EPSG) and the fact
7370+
// that with ESRI CRS, we always output E, N axis order
7371+
EXPECT_EQ(crs->coordinateSystem()->axisList()[0]->abbreviation(), "E");
7372+
EXPECT_EQ(crs->coordinateSystem()->axisList()[1]->direction(),
7373+
AxisDirection::NORTH);
7374+
EXPECT_EQ(crs->coordinateSystem()->axisList()[1]->abbreviation(), "N");
7375+
7376+
EXPECT_EQ(
7377+
crs->exportToWKT(
7378+
WKTFormatter::create(WKTFormatter::Convention::WKT1_ESRI, dbContext)
7379+
.get()),
7380+
wkt);
7381+
}
7382+
7383+
// ---------------------------------------------------------------------------
7384+
7385+
TEST(wkt_parse, wkt1_esri_wgs_1984_ups_north_E_N) {
7386+
// EPSG:5041
7387+
auto wkt = "PROJCS[\"WGS_1984_UPS_North_(E-N)\","
7388+
"GEOGCS[\"GCS_WGS_1984\",DATUM[\"D_WGS_1984\","
7389+
"SPHEROID[\"WGS_1984\",6378137.0,298.257223563]],"
7390+
"PRIMEM[\"Greenwich\",0.0],"
7391+
"UNIT[\"Degree\",0.0174532925199433]],"
7392+
"PROJECTION[\"Polar_Stereographic_Variant_A\"],"
7393+
"PARAMETER[\"False_Easting\",2000000.0],"
7394+
"PARAMETER[\"False_Northing\",2000000.0],"
7395+
"PARAMETER[\"Central_Meridian\",0.0],"
7396+
"PARAMETER[\"Scale_Factor\",0.994],"
7397+
"PARAMETER[\"Latitude_Of_Origin\",90.0],"
7398+
"UNIT[\"Meter\",1.0]]";
7399+
7400+
auto dbContext = DatabaseContext::create();
7401+
auto obj = WKTParser().attachDatabaseContext(dbContext).createFromWKT(wkt);
7402+
auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj);
7403+
ASSERT_TRUE(crs != nullptr);
7404+
7405+
EXPECT_EQ(crs->nameStr(), "WGS 84 / UPS North (E,N)");
7406+
EXPECT_EQ(crs->coordinateSystem()->axisList()[0]->direction(),
7407+
AxisDirection::SOUTH);
7408+
EXPECT_EQ(crs->coordinateSystem()->axisList()[0]->abbreviation(), "E");
7409+
EXPECT_EQ(crs->coordinateSystem()->axisList()[1]->direction(),
7410+
AxisDirection::SOUTH);
7411+
EXPECT_EQ(crs->coordinateSystem()->axisList()[1]->abbreviation(), "N");
7412+
7413+
EXPECT_EQ(
7414+
crs->exportToWKT(
7415+
WKTFormatter::create(WKTFormatter::Convention::WKT1_ESRI, dbContext)
7416+
.get()),
7417+
wkt);
7418+
}
7419+
7420+
// ---------------------------------------------------------------------------
7421+
7422+
TEST(wkt_parse, wkt1_esri_wgs_1984_ups_south_E_N) {
7423+
// EPSG:5042
7424+
auto wkt = "PROJCS[\"WGS_1984_UPS_South_(E-N)\","
7425+
"GEOGCS[\"GCS_WGS_1984\",DATUM[\"D_WGS_1984\","
7426+
"SPHEROID[\"WGS_1984\",6378137.0,298.257223563]],"
7427+
"PRIMEM[\"Greenwich\",0.0],"
7428+
"UNIT[\"Degree\",0.0174532925199433]],"
7429+
"PROJECTION[\"Polar_Stereographic_Variant_A\"],"
7430+
"PARAMETER[\"False_Easting\",2000000.0],"
7431+
"PARAMETER[\"False_Northing\",2000000.0],"
7432+
"PARAMETER[\"Central_Meridian\",0.0],"
7433+
"PARAMETER[\"Scale_Factor\",0.994],"
7434+
"PARAMETER[\"Latitude_Of_Origin\",-90.0],"
7435+
"UNIT[\"Meter\",1.0]]";
7436+
7437+
auto dbContext = DatabaseContext::create();
7438+
auto obj = WKTParser().attachDatabaseContext(dbContext).createFromWKT(wkt);
73557439
auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj);
73567440
ASSERT_TRUE(crs != nullptr);
73577441

@@ -7362,6 +7446,12 @@ TEST(wkt_parse, wkt1_esri_ups_south) {
73627446
EXPECT_EQ(crs->coordinateSystem()->axisList()[1]->direction(),
73637447
AxisDirection::NORTH);
73647448
EXPECT_EQ(crs->coordinateSystem()->axisList()[1]->abbreviation(), "N");
7449+
7450+
EXPECT_EQ(
7451+
crs->exportToWKT(
7452+
WKTFormatter::create(WKTFormatter::Convention::WKT1_ESRI, dbContext)
7453+
.get()),
7454+
wkt);
73657455
}
73667456

73677457
// ---------------------------------------------------------------------------

0 commit comments

Comments
 (0)