Skip to content

Commit

Permalink
proj_create_crs_to_crs(): restore behaviour of PROJ 9.1
Browse files Browse the repository at this point in the history
Fixes https://lists.osgeo.org/pipermail/proj/2023-April/011003.html
that is ``cs2cs EPSG:4326+5773 EPSG:4326+5782`` without grids available.

Fixes situations where getting operations in PROJ_GRID_AVAILABILITY_KNOWN_AVAILABLE
mode returns one single gridded operations where the grid isn't available or
a ballpark operation.
We retry in PROJ_GRID_AVAILABILITY_DISCARD_OPERATION_IF_MISSING_GRID
mode to get a potential ballpark operation.

Follow-up to similar fix of #3614
  • Loading branch information
rouault committed Apr 12, 2023
1 parent b214363 commit 78d563c
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 36 deletions.
115 changes: 79 additions & 36 deletions src/4D_api.cpp
Expand Up @@ -1878,25 +1878,29 @@ pj_create_prepared_operations(PJ_CONTEXT *ctx, const PJ *source_crs,
double north_lat = 0.0;

const char *areaName = nullptr;
if (proj_get_area_of_use(ctx, op, &west_lon, &south_lat, &east_lon,
&north_lat, &areaName)) {
const bool isOffshore =
areaName && strstr(areaName, "- offshore");
if (west_lon <= east_lon) {
op = add_coord_op_to_list(
i, op, west_lon, south_lat, east_lon, north_lat,
pjGeogToSrc, pjGeogToDst, isOffshore, preparedOpList);
} else {
auto op_clone = proj_clone(ctx, op);

op = add_coord_op_to_list(
i, op, west_lon, south_lat, 180, north_lat, pjGeogToSrc,
pjGeogToDst, isOffshore, preparedOpList);
op_clone = add_coord_op_to_list(
i, op_clone, -180, south_lat, east_lon, north_lat,
pjGeogToSrc, pjGeogToDst, isOffshore, preparedOpList);
proj_destroy(op_clone);
}
if (!proj_get_area_of_use(ctx, op, &west_lon, &south_lat, &east_lon,
&north_lat, &areaName)) {
west_lon = -180;
south_lat = -90;
east_lon = 180;
north_lat = 90;
}

const bool isOffshore = areaName && strstr(areaName, "- offshore");
if (west_lon <= east_lon) {
op = add_coord_op_to_list(i, op, west_lon, south_lat, east_lon,
north_lat, pjGeogToSrc, pjGeogToDst,
isOffshore, preparedOpList);
} else {
auto op_clone = proj_clone(ctx, op);

op = add_coord_op_to_list(i, op, west_lon, south_lat, 180,
north_lat, pjGeogToSrc, pjGeogToDst,
isOffshore, preparedOpList);
op_clone = add_coord_op_to_list(
i, op_clone, -180, south_lat, east_lon, north_lat,
pjGeogToSrc, pjGeogToDst, isOffshore, preparedOpList);
proj_destroy(op_clone);
}

proj_destroy(op);
Expand Down Expand Up @@ -2056,27 +2060,48 @@ PJ *proj_create_crs_to_crs_from_pj(PJ_CONTEXT *ctx, const PJ *source_crs,
P->skipNonInstantiable = warnIfBestTransformationNotAvailable;
}

if (P == nullptr || op_count == 1 ||
proj_get_type(source_crs) == PJ_TYPE_GEOCENTRIC_CRS ||
proj_get_type(target_crs) == PJ_TYPE_GEOCENTRIC_CRS) {
const bool mayNeedToReRunWithDiscardMissing =
(errorIfBestTransformationNotAvailable ||
warnIfBestTransformationNotAvailable) &&
!proj_context_is_network_enabled(ctx);
int singleOpIsInstanciable = -1;
if (P != nullptr && op_count == 1 && mayNeedToReRunWithDiscardMissing) {
singleOpIsInstanciable = proj_coordoperation_is_instantiable(ctx, P);
}

const auto backup_errno = proj_context_errno(ctx);
if ((P == nullptr ||
(op_count == 1 &&
(!mayNeedToReRunWithDiscardMissing ||
errorIfBestTransformationNotAvailable ||
singleOpIsInstanciable == static_cast<int>(true))) ||
proj_get_type(source_crs) == PJ_TYPE_GEOCENTRIC_CRS ||
proj_get_type(target_crs) == PJ_TYPE_GEOCENTRIC_CRS)) {
proj_list_destroy(op_list);
ctx->forceOver = false;

if (P != nullptr &&
(errorIfBestTransformationNotAvailable ||
warnIfBestTransformationNotAvailable) &&
!proj_coordoperation_is_instantiable(ctx, P)) {
warnAboutMissingGrid(P);
if (errorIfBestTransformationNotAvailable) {
proj_destroy(P);
return nullptr;
if (P != nullptr && (errorIfBestTransformationNotAvailable ||
warnIfBestTransformationNotAvailable)) {
if (singleOpIsInstanciable < 0) {
singleOpIsInstanciable =
proj_coordoperation_is_instantiable(ctx, P);
}
if (!singleOpIsInstanciable) {
warnAboutMissingGrid(P);
if (errorIfBestTransformationNotAvailable) {
proj_destroy(P);
return nullptr;
}
}
}

if (P != nullptr) {
P->over = forceOver;
}
return P;
} else if (op_count == 1 && mayNeedToReRunWithDiscardMissing &&
!singleOpIsInstanciable) {
warnAboutMissingGrid(P);
}

if (errorIfBestTransformationNotAvailable ||
Expand All @@ -2094,10 +2119,6 @@ PJ *proj_create_crs_to_crs_from_pj(PJ_CONTEXT *ctx, const PJ *source_crs,
return nullptr;
}

const bool mayNeedToReRunWithDiscardMissing =
(errorIfBestTransformationNotAvailable ||
warnIfBestTransformationNotAvailable) &&
!proj_context_is_network_enabled(ctx);
bool foundInstanciableAndNonBallpark = false;

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

op_list = proj_create_operations(ctx, source_crs, target_crs,
operation_ctx);
proj_operation_factory_context_destroy(operation_ctx);

if (op_list) {
ctx->forceOver = forceOver;
ctx->debug_level = PJ_LOG_NONE;
Expand Down Expand Up @@ -2179,10 +2202,30 @@ PJ *proj_create_crs_to_crs_from_pj(PJ_CONTEXT *ctx, const PJ *source_crs,
newOpList.emplace_back(std::move(op));
}
preparedOpList = std::move(newOpList);
} else {
// We get there in "cs2cs --only-best --no-ballpark
// EPSG:4326+3855 EPSG:4979" use case, where the initial
// create_operations returned 1 operation, and the retry
// with
// PROJ_GRID_AVAILABILITY_DISCARD_OPERATION_IF_MISSING_GRID
// returned 0.
if (op_count == 1 &&
(errorIfBestTransformationNotAvailable ||
warnIfBestTransformationNotAvailable)) {
if (singleOpIsInstanciable < 0) {
singleOpIsInstanciable =
proj_coordoperation_is_instantiable(ctx, P);
}
if (!singleOpIsInstanciable) {
if (errorIfBestTransformationNotAvailable) {
proj_destroy(P);
proj_context_errno_set(ctx, backup_errno);
return nullptr;
}
}
}
}
}

proj_operation_factory_context_destroy(operation_ctx);
}
}

Expand Down
30 changes: 30 additions & 0 deletions test/cli/testvarious
Expand Up @@ -1217,6 +1217,36 @@ EOF

rm -rf tmp_dir

echo "##############################################################" >> ${OUT}
echo "Test cs2cs (grid missing) with scenario of https://lists.osgeo.org/pipermail/proj/2023-April/011003.html" >> ${OUT}

mkdir tmp_dir
cp $PROJ_DATA/proj.db tmp_dir

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}

rm -rf tmp_dir

echo "##############################################################" >> ${OUT}
echo "Test cs2cs (grid missing) --only-best=no with scenario of https://lists.osgeo.org/pipermail/proj/2023-April/011003.html" >> ${OUT}

mkdir tmp_dir
cp $PROJ_DATA/proj.db tmp_dir

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}

rm -rf tmp_dir

echo "##############################################################" >> ${OUT}
echo "Test cs2cs (grid missing) --only-best with scenario of https://lists.osgeo.org/pipermail/proj/2023-April/011003.html" >> ${OUT}

mkdir tmp_dir
cp $PROJ_DATA/proj.db tmp_dir

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}

