from typing import Dict from PySide2.QtCore import Qt from PySide2.QtGui import QPixmap, QBrush, QColor, QWheelEvent, QPen, QFont from PySide2.QtWidgets import QGraphicsView, QFrame from gen import Conflict from qt_ui.widgets.map.QMapControlPoint import QMapControlPoint from qt_ui.widgets.map.QMapGroundObject import QMapGroundObject from qt_ui.widgets.map.QLiberationScene import QLiberationScene from dcs import Point from qt_ui.windows.GameUpdateSignal import GameUpdateSignal from theater import ControlPoint from game import Game import qt_ui.uiconstants as CONST class QLiberationMap(QGraphicsView): instance = None display_rules: Dict[str, bool] = { "cp": True, "go": True, "lines": True, "ennemy_sam_ranges": True, "ally_sam_ranges": True } def __init__(self, game: Game): super(QLiberationMap, self).__init__() QLiberationMap.instance = self self.frontline_vector_cache = {} self.setMinimumSize(800,600) self.setMaximumHeight(2160) self._zoom = 0 self.init_scene() self.connectSignals() self.setGame(game) def init_scene(self): scene = QLiberationScene(self) scene.addText("Hello World") self.setScene(scene) self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.setResizeAnchor(QGraphicsView.AnchorUnderMouse) self.setBackgroundBrush(QBrush(QColor(30, 30, 30))) self.setFrameShape(QFrame.NoFrame) self.setDragMode(QGraphicsView.ScrollHandDrag) def connectSignals(self): GameUpdateSignal.get_instance().gameupdated.connect(self.setGame) def setGame(self, game: Game): self.game = game print("Reloading Map Canvas") print(self.game) if self.game is not None: self.reload_scene() def reload_scene(self): scene = self.scene() scene.clear() scene.addPixmap(QPixmap("./resources/" + self.game.theater.overview_image)) for cp in self.game.theater.controlpoints: pos = self._transform_point(cp.position) scene.addItem(QMapControlPoint(self, pos[0] - CONST.CP_SIZE / 2, pos[1] - CONST.CP_SIZE / 2, CONST.CP_SIZE, CONST.CP_SIZE, cp, self.game)) # e = scene.addEllipse(pos[0]-CONST.CP_SIZE/2, pos[1]-CONST.CP_SIZE/2, CONST.CP_SIZE, CONST.CP_SIZE, QPen(brush=QBrush(color=color), width=5), brush=color) text = scene.addText(cp.name, font=QFont("Trebuchet MS", 10, weight=5, italic=False)) text.setPos(pos[0] + CONST.CP_SIZE, pos[1] - CONST.CP_SIZE / 2) for ground_object in cp.ground_objects: go_pos = self._transform_point(ground_object.position) scene.addItem(QMapGroundObject(self, go_pos[0], go_pos[1], 16, 16, cp, ground_object)) if self.get_display_rule("lines"): self.scene_create_lines_for_cp(cp) def scene_create_lines_for_cp(self, cp: ControlPoint): scene = self.scene() pos = self._transform_point(cp.position) for connected_cp in cp.connected_points: pos2 = self._transform_point(connected_cp.position) if connected_cp.captured != cp.captured: color = CONST.COLORS["red"] elif connected_cp.captured and cp.captured: color = CONST.COLORS["blue"] else: color = CONST.COLORS["black_transparent"] pen = QPen(brush=color) pen.setColor(color) pen.setWidth(4) scene.addLine(pos[0], pos[1], pos2[0], pos2[1], pen=pen) if cp.captured and not connected_cp.captured and Conflict.has_frontline_between(cp, connected_cp): frontline = self._frontline_vector(cp, connected_cp) if not frontline: continue frontline_pos, heading, distance = frontline if distance < 10000: frontline_pos = frontline_pos.point_from_heading(heading + 180, 5000) distance = 10000 start_coords = self._transform_point(frontline_pos, treshold=10) end_coords = self._transform_point(frontline_pos.point_from_heading(heading, distance), treshold=60) frontline_pen = QPen(brush=CONST.COLORS["bright_red"]) frontline_pen.setColor(CONST.COLORS["bright_red"]) frontline_pen.setWidth(4) frontline_pen.setStyle(Qt.DashDotLine) # frontline_pen.setDashPattern([0,1]) scene.addLine(start_coords[0], start_coords[1], end_coords[0], end_coords[1], pen=frontline_pen) def _frontline_vector(self, from_cp: ControlPoint, to_cp: ControlPoint): # Cache mechanism to avoid performing frontline vector computation on every frame key = str(from_cp.id) + "_" + str(to_cp.id) if key in self.frontline_vector_cache: return self.frontline_vector_cache[key] else: frontline = Conflict.frontline_vector(from_cp, to_cp, self.game.theater) self.frontline_vector_cache[key] = frontline return frontline def wheelEvent(self, event: QWheelEvent): if event.angleDelta().y() > 0: factor = 1.25 self._zoom += 1 else: factor = 0.8 self._zoom -= 1 if self._zoom > -5: self.scale(factor, factor) else: self._zoom = -5 def _transform_point(self, p: Point, treshold=30) -> (int, int): point_a = list(self.game.theater.reference_points.keys())[0] point_a_img = self.game.theater.reference_points[point_a] point_b = list(self.game.theater.reference_points.keys())[1] point_b_img = self.game.theater.reference_points[point_b] Y_dist = point_a_img[0] - point_b_img[0] lon_dist = point_a[1] - point_b[1] X_dist = point_a_img[1] - point_b_img[1] lat_dist = point_b[0] - point_a[0] Y_scale = float(Y_dist) / float(lon_dist) X_scale = float(X_dist) / float(lat_dist) # --- Y_offset = p.x - point_a[0] X_offset = p.y - point_a[1] X = point_b_img[1] + X_offset * X_scale Y = point_a_img[0] - Y_offset * Y_scale #X += 5 #Y += 5 return X > treshold and X or treshold, Y > treshold and Y or treshold @staticmethod def set_display_rule(rule: str, value: bool): QLiberationMap.display_rules[rule] = value QLiberationMap.instance.reload_scene() QLiberationMap.instance.update() @staticmethod def get_display_rules() -> Dict[str, bool]: return QLiberationMap.display_rules @staticmethod def get_display_rule(rule) -> bool: return QLiberationMap.display_rules[rule]