aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am2
-rw-r--r--src/PJ_axisswap.c243
-rw-r--r--src/lib_proj.cmake1
-rw-r--r--src/makefile.vc3
-rw-r--r--src/pj_list.h1
-rw-r--r--test/gie/axisswap.gie67
-rwxr-xr-xtravis/install.sh1
7 files changed, 315 insertions, 3 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 0bfcfb24..7edc05b1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -87,7 +87,7 @@ libproj_la_SOURCES = \
\
proj_4D_api.c PJ_cart.c PJ_pipeline.c PJ_horner.c PJ_helmert.c \
PJ_vgridshift.c PJ_hgridshift.c PJ_unitconvert.c PJ_molodensky.c \
- PJ_deformation.c pj_internal.c
+ PJ_deformation.c pj_internal.c PJ_axisswap.c
install-exec-local:
rm -f $(DESTDIR)$(bindir)/invproj$(EXEEXT)
diff --git a/src/PJ_axisswap.c b/src/PJ_axisswap.c
new file mode 100644
index 00000000..42c0d779
--- /dev/null
+++ b/src/PJ_axisswap.c
@@ -0,0 +1,243 @@
+/***********************************************************************
+
+ Axis order operation for use with transformation pipelines.
+
+ Kristian Evers, kreve@sdfe.dk, 2017-10-31
+
+************************************************************************
+
+Change the order and sign of 2,3 or 4 axes. Each of the possible four
+axes are numbered with 1-4, such that the first input axis is 1, the
+second is 2 and so on. The output ordering is controlled by a list of the
+input axes re-ordered to the new mapping. Examples:
+
+Reversing the order of the axes:
+
+ +proj=axisswap +order=4,3,2,1
+
+Swapping the first two axes (x and y):
+
+ +proj=axisswap +order=2,1,3,4
+
+The direction, or sign, of an axis can be changed by adding a minus in
+front of the axis-number:
+
+ +proj=axisswap +order=1,-2,3,4
+
+It is only necessary to specify the axes that are affected by the swap
+operation:
+
+ +proj=axisswap +order=2,1
+
+************************************************************************
+* Copyright (c) 2017, Kristian Evers / SDFE
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included
+* in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*
+***********************************************************************/
+
+#define PJ_LIB__
+#include <errno.h>
+#include "proj_internal.h"
+#include "projects.h"
+
+PROJ_HEAD(axisswap, "Axis ordering");
+
+struct pj_opaque {
+ unsigned int axis[4];
+ int sign[4];
+};
+
+static int sign(int x) {
+ return (x > 0) - (x < 0);
+}
+
+static XY forward_2d(LP lp, PJ *P) {
+ struct pj_opaque *Q = (struct pj_opaque *) P->opaque;
+ unsigned int i;
+ PJ_COORD out, in;
+
+ in.lp = lp;
+ out = proj_coord_error();
+
+ for (i=0; i<2; i++)
+ out.v[i] = in.v[Q->axis[i]] * Q->sign[i];
+
+ return out.xy;
+}
+
+
+static LP reverse_2d(XY xy, PJ *P) {
+ struct pj_opaque *Q = (struct pj_opaque *) P->opaque;
+ unsigned int i;
+ PJ_COORD out, in;
+
+ in.xy = xy;
+ out = proj_coord_error();
+
+ for (i=0; i<2; i++)
+ out.v[Q->axis[i]] = in.v[i] * Q->sign[i];
+
+ return out.lp;
+}
+
+
+static XYZ forward_3d(LPZ lpz, PJ *P) {
+ struct pj_opaque *Q = (struct pj_opaque *) P->opaque;
+ unsigned int i;
+ PJ_COORD out, in;
+
+ in.lpz = lpz;
+ out = proj_coord_error();
+
+ for (i=0; i<3; i++)
+ out.v[i] = in.v[Q->axis[i]] * Q->sign[i];
+
+ return out.xyz;
+}
+
+static LPZ reverse_3d(XYZ xyz, PJ *P) {
+ struct pj_opaque *Q = (struct pj_opaque *) P->opaque;
+ unsigned int i;
+ PJ_COORD in, out;
+
+ out = proj_coord_error();
+ in.xyz = xyz;
+
+ for (i=0; i<3; i++)
+ out.v[Q->axis[i]] = in.v[i] * Q->sign[i];
+
+ return out.lpz;
+}
+
+
+static PJ_OBS forward_obs(PJ_OBS obs, PJ *P) {
+ struct pj_opaque *Q = (struct pj_opaque *) P->opaque;
+ unsigned int i;
+ PJ_COORD in, out;
+
+ out = proj_coord_error();
+ in = obs.coo;
+
+ for (i=0; i<4; i++)
+ out.v[i] = in.v[Q->axis[i]] * Q->sign[i];
+
+ obs.coo = out;
+ return obs;
+}
+
+
+static PJ_OBS reverse_obs(PJ_OBS obs, PJ *P) {
+ struct pj_opaque *Q = (struct pj_opaque *) P->opaque;
+ unsigned int i;
+ PJ_COORD in, out;
+
+ out = proj_coord_error();
+ in = obs.coo;
+
+ for (i=0; i<4; i++) {
+ out.v[Q->axis[i]] = in.v[i] * Q->sign[i];
+ }
+
+ obs.coo = out;
+ return obs;
+}
+
+
+/***********************************************************************/
+PJ *PROJECTION(axisswap) {
+/***********************************************************************/
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ char *order, *s;
+ unsigned int i, j, n;
+
+ if (0==Q)
+ return pj_default_destructor (P, ENOMEM);
+ P->opaque = (void *) Q;
+
+ /* read axis order */
+ if (pj_param (P->ctx, P->params, "torder").i) {
+ order = pj_param(P->ctx, P->params, "sorder").s;
+ } else {
+ return pj_default_destructor(P, PJD_ERR_MISSING_ARGS);
+ }
+
+ /* fill axis list with indices from 4-7 to simplify duplicate search further down */
+ for (i=0; i<4; i++)
+ Q->axis[i] = i+4;
+
+ /* check that all characteds are valid */
+ for (i=0; i<strlen(order); i++)
+ if (strchr("1234-,", order[i]) == 0) {
+ proj_log_error(P, "axisswap: unknown axis '%c'", order[i]);
+ return pj_default_destructor(P, PJD_ERR_AXIS);
+ }
+
+ /* read axes numbers and signs */
+ for( s = order, n = 0; *s != '\0' && n < 4; ) {
+ Q->axis[n] = abs(atoi(s))-1;
+ Q->sign[n++] = sign(atoi(s));
+ while( *s != '\0' && *s != ',' )
+ s++;
+ if( *s == ',' )
+ s++;
+ }
+
+ /* check for duplicate axes */
+ for (i=0; i<4; i++)
+ for (j=0; j<4; j++) {
+ if (i==j)
+ continue;
+ if (Q->axis[i] == Q->axis[j]) {
+ proj_log_error(P, "swapaxis: duplicate axes specified");
+ return pj_default_destructor(P, PJD_ERR_AXIS);
+ }
+ }
+
+ /* only map fwd/inv functions that are possible with the given axis setup */
+ if (n == 4) {
+ P->fwdobs = forward_obs;
+ P->invobs = reverse_obs;
+ }
+ if (n == 3 && Q->axis[0] < 3 && Q->axis[1] < 3 && Q->axis[2] < 3) {
+ P->fwd3d = forward_3d;
+ P->inv3d = reverse_3d;
+ }
+ if (n == 2 && Q->axis[0] < 2 && Q->axis[1] < 2) {
+ P->fwd = forward_2d;
+ P->inv = reverse_2d;
+ }
+
+ if (P->fwdobs == NULL && P->fwd3d == NULL && P->fwd == NULL) {
+ proj_log_error(P, "swapaxis: bad axis order");
+ return pj_default_destructor(P, PJD_ERR_AXIS);
+ }
+
+ if (pj_param(P->ctx, P->params, "tangularunits").i) {
+ P->left = PJ_IO_UNITS_RADIANS;
+ P->right = PJ_IO_UNITS_RADIANS;
+ } else {
+ P->left = PJ_IO_UNITS_METERS;
+ P->right = PJ_IO_UNITS_METERS;
+ }
+
+ return P;
+}
+
+int pj_axisswap_selftest (void) {return 10000;}
diff --git a/src/lib_proj.cmake b/src/lib_proj.cmake
index 969ad64b..4b701886 100644
--- a/src/lib_proj.cmake
+++ b/src/lib_proj.cmake
@@ -45,6 +45,7 @@ SET(SRC_LIBPROJ_PJ
PJ_airy.c
PJ_aitoff.c
PJ_august.c
+ PJ_axisswap.c
PJ_bacon.c
PJ_bipc.c
PJ_boggs.c
diff --git a/src/makefile.vc b/src/makefile.vc
index edb683b0..ae2dc587 100644
--- a/src/makefile.vc
+++ b/src/makefile.vc
@@ -62,8 +62,7 @@ support = \
pipeline = \
proj_4D_api.obj PJ_cart.obj PJ_pipeline.obj PJ_horner.obj PJ_helmert.obj \
PJ_vgridshift.obj PJ_hgridshift.obj PJ_unitconvert.obj PJ_molodensky.obj \
- PJ_deformation.obj
-
+ PJ_deformation.obj PJ_axisswap.obj
geodesic = geodesic.obj
diff --git a/src/pj_list.h b/src/pj_list.h
index 76c37126..0720b456 100644
--- a/src/pj_list.h
+++ b/src/pj_list.h
@@ -12,6 +12,7 @@ PROJ_HEAD(aitoff, "Aitoff")
PROJ_HEAD(alsk, "Mod. Stererographics of Alaska")
PROJ_HEAD(apian, "Apian Globular I")
PROJ_HEAD(august, "August Epicycloidal")
+PROJ_HEAD(axisswap, "Axis ordering")
PROJ_HEAD(bacon, "Bacon Globular")
PROJ_HEAD(bipc, "Bipolar conic of western hemisphere")
PROJ_HEAD(boggs, "Boggs Eumorphic")
diff --git a/test/gie/axisswap.gie b/test/gie/axisswap.gie
new file mode 100644
index 00000000..409af742
--- /dev/null
+++ b/test/gie/axisswap.gie
@@ -0,0 +1,67 @@
+-------------------------------------------------------------------------------
+ Tests for the axisswap operation
+-------------------------------------------------------------------------------
+
+BEGIN
+
+OPERATION +proj=axisswap +order=1,2,3,4
+TOLERANCE 0.000001 m
+ACCEPT 1 2 3 4
+EXPECT 1 2 3 4
+ROUNDTRIP 100
+
+OPERATION +proj=axisswap +order=4,3,2,1
+TOLERANCE 0.000001 m
+ACCEPT 1 2 3 4
+EXPECT 4 3 2 1
+ROUNDTRIP 100
+
+OPERATION +proj=axisswap +order=-1,-2,-3,-4
+TOLERANCE 0.000001 m
+ACCEPT 1 2 3 4
+EXPECT -1 -2 -3 -4
+ROUNDTRIP 100
+
+OPERATION +proj=axisswap +order=1,2,-3,4
+TOLERANCE 0.000001 m
+ACCEPT 1 2 3 4
+EXPECT 1 2 -3 4
+ROUNDTRIP 100
+
+OPERATION +proj=axisswap +order=-1,2,3,4
+TOLERANCE 0.000001 m
+ACCEPT 1 2 3 4
+EXPECT -1 2 3 4
+ROUNDTRIP 100
+
+OPERATION +proj=axisswap +order=1,2,3,-4
+TOLERANCE 0.000001 m
+ACCEPT 1 2 3 4
+EXPECT 1 2 3 -4
+ROUNDTRIP 100
+
+OPERATION +proj=axisswap +order=-2,1
+TOLERANCE 0.000001 m
+ACCEPT 1 2 3 4
+EXPECT -2 1 3 4
+ROUNDTRIP 100
+$
+OPERATION +proj=axisswap +order=3,-2,1
+TOLERANCE 0.000001 m
+ACCEPT 1 2 3 4
+EXPECT 3 -2 1 4
+ROUNDTRIP 100
+
+
+
+OPERATION +proj=pipeline +step +proj=latlong +step +proj=axisswap +order=1,2,3,4 +angularunits
+TOLERANCE 0.00001 m
+ACCEPT 12 55 0 0
+EXPECT 12 55 0 0
+
+OPERATION +proj=pipeline +step +proj=latlong +step +proj=axisswap +order=-2,-1,3,4 +angularunits
+TOLERANCE 0.00001 m
+ACCEPT 12 55 0 0
+EXPECT -55 -12 0 0
+
+END
diff --git a/travis/install.sh b/travis/install.sh
index 62c2677f..a96a151f 100755
--- a/travis/install.sh
+++ b/travis/install.sh
@@ -83,6 +83,7 @@ make check
PROJ_LIB=$GRIDDIR ./src/proj -VC
PROJ_LIB=$GRIDDIR ./src/gie ./test/gie/builtins.gie
PROJ_LIB=$GRIDDIR ./src/gie ./test/gie/deformation.gie
+PROJ_LIB=$GRIDDIR ./src/gie ./test/gie/axisswap.gie
# install & run the working GIGS test
# create locations that pyproj understands