From 2dd68f992680586f64b79807d049bc6c648197b5 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 12 Sep 2019 13:27:23 +0200 Subject: createOperations(): make it work when transforming between CompoundCRS and Geog3D when the DB has only VertCS to Geog2D This is needed to fix cases that would not work if using the promoteTo3D()/--3d functionnality just added per a6e1d72890615b42f54edad9b17acff8e7623844 In some cases, the EPSG database only contains a Geographic 2D CRS (like NAD83), without a 3D version. Consequently vertical transformations between that Geographic CRS and a Vertical CRS are only available with a 2D CRS code (kind of a bug in modelization by the way...). So when promoting the Geographic 2D CRS to a 3D one, we suddenly cannot find the available transformations any more. So in such situation, try to fallback to the 2D CRS to restore the capability to find the available transformations. --- src/iso19111/coordinateoperation.cpp | 68 ++++++++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp index e86f1850..768ef76f 100644 --- a/src/iso19111/coordinateoperation.cpp +++ b/src/iso19111/coordinateoperation.cpp @@ -12106,11 +12106,16 @@ CoordinateOperationFactory::Private::createOperations( auto geodSrc = dynamic_cast(sourceCRS.get()); auto geodDst = dynamic_cast(targetCRS.get()); + auto geogSrc = dynamic_cast(sourceCRS.get()); + auto geogDst = dynamic_cast(targetCRS.get()); + auto vertSrc = dynamic_cast(sourceCRS.get()); + auto vertDst = dynamic_cast(targetCRS.get()); // First look-up if the registry provide us with operations. auto derivedSrc = dynamic_cast(sourceCRS.get()); auto derivedDst = dynamic_cast(targetCRS.get()); - if (context.context->getAuthorityFactory() && + const auto &authFactory = context.context->getAuthorityFactory(); + if (authFactory && (derivedSrc == nullptr || !derivedSrc->baseCRS()->_isEquivalentTo( targetCRS.get(), util::IComparable::Criterion::EQUIVALENT)) && @@ -12144,6 +12149,58 @@ CoordinateOperationFactory::Private::createOperations( util::IComparable::Criterion::EQUIVALENT); } + // NAD83 only exists in 2D version in EPSG, so if it has been + // promotted to 3D, when researching a vertical to geog + // transformation, + // try to down cast to 2D. + if (res.empty() && geogSrc && vertDst && + geogSrc->coordinateSystem()->axisList().size() == 3 && + geogSrc->datum()) { + const auto candidatesSrcGeod(findCandidateGeodCRSForDatum( + authFactory, geogSrc->datum().get())); + for (const auto &candidate : candidatesSrcGeod) { + auto geogCandidate = + util::nn_dynamic_pointer_cast( + candidate); + if (geogCandidate && + geogCandidate->coordinateSystem()->axisList().size() == + 2) { + res = + findOpsInRegistryDirect(NN_NO_CHECK(geogCandidate), + targetCRS, context.context); + if (res.empty()) { + res = applyInverse(findOpsInRegistryDirect( + targetCRS, NN_NO_CHECK(geogCandidate), + context.context)); + } + break; + } + } + } else if (res.empty() && geogDst && vertSrc && + geogDst->coordinateSystem()->axisList().size() == 3 && + geogDst->datum()) { + const auto candidatesDstGeod(findCandidateGeodCRSForDatum( + authFactory, geogDst->datum().get())); + for (const auto &candidate : candidatesDstGeod) { + auto geogCandidate = + util::nn_dynamic_pointer_cast( + candidate); + if (geogCandidate && + geogCandidate->coordinateSystem()->axisList().size() == + 2) { + res = findOpsInRegistryDirect( + sourceCRS, NN_NO_CHECK(geogCandidate), + context.context); + if (res.empty()) { + res = applyInverse(findOpsInRegistryDirect( + NN_NO_CHECK(geogCandidate), sourceCRS, + context.context)); + } + break; + } + } + } + if (res.empty() && !sameGeodeticDatum && !context.inCreateOperationsWithDatumPivotAntiRecursion && geodSrc && geodDst) { @@ -12202,10 +12259,6 @@ CoordinateOperationFactory::Private::createOperations( "celestial body"); } - auto geogSrc = - dynamic_cast(sourceCRS.get()); - auto geogDst = - dynamic_cast(targetCRS.get()); if (geogSrc && geogDst) { return createOperationsGeogToGeog(res, sourceCRS, targetCRS, geogSrc, geogDst); @@ -12293,7 +12346,6 @@ CoordinateOperationFactory::Private::createOperations( return applyInverse(createOperations(targetCRS, sourceCRS, context)); } - auto geogDst = dynamic_cast(targetCRS.get()); if (boundSrc && geogDst) { const auto &hubSrc = boundSrc->hubCRS(); auto hubSrcGeog = @@ -12482,14 +12534,12 @@ CoordinateOperationFactory::Private::createOperations( } // reverse of previous case - auto geogSrc = dynamic_cast(sourceCRS.get()); if (geogSrc && boundDst) { return applyInverse(createOperations(targetCRS, sourceCRS, context)); } // vertCRS (as boundCRS with transformation to target vertCRS) to // vertCRS - auto vertDst = dynamic_cast(targetCRS.get()); if (boundSrc && vertDst) { auto baseSrcVert = dynamic_cast(boundSrc->baseCRS().get()); @@ -12506,7 +12556,6 @@ CoordinateOperationFactory::Private::createOperations( } // reverse of previous case - auto vertSrc = dynamic_cast(sourceCRS.get()); if (boundDst && vertSrc) { return applyInverse(createOperations(targetCRS, sourceCRS, context)); } @@ -12550,7 +12599,6 @@ CoordinateOperationFactory::Private::createOperations( if (vertSrc && geogDst) { if (vertSrc->identifiers().empty()) { - const auto &authFactory = context.context->getAuthorityFactory(); const auto &vertSrcName = vertSrc->nameStr(); if (authFactory != nullptr && vertSrcName != "unnamed" && vertSrcName != "unknown") { -- cgit v1.2.3