Coverage Report

Created: 2025-06-13 06:29

/src/proj/src/projections/bipc.cpp
Line
Count
Source (jump to first uncovered line)
1
2
#include <errno.h>
3
#include <math.h>
4
5
#include "proj.h"
6
#include "proj_internal.h"
7
#include <math.h>
8
9
PROJ_HEAD(bipc, "Bipolar conic of western hemisphere") "\n\tConic Sph";
10
11
0
#define EPS 1e-10
12
0
#define EPS10 1e-10
13
0
#define ONEEPS 1.000000001
14
0
#define NITER 10
15
0
#define lamB -.34894976726250681539
16
0
#define n .63055844881274687180
17
0
#define F 1.89724742567461030582
18
0
#define Azab .81650043674686363166
19
0
#define Azba 1.82261843856185925133
20
0
#define T 1.27246578267089012270
21
0
#define rhoc 1.20709121521568721927
22
0
#define cAzc .69691523038678375519
23
0
#define sAzc .71715351331143607555
24
0
#define C45 .70710678118654752469
25
0
#define S45 .70710678118654752410
26
0
#define C20 .93969262078590838411
27
0
#define S20 -.34202014332566873287
28
0
#define R110 1.91986217719376253360
29
0
#define R104 1.81514242207410275904
30
31
namespace { // anonymous namespace
32
struct pj_bipc_data {
33
    int noskew;
34
};
35
} // anonymous namespace
36
37
0
static PJ_XY bipc_s_forward(PJ_LP lp, PJ *P) { /* Spheroidal, forward */
38
0
    PJ_XY xy = {0.0, 0.0};
39
0
    struct pj_bipc_data *Q = static_cast<struct pj_bipc_data *>(P->opaque);
40
0
    double cphi, sphi, tphi, t, al, Az, z, Av, cdlam, sdlam, r;
41
0
    int tag;
42
43
0
    cphi = cos(lp.phi);
44
0
    sphi = sin(lp.phi);
45
0
    cdlam = cos(sdlam = lamB - lp.lam);
46
0
    sdlam = sin(sdlam);
47
0
    if (fabs(fabs(lp.phi) - M_HALFPI) < EPS10) {
48
0
        Az = lp.phi < 0. ? M_PI : 0.;
49
0
        tphi = HUGE_VAL;
50
0
    } else {
51
0
        tphi = sphi / cphi;
52
0
        Az = atan2(sdlam, C45 * (tphi - cdlam));
53
0
    }
54
0
    if ((tag = (Az > Azba))) {
55
0
        sdlam = lp.lam + R110;
56
0
        cdlam = cos(sdlam);
57
0
        sdlam = sin(sdlam);
58
0
        z = S20 * sphi + C20 * cphi * cdlam;
59
0
        if (fabs(z) > 1.) {
60
0
            if (fabs(z) > ONEEPS) {
61
0
                proj_errno_set(
62
0
                    P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN);
63
0
                return xy;
64
0
            } else
65
0
                z = z < 0. ? -1. : 1.;
66
0
        } else
67
0
            z = acos(z);
68
0
        if (tphi != HUGE_VAL)
69
0
            Az = atan2(sdlam, (C20 * tphi - S20 * cdlam));
70
0
        Av = Azab;
71
0
        xy.y = rhoc;
72
0
    } else {
73
0
        z = S45 * (sphi + cphi * cdlam);
74
0
        if (fabs(z) > 1.) {
75
0
            if (fabs(z) > ONEEPS) {
76
0
                proj_errno_set(
77
0
                    P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN);
78
0
                return xy;
79
0
            } else
80
0
                z = z < 0. ? -1. : 1.;
81
0
        } else
82
0
            z = acos(z);
83
0
        Av = Azba;
84
0
        xy.y = -rhoc;
85
0
    }
86
0
    if (z < 0.) {
87
0
        proj_errno_set(P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN);
88
0
        return xy;
89
0
    }
90
0
    t = pow(tan(.5 * z), n);
91
0
    r = F * t;
92
0
    if ((al = .5 * (R104 - z)) < 0.) {
93
0
        proj_errno_set(P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN);
94
0
        return xy;
95
0
    }
96
0
    al = (t + pow(al, n)) / T;
97
0
    if (fabs(al) > 1.) {
98
0
        if (fabs(al) > ONEEPS) {
99
0
            proj_errno_set(P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN);
100
0
            return xy;
101
0
        } else
102
0
            al = al < 0. ? -1. : 1.;
103
0
    } else
104
0
        al = acos(al);
105
0
    t = n * (Av - Az);
106
0
    if (fabs(t) < al)
107
0
        r /= cos(al + (tag ? t : -t));
108
0
    xy.x = r * sin(t);
109
0
    xy.y += (tag ? -r : r) * cos(t);
110
0
    if (Q->noskew) {
111
0
        t = xy.x;
112
0
        xy.x = -xy.x * cAzc - xy.y * sAzc;
113
0
        xy.y = -xy.y * cAzc + t * sAzc;
114
0
    }
115
0
    return (xy);
116
0
}
117
118
0
static PJ_LP bipc_s_inverse(PJ_XY xy, PJ *P) { /* Spheroidal, inverse */
119
0
    PJ_LP lp = {0.0, 0.0};
120
0
    struct pj_bipc_data *Q = static_cast<struct pj_bipc_data *>(P->opaque);
121
0
    double t, r, rp, rl, al, z = 0.0, fAz, Az, s, c, Av;
122
0
    int neg, i;
123
124
0
    if (Q->noskew) {
125
0
        t = xy.x;
126
0
        xy.x = -xy.x * cAzc + xy.y * sAzc;
127
0
        xy.y = -xy.y * cAzc - t * sAzc;
128
0
    }
129
0
    if ((neg = (xy.x < 0.))) {
130
0
        xy.y = rhoc - xy.y;
131
0
        s = S20;
132
0
        c = C20;
133
0
        Av = Azab;
134
0
    } else {
135
0
        xy.y += rhoc;
136
0
        s = S45;
137
0
        c = C45;
138
0
        Av = Azba;
139
0
    }
140
0
    r = hypot(xy.x, xy.y);
141
0
    rl = rp = r;
142
0
    Az = atan2(xy.x, xy.y);
143
0
    fAz = fabs(Az);
144
0
    for (i = NITER; i; --i) {
145
0
        z = 2. * atan(pow(r / F, 1 / n));
146
0
        al = acos((pow(tan(.5 * z), n) + pow(tan(.5 * (R104 - z)), n)) / T);
147
0
        if (fAz < al)
148
0
            r = rp * cos(al + (neg ? Az : -Az));
149
0
        if (fabs(rl - r) < EPS)
150
0
            break;
151
0
        rl = r;
152
0
    }
153
0
    if (!i) {
154
0
        proj_errno_set(P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN);
155
0
        return lp;
156
0
    }
157
0
    Az = Av - Az / n;
158
0
    lp.phi = asin(s * cos(z) + c * sin(z) * cos(Az));
159
0
    lp.lam = atan2(sin(Az), c / tan(z) - s * cos(Az));
160
0
    if (neg)
161
0
        lp.lam -= R110;
162
0
    else
163
0
        lp.lam = lamB - lp.lam;
164
0
    return (lp);
165
0
}
166
167
226
PJ *PJ_PROJECTION(bipc) {
168
226
    struct pj_bipc_data *Q = static_cast<struct pj_bipc_data *>(
169
226
        calloc(1, sizeof(struct pj_bipc_data)));
170
226
    if (nullptr == Q)
171
0
        return pj_default_destructor(P, PROJ_ERR_OTHER /*ENOMEM*/);
172
226
    P->opaque = Q;
173
174
226
    Q->noskew = pj_param(P->ctx, P->params, "bns").i;
175
226
    P->inv = bipc_s_inverse;
176
226
    P->fwd = bipc_s_forward;
177
226
    P->es = 0.;
178
226
    return P;
179
226
}
180
181
#undef EPS
182
#undef EPS10
183
#undef ONEEPS
184
#undef NITER
185
#undef lamB
186
#undef n
187
#undef F
188
#undef Azab
189
#undef Azba
190
#undef T
191
#undef rhoc
192
#undef cAzc
193
#undef sAzc
194
#undef C45
195
#undef S45
196
#undef C20
197
#undef S20
198
#undef R110
199
#undef R104