Source code for powersimdata.utility.distance

from math import acos, asin, cos, degrees, radians, sin, sqrt


[docs]def haversine(point1, point2): """Given two lat/long pairs, return distance in miles. :param tuple point1: first point, (lat, long) in degrees. :param tuple point2: second point, (lat, long) in degrees. :return: (*float*) -- distance in miles. """ _AVG_EARTH_RADIUS_MILES = 3958.7613 # noqa: N806 # unpack latitude/longitude lat1, lng1 = point1 lat2, lng2 = point2 # convert all latitudes/longitudes from decimal degrees to radians lat1, lng1, lat2, lng2 = map(radians, (lat1, lng1, lat2, lng2)) # calculate haversine lat = lat2 - lat1 lng = lng2 - lng1 d = ( 2 * _AVG_EARTH_RADIUS_MILES * asin(sqrt(sin(lat * 0.5) ** 2 + cos(lat1) * cos(lat2) * sin(lng * 0.5) ** 2)) ) return d
[docs]def great_circle_distance(x): """Calculates distance between two sites. :param pandas.dataFrame x: start and end point coordinates of branches. :return: (*float*) -- length of branch (in km.). """ mi_to_km = 1.60934 return haversine((x.from_lat, x.from_lon), (x.to_lat, x.to_lon)) * mi_to_km
[docs]def ll2uv(lon, lat): """Convert (longitude, latitude) to unit vector. :param float lon: longitude of the site (in deg.) measured eastward from Greenwich, UK. :param float lat: latitude of the site (in deg.). Equator is the zero point. :return: (*list*) -- 3-components (x,y,z) unit vector. """ cos_lat = cos(radians(lat)) sin_lat = sin(radians(lat)) cos_lon = cos(radians(lon)) sin_lon = sin(radians(lon)) uv = [cos_lat * cos_lon, cos_lat * sin_lon, sin_lat] return uv
[docs]def angular_distance(uv1, uv2): """Calculate the angular distance between two vectors. :param list uv1: 3-components vector as returned by :func:`ll2uv`. :param list uv2: 3-components vector as returned by :func:`ll2uv`. :return: (*float*) -- angle (in degrees). """ cos_angle = uv1[0] * uv2[0] + uv1[1] * uv2[1] + uv1[2] * uv2[2] if cos_angle >= 1: cos_angle = 1 if cos_angle <= -1: cos_angle = -1 angle = degrees(acos(cos_angle)) return angle
[docs]def find_closest_neighbor(point, neighbors): """Locates the closest neighbor. :param tuple point: (lon, lat) in degrees. :param list neighbors: each element of the list are the (lon, lat) of potential neighbor. :return: (*int*) -- id of the closest neighbor """ uv_point = ll2uv(point[0], point[1]) id_neighbor = None angle_min = float("inf") for i, n in enumerate(neighbors): angle = angular_distance(uv_point, ll2uv(n[0], n[1])) if angle < angle_min: id_neighbor = i angle_min = angle return id_neighbor