Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ESRI WKT: improve roundtrip of name and definition for UPS WGS84 CRS #3720

Merged
merged 2 commits into from
May 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion scripts/build_esri_projection_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,15 @@
- Scale_Factor: EPSG_NAME_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN
- Latitude_Of_Origin: EPSG_NAME_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN

- Polar_Stereographic_Variant_A:
WKT2_name: EPSG_NAME_METHOD_POLAR_STEREOGRAPHIC_VARIANT_A
Params:
- False_Easting: EPSG_NAME_PARAMETER_FALSE_EASTING
- False_Northing: EPSG_NAME_PARAMETER_FALSE_NORTHING
- Central_Meridian: EPSG_NAME_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN
- Scale_Factor: EPSG_NAME_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN
- Latitude_Of_Origin: EPSG_NAME_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN

- Equidistant_Conic:
WKT2_name: PROJ_WKT2_NAME_METHOD_EQUIDISTANT_CONIC
Params:
Expand Down Expand Up @@ -740,7 +749,6 @@
# Missing mappings

# Transverse_Mercator_NGA_2014: utm -- tricky mapping from Central_Meridian to zone
# Polar_Stereographic_Variant_A: ups -- tricky mapping from Latitude_Of_Origin to "+south" when required
# Transverse Mercator: alias for Transverse_Mercator, as seen in ESRI:102470 - ESRI:102489


