"""좌표 거리 — 공용 한 벌. ★ 같은 하버사인 공식이 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