/src/proj/src/ell_set.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* set ellipsoid parameters a and es */ |
2 | | |
3 | | #include <math.h> |
4 | | #include <stddef.h> |
5 | | #include <string.h> |
6 | | |
7 | | #include "proj.h" |
8 | | #include "proj_internal.h" |
9 | | |
10 | | /* Prototypes of the pj_ellipsoid helper functions */ |
11 | | static int ellps_ellps(PJ *P); |
12 | | static int ellps_size(PJ *P); |
13 | | static int ellps_shape(PJ *P); |
14 | | static int ellps_spherification(PJ *P); |
15 | | |
16 | | static paralist *pj_get_param(paralist *list, const char *key); |
17 | | static char *pj_param_value(paralist *list); |
18 | | static const PJ_ELLPS *pj_find_ellps(const char *name); |
19 | | |
20 | | /***************************************************************************************/ |
21 | 136k | int pj_ellipsoid(PJ *P) { |
22 | | /**************************************************************************************** |
23 | | This is a replacement for the classic PROJ pj_ell_set function. The main |
24 | | difference is that pj_ellipsoid augments the PJ object with a copy of the |
25 | | exact tags used to define its related ellipsoid. |
26 | | |
27 | | This makes it possible to let a new PJ object inherit the geometrical |
28 | | properties of an existing one. |
29 | | |
30 | | A complete ellipsoid definition comprises a size (primary) and a shape |
31 | | (secondary) parameter. |
32 | | |
33 | | Size parameters supported are: |
34 | | R, defining the radius of a spherical planet |
35 | | a, defining the semimajor axis of an ellipsoidal planet |
36 | | |
37 | | Shape parameters supported are: |
38 | | rf, the reverse flattening of the ellipsoid |
39 | | f, the flattening of the ellipsoid |
40 | | es, the eccentricity squared |
41 | | e, the eccentricity |
42 | | b, the semiminor axis |
43 | | |
44 | | The ellps=xxx parameter provides both size and shape for a number of |
45 | | built in ellipsoid definitions. |
46 | | |
47 | | The ellipsoid definition may be augmented with a spherification flag, |
48 | | turning the ellipsoid into a sphere with features defined by the ellipsoid. |
49 | | |
50 | | Spherification parameters supported are: |
51 | | R_A, which gives a sphere with the same surface area as the |
52 | | ellipsoid R_V, which gives a sphere with the same volume as the |
53 | | ellipsoid |
54 | | |
55 | | R_a, which gives a sphere with R = (a + b)/2 (arithmetic mean) |
56 | | R_g, which gives a sphere with R = sqrt(a*b) (geometric mean) |
57 | | R_h, which gives a sphere with R = 2*a*b/(a+b) (harmonic mean) |
58 | | |
59 | | R_lat_a=phi, which gives a sphere with R being the arithmetic mean |
60 | | of of the corresponding ellipsoid at latitude phi. |
61 | | R_lat_g=phi, which gives |
62 | | a sphere with R being the geometric mean of of the corresponding |
63 | | ellipsoid at latitude phi. |
64 | | |
65 | | R_C, which gives a sphere with the radius of the conformal sphere |
66 | | at phi0. |
67 | | |
68 | | If R is given as size parameter, any shape and spherification parameters |
69 | | given are ignored. |
70 | | |
71 | | If size and shape are given as ellps=xxx, later shape and size |
72 | | parameters are are taken into account as modifiers for the built in |
73 | | ellipsoid definition. |
74 | | |
75 | | While this may seem strange, it is in accordance with historical PROJ |
76 | | behavior. It can e.g. be used to define coordinates on the ellipsoid |
77 | | scaled to unit semimajor axis by specifying "+ellps=xxx +a=1" |
78 | | |
79 | | ****************************************************************************************/ |
80 | 136k | int err = proj_errno_reset(P); |
81 | 136k | const char *empty = {""}; |
82 | | |
83 | 136k | free(P->def_size); |
84 | 136k | P->def_size = nullptr; |
85 | 136k | free(P->def_shape); |
86 | 136k | P->def_shape = nullptr; |
87 | 136k | free(P->def_spherification); |
88 | 136k | P->def_spherification = nullptr; |
89 | 136k | free(P->def_ellps); |
90 | 136k | P->def_ellps = nullptr; |
91 | | |
92 | | /* Specifying R overrules everything */ |
93 | 136k | if (pj_get_param(P->params, "R")) { |
94 | 3.12k | if (0 != ellps_size(P)) |
95 | 1.03k | return 1; |
96 | 2.08k | pj_calc_ellipsoid_params(P, P->a, 0); |
97 | 2.08k | if (proj_errno(P)) |
98 | 0 | return 1; |
99 | 2.08k | return proj_errno_restore(P, err); |
100 | 2.08k | } |
101 | | |
102 | | /* If an ellps argument is specified, start by using that */ |
103 | 133k | if (0 != ellps_ellps(P)) |
104 | 192 | return 1; |
105 | | |
106 | | /* We may overwrite the size */ |
107 | 133k | if (0 != ellps_size(P)) |
108 | 12.2k | return 2; |
109 | | |
110 | | /* We may also overwrite the shape */ |
111 | 121k | if (0 != ellps_shape(P)) |
112 | 342 | return 3; |
113 | | |
114 | | /* When we're done with it, we compute all related ellipsoid parameters */ |
115 | 120k | pj_calc_ellipsoid_params(P, P->a, P->es); |
116 | | |
117 | | /* And finally, we may turn it into a sphere */ |
118 | 120k | if (0 != ellps_spherification(P)) |
119 | 17 | return 4; |
120 | | |
121 | 120k | proj_log_trace(P, "pj_ellipsoid - final: a=%.3f f=1/%7.3f, errno=%d", P->a, |
122 | 120k | P->f != 0 ? 1 / P->f : 0, proj_errno(P)); |
123 | 120k | proj_log_trace(P, "pj_ellipsoid - final: %s %s %s %s", |
124 | 120k | P->def_size ? P->def_size : empty, |
125 | 120k | P->def_shape ? P->def_shape : empty, |
126 | 120k | P->def_spherification ? P->def_spherification : empty, |
127 | 120k | P->def_ellps ? P->def_ellps : empty); |
128 | | |
129 | 120k | if (proj_errno(P)) |
130 | 82 | return 5; |
131 | | |
132 | | /* success */ |
133 | 120k | return proj_errno_restore(P, err); |
134 | 120k | } |
135 | | |
136 | | /***************************************************************************************/ |
137 | 133k | static int ellps_ellps(PJ *P) { |
138 | | /***************************************************************************************/ |
139 | 133k | const PJ_ELLPS *ellps; |
140 | 133k | paralist *par = nullptr; |
141 | 133k | char *name; |
142 | 133k | int err; |
143 | | |
144 | | /* Sail home if ellps=xxx is not specified */ |
145 | 133k | par = pj_get_param(P->params, "ellps"); |
146 | 133k | if (nullptr == par) |
147 | 35.7k | return 0; |
148 | | |
149 | | /* Then look up the right size and shape parameters from the builtin list */ |
150 | 97.9k | if (strlen(par->param) < 7) { |
151 | 125 | proj_log_error(P, _("Invalid value for +ellps")); |
152 | 125 | return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
153 | 125 | } |
154 | 97.8k | name = par->param + 6; |
155 | 97.8k | ellps = pj_find_ellps(name); |
156 | 97.8k | if (nullptr == ellps) { |
157 | 67 | proj_log_error(P, _("Unrecognized value for +ellps")); |
158 | 67 | return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
159 | 67 | } |
160 | | |
161 | | /* Now, get things ready for ellps_size/ellps_shape, make them do their |
162 | | * thing |
163 | | */ |
164 | 97.7k | err = proj_errno_reset(P); |
165 | | |
166 | 97.7k | paralist *new_params = pj_mkparam(ellps->major); |
167 | 97.7k | if (nullptr == new_params) |
168 | 0 | return proj_errno_set(P, PROJ_ERR_OTHER /*ENOMEM*/); |
169 | 97.7k | new_params->next = pj_mkparam(ellps->ell); |
170 | 97.7k | if (nullptr == new_params->next) { |
171 | 0 | free(new_params); |
172 | 0 | return proj_errno_set(P, PROJ_ERR_OTHER /*ENOMEM*/); |
173 | 0 | } |
174 | 97.7k | paralist *old_params = P->params; |
175 | 97.7k | P->params = new_params; |
176 | | |
177 | 97.7k | { |
178 | 97.7k | PJ empty_PJ; |
179 | 97.7k | pj_inherit_ellipsoid_def(&empty_PJ, P); |
180 | 97.7k | } |
181 | 97.7k | const bool errorOnSizeOrShape = (ellps_size(P) || ellps_shape(P)); |
182 | 97.7k | P->params = old_params; |
183 | 97.7k | free(new_params->next); |
184 | 97.7k | free(new_params); |
185 | 97.7k | if (errorOnSizeOrShape) |
186 | 0 | return proj_errno_set(P, PROJ_ERR_OTHER /*ENOMEM*/); |
187 | 97.7k | if (proj_errno(P)) |
188 | 0 | return proj_errno(P); |
189 | | |
190 | | /* Finally update P and sail home */ |
191 | 97.7k | P->def_ellps = pj_strdup(par->param); |
192 | 97.7k | par->used = 1; |
193 | | |
194 | 97.7k | return proj_errno_restore(P, err); |
195 | 97.7k | } |
196 | | |
197 | | /***************************************************************************************/ |
198 | 234k | static int ellps_size(PJ *P) { |
199 | | /***************************************************************************************/ |
200 | 234k | paralist *par = nullptr; |
201 | 234k | int a_was_set = 0; |
202 | | |
203 | 234k | free(P->def_size); |
204 | 234k | P->def_size = nullptr; |
205 | | |
206 | | /* A size parameter *must* be given, but may have been given as ellps prior |
207 | | */ |
208 | 234k | if (P->a != 0) |
209 | 103k | a_was_set = 1; |
210 | | |
211 | | /* Check which size key is specified */ |
212 | 234k | par = pj_get_param(P->params, "R"); |
213 | 234k | if (nullptr == par) |
214 | 231k | par = pj_get_param(P->params, "a"); |
215 | 234k | if (nullptr == par) { |
216 | 114k | if (a_was_set) |
217 | 103k | return 0; |
218 | 11.8k | if (P->need_ellps) |
219 | 122 | proj_log_error(P, _("Major axis not given")); |
220 | 11.8k | return proj_errno_set(P, PROJ_ERR_INVALID_OP_MISSING_ARG); |
221 | 114k | } |
222 | | |
223 | 119k | P->def_size = pj_strdup(par->param); |
224 | 119k | par->used = 1; |
225 | 119k | P->a = pj_atof(pj_param_value(par)); |
226 | 119k | if (P->a <= 0) { |
227 | 1.47k | proj_log_error(P, _("Invalid value for major axis")); |
228 | 1.47k | return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
229 | 1.47k | } |
230 | 118k | if (HUGE_VAL == P->a) { |
231 | 12 | proj_log_error(P, _("Invalid value for major axis")); |
232 | 12 | return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
233 | 12 | } |
234 | | |
235 | 118k | if ('R' == par->param[0]) { |
236 | 2.08k | P->es = P->f = P->e = P->rf = 0; |
237 | 2.08k | P->b = P->a; |
238 | 2.08k | } |
239 | 118k | return 0; |
240 | 118k | } |
241 | | |
242 | | /***************************************************************************************/ |
243 | 218k | static int ellps_shape(PJ *P) { |
244 | | /***************************************************************************************/ |
245 | 218k | const char *keys[] = {"rf", "f", "es", "e", "b"}; |
246 | 218k | paralist *par = nullptr; |
247 | 218k | size_t i, len; |
248 | | |
249 | 218k | par = nullptr; |
250 | 218k | len = sizeof(keys) / sizeof(char *); |
251 | | |
252 | 218k | free(P->def_shape); |
253 | 218k | P->def_shape = nullptr; |
254 | | |
255 | | /* Check which shape key is specified */ |
256 | 781k | for (i = 0; i < len; i++) { |
257 | 676k | par = pj_get_param(P->params, keys[i]); |
258 | 676k | if (par) |
259 | 114k | break; |
260 | 676k | } |
261 | | |
262 | | /* Not giving a shape parameter means selecting a sphere, unless shape */ |
263 | | /* has been selected previously via ellps=xxx */ |
264 | 218k | if (nullptr == par && P->es != 0) |
265 | 100k | return 0; |
266 | 118k | if (nullptr == par && P->es == 0) { |
267 | 4.34k | P->es = P->f = 0; |
268 | 4.34k | P->b = P->a; |
269 | 4.34k | return 0; |
270 | 4.34k | } |
271 | | |
272 | 114k | P->def_shape = pj_strdup(par->param); |
273 | 114k | par->used = 1; |
274 | 114k | P->es = P->f = P->b = P->e = P->rf = 0; |
275 | | |
276 | 114k | switch (i) { |
277 | | |
278 | | /* reverse flattening, rf */ |
279 | 96.9k | case 0: |
280 | 96.9k | P->rf = pj_atof(pj_param_value(par)); |
281 | 96.9k | if (HUGE_VAL == P->rf || P->rf <= 0) { |
282 | 41 | proj_log_error(P, _("Invalid value for rf. Should be > 0")); |
283 | 41 | return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
284 | 41 | } |
285 | 96.8k | P->f = 1 / P->rf; |
286 | 96.8k | P->es = 2 * P->f - P->f * P->f; |
287 | 96.8k | break; |
288 | | |
289 | | /* flattening, f */ |
290 | 1.92k | case 1: |
291 | 1.92k | P->f = pj_atof(pj_param_value(par)); |
292 | 1.92k | if (HUGE_VAL == P->f || P->f < 0) { |
293 | 43 | proj_log_error(P, _("Invalid value for f. Should be >= 0")); |
294 | 43 | return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
295 | 43 | } |
296 | | |
297 | 1.88k | P->rf = P->f != 0.0 ? 1.0 / P->f : HUGE_VAL; |
298 | 1.88k | P->es = 2 * P->f - P->f * P->f; |
299 | 1.88k | break; |
300 | | |
301 | | /* eccentricity squared, es */ |
302 | 11.6k | case 2: |
303 | 11.6k | P->es = pj_atof(pj_param_value(par)); |
304 | 11.6k | if (HUGE_VAL == P->es || P->es < 0 || P->es >= 1) { |
305 | 53 | proj_log_error(P, |
306 | 53 | _("Invalid value for es. Should be in [0,1[ range")); |
307 | 53 | return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
308 | 53 | } |
309 | 11.6k | break; |
310 | | |
311 | | /* eccentricity, e */ |
312 | 11.6k | case 3: |
313 | 1.63k | P->e = pj_atof(pj_param_value(par)); |
314 | 1.63k | if (HUGE_VAL == P->e || P->e < 0 || P->e >= 1) { |
315 | 86 | proj_log_error(P, |
316 | 86 | _("Invalid value for e. Should be in [0,1[ range")); |
317 | 86 | return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
318 | 86 | } |
319 | 1.55k | P->es = P->e * P->e; |
320 | 1.55k | break; |
321 | | |
322 | | /* semiminor axis, b */ |
323 | 2.24k | case 4: |
324 | 2.24k | P->b = pj_atof(pj_param_value(par)); |
325 | 2.24k | if (HUGE_VAL == P->b || P->b <= 0) { |
326 | 109 | proj_log_error(P, _("Invalid value for b. Should be > 0")); |
327 | 109 | return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
328 | 109 | } |
329 | 2.13k | if (P->b == P->a) |
330 | 1.24k | break; |
331 | | // coverity[division_by_zero] |
332 | 894 | P->f = (P->a - P->b) / P->a; |
333 | 894 | P->es = 2 * P->f - P->f * P->f; |
334 | 894 | break; |
335 | 0 | default: |
336 | | // shouldn't happen |
337 | 0 | return PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE; |
338 | 114k | } |
339 | | |
340 | | // Written that way to catch NaN |
341 | 114k | if (!(P->es >= 0)) { |
342 | 10 | proj_log_error(P, _("Invalid eccentricity")); |
343 | 10 | return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
344 | 10 | } |
345 | 114k | return 0; |
346 | 114k | } |
347 | | |
348 | | /* series coefficients for calculating ellipsoid-equivalent spheres */ |
349 | | static const double SIXTH = 1 / 6.; |
350 | | static const double RA4 = 17 / 360.; |
351 | | static const double RA6 = 67 / 3024.; |
352 | | static const double RV4 = 5 / 72.; |
353 | | static const double RV6 = 55 / 1296.; |
354 | | |
355 | | /***************************************************************************************/ |
356 | 120k | static int ellps_spherification(PJ *P) { |
357 | | /***************************************************************************************/ |
358 | 120k | const char *keys[] = {"R_A", "R_V", "R_a", "R_g", |
359 | 120k | "R_h", "R_lat_a", "R_lat_g", "R_C"}; |
360 | 120k | size_t len, i; |
361 | 120k | paralist *par = nullptr; |
362 | | |
363 | 120k | double t; |
364 | 120k | char *v, *endp; |
365 | | |
366 | 120k | len = sizeof(keys) / sizeof(char *); |
367 | | |
368 | | /* Check which spherification key is specified */ |
369 | 1.06M | for (i = 0; i < len; i++) { |
370 | 948k | par = pj_get_param(P->params, keys[i]); |
371 | 948k | if (par) |
372 | 6.09k | break; |
373 | 948k | } |
374 | | |
375 | | /* No spherification specified? Then we're done */ |
376 | 120k | if (i == len) |
377 | 114k | return 0; |
378 | | |
379 | | /* Store definition */ |
380 | 6.09k | P->def_spherification = pj_strdup(par->param); |
381 | 6.09k | par->used = 1; |
382 | | |
383 | 6.09k | switch (i) { |
384 | | |
385 | | /* R_A - a sphere with same area as ellipsoid */ |
386 | 682 | case 0: |
387 | 682 | P->a *= 1. - P->es * (SIXTH + P->es * (RA4 + P->es * RA6)); |
388 | 682 | break; |
389 | | |
390 | | /* R_V - a sphere with same volume as ellipsoid */ |
391 | 152 | case 1: |
392 | 152 | P->a *= 1. - P->es * (SIXTH + P->es * (RV4 + P->es * RV6)); |
393 | 152 | break; |
394 | | |
395 | | /* R_a - a sphere with R = the arithmetic mean of the ellipsoid */ |
396 | 304 | case 2: |
397 | 304 | P->a = (P->a + P->b) / 2; |
398 | 304 | break; |
399 | | |
400 | | /* R_g - a sphere with R = the geometric mean of the ellipsoid */ |
401 | 1.16k | case 3: |
402 | 1.16k | P->a = sqrt(P->a * P->b); |
403 | 1.16k | break; |
404 | | |
405 | | /* R_h - a sphere with R = the harmonic mean of the ellipsoid */ |
406 | 58 | case 4: |
407 | 58 | if (P->a + P->b == 0) |
408 | 0 | return proj_errno_set( |
409 | 0 | P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN); |
410 | 58 | P->a = (2 * P->a * P->b) / (P->a + P->b); |
411 | 58 | break; |
412 | | |
413 | | /* R_lat_a - a sphere with R = the arithmetic mean of the ellipsoid at given |
414 | | * latitude */ |
415 | 3.03k | case 5: |
416 | | /* R_lat_g - a sphere with R = the geometric mean of the ellipsoid at given |
417 | | * latitude */ |
418 | 3.63k | case 6: |
419 | 3.63k | v = pj_param_value(par); |
420 | 3.63k | t = proj_dmstor(v, &endp); |
421 | 3.63k | if (fabs(t) > M_HALFPI) { |
422 | 17 | proj_log_error( |
423 | 17 | P, _("Invalid value for lat_g. |lat_g| should be <= 90°")); |
424 | 17 | return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
425 | 17 | } |
426 | 3.61k | t = sin(t); |
427 | 3.61k | t = 1 - P->es * t * t; |
428 | 3.61k | if (t == 0.) { |
429 | 0 | proj_log_error(P, _("Invalid eccentricity")); |
430 | 0 | return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
431 | 0 | } |
432 | 3.61k | if (i == 5) /* arithmetic */ |
433 | 3.01k | P->a *= (1. - P->es + t) / (2 * t * sqrt(t)); |
434 | 598 | else /* geometric */ |
435 | 598 | P->a *= sqrt(1 - P->es) / t; |
436 | 3.61k | break; |
437 | | |
438 | | /* R_C - a sphere with R = radius of conformal sphere, taken at a |
439 | | * latitude that is phi0 (note: at least for mercator. for other |
440 | | * projection methods, this could be phi1) |
441 | | * Formula from IOGP Publication 373-7-2 – Geomatics Guidance Note number 7, |
442 | | * part 2 1.1 Ellipsoid parameters |
443 | | */ |
444 | 95 | case 7: |
445 | 95 | t = sin(P->phi0); |
446 | 95 | t = 1 - P->es * t * t; |
447 | 95 | if (t == 0.) { |
448 | 0 | proj_log_error(P, _("Invalid eccentricity")); |
449 | 0 | return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
450 | 0 | } |
451 | 95 | P->a *= sqrt(1 - P->es) / t; |
452 | 95 | break; |
453 | 6.09k | } |
454 | | |
455 | 6.07k | if (P->a <= 0.) { |
456 | 0 | proj_log_error(P, _("Invalid or missing major axis")); |
457 | 0 | return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
458 | 0 | } |
459 | | |
460 | | /* Clean up the ellipsoidal parameters to reflect the sphere */ |
461 | 6.07k | P->es = P->e = P->f = 0; |
462 | 6.07k | P->rf = HUGE_VAL; |
463 | 6.07k | P->b = P->a; |
464 | 6.07k | pj_calc_ellipsoid_params(P, P->a, 0); |
465 | | |
466 | 6.07k | return 0; |
467 | 6.07k | } |
468 | | |
469 | | /* locate parameter in list */ |
470 | 2.36M | static paralist *pj_get_param(paralist *list, const char *key) { |
471 | 2.36M | size_t l = strlen(key); |
472 | 24.2M | while (list && !(0 == strncmp(list->param, key, l) && |
473 | 22.2M | (0 == list->param[l] || list->param[l] == '='))) |
474 | 21.9M | list = list->next; |
475 | 2.36M | return list; |
476 | 2.36M | } |
477 | | |
478 | 237k | static char *pj_param_value(paralist *list) { |
479 | 237k | char *key, *value; |
480 | 237k | if (nullptr == list) |
481 | 0 | return nullptr; |
482 | | |
483 | 237k | key = list->param; |
484 | 237k | value = strchr(key, '='); |
485 | | |
486 | | /* a flag (i.e. a key without value) has its own name (key) as value */ |
487 | 237k | return value ? value + 1 : key; |
488 | 237k | } |
489 | | |
490 | 97.8k | static const PJ_ELLPS *pj_find_ellps(const char *name) { |
491 | 97.8k | int i; |
492 | 97.8k | const char *s; |
493 | 97.8k | const PJ_ELLPS *ellps; |
494 | | |
495 | 97.8k | if (nullptr == name) |
496 | 0 | return nullptr; |
497 | | |
498 | 97.8k | ellps = proj_list_ellps(); |
499 | | |
500 | | /* Search through internal ellipsoid list for name */ |
501 | 1.77M | for (i = 0; (s = ellps[i].id) && strcmp(name, s); ++i) |
502 | 1.67M | ; |
503 | 97.8k | if (nullptr == s) |
504 | 67 | return nullptr; |
505 | 97.7k | return ellps + i; |
506 | 97.8k | } |
507 | | |
508 | | /**************************************************************************************/ |
509 | 106k | void pj_inherit_ellipsoid_def(const PJ *src, PJ *dst) { |
510 | | /*************************************************************************************** |
511 | | Brute force copy the ellipsoidal parameters from src to dst. This code |
512 | | was written before the actual ellipsoid setup parameters were kept available |
513 | | in the PJ->def_xxx elements. |
514 | | ***************************************************************************************/ |
515 | | |
516 | | /* The linear parameters */ |
517 | 106k | dst->a = src->a; |
518 | 106k | dst->b = src->b; |
519 | 106k | dst->ra = src->ra; |
520 | 106k | dst->rb = src->rb; |
521 | | |
522 | | /* The eccentricities */ |
523 | 106k | dst->alpha = src->alpha; |
524 | 106k | dst->e = src->e; |
525 | 106k | dst->es = src->es; |
526 | 106k | dst->e2 = src->e2; |
527 | 106k | dst->e2s = src->e2s; |
528 | 106k | dst->e3 = src->e3; |
529 | 106k | dst->e3s = src->e3s; |
530 | 106k | dst->one_es = src->one_es; |
531 | 106k | dst->rone_es = src->rone_es; |
532 | | |
533 | | /* The flattenings */ |
534 | 106k | dst->f = src->f; |
535 | 106k | dst->f2 = src->f2; |
536 | 106k | dst->n = src->n; |
537 | 106k | dst->rf = src->rf; |
538 | 106k | dst->rf2 = src->rf2; |
539 | 106k | dst->rn = src->rn; |
540 | | |
541 | | /* This one's for GRS80 */ |
542 | 106k | dst->J = src->J; |
543 | | |
544 | | /* es and a before any +proj related adjustment */ |
545 | 106k | dst->es_orig = src->es_orig; |
546 | 106k | dst->a_orig = src->a_orig; |
547 | 106k | } |
548 | | |
549 | | /***************************************************************************************/ |
550 | 297k | int pj_calc_ellipsoid_params(PJ *P, double a, double es) { |
551 | | /**************************************************************************************** |
552 | | Calculate a large number of ancillary ellipsoidal parameters, in |
553 | | addition to the two traditional PROJ defining parameters: Semimajor axis, a, |
554 | | and the eccentricity squared, es. |
555 | | |
556 | | Most of these parameters are fairly cheap to compute in comparison to |
557 | | the overall effort involved in initializing a PJ object. They may, however, |
558 | | take a substantial part of the time taken in computing an individual point |
559 | | transformation. |
560 | | |
561 | | So by providing them up front, we can amortize the (already modest) cost |
562 | | over all transformations carried out over the entire lifetime of a PJ |
563 | | object, rather than incur that cost for every single transformation. |
564 | | |
565 | | Most of the parameter calculations here are based on the "angular |
566 | | eccentricity", i.e. the angle, measured from the semiminor axis, of a line |
567 | | going from the north pole to one of the foci of the ellipsoid - or in other |
568 | | words: The arc sine of the eccentricity. |
569 | | |
570 | | The formulae used are mostly taken from: |
571 | | |
572 | | Richard H. Rapp: Geometric Geodesy, Part I, (178 pp, 1991). |
573 | | Columbus, Ohio: Dept. of Geodetic Science |
574 | | and Surveying, Ohio State University. |
575 | | |
576 | | ****************************************************************************************/ |
577 | | |
578 | 297k | P->a = a; |
579 | 297k | P->es = es; |
580 | | |
581 | | /* Compute some ancillary ellipsoidal parameters */ |
582 | 297k | if (P->e == 0) |
583 | 188k | P->e = sqrt(P->es); /* eccentricity */ |
584 | 297k | P->alpha = asin(P->e); /* angular eccentricity */ |
585 | | |
586 | | /* second eccentricity */ |
587 | 297k | P->e2 = tan(P->alpha); |
588 | 297k | P->e2s = P->e2 * P->e2; |
589 | | |
590 | | /* third eccentricity */ |
591 | 297k | P->e3 = (0 != P->alpha) |
592 | 297k | ? sin(P->alpha) / sqrt(2 - sin(P->alpha) * sin(P->alpha)) |
593 | 297k | : 0; |
594 | 297k | P->e3s = P->e3 * P->e3; |
595 | | |
596 | | /* flattening */ |
597 | 297k | if (0 == P->f) |
598 | 79.2k | P->f = 1 - cos(P->alpha); /* = 1 - sqrt (1 - PIN->es); */ |
599 | 297k | if (!(P->f >= 0.0 && P->f < 1.0)) { |
600 | 82 | proj_log_error(P, _("Invalid eccentricity")); |
601 | 82 | proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
602 | 82 | return PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE; |
603 | 82 | } |
604 | 297k | P->rf = P->f != 0.0 ? 1.0 / P->f : HUGE_VAL; |
605 | | |
606 | | /* second flattening */ |
607 | 297k | P->f2 = (cos(P->alpha) != 0) ? 1 / cos(P->alpha) - 1 : 0; |
608 | 297k | P->rf2 = P->f2 != 0.0 ? 1 / P->f2 : HUGE_VAL; |
609 | | |
610 | | /* third flattening */ |
611 | 297k | P->n = pow(tan(P->alpha / 2), 2); |
612 | 297k | P->rn = P->n != 0.0 ? 1 / P->n : HUGE_VAL; |
613 | | |
614 | | /* ...and a few more */ |
615 | 297k | if (0 == P->b) |
616 | 155k | P->b = (1 - P->f) * P->a; |
617 | 297k | P->rb = 1. / P->b; |
618 | 297k | P->ra = 1. / P->a; |
619 | | |
620 | 297k | P->one_es = 1. - P->es; |
621 | 297k | if (P->one_es == 0.) { |
622 | 0 | proj_log_error(P, _("Invalid eccentricity")); |
623 | 0 | proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
624 | 0 | return PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE; |
625 | 0 | } |
626 | | |
627 | 297k | P->rone_es = 1. / P->one_es; |
628 | | |
629 | 297k | return 0; |
630 | 297k | } |
631 | | |
632 | | /**************************************************************************************/ |
633 | 0 | int pj_ell_set(PJ_CONTEXT *ctx, paralist *pl, double *a, double *es) { |
634 | | /*************************************************************************************** |
635 | | Initialize ellipsoidal parameters by emulating the original ellipsoid |
636 | | setup function by Gerald Evenden, through a call to pj_ellipsoid |
637 | | ***************************************************************************************/ |
638 | 0 | PJ B; |
639 | 0 | int ret; |
640 | |
|
641 | 0 | B.ctx = ctx; |
642 | 0 | B.params = pl; |
643 | |
|
644 | 0 | ret = pj_ellipsoid(&B); |
645 | |
|
646 | 0 | free(B.def_size); |
647 | 0 | free(B.def_shape); |
648 | 0 | free(B.def_spherification); |
649 | 0 | free(B.def_ellps); |
650 | |
|
651 | 0 | if (ret) |
652 | 0 | return ret; |
653 | | |
654 | 0 | *a = B.a; |
655 | 0 | *es = B.es; |
656 | 0 | return 0; |
657 | 0 | } |