기상청 날씨정보 API 격자/위경도 변환

https://gist.github.com/fronteer-kr/14d7f779d52a21ac2f16 를 참고하여 php버전을 만듬.

백업용으로 이곳에 기록해둠.

 

PHP

소스코드

class ConvGridGps {
	const RE = 6371.00877; // 지구 반경(km)
	const GRID = 5.0; // 격자 간격(km)
	const SLAT1 = 30.0; // 투영 위도1(degree)
	const SLAT2 = 60.0; // 투영 위도2(degree)
	const OLON = 126.0; // 기준점 경도(degree)
	const OLAT = 38.0; // 기준점 위도(degree)
	const XO = 43; // 기준점 X좌표(GRID)
	const YO = 136; // 기1준점 Y좌표(GRID)

	const DEGRAD = M_PI / 180.0;
	const RADDEG = 180.0 / M_PI;

	const re = self::RE / self::GRID;
	const slat1 = self::SLAT1 * self::DEGRAD;
	const slat2 = self::SLAT2 * self::DEGRAD;
	const olon = self::OLON * self::DEGRAD;
	const olat = self::OLAT * self::DEGRAD;

	function sn(){
		$snTmp = tan(M_PI * 0.25 + self::slat2 * 0.5) / tan(M_PI * 0.25 + self::slat1 * 0.5);
		return log(cos(self::slat1) / cos(self::slat2)) / log($snTmp);
	}

	function sf(){
		$sfTmp = tan(M_PI * 0.25 + self::slat1 * 0.5);
		return pow($sfTmp, $this->sn()) * cos(self::slat1) / $this->sn();
	}

	function ro(){
		$roTmp = tan(M_PI * 0.25 + self::olat * 0.5);
		return self::re * $this->sf() / pow($roTmp, $this->sn());
	}

	function gridToGPS($v1, $v2) {
	  $rs['x'] = $v1;
	  $rs['y'] = $v2;
	  $xn = (int)($v1 - self::XO);
	  $yn = (int)($this->ro() - $v2 + self::YO);
	  $ra = sqrt($xn * $xn + $yn * $yn);
	  if ($this->sn() < 0.0) $ra = -$ra;
	  $alat = pow((self::re * $this->sf() / $ra), (1.0 / $this->sn()));
	  $alat = 2.0 * atan($alat) - M_PI * 0.5;

	  if (abs($xn) <= 0.0) {
		$theta = 0.0;
	  } else {
		if (abs($yn) <= 0.0) {
		  $theta = M_PI * 0.5;
		  if ($xn < 0.0) $theta = -$theta;
		} else
		  $theta = atan2($xn, $yn);
	  }
	  $alon = $theta / $this->sn() + self::olon;
	  $rs['lat'] = $alat * self::RADDEG;
	  $rs['lng'] = $alon * self::RADDEG;

	  return $rs;
	}

	function gpsToGRID($v1, $v2) {
	  $rs['lat'] = $v1;
	  $rs['lng'] = $v2;
	  $ra = tan(M_PI * 0.25 + ($v1) * self::DEGRAD * 0.5);
	  $ra = self::re * $this->sf() / pow($ra, $this->sn());
	  $theta = $v2 * self::DEGRAD - self::olon;
	  if ($theta > M_PI) $theta -= 2.0 * M_PI;
	  if ($theta < -M_PI) $theta += 2.0 * M_PI;
	  $theta *= $this->sn();
	  $rs['x'] = floor(($ra * sin($theta) + self::XO + 0.5));
	  $rs['y'] = floor(($this->ro() - $ra * cos($theta) + self::YO + 0.5));

	  return $rs;
	}
  }


  $ConvGridGps = new ConvGridGps();
  $gridToGpsData = $ConvGridGps->gridToGPS(60,127);
  $gpsToGridData = $ConvGridGps->gpsToGRID(37.579871128849334, 126.98935225645432);
  print_r($gridToGpsData);
  print_r($gpsToGridData);

 

실행결과

Array ( [x] => 60 [y] => 127 [lat] => 37.615741485765 [lng] => 126.98991183668 )
Array ( [lat] => 37.579871128849 [lng] => 126.98935225645 [x] => 60 [y] => 127 )

 

 

 

Flutter

import 'dart:math' as Math;


void main() {
  var gridToGpsData = ConvGridGps.gridToGPS(60, 127);
  var gpsToGridData = ConvGridGps.gpsToGRID(37.579871128849334, 126.98935225645432);
  print(gridToGpsData);
  print(gpsToGridData);
}



