• 홈
  • 정보
    • MeuWorks! photo

      MeuWorks!

      메우와 메우를 찬양하는 친구들의 모임이다 메우!

    • 더 보기
    • Email
    • Twitter
    • Facebook
    • Github
  • 게시글
    • 모든 게시글
    • 모든 태그
  • Projects

  • CenoX IDC

MGRS convert

23 Oct 2018

Reading time ~4 minutes

MGRS <-> Lat Lng

GPS 좌표 체계는 MGRS/UTM/Latitude-Longitude 등이 있는데, MGRS가 군사쪽에서 사용하는 좌표다 보니까 자료가 별로 없다…

그래서 개발하다가 암에 걸려버려서 아래 소스코드를 배포하니, 다른 사람들은 나와 같은 암에 걸리지 않길 바란다…

스택오버플로우에서 발견한 js 코드를 기반으로 수정했다.

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#ifndef PI
    #define PI 3.14159265358979323846
#endif

typedef struct __default_gps_mgrs_new_coordinate_t {
    union{
        char values[15];
        struct{
            char gzd[3];
            char id[2];
            char e[5];
            char n[5];
        };
    };
} gps_mgrs_new_coordinate_t;

char* pad (int val) {
    char* result = (char*)calloc(sizeof(char), 7);
    sprintf(result, "%05d", val);
    return result;
}
    
int16_t str_pos(const char * str, const char search) {
    int16_t i;
    const char * found = strchr(str, search);
    int16_t pos = 0;
    if (found == 0)
        return -1;
    while (*str && str < found) {
        i = 1;
        if ((*str & 0xE0) == 0xC0) i=2;
        else if ((*str & 0xF0) == 0xE0) i=3;
        else if ((*str & 0xF8) == 0xF0) i=4;
        str += i;
        pos += i == 4 ? 2 : 1;
    }
    return pos;
}

double* LatLongFromMGRSstring(gps_mgrs_new_coordinate_t mgrs) {
    char* temp = (char*)calloc(sizeof(char), 8);
    memcpy(temp, mgrs.gzd, 2);
    int c = atoi(temp);
    char d = mgrs.gzd[2];
    double e = (c*6-183)*PI / 180;
    const char* table0[] = {
        "ABCDEFGH","JKLMNPQR","STUVWXYZ"
    };
    int f = str_pos(table0[(c-1) % 3], mgrs.id[0]) + 1;
    const char* table1 = "CDEFGHJKLMNPQRSTUVWXX";
    int g = str_pos(table1, d);
    const char* table2[] = {
        "ABCDEFGHJKLMNPQRSTUV","FGHJKLMNPQRSTUVABCDE"
    };
    int h = str_pos(table2[(c-1) % 2], mgrs.id[1]);
    const double i[] = {1.1,2.0,2.8,3.7,4.6,5.5,6.4,7.3,8.2,9.1,0,0.8,1.7,2.6,3.5,4.4,5.3,6.2,7.0,7.9};
    const int j[] = {0,2,2,2,4,4,6,6,8,8,0,0,0,2,2,4,4,6,6,6};
    double k = i[g];
    double l = (double)j[g] + h / 10.0;
    if (l < k) {
        l += 2;
    }
    memset(temp, 0x00, 5);
    memcpy(temp, mgrs.e, 5);
    double m = f*100000.0 + atof(temp);
    memset(temp, 0x00, 5);
    memcpy(temp, mgrs.n, 5);
    double n = l*1000000 + atof(temp);
    m -= 500000.0;
    if (d < 'N') {
        n -= 10000000.0;
    }
    m /= 0.9996; 
    n /= 0.9996;
    double o = n / 6367449.14570093;
    double p = o + 
        (0.0025188266133249035*sin(2.0*o)) +
        (0.0000037009491206268*sin(4.0*o)) + 
        (0.0000000074477705265*sin(6.0*o)) + 
        (0.0000000000170359940*sin(8.0*o));

    double q = tan(p);
    double r = q*q;
    double s = r*r;
    double t = cos(p);
    double u = 0.006739496819936062*pow(t,2.0);
    double v = 40680631590769 / (6356752.314*sqrt(1.0 + u));
    double w = v;
    double x = 1.0 / (w*t); w *= v;
    double y = q / (2.0*w); w *= v;
    double z = 1.0 / (6.0*w*t); w *= v;
    double aa = q / (24.0*w); w *= v;
    double ab = 1.0 / (120.0*w*t); w *= v;
    double ac = q / (720.0*w); w *= v;
    double ad = 1.0 / (5040.0*w*t); w *= v;
    double ae = q / (40320.0*w);
    double af = -1.0-u;
    double ag = -1.0-2*r-u;
    double ah = 5.0 + 3.0*r + 6.0*u-6.0*r*u-3.0*(u*u)-9.0*r*(u*u);
    double ai = 5.0 + 28.0*r + 24.0*s + 6.0*u + 8.0*r*u;
    double aj = -61.0-90.0*r-45.0*s-107.0*u + 162.0*r*u;
    double ak = -61.0-662.0*r-1320.0*s-720.0*(s*r);
    double al = 1385.0 + 3633.0*r + 4095.0*s + 1575*(s*r);
    double lat = p + y*af*(m*m) + aa*ah*pow(m,4) + ac*aj*pow(m,6) + ae*al*pow(m,8);
    double lng = e + x*m + z*ag*pow(m,3) + ab*ai*pow(m,5) + ad*ak*pow(m,7);
    free(temp);
    double* result = (double*)calloc(sizeof(double), 2);
    result[0] = lat*180 / PI;
    result[1] = lng*180 / PI;
    return result;
}

