diff options
| author | Even Rouault <even.rouault@spatialys.com> | 2019-10-30 23:44:22 +0100 |
|---|---|---|
| committer | Even Rouault <even.rouault@spatialys.com> | 2019-10-30 23:44:22 +0100 |
| commit | 00608cc1c892a0d0522ffd08127a4494d4844e19 (patch) | |
| tree | af319bd888b5ccc8a46d361222a14eb3b20c3247 /src | |
| parent | 3655cfa7e96a753dca2425652344698d5d8e31e2 (diff) | |
| download | PROJ-00608cc1c892a0d0522ffd08127a4494d4844e19.tar.gz PROJ-00608cc1c892a0d0522ffd08127a4494d4844e19.zip | |
createOperations(): try to recover extent of CRS from the database when they are missing, especially for compound CRS. Helps having shorter/more relevant results
Diffstat (limited to 'src')
| -rw-r--r-- | src/iso19111/coordinateoperation.cpp | 163 | ||||
| -rw-r--r-- | src/iso19111/crs.cpp | 3 |
2 files changed, 133 insertions, 33 deletions
diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp index 6f99cd0c..9796221d 100644 --- a/src/iso19111/coordinateoperation.cpp +++ b/src/iso19111/coordinateoperation.cpp @@ -464,6 +464,31 @@ static const metadata::ExtentPtr &getExtent(const crs::CRSNNPtr &crs) { return nullExtent; } +static const metadata::ExtentPtr +getExtentPossiblySynthetized(const crs::CRSNNPtr &crs, bool &approxOut) { + const auto &rawExtent(getExtent(crs)); + approxOut = false; + if (rawExtent) + return rawExtent; + const auto compoundCRS = dynamic_cast<const crs::CompoundCRS *>(crs.get()); + if (compoundCRS) { + // For a compoundCRS, take the intersection of the extent of its + // components. + const auto &components = compoundCRS->componentReferenceSystems(); + metadata::ExtentPtr extent; + approxOut = true; + for (const auto &component : components) { + const auto &componentExtent(getExtent(component)); + if (extent && componentExtent) + extent = extent->intersection(NN_NO_CHECK(componentExtent)); + else if (componentExtent) + extent = componentExtent; + } + return extent; + } + return rawExtent; +} + // --------------------------------------------------------------------------- static metadata::ExtentPtr @@ -14033,57 +14058,129 @@ void CoordinateOperationFactory::Private::createOperationsBoundToCompound( static crs::CRSNNPtr getResolvedCRS(const crs::CRSNNPtr &crs, - const CoordinateOperationContextNNPtr &context) { + const CoordinateOperationContextNNPtr &context, + metadata::ExtentPtr &extentOut) { const auto &authFactory = context->getAuthorityFactory(); + const auto &ids = crs->identifiers(); + const auto &name = crs->nameStr(); + + bool approxExtent; + extentOut = getExtentPossiblySynthetized(crs, approxExtent); + + // We try to "identify" the provided CRS with the ones of the database, + // but in a more restricted way that what identify() does. + // If we get a match from id in priority, and from name as a fallback, and + // that they are equivalent to the input CRS, then use the identified CRS. + // Even if they aren't equivalent, we update extentOut with the one of the + // identified CRS if our input one is absent/not reliable. + + const auto tryToIdentifyByName = [&crs, &name, &authFactory, approxExtent, + &extentOut]( + io::AuthorityFactory::ObjectType objectType) { + if (name != "unknown" && name != "unnamed") { + auto matches = authFactory->createObjectsFromName( + name, {objectType}, false, 2); + if (matches.size() == 1) { + const auto match = + util::nn_static_pointer_cast<crs::CRS>(matches.front()); + if (approxExtent || !extentOut) { + extentOut = getExtent(match); + } + if (match->isEquivalentTo( + crs.get(), util::IComparable::Criterion::EQUIVALENT)) { + return match; + } + } + } + return crs; + }; + + auto geogCRS = dynamic_cast<crs::GeographicCRS *>(crs.get()); + if (geogCRS && authFactory) { + if (!ids.empty()) { + const auto tmpAuthFactory = io::AuthorityFactory::create( + authFactory->databaseContext(), *ids.front()->codeSpace()); + try { + auto resolvedCrs( + tmpAuthFactory->createGeographicCRS(ids.front()->code())); + if (approxExtent || !extentOut) { + extentOut = getExtent(resolvedCrs); + } + if (resolvedCrs->isEquivalentTo( + crs.get(), util::IComparable::Criterion::EQUIVALENT)) { + return util::nn_static_pointer_cast<crs::CRS>(resolvedCrs); + } + } catch (const std::exception &) { + } + } else { + return tryToIdentifyByName( + geogCRS->coordinateSystem()->axisList().size() == 2 + ? io::AuthorityFactory::ObjectType::GEOGRAPHIC_2D_CRS + : io::AuthorityFactory::ObjectType::GEOGRAPHIC_3D_CRS); + } + } auto projectedCrs = dynamic_cast<crs::ProjectedCRS *>(crs.get()); if (projectedCrs && authFactory) { - const auto &ids = projectedCrs->identifiers(); - if (!ids.empty() && projectedCrs->baseCRS()->identifiers().empty()) { + if (!ids.empty()) { const auto tmpAuthFactory = io::AuthorityFactory::create( authFactory->databaseContext(), *ids.front()->codeSpace()); try { auto resolvedCrs( tmpAuthFactory->createProjectedCRS(ids.front()->code())); + if (approxExtent || !extentOut) { + extentOut = getExtent(resolvedCrs); + } if (resolvedCrs->isEquivalentTo( crs.get(), util::IComparable::Criterion::EQUIVALENT)) { return util::nn_static_pointer_cast<crs::CRS>(resolvedCrs); } } catch (const std::exception &) { } + } else { + return tryToIdentifyByName( + io::AuthorityFactory::ObjectType::PROJECTED_CRS); } } auto compoundCrs = dynamic_cast<crs::CompoundCRS *>(crs.get()); - // If we get a CompoundCRS that has an EPSG code, but whose component CRS - // lack one, typically from WKT2, this might be an issue to get proper - // results in createOperations(), so import the CompoundCRS from the - // registry, and if equivalent to the original one, then use the version - // from the registry. if (compoundCrs && authFactory) { - const auto &ids = compoundCrs->identifiers(); if (!ids.empty()) { - const auto &components = compoundCrs->componentReferenceSystems(); - bool hasMissingId = false; - for (const auto &comp : components) { - if (comp->identifiers().empty()) { - hasMissingId = true; - break; + const auto tmpAuthFactory = io::AuthorityFactory::create( + authFactory->databaseContext(), *ids.front()->codeSpace()); + try { + auto resolvedCrs( + tmpAuthFactory->createCompoundCRS(ids.front()->code())); + if (approxExtent || !extentOut) { + extentOut = getExtent(resolvedCrs); + } + if (resolvedCrs->isEquivalentTo( + crs.get(), util::IComparable::Criterion::EQUIVALENT)) { + return util::nn_static_pointer_cast<crs::CRS>(resolvedCrs); } + } catch (const std::exception &) { } - if (hasMissingId) { - const auto tmpAuthFactory = io::AuthorityFactory::create( - authFactory->databaseContext(), *ids.front()->codeSpace()); - try { - auto resolvedCrs( - tmpAuthFactory->createCompoundCRS(ids.front()->code())); - if (resolvedCrs->isEquivalentTo( - crs.get(), - util::IComparable::Criterion::EQUIVALENT)) { - return util::nn_static_pointer_cast<crs::CRS>( - resolvedCrs); - } - } catch (const std::exception &) { + } else { + auto outCrs = tryToIdentifyByName( + io::AuthorityFactory::ObjectType::COMPOUND_CRS); + if (outCrs.get() != crs.get()) { + return outCrs; + } + if (approxExtent || !extentOut) { + // If we still did not get a reliable extent, then try to + // resolve the components of the compoundCRS, and take the + // intersection of their extent. + extentOut = metadata::ExtentPtr(); + const auto &components = + compoundCrs->componentReferenceSystems(); + for (const auto &component : components) { + metadata::ExtentPtr componentExtent; + getResolvedCRS(component, context, componentExtent); + if (extentOut && componentExtent) + extentOut = extentOut->intersection( + NN_NO_CHECK(componentExtent)); + else if (componentExtent) + extentOut = componentExtent; } } } @@ -14126,10 +14223,12 @@ CoordinateOperationFactory::createOperations( auto l_sourceCRS = srcBoundCRS ? NN_NO_CHECK(srcBoundCRS) : sourceCRS; auto l_targetCRS = targetBoundCRS ? NN_NO_CHECK(targetBoundCRS) : targetCRS; - auto l_resolvedSourceCRS = getResolvedCRS(l_sourceCRS, context); - auto l_resolvedTargetCRS = getResolvedCRS(l_targetCRS, context); - auto sourceCRSExtent(getExtent(l_resolvedSourceCRS)); - auto targetCRSExtent(getExtent(l_resolvedTargetCRS)); + metadata::ExtentPtr sourceCRSExtent; + auto l_resolvedSourceCRS = + getResolvedCRS(l_sourceCRS, context, sourceCRSExtent); + metadata::ExtentPtr targetCRSExtent; + auto l_resolvedTargetCRS = + getResolvedCRS(l_targetCRS, context, targetCRSExtent); Private::Context contextPrivate(sourceCRSExtent, targetCRSExtent, context); if (context->getSourceAndTargetCRSExtentUse() == diff --git a/src/iso19111/crs.cpp b/src/iso19111/crs.cpp index f16ed7cf..26725e24 100644 --- a/src/iso19111/crs.cpp +++ b/src/iso19111/crs.cpp @@ -993,7 +993,8 @@ bool SingleCRS::baseIsEquivalentTo( // TODO test DatumEnsemble return d->coordinateSystem->_isEquivalentTo( - otherSingleCRS->d->coordinateSystem.get(), criterion); + otherSingleCRS->d->coordinateSystem.get(), criterion) && + getExtensionProj4() == otherSingleCRS->getExtensionProj4(); } // --------------------------------------------------------------------------- |
