Coverage Report

Created: 2025-06-13 06:18

/src/proj/src/projections/labrd.cpp
Line
Count
Source (jump to first uncovered line)
1
2
3
#include <errno.h>
4
#include <math.h>
5
6
#include "proj.h"
7
#include "proj_internal.h"
8
9
PROJ_HEAD(labrd, "Laborde") "\n\tCyl, Sph\n\tSpecial for Madagascar\n\tlat_0=";
10
0
#define EPS 1.e-10
11
12
namespace { // anonymous namespace
13
struct pj_opaque {
14
    double kRg, p0s, A, C, Ca, Cb, Cc, Cd;
15
};
16
} // anonymous namespace
17
18
0
static PJ_XY labrd_e_forward(PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */
19
0
    PJ_XY xy = {0.0, 0.0};
20
0
    struct pj_opaque *Q = static_cast<struct pj_opaque *>(P->opaque);
21
0
    double V1, V2, ps, sinps, cosps, sinps2, cosps2;
22
0
    double I1, I2, I3, I4, I5, I6, x2, y2, t;
23
24
0
    V1 = Q->A * log(tan(M_FORTPI + .5 * lp.phi));
25
0
    t = P->e * sin(lp.phi);
26
0
    V2 = .5 * P->e * Q->A * log((1. + t) / (1. - t));
27
0
    ps = 2. * (atan(exp(V1 - V2 + Q->C)) - M_FORTPI);
28
0
    I1 = ps - Q->p0s;
29
0
    cosps = cos(ps);
30
0
    cosps2 = cosps * cosps;
31
0
    sinps = sin(ps);
32
0
    sinps2 = sinps * sinps;
33
0
    I4 = Q->A * cosps;
34
0
    I2 = .5 * Q->A * I4 * sinps;
35
0
    I3 = I2 * Q->A * Q->A * (5. * cosps2 - sinps2) / 12.;
36
0
    I6 = I4 * Q->A * Q->A;
37
0
    I5 = I6 * (cosps2 - sinps2) / 6.;
38
0
    I6 *= Q->A * Q->A *
39
0
          (5. * cosps2 * cosps2 + sinps2 * (sinps2 - 18. * cosps2)) / 120.;
40
0
    t = lp.lam * lp.lam;
41
0
    xy.x = Q->kRg * lp.lam * (I4 + t * (I5 + t * I6));
42
0
    xy.y = Q->kRg * (I1 + t * (I2 + t * I3));
43
0
    x2 = xy.x * xy.x;
44
0
    y2 = xy.y * xy.y;
45
0
    V1 = 3. * xy.x * y2 - xy.x * x2;
46
0
    V2 = xy.y * y2 - 3. * x2 * xy.y;
47
0
    xy.x += Q->Ca * V1 + Q->Cb * V2;
48
0
    xy.y += Q->Ca * V2 - Q->Cb * V1;
49
0
    return xy;
50
0
}
51
52
0
static PJ_LP labrd_e_inverse(PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */
53
0
    PJ_LP lp = {0.0, 0.0};
54
0
    struct pj_opaque *Q = static_cast<struct pj_opaque *>(P->opaque);
55
    /* t = 0.0 optimization is to avoid a false positive cppcheck warning */
56
    /* (cppcheck git beaf29c15867984aa3c2a15cf15bd7576ccde2b3). Might no */
57
    /* longer be necessary with later versions. */
58
0
    double x2, y2, V1, V2, V3, V4, t = 0.0, t2, ps, pe, tpe, s;
59
0
    double I7, I8, I9, I10, I11, d, Re;
60
0
    int i;
61
62
0
    x2 = xy.x * xy.x;
63
0
    y2 = xy.y * xy.y;
64
0
    V1 = 3. * xy.x * y2 - xy.x * x2;
65
0
    V2 = xy.y * y2 - 3. * x2 * xy.y;
66
0
    V3 = xy.x * (5. * y2 * y2 + x2 * (-10. * y2 + x2));
67
0
    V4 = xy.y * (5. * x2 * x2 + y2 * (-10. * x2 + y2));
68
0
    xy.x += -Q->Ca * V1 - Q->Cb * V2 + Q->Cc * V3 + Q->Cd * V4;
69
0
    xy.y += Q->Cb * V1 - Q->Ca * V2 - Q->Cd * V3 + Q->Cc * V4;
70
0
    ps = Q->p0s + xy.y / Q->kRg;
71
0
    pe = ps + P->phi0 - Q->p0s;
72
73
0
    for (i = 20; i; --i) {
74
0
        V1 = Q->A * log(tan(M_FORTPI + .5 * pe));
75
0
        tpe = P->e * sin(pe);
76
0
        V2 = .5 * P->e * Q->A * log((1. + tpe) / (1. - tpe));
77
0
        t = ps - 2. * (atan(exp(V1 - V2 + Q->C)) - M_FORTPI);
78
0
        pe += t;
79
0
        if (fabs(t) < EPS)
80
0
            break;
81
0
    }
82
83
0
    t = P->e * sin(pe);
84
0
    t = 1. - t * t;
85
0
    Re = P->one_es / (t * sqrt(t));
86
0
    t = tan(ps);
87
0
    t2 = t * t;
88
0
    s = Q->kRg * Q->kRg;
89
0
    d = Re * P->k0 * Q->kRg;
90
0
    I7 = t / (2. * d);
91
0
    I8 = t * (5. + 3. * t2) / (24. * d * s);
92
0
    d = cos(ps) * Q->kRg * Q->A;
93
0
    I9 = 1. / d;
94
0
    d *= s;
95
0
    I10 = (1. + 2. * t2) / (6. * d);
96
0
    I11 = (5. + t2 * (28. + 24. * t2)) / (120. * d * s);
97
0
    x2 = xy.x * xy.x;
98
0
    lp.phi = pe + x2 * (-I7 + I8 * x2);
99
0
    lp.lam = xy.x * (I9 + x2 * (-I10 + x2 * I11));
100
0
    return lp;
101
0
}
102
103
0
PJ *PJ_PROJECTION(labrd) {
104
0
    double Az, sinp, R, N, t;
105
0
    struct pj_opaque *Q =
106
0
        static_cast<struct pj_opaque *>(calloc(1, sizeof(struct pj_opaque)));
107
0
    if (nullptr == Q)
108
0
        return pj_default_destructor(P, PROJ_ERR_OTHER /*ENOMEM*/);
109
0
    P->opaque = Q;
110
111
0
    if (P->phi0 == 0.) {
112
0
        proj_log_error(
113
0
            P, _("Invalid value for lat_0: lat_0 should be different from 0"));
114
0
        return pj_default_destructor(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
115
0
    }
116
117
0
    Az = pj_param(P->ctx, P->params, "razi").f;
118
0
    sinp = sin(P->phi0);
119
0
    t = 1. - P->es * sinp * sinp;
120
0
    N = 1. / sqrt(t);
121
0
    R = P->one_es * N / t;
122
0
    Q->kRg = P->k0 * sqrt(N * R);
123
0
    Q->p0s = atan(sqrt(R / N) * tan(P->phi0));
124
0
    Q->A = sinp / sin(Q->p0s);
125
0
    t = P->e * sinp;
126
0
    Q->C = .5 * P->e * Q->A * log((1. + t) / (1. - t)) +
127
0
           -Q->A * log(tan(M_FORTPI + .5 * P->phi0)) +
128
0
           log(tan(M_FORTPI + .5 * Q->p0s));
129
0
    t = Az + Az;
130
0
    Q->Cb = 1. / (12. * Q->kRg * Q->kRg);
131
0
    Q->Ca = (1. - cos(t)) * Q->Cb;
132
0
    Q->Cb *= sin(t);
133
0
    Q->Cc = 3. * (Q->Ca * Q->Ca - Q->Cb * Q->Cb);
134
0
    Q->Cd = 6. * Q->Ca * Q->Cb;
135
136
0
    P->inv = labrd_e_inverse;
137
0
    P->fwd = labrd_e_forward;
138
139
0
    return P;
140
0
}