import numpy as np

def haversine_distance(lat1, lon1, lat2, lon2):
    R = 6371000
    lat1_rad = np.radians(lat1)
    lat2_rad = np.radians(lat2)
    delta_lat = np.radians(lat2 - lat1)
    delta_lon = np.radians(lon2 - lon1)
    a = np.sin(delta_lat/2)**2 + np.cos(lat1_rad) * np.cos(lat2_rad) * np.sin(delta_lon/2)**2
    c = 2 * np.arcsin(np.sqrt(a))
    return R * c

def haversine_km(lon1, lat1, lon2, lat2):
    lon1, lat1, lon2, lat2 = map(np.radians, [lon1, lat1, lon2, lat2])
    dlon = lon2 - lon1
    dlat = lat2 - lat1
    a = np.sin(dlat/2.0)**2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon/2.0)**2
    c = 2 * np.arcsin(np.sqrt(a))
    km = 6371 * c
    return km

def create_circle_points(center_lat, center_lon, radius_m, num_points=50):
    R = 6371000
    lats, lons = [], []
    for i in range(num_points + 1):
        bearing = 2 * np.pi * i / num_points
        lat1_rad = np.radians(center_lat)
        lon1_rad = np.radians(center_lon)
        angular_distance = radius_m / R
        lat2_rad = np.arcsin(
            np.sin(lat1_rad) * np.cos(angular_distance) +
            np.cos(lat1_rad) * np.sin(angular_distance) * np.cos(bearing)
        )
        lon2_rad = lon1_rad + np.arctan2(
            np.sin(bearing) * np.sin(angular_distance) * np.cos(lat1_rad),
            np.cos(angular_distance) - np.sin(lat1_rad) * np.sin(lat2_rad)
        )
        lats.append(np.degrees(lat2_rad))
        lons.append(np.degrees(lon2_rad))
    return lats, lons

def haversine_distance_vectorized(lat0, lon0, lats, lons):
    R = 6371000.0
    lat0r = np.radians(lat0)
    lon0r = np.radians(lon0)
    latr = np.radians(lats)
    lonr = np.radians(lons)
    dlat = latr - lat0r
    dlon = lonr - lon0r
    a = np.sin(dlat/2.0)**2 + np.cos(lat0r) * np.cos(latr) * np.sin(dlon/2.0)**2
    return 2.0 * R * np.arcsin(np.sqrt(a))
