""" Скрипт для исправления ObjItems без связи с Source. Для каждого ObjItem без source: 1. Получить координаты из geo_obj 2. Найти ближайший Source (по coords_average) 3. Если расстояние <= 0.5 градуса, связать ObjItem с этим Source 4. Иначе создать новый Source с coords_average = координаты geo_obj """ # import os # import django # os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dbapp.settings") # django.setup() # from mainapp.models import ObjItem, Source, CustomUser # from django.contrib.gis.geos import Point # from django.contrib.gis.measure import D # from django.contrib.gis.db.models.functions import Distance # def calculate_distance_degrees(coord1, coord2): # """Вычисляет расстояние между двумя координатами в градусах.""" # import math # lon1, lat1 = coord1 # lon2, lat2 = coord2 # return math.sqrt((lon2 - lon1) ** 2 + (lat2 - lat1) ** 2) # def fix_objitems_without_source(): # """Исправляет ObjItems без связи с Source.""" # # Получаем пользователя по умолчанию # default_user = CustomUser.objects.get(id=1) # # Получаем все ObjItems без source # objitems_without_source = ObjItem.objects.filter(source__isnull=True) # total_count = objitems_without_source.count() # print(f"Найдено {total_count} ObjItems без source") # if total_count == 0: # print("Нечего исправлять!") # return # fixed_count = 0 # new_sources_count = 0 # for objitem in objitems_without_source: # # Проверяем, есть ли geo_obj # if not hasattr(objitem, 'geo_obj') or not objitem.geo_obj or not objitem.geo_obj.coords: # print(f"ObjItem {objitem.id} не имеет geo_obj или координат, пропускаем") # continue # geo_coords = objitem.geo_obj.coords # coord_tuple = (geo_coords.x, geo_coords.y) # # Ищем ближайший Source # sources_with_coords = Source.objects.filter(coords_average__isnull=False) # closest_source = None # min_distance = float('inf') # for source in sources_with_coords: # source_coord = (source.coords_average.x, source.coords_average.y) # distance = calculate_distance_degrees(coord_tuple, source_coord) # if distance < min_distance: # min_distance = distance # closest_source = source # # Если нашли близкий Source (расстояние <= 0.5 градуса) # if closest_source and min_distance <= 0.5: # objitem.source = closest_source # objitem.save() # print(f"ObjItem {objitem.id} связан с Source {closest_source.id} (расстояние: {min_distance:.4f}°)") # fixed_count += 1 # else: # # Создаем новый Source # new_source = Source.objects.create( # coords_average=Point(coord_tuple, srid=4326), # created_by=default_user # ) # objitem.source = new_source # objitem.save() # print(f"ObjItem {objitem.id} связан с новым Source {new_source.id}") # fixed_count += 1 # new_sources_count += 1 # print(f"\nГотово!") # print(f"Исправлено ObjItems: {fixed_count}") # print(f"Создано новых Source: {new_sources_count}") # if __name__ == "__main__": # fix_objitems_without_source() from geographiclib.geodesic import Geodesic def calculate_mean_coords(coord1: tuple, coord2: tuple) -> tuple[tuple, float]: """ Вычисляет среднюю точку между двумя координатами с использованием геодезических вычислений (с учётом эллипсоида). :param lat1: Широта первой точки в градусах. :param lon1: Долгота первой точки в градусах. :param lat2: Широта второй точки в градусах. :param lon2: Долгота второй точки в градусах. :return: Словарь с ключами 'lat' и 'lon' для средней точки, и расстояние(dist) в КМ. """ lon1, lat1 = coord1 lon2, lat2 = coord2 geod_inv = Geodesic.WGS84.Inverse(lat1, lon1, lat2, lon2) azimuth1 = geod_inv['azi1'] distance = geod_inv['s12'] geod_direct = Geodesic.WGS84.Direct(lat1, lon1, azimuth1, distance / 2) return (geod_direct['lon2'], geod_direct['lat2']), distance/1000 # Пример использования lat1, lon1 = 56.15465080269812, 38.140518028837285 lat2, lon2 = 56.0852, 38.0852 midpoint = calculate_mean_coords((lat1, lon1), (lat2, lon2)) #56.15465080269812, 38.140518028837285 print(f"Средняя точка: {midpoint[0]}") print(f"Расстояние: {midpoint[1]} км")