diff options
| -rw-r--r-- | include/proj/internal/esri_projection_mappings.hpp | 10 | ||||
| -rw-r--r-- | scripts/build_esri_projection_mapping.py | 4 | ||||
| -rw-r--r-- | src/iso19111/coordinateoperation.cpp | 8 | ||||
| -rw-r--r-- | src/iso19111/io.cpp | 85 | ||||
| -rw-r--r-- | test/unit/test_io.cpp | 50 |
5 files changed, 120 insertions, 37 deletions
diff --git a/include/proj/internal/esri_projection_mappings.hpp b/include/proj/internal/esri_projection_mappings.hpp index bd1ccff9..95cd6335 100644 --- a/include/proj/internal/esri_projection_mappings.hpp +++ b/include/proj/internal/esri_projection_mappings.hpp @@ -929,9 +929,8 @@ 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_SPHERICAL, - EPSG_CODE_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA_SPHERICAL, - paramsESRI_Behrmann}, + {"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, @@ -973,9 +972,8 @@ static const ESRIMethodMapping esriMappings[] = { EPSG_NAME_METHOD_LAMBERT_AZIMUTHAL_EQUAL_AREA, EPSG_CODE_METHOD_LAMBERT_AZIMUTHAL_EQUAL_AREA, paramsESRI_Lambert_Azimuthal_Equal_Area}, - {"Cylindrical_Equal_Area", - EPSG_NAME_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA_SPHERICAL, - EPSG_CODE_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA_SPHERICAL, + {"Cylindrical_Equal_Area", EPSG_NAME_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA, + EPSG_CODE_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA, paramsESRI_Cylindrical_Equal_Area}, {"Hotine_Oblique_Mercator_Two_Point_Center", PROJ_WKT2_NAME_METHOD_HOTINE_OBLIQUE_MERCATOR_TWO_POINT_NATURAL_ORIGIN, 0, diff --git a/scripts/build_esri_projection_mapping.py b/scripts/build_esri_projection_mapping.py index 1fcc8008..220f105f 100644 --- a/scripts/build_esri_projection_mapping.py +++ b/scripts/build_esri_projection_mapping.py @@ -169,7 +169,7 @@ config_str = """ - Central_Meridian: EPSG_NAME_PARAMETER_LONGITUDE_OF_NATURAL_ORIGIN - Behrmann: - WKT2_name: EPSG_NAME_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA_SPHERICAL + WKT2_name: EPSG_NAME_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA Params: - False_Easting: EPSG_NAME_PARAMETER_FALSE_EASTING - False_Northing: EPSG_NAME_PARAMETER_FALSE_NORTHING @@ -349,7 +349,7 @@ config_str = """ - Latitude_Of_Origin: EPSG_NAME_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN - Cylindrical_Equal_Area: - WKT2_name: EPSG_NAME_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA_SPHERICAL + WKT2_name: EPSG_NAME_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA Params: - False_Easting: EPSG_NAME_PARAMETER_FALSE_EASTING - False_Northing: EPSG_NAME_PARAMETER_FALSE_NORTHING diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp index 03eea4ee..4b174636 100644 --- a/src/iso19111/coordinateoperation.cpp +++ b/src/iso19111/coordinateoperation.cpp @@ -1797,6 +1797,14 @@ bool SingleOperation::_isEquivalentTo(const util::IComparable *other, EPSG_CODE_METHOD_LAMBERT_AZIMUTHAL_EQUAL_AREA && methodEPSGCode == EPSG_CODE_METHOD_LAMBERT_AZIMUTHAL_EQUAL_AREA_SPHERICAL) || + (methodEPSGCode == + EPSG_CODE_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA && + otherMethodEPSGCode == + EPSG_CODE_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA_SPHERICAL) || + (otherMethodEPSGCode == + EPSG_CODE_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA && + methodEPSGCode == + EPSG_CODE_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA_SPHERICAL) || (methodEPSGCode == EPSG_CODE_METHOD_EQUIDISTANT_CYLINDRICAL && otherMethodEPSGCode == EPSG_CODE_METHOD_EQUIDISTANT_CYLINDRICAL_SPHERICAL) || diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index 8968b70e..e516e4b5 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -1298,19 +1298,22 @@ struct WKTParser::Private { static std::string projectionGetParameter(const WKTNodeNNPtr &projCRSNode, const char *paramName); - ConversionNNPtr buildProjection(const WKTNodeNNPtr &projCRSNode, + ConversionNNPtr buildProjection(const GeodeticCRSNNPtr &baseGeodCRS, + const WKTNodeNNPtr &projCRSNode, const WKTNodeNNPtr &projectionNode, const UnitOfMeasure &defaultLinearUnit, const UnitOfMeasure &defaultAngularUnit); ConversionNNPtr - buildProjectionStandard(const WKTNodeNNPtr &projCRSNode, + buildProjectionStandard(const GeodeticCRSNNPtr &baseGeodCRS, + const WKTNodeNNPtr &projCRSNode, const WKTNodeNNPtr &projectionNode, const UnitOfMeasure &defaultLinearUnit, const UnitOfMeasure &defaultAngularUnit); ConversionNNPtr - buildProjectionFromESRI(const WKTNodeNNPtr &projCRSNode, + buildProjectionFromESRI(const GeodeticCRSNNPtr &baseGeodCRS, + const WKTNodeNNPtr &projCRSNode, const WKTNodeNNPtr &projectionNode, const UnitOfMeasure &defaultLinearUnit, const UnitOfMeasure &defaultAngularUnit); @@ -3178,9 +3181,40 @@ bool WKTParser::Private::hasWebMercPROJ4String( // --------------------------------------------------------------------------- +static const MethodMapping * +selectSphericalOrEllipsoidal(const MethodMapping *mapping, + const GeodeticCRSNNPtr &baseGeodCRS) { + if (mapping->epsg_code == + EPSG_CODE_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA_SPHERICAL || + mapping->epsg_code == EPSG_CODE_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA) { + mapping = getMapping( + baseGeodCRS->ellipsoid()->isSphere() + ? EPSG_CODE_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA_SPHERICAL + : EPSG_CODE_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA); + } else if (mapping->epsg_code == + EPSG_CODE_METHOD_LAMBERT_AZIMUTHAL_EQUAL_AREA_SPHERICAL || + mapping->epsg_code == + EPSG_CODE_METHOD_LAMBERT_AZIMUTHAL_EQUAL_AREA) { + mapping = getMapping( + baseGeodCRS->ellipsoid()->isSphere() + ? EPSG_CODE_METHOD_LAMBERT_AZIMUTHAL_EQUAL_AREA_SPHERICAL + : EPSG_CODE_METHOD_LAMBERT_AZIMUTHAL_EQUAL_AREA); + } else if (mapping->epsg_code == + EPSG_CODE_METHOD_EQUIDISTANT_CYLINDRICAL_SPHERICAL || + mapping->epsg_code == EPSG_CODE_METHOD_EQUIDISTANT_CYLINDRICAL) { + mapping = + getMapping(baseGeodCRS->ellipsoid()->isSphere() + ? EPSG_CODE_METHOD_EQUIDISTANT_CYLINDRICAL_SPHERICAL + : EPSG_CODE_METHOD_EQUIDISTANT_CYLINDRICAL); + } + return mapping; +} + +// --------------------------------------------------------------------------- + ConversionNNPtr WKTParser::Private::buildProjectionFromESRI( - const WKTNodeNNPtr &projCRSNode, const WKTNodeNNPtr &projectionNode, - const UnitOfMeasure &defaultLinearUnit, + const GeodeticCRSNNPtr &baseGeodCRS, const WKTNodeNNPtr &projCRSNode, + const WKTNodeNNPtr &projectionNode, const UnitOfMeasure &defaultLinearUnit, const UnitOfMeasure &defaultAngularUnit) { const std::string esriProjectionName = stripQuotes(projectionNode->GP()->children()[0]); @@ -3190,7 +3224,7 @@ ConversionNNPtr WKTParser::Private::buildProjectionFromESRI( // on the parameters / their values const auto esriMappings = getMappingsFromESRI(esriProjectionName); if (esriMappings.empty()) { - return buildProjectionStandard(projCRSNode, projectionNode, + return buildProjectionStandard(baseGeodCRS, projCRSNode, projectionNode, defaultLinearUnit, defaultAngularUnit); } @@ -3273,6 +3307,8 @@ ConversionNNPtr WKTParser::Private::buildProjectionFromESRI( } assert(wkt2_mapping); + wkt2_mapping = selectSphericalOrEllipsoidal(wkt2_mapping, baseGeodCRS); + PropertyMap propertiesMethod; propertiesMethod.set(IdentifiedObject::NAME_KEY, wkt2_mapping->wkt2_name); if (wkt2_mapping->epsg_code != 0) { @@ -3360,19 +3396,18 @@ ConversionNNPtr WKTParser::Private::buildProjectionFromESRI( // --------------------------------------------------------------------------- -ConversionNNPtr -WKTParser::Private::buildProjection(const WKTNodeNNPtr &projCRSNode, - const WKTNodeNNPtr &projectionNode, - const UnitOfMeasure &defaultLinearUnit, - const UnitOfMeasure &defaultAngularUnit) { +ConversionNNPtr WKTParser::Private::buildProjection( + const GeodeticCRSNNPtr &baseGeodCRS, const WKTNodeNNPtr &projCRSNode, + const WKTNodeNNPtr &projectionNode, const UnitOfMeasure &defaultLinearUnit, + const UnitOfMeasure &defaultAngularUnit) { if (projectionNode->GP()->childrenSize() == 0) { ThrowNotEnoughChildren(WKTConstants::PROJECTION); } if (esriStyle_) { - return buildProjectionFromESRI(projCRSNode, projectionNode, + return buildProjectionFromESRI(baseGeodCRS, projCRSNode, projectionNode, defaultLinearUnit, defaultAngularUnit); } - return buildProjectionStandard(projCRSNode, projectionNode, + return buildProjectionStandard(baseGeodCRS, projCRSNode, projectionNode, defaultLinearUnit, defaultAngularUnit); } @@ -3397,8 +3432,8 @@ WKTParser::Private::projectionGetParameter(const WKTNodeNNPtr &projCRSNode, // --------------------------------------------------------------------------- ConversionNNPtr WKTParser::Private::buildProjectionStandard( - const WKTNodeNNPtr &projCRSNode, const WKTNodeNNPtr &projectionNode, - const UnitOfMeasure &defaultLinearUnit, + const GeodeticCRSNNPtr &baseGeodCRS, const WKTNodeNNPtr &projCRSNode, + const WKTNodeNNPtr &projectionNode, const UnitOfMeasure &defaultLinearUnit, const UnitOfMeasure &defaultAngularUnit) { std::string wkt1ProjectionName = stripQuotes(projectionNode->GP()->children()[0]); @@ -3516,6 +3551,9 @@ ConversionNNPtr WKTParser::Private::buildProjectionStandard( std::string projectionName(wkt1ProjectionName); const MethodMapping *mapping = tryToIdentifyWKT1Method ? getMappingFromWKT1(projectionName) : nullptr; + if (mapping) { + mapping = selectSphericalOrEllipsoidal(mapping, baseGeodCRS); + } // For Krovak, we need to look at axis to decide between the Krovak and // Krovak East-North Oriented methods @@ -3768,7 +3806,8 @@ WKTParser::Private::buildProjectedCRS(const WKTNodeNNPtr &node) { auto conversion = !isNull(conversionNode) ? buildConversion(conversionNode, linearUnit, angularUnit) - : buildProjection(node, projectionNode, linearUnit, angularUnit); + : buildProjection(baseGeodCRS, node, projectionNode, linearUnit, + angularUnit); // No explicit AXIS node ? (WKT1) if (isNull(nodeP->lookForChild(WKTConstants::AXIS))) { @@ -8677,6 +8716,9 @@ CRSNNPtr PROJStringParser::Private::buildProjectedCRS( auto &step = steps_[iStep]; auto mappings = getMappingsFromPROJName(step.name); const MethodMapping *mapping = mappings.empty() ? nullptr : mappings[0]; + if (mapping) { + mapping = selectSphericalOrEllipsoidal(mapping, geogCRS); + } assert(isProjectedStep(step.name)); assert(iUnitConvert < 0 || @@ -8722,8 +8764,6 @@ CRSNNPtr PROJStringParser::Private::buildProjectedCRS( } } else if (step.name == "aeqd" && hasParamValue(step, "guam")) { mapping = getMapping(EPSG_CODE_METHOD_GUAM_PROJECTION); - } else if (step.name == "cea" && !geogCRS->ellipsoid()->isSphere()) { - mapping = getMapping(EPSG_CODE_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA); } else if (step.name == "geos" && getParamValue(step, "sweep") == "x") { mapping = getMapping(PROJ_WKT2_NAME_METHOD_GEOSTATIONARY_SATELLITE_SWEEP_X); @@ -8829,15 +8869,6 @@ CRSNNPtr PROJStringParser::Private::buildProjectedCRS( axisType = AxisType::SOUTH_POLE; } } - if (geogCRS->ellipsoid()->isSphere()) { - mapping = getMapping( - EPSG_CODE_METHOD_LAMBERT_AZIMUTHAL_EQUAL_AREA_SPHERICAL); - } - } else if (step.name == "eqc") { - if (geogCRS->ellipsoid()->isSphere()) { - mapping = - getMapping(EPSG_CODE_METHOD_EQUIDISTANT_CYLINDRICAL_SPHERICAL); - } } UnitOfMeasure unit = buildUnit(step, "units", "to_meter"); diff --git a/test/unit/test_io.cpp b/test/unit/test_io.cpp index c95b1b57..a227ff31 100644 --- a/test/unit/test_io.cpp +++ b/test/unit/test_io.cpp @@ -4475,7 +4475,7 @@ static const struct { {"Behrmann", {{"False_Easting", 1}, {"False_Northing", 2}, {"Central_Meridian", 3}}, - "Lambert Cylindrical Equal Area (Spherical)", + "Lambert Cylindrical Equal Area", { {"Latitude of 1st standard parallel", 30}, {"Longitude of natural origin", 3}, @@ -4776,7 +4776,7 @@ static const struct { {"False_Northing", 2}, {"Central_Meridian", 3}, {"Standard_Parallel_1", 4}}, - "Lambert Cylindrical Equal Area (Spherical)", + "Lambert Cylindrical Equal Area", { {"Latitude of 1st standard parallel", 4}, {"Longitude of natural origin", 3}, @@ -8128,6 +8128,30 @@ TEST(io, projparse_aeqd_guam) { // --------------------------------------------------------------------------- +TEST(io, projparse_cea_spherical) { + auto obj = PROJStringParser().createFromPROJString( + "+proj=cea +R=6371228 +type=crs"); + auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj); + ASSERT_TRUE(crs != nullptr); + EXPECT_EQ(crs->derivingConversion()->method()->getEPSGCode(), + EPSG_CODE_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA_SPHERICAL); + + auto crs2 = ProjectedCRS::create( + PropertyMap(), crs->baseCRS(), + Conversion::createLambertCylindricalEqualArea( + PropertyMap(), Angle(0), Angle(0), Length(0), Length(0)), + crs->coordinateSystem()); + EXPECT_EQ(crs2->derivingConversion()->method()->getEPSGCode(), + EPSG_CODE_METHOD_LAMBERT_CYLINDRICAL_EQUAL_AREA); + + EXPECT_TRUE( + crs->isEquivalentTo(crs2.get(), IComparable::Criterion::EQUIVALENT)); + EXPECT_TRUE( + crs2->isEquivalentTo(crs.get(), IComparable::Criterion::EQUIVALENT)); +} + +// --------------------------------------------------------------------------- + TEST(io, projparse_cea_ellipsoidal) { auto obj = PROJStringParser().createFromPROJString( "+proj=cea +ellps=GRS80 +type=crs"); @@ -8651,6 +8675,17 @@ TEST(io, projparse_laea_spherical) { // --------------------------------------------------------------------------- +TEST(io, projparse_laea_ellipsoidal) { + auto obj = PROJStringParser().createFromPROJString( + "+proj=laea +ellps=WGS84 +type=crs"); + auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj); + ASSERT_TRUE(crs != nullptr); + EXPECT_EQ(crs->derivingConversion()->method()->getEPSGCode(), + EPSG_CODE_METHOD_LAMBERT_AZIMUTHAL_EQUAL_AREA); +} + +// --------------------------------------------------------------------------- + TEST(io, projparse_eqc_spherical) { auto obj = PROJStringParser().createFromPROJString( "+proj=eqc +R=6371228 +type=crs"); @@ -8675,6 +8710,17 @@ TEST(io, projparse_eqc_spherical) { // --------------------------------------------------------------------------- +TEST(io, projparse_eqc_ellipsoidal) { + auto obj = PROJStringParser().createFromPROJString( + "+proj=eqc +ellps=WGS84 +type=crs"); + auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj); + ASSERT_TRUE(crs != nullptr); + EXPECT_EQ(crs->derivingConversion()->method()->getEPSGCode(), + EPSG_CODE_METHOD_EQUIDISTANT_CYLINDRICAL); +} + +// --------------------------------------------------------------------------- + TEST(io, projparse_non_earth_ellipsoid) { std::string input("+proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +R=1 +units=m " "+no_defs +type=crs"); |
