aboutsummaryrefslogtreecommitdiff
path: root/src/PJ_pipeline.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/PJ_pipeline.c')
-rw-r--r--src/PJ_pipeline.c164
1 files changed, 90 insertions, 74 deletions
diff --git a/src/PJ_pipeline.c b/src/PJ_pipeline.c
index c8ce8582..25c7a953 100644
--- a/src/PJ_pipeline.c
+++ b/src/PJ_pipeline.c
@@ -51,12 +51,9 @@
pj_init code, implementing support for multilevel, embedded pipelines.
Syntactically, the pipeline system introduces the "+step" keyword (which
- indicates the start of each transformation step), the "+omit_fwd" and
- "+omit_inv" keywords (which indicate that a given transformation step
- should be omitted when the pipeline is executed in forward, resp. inverse
- direction), and reintroduces the +inv keyword (indicating that a given
- transformation step should run in reverse, i.e. forward, when the pipeline
- is executed in inverse direction, and vice versa).
+ indicates the start of each transformation step), and reintroduces the +inv
+ keyword (indicating that a given transformation step should run in reverse, i.e.
+ forward, when the pipeline is executed in inverse direction, and vice versa).
Hence, the first transformation example above, can be implemented as:
@@ -75,7 +72,7 @@
Thomas Knudsen, thokn@sdfe.dk, 2016-05-20
********************************************************************************
-* Copyright (c) 2016, Thomas Knudsen / SDFE
+* Copyright (c) 2016, 2017, 2018 Thomas Knudsen / SDFE
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -99,6 +96,7 @@ Thomas Knudsen, thokn@sdfe.dk, 2016-05-20
#define PJ_LIB__
#include <geodesic.h>
+#include <proj.h>
#include "proj_internal.h"
#include "projects.h"
@@ -110,7 +108,6 @@ PROJ_HEAD(pipeline, "Transformation pipeline manager");
struct pj_opaque {
int reversible;
int steps;
- int verbose;
char **argv;
char **current_argv;
PJ **pipeline;
@@ -127,52 +124,6 @@ static LP pipeline_reverse (XY xyz, PJ *P);
-/********************************************************************
-
- ISOMORPHIC TRANSFORMATIONS
-
-*********************************************************************
-
- In this context, an isomorphic transformation is a proj PJ
- object returning the same kind of coordinates that it
- receives, i.e. a transformation from angular to angular or
- linear to linear coordinates.
-
- The degrees-to-radians operation is an example of the former,
- while the latter is typical for most of the datum shift
- operations used in geodesy, e.g. the Helmert 7-parameter shift.
-
- Isomorphic transformations trips up the pj_inv/pj_fwd
- functions, which try to check input sanity and scale output to
- internal proj units, under the assumption that if input is of
- angular type, then output must be of linear (or vice versa).
-
- Hence, to avoid having pj_inv/pj_fwd stomping on output (or
- choking on input), we need a way to tell them that they should
- accept whatever is being handed to them.
-
- The P->left and P->right elements indicate isomorphism.
-
- For classic proj style projections, P->left has the value
- PJ_IO_UNITS_RADIANS, while P->right has the value
- PJ_IO_UNITS_CLASSIC, indicating that the forward driver expects
- angular input coordinates, and provides linear output coordinates,
- scaled by the P->a semimajor axis length.
-
- Newer projections may set P->left and P->right to either
- PJ_IO_UNITS_METERS, PJ_IO_UNITS_RADIANS or PJ_IO_UNITS_ANY,
- to indicate their I/O style.
-
- For the forward driver, left indicates input coordinate
- type, while right indicates output coordinate type.
-
- For the inverse driver, left indicates output coordinate
- type, while right indicates input coordinate type.
-
-*********************************************************************/
-
-
-
static PJ_COORD pipeline_forward_4d (PJ_COORD point, PJ *P) {
int i, first_step, last_step;
@@ -187,7 +138,6 @@ static PJ_COORD pipeline_forward_4d (PJ_COORD point, PJ *P) {
}
-
static PJ_COORD pipeline_reverse_4d (PJ_COORD point, PJ *P) {
int i, first_step, last_step;
@@ -201,37 +151,59 @@ static PJ_COORD pipeline_reverse_4d (PJ_COORD point, PJ *P) {
}
-/* Delegate the work to pipeline_forward_4d() */
+
+
static XYZ pipeline_forward_3d (LPZ lpz, PJ *P) {
PJ_COORD point = {{0,0,0,0}};
+ int i;
point.lpz = lpz;
- point = pipeline_forward_4d (point, P);
+
+ for (i = 1; i <= P->opaque->steps; i++)
+ point = pj_approx_3D_trans (P->opaque->pipeline[i], 1, point);
+
return point.xyz;
}
-/* Delegate the work to pipeline_reverse_4d() */
+
static LPZ pipeline_reverse_3d (XYZ xyz, PJ *P) {
PJ_COORD point = {{0,0,0,0}};
+ int i;
point.xyz = xyz;
- point = pipeline_reverse_4d (point, P);
+
+ for (i = P->opaque->steps; i > 0 ; i--)
+ point = pj_approx_3D_trans (P->opaque->pipeline[i], -1, point);
+
return point.lpz;
}
+
+
+
static XY pipeline_forward (LP lp, PJ *P) {
PJ_COORD point = {{0,0,0,0}};
+ int i;
point.lp = lp;
- point = pipeline_forward_4d (point, P);
+
+ for (i = 1; i <= P->opaque->steps; i++)
+ point = pj_approx_2D_trans (P->opaque->pipeline[i], 1, point);
+
return point.xy;
}
+
static LP pipeline_reverse (XY xy, PJ *P) {
PJ_COORD point = {{0,0,0,0}};
+ int i;
point.xy = xy;
- point = pipeline_reverse_4d (point, P);
+ for (i = P->opaque->steps; i > 0 ; i--)
+ point = pj_approx_2D_trans (P->opaque->pipeline[i], -1, point);
+
return point.lp;
}
+
+
static void *destructor (PJ *P, int errlev) {
int i;
if (0==P)
@@ -243,8 +215,7 @@ static void *destructor (PJ *P, int errlev) {
/* Deallocate each pipeine step, then pipeline array */
if (0!=P->opaque->pipeline)
for (i = 0; i < P->opaque->steps; i++)
- if (0!=P->opaque->pipeline[i+1])
- P->opaque->pipeline[i+1]->destructor (P->opaque->pipeline[i+1], errlev);
+ proj_destroy (P->opaque->pipeline[i+1]);
pj_dealloc (P->opaque->pipeline);
pj_dealloc (P->opaque->argv);
@@ -267,16 +238,20 @@ static PJ *pj_create_pipeline (PJ *P, size_t steps) {
}
-/* count the number of args in pipeline definition */
+
+
+/* count the number of args in pipeline definition, and mark all args as used */
static size_t argc_params (paralist *params) {
size_t argc = 0;
- for (; params != 0; params = params->next)
+ for (; params != 0; params = params->next) {
argc++;
+ params->used = 1;
+ }
return ++argc; /* one extra for the sentinel */
}
/* Sentinel for argument list */
-static char argv_sentinel[] = "step";
+static char *argv_sentinel = "step";
/* turn paralist into argc/argv style argument list */
static char **argv_params (paralist *params, size_t argc) {
@@ -291,6 +266,9 @@ static char **argv_params (paralist *params, size_t argc) {
return argv;
}
+
+
+
/* Being the special operator that the pipeline is, we have to handle the */
/* ellipsoid differently than usual. In general, the pipeline operation does */
/* not need an ellipsoid, but in some cases it is beneficial nonetheless. */
@@ -338,18 +316,29 @@ static void set_ellipsoid(PJ *P) {
}
+
+
PJ *OPERATION(pipeline,0) {
int i, nsteps = 0, argc;
int i_pipeline = -1, i_first_step = -1, i_current_step;
char **argv, **current_argv;
- P->fwd4d = pipeline_forward_4d;
- P->inv4d = pipeline_reverse_4d;
+ P->fwd4d = pipeline_forward_4d;
+ P->inv4d = pipeline_reverse_4d;
P->fwd3d = pipeline_forward_3d;
P->inv3d = pipeline_reverse_3d;
P->fwd = pipeline_forward;
P->inv = pipeline_reverse;
P->destructor = destructor;
+ P->is_pipeline = 1;
+
+ /* Currently, the pipeline driver is a raw bit mover, enabling other operations */
+ /* to collaborate efficiently. All prep/fin stuff is done at the step levels. */
+ P->skip_fwd_prepare = 1;
+ P->skip_fwd_finalize = 1;
+ P->skip_inv_prepare = 1;
+ P->skip_inv_finalize = 1;
+
P->opaque = pj_calloc (1, sizeof(struct pj_opaque));
if (0==P->opaque)
@@ -366,7 +355,7 @@ PJ *OPERATION(pipeline,0) {
/* Do some syntactical sanity checking */
for (i = 0; i < argc; i++) {
- if (0==strcmp ("step", argv[i])) {
+ if (0==strcmp (argv_sentinel, argv[i])) {
if (-1==i_pipeline) {
proj_log_error (P, "Pipeline: +step before +proj=pipeline");
return destructor (P, PJD_ERR_MALFORMED_PIPELINE);
@@ -379,7 +368,7 @@ PJ *OPERATION(pipeline,0) {
if (0==strcmp ("proj=pipeline", argv[i])) {
if (-1 != i_pipeline) {
- proj_log_error (P, "Pipeline: Nesting only allowed when child pipelines are wrapped in +init's");
+ 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;
@@ -427,7 +416,7 @@ PJ *OPERATION(pipeline,0) {
err = proj_errno_reset (P);
next_step = proj_create_argv (P->ctx, current_argc, current_argv);
- proj_log_trace (P, "Pipeline: Step %d at %p", i, next_step);
+ proj_log_trace (P, "Pipeline: Step %d (%s) at %p", i, current_argv[0], next_step);
if (0==next_step) {
/* The step init failed, but possibly without setting errno. If so, we say "malformed" */
@@ -442,12 +431,39 @@ 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 (0==strcmp("inv", current_argv[j])) {
+ /* 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;
- proj_log_trace (P, "Pipeline at [%p]: step at [%p] done", P, next_step);
+ proj_log_trace (P, "Pipeline at [%p]: step at [%p] (%s) done", P, next_step, current_argv[0]);
+ }
+
+ /* 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++) {
+ PJ *Q = P->opaque->pipeline[i];
+ if ( pj_has_inverse(Q) ) {
+ 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);