Programming/Java

Java 위도 경도에 따른 거리 계산(내 주변 반경)

Jan92 2022. 8. 3. 22:44
반응형

위도 경도에 따른 거리 계산

위도 경도에 따른 거리 계산 및 내 주변 일정 거리 이내에 있는 대상들을 판단하기 위해 작업된 코드 및 내용을 정리한 것입니다.

먼저 위도와 경도의 정의에 대해서 간단하게 살펴본 뒤 코드를 이어서 보겠습니다.

 

(코드만 필요하신 분들은 윗부분은 살짝 스킵하셔도 될 것 같습니다.)

 

 


 

 

위도(latitude), 경도(longitude)

'위도'는 적도를 기준으로 북위(N), 남위(S)로 나뉘며, 각각 0° ~ 90°로 표현합니다. 같은 위도를 연결한 가로선을 위선이라고 합니다.

'경도'는 영국의 그리니치 천문대를 기준(0°)으로 하여 동쪽과 서쪽을 각각 180°로 표현합니다. 같은 경도를 연결한 세로선을 경선이라고 합니다.

우리나라의 위도와 경도 기준점은 경기도 수원에 있는 국토지리정보원이며, 이곳의 위도와 경도는 북위 37°, 동경 127°입니다.

(한반도의 위도, 경도 범위는 북위 33° ~ 43° / 동경 124° ~ 132°입니다.)

 

계산에 사용되는 단위는 hddd.ddddd° 형식을 사용할 것인데요. 구글맵에서 출력되는 위도와 경도의 값이 도단위이기 때문입니다.

해당 형식은 '도'포맷이라고도 하며, 도(°) 단위 정수 이하를 소수로 표현한 것입니다. 소수 여섯째 자리에서 반올림하여 소수 다섯째 자리까지 표기합니다.

 

* h : 반구(Hemisphere) / d : 도(Degree)

 

 

***

위도, 경도에서 중요한 부분은 위도 1° 당 거리는 일정하지만, 경도 1° 당 거리는 일정하지 않다는 점인데요.

이유는 적도를 기준으로 하여 위아래로 이동할 경우 원주가 감소하기 때문에 경도 1° 간의 거리가 더 짧아지기 때문입니다.

(경도에 따른 거리를 근사치를 사용하여 계산하는 경우도 있습니다.)

 

//위도 1° = 지구 반지름 x 1° x 1rad(라디안)
6371 * 1 * (Math.PI / 180);

//경도 1° = 지구 반지름 x 1° x cos(위도) x 1rad(라디안)
6371 * 1 * (Math.PI / 180) * Math.cos(Math.toRadians(35.8448));

(해당 예시는 지구 반지름을 6,371km로 가정, 위도를 35.8448°로 가정한 예시입니다.)

 

 


 

 

거리 계산 및 내 주변 반경 지점 확인

//두 지점 간의 거리 계산
public static double getDistance(double lat1, double lon1, double lat2, double lon2) {
  double dLat = Math.toRadians(lat2 - lat1);
  double dLon = Math.toRadians(lon2 - lon1);

  double a = Math.sin(dLat/2)* Math.sin(dLat/2)+ Math.cos(Math.toRadians(lat1))* Math.cos(Math.toRadians(lat2))* Math.sin(dLon/2)* Math.sin(dLon/2);
  double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
  double d =EARTH_RADIUS* c * 1000;    // Distance in m
  return d;
}

(먼저 두 지점 간의 거리 계산 코드입니다. 결과의 단위는 m입니다.)

 

두 지점 간의 거리를 계산할 때는 주어진 두 좌표만으로 계산을 할 수 있습니다. 하지만 현재 기준 좌표 외 여러 개의 좌표와 거리가 주어지고, 기준 좌표에서 해당 거리 이내에 속하는 좌표들을 구하라고 했을 때는 계산할 것들이 조금 더 생기는데요. 

 

 

기준 좌표에서 거리 내에 속하는 좌표 구하기

public List<Shop>aroundShopList(Input input) {
  //현재 위도 좌표 (y 좌표)
  double nowLatitude = input.getLatitude();
  //현재 경도 좌표 (x 좌표)
  double nowLongitude = input.getLongitude();
  
  //m당 y 좌표 이동 값
  double mForLatitude =(1 /(EARTH_RADIUS* 1 *(Math.PI/ 180)))/ 1000;
  //m당 x 좌표 이동 값
  double mForLongitude =(1 /(EARTH_RADIUS* 1 *(Math.PI/ 180)* Math.cos(Math.toRadians(nowLatitude))))/ 1000;

  //현재 위치 기준 검색 거리 좌표
  double maxY = nowLatitude +(input.getDistance()* mForLatitude);
  double minY = nowLatitude -(input.getDistance()* mForLatitude);
  double maxX = nowLongitude +(input.getDistance()* mForLongitude);
  double minX = nowLongitude -(input.getDistance()* mForLongitude);

  //해당되는 좌표의 범위 안에 있는 가맹점
  List<AroundShopRes>tempAroundShopList = shopRepository.getAroundShopList(maxY, maxX, minY, minX);
  List<AroundShopRes>resultAroundShopList = new ArrayList<>();

  //정확한 거리 측정
  for(AroundShopRes aroundShop : tempAroundShopList) {
    double distance = Helper.getDistance(nowLatitude, nowLongitude, aroundShop.getLatitude(), aroundShop.getLongitude());
    if(distance < input.getDistance()) {
      resultAroundShopList.add(aroundShop);
    }
  }
  return resultAroundShopList;
}

(Input 객체에는 현재 기준이 되는 위도, 경도 그리고 주변 반경이 되는 거리를 받습니다.)

 

현재 위치를 기준해서 일정 반경 안에 있는 좌표들을 확인하기 위한 방법으로 먼저 위도와 경도의 최댓값과 최솟값 좌표를 구합니다.

그리고 해당 범위에 속하는 좌표들을 먼저 조회하는데요.

이렇게 되면 정사각형 기준의 범위 안에 있는 좌표들이 모두 포함되기 때문에, 기준 거리보다 더 먼 좌표들도 함께 포함되게 됩니다.

때문에 여기서 현재 좌표 기준 각각의 좌표들의 거리를 계산하여 기준에 포함되는 좌표들만을 걸러주는 과정을 한번 더 거치게 됩니다.

 

(더 좋은 방법이 분명 있을 것 같은데, 혹시 수정된다면 해당 내용을 추가로 업로드하도록 하겠습니다.)

 

 

 

 

< 참고 자료 >

 

[기상학] 지도에서 위도 1도 & 경도 1도는 몇 km 일까?

안녕하세요 서울기상센터, KS서울날씨청입니다. 이번 시간에는 궁금했지만 막상 어떻게 구하는지에 대해...

blog.naver.com

반응형