Coverage Report

Created: 2025-08-29 07:11

/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
257k
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
257k
    int err = proj_errno_reset(P);
81
257k
    const char *empty = {""};
82
83
257k
    free(P->def_size);
84
257k
    P->def_size = nullptr;
85
257k
    free(P->def_shape);
86
257k
    P->def_shape = nullptr;
87
257k
    free(P->def_spherification);
88
257k
    P->def_spherification = nullptr;
89
257k
    free(P->def_ellps);
90
257k
    P->def_ellps = nullptr;
91
92
    /* Specifying R overrules everything */
93
257k
    if (pj_get_param(P->params, "R")) {
94
681
        if (0 != ellps_size(P))
95
247
            return 1;
96
434
        pj_calc_ellipsoid_params(P, P->a, 0);
97
434
        if (proj_errno(P))
98
0
            return 1;
99
434
        return proj_errno_restore(P, err);
100
434
    }
101
102
    /* If an ellps argument is specified, start by using that */
103
257k
    if (0 != ellps_ellps(P))
104
124
        return 1;
105
106
    /* We may overwrite the size */
107
256k
    if (0 != ellps_size(P))
108
3.57k
        return 2;
109
110
    /* We may also overwrite the shape */
111
253k
    if (0 != ellps_shape(P))
112
143
        return 3;
113
114
    /* When we're done with it, we compute all related ellipsoid parameters */
115
253k
    pj_calc_ellipsoid_params(P, P->a, P->es);
116
117
    /* And finally, we may turn it into a sphere */
118
253k
    if (0 != ellps_spherification(P))
119
3
        return 4;
120
121
253k
    proj_log_trace(P, "pj_ellipsoid - final: a=%.3f f=1/%7.3f, errno=%d", P->a,
122
253k
                   P->f != 0 ? 1 / P->f : 0, proj_errno(P));
123
253k
    proj_log_trace(P, "pj_ellipsoid - final: %s %s %s %s",
124
253k
                   P->def_size ? P->def_size : empty,
125
253k
                   P->def_shape ? P->def_shape : empty,
126
253k
                   P->def_spherification ? P->def_spherification : empty,
127
253k
                   P->def_ellps ? P->def_ellps : empty);
128
129
253k
    if (proj_errno(P))
130
72
        return 5;
131
132
    /* success */
133
253k
    return proj_errno_restore(P, err);
