1 /******************************************************************************
2 * $Id$
3 *
4 * Project: SCH Coordinate system
5 * Purpose: Implementation of SCH Coordinate system
6 * References :
7 * 1. Hensley. Scott. SCH Coordinates and various transformations. June 15, 2000.
8 * 2. Buckley, Sean Monroe. Radar interferometry measurement of land subsidence. 2000..
9 * PhD Thesis. UT Austin. (Appendix)
10 * 3. Hensley, Scott, Elaine Chapin, and T. Michel. "Improved processing of AIRSAR
11 * data based on the GeoSAR processor." Airsar earth science and applications
12 * workshop, March. 2002. (http://airsar.jpl.nasa.gov/documents/workshop2002/papers/T3.pdf)
13 *
14 * Author: Piyush Agram (piyush.agram@jpl.nasa.gov)
15 * Copyright (c) 2015 California Institute of Technology.
16 * Government sponsorship acknowledged.
17 *
18 * NOTE: The SCH coordinate system is a sensor aligned coordinate system
19 * developed at JPL for radar mapping missions. Details pertaining to the
20 * coordinate system have been release in the public domain (see references above).
21 * This code is an independent implementation of the SCH coordinate system
22 * that conforms to the PROJ.4 conventions and uses the details presented in these
23 * publicly released documents. All credit for the development of the coordinate
24 * system and its use should be directed towards the original developers at JPL.
25 ******************************************************************************
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
29 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
31 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
32 * DEALINGS IN THE SOFTWARE.
33 ****************************************************************************/
34
35 #define PJ_LIB__
36 #include <projects.h>
37 #include "geocent.h"
38
39 struct pj_opaque {
40 double plat; /*Peg Latitude */
41 double plon; /*Peg Longitude*/
42 double phdg; /*Peg heading */
43 double h0; /*Average altitude */
44 double transMat[9];
45 double xyzoff[3];
46 double rcurv;
47 GeocentricInfo sph;
48 GeocentricInfo elp_0;
49 };
50
51 PROJ_HEAD(sch, "Spherical Cross-track Height") "\n\tMisc\n\tplat_0 = ,plon_0 = , phdg_0 = ,[h_0 = ]";
52
inverse3d(XYZ xyz,PJ * P)53 static LPZ inverse3d(XYZ xyz, PJ *P) {
54 LPZ lpz = {0.0, 0.0, 0.0};
55 struct pj_opaque *Q = P->opaque;
56 double temp[3];
57 double pxyz[3];
58
59 /* Local lat,lon using radius */
60 pxyz[0] = xyz.y * P->a / Q->rcurv;
61 pxyz[1] = xyz.x * P->a / Q->rcurv;
62 pxyz[2] = xyz.z;
63
64 if( pj_Convert_Geodetic_To_Geocentric( &(Q->sph), pxyz[0], pxyz[1], pxyz[2],
65 temp, temp+1, temp+2) != 0)
66 I3_ERROR;
67
68 /* Apply rotation */
69 pxyz[0] = Q->transMat[0] * temp[0] + Q->transMat[1] * temp[1] + Q->transMat[2] * temp[2];
70 pxyz[1] = Q->transMat[3] * temp[0] + Q->transMat[4] * temp[1] + Q->transMat[5] * temp[2];
71 pxyz[2] = Q->transMat[6] * temp[0] + Q->transMat[7] * temp[1] + Q->transMat[8] * temp[2];
72
73 /* Apply offset */
74 pxyz[0] += Q->xyzoff[0];
75 pxyz[1] += Q->xyzoff[1];
76 pxyz[2] += Q->xyzoff[2];
77
78 /* Convert geocentric coordinates to lat lon */
79 pj_Convert_Geocentric_To_Geodetic( &(Q->elp_0), pxyz[0], pxyz[1], pxyz[2],
80 temp, temp+1, temp+2);
81
82
83 lpz.lam = temp[1] ;
84 lpz.phi = temp[0] ;
85 lpz.z = temp[2];
86
87 #if 0
88 printf("INVERSE: \n");
89 printf("XYZ: %f %f %f \n", xyz.x, xyz.y, xyz.z);
90 printf("LPZ: %f %f %f \n", lpz.lam, lpz.phi, lpz.z);
91 #endif
92 return lpz;
93 }
94
forward3d(LPZ lpz,PJ * P)95 static XYZ forward3d(LPZ lpz, PJ *P) {
96 XYZ xyz = {0.0, 0.0, 0.0};
97 struct pj_opaque *Q = P->opaque;
98 double temp[3];
99 double pxyz[3];
100
101
102 /* Convert lat lon to geocentric coordinates */
103 if( pj_Convert_Geodetic_To_Geocentric( &(Q->elp_0), lpz.phi, lpz.lam, lpz.z,
104 temp, temp+1, temp+2 ) != 0 )
105 F3_ERROR;
106
107
108 /* Adjust for offset */
109 temp[0] -= Q->xyzoff[0];
110 temp[1] -= Q->xyzoff[1];
111 temp[2] -= Q->xyzoff[2];
112
113
114 /* Apply rotation */
115 pxyz[0] = Q->transMat[0] * temp[0] + Q->transMat[3] * temp[1] + Q->transMat[6] * temp[2];
116 pxyz[1] = Q->transMat[1] * temp[0] + Q->transMat[4] * temp[1] + Q->transMat[7] * temp[2];
117 pxyz[2] = Q->transMat[2] * temp[0] + Q->transMat[5] * temp[1] + Q->transMat[8] * temp[2];
118
119 /* Convert to local lat,lon */
120 pj_Convert_Geocentric_To_Geodetic( &(Q->sph), pxyz[0], pxyz[1], pxyz[2],
121 temp, temp+1, temp+2);
122
123
124 /* Scale by radius */
125 xyz.x = temp[1] * Q->rcurv / P->a;
126 xyz.y = temp[0] * Q->rcurv / P->a;
127 xyz.z = temp[2];
128
129 #if 0
130 printf("FORWARD: \n");
131 printf("LPZ: %f %f %f \n", lpz.lam, lpz.phi, lpz.z);
132 printf("XYZ: %f %f %f \n", xyz.x, xyz.y, xyz.z);
133 #endif
134 return xyz;
135 }
136
137
freeup_new(PJ * P)138 static void *freeup_new (PJ *P) { /* Destructor */
139 if (0==P)
140 return 0;
141 if (0==P->opaque)
142 return pj_dealloc (P);
143
144 pj_dealloc (P->opaque);
145 return pj_dealloc(P);
146 }
147
freeup(PJ * P)148 static void freeup (PJ *P) {
149 freeup_new (P);
150 return;
151 }
152
setup(PJ * P)153 static PJ *setup(PJ *P) { /* general initialization */
154 struct pj_opaque *Q = P->opaque;
155 double reast, rnorth;
156 double chdg, shdg;
157 double clt, slt;
158 double clo, slo;
159 double temp;
160 double pxyz[3];
161
162 temp = P->a * sqrt(1.0 - P->es);
163
164 /* Setup original geocentric system */
165 if ( pj_Set_Geocentric_Parameters(&(Q->elp_0), P->a, temp) != 0)
166 E_ERROR(-37);
167
168 clt = cos(Q->plat);
169 slt = sin(Q->plat);
170 clo = cos(Q->plon);
171 slo = sin(Q->plon);
172
173 /* Estimate the radius of curvature for given peg */
174 temp = sqrt(1.0 - (P->es) * slt * slt);
175 reast = (P->a)/temp;
176 rnorth = (P->a) * (1.0 - (P->es))/pow(temp,3);
177
178 chdg = cos(Q->phdg);
179 shdg = sin(Q->phdg);
180
181 Q->rcurv = Q->h0 + (reast*rnorth)/(reast * chdg * chdg + rnorth * shdg * shdg);
182
183 #if 0
184 printf("North Radius: %f \n", rnorth);
185 printf("East Radius: %f \n", reast);
186 printf("Effective Radius: %f \n", Q->rcurv);
187 #endif
188
189 /* Set up local sphere at the given peg point */
190 if ( pj_Set_Geocentric_Parameters(&(Q->sph), Q->rcurv, Q->rcurv) != 0)
191 E_ERROR(-37);
192
193 /* Set up the transformation matrices */
194 Q->transMat[0] = clt * clo;
195 Q->transMat[1] = -shdg*slo - slt*clo * chdg;
196 Q->transMat[2] = slo*chdg - slt*clo*shdg;
197 Q->transMat[3] = clt*slo;
198 Q->transMat[4] = clo*shdg - slt*slo*chdg;
199 Q->transMat[5] = -clo*chdg - slt*slo*shdg;
200 Q->transMat[6] = slt;
201 Q->transMat[7] = clt*chdg;
202 Q->transMat[8] = clt*shdg;
203
204
205 if( pj_Convert_Geodetic_To_Geocentric( &(Q->elp_0), Q->plat, Q->plon, Q->h0,
206 pxyz, pxyz+1, pxyz+2 ) != 0 )
207 {
208 E_ERROR(-14)
209 }
210
211
212 Q->xyzoff[0] = pxyz[0] - (Q->rcurv) * clt * clo;
213 Q->xyzoff[1] = pxyz[1] - (Q->rcurv) * clt * slo;
214 Q->xyzoff[2] = pxyz[2] - (Q->rcurv) * slt;
215
216 #if 0
217 printf("Offset: %f %f %f \n", Q->xyzoff[0], Q->xyzoff[1], Q->xyzoff[2]);
218 #endif
219
220 P->fwd3d = forward3d;
221 P->inv3d = inverse3d;
222 return P;
223 }
224
225
PROJECTION(sch)226 PJ *PROJECTION(sch) {
227 struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque));
228 if (0==Q)
229 return freeup_new (P);
230 P->opaque = Q;
231
232 Q->h0 = 0.0;
233
234 /* Check if peg latitude was defined */
235 if (pj_param(P->ctx, P->params, "tplat_0").i)
236 Q->plat = pj_param(P->ctx, P->params, "rplat_0").f;
237 else
238 E_ERROR(-37);
239
240 /* Check if peg longitude was defined */
241 if (pj_param(P->ctx, P->params, "tplon_0").i)
242 Q->plon = pj_param(P->ctx, P->params, "rplon_0").f;
243 else
244 E_ERROR(-37);
245
246 /* Check if peg latitude is defined */
247 if (pj_param(P->ctx, P->params, "tphdg_0").i)
248 Q->phdg = pj_param(P->ctx, P->params, "rphdg_0").f;
249 else
250 E_ERROR(-37);
251
252
253 /* Check if average height was defined - If so read it in */
254 if (pj_param(P->ctx, P->params, "th_0").i)
255 Q->h0 = pj_param(P->ctx, P->params, "dh_0").f;
256
257 /* Completed reading in the projection parameters */
258 #if 0
259 printf("PSA: Lat = %f Lon = %f Hdg = %f \n", Q->plat, Q->plon, Q->phdg);
260 #endif
261
262 return setup(P);
263 }
264
265 /* Skipping sef-test since the test system is not capable of handling
266 * 3D coordinate systems for the time being. Relying on tests in ../nad/
267 */
pj_sch_selftest(void)268 int pj_sch_selftest (void) {return 0;}
269