Coverage Report

Created: 2026-06-30 08:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/proj/src/projections/gn_sinu.cpp
Line
Count
Source
1
2
3
#include <errno.h>
4
#include <math.h>
5
6
#include "proj.h"
7
#include "proj_internal.h"
8
9
PROJ_HEAD(gn_sinu, "General Sinusoidal Series") "\n\tPCyl, Sph\n\tm= n=";
10
PROJ_HEAD(sinu, "Sinusoidal (Sanson-Flamsteed)") "\n\tPCyl, Sph&Ell";
11
PROJ_HEAD(eck6, "Eckert VI") "\n\tPCyl, Sph";
12
PROJ_HEAD(mbtfps, "McBryde-Thomas Flat-Polar Sinusoidal") "\n\tPCyl, Sph";
13
14
0
#define EPS10 1e-10
15
0
#define MAX_ITER 8
16
0
#define LOOP_TOL 1e-7
17
18
namespace { // anonymous namespace
19
struct pj_gn_sinu_data {
20
    double *en;
21
    double m, n, C_x, C_y;
22
};
23
} // anonymous namespace
24
25
0
static PJ_XY gn_sinu_e_forward(PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */
26
0
    PJ_XY xy = {0.0, 0.0};
27
28
0
    const double s = sin(lp.phi);
29
0
    const double c = cos(lp.phi);
30
0
    xy.y = pj_mlfn(lp.phi, s, c,
31
0
                   static_cast<struct pj_gn_sinu_data *>(P->opaque)->en);
32
0
    xy.x = lp.lam * c / sqrt(1. - P->es * s * s);
33
0
    return xy;
34
0
}
35
36
0
static PJ_LP gn_sinu_e_inverse(PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */
37
0
    PJ_LP lp = {0.0, 0.0};
38
0
    double s;
39
40
0
    lp.phi =
41
0
        pj_inv_mlfn(xy.y, static_cast<struct pj_gn_sinu_data *>(P->opaque)->en);
42
0
    s = fabs(lp.phi);
43
0
    if (s < M_HALFPI) {
44
0
        s = sin(lp.phi);
45
0
        lp.lam = xy.x * sqrt(1. - P->es * s * s) / cos(lp.phi);
46
0
    } else if ((s - EPS10) < M_HALFPI) {
47
0
        lp.lam = 0.;
48
0
    } else {
49
0
        proj_errno_set(P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN);
50
0
    }
51
52
0
    return lp;
53
0
}
54
55
11.5k
static PJ_XY gn_sinu_s_forward(PJ_LP lp, PJ *P) { /* Spheroidal, forward */
56
11.5k
    PJ_XY xy = {0.0, 0.0};
57
11.5k
    struct pj_gn_sinu_data *Q =
58
11.5k
        static_cast<struct pj_gn_sinu_data *>(P->opaque);
59
60
11.5k
    if (Q->m == 0.0)
61
11.5k
        lp.phi = Q->n != 1. ? aasin(P->ctx, Q->n * sin(lp.phi)) : lp.phi;
62
0
    else {
63
0
        int i;
64
65
0
        const double k = Q->n * sin(lp.phi);
66
0
        for (i = MAX_ITER; i; --i) {
67
0
            const double V =
68
0
                (Q->m * lp.phi + sin(lp.phi) - k) / (Q->m + cos(lp.phi));
69
0
            lp.phi -= V;
70
0
            if (fabs(V) < LOOP_TOL)
71
0
                break;
72
0
        }
73
0
        if (!i) {
74
0
            proj_errno_set(P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN);
75
0
            return xy;
76
0
        }
77
0
    }
78
11.5k
    xy.x = Q->C_x * lp.lam * (Q->m + cos(lp.phi));
79
11.5k
    xy.y = Q->C_y * lp.phi;
80
81
11.5k
    return xy;
82
11.5k
}
83
84
0
static PJ_LP gn_sinu_s_inverse(PJ_XY xy, PJ *P) { /* Spheroidal, inverse */
85
0
    PJ_LP lp = {0.0, 0.0};
86
0
    struct pj_gn_sinu_data *Q =
87
0
        static_cast<struct pj_gn_sinu_data *>(P->opaque);
88
89
0
    xy.y /= Q->C_y;
90
0
    lp.phi = (Q->m != 0.0)
91
0
                 ? aasin(P->ctx, (Q->m * xy.y + sin(xy.y)) / Q->n)
92
0
                 : (Q->n != 1. ? aasin(P->ctx, sin(xy.y) / Q->n) : xy.y);
93
0
    lp.lam = xy.x / (Q->C_x * (Q->m + cos(xy.y)));
94
0
    return lp;
95
0
}
96
97
90.8k
static PJ *pj_gn_sinu_destructor(PJ *P, int errlev) { /* Destructor */
98
90.8k
    if (nullptr == P)
99
0
        return nullptr;
100
101
90.8k
    if (nullptr == P->opaque)
102
0
        return pj_default_destructor(P, errlev);
103
104
90.8k
    free(static_cast<struct pj_gn_sinu_data *>(P->opaque)->en);
105
90.8k
    return pj_default_destructor(P, errlev);
106
90.8k
}
107
108
/* for spheres, only */
109
89.0k
static void pj_gn_sinu_setup(PJ *P) {
110
89.0k
    struct pj_gn_sinu_data *Q =
111
89.0k
        static_cast<struct pj_gn_sinu_data *>(P->opaque);
112
89.0k
    P->es = 0;
113
89.0k
    P->inv = gn_sinu_s_inverse;
114
89.0k
    P->fwd = gn_sinu_s_forward;
115
116
89.0k
    Q->C_y = sqrt((Q->m + 1.) / Q->n);
117
89.0k
    Q->C_x = Q->C_y / (Q->m + 1.);
118
89.0k
}
119
120
73.6k
PJ *PJ_PROJECTION(sinu) {
121
73.6k
    struct pj_gn_sinu_data *Q = static_cast<struct pj_gn_sinu_data *>(
122
73.6k
        calloc(1, sizeof(struct pj_gn_sinu_data)));
123
73.6k
    if (nullptr == Q)
124
0
        return pj_default_destructor(P, PROJ_ERR_OTHER /*ENOMEM*/);
125
73.6k
    P->opaque = Q;
126
73.6k
    P->destructor = pj_gn_sinu_destructor;
127
128
73.6k
    if (!(Q->en = pj_enfn(P->n)))
129
0
        return pj_default_destructor(P, PROJ_ERR_OTHER /*ENOMEM*/);
130
131
73.6k
    if (P->es != 0.0) {
132
1.75k
        P->inv = gn_sinu_e_inverse;
133
1.75k
        P->fwd = gn_sinu_e_forward;
134
71.8k
    } else {
135
71.8k
        Q->n = 1.;
136
71.8k
        Q->m = 0.;
137
71.8k
        pj_gn_sinu_setup(P);
138
71.8k
    }
139
73.6k
    return P;
140
73.6k
}
141
142
13.1k
PJ *PJ_PROJECTION(eck6) {
143
13.1k
    struct pj_gn_sinu_data *Q = static_cast<struct pj_gn_sinu_data *>(
144
13.1k
        calloc(1, sizeof(struct pj_gn_sinu_data)));
145
13.1k
    if (nullptr == Q)
146
0
        return pj_default_destructor(P, PROJ_ERR_OTHER /*ENOMEM*/);
147
13.1k
    P->opaque = Q;
148
13.1k
    P->destructor = pj_gn_sinu_destructor;
149
150
13.1k
    Q->m = 1.;
151
13.1k
    Q->n = 2.570796326794896619231321691;
152
13.1k
    pj_gn_sinu_setup(P);
153
154
13.1k
    return P;
155
13.1k
}
156
157
3.81k
PJ *PJ_PROJECTION(mbtfps) {
158
3.81k
    struct pj_gn_sinu_data *Q = static_cast<struct pj_gn_sinu_data *>(
159
3.81k
        calloc(1, sizeof(struct pj_gn_sinu_data)));
160
3.81k
    if (nullptr == Q)
161
0
        return pj_default_destructor(P, PROJ_ERR_OTHER /*ENOMEM*/);
162
3.81k
    P->opaque = Q;
163
3.81k
    P->destructor = pj_gn_sinu_destructor;
164
165
3.81k
    Q->m = 0.5;
166
3.81k
    Q->n = 1.785398163397448309615660845;
167
3.81k
    pj_gn_sinu_setup(P);
168
169
3.81k
    return P;
170
3.81k
}
171
172
1.49k
PJ *PJ_PROJECTION(gn_sinu) {
173
1.49k
    struct pj_gn_sinu_data *Q = static_cast<struct pj_gn_sinu_data *>(
174
1.49k
        calloc(1, sizeof(struct pj_gn_sinu_data)));
175
1.49k
    if (nullptr == Q)
176
0
        return pj_default_destructor(P, PROJ_ERR_OTHER /*ENOMEM*/);
177
1.49k
    P->opaque = Q;
178
1.49k
    P->destructor = pj_gn_sinu_destructor;
179
180
1.49k
    if (!pj_param(P->ctx, P->params, "tn").i) {
181
687
        proj_log_error(P, _("Missing parameter n."));
182
687
        return pj_default_destructor(P, PROJ_ERR_INVALID_OP_MISSING_ARG);
183
687
    }
184
803
    if (!pj_param(P->ctx, P->params, "tm").i) {
185
410
        proj_log_error(P, _("Missing parameter m."));
186
410
        return pj_default_destructor(P, PROJ_ERR_INVALID_OP_MISSING_ARG);
187
410
    }
188
189
393
    Q->n = pj_param(P->ctx, P->params, "dn").f;
190
393
    Q->m = pj_param(P->ctx, P->params, "dm").f;
191
393
    if (Q->n <= 0) {
192
104
        proj_log_error(P, _("Invalid value for n: it should be > 0."));
193
104
        return pj_default_destructor(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
194
104
    }
195
289
    if (Q->m < 0) {
196
0
        proj_log_error(P, _("Invalid value for m: it should be >= 0."));
197
0
        return pj_default_destructor(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
198
0
    }
199
200
289
    pj_gn_sinu_setup(P);
201
202
289
    return P;
203
289
}