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, <rlow, <rhi, &fnltr);
401 ltrnum[0] = LETTER_A;
402 UTMLIM(<rnum[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], <rlow, <rhi, &feltr, &fnltr, <rhy);
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], <rlow, <rhi, &feltr, &fnltr, <rhy);
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, <rlow, <rhi, &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