134
253k
}
135
136
/***************************************************************************************/
137
257k
static int ellps_ellps(PJ *P) {
138
    /***************************************************************************************/
139
257k
    const PJ_ELLPS *ellps;
140
257k
    paralist *par = nullptr;
141
257k
    char *name;
142
257k
    int err;
143
144
    /* Sail home if ellps=xxx is not specified */
145
257k
    par = pj_get_param(P->params, "ellps");
146
257k
    if (nullptr == par)
147
52.7k
        return 0;
148
149
    /* Then look up the right size and shape parameters from the builtin list */
150
204k
    if (strlen(par->param) < 7) {
151
13
        proj_log_error(P, _("Invalid value for +ellps"));
152
13
        return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
153
13
    }
154
204k
    name = par->param + 6;
155
204k
    ellps = pj_find_ellps(name);
156
204k
    if (nullptr == ellps) {
157
111
        proj_log_error(P, _("Unrecognized value for +ellps"));
158
111
        return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
159
111
    }
160
161
    /* Now, get things ready for ellps_size/ellps_shape, make them do their
162
     * thing
163
     */
164
204k
    err = proj_errno_reset(P);
165
166
204k
    paralist *new_params = pj_mkparam(ellps->major);
167
204k
    if (nullptr == new_params)
168
0
        return proj_errno_set(P, PROJ_ERR_OTHER /*ENOMEM*/);
169
204k
    new_params->next = pj_mkparam(ellps->ell);
170
204k
    if (nullptr == new_params->next) {
171
0
        free(new_params);
172
0
        return proj_errno_set(P, PROJ_ERR_OTHER /*ENOMEM*/);
173
0
    }
174
204k
    paralist *old_params = P->params;
175
204k
    P->params = new_params;
176
177
204k
    {
178
204k
        PJ empty_PJ;
179
204k
        pj_inherit_ellipsoid_def(&empty_PJ, P);
180
204k
    }
181
204k
    const bool errorOnSizeOrShape = (ellps_size(P) || ellps_shape(P));
182
204k
    P->params = old_params;
183
204k
    free(new_params->next);
184
204k
    free(new_params);
185
204k
    if (errorOnSizeOrShape)
186
0
        return proj_errno_set(P, PROJ_ERR_OTHER /*ENOMEM*/);
187
204k
    if (proj_errno(P))
188
0
        return proj_errno(P);
189
190
    /* Finally update P and sail home */
191
204k
    P->def_ellps = pj_strdup(par->param);
192
204k
    par->used = 1;
193
194
204k
    return proj_errno_restore(P, err);
195
204k
}
196
197
/***************************************************************************************/
198
461k
static int ellps_size(PJ *P) {
199
    /***************************************************************************************/
200
461k
    paralist *par = nullptr;
201
461k
    int a_was_set = 0;
202
203
461k
    free(P->def_size);
204
461k
    P->def_size = nullptr;
205
206
    /* A size parameter *must* be given, but may have been given as ellps prior
207
     */
208
461k
    if (P->a != 0)
209
227k
        a_was_set = 1;
210
211
    /* Check which size key is specified */
212
461k
    par = pj_get_param(P->params, "R");
213
461k
    if (nullptr == par)
214
461k
        par = pj_get_param(P->params, "a");
215
461k
    if (nullptr == par) {
216
230k
        if (a_was_set)
217
226k
            return 0;
218
3.48k
        if (P->need_ellps)
219
123
            proj_log_error(P, _("Major axis not given"));
220
3.48k
        return proj_errno_set(P, PROJ_ERR_INVALID_OP_MISSING_ARG);
221
230k
    }
222
223
231k
    P->def_size = pj_strdup(par->param);
224
231k
    par->used = 1;
225
231k
    P->a = pj_atof(pj_param_value(par));
226
231k
    if (P->a <= 0) {
227
327
        proj_log_error(P, _("Invalid value for major axis"));
228
327
        return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
229
327
    }
230
230k
    if (HUGE_VAL == P->a) {
231
15
        proj_log_error(P, _("Invalid value for major axis"));
232
15
        return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
233
15
    }
234
235
230k
    if ('R' == par->param[0]) {
236
434
        P->es = P->f = P->e = P->rf = 0;
237
434
        P->b = P->a;
238
434
    }
239
230k
    return 0;
240
230k
}
241
242
/***************************************************************************************/
243
457k
static int ellps_shape(PJ *P) {
244
    /***************************************************************************************/
245
457k
    const char *keys[] = {"rf", "f", "es", "e", "b"};
246
457k
    paralist *par = nullptr;
247
457k
    size_t i, len;
248
249
457k
    par = nullptr;
250
457k
    len = sizeof(keys) / sizeof(char *);
251
252
457k
    free(P->def_shape);
253
457k
    P->def_shape = nullptr;
254
255
    /* Check which shape key is specified */
256
1.76M
    for (i = 0; i < len; i++) {
257
1.53M
        par = pj_get_param(P->params, keys[i]);
258
1.53M
        if (par)
259
234k
            break;
260
1.53M
    }
261
262
    /* Not giving a shape parameter means selecting a sphere, unless shape */
263
    /* has been selected previously via ellps=xxx */
264
457k
    if (nullptr == par && P->es != 0)
265
220k
        return 0;
266
236k
    if (nullptr == par && P->es == 0) {
267
2.57k
        P->es = P->f = 0;
268
2.57k
        P->b = P->a;
269
2.57k
        return 0;
270
2.57k
    }
271
272
234k
    P->def_shape = pj_strdup(par->param);
273
234k
    par->used = 1;
274
234k
    P->es = P->f = P->b = P->e = P->rf = 0;
275
276
234k
    switch (i) {
277
278
    /* reverse flattening, rf */
279
173k
    case 0:
280
173k
        P->rf = pj_atof(pj_param_value(par));
281
173k
        if (HUGE_VAL == P->rf || P->rf <= 0) {
282
10
            proj_log_error(P, _("Invalid value for rf. Should be > 0"));
283
10
            return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
284
10
        }
285
173k
        P->f = 1 / P->rf;
286
173k
        P->es = 2 * P->f - P->f * P->f;
287
173k
        break;
288
289
    /* flattening, f */
290
1.45k
    case 1:
291
1.45k
        P->f = pj_atof(pj_param_value(par));
292
1.45k
        if (HUGE_VAL == P->f || P->f < 0) {
293
4
            proj_log_error(P, _("Invalid value for f. Should be >= 0"));
294
4
            return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
295
4
        }
296
297
1.44k
        P->rf = P->f != 0.0 ? 1.0 / P->f : HUGE_VAL;
298
1.44k
        P->es = 2 * P->f - P->f * P->f;
299
1.44k
        break;
300
301
    /* eccentricity squared, es */
302
23.1k
    case 2:
303
23.1k
        P->es = pj_atof(pj_param_value(par));
304
23.1k
        if (HUGE_VAL == P->es || P->es < 0 || P->es >= 1) {
305
10
            proj_log_error(P,
306
10
                           _("Invalid value for es. Should be in [0,1[ range"));
307
10
            return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
308
10
        }
309
23.1k
        break;
310
311
    /* eccentricity, e */
312
23.1k
    case 3:
313
3.39k
        P->e = pj_atof(pj_param_value(par));
314
3.39k
        if (HUGE_VAL == P->e || P->e < 0 || P->e >= 1) {
315
17
            proj_log_error(P,
316
17
                           _("Invalid value for e. Should be in [0,1[ range"));
317
17
            return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
318
17
        }
319
3.37k
        P->es = P->e * P->e;
320
3.37k
        break;
321
322
    /* semiminor axis, b */
323
32.4k
    case 4:
324
32.4k
        P->b = pj_atof(pj_param_value(par));
325
32.4k
        if (HUGE_VAL == P->b || P->b <= 0) {
326
64
            proj_log_error(P, _("Invalid value for b. Should be > 0"));
327
64
            return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
328
64
        }
329
32.4k
        if (P->b == P->a)
330
240
            break;
331
        // coverity[division_by_zero]
332
32.1k
        P->f = (P->a - P->b) / P->a;
333
32.1k
        P->es = 2 * P->f - P->f * P->f;
334
32.1k
        break;
335
0
    default:
336
        // shouldn't happen
337
0
        return PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE;
338
234k
    }
339
340
    // Written that way to catch NaN
341
234k
    if (!(P->es >= 0)) {
342
38
        proj_log_error(P, _("Invalid eccentricity"));
343
38
        return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
344
38
    }
345
234k
    return 0;
346
234k
}
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
253k
static int ellps_spherification(PJ *P) {
357
    /***************************************************************************************/
358
253k
    const char *keys[] = {"R_A", "R_V",     "R_a",     "R_g",
359
253k
                          "R_h", "R_lat_a", "R_lat_g", "R_C"};
360
253k
    size_t len, i;
361
253k
    paralist *par = nullptr;
362
363
253k
    double t;
364
253k
    char *v, *endp;
365
366
253k
    len = sizeof(keys) / sizeof(char *);
367
368
    /* Check which spherification key is specified */
369
2.27M
    for (i = 0; i < len; i++) {
370
2.02M
        par = pj_get_param(P->params, keys[i]);
371
2.02M
        if (par)
372
1.17k
            break;
373
2.02M
    }
374
375
    /* No spherification specified? Then we're done */
376
253k
    if (i == len)
377
252k
        return 0;
378
379
    /* Store definition */
380
1.17k
    P->def_spherification = pj_strdup(par->param);
381
1.17k
    par->used = 1;
382
383
1.17k
    switch (i) {
384
385
    /* R_A - a sphere with same area as ellipsoid */
386
417
    case 0:
387
417
        P->a *= 1. - P->es * (SIXTH + P->es * (RA4 + P->es * RA6));
388
417
        break;
389
390
    /* R_V - a sphere with same volume as ellipsoid */
391
17
    case 1:
392
17
        P->a *= 1. - P->es * (SIXTH + P->es * (RV4 + P->es * RV6));
393
17
        break;
394
395
    /* R_a - a sphere with R = the arithmetic mean of the ellipsoid */
396
65
    case 2:
397
65
        P->a = (P->a + P->b) / 2;
398
65
        break;
399
400
    /* R_g - a sphere with R = the geometric mean of the ellipsoid */
401
113
    case 3:
402
113
        P->a = sqrt(P->a * P->b);
403
113
        break;
404
405
    /* R_h - a sphere with R = the harmonic mean of the ellipsoid */
406
336
    case 4:
407
336
        if (P->a + P->b == 0)
408
0
            return proj_errno_set(
409
0
                P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN);
410
336
        P->a = (2 * P->a * P->b) / (P->a + P->b);
411
336
        break;
412
413
    /* R_lat_a - a sphere with R = the arithmetic mean of the ellipsoid at given
414
     * latitude */
415
33
    case 5:
416
    /* R_lat_g - a sphere with R = the geometric  mean of the ellipsoid at given
417
     * latitude */
418
91
    case 6:
419
91
        v = pj_param_value(par);
420
91
        t = proj_dmstor(v, &endp);
421
91
        if (fabs(t) > M_HALFPI) {
422
0
            proj_log_error(
423
0
                P, _("Invalid value for lat_g. |lat_g| should be <= 90°"));
424
0
            return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
425
0
        }
426
91
        t = sin(t);
427
91
        t = 1 - P->es * t * t;
428
91
        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
91
        if (i == 5) /* arithmetic */
433
33
            P->a *= (1. - P->es + t) / (2 * t * sqrt(t));
434
58
        else /* geometric */
435
58
            P->a *= sqrt(1 - P->es) / t;
436
91
        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
140
    case 7:
445
140
        t = sin(P->phi0);
446
140
        t = 1 - P->es * t * t;
447
140
        if (t == 0.) {
448
1
            proj_log_error(P, _("Invalid eccentricity"));
449
1
            return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
450
1
        }
451
139
        P->a *= sqrt(1 - P->es) / t;
452
139
        break;
453
1.17k
    }
454
455
1.17k
    if (P->a <= 0.) {
456
2
        proj_log_error(P, _("Invalid or missing major axis"));
457
2
        return proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
458
2
    }
459
460
    /* Clean up the ellipsoidal parameters to reflect the sphere */
461
1.17k
    P->es = P->e = P->f = 0;
462
1.17k
    P->rf = HUGE_VAL;
463
1.17k
    P->b = P->a;
464
1.17k
    pj_calc_ellipsoid_params(P, P->a, 0);
465
466
1.17k
    return 0;
467
1.17k
}
468
469
/* locate parameter in list */
470
4.99M
static paralist *pj_get_param(paralist *list, const char *key) {
471
4.99M
    size_t l = strlen(key);
472
52.8M
    while (list && !(0 == strncmp(list->param, key, l) &&
473
48.5M
                     (0 == list->param[l] || list->param[l] == '=')))
474
47.8M
        list = list->next;
475
4.99M
    return list;
476
4.99M
}
477
478
465k
static char *pj_param_value(paralist *list) {
479
465k
    char *key, *value;
480
465k
    if (nullptr == list)
481
0
        return nullptr;
482
483
465k
    key = list->param;
484
465k
    value = strchr(key, '=');
485
486
    /* a flag (i.e. a key without value) has its own name (key) as value */
487
465k
    return value ? value + 1 : key;
488
465k
}
489
490
204k
static const PJ_ELLPS *pj_find_ellps(const char *name) {
491
204k
    int i;
492
204k
    const char *s;
493
204k
    const PJ_ELLPS *ellps;
494
495
204k
    if (nullptr == name)
496
0
        return nullptr;
497
498
204k
    ellps = proj_list_ellps();
499
500
    /* Search through internal ellipsoid list for name */
501
3.16M
    for (i = 0; (s = ellps[i].id) && strcmp(name, s); ++i)
502
2.96M
        ;
503
204k
    if (nullptr == s)
504
111
        return nullptr;
505
204k
    return ellps + i;
506
204k
}
507
508
/**************************************************************************************/
509
225k
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
225k
    dst->a = src->a;
