/src/PROJ/src/projections/robin.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | |
2 | | #include "proj.h" |
3 | | #include "proj_internal.h" |
4 | | #include <cmath> |
5 | | |
6 | | PROJ_HEAD(robin, "Robinson") "\n\tPCyl, Sph"; |
7 | | |
8 | 0 | #define V(C, z) (C.c0 + z * (C.c1 + z * (C.c2 + z * C.c3))) |
9 | 0 | #define DV(C, z) (C.c1 + 2 * z * C.c2 + z * z * 3. * C.c3) |
10 | | |
11 | | /* |
12 | | note: following terms based upon 5 deg. intervals in degrees. |
13 | | |
14 | | Some background on these coefficients is available at: |
15 | | |
16 | | http://article.gmane.org/gmane.comp.gis.proj-4.devel/6039 |
17 | | http://trac.osgeo.org/proj/ticket/113 |
18 | | */ |
19 | | |
20 | | namespace { // anonymous namespace |
21 | | struct COEFS { |
22 | | float c0, c1, c2, c3; |
23 | | }; |
24 | | } // anonymous namespace |
25 | | |
26 | | static const struct COEFS X[] = { |
27 | | {1.0f, 2.2199e-17f, -7.15515e-05f, 3.1103e-06f}, |
28 | | {0.9986f, -0.000482243f, -2.4897e-05f, -1.3309e-06f}, |
29 | | {0.9954f, -0.00083103f, -4.48605e-05f, -9.86701e-07f}, |
30 | | {0.99f, -0.00135364f, -5.9661e-05f, 3.6777e-06f}, |
31 | | {0.9822f, -0.00167442f, -4.49547e-06f, -5.72411e-06f}, |
32 | | {0.973f, -0.00214868f, -9.03571e-05f, 1.8736e-08f}, |
33 | | {0.96f, -0.00305085f, -9.00761e-05f, 1.64917e-06f}, |
34 | | {0.9427f, -0.00382792f, -6.53386e-05f, -2.6154e-06f}, |
35 | | {0.9216f, -0.00467746f, -0.00010457f, 4.81243e-06f}, |
36 | | {0.8962f, -0.00536223f, -3.23831e-05f, -5.43432e-06f}, |
37 | | {0.8679f, -0.00609363f, -0.000113898f, 3.32484e-06f}, |
38 | | {0.835f, -0.00698325f, -6.40253e-05f, 9.34959e-07f}, |
39 | | {0.7986f, -0.00755338f, -5.00009e-05f, 9.35324e-07f}, |
40 | | {0.7597f, -0.00798324f, -3.5971e-05f, -2.27626e-06f}, |
41 | | {0.7186f, -0.00851367f, -7.01149e-05f, -8.6303e-06f}, |
42 | | {0.6732f, -0.00986209f, -0.000199569f, 1.91974e-05f}, |
43 | | {0.6213f, -0.010418f, 8.83923e-05f, 6.24051e-06f}, |
44 | | {0.5722f, -0.00906601f, 0.000182f, 6.24051e-06f}, |
45 | | {0.5322f, -0.00677797f, 0.000275608f, 6.24051e-06f}}; |
46 | | |
47 | | static const struct COEFS Y[] = { |
48 | | {-5.20417e-18f, 0.0124f, 1.21431e-18f, -8.45284e-11f}, |
49 | | {0.062f, 0.0124f, -1.26793e-09f, 4.22642e-10f}, |
50 | | {0.124f, 0.0124f, 5.07171e-09f, -1.60604e-09f}, |
51 | | {0.186f, 0.0123999f, -1.90189e-08f, 6.00152e-09f}, |
52 | | {0.248f, 0.0124002f, 7.10039e-08f, -2.24e-08f}, |
53 | | {0.31f, 0.0123992f, -2.64997e-07f, 8.35986e-08f}, |
54 | | {0.372f, 0.0124029f, 9.88983e-07f, -3.11994e-07f}, |
55 | | {0.434f, 0.0123893f, -3.69093e-06f, -4.35621e-07f}, |
56 | | {0.4958f, 0.0123198f, -1.02252e-05f, -3.45523e-07f}, |
57 | | {0.5571f, 0.0121916f, -1.54081e-05f, -5.82288e-07f}, |
58 | | {0.6176f, 0.0119938f, -2.41424e-05f, -5.25327e-07f}, |
59 | | {0.6769f, 0.011713f, -3.20223e-05f, -5.16405e-07f}, |
60 | | {0.7346f, 0.0113541f, -3.97684e-05f, -6.09052e-07f}, |
61 | | {0.7903f, 0.0109107f, -4.89042e-05f, -1.04739e-06f}, |
62 | | {0.8435f, 0.0103431f, -6.4615e-05f, -1.40374e-09f}, |
63 | | {0.8936f, 0.00969686f, -6.4636e-05f, -8.547e-06f}, |
64 | | {0.9394f, 0.00840947f, -0.000192841f, -4.2106e-06f}, |
65 | | {0.9761f, 0.00616527f, -0.000256f, -4.2106e-06f}, |
66 | | {1.0f, 0.00328947f, -0.000319159f, -4.2106e-06f}}; |
67 | | |
68 | 0 | #define FXC 0.8487 |
69 | 0 | #define FYC 1.3523 |
70 | 0 | #define C1 11.45915590261646417544 |
71 | 0 | #define RC1 0.08726646259971647884 |
72 | 0 | #define NODES 18 |
73 | 0 | #define ONEEPS 1.000001 |
74 | 0 | #define EPS 1e-10 |
75 | | /* Not sure at all of the appropriate number for MAX_ITER... */ |
76 | 0 | #define MAX_ITER 100 |
77 | | |
78 | 0 | static PJ_XY robin_s_forward(PJ_LP lp, PJ *P) { /* Spheroidal, forward */ |
79 | 0 | PJ_XY xy = {0.0, 0.0}; |
80 | 0 | long i; |
81 | 0 | double dphi; |
82 | 0 | (void)P; |
83 | |
|
84 | 0 | dphi = fabs(lp.phi); |
85 | 0 | i = std::isnan(lp.phi) ? -1 : lround(floor(dphi * C1 + 1e-15)); |
86 | 0 | if (i < 0) { |
87 | 0 | proj_errno_set(P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN); |
88 | 0 | return xy; |
89 | 0 | } |
90 | 0 | if (i >= NODES) |
91 | 0 | i = NODES; |
92 | 0 | dphi = RAD_TO_DEG * (dphi - RC1 * i); |
93 | 0 | xy.x = V(X[i], dphi) * FXC * lp.lam; |
94 | 0 | xy.y = V(Y[i], dphi) * FYC; |
95 | 0 | if (lp.phi < 0.) |
96 | 0 | xy.y = -xy.y; |
97 | |
|
98 | 0 | return xy; |
99 | 0 | } |
100 | | |
101 | 0 | static PJ_LP robin_s_inverse(PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ |
102 | 0 | PJ_LP lp = {0.0, 0.0}; |
103 | 0 | double t; |
104 | 0 | struct COEFS T; |
105 | 0 | int iters; |
106 | |
|
107 | 0 | lp.lam = xy.x / FXC; |
108 | 0 | lp.phi = fabs(xy.y / FYC); |
109 | 0 | if (lp.phi >= 1.) { /* simple pathologic cases */ |
110 | 0 | if (lp.phi > ONEEPS) { |
111 | 0 | proj_errno_set(P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN); |
112 | 0 | return lp; |
113 | 0 | } else { |
114 | 0 | lp.phi = xy.y < 0. ? -M_HALFPI : M_HALFPI; |
115 | 0 | lp.lam /= X[NODES].c0; |
116 | 0 | } |
117 | 0 | } else { /* general problem */ |
118 | | /* in Y space, reduce to table interval */ |
119 | 0 | long i = std::isnan(lp.phi) ? -1 : lround(floor(lp.phi * NODES)); |
120 | 0 | if (i < 0 || i >= NODES) { |
121 | 0 | proj_errno_set(P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN); |
122 | 0 | return lp; |
123 | 0 | } |
124 | 0 | for (;;) { |
125 | 0 | if (Y[i].c0 > lp.phi) |
126 | 0 | --i; |
127 | 0 | else if (Y[i + 1].c0 <= lp.phi) |
128 | 0 | ++i; |
129 | 0 | else |
130 | 0 | break; |
131 | 0 | } |
132 | 0 | T = Y[i]; |
133 | | /* first guess, linear interp */ |
134 | 0 | t = 5. * (lp.phi - T.c0) / (Y[i + 1].c0 - T.c0); |
135 | 0 | for (iters = MAX_ITER; iters; --iters) { /* Newton-Raphson */ |
136 | 0 | const double t1 = (V(T, t) - lp.phi) / DV(T, t); |
137 | 0 | t -= t1; |
138 | 0 | if (fabs(t1) < EPS) |
139 | 0 | break; |
140 | 0 | } |
141 | 0 | if (iters == 0) |
142 | 0 | proj_context_errno_set( |
143 | 0 | P->ctx, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN); |
144 | 0 | lp.phi = (5 * i + t) * DEG_TO_RAD; |
145 | 0 | if (xy.y < 0.) |
146 | 0 | lp.phi = -lp.phi; |
147 | 0 | lp.lam /= V(X[i], t); |
148 | 0 | if (fabs(lp.lam) > M_PI) { |
149 | 0 | proj_errno_set(P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN); |
150 | 0 | lp = proj_coord_error().lp; |
151 | 0 | } |
152 | 0 | } |
153 | 0 | return lp; |
154 | 0 | } |
155 | | |
156 | 3 | PJ *PJ_PROJECTION(robin) { |
157 | 3 | P->es = 0.; |
158 | 3 | P->inv = robin_s_inverse; |
159 | 3 | P->fwd = robin_s_forward; |
160 | | |
161 | 3 | return P; |
162 | 3 | } |