diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/iso19111/coordinateoperation.cpp | 135 | ||||
| -rw-r--r-- | src/iso19111/factory.cpp | 23 |
2 files changed, 157 insertions, 1 deletions
diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp index a1612339..f7ea385d 100644 --- a/src/iso19111/coordinateoperation.cpp +++ b/src/iso19111/coordinateoperation.cpp @@ -10171,6 +10171,7 @@ struct CoordinateOperationFactory::Private { const crs::CRSNNPtr &targetCRS; const CoordinateOperationContextNNPtr &context; bool inCreateOperationsWithDatumPivotAntiRecursion = false; + bool inCreateOperationsThroughPreferredHub = false; Context(const crs::CRSNNPtr &sourceCRSIn, const crs::CRSNNPtr &targetCRSIn, @@ -10195,6 +10196,12 @@ struct CoordinateOperationFactory::Private { const crs::GeodeticCRS *geodSrc, const crs::GeodeticCRS *geodDst, Context &context); + static void createOperationsThroughPreferredHub( + std::vector<CoordinateOperationNNPtr> &res, + const crs::CRSNNPtr &sourceCRS, const crs::CRSNNPtr &targetCRS, + const crs::GeodeticCRS *geodSrc, const crs::GeodeticCRS *geodDst, + Context &context); + static bool hasPerfectAccuracyResult(const std::vector<CoordinateOperationNNPtr> &res, const Context &context); @@ -12016,6 +12023,122 @@ void CoordinateOperationFactory::Private::createOperationsWithDatumPivot( // --------------------------------------------------------------------------- +void CoordinateOperationFactory::Private::createOperationsThroughPreferredHub( + std::vector<CoordinateOperationNNPtr> &res, const crs::CRSNNPtr &sourceCRS, + const crs::CRSNNPtr &targetCRS, const crs::GeodeticCRS *geodSrc, + const crs::GeodeticCRS *geodDst, Private::Context &context) { + + const auto &srcDatum = geodSrc->datum(); + const auto &dstDatum = geodDst->datum(); + + if (!srcDatum || !dstDatum) + return; + const auto &srcDatumIds = srcDatum->identifiers(); + const auto &dstDatumIds = dstDatum->identifiers(); + if (srcDatumIds.empty() || dstDatumIds.empty()) + return; + + const auto &authFactory = context.context->getAuthorityFactory(); + + const auto srcAuthFactory = io::AuthorityFactory::create( + authFactory->databaseContext(), *(srcDatumIds.front()->codeSpace())); + const auto srcPreferredHubs = + srcAuthFactory->getPreferredHubGeodeticReferenceFrames( + srcDatumIds.front()->code()); + + const auto dstAuthFactory = io::AuthorityFactory::create( + authFactory->databaseContext(), *(dstDatumIds.front()->codeSpace())); + const auto dstPreferredHubs = + dstAuthFactory->getPreferredHubGeodeticReferenceFrames( + dstDatumIds.front()->code()); + if (srcPreferredHubs.empty() && dstPreferredHubs.empty()) + return; + + // Currently if we have prefered hubs for both source and target, we + // will use only the one for target, arbitrarily... We could use boths + // but that would complicate things. + if (!srcPreferredHubs.empty() && dstPreferredHubs.empty()) { + std::vector<CoordinateOperationNNPtr> resTmp; + createOperationsThroughPreferredHub(resTmp, targetCRS, sourceCRS, + geodDst, geodSrc, context); + if (!resTmp.empty()) { + resTmp = applyInverse(resTmp); + res.insert(res.end(), resTmp.begin(), resTmp.end()); + } + return; + } + assert(!dstPreferredHubs.empty()); + +#ifdef DEBUG + EnterDebugLevel enterFunction; + debugTrace("createOperationsThroughPreferredHub(" + + objectAsStr(sourceCRS.get()) + "," + + objectAsStr(targetCRS.get()) + ")"); +#endif + + struct AntiRecursionGuard { + Context &context; + + explicit AntiRecursionGuard(Context &contextIn) : context(contextIn) { + assert(!context.inCreateOperationsThroughPreferredHub); + context.inCreateOperationsThroughPreferredHub = true; + } + + ~AntiRecursionGuard() { + context.inCreateOperationsThroughPreferredHub = false; + } + }; + AntiRecursionGuard guard(context); + + std::vector<crs::CRSNNPtr> candidatesIntermCRS; + for (const auto &datumHub : dstPreferredHubs) { + auto candidates = + findCandidateGeodCRSForDatum(authFactory, datumHub.get()); + bool addedGeog2D = false; + for (const auto &intermCRS : candidates) { + auto geogCRS = dynamic_cast<crs::GeographicCRS *>(intermCRS.get()); + if (geogCRS && + geogCRS->coordinateSystem()->axisList().size() == 2) { + candidatesIntermCRS.emplace_back(intermCRS); + addedGeog2D = true; + break; + } + } + if (!addedGeog2D) { + candidatesIntermCRS.insert(candidatesIntermCRS.end(), + candidates.begin(), candidates.end()); + } + } + + const bool allowEmptyIntersection = true; + for (const auto &intermCRS : candidatesIntermCRS) { +#ifdef DEBUG + EnterDebugLevel loopLevel; + debugTrace("try " + objectAsStr(sourceCRS.get()) + "->" + + objectAsStr(intermCRS.get()) + "->" + + objectAsStr(targetCRS.get()) + ")"); + EnterDebugLevel loopLevel2; +#endif + const auto opsFirst = createOperations(sourceCRS, intermCRS, context); + const auto opsLast = createOperations(intermCRS, targetCRS, context); + for (const auto &opFirst : opsFirst) { + for (const auto &opLast : opsLast) { + if (!opFirst->hasBallparkTransformation() || + !opLast->hasBallparkTransformation()) { + try { + res.emplace_back( + ConcatenatedOperation::createComputeMetadata( + {opFirst, opLast}, !allowEmptyIntersection)); + } catch (const InvalidOperationEmptyIntersection &) { + } + } + } + } + } +} + +// --------------------------------------------------------------------------- + static CoordinateOperationNNPtr createBallparkGeocentricTranslation(const crs::CRSNNPtr &sourceCRS, const crs::CRSNNPtr &targetCRS) { @@ -12262,7 +12385,17 @@ CoordinateOperationFactory::Private::createOperations( sourceCRS, targetCRS, context.context); res.insert(res.end(), resWithIntermediate.begin(), resWithIntermediate.end()); - doFilterAndCheckPerfectOp = true; + doFilterAndCheckPerfectOp = !res.empty(); + + // If transforming from/to WGS84 (Gxxxx), try through 'neutral' + // WGS84 + if (res.empty() && geodSrc && geodDst && + !context.inCreateOperationsThroughPreferredHub && + !context.inCreateOperationsWithDatumPivotAntiRecursion) { + createOperationsThroughPreferredHub( + res, sourceCRS, targetCRS, geodSrc, geodDst, context); + doFilterAndCheckPerfectOp = !res.empty(); + } } } diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index 1f40f1f0..4bf5427d 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -4982,6 +4982,29 @@ AuthorityFactory::createCompoundCRSFromExisting( // --------------------------------------------------------------------------- //! @cond Doxygen_Suppress +std::list<datum::GeodeticReferenceFrameNNPtr> +AuthorityFactory::getPreferredHubGeodeticReferenceFrames( + const std::string &geodeticReferenceFrameCode) const { + std::list<datum::GeodeticReferenceFrameNNPtr> res; + + const std::string sql("SELECT hub_auth_name, hub_code FROM " + "geodetic_datum_preferred_hub WHERE " + "src_auth_name = ? AND src_code = ?"); + auto sqlRes = d->run(sql, {d->authority(), geodeticReferenceFrameCode}); + for (const auto &row : sqlRes) { + const auto &auth_name = row[0]; + const auto &code = row[1]; + res.emplace_back( + d->createFactory(auth_name)->createGeodeticDatum(code)); + } + + return res; +} +//! @endcond + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress FactoryException::FactoryException(const char *message) : Exception(message) {} // --------------------------------------------------------------------------- |
