Coverage Report

Created: 2026-02-03 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PROJ/src/projections/bonne.cpp
Line
Count
Source
1
2
#include "proj.h"
3
#include "proj_internal.h"
4
#include <errno.h>
5
#include <math.h>
6
7
PROJ_HEAD(bonne, "Bonne (Werner lat_1=90)")
8
"\n\tConic Sph&Ell\n\tlat_1=";
9
137
#define EPS10 1e-10
10
11
namespace { // anonymous namespace
12
struct pj_bonne_data {
13
    double phi1;
14
    double cphi1;
15
    double am1;
16
    double m1;
17
    double *en;
18
};
19
} // anonymous namespace
20
21
0
static PJ_XY bonne_e_forward(PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */
22
0
    PJ_XY xy = {0.0, 0.0};
23
0
    struct pj_bonne_data *Q = static_cast<struct pj_bonne_data *>(P->opaque);
24
0
    double rh, E, c;
25
26
0
    E = sin(lp.phi);
27
0
    c = cos(lp.phi);
28
0
    rh = Q->am1 + Q->m1 - pj_mlfn(lp.phi, E, c, Q->en);
29
0
    if (fabs(rh) > EPS10) {
30
0
        E = c * lp.lam / (rh * sqrt(1. - P->es * E * E));
31
0
        xy.x = rh * sin(E);
32
0
        xy.y = Q->am1 - rh * cos(E);
33
0
    } else {
34
0
        xy.x = 0.;
35
0
        xy.y = 0.;
36
0
    }
37
0
    return xy;
38
0
}
39
40
0
static PJ_XY bonne_s_forward(PJ_LP lp, PJ *P) { /* Spheroidal, forward */
41
0
    PJ_XY xy = {0.0, 0.0};
42
0
    struct pj_bonne_data *Q = static_cast<struct pj_bonne_data *>(P->opaque);
43
0
    double E, rh;
44
45
0
    rh = Q->cphi1 + Q->phi1 - lp.phi;
46
0
    if (fabs(rh) > EPS10) {
47
0
        E = lp.lam * cos(lp.phi) / rh;
48
0
        xy.x = rh * sin(E);
49
0
        xy.y = Q->cphi1 - rh * cos(E);
50
0
    } else
51
0
        xy.x = xy.y = 0.;
52
0
    return xy;
53
0
}
54
55
0
static PJ_LP bonne_s_inverse(PJ_XY xy, PJ *P) { /* Spheroidal, inverse */
56
0
    PJ_LP lp = {0.0, 0.0};
57
0
    struct pj_bonne_data *Q = static_cast<struct pj_bonne_data *>(P->opaque);
58
59
0
    xy.y = Q->cphi1 - xy.y;
60
0
    const double rh = copysign(hypot(xy.x, xy.y), Q->phi1);
61
0
    lp.phi = Q->cphi1 + Q->phi1 - rh;
62
0
    const double abs_phi = fabs(lp.phi);
63
0
    if (abs_phi > M_HALFPI) {
64
0
        proj_errno_set(P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN);
65
0
        return lp;
66
0
    }
67
0
    if (M_HALFPI - abs_phi <= EPS10)
68
0
        lp.lam = 0.;
69
0
    else {
70
0
        const double lm = rh / cos(lp.phi);
71
0
        if (Q->phi1 > 0) {
72
0
            lp.lam = lm * atan2(xy.x, xy.y);
73
0
        } else {
74
0
            lp.lam = lm * atan2(-xy.x, -xy.y);
75
0
        }
76
0
    }
77
0
    return lp;
78
0
}
79
80
0
static PJ_LP bonne_e_inverse(PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */
81
0
    PJ_LP lp = {0.0, 0.0};
82
0
    struct pj_bonne_data *Q = static_cast<struct pj_bonne_data *>(P->opaque);
83
84
0
    xy.y = Q->am1 - xy.y;
85
0
    const double rh = copysign(hypot(xy.x, xy.y), Q->phi1);
86
0
    lp.phi = pj_inv_mlfn(Q->am1 + Q->m1 - rh, Q->en);
87
0
    const double abs_phi = fabs(lp.phi);
88
0
    if (abs_phi < M_HALFPI) {
89
0
        const double sinphi = sin(lp.phi);
90
0
        const double lm = rh * sqrt(1. - P->es * sinphi * sinphi) / cos(lp.phi);
91
0
        if (Q->phi1 > 0) {
92
0
            lp.lam = lm * atan2(xy.x, xy.y);
93
0
        } else {
94
0
            lp.lam = lm * atan2(-xy.x, -xy.y);
95
0
        }
96
0
    } else if (abs_phi - M_HALFPI <= EPS10)
97
0
        lp.lam = 0.;
98
0
    else {
99
0
        proj_errno_set(P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN);
100
0
        return lp;
101
0
    }
102
0
    return lp;
103
0
}
104
105
83
static PJ *pj_bonne_destructor(PJ *P, int errlev) { /* Destructor */
106
83
    if (nullptr == P)
107
0
        return nullptr;
108
109
83
    if (nullptr == P->opaque)
110
0
        return pj_default_destructor(P, errlev);
111
112
83
    free(static_cast<struct pj_bonne_data *>(P->opaque)->en);
113
83
    return pj_default_destructor(P, errlev);
114
83
}
115
116
83
PJ *PJ_PROJECTION(bonne) {
117
83
    double c;
118
83
    struct pj_bonne_data *Q = static_cast<struct pj_bonne_data *>(
119
83
        calloc(1, sizeof(struct pj_bonne_data)));
120
83
    if (nullptr == Q)
121
0
        return pj_default_destructor(P, PROJ_ERR_OTHER /*ENOMEM*/);
122
83
    P->opaque = Q;
123
83
    P->destructor = pj_bonne_destructor;
124
125
83
    Q->phi1 = pj_param(P->ctx, P->params, "rlat_1").f;
126
83
    if (fabs(Q->phi1) < EPS10) {
127
5
        proj_log_error(P, _("Invalid value for lat_1: |lat_1| should be > 0"));
128
5
        return pj_bonne_destructor(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
129
5
    }
130
131
78
    if (P->es != 0.0) {
132
24
        Q->en = pj_enfn(P->n);
133
24
        if (nullptr == Q->en)
134
0
            return pj_bonne_destructor(P, PROJ_ERR_OTHER /*ENOMEM*/);
135
24
        Q->am1 = sin(Q->phi1);
136
24
        c = cos(Q->phi1);
137
24
        Q->m1 = pj_mlfn(Q->phi1, Q->am1, c, Q->en);
138
24
        Q->am1 = c / (sqrt(1. - P->es * Q->am1 * Q->am1) * Q->am1);
139
24
        P->inv = bonne_e_inverse;
140
24
        P->fwd = bonne_e_forward;
141
54
    } else {
142
54
        if (fabs(Q->phi1) + EPS10 >= M_HALFPI)
143
43
            Q->cphi1 = 0.;
144
11
        else
145
11
            Q->cphi1 = 1. / tan(Q->phi1);
146
54
        P->inv = bonne_s_inverse;
147
54
        P->fwd = bonne_s_forward;
148
54
    }
149
78
    return P;
150
78
}
151
152
#undef EPS10