Переделал страницу с ObjItem. Теперь работает корректно.

This commit is contained in:
2025-11-13 14:21:02 +03:00
parent 50498166e5
commit d0a53e251e
8 changed files with 204 additions and 358 deletions

View File

@@ -10,7 +10,7 @@ from django.db.models import F
# Third-party imports
import pandas as pd
from geographiclib.geodesic import Geodesic
# Local imports
from mapsapp.models import Transponders
@@ -40,6 +40,7 @@ MAX_ITEMS_PER_PAGE = 10000
DEFAULT_NUMERIC_VALUE = -1.0
MINIMUM_BANDWIDTH_MHZ = 0.08
RANGE_DISTANCE = 56
def get_all_constants():
sats = [sat.name for sat in Satellite.objects.all()]
@@ -160,15 +161,9 @@ def fill_data_from_df(df: pd.DataFrame, sat: Satellite, current_user=None):
# Вычислить расстояние от координаты до coords_average
current_avg = (source.coords_average.x, source.coords_average.y)
distance = calculate_distance_degrees(current_avg, current_coord)
# Если расстояние <= 0.5 градуса
if distance <= 0.5:
# Вычислить новое среднее ИНКРЕМЕНТАЛЬНО
new_avg = calculate_average_coords_incremental(
current_avg, current_coord
)
new_avg, distance = calculate_mean_coords(current_avg, current_coord)
if distance <= RANGE_DISTANCE:
# Обновить coords_average в Source
source.coords_average = Point(new_avg, srid=4326)
source.save()
@@ -255,7 +250,6 @@ def _create_objitem_from_row(row, sat, source, user_to_use, consts):
comment = row["Комментарий"]
source_name = row["Объект наблюдения"]
# Создаем Geo объект (БЕЗ coords_kupsat и coords_valid)
geo, _ = Geo.objects.get_or_create(
timestamp=timestamp,
coords=geo_point,
@@ -469,7 +463,7 @@ def get_points_from_csv(file_content, current_user=None):
for source in existing_sources:
source_coord = (source.coords_average.x, source.coords_average.y)
distance = calculate_distance_degrees(source_coord, current_coord)
new_avg, distance = calculate_mean_coords(source_coord, current_coord)
if distance < min_distance:
min_distance = distance
@@ -479,7 +473,7 @@ def get_points_from_csv(file_content, current_user=None):
if closest_source and min_distance <= 0.5:
# Обновить coords_average инкрементально
current_avg = (closest_source.coords_average.x, closest_source.coords_average.y)
new_avg = calculate_average_coords_incremental(current_avg, current_coord)
# new_avg = calculate_average_coords_incremental(current_avg, current_coord)
closest_source.coords_average = Point(new_avg, srid=4326)
closest_source.save()
@@ -507,7 +501,7 @@ def get_points_from_csv(file_content, current_user=None):
return new_sources_count
def _is_duplicate_objitem(coord_tuple, frequency, freq_range, tolerance=0.001):
def _is_duplicate_objitem(coord_tuple, frequency, freq_range, tolerance=0.1):
"""
Проверяет, существует ли уже ObjItem с такими же координатами и частотой.
@@ -515,7 +509,7 @@ def _is_duplicate_objitem(coord_tuple, frequency, freq_range, tolerance=0.001):
coord_tuple: кортеж (lon, lat) координат
frequency: частота в МГц
freq_range: полоса частот в МГц
tolerance: допуск для сравнения координат в градусах (по умолчанию 0.001 ≈ 100м)
tolerance: допуск для сравнения координат в километрах
Returns:
bool: True если дубликат найден, False иначе
@@ -531,7 +525,7 @@ def _is_duplicate_objitem(coord_tuple, frequency, freq_range, tolerance=0.001):
# Проверяем расстояние между координатами
geo_coord = (objitem.geo_obj.coords.x, objitem.geo_obj.coords.y)
distance = calculate_distance_degrees(coord_tuple, geo_coord)
_, distance = calculate_mean_coords(coord_tuple, geo_coord)
if distance <= tolerance:
# Координаты совпадают, проверяем частоту
@@ -873,40 +867,24 @@ def kub_report(data_in: io.StringIO) -> pd.DataFrame:
# ============================================================================
def calculate_distance_degrees(coord1: tuple, coord2: tuple) -> float:
def calculate_mean_coords(coord1: tuple, coord2: tuple) -> tuple[tuple, float]:
"""
Вычисляет расстояние между двумя координатами в градусах.
Использует простую евклидову метрику для малых расстояний.
Подходит для определения близости точек в радиусе до нескольких градусов.
Args:
coord1 (tuple): Первая координата в формате (longitude, latitude)
coord2 (tuple): Вторая координата в формате (longitude, latitude)
Returns:
float: Расстояние в градусах
Example:
>>> dist = calculate_distance_degrees((37.62, 55.75), (37.63, 55.76))
>>> print(f"{dist:.4f}") # ~0.0141 градусов
0.0141
>>> dist = calculate_distance_degrees((37.62, 55.75), (37.62, 55.75))
>>> print(dist) # Одинаковые координаты
0.0
Вычисляет среднюю точку между двумя координатами с использованием геодезических вычислений (с учётом эллипсоида).
: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
# Простая евклидова метрика для малых расстояний
# Для более точных расчетов на больших расстояниях можно использовать формулу гаверсинуса
delta_lon = lon2 - lon1
delta_lat = lat2 - lat1
distance = (delta_lon**2 + delta_lat**2) ** 0.5
return distance
def calculate_average_coords_incremental(