rm -rf tmp_dir

echo "##############################################################" >> ${OUT}
echo "Test Similarity Transformation (example from EPSG Guidance Note 7.2)" >> ${OUT}
#
Expand Down
15 changes: 15 additions & 0 deletions test/cli/tv_out.dist
Expand Up @@ -592,6 +592,21 @@ Test cs2cs (grid missing) with scenario of https://github.com/OSGeo/PROJ/issues/
569704.5660295591 4269024.671083651 569720.46 4268813.88 0.00
569704.5660295591 4269024.671083651 569720.46 4268813.88 0.00
##############################################################
Test cs2cs (grid missing) with scenario of https://lists.osgeo.org/pipermail/proj/2023-April/011003.html
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).
Using coordinate operation Transformation from EGM96 height to Alicante height (ballpark vertical transformation)
39 -3 0 39.00 -3.00 0.00
##############################################################
Test cs2cs (grid missing) --only-best=no with scenario of https://lists.osgeo.org/pipermail/proj/2023-April/011003.html
39 -3 0 39.00 -3.00 0.00
##############################################################
Test cs2cs (grid missing) --only-best with scenario of https://lists.osgeo.org/pipermail/proj/2023-April/011003.html
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.

cannot initialize transformation
cause: File not found or invalid
program abnormally terminated
##############################################################
Test Similarity Transformation (example from EPSG Guidance Note 7.2)
300000 4500000 299905.060 4499796.515 0.000
##############################################################
Expand Down

0 comments on commit 78d563c

Please sign in to comment.