diff options
| author | Even Rouault <even.rouault@spatialys.com> | 2019-11-02 03:18:32 +0100 |
|---|---|---|
| committer | Even Rouault <even.rouault@spatialys.com> | 2019-11-02 14:54:20 +0100 |
| commit | d9064c3de62982c461a36ed9997eab56d1cb9f85 (patch) | |
| tree | 0689ff513a9de2c2cc9521ed447cded9ad9fd134 /src/iso19111/coordinateoperation.cpp | |
| parent | 00608cc1c892a0d0522ffd08127a4494d4844e19 (diff) | |
| download | PROJ-d9064c3de62982c461a36ed9997eab56d1cb9f85.tar.gz PROJ-d9064c3de62982c461a36ed9997eab56d1cb9f85.zip | |
Add tracing framework, and improve createOperations() performance
Diffstat (limited to 'src/iso19111/coordinateoperation.cpp')
| -rw-r--r-- | src/iso19111/coordinateoperation.cpp | 629 |
1 files changed, 346 insertions, 283 deletions
diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp index 9796221d..d0a1761c 100644 --- a/src/iso19111/coordinateoperation.cpp +++ b/src/iso19111/coordinateoperation.cpp @@ -40,6 +40,7 @@ #include "proj/internal/internal.hpp" #include "proj/internal/io_internal.hpp" +#include "proj/internal/tracing.hpp" // PROJ include order is sensitive // clang-format off @@ -56,11 +57,10 @@ #include <string> #include <vector> -// #define DEBUG +// #define TRACE_CREATE_OPERATIONS // #define DEBUG_SORT // #define DEBUG_CONCATENATED_OPERATION -#if defined(DEBUG) || defined(DEBUG_SORT) || \ - defined(DEBUG_CONCATENATED_OPERATION) +#if defined(DEBUG_SORT) || defined(DEBUG_CONCATENATED_OPERATION) #include <iostream> #endif @@ -135,6 +135,26 @@ createPropertiesForInverse(const CoordinateOperation *op, bool derivedFrom, // --------------------------------------------------------------------------- +#ifdef TRACE_CREATE_OPERATIONS + +//! @cond Doxygen_Suppress + +static std::string objectAsStr(const common::IdentifiedObject *obj) { + std::string ret(obj->nameStr()); + const auto &ids = obj->identifiers(); + if (!ids.empty()) { + ret += " ("; + ret += (*ids[0]->codeSpace()) + ":" + ids[0]->code(); + ret += ")"; + } + return ret; +} +//! @endcond + +#endif + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress class InvalidOperationEmptyIntersection : public InvalidOperation { @@ -10373,6 +10393,9 @@ struct CoordinateOperationFactory::Private { bool inCreateOperationsGeogToVertWithAlternativeGeog = false; bool inCreateOperationsGeogToVertWithIntermediateVert = false; bool skipHorizontalTransformation = false; + std::map<std::pair<io::AuthorityFactory::ObjectType, std::string>, + std::list<std::pair<std::string, std::string>>> + cacheNameToCRS{}; Context(const metadata::ExtentPtr &extent1In, const metadata::ExtentPtr &extent2In, @@ -10387,6 +10410,24 @@ struct CoordinateOperationFactory::Private { private: static constexpr bool allowEmptyIntersection = true; + static void + buildCRSIds(const crs::CRSNNPtr &crs, Private::Context &context, + std::list<std::pair<std::string, std::string>> &ids); + + static std::vector<CoordinateOperationNNPtr> + findOpsInRegistryDirect(const crs::CRSNNPtr &sourceCRS, + const crs::CRSNNPtr &targetCRS, + Private::Context &context); + + static std::vector<CoordinateOperationNNPtr> + findOpsInRegistryDirectTo(const crs::CRSNNPtr &targetCRS, + Private::Context &context); + + static std::vector<CoordinateOperationNNPtr> + findsOpsInRegistryWithIntermediate(const crs::CRSNNPtr &sourceCRS, + const crs::CRSNNPtr &targetCRS, + Private::Context &context); + static void createOperationsFromProj4Ext( const crs::CRSNNPtr &sourceCRS, const crs::CRSNNPtr &targetCRS, const crs::BoundCRS *boundSrc, const crs::BoundCRS *boundDst, @@ -11232,9 +11273,20 @@ filterAndSort(const std::vector<CoordinateOperationNNPtr> &sourceList, const CoordinateOperationContextNNPtr &context, const metadata::ExtentPtr &extent1, const metadata::ExtentPtr &extent2) { - return FilterResults(sourceList, context, extent1, extent2, false) - .andSort() - .getRes(); +#ifdef TRACE_CREATE_OPERATIONS + ENTER_FUNCTION(); + logTrace("number of results before filter and sort: " + + toString(static_cast<int>(sourceList.size()))); +#endif + auto resFiltered = + FilterResults(sourceList, context, extent1, extent2, false) + .andSort() + .getRes(); +#ifdef TRACE_CREATE_OPERATIONS + logTrace("number of results after filter and sort: " + + toString(static_cast<int>(resFiltered.size()))); +#endif + return resFiltered; } //! @endcond @@ -11256,13 +11308,9 @@ applyInverse(const std::vector<CoordinateOperationNNPtr> &list) { //! @cond Doxygen_Suppress -static void buildCRSIds(const crs::CRSNNPtr &crs, - const CoordinateOperationContextNNPtr &context, - std::list<std::pair<std::string, std::string>> &ids) { - const auto &authFactory = context->getAuthorityFactory(); - assert(authFactory); - const auto &authFactoryName = authFactory->getAuthority(); - +void CoordinateOperationFactory::Private::buildCRSIds( + const crs::CRSNNPtr &crs, Private::Context &context, + std::list<std::pair<std::string, std::string>> &ids) { for (const auto &id : crs->identifiers()) { const auto &authName = *(id->codeSpace()); const auto &code = id->code(); @@ -11271,24 +11319,40 @@ static void buildCRSIds(const crs::CRSNNPtr &crs, } } if (ids.empty()) { - try { - const auto tmpAuthFactory = io::AuthorityFactory::create( - authFactory->databaseContext(), - (authFactoryName.empty() || authFactoryName == "any") - ? std::string() - : authFactoryName); - std::vector<io::AuthorityFactory::ObjectType> allowedObjects; - auto geogCRS = dynamic_cast<const crs::GeographicCRS *>(crs.get()); - if (geogCRS) { - allowedObjects.push_back( - geogCRS->coordinateSystem()->axisList().size() == 2 - ? io::AuthorityFactory::ObjectType::GEOGRAPHIC_2D_CRS - : io::AuthorityFactory::ObjectType::GEOGRAPHIC_3D_CRS); - } else if (dynamic_cast<crs::ProjectedCRS *>(crs.get())) { - allowedObjects.push_back( - io::AuthorityFactory::ObjectType::PROJECTED_CRS); - } - if (!allowedObjects.empty()) { + std::vector<io::AuthorityFactory::ObjectType> allowedObjects; + auto geogCRS = dynamic_cast<const crs::GeographicCRS *>(crs.get()); + if (geogCRS) { + allowedObjects.push_back( + geogCRS->coordinateSystem()->axisList().size() == 2 + ? io::AuthorityFactory::ObjectType::GEOGRAPHIC_2D_CRS + : io::AuthorityFactory::ObjectType::GEOGRAPHIC_3D_CRS); + } else if (dynamic_cast<crs::ProjectedCRS *>(crs.get())) { + allowedObjects.push_back( + io::AuthorityFactory::ObjectType::PROJECTED_CRS); + } else if (dynamic_cast<crs::VerticalCRS *>(crs.get())) { + allowedObjects.push_back( + io::AuthorityFactory::ObjectType::VERTICAL_CRS); + } + if (!allowedObjects.empty()) { + + const std::pair<io::AuthorityFactory::ObjectType, std::string> key( + allowedObjects[0], crs->nameStr()); + auto iter = context.cacheNameToCRS.find(key); + if (iter != context.cacheNameToCRS.end()) { + ids = iter->second; + return; + } + + const auto &authFactory = context.context->getAuthorityFactory(); + assert(authFactory); + const auto &authFactoryName = authFactory->getAuthority(); + try { + const auto tmpAuthFactory = io::AuthorityFactory::create( + authFactory->databaseContext(), + (authFactoryName.empty() || authFactoryName == "any") + ? std::string() + : authFactoryName); + auto matches = tmpAuthFactory->createObjectsFromName( crs->nameStr(), allowedObjects, false, 2); if (matches.size() == 1 && @@ -11300,8 +11364,9 @@ static void buildCRSIds(const crs::CRSNNPtr &crs, ids.emplace_back(*(tmpIds[0]->codeSpace()), tmpIds[0]->code()); } + } catch (const std::exception &) { } - } catch (const std::exception &) { + context.cacheNameToCRS[key] = ids; } } } @@ -11332,13 +11397,18 @@ getCandidateAuthorities(const io::AuthorityFactoryPtr &authFactory, // --------------------------------------------------------------------------- // Look in the authority registry for operations from sourceCRS to targetCRS -static std::vector<CoordinateOperationNNPtr> -findOpsInRegistryDirect(const crs::CRSNNPtr &sourceCRS, - const crs::CRSNNPtr &targetCRS, - const CoordinateOperationContextNNPtr &context) { - const auto &authFactory = context->getAuthorityFactory(); +std::vector<CoordinateOperationNNPtr> +CoordinateOperationFactory::Private::findOpsInRegistryDirect( + const crs::CRSNNPtr &sourceCRS, const crs::CRSNNPtr &targetCRS, + Private::Context &context) { + const auto &authFactory = context.context->getAuthorityFactory(); assert(authFactory); +#ifdef TRACE_CREATE_OPERATIONS + ENTER_BLOCK("findOpsInRegistryDirect(" + objectAsStr(sourceCRS.get()) + + " --> " + objectAsStr(targetCRS.get()) + ")"); +#endif + std::list<std::pair<std::string, std::string>> sourceIds; std::list<std::pair<std::string, std::string>> targetIds; buildCRSIds(sourceCRS, context, sourceIds); @@ -11360,13 +11430,23 @@ findOpsInRegistryDirect(const crs::CRSNNPtr &sourceCRS, auto res = tmpAuthFactory->createFromCoordinateReferenceSystemCodes( srcAuthName, srcCode, targetAuthName, targetCode, - context->getUsePROJAlternativeGridNames(), - context->getGridAvailabilityUse() == + context.context->getUsePROJAlternativeGridNames(), + context.context->getGridAvailabilityUse() == CoordinateOperationContext::GridAvailabilityUse:: DISCARD_OPERATION_IF_MISSING_GRID, - context->getDiscardSuperseded()); + context.context->getDiscardSuperseded(), true, false, + context.extent1, context.extent2); if (!res.empty()) { - return res; + auto resFiltered = + FilterResults(res, context.context, context.extent1, + context.extent2, false) + .getRes(); +#ifdef TRACE_CREATE_OPERATIONS + logTrace("filtering reduced from " + + toString(static_cast<int>(res.size())) + " to " + + toString(static_cast<int>(resFiltered.size()))); +#endif + return resFiltered; } } } @@ -11376,48 +11456,16 @@ findOpsInRegistryDirect(const crs::CRSNNPtr &sourceCRS, // --------------------------------------------------------------------------- -// Look in the authority registry for operations from sourceCRS -static std::vector<CoordinateOperationNNPtr> -findOpsInRegistryDirectFrom(const crs::CRSNNPtr &sourceCRS, - const CoordinateOperationContextNNPtr &context) { - const auto &authFactory = context->getAuthorityFactory(); - assert(authFactory); - - std::list<std::pair<std::string, std::string>> ids; - buildCRSIds(sourceCRS, context, ids); - - for (const auto &id : ids) { - const auto &srcAuthName = id.first; - const auto &srcCode = id.second; - - const auto authorities( - getCandidateAuthorities(authFactory, srcAuthName, srcAuthName)); - for (const auto &authority : authorities) { - const auto tmpAuthFactory = io::AuthorityFactory::create( - authFactory->databaseContext(), - authority == "any" ? std::string() : authority); - auto res = tmpAuthFactory->createFromCoordinateReferenceSystemCodes( - srcAuthName, srcCode, std::string(), std::string(), - context->getUsePROJAlternativeGridNames(), - context->getGridAvailabilityUse() == - CoordinateOperationContext::GridAvailabilityUse:: - DISCARD_OPERATION_IF_MISSING_GRID, - context->getDiscardSuperseded()); - if (!res.empty()) { - return res; - } - } - } - return std::vector<CoordinateOperationNNPtr>(); -} - -// --------------------------------------------------------------------------- - // Look in the authority registry for operations to targetCRS -static std::vector<CoordinateOperationNNPtr> -findOpsInRegistryDirectTo(const crs::CRSNNPtr &targetCRS, - const CoordinateOperationContextNNPtr &context) { - const auto &authFactory = context->getAuthorityFactory(); +std::vector<CoordinateOperationNNPtr> +CoordinateOperationFactory::Private::findOpsInRegistryDirectTo( + const crs::CRSNNPtr &targetCRS, Private::Context &context) { +#ifdef TRACE_CREATE_OPERATIONS + ENTER_BLOCK("findOpsInRegistryDirectTo({any} -->" + + objectAsStr(targetCRS.get()) + ")"); +#endif + + const auto &authFactory = context.context->getAuthorityFactory(); assert(authFactory); std::list<std::pair<std::string, std::string>> ids; @@ -11435,13 +11483,23 @@ findOpsInRegistryDirectTo(const crs::CRSNNPtr &targetCRS, authority == "any" ? std::string() : authority); auto res = tmpAuthFactory->createFromCoordinateReferenceSystemCodes( std::string(), std::string(), targetAuthName, targetCode, - context->getUsePROJAlternativeGridNames(), - context->getGridAvailabilityUse() == + context.context->getUsePROJAlternativeGridNames(), + context.context->getGridAvailabilityUse() == CoordinateOperationContext::GridAvailabilityUse:: DISCARD_OPERATION_IF_MISSING_GRID, - context->getDiscardSuperseded()); + context.context->getDiscardSuperseded(), true, true, + context.extent1, context.extent2); if (!res.empty()) { - return res; + auto resFiltered = + FilterResults(res, context.context, context.extent1, + context.extent2, false) + .getRes(); +#ifdef TRACE_CREATE_OPERATIONS + logTrace("filtering reduced from " + + toString(static_cast<int>(res.size())) + " to " + + toString(static_cast<int>(resFiltered.size()))); +#endif + return resFiltered; } } } @@ -11456,11 +11514,18 @@ findOpsInRegistryDirectTo(const crs::CRSNNPtr &targetCRS, // Look in the authority registry for operations from sourceCRS to targetCRS // using an intermediate pivot -static std::vector<CoordinateOperationNNPtr> findsOpsInRegistryWithIntermediate( +std::vector<CoordinateOperationNNPtr> +CoordinateOperationFactory::Private::findsOpsInRegistryWithIntermediate( const crs::CRSNNPtr &sourceCRS, const crs::CRSNNPtr &targetCRS, - const CoordinateOperationContextNNPtr &context) { + Private::Context &context) { - const auto &authFactory = context->getAuthorityFactory(); +#ifdef TRACE_CREATE_OPERATIONS + ENTER_BLOCK("findsOpsInRegistryWithIntermediate(" + + objectAsStr(sourceCRS.get()) + " --> " + + objectAsStr(targetCRS.get()) + ")"); +#endif + + const auto &authFactory = context.context->getAuthorityFactory(); assert(authFactory); std::list<std::pair<std::string, std::string>> sourceIds; @@ -11482,41 +11547,40 @@ static std::vector<CoordinateOperationNNPtr> findsOpsInRegistryWithIntermediate( authFactory->databaseContext(), authority == "any" ? std::string() : authority); + io::AuthorityFactory::ObjectType intermediateObjectType = + io::AuthorityFactory::ObjectType::CRS; + + // If doing GeogCRS --> GeogCRS, only use GeogCRS as + // intermediate CRS + // Avoid weird behaviour when doing NAD83 -> NAD83(2011) + // that would go through NAVD88 otherwise. + if (context.context->getIntermediateCRS().empty() && + dynamic_cast<const crs::GeographicCRS *>(sourceCRS.get()) && + dynamic_cast<const crs::GeographicCRS *>(targetCRS.get())) { + intermediateObjectType = + io::AuthorityFactory::ObjectType::GEOGRAPHIC_CRS; + } auto res = tmpAuthFactory->createFromCRSCodesWithIntermediates( srcAuthName, srcCode, targetAuthName, targetCode, - context->getUsePROJAlternativeGridNames(), - context->getGridAvailabilityUse() == + context.context->getUsePROJAlternativeGridNames(), + context.context->getGridAvailabilityUse() == CoordinateOperationContext::GridAvailabilityUse:: DISCARD_OPERATION_IF_MISSING_GRID, - context->getDiscardSuperseded(), - context->getIntermediateCRS()); + context.context->getDiscardSuperseded(), + context.context->getIntermediateCRS(), + intermediateObjectType, context.extent1, context.extent2); if (!res.empty()) { - // If doing GeogCRS --> GeogCRS, only use GeogCRS as - // intermediate CRS - // Avoid weird behaviour when doing NAD83 -> NAD83(2011) - // that would go through NAVD88 otherwise. - if (context->getIntermediateCRS().empty() && - dynamic_cast<const crs::GeographicCRS *>( - sourceCRS.get()) && - dynamic_cast<const crs::GeographicCRS *>( - targetCRS.get())) { - std::vector<CoordinateOperationNNPtr> res2; - for (const auto &op : res) { - auto concatOp = - dynamic_cast<ConcatenatedOperation *>(op.get()); - if (concatOp && - dynamic_cast<const crs::GeographicCRS *>( - concatOp->operations() - .front() - ->targetCRS() - .get())) { - res2.emplace_back(op); - } - } - res = std::move(res2); - } - return res; + auto resFiltered = + FilterResults(res, context.context, context.extent1, + context.extent2, false) + .getRes(); +#ifdef TRACE_CREATE_OPERATIONS + logTrace("filtering reduced from " + + toString(static_cast<int>(res.size())) + " to " + + toString(static_cast<int>(resFiltered.size()))); +#endif + return resFiltered; } } } @@ -12065,6 +12129,7 @@ static bool hasIdentifiers(const CoordinateOperationNNPtr &op) { static std::vector<crs::CRSNNPtr> findCandidateGeodCRSForDatum(const io::AuthorityFactoryPtr &authFactory, + const crs::GeodeticCRS *crs, const datum::GeodeticReferenceFrame *datum) { std::vector<crs::CRSNNPtr> candidates; assert(datum); @@ -12075,7 +12140,15 @@ findCandidateGeodCRSForDatum(const io::AuthorityFactoryPtr &authFactory, const auto &authName = *(id->codeSpace()); const auto &code = id->code(); if (!authName.empty()) { - auto l_candidates = authFactory->createGeodeticCRSFromDatum( + const auto crsIds = crs->identifiers(); + const auto tmpFactory = + (crsIds.size() == 1 && + *(crsIds.front()->codeSpace()) == authName) + ? io::AuthorityFactory::create( + authFactory->databaseContext(), authName) + .as_nullable() + : authFactory; + auto l_candidates = tmpFactory->createGeodeticCRSFromDatum( authName, code, std::string()); for (const auto &candidate : l_candidates) { candidates.emplace_back(candidate); @@ -12093,7 +12166,7 @@ findCandidateGeodCRSForDatum(const io::AuthorityFactoryPtr &authFactory, match.get(), util::IComparable::Criterion::EQUIVALENT) && !match->identifiers().empty()) { return findCandidateGeodCRSForDatum( - authFactory, + authFactory, crs, dynamic_cast<const datum::GeodeticReferenceFrame *>( match.get())); } @@ -12113,35 +12186,6 @@ static bool isNullTransformation(const std::string &name) { // --------------------------------------------------------------------------- -#ifdef DEBUG - -static int nCallLevel = 0; - -struct EnterDebugLevel { - EnterDebugLevel() { ++nCallLevel; } - ~EnterDebugLevel() { --nCallLevel; } -}; - -static void debugTrace(const std::string &str) { - for (int i = 1; i < nCallLevel; i++) - std::cerr << " "; - std::cerr << str << std::endl; -} - -static std::string objectAsStr(const common::IdentifiedObject *obj) { - std::string ret(obj->nameStr()); - const auto &ids = obj->identifiers(); - if (!ids.empty()) { - ret += " ("; - ret += (*ids[0]->codeSpace()) + ":" + ids[0]->code(); - ret += ")"; - } - return ret; -} -#endif - -// --------------------------------------------------------------------------- - void CoordinateOperationFactory::Private::setCRSs( CoordinateOperation *co, const crs::CRSNNPtr &sourceCRS, const crs::CRSNNPtr &targetCRS) { @@ -12178,11 +12222,10 @@ void CoordinateOperationFactory::Private::createOperationsWithDatumPivot( const crs::CRSNNPtr &targetCRS, const crs::GeodeticCRS *geodSrc, const crs::GeodeticCRS *geodDst, Private::Context &context) { -#ifdef DEBUG - EnterDebugLevel enterFunction; - debugTrace("createOperationsWithDatumPivot(" + - objectAsStr(sourceCRS.get()) + "," + - objectAsStr(targetCRS.get()) + ")"); +#ifdef TRACE_CREATE_OPERATIONS + ENTER_BLOCK("createOperationsWithDatumPivot(" + + objectAsStr(sourceCRS.get()) + "," + + objectAsStr(targetCRS.get()) + ")"); #endif struct CreateOperationsWithDatumPivotAntiRecursion { @@ -12201,10 +12244,10 @@ void CoordinateOperationFactory::Private::createOperationsWithDatumPivot( CreateOperationsWithDatumPivotAntiRecursion guard(context); const auto &authFactory = context.context->getAuthorityFactory(); - const auto candidatesSrcGeod( - findCandidateGeodCRSForDatum(authFactory, geodSrc->datum().get())); - const auto candidatesDstGeod( - findCandidateGeodCRSForDatum(authFactory, geodDst->datum().get())); + const auto candidatesSrcGeod(findCandidateGeodCRSForDatum( + authFactory, geodSrc, geodSrc->datum().get())); + const auto candidatesDstGeod(findCandidateGeodCRSForDatum( + authFactory, geodDst, geodDst->datum().get())); auto createTransformations = [&](const crs::CRSNNPtr &candidateSrcGeod, const crs::CRSNNPtr &candidateDstGeod, @@ -12282,7 +12325,7 @@ void CoordinateOperationFactory::Private::createOperationsWithDatumPivot( subOps.emplace_back(opSecondCloned); subOps.emplace_back(opsThird[0]); } -#ifdef DEBUG +#ifdef TRACE_CREATE_OPERATIONS std::string debugStr; for (const auto &op : subOps) { if (!debugStr.empty()) { @@ -12295,7 +12338,7 @@ void CoordinateOperationFactory::Private::createOperationsWithDatumPivot( debugStr += objectAsStr(op->targetCRS().get()); debugStr += ")"; } - debugTrace("transformation " + debugStr); + logTrace("transformation " + debugStr); #endif res.emplace_back(ConcatenatedOperation::createComputeMetadata( subOps, !allowEmptyIntersection)); @@ -12308,13 +12351,11 @@ void CoordinateOperationFactory::Private::createOperationsWithDatumPivot( if (candidateSrcGeod->nameStr() == sourceCRS->nameStr()) { for (const auto &candidateDstGeod : candidatesDstGeod) { if (candidateDstGeod->nameStr() == targetCRS->nameStr()) { -#ifdef DEBUG - EnterDebugLevel loopLevel; - debugTrace("try " + objectAsStr(sourceCRS.get()) + "->" + - objectAsStr(candidateSrcGeod.get()) + "->" + - objectAsStr(candidateDstGeod.get()) + "->" + - objectAsStr(targetCRS.get()) + ")"); - EnterDebugLevel loopLevel2; +#ifdef TRACE_CREATE_OPERATIONS + ENTER_BLOCK("try " + objectAsStr(sourceCRS.get()) + "->" + + objectAsStr(candidateSrcGeod.get()) + "->" + + objectAsStr(candidateDstGeod.get()) + "->" + + objectAsStr(targetCRS.get()) + ")"); #endif const auto opsFirst = createOperations(sourceCRS, candidateSrcGeod, context); @@ -12334,8 +12375,8 @@ void CoordinateOperationFactory::Private::createOperationsWithDatumPivot( } for (const auto &candidateSrcGeod : candidatesSrcGeod) { -#ifdef DEBUG - EnterDebugLevel loopLevel; +#ifdef TRACE_CREATE_OPERATIONS + ENTER_BLOCK(""); #endif const auto opsFirst = createOperations(sourceCRS, candidateSrcGeod, context); @@ -12343,13 +12384,11 @@ void CoordinateOperationFactory::Private::createOperationsWithDatumPivot( const bool isNullFirst = isNullTransformation(opsFirst[0]->nameStr()); for (const auto &candidateDstGeod : candidatesDstGeod) { -#ifdef DEBUG - EnterDebugLevel loopLevel2; - debugTrace("try " + objectAsStr(sourceCRS.get()) + "->" + - objectAsStr(candidateSrcGeod.get()) + "->" + - objectAsStr(candidateDstGeod.get()) + "->" + - objectAsStr(targetCRS.get()) + ")"); - EnterDebugLevel loopLevel3; +#ifdef TRACE_CREATE_OPERATIONS + ENTER_BLOCK("try " + objectAsStr(sourceCRS.get()) + "->" + + objectAsStr(candidateSrcGeod.get()) + "->" + + objectAsStr(candidateDstGeod.get()) + "->" + + objectAsStr(targetCRS.get()) + ")"); #endif createTransformations(candidateSrcGeod, candidateDstGeod, opsFirst[0], isNullFirst); @@ -12408,11 +12447,10 @@ void CoordinateOperationFactory::Private::createOperationsThroughPreferredHub( } assert(!dstPreferredHubs.empty()); -#ifdef DEBUG - EnterDebugLevel enterFunction; - debugTrace("createOperationsThroughPreferredHub(" + - objectAsStr(sourceCRS.get()) + "," + - objectAsStr(targetCRS.get()) + ")"); +#ifdef TRACE_CREATE_OPERATIONS + ENTER_BLOCK("createOperationsThroughPreferredHub(" + + objectAsStr(sourceCRS.get()) + " --> " + + objectAsStr(targetCRS.get()) + ")"); #endif struct AntiRecursionGuard { @@ -12432,7 +12470,7 @@ void CoordinateOperationFactory::Private::createOperationsThroughPreferredHub( std::vector<crs::CRSNNPtr> candidatesIntermCRS; for (const auto &datumHub : dstPreferredHubs) { auto candidates = - findCandidateGeodCRSForDatum(authFactory, datumHub.get()); + findCandidateGeodCRSForDatum(authFactory, geodDst, datumHub.get()); bool addedGeog2D = false; for (const auto &intermCRS : candidates) { auto geogCRS = dynamic_cast<crs::GeographicCRS *>(intermCRS.get()); @@ -12450,12 +12488,10 @@ void CoordinateOperationFactory::Private::createOperationsThroughPreferredHub( } for (const auto &intermCRS : candidatesIntermCRS) { -#ifdef DEBUG - EnterDebugLevel loopLevel; - debugTrace("try " + objectAsStr(sourceCRS.get()) + "->" + - objectAsStr(intermCRS.get()) + "->" + - objectAsStr(targetCRS.get()) + ")"); - EnterDebugLevel loopLevel2; +#ifdef TRACE_CREATE_OPERATIONS + ENTER_BLOCK("try " + objectAsStr(sourceCRS.get()) + "->" + + objectAsStr(intermCRS.get()) + "->" + + objectAsStr(targetCRS.get()) + ")"); #endif const auto opsFirst = createOperations(sourceCRS, intermCRS, context); const auto opsLast = createOperations(intermCRS, targetCRS, context); @@ -12518,11 +12554,9 @@ CoordinateOperationFactory::Private::createOperations( const crs::CRSNNPtr &sourceCRS, const crs::CRSNNPtr &targetCRS, Private::Context &context) { -#ifdef DEBUG - EnterDebugLevel enterFunction; - auto debugStr("createOperations(" + objectAsStr(sourceCRS.get()) + "," + - objectAsStr(targetCRS.get()) + ")"); - debugTrace(debugStr); +#ifdef TRACE_CREATE_OPERATIONS + ENTER_BLOCK("createOperations(" + objectAsStr(sourceCRS.get()) + " --> " + + objectAsStr(targetCRS.get()) + ")"); #endif std::vector<CoordinateOperationNNPtr> res; @@ -12687,6 +12721,8 @@ void CoordinateOperationFactory::Private::createOperationsFromProj4Ext( const crs::BoundCRS *boundSrc, const crs::BoundCRS *boundDst, std::vector<CoordinateOperationNNPtr> &res) { + ENTER_FUNCTION(); + auto sourceProjExportable = dynamic_cast<const io::IPROJStringExportable *>( boundSrc ? boundSrc : sourceCRS.get()); auto targetProjExportable = dynamic_cast<const io::IPROJStringExportable *>( @@ -12737,79 +12773,75 @@ bool CoordinateOperationFactory::Private::createOperationsFromDatabase( const crs::VerticalCRS *vertDst, std::vector<CoordinateOperationNNPtr> &res) { - bool doFilterAndCheckPerfectOp = true; - res = findOpsInRegistryDirect(sourceCRS, targetCRS, context.context); - if (!sourceCRS->_isEquivalentTo(targetCRS.get())) { - auto resFromInverse = applyInverse( - findOpsInRegistryDirect(targetCRS, sourceCRS, context.context)); - res.insert(res.end(), resFromInverse.begin(), resFromInverse.end()); + ENTER_FUNCTION(); - // If we get at least a result with perfect accuracy, do not - // bother generating synthetic transforms. - if (hasPerfectAccuracyResult(res, context)) { - return true; - } + res = findOpsInRegistryDirect(sourceCRS, targetCRS, context); - doFilterAndCheckPerfectOp = false; - - bool sameGeodeticDatum = false; - - if (vertSrc || vertDst) { - createOperationsFromDatabaseWithVertCRS(sourceCRS, targetCRS, - context, geogSrc, geogDst, - vertSrc, vertDst, res); - } else if (geodSrc && geodDst) { - - const auto &srcDatum = geodSrc->datum(); - const auto &dstDatum = geodDst->datum(); - sameGeodeticDatum = - srcDatum != nullptr && dstDatum != nullptr && - srcDatum->_isEquivalentTo( - dstDatum.get(), util::IComparable::Criterion::EQUIVALENT); - - if (res.empty() && !sameGeodeticDatum && - !context.inCreateOperationsWithDatumPivotAntiRecursion && - srcDatum != nullptr && dstDatum != nullptr) { - // If we still didn't find a transformation, and that the source - // and target are GeodeticCRS, then go through their underlying - // datum to find potential transformations between other - // GeodeticRSs - // that are made of those datum - // The typical example is if transforming between two - // GeographicCRS, - // but transformations are only available between their - // corresponding geocentric CRS. - createOperationsWithDatumPivot(res, sourceCRS, targetCRS, - geodSrc, geodDst, context); - doFilterAndCheckPerfectOp = !res.empty(); - } - } - - // NAD27 to NAD83 has tens of results already. No need to look - // for a pivot - if (!sameGeodeticDatum && - ((res.empty() && - context.context->getAllowUseIntermediateCRS() == - CoordinateOperationContext::IntermediateCRSUse:: - IF_NO_DIRECT_TRANSFORMATION) || - context.context->getAllowUseIntermediateCRS() == - CoordinateOperationContext::IntermediateCRSUse::ALWAYS || - getenv("PROJ_FORCE_SEARCH_PIVOT"))) { - auto resWithIntermediate = findsOpsInRegistryWithIntermediate( - sourceCRS, targetCRS, context.context); - res.insert(res.end(), resWithIntermediate.begin(), - resWithIntermediate.end()); + // If we get at least a result with perfect accuracy, do not + // bother generating synthetic transforms. + if (hasPerfectAccuracyResult(res, context)) { + return true; + } + + bool doFilterAndCheckPerfectOp = false; + + bool sameGeodeticDatum = false; + + if (vertSrc || vertDst) { + createOperationsFromDatabaseWithVertCRS(sourceCRS, targetCRS, context, + geogSrc, geogDst, vertSrc, + vertDst, res); + } else if (geodSrc && geodDst) { + + const auto &srcDatum = geodSrc->datum(); + const auto &dstDatum = geodDst->datum(); + sameGeodeticDatum = + srcDatum != nullptr && dstDatum != nullptr && + srcDatum->_isEquivalentTo(dstDatum.get(), + util::IComparable::Criterion::EQUIVALENT); + + if (res.empty() && !sameGeodeticDatum && + !context.inCreateOperationsWithDatumPivotAntiRecursion && + srcDatum != nullptr && dstDatum != nullptr) { + // If we still didn't find a transformation, and that the source + // and target are GeodeticCRS, then go through their underlying + // datum to find potential transformations between other + // GeodeticRSs + // that are made of those datum + // The typical example is if transforming between two + // GeographicCRS, + // but transformations are only available between their + // corresponding geocentric CRS. + createOperationsWithDatumPivot(res, sourceCRS, targetCRS, geodSrc, + geodDst, context); 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(); - } + // NAD27 to NAD83 has tens of results already. No need to look + // for a pivot + if (!sameGeodeticDatum && + ((res.empty() && + context.context->getAllowUseIntermediateCRS() == + CoordinateOperationContext::IntermediateCRSUse:: + IF_NO_DIRECT_TRANSFORMATION) || + context.context->getAllowUseIntermediateCRS() == + CoordinateOperationContext::IntermediateCRSUse::ALWAYS || + getenv("PROJ_FORCE_SEARCH_PIVOT"))) { + auto resWithIntermediate = + findsOpsInRegistryWithIntermediate(sourceCRS, targetCRS, context); + res.insert(res.end(), resWithIntermediate.begin(), + resWithIntermediate.end()); + 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(); } } @@ -12871,6 +12903,8 @@ std::vector<CoordinateOperationNNPtr> CoordinateOperationFactory::Private:: const crs::CRSNNPtr &sourceCRS, const crs::CRSNNPtr &targetCRS, const crs::VerticalCRS *vertDst, Private::Context &context) { + ENTER_FUNCTION(); + std::vector<CoordinateOperationNNPtr> res; struct AntiRecursionGuard { @@ -12923,6 +12957,8 @@ std::vector<CoordinateOperationNNPtr> CoordinateOperationFactory::Private:: const crs::CRSNNPtr &targetCRS, // vertical CRS Private::Context &context) { + ENTER_FUNCTION(); + std::vector<CoordinateOperationNNPtr> res; struct AntiRecursionGuard { @@ -12939,22 +12975,14 @@ std::vector<CoordinateOperationNNPtr> CoordinateOperationFactory::Private:: }; AntiRecursionGuard guard(context); - for (int i = 0; i < 2; i++) { - - // Generally EPSG has operations from GeogCrs to VertCRS - auto ops = - i == 0 ? findOpsInRegistryDirectTo(targetCRS, context.context) - : findOpsInRegistryDirectFrom(targetCRS, context.context); + // Generally EPSG has operations from GeogCrs to VertCRS + auto ops = findOpsInRegistryDirectTo(targetCRS, context); - for (const auto &op : ops) { - const auto tmpCRS = i == 0 ? op->sourceCRS() : op->targetCRS(); - if (tmpCRS && - dynamic_cast<const crs::GeographicCRS *>(tmpCRS.get())) { - res.emplace_back(i == 0 ? op : op->inverse()); - } + for (const auto &op : ops) { + const auto tmpCRS = op->sourceCRS(); + if (tmpCRS && dynamic_cast<const crs::GeographicCRS *>(tmpCRS.get())) { + res.emplace_back(op); } - if (!res.empty()) - break; } return res; @@ -12995,7 +13023,7 @@ void CoordinateOperationFactory::Private:: geogSrcIn->datum()) { const auto &authFactory = context.context->getAuthorityFactory(); const auto candidatesSrcGeod(findCandidateGeodCRSForDatum( - authFactory, geogSrcIn->datum().get())); + authFactory, geogSrcIn, geogSrcIn->datum().get())); for (const auto &candidate : candidatesSrcGeod) { auto geogCandidate = util::nn_dynamic_pointer_cast<crs::GeographicCRS>( @@ -13003,12 +13031,7 @@ void CoordinateOperationFactory::Private:: if (geogCandidate && geogCandidate->coordinateSystem()->axisList().size() == 2) { res = findOpsInRegistryDirect(NN_NO_CHECK(geogCandidate), - targetCRSIn, context.context); - if (res.empty()) { - res = applyInverse(findOpsInRegistryDirect( - targetCRSIn, NN_NO_CHECK(geogCandidate), - context.context)); - } + targetCRSIn, context); break; } } @@ -13047,6 +13070,8 @@ void CoordinateOperationFactory::Private::createOperationsGeodToGeod( const crs::GeodeticCRS *geodDst, std::vector<CoordinateOperationNNPtr> &res) { + ENTER_FUNCTION(); + if (geodSrc->ellipsoid()->celestialBody() != geodDst->ellipsoid()->celestialBody()) { throw util::UnsupportedOperationException( @@ -13120,6 +13145,8 @@ void CoordinateOperationFactory::Private::createOperationsDerivedTo( Private::Context &context, const crs::DerivedCRS *derivedSrc, std::vector<CoordinateOperationNNPtr> &res) { + ENTER_FUNCTION(); + auto opFirst = derivedSrc->derivingConversion()->inverse(); // Small optimization if the targetCRS is the baseCRS of the source // derivedCRS. @@ -13147,6 +13174,8 @@ void CoordinateOperationFactory::Private::createOperationsBoundToGeog( const crs::GeographicCRS *geogDst, std::vector<CoordinateOperationNNPtr> &res) { + ENTER_FUNCTION(); + const auto &hubSrc = boundSrc->hubCRS(); auto hubSrcGeog = dynamic_cast<const crs::GeographicCRS *>(hubSrc.get()); auto geogCRSOfBaseOfBoundSrc = boundSrc->baseCRS()->extractGeographicCRS(); @@ -13339,6 +13368,8 @@ void CoordinateOperationFactory::Private::createOperationsBoundToVert( const crs::VerticalCRS *vertDst, std::vector<CoordinateOperationNNPtr> &res) { + ENTER_FUNCTION(); + auto baseSrcVert = dynamic_cast<const crs::VerticalCRS *>(boundSrc->baseCRS().get()); const auto &hubSrc = boundSrc->hubCRS(); @@ -13361,6 +13392,8 @@ void CoordinateOperationFactory::Private::createOperationsVertToVert( const crs::VerticalCRS *vertDst, std::vector<CoordinateOperationNNPtr> &res) { + ENTER_FUNCTION(); + const auto &srcDatum = vertSrc->datum(); const auto &dstDatum = vertDst->datum(); const bool equivalentVDatum = @@ -13415,6 +13448,8 @@ void CoordinateOperationFactory::Private::createOperationsVertToGeog( const crs::GeographicCRS *geogDst, std::vector<CoordinateOperationNNPtr> &res) { + ENTER_FUNCTION(); + if (vertSrc->identifiers().empty()) { const auto &vertSrcName = vertSrc->nameStr(); const auto &authFactory = context.context->getAuthorityFactory(); @@ -13466,6 +13501,8 @@ void CoordinateOperationFactory::Private::createOperationsBoundToBound( Private::Context &context, const crs::BoundCRS *boundSrc, const crs::BoundCRS *boundDst, std::vector<CoordinateOperationNNPtr> &res) { + ENTER_FUNCTION(); + const auto &hubSrc = boundSrc->hubCRS(); auto hubSrcGeog = dynamic_cast<const crs::GeographicCRS *>(hubSrc.get()); const auto &hubDst = boundDst->hubCRS(); @@ -13672,6 +13709,8 @@ void CoordinateOperationFactory::Private::createOperationsCompoundToGeog( const crs::GeographicCRS *geogDst, std::vector<CoordinateOperationNNPtr> &res) { + ENTER_FUNCTION(); + const auto &authFactory = context.context->getAuthorityFactory(); const auto &componentsSrc = compoundSrc->componentReferenceSystems(); if (!componentsSrc.empty()) { @@ -13783,9 +13822,17 @@ void CoordinateOperationFactory::Private::createOperationsCompoundToGeog( cacheHorizToInterpAndInterpToTarget; for (const auto &verticalTransform : verticalTransforms) { +#ifdef TRACE_CREATE_OPERATIONS + ENTER_BLOCK("Considering vertical transform " + + objectAsStr(verticalTransform.get())); +#endif crs::GeographicCRSPtr interpolationGeogCRS = getInterpolationGeogCRS(verticalTransform, dbContext); if (interpolationGeogCRS) { +#ifdef TRACE_CREATE_OPERATIONS + logTrace("Using " + objectAsStr(interpolationGeogCRS.get()) + + " as interpolation CRS"); +#endif std::vector<CoordinateOperationNNPtr> srcToInterpOps; std::vector<CoordinateOperationNNPtr> interpToTargetOps; @@ -13798,6 +13845,11 @@ void CoordinateOperationFactory::Private::createOperationsCompoundToGeog( if (!key.empty()) { auto iter = cacheHorizToInterpAndInterpToTarget.find(key); if (iter == cacheHorizToInterpAndInterpToTarget.end()) { +#ifdef TRACE_CREATE_OPERATIONS + ENTER_BLOCK("looking for horizontal transformation " + "from source to interpCRS and interpCRS to " + "target"); +#endif srcToInterpOps = createOperations( componentsSrc[0], NN_NO_CHECK(interpolationGeogCRS), context); @@ -13812,6 +13864,11 @@ void CoordinateOperationFactory::Private::createOperationsCompoundToGeog( interpToTargetOps = iter->second.second; } } else { +#ifdef TRACE_CREATE_OPERATIONS + ENTER_BLOCK("looking for horizontal transformation " + "from source to interpCRS and interpCRS to " + "target"); +#endif srcToInterpOps = createOperations( componentsSrc[0], NN_NO_CHECK(interpolationGeogCRS), context); @@ -13821,6 +13878,9 @@ void CoordinateOperationFactory::Private::createOperationsCompoundToGeog( context); } +#ifdef TRACE_CREATE_OPERATIONS + ENTER_BLOCK("creating HorizVerticalHorizPROJBased operations"); +#endif for (const auto &srcToInterp : srcToInterpOps) { for (const auto &interpToTarget : interpToTargetOps) { @@ -14215,6 +14275,9 @@ CoordinateOperationFactory::createOperations( const crs::CRSNNPtr &sourceCRS, const crs::CRSNNPtr &targetCRS, const CoordinateOperationContextNNPtr &context) const { +#ifdef TRACE_CREATE_OPERATIONS + ENTER_FUNCTION(); +#endif // Look if we are called on CRS that have a link to a 'canonical' // BoundCRS // If so, use that one as input |
