diff --git a/docs/source/apps/cs2cs.rst b/docs/source/apps/cs2cs.rst index b1499257c7..17a847fe07 100644 --- a/docs/source/apps/cs2cs.rst +++ b/docs/source/apps/cs2cs.rst @@ -14,7 +14,7 @@ Synopsis | **cs2cs** [**-eEfIlrstvwW** [args]] | [[--area ] | [--bbox ]] | [--authority ] [--3d] - | [--accuracy ] [--only-best] [--no-ballpark] + | [--accuracy ] [--only-best[=yes|=no]] [--no-ballpark] | ([*+opt[=arg]* ...] [+to *+opt[=arg]* ...] | {source_crs} {target_crs}) | file ... @@ -167,12 +167,13 @@ The following control parameters can appear in any order: `south_lat` and `north_lat` in the [-90,90]. `west_long` is generally lower than `east_long`, except in the case where the area of interest crosses the antimeridian. -.. option:: --only-best +.. option:: --only-best[=yes|=no] .. versionadded:: 9.2.0 - Error out if the best transformation, known of PROJ, and usable by PROJ if - all grids known and usable by PROJ were accessible, cannot be used. + If set to yes, error out if the best transformation, known of PROJ, and + usable by PROJ if all grids known and usable by PROJ were accessible, + cannot be used. Best transformation should be understood as the transformation returned by :cpp:func:`proj_get_suggested_operation` if all known grids were accessible (either locally or through network). diff --git a/src/4D_api.cpp b/src/4D_api.cpp index 630f4f38b7..5764a43fa0 100644 --- a/src/4D_api.cpp +++ b/src/4D_api.cpp @@ -348,7 +348,8 @@ similarly, but prefers the 2D resp. 3D interfaces if available. if( res.xyzt.x != HUGE_VAL ) { return res; } - else if( P->errorIfBestTransformationNotAvailable ) { + else if( P->errorIfBestTransformationNotAvailable || + P->ctx->warnIfBestTransformationNotAvailable ) { std::string msg("Attempt to use coordinate operation "); msg += alt.name; msg += " failed."; @@ -367,8 +368,18 @@ similarly, but prefers the 2D resp. 3D interfaces if available. msg += " is not available."; } } - pj_log(P->ctx, PJ_LOG_ERROR, msg.c_str()); - return res; + if( P->ctx->warnIfBestTransformationNotAvailable ) + { + msg += " This will become an error in PROJ 10. " + "Set the ONLY_BEST option to YES or NO. " + "This warning will no longer be emitted (for the current context)."; + P->ctx->warnIfBestTransformationNotAvailable = false; + } + pj_log(P->ctx, + P->errorIfBestTransformationNotAvailable ? PJ_LOG_ERROR : PJ_LOG_WARNING, + msg.c_str()); + if( P->errorIfBestTransformationNotAvailable ) + return res; } if( iRetry == N_MAX_RETRY ) { break; @@ -1939,6 +1950,7 @@ PJ *proj_create_crs_to_crs_from_pj (PJ_CONTEXT *ctx, const PJ *source_crs, cons return nullptr; } } else if ((value = getOptionValue(*iter, "ONLY_BEST="))) { + ctx->warnIfBestTransformationNotAvailable = false; if( ci_equal(value, "yes") ) errorIfBestTransformationNotAvailable = true; else if( ci_equal(value, "no") ) @@ -1996,7 +2008,9 @@ PJ *proj_create_crs_to_crs_from_pj (PJ_CONTEXT *ctx, const PJ *source_crs, cons ctx, operation_ctx, PROJ_SPATIAL_CRITERION_PARTIAL_INTERSECTION); proj_operation_factory_context_set_grid_availability_use( ctx, operation_ctx, - (errorIfBestTransformationNotAvailable || proj_context_is_network_enabled(ctx)) ? + (errorIfBestTransformationNotAvailable || + ctx->warnIfBestTransformationNotAvailable || + proj_context_is_network_enabled(ctx)) ? PROJ_GRID_AVAILABILITY_KNOWN_AVAILABLE: PROJ_GRID_AVAILABILITY_DISCARD_OPERATION_IF_MISSING_GRID); @@ -2018,7 +2032,7 @@ PJ *proj_create_crs_to_crs_from_pj (PJ_CONTEXT *ctx, const PJ *source_crs, cons ctx->forceOver = forceOver; const int old_debug_level = ctx->debug_level; - if( errorIfBestTransformationNotAvailable ) + if( errorIfBestTransformationNotAvailable || ctx->warnIfBestTransformationNotAvailable ) ctx->debug_level = PJ_LOG_NONE; PJ* P = proj_list_get(ctx, op_list, 0); ctx->debug_level = old_debug_level; @@ -2031,7 +2045,8 @@ PJ *proj_create_crs_to_crs_from_pj (PJ_CONTEXT *ctx, const PJ *source_crs, cons ctx->forceOver = false; if( P != nullptr && - errorIfBestTransformationNotAvailable && + (errorIfBestTransformationNotAvailable || + ctx->warnIfBestTransformationNotAvailable) && !proj_coordoperation_is_instantiable(ctx, P) ) { std::string msg("Attempt to use coordinate operation "); @@ -2052,13 +2067,22 @@ PJ *proj_create_crs_to_crs_from_pj (PJ_CONTEXT *ctx, const PJ *source_crs, cons msg += " is not available."; } } - pj_log(ctx, PJ_LOG_ERROR, msg.c_str()); + if( ctx->warnIfBestTransformationNotAvailable ) + { + msg += " This will become an error in PROJ 10. " + "Set the ONLY_BEST option to YES or NO. " + "This warning will no longer be emitted (for the current context)."; + ctx->warnIfBestTransformationNotAvailable = false; + } + pj_log(ctx, + errorIfBestTransformationNotAvailable ? PJ_LOG_ERROR : PJ_LOG_WARNING, + msg.c_str()); } return P; } - if( errorIfBestTransformationNotAvailable ) + if( errorIfBestTransformationNotAvailable || ctx->warnIfBestTransformationNotAvailable ) ctx->debug_level = PJ_LOG_NONE; auto preparedOpList = pj_create_prepared_operations(ctx, source_crs, target_crs, op_list); diff --git a/src/apps/cs2cs.cpp b/src/apps/cs2cs.cpp index 81d412db8c..426d59414e 100644 --- a/src/apps/cs2cs.cpp +++ b/src/apps/cs2cs.cpp @@ -79,7 +79,7 @@ static const char *usage = "%s\nusage: %s [-dDeEfIlrstvwW [args]]\n" " [[--area name_or_code] | [--bbox west_long,south_lat,east_long,north_lat]]\n" " [--authority {name}] [--3d]\n" - " [--accuracy {accuracy}] [--only-best] [--no-ballpark]\n" + " [--accuracy {accuracy}] [--only-best[=yes|=no]] [--no-ballpark]\n" " [+opt[=arg] ...] [+to +opt[=arg] ...] [file ...]\n"; static double (*informat)(const char *, @@ -419,6 +419,7 @@ int main(int argc, char **argv) { const char* authority = nullptr; double accuracy = -1; bool allowBallpark = true; + bool onlyBestSet = false; bool errorIfBestTransformationNotAvailable = false; bool promoteTo3D = false; @@ -486,9 +487,15 @@ int main(int argc, char **argv) { else if (strcmp(*argv, "--no-ballpark") == 0 ) { allowBallpark = false; } - else if (strcmp(*argv, "--only-best") == 0 ) { + else if (strcmp(*argv, "--only-best") == 0 || + strcmp(*argv, "--only-best=yes") == 0 ) { + onlyBestSet = true; errorIfBestTransformationNotAvailable = true; } + else if (strcmp(*argv, "--only-best=no") == 0 ) { + onlyBestSet = true; + errorIfBestTransformationNotAvailable = false; + } else if (strcmp(*argv, "--3d") == 0 ) { promoteTo3D = true; } @@ -898,8 +905,13 @@ int main(int argc, char **argv) { if( !allowBallpark ) { options.push_back("ALLOW_BALLPARK=NO"); } - if( errorIfBestTransformationNotAvailable ) { - options.push_back("ONLY_BEST=YES"); + if( onlyBestSet ) { + if( errorIfBestTransformationNotAvailable ) { + options.push_back("ONLY_BEST=YES"); + } + else { + options.push_back("ONLY_BEST=NO"); + } } options.push_back(nullptr); transformation = proj_create_crs_to_crs_from_pj(nullptr, src, dst, diff --git a/src/ctx.cpp b/src/ctx.cpp index 0547e9fd63..4a0122c0d2 100644 --- a/src/ctx.cpp +++ b/src/ctx.cpp @@ -150,6 +150,7 @@ pj_ctx::pj_ctx(const pj_ctx& other) : lastFullErrorMessage(std::string()), last_errno(0), debug_level(other.debug_level), + warnIfBestTransformationNotAvailable(other.warnIfBestTransformationNotAvailable), logger(other.logger), logger_app_data(other.logger_app_data), cpp_context(other.cpp_context ? other.cpp_context->clone(this) : nullptr), diff --git a/src/proj_internal.h b/src/proj_internal.h index fafc85d8ae..fc43532655 100644 --- a/src/proj_internal.h +++ b/src/proj_internal.h @@ -695,6 +695,7 @@ struct pj_ctx{ std::string lastFullErrorMessage{}; // used by proj_context_errno_string int last_errno = 0; int debug_level = PJ_LOG_WARNING; + bool warnIfBestTransformationNotAvailable = true; /* to remove in PROJ 10 */ void (*logger)(void *, int, const char *) = nullptr; void *logger_app_data = nullptr; struct projCppContext* cpp_context = nullptr; /* internal context for C++ code */ diff --git a/test/cli/testvarious b/test/cli/testvarious index 454fd69df1..3e17762684 100755 --- a/test/cli/testvarious +++ b/test/cli/testvarious @@ -1089,6 +1089,20 @@ $EXE --only-best NTF RGF93 -E >>${OUT} 2>&1 <> ${OUT} +echo "Test cs2cs (grid missing)" >> ${OUT} +# +$EXE EPSG:4326+3855 EPSG:4979 -E >>${OUT} 2>&1 <> ${OUT} +echo "Test cs2cs --only-best=no (grid missing)" >> ${OUT} +# +$EXE --only-best=no EPSG:4326+3855 EPSG:4979 -E >>${OUT} 2>&1 <> ${OUT} echo "Test cs2cs --only-best (grid missing)" >> ${OUT} # @@ -1096,6 +1110,13 @@ $EXE --only-best EPSG:4326+3855 EPSG:4979 -E >>${OUT} 2>&1 <> ${OUT} +echo "Test cs2cs --only-best=yes (grid missing)" >> ${OUT} +# +$EXE --only-best=yes EPSG:4326+3855 EPSG:4979 -E >>${OUT} 2>&1 <> ${OUT} echo "Test cs2cs --only-best (grid missing)" >> ${OUT} # diff --git a/test/cli/tv_out.dist b/test/cli/tv_out.dist index dc94c95521..6466e270c9 100644 --- a/test/cli/tv_out.dist +++ b/test/cli/tv_out.dist @@ -532,10 +532,21 @@ program abnormally terminated Test cs2cs --only-best (working) 49 2 0 48d59'59.756"N 1d59'57.4"E 0.000 ############################################################## +Test cs2cs (grid missing) +Warning: Attempt to use coordinate operation Inverse of WGS 84 to EGM2008 height (1) failed. Grid us_nga_egm08_25.tif is not available. This will become an error in PROJ 10. Set the ONLY_BEST option to YES or NO. This warning will no longer be emitted (for the current context). +49 2 0 49dN 2dE 0.000 +############################################################## +Test cs2cs --only-best=no (grid missing) +49 2 0 49dN 2dE 0.000 +############################################################## Test cs2cs --only-best (grid missing) Attempt to use coordinate operation Inverse of WGS 84 to EGM2008 height (1) failed. Grid us_nga_egm08_25.tif is not available. 49 2 0 * * inf ############################################################## +Test cs2cs --only-best=yes (grid missing) +Attempt to use coordinate operation Inverse of WGS 84 to EGM2008 height (1) failed. Grid us_nga_egm08_25.tif is not available. +49 2 0 * * inf +############################################################## Test cs2cs --only-best (grid missing) Attempt to use coordinate operation NAD27 to NAD83 (7) failed. Grid us_noaa_nadcon5_nad27_nad83_1986_conus.tif is not available. 40 -100 0 * * inf