class ConvGridGps {
  static const double RE = 6371.00877; // 지구 반경(km)
  static const double GRID = 5.0; // 격자 간격(km)
  static const double SLAT1 = 30.0; // 투영 위도1(degree)
  static const double SLAT2 = 60.0; // 투영 위도2(degree)
  static const double OLON = 126.0; // 기준점 경도(degree)
  static const double OLAT = 38.0; // 기준점 위도(degree)
  static const double XO = 43; // 기준점 X좌표(GRID)
  static const double YO = 136; // 기1준점 Y좌표(GRID)

  static const double DEGRAD = Math.pi / 180.0;
  static const double RADDEG = 180.0 / Math.pi;

  static double get re => RE / GRID;
  static double get slat1 => SLAT1 * DEGRAD;
  static double get slat2 => SLAT2 * DEGRAD;
  static double get olon => OLON * DEGRAD;
  static double get olat => OLAT * DEGRAD;

  static double get snTmp =>
      Math.tan(Math.pi * 0.25 + slat2 * 0.5) /
      Math.tan(Math.pi * 0.25 + slat1 * 0.5);
  static double get sn =>
      Math.log(Math.cos(slat1) / Math.cos(slat2)) / Math.log(snTmp);

  static double get sfTmp => Math.tan(Math.pi * 0.25 + slat1 * 0.5);
  static double get sf => Math.pow(sfTmp, sn) * Math.cos(slat1) / sn;

  static double get roTmp => Math.tan(Math.pi * 0.25 + olat * 0.5);

  static double get ro => re * sf / Math.pow(roTmp, sn);

  static gridToGPS(int v1, int v2) {
    var rs = {};
    double theta;

    rs['x'] = v1;
    rs['y'] = v2;
    int xn = (v1 - XO).toInt();
    int yn = (ro - v2 + YO).toInt();
    var ra = Math.sqrt(xn * xn + yn * yn);
    if (sn < 0.0) ra = -ra;
    var alat = Math.pow((re * sf / ra), (1.0 / sn));
    alat = 2.0 * Math.atan(alat) - Math.pi * 0.5;

    if (xn.abs() <= 0.0) {
      theta = 0.0;
    } else {
      if (yn.abs() <= 0.0) {
        theta = Math.pi * 0.5;
        if (xn < 0.0) theta = -theta;
      } else
        theta = Math.atan2(xn, yn);
    }
    var alon = theta / sn + olon;
    rs['lat'] = alat * RADDEG;
    rs['lng'] = alon * RADDEG;

    return rs;
  }

  static gpsToGRID(double v1, double v2) {
    var rs = {};
    double theta;

    rs['lat'] = v1;
    rs['lng'] = v2;
    var ra = Math.tan(Math.pi * 0.25 + (v1) * DEGRAD * 0.5);
    ra = re * sf / Math.pow(ra, sn);
    theta = v2 * DEGRAD - olon;
    if (theta > Math.pi) theta -= 2.0 * Math.pi;
    if (theta < -Math.pi) theta += 2.0 * Math.pi;
    theta *= sn;
    rs['x'] = (ra * Math.sin(theta) + XO + 0.5).floor();
    rs['y'] = (ro - ra * Math.cos(theta) + YO + 0.5).floor();

    return rs;
  }
}

 

실행결과

Flutter Web Bootstrap: Programmatic
{x: 60, y: 127, lat: 37.61574148576467, lng: 126.98991183668376}
{lat: 37.579871128849334, lng: 126.98935225645432, x: 60, y: 127}

 

 

 

Python

소스코드

import math
NX = 149            ## X축 격자점 수
NY = 253            ## Y축 격자점 수

Re = 6371.00877     ##  지도반경
grid = 5.0          ##  격자간격 (km)
slat1 = 30.0        ##  표준위도 1
slat2 = 60.0        ##  표준위도 2
olon = 126.0        ##  기준점 경도
olat = 38.0         ##  기준점 위도
xo = 210 / grid     ##  기준점 X좌표
yo = 675 / grid     ##  기준점 Y좌표
first = 0

if first == 0 :
    PI = math.asin(1.0) * 2.0
    DEGRAD = PI/ 180.0
    RADDEG = 180.0 / PI


    re = Re / grid
    slat1 = slat1 * DEGRAD
    slat2 = slat2 * DEGRAD
    olon = olon * DEGRAD
    olat = olat * DEGRAD

    sn = math.tan(PI * 0.25 + slat2 * 0.5) / math.tan(PI * 0.25 + slat1 * 0.5)
    sn = math.log(math.cos(slat1) / math.cos(slat2)) / math.log(sn)
    sf = math.tan(PI * 0.25 + slat1 * 0.5)
    sf = math.pow(sf, sn) * math.cos(slat1) / sn
    ro = math.tan(PI * 0.25 + olat * 0.5)
    ro = re * sf / math.pow(ro, sn)
    first = 1

