/src/PROJ/src/projections/chamb.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 | | typedef struct { |
10 | | double r, Az; |
11 | | } VECT; |
12 | | namespace { // anonymous namespace |
13 | | struct pj_chamb { |
14 | | struct { /* control point data */ |
15 | | double phi, lam; |
16 | | double cosphi, sinphi; |
17 | | VECT v; |
18 | | PJ_XY p; |
19 | | } c[3]; |
20 | | PJ_XY p; |
21 | | double beta_0, beta_1, beta_2; |
22 | | }; |
23 | | } // anonymous namespace |
24 | | |
25 | | PROJ_HEAD(chamb, "Chamberlin Trimetric") |
26 | | "\n\tMisc Sph, no inv" |
27 | | "\n\tlat_1= lon_1= lat_2= lon_2= lat_3= lon_3="; |
28 | | |
29 | | #include <stdio.h> |
30 | 0 | #define THIRD 0.333333333333333333 |
31 | 54 | #define TOL 1e-9 |
32 | | |
33 | | /* distance and azimuth from point 1 to point 2 */ |
34 | | static VECT vect(PJ_CONTEXT *ctx, double dphi, double c1, double s1, double c2, |
35 | 54 | double s2, double dlam) { |
36 | 54 | VECT v; |
37 | 54 | double cdl, dp, dl; |
38 | | |
39 | 54 | cdl = cos(dlam); |
40 | 54 | if (fabs(dphi) > 1. || fabs(dlam) > 1.) |
41 | 17 | v.r = aacos(ctx, s1 * s2 + c1 * c2 * cdl); |
42 | 37 | else { /* more accurate for smaller distances */ |
43 | 37 | dp = sin(.5 * dphi); |
44 | 37 | dl = sin(.5 * dlam); |
45 | 37 | v.r = 2. * aasin(ctx, sqrt(dp * dp + c1 * c2 * dl * dl)); |
46 | 37 | } |
47 | 54 | if (fabs(v.r) > TOL) |
48 | 51 | v.Az = atan2(c2 * sin(dlam), c1 * s2 - s1 * c2 * cdl); |
49 | 3 | else |
50 | 3 | v.r = v.Az = 0.; |
51 | 54 | return v; |
52 | 54 | } |
53 | | |
54 | | /* law of cosines */ |
55 | 32 | static double lc(PJ_CONTEXT *ctx, double b, double c, double a) { |
56 | 32 | return aacos(ctx, .5 * (b * b + c * c - a * a) / (b * c)); |
57 | 32 | } |
58 | | |
59 | 0 | static PJ_XY chamb_s_forward(PJ_LP lp, PJ *P) { /* Spheroidal, forward */ |
60 | 0 | PJ_XY xy; |
61 | 0 | struct pj_chamb *Q = static_cast<struct pj_chamb *>(P->opaque); |
62 | 0 | double sinphi, cosphi, a; |
63 | 0 | VECT v[3]; |
64 | 0 | int i, j; |
65 | |
|
66 | 0 | sinphi = sin(lp.phi); |
67 | 0 | cosphi = cos(lp.phi); |
68 | 0 | for (i = 0; i < 3; ++i) { /* dist/azimiths from control */ |
69 | 0 | v[i] = vect(P->ctx, lp.phi - Q->c[i].phi, Q->c[i].cosphi, |
70 | 0 | Q->c[i].sinphi, cosphi, sinphi, lp.lam - Q->c[i].lam); |
71 | 0 | if (v[i].r == 0.0) |
72 | 0 | break; |
73 | 0 | v[i].Az = adjlon(v[i].Az - Q->c[i].v.Az); |
74 | 0 | } |
75 | 0 | if (i < 3) /* current point at control point */ |
76 | 0 | xy = Q->c[i].p; |
77 | 0 | else { /* point mean of intercepts */ |
78 | 0 | xy = Q->p; |
79 | 0 | for (i = 0; i < 3; ++i) { |
80 | 0 | j = i == 2 ? 0 : i + 1; |
81 | 0 | a = lc(P->ctx, Q->c[i].v.r, v[i].r, v[j].r); |
82 | 0 | if (v[i].Az < 0.) |
83 | 0 | a = -a; |
84 | 0 | if (!i) { /* coord comp unique to each arc */ |
85 | 0 | xy.x += v[i].r * cos(a); |
86 | 0 | xy.y -= v[i].r * sin(a); |
87 | 0 | } else if (i == 1) { |
88 | 0 | a = Q->beta_1 - a; |
89 | 0 | xy.x -= v[i].r * cos(a); |
90 | 0 | xy.y -= v[i].r * sin(a); |
91 | 0 | } else { |
92 | 0 | a = Q->beta_2 - a; |
93 | 0 | xy.x += v[i].r * cos(a); |
94 | 0 | xy.y += v[i].r * sin(a); |
95 | 0 | } |
96 | 0 | } |
97 | 0 | xy.x *= THIRD; /* mean of arc intercepts */ |
98 | 0 | xy.y *= THIRD; |
99 | 0 | } |
100 | 0 | return xy; |
101 | 0 | } |
102 | | |
103 | 19 | PJ *PJ_PROJECTION(chamb) { |
104 | 19 | int i, j; |
105 | 19 | char line[10]; |
106 | 19 | struct pj_chamb *Q = |
107 | 19 | static_cast<struct pj_chamb *>(calloc(1, sizeof(struct pj_chamb))); |
108 | 19 | if (nullptr == Q) |
109 | 0 | return pj_default_destructor(P, PROJ_ERR_OTHER /*ENOMEM*/); |
110 | 19 | P->opaque = Q; |
111 | | |
112 | 76 | for (i = 0; i < 3; ++i) { /* get control point locations */ |
113 | 57 | (void)snprintf(line, sizeof(line), "rlat_%d", i + 1); |
114 | 57 | Q->c[i].phi = pj_param(P->ctx, P->params, line).f; |
115 | 57 | (void)snprintf(line, sizeof(line), "rlon_%d", i + 1); |
116 | 57 | Q->c[i].lam = pj_param(P->ctx, P->params, line).f; |
117 | 57 | Q->c[i].lam = adjlon(Q->c[i].lam - P->lam0); |
118 | 57 | Q->c[i].cosphi = cos(Q->c[i].phi); |
119 | 57 | Q->c[i].sinphi = sin(Q->c[i].phi); |
120 | 57 | } |
121 | 70 | for (i = 0; i < 3; ++i) { /* inter ctl pt. distances and azimuths */ |
122 | 54 | j = i == 2 ? 0 : i + 1; |
123 | 54 | Q->c[i].v = vect(P->ctx, Q->c[j].phi - Q->c[i].phi, Q->c[i].cosphi, |
124 | 54 | Q->c[i].sinphi, Q->c[j].cosphi, Q->c[j].sinphi, |
125 | 54 | Q->c[j].lam - Q->c[i].lam); |
126 | 54 | if (Q->c[i].v.r == 0.0) { |
127 | 3 | proj_log_error( |
128 | 3 | P, |
129 | 3 | _("Invalid value for control points: they should be distinct")); |
130 | 3 | return pj_default_destructor(P, |
131 | 3 | PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE); |
132 | 3 | } |
133 | | /* co-linearity problem ignored for now */ |
134 | 54 | } |
135 | 16 | Q->beta_0 = lc(P->ctx, Q->c[0].v.r, Q->c[2].v.r, Q->c[1].v.r); |
136 | 16 | Q->beta_1 = lc(P->ctx, Q->c[0].v.r, Q->c[1].v.r, Q->c[2].v.r); |
137 | 16 | Q->beta_2 = M_PI - Q->beta_0; |
138 | 16 | Q->c[0].p.y = Q->c[2].v.r * sin(Q->beta_0); |
139 | 16 | Q->c[1].p.y = Q->c[0].p.y; |
140 | 16 | Q->p.y = 2. * Q->c[0].p.y; |
141 | 16 | Q->c[2].p.y = 0.; |
142 | 16 | Q->c[1].p.x = 0.5 * Q->c[0].v.r; |
143 | 16 | Q->c[0].p.x = -Q->c[1].p.x; |
144 | 16 | Q->c[2].p.x = Q->c[0].p.x + Q->c[2].v.r * cos(Q->beta_0); |
145 | 16 | Q->p.x = Q->c[2].p.x; |
146 | | |
147 | 16 | P->es = 0.; |
148 | 16 | P->fwd = chamb_s_forward; |
149 | | |
150 | 16 | return P; |
151 | 19 | } |
152 | | |
153 | | #undef THIRD |
154 | | #undef TOL |