OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
state_plane.c
Go to the documentation of this file.
1 /*******************************************************************************
2 Name: STATE PLANE
3 
4 Purpose: Provides the transformations between Easting/Northing and longitude/
5  latitude for the state plane projection. The Easting and Northing
6  values are in meters. The longitude and latitude are in radians.
7 
8 Notes:
9 - The "state plane" projection is really nothing more than a way to use a
10  "zone" to indicate one of 134 pre-defined projections with different
11  projection parameters. The "zones" pick between the Transverse Mercator,
12  Lambert Conformal Conic, Polyconic, and Oblique Mercator projections.
13 
14 - This is implemented by creating a child projection transformation and
15  tracking it in this module.
16 
17 Algorithm References
18 
19 1. Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
20  Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
21  State Government Printing Office, Washington D.C., 1987.
22 
23 2. Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
24  U.S. Geological Survey Professional Paper 1453 , United State Government
25  Printing Office, Washington D.C., 1989.
26 *******************************************************************************/
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <limits.h>
30 #include "oli_cproj.h"
31 #include "gctp.h"
32 #include "oli_local.h"
33 
34 typedef struct state_plane_zone_data
35 {
36  int zone_id; /* Zone id */
37  int proj_id; /* projection id: 1 = Transverse Mercator,
38  2 = Lambert Conformal Conic, 3 = Polyconic,
39  4 = Oblique Mercator. 0 = not a valid zone */
40  double table[9]; /* Array of 9 projection parameters. Meaning varies
41  based on the proj_id. */
42  char name[33]; /* Zone name */
43 } STATE_PLANE_ZONE_DATA;
44 
45 /* Include the nad27_data and nad83_data tables */
46 #include "state_plane_table.h"
47 
48 
49 #if 0
50 /* Note that the following table appeared in the original GCTP code with code
51  similar to:
52 
53  if ((*inspheroid == 0) && (*insys == SPCS) && (*inunit == STPLN_TABLE))
54  unit = FEET;
55  if ((*inspheroid == 8) && (*insys == SPCS) && (*inunit == STPLN_TABLE))
56  unit = NADUT[(*inzone)/100];
57 
58  if (*insys == SPCS)
59  *inunit = unit;
60 
61  And the same for the output projection. So, essentially if the input
62  units were STPLN_TABLE for the state plane projection, it would
63  automatically select the units to use and return those units to the calling
64  routine. That feature has not been implemented here since nothing really
65  appears to use it and it is very strange behavior. If needed, this
66  feature should be implemented as a routine to return the units that
67  should be used for a given zone and let the calling routines deal with it. */
68 */
69 
70 /* Table of unit codes as specified by state laws as of 2/1/92 for NAD 1983
71  State Plane projection, 1 = U.S. Survey Feet, 2 = Meters, 5 = International
72  Feet */
73 static long NADUT[134] = {1, 5, 1, 1, 5, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 2,
74  1, 1, 5, 2, 1, 2, 5, 1, 2, 2, 2, 1, 1, 1, 5, 2, 1, 5,
75  2, 2, 5, 2, 1, 1, 5, 2, 2, 1, 2, 1, 2, 2, 1, 2, 2, 2};
76 
77 #endif
78 
79 /* structure to hold the setup data relevant to this projection */
81 {
82  TRANSFORMATION child_transform;
83 
84  int zone; /* state plane zone number */
85  int sphere; /* 0 = NAD27, 8 = GRS 1980 for NAD83 */
86  int proj_id; /* projection id: 1 = Transverse Mercator,
87  2 = Lambert Conformal Conic, 3 = Polyconic,
88  4 = Oblique Mercator */
89 };
90 
91 /*****************************************************************************
92 Name: print_info
93 
94 Purpose: Prints a summary of information about this projection.
95 
96 Returns:
97  nothing
98 
99 *****************************************************************************/
100 static void print_info
101 (
102  const TRANSFORMATION *trans
103 )
104 {
105  struct state_plane_proj *cache_ptr
106  = (struct state_plane_proj *)trans->cache;
107  int nadval;
108 
109  gctp_print_title("STATE PLANE");
110  gctp_print_genrpt_long(cache_ptr->zone, "Zone: ");
111 
112  if (cache_ptr->sphere == 0)
113  nadval = 27;
114  else
115  nadval = 83;
116 
117  gctp_print_genrpt_long(nadval, "Datum: NAD");
118 
119  cache_ptr->child_transform.print_info(&cache_ptr->child_transform);
120 }
121 
122 /*****************************************************************************
123 Name: dms2to3
124 
125 Purpose: Function to convert 2 digit alternate packed DMS format
126  (+/-)DDDMMSS.SSS to 3 digit standard packed DMS format (+/-)DDDMMMSSS.SSS.
127 
128 Returns:
129  3 digit DMS value
130 *****************************************************************************/
131 static double dms2to3
132 (
133  double dms_2digit /* Angle in 2 digit packed DMS format */
134 )
135 {
136  double con;
137  double secs;
138  long degs,mins;
139  char sgna;
140 
141  sgna = ' ';
142  if (dms_2digit < 0.0)
143  sgna = '-';
144  con = fabs (dms_2digit);
145  degs = (long) ((con / 10000.0) + .001);
146  con = con - degs * 10000;
147  mins = (long) ((con / 100.0) + .001);
148  secs = con - mins * 100;
149  con = (double) (degs) * 1000000.0 + (double) (mins) * 1000.0 + secs;
150  if (sgna == '-')
151  con = - con;
152  return(con);
153 }
154 
155 
156 /*******************************************************************************
157 Name: common_init
158 
159 Purpose: Initialization routine for initializing the projection information
160  that is common to both the forward and inverse transformations.
161 
162 Returns:
163  GCTP_SUCCESS or GCTP_ERROR
164 
165 *******************************************************************************/
166 static int common_init
167 (
168  TRANSFORMATION *trans /* I/O: transformation to initialize */
169 )
170 {
171  int ind; /* index for the zone */
172  int i; /* loop control variable */
173  const double *table; /* array containing the projection information */
174  const GCTP_PROJECTION *proj = &trans->proj;
175  int id;
176  struct state_plane_proj *cache = NULL;
177  const STATE_PLANE_ZONE_DATA *zone_data;
178 
179  int zone = proj->zone;
180  int sphere = proj->spheroid;
181 
182  ind = -1;
183 
184  /* Find the index for the zone
185  --------------------------*/
186  if (zone > 0)
187  {
188  if (sphere == 0)
189  {
190  zone_data = nad27_data;
191  }
192  else if (sphere == 8)
193  {
194  zone_data = nad83_data;
195  }
196  else
197  {
198  GCTP_PRINT_ERROR("Illegal spheroid #%4d", sphere);
199  return GCTP_ERROR;
200  }
201 
202  for (i = 0; i < 134; i++)
203  {
204  if ((zone == zone_data[i].zone_id) && (zone_data[i].proj_id != 0))
205  {
206  ind = i;
207  break;
208  }
209  }
210  }
211  if (ind == -1)
212  {
213  GCTP_PRINT_ERROR("Illegal zone #%4d for spheroid #%4d", zone, sphere);
214  return GCTP_ERROR;
215  }
216  table = zone_data[ind].table;
217  id = zone_data[ind].proj_id;
218  if ((id <= 0) || (id > 4))
219  {
220  GCTP_PRINT_ERROR("Illegal zone #%4d for spheroid #%4d", zone, sphere);
221  return GCTP_ERROR;
222  }
223 
224  /* Allocate a structure for the cached info */
225  cache = malloc(sizeof(*cache));
226  if (!cache)
227  {
228  GCTP_PRINT_ERROR("Error allocating memory for cache buffer");
229  return GCTP_ERROR;
230  }
231  trans->cache = cache;
232  cache->proj_id = id;
233  cache->zone = zone;
234  cache->sphere = sphere;
235 
236  /* Build the child transform projection information */
237  for (i = 0; i < GCTP_PROJECTION_PARAMETER_COUNT; i++)
238  cache->child_transform.proj.parameters[i] = 0.0;
239  cache->child_transform.proj.spheroid = sphere;
240  cache->child_transform.proj.units = proj->units;
241  cache->child_transform.proj.zone = 0;
242 
243  /* initialize proper projection */
244  if (id == 1)
245  {
246  cache->child_transform.proj.proj_code = TM;
247  /* scale factor */
248  cache->child_transform.proj.parameters[2] = table[3];
249  /* center longitude */
250  cache->child_transform.proj.parameters[4] = dms2to3(table[2]);
251  /* latitude of origin */
252  cache->child_transform.proj.parameters[5] = dms2to3(table[6]);
253  /* false easting */
254  cache->child_transform.proj.parameters[6] = table[7];
255  /* false northing */
256  cache->child_transform.proj.parameters[7] = table[8];
257  }
258  else if (id == 2)
259  {
260  cache->child_transform.proj.proj_code = LAMCC;
261  /* lat1 */
262  cache->child_transform.proj.parameters[2] = dms2to3(table[5]);
263  /* lat2 */
264  cache->child_transform.proj.parameters[3] = dms2to3(table[4]);
265  /* center longitude */
266  cache->child_transform.proj.parameters[4] = dms2to3(table[2]);
267  /* latitude of origin */
268  cache->child_transform.proj.parameters[5] = dms2to3(table[6]);
269  /* false easting */
270  cache->child_transform.proj.parameters[6] = table[7];
271  /* false northing */
272  cache->child_transform.proj.parameters[7] = table[8];
273  }
274  else if (id == 3)
275  {
276  cache->child_transform.proj.proj_code = POLYC;
277  /* center longitude */
278  cache->child_transform.proj.parameters[4] = dms2to3(table[2]);
279  /* center latitude */
280  cache->child_transform.proj.parameters[5] = dms2to3(table[3]);
281  /* false easting */
282  cache->child_transform.proj.parameters[6] = table[4];
283  /* false northing */
284  cache->child_transform.proj.parameters[7] = table[5];
285  }
286  else if (id == 4)
287  {
288  cache->child_transform.proj.proj_code = HOM;
289  /* scale factor */
290  cache->child_transform.proj.parameters[2] = table[3];
291  /* azimuth */
292  cache->child_transform.proj.parameters[3] = dms2to3(table[5]);
293  /* longitude of origin */
294  cache->child_transform.proj.parameters[4] = dms2to3(table[2]);
295  /* latitude of origin */
296  cache->child_transform.proj.parameters[5] = dms2to3(table[6]);
297  /* false easting */
298  cache->child_transform.proj.parameters[6] = table[7];
299  /* false northing */
300  cache->child_transform.proj.parameters[7] = table[8];
301  /* using format B */
302  cache->child_transform.proj.parameters[12] = 1.0;
303  }
304 
305  trans->print_info = print_info;
306 
307  return GCTP_SUCCESS;
308 }
309 
310 /*****************************************************************************
311 Name: destroy
312 
313 Purpose: Releases the resources allocated by this projection.
314 
315 Returns:
316  nothing
317 
318 *****************************************************************************/
319 static void destroy
320 (
321  TRANSFORMATION *trans
322 )
323 {
324  struct state_plane_proj *cache = (struct state_plane_proj *)trans->cache;
325  free(cache->child_transform.cache);
326  cache->child_transform.cache = NULL;
327 }
328 /*****************************************************************************
329 Name: inverse_transform
330 
331 Purpose: Transforms UTM X,Y to lat,long
332 
333 Returns:
334  GCTP_SUCCESS or GCTP_ERROR
335 
336 *****************************************************************************/
337 static int inverse_transform
338 (
339  const TRANSFORMATION *trans, /* I: transformation information */
340  double x, /* I: X projection coordinate */
341  double y, /* I: Y projection coordinate */
342  double *lon, /* O: Longitude */
343  double *lat /* O: Latitude */
344 )
345 {
346  struct state_plane_proj *cache_ptr
347  = (struct state_plane_proj *)trans->cache;
348 
349  return cache_ptr->child_transform.transform(&cache_ptr->child_transform,
350  x, y, lon, lat);
351 }
352 
353 /*****************************************************************************
354 Name: forward_transform
355 
356 Purpose: Transforms lat,long to polar stereographic X,Y
357 
358 Returns:
359  GCTP_SUCCESS or GCTP_ERROR
360 
361 *****************************************************************************/
362 static int forward_transform
363 (
364  const TRANSFORMATION *trans, /* I: transformation information */
365  double lon, /* I: Longitude */
366  double lat, /* I: Latitude */
367  double *x, /* O: X projection coordinate */
368  double *y /* O: Y projection coordinate */
369 )
370 {
371  struct state_plane_proj *cache_ptr
372  = (struct state_plane_proj *)trans->cache;
373 
374  return cache_ptr->child_transform.transform(&cache_ptr->child_transform,
375  lon, lat, x, y);
376 }
377 
378 /*****************************************************************************
379 Name: gctp_state_plane_inverse_init
380 
381 Purpose: Initializes the inverse state plane transformation
382 
383 Returns:
384  GCTP_SUCCESS or GCTP_ERROR
385 
386 *****************************************************************************/
388 (
389  TRANSFORMATION *trans
390 )
391 {
392  struct state_plane_proj *cache;
393 
394  /* Call the common routine used for the forward and inverse init */
395  if (common_init(trans) != GCTP_SUCCESS)
396  {
398  "Error initializing state plane inverse projection");
399  return GCTP_ERROR;
400  }
401 
402  cache = (struct state_plane_proj *)trans->cache;
403 
404  if (cache->proj_id == 1)
405  gctp_tm_inverse_init(&cache->child_transform);
406  else if (cache->proj_id == 2)
407  gctp_lamcc_inverse_init(&cache->child_transform);
408  else if (cache->proj_id == 3)
409  gctp_poly_inverse_init(&cache->child_transform);
410  else if (cache->proj_id == 4)
411  gctp_om_inverse_init(&cache->child_transform);
412 
413  trans->transform = inverse_transform;
414  trans->destroy = destroy;
415 
416  return GCTP_SUCCESS;
417 }
418 
419 /*****************************************************************************
420 Name: gctp_state_plane_forward_init
421 
422 Purpose: Initializes the forward state plane transformation
423 
424 Returns:
425  GCTP_SUCCESS or GCTP_ERROR
426 
427 *****************************************************************************/
429 (
430  TRANSFORMATION *trans
431 )
432 {
433  struct state_plane_proj *cache;
434 
435  /* Call the common routine used for the forward and inverse init */
436  if (common_init(trans) != GCTP_SUCCESS)
437  {
439  "Error initializing state plane forward projection");
440  return GCTP_ERROR;
441  }
442 
443  cache = (struct state_plane_proj *)trans->cache;
444 
445  if (cache->proj_id == 1)
446  gctp_tm_forward_init(&cache->child_transform);
447  else if (cache->proj_id == 2)
448  gctp_lamcc_forward_init(&cache->child_transform);
449  else if (cache->proj_id == 3)
450  gctp_poly_forward_init(&cache->child_transform);
451  else if (cache->proj_id == 4)
452  gctp_om_forward_init(&cache->child_transform);
453 
454  trans->transform = forward_transform;
455  trans->destroy = destroy;
456 
457  return GCTP_SUCCESS;
458 }
int gctp_lamcc_forward_init(TRANSFORMATION *trans)
void gctp_print_title(const char *proj_name)
Definition: gctp_report.c:14
#define GCTP_ERROR
Definition: gctp.h:81
an array had not been initialized Several spelling and grammar corrections were which is read from the appropriate MCF the above metadata values were hard coded A problem calculating the average background DN for SWIR bands when the moon is in the space view port was corrected The new algorithm used to calculate the average background DN for all reflective bands when the moon is in the space view port is now the same as the algorithm employed by the thermal bands For non SWIR changes in the averages are typically less than Also for non SWIR the black body DNs remain a backup in case the SV DNs are not available For SWIR the changes in computed averages were larger because the old which used the black body suffered from contamination by the micron leak As a consequence of the if SV DNs are not available for the SWIR the EV pixels will not be the granule time is used to identify the appropriate tables within the set given for one LUT table(e.g. m1) to be used for interpolation. The table values will be linearly interpolated using the tables corresponding to the node times bracketing the granule time. If the granule time falls before the time of the first node or after the time of the last node
#define POLYC
Definition: proj_define.h:43
#define NULL
Definition: decode_rs.h:63
TRANSFORMATION child_transform
Definition: state_plane.c:82
#define GCTP_PRINT_ERROR(format,...)
Definition: oli_local.h:81
void gctp_print_genrpt_long(long A, const char *S)
Definition: gctp_report.c:126
int gctp_state_plane_forward_init(TRANSFORMATION *trans)
Definition: state_plane.c:429
float * lat
character(len=1000) if
Definition: names.f90:13
int gctp_lamcc_inverse_init(TRANSFORMATION *trans)
#define LAMCC
Definition: proj_define.h:40
def cache(filename, recache=False)
Definition: utils.py:145
int gctp_om_forward_init(TRANSFORMATION *trans)
int gctp_tm_inverse_init(TRANSFORMATION *trans)
Definition: tm.c:539
#define TM
Definition: proj_define.h:45
integer, parameter double
#define GCTP_PROJECTION_PARAMETER_COUNT
Definition: gctp.h:78
#define GCTP_SUCCESS
Definition: gctp.h:82
int gctp_om_inverse_init(TRANSFORMATION *trans)
int gctp_tm_forward_init(TRANSFORMATION *trans)
Definition: tm.c:565
#define HOM
Definition: proj_define.h:56
#define fabs(a)
Definition: misc.h:93
int gctp_poly_inverse_init(TRANSFORMATION *trans)
Definition: polyconic.c:307
float * lon
int gctp_poly_forward_init(TRANSFORMATION *trans)
Definition: polyconic.c:334
int i
Definition: decode_rs.h:71
int gctp_state_plane_inverse_init(TRANSFORMATION *trans)
Definition: state_plane.c:388