def mapToGrid(lat, lon, code = 0 ):
    ra = math.tan(PI * 0.25 + lat * DEGRAD * 0.5)
    ra = re * sf / pow(ra, sn)
    theta = lon * DEGRAD - olon
    if theta > PI :
        theta -= 2.0 * PI
    if theta < -PI :
        theta += 2.0 * PI
    theta *= sn
    x = (ra * math.sin(theta)) + xo
    y = (ro - ra * math.cos(theta)) + yo
    x = int(x + 1.5)
    y = int(y + 1.5)
    return x, y

def gridToMap(x, y, code = 1):
    x = x - 1
    y = y - 1
    xn = x - xo
    yn = ro - y + yo
    ra = math.sqrt(xn * xn + yn * yn)
    if sn < 0.0 :
        ra = -ra
    alat = math.pow((re * sf / ra), (1.0 / sn))
    alat = 2.0 * math.atan(alat) - PI * 0.5
    if math.fabs(xn) <= 0.0 :
        theta = 0.0
    else :
        if math.fabs(yn) <= 0.0 :
            theta = PI * 0.5
            if xn < 0.0 :
                theta = -theta
        else :
            theta = math.atan2(xn, yn)
    alon = theta / sn + olon
    lat = alat * RADDEG
    lon = alon * RADDEG

    return lat, lon

print(mapToGrid(37.579871128849334, 126.98935225645432))
print(mapToGrid(35.101148844565955, 129.02478725562108))
print(mapToGrid(33.500946412305076, 126.54663058817043))


print(gridToMap(60, 127))
print(gridToMap(97, 74))
print(gridToMap(53, 38))

 

실행결과

### result :
#(60, 127)
#(97, 74)
#(53, 38)

### result
# 37.579871128849334, 126.98935225645432
# 35.101148844565955, 129.02478725562108
# 33.500946412305076, 126.54663058817043

 

 

 

Javascript

소스코드

    // LCC DFS 좌표변환을 위한 기초 자료
    //
    var RE = 6371.00877; // 지구 반경(km)
    var GRID = 5.0; // 격자 간격(km)
    var SLAT1 = 30.0; // 투영 위도1(degree)
    var SLAT2 = 60.0; // 투영 위도2(degree)
    var OLON = 126.0; // 기준점 경도(degree)
    var OLAT = 38.0; // 기준점 위도(degree)
    var XO = 43; // 기준점 X좌표(GRID)
    var YO = 136; // 기1준점 Y좌표(GRID)
    //
    // LCC DFS 좌표변환 ( code : "toXY"(위경도->좌표, v1:위도, v2:경도), "toLL"(좌표->위경도,v1:x, v2:y) )
    //


    function dfs_xy_conv(code, v1, v2) {
        var DEGRAD = Math.PI / 180.0;
        var RADDEG = 180.0 / Math.PI;

        var re = RE / GRID;
        var slat1 = SLAT1 * DEGRAD;
        var slat2 = SLAT2 * DEGRAD;
        var olon = OLON * DEGRAD;
        var olat = OLAT * DEGRAD;

        var sn = Math.tan(Math.PI * 0.25 + slat2 * 0.5) / Math.tan(Math.PI * 0.25 + slat1 * 0.5);
        sn = Math.log(Math.cos(slat1) / Math.cos(slat2)) / Math.log(sn);
        var sf = Math.tan(Math.PI * 0.25 + slat1 * 0.5);
        sf = Math.pow(sf, sn) * Math.cos(slat1) / sn;
        var ro = Math.tan(Math.PI * 0.25 + olat * 0.5);
        ro = re * sf / Math.pow(ro, sn);
        var rs = {};
        if (code == "toXY") {
            rs['lat'] = v1;
            rs['lng'] = v2;
            var ra = Math.tan(Math.PI * 0.25 + (v1) * DEGRAD * 0.5);
            ra = re * sf / Math.pow(ra, sn);
            var theta = v2 * DEGRAD - olon;
            if (theta > Math.PI) theta -= 2.0 * Math.PI;
            if (theta < -Math.PI) theta += 2.0 * Math.PI;
            theta *= sn;
            rs['x'] = Math.floor(ra * Math.sin(theta) + XO + 0.5);
            rs['y'] = Math.floor(ro - ra * Math.cos(theta) + YO + 0.5);
        }
        else {
            rs['x'] = v1;
            rs['y'] = v2;
            var xn = v1 - XO;
            var yn = ro - v2 + YO;
            ra = Math.sqrt(xn * xn + yn * yn);
            if (sn < 0.0) - ra;
            var alat = Math.pow((re * sf / ra), (1.0 / sn));
            alat = 2.0 * Math.atan(alat) - Math.PI * 0.5;

            if (Math.abs(xn) <= 0.0) {
                theta = 0.0;
            }
            else {
                if (Math.abs(yn) <= 0.0) {
                    theta = Math.PI * 0.5;
                    if (xn < 0.0) - theta;
                }
                else theta = Math.atan2(xn, yn);
            }
            var alon = theta / sn + olon;
            rs['lat'] = alat * RADDEG;
            rs['lng'] = alon * RADDEG;
        }
        return rs;
    }
    

