/src/proj/src/projections/oea.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | |
2 | | #include "proj.h" |
3 | | #include "proj_internal.h" |
4 | | #include <errno.h> |
5 | | #include <math.h> |
6 | | |
7 | | PROJ_HEAD(oea, "Oblated Equal Area") "\n\tMisc Sph\n\tn= m= theta="; |
8 | | |
9 | | namespace { // anonymous namespace |
10 | | struct pj_oea { |
11 | | double theta; |
12 | | double m, n; |
13 | | double two_r_m, two_r_n, rm, rn, hm, hn; |
14 | | double cp0, sp0; |
15 | | }; |
16 | | } // anonymous namespace |
17 | | |
18 | 0 | static PJ_XY oea_s_forward(PJ_LP lp, PJ *P) { /* Spheroidal, forward */ |
19 | 0 | PJ_XY xy = {0.0, 0.0}; |
20 | 0 | struct pj_oea *Q = static_cast<struct pj_oea *>(P->opaque); |
21 | |
|
22 | 0 | const double cp = cos(lp.phi); |
23 | 0 | const double sp = sin(lp.phi); |
24 | 0 | const double cl = cos(lp.lam); |
25 | 0 | const double Az = |
26 | 0 | aatan2(cp * sin(lp.lam), Q->cp0 * sp - Q->sp0 * cp * cl) + Q->theta; |
27 | 0 | const double shz = sin(0.5 * aacos(P->ctx, Q->sp0 * sp + Q->cp0 * cp * cl)); |
28 | 0 | const double M = aasin(P->ctx, shz * sin(Az)); |
29 | 0 | const double N = |
30 | 0 | aasin(P->ctx, shz * cos(Az) * cos(M) / cos(M * Q->two_r_m)); |
31 | 0 | xy.y = Q->n * sin(N * Q->two_r_n); |
32 | 0 | xy.x = Q->m * sin(M * Q->two_r_m) * cos(N) / cos(N * Q->two_r_n); |
33 | |
|
34 | 0 | return xy; |
35 | 0 | } |
36 | | |
37 | 0 | static PJ_LP oea_s_inverse(PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ |
38 | 0 | PJ_LP lp = {0.0, 0.0}; |
39 | 0 | struct pj_oea *Q = static_cast<struct pj_oea *>(P->opaque); |
40 | |
|
41 | 0 | const double N = Q->hn * aasin(P->ctx, xy.y * Q->rn); |
42 | 0 | const double M = |
43 | 0 | Q->hm * aasin(P->ctx, xy.x * Q->rm * cos(N * Q->two_r_n) / cos(N)); |
44 | 0 | const double xp = 2. * sin(M); |
45 | 0 | const double yp = 2. * sin(N) * cos(M * Q->two_r_m) / cos(M); |
46 | 0 | const double Az = aatan2(xp, yp) - Q->theta; |
47 | 0 | const double cAz = cos(Az); |
48 | 0 | const double z = 2. * aasin(P->ctx, 0.5 * hypot(xp, yp)); |
49 | 0 | const double sz = sin(z); |
50 | 0 | const double cz = cos(z); |
51 | 0 | lp.phi = aasin(P->ctx, Q->sp0 * cz + Q->cp0 * sz * cAz); |
52 | 0 | lp.lam = aatan2(sz * sin(Az), Q->cp0 * cz - Q->sp0 * sz * cAz); |
53 | |
|
54 | 0 | return lp; |
55 | 0 | } |
56 | | |
57 | 3 | PJ *PJ_PROJECTION(oea) { |
58 | 3 | struct pj_oea *Q = |
59 | 3 | static_cast<struct pj_oea *>(calloc(1, sizeof(struct pj_oea))); |
60 | 3 | if (nullptr == Q) |
61 | 0 | return pj_default_destructor(P, PROJ_ERR_OTHER /*ENOMEM*/); |
62 | 3 | P->opaque = Q; |
63 | | |
64 | 3 | if (((Q->n = pj_param(P->ctx, P->params, "dn").f) <= 0.)) { |
65 | 3 | proj_log_error(P, _("Invalid value for n: it should be > 0")); |
66 | 3 | return pj_default_destructor(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
67 | 3 | } |
68 | | |
69 | 0 | if (((Q->m = pj_param(P->ctx, P->params, "dm").f) <= 0.)) { |
70 | 0 | proj_log_error(P, _("Invalid value for m: it should be > 0")); |
71 | 0 | return pj_default_destructor(P, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
72 | 0 | } |
73 | | |
74 | 0 | Q->theta = pj_param(P->ctx, P->params, "rtheta").f; |
75 | 0 | Q->sp0 = sin(P->phi0); |
76 | 0 | Q->cp0 = cos(P->phi0); |
77 | 0 | Q->rn = 1. / Q->n; |
78 | 0 | Q->rm = 1. / Q->m; |
79 | 0 | Q->two_r_n = 2. * Q->rn; |
80 | 0 | Q->two_r_m = 2. * Q->rm; |
81 | 0 | Q->hm = 0.5 * Q->m; |
82 | 0 | Q->hn = 0.5 * Q->n; |
83 | 0 | P->fwd = oea_s_forward; |
84 | 0 | P->inv = oea_s_inverse; |
85 | 0 | P->es = 0.; |
86 | |
|
87 | 0 | return P; |
88 | 0 | } |