mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Add threat zone drawing for the new map.
https://github.com/dcs-liberation/dcs_liberation/issues/1097
This commit is contained in:
parent
5e68dbe1ca
commit
eae0d6be94
@ -2,13 +2,13 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from typing import List, Optional, Tuple
|
from typing import List, Optional, Tuple, Union
|
||||||
|
|
||||||
from PySide2.QtCore import Property, QObject, Signal, Slot
|
from PySide2.QtCore import Property, QObject, Signal, Slot
|
||||||
from dcs import Point
|
from dcs import Point
|
||||||
from dcs.unit import Unit
|
from dcs.unit import Unit
|
||||||
from dcs.vehicles import vehicle_map
|
from dcs.vehicles import vehicle_map
|
||||||
from shapely.geometry import LineString, Point as ShapelyPoint, Polygon
|
from shapely.geometry import LineString, Point as ShapelyPoint, Polygon, MultiPolygon
|
||||||
|
|
||||||
from game import Game, db
|
from game import Game, db
|
||||||
from game.factions.faction import Faction
|
from game.factions.faction import Faction
|
||||||
@ -19,9 +19,8 @@ from game.theater import (
|
|||||||
TheaterGroundObject,
|
TheaterGroundObject,
|
||||||
FrontLine,
|
FrontLine,
|
||||||
LatLon,
|
LatLon,
|
||||||
Airfield,
|
|
||||||
Carrier,
|
|
||||||
)
|
)
|
||||||
|
from game.threatzones import ThreatZones
|
||||||
from game.transfers import MultiGroupTransport, TransportMap
|
from game.transfers import MultiGroupTransport, TransportMap
|
||||||
from game.utils import meters, nautical_miles
|
from game.utils import meters, nautical_miles
|
||||||
from gen.ato import AirTaskingOrder
|
from gen.ato import AirTaskingOrder
|
||||||
@ -519,7 +518,7 @@ class FlightJs(QObject):
|
|||||||
return self._selected
|
return self._selected
|
||||||
|
|
||||||
@Property(list, notify=commitBoundaryChanged)
|
@Property(list, notify=commitBoundaryChanged)
|
||||||
def commitBoundary(self) -> Optional[List[LeafletLatLon]]:
|
def commitBoundary(self) -> List[LeafletLatLon]:
|
||||||
if not isinstance(self.flight.flight_plan, PatrollingFlightPlan):
|
if not isinstance(self.flight.flight_plan, PatrollingFlightPlan):
|
||||||
return []
|
return []
|
||||||
start = self.flight.flight_plan.patrol_start
|
start = self.flight.flight_plan.patrol_start
|
||||||
@ -535,6 +534,75 @@ class FlightJs(QObject):
|
|||||||
return shapely_poly_to_leaflet_points(bubble, self.theater)
|
return shapely_poly_to_leaflet_points(bubble, self.theater)
|
||||||
|
|
||||||
|
|
||||||
|
class ThreatZonesJs(QObject):
|
||||||
|
fullChanged = Signal()
|
||||||
|
aircraftChanged = Signal()
|
||||||
|
airDefensesChanged = Signal()
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
full: List[List[LeafletLatLon]],
|
||||||
|
aircraft: List[List[LeafletLatLon]],
|
||||||
|
air_defenses: List[List[LeafletLatLon]],
|
||||||
|
) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self._full = full
|
||||||
|
self._aircraft = aircraft
|
||||||
|
self._air_defenses = air_defenses
|
||||||
|
|
||||||
|
@Property(list, notify=fullChanged)
|
||||||
|
def full(self) -> List[List[LeafletLatLon]]:
|
||||||
|
return self._full
|
||||||
|
|
||||||
|
@Property(list, notify=aircraftChanged)
|
||||||
|
def aircraft(self) -> List[List[LeafletLatLon]]:
|
||||||
|
return self._aircraft
|
||||||
|
|
||||||
|
@Property(list, notify=airDefensesChanged)
|
||||||
|
def airDefenses(self) -> List[List[LeafletLatLon]]:
|
||||||
|
return self._air_defenses
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def polys_to_leaflet(
|
||||||
|
poly: Union[Polygon, MultiPolygon], theater: ConflictTheater
|
||||||
|
) -> List[List[LeafletLatLon]]:
|
||||||
|
if isinstance(poly, MultiPolygon):
|
||||||
|
polys = poly.geoms
|
||||||
|
else:
|
||||||
|
polys = [poly]
|
||||||
|
return [shapely_poly_to_leaflet_points(poly, theater) for poly in polys]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_zones(cls, zones: ThreatZones, theater: ConflictTheater) -> ThreatZonesJs:
|
||||||
|
return ThreatZonesJs(
|
||||||
|
cls.polys_to_leaflet(zones.all, theater),
|
||||||
|
cls.polys_to_leaflet(zones.airbases, theater),
|
||||||
|
cls.polys_to_leaflet(zones.air_defenses, theater),
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def empty(cls) -> ThreatZonesJs:
|
||||||
|
return ThreatZonesJs([], [], [])
|
||||||
|
|
||||||
|
|
||||||
|
class ThreatZoneContainerJs(QObject):
|
||||||
|
blueChanged = Signal()
|
||||||
|
redChanged = Signal()
|
||||||
|
|
||||||
|
def __init__(self, blue: ThreatZonesJs, red: ThreatZonesJs) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self._blue = blue
|
||||||
|
self._red = red
|
||||||
|
|
||||||
|
@Property(ThreatZonesJs, notify=blueChanged)
|
||||||
|
def blue(self) -> ThreatZonesJs:
|
||||||
|
return self._blue
|
||||||
|
|
||||||
|
@Property(ThreatZonesJs, notify=redChanged)
|
||||||
|
def red(self) -> ThreatZonesJs:
|
||||||
|
return self._red
|
||||||
|
|
||||||
|
|
||||||
class MapModel(QObject):
|
class MapModel(QObject):
|
||||||
cleared = Signal()
|
cleared = Signal()
|
||||||
|
|
||||||
@ -544,6 +612,7 @@ class MapModel(QObject):
|
|||||||
supplyRoutesChanged = Signal()
|
supplyRoutesChanged = Signal()
|
||||||
flightsChanged = Signal()
|
flightsChanged = Signal()
|
||||||
frontLinesChanged = Signal()
|
frontLinesChanged = Signal()
|
||||||
|
threatZonesChanged = Signal()
|
||||||
|
|
||||||
def __init__(self, game_model: GameModel) -> None:
|
def __init__(self, game_model: GameModel) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@ -554,6 +623,9 @@ class MapModel(QObject):
|
|||||||
self._supply_routes = []
|
self._supply_routes = []
|
||||||
self._flights = []
|
self._flights = []
|
||||||
self._front_lines = []
|
self._front_lines = []
|
||||||
|
self._threat_zones = ThreatZoneContainerJs(
|
||||||
|
ThreatZonesJs.empty(), ThreatZonesJs.empty()
|
||||||
|
)
|
||||||
self._selected_flight_index: Optional[Tuple[int, int]] = None
|
self._selected_flight_index: Optional[Tuple[int, int]] = None
|
||||||
GameUpdateSignal.get_instance().game_loaded.connect(self.on_game_load)
|
GameUpdateSignal.get_instance().game_loaded.connect(self.on_game_load)
|
||||||
GameUpdateSignal.get_instance().flight_paths_changed.connect(self.reset_atos)
|
GameUpdateSignal.get_instance().flight_paths_changed.connect(self.reset_atos)
|
||||||
@ -571,6 +643,9 @@ class MapModel(QObject):
|
|||||||
self._ground_objects = []
|
self._ground_objects = []
|
||||||
self._flights = []
|
self._flights = []
|
||||||
self._front_lines = []
|
self._front_lines = []
|
||||||
|
self._threat_zones = ThreatZoneContainerJs(
|
||||||
|
ThreatZonesJs.empty(), ThreatZonesJs.empty()
|
||||||
|
)
|
||||||
self.cleared.emit()
|
self.cleared.emit()
|
||||||
|
|
||||||
def set_package_selection(self, index: int) -> None:
|
def set_package_selection(self, index: int) -> None:
|
||||||
@ -614,6 +689,7 @@ class MapModel(QObject):
|
|||||||
self.reset_routes()
|
self.reset_routes()
|
||||||
self.reset_atos()
|
self.reset_atos()
|
||||||
self.reset_front_lines()
|
self.reset_front_lines()
|
||||||
|
self.reset_threat_zones()
|
||||||
|
|
||||||
def on_game_load(self, game: Optional[Game]) -> None:
|
def on_game_load(self, game: Optional[Game]) -> None:
|
||||||
if game is not None:
|
if game is not None:
|
||||||
@ -737,6 +813,21 @@ class MapModel(QObject):
|
|||||||
def frontLines(self) -> List[FrontLineJs]:
|
def frontLines(self) -> List[FrontLineJs]:
|
||||||
return self._front_lines
|
return self._front_lines
|
||||||
|
|
||||||
|
def reset_threat_zones(self) -> None:
|
||||||
|
self._threat_zones = ThreatZoneContainerJs(
|
||||||
|
ThreatZonesJs.from_zones(
|
||||||
|
self.game.threat_zone_for(player=True), self.game.theater
|
||||||
|
),
|
||||||
|
ThreatZonesJs.from_zones(
|
||||||
|
self.game.threat_zone_for(player=False), self.game.theater
|
||||||
|
),
|
||||||
|
)
|
||||||
|
self.threatZonesChanged.emit()
|
||||||
|
|
||||||
|
@Property(ThreatZoneContainerJs, notify=threatZonesChanged)
|
||||||
|
def threatZones(self) -> ThreatZoneContainerJs:
|
||||||
|
return self._threat_zones
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def game(self) -> Game:
|
def game(self) -> Game:
|
||||||
if self.game_model.game is None:
|
if self.game_model.game is None:
|
||||||
|
|||||||
@ -1,15 +1,3 @@
|
|||||||
/*
|
|
||||||
* TODO:
|
|
||||||
*
|
|
||||||
* - Culling
|
|
||||||
* - Threat zones
|
|
||||||
* - Navmeshes
|
|
||||||
* - Time of day/weather themeing
|
|
||||||
* - Exclusion zones
|
|
||||||
* - "Actual" front line
|
|
||||||
* - Debug flight plan drawing
|
|
||||||
*/
|
|
||||||
|
|
||||||
const Colors = Object.freeze({
|
const Colors = Object.freeze({
|
||||||
Blue: "#0084ff",
|
Blue: "#0084ff",
|
||||||
Red: "#c85050",
|
Red: "#c85050",
|
||||||
@ -172,6 +160,14 @@ const redFlightPlansLayer = L.layerGroup();
|
|||||||
const selectedFlightPlansLayer = L.layerGroup();
|
const selectedFlightPlansLayer = L.layerGroup();
|
||||||
const allFlightPlansLayer = L.layerGroup();
|
const allFlightPlansLayer = L.layerGroup();
|
||||||
|
|
||||||
|
const blueFullThreatZones = L.layerGroup();
|
||||||
|
const blueAircraftThreatZones = L.layerGroup();
|
||||||
|
const blueAirDefenseThreatZones = L.layerGroup();
|
||||||
|
|
||||||
|
const redFullThreatZones = L.layerGroup();
|
||||||
|
const redAircraftThreatZones = L.layerGroup();
|
||||||
|
const redAirDefenseThreatZones = L.layerGroup();
|
||||||
|
|
||||||
L.control
|
L.control
|
||||||
.groupedLayers(
|
.groupedLayers(
|
||||||
baseLayers,
|
baseLayers,
|
||||||
@ -197,8 +193,27 @@ L.control
|
|||||||
"Show all red": redFlightPlansLayer,
|
"Show all red": redFlightPlansLayer,
|
||||||
"Show all": allFlightPlansLayer,
|
"Show all": allFlightPlansLayer,
|
||||||
},
|
},
|
||||||
|
"Blue Threat Zones": {
|
||||||
|
Hide: L.layerGroup().addTo(map),
|
||||||
|
Full: blueFullThreatZones,
|
||||||
|
Aircraft: blueAircraftThreatZones,
|
||||||
|
"Air Defenses": blueAirDefenseThreatZones,
|
||||||
},
|
},
|
||||||
{ collapsed: false, exclusiveGroups: ["Flight Plans"] }
|
"Red Threat Zones": {
|
||||||
|
Hide: L.layerGroup().addTo(map),
|
||||||
|
Full: redFullThreatZones,
|
||||||
|
Aircraft: redAircraftThreatZones,
|
||||||
|
"Air Defenses": redAirDefenseThreatZones,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
collapsed: false,
|
||||||
|
exclusiveGroups: [
|
||||||
|
"Flight Plans",
|
||||||
|
"Blue Threat Zones",
|
||||||
|
"Red Threat Zones",
|
||||||
|
],
|
||||||
|
}
|
||||||
)
|
)
|
||||||
.addTo(map);
|
.addTo(map);
|
||||||
|
|
||||||
@ -213,6 +228,7 @@ new QWebChannel(qt.webChannelTransport, function (channel) {
|
|||||||
game.supplyRoutesChanged.connect(drawSupplyRoutes);
|
game.supplyRoutesChanged.connect(drawSupplyRoutes);
|
||||||
game.frontLinesChanged.connect(drawFrontLines);
|
game.frontLinesChanged.connect(drawFrontLines);
|
||||||
game.flightsChanged.connect(drawFlightPlans);
|
game.flightsChanged.connect(drawFlightPlans);
|
||||||
|
game.threatZonesChanged.connect(drawThreatZones);
|
||||||
});
|
});
|
||||||
|
|
||||||
function recenterMap(center) {
|
function recenterMap(center) {
|
||||||
@ -702,6 +718,52 @@ function drawFlightPlans() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _drawThreatZones(zones, layer, player) {
|
||||||
|
const color = player ? Colors.Blue : Colors.Red;
|
||||||
|
for (const zone of zones) {
|
||||||
|
L.polyline(zone, {
|
||||||
|
color: color,
|
||||||
|
weight: 1,
|
||||||
|
fill: true,
|
||||||
|
fillOpacity: 0.4,
|
||||||
|
noClip: true,
|
||||||
|
}).addTo(layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawThreatZones() {
|
||||||
|
blueFullThreatZones.clearLayers();
|
||||||
|
blueAircraftThreatZones.clearLayers();
|
||||||
|
blueAirDefenseThreatZones.clearLayers();
|
||||||
|
redFullThreatZones.clearLayers();
|
||||||
|
redAircraftThreatZones.clearLayers();
|
||||||
|
redAirDefenseThreatZones.clearLayers();
|
||||||
|
|
||||||
|
_drawThreatZones(game.threatZones.blue.full, blueFullThreatZones, true);
|
||||||
|
_drawThreatZones(
|
||||||
|
game.threatZones.blue.aircraft,
|
||||||
|
blueAircraftThreatZones,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
_drawThreatZones(
|
||||||
|
game.threatZones.blue.airDefenses,
|
||||||
|
blueAirDefenseThreatZones,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
_drawThreatZones(game.threatZones.red.full, redFullThreatZones, false);
|
||||||
|
_drawThreatZones(
|
||||||
|
game.threatZones.red.aircraft,
|
||||||
|
redAircraftThreatZones,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
_drawThreatZones(
|
||||||
|
game.threatZones.red.airDefenses,
|
||||||
|
redAirDefenseThreatZones,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function drawInitialMap() {
|
function drawInitialMap() {
|
||||||
recenterMap(game.mapCenter);
|
recenterMap(game.mapCenter);
|
||||||
drawControlPoints();
|
drawControlPoints();
|
||||||
@ -709,6 +771,7 @@ function drawInitialMap() {
|
|||||||
drawSupplyRoutes();
|
drawSupplyRoutes();
|
||||||
drawFrontLines();
|
drawFrontLines();
|
||||||
drawFlightPlans();
|
drawFlightPlans();
|
||||||
|
drawThreatZones();
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearAllLayers() {
|
function clearAllLayers() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user