LCOV - code coverage report
Current view: top level - frmts/nitf - mgrs.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 102 272 37.5 %
Date: 2025-01-18 12:42:00 Functions: 4 9 44.4 %

          Line data    Source code
       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             : #define LETTER_A 0        /* ARRAY INDEX FOR LETTER A               */
     109             : #define LETTER_B 1        /* ARRAY INDEX FOR LETTER B               */
     110             : #define LETTER_C 2        /* ARRAY INDEX FOR LETTER C               */
     111             : #define LETTER_D 3        /* ARRAY INDEX FOR LETTER D               */
     112             : #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             : #define LETTER_H 7        /* ARRAY INDEX FOR LETTER H               */
     116             : #define LETTER_I 8        /* ARRAY INDEX FOR LETTER I               */
     117             : #define LETTER_J 9        /* ARRAY INDEX FOR LETTER J               */
     118             : #define LETTER_K 10       /* ARRAY INDEX FOR LETTER J               */
     119             : #define LETTER_L 11       /* ARRAY INDEX FOR LETTER L               */
     120             : #define LETTER_M 12       /* ARRAY INDEX FOR LETTER M               */
     121             : #define LETTER_N 13       /* ARRAY INDEX FOR LETTER N               */
     122             : #define LETTER_O 14       /* ARRAY INDEX FOR LETTER O               */
     123             : #define LETTER_P 15       /* ARRAY INDEX FOR LETTER P               */
     124             : #define LETTER_Q 16       /* ARRAY INDEX FOR LETTER Q               */
     125             : #define LETTER_R 17       /* ARRAY INDEX FOR LETTER R               */
     126             : #define LETTER_S 18       /* ARRAY INDEX FOR LETTER S               */
     127             : #define LETTER_T 19       /* ARRAY INDEX FOR LETTER S               */
     128             : #define LETTER_U 20       /* ARRAY INDEX FOR LETTER U               */
     129             : #define LETTER_V 21       /* ARRAY INDEX FOR LETTER V               */
     130             : #define LETTER_W 22       /* ARRAY INDEX FOR LETTER W               */
     131             : #define LETTER_X 23       /* ARRAY INDEX FOR LETTER X               */
     132             : #define LETTER_Y 24       /* ARRAY INDEX FOR LETTER Y               */
     133             : #define LETTER_Z 25       /* ARRAY INDEX FOR LETTER Z               */
     134             : #define MGRS_LETTERS 3    /* NUMBER OF LETTERS IN MGRS              */
     135             : #define ONEHT 100000.e0   /* ONE HUNDRED THOUSAND                  */
     136             : #define TWOMIL 2000000.e0 /* TWO MILLION                           */
     137             : #define TRUE 1            /* CONSTANT VALUE FOR TRUE VALUE  */
     138             : #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             : #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             : #define MIN_EAST_NORTH 0
     150             : #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           8 : 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             : { /* Get_Latitude_Band_Min_Northing */
     227           8 :     long error_code = MGRS_NO_ERROR;
     228             : 
     229           8 :     if ((letter >= LETTER_C) && (letter <= LETTER_H))
     230           0 :         *min_northing = Latitude_Band_Table[letter - 2].min_northing;
     231           8 :     else if ((letter >= LETTER_J) && (letter <= LETTER_N))
     232           0 :         *min_northing = Latitude_Band_Table[letter - 3].min_northing;
     233           8 :     else if ((letter >= LETTER_P) && (letter <= LETTER_X))
     234           8 :         *min_northing = Latitude_Band_Table[letter - 4].min_northing;
     235             :     else
     236           0 :         error_code |= MGRS_STRING_ERROR;
     237             : 
     238           8 :     return error_code;
     239             : } /* 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           0 : 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             : { /* Round_MGRS */
     352             :     double ivalue;
     353             :     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             : } /* Round_MGRS */
     360             : 
     361           0 : 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             : { /* Make_MGRS_String */
     375             :     long i;
     376             :     long j;
     377             :     double divisor;
     378             :     long east;
     379             :     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             :     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             :                       north);
     403           0 :     return (error_code);
     404             : } /* Make_MGRS_String */
     405             : 
     406           8 : 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             : { /* Break_MGRS_String */
     421             :     long num_digits;
     422             :     long num_letters;
     423           8 :     long i = 0;
     424           8 :     long j = 0;
     425           8 :     long error_code = MGRS_NO_ERROR;
     426             : 
     427           8 :     while (MGRS[i] == ' ')
     428           0 :         i++; /* skip any leading blanks */
     429           8 :     j = i;
     430          24 :     while (isdigit((unsigned char)MGRS[i]))
     431          16 :         i++;
     432           8 :     num_digits = i - j;
     433           8 :     if (num_digits <= 2)
     434           8 :         if (num_digits > 0)
     435             :         {
     436             :             char zone_string[3];
     437             :             /* get zone */
     438           8 :             strncpy(zone_string, MGRS + j, 2);
     439           8 :             zone_string[2] = 0;
     440           8 :             sscanf(zone_string, "%ld", Zone);
     441           8 :             if ((*Zone < 1) || (*Zone > 60))
     442           0 :                 error_code |= MGRS_STRING_ERROR;
     443             :         }
     444             :         else
     445           0 :             *Zone = 0;
     446             :     else
     447           0 :         error_code |= MGRS_STRING_ERROR;
     448           8 :     j = i;
     449             : 
     450          32 :     while (isalpha((unsigned char)MGRS[i]))
     451          24 :         i++;
     452           8 :     num_letters = i - j;
     453           8 :     if (num_letters == 3)
     454             :     {
     455             :         /* get letters */
     456           8 :         Letters[0] = (toupper((unsigned char)MGRS[j]) - (long)'A');
     457           8 :         if ((Letters[0] == LETTER_I) || (Letters[0] == LETTER_O))
     458           0 :             error_code |= MGRS_STRING_ERROR;
     459           8 :         Letters[1] = (toupper((unsigned char)MGRS[j + 1]) - (long)'A');
     460           8 :         if ((Letters[1] == LETTER_I) || (Letters[1] == LETTER_O))
     461           0 :             error_code |= MGRS_STRING_ERROR;
     462           8 :         Letters[2] = (toupper((unsigned char)MGRS[j + 2]) - (long)'A');
     463           8 :         if ((Letters[2] == LETTER_I) || (Letters[2] == LETTER_O))
     464           0 :             error_code |= MGRS_STRING_ERROR;
     465             :     }
     466             :     else
     467           0 :         error_code |= MGRS_STRING_ERROR;
     468           8 :     j = i;
     469          88 :     while (isdigit((unsigned char)MGRS[i]))
     470          80 :         i++;
     471           8 :     num_digits = i - j;
     472           8 :     if ((num_digits <= 10) && (num_digits % 2 == 0))
     473           8 :     {
     474             :         long n;
     475             :         char east_string[6];
     476             :         char north_string[6];
     477             :         long east;
     478             :         long north;
     479             :         double multiplier;
     480             :         /* get easting & northing */
     481           8 :         n = num_digits / 2;
     482           8 :         *Precision = n;
     483           8 :         if (n > 0)
     484             :         {
     485           8 :             strncpy(east_string, MGRS + j, n);
     486           8 :             east_string[n] = 0;
     487           8 :             sscanf(east_string, "%ld", &east);
     488           8 :             strncpy(north_string, MGRS + j + n, n);
     489           8 :             north_string[n] = 0;
     490           8 :             sscanf(north_string, "%ld", &north);
     491           8 :             multiplier = pow(10.0, 5 - n);
     492           8 :             *Easting = east * multiplier;
     493           8 :             *Northing = north * multiplier;
     494             :         }
     495             :         else
     496             :         {
     497           0 :             *Easting = 0.0;
     498           0 :             *Northing = 0.0;
     499             :         }
     500             :     }
     501             :     else
     502           0 :         error_code |= MGRS_STRING_ERROR;
     503             : 
     504           8 :     return (error_code);
     505             : } /* Break_MGRS_String */
     506             : 
     507           8 : 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             : {                    /* BEGIN Get_Grid_Values */
     522             :     long set_number; /* Set number (1-6) based on UTM zone number */
     523             :     long aa_pattern; /* Pattern based on ellipsoid code */
     524             : 
     525           8 :     set_number = zone % 6;
     526             : 
     527           8 :     if (!set_number)
     528           0 :         set_number = 6;
     529             : 
     530           8 :     if (!strcmp(MGRS_Ellipsoid_Code, CLARKE_1866) ||
     531           8 :         !strcmp(MGRS_Ellipsoid_Code, CLARKE_1880) ||
     532           8 :         !strcmp(MGRS_Ellipsoid_Code, BESSEL_1841) ||
     533           8 :         !strcmp(MGRS_Ellipsoid_Code, BESSEL_1841_NAMIBIA))
     534             :         aa_pattern = FALSE;
     535             :     else
     536           8 :         aa_pattern = TRUE;
     537             : 
     538           8 :     if ((set_number == 1) || (set_number == 4))
     539             :     {
     540           8 :         *ltr2_low_value = LETTER_A;
     541           8 :         *ltr2_high_value = LETTER_H;
     542             :     }
     543           0 :     else if ((set_number == 2) || (set_number == 5))
     544             :     {
     545           0 :         *ltr2_low_value = LETTER_J;
     546           0 :         *ltr2_high_value = LETTER_R;
     547             :     }
     548           0 :     else if ((set_number == 3) || (set_number == 6))
     549             :     {
     550           0 :         *ltr2_low_value = LETTER_S;
     551           0 :         *ltr2_high_value = LETTER_Z;
     552             :     }
     553             : 
     554             :     /* False northing at A for second letter of grid square */
     555           8 :     if (aa_pattern)
     556             :     {
     557           8 :         if ((set_number % 2) == 0)
     558           0 :             *false_northing = 1500000.0;
     559             :         else
     560           8 :             *false_northing = 0.0;
     561             :     }
     562             :     else
     563             :     {
     564           0 :         if ((set_number % 2) == 0)
     565           0 :             *false_northing = 500000.0;
     566             :         else
     567           0 :             *false_northing = 1000000.00;
     568             :     }
     569           8 : } /* 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           0 : 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             : { /* 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             : } /* 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           8 : 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             : { /* Convert_MGRS_To_UTM */
     764             :     double scaled_min_northing;
     765             :     double min_northing;
     766           8 :     long ltr2_low_value = 0;
     767           8 :     long ltr2_high_value = 0;
     768             :     double false_northing;
     769             :     double grid_easting;  /* Easting for 100,000 meter grid square      */
     770             :     double grid_northing; /* Northing for 100,000 meter grid square     */
     771             :     long letters[MGRS_LETTERS];
     772             :     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           8 :     long error_code = MGRS_NO_ERROR;
     781             : 
     782           8 :     error_code = Break_MGRS_String(MGRS, Zone, letters, Easting, Northing,
     783             :                                    &in_precision);
     784           8 :     if (!*Zone)
     785           0 :         error_code |= MGRS_STRING_ERROR;
     786             :     else
     787             :     {
     788           8 :         if (!error_code)
     789             :         {
     790           8 :             if ((letters[0] == LETTER_X) &&
     791           0 :                 ((*Zone == 32) || (*Zone == 34) || (*Zone == 36)))
     792           0 :                 error_code |= MGRS_STRING_ERROR;
     793             :             else
     794             :             {
     795           8 :                 if (letters[0] < LETTER_N)
     796           0 :                     *Hemisphere = 'S';
     797             :                 else
     798           8 :                     *Hemisphere = 'N';
     799             : 
     800           8 :                 Get_Grid_Values(*Zone, &ltr2_low_value, &ltr2_high_value,
     801             :                                 &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           8 :                 if ((letters[1] < ltr2_low_value) ||
     807           8 :                     (letters[1] > ltr2_high_value) || (letters[2] > LETTER_V))
     808           0 :                     error_code |= MGRS_STRING_ERROR;
     809             : 
     810           8 :                 if (!error_code)
     811             :                 {
     812           8 :                     grid_northing =
     813           8 :                         (double)(letters[2]) * ONEHT + false_northing;
     814           8 :                     grid_easting =
     815           8 :                         (double)((letters[1]) - ltr2_low_value + 1) * ONEHT;
     816           8 :                     if ((ltr2_low_value == LETTER_J) && (letters[1] > LETTER_O))
     817           0 :                         grid_easting = grid_easting - ONEHT;
     818             : 
     819           8 :                     if (letters[2] > LETTER_O)
     820           8 :                         grid_northing = grid_northing - ONEHT;
     821             : 
     822           8 :                     if (letters[2] > LETTER_I)
     823           8 :                         grid_northing = grid_northing - ONEHT;
     824             : 
     825           8 :                     if (grid_northing >= TWOMIL)
     826           0 :                         grid_northing = grid_northing - TWOMIL;
     827             : 
     828           8 :                     error_code = Get_Latitude_Band_Min_Northing(letters[0],
     829             :                                                                 &min_northing);
     830           8 :                     if (!error_code)
     831             :                     {
     832           8 :                         scaled_min_northing = min_northing;
     833          24 :                         while (scaled_min_northing >= TWOMIL)
     834             :                         {
     835          16 :                             scaled_min_northing = scaled_min_northing - TWOMIL;
     836             :                         }
     837             : 
     838           8 :                         grid_northing = grid_northing - scaled_min_northing;
     839           8 :                         if (grid_northing < 0.0)
     840           0 :                             grid_northing = grid_northing + TWOMIL;
     841             : 
     842           8 :                         grid_northing = min_northing + grid_northing;
     843             : 
     844           8 :                         *Easting = grid_easting + *Easting;
     845           8 :                         *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             :                     }
     873             :                 }
     874             :             }
     875             :         }
     876             :     }
     877           8 :     return (error_code);
     878             : } /* Convert_MGRS_To_UTM */
     879             : 
     880           0 : 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             : {                          /* Convert_UPS_To_MGRS */
     896             :     double false_easting;  /* False easting for 2nd letter                 */
     897             :     double false_northing; /* False northing for 3rd letter                */
     898             :     double grid_easting;   /* Easting used to derive 2nd letter of MGRS    */
     899             :     double grid_northing;  /* Northing used to derive 3rd letter of MGRS   */
     900             :     long ltr2_low_value;   /* 2nd letter range - low number                */
     901           0 :     int letters[MGRS_LETTERS] = {
     902             :         0}; /* Number location of 3 letters in alphabet     */
     903             :     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             :     {
     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             :         {
     923           0 :             if (Easting >= TWOMIL)
     924           0 :                 letters[0] = LETTER_Z;
     925             :             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             :         }
     933             :         else
     934             :         {
     935           0 :             if (Easting >= TWOMIL)
     936           0 :                 letters[0] = LETTER_B;
     937             :             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             :         }
     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             :         {
     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             :         }
     967             :         else
     968             :         {
     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             :         }
     978             : 
     979           0 :         Make_MGRS_String(MGRS, 0, letters, Easting, Northing, Precision);
     980             :     }
     981           0 :     return (error_code);
     982             : } /* Convert_UPS_To_MGRS */
     983             : 
     984           0 : 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             : {                          /* Convert_MGRS_To_UPS */
     998             :     long ltr2_high_value;  /* 2nd letter range - high number             */
     999             :     long ltr3_high_value;  /* 3rd letter range - high number (UPS)       */
    1000             :     long ltr2_low_value;   /* 2nd letter range - low number              */
    1001             :     double false_easting;  /* False easting for 2nd letter               */
    1002             :     double false_northing; /* False northing for 3rd letter              */
    1003             :     double grid_easting;   /* easting for 100,000 meter grid square      */
    1004             :     double grid_northing;  /* northing for 100,000 meter grid square     */
    1005           0 :     long zone = 0;
    1006             :     long letters[MGRS_LETTERS];
    1007             :     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             :                                    &in_precision);
    1013           0 :     if (zone)
    1014           0 :         error_code |= MGRS_STRING_ERROR;
    1015             :     else
    1016             :     {
    1017           0 :         if (!error_code)
    1018             :         {
    1019           0 :             if (letters[0] >= LETTER_Y)
    1020             :             {
    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             :             }
    1030             :             else
    1031             :             {
    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             :             }
    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             :             {
    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             :                                false_easting;
    1065           0 :                 if (ltr2_low_value != LETTER_A)
    1066             :                 {
    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             :                 }
    1073             :                 else
    1074             :                 {
    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             :                 }
    1084             : 
    1085           0 :                 *Easting = grid_easting + *Easting;
    1086           0 :                 *Northing = grid_northing + *Northing;
    1087             :             }
    1088             :         }
    1089             :     }
    1090           0 :     return (error_code);
    1091             : } /* Convert_MGRS_To_UPS */

Generated by: LCOV version 1.14