Expand Down
10 changes: 1 addition & 9 deletions src/iso19111/io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4388,15 +4388,7 @@ WKTParser::Private::buildProjectedCRS(const WKTNodeNNPtr &node) {

const std::string projCRSName = stripQuotes(nodeP->children()[0]);
if (esriStyle_ && dbContext_) {
// It is likely that the ESRI definition of EPSG:32661 (UPS North) &
// EPSG:32761 (UPS South) uses the easting-northing order, instead
// of the EPSG northing-easting order
// so don't substitute names to avoid confusion.
if (projCRSName == "UPS_North") {
props.set(IdentifiedObject::NAME_KEY, "WGS 84 / UPS North (E,N)");
} else if (projCRSName == "UPS_South") {
props.set(IdentifiedObject::NAME_KEY, "WGS 84 / UPS South (E,N)");
} else if (cartesianCS) {
if (cartesianCS) {
std::string outTableName;
std::string authNameFromAlias;
std::string codeFromAlias;
Expand Down
13 changes: 13 additions & 0 deletions src/iso19111/operation/conversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3085,6 +3085,19 @@ static void getESRIMethodNameAndParams(const Conversion *conv,
esriParams = paramsESRI_Rectified_Skew_Orthomorphic_Center;
esriMethodName = "Rectified_Skew_Orthomorphic_Center";
}
} else if (esriMapping->epsg_code ==
EPSG_CODE_METHOD_POLAR_STEREOGRAPHIC_VARIANT_A) {
// Quite empiric, but looking at pe_list_projcs.csv, the only
// CRS that use Polar_Stereographic_Variant_A are EPSG:5041 and 5042
if (l_targetCRS &&
// EPSG:5041
(l_targetCRS->nameStr() == "WGS 84 / UPS North (E,N)" ||
// EPSG:5042
l_targetCRS->nameStr() == "WGS 84 / UPS South (E,N)")) {
esriMethodName = "Polar_Stereographic_Variant_A";
} else {
esriMethodName = "Stereographic";
}
} else if (esriMapping->epsg_code ==
EPSG_CODE_METHOD_POLAR_STEREOGRAPHIC_VARIANT_B) {
if (conv->parameterValueNumericAsSI(
Expand Down
17 changes: 17 additions & 0 deletions src/iso19111/operation/esriparammappings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,19 @@ static const ESRIParamMapping paramsESRI_Stereographic[] = {
EPSG_CODE_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN, "0.0", false},
{nullptr, nullptr, 0, "0.0", false}};

static const ESRIParamMapping paramsESRI_Polar_Stereographic_Variant_A[] = {
{"False_Easting", EPSG_NAME_PARAMETER_FALSE_EASTING,
EPSG_CODE_PARAMETER_FALSE_EASTING, "0.0", false},
{"False_Northing", EPSG_NAME_PARAMETER_FALSE_NORTHING,
EPSG_CODE_PARAMETER_FALSE_NORTHING, "0.0", false},
{"Central_Meridian", EPSG_NAME_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN,
EPSG_CODE_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN, "0.0", false},
{"Scale_Factor", EPSG_NAME_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN,
EPSG_CODE_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN, "0.0", false},
{"Latitude_Of_Origin", EPSG_NAME_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN,
EPSG_CODE_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN, "0.0", false},
{nullptr, nullptr, 0, "0.0", false}};

static const ESRIParamMapping paramsESRI_Equidistant_Conic[] = {
{"False_Easting", EPSG_NAME_PARAMETER_FALSE_EASTING,
EPSG_CODE_PARAMETER_FALSE_EASTING, "0.0", false},
Expand Down Expand Up @@ -1033,6 +1046,10 @@ static const ESRIMethodMapping esriMappings[] = {
paramsESRI_Hotine_Oblique_Mercator_Two_Point_Natural_Origin},
{"Stereographic", PROJ_WKT2_NAME_METHOD_STEREOGRAPHIC, 0,
paramsESRI_Stereographic},
{"Polar_Stereographic_Variant_A",
EPSG_NAME_METHOD_POLAR_STEREOGRAPHIC_VARIANT_A,
EPSG_CODE_METHOD_POLAR_STEREOGRAPHIC_VARIANT_A,
paramsESRI_Polar_Stereographic_Variant_A},
{"Equidistant_Conic", PROJ_WKT2_NAME_METHOD_EQUIDISTANT_CONIC, 0,
paramsESRI_Equidistant_Conic},
{"Cassini", EPSG_NAME_METHOD_CASSINI_SOLDNER,
Expand Down
104 changes: 97 additions & 7 deletions test/unit/test_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7307,6 +7307,7 @@ TEST(wkt_parse, wkt1_esri_normalize_unit) {
// ---------------------------------------------------------------------------

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

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<ProjectedCRS>(obj);
ASSERT_TRUE(crs != nullptr);

EXPECT_EQ(crs->nameStr(), "WGS 84 / UPS North (E,N)");
EXPECT_EQ(crs->nameStr(), "WGS 84 / UPS North (N,E)");
EXPECT_EQ(crs->coordinateSystem()->axisList()[0]->direction(),
AxisDirection::SOUTH);
// Yes, inconsistency between the name (coming from EPSG) and the fact
// that with ESRI CRS, we always output E, N axis order
EXPECT_EQ(crs->coordinateSystem()->axisList()[0]->abbreviation(), "E");
EXPECT_EQ(crs->coordinateSystem()->axisList()[1]->direction(),
AxisDirection::SOUTH);
EXPECT_EQ(crs->coordinateSystem()->axisList()[1]->abbreviation(), "N");

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

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

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

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<ProjectedCRS>(obj);
ASSERT_TRUE(crs != nullptr);

EXPECT_EQ(crs->nameStr(), "WGS 84 / UPS South (N,E)");
EXPECT_EQ(crs->coordinateSystem()->axisList()[0]->direction(),
AxisDirection::NORTH);
// Yes, inconsistency between the name (coming from EPSG) and the fact
// that with ESRI CRS, we always output E, N axis order
EXPECT_EQ(crs->coordinateSystem()->axisList()[0]->abbreviation(), "E");
EXPECT_EQ(crs->coordinateSystem()->axisList()[1]->direction(),
AxisDirection::NORTH);
EXPECT_EQ(crs->coordinateSystem()->axisList()[1]->abbreviation(), "N");

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

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

TEST(wkt_parse, wkt1_esri_wgs_1984_ups_north_E_N) {
// EPSG:5041
auto wkt = "PROJCS[\"WGS_1984_UPS_North_(E-N)\","
"GEOGCS[\"GCS_WGS_1984\",DATUM[\"D_WGS_1984\","
"SPHEROID[\"WGS_1984\",6378137.0,298.257223563]],"
"PRIMEM[\"Greenwich\",0.0],"
"UNIT[\"Degree\",0.0174532925199433]],"
"PROJECTION[\"Polar_Stereographic_Variant_A\"],"
"PARAMETER[\"False_Easting\",2000000.0],"
"PARAMETER[\"False_Northing\",2000000.0],"
"PARAMETER[\"Central_Meridian\",0.0],"
"PARAMETER[\"Scale_Factor\",0.994],"
"PARAMETER[\"Latitude_Of_Origin\",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);

EXPECT_EQ(crs->nameStr(), "WGS 84 / UPS North (E,N)");
EXPECT_EQ(crs->coordinateSystem()->axisList()[0]->direction(),
AxisDirection::SOUTH);
EXPECT_EQ(crs->coordinateSystem()->axisList()[0]->abbreviation(), "E");
EXPECT_EQ(crs->coordinateSystem()->axisList()[1]->direction(),
AxisDirection::SOUTH);
EXPECT_EQ(crs->coordinateSystem()->axisList()[1]->abbreviation(), "N");

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

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

TEST(wkt_parse, wkt1_esri_wgs_1984_ups_south_E_N) {
// EPSG:5042
auto wkt = "PROJCS[\"WGS_1984_UPS_South_(E-N)\","
"GEOGCS[\"GCS_WGS_1984\",DATUM[\"D_WGS_1984\","
"SPHEROID[\"WGS_1984\",6378137.0,298.257223563]],"
"PRIMEM[\"Greenwich\",0.0],"
"UNIT[\"Degree\",0.0174532925199433]],"
"PROJECTION[\"Polar_Stereographic_Variant_A\"],"
"PARAMETER[\"False_Easting\",2000000.0],"
"PARAMETER[\"False_Northing\",2000000.0],"
"PARAMETER[\"Central_Meridian\",0.0],"
"PARAMETER[\"Scale_Factor\",0.994],"
"PARAMETER[\"Latitude_Of_Origin\",-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);

Expand All @@ -7362,6 +7446,12 @@ TEST(wkt_parse, wkt1_esri_ups_south) {
EXPECT_EQ(crs->coordinateSystem()->axisList()[1]->direction(),
AxisDirection::NORTH);
EXPECT_EQ(crs->coordinateSystem()->axisList()[1]->abbreviation(), "N");

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

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