aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristian Evers <kristianevers@gmail.com>2017-10-28 15:42:00 +0200
committerGitHub <noreply@github.com>2017-10-28 15:42:00 +0200
commit0d0beff91ddfc2cc4d195a141524a139f3afb756 (patch)
tree4e0ff81f91f0cf96ba4c3f6e2fde8d86f97e4fec
parent1bb8efeb43e99dd0b032548abb9b390a63d12be6 (diff)
downloadPROJ-0d0beff91ddfc2cc4d195a141524a139f3afb756.tar.gz
PROJ-0d0beff91ddfc2cc4d195a141524a139f3afb756.zip
Allow nested pipelines. (#629)
Allow nested pipelines when wrapped in +init's. The previous behaviour was to quit pipeline initialization when encountering a nested pipeline definition. With this commit that behaviour is changed so that it is possible to nest pipelines as long as they are defined elsewhere in a init-file. This is useful in init-files where steps in complicated transformations can be grouped in "sub-pipelines". These "sub-pipelines" can then be used as individual steps in a larger and more complicated pipeline. Nested pipelines are governed by the following rules: 1. You can't have more than one literal +proj=pipeline in a proj-string 2. Pipelines can be nested if they are wrapped up in a +init 3. More than one +init is disallowed in non-pipeline proj-strings 4. +inits are expanded as late as possible, that is they will only be expanded in single operations (that can be a part of a pipeline)
-rw-r--r--src/PJ_pipeline.c2
-rw-r--r--src/pj_init.c96
-rw-r--r--src/pj_strerrno.c3
-rw-r--r--src/projects.h1
4 files changed, 62 insertions, 40 deletions
diff --git a/src/PJ_pipeline.c b/src/PJ_pipeline.c
index ab2d3420..f1411cb4 100644
--- a/src/PJ_pipeline.c
+++ b/src/PJ_pipeline.c
@@ -380,7 +380,7 @@ PJ *PROJECTION(pipeline) {
if (0==strcmp ("proj=pipeline", argv[i])) {
if (-1 != i_pipeline) {
- proj_log_error (P, "Pipeline: Nesting invalid");
+ proj_log_error (P, "Pipeline: Nesting only allowed when child pipelines are wrapped in +init's");
return destructor (P, PJD_ERR_MALFORMED_PIPELINE); /* ERROR: nested pipelines */
}
i_pipeline = i;
diff --git a/src/pj_init.c b/src/pj_init.c
index 704a8b55..2a945397 100644
--- a/src/pj_init.c
+++ b/src/pj_init.c
@@ -381,8 +381,9 @@ pj_init_plus_ctx( projCtx ctx, const char *definition )
if( argc+1 == MAX_ARG )
{
- pj_ctx_set_errno( ctx, -44 );
- goto bum_call;
+ pj_dalloc( defn_copy );
+ pj_ctx_set_errno( ctx, PJD_ERR_UNPARSEABLE_CS_DEF );
+ return 0;
}
argv[argc++] = defn_copy + i + 1;
@@ -410,9 +411,7 @@ pj_init_plus_ctx( projCtx ctx, const char *definition )
/* perform actual initialization */
result = pj_init_ctx( ctx, argc, argv );
-bum_call:
pj_dalloc( defn_copy );
-
return result;
}
@@ -441,6 +440,8 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) {
int i;
int found_def = 0;
PJ *PIN = 0;
+ int n_pipelines = 0;
+ int n_inits = 0;
if (0==ctx)
ctx = pj_get_default_ctx ();
@@ -452,36 +453,45 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) {
pj_ctx_set_errno (ctx, PJD_ERR_NO_ARGS);
return 0;
}
-
+
+ /* count occurrences of pipelines and inits */
+ for (i = 0; i < argc; ++i) {
+ if (!strcmp (argv[i], "+proj=pipeline") || !strcmp(argv[i], "proj=pipeline") )
+ n_pipelines++;
+ if (!strncmp (argv[i], "+init=", 6) || !strncmp(argv[i], "init=", 5))
+ n_inits++;
+ }
+
+ /* can't have nested pipeline directly */
+ if (n_pipelines > 1) {
+ pj_ctx_set_errno (ctx, PJD_ERR_MALFORMED_PIPELINE);
+ return 0;
+ }
+
+ /* don't allow more than one +init in non-pipeline operations */
+ if (n_pipelines == 0 && n_inits > 1) {
+ pj_ctx_set_errno (ctx, PJD_ERR_TOO_MANY_INITS);
+ return 0;
+ }
+
/* put arguments into internal linked list */
start = curr = pj_mkparam(argv[0]);
if (!curr)
return pj_dealloc_params (ctx, start, ENOMEM);
- /* build parameter list and expand +init's. Does not take care of a single +init. */
for (i = 1; i < argc; ++i) {
curr->next = pj_mkparam(argv[i]);
if (!curr->next)
return pj_dealloc_params (ctx, start, ENOMEM);
-
- /* check if +init present */
- if (pj_param(ctx, curr, "tinit").i) {
- found_def = 0;
- curr = get_init(ctx, &curr, curr->next, pj_param(ctx, curr, "sinit").s, &found_def);
- if (!curr)
- return pj_dealloc_params (ctx, start, PJD_ERR_NO_ARGS);
-
- if (!found_def)
- return pj_dealloc_params (ctx, start, PJD_ERR_NO_OPTION_IN_INIT_FILE);
-
- } else {
- curr = curr->next;
- }
+ curr = curr->next;
}
- /* in case the parameter list only consist of a +init parameter
- it is expanded here (will not be handled in the above loop). */
- if (pj_param(ctx, start, "tinit").i && argc == 1) {
+
+ /* Only expand +init's in non-pipeline operations. +init's in pipelines are */
+ /* expanded in the individual pipeline steps during pipeline initialization. */
+ /* Potentially this leads to many nested pipelines, which shouldn't be a */
+ /* problem when +inits are expanded as late as possible. */
+ if (pj_param(ctx, start, "tinit").i && n_pipelines == 0) {
found_def = 0;
curr = get_init(ctx, &start, curr, pj_param(ctx, start, "sinit").s, &found_def);
if (!curr)
@@ -489,10 +499,10 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) {
if (!found_def)
return pj_dealloc_params (ctx, start, PJD_ERR_NO_OPTION_IN_INIT_FILE);
}
-
+
if (ctx->last_errno)
return pj_dealloc_params (ctx, start, ctx->last_errno);
-
+
/* find projection selection */
if (!(name = pj_param(ctx, start, "sproj").s))
return pj_default_destructor (PIN, PJD_ERR_PROJ_NOT_NAMED);
@@ -500,10 +510,11 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) {
if (!s)
return pj_dealloc_params (ctx, start, PJD_ERR_UNKNOWN_PROJECTION_ID);
-
- /* set defaults, unless inhibited */
- if (!(pj_param(ctx, start, "bno_defs").i))
- curr = get_defaults(ctx,&start, curr, name);
+
+ /* set defaults, unless inhibited or we are initializing a pipeline */
+ if (!(pj_param(ctx, start, "bno_defs").i) && n_pipelines == 0)
+ curr = get_defaults(ctx,&start, curr, name);
+
proj = (PJ *(*)(PJ *)) pj_list[i].proj;
/* allocate projection structure */
@@ -511,6 +522,7 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) {
if (0==PIN)
return pj_dealloc_params (ctx, start, ENOMEM);
+
PIN->ctx = ctx;
PIN->params = start;
PIN->is_latlong = 0;
@@ -526,13 +538,21 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) {
PIN->vgridlist_geoid_count = 0;
/* set datum parameters */
- if (pj_datum_set(ctx, start, PIN))
+ if (pj_datum_set(ctx, start, PIN))
return pj_default_destructor (PIN, PJD_ERR_MISSING_ARGS);
- /* set ellipsoid/sphere parameters */
- if (pj_ell_set(ctx, start, &PIN->a, &PIN->es)) {
- pj_log (ctx, PJ_LOG_DEBUG_MINOR, "pj_init_ctx: Must specify ellipsoid or sphere");
- return pj_default_destructor (PIN, PJD_ERR_MISSING_ARGS);
+ /* set ellipsoid/sphere parameters. If we are initializing a pipeline we */
+ /* override ellipsoid-setter, since it also adds a "+ellps=WGS84" to the */
+ /* parameter list which creates problems when the pipeline driver passes */
+ /* the global parameters on the it's children. */
+ if (n_pipelines > 0) {
+ PIN->a = 6378137.0;
+ PIN->es = .00669438002290341575;
+ } else {
+ if (pj_ell_set(ctx, start, &PIN->a, &PIN->es)) {
+ pj_log (ctx, PJ_LOG_DEBUG_MINOR, "pj_init_ctx: Must specify ellipsoid or sphere");
+ return pj_default_destructor (PIN, PJD_ERR_MISSING_ARGS);
+ }
}
PIN->a_orig = PIN->a;
@@ -606,7 +626,7 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) {
if( !(fabs(PIN->long_wrap_center) < 10 * M_TWOPI) )
return pj_default_destructor (PIN, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT);
}
-
+
/* axis orientation */
if( (pj_param(ctx, start,"saxis").s) != NULL )
{
@@ -619,7 +639,7 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) {
|| strchr( axis_legal, axis_arg[1] ) == NULL
|| strchr( axis_legal, axis_arg[2] ) == NULL)
return pj_default_destructor (PIN, PJD_ERR_AXIS);
-
+
/* it would be nice to validate we don't have on axis repeated */
strcpy( PIN->axis, axis_arg );
}
@@ -643,7 +663,7 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) {
PIN->k0 = pj_param(ctx, start, "dk").f;
else
PIN->k0 = 1.;
- if (PIN->k0 <= 0.)
+ if (PIN->k0 <= 0.)
return pj_default_destructor (PIN, PJD_ERR_K_LESS_THAN_ZERO);
/* set units */
@@ -704,7 +724,7 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) {
&& *next_str == '\0' )
value = name;
- if (!value)
+ if (!value)
return pj_default_destructor (PIN, PJD_ERR_UNKNOWN_PRIME_MERIDIAN);
PIN->from_greenwich = dmstor_ctx(ctx,value,NULL);
}
diff --git a/src/pj_strerrno.c b/src/pj_strerrno.c
index 89a5a025..fe137b87 100644
--- a/src/pj_strerrno.c
+++ b/src/pj_strerrno.c
@@ -62,7 +62,8 @@ pj_err_list[] = {
"missing required arguments", /* -54 */
"lat_0 = 0", /* -55 */
"ellipsoidal usage unsupported", /* -56 */
-
+ "only one +init allowed for non-pipeline operations", /* -57 */
+
/* When adding error messages, remember to update ID defines in
projects.h, and transient_error array in pj_transform */
};
diff --git a/src/projects.h b/src/projects.h
index 1fe595bc..6ea0c914 100644
--- a/src/projects.h
+++ b/src/projects.h
@@ -532,6 +532,7 @@ struct FACTORS {
#define PJD_ERR_MISSING_ARGS -54
#define PJD_ERR_LAT_0_IS_ZERO -55
#define PJD_ERR_ELLIPSOIDAL_UNSUPPORTED -56
+#define PJD_ERR_TOO_MANY_INITS -57
struct projFileAPI_t;