aboutsummaryrefslogtreecommitdiff
path: root/src/PJ_aitoff.c
diff options
context:
space:
mode:
authorThomas Knudsen <lastname DOT firstname AT gmail DOT com>2016-04-05 23:56:01 +0200
committerThomas Knudsen <lastname DOT firstname AT gmail DOT com>2016-04-05 23:56:01 +0200
commit77f8c2947b934d64293da614bf7b8b8e0f90031b (patch)
treeae767e1a7213ff8882f7910e84489a785506fc90 /src/PJ_aitoff.c
parent2cd5e4f988e7f2d89f259ad2f3ac69be825acb75 (diff)
downloadPROJ-77f8c2947b934d64293da614bf7b8b8e0f90031b.tar.gz
PROJ-77f8c2947b934d64293da614bf7b8b8e0f90031b.zip
Added regression tests for projections beginning with a and b
Continuing alphabetically, with a few detours due to the occasional case of more than one projection in one source file.
Diffstat (limited to 'src/PJ_aitoff.c')
-rw-r--r--src/PJ_aitoff.c223
1 files changed, 183 insertions, 40 deletions
diff --git a/src/PJ_aitoff.c b/src/PJ_aitoff.c
index d5350f2c..6c766e5a 100644
--- a/src/PJ_aitoff.c
+++ b/src/PJ_aitoff.c
@@ -2,7 +2,9 @@
* Project: PROJ.4
* Purpose: Implementation of the aitoff (Aitoff) and wintri (Winkel Tripel)
* projections.
- * Author: Gerald Evenden
+ * Author: Gerald Evenden (1995)
+ * Drazen Tutic, Lovro Gradiser (2015) - add inverse
+ * Thomas Knudsen (2016) - revise/add regression tests
*
******************************************************************************
* Copyright (c) 1995, Gerald Evenden
@@ -26,12 +28,15 @@
* DEALINGS IN THE SOFTWARE.
*****************************************************************************/
-#define PROJ_PARMS__ \
- double cosphi1; \
- int mode;
#define PJ_LIB__
#include <projects.h>
+
+struct pj_opaque {
+ double cosphi1;
+ int mode;
+};
+
#ifndef M_PI
# define M_PI 3.14159265358979323846
#endif
@@ -42,7 +47,16 @@
PROJ_HEAD(aitoff, "Aitoff") "\n\tMisc Sph";
PROJ_HEAD(wintri, "Winkel Tripel") "\n\tMisc Sph\n\tlat_1";
+
+
+#if 0
FORWARD(s_forward); /* spheroid */
+#endif
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
double c, d;
if((d = acos(cos(lp.phi) * cos(c = 0.5 * lp.lam)))) {/* basic Aitoff */
@@ -50,8 +64,8 @@ FORWARD(s_forward); /* spheroid */
xy.y *= d * sin(lp.phi);
} else
xy.x = xy.y = 0.;
- if (P->mode) { /* Winkel Tripel */
- xy.x = (xy.x + lp.lam * P->cosphi1) * 0.5;
+ if (Q->mode) { /* Winkel Tripel */
+ xy.x = (xy.x + lp.lam * Q->cosphi1) * 0.5;
xy.y = (xy.y + lp.phi) * 0.5;
}
return (xy);
@@ -60,13 +74,13 @@ FORWARD(s_forward); /* spheroid */
/***********************************************************************************
*
* Inverse functions added by Drazen Tutic and Lovro Gradiser based on paper:
-*
-* I.Özbug Biklirici and Cengizhan Ipbüker. A General Algorithm for the Inverse
+*
+* I.Özbug Biklirici and Cengizhan Ipbüker. A General Algorithm for the Inverse
* Transformation of Map Projections Using Jacobian Matrices. In Proceedings of the
* Third International Symposium Mathematical & Computational Applications,
* pages 175{182, Turkey, September 2002.
*
-* Expected accuracy is defined by EPSILON = 1e-12. Should be appropriate for
+* Expected accuracy is defined by EPSILON = 1e-12. Should be appropriate for
* most applications of Aitoff and Winkel Tripel projections.
*
* Longitudes of 180W and 180E can be mixed in solution obtained.
@@ -78,19 +92,21 @@ FORWARD(s_forward); /* spheroid */
*
************************************************************************************/
-INVERSE(s_inverse); /* sphere */
- int iter, MAXITER = 10, round = 0, MAXROUND = 20;
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ int iter, MAXITER = 10, round = 0, MAXROUND = 20;
double EPSILON = 1e-12, D, C, f1, f2, f1p, f1l, f2p, f2l, dp, dl, sl, sp, cp, cl, x, y;
- if ((fabs(xy.x) < EPSILON) && (fabs(xy.y) < EPSILON )) { lp.phi = 0.; lp.lam = 0.; return (lp); }
+ if ((fabs(xy.x) < EPSILON) && (fabs(xy.y) < EPSILON )) { lp.phi = 0.; lp.lam = 0.; return lp; }
/* intial values for Newton-Raphson method */
- lp.phi = xy.y; lp.lam = xy.x;
+ lp.phi = xy.y; lp.lam = xy.x;
do {
- iter = 0;
- do {
- sl = sin(lp.lam * 0.5); cl = cos(lp.lam * 0.5);
- sp = sin(lp.phi); cp = cos(lp.phi);
+ iter = 0;
+ do {
+ sl = sin(lp.lam * 0.5); cl = cos(lp.lam * 0.5);
+ sp = sin(lp.phi); cp = cos(lp.phi);
D = cp * cl;
C = 1. - D * D;
D = acos(D) / pow(C, 1.5);
@@ -100,11 +116,11 @@ INVERSE(s_inverse); /* sphere */
f1l = cp * cp * sl * sl / C + D * cp * cl * sp * sp;
f2p = sp * sp * cl / C + D * sl * sl * cp;
f2l = 0.5 * (sp * cp * sl / C - D * sp * cp * cp * sl * cl);
- if (P->mode) { /* Winkel Tripel */
- f1 = 0.5 * (f1 + lp.lam * P->cosphi1);
+ if (Q->mode) { /* Winkel Tripel */
+ f1 = 0.5 * (f1 + lp.lam * Q->cosphi1);
f2 = 0.5 * (f2 + lp.phi);
f1p *= 0.5;
- f1l = 0.5 * (f1l + P->cosphi1);
+ f1l = 0.5 * (f1l + Q->cosphi1);
f2p = 0.5 * (f2p + 1.);
f2l *= 0.5;
}
@@ -115,9 +131,9 @@ INVERSE(s_inverse); /* sphere */
while (dl < -M_PI) dl += M_PI; /* set to interval [-M_PI, M_PI] */
lp.phi -= dp; lp.lam -= dl;
} while ((fabs(dp) > EPSILON || fabs(dl) > EPSILON) && (iter++ < MAXITER));
- if (lp.phi > M_PI_2) lp.phi -= 2.*(lp.phi-M_PI_2); /* correct if symmetrical solution for Aitoff */
- if (lp.phi < -M_PI_2) lp.phi -= 2.*(lp.phi+M_PI_2); /* correct if symmetrical solution for Aitoff */
- if ((fabs(fabs(lp.phi) - M_PI_2) < EPSILON) && (!P->mode)) lp.lam = 0.; /* if pole in Aitoff, return longitude of 0 */
+ if (lp.phi > M_PI_2) lp.phi -= 2.*(lp.phi-M_PI_2); /* correct if symmetrical solution for Aitoff */
+ if (lp.phi < -M_PI_2) lp.phi -= 2.*(lp.phi+M_PI_2); /* correct if symmetrical solution for Aitoff */
+ if ((fabs(fabs(lp.phi) - M_PI_2) < EPSILON) && (!Q->mode)) lp.lam = 0.; /* if pole in Aitoff, return longitude of 0 */
/* calculate x,y coordinates with solution obtained */
if((D = acos(cos(lp.phi) * cos(C = 0.5 * lp.lam)))) {/* Aitoff */
@@ -125,8 +141,8 @@ INVERSE(s_inverse); /* sphere */
y *= D * sin(lp.phi);
} else
x = y = 0.;
- if (P->mode) { /* Winkel Tripel */
- x = (x + lp.lam * P->cosphi1) * 0.5;
+ if (Q->mode) { /* Winkel Tripel */
+ x = (x + lp.lam * Q->cosphi1) * 0.5;
y = (y + lp.phi) * 0.5;
}
/* if too far from given values of x,y, repeat with better approximation of phi,lam */
@@ -134,27 +150,154 @@ INVERSE(s_inverse); /* sphere */
if (iter == MAXITER && round == MAXROUND) fprintf(stderr, "Warning: Accuracy of 1e-12 not reached. Last increments: dlat=%e and dlon=%e\n", dp, dl);
- return (lp);
+ return lp;
}
-FREEUP; if (P) pj_dalloc(P); }
- static PJ *
-setup(PJ *P) {
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+ if (0==P->opaque)
+ return pj_dealloc (P);
+
+ pj_dealloc (P->opaque);
+ return pj_dealloc(P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+static PJ *setup(PJ *P) {
P->inv = s_inverse;
P->fwd = s_forward;
P->es = 0.;
return P;
}
-ENTRY0(aitoff)
- P->mode = 0;
-ENDENTRY(setup(P))
-ENTRY0(wintri)
- P->mode = 1;
- if (pj_param(P->ctx, P->params, "tlat_1").i)
- {
- if ((P->cosphi1 = cos(pj_param(P->ctx, P->params, "rlat_1").f)) == 0.)
+
+
+PJ *PROJECTION(aitoff) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ P->pfree = freeup;
+ P->descr = des_aitoff;
+ Q->mode = 0;
+ return setup(P);
+}
+
+
+PJ *PROJECTION(wintri) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ P->pfree = freeup;
+ P->descr = des_wintri;
+ Q->mode = 1;
+ if (pj_param(P->ctx, P->params, "tlat_1").i) {
+ if ((Q->cosphi1 = cos(pj_param(P->ctx, P->params, "rlat_1").f)) == 0.)
E_ERROR(-22)
- }
+ }
else /* 50d28' or acos(2/pi) */
- P->cosphi1 = 0.636619772367581343;
-ENDENTRY(setup(P))
+ Q->cosphi1 = 0.636619772367581343;
+ return setup(P);
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_aitoff_selftest (void) {return 0;}
+#else
+
+int pj_aitoff_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=aitoff +a=6400000 +lat_1=0 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+
+ XY s_fwd_expect[] = {
+ {223379.45881169615, 111706.74288385305},
+ {223379.45881169615, -111706.74288385305},
+ {-223379.45881169615, 111706.74288385305},
+ {-223379.45881169615, -111706.74288385305},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+
+ LP s_inv_expect[] = {
+ {0.0017904931100388164, 0.00089524655491012516},
+ {0.0017904931100388164, -0.00089524655491012516},
+ {-0.0017904931100388164, 0.00089524655491012516},
+ {-0.0017904931100388164, -0.00089524655491012516},
+ };
+
+ return pj_generic_selftest (0, s_args, tolerance_xy, tolerance_lp, 4, 4, fwd_in, 0, s_fwd_expect, inv_in, 0, s_inv_expect);
+}
+
+
+#endif
+
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_wintri_selftest (void) {return 0;}
+#else
+
+int pj_wintri_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=wintri +a=6400000 +lat_1=0 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ {223390.80153348515, 111703.90750574505},
+ {223390.80153348515, -111703.90750574505},
+ {-223390.80153348515, 111703.90750574505},
+ {-223390.80153348515, -111703.90750574505},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ {0.0017904931099113196, 0.00089524655490101819},
+ {0.0017904931099113196, -0.00089524655490101819},
+ {-0.0017904931099113196, 0.00089524655490101819},
+ {-0.0017904931099113196, -0.00089524655490101819},
+ };
+
+ return pj_generic_selftest (0, s_args, tolerance_xy, tolerance_lp, 4, 4, fwd_in, 0, s_fwd_expect, inv_in, 0, s_inv_expect);
+}
+
+
+#endif