/src/PROJ/src/projections/gn_sinu.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | |
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 | 0 | #define EPS10 1e-10 |
15 | 840 | #define MAX_ITER 8 |
16 | 3.12k | #define LOOP_TOL 1e-7 |
17 | | |
18 | | namespace { // anonymous namespace |
19 | | struct pj_gn_sinu_data { |
20 | | double *en; |
21 | | double m, n, C_x, C_y; |
22 | | }; |
23 | | } // anonymous namespace |
24 | | |
25 | 0 | static PJ_XY gn_sinu_e_forward(PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ |
26 | 0 | PJ_XY xy = {0.0, 0.0}; |
27 | |
|
28 | 0 | const double s = sin(lp.phi); |
29 | 0 | const double c = cos(lp.phi); |
30 | 0 | xy.y = pj_mlfn(lp.phi, s, c, |
31 | 0 | static_cast<struct pj_gn_sinu_data *>(P->opaque)->en); |
32 | 0 | xy.x = lp.lam * c / sqrt(1. - P->es * s * s); |
33 | 0 | return xy; |
34 | 0 | } |
35 | | |
36 | 0 | static PJ_LP gn_sinu_e_inverse(PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ |
37 | 0 | PJ_LP lp = {0.0, 0.0}; |
38 | 0 | double s; |
39 | |
|
40 | 0 | lp.phi = |
41 | 0 | pj_inv_mlfn(xy.y, static_cast<struct pj_gn_sinu_data *>(P->opaque)->en); |
42 | 0 | s = fabs(lp.phi); |
43 | 0 | if (s < M_HALFPI) { |
44 | 0 | s = sin(lp.phi); |
45 | 0 | lp.lam = xy.x * sqrt(1. - P->es * s * s) / cos(lp.phi); |
46 | 0 | } else if ((s - EPS10) < M_HALFPI) { |
47 | 0 | lp.lam = 0.; |
48 | 0 | } else { |
49 | 0 | proj_errno_set(P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN); |
50 | 0 | } |
51 | |
|
52 | 0 | return lp; |
53 | 0 | } |
54 | | |
55 | 2.53k | static PJ_XY gn_sinu_s_forward(PJ_LP lp, PJ *P) { /* Spheroidal, forward */ |
56 | 2.53k | PJ_XY xy = {0.0, 0.0}; |
57 | 2.53k | struct pj_gn_sinu_data *Q = |
58 | 2.53k | static_cast<struct pj_gn_sinu_data *>(P->opaque); |
59 | | |
60 | 2.53k | if (Q->m == 0.0) |
61 | 1.69k | lp.phi = Q->n != 1. ? aasin(P->ctx, Q->n * sin(lp.phi)) : lp.phi; |
62 | 840 | else { |
63 | 840 | int i; |
64 | | |
65 | 840 | const double k = Q->n * sin(lp.phi); |
66 | 3.12k | for (i = MAX_ITER; i; --i) { |
67 | 3.12k | const double V = |
68 | 3.12k | (Q->m * lp.phi + sin(lp.phi) - k) / (Q->m + cos(lp.phi)); |
69 | 3.12k | lp.phi -= V; |
70 | 3.12k | if (fabs(V) < LOOP_TOL) |
71 | 840 | break; |
72 | 3.12k | } |
73 | 840 | if (!i) { |
74 | 0 | proj_errno_set(P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN); |
75 | 0 | return xy; |
76 | 0 | } |
77 | 840 | } |
78 | 2.53k | xy.x = Q->C_x * lp.lam * (Q->m + cos(lp.phi)); |
79 | 2.53k | xy.y = Q->C_y * lp.phi; |
80 | | |
81 | 2.53k | return xy; |
82 | 2.53k | } |
83 | | |
84 | 0 | static PJ_LP gn_sinu_s_inverse(PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ |
85 | 0 | PJ_LP lp = {0.0, 0.0}; |
86 | 0 | struct pj_gn_sinu_data *Q = |
87 | 0 | static_cast<struct pj_gn_sinu_data *>(P->opaque); |
88 | |
|
89 | 0 | xy.y /= Q->C_y; |
90 | 0 | lp.phi = (Q->m != 0.0) |
91 | 0 | ? aasin(P->ctx, (Q->m * xy.y + sin(xy.y)) / Q->n) |
92 | 0 | : (Q->n != 1. ? aasin(P->ctx, sin(xy.y) / Q->n) : xy.y); |
93 | 0 | lp.lam = xy.x / (Q->C_x * (Q->m + cos(xy.y))); |
94 | 0 | return lp; |
95 | 0 | } |
96 | | |
97 | 631 | static PJ *pj_gn_sinu_destructor(PJ *P, int errlev) { /* Destructor */ |
98 | 631 | if (nullptr == P) |
99 | 0 | return nullptr; |
100 | | |
101 | 631 | if (nullptr == P->opaque) |
102 | 0 | return pj_default_destructor(P, errlev); |
103 | | |
104 | 631 | free(static_cast<struct pj_gn_sinu_data *>(P->opaque)->en); |
105 | 631 | return pj_default_destructor(P, errlev); |
106 | 631 | } |
107 | | |
108 | | /* for spheres, only */ |
109 | 625 | static void pj_gn_sinu_setup(PJ *P) { |
110 | 625 | struct pj_gn_sinu_data *Q = |
111 | 625 | static_cast<struct pj_gn_sinu_data *>(P->opaque); |
112 | 625 | P->es = 0; |
113 | 625 | P->inv = gn_sinu_s_inverse; |
114 | 625 | P->fwd = gn_sinu_s_forward; |
115 | | |
116 | 625 | Q->C_y = sqrt((Q->m + 1.) / Q->n); |
117 | 625 | Q->C_x = Q->C_y / (Q->m + 1.); |
118 | 625 | } |
119 | | |
120 | 608 | PJ *PJ_PROJECTION(sinu) { |
121 | 608 | struct pj_gn_sinu_data *Q = static_cast<struct pj_gn_sinu_data *>( |
122 | 608 | calloc(1, sizeof(struct pj_gn_sinu_data))); |
123 | 608 | if (nullptr == Q) |
124 | 0 | return pj_default_destructor(P, PROJ_ERR_OTHER /*ENOMEM*/); |
125 | 608 | P->opaque = Q; |
126 | 608 | P->destructor = pj_gn_sinu_destructor; |
127 | | |
128 | 608 | if (!(Q->en = pj_enfn(P->n))) |
129 | 0 | return pj_default_destructor(P, PROJ_ERR_OTHER /*ENOMEM*/); |
130 | | |
131 | 608 | if (P->es != 0.0) { |
132 | 6 | P->inv = gn_sinu_e_inverse; |
133 | 6 | P->fwd = gn_sinu_e_forward; |
134 | 602 | } else { |
135 | 602 | Q->n = 1.; |
136 | 602 | Q->m = 0.; |
137 | 602 | pj_gn_sinu_setup(P); |
138 | 602 | } |
139 | 608 | return P; |
140 | 608 | } |
141 | | |
142 | 19 | PJ *PJ_PROJECTION(eck6) { |
143 | 19 | struct pj_gn_sinu_data *Q = static_cast<struct pj_gn_sinu_data *>( |
144 | 19 | calloc(1, sizeof(struct pj_gn_sinu_data))); |
145 | 19 | if (nullptr == Q) |
146 | 0 | return pj_default_destructor(P, PROJ_ERR_OTHER /*ENOMEM*/); |
147 | 19 | P->opaque = Q; |
148 | 19 | P->destructor = pj_gn_sinu_destructor; |
149 | | |
150 | 19 | Q->m = 1.; |
151 | 19 | Q->n = 2.570796326794896619231321691; |
152 | 19 | pj_gn_sinu_setup(P); |
153 | | |
154 | 19 | return P; |
155 | 19 | } |
156 | | |
157 | 2 | PJ *PJ_PROJECTION(mbtfps) { |
158 | 2 | struct pj_gn_sinu_data *Q = static_cast<struct pj_gn_sinu_data *>( |
159 | 2 | calloc(1, sizeof(struct pj_gn_sinu_data))); |
160 | 2 | if (nullptr == Q) |
161 | 0 | return pj_default_destructor(P, PROJ_ERR_OTHER /*ENOMEM*/); |
162 | 2 | P->opaque = Q; |
163 | 2 | P->destructor = pj_gn_sinu_destructor; |
164 | | |
165 | 2 | Q->m = 0.5; |
166 | 2 | Q->n = 1.785398163397448309615660845; |
167 | 2 | pj_gn_sinu_setup(P); |
168 | | |
169 | 2 | return P; |
170 | 2 | } |
171 | | |
172 | 6 | PJ *PJ_PROJECTION(gn_sinu) { |
173 | 6 | struct pj_gn_sinu_data *Q = static_cast<struct pj_gn_sinu_data *>( |
174 | 6 | calloc(1, sizeof(struct pj_gn_sinu_data))); |
175 | 6 | if (nullptr == Q) |
176 | 0 | return pj_default_destructor(P, PROJ_ERR_OTHER /*ENOMEM*/); |
177 | 6 | P->opaque = Q; |
178 | 6 | P->destructor = pj_gn_sinu_destructor; |
179 | | |
180 | 6 | if (!pj_param(P->ctx, P->params, "tn").i) { |
181 | 1 | proj_log_error(P, _("Missing parameter n.")); |
182 | 1 | return pj_default_destructor(P, PROJ_ERR_INVALID_OP_MISSING_ARG); |
183 | 1 | } |
184 | 5 | if (!pj_param(P->ctx, P->params, "tm").i) { |
185 | 3 | proj_log_error(P, _("Missing parameter m.")); |
186 | 3 | return pj_default_destructor(P, PROJ_ERR_INVALID_OP_MISSING_ARG); |
187 | 3 | } |
188 | | |
189 | 2 | Q->n = pj_param(P->ctx, P->params, "dn").f; |
190 | 2 | Q->m = pj_param(P->ctx, P->params, "dm").f; |
191 | 2 | if (Q->n <= 0) { |
192 | 0 | proj_log_error(P, _("Invalid value for n: it should be > 0.")); |
193 | 0 | return pj_default_destructor(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
194 | 0 | } |
195 | 2 | if (Q->m < 0) { |
196 | 0 | proj_log_error(P, _("Invalid value for m: it should be >= 0.")); |
197 | 0 | return pj_default_destructor(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
198 | 0 | } |
199 | | |
200 | 2 | pj_gn_sinu_setup(P); |
201 | | |
202 | 2 | return P; |
203 | 2 | } |