Coverage Report

Created: 2026-04-10 07:04

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