diff --git a/gen/conflictgen.py b/gen/conflictgen.py index 7f1a5e0a..42daa4c2 100644 --- a/gen/conflictgen.py +++ b/gen/conflictgen.py @@ -97,42 +97,16 @@ class Conflict: @classmethod def frontline_vector(cls, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater) -> Tuple[Point, int, int]: """ - probe_end_point = initial.point_from_heading(heading, FRONTLINE_LENGTH) - probe = geometry.LineString([(initial.x, initial.y), (probe_end_point.x, probe_end_point.y) ]) - intersection = probe.intersection(theater.land_poly) - - if isinstance(intersection, geometry.LineString): - intersection = intersection - elif isinstance(intersection, geometry.MultiLineString): - intersection = intersection.geoms[0] - else: - print(intersection) - return None - - return Point(*intersection.xy[0]), _heading_sum(heading, 90), intersection.length + Returns a vector for a valid frontline location avoiding exclusion zones. """ - frontline = cls.frontline_position(from_cp, to_cp, theater) - center_position, heading = frontline - left_position, right_position = None, None - - if not theater.is_on_land(center_position): - pos = cls._find_ground_position(center_position, FRONTLINE_LENGTH, _heading_sum(heading, -90), theater) - if pos: - right_position = pos - center_position = pos - else: - pos = cls._find_ground_position(center_position, FRONTLINE_LENGTH, _heading_sum(heading, +90), theater) - if pos: - left_position = pos - center_position = pos - - if left_position is None: - left_position = cls._extend_ground_position(center_position, int(FRONTLINE_LENGTH/2), _heading_sum(heading, -90), theater) - - if right_position is None: - right_position = cls._extend_ground_position(center_position, int(FRONTLINE_LENGTH/2), _heading_sum(heading, 90), theater) - - return left_position, _heading_sum(heading, 90), int(right_position.distance_to_point(left_position)) + center_position, heading = cls.frontline_position(from_cp, to_cp, theater) + center_position = cls._find_ground_position(center_position, FRONTLINE_LENGTH, _heading_sum(heading, 90), theater) + left_heading = _heading_sum(heading, 90) + right_heading = _heading_sum(heading, -90) + left_position = cls._extend_ground_position(center_position, int(FRONTLINE_LENGTH / 2), left_heading, theater) + right_position = cls._extend_ground_position(center_position, int(FRONTLINE_LENGTH / 2), right_heading, theater) + distance = int(left_position.distance_to_point(right_position)) + return left_position, right_heading, distance @classmethod def frontline_cas_conflict(cls, attacker_name: str, defender_name: str, attacker: Country, defender: Country, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater): @@ -154,46 +128,27 @@ class Conflict: @classmethod def _extend_ground_position(cls, initial: Point, max_distance: int, heading: int, theater: ConflictTheater) -> Point: + """Finds a valid ground position in one heading from an initial point""" pos = initial - for offset in range(0, int(max_distance), 500): - new_pos = initial.point_from_heading(heading, offset) - if theater.is_on_land(new_pos): - pos = new_pos - else: + for distance in range(0, int(max_distance), 100): + if not theater.is_on_land(pos): return pos - return pos - - """ - probe_end_point = initial.point_from_heading(heading, max_distance) - probe = geometry.LineString([(initial.x, initial.y), (probe_end_point.x, probe_end_point.y)]) - - intersection = probe.intersection(theater.land_poly) - if intersection is geometry.LineString: - return Point(*intersection.xy[1]) - elif intersection is geometry.MultiLineString: - return Point(*intersection.geoms[0].xy[1]) - - return None - """ + pos = initial.point_from_heading(heading, distance) + if theater.is_on_land(pos): + return pos + logging.error("Didn't find ground position ({})!".format(initial)) + return initial @classmethod def _find_ground_position(cls, initial: Point, max_distance: int, heading: int, theater: ConflictTheater) -> Point: + """Finds the nearest ground position along a provided heading and it's inverse""" pos = initial - for _ in range(0, int(max_distance), 100): + for distance in range(0, int(max_distance), 100): if theater.is_on_land(pos): return pos - - pos = pos.point_from_heading(heading, 500) - """ - probe_end_point = initial.point_from_heading(heading, max_distance) - probe = geometry.LineString([(initial.x, initial.y), (probe_end_point.x, probe_end_point.y) ]) - - intersection = probe.intersection(theater.land_poly) - if isinstance(intersection, geometry.LineString): - return Point(*intersection.xy[1]) - elif isinstance(intersection, geometry.MultiLineString): - return Point(*intersection.geoms[0].xy[1]) - """ - + pos = initial.point_from_heading(heading, distance) + if theater.is_on_land(pos): + return pos + pos = initial.point_from_heading(_opposite_heading(heading), distance) logging.error("Didn't find ground position ({})!".format(initial)) return initial diff --git a/qt_ui/displayoptions.py b/qt_ui/displayoptions.py index bec194fb..d99e3a99 100644 --- a/qt_ui/displayoptions.py +++ b/qt_ui/displayoptions.py @@ -58,6 +58,7 @@ class DisplayOptions: waypoint_info = DisplayRule("Waypoint Information", True) culling = DisplayRule("Display Culling Zones", False) flight_paths = FlightPathOptions() + actual_frontline_pos = DisplayRule("Display actual frontline width and location", False) @classmethod def menu_items(cls) -> Iterator[Union[DisplayGroup, DisplayRule]]: diff --git a/qt_ui/widgets/map/QLiberationMap.py b/qt_ui/widgets/map/QLiberationMap.py index 0937f8c9..d628a0b6 100644 --- a/qt_ui/widgets/map/QLiberationMap.py +++ b/qt_ui/widgets/map/QLiberationMap.py @@ -476,17 +476,52 @@ class QLiberationMap(QGraphicsView): pen.setWidth(6) frontline = FrontLine(cp, connected_cp, self.game.theater) if cp.captured and not connected_cp.captured and Conflict.has_frontline_between(cp, connected_cp): - posx = frontline.position - h = frontline.attack_heading - pos2 = self._transform_point(posx) - self.draw_bezier_frontline(scene, pen, frontline) - p1 = point_from_heading(pos2[0], pos2[1], h+180, 25) - p2 = point_from_heading(pos2[0], pos2[1], h, 25) - scene.addItem(QFrontLine(p1[0], p1[1], p2[0], p2[1], - frontline, self.game_model)) - + if DisplayOptions.actual_frontline_pos: + self.draw_actual_frontline(frontline, scene, pen) + else: + self.draw_frontline_approximation(frontline, scene, pen) else: self.draw_bezier_frontline(scene, pen, frontline) + + def draw_frontline_approximation(self, frontline: FrontLine, scene: QGraphicsScene, pen: QPen) -> None: + posx = frontline.position + h = frontline.attack_heading + pos2 = self._transform_point(posx) + self.draw_bezier_frontline(scene, pen, frontline) + p1 = point_from_heading(pos2[0], pos2[1], h+180, 25) + p2 = point_from_heading(pos2[0], pos2[1], h, 25) + scene.addItem( + QFrontLine( + p1[0], + p1[1], + p2[0], + p2[1], + frontline, + self.game_model + ) + ) + + def draw_actual_frontline(self, frontline: FrontLine, scene: QGraphicsScene, pen: QPen) -> None: + self.draw_bezier_frontline(scene, pen, frontline) + vector = Conflict.frontline_vector( + frontline.control_point_a, + frontline.control_point_b, + self.game.theater + ) + left_pos = self._transform_point(vector[0]) + right_pos = self._transform_point( + vector[0].point_from_heading(vector[1], vector[2]) + ) + scene.addItem( + QFrontLine( + left_pos[0], + left_pos[1], + right_pos[0], + right_pos[1], + frontline, + self.game_model + ) + ) def wheelEvent(self, event: QWheelEvent):