dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
mgrs.c
Go to the documentation of this file.
1 /***************************************************************************/
2 /* RSC IDENTIFIER: MGRS
3  *
4  * ABSTRACT
5  *
6  * This component converts between geodetic coordinates (latitude and
7  * Longitude) and Military Grid Reference System (MGRS) coordinates.
8  *
9  * ERROR HANDLING
10  *
11  * This component checks parameters for valid values. If an invalid value
12  * is found, the error code is combined with the current error code using
13  * the bitwise or. This combining allows multiple error codes to be
14  * returned. The possible error codes are:
15  *
16  * MGRS_NO_ERROR : No errors occurred in function
17  * MGRS_LAT_ERROR : Latitude outside of valid range
18  * (-90 to 90 degrees)
19  * MGRS_LON_ERROR : Longitude outside of valid range
20  * (-180 to 360 degrees)
21  * MGRS_STR_ERROR : An MGRS string error: string too int,
22  * too short, or badly formed
23  * MGRS_PRECISION_ERROR : The precision must be between 0 and 5
24  * inclusive.
25  * MGRS_A_ERROR : Semi-major axis less than or equal to zero
26  * MGRS_INV_F_ERROR : Inverse flattening outside of valid range
27  * (250 to 350)
28  * MGRS_EASTING_ERROR : Easting outside of valid range
29  * (100,000 to 900,000 meters for UTM)
30  * (0 to 4,000,000 meters for UPS)
31  * MGRS_NORTHING_ERROR : Northing outside of valid range
32  * (0 to 10,000,000 meters for UTM)
33  * (0 to 4,000,000 meters for UPS)
34  * MGRS_ZONE_ERROR : Zone outside of valid range (1 to 60)
35  * MGRS_HEMISPHERE_ERROR : Invalid hemisphere ('N' or 'S')
36  *
37  * REUSE NOTES
38  *
39  * MGRS is intended for reuse by any application that does conversions
40  * between geodetic coordinates and MGRS coordinates.
41  *
42  * REFERENCES
43  *
44  * Further information on MGRS can be found in the Reuse Manual.
45  *
46  * MGRS originated from : U.S. Army Topographic Engineering Center
47  * Geospatial Information Division
48  * 7701 Telegraph Road
49  * Alexandria, VA 22310-3864
50  *
51  * LICENSES
52  *
53  * None apply to this component.
54  *
55  * RESTRICTIONS
56  *
57  *
58  * ENVIRONMENT
59  *
60  * MGRS was tested and certified in the following environments:
61  *
62  * 1. Solaris 2.5 with GCC version 2.8.1
63  * 2. Windows 95 with MS Visual C++ version 6
64  *
65  * MODIFICATIONS
66  *
67  * Date Description
68  * ---- -----------
69  * 16-11-94 Original Code
70  * 15-09-99 Reengineered upper layers
71  * 02-05-03 Corrected latitude band bug in GRID_UTM
72  * 08-20-03 Reengineered lower layers
73  */
74 
75 
76 /***************************************************************************/
77 /*
78  * INCLUDES
79  */
80 #include <ctype.h>
81 #include <math.h>
82 #include <stdio.h>
83 #include <string.h>
84 #include "ups.h"
85 #include "utm.h"
86 #include "mgrs.h"
87 
88 /*
89  * ctype.h - Standard C character handling library
90  * math.h - Standard C math library
91  * stdio.h - Standard C input/output library
92  * string.h - Standard C string handling library
93  * ups.h - Universal Polar Stereographic (UPS) projection
94  * utm.h - Universal Transverse Mercator (UTM) projection
95  * mgrs.h - function prototype error checking
96  */
97 
98 
99 /***************************************************************************/
100 /*
101  * GLOBAL DECLARATIONS
102  */
103 #define DEG_TO_RAD 0.017453292519943295 /* PI/180 */
104 #define RAD_TO_DEG 57.29577951308232087 /* 180/PI */
105 #define LETTER_A 0 /* ARRAY INDEX FOR LETTER A */
106 #define LETTER_B 1 /* ARRAY INDEX FOR LETTER B */
107 #define LETTER_C 2 /* ARRAY INDEX FOR LETTER C */
108 #define LETTER_D 3 /* ARRAY INDEX FOR LETTER D */
109 #define LETTER_E 4 /* ARRAY INDEX FOR LETTER E */
110 #define LETTER_F 5 /* ARRAY INDEX FOR LETTER F */
111 #define LETTER_G 6 /* ARRAY INDEX FOR LETTER G */
112 #define LETTER_H 7 /* ARRAY INDEX FOR LETTER H */
113 #define LETTER_I 8 /* ARRAY INDEX FOR LETTER I */
114 #define LETTER_J 9 /* ARRAY INDEX FOR LETTER J */
115 #define LETTER_K 10 /* ARRAY INDEX FOR LETTER K */
116 #define LETTER_L 11 /* ARRAY INDEX FOR LETTER L */
117 #define LETTER_M 12 /* ARRAY INDEX FOR LETTER M */
118 #define LETTER_N 13 /* ARRAY INDEX FOR LETTER N */
119 #define LETTER_O 14 /* ARRAY INDEX FOR LETTER O */
120 #define LETTER_P 15 /* ARRAY INDEX FOR LETTER P */
121 #define LETTER_Q 16 /* ARRAY INDEX FOR LETTER Q */
122 #define LETTER_R 17 /* ARRAY INDEX FOR LETTER R */
123 #define LETTER_S 18 /* ARRAY INDEX FOR LETTER S */
124 #define LETTER_T 19 /* ARRAY INDEX FOR LETTER T */
125 #define LETTER_U 20 /* ARRAY INDEX FOR LETTER U */
126 #define LETTER_V 21 /* ARRAY INDEX FOR LETTER V */
127 #define LETTER_W 22 /* ARRAY INDEX FOR LETTER W */
128 #define LETTER_X 23 /* ARRAY INDEX FOR LETTER X */
129 #define LETTER_Y 24 /* ARRAY INDEX FOR LETTER Y */
130 #define LETTER_Z 25 /* ARRAY INDEX FOR LETTER Z */
131 #define MGRS_LETTERS 3 /* NUMBER OF LETTERS IN MGRS */
132 #define ONEHT 100000.e0 /* ONE HUNDRED THOUSAND */
133 #define TWOMIL 2000000.e0 /* TWO MILLION */
134 #define TRUE 1 /* CONSTANT VALUE FOR TRUE VALUE */
135 #define FALSE 0 /* CONSTANT VALUE FOR FALSE VALUE */
136 #define PI 3.14159265358979323e0 /* PI */
137 #define PI_OVER_2 (PI / 2.0e0)
138 
139 #define MIN_EASTING 100000
140 #define MAX_EASTING 900000
141 #define MIN_NORTHING 0
142 #define MAX_NORTHING 10000000
143 #define MAX_PRECISION 5 /* Maximum precision of easting & northing */
144 #define MIN_UTM_LAT ( (-80 * PI) / 180.0 ) /* -80 degrees in radians */
145 #define MAX_UTM_LAT ( (84 * PI) / 180.0 ) /* 84 degrees in radians */
146 
147 #define MIN_EAST_NORTH 0
148 #define MAX_EAST_NORTH 4000000
149 
150 
151 /* Ellipsoid parameters, default to WGS 84 */
152 double MGRS_a = 6378137.0; /* Semi-major axis of ellipsoid in meters */
153 double MGRS_f = 1 / 298.257223563; /* Flattening of ellipsoid */
154 char MGRS_Ellipsoid_Code[3] = {'W','E',0};
155 
156 
157 /*
158  * CLARKE_1866 : Ellipsoid code for CLARKE_1866
159  * CLARKE_1880 : Ellipsoid code for CLARKE_1880
160  * BESSEL_1841 : Ellipsoid code for BESSEL_1841
161  * BESSEL_1841_NAMIBIA : Ellipsoid code for BESSEL 1841 (NAMIBIA)
162  */
163 const char* CLARKE_1866 = "CC";
164 const char* CLARKE_1880 = "CD";
165 const char* BESSEL_1841 = "BR";
166 const char* BESSEL_1841_NAMIBIA = "BN";
167 
168 
169 typedef struct Latitude_Band_Value
170 {
171  int letter; /* letter representing latitude band */
172  double min_northing; /* minimum northing for latitude band */
173  double north; /* upper latitude for latitude band */
174  double south; /* lower latitude for latitude band */
175  double northing_offset; /* latitude band northing offset */
176 } Latitude_Band;
177 
179  {{LETTER_C, 1100000.0, -72.0, -80.5, 0.0},
180  {LETTER_D, 2000000.0, -64.0, -72.0, 2000000.0},
181  {LETTER_E, 2800000.0, -56.0, -64.0, 2000000.0},
182  {LETTER_F, 3700000.0, -48.0, -56.0, 2000000.0},
183  {LETTER_G, 4600000.0, -40.0, -48.0, 4000000.0},
184  {LETTER_H, 5500000.0, -32.0, -40.0, 4000000.0},
185  {LETTER_J, 6400000.0, -24.0, -32.0, 6000000.0},
186  {LETTER_K, 7300000.0, -16.0, -24.0, 6000000.0},
187  {LETTER_L, 8200000.0, -8.0, -16.0, 8000000.0},
188  {LETTER_M, 9100000.0, 0.0, -8.0, 8000000.0},
189  {LETTER_N, 0.0, 8.0, 0.0, 0.0},
190  {LETTER_P, 800000.0, 16.0, 8.0, 0.0},
191  {LETTER_Q, 1700000.0, 24.0, 16.0, 0.0},
192  {LETTER_R, 2600000.0, 32.0, 24.0, 2000000.0},
193  {LETTER_S, 3500000.0, 40.0, 32.0, 2000000.0},
194  {LETTER_T, 4400000.0, 48.0, 40.0, 4000000.0},
195  {LETTER_U, 5300000.0, 56.0, 48.0, 4000000.0},
196  {LETTER_V, 6200000.0, 64.0, 56.0, 6000000.0},
197  {LETTER_W, 7000000.0, 72.0, 64.0, 6000000.0},
198  {LETTER_X, 7900000.0, 84.5, 72.0, 6000000.0}};
199 
200 
201 typedef struct UPS_Constant_Value
202 {
203  int letter; /* letter representing latitude band */
204  int ltr2_low_value; /* 2nd letter range - low number */
205  int ltr2_high_value; /* 2nd letter range - high number */
206  int ltr3_high_value; /* 3rd letter range - high number (UPS) */
207  double false_easting; /* False easting based on 2nd letter */
208  double false_northing; /* False northing based on 3rd letter */
209 } UPS_Constant;
210 
212  {{LETTER_A, LETTER_J, LETTER_Z, LETTER_Z, 800000.0, 800000.0},
213  {LETTER_B, LETTER_A, LETTER_R, LETTER_Z, 2000000.0, 800000.0},
214  {LETTER_Y, LETTER_J, LETTER_Z, LETTER_P, 800000.0, 1300000.0},
215  {LETTER_Z, LETTER_A, LETTER_J, LETTER_P, 2000000.0, 1300000.0}};
216 
217 /***************************************************************************/
218 /*
219  * FUNCTIONS
220  */
221 
222 int Get_Latitude_Band_Min_Northing(int letter, double* min_northing, double* northing_offset)
223 /*
224  * The function Get_Latitude_Band_Min_Northing receives a latitude band letter
225  * and uses the Latitude_Band_Table to determine the minimum northing and northing offset
226  * for that latitude band letter.
227  *
228  * letter : Latitude band letter (input)
229  * min_northing : Minimum northing for that letter (output)
230  */
231 { /* Get_Latitude_Band_Min_Northing */
232  int error_code = MGRS_NO_ERROR;
233 
234  if ((letter >= LETTER_C) && (letter <= LETTER_H))
235  {
236  *min_northing = Latitude_Band_Table[letter-2].min_northing;
237  *northing_offset = Latitude_Band_Table[letter-2].northing_offset;
238  }
239  else if ((letter >= LETTER_J) && (letter <= LETTER_N))
240  {
241  *min_northing = Latitude_Band_Table[letter-3].min_northing;
242  *northing_offset = Latitude_Band_Table[letter-3].northing_offset;
243  }
244  else if ((letter >= LETTER_P) && (letter <= LETTER_X))
245  {
246  *min_northing = Latitude_Band_Table[letter-4].min_northing;
247  *northing_offset = Latitude_Band_Table[letter-4].northing_offset;
248  }
249  else
250  error_code |= MGRS_STRING_ERROR;
251 
252  return error_code;
253 } /* Get_Latitude_Band_Min_Northing */
254 
255 
256 int Get_Latitude_Range(int letter, double* north, double* south)
257 /*
258  * The function Get_Latitude_Range receives a latitude band letter
259  * and uses the Latitude_Band_Table to determine the latitude band
260  * boundaries for that latitude band letter.
261  *
262  * letter : Latitude band letter (input)
263  * north : Northern latitude boundary for that letter (output)
264  * north : Southern latitude boundary for that letter (output)
265  */
266 { /* Get_Latitude_Range */
267  int error_code = MGRS_NO_ERROR;
268 
269  if ((letter >= LETTER_C) && (letter <= LETTER_H))
270  {
271  *north = Latitude_Band_Table[letter-2].north * DEG_TO_RAD;
272  *south = Latitude_Band_Table[letter-2].south * DEG_TO_RAD;
273  }
274  else if ((letter >= LETTER_J) && (letter <= LETTER_N))
275  {
276  *north = Latitude_Band_Table[letter-3].north * DEG_TO_RAD;
277  *south = Latitude_Band_Table[letter-3].south * DEG_TO_RAD;
278  }
279  else if ((letter >= LETTER_P) && (letter <= LETTER_X))
280  {
281  *north = Latitude_Band_Table[letter-4].north * DEG_TO_RAD;
282  *south = Latitude_Band_Table[letter-4].south * DEG_TO_RAD;
283  }
284  else
285  error_code |= MGRS_STRING_ERROR;
286 
287  return error_code;
288 } /* Get_Latitude_Range */
289 
290 
291 int Get_Latitude_Letter(double latitude, int* letter)
292 /*
293  * The function Get_Latitude_Letter receives a latitude value
294  * and uses the Latitude_Band_Table to determine the latitude band
295  * letter for that latitude.
296  *
297  * latitude : Latitude (input)
298  * letter : Latitude band letter (output)
299  */
300 { /* Get_Latitude_Letter */
301  double temp = 0.0;
302  int error_code = MGRS_NO_ERROR;
303  double lat_deg = latitude * RAD_TO_DEG;
304 
305  if (lat_deg >= 72 && lat_deg < 84.5)
306  *letter = LETTER_X;
307  else if (lat_deg > -80.5 && lat_deg < 72)
308  {
309  temp = ((latitude + (80.0 * DEG_TO_RAD)) / (8.0 * DEG_TO_RAD)) + 1.0e-12;
310  *letter = Latitude_Band_Table[(int)temp].letter;
311  }
312  else
313  error_code |= MGRS_LAT_ERROR;
314 
315  return error_code;
316 } /* Get_Latitude_Letter */
317 
318 
319 int Check_Zone(char* MGRS, int* zone_exists)
320 /*
321  * The function Check_Zone receives an MGRS coordinate string.
322  * If a zone is given, TRUE is returned. Otherwise, FALSE
323  * is returned.
324  *
325  * MGRS : MGRS coordinate string (input)
326  * zone_exists : TRUE if a zone is given,
327  * FALSE if a zone is not given (output)
328  */
329 { /* Check_Zone */
330  unsigned int i = 0;
331  unsigned int j = 0;
332  int num_digits = 0;
333  int error_code = MGRS_NO_ERROR;
334 
335  /* skip any leading blanks */
336  while (MGRS[i] == ' ')
337  i++;
338  j = i;
339  while (isdigit((unsigned char)MGRS[i]))
340  i++;
341  num_digits = i - j;
342  if (num_digits <= 2)
343  if (num_digits > 0)
344  *zone_exists = TRUE;
345  else
346  *zone_exists = FALSE;
347  else
348  error_code |= MGRS_STRING_ERROR;
349 
350  return error_code;
351 } /* Check_Zone */
352 
353 
354 int Round_MGRS (double value)
355 /*
356  * The function Round_MGRS rounds the input value to the
357  * nearest integer, using the standard engineering rule.
358  * The rounded integer value is then returned.
359  *
360  * value : Value to be rounded (input)
361  */
362 { /* Round_MGRS */
363  double ivalue;
364  int ival;
365  double fraction = modf (value, &ivalue);
366  ival = (int)(ivalue);
367  if ((fraction > 0.5) || ((fraction == 0.5) && (ival%2 == 1)))
368  ival++;
369  return (ival);
370 } /* Round_MGRS */
371 
372 
373 int Make_MGRS_String (char* MGRS,
374  int Zone,
375  int Letters[MGRS_LETTERS],
376  double Easting,
377  double Northing,
378  int Precision)
379 /*
380  * The function Make_MGRS_String constructs an MGRS string
381  * from its component parts.
382  *
383  * MGRS : MGRS coordinate string (output)
384  * Zone : UTM Zone (input)
385  * Letters : MGRS coordinate string letters (input)
386  * Easting : Easting value (input)
387  * Northing : Northing value (input)
388  * Precision : Precision level of MGRS string (input)
389  */
390 { /* Make_MGRS_String */
391  int i;
392  int j;
393  double divisor;
394  int east;
395  int north;
396  char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
397  int error_code = MGRS_NO_ERROR;
398 
399  i = 0;
400  if (Zone)
401  i = sprintf (MGRS+i,"%2.2d",Zone);
402  else
403  strncpy(MGRS, " ", 2); // 2 spaces
404 
405  for (j=0;j<3;j++)
406  MGRS[i++] = alphabet[Letters[j]];
407 
408  MGRS[i++] = ' '; // space
409 
410  divisor = pow (10.0, (5 - Precision));
411  Easting = fmod (Easting, 100000.0);
412  if (Easting >= 99999.5)
413  Easting = 99999.0;
414  east = (int)(Easting/divisor);
415  Northing = fmod (Northing, 100000.0);
416  if (Northing >= 99999.5)
417  Northing = 99999.0;
418  north = (int)(Northing/divisor);
419 
420  switch (Precision){
421  case 5:
422  sprintf(MGRS+i, "%05d %05d", east, north);
423  break;
424  case 4:
425  sprintf(MGRS+i, "%04d %04d", east, north);
426  break;
427  case 3:
428  sprintf(MGRS+i, "%03d %03d", east, north);
429  break;
430  case 2:
431  sprintf(MGRS+i, "%02d %02d", east, north);
432  break;
433  case 1:
434  sprintf(MGRS+i, "%01d %01d", east, north);
435  break;
436  }
437 
438  return (error_code);
439 } /* Make_MGRS_String */
440 
441 
442 int Break_MGRS_String (char* MGRS,
443  int* Zone,
444  int Letters[MGRS_LETTERS],
445  double* Easting,
446  double* Northing,
447  int* Precision)
448 /*
449  * The function Break_MGRS_String breaks down an MGRS
450  * coordinate string into its component parts.
451  *
452  * MGRS : MGRS coordinate string (input)
453  * Zone : UTM Zone (output)
454  * Letters : MGRS coordinate string letters (output)
455  * Easting : Easting value (output)
456  * Northing : Northing value (output)
457  * Precision : Precision level of MGRS string (output)
458  */
459 { /* Break_MGRS_String */
460  int num_digits;
461  int num_letters;
462  unsigned int i = 0;
463  unsigned int j = 0;
464  int error_code = MGRS_NO_ERROR;
465 
466  while (MGRS[i] == ' ')
467  i++; /* skip any leading blanks */
468  j = i;
469  while (isdigit((unsigned char)MGRS[i]))
470  i++;
471  num_digits = i - j;
472  if (num_digits <= 2)
473  if (num_digits > 0)
474  {
475  char zone_string[3];
476  /* get zone */
477  strncpy (zone_string, MGRS+j, 2);
478  zone_string[2] = 0;
479  sscanf (zone_string, "%d", Zone);
480  if ((*Zone < 1) || (*Zone > 60))
481  error_code |= MGRS_STRING_ERROR;
482  }
483  else
484  *Zone = 0;
485  else
486  error_code |= MGRS_STRING_ERROR;
487  j = i;
488 
489  while (isalpha((unsigned char)MGRS[i]))
490  i++;
491  num_letters = i - j;
492  if (num_letters == 3)
493  {
494  /* get letters */
495  Letters[0] = (toupper((unsigned char)MGRS[j]) - (int)'A');
496  if ((Letters[0] == LETTER_I) || (Letters[0] == LETTER_O))
497  error_code |= MGRS_STRING_ERROR;
498  Letters[1] = (toupper((unsigned char)MGRS[j+1]) - (int)'A');
499  if ((Letters[1] == LETTER_I) || (Letters[1] == LETTER_O))
500  error_code |= MGRS_STRING_ERROR;
501  Letters[2] = (toupper((unsigned char)MGRS[j+2]) - (int)'A');
502  if ((Letters[2] == LETTER_I) || (Letters[2] == LETTER_O))
503  error_code |= MGRS_STRING_ERROR;
504  }
505  else
506  error_code |= MGRS_STRING_ERROR;
507  j = i;
508  while (isdigit((unsigned char)MGRS[i]))
509  i++;
510  num_digits = i - j;
511  if ((num_digits <= 10) && (num_digits%2 == 0))
512  {
513  int n;
514  char east_string[6];
515  char north_string[6];
516  int east;
517  int north;
518  double multiplier;
519  /* get easting & northing */
520  n = num_digits/2;
521  *Precision = n;
522  if (n > 0)
523  {
524  strncpy (east_string, MGRS+j, n);
525  east_string[n] = 0;
526  sscanf (east_string, "%d", &east);
527  strncpy (north_string, MGRS+j+n, n);
528  north_string[n] = 0;
529  sscanf (north_string, "%d", &north);
530  multiplier = pow (10.0, 5 - n);
531  *Easting = east * multiplier;
532  *Northing = north * multiplier;
533  }
534  else
535  {
536  *Easting = 0.0;
537  *Northing = 0.0;
538  }
539  }
540  else
541  error_code |= MGRS_STRING_ERROR;
542 
543  return (error_code);
544 } /* Break_MGRS_String */
545 
546 
547 void Get_Grid_Values (int zone,
548  int* ltr2_low_value,
549  int* ltr2_high_value,
550  double *pattern_offset)
551 /*
552  * The function getGridValues sets the letter range used for
553  * the 2nd letter in the MGRS coordinate string, based on the set
554  * number of the utm zone. It also sets the pattern offset using a
555  * value of A for the second letter of the grid square, based on
556  * the grid pattern and set number of the utm zone.
557  *
558  * zone : Zone number (input)
559  * ltr2_low_value : 2nd letter low number (output)
560  * ltr2_high_value : 2nd letter high number (output)
561  * pattern_offset : Pattern offset (output)
562  */
563 { /* BEGIN Get_Grid_Values */
564  int set_number; /* Set number (1-6) based on UTM zone number */
565  int aa_pattern; /* Pattern based on ellipsoid code */
566 
567  set_number = zone % 6;
568 
569  if (!set_number)
570  set_number = 6;
571 
572  if (!strcmp(MGRS_Ellipsoid_Code,CLARKE_1866) || !strcmp(MGRS_Ellipsoid_Code, CLARKE_1880) ||
574  aa_pattern = FALSE;
575  else
576  aa_pattern = TRUE;
577 
578  if ((set_number == 1) || (set_number == 4))
579  {
580  *ltr2_low_value = LETTER_A;
581  *ltr2_high_value = LETTER_H;
582  }
583  else if ((set_number == 2) || (set_number == 5))
584  {
585  *ltr2_low_value = LETTER_J;
586  *ltr2_high_value = LETTER_R;
587  }
588  else if ((set_number == 3) || (set_number == 6))
589  {
590  *ltr2_low_value = LETTER_S;
591  *ltr2_high_value = LETTER_Z;
592  }
593 
594  /* False northing at A for second letter of grid square */
595  if (aa_pattern)
596  {
597  if ((set_number % 2) == 0)
598  *pattern_offset = 500000.0;
599  else
600  *pattern_offset = 0.0;
601  }
602  else
603  {
604  if ((set_number % 2) == 0)
605  *pattern_offset = 1500000.0;
606  else
607  *pattern_offset = 1000000.00;
608  }
609 } /* END OF Get_Grid_Values */
610 
611 
612 int UTM_To_MGRS (int Zone,
613  char Hemisphere,
614  double Longitude,
615  double Latitude,
616  double Easting,
617  double Northing,
618  int Precision,
619  char *MGRS)
620 /*
621  * The function UTM_To_MGRS calculates an MGRS coordinate string
622  * based on the zone, latitude, easting and northing.
623  *
624  * Zone : Zone number (input)
625  * Hemisphere: Hemisphere (input)
626  * Longitude : Longitude in radians (input)
627  * Latitude : Latitude in radians (input)
628  * Easting : Easting (input)
629  * Northing : Northing (input)
630  * Precision : Precision (input)
631  * MGRS : MGRS coordinate string (output)
632  */
633 { /* BEGIN UTM_To_MGRS */
634  double pattern_offset; /* Northing offset for 3rd letter */
635  double grid_easting; /* Easting used to derive 2nd letter of MGRS */
636  double grid_northing; /* Northing used to derive 3rd letter of MGRS */
637  int ltr2_low_value; /* 2nd letter range - low number */
638  int ltr2_high_value; /* 2nd letter range - high number */
639  int letters[MGRS_LETTERS]; /* Number location of 3 letters in alphabet */
640  double divisor;
641  double rounded_easting;
642  int temp_error_code = MGRS_NO_ERROR;
643  int error_code = MGRS_NO_ERROR;
644 
645  divisor = pow (10.0, (5 - Precision));
646  rounded_easting = Round_MGRS (Easting/divisor) * divisor;
647 
648  /* Special check for rounding to (truncated) eastern edge of zone 31V */
649  if ((Zone == 31) && (((Latitude >= 56.0 * DEG_TO_RAD) && (Latitude < 64.0 * DEG_TO_RAD)) && ((Longitude >= 3.0 * DEG_TO_RAD) || (rounded_easting >= 500000.0))))
650  { /* Reconvert to UTM zone 32 */
652  temp_error_code = Convert_Geodetic_To_UTM (Latitude, Longitude, &Zone, &Hemisphere, &Easting, &Northing);
653  if(temp_error_code)
654  {
655  if(temp_error_code & UTM_LAT_ERROR)
656  error_code |= MGRS_LAT_ERROR;
657  if(temp_error_code & UTM_LON_ERROR)
658  error_code |= MGRS_LON_ERROR;
659  if(temp_error_code & UTM_ZONE_OVERRIDE_ERROR)
660  error_code |= MGRS_ZONE_ERROR;
661  if(temp_error_code & UTM_EASTING_ERROR)
662  error_code |= MGRS_EASTING_ERROR;
663  if(temp_error_code & UTM_NORTHING_ERROR)
664  error_code |= MGRS_NORTHING_ERROR;
665 
666  return error_code;
667  }
668  else
669  /* Round easting value using new easting */
670  Easting = Round_MGRS (Easting/divisor) * divisor;
671  }
672  else
673  Easting = rounded_easting;
674 
675  /* Round northing values */
676  Northing = Round_MGRS (Northing/divisor) * divisor;
677 
678  if( Latitude <= 0.0 && Northing == 1.0e7)
679  {
680  Latitude = 0.0;
681  Northing = 0.0;
682  }
683 
684  Get_Grid_Values(Zone, &ltr2_low_value, &ltr2_high_value, &pattern_offset);
685 
686  error_code = Get_Latitude_Letter(Latitude, &letters[0]);
687 
688  if (!error_code)
689  {
690  grid_northing = Northing;
691 
692  while (grid_northing >= TWOMIL)
693  {
694  grid_northing = grid_northing - TWOMIL;
695  }
696  grid_northing = grid_northing + pattern_offset;
697  if(grid_northing >= TWOMIL)
698  grid_northing = grid_northing - TWOMIL;
699 
700  letters[2] = (int)(grid_northing / ONEHT);
701  if (letters[2] > LETTER_H)
702  letters[2] = letters[2] + 1;
703 
704  if (letters[2] > LETTER_N)
705  letters[2] = letters[2] + 1;
706 
707  grid_easting = Easting;
708  if (((letters[0] == LETTER_V) && (Zone == 31)) && (grid_easting == 500000.0))
709  grid_easting = grid_easting - 1.0; /* SUBTRACT 1 METER */
710 
711  letters[1] = ltr2_low_value + ((int)(grid_easting / ONEHT) -1);
712  if ((ltr2_low_value == LETTER_J) && (letters[1] > LETTER_N))
713  letters[1] = letters[1] + 1;
714 
715  Make_MGRS_String (MGRS, Zone, letters, grid_easting, Northing, Precision);
716  }
717  return error_code;
718 } /* END UTM_To_MGRS */
719 
720 
721 int Set_MGRS_Parameters (double a,
722  double f,
723  char *Ellipsoid_Code)
724 /*
725  * The function SET_MGRS_PARAMETERS receives the ellipsoid parameters and sets
726  * the corresponding state variables. If any errors occur, the error code(s)
727  * are returned by the function, otherwise MGRS_NO_ERROR is returned.
728  *
729  * a : Semi-major axis of ellipsoid in meters (input)
730  * f : Flattening of ellipsoid (input)
731  * Ellipsoid_Code : 2-letter code for ellipsoid (input)
732  */
733 { /* Set_MGRS_Parameters */
734 
735  double inv_f = 1 / f;
736  int Error_Code = MGRS_NO_ERROR;
737 
738  if (a <= 0.0)
739  { /* Semi-major axis must be greater than zero */
740  Error_Code |= MGRS_A_ERROR;
741  }
742  if ((inv_f < 250) || (inv_f > 350))
743  { /* Inverse flattening must be between 250 and 350 */
744  Error_Code |= MGRS_INV_F_ERROR;
745  }
746  if (!Error_Code)
747  { /* no errors */
748  MGRS_a = a;
749  MGRS_f = f;
750  strcpy (MGRS_Ellipsoid_Code, Ellipsoid_Code);
751  }
752  return (Error_Code);
753 } /* Set_MGRS_Parameters */
754 
755 
756 void Get_MGRS_Parameters (double *a,
757  double *f,
758  char* Ellipsoid_Code)
759 /*
760  * The function Get_MGRS_Parameters returns the current ellipsoid
761  * parameters.
762  *
763  * a : Semi-major axis of ellipsoid, in meters (output)
764  * f : Flattening of ellipsoid (output)
765  * Ellipsoid_Code : 2-letter code for ellipsoid (output)
766  */
767 { /* Get_MGRS_Parameters */
768  *a = MGRS_a;
769  *f = MGRS_f;
770  strcpy (Ellipsoid_Code, MGRS_Ellipsoid_Code);
771  return;
772 } /* Get_MGRS_Parameters */
773 
774 
775 int Convert_Geodetic_To_MGRS (double Latitude,
776  double Longitude,
777  int Precision,
778  char* MGRS)
779 /*
780  * The function Convert_Geodetic_To_MGRS converts Geodetic (latitude and
781  * Longitude) coordinates to an MGRS coordinate string, according to the
782  * current ellipsoid parameters. If any errors occur, the error code(s)
783  * are returned by the function, otherwise MGRS_NO_ERROR is returned.
784  *
785  * Latitude : Latitude in radians (input)
786  * Longitude : Longitude in radians (input)
787  * Precision : Precision level of MGRS string (input)
788  * MGRS : MGRS coordinate string (output)
789  *
790  */
791 { /* Convert_Geodetic_To_MGRS */
792  int zone;
793  char hemisphere;
794  double easting;
795  double northing;
796  int temp_error_code = MGRS_NO_ERROR;
797  int error_code = MGRS_NO_ERROR;
798 
799  if ((Latitude < -PI_OVER_2) || (Latitude > PI_OVER_2))
800  { /* Latitude out of range */
801  error_code |= MGRS_LAT_ERROR;
802  }
803  if ((Longitude < -PI) || (Longitude > (2*PI)))
804  { /* Longitude out of range */
805  error_code |= MGRS_LON_ERROR;
806  }
807  if ((Precision < 0) || (Precision > MAX_PRECISION))
808  error_code |= MGRS_PRECISION_ERROR;
809  if (!error_code)
810  {
811  if ((Latitude < MIN_UTM_LAT) || (Latitude > MAX_UTM_LAT))
812  {
813  temp_error_code = Set_UPS_Parameters (MGRS_a, MGRS_f);
814  if(!temp_error_code)
815  {
816  temp_error_code = Convert_Geodetic_To_UPS (Latitude, Longitude, &hemisphere, &easting, &northing);
817  if(!temp_error_code)
818  {
819  error_code |= Convert_UPS_To_MGRS (hemisphere, easting, northing, Precision, MGRS);
820  }
821  else
822  {
823  if(temp_error_code & UPS_LAT_ERROR)
824  error_code |= MGRS_LAT_ERROR;
825  if(temp_error_code & UPS_LON_ERROR)
826  error_code |= MGRS_LON_ERROR;
827  }
828  }
829  else
830  {
831  if(temp_error_code & UPS_A_ERROR)
832  error_code |= MGRS_A_ERROR;
833  if(temp_error_code & UPS_INV_F_ERROR)
834  error_code |= MGRS_INV_F_ERROR;
835  }
836  }
837  else
838  {
839  temp_error_code = Set_UTM_Parameters (MGRS_a, MGRS_f, 0);
840  if(!temp_error_code)
841  {
842  temp_error_code = Convert_Geodetic_To_UTM (Latitude, Longitude, &zone, &hemisphere, &easting, &northing);
843  if(!temp_error_code)
844  error_code |= UTM_To_MGRS (zone, hemisphere, Longitude, Latitude, easting, northing, Precision, MGRS);
845  else
846  {
847  if(temp_error_code & UTM_LAT_ERROR)
848  error_code |= MGRS_LAT_ERROR;
849  if(temp_error_code & UTM_LON_ERROR)
850  error_code |= MGRS_LON_ERROR;
851  if(temp_error_code & UTM_ZONE_OVERRIDE_ERROR)
852  error_code |= MGRS_ZONE_ERROR;
853  if(temp_error_code & UTM_EASTING_ERROR)
854  error_code |= MGRS_EASTING_ERROR;
855  if(temp_error_code & UTM_NORTHING_ERROR)
856  error_code |= MGRS_NORTHING_ERROR;
857  }
858  }
859  else
860  {
861  if(temp_error_code & UTM_A_ERROR)
862  error_code |= MGRS_A_ERROR;
863  if(temp_error_code & UTM_INV_F_ERROR)
864  error_code |= MGRS_INV_F_ERROR;
865  if(temp_error_code & UTM_ZONE_OVERRIDE_ERROR)
866  error_code |= MGRS_ZONE_ERROR;
867  }
868  }
869  }
870  return (error_code);
871 } /* Convert_Geodetic_To_MGRS */
872 
873 
874 int Convert_MGRS_To_Geodetic (char* MGRS,
875  double *Latitude,
876  double *Longitude)
877 /*
878  * The function Convert_MGRS_To_Geodetic converts an MGRS coordinate string
879  * to Geodetic (latitude and Longitude) coordinates
880  * according to the current ellipsoid parameters. If any errors occur,
881  * the error code(s) are returned by the function, otherwise UTM_NO_ERROR
882  * is returned.
883  *
884  * MGRS : MGRS coordinate string (input)
885  * Latitude : Latitude in radians (output)
886  * Longitude : Longitude in radians (output)
887  *
888  */
889 { /* Convert_MGRS_To_Geodetic */
890  int zone;
891  char hemisphere;
892  double easting;
893  double northing;
894  int zone_exists;
895  int temp_error_code = MGRS_NO_ERROR;
896  int error_code = MGRS_NO_ERROR;
897 
898  error_code = Check_Zone(MGRS, &zone_exists);
899  if (!error_code){
900  if (zone_exists)
901  {
902  error_code |= Convert_MGRS_To_UTM (MGRS, &zone, &hemisphere, &easting, &northing);
903  if(!error_code || (error_code & MGRS_LAT_WARNING))
904  {
905  temp_error_code = Set_UTM_Parameters (MGRS_a, MGRS_f, 0);
906  if(!temp_error_code)
907  {
908  temp_error_code = Convert_UTM_To_Geodetic (zone, hemisphere, easting, northing, Latitude, Longitude);
909  if(temp_error_code)
910  {
911  if((temp_error_code & UTM_ZONE_ERROR) || (temp_error_code & UTM_HEMISPHERE_ERROR))
912  error_code |= MGRS_STRING_ERROR;
913  if(temp_error_code & UTM_EASTING_ERROR)
914  error_code |= MGRS_EASTING_ERROR;
915  if(temp_error_code & UTM_NORTHING_ERROR)
916  error_code |= MGRS_NORTHING_ERROR;
917  }
918  }
919  else
920  {
921  if(temp_error_code & UTM_A_ERROR)
922  error_code |= MGRS_A_ERROR;
923  if(temp_error_code & UTM_INV_F_ERROR)
924  error_code |= MGRS_INV_F_ERROR;
925  if(temp_error_code & UTM_ZONE_OVERRIDE_ERROR)
926  error_code |= MGRS_ZONE_ERROR;
927  }
928  }
929  }
930  else
931  {
932  error_code |= Convert_MGRS_To_UPS (MGRS, &hemisphere, &easting, &northing);
933  if(!error_code)
934  {
935  temp_error_code = Set_UPS_Parameters (MGRS_a, MGRS_f);
936  if(!temp_error_code)
937  {
938  temp_error_code = Convert_UPS_To_Geodetic (hemisphere, easting, northing, Latitude, Longitude);
939  if(temp_error_code)
940  {
941  if(temp_error_code & UPS_HEMISPHERE_ERROR)
942  error_code |= MGRS_STRING_ERROR;
943  if(temp_error_code & UPS_EASTING_ERROR)
944  error_code |= MGRS_EASTING_ERROR;
945  if(temp_error_code & UPS_LAT_ERROR)
946  error_code |= MGRS_NORTHING_ERROR;
947  }
948  }
949  else
950  {
951  if(temp_error_code & UPS_A_ERROR)
952  error_code |= MGRS_A_ERROR;
953  if(temp_error_code & UPS_INV_F_ERROR)
954  error_code |= MGRS_INV_F_ERROR;
955  }
956  }
957  }
958  }
959  return (error_code);
960 } /* END OF Convert_MGRS_To_Geodetic */
961 
962 
963 int Convert_UTM_To_MGRS (int Zone,
964  char Hemisphere,
965  double Easting,
966  double Northing,
967  int Precision,
968  char* MGRS)
969 /*
970  * The function Convert_UTM_To_MGRS converts UTM (zone, easting, and
971  * northing) coordinates to an MGRS coordinate string, according to the
972  * current ellipsoid parameters. If any errors occur, the error code(s)
973  * are returned by the function, otherwise MGRS_NO_ERROR is returned.
974  *
975  * Zone : UTM zone (input)
976  * Hemisphere : North or South hemisphere (input)
977  * Easting : Easting (X) in meters (input)
978  * Northing : Northing (Y) in meters (input)
979  * Precision : Precision level of MGRS string (input)
980  * MGRS : MGRS coordinate string (output)
981  */
982 { /* Convert_UTM_To_MGRS */
983  double latitude; /* Latitude of UTM point */
984  double Longitude; /* Longitude of UTM point */
985  int utm_error_code = MGRS_NO_ERROR;
986  int error_code = MGRS_NO_ERROR;
987 
988  if ((Zone < 1) || (Zone > 60))
989  error_code |= MGRS_ZONE_ERROR;
990  if ((Hemisphere != 'S') && (Hemisphere != 'N'))
991  error_code |= MGRS_HEMISPHERE_ERROR;
992  if ((Easting < MIN_EASTING) || (Easting > MAX_EASTING))
993  error_code |= MGRS_EASTING_ERROR;
994  if ((Northing < MIN_NORTHING) || (Northing > MAX_NORTHING))
995  error_code |= MGRS_NORTHING_ERROR;
996  if ((Precision < 0) || (Precision > MAX_PRECISION))
997  error_code |= MGRS_PRECISION_ERROR;
998  if (!error_code)
999  {
1001  utm_error_code = Convert_UTM_To_Geodetic (Zone, Hemisphere, Easting, Northing, &latitude, &Longitude);
1002  if(utm_error_code)
1003  {
1004  if((utm_error_code & UTM_ZONE_ERROR) || (utm_error_code & UTM_HEMISPHERE_ERROR))
1005  error_code |= MGRS_STRING_ERROR;
1006  if(utm_error_code & UTM_EASTING_ERROR)
1007  error_code |= MGRS_EASTING_ERROR;
1008  if(utm_error_code & UTM_NORTHING_ERROR)
1009  error_code |= MGRS_NORTHING_ERROR;
1010  }
1011 
1012  error_code = UTM_To_MGRS (Zone, Hemisphere, Longitude, latitude, Easting, Northing, Precision, MGRS);
1013  }
1014  return (error_code);
1015 } /* Convert_UTM_To_MGRS */
1016 
1017 
1018 int Convert_MGRS_To_UTM (char *MGRS,
1019  int *Zone,
1020  char *Hemisphere,
1021  double *Easting,
1022  double *Northing)
1023 /*
1024  * The function Convert_MGRS_To_UTM converts an MGRS coordinate string
1025  * to UTM projection (zone, hemisphere, easting and northing) coordinates
1026  * according to the current ellipsoid parameters. If any errors occur,
1027  * the error code(s) are returned by the function, otherwise UTM_NO_ERROR
1028  * is returned.
1029  *
1030  * MGRS : MGRS coordinate string (input)
1031  * Zone : UTM zone (output)
1032  * Hemisphere : North or South hemisphere (output)
1033  * Easting : Easting (X) in meters (output)
1034  * Northing : Northing (Y) in meters (output)
1035  */
1036 { /* Convert_MGRS_To_UTM */
1037  double min_northing;
1038  double northing_offset;
1039  int ltr2_low_value;
1040  int ltr2_high_value;
1041  double pattern_offset;
1042  double upper_lat_limit; /* North latitude limits based on 1st letter */
1043  double lower_lat_limit; /* South latitude limits based on 1st letter */
1044  double grid_easting; /* Easting for 100,000 meter grid square */
1045  double grid_northing; /* Northing for 100,000 meter grid square */
1046  int letters[MGRS_LETTERS];
1047  int in_precision;
1048  double latitude = 0.0;
1049  double Longitude = 0.0;
1050  double divisor = 1.0;
1051  int utm_error_code = MGRS_NO_ERROR;
1052  int error_code = MGRS_NO_ERROR;
1053 
1054  error_code = Break_MGRS_String (MGRS, Zone, letters, Easting, Northing, &in_precision);
1055  if (!*Zone)
1056  error_code |= MGRS_STRING_ERROR;
1057  else
1058  {
1059  if (!error_code)
1060  {
1061  if ((letters[0] == LETTER_X) && ((*Zone == 32) || (*Zone == 34) || (*Zone == 36)))
1062  error_code |= MGRS_STRING_ERROR;
1063  else
1064  {
1065  if (letters[0] < LETTER_N)
1066  *Hemisphere = 'S';
1067  else
1068  *Hemisphere = 'N';
1069 
1070  Get_Grid_Values(*Zone, &ltr2_low_value, &ltr2_high_value, &pattern_offset);
1071 
1072  /* Check that the second letter of the MGRS string is within
1073  * the range of valid second letter values
1074  * Also check that the third letter is valid */
1075  if ((letters[1] < ltr2_low_value) || (letters[1] > ltr2_high_value) || (letters[2] > LETTER_V))
1076  error_code |= MGRS_STRING_ERROR;
1077 
1078  if (!error_code)
1079  {
1080  double row_letter_northing = (double)(letters[2]) * ONEHT;
1081  grid_easting = (double)((letters[1]) - ltr2_low_value + 1) * ONEHT;
1082  if ((ltr2_low_value == LETTER_J) && (letters[1] > LETTER_O))
1083  grid_easting = grid_easting - ONEHT;
1084 
1085  if (letters[2] > LETTER_O)
1086  row_letter_northing = row_letter_northing - ONEHT;
1087 
1088  if (letters[2] > LETTER_I)
1089  row_letter_northing = row_letter_northing - ONEHT;
1090 
1091  if (row_letter_northing >= TWOMIL)
1092  row_letter_northing = row_letter_northing - TWOMIL;
1093 
1094  error_code = Get_Latitude_Band_Min_Northing(letters[0], &min_northing, &northing_offset);
1095  if (!error_code)
1096  {
1097  grid_northing = row_letter_northing - pattern_offset;
1098  if(grid_northing < 0)
1099  grid_northing += TWOMIL;
1100 
1101  grid_northing += northing_offset;
1102 
1103  if(grid_northing < min_northing)
1104  grid_northing += TWOMIL;
1105 
1106  *Easting = grid_easting + *Easting;
1107  *Northing = grid_northing + *Northing;
1108 
1109  /* check that point is within Zone Letter bounds */
1110  utm_error_code = Set_UTM_Parameters(MGRS_a,MGRS_f,0);
1111  if (!utm_error_code)
1112  {
1113  utm_error_code = Convert_UTM_To_Geodetic(*Zone,*Hemisphere,*Easting,*Northing,&latitude,&Longitude);
1114  if (!utm_error_code)
1115  {
1116  divisor = pow (10.0, in_precision);
1117  error_code = Get_Latitude_Range(letters[0], &upper_lat_limit, &lower_lat_limit);
1118  if (!error_code)
1119  {
1120  if (!(((lower_lat_limit - DEG_TO_RAD/divisor) <= latitude) && (latitude <= (upper_lat_limit + DEG_TO_RAD/divisor))))
1121  error_code |= MGRS_LAT_WARNING;
1122  }
1123  }
1124  else
1125  {
1126  if((utm_error_code & UTM_ZONE_ERROR) || (utm_error_code & UTM_HEMISPHERE_ERROR))
1127  error_code |= MGRS_STRING_ERROR;
1128  if(utm_error_code & UTM_EASTING_ERROR)
1129  error_code |= MGRS_EASTING_ERROR;
1130  if(utm_error_code & UTM_NORTHING_ERROR)
1131  error_code |= MGRS_NORTHING_ERROR;
1132  }
1133  }
1134  else
1135  {
1136  if(utm_error_code & UTM_A_ERROR)
1137  error_code |= MGRS_A_ERROR;
1138  if(utm_error_code & UTM_INV_F_ERROR)
1139  error_code |= MGRS_INV_F_ERROR;
1140  if(utm_error_code & UTM_ZONE_OVERRIDE_ERROR)
1141  error_code |= MGRS_ZONE_ERROR;
1142  }
1143  }
1144  }
1145  }
1146  }
1147  }
1148  return (error_code);
1149 } /* Convert_MGRS_To_UTM */
1150 
1151 
1152 int Convert_UPS_To_MGRS (char Hemisphere,
1153  double Easting,
1154  double Northing,
1155  int Precision,
1156  char* MGRS)
1157 /*
1158  * The function Convert_UPS_To_MGRS converts UPS (hemisphere, easting,
1159  * and northing) coordinates to an MGRS coordinate string according to
1160  * the current ellipsoid parameters. If any errors occur, the error
1161  * code(s) are returned by the function, otherwise UPS_NO_ERROR is
1162  * returned.
1163  *
1164  * Hemisphere : Hemisphere either 'N' or 'S' (input)
1165  * Easting : Easting/X in meters (input)
1166  * Northing : Northing/Y in meters (input)
1167  * Precision : Precision level of MGRS string (input)
1168  * MGRS : MGRS coordinate string (output)
1169  */
1170 { /* Convert_UPS_To_MGRS */
1171  double false_easting; /* False easting for 2nd letter */
1172  double false_northing; /* False northing for 3rd letter */
1173  double grid_easting; /* Easting used to derive 2nd letter of MGRS */
1174  double grid_northing; /* Northing used to derive 3rd letter of MGRS */
1175  int ltr2_low_value; /* 2nd letter range - low number */
1176  int letters[MGRS_LETTERS]; /* Number location of 3 letters in alphabet */
1177  double divisor;
1178  int index = 0;
1179  int error_code = MGRS_NO_ERROR;
1180 
1181  if ((Hemisphere != 'N') && (Hemisphere != 'S'))
1182  error_code |= MGRS_HEMISPHERE_ERROR;
1183  if ((Easting < MIN_EAST_NORTH) || (Easting > MAX_EAST_NORTH))
1184  error_code |= MGRS_EASTING_ERROR;
1185  if ((Northing < MIN_EAST_NORTH) || (Northing > MAX_EAST_NORTH))
1186  error_code |= MGRS_NORTHING_ERROR;
1187  if ((Precision < 0) || (Precision > MAX_PRECISION))
1188  error_code |= MGRS_PRECISION_ERROR;
1189  if (!error_code)
1190  {
1191  divisor = pow (10.0, (5 - Precision));
1192  Easting = Round_MGRS (Easting/divisor) * divisor;
1193  Northing = Round_MGRS (Northing/divisor) * divisor;
1194 
1195  if (Hemisphere == 'N')
1196  {
1197  if (Easting >= TWOMIL)
1198  letters[0] = LETTER_Z;
1199  else
1200  letters[0] = LETTER_Y;
1201 
1202  index = letters[0] - 22;
1203  ltr2_low_value = UPS_Constant_Table[index].ltr2_low_value;
1204  false_easting = UPS_Constant_Table[index].false_easting;
1205  false_northing = UPS_Constant_Table[index].false_northing;
1206  }
1207  else
1208  {
1209  if (Easting >= TWOMIL)
1210  letters[0] = LETTER_B;
1211  else
1212  letters[0] = LETTER_A;
1213 
1214  ltr2_low_value = UPS_Constant_Table[letters[0]].ltr2_low_value;
1215  false_easting = UPS_Constant_Table[letters[0]].false_easting;
1216  false_northing = UPS_Constant_Table[letters[0]].false_northing;
1217  }
1218 
1219  grid_northing = Northing;
1220  grid_northing = grid_northing - false_northing;
1221  letters[2] = (int)(grid_northing / ONEHT);
1222 
1223  if (letters[2] > LETTER_H)
1224  letters[2] = letters[2] + 1;
1225 
1226  if (letters[2] > LETTER_N)
1227  letters[2] = letters[2] + 1;
1228 
1229  grid_easting = Easting;
1230  grid_easting = grid_easting - false_easting;
1231  letters[1] = ltr2_low_value + ((int)(grid_easting / ONEHT));
1232 
1233  if (Easting < TWOMIL)
1234  {
1235  if (letters[1] > LETTER_L)
1236  letters[1] = letters[1] + 3;
1237 
1238  if (letters[1] > LETTER_U)
1239  letters[1] = letters[1] + 2;
1240  }
1241  else
1242  {
1243  if (letters[1] > LETTER_C)
1244  letters[1] = letters[1] + 2;
1245 
1246  if (letters[1] > LETTER_H)
1247  letters[1] = letters[1] + 1;
1248 
1249  if (letters[1] > LETTER_L)
1250  letters[1] = letters[1] + 3;
1251  }
1252 
1253  Make_MGRS_String (MGRS, 0, letters, Easting, Northing, Precision);
1254  }
1255  return (error_code);
1256 } /* Convert_UPS_To_MGRS */
1257 
1258 
1259 int Convert_MGRS_To_UPS ( char *MGRS,
1260  char *Hemisphere,
1261  double *Easting,
1262  double *Northing)
1263 /*
1264  * The function Convert_MGRS_To_UPS converts an MGRS coordinate string
1265  * to UPS (hemisphere, easting, and northing) coordinates, according
1266  * to the current ellipsoid parameters. If any errors occur, the error
1267  * code(s) are returned by the function, otherwide UPS_NO_ERROR is returned.
1268  *
1269  * MGRS : MGRS coordinate string (input)
1270  * Hemisphere : Hemisphere either 'N' or 'S' (output)
1271  * Easting : Easting/X in meters (output)
1272  * Northing : Northing/Y in meters (output)
1273  */
1274 { /* Convert_MGRS_To_UPS */
1275  int ltr2_high_value; /* 2nd letter range - high number */
1276  int ltr3_high_value; /* 3rd letter range - high number (UPS) */
1277  int ltr2_low_value; /* 2nd letter range - low number */
1278  double false_easting; /* False easting for 2nd letter */
1279  double false_northing; /* False northing for 3rd letter */
1280  double grid_easting; /* easting for 100,000 meter grid square */
1281  double grid_northing; /* northing for 100,000 meter grid square */
1282  int zone;
1283  int letters[MGRS_LETTERS];
1284  int in_precision;
1285  int index = 0;
1286  int error_code = MGRS_NO_ERROR;
1287 
1288  error_code = Break_MGRS_String (MGRS, &zone, letters, Easting, Northing, &in_precision);
1289  if (zone)
1290  error_code |= MGRS_STRING_ERROR;
1291  else
1292  {
1293  if (!error_code)
1294  {
1295  if (letters[0] >= LETTER_Y)
1296  {
1297  *Hemisphere = 'N';
1298 
1299  index = letters[0] - 22;
1300  ltr2_low_value = UPS_Constant_Table[index].ltr2_low_value;
1301  ltr2_high_value = UPS_Constant_Table[index].ltr2_high_value;
1302  ltr3_high_value = UPS_Constant_Table[index].ltr3_high_value;
1303  false_easting = UPS_Constant_Table[index].false_easting;
1304  false_northing = UPS_Constant_Table[index].false_northing;
1305  }
1306  else
1307  {
1308  *Hemisphere = 'S';
1309 
1310  ltr2_low_value = UPS_Constant_Table[letters[0]].ltr2_low_value;
1311  ltr2_high_value = UPS_Constant_Table[letters[0]].ltr2_high_value;
1312  ltr3_high_value = UPS_Constant_Table[letters[0]].ltr3_high_value;
1313  false_easting = UPS_Constant_Table[letters[0]].false_easting;
1314  false_northing = UPS_Constant_Table[letters[0]].false_northing;
1315  }
1316 
1317  /* Check that the second letter of the MGRS string is within
1318  * the range of valid second letter values
1319  * Also check that the third letter is valid */
1320  if ((letters[1] < ltr2_low_value) || (letters[1] > ltr2_high_value) ||
1321  ((letters[1] == LETTER_D) || (letters[1] == LETTER_E) ||
1322  (letters[1] == LETTER_M) || (letters[1] == LETTER_N) ||
1323  (letters[1] == LETTER_V) || (letters[1] == LETTER_W)) ||
1324  (letters[2] > ltr3_high_value))
1325  error_code |= MGRS_STRING_ERROR;
1326 
1327  if (!error_code)
1328  {
1329  grid_northing = (double)letters[2] * ONEHT + false_northing;
1330  if (letters[2] > LETTER_I)
1331  grid_northing = grid_northing - ONEHT;
1332 
1333  if (letters[2] > LETTER_O)
1334  grid_northing = grid_northing - ONEHT;
1335 
1336  grid_easting = (double)((letters[1]) - ltr2_low_value) * ONEHT + false_easting;
1337  if (ltr2_low_value != LETTER_A)
1338  {
1339  if (letters[1] > LETTER_L)
1340  grid_easting = grid_easting - 300000.0;
1341 
1342  if (letters[1] > LETTER_U)
1343  grid_easting = grid_easting - 200000.0;
1344  }
1345  else
1346  {
1347  if (letters[1] > LETTER_C)
1348  grid_easting = grid_easting - 200000.0;
1349 
1350  if (letters[1] > LETTER_I)
1351  grid_easting = grid_easting - ONEHT;
1352 
1353  if (letters[1] > LETTER_L)
1354  grid_easting = grid_easting - 300000.0;
1355  }
1356 
1357  *Easting = grid_easting + *Easting;
1358  *Northing = grid_northing + *Northing;
1359  }
1360  }
1361  }
1362  return (error_code);
1363 } /* Convert_MGRS_To_UPS */
1364 
1365 
1366 
#define MAX_EAST_NORTH
Definition: mgrs.c:148
#define LETTER_Z
Definition: mgrs.c:130
#define PI_OVER_2
Definition: mgrs.c:137
#define LETTER_R
Definition: mgrs.c:122
#define LETTER_Y
Definition: mgrs.c:129
int Convert_UTM_To_MGRS(int Zone, char Hemisphere, double Easting, double Northing, int Precision, char *MGRS)
Definition: mgrs.c:963
#define LETTER_B
Definition: mgrs.c:106
#define UTM_EASTING_ERROR
Definition: utm.h:83
int ltr3_high_value
Definition: mgrs.c:206
#define MIN_EASTING
Definition: mgrs.c:139
#define LETTER_O
Definition: mgrs.c:119
#define TWOMIL
Definition: mgrs.c:133
#define MAX_PRECISION
Definition: mgrs.c:143
int Convert_MGRS_To_UTM(char *MGRS, int *Zone, char *Hemisphere, double *Easting, double *Northing)
Definition: mgrs.c:1018
#define MAX_NORTHING
Definition: mgrs.c:142
#define LETTER_I
Definition: mgrs.c:113
#define MGRS_EASTING_ERROR
Definition: mgrs.h:98
#define LETTER_X
Definition: mgrs.c:128
double MGRS_f
Definition: mgrs.c:153
int sprintf(char *out, const char *format,...)
#define TRUE
Definition: mgrs.c:134
int Get_Latitude_Letter(double latitude, int *letter)
Definition: mgrs.c:291
int Convert_Geodetic_To_MGRS(double Latitude, double Longitude, int Precision, char *MGRS)
Definition: mgrs.c:775
#define MGRS_ZONE_ERROR
Definition: mgrs.h:100
int Convert_UTM_To_Geodetic(int Zone, char Hemisphere, double Easting, double Northing, double *Latitude, double *intitude)
Definition: utm.c:291
volatile int j
Definition: loadabletest.c:12
int Check_Zone(char *MGRS, int *zone_exists)
Definition: mgrs.c:319
#define LETTER_P
Definition: mgrs.c:120
#define UPS_LAT_ERROR
Definition: ups.h:89
#define UTM_LAT_ERROR
Definition: utm.h:81
#define LETTER_V
Definition: mgrs.c:126
#define ONEHT
Definition: mgrs.c:132
struct Latitude_Band_Value Latitude_Band
#define MGRS_STRING_ERROR
Definition: mgrs.h:94
int ltr2_low_value
Definition: mgrs.c:204
double south
Definition: mgrs.c:174
int Set_UTM_Parameters(double a, double f, int override)
Definition: utm.c:113
#define MIN_UTM_LAT
Definition: mgrs.c:144
#define MIN_EAST_NORTH
Definition: mgrs.c:147
#define MGRS_NO_ERROR
Definition: mgrs.h:91
char MGRS_Ellipsoid_Code[3]
Definition: mgrs.c:154
#define LETTER_K
Definition: mgrs.c:115
#define FALSE
Definition: mgrs.c:135
#define MGRS_LON_ERROR
Definition: mgrs.h:93
#define LETTER_E
Definition: mgrs.c:109
#define LETTER_M
Definition: mgrs.c:117
#define LETTER_W
Definition: mgrs.c:127
#define LETTER_S
Definition: mgrs.c:123
#define PI
Definition: mgrs.c:136
#define UTM_ZONE_OVERRIDE_ERROR
Definition: utm.h:87
void Get_MGRS_Parameters(double *a, double *f, char *Ellipsoid_Code)
Definition: mgrs.c:756
int Convert_UPS_To_MGRS(char Hemisphere, double Easting, double Northing, int Precision, char *MGRS)
Definition: mgrs.c:1152
#define LETTER_Q
Definition: mgrs.c:121
#define UTM_NORTHING_ERROR
Definition: utm.h:84
const char * CLARKE_1866
Definition: mgrs.c:163
double false_northing
Definition: mgrs.c:208
int Convert_Geodetic_To_UPS(double Latitude, double longitude, char *Hemisphere, double *Easting, double *Northing)
Definition: ups.c:174
static const Latitude_Band Latitude_Band_Table[20]
Definition: mgrs.c:178
#define LETTER_G
Definition: mgrs.c:111
#define LETTER_H
Definition: mgrs.c:112
uint8_t i
Definition: msp_messages.h:97
double northing_offset
Definition: mgrs.c:175
#define UTM_ZONE_ERROR
Definition: utm.h:85
int ltr2_high_value
Definition: mgrs.c:205
double false_easting
Definition: mgrs.c:207
#define LETTER_D
Definition: mgrs.c:108
#define LETTER_C
Definition: mgrs.c:107
const char * BESSEL_1841_NAMIBIA
Definition: mgrs.c:166
#define MGRS_NORTHING_ERROR
Definition: mgrs.h:99
int Get_Latitude_Range(int letter, double *north, double *south)
Definition: mgrs.c:256
#define UPS_A_ERROR
Definition: ups.h:94
uint16_t value
Definition: storm32bgc.c:155
double north
Definition: mgrs.c:173
#define MGRS_A_ERROR
Definition: mgrs.h:96
#define LETTER_T
Definition: mgrs.c:124
#define MAX_UTM_LAT
Definition: mgrs.c:145
int Set_MGRS_Parameters(double a, double f, char *Ellipsoid_Code)
Definition: mgrs.c:721
int Set_UPS_Parameters(double a, double f)
Definition: ups.c:125
static const UPS_Constant UPS_Constant_Table[4]
Definition: mgrs.c:211
#define MGRS_PRECISION_ERROR
Definition: mgrs.h:95
#define UTM_LON_ERROR
Definition: utm.h:82
#define UPS_INV_F_ERROR
Definition: ups.h:95
int Convert_Geodetic_To_UTM(double Latitude, double intitude, int *Zone, char *Hemisphere, double *Easting, double *Northing)
Definition: utm.c:172
#define LETTER_A
Definition: mgrs.c:105
tuple f
Definition: px_mkfw.py:81
#define RAD_TO_DEG
Definition: mgrs.c:104
#define UPS_EASTING_ERROR
Definition: ups.h:92
int Convert_MGRS_To_UPS(char *MGRS, char *Hemisphere, double *Easting, double *Northing)
Definition: mgrs.c:1259
int Convert_UPS_To_Geodetic(char Hemisphere, double Easting, double Northing, double *Latitude, double *longitude)
Definition: ups.c:244
#define DEG_TO_RAD
Definition: mgrs.c:103
#define UPS_HEMISPHERE_ERROR
Definition: ups.h:91
#define MGRS_HEMISPHERE_ERROR
Definition: mgrs.h:101
int Make_MGRS_String(char *MGRS, int Zone, int Letters[MGRS_LETTERS], double Easting, double Northing, int Precision)
Definition: mgrs.c:373
#define UTM_A_ERROR
Definition: utm.h:88
#define UTM_INV_F_ERROR
Definition: utm.h:89
int Get_Latitude_Band_Min_Northing(int letter, double *min_northing, double *northing_offset)
Definition: mgrs.c:222
#define LETTER_U
Definition: mgrs.c:125
#define MGRS_INV_F_ERROR
Definition: mgrs.h:97
const char * CLARKE_1880
Definition: mgrs.c:164
void Get_Grid_Values(int zone, int *ltr2_low_value, int *ltr2_high_value, double *pattern_offset)
Definition: mgrs.c:547
#define LETTER_N
Definition: mgrs.c:118
int Break_MGRS_String(char *MGRS, int *Zone, int Letters[MGRS_LETTERS], double *Easting, double *Northing, int *Precision)
Definition: mgrs.c:442
int32_t latitude
#define LETTER_L
Definition: mgrs.c:116
const char * BESSEL_1841
Definition: mgrs.c:165
#define MGRS_LAT_ERROR
Definition: mgrs.h:92
double min_northing
Definition: mgrs.c:172
int UTM_To_MGRS(int Zone, char Hemisphere, double Longitude, double Latitude, double Easting, double Northing, int Precision, char *MGRS)
Definition: mgrs.c:612
#define MAX_EASTING
Definition: mgrs.c:140
#define MIN_NORTHING
Definition: mgrs.c:141
#define UTM_HEMISPHERE_ERROR
Definition: utm.h:86
#define LETTER_F
Definition: mgrs.c:110
int Convert_MGRS_To_Geodetic(char *MGRS, double *Latitude, double *Longitude)
Definition: mgrs.c:874
double MGRS_a
Definition: mgrs.c:152
int Round_MGRS(double value)
Definition: mgrs.c:354
#define MGRS_LAT_WARNING
Definition: mgrs.h:102
#define UPS_LON_ERROR
Definition: ups.h:90
#define MGRS_LETTERS
Definition: mgrs.c:131
#define LETTER_J
Definition: mgrs.c:114
struct UPS_Constant_Value UPS_Constant