diff --git a/qt_ui/widgets/map/mapmodel.py b/qt_ui/widgets/map/mapmodel.py index b08a0260..536e78bf 100644 --- a/qt_ui/widgets/map/mapmodel.py +++ b/qt_ui/widgets/map/mapmodel.py @@ -2,7 +2,7 @@ from __future__ import annotations import logging from datetime import timedelta -from typing import List, Optional, Tuple, Union +from typing import List, Optional, Tuple, Union, Iterator from PySide2.QtCore import Property, QObject, Signal, Slot from dcs import Point @@ -696,6 +696,32 @@ class MapZonesJs(QObject): ) +class UnculledZone(QObject): + positionChanged = Signal() + radiusChanged = Signal() + + def __init__(self, position: LeafletLatLon, radius: float) -> None: + super().__init__() + self._position = position + self._radius = radius + + @Property(list, notify=positionChanged) + def position(self) -> LeafletLatLon: + return self._position + + @Property(float, notify=radiusChanged) + def radius(self) -> float: + return self._radius + + @classmethod + def each_from_game(cls, game: Game) -> Iterator[UnculledZone]: + for zone in game.get_culling_zones(): + ll = game.theater.point_to_ll(zone) + yield UnculledZone( + [ll.latitude, ll.longitude], game.settings.perf_culling_distance * 1000 + ) + + class MapModel(QObject): cleared = Signal() @@ -708,6 +734,7 @@ class MapModel(QObject): threatZonesChanged = Signal() navmeshesChanged = Signal() mapZonesChanged = Signal() + unculledZonesChanged = Signal() def __init__(self, game_model: GameModel) -> None: super().__init__() @@ -723,6 +750,7 @@ class MapModel(QObject): ) self._navmeshes = NavMeshJs([], []) self._map_zones = MapZonesJs([], [], []) + self._unculled_zones = [] self._selected_flight_index: Optional[Tuple[int, int]] = None GameUpdateSignal.get_instance().game_loaded.connect(self.on_game_load) GameUpdateSignal.get_instance().flight_paths_changed.connect(self.reset_atos) @@ -745,6 +773,7 @@ class MapModel(QObject): ) self._navmeshes = NavMeshJs([], []) self._map_zones = MapZonesJs([], [], []) + self._unculled_zones = [] self.cleared.emit() def set_package_selection(self, index: int) -> None: @@ -791,6 +820,7 @@ class MapModel(QObject): self.reset_threat_zones() self.reset_navmeshes() self.reset_map_zones() + self.reset_unculled_zones() def on_game_load(self, game: Optional[Game]) -> None: if game is not None: @@ -945,6 +975,14 @@ class MapModel(QObject): def mapZones(self) -> NavMeshJs: return self._map_zones + def reset_unculled_zones(self) -> None: + self._unculled_zones = list(UnculledZone.each_from_game(self.game)) + self.unculledZonesChanged.emit() + + @Property(list, notify=unculledZonesChanged) + def unculledZones(self) -> list[UnculledZone]: + return self._unculled_zones + @property def game(self) -> Game: if self.game_model.game is None: diff --git a/resources/ui/map/map.js b/resources/ui/map/map.js index 57b0aeed..ce721eea 100644 --- a/resources/ui/map/map.js +++ b/resources/ui/map/map.js @@ -182,6 +182,7 @@ const redNavmesh = L.layerGroup(); const inclusionZones = L.layerGroup(); const exclusionZones = L.layerGroup(); const seaZones = L.layerGroup(); +const unculledZones = L.layerGroup(); // Main map controls. These are the ones that we expect users to interact with. // These are always open, which unfortunately means that the scroll bar will not @@ -245,7 +246,7 @@ L.control "Air Defenses": redAirDefenseThreatZones, "Radar SAMs": redRadarSamThreatZones, }, - "Navmeshes": { + Navmeshes: { Hide: L.layerGroup().addTo(map), Blue: blueNavmesh, Red: redNavmesh, @@ -254,7 +255,8 @@ L.control "Inclusion zones": inclusionZones, "Exclusion zones": exclusionZones, "Sea zones": seaZones, - } + "Culling exclusion zones": unculledZones, + }, }, { position: "topleft", @@ -278,6 +280,7 @@ new QWebChannel(qt.webChannelTransport, function (channel) { game.threatZonesChanged.connect(drawThreatZones); game.navmeshesChanged.connect(drawNavmeshes); game.mapZonesChanged.connect(drawMapZones); + game.unculledZonesChanged.connect(drawUnculledZones); }); function recenterMap(center) { @@ -900,7 +903,7 @@ function drawNavmeshes() { } function drawMapZones() { - seaZones.clearLayers() + seaZones.clearLayers(); inclusionZones.clearLayers(); exclusionZones.clearLayers(); @@ -929,6 +932,21 @@ function drawMapZones() { } } +function drawUnculledZones() { + unculledZones.clearLayers(); + + for (const zone of game.unculledZones) { + console.log( + `Drawing unculled zone with radius ${zone.radius} at ${zone.position}` + ); + L.circle(zone.position, { + radius: zone.radius, + color: "#b4ff8c", + stroke: false, + }).addTo(unculledZones); + } +} + function drawInitialMap() { recenterMap(game.mapCenter); drawControlPoints(); @@ -939,6 +957,7 @@ function drawInitialMap() { drawThreatZones(); drawNavmeshes(); drawMapZones(); + drawUnculledZones(); } function clearAllLayers() {