OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
ias_geo_projection_transformation.c
Go to the documentation of this file.
1 /*****************************************************************************
2 Name: ias_geo_projection_transformation
3 
4 Purpose: Provides a wrapper around GCTP.
5 
6 Notes:
7  - It might be useful add a routine to print out transformation info by
8  echoing through to the gctp_print_transformation_info routine
9 
10 *****************************************************************************/
11 #include <stdlib.h>
12 #include <string.h>
13 #include <stdarg.h>
14 #include "gctp.h"
15 #include "ias_logging.h"
16 #include "ias_geo.h"
17 #include "ias_const.h"
18 
19 /* Declare a private structure to store information about a projection
20  transformation. */
22 {
23  GCTP_TRANSFORMATION *gctp_transform;/* Pointer to the GCTP transformation */
24  int source_is_som; /* Flag to indicate the source projection is
25  SOM so the needed coordinate swapping can
26  be performed */
27  int target_is_som; /* Flag to indicate the target projection is
28  SOM so the needed coordinate swapping can
29  be performed */
30  int source_is_dms; /* Flag to indicate the source units are DMS
31  so they can be converted to degrees */
32  int target_is_dms; /* Flag to indicate the target units are DMS
33  so they can be converted to degrees */
34 };
35 
36 /*****************************************************************************
37 Name: copy_ias_proj_to_gctp_proj
38 
39 Purpose: A helper routine to copy an IAS projection definition to a GCTP
40  projection definition.
41 
42 Returns: nothing
43 
44 *****************************************************************************/
45 static void copy_ias_proj_to_gctp_proj
46 (
47  const IAS_PROJECTION *ias_proj, /* I: source IAS projection */
48  GCTP_PROJECTION *gctp_proj /* O: target GCTP projection */
49 )
50 {
51  int i;
52 
53  /* Copy the projection code, zone, units, and spheroid to the GCTP proj */
54  gctp_proj->proj_code = ias_proj->proj_code;
55  gctp_proj->zone = ias_proj->zone;
56  gctp_proj->units = ias_proj->units;
57  gctp_proj->spheroid = ias_proj->spheroid;
58 
59  /* Copy the projection parameters */
60  for (i = 0; i < IAS_PROJ_PARAM_SIZE; i++)
61  gctp_proj->parameters[i] = ias_proj->parameters[i];
62 
63 }
64 
65 /*****************************************************************************
66 Name: ias_geo_set_projection
67 
68 Purpose: A routine to set the members into an IAS projection.
69 
70 Returns: nothing
71 
72 *****************************************************************************/
74 (
75  int proj_code, /* I: input projection code */
76  int zone, /* I: input zone */
77  int units, /* I: input units */
78  int spheroid, /* I: input spheroid */
79  const double *parms, /* I: input projection parameters */
80  IAS_PROJECTION *proj /* I: target projection structure */
81 )
82 {
83  int i;
84 
85  /* Set the projection code, zone, units, and spheroid to the GCTP proj */
86  proj->proj_code = proj_code;
87  proj->zone = zone;
88  proj->units = units;
89  proj->spheroid = spheroid;
90 
91  /* Set the projection parameters */
92  for (i = 0; i < IAS_PROJ_PARAM_SIZE; i++)
93  proj->parameters[i] = parms[i];
94 
95 }
96 
97 /*****************************************************************************
98 Name: gctp_message_callback
99 
100 Purpose: Handles the error messages from GCTP. It does some simple translation
101  of the message type and calls the IAS library logging routine. This allows
102  GCTP error messages to be formatted the same as any other message.
103 
104 Returns: nothing
105 
106 *****************************************************************************/
107 static void gctp_message_callback
108 (
109  GCTP_MESSAGE_TYPE_ENUM message_type, /* I: message type */
110  const char *filename, /* I: source code file name for input */
111  int line_number, /* I: source code line number for input */
112  const char *format, ... /* I: format string for message */
113 )
114 {
115  int ias_message_type;
116  va_list ap;
117 
118  /* Convert the message type */
119  if (message_type == GCTP_INFO_MESSAGE)
120  ias_message_type = IAS_LOG_LEVEL_INFO;
121  else if (message_type == GCTP_ERROR_MESSAGE)
122  ias_message_type = IAS_LOG_LEVEL_ERROR;
123  else
124  {
125  /* This shouldn't happen, but if it does, call it a warning */
126  ias_message_type = IAS_LOG_LEVEL_WARN;
127  }
128 
129  /* Call our log message routine */
130  va_start(ap, format);
131  ias_log_message(ias_message_type, filename, line_number, format, ap);
132  va_end(ap);
133 }
134 
135 /*****************************************************************************
136 Name: ias_geo_create_proj_transformation
137 
138 Purpose: Creates a projection transformation and returns it to the caller.
139 
140 Returns: A pointer to the created projection or NULL if there is an error.
141 
142 *****************************************************************************/
143 IAS_GEO_PROJ_TRANSFORMATION *ias_geo_create_proj_transformation
144 (
145  const IAS_PROJECTION *source_projection, /* I: source projection */
146  const IAS_PROJECTION *target_projection /* I: target projection */
147 )
148 {
149  IAS_GEO_PROJ_TRANSFORMATION *trans; /* created projection */
150  GCTP_TRANSFORMATION *gctp_trans; /* associated GCTP projection */
151  GCTP_PROJECTION source_proj; /* source GCTP projection */
152  GCTP_PROJECTION target_proj; /* target GCTP projection */
153 
154  /* Redirect gctp output to our local callback so we can control the
155  formatting. Note that this will be set for every projection created,
156  but it doesn't really matter since it will always be set to the same
157  routine. */
158  gctp_set_message_callback(gctp_message_callback);
159 
160  /* Allocate space for the local transformation structure */
161  trans = malloc(sizeof(*trans));
162  if (!trans)
163  {
164  IAS_LOG_ERROR("Failed allocating memory for a projection "
165  "transformation");
166  return NULL;
167  }
168 
169  /* Copy the source IAS projection to the GCTP version of a projection */
170  copy_ias_proj_to_gctp_proj(source_projection, &source_proj);
171  if (source_proj.units == DMS)
172  {
173  /* The IAS layer will translate DMS units to degrees, so set the
174  GCTP source projection to DEGREE units and remember the source is
175  in DMS */
176  source_proj.units = DEGREE;
177  trans->source_is_dms = 1;
178  }
179  else
180  trans->source_is_dms = 0;
181 
182  /* Copy the target IAS projection to the GCTP version of a projection */
183  copy_ias_proj_to_gctp_proj(target_projection, &target_proj);
184  if (target_proj.units == DMS)
185  {
186  /* The IAS layer will translate DMS units to degrees, so set the
187  GCTP target projection to DEGREE units and remember the target needs
188  to be converted to DMS */
189  target_proj.units = DEGREE;
190  trans->target_is_dms = 1;
191  }
192  else
193  trans->target_is_dms = 0;
194 
195  /* Set the flags for whether the SOM projection coordinate swapping is
196  required */
197  if (source_proj.proj_code == SOM)
198  trans->source_is_som = 1;
199  else
200  trans->source_is_som = 0;
201  if (target_proj.proj_code == SOM)
202  trans->target_is_som = 1;
203  else
204  trans->target_is_som = 0;
205 
206  /* Create the GCTP transformation */
207  gctp_trans = gctp_create_transformation(&source_proj, &target_proj);
208  if (!gctp_trans)
209  {
210  IAS_LOG_ERROR("Failed allocating memory for a GCTP projection "
211  "transformation");
212  free(trans);
213  return NULL;
214  }
215  trans->gctp_transform = gctp_trans;
216 
217  return trans;
218 }
219 
220 /*****************************************************************************
221 Name: ias_geo_destroy_proj_transformation
222 
223 Purpose: Releases the resources allocated by the creation of a projection
224  transformation
225 
226 Returns: nothing
227 
228 *****************************************************************************/
230 (
231  IAS_GEO_PROJ_TRANSFORMATION *trans
232 )
233 {
234  if (trans)
235  {
236  gctp_destroy_transformation(trans->gctp_transform);
237  trans->gctp_transform = NULL;
238  free(trans);
239  }
240 }
241 
242 /****************************************************************************
243 Name: ias_geo_only_allow_threadsafe_transforms
244 
245 Purpose: Many of the transformations haven't been made threadsafe yet. Until
246  they are, there needs to be a way to allow threaded applications to
247  indicate that they are threaded and therefore only threadsafe
248  transformations should be allowed. This routine should be called from any
249  application that uses threading. After calling this, non-threadsafe
250  projections will cause the transformation creation to return an error.
251 
252 Returns:
253  nothing
254 
255 ****************************************************************************/
257 {
259 }
260 
261 /*****************************************************************************
262 Name: ias_geo_transform_coordinate
263 
264 Purpose: Using a projection transformation, convert the input coordinates
265  from the source projection to the target projection.
266 
267 Returns: SUCCESS or ERROR
268 
269 *****************************************************************************/
271 (
272  const IAS_GEO_PROJ_TRANSFORMATION *trans, /* I: transformation to use */
273  double inx, /* I: Input X projection coordinate */
274  double iny, /* I: Input Y projection coordinate */
275  double *outx, /* O: Output X projection coordinate */
276  double *outy /* O: Output Y projection coordinate */
277 )
278 {
279  int status; /* Status code from call to GCTP */
280  double incoor[2]; /* Input coordinates */
281  double outcoor[2]; /* Output coordinates */
282 
283  /* Verify the transformation provided is valid */
284  if (trans == NULL)
285  {
286  IAS_LOG_ERROR("Invalid transformation provided");
287  return ERROR;
288  }
289 
290  /* Swap X & Y if the source projection is SOM */
291  if (trans->source_is_som)
292  {
293  incoor[0] = -iny;
294  incoor[1] = inx;
295  }
296  else
297  {
298  /* Pack input coordinates into a GCTP compatible array */
299  incoor[0] = inx;
300  incoor[1] = iny;
301  }
302 
303  /* Since the GCTP doesn't work with DMS units, convert to degrees if DMS
304  units are being used */
305  if (trans->source_is_dms)
306  {
307  double coord;
308 
309  if (ias_geo_convert_dms2deg(incoor[0], &coord, "LON") != SUCCESS)
310  {
311  IAS_LOG_ERROR("Failed converting input DMS longitude (%f) to "
312  "degrees", incoor[0]);
313  return ERROR;
314  }
315  incoor[0] = coord;
316  if (ias_geo_convert_dms2deg(incoor[1], &coord, "LAT") != SUCCESS)
317  {
318  IAS_LOG_ERROR("Failed converting input DMS latitude (%f) to "
319  "degrees", incoor[1]);
320  return ERROR;
321  }
322  incoor[1] = coord;
323  }
324 
325  /* Call the GCTP transformation routine */
326  status = gctp_transform(trans->gctp_transform, incoor, outcoor);
327  if (status != GCTP_SUCCESS)
328  {
329  if (status == GCTP_IN_BREAK)
330  {
331  /* We don't support any projections that can have break areas, so
332  just include some rudimentary support for it, but consider it an
333  error for now */
334  IAS_LOG_ERROR("In projection break");
335  return ERROR;
336  }
337  IAS_LOG_ERROR("Failed converting between coordinate systems in GCTP");
338  return ERROR;
339  }
340 
341  /* Unpack transformed coordinates */
342  *outx = outcoor[0];
343  *outy = outcoor[1];
344 
345  /* If target units are requested in DMS, do the conversion */
346  if (trans->target_is_dms)
347  {
348  if (ias_geo_convert_deg2dms(outcoor[0], outx, "LON") != SUCCESS)
349  {
350  IAS_LOG_ERROR("Failed converting output degrees longitude (%f) to "
351  "DMS", outcoor[0]);
352  return ERROR;
353  }
354  if (ias_geo_convert_deg2dms(outcoor[1], outy, "LAT") != SUCCESS)
355  {
356  IAS_LOG_ERROR("Failed converting output degrees latitude (%f) to "
357  "DMS", outcoor[1]);
358  return ERROR;
359  }
360  }
361 
362  /* If the target projection is SOM, swap the X & Y coordinates */
363  if (trans->target_is_som)
364  {
365  double temp; /* Temp storage variable */
366 
367  temp = *outx;
368  *outx = *outy;
369  *outy = -temp;
370  }
371 
372  return SUCCESS;
373 }
374 
#define SUCCESS
Definition: ObpgReadGrid.h:15
void gctp_set_message_callback(GCTP_CALLBACK_PRINT_FUNC callback)
#define IAS_LOG_ERROR(format,...)
Definition: ias_logging.h:96
int status
Definition: l1_czcs_hdf.c:32
@ GCTP_INFO_MESSAGE
Definition: gctp.h:142
#define NULL
Definition: decode_rs.h:63
void gctp_only_allow_threadsafe_transforms()
void ias_geo_set_projection(int proj_code, int zone, int units, int spheroid, const double *parms, IAS_PROJECTION *proj)
int ias_geo_transform_coordinate(const IAS_GEO_PROJ_TRANSFORMATION *trans, double inx, double iny, double *outx, double *outy)
#define SOM
Definition: proj_define.h:58
void gctp_destroy_transformation(GCTP_TRANSFORMATION *trans)
void ias_geo_only_allow_threadsafe_transforms()
@ IAS_LOG_LEVEL_WARN
Definition: ias_logging.h:48
@ IAS_LOG_LEVEL_ERROR
Definition: ias_logging.h:49
#define GCTP_IN_BREAK
Definition: gctp.h:86
int ias_geo_convert_dms2deg(double angle_dms, double *angle_degrees, const char *type)
char filename[FILENAME_MAX]
Definition: atrem_corl1.h:122
subroutine coord(X, GM, Y)
Definition: coord.f:2
IAS_GEO_PROJ_TRANSFORMATION * ias_geo_create_proj_transformation(const IAS_PROJECTION *source_projection, const IAS_PROJECTION *target_projection)
#define GCTP_SUCCESS
Definition: gctp.h:82
GCTP_TRANSFORMATION * gctp_create_transformation(const GCTP_PROJECTION *input_projection, const GCTP_PROJECTION *output_projection)
int gctp_transform(const GCTP_TRANSFORMATION *trans, const double *in_coor, double *out_coor)
#define DEGREE
Definition: gctp.h:93
void ias_log_message(int log_level, const char *filename, int line_number, const char *format,...)
Definition: ias_logging.c:330
int ias_geo_convert_deg2dms(double deg, double *dms, const char *check)
@ IAS_LOG_LEVEL_INFO
Definition: ias_logging.h:47
#define DMS
Definition: gctp.h:94
@ GCTP_ERROR_MESSAGE
Definition: gctp.h:143
Definition: dataday.h:40
void ias_geo_destroy_proj_transformation(IAS_GEO_PROJ_TRANSFORMATION *trans)
int i
Definition: decode_rs.h:71
#define IAS_PROJ_PARAM_SIZE
Definition: ias_const.h:61
#define ERROR
Definition: ancil.h:24