diff options
Diffstat (limited to 'src')
| -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 |
5 files changed, 161 insertions, 25 deletions
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()); |
