o2o-site-AEO/solution/backend/common/utils/geo.py
김성경 01824a7a91 [feat] solution,admin,postgres-init: 주변정보를 업장 좌표 기준으로 — 시군구 캐시는 "가까운 곳"을 못 준다
지역 정보(맛집·관광지·축제)는 행정구역 코드(local_contents.region_code) 단위로 캐시돼
"그 시군구에 있는 것"을 줬다. 양양군 업장 옆 5km 속초 관광지는 빠지고 같은 군 반대편
30km 맛집이 붙는 구조라, 캔버스의 지역 정보 섹션은 늘 "준비 중"이었다. 업장 좌표로
TourAPI 를 직접 물어 업장 단위(place_contents)에 담고, 캔버스는 스크린샷으로 받은
형식(도보 시간 필터 + 카드 캐러셀)으로 통일했다.
2026-09-08 11:46:03 +09:00

25 lines
1.3 KiB
Python

"""좌표 거리 — 공용 한 벌.
★ 같은 하버사인 공식이 tour_lookup(500m 동일업소 판정)·itinerary(일정 반경)·tour_api(축제 20km 필터)
세 곳에 각각 복사돼 있었다(2026-09-08 정리). 지구 반지름·단위가 파일마다 달라지면 같은 두 점의
거리가 모듈마다 다르게 나온다 — 거리로 무엇을 넣고 뺄지 정하는 코드가 셋이라 한 벌이어야 한다.
국내 범위라 하버사인(구면 근사)이면 충분하다. 오차는 수 m 수준으로, 우리가 쓰는 판정
(500m 이내·5~20km 반경)에서 결과를 바꾸지 않는다.
"""
import math
EARTH_RADIUS_M = 6_371_000.0
def haversine_m(lat1: float, lng1: float, lat2: float, lng2: float) -> float:
"""두 좌표(위도, 경도) 사이의 거리(m). ★ 인자 순서는 (위도, 경도) — mapx/mapy 는 (경도, 위도)라 뒤집어 넣는다."""
p1, p2 = math.radians(lat1), math.radians(lat2)
dp, dl = math.radians(lat2 - lat1), math.radians(lng2 - lng1)
a = math.sin(dp / 2) ** 2 + math.cos(p1) * math.cos(p2) * math.sin(dl / 2) ** 2
return 2 * EARTH_RADIUS_M * math.asin(math.sqrt(a))
def haversine_km(lat1: float, lng1: float, lat2: float, lng2: float) -> float:
return haversine_m(lat1, lng1, lat2, lng2) / 1000.0