aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbusstoptaktik <knudsen.thomas@gmail.com>2016-05-11 08:09:46 +0200
committerbusstoptaktik <knudsen.thomas@gmail.com>2016-05-11 08:09:46 +0200
commite8ed8e58e8f557fc6f9443a00af1e73a5956c759 (patch)
tree2872dd2196c763ab8953d6d66937781a15842d88 /src
parent9687e69b177933c2894adc842f6aa507fc70ca16 (diff)
parent6cbf7e5f6c51b3b88e0d604124d688f79512496b (diff)
downloadPROJ-e8ed8e58e8f557fc6f9443a00af1e73a5956c759.tar.gz
PROJ-e8ed8e58e8f557fc6f9443a00af1e73a5956c759.zip
Merge pull request #6 from kbevers/fix-projs-with-l
Converted files PJ_l*.c
Diffstat (limited to 'src')
-rw-r--r--src/PJ_aea.c70
-rw-r--r--src/PJ_aeqd.c544
-rw-r--r--src/PJ_eck5.c31
-rw-r--r--src/PJ_eqc.c123
-rw-r--r--src/PJ_eqdc.c265
-rw-r--r--src/PJ_fahey.c19
-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.c290
-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.c126
-rw-r--r--src/PJ_mill.c101
-rw-r--r--src/PJ_misrsom.c258
-rw-r--r--src/PJ_mod_ster.c713
-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.c152
-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.c337
-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_geocent.c94
-rw-r--r--src/pj_latlong.c120
-rw-r--r--src/proj_rouss.c258
52 files changed, 7914 insertions, 3513 deletions
diff --git a/src/PJ_aea.c b/src/PJ_aea.c
index 72091132..5f7c6c92 100644
--- a/src/PJ_aea.c
+++ b/src/PJ_aea.c
@@ -353,76 +353,6 @@ source files
***********************************************************************/
-int pj_aeqd_selftest (void) {return 10000;}
-int pj_alsk_selftest (void) {return 10000;}
-int pj_eqc_selftest (void) {return 10000;}
-int pj_eqdc_selftest (void) {return 10000;}
int pj_etmerc_selftest (void) {return 10000;}
-int pj_geocent_selftest (void) {return 10000;}
-int pj_gs48_selftest (void) {return 10000;}
-int pj_gs50_selftest (void) {return 10000;}
-
-int pj_labrd_selftest (void) {return 10000;}
-int pj_laea_selftest (void) {return 10000;}
-int pj_lagrng_selftest (void) {return 10000;}
-int pj_larr_selftest (void) {return 10000;}
-int pj_lask_selftest (void) {return 10000;}
-int pj_latlon_selftest (void) {return 10000;}
-int pj_latlong_selftest (void) {return 10000;}
-int pj_lonlat_selftest (void) {return 10000;}
-int pj_longlat_selftest (void) {return 10000;}
-int pj_lcc_selftest (void) {return 10000;}
-int pj_lcca_selftest (void) {return 10000;}
-
-int pj_lee_os_selftest (void) {return 10000;}
-int pj_loxim_selftest (void) {return 10000;}
-int pj_lsat_selftest (void) {return 10000;}
-
-int pj_mbt_fps_selftest (void) {return 10000;}
-int pj_mbtfpp_selftest (void) {return 10000;}
-int pj_mbtfpq_selftest (void) {return 10000;}
-int pj_merc_selftest (void) {return 10000;}
-int pj_mil_os_selftest (void) {return 10000;}
-int pj_mill_selftest (void) {return 10000;}
-int pj_misrsom_selftest (void) {return 10000;}
-int pj_moll_selftest (void) {return 10000;}
-int pj_natearth_selftest (void) {return 10000;}
-int pj_natearth2_selftest (void) {return 10000;}
-int pj_nell_selftest (void) {return 10000;}
-int pj_nell_h_selftest (void) {return 10000;}
-int pj_nicol_selftest (void) {return 10000;}
-int pj_nsper_selftest (void) {return 10000;}
-int pj_nzmg_selftest (void) {return 10000;}
-int pj_ob_tran_selftest (void) {return 10000;}
-int pj_ocea_selftest (void) {return 10000;}
-int pj_oea_selftest (void) {return 10000;}
-int pj_omerc_selftest (void) {return 10000;}
-int pj_ortho_selftest (void) {return 10000;}
-int pj_patterson_selftest (void) {return 10000;}
-int pj_poly_selftest (void) {return 10000;}
-int pj_putp2_selftest (void) {return 10000;}
-int pj_putp3_selftest (void) {return 10000;}
-int pj_putp3p_selftest (void) {return 10000;}
-int pj_putp4p_selftest (void) {return 10000;}
-int pj_putp5_selftest (void) {return 10000;}
-int pj_putp5p_selftest (void) {return 10000;}
-int pj_putp6_selftest (void) {return 10000;}
-int pj_putp6p_selftest (void) {return 10000;}
-
-int pj_qsc_selftest (void) {return 10000;}
-int pj_robin_selftest (void) {return 10000;}
-int pj_rouss_selftest (void) {return 10000;}
-int pj_rpoly_selftest (void) {return 10000;}
-int pj_sch_selftest (void) {return 10000;}
-
-int pj_tpers_selftest (void) {return 10000;}
-
int pj_utm_selftest (void) {return 10000;}
-int pj_vandg_selftest (void) {return 10000;}
-int pj_vandg2_selftest (void) {return 10000;}
-int pj_vandg3_selftest (void) {return 10000;}
-int pj_vandg4_selftest (void) {return 10000;}
-int pj_wag4_selftest (void) {return 10000;}
-int pj_wag5_selftest (void) {return 10000;}
-int pj_weren_selftest (void) {return 10000;}
#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_eck5.c b/src/PJ_eck5.c
index ccfcb88f..d7626939 100644
--- a/src/PJ_eck5.c
+++ b/src/PJ_eck5.c
@@ -56,7 +56,6 @@ int pj_eck5_selftest (void) {
double tolerance_lp = 1e-10;
double tolerance_xy = 1e-7;
- char e_args[] = {"+proj=eck5 +ellps=GRS80 +lat_1=0.5 +lat_2=2"};
char s_args[] = {"+proj=eck5 +a=6400000 +lat_1=0.5 +lat_2=2"};
LP fwd_in[] = {
@@ -66,18 +65,11 @@ int pj_eck5_selftest (void) {
{-2,-1}
};
- XY e_fwd_expect[] = {
- { 196358.31442683787, 98186.634363414545 },
- { 196358.31442683787, -98186.634363414545 },
- {-196358.31442683787, 98186.634363414545 },
- {-196358.31442683787, -98186.634363414545 },
- };
-
XY s_fwd_expect[] = {
- { 197031.39213406085, 98523.198847226551 },
- { 197031.39213406085, -98523.198847226551 },
- {-197031.39213406085, 98523.198847226551 },
- {-197031.39213406085, -98523.198847226551 },
+ { 197031.39213406085, 98523.198847226551},
+ { 197031.39213406085, -98523.198847226551},
+ {-197031.39213406085, 98523.198847226551},
+ {-197031.39213406085, -98523.198847226551},
};
XY inv_in[] = {
@@ -87,18 +79,11 @@ int pj_eck5_selftest (void) {
{-200,-100}
};
- LP e_inv_expect[] = {
- {0.0020369371178927064, 0.0010184685588659013 },
- {0.0020369371178927064, -0.0010184685588659013 },
- {-0.0020369371178927064, 0.0010184685588659013 },
- {-0.0020369371178927064, -0.0010184685588659013 },
- };
-
LP s_inv_expect[] = {
- {0.002029978749734037, 0.001014989374787388 },
- {0.002029978749734037, -0.001014989374787388 },
- {-0.002029978749734037, 0.001014989374787388 },
- {-0.002029978749734037, -0.001014989374787388 },
+ {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);
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..a7308335 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) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ double cosphi, sinphi;
+ int secant;
+
+ 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 864225f4..b8841c96 100644
--- a/src/PJ_fahey.c
+++ b/src/PJ_fahey.c
@@ -1,5 +1,5 @@
#define PJ_LIB__
-# include <projects.h>
+#include <projects.h>
PROJ_HEAD(fahey, "Fahey") "\n\tPcyl, Sph.";
@@ -58,7 +58,6 @@ int pj_fahey_selftest (void) {
double tolerance_lp = 1e-10;
double tolerance_xy = 1e-7;
- char e_args[] = {"+proj=fahey +ellps=GRS80 +lat_1=0.5 +lat_2=2"};
char s_args[] = {"+proj=fahey +a=6400000 +lat_1=0.5 +lat_2=2"};
LP fwd_in[] = {
@@ -69,10 +68,10 @@ int pj_fahey_selftest (void) {
};
XY s_fwd_expect[] = {
- { 182993.34464912376, 101603.19356988439 },
- { 182993.34464912376, -101603.19356988439 },
- {-182993.34464912376, 101603.19356988439 },
- {-182993.34464912376, -101603.19356988439 },
+ { 182993.34464912376, 101603.19356988439},
+ { 182993.34464912376, -101603.19356988439},
+ {-182993.34464912376, 101603.19356988439},
+ {-182993.34464912376, -101603.19356988439},
};
XY inv_in[] = {
@@ -83,10 +82,10 @@ int pj_fahey_selftest (void) {
};
LP s_inv_expect[] = {
- {0.0021857886080359551, 0.00098424601668238403 },
- {0.0021857886080359551, -0.00098424601668238403 },
- {-0.0021857886080359551, 0.00098424601668238403 },
- {-0.0021857886080359551, -0.00098424601668238403 },
+ {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);
diff --git a/src/PJ_labrd.c b/src/PJ_labrd.c
index 4cb39ec8..e7bca390 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) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+ double Az, sinp, R, N, t;
+
+ 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..02b281a4 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) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+ double t;
+
+ 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..9a018808 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) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+ double phi1;
+
+ 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 +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..28275089 100644
--- a/src/PJ_lcc.c
+++ b/src/PJ_lcc.c
@@ -1,105 +1,195 @@
-#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;
}
-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);
+
+
+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;
}
-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;
+
+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);
}
-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)
+
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
+}
+
+
+PJ *PROJECTION(lcc) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ double cosphi, sinphi;
+ int secant;
+
+ 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;
+}
+
+
+#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);
+}
+
+
+#endif
diff --git a/src/PJ_lcca.c b/src/PJ_lcca.c
index 320d52db..eef46110 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) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+ double s2p0, N0, R0, tan0;
+
+ (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..2dcdb000 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) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
int land, path;
double lam, alf, esc, ess;
- 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)
+ 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);
+}
+
+
+#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 89913e50..dd894bbd 100644
--- a/src/PJ_merc.c
+++ b/src/PJ_merc.c
@@ -1,44 +1,44 @@
#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
-
static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
XY xy = {0.0,0.0};
- if (fabs(fabs(lp.phi) - HALFPI) <= EPS10)
+ 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;
+ xy.x = P->k0 * lp.lam;
+ xy.y = - P->k0 * log(pj_tsfn(lp.phi, sin(lp.phi), P->e));
+ 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)
+ 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;
+ xy.x = P->k0 * lp.lam;
+ xy.y = P->k0 * log(tan(FORTPI + .5 * lp.phi));
+ return xy;
}
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)
+ 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;
+ 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;
+ lp.phi = HALFPI - 2. * atan(exp(-xy.y / P->k0));
+ lp.lam = xy.x / P->k0;
+ return lp;
}
@@ -48,27 +48,87 @@ static void freeup(PJ *P) { /* Destructor */
PJ *PROJECTION(merc) {
- double phits=0.0;
- int is_phits;
+ 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( (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;
- }
+ 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;
- }
+ 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_misrsom.c b/src/PJ_misrsom.c
index 19518a1d..fdafbd7c 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,22 +142,44 @@ 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) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
int path;
double lam, alf, esc, ess;
@@ -153,33 +187,97 @@ ENTRY0(misrsom)
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..551b83bd 100644
--- a/src/PJ_mod_ster.c
+++ b/src/PJ_mod_ster.c
@@ -1,211 +1,538 @@
/* 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;
+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) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ static COMPLEX AB[] = {
+ {0.924500, 0.},
+ {0., 0.},
+ {0.019430, 0.}
+ };
+
+ 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) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ static COMPLEX AB[] = {
+ {0.721316, 0.},
+ {0., 0.},
+ {-0.0088162, -0.00617325}
+ };
+
+ 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) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ static COMPLEX /* 48 United States */
+ AB[] = {
+ {0.98879, 0.},
+ {0., 0.},
+ {-0.050909, 0.},
+ {0., 0.},
+ {0.075528, 0.}
+ };
+
+ 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) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ 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}
+ };
+
+ 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) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ 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}
+ };
+
+ 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) {
+ double tolerance_lp = 1e-10;
+ double tolerance_xy = 1e-7;
+
+ 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..2a0ea702 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) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ 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;
+ 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..76222fe9 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) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ 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 || !(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 +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..72414e7f 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) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ double phi_0=0.0, phi_1, phi_2, lam_1, lam_2, lonz, alpha;
+
+ 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..50ab6b52 100644
--- a/src/PJ_oea.c
+++ b/src/PJ_oea.c
@@ -1,58 +1,142 @@
-#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;
+
+ P->pfree = freeup;
+ P->descr = des_oea;
+ 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..3b25fb26 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), Q->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), Q->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) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ 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;
+
+ 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, Q->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), Q->E), Q->B);
+ L = pow(pj_tsfn(phi2, sin(phi2), Q->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..29b7b34c 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,231 @@
* 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;
+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( &(P->sph), pxyz[0], pxyz[1], pxyz[2],
- temp, temp+1, temp+2) != 0)
- I3_ERROR;
+ 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] = 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 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] += P->xyzoff[0];
- pxyz[1] += P->xyzoff[1];
- pxyz[2] += P->xyzoff[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( &(P->elp_0), pxyz[0], pxyz[1], pxyz[2],
- temp, temp+1, temp+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];
+ 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);
+ // 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;
}
-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( &(Q->elp_0), lpz.phi, lpz.lam, lpz.z,
+ temp, temp+1, temp+2 ) != 0 )
+ F3_ERROR;
+
+ //Adjust for offset
+ temp[0] -= Q->xyzoff[0];
+ temp[1] -= Q->xyzoff[1];
+ temp[2] -= Q->xyzoff[2];
- //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;
+ //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];
- //Adjust for offset
- temp[0] -= P->xyzoff[0];
- temp[1] -= P->xyzoff[1];
- temp[2] -= P->xyzoff[2];
+ //Convert to local lat,lon
+ pj_Convert_Geocentric_To_Geodetic( &(Q->sph), pxyz[0], pxyz[1], pxyz[2],
+ temp, temp+1, temp+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);
+ //Scale by radius
+ xyz.x = temp[1] * Q->rcurv / P->a;
+ xyz.y = temp[0] * Q->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] * P->rcurv / P->a;
- xyz.y = temp[0] * P->rcurv / P->a;
- xyz.z = temp[2];
+ return xyz;
+}
+
+
+static void *freeup_new (PJ *P) { /* Destructor */
+ if (0==P)
+ return 0;
+ if (0==P->opaque)
+ return pj_dealloc (P);
-// 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);
+ pj_dealloc (P->opaque);
+ return pj_dealloc(P);
+}
- return (xyz);
+static void freeup (PJ *P) {
+ freeup_new (P);
+ return;
}
-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];
+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];
- temp = P->a * sqrt(1.0 - P->es);
+ temp = P->a * sqrt(1.0 - P->es);
- //Setup original geocentric system
- if ( pj_Set_Geocentric_Parameters(&(P->elp_0), P->a, temp) != 0)
- E_ERROR(-37);
+ //Setup original geocentric system
+ if ( pj_Set_Geocentric_Parameters(&(Q->elp_0), P->a, temp) != 0)
+ E_ERROR(-37);
+ clt = cos(Q->plat);
+ slt = sin(Q->plat);
+ clo = cos(Q->plon);
+ slo = sin(Q->plon);
- clt = cos(P->plat);
- slt = sin(P->plat);
- clo = cos(P->plon);
- slo = sin(P->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);
- //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);
- chdg = cos(P->phdg);
- shdg = sin(P->phdg);
-
- P->rcurv = P->h0 + (reast*rnorth)/(reast * chdg * chdg + rnorth * shdg * shdg);
+ Q->rcurv = Q->h0 + (reast*rnorth)/(reast * chdg * chdg + rnorth * shdg * shdg);
-// printf("North Radius: %f \n", rnorth);
-// printf("East Radius: %f \n", reast);
-// printf("Effective Radius: %f \n", P->rcurv);
+ // printf("North Radius: %f \n", rnorth);
+ // printf("East Radius: %f \n", reast);
+ // printf("Effective Radius: %f \n", Q->rcurv);
- //Set up local sphere at the given peg point
- if ( pj_Set_Geocentric_Parameters(&(P->sph), P->rcurv, P->rcurv) != 0)
- E_ERROR(-37);
+ //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
- 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;
+ //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( &(P->elp_0), P->plat, P->plon, P->h0,
- pxyz, pxyz+1, pxyz+2 ) != 0 )
- {
- E_ERROR(-14)
- }
+ if( pj_Convert_Geodetic_To_Geocentric( &(Q->elp_0), Q->plat, Q->plon, Q->h0,
+ pxyz, pxyz+1, pxyz+2 ) != 0 )
+ {
+ E_ERROR(-14)
+ }
- 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;
-// printf("Offset: %f %f %f \n", P->xyzoff[0], P->xyzoff[1], P->xyzoff[2]);
+ 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;
+ // printf("Offset: %f %f %f \n", Q->xyzoff[0], Q->xyzoff[1], Q->xyzoff[2]);
- P->fwd3d = forward3d;
- P->inv3d = inverse3d;
- return P;
+
+ P->fwd3d = forward3d;
+ P->inv3d = inverse3d;
+ return P;
}
-ENTRY0(sch)
- P->h0 = 0.0;
- //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);
-
+PJ *PROJECTION(sch) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ Q->h0 = 0.0;
+
+ //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 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;
+ //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);
- //Completed reading in the projection parameters
-// printf("PSA: Lat = %f Lon = %f Hdg = %f \n", P->plat, P->plon, P->phdg);
+ //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 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;
+
+ //Completed reading in the projection parameters
+ //printf("PSA: Lat = %f Lon = %f Hdg = %f \n", Q->plat, Q->plon, Q->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_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_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_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/proj_rouss.c b/src/proj_rouss.c
index f1c2f5a1..35cc73c7 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) {
+ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
+ if (0==Q)
+ return freeup_new (P);
+ P->opaque = Q;
+
+ double N0, es2, t, t2, R_R0_2, R_R0_4;
+
+ 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