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: 2024-11-21 22:18:42 Functions: 4 9 44.4 %

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

Generated by: LCOV version 1.14