[문제 해결] - 현재 내 위치에서 얼마나 떨어져 있는지 거리 구하기

Donggu(oo)·2023년 5월 13일
0

[Solo Project] - saveme

목록 보기
3/5
post-thumbnail

1. 위도, 경도를 이용하여 거리 구하기


  • 개인 프로젝트 진행 중 현재 내 위치로부터 각 화장실들이 얼마나 떨어져 있는지 거리를 구해야 하는 문제가 발생했다. 그래서 찾아보던 중 GeoDataSource Logo라는 사이트에서 두 지점 사이의 거리를 구하는 예제 코드를 찾았다.

  • 아래의 코드를 간단히 살펴보면 파라미터로 myLat(내 위치의 위도), myLng(내 위치의 r경도), dataLat(데이터의 위도), dataLng(데이터의 경도), unit(거리 단위, km, mile) 5가지를 받는다.

  • 현재 내가 있는 위치의 위도, 경도와 비교할 데이터의 위도, 경도가 같다면 그 데이터의 장소에 있는 것이므로 0을 리턴하고, 아니라면 입력받은 거리 단위가 km인지 mile에 따라 거리를 구하게 된다.

export const getDistance = (
  myLat: number,
  myLng: number,
  dataLat: number,
  dataLng: number,
  unit: string
) => {
  if (myLat === dataLat && myLng === dataLng) {
    return 0;
  } else {
    const radlat1 = (Math.PI * myLat) / 180;
    const radlat2 = (Math.PI * dataLat) / 180;
    const theta = myLng - dataLng;
    const radtheta = (Math.PI * theta) / 180;
    let dist =
      Math.sin(radlat1) * Math.sin(radlat2) +
      Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
    if (dist > 1) {
      dist = 1;
    }
    dist = Math.acos(dist);
    dist = (dist * 180) / Math.PI;
    dist = dist * 60 * 1.1515;
    if (unit === "K") {
      dist = dist * 1.609344;
    }
    if (unit === "N") {
      dist = dist * 0.8684;
    }
    return dist;
  }
};

2. 나와 가장 가까운 거리 순으로 데이터 정렬하기


  • 서울시에서 제공하는 공중화장실 위치정보 데이터에는 나와의 거리가 얼마인지를 알 수 있는 프로퍼티가 없기 때문에 위에서 구한 각각의 데이터들과 나와의 거리를 추가해 주어야 한다.

  • 먼저 나의 현재 위치를 불러왔다면 데이터를 불러온다. 이때 5번으로 나누어서 호출하는 이유는 서울시 공공데이터가 한 번에 최대 1000개까지만 불러올 수 있기 때문에 나누어서 호출해 주었다.

  • 불러온 데이터들을 하나의 데이터로 병합하고, 각각의 데이터에 위에서 구한 현재 나와의 거리를 계산해서 프로퍼티를 추가해 준다.

import { useRecoilValue } from "recoil";
import { currentMyLocationAtom} from "../../Recoil/atom";

const useFetch = (
  rowOneApi: string,
  rowTwoApi: string,
  rowThreeApi: string,
  rowFourApi: string,
  rowFiveApi: string
) => {
  const [toiletLocationData, setToiletLocationData] = useState<ToiletData[]>([]);
  const currentMyLocation = useRecoilValue<CurrentMyLocation>(currentMyLocationAtom);

  useEffect(() => {
    const getData = async () => {
      try {
        if (currentMyLocation.lat !== 0 && currentMyLocation.lng !== 0) {
          const resOne = await PROXY_API.get(rowOneApi);
          const resTwo = await PROXY_API.get(rowTwoApi);
          const resThree = await PROXY_API.get(rowThreeApi);
          const resFour = await PROXY_API.get(rowFourApi);
          const resFive = await PROXY_API.get(rowFiveApi);
          const resDataOne = resOne.data.SearchPublicToiletPOIService.row;
          const resDataTwo = resTwo.data.SearchPublicToiletPOIService.row;
          const resDataThree = resThree.data.SearchPublicToiletPOIService.row;
          const resDataFour = resFour.data.SearchPublicToiletPOIService.row;
          const resDataFive = resFive.data.SearchPublicToiletPOIService.row;
          // 데이터 병합
          const combineData = [
            ...resDataOne,
            ...resDataTwo,
            ...resDataThree,
            ...resDataFour,
            ...resDataFive,
          ];
          // get 해온 화장실 위치 데이터에 현재 내 위치와의 거리 DISTANCE 프로퍼티 추가
          for (let i = 0; i < combineData.length; i++) {
            const distance = getDistance(
              currentMyLocation.lat,
              currentMyLocation.lng,
              combineData[i].Y_WGS84,
              combineData[i].X_WGS84,
              "K"
            );
            combineData[i].DISTANCE = distance;
          }
          setToiletLocationData(combineData);
        }
      } catch (err) {
        console.error(err);
      }
    };
    getData();
  }, [
    rowOneApi,
    rowTwoApi,
    rowThreeApi,
    rowFourApi,
    rowFiveApi,
    currentMyLocation,
    setToiletLocationData,
  ]);

  return toiletLocationData;
};

export default useFetch;

  • 이렇게 가공한 데이터를 거리를 기준으로 오름차순으로 정렬해 주면 현재 나와 제일 가까이 있는 화장실은 어느 곳인지 알 수 있게 된다.
// 내 현재 위치에서 거리가 가까운 순으로 정렬한 데이터
const sortedToiletData: ToiletData[] = [...mergeToiletData].sort(
  (a: any, b: any) => a.DISTANCE - b.DISTANCE
);
  • 원본 데이터의 순서

  • 구한 거리를 기준으로 오름차순으로 정렬한 데이터의 순서

0개의 댓글