1 #define PJ_LIB__
2
3 #include <errno.h>
4 #include <math.h>
5
6 #include "proj.h"
7 #include "proj_internal.h"
8
9 PROJ_HEAD(gn_sinu, "General Sinusoidal Series") "\n\tPCyl, Sph\n\tm= n=";
10 PROJ_HEAD(sinu, "Sinusoidal (Sanson-Flamsteed)") "\n\tPCyl, Sph&Ell";
11 PROJ_HEAD(eck6, "Eckert VI") "\n\tPCyl, Sph";
12 PROJ_HEAD(mbtfps, "McBryde-Thomas Flat-Polar Sinusoidal") "\n\tPCyl, Sph";
13
14 #define EPS10 1e-10
15 #define MAX_ITER 8
16 #define LOOP_TOL 1e-7
17
18 namespace { // anonymous namespace
19 struct pj_opaque {
20 double *en;
21 double m, n, C_x, C_y;
22 };
23 } // anonymous namespace
24
25
gn_sinu_e_forward(PJ_LP lp,PJ * P)26 static PJ_XY gn_sinu_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */
27 PJ_XY xy = {0.0,0.0};
28
29 const double s = sin(lp.phi);
30 const double c = cos(lp.phi);
31 xy.y = pj_mlfn(lp.phi, s, c, static_cast<struct pj_opaque*>(P->opaque)->en);
32 xy.x = lp.lam * c / sqrt(1. - P->es * s * s);
33 return xy;
34 }
35
36
gn_sinu_e_inverse(PJ_XY xy,PJ * P)37 static PJ_LP gn_sinu_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */
38 PJ_LP lp = {0.0,0.0};
39 double s;
40
41 lp.phi = pj_inv_mlfn(P->ctx, xy.y, P->es, static_cast<struct pj_opaque*>(P->opaque)->en);
42 s = fabs(lp.phi);
43 if (s < M_HALFPI) {
44 s = sin(lp.phi);
45 lp.lam = xy.x * sqrt(1. - P->es * s * s) / cos(lp.phi);
46 } else if ((s - EPS10) < M_HALFPI) {
47 lp.lam = 0.;
48 } else {
49 proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION);
50 }
51
52 return lp;
53 }
54
55
gn_sinu_s_forward(PJ_LP lp,PJ * P)56 static PJ_XY gn_sinu_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */
57 PJ_XY xy = {0.0,0.0};
58 struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque);
59
60 if (Q->m == 0.0)
61 lp.phi = Q->n != 1. ? aasin(P->ctx,Q->n * sin(lp.phi)): lp.phi;
62 else {
63 int i;
64
65 const double k = Q->n * sin(lp.phi);
66 for (i = MAX_ITER; i ; --i) {
67 const double V = (Q->m * lp.phi + sin(lp.phi) - k) /
68 (Q->m + cos(lp.phi));
69 lp.phi -= V;
70 if (fabs(V) < LOOP_TOL)
71 break;
72 }
73 if (!i) {
74 proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION);
75 return xy;
76 }
77
78 }
79 xy.x = Q->C_x * lp.lam * (Q->m + cos(lp.phi));
80 xy.y = Q->C_y * lp.phi;
81
82 return xy;
83 }
84
85
gn_sinu_s_inverse(PJ_XY xy,PJ * P)86 static PJ_LP gn_sinu_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */
87 PJ_LP lp = {0.0,0.0};
88 struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque);
89
90 xy.y /= Q->C_y;
91 lp.phi = (Q->m != 0.0) ? aasin(P->ctx,(Q->m * xy.y + sin(xy.y)) / Q->n) :
92 ( Q->n != 1. ? aasin(P->ctx,sin(xy.y) / Q->n) : xy.y );
93 lp.lam = xy.x / (Q->C_x * (Q->m + cos(xy.y)));
94 return lp;
95 }
96
97
destructor(PJ * P,int errlev)98 static PJ *destructor (PJ *P, int errlev) { /* Destructor */
99 if (nullptr==P)
100 return nullptr;
101
102 if (nullptr==P->opaque)
103 return pj_default_destructor (P, errlev);
104
105 pj_dealloc (static_cast<struct pj_opaque*>(P->opaque)->en);
106 return pj_default_destructor (P, errlev);
107 }
108
109
110
111 /* for spheres, only */
setup(PJ * P)112 static void setup(PJ *P) {
113 struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque);
114 P->es = 0;
115 P->inv = gn_sinu_s_inverse;
116 P->fwd = gn_sinu_s_forward;
117
118 Q->C_y = sqrt((Q->m + 1.) / Q->n);
119 Q->C_x = Q->C_y/(Q->m + 1.);
120 }
121
122
PROJECTION(sinu)123 PJ *PROJECTION(sinu) {
124 struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque)));
125 if (nullptr==Q)
126 return pj_default_destructor (P, ENOMEM);
127 P->opaque = Q;
128 P->destructor = destructor;
129
130 if (!(Q->en = pj_enfn(P->es)))
131 return pj_default_destructor (P, ENOMEM);
132
133 if (P->es != 0.0) {
134 P->inv = gn_sinu_e_inverse;
135 P->fwd = gn_sinu_e_forward;
136 } else {
137 Q->n = 1.;
138 Q->m = 0.;
139 setup(P);
140 }
141 return P;
142 }
143
144
PROJECTION(eck6)145 PJ *PROJECTION(eck6) {
146 struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque)));
147 if (nullptr==Q)
148 return pj_default_destructor (P, ENOMEM);
149 P->opaque = Q;
150 P->destructor = destructor;
151
152 Q->m = 1.;
153 Q->n = 2.570796326794896619231321691;
154 setup(P);
155
156 return P;
157 }
158
159
PROJECTION(mbtfps)160 PJ *PROJECTION(mbtfps) {
161 struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque)));
162 if (nullptr==Q)
163 return pj_default_destructor (P, ENOMEM);
164 P->opaque = Q;
165 P->destructor = destructor;
166
167 Q->m = 0.5;
168 Q->n = 1.785398163397448309615660845;
169 setup(P);
170
171 return P;
172 }
173
174
PROJECTION(gn_sinu)175 PJ *PROJECTION(gn_sinu) {
176 struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque)));
177 if (nullptr==Q)
178 return pj_default_destructor (P, ENOMEM);
179 P->opaque = Q;
180 P->destructor = destructor;
181
182 if (pj_param(P->ctx, P->params, "tn").i && pj_param(P->ctx, P->params, "tm").i) {
183 Q->n = pj_param(P->ctx, P->params, "dn").f;
184 Q->m = pj_param(P->ctx, P->params, "dm").f;
185 if (Q->n <= 0 || Q->m < 0)
186 return destructor (P, PJD_ERR_INVALID_M_OR_N);
187 } else
188 return destructor (P, PJD_ERR_INVALID_M_OR_N);
189
190 setup(P);
191
192 return P;
193 }
194