Skip to content

Commit 700721e

Browse files
authored
Merge pull request OSGeo#3707 from rouault/fix_crs_to_crs_warn_only_best
proj_create_crs_to_crs(): restore behaviour of PROJ 9.1
2 parents 977ce13 + 78d563c commit 700721e

File tree

6 files changed

+154
-42
lines changed

6 files changed

+154
-42
lines changed

src/4D_api.cpp

Lines changed: 79 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1878,25 +1878,29 @@ pj_create_prepared_operations(PJ_CONTEXT *ctx, const PJ *source_crs,
18781878
double north_lat = 0.0;
18791879

18801880
const char *areaName = nullptr;
1881-
if (proj_get_area_of_use(ctx, op, &west_lon, &south_lat, &east_lon,
1882-
&north_lat, &areaName)) {
1883-
const bool isOffshore =
1884-
areaName && strstr(areaName, "- offshore");
1885-
if (west_lon <= east_lon) {
1886-
op = add_coord_op_to_list(
1887-
i, op, west_lon, south_lat, east_lon, north_lat,
1888-
pjGeogToSrc, pjGeogToDst, isOffshore, preparedOpList);
1889-
} else {
1890-
auto op_clone = proj_clone(ctx, op);
1891-
1892-
op = add_coord_op_to_list(
1893-
i, op, west_lon, south_lat, 180, north_lat, pjGeogToSrc,
1894-
pjGeogToDst, isOffshore, preparedOpList);
1895-
op_clone = add_coord_op_to_list(
1896-
i, op_clone, -180, south_lat, east_lon, north_lat,
1897-
pjGeogToSrc, pjGeogToDst, isOffshore, preparedOpList);
1898-
proj_destroy(op_clone);
1899-
}
1881+
if (!proj_get_area_of_use(ctx, op, &west_lon, &south_lat, &east_lon,
1882+
&north_lat, &areaName)) {
1883+
west_lon = -180;
1884+
south_lat = -90;
1885+
east_lon = 180;
1886+
north_lat = 90;
1887+
}
1888+
1889+
const bool isOffshore = areaName && strstr(areaName, "- offshore");
1890+
if (west_lon <= east_lon) {
1891+
op = add_coord_op_to_list(i, op, west_lon, south_lat, east_lon,
1892+
north_lat, pjGeogToSrc, pjGeogToDst,
1893+
isOffshore, preparedOpList);
1894+
} else {
1895+
auto op_clone = proj_clone(ctx, op);
1896+
1897+
op = add_coord_op_to_list(i, op, west_lon, south_lat, 180,
1898+
north_lat, pjGeogToSrc, pjGeogToDst,
1899+
isOffshore, preparedOpList);
1900+
op_clone = add_coord_op_to_list(
1901+
i, op_clone, -180, south_lat, east_lon, north_lat,
1902+
pjGeogToSrc, pjGeogToDst, isOffshore, preparedOpList);
1903+
proj_destroy(op_clone);
19001904
}
19011905

19021906
proj_destroy(op);
@@ -2056,27 +2060,48 @@ PJ *proj_create_crs_to_crs_from_pj(PJ_CONTEXT *ctx, const PJ *source_crs,
20562060
P->skipNonInstantiable = warnIfBestTransformationNotAvailable;
20572061
}
20582062

2059-
if (P == nullptr || op_count == 1 ||
2060-
proj_get_type(source_crs) == PJ_TYPE_GEOCENTRIC_CRS ||
2061-
proj_get_type(target_crs) == PJ_TYPE_GEOCENTRIC_CRS) {
2063+
const bool mayNeedToReRunWithDiscardMissing =
2064+
(errorIfBestTransformationNotAvailable ||
2065+
warnIfBestTransformationNotAvailable) &&
2066+
!proj_context_is_network_enabled(ctx);
2067+
int singleOpIsInstanciable = -1;
2068+
if (P != nullptr && op_count == 1 && mayNeedToReRunWithDiscardMissing) {
2069+
singleOpIsInstanciable = proj_coordoperation_is_instantiable(ctx, P);
2070+
}
2071+
2072+
const auto backup_errno = proj_context_errno(ctx);
2073+
if ((P == nullptr ||
2074+
(op_count == 1 &&
2075+
(!mayNeedToReRunWithDiscardMissing ||
2076+
errorIfBestTransformationNotAvailable ||
2077+
singleOpIsInstanciable == static_cast<int>(true))) ||
2078+
proj_get_type(source_crs) == PJ_TYPE_GEOCENTRIC_CRS ||
2079+
proj_get_type(target_crs) == PJ_TYPE_GEOCENTRIC_CRS)) {
20622080
proj_list_destroy(op_list);
20632081
ctx->forceOver = false;
20642082

2065-
if (P != nullptr &&
2066-
(errorIfBestTransformationNotAvailable ||
2067-
warnIfBestTransformationNotAvailable) &&
2068-
!proj_coordoperation_is_instantiable(ctx, P)) {
2069-
warnAboutMissingGrid(P);
2070-
if (errorIfBestTransformationNotAvailable) {
2071-
proj_destroy(P);
2072-
return nullptr;
2083+
if (P != nullptr && (errorIfBestTransformationNotAvailable ||
2084+
warnIfBestTransformationNotAvailable)) {
2085+
if (singleOpIsInstanciable < 0) {
2086+
singleOpIsInstanciable =
2087+
proj_coordoperation_is_instantiable(ctx, P);
2088+
}
2089+
if (!singleOpIsInstanciable) {
2090+
warnAboutMissingGrid(P);
2091+
if (errorIfBestTransformationNotAvailable) {
2092+
proj_destroy(P);
2093+
return nullptr;
2094+
}
20732095
}
20742096
}
20752097

20762098
if (P != nullptr) {
20772099
P->over = forceOver;
20782100
}
20792101
return P;
2102+
} else if (op_count == 1 && mayNeedToReRunWithDiscardMissing &&
2103+
!singleOpIsInstanciable) {
2104+
warnAboutMissingGrid(P);
20802105
}
20812106

20822107
if (errorIfBestTransformationNotAvailable ||
@@ -2094,10 +2119,6 @@ PJ *proj_create_crs_to_crs_from_pj(PJ_CONTEXT *ctx, const PJ *source_crs,
20942119
return nullptr;
20952120
}
20962121

2097-
const bool mayNeedToReRunWithDiscardMissing =
2098-
(errorIfBestTransformationNotAvailable ||
2099-
warnIfBestTransformationNotAvailable) &&
2100-
!proj_context_is_network_enabled(ctx);
21012122
bool foundInstanciableAndNonBallpark = false;
21022123

21032124
for (auto &op : preparedOpList) {
@@ -2152,6 +2173,8 @@ PJ *proj_create_crs_to_crs_from_pj(PJ_CONTEXT *ctx, const PJ *source_crs,
21522173

21532174
op_list = proj_create_operations(ctx, source_crs, target_crs,
21542175
operation_ctx);
2176+
proj_operation_factory_context_destroy(operation_ctx);
2177+
21552178
if (op_list) {
21562179
ctx->forceOver = forceOver;
21572180
ctx->debug_level = PJ_LOG_NONE;
@@ -2179,10 +2202,30 @@ PJ *proj_create_crs_to_crs_from_pj(PJ_CONTEXT *ctx, const PJ *source_crs,
21792202
newOpList.emplace_back(std::move(op));
21802203
}
21812204
preparedOpList = std::move(newOpList);
2205+
} else {
2206+
// We get there in "cs2cs --only-best --no-ballpark
2207+
// EPSG:4326+3855 EPSG:4979" use case, where the initial
2208+
// create_operations returned 1 operation, and the retry
2209+
// with
2210+
// PROJ_GRID_AVAILABILITY_DISCARD_OPERATION_IF_MISSING_GRID
2211+
// returned 0.
2212+
if (op_count == 1 &&
2213+
(errorIfBestTransformationNotAvailable ||
2214+
warnIfBestTransformationNotAvailable)) {
2215+
if (singleOpIsInstanciable < 0) {
2216+
singleOpIsInstanciable =
2217+
proj_coordoperation_is_instantiable(ctx, P);
2218+
}
2219+
if (!singleOpIsInstanciable) {
2220+
if (errorIfBestTransformationNotAvailable) {
2221+
proj_destroy(P);
2222+
proj_context_errno_set(ctx, backup_errno);
2223+
return nullptr;
2224+
}
2225+
}
2226+
}
21822227
}
21832228
}
2184-
2185-
proj_operation_factory_context_destroy(operation_ctx);
21862229
}
21872230
}
21882231

src/iso19111/factory.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3250,6 +3250,17 @@ bool DatabaseContext::lookForGridInfo(
32503250
bool &directDownload, bool &openLicense, bool &gridAvailable) const {
32513251
Private::GridInfoCache info;
32523252

3253+
if (projFilename == "null") {
3254+
// Special case for implicit "null" grid.
3255+
fullFilename.clear();
3256+
packageName.clear();
3257+
url.clear();
3258+
directDownload = false;
3259+
openLicense = true;
3260+
gridAvailable = true;
3261+
return true;
3262+
}
3263+
32533264
auto ctxt = d->pjCtxt();
32543265
if (ctxt == nullptr) {
32553266
ctxt = pj_get_default_ctx();

src/iso19111/operation/coordinateoperationfactory.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4860,14 +4860,27 @@ void CoordinateOperationFactory::Private::createOperationsVertToVert(
48604860
if (convDst == 0)
48614861
throw InvalidOperation("Conversion factor of target unit is 0");
48624862
const double factor = convSrc / convDst;
4863+
4864+
const auto &sourceCRSExtent = getExtent(sourceCRS);
4865+
const auto &targetCRSExtent = getExtent(targetCRS);
4866+
const bool sameExtent =
4867+
sourceCRSExtent && targetCRSExtent &&
4868+
sourceCRSExtent->_isEquivalentTo(
4869+
targetCRSExtent.get(), util::IComparable::Criterion::EQUIVALENT);
4870+
4871+
util::PropertyMap map;
4872+
map.set(common::ObjectUsage::DOMAIN_OF_VALIDITY_KEY,
4873+
sameExtent ? NN_NO_CHECK(sourceCRSExtent)
4874+
: metadata::Extent::WORLD);
4875+
48634876
if (!equivalentVDatum) {
48644877
auto name = buildTransfName(sourceCRS->nameStr(), targetCRS->nameStr());
48654878
name += " (";
48664879
name += BALLPARK_VERTICAL_TRANSFORMATION;
48674880
name += ')';
48684881
auto conv = Transformation::createChangeVerticalUnit(
4869-
util::PropertyMap().set(common::IdentifiedObject::NAME_KEY, name),
4870-
sourceCRS, targetCRS,
4882+
map.set(common::IdentifiedObject::NAME_KEY, name), sourceCRS,
4883+
targetCRS,
48714884
// In case of a height depth reversal, we should probably have
48724885
// 2 steps instead of putting a negative factor...
48734886
common::Scale(heightDepthReversal ? -factor : factor), {});
@@ -4876,7 +4889,7 @@ void CoordinateOperationFactory::Private::createOperationsVertToVert(
48764889
} else if (convSrc != convDst || !heightDepthReversal) {
48774890
auto name = buildConvName(sourceCRS->nameStr(), targetCRS->nameStr());
48784891
auto conv = Conversion::createChangeVerticalUnit(
4879-
util::PropertyMap().set(common::IdentifiedObject::NAME_KEY, name),
4892+
map.set(common::IdentifiedObject::NAME_KEY, name),
48804893
// In case of a height depth reversal, we should probably have
48814894
// 2 steps instead of putting a negative factor...
48824895
common::Scale(heightDepthReversal ? -factor : factor));
@@ -4885,7 +4898,7 @@ void CoordinateOperationFactory::Private::createOperationsVertToVert(
48854898
} else {
48864899
auto name = buildConvName(sourceCRS->nameStr(), targetCRS->nameStr());
48874900
auto conv = Conversion::createHeightDepthReversal(
4888-
util::PropertyMap().set(common::IdentifiedObject::NAME_KEY, name));
4901+
map.set(common::IdentifiedObject::NAME_KEY, name));
48894902
conv->setCRSs(sourceCRS, targetCRS, nullptr);
48904903
res.push_back(conv);
48914904
}

test/cli/testvarious

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,6 +1217,36 @@ EOF
12171217

12181218
rm -rf tmp_dir
12191219

1220+
echo "##############################################################" >> ${OUT}
1221+
echo "Test cs2cs (grid missing) with scenario of https://lists.osgeo.org/pipermail/proj/2023-April/011003.html" >> ${OUT}
1222+
1223+
mkdir tmp_dir
1224+
cp $PROJ_DATA/proj.db tmp_dir
1225+
1226+
echo 39 -3 0 | PROJ_DATA=tmp_dir PROJ_DEBUG=2 $EXE EPSG:4326+5773 EPSG:4326+5782 -E 2>&1|grep -v pj_open_lib >> ${OUT}
1227+
1228+
rm -rf tmp_dir
1229+
1230+
echo "##############################################################" >> ${OUT}
1231+
echo "Test cs2cs (grid missing) --only-best=no with scenario of https://lists.osgeo.org/pipermail/proj/2023-April/011003.html" >> ${OUT}
1232+
1233+
mkdir tmp_dir
1234+
cp $PROJ_DATA/proj.db tmp_dir
1235+
1236+
echo 39 -3 0 | PROJ_DATA=tmp_dir PROJ_DEBUG=2 $EXE --only-best=no EPSG:4326+5773 EPSG:4326+5782 -E 2>&1|grep -v pj_open_lib >> ${OUT}
1237+
1238+
rm -rf tmp_dir
1239+
1240+
echo "##############################################################" >> ${OUT}
1241+
echo "Test cs2cs (grid missing) --only-best with scenario of https://lists.osgeo.org/pipermail/proj/2023-April/011003.html" >> ${OUT}
1242+
1243+
mkdir tmp_dir
1244+
cp $PROJ_DATA/proj.db tmp_dir
1245+
1246+
echo 39 -3 0 | PROJ_DISPLAY_PROGRAM_NAME=NO PROJ_DATA=tmp_dir PROJ_DEBUG=2 $EXE --only-best EPSG:4326+5773 EPSG:4326+5782 -E 2>&1|grep -v pj_open_lib >> ${OUT}
1247+
1248+
rm -rf tmp_dir
1249+
12201250
echo "##############################################################" >> ${OUT}
12211251
echo "Test Similarity Transformation (example from EPSG Guidance Note 7.2)" >> ${OUT}
12221252
#

test/cli/tv_out.dist

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,21 @@ Test cs2cs (grid missing) with scenario of https://github.com/OSGeo/PROJ/issues/
592592
569704.5660295591 4269024.671083651 569720.46 4268813.88 0.00
593593
569704.5660295591 4269024.671083651 569720.46 4268813.88 0.00
594594
##############################################################
595+
Test cs2cs (grid missing) with scenario of https://lists.osgeo.org/pipermail/proj/2023-April/011003.html
596+
Attempt to use coordinate operation Inverse of WGS 84 to EGM96 height (1) + ETRS89 to Alicante height (1) using ETRS89 to WGS 84 (1) failed. Grid es_ign_egm08-rednap.tif is not available. Consult https://proj.org/resource_files.html for guidance. Grid us_nga_egm96_15.tif is not available. Consult https://proj.org/resource_files.html for guidance. This might become an error in a future PROJ major release. Set the ONLY_BEST option to YES or NO. This warning will no longer be emitted (for the current transformation instance).
597+
Using coordinate operation Transformation from EGM96 height to Alicante height (ballpark vertical transformation)
598+
39 -3 0 39.00 -3.00 0.00
599+
##############################################################
600+
Test cs2cs (grid missing) --only-best=no with scenario of https://lists.osgeo.org/pipermail/proj/2023-April/011003.html
601+
39 -3 0 39.00 -3.00 0.00
602+
##############################################################
603+
Test cs2cs (grid missing) --only-best with scenario of https://lists.osgeo.org/pipermail/proj/2023-April/011003.html
604+
Attempt to use coordinate operation Inverse of WGS 84 to EGM96 height (1) + ETRS89 to Alicante height (1) using ETRS89 to WGS 84 (1) failed. Grid es_ign_egm08-rednap.tif is not available. Consult https://proj.org/resource_files.html for guidance. Grid us_nga_egm96_15.tif is not available. Consult https://proj.org/resource_files.html for guidance.
605+
606+
cannot initialize transformation
607+
cause: File not found or invalid
608+
program abnormally terminated
609+
##############################################################
595610
Test Similarity Transformation (example from EPSG Guidance Note 7.2)
596611
300000 4500000 299905.060 4499796.515 0.000
597612
##############################################################

test/unit/test_operationfactory.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5988,7 +5988,7 @@ TEST(operation, vertCRS_to_vertCRS_context) {
59885988
authFactory->createCoordinateReferenceSystem("7968"),
59895989
// NAVD88 height (1)
59905990
authFactory->createCoordinateReferenceSystem("5703"), ctxt);
5991-
ASSERT_EQ(list.size(), 3U);
5991+
ASSERT_EQ(list.size(), 4U);
59925992
EXPECT_EQ(list[0]->nameStr(), "NGVD29 height (m) to NAVD88 height (3)");
59935993
EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
59945994
"+proj=vgridshift +grids=us_noaa_vertcone.tif +multiplier=1");
@@ -6005,7 +6005,7 @@ TEST(operation, vertCRS_to_vertCRS_New_Zealand_context) {
60056005
authFactory->createCoordinateReferenceSystem("7839"),
60066006
// Auckland 1946 height
60076007
authFactory->createCoordinateReferenceSystem("5759"), ctxt);
6008-
ASSERT_EQ(list.size(), 1U);
6008+
ASSERT_EQ(list.size(), 2U);
60096009
EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
60106010
"+proj=vgridshift +grids=nz_linz_auckht1946-nzvd2016.tif "
60116011
"+multiplier=1");

0 commit comments

Comments
 (0)