char* latLngToMGRS(double lat, double lng){
    int c = (int)(1 + floor((lng + 180) / 6));
    double e = c * 6 - 183;
    double k = lat * PI / 180;
    double l = lng * PI / 180;
    double m = e * PI / 180;
    double n = cos(k);
    double o = 0.006739496819936062 * pow(n, 2);
    double p = 40680631590769/(6356752.314*sqrt(1 + o));
    double q = tan(k);
    double r = q * q;
    double s = (r*r*r) - pow(q,6);
    double t = l - m;
    double u = 1.0 - r + o;
    double v = 5.0 - r + 9*o + 4.0*(o*o);
    double w = 5.0 - 18.0*r + (r*r) + 14.0*o - 58.0*r*o;
    double x = 61.0 - 58.0*r + (r*r) + 270.0*o - 330.0*r*o;
    double y = 61.0 - 479.0*r + 179.0*(r*r) - (r*r*r);
    double z = 1385.0 - 3111.0*r + 543.0*(r*r) - (r*r*r);
    double aa = p*n*t + (p/6.0*pow (n,3)*u*pow (t,3)) 
        + (p/120.0*pow (n,5)*w*pow (t,5)) 
        + (p/5040.0*pow (n,7)*y*pow (t,7));
    double ab = 6367449.14570093*(k - (0.00251882794504*sin (2*k)) 
        + (0.00000264354112*sin (4*k)) - (0.00000000345262*sin (6*k)) 
        + (0.000000000004892*sin (8*k))) + (q/2.0*p*pow (n,2)*pow (t,2)) 
        + (q/24.0*p*pow (n,4)*v*pow (t,4)) + (q/720.0*p*pow (n,6)*x*pow (t,6)) 
        + (q/40320.0*p*pow (n,8)*z*pow (t,8));
    aa = aa*0.9996 + 500000.0;
    ab = ab*0.9996; 
    if (ab < 0.0) {
        ab += 10000000.0;
    }
    const char* temp0 = "CDEFGHJKLMNPQRSTUVWXX\0";
    char ad = temp0[(int)floor (lat/8 + 10)];
    int ae = (int)floor (aa/100000);
    const char* temp1[] = {
        "ABCDEFGH\0"
        ,"JKLMNPQR\0"
        ,"STUVWXYZ\0"
    };
    char af = temp1[(c-1)%3][ae-1];
    int ag = (int)floor(ab/100000)%20;

    const char* temp2[] = {
        "ABCDEFGHJKLMNPQRSTUV\0"
        ,"FGHJKLMNPQRSTUVABCDE\0"
    };
    char ah = temp2[(c-1)%2][ag];
    aa = floor ((int)aa%100000); 
    char* aaStr = pad ((int)aa);
    ab = floor ((int)ab%100000); 
    char* abStr = pad ((int)ab);
    char* result = (char*)calloc(sizeof(char), 256);
    sprintf(result, "%d%c%c%c%s%s\n", c, ad, af, ah, aaStr, abStr);
    free(aaStr);
    free(abStr);
    return result;
}
#define ONE 0
int main(int argc, char const *argv[]){
    #if ONE
    double lat = 37.9975178;
    double lng = 127.2190851;
    #else
    double lat = 38.9972110;
    double lng = 123.2187474;
    #endif
    char* result = latLngToMGRS(lat, lng);
    printf("[START]\nLat : %lf \t Lng : %lf\n", lat, lng);
    printf("%s", result);
    gps_mgrs_new_coordinate_t mgrs;
    memcpy(mgrs.values, result, sizeof(gps_mgrs_new_coordinate_t));
    double* latLng = LatLongFromMGRSstring(mgrs);
    printf("Lat : %lf \t Lng : %lf\n", latLng[0], latLng[1]);
    free(result);
    result = latLngToMGRS(latLng[0], latLng[1]);
    printf("%s", result);
    free(latLng);
    free(result);
    return 0;
}



Gyungdal Share Tweet +1