compute_distance.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. import math as mt
  2. import numpy as np
  3. # Efficient calculating of distance(2-dim) matrix, use of symmetric and 0 in diagonals
  4. # nested sums, first does not contain the last element, second does not contain the first
  5. # Implemented Geo_graphic Coordsystem
  6. # https://www.movable-type.co.uk/scripts/latlong.html formula haversine
  7. # TODO General dimension
  8. def get_angle_in_rad(coordinate):
  9. return coordinate * mt.pi / 180
  10. def calc_haversine_angle(delta_lat, lat1, lat2, delta_long):
  11. return (
  12. mt.sin(delta_lat / 2) * mt.sin(delta_lat / 2)
  13. + mt.cos(lat1) * mt.cos(lat2) * mt.sin(delta_long / 2) * mt.sin(delta_long / 2)
  14. )
  15. def calc_haversine_distance_km(radius_earth_in_meter, haversine_angle):
  16. radius_km = radius_earth_in_meter / 1000
  17. return radius_km * 2 * mt.atan2(mt.sqrt(haversine_angle), mt.sqrt(1 - haversine_angle))
  18. def get_symmetric_distances_matrix(list_of_coordinates):
  19. radius_earth_in_meter = 6371000 # radius*pi/180
  20. matrix = np.zeros([len(list_of_coordinates), len(list_of_coordinates)])
  21. for rows in range(0, len(list_of_coordinates) - 1):
  22. for columns in range(rows + 1, len(list_of_coordinates)):
  23. lat1 = get_angle_in_rad(list_of_coordinates[rows][0])
  24. lat2 = get_angle_in_rad(list_of_coordinates[columns][0])
  25. lon1 = get_angle_in_rad(list_of_coordinates[rows][1])
  26. lon2 = get_angle_in_rad(list_of_coordinates[columns][1])
  27. distance = haversine_distance(lat1, lon1, lat2, lon2, radius_earth_in_meter)
  28. matrix[rows, columns] = distance
  29. matrix[columns, rows] = matrix[rows, columns]
  30. return matrix
  31. def haversine_distance(lat1, lon1, lat2, lon2, radius_earth_in_meter=6371000):
  32. """input in radiant, output in km"""
  33. for input_value in [lat1, lon1, lat2, lon2]:
  34. if abs(input_value) > 2 * mt.pi:
  35. raise ValueError(f"Input value is not in radiant. Values were {[lat1, lon1, lat2, lon2]}")
  36. delta_lat = lat2 - lat1
  37. delta_long = lon1 - lon2
  38. haversine_angle = calc_haversine_angle(delta_lat, lat1, lat2, delta_long)
  39. distance = calc_haversine_distance_km(radius_earth_in_meter, haversine_angle)
  40. return distance
  41. def haversine_distance_from_degrees(lat1, lon1, lat2, lon2, radius_earth_in_meter=6371000):
  42. return haversine_distance(
  43. np.deg2rad(lat1),
  44. np.deg2rad(lon1),
  45. np.deg2rad(lat2),
  46. np.deg2rad(lon2),
  47. radius_earth_in_meter
  48. )
  49. def get_row_of_distances(list_of_coordinates, start_coordinate):
  50. '''
  51. :param list_of_coordinates: list of coordinate tuple
  52. :param start_coordinate: tuple of latitude and longitude of a specific node
  53. :return:
  54. '''
  55. radius_earth_in_meter = 6371000 # radius*pi/180
  56. array = np.zeros([len(list_of_coordinates), 1])
  57. for rows in range(0, len(list_of_coordinates)):
  58. lat1 = get_angle_in_rad(list_of_coordinates[rows][0])
  59. lat2 = get_angle_in_rad(start_coordinate[0])
  60. lon1 = get_angle_in_rad(list_of_coordinates[rows][1])
  61. lon2 = get_angle_in_rad(start_coordinate[1])
  62. delta_lat = lat2 - lat1
  63. delta_long = lon1 - lon2
  64. haversine_angle = calc_haversine_angle(delta_lat, lat1, lat2, delta_long)
  65. distance = calc_haversine_distance_km(radius_earth_in_meter, haversine_angle)
  66. array[rows] = distance
  67. return array
  68. def geograpic_coord_to_cartesic(value):
  69. '''
  70. :param value: tuple latidude, longitude
  71. :return: tuple, x,y
  72. '''
  73. lat, lon = np.deg2rad(value[0]), np.deg2rad(value[1])
  74. radius_earth_in_km = 6371
  75. x = radius_earth_in_km * mt.cos(lat) * mt.cos(lon)
  76. y = radius_earth_in_km * mt.cos(lat) * mt.sin(lon)
  77. return (x, y)