OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
polyconic.c
Go to the documentation of this file.
1 /*******************************************************************************
2 Name: POLYCONIC
3 
4 Purpose: Provides the transformations between Easting/Northing and longitude/
5  latitude for the Polyconic projection. The Easting and Northing
6  values are in meters. The longitude and latitude are in radians.
7 
8 Algorithm References
9 
10 1. Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
11  Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
12  State Government Printing Office, Washington D.C., 1987.
13 
14 2. Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
15  U.S. Geological Survey Professional Paper 1453 , United State Government
16  Printing Office, Washington D.C., 1989.
17 *******************************************************************************/
18 #include <stdlib.h>
19 #include "oli_cproj.h"
20 #include "gctp.h"
21 #include "oli_local.h"
22 
23 /* structure to hold the setup data relevant to this projection */
24 struct poly_proj
25 {
26  double r_major; /* major axis */
27  double r_minor; /* minor axis */
28  double center_lon; /* Center longitude (projection center) */
29  double lat_origin; /* center latitude */
30  double e; /* eccentricity constants */
31  double e0;
32  double e1;
33  double e2;
34  double e3;
35  double es;
36  double ml0; /* small value m */
37  double false_northing; /* y offset in meters */
38  double false_easting; /* x offset in meters */
39 };
40 
41 /*****************************************************************************
42 Name: print_info
43 
44 Purpose: Prints a summary of information about this projection.
45 
46 Returns:
47  nothing
48 
49 *****************************************************************************/
50 static void print_info
51 (
52  const TRANSFORMATION *trans
53 )
54 {
55  struct poly_proj *cache_ptr = (struct poly_proj *)trans->cache;
56 
57  gctp_print_title("POLYCONIC");
58  gctp_print_radius2(cache_ptr->r_major, cache_ptr->r_minor);
59  gctp_print_cenlonmer(cache_ptr->center_lon);
60  gctp_print_origin(cache_ptr->lat_origin);
61  gctp_print_offsetp(cache_ptr->false_easting, cache_ptr->false_northing);
62 }
63 
64 /*******************************************************************************
65 Name: common_init
66 
67 Purpose: Initialization routine for initializing the projection information
68  that is common to both the forward and inverse transformations.
69 
70 Returns:
71  GCTP_SUCCESS or GCTP_ERROR
72 
73 *******************************************************************************/
74 static int common_init
75 (
76  TRANSFORMATION *trans /* I/O: transformation to initialize */
77 )
78 {
79  double r_major; /* major axis */
80  double r_minor; /* minor axis */
81  double radius;
82  double center_lon; /* center longitude */
83  double lat_origin; /* center latitude */
84  double false_easting; /* x offset in meters */
85  double false_northing; /* y offset in meters */
86 
87  double temp; /* temporary variable */
88  double es; /* eccentricity squared */
89 
90  const GCTP_PROJECTION *proj = &trans->proj;
91  struct poly_proj *cache = NULL;
92  int spheroid = proj->spheroid;
93 
94  gctp_get_spheroid(spheroid, proj->parameters, &r_major, &r_minor, &radius);
95  false_easting = proj->parameters[6];
96  false_northing = proj->parameters[7];
97 
98  if (gctp_dms2degrees(proj->parameters[4], &center_lon) != GCTP_SUCCESS)
99  {
100  GCTP_PRINT_ERROR("Error converting center longitude in parameter 4 "
101  "from DMS to degrees: %f", proj->parameters[4]);
102  return GCTP_ERROR;
103  }
104  center_lon *= 3600 * S2R;
105 
106  if (gctp_dms2degrees(proj->parameters[5], &lat_origin) != GCTP_SUCCESS)
107  {
108  GCTP_PRINT_ERROR("Error converting center latitude in parameter 4 "
109  "from DMS to degrees: %f", proj->parameters[5]);
110  return GCTP_ERROR;
111  }
112  lat_origin *= 3600 * S2R;
113 
114  /* Allocate a structure for the cached info */
115  cache = malloc(sizeof(*cache));
116  if (!cache)
117  {
118  GCTP_PRINT_ERROR("Error allocating memory for cache buffer");
119  return GCTP_ERROR;
120  }
121  trans->cache = cache;
122 
123  /* Save the information to the cache */
124  cache->r_major = r_major;
125  cache->r_minor = r_minor;
126  cache->false_northing = false_northing;
127  cache->false_easting = false_easting;
128  cache->center_lon = center_lon;
129  cache->lat_origin = lat_origin;
130 
131  temp = r_minor / r_major;
132  es = 1.0 - SQUARE(temp);
133  cache->es = es;
134  cache->e = sqrt(es);
135  cache->e0 = gctp_calc_e0(es);
136  cache->e1 = gctp_calc_e1(es);
137  cache->e2 = gctp_calc_e2(es);
138  cache->e3 = gctp_calc_e3(es);
139  cache->ml0 = gctp_calc_dist_from_equator(cache->e0, cache->e1, cache->e2,
140  cache->e3, lat_origin);
141 
142  trans->print_info = print_info;
143 
144  return GCTP_SUCCESS;
145 }
146 
147 /*******************************************************************************
148 Name: compute_phi4z
149 
150 Purpose: Function to compute, phi4, the latitude for the inverse of the
151  Polyconic projection.
152 
153 Returns:
154  GCTP_SUCCESS or GCTP_ERROR
155 
156 *******************************************************************************/
157 static int compute_phi4z
158 (
159  double eccent, /* Spheroid eccentricity squared */
160  double e0,
161  double e1,
162  double e2,
163  double e3,
164  double a,
165  double b,
166  double *c,
167  double *phi
168 )
169 {
170  double sinphi;
171  double sin2ph;
172  double tanphi;
173  double ml;
174  double mlp;
175  double con1;
176  double con2;
177  double con3;
178  double dphi;
179  long i;
180 
181  *phi = a;
182  for (i = 1; i <= 15; i++)
183  {
184  sinphi = sin(*phi);
185  tanphi = tan(*phi);
186  *c = tanphi * sqrt (1.0 - eccent * sinphi * sinphi);
187  sin2ph = sin (2.0 * *phi);
188  ml = e0 * *phi - e1 * sin2ph + e2 * sin (4.0 * *phi) - e3 *
189  sin (6.0 * *phi);
190  mlp = e0 - 2.0 * e1 * cos (2.0 * *phi) + 4.0 * e2 *
191  cos (4.0 * *phi) - 6.0 * e3 * cos (6.0 * *phi);
192  con1 = 2.0 * ml + *c * (ml * ml + b) - 2.0 * a * (*c * ml + 1.0);
193  con2 = eccent * sin2ph * (ml * ml + b - 2.0 * a * ml) / (2.0 * *c);
194  con3 = 2.0 * (a - ml) * (*c * mlp - 2.0 / sin2ph) - 2.0 * mlp;
195  dphi = con1 / (con2 + con3);
196  *phi += dphi;
197  if (fabs(dphi) <= .0000000001 )
198  return GCTP_SUCCESS;
199  }
200  GCTP_PRINT_ERROR("Latitude failed to converge");
201  return GCTP_ERROR;
202 }
203 
204 
205 /*****************************************************************************
206 Name: inverse_transform
207 
208 Purpose: Transforms X,Y to lat,long
209 
210 Returns:
211  GCTP_SUCCESS or GCTP_ERROR
212 
213 *****************************************************************************/
214 static int inverse_transform
215 (
216  const TRANSFORMATION *trans, /* I: transformation information */
217  double x, /* I: X projection coordinate */
218  double y, /* I: Y projection coordinate */
219  double *lon, /* O: Longitude */
220  double *lat /* O: Latitude */
221 )
222 {
223  struct poly_proj *cache_ptr = (struct poly_proj *)trans->cache;
224  double al; /* temporary values */
225  double b; /* temporary values */
226  double c; /* temporary values */
227 
228  x -= cache_ptr->false_easting;
229  y -= cache_ptr->false_northing;
230  al = cache_ptr->ml0 + y/cache_ptr->r_major;
231  if (fabs(al) <= .0000001)
232  {
233  *lon = x/cache_ptr->r_major + cache_ptr->center_lon;
234  *lat = 0.0;
235  }
236  else
237  {
238  b = al * al + (x/cache_ptr->r_major) * (x/cache_ptr->r_major);
239  if (compute_phi4z(cache_ptr->es, cache_ptr->e0, cache_ptr->e1,
240  cache_ptr->e2, cache_ptr->e3, al, b, &c, lat) != GCTP_SUCCESS)
241  {
242  return GCTP_ERROR;
243  }
244  *lon = adjust_lon((asinz(x * c / cache_ptr->r_major) / sin(*lat))
245  + cache_ptr->center_lon);
246  }
247 
248  return GCTP_SUCCESS;
249 }
250 
251 /*****************************************************************************
252 Name: forward_transform
253 
254 Purpose: Transforms lat,long to polyconic X,Y
255 
256 Returns:
257  GCTP_SUCCESS or GCTP_ERROR
258 
259 *****************************************************************************/
260 static int forward_transform
261 (
262  const TRANSFORMATION *trans, /* I: transformation information */
263  double lon, /* I: Longitude */
264  double lat, /* I: Latitude */
265  double *x, /* O: X projection coordinate */
266  double *y /* O: Y projection coordinate */
267 )
268 {
269  struct poly_proj *cache_ptr = (struct poly_proj *)trans->cache;
270  double sinphi, cosphi; /* sin and cos value */
271  double con, ml; /* cone constant, small m */
272  double ms; /* small m */
273 
274  con = adjust_lon(lon - cache_ptr->center_lon);
275  if (fabs(lat) <= .0000001)
276  {
277  *x = cache_ptr->false_easting + cache_ptr->r_major * con;
278  *y = cache_ptr->false_northing - cache_ptr->r_major * cache_ptr->ml0;
279  }
280  else
281  {
282  sincos(lat,&sinphi,&cosphi);
283  ml = gctp_calc_dist_from_equator(cache_ptr->e0, cache_ptr->e1,
284  cache_ptr->e2, cache_ptr->e3, lat);
285  ms = gctp_calc_small_radius(cache_ptr->e, sinphi, cosphi);
286  con *= sinphi;
287  *x = cache_ptr->false_easting + cache_ptr->r_major * ms * sin(con)
288  / sinphi;
289  *y = cache_ptr->false_northing + cache_ptr->r_major
290  * (ml - cache_ptr->ml0 + ms * (1.0 - cos(con))/sinphi);
291  }
292 
293  return GCTP_SUCCESS;
294 }
295 
296 
297 /*****************************************************************************
298 Name: gctp_poly_inverse_init
299 
300 Purpose: Initializes the inverse polyconic transformation
301 
302 Returns:
303  GCTP_SUCCESS or GCTP_ERROR
304 
305 *****************************************************************************/
307 (
308  TRANSFORMATION *trans
309 )
310 {
311  /* Call the common routine used for the forward and inverse init */
312  if (common_init(trans) != GCTP_SUCCESS)
313  {
315  "Error initializing polyconic inverse projection");
316  return GCTP_ERROR;
317  }
318 
319  trans->transform = inverse_transform;
320 
321  return GCTP_SUCCESS;
322 }
323 
324 /*****************************************************************************
325 Name: gctp_poly_forward_init
326 
327 Purpose: Initializes the forward polyconic transformation
328 
329 Returns:
330  GCTP_SUCCESS or GCTP_ERROR
331 
332 *****************************************************************************/
334 (
335  TRANSFORMATION *trans
336 )
337 {
338  /* Call the common routine used for the forward and inverse init */
339  if (common_init(trans) != GCTP_SUCCESS)
340  {
342  "Error initializing polyconic forward projection");
343  return GCTP_ERROR;
344  }
345 
346  trans->transform = forward_transform;
347 
348  return GCTP_SUCCESS;
349 }
#define SQUARE(x)
Definition: proj_define.h:99
void gctp_print_origin(double A)
Definition: gctp_report.c:65
void gctp_print_title(const char *proj_name)
Definition: gctp_report.c:14
double gctp_calc_e2(double x)
Definition: gctp_utility.c:139
int gctp_poly_forward_init(TRANSFORMATION *trans)
Definition: polyconic.c:334
double false_northing
Definition: polyconic.c:53
double ml0
Definition: polyconic.c:52
#define GCTP_ERROR
Definition: gctp.h:81
double center_lon
Definition: polyconic.c:44
#define NULL
Definition: decode_rs.h:63
double e2
Definition: polyconic.c:49
#define GCTP_PRINT_ERROR(format,...)
Definition: oli_local.h:81
float * lat
double lat_origin
Definition: polyconic.c:45
int gctp_poly_inverse_init(TRANSFORMATION *trans)
Definition: polyconic.c:307
character(len=1000) if
Definition: names.f90:13
double adjust_lon(double x)
Definition: proj_cproj.c:349
def cache(filename, recache=False)
Definition: utils.py:145
double gctp_calc_e0(double x)
Definition: gctp_utility.c:125
double false_easting
Definition: polyconic.c:54
double e3
Definition: polyconic.c:50
void gctp_print_offsetp(double A, double B)
Definition: gctp_report.c:91
#define GCTP_SUCCESS
Definition: gctp.h:82
double gctp_calc_e3(double x)
Definition: gctp_utility.c:146
int gctp_dms2degrees(double angle, double *degrees)
double gctp_calc_e1(double x)
Definition: gctp_utility.c:132
#define gctp_get_spheroid
Definition: oli_local.h:7
Definition: __init__.py:1
#define sincos
Definition: proj_define.h:108
data_t b[NROOTS+1]
Definition: decode_rs.h:77
void gctp_print_radius2(double radius1, double radius2)
Definition: gctp_report.c:30
void gctp_print_cenlonmer(double A)
Definition: gctp_report.c:48
double gctp_calc_small_radius(double eccent, double sinphi, double cosphi)
Definition: gctp_utility.c:253
double e1
Definition: polyconic.c:48
#define fabs(a)
Definition: misc.h:93
double e
Definition: polyconic.c:46
#define S2R
Definition: proj_define.h:92
double e0
Definition: polyconic.c:47
float * lon
double r_minor
Definition: polyconic.c:43
double r_major
Definition: polyconic.c:42
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
void radius(double A)
Definition: proj_report.c:132
int i
Definition: decode_rs.h:71
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 es
Definition: polyconic.c:51
double asinz(double con)
Definition: proj_cproj.c:67
double gctp_calc_dist_from_equator(double e0, double e1, double e2, double e3, double phi)
Definition: gctp_utility.c:187