diff options
| author | Thomas Knudsen <lastname DOT firstname AT gmail DOT com> | 2016-04-12 21:55:29 +0200 |
|---|---|---|
| committer | Thomas Knudsen <lastname DOT firstname AT gmail DOT com> | 2016-04-12 21:55:29 +0200 |
| commit | c8f040f1d6b52f89825c9a1060545a97bf799487 (patch) | |
| tree | 65cc06d0ba2bed9f84d3c5f676182ced243cbdf9 | |
| parent | 86a3221bdc26ea2cdbe85fcf270263ce02fef0e6 (diff) | |
| download | PROJ-c8f040f1d6b52f89825c9a1060545a97bf799487.tar.gz PROJ-c8f040f1d6b52f89825c9a1060545a97bf799487.zip | |
refactoring + added selftest for 7 more projections
tcc, tcea, tmerc, tpeqd, urm5, urmfps, wag1
| -rw-r--r-- | src/PJ_aea.c | 7 | ||||
| -rw-r--r-- | src/PJ_tcc.c | 76 | ||||
| -rw-r--r-- | src/PJ_tcea.c | 104 | ||||
| -rw-r--r-- | src/PJ_tmerc.c | 373 | ||||
| -rw-r--r-- | src/PJ_tpeqd.c | 193 | ||||
| -rw-r--r-- | src/PJ_urm5.c | 103 | ||||
| -rw-r--r-- | src/PJ_urmfps.c | 176 | ||||
| -rw-r--r-- | src/pj_generic_selftest.c | 20 |
8 files changed, 767 insertions, 285 deletions
diff --git a/src/PJ_aea.c b/src/PJ_aea.c index 6de8f00d..7a507460 100644 --- a/src/PJ_aea.c +++ b/src/PJ_aea.c @@ -457,22 +457,15 @@ int pj_somerc_selftest (void) {return 10000;} int pj_stere_selftest (void) {return 10000;} int pj_sterea_selftest (void) {return 10000;} int pj_gstmerc_selftest (void) {return 10000;} -int pj_tcc_selftest (void) {return 10000;} -int pj_tcea_selftest (void) {return 10000;} int pj_tissot_selftest (void) {return 10000;} -int pj_tmerc_selftest (void) {return 10000;} -int pj_tpeqd_selftest (void) {return 10000;} int pj_tpers_selftest (void) {return 10000;} int pj_ups_selftest (void) {return 10000;} -int pj_urm5_selftest (void) {return 10000;} -int pj_urmfps_selftest (void) {return 10000;} int pj_utm_selftest (void) {return 10000;} int pj_vandg_selftest (void) {return 10000;} int pj_vandg2_selftest (void) {return 10000;} int pj_vandg3_selftest (void) {return 10000;} int pj_vandg4_selftest (void) {return 10000;} int pj_vitk1_selftest (void) {return 10000;} -int pj_wag1_selftest (void) {return 10000;} int pj_wag4_selftest (void) {return 10000;} int pj_wag5_selftest (void) {return 10000;} int pj_wag6_selftest (void) {return 10000;} diff --git a/src/PJ_tcc.c b/src/PJ_tcc.c index 00cdb556..457924c0 100644 --- a/src/PJ_tcc.c +++ b/src/PJ_tcc.c @@ -1,17 +1,65 @@ -#define PROJ_PARMS__ \ - double ap; -#define EPS10 1.e-10 #define PJ_LIB__ -#include <projects.h> +#include <projects.h> + PROJ_HEAD(tcc, "Transverse Central Cylindrical") "\n\tCyl, Sph, no inv."; -FORWARD(s_forward); /* spheroid */ - double b, bt; - - b = cos(lp.phi) * sin(lp.lam); - if ((bt = 1. - b * b) < EPS10) F_ERROR; - xy.x = b / sqrt(bt); - xy.y = atan2(tan(lp.phi) , cos(lp.lam)); - return (xy); + +#define EPS10 1.e-10 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0, 0.0}; + double b, bt; + + b = cos (lp.phi) * sin (lp.lam); + if ((bt = 1. - b * b) < EPS10) F_ERROR; + xy.x = b / sqrt(bt); + xy.y = atan2 (tan (lp.phi) , cos (lp.lam)); + return xy; +} + + +static void *freeup_new (PJ *P) { /* Destructor */ + return pj_dealloc(P); +} + +static void freeup (PJ *P) { + freeup_new (P); + return; +} + + +PJ *PROJECTION(tcc) { + P->es = 0.; + P->fwd = s_forward; + P->inv = 0; + + return P; +} + + +#ifdef PJ_OMIT_SELFTEST +int pj_tcc_selftest (void) {return 0;} +#else +int pj_tcc_selftest (void) { + double tolerance_lp = 1e-10; + double tolerance_xy = 1e-7; + + char s_args[] = {"+proj=tcc +a=6400000 +lat_1=0.5 +lat_2=2 +n=0.5"}; + + LP fwd_in[] = { + { 2, 1}, + { 2,-1}, + {-2, 1}, + {-2,-1} + }; + + XY s_fwd_expect[] = { + {223458.84419245756, 111769.14504058579}, + {223458.84419245756, -111769.14504058579}, + {-223458.84419245756, 111769.14504058579}, + {-223458.84419245756, -111769.14504058579}, + }; + + return pj_generic_selftest (0, s_args, tolerance_xy, tolerance_lp, 4, 4, fwd_in, 0, s_fwd_expect, 0, 0, 0); } -FREEUP; if (P) pj_dalloc(P); } -ENTRY0(tcc) P->es = 0.; P->fwd = s_forward; ENDENTRY(P) +#endif diff --git a/src/PJ_tcea.c b/src/PJ_tcea.c index 3626fa17..7b469d0e 100644 --- a/src/PJ_tcea.c +++ b/src/PJ_tcea.c @@ -1,27 +1,85 @@ -#define PROJ_PARMS__ \ - double rk0; #define PJ_LIB__ -#include <projects.h> +#include <projects.h> + PROJ_HEAD(tcea, "Transverse Cylindrical Equal Area") "\n\tCyl, Sph"; -FORWARD(s_forward); /* spheroid */ - xy.x = P->rk0 * cos(lp.phi) * sin(lp.lam); - xy.y = P->k0 * (atan2(tan(lp.phi), cos(lp.lam)) - P->phi0); - return (xy); + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + xy.x = cos (lp.phi) * sin (lp.lam) / P->k0; + xy.y = P->k0 * (atan2 (tan (lp.phi), cos (lp.lam)) - P->phi0); + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0, 0.0}; + double t; + + xy.y = xy.y / P->k0 + P->phi0; + xy.x *= P->k0; + t = sqrt (1. - xy.x * xy.x); + lp.phi = asin (t * sin (xy.y)); + lp.lam = atan2 (xy.x, t * cos (xy.y)); + return lp; +} + + +static void *freeup_new (PJ *P) { /* Destructor */ + return pj_dealloc(P); +} + +static void freeup (PJ *P) { + freeup_new (P); + return; } -INVERSE(s_inverse); /* spheroid */ - double t; - - xy.y = xy.y * P->rk0 + P->phi0; - xy.x *= P->k0; - t = sqrt(1. - xy.x * xy.x); - lp.phi = asin(t * sin(xy.y)); - lp.lam = atan2(xy.x, t * cos(xy.y)); - return (lp); + + +PJ *PROJECTION(tcea) { + P->inv = s_inverse; + P->fwd = s_forward; + P->es = 0.; + return P; +} + + +#ifdef PJ_OMIT_SELFTEST +int pj_tcea_selftest (void) {return 0;} +#else +int pj_tcea_selftest (void) { + double tolerance_lp = 1e-10; + double tolerance_xy = 1e-7; + + char s_args[] = {"+proj=tcea +a=6400000 +lat_1=0.5 +lat_2=2 +n=0.5"}; + + LP fwd_in[] = { + { 2, 1}, + { 2,-1}, + {-2, 1}, + {-2,-1} + }; + + XY s_fwd_expect[] = { + { 223322.76057672748, 111769.14504058579}, + { 223322.76057672748, -111769.14504058579}, + {-223322.76057672748, 111769.14504058579}, + {-223322.76057672748, -111769.14504058579}, + }; + + XY inv_in[] = { + { 200, 100}, + { 200,-100}, + {-200, 100}, + {-200,-100} + }; + + LP s_inv_expect[] = { + { 0.0017904931102938101, 0.00089524655445477922}, + { 0.0017904931102938101, -0.00089524655445477922}, + {-0.0017904931102938101, 0.00089524655445477922}, + {-0.0017904931102938101, -0.00089524655445477922}, + }; + + 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); } -FREEUP; if (P) pj_dalloc(P); } -ENTRY0(tcea) - P->rk0 = 1 / P->k0; - P->inv = s_inverse; - P->fwd = s_forward; - P->es = 0.; -ENDENTRY(P) +#endif diff --git a/src/PJ_tmerc.c b/src/PJ_tmerc.c index 70e8e72f..35203261 100644 --- a/src/PJ_tmerc.c +++ b/src/PJ_tmerc.c @@ -1,13 +1,16 @@ -#define PROJ_PARMS__ \ - double esp; \ - double ml0; \ - double *en; #define PJ_LIB__ -#include <projects.h> +#include <projects.h> + PROJ_HEAD(tmerc, "Transverse Mercator") "\n\tCyl, Sph&Ell"; -#define EPS10 1.e-10 -#define aks0 P->esp -#define aks5 P->ml0 + + +struct pj_opaque { + double esp; \ + double ml0; \ + double *en; +}; + +#define EPS10 1.e-10 #define FC1 1. #define FC2 .5 #define FC3 .16666666666666666666 @@ -16,138 +19,234 @@ PROJ_HEAD(tmerc, "Transverse Mercator") "\n\tCyl, Sph&Ell"; #define FC6 .03333333333333333333 #define FC7 .02380952380952380952 #define FC8 .01785714285714285714 -FORWARD(e_forward); /* ellipse */ - double al, als, n, cosphi, sinphi, t; - - /* - * Fail if our longitude is more than 90 degrees from the - * central meridian since the results are essentially garbage. - * Is error -20 really an appropriate return value? - * - * http://trac.osgeo.org/proj/ticket/5 - */ - if( lp.lam < -HALFPI || lp.lam > HALFPI ) - { - xy.x = HUGE_VAL; - xy.y = HUGE_VAL; - pj_ctx_set_errno( P->ctx, -14 ); - return xy; - } - - sinphi = sin(lp.phi); cosphi = cos(lp.phi); - t = fabs(cosphi) > 1e-10 ? sinphi/cosphi : 0.; - t *= t; - al = cosphi * lp.lam; - als = al * al; - al /= sqrt(1. - P->es * sinphi * sinphi); - n = P->esp * cosphi * cosphi; - xy.x = P->k0 * al * (FC1 + - FC3 * als * (1. - t + n + - FC5 * als * (5. + t * (t - 18.) + n * (14. - 58. * t) - + FC7 * als * (61. + t * ( t * (179. - t) - 479. ) ) - ))); - xy.y = P->k0 * (pj_mlfn(lp.phi, sinphi, cosphi, P->en) - P->ml0 + - sinphi * al * lp.lam * FC2 * ( 1. + - FC4 * als * (5. - t + n * (9. + 4. * n) + - FC6 * als * (61. + t * (t - 58.) + n * (270. - 330 * t) - + FC8 * als * (1385. + t * ( t * (543. - t) - 3111.) ) - )))); - return (xy); + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + XY xy = {0.0, 0.0}; + struct pj_opaque *Q = P->opaque; + double al, als, n, cosphi, sinphi, t; + + /* + * Fail if our longitude is more than 90 degrees from the + * central meridian since the results are essentially garbage. + * Is error -20 really an appropriate return value? + * + * http://trac.osgeo.org/proj/ticket/5 + */ + if( lp.lam < -HALFPI || lp.lam > HALFPI ) { + xy.x = HUGE_VAL; + xy.y = HUGE_VAL; + pj_ctx_set_errno( P->ctx, -14 ); + return xy; + } + + sinphi = sin (lp.phi); + cosphi = cos (lp.phi); + t = fabs (cosphi) > 1e-10 ? sinphi/cosphi : 0.; + t *= t; + al = cosphi * lp.lam; + als = al * al; + al /= sqrt (1. - P->es * sinphi * sinphi); + n = Q->esp * cosphi * cosphi; + xy.x = P->k0 * al * (FC1 + + FC3 * als * (1. - t + n + + FC5 * als * (5. + t * (t - 18.) + n * (14. - 58. * t) + + FC7 * als * (61. + t * ( t * (179. - t) - 479. ) ) + ))); + xy.y = P->k0 * (pj_mlfn(lp.phi, sinphi, cosphi, Q->en) - Q->ml0 + + sinphi * al * lp.lam * FC2 * ( 1. + + FC4 * als * (5. - t + n * (9. + 4. * n) + + FC6 * als * (61. + t * (t - 58.) + n * (270. - 330 * t) + + FC8 * als * (1385. + t * ( t * (543. - t) - 3111.) ) + )))); + return (xy); +} + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + double b, cosphi; + + /* + * Fail if our longitude is more than 90 degrees from the + * central meridian since the results are essentially garbage. + * Is error -20 really an appropriate return value? + * + * http://trac.osgeo.org/proj/ticket/5 + */ + if( lp.lam < -HALFPI || lp.lam > HALFPI ) { + xy.x = HUGE_VAL; + xy.y = HUGE_VAL; + pj_ctx_set_errno( P->ctx, -14 ); + return xy; + } + + cosphi = cos(lp.phi); + b = cosphi * sin (lp.lam); + if (fabs (fabs (b) - 1.) <= EPS10) + F_ERROR; + + xy.x = P->opaque->ml0 * log ((1. + b) / (1. - b)); + xy.y = cosphi * cos (lp.lam) / sqrt (1. - b * b); + + b = fabs ( xy.y ); + if (b >= 1.) { + if ((b - 1.) > EPS10) + F_ERROR + else xy.y = 0.; + } else + xy.y = acos (xy.y); + + if (lp.phi < 0.) + xy.y = -xy.y; + xy.y = P->opaque->esp * (xy.y - P->phi0); + return xy; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = P->opaque; + double n, con, cosphi, d, ds, sinphi, t; + + lp.phi = pj_inv_mlfn(P->ctx, Q->ml0 + xy.y / P->k0, P->es, Q->en); + if (fabs(lp.phi) >= HALFPI) { + lp.phi = xy.y < 0. ? -HALFPI : HALFPI; + lp.lam = 0.; + } else { + sinphi = sin(lp.phi); + cosphi = cos(lp.phi); + t = fabs (cosphi) > 1e-10 ? sinphi/cosphi : 0.; + n = Q->esp * cosphi * cosphi; + d = xy.x * sqrt (con = 1. - P->es * sinphi * sinphi) / P->k0; + con *= t; + t *= t; + ds = d * d; + lp.phi -= (con * ds / (1.-P->es)) * FC2 * (1. - + ds * FC4 * (5. + t * (3. - 9. * n) + n * (1. - 4 * n) - + ds * FC6 * (61. + t * (90. - 252. * n + + 45. * t) + 46. * n + - ds * FC8 * (1385. + t * (3633. + t * (4095. + 1574. * t)) ) + ))); + lp.lam = d*(FC1 - + ds*FC3*( 1. + 2.*t + n - + ds*FC5*(5. + t*(28. + 24.*t + 8.*n) + 6.*n + - ds * FC7 * (61. + t * (662. + t * (1320. + 720. * t)) ) + ))) / cosphi; + } + return lp; } -FORWARD(s_forward); /* sphere */ - double b, cosphi; - - /* - * Fail if our longitude is more than 90 degrees from the - * central meridian since the results are essentially garbage. - * Is error -20 really an appropriate return value? - * - * http://trac.osgeo.org/proj/ticket/5 - */ - if( lp.lam < -HALFPI || lp.lam > HALFPI ) - { - xy.x = HUGE_VAL; - xy.y = HUGE_VAL; - pj_ctx_set_errno( P->ctx, -14 ); - return xy; - } - - b = (cosphi = cos(lp.phi)) * sin(lp.lam); - if (fabs(fabs(b) - 1.) <= EPS10) F_ERROR; - xy.x = aks5 * log((1. + b) / (1. - b)); - if ((b = fabs( xy.y = cosphi * cos(lp.lam) / sqrt(1. - b * b) )) >= 1.) { - if ((b - 1.) > EPS10) F_ERROR - else xy.y = 0.; - } else - xy.y = acos(xy.y); - if (lp.phi < 0.) xy.y = -xy.y; - xy.y = aks0 * (xy.y - P->phi0); - return (xy); + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0, 0.0}; + double h, g; + + h = exp(xy.x / P->opaque->esp); + g = .5 * (h - 1. / h); + h = cos (P->phi0 + xy.y / P->opaque->esp); + lp.phi = asin(sqrt((1. - h * h) / (1. + g * g))); + if (xy.y < 0.) lp.phi = -lp.phi; + lp.lam = (g || h) ? atan2 (g, h) : 0.; + return lp; +} + + +static void *freeup_new (PJ *P) { /* Destructor */ + if (0==P) + return 0; + if (0==P->opaque) + return pj_dealloc (P); + pj_dealloc (P->opaque->en); + pj_dealloc (P->opaque); + return pj_dealloc(P); } -INVERSE(e_inverse); /* ellipsoid */ - double n, con, cosphi, d, ds, sinphi, t; - - lp.phi = pj_inv_mlfn(P->ctx, P->ml0 + xy.y / P->k0, P->es, P->en); - if (fabs(lp.phi) >= HALFPI) { - lp.phi = xy.y < 0. ? -HALFPI : HALFPI; - lp.lam = 0.; - } else { - sinphi = sin(lp.phi); - cosphi = cos(lp.phi); - t = fabs(cosphi) > 1e-10 ? sinphi/cosphi : 0.; - n = P->esp * cosphi * cosphi; - d = xy.x * sqrt(con = 1. - P->es * sinphi * sinphi) / P->k0; - con *= t; - t *= t; - ds = d * d; - lp.phi -= (con * ds / (1.-P->es)) * FC2 * (1. - - ds * FC4 * (5. + t * (3. - 9. * n) + n * (1. - 4 * n) - - ds * FC6 * (61. + t * (90. - 252. * n + - 45. * t) + 46. * n - - ds * FC8 * (1385. + t * (3633. + t * (4095. + 1574. * t)) ) - ))); - lp.lam = d*(FC1 - - ds*FC3*( 1. + 2.*t + n - - ds*FC5*(5. + t*(28. + 24.*t + 8.*n) + 6.*n - - ds * FC7 * (61. + t * (662. + t * (1320. + 720. * t)) ) - ))) / cosphi; - } - return (lp); + +static void freeup (PJ *P) { + freeup_new (P); + return; } -INVERSE(s_inverse); /* sphere */ - double h, g; - - h = exp(xy.x / aks0); - g = .5 * (h - 1. / h); - h = cos(P->phi0 + xy.y / aks0); - lp.phi = asin(sqrt((1. - h * h) / (1. + g * g))); - if (xy.y < 0.) lp.phi = -lp.phi; - lp.lam = (g || h) ? atan2(g, h) : 0.; - return (lp); + +static PJ *setup(PJ *P) { /* general initialization */ + struct pj_opaque *Q = P->opaque; + if (P->es) { + if (!(Q->en = pj_enfn(P->es))) + E_ERROR_0; + Q->ml0 = pj_mlfn(P->phi0, sin(P->phi0), cos(P->phi0), Q->en); + Q->esp = P->es / (1. - P->es); + P->inv = e_inverse; + P->fwd = e_forward; + } else { + Q->esp = P->k0; + Q->ml0 = .5 * Q->esp; + P->inv = s_inverse; + P->fwd = s_forward; + } + return P; } -FREEUP; - if (P) { - if (P->en) - pj_dalloc(P->en); - pj_dalloc(P); - } + + +PJ *PROJECTION(tmerc) { + struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); + if (0==Q) + return freeup_new (P); + P->opaque = Q; + return setup(P); } - static PJ * -setup(PJ *P) { /* general initialization */ - if (P->es) { - if (!(P->en = pj_enfn(P->es))) - E_ERROR_0; - P->ml0 = pj_mlfn(P->phi0, sin(P->phi0), cos(P->phi0), P->en); - P->esp = P->es / (1. - P->es); - P->inv = e_inverse; - P->fwd = e_forward; - } else { - aks0 = P->k0; - aks5 = .5 * aks0; - P->inv = s_inverse; - P->fwd = s_forward; - } - return P; + + +#ifdef PJ_OMIT_SELFTEST +int pj_tmerc_selftest (void) {return 0;} +#else +int pj_tmerc_selftest (void) { + double tolerance_lp = 1e-10; + double tolerance_xy = 1e-7; + + char e_args[] = {"+proj=tmerc +ellps=GRS80 +lat_1=0.5 +lat_2=2 +n=0.5"}; + char s_args[] = {"+proj=tmerc +a=6400000 +lat_1=0.5 +lat_2=2 +n=0.5"}; + + LP fwd_in[] = { + { 2, 1}, + { 2,-1}, + {-2, 1}, + {-2,-1} + }; + + XY e_fwd_expect[] = { + { 222650.79679577847, 110642.22941192707}, + { 222650.79679577847, -110642.22941192707}, + {-222650.79679577847, 110642.22941192707}, + {-222650.79679577847, -110642.22941192707}, + }; + + XY s_fwd_expect[] = { + { 223413.46640632232, 111769.14504059685}, + { 223413.46640632232, -111769.14504059685}, + {-223413.46640632208, 111769.14504059685}, + {-223413.46640632208, -111769.14504059685}, + }; + + XY inv_in[] = { + { 200, 100}, + { 200,-100}, + {-200, 100}, + {-200,-100} + }; + + LP e_inv_expect[] = { + { 0.0017966305681649396, 0.00090436947663183841}, + { 0.0017966305681649396, -0.00090436947663183841}, + {-0.0017966305681649396, 0.00090436947663183841}, + {-0.0017966305681649396, -0.00090436947663183841}, + }; + + LP s_inv_expect[] = { + { 0.0017904931097048034, 0.00089524670602767842}, + { 0.0017904931097048034, -0.00089524670602767842}, + {-0.001790493109714345, 0.00089524670602767842}, + {-0.001790493109714345, -0.00089524670602767842}, + }; + + return pj_generic_selftest (e_args, s_args, tolerance_xy, tolerance_lp, 4, 4, fwd_in, e_fwd_expect, s_fwd_expect, inv_in, e_inv_expect, s_inv_expect); } -ENTRY1(tmerc, en) -ENDENTRY(setup(P)) +#endif diff --git a/src/PJ_tpeqd.c b/src/PJ_tpeqd.c index 4ab5cf4e..182f23a5 100644 --- a/src/PJ_tpeqd.c +++ b/src/PJ_tpeqd.c @@ -1,76 +1,177 @@ -#define PROJ_PARMS__ \ - double cp1, sp1, cp2, sp2, ccs, cs, sc, r2z0, z02, dlam2; \ - double hz0, thz0, rhshz0, ca, sa, lp, lamc; #define PJ_LIB__ #include <projects.h> + + PROJ_HEAD(tpeqd, "Two Point Equidistant") "\n\tMisc Sph\n\tlat_1= lon_1= lat_2= lon_2="; -FORWARD(s_forward); /* sphere */ + +struct pj_opaque { + double cp1, sp1, cp2, sp2, ccs, cs, sc, r2z0, z02, dlam2; \ + double hz0, thz0, rhshz0, ca, sa, lp, lamc; +}; + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0, 0.0}; + struct pj_opaque *Q = P->opaque; double t, z1, z2, dl1, dl2, sp, cp; sp = sin(lp.phi); cp = cos(lp.phi); - z1 = aacos(P->ctx,P->sp1 * sp + P->cp1 * cp * cos(dl1 = lp.lam + P->dlam2)); - z2 = aacos(P->ctx,P->sp2 * sp + P->cp2 * cp * cos(dl2 = lp.lam - P->dlam2)); + z1 = aacos(P->ctx, Q->sp1 * sp + Q->cp1 * cp * cos (dl1 = lp.lam + Q->dlam2)); + z2 = aacos(P->ctx, Q->sp2 * sp + Q->cp2 * cp * cos (dl2 = lp.lam - Q->dlam2)); z1 *= z1; z2 *= z2; - xy.x = P->r2z0 * (t = z1 - z2); - t = P->z02 - t; - xy.y = P->r2z0 * asqrt(4. * P->z02 * z2 - t * t); - if ((P->ccs * sp - cp * (P->cs * sin(dl1) - P->sc * sin(dl2))) < 0.) + + xy.x = Q->r2z0 * (t = z1 - z2); + t = Q->z02 - t; + xy.y = Q->r2z0 * asqrt (4. * Q->z02 * z2 - t * t); + if ((Q->ccs * sp - cp * (Q->cs * sin(dl1) - Q->sc * sin(dl2))) < 0.) xy.y = -xy.y; return xy; } -INVERSE(s_inverse); /* sphere */ + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = P->opaque; double cz1, cz2, s, d, cp, sp; - cz1 = cos(hypot(xy.y, xy.x + P->hz0)); - cz2 = cos(hypot(xy.y, xy.x - P->hz0)); + cz1 = cos (hypot(xy.y, xy.x + Q->hz0)); + cz2 = cos (hypot(xy.y, xy.x - Q->hz0)); s = cz1 + cz2; d = cz1 - cz2; - lp.lam = - atan2(d, (s * P->thz0)); - lp.phi = aacos(P->ctx,hypot(P->thz0 * s, d) * P->rhshz0); + lp.lam = - atan2(d, (s * Q->thz0)); + lp.phi = aacos(P->ctx, hypot (Q->thz0 * s, d) * Q->rhshz0); if ( xy.y < 0. ) lp.phi = - lp.phi; /* lam--phi now in system relative to P1--P2 base equator */ - sp = sin(lp.phi); - cp = cos(lp.phi); - lp.phi = aasin(P->ctx,P->sa * sp + P->ca * cp * (s = cos(lp.lam -= P->lp))); - lp.lam = atan2(cp * sin(lp.lam), P->sa * cp * s - P->ca * sp) + P->lamc; + sp = sin (lp.phi); + cp = cos (lp.phi); + lp.phi = aasin (P->ctx, Q->sa * sp + Q->ca * cp * (s = cos(lp.lam -= Q->lp))); + lp.lam = atan2 (cp * sin(lp.lam), Q->sa * cp * s - Q->ca * sp) + Q->lamc; return lp; } -FREEUP; if (P) pj_dalloc(P); } -ENTRY0(tpeqd) + + +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; +} + + +PJ *PROJECTION(tpeqd) { double lam_1, lam_2, phi_1, phi_2, A12, pp; + struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); + if (0==Q) + return freeup_new (P); + P->opaque = Q; + /* get control point locations */ phi_1 = pj_param(P->ctx, P->params, "rlat_1").f; lam_1 = pj_param(P->ctx, P->params, "rlon_1").f; phi_2 = pj_param(P->ctx, P->params, "rlat_2").f; lam_2 = pj_param(P->ctx, P->params, "rlon_2").f; - if (phi_1 == phi_2 && lam_1 == lam_2) E_ERROR(-25); - P->lam0 = adjlon(0.5 * (lam_1 + lam_2)); - P->dlam2 = adjlon(lam_2 - lam_1); - P->cp1 = cos(phi_1); - P->cp2 = cos(phi_2); - P->sp1 = sin(phi_1); - P->sp2 = sin(phi_2); - P->cs = P->cp1 * P->sp2; - P->sc = P->sp1 * P->cp2; - P->ccs = P->cp1 * P->cp2 * sin(P->dlam2); - P->z02 = aacos(P->ctx,P->sp1 * P->sp2 + P->cp1 * P->cp2 * cos(P->dlam2)); - P->hz0 = .5 * P->z02; - A12 = atan2(P->cp2 * sin(P->dlam2), - P->cp1 * P->sp2 - P->sp1 * P->cp2 * cos(P->dlam2)); - P->ca = cos(pp = aasin(P->ctx,P->cp1 * sin(A12))); - P->sa = sin(pp); - P->lp = adjlon(atan2(P->cp1 * cos(A12), P->sp1) - P->hz0); - P->dlam2 *= .5; - P->lamc = HALFPI - atan2(sin(A12) * P->sp1, cos(A12)) - P->dlam2; - P->thz0 = tan(P->hz0); - P->rhshz0 = .5 / sin(P->hz0); - P->r2z0 = 0.5 / P->z02; - P->z02 *= P->z02; - P->inv = s_inverse; P->fwd = s_forward; + + if (phi_1 == phi_2 && lam_1 == lam_2) + E_ERROR(-25); + P->lam0 = adjlon (0.5 * (lam_1 + lam_2)); + Q->dlam2 = adjlon (lam_2 - lam_1); + + Q->cp1 = cos (phi_1); + Q->cp2 = cos (phi_2); + Q->sp1 = sin (phi_1); + Q->sp2 = sin (phi_2); + Q->cs = Q->cp1 * Q->sp2; + Q->sc = Q->sp1 * Q->cp2; + Q->ccs = Q->cp1 * Q->cp2 * sin(Q->dlam2); + Q->z02 = aacos(P->ctx, Q->sp1 * Q->sp2 + Q->cp1 * Q->cp2 * cos (Q->dlam2)); + Q->hz0 = .5 * Q->z02; + A12 = atan2(Q->cp2 * sin (Q->dlam2), + Q->cp1 * Q->sp2 - Q->sp1 * Q->cp2 * cos (Q->dlam2)); + Q->ca = cos(pp = aasin(P->ctx, Q->cp1 * sin(A12))); + Q->sa = sin(pp); + Q->lp = adjlon ( atan2 (Q->cp1 * cos(A12), Q->sp1) - Q->hz0); + Q->dlam2 *= .5; + Q->lamc = HALFPI - atan2(sin(A12) * Q->sp1, cos(A12)) - Q->dlam2; + Q->thz0 = tan (Q->hz0); + Q->rhshz0 = .5 / sin (Q->hz0); + Q->r2z0 = 0.5 / Q->z02; + Q->z02 *= Q->z02; + + P->inv = s_inverse; + P->fwd = s_forward; P->es = 0.; -ENDENTRY(P) + + return P; +} + + +#ifdef PJ_OMIT_SELFTEST +int pj_tpeqd_selftest (void) {return 0;} +#else + +int pj_tpeqd_selftest (void) { + double tolerance_lp = 1e-10; + double tolerance_xy = 1e-7; + + char e_args[] = {"+proj=tpeqd +ellps=GRS80 +lat_1=0.5 +lat_2=2 +n=0.5"}; + char s_args[] = {"+proj=tpeqd +a=6400000 +lat_1=0.5 +lat_2=2 +n=0.5"}; + + LP fwd_in[] = { + { 2, 1}, + { 2,-1}, + {-2, 1}, + {-2,-1} + }; + + XY e_fwd_expect[] = { + {-27750.758831679042, -222599.40369177726}, + {-250434.93702403645, -222655.93819326628}, + {-27750.758831679042, 222599.40369177726}, + {-250434.93702403645, 222655.93819326628}, + }; + + XY s_fwd_expect[] = { + {-27845.882978485075, -223362.43069526015}, + {-251293.37876465076, -223419.15898590829}, + {-27845.882978485075, 223362.43069526015}, + {-251293.37876465076, 223419.15898590829}, + }; + + XY inv_in[] = { + { 200, 100}, + { 200,-100}, + {-200, 100}, + {-200,-100} + }; + + LP e_inv_expect[] = { + {-0.00089855554821257374, 1.2517966304145272}, + {0.0008985555481998515, 1.2517966304145272}, + {-0.00089855431859741167, 1.2482033692781642}, + {0.00089855431859741167, 1.2482033692781642}, + }; + + LP s_inv_expect[] = { + {-0.00089548606640108474, 1.2517904929571837}, + {0.0008954860663883625, 1.2517904929571837}, + {-0.000895484845182587, 1.248209506737604}, + {0.00089548484516986475, 1.248209506737604}, + }; + + return pj_generic_selftest (e_args, s_args, tolerance_xy, tolerance_lp, 4, 4, fwd_in, e_fwd_expect, s_fwd_expect, inv_in, e_inv_expect, s_inv_expect); +} + + +#endif diff --git a/src/PJ_urm5.c b/src/PJ_urm5.c index 9159df65..7a759b07 100644 --- a/src/PJ_urm5.c +++ b/src/PJ_urm5.c @@ -1,28 +1,81 @@ -#define PROJ_PARMS__ \ - double m, rmn, q3, n; #define PJ_LIB__ -# include <projects.h> +#include <projects.h> + PROJ_HEAD(urm5, "Urmaev V") "\n\tPCyl., Sph., no inv.\n\tn= q= alpha="; -FORWARD(s_forward); /* spheroid */ - double t; - - t = lp.phi = aasin(P->ctx,P->n * sin(lp.phi)); - xy.x = P->m * lp.lam * cos(lp.phi); - t *= t; - xy.y = lp.phi * (1. + t * P->q3) * P->rmn; - return xy; + +struct pj_opaque { + double m, rmn, q3, n; +}; + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0, 0.0}; + struct pj_opaque *Q = P->opaque; + double t; + + t = lp.phi = aasin (P->ctx, Q->n * sin (lp.phi)); + xy.x = Q->m * lp.lam * cos (lp.phi); + t *= t; + xy.y = lp.phi * (1. + t * Q->q3) * Q->rmn; + return xy; +} + + +static void *freeup_new (PJ *P) { /* Destructor */ + return pj_dealloc(P); +} + +static void freeup (PJ *P) { + freeup_new (P); + return; +} + + +PJ *PROJECTION(urm5) { + double alpha, t; + struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); + if (0==Q) + return freeup_new (P); + P->opaque = Q; + + Q->n = pj_param(P->ctx, P->params, "dn").f; + Q->q3 = pj_param(P->ctx, P->params, "dq").f / 3.; + alpha = pj_param(P->ctx, P->params, "ralpha").f; + t = Q->n * sin (alpha); + Q->m = cos (alpha) / sqrt (1. - t * t); + Q->rmn = 1. / (Q->m * Q->n); + + P->es = 0.; + P->inv = 0; + P->fwd = s_forward; + + return P; +} + + +#ifdef PJ_OMIT_SELFTEST +int pj_urm5_selftest (void) {return 0;} +#else +int pj_urm5_selftest (void) { + double tolerance_lp = 1e-10; + double tolerance_xy = 1e-7; + + char s_args[] = {"+proj=urm5 +a=6400000 +lat_1=0.5 +lat_2=2"}; + + LP fwd_in[] = { + { 2, 1}, + { 2,-1}, + {-2, 1}, + {-2,-1} + }; + + XY s_fwd_expect[] = { + { 223393.6384339639, 111696.81878511712}, + { 223393.6384339639, -111696.81878511712}, + {-223393.6384339639, 111696.81878511712}, + {-223393.6384339639, -111696.81878511712}, + }; + + return pj_generic_selftest (0, s_args, tolerance_xy, tolerance_lp, 4, 4, fwd_in, 0, s_fwd_expect, 0, 0, 0); } -FREEUP; if (P) pj_dalloc(P); } -ENTRY0(urm5) - double alpha, t; - - P->n = pj_param(P->ctx, P->params, "dn").f; - P->q3 = pj_param(P->ctx, P->params, "dq").f / 3.; - alpha = pj_param(P->ctx, P->params, "ralpha").f; - t = P->n * sin(alpha); - P->m = cos(alpha) / sqrt(1. - t * t); - P->rmn = 1. / (P->m * P->n); - P->es = 0.; - P->inv = 0; - P->fwd = s_forward; -ENDENTRY(P) +#endif diff --git a/src/PJ_urmfps.c b/src/PJ_urmfps.c index 5c5918ae..2322aa04 100644 --- a/src/PJ_urmfps.c +++ b/src/PJ_urmfps.c @@ -1,40 +1,166 @@ -#define PROJ_PARMS__ \ - double n, C_y; #define PJ_LIB__ #include <projects.h> + PROJ_HEAD(urmfps, "Urmaev Flat-Polar Sinusoidal") "\n\tPCyl, Sph.\n\tn="; PROJ_HEAD(wag1, "Wagner I (Kavraisky VI)") "\n\tPCyl, Sph."; + +struct pj_opaque { + double n, C_y; +}; + #define C_x 0.8773826753 #define Cy 1.139753528477 -FORWARD(s_forward); /* sphere */ - lp.phi = aasin(P->ctx,P->n * sin(lp.phi)); - xy.x = C_x * lp.lam * cos(lp.phi); - xy.y = P->C_y * lp.phi; - return (xy); -} -INVERSE(s_inverse); /* sphere */ - xy.y /= P->C_y; - lp.phi = aasin(P->ctx,sin(xy.y) / P->n); - lp.lam = xy.x / (C_x * cos(xy.y)); - return (lp); -} -FREEUP; if (P) pj_dalloc(P); } - static PJ * -setup(PJ *P) { - P->C_y = Cy / P->n; + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0, 0.0}; + lp.phi = aasin (P->ctx,P->opaque->n * sin (lp.phi)); + xy.x = C_x * lp.lam * cos (lp.phi); + xy.y = P->opaque->C_y * lp.phi; + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0, 0.0}; + xy.y /= P->opaque->C_y; + lp.phi = aasin(P->ctx, sin (xy.y) / P->opaque->n); + lp.lam = xy.x / (C_x * cos (xy.y)); + return lp; +} + + +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->opaque->C_y = Cy / P->opaque->n; P->es = 0.; P->inv = s_inverse; P->fwd = s_forward; return P; } -ENTRY0(urmfps) + + +PJ *PROJECTION(urmfps) { + struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); + if (0==Q) + return freeup_new (P); + P->opaque = Q; + if (pj_param(P->ctx, P->params, "tn").i) { - P->n = pj_param(P->ctx, P->params, "dn").f; - if (P->n <= 0. || P->n > 1.) + P->opaque->n = pj_param(P->ctx, P->params, "dn").f; + if (P->opaque->n <= 0. || P->opaque->n > 1.) E_ERROR(-40) } else E_ERROR(-40) -ENDENTRY(setup(P)) -ENTRY0(wag1) - P->n = 0.8660254037844386467637231707; -ENDENTRY(setup(P)) + + return setup(P); +} + + +PJ *PROJECTION(wag1) { + struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); + if (0==Q) + return freeup_new (P); + P->opaque = Q; + + P->opaque->n = 0.8660254037844386467637231707; + return setup(P); +} + + +#ifdef PJ_OMIT_SELFTEST +int pj_urmfps_selftest (void) {return 0;} +#else +int pj_urmfps_selftest (void) { + double tolerance_lp = 1e-10; + double tolerance_xy = 1e-7; + + char s_args[] = {"+proj=urmfps +a=6400000 +lat_1=0.5 +lat_2=2 +n=0.5"}; + + LP fwd_in[] = { + { 2, 1}, + { 2,-1}, + {-2, 1}, + {-2,-1} + }; + + XY s_fwd_expect[] = { + { 196001.70813419219, 127306.84332999329}, + { 196001.70813419219, -127306.84332999329}, + {-196001.70813419219, 127306.84332999329}, + {-196001.70813419219, -127306.84332999329}, + }; + + XY inv_in[] = { + { 200, 100}, + { 200,-100}, + {-200, 100}, + {-200,-100} + }; + + LP s_inv_expect[] = { + { 0.002040720839642371, 0.00078547381740438178}, + { 0.002040720839642371, -0.00078547381740438178}, + {-0.002040720839642371, 0.00078547381740438178}, + {-0.002040720839642371, -0.00078547381740438178}, + }; + + 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_wag1_selftest (void) {return 0;} +#else +int pj_wag1_selftest (void) { + double tolerance_lp = 1e-10; + double tolerance_xy = 1e-7; + + char s_args[] = {"+proj=wag1 +a=6400000 +lat_1=0.5 +lat_2=2 +n=0.5"}; + + LP fwd_in[] = { + { 2, 1}, + { 2,-1}, + {-2, 1}, + {-2,-1} + }; + + XY s_fwd_expect[] = { + { 195986.78156115755, 127310.07506065986}, + { 195986.78156115755, -127310.07506065986}, + {-195986.78156115755, 127310.07506065986}, + {-195986.78156115755, -127310.07506065986}, + }; + + XY inv_in[] = { + { 200, 100}, + { 200,-100}, + {-200, 100}, + {-200,-100} + }; + + LP s_inv_expect[] = { + { 0.002040720839738254, 0.00078547381739207999}, + { 0.002040720839738254, -0.00078547381739207999}, + {-0.002040720839738254, 0.00078547381739207999}, + {-0.002040720839738254, -0.00078547381739207999}, + }; + + 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 + diff --git a/src/pj_generic_selftest.c b/src/pj_generic_selftest.c index 5ac239e2..2af3f3b9 100644 --- a/src/pj_generic_selftest.c +++ b/src/pj_generic_selftest.c @@ -145,11 +145,15 @@ static int deviates_xy (XY expected, XY got, double tolerance) { Determine whether two XYs deviate by more than <tolerance>. + The test material ("expected" values) may contain coordinates that + are indeterminate. For those cases, we test the other coordinate + only by forcing expected and actual ("got") coordinates to 0. + ***********************************************************************/ - if (HUGE_VAL== expected.x) - return 0; - if (HUGE_VAL== expected.y) - return 0; + if ((HUGE_VAL== expected.x) || (isnan (expected.x))) + expected.x = got.x = 0; + if ((HUGE_VAL== expected.y) || (isnan (expected.y))) + expected.y = got.y = 0; if (hypot ( expected.x - got.x, expected.y - got.y ) > tolerance) return 1; return 0; @@ -169,10 +173,10 @@ static int deviates_lp (LP expected, LP got, double tolerance) { output from pj_inv) ***********************************************************************/ - if (HUGE_VAL== expected.lam) - return 0; - if (HUGE_VAL== expected.phi) - return 0; + if ((HUGE_VAL== expected.lam) || (isnan (expected.lam))) + expected.lam = got.lam = 0; + if ((HUGE_VAL== expected.phi) || (isnan (expected.phi))) + expected.phi = got.phi = 0; if (hypot ( DEG_TO_RAD * expected.lam - got.lam, DEG_TO_RAD * expected.phi - got.phi ) > tolerance) return 1; return 0; |
