Skip to content

Commit

Permalink
Merge pull request #4328 from rouault/fix_wkt1_esri_export_of_Cylindr…
Browse files Browse the repository at this point in the history
…ical_Equal_Area

WKT1 ESRI export: fix wrong mapping of Lambert Cylindrical Equal Area to Behrmann
  • Loading branch information
rouault authored Nov 25, 2024
2 parents 2d43066 + e0bd196 commit 10b0feb
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 44 deletions.
43 changes: 23 additions & 20 deletions scripts/build_esri_projection_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@
# Map methods from pe_list_projection.csv to WKT2 naming

config_str = """
- Equidistant_Cylindrical:
WKT2_name: EPSG_NAME_METHOD_EQUIDISTANT_CYLINDRICAL
Params:
- False_Easting: EPSG_NAME_PARAMETER_FALSE_EASTING
- False_Northing: EPSG_NAME_PARAMETER_FALSE_NORTHING
- Central_Meridian: EPSG_NAME_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN
- Standard_Parallel_1: EPSG_NAME_PARAMETER_LATITUDE_1ST_STD_PARALLEL
- Plate_Carree:
WKT2_name:
- EPSG_NAME_METHOD_EQUIDISTANT_CYLINDRICAL
Expand All @@ -45,14 +54,6 @@
Cond:
- EPSG_NAME_PARAMETER_LATITUDE_1ST_STD_PARALLEL = 0
- Equidistant_Cylindrical:
WKT2_name: EPSG_NAME_METHOD_EQUIDISTANT_CYLINDRICAL
Params:
- False_Easting: EPSG_NAME_PARAMETER_FALSE_EASTING
- False_Northing: EPSG_NAME_PARAMETER_FALSE_NORTHING
- Central_Meridian: EPSG_NAME_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN
- Standard_Parallel_1: EPSG_NAME_PARAMETER_LATITUDE_1ST_STD_PARALLEL
- Miller_Cylindrical:
WKT2_name: PROJ_WKT2_NAME_METHOD_MILLER_CYLINDRICAL
Params:
Expand Down Expand Up @@ -168,18 +169,6 @@
- False_Northing: EPSG_NAME_PARAMETER_FALSE_NORTHING
- Central_Meridian: EPSG_NAME_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN
- Behrmann:
WKT2_name: EPSG_NAME_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA
Params:
- False_Easting: EPSG_NAME_PARAMETER_FALSE_EASTING
- False_Northing: EPSG_NAME_PARAMETER_FALSE_NORTHING
- Central_Meridian:
Name: EPSG_NAME_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN
Default: 0.0
- Standard_Parallel_1:
Name: EPSG_NAME_PARAMETER_LATITUDE_1ST_STD_PARALLEL
Default: 30.0
- Winkel_I:
WKT2_name: "Winkel I"
Params:
Expand Down Expand Up @@ -365,6 +354,20 @@
- Central_Meridian: EPSG_NAME_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN
- Standard_Parallel_1: EPSG_NAME_PARAMETER_LATITUDE_1ST_STD_PARALLEL
- Behrmann:
WKT2_name: EPSG_NAME_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA
Params:
- False_Easting: EPSG_NAME_PARAMETER_FALSE_EASTING
- False_Northing: EPSG_NAME_PARAMETER_FALSE_NORTHING
- Central_Meridian:
Name: EPSG_NAME_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN
Default: 0.0
- Standard_Parallel_1:
Name: EPSG_NAME_PARAMETER_LATITUDE_1ST_STD_PARALLEL
Default: 30.0
Cond:
- EPSG_NAME_PARAMETER_LATITUDE_1ST_STD_PARALLEL = 30
# No example in pe_list_projection.csv: temptative mapping !
- Hotine_Oblique_Mercator_Two_Point_Center:
WKT2_name: PROJ_WKT2_NAME_METHOD_HOTINE_OBLIQUE_MERCATOR_TWO_POINT_NATURAL_ORIGIN
Expand Down
10 changes: 10 additions & 0 deletions src/iso19111/operation/conversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3206,6 +3206,16 @@ static void getESRIMethodNameAndParams(const Conversion *conv,
} else {
esriMethodName = "Stereographic_South_Pole";
}
} else if (esriMapping->epsg_code ==
EPSG_CODE_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA) {
if (std::abs(conv->parameterValueNumeric(
EPSG_CODE_PARAMETER_LATITUDE_1ST_STD_PARALLEL,
common::UnitOfMeasure::DEGREE) -
30.0) < 1e-10) {
esriMethodName = "Behrmann";
} else {
esriMethodName = "Cylindrical_Equal_Area";
}
}
}
}
Expand Down
40 changes: 20 additions & 20 deletions src/iso19111/operation/esriparammappings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,24 +46,24 @@ namespace operation {

//! @cond Doxygen_Suppress

const ESRIParamMapping paramsESRI_Plate_Carree[] = {
const ESRIParamMapping paramsESRI_Equidistant_Cylindrical[] = {
{"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},
{"Standard_Parallel_1", EPSG_NAME_PARAMETER_LATITUDE_1ST_STD_PARALLEL,
EPSG_CODE_PARAMETER_LATITUDE_1ST_STD_PARALLEL, "0.0", false},
{nullptr, nullptr, 0, "0.0", false}};

const ESRIParamMapping paramsESRI_Equidistant_Cylindrical[] = {
const ESRIParamMapping paramsESRI_Plate_Carree[] = {
{"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},
{"Standard_Parallel_1", EPSG_NAME_PARAMETER_LATITUDE_1ST_STD_PARALLEL,
EPSG_CODE_PARAMETER_LATITUDE_1ST_STD_PARALLEL, "0.0", false},
{nullptr, nullptr, 0, "0.0", false}};

static const ESRIParamMapping paramsESRI_Miller_Cylindrical[] = {
Expand Down Expand Up @@ -221,17 +221,6 @@ static const ESRIParamMapping paramsESRI_Gall_Stereographic[] = {
EPSG_CODE_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN, "0.0", false},
{nullptr, nullptr, 0, "0.0", false}};

static const ESRIParamMapping paramsESRI_Behrmann[] = {
{"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", true},
{"Standard_Parallel_1", EPSG_NAME_PARAMETER_LATITUDE_1ST_STD_PARALLEL,
EPSG_CODE_PARAMETER_LATITUDE_1ST_STD_PARALLEL, "30.0", true},
{nullptr, nullptr, 0, "0.0", false}};

static const ESRIParamMapping paramsESRI_Winkel_I[] = {
{"False_Easting", EPSG_NAME_PARAMETER_FALSE_EASTING,
EPSG_CODE_PARAMETER_FALSE_EASTING, "0.0", false},
Expand Down Expand Up @@ -487,6 +476,17 @@ static const ESRIParamMapping paramsESRI_Cylindrical_Equal_Area[] = {
EPSG_CODE_PARAMETER_LATITUDE_1ST_STD_PARALLEL, "0.0", false},
{nullptr, nullptr, 0, "0.0", false}};

static const ESRIParamMapping paramsESRI_Behrmann[] = {
{"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", true},
{"Standard_Parallel_1", EPSG_NAME_PARAMETER_LATITUDE_1ST_STD_PARALLEL,
EPSG_CODE_PARAMETER_LATITUDE_1ST_STD_PARALLEL, "30.0", true},
{nullptr, nullptr, 0, "0.0", false}};

static const ESRIParamMapping
paramsESRI_Hotine_Oblique_Mercator_Two_Point_Center[] = {
{"False_Easting", EPSG_NAME_PARAMETER_EASTING_PROJECTION_CENTRE,
Expand Down Expand Up @@ -990,14 +990,14 @@ static const ESRIParamMapping paramsESRI_Peirce_Quincuncial_alt2[] = {
{nullptr, nullptr, 0, "0.0", false}};

static const ESRIMethodMapping esriMappings[] = {
{"Equidistant_Cylindrical", EPSG_NAME_METHOD_EQUIDISTANT_CYLINDRICAL,
EPSG_CODE_METHOD_EQUIDISTANT_CYLINDRICAL,
paramsESRI_Equidistant_Cylindrical},
{"Plate_Carree", EPSG_NAME_METHOD_EQUIDISTANT_CYLINDRICAL,
EPSG_CODE_METHOD_EQUIDISTANT_CYLINDRICAL, paramsESRI_Plate_Carree},
{"Plate_Carree", EPSG_NAME_METHOD_EQUIDISTANT_CYLINDRICAL_SPHERICAL,
EPSG_CODE_METHOD_EQUIDISTANT_CYLINDRICAL_SPHERICAL,
paramsESRI_Plate_Carree},
{"Equidistant_Cylindrical", EPSG_NAME_METHOD_EQUIDISTANT_CYLINDRICAL,
EPSG_CODE_METHOD_EQUIDISTANT_CYLINDRICAL,
paramsESRI_Equidistant_Cylindrical},
{"Miller_Cylindrical", PROJ_WKT2_NAME_METHOD_MILLER_CYLINDRICAL, 0,
paramsESRI_Miller_Cylindrical},
{"Mercator", EPSG_NAME_METHOD_MERCATOR_VARIANT_B,
Expand All @@ -1021,8 +1021,6 @@ static const ESRIMethodMapping esriMappings[] = {
{"Eckert_VI", PROJ_WKT2_NAME_METHOD_ECKERT_VI, 0, paramsESRI_Eckert_VI},
{"Gall_Stereographic", PROJ_WKT2_NAME_METHOD_GALL_STEREOGRAPHIC, 0,
paramsESRI_Gall_Stereographic},
{"Behrmann", EPSG_NAME_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA,
EPSG_CODE_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA, paramsESRI_Behrmann},
{"Winkel_I", "Winkel I", 0, paramsESRI_Winkel_I},
{"Winkel_II", "Winkel II", 0, paramsESRI_Winkel_II},
{"Lambert_Conformal_Conic", EPSG_NAME_METHOD_LAMBERT_CONIC_CONFORMAL_1SP,
Expand Down Expand Up @@ -1070,6 +1068,8 @@ static const ESRIMethodMapping esriMappings[] = {
{"Cylindrical_Equal_Area", EPSG_NAME_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA,
EPSG_CODE_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA,
paramsESRI_Cylindrical_Equal_Area},
{"Behrmann", EPSG_NAME_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA,
EPSG_CODE_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA, paramsESRI_Behrmann},
{"Hotine_Oblique_Mercator_Two_Point_Center",
PROJ_WKT2_NAME_METHOD_HOTINE_OBLIQUE_MERCATOR_TWO_POINT_NATURAL_ORIGIN, 0,
paramsESRI_Hotine_Oblique_Mercator_Two_Point_Center},
Expand Down
35 changes: 31 additions & 4 deletions test/unit/test_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7791,10 +7791,15 @@ static const struct {
TEST(wkt_parse, esri_projcs) {

for (const auto &projDef : esriProjDefs) {
std::string wkt("PROJCS[\"unnamed\",GEOGCS[\"unnamed\","
"DATUM[\"unnamed\",SPHEROID[\"unnamed\","
"6378137.0,298.257223563]],PRIMEM[\"Greenwich\",0.0],"
"UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"");
std::string wkt("PROJCS[\"");
if (strcmp(projDef.esriProjectionName, "Plate_Carree") == 0)
wkt += "Plate Carree";
else
wkt += "unnamed";
wkt += "\",GEOGCS[\"unnamed\","
"DATUM[\"unnamed\",SPHEROID[\"unnamed\","
"6378137.0,298.257223563]],PRIMEM[\"Greenwich\",0.0],"
"UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"";
wkt += projDef.esriProjectionName;
wkt += "\"],";
for (const auto &param : projDef.esriParams) {
Expand Down Expand Up @@ -7829,6 +7834,28 @@ TEST(wkt_parse, esri_projcs) {
EXPECT_EQ(measure.value(), projDef.wkt2Params[i].second) << wkt;
}
}

auto wkt1Esri = crs->exportToWKT(
WKTFormatter::create(WKTFormatter::Convention::WKT1_ESRI).get());
const char *expectedESRIProjectionName = projDef.esriProjectionName;
// Not totally sure about the below exceptions. They just capture the
// current state of things.
if (strcmp(projDef.esriProjectionName, "Transverse_Mercator_Complex") ==
0)
expectedESRIProjectionName = "Transverse_Mercator";
else if (strcmp(projDef.esriProjectionName,
"Equidistant_Cylindrical_Ellipsoidal") == 0)
expectedESRIProjectionName = "Equidistant_Cylindrical";
else if (strcmp(projDef.esriProjectionName, "Mercator_Variant_C") == 0)
expectedESRIProjectionName = "Mercator";
else if (strcmp(projDef.esriProjectionName, "Gnomonic_Ellipsoidal") ==
0)
expectedESRIProjectionName = "Gnomonic";
EXPECT_TRUE(wkt1Esri.find(std::string("PROJECTION[\"")
.append(expectedESRIProjectionName)) !=
std::string::npos)
<< "input: " << wkt << std::endl
<< "output: " << wkt1Esri;
}
}

Expand Down

0 comments on commit 10b0feb

Please sign in to comment.