diff options
| -rw-r--r-- | include/proj/coordinateoperation.hpp | 2 | ||||
| -rw-r--r-- | include/proj/datum.hpp | 2 | ||||
| -rw-r--r-- | include/proj/internal/coordinateoperation_constants.hpp | 353 | ||||
| -rw-r--r-- | src/c_api.cpp | 5 | ||||
| -rw-r--r-- | src/coordinateoperation.cpp | 157 | ||||
| -rw-r--r-- | src/datum.cpp | 8 | ||||
| -rw-r--r-- | src/io.cpp | 11 | ||||
| -rw-r--r-- | src/static.cpp | 5 | ||||
| -rw-r--r-- | test/unit/test_crs.cpp | 1 | ||||
| -rw-r--r-- | test/unit/test_factory.cpp | 5 | ||||
| -rw-r--r-- | test/unit/test_operation.cpp | 208 |
11 files changed, 731 insertions, 26 deletions
diff --git a/include/proj/coordinateoperation.hpp b/include/proj/coordinateoperation.hpp index 5f0f834f..8b9f8ee1 100644 --- a/include/proj/coordinateoperation.hpp +++ b/include/proj/coordinateoperation.hpp @@ -565,6 +565,8 @@ class PROJ_GCC_DLL SingleOperation : virtual public CoordinateOperation { PROJ_DLL std::set<GridDescription> gridsNeeded(const io::DatabaseContextPtr &databaseContext) const override; + PROJ_DLL std::list<std::string> validateParameters() const; + PROJ_PRIVATE : //! @cond Doxygen_Suppress diff --git a/include/proj/datum.hpp b/include/proj/datum.hpp index 12b93a04..6e60c47c 100644 --- a/include/proj/datum.hpp +++ b/include/proj/datum.hpp @@ -185,6 +185,7 @@ class PROJ_GCC_DLL PrimeMeridian final : public common::IdentifiedObject, const common::Angle &longitudeIn); PROJ_DLL static const PrimeMeridianNNPtr GREENWICH; + PROJ_DLL static const PrimeMeridianNNPtr REFERENCE_MERIDIAN; PROJ_DLL static const PrimeMeridianNNPtr PARIS; PROJ_PRIVATE : @@ -221,6 +222,7 @@ class PROJ_GCC_DLL PrimeMeridian final : public common::IdentifiedObject, PrimeMeridian &operator=(const PrimeMeridian &other) = delete; PROJ_INTERNAL static const PrimeMeridianNNPtr createGREENWICH(); + PROJ_INTERNAL static const PrimeMeridianNNPtr createREFERENCE_MERIDIAN(); PROJ_INTERNAL static const PrimeMeridianNNPtr createPARIS(); }; diff --git a/include/proj/internal/coordinateoperation_constants.hpp b/include/proj/internal/coordinateoperation_constants.hpp index 2e29e767..53a2622e 100644 --- a/include/proj/internal/coordinateoperation_constants.hpp +++ b/include/proj/internal/coordinateoperation_constants.hpp @@ -490,7 +490,7 @@ static const ParamMapping *const paramsLabordeObliqueMercator[] = { ¶mFalseNorthing, nullptr}; -static const MethodMapping methodMappings[] = { +static const MethodMapping projectionMethodMappings[] = { {EPSG_NAME_METHOD_TRANSVERSE_MERCATOR, EPSG_CODE_METHOD_TRANSVERSE_MERCATOR, "Transverse_Mercator", "tmerc", nullptr, paramsNatOriginScaleK}, @@ -888,6 +888,357 @@ static const struct ParamNameCode { PARAM_NAME_CODE(ORDINATE_3_EVAL_POINT), }; +static const ParamMapping paramUnitConversionScalar = { + EPSG_NAME_PARAMETER_UNIT_CONVERSION_SCALAR, + EPSG_CODE_PARAMETER_UNIT_CONVERSION_SCALAR, nullptr, + common::UnitOfMeasure::Type::SCALE, nullptr}; + +static const ParamMapping *const paramsChangeVerticalUnit[] = { + ¶mUnitConversionScalar, nullptr}; + +static const ParamMapping paramLongitudeOffset = { + EPSG_NAME_PARAMETER_LONGITUDE_OFFSET, EPSG_CODE_PARAMETER_LONGITUDE_OFFSET, + nullptr, common::UnitOfMeasure::Type::ANGULAR, nullptr}; + +static const ParamMapping *const paramsLongitudeRotation[] = { + ¶mLongitudeOffset, nullptr}; + +static const ParamMapping paramA0 = { + EPSG_NAME_PARAMETER_A0, EPSG_CODE_PARAMETER_A0, nullptr, + common::UnitOfMeasure::Type::UNKNOWN, nullptr}; + +static const ParamMapping paramA1 = { + EPSG_NAME_PARAMETER_A1, EPSG_CODE_PARAMETER_A1, nullptr, + common::UnitOfMeasure::Type::UNKNOWN, nullptr}; + +static const ParamMapping paramA2 = { + EPSG_NAME_PARAMETER_A2, EPSG_CODE_PARAMETER_A2, nullptr, + common::UnitOfMeasure::Type::UNKNOWN, nullptr}; + +static const ParamMapping paramB0 = { + EPSG_NAME_PARAMETER_B0, EPSG_CODE_PARAMETER_B0, nullptr, + common::UnitOfMeasure::Type::UNKNOWN, nullptr}; + +static const ParamMapping paramB1 = { + EPSG_NAME_PARAMETER_B1, EPSG_CODE_PARAMETER_B1, nullptr, + common::UnitOfMeasure::Type::UNKNOWN, nullptr}; + +static const ParamMapping paramB2 = { + EPSG_NAME_PARAMETER_B2, EPSG_CODE_PARAMETER_B2, nullptr, + common::UnitOfMeasure::Type::UNKNOWN, nullptr}; + +static const ParamMapping *const paramsAffineParametricTransformation[] = { + ¶mA0, ¶mA1, ¶mA2, ¶mB0, ¶mB1, ¶mB2, nullptr}; + +static const ParamMapping paramXTranslation = { + EPSG_NAME_PARAMETER_X_AXIS_TRANSLATION, + EPSG_CODE_PARAMETER_X_AXIS_TRANSLATION, nullptr, + common::UnitOfMeasure::Type::LINEAR, nullptr}; + +static const ParamMapping paramYTranslation = { + EPSG_NAME_PARAMETER_Y_AXIS_TRANSLATION, + EPSG_CODE_PARAMETER_Y_AXIS_TRANSLATION, nullptr, + common::UnitOfMeasure::Type::LINEAR, nullptr}; + +static const ParamMapping paramZTranslation = { + EPSG_NAME_PARAMETER_Z_AXIS_TRANSLATION, + EPSG_CODE_PARAMETER_Z_AXIS_TRANSLATION, nullptr, + common::UnitOfMeasure::Type::LINEAR, nullptr}; + +static const ParamMapping paramXRotation = { + EPSG_NAME_PARAMETER_X_AXIS_ROTATION, EPSG_CODE_PARAMETER_X_AXIS_ROTATION, + nullptr, common::UnitOfMeasure::Type::LINEAR, nullptr}; + +static const ParamMapping paramYRotation = { + EPSG_NAME_PARAMETER_Y_AXIS_ROTATION, EPSG_CODE_PARAMETER_Y_AXIS_ROTATION, + nullptr, common::UnitOfMeasure::Type::LINEAR, nullptr}; + +static const ParamMapping paramZRotation = { + EPSG_NAME_PARAMETER_Z_AXIS_ROTATION, EPSG_CODE_PARAMETER_Z_AXIS_ROTATION, + nullptr, common::UnitOfMeasure::Type::LINEAR, nullptr}; + +static const ParamMapping paramScaleDifference = { + EPSG_NAME_PARAMETER_SCALE_DIFFERENCE, EPSG_CODE_PARAMETER_SCALE_DIFFERENCE, + nullptr, common::UnitOfMeasure::Type::SCALE, nullptr}; + +static const ParamMapping *const paramsHelmert3[] = { + ¶mXTranslation, ¶mYTranslation, ¶mZTranslation, nullptr}; + +static const ParamMapping *const paramsHelmert7[] = { + ¶mXTranslation, ¶mYTranslation, + ¶mZTranslation, ¶mXRotation, + ¶mYRotation, ¶mZRotation, + ¶mScaleDifference, nullptr}; + +static const ParamMapping paramRateXTranslation = { + EPSG_NAME_PARAMETER_RATE_X_AXIS_TRANSLATION, + EPSG_CODE_PARAMETER_RATE_X_AXIS_TRANSLATION, nullptr, + common::UnitOfMeasure::Type::LINEAR, nullptr}; + +static const ParamMapping paramRateYTranslation = { + EPSG_NAME_PARAMETER_RATE_Y_AXIS_TRANSLATION, + EPSG_CODE_PARAMETER_RATE_Y_AXIS_TRANSLATION, nullptr, + common::UnitOfMeasure::Type::LINEAR, nullptr}; + +static const ParamMapping paramRateZTranslation = { + EPSG_NAME_PARAMETER_RATE_Z_AXIS_TRANSLATION, + EPSG_CODE_PARAMETER_RATE_Z_AXIS_TRANSLATION, nullptr, + common::UnitOfMeasure::Type::LINEAR, nullptr}; + +static const ParamMapping paramRateXRotation = { + EPSG_NAME_PARAMETER_RATE_X_AXIS_ROTATION, + EPSG_CODE_PARAMETER_RATE_X_AXIS_ROTATION, nullptr, + common::UnitOfMeasure::Type::LINEAR, nullptr}; + +static const ParamMapping paramRateYRotation = { + EPSG_NAME_PARAMETER_RATE_Y_AXIS_ROTATION, + EPSG_CODE_PARAMETER_RATE_Y_AXIS_ROTATION, nullptr, + common::UnitOfMeasure::Type::LINEAR, nullptr}; + +static const ParamMapping paramRateZRotation = { + EPSG_NAME_PARAMETER_RATE_Z_AXIS_ROTATION, + EPSG_CODE_PARAMETER_RATE_Z_AXIS_ROTATION, nullptr, + common::UnitOfMeasure::Type::LINEAR, nullptr}; + +static const ParamMapping paramRateScaleDifference = { + EPSG_NAME_PARAMETER_RATE_SCALE_DIFFERENCE, + EPSG_CODE_PARAMETER_RATE_SCALE_DIFFERENCE, nullptr, + common::UnitOfMeasure::Type::SCALE, nullptr}; + +static const ParamMapping paramReferenceEpoch = { + EPSG_NAME_PARAMETER_REFERENCE_EPOCH, EPSG_CODE_PARAMETER_REFERENCE_EPOCH, + nullptr, common::UnitOfMeasure::Type::TIME, nullptr}; + +static const ParamMapping *const paramsHelmert15[] = { + ¶mXTranslation, ¶mYTranslation, + ¶mZTranslation, ¶mXRotation, + ¶mYRotation, ¶mZRotation, + ¶mScaleDifference, ¶mRateXTranslation, + ¶mRateYTranslation, ¶mRateZTranslation, + ¶mRateXRotation, ¶mRateYRotation, + ¶mRateZRotation, ¶mRateScaleDifference, + ¶mReferenceEpoch, nullptr}; + +static const ParamMapping paramOrdinate1EvalPoint = { + EPSG_NAME_PARAMETER_ORDINATE_1_EVAL_POINT, + EPSG_CODE_PARAMETER_ORDINATE_1_EVAL_POINT, nullptr, + common::UnitOfMeasure::Type::LINEAR, nullptr}; + +static const ParamMapping paramOrdinate2EvalPoint = { + EPSG_NAME_PARAMETER_ORDINATE_2_EVAL_POINT, + EPSG_CODE_PARAMETER_ORDINATE_2_EVAL_POINT, nullptr, + common::UnitOfMeasure::Type::LINEAR, nullptr}; + +static const ParamMapping paramOrdinate3EvalPoint = { + EPSG_NAME_PARAMETER_ORDINATE_3_EVAL_POINT, + EPSG_CODE_PARAMETER_ORDINATE_3_EVAL_POINT, nullptr, + common::UnitOfMeasure::Type::LINEAR, nullptr}; + +static const ParamMapping *const paramsMolodenskyBadekas[] = { + ¶mXTranslation, + ¶mYTranslation, + ¶mZTranslation, + ¶mXRotation, + ¶mYRotation, + ¶mZRotation, + ¶mScaleDifference, + ¶mOrdinate1EvalPoint, + ¶mOrdinate2EvalPoint, + ¶mOrdinate3EvalPoint, + nullptr}; + +static const ParamMapping paramSemiMajorAxisDifference = { + EPSG_NAME_PARAMETER_SEMI_MAJOR_AXIS_DIFFERENCE, + EPSG_CODE_PARAMETER_SEMI_MAJOR_AXIS_DIFFERENCE, nullptr, + common::UnitOfMeasure::Type::LINEAR, nullptr}; + +static const ParamMapping paramFlatteningDifference = { + EPSG_NAME_PARAMETER_FLATTENING_DIFFERENCE, + EPSG_CODE_PARAMETER_FLATTENING_DIFFERENCE, nullptr, + common::UnitOfMeasure::Type::NONE, nullptr}; + +static const ParamMapping *const paramsMolodensky[] = { + ¶mXTranslation, ¶mYTranslation, + ¶mZTranslation, ¶mSemiMajorAxisDifference, + ¶mFlatteningDifference, nullptr}; + +static const ParamMapping paramLatitudeOffset = { + EPSG_NAME_PARAMETER_LATITUDE_OFFSET, EPSG_CODE_PARAMETER_LATITUDE_OFFSET, + nullptr, common::UnitOfMeasure::Type::ANGULAR, nullptr}; + +static const ParamMapping *const paramsGeographic2DOffsets[] = { + ¶mLatitudeOffset, ¶mLongitudeOffset, nullptr}; + +static const ParamMapping paramGeoidUndulation = { + EPSG_NAME_PARAMETER_GEOID_UNDULATION, EPSG_CODE_PARAMETER_GEOID_UNDULATION, + nullptr, common::UnitOfMeasure::Type::LINEAR, nullptr}; + +static const ParamMapping *const paramsGeographic2DWithHeightOffsets[] = { + ¶mLatitudeOffset, ¶mLongitudeOffset, ¶mGeoidUndulation, + nullptr}; + +static const ParamMapping paramVerticalOffset = { + EPSG_NAME_PARAMETER_VERTICAL_OFFSET, EPSG_CODE_PARAMETER_VERTICAL_OFFSET, + nullptr, common::UnitOfMeasure::Type::LINEAR, nullptr}; + +static const ParamMapping *const paramsGeographic3DOffsets[] = { + ¶mLatitudeOffset, ¶mLongitudeOffset, ¶mVerticalOffset, nullptr}; + +static const ParamMapping *const paramsVerticalOffsets[] = { + ¶mVerticalOffset, nullptr}; + +static const ParamMapping paramLatitudeLongitudeDifferenceFile = { + EPSG_NAME_PARAMETER_LATITUDE_LONGITUDE_DIFFERENCE_FILE, + EPSG_CODE_PARAMETER_LATITUDE_LONGITUDE_DIFFERENCE_FILE, nullptr, + common::UnitOfMeasure::Type::NONE, nullptr}; + +static const ParamMapping *const paramsNTV2[] = { + ¶mLatitudeLongitudeDifferenceFile, nullptr}; + +static const ParamMapping paramLatitudeDifferenceFile = { + EPSG_NAME_PARAMETER_LATITUDE_DIFFERENCE_FILE, + EPSG_CODE_PARAMETER_LATITUDE_DIFFERENCE_FILE, nullptr, + common::UnitOfMeasure::Type::NONE, nullptr}; + +static const ParamMapping paramLongitudeDifferenceFile = { + EPSG_NAME_PARAMETER_LONGITUDE_DIFFERENCE_FILE, + EPSG_CODE_PARAMETER_LONGITUDE_DIFFERENCE_FILE, nullptr, + common::UnitOfMeasure::Type::NONE, nullptr}; + +static const ParamMapping *const paramsNADCON[] = { + ¶mLatitudeDifferenceFile, ¶mLongitudeDifferenceFile, nullptr}; + +static const ParamMapping paramVerticalOffsetFile = { + EPSG_NAME_PARAMETER_VERTICAL_OFFSET_FILE, + EPSG_CODE_PARAMETER_VERTICAL_OFFSET_FILE, nullptr, + common::UnitOfMeasure::Type::NONE, nullptr}; + +static const ParamMapping *const paramsVERTCON[] = {¶mVerticalOffsetFile, + nullptr}; + +static const MethodMapping otherMethodMappings[] = { + {EPSG_NAME_METHOD_CHANGE_VERTICAL_UNIT, + EPSG_CODE_METHOD_CHANGE_VERTICAL_UNIT, nullptr, nullptr, nullptr, + paramsChangeVerticalUnit}, + {EPSG_NAME_METHOD_AXIS_ORDER_REVERSAL_2D, + EPSG_CODE_METHOD_AXIS_ORDER_REVERSAL_2D, nullptr, nullptr, nullptr, + nullptr}, + {EPSG_NAME_METHOD_AXIS_ORDER_REVERSAL_3D, + EPSG_CODE_METHOD_AXIS_ORDER_REVERSAL_3D, nullptr, nullptr, nullptr, + nullptr}, + {EPSG_NAME_METHOD_GEOGRAPHIC_GEOCENTRIC, + EPSG_CODE_METHOD_GEOGRAPHIC_GEOCENTRIC, nullptr, nullptr, nullptr, + nullptr}, + {EPSG_NAME_METHOD_LONGITUDE_ROTATION, EPSG_CODE_METHOD_LONGITUDE_ROTATION, + nullptr, nullptr, nullptr, paramsLongitudeRotation}, + {EPSG_NAME_METHOD_AFFINE_PARAMETRIC_TRANSFORMATION, + EPSG_CODE_METHOD_AFFINE_PARAMETRIC_TRANSFORMATION, nullptr, nullptr, + nullptr, paramsAffineParametricTransformation}, + + {EPSG_NAME_METHOD_GEOCENTRIC_TRANSLATION_GEOCENTRIC, + EPSG_CODE_METHOD_GEOCENTRIC_TRANSLATION_GEOCENTRIC, nullptr, nullptr, + nullptr, paramsHelmert3}, + {EPSG_NAME_METHOD_GEOCENTRIC_TRANSLATION_GEOGRAPHIC_2D, + EPSG_CODE_METHOD_GEOCENTRIC_TRANSLATION_GEOGRAPHIC_2D, nullptr, nullptr, + nullptr, paramsHelmert3}, + {EPSG_NAME_METHOD_GEOCENTRIC_TRANSLATION_GEOGRAPHIC_3D, + EPSG_CODE_METHOD_GEOCENTRIC_TRANSLATION_GEOGRAPHIC_3D, nullptr, nullptr, + nullptr, paramsHelmert3}, + + {EPSG_NAME_METHOD_COORDINATE_FRAME_GEOCENTRIC, + EPSG_CODE_METHOD_COORDINATE_FRAME_GEOCENTRIC, nullptr, nullptr, nullptr, + paramsHelmert7}, + {EPSG_NAME_METHOD_COORDINATE_FRAME_GEOGRAPHIC_2D, + EPSG_CODE_METHOD_COORDINATE_FRAME_GEOGRAPHIC_2D, nullptr, nullptr, nullptr, + paramsHelmert7}, + {EPSG_NAME_METHOD_COORDINATE_FRAME_GEOGRAPHIC_3D, + EPSG_CODE_METHOD_COORDINATE_FRAME_GEOGRAPHIC_3D, nullptr, nullptr, nullptr, + paramsHelmert7}, + + {EPSG_NAME_METHOD_POSITION_VECTOR_GEOCENTRIC, + EPSG_CODE_METHOD_POSITION_VECTOR_GEOCENTRIC, nullptr, nullptr, nullptr, + paramsHelmert7}, + {EPSG_NAME_METHOD_POSITION_VECTOR_GEOGRAPHIC_2D, + EPSG_CODE_METHOD_POSITION_VECTOR_GEOGRAPHIC_2D, nullptr, nullptr, nullptr, + paramsHelmert7}, + {EPSG_NAME_METHOD_POSITION_VECTOR_GEOGRAPHIC_3D, + EPSG_CODE_METHOD_POSITION_VECTOR_GEOGRAPHIC_3D, nullptr, nullptr, nullptr, + paramsHelmert7}, + + {EPSG_NAME_METHOD_TIME_DEPENDENT_COORDINATE_FRAME_GEOCENTRIC, + EPSG_CODE_METHOD_TIME_DEPENDENT_COORDINATE_FRAME_GEOCENTRIC, nullptr, + nullptr, nullptr, paramsHelmert15}, + {EPSG_NAME_METHOD_TIME_DEPENDENT_COORDINATE_FRAME_GEOGRAPHIC_2D, + EPSG_CODE_METHOD_TIME_DEPENDENT_COORDINATE_FRAME_GEOGRAPHIC_2D, nullptr, + nullptr, nullptr, paramsHelmert15}, + {EPSG_NAME_METHOD_TIME_DEPENDENT_COORDINATE_FRAME_GEOGRAPHIC_3D, + EPSG_CODE_METHOD_TIME_DEPENDENT_COORDINATE_FRAME_GEOGRAPHIC_3D, nullptr, + nullptr, nullptr, paramsHelmert15}, + + {EPSG_NAME_METHOD_TIME_DEPENDENT_POSITION_VECTOR_GEOCENTRIC, + EPSG_CODE_METHOD_TIME_DEPENDENT_POSITION_VECTOR_GEOCENTRIC, nullptr, + nullptr, nullptr, paramsHelmert15}, + {EPSG_NAME_METHOD_TIME_DEPENDENT_POSITION_VECTOR_GEOGRAPHIC_2D, + EPSG_CODE_METHOD_TIME_DEPENDENT_POSITION_VECTOR_GEOGRAPHIC_2D, nullptr, + nullptr, nullptr, paramsHelmert15}, + {EPSG_NAME_METHOD_TIME_DEPENDENT_POSITION_VECTOR_GEOGRAPHIC_3D, + EPSG_CODE_METHOD_TIME_DEPENDENT_POSITION_VECTOR_GEOGRAPHIC_3D, nullptr, + nullptr, nullptr, paramsHelmert15}, + + {EPSG_NAME_METHOD_MOLODENSKY_BADEKAS_CF_GEOCENTRIC, + EPSG_CODE_METHOD_MOLODENSKY_BADEKAS_CF_GEOCENTRIC, nullptr, nullptr, + nullptr, paramsMolodenskyBadekas}, + {EPSG_NAME_METHOD_MOLODENSKY_BADEKAS_CF_GEOGRAPHIC_2D, + EPSG_CODE_METHOD_MOLODENSKY_BADEKAS_CF_GEOGRAPHIC_2D, nullptr, nullptr, + nullptr, paramsMolodenskyBadekas}, + {EPSG_NAME_METHOD_MOLODENSKY_BADEKAS_CF_GEOGRAPHIC_3D, + EPSG_CODE_METHOD_MOLODENSKY_BADEKAS_CF_GEOGRAPHIC_3D, nullptr, nullptr, + nullptr, paramsMolodenskyBadekas}, + + {EPSG_NAME_METHOD_MOLODENSKY_BADEKAS_PV_GEOCENTRIC, + EPSG_CODE_METHOD_MOLODENSKY_BADEKAS_PV_GEOCENTRIC, nullptr, nullptr, + nullptr, paramsMolodenskyBadekas}, + {EPSG_NAME_METHOD_MOLODENSKY_BADEKAS_PV_GEOGRAPHIC_2D, + EPSG_CODE_METHOD_MOLODENSKY_BADEKAS_PV_GEOGRAPHIC_2D, nullptr, nullptr, + nullptr, paramsMolodenskyBadekas}, + {EPSG_NAME_METHOD_MOLODENSKY_BADEKAS_PV_GEOGRAPHIC_3D, + EPSG_CODE_METHOD_MOLODENSKY_BADEKAS_PV_GEOGRAPHIC_3D, nullptr, nullptr, + nullptr, paramsMolodenskyBadekas}, + + {EPSG_NAME_METHOD_MOLODENSKY, EPSG_CODE_METHOD_MOLODENSKY, nullptr, nullptr, + nullptr, paramsMolodensky}, + + {EPSG_NAME_METHOD_ABRIDGED_MOLODENSKY, EPSG_CODE_METHOD_ABRIDGED_MOLODENSKY, + nullptr, nullptr, nullptr, paramsMolodensky}, + + {EPSG_NAME_METHOD_GEOGRAPHIC2D_OFFSETS, + EPSG_CODE_METHOD_GEOGRAPHIC2D_OFFSETS, nullptr, nullptr, nullptr, + paramsGeographic2DOffsets}, + + {EPSG_NAME_METHOD_GEOGRAPHIC2D_WITH_HEIGHT_OFFSETS, + EPSG_CODE_METHOD_GEOGRAPHIC2D_WITH_HEIGHT_OFFSETS, nullptr, nullptr, + nullptr, paramsGeographic2DWithHeightOffsets}, + + {EPSG_NAME_METHOD_GEOGRAPHIC3D_OFFSETS, + EPSG_CODE_METHOD_GEOGRAPHIC3D_OFFSETS, nullptr, nullptr, nullptr, + paramsGeographic3DOffsets}, + + {EPSG_NAME_METHOD_VERTICAL_OFFSET, EPSG_CODE_METHOD_VERTICAL_OFFSET, + nullptr, nullptr, nullptr, paramsVerticalOffsets}, + + {EPSG_NAME_METHOD_NTV2, EPSG_CODE_METHOD_NTV2, nullptr, nullptr, nullptr, + paramsNTV2}, + + {EPSG_NAME_METHOD_NTV1, EPSG_CODE_METHOD_NTV1, nullptr, nullptr, nullptr, + paramsNTV2}, + + {EPSG_NAME_METHOD_NADCON, EPSG_CODE_METHOD_NADCON, nullptr, nullptr, + nullptr, paramsNADCON}, + + {EPSG_NAME_METHOD_VERTCON, EPSG_CODE_METHOD_VERTCON, nullptr, nullptr, + nullptr, paramsVERTCON}, +}; + // end of anonymous namespace } diff --git a/src/c_api.cpp b/src/c_api.cpp index d4e5c5db..8140f3b3 100644 --- a/src/c_api.cpp +++ b/src/c_api.cpp @@ -2071,8 +2071,9 @@ static GeodeticReferenceFrameNNPtr createGeodeticReferenceFrame( ? prime_meridian_name : prime_meridian_offset == 0.0 ? (ellps->celestialBody() == Ellipsoid::EARTH - ? "Greenwich" - : "Reference meridian") + ? PrimeMeridian::GREENWICH->nameStr().c_str() + : PrimeMeridian::REFERENCE_MERIDIAN->nameStr() + .c_str()) : "unnamed"), Angle(prime_meridian_offset, angUnit)); diff --git a/src/coordinateoperation.cpp b/src/coordinateoperation.cpp index 43b04e03..98a2d830 100644 --- a/src/coordinateoperation.cpp +++ b/src/coordinateoperation.cpp @@ -200,7 +200,7 @@ bool areEquivalentParameters(const std::string &a, const std::string &b) { // --------------------------------------------------------------------------- PROJ_NO_INLINE const MethodMapping *getMapping(int epsg_code) noexcept { - for (const auto &mapping : methodMappings) { + for (const auto &mapping : projectionMethodMappings) { if (mapping.epsg_code == epsg_code) { return &mapping; } @@ -213,7 +213,7 @@ PROJ_NO_INLINE const MethodMapping *getMapping(int epsg_code) noexcept { const MethodMapping *getMapping(const OperationMethod *method) noexcept { const std::string &name(method->nameStr()); const int epsg_code = method->getEPSGCode(); - for (const auto &mapping : methodMappings) { + for (const auto &mapping : projectionMethodMappings) { if ((epsg_code != 0 && mapping.epsg_code == epsg_code) || metadata::Identifier::isEquivalentName(mapping.wkt2_name, name.c_str())) { @@ -231,7 +231,7 @@ const MethodMapping *getMappingFromWKT1(const std::string &wkt1_name) noexcept { return getMapping(EPSG_CODE_METHOD_TRANSVERSE_MERCATOR); } - for (const auto &mapping : methodMappings) { + for (const auto &mapping : projectionMethodMappings) { if (mapping.wkt1_name && metadata::Identifier::isEquivalentName( mapping.wkt1_name, wkt1_name.c_str())) { return &mapping; @@ -242,7 +242,7 @@ const MethodMapping *getMappingFromWKT1(const std::string &wkt1_name) noexcept { // --------------------------------------------------------------------------- const MethodMapping *getMapping(const char *wkt2_name) noexcept { - for (const auto &mapping : methodMappings) { + for (const auto &mapping : projectionMethodMappings) { if (metadata::Identifier::isEquivalentName(mapping.wkt2_name, wkt2_name)) { return &mapping; @@ -256,7 +256,7 @@ const MethodMapping *getMapping(const char *wkt2_name) noexcept { std::vector<const MethodMapping *> getMappingsFromPROJName(const std::string &projName) { std::vector<const MethodMapping *> res; - for (const auto &mapping : methodMappings) { + for (const auto &mapping : projectionMethodMappings) { if (mapping.proj_name_main && projName == mapping.proj_name_main) { res.push_back(&mapping); } @@ -268,6 +268,10 @@ getMappingsFromPROJName(const std::string &projName) { static const ParamMapping *getMapping(const MethodMapping *mapping, const OperationParameterNNPtr ¶m) { + if (mapping->params == nullptr) { + return nullptr; + } + // First try with id const int epsg_code = param->getEPSGCode(); if (epsg_code) { @@ -1766,6 +1770,140 @@ std::set<GridDescription> SingleOperation::gridsNeeded( // --------------------------------------------------------------------------- +/** \brief Validate the parameters used by a coodinate operation. + * + * Return whether the method is known or not, or a list of missing or extra + * parameters for the operations recognized by this implementation. + */ +std::list<std::string> SingleOperation::validateParameters() const { + std::list<std::string> res; + + const auto &l_method = method(); + const auto &methodName = l_method->nameStr(); + const MethodMapping *methodMapping = nullptr; + const auto methodEPSGCode = l_method->getEPSGCode(); + for (const auto &mapping : projectionMethodMappings) { + if (metadata::Identifier::isEquivalentName(mapping.wkt2_name, + methodName.c_str()) || + (methodEPSGCode != 0 && methodEPSGCode == mapping.epsg_code)) { + methodMapping = &mapping; + } + } + if (methodMapping == nullptr) { + for (const auto &mapping : otherMethodMappings) { + if (metadata::Identifier::isEquivalentName(mapping.wkt2_name, + methodName.c_str()) || + (methodEPSGCode != 0 && methodEPSGCode == mapping.epsg_code)) { + methodMapping = &mapping; + } + } + } + if (!methodMapping) { + res.emplace_back("Unknown method " + methodName); + return res; + } + if (methodMapping->wkt2_name != methodName) { + if (metadata::Identifier::isEquivalentName(methodMapping->wkt2_name, + methodName.c_str())) { + std::string msg("Method name "); + msg += methodName; + msg += " is equivalent to official "; + msg += methodMapping->wkt2_name; + msg += " but not strictly equal"; + res.emplace_back(msg); + } else { + std::string msg("Method name "); + msg += methodName; + msg += ", matched to "; + msg += methodMapping->wkt2_name; + msg += ", through its EPSG code has not an equivalent name"; + res.emplace_back(msg); + } + } + if (methodEPSGCode != 0 && methodEPSGCode != methodMapping->epsg_code) { + std::string msg("Method of EPSG code "); + msg += toString(methodEPSGCode); + msg += " does not match official code ("; + msg += toString(methodMapping->epsg_code); + msg += ')'; + res.emplace_back(msg); + } + + // Check if expected parameters are found + for (int i = 0; + methodMapping->params && methodMapping->params[i] != nullptr; ++i) { + const auto *paramMapping = methodMapping->params[i]; + + const OperationParameterValue *opv = nullptr; + for (const auto &genOpParamvalue : parameterValues()) { + auto opParamvalue = dynamic_cast<const OperationParameterValue *>( + genOpParamvalue.get()); + if (opParamvalue) { + const auto ¶meter = opParamvalue->parameter(); + if ((paramMapping->epsg_code != 0 && + parameter->getEPSGCode() == paramMapping->epsg_code) || + ci_equal(parameter->nameStr(), paramMapping->wkt2_name)) { + opv = opParamvalue; + break; + } + } + } + + if (!opv) { + std::string msg("Cannot find expected parameter "); + msg += paramMapping->wkt2_name; + res.emplace_back(msg); + continue; + } + const auto ¶meter = opv->parameter(); + if (paramMapping->wkt2_name != parameter->nameStr()) { + if (ci_equal(parameter->nameStr(), paramMapping->wkt2_name)) { + std::string msg("Parameter name "); + msg += parameter->nameStr(); + msg += " is equivalent to official "; + msg += paramMapping->wkt2_name; + msg += " but not strictly equal"; + res.emplace_back(msg); + } else { + std::string msg("Parameter name "); + msg += parameter->nameStr(); + msg += ", matched to "; + msg += paramMapping->wkt2_name; + msg += ", through its EPSG code has not an equivalent name"; + res.emplace_back(msg); + } + } + const auto paramEPSGCode = parameter->getEPSGCode(); + if (paramEPSGCode != 0 && paramEPSGCode != paramMapping->epsg_code) { + std::string msg("Paramater of EPSG code "); + msg += toString(paramEPSGCode); + msg += " does not match official code ("; + msg += toString(paramMapping->epsg_code); + msg += ')'; + res.emplace_back(msg); + } + } + + // Check if there are extra parameters + for (const auto &genOpParamvalue : parameterValues()) { + auto opParamvalue = dynamic_cast<const OperationParameterValue *>( + genOpParamvalue.get()); + if (opParamvalue) { + const auto ¶meter = opParamvalue->parameter(); + if (!getMapping(methodMapping, parameter)) { + std::string msg("Parameter "); + msg += parameter->nameStr(); + msg += " found but not expected for this method"; + res.emplace_back(msg); + } + } + } + + return res; +} + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress struct ParameterValue::Private { ParameterValue::Type type_{ParameterValue::Type::STRING}; @@ -7865,8 +8003,6 @@ static void setupPROJGeodeticTargetCRS(io::PROJStringFormatter *formatter, } } -inline static void consume_unused(const std::string &) {} - //! @endcond // --------------------------------------------------------------------------- @@ -8027,12 +8163,7 @@ void Transformation::_exportToPROJString( EPSG_CODE_METHOD_MOLODENSKY_BADEKAS_CF_GEOGRAPHIC_2D || methodEPSGCode == EPSG_CODE_METHOD_MOLODENSKY_BADEKAS_PV_GEOGRAPHIC_2D) { - consume_unused(EPSG_NAME_METHOD_MOLODENSKY_BADEKAS_CF_GEOCENTRIC); - consume_unused(EPSG_NAME_METHOD_MOLODENSKY_BADEKAS_PV_GEOCENTRIC); - consume_unused(EPSG_NAME_METHOD_MOLODENSKY_BADEKAS_CF_GEOGRAPHIC_3D); - consume_unused(EPSG_NAME_METHOD_MOLODENSKY_BADEKAS_PV_GEOGRAPHIC_3D); - consume_unused(EPSG_NAME_METHOD_MOLODENSKY_BADEKAS_CF_GEOGRAPHIC_2D); - consume_unused(EPSG_NAME_METHOD_MOLODENSKY_BADEKAS_PV_GEOGRAPHIC_2D); + positionVectorConvention = isPositionVector || methodEPSGCode == diff --git a/src/datum.cpp b/src/datum.cpp index 975a870a..16e86296 100644 --- a/src/datum.cpp +++ b/src/datum.cpp @@ -295,6 +295,14 @@ const PrimeMeridianNNPtr PrimeMeridian::createGREENWICH() { // --------------------------------------------------------------------------- +const PrimeMeridianNNPtr PrimeMeridian::createREFERENCE_MERIDIAN() { + return create(util::PropertyMap().set(IdentifiedObject::NAME_KEY, + "Reference meridian"), + common::Angle(0)); +} + +// --------------------------------------------------------------------------- + const PrimeMeridianNNPtr PrimeMeridian::createPARIS() { return create(createMapNameEPSGCode("Paris", 8903), common::Angle(2.5969213, common::UnitOfMeasure::GRAD)); @@ -1876,21 +1876,12 @@ optional<std::string> WKTParser::Private::getAnchor(const WKTNodeNNPtr &node) { // --------------------------------------------------------------------------- -static const PrimeMeridianNNPtr &createReferenceMeridian() { - static const PrimeMeridianNNPtr meridian = PrimeMeridian::create( - PropertyMap().set(IdentifiedObject::NAME_KEY, "Reference meridian"), - common::Angle(0)); - return meridian; -} - -// --------------------------------------------------------------------------- - static const PrimeMeridianNNPtr & fixupPrimeMeridan(const EllipsoidNNPtr &ellipsoid, const PrimeMeridianNNPtr &pm) { return (ellipsoid->celestialBody() != Ellipsoid::EARTH && pm.get() == PrimeMeridian::GREENWICH.get()) - ? createReferenceMeridian() + ? PrimeMeridian::REFERENCE_MERIDIAN : pm; } diff --git a/src/static.cpp b/src/static.cpp index e30e68b7..c79f2099 100644 --- a/src/static.cpp +++ b/src/static.cpp @@ -565,6 +565,11 @@ const RealizationMethod RealizationMethod::TIDAL("tidal"); /** \brief The Greenwich PrimeMeridian */ const PrimeMeridianNNPtr PrimeMeridian::GREENWICH(PrimeMeridian::createGREENWICH()); +/** \brief The "Reference Meridian" PrimeMeridian. + * + * This is a meridian of longitude 0 to be used with non-Earth bodies. */ +const PrimeMeridianNNPtr PrimeMeridian::REFERENCE_MERIDIAN( + PrimeMeridian::createREFERENCE_MERIDIAN()); /** \brief The Paris PrimeMeridian */ const PrimeMeridianNNPtr PrimeMeridian::PARIS(PrimeMeridian::createPARIS()); diff --git a/test/unit/test_crs.cpp b/test/unit/test_crs.cpp index 6ed002a9..30157611 100644 --- a/test/unit/test_crs.cpp +++ b/test/unit/test_crs.cpp @@ -4068,6 +4068,7 @@ TEST(crs, derivedGeographicCRS_with_affine_transform_to_PROJ) { auto obj = WKTParser().createFromWKT(wkt); auto crs = nn_dynamic_pointer_cast<DerivedGeographicCRS>(obj); ASSERT_TRUE(crs != nullptr); + EXPECT_TRUE(crs->derivingConversion()->validateParameters().empty()); EXPECT_EQ(crs->exportToPROJString(PROJStringFormatter::create().get()), "+proj=affine +xoff=0.5 +s11=1 +s12=0 +yoff=2.5 +s21=0 +s22=1"); } diff --git a/test/unit/test_factory.cpp b/test/unit/test_factory.cpp index 9ca844b1..3d9744c8 100644 --- a/test/unit/test_factory.cpp +++ b/test/unit/test_factory.cpp @@ -825,6 +825,11 @@ TEST(factory, AuthorityFactory_createCoordinateOperation_molodensky_badekas_PV) { auto factory = AuthorityFactory::create(DatabaseContext::create(), "EPSG"); auto op = factory->createCoordinateOperation("1066", false); + + auto so = nn_dynamic_pointer_cast<SingleOperation>(op); + ASSERT_TRUE(so != nullptr); + EXPECT_TRUE(so->validateParameters().empty()); + EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), "+proj=pipeline +step +proj=axisswap +order=2,1 +step " "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=cart " diff --git a/test/unit/test_operation.cpp b/test/unit/test_operation.cpp index 2695153a..905eecdb 100644 --- a/test/unit/test_operation.cpp +++ b/test/unit/test_operation.cpp @@ -541,6 +541,7 @@ TEST(operation, transformation_createGeocentricTranslations) { auto transf = Transformation::createGeocentricTranslations( PropertyMap(), GeographicCRS::EPSG_4269, GeographicCRS::EPSG_4326, 1.0, 2.0, 3.0, std::vector<PositionalAccuracyNNPtr>()); + EXPECT_TRUE(transf->validateParameters().empty()); auto params = transf->getTOWGS84Parameters(); auto expected = std::vector<double>{1.0, 2.0, 3.0, 0.0, 0.0, 0.0, 0.0}; @@ -659,6 +660,8 @@ TEST(operation, transformation_createPositionVector) { PropertyMap(), GeographicCRS::EPSG_4269, GeographicCRS::EPSG_4326, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, std::vector<PositionalAccuracyNNPtr>{ PositionalAccuracy::create("100")}); + EXPECT_TRUE(transf->validateParameters().empty()); + ASSERT_EQ(transf->coordinateOperationAccuracies().size(), 1); auto expected = std::vector<double>{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0}; @@ -727,6 +730,7 @@ TEST(operation, transformation_createCoordinateFrameRotation) { PropertyMap(), GeographicCRS::EPSG_4269, GeographicCRS::EPSG_4326, 1.0, 2.0, 3.0, -4.0, -5.0, -6.0, 7.0, std::vector<PositionalAccuracyNNPtr>()); + EXPECT_TRUE(transf->validateParameters().empty()); auto params = transf->getTOWGS84Parameters(); auto expected = std::vector<double>{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0}; @@ -795,6 +799,7 @@ TEST(operation, transformation_createTimeDependentPositionVector) { PropertyMap(), GeographicCRS::EPSG_4269, GeographicCRS::EPSG_4326, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 2018.5, std::vector<PositionalAccuracyNNPtr>()); + EXPECT_TRUE(transf->validateParameters().empty()); auto inv_transf = transf->inverse(); @@ -867,6 +872,7 @@ TEST(operation, transformation_createTimeDependentCoordinateFrameRotation) { PropertyMap(), GeographicCRS::EPSG_4269, GeographicCRS::EPSG_4326, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 2018.5, std::vector<PositionalAccuracyNNPtr>()); + EXPECT_TRUE(transf->validateParameters().empty()); auto inv_transf = transf->inverse(); @@ -1001,6 +1007,7 @@ TEST(operation, transformation_createMolodensky) { auto transf = Transformation::createMolodensky( PropertyMap(), GeographicCRS::EPSG_4326, GeographicCRS::EPSG_4269, 1.0, 2.0, 3.0, 4.0, 5.0, std::vector<PositionalAccuracyNNPtr>()); + EXPECT_TRUE(transf->validateParameters().empty()); auto wkt = transf->exportToWKT(WKTFormatter::create().get()); EXPECT_TRUE(replaceAll(replaceAll(wkt, " ", ""), "\n", "") @@ -1144,6 +1151,15 @@ TEST(operation, transformation_createTOWGS84) { TEST(operation, createAxisOrderReversal) { + { + auto conv = Conversion::createAxisOrderReversal(false); + EXPECT_TRUE(conv->validateParameters().empty()); + } + { + auto conv = Conversion::createAxisOrderReversal(true); + EXPECT_TRUE(conv->validateParameters().empty()); + } + auto latLongDeg = GeographicCRS::create( PropertyMap(), GeodeticReferenceFrame::EPSG_6326, EllipsoidalCS::createLatitudeLongitude(UnitOfMeasure::DEGREE)); @@ -1174,6 +1190,7 @@ TEST(operation, createAxisOrderReversal) { TEST(operation, utm_export) { auto conv = Conversion::createUTM(PropertyMap(), 1, false); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=utm +zone=1 +south"); @@ -1214,6 +1231,7 @@ TEST(operation, utm_export) { TEST(operation, tmerc_export) { auto conv = Conversion::createTransverseMercator( PropertyMap(), Angle(1), Angle(2), Scale(3), Length(4), Length(5)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=tmerc +lat_0=1 +lon_0=2 +k=3 +x_0=4 +y_0=5"); @@ -1260,6 +1278,7 @@ TEST(operation, tmerc_export) { TEST(operation, gstmerc_export) { auto conv = Conversion::createGaussSchreiberTransverseMercator( PropertyMap(), Angle(1), Angle(2), Scale(3), Length(4), Length(5)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=gstmerc +lat_0=1 +lon_0=2 +k_0=3 +x_0=4 +y_0=5"); @@ -1298,6 +1317,7 @@ TEST(operation, gstmerc_export) { TEST(operation, tmerc_south_oriented_export) { auto conv = Conversion::createTransverseMercatorSouthOriented( PropertyMap(), Angle(1), Angle(2), Scale(3), Length(4), Length(5)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=tmerc +axis=wsu +lat_0=1 +lon_0=2 +k=3 +x_0=4 +y_0=5"); @@ -1368,6 +1388,8 @@ TEST(operation, tped_export) { auto conv = Conversion::createTwoPointEquidistant( PropertyMap(), Angle(1), Angle(2), Angle(3), Angle(4), Length(5), Length(6)); + EXPECT_TRUE(conv->validateParameters().empty()); + EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=tpeqd +lat_1=1 +lon_1=2 +lat_2=3 +lon_2=4 +x_0=5 +y_0=6"); @@ -1408,6 +1430,8 @@ TEST(operation, tped_export) { TEST(operation, tmg_export) { auto conv = Conversion::createTunisiaMappingGrid( PropertyMap(), Angle(1), Angle(2), Length(3), Length(4)); + EXPECT_TRUE(conv->validateParameters().empty()); + EXPECT_THROW(conv->exportToPROJString(PROJStringFormatter::create().get()), FormattingException); @@ -1444,6 +1468,7 @@ TEST(operation, aea_export) { auto conv = Conversion::createAlbersEqualArea(PropertyMap(), Angle(1), Angle(2), Angle(3), Angle(4), Length(5), Length(6)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=aea +lat_0=1 +lon_0=2 +lat_1=3 +lat_2=4 +x_0=5 +y_0=6"); @@ -1488,6 +1513,7 @@ TEST(operation, aea_export) { TEST(operation, azimuthal_equidistant_export) { auto conv = Conversion::createAzimuthalEquidistant( PropertyMap(), Angle(1), Angle(2), Length(3), Length(4)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=aeqd +lat_0=1 +lon_0=2 +x_0=3 +y_0=4"); @@ -1524,6 +1550,7 @@ TEST(operation, azimuthal_equidistant_export) { TEST(operation, guam_projection_export) { auto conv = Conversion::createGuamProjection( PropertyMap(), Angle(1), Angle(2), Length(3), Length(4)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=aeqd +guam +lat_0=1 +lon_0=2 +x_0=3 +y_0=4"); @@ -1556,6 +1583,7 @@ TEST(operation, guam_projection_export) { TEST(operation, bonne_export) { auto conv = Conversion::createBonne(PropertyMap(), Angle(1), Angle(2), Length(3), Length(4)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=bonne +lat_1=1 +lon_0=2 +x_0=3 +y_0=4"); @@ -1611,6 +1639,7 @@ TEST(operation, bonne_export) { TEST(operation, lambert_cylindrical_equal_area_spherical_export) { auto conv = Conversion::createLambertCylindricalEqualAreaSpherical( PropertyMap(), Angle(1), Angle(2), Length(3), Length(4)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=cea +lat_ts=1 +lon_0=2 +x_0=3 +y_0=4"); @@ -1647,6 +1676,7 @@ TEST(operation, lambert_cylindrical_equal_area_spherical_export) { TEST(operation, lambert_cylindrical_equal_area_export) { auto conv = Conversion::createLambertCylindricalEqualArea( PropertyMap(), Angle(1), Angle(2), Length(3), Length(4)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=cea +lat_ts=1 +lon_0=2 +x_0=3 +y_0=4"); @@ -1683,6 +1713,8 @@ TEST(operation, lambert_cylindrical_equal_area_export) { TEST(operation, lcc1sp_export) { auto conv = Conversion::createLambertConicConformal_1SP( PropertyMap(), Angle(1), Angle(2), Scale(3), Length(4), Length(5)); + EXPECT_TRUE(conv->validateParameters().empty()); + EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=lcc +lat_1=1 +lat_0=1 +lon_0=2 +k_0=3 +x_0=4 +y_0=5"); @@ -1723,6 +1755,8 @@ TEST(operation, lcc2sp_export) { auto conv = Conversion::createLambertConicConformal_2SP( PropertyMap(), Angle(1), Angle(2), Angle(3), Angle(4), Length(5), Length(6)); + EXPECT_TRUE(conv->validateParameters().empty()); + EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=lcc +lat_0=1 +lon_0=2 +lat_1=3 +lat_2=4 +x_0=5 +y_0=6"); @@ -1788,6 +1822,8 @@ TEST(operation, lcc2sp_michigan_export) { auto conv = Conversion::createLambertConicConformal_2SP_Michigan( PropertyMap(), Angle(1), Angle(2), Angle(3), Angle(4), Length(5), Length(6), Scale(7)); + EXPECT_TRUE(conv->validateParameters().empty()); + EXPECT_EQ( conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=lcc +lat_0=1 +lon_0=2 +lat_1=3 +lat_2=4 +x_0=5 +y_0=6 +k_0=7"); @@ -1873,6 +1909,7 @@ TEST(operation, lcc2sp_belgium_export) { TEST(operation, cassini_soldner_export) { auto conv = Conversion::createCassiniSoldner( PropertyMap(), Angle(1), Angle(2), Length(4), Length(5)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=cass +lat_0=1 +lon_0=2 +x_0=4 +y_0=5"); @@ -1910,6 +1947,7 @@ TEST(operation, equidistant_conic_export) { auto conv = Conversion::createEquidistantConic(PropertyMap(), Angle(1), Angle(2), Angle(3), Angle(4), Length(5), Length(6)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=eqdc +lat_0=1 +lon_0=2 +lat_1=3 +lat_2=4 +x_0=5 +y_0=6"); @@ -1979,6 +2017,8 @@ TEST(operation, eckert_export) { PropertyMap(), Angle(1), Length(2), Length(3)); + EXPECT_TRUE(conv->validateParameters().empty()); + EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=eck" + numbers[i] + " +lon_0=1 +x_0=2 +y_0=3"); @@ -2014,6 +2054,7 @@ TEST(operation, eckert_export) { TEST(operation, createEquidistantCylindrical) { auto conv = Conversion::createEquidistantCylindrical( PropertyMap(), Angle(1), Angle(2), Length(3), Length(4)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=eqc +lat_ts=1 +lat_0=0 +lon_0=2 +x_0=3 +y_0=4"); @@ -2050,6 +2091,7 @@ TEST(operation, createEquidistantCylindrical) { TEST(operation, createEquidistantCylindricalSpherical) { auto conv = Conversion::createEquidistantCylindricalSpherical( PropertyMap(), Angle(1), Angle(2), Length(3), Length(4)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=eqc +lat_ts=1 +lat_0=0 +lon_0=2 +x_0=3 +y_0=4"); @@ -2109,6 +2151,7 @@ TEST(operation, gall_export) { auto conv = Conversion::createGall(PropertyMap(), Angle(1), Length(2), Length(3)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=gall +lon_0=1 +x_0=2 +y_0=3"); @@ -2141,6 +2184,7 @@ TEST(operation, goode_homolosine_export) { auto conv = Conversion::createGoodeHomolosine(PropertyMap(), Angle(1), Length(2), Length(3)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=goode +lon_0=1 +x_0=2 +y_0=3"); @@ -2173,6 +2217,7 @@ TEST(operation, interrupted_goode_homolosine_export) { auto conv = Conversion::createInterruptedGoodeHomolosine( PropertyMap(), Angle(1), Length(2), Length(3)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=igh +lon_0=1 +x_0=2 +y_0=3"); @@ -2205,6 +2250,7 @@ TEST(operation, geostationary_satellite_sweep_x_export) { auto conv = Conversion::createGeostationarySatelliteSweepX( PropertyMap(), Angle(1), Length(2), Length(3), Length(4)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=geos +sweep=x +lon_0=1 +h=2 +x_0=3 +y_0=4"); @@ -2245,6 +2291,7 @@ TEST(operation, geostationary_satellite_sweep_y_export) { auto conv = Conversion::createGeostationarySatelliteSweepY( PropertyMap(), Angle(1), Length(2), Length(3), Length(4)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=geos +lon_0=1 +h=2 +x_0=3 +y_0=4"); @@ -2280,6 +2327,8 @@ TEST(operation, geostationary_satellite_sweep_y_export) { TEST(operation, gnomonic_export) { auto conv = Conversion::createGnomonic(PropertyMap(), Angle(1), Angle(2), Length(4), Length(5)); + EXPECT_TRUE(conv->validateParameters().empty()); + EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=gnom +lat_0=1 +lon_0=2 +x_0=4 +y_0=5"); @@ -2315,6 +2364,8 @@ TEST(operation, hotine_oblique_mercator_variant_A_export) { auto conv = Conversion::createHotineObliqueMercatorVariantA( PropertyMap(), Angle(1), Angle(2), Angle(3), Angle(4), Scale(5), Length(6), Length(7)); + EXPECT_TRUE(conv->validateParameters().empty()); + EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=omerc +no_uoff +lat_0=1 +lonc=2 +alpha=3 +gamma=4 +k=5 " "+x_0=6 +y_0=7"); @@ -2375,6 +2426,8 @@ TEST(operation, hotine_oblique_mercator_variant_B_export) { auto conv = Conversion::createHotineObliqueMercatorVariantB( PropertyMap(), Angle(1), Angle(2), Angle(3), Angle(4), Scale(5), Length(6), Length(7)); + EXPECT_TRUE(conv->validateParameters().empty()); + EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=omerc +lat_0=1 +lonc=2 +alpha=3 +gamma=4 +k=5 " "+x_0=6 +y_0=7"); @@ -2435,6 +2488,8 @@ TEST(operation, hotine_oblique_mercator_two_point_natural_origin_export) { auto conv = Conversion::createHotineObliqueMercatorTwoPointNaturalOrigin( PropertyMap(), Angle(1), Angle(2), Angle(3), Angle(4), Angle(5), Scale(6), Length(7), Length(8)); + EXPECT_TRUE(conv->validateParameters().empty()); + EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=omerc +lat_0=1 +lat_1=2 +lon_1=3 +lat_2=4 +lon_2=5 +k=6 " "+x_0=7 +y_0=8"); @@ -2486,6 +2541,8 @@ TEST(operation, laborde_oblique_mercator_export) { auto conv = Conversion::createLabordeObliqueMercator( PropertyMap(), Angle(1), Angle(2), Angle(3), Scale(4), Length(5), Length(6)); + EXPECT_TRUE(conv->validateParameters().empty()); + EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=labrd +lat_0=1 +lon_0=2 +azi=3 +k=4 +x_0=5 +y_0=6"); @@ -2531,6 +2588,7 @@ TEST(operation, laborde_oblique_mercator_export) { TEST(operation, imw_polyconic_export) { auto conv = Conversion::createInternationalMapWorldPolyconic( PropertyMap(), Angle(1), Angle(3), Angle(4), Length(5), Length(6)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=imw_p +lon_0=1 +lat_1=3 +lat_2=4 +x_0=5 +y_0=6"); @@ -2571,6 +2629,7 @@ TEST(operation, krovak_north_oriented_export) { auto conv = Conversion::createKrovakNorthOriented( PropertyMap(), Angle(49.5), Angle(42.5), Angle(30.28813972222222), Angle(78.5), Scale(0.9999), Length(5), Length(6)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=krovak +lat_0=49.5 +lon_0=42.5 +alpha=30.2881397222222 " @@ -2622,6 +2681,7 @@ TEST(operation, krovak_export) { auto conv = Conversion::createKrovak( PropertyMap(), Angle(49.5), Angle(42.5), Angle(30.28813972222222), Angle(78.5), Scale(0.9999), Length(5), Length(6)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=krovak +axis=swu +lat_0=49.5 +lon_0=42.5 " @@ -2673,6 +2733,7 @@ TEST(operation, krovak_export) { TEST(operation, lambert_azimuthal_equal_area_export) { auto conv = Conversion::createLambertAzimuthalEqualArea( PropertyMap(), Angle(1), Angle(2), Length(3), Length(4)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=laea +lat_0=1 +lon_0=2 +x_0=3 +y_0=4"); @@ -2709,6 +2770,7 @@ TEST(operation, lambert_azimuthal_equal_area_export) { TEST(operation, miller_cylindrical_export) { auto conv = Conversion::createMillerCylindrical(PropertyMap(), Angle(2), Length(3), Length(4)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=mill +R_A +lon_0=2 +x_0=3 +y_0=4"); @@ -2740,6 +2802,7 @@ TEST(operation, miller_cylindrical_export) { TEST(operation, mercator_variant_A_export) { auto conv = Conversion::createMercatorVariantA( PropertyMap(), Angle(0), Angle(1), Scale(2), Length(3), Length(4)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=merc +lon_0=1 +k=2 +x_0=3 +y_0=4"); @@ -2847,6 +2910,7 @@ TEST(operation, wkt1_import_mercator_variant_A_that_is_variant_B) { TEST(operation, mercator_variant_B_export) { auto conv = Conversion::createMercatorVariantB( PropertyMap(), Angle(1), Angle(2), Length(3), Length(4)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=merc +lat_ts=1 +lon_0=2 +x_0=3 +y_0=4"); @@ -2947,6 +3011,7 @@ TEST(operation, odd_mercator_2sp_with_latitude_of_origin) { TEST(operation, webmerc_export) { auto conv = Conversion::createPopularVisualisationPseudoMercator( PropertyMap(), Angle(0), Angle(2), Length(3), Length(4)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=webmerc +lat_0=0 +lon_0=2 +x_0=3 +y_0=4"); @@ -3275,6 +3340,7 @@ TEST(operation, mollweide_export) { auto conv = Conversion::createMollweide(PropertyMap(), Angle(1), Length(2), Length(3)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=moll +lon_0=1 +x_0=2 +y_0=3"); @@ -3305,6 +3371,7 @@ TEST(operation, mollweide_export) { TEST(operation, nzmg_export) { auto conv = Conversion::createNewZealandMappingGrid( PropertyMap(), Angle(1), Angle(2), Length(4), Length(5)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=nzmg +lat_0=1 +lon_0=2 +x_0=4 +y_0=5"); @@ -3341,6 +3408,7 @@ TEST(operation, nzmg_export) { TEST(operation, oblique_stereographic_export) { auto conv = Conversion::createObliqueStereographic( PropertyMap(), Angle(1), Angle(2), Scale(3), Length(4), Length(5)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=sterea +lat_0=1 +lon_0=2 +k=3 +x_0=4 +y_0=5"); @@ -3381,6 +3449,7 @@ TEST(operation, oblique_stereographic_export) { TEST(operation, orthographic_export) { auto conv = Conversion::createOrthographic(PropertyMap(), Angle(1), Angle(2), Length(4), Length(5)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=ortho +lat_0=1 +lon_0=2 +x_0=4 +y_0=5"); @@ -3417,6 +3486,7 @@ TEST(operation, orthographic_export) { TEST(operation, american_polyconic_export) { auto conv = Conversion::createAmericanPolyconic( PropertyMap(), Angle(1), Angle(2), Length(4), Length(5)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=poly +lat_0=1 +lon_0=2 +x_0=4 +y_0=5"); @@ -3453,6 +3523,7 @@ TEST(operation, american_polyconic_export) { TEST(operation, polar_stereographic_variant_A_export) { auto conv = Conversion::createPolarStereographicVariantA( PropertyMap(), Angle(90), Angle(2), Scale(3), Length(4), Length(5)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=stere +lat_0=90 +lon_0=2 +k=3 +x_0=4 +y_0=5"); @@ -3493,6 +3564,7 @@ TEST(operation, polar_stereographic_variant_A_export) { TEST(operation, polar_stereographic_variant_B_export_positive_lat) { auto conv = Conversion::createPolarStereographicVariantB( PropertyMap(), Angle(70), Angle(2), Length(4), Length(5)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=stere +lat_0=90 +lat_ts=70 +lon_0=2 +x_0=4 +y_0=5"); @@ -3658,6 +3730,7 @@ TEST(operation, robinson_export) { auto conv = Conversion::createRobinson(PropertyMap(), Angle(1), Length(2), Length(3)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=robin +lon_0=1 +x_0=2 +y_0=3"); @@ -3690,6 +3763,7 @@ TEST(operation, sinusoidal_export) { auto conv = Conversion::createSinusoidal(PropertyMap(), Angle(1), Length(2), Length(3)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=sinu +lon_0=1 +x_0=2 +y_0=3"); @@ -3721,6 +3795,7 @@ TEST(operation, sinusoidal_export) { TEST(operation, stereographic_export) { auto conv = Conversion::createStereographic( PropertyMap(), Angle(1), Angle(2), Scale(3), Length(4), Length(5)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=stere +lat_0=1 +lon_0=2 +k=3 +x_0=4 +y_0=5"); @@ -3761,6 +3836,7 @@ TEST(operation, vandergrinten_export) { auto conv = Conversion::createVanDerGrinten(PropertyMap(), Angle(1), Length(2), Length(3)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=vandg +R_A +lon_0=1 +x_0=2 +y_0=3"); @@ -3821,6 +3897,7 @@ TEST(operation, wagner_export) { Conversion::createWagnerVII( PropertyMap(), Angle(1), Length(2), Length(3)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=wag" + numbers[i] + " +lon_0=1 +x_0=2 +y_0=3"); @@ -3897,6 +3974,7 @@ TEST(operation, qsc_export) { auto conv = Conversion::createQuadrilateralizedSphericalCube( PropertyMap(), Angle(1), Angle(2), Length(3), Length(4)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=qsc +lat_0=1 +lon_0=2 +x_0=3 +y_0=4"); @@ -3933,6 +4011,7 @@ TEST(operation, sch_export) { auto conv = Conversion::createSphericalCrossTrackHeight( PropertyMap(), Angle(1), Angle(2), Angle(3), Length(4)); + EXPECT_TRUE(conv->validateParameters().empty()); EXPECT_EQ(conv->exportToPROJString(PROJStringFormatter::create().get()), "+proj=sch +plat_0=1 +plon_0=2 +phdg_0=3 +h_0=4"); @@ -5576,6 +5655,7 @@ TEST(operation, transformation_longitude_rotation_to_PROJ_string) { EllipsoidalCS::createLatitudeLongitude(UnitOfMeasure::DEGREE)); auto transformation = Transformation::createLongitudeRotation( PropertyMap(), src, dest, Angle(10)); + EXPECT_TRUE(transformation->validateParameters().empty()); EXPECT_EQ( transformation->exportToPROJString(PROJStringFormatter::create().get()), "+proj=pipeline +step +proj=axisswap +order=2,1 +step " @@ -5597,6 +5677,8 @@ TEST(operation, transformation_Geographic2D_offsets_to_PROJ_string) { auto transformation = Transformation::createGeographic2DOffsets( PropertyMap(), GeographicCRS::EPSG_4326, GeographicCRS::EPSG_4326, Angle(0.5), Angle(-1), {}); + EXPECT_TRUE(transformation->validateParameters().empty()); + EXPECT_EQ( transformation->exportToPROJString(PROJStringFormatter::create().get()), "+proj=pipeline +step +proj=axisswap +order=2,1 +step " @@ -5618,6 +5700,8 @@ TEST(operation, transformation_Geographic3D_offsets_to_PROJ_string) { auto transformation = Transformation::createGeographic3DOffsets( PropertyMap(), GeographicCRS::EPSG_4326, GeographicCRS::EPSG_4326, Angle(0.5), Angle(-1), Length(2), {}); + EXPECT_TRUE(transformation->validateParameters().empty()); + EXPECT_EQ( transformation->exportToPROJString(PROJStringFormatter::create().get()), "+proj=pipeline +step +proj=axisswap +order=2,1 +step " @@ -5642,6 +5726,8 @@ TEST(operation, CompoundCRS::create(PropertyMap(), {GeographicCRS::EPSG_4326, createVerticalCRS()}), GeographicCRS::EPSG_4326, Angle(0.5), Angle(-1), Length(2), {}); + EXPECT_TRUE(transformation->validateParameters().empty()); + EXPECT_EQ( transformation->exportToPROJString(PROJStringFormatter::create().get()), "+proj=pipeline +step +proj=axisswap +order=2,1 +step " @@ -5662,6 +5748,8 @@ TEST(operation, transformation_vertical_offset_to_PROJ_string) { auto transformation = Transformation::createVerticalOffset( PropertyMap(), createVerticalCRS(), createVerticalCRS(), Length(1), {}); + EXPECT_TRUE(transformation->validateParameters().empty()); + EXPECT_EQ( transformation->exportToPROJString(PROJStringFormatter::create().get()), "+proj=geogoffset +dh=1"); @@ -6966,3 +7054,123 @@ TEST(operation, EXPECT_TRUE( conv1->isEquivalentTo(conv2.get(), IComparable::Criterion::EQUIVALENT)); } + +// --------------------------------------------------------------------------- + +TEST(operation, createChangeVerticalUnit) { + auto conv = Conversion::createChangeVerticalUnit(PropertyMap(), Scale(1)); + EXPECT_TRUE(conv->validateParameters().empty()); +} + +// --------------------------------------------------------------------------- + +TEST(operation, createGeographicGeocentric) { + auto conv = Conversion::createGeographicGeocentric(PropertyMap()); + EXPECT_TRUE(conv->validateParameters().empty()); +} + +// --------------------------------------------------------------------------- + +TEST(operation, validateParameters) { + { + auto conv = Conversion::create( + PropertyMap(), + PropertyMap().set(IdentifiedObject::NAME_KEY, "unknown"), {}, {}); + auto validation = conv->validateParameters(); + EXPECT_EQ(validation, std::list<std::string>{"Unknown method unknown"}); + } + + { + auto conv = Conversion::create( + PropertyMap(), PropertyMap().set(IdentifiedObject::NAME_KEY, + "change of vertical unit"), + {}, {}); + auto validation = conv->validateParameters(); + auto expected = std::list<std::string>{ + "Method name change of vertical unit is equivalent to official " + "Change of Vertical Unit but not strictly equal", + "Cannot find expected parameter Unit conversion scalar"}; + EXPECT_EQ(validation, expected); + } + + { + auto conv = Conversion::create( + PropertyMap(), PropertyMap() + .set(IdentifiedObject::NAME_KEY, + EPSG_NAME_METHOD_CHANGE_VERTICAL_UNIT) + .set(Identifier::CODESPACE_KEY, Identifier::EPSG) + .set(Identifier::CODE_KEY, "1234"), + {}, {}); + auto validation = conv->validateParameters(); + auto expected = std::list<std::string>{ + "Method of EPSG code 1234 does not match official code (1069)", + "Cannot find expected parameter Unit conversion scalar"}; + EXPECT_EQ(validation, expected); + } + + { + auto conv = Conversion::create( + PropertyMap(), + PropertyMap() + .set(IdentifiedObject::NAME_KEY, "some fancy name") + .set(Identifier::CODESPACE_KEY, Identifier::EPSG) + .set(Identifier::CODE_KEY, + EPSG_CODE_METHOD_CHANGE_VERTICAL_UNIT), + {}, {}); + auto validation = conv->validateParameters(); + auto expected = std::list<std::string>{ + "Method name some fancy name, matched to Change of Vertical Unit, " + "through its EPSG code has not an equivalent name", + "Cannot find expected parameter Unit conversion scalar"}; + EXPECT_EQ(validation, expected); + } + + { + auto conv = Conversion::create( + PropertyMap(), + PropertyMap().set(IdentifiedObject::NAME_KEY, + EPSG_NAME_METHOD_CHANGE_VERTICAL_UNIT), + {OperationParameter::create(PropertyMap().set( + IdentifiedObject::NAME_KEY, "unit conversion scalar"))}, + {ParameterValue::create(Measure(1.0, UnitOfMeasure::SCALE_UNITY))}); + auto validation = conv->validateParameters(); + auto expected = std::list<std::string>{ + "Parameter name unit conversion scalar is equivalent to official " + "Unit conversion scalar but not strictly equal"}; + EXPECT_EQ(validation, expected); + } + + { + auto conv = Conversion::create( + PropertyMap(), + PropertyMap().set(IdentifiedObject::NAME_KEY, + EPSG_NAME_METHOD_CHANGE_VERTICAL_UNIT), + {OperationParameter::create( + PropertyMap() + .set(IdentifiedObject::NAME_KEY, "fancy name") + .set(Identifier::CODESPACE_KEY, Identifier::EPSG) + .set(Identifier::CODE_KEY, + EPSG_CODE_PARAMETER_UNIT_CONVERSION_SCALAR))}, + {ParameterValue::create(Measure(1.0, UnitOfMeasure::SCALE_UNITY))}); + auto validation = conv->validateParameters(); + auto expected = std::list<std::string>{ + "Parameter name fancy name, matched to Unit conversion scalar, " + "through its EPSG code has not an equivalent name"}; + EXPECT_EQ(validation, expected); + } + + { + auto conv = Conversion::create( + PropertyMap(), + PropertyMap().set(IdentifiedObject::NAME_KEY, + EPSG_NAME_METHOD_CHANGE_VERTICAL_UNIT), + {OperationParameter::create( + PropertyMap().set(IdentifiedObject::NAME_KEY, "extra param"))}, + {ParameterValue::create(Measure(1.0, UnitOfMeasure::SCALE_UNITY))}); + auto validation = conv->validateParameters(); + auto expected = std::list<std::string>{ + "Cannot find expected parameter Unit conversion scalar", + "Parameter extra param found but not expected for this method"}; + EXPECT_EQ(validation, expected); + } +} |
