From a9ef3a229c6fef5ef8a05ba521a0237f2ffa6aa6 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 6 Dec 2018 16:23:07 +0100 Subject: Coordinate operation search: add a authority_to_authority_preference table to restrict and prioritize searches --- src/crs.cpp | 135 +++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 79 insertions(+), 56 deletions(-) (limited to 'src/crs.cpp') diff --git a/src/crs.cpp b/src/crs.cpp index 546cfb0a..6212f561 100644 --- a/src/crs.cpp +++ b/src/crs.cpp @@ -409,74 +409,97 @@ CRSNNPtr CRS::createBoundCRSToWGS84IfPossible( } else { geodCRS = geogCRS; } - auto l_domains = domains(); + + if (!dbContext) { + return thisAsCRS; + } + + const auto &l_domains = domains(); metadata::ExtentPtr extent; if (!l_domains.empty()) { extent = l_domains[0]->domainOfValidity(); } - try { - auto authFactory = dbContext - ? io::AuthorityFactory::create( - NN_NO_CHECK(dbContext), std::string()) - .as_nullable() - : nullptr; - auto ctxt = operation::CoordinateOperationContext::create(authFactory, - extent, 0.0); - // ctxt->setSpatialCriterion( - // operation::CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION); - auto list = - operation::CoordinateOperationFactory::create()->createOperations( - NN_NO_CHECK(geodCRS), hubCRS, ctxt); - for (const auto &op : list) { - auto transf = - util::nn_dynamic_pointer_cast(op); - if (transf) { - try { - transf->getTOWGS84Parameters(); - } catch (const std::exception &) { - continue; - } - return util::nn_static_pointer_cast( - BoundCRS::create(thisAsCRS, hubCRS, NN_NO_CHECK(transf))); - } else { - auto concatenated = - dynamic_cast( - op.get()); - if (concatenated) { - // Case for EPSG:4807 / "NTF (Paris)" that is made of a - // longitude rotation followed by a Helmert - // The prime meridian shift will be accounted elsewhere - const auto &subops = concatenated->operations(); - if (subops.size() == 2) { - auto firstOpIsTransformation = - dynamic_cast( - subops[0].get()); - auto firstOpIsConversion = - dynamic_cast( - subops[0].get()); - if ((firstOpIsTransformation && - firstOpIsTransformation->isLongitudeRotation()) || - (dynamic_cast(thisAsCRS.get()) && - firstOpIsConversion)) { - transf = util::nn_dynamic_pointer_cast< - operation::Transformation>(subops[1]); - if (transf) { - try { - transf->getTOWGS84Parameters(); - } catch (const std::exception &) { - continue; + std::string crs_authority; + const auto &l_identifiers = identifiers(); + // If the object has an authority, restrict the transformations to + // come from that codespace too. This avoids for example EPSG:4269 + // (NAD83) to use a (dubious) ESRI transformation. + if (!l_identifiers.empty()) { + crs_authority = *(l_identifiers[0]->codeSpace()); + } + + auto authorities = dbContext->getAllowedAuthorities(crs_authority, "EPSG"); + if (authorities.empty()) { + authorities.emplace_back(); + } + for (const auto &authority : authorities) { + try { + + auto authFactory = io::AuthorityFactory::create( + NN_NO_CHECK(dbContext), + authority == "any" ? std::string() : authority); + auto ctxt = operation::CoordinateOperationContext::create( + authFactory, extent, 0.0); + // ctxt->setSpatialCriterion( + // operation::CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION); + auto list = + operation::CoordinateOperationFactory::create() + ->createOperations(NN_NO_CHECK(geodCRS), hubCRS, ctxt); + for (const auto &op : list) { + auto transf = + util::nn_dynamic_pointer_cast( + op); + if (transf && !starts_with(transf->nameStr(), "Null geo")) { + try { + transf->getTOWGS84Parameters(); + } catch (const std::exception &) { + continue; + } + return util::nn_static_pointer_cast(BoundCRS::create( + thisAsCRS, hubCRS, NN_NO_CHECK(transf))); + } else { + auto concatenated = + dynamic_cast( + op.get()); + if (concatenated) { + // Case for EPSG:4807 / "NTF (Paris)" that is made of a + // longitude rotation followed by a Helmert + // The prime meridian shift will be accounted elsewhere + const auto &subops = concatenated->operations(); + if (subops.size() == 2) { + auto firstOpIsTransformation = + dynamic_cast( + subops[0].get()); + auto firstOpIsConversion = + dynamic_cast( + subops[0].get()); + if ((firstOpIsTransformation && + firstOpIsTransformation + ->isLongitudeRotation()) || + (dynamic_cast(thisAsCRS.get()) && + firstOpIsConversion)) { + transf = util::nn_dynamic_pointer_cast< + operation::Transformation>(subops[1]); + if (transf && + !starts_with(transf->nameStr(), + "Null geo")) { + try { + transf->getTOWGS84Parameters(); + } catch (const std::exception &) { + continue; + } + return util::nn_static_pointer_cast( + BoundCRS::create(thisAsCRS, hubCRS, + NN_NO_CHECK(transf))); } - return util::nn_static_pointer_cast( - BoundCRS::create(thisAsCRS, hubCRS, - NN_NO_CHECK(transf))); } } } } } + } catch (const std::exception &) { } - } catch (const std::exception &) { } return thisAsCRS; } -- cgit v1.2.3 From f06045c2f0145ec2290913fa144cd690e70736fd Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 6 Dec 2018 21:28:16 +0100 Subject: Add API to retrieve non-deprecated equivalent of an object --- src/crs.cpp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'src/crs.cpp') diff --git a/src/crs.cpp b/src/crs.cpp index 6212f561..81e9a300 100644 --- a/src/crs.cpp +++ b/src/crs.cpp @@ -603,6 +603,40 @@ CRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { // --------------------------------------------------------------------------- +/** \brief Return CRSs that are non-deprecated substitutes for the current CRS. + */ +std::list +CRS::getNonDeprecated(const io::DatabaseContextNNPtr &dbContext) const { + std::list res; + const auto &l_identifiers = identifiers(); + if (l_identifiers.empty()) { + return res; + } + const char *tableName = nullptr; + if (dynamic_cast(this)) { + tableName = "geodetic_crs"; + } else if (dynamic_cast(this)) { + tableName = "projected_crs"; + } else if (dynamic_cast(this)) { + tableName = "vertical_crs"; + } else if (dynamic_cast(this)) { + tableName = "compound_crs"; + } + if (!tableName) { + return res; + } + const auto &id = l_identifiers[0]; + auto tmpRes = + dbContext->getNonDeprecated(tableName, *(id->codeSpace()), id->code()); + for (const auto &pair : tmpRes) { + res.emplace_back(io::AuthorityFactory::create(dbContext, pair.first) + ->createCoordinateReferenceSystem(pair.second)); + } + return res; +} + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress std::list> -- cgit v1.2.3 From cae698abe380b3823c3f08151c25097031ae091f Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 6 Dec 2018 22:51:27 +0100 Subject: Speed-up createBoundCRSToWGS84IfPossible() --- src/crs.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/crs.cpp') diff --git a/src/crs.cpp b/src/crs.cpp index 81e9a300..639fc3a9 100644 --- a/src/crs.cpp +++ b/src/crs.cpp @@ -375,8 +375,9 @@ VerticalCRSPtr CRS::extractVerticalCRS() const { * * @return a CRS. */ -CRSNNPtr CRS::createBoundCRSToWGS84IfPossible( - const io::DatabaseContextPtr &dbContext) const { +CRSNNPtr +CRS::createBoundCRSToWGS84IfPossible(const io::DatabaseContextPtr &dbContext, + bool allowIntermediateCRS) const { auto thisAsCRS = NN_NO_CHECK( std::static_pointer_cast(shared_from_this().as_nullable())); auto boundCRS = util::nn_dynamic_pointer_cast(thisAsCRS); @@ -441,6 +442,7 @@ CRSNNPtr CRS::createBoundCRSToWGS84IfPossible( authority == "any" ? std::string() : authority); auto ctxt = operation::CoordinateOperationContext::create( authFactory, extent, 0.0); + ctxt->setAllowUseIntermediateCRS(allowIntermediateCRS); // ctxt->setSpatialCriterion( // operation::CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION); auto list = -- cgit v1.2.3 From 263b259b276edd075b0abcd6aad0e923230c2d15 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Fri, 7 Dec 2018 02:22:20 +0100 Subject: Various speed optimizations --- src/crs.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'src/crs.cpp') diff --git a/src/crs.cpp b/src/crs.cpp index 639fc3a9..572fae5d 100644 --- a/src/crs.cpp +++ b/src/crs.cpp @@ -92,10 +92,10 @@ struct CRS::Private { bool implicitCS_ = false; void setImplicitCS(const util::PropertyMap &properties) { - auto oIter = properties.find("IMPLICIT_CS"); - if (oIter != properties.end()) { - if (auto genVal = util::nn_dynamic_pointer_cast( - oIter->second)) { + const auto pVal = properties.get("IMPLICIT_CS"); + if (pVal) { + if (const auto genVal = + dynamic_cast(pVal->get())) { if (genVal->type() == util::BoxedValue::Type::BOOLEAN && genVal->booleanValue()) { implicitCS_ = true; @@ -3226,8 +3226,7 @@ CompoundCRSNNPtr CompoundCRS::create(const util::PropertyMap &properties, auto compoundCRS(CompoundCRS::nn_make_shared(components)); compoundCRS->assignSelf(compoundCRS); compoundCRS->setProperties(properties); - if (properties.find(common::IdentifiedObject::NAME_KEY) == - properties.end()) { + if (!properties.get(common::IdentifiedObject::NAME_KEY)) { std::string name; for (const auto &crs : components) { if (!name.empty()) { @@ -4518,10 +4517,10 @@ EngineeringCRS::create(const util::PropertyMap &properties, crs->assignSelf(crs); crs->setProperties(properties); - auto oIter = properties.find("FORCE_OUTPUT_CS"); - if (oIter != properties.end()) { - if (auto genVal = util::nn_dynamic_pointer_cast( - oIter->second)) { + const auto pVal = properties.get("FORCE_OUTPUT_CS"); + if (pVal) { + if (const auto genVal = + dynamic_cast(pVal->get())) { if (genVal->type() == util::BoxedValue::Type::BOOLEAN && genVal->booleanValue()) { crs->d->forceOutputCS_ = true; -- cgit v1.2.3