def nearest_land_pos(self, point: Point, extend_dist: int = 50) -> Point: """Returns the nearest point inside a land exclusion zone from point `extend_dist` determines how far inside the zone the point should be placed""" if self.is_on_land(point): return point point = geometry.Point(point.x, point.y) nearest_points = [] if not self.landmap: raise RuntimeError("Landmap not initialized") for inclusion_zone in self.landmap[0]: nearest_pair = ops.nearest_points(point, inclusion_zone) nearest_points.append(nearest_pair[1]) min_distance = point.distance( nearest_points[0]) # type: geometry.Point nearest_point = nearest_points[0] # type: geometry.Point for pt in nearest_points[1:]: distance = point.distance(pt) if distance < min_distance: min_distance = distance nearest_point = pt assert isinstance(nearest_point, geometry.Point) point = Point(point.x, point.y) nearest_point = Point(nearest_point.x, nearest_point.y) new_point = point.point_from_heading( point.heading_between_point(nearest_point), point.distance_to_point(nearest_point) + extend_dist) return new_point
def intercept_conflict(cls, attacker_name: str, defender_name: str, attacker: Country, defender: Country, position: Point, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater): heading = from_cp.position.heading_between_point(position) return cls(position=position.point_from_heading( position.heading_between_point(to_cp.position), INTERCEPT_CONFLICT_DISTANCE), theater=theater, from_cp=from_cp, to_cp=to_cp, attackers_side=attacker_name, defenders_side=defender_name, attackers_country=attacker, defenders_country=defender, ground_attackers_location=None, ground_defenders_location=None, air_attackers_location=position.point_from_heading( random.randint(*INTERCEPT_ATTACKERS_HEADING) + heading, INTERCEPT_ATTACKERS_DISTANCE), air_defenders_location=position)
def heading_to_conflict_from(self, position: Point) -> Optional[Heading]: # Heading for a Group to the enemy. # Should be the point between the nearest and the most distant conflict conflicts: dict[MissionTarget, float] = {} for conflict in self.conflicts(): conflicts[conflict] = conflict.position.distance_to_point(position) if len(conflicts) == 0: return None sorted_conflicts = [ k for k, v in sorted(conflicts.items(), key=lambda item: item[1]) ] last = len(sorted_conflicts) - 1 conflict_center = sorted_conflicts[0].position.midpoint( sorted_conflicts[last].position ) return Heading.from_degrees(position.heading_between_point(conflict_center))
def add_oblong( self, p1: Point, p2: Point, radius: float, color=Rgba(255, 0, 0, 255), fill=Rgba(255, 0, 0, 60), line_thickness=4, line_style=LineStyle.Solid, resolution=20, ) -> FreeFormPolygon: hdg_p1_p2 = p1.heading_between_point(p2) points: List[Point] = [] for i in range(0, resolution + 1): hdg = hdg_p1_p2 - 90 + i * (180 / resolution) points.append(p2.point_from_heading(hdg, radius)) for i in range(0, resolution + 1): hdg = hdg_p1_p2 + 90 + i * (180 / resolution) points.append(p1.point_from_heading(hdg, radius)) # Copy first point and insert last to close the polygon points.append(points[0] * 1) # Transform points to local coordinates startPoint = points[0] * 1 # Copy for point in points: point.x -= startPoint.x point.y -= startPoint.y polygon = self.add_freeform_polygon( startPoint, points, color=color, fill=fill, line_thickness=line_thickness, line_style=line_style, ) return polygon