diff options
| -rw-r--r-- | include/proj/coordinateoperation.hpp | 11 | ||||
| -rw-r--r-- | include/proj/internal/coordinateoperation_constants.hpp | 19 | ||||
| -rw-r--r-- | scripts/reference_exported_symbols.txt | 4 | ||||
| -rw-r--r-- | src/iso19111/c_api.cpp | 90 | ||||
| -rw-r--r-- | src/iso19111/coordinateoperation.cpp | 85 | ||||
| -rw-r--r-- | src/iso19111/crs.cpp | 6 | ||||
| -rw-r--r-- | src/proj_constants.h | 11 | ||||
| -rw-r--r-- | src/proj_experimental.h | 17 | ||||
| -rw-r--r-- | test/unit/test_c_api.cpp | 91 |
9 files changed, 333 insertions, 1 deletions
diff --git a/include/proj/coordinateoperation.hpp b/include/proj/coordinateoperation.hpp index 1ced5333..e3e3ece3 100644 --- a/include/proj/coordinateoperation.hpp +++ b/include/proj/coordinateoperation.hpp @@ -607,6 +607,11 @@ class PROJ_GCC_DLL SingleOperation : virtual public CoordinateOperation { const common::UnitOfMeasure &targetUnit) const noexcept; + PROJ_INTERNAL double + parameterValueNumeric(const char *param_name, + const common::UnitOfMeasure &targetUnit) const + noexcept; + PROJ_INTERNAL double parameterValueNumericAsSI(int epsg_code) const noexcept; @@ -1319,6 +1324,12 @@ class PROJ_GCC_DLL Conversion : public SingleOperation { const common::Length &falseEasting, const common::Length &falseNorthing); + PROJ_DLL static ConversionNNPtr createPoleRotationGRIBConvention( + const util::PropertyMap &properties, + const common::Angle &southPoleLatInUnrotatedCRS, + const common::Angle &southPoleLongInUnrotatedCRS, + const common::Angle &axisRotation); + PROJ_DLL static ConversionNNPtr createChangeVerticalUnit(const util::PropertyMap &properties, const common::Scale &factor); diff --git a/include/proj/internal/coordinateoperation_constants.hpp b/include/proj/internal/coordinateoperation_constants.hpp index eb0bb8c5..533599a0 100644 --- a/include/proj/internal/coordinateoperation_constants.hpp +++ b/include/proj/internal/coordinateoperation_constants.hpp @@ -1150,6 +1150,22 @@ static const ParamMapping paramVerticalOffsetFile = { static const ParamMapping *const paramsVERTCON[] = {¶mVerticalOffsetFile, nullptr}; +static const ParamMapping paramSouthPoleLatGRIB = { + PROJ_WKT2_NAME_PARAMETER_SOUTH_POLE_LATITUDE_GRIB_CONVENTION, 0, nullptr, + common::UnitOfMeasure::Type::ANGULAR, nullptr}; + +static const ParamMapping paramSouthPoleLonGRIB = { + PROJ_WKT2_NAME_PARAMETER_SOUTH_POLE_LONGITUDE_GRIB_CONVENTION, 0, nullptr, + common::UnitOfMeasure::Type::ANGULAR, nullptr}; + +static const ParamMapping paramAxisRotationGRIB = { + PROJ_WKT2_NAME_PARAMETER_AXIS_ROTATION_GRIB_CONVENTION, 0, nullptr, + common::UnitOfMeasure::Type::ANGULAR, nullptr}; + +static const ParamMapping *const paramsPoleRotationGRIBConvention[] = { + ¶mSouthPoleLatGRIB, ¶mSouthPoleLonGRIB, ¶mAxisRotationGRIB, + nullptr}; + static const MethodMapping otherMethodMappings[] = { {EPSG_NAME_METHOD_CHANGE_VERTICAL_UNIT, EPSG_CODE_METHOD_CHANGE_VERTICAL_UNIT, nullptr, nullptr, nullptr, @@ -1172,6 +1188,9 @@ static const MethodMapping otherMethodMappings[] = { EPSG_CODE_METHOD_AFFINE_PARAMETRIC_TRANSFORMATION, nullptr, nullptr, nullptr, paramsAffineParametricTransformation}, + {PROJ_WKT2_NAME_METHOD_POLE_ROTATION_GRIB_CONVENTION, 0, nullptr, nullptr, + nullptr, paramsPoleRotationGRIBConvention}, + {EPSG_NAME_METHOD_GEOCENTRIC_TRANSLATION_GEOCENTRIC, EPSG_CODE_METHOD_GEOCENTRIC_TRANSLATION_GEOCENTRIC, nullptr, nullptr, nullptr, paramsHelmert3}, diff --git a/scripts/reference_exported_symbols.txt b/scripts/reference_exported_symbols.txt index 4a1f6b90..e20f29b3 100644 --- a/scripts/reference_exported_symbols.txt +++ b/scripts/reference_exported_symbols.txt @@ -522,6 +522,7 @@ osgeo::proj::operation::Conversion::create(osgeo::proj::util::PropertyMap const& osgeo::proj::operation::Conversion::create(osgeo::proj::util::PropertyMap const&, osgeo::proj::util::PropertyMap const&, std::vector<dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::operation::OperationParameter> >, std::allocator<dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::operation::OperationParameter> > > > const&, std::vector<dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::operation::ParameterValue> >, std::allocator<dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::operation::ParameterValue> > > > const&) osgeo::proj::operation::Conversion::createPolarStereographicVariantA(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Scale const&, osgeo::proj::common::Length const&, osgeo::proj::common::Length const&) osgeo::proj::operation::Conversion::createPolarStereographicVariantB(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Length const&, osgeo::proj::common::Length const&) +osgeo::proj::operation::Conversion::createPoleRotationGRIBConvention(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&) osgeo::proj::operation::Conversion::createPopularVisualisationPseudoMercator(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Length const&, osgeo::proj::common::Length const&) osgeo::proj::operation::Conversion::createQuadrilateralizedSphericalCube(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Length const&, osgeo::proj::common::Length const&) osgeo::proj::operation::Conversion::createRobinson(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Length const&, osgeo::proj::common::Length const&) @@ -861,6 +862,7 @@ proj_create_conversion_oblique_stereographic proj_create_conversion_orthographic proj_create_conversion_polar_stereographic_variant_a proj_create_conversion_polar_stereographic_variant_b +proj_create_conversion_pole_rotation_grib_convention proj_create_conversion_popular_visualisation_pseudo_mercator proj_create_conversion_quadrilateralized_spherical_cube proj_create_conversion_robinson @@ -884,6 +886,7 @@ proj_create_conversion_wagner_vii proj_create_crs_to_crs proj_create_crs_to_crs_from_pj proj_create_cs +proj_create_derived_geographic_crs proj_create_ellipsoidal_2D_cs proj_create_ellipsoidal_3D_cs proj_create_engineering_crs @@ -955,6 +958,7 @@ proj_init_info proj_int_list_destroy proj_is_crs proj_is_deprecated +proj_is_derived_crs proj_is_equivalent_to proj_list_angular_units proj_list_destroy diff --git a/src/iso19111/c_api.cpp b/src/iso19111/c_api.cpp index 18794f9d..a389e792 100644 --- a/src/iso19111/c_api.cpp +++ b/src/iso19111/c_api.cpp @@ -2947,6 +2947,66 @@ PJ *proj_create_geocentric_crs_from_datum(PJ_CONTEXT *ctx, const char *crs_name, // --------------------------------------------------------------------------- +/** \brief Create a DerivedGeograhicCRS. + * + * The returned object must be unreferenced with proj_destroy() after + * use. + * It should be used by at most one thread at a time. + * + * @param ctx PROJ context, or NULL for default context + * @param crs_name Name of the GeographicCRS. Or NULL + * @param base_geographic_crs Base Geographic CRS. Must not be NULL. + * @param conversion Conversion from the base Geographic to the + * DerivedGeograhicCRS. Must not be NULL. + * @param ellipsoidal_cs Coordinate system. Must not be NULL. + * + * @return Object of type GeodeticCRS that must be unreferenced with + * proj_destroy(), or NULL in case of error. + * + * @since 7.0 + */ +PJ *proj_create_derived_geographic_crs(PJ_CONTEXT *ctx, const char *crs_name, + const PJ *base_geographic_crs, + const PJ *conversion, + const PJ *ellipsoidal_cs) { + SANITIZE_CTX(ctx); + auto base_crs = + std::dynamic_pointer_cast<GeographicCRS>(base_geographic_crs->iso_obj); + auto conversion_cpp = + std::dynamic_pointer_cast<Conversion>(conversion->iso_obj); + auto cs = std::dynamic_pointer_cast<EllipsoidalCS>(ellipsoidal_cs->iso_obj); + if (!base_crs || !conversion_cpp || !cs) { + return nullptr; + } + try { + auto derivedCRS = DerivedGeographicCRS::create( + createPropertyMapName(crs_name), NN_NO_CHECK(base_crs), + NN_NO_CHECK(conversion_cpp), NN_NO_CHECK(cs)); + return pj_obj_create(ctx, derivedCRS); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; +} + +// --------------------------------------------------------------------------- + +/** \brief Return whether a CRS is a Derived CRS. + * + * @param ctx PROJ context, or NULL for default context + * @param crs CRS. Must not be NULL. + * + * @return whether a CRS is a Derived CRS. + * + * @since 7.0 + */ +int proj_is_derived_crs(PJ_CONTEXT *ctx, const PJ *crs) { + SANITIZE_CTX(ctx); + return dynamic_cast<DerivedCRS *>(crs->iso_obj.get()) != nullptr; +} + +// --------------------------------------------------------------------------- + /** \brief Create a VerticalCRS * * The returned object must be unreferenced with proj_destroy() after @@ -6454,6 +6514,36 @@ PJ *proj_create_conversion_vertical_perspective( return nullptr; } +// --------------------------------------------------------------------------- + +/** \brief Instantiate a conversion based on the Pole Rotation method, using the + * conventions of the GRIB 1 and GRIB 2 data formats. + * + * See osgeo::proj::operation::Conversion::createPoleRotationGRIBConvention(). + * + * Linear parameters are expressed in (linear_unit_name, + * linear_unit_conv_factor). + * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor). + */ +PJ *proj_create_conversion_pole_rotation_grib_convention( + PJ_CONTEXT *ctx, double south_pole_lat_in_unrotated_crs, + double south_pole_long_in_unrotated_crs, double axis_rotation, + const char *ang_unit_name, double ang_unit_conv_factor) { + SANITIZE_CTX(ctx); + try { + UnitOfMeasure angUnit( + createAngularUnit(ang_unit_name, ang_unit_conv_factor)); + auto conv = Conversion::createPoleRotationGRIBConvention( + PropertyMap(), Angle(south_pole_lat_in_unrotated_crs, angUnit), + Angle(south_pole_long_in_unrotated_crs, angUnit), + Angle(axis_rotation, angUnit)); + return proj_create_conversion(ctx, conv); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + } + return nullptr; +} + /* END: Generated by scripts/create_c_api_projections.py*/ // --------------------------------------------------------------------------- diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp index 860b9a01..f8fbca13 100644 --- a/src/iso19111/coordinateoperation.cpp +++ b/src/iso19111/coordinateoperation.cpp @@ -296,6 +296,12 @@ const MethodMapping *getMapping(const char *wkt2_name) noexcept { return &mapping; } } + for (const auto &mapping : otherMethodMappings) { + if (metadata::Identifier::isEquivalentName(mapping.wkt2_name, + wkt2_name)) { + return &mapping; + } + } return nullptr; } @@ -1697,6 +1703,16 @@ double SingleOperation::parameterValueNumeric( return 0.0; } +double SingleOperation::parameterValueNumeric( + const char *param_name, const common::UnitOfMeasure &targetUnit) const + noexcept { + const auto &val = parameterValue(param_name, 0); + if (val && val->type() == ParameterValue::Type::MEASURE) { + return val->value().convertToUnit(targetUnit); + } + return 0.0; +} + //! @endcond // --------------------------------------------------------------------------- @@ -4669,6 +4685,58 @@ ConversionNNPtr Conversion::createVerticalPerspective( // --------------------------------------------------------------------------- +/** \brief Instantiate a conversion based on the Pole Rotation method, using + * the conventions of the GRIB 1 and GRIB 2 data formats. + * + * Those are mentionned in the Note 2 of + * https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp3-1.shtml + * + * Several conventions for the pole rotation method exists. + * The parameters provided in this method are remapped to the PROJ ob_tran + * operation with: + * <pre> + * +proj=ob_tran +o_proj=longlat +o_lon_p=-rotationAngle + * +o_lat_p=-southPoleLatInUnrotatedCRS + * +lon_0=southPoleLongInUnrotatedCRS + * </pre> + * + * Another implementation of that convention is also in the netcdf-java library: + * https://github.com/Unidata/netcdf-java/blob/3ce72c0cd167609ed8c69152bb4a004d1daa9273/cdm/core/src/main/java/ucar/unidata/geoloc/projection/RotatedLatLon.java + * + * The PROJ implementation of this method assumes a spherical ellipsoid. + * + * @param properties See \ref general_properties of the conversion. If the name + * is not provided, it is automatically set. + * @param southPoleLatInUnrotatedCRS Latitude of the point from the unrotated + * CRS, expressed in the unrotated CRS, that will become the south pole of the + * rotated CRS. + * @param southPoleLongInUnrotatedCRS Longitude of the point from the unrotated + * CRS, expressed in the unrotated CRS, that will become the south pole of the + * rotated CRS. + * @param axisRotation The angle of rotation about the new polar + * axis (measured clockwise when looking from the southern to the northern pole) + * of the coordinate system, assuming the new axis to have been obtained by + * first rotating the sphere through southPoleLongInUnrotatedCRS degrees about + * the geographic polar axis and then rotating through + * (90 + southPoleLatInUnrotatedCRS) degrees so that the southern pole moved + * along the (previously rotated) Greenwich meridian. + * @return a new Conversion. + * + * @since 7.0 + */ +ConversionNNPtr Conversion::createPoleRotationGRIBConvention( + const util::PropertyMap &properties, + const common::Angle &southPoleLatInUnrotatedCRS, + const common::Angle &southPoleLongInUnrotatedCRS, + const common::Angle &axisRotation) { + return create(properties, + PROJ_WKT2_NAME_METHOD_POLE_ROTATION_GRIB_CONVENTION, + createParams(southPoleLatInUnrotatedCRS, + southPoleLongInUnrotatedCRS, axisRotation)); +} + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress static OperationParameterNNPtr createOpParamNameEPSGCode(int code) { @@ -6069,6 +6137,23 @@ void Conversion::_exportToPROJString( } else if (starts_with(methodName, "PROJ ")) { bConversionDone = true; createPROJExtensionFromCustomProj(this, formatter, false); + } else if (ci_equal(methodName, + PROJ_WKT2_NAME_METHOD_POLE_ROTATION_GRIB_CONVENTION)) { + double southPoleLat = parameterValueNumeric( + PROJ_WKT2_NAME_PARAMETER_SOUTH_POLE_LATITUDE_GRIB_CONVENTION, + common::UnitOfMeasure::DEGREE); + double southPoleLon = parameterValueNumeric( + PROJ_WKT2_NAME_PARAMETER_SOUTH_POLE_LONGITUDE_GRIB_CONVENTION, + common::UnitOfMeasure::DEGREE); + double rotation = parameterValueNumeric( + PROJ_WKT2_NAME_PARAMETER_AXIS_ROTATION_GRIB_CONVENTION, + common::UnitOfMeasure::DEGREE); + formatter->addStep("ob_tran"); + formatter->addParam("o_proj", "longlat"); + formatter->addParam("o_lon_p", -rotation); + formatter->addParam("o_lat_p", -southPoleLat); + formatter->addParam("lon_0", southPoleLon); + bConversionDone = true; } else if (formatter->convention() == io::PROJStringFormatter::Convention::PROJ_5 && isZUnitConversion) { diff --git a/src/iso19111/crs.cpp b/src/iso19111/crs.cpp index cf533bd3..812707ef 100644 --- a/src/iso19111/crs.cpp +++ b/src/iso19111/crs.cpp @@ -45,6 +45,8 @@ #include "proj/internal/internal.hpp" #include "proj/internal/io_internal.hpp" +#include "proj_constants.h" + #include <algorithm> #include <cassert> #include <cstring> @@ -4893,7 +4895,9 @@ void DerivedGeographicCRS::_exportToPROJString( if (methodName == "PROJ ob_tran o_proj=longlat" || methodName == "PROJ ob_tran o_proj=lonlat" || methodName == "PROJ ob_tran o_proj=latlong" || - methodName == "PROJ ob_tran o_proj=latlon") { + methodName == "PROJ ob_tran o_proj=latlon" || + ci_equal(methodName, + PROJ_WKT2_NAME_METHOD_POLE_ROTATION_GRIB_CONVENTION)) { l_conv->_exportToPROJString(formatter); return; } diff --git a/src/proj_constants.h b/src/proj_constants.h index 62cf94be..5c642862 100644 --- a/src/proj_constants.h +++ b/src/proj_constants.h @@ -215,6 +215,8 @@ #define EPSG_NAME_METHOD_VERTICAL_PERSPECTIVE "Vertical Perspective" #define EPSG_CODE_METHOD_VERTICAL_PERSPECTIVE 9838 +#define PROJ_WKT2_NAME_METHOD_POLE_ROTATION_GRIB_CONVENTION "Pole rotation (GRIB convention)" + /* ------------------------------------------------------------------------ */ /* Projection parameters */ @@ -474,6 +476,15 @@ #define \ EPSG_NAME_PARAMETER_FLATTENING_DIFFERENCE "Flattening difference" +#define PROJ_WKT2_NAME_PARAMETER_SOUTH_POLE_LATITUDE_GRIB_CONVENTION \ + "Latitude of the southern pole (GRIB convention)" + +#define PROJ_WKT2_NAME_PARAMETER_SOUTH_POLE_LONGITUDE_GRIB_CONVENTION \ + "Longitude of the southern pole (GRIB convention)" + +#define PROJ_WKT2_NAME_PARAMETER_AXIS_ROTATION_GRIB_CONVENTION \ + "Axis rotation (GRIB convention)" + /* ------------------------------------------------------------------------ */ #define EPSG_CODE_METHOD_NTV1 9614 diff --git a/src/proj_experimental.h b/src/proj_experimental.h index 0886ba28..50f1fb9f 100644 --- a/src/proj_experimental.h +++ b/src/proj_experimental.h @@ -191,6 +191,16 @@ PJ PROJ_DLL *proj_create_geocentric_crs_from_datum( const char *linear_units, double linear_units_conv); +PJ PROJ_DLL *proj_create_derived_geographic_crs( + PJ_CONTEXT *ctx, + const char *crs_name, + const PJ* base_geographic_crs, + const PJ* conversion, + const PJ* ellipsoidal_cs); + +int PROJ_DLL proj_is_derived_crs(PJ_CONTEXT *ctx, + const PJ* crs); + PJ PROJ_DLL *proj_alter_name(PJ_CONTEXT *ctx, const PJ* obj, const char* name); @@ -947,6 +957,13 @@ PJ PROJ_DLL *proj_create_conversion_vertical_perspective( const char* ang_unit_name, double ang_unit_conv_factor, const char* linear_unit_name, double linear_unit_conv_factor); +PJ PROJ_DLL *proj_create_conversion_pole_rotation_grib_convention( + PJ_CONTEXT *ctx, + double south_pole_lat_in_unrotated_crs, + double south_pole_long_in_unrotated_crs, + double axis_rotation, + const char* ang_unit_name, double ang_unit_conv_factor); + /* END: Generated by scripts/create_c_api_projections.py*/ /**@}*/ diff --git a/test/unit/test_c_api.cpp b/test/unit/test_c_api.cpp index d8816acf..f87f6589 100644 --- a/test/unit/test_c_api.cpp +++ b/test/unit/test_c_api.cpp @@ -2411,6 +2411,13 @@ TEST_F(CApi, proj_create_projections) { ObjectKeeper keeper_projCRS(projCRS); ASSERT_NE(projCRS, nullptr); } + { + auto projCRS = proj_create_conversion_pole_rotation_grib_convention( + m_ctxt, 0, 0, 0, "Degree", 0.0174532925199433); + ObjectKeeper keeper_projCRS(projCRS); + ASSERT_NE(projCRS, nullptr); + } + /* END: Generated by scripts/create_c_api_projections.py*/ } @@ -4343,4 +4350,88 @@ TEST_F(CApi, proj_create_vertical_crs_ex_with_geog_crs) { EXPECT_EQ(std::string(proj_5_bis), std::string(proj_5)); } +// --------------------------------------------------------------------------- + +TEST_F(CApi, proj_create_derived_geographic_crs) { + + PJ *crs_4326 = proj_create(m_ctxt, "EPSG:4326"); + ObjectKeeper keeper_crs_4326(crs_4326); + ASSERT_NE(crs_4326, nullptr); + + PJ *conversion = proj_create_conversion_pole_rotation_grib_convention( + m_ctxt, 2, 3, 4, "Degree", 0.0174532925199433); + ObjectKeeper keeper_conversion(conversion); + ASSERT_NE(conversion, nullptr); + + PJ *cs = proj_crs_get_coordinate_system(m_ctxt, crs_4326); + ObjectKeeper keeper_cs(cs); + ASSERT_NE(cs, nullptr); + + ASSERT_EQ( + proj_create_derived_geographic_crs(m_ctxt, "my rotated CRS", + conversion, // wrong type of object + conversion, cs), + nullptr); + + ASSERT_EQ( + proj_create_derived_geographic_crs(m_ctxt, "my rotated CRS", crs_4326, + crs_4326, // wrong type of object + cs), + nullptr); + + ASSERT_EQ(proj_create_derived_geographic_crs( + m_ctxt, "my rotated CRS", crs_4326, conversion, + conversion // wrong type of object + ), + nullptr); + + PJ *derived_crs = proj_create_derived_geographic_crs( + m_ctxt, "my rotated CRS", crs_4326, conversion, cs); + ObjectKeeper keeper_derived_crs(derived_crs); + ASSERT_NE(derived_crs, nullptr); + + EXPECT_FALSE(proj_is_derived_crs(m_ctxt, crs_4326)); + EXPECT_TRUE(proj_is_derived_crs(m_ctxt, derived_crs)); + + auto wkt = proj_as_wkt(m_ctxt, derived_crs, PJ_WKT2_2019, nullptr); + const char *expected_wkt = + "GEOGCRS[\"my rotated CRS\",\n" + " BASEGEOGCRS[\"WGS 84\",\n" + " DATUM[\"World Geodetic System 1984\",\n" + " ELLIPSOID[\"WGS 84\",6378137,298.257223563,\n" + " LENGTHUNIT[\"metre\",1]]],\n" + " PRIMEM[\"Greenwich\",0,\n" + " ANGLEUNIT[\"degree\",0.0174532925199433]]],\n" + " DERIVINGCONVERSION[\"Pole rotation (GRIB convention)\",\n" + " METHOD[\"Pole rotation (GRIB convention)\"],\n" + " PARAMETER[\"Latitude of the southern pole (GRIB " + "convention)\",2,\n" + " ANGLEUNIT[\"degree\",0.0174532925199433,\n" + " ID[\"EPSG\",9122]]],\n" + " PARAMETER[\"Longitude of the southern pole (GRIB " + "convention)\",3,\n" + " ANGLEUNIT[\"degree\",0.0174532925199433,\n" + " ID[\"EPSG\",9122]]],\n" + " PARAMETER[\"Axis rotation (GRIB convention)\",4,\n" + " ANGLEUNIT[\"degree\",0.0174532925199433,\n" + " ID[\"EPSG\",9122]]]],\n" + " CS[ellipsoidal,2],\n" + " AXIS[\"geodetic latitude (Lat)\",north,\n" + " ORDER[1],\n" + " ANGLEUNIT[\"degree\",0.0174532925199433,\n" + " ID[\"EPSG\",9122]]],\n" + " AXIS[\"geodetic longitude (Lon)\",east,\n" + " ORDER[2],\n" + " ANGLEUNIT[\"degree\",0.0174532925199433,\n" + " ID[\"EPSG\",9122]]]]"; + + ASSERT_NE(wkt, nullptr); + EXPECT_EQ(wkt, std::string(expected_wkt)); + + auto proj_5 = proj_as_proj_string(m_ctxt, derived_crs, PJ_PROJ_5, nullptr); + ASSERT_NE(proj_5, nullptr); + EXPECT_EQ(proj_5, std::string("+proj=ob_tran +o_proj=longlat +o_lon_p=-4 " + "+o_lat_p=-2 +lon_0=3 +datum=WGS84 +no_defs " + "+type=crs")); +} } // namespace |
