Coverage Report

Created: 2026-02-14 09:00

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