Skip to content

Commit

Permalink
AuthorityFactory::createBetweenGeodeticCRSWithDatumBasedIntermediates…
Browse files Browse the repository at this point in the history
…(): avoid using intermediate CRS of ancient era when dealing with modern source/target CRS
  • Loading branch information
rouault committed Sep 4, 2024
1 parent b6bf25c commit 0100ad0
Showing 1 changed file with 52 additions and 5 deletions.
57 changes: 52 additions & 5 deletions src/iso19111/factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -636,14 +636,11 @@ SQLiteHandleCache::getHandle(const std::string &path, PJ_CONTEXT *ctx) {
// to acquire the mutex in invalidateHandles().
SQLiteHandleCache::get().sMutex_.lock();
},
[]() {
SQLiteHandleCache::get().sMutex_.unlock();
},
[]() { SQLiteHandleCache::get().sMutex_.unlock(); },
[]() {
SQLiteHandleCache::get().sMutex_.unlock();
SQLiteHandleCache::get().invalidateHandles();
}
);
});
}
#endif

Expand Down Expand Up @@ -8142,6 +8139,25 @@ AuthorityFactory::createBetweenGeodeticCRSWithDatumBasedIntermediates(
}
}

std::string sourceDatumPubDate;
const auto sourceDatum = sourceGeodCRS->datumNonNull(d->context());
if (sourceDatum->publicationDate().has_value()) {
sourceDatumPubDate = sourceDatum->publicationDate()->toString();
}

std::string targetDatumPubDate;
const auto targetDatum = targetGeodCRS->datumNonNull(d->context());
if (targetDatum->publicationDate().has_value()) {
targetDatumPubDate = targetDatum->publicationDate()->toString();
}

const std::string mostAncientDatumPubDate =
(!targetDatumPubDate.empty() &&
(sourceDatumPubDate.empty() ||
targetDatumPubDate < sourceDatumPubDate))
? targetDatumPubDate
: sourceDatumPubDate;

auto opFactory = operation::CoordinateOperationFactory::create();
for (const auto &pair : candidates) {
const auto &trfmSource = pair.first;
Expand Down Expand Up @@ -8169,6 +8185,37 @@ AuthorityFactory::createBetweenGeodeticCRSWithDatumBasedIntermediates(
continue;
}

// Skip operations using a datum that is older than the source or
// target datum (e.g to avoid ED50 to WGS84 to go through NTF)
if (!mostAncientDatumPubDate.empty()) {
const auto isOlderCRS = [this, &mostAncientDatumPubDate](
const crs::CRSPtr &crs) {
const auto geogCRS =
dynamic_cast<const crs::GeodeticCRS *>(crs.get());
if (geogCRS) {
const auto datum = geogCRS->datumNonNull(d->context());
// Hum, theoretically we'd want to check
// datum->publicationDate()->toString() <
// mostAncientDatumPubDate but that would exclude doing
// IG05/12 Intermediate CRS to ITRF2014 through ITRF2008,
// since IG05/12 Intermediate CRS has been published later
// than ITRF2008. So use a cut of date for ancient vs
// "modern" era.
constexpr const char *CUT_OFF_DATE = "1900-01-01";
if (datum->publicationDate().has_value() &&
datum->publicationDate()->toString() < CUT_OFF_DATE &&
mostAncientDatumPubDate > CUT_OFF_DATE) {
return true;
}
}
return false;
};

if (isOlderCRS(op1Source) || isOlderCRS(op1Target) ||
isOlderCRS(op2Source) || isOlderCRS(op2Target))
continue;
}

std::vector<operation::CoordinateOperationNNPtr> steps;

if (!sourceCRS->isEquivalentTo(
Expand Down

0 comments on commit 0100ad0

Please sign in to comment.