""" Map related views for displaying objects on maps. """ from collections import defaultdict from django.contrib.admin.views.decorators import staff_member_required from django.contrib.auth.mixins import LoginRequiredMixin from django.http import JsonResponse from django.shortcuts import redirect, render from django.utils.decorators import method_decorator from django.views import View from ..clusters import get_clusters from ..mixins import RoleRequiredMixin from ..models import ObjItem @method_decorator(staff_member_required, name="dispatch") class ShowMapView(RoleRequiredMixin, View): """View for displaying objects on map (admin interface).""" required_roles = ["admin", "moderator"] def get(self, request): ids = request.GET.get("ids", "") points = [] if ids: id_list = [int(x) for x in ids.split(",") if x.isdigit()] locations = ObjItem.objects.filter(id__in=id_list).select_related( "parameter_obj", "parameter_obj__id_satellite", "parameter_obj__polarization", "parameter_obj__modulation", "parameter_obj__standard", "geo_obj", ) for obj in locations: if ( not hasattr(obj, "geo_obj") or not obj.geo_obj or not obj.geo_obj.coords ): continue param = getattr(obj, "parameter_obj", None) if not param: continue points.append( { "name": f"{obj.name}", "freq": f"{param.frequency} [{param.freq_range}] МГц", "point": (obj.geo_obj.coords.x, obj.geo_obj.coords.y), } ) else: return redirect("admin") grouped = defaultdict(list) for p in points: grouped[p["name"]].append({"point": p["point"], "frequency": p["freq"]}) groups = [ {"name": name, "points": coords_list} for name, coords_list in grouped.items() ] context = { "groups": groups, } return render(request, "admin/map_custom.html", context) class ShowSelectedObjectsMapView(LoginRequiredMixin, View): """View for displaying selected objects on map.""" def get(self, request): ids = request.GET.get("ids", "") points = [] if ids: id_list = [int(x) for x in ids.split(",") if x.isdigit()] locations = ObjItem.objects.filter(id__in=id_list).select_related( "parameter_obj", "parameter_obj__id_satellite", "parameter_obj__polarization", "parameter_obj__modulation", "parameter_obj__standard", "geo_obj", ) for obj in locations: if ( not hasattr(obj, "geo_obj") or not obj.geo_obj or not obj.geo_obj.coords ): continue param = getattr(obj, "parameter_obj", None) if not param: continue points.append( { "name": f"{obj.name}", "freq": f"{param.frequency} [{param.freq_range}] МГц", "point": (obj.geo_obj.coords.x, obj.geo_obj.coords.y), } ) else: return redirect("mainapp:objitem_list") # Group points by object name grouped = defaultdict(list) for p in points: grouped[p["name"]].append({"point": p["point"], "frequency": p["freq"]}) groups = [ {"name": name, "points": coords_list} for name, coords_list in grouped.items() ] context = { "groups": groups, } return render(request, "mainapp/objitem_map.html", context) class ShowSourcesMapView(LoginRequiredMixin, View): """View for displaying selected sources on map.""" def get(self, request): from ..models import Source ids = request.GET.get("ids", "") groups = [] if ids: id_list = [int(x) for x in ids.split(",") if x.isdigit()] sources = Source.objects.filter(id__in=id_list) # Define coordinate types with their labels and colors coord_types = [ ("coords_average", "Усредненные координаты", "blue"), ("coords_kupsat", "Координаты Кубсата", "orange"), ("coords_valid", "Координаты оперативников", "green"), ("coords_reference", "Координаты справочные", "violet"), ] # Group points by coordinate type for coord_field, label, color in coord_types: points = [] for source in sources: coords = getattr(source, coord_field) if coords: # coords is a Point object with x (longitude) and y (latitude) points.append( { "point": (coords.x, coords.y), # (lon, lat) "source_id": f"Источник #{source.id}", } ) if points: groups.append( { "name": label, "points": points, "color": color, } ) else: return redirect("mainapp:home") context = { "groups": groups, } return render(request, "mainapp/source_map.html", context) class ShowSourceWithPointsMapView(LoginRequiredMixin, View): """View for displaying a single source with all its related ObjItem points.""" def get(self, request, source_id): from ..models import Source try: source = Source.objects.prefetch_related( "source_objitems", "source_objitems__parameter_obj", "source_objitems__geo_obj", ).get(id=source_id) except Source.DoesNotExist: return redirect("mainapp:home") groups = [] # Цвета для разных типов координат источника source_coord_types = [ ("coords_average", "Усредненные координаты", "blue"), ("coords_kupsat", "Координаты Кубсата", "orange"), ("coords_valid", "Координаты оперативников", "green"), ("coords_reference", "Координаты справочные", "violet"), ] # Добавляем координаты источника for coord_field, label, color in source_coord_types: coords = getattr(source, coord_field) if coords: groups.append( { "name": label, "points": [ { "point": (coords.x, coords.y), "source_id": f"Источник #{source.id}", } ], "color": color, } ) # Добавляем все точки ГЛ одной группой gl_points = source.source_objitems.select_related( "parameter_obj", "geo_obj" ).all() # Собираем все точки ГЛ в одну группу all_gl_points = [] for obj in gl_points: if ( not hasattr(obj, "geo_obj") or not obj.geo_obj or not obj.geo_obj.coords ): continue param = getattr(obj, "parameter_obj", None) if not param: continue all_gl_points.append( { "point": (obj.geo_obj.coords.x, obj.geo_obj.coords.y), "name": obj.name, "frequency": f"{param.frequency} [{param.freq_range}] МГц", } ) # Добавляем все точки ГЛ одним цветом (красный) if all_gl_points: groups.append( {"name": "Точки ГЛ", "points": all_gl_points, "color": "red"} ) context = { "groups": groups, "source_id": source_id, } return render(request, "mainapp/source_with_points_map.html", context) class ClusterTestView(LoginRequiredMixin, View): """Test view for clustering functionality.""" def get(self, request): objs = ObjItem.objects.filter( name__icontains="! Astra 4A 12654,040 [1,962] МГц H" ) coords = [] for obj in objs: if hasattr(obj, "geo_obj") and obj.geo_obj and obj.geo_obj.coords: coords.append( (obj.geo_obj.coords.coords[1], obj.geo_obj.coords.coords[0]) ) get_clusters(coords) return JsonResponse({"success": "ок"})