/src/PROJ/src/projections/poly.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(poly, "Polyconic (American)") |
10 | | "\n\tConic, Sph&Ell"; |
11 | | |
12 | | namespace { // anonymous namespace |
13 | | struct pj_poly_data { |
14 | | double ml0; |
15 | | double *en; |
16 | | }; |
17 | | } // anonymous namespace |
18 | | |
19 | 14.2k | #define TOL 1e-10 |
20 | 0 | #define CONV 1e-10 |
21 | 0 | #define N_ITER 10 |
22 | 0 | #define I_ITER 20 |
23 | 0 | #define ITOL 1.e-12 |
24 | | |
25 | 7.14k | static PJ_XY poly_e_forward(PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ |
26 | 7.14k | PJ_XY xy = {0.0, 0.0}; |
27 | 7.14k | struct pj_poly_data *Q = static_cast<struct pj_poly_data *>(P->opaque); |
28 | 7.14k | double ms, sp, cp; |
29 | | |
30 | 7.14k | if (fabs(lp.phi) <= TOL) { |
31 | 0 | xy.x = lp.lam; |
32 | 0 | xy.y = -Q->ml0; |
33 | 7.14k | } else { |
34 | 7.14k | sp = sin(lp.phi); |
35 | 7.14k | cp = cos(lp.phi); |
36 | 7.14k | ms = fabs(cp) > TOL ? pj_msfn(sp, cp, P->es) / sp : 0.; |
37 | 7.14k | lp.lam *= sp; |
38 | 7.14k | xy.x = ms * sin(lp.lam); |
39 | 7.14k | xy.y = |
40 | 7.14k | (pj_mlfn(lp.phi, sp, cp, Q->en) - Q->ml0) + ms * (1. - cos(lp.lam)); |
41 | 7.14k | } |
42 | | |
43 | 7.14k | return xy; |
44 | 7.14k | } |
45 | | |
46 | 0 | static PJ_XY poly_s_forward(PJ_LP lp, PJ *P) { /* Spheroidal, forward */ |
47 | 0 | PJ_XY xy = {0.0, 0.0}; |
48 | 0 | struct pj_poly_data *Q = static_cast<struct pj_poly_data *>(P->opaque); |
49 | |
|
50 | 0 | if (fabs(lp.phi) <= TOL) { |
51 | 0 | xy.x = lp.lam; |
52 | 0 | xy.y = Q->ml0; |
53 | 0 | } else { |
54 | 0 | const double cot = 1. / tan(lp.phi); |
55 | 0 | const double E = lp.lam * sin(lp.phi); |
56 | 0 | xy.x = sin(E) * cot; |
57 | 0 | xy.y = lp.phi - P->phi0 + cot * (1. - cos(E)); |
58 | 0 | } |
59 | |
|
60 | 0 | return xy; |
61 | 0 | } |
62 | | |
63 | 0 | static PJ_LP poly_e_inverse(PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ |
64 | 0 | PJ_LP lp = {0.0, 0.0}; |
65 | 0 | struct pj_poly_data *Q = static_cast<struct pj_poly_data *>(P->opaque); |
66 | |
|
67 | 0 | xy.y += Q->ml0; |
68 | 0 | if (fabs(xy.y) <= TOL) { |
69 | 0 | lp.lam = xy.x; |
70 | 0 | lp.phi = 0.; |
71 | 0 | } else { |
72 | 0 | int i; |
73 | |
|
74 | 0 | const double r = xy.y * xy.y + xy.x * xy.x; |
75 | 0 | lp.phi = xy.y; |
76 | 0 | for (i = I_ITER; i; --i) { |
77 | 0 | const double sp = sin(lp.phi); |
78 | 0 | const double cp = cos(lp.phi); |
79 | 0 | const double s2ph = sp * cp; |
80 | 0 | if (fabs(cp) < ITOL) { |
81 | 0 | proj_errno_set( |
82 | 0 | P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN); |
83 | 0 | return lp; |
84 | 0 | } |
85 | 0 | double mlp = sqrt(1. - P->es * sp * sp); |
86 | 0 | const double c = sp * mlp / cp; |
87 | 0 | const double ml = pj_mlfn(lp.phi, sp, cp, Q->en); |
88 | 0 | const double mlb = ml * ml + r; |
89 | 0 | mlp = P->one_es / (mlp * mlp * mlp); |
90 | 0 | const double dPhi = |
91 | 0 | (ml + ml + c * mlb - 2. * xy.y * (c * ml + 1.)) / |
92 | 0 | (P->es * s2ph * (mlb - 2. * xy.y * ml) / c + |
93 | 0 | 2. * (xy.y - ml) * (c * mlp - 1. / s2ph) - mlp - mlp); |
94 | 0 | lp.phi += dPhi; |
95 | 0 | if (fabs(dPhi) <= ITOL) |
96 | 0 | break; |
97 | 0 | } |
98 | 0 | if (!i) { |
99 | 0 | proj_errno_set(P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN); |
100 | 0 | return lp; |
101 | 0 | } |
102 | 0 | const double c = sin(lp.phi); |
103 | 0 | lp.lam = |
104 | 0 | asin(xy.x * tan(lp.phi) * sqrt(1. - P->es * c * c)) / sin(lp.phi); |
105 | 0 | } |
106 | | |
107 | 0 | return lp; |
108 | 0 | } |
109 | | |
110 | 0 | static PJ_LP poly_s_inverse(PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ |
111 | 0 | PJ_LP lp = {0.0, 0.0}; |
112 | |
|
113 | 0 | if (fabs(xy.y = P->phi0 + xy.y) <= TOL) { |
114 | 0 | lp.lam = xy.x; |
115 | 0 | lp.phi = 0.; |
116 | 0 | } else { |
117 | 0 | lp.phi = xy.y; |
118 | 0 | const double B = xy.x * xy.x + xy.y * xy.y; |
119 | 0 | int i = N_ITER; |
120 | 0 | while (true) { |
121 | 0 | const double tp = tan(lp.phi); |
122 | 0 | const double dphi = (xy.y * (lp.phi * tp + 1.) - lp.phi - |
123 | 0 | .5 * (lp.phi * lp.phi + B) * tp) / |
124 | 0 | ((lp.phi - xy.y) / tp - 1.); |
125 | 0 | lp.phi -= dphi; |
126 | 0 | if (!(fabs(dphi) > CONV)) |
127 | 0 | break; |
128 | 0 | --i; |
129 | 0 | if (i == 0) { |
130 | 0 | proj_errno_set( |
131 | 0 | P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN); |
132 | 0 | return lp; |
133 | 0 | } |
134 | 0 | } |
135 | 0 | lp.lam = asin(xy.x * tan(lp.phi)) / sin(lp.phi); |
136 | 0 | } |
137 | | |
138 | 0 | return lp; |
139 | 0 | } |
140 | | |
141 | 131 | static PJ *pj_poly_destructor(PJ *P, int errlev) { |
142 | 131 | if (nullptr == P) |
143 | 0 | return nullptr; |
144 | | |
145 | 131 | if (nullptr == P->opaque) |
146 | 0 | return pj_default_destructor(P, errlev); |
147 | | |
148 | 131 | if (static_cast<struct pj_poly_data *>(P->opaque)->en) |
149 | 121 | free(static_cast<struct pj_poly_data *>(P->opaque)->en); |
150 | | |
151 | 131 | return pj_default_destructor(P, errlev); |
152 | 131 | } |
153 | | |
154 | 131 | PJ *PJ_PROJECTION(poly) { |
155 | 131 | struct pj_poly_data *Q = static_cast<struct pj_poly_data *>( |
156 | 131 | calloc(1, sizeof(struct pj_poly_data))); |
157 | 131 | if (nullptr == Q) |
158 | 0 | return pj_default_destructor(P, PROJ_ERR_OTHER /*ENOMEM*/); |
159 | | |
160 | 131 | P->opaque = Q; |
161 | 131 | P->destructor = pj_poly_destructor; |
162 | | |
163 | 131 | if (P->es != 0.0) { |
164 | 121 | if (!(Q->en = pj_enfn(P->n))) |
165 | 0 | return pj_default_destructor(P, PROJ_ERR_OTHER /*ENOMEM*/); |
166 | 121 | Q->ml0 = pj_mlfn(P->phi0, sin(P->phi0), cos(P->phi0), Q->en); |
167 | 121 | P->inv = poly_e_inverse; |
168 | 121 | P->fwd = poly_e_forward; |
169 | 121 | } else { |
170 | 10 | Q->ml0 = -P->phi0; |
171 | 10 | P->inv = poly_s_inverse; |
172 | 10 | P->fwd = poly_s_forward; |
173 | 10 | } |
174 | | |
175 | 131 | return P; |
176 | 131 | } |
177 | | |
178 | | #undef TOL |
179 | | #undef CONV |
180 | | #undef N_ITER |
181 | | #undef I_ITER |
182 | | #undef ITOL |