Nerdegutta's logo

nerdegutta.no

C: Convert Lat Lon to MGRS

18.08.24

Programming

Creating a C program that converts latitude and longitude to the Military Grid Reference System (MGRS) without using any external libraries involves several steps. The MGRS is a geocoordinate standard used by NATO militaries for locating points on the Earth. It's based on the Universal Transverse Mercator (UTM) coordinate system and the Universal Polar Stereographic (UPS) coordinate system.

Here’s an outline of the process:

Convert Latitude/Longitude to UTM:

  • Determine the UTM zone.
  • Convert latitude and longitude to easting and northing using the Transverse Mercator projection.
  • Handle the hemisphere (North/South).

  • Convert UTM to MGRS:
  • Use the UTM zone, easting, and northing to form the MGRS coordinates.
  • Determine the 100,000-meter square identifier.
  • Format the easting and northing values into the MGRS format.

  • Below is a simplified example of how to achieve this in C:

    #include < stdio.h >
    #include < math.h >
    
    // Constants
    #define WGS84_A 6378137.0          // major axis
    #define WGS84_F 298.257223563      // flattening
    #define WGS84_E2 (1 - (1 - 1 / WGS84_F) * (1 - 1 / WGS84_F)) // first eccentricity squared
    
    // Function prototypes
    void latLonToUTM(double lat, double lon, int *zone, double *easting, double *northing);
    void utmToMGRS(int zone, double easting, double northing, char *mgrs);
    
    // Helper functions
    int getZone(double lon);
    double degToRad(double deg);
    double radToDeg(double rad);
    
    int main() {
        double lat = 37.7749; // example latitude
        double lon = -122.4194; // example longitude
        int zone;
        double easting, northing;
        char mgrs[20];
    
        // Convert latitude/longitude to UTM
        latLonToUTM(lat, lon, &zone, &easting, &northing);
    
        // Convert UTM to MGRS
        utmToMGRS(zone, easting, northing, mgrs);
    
        // Print the results
        printf("MGRS: %s
    ", mgrs);
    
        return 0;
    }
    
    // Converts latitude/longitude to UTM coordinates
    void latLonToUTM(double lat, double lon, int *zone, double *easting, double *northing) {
        double k0 = 0.9996; // scale factor
        double lon0, e2, N, T, C, A, M;
    
        *zone = getZone(lon);
        lon0 = ((*zone - 1) * 6 - 180 + 3) * M_PI / 180; // Central meridian
    
        lat = degToRad(lat);
        lon = degToRad(lon);
    
        e2 = WGS84_E2;
        N = WGS84_A / sqrt(1 - e2 * sin(lat) * sin(lat));
        T = tan(lat) * tan(lat);
        C = e2 * cos(lat) * cos(lat) / (1 - e2);
        A = cos(lat) * (lon - lon0);
    
        M = WGS84_A * ((1 - e2 / 4 - 3 * e2 * e2 / 64 - 5 * e2 * e2 * e2 / 256) * lat
                    - (3 * e2 / 8 + 3 * e2 * e2 / 32 + 45 * e2 * e2 * e2 / 1024) * sin(2 * lat)
                    + (15 * e2 * e2 / 256 + 45 * e2 * e2 * e2 / 1024) * sin(4 * lat)
                    - (35 * e2 * e2 * e2 / 3072) * sin(6 * lat));
    
        *easting = k0 * N * (A + (1 - T + C) * A * A * A / 6 + (5 - 18 * T + T * T + 72 * C - 58 * e2) * A * A * A * A * A / 120) + 500000.0;
    
        *northing = k0 * (M + N * tan(lat) * (A * A / 2 + (5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24
                        + (61 - 58 * T + T * T + 600 * C - 330 * e2) * A * A * A * A * A * A / 720));
    
        // If in the southern hemisphere, adjust the northing
        if (lat < 0)
            *northing += 10000000.0;
    }
    
    // Determines the UTM zone from longitude
    int getZone(double lon) {
        return (int)((lon + 180) / 6) + 1;
    }
    
    // Converts degrees to radians
    double degToRad(double deg) {
        return deg * M_PI / 180.0;
    }
    
    // Converts radians to degrees
    double radToDeg(double rad) {
        return rad * 180.0 / M_PI;
    }
    
    // Converts UTM coordinates to MGRS
    void utmToMGRS(int zone, double easting, double northing, char *mgrs) {
        int e100k = (int)(easting / 100000.0);
        int n100k = (int)(northing / 100000.0) % 20;
    
        char e100kLetters[] = "ABCDEFGHJKLMNPQRSTUV";
        char n100kLetters[] = "ABCDEFGHJKLMNPQRSTUV";
    
        int eIndex = e100k % 8;
        int nIndex = (zone % 2 == 0) ? (n100k + 5) % 20 : n100k;
    
        snprintf(mgrs, 20, "%02d%c%c %05d %05d", zone, e100kLetters[eIndex], n100kLetters[nIndex],
                 (int)fmod(easting, 100000), (int)fmod(northing, 100000));
    }
    
    
    Explanation:
    latLonToUTM: This function converts latitude and longitude into UTM coordinates. It calculates the UTM zone, easting, and northing using the WGS84 ellipsoid parameters.
    utmToMGRS: This function converts the UTM coordinates to an MGRS string. It determines the 100,000-meter square letters and formats the easting and northing into the final MGRS string.
    Simplifications:
    This implementation uses a simplified method for computing MGRS coordinates and does not handle certain edge cases (e.g., poles, areas near the UTM zone boundaries, or the finer details of letter zone determination). For real-world applications, edge cases and more sophisticated calculations should be considered. This implementation provides a basic, functional example to demonstrate the conversion process. This example should be sufficient for basic use and educational purposes. However, for precise or critical applications, a full understanding of the UTM and MGRS standards and possibly the use of a geospatial library is recommended.

    To run this program
    To run this program you need to compile it first . I'm a Linux guy, so I'll be using GCC with some parameters.
    gcc LatlonToMGRS.c -Wall -lm
    
    Important here is the -lm-parameter. This parameter link in the math.h library that we include in line #2, in the source code. I do not have an output name, so gcc will use the standard a.out-filename. When compiling is successful, you can run the program with ./a.out.