/src/PROJ/src/projections/calcofi.cpp
Line | Count | Source |
1 | | |
2 | | |
3 | | #include <math.h> |
4 | | |
5 | | #include "proj.h" |
6 | | #include "proj_internal.h" |
7 | | |
8 | | PROJ_HEAD(calcofi, "Cal Coop Ocean Fish Invest Lines/Stations") |
9 | | "\n\tCyl, Sph&Ell"; |
10 | | |
11 | | /* Conversions for the California Cooperative Oceanic Fisheries Investigations |
12 | | Line/Station coordinate system following the algorithm of: |
13 | | Eber, L.E., and R.P. Hewitt. 1979. Conversion algorithms for the CalCOFI |
14 | | station grid. California Cooperative Oceanic Fisheries Investigations Reports |
15 | | 20:135-137. (corrected for typographical errors). |
16 | | http://www.calcofi.org/publications/calcofireports/v20/Vol_20_Eber___Hewitt.pdf |
17 | | They assume 1 unit of CalCOFI Line == 1/5 degree in longitude or |
18 | | meridional units at reference point O, and similarly 1 unit of CalCOFI |
19 | | Station == 1/15 of a degree at O. |
20 | | By convention, CalCOFI Line/Station conversions use Clarke 1866 but we use |
21 | | whatever ellipsoid is provided. */ |
22 | | |
23 | 7.56k | #define EPS10 1.e-10 |
24 | 7.56k | #define DEG_TO_LINE 5 |
25 | 7.56k | #define DEG_TO_STATION 15 |
26 | 0 | #define LINE_TO_RAD 0.0034906585039886592 |
27 | 0 | #define STATION_TO_RAD 0.0011635528346628863 |
28 | 7.56k | #define PT_O_LINE 80 /* reference point O is at line 80, */ |
29 | 7.56k | #define PT_O_STATION 60 /* station 60, */ |
30 | 7.56k | #define PT_O_LAMBDA -2.1144663887911301 /* long -121.15 and */ |
31 | 22.6k | #define PT_O_PHI 0.59602993955606354 /* lat 34.15 */ |
32 | 37.8k | #define ROTATION_ANGLE 0.52359877559829882 /*CalCOFI angle of 30 deg in rad */ |
33 | | |
34 | 7.56k | static PJ_XY calcofi_e_forward(PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ |
35 | 7.56k | PJ_XY xy = {0.0, 0.0}; |
36 | 7.56k | double oy; /* pt O y value in Mercator */ |
37 | 7.56k | double l1; /* l1 and l2 are distances calculated using trig that sum |
38 | | to the east/west distance between point O and point xy */ |
39 | 7.56k | double l2; |
40 | 7.56k | double ry; /* r is the point on the same station as o (60) and the same |
41 | | line as xy xy, r, o form a right triangle */ |
42 | | |
43 | 7.56k | if (fabs(fabs(lp.phi) - M_HALFPI) <= EPS10) { |
44 | 0 | proj_errno_set(P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN); |
45 | 0 | return xy; |
46 | 0 | } |
47 | | |
48 | 7.56k | xy.x = lp.lam; |
49 | 7.56k | xy.y = -log(pj_tsfn(lp.phi, sin(lp.phi), P->e)); /* Mercator transform xy*/ |
50 | 7.56k | oy = -log(pj_tsfn(PT_O_PHI, sin(PT_O_PHI), P->e)); |
51 | 7.56k | l1 = (xy.y - oy) * tan(ROTATION_ANGLE); |
52 | 7.56k | l2 = -xy.x - l1 + PT_O_LAMBDA; |
53 | 7.56k | ry = l2 * cos(ROTATION_ANGLE) * sin(ROTATION_ANGLE) + xy.y; |
54 | 7.56k | ry = pj_phi2(P->ctx, exp(-ry), P->e); /*inverse Mercator*/ |
55 | 7.56k | xy.x = PT_O_LINE - |
56 | 7.56k | RAD_TO_DEG * (ry - PT_O_PHI) * DEG_TO_LINE / cos(ROTATION_ANGLE); |
57 | 7.56k | xy.y = PT_O_STATION + |
58 | 7.56k | RAD_TO_DEG * (ry - lp.phi) * DEG_TO_STATION / sin(ROTATION_ANGLE); |
59 | | /* set a = 1, x0 = 0, and y0 = 0 so that no further unit adjustments |
60 | | are done */ |
61 | | |
62 | 7.56k | return xy; |
63 | 7.56k | } |
64 | | |
65 | 0 | static PJ_XY calcofi_s_forward(PJ_LP lp, PJ *P) { /* Spheroidal, forward */ |
66 | 0 | PJ_XY xy = {0.0, 0.0}; |
67 | 0 | double oy; |
68 | 0 | double l1; |
69 | 0 | double l2; |
70 | 0 | double ry; |
71 | 0 | if (fabs(fabs(lp.phi) - M_HALFPI) <= EPS10) { |
72 | 0 | proj_errno_set(P, PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN); |
73 | 0 | return xy; |
74 | 0 | } |
75 | 0 | xy.x = lp.lam; |
76 | 0 | xy.y = log(tan(M_FORTPI + .5 * lp.phi)); |
77 | 0 | oy = log(tan(M_FORTPI + .5 * PT_O_PHI)); |
78 | 0 | l1 = (xy.y - oy) * tan(ROTATION_ANGLE); |
79 | 0 | l2 = -xy.x - l1 + PT_O_LAMBDA; |
80 | 0 | ry = l2 * cos(ROTATION_ANGLE) * sin(ROTATION_ANGLE) + xy.y; |
81 | 0 | ry = M_HALFPI - 2. * atan(exp(-ry)); |
82 | 0 | xy.x = PT_O_LINE - |
83 | 0 | RAD_TO_DEG * (ry - PT_O_PHI) * DEG_TO_LINE / cos(ROTATION_ANGLE); |
84 | 0 | xy.y = PT_O_STATION + |
85 | 0 | RAD_TO_DEG * (ry - lp.phi) * DEG_TO_STATION / sin(ROTATION_ANGLE); |
86 | |
|
87 | 0 | return xy; |
88 | 0 | } |
89 | | |
90 | 0 | static PJ_LP calcofi_e_inverse(PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ |
91 | 0 | PJ_LP lp = {0.0, 0.0}; |
92 | 0 | double ry; /* y value of point r */ |
93 | 0 | double oymctr; /* Mercator-transformed y value of point O */ |
94 | 0 | double rymctr; /* Mercator-transformed ry */ |
95 | 0 | double xymctr; /* Mercator-transformed xy.y */ |
96 | 0 | double l1; |
97 | 0 | double l2; |
98 | |
|
99 | 0 | ry = PT_O_PHI - LINE_TO_RAD * (xy.x - PT_O_LINE) * cos(ROTATION_ANGLE); |
100 | 0 | lp.phi = ry - STATION_TO_RAD * (xy.y - PT_O_STATION) * sin(ROTATION_ANGLE); |
101 | 0 | oymctr = -log(pj_tsfn(PT_O_PHI, sin(PT_O_PHI), P->e)); |
102 | 0 | rymctr = -log(pj_tsfn(ry, sin(ry), P->e)); |
103 | 0 | xymctr = -log(pj_tsfn(lp.phi, sin(lp.phi), P->e)); |
104 | 0 | l1 = (xymctr - oymctr) * tan(ROTATION_ANGLE); |
105 | 0 | l2 = (rymctr - xymctr) / (cos(ROTATION_ANGLE) * sin(ROTATION_ANGLE)); |
106 | 0 | lp.lam = PT_O_LAMBDA - (l1 + l2); |
107 | |
|
108 | 0 | return lp; |
109 | 0 | } |
110 | | |
111 | 0 | static PJ_LP calcofi_s_inverse(PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ |
112 | 0 | PJ_LP lp = {0.0, 0.0}; |
113 | 0 | double ry; |
114 | 0 | double oymctr; |
115 | 0 | double rymctr; |
116 | 0 | double xymctr; |
117 | 0 | double l1; |
118 | 0 | double l2; |
119 | 0 | (void)P; |
120 | |
|
121 | 0 | ry = PT_O_PHI - LINE_TO_RAD * (xy.x - PT_O_LINE) * cos(ROTATION_ANGLE); |
122 | 0 | lp.phi = ry - STATION_TO_RAD * (xy.y - PT_O_STATION) * sin(ROTATION_ANGLE); |
123 | 0 | oymctr = log(tan(M_FORTPI + .5 * PT_O_PHI)); |
124 | 0 | rymctr = log(tan(M_FORTPI + .5 * ry)); |
125 | 0 | xymctr = log(tan(M_FORTPI + .5 * lp.phi)); |
126 | 0 | l1 = (xymctr - oymctr) * tan(ROTATION_ANGLE); |
127 | 0 | l2 = (rymctr - xymctr) / (cos(ROTATION_ANGLE) * sin(ROTATION_ANGLE)); |
128 | 0 | lp.lam = PT_O_LAMBDA - (l1 + l2); |
129 | |
|
130 | 0 | return lp; |
131 | 0 | } |
132 | | |
133 | 117 | PJ *PJ_PROJECTION(calcofi) { |
134 | 117 | P->opaque = nullptr; |
135 | | |
136 | | /* if the user has specified +lon_0 or +k0 for some reason, |
137 | | we're going to ignore it so that xy is consistent with point O */ |
138 | 117 | P->lam0 = 0; |
139 | 117 | P->ra = 1; |
140 | 117 | P->a = 1; |
141 | 117 | P->x0 = 0; |
142 | 117 | P->y0 = 0; |
143 | 117 | P->over = 1; |
144 | | |
145 | 117 | if (P->es != 0.0) { /* ellipsoid */ |
146 | 112 | P->inv = calcofi_e_inverse; |
147 | 112 | P->fwd = calcofi_e_forward; |
148 | 112 | } else { /* sphere */ |
149 | 5 | P->inv = calcofi_s_inverse; |
150 | 5 | P->fwd = calcofi_s_forward; |
151 | 5 | } |
152 | 117 | return P; |
153 | 117 | } |