Coverage Report

Created: 2025-11-15 08:43

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