diff options
| -rw-r--r-- | data/sql/customizations.sql | 18 | ||||
| -rw-r--r-- | data/sql/proj_db_table_defs.sql | 9 | ||||
| -rw-r--r-- | include/proj/io.hpp | 5 | ||||
| -rw-r--r-- | src/c_api.cpp | 10 | ||||
| -rw-r--r-- | src/coordinateoperation.cpp | 100 | ||||
| -rw-r--r-- | src/crs.cpp | 135 | ||||
| -rw-r--r-- | src/factory.cpp | 62 | ||||
| -rw-r--r-- | test/cli/testprojinfo_out.dist | 53 | ||||
| -rw-r--r-- | test/unit/test_c_api.cpp | 6 | ||||
| -rw-r--r-- | test/unit/test_crs.cpp | 5 | ||||
| -rw-r--r-- | test/unit/test_operation.cpp | 8 |
11 files changed, 265 insertions, 146 deletions
diff --git a/data/sql/customizations.sql b/data/sql/customizations.sql index 2181cc2b..8e31c233 100644 --- a/data/sql/customizations.sql +++ b/data/sql/customizations.sql @@ -6,3 +6,21 @@ INSERT INTO "other_transformation" VALUES('PROJ','CRS84_TO_EPSG_4326','OGC:CRS84 -- alias of EPSG:3857 INSERT INTO "projected_crs" VALUES('EPSG','900913','Google Maps Global Mercator',NULL,NULL,'EPSG','4499','EPSG','4326','EPSG','3856','EPSG','3544',NULL,1); + +-- Define the allowed authorities, and their precedence, when researching a +-- coordinate operation + +INSERT INTO authority_to_authority_preference(source_auth_name, target_auth_name, allowed_authorities) VALUES + ('any', 'EPSG', 'PROJ,EPSG,any' ); + +INSERT INTO authority_to_authority_preference(source_auth_name, target_auth_name, allowed_authorities) VALUES + ('EPSG', 'EPSG', 'PROJ,EPSG' ); + +INSERT INTO authority_to_authority_preference(source_auth_name, target_auth_name, allowed_authorities) VALUES + ('PROJ', 'EPSG', 'PROJ,EPSG' ); + +INSERT INTO authority_to_authority_preference(source_auth_name, target_auth_name, allowed_authorities) VALUES + ('IGNF', 'EPSG', 'PROJ,IGNF,EPSG' ); + +INSERT INTO authority_to_authority_preference(source_auth_name, target_auth_name, allowed_authorities) VALUES + ('ESRI', 'EPSG', 'PROJ,ESRI,EPSG' );
\ No newline at end of file diff --git a/data/sql/proj_db_table_defs.sql b/data/sql/proj_db_table_defs.sql index 553dab38..c63637cf 100644 --- a/data/sql/proj_db_table_defs.sql +++ b/data/sql/proj_db_table_defs.sql @@ -1048,3 +1048,12 @@ CREATE VIEW authority_list AS UNION SELECT DISTINCT auth_name FROM coordinate_operation_view ; + +-- Define the allowed authorities, and their precedence, when researching a +-- coordinate operation +CREATE TABLE authority_to_authority_preference( + source_auth_name TEXT NOT NULL, -- 'any' for any source + target_auth_name TEXT NOT NULL, -- 'any' for any target + allowed_authorities TEXT NOT NULL, -- for example 'PROJ,EPSG,any' + CONSTRAINT unique_authority_to_authority_preference UNIQUE (source_auth_name, target_auth_name) +); diff --git a/include/proj/io.hpp b/include/proj/io.hpp index 26420150..f511bf5b 100644 --- a/include/proj/io.hpp +++ b/include/proj/io.hpp @@ -731,6 +731,11 @@ class PROJ_GCC_DLL DatabaseContext { PROJ_INTERNAL std::string getTextDefinition(const std::string &tableName, const std::string &authName, const std::string &code) const; + + PROJ_INTERNAL std::vector<std::string> + getAllowedAuthorities(const std::string &sourceAuthName, + const std::string &targetAuthName) const; + //! @endcond protected: diff --git a/src/c_api.cpp b/src/c_api.cpp index fed91750..e1f34012 100644 --- a/src/c_api.cpp +++ b/src/c_api.cpp @@ -5354,9 +5354,17 @@ struct PJ_OPERATION_FACTORY_CONTEXT { * The returned object must be unreferenced with * proj_operation_factory_context_unref() after use. * + * If authority is NULL or the empty string, then coordinate + * operations from any authority will be searched, with the restrictions set + * in the authority_to_authority_preference database table. + * If authority is set to "any", then coordinate + * operations from any authority will be searched + * If authority is a non-empty string different of "any", + * then coordinate operatiosn will be searched only in that authority namespace. + * * @param ctx Context, or NULL for default context. * @param authority Name of authority to which to restrict the search of - * canidate operations. Or NULL to allow any authority. + * candidate operations. * @return Object that must be unreferenced with * proj_operation_factory_context_unref(), or NULL in * case of error. diff --git a/src/coordinateoperation.cpp b/src/coordinateoperation.cpp index 04f9bc9a..d187f2cc 100644 --- a/src/coordinateoperation.cpp +++ b/src/coordinateoperation.cpp @@ -8937,6 +8937,14 @@ CoordinateOperationContext::getIntermediateCRS() const { * If a non null authorityFactory is provided, the resulting context should * not be used simultaneously by more than one thread. * + * If authorityFactory->getAuthority() is the empty string, then coordinate + * operations from any authority will be searched, with the restrictions set + * in the authority_to_authority_preference database table. + * If authorityFactory->getAuthority() is set to "any", then coordinate + * operations from any authority will be searched + * If authorityFactory->getAuthority() is a non-empty string different of "any", + * then coordinate operatiosn will be searched only in that authority namespace. + * * @param authorityFactory Authority factory, or null if no database lookup * is allowed. * Use io::authorityFactory::create(context, std::string()) to allow all @@ -9663,6 +9671,8 @@ findOpsInRegistryDirect(const crs::CRSNNPtr &sourceCRS, const CoordinateOperationContextNNPtr &context) { const auto &authFactory = context->getAuthorityFactory(); assert(authFactory); + const auto &authFactoryName = authFactory->getAuthority(); + for (const auto &idSrc : sourceCRS->identifiers()) { const auto &srcAuthName = *(idSrc->codeSpace()); const auto &srcCode = idSrc->code(); @@ -9671,17 +9681,39 @@ findOpsInRegistryDirect(const crs::CRSNNPtr &sourceCRS, const auto &targetAuthName = *(idTarget->codeSpace()); const auto &targetCode = idTarget->code(); if (!targetAuthName.empty()) { - auto res = - authFactory->createFromCoordinateReferenceSystemCodes( - srcAuthName, srcCode, targetAuthName, targetCode, - context->getUsePROJAlternativeGridNames(), - context->getGridAvailabilityUse() == - CoordinateOperationContext:: - GridAvailabilityUse:: - DISCARD_OPERATION_IF_MISSING_GRID, - context->getDiscardSuperseded()); - if (!res.empty()) { - return res; + std::vector<std::string> authorities; + if (authFactoryName == "any") { + authorities.emplace_back(); + } + if (authFactoryName.empty()) { + authorities = authFactory->databaseContext() + ->getAllowedAuthorities( + srcAuthName, targetAuthName); + if (authorities.empty()) { + authorities.emplace_back(); + } + } else { + authorities.emplace_back(authFactoryName); + } + for (const auto &authority : authorities) { + const auto tmpAuthFactory = + io::AuthorityFactory::create( + authFactory->databaseContext(), + authority == "any" ? std::string() : authority); + auto res = + tmpAuthFactory + ->createFromCoordinateReferenceSystemCodes( + srcAuthName, srcCode, targetAuthName, + targetCode, + context->getUsePROJAlternativeGridNames(), + context->getGridAvailabilityUse() == + CoordinateOperationContext:: + GridAvailabilityUse:: + DISCARD_OPERATION_IF_MISSING_GRID, + context->getDiscardSuperseded()); + if (!res.empty()) { + return res; + } } } } @@ -9706,6 +9738,8 @@ static std::vector<CoordinateOperationNNPtr> findsOpsInRegistryWithIntermediate( const auto &authFactory = context->getAuthorityFactory(); assert(authFactory); + const auto &authFactoryName = authFactory->getAuthority(); + for (const auto &idSrc : sourceCRS->identifiers()) { const auto &srcAuthName = *(idSrc->codeSpace()); const auto &srcCode = idSrc->code(); @@ -9714,16 +9748,40 @@ static std::vector<CoordinateOperationNNPtr> findsOpsInRegistryWithIntermediate( const auto &targetAuthName = *(idTarget->codeSpace()); const auto &targetCode = idTarget->code(); if (!targetAuthName.empty()) { - auto res = authFactory->createFromCRSCodesWithIntermediates( - srcAuthName, srcCode, targetAuthName, targetCode, - context->getUsePROJAlternativeGridNames(), - context->getGridAvailabilityUse() == - CoordinateOperationContext::GridAvailabilityUse:: - DISCARD_OPERATION_IF_MISSING_GRID, - context->getDiscardSuperseded(), - context->getIntermediateCRS()); - if (!res.empty()) { - return res; + std::vector<std::string> authorities; + if (authFactoryName == "any") { + authorities.emplace_back(); + } + if (authFactoryName.empty()) { + authorities = authFactory->databaseContext() + ->getAllowedAuthorities( + srcAuthName, targetAuthName); + if (authorities.empty()) { + authorities.emplace_back(); + } + } else { + authorities.emplace_back(authFactoryName); + } + for (const auto &authority : authorities) { + const auto tmpAuthFactory = + io::AuthorityFactory::create( + authFactory->databaseContext(), + authority == "any" ? std::string() : authority); + + auto res = + tmpAuthFactory->createFromCRSCodesWithIntermediates( + srcAuthName, srcCode, targetAuthName, + targetCode, + context->getUsePROJAlternativeGridNames(), + context->getGridAvailabilityUse() == + CoordinateOperationContext:: + GridAvailabilityUse:: + DISCARD_OPERATION_IF_MISSING_GRID, + context->getDiscardSuperseded(), + context->getIntermediateCRS()); + if (!res.empty()) { + return res; + } } } } 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<operation::Transformation>(op); - if (transf) { - try { - transf->getTOWGS84Parameters(); - } catch (const std::exception &) { - continue; - } - return util::nn_static_pointer_cast<CRS>( - BoundCRS::create(thisAsCRS, hubCRS, NN_NO_CHECK(transf))); - } else { - auto concatenated = - dynamic_cast<const operation::ConcatenatedOperation *>( - 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<const operation::Transformation *>( - subops[0].get()); - auto firstOpIsConversion = - dynamic_cast<const operation::Conversion *>( - subops[0].get()); - if ((firstOpIsTransformation && - firstOpIsTransformation->isLongitudeRotation()) || - (dynamic_cast<DerivedCRS *>(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<operation::Transformation>( + op); + if (transf && !starts_with(transf->nameStr(), "Null geo")) { + try { + transf->getTOWGS84Parameters(); + } catch (const std::exception &) { + continue; + } + return util::nn_static_pointer_cast<CRS>(BoundCRS::create( + thisAsCRS, hubCRS, NN_NO_CHECK(transf))); + } else { + auto concatenated = + dynamic_cast<const operation::ConcatenatedOperation *>( + 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<const operation::Transformation *>( + subops[0].get()); + auto firstOpIsConversion = + dynamic_cast<const operation::Conversion *>( + subops[0].get()); + if ((firstOpIsTransformation && + firstOpIsTransformation + ->isLongitudeRotation()) || + (dynamic_cast<DerivedCRS *>(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<CRS>( + BoundCRS::create(thisAsCRS, hubCRS, + NN_NO_CHECK(transf))); } - return util::nn_static_pointer_cast<CRS>( - BoundCRS::create(thisAsCRS, hubCRS, - NN_NO_CHECK(transf))); } } } } } + } catch (const std::exception &) { } - } catch (const std::exception &) { } return thisAsCRS; } diff --git a/src/factory.cpp b/src/factory.cpp index e24cee58..20701def 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -880,6 +880,44 @@ std::string DatabaseContext::getTextDefinition(const std::string &tableName, return res[0][0]; } +// --------------------------------------------------------------------------- + +/** \brief Return the allowed authorities when researching transformations + * between different authorities. + * + * @throw FactoryException + */ +std::vector<std::string> DatabaseContext::getAllowedAuthorities( + const std::string &sourceAuthName, + const std::string &targetAuthName) const { + auto res = d->run( + "SELECT allowed_authorities FROM authority_to_authority_preference " + "WHERE source_auth_name = ? AND target_auth_name = ?", + {sourceAuthName, targetAuthName}); + if (res.empty()) { + res = d->run( + "SELECT allowed_authorities FROM authority_to_authority_preference " + "WHERE source_auth_name = ? AND target_auth_name = 'any'", + {sourceAuthName}); + } + if (res.empty()) { + res = d->run( + "SELECT allowed_authorities FROM authority_to_authority_preference " + "WHERE source_auth_name = 'any' AND target_auth_name = ?", + {targetAuthName}); + } + if (res.empty()) { + res = d->run( + "SELECT allowed_authorities FROM authority_to_authority_preference " + "WHERE source_auth_name = 'any' AND target_auth_name = 'any'", + {}); + } + if (res.empty()) { + return std::vector<std::string>(); + } + return split(res[0][0], ','); +} + //! @endcond // --------------------------------------------------------------------------- @@ -947,6 +985,10 @@ struct AuthorityFactory::Private { SQLResultSet runWithCodeParam(const char *sql, const std::string &code); + bool hasAuthorityRestriction() const { + return !authority_.empty() && authority_ != "any"; + } + private: DatabaseContextNNPtr context_; std::string authority_; @@ -3097,7 +3139,7 @@ AuthorityFactory::createFromCoordinateReferenceSystemCodes( "= ? AND auth_name = ? AND code = ? AND deprecated != 1"); auto params = std::vector<SQLValues>{sourceCRSAuthName, sourceCRSCode, targetCRSAuthName, targetCRSCode}; - if (!getAuthority().empty()) { + if (d->hasAuthorityRestriction()) { sql += " AND conversion_auth_name = ?"; params.emplace_back(getAuthority()); } @@ -3134,7 +3176,7 @@ AuthorityFactory::createFromCoordinateReferenceSystemCodes( } params = {sourceCRSAuthName, sourceCRSCode, targetCRSAuthName, targetCRSCode}; - if (!getAuthority().empty()) { + if (d->hasAuthorityRestriction()) { sql += " AND cov.auth_name = ?"; params.emplace_back(getAuthority()); } @@ -3361,7 +3403,7 @@ AuthorityFactory::createFromCRSCodesWithIntermediates( "AND v1.deprecated = 0 AND v2.deprecated = 0 " "AND intersects_bbox(south_lat1, west_lon1, north_lat1, east_lon1, " "south_lat2, west_lon2, north_lat2, east_lon2) == 1 "); - if (!getAuthority().empty()) { + if (d->hasAuthorityRestriction()) { additionalWhere += "AND v1.auth_name = ? AND v2.auth_name = ? "; params.emplace_back(getAuthority()); params.emplace_back(getAuthority()); @@ -3852,7 +3894,7 @@ AuthorityFactory::createObjectsFromName( sql += "name LIKE ? AND "; params.push_back(searchedNameWithoutDeprecated); } - if (!getAuthority().empty()) { + if (d->hasAuthorityRestriction()) { sql += " auth_name = ? AND "; params.emplace_back(getAuthority()); } @@ -4152,7 +4194,7 @@ AuthorityFactory::listAreaOfUseFromName(const std::string &name, std::string sql( "SELECT auth_name, code FROM area WHERE deprecated = 0 AND "); std::vector<SQLValues> params; - if (!getAuthority().empty()) { + if (d->hasAuthorityRestriction()) { sql += " auth_name = ? AND "; params.emplace_back(getAuthority()); } @@ -4206,7 +4248,7 @@ std::list<crs::GeodeticCRSNNPtr> AuthorityFactory::createGeodeticCRSFromDatum( "SELECT auth_name, code FROM geodetic_crs WHERE " "datum_auth_name = ? AND datum_code = ? AND deprecated = 0"); std::vector<SQLValues> params{datum_auth_name, datum_code}; - if (!getAuthority().empty()) { + if (d->hasAuthorityRestriction()) { sql += " AND auth_name = ?"; params.emplace_back(getAuthority()); } @@ -4242,7 +4284,7 @@ AuthorityFactory::createGeodeticCRSFromEllipsoid( "geodetic_datum.deprecated = 0 AND " "geodetic_crs.deprecated = 0"); std::vector<SQLValues> params{ellipsoid_auth_name, ellipsoid_code}; - if (!getAuthority().empty()) { + if (d->hasAuthorityRestriction()) { sql += " AND geodetic_crs.auth_name = ?"; params.emplace_back(getAuthority()); } @@ -4363,7 +4405,7 @@ AuthorityFactory::createProjectedCRSFromExisting( sql += "conversion.method_auth_name = 'EPSG' AND " "conversion.method_code = ?"; params.emplace_back(toString(methodEPSGCode)); - if (!getAuthority().empty()) { + if (d->hasAuthorityRestriction()) { sql += " AND projected_crs.auth_name = ?"; params.emplace_back(getAuthority()); } @@ -4533,7 +4575,7 @@ AuthorityFactory::createProjectedCRSFromExisting( params.emplace_back(patternVal); } sql += ")"; - if (!getAuthority().empty()) { + if (d->hasAuthorityRestriction()) { sql += " AND auth_name = ?"; params.emplace_back(getAuthority()); } @@ -4597,7 +4639,7 @@ AuthorityFactory::createCompoundCRSFromExisting( "vertical_crs_"); addAnd = true; } - if (!getAuthority().empty()) { + if (d->hasAuthorityRestriction()) { if (addAnd) { sql += " AND "; } diff --git a/test/cli/testprojinfo_out.dist b/test/cli/testprojinfo_out.dist index f3d4854a..4a760c67 100644 --- a/test/cli/testprojinfo_out.dist +++ b/test/cli/testprojinfo_out.dist @@ -110,12 +110,11 @@ CONVERSION["UTM zone 31N", ID["EPSG",16031]] Testing projinfo -s NAD27 -t NAD83 --grid-check none --spatial-test intersects --summary -Candidate operations found: 8 +Candidate operations found: 7 DERIVED_FROM(EPSG):1312, NAD27 to NAD83 (3), 1.0 m, Canada DERIVED_FROM(EPSG):1313, NAD27 to NAD83 (4), 1.5 m, Canada - NAD27 DERIVED_FROM(EPSG):1241, NAD27 to NAD83 (1), 0.15 m, USA - CONUS including EEZ DERIVED_FROM(EPSG):1243, NAD27 to NAD83 (2), 0.5 m, USA - Alaska including EEZ -ESRI:108003, NAD_1927_To_NAD_1983_PR_VI, 0.05 m, Caribbean - Puerto Rico and Virgin Islands - onshore unknown id, Null geographic offset from NAD27 to NAD83, unknown accuracy, World EPSG:1462, NAD27 to NAD83 (5), 1.0 m, Canada - Quebec EPSG:1573, NAD27 to NAD83 (6), 1.5 m, Canada - Quebec @@ -306,52 +305,6 @@ COORDINATEOPERATION["NAD27 to NAD83 (2)", ------------------------------------- Operation n°5: -ESRI:108003, NAD_1927_To_NAD_1983_PR_VI, 0.05 m, Caribbean - Puerto Rico and Virgin Islands - onshore - -PROJ string: -+proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=prvi +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1 - -WKT2_2015 string: -COORDINATEOPERATION["NAD_1927_To_NAD_1983_PR_VI", - SOURCECRS[ - GEODCRS["NAD27", - DATUM["North American Datum 1927", - ELLIPSOID["Clarke 1866",6378206.4,294.978698213898, - LENGTHUNIT["metre",1]]], - PRIMEM["Greenwich",0, - ANGLEUNIT["degree",0.0174532925199433]], - CS[ellipsoidal,2], - AXIS["geodetic latitude (Lat)",north, - ORDER[1], - ANGLEUNIT["degree",0.0174532925199433]], - AXIS["geodetic longitude (Lon)",east, - ORDER[2], - ANGLEUNIT["degree",0.0174532925199433]]]], - TARGETCRS[ - GEODCRS["NAD83", - DATUM["North American Datum 1983", - ELLIPSOID["GRS 1980",6378137,298.257222101, - LENGTHUNIT["metre",1]]], - PRIMEM["Greenwich",0, - ANGLEUNIT["degree",0.0174532925199433]], - CS[ellipsoidal,2], - AXIS["geodetic latitude (Lat)",north, - ORDER[1], - ANGLEUNIT["degree",0.0174532925199433]], - AXIS["geodetic longitude (Lon)",east, - ORDER[2], - ANGLEUNIT["degree",0.0174532925199433]]]], - METHOD["NTv2", - ID["EPSG",9615]], - PARAMETERFILE["Latitude and longitude difference file","prvi"], - OPERATIONACCURACY[0.05], - AREA["Caribbean - Puerto Rico and Virgin Islands - onshore"], - BBOX[17.62,-67.97,18.78,-64.25], - ID["ESRI",108003]] - -------------------------------------- -Operation n°6: - unknown id, Null geographic offset from NAD27 to NAD83, unknown accuracy, World PROJ string: @@ -405,7 +358,7 @@ COORDINATEOPERATION["Null geographic offset from NAD27 to NAD83", BBOX[-90,-180,90,180]] ------------------------------------- -Operation n°7: +Operation n°6: EPSG:1462, NAD27 to NAD83 (5), 1.0 m, Canada - Quebec @@ -451,7 +404,7 @@ COORDINATEOPERATION["NAD27 to NAD83 (5)", ID["EPSG",1462]] ------------------------------------- -Operation n°8: +Operation n°7: EPSG:1573, NAD27 to NAD83 (6), 1.5 m, Canada - Quebec diff --git a/test/unit/test_c_api.cpp b/test/unit/test_c_api.cpp index 42d00fa6..20f4180b 100644 --- a/test/unit/test_c_api.cpp +++ b/test/unit/test_c_api.cpp @@ -1146,7 +1146,7 @@ TEST_F(CApi, proj_obj_create_operations) { ASSERT_NE(res, nullptr); ObjListKeeper keeper_res(res); - EXPECT_EQ(proj_obj_list_get_count(res), 8); + EXPECT_EQ(proj_obj_list_get_count(res), 7); EXPECT_EQ(proj_obj_list_get(m_ctxt, res, -1), nullptr); EXPECT_EQ(proj_obj_list_get(m_ctxt, res, proj_obj_list_get_count(res)), @@ -1247,7 +1247,7 @@ TEST_F(CApi, proj_obj_create_operations_with_pivot) { // Restrict pivot to JGD2000 { - auto ctxt = proj_create_operation_factory_context(m_ctxt, nullptr); + auto ctxt = proj_create_operation_factory_context(m_ctxt, "any"); ASSERT_NE(ctxt, nullptr); ContextKeeper keeper_ctxt(ctxt); @@ -1263,7 +1263,7 @@ TEST_F(CApi, proj_obj_create_operations_with_pivot) { proj_obj_create_operations(m_ctxt, source_crs, target_crs, ctxt); ASSERT_NE(res, nullptr); ObjListKeeper keeper_res(res); - // includes 2 results from ESRI + // includes results from ESRI EXPECT_EQ(proj_obj_list_get_count(res), 5); auto op = proj_obj_list_get(m_ctxt, res, 0); ASSERT_NE(op, nullptr); diff --git a/test/unit/test_crs.cpp b/test/unit/test_crs.cpp index 44b84401..9c11ac4c 100644 --- a/test/unit/test_crs.cpp +++ b/test/unit/test_crs.cpp @@ -4841,6 +4841,11 @@ TEST(crs, crs_createBoundCRSToWGS84IfPossible) { "+proj=geocent +ellps=intl " "+towgs84=324.8,153.6,172.1,0,0,0,0 +units=m +no_defs"); } + { + auto crs = factory->createCoordinateReferenceSystem("4269"); // NAD83 + auto bound = crs->createBoundCRSToWGS84IfPossible(dbContext); + EXPECT_EQ(bound, crs); + } } // --------------------------------------------------------------------------- diff --git a/test/unit/test_operation.cpp b/test/unit/test_operation.cpp index 057f1717..e5734cd1 100644 --- a/test/unit/test_operation.cpp +++ b/test/unit/test_operation.cpp @@ -5941,7 +5941,7 @@ TEST(operation, IGNF_LAMB1_TO_EPSG_4326) { AuthorityFactory::create(DatabaseContext::create(), "EPSG") ->createCoordinateReferenceSystem("4326"), ctxt); - ASSERT_GE(list2.size(), 4U); + ASSERT_GE(list2.size(), 3U); EXPECT_EQ(replaceAll(list2[0]->exportToPROJString( PROJStringFormatter::create().get()), @@ -5950,10 +5950,8 @@ TEST(operation, IGNF_LAMB1_TO_EPSG_4326) { // The second entry in list2 (list2[1]) uses the // weird +pm=2.33720833333333 from "NTF (Paris) to NTF (2)" - // and the third one uses the ESRI geographic offset method with another - // value - // so skip to the 4th method - EXPECT_EQ(replaceAll(list2[3]->exportToPROJString( + // so skip to the 3th method + EXPECT_EQ(replaceAll(list2[2]->exportToPROJString( PROJStringFormatter::create().get()), "0.999877341", "0.99987734"), list[1]->exportToPROJString(PROJStringFormatter::create().get())); |
