Coverage Report

Created: 2025-07-23 06:58

/src/PROJ/src/projections/lagrng.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
8
PROJ_HEAD(lagrng, "Lagrange") "\n\tMisc Sph\n\tW=";
9
10
30.4k
#define TOL 1e-10
11
12
namespace { // anonymous namespace
13
struct pj_lagrng {
14
    double a1;
15
    double a2;
16
    double hrw;
17
    double hw;
18
    double rw;
19
    double w;
20
};
21
} // anonymous namespace
22
23
15.1k
static PJ_XY lagrng_s_forward(PJ_LP lp, PJ *P) { /* Spheroidal, forward */
24
15.1k
    PJ_XY xy = {0.0, 0.0};
25
15.1k
    struct pj_lagrng *Q = static_cast<struct pj_lagrng *>(P->opaque);
26
15.1k
    double v, c;
27
28
15.1k
    const double sin_phi = sin(lp.phi);
29
15.1k
    if (fabs(fabs(sin_phi) - 1) < TOL) {
30
0
        xy.x = 0;
31
0
        xy.y = lp.phi < 0 ? -2. : 2.;
32
15.1k
    } else {
33
15.1k
        v = Q->a1 * pow((1. + sin_phi) / (1. - sin_phi), Q->hrw);
34
15.1k
        lp.lam *= Q->rw;
35
15.1k
        c = 0.5 * (v + 1. / v) + cos(lp.lam);
36
15.1k
        if (c < TOL) {
37
0
            proj_errno_set(P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN);
38
0
            return xy;
39
0
        }
40
15.1k
        xy.x = 2. * sin(lp.lam) / c;
41
15.1k
        xy.y = (v - 1. / v) / c;
42
15.1k
    }
43
15.1k
    return xy;
44
15.1k
}
45
46
0
static PJ_LP lagrng_s_inverse(PJ_XY xy, PJ *P) { /* Spheroidal, inverse */
47
0
    PJ_LP lp = {0.0, 0.0};
48
0
    struct pj_lagrng *Q = static_cast<struct pj_lagrng *>(P->opaque);
49
0
    double c, x2, y2p, y2m;
50
51
0
    if (fabs(fabs(xy.y) - 2.) < TOL) {
52
0
        lp.phi = xy.y < 0 ? -M_HALFPI : M_HALFPI;
53
0
        lp.lam = 0;
54
0
    } else {
55
0
        x2 = xy.x * xy.x;
56
0
        y2p = 2. + xy.y;
57
0
        y2m = 2. - xy.y;
58
0
        c = y2p * y2m - x2;
59
0
        if (fabs(c) < TOL) {
60
0
            proj_errno_set(P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN);
61
0
            return lp;
62
0
        }
63
0
        lp.phi = 2. * atan(pow((y2p * y2p + x2) / (Q->a2 * (y2m * y2m + x2)),
64
0
                               Q->hw)) -
65
0
                 M_HALFPI;
66
0
        lp.lam = Q->w * atan2(4. * xy.x, c);
67
0
    }
68
0
    return lp;
69
0
}
70
71
214
PJ *PJ_PROJECTION(lagrng) {
72
214
    double sin_phi1;
73
214
    struct pj_lagrng *Q =
74
214
        static_cast<struct pj_lagrng *>(calloc(1, sizeof(struct pj_lagrng)));
75
214
    if (nullptr == Q)
76
0
        return pj_default_destructor(P, PROJ_ERR_OTHER /*ENOMEM*/);
77
214
    P->opaque = Q;
78
79
214
    if (pj_param(P->ctx, P->params, "tW").i)
80
0
        Q->w = pj_param(P->ctx, P->params, "dW").f;
81
214
    else
82
214
        Q->w = 2;
83
214
    if (Q->w <= 0) {
84
0
        proj_log_error(P, _("Invalid value for W: it should be > 0"));
85
0
        return pj_default_destructor(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
86
0
    }
87
214
    Q->hw = 0.5 * Q->w;
88
214
    Q->rw = 1. / Q->w;
89
214
    Q->hrw = 0.5 * Q->rw;
90
214
    sin_phi1 = sin(pj_param(P->ctx, P->params, "rlat_1").f);
91
214
    if (fabs(fabs(sin_phi1) - 1.) < TOL) {
92
0
        proj_log_error(P,
93
0
                       _("Invalid value for lat_1: |lat_1| should be < 90°"));
94
0
        return pj_default_destructor(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE);
95
0
    }
96
97
214
    Q->a1 = pow((1. - sin_phi1) / (1. + sin_phi1), Q->hrw);
98
214
    Q->a2 = Q->a1 * Q->a1;
99
100
214
    P->es = 0.;
101
214
    P->inv = lagrng_s_inverse;
102
214
    P->fwd = lagrng_s_forward;
103
104
214
    return P;
105
214
}