aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Knudsen <knudsen.thomas@gmail.com>2016-05-20 00:44:56 +0200
committerThomas Knudsen <knudsen.thomas@gmail.com>2016-05-20 00:44:56 +0200
commit8b4c079485a68593b810ebfc14848ef6bc7864fa (patch)
tree5f8bf20027529b6365caba608d5372e19fce4fb3
parent1384b978373cead004211d8548518373d1f4950c (diff)
parent605dc6f3b47bf72c61712b275284212c66e541d0 (diff)
downloadPROJ-8b4c079485a68593b810ebfc14848ef6bc7864fa.tar.gz
PROJ-8b4c079485a68593b810ebfc14848ef6bc7864fa.zip
Merge pull request #373 from busstoptaktik/sdfe-refactor-macros--and-repair-generic-constructor-bug
First steps toward simplified macros/internals
-rw-r--r--.travis.yml4
-rw-r--r--man/man1/proj.115
-rw-r--r--src/Makefile.am5
-rw-r--r--src/PJ_aea.c309
-rw-r--r--src/PJ_aeqd.c544
-rw-r--r--src/PJ_airy.c142
-rw-r--r--src/PJ_aitoff.c219
-rw-r--r--src/PJ_august.c58
-rw-r--r--src/PJ_bacon.c180
-rw-r--r--src/PJ_bipc.c348
-rw-r--r--src/PJ_boggs.c51
-rw-r--r--src/PJ_bonne.c173
-rw-r--r--src/PJ_calcofi.c152
-rw-r--r--src/PJ_cass.c243
-rw-r--r--src/PJ_cc.c87
-rw-r--r--src/PJ_cea.c214
-rw-r--r--src/PJ_chamb.c275
-rw-r--r--src/PJ_collg.c76
-rw-r--r--src/PJ_comill.c134
-rw-r--r--src/PJ_crast.c112
-rw-r--r--src/PJ_denoy.c82
-rw-r--r--src/PJ_eck1.c113
-rw-r--r--src/PJ_eck2.c125
-rw-r--r--src/PJ_eck3.c335
-rw-r--r--src/PJ_eck4.c162
-rw-r--r--src/PJ_eck5.c113
-rw-r--r--src/PJ_eqc.c123
-rw-r--r--src/PJ_eqdc.c265
-rw-r--r--src/PJ_fahey.c114
-rw-r--r--src/PJ_fouc_s.c157
-rw-r--r--src/PJ_gall.c113
-rw-r--r--src/PJ_geos.c417
-rw-r--r--src/PJ_gins8.c87
-rw-r--r--src/PJ_gn_sinu.c445
-rw-r--r--src/PJ_gnom.c287
-rw-r--r--src/PJ_goode.c171
-rw-r--r--src/PJ_gstmerc.c171
-rw-r--r--src/PJ_hammer.c164
-rw-r--r--src/PJ_hatano.c185
-rw-r--r--src/PJ_healpix.c821
-rw-r--r--src/PJ_igh.c348
-rw-r--r--src/PJ_imw_p.c371
-rw-r--r--src/PJ_isea.c2295
-rw-r--r--src/PJ_krovak.c316
-rw-r--r--src/PJ_labrd.c287
-rw-r--r--src/PJ_laea.c553
-rw-r--r--src/PJ_lagrng.c132
-rw-r--r--src/PJ_larr.c77
-rw-r--r--src/PJ_lask.c102
-rw-r--r--src/PJ_lcc.c291
-rw-r--r--src/PJ_lcca.c206
-rw-r--r--src/PJ_loxim.c163
-rw-r--r--src/PJ_lsat.c389
-rw-r--r--src/PJ_mbt_fps.c129
-rw-r--r--src/PJ_mbtfpp.c139
-rw-r--r--src/PJ_mbtfpq.c159
-rw-r--r--src/PJ_merc.c167
-rw-r--r--src/PJ_mill.c101
-rw-r--r--src/PJ_minimal.c204
-rw-r--r--src/PJ_misrsom.c258
-rw-r--r--src/PJ_mod_ster.c719
-rw-r--r--src/PJ_moll.c299
-rw-r--r--src/PJ_natearth.c153
-rw-r--r--src/PJ_natearth2.c146
-rw-r--r--src/PJ_nell.c128
-rw-r--r--src/PJ_nell_h.c129
-rw-r--r--src/PJ_nocol.c130
-rw-r--r--src/PJ_nsper.c420
-rw-r--r--src/PJ_nzmg.c202
-rw-r--r--src/PJ_ob_tran.c334
-rw-r--r--src/PJ_ocea.c221
-rw-r--r--src/PJ_oea.c150
-rw-r--r--src/PJ_omerc.c395
-rw-r--r--src/PJ_ortho.c131
-rw-r--r--src/PJ_patterson.c259
-rw-r--r--src/PJ_poly.c174
-rw-r--r--src/PJ_putp2.c88
-rw-r--r--src/PJ_putp3.c191
-rw-r--r--src/PJ_putp4p.c200
-rw-r--r--src/PJ_putp5.c192
-rw-r--r--src/PJ_putp6.c247
-rw-r--r--src/PJ_qsc.c676
-rw-r--r--src/PJ_robin.c195
-rw-r--r--src/PJ_rpoly.c128
-rw-r--r--src/PJ_sch.c363
-rw-r--r--src/PJ_sconics.c827
-rw-r--r--src/PJ_somerc.c219
-rw-r--r--src/PJ_stere.c610
-rw-r--r--src/PJ_sterea.c205
-rw-r--r--src/PJ_sts.c367
-rw-r--r--src/PJ_tcc.c76
-rw-r--r--src/PJ_tcea.c104
-rw-r--r--src/PJ_tmerc.c373
-rw-r--r--src/PJ_tpeqd.c193
-rw-r--r--src/PJ_urm5.c103
-rw-r--r--src/PJ_urmfps.c176
-rw-r--r--src/PJ_vandg.c226
-rw-r--r--src/PJ_vandg2.c186
-rw-r--r--src/PJ_vandg4.c140
-rw-r--r--src/PJ_wag2.c81
-rw-r--r--src/PJ_wag3.c103
-rw-r--r--src/PJ_wag7.c66
-rw-r--r--src/PJ_wink1.c104
-rw-r--r--src/PJ_wink2.c89
-rw-r--r--src/lib_proj.cmake2
-rw-r--r--src/makefile.vc16
-rw-r--r--src/pj_fwd.c2
-rw-r--r--src/pj_fwd3d.c6
-rw-r--r--src/pj_generic_selftest.c197
-rw-r--r--src/pj_geocent.c94
-rw-r--r--src/pj_init.c96
-rw-r--r--src/pj_inv.c2
-rw-r--r--src/pj_inv3d.c8
-rw-r--r--src/pj_latlong.c120
-rw-r--r--src/pj_list.c49
-rw-r--r--src/pj_malloc.c57
-rw-r--r--src/pj_mutex.c8
-rw-r--r--src/pj_run_selftests.c78
-rw-r--r--src/pj_transform.c119
-rw-r--r--src/pj_utils.c30
-rw-r--r--src/proj.c16
-rw-r--r--src/proj.def179
-rw-r--r--src/proj_api.h5
-rw-r--r--src/proj_etmerc.c341
-rw-r--r--src/proj_rouss.c258
-rw-r--r--src/projects.h120
-rw-r--r--src/test228.c6
127 files changed, 18886 insertions, 7919 deletions
diff --git a/.travis.yml b/.travis.yml
index 7761baad..286d640c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -97,13 +97,15 @@ install:
fi
- make -j3
- make check
+ - ./src/proj -VC
- mv src/.libs/*.gc* src
script:
- echo "done"
after_success:
- - coveralls --extension .c
+# coveralls falsely reports .c-files in the build directories as having 100% coverage so we exclude them
+ - coveralls --extension .c --exclude build_autoconf --exclude build_cmake
- echo "$TRAVIS_SECURE_ENV_VARS"
- sh -c "./travis/build_docs.sh"
- sh -c 'if test "$TRAVIS_SECURE_ENV_VARS" = "true" -a "$TRAVIS_BRANCH" = "master"; then echo "publish website"; ./travis/add_deploy_key.sh; ./travis/deploy_website.sh $TRAVIS_BUILD_DIR/docs/build /tmp; fi'
diff --git a/man/man1/proj.1 b/man/man1/proj.1
index 645271c5..55d444c3 100644
--- a/man/man1/proj.1
+++ b/man/man1/proj.1
@@ -2,7 +2,7 @@
.nr LL 5.5i
.ad b
.hy 1
-.TH PROJ 1 "2000/03/21 Rel. 4.4"
+.TH PROJ 1 "2000/03/21 Rel. 4.4"
.SH NAME
proj \- forward cartographic projection filter
.br
@@ -10,7 +10,7 @@ invproj \- inverse cartographic projection filter
.SH SYNOPSIS
.B proj
[
-.B \-bceEfiIlmorsStTvVwW
+.B \-bcCeEfiIlmorsStTvVwW
[
.I args
] ] [
@@ -20,7 +20,7 @@ file[s]
.br
.B invproj
[
-.B \-bceEfiIlmorsStTwW
+.B \-bcCeEfiIlmorsStTwW
[
.I args
] ] [
@@ -52,6 +52,11 @@ process and allows bypassing formatting operations.
Selects binary input only (see
.B \-b option).
.TP
+.BI \-C
+Check. Invoke all built in self tests and report.
+Get more verbose report by preceding with the
+.B \-V option).
+.TP
.BI \-I
alternate method to specify inverse projection.
Redundant when used with
@@ -106,7 +111,7 @@ that can be selected with
.B +units
or
.B \-ld
-list of datums that can be selected with
+list of datums that can be selected with
.B +datum.
.TP
.BI \-r
@@ -278,7 +283,7 @@ projection coordinates within one datum.
The \fIcs2cs\fR program operates
similarly, but allows translation between any pair of definable coordinate
systems, including support for datum translation.
-.PP
+.PP
The \fIgeod\fR program provides the ability to compute geodesic (Great
Circle) computations.
.SH SEE ALSO
diff --git a/src/Makefile.am b/src/Makefile.am
index d59e3fde..b961c930 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -62,8 +62,9 @@ libproj_la_SOURCES = \
pj_factors.c pj_fwd.c pj_init.c pj_inv.c pj_fwd3d.c pj_inv3d.c\
pj_list.c pj_malloc.c pj_mlfn.c pj_msfn.c proj_mdist.c \
pj_open_lib.c pj_param.c pj_phi2.c pj_pr_list.c \
- pj_qsfn.c pj_strerrno.c pj_tsfn.c pj_units.c pj_ctx.c pj_log.c \
- pj_zpoly1.c rtodms.c vector1.c pj_release.c pj_gauss.c \
+ pj_qsfn.c pj_generic_selftest.c pj_run_selftests.c pj_strerrno.c \
+ pj_tsfn.c pj_units.c pj_ctx.c pj_log.c pj_zpoly1.c rtodms.c \
+ vector1.c pj_release.c pj_gauss.c \
PJ_healpix.c PJ_natearth.c PJ_natearth2.c PJ_calcofi.c pj_fileapi.c \
\
pj_gc_reader.c pj_gridcatalog.c \
diff --git a/src/PJ_aea.c b/src/PJ_aea.c
index 0881ba78..57898f3f 100644
--- a/src/PJ_aea.c
+++ b/src/PJ_aea.c
@@ -1,7 +1,9 @@
/******************************************************************************
* Project: PROJ.4
* Purpose: Implementation of the aea (Albers Equal Area) projection.
- * Author: Gerald Evenden
+ * and the leac (Lambert Equal Area Conic) projection
+ * Author: Gerald Evenden (1995)
+ * Thomas Knudsen (2016) - revise/add regression tests
*
******************************************************************************
* Copyright (c) 1995, Gerald Evenden
@@ -25,35 +27,21 @@
* DEALINGS IN THE SOFTWARE.
*****************************************************************************/
-#define PROJ_PARMS__ \
- double ec; \
- double n; \
- double c; \
- double dd; \
- double n2; \
- double rho0; \
- double rho; \
- double phi1; \
- double phi2; \
- double *en; \
- int ellips;
-
#define PJ_LIB__
#include <projects.h>
# define EPS10 1.e-10
# define TOL7 1.e-7
-PROJ_HEAD(aea, "Albers Equal Area")
- "\n\tConic Sph&Ell\n\tlat_1= lat_2=";
-PROJ_HEAD(leac, "Lambert Equal Area Conic")
- "\n\tConic, Sph&Ell\n\tlat_1= south";
+PROJ_HEAD(aea, "Albers Equal Area") "\n\tConic Sph&Ell\n\tlat_1= lat_2=";
+PROJ_HEAD(leac, "Lambert Equal Area Conic") "\n\tConic, Sph&Ell\n\tlat_1= south";
+
+
/* determine latitude angle phi-1 */
# define N_ITER 15
# define EPSILON 1.0e-7
# define TOL 1.0e-10
- static double
-phi1_(double qs, double Te, double Tone_es) {
+static double phi1_(double qs, double Te, double Tone_es) {
int i;
double Phi, sinpi, cospi, con, com, dphi;
@@ -73,86 +61,269 @@ phi1_(double qs, double Te, double Tone_es) {
} while (fabs(dphi) > TOL && --i);
return( i ? Phi : HUGE_VAL );
}
-FORWARD(e_forward); /* ellipsoid & spheroid */
- if ((P->rho = P->c - (P->ellips ? P->n * pj_qsfn(sin(lp.phi),
- P->e, P->one_es) : P->n2 * sin(lp.phi))) < 0.) F_ERROR
- P->rho = P->dd * sqrt(P->rho);
- xy.x = P->rho * sin( lp.lam *= P->n );
- xy.y = P->rho0 - P->rho * cos(lp.lam);
- return (xy);
+
+
+struct pj_opaque {
+ double ec;
+ double n;
+ double c;
+ double dd;
+ double n2;
+ double rho0;
+ double rho;
+ double phi1;
+ double phi2;
+ double *en;
+ int ellips;
+};
+
+
+
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoid/spheroid, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ if ((Q->rho = Q->c - (Q->ellips ? Q->n * pj_qsfn(sin(lp.phi),
+ P->e, P->one_es) : Q->n2 * sin(lp.phi))) < 0.) F_ERROR
+ Q->rho = Q->dd * sqrt(Q->rho);
+ xy.x = Q->rho * sin( lp.lam *= Q->n );
+ xy.y = Q->rho0 - Q->rho * cos(lp.lam);
+ return xy;
}
-INVERSE(e_inverse) /* ellipsoid & spheroid */;
- if( (P->rho = hypot(xy.x, xy.y = P->rho0 - xy.y)) != 0.0 ) {
- if (P->n < 0.) {
- P->rho = -P->rho;
+
+
+static LP e_inverse (XY xy, PJ *P) { /* Ellipsoid/spheroid, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ if( (Q->rho = hypot(xy.x, xy.y = Q->rho0 - xy.y)) != 0.0 ) {
+ if (Q->n < 0.) {
+ Q->rho = -Q->rho;
xy.x = -xy.x;
xy.y = -xy.y;
}
- lp.phi = P->rho / P->dd;
- if (P->ellips) {
- lp.phi = (P->c - lp.phi * lp.phi) / P->n;
- if (fabs(P->ec - fabs(lp.phi)) > TOL7) {
+ lp.phi = Q->rho / Q->dd;
+ if (Q->ellips) {
+ lp.phi = (Q->c - lp.phi * lp.phi) / Q->n;
+ if (fabs(Q->ec - fabs(lp.phi)) > TOL7) {
if ((lp.phi = phi1_(lp.phi, P->e, P->one_es)) == HUGE_VAL)
I_ERROR
} else
lp.phi = lp.phi < 0. ? -HALFPI : HALFPI;
- } else if (fabs(lp.phi = (P->c - lp.phi * lp.phi) / P->n2) <= 1.)
+ } else if (fabs(lp.phi = (Q->c - lp.phi * lp.phi) / Q->n2) <= 1.)
lp.phi = asin(lp.phi);
else
lp.phi = lp.phi < 0. ? -HALFPI : HALFPI;
- lp.lam = atan2(xy.x, xy.y) / P->n;
+ lp.lam = atan2(xy.x, xy.y) / Q->n;
} else {
lp.lam = 0.;
- lp.phi = P->n > 0. ? HALFPI : - HALFPI;
+ lp.phi = Q->n > 0. ? HALFPI : - HALFPI;
}
- return (lp);
+ return lp;
}
-FREEUP; if (P) { if (P->en) pj_dalloc(P->en); 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->en);
+ pj_dealloc (P->opaque);
+ return pj_dealloc(P);
+}
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+static PJ *setup(PJ *P) {
double cosphi, sinphi;
int secant;
+ struct pj_opaque *Q = P->opaque;
- if (fabs(P->phi1 + P->phi2) < EPS10) E_ERROR(-21);
- P->n = sinphi = sin(P->phi1);
- cosphi = cos(P->phi1);
- secant = fabs(P->phi1 - P->phi2) >= EPS10;
- if( (P->ellips = (P->es > 0.))) {
+ P->inv = e_inverse;
+ P->fwd = e_forward;
+
+ if (fabs(Q->phi1 + Q->phi2) < EPS10) E_ERROR(-21);
+ Q->n = sinphi = sin(Q->phi1);
+ cosphi = cos(Q->phi1);
+ secant = fabs(Q->phi1 - Q->phi2) >= EPS10;
+ if( (Q->ellips = (P->es > 0.))) {
double ml1, m1;
- if (!(P->en = pj_enfn(P->es))) E_ERROR_0;
+ if (!(Q->en = pj_enfn(P->es))) E_ERROR_0;
m1 = pj_msfn(sinphi, cosphi, P->es);
ml1 = pj_qsfn(sinphi, P->e, P->one_es);
if (secant) { /* secant cone */
double ml2, m2;
- sinphi = sin(P->phi2);
- cosphi = cos(P->phi2);
+ sinphi = sin(Q->phi2);
+ cosphi = cos(Q->phi2);
m2 = pj_msfn(sinphi, cosphi, P->es);
ml2 = pj_qsfn(sinphi, P->e, P->one_es);
- P->n = (m1 * m1 - m2 * m2) / (ml2 - ml1);
+ Q->n = (m1 * m1 - m2 * m2) / (ml2 - ml1);
}
- P->ec = 1. - .5 * P->one_es * log((1. - P->e) /
+ Q->ec = 1. - .5 * P->one_es * log((1. - P->e) /
(1. + P->e)) / P->e;
- P->c = m1 * m1 + P->n * ml1;
- P->dd = 1. / P->n;
- P->rho0 = P->dd * sqrt(P->c - P->n * pj_qsfn(sin(P->phi0),
+ Q->c = m1 * m1 + Q->n * ml1;
+ Q->dd = 1. / Q->n;
+ Q->rho0 = Q->dd * sqrt(Q->c - Q->n * pj_qsfn(sin(P->phi0),
P->e, P->one_es));
} else {
- if (secant) P->n = .5 * (P->n + sin(P->phi2));
- P->n2 = P->n + P->n;
- P->c = cosphi * cosphi + P->n2 * sinphi;
- P->dd = 1. / P->n;
- P->rho0 = P->dd * sqrt(P->c - P->n2 * sin(P->phi0));
+ if (secant) Q->n = .5 * (Q->n + sin(Q->phi2));
+ Q->n2 = Q->n + Q->n;
+ Q->c = cosphi * cosphi + Q->n2 * sinphi;
+ Q->dd = 1. / Q->n;
+ Q->rho0 = Q->dd * sqrt(Q->c - Q->n2 * sin(P->phi0));
}
- P->inv = e_inverse; P->fwd = e_forward;
+
return P;
}
-ENTRY1(aea,en)
- P->phi1 = pj_param(P->ctx, P->params, "rlat_1").f;
- P->phi2 = pj_param(P->ctx, P->params, "rlat_2").f;
-ENDENTRY(setup(P))
-ENTRY1(leac,en)
- P->phi2 = pj_param(P->ctx, P->params, "rlat_1").f;
- P->phi1 = pj_param(P->ctx, P->params, "bsouth").i ? - HALFPI: HALFPI;
-ENDENTRY(setup(P))
+
+
+PJ *PROJECTION(aea) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->phi1 = pj_param(P->ctx, P->params, "rlat_1").f;
+ Q->phi2 = pj_param(P->ctx, P->params, "rlat_2").f;
+ setup(P);
+ return P;
+}
+
+
+PJ *PROJECTION(leac) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->phi2 = pj_param(P->ctx, P->params, "rlat_1").f;
+ Q->phi1 = pj_param(P->ctx, P->params, "bsouth").i ? - HALFPI: HALFPI;
+ setup (P);
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_aea_selftest (void) {return 10000;}
+#else
+
+int pj_aea_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=aea +ellps=GRS80 +lat_1=0 +lat_2=2"};
+ char s_args[] = {"+proj=aea +a=6400000 +lat_1=0 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ {222571.60875710563, 110653.32674302977},
+ {222706.30650839131, -110484.26714439997},
+ {-222571.60875710563, 110653.32674302977},
+ {-222706.30650839131, -110484.26714439997},
+ };
+
+ XY s_fwd_expect[] = {
+ {223334.08517088494, 111780.43188447191},
+ {223470.15499168713, -111610.33943099028},
+ {-223334.08517088494, 111780.43188447191},
+ {-223470.15499168713, -111610.33943099028},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ {0.0017966310597749514, 0.00090436885862202158},
+ {0.0017966300767030448, -0.00090437009538581453},
+ {-0.0017966310597749514, 0.00090436885862202158},
+ {-0.0017966300767030448, -0.00090437009538581453},
+ };
+
+ LP s_inv_expect[] = {
+ {0.0017904935979658752, 0.00089524594491375306},
+ {0.0017904926216016812, -0.00089524716502493225},
+ {-0.0017904935979658752, 0.00089524594491375306},
+ {-0.0017904926216016812, -0.00089524716502493225},
+ };
+ 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
+
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_leac_selftest (void) {return 10000;}
+#else
+
+int pj_leac_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=leac +ellps=GRS80 +lat_1=0 +lat_2=2"};
+ char s_args[] = {"+proj=leac +a=6400000 +lat_1=0 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ {220685.14054297868, 112983.50088939646},
+ {224553.31227982609, -108128.63674487274},
+ {-220685.14054297868, 112983.50088939646},
+ {-224553.31227982609, -108128.63674487274},
+ };
+
+ XY s_fwd_expect[] = {
+ {221432.86859285168, 114119.45452653214},
+ {225331.72412711097, -109245.82943505641},
+ {-221432.86859285168, 114119.45452653214},
+ {-225331.72412711097, -109245.82943505641},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ {0.0017966446840328458, 0.00090435171340223211},
+ {0.0017966164523713021, -0.00090438724081843625},
+ {-0.0017966446840328458, 0.00090435171340223211},
+ {-0.0017966164523713021, -0.00090438724081843625},
+ };
+
+ LP s_inv_expect[] = {
+ {0.0017905070979748127, 0.00089522906964877795},
+ {0.001790479121519977, -0.00089526404022281043},
+ {-0.0017905070979748127, 0.00089522906964877795},
+ {-0.001790479121519977, -0.00089526404022281043},
+ };
+
+ 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_aeqd.c b/src/PJ_aeqd.c
index 22a75ac8..560d5a91 100644
--- a/src/PJ_aeqd.c
+++ b/src/PJ_aeqd.c
@@ -25,236 +25,346 @@
* DEALINGS IN THE SOFTWARE.
*****************************************************************************/
-#define PROJ_PARMS__ \
- double sinph0; \
- double cosph0; \
- double *en; \
- double M1; \
- double N1; \
- double Mp; \
- double He; \
- double G; \
- int mode; \
- struct geod_geodesic g;
#define PJ_LIB__
-#include "geodesic.h"
-#include <projects.h>
+#include "geodesic.h"
+#include <projects.h>
+
+struct pj_opaque {
+ double sinph0;
+ double cosph0;
+ double *en;
+ double M1;
+ double N1;
+ double Mp;
+ double He;
+ double G;
+ int mode;
+ struct geod_geodesic g;
+};
PROJ_HEAD(aeqd, "Azimuthal Equidistant") "\n\tAzi, Sph&Ell\n\tlat_0 guam";
#define EPS10 1.e-10
#define TOL 1.e-14
-#define N_POLE 0
-#define S_POLE 1
-#define EQUIT 2
-#define OBLIQ 3
-
-FORWARD(e_guam_fwd); /* Guam elliptical */
- double cosphi, sinphi, t;
-
- cosphi = cos(lp.phi);
- sinphi = sin(lp.phi);
- t = 1. / sqrt(1. - P->es * sinphi * sinphi);
- xy.x = lp.lam * cosphi * t;
- xy.y = pj_mlfn(lp.phi, sinphi, cosphi, P->en) - P->M1 +
- .5 * lp.lam * lp.lam * cosphi * sinphi * t;
- return (xy);
+#define N_POLE 0
+#define S_POLE 1
+#define EQUIT 2
+#define OBLIQ 3
+
+
+static XY e_guam_fwd(LP lp, PJ *P) { /* Guam elliptical */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double cosphi, sinphi, t;
+
+ cosphi = cos(lp.phi);
+ sinphi = sin(lp.phi);
+ t = 1. / sqrt(1. - P->es * sinphi * sinphi);
+ xy.x = lp.lam * cosphi * t;
+ xy.y = pj_mlfn(lp.phi, sinphi, cosphi, Q->en) - Q->M1 +
+ .5 * lp.lam * lp.lam * cosphi * sinphi * t;
+
+ return xy;
}
-FORWARD(e_forward); /* elliptical */
- double coslam, cosphi, sinphi, rho;
- double azi1, azi2, s12;
- double lam1, phi1, lam2, phi2;
-
- coslam = cos(lp.lam);
- cosphi = cos(lp.phi);
- sinphi = sin(lp.phi);
- switch (P->mode) {
- case N_POLE:
- coslam = - coslam;
- case S_POLE:
- xy.x = (rho = fabs(P->Mp - pj_mlfn(lp.phi, sinphi, cosphi, P->en))) *
- sin(lp.lam);
- xy.y = rho * coslam;
- break;
- case EQUIT:
- case OBLIQ:
- if (fabs(lp.lam) < EPS10 && fabs(lp.phi - P->phi0) < EPS10) {
- xy.x = xy.y = 0.;
- break;
- }
-
- phi1 = P->phi0 / DEG_TO_RAD; lam1 = P->lam0 / DEG_TO_RAD;
- phi2 = lp.phi / DEG_TO_RAD; lam2 = (lp.lam+P->lam0) / DEG_TO_RAD;
-
- geod_inverse(&P->g, phi1, lam1, phi2, lam2, &s12, &azi1, &azi2);
- azi1 *= DEG_TO_RAD;
- xy.x = s12 * sin(azi1) / P->a;
- xy.y = s12 * cos(azi1) / P->a;
- break;
- }
- 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 coslam, cosphi, sinphi, rho;
+ double azi1, azi2, s12;
+ double lam1, phi1, lam2, phi2;
+
+ coslam = cos(lp.lam);
+ cosphi = cos(lp.phi);
+ sinphi = sin(lp.phi);
+ switch (Q->mode) {
+ case N_POLE:
+ coslam = - coslam;
+ case S_POLE:
+ xy.x = (rho = fabs(Q->Mp - pj_mlfn(lp.phi, sinphi, cosphi, Q->en))) *
+ sin(lp.lam);
+ xy.y = rho * coslam;
+ break;
+ case EQUIT:
+ case OBLIQ:
+ if (fabs(lp.lam) < EPS10 && fabs(lp.phi - P->phi0) < EPS10) {
+ xy.x = xy.y = 0.;
+ break;
+ }
+
+ phi1 = P->phi0 / DEG_TO_RAD; lam1 = P->lam0 / DEG_TO_RAD;
+ phi2 = lp.phi / DEG_TO_RAD; lam2 = (lp.lam+P->lam0) / DEG_TO_RAD;
+
+ geod_inverse(&Q->g, phi1, lam1, phi2, lam2, &s12, &azi1, &azi2);
+ azi1 *= DEG_TO_RAD;
+ xy.x = s12 * sin(azi1) / P->a;
+ xy.y = s12 * cos(azi1) / P->a;
+ break;
+ }
+ return xy;
}
-FORWARD(s_forward); /* spherical */
- double coslam, cosphi, sinphi;
-
- sinphi = sin(lp.phi);
- cosphi = cos(lp.phi);
- coslam = cos(lp.lam);
- switch (P->mode) {
- case EQUIT:
- xy.y = cosphi * coslam;
- goto oblcon;
- case OBLIQ:
- xy.y = P->sinph0 * sinphi + P->cosph0 * cosphi * coslam;
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double coslam, cosphi, sinphi;
+
+ sinphi = sin(lp.phi);
+ cosphi = cos(lp.phi);
+ coslam = cos(lp.lam);
+ switch (Q->mode) {
+ case EQUIT:
+ xy.y = cosphi * coslam;
+ goto oblcon;
+ case OBLIQ:
+ xy.y = Q->sinph0 * sinphi + Q->cosph0 * cosphi * coslam;
oblcon:
- if (fabs(fabs(xy.y) - 1.) < TOL)
- if (xy.y < 0.)
- F_ERROR
- else
- xy.x = xy.y = 0.;
- else {
- xy.y = acos(xy.y);
- xy.y /= sin(xy.y);
- xy.x = xy.y * cosphi * sin(lp.lam);
- xy.y *= (P->mode == EQUIT) ? sinphi :
- P->cosph0 * sinphi - P->sinph0 * cosphi * coslam;
- }
- break;
- case N_POLE:
- lp.phi = -lp.phi;
- coslam = -coslam;
- case S_POLE:
- if (fabs(lp.phi - HALFPI) < EPS10) F_ERROR;
- xy.x = (xy.y = (HALFPI + lp.phi)) * sin(lp.lam);
- xy.y *= coslam;
- break;
- }
- return (xy);
+ if (fabs(fabs(xy.y) - 1.) < TOL)
+ if (xy.y < 0.)
+ F_ERROR
+ else
+ xy.x = xy.y = 0.;
+ else {
+ xy.y = acos(xy.y);
+ xy.y /= sin(xy.y);
+ xy.x = xy.y * cosphi * sin(lp.lam);
+ xy.y *= (Q->mode == EQUIT) ? sinphi :
+ Q->cosph0 * sinphi - Q->sinph0 * cosphi * coslam;
+ }
+ break;
+ case N_POLE:
+ lp.phi = -lp.phi;
+ coslam = -coslam;
+ case S_POLE:
+ if (fabs(lp.phi - HALFPI) < EPS10) F_ERROR;
+ xy.x = (xy.y = (HALFPI + lp.phi)) * sin(lp.lam);
+ xy.y *= coslam;
+ break;
+ }
+ return xy;
}
-INVERSE(e_guam_inv); /* Guam elliptical */
- double x2, t;
- int i;
-
- x2 = 0.5 * xy.x * xy.x;
- lp.phi = P->phi0;
- for (i = 0; i < 3; ++i) {
- t = P->e * sin(lp.phi);
- lp.phi = pj_inv_mlfn(P->ctx, P->M1 + xy.y -
- x2 * tan(lp.phi) * (t = sqrt(1. - t * t)), P->es, P->en);
- }
- lp.lam = xy.x * t / cos(lp.phi);
- return (lp);
+
+
+static LP e_guam_inv(XY xy, PJ *P) { /* Guam elliptical */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double x2, t;
+ int i;
+
+ x2 = 0.5 * xy.x * xy.x;
+ lp.phi = P->phi0;
+ for (i = 0; i < 3; ++i) {
+ t = P->e * sin(lp.phi);
+ lp.phi = pj_inv_mlfn(P->ctx, Q->M1 + xy.y -
+ x2 * tan(lp.phi) * (t = sqrt(1. - t * t)), P->es, Q->en);
+ }
+ lp.lam = xy.x * t / cos(lp.phi);
+ return lp;
}
-INVERSE(e_inverse); /* elliptical */
- double c;
- double azi1, azi2, s12, x2, y2, lat1, lon1, lat2, lon2;
-
- if ((c = hypot(xy.x, xy.y)) < EPS10) {
- lp.phi = P->phi0;
- lp.lam = 0.;
- return (lp);
- }
- if (P->mode == OBLIQ || P->mode == EQUIT) {
-
- x2 = xy.x * P->a;
- y2 = xy.y * P->a;
- lat1 = P->phi0 / DEG_TO_RAD;
- lon1 = P->lam0 / DEG_TO_RAD;
- azi1 = atan2(x2, y2) / DEG_TO_RAD;
- s12 = sqrt(x2 * x2 + y2 * y2);
- geod_direct(&P->g, lat1, lon1, azi1, s12, &lat2, &lon2, &azi2);
- lp.phi = lat2 * DEG_TO_RAD;
- lp.lam = lon2 * DEG_TO_RAD;
- lp.lam -= P->lam0;
- } else { /* Polar */
- lp.phi = pj_inv_mlfn(P->ctx, P->mode == N_POLE ? P->Mp - c : P->Mp + c,
- P->es, P->en);
- lp.lam = atan2(xy.x, P->mode == N_POLE ? -xy.y : xy.y);
- }
- return (lp);
+
+
+static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double c;
+ double azi1, azi2, s12, x2, y2, lat1, lon1, lat2, lon2;
+
+ if ((c = hypot(xy.x, xy.y)) < EPS10) {
+ lp.phi = P->phi0;
+ lp.lam = 0.;
+ return (lp);
+ }
+ if (Q->mode == OBLIQ || Q->mode == EQUIT) {
+
+ x2 = xy.x * P->a;
+ y2 = xy.y * P->a;
+ lat1 = P->phi0 / DEG_TO_RAD;
+ lon1 = P->lam0 / DEG_TO_RAD;
+ azi1 = atan2(x2, y2) / DEG_TO_RAD;
+ s12 = sqrt(x2 * x2 + y2 * y2);
+ geod_direct(&Q->g, lat1, lon1, azi1, s12, &lat2, &lon2, &azi2);
+ lp.phi = lat2 * DEG_TO_RAD;
+ lp.lam = lon2 * DEG_TO_RAD;
+ lp.lam -= P->lam0;
+ } else { /* Polar */
+ lp.phi = pj_inv_mlfn(P->ctx, Q->mode == N_POLE ? Q->Mp - c : Q->Mp + c,
+ P->es, Q->en);
+ lp.lam = atan2(xy.x, Q->mode == N_POLE ? -xy.y : xy.y);
+ }
+ return lp;
}
-INVERSE(s_inverse); /* spherical */
- double cosc, c_rh, sinc;
-
- if ((c_rh = hypot(xy.x, xy.y)) > PI) {
- if (c_rh - EPS10 > PI) I_ERROR;
- c_rh = PI;
- } else if (c_rh < EPS10) {
- lp.phi = P->phi0;
- lp.lam = 0.;
- return (lp);
- }
- if (P->mode == OBLIQ || P->mode == EQUIT) {
- sinc = sin(c_rh);
- cosc = cos(c_rh);
- if (P->mode == EQUIT) {
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double cosc, c_rh, sinc;
+
+ if ((c_rh = hypot(xy.x, xy.y)) > PI) {
+ if (c_rh - EPS10 > PI) I_ERROR;
+ c_rh = PI;
+ } else if (c_rh < EPS10) {
+ lp.phi = P->phi0;
+ lp.lam = 0.;
+ return (lp);
+ }
+ if (Q->mode == OBLIQ || Q->mode == EQUIT) {
+ sinc = sin(c_rh);
+ cosc = cos(c_rh);
+ if (Q->mode == EQUIT) {
lp.phi = aasin(P->ctx, xy.y * sinc / c_rh);
- xy.x *= sinc;
- xy.y = cosc * c_rh;
- } else {
- lp.phi = aasin(P->ctx,cosc * P->sinph0 + xy.y * sinc * P->cosph0 /
- c_rh);
- xy.y = (cosc - P->sinph0 * sin(lp.phi)) * c_rh;
- xy.x *= sinc * P->cosph0;
- }
- lp.lam = xy.y == 0. ? 0. : atan2(xy.x, xy.y);
- } else if (P->mode == N_POLE) {
- lp.phi = HALFPI - c_rh;
- lp.lam = atan2(xy.x, -xy.y);
- } else {
- lp.phi = c_rh - HALFPI;
- lp.lam = atan2(xy.x, xy.y);
- }
- return (lp);
+ xy.x *= sinc;
+ xy.y = cosc * c_rh;
+ } else {
+ lp.phi = aasin(P->ctx,cosc * Q->sinph0 + xy.y * sinc * Q->cosph0 /
+ c_rh);
+ xy.y = (cosc - Q->sinph0 * sin(lp.phi)) * c_rh;
+ xy.x *= sinc * Q->cosph0;
+ }
+ lp.lam = xy.y == 0. ? 0. : atan2(xy.x, xy.y);
+ } else if (Q->mode == N_POLE) {
+ lp.phi = HALFPI - c_rh;
+ lp.lam = atan2(xy.x, -xy.y);
+ } else {
+ lp.phi = c_rh - HALFPI;
+ lp.lam = atan2(xy.x, xy.y);
+ }
+ return lp;
+}
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+ if (0==P->opaque)
+ return pj_dealloc (P);
+
+ if (P->opaque->en)
+ pj_dealloc(P->opaque->en);
+ pj_dealloc (P->opaque);
+ return pj_dealloc(P);
+}
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
}
-FREEUP;
- if (P) {
- if (P->en)
- pj_dalloc(P->en);
- pj_dalloc(P);
- }
+
+
+PJ *PROJECTION(aeqd) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ geod_init(&Q->g, P->a, P->es / (1 + sqrt(P->one_es)));
+ P->phi0 = pj_param(P->ctx, P->params, "rlat_0").f;
+ if (fabs(fabs(P->phi0) - HALFPI) < EPS10) {
+ Q->mode = P->phi0 < 0. ? S_POLE : N_POLE;
+ Q->sinph0 = P->phi0 < 0. ? -1. : 1.;
+ Q->cosph0 = 0.;
+ } else if (fabs(P->phi0) < EPS10) {
+ Q->mode = EQUIT;
+ Q->sinph0 = 0.;
+ Q->cosph0 = 1.;
+ } else {
+ Q->mode = OBLIQ;
+ Q->sinph0 = sin(P->phi0);
+ Q->cosph0 = cos(P->phi0);
+ }
+ if (! P->es) {
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+ } else {
+ if (!(Q->en = pj_enfn(P->es))) E_ERROR_0;
+ if (pj_param(P->ctx, P->params, "bguam").i) {
+ Q->M1 = pj_mlfn(P->phi0, Q->sinph0, Q->cosph0, Q->en);
+ P->inv = e_guam_inv;
+ P->fwd = e_guam_fwd;
+ } else {
+ switch (Q->mode) {
+ case N_POLE:
+ Q->Mp = pj_mlfn(HALFPI, 1., 0., Q->en);
+ break;
+ case S_POLE:
+ Q->Mp = pj_mlfn(-HALFPI, -1., 0., Q->en);
+ break;
+ case EQUIT:
+ case OBLIQ:
+ P->inv = e_inverse; P->fwd = e_forward;
+ Q->N1 = 1. / sqrt(1. - P->es * Q->sinph0 * Q->sinph0);
+ Q->G = Q->sinph0 * (Q->He = P->e / sqrt(P->one_es));
+ Q->He *= Q->cosph0;
+ break;
+ }
+ P->inv = e_inverse;
+ P->fwd = e_forward;
+ }
+ }
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_aeqd_selftest (void) {return 0;}
+#else
+
+int pj_aeqd_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=aeqd +ellps=GRS80 +lat_1=0.5 +lat_2=2"};
+ char s_args[] = {"+proj=aeqd +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ { 222616.522190051648, 110596.996549550197},
+ { 222616.522190051648, -110596.996549550211},
+ {-222616.522190051648, 110596.996549550197},
+ {-222616.522190051648, -110596.996549550211},
+ };
+
+ XY s_fwd_expect[] = {
+ { 223379.456047271, 111723.757570854126},
+ { 223379.456047271, -111723.757570854126},
+ {-223379.456047271, 111723.757570854126},
+ {-223379.456047271, -111723.757570854126},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ { 0.00179663056838724787, 0.000904369476930248902},
+ { 0.00179663056838724787, -0.000904369476930248469},
+ {-0.00179663056838724787, 0.000904369476930248902},
+ {-0.00179663056838724787, -0.000904369476930248469},
+ };
+
+ LP s_inv_expect[] = {
+ { 0.00179049310992953335, 0.000895246554746200623},
+ { 0.00179049310992953335, -0.000895246554746200623},
+ {-0.00179049310992953335, 0.000895246554746200623},
+ {-0.00179049310992953335, -0.000895246554746200623},
+ };
+
+ 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(aeqd, en)
- geod_init(&P->g, P->a, P->es / (1 + sqrt(P->one_es)));
- P->phi0 = pj_param(P->ctx, P->params, "rlat_0").f;
- if (fabs(fabs(P->phi0) - HALFPI) < EPS10) {
- P->mode = P->phi0 < 0. ? S_POLE : N_POLE;
- P->sinph0 = P->phi0 < 0. ? -1. : 1.;
- P->cosph0 = 0.;
- } else if (fabs(P->phi0) < EPS10) {
- P->mode = EQUIT;
- P->sinph0 = 0.;
- P->cosph0 = 1.;
- } else {
- P->mode = OBLIQ;
- P->sinph0 = sin(P->phi0);
- P->cosph0 = cos(P->phi0);
- }
- if (! P->es) {
- P->inv = s_inverse; P->fwd = s_forward;
- } else {
- if (!(P->en = pj_enfn(P->es))) E_ERROR_0;
- if (pj_param(P->ctx, P->params, "bguam").i) {
- P->M1 = pj_mlfn(P->phi0, P->sinph0, P->cosph0, P->en);
- P->inv = e_guam_inv; P->fwd = e_guam_fwd;
- } else {
- switch (P->mode) {
- case N_POLE:
- P->Mp = pj_mlfn(HALFPI, 1., 0., P->en);
- break;
- case S_POLE:
- P->Mp = pj_mlfn(-HALFPI, -1., 0., P->en);
- break;
- case EQUIT:
- case OBLIQ:
- P->inv = e_inverse; P->fwd = e_forward;
- P->N1 = 1. / sqrt(1. - P->es * P->sinph0 * P->sinph0);
- P->G = P->sinph0 * (P->He = P->e / sqrt(P->one_es));
- P->He *= P->cosph0;
- break;
- }
- P->inv = e_inverse; P->fwd = e_forward;
- }
- }
-ENDENTRY(P)
+
+
+#endif
diff --git a/src/PJ_airy.c b/src/PJ_airy.c
index 73a51e5b..c1d31d6c 100644
--- a/src/PJ_airy.c
+++ b/src/PJ_airy.c
@@ -1,7 +1,8 @@
/******************************************************************************
* Project: PROJ.4
* Purpose: Implementation of the airy (Airy) projection.
- * Author: Gerald Evenden
+ * Author: Gerald Evenden (1995)
+ * Thomas Knudsen (2016) - revise/add regression tests
*
******************************************************************************
* Copyright (c) 1995, Gerald Evenden
@@ -25,96 +26,161 @@
* DEALINGS IN THE SOFTWARE.
*****************************************************************************/
-#define PROJ_PARMS__ \
- double p_halfpi; \
- double sinph0; \
- double cosph0; \
- double Cb; \
- int mode; \
- int no_cut; /* do not cut at hemisphere limit */
#define PJ_LIB__
#include <projects.h>
PROJ_HEAD(airy, "Airy") "\n\tMisc Sph, no inv.\n\tno_cut lat_b=";
+
+struct pj_opaque {
+ double p_halfpi;
+ double sinph0;
+ double cosph0;
+ double Cb;
+ int mode;
+ int no_cut; /* do not cut at hemisphere limit */
+};
+
+
# define EPS 1.e-10
# define N_POLE 0
# define S_POLE 1
# define EQUIT 2
# define OBLIQ 3
-FORWARD(s_forward); /* spheroid */
+
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
double sinlam, coslam, cosphi, sinphi, t, s, Krho, cosz;
sinlam = sin(lp.lam);
coslam = cos(lp.lam);
- switch (P->mode) {
+ switch (Q->mode) {
case EQUIT:
case OBLIQ:
sinphi = sin(lp.phi);
cosphi = cos(lp.phi);
cosz = cosphi * coslam;
- if (P->mode == OBLIQ)
- cosz = P->sinph0 * sinphi + P->cosph0 * cosz;
- if (!P->no_cut && cosz < -EPS)
+ if (Q->mode == OBLIQ)
+ cosz = Q->sinph0 * sinphi + Q->cosph0 * cosz;
+ if (!Q->no_cut && cosz < -EPS)
F_ERROR;
if (fabs(s = 1. - cosz) > EPS) {
t = 0.5 * (1. + cosz);
- Krho = -log(t)/s - P->Cb / t;
+ Krho = -log(t)/s - Q->Cb / t;
} else
- Krho = 0.5 - P->Cb;
+ Krho = 0.5 - Q->Cb;
xy.x = Krho * cosphi * sinlam;
- if (P->mode == OBLIQ)
- xy.y = Krho * (P->cosph0 * sinphi -
- P->sinph0 * cosphi * coslam);
+ if (Q->mode == OBLIQ)
+ xy.y = Krho * (Q->cosph0 * sinphi -
+ Q->sinph0 * cosphi * coslam);
else
xy.y = Krho * sinphi;
break;
case S_POLE:
case N_POLE:
- lp.phi = fabs(P->p_halfpi - lp.phi);
- if (!P->no_cut && (lp.phi - EPS) > HALFPI)
+ lp.phi = fabs(Q->p_halfpi - lp.phi);
+ if (!Q->no_cut && (lp.phi - EPS) > HALFPI)
F_ERROR;
if ((lp.phi *= 0.5) > EPS) {
t = tan(lp.phi);
- Krho = -2.*(log(cos(lp.phi)) / t + t * P->Cb);
+ Krho = -2.*(log(cos(lp.phi)) / t + t * Q->Cb);
xy.x = Krho * sinlam;
xy.y = Krho * coslam;
- if (P->mode == N_POLE)
+ if (Q->mode == N_POLE)
xy.y = -xy.y;
} else
xy.x = xy.y = 0.;
}
- return (xy);
+ return xy;
+}
+
+
+
+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;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(airy)
+
+
+PJ *PROJECTION(airy) {
double beta;
- P->no_cut = pj_param(P->ctx, P->params, "bno_cut").i;
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+
+ P->opaque = Q;
+
+ Q->no_cut = pj_param(P->ctx, P->params, "bno_cut").i;
beta = 0.5 * (HALFPI - pj_param(P->ctx, P->params, "rlat_b").f);
if (fabs(beta) < EPS)
- P->Cb = -0.5;
+ Q->Cb = -0.5;
else {
- P->Cb = 1./tan(beta);
- P->Cb *= P->Cb * log(cos(beta));
+ Q->Cb = 1./tan(beta);
+ Q->Cb *= Q->Cb * log(cos(beta));
}
+
if (fabs(fabs(P->phi0) - HALFPI) < EPS)
if (P->phi0 < 0.) {
- P->p_halfpi = -HALFPI;
- P->mode = S_POLE;
+ Q->p_halfpi = -HALFPI;
+ Q->mode = S_POLE;
} else {
- P->p_halfpi = HALFPI;
- P->mode = N_POLE;
+ Q->p_halfpi = HALFPI;
+ Q->mode = N_POLE;
}
else {
if (fabs(P->phi0) < EPS)
- P->mode = EQUIT;
+ Q->mode = EQUIT;
else {
- P->mode = OBLIQ;
- P->sinph0 = sin(P->phi0);
- P->cosph0 = cos(P->phi0);
+ Q->mode = OBLIQ;
+ Q->sinph0 = sin(P->phi0);
+ Q->cosph0 = cos(P->phi0);
}
}
P->fwd = s_forward;
P->es = 0.;
-ENDENTRY(P)
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_airy_selftest (void) {return 0;}
+#else
+
+int pj_airy_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=airy +a=6400000 +lat_1=0 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 189109.88690862127, 94583.752387504152},
+ { 189109.88690862127, -94583.752387504152},
+ {-189109.88690862127, 94583.752387504152},
+ {-189109.88690862127, -94583.752387504152},
+ };
+
+ return pj_generic_selftest (0, s_args, tolerance_xy, tolerance_lp, 4, 0, fwd_in, 0, s_fwd_expect, 0, 0, 0);
+}
+
+#endif
diff --git a/src/PJ_aitoff.c b/src/PJ_aitoff.c
index d5350f2c..c9fe1c22 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,150 @@ 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;
+
+ 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;
+
+ 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
diff --git a/src/PJ_august.c b/src/PJ_august.c
index 496fc3c3..83463e9f 100644
--- a/src/PJ_august.c
+++ b/src/PJ_august.c
@@ -1,8 +1,13 @@
#define PJ_LIB__
#include <projects.h>
+
+
PROJ_HEAD(august, "August Epicycloidal") "\n\tMisc Sph, no inv.";
#define M 1.333333333333333
-FORWARD(s_forward); /* spheroid */
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
double t, c1, c, x1, x12, y1, y12;
(void) P;
@@ -15,5 +20,52 @@ FORWARD(s_forward); /* spheroid */
xy.y = M * y1 * (3. + 3. * x12 - y12);
return (xy);
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(august) P->inv = 0; P->fwd = s_forward; P->es = 0.; ENDENTRY(P)
+
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ return pj_dealloc(P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(august) {
+ P->inv = 0;
+ P->fwd = s_forward;
+ P->es = 0.;
+ return P;
+}
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_august_selftest (void) {return 0;}
+#else
+
+int pj_august_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=august +a=6400000 +lat_1=0 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ {223404.97818097242, 111722.34028976287},
+ {223404.97818097242, -111722.34028976287},
+ {-223404.97818097242, 111722.34028976287},
+ {-223404.97818097242, -111722.34028976287},
+ };
+
+ return pj_generic_selftest (0, s_args, tolerance_xy, tolerance_lp, 4, 4, fwd_in, 0, s_fwd_expect, 0, 0, 0);
+}
+
+
+#endif
diff --git a/src/PJ_bacon.c b/src/PJ_bacon.c
index dfc559b8..75afaeb0 100644
--- a/src/PJ_bacon.c
+++ b/src/PJ_bacon.c
@@ -1,19 +1,27 @@
# define HLFPI2 2.46740110027233965467
# define EPS 1e-10
-#define PROJ_PARMS__ \
- int bacn; \
- int ortl;
#define PJ_LIB__
#include <projects.h>
+
+
+struct pj_opaque {
+ int bacn;
+ int ortl;
+};
+
PROJ_HEAD(apian, "Apian Globular I") "\n\tMisc Sph, no inv.";
PROJ_HEAD(ortel, "Ortelius Oval") "\n\tMisc Sph, no inv.";
PROJ_HEAD(bacon, "Bacon Globular") "\n\tMisc Sph, no inv.";
-FORWARD(s_forward); /* spheroid */
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
double ax, f;
- xy.y = P->bacn ? HALFPI * sin(lp.phi) : lp.phi;
+ xy.y = Q->bacn ? HALFPI * sin(lp.phi) : lp.phi;
if ((ax = fabs(lp.lam)) >= EPS) {
- if (P->ortl && ax >= HALFPI)
+ if (Q->ortl && ax >= HALFPI)
xy.x = sqrt(HLFPI2 - lp.phi * lp.phi + EPS) + ax - HALFPI;
else {
f = 0.5 * (HLFPI2 / ax + ax);
@@ -24,18 +32,148 @@ FORWARD(s_forward); /* spheroid */
xy.x = 0.;
return (xy);
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(bacon)
- P->bacn = 1;
- P->ortl = 0;
- P->es = 0.; P->fwd = s_forward;
-ENDENTRY(P)
-ENTRY0(apian)
- P->bacn = P->ortl = 0;
- P->es = 0.; P->fwd = s_forward;
-ENDENTRY(P)
-ENTRY0(ortel)
- P->bacn = 0;
- P->ortl = 1;
- P->es = 0.; P->fwd = s_forward;
-ENDENTRY(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;
+}
+
+
+PJ *PROJECTION(bacon) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->bacn = 1;
+ Q->ortl = 0;
+ P->es = 0.;
+ P->fwd = s_forward;
+ return P;
+}
+
+
+PJ *PROJECTION(apian) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->bacn = Q->ortl = 0;
+ P->es = 0.;
+ P->fwd = s_forward;
+ return P;
+}
+
+
+PJ *PROJECTION(ortel) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->bacn = 0;
+ Q->ortl = 1;
+ P->es = 0.;
+ P->fwd = s_forward;
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_bacon_selftest (void) {return 0;}
+#else
+int pj_bacon_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=bacon +a=6400000 +lat_1=0 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ {223334.13255596498, 175450.72592266591},
+ {223334.13255596498, -175450.72592266591},
+ {-223334.13255596498, 175450.72592266591},
+ {-223334.13255596498, -175450.72592266591},
+ };
+
+ return pj_generic_selftest (0, s_args, tolerance_xy, tolerance_lp, 4, 0, fwd_in, 0, s_fwd_expect, 0, 0, 0);
+}
+#endif
+
+
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_apian_selftest (void) {return 0;}
+#else
+int pj_apian_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=apian +a=6400000 +lat_1=0 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 223374.57735525275, 111701.07212763709},
+ { 223374.57735525275, -111701.07212763709},
+ {-223374.57735525275, 111701.07212763709},
+ {-223374.57735525275, -111701.07212763709},
+ };
+
+ return pj_generic_selftest (0, s_args, tolerance_xy, tolerance_lp, 4, 0, fwd_in, 0, s_fwd_expect, 0, 0, 0);
+}
+#endif
+
+
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_ortel_selftest (void) {return 0;}
+#else
+int pj_ortel_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=ortel +a=6400000 +lat_1=0 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 223374.57735525275, 111701.07212763709},
+ { 223374.57735525275, -111701.07212763709},
+ {-223374.57735525275, 111701.07212763709},
+ {-223374.57735525275, -111701.07212763709},
+ };
+ return pj_generic_selftest (0, s_args, tolerance_xy, tolerance_lp, 4, 0, fwd_in, 0, s_fwd_expect, 0, 0, 0);
+}
+#endif
+
diff --git a/src/PJ_bipc.c b/src/PJ_bipc.c
index 471e7266..96082604 100644
--- a/src/PJ_bipc.c
+++ b/src/PJ_bipc.c
@@ -1,132 +1,224 @@
-#define PROJ_PARMS__ \
- int noskew;
#define PJ_LIB__
-# include <projects.h>
-PROJ_HEAD(bipc, "Bipolar conic of western hemisphere")
- "\n\tConic Sph.";
-# define EPS 1e-10
-# define EPS10 1e-10
+#include <projects.h>
+
+PROJ_HEAD(bipc, "Bipolar conic of western hemisphere") "\n\tConic Sph.";
+
+# define EPS 1e-10
+# define EPS10 1e-10
# define ONEEPS 1.000000001
-# define NITER 10
-# define lamB -.34894976726250681539
-# define n .63055844881274687180
-# define F 1.89724742567461030582
-# define Azab .81650043674686363166
-# define Azba 1.82261843856185925133
-# define T 1.27246578267089012270
-# define rhoc 1.20709121521568721927
-# define cAzc .69691523038678375519
-# define sAzc .71715351331143607555
-# define C45 .70710678118654752469
-# define S45 .70710678118654752410
-# define C20 .93969262078590838411
-# define S20 -.34202014332566873287
-# define R110 1.91986217719376253360
-# define R104 1.81514242207410275904
-FORWARD(s_forward); /* spheroid */
- double cphi, sphi, tphi, t, al, Az, z, Av, cdlam, sdlam, r;
- int tag;
-
- cphi = cos(lp.phi);
- sphi = sin(lp.phi);
- cdlam = cos(sdlam = lamB - lp.lam);
- sdlam = sin(sdlam);
- if (fabs(fabs(lp.phi) - HALFPI) < EPS10) {
- Az = lp.phi < 0. ? PI : 0.;
- tphi = HUGE_VAL;
- } else {
- tphi = sphi / cphi;
- Az = atan2(sdlam , C45 * (tphi - cdlam));
- }
- if( (tag = (Az > Azba)) ) {
- cdlam = cos(sdlam = lp.lam + R110);
- sdlam = sin(sdlam);
- z = S20 * sphi + C20 * cphi * cdlam;
- if (fabs(z) > 1.) {
- if (fabs(z) > ONEEPS) F_ERROR
- else z = z < 0. ? -1. : 1.;
- } else
- z = acos(z);
- if (tphi != HUGE_VAL)
- Az = atan2(sdlam, (C20 * tphi - S20 * cdlam));
- Av = Azab;
- xy.y = rhoc;
- } else {
- z = S45 * (sphi + cphi * cdlam);
- if (fabs(z) > 1.) {
- if (fabs(z) > ONEEPS) F_ERROR
- else z = z < 0. ? -1. : 1.;
- } else
- z = acos(z);
- Av = Azba;
- xy.y = -rhoc;
- }
- if (z < 0.) F_ERROR;
- r = F * (t = pow(tan(.5 * z), n));
- if ((al = .5 * (R104 - z)) < 0.) F_ERROR;
- al = (t + pow(al, n)) / T;
- if (fabs(al) > 1.) {
- if (fabs(al) > ONEEPS) F_ERROR
- else al = al < 0. ? -1. : 1.;
- } else
- al = acos(al);
- if (fabs(t = n * (Av - Az)) < al)
- r /= cos(al + (tag ? t : -t));
- xy.x = r * sin(t);
- xy.y += (tag ? -r : r) * cos(t);
- if (P->noskew) {
- t = xy.x;
- xy.x = -xy.x * cAzc - xy.y * sAzc;
- xy.y = -xy.y * cAzc + t * sAzc;
- }
- return (xy);
+# define NITER 10
+# define lamB -.34894976726250681539
+# define n .63055844881274687180
+# define F 1.89724742567461030582
+# define Azab .81650043674686363166
+# define Azba 1.82261843856185925133
+# define T 1.27246578267089012270
+# define rhoc 1.20709121521568721927
+# define cAzc .69691523038678375519
+# define sAzc .71715351331143607555
+# define C45 .70710678118654752469
+# define S45 .70710678118654752410
+# define C20 .93969262078590838411
+# define S20 -.34202014332566873287
+# define R110 1.91986217719376253360
+# define R104 1.81514242207410275904
+
+
+struct pj_opaque {
+ int noskew;
+};
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double cphi, sphi, tphi, t, al, Az, z, Av, cdlam, sdlam, r;
+ int tag;
+
+ cphi = cos(lp.phi);
+ sphi = sin(lp.phi);
+ cdlam = cos(sdlam = lamB - lp.lam);
+ sdlam = sin(sdlam);
+ if (fabs(fabs(lp.phi) - HALFPI) < EPS10) {
+ Az = lp.phi < 0. ? PI : 0.;
+ tphi = HUGE_VAL;
+ } else {
+ tphi = sphi / cphi;
+ Az = atan2(sdlam , C45 * (tphi - cdlam));
+ }
+ if( (tag = (Az > Azba)) ) {
+ cdlam = cos(sdlam = lp.lam + R110);
+ sdlam = sin(sdlam);
+ z = S20 * sphi + C20 * cphi * cdlam;
+ if (fabs(z) > 1.) {
+ if (fabs(z) > ONEEPS) F_ERROR
+ else z = z < 0. ? -1. : 1.;
+ } else
+ z = acos(z);
+ if (tphi != HUGE_VAL)
+ Az = atan2(sdlam, (C20 * tphi - S20 * cdlam));
+ Av = Azab;
+ xy.y = rhoc;
+ } else {
+ z = S45 * (sphi + cphi * cdlam);
+ if (fabs(z) > 1.) {
+ if (fabs(z) > ONEEPS) F_ERROR
+ else z = z < 0. ? -1. : 1.;
+ } else
+ z = acos(z);
+ Av = Azba;
+ xy.y = -rhoc;
+ }
+ if (z < 0.) F_ERROR;
+ r = F * (t = pow(tan(.5 * z), n));
+ if ((al = .5 * (R104 - z)) < 0.) F_ERROR;
+ al = (t + pow(al, n)) / T;
+ if (fabs(al) > 1.) {
+ if (fabs(al) > ONEEPS) F_ERROR
+ else al = al < 0. ? -1. : 1.;
+ } else
+ al = acos(al);
+ if (fabs(t = n * (Av - Az)) < al)
+ r /= cos(al + (tag ? t : -t));
+ xy.x = r * sin(t);
+ xy.y += (tag ? -r : r) * cos(t);
+ if (Q->noskew) {
+ t = xy.x;
+ xy.x = -xy.x * cAzc - xy.y * sAzc;
+ xy.y = -xy.y * cAzc + t * sAzc;
+ }
+ return (xy);
}
-INVERSE(s_inverse); /* spheroid */
- double t, r, rp, rl, al, z, fAz, Az, s, c, Av;
- int neg, i;
-
- if (P->noskew) {
- t = xy.x;
- xy.x = -xy.x * cAzc + xy.y * sAzc;
- xy.y = -xy.y * cAzc - t * sAzc;
- }
- if( (neg = (xy.x < 0.)) ) {
- xy.y = rhoc - xy.y;
- s = S20;
- c = C20;
- Av = Azab;
- } else {
- xy.y += rhoc;
- s = S45;
- c = C45;
- Av = Azba;
- }
- rl = rp = r = hypot(xy.x, xy.y);
- fAz = fabs(Az = atan2(xy.x, xy.y));
- for (i = NITER; i ; --i) {
- z = 2. * atan(pow(r / F,1 / n));
- al = acos((pow(tan(.5 * z), n) +
- pow(tan(.5 * (R104 - z)), n)) / T);
- if (fAz < al)
- r = rp * cos(al + (neg ? Az : -Az));
- if (fabs(rl - r) < EPS)
- break;
- rl = r;
- }
- if (! i) I_ERROR;
- Az = Av - Az / n;
- lp.phi = asin(s * cos(z) + c * sin(z) * cos(Az));
- lp.lam = atan2(sin(Az), c / tan(z) - s * cos(Az));
- if (neg)
- lp.lam -= R110;
- else
- lp.lam = lamB - lp.lam;
- return (lp);
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double t, r, rp, rl, al, z, fAz, Az, s, c, Av;
+ int neg, i;
+
+ if (Q->noskew) {
+ t = xy.x;
+ xy.x = -xy.x * cAzc + xy.y * sAzc;
+ xy.y = -xy.y * cAzc - t * sAzc;
+ }
+ if( (neg = (xy.x < 0.)) ) {
+ xy.y = rhoc - xy.y;
+ s = S20;
+ c = C20;
+ Av = Azab;
+ } else {
+ xy.y += rhoc;
+ s = S45;
+ c = C45;
+ Av = Azba;
+ }
+ rl = rp = r = hypot(xy.x, xy.y);
+ fAz = fabs(Az = atan2(xy.x, xy.y));
+ for (i = NITER; i ; --i) {
+ z = 2. * atan(pow(r / F,1 / n));
+ al = acos((pow(tan(.5 * z), n) +
+ pow(tan(.5 * (R104 - z)), n)) / T);
+ if (fAz < al)
+ r = rp * cos(al + (neg ? Az : -Az));
+ if (fabs(rl - r) < EPS)
+ break;
+ rl = r;
+ }
+ if (! i) I_ERROR;
+ Az = Av - Az / n;
+ lp.phi = asin(s * cos(z) + c * sin(z) * cos(Az));
+ lp.lam = atan2(sin(Az), c / tan(z) - s * cos(Az));
+ if (neg)
+ lp.lam -= R110;
+ else
+ lp.lam = lamB - lp.lam;
+ return (lp);
+}
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+ pj_dealloc (P->opaque);
+ return pj_dealloc(P);
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(bipc)
- P->noskew = pj_param(P->ctx, P->params, "bns").i;
- P->inv = s_inverse;
- P->fwd = s_forward;
- P->es = 0.;
-ENDENTRY(P)
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(bipc) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->noskew = pj_param(P->ctx, P->params, "bns").i;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+ P->es = 0.;
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_bipc_selftest (void) {return 0;}
+#else
+
+int pj_bipc_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=bipc +ellps=GRS80 +lat_1=0.5 +lat_2=2"};
+ char s_args[] = {"+proj=bipc +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ {2452160.2177257561, -14548450.759654747},
+ {2447915.213725341, -14763427.21279873},
+ {2021695.5229349085, -14540413.695283702},
+ {2018090.5030046992, -14755620.651414108},
+ };
+
+ XY s_fwd_expect[] = {
+ {2460565.7409749646, -14598319.9893308},
+ {2456306.1859352002, -14814033.339502094},
+ {2028625.4978190989, -14590255.375482792},
+ {2025008.1205891429, -14806200.018759441},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ {-73.038700284978702, 17.248118466239116},
+ {-73.03730373933017, 17.249414978178777},
+ {-73.03589317304332, 17.245536403008771},
+ {-73.034496627213585, 17.246832895573739},
+ };
+
+ LP s_inv_expect[] = {
+ {-73.038693104942126, 17.248116270440242},
+ {-73.037301330021322, 17.24940835333777},
+ {-73.035895582251086, 17.245543027866539},
+ {-73.034503807150301, 17.246835091521532},
+ };
+
+ 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_boggs.c b/src/PJ_boggs.c
index b22a25ff..68010e6a 100644
--- a/src/PJ_boggs.c
+++ b/src/PJ_boggs.c
@@ -8,7 +8,10 @@ PROJ_HEAD(boggs, "Boggs Eumorphic") "\n\tPCyl., no inv., Sph.";
# define FXC2 1.11072
# define FYC 0.49931
# define FYC2 1.41421356237309504880
-FORWARD(s_forward); /* spheroid */
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
double theta, th1, c;
int i;
(void) P;
@@ -29,5 +32,47 @@ FORWARD(s_forward); /* spheroid */
xy.y = FYC * (lp.phi + FYC2 * sin(theta));
return (xy);
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(boggs) P->es = 0.; P->fwd = s_forward; ENDENTRY(P)
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ return pj_dealloc(P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(boggs) {
+ P->es = 0.;
+ P->fwd = s_forward;
+ return P;
+}
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_boggs_selftest (void) {return 0;}
+#else
+int pj_boggs_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=boggs +a=6400000 +lat_1=0 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 211949.70080818201, 117720.99830541089},
+ { 211949.70080818201, -117720.99830541089},
+ {-211949.70080818201, 117720.99830541089},
+ {-211949.70080818201, -117720.99830541089},
+ };
+
+ return pj_generic_selftest (0, s_args, tolerance_xy, tolerance_lp, 4, 0, fwd_in, 0, s_fwd_expect, 0, 0, 0);
+}
+#endif
diff --git a/src/PJ_bonne.c b/src/PJ_bonne.c
index 4b1e7866..13309f3f 100644
--- a/src/PJ_bonne.c
+++ b/src/PJ_bonne.c
@@ -1,51 +1,70 @@
-#define PROJ_PARMS__ \
- double phi1; \
- double cphi1; \
- double am1; \
- double m1; \
- double *en;
#define PJ_LIB__
#include <projects.h>
+
PROJ_HEAD(bonne, "Bonne (Werner lat_1=90)")
"\n\tConic Sph&Ell\n\tlat_1=";
#define EPS10 1e-10
-FORWARD(e_forward); /* ellipsoid */
+
+struct pj_opaque {
+ double phi1;
+ double cphi1;
+ double am1;
+ double m1;
+ double *en;
+};
+
+
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
double rh, E, c;
- rh = P->am1 + P->m1 - pj_mlfn(lp.phi, E = sin(lp.phi), c = cos(lp.phi), P->en);
+ rh = Q->am1 + Q->m1 - pj_mlfn(lp.phi, E = sin(lp.phi), c = cos(lp.phi), Q->en);
E = c * lp.lam / (rh * sqrt(1. - P->es * E * E));
xy.x = rh * sin(E);
- xy.y = P->am1 - rh * cos(E);
- return (xy);
+ xy.y = Q->am1 - rh * cos(E);
+ return xy;
}
-FORWARD(s_forward); /* spheroid */
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
double E, rh;
- rh = P->cphi1 + P->phi1 - lp.phi;
+ rh = Q->cphi1 + Q->phi1 - lp.phi;
if (fabs(rh) > EPS10) {
xy.x = rh * sin(E = lp.lam * cos(lp.phi) / rh);
- xy.y = P->cphi1 - rh * cos(E);
+ xy.y = Q->cphi1 - rh * cos(E);
} else
xy.x = xy.y = 0.;
- return (xy);
+ return xy;
}
-INVERSE(s_inverse); /* spheroid */
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
double rh;
- rh = hypot(xy.x, xy.y = P->cphi1 - xy.y);
- lp.phi = P->cphi1 + P->phi1 - rh;
+ rh = hypot(xy.x, xy.y = Q->cphi1 - xy.y);
+ lp.phi = Q->cphi1 + Q->phi1 - rh;
if (fabs(lp.phi) > HALFPI) I_ERROR;
if (fabs(fabs(lp.phi) - HALFPI) <= EPS10)
lp.lam = 0.;
else
lp.lam = rh * atan2(xy.x, xy.y) / cos(lp.phi);
- return (lp);
+ return lp;
}
-INVERSE(e_inverse); /* ellipsoid */
+
+
+static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
double s, rh;
- rh = hypot(xy.x, xy.y = P->am1 - xy.y);
- lp.phi = pj_inv_mlfn(P->ctx, P->am1 + P->m1 - rh, P->es, P->en);
+ rh = hypot(xy.x, xy.y = Q->am1 - xy.y);
+ lp.phi = pj_inv_mlfn(P->ctx, Q->am1 + Q->m1 - rh, P->es, Q->en);
if ((s = fabs(lp.phi)) < HALFPI) {
s = sin(lp.phi);
lp.lam = rh * atan2(xy.x, xy.y) *
@@ -53,33 +72,109 @@ INVERSE(e_inverse); /* ellipsoid */
} else if (fabs(s - HALFPI) <= EPS10)
lp.lam = 0.;
else I_ERROR;
- return (lp);
+ return lp;
}
-FREEUP;
- if (P) {
- if (P->en)
- pj_dalloc(P->en);
- pj_dalloc(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->en);
+ pj_dealloc (P->opaque);
+ return pj_dealloc(P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
}
-ENTRY1(bonne, en)
+
+
+PJ *PROJECTION(bonne) {
double c;
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
- P->phi1 = pj_param(P->ctx, P->params, "rlat_1").f;
- if (fabs(P->phi1) < EPS10) E_ERROR(-23);
+ Q->phi1 = pj_param(P->ctx, P->params, "rlat_1").f;
+ if (fabs(Q->phi1) < EPS10) E_ERROR(-23);
if (P->es) {
- P->en = pj_enfn(P->es);
- P->m1 = pj_mlfn(P->phi1, P->am1 = sin(P->phi1),
- c = cos(P->phi1), P->en);
- P->am1 = c / (sqrt(1. - P->es * P->am1 * P->am1) * P->am1);
+ Q->en = pj_enfn(P->es);
+ Q->m1 = pj_mlfn(Q->phi1, Q->am1 = sin(Q->phi1),
+ c = cos(Q->phi1), Q->en);
+ Q->am1 = c / (sqrt(1. - P->es * Q->am1 * Q->am1) * Q->am1);
P->inv = e_inverse;
P->fwd = e_forward;
} else {
- if (fabs(P->phi1) + EPS10 >= HALFPI)
- P->cphi1 = 0.;
+ if (fabs(Q->phi1) + EPS10 >= HALFPI)
+ Q->cphi1 = 0.;
else
- P->cphi1 = 1. / tan(P->phi1);
+ Q->cphi1 = 1. / tan(Q->phi1);
P->inv = s_inverse;
P->fwd = s_forward;
}
-ENDENTRY(P)
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_bonne_selftest (void) {return 0;}
+#else
+int pj_bonne_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=bonne +ellps=GRS80 +lat_1=0.5 +lat_2=2"};
+ char s_args[] = {"+proj=bonne +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ { 222605.29609715697, 55321.139565494814},
+ { 222605.29609923941, -165827.64779905154},
+ {-222605.29609715697, 55321.139565494814},
+ {-222605.29609923941, -165827.64779905154},
+ };
+
+ XY s_fwd_expect[] = {
+ { 223368.11557252839, 55884.555246393575},
+ { 223368.11557463196, -167517.59936969393},
+ {-223368.11557252839, 55884.555246393575},
+ {-223368.11557463196, -167517.59936969393},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ { 0.0017966987691132891, 0.50090436853737497},
+ { 0.0017966982774478867, 0.4990956309655612},
+ {-0.0017966987691132891, 0.50090436853737497},
+ {-0.0017966982774478867, 0.4990956309655612},
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0017905615332457991, 0.50089524631087834},
+ { 0.0017905610449335603, 0.49910475320072978},
+ {-0.0017905615332457991, 0.50089524631087834},
+ {-0.0017905610449335603, 0.49910475320072978},
+ };
+
+ 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_calcofi.c b/src/PJ_calcofi.c
index 2d142938..661893f6 100644
--- a/src/PJ_calcofi.c
+++ b/src/PJ_calcofi.c
@@ -1,25 +1,27 @@
#define PJ_LIB__
#include <projects.h>
+
+PROJ_HEAD(calcofi,
+ "Cal Coop Ocean Fish Invest Lines/Stations") "\n\tCyl, Sph&Ell";
+
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <proj_api.h>
#include <errno.h>
-/* Conversions for the California Cooperative Oceanic Fisheries Investigations
+/* Conversions for the California Cooperative Oceanic Fisheries Investigations
Line/Station coordinate system following the algorithm of:
-Eber, L.E., and R.P. Hewitt. 1979. Conversion algorithms for the CALCOFI
-station grid. California Cooperative Oceanic Fisheries Investigations Reports
-20:135-137. (corrected for typographical errors).
+Eber, L.E., and R.P. Hewitt. 1979. Conversion algorithms for the CALCOFI
+station grid. California Cooperative Oceanic Fisheries Investigations Reports
+20:135-137. (corrected for typographical errors).
http://www.calcofi.org/publications/calcofireports/v20/Vol_20_Eber___Hewitt.pdf
-They assume 1 unit of CalCOFI Line == 1/5 degree in longitude or
-meridional units at reference point O, and similarly 1 unit of CalCOFI
-Station == 1/15 of a degree at O.
-By convention, CalCOFI Line/Station conversions use Clarke 1866 but we use
+They assume 1 unit of CalCOFI Line == 1/5 degree in longitude or
+meridional units at reference point O, and similarly 1 unit of CalCOFI
+Station == 1/15 of a degree at O.
+By convention, CalCOFI Line/Station conversions use Clarke 1866 but we use
whatever ellipsoid is provided. */
-PROJ_HEAD(calcofi,
- "Cal Coop Ocean Fish Invest Lines/Stations") "\n\tCyl, Sph&Ell";
#define EPS10 1.e-10
#define DEG_TO_LINE 5
@@ -31,14 +33,17 @@ PROJ_HEAD(calcofi,
#define PT_O_LAMBDA -2.1144663887911301 /* lon -121.15 and */
#define PT_O_PHI 0.59602993955606354 /* lat 34.15 */
#define ROTATION_ANGLE 0.52359877559829882 /*CalCOFI angle of 30 deg in rad */
-FORWARD(e_forward); /* ellipsoid */
+
+
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
+ XY xy = {0.0,0.0};
double oy; /* pt O y value in Mercator */
double l1; /* l1 and l2 are distances calculated using trig that sum
to the east/west distance between point O and point xy */
double l2;
- double ry; /* r is the point on the same station as o (60) and the same
+ double ry; /* r is the point on the same station as o (60) and the same
line as xy xy, r, o form a right triangle */
- /* if the user has specified +lon_0 or +k0 for some reason,
+ /* if the user has specified +lon_0 or +k0 for some reason,
we're going to ignore it so that xy is consistent with point O */
lp.lam = lp.lam + P->lam0;
if (fabs(fabs(lp.phi) - HALFPI) <= EPS10) F_ERROR;
@@ -49,18 +54,21 @@ FORWARD(e_forward); /* ellipsoid */
l2 = -xy.x - l1 + PT_O_LAMBDA;
ry = l2 * cos(ROTATION_ANGLE) * sin(ROTATION_ANGLE) + xy.y;
ry = pj_phi2(P->ctx, exp(-ry), P->e); /*inverse Mercator*/
- xy.x = PT_O_LINE - RAD_TO_DEG *
- (ry - PT_O_PHI) * DEG_TO_LINE / cos(ROTATION_ANGLE);
- xy.y = PT_O_STATION + RAD_TO_DEG *
+ xy.x = PT_O_LINE - RAD_TO_DEG *
+ (ry - PT_O_PHI) * DEG_TO_LINE / cos(ROTATION_ANGLE);
+ xy.y = PT_O_STATION + RAD_TO_DEG *
(ry - lp.phi) * DEG_TO_STATION / sin(ROTATION_ANGLE);
/* set a = 1, x0 = 0, and y0 = 0 so that no further unit adjustments
are done */
P->a = 1;
P->x0 = 0;
P->y0 = 0;
- return (xy);
+ return xy;
}
-FORWARD(s_forward); /* spheroid */
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
double oy;
double l1;
double l2;
@@ -73,17 +81,20 @@ FORWARD(s_forward); /* spheroid */
l1 = (xy.y - oy) * tan(ROTATION_ANGLE);
l2 = -xy.x - l1 + PT_O_LAMBDA;
ry = l2 * cos(ROTATION_ANGLE) * sin(ROTATION_ANGLE) + xy.y;
- ry = HALFPI - 2. * atan(exp(-ry));
- xy.x = PT_O_LINE - RAD_TO_DEG *
- (ry - PT_O_PHI) * DEG_TO_LINE / cos(ROTATION_ANGLE);
- xy.y = PT_O_STATION + RAD_TO_DEG *
+ ry = HALFPI - 2. * atan(exp(-ry));
+ xy.x = PT_O_LINE - RAD_TO_DEG *
+ (ry - PT_O_PHI) * DEG_TO_LINE / cos(ROTATION_ANGLE);
+ xy.y = PT_O_STATION + RAD_TO_DEG *
(ry - lp.phi) * DEG_TO_STATION / sin(ROTATION_ANGLE);
P->a = 1;
P->x0 = 0;
P->y0 = 0;
- return (xy);
+ return xy;
}
-INVERSE(e_inverse); /* ellipsoid */
+
+
+static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */
+ LP lp = {0.0,0.0};
double ry; /* y value of point r */
double oymctr; /* Mercator-transformed y value of point O */
double rymctr; /* Mercator-transformed ry */
@@ -93,7 +104,7 @@ INVERSE(e_inverse); /* ellipsoid */
/* turn x and y back into Line/Station */
xy.x /= P->ra;
xy.y /= P->ra;
- ry = PT_O_PHI - LINE_TO_RAD * (xy.x - PT_O_LINE) *
+ ry = PT_O_PHI - LINE_TO_RAD * (xy.x - PT_O_LINE) *
cos(ROTATION_ANGLE);
lp.phi = ry - STATION_TO_RAD * (xy.y - PT_O_STATION) * sin(ROTATION_ANGLE);
oymctr = -log(pj_tsfn(PT_O_PHI, sin(PT_O_PHI), P->e));
@@ -103,9 +114,12 @@ INVERSE(e_inverse); /* ellipsoid */
l2 = (rymctr - xymctr) / (cos(ROTATION_ANGLE) * sin(ROTATION_ANGLE));
lp.lam = PT_O_LAMBDA - (l1 + l2);
P->over = 1;
- return (lp);
+ return lp;
}
-INVERSE(s_inverse); /* spheroid */
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
double ry;
double oymctr;
double rymctr;
@@ -114,7 +128,7 @@ INVERSE(s_inverse); /* spheroid */
double l2;
xy.x /= P->ra;
xy.y /= P->ra;
- ry = PT_O_PHI - LINE_TO_RAD * (xy.x - PT_O_LINE) *
+ ry = PT_O_PHI - LINE_TO_RAD * (xy.x - PT_O_LINE) *
cos(ROTATION_ANGLE);
lp.phi = ry - STATION_TO_RAD * (xy.y - PT_O_STATION) * sin(ROTATION_ANGLE);
oymctr = log(tan(FORTPI + .5 * PT_O_PHI));
@@ -124,10 +138,23 @@ INVERSE(s_inverse); /* spheroid */
l2 = (rymctr - xymctr) / (cos(ROTATION_ANGLE) * sin(ROTATION_ANGLE));
lp.lam = PT_O_LAMBDA - (l1 + l2);
P->over = 1;
- return (lp);
+ return lp;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(calcofi)
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ return pj_dealloc (P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(calcofi) {
+ P->opaque = 0;
+
if (P->es) { /* ellipsoid */
P->inv = e_inverse;
P->fwd = e_forward;
@@ -135,4 +162,65 @@ ENTRY0(calcofi)
P->inv = s_inverse;
P->fwd = s_forward;
}
-ENDENTRY(P)
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_calcofi_selftest (void) {return 0;}
+#else
+
+int pj_calcofi_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=calcofi +ellps=GRS80 +lat_1=0.5 +lat_2=2"};
+ char s_args[] = {"+proj=calcofi +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ {508.44487214981905, -1171.7648604175156},
+ {514.99916815188112, -1145.8219814677668},
+ {500.68538412539851, -1131.4453779204598},
+ {507.36971913666355, -1106.1782014834275},
+ };
+
+ XY s_fwd_expect[] = {
+ {507.09050748781806, -1164.7273751978314},
+ {513.68613637462886, -1138.9992682173072},
+ {499.33626147591531, -1124.4351309968195},
+ {506.0605703929898, -1099.3756650673038},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ {-110.36330792469906, 12.032056975840137},
+ {-98.455008863288782, 18.698723642506803},
+ {-207.4470245036909, 81.314089278595247},
+ {-62.486322854481287, 87.980755945261919},
+ };
+
+ LP s_inv_expect[] = {
+ {-110.30519040955151, 12.032056975840137},
+ {-98.322360950234085, 18.698723642506803},
+ {-207.54490681381429, 81.314089278595247},
+ {-62.576950371885275, 87.980755945261919},
+ };
+
+ 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_cass.c b/src/PJ_cass.c
index 38fa9db5..28d35b91 100644
--- a/src/PJ_cass.c
+++ b/src/PJ_cass.c
@@ -1,79 +1,178 @@
-#define PROJ_PARMS__ \
- double m0; \
- double n; \
- double t; \
- double a1; \
- double c; \
- double r; \
- double dd; \
- double d2; \
- double a2; \
- double tn; \
- double *en;
#define PJ_LIB__
-# include <projects.h>
+# include <projects.h>
PROJ_HEAD(cass, "Cassini") "\n\tCyl, Sph&Ell";
-# define EPS10 1e-10
-# define C1 .16666666666666666666
-# define C2 .00833333333333333333
-# define C3 .04166666666666666666
-# define C4 .33333333333333333333
-# define C5 .06666666666666666666
-FORWARD(e_forward); /* ellipsoid */
- xy.y = pj_mlfn(lp.phi, P->n = sin(lp.phi), P->c = cos(lp.phi), P->en);
- P->n = 1./sqrt(1. - P->es * P->n * P->n);
- P->tn = tan(lp.phi); P->t = P->tn * P->tn;
- P->a1 = lp.lam * P->c;
- P->c *= P->es * P->c / (1 - P->es);
- P->a2 = P->a1 * P->a1;
- xy.x = P->n * P->a1 * (1. - P->a2 * P->t *
- (C1 - (8. - P->t + 8. * P->c) * P->a2 * C2));
- xy.y -= P->m0 - P->n * P->tn * P->a2 *
- (.5 + (5. - P->t + 6. * P->c) * P->a2 * C3);
- return (xy);
+
+
+# define EPS10 1e-10
+# define C1 .16666666666666666666
+# define C2 .00833333333333333333
+# define C3 .04166666666666666666
+# define C4 .33333333333333333333
+# define C5 .06666666666666666666
+
+
+struct pj_opaque {
+ double *en;
+ double m0;
+};
+
+
+
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
+ double n, t, a1, c, a2, tn;
+ XY xy = {0.0, 0.0};
+ struct pj_opaque *Q = P->opaque;
+
+ xy.y = pj_mlfn (lp.phi, n = sin (lp.phi), c = cos (lp.phi), Q->en);
+
+ n = 1./sqrt(1. - P->es * n*n);
+ tn = tan(lp.phi); t = tn * tn;
+ a1 = lp.lam * c;
+ c *= P->es * c / (1 - P->es);
+ a2 = a1 * a1;
+
+ xy.x = n * a1 * (1. - a2 * t *
+ (C1 - (8. - t + 8. * c) * a2 * C2));
+ xy.y -= Q->m0 - n * tn * a2 *
+ (.5 + (5. - t + 6. * c) * a2 * C3);
+
+ return xy;
+}
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0, 0.0};
+ xy.x = asin (cos (lp.phi) * sin (lp.lam));
+ xy.y = atan2 (tan (lp.phi), cos (lp.lam)) - P->phi0;
+ return xy;
+}
+
+
+static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */
+ double n, t, r, dd, d2, tn, ph1;
+ LP lp = {0.0, 0.0};
+ struct pj_opaque *Q = P->opaque;
+
+ ph1 = pj_inv_mlfn (P->ctx, Q->m0 + xy.y, P->es, Q->en);
+ tn = tan (ph1); t = tn*tn;
+ n = sin (ph1);
+ r = 1. / (1. - P->es * n * n);
+ n = sqrt (r);
+ r *= (1. - P->es) * n;
+ dd = xy.x / n;
+ d2 = dd * dd;
+ lp.phi = ph1 - (n * tn / r) * d2 *
+ (.5 - (1. + 3. * t) * d2 * C3);
+ lp.lam = dd * (1. + t * d2 *
+ (-C4 + (1. + 3. * t) * d2 * C5)) / cos (ph1);
+ return lp;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ double dd;
+ lp.phi = asin(sin(dd = xy.y + P->phi0) * cos(xy.x));
+ lp.lam = atan2(tan(xy.x), cos(dd));
+ return lp;
}
-FORWARD(s_forward); /* spheroid */
- xy.x = asin(cos(lp.phi) * sin(lp.lam));
- xy.y = atan2(tan(lp.phi) , cos(lp.lam)) - P->phi0;
- return (xy);
+
+
+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 ph1;
-
- ph1 = pj_inv_mlfn(P->ctx, P->m0 + xy.y, P->es, P->en);
- P->tn = tan(ph1); P->t = P->tn * P->tn;
- P->n = sin(ph1);
- P->r = 1. / (1. - P->es * P->n * P->n);
- P->n = sqrt(P->r);
- P->r *= (1. - P->es) * P->n;
- P->dd = xy.x / P->n;
- P->d2 = P->dd * P->dd;
- lp.phi = ph1 - (P->n * P->tn / P->r) * P->d2 *
- (.5 - (1. + 3. * P->t) * P->d2 * C3);
- lp.lam = P->dd * (1. + P->t * P->d2 *
- (-C4 + (1. + 3. * P->t) * P->d2 * C5)) / cos(ph1);
- return (lp);
+
+static void freeup(PJ *P) { /* Destructor */
+ freeup_new (P);
+ return;
}
-INVERSE(s_inverse); /* spheroid */
- lp.phi = asin(sin(P->dd = xy.y + P->phi0) * cos(xy.x));
- lp.lam = atan2(tan(xy.x), cos(P->dd));
- return (lp);
+
+PJ *PROJECTION(cass) {
+
+ /* Spheroidal? */
+ if (0==P->es) {
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+ return P;
+ }
+
+ /* otherwise it's ellipsoidal */
+ P->opaque = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==P->opaque)
+ return freeup_new (P);
+
+ P->opaque->en = pj_enfn (P->es);
+ if (0==P->opaque->en)
+ return freeup_new (P);
+
+ P->opaque->m0 = pj_mlfn (P->phi0, sin (P->phi0), cos (P->phi0), P->opaque->en);
+ P->inv = e_inverse;
+ P->fwd = e_forward;
+
+ return P;
}
-FREEUP;
- if (P) {
- if (P->en)
- pj_dalloc(P->en);
- pj_dalloc(P);
- }
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_cass_selftest (void) {return 0;}
+#else
+
+int pj_cass_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=cass +ellps=GRS80 +lat_1=0.5 +lat_2=2"};
+ char s_args[] = {"+proj=cass +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ { 222605.28577699114, 110642.22925399939},
+ { 222605.28577699114, -110642.22925399939},
+ {-222605.28577699114, 110642.22925399939},
+ {-222605.28577699114, -110642.22925399939},
+ };
+
+ XY s_fwd_expect[] = {
+ { 223368.10520348375, 111769.14504058579},
+ { 223368.10520348375, -111769.14504058579},
+ {-223368.10520348375, 111769.14504058579},
+ {-223368.10520348375, -111769.14504058579},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ { 0.0017966305684613522, 0.00090436947663183841},
+ { 0.0017966305684613522, -0.00090436947663183841},
+ {-0.0017966305684613522, 0.00090436947663183841},
+ {-0.0017966305684613522, -0.00090436947663183841},
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0017904931100023887, 0.00089524655445477922},
+ { 0.0017904931100023887, -0.00089524655445477922},
+ {-0.0017904931100023887, 0.00089524655445477922},
+ {-0.0017904931100023887, -0.00089524655445477922},
+ };
+
+ 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(cass, en)
- if (P->es) {
- if (!(P->en = pj_enfn(P->es))) E_ERROR_0;
- P->m0 = pj_mlfn(P->phi0, sin(P->phi0), cos(P->phi0), P->en);
- P->inv = e_inverse;
- P->fwd = e_forward;
- } else {
- P->inv = s_inverse;
- P->fwd = s_forward;
- }
-ENDENTRY(P)
+#endif
diff --git a/src/PJ_cc.c b/src/PJ_cc.c
index 0f573929..475fbae4 100644
--- a/src/PJ_cc.c
+++ b/src/PJ_cc.c
@@ -1,20 +1,89 @@
-#define PROJ_PARMS__ \
- double ap;
#define PJ_LIB__
#include <projects.h>
+
PROJ_HEAD(cc, "Central Cylindrical") "\n\tCyl, Sph";
#define EPS10 1.e-10
-FORWARD(s_forward); /* spheroid */
- if (fabs(fabs(lp.phi) - HALFPI) <= EPS10) F_ERROR;
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ if (fabs (fabs(lp.phi) - HALFPI) <= EPS10) F_ERROR;
xy.x = lp.lam;
xy.y = tan(lp.phi);
- return (xy);
+ return xy;
}
-INVERSE(s_inverse); /* spheroid */
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
(void) P;
lp.phi = atan(xy.y);
lp.lam = xy.x;
- return (lp);
+ return lp;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(cc) P->es = 0.; P->inv = s_inverse; P->fwd = s_forward; ENDENTRY(P)
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ return pj_dealloc(P);
+}
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(cc) {
+ P->es = 0.;
+
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_cc_selftest (void) {return 0;}
+#else
+
+int pj_cc_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=cc +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ {223402.14425527418, 111712.41554059254},
+ {223402.14425527418, -111712.41554059254},
+ {-223402.14425527418, 111712.41554059254},
+ {-223402.14425527418, -111712.41554059254},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ {0.0017904931097838226, 0.00089524655481905597},
+ {0.0017904931097838226, -0.00089524655481905597},
+ {-0.0017904931097838226, 0.00089524655481905597},
+ {-0.0017904931097838226, -0.00089524655481905597},
+ };
+
+ 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_cea.c b/src/PJ_cea.c
index 44c0a887..e1bcb0af 100644
--- a/src/PJ_cea.c
+++ b/src/PJ_cea.c
@@ -1,63 +1,155 @@
-#define PROJ_PARMS__ \
- double qp; \
- double *apa;
#define PJ_LIB__
-# include <projects.h>
+#include <projects.h>
+
+struct pj_opaque {
+ double qp;
+ double *apa;
+};
+
PROJ_HEAD(cea, "Equal Area Cylindrical") "\n\tCyl, Sph&Ell\n\tlat_ts=";
-# define EPS 1e-10
-FORWARD(e_forward); /* spheroid */
- xy.x = P->k0 * lp.lam;
- xy.y = .5 * pj_qsfn(sin(lp.phi), P->e, P->one_es) / P->k0;
- return (xy);
-}
-FORWARD(s_forward); /* spheroid */
- xy.x = P->k0 * lp.lam;
- xy.y = sin(lp.phi) / P->k0;
- return (xy);
-}
-INVERSE(e_inverse); /* spheroid */
- lp.phi = pj_authlat(asin( 2. * xy.y * P->k0 / P->qp), P->apa);
- lp.lam = xy.x / P->k0;
- return (lp);
-}
-INVERSE(s_inverse); /* spheroid */
- double t;
-
- if ((t = fabs(xy.y *= P->k0)) - EPS <= 1.) {
- if (t >= 1.)
- lp.phi = xy.y < 0. ? -HALFPI : HALFPI;
- else
- lp.phi = asin(xy.y);
- lp.lam = xy.x / P->k0;
- } else I_ERROR;
- return (lp);
-}
-FREEUP;
- if (P) {
- if (P->apa)
- pj_dalloc(P->apa);
- pj_dalloc(P);
- }
-}
-ENTRY1(cea, apa)
- double t = 0.0;
-
- if (pj_param(P->ctx, P->params, "tlat_ts").i) {
- P->k0 = cos(t = pj_param(P->ctx, P->params, "rlat_ts").f);
- if (P->k0 < 0.) {
- E_ERROR(-24);
- }
- }
- if (P->es) {
- t = sin(t);
- P->k0 /= sqrt(1. - P->es * t * t);
- P->e = sqrt(P->es);
- if (!(P->apa = pj_authset(P->es))) E_ERROR_0;
- P->qp = pj_qsfn(1., P->e, P->one_es);
- P->inv = e_inverse;
- P->fwd = e_forward;
- } else {
- P->inv = s_inverse;
- P->fwd = s_forward;
- }
-ENDENTRY(P)
+# define EPS 1e-10
+
+
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
+ XY xy = {0.0,0.0};
+ xy.x = P->k0 * lp.lam;
+ xy.y = 0.5 * pj_qsfn (sin (lp.phi), P->e, P->one_es) / P->k0;
+ return xy;
+}
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ xy.x = P->k0 * lp.lam;
+ xy.y = sin(lp.phi) / P->k0;
+ return xy;
+}
+
+
+static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */
+ LP lp = {0.0,0.0};
+ lp.phi = pj_authlat(asin( 2. * xy.y * P->k0 / P->opaque->qp), P->opaque->apa);
+ lp.lam = xy.x / P->k0;
+ return lp;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ double t;
+
+ if ((t = fabs(xy.y *= P->k0)) - EPS <= 1.) {
+ if (t >= 1.)
+ lp.phi = xy.y < 0. ? -HALFPI : HALFPI;
+ else
+ lp.phi = asin(xy.y);
+ lp.lam = xy.x / P->k0;
+ } else I_ERROR;
+ 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->apa);
+ pj_dealloc (P->opaque);
+ return pj_dealloc (P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+PJ *PROJECTION(cea) {
+ double t = 0.0;
+ 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, "tlat_ts").i) {
+ P->k0 = cos(t = pj_param(P->ctx, P->params, "rlat_ts").f);
+ if (P->k0 < 0.) {
+ E_ERROR(-24);
+ }
+ }
+ if (P->es) {
+ t = sin(t);
+ P->k0 /= sqrt(1. - P->es * t * t);
+ P->e = sqrt(P->es);
+ if (!(Q->apa = pj_authset(P->es))) E_ERROR_0;
+ Q->qp = pj_qsfn(1., P->e, P->one_es);
+ P->inv = e_inverse;
+ P->fwd = e_forward;
+ } else {
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+ }
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_cea_selftest (void) {return 0;}
+#else
+
+int pj_cea_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=cea +ellps=GRS80 +lat_1=0.5 +lat_2=2"};
+ char s_args[] = {"+proj=cea +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ { 222638.981586547132, 110568.812396267356},
+ { 222638.981586547132, -110568.812396265886},
+ {-222638.981586547132, 110568.812396267356},
+ {-222638.981586547132, -110568.812396265886},
+ };
+
+ XY s_fwd_expect[] = {
+ { 223402.144255274179, 111695.401198614476},
+ { 223402.144255274179, -111695.401198614476},
+ {-223402.144255274179, 111695.401198614476},
+ {-223402.144255274179, -111695.401198614476},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ { 0.00179663056823904264, 0.000904369476105564289},
+ { 0.00179663056823904264, -0.000904369476105564289},
+ {-0.00179663056823904264, 0.000904369476105564289},
+ {-0.00179663056823904264, -0.000904369476105564289},
+ };
+
+ LP s_inv_expect[] = {
+ { 0.00179049310978382265, 0.000895246554928338998},
+ { 0.00179049310978382265, -0.000895246554928338998},
+ {-0.00179049310978382265, 0.000895246554928338998},
+ {-0.00179049310978382265, -0.000895246554928338998},
+ };
+
+ 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_chamb.c b/src/PJ_chamb.c
index 65f21129..68d99f26 100644
--- a/src/PJ_chamb.c
+++ b/src/PJ_chamb.c
@@ -1,112 +1,179 @@
-typedef struct { double r, Az; } VECT;
-#define PROJ_PARMS__ \
- struct { /* control point data */ \
- double phi, lam; \
- double cosphi, sinphi; \
- VECT v; \
- XY p; \
- double Az; \
- } c[3]; \
- XY p; \
- double beta_0, beta_1, beta_2;
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
+typedef struct { double r, Az; } VECT;
+struct pj_opaque {
+ struct { /* control point data */
+ double phi, lam;
+ double cosphi, sinphi;
+ VECT v;
+ XY p;
+ double Az;
+ } c[3];
+ XY p;
+ double beta_0, beta_1, beta_2;
+};
+
PROJ_HEAD(chamb, "Chamberlin Trimetric") "\n\tMisc Sph, no inv."
"\n\tlat_1= lon_1= lat_2= lon_2= lat_3= lon_3=";
-#include <stdio.h>
+
+#include <stdio.h>
#define THIRD 0.333333333333333333
#define TOL 1e-9
- static VECT /* distance and azimuth from point 1 to point 2 */
-vect(projCtx ctx, double dphi, double c1, double s1, double c2, double s2, double dlam) {
- VECT v;
- double cdl, dp, dl;
-
- cdl = cos(dlam);
- if (fabs(dphi) > 1. || fabs(dlam) > 1.)
- v.r = aacos(ctx, s1 * s2 + c1 * c2 * cdl);
- else { /* more accurate for smaller distances */
- dp = sin(.5 * dphi);
- dl = sin(.5 * dlam);
- v.r = 2. * aasin(ctx,sqrt(dp * dp + c1 * c2 * dl * dl));
- }
- if (fabs(v.r) > TOL)
- v.Az = atan2(c2 * sin(dlam), c1 * s2 - s1 * c2 * cdl);
- else
- v.r = v.Az = 0.;
- return v;
+
+/* distance and azimuth from point 1 to point 2 */
+static VECT vect(projCtx ctx, double dphi, double c1, double s1, double c2, double s2, double dlam) {
+ VECT v;
+ double cdl, dp, dl;
+
+ cdl = cos(dlam);
+ if (fabs(dphi) > 1. || fabs(dlam) > 1.)
+ v.r = aacos(ctx, s1 * s2 + c1 * c2 * cdl);
+ else { /* more accurate for smaller distances */
+ dp = sin(.5 * dphi);
+ dl = sin(.5 * dlam);
+ v.r = 2. * aasin(ctx,sqrt(dp * dp + c1 * c2 * dl * dl));
+ }
+ if (fabs(v.r) > TOL)
+ v.Az = atan2(c2 * sin(dlam), c1 * s2 - s1 * c2 * cdl);
+ else
+ v.r = v.Az = 0.;
+ return v;
+}
+
+/* law of cosines */
+static double lc(projCtx ctx, double b,double c,double a) {
+ return aacos(ctx, .5 * (b * b + c * c - a * a) / (b * c));
+}
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double sinphi, cosphi, a;
+ VECT v[3];
+ int i, j;
+
+ sinphi = sin(lp.phi);
+ cosphi = cos(lp.phi);
+ for (i = 0; i < 3; ++i) { /* dist/azimiths from control */
+ v[i] = vect(P->ctx, lp.phi - Q->c[i].phi, Q->c[i].cosphi, Q->c[i].sinphi,
+ cosphi, sinphi, lp.lam - Q->c[i].lam);
+ if ( ! v[i].r)
+ break;
+ v[i].Az = adjlon(v[i].Az - Q->c[i].v.Az);
+ }
+ if (i < 3) /* current point at control point */
+ xy = Q->c[i].p;
+ else { /* point mean of intersepts */
+ xy = Q->p;
+ for (i = 0; i < 3; ++i) {
+ j = i == 2 ? 0 : i + 1;
+ a = lc(P->ctx,Q->c[i].v.r, v[i].r, v[j].r);
+ if (v[i].Az < 0.)
+ a = -a;
+ if (! i) { /* coord comp unique to each arc */
+ xy.x += v[i].r * cos(a);
+ xy.y -= v[i].r * sin(a);
+ } else if (i == 1) {
+ a = Q->beta_1 - a;
+ xy.x -= v[i].r * cos(a);
+ xy.y -= v[i].r * sin(a);
+ } else {
+ a = Q->beta_2 - a;
+ xy.x += v[i].r * cos(a);
+ xy.y += v[i].r * sin(a);
+ }
+ }
+ xy.x *= THIRD; /* mean of arc intercepts */
+ xy.y *= THIRD;
+ }
+ return xy;
+}
+
+
+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 double /* law of cosines */
-lc(projCtx ctx, double b,double c,double a) {
- return aacos(ctx, .5 * (b * b + c * c - a * a) / (b * c));
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
}
-FORWARD(s_forward); /* spheroid */
- double sinphi, cosphi, a;
- VECT v[3];
- int i, j;
-
- sinphi = sin(lp.phi);
- cosphi = cos(lp.phi);
- for (i = 0; i < 3; ++i) { /* dist/azimiths from control */
- v[i] = vect(P->ctx, lp.phi - P->c[i].phi, P->c[i].cosphi, P->c[i].sinphi,
- cosphi, sinphi, lp.lam - P->c[i].lam);
- if ( ! v[i].r)
- break;
- v[i].Az = adjlon(v[i].Az - P->c[i].v.Az);
- }
- if (i < 3) /* current point at control point */
- xy = P->c[i].p;
- else { /* point mean of intersepts */
- xy = P->p;
- for (i = 0; i < 3; ++i) {
- j = i == 2 ? 0 : i + 1;
- a = lc(P->ctx,P->c[i].v.r, v[i].r, v[j].r);
- if (v[i].Az < 0.)
- a = -a;
- if (! i) { /* coord comp unique to each arc */
- xy.x += v[i].r * cos(a);
- xy.y -= v[i].r * sin(a);
- } else if (i == 1) {
- a = P->beta_1 - a;
- xy.x -= v[i].r * cos(a);
- xy.y -= v[i].r * sin(a);
- } else {
- a = P->beta_2 - a;
- xy.x += v[i].r * cos(a);
- xy.y += v[i].r * sin(a);
- }
- }
- xy.x *= THIRD; /* mean of arc intercepts */
- xy.y *= THIRD;
- }
- return xy;
+
+
+PJ *PROJECTION(chamb) {
+ int i, j;
+ char line[10];
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+
+ for (i = 0; i < 3; ++i) { /* get control point locations */
+ (void)sprintf(line, "rlat_%d", i+1);
+ Q->c[i].phi = pj_param(P->ctx, P->params, line).f;
+ (void)sprintf(line, "rlon_%d", i+1);
+ Q->c[i].lam = pj_param(P->ctx, P->params, line).f;
+ Q->c[i].lam = adjlon(Q->c[i].lam - P->lam0);
+ Q->c[i].cosphi = cos(Q->c[i].phi);
+ Q->c[i].sinphi = sin(Q->c[i].phi);
+ }
+ for (i = 0; i < 3; ++i) { /* inter ctl pt. distances and azimuths */
+ j = i == 2 ? 0 : i + 1;
+ Q->c[i].v = vect(P->ctx,Q->c[j].phi - Q->c[i].phi, Q->c[i].cosphi, Q->c[i].sinphi,
+ Q->c[j].cosphi, Q->c[j].sinphi, Q->c[j].lam - Q->c[i].lam);
+ if (! Q->c[i].v.r) E_ERROR(-25);
+ /* co-linearity problem ignored for now */
+ }
+ Q->beta_0 = lc(P->ctx,Q->c[0].v.r, Q->c[2].v.r, Q->c[1].v.r);
+ Q->beta_1 = lc(P->ctx,Q->c[0].v.r, Q->c[1].v.r, Q->c[2].v.r);
+ Q->beta_2 = PI - Q->beta_0;
+ Q->p.y = 2. * (Q->c[0].p.y = Q->c[1].p.y = Q->c[2].v.r * sin(Q->beta_0));
+ Q->c[2].p.y = 0.;
+ Q->c[0].p.x = - (Q->c[1].p.x = 0.5 * Q->c[0].v.r);
+ Q->p.x = Q->c[2].p.x = Q->c[0].p.x + Q->c[2].v.r * cos(Q->beta_0);
+
+ P->es = 0.;
+ P->fwd = s_forward;
+
+ return P;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(chamb)
- int i, j;
- char line[10];
-
- for (i = 0; i < 3; ++i) { /* get control point locations */
- (void)sprintf(line, "rlat_%d", i+1);
- P->c[i].phi = pj_param(P->ctx, P->params, line).f;
- (void)sprintf(line, "rlon_%d", i+1);
- P->c[i].lam = pj_param(P->ctx, P->params, line).f;
- P->c[i].lam = adjlon(P->c[i].lam - P->lam0);
- P->c[i].cosphi = cos(P->c[i].phi);
- P->c[i].sinphi = sin(P->c[i].phi);
- }
- for (i = 0; i < 3; ++i) { /* inter ctl pt. distances and azimuths */
- j = i == 2 ? 0 : i + 1;
- P->c[i].v = vect(P->ctx,P->c[j].phi - P->c[i].phi, P->c[i].cosphi, P->c[i].sinphi,
- P->c[j].cosphi, P->c[j].sinphi, P->c[j].lam - P->c[i].lam);
- if (! P->c[i].v.r) E_ERROR(-25);
- /* co-linearity problem ignored for now */
- }
- P->beta_0 = lc(P->ctx,P->c[0].v.r, P->c[2].v.r, P->c[1].v.r);
- P->beta_1 = lc(P->ctx,P->c[0].v.r, P->c[1].v.r, P->c[2].v.r);
- P->beta_2 = PI - P->beta_0;
- P->p.y = 2. * (P->c[0].p.y = P->c[1].p.y = P->c[2].v.r * sin(P->beta_0));
- P->c[2].p.y = 0.;
- P->c[0].p.x = - (P->c[1].p.x = 0.5 * P->c[0].v.r);
- P->p.x = P->c[2].p.x = P->c[0].p.x + P->c[2].v.r * cos(P->beta_0);
- P->es = 0.; P->fwd = s_forward;
-ENDENTRY(P)
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_chamb_selftest (void) {return 0;}
+#else
+
+int pj_chamb_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=chamb +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ {-27864.7795868005815, -223364.324593274243},
+ {-251312.283053493476, -223402.145526208304},
+ {-27864.7856491046077, 223364.327328827145},
+ {-251312.289116443484, 223402.142197287147},
+ };
+
+ return pj_generic_selftest (0, s_args, tolerance_xy, tolerance_lp, 4, 4, fwd_in, 0, s_fwd_expect, 0, 0, 0);
+}
+
+
+#endif
diff --git a/src/PJ_collg.c b/src/PJ_collg.c
index 871dfc97..80029a3a 100644
--- a/src/PJ_collg.c
+++ b/src/PJ_collg.c
@@ -1,10 +1,14 @@
#define PJ_LIB__
# include <projects.h>
+
PROJ_HEAD(collg, "Collignon") "\n\tPCyl, Sph.";
#define FXC 1.12837916709551257390
#define FYC 1.77245385090551602729
#define ONEEPS 1.0000001
-FORWARD(s_forward); /* spheroid */
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
(void) P;
if ((xy.y = 1. - sin(lp.phi)) <= 0.)
xy.y = 0.;
@@ -14,7 +18,10 @@ FORWARD(s_forward); /* spheroid */
xy.y = FYC * (1. - xy.y);
return (xy);
}
-INVERSE(s_inverse); /* spheroid */
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
lp.phi = xy.y / FYC - 1.;
if (fabs(lp.phi = 1. - lp.phi * lp.phi) < 1.)
lp.phi = asin(lp.phi);
@@ -26,5 +33,66 @@ INVERSE(s_inverse); /* spheroid */
lp.lam = xy.x / (FXC * sqrt(lp.lam));
return (lp);
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(collg) P->es = 0.; P->inv = s_inverse; P->fwd = s_forward; ENDENTRY(P)
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ return pj_dealloc(P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(collg) {
+ P->es = 0.0;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_collg_selftest (void) {return 0;}
+#else
+
+int pj_collg_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=collg +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ {249872.921577929839, 99423.1747884602082},
+ {254272.532301245432, -98559.3077607425657},
+ {-249872.921577929839, 99423.1747884602082},
+ {-254272.532301245432, -98559.3077607425657},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ {0.00158679719207879865, 0.00101017310941749921},
+ {0.001586769215623956, -0.00101018201458258111},
+ {-0.00158679719207879865, 0.00101017310941749921},
+ {-0.001586769215623956, -0.00101018201458258111},
+ };
+
+ 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_comill.c b/src/PJ_comill.c
index ad9914d4..6bccb264 100644
--- a/src/PJ_comill.c
+++ b/src/PJ_comill.c
@@ -1,13 +1,14 @@
/*
-The Compact Miller projection was designed by Tom Patterson, US National
-Park Service, in 2014. The polynomial equation was developed by Bojan
-Savric and Bernhard Jenny, College of Earth, Ocean, and Atmospheric
+The Compact Miller projection was designed by Tom Patterson, US National
+Park Service, in 2014. The polynomial equation was developed by Bojan
+Savric and Bernhard Jenny, College of Earth, Ocean, and Atmospheric
Sciences, Oregon State University.
Port to PROJ.4 by Bojan Savric, 4 April 2016
*/
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(comill, "Compact Miller") "\n\tCyl., Sph.";
#define K1 0.9902
@@ -19,41 +20,112 @@ PROJ_HEAD(comill, "Compact Miller") "\n\tCyl., Sph.";
#define EPS 1e-11
#define MAX_Y (0.6000207669862655 * PI)
-FORWARD(s_forward); /* spheroid */
- double lat_sq;
- lat_sq = lp.phi * lp.phi;
- xy.x = lp.lam;
- xy.y = lp.phi * (K1 + lat_sq * (K2 + K3 * lat_sq));
- return (xy);
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ double lat_sq;
+
+ (void) P; /* silence unused parameter warnings */
+
+ lat_sq = lp.phi * lp.phi;
+ xy.x = lp.lam;
+ xy.y = lp.phi * (K1 + lat_sq * (K2 + K3 * lat_sq));
+ return xy;
}
-INVERSE(s_inverse); /* spheroid */
- double yc, tol, y2, y4, f, fder;
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ double yc, tol, y2, f, fder;
+
+ (void) P; /* silence unused parameter warnings */
/* make sure y is inside valid range */
- if (xy.y > MAX_Y) {
- xy.y = MAX_Y;
- } else if (xy.y < -MAX_Y) {
- xy.y = -MAX_Y;
- }
+ if (xy.y > MAX_Y) {
+ xy.y = MAX_Y;
+ } else if (xy.y < -MAX_Y) {
+ xy.y = -MAX_Y;
+ }
/* latitude */
- yc = xy.y;
+ yc = xy.y;
for (;;) { /* Newton-Raphson */
- y2 = yc * yc;
- f = (yc * (K1 + y2 * (K2 + K3 * y2))) - xy.y;
- fder = C1 + y2 * (C2 + C3 * y2);
- yc -= tol = f / fder;
- if (fabs(tol) < EPS) {
- break;
- }
- }
- lp.phi = yc;
+ y2 = yc * yc;
+ f = (yc * (K1 + y2 * (K2 + K3 * y2))) - xy.y;
+ fder = C1 + y2 * (C2 + C3 * y2);
+ yc -= tol = f / fder;
+ if (fabs(tol) < EPS) {
+ break;
+ }
+ }
+ lp.phi = yc;
/* longitude */
- lp.lam = xy.x;
+ lp.lam = xy.x;
+
+ return lp;
+}
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ return pj_dealloc(P);
+}
- return (lp);
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(comill) P->es = 0; P->inv = s_inverse; P->fwd = s_forward; ENDENTRY(P)
+
+
+PJ *PROJECTION(comill) {
+ P->es = 0;
+
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_comill_selftest (void) {return 0;}
+#else
+
+int pj_comill_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=comill +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ {223402.144255274179, 110611.859089458536},
+ {223402.144255274179, -110611.859089458536},
+ {-223402.144255274179, 110611.859089458536},
+ {-223402.144255274179, -110611.859089458536},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ {0.00179049310978382265, 0.000904106801510605831},
+ {0.00179049310978382265, -0.000904106801510605831},
+ {-0.00179049310978382265, 0.000904106801510605831},
+ {-0.00179049310978382265, -0.000904106801510605831},
+ };
+
+ 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_crast.c b/src/PJ_crast.c
index 3f251ac6..4773ee7c 100644
--- a/src/PJ_crast.c
+++ b/src/PJ_crast.c
@@ -1,24 +1,94 @@
#define PJ_LIB__
-# include <projects.h>
-PROJ_HEAD(crast, "Craster Parabolic (Putnins P4)")
-"\n\tPCyl., Sph.";
-#define XM 0.97720502380583984317
-#define RXM 1.02332670794648848847
-#define YM 3.06998012383946546542
-#define RYM 0.32573500793527994772
-#define THIRD 0.333333333333333333
-FORWARD(s_forward); /* spheroid */
- (void) P;
- lp.phi *= THIRD;
- xy.x = XM * lp.lam * (2. * cos(lp.phi + lp.phi) - 1.);
- xy.y = YM * sin(lp.phi);
- return (xy);
+# include <projects.h>
+
+PROJ_HEAD(crast, "Craster Parabolic (Putnins P4)") "\n\tPCyl., Sph.";
+
+#define XM 0.97720502380583984317
+#define RXM 1.02332670794648848847
+#define YM 3.06998012383946546542
+#define RYM 0.32573500793527994772
+#define THIRD 0.333333333333333333
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ (void) P;
+ lp.phi *= THIRD;
+ xy.x = XM * lp.lam * (2. * cos(lp.phi + lp.phi) - 1.);
+ xy.y = YM * sin(lp.phi);
+ return xy;
}
-INVERSE(s_inverse); /* spheroid */
- (void) P;
- lp.phi = 3. * asin(xy.y * RYM);
- lp.lam = xy.x * RXM / (2. * cos((lp.phi + lp.phi) * THIRD) - 1);
- return (lp);
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ (void) P;
+ lp.phi = 3. * asin(xy.y * RYM);
+ lp.lam = xy.x * RXM / (2. * cos((lp.phi + lp.phi) * THIRD) - 1);
+ return lp;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(crast) P->es = 0.; P->inv = s_inverse; P->fwd = s_forward; ENDENTRY(P)
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ return pj_dealloc(P);
+}
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(crast) {
+ P->es = 0.0;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_crast_selftest (void) {return 0;}
+#else
+
+int pj_crast_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=crast +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+
+ XY s_fwd_expect[] = {
+ {218280.142056780722, 114306.045604279774},
+ {218280.142056780722, -114306.045604279774},
+ {-218280.142056780722, 114306.045604279774},
+ {-218280.142056780722, -114306.045604279774},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ {0.00183225941982580187, 0.00087483943098902331},
+ {0.00183225941982580187, -0.00087483943098902331},
+ {-0.00183225941982580187, 0.00087483943098902331},
+ {-0.00183225941982580187, -0.00087483943098902331},
+ };
+
+ 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_denoy.c b/src/PJ_denoy.c
index b1a6fe80..10005a31 100644
--- a/src/PJ_denoy.c
+++ b/src/PJ_denoy.c
@@ -1,19 +1,69 @@
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(denoy, "Denoyer Semi-Elliptical") "\n\tPCyl., no inv., Sph.";
-#define C0 0.95
-#define C1 -.08333333333333333333
-#define C3 .00166666666666666666
-#define D1 0.9
-#define D5 0.03
-FORWARD(s_forward); /* spheroid */
- (void) P;
- xy.y = lp.phi;
- xy.x = lp.lam;
- lp.lam = fabs(lp.lam);
- xy.x *= cos((C0 + lp.lam * (C1 + lp.lam * lp.lam * C3)) *
- (lp.phi * (D1 + D5 * lp.phi * lp.phi * lp.phi * lp.phi)));
- return (xy);
+
+#define C0 0.95
+#define C1 -0.08333333333333333333
+#define C3 0.00166666666666666666
+#define D1 0.9
+#define D5 0.03
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0, 0.0};
+ (void) P;
+ xy.y = lp.phi;
+ xy.x = lp.lam;
+ lp.lam = fabs(lp.lam);
+ xy.x *= cos((C0 + lp.lam * (C1 + lp.lam * lp.lam * C3)) *
+ (lp.phi * (D1 + D5 * lp.phi * lp.phi * lp.phi * lp.phi)));
+ return xy;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(denoy) P->es = 0.; P->fwd = s_forward; ENDENTRY(P)
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ return pj_dealloc(P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(denoy) {
+ P->es = 0.0;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_denoy_selftest (void) {return 0;}
+#else
+
+int pj_denoy_selftest (void) {
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=denoy +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 223377.422876954137, 111701.07212763709},
+ { 223377.422876954137, -111701.07212763709},
+ {-223377.422876954137, 111701.07212763709},
+ {-223377.422876954137, -111701.07212763709},
+ };
+
+ return pj_generic_selftest (0, s_args, tolerance_xy, 0, 4, 4, fwd_in, 0, s_fwd_expect, 0, 0, 0);
+}
+
+
+#endif
diff --git a/src/PJ_eck1.c b/src/PJ_eck1.c
index b0b43da5..da2c8685 100644
--- a/src/PJ_eck1.c
+++ b/src/PJ_eck1.c
@@ -1,21 +1,92 @@
-#define PJ_LIB__
-#include <projects.h>
-PROJ_HEAD(eck1, "Eckert I") "\n\tPCyl., Sph.";
-#define FC .92131773192356127802
-#define RP .31830988618379067154
-FORWARD(s_forward); /* spheroid */
- (void) P;
- xy.x = FC * lp.lam * (1. - RP * fabs(lp.phi));
- xy.y = FC * lp.phi;
- return (xy);
-}
-INVERSE(s_inverse); /* spheroid */
- (void) P;
- lp.phi = xy.y / FC;
- lp.lam = xy.x / (FC * (1. - RP * fabs(lp.phi)));
- return (lp);
-}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(eck1)
- P->es = 0.; P->inv = s_inverse; P->fwd = s_forward;
-ENDENTRY(P)
+#define PJ_LIB__
+#include <projects.h>
+
+PROJ_HEAD(eck1, "Eckert I") "\n\tPCyl., Sph.";
+#define FC 0.92131773192356127802
+#define RP 0.31830988618379067154
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ (void) P;
+
+ xy.x = FC * lp.lam * (1. - RP * fabs(lp.phi));
+ xy.y = FC * lp.phi;
+
+ return xy;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ (void) P;
+
+ lp.phi = xy.y / FC;
+ lp.lam = xy.x / (FC * (1. - RP * fabs(lp.phi)));
+
+ return (lp);
+}
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ return pj_dealloc(P);
+}
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(eck1) {
+ P->es = 0.0;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P ;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_eck1_selftest (void) {return 0;}
+#else
+
+int pj_eck1_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=eck1 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+ XY s_fwd_expect[] = {
+ { 204680.88820295094, 102912.17842606473},
+ { 204680.88820295094, -102912.17842606473},
+ {-204680.88820295094, 102912.17842606473},
+ {-204680.88820295094, -102912.17842606473},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0019434150820034624, 0.00097170229538813102},
+ { 0.0019434150820034624, -0.00097170229538813102},
+ {-0.0019434150820034624, 0.00097170229538813102},
+ {-0.0019434150820034624, -0.00097170229538813102},
+ };
+
+ 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_eck2.c b/src/PJ_eck2.c
index 08b65595..6d73b88a 100644
--- a/src/PJ_eck2.c
+++ b/src/PJ_eck2.c
@@ -1,29 +1,104 @@
#define PJ_LIB__
-# include <projects.h>
+# include <projects.h>
+
PROJ_HEAD(eck2, "Eckert II") "\n\tPCyl. Sph.";
-#define FXC 0.46065886596178063902
-#define FYC 1.44720250911653531871
-#define C13 0.33333333333333333333
-#define ONEEPS 1.0000001
-FORWARD(s_forward); /* spheroid */
- (void) P;
- xy.x = FXC * lp.lam * (xy.y = sqrt(4. - 3. * sin(fabs(lp.phi))));
- xy.y = FYC * (2. - xy.y);
- if ( lp.phi < 0.) xy.y = -xy.y;
- return (xy);
+
+#define FXC 0.46065886596178063902
+#define FYC 1.44720250911653531871
+#define C13 0.33333333333333333333
+#define ONEEPS 1.0000001
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ (void) P;
+
+ xy.x = FXC * lp.lam * (xy.y = sqrt(4. - 3. * sin(fabs(lp.phi))));
+ xy.y = FYC * (2. - xy.y);
+ if ( lp.phi < 0.) xy.y = -xy.y;
+
+ return (xy);
}
-INVERSE(s_inverse); /* spheroid */
- lp.lam = xy.x / (FXC * ( lp.phi = 2. - fabs(xy.y) / FYC) );
- lp.phi = (4. - lp.phi * lp.phi) * C13;
- if (fabs(lp.phi) >= 1.) {
- if (fabs(lp.phi) > ONEEPS) I_ERROR
- else
- lp.phi = lp.phi < 0. ? -HALFPI : HALFPI;
- } else
- lp.phi = asin(lp.phi);
- if (xy.y < 0)
- lp.phi = -lp.phi;
- return (lp);
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ (void) P;
+
+ lp.lam = xy.x / (FXC * ( lp.phi = 2. - fabs(xy.y) / FYC) );
+ lp.phi = (4. - lp.phi * lp.phi) * C13;
+ if (fabs(lp.phi) >= 1.) {
+ if (fabs(lp.phi) > ONEEPS) I_ERROR
+ else
+ lp.phi = lp.phi < 0. ? -HALFPI : HALFPI;
+ } else
+ lp.phi = asin(lp.phi);
+ if (xy.y < 0)
+ lp.phi = -lp.phi;
+ return (lp);
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(eck2); P->es = 0.; P->inv = s_inverse; P->fwd = s_forward; ENDENTRY(P)
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ return pj_dealloc (P);
+}
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(eck2) {
+ P->es = 0.;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_eck2_selftest (void) {return 0;}
+#else
+
+int pj_eck2_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=eck2 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 204472.87090796008, 121633.73497524235},
+ { 204472.87090796008, -121633.73497524235},
+ {-204472.87090796008, 121633.73497524235},
+ {-204472.87090796008, -121633.73497524235},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0019434150820034624, 0.00082480429919795412},
+ { 0.0019434150820034624, -0.00082480429919795412},
+ {-0.0019434150820034624, 0.00082480429919795412},
+ {-0.0019434150820034624, -0.00082480429919795412},
+ };
+
+ 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_eck3.c b/src/PJ_eck3.c
index d7755f0c..3eb7f8f9 100644
--- a/src/PJ_eck3.c
+++ b/src/PJ_eck3.c
@@ -1,50 +1,295 @@
-#define PROJ_PARMS__ \
- double C_x, C_y, A, B;
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(eck3, "Eckert III") "\n\tPCyl, Sph.";
PROJ_HEAD(putp1, "Putnins P1") "\n\tPCyl, Sph.";
PROJ_HEAD(wag6, "Wagner VI") "\n\tPCyl, Sph.";
PROJ_HEAD(kav7, "Kavraisky VII") "\n\tPCyl, Sph.";
-FORWARD(s_forward); /* spheroid */
- xy.y = P->C_y * lp.phi;
- xy.x = P->C_x * lp.lam * (P->A + asqrt(1. - P->B * lp.phi * lp.phi));
- return (xy);
-}
-INVERSE(s_inverse); /* spheroid */
- lp.phi = xy.y / P->C_y;
- lp.lam = xy.x / (P->C_x * (P->A + asqrt(1. - P->B * lp.phi * lp.phi)));
- return (lp);
-}
-FREEUP; if (P) pj_dalloc(P); }
- static PJ *
-setup(PJ *P) {
- P->es = 0.;
- P->inv = s_inverse;
- P->fwd = s_forward;
- return P;
-}
-ENTRY0(eck3)
- P->C_x = .42223820031577120149;
- P->C_y = .84447640063154240298;
- P->A = 1.;
- P->B = 0.4052847345693510857755;
-ENDENTRY(setup(P))
-ENTRY0(kav7)
- P->C_x = 0.2632401569273184856851;
- P->C_x = 0.8660254037844;
- P->C_y = 1.;
- P->A = 0.;
- P->B = 0.30396355092701331433;
-ENDENTRY(setup(P))
-ENTRY0(wag6);
- P->C_x = P->C_y = 0.94745;
- P->A = 0.;
- P->B = 0.30396355092701331433;
-ENDENTRY(setup(P))
-ENTRY0(putp1);
- P->C_x = 1.89490;
- P->C_y = 0.94745;
- P->A = -0.5;
- P->B = 0.30396355092701331433;
-ENDENTRY(setup(P))
+
+struct pj_opaque {
+ double C_x, C_y, A, B;
+};
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+
+ xy.y = Q->C_y * lp.phi;
+ xy.x = Q->C_x * lp.lam * (Q->A + asqrt(1. - Q->B * lp.phi * lp.phi));
+ return xy;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+
+ lp.phi = xy.y / Q->C_y;
+ lp.lam = xy.x / (Q->C_x * (Q->A + asqrt(1. - Q->B * lp.phi * lp.phi)));
+ 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->es = 0.;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+ return P;
+}
+
+
+PJ *PROJECTION(eck3) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->C_x = 0.42223820031577120149;
+ Q->C_y = 0.84447640063154240298;
+ Q->A = 1.0;
+ Q->B = 0.4052847345693510857755;
+
+ return setup(P);
+}
+
+
+PJ *PROJECTION(kav7) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ /* Defined twice in original code - Using 0.866...,
+ * but leaving the other one here as a safety measure.
+ * Q->C_x = 0.2632401569273184856851; */
+ Q->C_x = 0.8660254037844;
+ Q->C_y = 1.;
+ Q->A = 0.;
+ Q->B = 0.30396355092701331433;
+
+ return setup(P);
+}
+
+
+PJ *PROJECTION(wag6) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->C_x = Q->C_y = 0.94745;
+ Q->A = 0.0;
+ Q->B = 0.30396355092701331433;
+
+ return setup(P);
+}
+
+
+PJ *PROJECTION(putp1) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->C_x = 1.89490;
+ Q->C_y = 0.94745;
+ Q->A = -0.5;
+ Q->B = 0.30396355092701331433;
+
+ return setup(P);
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_eck3_selftest (void) {return 0;}
+#else
+
+int pj_eck3_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=eck3 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 188652.01572153764, 94328.919337031271},
+ { 188652.01572153764, -94328.919337031271},
+ {-188652.01572153764, 94328.919337031271},
+ {-188652.01572153764, -94328.919337031271},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0021202405520236059, 0.0010601202759750307},
+ { 0.0021202405520236059, -0.0010601202759750307},
+ {-0.0021202405520236059, 0.0010601202759750307},
+ {-0.0021202405520236059, -0.0010601202759750307},
+ };
+
+ 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_kav7_selftest (void) {return 0;}
+#else
+
+int pj_kav7_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=kav7 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 193462.9749437288, 111701.07212763709},
+ { 193462.9749437288, -111701.07212763709},
+ {-193462.9749437288, 111701.07212763709},
+ {-193462.9749437288, -111701.07212763709}
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0020674833579085268, 0.00089524655489191132},
+ { 0.0020674833579085268, -0.00089524655489191132},
+ {-0.0020674833579085268, 0.00089524655489191132},
+ {-0.0020674833579085268, -0.00089524655489191132}
+ };
+
+ 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_wag6_selftest (void) {return 0;}
+#else
+
+int pj_wag6_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=wag6 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 211652.56216440981, 105831.18078732977},
+ { 211652.56216440981, -105831.18078732977},
+ {-211652.56216440981, 105831.18078732977},
+ {-211652.56216440981, -105831.18078732977}
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0018898022163257513, 0.000944901108123818},
+ { 0.0018898022163257513, -0.000944901108123818},
+ {-0.0018898022163257513, 0.000944901108123818},
+ {-0.0018898022163257513, -0.000944901108123818}
+ };
+
+ 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_putp1_selftest (void) {return 0;}
+#else
+
+int pj_putp1_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=putp1 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 211642.76275416015, 105831.18078732977},
+ { 211642.76275416015, -105831.18078732977},
+ {-211642.76275416015, 105831.18078732977},
+ {-211642.76275416015, -105831.18078732977}
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0018898022164038663, 0.000944901108123818},
+ { 0.0018898022164038663, -0.000944901108123818},
+ {-0.0018898022164038663, 0.000944901108123818},
+ {-0.0018898022164038663, -0.000944901108123818}
+ };
+
+ 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_eck4.c b/src/PJ_eck4.c
index 0bedbbc9..8a56f019 100644
--- a/src/PJ_eck4.c
+++ b/src/PJ_eck4.c
@@ -1,45 +1,117 @@
-#define PJ_LIB__
-#include <projects.h>
-PROJ_HEAD(eck4, "Eckert IV") "\n\tPCyl, Sph.";
-#define C_x .42223820031577120149
-#define C_y 1.32650042817700232218
-#define RC_y .75386330736002178205
-#define C_p 3.57079632679489661922
-#define RC_p .28004957675577868795
-#define EPS 1e-7
-#define NITER 6
-FORWARD(s_forward); /* spheroid */
- double p, V, s, c;
- int i;
- (void) P;
-
- p = C_p * sin(lp.phi);
- V = lp.phi * lp.phi;
- lp.phi *= 0.895168 + V * ( 0.0218849 + V * 0.00826809 );
- for (i = NITER; i ; --i) {
- c = cos(lp.phi);
- s = sin(lp.phi);
- lp.phi -= V = (lp.phi + s * (c + 2.) - p) /
- (1. + c * (c + 2.) - s * s);
- if (fabs(V) < EPS)
- break;
- }
- if (!i) {
- xy.x = C_x * lp.lam;
- xy.y = lp.phi < 0. ? -C_y : C_y;
- } else {
- xy.x = C_x * lp.lam * (1. + cos(lp.phi));
- xy.y = C_y * sin(lp.phi);
- }
- return (xy);
-}
-INVERSE(s_inverse); /* spheroid */
- double c;
-
- lp.phi = aasin(P->ctx,xy.y / C_y);
- lp.lam = xy.x / (C_x * (1. + (c = cos(lp.phi))));
- lp.phi = aasin(P->ctx,(lp.phi + sin(lp.phi) * (c + 2.)) / C_p);
- return (lp);
-}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(eck4); P->es = 0.; P->inv = s_inverse; P->fwd = s_forward; ENDENTRY(P)
+#define PJ_LIB__
+#include <projects.h>
+
+PROJ_HEAD(eck4, "Eckert IV") "\n\tPCyl, Sph.";
+
+#define C_x .42223820031577120149
+#define C_y 1.32650042817700232218
+#define RC_y .75386330736002178205
+#define C_p 3.57079632679489661922
+#define RC_p .28004957675577868795
+#define EPS 1e-7
+#define NITER 6
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ double p, V, s, c;
+ int i;
+ (void) P;
+
+ p = C_p * sin(lp.phi);
+ V = lp.phi * lp.phi;
+ lp.phi *= 0.895168 + V * ( 0.0218849 + V * 0.00826809 );
+ for (i = NITER; i ; --i) {
+ c = cos(lp.phi);
+ s = sin(lp.phi);
+ lp.phi -= V = (lp.phi + s * (c + 2.) - p) /
+ (1. + c * (c + 2.) - s * s);
+ if (fabs(V) < EPS)
+ break;
+ }
+ if (!i) {
+ xy.x = C_x * lp.lam;
+ xy.y = lp.phi < 0. ? -C_y : C_y;
+ } else {
+ xy.x = C_x * lp.lam * (1. + cos(lp.phi));
+ xy.y = C_y * sin(lp.phi);
+ }
+ return xy;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ double c;
+
+ lp.phi = aasin(P->ctx,xy.y / C_y);
+ lp.lam = xy.x / (C_x * (1. + (c = cos(lp.phi))));
+ lp.phi = aasin(P->ctx,(lp.phi + sin(lp.phi) * (c + 2.)) / C_p);
+ return lp;
+}
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+ return pj_dealloc(P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(eck4) {
+ P->es = 0.0;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_eck4_selftest (void) {return 0;}
+#else
+
+int pj_eck4_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=eck4 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 188646.38935641639, 132268.54017406539},
+ { 188646.38935641639, -132268.54017406539},
+ {-188646.38935641639, 132268.54017406539},
+ {-188646.38935641639, -132268.54017406539},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0021202405520236059, 0.00075601458836610643},
+ { 0.0021202405520236059, -0.00075601458836610643},
+ {-0.0021202405520236059, 0.00075601458836610643},
+ {-0.0021202405520236059, -0.00075601458836610643},
+ };
+
+ 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_eck5.c b/src/PJ_eck5.c
index 029c18e0..d7626939 100644
--- a/src/PJ_eck5.c
+++ b/src/PJ_eck5.c
@@ -1,20 +1,93 @@
-#define PJ_LIB__
-# include <projects.h>
-PROJ_HEAD(eck5, "Eckert V") "\n\tPCyl, Sph.";
-#define XF 0.44101277172455148219
-#define RXF 2.26750802723822639137
-#define YF 0.88202554344910296438
-#define RYF 1.13375401361911319568
-FORWARD(s_forward); /* spheroid */
- (void) P;
- xy.x = XF * (1. + cos(lp.phi)) * lp.lam;
- xy.y = YF * lp.phi;
- return (xy);
-}
-INVERSE(s_inverse); /* spheroid */
- (void) P;
- lp.lam = RXF * xy.x / (1. + cos( lp.phi = RYF * xy.y));
- return (lp);
-}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(eck5); P->es = 0.; P->inv = s_inverse; P->fwd = s_forward; ENDENTRY(P)
+#define PJ_LIB__
+#include <projects.h>
+
+PROJ_HEAD(eck5, "Eckert V") "\n\tPCyl, Sph.";
+
+#define XF 0.44101277172455148219
+#define RXF 2.26750802723822639137
+#define YF 0.88202554344910296438
+#define RYF 1.13375401361911319568
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ (void) P;
+ xy.x = XF * (1. + cos(lp.phi)) * lp.lam;
+ xy.y = YF * lp.phi;
+
+ return xy;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ (void) P;
+ lp.lam = RXF * xy.x / (1. + cos( lp.phi = RYF * xy.y));
+
+ return lp;
+}
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+ return pj_dealloc(P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(eck5) {
+ P->es = 0.0;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_eck5_selftest (void) {return 0;}
+#else
+
+int pj_eck5_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=eck5 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 197031.39213406085, 98523.198847226551},
+ { 197031.39213406085, -98523.198847226551},
+ {-197031.39213406085, 98523.198847226551},
+ {-197031.39213406085, -98523.198847226551},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ {0.002029978749734037, 0.001014989374787388},
+ {0.002029978749734037, -0.001014989374787388},
+ {-0.002029978749734037, 0.001014989374787388},
+ {-0.002029978749734037, -0.001014989374787388},
+ };
+
+ 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_eqc.c b/src/PJ_eqc.c
index c69a6baa..3fcb1007 100644
--- a/src/PJ_eqc.c
+++ b/src/PJ_eqc.c
@@ -1,23 +1,108 @@
-#define PROJ_PARMS__ \
- double rc;
#define PJ_LIB__
-# include <projects.h>
+#include <projects.h>
+
+struct pj_opaque {
+ double rc;
+};
+
PROJ_HEAD(eqc, "Equidistant Cylindrical (Plate Caree)")
- "\n\tCyl, Sph\n\tlat_ts=[, lat_0=0]";
-FORWARD(s_forward); /* spheroid */
- xy.x = P->rc * lp.lam;
- xy.y = lp.phi - P->phi0;
- return (xy);
+ "\n\tCyl, Sph\n\tlat_ts=[, lat_0=0]";
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+
+ xy.x = Q->rc * lp.lam;
+ xy.y = lp.phi - P->phi0;
+
+ return xy;
}
-INVERSE(s_inverse); /* spheroid */
- lp.lam = xy.x / P->rc;
- lp.phi = xy.y + P->phi0;
- return (lp);
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+
+ lp.lam = xy.x / Q->rc;
+ lp.phi = xy.y + P->phi0;
+
+ return lp;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(eqc)
- if ((P->rc = cos(pj_param(P->ctx, P->params, "rlat_ts").f)) <= 0.) E_ERROR(-24);
- P->inv = s_inverse;
- P->fwd = s_forward;
- P->es = 0.;
-ENDENTRY(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;
+}
+
+
+PJ *PROJECTION(eqc) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ if ((Q->rc = cos(pj_param(P->ctx, P->params, "rlat_ts").f)) <= 0.) E_ERROR(-24);
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+ P->es = 0.;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_eqc_selftest (void) {return 0;}
+#else
+
+int pj_eqc_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=eqc +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 223402.144255274179, 111701.07212763709},
+ { 223402.144255274179, -111701.07212763709},
+ {-223402.144255274179, 111701.07212763709},
+ {-223402.144255274179, -111701.07212763709},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.00179049310978382265, 0.000895246554891911323},
+ { 0.00179049310978382265, -0.000895246554891911323},
+ {-0.00179049310978382265, 0.000895246554891911323},
+ {-0.00179049310978382265, -0.000895246554891911323},
+ };
+
+ 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_eqdc.c b/src/PJ_eqdc.c
index 01a0f03f..917131e1 100644
--- a/src/PJ_eqdc.c
+++ b/src/PJ_eqdc.c
@@ -1,85 +1,190 @@
-#define PROJ_PARMS__ \
- double phi1; \
- double phi2; \
- double n; \
- double rho; \
- double rho0; \
- double c; \
- double *en; \
- int ellips;
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
+struct pj_opaque {
+ double phi1;
+ double phi2;
+ double n;
+ double rho;
+ double rho0;
+ double c;
+ double *en;
+ int ellips;
+};
+
PROJ_HEAD(eqdc, "Equidistant Conic")
- "\n\tConic, Sph&Ell\n\tlat_1= lat_2=";
-# define EPS10 1.e-10
-FORWARD(e_forward); /* sphere & ellipsoid */
- P->rho = P->c - (P->ellips ? pj_mlfn(lp.phi, sin(lp.phi),
- cos(lp.phi), P->en) : lp.phi);
- xy.x = P->rho * sin( lp.lam *= P->n );
- xy.y = P->rho0 - P->rho * cos(lp.lam);
- return (xy);
+ "\n\tConic, Sph&Ell\n\tlat_1= lat_2=";
+# define EPS10 1.e-10
+
+
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+
+ Q->rho = Q->c - (Q->ellips ? pj_mlfn(lp.phi, sin(lp.phi),
+ cos(lp.phi), Q->en) : lp.phi);
+ xy.x = Q->rho * sin( lp.lam *= Q->n );
+ xy.y = Q->rho0 - Q->rho * cos(lp.lam);
+
+ return xy;
}
-INVERSE(e_inverse); /* sphere & ellipsoid */
- if ((P->rho = hypot(xy.x, xy.y = P->rho0 - xy.y)) != 0.0 ) {
- if (P->n < 0.) {
- P->rho = -P->rho;
- xy.x = -xy.x;
- xy.y = -xy.y;
- }
- lp.phi = P->c - P->rho;
- if (P->ellips)
- lp.phi = pj_inv_mlfn(P->ctx, lp.phi, P->es, P->en);
- lp.lam = atan2(xy.x, xy.y) / P->n;
- } else {
- lp.lam = 0.;
- lp.phi = P->n > 0. ? HALFPI : - HALFPI;
- }
- return (lp);
+
+
+static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+
+ if ((Q->rho = hypot(xy.x, xy.y = Q->rho0 - xy.y)) != 0.0 ) {
+ if (Q->n < 0.) {
+ Q->rho = -Q->rho;
+ xy.x = -xy.x;
+ xy.y = -xy.y;
+ }
+ lp.phi = Q->c - Q->rho;
+ if (Q->ellips)
+ lp.phi = pj_inv_mlfn(P->ctx, lp.phi, P->es, Q->en);
+ lp.lam = atan2(xy.x, xy.y) / Q->n;
+ } else {
+ lp.lam = 0.;
+ lp.phi = Q->n > 0. ? HALFPI : - HALFPI;
+ }
+ return lp;
}
-SPECIAL(fac) {
- double sinphi, cosphi;
-
- sinphi = sin(lp.phi);
- cosphi = cos(lp.phi);
- fac->code |= IS_ANAL_HK;
- fac->h = 1.;
- fac->k = P->n * (P->c - (P->ellips ? pj_mlfn(lp.phi, sinphi,
- cosphi, P->en) : lp.phi)) / pj_msfn(sinphi, cosphi, P->es);
+
+
+static void special(LP lp, PJ *P, struct FACTORS *fac) {
+ struct pj_opaque *Q = P->opaque;
+ double sinphi, cosphi;
+
+ sinphi = sin(lp.phi);
+ cosphi = cos(lp.phi);
+ fac->code |= IS_ANAL_HK;
+ fac->h = 1.;
+ fac->k = Q->n * (Q->c - (Q->ellips ? pj_mlfn(lp.phi, sinphi,
+ cosphi, Q->en) : lp.phi)) / pj_msfn(sinphi, cosphi, P->es);
+}
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+ if (0==P->opaque)
+ return pj_dealloc (P);
+
+ if (P->opaque->en)
+ pj_dealloc (P->opaque->en);
+
+ pj_dealloc (P->opaque);
+ return pj_dealloc(P);
}
-FREEUP; if (P) { if (P->en) pj_dalloc(P->en); pj_dalloc(P); } }
-ENTRY1(eqdc, en)
- double cosphi, sinphi;
- int secant;
-
- P->phi1 = pj_param(P->ctx, P->params, "rlat_1").f;
- P->phi2 = pj_param(P->ctx, P->params, "rlat_2").f;
- if (fabs(P->phi1 + P->phi2) < EPS10) E_ERROR(-21);
- if (!(P->en = pj_enfn(P->es)))
- E_ERROR_0;
- P->n = sinphi = sin(P->phi1);
- cosphi = cos(P->phi1);
- secant = fabs(P->phi1 - P->phi2) >= EPS10;
- if( (P->ellips = (P->es > 0.)) ) {
- double ml1, m1;
-
- m1 = pj_msfn(sinphi, cosphi, P->es);
- ml1 = pj_mlfn(P->phi1, sinphi, cosphi, P->en);
- if (secant) { /* secant cone */
- sinphi = sin(P->phi2);
- cosphi = cos(P->phi2);
- P->n = (m1 - pj_msfn(sinphi, cosphi, P->es)) /
- (pj_mlfn(P->phi2, sinphi, cosphi, P->en) - ml1);
- }
- P->c = ml1 + m1 / P->n;
- P->rho0 = P->c - pj_mlfn(P->phi0, sin(P->phi0),
- cos(P->phi0), P->en);
- } else {
- if (secant)
- P->n = (cosphi - cos(P->phi2)) / (P->phi2 - P->phi1);
- P->c = P->phi1 + cos(P->phi1) / P->n;
- P->rho0 = P->c - P->phi0;
- }
- P->inv = e_inverse;
- P->fwd = e_forward;
- P->spc = fac;
-ENDENTRY(P)
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(eqdc) {
+ double cosphi, sinphi;
+ int secant;
+
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->phi1 = pj_param(P->ctx, P->params, "rlat_1").f;
+ Q->phi2 = pj_param(P->ctx, P->params, "rlat_2").f;
+ if (fabs(Q->phi1 + Q->phi2) < EPS10) E_ERROR(-21);
+ if (!(Q->en = pj_enfn(P->es)))
+ E_ERROR_0;
+ Q->n = sinphi = sin(Q->phi1);
+ cosphi = cos(Q->phi1);
+ secant = fabs(Q->phi1 - Q->phi2) >= EPS10;
+ if( (Q->ellips = (P->es > 0.)) ) {
+ double ml1, m1;
+
+ m1 = pj_msfn(sinphi, cosphi, P->es);
+ ml1 = pj_mlfn(Q->phi1, sinphi, cosphi, Q->en);
+ if (secant) { /* secant cone */
+ sinphi = sin(Q->phi2);
+ cosphi = cos(Q->phi2);
+ Q->n = (m1 - pj_msfn(sinphi, cosphi, P->es)) /
+ (pj_mlfn(Q->phi2, sinphi, cosphi, Q->en) - ml1);
+ }
+ Q->c = ml1 + m1 / Q->n;
+ Q->rho0 = Q->c - pj_mlfn(P->phi0, sin(P->phi0),
+ cos(P->phi0), Q->en);
+ } else {
+ if (secant)
+ Q->n = (cosphi - cos(Q->phi2)) / (Q->phi2 - Q->phi1);
+ Q->c = Q->phi1 + cos(Q->phi1) / Q->n;
+ Q->rho0 = Q->c - P->phi0;
+ }
+ P->inv = e_inverse;
+ P->fwd = e_forward;
+ P->spc = special;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_eqdc_selftest (void) {return 0;}
+#else
+
+int pj_eqdc_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=eqdc +ellps=GRS80 +lat_1=0.5 +lat_2=2"};
+ char s_args[] = {"+proj=eqdc +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ { 222588.440269285755, 110659.134907347048},
+ { 222756.836702042434, -110489.578087220681},
+ {-222588.440269285755, 110659.134907347048},
+ {-222756.836702042434, -110489.578087220681},
+ };
+
+ XY s_fwd_expect[] = {
+ { 223351.088175113517, 111786.108747173785},
+ { 223521.200266735133, -111615.970741240744},
+ {-223351.088175113517, 111786.108747173785},
+ {-223521.200266735133, -111615.970741240744},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ { 0.00179635944879094839, 0.000904368858588402644},
+ { 0.00179635822020772734, -0.000904370095529954975},
+ {-0.00179635944879094839, 0.000904368858588402644},
+ {-0.00179635822020772734, -0.000904370095529954975},
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0017902210900486641, 0.000895245944814909169},
+ { 0.00179021986984890255, -0.000895247165333684842},
+ {-0.0017902210900486641, 0.000895245944814909169},
+ {-0.00179021986984890255, -0.000895247165333684842},
+ };
+
+ 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_fahey.c b/src/PJ_fahey.c
index 007fc906..b8841c96 100644
--- a/src/PJ_fahey.c
+++ b/src/PJ_fahey.c
@@ -1,19 +1,95 @@
-#define PJ_LIB__
-# include <projects.h>
-PROJ_HEAD(fahey, "Fahey") "\n\tPcyl, Sph.";
-#define TOL 1e-6
-FORWARD(s_forward); /* spheroid */
- (void) P;
- xy.y = 1.819152 * ( xy.x = tan(0.5 * lp.phi) );
- xy.x = 0.819152 * lp.lam * asqrt(1 - xy.x * xy.x);
- return (xy);
-}
-INVERSE(s_inverse); /* spheroid */
- (void) P;
- lp.phi = 2. * atan(xy.y /= 1.819152);
- lp.lam = fabs(xy.y = 1. - xy.y * xy.y) < TOL ? 0. :
- xy.x / (0.819152 * sqrt(xy.y));
- return (lp);
-}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(fahey) P->es = 0.; P->inv = s_inverse; P->fwd = s_forward; ENDENTRY(P)
+#define PJ_LIB__
+#include <projects.h>
+
+PROJ_HEAD(fahey, "Fahey") "\n\tPcyl, Sph.";
+
+#define TOL 1e-6
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ (void) P;
+
+ xy.x = tan(0.5 * lp.phi);
+ xy.y = 1.819152 * xy.x;
+ xy.x = 0.819152 * lp.lam * asqrt(1 - xy.x * xy.x);
+ return xy;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ (void) P;
+
+ xy.y /= 1.819152;
+ lp.phi = 2. * atan(xy.y);
+ xy.y = 1. - xy.y * xy.y;
+ lp.lam = fabs(xy.y) < TOL ? 0. : xy.x / (0.819152 * sqrt(xy.y));
+ return lp;
+}
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+ return pj_dealloc(P);
+}
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(fahey) {
+ P->es = 0.;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_fahey_selftest (void) {return 0;}
+#else
+
+int pj_fahey_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=fahey +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 182993.34464912376, 101603.19356988439},
+ { 182993.34464912376, -101603.19356988439},
+ {-182993.34464912376, 101603.19356988439},
+ {-182993.34464912376, -101603.19356988439},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ {0.0021857886080359551, 0.00098424601668238403},
+ {0.0021857886080359551, -0.00098424601668238403},
+ {-0.0021857886080359551, 0.00098424601668238403},
+ {-0.0021857886080359551, -0.00098424601668238403},
+ };
+
+ 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_fouc_s.c b/src/PJ_fouc_s.c
index b84b3f82..4123497c 100644
--- a/src/PJ_fouc_s.c
+++ b/src/PJ_fouc_s.c
@@ -1,45 +1,126 @@
-#define PROJ_PARMS__ \
- double n, n1;
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(fouc_s, "Foucaut Sinusoidal") "\n\tPCyl., Sph.";
+
#define MAX_ITER 10
#define LOOP_TOL 1e-7
-FORWARD(s_forward); /* spheroid */
- double t;
- t = cos(lp.phi);
- xy.x = lp.lam * t / (P->n + P->n1 * t);
- xy.y = P->n * lp.phi + P->n1 * sin(lp.phi);
- return (xy);
+struct pj_opaque {
+ double n, n1;
+};
+
+
+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 = cos(lp.phi);
+ xy.x = lp.lam * t / (Q->n + Q->n1 * t);
+ xy.y = Q->n * lp.phi + Q->n1 * sin(lp.phi);
+ return xy;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double V;
+ int i;
+
+ if (Q->n) {
+ lp.phi = xy.y;
+ for (i = MAX_ITER; i ; --i) {
+ lp.phi -= V = (Q->n * lp.phi + Q->n1 * sin(lp.phi) - xy.y ) /
+ (Q->n + Q->n1 * cos(lp.phi));
+ if (fabs(V) < LOOP_TOL)
+ break;
+ }
+ if (!i)
+ lp.phi = xy.y < 0. ? -HALFPI : HALFPI;
+ } else
+ lp.phi = aasin(P->ctx,xy.y);
+ V = cos(lp.phi);
+ lp.lam = xy.x * (Q->n + Q->n1 * V) / V;
+ 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);
}
-INVERSE(s_inverse); /* spheroid */
- double V;
- int i;
-
- if (P->n) {
- lp.phi = xy.y;
- for (i = MAX_ITER; i ; --i) {
- lp.phi -= V = (P->n * lp.phi + P->n1 * sin(lp.phi) - xy.y ) /
- (P->n + P->n1 * cos(lp.phi));
- if (fabs(V) < LOOP_TOL)
- break;
- }
- if (!i)
- lp.phi = xy.y < 0. ? -HALFPI : HALFPI;
- } else
- lp.phi = aasin(P->ctx,xy.y);
- V = cos(lp.phi);
- lp.lam = xy.x * (P->n + P->n1 * V) / V;
- return (lp);
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(fouc_s)
- P->n = pj_param(P->ctx, P->params, "dn").f;
- if (P->n < 0. || P->n > 1.)
- E_ERROR(-99)
- P->n1 = 1. - P->n;
- P->es = 0;
- P->inv = s_inverse;
- P->fwd = s_forward;
-ENDENTRY(P)
+
+
+PJ *PROJECTION(fouc_s) {
+ 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;
+ if (Q->n < 0. || Q->n > 1.)
+ E_ERROR(-99)
+ Q->n1 = 1. - Q->n;
+ P->es = 0;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_fouc_s_selftest (void) {return 0;}
+#else
+
+int pj_fouc_s_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=fouc_s +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 223402.14425527424, 111695.40119861449},
+ { 223402.14425527424, -111695.40119861449},
+ {-223402.14425527424, 111695.40119861449},
+ {-223402.14425527424, -111695.40119861449},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0017904931097838226, 0.000895246554928339},
+ { 0.0017904931097838226, -0.000895246554928339},
+ {-0.0017904931097838226, 0.000895246554928339},
+ {-0.0017904931097838226, -0.000895246554928339},
+ };
+
+ 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_gall.c b/src/PJ_gall.c
index 1acd7d09..b3d7cc6c 100644
--- a/src/PJ_gall.c
+++ b/src/PJ_gall.c
@@ -1,21 +1,100 @@
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(gall, "Gall (Gall Stereographic)") "\n\tCyl, Sph";
-#define YF 1.70710678118654752440
-#define XF 0.70710678118654752440
-#define RYF 0.58578643762690495119
-#define RXF 1.41421356237309504880
-FORWARD(s_forward); /* spheroid */
- (void) P;
- xy.x = XF * lp.lam;
- xy.y = YF * tan(.5 * lp.phi);
- return (xy);
+
+#define YF 1.70710678118654752440
+#define XF 0.70710678118654752440
+#define RYF 0.58578643762690495119
+#define RXF 1.41421356237309504880
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ (void) P;
+
+ xy.x = XF * lp.lam;
+ xy.y = YF * tan(.5 * lp.phi);
+
+ return xy;
}
-INVERSE(s_inverse); /* spheroid */
- (void) P;
- lp.lam = RXF * xy.x;
- lp.phi = 2. * atan(xy.y * RYF);
- return (lp);
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ (void) P;
+
+ lp.lam = RXF * xy.x;
+ lp.phi = 2. * atan(xy.y * RYF);
+
+ return lp;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(gall) P->es = 0.; P->inv = s_inverse; P->fwd = s_forward; ENDENTRY(P)
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+
+ return pj_dealloc(P);
+}
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(gall) {
+ P->es = 0.0;
+
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_gall_selftest (void) {return 0;}
+#else
+
+int pj_gall_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=gall +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 157969.17113451968, 95345.249178385886},
+ { 157969.17113451968, -95345.249178385886},
+ {-157969.17113451968, 95345.249178385886},
+ {-157969.17113451968, -95345.249178385886},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0025321396391918614, 0.001048846580346495},
+ { 0.0025321396391918614, -0.001048846580346495},
+ {-0.0025321396391918614, 0.001048846580346495},
+ {-0.0025321396391918614, -0.001048846580346495},
+ };
+
+ 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_geos.c b/src/PJ_geos.c
index 09393adf..578608c9 100644
--- a/src/PJ_geos.c
+++ b/src/PJ_geos.c
@@ -3,8 +3,7 @@
**
** Copyright (c) 2004 Gerald I. Evenden
** Copyright (c) 2012 Martin Raspaud
-*/
-/*
+**
** See also (section 4.4.3.2):
** http://www.eumetsat.int/en/area4/msg/news/us_doc/cgms_03_26.pdf
**
@@ -27,164 +26,274 @@
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#define PROJ_PARMS__ \
- double h; \
- double radius_p; \
- double radius_p2; \
- double radius_p_inv2; \
- double radius_g; \
- double radius_g_1; \
- double C; \
- char * sweep_axis; \
- int flip_axis;
+
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
+struct pj_opaque {
+ double h;
+ double radius_p;
+ double radius_p2;
+ double radius_p_inv2;
+ double radius_g;
+ double radius_g_1;
+ double C;
+ char *sweep_axis;
+ int flip_axis;
+};
PROJ_HEAD(geos, "Geostationary Satellite View") "\n\tAzi, Sph&Ell\n\th=";
-FORWARD(s_forward); /* spheroid */
- double Vx, Vy, Vz, tmp;
-
-/* Calculation of the three components of the vector from satellite to
-** position on earth surface (lon,lat).*/
- tmp = cos(lp.phi);
- Vx = cos (lp.lam) * tmp;
- Vy = sin (lp.lam) * tmp;
- Vz = sin (lp.phi);
-/* Check visibility.*/
- if (((P->radius_g - Vx) * Vx - Vy * Vy - Vz * Vz) < 0.) F_ERROR;
-/* Calculation based on view angles from satellite.*/
- tmp = P->radius_g - Vx;
- if(P->flip_axis)
- {
- xy.x = P->radius_g_1 * atan(Vy / hypot(Vz, tmp));
- xy.y = P->radius_g_1 * atan(Vz / tmp);
- }
- else
- {
- xy.x = P->radius_g_1 * atan(Vy / tmp);
- xy.y = P->radius_g_1 * atan(Vz / hypot(Vy, tmp));
- }
- return (xy);
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double Vx, Vy, Vz, tmp;
+
+ /* Calculation of the three components of the vector from satellite to
+ ** position on earth surface (lon,lat).*/
+ tmp = cos(lp.phi);
+ Vx = cos (lp.lam) * tmp;
+ Vy = sin (lp.lam) * tmp;
+ Vz = sin (lp.phi);
+
+ /* Check visibility*/
+
+
+ /* Calculation based on view angles from satellite.*/
+ tmp = Q->radius_g - Vx;
+
+ if(Q->flip_axis) {
+ xy.x = Q->radius_g_1 * atan(Vy / hypot(Vz, tmp));
+ xy.y = Q->radius_g_1 * atan(Vz / tmp);
+ } else {
+ xy.x = Q->radius_g_1 * atan(Vy / tmp);
+ xy.y = Q->radius_g_1 * atan(Vz / hypot(Vy, tmp));
+ }
+
+ return xy;
}
-FORWARD(e_forward); /* ellipsoid */
- double r, Vx, Vy, Vz, tmp;
-
-/* Calculation of geocentric latitude. */
- lp.phi = atan (P->radius_p2 * tan (lp.phi));
-/* Calculation of the three components of the vector from satellite to
-** position on earth surface (lon,lat).*/
- r = (P->radius_p) / hypot(P->radius_p * cos (lp.phi), sin (lp.phi));
- Vx = r * cos (lp.lam) * cos (lp.phi);
- Vy = r * sin (lp.lam) * cos (lp.phi);
- Vz = r * sin (lp.phi);
-/* Check visibility. */
- if (((P->radius_g - Vx) * Vx - Vy * Vy - Vz * Vz * P->radius_p_inv2) < 0.)
- F_ERROR;
-/* Calculation based on view angles from satellite. */
- tmp = P->radius_g - Vx;
- if(P->flip_axis)
- {
- xy.x = P->radius_g_1 * atan (Vy / hypot (Vz, tmp));
- xy.y = P->radius_g_1 * atan (Vz / tmp);
- }
- else
- {
- xy.x = P->radius_g_1 * atan (Vy / tmp);
- xy.y = P->radius_g_1 * atan (Vz / hypot (Vy, tmp));
- }
- 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 r, Vx, Vy, Vz, tmp;
+
+ /* Calculation of geocentric latitude. */
+ lp.phi = atan (Q->radius_p2 * tan (lp.phi));
+
+ /* Calculation of the three components of the vector from satellite to
+ ** position on earth surface (lon,lat).*/
+ r = (Q->radius_p) / hypot(Q->radius_p * cos (lp.phi), sin (lp.phi));
+ Vx = r * cos (lp.lam) * cos (lp.phi);
+ Vy = r * sin (lp.lam) * cos (lp.phi);
+ Vz = r * sin (lp.phi);
+
+ /* Check visibility. */
+ if (((Q->radius_g - Vx) * Vx - Vy * Vy - Vz * Vz * Q->radius_p_inv2) < 0.)
+ F_ERROR;
+
+ /* Calculation based on view angles from satellite. */
+ tmp = Q->radius_g - Vx;
+
+ if(Q->flip_axis) {
+ xy.x = Q->radius_g_1 * atan (Vy / hypot (Vz, tmp));
+ xy.y = Q->radius_g_1 * atan (Vz / tmp);
+ } else {
+ xy.x = Q->radius_g_1 * atan (Vy / tmp);
+ xy.y = Q->radius_g_1 * atan (Vz / hypot (Vy, tmp));
+ }
+
+ return xy;
}
-INVERSE(s_inverse); /* spheroid */
- double Vx, Vy, Vz, a, b, det, k;
-
-/* Setting three components of vector from satellite to position.*/
- Vx = -1.0;
- if(P->flip_axis)
- {
- Vz = tan (xy.y / (P->radius_g - 1.0));
- Vy = tan (xy.x / (P->radius_g - 1.0)) * sqrt (1.0 + Vz * Vz);
- }
- else
- {
- Vy = tan (xy.x / (P->radius_g - 1.0));
- Vz = tan (xy.y / (P->radius_g - 1.0)) * sqrt (1.0 + Vy * Vy);
- }
-/* Calculation of terms in cubic equation and determinant.*/
- a = Vy * Vy + Vz * Vz + Vx * Vx;
- b = 2 * P->radius_g * Vx;
- if ((det = (b * b) - 4 * a * P->C) < 0.) I_ERROR;
-/* Calculation of three components of vector from satellite to position.*/
- k = (-b - sqrt(det)) / (2 * a);
- Vx = P->radius_g + k * Vx;
- Vy *= k;
- Vz *= k;
-/* Calculation of longitude and latitude.*/
- lp.lam = atan2 (Vy, Vx);
- lp.phi = atan (Vz * cos (lp.lam) / Vx);
- return (lp);
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double Vx, Vy, Vz, a, b, det, k;
+
+ /* Setting three components of vector from satellite to position.*/
+ Vx = -1.0;
+ if(Q->flip_axis) {
+ Vz = tan (xy.y / (Q->radius_g - 1.0));
+ Vy = tan (xy.x / (Q->radius_g - 1.0)) * sqrt (1.0 + Vz * Vz);
+ } else {
+ Vy = tan (xy.x / (Q->radius_g - 1.0));
+ Vz = tan (xy.y / (Q->radius_g - 1.0)) * sqrt (1.0 + Vy * Vy);
+ }
+
+ /* Calculation of terms in cubic equation and determinant.*/
+ a = Vy * Vy + Vz * Vz + Vx * Vx;
+ b = 2 * Q->radius_g * Vx;
+ if ((det = (b * b) - 4 * a * Q->C) < 0.) I_ERROR;
+
+ /* Calculation of three components of vector from satellite to position.*/
+ k = (-b - sqrt(det)) / (2 * a);
+ Vx = Q->radius_g + k * Vx;
+ Vy *= k;
+ Vz *= k;
+
+ /* Calculation of longitude and latitude.*/
+ lp.lam = atan2 (Vy, Vx);
+ lp.phi = atan (Vz * cos (lp.lam) / Vx);
+
+ return lp;
}
-INVERSE(e_inverse); /* ellipsoid */
- double Vx, Vy, Vz, a, b, det, k;
-
-/* Setting three components of vector from satellite to position.*/
- Vx = -1.0;
- if(P->flip_axis)
- {
- Vz = tan (xy.y / P->radius_g_1);
- Vy = tan (xy.x / P->radius_g_1) * hypot(1.0, Vz);
- }
- else
- {
- Vy = tan (xy.x / P->radius_g_1);
- Vz = tan (xy.y / P->radius_g_1) * hypot(1.0, Vy);
- }
-/* Calculation of terms in cubic equation and determinant.*/
- a = Vz / P->radius_p;
- a = Vy * Vy + a * a + Vx * Vx;
- b = 2 * P->radius_g * Vx;
- if ((det = (b * b) - 4 * a * P->C) < 0.) I_ERROR;
-/* Calculation of three components of vector from satellite to position.*/
- k = (-b - sqrt(det)) / (2. * a);
- Vx = P->radius_g + k * Vx;
- Vy *= k;
- Vz *= k;
-/* Calculation of longitude and latitude.*/
- lp.lam = atan2 (Vy, Vx);
- lp.phi = atan (Vz * cos (lp.lam) / Vx);
- lp.phi = atan (P->radius_p_inv2 * tan (lp.phi));
- return (lp);
+
+
+static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double Vx, Vy, Vz, a, b, det, k;
+
+ /* Setting three components of vector from satellite to position.*/
+ Vx = -1.0;
+
+ if(Q->flip_axis) {
+ Vz = tan (xy.y / Q->radius_g_1);
+ Vy = tan (xy.x / Q->radius_g_1) * hypot(1.0, Vz);
+ } else {
+ Vy = tan (xy.x / Q->radius_g_1);
+ Vz = tan (xy.y / Q->radius_g_1) * hypot(1.0, Vy);
+ }
+
+ /* Calculation of terms in cubic equation and determinant.*/
+ a = Vz / Q->radius_p;
+ a = Vy * Vy + a * a + Vx * Vx;
+ b = 2 * Q->radius_g * Vx;
+ if ((det = (b * b) - 4 * a * Q->C) < 0.) I_ERROR;
+
+ /* Calculation of three components of vector from satellite to position.*/
+ k = (-b - sqrt(det)) / (2. * a);
+ Vx = Q->radius_g + k * Vx;
+ Vy *= k;
+ Vz *= k;
+
+ /* Calculation of longitude and latitude.*/
+ lp.lam = atan2 (Vy, Vx);
+ lp.phi = atan (Vz * cos (lp.lam) / Vx);
+ lp.phi = atan (Q->radius_p_inv2 * tan (lp.phi));
+
+ 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);
}
-FREEUP; if (P) free(P); }
-ENTRY0(geos)
- if ((P->h = pj_param(P->ctx, P->params, "dh").f) <= 0.) E_ERROR(-30);
- if (P->phi0) E_ERROR(-46);
- P->sweep_axis = pj_param(P->ctx, P->params, "ssweep").s;
- if (P->sweep_axis == NULL)
- P->flip_axis = 0;
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(geos) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ if ((Q->h = pj_param(P->ctx, P->params, "dh").f) <= 0.) E_ERROR(-30);
+
+ if (P->phi0) E_ERROR(-46);
+
+ Q->sweep_axis = pj_param(P->ctx, P->params, "ssweep").s;
+ if (Q->sweep_axis == NULL)
+ Q->flip_axis = 0;
+ else {
+ if (Q->sweep_axis[1] != '\0' ||
+ (Q->sweep_axis[0] != 'x' &&
+ Q->sweep_axis[0] != 'y'))
+ E_ERROR(-49);
+ if (Q->sweep_axis[0] == 'x')
+ Q->flip_axis = 1;
else
- {
- if (P->sweep_axis[1] != '\0' ||
- (P->sweep_axis[0] != 'x' &&
- P->sweep_axis[0] != 'y'))
- E_ERROR(-49);
- if (P->sweep_axis[0] == 'x')
- P->flip_axis = 1;
- else
- P->flip_axis = 0;
- }
- P->radius_g_1 = P->h / P->a;
- P->radius_g = 1. + P->radius_g_1;
- P->C = P->radius_g * P->radius_g - 1.0;
- if (P->es) {
- P->radius_p = sqrt (P->one_es);
- P->radius_p2 = P->one_es;
- P->radius_p_inv2 = P->rone_es;
- P->inv = e_inverse;
- P->fwd = e_forward;
- } else {
- P->radius_p = P->radius_p2 = P->radius_p_inv2 = 1.0;
- P->inv = s_inverse;
- P->fwd = s_forward;
- }
-ENDENTRY(P)
+ Q->flip_axis = 0;
+ }
+
+ Q->radius_g_1 = Q->h / P->a;
+ Q->radius_g = 1. + Q->radius_g_1;
+ Q->C = Q->radius_g * Q->radius_g - 1.0;
+ if (P->es) {
+ Q->radius_p = sqrt (P->one_es);
+ Q->radius_p2 = P->one_es;
+ Q->radius_p_inv2 = P->rone_es;
+ P->inv = e_inverse;
+ P->fwd = e_forward;
+ } else {
+ Q->radius_p = Q->radius_p2 = Q->radius_p_inv2 = 1.0;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+ }
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_geos_selftest (void) {return 0;}
+#else
+
+int pj_geos_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=geos +ellps=GRS80 +lat_1=0.5 +lat_2=2 +h=35785831"};
+ char s_args[] = {"+proj=geos +a=6400000 +lat_1=0.5 +lat_2=2 +h=35785831"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ { 222527.07036580026, 110551.30341332949},
+ { 222527.07036580026, -110551.30341332949},
+ {-222527.07036580026, 110551.30341332949},
+ {-222527.07036580026, -110551.30341332949},
+ };
+
+ XY s_fwd_expect[] = {
+ { 223289.45763579503, 111677.65745653701},
+ { 223289.45763579503, -111677.65745653701},
+ {-223289.45763579503, 111677.65745653701},
+ {-223289.45763579503, -111677.65745653701},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ { 0.0017966305689715385, 0.00090436947723267452},
+ { 0.0017966305689715385, -0.00090436947723267452},
+ {-0.0017966305689715385, 0.00090436947723267452},
+ {-0.0017966305689715385, -0.00090436947723267452},
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0017904931105078943, 0.00089524655504237148},
+ { 0.0017904931105078943, -0.00089524655504237148},
+ {-0.0017904931105078943, 0.00089524655504237148},
+ {-0.0017904931105078943, -0.00089524655504237148},
+ };
+
+ 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_gins8.c b/src/PJ_gins8.c
index b7f38ad9..3eae7efa 100644
--- a/src/PJ_gins8.c
+++ b/src/PJ_gins8.c
@@ -1,18 +1,75 @@
#define PJ_LIB__
-# include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(gins8, "Ginsburg VIII (TsNIIGAiK)") "\n\tPCyl, Sph., no inv.";
-#define Cl 0.000952426
-#define Cp 0.162388
-#define C12 0.08333333333333333
-FORWARD(s_forward); /* spheroid */
- double t = lp.phi * lp.phi;
- (void) P;
-
- xy.y = lp.phi * (1. + t * C12);
- xy.x = lp.lam * (1. - Cp * t);
- t = lp.lam * lp.lam;
- xy.x *= (0.87 - Cl * t * t);
- return (xy);
+
+#define Cl 0.000952426
+#define Cp 0.162388
+#define C12 0.08333333333333333
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ double t = lp.phi * lp.phi;
+ (void) P;
+
+ xy.y = lp.phi * (1. + t * C12);
+ xy.x = lp.lam * (1. - Cp * t);
+ t = lp.lam * lp.lam;
+ xy.x *= (0.87 - Cl * t * t);
+
+ return xy;
+}
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+
+ return pj_dealloc(P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(gins8) {
+ P->es = 0.0;
+ P->inv = 0;
+ P->fwd = s_forward;
+
+ return P;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(gins8) P->es = 0.; P->inv = 0; P->fwd = s_forward; ENDENTRY(P)
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_gins8_selftest (void) {return 0;}
+#else
+
+int pj_gins8_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=gins8 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 194350.25093959007, 111703.90763533533},
+ { 194350.25093959007, -111703.90763533533},
+ {-194350.25093959007, 111703.90763533533},
+ {-194350.25093959007, -111703.90763533533},
+ };
+
+ return pj_generic_selftest (0, s_args, tolerance_xy, tolerance_lp, 4, 4, fwd_in, 0, s_fwd_expect, 0, 0, 0);
+}
+
+
+#endif
diff --git a/src/PJ_gn_sinu.c b/src/PJ_gn_sinu.c
index bfd8bc2d..4b33b185 100644
--- a/src/PJ_gn_sinu.c
+++ b/src/PJ_gn_sinu.c
@@ -1,98 +1,373 @@
-#define PROJ_PARMS__ \
- double *en; \
- double m, n, C_x, C_y;
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(gn_sinu, "General Sinusoidal Series") "\n\tPCyl, Sph.\n\tm= n=";
PROJ_HEAD(sinu, "Sinusoidal (Sanson-Flamsteed)") "\n\tPCyl, Sph&Ell";
PROJ_HEAD(eck6, "Eckert VI") "\n\tPCyl, Sph.";
PROJ_HEAD(mbtfps, "McBryde-Thomas Flat-Polar Sinusoidal") "\n\tPCyl, Sph.";
-#define EPS10 1e-10
+
+#define EPS10 1e-10
#define MAX_ITER 8
#define LOOP_TOL 1e-7
-/* Ellipsoidal Sinusoidal only */
-FORWARD(e_forward); /* ellipsoid */
- double s, c;
- xy.y = pj_mlfn(lp.phi, s = sin(lp.phi), c = cos(lp.phi), P->en);
- xy.x = lp.lam * c / sqrt(1. - P->es * s * s);
- return (xy);
+struct pj_opaque {
+ double *en;
+ double m, n, C_x, C_y;
+};
+
+
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
+ XY xy = {0.0,0.0};
+ double s, c;
+
+ xy.y = pj_mlfn(lp.phi, s = sin(lp.phi), c = cos(lp.phi), P->opaque->en);
+ xy.x = lp.lam * c / sqrt(1. - P->es * s * s);
+ return xy;
}
-INVERSE(e_inverse); /* ellipsoid */
- double s;
-
- if ((s = fabs(lp.phi = pj_inv_mlfn(P->ctx, xy.y, P->es, P->en))) < HALFPI) {
- s = sin(lp.phi);
- lp.lam = xy.x * sqrt(1. - P->es * s * s) / cos(lp.phi);
- } else if ((s - EPS10) < HALFPI)
- lp.lam = 0.;
- else I_ERROR;
- return (lp);
+
+
+static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */
+ LP lp = {0.0,0.0};
+ double s;
+
+ if ((s = fabs(lp.phi = pj_inv_mlfn(P->ctx, xy.y, P->es, P->opaque->en))) < HALFPI) {
+ s = sin(lp.phi);
+ lp.lam = xy.x * sqrt(1. - P->es * s * s) / cos(lp.phi);
+ } else if ((s - EPS10) < HALFPI) {
+ lp.lam = 0.;
+ } else {
+ I_ERROR;
+ }
+
+ return lp;
}
-/* General spherical sinusoidals */
-FORWARD(s_forward); /* sphere */
- if (!P->m)
- lp.phi = P->n != 1. ? aasin(P->ctx,P->n * sin(lp.phi)): lp.phi;
- else {
- double k, V;
- int i;
-
- k = P->n * sin(lp.phi);
- for (i = MAX_ITER; i ; --i) {
- lp.phi -= V = (P->m * lp.phi + sin(lp.phi) - k) /
- (P->m + cos(lp.phi));
- if (fabs(V) < LOOP_TOL)
- break;
- }
- if (!i)
- F_ERROR
- }
- xy.x = P->C_x * lp.lam * (P->m + cos(lp.phi));
- xy.y = P->C_y * lp.phi;
- return (xy);
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+
+ if (!Q->m)
+ lp.phi = Q->n != 1. ? aasin(P->ctx,Q->n * sin(lp.phi)): lp.phi;
+ else {
+ double k, V;
+ int i;
+
+ k = Q->n * sin(lp.phi);
+ for (i = MAX_ITER; i ; --i) {
+ lp.phi -= V = (Q->m * lp.phi + sin(lp.phi) - k) /
+ (Q->m + cos(lp.phi));
+ if (fabs(V) < LOOP_TOL)
+ break;
+ }
+ if (!i)
+ F_ERROR
+ }
+ xy.x = Q->C_x * lp.lam * (Q->m + cos(lp.phi));
+ xy.y = Q->C_y * lp.phi;
+
+ return xy;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+
+ xy.y /= Q->C_y;
+ lp.phi = Q->m ? aasin(P->ctx,(Q->m * xy.y + sin(xy.y)) / Q->n) :
+ ( Q->n != 1. ? aasin(P->ctx,sin(xy.y) / Q->n) : xy.y );
+ lp.lam = xy.x / (Q->C_x * (Q->m + 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);
+
+ if (P->opaque->en)
+ pj_dalloc(P->opaque->en);
+
+ pj_dealloc (P->opaque);
+ return pj_dealloc(P);
}
-INVERSE(s_inverse); /* sphere */
- xy.y /= P->C_y;
- lp.phi = P->m ? aasin(P->ctx,(P->m * xy.y + sin(xy.y)) / P->n) :
- ( P->n != 1. ? aasin(P->ctx,sin(xy.y) / P->n) : xy.y );
- lp.lam = xy.x / (P->C_x * (P->m + cos(xy.y)));
- return (lp);
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
}
-FREEUP; if (P) { if (P->en) pj_dalloc(P->en); pj_dalloc(P); } }
- static void /* for spheres, only */
-setup(PJ *P) {
- P->es = 0;
- P->C_x = (P->C_y = sqrt((P->m + 1.) / P->n))/(P->m + 1.);
- P->inv = s_inverse;
- P->fwd = s_forward;
+
+
+/* for spheres, only */
+static void setup(PJ *P) {
+ struct pj_opaque *Q = P->opaque;
+ P->es = 0;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ Q->C_x = (Q->C_y = sqrt((Q->m + 1.) / Q->n))/(Q->m + 1.);
+}
+
+
+PJ *PROJECTION(sinu) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ if (!(Q->en = pj_enfn(P->es)))
+ E_ERROR_0;
+
+ if (P->es) {
+ P->inv = e_inverse;
+ P->fwd = e_forward;
+ } else {
+ Q->n = 1.;
+ Q->m = 0.;
+ setup(P);
+ }
+ return P;
+}
+
+
+PJ *PROJECTION(eck6) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->m = 1.;
+ Q->n = 2.570796326794896619231321691;
+ setup(P);
+
+ return P;
+}
+
+
+PJ *PROJECTION(mbtfps) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->m = 0.5;
+ Q->n = 1.785398163397448309615660845;
+ setup(P);
+
+ return P;
+}
+
+
+PJ *PROJECTION(gn_sinu) {
+ 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 && pj_param(P->ctx, P->params, "tm").i) {
+ Q->n = pj_param(P->ctx, P->params, "dn").f;
+ Q->m = pj_param(P->ctx, P->params, "dm").f;
+ } else
+ E_ERROR(-99)
+
+ setup(P);
+
+ return P;
}
-ENTRY1(sinu, en)
- if (!(P->en = pj_enfn(P->es)))
- E_ERROR_0;
- if (P->es) {
- P->inv = e_inverse;
- P->fwd = e_forward;
- } else {
- P->n = 1.;
- P->m = 0.;
- setup(P);
- }
-ENDENTRY(P)
-ENTRY1(eck6, en)
- P->m = 1.;
- P->n = 2.570796326794896619231321691;
- setup(P);
-ENDENTRY(P)
-ENTRY1(mbtfps, en)
- P->m = 0.5;
- P->n = 1.785398163397448309615660845;
- setup(P);
-ENDENTRY(P)
-ENTRY1(gn_sinu, en)
- if (pj_param(P->ctx, P->params, "tn").i && pj_param(P->ctx, P->params, "tm").i) {
- P->n = pj_param(P->ctx, P->params, "dn").f;
- P->m = pj_param(P->ctx, P->params, "dm").f;
- } else
- E_ERROR(-99)
- setup(P);
-ENDENTRY(P)
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_sinu_selftest (void) {return 0;}
+#else
+
+int pj_sinu_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=sinu +ellps=GRS80 +lat_1=0.5 +lat_2=2"};
+ char s_args[] = {"+proj=sinu +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ { 222605.29953946592, 110574.38855415257},
+ { 222605.29953946592, -110574.38855415257},
+ {-222605.29953946592, 110574.38855415257},
+ {-222605.29953946592, -110574.38855415257},
+ };
+
+ XY s_fwd_expect[] = {
+ { 223368.11902663155, 111701.07212763709},
+ { 223368.11902663155, -111701.07212763709},
+ {-223368.11902663155, 111701.07212763709},
+ {-223368.11902663155, -111701.07212763709},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ { 0.0017966305684613522, 0.00090436947707945409},
+ { 0.0017966305684613522, -0.00090436947707945409},
+ {-0.0017966305684613522, 0.00090436947707945409},
+ {-0.0017966305684613522, -0.00090436947707945409},
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0017904931100023887, 0.00089524655489191132},
+ { 0.0017904931100023887, -0.00089524655489191132},
+ {-0.0017904931100023887, 0.00089524655489191132},
+ {-0.0017904931100023887, -0.00089524655489191132},
+ };
+
+ 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
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_eck6_selftest (void) {return 0;}
+#else
+
+int pj_eck6_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=eck6 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 197021.60562899226, 126640.42073317352},
+ { 197021.60562899226, -126640.42073317352},
+ {-197021.60562899226, 126640.42073317352},
+ {-197021.60562899226, -126640.42073317352},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.002029978749734037, 0.00078963032910382171},
+ { 0.002029978749734037, -0.00078963032910382171},
+ {-0.002029978749734037, 0.00078963032910382171},
+ {-0.002029978749734037, -0.00078963032910382171},
+ };
+
+ 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_mbtfps_selftest (void) {return 0;}
+#else
+
+int pj_mbtfps_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=mbtfps +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 204740.11747857218, 121864.72971934026},
+ { 204740.11747857218, -121864.72971934026},
+ {-204740.11747857218, 121864.72971934026},
+ {-204740.11747857218, -121864.72971934026},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0019534152166442065, 0.00082057965689633387},
+ { 0.0019534152166442065, -0.00082057965689633387},
+ {-0.0019534152166442065, 0.00082057965689633387},
+ {-0.0019534152166442065, -0.00082057965689633387},
+ };
+
+ 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_gn_sinu_selftest (void) {return 0;}
+#else
+
+int pj_gn_sinu_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=gn_sinu +a=6400000 +lat_1=0.5 +lat_2=2 +m=1 +n=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 223385.13250469571, 111698.23644718733},
+ { 223385.13250469571, -111698.23644718733},
+ {-223385.13250469571, 111698.23644718733},
+ {-223385.13250469571, -111698.23644718733},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0017904931098931057, 0.00089524655491012516},
+ { 0.0017904931098931057, -0.00089524655491012516},
+ {-0.0017904931098931057, 0.00089524655491012516},
+ {-0.0017904931098931057, -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
diff --git a/src/PJ_gnom.c b/src/PJ_gnom.c
index 11deb86c..151f718e 100644
--- a/src/PJ_gnom.c
+++ b/src/PJ_gnom.c
@@ -1,105 +1,192 @@
-#define PROJ_PARMS__ \
- double sinph0; \
- double cosph0; \
- int mode;
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(gnom, "Gnomonic") "\n\tAzi, Sph.";
-#define EPS10 1.e-10
-#define N_POLE 0
+
+#define EPS10 1.e-10
+#define N_POLE 0
#define S_POLE 1
-#define EQUIT 2
-#define OBLIQ 3
-FORWARD(s_forward); /* spheroid */
- double coslam, cosphi, sinphi;
-
- sinphi = sin(lp.phi);
- cosphi = cos(lp.phi);
- coslam = cos(lp.lam);
- switch (P->mode) {
- case EQUIT:
- xy.y = cosphi * coslam;
- break;
- case OBLIQ:
- xy.y = P->sinph0 * sinphi + P->cosph0 * cosphi * coslam;
- break;
- case S_POLE:
- xy.y = - sinphi;
- break;
- case N_POLE:
- xy.y = sinphi;
- break;
- }
- if (xy.y <= EPS10) F_ERROR;
- xy.x = (xy.y = 1. / xy.y) * cosphi * sin(lp.lam);
- switch (P->mode) {
- case EQUIT:
- xy.y *= sinphi;
- break;
- case OBLIQ:
- xy.y *= P->cosph0 * sinphi - P->sinph0 * cosphi * coslam;
- break;
- case N_POLE:
- coslam = - coslam;
- case S_POLE:
- xy.y *= cosphi * coslam;
- break;
- }
- return (xy);
+#define EQUIT 2
+#define OBLIQ 3
+
+struct pj_opaque {
+ double sinph0;
+ double cosph0;
+ int mode;
+};
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double coslam, cosphi, sinphi;
+
+ sinphi = sin(lp.phi);
+ cosphi = cos(lp.phi);
+ coslam = cos(lp.lam);
+
+ switch (Q->mode) {
+ case EQUIT:
+ xy.y = cosphi * coslam;
+ break;
+ case OBLIQ:
+ xy.y = Q->sinph0 * sinphi + Q->cosph0 * cosphi * coslam;
+ break;
+ case S_POLE:
+ xy.y = - sinphi;
+ break;
+ case N_POLE:
+ xy.y = sinphi;
+ break;
+ }
+
+ if (xy.y <= EPS10) F_ERROR;
+
+ xy.x = (xy.y = 1. / xy.y) * cosphi * sin(lp.lam);
+ switch (Q->mode) {
+ case EQUIT:
+ xy.y *= sinphi;
+ break;
+ case OBLIQ:
+ xy.y *= Q->cosph0 * sinphi - Q->sinph0 * cosphi * coslam;
+ break;
+ case N_POLE:
+ coslam = - coslam;
+ case S_POLE:
+ xy.y *= cosphi * coslam;
+ break;
+ }
+ return xy;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double rh, cosz, sinz;
+
+ rh = hypot(xy.x, xy.y);
+ sinz = sin(lp.phi = atan(rh));
+ cosz = sqrt(1. - sinz * sinz);
+
+ if (fabs(rh) <= EPS10) {
+ lp.phi = P->phi0;
+ lp.lam = 0.;
+ } else {
+ switch (Q->mode) {
+ case OBLIQ:
+ lp.phi = cosz * Q->sinph0 + xy.y * sinz * Q->cosph0 / rh;
+ if (fabs(lp.phi) >= 1.)
+ lp.phi = lp.phi > 0. ? HALFPI : - HALFPI;
+ else
+ lp.phi = asin(lp.phi);
+ xy.y = (cosz - Q->sinph0 * sin(lp.phi)) * rh;
+ xy.x *= sinz * Q->cosph0;
+ break;
+ case EQUIT:
+ lp.phi = xy.y * sinz / rh;
+ if (fabs(lp.phi) >= 1.)
+ lp.phi = lp.phi > 0. ? HALFPI : - HALFPI;
+ else
+ lp.phi = asin(lp.phi);
+ xy.y = cosz * rh;
+ xy.x *= sinz;
+ break;
+ case S_POLE:
+ lp.phi -= HALFPI;
+ break;
+ case N_POLE:
+ lp.phi = HALFPI - lp.phi;
+ xy.y = -xy.y;
+ break;
+ }
+ lp.lam = atan2(xy.x, 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;
}
-INVERSE(s_inverse); /* spheroid */
- double rh, cosz, sinz;
-
- rh = hypot(xy.x, xy.y);
- sinz = sin(lp.phi = atan(rh));
- cosz = sqrt(1. - sinz * sinz);
- if (fabs(rh) <= EPS10) {
- lp.phi = P->phi0;
- lp.lam = 0.;
- } else {
- switch (P->mode) {
- case OBLIQ:
- lp.phi = cosz * P->sinph0 + xy.y * sinz * P->cosph0 / rh;
- if (fabs(lp.phi) >= 1.)
- lp.phi = lp.phi > 0. ? HALFPI : - HALFPI;
- else
- lp.phi = asin(lp.phi);
- xy.y = (cosz - P->sinph0 * sin(lp.phi)) * rh;
- xy.x *= sinz * P->cosph0;
- break;
- case EQUIT:
- lp.phi = xy.y * sinz / rh;
- if (fabs(lp.phi) >= 1.)
- lp.phi = lp.phi > 0. ? HALFPI : - HALFPI;
- else
- lp.phi = asin(lp.phi);
- xy.y = cosz * rh;
- xy.x *= sinz;
- break;
- case S_POLE:
- lp.phi -= HALFPI;
- break;
- case N_POLE:
- lp.phi = HALFPI - lp.phi;
- xy.y = -xy.y;
- break;
- }
- lp.lam = atan2(xy.x, xy.y);
- }
- return (lp);
+
+
+PJ *PROJECTION(gnom) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ if (fabs(fabs(P->phi0) - HALFPI) < EPS10) {
+ Q->mode = P->phi0 < 0. ? S_POLE : N_POLE;
+ } else if (fabs(P->phi0) < EPS10) {
+ Q->mode = EQUIT;
+ } else {
+ Q->mode = OBLIQ;
+ Q->sinph0 = sin(P->phi0);
+ Q->cosph0 = cos(P->phi0);
+ }
+
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+ P->es = 0.;
+
+ return P;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(gnom)
- if (fabs(fabs(P->phi0) - HALFPI) < EPS10)
- P->mode = P->phi0 < 0. ? S_POLE : N_POLE;
- else if (fabs(P->phi0) < EPS10)
- P->mode = EQUIT;
- else {
- P->mode = OBLIQ;
- P->sinph0 = sin(P->phi0);
- P->cosph0 = cos(P->phi0);
- }
- P->inv = s_inverse;
- P->fwd = s_forward;
- P->es = 0.;
-ENDENTRY(P)
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_gnom_selftest (void) {return 0;}
+#else
+
+int pj_gnom_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=gnom +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 223492.92474718543, 111780.50920659291},
+ { 223492.92474718543, -111780.50920659291},
+ {-223492.92474718543, 111780.50920659291},
+ {-223492.92474718543, -111780.50920659291},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0017904931092009798, 0.00089524655438192376},
+ { 0.0017904931092009798, -0.00089524655438192376},
+ {-0.0017904931092009798, 0.00089524655438192376},
+ {-0.0017904931092009798, -0.00089524655438192376},
+ };
+
+ 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_goode.c b/src/PJ_goode.c
index 387557e6..48fc9ad5 100644
--- a/src/PJ_goode.c
+++ b/src/PJ_goode.c
@@ -1,49 +1,122 @@
-#define PROJ_PARMS__ \
- struct PJconsts *sinu; \
- struct PJconsts *moll;
-#define PJ_LIB__
-#include <projects.h>
-PROJ_HEAD(goode, "Goode Homolosine") "\n\tPCyl, Sph.";
- C_NAMESPACE PJ
-*pj_sinu(PJ *), *pj_moll(PJ *);
-#define Y_COR 0.05280
-#define PHI_LIM .71093078197902358062
-FORWARD(s_forward); /* spheroid */
- if (fabs(lp.phi) <= PHI_LIM)
- xy = P->sinu->fwd(lp, P->sinu);
- else {
- xy = P->moll->fwd(lp, P->moll);
- xy.y -= lp.phi >= 0.0 ? Y_COR : -Y_COR;
- }
- return (xy);
-}
-INVERSE(s_inverse); /* spheroid */
- if (fabs(xy.y) <= PHI_LIM)
- lp = P->sinu->inv(xy, P->sinu);
- else {
- xy.y += xy.y >= 0.0 ? Y_COR : -Y_COR;
- lp = P->moll->inv(xy, P->moll);
- }
- return (lp);
-}
-FREEUP;
- if (P) {
- if (P->sinu)
- (*(P->sinu->pfree))(P->sinu);
- if (P->moll)
- (*(P->moll->pfree))(P->moll);
- pj_dalloc(P);
- }
-}
-ENTRY2(goode, sinu, moll)
- P->es = 0.;
- if (!(P->sinu = pj_sinu(0)) || !(P->moll = pj_moll(0)))
- E_ERROR_0;
- P->sinu->es = 0.;
- P->sinu->ctx = P->ctx;
- P->moll->ctx = P->ctx;
- if (!(P->sinu = pj_sinu(P->sinu)) || !(P->moll = pj_moll(P->moll)))
- E_ERROR_0;
- P->fwd = s_forward;
- P->inv = s_inverse;
-ENDENTRY(P)
+#define PJ_LIB__
+#include <projects.h>
+
+PROJ_HEAD(goode, "Goode Homolosine") "\n\tPCyl, Sph.";
+
+#define Y_COR 0.05280
+#define PHI_LIM 0.71093078197902358062
+
+C_NAMESPACE PJ *pj_sinu(PJ *), *pj_moll(PJ *);
+
+struct pj_opaque {
+ PJ *sinu;
+ PJ *moll;
+};
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+
+ if (fabs(lp.phi) <= PHI_LIM)
+ xy = Q->sinu->fwd(lp, Q->sinu);
+ else {
+ xy = Q->moll->fwd(lp, Q->moll);
+ xy.y -= lp.phi >= 0.0 ? Y_COR : -Y_COR;
+ }
+ return xy;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+
+ if (fabs(xy.y) <= PHI_LIM)
+ lp = Q->sinu->inv(xy, Q->sinu);
+ else {
+ xy.y += xy.y >= 0.0 ? Y_COR : -Y_COR;
+ lp = Q->moll->inv(xy, Q->moll);
+ }
+ return lp;
+}
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+ if (0==P->opaque)
+ return pj_dealloc(P);
+ if (P->opaque->sinu)
+ pj_dealloc(P->opaque->sinu);
+ if (P->opaque->moll)
+ pj_dealloc(P->opaque->moll);
+ pj_dealloc (P->opaque);
+ return pj_dealloc(P);
+
+}
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(goode) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ P->es = 0.;
+ if (!(Q->sinu = pj_sinu(0)) || !(Q->moll = pj_moll(0)))
+ E_ERROR_0;
+ Q->sinu->es = 0.;
+ Q->sinu->ctx = P->ctx;
+ Q->moll->ctx = P->ctx;
+ if (!(Q->sinu = pj_sinu(Q->sinu)) || !(Q->moll = pj_moll(Q->moll)))
+ E_ERROR_0;
+
+ P->fwd = s_forward;
+ P->inv = s_inverse;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_goode_selftest (void) {return 0;}
+#else
+
+int pj_goode_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=goode +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 223368.11902663155, 111701.07212763709}, { 223368.11902663155, -111701.07212763709}, {-223368.11902663155, 111701.07212763709}, {-223368.11902663155, -111701.07212763709}, };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0017904931100023887, 0.00089524655489191132}, { 0.0017904931100023887, -0.00089524655489191132}, {-0.0017904931100023887, 0.00089524655489191132}, {-0.0017904931100023887, -0.00089524655489191132}, };
+
+ 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_gstmerc.c b/src/PJ_gstmerc.c
index bffe0b26..2720c945 100644
--- a/src/PJ_gstmerc.c
+++ b/src/PJ_gstmerc.c
@@ -1,48 +1,131 @@
-#define PROJ_PARMS__ \
- double lamc;\
- double phic;\
- double c;\
- double n1;\
- double n2;\
- double XS;\
- double YS;
-
#define PJ_LIB__
-# include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(gstmerc, "Gauss-Schreiber Transverse Mercator (aka Gauss-Laborde Reunion)")
- "\n\tCyl, Sph&Ell\n\tlat_0= lon_0= k_0=";
-FORWARD(s_forward); /* spheroid */
- double L, Ls, sinLs1, Ls1;
- L= P->n1*lp.lam;
- Ls= P->c+P->n1*log(pj_tsfn(-1.0*lp.phi,-1.0*sin(lp.phi),P->e));
- sinLs1= sin(L)/cosh(Ls);
- Ls1= log(pj_tsfn(-1.0*asin(sinLs1),0.0,0.0));
- xy.x= (P->XS + P->n2*Ls1)*P->ra;
- xy.y= (P->YS + P->n2*atan(sinh(Ls)/cos(L)))*P->ra;
- /*fprintf(stderr,"fwd:\nL =%16.13f\nLs =%16.13f\nLs1 =%16.13f\nLP(%16.13f,%16.13f)=XY(%16.4f,%16.4f)\n",L,Ls,Ls1,lp.lam+P->lam0,lp.phi,(xy.x*P->a + P->x0)*P->to_meter,(xy.y*P->a + P->y0)*P->to_meter);*/
- return (xy);
+ "\n\tCyl, Sph&Ell\n\tlat_0= lon_0= k_0=";
+
+struct pj_opaque {
+ double lamc;
+ double phic;
+ double c;
+ double n1;
+ double n2;
+ double XS;
+ double YS;
+};
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double L, Ls, sinLs1, Ls1;
+
+ L = Q->n1*lp.lam;
+ Ls = Q->c + Q->n1 * log(pj_tsfn(-1.0 * lp.phi, -1.0 * sin(lp.phi), P->e));
+ sinLs1 = sin(L) / cosh(Ls);
+ Ls1 = log(pj_tsfn(-1.0 * asin(sinLs1), 0.0, 0.0));
+ xy.x = (Q->XS + Q->n2*Ls1) * P->ra;
+ xy.y = (Q->YS + Q->n2*atan(sinh(Ls) / cos(L))) * P->ra;
+
+ return xy;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double L, LC, sinC;
+
+ L = atan(sinh((xy.x * P->a - Q->XS) / Q->n2) / cos((xy.y * P->a - Q->YS) / Q->n2));
+ sinC = sin((xy.y * P->a - Q->YS) / Q->n2) / cosh((xy.x * P->a - Q->XS) / Q->n2);
+ LC = log(pj_tsfn(-1.0 * asin(sinC), 0.0, 0.0));
+ lp.lam = L / Q->n1;
+ lp.phi = -1.0 * pj_phi2(P->ctx, exp((LC - Q->c) / Q->n1), P->e);
+
+ 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);
}
-INVERSE(s_inverse); /* spheroid */
- double L, LC, sinC;
- L= atan(sinh((xy.x*P->a - P->XS)/P->n2)/cos((xy.y*P->a - P->YS)/P->n2));
- sinC= sin((xy.y*P->a - P->YS)/P->n2)/cosh((xy.x*P->a - P->XS)/P->n2);
- LC= log(pj_tsfn(-1.0*asin(sinC),0.0,0.0));
- lp.lam= L/P->n1;
- lp.phi= -1.0*pj_phi2(P->ctx, exp((LC-P->c)/P->n1),P->e);
- /*fprintf(stderr,"inv:\nL =%16.13f\nsinC =%16.13f\nLC =%16.13f\nXY(%16.4f,%16.4f)=LP(%16.13f,%16.13f)\n",L,sinC,LC,((xy.x/P->ra)+P->x0)/P->to_meter,((xy.y/P->ra)+P->y0)/P->to_meter,lp.lam+P->lam0,lp.phi);*/
- return (lp);
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(gstmerc)
- P->lamc= P->lam0;
- P->n1= sqrt(1.0+P->es*pow(cos(P->phi0),4.0)/(1.0-P->es));
- P->phic= asin(sin(P->phi0)/P->n1);
- P->c= log(pj_tsfn(-1.0*P->phic,0.0,0.0))
- -P->n1*log(pj_tsfn(-1.0*P->phi0,-1.0*sin(P->phi0),P->e));
- P->n2= P->k0*P->a*sqrt(1.0-P->es)/(1.0-P->es*sin(P->phi0)*sin(P->phi0));
- P->XS= 0;/* -P->x0 */
- P->YS= -1.0*P->n2*P->phic;/* -P->y0 */
- P->inv= s_inverse;
- P->fwd= s_forward;
- /*fprintf(stderr,"a (m) =%16.4f\ne =%16.13f\nl0(rad)=%16.13f\np0(rad)=%16.13f\nk0 =%16.4f\nX0 (m)=%16.4f\nY0 (m)=%16.4f\n\nlC(rad)=%16.13f\npC(rad)=%16.13f\nc =%16.13f\nn1 =%16.13f\nn2 (m) =%16.4f\nXS (m) =%16.4f\nYS (m) =%16.4f\n", P->a, P->e, P->lam0, P->phi0, P->k0, P->x0, P->y0, P->lamc, P->phic, P->c, P->n1, P->n2, P->XS +P->x0, P->YS + P->y0);*/
-ENDENTRY(P)
+
+
+PJ *PROJECTION(gstmerc) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->lamc = P->lam0;
+ Q->n1 = sqrt(1.0 + P->es * pow(cos(P->phi0), 4.0) / (1.0 - P->es));
+ Q->phic = asin(sin(P->phi0) / Q->n1);
+ Q->c = log(pj_tsfn(-1.0 * Q->phic, 0.0, 0.0))
+ - Q->n1 * log(pj_tsfn(-1.0 * P->phi0, -1.0 * sin(P->phi0), P->e));
+ Q->n2 = P->k0 * P->a * sqrt(1.0 - P->es) / (1.0 - P->es * sin(P->phi0) * sin(P->phi0));
+ Q->XS = 0;
+ Q->YS = -1.0 * Q->n2 * Q->phic;
+
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_gstmerc_selftest (void) {return 0;}
+#else
+
+int pj_gstmerc_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=gstmerc +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+
+ XY s_fwd_expect[] = {
+ { 223413.46640632182, 111769.14504058557},
+ { 223413.46640632182, -111769.14504058668},
+ {-223413.46640632302, 111769.14504058557},
+ {-223413.46640632302, -111769.14504058668},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0017904931097109673, 0.0008952465544509083},
+ { 0.0017904931097109673, -0.0008952465544509083},
+ {-0.0017904931097109673, 0.0008952465544509083},
+ {-0.0017904931097109673, -0.0008952465544509083},
+ };
+
+ 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_hammer.c b/src/PJ_hammer.c
index 31e7a127..3118640b 100644
--- a/src/PJ_hammer.c
+++ b/src/PJ_hammer.c
@@ -1,43 +1,129 @@
-#define PROJ_PARMS__ \
- double w; \
- double m, rm;
#define PJ_LIB__
-#define EPS 1.0e-10
-# include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(hammer, "Hammer & Eckert-Greifendorff")
- "\n\tMisc Sph, \n\tW= M=";
-FORWARD(s_forward); /* spheroid */
- double cosphi, d;
-
- d = sqrt(2./(1. + (cosphi = cos(lp.phi)) * cos(lp.lam *= P->w)));
- xy.x = P->m * d * cosphi * sin(lp.lam);
- xy.y = P->rm * d * sin(lp.phi);
- return (xy);
+ "\n\tMisc Sph, \n\tW= M=";
+
+#define EPS 1.0e-10
+
+struct pj_opaque {
+ double w; \
+ double m, rm;
+};
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double cosphi, d;
+
+ d = sqrt(2./(1. + (cosphi = cos(lp.phi)) * cos(lp.lam *= Q->w)));
+ xy.x = Q->m * d * cosphi * sin(lp.lam);
+ xy.y = Q->rm * d * sin(lp.phi);
+ return xy;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double z;
+
+ z = sqrt(1. - 0.25*Q->w*Q->w*xy.x*xy.x - 0.25*xy.y*xy.y);
+ if (fabs(2.*z*z-1.) < EPS) {
+ lp.lam = HUGE_VAL;
+ lp.phi = HUGE_VAL;
+ pj_errno = -14;
+ } else {
+ lp.lam = aatan2(Q->w * xy.x * z,2. * z * z - 1)/Q->w;
+ lp.phi = aasin(P->ctx,z * 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;
}
-INVERSE(s_inverse); /* spheroid */
- double z;
- z = sqrt(1. - 0.25*P->w*P->w*xy.x*xy.x - 0.25*xy.y*xy.y);
- if (fabs(2.*z*z-1.) < EPS) {
- lp.lam = HUGE_VAL;
- lp.phi = HUGE_VAL;
- pj_errno = -14;
- } else {
- lp.lam = aatan2(P->w * xy.x * z,2. * z * z - 1)/P->w;
- lp.phi = aasin(P->ctx,z * xy.y);
- }
- return (lp);
+
+
+PJ *PROJECTION(hammer) {
+ 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, "tW").i) {
+ if ((Q->w = fabs(pj_param(P->ctx, P->params, "dW").f)) <= 0.) E_ERROR(-27);
+ } else
+ Q->w = .5;
+ if (pj_param(P->ctx, P->params, "tM").i) {
+ if ((Q->m = fabs(pj_param(P->ctx, P->params, "dM").f)) <= 0.) E_ERROR(-27);
+ } else
+ Q->m = 1.;
+
+ Q->rm = 1. / Q->m;
+ Q->m /= Q->w;
+
+ P->es = 0.;
+ P->fwd = s_forward;
+ P->inv = s_inverse;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_hammer_selftest (void) {return 0;}
+#else
+
+int pj_hammer_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=hammer +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 223373.78870324057, 111703.90739776699},
+ { 223373.78870324057, -111703.90739776699},
+ {-223373.78870324057, 111703.90739776699},
+ {-223373.78870324057, -111703.90739776699},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.001790493109965961, 0.00089524655487369749},
+ { 0.001790493109965961, -0.00089524655487369749},
+ {-0.001790493109965961, 0.00089524655487369749},
+ {-0.001790493109965961, -0.00089524655487369749},
+ };
+
+ 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(hammer)
- if (pj_param(P->ctx, P->params, "tW").i) {
- if ((P->w = fabs(pj_param(P->ctx, P->params, "dW").f)) <= 0.) E_ERROR(-27);
- } else
- P->w = .5;
- if (pj_param(P->ctx, P->params, "tM").i) {
- if ((P->m = fabs(pj_param(P->ctx, P->params, "dM").f)) <= 0.) E_ERROR(-27);
- } else
- P->m = 1.;
- P->rm = 1. / P->m;
- P->m /= P->w;
- P->es = 0.; P->fwd = s_forward; P->inv = s_inverse;
-ENDENTRY(P)
+
+
+#endif
diff --git a/src/PJ_hatano.c b/src/PJ_hatano.c
index 7516ba6e..ca97849b 100644
--- a/src/PJ_hatano.c
+++ b/src/PJ_hatano.c
@@ -1,51 +1,134 @@
-#define PJ_LIB__
-#include <projects.h>
-PROJ_HEAD(hatano, "Hatano Asymmetrical Equal Area") "\n\tPCyl, Sph.";
-#define NITER 20
-#define EPS 1e-7
-#define ONETOL 1.000001
-#define CN 2.67595
-#define CS 2.43763
-#define RCN 0.37369906014686373063
-#define RCS 0.41023453108141924738
-#define FYCN 1.75859
-#define FYCS 1.93052
-#define RYCN 0.56863737426006061674
-#define RYCS 0.51799515156538134803
-#define FXC 0.85
-#define RXC 1.17647058823529411764
-FORWARD(s_forward); /* spheroid */
- double th1, c;
- int i;
- (void) P;
-
- c = sin(lp.phi) * (lp.phi < 0. ? CS : CN);
- for (i = NITER; i; --i) {
- lp.phi -= th1 = (lp.phi + sin(lp.phi) - c) / (1. + cos(lp.phi));
- if (fabs(th1) < EPS) break;
- }
- xy.x = FXC * lp.lam * cos(lp.phi *= .5);
- xy.y = sin(lp.phi) * (lp.phi < 0. ? FYCS : FYCN);
- return (xy);
-}
-INVERSE(s_inverse); /* spheroid */
- double th;
-
- th = xy.y * ( xy.y < 0. ? RYCS : RYCN);
- if (fabs(th) > 1.)
- if (fabs(th) > ONETOL) I_ERROR
- else th = th > 0. ? HALFPI : - HALFPI;
- else
- th = asin(th);
- lp.lam = RXC * xy.x / cos(th);
- th += th;
- lp.phi = (th + sin(th)) * (xy.y < 0. ? RCS : RCN);
- if (fabs(lp.phi) > 1.)
- if (fabs(lp.phi) > ONETOL) I_ERROR
- else lp.phi = lp.phi > 0. ? HALFPI : - HALFPI;
- else
- lp.phi = asin(lp.phi);
- return (lp);
-}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(hatano) P->es = 0.; P->inv = s_inverse; P->fwd = s_forward; ENDENTRY(P)
+#define PJ_LIB__
+#include <projects.h>
+
+PROJ_HEAD(hatano, "Hatano Asymmetrical Equal Area") "\n\tPCyl, Sph.";
+
+#define NITER 20
+#define EPS 1e-7
+#define ONETOL 1.000001
+#define CN 2.67595
+#define CS 2.43763
+#define RCN 0.37369906014686373063
+#define RCS 0.41023453108141924738
+#define FYCN 1.75859
+#define FYCS 1.93052
+#define RYCN 0.56863737426006061674
+#define RYCS 0.51799515156538134803
+#define FXC 0.85
+#define RXC 1.17647058823529411764
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ double th1, c;
+ int i;
+ (void) P;
+
+ c = sin(lp.phi) * (lp.phi < 0. ? CS : CN);
+ for (i = NITER; i; --i) {
+ lp.phi -= th1 = (lp.phi + sin(lp.phi) - c) / (1. + cos(lp.phi));
+ if (fabs(th1) < EPS) break;
+ }
+ xy.x = FXC * lp.lam * cos(lp.phi *= .5);
+ xy.y = sin(lp.phi) * (lp.phi < 0. ? FYCS : FYCN);
+
+ return xy;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ double th;
+
+ th = xy.y * ( xy.y < 0. ? RYCS : RYCN);
+ if (fabs(th) > 1.) {
+ if (fabs(th) > ONETOL) {
+ I_ERROR;
+ } else {
+ th = th > 0. ? HALFPI : - HALFPI;
+ }
+ } else {
+ th = asin(th);
+ }
+
+ lp.lam = RXC * xy.x / cos(th);
+ th += th;
+ lp.phi = (th + sin(th)) * (xy.y < 0. ? RCS : RCN);
+ if (fabs(lp.phi) > 1.) {
+ if (fabs(lp.phi) > ONETOL) {
+ I_ERROR;
+ } else {
+ lp.phi = lp.phi > 0. ? HALFPI : - HALFPI;
+ }
+ } else {
+ lp.phi = asin(lp.phi);
+ }
+
+ return (lp);
+}
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+
+ return pj_dealloc(P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(hatano) {
+ P->es = 0.;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_hatano_selftest (void) {return 0;}
+#else
+
+int pj_hatano_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=hatano +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 189878.87894652804, 131409.8024406255 },
+ { 189881.08195244463, -131409.14227607418 },
+ {-189878.87894652804, 131409.8024406255 },
+ {-189881.08195244463, -131409.14227607418 },
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0021064624821817597, 0.00076095689425791926 },
+ { 0.0021064624821676096, -0.00076095777439265377 },
+ {-0.0021064624821817597, 0.00076095689425791926 },
+ {-0.0021064624821676096, -0.00076095777439265377 },
+ };
+
+ 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_healpix.c b/src/PJ_healpix.c
index 12d57ff2..f6fe624b 100644
--- a/src/PJ_healpix.c
+++ b/src/PJ_healpix.c
@@ -2,10 +2,10 @@
* Project: PROJ.4
* Purpose: Implementation of the HEALPix and rHEALPix projections.
* For background see <http://code.scenzgrid.org/index.php/p/scenzgrid-py/source/tree/master/docs/rhealpix_dggs.pdf>.
- * Authors: Alex Raichev (raichev@cs.auckland.ac.nz)
+ * Authors: Alex Raichev (raichev@cs.auckland.ac.nz)
* Michael Speth (spethm@landcareresearch.co.nz)
- * Notes: Raichev implemented these projections in Python and
- * Speth translated them into C here.
+ * Notes: Raichev implemented these projections in Python and
+ * Speth translated them into C here.
******************************************************************************
* Copyright (c) 2001, Thomas Flemming, tf@ttqv.com
*
@@ -28,38 +28,46 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*****************************************************************************/
-# define PROJ_PARMS__ \
- int north_square; \
- int south_square; \
- double qp; \
- double *apa;
-# define PJ_LIB__
-# include <projects.h>
+# define PJ_LIB__
+# include <projects.h>
+
PROJ_HEAD(healpix, "HEALPix") "\n\tSph., Ellps.";
PROJ_HEAD(rhealpix, "rHEALPix") "\n\tSph., Ellps.\n\tnorth_square= south_square=";
-# include <stdio.h>
+
+# include <stdio.h>
/* Matrix for counterclockwise rotation by pi/2: */
-# define R1 {{ 0,-1},{ 1, 0}}
+# define R1 {{ 0,-1},{ 1, 0}}
/* Matrix for counterclockwise rotation by pi: */
-# define R2 {{-1, 0},{ 0,-1}}
+# define R2 {{-1, 0},{ 0,-1}}
/* Matrix for counterclockwise rotation by 3*pi/2: */
-# define R3 {{ 0, 1},{-1, 0}}
+# define R3 {{ 0, 1},{-1, 0}}
/* Identity matrix */
# define IDENT {{1, 0},{0, 1}}
/* IDENT, R1, R2, R3, R1 inverse, R2 inverse, R3 inverse:*/
# define ROT {IDENT, R1, R2, R3, R3, R2, R1}
/* Fuzz to handle rounding errors: */
# define EPS 1e-15
+
+struct pj_opaque {
+ int north_square; \
+ int south_square; \
+ double qp; \
+ double *apa;
+};
+
typedef struct {
int cn; /* An integer 0--3 indicating the position of the polar cap. */
double x, y; /* Coordinates of the pole point (point of most extreme latitude on the polar caps). */
enum Region {north, south, equatorial} region;
} CapMap;
+
typedef struct {
double x, y;
} Point;
+
double rot[7][2][2] = ROT;
+
/**
* Returns the sign of the double.
* @param v the parameter whose sign is returned.
@@ -68,31 +76,35 @@ double rot[7][2][2] = ROT;
double pj_sign (double v) {
return v > 0 ? 1 : (v < 0 ? -1 : 0);
}
+
+
/**
* Return the index of the matrix in ROT.
* @param index ranges from -3 to 3.
*/
static int get_rotate_index(int index) {
switch(index) {
- case 0:
- return 0;
- case 1:
- return 1;
- case 2:
- return 2;
- case 3:
- return 3;
- case -1:
- return 4;
- case -2:
- return 5;
- case -3:
- return 6;
+ case 0:
+ return 0;
+ case 1:
+ return 1;
+ case 2:
+ return 2;
+ case 3:
+ return 3;
+ case -1:
+ return 4;
+ case -2:
+ return 5;
+ case -3:
+ return 6;
}
return 0;
}
+
+
/**
- * Return 1 if point (testx, testy) lies in the interior of the polygon
+ * Return 1 if point (testx, testy) lies in the interior of the polygon
* determined by the vertices in vert, and return 0 otherwise.
* See http://paulbourke.net/geometry/polygonmesh/ for more details.
* @param nvert the number of vertices in the polygon.
@@ -103,6 +115,7 @@ static int pnpoly(int nvert, double vert[][2], double testx, double testy) {
int counter = 0;
double xinters;
Point p1, p2;
+
/* Check for boundrary cases */
for (i = 0; i < nvert; i++) {
if (testx == vert[i][0] && testy == vert[i][1]) {
@@ -135,76 +148,84 @@ static int pnpoly(int nvert, double vert[][2], double testx, double testy) {
}
return c;
}
+
+
/**
* Return 1 if (x, y) lies in (the interior or boundary of) the image of the
- * HEALPix projection (in case proj=0) or in the image the rHEALPix projection
+ * HEALPix projection (in case proj=0) or in the image the rHEALPix projection
* (in case proj=1), and return 0 otherwise.
- * @param north_square the position of the north polar square (rHEALPix only)
- * @param south_square the position of the south polar square (rHEALPix only)
+ * @param north_square the position of the north polar square (rHEALPix only)
+ * @param south_square the position of the south polar square (rHEALPix only)
**/
int in_image(double x, double y, int proj, int north_square, int south_square) {
if (proj == 0) {
- double healpixVertsJit[][2] = {
- {-1.0*PI- EPS, PI/4.0},
- {-3.0*PI/4.0, PI/2.0 + EPS},
- {-1.0*PI/2.0, PI/4.0 + EPS},
- {-1.0*PI/4.0, PI/2.0 + EPS},
- {0.0, PI/4.0 + EPS},
- {PI/4.0, PI/2.0 + EPS},
- {PI/2.0, PI/4.0 + EPS},
- {3.0*PI/4.0, PI/2.0 + EPS},
- {PI+ EPS, PI/4.0},
- {PI+ EPS, -1.0*PI/4.0},
- {3.0*PI/4.0, -1.0*PI/2.0 - EPS},
- {PI/2.0, -1.0*PI/4.0 - EPS},
- {PI/4.0, -1.0*PI/2.0 - EPS},
- {0.0, -1.0*PI/4.0 - EPS},
- {-1.0*PI/4.0, -1.0*PI/2.0 - EPS},
- {-1.0*PI/2.0, -1.0*PI/4.0 - EPS},
- {-3.0*PI/4.0, -1.0*PI/2.0 - EPS},
- {-1.0*PI - EPS, -1.0*PI/4.0}
- };
- return pnpoly((int)sizeof(healpixVertsJit)/
- sizeof(healpixVertsJit[0]), healpixVertsJit, x, y);
+ double healpixVertsJit[][2] = {
+ {-1.0*PI- EPS, PI/4.0},
+ {-3.0*PI/4.0, PI/2.0 + EPS},
+ {-1.0*PI/2.0, PI/4.0 + EPS},
+ {-1.0*PI/4.0, PI/2.0 + EPS},
+ {0.0, PI/4.0 + EPS},
+ {PI/4.0, PI/2.0 + EPS},
+ {PI/2.0, PI/4.0 + EPS},
+ {3.0*PI/4.0, PI/2.0 + EPS},
+ {PI+ EPS, PI/4.0},
+ {PI+ EPS, -1.0*PI/4.0},
+ {3.0*PI/4.0, -1.0*PI/2.0 - EPS},
+ {PI/2.0, -1.0*PI/4.0 - EPS},
+ {PI/4.0, -1.0*PI/2.0 - EPS},
+ {0.0, -1.0*PI/4.0 - EPS},
+ {-1.0*PI/4.0, -1.0*PI/2.0 - EPS},
+ {-1.0*PI/2.0, -1.0*PI/4.0 - EPS},
+ {-3.0*PI/4.0, -1.0*PI/2.0 - EPS},
+ {-1.0*PI - EPS, -1.0*PI/4.0}
+ };
+ return pnpoly((int)sizeof(healpixVertsJit)/
+ sizeof(healpixVertsJit[0]), healpixVertsJit, x, y);
} else {
- double rhealpixVertsJit[][2] = {
- {-1.0*PI - EPS, PI/4.0 + EPS},
- {-1.0*PI + north_square*PI/2.0- EPS, PI/4.0 + EPS},
- {-1.0*PI + north_square*PI/2.0- EPS, 3*PI/4.0 + EPS},
- {-1.0*PI + (north_square + 1.0)*PI/2.0 + EPS, 3*PI/4.0 + EPS},
- {-1.0*PI + (north_square + 1.0)*PI/2.0 + EPS, PI/4.0 + EPS},
- {PI + EPS, PI/4.0 + EPS},
- {PI + EPS, -1.0*PI/4.0 - EPS},
- {-1.0*PI + (south_square + 1.0)*PI/2.0 + EPS, -1.0*PI/4.0 - EPS},
- {-1.0*PI + (south_square + 1.0)*PI/2.0 + EPS, -3.0*PI/4.0 - EPS},
- {-1.0*PI + south_square*PI/2.0 - EPS, -3.0*PI/4.0 - EPS},
- {-1.0*PI + south_square*PI/2.0 - EPS, -1.0*PI/4.0 - EPS},
- {-1.0*PI - EPS, -1.0*PI/4.0 - EPS}};
- return pnpoly((int)sizeof(rhealpixVertsJit)/
- sizeof(rhealpixVertsJit[0]), rhealpixVertsJit, x, y);
+ double rhealpixVertsJit[][2] = {
+ {-1.0*PI - EPS, PI/4.0 + EPS},
+ {-1.0*PI + north_square*PI/2.0- EPS, PI/4.0 + EPS},
+ {-1.0*PI + north_square*PI/2.0- EPS, 3*PI/4.0 + EPS},
+ {-1.0*PI + (north_square + 1.0)*PI/2.0 + EPS, 3*PI/4.0 + EPS},
+ {-1.0*PI + (north_square + 1.0)*PI/2.0 + EPS, PI/4.0 + EPS},
+ {PI + EPS, PI/4.0 + EPS},
+ {PI + EPS, -1.0*PI/4.0 - EPS},
+ {-1.0*PI + (south_square + 1.0)*PI/2.0 + EPS, -1.0*PI/4.0 - EPS},
+ {-1.0*PI + (south_square + 1.0)*PI/2.0 + EPS, -3.0*PI/4.0 - EPS},
+ {-1.0*PI + south_square*PI/2.0 - EPS, -3.0*PI/4.0 - EPS},
+ {-1.0*PI + south_square*PI/2.0 - EPS, -1.0*PI/4.0 - EPS},
+ {-1.0*PI - EPS, -1.0*PI/4.0 - EPS}};
+ return pnpoly((int)sizeof(rhealpixVertsJit)/
+ sizeof(rhealpixVertsJit[0]), rhealpixVertsJit, x, y);
}
}
+
+
/**
* Return the authalic latitude of latitude alpha (if inverse=0) or
- * return the approximate latitude of authalic latitude alpha (if inverse=1).
- * P contains the relavent ellipsoid parameters.
+ * return the approximate latitude of authalic latitude alpha (if inverse=1).
+ * P contains the relavent ellipsoid parameters.
**/
double auth_lat(PJ *P, double alpha, int inverse) {
+ struct pj_opaque *Q = P->opaque;
if (inverse == 0) {
/* Authalic latitude. */
double q = pj_qsfn(sin(alpha), P->e, 1.0 - P->es);
- double qp = P->qp;
- double ratio = q/qp;
- if (fabsl(ratio) > 1) {
- /* Rounding error. */
- ratio = pj_sign(ratio);
- }
- return asin(ratio);
+ double qp = Q->qp;
+ double ratio = q/qp;
+
+ if (fabsl(ratio) > 1) {
+ /* Rounding error. */
+ ratio = pj_sign(ratio);
+ }
+ return asin(ratio);
} else {
/* Approximation to inverse authalic latitude. */
- return pj_authlat(alpha, P->apa);
+ return pj_authlat(alpha, Q->apa);
}
}
+
+
/**
* Return the HEALPix projection of the longitude-latitude point lp on
* the unit sphere.
@@ -214,51 +235,57 @@ XY healpix_sphere(LP lp) {
double phi = lp.phi;
double phi0 = asin(2.0/3.0);
XY xy;
+
/* equatorial region */
if ( fabsl(phi) <= phi0) {
- xy.x = lam;
- xy.y = 3.0*PI/8.0*sin(phi);
+ xy.x = lam;
+ xy.y = 3.0*PI/8.0*sin(phi);
} else {
- double lamc;
- double sigma = sqrt(3.0*(1 - fabsl(sin(phi))));
- double cn = floor(2*lam / PI + 2);
- if (cn >= 4) {
- cn = 3;
- }
- lamc = -3*PI/4 + (PI/2)*cn;
- xy.x = lamc + (lam - lamc)*sigma;
- xy.y = pj_sign(phi)*PI/4*(2 - sigma);
+ double lamc;
+ double sigma = sqrt(3.0*(1 - fabsl(sin(phi))));
+ double cn = floor(2*lam / PI + 2);
+ if (cn >= 4) {
+ cn = 3;
+ }
+ lamc = -3*PI/4 + (PI/2)*cn;
+ xy.x = lamc + (lam - lamc)*sigma;
+ xy.y = pj_sign(phi)*PI/4*(2 - sigma);
}
return xy;
}
+
+
/**
- * Return the inverse of healpix_sphere().
+ * Return the inverse of healpix_sphere().
**/
LP healpix_sphere_inverse(XY xy) {
- LP lp;
+ LP lp;
double x = xy.x;
double y = xy.y;
double y0 = PI/4.0;
+
/* Equatorial region. */
if (fabsl(y) <= y0) {
- lp.lam = x;
- lp.phi = asin(8.0*y/(3.0*PI));
+ lp.lam = x;
+ lp.phi = asin(8.0*y/(3.0*PI));
} else if (fabsl(y) < PI/2.0) {
- double cn = floor(2.0*x/PI + 2.0);
+ double cn = floor(2.0*x/PI + 2.0);
double xc, tau;
- if (cn >= 4) {
- cn = 3;
- }
- xc = -3.0*PI/4.0 + (PI/2.0)*cn;
- tau = 2.0 - 4.0*fabsl(y)/PI;
- lp.lam = xc + (x - xc)/tau;
- lp.phi = pj_sign(y)*asin(1.0 - pow(tau , 2.0)/3.0);
+ if (cn >= 4) {
+ cn = 3;
+ }
+ xc = -3.0*PI/4.0 + (PI/2.0)*cn;
+ tau = 2.0 - 4.0*fabsl(y)/PI;
+ lp.lam = xc + (x - xc)/tau;
+ lp.phi = pj_sign(y)*asin(1.0 - pow(tau , 2.0)/3.0);
} else {
- lp.lam = -1.0*PI;
- lp.phi = pj_sign(y)*PI/2.0;
+ lp.lam = -1.0*PI;
+ lp.phi = pj_sign(y)*PI/2.0;
}
return (lp);
}
+
+
/**
* Return the vector sum a + b, where a and b are 2-dimensional vectors.
* @param ret holds a + b.
@@ -266,21 +293,25 @@ LP healpix_sphere_inverse(XY xy) {
static void vector_add(double a[2], double b[2], double *ret) {
int i;
for(i = 0; i < 2; i++) {
- ret[i] = a[i] + b[i];
+ ret[i] = a[i] + b[i];
}
}
+
+
/**
* Return the vector difference a - b, where a and b are 2-dimensional vectors.
* @param ret holds a - b.
**/
static void vector_sub(double a[2], double b[2], double*ret) {
int i;
- for(i = 0; i < 2; i++) {
- ret[i] = a[i] - b[i];
+ for(i = 0; i < 2; i++) {
+ ret[i] = a[i] - b[i];
}
}
+
+
/**
- * Return the 2 x 1 matrix product a*b, where a is a 2 x 2 matrix and
+ * Return the 2 x 1 matrix product a*b, where a is a 2 x 2 matrix and
* b is a 2 x 1 matrix.
* @param ret holds a*b.
**/
@@ -288,105 +319,110 @@ static void dot_product(double a[2][2], double b[2], double *ret) {
int i, j;
int length = 2;
for(i = 0; i < length; i++) {
- ret[i] = 0;
- for(j = 0; j < length; j++) {
- ret[i] += a[i][j]*b[j];
- }
+ ret[i] = 0;
+ for(j = 0; j < length; j++) {
+ ret[i] += a[i][j]*b[j];
+ }
}
}
+
+
/**
- * Return the number of the polar cap, the pole point coordinates, and
+ * Return the number of the polar cap, the pole point coordinates, and
* the region that (x, y) lies in.
- * If inverse=0, then assume (x,y) lies in the image of the HEALPix
+ * If inverse=0, then assume (x,y) lies in the image of the HEALPix
* projection of the unit sphere.
- * If inverse=1, then assume (x,y) lies in the image of the
+ * If inverse=1, then assume (x,y) lies in the image of the
* (north_square, south_square)-rHEALPix projection of the unit sphere.
**/
static CapMap get_cap(double x, double y, int north_square, int south_square,
int inverse) {
CapMap capmap;
double c;
+
capmap.x = x;
capmap.y = y;
if (inverse == 0) {
- if (y > PI/4.0) {
- capmap.region = north;
- c = PI/2.0;
- } else if (y < -1*PI/4.0) {
- capmap.region = south;
- c = -1*PI/2.0;
- } else {
- capmap.region = equatorial;
- capmap.cn = 0;
- return capmap;
- }
- /* polar region */
- if (x < -1*PI/2.0) {
- capmap.cn = 0;
- capmap.x = (-1*3.0*PI/4.0);
- capmap.y = c;
- } else if (x >= -1*PI/2.0 && x < 0) {
- capmap.cn = 1;
- capmap.x = -1*PI/4.0;
- capmap.y = c;
- } else if (x >= 0 && x < PI/2.0) {
- capmap.cn = 2;
- capmap.x = PI/4.0;
- capmap.y = c;
- } else {
- capmap.cn = 3;
- capmap.x = 3.0*PI/4.0;
- capmap.y = c;
- }
- return capmap;
+ if (y > PI/4.0) {
+ capmap.region = north;
+ c = PI/2.0;
+ } else if (y < -1*PI/4.0) {
+ capmap.region = south;
+ c = -1*PI/2.0;
+ } else {
+ capmap.region = equatorial;
+ capmap.cn = 0;
+ return capmap;
+ }
+ /* polar region */
+ if (x < -1*PI/2.0) {
+ capmap.cn = 0;
+ capmap.x = (-1*3.0*PI/4.0);
+ capmap.y = c;
+ } else if (x >= -1*PI/2.0 && x < 0) {
+ capmap.cn = 1;
+ capmap.x = -1*PI/4.0;
+ capmap.y = c;
+ } else if (x >= 0 && x < PI/2.0) {
+ capmap.cn = 2;
+ capmap.x = PI/4.0;
+ capmap.y = c;
+ } else {
+ capmap.cn = 3;
+ capmap.x = 3.0*PI/4.0;
+ capmap.y = c;
+ }
+ return capmap;
} else {
- double eps;
- if (y > PI/4.0) {
- capmap.region = north;
- capmap.x = (-3.0*PI/4.0 + north_square*PI/2.0);
- capmap.y = PI/2.0;
- x = x - north_square*PI/2.0;
- } else if (y < -1*PI/4.0) {
- capmap.region = south;
- capmap.x = (-3.0*PI/4.0 + south_square*PI/2);
- capmap.y = -1*PI/2.0;
- x = x - south_square*PI/2.0;
- } else {
- capmap.region = equatorial;
- capmap.cn = 0;
- return capmap;
- }
- /* Polar Region, find the HEALPix polar cap number that
- x, y moves to when rHEALPix polar square is disassembled. */
- eps = 1e-15; /* Kludge. Fuzz to avoid some rounding errors. */
- if (capmap.region == north) {
- if (y >= -1*x - PI/4.0 - eps && y < x + 5.0*PI/4.0 - eps) {
- capmap.cn = (north_square + 1) % 4;
- } else if (y > -1*x -1*PI/4.0 + eps && y >= x + 5.0*PI/4.0 - eps) {
- capmap.cn = (north_square + 2) % 4;
- } else if (y <= -1*x -1*PI/4.0 + eps && y > x + 5.0*PI/4.0 + eps) {
- capmap.cn = (north_square + 3) % 4;
- } else {
- capmap.cn = north_square;
- }
- } else if (capmap.region == south) {
- if (y <= x + PI/4.0 + eps && y > -1*x - 5.0*PI/4 + eps) {
- capmap.cn = (south_square + 1) % 4;
- } else if (y < x + PI/4.0 - eps && y <= -1*x - 5.0*PI/4.0 + eps) {
- capmap.cn = (south_square + 2) % 4;
- } else if (y >= x + PI/4.0 - eps && y < -1*x - 5.0*PI/4.0 - eps) {
- capmap.cn = (south_square + 3) % 4;
- } else {
- capmap.cn = south_square;
- }
- }
- return capmap;
+ double eps;
+ if (y > PI/4.0) {
+ capmap.region = north;
+ capmap.x = (-3.0*PI/4.0 + north_square*PI/2.0);
+ capmap.y = PI/2.0;
+ x = x - north_square*PI/2.0;
+ } else if (y < -1*PI/4.0) {
+ capmap.region = south;
+ capmap.x = (-3.0*PI/4.0 + south_square*PI/2);
+ capmap.y = -1*PI/2.0;
+ x = x - south_square*PI/2.0;
+ } else {
+ capmap.region = equatorial;
+ capmap.cn = 0;
+ return capmap;
+ }
+ /* Polar Region, find the HEALPix polar cap number that
+ x, y moves to when rHEALPix polar square is disassembled. */
+ eps = 1e-15; /* Kludge. Fuzz to avoid some rounding errors. */
+ if (capmap.region == north) {
+ if (y >= -1*x - PI/4.0 - eps && y < x + 5.0*PI/4.0 - eps) {
+ capmap.cn = (north_square + 1) % 4;
+ } else if (y > -1*x -1*PI/4.0 + eps && y >= x + 5.0*PI/4.0 - eps) {
+ capmap.cn = (north_square + 2) % 4;
+ } else if (y <= -1*x -1*PI/4.0 + eps && y > x + 5.0*PI/4.0 + eps) {
+ capmap.cn = (north_square + 3) % 4;
+ } else {
+ capmap.cn = north_square;
+ }
+ } else if (capmap.region == south) {
+ if (y <= x + PI/4.0 + eps && y > -1*x - 5.0*PI/4 + eps) {
+ capmap.cn = (south_square + 1) % 4;
+ } else if (y < x + PI/4.0 - eps && y <= -1*x - 5.0*PI/4.0 + eps) {
+ capmap.cn = (south_square + 2) % 4;
+ } else if (y >= x + PI/4.0 - eps && y < -1*x - 5.0*PI/4.0 - eps) {
+ capmap.cn = (south_square + 3) % 4;
+ } else {
+ capmap.cn = south_square;
+ }
+ }
+ return capmap;
}
}
+
+
/**
- * Rearrange point (x, y) in the HEALPix projection by
+ * Rearrange point (x, y) in the HEALPix projection by
* combining the polar caps into two polar squares.
- * Put the north polar square in position north_square and
+ * Put the north polar square in position north_square and
* the south polar square in position south_square.
* If inverse=1, then uncombine the polar caps.
* @param north_square integer between 0 and 3.
@@ -400,173 +436,352 @@ static XY combine_caps(double x, double y, int north_square, int south_square,
double vector[2];
double v_min_c[2];
double ret_dot[2];
+
CapMap capmap = get_cap(x, y, north_square, south_square, inverse);
if (capmap.region == equatorial) {
- xy.x = capmap.x;
- xy.y = capmap.y;
- return xy;
+ xy.x = capmap.x;
+ xy.y = capmap.y;
+ return xy;
}
v[0] = x;
v[1] = y;
if (inverse == 0) {
- /* Rotate (x, y) about its polar cap tip and then translate it to
+ /* Rotate (x, y) about its polar cap tip and then translate it to
north_square or south_square. */
- int pole = 0;
- double (*tmpRot)[2];
- double c[2] = {capmap.x, capmap.y};
- if (capmap.region == north) {
- pole = north_square;
- a[0] = (-3.0*PI/4.0 + pole*PI/2);
- a[1] = (PI/2.0 + pole*0);
- tmpRot = rot[get_rotate_index(capmap.cn - pole)];
- vector_sub(v, c, v_min_c);
- dot_product(tmpRot, v_min_c, ret_dot);
- vector_add(ret_dot, a, vector);
- } else {
- pole = south_square;
- a[0] = (-3.0*PI/4.0 + pole*PI/2);
- a[1] = (PI/-2.0 + pole*0);
- tmpRot = rot[get_rotate_index(-1*(capmap.cn - pole))];
- vector_sub(v, c, v_min_c);
- dot_product(tmpRot, v_min_c, ret_dot);
- vector_add(ret_dot, a, vector);
- }
- xy.x = vector[0];
- xy.y = vector[1];
- return xy;
+ int pole = 0;
+ double (*tmpRot)[2];
+ double c[2] = {capmap.x, capmap.y};
+ if (capmap.region == north) {
+ pole = north_square;
+ a[0] = (-3.0*PI/4.0 + pole*PI/2);
+ a[1] = (PI/2.0 + pole*0);
+ tmpRot = rot[get_rotate_index(capmap.cn - pole)];
+ vector_sub(v, c, v_min_c);
+ dot_product(tmpRot, v_min_c, ret_dot);
+ vector_add(ret_dot, a, vector);
+ } else {
+ pole = south_square;
+ a[0] = (-3.0*PI/4.0 + pole*PI/2);
+ a[1] = (PI/-2.0 + pole*0);
+ tmpRot = rot[get_rotate_index(-1*(capmap.cn - pole))];
+ vector_sub(v, c, v_min_c);
+ dot_product(tmpRot, v_min_c, ret_dot);
+ vector_add(ret_dot, a, vector);
+ }
+ xy.x = vector[0];
+ xy.y = vector[1];
+ return xy;
} else {
/* Inverse function.
Unrotate (x, y) and then translate it back. */
- int pole = 0;
- double (*tmpRot)[2];
- double c[2] = {capmap.x, capmap.y};
- /* disassemble */
- if (capmap.region == north) {
- pole = north_square;
- a[0] = (-3.0*PI/4.0 + capmap.cn*PI/2);
- a[1] = (PI/2.0 + capmap.cn*0);
- tmpRot = rot[get_rotate_index(-1*(capmap.cn - pole))];
- vector_sub(v, c, v_min_c);
- dot_product(tmpRot, v_min_c, ret_dot);
- vector_add(ret_dot, a, vector);
- } else {
- pole = south_square;
- a[0] = (-3.0*PI/4.0 + capmap.cn*PI/2);
- a[1] = (PI/-2.0 + capmap.cn*0);
- tmpRot = rot[get_rotate_index(capmap.cn - pole)];
- vector_sub(v, c, v_min_c);
- dot_product(tmpRot, v_min_c, ret_dot);
- vector_add(ret_dot, a, vector);
- }
- xy.x = vector[0];
- xy.y = vector[1];
- return xy;
+ int pole = 0;
+ double (*tmpRot)[2];
+ double c[2] = {capmap.x, capmap.y};
+ /* disassemble */
+ if (capmap.region == north) {
+ pole = north_square;
+ a[0] = (-3.0*PI/4.0 + capmap.cn*PI/2);
+ a[1] = (PI/2.0 + capmap.cn*0);
+ tmpRot = rot[get_rotate_index(-1*(capmap.cn - pole))];
+ vector_sub(v, c, v_min_c);
+ dot_product(tmpRot, v_min_c, ret_dot);
+ vector_add(ret_dot, a, vector);
+ } else {
+ pole = south_square;
+ a[0] = (-3.0*PI/4.0 + capmap.cn*PI/2);
+ a[1] = (PI/-2.0 + capmap.cn*0);
+ tmpRot = rot[get_rotate_index(capmap.cn - pole)];
+ vector_sub(v, c, v_min_c);
+ dot_product(tmpRot, v_min_c, ret_dot);
+ vector_add(ret_dot, a, vector);
+ }
+ xy.x = vector[0];
+ xy.y = vector[1];
+ return xy;
}
}
-FORWARD(s_healpix_forward); /* sphere */
+
+
+static XY s_healpix_forward(LP lp, PJ *P) { /* sphere */
(void) P;
- (void) xy;
return healpix_sphere(lp);
}
-FORWARD(e_healpix_forward); /* ellipsoid */
- (void) xy;
+
+
+static XY e_healpix_forward(LP lp, PJ *P) { /* ellipsoid */
lp.phi = auth_lat(P, lp.phi, 0);
return healpix_sphere(lp);
}
-INVERSE(s_healpix_inverse); /* sphere */
+
+
+static LP s_healpix_inverse(XY xy, PJ *P) { /* sphere */
+ LP lp = {0.0,0.0};
+
/* Check whether (x, y) lies in the HEALPix image */
if (in_image(xy.x, xy.y, 0, 0, 0) == 0) {
- lp.lam = HUGE_VAL;
- lp.phi = HUGE_VAL;
- pj_ctx_set_errno(P->ctx, -15);
- return lp;
+ lp.lam = HUGE_VAL;
+ lp.phi = HUGE_VAL;
+ pj_ctx_set_errno(P->ctx, -15);
+ return lp;
}
return healpix_sphere_inverse(xy);
}
-INVERSE(e_healpix_inverse); /* ellipsoid */
+
+
+static LP e_healpix_inverse(XY xy, PJ *P) { /* ellipsoid */
+ LP lp = {0.0,0.0};
+
/* Check whether (x, y) lies in the HEALPix image. */
if (in_image(xy.x, xy.y, 0, 0, 0) == 0) {
- lp.lam = HUGE_VAL;
- lp.phi = HUGE_VAL;
- pj_ctx_set_errno(P->ctx, -15);
- return lp;
+ lp.lam = HUGE_VAL;
+ lp.phi = HUGE_VAL;
+ pj_ctx_set_errno(P->ctx, -15);
+ return lp;
}
lp = healpix_sphere_inverse(xy);
lp.phi = auth_lat(P, lp.phi, 1);
- return (lp);
+ return lp;
}
-FORWARD(s_rhealpix_forward); /* sphere */
- xy = healpix_sphere(lp);
- return combine_caps(xy.x, xy.y, P->north_square, P->south_square, 0);
+
+
+static XY s_rhealpix_forward(LP lp, PJ *P) { /* sphere */
+ struct pj_opaque *Q = P->opaque;
+
+ XY xy = healpix_sphere(lp);
+ return combine_caps(xy.x, xy.y, Q->north_square, Q->south_square, 0);
}
-FORWARD(e_rhealpix_forward); /* ellipsoid */
+
+
+static XY e_rhealpix_forward(LP lp, PJ *P) { /* ellipsoid */
+ struct pj_opaque *Q = P->opaque;
+ XY xy;
lp.phi = auth_lat(P, lp.phi, 0);
xy = healpix_sphere(lp);
- return combine_caps(xy.x, xy.y, P->north_square, P->south_square, 0);
+ return combine_caps(xy.x, xy.y, Q->north_square, Q->south_square, 0);
}
-INVERSE(s_rhealpix_inverse); /* sphere */
+
+
+static LP s_rhealpix_inverse(XY xy, PJ *P) { /* sphere */
+ struct pj_opaque *Q = P->opaque;
+ LP lp = {0.0,0.0};
+
/* Check whether (x, y) lies in the rHEALPix image. */
- if (in_image(xy.x, xy.y, 1, P->north_square, P->south_square) == 0) {
- lp.lam = HUGE_VAL;
- lp.phi = HUGE_VAL;
- pj_ctx_set_errno(P->ctx, -15);
- return lp;
+ if (in_image(xy.x, xy.y, 1, Q->north_square, Q->south_square) == 0) {
+ lp.lam = HUGE_VAL;
+ lp.phi = HUGE_VAL;
+ pj_ctx_set_errno(P->ctx, -15);
+ return lp;
}
- xy = combine_caps(xy.x, xy.y, P->north_square, P->south_square, 1);
+ xy = combine_caps(xy.x, xy.y, Q->north_square, Q->south_square, 1);
return healpix_sphere_inverse(xy);
}
-INVERSE(e_rhealpix_inverse); /* ellipsoid */
+
+
+static LP e_rhealpix_inverse(XY xy, PJ *P) { /* ellipsoid */
+ struct pj_opaque *Q = P->opaque;
+ LP lp = {0.0,0.0};
+
/* Check whether (x, y) lies in the rHEALPix image. */
- if (in_image(xy.x, xy.y, 1, P->north_square, P->south_square) == 0) {
- lp.lam = HUGE_VAL;
- lp.phi = HUGE_VAL;
- pj_ctx_set_errno(P->ctx, -15);
- return lp;
+ if (in_image(xy.x, xy.y, 1, Q->north_square, Q->south_square) == 0) {
+ lp.lam = HUGE_VAL;
+ lp.phi = HUGE_VAL;
+ pj_ctx_set_errno(P->ctx, -15);
+ return lp;
}
- xy = combine_caps(xy.x, xy.y, P->north_square, P->south_square, 1);
+ xy = combine_caps(xy.x, xy.y, Q->north_square, Q->south_square, 1);
lp = healpix_sphere_inverse(xy);
lp.phi = auth_lat(P, lp.phi, 1);
return lp;
}
-FREEUP;
- if (P) {
- if (P->apa)
- pj_dalloc(P->apa);
- pj_dalloc(P);
- }
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+ if (0==P->opaque)
+ return pj_dealloc (P);
+
+ if (P->opaque->apa)
+ pj_dealloc(P->opaque->apa);
+
+ pj_dealloc (P->opaque);
+ return pj_dealloc(P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
}
-ENTRY1(healpix, apa)
+
+
+PJ *PROJECTION(healpix) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
if (P->es) {
- P->apa = pj_authset(P->es); /* For auth_lat(). */
- P->qp = pj_qsfn(1.0, P->e, P->one_es); /* For auth_lat(). */
- P->a = P->a*sqrt(0.5*P->qp); /* Set P->a to authalic radius. */
+ Q->apa = pj_authset(P->es); /* For auth_lat(). */
+ Q->qp = pj_qsfn(1.0, P->e, P->one_es); /* For auth_lat(). */
+ P->a = P->a*sqrt(0.5*Q->qp); /* Set P->a to authalic radius. */
P->ra = 1.0/P->a;
- P->fwd = e_healpix_forward;
- P->inv = e_healpix_inverse;
+ P->fwd = e_healpix_forward;
+ P->inv = e_healpix_inverse;
} else {
- P->fwd = s_healpix_forward;
- P->inv = s_healpix_inverse;
+ P->fwd = s_healpix_forward;
+ P->inv = s_healpix_inverse;
}
-ENDENTRY(P)
-ENTRY1(rhealpix, apa)
- P->north_square = pj_param(P->ctx, P->params,"inorth_square").i;
- P->south_square = pj_param(P->ctx, P->params,"isouth_square").i;
+
+ return P;
+}
+
+
+PJ *PROJECTION(rhealpix) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->north_square = pj_param(P->ctx, P->params,"inorth_square").i;
+ Q->south_square = pj_param(P->ctx, P->params,"isouth_square").i;
+
/* Check for valid north_square and south_square inputs. */
- if (P->north_square < 0 || P->north_square > 3) {
- E_ERROR(-47);
+ if (Q->north_square < 0 || Q->north_square > 3) {
+ E_ERROR(-47);
}
- if (P->south_square < 0 || P->south_square > 3) {
- E_ERROR(-47);
+ if (Q->south_square < 0 || Q->south_square > 3) {
+ E_ERROR(-47);
}
if (P->es) {
- P->apa = pj_authset(P->es); /* For auth_lat(). */
- P->qp = pj_qsfn(1.0, P->e, P->one_es); /* For auth_lat(). */
- P->a = P->a*sqrt(0.5*P->qp); /* Set P->a to authalic radius. */
+ Q->apa = pj_authset(P->es); /* For auth_lat(). */
+ Q->qp = pj_qsfn(1.0, P->e, P->one_es); /* For auth_lat(). */
+ P->a = P->a*sqrt(0.5*Q->qp); /* Set P->a to authalic radius. */
P->ra = 1.0/P->a;
- P->fwd = e_rhealpix_forward;
- P->inv = e_rhealpix_inverse;
+ P->fwd = e_rhealpix_forward;
+ P->inv = e_rhealpix_inverse;
} else {
- P->fwd = s_rhealpix_forward;
- P->inv = s_rhealpix_inverse;
+ P->fwd = s_rhealpix_forward;
+ P->inv = s_rhealpix_inverse;
}
-ENDENTRY(P)
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_healpix_selftest (void) {return 0;}
+#else
+
+int pj_healpix_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=healpix +ellps=GRS80 +lat_1=0.5 +lat_2=2"};
+ char s_args[] = {"+proj=healpix +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ { 222390.10394923863, 130406.58866448226},
+ { 222390.10394923863, -130406.58866448054},
+ {-222390.10394923863, 130406.58866448226},
+ {-222390.10394923863, -130406.58866448054},
+ };
+
+ XY s_fwd_expect[] = {
+ { 223402.14425527418, 131588.04444199943},
+ { 223402.14425527418, -131588.04444199943},
+ {-223402.14425527418, 131588.04444199943},
+ {-223402.14425527418, -131588.04444199943},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ { 0.0017986411845524453, 0.00076679453057823619},
+ { 0.0017986411845524453, -0.00076679453057823619},
+ {-0.0017986411845524453, 0.00076679453057823619},
+ {-0.0017986411845524453, -0.00076679453057823619},
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0017904931097838226, 0.00075990887733981202},
+ { 0.0017904931097838226, -0.00075990887733981202},
+ {-0.0017904931097838226, 0.00075990887733981202},
+ {-0.0017904931097838226, -0.00075990887733981202},
+ };
+
+ 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
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_rhealpix_selftest (void) {return 0;}
+#else
+
+int pj_rhealpix_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=rhealpix +ellps=GRS80 +lat_1=0.5 +lat_2=2"};
+ char s_args[] = {"+proj=rhealpix +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ { 222390.10394923863, 130406.58866448226},
+ { 222390.10394923863, -130406.58866448054},
+ {-222390.10394923863, 130406.58866448226},
+ {-222390.10394923863, -130406.58866448054},
+ };
+
+ XY s_fwd_expect[] = {
+ { 223402.14425527418, 131588.04444199943},
+ { 223402.14425527418, -131588.04444199943},
+ {-223402.14425527418, 131588.04444199943},
+ {-223402.14425527418, -131588.04444199943},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ { 0.0017986411845524453, 0.00076679453057823619},
+ { 0.0017986411845524453, -0.00076679453057823619},
+ {-0.0017986411845524453, 0.00076679453057823619},
+ {-0.0017986411845524453, -0.00076679453057823619},
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0017904931097838226, 0.00075990887733981202},
+ { 0.0017904931097838226, -0.00075990887733981202},
+ {-0.0017904931097838226, 0.00075990887733981202},
+ {-0.0017904931097838226, -0.00075990887733981202},
+ };
+
+ 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_igh.c b/src/PJ_igh.c
index 4155c856..533c3aa0 100644
--- a/src/PJ_igh.c
+++ b/src/PJ_igh.c
@@ -1,13 +1,17 @@
-#define PROJ_PARMS__ \
- struct PJconsts* pj[12]; \
- double dy0;
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(igh, "Interrupted Goode Homolosine") "\n\tPCyl, Sph.";
- C_NAMESPACE PJ
-*pj_sinu(PJ *), *pj_moll(PJ *);
-static const double d4044118 = (40 + 44/60. + 11.8/3600.) * DEG_TO_RAD; // 40d 44' 11.8" [degrees]
+C_NAMESPACE PJ *pj_sinu(PJ *), *pj_moll(PJ *);
+
+/* 40d 44' 11.8" [degrees] */
+/*
+static const double d4044118 = (40 + 44/60. + 11.8/3600.) * DEG_TO_RAD;
+has been replaced by this define, to eliminate portability issue:
+Initializer element not computable at load time
+*/
+#define d4044118 ((40 + 44/60. + 11.8/3600.) * DEG_TO_RAD)
static const double d10 = 10 * DEG_TO_RAD;
static const double d20 = 20 * DEG_TO_RAD;
@@ -22,108 +26,134 @@ static const double d140 = 140 * DEG_TO_RAD;
static const double d160 = 160 * DEG_TO_RAD;
static const double d180 = 180 * DEG_TO_RAD;
-static const double EPSLN = 1.e-10; // allow a little 'slack' on zone edge positions
+static const double EPSLN = 1.e-10; /* allow a little 'slack' on zone edge positions */
-FORWARD(s_forward); /* spheroid */
- int z;
- if (lp.phi >= d4044118) { // 1|2
- z = (lp.lam <= -d40 ? 1: 2);
- }
- else if (lp.phi >= 0) { // 3|4
- z = (lp.lam <= -d40 ? 3: 4);
- }
- else if (lp.phi >= -d4044118) { // 5|6|7|8
- if (lp.lam <= -d100) z = 5; // 5
- else if (lp.lam <= -d20) z = 6; // 6
- else if (lp.lam <= d80) z = 7; // 7
- else z = 8; // 8
- }
- else { // 9|10|11|12
- if (lp.lam <= -d100) z = 9; // 9
- else if (lp.lam <= -d20) z = 10; // 10
- else if (lp.lam <= d80) z = 11; // 11
- else z = 12; // 12
- }
+struct pj_opaque {
+ struct PJconsts* pj[12]; \
+ double dy0;
+};
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ int z;
+
+ if (lp.phi >= d4044118) { /* 1|2 */
+ z = (lp.lam <= -d40 ? 1: 2);
+ }
+ else if (lp.phi >= 0) { /* 3|4 */
+ z = (lp.lam <= -d40 ? 3: 4);
+ }
+ else if (lp.phi >= -d4044118) { /* 5|6|7|8 */
+ if (lp.lam <= -d100) z = 5; /* 5 */
+ else if (lp.lam <= -d20) z = 6; /* 6 */
+ else if (lp.lam <= d80) z = 7; /* 7 */
+ else z = 8; /* 8 */
+ }
+ else { /* 9|10|11|12 */
+ if (lp.lam <= -d100) z = 9; /* 9 */
+ else if (lp.lam <= -d20) z = 10; /* 10 */
+ else if (lp.lam <= d80) z = 11; /* 11 */
+ else z = 12; /* 12 */
+ }
- lp.lam -= P->pj[z-1]->lam0;
- xy = P->pj[z-1]->fwd(lp, P->pj[z-1]);
- xy.x += P->pj[z-1]->x0;
- xy.y += P->pj[z-1]->y0;
+ lp.lam -= Q->pj[z-1]->lam0;
+ xy = Q->pj[z-1]->fwd(lp, Q->pj[z-1]);
+ xy.x += Q->pj[z-1]->x0;
+ xy.y += Q->pj[z-1]->y0;
- return (xy);
+ return xy;
}
-INVERSE(s_inverse); /* spheroid */
- const double y90 = P->dy0 + sqrt(2); // lt=90 corresponds to y=y0+sqrt(2)
-
- int z = 0;
- if (xy.y > y90+EPSLN || xy.y < -y90+EPSLN) // 0
- z = 0;
- else if (xy.y >= d4044118) // 1|2
- z = (xy.x <= -d40? 1: 2);
- else if (xy.y >= 0) // 3|4
- z = (xy.x <= -d40? 3: 4);
- else if (xy.y >= -d4044118) { // 5|6|7|8
- if (xy.x <= -d100) z = 5; // 5
- else if (xy.x <= -d20) z = 6; // 6
- else if (xy.x <= d80) z = 7; // 7
- else z = 8; // 8
- }
- else { // 9|10|11|12
- if (xy.x <= -d100) z = 9; // 9
- else if (xy.x <= -d20) z = 10; // 10
- else if (xy.x <= d80) z = 11; // 11
- else z = 12; // 12
- }
- if (z)
- {
- int ok = 0;
-
- xy.x -= P->pj[z-1]->x0;
- xy.y -= P->pj[z-1]->y0;
- lp = P->pj[z-1]->inv(xy, P->pj[z-1]);
- lp.lam += P->pj[z-1]->lam0;
-
- switch (z) {
- case 1: ok = (lp.lam >= -d180-EPSLN && lp.lam <= -d40+EPSLN) ||
- ((lp.lam >= -d40-EPSLN && lp.lam <= -d10+EPSLN) &&
- (lp.phi >= d60-EPSLN && lp.phi <= d90+EPSLN)); break;
- case 2: ok = (lp.lam >= -d40-EPSLN && lp.lam <= d180+EPSLN) ||
- ((lp.lam >= -d180-EPSLN && lp.lam <= -d160+EPSLN) &&
- (lp.phi >= d50-EPSLN && lp.phi <= d90+EPSLN)) ||
- ((lp.lam >= -d50-EPSLN && lp.lam <= -d40+EPSLN) &&
- (lp.phi >= d60-EPSLN && lp.phi <= d90+EPSLN)); break;
- case 3: ok = (lp.lam >= -d180-EPSLN && lp.lam <= -d40+EPSLN); break;
- case 4: ok = (lp.lam >= -d40-EPSLN && lp.lam <= d180+EPSLN); break;
- case 5: ok = (lp.lam >= -d180-EPSLN && lp.lam <= -d100+EPSLN); break;
- case 6: ok = (lp.lam >= -d100-EPSLN && lp.lam <= -d20+EPSLN); break;
- case 7: ok = (lp.lam >= -d20-EPSLN && lp.lam <= d80+EPSLN); break;
- case 8: ok = (lp.lam >= d80-EPSLN && lp.lam <= d180+EPSLN); break;
- case 9: ok = (lp.lam >= -d180-EPSLN && lp.lam <= -d100+EPSLN); break;
- case 10: ok = (lp.lam >= -d100-EPSLN && lp.lam <= -d20+EPSLN); break;
- case 11: ok = (lp.lam >= -d20-EPSLN && lp.lam <= d80+EPSLN); break;
- case 12: ok = (lp.lam >= d80-EPSLN && lp.lam <= d180+EPSLN); break;
- }
-
- z = (!ok? 0: z); // projectable?
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ const double y90 = Q->dy0 + sqrt(2); /* lt=90 corresponds to y=y0+sqrt(2) */
+
+ int z = 0;
+ if (xy.y > y90+EPSLN || xy.y < -y90+EPSLN) /* 0 */
+ z = 0;
+ else if (xy.y >= d4044118) /* 1|2 */
+ z = (xy.x <= -d40? 1: 2);
+ else if (xy.y >= 0) /* 3|4 */
+ z = (xy.x <= -d40? 3: 4);
+ else if (xy.y >= -d4044118) { /* 5|6|7|8 */
+ if (xy.x <= -d100) z = 5; /* 5 */
+ else if (xy.x <= -d20) z = 6; /* 6 */
+ else if (xy.x <= d80) z = 7; /* 7 */
+ else z = 8; /* 8 */
+ }
+ else { /* 9|10|11|12 */
+ if (xy.x <= -d100) z = 9; /* 9 */
+ else if (xy.x <= -d20) z = 10; /* 10 */
+ else if (xy.x <= d80) z = 11; /* 11 */
+ else z = 12; /* 12 */
+ }
+
+ if (z) {
+ int ok = 0;
+
+ xy.x -= Q->pj[z-1]->x0;
+ xy.y -= Q->pj[z-1]->y0;
+ lp = Q->pj[z-1]->inv(xy, Q->pj[z-1]);
+ lp.lam += Q->pj[z-1]->lam0;
+
+ switch (z) {
+ case 1: ok = (lp.lam >= -d180-EPSLN && lp.lam <= -d40+EPSLN) ||
+ ((lp.lam >= -d40-EPSLN && lp.lam <= -d10+EPSLN) &&
+ (lp.phi >= d60-EPSLN && lp.phi <= d90+EPSLN)); break;
+ case 2: ok = (lp.lam >= -d40-EPSLN && lp.lam <= d180+EPSLN) ||
+ ((lp.lam >= -d180-EPSLN && lp.lam <= -d160+EPSLN) &&
+ (lp.phi >= d50-EPSLN && lp.phi <= d90+EPSLN)) ||
+ ((lp.lam >= -d50-EPSLN && lp.lam <= -d40+EPSLN) &&
+ (lp.phi >= d60-EPSLN && lp.phi <= d90+EPSLN)); break;
+ case 3: ok = (lp.lam >= -d180-EPSLN && lp.lam <= -d40+EPSLN); break;
+ case 4: ok = (lp.lam >= -d40-EPSLN && lp.lam <= d180+EPSLN); break;
+ case 5: ok = (lp.lam >= -d180-EPSLN && lp.lam <= -d100+EPSLN); break;
+ case 6: ok = (lp.lam >= -d100-EPSLN && lp.lam <= -d20+EPSLN); break;
+ case 7: ok = (lp.lam >= -d20-EPSLN && lp.lam <= d80+EPSLN); break;
+ case 8: ok = (lp.lam >= d80-EPSLN && lp.lam <= d180+EPSLN); break;
+ case 9: ok = (lp.lam >= -d180-EPSLN && lp.lam <= -d100+EPSLN); break;
+ case 10: ok = (lp.lam >= -d100-EPSLN && lp.lam <= -d20+EPSLN); break;
+ case 11: ok = (lp.lam >= -d20-EPSLN && lp.lam <= d80+EPSLN); break;
+ case 12: ok = (lp.lam >= d80-EPSLN && lp.lam <= d180+EPSLN); break;
}
- // if (!z) pj_errno = -15; // invalid x or y
- if (!z) lp.lam = HUGE_VAL;
- if (!z) lp.phi = HUGE_VAL;
- return (lp);
+ z = (!ok? 0: z); /* projectable? */
+ }
+
+ if (!z) lp.lam = HUGE_VAL;
+ if (!z) lp.phi = HUGE_VAL;
+
+ return lp;
}
-FREEUP;
- if (P) {
- int i;
- for (i = 0; i < 12; ++i)
- {
- if (P->pj[i])
- (*(P->pj[i]->pfree))(P->pj[i]);
- }
- pj_dalloc(P);
- }
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ int i;
+ if (0==P)
+ return 0;
+ if (0==P->opaque)
+ return pj_dealloc (P);
+
+ for (i = 0; i < 12; ++i) {
+ if (P->opaque->pj[i])
+ pj_dealloc(P->opaque->pj[i]);
+ }
+
+ pj_dealloc (P->opaque);
+ return pj_dealloc(P);
+}
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
}
-ENTRY0(igh)
+
+
+
/*
Zones:
@@ -145,46 +175,96 @@ ENTRY0(igh)
*/
#define SETUP(n, proj, x_0, y_0, lon_0) \
- if (!(P->pj[n-1] = pj_##proj(0))) E_ERROR_0; \
- if (!(P->pj[n-1] = pj_##proj(P->pj[n-1]))) E_ERROR_0; \
- P->pj[n-1]->x0 = x_0; \
- P->pj[n-1]->y0 = y_0; \
- P->pj[n-1]->lam0 = lon_0;
+ if (!(Q->pj[n-1] = pj_##proj(0))) E_ERROR_0; \
+ if (!(Q->pj[n-1] = pj_##proj(Q->pj[n-1]))) E_ERROR_0; \
+ Q->pj[n-1]->x0 = x_0; \
+ Q->pj[n-1]->y0 = y_0; \
+ Q->pj[n-1]->lam0 = lon_0;
+
+
+PJ *PROJECTION(igh) {
+ XY xy1, xy3;
+ LP lp = { 0, d4044118 };
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
- LP lp = { 0, d4044118 };
- XY xy1;
- XY xy3;
- // sinusoidal zones
- SETUP(3, sinu, -d100, 0, -d100);
- SETUP(4, sinu, d30, 0, d30);
- SETUP(5, sinu, -d160, 0, -d160);
- SETUP(6, sinu, -d60, 0, -d60);
- SETUP(7, sinu, d20, 0, d20);
- SETUP(8, sinu, d140, 0, d140);
+ /* sinusoidal zones */
+ SETUP(3, sinu, -d100, 0, -d100);
+ SETUP(4, sinu, d30, 0, d30);
+ SETUP(5, sinu, -d160, 0, -d160);
+ SETUP(6, sinu, -d60, 0, -d60);
+ SETUP(7, sinu, d20, 0, d20);
+ SETUP(8, sinu, d140, 0, d140);
- // mollweide zones
- SETUP(1, moll, -d100, 0, -d100);
+ /* mollweide zones */
+ SETUP(1, moll, -d100, 0, -d100);
- // y0 ?
- xy1 = P->pj[0]->fwd(lp, P->pj[0]); // zone 1
- xy3 = P->pj[2]->fwd(lp, P->pj[2]); // zone 3
- // y0 + xy1.y = xy3.y for lt = 40d44'11.8"
- P->dy0 = xy3.y - xy1.y;
+ /* y0 ? */
+ xy1 = Q->pj[0]->fwd(lp, Q->pj[0]); /* zone 1 */
+ xy3 = Q->pj[2]->fwd(lp, Q->pj[2]); /* zone 3 */
+ /* y0 + xy1.y = xy3.y for lt = 40d44'11.8" */
+ Q->dy0 = xy3.y - xy1.y;
- P->pj[0]->y0 = P->dy0;
+ Q->pj[0]->y0 = Q->dy0;
- // mollweide zones (cont'd)
- SETUP( 2, moll, d30, P->dy0, d30);
- SETUP( 9, moll, -d160, -P->dy0, -d160);
- SETUP(10, moll, -d60, -P->dy0, -d60);
- SETUP(11, moll, d20, -P->dy0, d20);
- SETUP(12, moll, d140, -P->dy0, d140);
+ /* mollweide zones (cont'd) */
+ SETUP( 2, moll, d30, Q->dy0, d30);
+ SETUP( 9, moll, -d160, -Q->dy0, -d160);
+ SETUP(10, moll, -d60, -Q->dy0, -d60);
+ SETUP(11, moll, d20, -Q->dy0, d20);
+ SETUP(12, moll, d140, -Q->dy0, d140);
- P->inv = s_inverse;
- P->fwd = s_forward;
- P->es = 0.;
-ENDENTRY(P)
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+ P->es = 0.;
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_igh_selftest (void) {return 0;}
+#else
+
+int pj_igh_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=igh +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 223878.49745627123, 111701.07212763709},
+ { 223708.37131305804, -111701.07212763709},
+ {-222857.74059699223, 111701.07212763709},
+ {-223027.86674020503, -111701.07212763709},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.001790489447892545, 0.00089524655489191132},
+ { 0.0017904906685957927, -0.00089524655489191132},
+ {-0.001790496772112032, 0.00089524655489191132},
+ {-0.0017904955514087843, -0.00089524655489191132},
+ };
+
+ 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_imw_p.c b/src/PJ_imw_p.c
index ae411116..a1675a90 100644
--- a/src/PJ_imw_p.c
+++ b/src/PJ_imw_p.c
@@ -1,151 +1,238 @@
-#define PROJ_PARMS__ \
- double P, Pp, Q, Qp, R_1, R_2, sphi_1, sphi_2, C2; \
- double phi_1, phi_2, lam_1; \
- double *en; \
- int mode; /* = 0, phi_1 and phi_2 != 0, = 1, phi_1 = 0, = -1 phi_2 = 0 */
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(imw_p, "International Map of the World Polyconic")
- "\n\tMod. Polyconic, Ell\n\tlat_1= and lat_2= [lon_1=]";
+ "\n\tMod. Polyconic, Ell\n\tlat_1= and lat_2= [lon_1=]";
+
#define TOL 1e-10
#define EPS 1e-10
- static int
-phi12(PJ *P, double *del, double *sig) {
- int err = 0;
-
- if (!pj_param(P->ctx, P->params, "tlat_1").i ||
- !pj_param(P->ctx, P->params, "tlat_2").i) {
- err = -41;
- } else {
- P->phi_1 = pj_param(P->ctx, P->params, "rlat_1").f;
- P->phi_2 = pj_param(P->ctx, P->params, "rlat_2").f;
- *del = 0.5 * (P->phi_2 - P->phi_1);
- *sig = 0.5 * (P->phi_2 + P->phi_1);
- err = (fabs(*del) < EPS || fabs(*sig) < EPS) ? -42 : 0;
- }
- return err;
+
+struct pj_opaque {
+ double P, Pp, Q, Qp, R_1, R_2, sphi_1, sphi_2, C2; \
+ double phi_1, phi_2, lam_1; \
+ double *en; \
+ int mode; /* = 0, phi_1 and phi_2 != 0, = 1, phi_1 = 0, = -1 phi_2 = 0 */
+};
+
+
+static int phi12(PJ *P, double *del, double *sig) {
+ struct pj_opaque *Q = P->opaque;
+ int err = 0;
+
+ if (!pj_param(P->ctx, P->params, "tlat_1").i ||
+ !pj_param(P->ctx, P->params, "tlat_2").i) {
+ err = -41;
+ } else {
+ Q->phi_1 = pj_param(P->ctx, P->params, "rlat_1").f;
+ Q->phi_2 = pj_param(P->ctx, P->params, "rlat_2").f;
+ *del = 0.5 * (Q->phi_2 - Q->phi_1);
+ *sig = 0.5 * (Q->phi_2 + Q->phi_1);
+ err = (fabs(*del) < EPS || fabs(*sig) < EPS) ? -42 : 0;
+ }
+ return err;
+}
+
+
+static XY loc_for(LP lp, PJ *P, double *yc) {
+ struct pj_opaque *Q = P->opaque;
+ XY xy;
+
+ if (! lp.phi) {
+ xy.x = lp.lam;
+ xy.y = 0.;
+ } else {
+ double xa, ya, xb, yb, xc, D, B, m, sp, t, R, C;
+
+ sp = sin(lp.phi);
+ m = pj_mlfn(lp.phi, sp, cos(lp.phi), Q->en);
+ xa = Q->Pp + Q->Qp * m;
+ ya = Q->P + Q->Q * m;
+ R = 1. / (tan(lp.phi) * sqrt(1. - P->es * sp * sp));
+ C = sqrt(R * R - xa * xa);
+ if (lp.phi < 0.) C = - C;
+ C += ya - R;
+ if (Q->mode < 0) {
+ xb = lp.lam;
+ yb = Q->C2;
+ } else {
+ t = lp.lam * Q->sphi_2;
+ xb = Q->R_2 * sin(t);
+ yb = Q->C2 + Q->R_2 * (1. - cos(t));
+ }
+ if (Q->mode > 0) {
+ xc = lp.lam;
+ *yc = 0.;
+ } else {
+ t = lp.lam * Q->sphi_1;
+ xc = Q->R_1 * sin(t);
+ *yc = Q->R_1 * (1. - cos(t));
+ }
+ D = (xb - xc)/(yb - *yc);
+ B = xc + D * (C + R - *yc);
+ xy.x = D * sqrt(R * R * (1 + D * D) - B * B);
+ if (lp.phi > 0)
+ xy.x = - xy.x;
+ xy.x = (B + xy.x) / (1. + D * D);
+ xy.y = sqrt(R * R - xy.x * xy.x);
+ if (lp.phi > 0)
+ xy.y = - xy.y;
+ xy.y += C + R;
+ }
+ return xy;
+}
+
+
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
+ XY xy = {0.0,0.0};
+ double yc;
+
+ xy = loc_for(lp, P, &yc);
+ return (xy);
+}
+
+
+static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ XY t;
+ double yc;
+
+ lp.phi = Q->phi_2;
+ lp.lam = xy.x / cos(lp.phi);
+ do {
+ t = loc_for(lp, P, &yc);
+ lp.phi = ((lp.phi - Q->phi_1) * (xy.y - yc) / (t.y - yc)) + Q->phi_1;
+ lp.lam = lp.lam * xy.x / t.x;
+ } while (fabs(t.x - xy.x) > TOL || fabs(t.y - xy.y) > TOL);
+
+ return lp;
+}
+
+
+static void xy(PJ *P, double phi, double *x, double *y, double *sp, double *R) {
+ double F;
+
+ *sp = sin(phi);
+ *R = 1./(tan(phi) * sqrt(1. - P->es * *sp * *sp ));
+ F = P->opaque->lam_1 * *sp;
+ *y = *R * (1 - cos(F));
+ *x = *R * sin(F);
}
- static XY
-loc_for(LP lp, PJ *P, double *yc) {
- XY xy;
-
- if (! lp.phi) {
- xy.x = lp.lam;
- xy.y = 0.;
- } else {
- double xa, ya, xb, yb, xc, D, B, m, sp, t, R, C;
-
- sp = sin(lp.phi);
- m = pj_mlfn(lp.phi, sp, cos(lp.phi), P->en);
- xa = P->Pp + P->Qp * m;
- ya = P->P + P->Q * m;
- R = 1. / (tan(lp.phi) * sqrt(1. - P->es * sp * sp));
- C = sqrt(R * R - xa * xa);
- if (lp.phi < 0.) C = - C;
- C += ya - R;
- if (P->mode < 0) {
- xb = lp.lam;
- yb = P->C2;
- } else {
- t = lp.lam * P->sphi_2;
- xb = P->R_2 * sin(t);
- yb = P->C2 + P->R_2 * (1. - cos(t));
- }
- if (P->mode > 0) {
- xc = lp.lam;
- *yc = 0.;
- } else {
- t = lp.lam * P->sphi_1;
- xc = P->R_1 * sin(t);
- *yc = P->R_1 * (1. - cos(t));
- }
- D = (xb - xc)/(yb - *yc);
- B = xc + D * (C + R - *yc);
- xy.x = D * sqrt(R * R * (1 + D * D) - B * B);
- if (lp.phi > 0)
- xy.x = - xy.x;
- xy.x = (B + xy.x) / (1. + D * D);
- xy.y = sqrt(R * R - xy.x * xy.x);
- if (lp.phi > 0)
- xy.y = - xy.y;
- xy.y += C + R;
- }
- return (xy);
+
+
+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);
}
-FORWARD(e_forward); /* ellipsoid */
- double yc;
- xy = loc_for(lp, P, &yc);
- return (xy);
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
}
-INVERSE(e_inverse); /* ellipsoid */
- XY t;
- double yc;
-
- lp.phi = P->phi_2;
- lp.lam = xy.x / cos(lp.phi);
- do {
- t = loc_for(lp, P, &yc);
- lp.phi = ((lp.phi - P->phi_1) * (xy.y - yc) / (t.y - yc)) + P->phi_1;
- lp.lam = lp.lam * xy.x / t.x;
- } while (fabs(t.x - xy.x) > TOL || fabs(t.y - xy.y) > TOL);
- return (lp);
+
+
+PJ *PROJECTION(imw_p) {
+ double del, sig, s, t, x1, x2, T2, y1, m1, m2, y2;
+ int i;
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ if (!(Q->en = pj_enfn(P->es))) E_ERROR_0;
+ if( (i = phi12(P, &del, &sig)) != 0)
+ E_ERROR(i);
+ if (Q->phi_2 < Q->phi_1) { /* make sure P->phi_1 most southerly */
+ del = Q->phi_1;
+ Q->phi_1 = Q->phi_2;
+ Q->phi_2 = del;
+ }
+ if (pj_param(P->ctx, P->params, "tlon_1").i)
+ Q->lam_1 = pj_param(P->ctx, P->params, "rlon_1").f;
+ else { /* use predefined based upon latitude */
+ sig = fabs(sig * RAD_TO_DEG);
+ if (sig <= 60) sig = 2.;
+ else if (sig <= 76) sig = 4.;
+ else sig = 8.;
+ Q->lam_1 = sig * DEG_TO_RAD;
+ }
+ Q->mode = 0;
+ if (Q->phi_1) xy(P, Q->phi_1, &x1, &y1, &Q->sphi_1, &Q->R_1);
+ else {
+ Q->mode = 1;
+ y1 = 0.;
+ x1 = Q->lam_1;
+ }
+ if (Q->phi_2) xy(P, Q->phi_2, &x2, &T2, &Q->sphi_2, &Q->R_2);
+ else {
+ Q->mode = -1;
+ T2 = 0.;
+ x2 = Q->lam_1;
+ }
+ m1 = pj_mlfn(Q->phi_1, Q->sphi_1, cos(Q->phi_1), Q->en);
+ m2 = pj_mlfn(Q->phi_2, Q->sphi_2, cos(Q->phi_2), Q->en);
+ t = m2 - m1;
+ s = x2 - x1;
+ y2 = sqrt(t * t - s * s) + y1;
+ Q->C2 = y2 - T2;
+ t = 1. / t;
+ Q->P = (m2 * y1 - m1 * y2) * t;
+ Q->Q = (y2 - y1) * t;
+ Q->Pp = (m2 * x1 - m1 * x2) * t;
+ Q->Qp = (x2 - x1) * t;
+
+ P->fwd = e_forward;
+ P->inv = e_inverse;
+
+ return P;
}
- static void
-xy(PJ *P, double phi, double *x, double *y, double *sp, double *R) {
- double F;
-
- *sp = sin(phi);
- *R = 1./(tan(phi) * sqrt(1. - P->es * *sp * *sp ));
- F = P->lam_1 * *sp;
- *y = *R * (1 - cos(F));
- *x = *R * sin(F);
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_imw_p_selftest (void) {return 0;}
+#else
+
+int pj_imw_p_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=imw_p +ellps=GRS80 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ { 222588.4411393762, 55321.128653809537},
+ { 222756.90637768712, -165827.58428832365},
+ {-222588.4411393762, 55321.128653809537},
+ {-222756.90637768712, -165827.58428832365},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ { 0.0017966991379592214, 0.50090492361427374},
+ { 0.0017966979081574697, 0.49909507588689922},
+ {-0.0017966991379592214, 0.50090492361427374},
+ {-0.0017966979081574697, 0.49909507588689922},
+ };
+
+ return pj_generic_selftest (e_args, 0, tolerance_xy, tolerance_lp, 4, 4, fwd_in, e_fwd_expect, 0, inv_in, e_inv_expect, 0);
}
-FREEUP; if (P) { if (P->en) pj_dalloc(P->en); pj_dalloc(P); } }
-ENTRY1(imw_p, en)
- double del, sig, s, t, x1, x2, T2, y1, m1, m2, y2;
- int i;
-
- if (!(P->en = pj_enfn(P->es))) E_ERROR_0;
- if( (i = phi12(P, &del, &sig)) != 0)
- E_ERROR(i);
- if (P->phi_2 < P->phi_1) { /* make sure P->phi_1 most southerly */
- del = P->phi_1;
- P->phi_1 = P->phi_2;
- P->phi_2 = del;
- }
- if (pj_param(P->ctx, P->params, "tlon_1").i)
- P->lam_1 = pj_param(P->ctx, P->params, "rlon_1").f;
- else { /* use predefined based upon latitude */
- sig = fabs(sig * RAD_TO_DEG);
- if (sig <= 60) sig = 2.;
- else if (sig <= 76) sig = 4.;
- else sig = 8.;
- P->lam_1 = sig * DEG_TO_RAD;
- }
- P->mode = 0;
- if (P->phi_1) xy(P, P->phi_1, &x1, &y1, &P->sphi_1, &P->R_1);
- else {
- P->mode = 1;
- y1 = 0.;
- x1 = P->lam_1;
- }
- if (P->phi_2) xy(P, P->phi_2, &x2, &T2, &P->sphi_2, &P->R_2);
- else {
- P->mode = -1;
- T2 = 0.;
- x2 = P->lam_1;
- }
- m1 = pj_mlfn(P->phi_1, P->sphi_1, cos(P->phi_1), P->en);
- m2 = pj_mlfn(P->phi_2, P->sphi_2, cos(P->phi_2), P->en);
- t = m2 - m1;
- s = x2 - x1;
- y2 = sqrt(t * t - s * s) + y1;
- P->C2 = y2 - T2;
- t = 1. / t;
- P->P = (m2 * y1 - m1 * y2) * t;
- P->Q = (y2 - y1) * t;
- P->Pp = (m2 * x1 - m1 * x2) * t;
- P->Qp = (x2 - x1) * t;
- P->fwd = e_forward;
- P->inv = e_inverse;
-ENDENTRY(P)
+
+
+#endif
diff --git a/src/PJ_isea.c b/src/PJ_isea.c
index 7c09189c..ba9d3c62 100644
--- a/src/PJ_isea.c
+++ b/src/PJ_isea.c
@@ -1,1119 +1,1176 @@
-/*
- * This code was entirely written by Nathan Wagner
- * and is in the public domain.
- */
-
-#include <math.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <float.h>
-
-#ifndef M_PI
-# define M_PI 3.14159265358979323846
-#endif
-
-/*
- * Proj 4 provides its own entry points into
- * the code, so none of the library functions
- * need to be global
- */
-#define ISEA_STATIC static
-#ifndef ISEA_STATIC
-#define ISEA_STATIC
-#endif
-
-struct hex {
- int iso;
- int x, y, z;
-};
-
-/* y *must* be positive down as the xy /iso conversion assumes this */
-ISEA_STATIC
-int hex_xy(struct hex *h) {
- if (!h->iso) return 1;
- if (h->x >= 0) {
- h->y = -h->y - (h->x+1)/2;
- } else {
- /* need to round toward -inf, not toward zero, so x-1 */
- h->y = -h->y - h->x/2;
- }
- h->iso = 0;
-
- return 1;
-}
-
-ISEA_STATIC
-int hex_iso(struct hex *h) {
- if (h->iso) return 1;
-
- if (h->x >= 0) {
- h->y = (-h->y - (h->x+1)/2);
- } else {
- /* need to round toward -inf, not toward zero, so x-1 */
- h->y = (-h->y - (h->x)/2);
- }
-
- h->z = -h->x - h->y;
- h->iso = 1;
- return 1;
-}
-
-ISEA_STATIC
-int hexbin2(double width, double x, double y,
- int *i, int *j) {
- double z, rx, ry, rz;
- double abs_dx, abs_dy, abs_dz;
- int ix, iy, iz, s;
- struct hex h;
-
- x = x / cos(30 * M_PI / 180.0); /* rotated X coord */
- y = y - x / 2.0; /* adjustment for rotated X */
-
- /* adjust for actual hexwidth */
- x /= width;
- y /= width;
-
- z = -x - y;
-
- ix = rx = floor(x + 0.5);
- iy = ry = floor(y + 0.5);
- iz = rz = floor(z + 0.5);
-
- s = ix + iy + iz;
-
- if (s) {
- abs_dx = fabs(rx - x);
- abs_dy = fabs(ry - y);
- abs_dz = fabs(rz - z);
-
- if (abs_dx >= abs_dy && abs_dx >= abs_dz) {
- ix -= s;
- } else if (abs_dy >= abs_dx && abs_dy >= abs_dz) {
- iy -= s;
- } else {
- iz -= s;
- }
- }
- h.x = ix;
- h.y = iy;
- h.z = iz;
- h.iso = 1;
-
- hex_xy(&h);
- *i = h.x;
- *j = h.y;
- return ix * 100 + iy;
-}
-#ifndef ISEA_STATIC
-#define ISEA_STATIC
-#endif
-
-enum isea_poly { ISEA_NONE, ISEA_ICOSAHEDRON = 20 };
-enum isea_topology { ISEA_HEXAGON=6, ISEA_TRIANGLE=3, ISEA_DIAMOND=4 };
-enum isea_address_form { ISEA_GEO, ISEA_Q2DI, ISEA_SEQNUM, ISEA_INTERLEAVE,
- ISEA_PLANE, ISEA_Q2DD, ISEA_PROJTRI, ISEA_VERTEX2DD, ISEA_HEX
-};
-
-struct isea_dgg {
- int polyhedron; /* ignored, icosahedron */
- double o_lat, o_lon, o_az; /* orientation, radians */
- int pole; /* true if standard snyder */
- int topology; /* ignored, hexagon */
- int aperture; /* valid values depend on partitioning method */
- int resolution;
- double radius; /* radius of the earth in meters, ignored 1.0 */
- int output; /* an isea_address_form */
- int triangle; /* triangle of last transformed point */
- int quad; /* quad of last transformed point */
- unsigned long serial;
-};
-
-struct isea_pt {
- double x, y;
-};
-
-struct isea_geo {
- double lon, lat;
-};
-
-struct isea_address {
- int type; /* enum isea_address_form */
- int number;
- double x,y; /* or i,j or lon,lat depending on type */
-};
-
-/* ENDINC */
-
-enum snyder_polyhedron {
- SNYDER_POLY_HEXAGON, SNYDER_POLY_PENTAGON,
- SNYDER_POLY_TETRAHEDRON, SNYDER_POLY_CUBE,
- SNYDER_POLY_OCTAHEDRON, SNYDER_POLY_DODECAHEDRON,
- SNYDER_POLY_ICOSAHEDRON
-};
-
-struct snyder_constants {
- double g, G, theta, ea_w, ea_a, ea_b, g_w, g_a, g_b;
-};
-
-/* TODO put these in radians to avoid a later conversion */
-ISEA_STATIC
-struct snyder_constants constants[] = {
- {23.80018260, 62.15458023, 60.0, 3.75, 1.033, 0.968, 5.09, 1.195, 1.0},
- {20.07675127, 55.69063953, 54.0, 2.65, 1.030, 0.983, 3.59, 1.141, 1.027},
- {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
- {37.37736814, 36.0, 30.0, 17.27, 1.163, 0.860, 13.14, 1.584, 1.0},
-};
-
-#define E 52.62263186
-#define F 10.81231696
-
-#define DEG60 1.04719755119659774614
-#define DEG120 2.09439510239319549229
-#define DEG72 1.25663706143591729537
-#define DEG90 1.57079632679489661922
-#define DEG144 2.51327412287183459075
-#define DEG36 0.62831853071795864768
-#define DEG108 1.88495559215387594306
-#define DEG180 M_PI
-/* sqrt(5)/M_PI */
-#define ISEA_SCALE 0.8301572857837594396028083
-
-/* 26.565051177 degrees */
-#define V_LAT 0.46364760899944494524
-
-#define RAD2DEG (180.0/M_PI)
-#define DEG2RAD (M_PI/180.0)
-
-ISEA_STATIC
-struct isea_geo vertex[] = {
- {0.0, DEG90},
- {DEG180, V_LAT},
- {-DEG108, V_LAT},
- {-DEG36, V_LAT},
- {DEG36, V_LAT},
- {DEG108, V_LAT},
- {-DEG144, -V_LAT},
- {-DEG72, -V_LAT},
- {0.0, -V_LAT},
- {DEG72, -V_LAT},
- {DEG144, -V_LAT},
- {0.0, -DEG90}
-};
-
-/* TODO make an isea_pt array of the vertices as well */
-
-static int tri_v1[] = {0, 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 2, 3, 4, 5, 1, 11, 11, 11, 11, 11};
-
-/* 52.62263186 */
-#define E_RAD 0.91843818702186776133
-
-/* 10.81231696 */
-#define F_RAD 0.18871053072122403508
-
-/* triangle Centers */
-struct isea_geo icostriangles[] = {
- {0.0, 0.0},
- {-DEG144, E_RAD},
- {-DEG72, E_RAD},
- {0.0, E_RAD},
- {DEG72, E_RAD},
- {DEG144, E_RAD},
- {-DEG144, F_RAD},
- {-DEG72, F_RAD},
- {0.0, F_RAD},
- {DEG72, F_RAD},
- {DEG144, F_RAD},
- {-DEG108, -F_RAD},
- {-DEG36, -F_RAD},
- {DEG36, -F_RAD},
- {DEG108, -F_RAD},
- {DEG180, -F_RAD},
- {-DEG108, -E_RAD},
- {-DEG36, -E_RAD},
- {DEG36, -E_RAD},
- {DEG108, -E_RAD},
- {DEG180, -E_RAD},
-};
-
-static double
-az_adjustment(int triangle)
-{
- double adj;
-
- struct isea_geo v;
- struct isea_geo c;
-
- v = vertex[tri_v1[triangle]];
- c = icostriangles[triangle];
-
- /* TODO looks like the adjustment is always either 0 or 180 */
- /* at least if you pick your vertex carefully */
- adj = atan2(cos(v.lat) * sin(v.lon - c.lon),
- cos(c.lat) * sin(v.lat)
- - sin(c.lat) * cos(v.lat) * cos(v.lon - c.lon));
- return adj;
-}
-
-/* R tan(g) sin(60) */
-#define TABLE_G 0.6615845383
-
-/* H = 0.25 R tan g = */
-#define TABLE_H 0.1909830056
-
-#define RPRIME 0.91038328153090290025
-
-ISEA_STATIC
-struct isea_pt
-isea_triangle_xy(int triangle)
-{
- struct isea_pt c;
- double Rprime = 0.91038328153090290025;
-
- triangle = (triangle - 1) % 20;
-
- c.x = TABLE_G * ((triangle % 5) - 2) * 2.0;
- if (triangle > 9) {
- c.x += TABLE_G;
- }
- switch (triangle / 5) {
- case 0:
- c.y = 5.0 * TABLE_H;
- break;
- case 1:
- c.y = TABLE_H;
- break;
- case 2:
- c.y = -TABLE_H;
- break;
- case 3:
- c.y = -5.0 * TABLE_H;
- break;
- default:
- /* should be impossible */
- exit(EXIT_FAILURE);
- };
- c.x *= Rprime;
- c.y *= Rprime;
-
- return c;
-}
-
-/* snyder eq 14 */
-static double
-sph_azimuth(double f_lon, double f_lat, double t_lon, double t_lat)
-{
- double az;
-
- az = atan2(cos(t_lat) * sin(t_lon - f_lon),
- cos(f_lat) * sin(t_lat)
- - sin(f_lat) * cos(t_lat) * cos(t_lon - f_lon)
- );
- return az;
-}
-
-/* coord needs to be in radians */
-ISEA_STATIC
-int
-isea_snyder_forward(struct isea_geo * ll, struct isea_pt * out)
-{
- int i;
-
- /*
- * spherical distance from center of polygon face to any of its
- * vertexes on the globe
- */
- double g;
-
- /*
- * spherical angle between radius vector to center and adjacent edge
- * of spherical polygon on the globe
- */
- double G;
-
- /*
- * plane angle between radius vector to center and adjacent edge of
- * plane polygon
- */
- double theta;
-
- /* additional variables from snyder */
- double q, Rprime, H, Ag, Azprime, Az, dprime, f, rho,
- x, y;
-
- /* variables used to store intermediate results */
- double cot_theta, tan_g, az_offset;
-
- /* how many multiples of 60 degrees we adjust the azimuth */
- int Az_adjust_multiples;
-
- struct snyder_constants c;
-
- /*
- * TODO by locality of reference, start by trying the same triangle
- * as last time
- */
-
- /* TODO put these constants in as radians to begin with */
- c = constants[SNYDER_POLY_ICOSAHEDRON];
- theta = c.theta * DEG2RAD;
- g = c.g * DEG2RAD;
- G = c.G * DEG2RAD;
-
- for (i = 1; i <= 20; i++) {
- double z;
- struct isea_geo center;
-
- center = icostriangles[i];
-
- /* step 1 */
- z = acos(sin(center.lat) * sin(ll->lat)
- + cos(center.lat) * cos(ll->lat) * cos(ll->lon - center.lon));
- /* not on this triangle */
- if (z > g + 0.000005) { /* TODO DBL_EPSILON */
- continue;
- }
-
- Az = sph_azimuth(center.lon, center.lat, ll->lon, ll->lat);
-
- /* step 2 */
-
- /* This calculates "some" vertex coordinate */
- az_offset = az_adjustment(i);
-
- Az -= az_offset;
-
- /* TODO I don't know why we do this. It's not in snyder */
- /* maybe because we should have picked a better vertex */
- if (Az < 0.0) {
- Az += 2.0 * M_PI;
- }
- /*
- * adjust Az for the point to fall within the range of 0 to
- * 2(90 - theta) or 60 degrees for the hexagon, by
- * and therefore 120 degrees for the triangle
- * of the icosahedron
- * subtracting or adding multiples of 60 degrees to Az and
- * recording the amount of adjustment
- */
-
- Az_adjust_multiples = 0;
- while (Az < 0.0) {
- Az += DEG120;
- Az_adjust_multiples--;
- }
- while (Az > DEG120 + DBL_EPSILON) {
- Az -= DEG120;
- Az_adjust_multiples++;
- }
-
- /* step 3 */
- cot_theta = 1.0 / tan(theta);
- tan_g = tan(g); /* TODO this is a constant */
-
- /* Calculate q from eq 9. */
- /* TODO cot_theta is cot(30) */
- q = atan2(tan_g, cos(Az) + sin(Az) * cot_theta);
-
- /* not in this triangle */
- if (z > q + 0.000005) {
- continue;
- }
- /* step 4 */
-
- /* Apply equations 5-8 and 10-12 in order */
-
- /* eq 5 */
- /* Rprime = 0.9449322893 * R; */
- /* R' in the paper is for the truncated */
- Rprime = 0.91038328153090290025;
-
- /* eq 6 */
- H = acos(sin(Az) * sin(G) * cos(g) - cos(Az) * cos(G));
-
- /* eq 7 */
- /* Ag = (Az + G + H - DEG180) * M_PI * R * R / DEG180; */
- Ag = Az + G + H - DEG180;
-
- /* eq 8 */
- Azprime = atan2(2.0 * Ag, Rprime * Rprime * tan_g * tan_g - 2.0 * Ag * cot_theta);
-
- /* eq 10 */
- /* cot(theta) = 1.73205080756887729355 */
- dprime = Rprime * tan_g / (cos(Azprime) + sin(Azprime) * cot_theta);
-
- /* eq 11 */
- f = dprime / (2.0 * Rprime * sin(q / 2.0));
-
- /* eq 12 */
- rho = 2.0 * Rprime * f * sin(z / 2.0);
-
- /*
- * add back the same 60 degree multiple adjustment from step
- * 2 to Azprime
- */
-
- Azprime += DEG120 * Az_adjust_multiples;
-
- /* calculate rectangular coordinates */
-
- x = rho * sin(Azprime);
- y = rho * cos(Azprime);
-
- /*
- * TODO
- * translate coordinates to the origin for the particular
- * hexagon on the flattened polyhedral map plot
- */
-
- out->x = x;
- out->y = y;
-
- return i;
- }
-
- /*
- * should be impossible, this implies that the coordinate is not on
- * any triangle
- */
-
- fprintf(stderr, "impossible transform: %f %f is not on any triangle\n",
- ll->lon * RAD2DEG, ll->lat * RAD2DEG);
-
- exit(EXIT_FAILURE);
-
- /* not reached */
- return 0; /* supresses a warning */
-}
-
-/*
- * return the new coordinates of any point in orginal coordinate system.
- * Define a point (newNPold) in orginal coordinate system as the North Pole in
- * new coordinate system, and the great circle connect the original and new
- * North Pole as the lon0 longitude in new coordinate system, given any point
- * in orginal coordinate system, this function return the new coordinates.
- */
-
-#define PRECISION 0.0000000000005
-
-/* formula from Snyder, Map Projections: A working manual, p31 */
-/*
- * old north pole at np in new coordinates
- * could be simplified a bit with fewer intermediates
- *
- * TODO take a result pointer
- */
-ISEA_STATIC
-struct isea_geo
-snyder_ctran(struct isea_geo * np, struct isea_geo * pt)
-{
- struct isea_geo npt;
- double alpha, phi, lambda, lambda0, beta, lambdap, phip;
- double sin_phip;
- double lp_b; /* lambda prime minus beta */
- double cos_p, sin_a;
-
- phi = pt->lat;
- lambda = pt->lon;
- alpha = np->lat;
- beta = np->lon;
- lambda0 = beta;
-
- cos_p = cos(phi);
- sin_a = sin(alpha);
-
- /* mpawm 5-7 */
- sin_phip = sin_a * sin(phi) - cos(alpha) * cos_p * cos(lambda - lambda0);
-
- /* mpawm 5-8b */
-
- /* use the two argument form so we end up in the right quadrant */
- lp_b = atan2(cos_p * sin(lambda - lambda0),
- (sin_a * cos_p * cos(lambda - lambda0) + cos(alpha) * sin(phi)));
-
- lambdap = lp_b + beta;
-
- /* normalize longitude */
- /* TODO can we just do a modulus ? */
- lambdap = fmod(lambdap, 2 * M_PI);
- while (lambdap > M_PI)
- lambdap -= 2 * M_PI;
- while (lambdap < -M_PI)
- lambdap += 2 * M_PI;
-
- phip = asin(sin_phip);
-
- npt.lat = phip;
- npt.lon = lambdap;
-
- return npt;
-}
-
-ISEA_STATIC
-struct isea_geo
-isea_ctran(struct isea_geo * np, struct isea_geo * pt, double lon0)
-{
- struct isea_geo npt;
-
- np->lon += M_PI;
- npt = snyder_ctran(np, pt);
- np->lon -= M_PI;
-
- npt.lon -= (M_PI - lon0 + np->lon);
-
- /*
- * snyder is down tri 3, isea is along side of tri1 from vertex 0 to
- * vertex 1 these are 180 degrees apart
- */
- npt.lon += M_PI;
- /* normalize longitude */
- npt.lon = fmod(npt.lon, 2 * M_PI);
- while (npt.lon > M_PI)
- npt.lon -= 2 * M_PI;
- while (npt.lon < -M_PI)
- npt.lon += 2 * M_PI;
-
- return npt;
-}
-
-/* in radians */
-#define ISEA_STD_LAT 1.01722196792335072101
-#define ISEA_STD_LON .19634954084936207740
-
-/* fuller's at 5.2454 west, 2.3009 N, adjacent at 7.46658 deg */
-
-ISEA_STATIC
-int
-isea_grid_init(struct isea_dgg * g)
-{
- if (!g)
- return 0;
-
- g->polyhedron = 20;
- g->o_lat = ISEA_STD_LAT;
- g->o_lon = ISEA_STD_LON;
- g->o_az = 0.0;
- g->aperture = 4;
- g->resolution = 6;
- g->radius = 1.0;
- g->topology = 6;
-
- return 1;
-}
-
-ISEA_STATIC
-int
-isea_orient_isea(struct isea_dgg * g)
-{
- if (!g)
- return 0;
- g->o_lat = ISEA_STD_LAT;
- g->o_lon = ISEA_STD_LON;
- g->o_az = 0.0;
- return 1;
-}
-
-ISEA_STATIC
-int
-isea_orient_pole(struct isea_dgg * g)
-{
- if (!g)
- return 0;
- g->o_lat = M_PI / 2.0;
- g->o_lon = 0.0;
- g->o_az = 0;
- return 1;
-}
-
-ISEA_STATIC
-int
-isea_transform(struct isea_dgg * g, struct isea_geo * in,
- struct isea_pt * out)
-{
- struct isea_geo i, pole;
- int tri;
-
- pole.lat = g->o_lat;
- pole.lon = g->o_lon;
-
- i = isea_ctran(&pole, in, g->o_az);
-
- tri = isea_snyder_forward(&i, out);
- out->x *= g->radius;
- out->y *= g->radius;
- g->triangle = tri;
-
- return tri;
-}
-
-#define DOWNTRI(tri) (((tri - 1) / 5) % 2 == 1)
-
-ISEA_STATIC
-void
-isea_rotate(struct isea_pt * pt, double degrees)
-{
- double rad;
-
- double x, y;
-
- rad = -degrees * M_PI / 180.0;
- while (rad >= 2.0 * M_PI) rad -= 2.0 * M_PI;
- while (rad <= -2.0 * M_PI) rad += 2.0 * M_PI;
-
- x = pt->x * cos(rad) + pt->y * sin(rad);
- y = -pt->x * sin(rad) + pt->y * cos(rad);
-
- pt->x = x;
- pt->y = y;
-}
-
-ISEA_STATIC
-int isea_tri_plane(int tri, struct isea_pt *pt, double radius) {
- struct isea_pt tc; /* center of triangle */
-
- if (DOWNTRI(tri)) {
- isea_rotate(pt, 180.0);
- }
- tc = isea_triangle_xy(tri);
- tc.x *= radius;
- tc.y *= radius;
- pt->x += tc.x;
- pt->y += tc.y;
-
- return tri;
-}
-
-/* convert projected triangle coords to quad xy coords, return quad number */
-ISEA_STATIC
-int
-isea_ptdd(int tri, struct isea_pt *pt) {
- int downtri, quad;
-
- downtri = (((tri - 1) / 5) % 2 == 1);
- quad = ((tri - 1) % 5) + ((tri - 1) / 10) * 5 + 1;
-
- isea_rotate(pt, downtri ? 240.0 : 60.0);
- if (downtri) {
- pt->x += 0.5;
- /* pt->y += cos(30.0 * M_PI / 180.0); */
- pt->y += .86602540378443864672;
- }
- return quad;
-}
-
-ISEA_STATIC
-int
-isea_dddi_ap3odd(struct isea_dgg *g, int quad, struct isea_pt *pt, struct isea_pt *di)
-{
- struct isea_pt v;
- double hexwidth;
- double sidelength; /* in hexes */
- int d, i;
- int maxcoord;
- struct hex h;
-
- /* This is the number of hexes from apex to base of a triangle */
- sidelength = (pow(2.0, g->resolution) + 1.0) / 2.0;
-
- /* apex to base is cos(30deg) */
- hexwidth = cos(M_PI / 6.0) / sidelength;
-
- /* TODO I think sidelength is always x.5, so
- * (int)sidelength * 2 + 1 might be just as good
- */
- maxcoord = (int) (sidelength * 2.0 + 0.5);
-
- v = *pt;
- hexbin2(hexwidth, v.x, v.y, &h.x, &h.y);
- h.iso = 0;
- hex_iso(&h);
-
- d = h.x - h.z;
- i = h.x + h.y + h.y;
-
- /*
- * you want to test for max coords for the next quad in the same
- * "row" first to get the case where both are max
- */
- if (quad <= 5) {
- if (d == 0 && i == maxcoord) {
- /* north pole */
- quad = 0;
- d = 0;
- i = 0;
- } else if (i == maxcoord) {
- /* upper right in next quad */
- quad += 1;
- if (quad == 6)
- quad = 1;
- i = maxcoord - d;
- d = 0;
- } else if (d == maxcoord) {
- /* lower right in quad to lower right */
- quad += 5;
- d = 0;
- }
- } else if (quad >= 6) {
- if (i == 0 && d == maxcoord) {
- /* south pole */
- quad = 11;
- d = 0;
- i = 0;
- } else if (d == maxcoord) {
- /* lower right in next quad */
- quad += 1;
- if (quad == 11)
- quad = 6;
- d = maxcoord - i;
- i = 0;
- } else if (i == maxcoord) {
- /* upper right in quad to upper right */
- quad = (quad - 4) % 5;
- i = 0;
- }
- }
-
- di->x = d;
- di->y = i;
-
- g->quad = quad;
- return quad;
-}
-
-ISEA_STATIC
-int
-isea_dddi(struct isea_dgg *g, int quad, struct isea_pt *pt, struct isea_pt *di) {
- struct isea_pt v;
- double hexwidth;
- int sidelength; /* in hexes */
- struct hex h;
-
- if (g->aperture == 3 && g->resolution % 2 != 0) {
- return isea_dddi_ap3odd(g, quad, pt, di);
- }
- /* todo might want to do this as an iterated loop */
- if (g->aperture >0) {
- sidelength = (int) (pow(g->aperture, g->resolution / 2.0) + 0.5);
- } else {
- sidelength = g->resolution;
- }
-
- hexwidth = 1.0 / sidelength;
-
- v = *pt;
- isea_rotate(&v, -30.0);
- hexbin2(hexwidth, v.x, v.y, &h.x, &h.y);
- h.iso = 0;
- hex_iso(&h);
-
- /* we may actually be on another quad */
- if (quad <= 5) {
- if (h.x == 0 && h.z == -sidelength) {
- /* north pole */
- quad = 0;
- h.z = 0;
- h.y = 0;
- h.x = 0;
- } else if (h.z == -sidelength) {
- quad = quad + 1;
- if (quad == 6)
- quad = 1;
- h.y = sidelength - h.x;
- h.z = h.x - sidelength;
- h.x = 0;
- } else if (h.x == sidelength) {
- quad += 5;
- h.y = -h.z;
- h.x = 0;
- }
- } else if (quad >= 6) {
- if (h.z == 0 && h.x == sidelength) {
- /* south pole */
- quad = 11;
- h.x = 0;
- h.y = 0;
- h.z = 0;
- } else if (h.x == sidelength) {
- quad = quad + 1;
- if (quad == 11)
- quad = 6;
- h.x = h.y + sidelength;
- h.y = 0;
- h.z = -h.x;
- } else if (h.y == -sidelength) {
- quad -= 4;
- h.y = 0;
- h.z = -h.x;
- }
- }
- di->x = h.x;
- di->y = -h.z;
-
- g->quad = quad;
- return quad;
-}
-
-ISEA_STATIC
-int isea_ptdi(struct isea_dgg *g, int tri, struct isea_pt *pt,
- struct isea_pt *di) {
- struct isea_pt v;
- int quad;
-
- v = *pt;
- quad = isea_ptdd(tri, &v);
- quad = isea_dddi(g, quad, &v, di);
- return quad;
-}
-
-/* q2di to seqnum */
-ISEA_STATIC
-int isea_disn(struct isea_dgg *g, int quad, struct isea_pt *di) {
- int sidelength;
- int sn, height;
- int hexes;
-
- if (quad == 0) {
- g->serial = 1;
- return g->serial;
- }
- /* hexes in a quad */
- hexes = (int) (pow(g->aperture, g->resolution) + 0.5);
- if (quad == 11) {
- g->serial = 1 + 10 * hexes + 1;
- return g->serial;
- }
- if (g->aperture == 3 && g->resolution % 2 == 1) {
- height = (int) (pow(g->aperture, (g->resolution - 1) / 2.0));
- sn = ((int) di->x) * height;
- sn += ((int) di->y) / height;
- sn += (quad - 1) * hexes;
- sn += 2;
- } else {
- sidelength = (int) (pow(g->aperture, g->resolution / 2.0) + 0.5);
- sn = (quad - 1) * hexes + sidelength * di->x + di->y + 2;
- }
-
- g->serial = sn;
- return sn;
-}
-
-/* TODO just encode the quad in the d or i coordinate
- * quad is 0-11, which can be four bits.
- * d' = d << 4 + q, d = d' >> 4, q = d' & 0xf
- */
-/* convert a q2di to global hex coord */
-ISEA_STATIC
-int isea_hex(struct isea_dgg *g, int tri,
- struct isea_pt *pt, struct isea_pt *hex) {
- struct isea_pt v;
- int sidelength;
- int d, i, x, y, quad;
-
- quad = isea_ptdi(g, tri, pt, &v);
-
- hex->x = ((int)v.x << 4) + quad;
- hex->y = v.y;
-
- return 1;
-
- d = v.x;
- i = v.y;
-
- /* Aperture 3 odd resolutions */
- if (g->aperture == 3 && g->resolution % 2 != 0) {
- int offset = (int)(pow(3.0, g->resolution - 1) + 0.5);
-
- d += offset * ((g->quad-1) % 5);
- i += offset * ((g->quad-1) % 5);
-
- if (quad == 0) {
- d = 0;
- i = offset;
- } else if (quad == 11) {
- d = 2 * offset;
- i = 0;
- } else if (quad > 5) {
- d += offset;
- }
-
- x = (2*d - i) /3;
- y = (2*i - d) /3;
-
- hex->x = x + offset / 3;
- hex->y = y + 2 * offset / 3;
- return 1;
- }
-
- /* aperture 3 even resolutions and aperture 4 */
- sidelength = (int) (pow(g->aperture, g->resolution / 2.0) + 0.5);
- if (g->quad == 0) {
- hex->x = 0;
- hex->y = sidelength;
- } else if (g->quad == 11) {
- hex->x = sidelength * 2;
- hex->y = 0;
- } else {
- hex->x = d + sidelength * ((g->quad-1) % 5);
- if (g->quad > 5) hex->x += sidelength;
- hex->y = i + sidelength * ((g->quad-1) % 5);
- }
-
- return 1;
-}
-
-ISEA_STATIC
-struct isea_pt
-isea_forward(struct isea_dgg *g, struct isea_geo *in)
-{
- int tri;
- struct isea_pt out, coord;
-
- tri = isea_transform(g, in, &out);
-
- if (g->output == ISEA_PLANE) {
- isea_tri_plane(tri, &out, g->radius);
- return out;
- }
-
- /* convert to isea standard triangle size */
- out.x = out.x / g->radius * ISEA_SCALE;
- out.y = out.y / g->radius * ISEA_SCALE;
- out.x += 0.5;
- out.y += 2.0 * .14433756729740644112;
-
- switch (g->output) {
- case ISEA_PROJTRI:
- /* nothing to do, already in projected triangle */
- break;
- case ISEA_VERTEX2DD:
- g->quad = isea_ptdd(tri, &out);
- break;
- case ISEA_Q2DD:
- /* Same as above, we just don't print as much */
- g->quad = isea_ptdd(tri, &out);
- break;
- case ISEA_Q2DI:
- g->quad = isea_ptdi(g, tri, &out, &coord);
- return coord;
- break;
- case ISEA_SEQNUM:
- isea_ptdi(g, tri, &out, &coord);
- /* disn will set g->serial */
- isea_disn(g, g->quad, &coord);
- return coord;
- break;
- case ISEA_HEX:
- isea_hex(g, tri, &out, &coord);
- return coord;
- break;
- }
-
- return out;
-}
-/*
- * Proj 4 integration code follows
- */
-
-#define PROJ_PARMS__ \
- struct isea_dgg dgg;
-
-#define PJ_LIB__
-#include <projects.h>
-
-PROJ_HEAD(isea, "Icosahedral Snyder Equal Area") "\n\tSph";
-
-FORWARD(s_forward);
- struct isea_pt out;
- struct isea_geo in;
-
- in.lon = lp.lam;
- in.lat = lp.phi;
-
- out = isea_forward(&P->dgg, &in);
-
- xy.x = out.x;
- xy.y = out.y;
-
- return xy;
-}
-FREEUP; if (P) pj_dalloc(P); }
-
-ENTRY0(isea)
- char *opt;
-
- P->fwd = s_forward;
- isea_grid_init(&P->dgg);
-
- P->dgg.output = ISEA_PLANE;
-/* P->dgg.radius = P->a; / * otherwise defaults to 1 */
- /* calling library will scale, I think */
-
- opt = pj_param(P->ctx,P->params, "sorient").s;
- if (opt) {
- if (!strcmp(opt, "isea")) {
- isea_orient_isea(&P->dgg);
- } else if (!strcmp(opt, "pole")) {
- isea_orient_pole(&P->dgg);
- } else {
- E_ERROR(-34);
- }
- }
-
- if (pj_param(P->ctx,P->params, "tazi").i) {
- P->dgg.o_az = pj_param(P->ctx,P->params, "razi").f;
- }
-
- if (pj_param(P->ctx,P->params, "tlon_0").i) {
- P->dgg.o_lon = pj_param(P->ctx,P->params, "rlon_0").f;
- }
-
- if (pj_param(P->ctx,P->params, "tlat_0").i) {
- P->dgg.o_lat = pj_param(P->ctx,P->params, "rlat_0").f;
- }
-
- if (pj_param(P->ctx,P->params, "taperture").i) {
- P->dgg.aperture = pj_param(P->ctx,P->params, "iaperture").i;
- }
-
- if (pj_param(P->ctx,P->params, "tresolution").i) {
- P->dgg.resolution = pj_param(P->ctx,P->params, "iresolution").i;
- }
-
- opt = pj_param(P->ctx,P->params, "smode").s;
- if (opt) {
- if (!strcmp(opt, "plane")) {
- P->dgg.output = ISEA_PLANE;
- } else if (!strcmp(opt, "di")) {
- P->dgg.output = ISEA_Q2DI;
- }
- else if (!strcmp(opt, "dd")) {
- P->dgg.output = ISEA_Q2DD;
- }
- else if (!strcmp(opt, "hex")) {
- P->dgg.output = ISEA_HEX;
- }
- else {
- /* TODO verify error code. Possibly eliminate magic */
- E_ERROR(-34);
- }
- }
-
- if (pj_param(P->ctx,P->params, "trescale").i) {
- P->dgg.radius = ISEA_SCALE;
- }
-
- if (pj_param(P->ctx,P->params, "tresolution").i) {
- P->dgg.resolution = pj_param(P->ctx,P->params, "iresolution").i;
- } else {
- P->dgg.resolution = 4;
- }
-
- if (pj_param(P->ctx,P->params, "taperture").i) {
- P->dgg.aperture = pj_param(P->ctx,P->params, "iaperture").i;
- } else {
- P->dgg.aperture = 3;
- }
-
-ENDENTRY(P)
+/*
+ * This code was entirely written by Nathan Wagner
+ * and is in the public domain.
+ */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <float.h>
+
+#ifndef M_PI
+# define M_PI 3.14159265358979323846
+#endif
+
+/*
+ * Proj 4 provides its own entry points into
+ * the code, so none of the library functions
+ * need to be global
+ */
+#define ISEA_STATIC static
+#ifndef ISEA_STATIC
+#define ISEA_STATIC
+#endif
+
+struct hex {
+ int iso;
+ int x, y, z;
+};
+
+/* y *must* be positive down as the xy /iso conversion assumes this */
+ISEA_STATIC
+int hex_xy(struct hex *h) {
+ if (!h->iso) return 1;
+ if (h->x >= 0) {
+ h->y = -h->y - (h->x+1)/2;
+ } else {
+ /* need to round toward -inf, not toward zero, so x-1 */
+ h->y = -h->y - h->x/2;
+ }
+ h->iso = 0;
+
+ return 1;
+}
+
+ISEA_STATIC
+int hex_iso(struct hex *h) {
+ if (h->iso) return 1;
+
+ if (h->x >= 0) {
+ h->y = (-h->y - (h->x+1)/2);
+ } else {
+ /* need to round toward -inf, not toward zero, so x-1 */
+ h->y = (-h->y - (h->x)/2);
+ }
+
+ h->z = -h->x - h->y;
+ h->iso = 1;
+ return 1;
+}
+
+ISEA_STATIC
+int hexbin2(double width, double x, double y,
+ int *i, int *j) {
+ double z, rx, ry, rz;
+ double abs_dx, abs_dy, abs_dz;
+ int ix, iy, iz, s;
+ struct hex h;
+
+ x = x / cos(30 * M_PI / 180.0); /* rotated X coord */
+ y = y - x / 2.0; /* adjustment for rotated X */
+
+ /* adjust for actual hexwidth */
+ x /= width;
+ y /= width;
+
+ z = -x - y;
+
+ ix = rx = floor(x + 0.5);
+ iy = ry = floor(y + 0.5);
+ iz = rz = floor(z + 0.5);
+
+ s = ix + iy + iz;
+
+ if (s) {
+ abs_dx = fabs(rx - x);
+ abs_dy = fabs(ry - y);
+ abs_dz = fabs(rz - z);
+
+ if (abs_dx >= abs_dy && abs_dx >= abs_dz) {
+ ix -= s;
+ } else if (abs_dy >= abs_dx && abs_dy >= abs_dz) {
+ iy -= s;
+ } else {
+ iz -= s;
+ }
+ }
+ h.x = ix;
+ h.y = iy;
+ h.z = iz;
+ h.iso = 1;
+
+ hex_xy(&h);
+ *i = h.x;
+ *j = h.y;
+ return ix * 100 + iy;
+}
+#ifndef ISEA_STATIC
+#define ISEA_STATIC
+#endif
+
+enum isea_poly { ISEA_NONE, ISEA_ICOSAHEDRON = 20 };
+enum isea_topology { ISEA_HEXAGON=6, ISEA_TRIANGLE=3, ISEA_DIAMOND=4 };
+enum isea_address_form { ISEA_GEO, ISEA_Q2DI, ISEA_SEQNUM, ISEA_INTERLEAVE,
+ ISEA_PLANE, ISEA_Q2DD, ISEA_PROJTRI, ISEA_VERTEX2DD, ISEA_HEX
+};
+
+struct isea_dgg {
+ int polyhedron; /* ignored, icosahedron */
+ double o_lat, o_lon, o_az; /* orientation, radians */
+ int pole; /* true if standard snyder */
+ int topology; /* ignored, hexagon */
+ int aperture; /* valid values depend on partitioning method */
+ int resolution;
+ double radius; /* radius of the earth in meters, ignored 1.0 */
+ int output; /* an isea_address_form */
+ int triangle; /* triangle of last transformed point */
+ int quad; /* quad of last transformed point */
+ unsigned long serial;
+};
+
+struct isea_pt {
+ double x, y;
+};
+
+struct isea_geo {
+ double lon, lat;
+};
+
+struct isea_address {
+ int type; /* enum isea_address_form */
+ int number;
+ double x,y; /* or i,j or lon,lat depending on type */
+};
+
+/* ENDINC */
+
+enum snyder_polyhedron {
+ SNYDER_POLY_HEXAGON, SNYDER_POLY_PENTAGON,
+ SNYDER_POLY_TETRAHEDRON, SNYDER_POLY_CUBE,
+ SNYDER_POLY_OCTAHEDRON, SNYDER_POLY_DODECAHEDRON,
+ SNYDER_POLY_ICOSAHEDRON
+};
+
+struct snyder_constants {
+ double g, G, theta, ea_w, ea_a, ea_b, g_w, g_a, g_b;
+};
+
+/* TODO put these in radians to avoid a later conversion */
+ISEA_STATIC
+struct snyder_constants constants[] = {
+ {23.80018260, 62.15458023, 60.0, 3.75, 1.033, 0.968, 5.09, 1.195, 1.0},
+ {20.07675127, 55.69063953, 54.0, 2.65, 1.030, 0.983, 3.59, 1.141, 1.027},
+ {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
+ {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
+ {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
+ {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
+ {37.37736814, 36.0, 30.0, 17.27, 1.163, 0.860, 13.14, 1.584, 1.0},
+};
+
+#define E 52.62263186
+#define F 10.81231696
+
+#define DEG60 1.04719755119659774614
+#define DEG120 2.09439510239319549229
+#define DEG72 1.25663706143591729537
+#define DEG90 1.57079632679489661922
+#define DEG144 2.51327412287183459075
+#define DEG36 0.62831853071795864768
+#define DEG108 1.88495559215387594306
+#define DEG180 M_PI
+/* sqrt(5)/M_PI */
+#define ISEA_SCALE 0.8301572857837594396028083
+
+/* 26.565051177 degrees */
+#define V_LAT 0.46364760899944494524
+
+#define RAD2DEG (180.0/M_PI)
+#define DEG2RAD (M_PI/180.0)
+
+ISEA_STATIC
+struct isea_geo vertex[] = {
+ {0.0, DEG90},
+ {DEG180, V_LAT},
+ {-DEG108, V_LAT},
+ {-DEG36, V_LAT},
+ {DEG36, V_LAT},
+ {DEG108, V_LAT},
+ {-DEG144, -V_LAT},
+ {-DEG72, -V_LAT},
+ {0.0, -V_LAT},
+ {DEG72, -V_LAT},
+ {DEG144, -V_LAT},
+ {0.0, -DEG90}
+};
+
+/* TODO make an isea_pt array of the vertices as well */
+
+static int tri_v1[] = {0, 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 2, 3, 4, 5, 1, 11, 11, 11, 11, 11};
+
+/* 52.62263186 */
+#define E_RAD 0.91843818702186776133
+
+/* 10.81231696 */
+#define F_RAD 0.18871053072122403508
+
+/* triangle Centers */
+struct isea_geo icostriangles[] = {
+ {0.0, 0.0},
+ {-DEG144, E_RAD},
+ {-DEG72, E_RAD},
+ {0.0, E_RAD},
+ {DEG72, E_RAD},
+ {DEG144, E_RAD},
+ {-DEG144, F_RAD},
+ {-DEG72, F_RAD},
+ {0.0, F_RAD},
+ {DEG72, F_RAD},
+ {DEG144, F_RAD},
+ {-DEG108, -F_RAD},
+ {-DEG36, -F_RAD},
+ {DEG36, -F_RAD},
+ {DEG108, -F_RAD},
+ {DEG180, -F_RAD},
+ {-DEG108, -E_RAD},
+ {-DEG36, -E_RAD},
+ {DEG36, -E_RAD},
+ {DEG108, -E_RAD},
+ {DEG180, -E_RAD},
+};
+
+static double
+az_adjustment(int triangle)
+{
+ double adj;
+
+ struct isea_geo v;
+ struct isea_geo c;
+
+ v = vertex[tri_v1[triangle]];
+ c = icostriangles[triangle];
+
+ /* TODO looks like the adjustment is always either 0 or 180 */
+ /* at least if you pick your vertex carefully */
+ adj = atan2(cos(v.lat) * sin(v.lon - c.lon),
+ cos(c.lat) * sin(v.lat)
+ - sin(c.lat) * cos(v.lat) * cos(v.lon - c.lon));
+ return adj;
+}
+
+/* R tan(g) sin(60) */
+#define TABLE_G 0.6615845383
+
+/* H = 0.25 R tan g = */
+#define TABLE_H 0.1909830056
+
+#define RPRIME 0.91038328153090290025
+
+ISEA_STATIC
+struct isea_pt
+isea_triangle_xy(int triangle)
+{
+ struct isea_pt c;
+ double Rprime = 0.91038328153090290025;
+
+ triangle = (triangle - 1) % 20;
+
+ c.x = TABLE_G * ((triangle % 5) - 2) * 2.0;
+ if (triangle > 9) {
+ c.x += TABLE_G;
+ }
+ switch (triangle / 5) {
+ case 0:
+ c.y = 5.0 * TABLE_H;
+ break;
+ case 1:
+ c.y = TABLE_H;
+ break;
+ case 2:
+ c.y = -TABLE_H;
+ break;
+ case 3:
+ c.y = -5.0 * TABLE_H;
+ break;
+ default:
+ /* should be impossible */
+ exit(EXIT_FAILURE);
+ };
+ c.x *= Rprime;
+ c.y *= Rprime;
+
+ return c;
+}
+
+/* snyder eq 14 */
+static double
+sph_azimuth(double f_lon, double f_lat, double t_lon, double t_lat)
+{
+ double az;
+
+ az = atan2(cos(t_lat) * sin(t_lon - f_lon),
+ cos(f_lat) * sin(t_lat)
+ - sin(f_lat) * cos(t_lat) * cos(t_lon - f_lon)
+ );
+ return az;
+}
+
+/* coord needs to be in radians */
+ISEA_STATIC
+int
+isea_snyder_forward(struct isea_geo * ll, struct isea_pt * out)
+{
+ int i;
+
+ /*
+ * spherical distance from center of polygon face to any of its
+ * vertexes on the globe
+ */
+ double g;
+
+ /*
+ * spherical angle between radius vector to center and adjacent edge
+ * of spherical polygon on the globe
+ */
+ double G;
+
+ /*
+ * plane angle between radius vector to center and adjacent edge of
+ * plane polygon
+ */
+ double theta;
+
+ /* additional variables from snyder */
+ double q, Rprime, H, Ag, Azprime, Az, dprime, f, rho,
+ x, y;
+
+ /* variables used to store intermediate results */
+ double cot_theta, tan_g, az_offset;
+
+ /* how many multiples of 60 degrees we adjust the azimuth */
+ int Az_adjust_multiples;
+
+ struct snyder_constants c;
+
+ /*
+ * TODO by locality of reference, start by trying the same triangle
+ * as last time
+ */
+
+ /* TODO put these constants in as radians to begin with */
+ c = constants[SNYDER_POLY_ICOSAHEDRON];
+ theta = c.theta * DEG2RAD;
+ g = c.g * DEG2RAD;
+ G = c.G * DEG2RAD;
+
+ for (i = 1; i <= 20; i++) {
+ double z;
+ struct isea_geo center;
+
+ center = icostriangles[i];
+
+ /* step 1 */
+ z = acos(sin(center.lat) * sin(ll->lat)
+ + cos(center.lat) * cos(ll->lat) * cos(ll->lon - center.lon));
+ /* not on this triangle */
+ if (z > g + 0.000005) { /* TODO DBL_EPSILON */
+ continue;
+ }
+
+ Az = sph_azimuth(center.lon, center.lat, ll->lon, ll->lat);
+
+ /* step 2 */
+
+ /* This calculates "some" vertex coordinate */
+ az_offset = az_adjustment(i);
+
+ Az -= az_offset;
+
+ /* TODO I don't know why we do this. It's not in snyder */
+ /* maybe because we should have picked a better vertex */
+ if (Az < 0.0) {
+ Az += 2.0 * M_PI;
+ }
+ /*
+ * adjust Az for the point to fall within the range of 0 to
+ * 2(90 - theta) or 60 degrees for the hexagon, by
+ * and therefore 120 degrees for the triangle
+ * of the icosahedron
+ * subtracting or adding multiples of 60 degrees to Az and
+ * recording the amount of adjustment
+ */
+
+ Az_adjust_multiples = 0;
+ while (Az < 0.0) {
+ Az += DEG120;
+ Az_adjust_multiples--;
+ }
+ while (Az > DEG120 + DBL_EPSILON) {
+ Az -= DEG120;
+ Az_adjust_multiples++;
+ }
+
+ /* step 3 */
+ cot_theta = 1.0 / tan(theta);
+ tan_g = tan(g); /* TODO this is a constant */
+
+ /* Calculate q from eq 9. */
+ /* TODO cot_theta is cot(30) */
+ q = atan2(tan_g, cos(Az) + sin(Az) * cot_theta);
+
+ /* not in this triangle */
+ if (z > q + 0.000005) {
+ continue;
+ }
+ /* step 4 */
+
+ /* Apply equations 5-8 and 10-12 in order */
+
+ /* eq 5 */
+ /* Rprime = 0.9449322893 * R; */
+ /* R' in the paper is for the truncated */
+ Rprime = 0.91038328153090290025;
+
+ /* eq 6 */
+ H = acos(sin(Az) * sin(G) * cos(g) - cos(Az) * cos(G));
+
+ /* eq 7 */
+ /* Ag = (Az + G + H - DEG180) * M_PI * R * R / DEG180; */
+ Ag = Az + G + H - DEG180;
+
+ /* eq 8 */
+ Azprime = atan2(2.0 * Ag, Rprime * Rprime * tan_g * tan_g - 2.0 * Ag * cot_theta);
+
+ /* eq 10 */
+ /* cot(theta) = 1.73205080756887729355 */
+ dprime = Rprime * tan_g / (cos(Azprime) + sin(Azprime) * cot_theta);
+
+ /* eq 11 */
+ f = dprime / (2.0 * Rprime * sin(q / 2.0));
+
+ /* eq 12 */
+ rho = 2.0 * Rprime * f * sin(z / 2.0);
+
+ /*
+ * add back the same 60 degree multiple adjustment from step
+ * 2 to Azprime
+ */
+
+ Azprime += DEG120 * Az_adjust_multiples;
+
+ /* calculate rectangular coordinates */
+
+ x = rho * sin(Azprime);
+ y = rho * cos(Azprime);
+
+ /*
+ * TODO
+ * translate coordinates to the origin for the particular
+ * hexagon on the flattened polyhedral map plot
+ */
+
+ out->x = x;
+ out->y = y;
+
+ return i;
+ }
+
+ /*
+ * should be impossible, this implies that the coordinate is not on
+ * any triangle
+ */
+
+ fprintf(stderr, "impossible transform: %f %f is not on any triangle\n",
+ ll->lon * RAD2DEG, ll->lat * RAD2DEG);
+
+ exit(EXIT_FAILURE);
+
+ /* not reached */
+ return 0; /* supresses a warning */
+}
+
+/*
+ * return the new coordinates of any point in orginal coordinate system.
+ * Define a point (newNPold) in orginal coordinate system as the North Pole in
+ * new coordinate system, and the great circle connect the original and new
+ * North Pole as the lon0 longitude in new coordinate system, given any point
+ * in orginal coordinate system, this function return the new coordinates.
+ */
+
+#define PRECISION 0.0000000000005
+
+/* formula from Snyder, Map Projections: A working manual, p31 */
+/*
+ * old north pole at np in new coordinates
+ * could be simplified a bit with fewer intermediates
+ *
+ * TODO take a result pointer
+ */
+ISEA_STATIC
+struct isea_geo
+snyder_ctran(struct isea_geo * np, struct isea_geo * pt)
+{
+ struct isea_geo npt;
+ double alpha, phi, lambda, lambda0, beta, lambdap, phip;
+ double sin_phip;
+ double lp_b; /* lambda prime minus beta */
+ double cos_p, sin_a;
+
+ phi = pt->lat;
+ lambda = pt->lon;
+ alpha = np->lat;
+ beta = np->lon;
+ lambda0 = beta;
+
+ cos_p = cos(phi);
+ sin_a = sin(alpha);
+
+ /* mpawm 5-7 */
+ sin_phip = sin_a * sin(phi) - cos(alpha) * cos_p * cos(lambda - lambda0);
+
+ /* mpawm 5-8b */
+
+ /* use the two argument form so we end up in the right quadrant */
+ lp_b = atan2(cos_p * sin(lambda - lambda0),
+ (sin_a * cos_p * cos(lambda - lambda0) + cos(alpha) * sin(phi)));
+
+ lambdap = lp_b + beta;
+
+ /* normalize longitude */
+ /* TODO can we just do a modulus ? */
+ lambdap = fmod(lambdap, 2 * M_PI);
+ while (lambdap > M_PI)
+ lambdap -= 2 * M_PI;
+ while (lambdap < -M_PI)
+ lambdap += 2 * M_PI;
+
+ phip = asin(sin_phip);
+
+ npt.lat = phip;
+ npt.lon = lambdap;
+
+ return npt;
+}
+
+ISEA_STATIC
+struct isea_geo
+isea_ctran(struct isea_geo * np, struct isea_geo * pt, double lon0)
+{
+ struct isea_geo npt;
+
+ np->lon += M_PI;
+ npt = snyder_ctran(np, pt);
+ np->lon -= M_PI;
+
+ npt.lon -= (M_PI - lon0 + np->lon);
+
+ /*
+ * snyder is down tri 3, isea is along side of tri1 from vertex 0 to
+ * vertex 1 these are 180 degrees apart
+ */
+ npt.lon += M_PI;
+ /* normalize longitude */
+ npt.lon = fmod(npt.lon, 2 * M_PI);
+ while (npt.lon > M_PI)
+ npt.lon -= 2 * M_PI;
+ while (npt.lon < -M_PI)
+ npt.lon += 2 * M_PI;
+
+ return npt;
+}
+
+/* in radians */
+#define ISEA_STD_LAT 1.01722196792335072101
+#define ISEA_STD_LON .19634954084936207740
+
+/* fuller's at 5.2454 west, 2.3009 N, adjacent at 7.46658 deg */
+
+ISEA_STATIC
+int
+isea_grid_init(struct isea_dgg * g)
+{
+ if (!g)
+ return 0;
+
+ g->polyhedron = 20;
+ g->o_lat = ISEA_STD_LAT;
+ g->o_lon = ISEA_STD_LON;
+ g->o_az = 0.0;
+ g->aperture = 4;
+ g->resolution = 6;
+ g->radius = 1.0;
+ g->topology = 6;
+
+ return 1;
+}
+
+ISEA_STATIC
+int
+isea_orient_isea(struct isea_dgg * g)
+{
+ if (!g)
+ return 0;
+ g->o_lat = ISEA_STD_LAT;
+ g->o_lon = ISEA_STD_LON;
+ g->o_az = 0.0;
+ return 1;
+}
+
+ISEA_STATIC
+int
+isea_orient_pole(struct isea_dgg * g)
+{
+ if (!g)
+ return 0;
+ g->o_lat = M_PI / 2.0;
+ g->o_lon = 0.0;
+ g->o_az = 0;
+ return 1;
+}
+
+ISEA_STATIC
+int
+isea_transform(struct isea_dgg * g, struct isea_geo * in,
+ struct isea_pt * out)
+{
+ struct isea_geo i, pole;
+ int tri;
+
+ pole.lat = g->o_lat;
+ pole.lon = g->o_lon;
+
+ i = isea_ctran(&pole, in, g->o_az);
+
+ tri = isea_snyder_forward(&i, out);
+ out->x *= g->radius;
+ out->y *= g->radius;
+ g->triangle = tri;
+
+ return tri;
+}
+
+#define DOWNTRI(tri) (((tri - 1) / 5) % 2 == 1)
+
+ISEA_STATIC
+void
+isea_rotate(struct isea_pt * pt, double degrees)
+{
+ double rad;
+
+ double x, y;
+
+ rad = -degrees * M_PI / 180.0;
+ while (rad >= 2.0 * M_PI) rad -= 2.0 * M_PI;
+ while (rad <= -2.0 * M_PI) rad += 2.0 * M_PI;
+
+ x = pt->x * cos(rad) + pt->y * sin(rad);
+ y = -pt->x * sin(rad) + pt->y * cos(rad);
+
+ pt->x = x;
+ pt->y = y;
+}
+
+ISEA_STATIC
+int isea_tri_plane(int tri, struct isea_pt *pt, double radius) {
+ struct isea_pt tc; /* center of triangle */
+
+ if (DOWNTRI(tri)) {
+ isea_rotate(pt, 180.0);
+ }
+ tc = isea_triangle_xy(tri);
+ tc.x *= radius;
+ tc.y *= radius;
+ pt->x += tc.x;
+ pt->y += tc.y;
+
+ return tri;
+}
+
+/* convert projected triangle coords to quad xy coords, return quad number */
+ISEA_STATIC
+int
+isea_ptdd(int tri, struct isea_pt *pt) {
+ int downtri, quad;
+
+ downtri = (((tri - 1) / 5) % 2 == 1);
+ quad = ((tri - 1) % 5) + ((tri - 1) / 10) * 5 + 1;
+
+ isea_rotate(pt, downtri ? 240.0 : 60.0);
+ if (downtri) {
+ pt->x += 0.5;
+ /* pt->y += cos(30.0 * M_PI / 180.0); */
+ pt->y += .86602540378443864672;
+ }
+ return quad;
+}
+
+ISEA_STATIC
+int
+isea_dddi_ap3odd(struct isea_dgg *g, int quad, struct isea_pt *pt, struct isea_pt *di)
+{
+ struct isea_pt v;
+ double hexwidth;
+ double sidelength; /* in hexes */
+ int d, i;
+ int maxcoord;
+ struct hex h;
+
+ /* This is the number of hexes from apex to base of a triangle */
+ sidelength = (pow(2.0, g->resolution) + 1.0) / 2.0;
+
+ /* apex to base is cos(30deg) */
+ hexwidth = cos(M_PI / 6.0) / sidelength;
+
+ /* TODO I think sidelength is always x.5, so
+ * (int)sidelength * 2 + 1 might be just as good
+ */
+ maxcoord = (int) (sidelength * 2.0 + 0.5);
+
+ v = *pt;
+ hexbin2(hexwidth, v.x, v.y, &h.x, &h.y);
+ h.iso = 0;
+ hex_iso(&h);
+
+ d = h.x - h.z;
+ i = h.x + h.y + h.y;
+
+ /*
+ * you want to test for max coords for the next quad in the same
+ * "row" first to get the case where both are max
+ */
+ if (quad <= 5) {
+ if (d == 0 && i == maxcoord) {
+ /* north pole */
+ quad = 0;
+ d = 0;
+ i = 0;
+ } else if (i == maxcoord) {
+ /* upper right in next quad */
+ quad += 1;
+ if (quad == 6)
+ quad = 1;
+ i = maxcoord - d;
+ d = 0;
+ } else if (d == maxcoord) {
+ /* lower right in quad to lower right */
+ quad += 5;
+ d = 0;
+ }
+ } else if (quad >= 6) {
+ if (i == 0 && d == maxcoord) {
+ /* south pole */
+ quad = 11;
+ d = 0;
+ i = 0;
+ } else if (d == maxcoord) {
+ /* lower right in next quad */
+ quad += 1;
+ if (quad == 11)
+ quad = 6;
+ d = maxcoord - i;
+ i = 0;
+ } else if (i == maxcoord) {
+ /* upper right in quad to upper right */
+ quad = (quad - 4) % 5;
+ i = 0;
+ }
+ }
+
+ di->x = d;
+ di->y = i;
+
+ g->quad = quad;
+ return quad;
+}
+
+ISEA_STATIC
+int
+isea_dddi(struct isea_dgg *g, int quad, struct isea_pt *pt, struct isea_pt *di) {
+ struct isea_pt v;
+ double hexwidth;
+ int sidelength; /* in hexes */
+ struct hex h;
+
+ if (g->aperture == 3 && g->resolution % 2 != 0) {
+ return isea_dddi_ap3odd(g, quad, pt, di);
+ }
+ /* todo might want to do this as an iterated loop */
+ if (g->aperture >0) {
+ sidelength = (int) (pow(g->aperture, g->resolution / 2.0) + 0.5);
+ } else {
+ sidelength = g->resolution;
+ }
+
+ hexwidth = 1.0 / sidelength;
+
+ v = *pt;
+ isea_rotate(&v, -30.0);
+ hexbin2(hexwidth, v.x, v.y, &h.x, &h.y);
+ h.iso = 0;
+ hex_iso(&h);
+
+ /* we may actually be on another quad */
+ if (quad <= 5) {
+ if (h.x == 0 && h.z == -sidelength) {
+ /* north pole */
+ quad = 0;
+ h.z = 0;
+ h.y = 0;
+ h.x = 0;
+ } else if (h.z == -sidelength) {
+ quad = quad + 1;
+ if (quad == 6)
+ quad = 1;
+ h.y = sidelength - h.x;
+ h.z = h.x - sidelength;
+ h.x = 0;
+ } else if (h.x == sidelength) {
+ quad += 5;
+ h.y = -h.z;
+ h.x = 0;
+ }
+ } else if (quad >= 6) {
+ if (h.z == 0 && h.x == sidelength) {
+ /* south pole */
+ quad = 11;
+ h.x = 0;
+ h.y = 0;
+ h.z = 0;
+ } else if (h.x == sidelength) {
+ quad = quad + 1;
+ if (quad == 11)
+ quad = 6;
+ h.x = h.y + sidelength;
+ h.y = 0;
+ h.z = -h.x;
+ } else if (h.y == -sidelength) {
+ quad -= 4;
+ h.y = 0;
+ h.z = -h.x;
+ }
+ }
+ di->x = h.x;
+ di->y = -h.z;
+
+ g->quad = quad;
+ return quad;
+}
+
+ISEA_STATIC
+int isea_ptdi(struct isea_dgg *g, int tri, struct isea_pt *pt,
+ struct isea_pt *di) {
+ struct isea_pt v;
+ int quad;
+
+ v = *pt;
+ quad = isea_ptdd(tri, &v);
+ quad = isea_dddi(g, quad, &v, di);
+ return quad;
+}
+
+/* q2di to seqnum */
+ISEA_STATIC
+int isea_disn(struct isea_dgg *g, int quad, struct isea_pt *di) {
+ int sidelength;
+ int sn, height;
+ int hexes;
+
+ if (quad == 0) {
+ g->serial = 1;
+ return g->serial;
+ }
+ /* hexes in a quad */
+ hexes = (int) (pow(g->aperture, g->resolution) + 0.5);
+ if (quad == 11) {
+ g->serial = 1 + 10 * hexes + 1;
+ return g->serial;
+ }
+ if (g->aperture == 3 && g->resolution % 2 == 1) {
+ height = (int) (pow(g->aperture, (g->resolution - 1) / 2.0));
+ sn = ((int) di->x) * height;
+ sn += ((int) di->y) / height;
+ sn += (quad - 1) * hexes;
+ sn += 2;
+ } else {
+ sidelength = (int) (pow(g->aperture, g->resolution / 2.0) + 0.5);
+ sn = (quad - 1) * hexes + sidelength * di->x + di->y + 2;
+ }
+
+ g->serial = sn;
+ return sn;
+}
+
+/* TODO just encode the quad in the d or i coordinate
+ * quad is 0-11, which can be four bits.
+ * d' = d << 4 + q, d = d' >> 4, q = d' & 0xf
+ */
+/* convert a q2di to global hex coord */
+ISEA_STATIC
+int isea_hex(struct isea_dgg *g, int tri,
+ struct isea_pt *pt, struct isea_pt *hex) {
+ struct isea_pt v;
+ int sidelength;
+ int d, i, x, y, quad;
+
+ quad = isea_ptdi(g, tri, pt, &v);
+
+ hex->x = ((int)v.x << 4) + quad;
+ hex->y = v.y;
+
+ return 1;
+
+ d = v.x;
+ i = v.y;
+
+ /* Aperture 3 odd resolutions */
+ if (g->aperture == 3 && g->resolution % 2 != 0) {
+ int offset = (int)(pow(3.0, g->resolution - 1) + 0.5);
+
+ d += offset * ((g->quad-1) % 5);
+ i += offset * ((g->quad-1) % 5);
+
+ if (quad == 0) {
+ d = 0;
+ i = offset;
+ } else if (quad == 11) {
+ d = 2 * offset;
+ i = 0;
+ } else if (quad > 5) {
+ d += offset;
+ }
+
+ x = (2*d - i) /3;
+ y = (2*i - d) /3;
+
+ hex->x = x + offset / 3;
+ hex->y = y + 2 * offset / 3;
+ return 1;
+ }
+
+ /* aperture 3 even resolutions and aperture 4 */
+ sidelength = (int) (pow(g->aperture, g->resolution / 2.0) + 0.5);
+ if (g->quad == 0) {
+ hex->x = 0;
+ hex->y = sidelength;
+ } else if (g->quad == 11) {
+ hex->x = sidelength * 2;
+ hex->y = 0;
+ } else {
+ hex->x = d + sidelength * ((g->quad-1) % 5);
+ if (g->quad > 5) hex->x += sidelength;
+ hex->y = i + sidelength * ((g->quad-1) % 5);
+ }
+
+ return 1;
+}
+
+ISEA_STATIC
+struct isea_pt
+isea_forward(struct isea_dgg *g, struct isea_geo *in)
+{
+ int tri;
+ struct isea_pt out, coord;
+
+ tri = isea_transform(g, in, &out);
+
+ if (g->output == ISEA_PLANE) {
+ isea_tri_plane(tri, &out, g->radius);
+ return out;
+ }
+
+ /* convert to isea standard triangle size */
+ out.x = out.x / g->radius * ISEA_SCALE;
+ out.y = out.y / g->radius * ISEA_SCALE;
+ out.x += 0.5;
+ out.y += 2.0 * .14433756729740644112;
+
+ switch (g->output) {
+ case ISEA_PROJTRI:
+ /* nothing to do, already in projected triangle */
+ break;
+ case ISEA_VERTEX2DD:
+ g->quad = isea_ptdd(tri, &out);
+ break;
+ case ISEA_Q2DD:
+ /* Same as above, we just don't print as much */
+ g->quad = isea_ptdd(tri, &out);
+ break;
+ case ISEA_Q2DI:
+ g->quad = isea_ptdi(g, tri, &out, &coord);
+ return coord;
+ break;
+ case ISEA_SEQNUM:
+ isea_ptdi(g, tri, &out, &coord);
+ /* disn will set g->serial */
+ isea_disn(g, g->quad, &coord);
+ return coord;
+ break;
+ case ISEA_HEX:
+ isea_hex(g, tri, &out, &coord);
+ return coord;
+ break;
+ }
+
+ return out;
+}
+/*
+ * Proj 4 integration code follows
+ */
+
+#define PJ_LIB__
+#include <projects.h>
+
+PROJ_HEAD(isea, "Icosahedral Snyder Equal Area") "\n\tSph";
+
+struct pj_opaque {
+ struct isea_dgg dgg;
+};
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ struct isea_pt out;
+ struct isea_geo in;
+
+ in.lon = lp.lam;
+ in.lat = lp.phi;
+
+ out = isea_forward(&Q->dgg, &in);
+
+ xy.x = out.x;
+ xy.y = out.y;
+
+ return xy;
+}
+
+
+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(isea) {
+ char *opt;
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+
+ P->fwd = s_forward;
+ isea_grid_init(&Q->dgg);
+
+ Q->dgg.output = ISEA_PLANE;
+/* P->dgg.radius = P->a; / * otherwise defaults to 1 */
+ /* calling library will scale, I think */
+
+ opt = pj_param(P->ctx,P->params, "sorient").s;
+ if (opt) {
+ if (!strcmp(opt, "isea")) {
+ isea_orient_isea(&Q->dgg);
+ } else if (!strcmp(opt, "pole")) {
+ isea_orient_pole(&Q->dgg);
+ } else {
+ E_ERROR(-34);
+ }
+ }
+
+ if (pj_param(P->ctx,P->params, "tazi").i) {
+ Q->dgg.o_az = pj_param(P->ctx,P->params, "razi").f;
+ }
+
+ if (pj_param(P->ctx,P->params, "tlon_0").i) {
+ Q->dgg.o_lon = pj_param(P->ctx,P->params, "rlon_0").f;
+ }
+
+ if (pj_param(P->ctx,P->params, "tlat_0").i) {
+ Q->dgg.o_lat = pj_param(P->ctx,P->params, "rlat_0").f;
+ }
+
+ if (pj_param(P->ctx,P->params, "taperture").i) {
+ Q->dgg.aperture = pj_param(P->ctx,P->params, "iaperture").i;
+ }
+
+ if (pj_param(P->ctx,P->params, "tresolution").i) {
+ Q->dgg.resolution = pj_param(P->ctx,P->params, "iresolution").i;
+ }
+
+ opt = pj_param(P->ctx,P->params, "smode").s;
+ if (opt) {
+ if (!strcmp(opt, "plane")) {
+ Q->dgg.output = ISEA_PLANE;
+ } else if (!strcmp(opt, "di")) {
+ Q->dgg.output = ISEA_Q2DI;
+ }
+ else if (!strcmp(opt, "dd")) {
+ Q->dgg.output = ISEA_Q2DD;
+ }
+ else if (!strcmp(opt, "hex")) {
+ Q->dgg.output = ISEA_HEX;
+ }
+ else {
+ /* TODO verify error code. Possibly eliminate magic */
+ E_ERROR(-34);
+ }
+ }
+
+ if (pj_param(P->ctx,P->params, "trescale").i) {
+ Q->dgg.radius = ISEA_SCALE;
+ }
+
+ if (pj_param(P->ctx,P->params, "tresolution").i) {
+ Q->dgg.resolution = pj_param(P->ctx,P->params, "iresolution").i;
+ } else {
+ Q->dgg.resolution = 4;
+ }
+
+ if (pj_param(P->ctx,P->params, "taperture").i) {
+ Q->dgg.aperture = pj_param(P->ctx,P->params, "iaperture").i;
+ } else {
+ Q->dgg.aperture = 3;
+ }
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_isea_selftest (void) {return 0;}
+#else
+
+int pj_isea_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=isea +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ {-1097074.9480224741, 3442909.3090371834},
+ {-1097074.9482647954, 3233611.7285857084},
+ {-1575486.3536415542, 3442168.3420281881},
+ {-1575486.353880283, 3234352.6955947056},
+ };
+
+ return pj_generic_selftest (0, s_args, tolerance_xy, tolerance_lp, 4, 4, fwd_in, 0, s_fwd_expect, 0, 0, 0);
+}
+
+
+#endif
diff --git a/src/PJ_krovak.c b/src/PJ_krovak.c
index dd250134..4a9a4e53 100644
--- a/src/PJ_krovak.c
+++ b/src/PJ_krovak.c
@@ -29,220 +29,282 @@
* SOFTWARE.
*****************************************************************************/
-#define PROJ_PARMS__ \
- double C_x;
#define PJ_LIB__
-
#include <projects.h>
#include <string.h>
#include <stdio.h>
PROJ_HEAD(krovak, "Krovak") "\n\tPCyl., Ellps.";
+struct pj_opaque {
+ double C_x;
+};
+
/**
NOTES: According to EPSG the full Krovak projection method should have
the following parameters. Within PROJ.4 the azimuth, and pseudo
- standard parallel are hardcoded in the algorithm and can't be
+ standard parallel are hardcoded in the algorithm and can't be
altered from outside. The others all have defaults to match the
common usage with Krovak projection.
lat_0 = latitude of centre of the projection
-
+
lon_0 = longitude of centre of the projection
-
+
** = azimuth (true) of the centre line passing through the centre of the projection
** = latitude of pseudo standard parallel
-
+
k = scale factor on the pseudo standard parallel
-
+
x_0 = False Easting of the centre of the projection at the apex of the cone
-
+
y_0 = False Northing of the centre of the projection at the apex of the cone
**/
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
+ XY xy = {0.0,0.0};
-FORWARD(e_forward); /* ellipsoid */
-/* calculate xy from lat/lon */
+ /* calculate xy from lat/lon */
-/* Constants, identical to inverse transform function */
- double s45, s90, e2, e, alfa, uq, u0, g, k, k1, n0, ro0, ad, a, s0, n;
- double gfi, u, fi0, deltav, s, d, eps, ro;
+ /* Constants, identical to inverse transform function */
+ double s45, s90, e2, e, alfa, uq, u0, g, k, k1, n0, ro0, ad, a, s0, n;
+ double gfi, u, fi0, deltav, s, d, eps, ro;
- s45 = 0.785398163397448; /* 45deg */
- s90 = 2 * s45;
- fi0 = P->phi0; /* Latitude of projection centre 49deg 30' */
+ s45 = 0.785398163397448; /* 45deg */
+ s90 = 2 * s45;
+ fi0 = P->phi0; /* Latitude of projection centre 49deg 30' */
- /* Ellipsoid is used as Parameter in for.c and inv.c, therefore a must
+ /* Ellipsoid is used as Parameter in for.c and inv.c, therefore a must
be set to 1 here.
Ellipsoid Bessel 1841 a = 6377397.155m 1/f = 299.1528128,
e2=0.006674372230614;
- */
- a = 1; /* 6377397.155; */
- /* e2 = P->es;*/ /* 0.006674372230614; */
- e2 = 0.006674372230614;
- e = sqrt(e2);
-
- alfa = sqrt(1. + (e2 * pow(cos(fi0), 4)) / (1. - e2));
+ */
+ a = 1; /* 6377397.155; */
+ /* e2 = P->es;*/ /* 0.006674372230614; */
+ e2 = 0.006674372230614;
+ e = sqrt(e2);
- uq = 1.04216856380474; /* DU(2, 59, 42, 42.69689) */
- u0 = asin(sin(fi0) / alfa);
- g = pow( (1. + e * sin(fi0)) / (1. - e * sin(fi0)) , alfa * e / 2. );
+ alfa = sqrt(1. + (e2 * pow(cos(fi0), 4)) / (1. - e2));
- k = tan( u0 / 2. + s45) / pow (tan(fi0 / 2. + s45) , alfa) * g;
+ uq = 1.04216856380474; /* DU(2, 59, 42, 42.69689) */
+ u0 = asin(sin(fi0) / alfa);
+ g = pow( (1. + e * sin(fi0)) / (1. - e * sin(fi0)) , alfa * e / 2. );
- k1 = P->k0;
- n0 = a * sqrt(1. - e2) / (1. - e2 * pow(sin(fi0), 2));
- s0 = 1.37008346281555; /* Latitude of pseudo standard parallel 78deg 30'00" N */
- n = sin(s0);
- ro0 = k1 * n0 / tan(s0);
- ad = s90 - uq;
+ k = tan( u0 / 2. + s45) / pow (tan(fi0 / 2. + s45) , alfa) * g;
-/* Transformation */
+ k1 = P->k0;
+ n0 = a * sqrt(1. - e2) / (1. - e2 * pow(sin(fi0), 2));
+ s0 = 1.37008346281555; /* Latitude of pseudo standard parallel 78deg 30'00" N */
+ n = sin(s0);
+ ro0 = k1 * n0 / tan(s0);
+ ad = s90 - uq;
- gfi =pow ( ((1. + e * sin(lp.phi)) /
- (1. - e * sin(lp.phi))) , (alfa * e / 2.));
+ /* Transformation */
+ gfi = pow ( ((1. + e * sin(lp.phi)) /
+ (1. - e * sin(lp.phi))) , (alfa * e / 2.));
- u= 2. * (atan(k * pow( tan(lp.phi / 2. + s45), alfa) / gfi)-s45);
+ u = 2. * (atan(k * pow( tan(lp.phi / 2. + s45), alfa) / gfi)-s45);
- deltav = - lp.lam * alfa;
+ deltav = - lp.lam * alfa;
- s = asin(cos(ad) * sin(u) + sin(ad) * cos(u) * cos(deltav));
- d = asin(cos(u) * sin(deltav) / cos(s));
- eps = n * d;
- ro = ro0 * pow(tan(s0 / 2. + s45) , n) / pow(tan(s / 2. + s45) , n) ;
+ s = asin(cos(ad) * sin(u) + sin(ad) * cos(u) * cos(deltav));
+ d = asin(cos(u) * sin(deltav) / cos(s));
+ eps = n * d;
+ ro = ro0 * pow(tan(s0 / 2. + s45) , n) / pow(tan(s / 2. + s45) , n);
/* x and y are reverted! */
- xy.y = ro * cos(eps) / a;
- xy.x = ro * sin(eps) / a;
+ xy.y = ro * cos(eps) / a;
+ xy.x = ro * sin(eps) / a;
- if( !pj_param(P->ctx, P->params, "tczech").i )
- {
- xy.y *= -1.0;
- xy.x *= -1.0;
- }
+ if( !pj_param(P->ctx, P->params, "tczech").i ) {
+ xy.y *= -1.0;
+ xy.x *= -1.0;
+ }
- return (xy);
+ return xy;
}
+static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */
+ LP lp = {0.0,0.0};
-INVERSE(e_inverse); /* ellipsoid */
- /* calculate lat/lon from xy */
+ /* calculate lat/lon from xy */
-/* Constants, identisch wie in der Umkehrfunktion */
- double s45, s90, fi0, e2, e, alfa, uq, u0, g, k, k1, n0, ro0, ad, a, s0, n;
- double u, deltav, s, d, eps, ro, fi1, xy0;
- int ok;
+ /* Constants, identisch wie in der Umkehrfunktion */
+ double s45, s90, fi0, e2, e, alfa, uq, u0, g, k, k1, n0, ro0, ad, a, s0, n;
+ double u, deltav, s, d, eps, ro, fi1, xy0;
+ int ok;
- s45 = 0.785398163397448; /* 45deg */
- s90 = 2 * s45;
- fi0 = P->phi0; /* Latitude of projection centre 49deg 30' */
+ s45 = 0.785398163397448; /* 45deg */
+ s90 = 2 * s45;
+ fi0 = P->phi0; /* Latitude of projection centre 49deg 30' */
- /* Ellipsoid is used as Parameter in for.c and inv.c, therefore a must
+ /* Ellipsoid is used as Parameter in for.c and inv.c, therefore a must
be set to 1 here.
Ellipsoid Bessel 1841 a = 6377397.155m 1/f = 299.1528128,
e2=0.006674372230614;
*/
- a = 1; /* 6377397.155; */
- /* e2 = P->es; */ /* 0.006674372230614; */
- e2 = 0.006674372230614;
- e = sqrt(e2);
+ a = 1; /* 6377397.155; */
+ /* e2 = P->es; */ /* 0.006674372230614; */
+ e2 = 0.006674372230614;
+ e = sqrt(e2);
- alfa = sqrt(1. + (e2 * pow(cos(fi0), 4)) / (1. - e2));
- uq = 1.04216856380474; /* DU(2, 59, 42, 42.69689) */
- u0 = asin(sin(fi0) / alfa);
- g = pow( (1. + e * sin(fi0)) / (1. - e * sin(fi0)) , alfa * e / 2. );
+ alfa = sqrt(1. + (e2 * pow(cos(fi0), 4)) / (1. - e2));
+ uq = 1.04216856380474; /* DU(2, 59, 42, 42.69689) */
+ u0 = asin(sin(fi0) / alfa);
+ g = pow( (1. + e * sin(fi0)) / (1. - e * sin(fi0)) , alfa * e / 2. );
- k = tan( u0 / 2. + s45) / pow (tan(fi0 / 2. + s45) , alfa) * g;
+ k = tan( u0 / 2. + s45) / pow (tan(fi0 / 2. + s45) , alfa) * g;
- k1 = P->k0;
- n0 = a * sqrt(1. - e2) / (1. - e2 * pow(sin(fi0), 2));
- s0 = 1.37008346281555; /* Latitude of pseudo standard parallel 78deg 30'00" N */
- n = sin(s0);
- ro0 = k1 * n0 / tan(s0);
- ad = s90 - uq;
+ k1 = P->k0;
+ n0 = a * sqrt(1. - e2) / (1. - e2 * pow(sin(fi0), 2));
+ s0 = 1.37008346281555; /* Latitude of pseudo standard parallel 78deg 30'00" N */
+ n = sin(s0);
+ ro0 = k1 * n0 / tan(s0);
+ ad = s90 - uq;
-/* Transformation */
+ /* Transformation */
/* revert y, x*/
- xy0=xy.x;
- xy.x=xy.y;
- xy.y=xy0;
+ xy0 = xy.x;
+ xy.x = xy.y;
+ xy.y = xy0;
- if( !pj_param(P->ctx, P->params, "tczech").i )
- {
- xy.x *= -1.0;
- xy.y *= -1.0;
- }
+ if( !pj_param(P->ctx, P->params, "tczech").i ) {
+ xy.x *= -1.0;
+ xy.y *= -1.0;
+ }
- ro = sqrt(xy.x * xy.x + xy.y * xy.y);
- eps = atan2(xy.y, xy.x);
- d = eps / sin(s0);
- s = 2. * (atan( pow(ro0 / ro, 1. / n) * tan(s0 / 2. + s45)) - s45);
+ ro = sqrt(xy.x * xy.x + xy.y * xy.y);
+ eps = atan2(xy.y, xy.x);
+ d = eps / sin(s0);
+ s = 2. * (atan( pow(ro0 / ro, 1. / n) * tan(s0 / 2. + s45)) - s45);
- u = asin(cos(ad) * sin(s) - sin(ad) * cos(s) * cos(d));
- deltav = asin(cos(s) * sin(d) / cos(u));
+ u = asin(cos(ad) * sin(s) - sin(ad) * cos(s) * cos(d));
+ deltav = asin(cos(s) * sin(d) / cos(u));
- lp.lam = P->lam0 - deltav / alfa;
+ lp.lam = P->lam0 - deltav / alfa;
-/* ITERATION FOR lp.phi */
- fi1 = u;
+ /* ITERATION FOR lp.phi */
+ fi1 = u;
- ok = 0;
- do
- {
- lp.phi = 2. * ( atan( pow( k, -1. / alfa) *
- pow( tan(u / 2. + s45) , 1. / alfa) *
- pow( (1. + e * sin(fi1)) / (1. - e * sin(fi1)) , e / 2.)
- ) - s45);
+ ok = 0;
+ do {
+ lp.phi = 2. * ( atan( pow( k, -1. / alfa) *
+ pow( tan(u / 2. + s45) , 1. / alfa) *
+ pow( (1. + e * sin(fi1)) / (1. - e * sin(fi1)) , e / 2.)
+ ) - s45);
- if (fabs(fi1 - lp.phi) < 0.000000000000001) ok=1;
- fi1 = lp.phi;
-
- }
- while (ok==0);
+ if (fabs(fi1 - lp.phi) < 0.000000000000001) ok=1;
+ fi1 = lp.phi;
+ } while (ok==0);
lp.lam -= P->lam0;
- return (lp);
+ return lp;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(krovak)
- double ts;
- /* read some Parameters,
- * here Latitude Truescale */
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+ if (0==P->opaque)
+ return pj_dealloc (P);
- ts = pj_param(P->ctx, P->params, "rlat_ts").f;
- P->C_x = ts;
-
- /* we want Bessel as fixed ellipsoid */
- P->a = 6377397.155;
- P->e = sqrt(P->es = 0.006674372230614);
+ pj_dealloc (P->opaque);
+ return pj_dealloc(P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(krovak) {
+ double ts;
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ /* read some Parameters,
+ * here Latitude Truescale */
+
+ ts = pj_param(P->ctx, P->params, "rlat_ts").f;
+ Q->C_x = ts;
+
+ /* we want Bessel as fixed ellipsoid */
+ P->a = 6377397.155;
+ P->e = sqrt(P->es = 0.006674372230614);
/* if latitude of projection center is not set, use 49d30'N */
- if (!pj_param(P->ctx, P->params, "tlat_0").i)
- P->phi0 = 0.863937979737193;
+ if (!pj_param(P->ctx, P->params, "tlat_0").i)
+ P->phi0 = 0.863937979737193;
/* if center long is not set use 42d30'E of Ferro - 17d40' for Ferro */
/* that will correspond to using longitudes relative to greenwich */
/* as input and output, instead of lat/long relative to Ferro */
- if (!pj_param(P->ctx, P->params, "tlon_0").i)
+ if (!pj_param(P->ctx, P->params, "tlon_0").i)
P->lam0 = 0.7417649320975901 - 0.308341501185665;
/* if scale not set default to 0.9999 */
- if (!pj_param(P->ctx, P->params, "tk").i)
+ if (!pj_param(P->ctx, P->params, "tk").i)
P->k0 = 0.9999;
- /* always the same */
- P->inv = e_inverse;
- P->fwd = e_forward;
+ /* always the same */
+ P->inv = e_inverse;
+ P->fwd = e_forward;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_krovak_selftest (void) {return 0;}
+#else
+
+int pj_krovak_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=krovak +ellps=GRS80 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ {-3196535.2325636409, -6617878.8675514441},
+ {-3260035.4405521089, -6898873.6148780314},
+ {-3756305.3288691747, -6478142.5615715114},
+ {-3831703.6585019818, -6759107.1701553948},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ {24.836218918719162, 59.758403933233858},
+ {24.836315484509566, 59.756888425730189},
+ {24.830447747947495, 59.758403933233858},
+ {24.830351182157091, 59.756888425730189},
+ };
+
+ return pj_generic_selftest (e_args, 0, tolerance_xy, tolerance_lp, 4, 4, fwd_in, e_fwd_expect, 0, inv_in, e_inv_expect, 0);
+}
-ENDENTRY(P)
+#endif
diff --git a/src/PJ_labrd.c b/src/PJ_labrd.c
index 4cb39ec8..4c435731 100644
--- a/src/PJ_labrd.c
+++ b/src/PJ_labrd.c
@@ -1,109 +1,186 @@
-#define PROJ_PARMS__ \
- double Az, kRg, p0s, A, C, Ca, Cb, Cc, Cd; \
- int rot;
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(labrd, "Laborde") "\n\tCyl, Sph\n\tSpecial for Madagascar";
-#define EPS 1.e-10
-FORWARD(e_forward);
- double V1, V2, ps, sinps, cosps, sinps2, cosps2, I1, I2, I3, I4, I5, I6,
- x2, y2, t;
-
- V1 = P->A * log( tan(FORTPI + .5 * lp.phi) );
- t = P->e * sin(lp.phi);
- V2 = .5 * P->e * P->A * log ((1. + t)/(1. - t));
- ps = 2. * (atan(exp(V1 - V2 + P->C)) - FORTPI);
- I1 = ps - P->p0s;
- cosps = cos(ps); cosps2 = cosps * cosps;
- sinps = sin(ps); sinps2 = sinps * sinps;
- I4 = P->A * cosps;
- I2 = .5 * P->A * I4 * sinps;
- I3 = I2 * P->A * P->A * (5. * cosps2 - sinps2) / 12.;
- I6 = I4 * P->A * P->A;
- I5 = I6 * (cosps2 - sinps2) / 6.;
- I6 *= P->A * P->A *
- (5. * cosps2 * cosps2 + sinps2 * (sinps2 - 18. * cosps2)) / 120.;
- t = lp.lam * lp.lam;
- xy.x = P->kRg * lp.lam * (I4 + t * (I5 + t * I6));
- xy.y = P->kRg * (I1 + t * (I2 + t * I3));
- x2 = xy.x * xy.x;
- y2 = xy.y * xy.y;
- V1 = 3. * xy.x * y2 - xy.x * x2;
- V2 = xy.y * y2 - 3. * x2 * xy.y;
- xy.x += P->Ca * V1 + P->Cb * V2;
- xy.y += P->Ca * V2 - P->Cb * V1;
- return (xy);
+#define EPS 1.e-10
+
+struct pj_opaque {
+ double kRg, p0s, A, C, Ca, Cb, Cc, Cd; \
+ int rot;
+};
+
+
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double V1, V2, ps, sinps, cosps, sinps2, cosps2;
+ double I1, I2, I3, I4, I5, I6, x2, y2, t;
+
+ V1 = Q->A * log( tan(FORTPI + .5 * lp.phi) );
+ t = P->e * sin(lp.phi);
+ V2 = .5 * P->e * Q->A * log ((1. + t)/(1. - t));
+ ps = 2. * (atan(exp(V1 - V2 + Q->C)) - FORTPI);
+ I1 = ps - Q->p0s;
+ cosps = cos(ps); cosps2 = cosps * cosps;
+ sinps = sin(ps); sinps2 = sinps * sinps;
+ I4 = Q->A * cosps;
+ I2 = .5 * Q->A * I4 * sinps;
+ I3 = I2 * Q->A * Q->A * (5. * cosps2 - sinps2) / 12.;
+ I6 = I4 * Q->A * Q->A;
+ I5 = I6 * (cosps2 - sinps2) / 6.;
+ I6 *= Q->A * Q->A *
+ (5. * cosps2 * cosps2 + sinps2 * (sinps2 - 18. * cosps2)) / 120.;
+ t = lp.lam * lp.lam;
+ xy.x = Q->kRg * lp.lam * (I4 + t * (I5 + t * I6));
+ xy.y = Q->kRg * (I1 + t * (I2 + t * I3));
+ x2 = xy.x * xy.x;
+ y2 = xy.y * xy.y;
+ V1 = 3. * xy.x * y2 - xy.x * x2;
+ V2 = xy.y * y2 - 3. * x2 * xy.y;
+ xy.x += Q->Ca * V1 + Q->Cb * V2;
+ xy.y += Q->Ca * V2 - Q->Cb * V1;
+ 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 x2, y2, V1, V2, V3, V4, t, t2, ps, pe, tpe, s;
+ double I7, I8, I9, I10, I11, d, Re;
+ int i;
+
+ x2 = xy.x * xy.x;
+ y2 = xy.y * xy.y;
+ V1 = 3. * xy.x * y2 - xy.x * x2;
+ V2 = xy.y * y2 - 3. * x2 * xy.y;
+ V3 = xy.x * (5. * y2 * y2 + x2 * (-10. * y2 + x2 ));
+ V4 = xy.y * (5. * x2 * x2 + y2 * (-10. * x2 + y2 ));
+ xy.x += - Q->Ca * V1 - Q->Cb * V2 + Q->Cc * V3 + Q->Cd * V4;
+ xy.y += Q->Cb * V1 - Q->Ca * V2 - Q->Cd * V3 + Q->Cc * V4;
+ ps = Q->p0s + xy.y / Q->kRg;
+ pe = ps + P->phi0 - Q->p0s;
+ for ( i = 20; i; --i) {
+ V1 = Q->A * log(tan(FORTPI + .5 * pe));
+ tpe = P->e * sin(pe);
+ V2 = .5 * P->e * Q->A * log((1. + tpe)/(1. - tpe));
+ t = ps - 2. * (atan(exp(V1 - V2 + Q->C)) - FORTPI);
+ pe += t;
+ if (fabs(t) < EPS)
+ break;
+ }
+
+ t = P->e * sin(pe);
+ t = 1. - t * t;
+ Re = P->one_es / ( t * sqrt(t) );
+ t = tan(ps);
+ t2 = t * t;
+ s = Q->kRg * Q->kRg;
+ d = Re * P->k0 * Q->kRg;
+ I7 = t / (2. * d);
+ I8 = t * (5. + 3. * t2) / (24. * d * s);
+ d = cos(ps) * Q->kRg * Q->A;
+ I9 = 1. / d;
+ d *= s;
+ I10 = (1. + 2. * t2) / (6. * d);
+ I11 = (5. + t2 * (28. + 24. * t2)) / (120. * d * s);
+ x2 = xy.x * xy.x;
+ lp.phi = pe + x2 * (-I7 + I8 * x2);
+ lp.lam = xy.x * (I9 + x2 * (-I10 + x2 * I11));
+ 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;
}
-INVERSE(e_inverse); /* ellipsoid & spheroid */
- double x2, y2, V1, V2, V3, V4, t, t2, ps, pe, tpe, s,
- I7, I8, I9, I10, I11, d, Re;
- int i;
-
- x2 = xy.x * xy.x;
- y2 = xy.y * xy.y;
- V1 = 3. * xy.x * y2 - xy.x * x2;
- V2 = xy.y * y2 - 3. * x2 * xy.y;
- V3 = xy.x * (5. * y2 * y2 + x2 * (-10. * y2 + x2 ));
- V4 = xy.y * (5. * x2 * x2 + y2 * (-10. * x2 + y2 ));
- xy.x += - P->Ca * V1 - P->Cb * V2 + P->Cc * V3 + P->Cd * V4;
- xy.y += P->Cb * V1 - P->Ca * V2 - P->Cd * V3 + P->Cc * V4;
- ps = P->p0s + xy.y / P->kRg;
- pe = ps + P->phi0 - P->p0s;
- for ( i = 20; i; --i) {
- V1 = P->A * log(tan(FORTPI + .5 * pe));
- tpe = P->e * sin(pe);
- V2 = .5 * P->e * P->A * log((1. + tpe)/(1. - tpe));
- t = ps - 2. * (atan(exp(V1 - V2 + P->C)) - FORTPI);
- pe += t;
- if (fabs(t) < EPS)
- break;
- }
-/*
- if (!i) {
- } else {
- }
-*/
- t = P->e * sin(pe);
- t = 1. - t * t;
- Re = P->one_es / ( t * sqrt(t) );
- t = tan(ps);
- t2 = t * t;
- s = P->kRg * P->kRg;
- d = Re * P->k0 * P->kRg;
- I7 = t / (2. * d);
- I8 = t * (5. + 3. * t2) / (24. * d * s);
- d = cos(ps) * P->kRg * P->A;
- I9 = 1. / d;
- d *= s;
- I10 = (1. + 2. * t2) / (6. * d);
- I11 = (5. + t2 * (28. + 24. * t2)) / (120. * d * s);
- x2 = xy.x * xy.x;
- lp.phi = pe + x2 * (-I7 + I8 * x2);
- lp.lam = xy.x * (I9 + x2 * (-I10 + x2 * I11));
- return (lp);
+
+
+PJ *PROJECTION(labrd) {
+ double Az, sinp, R, N, t;
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->rot = pj_param(P->ctx, P->params, "bno_rot").i == 0;
+ Az = pj_param(P->ctx, P->params, "razi").f;
+ sinp = sin(P->phi0);
+ t = 1. - P->es * sinp * sinp;
+ N = 1. / sqrt(t);
+ R = P->one_es * N / t;
+ Q->kRg = P->k0 * sqrt( N * R );
+ Q->p0s = atan( sqrt(R / N) * tan(P->phi0) );
+ Q->A = sinp / sin(Q->p0s);
+ t = P->e * sinp;
+ Q->C = .5 * P->e * Q->A * log((1. + t)/(1. - t)) +
+ - Q->A * log( tan(FORTPI + .5 * P->phi0))
+ + log( tan(FORTPI + .5 * Q->p0s));
+ t = Az + Az;
+ Q->Ca = (1. - cos(t)) * ( Q->Cb = 1. / (12. * Q->kRg * Q->kRg) );
+ Q->Cb *= sin(t);
+ Q->Cc = 3. * (Q->Ca * Q->Ca - Q->Cb * Q->Cb);
+ Q->Cd = 6. * Q->Ca * Q->Cb;
+
+ P->inv = e_inverse;
+ P->fwd = e_forward;
+
+ return P;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(labrd)
- double Az, sinp, R, N, t;
-
- P->rot = pj_param(P->ctx, P->params, "bno_rot").i == 0;
- Az = pj_param(P->ctx, P->params, "razi").f;
- sinp = sin(P->phi0);
- t = 1. - P->es * sinp * sinp;
- N = 1. / sqrt(t);
- R = P->one_es * N / t;
- P->kRg = P->k0 * sqrt( N * R );
- P->p0s = atan( sqrt(R / N) * tan(P->phi0) );
- P->A = sinp / sin(P->p0s);
- t = P->e * sinp;
- P->C = .5 * P->e * P->A * log((1. + t)/(1. - t)) +
- - P->A * log( tan(FORTPI + .5 * P->phi0))
- + log( tan(FORTPI + .5 * P->p0s));
- t = Az + Az;
- P->Ca = (1. - cos(t)) * ( P->Cb = 1. / (12. * P->kRg * P->kRg) );
- P->Cb *= sin(t);
- P->Cc = 3. * (P->Ca * P->Ca - P->Cb * P->Cb);
- P->Cd = 6. * P->Ca * P->Cb;
- P->inv = e_inverse;
- P->fwd = e_forward;
-ENDENTRY(P)
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_labrd_selftest (void) {return 0;}
+#else
+
+int pj_labrd_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=labrd +ellps=GRS80 +lon_0=0.5 +lat_0=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ { 166973.166090228391, -110536.912730266107},
+ { 166973.168287157256, -331761.993650884193},
+ {-278345.500519976194, -110469.032642031714},
+ {-278345.504185269645, -331829.870790275279},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ {0.501797719349373672, 2.00090435742047923},
+ {0.501797717380853658, 1.99909564058898681},
+ {0.498202280650626328, 2.00090435742047923},
+ {0.498202282619146342, 1.99909564058898681},
+ };
+
+ return pj_generic_selftest (e_args, 0, tolerance_xy, tolerance_lp, 4, 4, fwd_in, e_fwd_expect, 0, inv_in, e_inv_expect, 0);
+}
+
+
+#endif
diff --git a/src/PJ_laea.c b/src/PJ_laea.c
index 445e39c3..8393ebd0 100644
--- a/src/PJ_laea.c
+++ b/src/PJ_laea.c
@@ -1,233 +1,338 @@
-#define PROJ_PARMS__ \
- double sinb1; \
- double cosb1; \
- double xmf; \
- double ymf; \
- double mmf; \
- double qp; \
- double dd; \
- double rq; \
- double *apa; \
- int mode;
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(laea, "Lambert Azimuthal Equal Area") "\n\tAzi, Sph&Ell";
-#define sinph0 P->sinb1
-#define cosph0 P->cosb1
-#define EPS10 1.e-10
-#define NITER 20
-#define CONV 1.e-10
-#define N_POLE 0
-#define S_POLE 1
-#define EQUIT 2
-#define OBLIQ 3
-FORWARD(e_forward); /* ellipsoid */
- double coslam, sinlam, sinphi, q, sinb=0.0, cosb=0.0, b=0.0;
-
- coslam = cos(lp.lam);
- sinlam = sin(lp.lam);
- sinphi = sin(lp.phi);
- q = pj_qsfn(sinphi, P->e, P->one_es);
- if (P->mode == OBLIQ || P->mode == EQUIT) {
- sinb = q / P->qp;
- cosb = sqrt(1. - sinb * sinb);
- }
- switch (P->mode) {
- case OBLIQ:
- b = 1. + P->sinb1 * sinb + P->cosb1 * cosb * coslam;
- break;
- case EQUIT:
- b = 1. + cosb * coslam;
- break;
- case N_POLE:
- b = HALFPI + lp.phi;
- q = P->qp - q;
- break;
- case S_POLE:
- b = lp.phi - HALFPI;
- q = P->qp + q;
- break;
- }
- if (fabs(b) < EPS10) F_ERROR;
- switch (P->mode) {
- case OBLIQ:
- xy.y = P->ymf * ( b = sqrt(2. / b) )
- * (P->cosb1 * sinb - P->sinb1 * cosb * coslam);
- goto eqcon;
- break;
- case EQUIT:
- xy.y = (b = sqrt(2. / (1. + cosb * coslam))) * sinb * P->ymf;
+
+struct pj_opaque {
+ double sinb1;
+ double cosb1;
+ double xmf;
+ double ymf;
+ double mmf;
+ double qp;
+ double dd;
+ double rq;
+ double *apa;
+ int mode;
+};
+
+#define EPS10 1.e-10
+#define NITER 20
+#define CONV 1.e-10
+#define N_POLE 0
+#define S_POLE 1
+#define EQUIT 2
+#define OBLIQ 3
+
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double coslam, sinlam, sinphi, q, sinb=0.0, cosb=0.0, b=0.0;
+
+ coslam = cos(lp.lam);
+ sinlam = sin(lp.lam);
+ sinphi = sin(lp.phi);
+ q = pj_qsfn(sinphi, P->e, P->one_es);
+
+ if (Q->mode == OBLIQ || Q->mode == EQUIT) {
+ sinb = q / Q->qp;
+ cosb = sqrt(1. - sinb * sinb);
+ }
+
+ switch (Q->mode) {
+ case OBLIQ:
+ b = 1. + Q->sinb1 * sinb + Q->cosb1 * cosb * coslam;
+ break;
+ case EQUIT:
+ b = 1. + cosb * coslam;
+ break;
+ case N_POLE:
+ b = HALFPI + lp.phi;
+ q = Q->qp - q;
+ break;
+ case S_POLE:
+ b = lp.phi - HALFPI;
+ q = Q->qp + q;
+ break;
+ }
+ if (fabs(b) < EPS10) F_ERROR;
+
+ switch (Q->mode) {
+ case OBLIQ:
+ b = sqrt(2. / b);
+ xy.y = Q->ymf * b * (Q->cosb1 * sinb - Q->sinb1 * cosb * coslam);
+ goto eqcon;
+ break;
+ case EQUIT:
+ b = sqrt(2. / (1. + cosb * coslam));
+ xy.y = b * sinb * Q->ymf;
eqcon:
- xy.x = P->xmf * b * cosb * sinlam;
- break;
- case N_POLE:
- case S_POLE:
- if (q >= 0.) {
- xy.x = (b = sqrt(q)) * sinlam;
- xy.y = coslam * (P->mode == S_POLE ? b : -b);
- } else
- xy.x = xy.y = 0.;
- break;
- }
- return (xy);
+ xy.x = Q->xmf * b * cosb * sinlam;
+ break;
+ case N_POLE:
+ case S_POLE:
+ if (q >= 0.) {
+ b = sqrt(q);
+ xy.x = b * sinlam;
+ xy.y = coslam * (Q->mode == S_POLE ? b : -b);
+ } else
+ xy.x = xy.y = 0.;
+ break;
+ }
+ return xy;
}
-FORWARD(s_forward); /* spheroid */
- double coslam, cosphi, sinphi;
-
- sinphi = sin(lp.phi);
- cosphi = cos(lp.phi);
- coslam = cos(lp.lam);
- switch (P->mode) {
- case EQUIT:
- xy.y = 1. + cosphi * coslam;
- goto oblcon;
- case OBLIQ:
- xy.y = 1. + sinph0 * sinphi + cosph0 * cosphi * coslam;
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double coslam, cosphi, sinphi;
+
+ sinphi = sin(lp.phi);
+ cosphi = cos(lp.phi);
+ coslam = cos(lp.lam);
+ switch (Q->mode) {
+ case EQUIT:
+ xy.y = 1. + cosphi * coslam;
+ goto oblcon;
+ case OBLIQ:
+ xy.y = 1. + Q->sinb1 * sinphi + Q->cosb1 * cosphi * coslam;
oblcon:
- if (xy.y <= EPS10) F_ERROR;
- xy.x = (xy.y = sqrt(2. / xy.y)) * cosphi * sin(lp.lam);
- xy.y *= P->mode == EQUIT ? sinphi :
- cosph0 * sinphi - sinph0 * cosphi * coslam;
- break;
- case N_POLE:
- coslam = -coslam;
- case S_POLE:
- if (fabs(lp.phi + P->phi0) < EPS10) F_ERROR;
- xy.y = FORTPI - lp.phi * .5;
- xy.y = 2. * (P->mode == S_POLE ? cos(xy.y) : sin(xy.y));
- xy.x = xy.y * sin(lp.lam);
- xy.y *= coslam;
- break;
- }
- return (xy);
+ if (xy.y <= EPS10) F_ERROR;
+ xy.y = sqrt(2. / xy.y);
+ xy.x = xy.y * cosphi * sin(lp.lam);
+ xy.y *= Q->mode == EQUIT ? sinphi :
+ Q->cosb1 * sinphi - Q->sinb1 * cosphi * coslam;
+ break;
+ case N_POLE:
+ coslam = -coslam;
+ case S_POLE:
+ if (fabs(lp.phi + P->phi0) < EPS10) F_ERROR;
+ xy.y = FORTPI - lp.phi * .5;
+ xy.y = 2. * (Q->mode == S_POLE ? cos(xy.y) : sin(xy.y));
+ xy.x = xy.y * sin(lp.lam);
+ xy.y *= coslam;
+ break;
+ }
+ 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 cCe, sCe, q, rho, ab=0.0;
+
+ switch (Q->mode) {
+ case EQUIT:
+ case OBLIQ:
+ xy.x /= Q->dd;
+ xy.y *= Q->dd;
+ rho = hypot(xy.x, xy.y);
+ if (rho < EPS10) {
+ lp.lam = 0.;
+ lp.phi = P->phi0;
+ return lp;
+ }
+ sCe = 2. * asin(.5 * rho / Q->rq);
+ cCe = cos(sCe);
+ sCe = sin(sCe);
+ xy.x *= sCe;
+ if (Q->mode == OBLIQ) {
+ ab = cCe * Q->sinb1 + xy.y * sCe * Q->cosb1 / rho;
+ xy.y = rho * Q->cosb1 * cCe - xy.y * Q->sinb1 * sCe;
+ } else {
+ ab = xy.y * sCe / rho;
+ xy.y = rho * cCe;
+ }
+ break;
+ case N_POLE:
+ xy.y = -xy.y;
+ case S_POLE:
+ q = (xy.x * xy.x + xy.y * xy.y);
+ if (!q) {
+ lp.lam = 0.;
+ lp.phi = P->phi0;
+ return (lp);
+ }
+ ab = 1. - q / Q->qp;
+ if (Q->mode == S_POLE)
+ ab = - ab;
+ break;
+ }
+ lp.lam = atan2(xy.x, xy.y);
+ lp.phi = pj_authlat(asin(ab), Q->apa);
+ return lp;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double cosz=0.0, rh, sinz=0.0;
+
+ rh = hypot(xy.x, xy.y);
+ if ((lp.phi = rh * .5 ) > 1.) I_ERROR;
+ lp.phi = 2. * asin(lp.phi);
+ if (Q->mode == OBLIQ || Q->mode == EQUIT) {
+ sinz = sin(lp.phi);
+ cosz = cos(lp.phi);
+ }
+ switch (Q->mode) {
+ case EQUIT:
+ lp.phi = fabs(rh) <= EPS10 ? 0. : asin(xy.y * sinz / rh);
+ xy.x *= sinz;
+ xy.y = cosz * rh;
+ break;
+ case OBLIQ:
+ lp.phi = fabs(rh) <= EPS10 ? P->phi0 :
+ asin(cosz * Q->sinb1 + xy.y * sinz * Q->cosb1 / rh);
+ xy.x *= sinz * Q->cosb1;
+ xy.y = (cosz - sin(lp.phi) * Q->sinb1) * rh;
+ break;
+ case N_POLE:
+ xy.y = -xy.y;
+ lp.phi = HALFPI - lp.phi;
+ break;
+ case S_POLE:
+ lp.phi -= HALFPI;
+ break;
+ }
+ lp.lam = (xy.y == 0. && (Q->mode == EQUIT || Q->mode == OBLIQ)) ?
+ 0. : atan2(xy.x, 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->apa);
+ pj_dealloc (P->opaque);
+ return pj_dealloc(P);
}
-INVERSE(e_inverse); /* ellipsoid */
- double cCe, sCe, q, rho, ab=0.0;
-
- switch (P->mode) {
- case EQUIT:
- case OBLIQ:
- if ((rho = hypot(xy.x /= P->dd, xy.y *= P->dd)) < EPS10) {
- lp.lam = 0.;
- lp.phi = P->phi0;
- return (lp);
- }
- cCe = cos(sCe = 2. * asin(.5 * rho / P->rq));
- xy.x *= (sCe = sin(sCe));
- if (P->mode == OBLIQ) {
- ab = cCe * P->sinb1 + xy.y * sCe * P->cosb1 / rho;
- xy.y = rho * P->cosb1 * cCe - xy.y * P->sinb1 * sCe;
- } else {
- ab = xy.y * sCe / rho;
- xy.y = rho * cCe;
- }
- break;
- case N_POLE:
- xy.y = -xy.y;
- case S_POLE:
- if (!(q = (xy.x * xy.x + xy.y * xy.y)) ) {
- lp.lam = 0.;
- lp.phi = P->phi0;
- return (lp);
- }
- /*
- q = P->qp - q;
- */
- ab = 1. - q / P->qp;
- if (P->mode == S_POLE)
- ab = - ab;
- break;
- }
- lp.lam = atan2(xy.x, xy.y);
- lp.phi = pj_authlat(asin(ab), P->apa);
- return (lp);
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
}
-INVERSE(s_inverse); /* spheroid */
- double cosz=0.0, rh, sinz=0.0;
-
- rh = hypot(xy.x, xy.y);
- if ((lp.phi = rh * .5 ) > 1.) I_ERROR;
- lp.phi = 2. * asin(lp.phi);
- if (P->mode == OBLIQ || P->mode == EQUIT) {
- sinz = sin(lp.phi);
- cosz = cos(lp.phi);
- }
- switch (P->mode) {
- case EQUIT:
- lp.phi = fabs(rh) <= EPS10 ? 0. : asin(xy.y * sinz / rh);
- xy.x *= sinz;
- xy.y = cosz * rh;
- break;
- case OBLIQ:
- lp.phi = fabs(rh) <= EPS10 ? P->phi0 :
- asin(cosz * sinph0 + xy.y * sinz * cosph0 / rh);
- xy.x *= sinz * cosph0;
- xy.y = (cosz - sin(lp.phi) * sinph0) * rh;
- break;
- case N_POLE:
- xy.y = -xy.y;
- lp.phi = HALFPI - lp.phi;
- break;
- case S_POLE:
- lp.phi -= HALFPI;
- break;
- }
- lp.lam = (xy.y == 0. && (P->mode == EQUIT || P->mode == OBLIQ)) ?
- 0. : atan2(xy.x, xy.y);
- return (lp);
+
+
+PJ *PROJECTION(laea) {
+ double t;
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ t = fabs(P->phi0);
+ if (fabs(t - HALFPI) < EPS10)
+ Q->mode = P->phi0 < 0. ? S_POLE : N_POLE;
+ else if (fabs(t) < EPS10)
+ Q->mode = EQUIT;
+ else
+ Q->mode = OBLIQ;
+ if (P->es) {
+ double sinphi;
+
+ P->e = sqrt(P->es);
+ Q->qp = pj_qsfn(1., P->e, P->one_es);
+ Q->mmf = .5 / (1. - P->es);
+ Q->apa = pj_authset(P->es);
+ switch (Q->mode) {
+ case N_POLE:
+ case S_POLE:
+ Q->dd = 1.;
+ break;
+ case EQUIT:
+ Q->dd = 1. / (Q->rq = sqrt(.5 * Q->qp));
+ Q->xmf = 1.;
+ Q->ymf = .5 * Q->qp;
+ break;
+ case OBLIQ:
+ Q->rq = sqrt(.5 * Q->qp);
+ sinphi = sin(P->phi0);
+ Q->sinb1 = pj_qsfn(sinphi, P->e, P->one_es) / Q->qp;
+ Q->cosb1 = sqrt(1. - Q->sinb1 * Q->sinb1);
+ Q->dd = cos(P->phi0) / (sqrt(1. - P->es * sinphi * sinphi) *
+ Q->rq * Q->cosb1);
+ Q->ymf = (Q->xmf = Q->rq) / Q->dd;
+ Q->xmf *= Q->dd;
+ break;
+ }
+ P->inv = e_inverse;
+ P->fwd = e_forward;
+ } else {
+ if (Q->mode == OBLIQ) {
+ Q->sinb1 = sin(P->phi0);
+ Q->cosb1 = cos(P->phi0);
+ }
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+ }
+
+ return P;
}
-FREEUP;
- if (P) {
- if (P->apa)
- pj_dalloc(P->apa);
- pj_dalloc(P);
- }
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_laea_selftest (void) {return 0;}
+#else
+
+int pj_laea_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=laea +ellps=GRS80 +lat_1=0.5 +lat_2=2"};
+ char s_args[] = {"+proj=laea +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ { 222602.471450095181, 110589.82722441027},
+ { 222602.471450095181, -110589.827224408786},
+ {-222602.471450095181, 110589.82722441027},
+ {-222602.471450095181, -110589.827224408786},
+ };
+
+ XY s_fwd_expect[] = {
+ { 223365.281370124663, 111716.668072915665},
+ { 223365.281370124663, -111716.668072915665},
+ {-223365.281370124663, 111716.668072915665},
+ {-223365.281370124663, -111716.668072915665},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ { 0.00179663056847900867, 0.000904369475966495845},
+ { 0.00179663056847900867, -0.000904369475966495845},
+ {-0.00179663056847900867, 0.000904369475966495845},
+ {-0.00179663056847900867, -0.000904369475966495845},
+ };
+
+ LP s_inv_expect[] = {
+ { 0.00179049311002060264, 0.000895246554791735271},
+ { 0.00179049311002060264, -0.000895246554791735271},
+ {-0.00179049311002060264, 0.000895246554791735271},
+ {-0.00179049311002060264, -0.000895246554791735271},
+ };
+
+ 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(laea,apa)
- double t;
-
- if (fabs((t = fabs(P->phi0)) - HALFPI) < EPS10)
- P->mode = P->phi0 < 0. ? S_POLE : N_POLE;
- else if (fabs(t) < EPS10)
- P->mode = EQUIT;
- else
- P->mode = OBLIQ;
- if (P->es) {
- double sinphi;
-
- P->e = sqrt(P->es);
- P->qp = pj_qsfn(1., P->e, P->one_es);
- P->mmf = .5 / (1. - P->es);
- P->apa = pj_authset(P->es);
- switch (P->mode) {
- case N_POLE:
- case S_POLE:
- P->dd = 1.;
- break;
- case EQUIT:
- P->dd = 1. / (P->rq = sqrt(.5 * P->qp));
- P->xmf = 1.;
- P->ymf = .5 * P->qp;
- break;
- case OBLIQ:
- P->rq = sqrt(.5 * P->qp);
- sinphi = sin(P->phi0);
- P->sinb1 = pj_qsfn(sinphi, P->e, P->one_es) / P->qp;
- P->cosb1 = sqrt(1. - P->sinb1 * P->sinb1);
- P->dd = cos(P->phi0) / (sqrt(1. - P->es * sinphi * sinphi) *
- P->rq * P->cosb1);
- P->ymf = (P->xmf = P->rq) / P->dd;
- P->xmf *= P->dd;
- break;
- }
- P->inv = e_inverse;
- P->fwd = e_forward;
- } else {
- if (P->mode == OBLIQ) {
- sinph0 = sin(P->phi0);
- cosph0 = cos(P->phi0);
- }
- P->inv = s_inverse;
- P->fwd = s_forward;
- }
-ENDENTRY(P)
+
+
+#endif
diff --git a/src/PJ_lagrng.c b/src/PJ_lagrng.c
index 8a13b3da..776894d7 100644
--- a/src/PJ_lagrng.c
+++ b/src/PJ_lagrng.c
@@ -1,35 +1,103 @@
-#define PROJ_PARMS__ \
- double hrw; \
- double rw; \
- double a1;
-#define TOL 1e-10
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(lagrng, "Lagrange") "\n\tMisc Sph, no inv.\n\tW=";
-FORWARD(s_forward); /* spheroid */
- double v, c;
-
- if (fabs(fabs(lp.phi) - HALFPI) < TOL) {
- xy.x = 0;
- xy.y = lp.phi < 0 ? -2. : 2.;
- } else {
- lp.phi = sin(lp.phi);
- v = P->a1 * pow((1. + lp.phi)/(1. - lp.phi), P->hrw);
- if ((c = 0.5 * (v + 1./v) + cos(lp.lam *= P->rw)) < TOL)
- F_ERROR;
- xy.x = 2. * sin(lp.lam) / c;
- xy.y = (v - 1./v) / c;
- }
- return (xy);
+
+#define TOL 1e-10
+
+struct pj_opaque {
+ double a1;
+ double hrw;
+ double rw;
+};
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double v, c;
+
+ if (fabs(fabs(lp.phi) - HALFPI) < TOL) {
+ xy.x = 0;
+ xy.y = lp.phi < 0 ? -2. : 2.;
+ } else {
+ lp.phi = sin(lp.phi);
+ v = Q->a1 * pow((1. + lp.phi)/(1. - lp.phi), Q->hrw);
+ if ((c = 0.5 * (v + 1./v) + cos(lp.lam *= Q->rw)) < TOL)
+ F_ERROR;
+ xy.x = 2. * sin(lp.lam) / c;
+ xy.y = (v - 1./v) / c;
+ }
+ return xy;
+}
+
+
+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(lagrng) {
+ double phi1;
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->rw = pj_param(P->ctx, P->params, "dW").f;
+ if (Q->rw <= 0) E_ERROR(-27);
+
+ Q->rw = 1. / Q->rw;
+ Q->hrw = 0.5 * Q->rw;
+ phi1 = sin(pj_param(P->ctx, P->params, "rlat_1").f);
+ if (fabs(fabs(phi1) - 1.) < TOL) E_ERROR(-22);
+
+ Q->a1 = pow((1. - phi1)/(1. + phi1), Q->hrw);
+
+ P->es = 0.;
+ P->fwd = s_forward;
+
+ return P;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(lagrng)
- double phi1;
-
- if ((P->rw = pj_param(P->ctx, P->params, "dW").f) <= 0) E_ERROR(-27);
- P->hrw = 0.5 * (P->rw = 1. / P->rw);
- phi1 = pj_param(P->ctx, P->params, "rlat_1").f;
- if (fabs(fabs(phi1 = sin(phi1)) - 1.) < TOL) E_ERROR(-22);
- P->a1 = pow((1. - phi1)/(1. + phi1), P->hrw);
- P->es = 0.; P->fwd = s_forward;
-ENDENTRY(P)
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_lagrng_selftest (void) {return 0;}
+#else
+
+int pj_lagrng_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=lagrng +a=6400000 +W=2 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 111703.37591722561, 27929.8319080333386},
+ { 111699.122088816002, -83784.1780133577704},
+ {-111703.37591722561, 27929.8319080333386},
+ {-111699.122088816002, -83784.1780133577704},
+ };
+
+ return pj_generic_selftest (0, s_args, tolerance_xy, tolerance_lp, 4, 4, fwd_in, 0, s_fwd_expect, 0, 0, 0);
+}
+
+
+#endif
diff --git a/src/PJ_larr.c b/src/PJ_larr.c
index 118bef00..f55289b1 100644
--- a/src/PJ_larr.c
+++ b/src/PJ_larr.c
@@ -1,13 +1,70 @@
-#define PROJ_PARMS__
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(larr, "Larrivee") "\n\tMisc Sph, no inv.";
+
#define SIXTH .16666666666666666
-FORWARD(s_forward); /* sphere */
- (void) P;
- xy.x = 0.5 * lp.lam * (1. + sqrt(cos(lp.phi)));
- xy.y = lp.phi / (cos(0.5 * lp.phi) * cos(SIXTH * lp.lam));
- return (xy);
-}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(larr) P->fwd = s_forward; P->inv = 0; P->es = 0.; ENDENTRY(P)
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ (void) P;
+
+ xy.x = 0.5 * lp.lam * (1. + sqrt(cos(lp.phi)));
+ xy.y = lp.phi / (cos(0.5 * lp.phi) * cos(SIXTH * lp.lam));
+ return xy;
+}
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+
+ return pj_dealloc(P);
+}
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(larr) {
+
+ P->es = 0;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_larr_selftest (void) {return 0;}
+#else
+
+int pj_larr_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=larr +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.637624200899, 111707.215961255497},
+ {223393.637624200899, -111707.215961255497},
+ {-223393.637624200899, 111707.215961255497},
+ {-223393.637624200899, -111707.215961255497},
+ };
+
+ return pj_generic_selftest (0, s_args, tolerance_xy, tolerance_lp, 4, 4, fwd_in, 0, s_fwd_expect, 0, 0, 0);
+}
+
+
+#endif
diff --git a/src/PJ_lask.c b/src/PJ_lask.c
index 797b580d..38e7045c 100644
--- a/src/PJ_lask.c
+++ b/src/PJ_lask.c
@@ -1,27 +1,81 @@
-#define PROJ_PARMS__
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(lask, "Laskowski") "\n\tMisc Sph, no inv.";
-#define a10 0.975534
-#define a12 -0.119161
-#define a32 -0.0143059
-#define a14 -0.0547009
-#define b01 1.00384
-#define b21 0.0802894
-#define b03 0.0998909
-#define b41 0.000199025
-#define b23 -0.0285500
-#define b05 -0.0491032
-FORWARD(s_forward); /* sphere */
- double l2, p2;
- (void) P;
-
- l2 = lp.lam * lp.lam;
- p2 = lp.phi * lp.phi;
- xy.x = lp.lam * (a10 + p2 * (a12 + l2 * a32 + p2 * a14));
- xy.y = lp.phi * (b01 + l2 * (b21 + p2 * b23 + l2 * b41) +
- p2 * (b03 + p2 * b05));
- return (xy);
+
+#define a10 0.975534
+#define a12 -0.119161
+#define a32 -0.0143059
+#define a14 -0.0547009
+#define b01 1.00384
+#define b21 0.0802894
+#define b03 0.0998909
+#define b41 0.000199025
+#define b23 -0.0285500
+#define b05 -0.0491032
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ double l2, p2;
+ (void) P;
+
+ l2 = lp.lam * lp.lam;
+ p2 = lp.phi * lp.phi;
+ xy.x = lp.lam * (a10 + p2 * (a12 + l2 * a32 + p2 * a14));
+ xy.y = lp.phi * (b01 + l2 * (b21 + p2 * b23 + l2 * b41) +
+ p2 * (b03 + p2 * b05));
+ return xy;
+}
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+
+ pj_dealloc (P->opaque);
+ return pj_dealloc(P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(lask) {
+
+ P->fwd = s_forward;
+ P->es = 0.;
+
+ return P;
+}
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_lask_selftest (void) {return 0;}
+#else
+
+int pj_lask_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=lask +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 217928.275907355128, 112144.32922014239},
+ { 217928.275907355128, -112144.32922014239},
+ {-217928.275907355128, 112144.32922014239},
+ {-217928.275907355128, -112144.32922014239},
+ };
+
+ 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(lask) P->fwd = s_forward; P->inv = 0; P->es = 0.; ENDENTRY(P)
+
+
+#endif
diff --git a/src/PJ_lcc.c b/src/PJ_lcc.c
index 9d3494bf..e7b74be4 100644
--- a/src/PJ_lcc.c
+++ b/src/PJ_lcc.c
@@ -1,105 +1,196 @@
-#define PROJ_PARMS__ \
- double phi1; \
- double phi2; \
- double n; \
- double rho0; \
- double c; \
- int ellips;
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(lcc, "Lambert Conformal Conic")
- "\n\tConic, Sph&Ell\n\tlat_1= and lat_2= or lat_0";
-# define EPS10 1.e-10
-FORWARD(e_forward); /* ellipsoid & spheroid */
- double rho;
- if (fabs(fabs(lp.phi) - HALFPI) < EPS10) {
- if ((lp.phi * P->n) <= 0.) F_ERROR;
- rho = 0.;
- }
- else
- rho = P->c * (P->ellips ? pow(pj_tsfn(lp.phi, sin(lp.phi),
- P->e), P->n) : pow(tan(FORTPI + .5 * lp.phi), -P->n));
- xy.x = P->k0 * (rho * sin( lp.lam *= P->n ) );
- xy.y = P->k0 * (P->rho0 - rho * cos(lp.lam) );
- return (xy);
+ "\n\tConic, Sph&Ell\n\tlat_1= and lat_2= or lat_0";
+
+# define EPS10 1.e-10
+
+struct pj_opaque {
+ double phi1;
+ double phi2;
+ double n;
+ double rho0;
+ double c;
+ int ellips;
+};
+
+
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double rho;
+
+ if (fabs(fabs(lp.phi) - HALFPI) < EPS10) {
+ if ((lp.phi * Q->n) <= 0.) F_ERROR;
+ rho = 0.;
+ } else {
+ rho = Q->c * (Q->ellips ? pow(pj_tsfn(lp.phi, sin(lp.phi),
+ P->e), Q->n) : pow(tan(FORTPI + .5 * lp.phi), -Q->n));
+ }
+ lp.lam *= Q->n;
+ xy.x = P->k0 * (rho * sin( lp.lam) );
+ xy.y = P->k0 * (Q->rho0 - rho * cos(lp.lam) );
+ 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 rho;
+
+ xy.x /= P->k0;
+ xy.y /= P->k0;
+
+ xy.y = Q->rho0 - xy.y;
+ rho = hypot(xy.x, xy.y);
+ if (rho != 0.0) {
+ if (Q->n < 0.) {
+ rho = -rho;
+ xy.x = -xy.x;
+ xy.y = -xy.y;
+ }
+ if (Q->ellips) {
+ lp.phi = pj_phi2(P->ctx, pow(rho / Q->c, 1./Q->n), P->e);
+ if (lp.phi == HUGE_VAL)
+ I_ERROR;
+ } else
+ lp.phi = 2. * atan(pow(Q->c / rho, 1./Q->n)) - HALFPI;
+ lp.lam = atan2(xy.x, xy.y) / Q->n;
+ } else {
+ lp.lam = 0.;
+ lp.phi = Q->n > 0. ? HALFPI : - HALFPI;
+ }
+ return lp;
+}
+
+static void special(LP lp, PJ *P, struct FACTORS *fac) {
+ struct pj_opaque *Q = P->opaque;
+ double rho;
+ if (fabs(fabs(lp.phi) - HALFPI) < EPS10) {
+ if ((lp.phi * Q->n) <= 0.) return;
+ rho = 0.;
+ } else
+ rho = Q->c * (Q->ellips ? pow(pj_tsfn(lp.phi, sin(lp.phi),
+ P->e), Q->n) : pow(tan(FORTPI + .5 * lp.phi), -Q->n));
+ fac->code |= IS_ANAL_HK + IS_ANAL_CONV;
+ fac->k = fac->h = P->k0 * Q->n * rho /
+ pj_msfn(sin(lp.phi), cos(lp.phi), P->es);
+ fac->conv = - Q->n * lp.lam;
+}
+
+
+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;
}
-INVERSE(e_inverse); /* ellipsoid & spheroid */
- double rho;
- xy.x /= P->k0;
- xy.y /= P->k0;
- if( (rho = hypot(xy.x, xy.y = P->rho0 - xy.y)) != 0.0) {
- if (P->n < 0.) {
- rho = -rho;
- xy.x = -xy.x;
- xy.y = -xy.y;
- }
- if (P->ellips) {
- if ((lp.phi = pj_phi2(P->ctx, pow(rho / P->c, 1./P->n), P->e))
- == HUGE_VAL)
- I_ERROR;
- } else
- lp.phi = 2. * atan(pow(P->c / rho, 1./P->n)) - HALFPI;
- lp.lam = atan2(xy.x, xy.y) / P->n;
- } else {
- lp.lam = 0.;
- lp.phi = P->n > 0. ? HALFPI : - HALFPI;
- }
- return (lp);
+
+
+PJ *PROJECTION(lcc) {
+ double cosphi, sinphi;
+ int secant;
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+
+ Q->phi1 = pj_param(P->ctx, P->params, "rlat_1").f;
+ if (pj_param(P->ctx, P->params, "tlat_2").i)
+ Q->phi2 = pj_param(P->ctx, P->params, "rlat_2").f;
+ else {
+ Q->phi2 = Q->phi1;
+ if (!pj_param(P->ctx, P->params, "tlat_0").i)
+ P->phi0 = Q->phi1;
+ }
+ if (fabs(Q->phi1 + Q->phi2) < EPS10) E_ERROR(-21);
+ Q->n = sinphi = sin(Q->phi1);
+ cosphi = cos(Q->phi1);
+ secant = fabs(Q->phi1 - Q->phi2) >= EPS10;
+ if( (Q->ellips = (P->es != 0.)) ) {
+ double ml1, m1;
+
+ P->e = sqrt(P->es);
+ m1 = pj_msfn(sinphi, cosphi, P->es);
+ ml1 = pj_tsfn(Q->phi1, sinphi, P->e);
+ if (secant) { /* secant cone */
+ sinphi = sin(Q->phi2);
+ Q->n = log(m1 / pj_msfn(sinphi, cos(Q->phi2), P->es));
+ Q->n /= log(ml1 / pj_tsfn(Q->phi2, sinphi, P->e));
+ }
+ Q->c = (Q->rho0 = m1 * pow(ml1, -Q->n) / Q->n);
+ Q->rho0 *= (fabs(fabs(P->phi0) - HALFPI) < EPS10) ? 0. :
+ pow(pj_tsfn(P->phi0, sin(P->phi0), P->e), Q->n);
+ } else {
+ if (secant)
+ Q->n = log(cosphi / cos(Q->phi2)) /
+ log(tan(FORTPI + .5 * Q->phi2) /
+ tan(FORTPI + .5 * Q->phi1));
+ Q->c = cosphi * pow(tan(FORTPI + .5 * Q->phi1), Q->n) / Q->n;
+ Q->rho0 = (fabs(fabs(P->phi0) - HALFPI) < EPS10) ? 0. :
+ Q->c * pow(tan(FORTPI + .5 * P->phi0), -Q->n);
+ }
+
+ P->inv = e_inverse;
+ P->fwd = e_forward;
+ P->spc = special;
+
+ return P;
}
-SPECIAL(fac) {
- double rho;
- if (fabs(fabs(lp.phi) - HALFPI) < EPS10) {
- if ((lp.phi * P->n) <= 0.) return;
- rho = 0.;
- } else
- rho = P->c * (P->ellips ? pow(pj_tsfn(lp.phi, sin(lp.phi),
- P->e), P->n) : pow(tan(FORTPI + .5 * lp.phi), -P->n));
- fac->code |= IS_ANAL_HK + IS_ANAL_CONV;
- fac->k = fac->h = P->k0 * P->n * rho /
- pj_msfn(sin(lp.phi), cos(lp.phi), P->es);
- fac->conv = - P->n * lp.lam;
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_lcc_selftest (void) {return 0;}
+#else
+
+int pj_lcc_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=lcc +ellps=GRS80 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ { 222588.439735968423, 110660.533870799671},
+ { 222756.879700278747, -110532.797660827026},
+ {-222588.439735968423, 110660.533870799671},
+ {-222756.879700278747, -110532.797660827026},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ { 0.00179635940600536667, 0.000904232207322381741},
+ { 0.00179635817735249777, -0.000904233135128348995},
+ {-0.00179635940600536667, 0.000904232207322381741},
+ {-0.00179635817735249777, -0.000904233135128348995},
+ };
+
+ return pj_generic_selftest (e_args, 0, tolerance_xy, tolerance_lp, 4, 4, fwd_in, e_fwd_expect, 0, inv_in, e_inv_expect, 0);
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(lcc)
- double cosphi, sinphi;
- int secant;
-
- P->phi1 = pj_param(P->ctx, P->params, "rlat_1").f;
- if (pj_param(P->ctx, P->params, "tlat_2").i)
- P->phi2 = pj_param(P->ctx, P->params, "rlat_2").f;
- else {
- P->phi2 = P->phi1;
- if (!pj_param(P->ctx, P->params, "tlat_0").i)
- P->phi0 = P->phi1;
- }
- if (fabs(P->phi1 + P->phi2) < EPS10) E_ERROR(-21);
- P->n = sinphi = sin(P->phi1);
- cosphi = cos(P->phi1);
- secant = fabs(P->phi1 - P->phi2) >= EPS10;
- if( (P->ellips = (P->es != 0.)) ) {
- double ml1, m1;
-
- P->e = sqrt(P->es);
- m1 = pj_msfn(sinphi, cosphi, P->es);
- ml1 = pj_tsfn(P->phi1, sinphi, P->e);
- if (secant) { /* secant cone */
- P->n = log(m1 /
- pj_msfn(sinphi = sin(P->phi2), cos(P->phi2), P->es));
- P->n /= log(ml1 / pj_tsfn(P->phi2, sinphi, P->e));
- }
- P->c = (P->rho0 = m1 * pow(ml1, -P->n) / P->n);
- P->rho0 *= (fabs(fabs(P->phi0) - HALFPI) < EPS10) ? 0. :
- pow(pj_tsfn(P->phi0, sin(P->phi0), P->e), P->n);
- } else {
- if (secant)
- P->n = log(cosphi / cos(P->phi2)) /
- log(tan(FORTPI + .5 * P->phi2) /
- tan(FORTPI + .5 * P->phi1));
- P->c = cosphi * pow(tan(FORTPI + .5 * P->phi1), P->n) / P->n;
- P->rho0 = (fabs(fabs(P->phi0) - HALFPI) < EPS10) ? 0. :
- P->c * pow(tan(FORTPI + .5 * P->phi0), -P->n);
- }
- P->inv = e_inverse;
- P->fwd = e_forward;
- P->spc = fac;
-ENDENTRY(P)
+
+
+#endif
diff --git a/src/PJ_lcca.c b/src/PJ_lcca.c
index 320d52db..50c89978 100644
--- a/src/PJ_lcca.c
+++ b/src/PJ_lcca.c
@@ -1,70 +1,156 @@
-/* PROJ.4 Cartographic Projection System
+/* PROJ.4 Cartographic Projection System
*/
-#define MAX_ITER 10
-#define DEL_TOL 1e-12
-#define PROJ_PARMS__ \
- double *en; \
- double r0, l, M0; \
- double C;
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
PROJ_HEAD(lcca, "Lambert Conformal Conic Alternative")
- "\n\tConic, Sph&Ell\n\tlat_0=";
+ "\n\tConic, Sph&Ell\n\tlat_0=";
+
+#define MAX_ITER 10
+#define DEL_TOL 1e-12
+
+struct pj_opaque {
+ double *en;
+ double r0, l, M0;
+ double C;
+};
+
+
+static double fS(double S, double C) { /* func to compute dr */
+
+ return S * ( 1. + S * S * C);
+}
+
+
+static double fSp(double S, double C) { /* deriv of fs */
+
+ return 1. + 3.* S * S * C;
+}
+
+
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double S, r, dr;
+
+ S = pj_mlfn(lp.phi, sin(lp.phi), cos(lp.phi), Q->en) - Q->M0;
+ dr = fS(S, Q->C);
+ r = Q->r0 - dr;
+ xy.x = P->k0 * (r * sin( lp.lam *= Q->l ) );
+ xy.y = P->k0 * (Q->r0 - r * cos(lp.lam) );
+ 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 theta, dr, S, dif;
+ int i;
+
+ xy.x /= P->k0;
+ xy.y /= P->k0;
+ theta = atan2(xy.x , Q->r0 - xy.y);
+ dr = xy.y - xy.x * tan(0.5 * theta);
+ lp.lam = theta / Q->l;
+ S = dr;
+ for (i = MAX_ITER; i ; --i) {
+ S -= (dif = (fS(S, Q->C) - dr) / fSp(S, Q->C));
+ if (fabs(dif) < DEL_TOL) break;
+ }
+ if (!i) I_ERROR
+ lp.phi = pj_inv_mlfn(P->ctx, S + Q->M0, P->es, Q->en);
- static double /* func to compute dr */
-fS(double S, double C) {
- return(S * ( 1. + S * S * C));
+ return lp;
}
- static double /* deriv of fs */
-fSp(double S, double C) {
- return(1. + 3.* S * S * C);
+
+
+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);
}
-FORWARD(e_forward); /* ellipsoid */
- double S, r, dr;
-
- S = pj_mlfn(lp.phi, sin(lp.phi), cos(lp.phi), P->en) - P->M0;
- dr = fS(S, P->C);
- r = P->r0 - dr;
- xy.x = P->k0 * (r * sin( lp.lam *= P->l ) );
- xy.y = P->k0 * (P->r0 - r * cos(lp.lam) );
- return (xy);
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
}
-INVERSE(e_inverse); /* ellipsoid & spheroid */
- double theta, dr, S, dif;
- int i;
-
- xy.x /= P->k0;
- xy.y /= P->k0;
- theta = atan2(xy.x , P->r0 - xy.y);
- dr = xy.y - xy.x * tan(0.5 * theta);
- lp.lam = theta / P->l;
- S = dr;
- for (i = MAX_ITER; i ; --i) {
- S -= (dif = (fS(S, P->C) - dr) / fSp(S, P->C));
- if (fabs(dif) < DEL_TOL) break;
- }
- if (!i) I_ERROR
- lp.phi = pj_inv_mlfn(P->ctx, S + P->M0, P->es, P->en);
- return (lp);
+
+
+PJ *PROJECTION(lcca) {
+ double s2p0, N0, R0, tan0;
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ (Q->en = pj_enfn(P->es));
+ if (!Q->en) E_ERROR_0;
+ if (!pj_param(P->ctx, P->params, "tlat_0").i) E_ERROR(50);
+ if (P->phi0 == 0.) E_ERROR(51);
+ Q->l = sin(P->phi0);
+ Q->M0 = pj_mlfn(P->phi0, Q->l, cos(P->phi0), Q->en);
+ s2p0 = Q->l * Q->l;
+ R0 = 1. / (1. - P->es * s2p0);
+ N0 = sqrt(R0);
+ R0 *= P->one_es * N0;
+ tan0 = tan(P->phi0);
+ Q->r0 = N0 / tan0;
+ Q->C = 1. / (6. * R0 * N0);
+
+ P->inv = e_inverse;
+ P->fwd = e_forward;
+
+ return P;
}
-FREEUP; if (P) { if (P->en) pj_dalloc(P->en); pj_dalloc(P); } }
-ENTRY0(lcca)
- double s2p0, N0, R0, tan0;
-
- if (!(P->en = pj_enfn(P->es))) E_ERROR_0;
- if (!pj_param(P->ctx, P->params, "tlat_0").i) E_ERROR(50);
- if (P->phi0 == 0.) E_ERROR(51);
- P->l = sin(P->phi0);
- P->M0 = pj_mlfn(P->phi0, P->l, cos(P->phi0), P->en);
- s2p0 = P->l * P->l;
- R0 = 1. / (1. - P->es * s2p0);
- N0 = sqrt(R0);
- R0 *= P->one_es * N0;
- tan0 = tan(P->phi0);
- P->r0 = N0 / tan0;
- P->C = 1. / (6. * R0 * N0);
- P->inv = e_inverse;
- P->fwd = e_forward;
-ENDENTRY(P)
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_lcca_selftest (void) {return 0;}
+#else
+
+int pj_lcca_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=lcca +ellps=GRS80 +lat_0=1 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ { 222605.285770237417, 67.8060072715846616},
+ { 222740.037637936533, -221125.539829601563},
+ {-222605.285770237417, 67.8060072715846616},
+ {-222740.037637936533, -221125.539829601563},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ { 0.00179690290525662526, 1.00090436621350798},
+ { 0.00179690192174008037, 0.999095632791497268},
+ {-0.00179690290525662526, 1.00090436621350798},
+ {-0.00179690192174008037, 0.999095632791497268},
+ };
+
+ return pj_generic_selftest (e_args, 0, tolerance_xy, tolerance_lp, 4, 4, fwd_in, e_fwd_expect, 0, inv_in, e_inv_expect, 0);
+}
+
+
+#endif
diff --git a/src/PJ_loxim.c b/src/PJ_loxim.c
index 595423f7..9ddfd51c 100644
--- a/src/PJ_loxim.c
+++ b/src/PJ_loxim.c
@@ -1,41 +1,130 @@
-#define PROJ_PARMS__ \
- double phi1; \
- double cosphi1; \
- double tanphi1;
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(loxim, "Loximuthal") "\n\tPCyl Sph";
-#define EPS 1e-8
-FORWARD(s_forward); /* spheroid */
- xy.y = lp.phi - P->phi1;
- if (fabs(xy.y) < EPS)
- xy.x = lp.lam * P->cosphi1;
- else {
- xy.x = FORTPI + 0.5 * lp.phi;
- if (fabs(xy.x) < EPS || fabs(fabs(xy.x) - HALFPI) < EPS)
- xy.x = 0.;
- else
- xy.x = lp.lam * xy.y / log( tan(xy.x) / P->tanphi1 );
- }
- return (xy);
+
+#define EPS 1e-8
+
+struct pj_opaque {
+ double phi1;
+ double cosphi1;
+ double tanphi1;
+};
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+
+ xy.y = lp.phi - Q->phi1;
+ if (fabs(xy.y) < EPS)
+ xy.x = lp.lam * Q->cosphi1;
+ else {
+ xy.x = FORTPI + 0.5 * lp.phi;
+ if (fabs(xy.x) < EPS || fabs(fabs(xy.x) - HALFPI) < EPS)
+ xy.x = 0.;
+ else
+ xy.x = lp.lam * xy.y / log( tan(xy.x) / Q->tanphi1 );
+ }
+ return xy;
}
-INVERSE(s_inverse); /* spheroid */
- lp.phi = xy.y + P->phi1;
- if (fabs(xy.y) < EPS)
- lp.lam = xy.x / P->cosphi1;
- else
- if (fabs( lp.lam = FORTPI + 0.5 * lp.phi ) < EPS ||
- fabs(fabs(lp.lam) - HALFPI) < EPS)
- lp.lam = 0.;
- else
- lp.lam = xy.x * log( tan(lp.lam) / P->tanphi1 ) / xy.y ;
- return (lp);
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+
+ lp.phi = xy.y + Q->phi1;
+ if (fabs(xy.y) < EPS) {
+ lp.lam = xy.x / Q->cosphi1;
+ } else {
+ lp.lam = FORTPI + 0.5 * lp.phi;
+ if (fabs(lp.lam) < EPS || fabs(fabs(lp.lam) - HALFPI) < EPS)
+ lp.lam = 0.;
+ else
+ lp.lam = xy.x * log( tan(lp.lam) / Q->tanphi1 ) / xy.y ;
+ }
+ return lp;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(loxim);
- P->phi1 = pj_param(P->ctx, P->params, "rlat_1").f;
- if ((P->cosphi1 = cos(P->phi1)) < EPS) E_ERROR(-22);
- P->tanphi1 = tan(FORTPI + 0.5 * P->phi1);
- P->inv = s_inverse; P->fwd = s_forward;
- P->es = 0.;
-ENDENTRY(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;
+}
+
+
+PJ *PROJECTION(loxim) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->phi1 = pj_param(P->ctx, P->params, "rlat_1").f;
+ Q->cosphi1 = cos(Q->phi1);
+ if (Q->cosphi1 < EPS)
+ E_ERROR(-22);
+
+ Q->tanphi1 = tan(FORTPI + 0.5 * Q->phi1);
+
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+ P->es = 0.;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_loxim_selftest (void) {return 0;}
+#else
+
+int pj_loxim_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=loxim +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 223382.295791338867, 55850.5360638185448},
+ { 223393.637462243292, -167551.608191455656},
+ {-223382.295791338867, 55850.5360638185448},
+ {-223393.637462243292, -167551.608191455656},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.00179056141104335601, 0.500895246554891926},
+ { 0.00179056116683692576, 0.499104753445108074},
+ {-0.00179056141104335601, 0.500895246554891926},
+ {-0.00179056116683692576, 0.499104753445108074},
+ };
+
+ 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_lsat.c b/src/PJ_lsat.c
index d11a5c14..fa96407b 100644
--- a/src/PJ_lsat.c
+++ b/src/PJ_lsat.c
@@ -1,171 +1,258 @@
/* based upon Snyder and Linck, USGS-NMD */
-#define PROJ_PARMS__ \
- double a2, a4, b, c1, c3; \
- double q, t, u, w, p22, sa, ca, xj, rlm, rlm2;
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(lsat, "Space oblique for LANDSAT")
- "\n\tCyl, Sph&Ell\n\tlsat= path=";
+ "\n\tCyl, Sph&Ell\n\tlsat= path=";
+
#define TOL 1e-7
#define PI_HALFPI 4.71238898038468985766
#define TWOPI_HALFPI 7.85398163397448309610
- static void
-seraz0(double lam, double mult, PJ *P) {
- double sdsq, h, s, fc, sd, sq, d__1;
+
+struct pj_opaque {
+ double a2, a4, b, c1, c3;
+ double q, t, u, w, p22, sa, ca, xj, rlm, rlm2;
+};
+
+static void seraz0(double lam, double mult, PJ *P) {
+ struct pj_opaque *Q = P->opaque;
+ double sdsq, h, s, fc, sd, sq, d__1 = 0;
lam *= DEG_TO_RAD;
sd = sin(lam);
sdsq = sd * sd;
- s = P->p22 * P->sa * cos(lam) * sqrt((1. + P->t * sdsq) / ((
- 1. + P->w * sdsq) * (1. + P->q * sdsq)));
- d__1 = 1. + P->q * sdsq;
- h = sqrt((1. + P->q * sdsq) / (1. + P->w * sdsq)) * ((1. +
- P->w * sdsq) / (d__1 * d__1) - P->p22 * P->ca);
- sq = sqrt(P->xj * P->xj + s * s);
- P->b += fc = mult * (h * P->xj - s * s) / sq;
- P->a2 += fc * cos(lam + lam);
- P->a4 += fc * cos(lam * 4.);
- fc = mult * s * (h + P->xj) / sq;
- P->c1 += fc * cos(lam);
- P->c3 += fc * cos(lam * 3.);
+ s = Q->p22 * Q->sa * cos(lam) * sqrt((1. + Q->t * sdsq)
+ / ((1. + Q->w * sdsq) * (1. + Q->q * sdsq)));
+
+ h = sqrt((1. + Q->q * sdsq) / (1. + Q->w * sdsq)) * ((1. + Q->w * sdsq)
+ / (d__1 * d__1) - Q->p22 * Q->ca);
+
+ sq = sqrt(Q->xj * Q->xj + s * s);
+ fc = mult * (h * Q->xj - s * s) / sq;
+ Q->b += fc;
+ Q->a2 += fc * cos(lam + lam);
+ Q->a4 += fc * cos(lam * 4.);
+ fc = mult * s * (h + Q->xj) / sq;
+ Q->c1 += fc * cos(lam);
+ Q->c3 += fc * cos(lam * 3.);
}
-FORWARD(e_forward); /* ellipsoid */
+
+
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
int l, nn;
- double lamt, xlam, sdsq, c, d, s, lamdp, phidp, lampp, tanph,
- lamtp, cl, sd, sp, fac, sav, tanphi;
-
- if (lp.phi > HALFPI)
- lp.phi = HALFPI;
- else if (lp.phi < -HALFPI)
- lp.phi = -HALFPI;
- lampp = lp.phi >= 0. ? HALFPI : PI_HALFPI;
- tanphi = tan(lp.phi);
- for (nn = 0;;) {
- sav = lampp;
- lamtp = lp.lam + P->p22 * lampp;
- cl = cos(lamtp);
- if (fabs(cl) < TOL)
- lamtp -= TOL;
- fac = lampp - sin(lampp) * (cl < 0. ? -HALFPI : HALFPI);
- for (l = 50; l; --l) {
- lamt = lp.lam + P->p22 * sav;
- if (fabs(c = cos(lamt)) < TOL)
- lamt -= TOL;
- xlam = (P->one_es * tanphi * P->sa + sin(lamt) * P->ca) / c;
- lamdp = atan(xlam) + fac;
- if (fabs(fabs(sav) - fabs(lamdp)) < TOL)
- break;
- sav = lamdp;
- }
- if (!l || ++nn >= 3 || (lamdp > P->rlm && lamdp < P->rlm2))
- break;
- if (lamdp <= P->rlm)
- lampp = TWOPI_HALFPI;
- else if (lamdp >= P->rlm2)
- lampp = HALFPI;
- }
- if (l) {
- sp = sin(lp.phi);
- phidp = aasin(P->ctx,(P->one_es * P->ca * sp - P->sa * cos(lp.phi) *
- sin(lamt)) / sqrt(1. - P->es * sp * sp));
- tanph = log(tan(FORTPI + .5 * phidp));
- sd = sin(lamdp);
- sdsq = sd * sd;
- s = P->p22 * P->sa * cos(lamdp) * sqrt((1. + P->t * sdsq)
- / ((1. + P->w * sdsq) * (1. + P->q * sdsq)));
- d = sqrt(P->xj * P->xj + s * s);
- xy.x = P->b * lamdp + P->a2 * sin(2. * lamdp) + P->a4 *
- sin(lamdp * 4.) - tanph * s / d;
- xy.y = P->c1 * sd + P->c3 * sin(lamdp * 3.) + tanph * P->xj / d;
- } else
- xy.x = xy.y = HUGE_VAL;
- return xy;
+ double lamt, xlam, sdsq, c, d, s, lamdp, phidp, lampp, tanph;
+ double lamtp, cl, sd, sp, fac, sav, tanphi;
+
+ if (lp.phi > HALFPI)
+ lp.phi = HALFPI;
+ else if (lp.phi < -HALFPI)
+ lp.phi = -HALFPI;
+
+ lampp = lp.phi >= 0. ? HALFPI : PI_HALFPI;
+ tanphi = tan(lp.phi);
+ for (nn = 0;;) {
+ sav = lampp;
+ lamtp = lp.lam + Q->p22 * lampp;
+ cl = cos(lamtp);
+ if (fabs(cl) < TOL)
+ lamtp -= TOL;
+ fac = lampp - sin(lampp) * (cl < 0. ? -HALFPI : HALFPI);
+ for (l = 50; l; --l) {
+ lamt = lp.lam + Q->p22 * sav;
+ c = cos(lamt);
+ if (fabs(c) < TOL)
+ lamt -= TOL;
+ xlam = (P->one_es * tanphi * Q->sa + sin(lamt) * Q->ca) / c;
+ lamdp = atan(xlam) + fac;
+ if (fabs(fabs(sav) - fabs(lamdp)) < TOL)
+ break;
+ sav = lamdp;
+ }
+ if (!l || ++nn >= 3 || (lamdp > Q->rlm && lamdp < Q->rlm2))
+ break;
+ if (lamdp <= Q->rlm)
+ lampp = TWOPI_HALFPI;
+ else if (lamdp >= Q->rlm2)
+ lampp = HALFPI;
+ }
+ if (l) {
+ sp = sin(lp.phi);
+ phidp = aasin(P->ctx,(P->one_es * Q->ca * sp - Q->sa * cos(lp.phi) *
+ sin(lamt)) / sqrt(1. - P->es * sp * sp));
+ tanph = log(tan(FORTPI + .5 * phidp));
+ sd = sin(lamdp);
+ sdsq = sd * sd;
+ s = Q->p22 * Q->sa * cos(lamdp) * sqrt((1. + Q->t * sdsq)
+ / ((1. + Q->w * sdsq) * (1. + Q->q * sdsq)));
+ d = sqrt(Q->xj * Q->xj + s * s);
+ xy.x = Q->b * lamdp + Q->a2 * sin(2. * lamdp) + Q->a4 *
+ sin(lamdp * 4.) - tanph * s / d;
+ xy.y = Q->c1 * sd + Q->c3 * sin(lamdp * 3.) + tanph * Q->xj / d;
+ } else
+ xy.x = xy.y = HUGE_VAL;
+ return xy;
}
-INVERSE(e_inverse); /* ellipsoid */
+
+
+static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
int nn;
double lamt, sdsq, s, lamdp, phidp, sppsq, dd, sd, sl, fac, scl, sav, spp;
- lamdp = xy.x / P->b;
- nn = 50;
- do {
- sav = lamdp;
- sd = sin(lamdp);
- sdsq = sd * sd;
- s = P->p22 * P->sa * cos(lamdp) * sqrt((1. + P->t * sdsq)
- / ((1. + P->w * sdsq) * (1. + P->q * sdsq)));
- lamdp = xy.x + xy.y * s / P->xj - P->a2 * sin(
- 2. * lamdp) - P->a4 * sin(lamdp * 4.) - s / P->xj * (
- P->c1 * sin(lamdp) + P->c3 * sin(lamdp * 3.));
- lamdp /= P->b;
- } while (fabs(lamdp - sav) >= TOL && --nn);
- sl = sin(lamdp);
- fac = exp(sqrt(1. + s * s / P->xj / P->xj) * (xy.y -
- P->c1 * sl - P->c3 * sin(lamdp * 3.)));
- phidp = 2. * (atan(fac) - FORTPI);
- dd = sl * sl;
- if (fabs(cos(lamdp)) < TOL)
- lamdp -= TOL;
- spp = sin(phidp);
- sppsq = spp * spp;
- lamt = atan(((1. - sppsq * P->rone_es) * tan(lamdp) *
- P->ca - spp * P->sa * sqrt((1. + P->q * dd) * (
- 1. - sppsq) - sppsq * P->u) / cos(lamdp)) / (1. - sppsq
- * (1. + P->u)));
- sl = lamt >= 0. ? 1. : -1.;
- scl = cos(lamdp) >= 0. ? 1. : -1;
- lamt -= HALFPI * (1. - scl) * sl;
- lp.lam = lamt - P->p22 * lamdp;
- if (fabs(P->sa) < TOL)
- lp.phi = aasin(P->ctx,spp / sqrt(P->one_es * P->one_es + P->es * sppsq));
- else
- lp.phi = atan((tan(lamdp) * cos(lamt) - P->ca * sin(lamt)) /
- (P->one_es * P->sa));
- return lp;
+ lamdp = xy.x / Q->b;
+ nn = 50;
+ do {
+ sav = lamdp;
+ sd = sin(lamdp);
+ sdsq = sd * sd;
+ s = Q->p22 * Q->sa * cos(lamdp) * sqrt((1. + Q->t * sdsq)
+ / ((1. + Q->w * sdsq) * (1. + Q->q * sdsq)));
+ lamdp = xy.x + xy.y * s / Q->xj - Q->a2 * sin(
+ 2. * lamdp) - Q->a4 * sin(lamdp * 4.) - s / Q->xj * (
+ Q->c1 * sin(lamdp) + Q->c3 * sin(lamdp * 3.));
+ lamdp /= Q->b;
+ } while (fabs(lamdp - sav) >= TOL && --nn);
+ sl = sin(lamdp);
+ fac = exp(sqrt(1. + s * s / Q->xj / Q->xj) * (xy.y -
+ Q->c1 * sl - Q->c3 * sin(lamdp * 3.)));
+ phidp = 2. * (atan(fac) - FORTPI);
+ dd = sl * sl;
+ if (fabs(cos(lamdp)) < TOL)
+ lamdp -= TOL;
+ spp = sin(phidp);
+ sppsq = spp * spp;
+ lamt = atan(((1. - sppsq * P->rone_es) * tan(lamdp) *
+ Q->ca - spp * Q->sa * sqrt((1. + Q->q * dd) * (
+ 1. - sppsq) - sppsq * Q->u) / cos(lamdp)) / (1. - sppsq
+ * (1. + Q->u)));
+ sl = lamt >= 0. ? 1. : -1.;
+ scl = cos(lamdp) >= 0. ? 1. : -1;
+ lamt -= HALFPI * (1. - scl) * sl;
+ lp.lam = lamt - Q->p22 * lamdp;
+ if (fabs(Q->sa) < TOL)
+ lp.phi = aasin(P->ctx,spp / sqrt(P->one_es * P->one_es + P->es * sppsq));
+ else
+ lp.phi = atan((tan(lamdp) * cos(lamt) - Q->ca * sin(lamt)) /
+ (P->one_es * Q->sa));
+ return lp;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(lsat)
+
+
+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(lsat) {
int land, path;
double lam, alf, esc, ess;
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ land = pj_param(P->ctx, P->params, "ilsat").i;
+ if (land <= 0 || land > 5) E_ERROR(-28);
+ path = pj_param(P->ctx, P->params, "ipath").i;
+ if (path <= 0 || path > (land <= 3 ? 251 : 233)) E_ERROR(-29);
+ if (land <= 3) {
+ P->lam0 = DEG_TO_RAD * 128.87 - TWOPI / 251. * path;
+ Q->p22 = 103.2669323;
+ alf = DEG_TO_RAD * 99.092;
+ } else {
+ P->lam0 = DEG_TO_RAD * 129.3 - TWOPI / 233. * path;
+ Q->p22 = 98.8841202;
+ alf = DEG_TO_RAD * 98.2;
+ }
+ Q->p22 /= 1440.;
+ Q->sa = sin(alf);
+ Q->ca = cos(alf);
+ if (fabs(Q->ca) < 1e-9)
+ Q->ca = 1e-9;
+ esc = P->es * Q->ca * Q->ca;
+ ess = P->es * Q->sa * Q->sa;
+ Q->w = (1. - esc) * P->rone_es;
+ Q->w = Q->w * Q->w - 1.;
+ Q->q = ess * P->rone_es;
+ Q->t = ess * (2. - P->es) * P->rone_es * P->rone_es;
+ Q->u = esc * P->rone_es;
+ Q->xj = P->one_es * P->one_es * P->one_es;
+ Q->rlm = PI * (1. / 248. + .5161290322580645);
+ Q->rlm2 = Q->rlm + TWOPI;
+ Q->a2 = Q->a4 = Q->b = Q->c1 = Q->c3 = 0.;
+ seraz0(0., 1., P);
+ for (lam = 9.; lam <= 81.0001; lam += 18.)
+ seraz0(lam, 4., P);
+ for (lam = 18; lam <= 72.0001; lam += 18.)
+ seraz0(lam, 2., P);
+ seraz0(90., 1., P);
+ Q->a2 /= 30.;
+ Q->a4 /= 60.;
+ Q->b /= 30.;
+ Q->c1 /= 15.;
+ Q->c3 /= 45.;
+
+ P->inv = e_inverse;
+ P->fwd = e_forward;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_lsat_selftest (void) {return 0;}
+#else
+
+int pj_lsat_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=lsat +ellps=GRS80 +lat_1=0.5 +lat_2=2 +lsat=1 +path=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ {18241950.01455855, 9998256.83982293494},
+ {18746856.2533194572, 10215761.669925211},
+ {18565503.6836331636, 9085039.14672705345},
+ {19019696.9020289108, 9247763.0394328218},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ {126.000423834530011, 0.00172378224025701425},
+ {126.002213738256714, 0.00188015467480917966},
+ {126.000734468914601, -0.00188015467480917966},
+ {126.002524372641304, -0.00172378224025701425},
+ };
+
+ return pj_generic_selftest (e_args, 0, tolerance_xy, tolerance_lp, 4, 4, fwd_in, e_fwd_expect, 0, inv_in, e_inv_expect, 0);
+}
+
- land = pj_param(P->ctx, P->params, "ilsat").i;
- if (land <= 0 || land > 5) E_ERROR(-28);
- path = pj_param(P->ctx, P->params, "ipath").i;
- if (path <= 0 || path > (land <= 3 ? 251 : 233)) E_ERROR(-29);
- if (land <= 3) {
- P->lam0 = DEG_TO_RAD * 128.87 - TWOPI / 251. * path;
- P->p22 = 103.2669323;
- alf = DEG_TO_RAD * 99.092;
- } else {
- P->lam0 = DEG_TO_RAD * 129.3 - TWOPI / 233. * path;
- P->p22 = 98.8841202;
- alf = DEG_TO_RAD * 98.2;
- }
- P->p22 /= 1440.;
- P->sa = sin(alf);
- P->ca = cos(alf);
- if (fabs(P->ca) < 1e-9)
- P->ca = 1e-9;
- esc = P->es * P->ca * P->ca;
- ess = P->es * P->sa * P->sa;
- P->w = (1. - esc) * P->rone_es;
- P->w = P->w * P->w - 1.;
- P->q = ess * P->rone_es;
- P->t = ess * (2. - P->es) * P->rone_es * P->rone_es;
- P->u = esc * P->rone_es;
- P->xj = P->one_es * P->one_es * P->one_es;
- P->rlm = PI * (1. / 248. + .5161290322580645);
- P->rlm2 = P->rlm + TWOPI;
- P->a2 = P->a4 = P->b = P->c1 = P->c3 = 0.;
- seraz0(0., 1., P);
- for (lam = 9.; lam <= 81.0001; lam += 18.)
- seraz0(lam, 4., P);
- for (lam = 18; lam <= 72.0001; lam += 18.)
- seraz0(lam, 2., P);
- seraz0(90., 1., P);
- P->a2 /= 30.;
- P->a4 /= 60.;
- P->b /= 30.;
- P->c1 /= 15.;
- P->c3 /= 45.;
- P->inv = e_inverse; P->fwd = e_forward;
-ENDENTRY(P)
+#endif
diff --git a/src/PJ_mbt_fps.c b/src/PJ_mbt_fps.c
index 3cd5e674..daa1555c 100644
--- a/src/PJ_mbt_fps.c
+++ b/src/PJ_mbt_fps.c
@@ -1,39 +1,112 @@
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(mbt_fps, "McBryde-Thomas Flat-Pole Sine (No. 2)") "\n\tCyl., Sph.";
-#define MAX_ITER 10
-#define LOOP_TOL 1e-7
+
+#define MAX_ITER 10
+#define LOOP_TOL 1e-7
#define C1 0.45503
#define C2 1.36509
#define C3 1.41546
#define C_x 0.22248
#define C_y 1.44492
#define C1_2 0.33333333333333333333333333
-FORWARD(s_forward); /* spheroid */
- double k, V, t;
- int i;
- (void) P;
-
- k = C3 * sin(lp.phi);
- for (i = MAX_ITER; i ; --i) {
- t = lp.phi / C2;
- lp.phi -= V = (C1 * sin(t) + sin(lp.phi) - k) /
- (C1_2 * cos(t) + cos(lp.phi));
- if (fabs(V) < LOOP_TOL)
- break;
- }
- t = lp.phi / C2;
- xy.x = C_x * lp.lam * (1. + 3. * cos(lp.phi)/cos(t) );
- xy.y = C_y * sin(t);
- return (xy);
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ double k, V, t;
+ int i;
+ (void) P;
+
+ k = C3 * sin(lp.phi);
+ for (i = MAX_ITER; i ; --i) {
+ t = lp.phi / C2;
+ lp.phi -= V = (C1 * sin(t) + sin(lp.phi) - k) /
+ (C1_2 * cos(t) + cos(lp.phi));
+ if (fabs(V) < LOOP_TOL)
+ break;
+ }
+ t = lp.phi / C2;
+ xy.x = C_x * lp.lam * (1. + 3. * cos(lp.phi)/cos(t) );
+ xy.y = C_y * sin(t);
+ return xy;
}
-INVERSE(s_inverse); /* spheroid */
- double t;
- lp.phi = C2 * (t = aasin(P->ctx,xy.y / C_y));
- lp.lam = xy.x / (C_x * (1. + 3. * cos(lp.phi)/cos(t)));
- lp.phi = aasin(P->ctx,(C1 * sin(t) + sin(lp.phi)) / C3);
- return (lp);
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ double t;
+
+ lp.phi = C2 * (t = aasin(P->ctx,xy.y / C_y));
+ lp.lam = xy.x / (C_x * (1. + 3. * cos(lp.phi)/cos(t)));
+ lp.phi = aasin(P->ctx,(C1 * sin(t) + sin(lp.phi)) / C3);
+ return (lp);
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(mbt_fps) P->es = 0; P->inv = s_inverse; P->fwd = s_forward; ENDENTRY(P)
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+
+ return pj_dealloc(P);
+}
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(mbt_fps) {
+
+ P->es = 0;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_mbt_fps_selftest (void) {return 0;}
+#else
+
+int pj_mbt_fps_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=mbt_fps +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 198798.176129849948, 125512.017254530627},
+ { 198798.176129849948, -125512.017254530627},
+ {-198798.176129849948, 125512.017254530627},
+ {-198798.176129849948, -125512.017254530627},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.00201197086238270742, 0.000796711850174446003},
+ { 0.00201197086238270742, -0.000796711850174446003},
+ {-0.00201197086238270742, 0.000796711850174446003},
+ {-0.00201197086238270742, -0.000796711850174446003},
+ };
+
+ 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_mbtfpp.c b/src/PJ_mbtfpp.c
index 433d3c8f..688150fe 100644
--- a/src/PJ_mbtfpp.c
+++ b/src/PJ_mbtfpp.c
@@ -1,33 +1,114 @@
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(mbtfpp, "McBride-Thomas Flat-Polar Parabolic") "\n\tCyl., Sph.";
-#define CS .95257934441568037152
-#define FXC .92582009977255146156
-#define FYC 3.40168025708304504493
-#define C23 .66666666666666666666
-#define C13 .33333333333333333333
-#define ONEEPS 1.0000001
-FORWARD(s_forward); /* spheroid */
- (void) P;
- lp.phi = asin(CS * sin(lp.phi));
- xy.x = FXC * lp.lam * (2. * cos(C23 * lp.phi) - 1.);
- xy.y = FYC * sin(C13 * lp.phi);
- return (xy);
+
+#define CS .95257934441568037152
+#define FXC .92582009977255146156
+#define FYC 3.40168025708304504493
+#define C23 .66666666666666666666
+#define C13 .33333333333333333333
+#define ONEEPS 1.0000001
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ (void) P;
+
+ lp.phi = asin(CS * sin(lp.phi));
+ xy.x = FXC * lp.lam * (2. * cos(C23 * lp.phi) - 1.);
+ xy.y = FYC * sin(C13 * lp.phi);
+ return xy;
}
-INVERSE(s_inverse); /* spheroid */
- lp.phi = xy.y / FYC;
- if (fabs(lp.phi) >= 1.) {
- if (fabs(lp.phi) > ONEEPS) I_ERROR
- else lp.phi = (lp.phi < 0.) ? -HALFPI : HALFPI;
- } else
- lp.phi = asin(lp.phi);
- lp.lam = xy.x / ( FXC * (2. * cos(C23 * (lp.phi *= 3.)) - 1.) );
- if (fabs(lp.phi = sin(lp.phi) / CS) >= 1.) {
- if (fabs(lp.phi) > ONEEPS) I_ERROR
- else lp.phi = (lp.phi < 0.) ? -HALFPI : HALFPI;
- } else
- lp.phi = asin(lp.phi);
- return (lp);
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+
+ lp.phi = xy.y / FYC;
+ if (fabs(lp.phi) >= 1.) {
+ if (fabs(lp.phi) > ONEEPS)
+ I_ERROR
+ else
+ lp.phi = (lp.phi < 0.) ? -HALFPI : HALFPI;
+ } else
+ lp.phi = asin(lp.phi);
+
+ lp.lam = xy.x / ( FXC * (2. * cos(C23 * (lp.phi *= 3.)) - 1.) );
+ if (fabs(lp.phi = sin(lp.phi) / CS) >= 1.) {
+ if (fabs(lp.phi) > ONEEPS)
+ I_ERROR
+ else
+ lp.phi = (lp.phi < 0.) ? -HALFPI : HALFPI;
+ } else
+ lp.phi = asin(lp.phi);
+
+ return lp;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(mbtfpp) P->es = 0.; P->inv = s_inverse; P->fwd = s_forward; ENDENTRY(P)
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+
+ return pj_dealloc(P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(mbtfpp) {
+
+ P->es = 0.;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_mbtfpp_selftest (void) {return 0;}
+#else
+
+int pj_mbtfpp_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=mbtfpp +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ {206804.786929820373, 120649.762565792524},
+ {206804.786929820373, -120649.762565792524},
+ {-206804.786929820373, 120649.762565792524},
+ {-206804.786929820373, -120649.762565792524},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ {0.00193395359462902698, 0.00082883725477665357},
+ {0.00193395359462902698, -0.00082883725477665357},
+ {-0.00193395359462902698, 0.00082883725477665357},
+ {-0.00193395359462902698, -0.00082883725477665357},
+ };
+
+ 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_mbtfpq.c b/src/PJ_mbtfpq.c
index 0d343fad..d382f45a 100644
--- a/src/PJ_mbtfpq.c
+++ b/src/PJ_mbtfpq.c
@@ -1,48 +1,121 @@
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(mbtfpq, "McBryde-Thomas Flat-Polar Quartic") "\n\tCyl., Sph.";
-#define NITER 20
-#define EPS 1e-7
+
+#define NITER 20
+#define EPS 1e-7
#define ONETOL 1.000001
-#define C 1.70710678118654752440
-#define RC 0.58578643762690495119
-#define FYC 1.87475828462269495505
-#define RYC 0.53340209679417701685
-#define FXC 0.31245971410378249250
-#define RXC 3.20041258076506210122
-FORWARD(s_forward); /* spheroid */
- double th1, c;
- int i;
- (void) P;
-
- c = C * sin(lp.phi);
- for (i = NITER; i; --i) {
- lp.phi -= th1 = (sin(.5*lp.phi) + sin(lp.phi) - c) /
- (.5*cos(.5*lp.phi) + cos(lp.phi));
- if (fabs(th1) < EPS) break;
- }
- xy.x = FXC * lp.lam * (1.0 + 2. * cos(lp.phi)/cos(0.5 * lp.phi));
- xy.y = FYC * sin(0.5 * lp.phi);
- return (xy);
+#define C 1.70710678118654752440
+#define RC 0.58578643762690495119
+#define FYC 1.87475828462269495505
+#define RYC 0.53340209679417701685
+#define FXC 0.31245971410378249250
+#define RXC 3.20041258076506210122
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ double th1, c;
+ int i;
+ (void) P;
+
+ c = C * sin(lp.phi);
+ for (i = NITER; i; --i) {
+ lp.phi -= th1 = (sin(.5*lp.phi) + sin(lp.phi) - c) /
+ (.5*cos(.5*lp.phi) + cos(lp.phi));
+ if (fabs(th1) < EPS) break;
+ }
+ xy.x = FXC * lp.lam * (1.0 + 2. * cos(lp.phi)/cos(0.5 * lp.phi));
+ xy.y = FYC * sin(0.5 * lp.phi);
+ return xy;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ double t;
+
+ lp.phi = RYC * xy.y;
+ if (fabs(lp.phi) > 1.) {
+ if (fabs(lp.phi) > ONETOL) I_ERROR
+ else if (lp.phi < 0.) { t = -1.; lp.phi = -PI; }
+ else { t = 1.; lp.phi = PI; }
+ } else
+ lp.phi = 2. * asin(t = lp.phi);
+ lp.lam = RXC * xy.x / (1. + 2. * cos(lp.phi)/cos(0.5 * lp.phi));
+ lp.phi = RC * (t + sin(lp.phi));
+ if (fabs(lp.phi) > 1.)
+ if (fabs(lp.phi) > ONETOL) I_ERROR
+ else lp.phi = lp.phi < 0. ? -HALFPI : HALFPI;
+ else
+ lp.phi = asin(lp.phi);
+ return lp;
+}
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+
+ return pj_dealloc(P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
}
-INVERSE(s_inverse); /* spheroid */
- double t;
-
- lp.phi = RYC * xy.y;
- if (fabs(lp.phi) > 1.) {
- if (fabs(lp.phi) > ONETOL) I_ERROR
- else if (lp.phi < 0.) { t = -1.; lp.phi = -PI; }
- else { t = 1.; lp.phi = PI; }
- } else
- lp.phi = 2. * asin(t = lp.phi);
- lp.lam = RXC * xy.x / (1. + 2. * cos(lp.phi)/cos(0.5 * lp.phi));
- lp.phi = RC * (t + sin(lp.phi));
- if (fabs(lp.phi) > 1.)
- if (fabs(lp.phi) > ONETOL) I_ERROR
- else lp.phi = lp.phi < 0. ? -HALFPI : HALFPI;
- else
- lp.phi = asin(lp.phi);
- return (lp);
+
+
+PJ *PROJECTION(mbtfpq) {
+
+ P->es = 0.;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(mbtfpq) P->es = 0.; P->inv = s_inverse; P->fwd = s_forward; ENDENTRY(P)
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_mbtfpq_selftest (void) {return 0;}
+#else
+
+int pj_mbtfpq_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=mbtfpq +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 209391.854738393013, 119161.040199054827},
+ { 209391.854738393013, -119161.040199054827},
+ {-209391.854738393013, 119161.040199054827},
+ {-209391.854738393013, -119161.040199054827},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.00191010555824111571, 0.000839185447792341723},
+ { 0.00191010555824111571, -0.000839185447792341723},
+ {-0.00191010555824111571, 0.000839185447792341723},
+ {-0.00191010555824111571, -0.000839185447792341723},
+ };
+
+ 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_merc.c b/src/PJ_merc.c
index 4b991c1c..dd894bbd 100644
--- a/src/PJ_merc.c
+++ b/src/PJ_merc.c
@@ -1,47 +1,134 @@
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(merc, "Mercator") "\n\tCyl, Sph&Ell\n\tlat_ts=";
+
#define EPS10 1.e-10
-FORWARD(e_forward); /* ellipsoid */
- if (fabs(fabs(lp.phi) - HALFPI) <= EPS10) F_ERROR;
- xy.x = P->k0 * lp.lam;
- xy.y = - P->k0 * log(pj_tsfn(lp.phi, sin(lp.phi), P->e));
- return (xy);
+
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
+ XY xy = {0.0,0.0};
+ if (fabs(fabs(lp.phi) - HALFPI) <= EPS10)
+ F_ERROR;
+ xy.x = P->k0 * lp.lam;
+ xy.y = - P->k0 * log(pj_tsfn(lp.phi, sin(lp.phi), P->e));
+ return xy;
}
-FORWARD(s_forward); /* spheroid */
- if (fabs(fabs(lp.phi) - HALFPI) <= EPS10) F_ERROR;
- xy.x = P->k0 * lp.lam;
- xy.y = P->k0 * log(tan(FORTPI + .5 * lp.phi));
- return (xy);
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ if (fabs(fabs(lp.phi) - HALFPI) <= EPS10)
+ F_ERROR;
+ xy.x = P->k0 * lp.lam;
+ xy.y = P->k0 * log(tan(FORTPI + .5 * lp.phi));
+ return xy;
}
-INVERSE(e_inverse); /* ellipsoid */
- if ((lp.phi = pj_phi2(P->ctx, exp(- xy.y / P->k0), P->e)) == HUGE_VAL) I_ERROR;
- lp.lam = xy.x / P->k0;
- return (lp);
+
+
+static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */
+ LP lp = {0.0,0.0};
+ if ((lp.phi = pj_phi2(P->ctx, exp(- xy.y / P->k0), P->e)) == HUGE_VAL)
+ I_ERROR;
+ lp.lam = xy.x / P->k0;
+ return lp;
}
-INVERSE(s_inverse); /* spheroid */
- lp.phi = HALFPI - 2. * atan(exp(-xy.y / P->k0));
- lp.lam = xy.x / P->k0;
- return (lp);
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ lp.phi = HALFPI - 2. * atan(exp(-xy.y / P->k0));
+ lp.lam = xy.x / P->k0;
+ return lp;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(merc)
- double phits=0.0;
- int is_phits;
-
- if( (is_phits = pj_param(P->ctx, P->params, "tlat_ts").i) ) {
- phits = fabs(pj_param(P->ctx, P->params, "rlat_ts").f);
- if (phits >= HALFPI) E_ERROR(-24);
- }
- if (P->es) { /* ellipsoid */
- if (is_phits)
- P->k0 = pj_msfn(sin(phits), cos(phits), P->es);
- P->inv = e_inverse;
- P->fwd = e_forward;
- } else { /* sphere */
- if (is_phits)
- P->k0 = cos(phits);
- P->inv = s_inverse;
- P->fwd = s_forward;
- }
-ENDENTRY(P)
+
+
+static void freeup(PJ *P) { /* Destructor */
+ pj_dealloc(P);
+}
+
+
+PJ *PROJECTION(merc) {
+ double phits=0.0;
+ int is_phits;
+
+ if( (is_phits = pj_param(P->ctx, P->params, "tlat_ts").i) ) {
+ phits = fabs(pj_param(P->ctx, P->params, "rlat_ts").f);
+ if (phits >= HALFPI) E_ERROR(-24);
+ }
+
+ if (P->es) { /* ellipsoid */
+ if (is_phits)
+ P->k0 = pj_msfn(sin(phits), cos(phits), P->es);
+ P->inv = e_inverse;
+ P->fwd = e_forward;
+ }
+
+ else { /* sphere */
+ if (is_phits)
+ P->k0 = cos(phits);
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+ }
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_merc_selftest (void) {return 0;}
+#else
+
+int pj_merc_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=merc +ellps=GRS80 +lat_1=0.5 +lat_2=2"};
+ char s_args[] = {"+proj=merc +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ { 222638.981586547132, 110579.965218249708},
+ { 222638.981586547132, -110579.965218249112},
+ {-222638.981586547132, 110579.965218249708},
+ {-222638.981586547132, -110579.965218249112},
+ };
+
+ XY s_fwd_expect[] = {
+ { 223402.144255274179, 111706.743574944077},
+ { 223402.144255274179, -111706.743574944485},
+ {-223402.144255274179, 111706.743574944077},
+ {-223402.144255274179, -111706.743574944485},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ { 0.00179663056823904264, 0.00090436947522799056},
+ { 0.00179663056823904264, -0.00090436947522799056},
+ {-0.00179663056823904264, 0.00090436947522799056},
+ {-0.00179663056823904264, -0.00090436947522799056},
+ };
+
+ LP s_inv_expect[] = {
+ { 0.00179049310978382265, 0.000895246554845297135},
+ { 0.00179049310978382265, -0.000895246554858019272},
+ {-0.00179049310978382265, 0.000895246554845297135},
+ {-0.00179049310978382265, -0.000895246554858019272},
+ };
+
+ 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_mill.c b/src/PJ_mill.c
index c4cee7f5..2c7fa266 100644
--- a/src/PJ_mill.c
+++ b/src/PJ_mill.c
@@ -1,17 +1,92 @@
#define PJ_LIB__
-# include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(mill, "Miller Cylindrical") "\n\tCyl, Sph";
-FORWARD(s_forward); /* spheroid */
- (void) P;
- xy.x = lp.lam;
- xy.y = log(tan(FORTPI + lp.phi * .4)) * 1.25;
- return (xy);
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ (void) P;
+
+ xy.x = lp.lam;
+ xy.y = log(tan(FORTPI + lp.phi * .4)) * 1.25;
+
+ return (xy);
}
-INVERSE(s_inverse); /* spheroid */
- (void) P;
- lp.lam = xy.x;
- lp.phi = 2.5 * (atan(exp(.8 * xy.y)) - FORTPI);
- return (lp);
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ (void) P;
+
+ lp.lam = xy.x;
+ lp.phi = 2.5 * (atan(exp(.8 * xy.y)) - FORTPI);
+
+ return (lp);
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(mill) P->es = 0.; P->inv = s_inverse; P->fwd = s_forward; ENDENTRY(P)
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+
+ return pj_dealloc(P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(mill) {
+ P->es = 0.;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_mill_selftest (void) {return 0;}
+#else
+
+int pj_mill_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=mill +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 223402.144255274179, 111704.701754393827},
+ { 223402.144255274179, -111704.701754396243},
+ {-223402.144255274179, 111704.701754393827},
+ {-223402.144255274179, -111704.701754396243},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.00179049310978382265, 0.000895246554873922024},
+ { 0.00179049310978382265, -0.000895246554873922024},
+ {-0.00179049310978382265, 0.000895246554873922024},
+ {-0.00179049310978382265, -0.000895246554873922024},
+ };
+
+ 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_minimal.c b/src/PJ_minimal.c
new file mode 100644
index 00000000..1108c4fa
--- /dev/null
+++ b/src/PJ_minimal.c
@@ -0,0 +1,204 @@
+/***********************************************************************
+
+ A minimal example of a new proj.4 projection implementation
+
+ ...and a verbose justification for some highly intrusive code
+ surgery
+
+************************************************************************
+
+**The brief version:**
+
+In an attempt to make proj.4 code slightly more secure and much easier
+to read and maintain, I'm trying to eliminate a few unfortunate design
+decisions from the early days of proj.4
+
+The work will be *very* intrusive, especially in the PJ_xxx segment of
+the code tree, but great care has been taken to design a process that
+can be implemented stepwise and localized, one projection at a time,
+then finalized with a relatively small and concentrated work package.
+
+**The (very) long version:**
+
+Gerald I. Evenden's original design for the proj.4 projection system
+is a beautiful example of software architecture, where a very limited
+set of policy rules leads to a well defined hierarchical structure and
+a high degree of both encapsulation and internal interoperability.
+
+In the proj.4 code, the policy rules are *enforced* by a system of
+preprocessor macros for building the scaffolding for implementation
+of a new projection.
+
+While this system of macros undeniably possesses the property of both
+reducing repetitive code and enforcing policy, unfortunately it also
+possesses two much less desirable properties:
+
+First, while enforcing policy, it also *hides* policy: The "beauty in
+simplicity" of Gerald's design is hidden behind layers of macros,
+whose architectural clarity do not match that of proj.4 in general.
+
+Second (and related), the macros make the source code look like
+something only vaguely related to C, making it hard to read (an effect
+that gets amplified to the tune of syntax highlighters getting confused
+by the macros).
+
+While the policy rule enforcement macros can be eliminated in relatively
+non-intrusive ways, a more fundamental flaw in the proj.4 use of macros
+is found in the PJ_xxx.c files implementing the individual projections:
+The use of internal redefinition of PJ, the fundamental proj data object,
+through the use of the PROJ_PARMS__ macro, makes the sizeof (PJ)
+fundamentally unknown to the calling pj_init function.
+
+This leads to code that is probably not in full conformance with the
+C standard.
+
+It is also a memory management catastrophe waiting to happen.
+
+But first and foremost, it leads to some very clumsy initialization code,
+where pj_init (the constructor function), needs to start the constsruction
+process by asking the PJ_xxx function to do the memory allocation (because
+pj_init does not know the size of the PROJ_PARMS-mangled PJ object being
+instantiated).
+
+Then, after doing some initialization work, pj_init returns control to
+PJ_xxx, asking it to finalize the initialization with the projection
+specific parameters specified by the PROJ_PARMS__ macro.
+
+Behind the scenes, hidden by two layers of macros, what happens is even
+worse, as a lot of the initialization code is duplicated in every PJ_xxx
+file, rather than being centralized in the pj_init function.
+
+**Solution procedure:**
+
+Evidently, the way to eliminate this clumsyness will be to introduce an
+opaque object, that is managed by tne individual PJ_xxx projection code,
+and represented as a simple void-pointer in the PJ object.
+
+This can be done one projection code file at a time, working through the
+code base as time permits (it will take at least a month).
+
+When a PJ_xxx file is on the surgical bench, it will also have its
+ENTRYA/ENTRY0/ENTRY1/ENTRY2/ENDENTRY/etc. etc. macro-guts torn out and
+replaced by the PROJECTION macro (introduced in projects.h).
+
+This leads to code that looks a lot more like real C, and hence is much
+less confusing to both syntax higlighters and humans. It also leads
+to code that, after all projections have been processed, with a final
+sweep over the code base can be brought into the style of the code in
+PJ_minimal.c
+
+In my humble opinion the result wil be a code base that is not only easier
+to maintain, but also more welcoming to new contributors.
+
+And if proj is to expand its strong basis in projections into the fields
+of geodetic transformations and general geometric geodesy, we will need
+to be able to attract quite a few expert geodesist contributors.
+
+And since expert geodesists are not necessarily expert coders, a welcoming
+code base is a real asset (to put the icing on the cake of the already
+welcoming user- and developer community).
+
+Note that the entire process does not touch the algorithmic/mathematical
+parts of the code at all - it is actuallly an attempt to make this part
+stand out more clearly.
+
+---
+
+The attached material is an attempt to show what happens if we remove
+the layers of macros, and introduce a more centralized approach to
+memory allocation and initialization.
+
+Please note, however, that the level of cantralization achieved here
+is not yet fully supported by the proj.4 infrastructure: It is an
+example, intended to show what can be achieved through a smooth,
+gradual and safe refactoring of the existing layered macro system.
+
+In my humble opinion, this version makes the beauty of Gerald's design
+much more evident than the current layered-macro-version.
+
+Thomas Knudsen, thokn@sdfe.dk, 2016-03-31
+
+***********************************************************************/
+
+#define PJ_LIB__
+#include <projects.h>
+#include <assert.h>
+PROJ_HEAD(minimal, "Minimal example (brief description goes here)");
+
+
+/* Projection specific elements for the PJ object */
+struct pj_opaque {
+ double a;
+ int b;
+};
+
+
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
+ XY xy = {0.0,0.0};
+ /* Actual ellipsoidal forward code goes here */
+ xy.y = lp.lam + P->es;
+ xy.x = lp.phi + 42;
+ return xy;
+}
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ /* Actual spheroidal forward code goes here */
+ xy.y = lp.lam + P->es;
+ xy.x = lp.phi + 42;
+ return xy;
+}
+
+
+static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */
+ LP lp = {0.0,0.0};
+ /* Actual ellipsoidal forward code goes here */
+ lp.lam = xy.x - P->es;
+ lp.phi = xy.y - P->opaque->b;
+ return lp;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ /* Actual spheroidal forward code goes here */
+ lp.lam = xy.x - P->es;
+ lp.phi = xy.y - P->opaque->b;
+ return lp;
+}
+
+
+static void freeup(PJ *P) { /* Destructor */
+ if (P==0)
+ return;
+ /* Projection specific deallocation goes here */
+ pj_dealloc (P->opaque);
+ pj_dealloc (P);
+ return;
+}
+
+
+PJ *pj_projection_specific_setup_minimal (PJ *P) {
+ pj_prepare (P, des_minimal, freeup, sizeof (struct pj_opaque));
+ if (0==P->opaque) {
+ freeup (P);
+ return 0;
+ }
+
+ P->opaque->a = 42.42;
+ P->opaque->b = 42;
+
+ /* Spheroidal? */
+ if (0==P->es) {
+ P->fwd = s_forward;
+ P->inv = s_inverse;
+ return P;
+ }
+
+ /* Otherwise it's ellipsoidal */
+ P->fwd = e_forward;
+ P->inv = e_inverse;
+
+ return P;
+}
diff --git a/src/PJ_misrsom.c b/src/PJ_misrsom.c
index 19518a1d..c164b1c7 100644
--- a/src/PJ_misrsom.c
+++ b/src/PJ_misrsom.c
@@ -12,49 +12,57 @@
*
* and the following code change:
*
- * P->rlm = PI * (1. / 248. + .5161290322580645);
+ * Q->rlm = PI * (1. / 248. + .5161290322580645);
*
* changed to:
*
- * P->rlm = 0
+ * Q->rlm = 0
*
*****************************************************************************/
/* based upon Snyder and Linck, USGS-NMD */
-#define PROJ_PARMS__ \
- double a2, a4, b, c1, c3; \
- double q, t, u, w, p22, sa, ca, xj, rlm, rlm2;
#define PJ_LIB__
#include <projects.h>
+
PROJ_HEAD(misrsom, "Space oblique for MISR")
"\n\tCyl, Sph&Ell\n\tpath=";
+
#define TOL 1e-7
#define PI_HALFPI 4.71238898038468985766
#define TWOPI_HALFPI 7.85398163397448309610
-static void
-seraz0(double lam, double mult, PJ *P) {
+struct pj_opaque {
+ double a2, a4, b, c1, c3;
+ double q, t, u, w, p22, sa, ca, xj, rlm, rlm2;
+};
+
+static void seraz0(double lam, double mult, PJ *P) {
+ struct pj_opaque *Q = P->opaque;
double sdsq, h, s, fc, sd, sq, d__1;
lam *= DEG_TO_RAD;
sd = sin(lam);
sdsq = sd * sd;
- s = P->p22 * P->sa * cos(lam) * sqrt((1. + P->t * sdsq) / ((
- 1. + P->w * sdsq) * (1. + P->q * sdsq)));
- d__1 = 1. + P->q * sdsq;
- h = sqrt((1. + P->q * sdsq) / (1. + P->w * sdsq)) * ((1. +
- P->w * sdsq) / (d__1 * d__1) - P->p22 * P->ca);
- sq = sqrt(P->xj * P->xj + s * s);
- P->b += fc = mult * (h * P->xj - s * s) / sq;
- P->a2 += fc * cos(lam + lam);
- P->a4 += fc * cos(lam * 4.);
- fc = mult * s * (h + P->xj) / sq;
- P->c1 += fc * cos(lam);
- P->c3 += fc * cos(lam * 3.);
+ s = Q->p22 * Q->sa * cos(lam) * sqrt((1. + Q->t * sdsq) / ((
+ 1. + Q->w * sdsq) * (1. + Q->q * sdsq)));
+ d__1 = 1. + Q->q * sdsq;
+ h = sqrt((1. + Q->q * sdsq) / (1. + Q->w * sdsq)) * ((1. +
+ Q->w * sdsq) / (d__1 * d__1) - Q->p22 * Q->ca);
+ sq = sqrt(Q->xj * Q->xj + s * s);
+ Q->b += fc = mult * (h * Q->xj - s * s) / sq;
+ Q->a2 += fc * cos(lam + lam);
+ Q->a4 += fc * cos(lam * 4.);
+ fc = mult * s * (h + Q->xj) / sq;
+ Q->c1 += fc * cos(lam);
+ Q->c3 += fc * cos(lam * 3.);
}
-FORWARD(e_forward); /* ellipsoid */
+
+
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
int l, nn;
- double lamt, xlam, sdsq, c, d, s, lamdp, phidp, lampp, tanph,
- lamtp, cl, sd, sp, fac, sav, tanphi;
+ double lamt, xlam, sdsq, c, d, s, lamdp, phidp, lampp, tanph;
+ double lamtp, cl, sd, sp, fac, sav, tanphi;
if (lp.phi > HALFPI)
lp.phi = HALFPI;
@@ -64,65 +72,69 @@ FORWARD(e_forward); /* ellipsoid */
tanphi = tan(lp.phi);
for (nn = 0;;) {
sav = lampp;
- lamtp = lp.lam + P->p22 * lampp;
+ lamtp = lp.lam + Q->p22 * lampp;
cl = cos(lamtp);
if (fabs(cl) < TOL)
lamtp -= TOL;
fac = lampp - sin(lampp) * (cl < 0. ? -HALFPI : HALFPI);
for (l = 50; l; --l) {
- lamt = lp.lam + P->p22 * sav;
+ lamt = lp.lam + Q->p22 * sav;
if (fabs(c = cos(lamt)) < TOL)
lamt -= TOL;
- xlam = (P->one_es * tanphi * P->sa + sin(lamt) * P->ca) / c;
+ xlam = (P->one_es * tanphi * Q->sa + sin(lamt) * Q->ca) / c;
lamdp = atan(xlam) + fac;
if (fabs(fabs(sav) - fabs(lamdp)) < TOL)
break;
sav = lamdp;
}
- if (!l || ++nn >= 3 || (lamdp > P->rlm && lamdp < P->rlm2))
+ if (!l || ++nn >= 3 || (lamdp > Q->rlm && lamdp < Q->rlm2))
break;
- if (lamdp <= P->rlm)
+ if (lamdp <= Q->rlm)
lampp = TWOPI_HALFPI;
- else if (lamdp >= P->rlm2)
+ else if (lamdp >= Q->rlm2)
lampp = HALFPI;
}
if (l) {
sp = sin(lp.phi);
- phidp = aasin(P->ctx,(P->one_es * P->ca * sp - P->sa * cos(lp.phi) *
+ phidp = aasin(P->ctx,(P->one_es * Q->ca * sp - Q->sa * cos(lp.phi) *
sin(lamt)) / sqrt(1. - P->es * sp * sp));
tanph = log(tan(FORTPI + .5 * phidp));
sd = sin(lamdp);
sdsq = sd * sd;
- s = P->p22 * P->sa * cos(lamdp) * sqrt((1. + P->t * sdsq)
- / ((1. + P->w * sdsq) * (1. + P->q * sdsq)));
- d = sqrt(P->xj * P->xj + s * s);
- xy.x = P->b * lamdp + P->a2 * sin(2. * lamdp) + P->a4 *
+ s = Q->p22 * Q->sa * cos(lamdp) * sqrt((1. + Q->t * sdsq)
+ / ((1. + Q->w * sdsq) * (1. + Q->q * sdsq)));
+ d = sqrt(Q->xj * Q->xj + s * s);
+ xy.x = Q->b * lamdp + Q->a2 * sin(2. * lamdp) + Q->a4 *
sin(lamdp * 4.) - tanph * s / d;
- xy.y = P->c1 * sd + P->c3 * sin(lamdp * 3.) + tanph * P->xj / d;
+ xy.y = Q->c1 * sd + Q->c3 * sin(lamdp * 3.) + tanph * Q->xj / d;
} else
xy.x = xy.y = HUGE_VAL;
return xy;
}
-INVERSE(e_inverse); /* ellipsoid */
+
+
+static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
int nn;
double lamt, sdsq, s, lamdp, phidp, sppsq, dd, sd, sl, fac, scl, sav, spp;
- lamdp = xy.x / P->b;
+ lamdp = xy.x / Q->b;
nn = 50;
do {
- sav = lamdp;
- sd = sin(lamdp);
- sdsq = sd * sd;
- s = P->p22 * P->sa * cos(lamdp) * sqrt((1. + P->t * sdsq)
- / ((1. + P->w * sdsq) * (1. + P->q * sdsq)));
- lamdp = xy.x + xy.y * s / P->xj - P->a2 * sin(
- 2. * lamdp) - P->a4 * sin(lamdp * 4.) - s / P->xj * (
- P->c1 * sin(lamdp) + P->c3 * sin(lamdp * 3.));
- lamdp /= P->b;
+ sav = lamdp;
+ sd = sin(lamdp);
+ sdsq = sd * sd;
+ s = Q->p22 * Q->sa * cos(lamdp) * sqrt((1. + Q->t * sdsq)
+ / ((1. + Q->w * sdsq) * (1. + Q->q * sdsq)));
+ lamdp = xy.x + xy.y * s / Q->xj - Q->a2 * sin(
+ 2. * lamdp) - Q->a4 * sin(lamdp * 4.) - s / Q->xj * (
+ Q->c1 * sin(lamdp) + Q->c3 * sin(lamdp * 3.));
+ lamdp /= Q->b;
} while (fabs(lamdp - sav) >= TOL && --nn);
sl = sin(lamdp);
- fac = exp(sqrt(1. + s * s / P->xj / P->xj) * (xy.y -
- P->c1 * sl - P->c3 * sin(lamdp * 3.)));
+ fac = exp(sqrt(1. + s * s / Q->xj / Q->xj) * (xy.y -
+ Q->c1 * sl - Q->c3 * sin(lamdp * 3.)));
phidp = 2. * (atan(fac) - FORTPI);
dd = sl * sl;
if (fabs(cos(lamdp)) < TOL)
@@ -130,56 +142,142 @@ INVERSE(e_inverse); /* ellipsoid */
spp = sin(phidp);
sppsq = spp * spp;
lamt = atan(((1. - sppsq * P->rone_es) * tan(lamdp) *
- P->ca - spp * P->sa * sqrt((1. + P->q * dd) * (
- 1. - sppsq) - sppsq * P->u) / cos(lamdp)) / (1. - sppsq
- * (1. + P->u)));
+ Q->ca - spp * Q->sa * sqrt((1. + Q->q * dd) * (
+ 1. - sppsq) - sppsq * Q->u) / cos(lamdp)) / (1. - sppsq
+ * (1. + Q->u)));
sl = lamt >= 0. ? 1. : -1.;
scl = cos(lamdp) >= 0. ? 1. : -1;
lamt -= HALFPI * (1. - scl) * sl;
- lp.lam = lamt - P->p22 * lamdp;
- if (fabs(P->sa) < TOL)
+ lp.lam = lamt - Q->p22 * lamdp;
+ if (fabs(Q->sa) < TOL)
lp.phi = aasin(P->ctx,spp / sqrt(P->one_es * P->one_es + P->es * sppsq));
else
- lp.phi = atan((tan(lamdp) * cos(lamt) - P->ca * sin(lamt)) /
- (P->one_es * P->sa));
+ lp.phi = atan((tan(lamdp) * cos(lamt) - Q->ca * sin(lamt)) /
+ (P->one_es * Q->sa));
return lp;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(misrsom)
+
+
+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(misrsom) {
int path;
double lam, alf, esc, ess;
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
path = pj_param(P->ctx, P->params, "ipath").i;
if (path <= 0 || path > 233) E_ERROR(-29);
P->lam0 = DEG_TO_RAD * 129.3056 - TWOPI / 233. * path;
alf = 98.30382 * DEG_TO_RAD;
- P->p22 = 98.88 / 1440.0;
-
- P->sa = sin(alf);
- P->ca = cos(alf);
- if (fabs(P->ca) < 1e-9)
- P->ca = 1e-9;
- esc = P->es * P->ca * P->ca;
- ess = P->es * P->sa * P->sa;
- P->w = (1. - esc) * P->rone_es;
- P->w = P->w * P->w - 1.;
- P->q = ess * P->rone_es;
- P->t = ess * (2. - P->es) * P->rone_es * P->rone_es;
- P->u = esc * P->rone_es;
- P->xj = P->one_es * P->one_es * P->one_es;
- P->rlm = 0;
- P->rlm2 = P->rlm + TWOPI;
- P->a2 = P->a4 = P->b = P->c1 = P->c3 = 0.;
+ Q->p22 = 98.88 / 1440.0;
+
+ Q->sa = sin(alf);
+ Q->ca = cos(alf);
+ if (fabs(Q->ca) < 1e-9)
+ Q->ca = 1e-9;
+ esc = P->es * Q->ca * Q->ca;
+ ess = P->es * Q->sa * Q->sa;
+ Q->w = (1. - esc) * P->rone_es;
+ Q->w = Q->w * Q->w - 1.;
+ Q->q = ess * P->rone_es;
+ Q->t = ess * (2. - P->es) * P->rone_es * P->rone_es;
+ Q->u = esc * P->rone_es;
+ Q->xj = P->one_es * P->one_es * P->one_es;
+ Q->rlm = 0;
+ Q->rlm2 = Q->rlm + TWOPI;
+ Q->a2 = Q->a4 = Q->b = Q->c1 = Q->c3 = 0.;
seraz0(0., 1., P);
for (lam = 9.; lam <= 81.0001; lam += 18.)
seraz0(lam, 4., P);
for (lam = 18; lam <= 72.0001; lam += 18.)
seraz0(lam, 2., P);
seraz0(90., 1., P);
- P->a2 /= 30.;
- P->a4 /= 60.;
- P->b /= 30.;
- P->c1 /= 15.;
- P->c3 /= 45.;
- P->inv = e_inverse; P->fwd = e_forward;
-ENDENTRY(P)
+ Q->a2 /= 30.;
+ Q->a4 /= 60.;
+ Q->b /= 30.;
+ Q->c1 /= 15.;
+ Q->c3 /= 45.;
+
+ P->inv = e_inverse;
+ P->fwd = e_forward;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_misrsom_selftest (void) {return 0;}
+#else
+
+int pj_misrsom_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=misrsom +ellps=GRS80 +lat_1=0.5 +lat_2=2 +path=1"};
+ char s_args[] = {"+proj=misrsom +a=6400000 +lat_1=0.5 +lat_2=2 +path=1"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ {18556630.3683698252, 9533394.6753112711},
+ {19041866.0067297369, 9707182.17532352544},
+ {18816810.1301847994, 8647669.64980295487},
+ {19252610.7845367305, 8778164.08580140397},
+ };
+
+ XY s_fwd_expect[] = {
+ {18641249.2791703865, 9563342.53233416565},
+ {19130982.4615812786, 9739539.59350463562},
+ {18903483.5150115378, 8675064.50061797537},
+ {19343388.3998006098, 8807471.90406848863},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ {127.759503987730625, 0.00173515039622462014},
+ {127.761295471077958, 0.00187196632421706517},
+ {127.759775773557251, -0.00187196632421891525},
+ {127.76156725690457, -0.00173515039622462014},
+ };
+
+ LP s_inv_expect[] = {
+ {127.75950514818588, 0.00171623111593511971},
+ {127.761290323778738, 0.00185412132880796244},
+ {127.759780920856471, -0.00185412132880796244},
+ {127.761566096449329, -0.00171623111593511971},
+ };
+
+ 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_mod_ster.c b/src/PJ_mod_ster.c
index 185e95e3..4c217141 100644
--- a/src/PJ_mod_ster.c
+++ b/src/PJ_mod_ster.c
@@ -1,211 +1,540 @@
/* based upon Snyder and Linck, USGS-NMD */
-#define PROJ_PARMS__ \
- COMPLEX *zcoeff; \
- double cchio, schio; \
- int n;
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(mil_os, "Miller Oblated Stereographic") "\n\tAzi(mod)";
PROJ_HEAD(lee_os, "Lee Oblated Stereographic") "\n\tAzi(mod)";
PROJ_HEAD(gs48, "Mod. Stererographics of 48 U.S.") "\n\tAzi(mod)";
PROJ_HEAD(alsk, "Mod. Stererographics of Alaska") "\n\tAzi(mod)";
PROJ_HEAD(gs50, "Mod. Stererographics of 50 U.S.") "\n\tAzi(mod)";
-#define EPSLN 1e-10
-
-FORWARD(e_forward); /* ellipsoid */
- double sinlon, coslon, esphi, chi, schi, cchi, s;
- COMPLEX p;
-
- sinlon = sin(lp.lam);
- coslon = cos(lp.lam);
- esphi = P->e * sin(lp.phi);
- chi = 2. * atan(tan((HALFPI + lp.phi) * .5) *
- pow((1. - esphi) / (1. + esphi), P->e * .5)) - HALFPI;
- schi = sin(chi);
- cchi = cos(chi);
- s = 2. / (1. + P->schio * schi + P->cchio * cchi * coslon);
- p.r = s * cchi * sinlon;
- p.i = s * (P->cchio * schi - P->schio * cchi * coslon);
- p = pj_zpoly1(p, P->zcoeff, P->n);
- xy.x = p.r;
- xy.y = p.i;
- return xy;
+
+#define EPSLN 1e-12
+
+struct pj_opaque {
+ COMPLEX *zcoeff; \
+ double cchio, schio; \
+ int n;
+};
+
+
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double sinlon, coslon, esphi, chi, schi, cchi, s;
+ COMPLEX p;
+
+ sinlon = sin(lp.lam);
+ coslon = cos(lp.lam);
+ esphi = P->e * sin(lp.phi);
+ chi = 2. * atan(tan((HALFPI + lp.phi) * .5) *
+ pow((1. - esphi) / (1. + esphi), P->e * .5)) - HALFPI;
+ schi = sin(chi);
+ cchi = cos(chi);
+ s = 2. / (1. + Q->schio * schi + Q->cchio * cchi * coslon);
+ p.r = s * cchi * sinlon;
+ p.i = s * (Q->cchio * schi - Q->schio * cchi * coslon);
+ p = pj_zpoly1(p, Q->zcoeff, Q->n);
+ xy.x = p.r;
+ xy.y = p.i;
+
+ return xy;
}
-INVERSE(e_inverse); /* ellipsoid */
- int nn;
- COMPLEX p, fxy, fpxy, dp;
- double den, rh, z, sinz, cosz, chi, phi, dphi, esphi;
-
- p.r = xy.x;
- p.i = xy.y;
- for (nn = 20; nn ;--nn) {
- fxy = pj_zpolyd1(p, P->zcoeff, P->n, &fpxy);
- fxy.r -= xy.x;
- fxy.i -= xy.y;
- den = fpxy.r * fpxy.r + fpxy.i * fpxy.i;
- dp.r = -(fxy.r * fpxy.r + fxy.i * fpxy.i) / den;
- dp.i = -(fxy.i * fpxy.r - fxy.r * fpxy.i) / den;
- p.r += dp.r;
- p.i += dp.i;
- if ((fabs(dp.r) + fabs(dp.i)) <= EPSLN)
- break;
- }
- if (nn) {
- rh = hypot(p.r, p.i);
- z = 2. * atan(.5 * rh);
- sinz = sin(z);
- cosz = cos(z);
- lp.lam = P->lam0;
- if (fabs(rh) <= EPSLN) {
- lp.phi = P->phi0;
- return lp;
- }
- chi = aasin(P->ctx, cosz * P->schio + p.i * sinz * P->cchio / rh);
- phi = chi;
- for (nn = 20; nn ;--nn) {
- esphi = P->e * sin(phi);
- dphi = 2. * atan(tan((HALFPI + chi) * .5) *
- pow((1. + esphi) / (1. - esphi), P->e * .5)) - HALFPI - phi;
- phi += dphi;
- if (fabs(dphi) <= EPSLN)
- break;
- }
- }
- if (nn) {
- lp.phi = phi;
- lp.lam = atan2(p.r * sinz, rh * P->cchio * cosz - p.i *
- P->schio * sinz);
+
+
+static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ int nn;
+ COMPLEX p, fxy, fpxy, dp;
+ double den, rh, z, sinz, cosz, chi, phi, dphi, esphi;
+
+ p.r = xy.x;
+ p.i = xy.y;
+ for (nn = 20; nn ;--nn) {
+ fxy = pj_zpolyd1(p, Q->zcoeff, Q->n, &fpxy);
+ fxy.r -= xy.x;
+ fxy.i -= xy.y;
+ den = fpxy.r * fpxy.r + fpxy.i * fpxy.i;
+ dp.r = -(fxy.r * fpxy.r + fxy.i * fpxy.i) / den;
+ dp.i = -(fxy.i * fpxy.r - fxy.r * fpxy.i) / den;
+ p.r += dp.r;
+ p.i += dp.i;
+ if ((fabs(dp.r) + fabs(dp.i)) <= EPSLN)
+ break;
+ }
+ if (nn) {
+ rh = hypot(p.r, p.i);
+ z = 2. * atan(.5 * rh);
+ sinz = sin(z);
+ cosz = cos(z);
+ lp.lam = P->lam0;
+ if (fabs(rh) <= EPSLN) {
+ lp.phi = P->phi0;
+ return lp;
+ }
+ chi = aasin(P->ctx, cosz * Q->schio + p.i * sinz * Q->cchio / rh);
+ phi = chi;
+ for (nn = 20; nn ;--nn) {
+ esphi = P->e * sin(phi);
+ dphi = 2. * atan(tan((HALFPI + chi) * .5) *
+ pow((1. + esphi) / (1. - esphi), P->e * .5)) - HALFPI - phi;
+ phi += dphi;
+ if (fabs(dphi) <= EPSLN)
+ break;
+ }
+ }
+ if (nn) {
+ lp.phi = phi;
+ lp.lam = atan2(p.r * sinz, rh * Q->cchio * cosz - p.i *
+ Q->schio * sinz);
} else
- lp.lam = lp.phi = HUGE_VAL;
- return lp;
+ lp.lam = lp.phi = HUGE_VAL;
+ return lp;
}
-FREEUP; if (P) pj_dalloc(P); }
- static PJ *
-setup(PJ *P) { /* general initialization */
- double esphi, chio;
-
- if (P->es) {
- esphi = P->e * sin(P->phi0);
- chio = 2. * atan(tan((HALFPI + P->phi0) * .5) *
- pow((1. - esphi) / (1. + esphi), P->e * .5)) - HALFPI;
- } else
- chio = P->phi0;
- P->schio = sin(chio);
- P->cchio = cos(chio);
- P->inv = e_inverse; P->fwd = e_forward;
- return 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);
}
-ENTRY0(mil_os)
- static COMPLEX /* Miller Oblated Stereographic */
-AB[] = {
- {0.924500, 0.},
- {0., 0.},
- {0.019430, 0.}
-};
- P->n = 2;
- P->lam0 = DEG_TO_RAD * 20.;
- P->phi0 = DEG_TO_RAD * 18.;
- P->zcoeff = AB;
- P->es = 0.;
-ENDENTRY(setup(P))
-ENTRY0(lee_os)
- static COMPLEX /* Lee Oblated Stereographic */
-AB[] = {
- {0.721316, 0.},
- {0., 0.},
- {-0.0088162, -0.00617325}
-};
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
- P->n = 2;
- P->lam0 = DEG_TO_RAD * -165.;
- P->phi0 = DEG_TO_RAD * -10.;
- P->zcoeff = AB;
- P->es = 0.;
-ENDENTRY(setup(P))
-ENTRY0(gs48)
- static COMPLEX /* 48 United States */
-AB[] = {
- {0.98879, 0.},
- {0., 0.},
- {-0.050909, 0.},
- {0., 0.},
- {0.075528, 0.}
-};
+static PJ *setup(PJ *P) { /* general initialization */
+ struct pj_opaque *Q = P->opaque;
+ double esphi, chio;
- P->n = 4;
- P->lam0 = DEG_TO_RAD * -96.;
- P->phi0 = DEG_TO_RAD * -39.;
- P->zcoeff = AB;
- P->es = 0.;
- P->a = 6370997.;
-ENDENTRY(setup(P))
-ENTRY0(alsk)
- static COMPLEX
-ABe[] = { /* Alaska ellipsoid */
- {.9945303, 0.},
- {.0052083, -.0027404},
- {.0072721, .0048181},
- {-.0151089, -.1932526},
- {.0642675, -.1381226},
- {.3582802, -.2884586}},
-ABs[] = { /* Alaska sphere */
- {.9972523, 0.},
- {.0052513, -.0041175},
- {.0074606, .0048125},
- {-.0153783, -.1968253},
- {.0636871, -.1408027},
- {.3660976, -.2937382}
-};
+ if (P->es) {
+ esphi = P->e * sin(P->phi0);
+ chio = 2. * atan(tan((HALFPI + P->phi0) * .5) *
+ pow((1. - esphi) / (1. + esphi), P->e * .5)) - HALFPI;
+ } else
+ chio = P->phi0;
+ Q->schio = sin(chio);
+ Q->cchio = cos(chio);
+ P->inv = e_inverse;
+ P->fwd = e_forward;
+
+ return P;
+}
+
+
+/* Miller Oblated Stereographic */
+PJ *PROJECTION(mil_os) {
+ static COMPLEX AB[] = {
+ {0.924500, 0.},
+ {0., 0.},
+ {0.019430, 0.}
+ };
+
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->n = 2;
+ P->lam0 = DEG_TO_RAD * 20.;
+ P->phi0 = DEG_TO_RAD * 18.;
+ Q->zcoeff = AB;
+ P->es = 0.;
+
+ return setup(P);
+}
+
+
+/* Lee Oblated Stereographic */
+PJ *PROJECTION(lee_os) {
+ static COMPLEX AB[] = {
+ {0.721316, 0.},
+ {0., 0.},
+ {-0.0088162, -0.00617325}
+ };
+
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->n = 2;
+ P->lam0 = DEG_TO_RAD * -165.;
+ P->phi0 = DEG_TO_RAD * -10.;
+ Q->zcoeff = AB;
+ P->es = 0.;
+
+ return setup(P);
+}
+
+
+PJ *PROJECTION(gs48) {
+ static COMPLEX /* 48 United States */
+ AB[] = {
+ {0.98879, 0.},
+ {0., 0.},
+ {-0.050909, 0.},
+ {0., 0.},
+ {0.075528, 0.}
+ };
+
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->n = 4;
+ P->lam0 = DEG_TO_RAD * -96.;
+ P->phi0 = DEG_TO_RAD * -39.;
+ Q->zcoeff = AB;
+ P->es = 0.;
+ P->a = 6370997.;
+
+ return setup(P);
+}
+
+
+PJ *PROJECTION(alsk) {
+ static COMPLEX ABe[] = { /* Alaska ellipsoid */
+ { .9945303, 0.},
+ { .0052083, -.0027404},
+ { .0072721, .0048181},
+ {-.0151089, -.1932526},
+ { .0642675, -.1381226},
+ { .3582802, -.2884586},
+ };
+
+ static COMPLEX ABs[] = { /* Alaska sphere */
+ { .9972523, 0.},
+ { .0052513, -.0041175},
+ { .0074606, .0048125},
+ {-.0153783, -.1968253},
+ { .0636871, -.1408027},
+ { .3660976, -.2937382}
+ };
+
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->n = 5;
+ P->lam0 = DEG_TO_RAD * -152.;
+ P->phi0 = DEG_TO_RAD * 64.;
+ if (P->es) { /* fixed ellipsoid/sphere */
+ Q->zcoeff = ABe;
+ P->a = 6378206.4;
+ P->e = sqrt(P->es = 0.00676866);
+ } else {
+ Q->zcoeff = ABs;
+ P->a = 6370997.;
+ }
+
+ return setup(P);
+}
+
+
+PJ *PROJECTION(gs50) {
+ static COMPLEX ABe[] = { /* GS50 ellipsoid */
+ { .9827497, 0.},
+ { .0210669, .0053804},
+ {-.1031415, -.0571664},
+ {-.0323337, -.0322847},
+ { .0502303, .1211983},
+ { .0251805, .0895678},
+ {-.0012315, -.1416121},
+ { .0072202, -.1317091},
+ {-.0194029, .0759677},
+ {-.0210072, .0834037}
+ };
+
+ static COMPLEX ABs[] = { /* GS50 sphere */
+ { .9842990, 0.},
+ { .0211642, .0037608},
+ {-.1036018, -.0575102},
+ {-.0329095, -.0320119},
+ { .0499471, .1223335},
+ { .0260460, .0899805},
+ { .0007388, -.1435792},
+ { .0075848, -.1334108},
+ {-.0216473, .0776645},
+ {-.0225161, .0853673}
+ };
+
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->n = 9;
+ P->lam0 = DEG_TO_RAD * -120.;
+ P->phi0 = DEG_TO_RAD * 45.;
+ if (P->es) { /* fixed ellipsoid/sphere */
+ Q->zcoeff = ABe;
+ P->a = 6378206.4;
+ P->e = sqrt(P->es = 0.00676866);
+ } else {
+ Q->zcoeff = ABs;
+ P->a = 6370997.;
+ }
+
+ return setup(P);
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_mil_os_selftest (void) {return 0;}
+#else
+
+int pj_mil_os_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=mil_os +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ {-1908527.94959420455, -1726237.4730614475},
+ {-1916673.02291848511, -1943133.88812552323},
+ {-2344429.41208962305, -1706258.05121891224},
+ {-2354637.83553299867, -1926468.60513541684},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ {20.0020363939492398, 18.0009683469140498},
+ {20.0020363715837419, 17.999031631815086},
+ {19.9979636060507602, 18.0009683469140498},
+ {19.9979636284162581, 17.999031631815086},
+ };
+
+ 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_lee_os_selftest (void) {return 0;}
+#else
+
+int pj_lee_os_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=lee_os +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ {-25564478.9526050538, 154490848.8286255},
+ { 30115393.9385746419, 125193997.439701974},
+ {-31039340.5921660066, 57678685.0448915437},
+ {-3088419.93942357088, 58150091.0991110131},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ {-164.997479457813824, -9.99875886103541411},
+ {-164.997479438558884, -10.0012411200022751},
+ {-165.002520542186289, -9.99875886103545142},
+ {-165.002520561440946, -10.0012411200022999},
+ };
+
+ 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_gs48_selftest (void) {return 0;}
+#else
+
+int pj_gs48_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=gs48 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ {36625944.1923860237, -10443454.370062707},
+ {32392147.7449533679, -12580705.358382076},
+ {31394918.3206626177, -3352580.92795714363},
+ {28553241.7702435851, -5673083.97367164213},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ {-95.997669975773789, -38.9990945807843801},
+ {-95.9976699161415326, -39.0009053728726585},
+ {-96.0023300242262252, -38.9990945807843801},
+ {-96.0023300838584817, -39.0009053728726585},
+ };
+
+ 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_alsk_selftest (void) {return 0;}
+#else
+
+int pj_alsk_selftest (void) {
+
+ /* The standard test points are way outside the definition area bounds, hence we relax tolerances */
+ double tolerance_lp = 1e-7;
+ double tolerance_xy = 1e-4;
+
+ char e_args[] = {"+proj=alsk +ellps=GRS80 +lat_1=0.5 +lat_2=2"};
+ char s_args[] = {"+proj=alsk +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ {1642864080.02732754, -1139302009.02887797},
+ {1991193850.2052319, -1518851027.13339996},
+ { 896601956.44416213, -1580143099.4169271},
+ {1018553822.30535674, -2028874099.61853552},
+ };
+
+ XY s_fwd_expect[] = {
+ {1651105846.06753755, -1132233885.29928017},
+ {2004822703.03845358, -1512578241.93150067},
+ { 907039096.196665168, -1578565868.60405397},
+ {1033243931.08174837, -2030485879.68075895},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ {-151.99590140340095, 64.0008994430213534},
+ {-151.995901665843263, 63.9991004415502687},
+ {-152.004098597614217, 64.0008994436154524},
+ {-152.004098335171818, 63.9991004409561413},
+ };
+
+ LP s_inv_expect[] = {
+ {-151.995904192970613, 64.0008976554005926},
+ {-151.995904455051942, 63.9991022295943921},
+ {-152.004095808043218, 64.0008976559930716},
+ {-152.004095545961775, 63.9991022290018208},
+ };
+
+ 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
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_gs50_selftest (void) {return 0;}
+#else
+
+int pj_gs50_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=gs50 +ellps=GRS80 +lat_1=0.5 +lat_2=2"};
+ char s_args[] = {"+proj=gs50 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ {29729016747.3571701, -3918216218.3354063},
+ {36735969814.5893631, -14677374776.9809761},
+ {14161556831.8443203, -11410194658.0201168},
+ {14213883663.1140423, -19065362387.8745575},
+ };
+
+ XY s_fwd_expect[] = {
+ {30210185088.2270584, -3211636634.93554688},
+ {37664745793.3519745, -13981519124.6516781},
+ {14657726636.8231983, -11238369787.8965397},
+ {14923510723.7682972, -19062616309.6883698},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ {-119.997423271634844, 45.0009140704890811},
+ {-119.997423354194112, 44.9990858708950014},
+ {-120.00257673100937, 45.0009140729899428},
+ {-120.002576648448965, 44.9990858683939408},
+ };
+
+ LP s_inv_expect[] = {
+ {-119.997427429220934, 45.0009094967551704},
+ {-119.997427511518453, 44.9990904451617482},
+ {-120.002572573413815, 45.0009094992385954},
+ {-120.00257249111516, 44.9990904426780602},
+ };
+
+ 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);
+}
- P->n = 5;
- P->lam0 = DEG_TO_RAD * -152.;
- P->phi0 = DEG_TO_RAD * 64.;
- if (P->es) { /* fixed ellipsoid/sphere */
- P->zcoeff = ABe;
- P->a = 6378206.4;
- P->e = sqrt(P->es = 0.00676866);
- } else {
- P->zcoeff = ABs;
- P->a = 6370997.;
- }
-ENDENTRY(setup(P))
-ENTRY0(gs50)
- static COMPLEX
-ABe[] = { /* GS50 ellipsoid */
- {.9827497, 0.},
- {.0210669, .0053804},
- {-.1031415, -.0571664},
- {-.0323337, -.0322847},
- {.0502303, .1211983},
- {.0251805, .0895678},
- {-.0012315, -.1416121},
- {.0072202, -.1317091},
- {-.0194029, .0759677},
- {-.0210072, .0834037}
-},
-ABs[] = { /* GS50 sphere */
- {.9842990, 0.},
- {.0211642, .0037608},
- {-.1036018, -.0575102},
- {-.0329095, -.0320119},
- {.0499471, .1223335},
- {.0260460, .0899805},
- {.0007388, -.1435792},
- {.0075848, -.1334108},
- {-.0216473, .0776645},
- {-.0225161, .0853673}
-};
- P->n = 9;
- P->lam0 = DEG_TO_RAD * -120.;
- P->phi0 = DEG_TO_RAD * 45.;
- if (P->es) { /* fixed ellipsoid/sphere */
- P->zcoeff = ABe;
- P->a = 6378206.4;
- P->e = sqrt(P->es = 0.00676866);
- } else {
- P->zcoeff = ABs;
- P->a = 6370997.;
- }
-ENDENTRY(setup(P))
+#endif
diff --git a/src/PJ_moll.c b/src/PJ_moll.c
index cf9369dc..31829b68 100644
--- a/src/PJ_moll.c
+++ b/src/PJ_moll.c
@@ -1,64 +1,259 @@
-#define PROJ_PARMS__ \
- double C_x, C_y, C_p;
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(moll, "Mollweide") "\n\tPCyl., Sph.";
PROJ_HEAD(wag4, "Wagner IV") "\n\tPCyl., Sph.";
PROJ_HEAD(wag5, "Wagner V") "\n\tPCyl., Sph.";
-#define MAX_ITER 10
-#define LOOP_TOL 1e-7
-FORWARD(s_forward); /* spheroid */
- double k, V;
- int i;
-
- k = P->C_p * sin(lp.phi);
- for (i = MAX_ITER; i ; --i) {
- lp.phi -= V = (lp.phi + sin(lp.phi) - k) /
- (1. + cos(lp.phi));
- if (fabs(V) < LOOP_TOL)
- break;
- }
- if (!i)
- lp.phi = (lp.phi < 0.) ? -HALFPI : HALFPI;
- else
- lp.phi *= 0.5;
- xy.x = P->C_x * lp.lam * cos(lp.phi);
- xy.y = P->C_y * sin(lp.phi);
- return (xy);
+
+#define MAX_ITER 10
+#define LOOP_TOL 1e-7
+
+struct pj_opaque {
+ double C_x, C_y, C_p;
+};
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double k, V;
+ int i;
+
+ k = Q->C_p * sin(lp.phi);
+ for (i = MAX_ITER; i ; --i) {
+ lp.phi -= V = (lp.phi + sin(lp.phi) - k) /
+ (1. + cos(lp.phi));
+ if (fabs(V) < LOOP_TOL)
+ break;
+ }
+ if (!i)
+ lp.phi = (lp.phi < 0.) ? -HALFPI : HALFPI;
+ else
+ lp.phi *= 0.5;
+ xy.x = Q->C_x * lp.lam * cos(lp.phi);
+ xy.y = Q->C_y * sin(lp.phi);
+ return xy;
}
-INVERSE(s_inverse); /* spheroid */
- lp.phi = aasin(P->ctx, xy.y / P->C_y);
- lp.lam = xy.x / (P->C_x * cos(lp.phi));
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ lp.phi = aasin(P->ctx, xy.y / Q->C_y);
+ lp.lam = xy.x / (Q->C_x * cos(lp.phi));
if (fabs(lp.lam) < PI) {
lp.phi += lp.phi;
- lp.phi = aasin(P->ctx, (lp.phi + sin(lp.phi)) / P->C_p);
+ lp.phi = aasin(P->ctx, (lp.phi + sin(lp.phi)) / Q->C_p);
} else {
lp.lam = lp.phi = HUGE_VAL;
}
- return (lp);
+ 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, double p) {
+ struct pj_opaque *Q = P->opaque;
+ double r, sp, p2 = p + p;
+
+ P->es = 0;
+ sp = sin(p);
+ r = sqrt(TWOPI * sp / (p2 + sin(p2)));
+
+ Q->C_x = 2. * r / PI;
+ Q->C_y = r / sp;
+ Q->C_p = p2 + sin(p2);
+
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+ return P;
+}
+
+
+PJ *PROJECTION(moll) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ return setup(P, HALFPI);
+}
+
+
+PJ *PROJECTION(wag4) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ return setup(P, PI/3.);
+}
+
+PJ *PROJECTION(wag5) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ P->es = 0;
+ Q->C_x = 0.90977;
+ Q->C_y = 1.65014;
+ Q->C_p = 3.00896;
+
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_moll_selftest (void) {return 0;}
+#else
+
+int pj_moll_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=moll +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ {201113.698641813244, 124066.283433859542},
+ {201113.698641813244, -124066.283433859542},
+ {-201113.698641813244, 124066.283433859542},
+ {-201113.698641813244, -124066.283433859542},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ {0.00198873782220854774, 0.000806005080362811612},
+ {0.00198873782220854774, -0.000806005080362811612},
+ {-0.00198873782220854774, 0.000806005080362811612},
+ {-0.00198873782220854774, -0.000806005080362811612},
+ };
+
+ 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); }
- static PJ *
-setup(PJ *P, double p) {
- double r, sp, p2 = p + p;
-
- P->es = 0;
- sp = sin(p);
- r = sqrt(TWOPI * sp / (p2 + sin(p2)));
- P->C_x = 2. * r / PI;
- P->C_y = r / sp;
- P->C_p = p2 + sin(p2);
- P->inv = s_inverse;
- P->fwd = s_forward;
- return P;
+
+#endif
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_wag4_selftest (void) {return 0;}
+#else
+
+int pj_wag4_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=wag4 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 192801.218662384286, 129416.216394802992},
+ { 192801.218662384286, -129416.216394802992},
+ {-192801.218662384286, 129416.216394802992},
+ {-192801.218662384286, -129416.216394802992},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.00207450259783523421, 0.000772682950537716476},
+ { 0.00207450259783523421, -0.000772682950537716476},
+ {-0.00207450259783523421, 0.000772682950537716476},
+ {-0.00207450259783523421, -0.000772682950537716476},
+ };
+
+ 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);
}
-ENTRY0(moll) ENDENTRY(setup(P, HALFPI))
-ENTRY0(wag4) ENDENTRY(setup(P, PI/3.))
-ENTRY0(wag5)
- P->es = 0;
- P->C_x = 0.90977;
- P->C_y = 1.65014;
- P->C_p = 3.00896;
- P->inv = s_inverse;
- P->fwd = s_forward;
-ENDENTRY(P)
+
+#endif
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_wag5_selftest (void) {return 0;}
+#else
+
+int pj_wag5_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=wag5 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+
+ XY s_fwd_expect[] = {
+ { 203227.05192532466, 138651.631442713202},
+ { 203227.05192532466, -138651.631442713202},
+ {-203227.05192532466, 138651.631442713202},
+ {-203227.05192532466, -138651.631442713202},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+
+
+
+ LP s_inv_expect[] = {
+ { 0.00196807227086416396, 0.00072121615041701424},
+ { 0.00196807227086416396, -0.00072121615041701424},
+ {-0.00196807227086416396, 0.00072121615041701424},
+ {-0.00196807227086416396, -0.00072121615041701424},
+ };
+
+ 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_natearth.c b/src/PJ_natearth.c
index 0f283415..290f8efe 100644
--- a/src/PJ_natearth.c
+++ b/src/PJ_natearth.c
@@ -12,10 +12,11 @@ where they meet the horizontal pole line. This improvement is by intention
and designed in collaboration with Tom Patterson.
Port to PROJ.4 by Bernhard Jenny, 6 June 2011
*/
-
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(natearth, "Natural Earth") "\n\tPCyl., Sph.";
+
#define A0 0.8707
#define A1 -0.131979
#define A2 -0.013791
@@ -34,46 +35,116 @@ PROJ_HEAD(natearth, "Natural Earth") "\n\tPCyl., Sph.";
#define EPS 1e-11
#define MAX_Y (0.8707 * 0.52 * PI)
-FORWARD(s_forward); /* spheroid */
- double phi2, phi4;
- (void) P;
- phi2 = lp.phi * lp.phi;
- phi4 = phi2 * phi2;
- xy.x = lp.lam * (A0 + phi2 * (A1 + phi2 * (A2 + phi4 * phi2 * (A3 + phi2 * A4))));
- xy.y = lp.phi * (B0 + phi2 * (B1 + phi4 * (B2 + B3 * phi2 + B4 * phi4)));
- return (xy);
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ double phi2, phi4;
+ (void) P;
+
+ phi2 = lp.phi * lp.phi;
+ phi4 = phi2 * phi2;
+ xy.x = lp.lam * (A0 + phi2 * (A1 + phi2 * (A2 + phi4 * phi2 * (A3 + phi2 * A4))));
+ xy.y = lp.phi * (B0 + phi2 * (B1 + phi4 * (B2 + B3 * phi2 + B4 * phi4)));
+ return xy;
}
-INVERSE(s_inverse); /* spheroid */
- double yc, tol, y2, y4, f, fder;
- (void) P;
-
- /* make sure y is inside valid range */
- if (xy.y > MAX_Y) {
- xy.y = MAX_Y;
- } else if (xy.y < -MAX_Y) {
- xy.y = -MAX_Y;
- }
-
- /* latitude */
- yc = xy.y;
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ double yc, tol, y2, y4, f, fder;
+ (void) P;
+
+ /* make sure y is inside valid range */
+ if (xy.y > MAX_Y) {
+ xy.y = MAX_Y;
+ } else if (xy.y < -MAX_Y) {
+ xy.y = -MAX_Y;
+ }
+
+ /* latitude */
+ yc = xy.y;
for (;;) { /* Newton-Raphson */
- y2 = yc * yc;
- y4 = y2 * y2;
- f = (yc * (B0 + y2 * (B1 + y4 * (B2 + B3 * y2 + B4 * y4)))) - xy.y;
- fder = C0 + y2 * (C1 + y4 * (C2 + C3 * y2 + C4 * y4));
- yc -= tol = f / fder;
- if (fabs(tol) < EPS) {
- break;
- }
- }
- lp.phi = yc;
-
- /* longitude */
- y2 = yc * yc;
- lp.lam = xy.x / (A0 + y2 * (A1 + y2 * (A2 + y2 * y2 * y2 * (A3 + y2 * A4))));
-
- return (lp);
+ y2 = yc * yc;
+ y4 = y2 * y2;
+ f = (yc * (B0 + y2 * (B1 + y4 * (B2 + B3 * y2 + B4 * y4)))) - xy.y;
+ fder = C0 + y2 * (C1 + y4 * (C2 + C3 * y2 + C4 * y4));
+ yc -= tol = f / fder;
+ if (fabs(tol) < EPS) {
+ break;
+ }
+ }
+ lp.phi = yc;
+
+ /* longitude */
+ y2 = yc * yc;
+ lp.lam = xy.x / (A0 + y2 * (A1 + y2 * (A2 + y2 * y2 * y2 * (A3 + y2 * A4))));
+
+ return lp;
+}
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+
+ return pj_dealloc(P);
+}
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(natearth) {
+ P->es = 0;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_natearth_selftest (void) {return 0;}
+#else
+
+int pj_natearth_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=natearth +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 194507.265257889288, 112508.737358294515},
+ { 194507.265257889288, -112508.737358294515},
+ {-194507.265257889288, 112508.737358294515},
+ {-194507.265257889288, -112508.737358294515},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.00205638349586440223, 0.000888823913291242177},
+ { 0.00205638349586440223, -0.000888823913291242177},
+ {-0.00205638349586440223, 0.000888823913291242177},
+ {-0.00205638349586440223, -0.000888823913291242177},
+ };
+
+ 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(natearth) P->es = 0; P->inv = s_inverse; P->fwd = s_forward; ENDENTRY(P)
+
+
+#endif
diff --git a/src/PJ_natearth2.c b/src/PJ_natearth2.c
index c3776a8b..5a57fb14 100644
--- a/src/PJ_natearth2.c
+++ b/src/PJ_natearth2.c
@@ -1,13 +1,13 @@
/*
-The Natural Earth II projection was designed by Tom Patterson, US National
+The Natural Earth II projection was designed by Tom Patterson, US National
Park Service, in 2012, using Flex Projector. The polynomial equation was
-developed by Bojan Savric and Bernhard Jenny, College of Earth, Ocean,
+developed by Bojan Savric and Bernhard Jenny, College of Earth, Ocean,
and Atmospheric Sciences, Oregon State University.
Port to PROJ.4 by Bojan Savric, 4 April 2016
*/
-
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(natearth2, "Natural Earth 2") "\n\tPCyl., Sph.";
#define A0 0.84719
@@ -27,49 +27,121 @@ PROJ_HEAD(natearth2, "Natural Earth 2") "\n\tPCyl., Sph.";
#define EPS 1e-11
#define MAX_Y (0.84719 * 0.535117535153096 * PI)
-FORWARD(s_forward); /* spheroid */
- double phi2, phi4, phi6;
- phi2 = lp.phi * lp.phi;
- phi4 = phi2 * phi2;
- phi6 = phi2 * phi4;
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ double phi2, phi4, phi6;
+ (void) P;
- xy.x = lp.lam * (A0 + A1 * phi2 + phi6 * phi6 * (A2 + A3 * phi2 + A4 * phi4 + A5 * phi6));
- xy.y = lp.phi * (B0 + phi4 * phi4 * (B1 + B2 * phi2 + B3 * phi4));
- return (xy);
+ phi2 = lp.phi * lp.phi;
+ phi4 = phi2 * phi2;
+ phi6 = phi2 * phi4;
+
+ xy.x = lp.lam * (A0 + A1 * phi2 + phi6 * phi6 * (A2 + A3 * phi2 + A4 * phi4 + A5 * phi6));
+ xy.y = lp.phi * (B0 + phi4 * phi4 * (B1 + B2 * phi2 + B3 * phi4));
+ return xy;
}
-INVERSE(s_inverse); /* spheroid */
- double yc, tol, y2, y4, y6, f, fder;
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ double yc, tol, y2, y4, y6, f, fder;
+ (void) P;
/* make sure y is inside valid range */
- if (xy.y > MAX_Y) {
- xy.y = MAX_Y;
- } else if (xy.y < -MAX_Y) {
- xy.y = -MAX_Y;
- }
+ if (xy.y > MAX_Y) {
+ xy.y = MAX_Y;
+ } else if (xy.y < -MAX_Y) {
+ xy.y = -MAX_Y;
+ }
/* latitude */
- yc = xy.y;
+ yc = xy.y;
for (;;) { /* Newton-Raphson */
- y2 = yc * yc;
- y4 = y2 * y2;
- f = (yc * (B0 + y4 * y4 * (B1 + B2 * y2 + B3 * y4))) - xy.y;
- fder = C0 + y4 * y4 * (C1 + C2 * y2 + C3 * y4);
- yc -= tol = f / fder;
- if (fabs(tol) < EPS) {
- break;
- }
- }
- lp.phi = yc;
+ y2 = yc * yc;
+ y4 = y2 * y2;
+ f = (yc * (B0 + y4 * y4 * (B1 + B2 * y2 + B3 * y4))) - xy.y;
+ fder = C0 + y4 * y4 * (C1 + C2 * y2 + C3 * y4);
+ yc -= tol = f / fder;
+ if (fabs(tol) < EPS) {
+ break;
+ }
+ }
+ lp.phi = yc;
/* longitude */
- y2 = yc * yc;
- y4 = y2 * y2;
- y6 = y2 * y4;
+ y2 = yc * yc;
+ y4 = y2 * y2;
+ y6 = y2 * y4;
+
+ lp.lam = xy.x / (A0 + A1 * y2 + y6 * y6 * (A2 + A3 * y2 + A4 * y4 + A5 * y6));
+
+ return lp;
+}
+
- lp.lam = xy.x / (A0 + A1 * y2 + y6 * y6 * (A2 + A3 * y2 + A4 * y4 + A5 * y6));
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
- return (lp);
+ return pj_dealloc(P);
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(natearth2) P->es = 0; P->inv = s_inverse; P->fwd = s_forward; ENDENTRY(P)
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(natearth2) {
+ P->es = 0;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_natearth2_selftest (void) {return 0;}
+#else
+
+int pj_natearth2_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=natearth2 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 189255.172934730799, 113022.495810907014},
+ { 189255.172934730799, -113022.495810907014},
+ {-189255.172934730799, 113022.495810907014},
+ {-189255.172934730799, -113022.495810907014},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.00211344929691056112, 0.000884779612080993237},
+ { 0.00211344929691056112, -0.000884779612080993237},
+ {-0.00211344929691056112, 0.000884779612080993237},
+ {-0.00211344929691056112, -0.000884779612080993237},
+ };
+
+ 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_nell.c b/src/PJ_nell.c
index 77983de8..b69b9997 100644
--- a/src/PJ_nell.c
+++ b/src/PJ_nell.c
@@ -1,30 +1,106 @@
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(nell, "Nell") "\n\tPCyl., Sph.";
-#define MAX_ITER 10
-#define LOOP_TOL 1e-7
-FORWARD(s_forward); /* spheroid */
- double k, V;
- int i;
- (void) P;
-
- k = 2. * sin(lp.phi);
- V = lp.phi * lp.phi;
- lp.phi *= 1.00371 + V * (-0.0935382 + V * -0.011412);
- for (i = MAX_ITER; i ; --i) {
- lp.phi -= V = (lp.phi + sin(lp.phi) - k) /
- (1. + cos(lp.phi));
- if (fabs(V) < LOOP_TOL)
- break;
- }
- xy.x = 0.5 * lp.lam * (1. + cos(lp.phi));
- xy.y = lp.phi;
- return (xy);
+
+#define MAX_ITER 10
+#define LOOP_TOL 1e-7
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ double k, V;
+ int i;
+ (void) P;
+
+ k = 2. * sin(lp.phi);
+ V = lp.phi * lp.phi;
+ lp.phi *= 1.00371 + V * (-0.0935382 + V * -0.011412);
+ for (i = MAX_ITER; i ; --i) {
+ lp.phi -= V = (lp.phi + sin(lp.phi) - k) /
+ (1. + cos(lp.phi));
+ if (fabs(V) < LOOP_TOL)
+ break;
+ }
+ xy.x = 0.5 * lp.lam * (1. + cos(lp.phi));
+ xy.y = lp.phi;
+
+ return xy;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ lp.lam = 2. * xy.x / (1. + cos(xy.y));
+ lp.phi = aasin(P->ctx,0.5 * (xy.y + sin(xy.y)));
+
+ return lp;
+}
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+
+ return pj_dealloc(P);
+}
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(nell) {
+
+ P->es = 0;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
}
-INVERSE(s_inverse); /* spheroid */
- lp.lam = 2. * xy.x / (1. + cos(xy.y));
- lp.phi = aasin(P->ctx,0.5 * (xy.y + sin(xy.y)));
- return (lp);
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_nell_selftest (void) {return 0;}
+#else
+
+int pj_nell_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=nell +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 223385.132504695706, 111698.23644718733},
+ { 223385.132504695706, -111698.23644718733},
+ {-223385.132504695706, 111698.23644718733},
+ {-223385.132504695706, -111698.23644718733},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.00179049310989310567, 0.000895246554910125161},
+ { 0.00179049310989310567, -0.000895246554910125161},
+ {-0.00179049310989310567, 0.000895246554910125161},
+ {-0.00179049310989310567, -0.000895246554910125161},
+ };
+
+ 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(nell) P->es = 0; P->inv = s_inverse; P->fwd = s_forward; ENDENTRY(P)
+
+
+#endif
diff --git a/src/PJ_nell_h.c b/src/PJ_nell_h.c
index 22061ea9..1e863945 100644
--- a/src/PJ_nell_h.c
+++ b/src/PJ_nell_h.c
@@ -1,32 +1,109 @@
#define PJ_LIB__
-# include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(nell_h, "Nell-Hammer") "\n\tPCyl., Sph.";
+
#define NITER 9
#define EPS 1e-7
-FORWARD(s_forward); /* spheroid */
- (void) P;
- xy.x = 0.5 * lp.lam * (1. + cos(lp.phi));
- xy.y = 2.0 * (lp.phi - tan(0.5 *lp.phi));
- return (xy);
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ (void) P;
+
+ xy.x = 0.5 * lp.lam * (1. + cos(lp.phi));
+ xy.y = 2.0 * (lp.phi - tan(0.5 *lp.phi));
+
+ return xy;
}
-INVERSE(s_inverse); /* spheroid */
- double V, c, p;
- int i;
- (void) P;
-
- p = 0.5 * xy.y;
- for (i = NITER; i ; --i) {
- c = cos(0.5 * lp.phi);
- lp.phi -= V = (lp.phi - tan(lp.phi/2) - p)/(1. - 0.5/(c*c));
- if (fabs(V) < EPS)
- break;
- }
- if (!i) {
- lp.phi = p < 0. ? -HALFPI : HALFPI;
- lp.lam = 2. * xy.x;
- } else
- lp.lam = 2. * xy.x / (1. + cos(lp.phi));
- return (lp);
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ double V, c, p;
+ int i;
+ (void) P;
+
+ p = 0.5 * xy.y;
+ for (i = NITER; i ; --i) {
+ c = cos(0.5 * lp.phi);
+ lp.phi -= V = (lp.phi - tan(lp.phi/2) - p)/(1. - 0.5/(c*c));
+ if (fabs(V) < EPS)
+ break;
+ }
+ if (!i) {
+ lp.phi = p < 0. ? -HALFPI : HALFPI;
+ lp.lam = 2. * xy.x;
+ } else
+ lp.lam = 2. * xy.x / (1. + cos(lp.phi));
+
+ return lp;
+}
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+
+ return pj_dealloc(P);
+}
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(nell_h) P->es = 0.; P->inv = s_inverse; P->fwd = s_forward; ENDENTRY(P)
+
+
+PJ *PROJECTION(nell_h) {
+ P->es = 0.;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_nell_h_selftest (void) {return 0;}
+#else
+
+int pj_nell_h_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=nell_h +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 223385.131640952837, 111698.236533561678},
+ { 223385.131640952837, -111698.236533561678},
+ {-223385.131640952837, 111698.236533561678},
+ {-223385.131640952837, -111698.236533561678},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.00179049310989310567, 0.000895246554910125378},
+ { 0.00179049310989310567, -0.000895246554910125378},
+ {-0.00179049310989310567, 0.000895246554910125378},
+ {-0.00179049310989310567, -0.000895246554910125378},
+ };
+
+ 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_nocol.c b/src/PJ_nocol.c
index 2b005e1d..ad96ff31 100644
--- a/src/PJ_nocol.c
+++ b/src/PJ_nocol.c
@@ -1,40 +1,96 @@
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(nicol, "Nicolosi Globular") "\n\tMisc Sph, no inv.";
-#define EPS 1e-10
-FORWARD(s_forward); /* spheroid */
- (void) P;
-
- if (fabs(lp.lam) < EPS) {
- xy.x = 0;
- xy.y = lp.phi;
- } else if (fabs(lp.phi) < EPS) {
- xy.x = lp.lam;
- xy.y = 0.;
- } else if (fabs(fabs(lp.lam) - HALFPI) < EPS) {
- xy.x = lp.lam * cos(lp.phi);
- xy.y = HALFPI * sin(lp.phi);
- } else if (fabs(fabs(lp.phi) - HALFPI) < EPS) {
- xy.x = 0;
- xy.y = lp.phi;
- } else {
- double tb, c, d, m, n, r2, sp;
-
- tb = HALFPI / lp.lam - lp.lam / HALFPI;
- c = lp.phi / HALFPI;
- d = (1 - c * c)/((sp = sin(lp.phi)) - c);
- r2 = tb / d;
- r2 *= r2;
- m = (tb * sp / d - 0.5 * tb)/(1. + r2);
- n = (sp / r2 + 0.5 * d)/(1. + 1./r2);
- xy.x = cos(lp.phi);
- xy.x = sqrt(m * m + xy.x * xy.x / (1. + r2));
- xy.x = HALFPI * ( m + (lp.lam < 0. ? -xy.x : xy.x));
- xy.y = sqrt(n * n - (sp * sp / r2 + d * sp - 1.) /
- (1. + 1./r2));
- xy.y = HALFPI * ( n + (lp.phi < 0. ? xy.y : -xy.y ));
- }
- return (xy);
+
+#define EPS 1e-10
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ (void) P;
+
+ if (fabs(lp.lam) < EPS) {
+ xy.x = 0;
+ xy.y = lp.phi;
+ } else if (fabs(lp.phi) < EPS) {
+ xy.x = lp.lam;
+ xy.y = 0.;
+ } else if (fabs(fabs(lp.lam) - HALFPI) < EPS) {
+ xy.x = lp.lam * cos(lp.phi);
+ xy.y = HALFPI * sin(lp.phi);
+ } else if (fabs(fabs(lp.phi) - HALFPI) < EPS) {
+ xy.x = 0;
+ xy.y = lp.phi;
+ } else {
+ double tb, c, d, m, n, r2, sp;
+
+ tb = HALFPI / lp.lam - lp.lam / HALFPI;
+ c = lp.phi / HALFPI;
+ d = (1 - c * c)/((sp = sin(lp.phi)) - c);
+ r2 = tb / d;
+ r2 *= r2;
+ m = (tb * sp / d - 0.5 * tb)/(1. + r2);
+ n = (sp / r2 + 0.5 * d)/(1. + 1./r2);
+ xy.x = cos(lp.phi);
+ xy.x = sqrt(m * m + xy.x * xy.x / (1. + r2));
+ xy.x = HALFPI * ( m + (lp.lam < 0. ? -xy.x : xy.x));
+ xy.y = sqrt(n * n - (sp * sp / r2 + d * sp - 1.) /
+ (1. + 1./r2));
+ xy.y = HALFPI * ( n + (lp.phi < 0. ? xy.y : -xy.y ));
+ }
+ return (xy);
+}
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+
+ return pj_dealloc(P);
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(nicol) P->es = 0.; P->fwd = s_forward; ENDENTRY(P)
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(nicol) {
+ P->es = 0.;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_nicol_selftest (void) {return 0;}
+#else
+
+int pj_nicol_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=nicol +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 223374.561814139714, 111732.553988545071},
+ { 223374.561814139714, -111732.553988545071},
+ {-223374.561814139714, 111732.553988545071},
+ {-223374.561814139714, -111732.553988545071},
+ };
+
+ return pj_generic_selftest (0, s_args, tolerance_xy, tolerance_lp, 4, 4, fwd_in, 0, s_fwd_expect, 0, 0, 0);
+}
+
+
+#endif
diff --git a/src/PJ_nsper.c b/src/PJ_nsper.c
index 0f355b93..7e3fcda8 100644
--- a/src/PJ_nsper.c
+++ b/src/PJ_nsper.c
@@ -1,149 +1,287 @@
-#define PROJ_PARMS__ \
- double height; \
- double sinph0; \
- double cosph0; \
- double p; \
- double rp; \
- double pn1; \
- double pfact; \
- double h; \
- double cg; \
- double sg; \
- double sw; \
- double cw; \
- int mode; \
- int tilt;
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
+struct pj_opaque {
+ double height;
+ double sinph0;
+ double cosph0;
+ double p;
+ double rp;
+ double pn1;
+ double pfact;
+ double h;
+ double cg;
+ double sg;
+ double sw;
+ double cw;
+ int mode;
+ int tilt;
+};
+
PROJ_HEAD(nsper, "Near-sided perspective") "\n\tAzi, Sph\n\th=";
PROJ_HEAD(tpers, "Tilted perspective") "\n\tAzi, Sph\n\ttilt= azi= h=";
+
# define EPS10 1.e-10
-# define N_POLE 0
+# define N_POLE 0
# define S_POLE 1
-# define EQUIT 2
-# define OBLIQ 3
-FORWARD(s_forward); /* spheroid */
- double coslam, cosphi, sinphi;
-
- sinphi = sin(lp.phi);
- cosphi = cos(lp.phi);
- coslam = cos(lp.lam);
- switch (P->mode) {
- case OBLIQ:
- xy.y = P->sinph0 * sinphi + P->cosph0 * cosphi * coslam;
- break;
- case EQUIT:
- xy.y = cosphi * coslam;
- break;
- case S_POLE:
- xy.y = - sinphi;
- break;
- case N_POLE:
- xy.y = sinphi;
- break;
- }
- if (xy.y < P->rp) F_ERROR;
- xy.y = P->pn1 / (P->p - xy.y);
- xy.x = xy.y * cosphi * sin(lp.lam);
- switch (P->mode) {
- case OBLIQ:
- xy.y *= (P->cosph0 * sinphi -
- P->sinph0 * cosphi * coslam);
- break;
- case EQUIT:
- xy.y *= sinphi;
- break;
- case N_POLE:
- coslam = - coslam;
- case S_POLE:
- xy.y *= cosphi * coslam;
- break;
- }
- if (P->tilt) {
- double yt, ba;
-
- yt = xy.y * P->cg + xy.x * P->sg;
- ba = 1. / (yt * P->sw * P->h + P->cw);
- xy.x = (xy.x * P->cg - xy.y * P->sg) * P->cw * ba;
- xy.y = yt * ba;
- }
- return (xy);
+# define EQUIT 2
+# define OBLIQ 3
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double coslam, cosphi, sinphi;
+
+ sinphi = sin(lp.phi);
+ cosphi = cos(lp.phi);
+ coslam = cos(lp.lam);
+ switch (Q->mode) {
+ case OBLIQ:
+ xy.y = Q->sinph0 * sinphi + Q->cosph0 * cosphi * coslam;
+ break;
+ case EQUIT:
+ xy.y = cosphi * coslam;
+ break;
+ case S_POLE:
+ xy.y = - sinphi;
+ break;
+ case N_POLE:
+ xy.y = sinphi;
+ break;
+ }
+ if (xy.y < Q->rp) F_ERROR;
+ xy.y = Q->pn1 / (Q->p - xy.y);
+ xy.x = xy.y * cosphi * sin(lp.lam);
+ switch (Q->mode) {
+ case OBLIQ:
+ xy.y *= (Q->cosph0 * sinphi -
+ Q->sinph0 * cosphi * coslam);
+ break;
+ case EQUIT:
+ xy.y *= sinphi;
+ break;
+ case N_POLE:
+ coslam = - coslam;
+ case S_POLE:
+ xy.y *= cosphi * coslam;
+ break;
+ }
+ if (Q->tilt) {
+ double yt, ba;
+
+ yt = xy.y * Q->cg + xy.x * Q->sg;
+ ba = 1. / (yt * Q->sw * Q->h + Q->cw);
+ xy.x = (xy.x * Q->cg - xy.y * Q->sg) * Q->cw * ba;
+ xy.y = yt * ba;
+ }
+ return xy;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double rh, cosz, sinz;
+
+ if (Q->tilt) {
+ double bm, bq, yt;
+
+ yt = 1./(Q->pn1 - xy.y * Q->sw);
+ bm = Q->pn1 * xy.x * yt;
+ bq = Q->pn1 * xy.y * Q->cw * yt;
+ xy.x = bm * Q->cg + bq * Q->sg;
+ xy.y = bq * Q->cg - bm * Q->sg;
+ }
+ rh = hypot(xy.x, xy.y);
+ if ((sinz = 1. - rh * rh * Q->pfact) < 0.) I_ERROR;
+ sinz = (Q->p - sqrt(sinz)) / (Q->pn1 / rh + rh / Q->pn1);
+ cosz = sqrt(1. - sinz * sinz);
+ if (fabs(rh) <= EPS10) {
+ lp.lam = 0.;
+ lp.phi = P->phi0;
+ } else {
+ switch (Q->mode) {
+ case OBLIQ:
+ lp.phi = asin(cosz * Q->sinph0 + xy.y * sinz * Q->cosph0 / rh);
+ xy.y = (cosz - Q->sinph0 * sin(lp.phi)) * rh;
+ xy.x *= sinz * Q->cosph0;
+ break;
+ case EQUIT:
+ lp.phi = asin(xy.y * sinz / rh);
+ xy.y = cosz * rh;
+ xy.x *= sinz;
+ break;
+ case N_POLE:
+ lp.phi = asin(cosz);
+ xy.y = -xy.y;
+ break;
+ case S_POLE:
+ lp.phi = - asin(cosz);
+ break;
+ }
+ lp.lam = atan2(xy.x, 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;
}
-INVERSE(s_inverse); /* spheroid */
- double rh, cosz, sinz;
-
- if (P->tilt) {
- double bm, bq, yt;
-
- yt = 1./(P->pn1 - xy.y * P->sw);
- bm = P->pn1 * xy.x * yt;
- bq = P->pn1 * xy.y * P->cw * yt;
- xy.x = bm * P->cg + bq * P->sg;
- xy.y = bq * P->cg - bm * P->sg;
- }
- rh = hypot(xy.x, xy.y);
- if ((sinz = 1. - rh * rh * P->pfact) < 0.) I_ERROR;
- sinz = (P->p - sqrt(sinz)) / (P->pn1 / rh + rh / P->pn1);
- cosz = sqrt(1. - sinz * sinz);
- if (fabs(rh) <= EPS10) {
- lp.lam = 0.;
- lp.phi = P->phi0;
- } else {
- switch (P->mode) {
- case OBLIQ:
- lp.phi = asin(cosz * P->sinph0 + xy.y * sinz * P->cosph0 / rh);
- xy.y = (cosz - P->sinph0 * sin(lp.phi)) * rh;
- xy.x *= sinz * P->cosph0;
- break;
- case EQUIT:
- lp.phi = asin(xy.y * sinz / rh);
- xy.y = cosz * rh;
- xy.x *= sinz;
- break;
- case N_POLE:
- lp.phi = asin(cosz);
- xy.y = -xy.y;
- break;
- case S_POLE:
- lp.phi = - asin(cosz);
- break;
- }
- lp.lam = atan2(xy.x, xy.y);
- }
- return (lp);
+
+
+static PJ *setup(PJ *P) {
+ struct pj_opaque *Q = P->opaque;
+
+ if ((Q->height = pj_param(P->ctx, P->params, "dh").f) <= 0.) E_ERROR(-30);
+ if (fabs(fabs(P->phi0) - HALFPI) < EPS10)
+ Q->mode = P->phi0 < 0. ? S_POLE : N_POLE;
+ else if (fabs(P->phi0) < EPS10)
+ Q->mode = EQUIT;
+ else {
+ Q->mode = OBLIQ;
+ Q->sinph0 = sin(P->phi0);
+ Q->cosph0 = cos(P->phi0);
+ }
+ Q->pn1 = Q->height / P->a; /* normalize by radius */
+ Q->p = 1. + Q->pn1;
+ Q->rp = 1. / Q->p;
+ Q->h = 1. / Q->pn1;
+ Q->pfact = (Q->p + 1.) * Q->h;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+ P->es = 0.;
+ return P;
}
-FREEUP; if (P) pj_dalloc(P); }
- static PJ *
-setup(PJ *P) {
- if ((P->height = pj_param(P->ctx, P->params, "dh").f) <= 0.) E_ERROR(-30);
- if (fabs(fabs(P->phi0) - HALFPI) < EPS10)
- P->mode = P->phi0 < 0. ? S_POLE : N_POLE;
- else if (fabs(P->phi0) < EPS10)
- P->mode = EQUIT;
- else {
- P->mode = OBLIQ;
- P->sinph0 = sin(P->phi0);
- P->cosph0 = cos(P->phi0);
- }
- P->pn1 = P->height / P->a; /* normalize by radius */
- P->p = 1. + P->pn1;
- P->rp = 1. / P->p;
- P->h = 1. / P->pn1;
- P->pfact = (P->p + 1.) * P->h;
- P->inv = s_inverse;
- P->fwd = s_forward;
- P->es = 0.;
- return P;
+
+
+PJ *PROJECTION(nsper) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->tilt = 0;
+
+ return setup(P);
}
-ENTRY0(nsper)
- P->tilt = 0;
-ENDENTRY(setup(P))
-ENTRY0(tpers)
- double omega, gamma;
-
- omega = pj_param(P->ctx, P->params, "dtilt").f * DEG_TO_RAD;
- gamma = pj_param(P->ctx, P->params, "dazi").f * DEG_TO_RAD;
- P->tilt = 1;
- P->cg = cos(gamma); P->sg = sin(gamma);
- P->cw = cos(omega); P->sw = sin(omega);
-ENDENTRY(setup(P))
+
+
+PJ *PROJECTION(tpers) {
+ double omega, gamma;
+
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ omega = pj_param(P->ctx, P->params, "dtilt").f * DEG_TO_RAD;
+ gamma = pj_param(P->ctx, P->params, "dazi").f * DEG_TO_RAD;
+ Q->tilt = 1;
+ Q->cg = cos(gamma); Q->sg = sin(gamma);
+ Q->cw = cos(omega); Q->sw = sin(omega);
+
+ return setup(P);
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_nsper_selftest (void) {return 0;}
+#else
+
+int pj_nsper_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=nsper +a=6400000 +h=1000000"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 222239.816114099842, 111153.763991924759},
+ { 222239.816114099842, -111153.763991924759},
+ {-222239.816114099842, 111153.763991924759},
+ {-222239.816114099842, -111153.763991924759},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.00179049311728792437, 0.000895246558425396135},
+ { 0.00179049311728792437, -0.000895246558425396135},
+ {-0.00179049311728792437, 0.000895246558425396135},
+ {-0.00179049311728792437, -0.000895246558425396135},
+ };
+
+ 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_tpers_selftest (void) {return 0;}
+#else
+
+int pj_tpers_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=tpers +a=6400000 +h=1000000 +azi=20"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 170820.288955531199, 180460.865555804776},
+ { 246853.941538942483, -28439.8780357754222},
+ {-246853.941538942483, 28439.8780357754222},
+ {-170820.288955531199, -180460.865555804776}
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.00198870552603137678, 0.000228871872278689991},
+ { 0.00137632081376749859, -0.00145364129728205432},
+ {-0.00137632081376749859, 0.00145364129728205432},
+ {-0.00198870552603137678, -0.000228871872278689991},
+ };
+
+ 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_nzmg.c b/src/PJ_nzmg.c
index 60df0041..8dcb2634 100644
--- a/src/PJ_nzmg.c
+++ b/src/PJ_nzmg.c
@@ -25,79 +25,153 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*****************************************************************************/
-
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
PROJ_HEAD(nzmg, "New Zealand Map Grid") "\n\tfixed Earth";
#define EPSLN 1e-10
#define SEC5_TO_RAD 0.4848136811095359935899141023
#define RAD_TO_SEC5 2.062648062470963551564733573
- static COMPLEX
-bf[] = {
- {.7557853228, 0.0},
- {.249204646, .003371507},
- {-.001541739, .041058560},
- {-.10162907, .01727609},
- {-.26623489, -.36249218},
- {-.6870983, -1.1651967} };
- static double
-tphi[] = { 1.5627014243, .5185406398, -.03333098, -.1052906, -.0368594,
- .007317, .01220, .00394, -.0013 },
-tpsi[] = { .6399175073, -.1358797613, .063294409, -.02526853, .0117879,
- -.0055161, .0026906, -.001333, .00067, -.00034 };
+
+static COMPLEX bf[] = {
+ { .7557853228, 0.0},
+ { .249204646, 0.003371507},
+ {-.001541739, 0.041058560},
+ {-.10162907, 0.01727609},
+ {-.26623489, -0.36249218},
+ {-.6870983, -1.1651967} };
+
+static double tphi[] = { 1.5627014243, .5185406398, -.03333098,
+ -.1052906, -.0368594, .007317,
+ .01220, .00394, -.0013 };
+
+static double tpsi[] = { .6399175073, -.1358797613, .063294409, -.02526853, .0117879,
+ -.0055161, .0026906, -.001333, .00067, -.00034 };
+
#define Nbf 5
#define Ntpsi 9
#define Ntphi 8
-FORWARD(e_forward); /* ellipsoid */
- COMPLEX p;
- double *C;
- int i;
-
- lp.phi = (lp.phi - P->phi0) * RAD_TO_SEC5;
- for (p.r = *(C = tpsi + (i = Ntpsi)); i ; --i)
- p.r = *--C + lp.phi * p.r;
- p.r *= lp.phi;
- p.i = lp.lam;
- p = pj_zpoly1(p, bf, Nbf);
- xy.x = p.i;
- xy.y = p.r;
- return xy;
+
+
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
+ XY xy = {0.0,0.0};
+ COMPLEX p;
+ double *C;
+ int i;
+
+ lp.phi = (lp.phi - P->phi0) * RAD_TO_SEC5;
+ for (p.r = *(C = tpsi + (i = Ntpsi)); i ; --i)
+ p.r = *--C + lp.phi * p.r;
+ p.r *= lp.phi;
+ p.i = lp.lam;
+ p = pj_zpoly1(p, bf, Nbf);
+ xy.x = p.i;
+ xy.y = p.r;
+
+ return xy;
}
-INVERSE(e_inverse); /* ellipsoid */
- int nn, i;
- COMPLEX p, f, fp, dp;
- double den, *C;
-
- p.r = xy.y;
- p.i = xy.x;
- for (nn = 20; nn ;--nn) {
- f = pj_zpolyd1(p, bf, Nbf, &fp);
- f.r -= xy.y;
- f.i -= xy.x;
- den = fp.r * fp.r + fp.i * fp.i;
- p.r += dp.r = -(f.r * fp.r + f.i * fp.i) / den;
- p.i += dp.i = -(f.i * fp.r - f.r * fp.i) / den;
- if ((fabs(dp.r) + fabs(dp.i)) <= EPSLN)
- break;
- }
- if (nn) {
- lp.lam = p.i;
- for (lp.phi = *(C = tphi + (i = Ntphi)); i ; --i)
- lp.phi = *--C + p.r * lp.phi;
- lp.phi = P->phi0 + p.r * lp.phi * SEC5_TO_RAD;
- } else
- lp.lam = lp.phi = HUGE_VAL;
- return lp;
+
+
+static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */
+ LP lp = {0.0,0.0};
+ int nn, i;
+ COMPLEX p, f, fp, dp;
+ double den, *C;
+
+ p.r = xy.y;
+ p.i = xy.x;
+ for (nn = 20; nn ;--nn) {
+ f = pj_zpolyd1(p, bf, Nbf, &fp);
+ f.r -= xy.y;
+ f.i -= xy.x;
+ den = fp.r * fp.r + fp.i * fp.i;
+ p.r += dp.r = -(f.r * fp.r + f.i * fp.i) / den;
+ p.i += dp.i = -(f.i * fp.r - f.r * fp.i) / den;
+ if ((fabs(dp.r) + fabs(dp.i)) <= EPSLN)
+ break;
+ }
+ if (nn) {
+ lp.lam = p.i;
+ for (lp.phi = *(C = tphi + (i = Ntphi)); i ; --i)
+ lp.phi = *--C + p.r * lp.phi;
+ lp.phi = P->phi0 + p.r * lp.phi * SEC5_TO_RAD;
+ } else
+ lp.lam = lp.phi = HUGE_VAL;
+
+ return lp;
+}
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+
+ return pj_dealloc(P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(nzmg)
- /* force to International major axis */
- P->ra = 1. / (P->a = 6378388.0);
- P->lam0 = DEG_TO_RAD * 173.;
- P->phi0 = DEG_TO_RAD * -41.;
- P->x0 = 2510000.;
- P->y0 = 6023150.;
- P->inv = e_inverse; P->fwd = e_forward;
-ENDENTRY(P)
+
+
+PJ *PROJECTION(nzmg) {
+ /* force to International major axis */
+ P->ra = 1. / (P->a = 6378388.0);
+ P->lam0 = DEG_TO_RAD * 173.;
+ P->phi0 = DEG_TO_RAD * -41.;
+ P->x0 = 2510000.;
+ P->y0 = 6023150.;
+
+ P->inv = e_inverse;
+ P->fwd = e_forward;
+
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_nzmg_selftest (void) {return 0;}
+#else
+
+int pj_nzmg_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=nzmg +ellps=GRS80 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ {3352675144.74742508, -7043205391.10024357},
+ {3691989502.77930641, -6729069415.33210468},
+ {4099000768.45323849, -7863208779.66724873},
+ {4466166927.36997604, -7502531736.62860489},
+ };
+
+ XY inv_in[] = {
+ { 200000, 100000},
+ { 200000,-100000},
+ {-200000, 100000},
+ {-200000,-100000}
+ };
+
+ LP e_inv_expect[] = {
+ {175.48208682711271, -69.4226921826331846},
+ {175.756819472543611, -69.5335710883796168},
+ {134.605119233460016, -61.4599957106629091},
+ {134.333684315954827, -61.6215536756024349},
+ };
+
+ return pj_generic_selftest (e_args, 0, tolerance_xy, tolerance_lp, 4, 4, fwd_in, e_fwd_expect, 0, inv_in, e_inv_expect, 0);
+}
+
+
+#endif
diff --git a/src/PJ_ob_tran.c b/src/PJ_ob_tran.c
index 4ddba9a4..e726b3b2 100644
--- a/src/PJ_ob_tran.c
+++ b/src/PJ_ob_tran.c
@@ -1,145 +1,225 @@
-#define PROJ_PARMS__ \
- struct PJconsts *link; \
- double lamp; \
- double cphip, sphip;
#define PJ_LIB__
#include <projects.h>
#include <string.h>
+
+struct pj_opaque {
+ struct PJconsts *link;
+ double lamp;
+ double cphip, sphip;
+};
+
PROJ_HEAD(ob_tran, "General Oblique Transformation") "\n\tMisc Sph"
"\n\to_proj= plus parameters for projection"
"\n\to_lat_p= o_lon_p= (new pole) or"
"\n\to_alpha= o_lon_c= o_lat_c= or"
"\n\to_lon_1= o_lat_1= o_lon_2= o_lat_2=";
+
#define TOL 1e-10
-FORWARD(o_forward); /* spheroid */
- double coslam, sinphi, cosphi;
-
- (void) xy;
-
- coslam = cos(lp.lam);
- sinphi = sin(lp.phi);
- cosphi = cos(lp.phi);
- lp.lam = adjlon(aatan2(cosphi * sin(lp.lam), P->sphip * cosphi * coslam +
- P->cphip * sinphi) + P->lamp);
- lp.phi = aasin(P->ctx,P->sphip * sinphi - P->cphip * cosphi * coslam);
- return (P->link->fwd(lp, P->link));
+
+
+static XY o_forward(LP lp, PJ *P) { /* spheroid */
+ struct pj_opaque *Q = P->opaque;
+ double coslam, sinphi, cosphi;
+
+ coslam = cos(lp.lam);
+ sinphi = sin(lp.phi);
+ cosphi = cos(lp.phi);
+ lp.lam = adjlon(aatan2(cosphi * sin(lp.lam), Q->sphip * cosphi * coslam +
+ Q->cphip * sinphi) + Q->lamp);
+ lp.phi = aasin(P->ctx,Q->sphip * sinphi - Q->cphip * cosphi * coslam);
+
+ return Q->link->fwd(lp, Q->link);
+}
+
+
+static XY t_forward(LP lp, PJ *P) { /* spheroid */
+ struct pj_opaque *Q = P->opaque;
+ double cosphi, coslam;
+
+ cosphi = cos(lp.phi);
+ coslam = cos(lp.lam);
+ lp.lam = adjlon(aatan2(cosphi * sin(lp.lam), sin(lp.phi)) + Q->lamp);
+ lp.phi = aasin(P->ctx, - cosphi * coslam);
+
+ return Q->link->fwd(lp, Q->link);
}
-FORWARD(t_forward); /* spheroid */
- double cosphi, coslam;
- (void) xy;
- cosphi = cos(lp.phi);
- coslam = cos(lp.lam);
- lp.lam = adjlon(aatan2(cosphi * sin(lp.lam), sin(lp.phi)) + P->lamp);
- lp.phi = aasin(P->ctx, - cosphi * coslam);
- return (P->link->fwd(lp, P->link));
+static LP o_inverse(XY xy, PJ *P) { /* spheroid */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double coslam, sinphi, cosphi;
+
+ lp = Q->link->inv(xy, Q->link);
+ if (lp.lam != HUGE_VAL) {
+ coslam = cos(lp.lam -= Q->lamp);
+ sinphi = sin(lp.phi);
+ cosphi = cos(lp.phi);
+ lp.phi = aasin(P->ctx,Q->sphip * sinphi + Q->cphip * cosphi * coslam);
+ lp.lam = aatan2(cosphi * sin(lp.lam), Q->sphip * cosphi * coslam -
+ Q->cphip * sinphi);
+ }
+ return lp;
}
-INVERSE(o_inverse); /* spheroid */
- double coslam, sinphi, cosphi;
-
- lp = P->link->inv(xy, P->link);
- if (lp.lam != HUGE_VAL) {
- coslam = cos(lp.lam -= P->lamp);
- sinphi = sin(lp.phi);
- cosphi = cos(lp.phi);
- lp.phi = aasin(P->ctx,P->sphip * sinphi + P->cphip * cosphi * coslam);
- lp.lam = aatan2(cosphi * sin(lp.lam), P->sphip * cosphi * coslam -
- P->cphip * sinphi);
- }
- return (lp);
+
+
+static LP t_inverse(XY xy, PJ *P) { /* spheroid */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double cosphi, t;
+
+ lp = Q->link->inv(xy, Q->link);
+ if (lp.lam != HUGE_VAL) {
+ cosphi = cos(lp.phi);
+ t = lp.lam - Q->lamp;
+ lp.lam = aatan2(cosphi * sin(t), - sin(lp.phi));
+ lp.phi = aasin(P->ctx,cosphi * cos(t));
+ }
+ return lp;
}
-INVERSE(t_inverse); /* spheroid */
- double cosphi, t;
-
- lp = P->link->inv(xy, P->link);
- if (lp.lam != HUGE_VAL) {
- cosphi = cos(lp.phi);
- t = lp.lam - P->lamp;
- lp.lam = aatan2(cosphi * sin(t), - sin(lp.phi));
- lp.phi = aasin(P->ctx,cosphi * cos(t));
- }
- return (lp);
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+ if (0==P->opaque)
+ return pj_dealloc (P);
+
+ if (P->opaque->link)
+ return pj_dealloc (P->opaque->link);
+
+ pj_dealloc (P->opaque);
+ return pj_dealloc(P);
}
-FREEUP;
- if (P) {
- if (P->link)
- (*(P->link->pfree))(P->link);
- pj_dalloc(P);
- }
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
}
-ENTRY1(ob_tran, link)
- int i;
- double phip;
- char *name, *s;
-
- /* get name of projection to be translated */
- if (!(name = pj_param(P->ctx, P->params, "so_proj").s)) E_ERROR(-26);
- for (i = 0; (s = pj_list[i].id) && strcmp(name, s) ; ++i) ;
- if (!s || !(P->link = (*pj_list[i].proj)(0))) E_ERROR(-37);
- /* copy existing header into new */
- P->es = 0.; /* force to spherical */
- P->link->params = P->params;
- P->link->ctx = P->ctx;
- P->link->over = P->over;
- P->link->geoc = P->geoc;
- P->link->a = P->a;
- P->link->es = P->es;
- P->link->ra = P->ra;
- P->link->lam0 = P->lam0;
- P->link->phi0 = P->phi0;
- P->link->x0 = P->x0;
- P->link->y0 = P->y0;
- P->link->k0 = P->k0;
- /* force spherical earth */
- P->link->one_es = P->link->rone_es = 1.;
- P->link->es = P->link->e = 0.;
- if (!(P->link = pj_list[i].proj(P->link))) {
- freeup(P);
- return 0;
- }
- if (pj_param(P->ctx, P->params, "to_alpha").i) {
- double lamc, phic, alpha;
-
- lamc = pj_param(P->ctx, P->params, "ro_lon_c").f;
- phic = pj_param(P->ctx, P->params, "ro_lat_c").f;
- alpha = pj_param(P->ctx, P->params, "ro_alpha").f;
+
+
+PJ *PROJECTION(ob_tran) {
+ int i;
+ double phip;
+ char *name, *s;
+
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ /* get name of projection to be translated */
+ if (!(name = pj_param(P->ctx, P->params, "so_proj").s)) E_ERROR(-26);
+ for (i = 0; (s = pj_list[i].id) && strcmp(name, s) ; ++i) ;
+ if (!s || !(Q->link = (*pj_list[i].proj)(0))) E_ERROR(-37);
+ /* copy existing header into new */
+ P->es = 0.; /* force to spherical */
+ Q->link->params = P->params;
+ Q->link->ctx = P->ctx;
+ Q->link->over = P->over;
+ Q->link->geoc = P->geoc;
+ Q->link->a = P->a;
+ Q->link->es = P->es;
+ Q->link->ra = P->ra;
+ Q->link->lam0 = P->lam0;
+ Q->link->phi0 = P->phi0;
+ Q->link->x0 = P->x0;
+ Q->link->y0 = P->y0;
+ Q->link->k0 = P->k0;
+ /* force spherical earth */
+ Q->link->one_es = Q->link->rone_es = 1.;
+ Q->link->es = Q->link->e = 0.;
+ if (!(Q->link = pj_list[i].proj(Q->link))) {
+ return freeup_new(P);
+ }
+ if (pj_param(P->ctx, P->params, "to_alpha").i) {
+ double lamc, phic, alpha;
+
+ lamc = pj_param(P->ctx, P->params, "ro_lon_c").f;
+ phic = pj_param(P->ctx, P->params, "ro_lat_c").f;
+ alpha = pj_param(P->ctx, P->params, "ro_alpha").f;
/*
- if (fabs(phic) <= TOL ||
- fabs(fabs(phic) - HALFPI) <= TOL ||
- fabs(fabs(alpha) - HALFPI) <= TOL)
+ if (fabs(phic) <= TOL ||
+ fabs(fabs(phic) - HALFPI) <= TOL ||
+ fabs(fabs(alpha) - HALFPI) <= TOL)
*/
- if (fabs(fabs(phic) - HALFPI) <= TOL)
- E_ERROR(-32);
- P->lamp = lamc + aatan2(-cos(alpha), -sin(alpha) * sin(phic));
- phip = aasin(P->ctx,cos(phic) * sin(alpha));
- } else if (pj_param(P->ctx, P->params, "to_lat_p").i) { /* specified new pole */
- P->lamp = pj_param(P->ctx, P->params, "ro_lon_p").f;
- phip = pj_param(P->ctx, P->params, "ro_lat_p").f;
- } else { /* specified new "equator" points */
- double lam1, lam2, phi1, phi2, con;
-
- lam1 = pj_param(P->ctx, P->params, "ro_lon_1").f;
- phi1 = pj_param(P->ctx, P->params, "ro_lat_1").f;
- lam2 = pj_param(P->ctx, P->params, "ro_lon_2").f;
- phi2 = pj_param(P->ctx, P->params, "ro_lat_2").f;
- if (fabs(phi1 - phi2) <= TOL ||
- (con = fabs(phi1)) <= TOL ||
- fabs(con - HALFPI) <= TOL ||
- fabs(fabs(phi2) - HALFPI) <= TOL) E_ERROR(-33);
- P->lamp = atan2(cos(phi1) * sin(phi2) * cos(lam1) -
- sin(phi1) * cos(phi2) * cos(lam2),
- sin(phi1) * cos(phi2) * sin(lam2) -
- cos(phi1) * sin(phi2) * sin(lam1));
- phip = atan(-cos(P->lamp - lam1) / tan(phi1));
- }
- if (fabs(phip) > TOL) { /* oblique */
- P->cphip = cos(phip);
- P->sphip = sin(phip);
- P->fwd = o_forward;
- P->inv = P->link->inv ? o_inverse : 0;
- } else { /* transverse */
- P->fwd = t_forward;
- P->inv = P->link->inv ? t_inverse : 0;
- }
-ENDENTRY(P)
+ if (fabs(fabs(phic) - HALFPI) <= TOL)
+ E_ERROR(-32);
+ Q->lamp = lamc + aatan2(-cos(alpha), -sin(alpha) * sin(phic));
+ phip = aasin(P->ctx,cos(phic) * sin(alpha));
+ } else if (pj_param(P->ctx, P->params, "to_lat_p").i) { /* specified new pole */
+ Q->lamp = pj_param(P->ctx, P->params, "ro_lon_p").f;
+ phip = pj_param(P->ctx, P->params, "ro_lat_p").f;
+ } else { /* specified new "equator" points */
+ double lam1, lam2, phi1, phi2, con;
+
+ lam1 = pj_param(P->ctx, P->params, "ro_lon_1").f;
+ phi1 = pj_param(P->ctx, P->params, "ro_lat_1").f;
+ lam2 = pj_param(P->ctx, P->params, "ro_lon_2").f;
+ phi2 = pj_param(P->ctx, P->params, "ro_lat_2").f;
+ if (fabs(phi1 - phi2) <= TOL ||
+ (con = fabs(phi1)) <= TOL ||
+ fabs(con - HALFPI) <= TOL ||
+ fabs(fabs(phi2) - HALFPI) <= TOL) E_ERROR(-33);
+ Q->lamp = atan2(cos(phi1) * sin(phi2) * cos(lam1) -
+ sin(phi1) * cos(phi2) * cos(lam2),
+ sin(phi1) * cos(phi2) * sin(lam2) -
+ cos(phi1) * sin(phi2) * sin(lam1));
+ phip = atan(-cos(Q->lamp - lam1) / tan(phi1));
+ }
+ if (fabs(phip) > TOL) { /* oblique */
+ Q->cphip = cos(phip);
+ Q->sphip = sin(phip);
+ P->fwd = o_forward;
+ P->inv = Q->link->inv ? o_inverse : 0;
+ } else { /* transverse */
+ P->fwd = t_forward;
+ P->inv = Q->link->inv ? t_inverse : 0;
+ }
+
+ return P;
+}
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_ob_tran_selftest (void) {return 0;}
+#else
+
+int pj_ob_tran_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=ob_tran +a=6400000 +o_proj=latlon +o_lon_p=20 +o_lat_p=20 +lon_0=180"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ {-2.6856872138416592, 1.2374302350496296},
+ {-2.6954069748943286, 1.2026833954513816},
+ {-2.8993663925401947, 1.2374302350496296},
+ {-2.8896466314875244, 1.2026833954513816},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 121.5518748407577, -2.5361001573966084},
+ { 63.261184340201858, 17.585319578673531},
+ {-141.10073322351622, 26.091712304855108},
+ {-65.862385598848391, 51.830295078417215},
+ };
+
+ 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_ocea.c b/src/PJ_ocea.c
index b268e1b8..817f0ce6 100644
--- a/src/PJ_ocea.c
+++ b/src/PJ_ocea.c
@@ -1,76 +1,153 @@
-#define PROJ_PARMS__ \
- double rok; \
- double rtk; \
- double sinphi; \
- double cosphi; \
- double singam; \
- double cosgam;
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(ocea, "Oblique Cylindrical Equal Area") "\n\tCyl, Sph"
- "lonc= alpha= or\n\tlat_1= lat_2= lon_1= lon_2=";
-FORWARD(s_forward); /* spheroid */
- double t;
-
- xy.y = sin(lp.lam);
-/*
- xy.x = atan2((tan(lp.phi) * P->cosphi + P->sinphi * xy.y) , cos(lp.lam));
-*/
- t = cos(lp.lam);
- xy.x = atan((tan(lp.phi) * P->cosphi + P->sinphi * xy.y) / t);
- if (t < 0.)
- xy.x += PI;
- xy.x *= P->rtk;
- xy.y = P->rok * (P->sinphi * sin(lp.phi) - P->cosphi * cos(lp.phi) * xy.y);
- return (xy);
+ "lonc= alpha= or\n\tlat_1= lat_2= lon_1= lon_2=";
+
+struct pj_opaque {
+ double rok;
+ double rtk;
+ double sinphi;
+ double cosphi;
+ double singam;
+ double cosgam;
+};
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double t;
+
+ xy.y = sin(lp.lam);
+ t = cos(lp.lam);
+ xy.x = atan((tan(lp.phi) * Q->cosphi + Q->sinphi * xy.y) / t);
+ if (t < 0.)
+ xy.x += PI;
+ xy.x *= Q->rtk;
+ xy.y = Q->rok * (Q->sinphi * sin(lp.phi) - Q->cosphi * cos(lp.phi) * xy.y);
+ return xy;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double t, s;
+
+ xy.y /= Q->rok;
+ xy.x /= Q->rtk;
+ t = sqrt(1. - xy.y * xy.y);
+ lp.phi = asin(xy.y * Q->sinphi + t * Q->cosphi * (s = sin(xy.x)));
+ lp.lam = atan2(t * Q->sinphi * s - xy.y * Q->cosphi,
+ t * cos(xy.x));
+ 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;
+}
+
+
+PJ *PROJECTION(ocea) {
+ double phi_0=0.0, phi_1, phi_2, lam_1, lam_2, lonz, alpha;
+
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->rok = P->a / P->k0;
+ Q->rtk = P->a * P->k0;
+ /*If the keyword "alpha" is found in the sentence then use 1point+1azimuth*/
+ if ( pj_param(P->ctx, P->params, "talpha").i) {
+ /*Define Pole of oblique transformation from 1 point & 1 azimuth*/
+ alpha = pj_param(P->ctx, P->params, "ralpha").f;
+ lonz = pj_param(P->ctx, P->params, "rlonc").f;
+ /*Equation 9-8 page 80 (http://pubs.usgs.gov/pp/1395/report.pdf)*/
+ Q->singam = atan(-cos(alpha)/(-sin(phi_0) * sin(alpha))) + lonz;
+ /*Equation 9-7 page 80 (http://pubs.usgs.gov/pp/1395/report.pdf)*/
+ Q->sinphi = asin(cos(phi_0) * sin(alpha));
+ /*If the keyword "alpha" is NOT found in the sentence then use 2points*/
+ } else {
+ /*Define Pole of oblique transformation from 2 points*/
+ phi_1 = pj_param(P->ctx, P->params, "rlat_1").f;
+ phi_2 = pj_param(P->ctx, P->params, "rlat_2").f;
+ lam_1 = pj_param(P->ctx, P->params, "rlon_1").f;
+ lam_2 = pj_param(P->ctx, P->params, "rlon_2").f;
+ /*Equation 9-1 page 80 (http://pubs.usgs.gov/pp/1395/report.pdf)*/
+ Q->singam = atan2(cos(phi_1) * sin(phi_2) * cos(lam_1) -
+ sin(phi_1) * cos(phi_2) * cos(lam_2),
+ sin(phi_1) * cos(phi_2) * sin(lam_2) -
+ cos(phi_1) * sin(phi_2) * sin(lam_1) );
+ /*Equation 9-2 page 80 (http://pubs.usgs.gov/pp/1395/report.pdf)*/
+ Q->sinphi = atan(-cos(Q->singam - lam_1) / tan(phi_1));
+ }
+ P->lam0 = Q->singam + HALFPI;
+ Q->cosphi = cos(Q->sinphi);
+ Q->sinphi = sin(Q->sinphi);
+ Q->cosgam = cos(Q->singam);
+ Q->singam = sin(Q->singam);
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+ P->es = 0.;
+
+ return P;
}
-INVERSE(s_inverse); /* spheroid */
- double t, s;
-
- xy.y /= P->rok;
- xy.x /= P->rtk;
- t = sqrt(1. - xy.y * xy.y);
- lp.phi = asin(xy.y * P->sinphi + t * P->cosphi * (s = sin(xy.x)));
- lp.lam = atan2(t * P->sinphi * s - xy.y * P->cosphi,
- t * cos(xy.x));
- return (lp);
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_ocea_selftest (void) {return 0;}
+#else
+
+int pj_ocea_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=ocea +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ {127964312562778.156, 1429265667691.05786},
+ {129394957619297.641, 1429265667691.06812},
+ {127964312562778.188, -1429265667691.0498},
+ {129394957619297.688, -1429265667691.03955},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 179.999999999860108, 2.79764548403721305e-10},
+ {-179.999999999860108, 2.7976454840372327e-10},
+ { 179.999999999860108, -2.7976454840372327e-10},
+ {-179.999999999860108, -2.79764548403721305e-10},
+ };
+
+ 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(ocea)
- double phi_0=0.0, phi_1, phi_2, lam_1, lam_2, lonz, alpha;
-
- P->rok = P->a / P->k0;
- P->rtk = P->a * P->k0;
- /*If the keyword "alpha" is found in the sentence then use 1point+1azimuth*/
- if ( pj_param(P->ctx, P->params, "talpha").i) {
- /*Define Pole of oblique transformation from 1 point & 1 azimuth*/
- alpha = pj_param(P->ctx, P->params, "ralpha").f;
- lonz = pj_param(P->ctx, P->params, "rlonc").f;
- /*Equation 9-8 page 80 (http://pubs.usgs.gov/pp/1395/report.pdf)*/
- P->singam = atan(-cos(alpha)/(-sin(phi_0) * sin(alpha))) + lonz;
- /*Equation 9-7 page 80 (http://pubs.usgs.gov/pp/1395/report.pdf)*/
- P->sinphi = asin(cos(phi_0) * sin(alpha));
- /*If the keyword "alpha" is NOT found in the sentence then use 2points*/
- } else {
- /*Define Pole of oblique transformation from 2 points*/
- phi_1 = pj_param(P->ctx, P->params, "rlat_1").f;
- phi_2 = pj_param(P->ctx, P->params, "rlat_2").f;
- lam_1 = pj_param(P->ctx, P->params, "rlon_1").f;
- lam_2 = pj_param(P->ctx, P->params, "rlon_2").f;
- /*Equation 9-1 page 80 (http://pubs.usgs.gov/pp/1395/report.pdf)*/
- P->singam = atan2(cos(phi_1) * sin(phi_2) * cos(lam_1) -
- sin(phi_1) * cos(phi_2) * cos(lam_2),
- sin(phi_1) * cos(phi_2) * sin(lam_2) -
- cos(phi_1) * sin(phi_2) * sin(lam_1) );
- /*Equation 9-2 page 80 (http://pubs.usgs.gov/pp/1395/report.pdf)*/
- P->sinphi = atan(-cos(P->singam - lam_1) / tan(phi_1));
- }
- P->lam0 = P->singam + HALFPI;
- P->cosphi = cos(P->sinphi);
- P->sinphi = sin(P->sinphi);
- P->cosgam = cos(P->singam);
- P->singam = sin(P->singam);
- P->inv = s_inverse;
- P->fwd = s_forward;
- P->es = 0.;
-ENDENTRY(P)
+
+
+#endif
diff --git a/src/PJ_oea.c b/src/PJ_oea.c
index b84a7ea6..f29dcfd0 100644
--- a/src/PJ_oea.c
+++ b/src/PJ_oea.c
@@ -1,58 +1,140 @@
-#define PROJ_PARMS__ \
- double theta; \
- double m, n; \
- double two_r_m, two_r_n, rm, rn, hm, hn; \
- double cp0, sp0;
#define PJ_LIB__
#include <projects.h>
+
PROJ_HEAD(oea, "Oblated Equal Area") "\n\tMisc Sph\n\tn= m= theta=";
-FORWARD(s_forward); /* sphere */
+
+struct pj_opaque {
+ double theta;
+ double m, n;
+ double two_r_m, two_r_n, rm, rn, hm, hn;
+ double cp0, sp0;
+};
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
double Az, M, N, cp, sp, cl, shz;
cp = cos(lp.phi);
sp = sin(lp.phi);
cl = cos(lp.lam);
- Az = aatan2(cp * sin(lp.lam), P->cp0 * sp - P->sp0 * cp * cl) + P->theta;
- shz = sin(0.5 * aacos(P->ctx, P->sp0 * sp + P->cp0 * cp * cl));
+ Az = aatan2(cp * sin(lp.lam), Q->cp0 * sp - Q->sp0 * cp * cl) + Q->theta;
+ shz = sin(0.5 * aacos(P->ctx, Q->sp0 * sp + Q->cp0 * cp * cl));
M = aasin(P->ctx, shz * sin(Az));
- N = aasin(P->ctx, shz * cos(Az) * cos(M) / cos(M * P->two_r_m));
- xy.y = P->n * sin(N * P->two_r_n);
- xy.x = P->m * sin(M * P->two_r_m) * cos(N) / cos(N * P->two_r_n);
- return (xy);
+ N = aasin(P->ctx, shz * cos(Az) * cos(M) / cos(M * Q->two_r_m));
+ xy.y = Q->n * sin(N * Q->two_r_n);
+ xy.x = Q->m * sin(M * Q->two_r_m) * cos(N) / cos(N * Q->two_r_n);
+
+ 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 N, M, xp, yp, z, Az, cz, sz, cAz;
- N = P->hn * aasin(P->ctx,xy.y * P->rn);
- M = P->hm * aasin(P->ctx,xy.x * P->rm * cos(N * P->two_r_n) / cos(N));
+ N = Q->hn * aasin(P->ctx,xy.y * Q->rn);
+ M = Q->hm * aasin(P->ctx,xy.x * Q->rm * cos(N * Q->two_r_n) / cos(N));
xp = 2. * sin(M);
- yp = 2. * sin(N) * cos(M * P->two_r_m) / cos(M);
- cAz = cos(Az = aatan2(xp, yp) - P->theta);
+ yp = 2. * sin(N) * cos(M * Q->two_r_m) / cos(M);
+ cAz = cos(Az = aatan2(xp, yp) - Q->theta);
z = 2. * aasin(P->ctx, 0.5 * hypot(xp, yp));
sz = sin(z);
cz = cos(z);
- lp.phi = aasin(P->ctx, P->sp0 * cz + P->cp0 * sz * cAz);
+ lp.phi = aasin(P->ctx, Q->sp0 * cz + Q->cp0 * sz * cAz);
lp.lam = aatan2(sz * sin(Az),
- P->cp0 * cz - P->sp0 * sz * cAz);
- return (lp);
+ Q->cp0 * cz - Q->sp0 * sz * cAz);
+
+ 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;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(oea)
- if (((P->n = pj_param(P->ctx, P->params, "dn").f) <= 0.) ||
- ((P->m = pj_param(P->ctx, P->params, "dm").f) <= 0.))
+
+
+PJ *PROJECTION(oea) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ if (((Q->n = pj_param(P->ctx, P->params, "dn").f) <= 0.) ||
+ ((Q->m = pj_param(P->ctx, P->params, "dm").f) <= 0.))
E_ERROR(-39)
else {
- P->theta = pj_param(P->ctx, P->params, "rtheta").f;
- P->sp0 = sin(P->phi0);
- P->cp0 = cos(P->phi0);
- P->rn = 1./ P->n;
- P->rm = 1./ P->m;
- P->two_r_n = 2. * P->rn;
- P->two_r_m = 2. * P->rm;
- P->hm = 0.5 * P->m;
- P->hn = 0.5 * P->n;
+ Q->theta = pj_param(P->ctx, P->params, "rtheta").f;
+ Q->sp0 = sin(P->phi0);
+ Q->cp0 = cos(P->phi0);
+ Q->rn = 1./ Q->n;
+ Q->rm = 1./ Q->m;
+ Q->two_r_n = 2. * Q->rn;
+ Q->two_r_m = 2. * Q->rm;
+ Q->hm = 0.5 * Q->m;
+ Q->hn = 0.5 * Q->n;
P->fwd = s_forward;
P->inv = s_inverse;
P->es = 0.;
}
-ENDENTRY(P)
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_oea_selftest (void) {return 0;}
+#else
+
+int pj_oea_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=oea +a=6400000 +lat_1=0.5 +lat_2=2 +n=1 +m=2 +theta=3"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 228926.872097864107, 99870.4884300760023},
+ { 217242.584036940476, -123247.885607474513},
+ {-217242.584036940476, 123247.885607474556},
+ {-228926.872097864078, -99870.4884300760168},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0017411857167771369, 0.000987726819566195693},
+ { 0.00183489288577854998, -0.000800312481495174641},
+ {-0.00183489288577854954, 0.000800312481495174966},
+ {-0.00174118571677713712, -0.000987726819566195043},
+ };
+
+ 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_omerc.c b/src/PJ_omerc.c
index 8a9fa0db..2fe41426 100644
--- a/src/PJ_omerc.c
+++ b/src/PJ_omerc.c
@@ -21,93 +21,125 @@
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#define PROJ_PARMS__ \
- double A, B, E, AB, ArB, BrA, rB, singam, cosgam, sinrot, cosrot; \
- double v_pole_n, v_pole_s, u_0; \
- int no_rot;
#define PJ_LIB__
#include <projects.h>
PROJ_HEAD(omerc, "Oblique Mercator")
- "\n\tCyl, Sph&Ell no_rot\n\t"
-"alpha= [gamma=] [no_off] lonc= or\n\t lon_1= lat_1= lon_2= lat_2=";
-#define TOL 1.e-7
-#define EPS 1.e-10
-
-FORWARD(e_forward); /* ellipsoid */
- double Q, S, T, U, V, temp, u, v;
-
- if (fabs(fabs(lp.phi) - HALFPI) > EPS) {
- Q = P->E / pow(pj_tsfn(lp.phi, sin(lp.phi), P->e), P->B);
- temp = 1. / Q;
- S = .5 * (Q - temp);
- T = .5 * (Q + temp);
- V = sin(P->B * lp.lam);
- U = (S * P->singam - V * P->cosgam) / T;
- if (fabs(fabs(U) - 1.0) < EPS)
- F_ERROR;
- v = 0.5 * P->ArB * log((1. - U)/(1. + U));
- temp = cos(P->B * lp.lam);
+ "\n\tCyl, Sph&Ell no_rot\n\t"
+ "alpha= [gamma=] [no_off] lonc= or\n\t lon_1= lat_1= lon_2= lat_2=";
+
+struct pj_opaque {
+ double A, B, E, AB, ArB, BrA, rB, singam, cosgam, sinrot, cosrot;
+ double v_pole_n, v_pole_s, u_0;
+ int no_rot;
+};
+
+#define TOL 1.e-7
+#define EPS 1.e-10
+
+
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double S, T, U, V, W, temp, u, v;
+
+ if (fabs(fabs(lp.phi) - HALFPI) > EPS) {
+ W = Q->E / pow(pj_tsfn(lp.phi, sin(lp.phi), P->e), Q->B);
+ temp = 1. / W;
+ S = .5 * (W - temp);
+ T = .5 * (W + temp);
+ V = sin(Q->B * lp.lam);
+ U = (S * Q->singam - V * Q->cosgam) / T;
+ if (fabs(fabs(U) - 1.0) < EPS)
+ F_ERROR;
+ v = 0.5 * Q->ArB * log((1. - U)/(1. + U));
+ temp = cos(Q->B * lp.lam);
if(fabs(temp) < TOL) {
- u = P->A * lp.lam;
+ u = Q->A * lp.lam;
} else {
- u = P->ArB * atan2((S * P->cosgam + V * P->singam), temp);
+ u = Q->ArB * atan2((S * Q->cosgam + V * Q->singam), temp);
}
- } else {
- v = lp.phi > 0 ? P->v_pole_n : P->v_pole_s;
- u = P->ArB * lp.phi;
- }
- if (P->no_rot) {
- xy.x = u;
- xy.y = v;
- } else {
- u -= P->u_0;
- xy.x = v * P->cosrot + u * P->sinrot;
- xy.y = u * P->cosrot - v * P->sinrot;
- }
- return (xy);
+ } else {
+ v = lp.phi > 0 ? Q->v_pole_n : Q->v_pole_s;
+ u = Q->ArB * lp.phi;
+ }
+ if (Q->no_rot) {
+ xy.x = u;
+ xy.y = v;
+ } else {
+ u -= Q->u_0;
+ xy.x = v * Q->cosrot + u * Q->sinrot;
+ xy.y = u * Q->cosrot - v * Q->sinrot;
+ }
+ 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 u, v, Qp, Sp, Tp, Vp, Up;
+
+ if (Q->no_rot) {
+ v = xy.y;
+ u = xy.x;
+ } else {
+ v = xy.x * Q->cosrot - xy.y * Q->sinrot;
+ u = xy.y * Q->cosrot + xy.x * Q->sinrot + Q->u_0;
+ }
+ Qp = exp(- Q->BrA * v);
+ Sp = .5 * (Qp - 1. / Qp);
+ Tp = .5 * (Qp + 1. / Qp);
+ Vp = sin(Q->BrA * u);
+ Up = (Vp * Q->cosgam + Sp * Q->singam) / Tp;
+ if (fabs(fabs(Up) - 1.) < EPS) {
+ lp.lam = 0.;
+ lp.phi = Up < 0. ? -HALFPI : HALFPI;
+ } else {
+ lp.phi = Q->E / sqrt((1. + Up) / (1. - Up));
+ if ((lp.phi = pj_phi2(P->ctx, pow(lp.phi, 1. / Q->B), P->e)) == HUGE_VAL)
+ I_ERROR;
+ lp.lam = - Q->rB * atan2((Sp * Q->cosgam -
+ Vp * Q->singam), cos(Q->BrA * u));
+ }
+ 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);
}
-INVERSE(e_inverse); /* ellipsoid */
- double u, v, Qp, Sp, Tp, Vp, Up;
-
- if (P->no_rot) {
- v = xy.y;
- u = xy.x;
- } else {
- v = xy.x * P->cosrot - xy.y * P->sinrot;
- u = xy.y * P->cosrot + xy.x * P->sinrot + P->u_0;
- }
- Qp = exp(- P->BrA * v);
- Sp = .5 * (Qp - 1. / Qp);
- Tp = .5 * (Qp + 1. / Qp);
- Vp = sin(P->BrA * u);
- Up = (Vp * P->cosgam + Sp * P->singam) / Tp;
- if (fabs(fabs(Up) - 1.) < EPS) {
- lp.lam = 0.;
- lp.phi = Up < 0. ? -HALFPI : HALFPI;
- } else {
- lp.phi = P->E / sqrt((1. + Up) / (1. - Up));
- if ((lp.phi = pj_phi2(P->ctx, pow(lp.phi, 1. / P->B), P->e)) == HUGE_VAL)
- I_ERROR;
- lp.lam = - P->rB * atan2((Sp * P->cosgam -
- Vp * P->singam), cos(P->BrA * u));
- }
- return (lp);
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(omerc)
- double con, com, cosph0, D, F, H, L, sinph0, p, J, gamma=0,
- gamma0, lamc=0, lam1=0, lam2=0, phi1=0, phi2=0, alpha_c=0;
- int alp, gam, no_off = 0;
- P->no_rot = pj_param(P->ctx, P->params, "tno_rot").i;
+
+PJ *PROJECTION(omerc) {
+ double con, com, cosph0, D, F, H, L, sinph0, p, J, gamma=0,
+ gamma0, lamc=0, lam1=0, lam2=0, phi1=0, phi2=0, alpha_c=0;
+ int alp, gam, no_off = 0;
+
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->no_rot = pj_param(P->ctx, P->params, "tno_rot").i;
if ((alp = pj_param(P->ctx, P->params, "talpha").i) != 0)
- alpha_c = pj_param(P->ctx, P->params, "ralpha").f;
+ alpha_c = pj_param(P->ctx, P->params, "ralpha").f;
if ((gam = pj_param(P->ctx, P->params, "tgamma").i) != 0)
- gamma = pj_param(P->ctx, P->params, "rgamma").f;
- if (alp || gam) {
- lamc = pj_param(P->ctx, P->params, "rlonc").f;
- no_off =
+ gamma = pj_param(P->ctx, P->params, "rgamma").f;
+ if (alp || gam) {
+ lamc = pj_param(P->ctx, P->params, "rlonc").f;
+ no_off =
/* For libproj4 compatability */
pj_param(P->ctx, P->params, "tno_off").i
/* for backward compatibility */
@@ -118,86 +150,133 @@ ENTRY0(omerc)
pj_param(P->ctx, P->params, "sno_uoff");
pj_param(P->ctx, P->params, "sno_off");
}
- } else {
- lam1 = pj_param(P->ctx, P->params, "rlon_1").f;
- phi1 = pj_param(P->ctx, P->params, "rlat_1").f;
- lam2 = pj_param(P->ctx, P->params, "rlon_2").f;
- phi2 = pj_param(P->ctx, P->params, "rlat_2").f;
- if (fabs(phi1 - phi2) <= TOL ||
- (con = fabs(phi1)) <= TOL ||
- fabs(con - HALFPI) <= TOL ||
- fabs(fabs(P->phi0) - HALFPI) <= TOL ||
- fabs(fabs(phi2) - HALFPI) <= TOL) E_ERROR(-33);
- }
- com = sqrt(P->one_es);
- if (fabs(P->phi0) > EPS) {
- sinph0 = sin(P->phi0);
- cosph0 = cos(P->phi0);
- con = 1. - P->es * sinph0 * sinph0;
- P->B = cosph0 * cosph0;
- P->B = sqrt(1. + P->es * P->B * P->B / P->one_es);
- P->A = P->B * P->k0 * com / con;
- D = P->B * com / (cosph0 * sqrt(con));
- if ((F = D * D - 1.) <= 0.)
- F = 0.;
- else {
- F = sqrt(F);
- if (P->phi0 < 0.)
- F = -F;
- }
- P->E = F += D;
- P->E *= pow(pj_tsfn(P->phi0, sinph0, P->e), P->B);
- } else {
- P->B = 1. / com;
- P->A = P->k0;
- P->E = D = F = 1.;
- }
- if (alp || gam) {
- if (alp) {
- gamma0 = asin(sin(alpha_c) / D);
- if (!gam)
- gamma = alpha_c;
- } else
- alpha_c = asin(D*sin(gamma0 = gamma));
- if ((con = fabs(alpha_c)) <= TOL ||
- fabs(con - PI) <= TOL ||
- fabs(fabs(P->phi0) - HALFPI) <= TOL)
- E_ERROR(-32);
- P->lam0 = lamc - asin(.5 * (F - 1. / F) *
- tan(gamma0)) / P->B;
- } else {
- H = pow(pj_tsfn(phi1, sin(phi1), P->e), P->B);
- L = pow(pj_tsfn(phi2, sin(phi2), P->e), P->B);
- F = P->E / H;
- p = (L - H) / (L + H);
- J = P->E * P->E;
- J = (J - L * H) / (J + L * H);
- if ((con = lam1 - lam2) < -PI)
- lam2 -= TWOPI;
- else if (con > PI)
- lam2 += TWOPI;
- P->lam0 = adjlon(.5 * (lam1 + lam2) - atan(
- J * tan(.5 * P->B * (lam1 - lam2)) / p) / P->B);
- gamma0 = atan(2. * sin(P->B * adjlon(lam1 - P->lam0)) /
- (F - 1. / F));
- gamma = alpha_c = asin(D * sin(gamma0));
- }
- P->singam = sin(gamma0);
- P->cosgam = cos(gamma0);
- P->sinrot = sin(gamma);
- P->cosrot = cos(gamma);
- P->BrA = 1. / (P->ArB = P->A * (P->rB = 1. / P->B));
- P->AB = P->A * P->B;
- if (no_off)
- P->u_0 = 0;
- else {
- P->u_0 = fabs(P->ArB * atan2(sqrt(D * D - 1.), cos(alpha_c)));
- if (P->phi0 < 0.)
- P->u_0 = - P->u_0;
- }
- F = 0.5 * gamma0;
- P->v_pole_n = P->ArB * log(tan(FORTPI - F));
- P->v_pole_s = P->ArB * log(tan(FORTPI + F));
- P->inv = e_inverse;
- P->fwd = e_forward;
-ENDENTRY(P)
+ } else {
+ lam1 = pj_param(P->ctx, P->params, "rlon_1").f;
+ phi1 = pj_param(P->ctx, P->params, "rlat_1").f;
+ lam2 = pj_param(P->ctx, P->params, "rlon_2").f;
+ phi2 = pj_param(P->ctx, P->params, "rlat_2").f;
+ if (fabs(phi1 - phi2) <= TOL ||
+ (con = fabs(phi1)) <= TOL ||
+ fabs(con - HALFPI) <= TOL ||
+ fabs(fabs(P->phi0) - HALFPI) <= TOL ||
+ fabs(fabs(phi2) - HALFPI) <= TOL) E_ERROR(-33);
+ }
+ com = sqrt(P->one_es);
+ if (fabs(P->phi0) > EPS) {
+ sinph0 = sin(P->phi0);
+ cosph0 = cos(P->phi0);
+ con = 1. - P->es * sinph0 * sinph0;
+ Q->B = cosph0 * cosph0;
+ Q->B = sqrt(1. + P->es * Q->B * Q->B / P->one_es);
+ Q->A = Q->B * P->k0 * com / con;
+ D = Q->B * com / (cosph0 * sqrt(con));
+ if ((F = D * D - 1.) <= 0.)
+ F = 0.;
+ else {
+ F = sqrt(F);
+ if (P->phi0 < 0.)
+ F = -F;
+ }
+ Q->E = F += D;
+ Q->E *= pow(pj_tsfn(P->phi0, sinph0, P->e), Q->B);
+ } else {
+ Q->B = 1. / com;
+ Q->A = P->k0;
+ Q->E = D = F = 1.;
+ }
+ if (alp || gam) {
+ if (alp) {
+ gamma0 = asin(sin(alpha_c) / D);
+ if (!gam)
+ gamma = alpha_c;
+ } else
+ alpha_c = asin(D*sin(gamma0 = gamma));
+ if ((con = fabs(alpha_c)) <= TOL ||
+ fabs(con - PI) <= TOL ||
+ fabs(fabs(P->phi0) - HALFPI) <= TOL)
+ E_ERROR(-32);
+ P->lam0 = lamc - asin(.5 * (F - 1. / F) *
+ tan(gamma0)) / Q->B;
+ } else {
+ H = pow(pj_tsfn(phi1, sin(phi1), P->e), Q->B);
+ L = pow(pj_tsfn(phi2, sin(phi2), P->e), Q->B);
+ F = Q->E / H;
+ p = (L - H) / (L + H);
+ J = Q->E * Q->E;
+ J = (J - L * H) / (J + L * H);
+ if ((con = lam1 - lam2) < -PI)
+ lam2 -= TWOPI;
+ else if (con > PI)
+ lam2 += TWOPI;
+ P->lam0 = adjlon(.5 * (lam1 + lam2) - atan(
+ J * tan(.5 * Q->B * (lam1 - lam2)) / p) / Q->B);
+ gamma0 = atan(2. * sin(Q->B * adjlon(lam1 - P->lam0)) /
+ (F - 1. / F));
+ gamma = alpha_c = asin(D * sin(gamma0));
+ }
+ Q->singam = sin(gamma0);
+ Q->cosgam = cos(gamma0);
+ Q->sinrot = sin(gamma);
+ Q->cosrot = cos(gamma);
+ Q->BrA = 1. / (Q->ArB = Q->A * (Q->rB = 1. / Q->B));
+ Q->AB = Q->A * Q->B;
+ if (no_off)
+ Q->u_0 = 0;
+ else {
+ Q->u_0 = fabs(Q->ArB * atan2(sqrt(D * D - 1.), cos(alpha_c)));
+ if (P->phi0 < 0.)
+ Q->u_0 = - Q->u_0;
+ }
+ F = 0.5 * gamma0;
+ Q->v_pole_n = Q->ArB * log(tan(FORTPI - F));
+ Q->v_pole_s = Q->ArB * log(tan(FORTPI + F));
+ P->inv = e_inverse;
+ P->fwd = e_forward;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_omerc_selftest (void) {return 0;}
+#else
+
+int pj_omerc_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=omerc +ellps=GRS80 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ { 222650.796885261341, 110642.229314983808},
+ { 222650.796885261341, -110642.229314983808},
+ {-222650.796885261545, 110642.229314983808},
+ {-222650.796885261545, -110642.229314983808},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ { 0.00179663056816996357, 0.000904369474808157338},
+ { 0.00179663056816996357, -0.000904369474820879583},
+ {-0.0017966305681604536, 0.000904369474808157338},
+ {-0.0017966305681604536, -0.000904369474820879583},
+ };
+
+ return pj_generic_selftest (e_args, 0, tolerance_xy, tolerance_lp, 4, 4, fwd_in, e_fwd_expect, 0, inv_in, e_inv_expect, 0);
+}
+
+
+#endif
diff --git a/src/PJ_ortho.c b/src/PJ_ortho.c
index 202b0176..14aeacc3 100644
--- a/src/PJ_ortho.c
+++ b/src/PJ_ortho.c
@@ -1,29 +1,37 @@
-#define PROJ_PARMS__ \
- double sinph0; \
- double cosph0; \
- int mode;
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(ortho, "Orthographic") "\n\tAzi, Sph.";
+
+struct pj_opaque {
+ double sinph0;
+ double cosph0;
+ int mode;
+};
+
#define EPS10 1.e-10
#define N_POLE 0
#define S_POLE 1
#define EQUIT 2
#define OBLIQ 3
-FORWARD(s_forward); /* spheroid */
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
double coslam, cosphi, sinphi;
cosphi = cos(lp.phi);
coslam = cos(lp.lam);
- switch (P->mode) {
+ switch (Q->mode) {
case EQUIT:
if (cosphi * coslam < - EPS10) F_ERROR;
xy.y = sin(lp.phi);
break;
case OBLIQ:
- if (P->sinph0 * (sinphi = sin(lp.phi)) +
- P->cosph0 * cosphi * coslam < - EPS10) F_ERROR;
- xy.y = P->cosph0 * sinphi - P->sinph0 * cosphi * coslam;
+ if (Q->sinph0 * (sinphi = sin(lp.phi)) +
+ Q->cosph0 * cosphi * coslam < - EPS10) F_ERROR;
+ xy.y = Q->cosph0 * sinphi - Q->sinph0 * cosphi * coslam;
break;
case N_POLE:
coslam = - coslam;
@@ -33,10 +41,13 @@ FORWARD(s_forward); /* spheroid */
break;
}
xy.x = cosphi * sin(lp.lam);
- return (xy);
+ return xy;
}
-INVERSE(s_inverse); /* spheroid */
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
double rh, cosc, sinc;
if ((sinc = (rh = hypot(xy.x, xy.y))) > 1.) {
@@ -48,7 +59,7 @@ INVERSE(s_inverse); /* spheroid */
lp.phi = P->phi0;
lp.lam = 0.0;
} else {
- switch (P->mode) {
+ switch (Q->mode) {
case N_POLE:
xy.y = -xy.y;
lp.phi = acos(sinc);
@@ -62,9 +73,9 @@ INVERSE(s_inverse); /* spheroid */
xy.y = cosc * rh;
goto sinchk;
case OBLIQ:
- lp.phi = cosc * P->sinph0 + xy.y * sinc * P->cosph0 /rh;
- xy.y = (cosc - P->sinph0 * lp.phi) * rh;
- xy.x *= sinc * P->cosph0;
+ lp.phi = cosc * Q->sinph0 + xy.y * sinc * Q->cosph0 /rh;
+ xy.y = (cosc - Q->sinph0 * lp.phi) * rh;
+ xy.x *= sinc * Q->cosph0;
sinchk:
if (fabs(lp.phi) >= 1.)
lp.phi = lp.phi < 0. ? -HALFPI : HALFPI;
@@ -72,24 +83,92 @@ INVERSE(s_inverse); /* spheroid */
lp.phi = asin(lp.phi);
break;
}
- lp.lam = (xy.y == 0. && (P->mode == OBLIQ || P->mode == EQUIT))
+ lp.lam = (xy.y == 0. && (Q->mode == OBLIQ || Q->mode == EQUIT))
? (xy.x == 0. ? 0. : xy.x < 0. ? -HALFPI : HALFPI)
: atan2(xy.x, xy.y);
}
- return (lp);
+ return lp;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(ortho)
+
+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(ortho) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
if (fabs(fabs(P->phi0) - HALFPI) <= EPS10)
- P->mode = P->phi0 < 0. ? S_POLE : N_POLE;
+ Q->mode = P->phi0 < 0. ? S_POLE : N_POLE;
else if (fabs(P->phi0) > EPS10) {
- P->mode = OBLIQ;
- P->sinph0 = sin(P->phi0);
- P->cosph0 = cos(P->phi0);
+ Q->mode = OBLIQ;
+ Q->sinph0 = sin(P->phi0);
+ Q->cosph0 = cos(P->phi0);
} else
- P->mode = EQUIT;
+ Q->mode = EQUIT;
P->inv = s_inverse;
P->fwd = s_forward;
P->es = 0.;
-ENDENTRY(P)
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_ortho_selftest (void) {return 0;}
+#else
+
+int pj_ortho_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=ortho +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 223322.76057672748, 111695.401198614476},
+ { 223322.76057672748, -111695.401198614476},
+ {-223322.76057672748, 111695.401198614476},
+ {-223322.76057672748, -111695.401198614476},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0017904931102938101, 0.000895246554928338998},
+ { 0.0017904931102938101, -0.000895246554928338998},
+ {-0.0017904931102938101, 0.000895246554928338998},
+ {-0.0017904931102938101, -0.000895246554928338998},
+ };
+
+ 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_patterson.c b/src/PJ_patterson.c
index 6fa10c28..f3a18423 100644
--- a/src/PJ_patterson.c
+++ b/src/PJ_patterson.c
@@ -1,92 +1,167 @@
-/*
- * Copyright (c) 2014 Bojan Savric
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * The Patterson Cylindrical projection was designed by Tom Patterson, US National
- * Park Service, in 2014, using Flex Projector. The polynomial equations for the
- * projection were developed by Bojan Savric, Oregon State University, in
- * collaboration with Tom Patterson and Bernhard Jenny, Oregon State University.
- *
- * Java reference algorithm implemented by Bojan Savric in Java Map Projection
- * Library (a Java port of PROJ.4) in the file PattersonProjection.java.
- *
- * References:
- * Java Map Projection Library
- * https://github.com/OSUCartography/JMapProjLib
- *
- * Patterson Cylindrical Projection
- * http://shadedrelief.com/patterson/
- *
- * Patterson, T., Savric, B., and Jenny, B. (2015). Cartographic Perspectives
- * (No.78). Describes the projection design and characteristics, and
- * developing the equations. doi:10.14714/CP78.1270
- * http://dx.doi.org/10.14714/CP78.1270
- *
- * Port to PROJ.4 by Micah Cochran, 26 March 2016
- */
-
-#define PJ_LIB__
-# include <projects.h>
-PROJ_HEAD(patterson, "Patterson Cylindrical") "\n\tCyl.";
-#define K1 1.0148
-#define K2 0.23185
-#define K3 -0.14499
-#define K4 0.02406
-#define C1 K1
-#define C2 (5.0 * K2)
-#define C3 (7.0 * K3)
-#define C4 (9.0 * K4)
-#define EPS11 1.0e-11
-#define MAX_Y 1.790857183
-
-FORWARD(s_forward); /* spheroid */
- double phi2;
- (void) P;
- phi2 = lp.phi * lp.phi;
- xy.x = lp.lam;
- xy.y = lp.phi * (K1 + phi2 * phi2 * (K2 + phi2 * (K3 + K4 * phi2)));
- return (xy);
-}
-INVERSE(s_inverse); /* spheroid */
- double yc, tol, y2, f, fder;
- (void) P;
- yc = xy.y;
-
- /* make sure y is inside valid range */
- if (xy.y > MAX_Y) {
- xy.y = MAX_Y;
- } else if (xy.y < -MAX_Y) {
- xy.y = -MAX_Y;
- }
-
- for (;;) { /* Newton-Raphson */
- y2 = yc * yc;
- f = (yc * (K1 + y2 * y2 * (K2 + y2 * (K3 + K4 * y2)))) - xy.y;
- fder = C1 + y2 * y2 * (C2 + y2 * (C3 + C4 * y2));
- yc -= tol = f / fder;
- if (fabs(tol) < EPS11) {
- break;
- }
- }
- lp.phi = yc;
-
- /* longitude */
- lp.lam = xy.x;
-
- return (lp);
-}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(patterson) P->es = 0.; P->inv = s_inverse; P->fwd = s_forward; ENDENTRY(P)
+/*
+ * Copyright (c) 2014 Bojan Savric
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * The Patterson Cylindrical projection was designed by Tom Patterson, US National
+ * Park Service, in 2014, using Flex Projector. The polynomial equations for the
+ * projection were developed by Bojan Savric, Oregon State University, in
+ * collaboration with Tom Patterson and Bernhard Jenny, Oregon State University.
+ *
+ * Java reference algorithm implemented by Bojan Savric in Java Map Projection
+ * Library (a Java port of PROJ.4) in the file PattersonProjection.java.
+ *
+ * References:
+ * Java Map Projection Library
+ * https://github.com/OSUCartography/JMapProjLib
+ *
+ * Patterson Cylindrical Projection
+ * http://shadedrelief.com/patterson/
+ *
+ * Patterson, T., Savric, B., and Jenny, B. (2015). Cartographic Perspectives
+ * (No.78). Describes the projection design and characteristics, and
+ * developing the equations. doi:10.14714/CP78.1270
+ * http://dx.doi.org/10.14714/CP78.1270
+ *
+ * Port to PROJ.4 by Micah Cochran, 26 March 2016
+ */
+
+#define PJ_LIB__
+#include <projects.h>
+
+PROJ_HEAD(patterson, "Patterson Cylindrical") "\n\tCyl.";
+
+#define K1 1.0148
+#define K2 0.23185
+#define K3 -0.14499
+#define K4 0.02406
+#define C1 K1
+#define C2 (5.0 * K2)
+#define C3 (7.0 * K3)
+#define C4 (9.0 * K4)
+#define EPS11 1.0e-11
+#define MAX_Y 1.790857183
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ double phi2;
+ (void) P;
+
+ phi2 = lp.phi * lp.phi;
+ xy.x = lp.lam;
+ xy.y = lp.phi * (K1 + phi2 * phi2 * (K2 + phi2 * (K3 + K4 * phi2)));
+
+ return xy;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ double yc, tol, y2, f, fder;
+ (void) P;
+
+ yc = xy.y;
+
+ /* make sure y is inside valid range */
+ if (xy.y > MAX_Y) {
+ xy.y = MAX_Y;
+ } else if (xy.y < -MAX_Y) {
+ xy.y = -MAX_Y;
+ }
+
+ for (;;) { /* Newton-Raphson */
+ y2 = yc * yc;
+ f = (yc * (K1 + y2 * y2 * (K2 + y2 * (K3 + K4 * y2)))) - xy.y;
+ fder = C1 + y2 * y2 * (C2 + y2 * (C3 + C4 * y2));
+ yc -= tol = f / fder;
+ if (fabs(tol) < EPS11) {
+ break;
+ }
+ }
+ lp.phi = yc;
+
+ /* longitude */
+ lp.lam = xy.x;
+
+ return lp;
+}
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+
+ return pj_dealloc(P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(patterson) {
+ P->es = 0.;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_patterson_selftest (void) {return 0;}
+#else
+
+int pj_patterson_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=patterson +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ {223402.144255274179, 113354.250397779804},
+ {223402.144255274179, -113354.250397779804},
+ {-223402.144255274179, 113354.250397779804},
+ {-223402.144255274179, -113354.250397779804},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ {0.00179049310978382265, 0.000882190140807953657},
+ {0.00179049310978382265, -0.000882190140807953657},
+ {-0.00179049310978382265, 0.000882190140807953657},
+ {-0.00179049310978382265, -0.000882190140807953657},
+ };
+
+ 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_poly.c b/src/PJ_poly.c
index ef5b8905..50c0ee5f 100644
--- a/src/PJ_poly.c
+++ b/src/PJ_poly.c
@@ -1,42 +1,67 @@
-#define PROJ_PARMS__ \
- double ml0; \
- double *en;
#define PJ_LIB__
#include <projects.h>
+
PROJ_HEAD(poly, "Polyconic (American)")
"\n\tConic, Sph&Ell";
+
+struct pj_opaque {
+ double ml0; \
+ double *en;
+};
+
#define TOL 1e-10
#define CONV 1e-10
#define N_ITER 10
#define I_ITER 20
#define ITOL 1.e-12
-FORWARD(e_forward); /* ellipsoid */
+
+
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
double ms, sp, cp;
- if (fabs(lp.phi) <= TOL) { xy.x = lp.lam; xy.y = -P->ml0; }
- else {
+ if (fabs(lp.phi) <= TOL) {
+ xy.x = lp.lam;
+ xy.y = -Q->ml0;
+ } else {
sp = sin(lp.phi);
ms = fabs(cp = cos(lp.phi)) > TOL ? pj_msfn(sp, cp, P->es) / sp : 0.;
xy.x = ms * sin(lp.lam *= sp);
- xy.y = (pj_mlfn(lp.phi, sp, cp, P->en) - P->ml0) + ms * (1. - cos(lp.lam));
+ xy.y = (pj_mlfn(lp.phi, sp, cp, Q->en) - Q->ml0) + ms * (1. - cos(lp.lam));
}
- return (xy);
+
+ return xy;
}
-FORWARD(s_forward); /* spheroid */
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
double cot, E;
- if (fabs(lp.phi) <= TOL) { xy.x = lp.lam; xy.y = P->ml0; }
- else {
+ if (fabs(lp.phi) <= TOL) {
+ xy.x = lp.lam;
+ xy.y = Q->ml0;
+ } else {
cot = 1. / tan(lp.phi);
xy.x = sin(E = lp.lam * sin(lp.phi)) * cot;
xy.y = lp.phi - P->phi0 + cot * (1. - cos(E));
}
- return (xy);
+
+ return xy;
}
-INVERSE(e_inverse); /* ellipsoid */
- xy.y += P->ml0;
- if (fabs(xy.y) <= TOL) { lp.lam = xy.x; lp.phi = 0.; }
- else {
+
+
+static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+
+ xy.y += Q->ml0;
+ if (fabs(xy.y) <= TOL) {
+ lp.lam = xy.x;
+ lp.phi = 0.;
+ } else {
double r, c, sp, cp, s2ph, ml, mlb, mlp, dPhi;
int i;
@@ -47,7 +72,7 @@ INVERSE(e_inverse); /* ellipsoid */
if (fabs(cp) < ITOL)
I_ERROR;
c = sp * (mlp = sqrt(1. - P->es * sp * sp)) / cp;
- ml = pj_mlfn(lp.phi, sp, cp, P->en);
+ ml = pj_mlfn(lp.phi, sp, cp, Q->en);
mlb = ml * ml + r;
mlp = P->one_es / (mlp * mlp * mlp);
lp.phi += ( dPhi =
@@ -62,14 +87,20 @@ INVERSE(e_inverse); /* ellipsoid */
c = sin(lp.phi);
lp.lam = asin(xy.x * tan(lp.phi) * sqrt(1. - P->es * c * c)) / sin(lp.phi);
}
- return (lp);
+
+ return lp;
}
-INVERSE(s_inverse); /* spheroid */
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
double B, dphi, tp;
int i;
- if (fabs(xy.y = P->phi0 + xy.y) <= TOL) { lp.lam = xy.x; lp.phi = 0.; }
- else {
+ if (fabs(xy.y = P->phi0 + xy.y) <= TOL) {
+ lp.lam = xy.x;
+ lp.phi = 0.;
+ } else {
lp.phi = xy.y;
B = xy.x * xy.x + xy.y * xy.y;
i = N_ITER;
@@ -82,18 +113,105 @@ INVERSE(s_inverse); /* spheroid */
if (! i) I_ERROR;
lp.lam = asin(xy.x * tan(lp.phi)) / sin(lp.phi);
}
- return (lp);
+
+ return lp;
}
-FREEUP; if (P) { if (P->en) pj_dalloc(P->en); pj_dalloc(P); } }
-ENTRY1(poly, en)
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+ if (0==P->opaque)
+ return pj_dealloc (P);
+ if (P->opaque->en)
+ pj_dealloc (P->opaque->en);
+ pj_dealloc (P->opaque);
+
+ return pj_dealloc(P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(poly) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
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);
+ if (!(Q->en = pj_enfn(P->es))) E_ERROR_0;
+ Q->ml0 = pj_mlfn(P->phi0, sin(P->phi0), cos(P->phi0), Q->en);
P->inv = e_inverse;
P->fwd = e_forward;
} else {
- P->ml0 = -P->phi0;
+ Q->ml0 = -P->phi0;
P->inv = s_inverse;
P->fwd = s_forward;
}
-ENDENTRY(P)
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_poly_selftest (void) {return 0;}
+#else
+
+int pj_poly_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=poly +ellps=GRS80 +lat_1=0.5 +lat_2=2"};
+ char s_args[] = {"+proj=poly +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ { 222605.285770237475, 110642.194561440483},
+ { 222605.285770237475, -110642.194561440483},
+ {-222605.285770237475, 110642.194561440483},
+ {-222605.285770237475, -110642.194561440483},
+ };
+
+ XY s_fwd_expect[] = {
+ { 223368.105210218986, 111769.110491224754},
+ { 223368.105210218986, -111769.110491224754},
+ {-223368.105210218986, 111769.110491224754},
+ {-223368.105210218986, -111769.110491224754},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ { 0.00179663056846135222, 0.000904369476631838518},
+ { 0.00179663056846135222, -0.000904369476631838518},
+ {-0.00179663056846135222, 0.000904369476631838518},
+ {-0.00179663056846135222, -0.000904369476631838518},
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0017904931100023887, 0.000895246554454779222},
+ { 0.0017904931100023887, -0.000895246554454779222},
+ {-0.0017904931100023887, 0.000895246554454779222},
+ {-0.0017904931100023887, -0.000895246554454779222},
+ };
+
+ 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_putp2.c b/src/PJ_putp2.c
index d6fcaea0..4c5a417a 100644
--- a/src/PJ_putp2.c
+++ b/src/PJ_putp2.c
@@ -1,13 +1,18 @@
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(putp2, "Putnins P2") "\n\tPCyl., Sph.";
+
#define C_x 1.89490
#define C_y 1.71848
#define C_p 0.6141848493043784
#define EPS 1e-10
#define NITER 10
#define PI_DIV_3 1.0471975511965977
-FORWARD(s_forward); /* spheroid */
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
double p, c, s, V;
int i;
(void) P;
@@ -27,15 +32,84 @@ FORWARD(s_forward); /* spheroid */
lp.phi = lp.phi < 0 ? - PI_DIV_3 : PI_DIV_3;
xy.x = C_x * lp.lam * (cos(lp.phi) - 0.5);
xy.y = C_y * sin(lp.phi);
- return (xy);
+
+ return xy;
}
-INVERSE(s_inverse); /* spheroid */
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
double c;
lp.phi = aasin(P->ctx,xy.y / C_y);
lp.lam = xy.x / (C_x * ((c = cos(lp.phi)) - 0.5));
lp.phi = aasin(P->ctx,(lp.phi + sin(lp.phi) * (c - 1.)) / C_p);
- return (lp);
+
+ return lp;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(putp2) P->es = 0.; P->inv = s_inverse; P->fwd = s_forward; ENDENTRY(P)
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+
+ return pj_dealloc(P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(putp2) {
+ P->es = 0.;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_putp2_selftest (void) {return 0;}
+#else
+
+int pj_putp2_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=putp2 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 211638.039634339279, 117895.033043379764},
+ { 211638.039634339279, -117895.033043379764},
+ {-211638.039634339279, 117895.033043379764},
+ {-211638.039634339279, -117895.033043379764},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.00188980221640386672, 0.000848201580276863377},
+ { 0.00188980221640386672, -0.000848201580276863377},
+ {-0.00188980221640386672, 0.000848201580276863377},
+ {-0.00188980221640386672, -0.000848201580276863377},
+ };
+
+ 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_putp3.c b/src/PJ_putp3.c
index 298ce55d..26fc0a90 100644
--- a/src/PJ_putp3.c
+++ b/src/PJ_putp3.c
@@ -1,26 +1,171 @@
-#define PROJ_PARMS__ \
- double A;
#define PJ_LIB__
-# include <projects.h>
+#include <projects.h>
+
+struct pj_opaque {
+ double A;
+};
+
PROJ_HEAD(putp3, "Putnins P3") "\n\tPCyl., Sph.";
PROJ_HEAD(putp3p, "Putnins P3'") "\n\tPCyl., Sph.";
-#define C 0.79788456
-#define RPISQ 0.1013211836
-FORWARD(s_forward); /* spheroid */
- xy.x = C * lp.lam * (1. - P->A * lp.phi * lp.phi);
- xy.y = C * lp.phi;
- return (xy);
-}
-INVERSE(s_inverse); /* spheroid */
- lp.phi = xy.y / C;
- lp.lam = xy.x / (C * (1. - P->A * lp.phi * lp.phi));
- return (lp);
-}
-FREEUP; if (P) pj_dalloc(P); }
- static PJ *
-setup(PJ *P) {
- P->es = 0.; P->inv = s_inverse; P->fwd = s_forward;
- return P;
-}
-ENTRY0(putp3) P->A = 4. * RPISQ; ENDENTRY(setup(P))
-ENTRY0(putp3p) P->A = 2. * RPISQ; ENDENTRY(setup(P))
+
+#define C 0.79788456
+#define RPISQ 0.1013211836
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+
+ xy.x = C * lp.lam * (1. - P->opaque->A * lp.phi * lp.phi);
+ xy.y = C * lp.phi;
+
+ return xy;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+
+ lp.phi = xy.y / C;
+ lp.lam = xy.x / (C * (1. - P->opaque->A * lp.phi * lp.phi));
+
+ 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;
+}
+
+
+PJ *PROJECTION(putp3) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->A = 4. * RPISQ;
+
+ P->es = 0.;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+PJ *PROJECTION(putp3p) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->A = 2. * RPISQ;
+
+ P->es = 0.;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_putp3_selftest (void) {return 0;}
+#else
+
+int pj_putp3_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=putp3 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 178227.115507793525, 89124.5607860879827},
+ { 178227.115507793525, -89124.5607860879827},
+ {-178227.115507793525, 89124.5607860879827},
+ {-178227.115507793525, -89124.5607860879827},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.00224405032986489889, 0.00112202516475805899},
+ { 0.00224405032986489889, -0.00112202516475805899},
+ {-0.00224405032986489889, 0.00112202516475805899},
+ {-0.00224405032986489889, -0.00112202516475805899},
+ };
+
+ 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_putp3p_selftest (void) {return 0;}
+#else
+
+int pj_putp3p_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=putp3p +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 178238.118539984745, 89124.5607860879827},
+ { 178238.118539984745, -89124.5607860879827},
+ {-178238.118539984745, 89124.5607860879827},
+ {-178238.118539984745, -89124.5607860879827},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.00224405032969050844, 0.00112202516475805899},
+ { 0.00224405032969050844, -0.00112202516475805899},
+ {-0.00224405032969050844, 0.00112202516475805899},
+ {-0.00224405032969050844, -0.00112202516475805899},
+
+ };
+
+ 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_putp4p.c b/src/PJ_putp4p.c
index 32036bbe..9264d896 100644
--- a/src/PJ_putp4p.c
+++ b/src/PJ_putp4p.c
@@ -1,29 +1,177 @@
-#define PROJ_PARMS__ \
- double C_x, C_y;
#define PJ_LIB__
-# include <projects.h>
+#include <projects.h>
+
+struct pj_opaque {
+ double C_x, C_y;
+};
+
PROJ_HEAD(putp4p, "Putnins P4'") "\n\tPCyl., Sph.";
PROJ_HEAD(weren, "Werenskiold I") "\n\tPCyl., Sph.";
-FORWARD(s_forward); /* spheroid */
- lp.phi = aasin(P->ctx,0.883883476 * sin(lp.phi));
- xy.x = P->C_x * lp.lam * cos(lp.phi);
- xy.x /= cos(lp.phi *= 0.333333333333333);
- xy.y = P->C_y * sin(lp.phi);
- return (xy);
-}
-INVERSE(s_inverse); /* spheroid */
- lp.phi = aasin(P->ctx,xy.y / P->C_y);
- lp.lam = xy.x * cos(lp.phi) / P->C_x;
- lp.phi *= 3.;
- lp.lam /= cos(lp.phi);
- lp.phi = aasin(P->ctx,1.13137085 * sin(lp.phi));
- return (lp);
-}
-FREEUP; if (P) pj_dalloc(P); }
- static PJ *
-setup(PJ *P) {
- P->es = 0.; P->inv = s_inverse; P->fwd = s_forward;
- return P;
-}
-ENTRY0(putp4p) P->C_x = 0.874038744; P->C_y = 3.883251825; ENDENTRY(setup(P))
-ENTRY0(weren) P->C_x = 1.; P->C_y = 4.442882938; ENDENTRY(setup(P))
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+
+ lp.phi = aasin(P->ctx,0.883883476 * sin(lp.phi));
+ xy.x = Q->C_x * lp.lam * cos(lp.phi);
+ xy.x /= cos(lp.phi *= 0.333333333333333);
+ xy.y = Q->C_y * sin(lp.phi);
+
+ return xy;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+
+ lp.phi = aasin(P->ctx,xy.y / Q->C_y);
+ lp.lam = xy.x * cos(lp.phi) / Q->C_x;
+ lp.phi *= 3.;
+ lp.lam /= cos(lp.phi);
+ lp.phi = aasin(P->ctx,1.13137085 * sin(lp.phi));
+
+ 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;
+}
+
+
+PJ *PROJECTION(putp4p) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->C_x = 0.874038744;
+ Q->C_y = 3.883251825;
+
+ P->es = 0.;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+
+PJ *PROJECTION(weren) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->C_x = 1.;
+ Q->C_y = 4.442882938;
+
+ P->es = 0.;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_putp4p_selftest (void) {return 0;}
+#else
+
+int pj_putp4p_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=putp4p +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 195241.47734938623, 127796.782307926231},
+ { 195241.47734938623, -127796.782307926231},
+ {-195241.47734938623, 127796.782307926231},
+ {-195241.47734938623, -127796.782307926231},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.00204852830860296001, 0.000782480174932193733},
+ { 0.00204852830860296001, -0.000782480174932193733},
+ {-0.00204852830860296001, 0.000782480174932193733},
+ {-0.00204852830860296001, -0.000782480174932193733},
+ };
+
+ 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_weren_selftest (void) {return 0;}
+#else
+
+int pj_weren_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=weren +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 223378.515757633519, 146214.093042288267},
+ { 223378.515757633519, -146214.093042288267},
+ {-223378.515757633519, 146214.093042288267},
+ {-223378.515757633519, -146214.093042288267},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.00179049310987240413, 0.000683917989676492265},
+ { 0.00179049310987240413, -0.000683917989676492265},
+ {-0.00179049310987240413, 0.000683917989676492265},
+ {-0.00179049310987240413, -0.000683917989676492265},
+ };
+
+ 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_putp5.c b/src/PJ_putp5.c
index 8d3c59a0..d4e59ee8 100644
--- a/src/PJ_putp5.c
+++ b/src/PJ_putp5.c
@@ -1,26 +1,172 @@
-#define PROJ_PARMS__ \
- double A, B;
#define PJ_LIB__
-# include <projects.h>
+#include <projects.h>
+
+struct pj_opaque {
+ double A, B;
+};
+
PROJ_HEAD(putp5, "Putnins P5") "\n\tPCyl., Sph.";
PROJ_HEAD(putp5p, "Putnins P5'") "\n\tPCyl., Sph.";
-#define C 1.01346
-#define D 1.2158542
-FORWARD(s_forward); /* spheroid */
- xy.x = C * lp.lam * (P->A - P->B * sqrt(1. + D * lp.phi * lp.phi));
- xy.y = C * lp.phi;
- return (xy);
-}
-INVERSE(s_inverse); /* spheroid */
- lp.phi = xy.y / C;
- lp.lam = xy.x / (C * (P->A - P->B * sqrt(1. + D * lp.phi * lp.phi)));
- return (lp);
-}
-FREEUP; if (P) pj_dalloc(P); }
- static PJ *
-setup(PJ *P) {
- P->es = 0.; P->inv = s_inverse; P->fwd = s_forward;
- return P;
-}
-ENTRY0(putp5) P->A = 2.; P->B = 1.; ENDENTRY(setup(P))
-ENTRY0(putp5p) P->A = 1.5; P->B = 0.5; ENDENTRY(setup(P))
+
+#define C 1.01346
+#define D 1.2158542
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+
+ xy.x = C * lp.lam * (Q->A - Q->B * sqrt(1. + D * lp.phi * lp.phi));
+ xy.y = C * lp.phi;
+
+ return xy;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+
+ lp.phi = xy.y / C;
+ lp.lam = xy.x / (C * (Q->A - Q->B * sqrt(1. + D * lp.phi * lp.phi)));
+
+ 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;
+}
+
+
+PJ *PROJECTION(putp5) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->A = 2.;
+ Q->B = 1.;
+
+ P->es = 0.;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+
+PJ *PROJECTION(putp5p) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->A = 1.5;
+ Q->B = 0.5;
+
+ P->es = 0.;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_putp5_selftest (void) {return 0;}
+#else
+
+int pj_putp5_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=putp5 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 226367.21338056153, 113204.56855847509},
+ { 226367.21338056153, -113204.56855847509},
+ {-226367.21338056153, 113204.56855847509},
+ {-226367.21338056153, -113204.56855847509},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.00176671315102969553, 0.000883356575387199546},
+ { 0.00176671315102969553, -0.000883356575387199546},
+ {-0.00176671315102969553, 0.000883356575387199546},
+ {-0.00176671315102969553, -0.000883356575387199546},
+ };
+
+ 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_putp5p_selftest (void) {return 0;}
+#else
+
+int pj_putp5p_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=putp5p +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 226388.175248755841, 113204.56855847509},
+ { 226388.175248755841, -113204.56855847509},
+ {-226388.175248755841, 113204.56855847509},
+ {-226388.175248755841, -113204.56855847509},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.00176671315090204742, 0.000883356575387199546},
+ { 0.00176671315090204742, -0.000883356575387199546},
+ {-0.00176671315090204742, 0.000883356575387199546},
+ {-0.00176671315090204742, -0.000883356575387199546},
+ };
+
+ 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_putp6.c b/src/PJ_putp6.c
index 5909dd4c..7c860cdb 100644
--- a/src/PJ_putp6.c
+++ b/src/PJ_putp6.c
@@ -1,59 +1,196 @@
-#define PROJ_PARMS__ \
- double C_x, C_y, A, B, D;
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
+struct pj_opaque {
+ double C_x, C_y, A, B, D;
+};
+
PROJ_HEAD(putp6, "Putnins P6") "\n\tPCyl., Sph.";
PROJ_HEAD(putp6p, "Putnins P6'") "\n\tPCyl., Sph.";
-#define EPS 1e-10
-#define NITER 10
+
+#define EPS 1e-10
+#define NITER 10
#define CON_POLE 1.732050807568877
-FORWARD(s_forward); /* spheroid */
- double p, r, V;
- int i;
-
- p = P->B * sin(lp.phi);
- lp.phi *= 1.10265779;
- for (i = NITER; i ; --i) {
- r = sqrt(1. + lp.phi * lp.phi);
- lp.phi -= V = ( (P->A - r) * lp.phi - log(lp.phi + r) - p ) /
- (P->A - 2. * r);
- if (fabs(V) < EPS)
- break;
- }
- if (!i)
- lp.phi = p < 0. ? -CON_POLE : CON_POLE;
- xy.x = P->C_x * lp.lam * (P->D - sqrt(1. + lp.phi * lp.phi));
- xy.y = P->C_y * lp.phi;
- return (xy);
-}
-INVERSE(s_inverse); /* spheroid */
- double r;
-
- lp.phi = xy.y / P->C_y;
- r = sqrt(1. + lp.phi * lp.phi);
- lp.lam = xy.x / (P->C_x * (P->D - r));
- lp.phi = aasin( P->ctx, ( (P->A - r) * lp.phi - log(lp.phi + r) ) / P->B);
- return (lp);
-}
-FREEUP; if (P) pj_dalloc(P); }
- static PJ *
-setup(PJ *P) {
- P->es = 0.;
- P->inv = s_inverse;
- P->fwd = s_forward;
- return P;
-}
-ENTRY0(putp6)
- P->C_x = 1.01346;
- P->C_y = 0.91910;
- P->A = 4.;
- P->B = 2.1471437182129378784;
- P->D = 2.;
-ENDENTRY(setup(P))
-ENTRY0(putp6p)
- P->C_x = 0.44329;
- P->C_y = 0.80404;
- P->A = 6.;
- P->B = 5.61125;
- P->D = 3.;
-ENDENTRY(setup(P))
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double p, r, V;
+ int i;
+
+ p = Q->B * sin(lp.phi);
+ lp.phi *= 1.10265779;
+ for (i = NITER; i ; --i) {
+ r = sqrt(1. + lp.phi * lp.phi);
+ lp.phi -= V = ( (Q->A - r) * lp.phi - log(lp.phi + r) - p ) /
+ (Q->A - 2. * r);
+ if (fabs(V) < EPS)
+ break;
+ }
+ if (!i)
+ lp.phi = p < 0. ? -CON_POLE : CON_POLE;
+ xy.x = Q->C_x * lp.lam * (Q->D - sqrt(1. + lp.phi * lp.phi));
+ xy.y = Q->C_y * lp.phi;
+
+ return xy;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double r;
+
+ lp.phi = xy.y / Q->C_y;
+ r = sqrt(1. + lp.phi * lp.phi);
+ lp.lam = xy.x / (Q->C_x * (Q->D - r));
+ lp.phi = aasin( P->ctx, ( (Q->A - r) * lp.phi - log(lp.phi + r) ) / Q->B);
+
+ 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;
+}
+
+
+PJ *PROJECTION(putp6) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->C_x = 1.01346;
+ Q->C_y = 0.91910;
+ Q->A = 4.;
+ Q->B = 2.1471437182129378784;
+ Q->D = 2.;
+
+ P->es = 0.;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+
+PJ *PROJECTION(putp6p) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->C_x = 0.44329;
+ Q->C_y = 0.80404;
+ Q->A = 6.;
+ Q->B = 5.61125;
+ Q->D = 3.;
+
+ P->es = 0.;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_putp6_selftest (void) {return 0;}
+#else
+
+int pj_putp6_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=putp6 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 226369.395133402577, 110218.523796520662},
+ { 226369.395133402577, -110218.523796520749},
+ {-226369.395133402577, 110218.523796520662},
+ {-226369.395133402577, -110218.523796520749},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.00176671315102969921, 0.000907295534210503544},
+ { 0.00176671315102969921, -0.000907295534205924308},
+ {-0.00176671315102969921, 0.000907295534210503544},
+ {-0.00176671315102969921, -0.000907295534205924308},
+ };
+
+ 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_putp6p_selftest (void) {return 0;}
+#else
+
+int pj_putp6p_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=putp6p +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 198034.195132195076, 125989.475461323193},
+ { 198034.195132195076, -125989.475461323193},
+ {-198034.195132195076, 125989.475461323193},
+ {-198034.195132195076, -125989.475461323193},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.00201955053120177067, 0.000793716441164738612},
+ { 0.00201955053120177067, -0.000793716441164738612},
+ {-0.00201955053120177067, 0.000793716441164738612},
+ {-0.00201955053120177067, -0.000793716441164738612},
+ };
+
+ 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_qsc.c b/src/PJ_qsc.c
index 12cb9d63..b9e9eb0d 100644
--- a/src/PJ_qsc.c
+++ b/src/PJ_qsc.c
@@ -28,7 +28,7 @@
* Other projection centers will not work!
*
* In the projection code below, each cube face is handled differently.
- * See the computation of the face parameter in the ENTRY0(qsc) function
+ * See the computation of the face parameter in the PROJECTION(qsc) function
* and the handling of different face values (FACE_*) in the forward and
* inverse projections.
*
@@ -38,15 +38,18 @@
* three areas of a cube face are handled by rotation of AREA_0.
*/
-#define PROJ_PARMS__ \
- int face; \
- double a_squared; \
- double b; \
- double one_minus_f; \
- double one_minus_f_squared;
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
+struct pj_opaque {
+ int face;
+ double a_squared;
+ double b;
+ double one_minus_f;
+ double one_minus_f_squared;
+};
PROJ_HEAD(qsc, "Quadrilateralized Spherical Cube") "\n\tAzi, Sph.";
+
#define EPS10 1.e-10
/* The six cube faces. */
@@ -66,316 +69,403 @@ PROJ_HEAD(qsc, "Quadrilateralized Spherical Cube") "\n\tAzi, Sph.";
/* Helper function for forward projection: compute the theta angle
* and determine the area number. */
-static double
-qsc_fwd_equat_face_theta(double phi, double y, double x, int *area) {
- double theta;
- if (phi < EPS10) {
+static double qsc_fwd_equat_face_theta(double phi, double y, double x, int *area) {
+ double theta;
+ if (phi < EPS10) {
+ *area = AREA_0;
+ theta = 0.0;
+ } else {
+ theta = atan2(y, x);
+ if (fabs(theta) <= FORTPI) {
*area = AREA_0;
- theta = 0.0;
+ } else if (theta > FORTPI && theta <= HALFPI + FORTPI) {
+ *area = AREA_1;
+ theta -= HALFPI;
+ } else if (theta > HALFPI + FORTPI || theta <= -(HALFPI + FORTPI)) {
+ *area = AREA_2;
+ theta = (theta >= 0.0 ? theta - PI : theta + PI);
} else {
- theta = atan2(y, x);
- if (fabs(theta) <= FORTPI) {
- *area = AREA_0;
- } else if (theta > FORTPI && theta <= HALFPI + FORTPI) {
- *area = AREA_1;
- theta -= HALFPI;
- } else if (theta > HALFPI + FORTPI || theta <= -(HALFPI + FORTPI)) {
- *area = AREA_2;
- theta = (theta >= 0.0 ? theta - PI : theta + PI);
- } else {
- *area = AREA_3;
- theta += HALFPI;
- }
+ *area = AREA_3;
+ theta += HALFPI;
}
- return (theta);
+ }
+ return theta;
}
/* Helper function: shift the longitude. */
-static double
-qsc_shift_lon_origin(double lon, double offset) {
- double slon = lon + offset;
- if (slon < -PI) {
- slon += TWOPI;
- } else if (slon > +PI) {
- slon -= TWOPI;
- }
- return slon;
+static double qsc_shift_lon_origin(double lon, double offset) {
+ double slon = lon + offset;
+ if (slon < -PI) {
+ slon += TWOPI;
+ } else if (slon > +PI) {
+ slon -= TWOPI;
+ }
+ return slon;
}
-/* Forward projection, ellipsoid */
-FORWARD(e_forward);
- double lat, lon;
- double theta, phi;
- double t, mu; /* nu; */
- int area;
-
- /* Convert the geodetic latitude to a geocentric latitude.
- * This corresponds to the shift from the ellipsoid to the sphere
- * described in [LK12]. */
- if (P->es) {
- lat = atan(P->one_minus_f_squared * tan(lp.phi));
- } else {
- lat = lp.phi;
- }
- /* Convert the input lat, lon into theta, phi as used by QSC.
- * This depends on the cube face and the area on it.
- * For the top and bottom face, we can compute theta and phi
- * directly from phi, lam. For the other faces, we must use
- * unit sphere cartesian coordinates as an intermediate step. */
- lon = lp.lam;
- if (P->face == FACE_TOP) {
- phi = HALFPI - lat;
- if (lon >= FORTPI && lon <= HALFPI + FORTPI) {
- area = AREA_0;
- theta = lon - HALFPI;
- } else if (lon > HALFPI + FORTPI || lon <= -(HALFPI + FORTPI)) {
- area = AREA_1;
- theta = (lon > 0.0 ? lon - PI : lon + PI);
- } else if (lon > -(HALFPI + FORTPI) && lon <= -FORTPI) {
- area = AREA_2;
- theta = lon + HALFPI;
- } else {
- area = AREA_3;
- theta = lon;
- }
- } else if (P->face == FACE_BOTTOM) {
- phi = HALFPI + lat;
- if (lon >= FORTPI && lon <= HALFPI + FORTPI) {
- area = AREA_0;
- theta = -lon + HALFPI;
- } else if (lon < FORTPI && lon >= -FORTPI) {
- area = AREA_1;
- theta = -lon;
- } else if (lon < -FORTPI && lon >= -(HALFPI + FORTPI)) {
- area = AREA_2;
- theta = -lon - HALFPI;
- } else {
- area = AREA_3;
- theta = (lon > 0.0 ? -lon + PI : -lon - PI);
- }
- } else {
- double q, r, s;
- double sinlat, coslat;
- double sinlon, coslon;
-
- if (P->face == FACE_RIGHT) {
- lon = qsc_shift_lon_origin(lon, +HALFPI);
- } else if (P->face == FACE_BACK) {
- lon = qsc_shift_lon_origin(lon, +PI);
- } else if (P->face == FACE_LEFT) {
- lon = qsc_shift_lon_origin(lon, -HALFPI);
- }
- sinlat = sin(lat);
- coslat = cos(lat);
- sinlon = sin(lon);
- coslon = cos(lon);
- q = coslat * coslon;
- r = coslat * sinlon;
- s = sinlat;
-
- if (P->face == FACE_FRONT) {
- phi = acos(q);
- theta = qsc_fwd_equat_face_theta(phi, s, r, &area);
- } else if (P->face == FACE_RIGHT) {
- phi = acos(r);
- theta = qsc_fwd_equat_face_theta(phi, s, -q, &area);
- } else if (P->face == FACE_BACK) {
- phi = acos(-q);
- theta = qsc_fwd_equat_face_theta(phi, s, -r, &area);
- } else if (P->face == FACE_LEFT) {
- phi = acos(-r);
- theta = qsc_fwd_equat_face_theta(phi, s, q, &area);
- } else {
- /* Impossible */
- phi = theta = 0.0;
- area = AREA_0;
- }
- }
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double lat, lon;
+ double theta, phi;
+ double t, mu; /* nu; */
+ int area;
- /* Compute mu and nu for the area of definition.
- * For mu, see Eq. (3-21) in [OL76], but note the typos:
- * compare with Eq. (3-14). For nu, see Eq. (3-38). */
- mu = atan((12.0 / PI) * (theta + acos(sin(theta) * cos(FORTPI)) - HALFPI));
- t = sqrt((1.0 - cos(phi)) / (cos(mu) * cos(mu)) / (1.0 - cos(atan(1.0 / cos(theta)))));
- /* nu = atan(t); We don't really need nu, just t, see below. */
+ /* Convert the geodetic latitude to a geocentric latitude.
+ * This corresponds to the shift from the ellipsoid to the sphere
+ * described in [LK12]. */
+ if (P->es) {
+ lat = atan(Q->one_minus_f_squared * tan(lp.phi));
+ } else {
+ lat = lp.phi;
+ }
- /* Apply the result to the real area. */
- if (area == AREA_1) {
- mu += HALFPI;
- } else if (area == AREA_2) {
- mu += PI;
- } else if (area == AREA_3) {
- mu += HALFPI + PI;
+ /* Convert the input lat, lon into theta, phi as used by QSC.
+ * This depends on the cube face and the area on it.
+ * For the top and bottom face, we can compute theta and phi
+ * directly from phi, lam. For the other faces, we must use
+ * unit sphere cartesian coordinates as an intermediate step. */
+ lon = lp.lam;
+ if (Q->face == FACE_TOP) {
+ phi = HALFPI - lat;
+ if (lon >= FORTPI && lon <= HALFPI + FORTPI) {
+ area = AREA_0;
+ theta = lon - HALFPI;
+ } else if (lon > HALFPI + FORTPI || lon <= -(HALFPI + FORTPI)) {
+ area = AREA_1;
+ theta = (lon > 0.0 ? lon - PI : lon + PI);
+ } else if (lon > -(HALFPI + FORTPI) && lon <= -FORTPI) {
+ area = AREA_2;
+ theta = lon + HALFPI;
+ } else {
+ area = AREA_3;
+ theta = lon;
}
-
- /* Now compute x, y from mu and nu */
- /* t = tan(nu); */
- xy.x = t * cos(mu);
- xy.y = t * sin(mu);
- return (xy);
-}
-
-/* Inverse projection, ellipsoid */
-INVERSE(e_inverse);
- double mu, nu, cosmu, tannu;
- double tantheta, theta, cosphi, phi;
- double t;
- int area;
-
- /* Convert the input x, y to the mu and nu angles as used by QSC.
- * This depends on the area of the cube face. */
- nu = atan(sqrt(xy.x * xy.x + xy.y * xy.y));
- mu = atan2(xy.y, xy.x);
- if (xy.x >= 0.0 && xy.x >= fabs(xy.y)) {
+ } else if (Q->face == FACE_BOTTOM) {
+ phi = HALFPI + lat;
+ if (lon >= FORTPI && lon <= HALFPI + FORTPI) {
area = AREA_0;
- } else if (xy.y >= 0.0 && xy.y >= fabs(xy.x)) {
+ theta = -lon + HALFPI;
+ } else if (lon < FORTPI && lon >= -FORTPI) {
area = AREA_1;
- mu -= HALFPI;
- } else if (xy.x < 0.0 && -xy.x >= fabs(xy.y)) {
+ theta = -lon;
+ } else if (lon < -FORTPI && lon >= -(HALFPI + FORTPI)) {
area = AREA_2;
- mu = (mu < 0.0 ? mu + PI : mu - PI);
+ theta = -lon - HALFPI;
} else {
area = AREA_3;
- mu += HALFPI;
+ theta = (lon > 0.0 ? -lon + PI : -lon - PI);
}
+ } else {
+ double q, r, s;
+ double sinlat, coslat;
+ double sinlon, coslon;
- /* Compute phi and theta for the area of definition.
- * The inverse projection is not described in the original paper, but some
- * good hints can be found here (as of 2011-12-14):
- * http://fits.gsfc.nasa.gov/fitsbits/saf.93/saf.9302
- * (search for "Message-Id: <9302181759.AA25477 at fits.cv.nrao.edu>") */
- t = (PI / 12.0) * tan(mu);
- tantheta = sin(t) / (cos(t) - (1.0 / sqrt(2.0)));
- theta = atan(tantheta);
- cosmu = cos(mu);
- tannu = tan(nu);
- cosphi = 1.0 - cosmu * cosmu * tannu * tannu * (1.0 - cos(atan(1.0 / cos(theta))));
- if (cosphi < -1.0) {
- cosphi = -1.0;
- } else if (cosphi > +1.0) {
- cosphi = +1.0;
+ if (Q->face == FACE_RIGHT) {
+ lon = qsc_shift_lon_origin(lon, +HALFPI);
+ } else if (Q->face == FACE_BACK) {
+ lon = qsc_shift_lon_origin(lon, +PI);
+ } else if (Q->face == FACE_LEFT) {
+ lon = qsc_shift_lon_origin(lon, -HALFPI);
}
+ sinlat = sin(lat);
+ coslat = cos(lat);
+ sinlon = sin(lon);
+ coslon = cos(lon);
+ q = coslat * coslon;
+ r = coslat * sinlon;
+ s = sinlat;
- /* Apply the result to the real area on the cube face.
- * For the top and bottom face, we can compute phi and lam directly.
- * For the other faces, we must use unit sphere cartesian coordinates
- * as an intermediate step. */
- if (P->face == FACE_TOP) {
- phi = acos(cosphi);
- lp.phi = HALFPI - phi;
- if (area == AREA_0) {
- lp.lam = theta + HALFPI;
- } else if (area == AREA_1) {
- lp.lam = (theta < 0.0 ? theta + PI : theta - PI);
- } else if (area == AREA_2) {
- lp.lam = theta - HALFPI;
- } else /* area == AREA_3 */ {
- lp.lam = theta;
- }
- } else if (P->face == FACE_BOTTOM) {
- phi = acos(cosphi);
- lp.phi = phi - HALFPI;
- if (area == AREA_0) {
- lp.lam = -theta + HALFPI;
- } else if (area == AREA_1) {
- lp.lam = -theta;
- } else if (area == AREA_2) {
- lp.lam = -theta - HALFPI;
- } else /* area == AREA_3 */ {
- lp.lam = (theta < 0.0 ? -theta - PI : -theta + PI);
- }
+ if (Q->face == FACE_FRONT) {
+ phi = acos(q);
+ theta = qsc_fwd_equat_face_theta(phi, s, r, &area);
+ } else if (Q->face == FACE_RIGHT) {
+ phi = acos(r);
+ theta = qsc_fwd_equat_face_theta(phi, s, -q, &area);
+ } else if (Q->face == FACE_BACK) {
+ phi = acos(-q);
+ theta = qsc_fwd_equat_face_theta(phi, s, -r, &area);
+ } else if (Q->face == FACE_LEFT) {
+ phi = acos(-r);
+ theta = qsc_fwd_equat_face_theta(phi, s, q, &area);
} else {
- /* Compute phi and lam via cartesian unit sphere coordinates. */
- double q, r, s, t;
- q = cosphi;
- t = q * q;
- if (t >= 1.0) {
- s = 0.0;
- } else {
- s = sqrt(1.0 - t) * sin(theta);
- }
- t += s * s;
- if (t >= 1.0) {
- r = 0.0;
- } else {
- r = sqrt(1.0 - t);
- }
- /* Rotate q,r,s into the correct area. */
- if (area == AREA_1) {
- t = r;
- r = -s;
- s = t;
- } else if (area == AREA_2) {
- r = -r;
- s = -s;
- } else if (area == AREA_3) {
- t = r;
- r = s;
- s = -t;
- }
- /* Rotate q,r,s into the correct cube face. */
- if (P->face == FACE_RIGHT) {
- t = q;
- q = -r;
- r = t;
- } else if (P->face == FACE_BACK) {
- q = -q;
- r = -r;
- } else if (P->face == FACE_LEFT) {
- t = q;
- q = r;
- r = -t;
- }
- /* Now compute phi and lam from the unit sphere coordinates. */
- lp.phi = acos(-s) - HALFPI;
- lp.lam = atan2(r, q);
- if (P->face == FACE_RIGHT) {
- lp.lam = qsc_shift_lon_origin(lp.lam, -HALFPI);
- } else if (P->face == FACE_BACK) {
- lp.lam = qsc_shift_lon_origin(lp.lam, -PI);
- } else if (P->face == FACE_LEFT) {
- lp.lam = qsc_shift_lon_origin(lp.lam, +HALFPI);
- }
+ /* Impossible */
+ phi = theta = 0.0;
+ area = AREA_0;
}
+ }
- /* Apply the shift from the sphere to the ellipsoid as described
- * in [LK12]. */
- if (P->es) {
- int invert_sign;
- double tanphi, xa;
- invert_sign = (lp.phi < 0.0 ? 1 : 0);
- tanphi = tan(lp.phi);
- xa = P->b / sqrt(tanphi * tanphi + P->one_minus_f_squared);
- lp.phi = atan(sqrt(P->a * P->a - xa * xa) / (P->one_minus_f * xa));
- if (invert_sign) {
- lp.phi = -lp.phi;
- }
- }
- return (lp);
+ /* Compute mu and nu for the area of definition.
+ * For mu, see Eq. (3-21) in [OL76], but note the typos:
+ * compare with Eq. (3-14). For nu, see Eq. (3-38). */
+ mu = atan((12.0 / PI) * (theta + acos(sin(theta) * cos(FORTPI)) - HALFPI));
+ t = sqrt((1.0 - cos(phi)) / (cos(mu) * cos(mu)) / (1.0 - cos(atan(1.0 / cos(theta)))));
+ /* nu = atan(t); We don't really need nu, just t, see below. */
+
+ /* Apply the result to the real area. */
+ if (area == AREA_1) {
+ mu += HALFPI;
+ } else if (area == AREA_2) {
+ mu += PI;
+ } else if (area == AREA_3) {
+ mu += HALFPI + PI;
+ }
+
+ /* Now compute x, y from mu and nu */
+ /* t = tan(nu); */
+ xy.x = t * cos(mu);
+ xy.y = t * sin(mu);
+ return xy;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(qsc)
- P->inv = e_inverse;
- P->fwd = e_forward;
- /* Determine the cube face from the center of projection. */
- if (P->phi0 >= HALFPI - FORTPI / 2.0) {
- P->face = FACE_TOP;
- } else if (P->phi0 <= -(HALFPI - FORTPI / 2.0)) {
- P->face = FACE_BOTTOM;
- } else if (fabs(P->lam0) <= FORTPI) {
- P->face = FACE_FRONT;
- } else if (fabs(P->lam0) <= HALFPI + FORTPI) {
- P->face = (P->lam0 > 0.0 ? FACE_RIGHT : FACE_LEFT);
+
+
+static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double mu, nu, cosmu, tannu;
+ double tantheta, theta, cosphi, phi;
+ double t;
+ int area;
+
+ /* Convert the input x, y to the mu and nu angles as used by QSC.
+ * This depends on the area of the cube face. */
+ nu = atan(sqrt(xy.x * xy.x + xy.y * xy.y));
+ mu = atan2(xy.y, xy.x);
+ if (xy.x >= 0.0 && xy.x >= fabs(xy.y)) {
+ area = AREA_0;
+ } else if (xy.y >= 0.0 && xy.y >= fabs(xy.x)) {
+ area = AREA_1;
+ mu -= HALFPI;
+ } else if (xy.x < 0.0 && -xy.x >= fabs(xy.y)) {
+ area = AREA_2;
+ mu = (mu < 0.0 ? mu + PI : mu - PI);
+ } else {
+ area = AREA_3;
+ mu += HALFPI;
+ }
+
+ /* Compute phi and theta for the area of definition.
+ * The inverse projection is not described in the original paper, but some
+ * good hints can be found here (as of 2011-12-14):
+ * http://fits.gsfc.nasa.gov/fitsbits/saf.93/saf.9302
+ * (search for "Message-Id: <9302181759.AA25477 at fits.cv.nrao.edu>") */
+ t = (PI / 12.0) * tan(mu);
+ tantheta = sin(t) / (cos(t) - (1.0 / sqrt(2.0)));
+ theta = atan(tantheta);
+ cosmu = cos(mu);
+ tannu = tan(nu);
+ cosphi = 1.0 - cosmu * cosmu * tannu * tannu * (1.0 - cos(atan(1.0 / cos(theta))));
+ if (cosphi < -1.0) {
+ cosphi = -1.0;
+ } else if (cosphi > +1.0) {
+ cosphi = +1.0;
+ }
+
+ /* Apply the result to the real area on the cube face.
+ * For the top and bottom face, we can compute phi and lam directly.
+ * For the other faces, we must use unit sphere cartesian coordinates
+ * as an intermediate step. */
+ if (Q->face == FACE_TOP) {
+ phi = acos(cosphi);
+ lp.phi = HALFPI - phi;
+ if (area == AREA_0) {
+ lp.lam = theta + HALFPI;
+ } else if (area == AREA_1) {
+ lp.lam = (theta < 0.0 ? theta + PI : theta - PI);
+ } else if (area == AREA_2) {
+ lp.lam = theta - HALFPI;
+ } else /* area == AREA_3 */ {
+ lp.lam = theta;
+ }
+ } else if (Q->face == FACE_BOTTOM) {
+ phi = acos(cosphi);
+ lp.phi = phi - HALFPI;
+ if (area == AREA_0) {
+ lp.lam = -theta + HALFPI;
+ } else if (area == AREA_1) {
+ lp.lam = -theta;
+ } else if (area == AREA_2) {
+ lp.lam = -theta - HALFPI;
+ } else /* area == AREA_3 */ {
+ lp.lam = (theta < 0.0 ? -theta - PI : -theta + PI);
+ }
+ } else {
+ /* Compute phi and lam via cartesian unit sphere coordinates. */
+ double q, r, s, t;
+ q = cosphi;
+ t = q * q;
+ if (t >= 1.0) {
+ s = 0.0;
} else {
- P->face = FACE_BACK;
+ s = sqrt(1.0 - t) * sin(theta);
}
- /* Fill in useful values for the ellipsoid <-> sphere shift
- * described in [LK12]. */
- if (P->es) {
- P->a_squared = P->a * P->a;
- P->b = P->a * sqrt(1.0 - P->es);
- P->one_minus_f = 1.0 - (P->a - P->b) / P->a;
- P->one_minus_f_squared = P->one_minus_f * P->one_minus_f;
+ t += s * s;
+ if (t >= 1.0) {
+ r = 0.0;
+ } else {
+ r = sqrt(1.0 - t);
}
-ENDENTRY(P)
+ /* Rotate q,r,s into the correct area. */
+ if (area == AREA_1) {
+ t = r;
+ r = -s;
+ s = t;
+ } else if (area == AREA_2) {
+ r = -r;
+ s = -s;
+ } else if (area == AREA_3) {
+ t = r;
+ r = s;
+ s = -t;
+ }
+ /* Rotate q,r,s into the correct cube face. */
+ if (Q->face == FACE_RIGHT) {
+ t = q;
+ q = -r;
+ r = t;
+ } else if (Q->face == FACE_BACK) {
+ q = -q;
+ r = -r;
+ } else if (Q->face == FACE_LEFT) {
+ t = q;
+ q = r;
+ r = -t;
+ }
+ /* Now compute phi and lam from the unit sphere coordinates. */
+ lp.phi = acos(-s) - HALFPI;
+ lp.lam = atan2(r, q);
+ if (Q->face == FACE_RIGHT) {
+ lp.lam = qsc_shift_lon_origin(lp.lam, -HALFPI);
+ } else if (Q->face == FACE_BACK) {
+ lp.lam = qsc_shift_lon_origin(lp.lam, -PI);
+ } else if (Q->face == FACE_LEFT) {
+ lp.lam = qsc_shift_lon_origin(lp.lam, +HALFPI);
+ }
+ }
+
+ /* Apply the shift from the sphere to the ellipsoid as described
+ * in [LK12]. */
+ if (P->es) {
+ int invert_sign;
+ double tanphi, xa;
+ invert_sign = (lp.phi < 0.0 ? 1 : 0);
+ tanphi = tan(lp.phi);
+ xa = Q->b / sqrt(tanphi * tanphi + Q->one_minus_f_squared);
+ lp.phi = atan(sqrt(P->a * P->a - xa * xa) / (Q->one_minus_f * xa));
+ if (invert_sign) {
+ lp.phi = -lp.phi;
+ }
+ }
+ 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;
+}
+
+
+PJ *PROJECTION(qsc) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ P->inv = e_inverse;
+ P->fwd = e_forward;
+ /* Determine the cube face from the center of projection. */
+ if (P->phi0 >= HALFPI - FORTPI / 2.0) {
+ Q->face = FACE_TOP;
+ } else if (P->phi0 <= -(HALFPI - FORTPI / 2.0)) {
+ Q->face = FACE_BOTTOM;
+ } else if (fabs(P->lam0) <= FORTPI) {
+ Q->face = FACE_FRONT;
+ } else if (fabs(P->lam0) <= HALFPI + FORTPI) {
+ Q->face = (P->lam0 > 0.0 ? FACE_RIGHT : FACE_LEFT);
+ } else {
+ Q->face = FACE_BACK;
+ }
+ /* Fill in useful values for the ellipsoid <-> sphere shift
+ * described in [LK12]. */
+ if (P->es) {
+ Q->a_squared = P->a * P->a;
+ Q->b = P->a * sqrt(1.0 - P->es);
+ Q->one_minus_f = 1.0 - (P->a - Q->b) / P->a;
+ Q->one_minus_f_squared = Q->one_minus_f * Q->one_minus_f;
+ }
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_qsc_selftest (void) {return 0;}
+#else
+
+int pj_qsc_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=qsc +ellps=GRS80 +lat_1=0.5 +lat_2=2"};
+ char s_args[] = {"+proj=qsc +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ { 304638.450843852363, 164123.870923793991},
+ { 304638.450843852363, -164123.870923793991},
+ {-304638.450843852363, 164123.870923793962},
+ {-304638.450843852421, -164123.870923793904},
+ };
+
+ XY s_fwd_expect[] = {
+ { 305863.792402890511, 165827.722754715243},
+ { 305863.792402890511, -165827.722754715243},
+ {-305863.792402890511, 165827.722754715243},
+ {-305863.792402890569, -165827.722754715156},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ { 0.00132134098471627126, 0.000610652900922527926},
+ { 0.00132134098471627126, -0.000610652900922527926},
+ {-0.00132134098471627126, 0.000610652900922527926},
+ {-0.00132134098471627126, -0.000610652900922527926},
+ };
+
+ LP s_inv_expect[] = {
+ { 0.00131682718763827234, 0.000604493198178676161},
+ { 0.00131682718763827234, -0.000604493198178676161},
+ {-0.00131682718763827234, 0.000604493198178676161},
+ {-0.00131682718763827234, -0.000604493198178676161},
+ };
+
+ 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_robin.c b/src/PJ_robin.c
index e8572ae4..5fabd9d0 100644
--- a/src/PJ_robin.c
+++ b/src/PJ_robin.c
@@ -1,10 +1,12 @@
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(robin, "Robinson") "\n\tPCyl., Sph.";
+
#define V(C,z) (C.c0 + z * (C.c1 + z * (C.c2 + z * C.c3)))
#define DV(C,z) (C.c1 + z * (C.c2 + C.c2 + z * 3. * C.c3))
-/*
+/*
note: following terms based upon 5 deg. intervals in degrees.
Some background on these coefficients is available at:
@@ -14,7 +16,7 @@ http://trac.osgeo.org/proj/ticket/113
*/
struct COEFS {
- float c0, c1, c2, c3;
+ float c0, c1, c2, c3;
};
static const struct COEFS X[] = {
@@ -38,6 +40,7 @@ static const struct COEFS X[] = {
{0.5722, -0.00906601, 0.000182, 6.24051e-06},
{0.5322, -0.00677797, 0.000275608, 6.24051e-06}
};
+
static const struct COEFS Y[] = {
{-5.20417e-18, 0.0124, 1.21431e-18, -8.45284e-11},
{0.062, 0.0124, -1.26793e-09, 4.22642e-10},
@@ -59,61 +62,135 @@ static const struct COEFS Y[] = {
{0.9761, 0.00616527, -0.000256, -4.2106e-06},
{1, 0.00328947, -0.000319159, -4.2106e-06}
};
-#define FXC 0.8487
-#define FYC 1.3523
-#define C1 11.45915590261646417544
-#define RC1 0.08726646259971647884
-#define NODES 18
-#define ONEEPS 1.000001
-#define EPS 1e-8
-FORWARD(s_forward); /* spheroid */
- int i;
- double dphi;
- (void) P;
-
- i = floor((dphi = fabs(lp.phi)) * C1);
- if (i >= NODES) i = NODES - 1;
- dphi = RAD_TO_DEG * (dphi - RC1 * i);
- xy.x = V(X[i], dphi) * FXC * lp.lam;
- xy.y = V(Y[i], dphi) * FYC;
- if (lp.phi < 0.) xy.y = -xy.y;
- return (xy);
+
+#define FXC 0.8487
+#define FYC 1.3523
+#define C1 11.45915590261646417544
+#define RC1 0.08726646259971647884
+#define NODES 18
+#define ONEEPS 1.000001
+#define EPS 1e-8
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ int i;
+ double dphi;
+ (void) P;
+
+ i = floor((dphi = fabs(lp.phi)) * C1);
+ if (i >= NODES) i = NODES - 1;
+ dphi = RAD_TO_DEG * (dphi - RC1 * i);
+ xy.x = V(X[i], dphi) * FXC * lp.lam;
+ xy.y = V(Y[i], dphi) * FYC;
+ if (lp.phi < 0.) xy.y = -xy.y;
+
+ return xy;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ int i;
+ double t, t1;
+ struct COEFS T;
+
+ lp.lam = xy.x / FXC;
+ lp.phi = fabs(xy.y / FYC);
+ if (lp.phi >= 1.) { /* simple pathologic cases */
+ if (lp.phi > ONEEPS) I_ERROR
+ else {
+ lp.phi = xy.y < 0. ? -HALFPI : HALFPI;
+ lp.lam /= X[NODES].c0;
+ }
+ } else { /* general problem */
+ /* in Y space, reduce to table interval */
+ for (i = floor(lp.phi * NODES);;) {
+ if (Y[i].c0 > lp.phi) --i;
+ else if (Y[i+1].c0 <= lp.phi) ++i;
+ else break;
+ }
+ T = Y[i];
+ /* first guess, linear interp */
+ t = 5. * (lp.phi - T.c0)/(Y[i+1].c0 - T.c0);
+ /* make into root */
+ T.c0 -= lp.phi;
+ for (;;) { /* Newton-Raphson reduction */
+ t -= t1 = V(T,t) / DV(T,t);
+ if (fabs(t1) < EPS)
+ break;
+ }
+ lp.phi = (5 * i + t) * DEG_TO_RAD;
+ if (xy.y < 0.) lp.phi = -lp.phi;
+ lp.lam /= V(X[i], t);
+ }
+ return lp;
+}
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+
+ return pj_dealloc(P);
+}
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
}
-INVERSE(s_inverse); /* spheroid */
- int i;
- double t, t1;
- struct COEFS T;
-
- lp.lam = xy.x / FXC;
- lp.phi = fabs(xy.y / FYC);
- if (lp.phi >= 1.) { /* simple pathologic cases */
- if (lp.phi > ONEEPS) I_ERROR
- else {
- lp.phi = xy.y < 0. ? -HALFPI : HALFPI;
- lp.lam /= X[NODES].c0;
- }
- } else { /* general problem */
- /* in Y space, reduce to table interval */
- for (i = floor(lp.phi * NODES);;) {
- if (Y[i].c0 > lp.phi) --i;
- else if (Y[i+1].c0 <= lp.phi) ++i;
- else break;
- }
- T = Y[i];
- /* first guess, linear interp */
- t = 5. * (lp.phi - T.c0)/(Y[i+1].c0 - T.c0);
- /* make into root */
- T.c0 -= lp.phi;
- for (;;) { /* Newton-Raphson reduction */
- t -= t1 = V(T,t) / DV(T,t);
- if (fabs(t1) < EPS)
- break;
- }
- lp.phi = (5 * i + t) * DEG_TO_RAD;
- if (xy.y < 0.) lp.phi = -lp.phi;
- lp.lam /= V(X[i], t);
- }
- return (lp);
+
+
+PJ *PROJECTION(robin) {
+ P->es = 0.;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(robin) P->es = 0.; P->inv = s_inverse; P->fwd = s_forward; ENDENTRY(P)
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_robin_selftest (void) {return 0;}
+#else
+
+int pj_robin_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=robin +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 189588.423282507836, 107318.530350702888},
+ { 189588.423282507836, -107318.530350702888},
+ {-189588.423282507836, 107318.530350702888},
+ {-189588.423282507836, -107318.530350702888},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.002109689065506131, 0.000931805533547745983},
+ { 0.002109689065506131, -0.000931805533547745983},
+ {-0.002109689065506131, 0.000931805533547745983},
+ {-0.002109689065506131, -0.000931805533547745983},
+ };
+
+ 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_rpoly.c b/src/PJ_rpoly.c
index 7a7670ed..ad240917 100644
--- a/src/PJ_rpoly.c
+++ b/src/PJ_rpoly.c
@@ -1,35 +1,99 @@
-#define PROJ_PARMS__ \
- double phi1; \
- double fxa; \
- double fxb; \
- int mode;
-#define EPS 1e-9
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
+struct pj_opaque {
+ double phi1;
+ double fxa;
+ double fxb;
+ int mode;
+};
+
PROJ_HEAD(rpoly, "Rectangular Polyconic")
- "\n\tConic, Sph., no inv.\n\tlat_ts=";
-FORWARD(s_forward); /* spheroid */
- double fa;
-
- if (P->mode)
- fa = tan(lp.lam * P->fxb) * P->fxa;
- else
- fa = 0.5 * lp.lam;
- if (fabs(lp.phi) < EPS) {
- xy.x = fa + fa;
- xy.y = - P->phi0;
- } else {
- xy.y = 1. / tan(lp.phi);
- xy.x = sin(fa = 2. * atan(fa * sin(lp.phi))) * xy.y;
- xy.y = lp.phi - P->phi0 + (1. - cos(fa)) * xy.y;
- }
- return (xy);
+ "\n\tConic, Sph., no inv.\n\tlat_ts=";
+
+#define EPS 1e-9
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double fa;
+
+ if (Q->mode)
+ fa = tan(lp.lam * Q->fxb) * Q->fxa;
+ else
+ fa = 0.5 * lp.lam;
+ if (fabs(lp.phi) < EPS) {
+ xy.x = fa + fa;
+ xy.y = - P->phi0;
+ } else {
+ xy.y = 1. / tan(lp.phi);
+ xy.x = sin(fa = 2. * atan(fa * sin(lp.phi))) * xy.y;
+ xy.y = lp.phi - P->phi0 + (1. - cos(fa)) * xy.y;
+ }
+ return xy;
+}
+
+
+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);
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(rpoly)
- if ((P->mode = (P->phi1 = fabs(pj_param(P->ctx, P->params, "rlat_ts").f)) > EPS)) {
- P->fxb = 0.5 * sin(P->phi1);
- P->fxa = 0.5 / P->fxb;
- }
- P->es = 0.; P->fwd = s_forward;
-ENDENTRY(P)
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(rpoly) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ if ((Q->mode = (Q->phi1 = fabs(pj_param(P->ctx, P->params, "rlat_ts").f)) > EPS)) {
+ Q->fxb = 0.5 * sin(Q->phi1);
+ Q->fxa = 0.5 / Q->fxb;
+ }
+ P->es = 0.;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_rpoly_selftest (void) {return 0;}
+#else
+
+int pj_rpoly_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=rpoly +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 223368.09830201423, 111769.110486991223},
+ { 223368.09830201423, -111769.110486991223},
+ {-223368.09830201423, 111769.110486991223},
+ {-223368.09830201423, -111769.110486991223},
+ };
+
+ return pj_generic_selftest (0, s_args, tolerance_xy, tolerance_lp, 4, 4, fwd_in, 0, s_fwd_expect, 0, 0, 0);
+}
+
+
+#endif
diff --git a/src/PJ_sch.c b/src/PJ_sch.c
index 9a0120fe..048224ec 100644
--- a/src/PJ_sch.c
+++ b/src/PJ_sch.c
@@ -3,8 +3,8 @@
*
* Project: SCH Coordinate system
* Purpose: Implementation of SCH Coordinate system
- * References :
- * 1. Hensley. Scott. SCH Coordinates and various transformations. June 15, 2000.
+ * References :
+ * 1. Hensley. Scott. SCH Coordinates and various transformations. June 15, 2000.
* 2. Buckley, Sean Monroe. Radar interferometry measurement of land subsidence. 2000..
* PhD Thesis. UT Austin. (Appendix)
* 3. Hensley, Scott, Elaine Chapin, and T. Michel. "Improved processing of AIRSAR
@@ -15,8 +15,8 @@
* Copyright (c) 2015 California Institute of Technology.
* Government sponsorship acknowledged.
*
- * NOTE: The SCH coordinate system is a sensor aligned coordinate system
- * developed at JPL for radar mapping missions. Details pertaining to the
+ * NOTE: The SCH coordinate system is a sensor aligned coordinate system
+ * developed at JPL for radar mapping missions. Details pertaining to the
* coordinate system have been release in the public domain (see references above).
* This code is an independent implementation of the SCH coordinate system
* that conforms to the PROJ.4 conventions and uses the details presented in these
@@ -32,200 +32,237 @@
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
+#define PJ_LIB__
+#include <projects.h>
#include "geocent.h"
-#define PROJ_PARMS__ \
- double plat; /*Peg Latitude */ \
- double plon; /*Peg Longitude*/ \
- double phdg; /*Peg heading */ \
- double h0; /*Average altitude */\
- double transMat[9]; \
- double xyzoff[3]; \
- double rcurv; \
- GeocentricInfo sph; \
- GeocentricInfo elp_0;
-
-#define PJ_LIB__
-#include <projects.h>
+struct pj_opaque {
+ double plat; /*Peg Latitude */
+ double plon; /*Peg Longitude*/
+ double phdg; /*Peg heading */
+ double h0; /*Average altitude */
+ double transMat[9];
+ double xyzoff[3];
+ double rcurv;
+ GeocentricInfo sph;
+ GeocentricInfo elp_0;
+};
PROJ_HEAD(sch, "Spherical Cross-track Height") "\n\tMisc\n\tplat_0 = ,plon_0 = , phdg_0 = ,[h_0 = ]";
-INVERSE3D(inverse3d);
- double temp[3];
- double pxyz[3];
-
- //Local lat,lon using radius
- pxyz[0] = xyz.y * P->a / P->rcurv;
- pxyz[1] = xyz.x * P->a / P->rcurv;
- pxyz[2] = xyz.z;
-
-
- if( pj_Convert_Geodetic_To_Geocentric( &(P->sph), pxyz[0], pxyz[1], pxyz[2],
- temp, temp+1, temp+2) != 0)
- I3_ERROR;
-
- //Apply rotation
- pxyz[0] = P->transMat[0] * temp[0] + P->transMat[1] * temp[1] + P->transMat[2] * temp[2];
- pxyz[1] = P->transMat[3] * temp[0] + P->transMat[4] * temp[1] + P->transMat[5] * temp[2];
- pxyz[2] = P->transMat[6] * temp[0] + P->transMat[7] * temp[1] + P->transMat[8] * temp[2];
-
- //Apply offset
- pxyz[0] += P->xyzoff[0];
- pxyz[1] += P->xyzoff[1];
- pxyz[2] += P->xyzoff[2];
-
- //Convert geocentric coordinates to lat lon
- pj_Convert_Geocentric_To_Geodetic( &(P->elp_0), pxyz[0], pxyz[1], pxyz[2],
- temp, temp+1, temp+2);
-
-
- lpz.lam = temp[1] ;
- lpz.phi = temp[0] ;
- lpz.z = temp[2];
-
-// printf("INVERSE: \n");
-// printf("XYZ: %f %f %f \n", xyz.x, xyz.y, xyz.z);
-// printf("LPZ: %f %f %f \n", lpz.lam, lpz.phi, lpz.z);
- return (lpz);
+static LPZ inverse3d(XYZ xyz, PJ *P) {
+ LPZ lpz = {0.0, 0.0, 0.0};
+ struct pj_opaque *Q = P->opaque;
+ double temp[3];
+ double pxyz[3];
+
+ /* Local lat,lon using radius */
+ pxyz[0] = xyz.y * P->a / Q->rcurv;
+ pxyz[1] = xyz.x * P->a / Q->rcurv;
+ pxyz[2] = xyz.z;
+
+ if( pj_Convert_Geodetic_To_Geocentric( &(Q->sph), pxyz[0], pxyz[1], pxyz[2],
+ temp, temp+1, temp+2) != 0)
+ I3_ERROR;
+
+ /* Apply rotation */
+ pxyz[0] = Q->transMat[0] * temp[0] + Q->transMat[1] * temp[1] + Q->transMat[2] * temp[2];
+ pxyz[1] = Q->transMat[3] * temp[0] + Q->transMat[4] * temp[1] + Q->transMat[5] * temp[2];
+ pxyz[2] = Q->transMat[6] * temp[0] + Q->transMat[7] * temp[1] + Q->transMat[8] * temp[2];
+
+ /* Apply offset */
+ pxyz[0] += Q->xyzoff[0];
+ pxyz[1] += Q->xyzoff[1];
+ pxyz[2] += Q->xyzoff[2];
+
+ /* Convert geocentric coordinates to lat lon */
+ pj_Convert_Geocentric_To_Geodetic( &(Q->elp_0), pxyz[0], pxyz[1], pxyz[2],
+ temp, temp+1, temp+2);
+
+
+ lpz.lam = temp[1] ;
+ lpz.phi = temp[0] ;
+ lpz.z = temp[2];
+
+#if 0
+ printf("INVERSE: \n");
+ printf("XYZ: %f %f %f \n", xyz.x, xyz.y, xyz.z);
+ printf("LPZ: %f %f %f \n", lpz.lam, lpz.phi, lpz.z);
+#endif
+ return lpz;
}
-FORWARD3D(forward3d);
- double temp[3];
- double pxyz[3];
+static XYZ forward3d(LPZ lpz, PJ *P) {
+ XYZ xyz = {0.0, 0.0, 0.0};
+ struct pj_opaque *Q = P->opaque;
+ double temp[3];
+ double pxyz[3];
- //Convert lat lon to geocentric coordinates
- if( pj_Convert_Geodetic_To_Geocentric( &(P->elp_0), lpz.phi, lpz.lam, lpz.z,
- temp, temp+1, temp+2 ) != 0 )
- F3_ERROR;
+ /* Convert lat lon to geocentric coordinates */
+ if( pj_Convert_Geodetic_To_Geocentric( &(Q->elp_0), lpz.phi, lpz.lam, lpz.z,
+ temp, temp+1, temp+2 ) != 0 )
+ F3_ERROR;
- //Adjust for offset
- temp[0] -= P->xyzoff[0];
- temp[1] -= P->xyzoff[1];
- temp[2] -= P->xyzoff[2];
+ /* Adjust for offset */
+ temp[0] -= Q->xyzoff[0];
+ temp[1] -= Q->xyzoff[1];
+ temp[2] -= Q->xyzoff[2];
-
- //Apply rotation
- pxyz[0] = P->transMat[0] * temp[0] + P->transMat[3] * temp[1] + P->transMat[6] * temp[2];
- pxyz[1] = P->transMat[1] * temp[0] + P->transMat[4] * temp[1] + P->transMat[7] * temp[2];
- pxyz[2] = P->transMat[2] * temp[0] + P->transMat[5] * temp[1] + P->transMat[8] * temp[2];
- //Convert to local lat,lon
- pj_Convert_Geocentric_To_Geodetic( &(P->sph), pxyz[0], pxyz[1], pxyz[2],
- temp, temp+1, temp+2);
+ /* Apply rotation */
+ pxyz[0] = Q->transMat[0] * temp[0] + Q->transMat[3] * temp[1] + Q->transMat[6] * temp[2];
+ pxyz[1] = Q->transMat[1] * temp[0] + Q->transMat[4] * temp[1] + Q->transMat[7] * temp[2];
+ pxyz[2] = Q->transMat[2] * temp[0] + Q->transMat[5] * temp[1] + Q->transMat[8] * temp[2];
+ /* Convert to local lat,lon */
+ pj_Convert_Geocentric_To_Geodetic( &(Q->sph), pxyz[0], pxyz[1], pxyz[2],
+ temp, temp+1, temp+2);
- //Scale by radius
- xyz.x = temp[1] * P->rcurv / P->a;
- xyz.y = temp[0] * P->rcurv / P->a;
- xyz.z = temp[2];
-// printf("FORWARD: \n");
-// printf("LPZ: %f %f %f \n", lpz.lam, lpz.phi, lpz.z);
-// printf("XYZ: %f %f %f \n", xyz.x, xyz.y, xyz.z);
+ /* Scale by radius */
+ xyz.x = temp[1] * Q->rcurv / P->a;
+ xyz.y = temp[0] * Q->rcurv / P->a;
+ xyz.z = temp[2];
- return (xyz);
+#if 0
+ printf("FORWARD: \n");
+ printf("LPZ: %f %f %f \n", lpz.lam, lpz.phi, lpz.z);
+ printf("XYZ: %f %f %f \n", xyz.x, xyz.y, xyz.z);
+#endif
+ return xyz;
}
-FREEUP; if (P) pj_dalloc(P); }
- static PJ *
-setup(PJ *P) { /* general initialization */
- double reast, rnorth;
- double chdg, shdg;
- double clt, slt;
- double clo, slo;
- double temp;
- double pxyz[3];
- temp = P->a * sqrt(1.0 - P->es);
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+ if (0==P->opaque)
+ return pj_dealloc (P);
- //Setup original geocentric system
- if ( pj_Set_Geocentric_Parameters(&(P->elp_0), P->a, temp) != 0)
- E_ERROR(-37);
-
-
- clt = cos(P->plat);
- slt = sin(P->plat);
- clo = cos(P->plon);
- slo = sin(P->plon);
+ pj_dealloc (P->opaque);
+ return pj_dealloc(P);
+}
- //Estimate the radius of curvature for given peg
- temp = sqrt(1.0 - (P->es) * slt * slt);
- reast = (P->a)/temp;
- rnorth = (P->a) * (1.0 - (P->es))/pow(temp,3);
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
- chdg = cos(P->phdg);
- shdg = sin(P->phdg);
-
- P->rcurv = P->h0 + (reast*rnorth)/(reast * chdg * chdg + rnorth * shdg * shdg);
+static PJ *setup(PJ *P) { /* general initialization */
+ struct pj_opaque *Q = P->opaque;
+ double reast, rnorth;
+ double chdg, shdg;
+ double clt, slt;
+ double clo, slo;
+ double temp;
+ double pxyz[3];
-// printf("North Radius: %f \n", rnorth);
-// printf("East Radius: %f \n", reast);
-// printf("Effective Radius: %f \n", P->rcurv);
+ temp = P->a * sqrt(1.0 - P->es);
- //Set up local sphere at the given peg point
- if ( pj_Set_Geocentric_Parameters(&(P->sph), P->rcurv, P->rcurv) != 0)
+ /* Setup original geocentric system */
+ if ( pj_Set_Geocentric_Parameters(&(Q->elp_0), P->a, temp) != 0)
E_ERROR(-37);
- //Set up the transformation matrices
- P->transMat[0] = clt * clo;
- P->transMat[1] = -shdg*slo - slt*clo * chdg;
- P->transMat[2] = slo*chdg - slt*clo*shdg;
- P->transMat[3] = clt*slo;
- P->transMat[4] = clo*shdg - slt*slo*chdg;
- P->transMat[5] = -clo*chdg - slt*slo*shdg;
- P->transMat[6] = slt;
- P->transMat[7] = clt*chdg;
- P->transMat[8] = clt*shdg;
+ clt = cos(Q->plat);
+ slt = sin(Q->plat);
+ clo = cos(Q->plon);
+ slo = sin(Q->plon);
+
+ /* Estimate the radius of curvature for given peg */
+ temp = sqrt(1.0 - (P->es) * slt * slt);
+ reast = (P->a)/temp;
+ rnorth = (P->a) * (1.0 - (P->es))/pow(temp,3);
+
+ chdg = cos(Q->phdg);
+ shdg = sin(Q->phdg);
+
+ Q->rcurv = Q->h0 + (reast*rnorth)/(reast * chdg * chdg + rnorth * shdg * shdg);
+
+#if 0
+ printf("North Radius: %f \n", rnorth);
+ printf("East Radius: %f \n", reast);
+ printf("Effective Radius: %f \n", Q->rcurv);
+#endif
+
+ /* Set up local sphere at the given peg point */
+ if ( pj_Set_Geocentric_Parameters(&(Q->sph), Q->rcurv, Q->rcurv) != 0)
+ E_ERROR(-37);
+
+ /* Set up the transformation matrices */
+ Q->transMat[0] = clt * clo;
+ Q->transMat[1] = -shdg*slo - slt*clo * chdg;
+ Q->transMat[2] = slo*chdg - slt*clo*shdg;
+ Q->transMat[3] = clt*slo;
+ Q->transMat[4] = clo*shdg - slt*slo*chdg;
+ Q->transMat[5] = -clo*chdg - slt*slo*shdg;
+ Q->transMat[6] = slt;
+ Q->transMat[7] = clt*chdg;
+ Q->transMat[8] = clt*shdg;
+
+
+ if( pj_Convert_Geodetic_To_Geocentric( &(Q->elp_0), Q->plat, Q->plon, Q->h0,
+ pxyz, pxyz+1, pxyz+2 ) != 0 )
+ {
+ E_ERROR(-14)
+ }
+
+
+ Q->xyzoff[0] = pxyz[0] - (Q->rcurv) * clt * clo;
+ Q->xyzoff[1] = pxyz[1] - (Q->rcurv) * clt * slo;
+ Q->xyzoff[2] = pxyz[2] - (Q->rcurv) * slt;
+
+#if 0
+ printf("Offset: %f %f %f \n", Q->xyzoff[0], Q->xyzoff[1], Q->xyzoff[2]);
+#endif
+
+ P->fwd3d = forward3d;
+ P->inv3d = inverse3d;
+ return P;
+}
-
- if( pj_Convert_Geodetic_To_Geocentric( &(P->elp_0), P->plat, P->plon, P->h0,
- pxyz, pxyz+1, pxyz+2 ) != 0 )
- {
- E_ERROR(-14)
- }
+PJ *PROJECTION(sch) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
- P->xyzoff[0] = pxyz[0] - (P->rcurv) * clt * clo;
- P->xyzoff[1] = pxyz[1] - (P->rcurv) * clt * slo;
- P->xyzoff[2] = pxyz[2] - (P->rcurv) * slt;
+ Q->h0 = 0.0;
-// printf("Offset: %f %f %f \n", P->xyzoff[0], P->xyzoff[1], P->xyzoff[2]);
+ /* Check if peg latitude was defined */
+ if (pj_param(P->ctx, P->params, "tplat_0").i)
+ Q->plat = pj_param(P->ctx, P->params, "rplat_0").f;
+ else
+ E_ERROR(-37);
+ /* Check if peg longitude was defined */
+ if (pj_param(P->ctx, P->params, "tplon_0").i)
+ Q->plon = pj_param(P->ctx, P->params, "rplon_0").f;
+ else
+ E_ERROR(-37);
- P->fwd3d = forward3d;
- P->inv3d = inverse3d;
- return P;
-}
-ENTRY0(sch)
- P->h0 = 0.0;
+ /* Check if peg latitude is defined */
+ if (pj_param(P->ctx, P->params, "tphdg_0").i)
+ Q->phdg = pj_param(P->ctx, P->params, "rphdg_0").f;
+ else
+ E_ERROR(-37);
- //Check if peg latitude was defined
- if (pj_param(P->ctx, P->params, "tplat_0").i)
- P->plat = pj_param(P->ctx, P->params, "rplat_0").f;
- else
- E_ERROR(-37);
- //Check if peg longitude was defined
- if (pj_param(P->ctx, P->params, "tplon_0").i)
- P->plon = pj_param(P->ctx, P->params, "rplon_0").f;
- else
- E_ERROR(-37);
-
- //Check if peg latitude is defined
- if (pj_param(P->ctx, P->params, "tphdg_0").i)
- P->phdg = pj_param(P->ctx, P->params, "rphdg_0").f;
- else
- E_ERROR(-37);
-
+ /* Check if average height was defined - If so read it in */
+ if (pj_param(P->ctx, P->params, "th_0").i)
+ Q->h0 = pj_param(P->ctx, P->params, "dh_0").f;
- //Check if average height was defined
- //If so read it in
- if (pj_param(P->ctx, P->params, "th_0").i)
- P->h0 = pj_param(P->ctx, P->params, "dh_0").f;
+ /* Completed reading in the projection parameters */
+#if 0
+ printf("PSA: Lat = %f Lon = %f Hdg = %f \n", Q->plat, Q->plon, Q->phdg);
+#endif
- //Completed reading in the projection parameters
-// printf("PSA: Lat = %f Lon = %f Hdg = %f \n", P->plat, P->plon, P->phdg);
+ return setup(P);
+}
-ENDENTRY(setup(P))
+/* Skipping sef-test since the test system is not capable of handling
+ * 3D coordinate systems for the time being. Relying on tests in ../nad/
+ */
+int pj_sch_selftest (void) {return 0;}
diff --git a/src/PJ_sconics.c b/src/PJ_sconics.c
index 8c17533d..2bf2213b 100644
--- a/src/PJ_sconics.c
+++ b/src/PJ_sconics.c
@@ -1,12 +1,17 @@
-#define PROJ_PARMS__ \
- double n; \
- double rho_c; \
- double rho_0; \
- double sig; \
- double c1, c2; \
- int type;
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
+
+struct pj_opaque {
+ double n;
+ double rho_c;
+ double rho_0;
+ double sig;
+ double c1, c2;
+ int type;
+};
+
+
#define EULER 0
#define MURD1 1
#define MURD2 2
@@ -14,141 +19,677 @@
#define PCONIC 4
#define TISSOT 5
#define VITK1 6
-#define EPS10 1.e-10
+#define EPS10 1.e-10
#define EPS 1e-10
#define LINE2 "\n\tConic, Sph\n\tlat_1= and lat_2="
-PROJ_HEAD(tissot, "Tissot")
- LINE2;
-PROJ_HEAD(murd1, "Murdoch I")
- LINE2;
-PROJ_HEAD(murd2, "Murdoch II")
- LINE2;
-PROJ_HEAD(murd3, "Murdoch III")
- LINE2;
-PROJ_HEAD(euler, "Euler")
- LINE2;
-PROJ_HEAD(pconic, "Perspective Conic")
- LINE2;
-PROJ_HEAD(vitk1, "Vitkovsky I")
- LINE2;
+
+PROJ_HEAD(euler, "Euler") LINE2;
+PROJ_HEAD(murd1, "Murdoch I") LINE2;
+PROJ_HEAD(murd2, "Murdoch II") LINE2;
+PROJ_HEAD(murd3, "Murdoch III") LINE2;
+PROJ_HEAD(pconic, "Perspective Conic") LINE2;
+PROJ_HEAD(tissot, "Tissot") LINE2;
+PROJ_HEAD(vitk1, "Vitkovsky I") LINE2;
+
+
+
/* get common factors for simple conics */
- static int
-phi12(PJ *P, double *del) {
- double p1, p2;
- int err = 0;
-
- if (!pj_param(P->ctx, P->params, "tlat_1").i ||
- !pj_param(P->ctx, P->params, "tlat_2").i) {
- err = -41;
- } else {
- p1 = pj_param(P->ctx, P->params, "rlat_1").f;
- p2 = pj_param(P->ctx, P->params, "rlat_2").f;
- *del = 0.5 * (p2 - p1);
- P->sig = 0.5 * (p2 + p1);
- err = (fabs(*del) < EPS || fabs(P->sig) < EPS) ? -42 : 0;
- *del = *del;
- }
- return err;
-}
-FORWARD(s_forward); /* spheroid */
- double rho;
-
- switch (P->type) {
- case MURD2:
- rho = P->rho_c + tan(P->sig - lp.phi);
- break;
- case PCONIC:
- rho = P->c2 * (P->c1 - tan(lp.phi - P->sig));
- break;
- default:
- rho = P->rho_c - lp.phi;
- break;
- }
- xy.x = rho * sin( lp.lam *= P->n );
- xy.y = P->rho_0 - rho * cos(lp.lam);
- return (xy);
-}
-INVERSE(s_inverse); /* ellipsoid & spheroid */
- double rho;
-
- rho = hypot(xy.x, xy.y = P->rho_0 - xy.y);
- if (P->n < 0.) {
- rho = - rho;
- xy.x = - xy.x;
- xy.y = - xy.y;
- }
- lp.lam = atan2(xy.x, xy.y) / P->n;
- switch (P->type) {
- case PCONIC:
- lp.phi = atan(P->c1 - rho / P->c2) + P->sig;
- break;
- case MURD2:
- lp.phi = P->sig - atan(rho - P->rho_c);
- break;
- default:
- lp.phi = P->rho_c - rho;
- }
- return (lp);
-}
-FREEUP; if (P) pj_dalloc(P); }
- static PJ *
-setup(PJ *P) {
- double del, cs;
- int i;
-
- if( (i = phi12(P, &del)) )
- E_ERROR(i);
- switch (P->type) {
- case TISSOT:
- P->n = sin(P->sig);
- cs = cos(del);
- P->rho_c = P->n / cs + cs / P->n;
- P->rho_0 = sqrt((P->rho_c - 2 * sin(P->phi0))/P->n);
- break;
- case MURD1:
- P->rho_c = sin(del)/(del * tan(P->sig)) + P->sig;
- P->rho_0 = P->rho_c - P->phi0;
- P->n = sin(P->sig);
- break;
- case MURD2:
- P->rho_c = (cs = sqrt(cos(del))) / tan(P->sig);
- P->rho_0 = P->rho_c + tan(P->sig - P->phi0);
- P->n = sin(P->sig) * cs;
- break;
- case MURD3:
- P->rho_c = del / (tan(P->sig) * tan(del)) + P->sig;
- P->rho_0 = P->rho_c - P->phi0;
- P->n = sin(P->sig) * sin(del) * tan(del) / (del * del);
- break;
- case EULER:
- P->n = sin(P->sig) * sin(del) / del;
- del *= 0.5;
- P->rho_c = del / (tan(del) * tan(P->sig)) + P->sig;
- P->rho_0 = P->rho_c - P->phi0;
- break;
- case PCONIC:
- P->n = sin(P->sig);
- P->c2 = cos(del);
- P->c1 = 1./tan(P->sig);
- if (fabs(del = P->phi0 - P->sig) - EPS10 >= HALFPI)
- E_ERROR(-43);
- P->rho_0 = P->c2 * (P->c1 - tan(del));
- break;
- case VITK1:
- P->n = (cs = tan(del)) * sin(P->sig) / del;
- P->rho_c = del / (cs * tan(P->sig)) + P->sig;
- P->rho_0 = P->rho_c - P->phi0;
- break;
- }
- P->inv = s_inverse;
- P->fwd = s_forward;
- P->es = 0;
- return (P);
-}
-ENTRY0(euler) P->type = EULER; ENDENTRY(setup(P))
-ENTRY0(tissot) P->type = TISSOT; ENDENTRY(setup(P))
-ENTRY0(murd1) P->type = MURD1; ENDENTRY(setup(P))
-ENTRY0(murd2) P->type = MURD2; ENDENTRY(setup(P))
-ENTRY0(murd3) P->type = MURD3; ENDENTRY(setup(P))
-ENTRY0(pconic) P->type = PCONIC; ENDENTRY(setup(P))
-ENTRY0(vitk1) P->type = VITK1; ENDENTRY(setup(P))
+static int phi12(PJ *P, double *del) {
+ double p1, p2;
+ int err = 0;
+
+ if (!pj_param(P->ctx, P->params, "tlat_1").i ||
+ !pj_param(P->ctx, P->params, "tlat_2").i) {
+ err = -41;
+ } else {
+ p1 = pj_param(P->ctx, P->params, "rlat_1").f;
+ p2 = pj_param(P->ctx, P->params, "rlat_2").f;
+ *del = 0.5 * (p2 - p1);
+ P->opaque->sig = 0.5 * (p2 + p1);
+ err = (fabs(*del) < EPS || fabs(P->opaque->sig) < EPS) ? -42 : 0;
+ *del = *del;
+ }
+ return err;
+}
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0, 0.0};
+ struct pj_opaque *Q = P->opaque;
+ double rho;
+
+ switch (Q->type) {
+ case MURD2:
+ rho = Q->rho_c + tan (Q->sig - lp.phi);
+ break;
+ case PCONIC:
+ rho = Q->c2 * (Q->c1 - tan (lp.phi - Q->sig));
+ break;
+ default:
+ rho = Q->rho_c - lp.phi;
+ break;
+ }
+
+ xy.x = rho * sin ( lp.lam *= Q->n );
+ xy.y = Q->rho_0 - rho * cos (lp.lam);
+ return xy;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, (and ellipsoidal?) inverse */
+ LP lp = {0.0, 0.0};
+ struct pj_opaque *Q = P->opaque;
+ double rho;
+
+ rho = hypot (xy.x, xy.y = Q->rho_0 - xy.y);
+ if (Q->n < 0.) {
+ rho = - rho;
+ xy.x = - xy.x;
+ xy.y = - xy.y;
+ }
+
+ lp.lam = atan2 (xy.x, xy.y) / Q->n;
+
+ switch (Q->type) {
+ case PCONIC:
+ lp.phi = atan (Q->c1 - rho / Q->c2) + Q->sig;
+ break;
+ case MURD2:
+ lp.phi = Q->sig - atan(rho - Q->rho_c);
+ break;
+ default:
+ lp.phi = Q->rho_c - rho;
+ }
+ 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, int type) {
+ double del, cs;
+ int i;
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+ Q->type = type;
+
+ i = phi12 (P, &del);
+ if(i)
+ E_ERROR(i);
+ switch (Q->type) {
+
+ case TISSOT:
+ Q->n = sin (Q->sig);
+ cs = cos (del);
+ Q->rho_c = Q->n / cs + cs / Q->n;
+ Q->rho_0 = sqrt ((Q->rho_c - 2 * sin (P->phi0)) / Q->n);
+ break;
+
+ case MURD1:
+ Q->rho_c = sin(del)/(del * tan(Q->sig)) + Q->sig;
+ Q->rho_0 = Q->rho_c - P->phi0;
+ Q->n = sin(Q->sig);
+ break;
+
+ case MURD2:
+ Q->rho_c = (cs = sqrt (cos (del))) / tan (Q->sig);
+ Q->rho_0 = Q->rho_c + tan (Q->sig - P->phi0);
+ Q->n = sin (Q->sig) * cs;
+ break;
+
+ case MURD3:
+ Q->rho_c = del / (tan(Q->sig) * tan(del)) + Q->sig;
+ Q->rho_0 = Q->rho_c - P->phi0;
+ Q->n = sin (Q->sig) * sin (del) * tan (del) / (del * del);
+ break;
+
+ case EULER:
+ Q->n = sin (Q->sig) * sin (del) / del;
+ del *= 0.5;
+ Q->rho_c = del / (tan (del) * tan (Q->sig)) + Q->sig;
+ Q->rho_0 = Q->rho_c - P->phi0;
+ break;
+
+ case PCONIC:
+ Q->n = sin (Q->sig);
+ Q->c2 = cos (del);
+ Q->c1 = 1./tan (Q->sig);
+ if (fabs (del = P->phi0 - Q->sig) - EPS10 >= HALFPI)
+ E_ERROR(-43);
+ Q->rho_0 = Q->c2 * (Q->c1 - tan (del));
+ break;
+
+ case VITK1:
+ Q->n = (cs = tan (del)) * sin (Q->sig) / del;
+ Q->rho_c = del / (cs * tan (Q->sig)) + Q->sig;
+ Q->rho_0 = Q->rho_c - P->phi0;
+ break;
+ }
+
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+ P->es = 0;
+ return (P);
+}
+
+
+PJ *PROJECTION(euler) {
+ return setup(P, EULER);
+}
+
+
+PJ *PROJECTION(tissot) {
+ return setup(P, TISSOT);
+}
+
+
+PJ *PROJECTION(murd1) {
+ return setup(P, MURD1);
+}
+
+
+PJ *PROJECTION(murd2) {
+ return setup(P, MURD2);
+}
+
+
+PJ *PROJECTION(murd3) {
+ return setup(P, MURD3);
+}
+
+
+PJ *PROJECTION(pconic) {
+ return setup(P, PCONIC);
+}
+
+
+PJ *PROJECTION(vitk1) {
+ return setup(P, VITK1);
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_euler_selftest (void) {return 0;}
+#else
+
+int pj_euler_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=euler +ellps=GRS80 +lat_1=0.5 +lat_2=2 +n=0.5"};
+ char s_args[] = {"+proj=euler +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[] = {
+ {222597.63465910763, 111404.24054991946},
+ {222767.16563187627, -111234.6764910177},
+ {-222597.63465910763, 111404.24054991946},
+ {-222767.16563187627, -111234.6764910177},
+ };
+
+ XY s_fwd_expect[] = {
+ {223360.65559869423, 111786.11238979101},
+ {223530.76769031584, -111615.96709862351},
+ {-223360.65559869423, 111786.11238979101},
+ {-223530.76769031584, -111615.96709862351},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ {0.0017962807023075235, 0.0008983146697688839},
+ {0.0017962794738334226, -0.00089831589842987965},
+ {-0.0017962807023075235, 0.0008983146697688839},
+ {-0.0017962794738334226, -0.00089831589842987965},
+ };
+
+ LP s_inv_expect[] = {
+ {0.0017901444369360026, 0.00089524594522202015},
+ {0.001790143216840731, -0.00089524716533368484},
+ {-0.0017901444369360026, 0.00089524594522202015},
+ {-0.001790143216840731, -0.00089524716533368484},
+ };
+
+ 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
+
+
+
+
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_murd1_selftest (void) {return 0;}
+#else
+
+int pj_murd1_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=murd1 +ellps=GRS80 +lat_1=0.5 +lat_2=2 +n=0.5"};
+ char s_args[] = {"+proj=murd1 +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[] = {
+ {222600.81347355421, 111404.24418054636},
+ {222770.3492878644, -111234.6728566746},
+ {-222600.81347355421, 111404.24418054636},
+ {-222770.3492878644, -111234.6728566746},
+ };
+
+ XY s_fwd_expect[] = {
+ {223363.84530949194, 111786.11603286299},
+ {223533.96225925098, -111615.96345182261},
+ {-223363.84530949194, 111786.11603286299},
+ {-223533.96225925098, -111615.96345182261},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ {0.0017962550410516366, 0.0008983146697688839},
+ {0.0017962538125775522, -0.00089831589842987965},
+ {-0.0017962550410516366, 0.0008983146697688839},
+ {-0.0017962538125775522, -0.00089831589842987965},
+ };
+
+ LP s_inv_expect[] = {
+ {0.0017901188633413715, 0.00089524594522202015},
+ {0.0017901176432461162, -0.00089524716492657387},
+ {-0.0017901188633413715, 0.00089524594522202015},
+ {-0.0017901176432461162, -0.00089524716492657387},
+ };
+
+ 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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_murd2_selftest (void) {return 0;}
+#else
+
+int pj_murd2_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=murd2 +ellps=GRS80 +lat_1=0.5 +lat_2=2 +n=0.5"};
+ char s_args[] = {"+proj=murd2 +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[] = {
+ {222588.09975123021, 111426.14002741246},
+ {222757.72626701824, -111341.43131750476},
+ {-222588.09975123021, 111426.14002741246},
+ {-222757.72626701824, -111341.43131750476},
+ };
+
+ XY s_fwd_expect[] = {
+ {223351.08800702673, 111808.08693438848},
+ {223521.2959691704, -111723.08785967289},
+ {-223351.08800702673, 111808.08693438848},
+ {-223521.2959691704, -111723.08785967289},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ {0.0017963574947305447, 0.00089788747830845382},
+ {0.0017963562661689487, -0.00089788809264252983},
+ {-0.0017963574947305447, 0.00089788747830845382},
+ {-0.0017963562661689487, -0.00089788809264252983},
+ };
+
+ LP s_inv_expect[] = {
+ {0.0017902209670287586, 0.00089482021163422854},
+ {0.0017902197468465887, -0.00089482082161134206},
+ {-0.0017902209670287586, 0.00089482021163422854},
+ {-0.0017902197468465887, -0.00089482082161134206},
+ };
+
+ 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
+
+
+
+
+
+
+
+
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_murd3_selftest (void) {return 0;}
+#else
+
+int pj_murd3_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=murd3 +ellps=GRS80 +lat_1=0.5 +lat_2=2 +n=0.5"};
+ char s_args[] = {"+proj=murd3 +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[] = {
+ {222600.81407757697, 111404.24660137216},
+ {222770.35473389886, -111234.67043217793},
+ {-222600.81407757697, 111404.24660137216},
+ {-222770.35473389886, -111234.67043217793},
+ };
+
+ XY s_fwd_expect[] = {
+ {223363.84591558515, 111786.11846198692},
+ {223533.96772395336, -111615.96101901523},
+ {-223363.84591558515, 111786.11846198692},
+ {-223533.96772395336, -111615.96101901523},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ {0.0017962550166583809, 0.0008983146697688839},
+ {0.0017962537881492445, -0.00089831589842987965},
+ {-0.0017962550166583809, 0.0008983146697688839},
+ {-0.0017962537881492445, -0.00089831589842987965},
+ };
+
+ LP s_inv_expect[] = {
+ {0.0017901188390313859, 0.00089524594522202015},
+ {0.0017901176189013177, -0.00089524716533368484},
+ {-0.0017901188390313859, 0.00089524594522202015},
+ {-0.0017901176189013177, -0.00089524716533368484},
+ };
+
+ 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
+
+
+
+
+
+
+
+
+
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_pconic_selftest (void) {return 0;}
+#else
+
+int pj_pconic_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=pconic +ellps=GRS80 +lat_1=0.5 +lat_2=2 +n=0.5"};
+ char s_args[] = {"+proj=pconic +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[] = {
+ {222588.09884161691, 111416.60477006658},
+ {222757.71809109033, -111331.88153107995},
+ {-222588.09884161691, 111416.60477006658},
+ {-222757.71809109033, -111331.88153107995},
+ };
+
+ XY s_fwd_expect[] = {
+ {223351.08709429545, 111798.5189920546},
+ {223521.28776521701, -111713.50533845725},
+ {-223351.08709429545, 111798.5189920546},
+ {-223521.28776521701, -111713.50533845725},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ {0.0017963575313784969, 0.0008979644089172499},
+ {0.0017963563027642206, -0.00089796502355327969},
+ {-0.0017963575313784969, 0.0008979644089172499},
+ {-0.0017963563027642206, -0.00089796502355327969},
+ };
+
+ LP s_inv_expect[] = {
+ {0.0017902210035514285, 0.0008948968793741558},
+ {0.0017902197833169374, -0.00089489748965381963},
+ {-0.0017902210035514285, 0.0008948968793741558},
+ {-0.0017902197833169374, -0.00089489748965381963},
+ };
+
+ 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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_tissot_selftest (void) {return 0;}
+#else
+
+int pj_tissot_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=tissot +ellps=GRS80 +lat_1=0.5 +lat_2=2 +n=0.5"};
+ char s_args[] = {"+proj=tissot +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[] = {
+ {222641.07869963095, 54347.828487281469},
+ {222810.61451394114, -168291.08854993948},
+ {-222641.07869963095, 54347.828487281469},
+ {-222810.61451394114, -168291.08854993948},
+ };
+
+ XY s_fwd_expect[] = {
+ {223404.24855684943, 54534.122161157939},
+ {223574.36550660848, -168867.95732352766},
+ {-223404.24855684943, 54534.122161157939},
+ {-223574.36550660848, -168867.95732352766},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ {0.0017962807107425871, 0.51344495513064536},
+ {0.0017962794822333915, 0.51164832456244658},
+ {-0.0017962807107425871, 0.51344495513064536},
+ {-0.0017962794822333915, 0.51164832456244658},
+ };
+
+ LP s_inv_expect[] = {
+ {0.0017901444453421915, 0.51344188640609856},
+ {0.001790143225212064, 0.51165139329554277},
+ {-0.0017901444453421915, 0.51344188640609856},
+ {-0.001790143225212064, 0.51165139329554277},
+ };
+
+ 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
+
+
+
+
+
+
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_vitk1_selftest (void) {return 0;}
+#else
+
+int pj_vitk1_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=vitk1 +ellps=GRS80 +lat_1=0.5 +lat_2=2 +n=0.5"};
+ char s_args[] = {"+proj=vitk1 +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[] = {
+ {222607.17121145778, 111404.25144243463},
+ {222776.71670959776, -111234.66558744459},
+ {-222607.17121145778, 111404.25144243463},
+ {-222776.71670959776, -111234.66558744459},
+ };
+
+ XY s_fwd_expect[] = {
+ {223370.22484047143, 111786.12331964359},
+ {223540.3515072545, -111615.9561576751},
+ {-223370.22484047143, 111786.12331964359},
+ {-223540.3515072545, -111615.9561576751},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ {0.0017962037198570686, 0.0008983146697688839},
+ {0.0017962024913830157, -0.00089831589842987965},
+ {-0.0017962037198570686, 0.0008983146697688839},
+ {-0.0017962024913830157, -0.00089831589842987965},
+ };
+
+ LP s_inv_expect[] = {
+ {0.0017900677174648159, 0.00089524594522202015},
+ {0.0017900664973695916, -0.00089524716533368484},
+ {-0.0017900677174648159, 0.00089524594522202015},
+ {-0.0017900664973695916, -0.00089524716533368484},
+ };
+
+ 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_somerc.c b/src/PJ_somerc.c
index f7d1f119..e7659876 100644
--- a/src/PJ_somerc.c
+++ b/src/PJ_somerc.c
@@ -1,66 +1,165 @@
-#define PROJ_PARMS__ \
- double K, c, hlf_e, kR, cosp0, sinp0;
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(somerc, "Swiss. Obl. Mercator") "\n\tCyl, Ell\n\tFor CH1903";
-#define EPS 1.e-10
+
+struct pj_opaque {
+ double K, c, hlf_e, kR, cosp0, sinp0;
+};
+
+#define EPS 1.e-10
#define NITER 6
-FORWARD(e_forward);
- double phip, lamp, phipp, lampp, sp, cp;
-
- sp = P->e * sin(lp.phi);
- phip = 2.* atan( exp( P->c * (
- log(tan(FORTPI + 0.5 * lp.phi)) - P->hlf_e * log((1. + sp)/(1. - sp)))
- + P->K)) - HALFPI;
- lamp = P->c * lp.lam;
- cp = cos(phip);
- phipp = aasin(P->ctx,P->cosp0 * sin(phip) - P->sinp0 * cp * cos(lamp));
- lampp = aasin(P->ctx,cp * sin(lamp) / cos(phipp));
- xy.x = P->kR * lampp;
- xy.y = P->kR * log(tan(FORTPI + 0.5 * phipp));
- return (xy);
+
+
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
+ XY xy = {0.0, 0.0};
+ double phip, lamp, phipp, lampp, sp, cp;
+ struct pj_opaque *Q = P->opaque;
+
+ sp = P->e * sin (lp.phi);
+ phip = 2.* atan ( exp ( Q->c * (
+ log (tan (FORTPI + 0.5 * lp.phi)) - Q->hlf_e * log ((1. + sp)/(1. - sp)))
+ + Q->K)) - HALFPI;
+ lamp = Q->c * lp.lam;
+ cp = cos(phip);
+ phipp = aasin (P->ctx, Q->cosp0 * sin (phip) - Q->sinp0 * cp * cos (lamp));
+ lampp = aasin (P->ctx, cp * sin (lamp) / cos (phipp));
+ xy.x = Q->kR * lampp;
+ xy.y = Q->kR * log (tan (FORTPI + 0.5 * phipp));
+ return xy;
}
-INVERSE(e_inverse); /* ellipsoid & spheroid */
- double phip, lamp, phipp, lampp, cp, esp, con, delp;
- int i;
-
- phipp = 2. * (atan(exp(xy.y / P->kR)) - FORTPI);
- lampp = xy.x / P->kR;
- cp = cos(phipp);
- phip = aasin(P->ctx,P->cosp0 * sin(phipp) + P->sinp0 * cp * cos(lampp));
- lamp = aasin(P->ctx,cp * sin(lampp) / cos(phip));
- con = (P->K - log(tan(FORTPI + 0.5 * phip)))/P->c;
- for (i = NITER; i ; --i) {
- esp = P->e * sin(phip);
- delp = (con + log(tan(FORTPI + 0.5 * phip)) - P->hlf_e *
- log((1. + esp)/(1. - esp)) ) *
- (1. - esp * esp) * cos(phip) * P->rone_es;
- phip -= delp;
- if (fabs(delp) < EPS)
- break;
- }
- if (i) {
- lp.phi = phip;
- lp.lam = lamp / P->c;
- } else
- I_ERROR
- return (lp);
+
+
+static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double phip, lamp, phipp, lampp, cp, esp, con, delp;
+ int i;
+
+ phipp = 2. * (atan (exp (xy.y / Q->kR)) - FORTPI);
+ lampp = xy.x / Q->kR;
+ cp = cos (phipp);
+ phip = aasin (P->ctx, Q->cosp0 * sin (phipp) + Q->sinp0 * cp * cos (lampp));
+ lamp = aasin (P->ctx, cp * sin (lampp) / cos (phip));
+ con = (Q->K - log (tan (FORTPI + 0.5 * phip)))/Q->c;
+ for (i = NITER; i ; --i) {
+ esp = P->e * sin(phip);
+ delp = (con + log(tan(FORTPI + 0.5 * phip)) - Q->hlf_e *
+ log((1. + esp)/(1. - esp)) ) *
+ (1. - esp * esp) * cos(phip) * P->rone_es;
+ phip -= delp;
+ if (fabs(delp) < EPS)
+ break;
+ }
+ if (i) {
+ lp.phi = phip;
+ lp.lam = lamp / Q->c;
+ } else
+ I_ERROR
+ return (lp);
}
+
+
+#if 0
FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(somerc)
- double cp, phip0, sp;
-
- P->hlf_e = 0.5 * P->e;
- cp = cos(P->phi0);
- cp *= cp;
- P->c = sqrt(1 + P->es * cp * cp * P->rone_es);
- sp = sin(P->phi0);
- P->cosp0 = cos( phip0 = aasin(P->ctx, P->sinp0 = sp / P->c) );
- sp *= P->e;
- P->K = log(tan(FORTPI + 0.5 * phip0)) - P->c * (
- log(tan(FORTPI + 0.5 * P->phi0)) - P->hlf_e *
- log((1. + sp) / (1. - sp)));
- P->kR = P->k0 * sqrt(P->one_es) / (1. - sp * sp);
- P->inv = e_inverse;
- P->fwd = e_forward;
-ENDENTRY(P)
+#endif
+
+
+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(somerc) {
+ double cp, phip0, sp;
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+
+ Q->hlf_e = 0.5 * P->e;
+ cp = cos (P->phi0);
+ cp *= cp;
+ Q->c = sqrt (1 + P->es * cp * cp * P->rone_es);
+ sp = sin (P->phi0);
+ Q->cosp0 = cos( phip0 = aasin (P->ctx, Q->sinp0 = sp / Q->c) );
+ sp *= P->e;
+ Q->K = log (tan (FORTPI + 0.5 * phip0)) - Q->c * (
+ log (tan (FORTPI + 0.5 * P->phi0)) - Q->hlf_e *
+ log ((1. + sp) / (1. - sp)));
+ Q->kR = P->k0 * sqrt(P->one_es) / (1. - sp * sp);
+ P->inv = e_inverse;
+ P->fwd = e_forward;
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_somerc_selftest (void) {return 0;}
+#else
+
+int pj_somerc_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=somerc +ellps=GRS80 +lat_1=0.5 +lat_2=2 +n=0.5"};
+ char s_args[] = {"+proj=somerc +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[] = {
+ {222638.98158654713, 110579.96521824898},
+ {222638.98158654713, -110579.96521825089},
+ {-222638.98158654713, 110579.96521824898},
+ {-222638.98158654713, -110579.96521825089},
+ };
+
+ XY s_fwd_expect[] = {
+ {223402.14425527418, 111706.74357494408},
+ {223402.14425527418, -111706.74357494518},
+ {-223402.14425527418, 111706.74357494408},
+ {-223402.14425527418, -111706.74357494518},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ {0.0017966305682390426, 0.00090436947704129484},
+ {0.0017966305682390426, -0.00090436947704377105},
+ {-0.0017966305682390426, 0.00090436947704129484},
+ {-0.0017966305682390426, -0.00090436947704377105},
+ };
+
+ LP s_inv_expect[] = {
+ {0.0017904931097838226, 0.00089524655485801927},
+ {0.0017904931097838226, -0.00089524655484529714},
+ {-0.0017904931097838226, 0.00089524655485801927},
+ {-0.0017904931097838226, -0.00089524655484529714},
+ };
+
+ 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_stere.c b/src/PJ_stere.c
index a0524627..fbca195f 100644
--- a/src/PJ_stere.c
+++ b/src/PJ_stere.c
@@ -1,239 +1,409 @@
-#define PROJ_PARMS__ \
- double phits; \
- double sinX1; \
- double cosX1; \
- double akm1; \
- int mode;
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(stere, "Stereographic") "\n\tAzi, Sph&Ell\n\tlat_ts=";
PROJ_HEAD(ups, "Universal Polar Stereographic") "\n\tAzi, Sph&Ell\n\tsouth";
-#define sinph0 P->sinX1
-#define cosph0 P->cosX1
-#define EPS10 1.e-10
-#define TOL 1.e-8
-#define NITER 8
-#define CONV 1.e-10
-#define S_POLE 0
-#define N_POLE 1
-#define OBLIQ 2
-#define EQUIT 3
- static double
-ssfn_(double phit, double sinphi, double eccen) {
- sinphi *= eccen;
- return (tan (.5 * (HALFPI + phit)) *
- pow((1. - sinphi) / (1. + sinphi), .5 * eccen));
+
+
+struct pj_opaque {
+ double phits;
+ double sinX1;
+ double cosX1;
+ double akm1;
+ int mode;
+};
+
+#define sinph0 P->opaque->sinX1
+#define cosph0 P->opaque->cosX1
+#define EPS10 1.e-10
+#define TOL 1.e-8
+#define NITER 8
+#define CONV 1.e-10
+#define S_POLE 0
+#define N_POLE 1
+#define OBLIQ 2
+#define EQUIT 3
+
+static double ssfn_ (double phit, double sinphi, double eccen) {
+ sinphi *= eccen;
+ return (tan (.5 * (HALFPI + phit)) *
+ pow ((1. - sinphi) / (1. + sinphi), .5 * eccen));
}
-FORWARD(e_forward); /* ellipsoid */
- double coslam, sinlam, sinX=0.0, cosX=0.0, X, A, sinphi;
-
- coslam = cos(lp.lam);
- sinlam = sin(lp.lam);
- sinphi = sin(lp.phi);
- if (P->mode == OBLIQ || P->mode == EQUIT) {
- sinX = sin(X = 2. * atan(ssfn_(lp.phi, sinphi, P->e)) - HALFPI);
- cosX = cos(X);
- }
- switch (P->mode) {
- case OBLIQ:
- A = P->akm1 / (P->cosX1 * (1. + P->sinX1 * sinX +
- P->cosX1 * cosX * coslam));
- xy.y = A * (P->cosX1 * sinX - P->sinX1 * cosX * coslam);
- goto xmul;
- case EQUIT:
- A = 2. * P->akm1 / (1. + cosX * coslam);
- xy.y = A * sinX;
+
+
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double coslam, sinlam, sinX = 0.0, cosX = 0.0, X, A, sinphi;
+
+ coslam = cos (lp.lam);
+ sinlam = sin (lp.lam);
+ sinphi = sin (lp.phi);
+ if (Q->mode == OBLIQ || Q->mode == EQUIT) {
+ sinX = sin (X = 2. * atan(ssfn_(lp.phi, sinphi, P->e)) - HALFPI);
+ cosX = cos (X);
+ }
+
+ switch (Q->mode) {
+ case OBLIQ:
+ A = Q->akm1 / (Q->cosX1 * (1. + Q->sinX1 * sinX +
+ Q->cosX1 * cosX * coslam));
+ xy.y = A * (Q->cosX1 * sinX - Q->sinX1 * cosX * coslam);
+ goto xmul; /* but why not just xy.x = A * cosX; break; ? */
+
+ case EQUIT:
+ A = 2. * Q->akm1 / (1. + cosX * coslam);
+ xy.y = A * sinX;
xmul:
- xy.x = A * cosX;
- break;
- case S_POLE:
- lp.phi = -lp.phi;
- coslam = - coslam;
- sinphi = -sinphi;
- case N_POLE:
- xy.x = P->akm1 * pj_tsfn(lp.phi, sinphi, P->e);
- xy.y = - xy.x * coslam;
- break;
- }
- xy.x = xy.x * sinlam;
- return (xy);
+ xy.x = A * cosX;
+ break;
+
+ case S_POLE:
+ lp.phi = -lp.phi;
+ coslam = - coslam;
+ sinphi = -sinphi;
+ case N_POLE:
+ xy.x = Q->akm1 * pj_tsfn (lp.phi, sinphi, P->e);
+ xy.y = - xy.x * coslam;
+ break;
+ }
+
+ xy.x = xy.x * sinlam;
+ return xy;
}
-FORWARD(s_forward); /* spheroid */
- double sinphi, cosphi, coslam, sinlam;
-
- sinphi = sin(lp.phi);
- cosphi = cos(lp.phi);
- coslam = cos(lp.lam);
- sinlam = sin(lp.lam);
- switch (P->mode) {
- case EQUIT:
- xy.y = 1. + cosphi * coslam;
- goto oblcon;
- case OBLIQ:
- xy.y = 1. + sinph0 * sinphi + cosph0 * cosphi * coslam;
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double sinphi, cosphi, coslam, sinlam;
+
+ sinphi = sin(lp.phi);
+ cosphi = cos(lp.phi);
+ coslam = cos(lp.lam);
+ sinlam = sin(lp.lam);
+
+ switch (Q->mode) {
+ case EQUIT:
+ xy.y = 1. + cosphi * coslam;
+ goto oblcon;
+ case OBLIQ:
+ xy.y = 1. + sinph0 * sinphi + cosph0 * cosphi * coslam;
oblcon:
- if (xy.y <= EPS10) F_ERROR;
- xy.x = (xy.y = P->akm1 / xy.y) * cosphi * sinlam;
- xy.y *= (P->mode == EQUIT) ? sinphi :
- cosph0 * sinphi - sinph0 * cosphi * coslam;
- break;
- case N_POLE:
- coslam = - coslam;
- lp.phi = - lp.phi;
- case S_POLE:
- if (fabs(lp.phi - HALFPI) < TOL) F_ERROR;
- xy.x = sinlam * ( xy.y = P->akm1 * tan(FORTPI + .5 * lp.phi) );
- xy.y *= coslam;
- break;
- }
- return (xy);
+ if (xy.y <= EPS10) F_ERROR;
+ xy.x = (xy.y = Q->akm1 / xy.y) * cosphi * sinlam;
+ xy.y *= (Q->mode == EQUIT) ? sinphi :
+ cosph0 * sinphi - sinph0 * cosphi * coslam;
+ break;
+ case N_POLE:
+ coslam = - coslam;
+ lp.phi = - lp.phi;
+ case S_POLE:
+ if (fabs (lp.phi - HALFPI) < TOL) F_ERROR;
+ xy.x = sinlam * ( xy.y = Q->akm1 * tan (FORTPI + .5 * lp.phi) );
+ xy.y *= coslam;
+ break;
+ }
+ return xy;
}
-INVERSE(e_inverse); /* ellipsoid */
- double cosphi, sinphi, tp=0.0, phi_l=0.0, rho, halfe=0.0, halfpi=0.0;
- int i;
-
- rho = hypot(xy.x, xy.y);
- switch (P->mode) {
- case OBLIQ:
- case EQUIT:
- cosphi = cos( tp = 2. * atan2(rho * P->cosX1 , P->akm1) );
- sinphi = sin(tp);
- if( rho == 0.0 )
- phi_l = asin(cosphi * P->sinX1);
+
+
+static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double cosphi, sinphi, tp=0.0, phi_l=0.0, rho, halfe=0.0, halfpi=0.0;
+ int i;
+
+ rho = hypot (xy.x, xy.y);
+
+ switch (Q->mode) {
+ case OBLIQ:
+ case EQUIT:
+ cosphi = cos ( tp = 2. * atan2 (rho * Q->cosX1 , Q->akm1) );
+ sinphi = sin (tp);
+ if ( rho == 0.0 )
+ phi_l = asin (cosphi * Q->sinX1);
else
- phi_l = asin(cosphi * P->sinX1 + (xy.y * sinphi * P->cosX1 / rho));
-
- tp = tan(.5 * (HALFPI + phi_l));
- xy.x *= sinphi;
- xy.y = rho * P->cosX1 * cosphi - xy.y * P->sinX1* sinphi;
- halfpi = HALFPI;
- halfe = .5 * P->e;
- break;
- case N_POLE:
- xy.y = -xy.y;
- case S_POLE:
- phi_l = HALFPI - 2. * atan(tp = - rho / P->akm1);
- halfpi = -HALFPI;
- halfe = -.5 * P->e;
- break;
- }
- for (i = NITER; i--; phi_l = lp.phi) {
- sinphi = P->e * sin(phi_l);
- lp.phi = 2. * atan(tp * pow((1.+sinphi)/(1.-sinphi),
- halfe)) - halfpi;
- if (fabs(phi_l - lp.phi) < CONV) {
- if (P->mode == S_POLE)
- lp.phi = -lp.phi;
- lp.lam = (xy.x == 0. && xy.y == 0.) ? 0. : atan2(xy.x, xy.y);
- return (lp);
- }
- }
- I_ERROR;
+ phi_l = asin (cosphi * Q->sinX1 + (xy.y * sinphi * Q->cosX1 / rho));
+
+ tp = tan (.5 * (HALFPI + phi_l));
+ xy.x *= sinphi;
+ xy.y = rho * Q->cosX1 * cosphi - xy.y * Q->sinX1* sinphi;
+ halfpi = HALFPI;
+ halfe = .5 * P->e;
+ break;
+ case N_POLE:
+ xy.y = -xy.y;
+ case S_POLE:
+ phi_l = HALFPI - 2. * atan (tp = - rho / Q->akm1);
+ halfpi = -HALFPI;
+ halfe = -.5 * P->e;
+ break;
+ }
+
+ for (i = NITER; i--; phi_l = lp.phi) {
+ sinphi = P->e * sin(phi_l);
+ lp.phi = 2. * atan (tp * pow ((1.+sinphi)/(1.-sinphi), halfe)) - halfpi;
+ if (fabs (phi_l - lp.phi) < CONV) {
+ if (Q->mode == S_POLE)
+ lp.phi = -lp.phi;
+ lp.lam = (xy.x == 0. && xy.y == 0.) ? 0. : atan2 (xy.x, xy.y);
+ return lp;
+ }
+ }
+ I_ERROR;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double c, rh, sinc, cosc;
+
+ sinc = sin (c = 2. * atan ((rh = hypot (xy.x, xy.y)) / Q->akm1));
+ cosc = cos (c);
+ lp.lam = 0.;
+
+ switch (Q->mode) {
+ case EQUIT:
+ if (fabs (rh) <= EPS10)
+ lp.phi = 0.;
+ else
+ lp.phi = asin (xy.y * sinc / rh);
+ if (cosc != 0. || xy.x != 0.)
+ lp.lam = atan2 (xy.x * sinc, cosc * rh);
+ break;
+ case OBLIQ:
+ if (fabs (rh) <= EPS10)
+ lp.phi = P->phi0;
+ else
+ lp.phi = asin (cosc * sinph0 + xy.y * sinc * cosph0 / rh);
+ if ((c = cosc - sinph0 * sin (lp.phi)) != 0. || xy.x != 0.)
+ lp.lam = atan2 (xy.x * sinc * cosph0, c * rh);
+ break;
+ case N_POLE:
+ xy.y = -xy.y;
+ case S_POLE:
+ if (fabs (rh) <= EPS10)
+ lp.phi = P->phi0;
+ else
+ lp.phi = asin (Q->mode == S_POLE ? - cosc : cosc);
+ lp.lam = (xy.x == 0. && xy.y == 0.) ? 0. : atan2 (xy.x, xy.y);
+ break;
+ }
+ return lp;
}
-INVERSE(s_inverse); /* spheroid */
- double c, rh, sinc, cosc;
-
- sinc = sin(c = 2. * atan((rh = hypot(xy.x, xy.y)) / P->akm1));
- cosc = cos(c);
- lp.lam = 0.;
- switch (P->mode) {
- case EQUIT:
- if (fabs(rh) <= EPS10)
- lp.phi = 0.;
- else
- lp.phi = asin(xy.y * sinc / rh);
- if (cosc != 0. || xy.x != 0.)
- lp.lam = atan2(xy.x * sinc, cosc * rh);
- break;
- case OBLIQ:
- if (fabs(rh) <= EPS10)
- lp.phi = P->phi0;
- else
- lp.phi = asin(cosc * sinph0 + xy.y * sinc * cosph0 / rh);
- if ((c = cosc - sinph0 * sin(lp.phi)) != 0. || xy.x != 0.)
- lp.lam = atan2(xy.x * sinc * cosph0, c * rh);
- break;
- case N_POLE:
- xy.y = -xy.y;
- case S_POLE:
- if (fabs(rh) <= EPS10)
- lp.phi = P->phi0;
- else
- lp.phi = asin(P->mode == S_POLE ? - cosc : cosc);
- lp.lam = (xy.x == 0. && xy.y == 0.) ? 0. : atan2(xy.x, xy.y);
- break;
- }
- return (lp);
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+ pj_dealloc (P->opaque);
+ return pj_dealloc(P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+static PJ *setup(PJ *P) { /* general initialization */
+ double t;
+ struct pj_opaque *Q = P->opaque;
+
+ if (fabs ((t = fabs (P->phi0)) - HALFPI) < EPS10)
+ Q->mode = P->phi0 < 0. ? S_POLE : N_POLE;
+ else
+ Q->mode = t > EPS10 ? OBLIQ : EQUIT;
+ Q->phits = fabs (Q->phits);
+
+ if (P->es) {
+ double X;
+
+ switch (Q->mode) {
+ case N_POLE:
+ case S_POLE:
+ if (fabs (Q->phits - HALFPI) < EPS10)
+ Q->akm1 = 2. * P->k0 /
+ sqrt (pow (1+P->e,1+P->e) * pow (1-P->e,1-P->e));
+ else {
+ Q->akm1 = cos (Q->phits) /
+ pj_tsfn (Q->phits, t = sin (Q->phits), P->e);
+ t *= P->e;
+ Q->akm1 /= sqrt(1. - t * t);
+ }
+ break;
+ case EQUIT:
+ case OBLIQ:
+ t = sin (P->phi0);
+ X = 2. * atan (ssfn_(P->phi0, t, P->e)) - HALFPI;
+ t *= P->e;
+ Q->akm1 = 2. * P->k0 * cos (P->phi0) / sqrt(1. - t * t);
+ Q->sinX1 = sin (X);
+ Q->cosX1 = cos (X);
+ break;
+ }
+ P->inv = e_inverse;
+ P->fwd = e_forward;
+ } else {
+ switch (Q->mode) {
+ case OBLIQ:
+ sinph0 = sin (P->phi0);
+ cosph0 = cos (P->phi0);
+ case EQUIT:
+ Q->akm1 = 2. * P->k0;
+ break;
+ case S_POLE:
+ case N_POLE:
+ Q->akm1 = fabs (Q->phits - HALFPI) >= EPS10 ?
+ cos (Q->phits) / tan (FORTPI - .5 * Q->phits) :
+ 2. * P->k0 ;
+ break;
+ }
+
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+ }
+ return P;
}
-FREEUP; if (P) pj_dalloc(P); }
- static PJ *
-setup(PJ *P) { /* general initialization */
- double t;
-
- if (fabs((t = fabs(P->phi0)) - HALFPI) < EPS10)
- P->mode = P->phi0 < 0. ? S_POLE : N_POLE;
- else
- P->mode = t > EPS10 ? OBLIQ : EQUIT;
- P->phits = fabs(P->phits);
- if (P->es) {
- double X;
-
- switch (P->mode) {
- case N_POLE:
- case S_POLE:
- if (fabs(P->phits - HALFPI) < EPS10)
- P->akm1 = 2. * P->k0 /
- sqrt(pow(1+P->e,1+P->e)*pow(1-P->e,1-P->e));
- else {
- P->akm1 = cos(P->phits) /
- pj_tsfn(P->phits, t = sin(P->phits), P->e);
- t *= P->e;
- P->akm1 /= sqrt(1. - t * t);
- }
- break;
- case EQUIT:
- case OBLIQ:
- t = sin(P->phi0);
- X = 2. * atan(ssfn_(P->phi0, t, P->e)) - HALFPI;
- t *= P->e;
- P->akm1 = 2. * P->k0 * cos(P->phi0) / sqrt(1. - t * t);
- P->sinX1 = sin(X);
- P->cosX1 = cos(X);
- break;
- }
- P->inv = e_inverse;
- P->fwd = e_forward;
- } else {
- switch (P->mode) {
- case OBLIQ:
- sinph0 = sin(P->phi0);
- cosph0 = cos(P->phi0);
- case EQUIT:
- P->akm1 = 2. * P->k0;
- break;
- case S_POLE:
- case N_POLE:
- P->akm1 = fabs(P->phits - HALFPI) >= EPS10 ?
- cos(P->phits) / tan(FORTPI - .5 * P->phits) :
- 2. * P->k0 ;
- break;
- }
- P->inv = s_inverse;
- P->fwd = s_forward;
- }
- return P;
+
+
+PJ *PROJECTION(stere) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->phits = pj_param (P->ctx, P->params, "tlat_ts").i ?
+ pj_param (P->ctx, P->params, "rlat_ts").f : HALFPI;
+
+ return setup(P);
}
-ENTRY0(stere)
- P->phits = pj_param(P->ctx, P->params, "tlat_ts").i ?
- pj_param(P->ctx, P->params, "rlat_ts").f : HALFPI;
-ENDENTRY(setup(P))
-ENTRY0(ups)
+
+
+PJ *PROJECTION(ups) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
/* International Ellipsoid */
P->phi0 = pj_param(P->ctx, P->params, "bsouth").i ? - HALFPI: HALFPI;
if (!P->es) E_ERROR(-34);
P->k0 = .994;
P->x0 = 2000000.;
P->y0 = 2000000.;
- P->phits = HALFPI;
+ Q->phits = HALFPI;
P->lam0 = 0.;
-ENDENTRY(setup(P))
+
+ return setup(P);
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_stere_selftest (void) {return 0;}
+#else
+
+int pj_stere_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=stere +ellps=GRS80 +lat_1=0.5 +lat_2=2 +n=0.5"};
+ char s_args[] = {"+proj=stere +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[] = {
+ { 445289.70910023432, 221221.76694834774},
+ { 445289.70910023432, -221221.76694835056},
+ {-445289.70910023432, 221221.76694834774},
+ {-445289.70910023432, -221221.76694835056},
+ };
+
+ XY s_fwd_expect[] = {
+ { 223407.81025950745, 111737.938996443},
+ { 223407.81025950745, -111737.938996443},
+ {-223407.81025950745, 111737.938996443},
+ {-223407.81025950745, -111737.938996443},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ { 0.0017966305682022392, 0.00090436947502443507},
+ { 0.0017966305682022392, -0.00090436947502443507},
+ {-0.0017966305682022392, 0.00090436947502443507},
+ {-0.0017966305682022392, -0.00090436947502443507},
+ };
+
+ LP s_inv_expect[] = {
+ { 0.001790493109747395, 0.00089524655465513144},
+ { 0.001790493109747395, -0.00089524655465513144},
+ {-0.001790493109747395, 0.00089524655465513144},
+ {-0.001790493109747395, -0.00089524655465513144},
+ };
+
+ 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
+
+
+
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_ups_selftest (void) {return 0;}
+#else
+
+int pj_ups_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=ups +ellps=GRS80 +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[] = {
+ {2433455.5634384668, -10412543.301512826},
+ {2448749.1185681992, -10850493.419804076},
+ {1566544.4365615332, -10412543.301512826},
+ {1551250.8814318008, -10850493.419804076},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ {-44.998567498074834, 64.9182362867341},
+ {-44.995702709112308, 64.917020250675748},
+ {-45.004297076028529, 64.915804280954518},
+ {-45.001432287066002, 64.914588377560719},
+ };
+
+ return pj_generic_selftest (e_args, 0, tolerance_xy, tolerance_lp, 4, 4, fwd_in, e_fwd_expect, 0, inv_in, e_inv_expect, 0);
+}
+
+
+#endif
diff --git a/src/PJ_sterea.c b/src/PJ_sterea.c
index fff2e952..93799011 100644
--- a/src/PJ_sterea.c
+++ b/src/PJ_sterea.c
@@ -23,61 +23,156 @@
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#define PROJ_PARMS__ \
- double phic0; \
- double cosc0, sinc0; \
- double R2; \
- void *en;
-
#define PJ_LIB__
-#include <projects.h>
-
-PROJ_HEAD(sterea, "Oblique Stereographic Alternative")
- "\n\tAzimuthal, Sph&Ell";
-# define DEL_TOL 1.e-14
-# define MAX_ITER 10
-
-FORWARD(e_forward); /* ellipsoid */
- double cosc, sinc, cosl, k;
-
- lp = pj_gauss(P->ctx, lp, P->en);
- sinc = sin(lp.phi);
- cosc = cos(lp.phi);
- cosl = cos(lp.lam);
- k = P->k0 * P->R2 / (1. + P->sinc0 * sinc + P->cosc0 * cosc * cosl);
- xy.x = k * cosc * sin(lp.lam);
- xy.y = k * (P->cosc0 * sinc - P->sinc0 * cosc * cosl);
- return (xy);
+#include <projects.h>
+
+
+struct pj_opaque {
+ double phic0;
+ double cosc0, sinc0;
+ double R2;
+ void *en;
+};
+
+
+PROJ_HEAD(sterea, "Oblique Stereographic Alternative") "\n\tAzimuthal, Sph&Ell";
+# define DEL_TOL 1.e-14
+# define MAX_ITER 10
+
+
+
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double cosc, sinc, cosl, k;
+
+ lp = pj_gauss(P->ctx, lp, Q->en);
+ sinc = sin(lp.phi);
+ cosc = cos(lp.phi);
+ cosl = cos(lp.lam);
+ k = P->k0 * Q->R2 / (1. + Q->sinc0 * sinc + Q->cosc0 * cosc * cosl);
+ xy.x = k * cosc * sin(lp.lam);
+ xy.y = k * (Q->cosc0 * sinc - Q->sinc0 * cosc * cosl);
+ 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 rho, c, sinc, cosc;
+
+ xy.x /= P->k0;
+ xy.y /= P->k0;
+ if ( (rho = hypot (xy.x, xy.y)) ) {
+ c = 2. * atan2 (rho, Q->R2);
+ sinc = sin (c);
+ cosc = cos (c);
+ lp.phi = asin (cosc * Q->sinc0 + xy.y * sinc * Q->cosc0 / rho);
+ lp.lam = atan2 (xy.x * sinc, rho * Q->cosc0 * cosc - xy.y * Q->sinc0 * sinc);
+ } else {
+ lp.phi = Q->phic0;
+ lp.lam = 0.;
+ }
+ return pj_inv_gauss(P->ctx, lp, Q->en);
+}
+
+
+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);
+}
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
}
-INVERSE(e_inverse); /* ellipsoid */
- double rho, c, sinc, cosc;
-
- xy.x /= P->k0;
- xy.y /= P->k0;
- if((rho = hypot(xy.x, xy.y))) {
- c = 2. * atan2(rho, P->R2);
- sinc = sin(c);
- cosc = cos(c);
- lp.phi = asin(cosc * P->sinc0 + xy.y * sinc * P->cosc0 / rho);
- lp.lam = atan2(xy.x * sinc, rho * P->cosc0 * cosc -
- xy.y * P->sinc0 * sinc);
- } else {
- lp.phi = P->phic0;
- lp.lam = 0.;
- }
- return(pj_inv_gauss(P->ctx, lp, P->en));
+
+
+PJ *PROJECTION(sterea) {
+ double R;
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->en = pj_gauss_ini(P->e, P->phi0, &(Q->phic0), &R);
+ if (0==Q->en)
+ return freeup_new (P);
+
+ Q->sinc0 = sin (Q->phic0);
+ Q->cosc0 = cos (Q->phic0);
+ Q->R2 = 2. * R;
+
+ P->inv = e_inverse;
+ P->fwd = e_forward;
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_sterea_selftest (void) {return 0;}
+#else
+
+int pj_sterea_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=sterea +ellps=GRS80 +lat_1=0.5 +lat_2=2 +n=0.5"};
+ char s_args[] = {"+proj=sterea +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[] = {
+ { 222644.89410919772, 110611.09187173686},
+ { 222644.89410919772, -110611.09187173827},
+ {-222644.89410919772, 110611.09187173686},
+ {-222644.89410919772, -110611.09187173827},
+ };
+
+ XY s_fwd_expect[] = {
+ { 223407.81025950745, 111737.93899644315},
+ { 223407.81025950745, -111737.93899644315},
+ {-223407.81025950745, 111737.93899644315},
+ {-223407.81025950745, -111737.93899644315},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ { 0.0017966305682019911, 0.00090436947683099009},
+ { 0.0017966305682019911, -0.00090436947684371233},
+ {-0.0017966305682019911, 0.00090436947683099009},
+ {-0.0017966305682019911, -0.00090436947684371233},
+ };
+
+ LP s_inv_expect[] = {
+ { 0.001790493109747395, 0.00089524655465446378},
+ { 0.001790493109747395, -0.00089524655465446378},
+ {-0.001790493109747395, 0.00089524655465446378},
+ {-0.001790493109747395, -0.00089524655465446378},
+ };
+
+ 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);
}
-FREEUP; if (P) { if (P->en) free(P->en); free(P); } }
-ENTRYA(sterea)
-
- P->en=0;
-ENTRYX
- double R;
-
- if (!(P->en = pj_gauss_ini(P->e, P->phi0, &(P->phic0), &R))) E_ERROR_0;
- P->sinc0 = sin(P->phic0);
- P->cosc0 = cos(P->phic0);
- P->R2 = 2. * R;
- P->inv = e_inverse;
- P->fwd = e_forward;
-ENDENTRY(P)
+
+
+#endif
diff --git a/src/PJ_sts.c b/src/PJ_sts.c
index c35d5cfc..347a7303 100644
--- a/src/PJ_sts.c
+++ b/src/PJ_sts.c
@@ -1,54 +1,351 @@
-#define PROJ_PARMS__ \
- double C_x, C_y, C_p; \
- int tan_mode;
#define PJ_LIB__
# include <projects.h>
-PROJ_HEAD(kav5, "Kavraisky V") "\n\tPCyl., Sph.";
-PROJ_HEAD(qua_aut, "Quartic Authalic") "\n\tPCyl., Sph.";
-PROJ_HEAD(mbt_s, "McBryde-Thomas Flat-Polar Sine (No. 1)") "\n\tPCyl., Sph.";
-PROJ_HEAD(fouc, "Foucaut") "\n\tPCyl., Sph.";
-FORWARD(s_forward); /* spheroid */
+
+PROJ_HEAD(kav5, "Kavraisky V") "\n\tPCyl., Sph.";
+PROJ_HEAD(qua_aut, "Quartic Authalic") "\n\tPCyl., Sph.";
+PROJ_HEAD(fouc, "Foucaut") "\n\tPCyl., Sph.";
+PROJ_HEAD(mbt_s, "McBryde-Thomas Flat-Polar Sine (No. 1)") "\n\tPCyl., Sph.";
+
+
+struct pj_opaque {
+ double C_x, C_y, C_p; \
+ int tan_mode;
+};
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
double c;
- xy.x = P->C_x * lp.lam * cos(lp.phi);
- xy.y = P->C_y;
- lp.phi *= P->C_p;
+ xy.x = Q->C_x * lp.lam * cos(lp.phi);
+ xy.y = Q->C_y;
+ lp.phi *= Q->C_p;
c = cos(lp.phi);
- if (P->tan_mode) {
+ if (Q->tan_mode) {
xy.x *= c * c;
- xy.y *= tan(lp.phi);
+ xy.y *= tan (lp.phi);
} else {
xy.x /= c;
- xy.y *= sin(lp.phi);
+ xy.y *= sin (lp.phi);
}
- return (xy);
+ return xy;
}
-INVERSE(s_inverse); /* spheroid */
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
double c;
-
- xy.y /= P->C_y;
- c = cos(lp.phi = P->tan_mode ? atan(xy.y) : aasin(P->ctx,xy.y));
- lp.phi /= P->C_p;
- lp.lam = xy.x / (P->C_x * cos(lp.phi));
- if (P->tan_mode)
+
+ xy.y /= Q->C_y;
+ c = cos (lp.phi = Q->tan_mode ? atan (xy.y) : aasin (P->ctx, xy.y));
+ lp.phi /= Q->C_p;
+ lp.lam = xy.x / (Q->C_x * cos(lp.phi));
+ if (Q->tan_mode)
lp.lam /= c * c;
else
lp.lam *= c;
- return (lp);
+ return lp;
+}
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+ pj_dealloc (P->opaque);
+ return pj_dealloc(P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
}
-FREEUP; if (P) pj_dalloc(P); }
- static PJ *
-setup(PJ *P, double p, double q, int mode) {
- P->es = 0.;
+
+
+static PJ *setup(PJ *P, double p, double q, int mode) {
+ P->es = 0.;
P->inv = s_inverse;
P->fwd = s_forward;
- P->C_x = q / p;
- P->C_y = p;
- P->C_p = 1/ q;
- P->tan_mode = mode;
+ P->opaque->C_x = q / p;
+ P->opaque->C_y = p;
+ P->opaque->C_p = 1/ q;
+ P->opaque->tan_mode = mode;
return P;
}
-ENTRY0(kav5) ENDENTRY(setup(P, 1.50488, 1.35439, 0))
-ENTRY0(qua_aut) ENDENTRY(setup(P, 2., 2., 0))
-ENTRY0(mbt_s) ENDENTRY(setup(P, 1.48875, 1.36509, 0))
-ENTRY0(fouc) ENDENTRY(setup(P, 2., 2., 1))
+
+
+
+
+
+PJ *PROJECTION(fouc) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+ return setup(P, 2., 2., 1);
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_fouc_selftest (void) {return 0;}
+#else
+int pj_fouc_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=fouc +ellps=GRS80 +lat_1=0.5 +lat_2=2 +n=0.5"};
+ char s_args[] = {"+proj=fouc +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[] = {
+ {222588.12067589167, 111322.31670069379},
+ {222588.12067589167, -111322.31670069379},
+ {-222588.12067589167, 111322.31670069379},
+ {-222588.12067589167, -111322.31670069379},
+ };
+
+ XY s_fwd_expect[] = {
+ {223351.10900341379, 111703.9077217125},
+ {223351.10900341379, -111703.9077217125},
+ {-223351.10900341379, 111703.9077217125},
+ {-223351.10900341379, -111703.9077217125},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ {0.0017966305685702751, 0.00089831528410111959},
+ {0.0017966305685702751, -0.00089831528410111959},
+ {-0.0017966305685702751, 0.00089831528410111959},
+ {-0.0017966305685702751, -0.00089831528410111959},
+ };
+
+ LP s_inv_expect[] = {
+ {0.0017904931101116717, 0.00089524655487369749},
+ {0.0017904931101116717, -0.00089524655487369749},
+ {-0.0017904931101116717, 0.00089524655487369749},
+ {-0.0017904931101116717, -0.00089524655487369749},
+ };
+
+ 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
+
+
+
+
+
+
+PJ *PROJECTION(kav5) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ return setup(P, 1.50488, 1.35439, 0);
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_kav5_selftest (void) {return 0;}
+#else
+int pj_kav5_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=kav5 +ellps=GRS80 +lat_1=0.5 +lat_2=2 +n=0.5"};
+ char s_args[] = {"+proj=kav5 +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[] = {
+ {200360.90530882866, 123685.08247699818},
+ {200360.90530882866, -123685.08247699818},
+ {-200360.90530882866, 123685.08247699818},
+ {-200360.90530882866, -123685.08247699818},
+ };
+
+ XY s_fwd_expect[] = {
+ {201047.7031108776, 124109.05062917093},
+ {201047.7031108776, -124109.05062917093},
+ {-201047.7031108776, 124109.05062917093},
+ {-201047.7031108776, -124109.05062917093},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ {0.0019962591348533314, 0.00080848256185253912},
+ {0.0019962591348533314, -0.00080848256185253912},
+ {-0.0019962591348533314, 0.00080848256185253912},
+ {-0.0019962591348533314, -0.00080848256185253912},
+ };
+
+ LP s_inv_expect[] = {
+ {0.0019894397264987643, 0.00080572070962591153},
+ {0.0019894397264987643, -0.00080572070962591153},
+ {-0.0019894397264987643, 0.00080572070962591153},
+ {-0.0019894397264987643, -0.00080572070962591153},
+ };
+
+ 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
+
+
+
+
+
+PJ *PROJECTION(qua_aut) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+ return setup(P, 2., 2., 0);
+}
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_qua_aut_selftest (void) {return 0;}
+#else
+int pj_qua_aut_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=qua_aut +ellps=GRS80 +lat_1=0.5 +lat_2=2 +n=0.5"};
+ char s_args[] = {"+proj=qua_aut +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[] = {
+ {222613.54903309655, 111318.07788798446},
+ {222613.54903309655, -111318.07788798446},
+ {-222613.54903309655, 111318.07788798446},
+ {-222613.54903309655, -111318.07788798446},
+ };
+
+ XY s_fwd_expect[] = {
+ {223376.62452402918, 111699.65437918637},
+ {223376.62452402918, -111699.65437918637},
+ {-223376.62452402918, 111699.65437918637},
+ {-223376.62452402918, -111699.65437918637},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ {0.0017966305684046586, 0.00089831528412872229},
+ {0.0017966305684046586, -0.00089831528412872229},
+ {-0.0017966305684046586, 0.00089831528412872229},
+ {-0.0017966305684046586, -0.00089831528412872229},
+ };
+
+ LP s_inv_expect[] = {
+ {0.0017904931099477471, 0.00089524655490101819},
+ {0.0017904931099477471, -0.00089524655490101819},
+ {-0.0017904931099477471, 0.00089524655490101819},
+ {-0.0017904931099477471, -0.00089524655490101819},
+ };
+
+ 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
+
+
+
+
+
+PJ *PROJECTION(mbt_s) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+ return setup(P, 1.48875, 1.36509, 0);
+}
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_mbt_s_selftest (void) {return 0;}
+#else
+int pj_mbt_s_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=mbt_s +ellps=GRS80 +lat_1=0.5 +lat_2=2 +n=0.5"};
+ char s_args[] = {"+proj=mbt_s +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[] = {
+ {204131.51785027285, 121400.33022550763},
+ {204131.51785027285, -121400.33022550763},
+ {-204131.51785027285, 121400.33022550763},
+ {-204131.51785027285, -121400.33022550763},
+ };
+
+ XY s_fwd_expect[] = {
+ {204831.24057099217, 121816.46669603503},
+ {204831.24057099217, -121816.46669603503},
+ {-204831.24057099217, 121816.46669603503},
+ {-204831.24057099217, -121816.46669603503},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ {0.0019593827209883237, 0.00082369854658027549},
+ {0.0019593827209883237, -0.00082369854658027549},
+ {-0.0019593827209883237, 0.00082369854658027549},
+ {-0.0019593827209883237, -0.00082369854658027549},
+ };
+
+ LP s_inv_expect[] = {
+ {0.0019526892859206603, 0.00082088471512331508},
+ {0.0019526892859206603, -0.00082088471512331508},
+ {-0.0019526892859206603, 0.00082088471512331508},
+ {-0.0019526892859206603, -0.00082088471512331508},
+ };
+
+ 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_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_vandg.c b/src/PJ_vandg.c
index 784674b7..5ce058fd 100644
--- a/src/PJ_vandg.c
+++ b/src/PJ_vandg.c
@@ -1,78 +1,156 @@
#define PJ_LIB__
-# include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(vandg, "van der Grinten (I)") "\n\tMisc Sph";
-# define TOL 1.e-10
-# define THIRD .33333333333333333333
-# define TWO_THRD .66666666666666666666
-# define C2_27 .07407407407407407407
-# define PI4_3 4.18879020478639098458
-# define PISQ 9.86960440108935861869
-# define TPISQ 19.73920880217871723738
-# define HPISQ 4.93480220054467930934
-FORWARD(s_forward); /* spheroid */
- double al, al2, g, g2, p2;
-
- p2 = fabs(lp.phi / HALFPI);
- if ((p2 - TOL) > 1.) F_ERROR;
- if (p2 > 1.)
- p2 = 1.;
- if (fabs(lp.phi) <= TOL) {
- xy.x = lp.lam;
- xy.y = 0.;
- } else if (fabs(lp.lam) <= TOL || fabs(p2 - 1.) < TOL) {
- xy.x = 0.;
- xy.y = PI * tan(.5 * asin(p2));
- if (lp.phi < 0.) xy.y = -xy.y;
- } else {
- al = .5 * fabs(PI / lp.lam - lp.lam / PI);
- al2 = al * al;
- g = sqrt(1. - p2 * p2);
- g = g / (p2 + g - 1.);
- g2 = g * g;
- p2 = g * (2. / p2 - 1.);
- p2 = p2 * p2;
- xy.x = g - p2; g = p2 + al2;
- xy.x = PI * (al * xy.x + sqrt(al2 * xy.x * xy.x - g * (g2 - p2))) / g;
- if (lp.lam < 0.) xy.x = -xy.x;
- xy.y = fabs(xy.x / PI);
- xy.y = 1. - xy.y * (xy.y + 2. * al);
- if (xy.y < -TOL) F_ERROR;
- if (xy.y < 0.) xy.y = 0.;
- else xy.y = sqrt(xy.y) * (lp.phi < 0. ? -PI : PI);
- }
- return (xy);
+
+# define TOL 1.e-10
+# define THIRD .33333333333333333333
+# define TWO_THRD .66666666666666666666
+# define C2_27 .07407407407407407407
+# define PI4_3 4.18879020478639098458
+# define PISQ 9.86960440108935861869
+# define TPISQ 19.73920880217871723738
+# define HPISQ 4.93480220054467930934
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ double al, al2, g, g2, p2;
+
+ p2 = fabs(lp.phi / HALFPI);
+ if ((p2 - TOL) > 1.) F_ERROR;
+ if (p2 > 1.)
+ p2 = 1.;
+ if (fabs(lp.phi) <= TOL) {
+ xy.x = lp.lam;
+ xy.y = 0.;
+ } else if (fabs(lp.lam) <= TOL || fabs(p2 - 1.) < TOL) {
+ xy.x = 0.;
+ xy.y = PI * tan(.5 * asin(p2));
+ if (lp.phi < 0.) xy.y = -xy.y;
+ } else {
+ al = .5 * fabs(PI / lp.lam - lp.lam / PI);
+ al2 = al * al;
+ g = sqrt(1. - p2 * p2);
+ g = g / (p2 + g - 1.);
+ g2 = g * g;
+ p2 = g * (2. / p2 - 1.);
+ p2 = p2 * p2;
+ xy.x = g - p2; g = p2 + al2;
+ xy.x = PI * (al * xy.x + sqrt(al2 * xy.x * xy.x - g * (g2 - p2))) / g;
+ if (lp.lam < 0.) xy.x = -xy.x;
+ xy.y = fabs(xy.x / PI);
+ xy.y = 1. - xy.y * (xy.y + 2. * al);
+ if (xy.y < -TOL) F_ERROR;
+ if (xy.y < 0.)
+ xy.y = 0.;
+ else
+ xy.y = sqrt(xy.y) * (lp.phi < 0. ? -PI : PI);
+ }
+
+ return xy;
}
-INVERSE(s_inverse); /* spheroid */
- double t, c0, c1, c2, c3, al, r2, r, m, d, ay, x2, y2;
-
- x2 = xy.x * xy.x;
- if ((ay = fabs(xy.y)) < TOL) {
- lp.phi = 0.;
- t = x2 * x2 + TPISQ * (x2 + HPISQ);
- lp.lam = fabs(xy.x) <= TOL ? 0. :
- .5 * (x2 - PISQ + sqrt(t)) / xy.x;
- return (lp);
- }
- y2 = xy.y * xy.y;
- r = x2 + y2; r2 = r * r;
- c1 = - PI * ay * (r + PISQ);
- c3 = r2 + TWOPI * (ay * r + PI * (y2 + PI * (ay + HALFPI)));
- c2 = c1 + PISQ * (r - 3. * y2);
- c0 = PI * ay;
- c2 /= c3;
- al = c1 / c3 - THIRD * c2 * c2;
- m = 2. * sqrt(-THIRD * al);
- d = C2_27 * c2 * c2 * c2 + (c0 * c0 - THIRD * c2 * c1) / c3;
- if (((t = fabs(d = 3. * d / (al * m))) - TOL) <= 1.) {
- d = t > 1. ? (d > 0. ? 0. : PI) : acos(d);
- lp.phi = PI * (m * cos(d * THIRD + PI4_3) - THIRD * c2);
- if (xy.y < 0.) lp.phi = -lp.phi;
- t = r2 + TPISQ * (x2 - y2 + HPISQ);
- lp.lam = fabs(xy.x) <= TOL ? 0. :
- .5 * (r - PISQ + (t <= 0. ? 0. : sqrt(t))) / xy.x;
- } else
- I_ERROR;
- return (lp);
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ double t, c0, c1, c2, c3, al, r2, r, m, d, ay, x2, y2;
+
+ x2 = xy.x * xy.x;
+ if ((ay = fabs(xy.y)) < TOL) {
+ lp.phi = 0.;
+ t = x2 * x2 + TPISQ * (x2 + HPISQ);
+ lp.lam = fabs(xy.x) <= TOL ? 0. :
+ .5 * (x2 - PISQ + sqrt(t)) / xy.x;
+ return (lp);
+ }
+ y2 = xy.y * xy.y;
+ r = x2 + y2; r2 = r * r;
+ c1 = - PI * ay * (r + PISQ);
+ c3 = r2 + TWOPI * (ay * r + PI * (y2 + PI * (ay + HALFPI)));
+ c2 = c1 + PISQ * (r - 3. * y2);
+ c0 = PI * ay;
+ c2 /= c3;
+ al = c1 / c3 - THIRD * c2 * c2;
+ m = 2. * sqrt(-THIRD * al);
+ d = C2_27 * c2 * c2 * c2 + (c0 * c0 - THIRD * c2 * c1) / c3;
+ if (((t = fabs(d = 3. * d / (al * m))) - TOL) <= 1.) {
+ d = t > 1. ? (d > 0. ? 0. : PI) : acos(d);
+ lp.phi = PI * (m * cos(d * THIRD + PI4_3) - THIRD * c2);
+ if (xy.y < 0.) lp.phi = -lp.phi;
+ t = r2 + TPISQ * (x2 - y2 + HPISQ);
+ lp.lam = fabs(xy.x) <= TOL ? 0. :
+ .5 * (r - PISQ + (t <= 0. ? 0. : sqrt(t))) / xy.x;
+ } else
+ I_ERROR;
+
+ return lp;
+}
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+
+ return pj_dealloc(P);
+}
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(vandg) P->es = 0.; P->inv = s_inverse; P->fwd = s_forward; ENDENTRY(P)
+
+
+PJ *PROJECTION(vandg) {
+ P->es = 0.;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_vandg_selftest (void) {return 0;}
+#else
+
+int pj_vandg_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=vandg +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 223395.24954340671, 111704.59663367498},
+ { 223395.24954340671, -111704.59663367498},
+ {-223395.24954340671, 111704.59663367498},
+ {-223395.24954340671, -111704.59663367498},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.001790493715929761, 0.00089524655486993867},
+ { 0.001790493715929761, -0.00089524655486993867},
+ {-0.001790493715929761, 0.00089524655486993867},
+ {-0.001790493715929761, -0.00089524655486993867},
+ };
+
+ 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_vandg2.c b/src/PJ_vandg2.c
index 7bfa8f4e..f8850cad 100644
--- a/src/PJ_vandg2.c
+++ b/src/PJ_vandg2.c
@@ -1,45 +1,149 @@
-# define TOL 1e-10
-# define TWORPI 0.63661977236758134308
-#define PROJ_PARMS__ \
- int vdg3;
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
+struct pj_opaque {
+ int vdg3;
+};
+
PROJ_HEAD(vandg2, "van der Grinten II") "\n\tMisc Sph, no inv.";
PROJ_HEAD(vandg3, "van der Grinten III") "\n\tMisc Sph, no inv.";
-FORWARD(s_forward); /* spheroid */
- double x1, at, bt, ct;
-
- bt = fabs(TWORPI * lp.phi);
- if ((ct = 1. - bt * bt) < 0.)
- ct = 0.;
- else
- ct = sqrt(ct);
- if (fabs(lp.lam) < TOL) {
- xy.x = 0.;
- xy.y = PI * (lp.phi < 0. ? -bt : bt) / (1. + ct);
- } else {
- at = 0.5 * fabs(PI / lp.lam - lp.lam / PI);
- if (P->vdg3) {
- x1 = bt / (1. + ct);
- xy.x = PI * (sqrt(at * at + 1. - x1 * x1) - at);
- xy.y = PI * x1;
- } else {
- x1 = (ct * sqrt(1. + at * at) - at * ct * ct) /
- (1. + at * at * bt * bt);
- xy.x = PI * x1;
- xy.y = PI * sqrt(1. - x1 * (x1 + 2. * at) + TOL);
- }
- if ( lp.lam < 0.) xy.x = -xy.x;
- if ( lp.phi < 0.) xy.y = -xy.y;
- }
- return (xy);
+
+#define TOL 1e-10
+#define TWORPI 0.63661977236758134308
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double x1, at, bt, ct;
+
+ bt = fabs(TWORPI * lp.phi);
+ if ((ct = 1. - bt * bt) < 0.)
+ ct = 0.;
+ else
+ ct = sqrt(ct);
+ if (fabs(lp.lam) < TOL) {
+ xy.x = 0.;
+ xy.y = PI * (lp.phi < 0. ? -bt : bt) / (1. + ct);
+ } else {
+ at = 0.5 * fabs(PI / lp.lam - lp.lam / PI);
+ if (Q->vdg3) {
+ x1 = bt / (1. + ct);
+ xy.x = PI * (sqrt(at * at + 1. - x1 * x1) - at);
+ xy.y = PI * x1;
+ } else {
+ x1 = (ct * sqrt(1. + at * at) - at * ct * ct) /
+ (1. + at * at * bt * bt);
+ xy.x = PI * x1;
+ xy.y = PI * sqrt(1. - x1 * (x1 + 2. * at) + TOL);
+ }
+ if ( lp.lam < 0.) xy.x = -xy.x;
+ if ( lp.phi < 0.) xy.y = -xy.y;
+ }
+
+ return xy;
+}
+
+
+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(vandg2) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->vdg3 = 0;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+PJ *PROJECTION(vandg3) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->vdg3 = 1;
+ P->es = 0.;
+ P->fwd = s_forward;
+
+ return P;
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(vandg2)
- P->vdg3 = 0;
- P->inv = 0; P->fwd = s_forward;
-ENDENTRY(P)
-ENTRY0(vandg3)
- P->vdg3 = 1;
- P->es = 0.; P->fwd = s_forward;
-ENDENTRY(P)
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_vandg2_selftest (void) {return 0;}
+#else
+
+int pj_vandg2_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=vandg2 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 223395.24785043663, 111718.49103722633},
+ { 223395.24785043663, -111718.49103722633},
+ {-223395.24785043663, 111718.49103722633},
+ {-223395.24785043663, -111718.49103722633},
+ };
+
+ return pj_generic_selftest (0, s_args, tolerance_xy, tolerance_lp, 4, 4, fwd_in, 0, s_fwd_expect, 0, 0, 0);
+}
+
+
+#endif
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_vandg3_selftest (void) {return 0;}
+#else
+
+int pj_vandg3_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=vandg3 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 223395.24955283134, 111704.51990442065},
+ { 223395.24955283134, -111704.51990442065},
+ {-223395.24955283134, 111704.51990442065},
+ {-223395.24955283134, -111704.51990442065},
+ };
+
+ return pj_generic_selftest (0, s_args, tolerance_xy, tolerance_lp, 4, 4, fwd_in, 0, s_fwd_expect, 0, 0, 0);
+}
+
+
+#endif
diff --git a/src/PJ_vandg4.c b/src/PJ_vandg4.c
index 0229042b..7a7ffefb 100644
--- a/src/PJ_vandg4.c
+++ b/src/PJ_vandg4.c
@@ -1,42 +1,98 @@
-#define PJ_LIB__
-#include <projects.h>
-PROJ_HEAD(vandg4, "van der Grinten IV") "\n\tMisc Sph, no inv.";
-#define TOL 1e-10
-#define TWORPI 0.63661977236758134308
-FORWARD(s_forward); /* spheroid */
- double x1, t, bt, ct, ft, bt2, ct2, dt, dt2;
- (void) P;
-
- if (fabs(lp.phi) < TOL) {
- xy.x = lp.lam;
- xy.y = 0.;
- } else if (fabs(lp.lam) < TOL || fabs(fabs(lp.phi) - HALFPI) < TOL) {
- xy.x = 0.;
- xy.y = lp.phi;
- } else {
- bt = fabs(TWORPI * lp.phi);
- bt2 = bt * bt;
- ct = 0.5 * (bt * (8. - bt * (2. + bt2)) - 5.)
- / (bt2 * (bt - 1.));
- ct2 = ct * ct;
- dt = TWORPI * lp.lam;
- dt = dt + 1. / dt;
- dt = sqrt(dt * dt - 4.);
- if ((fabs(lp.lam) - HALFPI) < 0.) dt = -dt;
- dt2 = dt * dt;
- x1 = bt + ct; x1 *= x1;
- t = bt + 3.*ct;
- ft = x1 * (bt2 + ct2 * dt2 - 1.) + (1.-bt2) * (
- bt2 * (t * t + 4. * ct2) +
- ct2 * (12. * bt * ct + 4. * ct2) );
- x1 = (dt*(x1 + ct2 - 1.) + 2.*sqrt(ft)) /
- (4.* x1 + dt2);
- xy.x = HALFPI * x1;
- xy.y = HALFPI * sqrt(1. + dt * fabs(x1) - x1 * x1);
- if (lp.lam < 0.) xy.x = -xy.x;
- if (lp.phi < 0.) xy.y = -xy.y;
- }
- return (xy);
-}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(vandg4) P->es = 0.; P->fwd = s_forward; ENDENTRY(P)
+#define PJ_LIB__
+#include <projects.h>
+
+PROJ_HEAD(vandg4, "van der Grinten IV") "\n\tMisc Sph, no inv.";
+
+#define TOL 1e-10
+#define TWORPI 0.63661977236758134308
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ double x1, t, bt, ct, ft, bt2, ct2, dt, dt2;
+ (void) P;
+
+ if (fabs(lp.phi) < TOL) {
+ xy.x = lp.lam;
+ xy.y = 0.;
+ } else if (fabs(lp.lam) < TOL || fabs(fabs(lp.phi) - HALFPI) < TOL) {
+ xy.x = 0.;
+ xy.y = lp.phi;
+ } else {
+ bt = fabs(TWORPI * lp.phi);
+ bt2 = bt * bt;
+ ct = 0.5 * (bt * (8. - bt * (2. + bt2)) - 5.)
+ / (bt2 * (bt - 1.));
+ ct2 = ct * ct;
+ dt = TWORPI * lp.lam;
+ dt = dt + 1. / dt;
+ dt = sqrt(dt * dt - 4.);
+ if ((fabs(lp.lam) - HALFPI) < 0.) dt = -dt;
+ dt2 = dt * dt;
+ x1 = bt + ct; x1 *= x1;
+ t = bt + 3.*ct;
+ ft = x1 * (bt2 + ct2 * dt2 - 1.) + (1.-bt2) * (
+ bt2 * (t * t + 4. * ct2) +
+ ct2 * (12. * bt * ct + 4. * ct2) );
+ x1 = (dt*(x1 + ct2 - 1.) + 2.*sqrt(ft)) /
+ (4.* x1 + dt2);
+ xy.x = HALFPI * x1;
+ xy.y = HALFPI * sqrt(1. + dt * fabs(x1) - x1 * x1);
+ if (lp.lam < 0.) xy.x = -xy.x;
+ if (lp.phi < 0.) xy.y = -xy.y;
+ }
+ return xy;
+}
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+
+ return pj_dealloc(P);
+}
+
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(vandg4) {
+ P->es = 0.;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_vandg4_selftest (void) {return 0;}
+#else
+
+int pj_vandg4_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=vandg4 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 223374.57729435508, 111701.19548415358 },
+ { 223374.57729435508, -111701.19548415358 },
+ {-223374.57729435508, 111701.19548415358 },
+ {-223374.57729435508, -111701.19548415358 },
+ };
+
+ return pj_generic_selftest (0, s_args, tolerance_xy, tolerance_lp, 4, 4, fwd_in, 0, s_fwd_expect, 0, 0, 0);
+}
+
+
+#endif
diff --git a/src/PJ_wag2.c b/src/PJ_wag2.c
index f4942bb2..b70dcd4f 100644
--- a/src/PJ_wag2.c
+++ b/src/PJ_wag2.c
@@ -5,17 +5,84 @@ PROJ_HEAD(wag2, "Wagner II") "\n\tPCyl., Sph.";
#define C_y 1.38725
#define C_p1 0.88022
#define C_p2 0.88550
-FORWARD(s_forward); /* spheroid */
- lp.phi = aasin(P->ctx,C_p1 * sin(C_p2 * lp.phi));
- xy.x = C_x * lp.lam * cos(lp.phi);
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ lp.phi = aasin (P->ctx,C_p1 * sin (C_p2 * lp.phi));
+ xy.x = C_x * lp.lam * cos (lp.phi);
xy.y = C_y * lp.phi;
return (xy);
}
-INVERSE(s_inverse); /* spheroid */
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
lp.phi = xy.y / C_y;
lp.lam = xy.x / (C_x * cos(lp.phi));
- lp.phi = aasin(P->ctx,sin(lp.phi) / C_p1) / C_p2;
+ lp.phi = aasin (P->ctx,sin(lp.phi) / C_p1) / C_p2;
return (lp);
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(wag2) P->es = 0.; P->inv = s_inverse; P->fwd = s_forward; ENDENTRY(P)
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ return pj_dealloc(P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(wag2) {
+ P->es = 0.;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_wag2_selftest (void) {return 0;}
+#else
+
+int pj_wag2_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=wag2 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 206589.88809996162, 120778.04035754716},
+ { 206589.88809996162, -120778.04035754716},
+ {-206589.88809996162, 120778.04035754716},
+ {-206589.88809996162, -120778.04035754716},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0019360240367390709, 0.00082795765763814082},
+ { 0.0019360240367390709, -0.00082795765763814082},
+ {-0.0019360240367390709, 0.00082795765763814082},
+ {-0.0019360240367390709, -0.00082795765763814082},
+ };
+
+ 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_wag3.c b/src/PJ_wag3.c
index 482e389c..0539f4a1 100644
--- a/src/PJ_wag3.c
+++ b/src/PJ_wag3.c
@@ -1,24 +1,101 @@
-#define PROJ_PARMS__ \
- double C_x;
#define PJ_LIB__
# include <projects.h>
PROJ_HEAD(wag3, "Wagner III") "\n\tPCyl., Sph.\n\tlat_ts=";
#define TWOTHIRD 0.6666666666666666666667
-FORWARD(s_forward); /* spheroid */
- xy.x = P->C_x * lp.lam * cos(TWOTHIRD * lp.phi);
+
+struct pj_opaque {
+ double C_x;
+};
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ xy.x = P->opaque->C_x * lp.lam * cos(TWOTHIRD * lp.phi);
xy.y = lp.phi;
- return (xy);
+ return xy;
}
+
+
+#if 0
INVERSE(s_inverse); /* spheroid */
+#endif
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
lp.phi = xy.y;
- lp.lam = xy.x / (P->C_x * cos(TWOTHIRD * lp.phi));
- return (lp);
+ lp.lam = xy.x / (P->opaque->C_x * cos(TWOTHIRD * lp.phi));
+ return lp;
+}
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ return pj_dealloc(P);
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(wag3)
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(wag3) {
double ts;
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ ts = pj_param (P->ctx, P->params, "rlat_ts").f;
+ P->opaque->C_x = cos (ts) / cos (2.*ts/3.);
+ P->es = 0.;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_wag3_selftest (void) {return 0;}
+#else
+
+int pj_wag3_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=wag3 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ {223387.02171816575, 111701.07212763709},
+ {223387.02171816575, -111701.07212763709},
+ {-223387.02171816575, 111701.07212763709},
+ {-223387.02171816575, -111701.07212763709},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ {0.001790493109880963, 0.00089524655489191132},
+ {0.001790493109880963, -0.00089524655489191132},
+ {-0.001790493109880963, 0.00089524655489191132},
+ {-0.001790493109880963, -0.00089524655489191132},
+ };
+
+ 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);
+}
+
- ts = pj_param(P->ctx, P->params, "rlat_ts").f;
- P->C_x = cos(ts) / cos(2.*ts/3.);
- P->es = 0.; P->inv = s_inverse; P->fwd = s_forward;
-ENDENTRY(P)
+#endif
diff --git a/src/PJ_wag7.c b/src/PJ_wag7.c
index db29ffb1..847566d8 100644
--- a/src/PJ_wag7.c
+++ b/src/PJ_wag7.c
@@ -1,15 +1,67 @@
#define PJ_LIB__
#include <projects.h>
+
PROJ_HEAD(wag7, "Wagner VII") "\n\tMisc Sph, no inv.";
-FORWARD(s_forward); /* sphere */
+
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0, 0.0};
double theta, ct, D;
- (void) P;
- theta = asin(xy.y = 0.90630778703664996 * sin(lp.phi));
- xy.x = 2.66723 * (ct = cos(theta)) * sin(lp.lam /= 3.);
- xy.y *= 1.24104 * (D = 1/(sqrt(0.5 * (1 + ct * cos(lp.lam)))));
+ (void) P; /* Shut up compiler warnnings about unused P */
+
+ theta = asin (xy.y = 0.90630778703664996 * sin(lp.phi));
+ xy.x = 2.66723 * (ct = cos (theta)) * sin (lp.lam /= 3.);
+ xy.y *= 1.24104 * (D = 1/(sqrt (0.5 * (1 + ct * cos (lp.lam)))));
xy.x *= D;
return (xy);
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(wag7) P->fwd = s_forward; P->inv = 0; P->es = 0.; ENDENTRY(P)
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ return pj_dealloc(P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+
+PJ *PROJECTION(wag7) {
+ P->fwd = s_forward;
+ P->inv = 0;
+ P->es = 0.;
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_wag7_selftest (void) {return 0;}
+#else
+
+int pj_wag7_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=wag7 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 198601.87695731167, 125637.0457141714},
+ { 198601.87695731167, -125637.0457141714},
+ {-198601.87695731167, 125637.0457141714},
+ {-198601.87695731167, -125637.0457141714},
+ };
+
+ return pj_generic_selftest (0, s_args, tolerance_xy, tolerance_lp, 4, 4, fwd_in, 0, s_fwd_expect, 0, 0, 0);
+}
+#endif
diff --git a/src/PJ_wink1.c b/src/PJ_wink1.c
index dfb455e0..f9d127c0 100644
--- a/src/PJ_wink1.c
+++ b/src/PJ_wink1.c
@@ -1,20 +1,100 @@
-#define PROJ_PARMS__ \
- double cosphi1;
#define PJ_LIB__
-# include <projects.h>
+#include <projects.h>
PROJ_HEAD(wink1, "Winkel I") "\n\tPCyl., Sph.\n\tlat_ts=";
-FORWARD(s_forward); /* spheroid */
- xy.x = .5 * lp.lam * (P->cosphi1 + cos(lp.phi));
+
+
+struct pj_opaque {
+ double cosphi1;
+};
+
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0,0.0};
+ xy.x = .5 * lp.lam * (P->opaque->cosphi1 + cos(lp.phi));
xy.y = lp.phi;
return (xy);
}
-INVERSE(s_inverse); /* spheroid */
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
lp.phi = xy.y;
- lp.lam = 2. * xy.x / (P->cosphi1 + cos(lp.phi));
+ lp.lam = 2. * xy.x / (P->opaque->cosphi1 + cos(lp.phi));
return (lp);
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(wink1)
- P->cosphi1 = cos(pj_param(P->ctx, P->params, "rlat_ts").f);
- P->es = 0.; P->inv = s_inverse; P->fwd = s_forward;
-ENDENTRY(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;
+}
+
+
+PJ *PROJECTION(wink1) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ P->opaque->cosphi1 = cos (pj_param(P->ctx, P->params, "rlat_ts").f);
+ P->es = 0.;
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_wink1_selftest (void) {return 0;}
+#else
+
+int pj_wink1_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=wink1 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 223385.13164095284, 111701.07212763709},
+ { 223385.13164095284, -111701.07212763709},
+ {-223385.13164095284, 111701.07212763709},
+ {-223385.13164095284, -111701.07212763709},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP s_inv_expect[] = {
+ { 0.0017904931098931057, 0.00089524655489191132},
+ { 0.0017904931098931057, -0.00089524655489191132},
+ {-0.0017904931098931057, 0.00089524655489191132},
+ {-0.0017904931098931057, -0.00089524655489191132},
+ };
+
+ 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_wink2.c b/src/PJ_wink2.c
index 388c790a..f31ba5a5 100644
--- a/src/PJ_wink2.c
+++ b/src/PJ_wink2.c
@@ -1,34 +1,93 @@
-#define PROJ_PARMS__ \
- double cosphi1;
#define PJ_LIB__
# include <projects.h>
+
PROJ_HEAD(wink2, "Winkel II") "\n\tPCyl., Sph., no inv.\n\tlat_1=";
+
+struct pj_opaque { double cosphi1; };
+
#define MAX_ITER 10
#define LOOP_TOL 1e-7
#define TWO_D_PI 0.636619772367581343
-FORWARD(s_forward); /* spheroid */
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy = {0.0, 0.0};
double k, V;
int i;
xy.y = lp.phi * TWO_D_PI;
- k = PI * sin(lp.phi);
+ k = PI * sin (lp.phi);
lp.phi *= 1.8;
for (i = MAX_ITER; i ; --i) {
- lp.phi -= V = (lp.phi + sin(lp.phi) - k) /
- (1. + cos(lp.phi));
- if (fabs(V) < LOOP_TOL)
+ lp.phi -= V = (lp.phi + sin (lp.phi) - k) /
+ (1. + cos (lp.phi));
+ if (fabs (V) < LOOP_TOL)
break;
}
if (!i)
lp.phi = (lp.phi < 0.) ? -HALFPI : HALFPI;
else
lp.phi *= 0.5;
- xy.x = 0.5 * lp.lam * (cos(lp.phi) + P->cosphi1);
- xy.y = FORTPI * (sin(lp.phi) + xy.y);
- return (xy);
+ xy.x = 0.5 * lp.lam * (cos (lp.phi) + P->opaque->cosphi1);
+ xy.y = FORTPI * (sin (lp.phi) + xy.y);
+ return xy;
+}
+
+
+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(wink2) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ P->opaque->cosphi1 = cos(pj_param(P->ctx, P->params, "rlat_1").f);
+ P->es = 0.;
+ P->inv = 0;
+ P->fwd = s_forward;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_wink2_selftest (void) {return 0;}
+#else
+
+int pj_wink2_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char s_args[] = {"+proj=wink2 +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY s_fwd_expect[] = {
+ { 223387.39643378611, 124752.03279744535},
+ { 223387.39643378611, -124752.03279744535},
+ {-223387.39643378611, 124752.03279744535},
+ {-223387.39643378611, -124752.03279744535},
+ };
+
+ 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(wink2)
- P->cosphi1 = cos(pj_param(P->ctx, P->params, "rlat_1").f);
- P->es = 0.; P->inv = 0; P->fwd = s_forward;
-ENDENTRY(P)
+#endif
diff --git a/src/lib_proj.cmake b/src/lib_proj.cmake
index ed14e99e..7b8ec961 100644
--- a/src/lib_proj.cmake
+++ b/src/lib_proj.cmake
@@ -174,6 +174,7 @@ SET(SRC_LIBPROJ_CORE
pj_fwd3d.c
pj_gauss.c
pj_gc_reader.c
+ pj_generic_selftest.c
pj_geocent.c
pj_gridcatalog.c
pj_gridinfo.c
@@ -197,6 +198,7 @@ SET(SRC_LIBPROJ_CORE
pj_pr_list.c
pj_qsfn.c
pj_release.c
+ pj_run_selftests.c
pj_strerrno.c
pj_transform.c
pj_tsfn.c
diff --git a/src/makefile.vc b/src/makefile.vc
index 6989519d..2efad1f0 100644
--- a/src/makefile.vc
+++ b/src/makefile.vc
@@ -14,19 +14,19 @@ conic = \
PJ_rpoly.obj PJ_sconics.obj PJ_lcca.obj
cylinder = \
- PJ_cass.obj PJ_cc.obj PJ_cea.obj PJ_comill.obj PJ_eqc.obj \
+ PJ_cass.obj PJ_cc.obj PJ_cea.obj PJ_eqc.obj \
PJ_gall.obj PJ_labrd.obj PJ_lsat.obj PJ_misrsom.obj PJ_merc.obj \
PJ_mill.obj PJ_ocea.obj PJ_omerc.obj PJ_patterson.obj PJ_somerc.obj \
PJ_tcc.obj PJ_tcea.obj PJ_tmerc.obj PJ_geos.obj \
- PJ_gstmerc.obj proj_etmerc.obj
+ PJ_gstmerc.obj proj_etmerc.obj PJ_comill.obj
misc = \
PJ_airy.obj PJ_aitoff.obj PJ_august.obj PJ_bacon.obj \
PJ_chamb.obj PJ_hammer.obj PJ_lagrng.obj PJ_larr.obj \
PJ_lask.obj PJ_nocol.obj PJ_ob_tran.obj PJ_oea.obj \
PJ_sch.obj PJ_tpeqd.obj PJ_vandg.obj PJ_vandg2.obj \
- PJ_vandg4.obj PJ_wag7.obj pj_latlong.obj PJ_krovak.obj \
- pj_geocent.obj PJ_healpix.obj PJ_natearth.obj PJ_natearth2.obj PJ_qsc.obj
+ PJ_vandg4.obj PJ_wag7.obj pj_latlong.obj PJ_krovak.obj \
+ pj_geocent.obj PJ_healpix.obj PJ_qsc.obj
pseudo = \
PJ_boggs.obj PJ_collg.obj PJ_crast.obj PJ_denoy.obj \
@@ -38,14 +38,14 @@ pseudo = \
PJ_putp4p.obj PJ_putp5.obj PJ_putp6.obj PJ_robin.obj \
PJ_sts.obj PJ_urm5.obj PJ_urmfps.obj PJ_wag2.obj \
PJ_wag3.obj PJ_wink1.obj PJ_wink2.obj PJ_isea.obj \
- PJ_calcofi.obj
+ PJ_calcofi.obj PJ_natearth.obj PJ_natearth2.obj
support = \
aasincos.obj adjlon.obj bch2bps.obj bchgen.obj pj_gauss.obj \
biveval.obj dmstor.obj mk_cheby.obj pj_auth.obj \
pj_deriv.obj pj_ell_set.obj pj_ellps.obj pj_errno.obj \
pj_factors.obj pj_fwd.obj pj_init.obj pj_inv.obj \
- pj_fwd3d.obj pj_inv3d.obj \
+ pj_fwd3d.obj pj_inv3d.obj \
pj_list.obj pj_malloc.obj pj_mlfn.obj pj_msfn.obj \
pj_open_lib.obj pj_param.obj pj_phi2.obj pj_pr_list.obj \
pj_qsfn.obj pj_strerrno.obj pj_tsfn.obj pj_units.obj \
@@ -56,7 +56,7 @@ support = \
pj_utils.obj pj_gridlist.obj pj_gridinfo.obj \
proj_mdist.obj pj_mutex.obj pj_initcache.obj \
pj_ctx.obj pj_fileapi.obj pj_log.obj pj_apply_vgridshift.obj \
- pj_strtod.obj
+ pj_strtod.obj pj_run_selftests.obj pj_generic_selftest.obj
geodesic = geodesic.obj
LIBOBJ = $(support) $(pseudo) $(azimuthal) $(conic) $(cylinder) $(misc) \
@@ -146,4 +146,4 @@ install: all
copy proj_api.h $(INSTDIR)\include
copy projects.h $(INSTDIR)\include
copy geodesic.h $(INSTDIR)\include
-
+
diff --git a/src/pj_fwd.c b/src/pj_fwd.c
index 1cd002b5..d4948d99 100644
--- a/src/pj_fwd.c
+++ b/src/pj_fwd.c
@@ -25,7 +25,7 @@ pj_fwd(LP lp, PJ *P) {
if (!P->over)
lp.lam = adjlon(lp.lam); /* adjust del longitude */
- //Check for NULL pointer
+ /* Check for NULL pointer */
if (P->fwd != NULL)
{
xy = (*P->fwd)(lp, P); /* project */
diff --git a/src/pj_fwd3d.c b/src/pj_fwd3d.c
index 834746d4..9da8a482 100644
--- a/src/pj_fwd3d.c
+++ b/src/pj_fwd3d.c
@@ -19,13 +19,13 @@ pj_fwd3d(LPZ lpz, PJ *P) {
if (fabs(t) <= EPS)
lpz.phi = lpz.phi < 0. ? -HALFPI : HALFPI;
- else if (P->geoc) //Maybe redundant and never used.
+ else if (P->geoc) /* Maybe redundant and never used. */
lpz.phi = atan(P->rone_es * tan(lpz.phi));
lpz.lam -= P->lam0; /* compute del lp.lam */
if (!P->over)
lpz.lam = adjlon(lpz.lam); /* adjust del longitude */
- //Check for NULL pointer
+ /* Check for NULL pointer */
if (P->fwd3d != NULL)
{
xyz = (*P->fwd3d)(lpz, P); /* project */
@@ -35,7 +35,7 @@ pj_fwd3d(LPZ lpz, PJ *P) {
else {
xyz.x = P->fr_meter * (P->a * xyz.x + P->x0);
xyz.y = P->fr_meter * (P->a * xyz.y + P->y0);
- //z is not scaled since this handled by vto_meter outside
+ /* z is not scaled since this handled by vto_meter outside */
}
}
else
diff --git a/src/pj_generic_selftest.c b/src/pj_generic_selftest.c
new file mode 100644
index 00000000..88b5c308
--- /dev/null
+++ b/src/pj_generic_selftest.c
@@ -0,0 +1,197 @@
+/******************************************************************************
+ * Project: PROJ.4
+ * Purpose: Generic regression test for PROJ.4 projection algorithms.
+ * Author: Thomas Knudsen
+ *
+ ******************************************************************************
+ * Copyright (c) 2016, Thomas Knudsen
+ *
+ * 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.
+ *****************************************************************************/
+
+
+#include <stdio.h>
+#define PJ_LIB__
+#include <projects.h>
+
+
+static int deviates_xy (XY expected, XY got, double tolerance);
+static int deviates_lp (LP expected, LP got, double tolerance);
+static XY pj_fwd_deg (LP in, PJ *P);
+
+
+/**********************************************************************/
+int pj_generic_selftest (
+/**********************************************************************/
+ char *e_args,
+ char *s_args,
+ double tolerance_xy,
+ double tolerance_lp,
+ int n_fwd,
+ int n_inv,
+ LP *fwd_in,
+ XY *e_fwd_expect,
+ XY *s_fwd_expect,
+ XY *inv_in,
+ LP *e_inv_expect,
+ LP *s_inv_expect
+) {
+/***********************************************************************
+
+Generic regression test for PROJ.4 projection algorithms, testing both
+ellipsoidal ("e_") and spheroidal ("s_") versions of the projection
+algorithms in both forward ("_fwd_") and inverse ("_inv_") mode.
+
+Compares the "known good" results in <e_fwd_expect> and <s_fwd_expect>
+with the actual results obtained by transforming the forward input data
+set in <fwd_in> with pj_fwd() using setup arguments <e_args> and
+<s_args>, respectively.
+
+Then
+
+Compares the "known good" results in <e_inv_expect> and <s_inv_expect>
+with the actual results obtained by transforming the inverse input data
+set in <inv_in> with pj_inv() using setup arguments <e_args> and
+<s_args>, respectively.
+
+Any of the pointers passed may be set to 0, indicating "don't test this
+part".
+
+Returns 0 if all data agree to within the accuracy specified in
+<tolerance_xy> and <tolerance_lp>. Non-zero otherwise.
+
+***********************************************************************/
+ int i;
+
+ PJ *P;
+
+ if (e_args) {
+ P = pj_init_plus(e_args);
+ if (0==P)
+ return 2;
+
+ /* Test forward ellipsoidal */
+ if (e_fwd_expect) {
+ for (i = 0; i < n_fwd; i++)
+ if (deviates_xy (e_fwd_expect[i], pj_fwd_deg ( fwd_in[i], P ), tolerance_xy))
+ break;
+ if ( i != n_fwd )
+ return 100 + i;
+ }
+
+ /* Test inverse ellipsoidal */
+ if (e_inv_expect) {
+ for (i = 0; i < n_inv; i++)
+ if (deviates_lp (e_inv_expect[i], pj_inv ( inv_in[i], P ), tolerance_lp))
+ break;
+ if ( i != n_inv )
+ return 200 + i;
+ }
+
+ pj_free (P);
+ }
+
+
+ if (s_args) {
+ P = pj_init_plus(s_args);
+ if (0==P)
+ return 3;
+
+ /* Test forward spherical */
+ if (s_fwd_expect) {
+ for (i = 0; i < n_fwd; i++)
+ if (deviates_xy (s_fwd_expect[i], pj_fwd_deg ( fwd_in[i], P ), tolerance_xy))
+ break;
+ if ( i != n_fwd )
+ return 300 + i;
+ }
+
+ /* Test inverse spherical */
+ if (s_inv_expect) {
+ for (i = 0; i < n_inv; i++)
+ if (deviates_lp (s_inv_expect[i], pj_inv ( inv_in[i], P ), tolerance_lp))
+ break;
+ if ( i != n_inv )
+ return 400 + i;
+ }
+
+ pj_free (P);
+ }
+
+ return 0;
+}
+
+
+
+/**********************************************************************/
+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 (hypot ( expected.x - got.x, expected.y - got.y ) > tolerance)
+ return 1;
+ return 0;
+}
+
+
+/**********************************************************************/
+static int deviates_lp (LP expected, LP got, double tolerance) {
+/***********************************************************************
+
+ Determine whether two LPs deviate by more than <tolerance>.
+
+ This one is slightly tricky, since the <expected> LP is
+ supposed to be represented as degrees (since it was at some
+ time written down by a real human), whereas the <got> LP is
+ represented in radians (since it is supposed to be the result
+ output from pj_inv)
+
+***********************************************************************/
+ if (HUGE_VAL== expected.lam)
+ return 0;
+ if (HUGE_VAL== expected.phi)
+ return 0;
+ if (hypot ( DEG_TO_RAD * expected.lam - got.lam, DEG_TO_RAD * expected.phi - got.phi ) > tolerance)
+ return 1;
+ return 0;
+}
+
+
+/**********************************************************************/
+static XY pj_fwd_deg (LP in, PJ *P) {
+/***********************************************************************
+
+ Wrapper for pj_fwd, accepting input in degrees.
+
+***********************************************************************/
+ LP in_rad;
+ in_rad.lam = DEG_TO_RAD * in.lam;
+ in_rad.phi = DEG_TO_RAD * in.phi;
+ return pj_fwd (in_rad, P);
+}
diff --git a/src/pj_geocent.c b/src/pj_geocent.c
index 6b2f3026..fa01b01f 100644
--- a/src/pj_geocent.c
+++ b/src/pj_geocent.c
@@ -32,24 +32,88 @@
PROJ_HEAD(geocent, "Geocentric") "\n\t";
-FORWARD(forward);
- (void) P;
- xy.x = lp.lam;
- xy.y = lp.phi;
- return xy;
+static XY forward(LP lp, PJ *P) {
+ XY xy = {0.0,0.0};
+ (void) P;
+ xy.x = lp.lam;
+ xy.y = lp.phi;
+ return xy;
}
-INVERSE(inverse);
- (void) P;
- lp.phi = xy.y;
- lp.lam = xy.x;
- return lp;
+
+static LP inverse(XY xy, PJ *P) {
+ LP lp = {0.0,0.0};
+ (void) P;
+ lp.phi = xy.y;
+ lp.lam = xy.x;
+ return lp;
+}
+
+
+static void *freeup_new (PJ *P) {
+ if (0==P)
+ return 0;
+
+ return pj_dealloc(P);
}
-FREEUP; if (P) pj_dalloc(P); }
-ENTRY0(geocent)
- P->is_geocent = 1;
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+PJ *PROJECTION(geocent) {
+ P->is_geocent = 1;
P->x0 = 0.0;
P->y0 = 0.0;
- P->inv = inverse; P->fwd = forward;
-ENDENTRY(P)
+ P->inv = inverse;
+ P->fwd = forward;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_geocent_selftest (void) {return 0;}
+#else
+
+int pj_geocent_selftest (void) {
+
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=geocent +ellps=GRS80 +lat_1=0.5 +lat_2=2"};
+ char s_args[] = {"+proj=geocent +a=6400000 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ { 222638.98158654713, 111319.49079327357},
+ { 222638.98158654713, -111319.49079327357},
+ {-222638.98158654713, 111319.49079327357},
+ {-222638.98158654713, -111319.49079327357},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ { 0.0017966305682390426, 0.00089831528411952132},
+ { 0.0017966305682390426, -0.00089831528411952132},
+ {-0.0017966305682390426, 0.00089831528411952132},
+ {-0.0017966305682390426, -0.00089831528411952132},
+ };
+
+ return pj_generic_selftest (e_args, s_args, tolerance_xy, tolerance_lp, 4, 4, fwd_in, e_fwd_expect, 0, inv_in, e_inv_expect, 0);
+}
+
+#endif
diff --git a/src/pj_init.c b/src/pj_init.c
index 13d469da..79b64bb3 100644
--- a/src/pj_init.c
+++ b/src/pj_init.c
@@ -110,7 +110,7 @@ get_opt(projCtx ctx, paralist **start, PAFile fid, char *name, paralist *next,
*sword = 't';
/* loop till we find our target keyword */
- while (*next_char)
+ while (*next_char)
{
next_char = fill_buffer(state, next_char);
@@ -119,9 +119,9 @@ get_opt(projCtx ctx, paralist **start, PAFile fid, char *name, paralist *next,
next_char++;
next_char = fill_buffer(state, next_char);
-
+
/* for comments, skip past end of line. */
- if( *next_char == '#' )
+ if( *next_char == '#' )
{
while( *next_char && *next_char != '\n' )
next_char++;
@@ -131,11 +131,11 @@ get_opt(projCtx ctx, paralist **start, PAFile fid, char *name, paralist *next,
next_char++;
if (*next_char == '\r')
next_char++;
-
- }
+
+ }
/* Is this our target? */
- else if( *next_char == '<' )
+ else if( *next_char == '<' )
{
/* terminate processing target on the next block definition */
if (in_target)
@@ -143,7 +143,7 @@ get_opt(projCtx ctx, paralist **start, PAFile fid, char *name, paralist *next,
next_char++;
if (strncmp(name, next_char, len) == 0
- && next_char[len] == '>')
+ && next_char[len] == '>')
{
/* skip past target word */
next_char += len + 1;
@@ -151,14 +151,14 @@ get_opt(projCtx ctx, paralist **start, PAFile fid, char *name, paralist *next,
if(found_def)
*found_def = 1;
}
- else
+ else
{
/* skip past end of line */
while( *next_char && *next_char != '\n' )
next_char++;
}
}
- else if (in_target)
+ else if (in_target)
{
const char *start_of_word = next_char;
int word_len = 0;
@@ -183,27 +183,27 @@ get_opt(projCtx ctx, paralist **start, PAFile fid, char *name, paralist *next,
if (!pj_param(ctx, *start, sword).i) {
/* don't default ellipse if datum, ellps or any earth model
information is set. */
- if( strncmp(sword+1,"ellps=",6) != 0
- || (!pj_param(ctx, *start, "tdatum").i
- && !pj_param(ctx, *start, "tellps").i
- && !pj_param(ctx, *start, "ta").i
- && !pj_param(ctx, *start, "tb").i
- && !pj_param(ctx, *start, "trf").i
+ if( strncmp(sword+1,"ellps=",6) != 0
+ || (!pj_param(ctx, *start, "tdatum").i
+ && !pj_param(ctx, *start, "tellps").i
+ && !pj_param(ctx, *start, "ta").i
+ && !pj_param(ctx, *start, "tb").i
+ && !pj_param(ctx, *start, "trf").i
&& !pj_param(ctx, *start, "tf").i) )
{
next = next->next = pj_mkparam(sword+1);
}
}
-
+
}
- else
+ else
{
/* skip past word */
while( *next_char && !isspace(*next_char) )
next_char++;
-
+
}
- }
+ }
if (errno == 25)
errno = 0;
@@ -229,7 +229,7 @@ get_defaults(projCtx ctx, paralist **start, paralist *next, char *name) {
if (errno)
errno = 0; /* don't care if can't open file */
ctx->last_errno = 0;
-
+
return next;
}
@@ -245,11 +245,11 @@ get_init(projCtx ctx, paralist **start, paralist *next, char *name,
const paralist *orig_next = next;
(void)strncpy(fname, name, MAX_PATH_FILENAME + ID_TAG_MAX + 1);
-
- /*
- ** Search for file/key pair in cache
+
+ /*
+ ** Search for file/key pair in cache
*/
-
+
init_items = pj_search_initcache( name );
if( init_items != NULL )
{
@@ -275,8 +275,8 @@ get_init(projCtx ctx, paralist **start, paralist *next, char *name,
if (errno == 25)
errno = 0; /* unknown problem with some sys errno<-25 */
- /*
- ** If we seem to have gotten a result, insert it into the
+ /*
+ ** If we seem to have gotten a result, insert it into the
** init file cache.
*/
if( next != NULL && next != orig_next )
@@ -308,7 +308,7 @@ pj_init_plus_ctx( projCtx ctx, const char *definition )
char *defn_copy;
int argc = 0, i, blank_count = 0;
PJ *result = NULL;
-
+
/* make a copy that we can manipulate */
defn_copy = (char *) pj_malloc( strlen(definition)+1 );
strcpy( defn_copy, definition );
@@ -328,13 +328,13 @@ pj_init_plus_ctx( projCtx ctx, const char *definition )
defn_copy[i - blank_count] = '\0';
blank_count = 0;
}
-
+
if( argc+1 == MAX_ARG )
{
pj_ctx_set_errno( ctx, -44 );
goto bum_call;
}
-
+
argv[argc++] = defn_copy + i + 1;
}
break;
@@ -455,7 +455,7 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) {
PIN->rone_es = 1./PIN->one_es;
/* Now that we have ellipse information check for WGS84 datum */
- if( PIN->datum_type == PJD_3PARAM
+ if( PIN->datum_type == PJD_3PARAM
&& PIN->datum_params[0] == 0.0
&& PIN->datum_params[1] == 0.0
&& PIN->datum_params[2] == 0.0
@@ -464,7 +464,7 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) {
{
PIN->datum_type = PJD_WGS84;
}
-
+
/* set PIN->geoc coordinate system */
PIN->geoc = (PIN->es && pj_param(ctx, start, "bgeoc").i);
@@ -532,7 +532,7 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) {
/* set units */
s = 0;
- if ((name = pj_param(ctx, start, "sunits").s) != NULL) {
+ if ((name = pj_param(ctx, start, "sunits").s) != NULL) {
for (i = 0; (s = pj_units[i].id) && strcmp(name, s) ; ++i) ;
if (!s) { pj_ctx_set_errno( ctx, -7 ); goto bum_call; }
s = pj_units[i].to_meter;
@@ -547,7 +547,7 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) {
/* set vertical units */
s = 0;
- if ((name = pj_param(ctx, start, "svunits").s) != NULL) {
+ if ((name = pj_param(ctx, start, "svunits").s) != NULL) {
for (i = 0; (s = pj_units[i].id) && strcmp(name, s) ; ++i) ;
if (!s) { pj_ctx_set_errno( ctx, -7 ); goto bum_call; }
s = pj_units[i].to_meter;
@@ -564,7 +564,7 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) {
/* prime meridian */
s = 0;
- if ((name = pj_param(ctx, start, "spm").s) != NULL) {
+ if ((name = pj_param(ctx, start, "spm").s) != NULL) {
const char *value = NULL;
char *next_str = NULL;
@@ -576,8 +576,8 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) {
break;
}
}
-
- if( value == NULL
+
+ if( value == NULL
&& (dmstor_ctx(ctx,name,&next_str) != 0.0 || *name == '0')
&& *next_str == '\0' )
value = name;
@@ -639,3 +639,27 @@ pj_free(PJ *P) {
P->pfree(P);
}
}
+
+
+
+
+
+
+
+
+/************************************************************************/
+/* pj_prepare() */
+/* */
+/* Helper function for the PJ_xxxx functions providing the */
+/* projection specific setup for each projection type. */
+/* */
+/* Currently not used, but placed here as part of the material */
+/* Demonstrating the idea for a future PJ_xxx architecture */
+/* (cf. pj_minimal.c) */
+/* */
+/************************************************************************/
+void pj_prepare (PJ *P, const char *description, void (*freeup)(struct PJconsts *), size_t sizeof_struct_opaque) {
+ P->descr = description;
+ P->pfree = freeup;
+ P->opaque = pj_calloc (1, sizeof_struct_opaque);
+}
diff --git a/src/pj_inv.c b/src/pj_inv.c
index d77b4e56..711a0005 100644
--- a/src/pj_inv.c
+++ b/src/pj_inv.c
@@ -20,7 +20,7 @@ pj_inv(XY xy, PJ *P) {
xy.x = (xy.x * P->to_meter - P->x0) * P->ra; /* descale and de-offset */
xy.y = (xy.y * P->to_meter - P->y0) * P->ra;
- //Check for NULL pointer
+ /* Check for NULL pointer */
if (P->inv != NULL)
{
lp = (*P->inv)(xy, P); /* inverse project */
diff --git a/src/pj_inv3d.c b/src/pj_inv3d.c
index de35e776..d06ed080 100644
--- a/src/pj_inv3d.c
+++ b/src/pj_inv3d.c
@@ -19,9 +19,9 @@ pj_inv3d(XYZ xyz, PJ *P) {
xyz.x = (xyz.x * P->to_meter - P->x0) * P->ra; /* descale and de-offset */
xyz.y = (xyz.y * P->to_meter - P->y0) * P->ra;
- //z is not scaled since that is handled by vto_meter before we get here
-
- //Check for NULL pointer
+ /* z is not scaled since that is handled by vto_meter before we get here */
+
+ /* Check for NULL pointer */
if (P->inv3d != NULL)
{
lpz = (*P->inv3d)(xyz, P); /* inverse project */
@@ -32,7 +32,7 @@ pj_inv3d(XYZ xyz, PJ *P) {
if (!P->over)
lpz.lam = adjlon(lpz.lam); /* adjust longitude to CM */
- //This maybe redundant and never user
+ /* This may be redundant and never used */
if (P->geoc && fabs(fabs(lpz.phi)-HALFPI) > EPS)
lpz.phi = atan(P->one_es * tan(lpz.phi));
}
diff --git a/src/pj_latlong.c b/src/pj_latlong.c
index b7a771a8..761eadc5 100644
--- a/src/pj_latlong.c
+++ b/src/pj_latlong.c
@@ -29,50 +29,94 @@
/* very loosely based upon DMA code by Bradford W. Drew */
#define PJ_LIB__
-#include <projects.h>
+#include <projects.h>
+
PROJ_HEAD(lonlat, "Lat/long (Geodetic)") "\n\t";
PROJ_HEAD(latlon, "Lat/long (Geodetic alias)") "\n\t";
PROJ_HEAD(latlong, "Lat/long (Geodetic alias)") "\n\t";
PROJ_HEAD(longlat, "Lat/long (Geodetic alias)") "\n\t";
-FORWARD(forward);
- xy.x = lp.lam / P->a;
- xy.y = lp.phi / P->a;
- return xy;
+ static XY forward(LP lp, PJ *P) {
+ XY xy = {0.0,0.0};
+ xy.x = lp.lam / P->a;
+ xy.y = lp.phi / P->a;
+ return xy;
+}
+
+
+static LP inverse(XY xy, PJ *P) {
+ LP lp = {0.0,0.0};
+ lp.phi = xy.y * P->a;
+ lp.lam = xy.x * P->a;
+ return lp;
+}
+
+
+static void *freeup_new (PJ *P) {
+ if (0==P)
+ return 0;
+
+ return pj_dealloc(P);
}
-INVERSE(inverse);
- lp.phi = xy.y * P->a;
- lp.lam = xy.x * P->a;
- return lp;
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
}
-FREEUP; if (P) pj_dalloc(P); }
-
-ENTRY0(latlong)
- P->is_latlong = 1;
- P->x0 = 0.0;
- P->y0 = 0.0;
- P->inv = inverse; P->fwd = forward;
-ENDENTRY(P)
-
-ENTRY0(longlat)
- P->is_latlong = 1;
- P->x0 = 0.0;
- P->y0 = 0.0;
- P->inv = inverse; P->fwd = forward;
-ENDENTRY(P)
-
-ENTRY0(latlon)
- P->is_latlong = 1;
- P->x0 = 0.0;
- P->y0 = 0.0;
- P->inv = inverse; P->fwd = forward;
-ENDENTRY(P)
-
-ENTRY0(lonlat)
- P->is_latlong = 1;
- P->x0 = 0.0;
- P->y0 = 0.0;
- P->inv = inverse; P->fwd = forward;
-ENDENTRY(P)
+
+
+PJ *PROJECTION(latlong) {
+ P->is_latlong = 1;
+ P->x0 = 0.0;
+ P->y0 = 0.0;
+ P->inv = inverse;
+ P->fwd = forward;
+
+ return P;
+}
+
+
+PJ *PROJECTION(longlat) {
+ P->is_latlong = 1;
+ P->x0 = 0.0;
+ P->y0 = 0.0;
+ P->inv = inverse;
+ P->fwd = forward;
+
+ return P;
+}
+
+
+PJ *PROJECTION(latlon) {
+ P->is_latlong = 1;
+ P->x0 = 0.0;
+ P->y0 = 0.0;
+ P->inv = inverse;
+ P->fwd = forward;
+
+ return P;
+}
+
+
+PJ *PROJECTION(lonlat) {
+ P->is_latlong = 1;
+ P->x0 = 0.0;
+ P->y0 = 0.0;
+ P->inv = inverse; P->fwd = forward;
+
+ return P;
+}
+
+
+/* Bogus self-test functions. Self-tests can't be implemented the usual way for
+ * these "projections" since they can't be used directly from proj.
+ * We still need them though, as all projections are automatically added to
+ * the list of self-test functions.
+ *
+ * The code should be covered by the tests in nad/.
+ * */
+int pj_latlong_selftest (void) {return 0;}
+int pj_longlat_selftest (void) {return 0;}
+int pj_latlon_selftest (void) {return 0;}
+int pj_lonlat_selftest (void) {return 0;}
diff --git a/src/pj_list.c b/src/pj_list.c
index bb56ade9..a8f171ab 100644
--- a/src/pj_list.c
+++ b/src/pj_list.c
@@ -1,11 +1,56 @@
/* Projection System: default list of projections
** Use local definition of PJ_LIST_H for subset.
*/
+
#define USE_PJ_LIST_H 1
#include "projects.h"
-struct PJ_LIST *pj_get_list_ref()
-{
+
+#define PASTE(a,b) a##b
+
+/* Generate prototypes for projection functions */
+#define PROJ_HEAD(id, name) struct PJconsts *pj_##id(struct PJconsts*);
+#include "pj_list.h"
+#undef PROJ_HEAD
+
+/* Generate prototypes for projection selftest functions */
+#define PROJ_HEAD(id, name) int PASTE(pj_##id, _selftest) (void);
+#include "pj_list.h"
+#undef PROJ_HEAD
+
+
+/* Generate extern declarations for description strings */
+#define PROJ_HEAD(id, name) extern char * const pj_s_##id;
+#include "pj_list.h"
+#undef PROJ_HEAD
+
+
+/* Generate the null-terminated list of projection functions with associated mnemonics and descriptions */
+#define PROJ_HEAD(id, name) {#id, pj_##id, &pj_s_##id},
+struct PJ_LIST pj_list[] = {
+#include "pj_list.h"
+ {0, 0, 0},
+ };
+#undef PROJ_HEAD
+
+
+/* Generate the null-terminated list of projection selftest functions with associated mnemonics */
+#define PROJ_HEAD(id, name) {#id, PASTE(pj_##id, _selftest)},
+struct PJ_SELFTEST_LIST pj_selftest_list[] = {
+#include "pj_list.h"
+ {0, 0},
+ };
+#undef PROJ_HEAD
+#undef PASTE
+
+
+struct PJ_LIST *pj_get_list_ref (void) {
return pj_list;
}
+
+
+struct PJ_SELFTEST_LIST *pj_get_selftest_list_ref (void) {
+ return pj_selftest_list;
+}
+
diff --git a/src/pj_malloc.c b/src/pj_malloc.c
index 80443a2b..aab69e99 100644
--- a/src/pj_malloc.c
+++ b/src/pj_malloc.c
@@ -9,19 +9,64 @@
pj_malloc(size_t size) {
/*
/ Currently, pj_malloc is a hack to solve an errno problem.
-/ The problem is described in more details at
-/ https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=86420.
-/ It seems, that pj_init and similar functions incorrectly
-/ (under debian/glibs-2.3.2) assume that pj_malloc resets
+/ The problem is described in more details at
+/ https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=86420.
+/ It seems, that pj_init and similar functions incorrectly
+/ (under debian/glibs-2.3.2) assume that pj_malloc resets
/ errno after success. pj_malloc tries to mimic this.
*/
int old_errno = errno;
- void *res = malloc(size);
+ void *res = malloc(size);
if ( res && !old_errno )
- errno = 0;
+ errno = 0;
return res;
}
void
pj_dalloc(void *ptr) {
free(ptr);
}
+
+
+/**********************************************************************/
+void *pj_calloc (size_t n, size_t size) {
+/***********************************************************************
+
+pj_calloc is the pj-equivalent of calloc().
+
+It allocates space for an array of <n> elements of size <size>.
+The array is initialized to zeros.
+
+***********************************************************************/
+ void *res = pj_malloc (n*size);
+ if (0==res)
+ return 0;
+ memset (res, 0, n*size);
+ return res;
+}
+
+
+/**********************************************************************/
+void *pj_dealloc (void *ptr) {
+/***********************************************************************
+
+pj_dealloc supports the common use case of "clean up and return a null
+pointer" to signal an error in a multi level allocation:
+
+ struct foo { int bar; int *baz; };
+
+ struct foo *p = pj_calloc (1, sizeof (struct foo));
+ if (0==p)
+ return 0;
+
+ p->baz = pj_calloc (10, sizeof(int));
+ if (0==p->baz)
+ return pj_dealloc (p); // clean up + signal error by 0-return
+
+ return p; // success
+
+***********************************************************************/
+ if (0==ptr)
+ return 0;
+ pj_dalloc (ptr);
+ return 0;
+}
diff --git a/src/pj_mutex.c b/src/pj_mutex.c
index dc484c69..2f6533be 100644
--- a/src/pj_mutex.c
+++ b/src/pj_mutex.c
@@ -29,7 +29,7 @@
/* projects.h and windows.h conflict - avoid this! */
#if defined(MUTEX_pthread) && !defined(_XOPEN_SOURCE)
-// For pthread_mutexattr_settype
+/* For pthread_mutexattr_settype */
#define _XOPEN_SOURCE 500
#endif
@@ -86,7 +86,7 @@ void pj_cleanup_lock()
{
}
-#endif // def MUTEX_stub
+#endif /* def MUTEX_stub */
/************************************************************************/
/* ==================================================================== */
@@ -154,7 +154,7 @@ void pj_cleanup_lock()
{
}
-#endif // def MUTEX_pthread
+#endif /* def MUTEX_pthread */
/************************************************************************/
/* ==================================================================== */
@@ -219,4 +219,4 @@ void pj_cleanup_lock()
}
}
-#endif // def MUTEX_win32
+#endif /* def MUTEX_win32 */
diff --git a/src/pj_run_selftests.c b/src/pj_run_selftests.c
new file mode 100644
index 00000000..cede4961
--- /dev/null
+++ b/src/pj_run_selftests.c
@@ -0,0 +1,78 @@
+/******************************************************************************
+ * Project: PROJ.4
+ * Purpose: Generic regression test for PROJ.4 projection algorithms.
+ * Author: Thomas Knudsen
+ *
+ ******************************************************************************
+ * Copyright (c) 2016, Thomas Knudsen
+ *
+ * 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.
+ *****************************************************************************/
+
+#include <stdio.h>
+#define PJ_LIB__
+#include <projects.h>
+
+
+static void run_one_test (const char *mnemonic, int (testfunc)(void), int verbosity, int *n_ok, int *n_ko, int *n_stubs) {
+ int ret = testfunc ();
+ switch (ret) {
+ case 0: (*n_ok)++; break;
+ case 10000: (*n_stubs)++; break;
+ default: (*n_ko)++;
+ }
+
+ if (verbosity) {
+ if (ret==10000)
+ printf ("Testing: %10s - [stub]\n", mnemonic);
+ else
+ printf ("Testing: %10s - return code: %d\n", mnemonic, ret);
+ }
+ return;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_run_selftests (int verbosity) {
+ printf ("This version of libproj is not configured for internal regression tests.\n");
+ return 0;
+}
+#else
+
+
+int pj_run_selftests (int verbosity) {
+ int n_ok = 0, n_ko = 0, n_stubs = 0, i = 0;
+
+ struct PJ_SELFTEST_LIST *tests = pj_get_selftest_list_ref ();
+
+ if (0==tests)
+ printf ("This version of libproj is not configured for internal regression tests.\n");
+
+ if (verbosity)
+ printf ("Running internal regression tests\n");
+
+ for (i = 0; tests[i].testfunc != 0; i++)
+ run_one_test (tests[i].id, tests[i].testfunc, verbosity, &n_ok, &n_ko, &n_stubs);
+
+ if (0==verbosity)
+ printf ("Internal regression tests done. ");
+ printf ("[Stubs: %d] Total: %d. Failure: %d. Success: %d\n", n_stubs, n_ok+n_ko, n_ko, n_ok);
+ return n_ko;
+}
+#endif
diff --git a/src/pj_transform.c b/src/pj_transform.c
index 32f14955..ce7b96a3 100644
--- a/src/pj_transform.c
+++ b/src/pj_transform.c
@@ -1,6 +1,6 @@
/******************************************************************************
* Project: PROJ.4
- * Purpose: Perform overall coordinate system to coordinate system
+ * Purpose: Perform overall coordinate system to coordinate system
* transformations (pj_transform() function) including reprojection
* and datum shifting.
* Author: Frank Warmerdam, warmerdam@pobox.com
@@ -33,7 +33,7 @@
#include "geocent.h"
static int pj_adjust_axis( projCtx ctx, const char *axis, int denormalize_flag,
- long point_count, int point_offset,
+ long point_count, int point_offset,
double *x, double *y, double *z );
#ifndef SRS_WGS84_SEMIMAJOR
@@ -52,23 +52,23 @@ static int pj_adjust_axis( projCtx ctx, const char *axis, int denormalize_flag,
#define Rz_BF (defn->datum_params[5])
#define M_BF (defn->datum_params[6])
-/*
-** This table is intended to indicate for any given error code in
+/*
+** This table is intended to indicate for any given error code in
** the range 0 to -44, whether that error will occur for all locations (ie.
** it is a problem with the coordinate system as a whole) in which case the
** value would be 0, or if the problem is with the point being transformed
-** in which case the value is 1.
+** in which case the value is 1.
**
** At some point we might want to move this array in with the error message
-** list or something, but while experimenting with it this should be fine.
+** list or something, but while experimenting with it this should be fine.
*/
static const int transient_error[50] = {
/* 0 1 2 3 4 5 6 7 8 9 */
- /* 0 to 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 10 to 19 */ 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
- /* 20 to 29 */ 1, 0, 0, 0, 0, 0, 0, 1, 0, 0,
- /* 30 to 39 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0 to 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 10 to 19 */ 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
+ /* 20 to 29 */ 1, 0, 0, 0, 0, 0, 0, 1, 0, 0,
+ /* 30 to 39 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 40 to 49 */ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
/************************************************************************/
@@ -101,7 +101,7 @@ int pj_transform( PJ *srcdefn, PJ *dstdefn, long point_count, int point_offset,
{
int err;
- err = pj_adjust_axis( srcdefn->ctx, srcdefn->axis,
+ err = pj_adjust_axis( srcdefn->ctx, srcdefn->axis,
0, point_count, point_offset, x, y, z );
if( err != 0 )
return err;
@@ -140,7 +140,7 @@ int pj_transform( PJ *srcdefn, PJ *dstdefn, long point_count, int point_offset,
}
err = pj_geocentric_to_geodetic( srcdefn->a_orig, srcdefn->es_orig,
- point_count, point_offset,
+ point_count, point_offset,
x, y, z );
if( err != 0 )
return err;
@@ -153,19 +153,19 @@ int pj_transform( PJ *srcdefn, PJ *dstdefn, long point_count, int point_offset,
else if( !srcdefn->is_latlong )
{
- //Check first if projection is invertible.
+ /* Check first if projection is invertible. */
if( (srcdefn->inv3d == NULL) && (srcdefn->inv == NULL))
{
pj_ctx_set_errno( pj_get_ctx(srcdefn), -17 );
- pj_log( pj_get_ctx(srcdefn), PJ_LOG_ERROR,
+ pj_log( pj_get_ctx(srcdefn), PJ_LOG_ERROR,
"pj_transform(): source projection not invertable" );
return -17;
}
- //If invertible - First try inv3d if defined
+ /* If invertible - First try inv3d if defined */
if (srcdefn->inv3d != NULL)
{
- //Three dimensions must be defined
+ /* Three dimensions must be defined */
if ( z == NULL)
{
pj_ctx_set_errno( pj_get_ctx(srcdefn), PJD_ERR_GEOCENTRIC);
@@ -187,9 +187,9 @@ int pj_transform( PJ *srcdefn, PJ *dstdefn, long point_count, int point_offset,
geodetic_loc = pj_inv3d(projected_loc, srcdefn);
if( srcdefn->ctx->last_errno != 0 )
{
- if( (srcdefn->ctx->last_errno != 33 /*EDOM*/
+ if( (srcdefn->ctx->last_errno != 33 /*EDOM*/
&& srcdefn->ctx->last_errno != 34 /*ERANGE*/ )
- && (srcdefn->ctx->last_errno > 0
+ && (srcdefn->ctx->last_errno > 0
|| srcdefn->ctx->last_errno < -44 || point_count == 1
|| transient_error[-srcdefn->ctx->last_errno] == 0 ) )
return srcdefn->ctx->last_errno;
@@ -210,7 +210,7 @@ int pj_transform( PJ *srcdefn, PJ *dstdefn, long point_count, int point_offset,
}
else
{
- //Fallback to the original PROJ.4 API 2d inversion- inv
+ /* Fallback to the original PROJ.4 API 2d inversion - inv */
for( i = 0; i < point_count; i++ )
{
XY projected_loc;
@@ -225,9 +225,9 @@ int pj_transform( PJ *srcdefn, PJ *dstdefn, long point_count, int point_offset,
geodetic_loc = pj_inv( projected_loc, srcdefn );
if( srcdefn->ctx->last_errno != 0 )
{
- if( (srcdefn->ctx->last_errno != 33 /*EDOM*/
+ if( (srcdefn->ctx->last_errno != 33 /*EDOM*/
&& srcdefn->ctx->last_errno != 34 /*ERANGE*/ )
- && (srcdefn->ctx->last_errno > 0
+ && (srcdefn->ctx->last_errno > 0
|| srcdefn->ctx->last_errno < -44 || point_count == 1
|| transient_error[-srcdefn->ctx->last_errno] == 0 ) )
return srcdefn->ctx->last_errno;
@@ -262,17 +262,17 @@ int pj_transform( PJ *srcdefn, PJ *dstdefn, long point_count, int point_offset,
/* -------------------------------------------------------------------- */
if( srcdefn->has_geoid_vgrids && z != NULL )
{
- if( pj_apply_vgridshift( srcdefn, "sgeoidgrids",
- &(srcdefn->vgridlist_geoid),
+ if( pj_apply_vgridshift( srcdefn, "sgeoidgrids",
+ &(srcdefn->vgridlist_geoid),
&(srcdefn->vgridlist_geoid_count),
0, point_count, point_offset, x, y, z ) != 0 )
return pj_ctx_get_errno(srcdefn->ctx);
}
-
+
/* -------------------------------------------------------------------- */
/* Convert datums if needed, and possible. */
/* -------------------------------------------------------------------- */
- if( pj_datum_transform( srcdefn, dstdefn, point_count, point_offset,
+ if( pj_datum_transform( srcdefn, dstdefn, point_count, point_offset,
x, y, z ) != 0 )
{
if( srcdefn->ctx->last_errno != 0 )
@@ -287,13 +287,13 @@ int pj_transform( PJ *srcdefn, PJ *dstdefn, long point_count, int point_offset,
/* -------------------------------------------------------------------- */
if( dstdefn->has_geoid_vgrids && z != NULL )
{
- if( pj_apply_vgridshift( dstdefn, "sgeoidgrids",
- &(dstdefn->vgridlist_geoid),
+ if( pj_apply_vgridshift( dstdefn, "sgeoidgrids",
+ &(dstdefn->vgridlist_geoid),
&(dstdefn->vgridlist_geoid_count),
1, point_count, point_offset, x, y, z ) != 0 )
return dstdefn->ctx->last_errno;
}
-
+
/* -------------------------------------------------------------------- */
/* But if they are staying lat long, adjust for the prime */
/* meridian if there is one in effect. */
@@ -348,7 +348,7 @@ int pj_transform( PJ *srcdefn, PJ *dstdefn, long point_count, int point_offset,
{
XYZ projected_loc;
LPZ geodetic_loc;
-
+
geodetic_loc.u = x[point_offset*i];
geodetic_loc.v = y[point_offset*i];
geodetic_loc.w = z[point_offset*i];
@@ -359,9 +359,9 @@ int pj_transform( PJ *srcdefn, PJ *dstdefn, long point_count, int point_offset,
projected_loc = pj_fwd3d( geodetic_loc, dstdefn);
if( dstdefn->ctx->last_errno != 0 )
{
- if( (dstdefn->ctx->last_errno != 33 /*EDOM*/
+ if( (dstdefn->ctx->last_errno != 33 /*EDOM*/
&& dstdefn->ctx->last_errno != 34 /*ERANGE*/ )
- && (dstdefn->ctx->last_errno > 0
+ && (dstdefn->ctx->last_errno > 0
|| dstdefn->ctx->last_errno < -44 || point_count == 1
|| transient_error[-dstdefn->ctx->last_errno] == 0 ) )
return dstdefn->ctx->last_errno;
@@ -371,7 +371,7 @@ int pj_transform( PJ *srcdefn, PJ *dstdefn, long point_count, int point_offset,
projected_loc.v = HUGE_VAL;
projected_loc.w = HUGE_VAL;
}
- }
+ }
x[point_offset*i] = projected_loc.u;
y[point_offset*i] = projected_loc.v;
@@ -395,9 +395,9 @@ int pj_transform( PJ *srcdefn, PJ *dstdefn, long point_count, int point_offset,
projected_loc = pj_fwd( geodetic_loc, dstdefn );
if( dstdefn->ctx->last_errno != 0 )
{
- if( (dstdefn->ctx->last_errno != 33 /*EDOM*/
+ if( (dstdefn->ctx->last_errno != 33 /*EDOM*/
&& dstdefn->ctx->last_errno != 34 /*ERANGE*/ )
- && (dstdefn->ctx->last_errno > 0
+ && (dstdefn->ctx->last_errno > 0
|| dstdefn->ctx->last_errno < -44 || point_count == 1
|| transient_error[-dstdefn->ctx->last_errno] == 0 ) )
return dstdefn->ctx->last_errno;
@@ -406,7 +406,7 @@ int pj_transform( PJ *srcdefn, PJ *dstdefn, long point_count, int point_offset,
projected_loc.u = HUGE_VAL;
projected_loc.v = HUGE_VAL;
}
- }
+ }
x[point_offset*i] = projected_loc.u;
y[point_offset*i] = projected_loc.v;
@@ -449,7 +449,7 @@ int pj_transform( PJ *srcdefn, PJ *dstdefn, long point_count, int point_offset,
{
int err;
- err = pj_adjust_axis( dstdefn->ctx, dstdefn->axis,
+ err = pj_adjust_axis( dstdefn->ctx, dstdefn->axis,
1, point_count, point_offset, x, y, z );
if( err != 0 )
return err;
@@ -462,7 +462,7 @@ int pj_transform( PJ *srcdefn, PJ *dstdefn, long point_count, int point_offset,
/* pj_geodetic_to_geocentric() */
/************************************************************************/
-int pj_geodetic_to_geocentric( double a, double es,
+int pj_geodetic_to_geocentric( double a, double es,
long point_count, int point_offset,
double *x, double *y, double *z )
@@ -489,7 +489,7 @@ int pj_geodetic_to_geocentric( double a, double es,
if( x[io] == HUGE_VAL )
continue;
- if( pj_Convert_Geodetic_To_Geocentric( &gi, y[io], x[io], z[io],
+ if( pj_Convert_Geodetic_To_Geocentric( &gi, y[io], x[io], z[io],
x+io, y+io, z+io ) != 0 )
{
ret_errno = -14;
@@ -505,7 +505,7 @@ int pj_geodetic_to_geocentric( double a, double es,
/* pj_geodetic_to_geocentric() */
/************************************************************************/
-int pj_geocentric_to_geodetic( double a, double es,
+int pj_geocentric_to_geodetic( double a, double es,
long point_count, int point_offset,
double *x, double *y, double *z )
@@ -531,7 +531,7 @@ int pj_geocentric_to_geodetic( double a, double es,
if( x[io] == HUGE_VAL )
continue;
- pj_Convert_Geocentric_To_Geodetic( &gi, x[io], y[io], z[io],
+ pj_Convert_Geocentric_To_Geodetic( &gi, x[io], y[io], z[io],
y+io, x+io, z+io );
}
@@ -552,7 +552,7 @@ int pj_compare_datums( PJ *srcdefn, PJ *dstdefn )
{
return 0;
}
- else if( srcdefn->a_orig != dstdefn->a_orig
+ else if( srcdefn->a_orig != dstdefn->a_orig
|| ABS(srcdefn->es_orig - dstdefn->es_orig) > 0.000000000050 )
{
/* the tolerence for es is to ensure that GRS80 and WGS84 are
@@ -588,7 +588,7 @@ int pj_compare_datums( PJ *srcdefn, PJ *dstdefn )
/* pj_geocentic_to_wgs84() */
/************************************************************************/
-int pj_geocentric_to_wgs84( PJ *defn,
+int pj_geocentric_to_wgs84( PJ *defn,
long point_count, int point_offset,
double *x, double *y, double *z )
@@ -600,7 +600,7 @@ int pj_geocentric_to_wgs84( PJ *defn,
for( i = 0; i < point_count; i++ )
{
long io = i * point_offset;
-
+
if( x[io] == HUGE_VAL )
continue;
@@ -636,7 +636,7 @@ int pj_geocentric_to_wgs84( PJ *defn,
/* pj_geocentic_from_wgs84() */
/************************************************************************/
-int pj_geocentric_from_wgs84( PJ *defn,
+int pj_geocentric_from_wgs84( PJ *defn,
long point_count, int point_offset,
double *x, double *y, double *z )
@@ -651,7 +651,7 @@ int pj_geocentric_from_wgs84( PJ *defn,
if( x[io] == HUGE_VAL )
continue;
-
+
x[io] = x[io] - Dx_BF;
y[io] = y[io] - Dy_BF;
z[io] = z[io] - Dz_BF;
@@ -688,7 +688,7 @@ int pj_geocentric_from_wgs84( PJ *defn,
/* coordinates in radians in the destination datum. */
/************************************************************************/
-int pj_datum_transform( PJ *srcdefn, PJ *dstdefn,
+int pj_datum_transform( PJ *srcdefn, PJ *dstdefn,
long point_count, int point_offset,
double *x, double *y, double *z )
@@ -754,15 +754,15 @@ int pj_datum_transform( PJ *srcdefn, PJ *dstdefn,
/* Do we need to go through geocentric coordinates? */
/* ==================================================================== */
if( src_es != dst_es || src_a != dst_a
- || srcdefn->datum_type == PJD_3PARAM
+ || srcdefn->datum_type == PJD_3PARAM
|| srcdefn->datum_type == PJD_7PARAM
- || dstdefn->datum_type == PJD_3PARAM
+ || dstdefn->datum_type == PJD_3PARAM
|| dstdefn->datum_type == PJD_7PARAM)
{
/* -------------------------------------------------------------------- */
/* Convert to geocentric coordinates. */
/* -------------------------------------------------------------------- */
- srcdefn->ctx->last_errno =
+ srcdefn->ctx->last_errno =
pj_geodetic_to_geocentric( src_a, src_es,
point_count, point_offset, x, y, z );
CHECK_RETURN(srcdefn);
@@ -770,14 +770,14 @@ int pj_datum_transform( PJ *srcdefn, PJ *dstdefn,
/* -------------------------------------------------------------------- */
/* Convert between datums. */
/* -------------------------------------------------------------------- */
- if( srcdefn->datum_type == PJD_3PARAM
+ if( srcdefn->datum_type == PJD_3PARAM
|| srcdefn->datum_type == PJD_7PARAM )
{
pj_geocentric_to_wgs84( srcdefn, point_count, point_offset,x,y,z);
CHECK_RETURN(srcdefn);
}
- if( dstdefn->datum_type == PJD_3PARAM
+ if( dstdefn->datum_type == PJD_3PARAM
|| dstdefn->datum_type == PJD_7PARAM )
{
pj_geocentric_from_wgs84( dstdefn, point_count,point_offset,x,y,z);
@@ -787,7 +787,7 @@ int pj_datum_transform( PJ *srcdefn, PJ *dstdefn,
/* -------------------------------------------------------------------- */
/* Convert back to geodetic coordinates. */
/* -------------------------------------------------------------------- */
- dstdefn->ctx->last_errno =
+ dstdefn->ctx->last_errno =
pj_geocentric_to_geodetic( dst_a, dst_es,
point_count, point_offset, x, y, z );
CHECK_RETURN(dstdefn);
@@ -814,9 +814,9 @@ int pj_datum_transform( PJ *srcdefn, PJ *dstdefn,
/* Normalize or de-normalized the x/y/z axes. The normal form */
/* is "enu" (easting, northing, up). */
/************************************************************************/
-static int pj_adjust_axis( projCtx ctx,
+static int pj_adjust_axis( projCtx ctx,
const char *axis, int denormalize_flag,
- long point_count, int point_offset,
+ long point_count, int point_offset,
double *x, double *y, double *z )
{
@@ -831,7 +831,7 @@ static int pj_adjust_axis( projCtx ctx,
y_in = y[point_offset*i];
if( z )
z_in = z[point_offset*i];
-
+
for( i_axis = 0; i_axis < 3; i_axis++ )
{
double value;
@@ -842,7 +842,7 @@ static int pj_adjust_axis( projCtx ctx,
value = y_in;
else
value = z_in;
-
+
switch( axis[i_axis] )
{
case 'e':
@@ -873,7 +873,7 @@ static int pj_adjust_axis( projCtx ctx,
y_in = y[point_offset*i];
if( z )
z_in = z[point_offset*i];
-
+
for( i_axis = 0; i_axis < 3; i_axis++ )
{
double *target;
@@ -887,7 +887,7 @@ static int pj_adjust_axis( projCtx ctx,
target = y;
else
target = z;
-
+
switch( axis[i_axis] )
{
case 'e':
@@ -909,7 +909,6 @@ static int pj_adjust_axis( projCtx ctx,
} /* i_axis */
} /* i (point) */
}
-
+
return 0;
}
-
diff --git a/src/pj_utils.c b/src/pj_utils.c
index f11081fc..203c637c 100644
--- a/src/pj_utils.c
+++ b/src/pj_utils.c
@@ -78,27 +78,27 @@ PJ *pj_latlong_from_proj( PJ *pj_in )
if( pj_param(pj_in->ctx, pj_in->params, "tdatum").i )
{
got_datum = TRUE;
- sprintf( defn+strlen(defn), " +datum=%s",
+ sprintf( defn+strlen(defn), " +datum=%s",
pj_param(pj_in->ctx, pj_in->params,"sdatum").s );
}
else if( pj_param(pj_in->ctx, pj_in->params, "tellps").i )
{
- sprintf( defn+strlen(defn), " +ellps=%s",
+ sprintf( defn+strlen(defn), " +ellps=%s",
pj_param(pj_in->ctx, pj_in->params,"sellps").s );
}
else if( pj_param(pj_in->ctx,pj_in->params, "ta").i )
{
- sprintf( defn+strlen(defn), " +a=%s",
+ sprintf( defn+strlen(defn), " +a=%s",
pj_param(pj_in->ctx,pj_in->params,"sa").s );
-
+
if( pj_param(pj_in->ctx,pj_in->params, "tb").i )
- sprintf( defn+strlen(defn), " +b=%s",
+ sprintf( defn+strlen(defn), " +b=%s",
pj_param(pj_in->ctx,pj_in->params,"sb").s );
else if( pj_param(pj_in->ctx,pj_in->params, "tes").i )
- sprintf( defn+strlen(defn), " +es=%s",
+ sprintf( defn+strlen(defn), " +es=%s",
pj_param(pj_in->ctx,pj_in->params,"ses").s );
else if( pj_param(pj_in->ctx,pj_in->params, "tf").i )
- sprintf( defn+strlen(defn), " +f=%s",
+ sprintf( defn+strlen(defn), " +f=%s",
pj_param(pj_in->ctx,pj_in->params,"sf").s );
else
{
@@ -121,17 +121,17 @@ PJ *pj_latlong_from_proj( PJ *pj_in )
if( !got_datum )
{
if( pj_param(pj_in->ctx,pj_in->params, "ttowgs84").i )
- sprintf( defn+strlen(defn), " +towgs84=%s",
+ sprintf( defn+strlen(defn), " +towgs84=%s",
pj_param(pj_in->ctx,pj_in->params,"stowgs84").s );
if( pj_param(pj_in->ctx,pj_in->params, "tnadgrids").i )
- sprintf( defn+strlen(defn), " +nadgrids=%s",
+ sprintf( defn+strlen(defn), " +nadgrids=%s",
pj_param(pj_in->ctx,pj_in->params,"snadgrids").s );
}
/* copy over some other information related to ellipsoid */
if( pj_param(pj_in->ctx,pj_in->params, "tR").i )
- sprintf( defn+strlen(defn), " +R=%s",
+ sprintf( defn+strlen(defn), " +R=%s",
pj_param(pj_in->ctx,pj_in->params,"sR").s );
if( pj_param(pj_in->ctx,pj_in->params, "tR_A").i )
@@ -144,16 +144,16 @@ PJ *pj_latlong_from_proj( PJ *pj_in )
sprintf( defn+strlen(defn), " +R_a" );
if( pj_param(pj_in->ctx,pj_in->params, "tR_lat_a").i )
- sprintf( defn+strlen(defn), " +R_lat_a=%s",
+ sprintf( defn+strlen(defn), " +R_lat_a=%s",
pj_param(pj_in->ctx,pj_in->params,"sR_lat_a").s );
if( pj_param(pj_in->ctx,pj_in->params, "tR_lat_g").i )
- sprintf( defn+strlen(defn), " +R_lat_g=%s",
+ sprintf( defn+strlen(defn), " +R_lat_g=%s",
pj_param(pj_in->ctx,pj_in->params,"sR_lat_g").s );
/* copy over prime meridian */
if( pj_param(pj_in->ctx,pj_in->params, "tpm").i )
- sprintf( defn+strlen(defn), " +pm=%s",
+ sprintf( defn+strlen(defn), " +pm=%s",
pj_param(pj_in->ctx,pj_in->params,"spm").s );
return pj_init_plus_ctx( pj_in->ctx, defn );
@@ -172,7 +172,7 @@ void pj_get_spheroid_defn(projPJ defn, double *major_axis, double *eccentricity_
{
if ( major_axis )
*major_axis = defn->a;
-
+
if ( eccentricity_squared )
*eccentricity_squared = defn->es;
-};
+}
diff --git a/src/proj.c b/src/proj.c
index 23f9cca9..00853994 100644
--- a/src/proj.c
+++ b/src/proj.c
@@ -42,7 +42,7 @@ postscale = 0;
*oform = (char *)0, /* output format for x-y or decimal degrees */
*oterr = "*\t*", /* output line for unprojectable input */
*usage =
-"%s\nusage: %s [ -beEfiIlormsStTvVwW [args] ] [ +opts[=arg] ] [ files ]\n";
+"%s\nusage: %s [ -bCeEfiIlormsStTvVwW [args] ] [ +opts[=arg] ] [ files ]\n";
static struct FACTORS
facs;
static double
@@ -158,7 +158,7 @@ vprocess(FILE *fid) {
if (!oform)
oform = "%.3f";
if (bin_in || bin_out)
- emess(1,"binary I/O not available in -V option");
+ emess(1,"binary I/O not available in -V option");
for (;;) {
++emess_dat.File_line;
if (!(s = fgets(line, MAX_LINE, fid)))
@@ -267,6 +267,10 @@ int main(int argc, char **argv) {
case 'b': /* binary I/O */
bin_in = bin_out = 1;
continue;
+ case 'C': /* Check - run internal regression tests */
+ pj_run_selftests (very_verby);
+ return 0;
+ continue;
case 'v': /* monitor dump of initialization */
mon = 1;
continue;
@@ -300,8 +304,8 @@ int main(int argc, char **argv) {
char *str;
for (lp = pj_get_list_ref() ; lp->id ; ++lp) {
- if( strcmp(lp->id,"latlong") == 0
- || strcmp(lp->id,"longlat") == 0
+ if( strcmp(lp->id,"latlong") == 0
+ || strcmp(lp->id,"longlat") == 0
|| strcmp(lp->id,"geocent") == 0 )
continue;
@@ -353,7 +357,7 @@ int main(int argc, char **argv) {
continue; /* artificial */
case 'e': /* error line alternative */
if (--argc <= 0)
- noargument:
+ noargument:
emess(1,"missing argument for -%c",*arg);
oterr = *++argv;
continue;
@@ -364,7 +368,7 @@ int main(int argc, char **argv) {
case 'm': /* cartesian multiplier */
if (--argc <= 0) goto noargument;
postscale = 1;
- if (!strncmp("1/",*++argv,2) ||
+ if (!strncmp("1/",*++argv,2) ||
!strncmp("1:",*argv,2)) {
if((fscale = atof((*argv)+2)) == 0.)
goto badscale;
diff --git a/src/proj.def b/src/proj.def
index c7708cc5..1f228a6c 100644
--- a/src/proj.def
+++ b/src/proj.def
@@ -1,90 +1,91 @@
-VERSION 1.2
+VERSION 1.2
EXPORTS
- pj_init @1
- pj_fwd @2
- pj_inv @3
- pj_free @4
- pj_transform @5
- pj_geocentric_to_geodetic @6
- pj_geodetic_to_geocentric @7
- pj_deallocate_grids @8
- pj_init_plus @9
- pj_latlong_from_proj @10
- pj_is_latlong @11
- pj_get_errno_ref @12
- pj_set_finder @13
- pj_strerrno @14
- pj_errno @15
- pj_get_def @16
- pj_dalloc @17
- pj_is_geocent @18
- pj_get_release @19
- pj_malloc @20
- pj_pr_list @21
- pj_compare_datums @22
- pj_apply_gridshift @23
- pj_datum_transform @24
- pj_set_searchpath @25
- dmstor @26
- pj_get_ellps_ref @27
- pj_get_datums_ref @28
- pj_get_units_ref @29
- pj_get_list_ref @30
- pj_get_prime_meridians_ref @31
- rtodms @32
- set_rtodms @33
- pj_factors @34
- mk_cheby @35
- adjlon @36
- pj_param @37
- pj_ell_set @38
- pj_mkparam @39
- pj_init_ctx @40
- pj_init_plus_ctx @41
- pj_get_default_ctx @42
- pj_get_ctx @43
- pj_set_ctx @44
- pj_ctx_alloc @45
- pj_ctx_free @46
- pj_ctx_get_errno @47
- pj_ctx_set_errno @48
- pj_ctx_set_debug @49
- pj_ctx_set_logger @50
- pj_ctx_set_app_data @51
- pj_ctx_get_app_data @52
- pj_log @53
- pj_clear_initcache @54
- geod_init @55
- geod_lineinit @56
- geod_genposition @57
- geod_position @58
- geod_gendirect @59
- geod_direct @60
- geod_geninverse @61
- geod_inverse @62
- geod_polygonarea @63
- pj_get_spheroid_defn @64
- pj_get_default_fileapi @65
- pj_ctx_set_fileapi @66
- pj_ctx_get_fileapi @67
- pj_ctx_fopen @68
- pj_ctx_fread @69
- pj_ctx_ftell @70
- pj_ctx_fclose @71
- pj_open_lib @72
- pj_atof @73
- pj_strtod @74
- pj_fwd3d @75
- pj_inv3d @76
- geod_gensetdistance @77
- geod_setdistance @78
- geod_gendirectline @79
- geod_directline @80
- geod_inverseline @81
- geod_polygon_init @82
- geod_polygon_addedge @83
- geod_polygon_addpoint @84
- geod_polygon_compute @85
- geod_polygon_testedge @86
- geod_polygon_testpoint @87
- geod_polygon_clear @88
+ pj_init @1
+ pj_fwd @2
+ pj_inv @3
+ pj_free @4
+ pj_transform @5
+ pj_geocentric_to_geodetic @6
+ pj_geodetic_to_geocentric @7
+ pj_deallocate_grids @8
+ pj_init_plus @9
+ pj_latlong_from_proj @10
+ pj_is_latlong @11
+ pj_get_errno_ref @12
+ pj_set_finder @13
+ pj_strerrno @14
+ pj_errno @15
+ pj_get_def @16
+ pj_dalloc @17
+ pj_is_geocent @18
+ pj_get_release @19
+ pj_malloc @20
+ pj_pr_list @21
+ pj_compare_datums @22
+ pj_apply_gridshift @23
+ pj_datum_transform @24
+ pj_set_searchpath @25
+ dmstor @26
+ pj_get_ellps_ref @27
+ pj_get_datums_ref @28
+ pj_get_units_ref @29
+ pj_get_list_ref @30
+ pj_get_prime_meridians_ref @31
+ rtodms @32
+ set_rtodms @33
+ pj_factors @34
+ mk_cheby @35
+ adjlon @36
+ pj_param @37
+ pj_ell_set @38
+ pj_mkparam @39
+ pj_init_ctx @40
+ pj_init_plus_ctx @41
+ pj_get_default_ctx @42
+ pj_get_ctx @43
+ pj_set_ctx @44
+ pj_ctx_alloc @45
+ pj_ctx_free @46
+ pj_ctx_get_errno @47
+ pj_ctx_set_errno @48
+ pj_ctx_set_debug @49
+ pj_ctx_set_logger @50
+ pj_ctx_set_app_data @51
+ pj_ctx_get_app_data @52
+ pj_log @53
+ pj_clear_initcache @54
+ geod_init @55
+ geod_lineinit @56
+ geod_genposition @57
+ geod_position @58
+ geod_gendirect @59
+ geod_direct @60
+ geod_geninverse @61
+ geod_inverse @62
+ geod_polygonarea @63
+ pj_get_spheroid_defn @64
+ pj_get_default_fileapi @65
+ pj_ctx_set_fileapi @66
+ pj_ctx_get_fileapi @67
+ pj_ctx_fopen @68
+ pj_ctx_fread @69
+ pj_ctx_ftell @70
+ pj_ctx_fclose @71
+ pj_open_lib @72
+ pj_atof @73
+ pj_strtod @74
+ pj_fwd3d @75
+ pj_inv3d @76
+ geod_gensetdistance @77
+ geod_setdistance @78
+ geod_gendirectline @79
+ geod_directline @80
+ geod_inverseline @81
+ geod_polygon_init @82
+ geod_polygon_addedge @83
+ geod_polygon_addpoint @84
+ geod_polygon_compute @85
+ geod_polygon_testedge @86
+ geod_polygon_testpoint @87
+ geod_polygon_clear @88
+ pj_run_selftests @89
diff --git a/src/proj_api.h b/src/proj_api.h
index b482c0f5..24a6f053 100644
--- a/src/proj_api.h
+++ b/src/proj_api.h
@@ -130,6 +130,8 @@ char *pj_get_def(projPJ, int);
projPJ pj_latlong_from_proj( projPJ );
void *pj_malloc(size_t);
void pj_dalloc(void *);
+void *pj_calloc (size_t n, size_t size);
+void *pj_dealloc (void *ptr);
char *pj_strerrno(int);
int *pj_get_errno_ref(void);
const char *pj_get_release(void);
@@ -166,6 +168,9 @@ char *pj_ctx_fgets(projCtx ctx, char *line, int size, PAFile file);
PAFile pj_open_lib(projCtx, const char *, const char *);
+int pj_run_selftests (int verbosity);
+
+
#define PJ_LOG_NONE 0
#define PJ_LOG_ERROR 1
#define PJ_LOG_DEBUG_MAJOR 2
diff --git a/src/proj_etmerc.c b/src/proj_etmerc.c
index 3ef0903f..a88a0837 100644
--- a/src/proj_etmerc.c
+++ b/src/proj_etmerc.c
@@ -35,20 +35,24 @@
*
* Modified and used here by permission of Reference Networks
* Division, Kort og Matrikelstyrelsen (KMS), Copenhagen, Denmark
+ *
*/
-#define PROJ_PARMS__ \
+
+#define PROJ_LIB__
+#define PJ_LIB__
+
+#include <projects.h>
+
+
+struct pj_opaque {
double Qn; /* Merid. quad., scaled to the projection */ \
double Zb; /* Radius vector in polar coord. systems */ \
double cgb[6]; /* Constants for Gauss -> Geo lat */ \
double cbg[6]; /* Constants for Geo lat -> Gauss */ \
double utg[6]; /* Constants for transv. merc. -> geo */ \
double gtu[6]; /* Constants for geo -> transv. merc. */
-
-#define PROJ_LIB__
-#define PJ_LIB__
-
-#include <projects.h>
+};
PROJ_HEAD(etmerc, "Extended Transverse Mercator")
"\n\tCyl, Sph\n\tlat_ts=(0)\nlat_0=(0)";
@@ -57,11 +61,11 @@ PROJ_HEAD(utm, "Universal Transverse Mercator (UTM)")
#define PROJ_ETMERC_ORDER 6
+
#ifdef _GNU_SOURCE
inline
#endif
- static double
-log1py(double x) { /* Compute log(1+x) accurately */
+static double log1py(double x) { /* Compute log(1+x) accurately */
volatile double
y = 1 + x,
z = y - 1;
@@ -72,21 +76,21 @@ log1py(double x) { /* Compute log(1+x) accurately */
return z == 0 ? x : x * log(y) / z;
}
+
#ifdef _GNU_SOURCE
inline
#endif
- static double
-asinhy(double x) { /* Compute asinh(x) accurately */
+static double asinhy(double x) { /* Compute asinh(x) accurately */
double y = fabs(x); /* Enforce odd parity */
y = log1py(y * (1 + y/(hypot(1.0, y) + 1)));
return x < 0 ? -y : y;
}
+
#ifdef _GNU_SOURCE
inline
#endif
- static double
-gatg(double *p1, int len_p1, double B) {
+static double gatg(double *p1, int len_p1, double B) {
double *p;
double h = 0, h1, h2 = 0, cos_2B;
@@ -96,11 +100,11 @@ gatg(double *p1, int len_p1, double B) {
return (B + h*sin(2*B));
}
+/* Complex Clenshaw summation */
#ifdef _GNU_SOURCE
inline
#endif
- static double
-clenS(double *a, int size, double arg_r, double arg_i, double *R, double *I) {
+static double clenS(double *a, int size, double arg_r, double arg_i, double *R, double *I) {
double *p, r, i, hr, hr1, hr2, hi, hi1, hi2;
double sin_arg_r, cos_arg_r, sinh_arg_i, cosh_arg_i;
@@ -116,6 +120,7 @@ clenS(double *a, int size, double arg_r, double arg_i, double *R, double *I) {
cosh_arg_i = cosh(arg_i);
r = 2*cos_arg_r*cosh_arg_i;
i = -2*sin_arg_r*sinh_arg_i;
+
/* summation loop */
for (hi1 = hr1 = hi = 0, hr = *--p; a - p;) {
hr2 = hr1;
@@ -125,100 +130,132 @@ clenS(double *a, int size, double arg_r, double arg_i, double *R, double *I) {
hr = -hr2 + r*hr1 - i*hi1 + *--p;
hi = -hi2 + i*hr1 + r*hi1;
}
+
r = sin_arg_r*cosh_arg_i;
i = cos_arg_r*sinh_arg_i;
*R = r*hr - i*hi;
*I = r*hi + i*hr;
- return(*R);
+ return *R;
}
- static double
-clens(double *a, int size, double arg_r) {
+
+
+/* Real Clenshaw summation */
+static double clens(double *a, int size, double arg_r) {
double *p, r, hr, hr1, hr2, cos_arg_r;
p = a + size;
cos_arg_r = cos(arg_r);
r = 2*cos_arg_r;
+
/* summation loop */
for (hr1 = 0, hr = *--p; a - p;) {
hr2 = hr1;
hr1 = hr;
hr = -hr2 + r*hr1 + *--p;
}
- return(sin(arg_r)*hr);
+ return sin (arg_r)*hr;
}
-FORWARD(e_forward); /* ellipsoid */
+
+
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
+ XY xy = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
double sin_Cn, cos_Cn, cos_Ce, sin_Ce, dCn, dCe;
double Cn = lp.phi, Ce = lp.lam;
/* ell. LAT, LNG -> Gaussian LAT, LNG */
- Cn = gatg(P->cbg, PROJ_ETMERC_ORDER, Cn);
+ Cn = gatg (Q->cbg, PROJ_ETMERC_ORDER, Cn);
/* Gaussian LAT, LNG -> compl. sph. LAT */
#ifdef _GNU_SOURCE
- sincos(Cn, &sin_Cn, &cos_Cn);
- sincos(Ce, &sin_Ce, &cos_Ce);
+ sincos (Cn, &sin_Cn, &cos_Cn);
+ sincos (Ce, &sin_Ce, &cos_Ce);
#else
- sin_Cn = sin(Cn);
- cos_Cn = cos(Cn);
- sin_Ce = sin(Ce);
- cos_Ce = cos(Ce);
+ sin_Cn = sin (Cn);
+ cos_Cn = cos (Cn);
+ sin_Ce = sin (Ce);
+ cos_Ce = cos (Ce);
#endif
- Cn = atan2(sin_Cn, cos_Ce*cos_Cn);
- Ce = atan2(sin_Ce*cos_Cn, hypot(sin_Cn, cos_Cn*cos_Ce));
+ Cn = atan2 (sin_Cn, cos_Ce*cos_Cn);
+ Ce = atan2 (sin_Ce*cos_Cn, hypot (sin_Cn, cos_Cn*cos_Ce));
+
/* compl. sph. N, E -> ell. norm. N, E */
- Ce = asinhy(tan(Ce)); /* Replaces: Ce = log(tan(FORTPI + Ce*0.5)); */
- Cn += clenS(P->gtu, PROJ_ETMERC_ORDER, 2*Cn, 2*Ce, &dCn, &dCe);
+ Ce = asinhy ( tan (Ce) ); /* Replaces: Ce = log(tan(FORTPI + Ce*0.5)); */
+ Cn += clenS (Q->gtu, PROJ_ETMERC_ORDER, 2*Cn, 2*Ce, &dCn, &dCe);
Ce += dCe;
- if (fabs(Ce) <= 2.623395162778) {
- xy.y = P->Qn * Cn + P->Zb; /* Northing */
- xy.x = P->Qn * Ce; /* Easting */
+ if (fabs (Ce) <= 2.623395162778) {
+ xy.y = Q->Qn * Cn + Q->Zb; /* Northing */
+ xy.x = Q->Qn * Ce; /* Easting */
} else
xy.x = xy.y = HUGE_VAL;
- return (xy);
+ return xy;
}
-INVERSE(e_inverse); /* ellipsoid */
+
+
+static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
double sin_Cn, cos_Cn, cos_Ce, sin_Ce, dCn, dCe;
double Cn = xy.y, Ce = xy.x;
/* normalize N, E */
- Cn = (Cn - P->Zb)/P->Qn;
- Ce = Ce/P->Qn;
+ Cn = (Cn - Q->Zb)/Q->Qn;
+ Ce = Ce/Q->Qn;
+
if (fabs(Ce) <= 2.623395162778) { /* 150 degrees */
- /* norm. N, E -> compl. sph. LAT, LNG */
- Cn += clenS(P->utg, PROJ_ETMERC_ORDER, 2*Cn, 2*Ce, &dCn, &dCe);
+ /* norm. N, E -> compl. sph. LAT, LNG */
+ Cn += clenS(Q->utg, PROJ_ETMERC_ORDER, 2*Cn, 2*Ce, &dCn, &dCe);
Ce += dCe;
- Ce = atan(sinh(Ce)); /* Replaces: Ce = 2*(atan(exp(Ce)) - FORTPI); */
+ Ce = atan (sinh (Ce)); /* Replaces: Ce = 2*(atan(exp(Ce)) - FORTPI); */
/* compl. sph. LAT -> Gaussian LAT, LNG */
#ifdef _GNU_SOURCE
- sincos(Cn, &sin_Cn, &cos_Cn);
- sincos(Ce, &sin_Ce, &cos_Ce);
+ sincos (Cn, &sin_Cn, &cos_Cn);
+ sincos (Ce, &sin_Ce, &cos_Ce);
#else
- sin_Cn = sin(Cn);
- cos_Cn = cos(Cn);
- sin_Ce = sin(Ce);
- cos_Ce = cos(Ce);
+ sin_Cn = sin (Cn);
+ cos_Cn = cos (Cn);
+ sin_Ce = sin (Ce);
+ cos_Ce = cos (Ce);
#endif
- Ce = atan2(sin_Ce, cos_Ce*cos_Cn);
- Cn = atan2(sin_Cn*cos_Ce, hypot(sin_Ce, cos_Ce*cos_Cn));
+ Ce = atan2 (sin_Ce, cos_Ce*cos_Cn);
+ Cn = atan2 (sin_Cn*cos_Ce, hypot (sin_Ce, cos_Ce*cos_Cn));
/* Gaussian LAT, LNG -> ell. LAT, LNG */
- lp.phi = gatg(P->cgb, PROJ_ETMERC_ORDER, Cn);
+ lp.phi = gatg (Q->cgb, PROJ_ETMERC_ORDER, Cn);
lp.lam = Ce;
}
else
lp.phi = lp.lam = HUGE_VAL;
- return (lp);
+ return lp;
}
-FREEUP; if (P) free(P); }
- static PJ *
-setup(PJ *P) { /* general initialization */
+
+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) { /* general initialization */
double f, n, np, Z;
+ struct pj_opaque *Q = P->opaque;
+
+ if (P->es <= 0)
+ E_ERROR(-34);
+
+ /* flattening */
+ f = P->es / (1 + sqrt (1 - P->es)); /* Replaces: f = 1 - sqrt(1-P->es); */
- if (P->es <= 0) E_ERROR(-34);
- f = P->es / (1 + sqrt(1 - P->es)); /* Replaces: f = 1 - sqrt(1-P->es); */
/* third flattening */
np = n = f/(2 - f);
@@ -226,93 +263,217 @@ setup(PJ *P) { /* general initialization */
/* cgb := Gaussian -> Geodetic, KW p190 - 191 (61) - (62) */
/* cbg := Geodetic -> Gaussian, KW p186 - 187 (51) - (52) */
/* PROJ_ETMERC_ORDER = 6th degree : Engsager and Poder: ICC2007 */
- P->cgb[0] = n*( 2 + n*(-2/3.0 + n*(-2 + n*(116/45.0 + n*(26/45.0 +
+
+ Q->cgb[0] = n*( 2 + n*(-2/3.0 + n*(-2 + n*(116/45.0 + n*(26/45.0 +
n*(-2854/675.0 ))))));
- P->cbg[0] = n*(-2 + n*( 2/3.0 + n*( 4/3.0 + n*(-82/45.0 + n*(32/45.0 +
+ Q->cbg[0] = n*(-2 + n*( 2/3.0 + n*( 4/3.0 + n*(-82/45.0 + n*(32/45.0 +
n*( 4642/4725.0))))));
np *= n;
- P->cgb[1] = np*(7/3.0 + n*( -8/5.0 + n*(-227/45.0 + n*(2704/315.0 +
+ Q->cgb[1] = np*(7/3.0 + n*( -8/5.0 + n*(-227/45.0 + n*(2704/315.0 +
n*( 2323/945.0)))));
- P->cbg[1] = np*(5/3.0 + n*(-16/15.0 + n*( -13/9.0 + n*( 904/315.0 +
+ Q->cbg[1] = np*(5/3.0 + n*(-16/15.0 + n*( -13/9.0 + n*( 904/315.0 +
n*(-1522/945.0)))));
np *= n;
/* n^5 coeff corrected from 1262/105 -> -1262/105 */
- P->cgb[2] = np*( 56/15.0 + n*(-136/35.0 + n*(-1262/105.0 +
+ Q->cgb[2] = np*( 56/15.0 + n*(-136/35.0 + n*(-1262/105.0 +
n*( 73814/2835.0))));
- P->cbg[2] = np*(-26/15.0 + n*( 34/21.0 + n*( 8/5.0 +
+ Q->cbg[2] = np*(-26/15.0 + n*( 34/21.0 + n*( 8/5.0 +
n*(-12686/2835.0))));
np *= n;
/* n^5 coeff corrected from 322/35 -> 332/35 */
- P->cgb[3] = np*(4279/630.0 + n*(-332/35.0 + n*(-399572/14175.0)));
- P->cbg[3] = np*(1237/630.0 + n*( -12/5.0 + n*( -24832/14175.0)));
+ Q->cgb[3] = np*(4279/630.0 + n*(-332/35.0 + n*(-399572/14175.0)));
+ Q->cbg[3] = np*(1237/630.0 + n*( -12/5.0 + n*( -24832/14175.0)));
np *= n;
- P->cgb[4] = np*(4174/315.0 + n*(-144838/6237.0 ));
- P->cbg[4] = np*(-734/315.0 + n*( 109598/31185.0));
+ Q->cgb[4] = np*(4174/315.0 + n*(-144838/6237.0 ));
+ Q->cbg[4] = np*(-734/315.0 + n*( 109598/31185.0));
np *= n;
- P->cgb[5] = np*(601676/22275.0 );
- P->cbg[5] = np*(444337/155925.0);
+ Q->cgb[5] = np*(601676/22275.0 );
+ Q->cbg[5] = np*(444337/155925.0);
/* Constants of the projections */
/* Transverse Mercator (UTM, ITM, etc) */
np = n*n;
/* Norm. mer. quad, K&W p.50 (96), p.19 (38b), p.5 (2) */
- P->Qn = P->k0/(1 + n) * (1 + np*(1/4.0 + np*(1/64.0 + np/256.0)));
+ Q->Qn = P->k0/(1 + n) * (1 + np*(1/4.0 + np*(1/64.0 + np/256.0)));
/* coef of trig series */
/* utg := ell. N, E -> sph. N, E, KW p194 (65) */
/* gtu := sph. N, E -> ell. N, E, KW p196 (69) */
- P->utg[0] = n*(-0.5 + n*( 2/3.0 + n*(-37/96.0 + n*( 1/360.0 +
+ Q->utg[0] = n*(-0.5 + n*( 2/3.0 + n*(-37/96.0 + n*( 1/360.0 +
n*( 81/512.0 + n*(-96199/604800.0))))));
- P->gtu[0] = n*( 0.5 + n*(-2/3.0 + n*( 5/16.0 + n*(41/180.0 +
+ Q->gtu[0] = n*( 0.5 + n*(-2/3.0 + n*( 5/16.0 + n*(41/180.0 +
n*(-127/288.0 + n*( 7891/37800.0 ))))));
- P->utg[1] = np*(-1/48.0 + n*(-1/15.0 + n*(437/1440.0 + n*(-46/105.0 +
+ Q->utg[1] = np*(-1/48.0 + n*(-1/15.0 + n*(437/1440.0 + n*(-46/105.0 +
n*( 1118711/3870720.0)))));
- P->gtu[1] = np*(13/48.0 + n*(-3/5.0 + n*(557/1440.0 + n*(281/630.0 +
+ Q->gtu[1] = np*(13/48.0 + n*(-3/5.0 + n*(557/1440.0 + n*(281/630.0 +
n*(-1983433/1935360.0)))));
np *= n;
- P->utg[2] = np*(-17/480.0 + n*( 37/840.0 + n*( 209/4480.0 +
+ Q->utg[2] = np*(-17/480.0 + n*( 37/840.0 + n*( 209/4480.0 +
n*( -5569/90720.0 ))));
- P->gtu[2] = np*( 61/240.0 + n*(-103/140.0 + n*(15061/26880.0 +
+ Q->gtu[2] = np*( 61/240.0 + n*(-103/140.0 + n*(15061/26880.0 +
n*(167603/181440.0))));
np *= n;
- P->utg[3] = np*(-4397/161280.0 + n*( 11/504.0 + n*( 830251/7257600.0)));
- P->gtu[3] = np*(49561/161280.0 + n*(-179/168.0 + n*(6601661/7257600.0)));
+ Q->utg[3] = np*(-4397/161280.0 + n*( 11/504.0 + n*( 830251/7257600.0)));
+ Q->gtu[3] = np*(49561/161280.0 + n*(-179/168.0 + n*(6601661/7257600.0)));
np *= n;
- P->utg[4] = np*(-4583/161280.0 + n*( 108847/3991680.0));
- P->gtu[4] = np*(34729/80640.0 + n*(-3418889/1995840.0));
+ Q->utg[4] = np*(-4583/161280.0 + n*( 108847/3991680.0));
+ Q->gtu[4] = np*(34729/80640.0 + n*(-3418889/1995840.0));
np *= n;
- P->utg[5] = np*(-20648693/638668800.0);
- P->gtu[5] = np*(212378941/319334400.0);
+ Q->utg[5] = np*(-20648693/638668800.0);
+ Q->gtu[5] = np*(212378941/319334400.0);
+
/* Gaussian latitude value of the origin latitude */
- Z = gatg(P->cbg, PROJ_ETMERC_ORDER, P->phi0);
+ Z = gatg (Q->cbg, PROJ_ETMERC_ORDER, P->phi0);
+
/* Origin northing minus true northing at the origin latitude */
/* i.e. true northing = N - P->Zb */
- P->Zb = - P->Qn*(Z + clens(P->gtu, PROJ_ETMERC_ORDER, 2*Z));
+ Q->Zb = - Q->Qn*(Z + clens(Q->gtu, PROJ_ETMERC_ORDER, 2*Z));
P->inv = e_inverse;
P->fwd = e_forward;
return P;
}
-ENTRY0(etmerc)
-ENDENTRY(setup(P))
+
+
+PJ *PROJECTION(etmerc) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+ return setup (P);
+}
+
+
+
+
+
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_etmerc_selftest (void) {return 0;}
+#else
+
+int pj_etmerc_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=etmerc +ellps=GRS80 +lat_1=0.5 +lat_2=2 +n=0.5 +zone=30"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ {222650.79679758562, 110642.22941193319},
+ {222650.79679758562, -110642.22941193319},
+ {-222650.79679758562, 110642.22941193319},
+ {-222650.79679758562, -110642.22941193319},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ {0.0017966305681649398, 0.00090436947663183873},
+ {0.0017966305681649398, -0.00090436947663183873},
+ {-0.0017966305681649398, 0.00090436947663183873},
+ {-0.0017966305681649398, -0.00090436947663183873},
+ };
+
+ return pj_generic_selftest (e_args, 0, tolerance_xy, tolerance_lp, 4, 4, fwd_in, e_fwd_expect, 0, inv_in, e_inv_expect, 0);
+}
+#endif
+
+
+
+
+
+
+
+
+
+
+
/* utm uses etmerc for the underlying projection */
-ENTRY0(utm)
+
+
+PJ *PROJECTION(utm) {
int zone;
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
- if (!P->es) E_ERROR(-34);
- P->y0 = pj_param(P->ctx, P->params, "bsouth").i ? 10000000. : 0.;
+ if (!P->es)
+ E_ERROR(-34);
+ P->y0 = pj_param (P->ctx, P->params, "bsouth").i ? 10000000. : 0.;
P->x0 = 500000.;
- if (pj_param(P->ctx, P->params, "tzone").i) /* zone input ? */
+ if (pj_param (P->ctx, P->params, "tzone").i) /* zone input ? */
if ((zone = pj_param(P->ctx, P->params, "izone").i) > 0 && zone <= 60)
--zone;
else
E_ERROR(-35)
else /* nearest central meridian input */
- if ((zone = (int)(floor((adjlon(P->lam0) + PI) * 30. / PI))) < 0)
+ if ((zone = (int)(floor ((adjlon (P->lam0) + PI) * 30. / PI))) < 0)
zone = 0;
else if (zone >= 60)
zone = 59;
P->lam0 = (zone + .5) * PI / 30. - PI;
P->k0 = 0.9996;
P->phi0 = 0.;
-ENDENTRY(setup(P))
+
+ return setup (P);
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_utm_selftest (void) {return 0;}
+#else
+
+int pj_utm_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=utm +ellps=GRS80 +lat_1=0.5 +lat_2=2 +n=0.5 +zone=30"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ {1057002.4054912981, 110955.14117594929},
+ {1057002.4054912981, -110955.14117594929},
+ {611263.81227890507, 110547.10569680421},
+ {611263.81227890507, -110547.10569680421},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ {-7.4869520833902357, 0.00090193980983462605},
+ {-7.4869520833902357, -0.00090193980983462605},
+ {-7.4905356820622613, 0.00090193535121489081},
+ {-7.4905356820622613, -0.00090193535121489081},
+ };
+
+ return pj_generic_selftest (e_args, 0, tolerance_xy, tolerance_lp, 4, 4, fwd_in, e_fwd_expect, 0, inv_in, e_inv_expect, 0);
+}
+#endif
+
+
+
diff --git a/src/proj_rouss.c b/src/proj_rouss.c
index f1c2f5a1..fc9918be 100644
--- a/src/proj_rouss.c
+++ b/src/proj_rouss.c
@@ -23,98 +23,176 @@
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#define PROJ_PARMS__ \
- double s0; \
- double A1, A2, A3, A4, A5, A6; \
- double B1, B2, B3, B4, B5, B6, B7, B8; \
- double C1, C2, C3, C4, C5, C6, C7, C8; \
- double D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11; \
- void *en;
#define PJ_LIB__
-# include <projects.h>
+#include <projects.h>
+
+struct pj_opaque {
+ double s0;
+ double A1, A2, A3, A4, A5, A6;
+ double B1, B2, B3, B4, B5, B6, B7, B8;
+ double C1, C2, C3, C4, C5, C6, C7, C8;
+ double D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11;
+ void *en;
+};
PROJ_HEAD(rouss, "Roussilhe Stereographic") "\n\tAzi., Ellps.";
-FORWARD(e_forward); /* ellipsoid */
- double s, al, cp, sp, al2, s2;
-
- cp = cos(lp.phi);
- sp = sin(lp.phi);
- s = proj_mdist(lp.phi, sp, cp, P->en) - P->s0;
- s2 = s * s;
- al = lp.lam * cp / sqrt(1. - P->es * sp * sp);
- al2 = al * al;
- xy.x = P->k0 * al*(1.+s2*(P->A1+s2*P->A4)-al2*(P->A2+s*P->A3+s2*P->A5
- +al2*P->A6));
- xy.y = P->k0 * (al2*(P->B1+al2*P->B4)+
- s*(1.+al2*(P->B3-al2*P->B6)+s2*(P->B2+s2*P->B8)+
- s*al2*(P->B5+s*P->B7)));
- 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 s, al, cp, sp, al2, s2;
+
+ cp = cos(lp.phi);
+ sp = sin(lp.phi);
+ s = proj_mdist(lp.phi, sp, cp, Q->en) - Q->s0;
+ s2 = s * s;
+ al = lp.lam * cp / sqrt(1. - P->es * sp * sp);
+ al2 = al * al;
+ xy.x = P->k0 * al*(1.+s2*(Q->A1+s2*Q->A4)-al2*(Q->A2+s*Q->A3+s2*Q->A5
+ +al2*Q->A6));
+ xy.y = P->k0 * (al2*(Q->B1+al2*Q->B4)+
+ s*(1.+al2*(Q->B3-al2*Q->B6)+s2*(Q->B2+s2*Q->B8)+
+ s*al2*(Q->B5+s*Q->B7)));
+
+ return xy;
}
-INVERSE(e_inverse); /* ellipsoid */
- double s, al, x = xy.x / P->k0, y = xy.y / P->k0, x2, y2;;
-
- x2 = x * x;
- y2 = y * y;
- al = x*(1.-P->C1*y2+x2*(P->C2+P->C3*y-P->C4*x2+P->C5*y2-P->C7*x2*y)
- +y2*(P->C6*y2-P->C8*x2*y));
- s = P->s0 + y*(1.+y2*(-P->D2+P->D8*y2))+
- x2*(-P->D1+y*(-P->D3+y*(-P->D5+y*(-P->D7+y*P->D11)))+
- x2*(P->D4+y*(P->D6+y*P->D10)-x2*P->D9));
- lp.phi=proj_inv_mdist(P->ctx, s, P->en);
- s = sin(lp.phi);
- lp.lam=al * sqrt(1. - P->es * s * s)/cos(lp.phi);
- return (lp);
+
+
+static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = P->opaque;
+ double s, al, x = xy.x / P->k0, y = xy.y / P->k0, x2, y2;;
+
+ x2 = x * x;
+ y2 = y * y;
+ al = x*(1.-Q->C1*y2+x2*(Q->C2+Q->C3*y-Q->C4*x2+Q->C5*y2-Q->C7*x2*y)
+ +y2*(Q->C6*y2-Q->C8*x2*y));
+ s = Q->s0 + y*(1.+y2*(-Q->D2+Q->D8*y2))+
+ x2*(-Q->D1+y*(-Q->D3+y*(-Q->D5+y*(-Q->D7+y*Q->D11)))+
+ x2*(Q->D4+y*(Q->D6+y*Q->D10)-x2*Q->D9));
+ lp.phi=proj_inv_mdist(P->ctx, s, Q->en);
+ s = sin(lp.phi);
+ lp.lam=al * sqrt(1. - P->es * s * s)/cos(lp.phi);
+
+ return lp;
}
-FREEUP;
- if (P) {
- if (P->en)
- free(P->en);
- free(P);
- }
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+ if (0==P->opaque)
+ return pj_dealloc (P);
+
+ if (P->opaque->en)
+ pj_dealloc (P->opaque->en);
+ pj_dealloc (P->opaque);
+ return pj_dealloc(P);
+}
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
}
-ENTRY1(rouss, en)
- double N0, es2, t, t2, R_R0_2, R_R0_4;
-
- if (!((P->en = proj_mdist_ini(P->es))))
- E_ERROR_0;
- es2 = sin(P->phi0);
- P->s0 = proj_mdist(P->phi0, es2, cos(P->phi0), P->en);
- t = 1. - (es2 = P->es * es2 * es2);
- N0 = 1./sqrt(t);
- R_R0_2 = t * t / P->one_es;
- R_R0_4 = R_R0_2 * R_R0_2;
- t = tan(P->phi0);
- t2 = t * t;
- P->C1 = P->A1 = R_R0_2 / 4.;
- P->C2 = P->A2 = R_R0_2 * (2 * t2 - 1. - 2. * es2) / 12.;
- P->A3 = R_R0_2 * t * (1. + 4. * t2)/ ( 12. * N0);
- P->A4 = R_R0_4 / 24.;
- P->A5 = R_R0_4 * ( -1. + t2 * (11. + 12. * t2))/24.;
- P->A6 = R_R0_4 * ( -2. + t2 * (11. - 2. * t2))/240.;
- P->B1 = t / (2. * N0);
- P->B2 = R_R0_2 / 12.;
- P->B3 = R_R0_2 * (1. + 2. * t2 - 2. * es2)/4.;
- P->B4 = R_R0_2 * t * (2. - t2)/(24. * N0);
- P->B5 = R_R0_2 * t * (5. + 4.* t2)/(8. * N0);
- P->B6 = R_R0_4 * (-2. + t2 * (-5. + 6. * t2))/48.;
- P->B7 = R_R0_4 * (5. + t2 * (19. + 12. * t2))/24.;
- P->B8 = R_R0_4 / 120.;
- P->C3 = R_R0_2 * t * (1. + t2)/(3. * N0);
- P->C4 = R_R0_4 * (-3. + t2 * (34. + 22. * t2))/240.;
- P->C5 = R_R0_4 * (4. + t2 * (13. + 12. * t2))/24.;
- P->C6 = R_R0_4 / 16.;
- P->C7 = R_R0_4 * t * (11. + t2 * (33. + t2 * 16.))/(48. * N0);
- P->C8 = R_R0_4 * t * (1. + t2 * 4.)/(36. * N0);
- P->D1 = t / (2. * N0);
- P->D2 = R_R0_2 / 12.;
- P->D3 = R_R0_2 * (2 * t2 + 1. - 2. * es2) / 4.;
- P->D4 = R_R0_2 * t * (1. + t2)/(8. * N0);
- P->D5 = R_R0_2 * t * (1. + t2 * 2.)/(4. * N0);
- P->D6 = R_R0_4 * (1. + t2 * (6. + t2 * 6.))/16.;
- P->D7 = R_R0_4 * t2 * (3. + t2 * 4.)/8.;
- P->D8 = R_R0_4 / 80.;
- P->D9 = R_R0_4 * t * (-21. + t2 * (178. - t2 * 26.))/720.;
- P->D10 = R_R0_4 * t * (29. + t2 * (86. + t2 * 48.))/(96. * N0);
- P->D11 = R_R0_4 * t * (37. + t2 * 44.)/(96. * N0);
- P->fwd = e_forward;
- P->inv = e_inverse;
- ENDENTRY(P)
+
+
+PJ *PROJECTION(rouss) {
+ double N0, es2, t, t2, R_R0_2, R_R0_4;
+
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ if (!((Q->en = proj_mdist_ini(P->es))))
+ E_ERROR_0;
+ es2 = sin(P->phi0);
+ Q->s0 = proj_mdist(P->phi0, es2, cos(P->phi0), Q->en);
+ t = 1. - (es2 = P->es * es2 * es2);
+ N0 = 1./sqrt(t);
+ R_R0_2 = t * t / P->one_es;
+ R_R0_4 = R_R0_2 * R_R0_2;
+ t = tan(P->phi0);
+ t2 = t * t;
+ Q->C1 = Q->A1 = R_R0_2 / 4.;
+ Q->C2 = Q->A2 = R_R0_2 * (2 * t2 - 1. - 2. * es2) / 12.;
+ Q->A3 = R_R0_2 * t * (1. + 4. * t2)/ ( 12. * N0);
+ Q->A4 = R_R0_4 / 24.;
+ Q->A5 = R_R0_4 * ( -1. + t2 * (11. + 12. * t2))/24.;
+ Q->A6 = R_R0_4 * ( -2. + t2 * (11. - 2. * t2))/240.;
+ Q->B1 = t / (2. * N0);
+ Q->B2 = R_R0_2 / 12.;
+ Q->B3 = R_R0_2 * (1. + 2. * t2 - 2. * es2)/4.;
+ Q->B4 = R_R0_2 * t * (2. - t2)/(24. * N0);
+ Q->B5 = R_R0_2 * t * (5. + 4.* t2)/(8. * N0);
+ Q->B6 = R_R0_4 * (-2. + t2 * (-5. + 6. * t2))/48.;
+ Q->B7 = R_R0_4 * (5. + t2 * (19. + 12. * t2))/24.;
+ Q->B8 = R_R0_4 / 120.;
+ Q->C3 = R_R0_2 * t * (1. + t2)/(3. * N0);
+ Q->C4 = R_R0_4 * (-3. + t2 * (34. + 22. * t2))/240.;
+ Q->C5 = R_R0_4 * (4. + t2 * (13. + 12. * t2))/24.;
+ Q->C6 = R_R0_4 / 16.;
+ Q->C7 = R_R0_4 * t * (11. + t2 * (33. + t2 * 16.))/(48. * N0);
+ Q->C8 = R_R0_4 * t * (1. + t2 * 4.)/(36. * N0);
+ Q->D1 = t / (2. * N0);
+ Q->D2 = R_R0_2 / 12.;
+ Q->D3 = R_R0_2 * (2 * t2 + 1. - 2. * es2) / 4.;
+ Q->D4 = R_R0_2 * t * (1. + t2)/(8. * N0);
+ Q->D5 = R_R0_2 * t * (1. + t2 * 2.)/(4. * N0);
+ Q->D6 = R_R0_4 * (1. + t2 * (6. + t2 * 6.))/16.;
+ Q->D7 = R_R0_4 * t2 * (3. + t2 * 4.)/8.;
+ Q->D8 = R_R0_4 / 80.;
+ Q->D9 = R_R0_4 * t * (-21. + t2 * (178. - t2 * 26.))/720.;
+ Q->D10 = R_R0_4 * t * (29. + t2 * (86. + t2 * 48.))/(96. * N0);
+ Q->D11 = R_R0_4 * t * (37. + t2 * 44.)/(96. * N0);
+
+ P->fwd = e_forward;
+ P->inv = e_inverse;
+
+ return P;
+}
+
+
+#ifdef PJ_OMIT_SELFTEST
+int pj_rouss_selftest (void) {return 0;}
+#else
+
+int pj_rouss_selftest (void) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ char e_args[] = {"+proj=rouss +ellps=GRS80 +lat_1=0.5 +lat_2=2"};
+
+ LP fwd_in[] = {
+ { 2, 1},
+ { 2,-1},
+ {-2, 1},
+ {-2,-1}
+ };
+
+ XY e_fwd_expect[] = {
+ { 222644.89413161727, 110611.09186837047},
+ { 222644.89413161727, -110611.09186837047},
+ {-222644.89413161727, 110611.09186837047},
+ {-222644.89413161727, -110611.09186837047},
+ };
+
+ XY inv_in[] = {
+ { 200, 100},
+ { 200,-100},
+ {-200, 100},
+ {-200,-100}
+ };
+
+ LP e_inv_expect[] = {
+ { 0.0017966305682019911, 0.00090436947683699559},
+ { 0.0017966305682019911, -0.00090436947683699559},
+ {-0.0017966305682019911, 0.00090436947683699559},
+ {-0.0017966305682019911, -0.00090436947683699559},
+ };
+
+ return pj_generic_selftest (e_args, 0, tolerance_xy, tolerance_lp, 4, 4, fwd_in, e_fwd_expect, 0, inv_in, e_inv_expect, 0);
+}
+
+
+#endif
diff --git a/src/projects.h b/src/projects.h
index 411a3403..2957f848 100644
--- a/src/projects.h
+++ b/src/projects.h
@@ -48,7 +48,7 @@
#define C_NAMESPACE extern "C"
#define C_NAMESPACE_VAR extern "C"
extern "C" {
-#else
+#else
#define C_NAMESPACE extern
#define C_NAMESPACE_VAR
#endif
@@ -132,8 +132,8 @@ typedef struct {
/* datum_type values */
#define PJD_UNKNOWN 0
-#define PJD_3PARAM 1
-#define PJD_7PARAM 2
+#define PJD_3PARAM 1
+#define PJD_7PARAM 2
#define PJD_GRIDSHIFT 3
#define PJD_WGS84 4 /* WGS84 (or anything considered equivelent) */
@@ -143,7 +143,7 @@ typedef struct {
#define PJD_ERR_GRID_AREA -48
#define PJD_ERR_CATALOG -49
-#define USE_PROJUV
+#define USE_PROJUV
typedef struct { double u, v; } projUV;
typedef struct { double r, i; } COMPLEX;
@@ -163,12 +163,19 @@ typedef struct { double lam, phi, z; } LPZ;
typedef union { double f; int i; char *s; } PROJVALUE;
struct PJconsts;
-
+
struct PJ_LIST {
char *id; /* projection keyword */
struct PJconsts *(*proj)(struct PJconsts*);/* projection entry point */
char * const *descr; /* description text */
};
+
+/* Merging this into the PJ_LIST infrastructure is tempting, but may imply ABI breakage. Perhaps at next major version? */
+struct PJ_SELFTEST_LIST {
+ char *id; /* projection keyword */
+ int (* testfunc)(void); /* projection entry point */
+};
+
struct PJ_ELLPS {
char *id; /* ellipse keyword name */
char *major; /* a= value */
@@ -197,14 +204,14 @@ typedef struct {
double ll_long; /* lower left corner coordinates (radians) */
double ll_lat;
double ur_long; /* upper right corner coordinates (radians) */
- double ur_lat;
+ double ur_lat;
} PJ_Region;
struct DERIVS {
double x_l, x_p; /* derivatives of x for lambda-phi */
double y_l, y_p; /* derivatives of y for lambda-phi */
};
-
+
struct FACTORS {
struct DERIVS der;
double h, k; /* meridinal, parallel scales */
@@ -226,12 +233,18 @@ typedef struct ARG_list {
/* base projection data structure */
+#ifdef PJ_LIB__
+ /* we need this forward declaration in order to be able to add a
+ pointer to struct opaque to the typedef struct PJconsts below */
+ struct pj_opaque;
+#endif
+
typedef struct PJconsts {
projCtx_t *ctx;
XY (*fwd)(LP, struct PJconsts *);
LP (*inv)(XY, struct PJconsts *);
XYZ (*fwd3d)(LPZ, struct PJconsts *);
- LPZ (*inv3d)(XYZ, struct PJconsts *);
+ LPZ (*inv3d)(XYZ, struct PJconsts *);
void (*spc)(LP, struct PJconsts *, struct FACTORS *);
void (*pfree)(struct PJconsts *);
const char *descr;
@@ -253,7 +266,7 @@ typedef struct PJconsts {
x0, y0, /* easting and northing */
k0, /* general scaling factor */
to_meter, fr_meter; /* cartesian scaling */
-
+
int datum_type; /* PJD_UNKNOWN/3PARAM/7PARAM/GRIDSHIFT/WGS84 */
double datum_params[7];
struct _pj_gi **gridlist;
@@ -272,9 +285,9 @@ typedef struct PJconsts {
/* New Datum Shift Grid Catalogs */
char *catalog_name;
struct _PJ_GridCatalog *catalog;
-
+
double datum_date;
-
+
struct _pj_gi *last_before_grid;
PJ_Region last_before_region;
double last_before_date;
@@ -283,6 +296,10 @@ typedef struct PJconsts {
PJ_Region last_after_region;
double last_after_date;
+#ifdef PJ_LIB__
+ struct pj_opaque *opaque;
+#endif
+
#ifdef PROJ_PARMS__
PROJ_PARMS__
#endif /* end of optional extensions */
@@ -291,24 +308,16 @@ PROJ_PARMS__
/* public API */
#include "proj_api.h"
+
/* Generate pj_list external or make list from include file */
+
#ifndef USE_PJ_LIST_H
extern struct PJ_LIST pj_list[];
-#else
-#define PROJ_HEAD(id, name) \
- struct PJconsts *pj_##id(struct PJconsts*); extern char * const pj_s_##id;
-
-#include "pj_list.h"
-#undef PROJ_HEAD
-#define PROJ_HEAD(id, name) {#id, pj_##id, &pj_s_##id},
- struct PJ_LIST
-pj_list[] = {
-#include "pj_list.h"
- {0, 0, 0},
- };
-#undef PROJ_HEAD
+extern struct PJ_SELFTEST_LIST pj_selftest_list[];
#endif
+
+
#ifndef PJ_ELLPS__
extern struct PJ_ELLPS pj_ellps[];
#endif
@@ -350,7 +359,45 @@ extern struct PJ_PRIME_MERIDIANS pj_prime_meridians[];
#define INVERSE3D(name) static LPZ name(XYZ xyz, PJ *P) {LPZ lpz = {0.0, 0.0, 0.0}
#define FREEUP static void freeup(PJ *P) {
#define SPECIAL(name) static void name(LP lp, PJ *P, struct FACTORS *fac)
+#define ELLIPSOIDAL(P) ((P->es==0)? (FALSE): (TRUE))
+
+/* cleaned up alternative to most of the "repetitive projection code" macros */
+#define PROJECTION(name) \
+pj_projection_specific_setup_##name (PJ *P); \
+C_NAMESPACE_VAR const char * const pj_s_##name = des_##name; \
+C_NAMESPACE PJ *pj_##name (PJ *P) { \
+ if (P) \
+ return pj_projection_specific_setup_##name (P); \
+ P = (PJ*) pj_calloc (1, sizeof(PJ)); \
+ if (0==P) \
+ return 0; \
+ P->pfree = freeup; \
+ P->descr = des_##name; \
+ return P; \
+} \
+PJ *pj_projection_specific_setup_##name (PJ *P)
+
#endif
+
+
+int pj_generic_selftest (
+ char *e_args,
+ char *s_args,
+ double tolerance_xy,
+ double tolerance_lp,
+ int n_fwd,
+ int n_inv,
+ LP *fwd_in,
+ XY *e_fwd_expect,
+ XY *s_fwd_expect,
+ XY *inv_in,
+ LP *e_inv_expect,
+ LP *s_inv_expect
+);
+
+
+
+
#define MAX_TAB_ID 80
typedef struct { float lam, phi; } FLP;
typedef struct { int lam, phi; } ILP;
@@ -366,8 +413,8 @@ struct CTABLE {
typedef struct _pj_gi {
char *gridname; /* identifying name of grid, eg "conus" or ntv2_0.gsb */
char *filename; /* full path to filename */
-
- const char *format; /* format of this grid, ie "ctable", "ntv1",
+
+ const char *format; /* format of this grid, ie "ctable", "ntv1",
"ntv2" or "missing". */
int grid_offset; /* offset in file, for delayed loading */
@@ -414,6 +461,7 @@ int pj_ell_set(projCtx ctx, paralist *, double *, double *);
int pj_datum_set(projCtx,paralist *, PJ *);
int pj_prime_meridian_set(paralist *, PJ *);
int pj_angular_units_set(paralist *, PJ *);
+void pj_prepare (PJ *P, const char *description, void (*freeup)(struct PJconsts *), size_t sizeof_struct_opaque);
paralist *pj_clone_paralist( const paralist* );
paralist*pj_search_initcache( const char *filekey );
@@ -439,7 +487,7 @@ struct PW_COEF {/* row coefficient structure */
int m; /* number of c coefficients (=0 for none) */
double *c; /* power coefficients */
};
-
+
/* Approximation structures and procedures */
typedef struct { /* Chebyshev or Power series structure */
projUV a, b; /* power series range for evaluation */
@@ -457,6 +505,7 @@ void **vector2(int, int, int);
void freev2(void **v, int nrows);
int bchgen(projUV, projUV, int, int, projUV **, projUV(*)(projUV));
int bch2bps(projUV, projUV, projUV **, int, int);
+
/* nadcon related protos */
LP nad_intr(LP, struct CTABLE *);
LP nad_cvt(LP, int, struct CTABLE *);
@@ -470,15 +519,15 @@ void nad_free(struct CTABLE *);
/* higher level handling of datum grid shift files */
int pj_apply_vgridshift( PJ *defn, const char *listname,
- PJ_GRIDINFO ***gridlist_p,
+ PJ_GRIDINFO ***gridlist_p,
int *gridlist_count_p,
- int inverse,
+ int inverse,
long point_count, int point_offset,
double *x, double *y, double *z );
-int pj_apply_gridshift_2( PJ *defn, int inverse,
+int pj_apply_gridshift_2( PJ *defn, int inverse,
long point_count, int point_offset,
double *x, double *y, double *z );
-int pj_apply_gridshift_3( projCtx ctx,
+int pj_apply_gridshift_3( projCtx ctx,
PJ_GRIDINFO **gridlist, int gridlist_count,
int inverse, long point_count, int point_offset,
double *x, double *y, double *z );
@@ -493,15 +542,15 @@ void pj_gridinfo_free( projCtx, PJ_GRIDINFO * );
PJ_GridCatalog *pj_gc_findcatalog( projCtx, const char * );
PJ_GridCatalog *pj_gc_readcatalog( projCtx, const char * );
void pj_gc_unloadall( projCtx );
-int pj_gc_apply_gridshift( PJ *defn, int inverse,
+int pj_gc_apply_gridshift( PJ *defn, int inverse,
long point_count, int point_offset,
double *x, double *y, double *z );
-int pj_gc_apply_gridshift( PJ *defn, int inverse,
+int pj_gc_apply_gridshift( PJ *defn, int inverse,
long point_count, int point_offset,
double *x, double *y, double *z );
-PJ_GRIDINFO *pj_gc_findgrid( projCtx ctx,
- PJ_GridCatalog *catalog, int after,
+PJ_GRIDINFO *pj_gc_findgrid( projCtx ctx,
+ PJ_GridCatalog *catalog, int after,
LP location, double date,
PJ_Region *optional_region,
double *grid_date );
@@ -521,6 +570,7 @@ struct PJ_ELLPS *pj_get_ellps_ref( void );
struct PJ_DATUMS *pj_get_datums_ref( void );
struct PJ_UNITS *pj_get_units_ref( void );
struct PJ_LIST *pj_get_list_ref( void );
+struct PJ_SELFTEST_LIST *pj_get_selftest_list_ref ( void );
struct PJ_PRIME_MERIDIANS *pj_get_prime_meridians_ref( void );
double pj_atof( const char* nptr );
diff --git a/src/test228.c b/src/test228.c
index cdfc8650..a8e55c4c 100644
--- a/src/test228.c
+++ b/src/test228.c
@@ -1,4 +1,6 @@
#include <proj_api.h>
+#include <stdio.h> /* for printf declaration */
+
#ifdef _WIN32
@@ -33,7 +35,7 @@ void* thread_main(void* unused)
p_OSGB36_proj=pj_init_plus_ctx(p_proj_ctxt,
"+proj=longlat +ellps=airy +datum=OSGB36 +nadgrids=OSTN02_NTv2.gsb "
"+no_defs");
-
+
while(run)
{
double x, y;
@@ -73,4 +75,4 @@ int main(int argc, char* argv[])
return 0;
}
-#endif /* _WIN32 */ \ No newline at end of file
+#endif /* _WIN32 */