Coverage Report

Created: 2026-06-30 06:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PROJ/src/projections/cea.cpp
Line
Count
Source
1
#include <errno.h>
2
#include <math.h>
3
4
#include "proj.h"
5
#include "proj_internal.h"
6
7
namespace { // anonymous namespace
8
struct pj_cea_data {
9
    double qp;
10
    double *apa;
11
};
12
} // anonymous namespace
13
14
PROJ_HEAD(cea, "Equal Area Cylindrical") "\n\tCyl, Sph&Ell\n\tlat_ts=";
15
0
#define EPS 1e-10
16
17
20.0k
static PJ_XY cea_e_forward(PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */
18
20.0k
    PJ_XY xy = {0.0, 0.0};
19
20.0k
    xy.x = P->k0 * lp.lam;
20
20.0k
    xy.y = 0.5 * pj_authalic_lat_q(sin(lp.phi), P) / P->k0;
21
20.0k
    return xy;
22
20.0k
}
23
24
5.71k
static PJ_XY cea_s_forward(PJ_LP lp, PJ *P) { /* Spheroidal, forward */
25
5.71k
    PJ_XY xy = {0.0, 0.0};
26
5.71k
    xy.x = P->k0 * lp.lam;
27
5.71k
    xy.y = sin(lp.phi) / P->k0;
28
5.71k
    return xy;
29
5.71k
}
30
31
0
static PJ_LP cea_e_inverse(PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */
32
0
    PJ_LP lp = {0.0, 0.0};
33
0
    const struct pj_cea_data *Q =
34
0
        static_cast<const struct pj_cea_data *>(P->opaque);
35
0
    lp.phi = pj_authalic_lat_inverse(asin(2. * xy.y * P->k0 / Q->qp), Q->apa, P,
36
0
                                     Q->qp);
37
0
    lp.lam = xy.x / P->k0;
38
0
    return lp;
39
0
}
40
41
0
static PJ_LP cea_s_inverse(PJ_XY xy, PJ *P) { /* Spheroidal, inverse */
42
0
    PJ_LP lp = {0.0, 0.0};
43
44
0
    xy.y *= P->k0;
45
0
    const double t = fabs(xy.y);
46
0
    if (t - EPS <= 1.) {
47
0
        if (t >= 1.)
48
0
            lp.phi = xy.y < 0. ? -M_HALFPI : M_HALFPI;
49
0
        else
50
0
            lp.phi = asin(xy.y);
51
0
        lp.lam = xy.x / P->k0;
52
0
    } else {
53
0
        proj_errno_set(P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN);
54
0
        return lp;
55
0
    }
56
0
    return (lp);
57
0
}
58
59
616
static PJ *pj_cea_destructor(PJ *P, int errlev) { /* Destructor */
60
616
    if (nullptr == P)
61
0
        return nullptr;
62
63
616
    if (nullptr == P->opaque)
64
0
        return pj_default_destructor(P, errlev);
65
66
616
    free(static_cast<struct pj_cea_data *>(P->opaque)->apa);
67
616
    return pj_default_destructor(P, errlev);
68
616
}
69
70
616
PJ *PJ_PROJECTION(cea) {
71
616
    double t = 0.0;
72
616
    struct pj_cea_data *Q = static_cast<struct pj_cea_data *>(
73
616
        calloc(1, sizeof(struct pj_cea_data)));
74
616
    if (nullptr == Q)
75
0
        return pj_default_destructor(P, PROJ_ERR_OTHER /*ENOMEM*/);
76
616
    P->opaque = Q;
77
616
    P->destructor = pj_cea_destructor;
78
79
616
    if (pj_param(P->ctx, P->params, "tlat_ts").i) {
80
326
        t = pj_param(P->ctx, P->params, "rlat_ts").f;
81
326
        P->k0 = cos(t);
82
326
        if (P->k0 < 0.) {
83
0
            proj_log_error(
84
0
                P, _("Invalid value for lat_ts: |lat_ts| should be <= 90°"));
85
0
            return pj_default_destructor(P,
86
0
                                         PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
87
0
        }
88
326
    }
89
616
    if (P->es != 0.0) {
90
489
        t = sin(t);
91
489
        P->k0 /= sqrt(1. - P->es * t * t);
92
489
        P->e = sqrt(P->es);
93
489
        Q->apa = pj_authalic_lat_compute_coeffs(P->n);
94
489
        if (!(Q->apa))
95
0
            return pj_default_destructor(P, PROJ_ERR_OTHER /*ENOMEM*/);
96
97
489
        Q->qp = pj_authalic_lat_q(1.0, P);
98
489
        P->inv = cea_e_inverse;
99
489
        P->fwd = cea_e_forward;
100
489
    } else {
101
127
        P->inv = cea_s_inverse;
102
127
        P->fwd = cea_s_forward;
103
127
    }
104
105
616
    return P;
106
616
}
107
108
#undef EPS