diff options
| author | Even Rouault <even.rouault@spatialys.com> | 2019-12-16 15:23:22 +0100 |
|---|---|---|
| committer | Even Rouault <even.rouault@spatialys.com> | 2019-12-16 17:50:39 +0100 |
| commit | bd9ecbacf575a1926fb8e223c4add1a4cc45d7f3 (patch) | |
| tree | 770cc59bf111f8b427d9bc14ea7548ff3edbc9b3 /src/iso19111 | |
| parent | a68c146d7f3c1efb0f42b46c708a0a195e51a2ff (diff) | |
| download | PROJ-bd9ecbacf575a1926fb8e223c4add1a4cc45d7f3.tar.gz PROJ-bd9ecbacf575a1926fb8e223c4add1a4cc45d7f3.zip | |
identify(): take into datum name aliases (fixes #1800)
Diffstat (limited to 'src/iso19111')
| -rw-r--r-- | src/iso19111/c_api.cpp | 57 | ||||
| -rw-r--r-- | src/iso19111/common.cpp | 33 | ||||
| -rw-r--r-- | src/iso19111/coordinateoperation.cpp | 91 | ||||
| -rw-r--r-- | src/iso19111/coordinatesystem.cpp | 15 | ||||
| -rw-r--r-- | src/iso19111/crs.cpp | 259 | ||||
| -rw-r--r-- | src/iso19111/datum.cpp | 115 | ||||
| -rw-r--r-- | src/iso19111/factory.cpp | 62 | ||||
| -rw-r--r-- | src/iso19111/metadata.cpp | 21 | ||||
| -rw-r--r-- | src/iso19111/util.cpp | 8 |
9 files changed, 435 insertions, 226 deletions
diff --git a/src/iso19111/c_api.cpp b/src/iso19111/c_api.cpp index 5e2ac522..5a5e97f6 100644 --- a/src/iso19111/c_api.cpp +++ b/src/iso19111/c_api.cpp @@ -1142,15 +1142,9 @@ PJ_OBJ_LIST *proj_get_non_deprecated(PJ_CONTEXT *ctx, const PJ *obj) { // --------------------------------------------------------------------------- -/** \brief Return whether two objects are equivalent. - * - * @param obj Object (must not be NULL) - * @param other Other object (must not be NULL) - * @param criterion Comparison criterion - * @return TRUE if they are equivalent - */ -int proj_is_equivalent_to(const PJ *obj, const PJ *other, - PJ_COMPARISON_CRITERION criterion) { +static int proj_is_equivalent_to_internal(PJ_CONTEXT *ctx, const PJ *obj, + const PJ *other, + PJ_COMPARISON_CRITERION criterion) { assert(obj); assert(other); if (!obj->iso_obj) { @@ -1172,7 +1166,50 @@ int proj_is_equivalent_to(const PJ *obj, const PJ *other, return IComparable::Criterion::EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS; })(criterion); - return obj->iso_obj->isEquivalentTo(other->iso_obj.get(), cppCriterion); + int res = obj->iso_obj->isEquivalentTo( + other->iso_obj.get(), cppCriterion, + ctx ? getDBcontextNoException(ctx, "proj_is_equivalent_to_with_ctx") + : nullptr); + if (ctx && ctx->cpp_context) { + ctx->cpp_context->autoCloseDbIfNeeded(); + } + return res; +} + +// --------------------------------------------------------------------------- + +/** \brief Return whether two objects are equivalent. + * + * Use proj_is_equivalent_to_with_ctx() to be able to use database information. + * + * @param obj Object (must not be NULL) + * @param other Other object (must not be NULL) + * @param criterion Comparison criterion + * @return TRUE if they are equivalent + */ +int proj_is_equivalent_to(const PJ *obj, const PJ *other, + PJ_COMPARISON_CRITERION criterion) { + return proj_is_equivalent_to_internal(nullptr, obj, other, criterion); +} + +// --------------------------------------------------------------------------- + +/** \brief Return whether two objects are equivalent + * + * Possibly using database to check for name aliases. + * + * @param ctx PROJ context, or NULL for default context + * @param obj Object (must not be NULL) + * @param other Other object (must not be NULL) + * @param criterion Comparison criterion + * @return TRUE if they are equivalent + * @since 6.3 + */ +int proj_is_equivalent_to_with_ctx(PJ_CONTEXT *ctx, const PJ *obj, + const PJ *other, + PJ_COMPARISON_CRITERION criterion) { + SANITIZE_CTX(ctx); + return proj_is_equivalent_to_internal(ctx, obj, other, criterion); } // --------------------------------------------------------------------------- diff --git a/src/iso19111/common.cpp b/src/iso19111/common.cpp index 97900bda..f2e4de4c 100644 --- a/src/iso19111/common.cpp +++ b/src/iso19111/common.cpp @@ -901,19 +901,19 @@ void IdentifiedObject::formatRemarks(JSONFormatter *formatter) const { // --------------------------------------------------------------------------- bool IdentifiedObject::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherIdObj = dynamic_cast<const IdentifiedObject *>(other); if (!otherIdObj) return false; - return _isEquivalentTo(otherIdObj, criterion); + return _isEquivalentTo(otherIdObj, criterion, dbContext); } // --------------------------------------------------------------------------- -bool IdentifiedObject::_isEquivalentTo(const IdentifiedObject *otherIdObj, - util::IComparable::Criterion criterion) - PROJ_PURE_DEFN { +bool IdentifiedObject::_isEquivalentTo( + const IdentifiedObject *otherIdObj, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) PROJ_PURE_DEFN { if (criterion == util::IComparable::Criterion::STRICT) { if (!ci_equal(nameStr(), otherIdObj->nameStr())) { return false; @@ -922,12 +922,19 @@ bool IdentifiedObject::_isEquivalentTo(const IdentifiedObject *otherIdObj, } else { if (!metadata::Identifier::isEquivalentName( nameStr().c_str(), otherIdObj->nameStr().c_str())) { - return false; + return hasEquivalentNameToUsingAlias(otherIdObj, dbContext); } } return true; } +// --------------------------------------------------------------------------- + +bool IdentifiedObject::hasEquivalentNameToUsingAlias( + const IdentifiedObject *, const io::DatabaseContextPtr &) const { + return false; +} + //! @endcond // --------------------------------------------------------------------------- @@ -1092,8 +1099,8 @@ void ObjectDomain::_exportToJSON(JSONFormatter *formatter) const { //! @cond Doxygen_Suppress bool ObjectDomain::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherDomain = dynamic_cast<const ObjectDomain *>(other); if (!otherDomain) return false; @@ -1106,7 +1113,7 @@ bool ObjectDomain::_isEquivalentTo( return false; return domainOfValidity().get() == nullptr || domainOfValidity()->_isEquivalentTo( - otherDomain->domainOfValidity().get(), criterion); + otherDomain->domainOfValidity().get(), criterion, dbContext); } //! @endcond @@ -1249,14 +1256,14 @@ void ObjectUsage::baseExportToJSON(JSONFormatter *formatter) const { //! @cond Doxygen_Suppress bool ObjectUsage::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherObjUsage = dynamic_cast<const ObjectUsage *>(other); if (!otherObjUsage) return false; // TODO: incomplete - return IdentifiedObject::_isEquivalentTo(other, criterion); + return IdentifiedObject::_isEquivalentTo(other, criterion, dbContext); } //! @endcond diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp index 2c3e38ac..62d72e65 100644 --- a/src/iso19111/coordinateoperation.cpp +++ b/src/iso19111/coordinateoperation.cpp @@ -1068,11 +1068,11 @@ void OperationMethod::_exportToJSON( //! @cond Doxygen_Suppress bool OperationMethod::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherOM = dynamic_cast<const OperationMethod *>(other); if (otherOM == nullptr || - !IdentifiedObject::_isEquivalentTo(other, criterion)) { + !IdentifiedObject::_isEquivalentTo(other, criterion, dbContext)) { return false; } // TODO test formula and formulaCitation @@ -1084,7 +1084,8 @@ bool OperationMethod::_isEquivalentTo( } if (criterion == util::IComparable::Criterion::STRICT) { for (size_t i = 0; i < paramsSize; i++) { - if (!params[i]->_isEquivalentTo(otherParams[i].get(), criterion)) { + if (!params[i]->_isEquivalentTo(otherParams[i].get(), criterion, + dbContext)) { return false; } } @@ -1094,8 +1095,8 @@ bool OperationMethod::_isEquivalentTo( bool found = false; for (size_t j = 0; j < paramsSize; j++) { if (candidateIndices[j] && - params[i]->_isEquivalentTo(otherParams[j].get(), - criterion)) { + params[i]->_isEquivalentTo(otherParams[j].get(), criterion, + dbContext)) { candidateIndices[j] = false; found = true; break; @@ -1341,14 +1342,14 @@ bool OperationParameterValue::convertFromAbridged( //! @cond Doxygen_Suppress bool OperationParameterValue::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherOPV = dynamic_cast<const OperationParameterValue *>(other); if (otherOPV == nullptr) { return false; } - if (!d->parameter->_isEquivalentTo(otherOPV->d->parameter.get(), - criterion)) { + if (!d->parameter->_isEquivalentTo(otherOPV->d->parameter.get(), criterion, + dbContext)) { return false; } if (criterion == util::IComparable::Criterion::STRICT) { @@ -1356,7 +1357,7 @@ bool OperationParameterValue::_isEquivalentTo( otherOPV->d->parameterValue.get(), criterion); } if (d->parameterValue->_isEquivalentTo(otherOPV->d->parameterValue.get(), - criterion)) { + criterion, dbContext)) { return true; } if (d->parameter->getEPSGCode() == @@ -1446,16 +1447,16 @@ OperationParameter::create(const util::PropertyMap &properties) { //! @cond Doxygen_Suppress bool OperationParameter::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherOP = dynamic_cast<const OperationParameter *>(other); if (otherOP == nullptr) { return false; } if (criterion == util::IComparable::Criterion::STRICT) { - return IdentifiedObject::_isEquivalentTo(other, criterion); + return IdentifiedObject::_isEquivalentTo(other, criterion, dbContext); } - if (IdentifiedObject::_isEquivalentTo(other, criterion)) { + if (IdentifiedObject::_isEquivalentTo(other, criterion, dbContext)) { return true; } auto l_epsgCode = getEPSGCode(); @@ -1759,19 +1760,20 @@ static SingleOperationNNPtr createPROJBased( //! @cond Doxygen_Suppress bool SingleOperation::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { - return _isEquivalentTo(other, criterion, false); + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { + return _isEquivalentTo(other, criterion, dbContext, false); } bool SingleOperation::_isEquivalentTo(const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext, bool inOtherDirection) const { auto otherSO = dynamic_cast<const SingleOperation *>(other); if (otherSO == nullptr || (criterion == util::IComparable::Criterion::STRICT && - !ObjectUsage::_isEquivalentTo(other, criterion))) { + !ObjectUsage::_isEquivalentTo(other, criterion, dbContext))) { return false; } @@ -1781,7 +1783,8 @@ bool SingleOperation::_isEquivalentTo(const util::IComparable *other, bool equivalentMethods = (criterion == util::IComparable::Criterion::EQUIVALENT && methodEPSGCode != 0 && methodEPSGCode == otherMethodEPSGCode) || - d->method_->_isEquivalentTo(otherSO->d->method_.get(), criterion); + d->method_->_isEquivalentTo(otherSO->d->method_.get(), criterion, + dbContext); if (!equivalentMethods && criterion == util::IComparable::Criterion::EQUIVALENT) { if ((methodEPSGCode == EPSG_CODE_METHOD_LAMBERT_AZIMUTHAL_EQUAL_AREA && @@ -1854,7 +1857,7 @@ bool SingleOperation::_isEquivalentTo(const util::IComparable *other, EPSG_CODE_METHOD_LAMBERT_CONIC_CONFORMAL_2SP) { // Convert from 2SP to 1SP as the other direction has more // degree of liberties. - return otherSO->_isEquivalentTo(this, criterion); + return otherSO->_isEquivalentTo(this, criterion, dbContext); } else if ((methodEPSGCode == EPSG_CODE_METHOD_MERCATOR_VARIANT_A && otherMethodEPSGCode == EPSG_CODE_METHOD_MERCATOR_VARIANT_B) || @@ -1870,7 +1873,8 @@ bool SingleOperation::_isEquivalentTo(const util::IComparable *other, auto eqConv = conv->convertToOtherMethod(otherMethodEPSGCode); if (eqConv) { - return eqConv->_isEquivalentTo(other, criterion); + return eqConv->_isEquivalentTo(other, criterion, + dbContext); } } } @@ -1888,7 +1892,8 @@ bool SingleOperation::_isEquivalentTo(const util::IComparable *other, return false; } for (size_t i = 0; i < valuesSize; i++) { - if (!values[i]->_isEquivalentTo(otherValues[i].get(), criterion)) { + if (!values[i]->_isEquivalentTo(otherValues[i].get(), criterion, + dbContext)) { return false; } } @@ -1909,7 +1914,8 @@ bool SingleOperation::_isEquivalentTo(const util::IComparable *other, bool sameNameDifferentValue = false; for (size_t j = 0; j < otherValuesSize; j++) { if (candidateIndices[j] && - values[i]->_isEquivalentTo(otherValues[j].get(), criterion)) { + values[i]->_isEquivalentTo(otherValues[j].get(), criterion, + dbContext)) { candidateIndices[j] = false; equivalent = true; break; @@ -1921,7 +1927,8 @@ bool SingleOperation::_isEquivalentTo(const util::IComparable *other, return false; sameNameDifferentValue = opParamvalue->parameter()->_isEquivalentTo( - otherOpParamvalue->parameter().get(), criterion); + otherOpParamvalue->parameter().get(), criterion, + dbContext); if (sameNameDifferentValue) { candidateIndices[j] = false; break; @@ -1949,13 +1956,13 @@ bool SingleOperation::_isEquivalentTo(const util::IComparable *other, ->parameterValue( EPSG_CODE_PARAMETER_LATITUDE_2ND_STD_PARALLEL) .get(), - criterion) && + criterion, dbContext) && value_2nd->_isEquivalentTo( otherSO ->parameterValue( EPSG_CODE_PARAMETER_LATITUDE_1ST_STD_PARALLEL) .get(), - criterion); + criterion, dbContext); } } } @@ -1987,7 +1994,7 @@ bool SingleOperation::_isEquivalentTo(const util::IComparable *other, // In the case the arguments don't perfectly match, try the reverse // check. if (equivalent && foundMissingArgs && !inOtherDirection) { - return otherSO->_isEquivalentTo(this, criterion, true); + return otherSO->_isEquivalentTo(this, criterion, dbContext, true); } // Equivalent formulations of 2SP can have different parameters @@ -2002,8 +2009,8 @@ bool SingleOperation::_isEquivalentTo(const util::IComparable *other, auto otherAs1SP = otherConv->convertToOtherMethod( EPSG_CODE_METHOD_LAMBERT_CONIC_CONFORMAL_1SP); if (thisAs1SP && otherAs1SP) { - equivalent = - thisAs1SP->_isEquivalentTo(otherAs1SP.get(), criterion); + equivalent = thisAs1SP->_isEquivalentTo(otherAs1SP.get(), + criterion, dbContext); } } } @@ -2412,9 +2419,9 @@ void ParameterValue::_exportToWKT(io::WKTFormatter *formatter) const { // --------------------------------------------------------------------------- //! @cond Doxygen_Suppress -bool ParameterValue::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { +bool ParameterValue::_isEquivalentTo(const util::IComparable *other, + util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &) const { auto otherPV = dynamic_cast<const ParameterValue *>(other); if (otherPV == nullptr) { return false; @@ -10186,12 +10193,12 @@ void ConcatenatedOperation::_exportToPROJString( //! @cond Doxygen_Suppress bool ConcatenatedOperation::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherCO = dynamic_cast<const ConcatenatedOperation *>(other); if (otherCO == nullptr || (criterion == util::IComparable::Criterion::STRICT && - !ObjectUsage::_isEquivalentTo(other, criterion))) { + !ObjectUsage::_isEquivalentTo(other, criterion, dbContext))) { return false; } const auto &steps = operations(); @@ -10200,7 +10207,8 @@ bool ConcatenatedOperation::_isEquivalentTo( return false; } for (size_t i = 0; i < steps.size(); i++) { - if (!steps[i]->_isEquivalentTo(otherSteps[i].get(), criterion)) { + if (!steps[i]->_isEquivalentTo(otherSteps[i].get(), criterion, + dbContext)) { return false; } } @@ -14841,14 +14849,15 @@ void InverseCoordinateOperation::_exportToPROJString( // --------------------------------------------------------------------------- bool InverseCoordinateOperation::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherICO = dynamic_cast<const InverseCoordinateOperation *>(other); if (otherICO == nullptr || - !ObjectUsage::_isEquivalentTo(other, criterion)) { + !ObjectUsage::_isEquivalentTo(other, criterion, dbContext)) { return false; } - return inverse()->_isEquivalentTo(otherICO->inverse().get(), criterion); + return inverse()->_isEquivalentTo(otherICO->inverse().get(), criterion, + dbContext); } // --------------------------------------------------------------------------- diff --git a/src/iso19111/coordinatesystem.cpp b/src/iso19111/coordinatesystem.cpp index 6769b486..163f0f43 100644 --- a/src/iso19111/coordinatesystem.cpp +++ b/src/iso19111/coordinatesystem.cpp @@ -429,8 +429,8 @@ void CoordinateSystemAxis::_exportToJSON( //! @cond Doxygen_Suppress bool CoordinateSystemAxis::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherCSA = dynamic_cast<const CoordinateSystemAxis *>(other); if (otherCSA == nullptr) { return false; @@ -441,7 +441,7 @@ bool CoordinateSystemAxis::_isEquivalentTo( return false; } if (criterion == util::IComparable::Criterion::STRICT) { - if (!IdentifiedObject::_isEquivalentTo(other, criterion)) { + if (!IdentifiedObject::_isEquivalentTo(other, criterion, dbContext)) { return false; } if (abbreviation() != otherCSA->abbreviation()) { @@ -599,11 +599,11 @@ void CoordinateSystem::_exportToJSON( //! @cond Doxygen_Suppress bool CoordinateSystem::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherCS = dynamic_cast<const CoordinateSystem *>(other); if (otherCS == nullptr || - !IdentifiedObject::_isEquivalentTo(other, criterion)) { + !IdentifiedObject::_isEquivalentTo(other, criterion, dbContext)) { return false; } const auto &list = axisList(); @@ -615,7 +615,8 @@ bool CoordinateSystem::_isEquivalentTo( return false; } for (size_t i = 0; i < list.size(); i++) { - if (!list[i]->_isEquivalentTo(otherList[i].get(), criterion)) { + if (!list[i]->_isEquivalentTo(otherList[i].get(), criterion, + dbContext)) { return false; } } diff --git a/src/iso19111/crs.cpp b/src/iso19111/crs.cpp index f231d072..cf90c388 100644 --- a/src/iso19111/crs.cpp +++ b/src/iso19111/crs.cpp @@ -391,7 +391,7 @@ CRSNNPtr CRS::createBoundCRSToWGS84IfPossible( if (boundCRS) { if (boundCRS->hubCRS()->_isEquivalentTo( GeographicCRS::EPSG_4326.get(), - util::IComparable::Criterion::EQUIVALENT)) { + util::IComparable::Criterion::EQUIVALENT, dbContext)) { return NN_NO_CHECK(boundCRS); } } @@ -400,16 +400,16 @@ CRSNNPtr CRS::createBoundCRSToWGS84IfPossible( auto geogCRS = extractGeographicCRS(); auto hubCRS = util::nn_static_pointer_cast<CRS>(GeographicCRS::EPSG_4326); if (geodCRS && !geogCRS) { - if (geodCRS->_isEquivalentTo( - GeographicCRS::EPSG_4978.get(), - util::IComparable::Criterion::EQUIVALENT)) { + if (geodCRS->_isEquivalentTo(GeographicCRS::EPSG_4978.get(), + util::IComparable::Criterion::EQUIVALENT, + dbContext)) { return thisAsCRS; } hubCRS = util::nn_static_pointer_cast<CRS>(GeodeticCRS::EPSG_4978); } else if (!geogCRS || geogCRS->_isEquivalentTo( GeographicCRS::EPSG_4326.get(), - util::IComparable::Criterion::EQUIVALENT)) { + util::IComparable::Criterion::EQUIVALENT, dbContext)) { return thisAsCRS; } else { geodCRS = geogCRS; @@ -1022,18 +1022,19 @@ const cs::CoordinateSystemNNPtr &SingleCRS::coordinateSystem() PROJ_PURE_DEFN { // --------------------------------------------------------------------------- bool SingleCRS::baseIsEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherSingleCRS = dynamic_cast<const SingleCRS *>(other); if (otherSingleCRS == nullptr || (criterion == util::IComparable::Criterion::STRICT && - !ObjectUsage::_isEquivalentTo(other, criterion))) { + !ObjectUsage::_isEquivalentTo(other, criterion, dbContext))) { return false; } const auto &thisDatum = d->datum; const auto &otherDatum = otherSingleCRS->d->datum; if (thisDatum) { - if (!thisDatum->_isEquivalentTo(otherDatum.get(), criterion)) { + if (!thisDatum->_isEquivalentTo(otherDatum.get(), criterion, + dbContext)) { return false; } } else { @@ -1044,7 +1045,8 @@ bool SingleCRS::baseIsEquivalentTo( // TODO test DatumEnsemble return d->coordinateSystem->_isEquivalentTo( - otherSingleCRS->d->coordinateSystem.get(), criterion) && + otherSingleCRS->d->coordinateSystem.get(), criterion, + dbContext) && getExtensionProj4() == otherSingleCRS->getExtensionProj4(); } @@ -1579,13 +1581,13 @@ getStandardCriterion(util::IComparable::Criterion criterion) { //! @cond Doxygen_Suppress bool GeodeticCRS::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { const auto standardCriterion = getStandardCriterion(criterion); auto otherGeodCRS = dynamic_cast<const GeodeticCRS *>(other); // TODO test velocityModel return otherGeodCRS != nullptr && - SingleCRS::baseIsEquivalentTo(other, standardCriterion); + SingleCRS::baseIsEquivalentTo(other, standardCriterion, dbContext); } //! @endcond @@ -1686,6 +1688,9 @@ GeodeticCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { std::list<Pair> res; const auto &thisName(nameStr()); + io::DatabaseContextPtr dbContext = + authorityFactory ? authorityFactory->databaseContext().as_nullable() + : nullptr; const bool l_implicitCS = CRS::getPrivate()->implicitCS_; const auto crsCriterion = l_implicitCS @@ -1699,7 +1704,7 @@ GeodeticCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { const bool nameEquivalent = metadata::Identifier::isEquivalentName( thisName.c_str(), crs->nameStr().c_str()); const bool nameEqual = thisName == crs->nameStr(); - const bool isEq = _isEquivalentTo(crs.get(), crsCriterion); + const bool isEq = _isEquivalentTo(crs.get(), crsCriterion, dbContext); if (nameEquivalent && isEq && (!authorityFactory || nameEqual)) { res.emplace_back(util::nn_static_pointer_cast<GeodeticCRS>(crs), nameEqual ? 100 : 90); @@ -1734,13 +1739,14 @@ GeodeticCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { const auto &thisDatum(datum()); auto searchByDatum = [this, &authorityFactory, &res, &thisDatum, - &geodetic_crs_type, crsCriterion]() { + &geodetic_crs_type, crsCriterion, &dbContext]() { for (const auto &id : thisDatum->identifiers()) { try { auto tempRes = authorityFactory->createGeodeticCRSFromDatum( *id->codeSpace(), id->code(), geodetic_crs_type); for (const auto &crs : tempRes) { - if (_isEquivalentTo(crs.get(), crsCriterion)) { + if (_isEquivalentTo(crs.get(), crsCriterion, + dbContext)) { res.emplace_back(crs, 70); } } @@ -1752,7 +1758,7 @@ GeodeticCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { const auto &thisEllipsoid(ellipsoid()); auto searchByEllipsoid = [this, &authorityFactory, &res, &thisDatum, &thisEllipsoid, &geodetic_crs_type, - l_implicitCS]() { + l_implicitCS, &dbContext]() { const auto ellipsoids = thisEllipsoid->identifiers().empty() ? authorityFactory->createEllipsoidFromExisting( @@ -1770,15 +1776,17 @@ GeodeticCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { if (crsDatum && crsDatum->ellipsoid()->_isEquivalentTo( ellps.get(), - util::IComparable::Criterion::EQUIVALENT) && + util::IComparable::Criterion::EQUIVALENT, + dbContext) && crsDatum->primeMeridian()->_isEquivalentTo( thisDatum->primeMeridian().get(), - util::IComparable::Criterion::EQUIVALENT) && + util::IComparable::Criterion::EQUIVALENT, + dbContext) && (!l_implicitCS || coordinateSystem()->_isEquivalentTo( crs->coordinateSystem().get(), - util::IComparable::Criterion:: - EQUIVALENT))) { + util::IComparable::Criterion::EQUIVALENT, + dbContext))) { res.emplace_back(crs, 60); } } @@ -1811,7 +1819,8 @@ GeodeticCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { authorityFactory->databaseContext(), *id->codeSpace()) ->createGeodeticCRS(id->code()); - bool match = _isEquivalentTo(crs.get(), crsCriterion); + bool match = + _isEquivalentTo(crs.get(), crsCriterion, dbContext); res.emplace_back(crs, match ? 100 : 25); return res; } catch (const std::exception &) { @@ -1829,7 +1838,7 @@ GeodeticCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { auto crs = util::nn_dynamic_pointer_cast<GeodeticCRS>(obj); assert(crs); auto crsNN = NN_NO_CHECK(crs); - if (_isEquivalentTo(crs.get(), crsCriterion)) { + if (_isEquivalentTo(crs.get(), crsCriterion, dbContext)) { if (crs->nameStr() == thisName) { res.clear(); res.emplace_back(crsNN, 100); @@ -1859,8 +1868,8 @@ GeodeticCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { const auto &thisCS(coordinateSystem()); // Sort results - res.sort([&thisName, &thisDatum, &thisCS](const Pair &a, - const Pair &b) { + res.sort([&thisName, &thisDatum, &thisCS, &dbContext](const Pair &a, + const Pair &b) { // First consider confidence if (a.second > b.second) { return true; @@ -1884,9 +1893,11 @@ GeodeticCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { const auto &bDatum(b.first->datum()); if (thisDatum && aDatum && bDatum) { const auto thisEquivADatum(thisDatum->_isEquivalentTo( - aDatum.get(), util::IComparable::Criterion::EQUIVALENT)); + aDatum.get(), util::IComparable::Criterion::EQUIVALENT, + dbContext)); const auto thisEquivBDatum(thisDatum->_isEquivalentTo( - bDatum.get(), util::IComparable::Criterion::EQUIVALENT)); + bDatum.get(), util::IComparable::Criterion::EQUIVALENT, + dbContext)); if (thisEquivADatum && !thisEquivBDatum) { return true; @@ -1900,9 +1911,11 @@ GeodeticCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { const auto &aCS(a.first->coordinateSystem()); const auto &bCS(b.first->coordinateSystem()); const auto thisEquivACs(thisCS->_isEquivalentTo( - aCS.get(), util::IComparable::Criterion::EQUIVALENT)); + aCS.get(), util::IComparable::Criterion::EQUIVALENT, + dbContext)); const auto thisEquivBCs(thisCS->_isEquivalentTo( - bCS.get(), util::IComparable::Criterion::EQUIVALENT)); + bCS.get(), util::IComparable::Criterion::EQUIVALENT, + dbContext)); if (thisEquivACs && !thisEquivBCs) { return true; } @@ -2119,14 +2132,14 @@ bool GeographicCRS::is2DPartOf3D(util::nn<const GeographicCRS *> other) //! @cond Doxygen_Suppress bool GeographicCRS::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherGeogCRS = dynamic_cast<const GeographicCRS *>(other); if (otherGeogCRS == nullptr) { return false; } const auto standardCriterion = getStandardCriterion(criterion); - if (GeodeticCRS::_isEquivalentTo(other, standardCriterion)) { + if (GeodeticCRS::_isEquivalentTo(other, standardCriterion, dbContext)) { return true; } if (criterion != @@ -2145,7 +2158,7 @@ bool GeographicCRS::_isEquivalentTo( cs::EllipsoidalCS::AxisOrder::LONG_EAST_LAT_NORTH ? cs::EllipsoidalCS::createLatitudeLongitude(unit) : cs::EllipsoidalCS::createLongitudeLatitude(unit)) - ->GeodeticCRS::_isEquivalentTo(other, standardCriterion); + ->GeodeticCRS::_isEquivalentTo(other, standardCriterion, dbContext); } return false; } @@ -2717,12 +2730,12 @@ VerticalCRS::create(const util::PropertyMap &properties, //! @cond Doxygen_Suppress bool VerticalCRS::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherVertCRS = dynamic_cast<const VerticalCRS *>(other); // TODO test geoidModel and velocityModel return otherVertCRS != nullptr && - SingleCRS::baseIsEquivalentTo(other, criterion); + SingleCRS::baseIsEquivalentTo(other, criterion, dbContext); } //! @endcond @@ -2757,6 +2770,8 @@ VerticalCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { const auto &thisName(nameStr()); if (authorityFactory) { + const io::DatabaseContextNNPtr &dbContext = + authorityFactory->databaseContext(); const bool unsignificantName = thisName.empty() || ci_equal(thisName, "unknown") || @@ -2768,12 +2783,11 @@ VerticalCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { if (hasCodeCompatibleOfAuthorityFactory(id, authorityFactory)) { try { auto crs = io::AuthorityFactory::create( - authorityFactory->databaseContext(), - *id->codeSpace()) + dbContext, *id->codeSpace()) ->createVerticalCRS(id->code()); bool match = _isEquivalentTo( - crs.get(), - util::IComparable::Criterion::EQUIVALENT); + crs.get(), util::IComparable::Criterion::EQUIVALENT, + dbContext); res.emplace_back(crs, match ? 100 : 25); return res; } catch (const std::exception &) { @@ -2791,8 +2805,8 @@ VerticalCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { assert(crs); auto crsNN = NN_NO_CHECK(crs); if (_isEquivalentTo( - crs.get(), - util::IComparable::Criterion::EQUIVALENT)) { + crs.get(), util::IComparable::Criterion::EQUIVALENT, + dbContext)) { if (crs->nameStr() == thisName) { res.clear(); res.emplace_back(crsNN, 100); @@ -2957,19 +2971,20 @@ DerivedCRS::derivingConversionRef() PROJ_PURE_DEFN { // --------------------------------------------------------------------------- -bool DerivedCRS::_isEquivalentTo(const util::IComparable *other, - util::IComparable::Criterion criterion) const { +bool DerivedCRS::_isEquivalentTo( + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherDerivedCRS = dynamic_cast<const DerivedCRS *>(other); const auto standardCriterion = getStandardCriterion(criterion); if (otherDerivedCRS == nullptr || - !SingleCRS::baseIsEquivalentTo(other, standardCriterion)) { + !SingleCRS::baseIsEquivalentTo(other, standardCriterion, dbContext)) { return false; } return d->baseCRS_->_isEquivalentTo(otherDerivedCRS->d->baseCRS_.get(), - criterion) && + criterion, dbContext) && d->derivingConversion_->_isEquivalentTo( - otherDerivedCRS->d->derivingConversion_.get(), - standardCriterion); + otherDerivedCRS->d->derivingConversion_.get(), standardCriterion, + dbContext); } // --------------------------------------------------------------------------- @@ -3402,11 +3417,11 @@ ProjectedCRS::create(const util::PropertyMap &properties, // --------------------------------------------------------------------------- bool ProjectedCRS::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherProjCRS = dynamic_cast<const ProjectedCRS *>(other); return otherProjCRS != nullptr && - DerivedCRS::_isEquivalentTo(other, criterion); + DerivedCRS::_isEquivalentTo(other, criterion, dbContext); } // --------------------------------------------------------------------------- @@ -3580,14 +3595,19 @@ ProjectedCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { const auto &conv = derivingConversionRef(); const auto &cs = coordinateSystem(); + io::DatabaseContextPtr dbContext = + authorityFactory ? authorityFactory->databaseContext().as_nullable() + : nullptr; + if (baseRes.size() == 1 && baseRes.front().second >= 70 && conv->isUTM(zone, north) && cs->_isEquivalentTo( cs::CartesianCS::createEastingNorthing(common::UnitOfMeasure::METRE) - .get())) { + .get(), + util::IComparable::Criterion::EQUIVALENT, dbContext)) { if (baseRes.front().first->_isEquivalentTo( GeographicCRS::EPSG_4326.get(), - util::IComparable::Criterion::EQUIVALENT)) { + util::IComparable::Criterion::EQUIVALENT, dbContext)) { std::string crsName( computeUTMCRSName("WGS 84 / UTM zone ", zone, north)); res.emplace_back( @@ -3601,7 +3621,7 @@ ProjectedCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { north && baseRes.front().first->_isEquivalentTo( GeographicCRS::EPSG_4267.get(), - util::IComparable::Criterion::EQUIVALENT)) { + util::IComparable::Criterion::EQUIVALENT, dbContext)) { std::string crsName( computeUTMCRSName("NAD27 / UTM zone ", zone, north)); res.emplace_back( @@ -3616,7 +3636,7 @@ ProjectedCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { north && baseRes.front().first->_isEquivalentTo( GeographicCRS::EPSG_4269.get(), - util::IComparable::Criterion::EQUIVALENT)) { + util::IComparable::Criterion::EQUIVALENT, dbContext)) { std::string crsName( computeUTMCRSName("NAD83 / UTM zone ", zone, north)); res.emplace_back( @@ -3648,9 +3668,9 @@ ProjectedCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { *id->codeSpace()) ->createProjectedCRS(id->code()); bool match = _isEquivalentTo( - crs.get(), - util::IComparable::Criterion:: - EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS); + crs.get(), util::IComparable::Criterion:: + EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS, + dbContext); res.emplace_back(crs, match ? 100 : 25); return res; } catch (const std::exception &) { @@ -3671,9 +3691,9 @@ ProjectedCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { thisName.c_str(), crs->nameStr().c_str()); foundEquivalentName |= eqName; if (_isEquivalentTo( - crs.get(), - util::IComparable::Criterion:: - EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS)) { + crs.get(), util::IComparable::Criterion:: + EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS, + dbContext)) { if (crs->nameStr() == thisName) { res.clear(); res.emplace_back(crsNN, 100); @@ -3685,10 +3705,12 @@ ProjectedCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { l_baseCRS->_isEquivalentTo( crs->baseCRS().get(), util::IComparable::Criterion:: - EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS) && + EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS, + dbContext) && derivingConversionRef()->_isEquivalentTo( crs->derivingConversionRef().get(), - util::IComparable::Criterion::EQUIVALENT) && + util::IComparable::Criterion::EQUIVALENT, + dbContext) && objects.size() == 1) { res.clear(); res.emplace_back(crsNN, 100); @@ -3755,17 +3777,21 @@ ProjectedCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { if (_isEquivalentTo(crs.get(), util::IComparable::Criterion:: - EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS)) { + EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS, + dbContext)) { res.emplace_back(crs, unsignificantName ? 90 : 70); } else if (ellipsoid->_isEquivalentTo( crs->baseCRS()->ellipsoid().get(), - util::IComparable::Criterion::EQUIVALENT) && + util::IComparable::Criterion::EQUIVALENT, + dbContext) && derivingConversionRef()->_isEquivalentTo( crs->derivingConversionRef().get(), - util::IComparable::Criterion::EQUIVALENT)) { + util::IComparable::Criterion::EQUIVALENT, + dbContext)) { if (coordinateSystem()->_isEquivalentTo( crs->coordinateSystem().get(), - util::IComparable::Criterion::EQUIVALENT)) { + util::IComparable::Criterion::EQUIVALENT, + dbContext)) { res.emplace_back(crs, 70); } else { res.emplace_back(crs, 50); @@ -3995,12 +4021,12 @@ void CompoundCRS::_exportToPROJString( // --------------------------------------------------------------------------- bool CompoundCRS::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherCompoundCRS = dynamic_cast<const CompoundCRS *>(other); if (otherCompoundCRS == nullptr || (criterion == util::IComparable::Criterion::STRICT && - !ObjectUsage::_isEquivalentTo(other, criterion))) { + !ObjectUsage::_isEquivalentTo(other, criterion, dbContext))) { return false; } const auto &components = componentReferenceSystems(); @@ -4009,8 +4035,8 @@ bool CompoundCRS::_isEquivalentTo( return false; } for (size_t i = 0; i < components.size(); i++) { - if (!components[i]->_isEquivalentTo(otherComponents[i].get(), - criterion)) { + if (!components[i]->_isEquivalentTo(otherComponents[i].get(), criterion, + dbContext)) { return false; } } @@ -4050,6 +4076,8 @@ CompoundCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { const auto &thisName(nameStr()); if (authorityFactory) { + const io::DatabaseContextNNPtr &dbContext = + authorityFactory->databaseContext(); const bool unsignificantName = thisName.empty() || ci_equal(thisName, "unknown") || @@ -4063,12 +4091,11 @@ CompoundCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { if (hasCodeCompatibleOfAuthorityFactory(id, authorityFactory)) { try { auto crs = io::AuthorityFactory::create( - authorityFactory->databaseContext(), - *id->codeSpace()) + dbContext, *id->codeSpace()) ->createCompoundCRS(id->code()); bool match = _isEquivalentTo( - crs.get(), - util::IComparable::Criterion::EQUIVALENT); + crs.get(), util::IComparable::Criterion::EQUIVALENT, + dbContext); res.emplace_back(crs, match ? 100 : 25); return res; } catch (const std::exception &) { @@ -4089,8 +4116,8 @@ CompoundCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { thisName.c_str(), crs->nameStr().c_str()); foundEquivalentName |= eqName; if (_isEquivalentTo( - crs.get(), - util::IComparable::Criterion::EQUIVALENT)) { + crs.get(), util::IComparable::Criterion::EQUIVALENT, + dbContext)) { if (crs->nameStr() == thisName) { res.clear(); res.emplace_back(crsNN, 100); @@ -4157,7 +4184,8 @@ CompoundCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { } if (_isEquivalentTo(crs.get(), - util::IComparable::Criterion::EQUIVALENT)) { + util::IComparable::Criterion::EQUIVALENT, + dbContext)) { res.emplace_back(crs, unsignificantName ? 90 : 70); } else { res.emplace_back(crs, 25); @@ -4529,20 +4557,22 @@ void BoundCRS::_exportToPROJString( // --------------------------------------------------------------------------- bool BoundCRS::_isEquivalentTo(const util::IComparable *other, - util::IComparable::Criterion criterion) const { + util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherBoundCRS = dynamic_cast<const BoundCRS *>(other); if (otherBoundCRS == nullptr || (criterion == util::IComparable::Criterion::STRICT && - !ObjectUsage::_isEquivalentTo(other, criterion))) { + !ObjectUsage::_isEquivalentTo(other, criterion, dbContext))) { return false; } const auto standardCriterion = getStandardCriterion(criterion); return d->baseCRS_->_isEquivalentTo(otherBoundCRS->d->baseCRS_.get(), - criterion) && + criterion, dbContext) && d->hubCRS_->_isEquivalentTo(otherBoundCRS->d->hubCRS_.get(), - criterion) && + criterion, dbContext) && d->transformation_->_isEquivalentTo( - otherBoundCRS->d->transformation_.get(), standardCriterion); + otherBoundCRS->d->transformation_.get(), standardCriterion, + dbContext); } // --------------------------------------------------------------------------- @@ -4553,10 +4583,14 @@ std::list<std::pair<CRSNNPtr, int>> BoundCRS::_identify(const io::AuthorityFactoryPtr &authorityFactory) const { typedef std::pair<CRSNNPtr, int> Pair; std::list<Pair> res; + if (!authorityFactory) + return res; std::list<Pair> resMatchOfTransfToWGS84; - if (authorityFactory && - d->hubCRS_->_isEquivalentTo(GeographicCRS::EPSG_4326.get(), - util::IComparable::Criterion::EQUIVALENT)) { + const io::DatabaseContextNNPtr &dbContext = + authorityFactory->databaseContext(); + if (d->hubCRS_->_isEquivalentTo(GeographicCRS::EPSG_4326.get(), + util::IComparable::Criterion::EQUIVALENT, + dbContext)) { auto resTemp = d->baseCRS_->identify(authorityFactory); std::string refTransfPROJString; @@ -4627,7 +4661,8 @@ BoundCRS::_identify(const io::AuthorityFactoryPtr &authorityFactory) const { refTransfPROJString == opTransfPROJString) || opNormalized->_isEquivalentTo( refTransf.get(), - util::IComparable::Criterion::EQUIVALENT)) { + util::IComparable::Criterion::EQUIVALENT, + dbContext)) { resMatchOfTransfToWGS84.emplace_back( create(candidateBaseCRS, d->hubCRS_, NN_NO_CHECK(util::nn_dynamic_pointer_cast< @@ -4807,11 +4842,11 @@ void DerivedGeodeticCRS::_exportToPROJString( // --------------------------------------------------------------------------- bool DerivedGeodeticCRS::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherDerivedCRS = dynamic_cast<const DerivedGeodeticCRS *>(other); return otherDerivedCRS != nullptr && - DerivedCRS::_isEquivalentTo(other, criterion); + DerivedCRS::_isEquivalentTo(other, criterion, dbContext); } // --------------------------------------------------------------------------- @@ -4957,11 +4992,11 @@ void DerivedGeographicCRS::_exportToPROJString( // --------------------------------------------------------------------------- bool DerivedGeographicCRS::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherDerivedCRS = dynamic_cast<const DerivedGeographicCRS *>(other); return otherDerivedCRS != nullptr && - DerivedCRS::_isEquivalentTo(other, criterion); + DerivedCRS::_isEquivalentTo(other, criterion, dbContext); } // --------------------------------------------------------------------------- @@ -5104,11 +5139,11 @@ void DerivedProjectedCRS::_exportToWKT(io::WKTFormatter *formatter) const { // --------------------------------------------------------------------------- bool DerivedProjectedCRS::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherDerivedCRS = dynamic_cast<const DerivedProjectedCRS *>(other); return otherDerivedCRS != nullptr && - DerivedCRS::_isEquivalentTo(other, criterion); + DerivedCRS::_isEquivalentTo(other, criterion, dbContext); } // --------------------------------------------------------------------------- @@ -5234,11 +5269,11 @@ void TemporalCRS::_exportToJSON( // --------------------------------------------------------------------------- bool TemporalCRS::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherTemporalCRS = dynamic_cast<const TemporalCRS *>(other); return otherTemporalCRS != nullptr && - SingleCRS::baseIsEquivalentTo(other, criterion); + SingleCRS::baseIsEquivalentTo(other, criterion, dbContext); } // --------------------------------------------------------------------------- @@ -5372,11 +5407,11 @@ void EngineeringCRS::_exportToJSON( // --------------------------------------------------------------------------- bool EngineeringCRS::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherEngineeringCRS = dynamic_cast<const EngineeringCRS *>(other); return otherEngineeringCRS != nullptr && - SingleCRS::baseIsEquivalentTo(other, criterion); + SingleCRS::baseIsEquivalentTo(other, criterion, dbContext); } // --------------------------------------------------------------------------- @@ -5504,11 +5539,11 @@ void ParametricCRS::_exportToJSON( // --------------------------------------------------------------------------- bool ParametricCRS::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherParametricCRS = dynamic_cast<const ParametricCRS *>(other); return otherParametricCRS != nullptr && - SingleCRS::baseIsEquivalentTo(other, criterion); + SingleCRS::baseIsEquivalentTo(other, criterion, dbContext); } // --------------------------------------------------------------------------- @@ -5609,11 +5644,11 @@ void DerivedVerticalCRS::_exportToPROJString( // --------------------------------------------------------------------------- bool DerivedVerticalCRS::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherDerivedCRS = dynamic_cast<const DerivedVerticalCRS *>(other); return otherDerivedCRS != nullptr && - DerivedCRS::_isEquivalentTo(other, criterion); + DerivedCRS::_isEquivalentTo(other, criterion, dbContext); } // --------------------------------------------------------------------------- @@ -5730,11 +5765,11 @@ void DerivedCRSTemplate<DerivedCRSTraits>::_exportToWKT( template <class DerivedCRSTraits> bool DerivedCRSTemplate<DerivedCRSTraits>::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherDerivedCRS = dynamic_cast<const DerivedCRSTemplate *>(other); return otherDerivedCRS != nullptr && - DerivedCRS::_isEquivalentTo(other, criterion); + DerivedCRS::_isEquivalentTo(other, criterion, dbContext); } //! @endcond diff --git a/src/iso19111/datum.cpp b/src/iso19111/datum.cpp index 321fe93f..255f9822 100644 --- a/src/iso19111/datum.cpp +++ b/src/iso19111/datum.cpp @@ -213,11 +213,13 @@ void Datum::setProperties( // --------------------------------------------------------------------------- -bool Datum::__isEquivalentTo(const util::IComparable *other, - util::IComparable::Criterion criterion) const { +//! @cond Doxygen_Suppress +bool Datum::_isEquivalentTo(const util::IComparable *other, + util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherDatum = dynamic_cast<const Datum *>(other); if (otherDatum == nullptr || - !ObjectUsage::_isEquivalentTo(other, criterion)) { + !ObjectUsage::_isEquivalentTo(other, criterion, dbContext)) { return false; } if (criterion == util::IComparable::Criterion::STRICT) { @@ -248,12 +250,13 @@ bool Datum::__isEquivalentTo(const util::IComparable *other, } if (conventionalRS() && otherDatum->conventionalRS() && conventionalRS()->_isEquivalentTo( - otherDatum->conventionalRS().get(), criterion)) { + otherDatum->conventionalRS().get(), criterion, dbContext)) { return false; } } return true; } +//! @endcond // --------------------------------------------------------------------------- @@ -450,11 +453,11 @@ void PrimeMeridian::_exportToPROJString( //! @cond Doxygen_Suppress bool PrimeMeridian::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherPM = dynamic_cast<const PrimeMeridian *>(other); if (otherPM == nullptr || - !IdentifiedObject::_isEquivalentTo(other, criterion)) { + !IdentifiedObject::_isEquivalentTo(other, criterion, dbContext)) { return false; } // In MapInfo, the Paris prime meridian is returned as 2.3372291666667 @@ -984,11 +987,12 @@ EllipsoidNNPtr Ellipsoid::identify() const { //! @cond Doxygen_Suppress bool Ellipsoid::_isEquivalentTo(const util::IComparable *other, - util::IComparable::Criterion criterion) const { + util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherEllipsoid = dynamic_cast<const Ellipsoid *>(other); if (otherEllipsoid == nullptr || (criterion == util::IComparable::Criterion::STRICT && - !IdentifiedObject::_isEquivalentTo(other, criterion))) { + !IdentifiedObject::_isEquivalentTo(other, criterion, dbContext))) { return false; } @@ -1324,20 +1328,63 @@ void GeodeticReferenceFrame::_exportToJSON( //! @cond Doxygen_Suppress bool GeodeticReferenceFrame::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherGRF = dynamic_cast<const GeodeticReferenceFrame *>(other); - if (otherGRF == nullptr || !Datum::_isEquivalentTo(other, criterion)) { + if (otherGRF == nullptr || + !Datum::_isEquivalentTo(other, criterion, dbContext)) { return false; } return primeMeridian()->_isEquivalentTo(otherGRF->primeMeridian().get(), - criterion) && - ellipsoid()->_isEquivalentTo(otherGRF->ellipsoid().get(), criterion); + criterion, dbContext) && + ellipsoid()->_isEquivalentTo(otherGRF->ellipsoid().get(), criterion, + dbContext); } //! @endcond // --------------------------------------------------------------------------- +bool GeodeticReferenceFrame::hasEquivalentNameToUsingAlias( + const IdentifiedObject *other, + const io::DatabaseContextPtr &dbContext) const { + if (dbContext) { + if (!identifiers().empty()) { + const auto &id = identifiers().front(); + auto aliases = + dbContext->getAliases(*(id->codeSpace()), id->code(), nameStr(), + "geodetic_datum", std::string()); + const char *otherName = other->nameStr().c_str(); + for (const auto &alias : aliases) { + if (metadata::Identifier::isEquivalentName(otherName, + alias.c_str())) { + return true; + } + } + return false; + } else if (!other->identifiers().empty()) { + auto otherGRF = dynamic_cast<const GeodeticReferenceFrame *>(other); + if (otherGRF) { + return otherGRF->hasEquivalentNameToUsingAlias(this, dbContext); + } + return false; + } + + auto aliases = + dbContext->getAliases(std::string(), std::string(), nameStr(), + "geodetic_datum", std::string()); + const char *otherName = other->nameStr().c_str(); + for (const auto &alias : aliases) { + if (metadata::Identifier::isEquivalentName(otherName, + alias.c_str())) { + return true; + } + } + } + return false; +} + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress struct DynamicGeodeticReferenceFrame::Private { common::Measure frameReferenceEpoch{}; @@ -1407,11 +1454,11 @@ DynamicGeodeticReferenceFrame::deformationModelName() const { //! @cond Doxygen_Suppress bool DynamicGeodeticReferenceFrame::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherDGRF = dynamic_cast<const DynamicGeodeticReferenceFrame *>(other); if (otherDGRF == nullptr || - !GeodeticReferenceFrame::_isEquivalentTo(other, criterion)) { + !GeodeticReferenceFrame::_isEquivalentTo(other, criterion, dbContext)) { return false; } return frameReferenceEpoch()._isEquivalentTo( @@ -1842,10 +1889,11 @@ void VerticalReferenceFrame::_exportToJSON( //! @cond Doxygen_Suppress bool VerticalReferenceFrame::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherVRF = dynamic_cast<const VerticalReferenceFrame *>(other); - if (otherVRF == nullptr || !Datum::_isEquivalentTo(other, criterion)) { + if (otherVRF == nullptr || + !Datum::_isEquivalentTo(other, criterion, dbContext)) { return false; } if ((realizationMethod().has_value() ^ @@ -1932,11 +1980,11 @@ DynamicVerticalReferenceFrame::deformationModelName() const { //! @cond Doxygen_Suppress bool DynamicVerticalReferenceFrame::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherDGRF = dynamic_cast<const DynamicVerticalReferenceFrame *>(other); if (otherDGRF == nullptr || - !VerticalReferenceFrame::_isEquivalentTo(other, criterion)) { + !VerticalReferenceFrame::_isEquivalentTo(other, criterion, dbContext)) { return false; } return frameReferenceEpoch()._isEquivalentTo( @@ -2131,10 +2179,11 @@ void TemporalDatum::_exportToJSON( //! @cond Doxygen_Suppress bool TemporalDatum::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherTD = dynamic_cast<const TemporalDatum *>(other); - if (otherTD == nullptr || !Datum::_isEquivalentTo(other, criterion)) { + if (otherTD == nullptr || + !Datum::_isEquivalentTo(other, criterion, dbContext)) { return false; } return temporalOrigin().toString() == @@ -2223,10 +2272,11 @@ void EngineeringDatum::_exportToJSON( //! @cond Doxygen_Suppress bool EngineeringDatum::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherTD = dynamic_cast<const EngineeringDatum *>(other); - if (otherTD == nullptr || !Datum::_isEquivalentTo(other, criterion)) { + if (otherTD == nullptr || + !Datum::_isEquivalentTo(other, criterion, dbContext)) { return false; } return true; @@ -2308,10 +2358,11 @@ void ParametricDatum::_exportToJSON( //! @cond Doxygen_Suppress bool ParametricDatum::_isEquivalentTo( - const util::IComparable *other, - util::IComparable::Criterion criterion) const { + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherTD = dynamic_cast<const ParametricDatum *>(other); - if (otherTD == nullptr || !Datum::_isEquivalentTo(other, criterion)) { + if (otherTD == nullptr || + !Datum::_isEquivalentTo(other, criterion, dbContext)) { return false; } return true; diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index f0ad157e..0bd44308 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -262,6 +262,9 @@ struct DatabaseContext::Private { std::map<std::string, std::vector<std::string>> cacheAllowedAuthorities_{}; + lru11::Cache<std::string, std::list<std::string>> cacheAliasNames_{ + CACHE_SIZE}; + static void insertIntoCache(LRUCacheOfObjects &cache, const std::string &code, const util::BaseObjectPtr &obj); @@ -1100,7 +1103,7 @@ bool DatabaseContext::isKnownName(const std::string &name, /** \brief Gets the alias name from an official name. * - * @param officialName Official name. + * @param officialName Official name. Mandatory * @param tableName Table name/category. Mandatory * @param source Source of the alias. Mandatory * @return Alias name (or empty if not found). @@ -1132,6 +1135,63 @@ DatabaseContext::getAliasFromOfficialName(const std::string &officialName, // --------------------------------------------------------------------------- +/** \brief Gets the alias names for an object. + * + * Either authName + code or officialName must be non empty. + * + * @param authName Authority. + * @param code Code. + * @param officialName Official name. + * @param tableName Table name/category. Mandatory + * @param source Source of the alias. May be empty. + * @return Aliases + */ +std::list<std::string> DatabaseContext::getAliases( + const std::string &authName, const std::string &code, + const std::string &officialName, const std::string &tableName, + const std::string &source) const { + + std::list<std::string> res; + const auto key(authName + code + officialName + tableName + source); + if (d->cacheAliasNames_.tryGet(key, res)) { + return res; + } + + std::string resolvedAuthName(authName); + std::string resolvedCode(code); + if (authName.empty() || code.empty()) { + std::string sql("SELECT auth_name, code FROM \""); + sql += replaceAll(tableName, "\"", "\"\""); + sql += "\" WHERE name = ?"; + if (tableName == "geodetic_crs") { + sql += " AND type = " GEOG_2D_SINGLE_QUOTED; + } + auto resSql = d->run(sql, {officialName}); + if (resSql.empty()) { + d->cacheAliasNames_.insert(key, res); + return res; + } + const auto &row = resSql.front(); + resolvedAuthName = row[0]; + resolvedCode = row[1]; + } + std::string sql("SELECT alt_name FROM alias_name WHERE table_name = ? AND " + "auth_name = ? AND code = ?"); + ListOfParams params{tableName, resolvedAuthName, resolvedCode}; + if (!source.empty()) { + sql += " AND source = ?"; + params.emplace_back(source); + } + auto resSql = d->run(sql, params); + for (const auto &row : resSql) { + res.emplace_back(row[0]); + } + d->cacheAliasNames_.insert(key, res); + return res; +} + +// --------------------------------------------------------------------------- + /** \brief Return the 'text_definition' column of a table for an object * * @param tableName Table name/category. diff --git a/src/iso19111/metadata.cpp b/src/iso19111/metadata.cpp index 41653b32..6266a86d 100644 --- a/src/iso19111/metadata.cpp +++ b/src/iso19111/metadata.cpp @@ -237,7 +237,8 @@ GeographicBoundingBoxNNPtr GeographicBoundingBox::create(double west, //! @cond Doxygen_Suppress bool GeographicBoundingBox::_isEquivalentTo( - const util::IComparable *other, util::IComparable::Criterion) const { + const util::IComparable *other, util::IComparable::Criterion, + const io::DatabaseContextPtr &) const { auto otherExtent = dynamic_cast<const GeographicBoundingBox *>(other); if (!otherExtent) return false; @@ -502,7 +503,8 @@ VerticalExtent::create(double minimumIn, double maximumIn, //! @cond Doxygen_Suppress bool VerticalExtent::_isEquivalentTo(const util::IComparable *other, - util::IComparable::Criterion) const { + util::IComparable::Criterion, + const io::DatabaseContextPtr &) const { auto otherExtent = dynamic_cast<const VerticalExtent *>(other); if (!otherExtent) return false; @@ -587,7 +589,8 @@ TemporalExtentNNPtr TemporalExtent::create(const std::string &start, //! @cond Doxygen_Suppress bool TemporalExtent::_isEquivalentTo(const util::IComparable *other, - util::IComparable::Criterion) const { + util::IComparable::Criterion, + const io::DatabaseContextPtr &) const { auto otherExtent = dynamic_cast<const TemporalExtent *>(other); if (!otherExtent) return false; @@ -734,7 +737,8 @@ Extent::createFromBBOX(double west, double south, double east, double north, //! @cond Doxygen_Suppress bool Extent::_isEquivalentTo(const util::IComparable *other, - util::IComparable::Criterion criterion) const { + util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { auto otherExtent = dynamic_cast<const Extent *>(other); bool ret = (otherExtent && @@ -749,15 +753,18 @@ bool Extent::_isEquivalentTo(const util::IComparable *other, if (ret) { for (size_t i = 0; ret && i < d->geographicElements_.size(); ++i) { ret = d->geographicElements_[i]->_isEquivalentTo( - otherExtent->d->geographicElements_[i].get(), criterion); + otherExtent->d->geographicElements_[i].get(), criterion, + dbContext); } for (size_t i = 0; ret && i < d->verticalElements_.size(); ++i) { ret = d->verticalElements_[i]->_isEquivalentTo( - otherExtent->d->verticalElements_[i].get(), criterion); + otherExtent->d->verticalElements_[i].get(), criterion, + dbContext); } for (size_t i = 0; ret && i < d->temporalElements_.size(); ++i) { ret = d->temporalElements_[i]->_isEquivalentTo( - otherExtent->d->temporalElements_[i].get(), criterion); + otherExtent->d->temporalElements_[i].get(), criterion, + dbContext); } } return ret; diff --git a/src/iso19111/util.cpp b/src/iso19111/util.cpp index 25207d5c..2a6178e2 100644 --- a/src/iso19111/util.cpp +++ b/src/iso19111/util.cpp @@ -687,11 +687,13 @@ IComparable::~IComparable() = default; /** \brief Returns whether an object is equivalent to another one. * @param other other object to compare to * @param criterion comparaison criterion. + * @param dbContext Database context, or nullptr. * @return true if objects are equivalent. */ -bool IComparable::isEquivalentTo(const IComparable *other, - Criterion criterion) const { - return _isEquivalentTo(other, criterion); +bool IComparable::isEquivalentTo( + const IComparable *other, Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { + return _isEquivalentTo(other, criterion, dbContext); } // --------------------------------------------------------------------------- |