518
225k
    dst->b = src->b;
519
225k
    dst->ra = src->ra;
520
225k
    dst->rb = src->rb;
521
522
    /* The eccentricities */
523
225k
    dst->alpha = src->alpha;
524
225k
    dst->e = src->e;
525
225k
    dst->es = src->es;
526
225k
    dst->e2 = src->e2;
527
225k
    dst->e2s = src->e2s;
528
225k
    dst->e3 = src->e3;
529
225k
    dst->e3s = src->e3s;
530
225k
    dst->one_es = src->one_es;
531
225k
    dst->rone_es = src->rone_es;
532
533
    /* The flattenings */
534
225k
    dst->f = src->f;
535
225k
    dst->f2 = src->f2;
536
225k
    dst->n = src->n;
537
225k
    dst->rf = src->rf;
538
225k
    dst->rf2 = src->rf2;
539
225k
    dst->rn = src->rn;
540
541
    /* This one's for GRS80 */
542
225k
    dst->J = src->J;
543
544
    /* es and a before any +proj related adjustment */
545
225k
    dst->es_orig = src->es_orig;
546
225k
    dst->a_orig = src->a_orig;
547
225k
}
548
549
/***************************************************************************************/
550
552k
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
552k
    P->a = a;
579
552k
    P->es = es;
