diff --git a/src/iso19111/crs.cpp b/src/iso19111/crs.cpp index fc42bc29ab..7af6194125 100644 --- a/src/iso19111/crs.cpp +++ b/src/iso19111/crs.cpp @@ -636,16 +636,18 @@ CRSNNPtr CRS::createBoundCRSToWGS84IfPossible( auto geogCRS = extractGeographicCRS(); auto hubCRS = util::nn_static_pointer_cast(GeographicCRS::EPSG_4326); if (geodCRS && !geogCRS) { - if (geodCRS->_isEquivalentTo(GeographicCRS::EPSG_4978.get(), + if (geodCRS->datumNonNull(dbContext)->nameStr() != "unknown" && + geodCRS->_isEquivalentTo(GeographicCRS::EPSG_4978.get(), util::IComparable::Criterion::EQUIVALENT, dbContext)) { return thisAsCRS; } hubCRS = util::nn_static_pointer_cast(GeodeticCRS::EPSG_4978); } else if (!geogCRS || - geogCRS->_isEquivalentTo( - GeographicCRS::EPSG_4326.get(), - util::IComparable::Criterion::EQUIVALENT, dbContext)) { + (geogCRS->datumNonNull(dbContext)->nameStr() != "unknown" && + geogCRS->_isEquivalentTo( + GeographicCRS::EPSG_4326.get(), + util::IComparable::Criterion::EQUIVALENT, dbContext))) { return thisAsCRS; } else { geodCRS = geogCRS; @@ -2432,7 +2434,7 @@ void GeodeticCRS::addDatumInfoToPROJString( const auto &nadgrids = formatter->getHDatumExtension(); const auto l_datum = datumNonNull(formatter->databaseContext()); if (formatter->getCRSExport() && TOWGS84Params.empty() && - nadgrids.empty()) { + nadgrids.empty() && l_datum->nameStr() != "unknown") { if (l_datum->_isEquivalentTo( datum::GeodeticReferenceFrame::EPSG_6326.get(), util::IComparable::Criterion::EQUIVALENT)) { @@ -4846,22 +4848,28 @@ ProjectedCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { const auto addCRS = [&](const ProjectedCRSNNPtr &crs, const bool eqName, bool hasNonMatchingId) { const auto &l_unit = cs->axisList()[0]->unit(); - if (_isEquivalentTo(crs.get(), - util::IComparable::Criterion:: - EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS, - dbContext) || - (l_implicitCS && - l_unit._isEquivalentTo( - crs->coordinateSystem()->axisList()[0]->unit(), - util::IComparable::Criterion::EQUIVALENT) && - l_baseCRS->_isEquivalentTo( - crs->baseCRS().get(), - util::IComparable::Criterion:: - EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS, - dbContext) && - derivingConversionRef()->_isEquivalentTo( - crs->derivingConversionRef().get(), - util::IComparable::Criterion::EQUIVALENT, dbContext))) { + if ((_isEquivalentTo(crs.get(), + util::IComparable::Criterion:: + EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS, + dbContext) || + (l_implicitCS && + l_unit._isEquivalentTo( + crs->coordinateSystem()->axisList()[0]->unit(), + util::IComparable::Criterion::EQUIVALENT) && + l_baseCRS->_isEquivalentTo( + crs->baseCRS().get(), + util::IComparable::Criterion:: + EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS, + dbContext) && + derivingConversionRef()->_isEquivalentTo( + crs->derivingConversionRef().get(), + util::IComparable::Criterion::EQUIVALENT, dbContext))) && + !((baseCRS()->datumNonNull(dbContext)->nameStr() == "unknown" && + crs->baseCRS()->datumNonNull(dbContext)->nameStr() != + "unknown") || + (baseCRS()->datumNonNull(dbContext)->nameStr() != "unknown" && + crs->baseCRS()->datumNonNull(dbContext)->nameStr() == + "unknown"))) { if (crs->nameStr() == thisName) { res.clear(); res.emplace_back(crs, hasNonMatchingId ? 70 : 100); diff --git a/src/iso19111/datum.cpp b/src/iso19111/datum.cpp index 777addd22c..2957b99ace 100644 --- a/src/iso19111/datum.cpp +++ b/src/iso19111/datum.cpp @@ -1547,6 +1547,9 @@ bool GeodeticReferenceFrame::_isEquivalentTo( bool GeodeticReferenceFrame::hasEquivalentNameToUsingAlias( const IdentifiedObject *other, const io::DatabaseContextPtr &dbContext) const { + if (nameStr() == "unknown" || other->nameStr() == "unknown") { + return true; + } if (dbContext) { if (!identifiers().empty()) { const auto &id = identifiers().front(); diff --git a/src/iso19111/operation/coordinateoperationfactory.cpp b/src/iso19111/operation/coordinateoperationfactory.cpp index 2ee18660f9..85e9b11b15 100644 --- a/src/iso19111/operation/coordinateoperationfactory.cpp +++ b/src/iso19111/operation/coordinateoperationfactory.cpp @@ -1939,6 +1939,20 @@ findCandidateGeodCRSForDatum(const io::AuthorityFactoryPtr &authFactory, //! @cond Doxygen_Suppress +static bool +isSameGeodeticDatum(const datum::GeodeticReferenceFrameNNPtr &datum1, + const datum::GeodeticReferenceFrameNNPtr &datum2, + const io::DatabaseContextPtr &dbContext) { + if (datum1->nameStr() == "unknown" && datum2->nameStr() != "unknown") + return false; + if (datum2->nameStr() == "unknown" && datum1->nameStr() != "unknown") + return false; + return datum1->_isEquivalentTo( + datum2.get(), util::IComparable::Criterion::EQUIVALENT, dbContext); +} + +// --------------------------------------------------------------------------- + // Look in the authority registry for operations from sourceCRS to targetCRS // using an intermediate pivot std::vector @@ -1978,10 +1992,7 @@ CoordinateOperationFactory::Private::findsOpsInRegistryWithIntermediate( candidateSrcGeod->datumNonNull(dbContext); const auto dstDatum = geodDst->datumNonNull(dbContext); const bool sameGeodeticDatum = - srcDatum->_isEquivalentTo( - dstDatum.get(), - util::IComparable::Criterion::EQUIVALENT, - dbContext); + isSameGeodeticDatum(srcDatum, dstDatum, dbContext); if (sameGeodeticDatum) { continue; } @@ -2133,9 +2144,8 @@ createBallparkGeographicOffset(const crs::CRSNNPtr &sourceCRS, dynamic_cast(targetCRS.get()); const bool isSameDatum = geogSrc && geogDst && - geogSrc->datumNonNull(dbContext)->_isEquivalentTo( - geogDst->datumNonNull(dbContext).get(), - util::IComparable::Criterion::EQUIVALENT, dbContext); + isSameGeodeticDatum(geogSrc->datumNonNull(dbContext), + geogDst->datumNonNull(dbContext), dbContext); auto name = buildOpName(isSameDatum ? NULL_GEOGRAPHIC_OFFSET : BALLPARK_GEOGRAPHIC_OFFSET, @@ -2706,9 +2716,9 @@ CoordinateOperationFactory::Private::createOperationsGeogToGeog( const auto dbContext = authFactory ? authFactory->databaseContext().as_nullable() : nullptr; - const bool sameDatum = geogSrc->datumNonNull(dbContext)->_isEquivalentTo( - geogDst->datumNonNull(dbContext).get(), - util::IComparable::Criterion::EQUIVALENT, dbContext); + const bool sameDatum = + isSameGeodeticDatum(geogSrc->datumNonNull(dbContext), + geogDst->datumNonNull(dbContext), dbContext); // Do the CRS differ by their axis order ? bool axisReversal2D = false; @@ -3610,9 +3620,8 @@ bool CoordinateOperationFactory::Private::createOperationsFromDatabase( const auto srcDatum = geodSrc->datumNonNull(dbContext); const auto dstDatum = geodDst->datumNonNull(dbContext); - sameGeodeticDatum = srcDatum->_isEquivalentTo( - dstDatum.get(), util::IComparable::Criterion::EQUIVALENT, - dbContext); + + sameGeodeticDatum = isSameGeodeticDatum(srcDatum, dstDatum, dbContext); if (res.empty() && !sameGeodeticDatum && !context.inCreateOperationsWithDatumPivotAntiRecursion) { diff --git a/test/unit/test_datum.cpp b/test/unit/test_datum.cpp index 423438cca1..df0596af92 100644 --- a/test/unit/test_datum.cpp +++ b/test/unit/test_datum.cpp @@ -289,6 +289,28 @@ TEST(datum, datum_with_ANCHOREPOCH) { // --------------------------------------------------------------------------- +TEST(datum, unknown_datum) { + auto datum = GeodeticReferenceFrame::create( + PropertyMap().set(IdentifiedObject::NAME_KEY, "my_datum"), + Ellipsoid::GRS1980, optional(), optional(), + PrimeMeridian::GREENWICH); + auto unknown_datum = GeodeticReferenceFrame::create( + PropertyMap().set(IdentifiedObject::NAME_KEY, "unknown"), + Ellipsoid::GRS1980, optional(), optional(), + PrimeMeridian::GREENWICH); + + EXPECT_FALSE(datum->isEquivalentTo(unknown_datum.get(), + IComparable::Criterion::STRICT)); + EXPECT_TRUE(datum->isEquivalentTo(unknown_datum.get(), + IComparable::Criterion::EQUIVALENT)); + EXPECT_FALSE(unknown_datum->isEquivalentTo(datum.get(), + IComparable::Criterion::STRICT)); + EXPECT_TRUE(unknown_datum->isEquivalentTo( + datum.get(), IComparable::Criterion::EQUIVALENT)); +} + +// --------------------------------------------------------------------------- + TEST(datum, dynamic_geodetic_reference_frame) { auto drf = DynamicGeodeticReferenceFrame::create( PropertyMap().set(IdentifiedObject::NAME_KEY, "test"), Ellipsoid::WGS84,