Coverage Report

Created: 2026-10-17 06:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PROJ/src/latitudes.cpp
Line
Count
Source
1
/*
2
 * Project:  PROJ
3
 *
4
 * Helper functions to compute latitudes
5
 *
6
 * Some from Map Projections - A Working Manual. 1987. John P. Snyder
7
 * https://neacsu.net/docs/geodesy/snyder/2-general/sect_3/
8
 *
9
 * Copyright (c) 2025 Javier Jimenez Shaw
10
 */
11
12
#include <exception>
13
#include <math.h>
14
15
#include "proj_internal.h"
16
17
/*****************************************************************************/
18
10
double pj_conformal_lat(double phi, const PJ *P) {
19
    /***********************************
20
     * The conformal latitude chi, in terms of the geodetic latitude, phi.
21
     *
22
     * phi: geodetic latitude, in radians
23
     * returns: conformal latitude, chi, in radians
24
     * Copied from merc.cpp
25
     ***********************************/
26
10
    if (P->e == 0.0)
27
1
        return phi;
28
29
    // Instead of calling tan and sin, call sin and cos which the compiler
30
    // optimizes to a single call to sincos.
31
9
    double sphi = sin(phi), cphi = cos(phi);
32
9
    return atan(sinh(asinh(sphi / cphi) - P->e * atanh(P->e * sphi)));
33
10
}
34
35
/*****************************************************************************/
36
0
double pj_conformal_lat_inverse(double chi, const PJ *P) {
37
    /***********************************
38
     * The geodetic latitude, phi, in terms of the conformal latitude, chi.
39
     *
40
     * chi: conformal latitude, in radians
41
     * returns: geodetic latitude, phi, in radians
42
     * Copied from merc.cpp
43
     ***********************************/
44
0
    if (P->e == 0.0)
45
0
        return chi;
46
47
0
    return atan(pj_sinhpsi2tanphi(P->ctx, tan(chi), P->e));
48
0
}
49
50
/*****************************************************************************/
51
52
// Computes coefficient q such that authalic_latitude = beta = asin(q / qp)
53
// where qp is q at phi=90deg, i.e. qp = pj_authalic_lat_q(1, e, one_es)
54
// Cf  Snyder (3-11) and (3-12)
55
20.7k
double pj_authalic_lat_q(double sinphi, const PJ *P) {
56
20.7k
    constexpr double EPSILON = 1e-7;
57
20.7k
    if (P->e >= EPSILON) {
58
20.7k
        const double e_sinphi = P->e * sinphi;
59
20.7k
        const double one_minus_e_sinphi_sq = 1.0 - e_sinphi * e_sinphi;
60
61
        /* avoid zero division, fail gracefully */
62
20.7k
        if (one_minus_e_sinphi_sq == 0.0)
63
0
            return HUGE_VAL;
64
65
        // Snyder uses 0.5 * ln((1-e*sinphi)/(1+e*sinphi) which is
66
        // -atanh(e*sinphi)
67
20.7k
        return P->one_es *
68
20.7k
               (sinphi / one_minus_e_sinphi_sq + atanh(e_sinphi) / P->e);
69
20.7k
    } else
70
0
        return 2 * sinphi;
71
20.7k
}
72
73
/*****************************************************************************/
74
75
// Computes coefficients needed for conversions between geographic and authalic
76
// latitude.  These are preferred over the analytical expressions for |n| <
77
// 0.01.  However the inverse series is used to start the inverse method for
78
// large |n|.
79
80
// Ensure we use the cutoff in n consistently
81
33.4k
#define PROJ_AUTHALIC_SERIES_VALID(n) (fabs(n) < 0.01)
82
1.58k
double *pj_authalic_lat_compute_coeffs(double n) {
83
1.58k
    double *APA;
84
1.58k
    constexpr int Lmax = int(AuxLat::ORDER);
85
1.58k
    const int APA_SIZE = Lmax * (PROJ_AUTHALIC_SERIES_VALID(n) ? 2 : 1);
86
1.58k
    if ((APA = (double *)malloc(APA_SIZE * sizeof(double))) != nullptr) {
87
1.58k
        pj_auxlat_coeffs(n, AuxLat::AUTHALIC, AuxLat::GEOGRAPHIC, APA);
88
1.58k
        if (PROJ_AUTHALIC_SERIES_VALID(n))
89
1.54k
            pj_auxlat_coeffs(n, AuxLat::GEOGRAPHIC, AuxLat::AUTHALIC,
90
1.54k
                             APA + Lmax);
91
1.58k
    }
92
1.58k
    return APA;
93
1.58k
}
94
95
/*****************************************************************************/
96
97
// Computes authalic latitude from the geographic latitude.
98
// qp is q at phi=90deg, i.e. qp = pj_authalic_lat_q(1, e, one_es)
99
double pj_authalic_lat(double phi, double sinphi, double cosphi,
100
30.2k
                       const double *APA, const PJ *P, double qp) {
101
30.2k
    if (PROJ_AUTHALIC_SERIES_VALID(P->n)) {
102
29.0k
        constexpr int Lmax = int(AuxLat::ORDER);
103
29.0k
        return pj_auxlat_convert(phi, sinphi, cosphi, APA + Lmax);
104
29.0k
    } else {
105
        // This result is ill-conditioned near the poles.  So don't use this if
106
        // the series are accurate.
107
1.17k
        const double q = pj_authalic_lat_q(sinphi, P);
108
1.17k
        double ratio = q / qp;
109
110
1.17k
        if (fabs(ratio) > 1) {
111
            /* Rounding error. */
112
0
            ratio = ratio > 0 ? 1 : -1;
113
0
        }
114
1.17k
        return asin(ratio);
115
1.17k
    }
116
30.2k
}
117
118
/*****************************************************************************/
119
120
// Compute the geographic latitude from beta = authalic_latitude
121
// where APA = pj_compute_coefficients_for_inverse_authalic_lat() and
122
// qp = pj_authalic_lat_q(1, P->e, P->one_es)
123
double pj_authalic_lat_inverse(double beta, const double *APA, const PJ *P,
124
0
                               double qp) {
125
0
    double phi = pj_auxlat_convert(beta, APA);
126
0
    if (PROJ_AUTHALIC_SERIES_VALID(P->n))
127
0
        return phi;
128
    // If the flattening is large, solve
129
    //   f(phi) = qp*sin(beta)/(1-e^2) - q(phi)/(1-e^2) = 0
130
    // for phi, using Newton's method, where
131
    //   q(phi)/(1-e^2) = sin(phi)/(1 - e^2*sin(phi)^2) + atanh(e*sin(phi))/e
132
    // and
133
    //   df(phi)/dphi = - dq(phi)/dphi / (1-e^2)
134
    //                = - 2 * (1-e^2) * cos(phi) / (1 - e^2*sinphi^2)^2
135
    // This is subject to large roundoff errors near the poles, so only use
136
    // this if the series isn't accurate.
137
0
    const double q = sin(beta) * qp;
138
0
    const double q_div_one_minus_es = q / P->one_es;
139
0
    for (int i = 0; i < 10; ++i) {
140
0
        const double sinphi = sin(phi);
141
0
        const double cosphi = cos(phi);
142
0
        const double one_minus_es_sin2phi = 1 - P->es * (sinphi * sinphi);
143
        // Snyder uses 0.5 * ln((1-e*sinphi)/(1+e*sinphi) which is
144
        // -atanh(e*sinphi)
145
0
        const double dphi =
146
0
            (one_minus_es_sin2phi * one_minus_es_sin2phi) / (2 * cosphi) *
147
0
            (q_div_one_minus_es - sinphi / one_minus_es_sin2phi -
148
0
             atanh(P->e * sinphi) / P->e);
149
0
        if (!(fabs(dphi) >= 1e-15))
150
0
            break;
151
0
        phi += dphi;
152
0
    }
153
0
    return phi;
154
0
}
155
#undef PROJ_AUTHALIC_SERIES_VALID
156
157
// The following routines pj_auxlat_coeffs, pj_polyvol, pj_clenshaw,
158
// pj_auxlat_convert (3 signatures) provide a uniform interface for converting
159
// between any pair of auxiliary latitudes using series expansions in the third
160
// flattening, n.  There are 6 (= AuxLat::NUMBER) auxiliary latitudes
161
// supported labeled by
162
//
163
//   AuxLat::GEOGRAPHIC for geographic latitude, phi
164
//   AuxLat::PARAMETRIC for parametric latitude, beta
165
//   AuxLat::GEOCENTRIC for geocentric latitude, theta
166
//   AuxLat::RECTIFYING for rectifying latitude, mu
167
//   AuxLat::CONFORMAL for conformal latitude, chi
168
//   AuxLat::AUTHALIC for authlatic latitude, xi
169
//
170
// This is adapted from
171
//
172
//   C. F. F. Karney, On auxiliary latitudes,
173
//   Survey Review 56, 165-180 (2024)
174
//   https://doi.org/10.1080/00396265.2023.2217604
175
//   Preprint: https://arxiv.org/abs/2212.05818
176
//
177
// The typical calling sequence is
178
//
179
//   constexpr int L = int(AuxLat::ORDER);
180
//   // Managing the memory for the coefficient array is the
181
//   // responsibility of the calling routine.
182
//   double F[L];
183
//   // Fill F[] with coefficients to convert conformal to geographic
184
//   pj_auxlat_coeffs(P->n, AuxLat::CONFORMAL, AuxLat::GEOGRAPHIC, F);
185
//   ...
186
//   double chi = 1;                 // known conformal latitude
187
//   // compute corresponding geographic latitude
188
//   double phi = pj_auxlat_convert(chi, F);
189
//
190
// The conversions are Fourier series in the auxiliary latitude where each
191
// coefficient is given as a Taylor series in n truncated at order 6 (=
192
// AuxLat::ORDER).  This suffices to give full double precision accuracy for
193
// |f| <= 1/150 and probably provide satisfactory results for |f| <= 1/50.  The
194
// coefficients for these Taylor series are given by matrices listed in
195
// Eqs. (A1-A28) of this paper.
196
//
197
// These coefficients are bundled up into a single array coeffs in
198
// pj_auxlat_coeffs.  Only the upper triangular portion of the matrices are
199
// included.  Furthermore, half the coefficients for the conversions between
200
// any of phi, bete, theta, and mu are zero (the Taylor series are expansions
201
// in n^2), these zero elements are excluded.
202
//
203
// The coefficient array, coeffs, is machine-generated by the Maxima code
204
// auxlat.mac bundled with GeographicLib.  To use
205
//
206
// * Ensure that Lmax (set near the top of the file) is set to 6 (=
207
//   AuxLat::ORDER).
208
// * run
209
//     $ maxima
210
//     Maxima 5.47.0 https://maxima.sourceforge.io
211
//     (%i1) load("auxlat.mac")$
212
//     (%i2) writecppproj()$
213
//     ....
214
//     #<CLOSED OUTPUT BUFFERED FILE-STREAM CHARACTER auxvalsproj6.cpp>
215
// * The results are in the file auxvalsproj6.cpp
216
//
217
// Only a subset of the conversion matrices are written out.  To add others,
218
// include them in the list "required" in writecppproj().  The conversions
219
// currently supported are
220
//
221
//   phi <-> mu for meridian distance
222
//   phi <-> chi for tmerc
223
//   phi <-> xi for authalic latitude conversions
224
//   chi <-> mu for tmerc
225
//
226
// Because all the matrices are concatenated together into a single array,
227
// coeff, an auxiliary array, ptrs, or length 37 = AUXNUMBER^2 + 1, is written
228
// out to give the starting point of any particular matrix.
229
//
230
// Input:
231
//   n -- the third flattening (a-b)/(a+b)
232
//   auxin, auxout -- compute the coefficients for converting auxin (zeta) to
233
//     auxout (eta).
234
// Output:
235
//   F -- F[eta,zeta] = C[eta,zeta] . P(n), where C is a matrix of constants
236
//     and P(n) = [n, n^2, n^3, ...]^T; the first AuxLat::ORDER elements of F
237
//     are filled.
238
26.1k
void pj_auxlat_coeffs(double n, AuxLat auxin, AuxLat auxout, double F[]) {
239
    // Generated by Maxima on 2025-03-23 19:13:00-04:00
240
26.1k
    constexpr int Lmax = 6;
241
26.1k
    static_assert(Lmax == int(AuxLat::ORDER),
242
26.1k
                  "Mismatch between maxima and AuxLat::ORDER");
243
26.1k
    static const double coeffs[] = {
244
        // C[phi,phi] skipped
245
        // C[phi,beta] skipped
246
        // C[phi,theta] skipped
247
        // C[phi,mu]; even coeffs only
248
26.1k
        3.0 / 2.0, -27.0 / 32.0, 269.0 / 512.0, 21.0 / 16.0, -55.0 / 32.0,
249
26.1k
        6759.0 / 4096.0, 151.0 / 96.0, -417.0 / 128.0, 1097.0 / 512.0,
250
26.1k
        -15543.0 / 2560.0, 8011.0 / 2560.0, 293393.0 / 61440.0,
251
        // C[phi,chi]
252
26.1k
        2.0, -2.0 / 3.0, -2.0, 116.0 / 45.0, 26.0 / 45.0, -2854.0 / 675.0,
253
26.1k
        7.0 / 3.0, -8.0 / 5.0, -227.0 / 45.0, 2704.0 / 315.0, 2323.0 / 945.0,
254
26.1k
        56.0 / 15.0, -136.0 / 35.0, -1262.0 / 105.0, 73814.0 / 2835.0,
255
26.1k
        4279.0 / 630.0, -332.0 / 35.0, -399572.0 / 14175.0, 4174.0 / 315.0,
256
26.1k
        -144838.0 / 6237.0, 601676.0 / 22275.0,
257
        // C[phi,xi]
258
26.1k
        4.0 / 3.0, 4.0 / 45.0, -16.0 / 35.0, -2582.0 / 14175.0,
259
26.1k
        60136.0 / 467775.0, 28112932.0 / 212837625.0, 46.0 / 45.0,
260
26.1k
        152.0 / 945.0, -11966.0 / 14175.0, -21016.0 / 51975.0,
261
26.1k
        251310128.0 / 638512875.0, 3044.0 / 2835.0, 3802.0 / 14175.0,
262
26.1k
        -94388.0 / 66825.0, -8797648.0 / 10945935.0, 6059.0 / 4725.0,
263
26.1k
        41072.0 / 93555.0, -1472637812.0 / 638512875.0, 768272.0 / 467775.0,
264
26.1k
        455935736.0 / 638512875.0, 4210684958.0 / 1915538625.0,
265
        // C[beta,phi] skipped
266
        // C[beta,beta] skipped
267
        // C[beta,theta] skipped
268
        // C[beta,mu] skipped
269
        // C[beta,chi] skipped
270
        // C[beta,xi] skipped
271
        // C[theta,phi] skipped
272
        // C[theta,beta] skipped
273
        // C[theta,theta] skipped
274
        // C[theta,mu] skipped
275
        // C[theta,chi] skipped
276
        // C[theta,xi] skipped
277
        // C[mu,phi]; even coeffs only
278
26.1k
        -3.0 / 2.0, 9.0 / 16.0, -3.0 / 32.0, 15.0 / 16.0, -15.0 / 32.0,
279
26.1k
        135.0 / 2048.0, -35.0 / 48.0, 105.0 / 256.0, 315.0 / 512.0,
280
26.1k
        -189.0 / 512.0, -693.0 / 1280.0, 1001.0 / 2048.0,
281
        // C[mu,beta] skipped
282
        // C[mu,theta] skipped
283
        // C[mu,mu] skipped
284
        // C[mu,chi]
285
26.1k
        1.0 / 2.0, -2.0 / 3.0, 5.0 / 16.0, 41.0 / 180.0, -127.0 / 288.0,
286
26.1k
        7891.0 / 37800.0, 13.0 / 48.0, -3.0 / 5.0, 557.0 / 1440.0,
287
26.1k
        281.0 / 630.0, -1983433.0 / 1935360.0, 61.0 / 240.0, -103.0 / 140.0,
288
26.1k
        15061.0 / 26880.0, 167603.0 / 181440.0, 49561.0 / 161280.0,
289
26.1k
        -179.0 / 168.0, 6601661.0 / 7257600.0, 34729.0 / 80640.0,
290
26.1k
        -3418889.0 / 1995840.0, 212378941.0 / 319334400.0,
291
        // C[mu,xi] skipped
292
        // C[chi,phi]
293
26.1k
        -2.0, 2.0 / 3.0, 4.0 / 3.0, -82.0 / 45.0, 32.0 / 45.0, 4642.0 / 4725.0,
294
26.1k
        5.0 / 3.0, -16.0 / 15.0, -13.0 / 9.0, 904.0 / 315.0, -1522.0 / 945.0,
295
26.1k
        -26.0 / 15.0, 34.0 / 21.0, 8.0 / 5.0, -12686.0 / 2835.0, 1237.0 / 630.0,
296
26.1k
        -12.0 / 5.0, -24832.0 / 14175.0, -734.0 / 315.0, 109598.0 / 31185.0,
297
26.1k
        444337.0 / 155925.0,
298
        // C[chi,beta] skipped
299
        // C[chi,theta] skipped
300
        // C[chi,mu]
301
26.1k
        -1.0 / 2.0, 2.0 / 3.0, -37.0 / 96.0, 1.0 / 360.0, 81.0 / 512.0,
302
26.1k
        -96199.0 / 604800.0, -1.0 / 48.0, -1.0 / 15.0, 437.0 / 1440.0,
303
26.1k
        -46.0 / 105.0, 1118711.0 / 3870720.0, -17.0 / 480.0, 37.0 / 840.0,
304
26.1k
        209.0 / 4480.0, -5569.0 / 90720.0, -4397.0 / 161280.0, 11.0 / 504.0,
305
26.1k
        830251.0 / 7257600.0, -4583.0 / 161280.0, 108847.0 / 3991680.0,
306
26.1k
        -20648693.0 / 638668800.0,
307
        // C[chi,chi] skipped
308
        // C[chi,xi] skipped
309
        // C[xi,phi]
310
26.1k
        -4.0 / 3.0, -4.0 / 45.0, 88.0 / 315.0, 538.0 / 4725.0,
311
26.1k
        20824.0 / 467775.0, -44732.0 / 2837835.0, 34.0 / 45.0, 8.0 / 105.0,
312
26.1k
        -2482.0 / 14175.0, -37192.0 / 467775.0, -12467764.0 / 212837625.0,
313
26.1k
        -1532.0 / 2835.0, -898.0 / 14175.0, 54968.0 / 467775.0,
314
26.1k
        100320856.0 / 1915538625.0, 6007.0 / 14175.0, 24496.0 / 467775.0,
315
26.1k
        -5884124.0 / 70945875.0, -23356.0 / 66825.0, -839792.0 / 19348875.0,
316
26.1k
        570284222.0 / 1915538625.0,
317
        // C[xi,beta] skipped
318
        // C[xi,theta] skipped
319
        // C[xi,mu] skipped
320
        // C[xi,chi] skipped
321
        // C[xi,xi] skipped
322
26.1k
    };
323
26.1k
    static constexpr int ptrs[] = {
324
26.1k
        0,   0,   0,   0,   12,  33,  54,  54,  54,  54,  54,  54, 54,
325
26.1k
        54,  54,  54,  54,  54,  54,  66,  66,  66,  66,  87,  87, 108,
326
26.1k
        108, 108, 129, 129, 129, 150, 150, 150, 150, 150, 150,
327
26.1k
    };
328
26.1k
    static_assert(sizeof(ptrs) / sizeof(int) ==
329
26.1k
                      int(AuxLat::NUMBER) * int(AuxLat::NUMBER) + 1,
330
26.1k
                  "Mismatch in size of ptrs array");
331
26.1k
    static_assert(sizeof(coeffs) / sizeof(double) ==
332
26.1k
                      ptrs[int(AuxLat::NUMBER) * int(AuxLat::NUMBER)],
333
26.1k
                  "Mismatch in size of coeffs array");
334
26.1k
    if (!(auxin >= AuxLat(0) && auxin < AuxLat::NUMBER && auxout >= AuxLat(0) &&
335
26.1k
          auxout < AuxLat::NUMBER))
336
0
        throw std::out_of_range("Bad specification for auxiliary latitude");
337
26.1k
    int k = int(AuxLat::NUMBER) * int(auxout) + int(auxin), o = ptrs[k];
338
26.1k
    if (o == ptrs[k + 1])
339
0
        throw std::out_of_range(
340
0
            "Unsupported conversion between auxiliary latitudes");
341
26.1k
    double d = n, n2 = n * n;
342
26.1k
    if (auxin <= AuxLat::RECTIFYING && auxout <= AuxLat::RECTIFYING) {
343
36.4k
        for (int l = 0; l < Lmax; ++l) {
344
31.2k
            int m = (Lmax - l - 1) / 2; // order of polynomial in n^2
345
31.2k
            F[l] = d * pj_polyval(n2, coeffs + o, m);
346
31.2k
            o += m + 1;
347
            // coverity[copy_paste_error]
348
31.2k
            d *= n;
349
31.2k
        }
350
20.9k
    } else {
351
146k
        for (int l = 0; l < Lmax; ++l) {
352
125k
            int m = (Lmax - l - 1); // order of polynomial in n
353
125k
            F[l] = d * pj_polyval(n, coeffs + o, m);
354
125k
            o += m + 1;
355
125k
            d *= n;
356
125k
        }
357
20.9k
    }
358
    // assert (o == ptrs[k+1]);
359
26.1k
}
360
361
// Evaluation sum(p[i] * x^i, i, 0, N) via Horner's method.  N.B. p is of
362
// length N+1.
363
164k
double pj_polyval(double x, const double p[], int N) {
364
164k
    double y = N < 0 ? 0 : p[N];
365
531k
    for (; N > 0;)
366
367k
        y = y * x + p[--N];
367
164k
    return y;
368
164k
}
369
370
// Evaluate y = sum(F[k] * sin((2*k+2) * zeta), k, 0, K-1) by Clenshaw
371
// summation.  zeta is specify by its sine and cosine, szeta and czeta.
372
551k
double pj_clenshaw(double szeta, double czeta, const double F[], int K) {
373
    // Approx operation count = (K + 5) mult and (2 * K + 2) add
374
551k
    double u0 = 0, u1 = 0,                         // accumulators for sum
375
551k
        X = 2 * (czeta - szeta) * (czeta + szeta); // 2 * cos(2*zeta)
376
3.85M
    for (; K > 0;) {
377
3.30M
        double t = X * u0 - u1 + F[--K];
378
3.30M
        u1 = u0;
379
3.30M
        u0 = t;
380
3.30M
    }
381
551k
    return 2 * szeta * czeta * u0; // sin(2*zeta) * u0
382
551k
}
383
384
// Convert auxiliary latitude zeta to eta, given coefficients F produced by
385
// pj_auxlats_coeffs(n, zeta, eta, F).  K is the size of F (defaults to
386
// AuxLat::ORDER).
387
484k
double pj_auxlat_convert(double zeta, const double F[], int K) {
388
484k
    return pj_auxlat_convert(zeta, sin(zeta), cos(zeta), F, K);
389
484k
}
390
391
// Convert auxiliary latitude zeta to eta, given coefficients F produced by
392
// pj_auxlats_coeffs(n, zeta, eta, F).  In this signature, szeta and czeta (the
393
// sine and cosine of zeta) are given as inputs.  K is the size of F (defaults
394
// to AuxLat::ORDER).
395
double pj_auxlat_convert(double zeta, double szeta, double czeta,
396
551k
                         const double F[], int K) {
397
551k
    return zeta + pj_clenshaw(szeta, czeta, F, K);
398
551k
}
399
400
// Convert auxiliary latitude zeta to eta, given coefficients F produced by
401
// pj_auxlats_coeffs(n, zeta, eta, F).  K is the size of F (defaults to
402
// AuxLat::ORDER).  In this signature, the sine and cosine of eta are returned.
403
// This provides high relative accuracy near the poles.
404
void pj_auxlat_convert(double szeta, double czeta, double &seta, double &ceta,
405
0
                       const double F[], int K) {
406
0
    double delta = pj_clenshaw(szeta, czeta, F, K), sdelta = sin(delta),
407
0
           cdelta = cos(delta);
408
0
    seta = szeta * cdelta + czeta * sdelta;
409
0
    ceta = czeta * cdelta - szeta * sdelta;
410
0
}
411
412
// Compute the rectifying radius = quarter meridian / (pi/2 * a).  The accuracy
413
// of this series is the same as those used for the computation of the
414
// auxiliary latitudes.
415
7.06k
double pj_rectifying_radius(double n) {
416
    // Expansion of (quarter meridian) / ((a+b)/2 * pi/2) as series in n^2;
417
    // these coefficients are ( (2*k - 3)!! / (2*k)!! )^2 for k = 0..3
418
7.06k
    static const double coeff_rad[] = {1, 1.0 / 4, 1.0 / 64, 1.0 / 256};
419
7.06k
    return pj_polyval(n * n, coeff_rad, 3) / (1 + n);
420
7.06k
}