580
581
    /* Compute some ancillary ellipsoidal parameters */
582
552k
    if (P->e == 0)
583
288k
        P->e = sqrt(P->es); /* eccentricity */
584
552k
    P->alpha = asin(P->e);  /* angular eccentricity */
585
586
    /* second eccentricity */
587
552k
    P->e2 = tan(P->alpha);
588
552k
    P->e2s = P->e2 * P->e2;
589
590
    /* third eccentricity */
591
552k
    P->e3 = (0 != P->alpha)
592
552k
                ? sin(P->alpha) / sqrt(2 - sin(P->alpha) * sin(P->alpha))
593
552k
                : 0;
594
552k
    P->e3s = P->e3 * P->e3;
595
596
    /* flattening */
597
552k
    if (0 == P->f)
598
83.7k
        P->f = 1 - cos(P->alpha); /* = 1 - sqrt (1 - PIN->es); */
599
552k
    if (!(P->f >= 0.0 && P->f < 1.0)) {
600
13
        proj_log_error(P, _("Invalid eccentricity"));
601
13
        proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
602
13
        return PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE;
603
13
    }
604
552k
    P->rf = P->f != 0.0 ? 1.0 / P->f : HUGE_VAL;
605
606
    /* second flattening */
607
552k
    P->f2 = (cos(P->alpha) != 0) ? 1 / cos(P->alpha) - 1 : 0;
608
552k
    P->rf2 = P->f2 != 0.0 ? 1 / P->f2 : HUGE_VAL;
609
610
    /* third flattening */
611
552k
    P->n = pow(tan(P->alpha / 2), 2);
612
552k
    P->rn = P->n != 0.0 ? 1 / P->n : HUGE_VAL;
613
614
    /* ...and a few more */
615
552k
    if (0 == P->b)
616
241k
        P->b = (1 - P->f) * P->a;
617
552k
    P->rb = 1. / P->b;
618
552k
    P->ra = 1. / P->a;
619
620
552k
    P->one_es = 1. - P->es;
621
552k
    if (P->one_es == 0.) {
622
62
        proj_log_error(P, _("Invalid eccentricity"));
623
62
        proj_errno_set(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
624
62
        return PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE;
625
62
    }
626
627
552k
    P->rone_es = 1. / P->one_es;
628
629
552k
    return 0;
630
552k
}
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
}