/src/proj/src/projections/natearth.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | The Natural Earth projection was designed by Tom Patterson, US National Park |
3 | | Service, in 2007, using Flex Projector. The shape of the original projection |
4 | | was defined at every 5 degrees and piece-wise cubic spline interpolation was |
5 | | used to compute the complete graticule. |
6 | | The code here uses polynomial functions instead of cubic splines and |
7 | | is therefore much simpler to program. The polynomial approximation was |
8 | | developed by Bojan Savric, in collaboration with Tom Patterson and Bernhard |
9 | | Jenny, Institute of Cartography, ETH Zurich. It slightly deviates from |
10 | | Patterson's original projection by adding additional curvature to meridians |
11 | | where they meet the horizontal pole line. This improvement is by intention |
12 | | and designed in collaboration with Tom Patterson. |
13 | | Port to PROJ.4 by Bernhard Jenny, 6 June 2011 |
14 | | */ |
15 | | |
16 | | #include <math.h> |
17 | | |
18 | | #include "proj.h" |
19 | | #include "proj_internal.h" |
20 | | |
21 | | PROJ_HEAD(natearth, "Natural Earth") "\n\tPCyl, Sph"; |
22 | | |
23 | 0 | #define A0 0.8707 |
24 | 0 | #define A1 -0.131979 |
25 | 0 | #define A2 -0.013791 |
26 | 0 | #define A3 0.003971 |
27 | 0 | #define A4 -0.001529 |
28 | 0 | #define B0 1.007226 |
29 | 0 | #define B1 0.015085 |
30 | 0 | #define B2 -0.044475 |
31 | 0 | #define B3 0.028874 |
32 | 0 | #define B4 -0.005916 |
33 | 0 | #define C0 B0 |
34 | 0 | #define C1 (3 * B1) |
35 | 0 | #define C2 (7 * B2) |
36 | 0 | #define C3 (9 * B3) |
37 | 0 | #define C4 (11 * B4) |
38 | 0 | #define EPS 1e-11 |
39 | 0 | #define MAX_Y (0.8707 * 0.52 * M_PI) |
40 | | /* Not sure at all of the appropriate number for MAX_ITER... */ |
41 | 0 | #define MAX_ITER 100 |
42 | | |
43 | 0 | static PJ_XY natearth_s_forward(PJ_LP lp, PJ *P) { /* Spheroidal, forward */ |
44 | 0 | PJ_XY xy = {0.0, 0.0}; |
45 | 0 | double phi2, phi4; |
46 | 0 | (void)P; |
47 | |
|
48 | 0 | phi2 = lp.phi * lp.phi; |
49 | 0 | phi4 = phi2 * phi2; |
50 | 0 | xy.x = lp.lam * |
51 | 0 | (A0 + phi2 * (A1 + phi2 * (A2 + phi4 * phi2 * (A3 + phi2 * A4)))); |
52 | 0 | xy.y = lp.phi * (B0 + phi2 * (B1 + phi4 * (B2 + B3 * phi2 + B4 * phi4))); |
53 | 0 | return xy; |
54 | 0 | } |
55 | | |
56 | 0 | static PJ_LP natearth_s_inverse(PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ |
57 | 0 | PJ_LP lp = {0.0, 0.0}; |
58 | 0 | double yc, y2, y4, f, fder; |
59 | 0 | int i; |
60 | 0 | (void)P; |
61 | | |
62 | | /* make sure y is inside valid range */ |
63 | 0 | if (xy.y > MAX_Y) { |
64 | 0 | xy.y = MAX_Y; |
65 | 0 | } else if (xy.y < -MAX_Y) { |
66 | 0 | xy.y = -MAX_Y; |
67 | 0 | } |
68 | | |
69 | | /* latitude */ |
70 | 0 | yc = xy.y; |
71 | 0 | for (i = MAX_ITER; i; --i) { /* Newton-Raphson */ |
72 | 0 | y2 = yc * yc; |
73 | 0 | y4 = y2 * y2; |
74 | 0 | f = (yc * (B0 + y2 * (B1 + y4 * (B2 + B3 * y2 + B4 * y4)))) - xy.y; |
75 | 0 | fder = C0 + y2 * (C1 + y4 * (C2 + C3 * y2 + C4 * y4)); |
76 | 0 | const double tol = f / fder; |
77 | 0 | yc -= tol; |
78 | 0 | if (fabs(tol) < EPS) { |
79 | 0 | break; |
80 | 0 | } |
81 | 0 | } |
82 | 0 | if (i == 0) |
83 | 0 | proj_context_errno_set( |
84 | 0 | P->ctx, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN); |
85 | 0 | lp.phi = yc; |
86 | | |
87 | | /* longitude */ |
88 | 0 | y2 = yc * yc; |
89 | 0 | lp.lam = |
90 | 0 | xy.x / (A0 + y2 * (A1 + y2 * (A2 + y2 * y2 * y2 * (A3 + y2 * A4)))); |
91 | |
|
92 | 0 | return lp; |
93 | 0 | } |
94 | | |
95 | 18 | PJ *PJ_PROJECTION(natearth) { |
96 | 18 | P->es = 0; |
97 | 18 | P->inv = natearth_s_inverse; |
98 | 18 | P->fwd = natearth_s_forward; |
99 | | |
100 | 18 | return P; |
101 | 18 | } |
102 | | |
103 | | #undef A0 |
104 | | #undef A1 |
105 | | #undef A2 |
106 | | #undef A3 |
107 | | #undef A4 |
108 | | #undef A5 |
109 | | #undef B0 |
110 | | #undef B1 |
111 | | #undef B2 |
112 | | #undef B3 |
113 | | #undef C0 |
114 | | #undef C1 |
115 | | #undef C2 |
116 | | #undef C3 |
117 | | #undef EPS |
118 | | #undef MAX_Y |
119 | | #undef MAX_ITER |