diff options
Diffstat (limited to 'src/iso19111/operation/conversion.cpp')
| -rw-r--r-- | src/iso19111/operation/conversion.cpp | 116 |
1 files changed, 112 insertions, 4 deletions
diff --git a/src/iso19111/operation/conversion.cpp b/src/iso19111/operation/conversion.cpp index 3d09c9fa..f7bb8ec8 100644 --- a/src/iso19111/operation/conversion.cpp +++ b/src/iso19111/operation/conversion.cpp @@ -79,6 +79,7 @@ constexpr double UTM_SCALE_FACTOR = 0.9996; constexpr double UTM_FALSE_EASTING = 500000.0; constexpr double UTM_NORTH_FALSE_NORTHING = 0.0; constexpr double UTM_SOUTH_FALSE_NORTHING = 10000000.0; + //! @endcond // --------------------------------------------------------------------------- @@ -264,7 +265,8 @@ createConversion(const util::PropertyMap &properties, const std::vector<ParameterValueNNPtr> &values) { std::vector<OperationParameterNNPtr> parameters; - for (int i = 0; mapping->params[i] != nullptr; i++) { + for (int i = 0; mapping->params != nullptr && mapping->params[i] != nullptr; + i++) { const auto *param = mapping->params[i]; auto paramProperties = util::PropertyMap().set( common::IdentifiedObject::NAME_KEY, param->wkt2_name); @@ -2402,6 +2404,28 @@ Conversion::createGeographicGeocentric(const crs::CRSNNPtr &sourceCRS, // --------------------------------------------------------------------------- +/** \brief Instantiate a conversion between a GeographicCRS and a spherical + * planetocentric GeodeticCRS + * + * This method peforms conversion between geodetic latitude and geocentric + * latitude + * + * @return a new Conversion. + */ +ConversionNNPtr +Conversion::createGeographicGeocentricLatitude(const crs::CRSNNPtr &sourceCRS, + const crs::CRSNNPtr &targetCRS) { + auto properties = util::PropertyMap().set( + common::IdentifiedObject::NAME_KEY, + buildOpName("Conversion", sourceCRS, targetCRS)); + auto conv = create( + properties, PROJ_WKT2_NAME_METHOD_GEOGRAPHIC_GEOCENTRIC_LATITUDE, {}); + conv->setCRSs(sourceCRS, targetCRS, nullptr); + return conv; +} + +// --------------------------------------------------------------------------- + InverseConversion::InverseConversion(const ConversionNNPtr &forward) : Conversion( OperationMethod::create(createPropertiesForInverse(forward->method()), @@ -2508,6 +2532,15 @@ CoordinateOperationNNPtr Conversion::inverse() const { return conv; } + if (method()->nameStr() == + PROJ_WKT2_NAME_METHOD_GEOGRAPHIC_GEOCENTRIC_LATITUDE) { + auto conv = + create(createPropertiesForInverse(this, false, false), + PROJ_WKT2_NAME_METHOD_GEOGRAPHIC_GEOCENTRIC_LATITUDE, {}); + conv->setCRSs(this, true); + return conv; + } + return InverseConversion::create(NN_NO_CHECK( util::nn_dynamic_pointer_cast<Conversion>(shared_from_this()))); } @@ -3446,6 +3479,77 @@ void Conversion::_exportToPROJString( auto l_sourceCRS = sourceCRS(); auto l_targetCRS = targetCRS(); + if (methodName == PROJ_WKT2_NAME_METHOD_GEOGRAPHIC_GEOCENTRIC_LATITUDE) { + + const auto extractGeodeticCRSIfGeodeticCRSOrEquivalent = + [](const crs::CRSPtr &crs) { + auto geodCRS = std::dynamic_pointer_cast<crs::GeodeticCRS>(crs); + if (!geodCRS) { + auto compoundCRS = + std::dynamic_pointer_cast<crs::CompoundCRS>(crs); + if (compoundCRS) { + const auto &components = + compoundCRS->componentReferenceSystems(); + if (!components.empty()) { + geodCRS = + util::nn_dynamic_pointer_cast<crs::GeodeticCRS>( + components[0]); + if (!geodCRS) { + auto boundCRS = util::nn_dynamic_pointer_cast< + crs::BoundCRS>(components[0]); + if (boundCRS) { + geodCRS = util::nn_dynamic_pointer_cast< + crs::GeodeticCRS>(boundCRS->baseCRS()); + } + } + } + } else { + auto boundCRS = + std::dynamic_pointer_cast<crs::BoundCRS>(crs); + if (boundCRS) { + geodCRS = + util::nn_dynamic_pointer_cast<crs::GeodeticCRS>( + boundCRS->baseCRS()); + } + } + } + return geodCRS; + }; + + auto sourceCRSGeod = dynamic_cast<const crs::GeodeticCRS *>( + extractGeodeticCRSIfGeodeticCRSOrEquivalent(l_sourceCRS).get()); + auto targetCRSGeod = dynamic_cast<const crs::GeodeticCRS *>( + extractGeodeticCRSIfGeodeticCRSOrEquivalent(l_targetCRS).get()); + if (sourceCRSGeod && targetCRSGeod) { + auto sourceCRSGeog = + dynamic_cast<const crs::GeographicCRS *>(sourceCRSGeod); + auto targetCRSGeog = + dynamic_cast<const crs::GeographicCRS *>(targetCRSGeod); + bool isSrcGeocentricLat = + sourceCRSGeod->isSphericalPlanetocentric(); + bool isSrcGeographic = sourceCRSGeog != nullptr; + bool isTargetGeocentricLat = + targetCRSGeod->isSphericalPlanetocentric(); + bool isTargetGeographic = targetCRSGeog != nullptr; + if ((isSrcGeocentricLat && isTargetGeographic) || + (isSrcGeographic && isTargetGeocentricLat)) { + + formatter->startInversion(); + sourceCRSGeod->_exportToPROJString(formatter); + formatter->stopInversion(); + + targetCRSGeod->_exportToPROJString(formatter); + + return; + } + } + + throw io::FormattingException("Invalid nature of source and/or " + "targetCRS for Geographic latitude / " + "Geocentric latitude" + "conversion"); + } + crs::GeographicCRSPtr srcGeogCRS; if (!formatter->getCRSExport() && l_sourceCRS && applySourceCRSModifiers) { @@ -3459,11 +3563,15 @@ void Conversion::_exportToPROJString( } } - srcGeogCRS = std::dynamic_pointer_cast<crs::GeographicCRS>(horiz); - if (srcGeogCRS) { + auto srcGeodCRS = dynamic_cast<const crs::GeodeticCRS *>(horiz.get()); + if (srcGeodCRS) { + srcGeogCRS = std::dynamic_pointer_cast<crs::GeographicCRS>(horiz); + } + if (srcGeodCRS && + (srcGeogCRS || srcGeodCRS->isSphericalPlanetocentric())) { formatter->setOmitProjLongLatIfPossible(true); formatter->startInversion(); - srcGeogCRS->_exportToPROJString(formatter); + srcGeodCRS->_exportToPROJString(formatter); formatter->stopInversion(); formatter->setOmitProjLongLatIfPossible(false); } |
