/src/PROJ/src/projections/bonne.cpp
Line | Count | Source |
1 | | |
2 | | #include "proj.h" |
3 | | #include "proj_internal.h" |
4 | | #include <errno.h> |
5 | | #include <math.h> |
6 | | |
7 | | PROJ_HEAD(bonne, "Bonne (Werner lat_1=90)") |
8 | | "\n\tConic Sph&Ell\n\tlat_1="; |
9 | 137 | #define EPS10 1e-10 |
10 | | |
11 | | namespace { // anonymous namespace |
12 | | struct pj_bonne_data { |
13 | | double phi1; |
14 | | double cphi1; |
15 | | double am1; |
16 | | double m1; |
17 | | double *en; |
18 | | }; |
19 | | } // anonymous namespace |
20 | | |
21 | 0 | static PJ_XY bonne_e_forward(PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ |
22 | 0 | PJ_XY xy = {0.0, 0.0}; |
23 | 0 | struct pj_bonne_data *Q = static_cast<struct pj_bonne_data *>(P->opaque); |
24 | 0 | double rh, E, c; |
25 | |
|
26 | 0 | E = sin(lp.phi); |
27 | 0 | c = cos(lp.phi); |
28 | 0 | rh = Q->am1 + Q->m1 - pj_mlfn(lp.phi, E, c, Q->en); |
29 | 0 | if (fabs(rh) > EPS10) { |
30 | 0 | E = c * lp.lam / (rh * sqrt(1. - P->es * E * E)); |
31 | 0 | xy.x = rh * sin(E); |
32 | 0 | xy.y = Q->am1 - rh * cos(E); |
33 | 0 | } else { |
34 | 0 | xy.x = 0.; |
35 | 0 | xy.y = 0.; |
36 | 0 | } |
37 | 0 | return xy; |
38 | 0 | } |
39 | | |
40 | 0 | static PJ_XY bonne_s_forward(PJ_LP lp, PJ *P) { /* Spheroidal, forward */ |
41 | 0 | PJ_XY xy = {0.0, 0.0}; |
42 | 0 | struct pj_bonne_data *Q = static_cast<struct pj_bonne_data *>(P->opaque); |
43 | 0 | double E, rh; |
44 | |
|
45 | 0 | rh = Q->cphi1 + Q->phi1 - lp.phi; |
46 | 0 | if (fabs(rh) > EPS10) { |
47 | 0 | E = lp.lam * cos(lp.phi) / rh; |
48 | 0 | xy.x = rh * sin(E); |
49 | 0 | xy.y = Q->cphi1 - rh * cos(E); |
50 | 0 | } else |
51 | 0 | xy.x = xy.y = 0.; |
52 | 0 | return xy; |
53 | 0 | } |
54 | | |
55 | 0 | static PJ_LP bonne_s_inverse(PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ |
56 | 0 | PJ_LP lp = {0.0, 0.0}; |
57 | 0 | struct pj_bonne_data *Q = static_cast<struct pj_bonne_data *>(P->opaque); |
58 | |
|
59 | 0 | xy.y = Q->cphi1 - xy.y; |
60 | 0 | const double rh = copysign(hypot(xy.x, xy.y), Q->phi1); |
61 | 0 | lp.phi = Q->cphi1 + Q->phi1 - rh; |
62 | 0 | const double abs_phi = fabs(lp.phi); |
63 | 0 | if (abs_phi > M_HALFPI) { |
64 | 0 | proj_errno_set(P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN); |
65 | 0 | return lp; |
66 | 0 | } |
67 | 0 | if (M_HALFPI - abs_phi <= EPS10) |
68 | 0 | lp.lam = 0.; |
69 | 0 | else { |
70 | 0 | const double lm = rh / cos(lp.phi); |
71 | 0 | if (Q->phi1 > 0) { |
72 | 0 | lp.lam = lm * atan2(xy.x, xy.y); |
73 | 0 | } else { |
74 | 0 | lp.lam = lm * atan2(-xy.x, -xy.y); |
75 | 0 | } |
76 | 0 | } |
77 | 0 | return lp; |
78 | 0 | } |
79 | | |
80 | 0 | static PJ_LP bonne_e_inverse(PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ |
81 | 0 | PJ_LP lp = {0.0, 0.0}; |
82 | 0 | struct pj_bonne_data *Q = static_cast<struct pj_bonne_data *>(P->opaque); |
83 | |
|
84 | 0 | xy.y = Q->am1 - xy.y; |
85 | 0 | const double rh = copysign(hypot(xy.x, xy.y), Q->phi1); |
86 | 0 | lp.phi = pj_inv_mlfn(Q->am1 + Q->m1 - rh, Q->en); |
87 | 0 | const double abs_phi = fabs(lp.phi); |
88 | 0 | if (abs_phi < M_HALFPI) { |
89 | 0 | const double sinphi = sin(lp.phi); |
90 | 0 | const double lm = rh * sqrt(1. - P->es * sinphi * sinphi) / cos(lp.phi); |
91 | 0 | if (Q->phi1 > 0) { |
92 | 0 | lp.lam = lm * atan2(xy.x, xy.y); |
93 | 0 | } else { |
94 | 0 | lp.lam = lm * atan2(-xy.x, -xy.y); |
95 | 0 | } |
96 | 0 | } else if (abs_phi - M_HALFPI <= EPS10) |
97 | 0 | lp.lam = 0.; |
98 | 0 | else { |
99 | 0 | proj_errno_set(P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN); |
100 | 0 | return lp; |
101 | 0 | } |
102 | 0 | return lp; |
103 | 0 | } |
104 | | |
105 | 83 | static PJ *pj_bonne_destructor(PJ *P, int errlev) { /* Destructor */ |
106 | 83 | if (nullptr == P) |
107 | 0 | return nullptr; |
108 | | |
109 | 83 | if (nullptr == P->opaque) |
110 | 0 | return pj_default_destructor(P, errlev); |
111 | | |
112 | 83 | free(static_cast<struct pj_bonne_data *>(P->opaque)->en); |
113 | 83 | return pj_default_destructor(P, errlev); |
114 | 83 | } |
115 | | |
116 | 83 | PJ *PJ_PROJECTION(bonne) { |
117 | 83 | double c; |
118 | 83 | struct pj_bonne_data *Q = static_cast<struct pj_bonne_data *>( |
119 | 83 | calloc(1, sizeof(struct pj_bonne_data))); |
120 | 83 | if (nullptr == Q) |
121 | 0 | return pj_default_destructor(P, PROJ_ERR_OTHER /*ENOMEM*/); |
122 | 83 | P->opaque = Q; |
123 | 83 | P->destructor = pj_bonne_destructor; |
124 | | |
125 | 83 | Q->phi1 = pj_param(P->ctx, P->params, "rlat_1").f; |
126 | 83 | if (fabs(Q->phi1) < EPS10) { |
127 | 5 | proj_log_error(P, _("Invalid value for lat_1: |lat_1| should be > 0")); |
128 | 5 | return pj_bonne_destructor(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
129 | 5 | } |
130 | | |
131 | 78 | if (P->es != 0.0) { |
132 | 24 | Q->en = pj_enfn(P->n); |
133 | 24 | if (nullptr == Q->en) |
134 | 0 | return pj_bonne_destructor(P, PROJ_ERR_OTHER /*ENOMEM*/); |
135 | 24 | Q->am1 = sin(Q->phi1); |
136 | 24 | c = cos(Q->phi1); |
137 | 24 | Q->m1 = pj_mlfn(Q->phi1, Q->am1, c, Q->en); |
138 | 24 | Q->am1 = c / (sqrt(1. - P->es * Q->am1 * Q->am1) * Q->am1); |
139 | 24 | P->inv = bonne_e_inverse; |
140 | 24 | P->fwd = bonne_e_forward; |
141 | 54 | } else { |
142 | 54 | if (fabs(Q->phi1) + EPS10 >= M_HALFPI) |
143 | 43 | Q->cphi1 = 0.; |
144 | 11 | else |
145 | 11 | Q->cphi1 = 1. / tan(Q->phi1); |
146 | 54 | P->inv = bonne_s_inverse; |
147 | 54 | P->fwd = bonne_s_forward; |
148 | 54 | } |
149 | 78 | return P; |
150 | 78 | } |
151 | | |
152 | | #undef EPS10 |