// 실행
var rs = dfs_xy_conv("toLL","60","127");
console.log(rs.lat, rs.lng);

 

 

 

Android 

소스코드

public class MainActivity extends AppCompatActivity {

	public static int TO_GRID = 0;
	public static int TO_GPS = 1;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		LatXLngY tmp = convertGRID_GPS(TO_GRID, 37.579871128849334, 126.98935225645432);
		LatXLngY tmp2 = convertGRID_GPS(TO_GRID, 35.101148844565955, 129.02478725562108);
		LatXLngY tmp3 = convertGRID_GPS(TO_GRID, 33.500946412305076, 126.54663058817043);

		Log.e(">>", "x = " + tmp.x + ", y = " + tmp.y);
		Log.e(">>", "x = " + tmp2.x + ", y = " + tmp2.y);
		Log.e(">>", "x = " + tmp3.x + ", y = " + tmp3.y);
	}


	private LatXLngY convertGRID_GPS(int mode, double lat_X, double lng_Y) {
		double RE = 6371.00877; // 지구 반경(km)
		double GRID = 5.0; // 격자 간격(km)
		double SLAT1 = 30.0; // 투영 위도1(degree)
		double SLAT2 = 60.0; // 투영 위도2(degree)
		double OLON = 126.0; // 기준점 경도(degree)
		double OLAT = 38.0; // 기준점 위도(degree)
		double XO = 43; // 기준점 X좌표(GRID)
		double YO = 136; // 기1준점 Y좌표(GRID)

		//
		// LCC DFS 좌표변환 ( code : "TO_GRID"(위경도->좌표, lat_X:위도,  lng_Y:경도), "TO_GPS"(좌표->위경도,  lat_X:x, lng_Y:y) )
		//


		double DEGRAD = Math.PI / 180.0;
		double RADDEG = 180.0 / Math.PI;

		double re = RE / GRID;
		double slat1 = SLAT1 * DEGRAD;
		double slat2 = SLAT2 * DEGRAD;
		double olon = OLON * DEGRAD;
		double olat = OLAT * DEGRAD;

		double sn = Math.tan(Math.PI * 0.25 + slat2 * 0.5) / Math.tan(Math.PI * 0.25 + slat1 * 0.5);
		sn = Math.log(Math.cos(slat1) / Math.cos(slat2)) / Math.log(sn);
		double sf = Math.tan(Math.PI * 0.25 + slat1 * 0.5);
		sf = Math.pow(sf, sn) * Math.cos(slat1) / sn;
		double ro = Math.tan(Math.PI * 0.25 + olat * 0.5);
		ro = re * sf / Math.pow(ro, sn);
		LatXLngY rs = new LatXLngY();

		if (mode == TO_GRID) {
			rs.lat = lat_X;
			rs.lng = lng_Y;
			double ra = Math.tan(Math.PI * 0.25 + (lat_X) * DEGRAD * 0.5);
			ra = re * sf / Math.pow(ra, sn);
			double theta = lng_Y * DEGRAD - olon;
			if (theta > Math.PI) theta -= 2.0 * Math.PI;
			if (theta < -Math.PI) theta += 2.0 * Math.PI;
			theta *= sn;
			rs.x = Math.floor(ra * Math.sin(theta) + XO + 0.5);
			rs.y = Math.floor(ro - ra * Math.cos(theta) + YO + 0.5);
		} else {
			rs.x = lat_X;
			rs.y = lng_Y;
			double xn = lat_X - XO;
			double yn = ro - lng_Y + YO;
			double ra = Math.sqrt(xn * xn + yn * yn);
			if (sn < 0.0) {
				ra = -ra;
			}
			double alat = Math.pow((re * sf / ra), (1.0 / sn));
			alat = 2.0 * Math.atan(alat) - Math.PI * 0.5;

			double theta = 0.0;
			if (Math.abs(xn) <= 0.0) {
				theta = 0.0;
			} else {
				if (Math.abs(yn) <= 0.0) {
					theta = Math.PI * 0.5;
					if (xn < 0.0) {
						theta = -theta;
					}
				} else theta = Math.atan2(xn, yn);
			}
			double alon = theta / sn + olon;
			rs.lat = alat * RADDEG;
			rs.lng = alon * RADDEG;
		}
		return rs;
	}



	class LatXLngY {
		public double lat;
		public double lng;

		public double x;
		public double y;

	}
}

 

 

나머지 언어는 https://gist.github.com/fronteer-kr/14d7f779d52a21ac2f16 를 참고