Skip to content

Instantly share code, notes, and snippets.

@fronteer-kr
Last active April 12, 2024 18:42
Show Gist options
  • Star 80 You must be signed in to star a gist
  • Fork 16 You must be signed in to fork a gist
  • Save fronteer-kr/14d7f779d52a21ac2f16 to your computer and use it in GitHub Desktop.
Save fronteer-kr/14d7f779d52a21ac2f16 to your computer and use it in GitHub Desktop.
// 소스출처 : http://www.kma.go.kr/weather/forecast/digital_forecast.jsp 내부에 있음
// 기상청에서 이걸 왜 공식적으로 공개하지 않을까?
//
// (사용 예)
// var rs = dfs_xy_conv("toLL","60","127");
// console.log(rs.lat, rs.lng);
//
<script language="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;
}
//-->
</script>
@khjde1207
Copy link

khjde1207 commented Oct 18, 2021

flutter 용 공유해 볼께요. static 으로 만들었는데. 상황에 따라 변경해서 써야 할 수도 있어요.

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

결과 :
I/flutter (27910): {x: 60, y: 127, lat: 37.61574148576467, lng: 126.98991183668376}
I/flutter (27910): {lat: 37.579871128849334, lng: 126.98935225645432, x: 60, y: 127}

import 'dart:math' as Math;

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;
  }
}


@koprodev
Copy link

koprodev commented May 23, 2022

// PHP 버전입니다.
// 위 [khjde1207]님의 flutter 버전을 참고했습니다.
// 결과

  $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 )

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;
	}
  }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment