From a96e8f5f4e2a2145656c533271d1461ea077a35d Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Sat, 6 Jun 2020 20:35:00 +0200 Subject: createOperations(): changes so that EPSG:9635 'Geog3D to Geog2D+GravityRelatedHeight (US .gtx)' method used by Slovakian geoids correctly deal with axis order and unit conversion, to be used as 'standalone'. Also improves when using directly 'Geographic3D to GravityRelatedHeight' method --- src/iso19111/coordinateoperation.cpp | 54 ++++++++++++++++++++++++++++++++++++ src/iso19111/io.cpp | 20 +++++++++++++ 2 files changed, 74 insertions(+) (limited to 'src') diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp index bdb2ad2e..c64dab5f 100644 --- a/src/iso19111/coordinateoperation.cpp +++ b/src/iso19111/coordinateoperation.cpp @@ -8662,6 +8662,7 @@ isGeographic3DToGravityRelatedHeight(const OperationMethodNNPtr &method, "9663", // Geographic3D to GravityRelatedHeight (OSGM-GB) "9664", // Geographic3D to GravityRelatedHeight (IGN1997) "9665", // Geographic3D to GravityRelatedHeight (US .gtx) + "9635", // Geog3D to Geog2D+GravityRelatedHeight (US .gtx) }; if (ci_find(methodName, "Geographic3D to GravityRelatedHeight") == 0) { @@ -9697,6 +9698,21 @@ void Transformation::_exportToPROJString( const auto &heightFilename = _getHeightToGeographic3DFilename(this, true); if (!heightFilename.empty()) { + auto targetCRSGeog = + extractGeographicCRSIfGeographicCRSOrEquivalent(targetCRS()); + if (!targetCRSGeog) { + throw io::FormattingException( + concat("Can apply ", methodName, " only to GeographicCRS")); + } + + if (!formatter->omitHorizontalConversionInVertTransformation()) { + formatter->startInversion(); + formatter->pushOmitZUnitConversion(); + targetCRSGeog->addAngularUnitConvertAndAxisSwap(formatter); + formatter->popOmitZUnitConversion(); + formatter->stopInversion(); + } + if (isMethodInverseOf) { formatter->startInversion(); } @@ -9706,6 +9722,13 @@ void Transformation::_exportToPROJString( if (isMethodInverseOf) { formatter->stopInversion(); } + + if (!formatter->omitHorizontalConversionInVertTransformation()) { + formatter->pushOmitZUnitConversion(); + targetCRSGeog->addAngularUnitConvertAndAxisSwap(formatter); + formatter->popOmitZUnitConversion(); + } + return; } @@ -9716,6 +9739,22 @@ void Transformation::_exportToPROJString( if (fileParameter && fileParameter->type() == ParameterValue::Type::FILENAME) { auto filename = fileParameter->valueFile(); + + auto sourceCRSGeog = + extractGeographicCRSIfGeographicCRSOrEquivalent(sourceCRS()); + if (!sourceCRSGeog) { + throw io::FormattingException( + concat("Can apply ", methodName, " only to GeographicCRS")); + } + + if (!formatter->omitHorizontalConversionInVertTransformation()) { + formatter->startInversion(); + formatter->pushOmitZUnitConversion(); + sourceCRSGeog->addAngularUnitConvertAndAxisSwap(formatter); + formatter->popOmitZUnitConversion(); + formatter->stopInversion(); + } + bool doInversion = isMethodInverseOf; // The EPSG Geog3DToHeight is the reverse convention of PROJ ! doInversion = !doInversion; @@ -9728,6 +9767,13 @@ void Transformation::_exportToPROJString( if (doInversion) { formatter->stopInversion(); } + + if (!formatter->omitHorizontalConversionInVertTransformation()) { + formatter->pushOmitZUnitConversion(); + sourceCRSGeog->addAngularUnitConvertAndAxisSwap(formatter); + formatter->popOmitZUnitConversion(); + } + return; } } @@ -12286,6 +12332,8 @@ createBallparkGeographicOffset(const crs::CRSNNPtr &sourceCRS, //! @cond Doxygen_Suppress +// --------------------------------------------------------------------------- + struct MyPROJStringExportableGeodToGeod final : public io::IPROJStringExportable { crs::GeodeticCRSPtr geodSrc{}; @@ -12332,14 +12380,18 @@ struct MyPROJStringExportableHorizVertical final _exportToPROJString(io::PROJStringFormatter *formatter) const override { formatter->pushOmitZUnitConversion(); + horizTransform->_exportToPROJString(formatter); formatter->startInversion(); geogDst->addAngularUnitConvertAndAxisSwap(formatter); formatter->stopInversion(); + formatter->popOmitZUnitConversion(); + formatter->pushOmitHorizontalConversionInVertTransformation(); verticalTransform->_exportToPROJString(formatter); + formatter->popOmitHorizontalConversionInVertTransformation(); formatter->pushOmitZUnitConversion(); geogDst->addAngularUnitConvertAndAxisSwap(formatter); @@ -12385,7 +12437,9 @@ struct MyPROJStringExportableHorizVerticalHorizPROJBased final formatter->popOmitZUnitConversion(); + formatter->pushOmitHorizontalConversionInVertTransformation(); verticalTransform->_exportToPROJString(formatter); + formatter->popOmitHorizontalConversionInVertTransformation(); formatter->pushOmitZUnitConversion(); diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index e7f8769c..38b407ee 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -6635,6 +6635,7 @@ struct PROJStringFormatter::Private { std::vector inversionStack_{InversionStackElt()}; bool omitProjLongLatIfPossible_ = false; std::vector omitZUnitConversion_{false}; + std::vector omitHorizontalConversionInVertTransformation_{false}; DatabaseContextPtr dbContext_{}; bool useApproxTMerc_ = false; bool addNoDefs_ = true; @@ -7739,6 +7740,25 @@ bool PROJStringFormatter::omitZUnitConversion() const { // --------------------------------------------------------------------------- +void PROJStringFormatter::pushOmitHorizontalConversionInVertTransformation() { + d->omitHorizontalConversionInVertTransformation_.push_back(true); +} + +// --------------------------------------------------------------------------- + +void PROJStringFormatter::popOmitHorizontalConversionInVertTransformation() { + assert(d->omitHorizontalConversionInVertTransformation_.size() > 1); + d->omitHorizontalConversionInVertTransformation_.pop_back(); +} + +// --------------------------------------------------------------------------- + +bool PROJStringFormatter::omitHorizontalConversionInVertTransformation() const { + return d->omitHorizontalConversionInVertTransformation_.back(); +} + +// --------------------------------------------------------------------------- + void PROJStringFormatter::setLegacyCRSToCRSContext(bool legacyContext) { d->legacyCRSToCRSContext_ = legacyContext; } -- cgit v1.2.3 From c6ff686bf8334efce9995dacc899022d3a5b813b Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Sat, 6 Jun 2020 21:09:21 +0200 Subject: createOperations(): improve name of inverse transformation when there are registered transformations between compoundCRS and something else --- src/iso19111/coordinateoperation.cpp | 37 ++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp index c64dab5f..ecc3df06 100644 --- a/src/iso19111/coordinateoperation.cpp +++ b/src/iso19111/coordinateoperation.cpp @@ -7822,9 +7822,34 @@ createPropertiesForInverse(const CoordinateOperation *op, bool derivedFrom, auto targetCRS = op->targetCRS(); std::string name; if (!forwardName.empty()) { - if (starts_with(forwardName, INVERSE_OF) || - forwardName.find(" + ") != std::string::npos) { - auto tokens = split(forwardName, " + "); + if (dynamic_cast(op) == nullptr && + dynamic_cast(op) == nullptr && + (starts_with(forwardName, INVERSE_OF) || + forwardName.find(" + ") != std::string::npos)) { + std::vector tokens; + std::string curToken; + bool inString = false; + for (size_t i = 0; i < forwardName.size(); ++i) { + if (inString) { + curToken += forwardName[i]; + if (forwardName[i] == '\'') { + inString = false; + } + } else if (i + 3 < forwardName.size() && + memcmp(&forwardName[i], " + ", 3) == 0) { + tokens.push_back(curToken); + curToken.clear(); + i += 2; + } else if (forwardName[i] == '\'') { + inString = true; + curToken += forwardName[i]; + } else { + curToken += forwardName[i]; + } + } + if (!curToken.empty()) { + tokens.push_back(curToken); + } for (size_t i = tokens.size(); i > 0;) { i--; if (!name.empty()) { @@ -7841,7 +7866,11 @@ createPropertiesForInverse(const CoordinateOperation *op, bool derivedFrom, } } else if (!sourceCRS || !targetCRS || forwardName != buildOpName(opType, sourceCRS, targetCRS)) { - name = INVERSE_OF + forwardName; + if (forwardName.find(" + ") != std::string::npos) { + name = INVERSE_OF + '\'' + forwardName + '\''; + } else { + name = INVERSE_OF + forwardName; + } } } if (name.empty() && sourceCRS && targetCRS) { -- cgit v1.2.3