mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Convert front line segments to proper class.
Needed so we can add context menus to the lines.
This commit is contained in:
parent
2a5b37b9ad
commit
2b06d8a096
@ -4,7 +4,7 @@ import datetime
|
|||||||
import logging
|
import logging
|
||||||
import math
|
import math
|
||||||
from functools import singledispatchmethod
|
from functools import singledispatchmethod
|
||||||
from typing import Iterable, Iterator, List, Optional, Set, Tuple
|
from typing import Iterable, Iterator, List, Optional, Tuple
|
||||||
|
|
||||||
from PySide2 import QtCore, QtWidgets
|
from PySide2 import QtCore, QtWidgets
|
||||||
from PySide2.QtCore import QLineF, QPointF, QRectF, Qt
|
from PySide2.QtCore import QLineF, QPointF, QRectF, Qt
|
||||||
@ -26,8 +26,8 @@ from PySide2.QtWidgets import (
|
|||||||
QGraphicsView,
|
QGraphicsView,
|
||||||
)
|
)
|
||||||
from dcs import Point
|
from dcs import Point
|
||||||
from dcs.planes import F_16C_50
|
|
||||||
from dcs.mapping import point_from_heading
|
from dcs.mapping import point_from_heading
|
||||||
|
from dcs.planes import F_16C_50
|
||||||
from dcs.unitgroup import Group
|
from dcs.unitgroup import Group
|
||||||
from shapely.geometry import (
|
from shapely.geometry import (
|
||||||
LineString,
|
LineString,
|
||||||
@ -44,6 +44,7 @@ from game.theater.conflicttheater import FrontLine, ReferencePoint
|
|||||||
from game.theater.theatergroundobject import (
|
from game.theater.theatergroundobject import (
|
||||||
TheaterGroundObject,
|
TheaterGroundObject,
|
||||||
)
|
)
|
||||||
|
from game.transfers import RoadTransferOrder
|
||||||
from game.utils import Distance, meters, nautical_miles
|
from game.utils import Distance, meters, nautical_miles
|
||||||
from game.weather import TimeOfDay
|
from game.weather import TimeOfDay
|
||||||
from gen import Conflict, Package
|
from gen import Conflict, Package
|
||||||
@ -66,6 +67,7 @@ from qt_ui.widgets.map.QFrontLine import QFrontLine
|
|||||||
from qt_ui.widgets.map.QLiberationScene import QLiberationScene
|
from qt_ui.widgets.map.QLiberationScene import QLiberationScene
|
||||||
from qt_ui.widgets.map.QMapControlPoint import QMapControlPoint
|
from qt_ui.widgets.map.QMapControlPoint import QMapControlPoint
|
||||||
from qt_ui.widgets.map.QMapGroundObject import QMapGroundObject
|
from qt_ui.widgets.map.QMapGroundObject import QMapGroundObject
|
||||||
|
from qt_ui.widgets.map.SupplyRouteSegment import SupplyRouteSegment
|
||||||
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
|
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
|
||||||
|
|
||||||
MAX_SHIP_DISTANCE = nautical_miles(80)
|
MAX_SHIP_DISTANCE = nautical_miles(80)
|
||||||
@ -824,9 +826,8 @@ class QLiberationMap(QGraphicsView):
|
|||||||
def draw_bezier_frontline(
|
def draw_bezier_frontline(
|
||||||
self,
|
self,
|
||||||
scene: QGraphicsScene,
|
scene: QGraphicsScene,
|
||||||
pen: QPen,
|
|
||||||
frontline: FrontLine,
|
frontline: FrontLine,
|
||||||
convoy_size: int = 0,
|
convoys: List[RoadTransferOrder],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Thanks to Alquimista for sharing a python implementation of the bezier algorithm this is adapted from.
|
Thanks to Alquimista for sharing a python implementation of the bezier algorithm this is adapted from.
|
||||||
@ -841,18 +842,17 @@ class QLiberationMap(QGraphicsView):
|
|||||||
for point in bezier_curve_range(
|
for point in bezier_curve_range(
|
||||||
int(len(bezier_fixed_points) * 2), bezier_fixed_points
|
int(len(bezier_fixed_points) * 2), bezier_fixed_points
|
||||||
):
|
):
|
||||||
line = scene.addLine(
|
scene.addItem(
|
||||||
old_point[0], old_point[1], point[0], point[1], pen=pen
|
SupplyRouteSegment(
|
||||||
)
|
old_point[0],
|
||||||
if convoy_size:
|
old_point[1],
|
||||||
units = "units" if convoy_size > 1 else "unit"
|
point[0],
|
||||||
tooltip = (
|
point[1],
|
||||||
f"{convoy_size} {units} transferring between "
|
frontline.control_point_a,
|
||||||
f"{frontline.control_point_a} and {frontline.control_point_b}."
|
frontline.control_point_b,
|
||||||
|
convoys,
|
||||||
)
|
)
|
||||||
else:
|
)
|
||||||
tooltip = "No convoys present on this supply route."
|
|
||||||
line.setToolTip(tooltip)
|
|
||||||
old_point = point
|
old_point = point
|
||||||
|
|
||||||
def draw_supply_routes(self) -> None:
|
def draw_supply_routes(self) -> None:
|
||||||
@ -865,19 +865,21 @@ class QLiberationMap(QGraphicsView):
|
|||||||
if DisplayOptions.lines:
|
if DisplayOptions.lines:
|
||||||
self.draw_supply_route_between(cp, connected)
|
self.draw_supply_route_between(cp, connected)
|
||||||
|
|
||||||
def _count_units_tranferring_between(self, a: ControlPoint, b: ControlPoint) -> int:
|
def _transfers_between(
|
||||||
|
self, a: ControlPoint, b: ControlPoint
|
||||||
|
) -> List[RoadTransferOrder]:
|
||||||
# We attempt to short circuit the expensive shortest path computation for the
|
# We attempt to short circuit the expensive shortest path computation for the
|
||||||
# cases where there is never a transfer, but caching might be needed.
|
# cases where there is never a transfer, but caching might be needed.
|
||||||
|
|
||||||
if a.captured != b.captured:
|
if a.captured != b.captured:
|
||||||
# Cannot transfer to enemy CPs.
|
# Cannot transfer to enemy CPs.
|
||||||
return 0
|
return []
|
||||||
|
|
||||||
# This is only called for drawing lines between nodes and have rules out routes
|
# This is only called for drawing lines between nodes and have rules out routes
|
||||||
# to enemy bases, so a and b are guaranteed to be in the same supply route.
|
# to enemy bases, so a and b are guaranteed to be in the same supply route.
|
||||||
supply_route = SupplyRoute.for_control_point(a)
|
supply_route = SupplyRoute.for_control_point(a)
|
||||||
|
|
||||||
count = 0
|
transfers = []
|
||||||
points = {a, b}
|
points = {a, b}
|
||||||
for transfer in self.game.transfers:
|
for transfer in self.game.transfers:
|
||||||
# No possible route from our network to this transfer.
|
# No possible route from our network to this transfer.
|
||||||
@ -887,55 +889,32 @@ class QLiberationMap(QGraphicsView):
|
|||||||
# Anything left is a transfer within our supply route.
|
# Anything left is a transfer within our supply route.
|
||||||
transfer_points = {transfer.position, transfer.next_stop()}
|
transfer_points = {transfer.position, transfer.next_stop()}
|
||||||
if points == transfer_points:
|
if points == transfer_points:
|
||||||
count += sum(transfer.units.values())
|
transfers.append(transfer)
|
||||||
return count
|
return transfers
|
||||||
|
|
||||||
def supply_route_color(self, a: ControlPoint, b: ControlPoint) -> QColor:
|
|
||||||
if a.front_is_active(b):
|
|
||||||
return CONST.COLORS["red"]
|
|
||||||
elif a.captured:
|
|
||||||
return CONST.COLORS["dark_" + self.game.get_player_color()]
|
|
||||||
else:
|
|
||||||
return CONST.COLORS["dark_" + self.game.get_enemy_color()]
|
|
||||||
|
|
||||||
def supply_route_style(
|
|
||||||
self, a: ControlPoint, b: ControlPoint, has_transfer: bool
|
|
||||||
) -> Qt.PenStyle:
|
|
||||||
if a.front_is_active(b) or has_transfer:
|
|
||||||
return Qt.PenStyle.SolidLine
|
|
||||||
return Qt.PenStyle.DotLine
|
|
||||||
|
|
||||||
def supply_route_pen(
|
|
||||||
self, a: ControlPoint, b: ControlPoint, has_transfer: bool
|
|
||||||
) -> QPen:
|
|
||||||
color = self.supply_route_color(a, b)
|
|
||||||
pen = QPen(brush=color)
|
|
||||||
pen.setColor(color)
|
|
||||||
pen.setStyle(self.supply_route_style(a, b, has_transfer))
|
|
||||||
pen.setWidth(6)
|
|
||||||
return pen
|
|
||||||
|
|
||||||
def draw_supply_route_between(self, a: ControlPoint, b: ControlPoint) -> None:
|
def draw_supply_route_between(self, a: ControlPoint, b: ControlPoint) -> None:
|
||||||
scene = self.scene()
|
scene = self.scene()
|
||||||
|
|
||||||
convoy_size = self._count_units_tranferring_between(a, b)
|
convoys = self._transfers_between(a, b)
|
||||||
pen = self.supply_route_pen(a, b, convoy_size > 0)
|
|
||||||
frontline = FrontLine(a, b, self.game.theater)
|
frontline = FrontLine(a, b, self.game.theater)
|
||||||
if a.front_is_active(b):
|
if a.front_is_active(b):
|
||||||
if DisplayOptions.actual_frontline_pos:
|
if DisplayOptions.actual_frontline_pos:
|
||||||
self.draw_actual_frontline(frontline, scene, pen)
|
self.draw_actual_frontline(scene, frontline, convoys)
|
||||||
else:
|
else:
|
||||||
self.draw_frontline_approximation(frontline, scene, pen)
|
self.draw_frontline_approximation(scene, frontline, convoys)
|
||||||
else:
|
else:
|
||||||
self.draw_bezier_frontline(scene, pen, frontline, convoy_size)
|
self.draw_bezier_frontline(scene, frontline, convoys)
|
||||||
|
|
||||||
def draw_frontline_approximation(
|
def draw_frontline_approximation(
|
||||||
self, frontline: FrontLine, scene: QGraphicsScene, pen: QPen
|
self,
|
||||||
|
scene: QGraphicsScene,
|
||||||
|
frontline: FrontLine,
|
||||||
|
convoys: List[RoadTransferOrder],
|
||||||
) -> None:
|
) -> None:
|
||||||
posx = frontline.position
|
posx = frontline.position
|
||||||
h = frontline.attack_heading
|
h = frontline.attack_heading
|
||||||
pos2 = self._transform_point(posx)
|
pos2 = self._transform_point(posx)
|
||||||
self.draw_bezier_frontline(scene, pen, frontline)
|
self.draw_bezier_frontline(scene, frontline, convoys)
|
||||||
p1 = point_from_heading(pos2[0], pos2[1], h + 180, 25)
|
p1 = point_from_heading(pos2[0], pos2[1], h + 180, 25)
|
||||||
p2 = point_from_heading(pos2[0], pos2[1], h, 25)
|
p2 = point_from_heading(pos2[0], pos2[1], h, 25)
|
||||||
scene.addItem(
|
scene.addItem(
|
||||||
@ -943,9 +922,12 @@ class QLiberationMap(QGraphicsView):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def draw_actual_frontline(
|
def draw_actual_frontline(
|
||||||
self, frontline: FrontLine, scene: QGraphicsScene, pen: QPen
|
self,
|
||||||
|
scene: QGraphicsScene,
|
||||||
|
frontline: FrontLine,
|
||||||
|
convoys: List[RoadTransferOrder],
|
||||||
) -> None:
|
) -> None:
|
||||||
self.draw_bezier_frontline(scene, pen, frontline)
|
self.draw_bezier_frontline(scene, frontline, convoys)
|
||||||
vector = Conflict.frontline_vector(
|
vector = Conflict.frontline_vector(
|
||||||
frontline.control_point_a, frontline.control_point_b, self.game.theater
|
frontline.control_point_a, frontline.control_point_b, self.game.theater
|
||||||
)
|
)
|
||||||
|
|||||||
73
qt_ui/widgets/map/SupplyRouteSegment.py
Normal file
73
qt_ui/widgets/map/SupplyRouteSegment.py
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
from functools import cached_property
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
from PySide2.QtCore import Qt
|
||||||
|
from PySide2.QtGui import QColor, QPen
|
||||||
|
from PySide2.QtWidgets import QGraphicsItem, QGraphicsLineItem
|
||||||
|
|
||||||
|
from game.theater import ControlPoint
|
||||||
|
from game.transfers import RoadTransferOrder
|
||||||
|
from qt_ui.uiconstants import COLORS
|
||||||
|
|
||||||
|
|
||||||
|
class SupplyRouteSegment(QGraphicsLineItem):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
x0: float,
|
||||||
|
y0: float,
|
||||||
|
x1: float,
|
||||||
|
y1: float,
|
||||||
|
control_point_a: ControlPoint,
|
||||||
|
control_point_b: ControlPoint,
|
||||||
|
convoys: List[RoadTransferOrder],
|
||||||
|
parent: Optional[QGraphicsItem] = None,
|
||||||
|
) -> None:
|
||||||
|
super().__init__(x0, y0, x1, y1, parent)
|
||||||
|
self.control_point_a = control_point_a
|
||||||
|
self.control_point_b = control_point_b
|
||||||
|
self.convoys = convoys
|
||||||
|
self.setPen(self.make_pen())
|
||||||
|
self.setToolTip(self.make_tooltip())
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def convoy_size(self) -> int:
|
||||||
|
return sum(sum(c.units.values()) for c in self.convoys)
|
||||||
|
|
||||||
|
def make_tooltip(self) -> str:
|
||||||
|
if not self.convoys:
|
||||||
|
return "No convoys present on this supply route."
|
||||||
|
units = "units" if self.convoy_size > 1 else "unit"
|
||||||
|
|
||||||
|
return (
|
||||||
|
f"{self.convoy_size} {units} transferring between {self.control_point_a} "
|
||||||
|
f"and {self.control_point_b}."
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def line_color(self) -> QColor:
|
||||||
|
if self.control_point_a.front_is_active(self.control_point_b):
|
||||||
|
return COLORS["red"]
|
||||||
|
elif self.control_point_a.captured:
|
||||||
|
return COLORS["dark_blue"]
|
||||||
|
else:
|
||||||
|
return COLORS["dark_red"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def line_style(self) -> Qt.PenStyle:
|
||||||
|
if (
|
||||||
|
self.control_point_a.front_is_active(self.control_point_b)
|
||||||
|
or self.has_convoys
|
||||||
|
):
|
||||||
|
return Qt.PenStyle.SolidLine
|
||||||
|
return Qt.PenStyle.DotLine
|
||||||
|
|
||||||
|
def make_pen(self) -> QPen:
|
||||||
|
pen = QPen(brush=self.line_color)
|
||||||
|
pen.setColor(self.line_color)
|
||||||
|
pen.setStyle(self.line_style)
|
||||||
|
pen.setWidth(6)
|
||||||
|
return pen
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_convoys(self) -> bool:
|
||||||
|
return bool(self.convoys)
|
||||||
Loading…
x
Reference in New Issue
Block a user