Coverage Report

Created: 2025-06-13 06:29

/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
}