개인 프로젝트 진행 중 현재 내 위치로부터 각 화장실들이 얼마나 떨어져 있는지 거리를 구해야 하는 문제가 발생했다. 그래서 찾아보던 중 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;
}
};
서울시에서 제공하는 공중화장실 위치정보 데이터에는 나와의 거리가 얼마인지를 알 수 있는 프로퍼티가 없기 때문에 위에서 구한 각각의 데이터들과 나와의 거리를 추가해 주어야 한다.
먼저 나의 현재 위치를 불러왔다면 데이터를 불러온다. 이때 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
);