Coverage Report

Created: 2026-07-14 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PROJ/src/projections/bipc.cpp
Line
Count
Source
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
2.60k
#define EPS10 1e-10
13
0
#define ONEEPS 1.000000001
14
0
#define NITER 10
15
2.60k
#define lamB -.34894976726250681539
16
7.81k
#define n .63055844881274687180
17
2.60k
#define F 1.89724742567461030582
18
183
#define Azab .81650043674686363166
19
5.02k
#define Azba 1.82261843856185925133
20
2.60k
#define T 1.27246578267089012270
21
2.60k
#define rhoc 1.20709121521568721927
22
0
#define cAzc .69691523038678375519
23
0
#define sAzc .71715351331143607555
24
2.60k
#define C45 .70710678118654752469
25
2.42k
#define S45 .70710678118654752410
26
366
#define C20 .93969262078590838411
27
366
#define S20 -.34202014332566873287
28
183
#define R110 1.91986217719376253360
29
2.60k
#define R104 1.81514242207410275904
30
31
namespace { // anonymous namespace
32
struct pj_bipc_data {
33
    int noskew;
34
};
35
} // anonymous namespace
36
37
2.60k
static PJ_XY bipc_s_forward(PJ_LP lp, PJ *P) { /* Spheroidal, forward */
38
2.60k
    PJ_XY xy = {0.0, 0.0};
39
2.60k
    struct pj_bipc_data *Q = static_cast<struct pj_bipc_data *>(P->opaque);
40
2.60k
    double cphi, sphi, tphi, t, al, Az, z, Av, cdlam, sdlam, r;
41
2.60k
    int tag;
42
43
2.60k
    cphi = cos(lp.phi);
44
2.60k
    sphi = sin(lp.phi);
45
2.60k
    cdlam = cos(sdlam = lamB - lp.lam);
46
2.60k
    sdlam = sin(sdlam);
47
2.60k
    if (fabs(fabs(lp.phi) - M_HALFPI) < EPS10) {
48
0
        Az = lp.phi < 0. ? M_PI : 0.;
49
0
        tphi = HUGE_VAL;
50
2.60k
    } else {
51
2.60k
        tphi = sphi / cphi;
52
2.60k
        Az = atan2(sdlam, C45 * (tphi - cdlam));
53
2.60k
    }
54
2.60k
    if ((tag = (Az > Azba))) {
55
183
        sdlam = lp.lam + R110;
56
183
        cdlam = cos(sdlam);
57
183
        sdlam = sin(sdlam);
58
183
        z = S20 * sphi + C20 * cphi * cdlam;
59
183
        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
183
            z = acos(z);
68
183
        if (tphi != HUGE_VAL)
69
183
            Az = atan2(sdlam, (C20 * tphi - S20 * cdlam));
70
183
        Av = Azab;
71
183
        xy.y = rhoc;
72
2.42k
    } else {
73
2.42k
        z = S45 * (sphi + cphi * cdlam);
74
2.42k
        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
2.42k
            z = acos(z);
83
2.42k
        Av = Azba;
84
2.42k
        xy.y = -rhoc;
85
2.42k
    }
86
2.60k
    if (z < 0.) {
87
0
        proj_errno_set(P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN);
88
0
        return xy;
89
0
    }
90
2.60k
    t = pow(tan(.5 * z), n);
91
2.60k
    r = F * t;
92
2.60k
    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
2.60k
    al = (t + pow(al, n)) / T;
97
2.60k
    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
2.60k
        al = acos(al);
105
2.60k
    t = n * (Av - Az);
106
2.60k
    if (fabs(t) < al)
107
916
        r /= cos(al + (tag ? t : -t));
108
2.60k
    xy.x = r * sin(t);
109
2.60k
    xy.y += (tag ? -r : r) * cos(t);
110
2.60k
    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
2.60k
    return (xy);
116
2.60k
}
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
70
PJ *PJ_PROJECTION(bipc) {
168
70
    struct pj_bipc_data *Q = static_cast<struct pj_bipc_data *>(
169
70
        calloc(1, sizeof(struct pj_bipc_data)));
170
70
    if (nullptr == Q)
171
0
        return pj_default_destructor(P, PROJ_ERR_OTHER /*ENOMEM*/);
172
70
    P->opaque = Q;
173
174
70
    Q->noskew = pj_param(P->ctx, P->params, "bns").i;
175
70
    P->inv = bipc_s_inverse;
176
70
    P->fwd = bipc_s_forward;
177
70
    P->es = 0.;
178
70
    return P;
179
70
}
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