OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
proj_cproj.c
Go to the documentation of this file.
1 /*******************************************************************************
2 NAME Projection support routines listed below.
3 
4 PURPOSE: The following functions are included in CPROJ.C.
5 
6  SINCOS: Calculates the sine and cosine.
7  ASINZ: Eliminates roundoff errors.
8  MSFNZ: Computes the constant small m for Oblique Equal Area.
9  QSFNZ: Computes the constant small q for Oblique Equal Area.
10  PHI1Z: Computes phi1 for Albers Conical Equal-Area.
11  PHI2Z: Computes the latitude angle, phi2, for Lambert
12  Conformal Conic and Polar Stereographic.
13  PHI3Z: Computes the latitude, phi3, for Equidistant Conic.
14  PHI4Z: Computes the latitude, phi4, for Polyconic.
15  PAKCZ: Converts a 2 digit alternate packed DMS format to
16  standard packed DMS format.
17  PAKR2DM: Converts radians to 3 digit packed DMS format.
18  TSFNZ: Computes the small t for Lambert Conformal Conic and
19  Polar Stereographic.
20  SIGN: Returns the sign of an argument.
21  ADJUST_LON: Adjusts a longitude angle to range -180 to 180.
22  E0FN, E1FN, E2FN, E3FN:
23  Computes the constants e0,e1,e2,and e3 for
24  calculating the distance along a meridian.
25  E4FN: Computes e4 used for Polar Stereographic.
26  MLFN: Computes M, the distance along a meridian.
27  CALC_UTM_ZONE: Calculates the UTM zone number.
28 
29 PROGRAMMER DATE REASON
30 ---------- ---- ------
31 D. Steinwand, EROS July, 1991 Initial development
32 T. Mittan, EROS May, 1993 Modified from Fortran GCTP for C GCTP
33 S. Nelson, EROS June, 1993 Added inline comments
34 S. Nelson, EROS Nov, 1993 Added loop counter in ADJUST_LON
35 
36  *******************************************************************************/
37 #include "proj_cproj.h"
38 
39 #include <stdint.h>
40 
41 #define MAX_VAL 4
42 #define MAXLONG 2147483647.
43 #define DBLLONG 4.61168601e18
44 
45 /* Function to calculate the sine and cosine in one call. Some computer
46  systems have implemented this function, resulting in a faster implementation
47  than calling each function separately. It is provided here for those
48  computer systems which don`t implement this function
49  ----------------------------------------------------*/
50 #ifndef sun
51 
52 void sincos(val, sin_val, cos_val) double val;
53 double *sin_val;
54 double *cos_val;
55 {
56  *sin_val = sin(val);
57  *cos_val = cos(val);
58  return;
59 }
60 #endif
61 
62 /* function prototypes */
63 void p_error(char *what, char *where);
64 
65 /* Function to eliminate roundoff errors in asin
66 ----------------------------------------------*/
67 double asinz(con)
68 
69 double con;
70 {
71  if (fabs(con) > 1.0) {
72  if (con > 1.0)
73  con = 1.0;
74  else
75  con = -1.0;
76  }
77  return (asin(con));
78 }
79 
80 /* Function to compute the constant small m which is the radius of
81  a parallel of latitude, phi, divided by the semimajor axis.
82 ---------------------------------------------------------------*/
83 double msfnz(eccent, sinphi, cosphi)
84 double eccent;
85 double sinphi;
86 double cosphi;
87 {
88  double con;
89 
90  con = eccent * sinphi;
91  return ((cosphi / (sqrt(1.0 - con * con))));
92 }
93 
94 /* Function to compute constant small q which is the radius of a
95  parallel of latitude, phi, divided by the semimajor axis.
96 ------------------------------------------------------------*/
97 double qsfnz(eccent, sinphi, cosphi)
98 double eccent;
99 double sinphi;
100 double cosphi;
101 {
102  double con;
103 
104  if (eccent > 1.0e-7) {
105  con = eccent * sinphi;
106  return ((1.0 - eccent * eccent) * (sinphi / (1.0 - con * con) - (.5 / eccent) *
107  log((1.0 - con) / (1.0 + con))));
108  } else
109  return (2.0 * sinphi);
110 }
111 
112 /* Function to compute phi1, the latitude for the inverse of the
113  Albers Conical Equal-Area projection.
114 -------------------------------------------*/
115 double phi1z(eccent, qs, flag)
116 double eccent; /* Eccentricity angle in radians */
117 double qs; /* Angle in radians */
118 int32_t *flag; /* Error flag number */
119 {
120  double eccnts;
121  double dphi;
122  double con;
123  double com;
124  double sinpi;
125  double cospi;
126  double phi;
127  double asinz();
128  int32_t i;
129 
130  phi = asinz(.5 * qs);
131  if (eccent < EPSLN)
132  return (phi);
133  eccnts = eccent * eccent;
134  for (i = 1; i <= 25; i++) {
135  sincos(phi, &sinpi, &cospi);
136  con = eccent * sinpi;
137  com = 1.0 - con * con;
138  dphi = .5 * com * com / cospi * (qs / (1.0 - eccnts) - sinpi / com +
139  .5 / eccent * log((1.0 - con) / (1.0 + con)));
140  phi = phi + dphi;
141  if (fabs(dphi) <= 1e-7)
142  return (phi);
143  }
144  p_error("Convergence error", "phi1z-conv");
145  *flag = 001;
146  return (ERROR);
147 }
148 
149 /* Function to compute the latitude angle, phi2, for the inverse of the
150  Lambert Conformal Conic and Polar Stereographic projections.
151 ----------------------------------------------------------------*/
152 double phi2z(eccent, ts, flag)
153 
154 double eccent; /* Spheroid eccentricity */
155 double ts; /* Constant value t */
156 int32_t *flag; /* Error flag number */
157 
158 {
159  double eccnth;
160  double phi;
161  double con;
162  double dphi;
163  double sinpi;
164  int32_t i;
165 
166  flag = 0;
167  eccnth = .5 * eccent;
168  phi = HALF_PI - 2 * atan(ts);
169  for (i = 0; i <= 15; i++) {
170  sinpi = sin(phi);
171  con = eccent * sinpi;
172  dphi = HALF_PI - 2 * atan(ts * (pow(((1.0 - con) / (1.0 + con)), eccnth))) -
173  phi;
174  phi += dphi;
175  if (fabs(dphi) <= .0000000001)
176  return (phi);
177  }
178  p_error("Convergence error", "phi2z-conv");
179  *flag = 002;
180  return (002);
181 }
182 
183 /* Function to compute latitude, phi3, for the inverse of the Equidistant
184  Conic projection.
185 -----------------------------------------------------------------*/
186 double phi3z(ml, e0, e1, e2, e3, flag)
187 
188 double ml; /* Constant */
189 double e0; /* Constant */
190 double e1; /* Constant */
191 double e2; /* Constant */
192 double e3; /* Constant */
193 int32_t *flag; /* Error flag number */
194 
195 {
196  double phi;
197  double dphi;
198  int32_t i;
199 
200  phi = ml;
201  for (i = 0; i < 15; i++) {
202  dphi = (ml + e1 * sin(2.0 * phi) - e2 * sin(4.0 * phi) + e3 * sin(6.0 * phi))
203  / e0 - phi;
204  phi += dphi;
205  if (fabs(dphi) <= .0000000001) {
206  *flag = 0;
207  return (phi);
208  }
209  }
210  p_error("Latitude failed to converge after 15 iterations", "PHI3Z-CONV");
211  *flag = 3;
212  return (3);
213 }
214 
215 /* Function to compute, phi4, the latitude for the inverse of the
216  Polyconic projection.
217 ------------------------------------------------------------*/
218 double phi4z(eccent, e0, e1, e2, e3, a, b, c, phi)
219 
220 double eccent; /* Spheroid eccentricity squared */
221 double e0;
222 double e1;
223 double e2;
224 double e3;
225 double a;
226 double b;
227 double *c;
228 double *phi;
229 {
230  double sinphi;
231  double sin2ph;
232  double tanphi;
233  double ml;
234  double mlp;
235  double con1;
236  double con2;
237  double con3;
238  double dphi;
239  int32_t i;
240 
241  *phi = a;
242  for (i = 1; i <= 15; i++) {
243  sinphi = sin(*phi);
244  tanphi = tan(*phi);
245  *c = tanphi * sqrt(1.0 - eccent * sinphi * sinphi);
246  sin2ph = sin(2.0 * *phi);
247  /*
248  ml = e0 * *phi - e1 * sin2ph + e2 * sin (4.0 * *phi);
249  mlp = e0 - 2.0 * e1 * cos (2.0 * *phi) + 4.0 * e2 *
250  cos (4.0 * *phi);
251  */
252  ml = e0 * *phi - e1 * sin2ph + e2 * sin(4.0 * *phi) - e3 *
253  sin(6.0 * *phi);
254  mlp = e0 - 2.0 * e1 * cos(2.0 * *phi) + 4.0 * e2 *
255  cos(4.0 * *phi) - 6.0 * e3 * cos(6.0 * *phi);
256  con1 = 2.0 * ml + *c * (ml * ml + b) - 2.0 * a * (*c * ml + 1.0);
257  con2 = eccent * sin2ph * (ml * ml + b - 2.0 * a * ml) / (2.0 * *c);
258  con3 = 2.0 * (a - ml) * (*c * mlp - 2.0 / sin2ph) - 2.0 * mlp;
259  dphi = con1 / (con2 + con3);
260  *phi += dphi;
261  if (fabs(dphi) <= .0000000001)
262  return (OK);
263  }
264  p_error("Lattitude failed to converge", "phi4z-conv");
265  return (004);
266 }
267 
268 /* Function to convert 2 digit alternate packed DMS format (+/-)DDDMMSS.SSS
269  to 3 digit standard packed DMS format (+/-)DDDMMMSSS.SSS.
270 -----------------------------------------------------------------*/
271 double pakcz(pak)
272 
273 double pak; /* Angle in alternate packed DMS format */
274 {
275  double con;
276  double secs;
277  int32_t degs, mins;
278  char sgna;
279 
280  sgna = ' ';
281  if (pak < 0.0)
282  sgna = '-';
283  con = fabs(pak);
284  degs = (int32_t) ((con / 10000.0) + .001);
285  con = con - degs * 10000;
286  mins = (int32_t) ((con / 100.0) + .001);
287  secs = con - mins * 100;
288  con = (double) (degs) * 1000000.0 + (double) (mins) * 1000.0 + secs;
289  if (sgna == '-')
290  con = -con;
291  return (con);
292 }
293 
294 /* Function to convert radians to 3 digit packed DMS format (+/-)DDDMMMSSS.SSS
295 ----------------------------------------------------------------------------*/
296 double pakr2dm(pak)
297 
298 double pak; /* Angle in radians */
299 {
300  double con;
301  double secs;
302  int32_t degs, mins;
303  char sgna;
304 
305  sgna = ' ';
306  pak *= R2D;
307  if (pak < 0.0)
308  sgna = '-';
309  con = fabs(pak);
310  degs = (int32_t) (con);
311  con = (con - degs) * 60;
312  mins = (int32_t) con;
313  secs = (con - mins) * 60;
314  con = (double) (degs) * 1000000.0 + (double) (mins) * 1000.0 + secs;
315  if (sgna == '-')
316  con = -con;
317  return (con);
318 }
319 
320 /* Function to compute the constant small t for use in the forward
321  computations in the Lambert Conformal Conic and the Polar
322  Stereographic projections.
323 --------------------------------------------------------------*/
324 double tsfnz(eccent, phi, sinphi)
325 double eccent; /* Eccentricity of the spheroid */
326 double phi; /* Latitude phi */
327 double sinphi; /* Sine of the latitude */
328 {
329  double con;
330  double com;
331 
332  con = eccent * sinphi;
333  com = .5 * eccent;
334  con = pow(((1.0 - con) / (1.0 + con)), com);
335  return (tan(.5 * (HALF_PI - phi)) / con);
336 }
337 
338 /* Function to return the sign of an argument
339  ------------------------------------------*/
340 int sign(x) double x;
341 {
342  if (x < 0.0) return (-1);
343  else return (1);
344 }
345 
346 /* Function to adjust a longitude angle to range from -180 to 180 radians
347  added if statments
348  -----------------------------------------------------------------------*/
349 double adjust_lon(x)
350 
351 double x; /* Angle in radians */
352 {
353  /* Will disable this to prevent wrap-around: 23-JUL-97, Jim Ray (UMD/GSFC)
354  for(;;)
355  {
356  if (fabs(x)<=PI)
357  break;
358  else
359  if (((int32_t) fabs(x / PI)) < 2)
360  x = x-(sign(x) *TWO_PI);
361 
362  else
363  if (((int32_t) fabs(x / TWO_PI)) < MAXLONG)
364  {
365  x = x-(((int32_t)(x / TWO_PI))*TWO_PI);
366  }
367  else
368  if (((int32_t) fabs(x / (MAXLONG * TWO_PI))) < MAXLONG)
369  {
370  x = x-(((int32_t)(x / (MAXLONG * TWO_PI))) * (TWO_PI * MAXLONG));
371  }
372  else
373  if (((int32_t) fabs(x / (DBLLONG * TWO_PI))) < MAXLONG)
374  {
375  x = x-(((int32_t)(x / (DBLLONG * TWO_PI))) * (TWO_PI * DBLLONG));
376  }
377  else
378  x = x-(sign(x) *TWO_PI);
379 
380  count++;
381  if (count > MAX_VAL)
382  break;
383  }
384  */
385  return (x);
386 }
387 
388 /* Functions to compute the constants e0, e1, e2, and e3 which are used
389  in a series for calculating the distance along a meridian. The
390  input x represents the eccentricity squared.
391 ----------------------------------------------------------------*/
392 double e0fn(x) double x;
393 {
394  return (1.0 - 0.25 * x * (1.0 + x / 16.0 * (3.0 + 1.25 * x)));
395 }
396 
397 double e1fn(x) double x;
398 {
399  return (0.375 * x * (1.0 + 0.25 * x * (1.0 + 0.46875 * x)));
400 }
401 
402 double e2fn(x) double x;
403 {
404  return (0.05859375 * x * x * (1.0 + 0.75 * x));
405 }
406 
407 double e3fn(x) double x;
408 {
409  return (x * x * x * (35.0 / 3072.0));
410 }
411 
412 /* Function to compute the constant e4 from the input of the eccentricity
413  of the spheroid, x. This constant is used in the Polar Stereographic
414  projection.
415 --------------------------------------------------------------------*/
416 double e4fn(x)
417 double x;
418 {
419  double con;
420  double com;
421  con = 1.0 + x;
422  com = 1.0 - x;
423  return (sqrt((pow(con, con))*(pow(com, com))));
424 }
425 
426 /* Function computes the value of M which is the distance along a meridian
427  from the Equator to latitude phi.
428 ------------------------------------------------*/
429 double mlfn(e0, e1, e2, e3, phi) double e0, e1, e2, e3, phi;
430 {
431  return (e0 * phi - e1 * sin(2.0 * phi) + e2 * sin(4.0 * phi) - e3 * sin(6.0 * phi));
432 }
433 
434 /* Function to calculate UTM zone number--NOTE Longitude entered in DEGREES!!!
435  ---------------------------------------------------------------------------*/
436 int calc_utm_zone(lon) double lon;
437 {
438  return ((int32_t) (((lon + 180.0) / 6.0) + 1.0));
439 }
int sign(double x)
Definition: proj_cproj.c:340
double e4fn(double x)
Definition: proj_cproj.c:416
double mlfn(double e0, double e1, double e2, double e3, double phi)
Definition: proj_cproj.c:429
void sincos(double val, double *sin_val, double *cos_val)
Definition: proj_cproj.c:52
double phi1z(double eccent, double qs, int32_t *flag)
Definition: proj_cproj.c:115
int calc_utm_zone(double lon)
Definition: proj_cproj.c:436
double e0fn(double x)
Definition: proj_cproj.c:392
double adjust_lon(double x)
Definition: proj_cproj.c:349
double qsfnz(double eccent, double sinphi, double cosphi)
Definition: proj_cproj.c:97
double phi2z(double eccent, double ts, int32_t *flag)
Definition: proj_cproj.c:152
double e2fn(double x)
Definition: proj_cproj.c:402
double e1fn(double x)
Definition: proj_cproj.c:397
double pakcz(double pak)
Definition: proj_cproj.c:271
double e3fn(double x)
Definition: proj_cproj.c:407
#define HALF_PI
Definition: proj_define.h:84
double msfnz(double eccent, double sinphi, double cosphi)
Definition: proj_cproj.c:83
double phi4z(double eccent, double e0, double e1, double e2, double e3, double a, double b, double *c, double *phi)
Definition: proj_cproj.c:218
#define OK
Definition: ancil.h:30
integer, parameter double
double tsfnz(double eccent, double phi, double sinphi)
Definition: proj_cproj.c:324
Definition: __init__.py:1
data_t b[NROOTS+1]
Definition: decode_rs.h:77
void p_error(char *what, char *where)
Definition: proj_report.c:277
double phi3z(double ml, double e0, double e1, double e2, double e3, int32_t *flag)
Definition: proj_cproj.c:186
#define fabs(a)
Definition: misc.h:93
#define R2D
Definition: proj_define.h:87
float * lon
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude resolving resolving GSFcd00179 Corrected handling of fill values for[Sensor|Solar][Zenith|Azimuth] resolving MODxl01751 Changed to validate LUT version against a value retrieved from the resolving MODxl02056 Changed to calculate Solar Diffuser angles without adjustment for estimated post launch changes in the MODIS orientation relative to incidentally resolving defects MODxl01766 Also resolves MODxl01947 Changed to ignore fill values in SCI_ABNORM and SCI_STATE rather than treating them as resolving MODxl01780 Changed to use spacecraft ancillary data to recognise when the mirror encoder data is being set by side A or side B and to change calculations accordingly This removes the need for seperate LUTs for Side A and Side B data it makes the new LUTs incompatible with older versions of the and vice versa Also resolves MODxl01685 A more robust GRing algorithm is being which will create a non default GRing anytime there s even a single geolocated pixel in a granule Removed obsolete messages from seed as required for compatibility with version of the SDP toolkit Corrected test output file names to end in per delivery and then split off a new MYD_PR03 pcf file for Aqua Added AssociatedPlatformInstrumentSensor to the inventory metadata in MOD01 mcf and MOD03 mcf Created new versions named MYD01 mcf and MYD03 where AssociatedPlatformShortName is rather than Terra The program itself has been changed to read the Satellite Instrument validate it against the input L1A and LUT and to use it determine the correct files to retrieve the ephemeris and attitude data from Changed to produce a LocalGranuleID starting with MYD03 if run on Aqua data Added the Scan Type file attribute to the Geolocation copied from the L1A and attitude_angels to radians rather than degrees The accumulation of Cumulated gflags was moved from GEO_validate_earth_location c to GEO_locate_one_scan c
Definition: HISTORY.txt:464
double pakr2dm(double pak)
Definition: proj_cproj.c:296
int i
Definition: decode_rs.h:71
msiBandIdx val
Definition: l1c_msi.cpp:34
PGE01 indicating that PGE02 PGE01 V6 for and PGE01 V2 for MOD03 were used to produce the granule By convention adopted in all MODIS Terra PGE02 code versions are The fourth digit of the PGE02 version denotes the LUT version used to produce the granule The source of the metadata environment variable ProcessingCenter was changed from a QA LUT value to the Process Configuration A sign used in error in the second order term was changed to a
Definition: HISTORY.txt:424
double asinz(double con)
Definition: proj_cproj.c:67
#define ERROR
Definition: ancil.h:24
#define EPSLN
Definition: proj_define.h:86