diff options
| author | Even Rouault <even.rouault@spatialys.com> | 2019-05-07 11:39:48 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-05-07 11:39:48 +0200 |
| commit | 850050693a25843d6ae69492cfad72f7753e39f7 (patch) | |
| tree | 4d464df04190ae115e7f54259457286d22580eb9 /src | |
| parent | 4636df33ed4d2a9bedf19973d58a42858fb816c0 (diff) | |
| parent | d4ffaca08a4f2ef3475165c2634561ee9bf01885 (diff) | |
| download | PROJ-850050693a25843d6ae69492cfad72f7753e39f7.tar.gz PROJ-850050693a25843d6ae69492cfad72f7753e39f7.zip | |
Merge pull request #1454 from rouault/fix_ETRS89_3D_to_proj_string_with_geoidgrids_nadgrids
createOperations(): fix case of ETRS89 3D to proj string with nadgrids and geoidgrids
Diffstat (limited to 'src')
| -rw-r--r-- | src/iso19111/coordinateoperation.cpp | 142 | ||||
| -rw-r--r-- | src/iso19111/internal.cpp | 15 | ||||
| -rw-r--r-- | src/iso19111/io.cpp | 20 |
3 files changed, 148 insertions, 29 deletions
diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp index 605004b6..348a776a 100644 --- a/src/iso19111/coordinateoperation.cpp +++ b/src/iso19111/coordinateoperation.cpp @@ -6958,11 +6958,11 @@ TransformationNNPtr Transformation::createNTv2( static TransformationNNPtr _createGravityRelatedHeightToGeographic3D( const util::PropertyMap &properties, bool inverse, const crs::CRSNNPtr &sourceCRSIn, const crs::CRSNNPtr &targetCRSIn, - const std::string &filename, + const crs::CRSPtr &interpolationCRSIn, const std::string &filename, const std::vector<metadata::PositionalAccuracyNNPtr> &accuracies) { return Transformation::create( - properties, sourceCRSIn, targetCRSIn, nullptr, + properties, sourceCRSIn, targetCRSIn, interpolationCRSIn, util::PropertyMap().set( common::IdentifiedObject::NAME_KEY, inverse ? INVERSE_OF + PROJ_WKT2_NAME_METHOD_HEIGHT_TO_GEOG3D @@ -6981,17 +6981,20 @@ static TransformationNNPtr _createGravityRelatedHeightToGeographic3D( * At minimum the name should be defined. * @param sourceCRSIn Source CRS. * @param targetCRSIn Target CRS. + * @param interpolationCRSIn Interpolation CRS. (might be null) * @param filename GRID filename. * @param accuracies Vector of positional accuracy (might be empty). * @return new Transformation. */ TransformationNNPtr Transformation::createGravityRelatedHeightToGeographic3D( const util::PropertyMap &properties, const crs::CRSNNPtr &sourceCRSIn, - const crs::CRSNNPtr &targetCRSIn, const std::string &filename, + const crs::CRSNNPtr &targetCRSIn, const crs::CRSPtr &interpolationCRSIn, + const std::string &filename, const std::vector<metadata::PositionalAccuracyNNPtr> &accuracies) { return _createGravityRelatedHeightToGeographic3D( - properties, false, sourceCRSIn, targetCRSIn, filename, accuracies); + properties, false, sourceCRSIn, targetCRSIn, interpolationCRSIn, + filename, accuracies); } // --------------------------------------------------------------------------- @@ -7302,8 +7305,20 @@ createPropertiesForInverse(const CoordinateOperation *op, bool derivedFrom, auto targetCRS = op->targetCRS(); std::string name; if (!forwardName.empty()) { - if (starts_with(forwardName, INVERSE_OF)) { - name = forwardName.substr(INVERSE_OF.size()); + if (starts_with(forwardName, INVERSE_OF) || + forwardName.find(" + ") != std::string::npos) { + auto tokens = split(forwardName, " + "); + for (size_t i = tokens.size(); i > 0;) { + i--; + if (!name.empty()) { + name += " + "; + } + if (starts_with(tokens[i], INVERSE_OF)) { + name += tokens[i].substr(INVERSE_OF.size()); + } else { + name += INVERSE_OF + tokens[i]; + } + } } else if (!sourceCRS || !targetCRS || forwardName != buildOpName(opType, sourceCRS, targetCRS)) { name = INVERSE_OF + forwardName; @@ -8195,13 +8210,14 @@ TransformationNNPtr Transformation::substitutePROJAlternativeGridNames( return createGravityRelatedHeightToGeographic3D( createPropertiesForInverse(self.as_nullable().get(), true, false), - targetCRS(), sourceCRS(), projFilename, - coordinateOperationAccuracies()) + targetCRS(), sourceCRS(), interpolationCRS(), + projFilename, coordinateOperationAccuracies()) ->inverseAsTransformation(); } else { return createGravityRelatedHeightToGeographic3D( createSimilarPropertiesTransformation(self), sourceCRS(), - targetCRS(), projFilename, coordinateOperationAccuracies()); + targetCRS(), interpolationCRS(), projFilename, + coordinateOperationAccuracies()); } } } @@ -10972,19 +10988,19 @@ struct MyPROJStringExportableHorizVertical final // cppcheck-suppress functionStatic _exportToPROJString(io::PROJStringFormatter *formatter) const override { - formatter->setOmitZUnitConversion(true); + formatter->pushOmitZUnitConversion(); horizTransform->_exportToPROJString(formatter); formatter->startInversion(); geogDst->addAngularUnitConvertAndAxisSwap(formatter); formatter->stopInversion(); - formatter->setOmitZUnitConversion(false); + formatter->popOmitZUnitConversion(); verticalTransform->_exportToPROJString(formatter); - formatter->setOmitZUnitConversion(true); + formatter->pushOmitZUnitConversion(); geogDst->addAngularUnitConvertAndAxisSwap(formatter); - formatter->setOmitZUnitConversion(false); + formatter->popOmitZUnitConversion(); } }; @@ -11016,7 +11032,7 @@ struct MyPROJStringExportableHorizVerticalHorizPROJBased final // cppcheck-suppress functionStatic _exportToPROJString(io::PROJStringFormatter *formatter) const override { - formatter->setOmitZUnitConversion(true); + formatter->pushOmitZUnitConversion(); opSrcCRSToGeogCRS->_exportToPROJString(formatter); @@ -11024,17 +11040,17 @@ struct MyPROJStringExportableHorizVerticalHorizPROJBased final interpolationGeogCRS->addAngularUnitConvertAndAxisSwap(formatter); formatter->stopInversion(); - formatter->setOmitZUnitConversion(false); + formatter->popOmitZUnitConversion(); verticalTransform->_exportToPROJString(formatter); - formatter->setOmitZUnitConversion(true); + formatter->pushOmitZUnitConversion(); interpolationGeogCRS->addAngularUnitConvertAndAxisSwap(formatter); opGeogCRStoDstCRS->_exportToPROJString(formatter); - formatter->setOmitZUnitConversion(false); + formatter->popOmitZUnitConversion(); } }; @@ -12135,6 +12151,37 @@ CoordinateOperationFactory::Private::createOperations( } } + auto vertCRSOfBaseOfBoundSrc = + dynamic_cast<const crs::VerticalCRS *>(boundSrc->baseCRS().get()); + if (vertCRSOfBaseOfBoundSrc && hubSrcGeog && + hubSrcGeog->coordinateSystem()->axisList().size() == 3 && + geogDst->coordinateSystem()->axisList().size() == 3) { + auto opsFirst = createOperations(sourceCRS, hubSrc, context); + auto opsSecond = createOperations(hubSrc, targetCRS, context); + if (!opsFirst.empty() && !opsSecond.empty()) { + for (const auto &opFirst : opsFirst) { + for (const auto &opLast : opsSecond) { + // Exclude artificial transformations from the hub + // to the target CRS + if (!opLast->hasBallparkTransformation()) { + try { + res.emplace_back( + ConcatenatedOperation:: + createComputeMetadata( + {opFirst, opLast}, + !allowEmptyIntersection)); + } catch ( + const InvalidOperationEmptyIntersection &) { + } + } + } + } + if (!res.empty()) { + return res; + } + } + } + return createOperations(boundSrc->baseCRS(), targetCRS, context); } @@ -12349,7 +12396,8 @@ CoordinateOperationFactory::Private::createOperations( const auto &componentsSrc = compoundSrc->componentReferenceSystems(); if (!componentsSrc.empty()) { std::vector<CoordinateOperationNNPtr> horizTransforms; - if (componentsSrc[0]->extractGeographicCRS()) { + auto srcGeogCRS = componentsSrc[0]->extractGeographicCRS(); + if (srcGeogCRS) { horizTransforms = createOperations(componentsSrc[0], targetCRS, context); } @@ -12363,11 +12411,61 @@ CoordinateOperationFactory::Private::createOperations( for (const auto &horizTransform : horizTransforms) { for (const auto &verticalTransform : verticalTransforms) { - auto op = createHorizVerticalPROJBased( - sourceCRS, targetCRS, horizTransform, - verticalTransform); + crs::GeographicCRSPtr interpolationGeogCRS; + auto transformationVerticalTransform = + dynamic_cast<const Transformation *>( + verticalTransform.get()); + if (transformationVerticalTransform) { + auto interpTransformCRS = + transformationVerticalTransform + ->interpolationCRS(); + if (interpTransformCRS) { + auto nn_interpTransformCRS = + NN_NO_CHECK(interpTransformCRS); + if (dynamic_cast<const crs::GeographicCRS *>( + nn_interpTransformCRS.get())) { + interpolationGeogCRS = + util::nn_dynamic_pointer_cast< + crs::GeographicCRS>( + nn_interpTransformCRS); + } + } + } + bool done = false; + if (interpolationGeogCRS && + (interpolationGeogCRS->_isEquivalentTo( + srcGeogCRS.get(), + util::IComparable::Criterion::EQUIVALENT) || + interpolationGeogCRS->is2DPartOf3D( + NN_NO_CHECK(srcGeogCRS.get())))) { + auto srcToInterp = createOperations( + componentsSrc[0], + NN_NO_CHECK(interpolationGeogCRS), context); + auto interpToCompoundHoriz = createOperations( + NN_NO_CHECK(interpolationGeogCRS), + componentsSrc[0], context); + if (!srcToInterp.empty() && + !interpToCompoundHoriz.empty()) { + auto op = createHorizVerticalHorizPROJBased( + sourceCRS, componentsSrc[0], + srcToInterp.front(), verticalTransform, + interpToCompoundHoriz.front(), + interpolationGeogCRS); + done = true; + res.emplace_back( + ConcatenatedOperation:: + createComputeMetadata( + {op, horizTransform}, + !allowEmptyIntersection)); + } + } + if (!done) { + auto op = createHorizVerticalPROJBased( + sourceCRS, targetCRS, horizTransform, + verticalTransform); - res.emplace_back(op); + res.emplace_back(op); + } } } return res; diff --git a/src/iso19111/internal.cpp b/src/iso19111/internal.cpp index 240c98f4..4810202d 100644 --- a/src/iso19111/internal.cpp +++ b/src/iso19111/internal.cpp @@ -298,6 +298,21 @@ std::vector<std::string> split(const std::string &str, char separator) { // --------------------------------------------------------------------------- +std::vector<std::string> split(const std::string &str, + const std::string &separator) { + std::vector<std::string> res; + size_t lastPos = 0; + size_t newPos = 0; + while ((newPos = str.find(separator, lastPos)) != std::string::npos) { + res.push_back(str.substr(lastPos, newPos - lastPos)); + lastPos = newPos + separator.size(); + } + res.push_back(str.substr(lastPos)); + return res; +} + +// --------------------------------------------------------------------------- + #ifdef _WIN32 // For some reason, sqlite3_snprintf() in the sqlite3 builds used on AppVeyor diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index e072a66f..c84ea2f3 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -3818,7 +3818,7 @@ CRSNNPtr WKTParser::Private::buildVerticalCRS(const WKTNodeNNPtr &node) { Transformation::createGravityRelatedHeightToGeographic3D( PropertyMap().set(IdentifiedObject::NAME_KEY, transformationName), - crs, GeographicCRS::EPSG_4979, + crs, GeographicCRS::EPSG_4979, nullptr, stripQuotes(extensionChildren[1]), std::vector<PositionalAccuracyNNPtr>()); return nn_static_pointer_cast<CRS>(BoundCRS::create( @@ -4922,7 +4922,7 @@ struct PROJStringFormatter::Private { }; std::vector<InversionStackElt> inversionStack_{InversionStackElt()}; bool omitProjLongLatIfPossible_ = false; - bool omitZUnitConversion_ = false; + std::vector<bool> omitZUnitConversion_{false}; DatabaseContextPtr dbContext_{}; bool useApproxTMerc_ = false; bool addNoDefs_ = true; @@ -5939,15 +5939,21 @@ bool PROJStringFormatter::omitProjLongLatIfPossible() const { // --------------------------------------------------------------------------- -void PROJStringFormatter::setOmitZUnitConversion(bool omit) { - assert(d->omitZUnitConversion_ ^ omit); - d->omitZUnitConversion_ = omit; +void PROJStringFormatter::pushOmitZUnitConversion() { + d->omitZUnitConversion_.push_back(true); +} + +// --------------------------------------------------------------------------- + +void PROJStringFormatter::popOmitZUnitConversion() { + assert(d->omitZUnitConversion_.size() > 1); + d->omitZUnitConversion_.pop_back(); } // --------------------------------------------------------------------------- bool PROJStringFormatter::omitZUnitConversion() const { - return d->omitZUnitConversion_; + return d->omitZUnitConversion_.back(); } // --------------------------------------------------------------------------- @@ -6995,7 +7001,7 @@ PROJStringParser::Private::buildBoundOrCompoundCRSIfNeeded(int iStep, Transformation::createGravityRelatedHeightToGeographic3D( PropertyMap().set(IdentifiedObject::NAME_KEY, "unknown to WGS84 ellipsoidal height"), - crs, GeographicCRS::EPSG_4979, geoidgrids, + crs, GeographicCRS::EPSG_4979, nullptr, geoidgrids, std::vector<PositionalAccuracyNNPtr>()); auto boundvcrs = BoundCRS::create(vcrs, GeographicCRS::EPSG_4979, transformation); |
