두 좌표 간의 거리를 구하라는 task가 떨어졌습니다.

어떻게 계산하면 좋을까요?


저는 처음에 피타고라스의 정리를 이용하면 될 것 같았어요.

피타고라스의 정리에 대한 이미지 검색결과

a^{2}+b^{2}=c^{2}\,


이 그림 어때요? 오랜만이죠??



그런데, 지구 상의 두 좌표의 거리를 구하기 위해서는 Haversine formula를 적용해야 할 필요가 있습니다.

왜냐하면 지구는 평면이 아니기 때문입니다.


그 공식은 아래와 같습니다.



코딩해 보죠...

자 그럼 먼저...



으음...




하아...


찾아봅시다... :)



function getDistanceFromLatLonInKm(lat1,lon1,lat2,lon2) {
  var R = 6371; // Radius of the earth in km
  var dLat = deg2rad(lat2-lat1);  // deg2rad below
  var dLon = deg2rad(lon2-lon1); 
  var a = 
    Math.sin(dLat/2) * Math.sin(dLat/2) +
    Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * 
    Math.sin(dLon/2) * Math.sin(dLon/2)
    ; 
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
  var d = R * c; // Distance in km
  return d;
}

function deg2rad(deg) {
  return deg * (Math.PI/180)
}

Stack overflow를 보니 Chunck라는 친구가 javascript function을 작성해서 공유해 주었습니다.

친절하게 단위도 km네요. 저는 mile을 써야 하는데 ㅋ


그리고 Salvador Dali라는 친구가 코드를 최적화 해 줬습니다.

처리 속도가 2배 빠르다고 합니다.


function distance(lat1, lon1, lat2, lon2) {
  var p = 0.017453292519943295;    // Math.PI / 180
  var c = Math.cos;
  var a = 0.5 - c((lat2 - lat1) * p)/2 + 
          c(lat1 * p) * c(lat2 * p) * 
          (1 - c((lon2 - lon1) * p))/2;

  return 12742 * Math.asin(Math.sqrt(a)); // 2 * R; R = 6371 km
}

이렇게요.

최종 반환 값에 mile 변환을 위한 상수 0.621371를 곱하면 원하는 mile단위의 거리를 가져올 수 있겠네요.



결과를 검증해 보겠습니다.



google map에서 사무실 근처의 좌표를 가져왔습니다.

좌표는 각각 37.4137701, 127.1284930 / 37.4073826, 127.1338793이구요.

직선 거리는 약 853.75m가 나왔습니다.




jsFiddle에서 해당 function을 테스트해 보았습니다. (#)

좌표를 넣고 계산한 값을 console로 출력했습니다. km/mile 단위로


그 결과는 아래와 같습니다.

distance 0.854860114404647 km

distance 0.5311852841477299 mile


853.75 | 854.86 약 1km 거리에서 약 1m 정도 차이가 나네요.

허용 가능한 오차 수준이라고 우겨봅니다.



References

https://en.wikipedia.org/wiki/Haversine_formula

https://stackoverflow.com/questions/27928/calculate-distance-between-two-latitude-longitude-points-haversine-formula

https://jsfiddle.net/n5d7tgez/

'Javascript' 카테고리의 다른 글

Ionic 2 Unit test  (0) 2017.07.31
Implement base controller  (0) 2017.07.26
Service workers.  (0) 2017.07.06
npm lite-server  (0) 2017.07.06

Data를 migration하는 것은 그리 유쾌한 작업이 아닙니다.

데이터를 분석하고 변환하여 옮기는 과정에 수차례의 실패를 각오해야 하는 신중한 작업이기 때문이죠. (사실 재미도 없습니다.)


많은 시스템에 자체적으로 제공한는 Import기능이 있지만,
저는 Excel을 이용하여 SQL구문을 만들고 이를 이용하여 데이터를 등록하는 방법을 선호합니다.


그 이유 중 하나는 실제 SQL구문을 실행한 뒤 에러가 발생했을 때, 이를 추적하기 쉽기 때문입니다.

또한, 추가적인 데이터를 등록할 때 재활용할 수 있는 점도 있습니다.



아래는 Oracle에 Insert할 때 사용했던 실제의 예제입니다.

=IF(L2="","NULL",CONCATENATE("TO_DATE('",TEXT(L2, "YYYY-MM-DD HH:mm:ss"),"','YYYY-MM-DD HH24:mi:ss')"))
=CONCATENATE(AL2," VALUES ('",A2,"','",B2,"','",C2,"','",D2,"');")


첫 번째 라인은 date 값을 column에 등록하기 위한 구문으로 변경하기 위해서 사용합니다.

두 번째 라인은 여러 cell의 값을 조합하여 실제 insert 구문을 만들기 위해서 사용합니다.


Datetime의 가공

Oracel의 경우 TO_DATE function으로 형변환이 필요합니다.

nullable column인 경우를 고려하여 값의 유무에 따른 분기처리가 또한 필요합니다.

Excel에서 date 값의 cell을 참조할 때 기본적으로 숫자로 취급하므로 이에 대한 방지 코드가 필요합니다.


IF

=IF({condition},{true case},{false case})

if function은 조건에 따른 분기 처리를 지원함. 위의 L2="", L2 cell이 empty인 경우를 의미하며 equal character가 하나인 것에 주의가 필요합니다.

TEXT

=TEXT({text},{format})

값의 포맷을 변경. 위의 TEXT(L2, "YYYY-MM-DD HH:mm:ss"), L2 값을 ToString() 처리합니다.


위 예의 결과는

TO_DATE('1980-06-26 00:00:00','YYYY-MM-DD HH24:mi:ss') 또는 NULL 이 됩니다.


Insert 구문의 작성

주로 INSERT ({columns}) VALUES ({values}); 구문의 {values} 쪽을 동적으로 작성하게 됩니다.


CONCATENATE

인자들을 combine하는 함수

=CONCATENATE(AL2," VALUES ('",A2,"','",B2,"','",C2,"','",D2,"');")

다만, 인자의 개수 및 길이에 제한이 있으므로 주의.

AL2는 static한 INSERT 구문이 있고 A2:D2까지의 값을 작은 따옴표로 감싸서 열거하였습니다.



※ H社의 Push 간 실제 작업에 활용한 결과물은 공용 drive에서 확인하세요.

'Database > Common' 카테고리의 다른 글

DA와 DBA의 업무 영역  (3) 2017.09.19

오랜만에 ADO.Net을 쓰려다 보니까, SqlConnection, SqlCommand 이런 녀석들의 사용 방법이 헷갈리더라구요... ㅡ.ㅡ

하여, Google 다음가는 우리의 친구 Stack overflow의 도움을 받았습니다.

SQL에 parameter 넘길 필요가 있어 해당 keyword로 검색하여 보니.. 아래와 같은 재미있는 4컷 만화가 :-)


enter image description here





그리고... 거기 달린 댓글...


References

https://stackoverflow.com/questions/7505808/why-do-we-always-prefer-using-parameters-in-sql-statements


+ Recent posts