diff options
| author | Thomas Knudsen <lastname DOT firstname AT gmail DOT com> | 2016-04-05 23:56:01 +0200 |
|---|---|---|
| committer | Thomas Knudsen <lastname DOT firstname AT gmail DOT com> | 2016-04-05 23:56:01 +0200 |
| commit | 77f8c2947b934d64293da614bf7b8b8e0f90031b (patch) | |
| tree | ae767e1a7213ff8882f7910e84489a785506fc90 /src/PJ_aitoff.c | |
| parent | 2cd5e4f988e7f2d89f259ad2f3ac69be825acb75 (diff) | |
| download | PROJ-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.c | 223 |
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 |
