From fb69e67f8694fd61943cc9f9c2da75ec35ce9841 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Thu, 11 Jan 2018 16:34:47 +0100 Subject: Fail gracefully when invalid inverse operation is specified in cct. Similar to proj and cs2cs, cct now returns immediately when trying to do an inverse operation that is not possible, for example using proj=urm5 which doesn't have an inverse: $ cct.exe -I +proj=pipeline +step +proj=urm5 +n=0.5 Inverse operation not available --- src/cct.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/cct.c b/src/cct.c index f315ae1a..7e48311a 100644 --- a/src/cct.c +++ b/src/cct.c @@ -217,9 +217,15 @@ int main(int argc, char **argv) { return 1; } - /* We have no API call for inverting an operation, so we brute force it. */ - if (direction==-1) + if (direction==-1) { + /* fail if an inverse operation is not available */ + if (!proj_pj_info(P).has_inverse) { + fprintf (stderr, "Inverse operation not available\n"); + return 1; + } + /* We have no API call for inverting an operation, so we brute force it. */ P->inverted = !(P->inverted); + } direction = 1; /* Allocate input buffer */ -- cgit v1.2.3 From b6c8e417d71dca9ac04f57660da2c94a0a85e8ff Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Thu, 11 Jan 2018 16:40:01 +0100 Subject: Set inv*-functions to zero on pipeline PJ's where an inverse does not exist. Some projections do not have an inverse mapping. If such a projection is used as a (forward) step in a pipeline we won't be able to perform an inverse operation using the pipeline. By setting the inv, inv3d and inv4d pointers to zero we signal to the caller that an inverse mapping is not available. --- src/PJ_pipeline.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/PJ_pipeline.c b/src/PJ_pipeline.c index af9c5394..3dcc85d9 100644 --- a/src/PJ_pipeline.c +++ b/src/PJ_pipeline.c @@ -320,6 +320,7 @@ PJ *OPERATION(pipeline,0) { int i, nsteps = 0, argc; int i_pipeline = -1, i_first_step = -1, i_current_step; char **argv, **current_argv; + PJ *Q; P->fwd4d = pipeline_forward_4d; P->inv4d = pipeline_reverse_4d; @@ -429,14 +430,29 @@ PJ *OPERATION(pipeline,0) { /* Is this step inverted? */ for (j = 0; j < current_argc; j++) - if (0==strcmp("inv", current_argv[j])) + if (0==strcmp("inv", current_argv[j])) { next_step->inverted = 1; + } P->opaque->pipeline[i+1] = next_step; proj_log_trace (P, "Pipeline at [%p]: step at [%p] done", P, next_step); } + /* determine if an inverse operation is possible */ + for (i = 1; i <= nsteps; i++) { + Q = P->opaque->pipeline[i]; + if ( ( Q->inverted && (Q->fwd || Q->fwd3d || Q->fwd4d) ) || + ( Q->inv || Q->inv3d || Q->inv4d) ) { + continue; + } else { + P->inv = 0; + P->inv3d = 0; + P->inv4d = 0; + break; + } + } + proj_log_trace (P, "Pipeline: %d steps built. Determining i/o characteristics", nsteps); /* Determine forward input (= reverse output) data type */ -- cgit v1.2.3 From 9181fcfebde8a3969dc49100674f16286119059b Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Tue, 16 Jan 2018 13:16:18 +0100 Subject: Fix "double inversions" in pipelines, require a defined forward operation. "+proj=pipeline +inv +step +urm5 +n=0.5 +inv" now works as expected, returning the forward operation of urm5. In principle adding more +inv's should also work, resulting in the forward operation when an even number of +inv's are present, and the inverse when an odd number of +inv's are present. "+proj=pipeline +step +urm5 +n=0.5 +inv" fails at initialization since no forward operation can be performed. This is a new requirement, but aligns perfectly with the rest of the library since no operation without a forward method exists. --- src/PJ_pipeline.c | 18 +++++++++++++++--- test/gie/more_builtins.gie | 18 +++++++++++++++++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/PJ_pipeline.c b/src/PJ_pipeline.c index 3dcc85d9..befc8557 100644 --- a/src/PJ_pipeline.c +++ b/src/PJ_pipeline.c @@ -320,7 +320,6 @@ PJ *OPERATION(pipeline,0) { int i, nsteps = 0, argc; int i_pipeline = -1, i_first_step = -1, i_current_step; char **argv, **current_argv; - PJ *Q; P->fwd4d = pipeline_forward_4d; P->inv4d = pipeline_reverse_4d; @@ -431,7 +430,8 @@ PJ *OPERATION(pipeline,0) { /* Is this step inverted? */ for (j = 0; j < current_argc; j++) if (0==strcmp("inv", current_argv[j])) { - next_step->inverted = 1; + /* if +inv exists in both global and local args the forward operation should be used */ + next_step->inverted = next_step->inverted == 0 ? 1 : 0; } P->opaque->pipeline[i+1] = next_step; @@ -439,9 +439,21 @@ PJ *OPERATION(pipeline,0) { proj_log_trace (P, "Pipeline at [%p]: step at [%p] done", P, next_step); } + /* Require a forward path through the pipeline */ + for (i = 1; i <= nsteps; i++) { + PJ *Q = P->opaque->pipeline[i]; + if ( ( Q->inverted && (Q->inv || Q->inv3d || Q->fwd4d) ) || + (!Q->inverted && (Q->fwd || Q->fwd3d || Q->fwd4d) ) ) { + continue; + } else { + proj_log_error (P, "Pipeline: A forward operation couldn't be constructed"); + return destructor (P, PJD_ERR_MALFORMED_PIPELINE); + } + } + /* determine if an inverse operation is possible */ for (i = 1; i <= nsteps; i++) { - Q = P->opaque->pipeline[i]; + PJ *Q = P->opaque->pipeline[i]; if ( ( Q->inverted && (Q->fwd || Q->fwd3d || Q->fwd4d) ) || ( Q->inv || Q->inv3d || Q->inv4d) ) { continue; diff --git a/test/gie/more_builtins.gie b/test/gie/more_builtins.gie index 099934a7..00f584b4 100644 --- a/test/gie/more_builtins.gie +++ b/test/gie/more_builtins.gie @@ -115,10 +115,26 @@ expect 691875.63214 6098907.82501 0 0 direction inverse accept 12 55 0 0 expect 12 55 0 0 +------------------------------------------------------------------------------- +Test a few inversion scenarios (urm5 has no inverse operation) +------------------------------------------------------------------------------- +operation proj=pipeline step + proj=urm5 n=0.5 inv +expect failure pjd_err_malformed_pipeline +operation proj=pipeline inv step + proj=urm5 n=0.5 +expect failure pjd_err_malformed_pipeline +operation proj=pipeline inv step + proj=urm5 n=0.5 inv +accept 12 56 +expect 1215663.2814182492 5452209.5424045017 - +operation proj=pipeline step + proj=urm5 n=0.5 +accept 12 56 +expect 1215663.2814182492 5452209.5424045017 ------------------------------------------------------------------------------- Some tests from PJ_vgridshift.c -- cgit v1.2.3 From 046ce54719f3224b1b9299ee8d370cc92b0929af Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Tue, 16 Jan 2018 14:08:39 +0100 Subject: Adding a few more test cases for pipeline, ensuring better test coverage --- test/gie/more_builtins.gie | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/test/gie/more_builtins.gie b/test/gie/more_builtins.gie index 00f584b4..20bffbd9 100644 --- a/test/gie/more_builtins.gie +++ b/test/gie/more_builtins.gie @@ -65,7 +65,7 @@ roundtrip 100 1 m ------------------------------------------------------------------------------- Some tests from PJ_pipeline.c ------------------------------------------------------------------------------- -Forward-reverse geo->utm->geo +Forward-reverse geo->utm->geo (4D functions) ------------------------------------------------------------------------------- operation proj=pipeline zone=32 step proj=utm ellps=GRS80 step @@ -81,7 +81,7 @@ Now the inverse direction (still same result: the pipeline is symmetrical) direction inverse expect 12 55 0 0 ------------------------------------------------------------------------------- -And now the back-to-back situation utm->geo->utm +And now the back-to-back situation utm->geo->utm (4D functions) ------------------------------------------------------------------------------- operation proj=pipeline zone=32 ellps=GRS80 step proj=utm inv step @@ -92,6 +92,33 @@ expect 691875.63214 6098907.82501 0 0 direction inverse expect 691875.63214 6098907.82501 0 0 ------------------------------------------------------------------------------- +Forward-reverse geo->utm->geo (3D functions) +------------------------------------------------------------------------------- +operation proj=pipeline zone=32 step + proj=utm ellps=GRS80 step + proj=utm ellps=GRS80 inv +------------------------------------------------------------------------------- +tolerance 0.1 mm + +accept 12 55 0 +expect 12 55 0 + +Now the inverse direction (still same result: the pipeline is symmetrical) + +direction inverse +expect 12 55 0 +------------------------------------------------------------------------------- +And now the back-to-back situation utm->geo->utm (3D functions) +------------------------------------------------------------------------------- +operation proj=pipeline zone=32 ellps=GRS80 step + proj=utm inv step + proj=utm +------------------------------------------------------------------------------- +accept 691875.63214 6098907.82501 0 +expect 691875.63214 6098907.82501 0 +direction inverse +expect 691875.63214 6098907.82501 0 +------------------------------------------------------------------------------- Test a corner case: A rather pointless one-step pipeline geo->utm ------------------------------------------------------------------------------- operation proj=pipeline step proj=utm zone=32 ellps=GRS80 @@ -135,6 +162,20 @@ operation proj=pipeline step proj=urm5 n=0.5 accept 12 56 expect 1215663.2814182492 5452209.5424045017 +------------------------------------------------------------------------------- +Test various failing scenarios. +------------------------------------------------------------------------------- +operation proj=pipeline step + proj=pipeline step + proj=merc +expect failure pjd_err_malformed_pipeline + +operation step proj=pipeline step proj=merc +expect failure pjd_err_malformed_pipeline + +operation proj=pipeline +expect failure pjd_err_malformed_pipeline + ------------------------------------------------------------------------------- Some tests from PJ_vgridshift.c -- cgit v1.2.3