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 long,
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  *
72  */
73 
74 
75 /***************************************************************************/
76 /*
77  *                               INCLUDES
78  */
79 #include <ctype.h>
80 #include <math.h>
81 #include <stdio.h>
82 #include <string.h>
83 #include <ossim/projection/ossimUps.h>
84 #include <ossim/projection/ossimUtm.h>
85 #include <ossim/projection/ossimMgrs.h>
86 
87 /*
88  *      ctype.h     - Standard C character handling library
89  *      math.h      - Standard C math library
90  *      stdio.h     - Standard C input/output library
91  *      string.h    - Standard C string handling library
92  *      ups.h       - Universal Polar Stereographic (UPS) projection
93  *      utm.h       - Universal Transverse Mercator (UTM) projection
94  *      mgrs.h      - function prototype error checking
95  */
96 
97 
98 /***************************************************************************/
99 /*
100  *                              GLOBAL DECLARATIONS
101  */
102 #define DEGRAD       0.017453292519943295 /* PI/180                          */
103 #define R3           0.052359877559829890 /* RADIANS FOR  3 DEGREES          */
104 #define R8           0.139626340159546400 /* RADIANS FOR  8 DEGREES          */
105 #define R9           0.157079632679489700 /* RADIANS FOR  9 DEGREES          */
106 #define R21          0.366519142918809200 /* RADIANS FOR  21 DEGREES         */
107 #define R33          0.575958653158128800 /* RADIANS FOR  33 DEGREES         */
108 #define R56          0.977384381116824600 /* RADIANS FOR  56 DEGREES         */
109 #define R64          1.117010721276371000 /* RADIANS FOR  64 DEGREES         */
110 #define R72          1.256637061435917000 /* RADIANS FOR  72 DEGREES         */
111 #define R80          1.396263401595464000 /* RADIANS FOR  80 DEGREES         */
112 #define UPS_SOUTH              3    /* UPS COORDINATE IN SOUTHERN HEMISPHERE */
113 #define UPS_NORTH              2    /* UPS COORDINATE IN NORTHERN HEMISPHERE */
114 #define UTM                    1    /* UTM COORDINATE                        */
115 #define ALBET                 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* ALPHABET       */
116 #define LETTER_A               0   /* ARRAY INDEX FOR LETTER A               */
117 #define LETTER_B               1   /* ARRAY INDEX FOR LETTER B               */
118 #define LETTER_C               2   /* ARRAY INDEX FOR LETTER C               */
119 #define LETTER_D               3   /* ARRAY INDEX FOR LETTER D               */
120 #define LETTER_E               4   /* ARRAY INDEX FOR LETTER E               */
121 #define LETTER_H               7   /* ARRAY INDEX FOR LETTER H               */
122 #define LETTER_I               8   /* ARRAY INDEX FOR LETTER I               */
123 #define LETTER_J               9   /* ARRAY INDEX FOR LETTER J               */
124 #define LETTER_L              11   /* ARRAY INDEX FOR LETTER L               */
125 #define LETTER_M              12   /* ARRAY INDEX FOR LETTER M               */
126 #define LETTER_N              13   /* ARRAY INDEX FOR LETTER N               */
127 #define LETTER_O              14   /* ARRAY INDEX FOR LETTER O               */
128 #define LETTER_P              15   /* ARRAY INDEX FOR LETTER P               */
129 #define LETTER_Q              16   /* ARRAY INDEX FOR LETTER Q               */
130 #define LETTER_R              17   /* ARRAY INDEX FOR LETTER R               */
131 #define LETTER_S              18   /* ARRAY INDEX FOR LETTER S               */
132 #define LETTER_U              20   /* ARRAY INDEX FOR LETTER U               */
133 #define LETTER_V              21   /* ARRAY INDEX FOR LETTER V               */
134 #define LETTER_W              22   /* ARRAY INDEX FOR LETTER W               */
135 #define LETTER_X              23   /* ARRAY INDEX FOR LETTER X               */
136 #define LETTER_Y              24   /* ARRAY INDEX FOR LETTER Y               */
137 #define LETTER_Z              25   /* ARRAY INDEX FOR LETTER Z               */
138 #define RND1                  0.1e0  /* ROUND TO NEAREST .1            */
139 #define RND5                  0.5e0  /* ROUND TO NEAREST .5            */
140 #define EOLN                   '\0'  /* END OF STRING CHARACTER        */
141 #define BLANK                   ' '  /* BLANK CHARACTER                */
142 #define OSSIM_MGRS_LETTERS            3  /* NUMBER OF LETTERS IN MGRS              */
143 #define NUM_OFFSET             48  /* USED TO CONVERT NUMBERS TO LETTERS     */
144 #define ONEHT          100000.e0    /* ONE HUNDRED THOUSAND                  */
145 #define TWOMIL        2000000.e0    /* TWO MILLION                           */
146 #define EIGHT          800000.e0    /* EIGHT HUNDRED THOUSAND                */
147 #define ONE3HT        1300000.e0    /* ONE MILLION THREE HUNDRED THOUSAND    */
148 #define ZERO                   0.e0  /* ZERO                           */
149 #define TEN                10.e0    /* TEN                                   */
150 #define TRUE                      1  /* CONSTANT VALUE FOR TRUE VALUE  */
151 #define FALSE                     0  /* CONSTANT VALUE FOR FALSE VALUE */
152 #define PI    3.14159265358979323e0  /* PI                             */
153 #define PI_OVER_2  (PI / 2.0e0)
154 #define NUM                   "01234567890"                /* NUMBERS        */
155 #define MAXALBET              25   /* LAST INDEX IN ALPHABET ARRAY(0-25)     */
156 #define MAXNUMBER             10   /* LAST INDEX IN NUMBER ARRAY(0-9)        */
157 #define OSSIM_MGRS_ZONE_AND_LETTERS   5  /* NUM. OF CHARS. IN ZONE AND LETTERS     */
158 #define OSSIM_MGRS_MINIMUM            9  /* MINIMUM NUMBER OF CHARS FOR MGRS       */
159 #define OSSIM_MGRS_MAXIMUM           15  /* MAXIMUM NUMBER OF CHARS FOR MGRS       */
160 
161 #define MIN_EASTING  100000
162 #define MAX_EASTING  900000
163 #define MIN_NORTHING 0
164 #define MAX_NORTHING 10000000
165 #define MAX_PRECISION           5   /* Maximum precision of easting & northing */
166 #define MIN_UTM_LAT      ( (-80 * PI) / 180.0 ) /* -80 degrees in radians    */
167 #define MAX_UTM_LAT      ( (84 * PI) / 180.0 )  /* 84 degrees in radians     */
168 
169 #define MIN_EAST_NORTH 0
170 #define MAX_EAST_NORTH 4000000
171 
172 /* Ellipsoid parameters, default to WGS 84 */
173 double OSSIM_MGRS_a = 6378137.0;    /* Semi-major axis of ellipsoid in meters */
174 double OSSIM_MGRS_f = 1 / 298.257223563; /* Flattening of ellipsoid           */
175 double OSSIM_MGRS_recpf = 298.257223563;
176 char   OSSIM_MGRS_Ellipsoid_Code[3] = {'W','E',0};
177 
178 const char* OSSIM_CLARKE_1866 = "CC";
179 const char* OSSIM_CLARKE_1880 = "CD";
180 const char* OSSIM_BESSEL_1841 = "BR";
181 /*
182  *    OSSIM_CLARKE_1866 : Ellipsoid code for OSSIM_CLARKE_1866
183  *    OSSIM_CLARKE_1880 : Ellipsoid code for OSSIM_CLARKE_1880
184  *    OSSIM_BESSEL_1841 : Ellipsoid code for OSSIM_BESSEL_1841
185  */
186 
187 
188 /***************************************************************************/
189 /*
190  *                              FUNCTIONS
191  */
192 
193 
UTMSET(long izone,long * ltrlow,long * ltrhi,double * fnltr)194 void UTMSET (long izone,
195              long* ltrlow,
196              long* ltrhi,
197              double *fnltr)
198 { /* BEGIN UTMSET */
199   /*
200    *    izone  : Zone number
201    *    ltrlow : 2nd letter low number
202    *    ltrhi  : 2nd letter high number
203    *    fnltr  : False northing
204    */
205   long iset;      /* Set number (1-6) based on UTM zone number           */
206   long igroup;    /* Group number (1-2) based on ellipsoid code and zone */
207   iset = 1;
208   while (((izone-iset) / 6) * 6 + iset != izone)
209   {
210     iset = iset +1;
211     if (iset > 6)
212     {
213       return;
214     }
215   }
216   igroup = 1;
217   if (!strcmp(OSSIM_MGRS_Ellipsoid_Code,OSSIM_CLARKE_1866) || !strcmp(OSSIM_MGRS_Ellipsoid_Code, OSSIM_CLARKE_1880) || !strcmp(OSSIM_MGRS_Ellipsoid_Code,OSSIM_BESSEL_1841))
218   {
219     igroup = 2;
220   }
221   else if (!strcmp(OSSIM_MGRS_Ellipsoid_Code, OSSIM_CLARKE_1866) && (izone >= 47) && (izone <= 55 ))
222   {
223     igroup = 1;
224   }
225   if ((iset == 1) || (iset == 4))
226   {
227     *ltrlow = LETTER_A;
228     *ltrhi = LETTER_H;
229   }
230   else if ((iset == 2) || (iset == 5))
231   {
232     *ltrlow = LETTER_J;
233     *ltrhi = LETTER_R;
234   }
235   else if ((iset == 3) || (iset == 6))
236   {
237     *ltrlow = LETTER_S;
238     *ltrhi = LETTER_Z;
239   }
240   if (igroup == 1)
241   {
242     *fnltr = ZERO;
243     if ((iset % 2) ==  0)
244     {
245       *fnltr = 1500000.e0;
246     }
247   }
248   else if (igroup == 2)
249   {
250     *fnltr = 1000000.0e0;
251     if ((iset % 2) == 0)
252     {
253       *fnltr =  500000.e0;
254     }
255   }
256   return;
257 } /* END OF UTMSET */
258 
259 
UTMLIM(long * n,double sphi,long izone,double * spsou,double * spnor,double * sleast,double * slwest)260 void UTMLIM (long* n,
261              double sphi,
262              long izone,
263              double *spsou,
264              double *spnor,
265              double *sleast,
266              double *slwest)
267 {                          /* BEGIN UTMLIM */
268   /*
269    *    n      : 1st letter number for MGRS
270    *    sphi   : Latitude in radians
271    *    izone  : Zone number
272    *    spsou  : South latitude limit
273    *    spnor  : North latitude limit
274    *    sleast : East longitude limit
275    *    slwest : West longitude limit
276    */
277   double slcm;     /* Central meridian - Longitude of origin              */
278   double temp;     /* Temporary variable                                  */
279   long icm;        /* Central meridian                                    */
280   long isphi;      /* South latitude limit                                */
281   if (*n <= LETTER_A)
282   {
283     temp = ((sphi + R80) / (R8)) + 2;
284     temp = temp + .00000001;
285     *n = (long)temp;
286     if (*n > LETTER_H)
287     {
288       *n = *n + 1;
289     }
290     if (*n > LETTER_N)
291     {
292       *n = *n + 1;
293     }
294     if (*n >= LETTER_Y)
295     {
296       *n = LETTER_X;
297     }
298     if ((*n  ==  LETTER_M) && (sphi  ==  ZERO ))
299     {
300       *n = LETTER_N;
301     }
302     isphi = (*n - 3) * 8 - 80;
303   }
304   else
305   {
306     isphi = (*n - 3) * 8 - 80;
307     *n = *n - 1;
308   }
309   if (*n > LETTER_H)
310   {
311     isphi = isphi - 8;
312   }
313   if (*n > LETTER_N)
314   {
315     isphi = isphi - 8;
316   }
317   *spsou = (double)(isphi) * DEGRAD;
318   *spnor = *spsou + R8;
319   if (*n == LETTER_X)
320   {
321     *spnor = *spsou + 12.e0 * DEGRAD;
322   }
323   icm = izone * 6 - 183;
324   slcm = (double) icm * DEGRAD;
325   *sleast = slcm + R3;
326   *slwest = slcm - R3;
327   if ((izone < 31) || (izone > 37))
328   {
329     return;
330   }
331   if (*n < LETTER_V)
332   {
333     return;
334   }
335   if ((*n == LETTER_V) && (izone == 31))
336   {
337     *sleast = R3;
338   }
339   if ((*n == LETTER_V) && (izone == 32))
340   {
341     *slwest = R3;
342   }
343   if (*n < LETTER_X)
344   {
345     return;
346   }
347   if (izone == 31)
348   {
349     *sleast = R9;
350   }
351   if (izone == 33)
352   {
353     *slwest = R9;
354     *sleast = R21;
355   }
356   if (izone == 35)
357   {
358     *slwest = R21;
359     *sleast = R33;
360   }
361   if (izone == 37)
362   {
363     *slwest = R33;
364   }
365   return;
366 } /* END OF UTMLIM */
367 
368 
UTMOSSIM_MGRS(long izone,long * ltrnum,double sphi,double x,double y)369 void UTMOSSIM_MGRS (long izone,
370               long* ltrnum,
371               double sphi,
372               double x,
373               double y)
374 { /* BEGIN UTMMGRS */
375   /*
376    *    izone      : Zone number.
377    *    ltrnum     : Values of letters in the MGRS coordinate.
378    *    sphi       : Latitude in radians.
379    *    x          : Easting.
380    *    y          : Northing.
381    *
382    *    UTMMGRS CALLS THE FOLLOWING ROUTINES:
383    *
384    *    GPTUTM
385    *    UTMLIM
386    *    UTMSET
387    */
388   double fnltr;       /* False northing for 3rd letter                     */
389   double slcm;        /* Central meridian - longitude of origin            */
390   double sleast;      /* Longitude east limit - UTM                        */
391   double slwest;      /* Longitude west limit -UTM                         */
392   double spnor;       /* MGRS north latitude limits based on 1st letter    */
393   double spsou;       /* MGRS south latitude limits based on 1st letter    */
394   double xltr;        /* Easting used to derive 2nd letter of MGRS         */
395   double yltr;        /* Northing used to derive 3rd letter of MGRS        */
396   long ltrlow;        /* 2nd letter range - low number                     */
397   long ltrhi;         /* 2nd letter range - high number                    */
398   char hemisphere;
399 
400   UTMSET(izone, &ltrlow, &ltrhi, &fnltr);
401   ltrnum[0] = LETTER_A;
402   UTMLIM(&ltrnum[0], sphi, izone, &spsou, &spnor, &sleast, &slwest);
403   slcm = (double)(izone * 6 - 183) * DEGRAD;
404   /*
405     GPTUTM(a, recf, spsou, slcm, &izone, &yltr, &xltr, (long)1);
406   */
407   Set_UTM_Parameters(OSSIM_MGRS_a,OSSIM_MGRS_f,izone);
408   Convert_Geodetic_To_UTM(spsou,slcm,&izone,&hemisphere,&xltr,&yltr);
409 
410   yltr = (double)((long)(y + RND5));
411   if (((double)((long)(yltr + RND5))) == ((double)((long)(1.e7 + RND5))))
412   {
413     yltr = (double)((long)(yltr - 1.e0 + RND5));
414   }
415   while (yltr >= TWOMIL)
416   {
417     yltr = yltr - TWOMIL;
418   }
419   yltr = yltr - fnltr;
420   if (yltr < ZERO)
421   {
422     yltr = yltr + TWOMIL;
423   }
424   ltrnum[2] = (long)((yltr + RND1) / ONEHT);
425   if (ltrnum[2] > LETTER_H)
426   {
427     ltrnum[2] = ltrnum[2] + 1;
428   }
429   if (ltrnum[2] > LETTER_N)
430   {
431     ltrnum[2] = ltrnum[2] + 1;
432   }
433   xltr = (double)((long)(x));
434   if (((ltrnum[0] == LETTER_V) && (izone == 31)) &&
435       (((double)((long)(xltr + RND5))) == ((double)((long)(5.e5 + RND5)))))
436   {
437     xltr = (double)((long)(xltr - 1.e0 + RND5)); /* SUBTRACT 1 METER */
438   }
439   ltrnum[1] = ltrlow + ((long)((xltr + RND1) / ONEHT) -1);
440   if ((ltrlow == LETTER_J) && (ltrnum[1] > LETTER_N))
441   {
442     ltrnum[1] = ltrnum[1] + 1;
443   }
444   return;
445 } /* END UTMMGRS */
446 
447 
UPSSET(long n,long * ltrlow,long * ltrhi,double * feltr,double * fnltr,long * ltrhy)448 void UPSSET (long n,
449              long* ltrlow,
450              long* ltrhi,
451              double *feltr,
452              double *fnltr,
453              long* ltrhy)
454 { /* BEGIN UPSSET */
455   /*
456    *   n      : Value of 1st letter in MGRS coordinate.
457    *   ltrlow : Low number for 2nd letter.
458    *   ltrhi  : High number for 2nd letter.
459    *   feltr  : False easting.
460    *   fnltr  : False northing.
461    *   ltrhy  : High number for 3rd letter.
462    */
463   if (n == LETTER_Z) /* EASTERN HEMISPHERE-NORTH ZONE */
464   {
465     *ltrlow = LETTER_A;
466     *ltrhi  = LETTER_J;
467     *feltr = TWOMIL;
468     *fnltr = ONE3HT;
469     *ltrhy = LETTER_P;
470   }
471   else if (n == LETTER_Y) /* WESTERN HEMISPHERE-NORTH ZONE */
472   {
473     *ltrlow = LETTER_J;
474     *ltrhi  = LETTER_Z;
475     *feltr = EIGHT;
476     *fnltr = ONE3HT;
477     *ltrhy = LETTER_P;
478   }
479   else if (n == LETTER_B) /* ** EASTERN HEMISPHERE - SOUTH ZONE */
480   {
481     *ltrlow = LETTER_A;
482     *ltrhi  = LETTER_R;
483     *feltr = TWOMIL;
484     *fnltr = EIGHT;
485     *ltrhy = LETTER_Z;
486   }
487   else if (n == LETTER_A) /* ** WESTERN HEMISPHERE - SOUTH ZONE */
488   {
489     *ltrlow = LETTER_J;
490     *ltrhi  = LETTER_Z;
491     *feltr = EIGHT;
492     *fnltr = EIGHT;
493     *ltrhy = LETTER_Z;
494   }
495   return;
496 } /* END OF UPSSET */
497 
498 
UPS(char * mgrs,long * ltrnum,double x,double y,long iarea)499 void UPS (char* mgrs,
500           long* ltrnum,
501           double x,
502           double y,
503           long iarea)
504 { /* BEGIN UPS */
505   /*
506    *    mgrs   : MGRS coordinate.
507    *    ltrnum : Values of the letters in the MGRS coordinate.
508    *    x      : Easting.
509    *    y      : Northing.
510    *    iarea  : Set to UPS_NORTH or UPS_SOUTH.
511    *
512    *    UPS CALLS THE FOLLOWING ROUTINES:
513    *
514    *    UPSSET
515    */
516   double feltr=0.0;       /* False easting for 2nd letter                      */
517   double fnltr=0.0;       /* False northing for 3rd letter                     */
518   double xltr=0.0;        /* Easting used to derive 2nd letter of MGRS         */
519   double yltr=0.0;        /* Northing used to derive 3rd letter of MGRS        */
520   long ltrlow=0;        /* 2nd letter range - low number                     */
521   long ltrhi=0;         /* 2nd letter range - high number                    */
522   long ltrhy=0;         /* 3rd letter range - high number (UPS)              */
523   if (iarea == UPS_NORTH)
524   {
525     ltrnum[0] = LETTER_Y;
526     if (((double)((long)(x + RND5))) >= TWOMIL)
527     {
528       ltrnum[0] = LETTER_Z;
529     }
530   }
531   else if (iarea == UPS_SOUTH)
532   {
533     ltrnum[0] = LETTER_A;
534     if (((double)((long)(x + RND5))) >= TWOMIL)
535     {
536       ltrnum[0] = LETTER_B;
537     }
538   }
539   UPSSET(ltrnum[0], &ltrlow, &ltrhi, &feltr, &fnltr, &ltrhy);
540   mgrs[0] = BLANK;
541   mgrs[1] = BLANK;
542   yltr = (double)((long)(y + RND5));
543   yltr = yltr - fnltr;
544   ltrnum[2] = (long)((yltr + RND1) / ONEHT);
545   if (ltrnum[2] > LETTER_H)
546   {
547     ltrnum[2] = ltrnum[2] + 1;
548   }
549   if (ltrnum[2] > LETTER_N)
550   {
551     ltrnum[2] = ltrnum[2] + 1;
552   }
553   xltr = (double)((long)(x + RND5));
554   xltr = xltr - feltr;
555   ltrnum[1] = ltrlow + ((long)((xltr + RND1) / ONEHT));
556   if (x < TWOMIL)
557   {
558     if (ltrnum[1] > LETTER_L)
559     {
560       ltrnum[1] = ltrnum[1] + 3;
561     }
562     if (ltrnum[1] > LETTER_U)
563     {
564       ltrnum[1] = ltrnum[1] + 2;
565     }
566   }
567   if (x >= TWOMIL)
568   {
569     if (ltrnum[1] > LETTER_C)
570     {
571       ltrnum[1] = ltrnum[1] + 2;
572     }
573     if (ltrnum[1] > LETTER_H)
574     {
575       ltrnum[1] = ltrnum[1] + 1;
576     }
577     if (ltrnum[1] > LETTER_L)
578     {
579       ltrnum[1] = ltrnum[1] + 3;
580     }
581   }
582   return;
583 } /* END OF UPS */
584 
585 
LTR2UPS(long * ltrnum,long ltrlow,long ltrhi,long ltrhy,long * ierr,double * xltr,double * yltr,double fnltr,double feltr,double * x,double * y,double sign)586 void LTR2UPS (long* ltrnum,
587               long ltrlow,
588               long ltrhi,
589               long ltrhy,
590               long* ierr,
591               double *xltr,
592               double *yltr,
593               double fnltr,
594               double feltr,
595               double *x,
596               double *y,
597               double sign)
598 { /* BEGIN LTR2UPS */
599   /*
600    *    ltrnum : Values of the letters in the MGRS coordinate
601    *    ltrlow : Low number
602    *    ltrhi  : High number-2nd letter
603    *    ltrhy  : High number-3rd letter
604    *    ierr   : Error code
605    *    xltr   : Easting for 100,000 meter grid square
606    *    yltr   : Northing for 100,000 meter grid square
607    *    fnltr  : False northing for 3rd letter
608    *    feltr  : False easting for 2nd letter
609    *    x      : Easting
610    *    y      : Northing
611    *    sign   : Set to either positive or negative
612    */
613   if (ltrnum[1] < ltrlow)
614   {
615     *ierr = TRUE;
616     return;
617   }
618   if (ltrnum[1] > ltrhi)
619   {
620     *ierr = TRUE;
621     return;
622   }
623   if (ltrnum[2] > ltrhy)
624   {
625     *ierr = TRUE;
626     return;
627   }
628   if ((ltrnum[1] == LETTER_D) || (ltrnum[1] == LETTER_E) ||
629       (ltrnum[1] == LETTER_M) || (ltrnum[1] == LETTER_N) ||
630       (ltrnum[1] == LETTER_V) || (ltrnum[1] == LETTER_W))
631   {
632     *ierr = TRUE;
633     return;
634   }
635   *yltr = (double)ltrnum[2] * ONEHT + fnltr;
636   if (ltrnum[2] > LETTER_I)
637   {
638     *yltr = *yltr - ONEHT;
639   }
640   if (ltrnum[2] > LETTER_O)
641   {
642     *yltr = *yltr - ONEHT;
643   }
644   *xltr = (double)((ltrnum[1]) - ltrlow) * ONEHT + feltr;
645   if (ltrlow != LETTER_A)
646   {
647     if (ltrnum[1] > LETTER_L)
648     {
649       *xltr = *xltr - 3.e0 * ONEHT;
650     }
651     if (ltrnum[1] > LETTER_U)
652     {
653       *xltr = *xltr - 2.e0 * ONEHT;
654     }
655   }
656   else if (ltrlow == LETTER_A)
657   {
658     if (ltrnum[1] > LETTER_C)
659     {
660       *xltr = *xltr - 2.e0 * ONEHT;
661     }
662     if (ltrnum[1] > LETTER_I)
663     {
664       *xltr = *xltr - ONEHT;
665     }
666     if (ltrnum[1] > LETTER_L)
667     {
668       *xltr = *xltr - 3.e0 * ONEHT ;
669     }
670   }
671   *x = *xltr;
672   *y = *yltr * sign;
673   return;
674 } /* END OF LTR2UPS */
675 
676 
GRID_UPS(long * Letters,char * Hemisphere,double * Easting,double * Northing,long * Error)677 void GRID_UPS (long   *Letters,
678                char   *Hemisphere,
679                double *Easting,
680                double *Northing,
681                long   *Error)
682 { /* BEGIN GRID_UPS */
683   double feltr=0.0;               /* False easting for 2nd letter               */
684   double fnltr=0.0;               /* False northing for 3rd letter              */
685   // double sleast=0.0;              /* Longitude east limit - UTM                 */
686   // double slwest=0.0;              /* Longitude west limit -UTM                  */
687   // double spnor=0.0;               /* North latitude limits based on 1st letter  */
688   double spsou=0.0;               /* South latitude limits based on 1st letter  */
689   double x=0.0;                   /* easting                                    */
690   double xltr=0.0;                /* easting for 100,000 meter grid square      */
691   double xnum=0.0;                /* easting part of MGRS                       */
692   double y=0.0;                   /* northing                                   */
693   double yltr=0.0;                /* northing for 100,000 meter grid square     */
694   double ynum=0.0;                /* northing part of MGRS                      */
695   // long izone=0;                 /* Zone number                                */
696   long ltrhi=0;                 /* 2nd letter range - high number             */
697   long ltrhy=0;                 /* 3rd letter range - high number (UPS)       */
698   long ltrlow=0;                /* 2nd letter range - low number              */
699   long sign=0;
700   double sphi=0.0;
701   double slam=0.0;
702   if ((Letters[0] == LETTER_Y) || (Letters[0] == LETTER_Z))
703   {
704     spsou = MAX_UTM_LAT;
705     sign = 1;
706   }
707   else
708   {
709     spsou = MIN_UTM_LAT;
710     sign = -1;
711   }
712   slam = PI / 2.e0;
713   if ((Letters[0] == LETTER_Y) || (Letters[0] == LETTER_A))
714   {
715     slam = -slam;
716   }
717   // izone = 0;
718   sphi = spsou;
719   Set_UPS_Parameters(OSSIM_MGRS_a,OSSIM_MGRS_f);
720   Convert_Geodetic_To_UPS(sphi,slam,Hemisphere,&x,&y);
721   // spnor = sphi;
722   // sleast = slam;
723   // slwest = slam;
724   UPSSET(Letters[0], &ltrlow, &ltrhi, &feltr, &fnltr, &ltrhy);
725   LTR2UPS(Letters, ltrlow, ltrhi, ltrhy, Error, &xltr, &yltr, fnltr, feltr,
726           &x, &y, sign);
727   xnum = *Easting;
728   ynum = *Northing;
729   y = (yltr + ynum);
730   x = xltr + xnum;
731   *Easting = x;
732   *Northing = y;
733   return;
734 } /* END OF GRID_UPS */
735 
736 
LTR2UTM(long * ltrnum,long ltrlow,long ltrhi,long * ierr,double * xltr,double * yltr,double fnltr,double yslow,double ylow)737 void LTR2UTM (long* ltrnum,
738               long ltrlow,
739               long ltrhi,
740               long* ierr,
741               double *xltr,
742               double *yltr,
743               double fnltr,
744               double yslow,
745               double ylow)
746 { /* BEGIN LTR2UTM */
747   /*
748    *    xltr   : Easting for 100,000 meter grid square.
749    *    yltr   : Northing for 100,000 meter grid square.
750    *    ierr   : Error code.
751    *    ltrnum : Values of the letters in the OSSIM_MGRS coordinate.
752    *    ltrlow : Low number.
753    *    ltrhi  : High number.
754    *    fnltr  : False northing for 3rd letter.
755    *    yslow  : Northing scaled down to less than 2 million.
756    *    ylow   : Lowest northing of area to nearest 100,000.
757    */
758   if (ltrnum[1] < ltrlow)
759   {
760     *ierr = TRUE;
761     return;
762   }
763   if (ltrnum[1] > ltrhi)
764   {
765     *ierr = TRUE;
766     return;
767   }
768   if (ltrnum[2] > LETTER_V)
769   {
770     *ierr = TRUE;
771     return;
772   }
773   *yltr = (double)(ltrnum[2]) * ONEHT + fnltr;
774   *xltr = (double)((ltrnum[1]) - ltrlow + 1) * ONEHT;
775   if ((ltrlow == LETTER_J) && (ltrnum[1] > LETTER_O))
776   {
777     *xltr = *xltr - ONEHT;
778   }
779   if (ltrnum[2] > LETTER_O)
780   {
781     *yltr = *yltr - ONEHT;
782   }
783   if (ltrnum[2] > LETTER_I)
784   {
785     *yltr = *yltr - ONEHT;
786   }
787   if (((double)((long)(*yltr + RND5))) >= ((double)((long)(TWOMIL + RND5))))
788   {
789     *yltr = *yltr - TWOMIL;
790   }
791   *yltr = ((double)((long)(*yltr + RND5)));
792   *yltr = *yltr - yslow;
793   if (*yltr < ZERO)
794   {
795     *yltr = *yltr + TWOMIL;
796   }
797   *yltr = ((double)((long)(ylow + *yltr + RND5)));
798   return;
799 } /* END OF LTR2UTM */
800 
801 
GRID_UTM(long * Zone,long * Letters,char * Hemisphere,double * Easting,double * Northing,long In_Precision,long * Error)802 void GRID_UTM (long   *Zone,
803                long   *Letters,
804                char   *Hemisphere,
805                double *Easting,
806                double *Northing,
807                long   In_Precision,
808                long   *Error)
809 { /* BEGIN GRID_UTM */
810   double fnltr;               /* False northing for 3rd letter              */
811   long ltrhi;                 /* 2nd letter range - High number             */
812   long ltrlow;                /* 2nd letter range - Low number              */
813   long number;                /* Value of ltrnum[0] + 1                     */
814 /*  double slam;*/
815   double slcm;                /* Central meridian                           */
816   double sleast;              /* Longitude east limit - UTM                 */
817   double slwest;              /* Longitude west limit -UTM                  */
818   double sphi;                /* Latitude (needed by UTMLIM)                */
819   double spnor;               /* North latitude limits based on 1st letter  */
820   double spsou;               /* South latitude limits based on 1st letter  */
821   double xltr;                /* Easting for 100,000 meter grid square      */
822   double ylow;                /* Lowest northing of area to nearest 100,000 */
823   double yltr;                /* Northing for 100,000 meter grid square     */
824   double yslow;               /* Northing scaled down to less than 2 million*/
825   double Latitude = 0.0;
826   double Longitude = 0.0;
827   double divisor = 1.0;
828   if ((*Zone == 32) && (Letters[0] == LETTER_X))
829   {
830     *Error = TRUE;
831     return;
832   }
833   if ((*Zone == 34) && (Letters[0] == LETTER_X))
834   {
835     *Error = TRUE;
836     return;
837   }
838   if ((*Zone == 36) && (Letters[0] == LETTER_X))
839   {
840     *Error = TRUE;
841     return;
842   }
843   number = Letters[0] + 1;
844   sphi = 0.0;
845   UTMLIM(&number,sphi,*Zone,&spsou,&spnor,&sleast,&slwest);
846   Set_UTM_Parameters(OSSIM_MGRS_a,OSSIM_MGRS_f,*Zone);
847   slcm = (double)(*Zone * 6 - 183) * DEGRAD;
848   Convert_Geodetic_To_UTM(spsou,slcm,Zone,Hemisphere,&xltr,&yltr);
849   ylow = ((double)((long)((double)((long)(yltr / ONEHT)) * ONEHT)));
850   yslow = ylow;
851   while (yslow >= TWOMIL)
852   {
853     yslow = yslow - TWOMIL;
854   }
855   yslow = ((double)((long)(yslow)));
856   UTMSET(*Zone, &ltrlow, &ltrhi, &fnltr);
857   LTR2UTM(Letters, ltrlow, ltrhi, Error, &xltr, &yltr, fnltr, yslow, ylow);
858   *Easting = xltr + *Easting;
859   *Northing = yltr + *Northing;
860   /* check that point is within Zone Letter bounds */
861   Convert_UTM_To_Geodetic(*Zone,*Hemisphere,*Easting,*Northing,&Latitude,&Longitude);
862   divisor = pow (10.0, In_Precision);
863   if (((spsou - DEGRAD/divisor) <= Latitude) && (Latitude <= (spnor + DEGRAD/divisor)))
864     return;
865   else
866     *Error = TRUE;
867   return;
868 }/* END OF GRID_UTM */
869 
870 
Round_OSSIM_MGRS(double value)871 long Round_OSSIM_MGRS (double value)
872 /* Round value to nearest integer, using standard engineering rule */
873 { /* Round_OSSIM_MGRS */
874   double ivalue;
875   long ival;
876   double fraction = modf (value, &ivalue);
877   ival = (long)(ivalue);
878   if ((fraction > 0.5) || ((fraction == 0.5) && (ival%2 == 1)))
879     ival++;
880   return (ival);
881 } /* Round_OSSIM_MGRS */
882 
883 
Make_OSSIM_MGRS_String(char * OSSIM_MGRS,long Zone,long ltrnum[OSSIM_MGRS_LETTERS],double Easting,double Northing,long Precision)884 long Make_OSSIM_MGRS_String (char* OSSIM_MGRS,
885                        long Zone,
886                        long ltrnum[OSSIM_MGRS_LETTERS],
887                        double Easting,
888                        double Northing,
889                        long Precision)
890 /* Construct an OSSIM_MGRS string from its component parts */
891 { /* Make_OSSIM_MGRS_String */
892   int i;
893   int j;
894   int error_code = OSSIM_MGRS_NO_ERROR;
895   double divisor;
896   long int east;  /* double data type? (drb) */
897   long int north; /* double data type? (drb) */
898   i = 0;
899   if (Zone)
900     i = sprintf (OSSIM_MGRS+i,"%2.2ld",Zone);
901   for (j=0;j<3;j++)
902     OSSIM_MGRS[i++] = ALBET[ltrnum[j]];
903   divisor = pow (10.0, (5 - Precision));
904   Easting = fmod (Easting, 100000.0);
905   if (Easting >= 99999.5)
906     Easting = 99999.0;
907   east = (long int)(Easting/divisor);
908   i += sprintf (OSSIM_MGRS+i, "%*.*ld", (int)Precision, (int)Precision, east);
909   Northing = fmod (Northing, 100000.0);
910   if (Northing >= 99999.5)
911     Northing = 99999.0;
912   north = (long int)(Northing/divisor);
913   i += sprintf (OSSIM_MGRS+i, "%*.*ld", (int)Precision, (int)Precision, north);
914   return (error_code);
915 } /* Make_OSSIM_MGRS_String */
916 
917 
Break_OSSIM_MGRS_String(const char * OSSIM_MGRS,long * Zone,long Letters[OSSIM_MGRS_LETTERS],double * Easting,double * Northing,long * Precision)918 long Break_OSSIM_MGRS_String (const char* OSSIM_MGRS,
919                         long* Zone,
920                         long Letters[OSSIM_MGRS_LETTERS],
921                         double* Easting,
922                         double* Northing,
923                         long* Precision)
924 /* Break down an OSSIM_MGRS string into its component parts */
925 { /* Break_OSSIM_MGRS_String */
926   long error_code = OSSIM_MGRS_NO_ERROR;
927   long i = 0;
928   long j;
929   long num_digits;
930   long num_letters;
931   while (OSSIM_MGRS[i] == ' ')
932     i++;  /* skip any leading blanks */
933   j = i;
934   while (isdigit(OSSIM_MGRS[i]))
935     i++;
936   num_digits = i - j;
937   if (num_digits <= 2)
938     if (num_digits > 0)
939     {
940       char zone_string[3];
941       /* get zone */
942       strncpy (zone_string, OSSIM_MGRS+j, 2);
943       zone_string[2] = 0;
944       sscanf (zone_string, "%ld", Zone);
945       if ((*Zone < 1) || (*Zone > 60))
946         error_code |= OSSIM_MGRS_STRING_ERROR;
947     }
948     else
949       *Zone = 0;
950   else
951     error_code |= OSSIM_MGRS_STRING_ERROR;
952   j = i;
953   while (isalpha(OSSIM_MGRS[i]))
954     i++;
955   num_letters = i - j;
956   if (num_letters == 3)
957   {
958     /* get letters */
959     Letters[0] = (toupper(OSSIM_MGRS[j]) - (long)'A');
960     if ((Letters[0] == LETTER_I) || (Letters[0] == LETTER_O))
961       error_code |= OSSIM_MGRS_STRING_ERROR;
962     Letters[1] = (toupper(OSSIM_MGRS[j+1]) - (long)'A');
963     if ((Letters[1] == LETTER_I) || (Letters[1] == LETTER_O))
964       error_code |= OSSIM_MGRS_STRING_ERROR;
965     Letters[2] = (toupper(OSSIM_MGRS[j+2]) - (long)'A');
966     if ((Letters[2] == LETTER_I) || (Letters[2] == LETTER_O))
967       error_code |= OSSIM_MGRS_STRING_ERROR;
968   }
969   else
970     error_code |= OSSIM_MGRS_STRING_ERROR;
971   j = i;
972   while (isdigit(OSSIM_MGRS[i]))
973     i++;
974   num_digits = i - j;
975   if ((num_digits <= 10) && (num_digits%2 == 0))
976   {
977     long n;
978     char east_string[6];
979     char north_string[6];
980     long east;
981     long north;
982     double multiplier;
983     /* get easting & northing */
984     n = num_digits/2;
985     *Precision = n;
986     if (n > 0)
987     {
988       strncpy (east_string, OSSIM_MGRS+j, n);
989       east_string[n] = 0;
990       sscanf (east_string, "%ld", &east);
991       strncpy (north_string, OSSIM_MGRS+j+n, n);
992       north_string[n] = 0;
993       sscanf (north_string, "%ld", &north);
994       multiplier = pow (10.0, 5 - n);
995       *Easting = east * multiplier;
996       *Northing = north * multiplier;
997     }
998     else
999     {
1000       *Easting = 0.0;
1001       *Northing = 0.0;
1002     }
1003   }
1004   else
1005     error_code |= OSSIM_MGRS_STRING_ERROR;
1006   return (error_code);
1007 } /* Break_OSSIM_MGRS_String */
1008 
1009 
Set_OSSIM_MGRS_Parameters(double a,double f,const char * Ellipsoid_Code)1010 long Set_OSSIM_MGRS_Parameters (double a,
1011                           double f,
1012                           const char* Ellipsoid_Code)
1013 /*
1014  * The function SET_OSSIM_MGRS_PARAMETERS receives the ellipsoid parameters and sets
1015  * the corresponding state variables. If any errors occur, the error code(s)
1016  * are returned by the function, otherwise OSSIM_MGRS_NO_ERROR is returned.
1017  *
1018  *   a                : Semi-major axis of ellipsoid in meters  (input)
1019  *   f                : Flattening of ellipsoid                 (input)
1020  *   Ellipsoid_Code   : 2-letter code for ellipsoid             (input)
1021  */
1022 { /* Set_OSSIM_MGRS_Parameters  */
1023 
1024   double inv_f = 1 / f;
1025   long Error_Code = OSSIM_MGRS_NO_ERROR;
1026 
1027   if (a <= 0.0)
1028   { /* Semi-major axis must be greater than zero */
1029     Error_Code |= OSSIM_MGRS_A_ERROR;
1030   }
1031   if ((inv_f < 250) || (inv_f > 350))
1032   { /* Inverse flattening must be between 250 and 350 */
1033     Error_Code |= OSSIM_MGRS_INV_F_ERROR;
1034   }
1035   if (!Error_Code)
1036   { /* no errors */
1037     OSSIM_MGRS_a = a;
1038     OSSIM_MGRS_f = f;
1039     OSSIM_MGRS_recpf = inv_f;
1040     strcpy (OSSIM_MGRS_Ellipsoid_Code, Ellipsoid_Code);
1041   }
1042   return (Error_Code);
1043 }  /* Set_OSSIM_MGRS_Parameters  */
1044 
1045 
1046 
Get_OSSIM_MGRS_Parameters(double * a,double * f,char * Ellipsoid_Code)1047 void Get_OSSIM_MGRS_Parameters (double *a,
1048                           double *f,
1049                           char* Ellipsoid_Code)
1050 /*
1051  * The function Get_OSSIM_MGRS_Parameters returns the current ellipsoid
1052  * parameters.
1053  *
1054  *  a                : Semi-major axis of ellipsoid, in meters (output)
1055  *  f                : Flattening of ellipsoid					       (output)
1056  *  Ellipsoid_Code   : 2-letter code for ellipsoid             (output)
1057  */
1058 { /* Get_OSSIM_MGRS_Parameters */
1059   *a = OSSIM_MGRS_a;
1060   *f = OSSIM_MGRS_f;
1061   strcpy (Ellipsoid_Code, OSSIM_MGRS_Ellipsoid_Code);
1062   return;
1063 } /* Get_OSSIM_MGRS_Parameters */
1064 
1065 
Convert_Geodetic_To_OSSIM_MGRS(double Latitude,double Longitude,long Precision,char * OSSIM_MGRS)1066 long Convert_Geodetic_To_OSSIM_MGRS (double Latitude,
1067                                double Longitude,
1068                                long Precision,
1069                                char* OSSIM_MGRS)
1070 /*
1071  *    Latitude   : Latitude in radians              (input)
1072  *    Longitude  : Longitude in radians             (input)
1073  *    OSSIM_MGRS       : OSSIM_MGRS coordinate string           (output)
1074  *
1075  */
1076 { /* Convert_Geodetic_To_OSSIM_MGRS */
1077   long error_code = OSSIM_MGRS_NO_ERROR;
1078   long zone;
1079   char hemisphere;
1080   double easting;
1081   double northing;
1082   if ((Latitude < -PI_OVER_2) || (Latitude > PI_OVER_2))
1083   { /* Latitude out of range */
1084     error_code |= OSSIM_MGRS_LAT_ERROR;
1085   }
1086   if ((Longitude < -PI) || (Longitude > (2*PI)))
1087   { /* Longitude out of range */
1088     error_code |= OSSIM_MGRS_LON_ERROR;
1089   }
1090   if ((Precision < 0) || (Precision > MAX_PRECISION))
1091     error_code |= OSSIM_MGRS_PRECISION_ERROR;
1092   if (!error_code)
1093   {
1094     if ((Latitude < MIN_UTM_LAT) || (Latitude > MAX_UTM_LAT))
1095     {
1096       Set_UPS_Parameters (OSSIM_MGRS_a, OSSIM_MGRS_f);
1097       error_code |= Convert_Geodetic_To_UPS (Latitude, Longitude, &hemisphere, &easting, &northing);
1098       error_code |= Convert_UPS_To_OSSIM_MGRS (hemisphere, easting, northing, Precision, OSSIM_MGRS);
1099     }
1100     else
1101     {
1102       Set_UTM_Parameters (OSSIM_MGRS_a, OSSIM_MGRS_f, 0);
1103       error_code |= Convert_Geodetic_To_UTM (Latitude, Longitude, &zone, &hemisphere, &easting, &northing);
1104       error_code |= Convert_UTM_To_OSSIM_MGRS (zone, hemisphere, easting, northing, Precision, OSSIM_MGRS);
1105     }
1106   }
1107   return (error_code);
1108 } /* Convert_Geodetic_To_OSSIM_MGRS */
1109 
1110 
Convert_OSSIM_MGRS_To_Geodetic(const char * OSSIM_MGRS,double * Latitude,double * Longitude)1111 long Convert_OSSIM_MGRS_To_Geodetic (const char* OSSIM_MGRS,
1112                                double *Latitude,
1113                                double *Longitude)
1114 /*
1115  *    OSSIM_MGRS       : OSSIM_MGRS coordinate string           (output)
1116  *    Latitude   : Latitude in radians              (input)
1117  *    Longitude  : Longitude in radians             (input)
1118  *
1119  */
1120 { /* Convert_OSSIM_MGRS_To_Geodetic */
1121   long error_code = OSSIM_MGRS_NO_ERROR;
1122   long Zone;
1123   long Letters[OSSIM_MGRS_LETTERS];
1124   char Hemisphere;
1125   double Easting;
1126   double Northing;
1127   long In_Precision;
1128   error_code = Break_OSSIM_MGRS_String (OSSIM_MGRS, &Zone, Letters, &Easting, &Northing, &In_Precision);
1129   if (!error_code)
1130   {
1131      if (Zone)
1132      {
1133         error_code |= Convert_OSSIM_MGRS_To_UTM (OSSIM_MGRS, &Zone, &Hemisphere, &Easting, &Northing);
1134         Set_UTM_Parameters (OSSIM_MGRS_a, OSSIM_MGRS_f, 0);
1135         error_code |= Convert_UTM_To_Geodetic (Zone, Hemisphere, Easting, Northing, Latitude, Longitude);
1136      }
1137      else
1138      {
1139         error_code |= Convert_OSSIM_MGRS_To_UPS (OSSIM_MGRS, &Hemisphere, &Easting, &Northing);
1140         Set_UPS_Parameters (OSSIM_MGRS_a, OSSIM_MGRS_f);
1141         error_code |= Convert_UPS_To_Geodetic (Hemisphere, Easting, Northing, Latitude, Longitude);
1142      }
1143   }
1144   return (error_code);
1145 } /* END OF Convert_OSSIM_MGRS_To_Geodetic */
1146 
1147 
1148 
Convert_UTM_To_OSSIM_MGRS(long Zone,char Hemisphere,double Easting,double Northing,long Precision,char * OSSIM_MGRS)1149 long Convert_UTM_To_OSSIM_MGRS (long Zone,
1150                           char Hemisphere,
1151                           double Easting,
1152                           double Northing,
1153                           long Precision,
1154                           char* OSSIM_MGRS)
1155 /*
1156  * The function Convert_UTM_To_OSSIM_MGRS converts UTM (zone, easting, and
1157  * northing) coordinates to an OSSIM_MGRS coordinate string, according to the
1158  * current ellipsoid parameters.  If any errors occur, the error code(s)
1159  * are returned by the  function, otherwise OSSIM_MGRS_NO_ERROR is returned.
1160  *
1161  *    Zone       : UTM zone                         (input)
1162  *    Hemisphere : North or South hemisphere        (input)
1163  *    Easting    : Easting (X) in meters            (input)
1164  *    Northing   : Northing (Y) in meters           (input)
1165  *    Precision  : Precision level of OSSIM_MGRS string   (input)
1166  *    OSSIM_MGRS       : OSSIM_MGRS coordinate string           (output)
1167  */
1168 { /* Convert_UTM_To_OSSIM_MGRS */
1169   long error_code = OSSIM_MGRS_NO_ERROR;
1170   long temp_error = OSSIM_MGRS_NO_ERROR;
1171   long Letters[OSSIM_MGRS_LETTERS]; /* Number location of 3 letters in alphabet   */
1172   double Latitude;           /* Latitude of UTM point */
1173   double Longitude;          /* Longitude of UTM point */
1174   double divisor;
1175   if ((Zone < 1) || (Zone > 60))
1176     error_code |= OSSIM_MGRS_ZONE_ERROR;
1177   if ((Hemisphere != 'S') && (Hemisphere != 'N'))
1178     error_code |= OSSIM_MGRS_HEMISPHERE_ERROR;
1179   if ((Easting < MIN_EASTING) || (Easting > MAX_EASTING))
1180     error_code |= OSSIM_MGRS_EASTING_ERROR;
1181   if ((Northing < MIN_NORTHING) || (Northing > MAX_NORTHING))
1182     error_code |= OSSIM_MGRS_NORTHING_ERROR;
1183   if ((Precision < 0) || (Precision > MAX_PRECISION))
1184     error_code |= OSSIM_MGRS_PRECISION_ERROR;
1185   if (!error_code)
1186   {
1187     Set_UTM_Parameters (OSSIM_MGRS_a, OSSIM_MGRS_f,0);
1188     temp_error = Convert_UTM_To_Geodetic (Zone, Hemisphere, Easting, Northing, &Latitude, &Longitude);
1189 	if (temp_error & UTM_NORTHING_ERROR)
1190 		error_code |= OSSIM_MGRS_NORTHING_ERROR;
1191 	else
1192 	{
1193 	  /* Round easting and northing values */
1194 	  divisor = pow (10.0, (5 - Precision));
1195 	  Easting = Round_OSSIM_MGRS (Easting/divisor) * divisor;
1196 	  Northing = Round_OSSIM_MGRS (Northing/divisor) * divisor;
1197 	  UTMOSSIM_MGRS (Zone, Letters, Latitude, Easting, Northing);
1198 	  /* UTM checks - these should be done in UTMOSSIM_MGRS */
1199 	  if ((Zone == 31) && (Letters[0] == LETTER_V))
1200 	    if (Easting > 500000)
1201 		  Easting = 500000;
1202 	  if (Northing > 10000000)
1203 	    Northing = 10000000;
1204 	  Make_OSSIM_MGRS_String (OSSIM_MGRS, Zone, Letters, Easting, Northing, Precision);
1205 	}
1206   }
1207   return (error_code);
1208 } /* Convert_UTM_To_OSSIM_MGRS */
1209 
1210 
Convert_OSSIM_MGRS_To_UTM(const char * OSSIM_MGRS,long * Zone,char * Hemisphere,double * Easting,double * Northing)1211 long Convert_OSSIM_MGRS_To_UTM (const char   *OSSIM_MGRS,
1212                           long   *Zone,
1213                           char   *Hemisphere,
1214                           double *Easting,
1215                           double *Northing)
1216 /*
1217  * The function Convert_OSSIM_MGRS_To_UTM converts an OSSIM_MGRS coordinate string
1218  * to UTM projection (zone, hemisphere, easting and northing) coordinates
1219  * according to the current ellipsoid parameters.  If any errors occur,
1220  * the error code(s) are returned by the function, otherwise UTM_NO_ERROR
1221  * is returned.
1222  *
1223  *    OSSIM_MGRS       : OSSIM_MGRS coordinate string           (input)
1224  *    Zone       : UTM zone                         (output)
1225  *    Hemisphere : North or South hemisphere        (output)
1226  *    Easting    : Easting (X) in meters            (output)
1227  *    Northing   : Northing (Y) in meters           (output)
1228  */
1229 { /* Convert_OSSIM_MGRS_To_UTM */
1230   long error_code = OSSIM_MGRS_NO_ERROR;
1231   long Letters[OSSIM_MGRS_LETTERS];
1232   long In_Precision;
1233   long Error = 0;
1234   error_code = Break_OSSIM_MGRS_String (OSSIM_MGRS, Zone, Letters, Easting, Northing, &In_Precision);
1235   if (!*Zone)
1236     error_code |= OSSIM_MGRS_STRING_ERROR;
1237   if (!error_code)
1238   {
1239     GRID_UTM (Zone, Letters, Hemisphere, Easting, Northing, In_Precision, &Error);
1240     if (Error)
1241       error_code = OSSIM_MGRS_STRING_ERROR;
1242   }
1243   return (error_code);
1244 } /* Convert_OSSIM_MGRS_To_UTM */
1245 
1246 
Convert_UPS_To_OSSIM_MGRS(char Hemisphere,double Easting,double Northing,long Precision,char * OSSIM_MGRS)1247 long Convert_UPS_To_OSSIM_MGRS (char   Hemisphere,
1248                           double Easting,
1249                           double Northing,
1250                           long   Precision,
1251                           char*  OSSIM_MGRS)
1252 /*
1253  *  The function Convert_UPS_To_OSSIM_MGRS converts UPS (hemisphere, easting,
1254  *  and northing) coordinates to an OSSIM_MGRS coordinate string according to
1255  *  the current ellipsoid parameters.  If any errors occur, the error
1256  *  code(s) are returned by the function, otherwise UPS_NO_ERROR is
1257  *  returned.
1258  *
1259  *    Hemisphere    : Hemisphere either 'N' or 'S'     (input)
1260  *    Easting       : Easting/X in meters              (input)
1261  *    Northing      : Northing/Y in meters             (input)
1262  *    Precision     : Precision level of OSSIM_MGRS string   (input)
1263  *    OSSIM_MGRS          : OSSIM_MGRS coordinate string           (output)
1264  */
1265 { /* Convert_UPS_To_OSSIM_MGRS */
1266   double divisor;
1267   long error_code = OSSIM_MGRS_NO_ERROR;
1268   long ltrnum[OSSIM_MGRS_LETTERS]; /* Number location of 3 letters in alphabet   */
1269   if ((Hemisphere != 'N') && (Hemisphere != 'S'))
1270     error_code |= OSSIM_MGRS_HEMISPHERE_ERROR;
1271   if ((Easting < MIN_EAST_NORTH) || (Easting > MAX_EAST_NORTH))
1272     error_code |= OSSIM_MGRS_EASTING_ERROR;
1273   if ((Northing < MIN_EAST_NORTH) || (Northing > MAX_EAST_NORTH))
1274     error_code |= OSSIM_MGRS_NORTHING_ERROR;
1275   if ((Precision < 0) || (Precision > MAX_PRECISION))
1276     error_code |= OSSIM_MGRS_PRECISION_ERROR;
1277   if (!error_code)
1278   {
1279     divisor = pow (10.0, (5 - Precision));
1280     Easting = Round_OSSIM_MGRS (Easting/divisor) * divisor;
1281     Northing = Round_OSSIM_MGRS (Northing/divisor) * divisor;
1282     if (Hemisphere == 'S')
1283       UPS (OSSIM_MGRS, ltrnum, Easting, Northing, UPS_SOUTH);
1284     else
1285       UPS (OSSIM_MGRS, ltrnum, Easting, Northing, UPS_NORTH);
1286     Make_OSSIM_MGRS_String (OSSIM_MGRS, 0, ltrnum, Easting, Northing, Precision);
1287   }
1288   return (error_code);
1289 } /* Convert_UPS_To_OSSIM_MGRS */
1290 
1291 
Convert_OSSIM_MGRS_To_UPS(const char * OSSIM_MGRS,char * Hemisphere,double * Easting,double * Northing)1292 long Convert_OSSIM_MGRS_To_UPS ( const char   *OSSIM_MGRS,
1293                            char   *Hemisphere,
1294                            double *Easting,
1295                            double *Northing)
1296 /*
1297  *  The function Convert_OSSIM_MGRS_To_UPS converts an OSSIM_MGRS coordinate string
1298  *  to UPS (hemisphere, easting, and northing) coordinates, according
1299  *  to the current ellipsoid parameters. If any errors occur, the error
1300  *  code(s) are returned by the function, otherwide UPS_NO_ERROR is returned.
1301  *
1302  *    OSSIM_MGRS          : OSSIM_MGRS coordinate string           (input)
1303  *    Hemisphere    : Hemisphere either 'N' or 'S'     (output)
1304  *    Easting       : Easting/X in meters              (output)
1305  *    Northing      : Northing/Y in meters             (output)
1306  */
1307 { /* Convert_OSSIM_MGRS_To_UPS */
1308   long error_code = OSSIM_MGRS_NO_ERROR;
1309   long Error = 0;
1310   long Zone;
1311   long Letters[OSSIM_MGRS_LETTERS];
1312   long In_Precision;
1313   error_code = Break_OSSIM_MGRS_String (OSSIM_MGRS, &Zone, Letters, Easting, Northing, &In_Precision);
1314   if (Zone)
1315     error_code |= OSSIM_MGRS_STRING_ERROR;
1316   if (!error_code)
1317   {
1318     GRID_UPS (Letters, Hemisphere, Easting, Northing, &Error);
1319     if (Error)
1320       error_code = OSSIM_MGRS_STRING_ERROR;
1321   }
1322   return (error_code);
1323 } /* Convert_OSSIM_MGRS_To_UPS */
1324 
1325 
1326