Typescript : 지구 두 좌표 사이 거리 구하기

Typescript : 지구 두 좌표 사이 거리 구하기

라디안(Radian)

  • 각의 크기를 재는 SI 유도 단위로 기호는 rad 또는 c를 사용한다.
1 rad = 180 / π

Haversine 공식

  • Haversine 공식은, 구형 지구로 가정하고 주어지는 두 위도, 경도에 따라 거리를 구하는 공식입니다.
  • 지구 표면에서 최단거리를 구하는 것으로, 지구는 실제로 타원 모양이기 때문에 최대 0.3%의 오차가 존재한다고 합니다.
a = sin²(Δφ/2) + cos φ 1 ⋅ cos φ 2 ⋅ sin²(Δλ/2)
c = 2 ⋅ atan2( √ a , √ (1−a) )
d = R ⋅ c
// φ는 위도, λ는 경도, R은 지구의 반지름(평균 반지름 = 6,371km)
  • Haversine 공식 알고리즘 코드
/** 두 지점 위치의 거리 반환
  * @param point1 좌표 1
  * @param point2 좌표 2
  */
latLonToKm(point1: [number, number], point2: [number, number]) {
    // 두 좌표를 각각 위도와 경도 변수로 저장
    const lat1 = point1[1];
    const lon1 = point1[0];
    const lat2 = point2[1];
    const lon2 = point2[0];

    const R = 6371; // 지구의 반지름 길이 상수
    
    // 각 위도 및 경도 차이를 라디안 값으로 계산
    const dLat = this.toRadians(lat2 - lat1);
    const dLon = this.toRadians(lon2 - lon1);

    // 각 지점의 위도를 라디안 값으로 변환
    const radLat1 = this.toRadians(lat1);
    const radLat2 = this.toRadians(lat2);

    // Haversine 공식을 사용하여 두 지점 사이의 거리 계산
    const a =
                Math.sin(dLat / 2) * Math.sin(dLat / 2) + // sin²(Δφ/2)
                Math.sin(dLon / 2) * // cos φ1 ⋅ cos φ2 ⋅ sin²(Δλ/2)
                Math.sin(dLon / 2) *
                Math.cos(radLat1) *
                Math.cos(radLat2);
    const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); // 2 ⋅ atan2( √a, √(1−a) )

    // 거리 반환 (단위: 킬로미터)
    return R * c;
}

/** 각도를 라디안 값으로 반환 */
private toRadians(degrees: number) {
    return degrees * (Math.PI / 180);
}

구면 코사인 법칙(Spherical Law of Cosines)

  • 대부분의 컴퓨터 언어는 IEEE 754 64비트 부동 소수점 숫자를 사용하기 때문에, 소수점 15자리까지의 정밀도를 제공한다.
  • 구면 코사인 법칙을 함께 이용해 정밀한 거리 결과를 가져올 수 있지만, Haversine 공식보다는 약간 느린 성능을 갖는다고 합니다.
  • 또한 짧은 거리의 경우 아래 서술할 정방형 근사가 더 정확하다고 합니다.
d = acos( sin φ 1 ⋅ sin φ 2 + cos φ 1 ⋅ cos φ 2 ⋅ cos Δλ ) ⋅ R
  • 구면 코사인 법칙 알고리즘 코드
/** 두 지점 위치의 거리 반환
  * @param point1 좌표 1
  * @param point2 좌표 2
  */
latLonToKm(point1: [number, number], point2: [number, number]) {
    // 두 좌표를 각각 위도와 경도 변수로 저장
    const lat1 = point1[1];
    const lon1 = point1[0];
    const lat2 = point2[1];
    const lon2 = point2[0];

    const R = 6371; // 지구의 반지름 길이 상수
    
    // 경도 차이를 라디안 값으로 계산
    const dLon = this.toRadians(lon2 - lon1);

    // 각 지점의 위도를 라디안 값으로 변환
    const radLat1 = this.toRadians(lat1);
    const radLat2 = this.toRadians(lat2);

    // 구면 코사인 법칙을 이용한 거리 반환 (단위: 킬로미터)
    return Math.acos(
                    Math.sin(radLat1) * Math.sin(radLat2) + // sin φ 1 ⋅ sin φ 2
                    Math.cos(radLat1) * // cos φ 1 ⋅ cos φ 2 ⋅ cos Δλ
                    Math.cos(radLat2) *
                    Math.cos(dLon)
                ) * R;
}

/** 각도를 라디안 값으로 반환 */
private toRadians(degrees: number) {
    return degrees * (Math.PI / 180);
}

정방형 근사(Spherical Law of Cosines)

  • 정확도보다 성능이 중요한 상황이라면, 짧은 거리에 한하여 피타고라스 법칙을 사용한 정방형 근사를 사용할 수 있습니다.
  • 거리가 길어질 수록 오차값이 커집니다.
x = Δλ ⋅ cos φ m
y = Δφ
d = R ⋅ √x² + y²
  • 정방형 근사 알고리즘 코드
/** 두 지점 위치의 거리 반환
  * @param point1 좌표 1
  * @param point2 좌표 2
  */
latLonToKm(point1: [number, number], point2: [number, number]) {
    // 두 좌표를 각각 위도와 경도 변수로 저장
    const lat1 = point1[1];
    const lon1 = point1[0];
    const lat2 = point2[1];
    const lon2 = point2[0];

    const R = 6371; // 지구의 반지름 길이 상수
    
    // 정방형 근사를 이용한 거리 반환 (단위: 킬로미터)
    const x = (lon2 - lon1) * Math.cos((lat1 + lat2) / 2);
    const y = (lat2 - lat1);
    return Math.sqrt(x * x + y * y) * R
}

참고 자료

이 글이 도움이 되었나요?

신고하기
0분 전
작성된 댓글이 없습니다. 첫 댓글을 달아보세요!
    댓글을 작성하려면 로그인이 필요합니다.