aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/proj/coordinateoperation.hpp2
-rw-r--r--include/proj/datum.hpp2
-rw-r--r--include/proj/internal/coordinateoperation_constants.hpp353
-rw-r--r--src/c_api.cpp5
-rw-r--r--src/coordinateoperation.cpp157
-rw-r--r--src/datum.cpp8
-rw-r--r--src/io.cpp11
-rw-r--r--src/static.cpp5
-rw-r--r--test/unit/test_crs.cpp1
-rw-r--r--test/unit/test_factory.cpp5
-rw-r--r--test/unit/test_operation.cpp208
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[] = {
&paramFalseNorthing,
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[] = {
+ &paramUnitConversionScalar, 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[] = {
+ &paramLongitudeOffset, 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[] = {
+ &paramA0, &paramA1, &paramA2, &paramB0, &paramB1, &paramB2, 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[] = {
+ &paramXTranslation, &paramYTranslation, &paramZTranslation, nullptr};
+
+static const ParamMapping *const paramsHelmert7[] = {
+ &paramXTranslation, &paramYTranslation,
+ &paramZTranslation, &paramXRotation,
+ &paramYRotation, &paramZRotation,
+ &paramScaleDifference, 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[] = {
+ &paramXTranslation, &paramYTranslation,
+ &paramZTranslation, &paramXRotation,
+ &paramYRotation, &paramZRotation,
+ &paramScaleDifference, &paramRateXTranslation,
+ &paramRateYTranslation, &paramRateZTranslation,
+ &paramRateXRotation, &paramRateYRotation,
+ &paramRateZRotation, &paramRateScaleDifference,
+ &paramReferenceEpoch, 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[] = {
+ &paramXTranslation,
+ &paramYTranslation,
+ &paramZTranslation,
+ &paramXRotation,
+ &paramYRotation,
+ &paramZRotation,
+ &paramScaleDifference,
+ &paramOrdinate1EvalPoint,
+ &paramOrdinate2EvalPoint,
+ &paramOrdinate3EvalPoint,
+ 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[] = {
+ &paramXTranslation, &paramYTranslation,
+ &paramZTranslation, &paramSemiMajorAxisDifference,
+ &paramFlatteningDifference, 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[] = {
+ &paramLatitudeOffset, &paramLongitudeOffset, 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[] = {
+ &paramLatitudeOffset, &paramLongitudeOffset, &paramGeoidUndulation,
+ 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[] = {
+ &paramLatitudeOffset, &paramLongitudeOffset, &paramVerticalOffset, nullptr};
+
+static const ParamMapping *const paramsVerticalOffsets[] = {
+ &paramVerticalOffset, 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[] = {
+ &paramLatitudeLongitudeDifferenceFile, 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[] = {
+ &paramLatitudeDifferenceFile, &paramLongitudeDifferenceFile, 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[] = {&paramVerticalOffsetFile,
+ 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 &param) {
+ 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 &parameter = 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 &parameter = 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 &parameter = 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));
diff --git a/src/io.cpp b/src/io.cpp
index fb00bcd1..65921019 100644
--- a/src/io.cpp
+++ b/src/io.cpp
@@ -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);
+ }
+}