```python
Герр Фауст, [30.09.2024 6:26]
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from matplotlib.patches import Rectangle
from matplotlib.transforms import Affine2D
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
from matplotlib.image import imread
import tkinter as tk
from tkinter import simpledialog, messagebox

# -------------------------------------------------------------------
# Класс для описания характеристик патрона
# -------------------------------------------------------------------
class Cartridge:
    def __init__(self):
        # Основные параметры
        self.diameter = 6.0e-3          # Диаметр пули в метрах (6,0 мм)
        self.mass = 12.5e-3             # Масса пули в килограммах (12,5 г)
        self.initial_velocity = 1100    # Начальная скорость в м/с
        self.energy = 7500              # Кинетическая энергия в Джоулях
        self.pressure = 375             # Давление в атмосферах
        self.length = 0.040             # Длина гильзы в метрах (40 мм)
        self.total_length = 0.055       # Общая длина патрона в метрах (55 мм)
        self.drag_coefficient = 0.295   # Коэффициент сопротивления для полумягкой пули
        self.cross_section_area = (np.pi / 4) * self.diameter ** 2  # Площадь поперечного сечения

        # Дополнительные параметры
        self.spin_rate = 2000  # Вращение пули в оборотах в минуту
        self.lift_coefficient = 0.05  # Коэффициент подъёмной силы (примерное значение)

# -------------------------------------------------------------------
# Физические константы
# -------------------------------------------------------------------
g = 9.81            # Ускорение свободного падения, м/с²
rho0_air = 1.225    # Плотность воздуха на уровне моря, кг/м³
H = 8500            # Масштаб высоты для модели атмосферы, м

# -------------------------------------------------------------------
# Функции для модели сопротивления и ускорения
# -------------------------------------------------------------------

def get_air_density(y):
    """
    Рассчитывает плотность воздуха в зависимости от высоты y.
    Используется упрощённая модель: rho = rho0 * exp(-y / H)
    """
    return rho0_air * np.exp(-y / H)

def acceleration(v, y, wind_velocity, cartridge):
    """
    Вычисляет ускорение пули с учётом сопротивления воздуха, подъёмной силы и гравитации.
    
    Параметры:
    - v: текущая скорость пули (вектор)
    - y: текущая высота пули
    - wind_velocity: скорость ветра (вектор)
    - cartridge: экземпляр класса Cartridge
    """
    # Относительная скорость пули относительно воздуха
    relative_v = v - wind_velocity
    speed = np.linalg.norm(relative_v)
    
    if speed == 0:
        drag_acc = np.array([0, 0])
        lift_acc = np.array([0, 0])
    else:
        # Плотность воздуха на текущей высоте
        rho = get_air_density(y)
        
        # Сила сопротивления воздуха
        drag_force = 0.5 * cartridge.drag_coefficient * rho * cartridge.cross_section_area * speed**2
        drag_acceleration = drag_force / cartridge.mass
        drag_acc = -drag_acceleration * (relative_v / speed)
        
        # Подъёмная сила из-за вращения пули (эффект Magnus)
        # Направление подъёмной силы перпендикулярно вектору скорости
        lift_force = 0.5 * cartridge.lift_coefficient * rho * cartridge.cross_section_area * speed**2
        lift_acc = lift_force / cartridge.mass * np.array([-relative_v[1], relative_v[0]]) / speed  # Поворот на 90 градусов
        
    # Ускорение свободного падения
    gravity_acc = np.array([0, -g])
    
    # Итоговое ускорение
    total_acc = drag_acc + lift_acc + gravity_acc
    return total_acc

# -------------------------------------------------------------------
# Численный метод интеграции (Рунге-Кутты 4-го порядка)
# -------------------------------------------------------------------
def simulate_motion_rk4(cartridge, angle_deg, wind_velocity, time_step=0.001, max_time=10):
    """
    Симулирует движение пули с использованием метода Рунге-Кутты 4-го порядка.
    
    Параметры:
    - cartridge: экземпля

Герр Фауст, [30.09.2024 6:26]
р класса Cartridge
    - angle_deg: угол выстрела в градусах
    - wind_velocity: скорость ветра (вектор)
    - time_step: шаг времени (с)
    - max_time: максимальное время симуляции (с)
    
    Возвращает:
    - positions: массив позиций пули (м)
    - times: массив времён (с)
    """
    angle_rad = np.radians(angle_deg)
    v0 = np.array([
        cartridge.initial_velocity * np.cos(angle_rad),
        cartridge.initial_velocity * np.sin(angle_rad)
    ])
    position = np.array([0.0, 0.0])
    velocity = v0.copy()
    positions = [position.copy()]
    times = [0.0]
    t = 0.0

    while t < max_time and position[1] >= 0:
        # Определение производных для RK4
        def derivatives(pos, vel):
            acc = acceleration(vel, pos[1], wind_velocity, cartridge)
            return vel, acc

        # RK4 шаги
        vel1, acc1 = derivatives(position, velocity)
        vel2, acc2 = derivatives(position + 0.5 * time_step * vel1, velocity + 0.5 * time_step * acc1)
        vel3, acc3 = derivatives(position + 0.5 * time_step * vel2, velocity + 0.5 * time_step * acc2)
        vel4, acc4 = derivatives(position + time_step * vel3, velocity + time_step * acc3)

        # Обновление скорости и позиции
        velocity += (time_step / 6.0) * (acc1 + 2 * acc2 + 2 * acc3 + acc4)
        position += (time_step / 6.0) * (vel1 + 2 * vel2 + 2 * vel3 + vel4)

        # Обновление времени и сохранение данных
        t += time_step
        positions.append(position.copy())
        times.append(t)

    return np.array(positions), np.array(times)

# -------------------------------------------------------------------
# Функции для получения пользовательского ввода через GUI
# -------------------------------------------------------------------
def get_user_input():
    """
    Запрашивает у пользователя параметры симуляции через графический интерфейс.
    
    Возвращает:
    - angle: угол выстрела в градусах
    - wind_speed: скорость ветра (м/с)
    - wind_angle: угол ветра относительно оси X в градусах
    """
    root = tk.Tk()
    root.withdraw()  # Скрыть основное окно

    try:
        angle = simpledialog.askfloat("Угол выстрела",
                                      "Введите угол выстрела в градусах (0-90):",
                                      minvalue=0.0, maxvalue=90.0)
        if angle is None:
            raise ValueError("Угол выстрела не был введён.")

        wind_speed = simpledialog.askfloat("Скорость ветра",
                                          "Введите скорость ветра (м/с):",
                                          minvalue=0.0)
        if wind_speed is None:
            wind_speed = 0.0  # Если не введено, принять как 0

        wind_angle = simpledialog.askfloat("Угол ветра",
                                          "Введите угол ветра относительно оси X в градусах (0-360):",
                                          minvalue=0.0, maxvalue=360.0)
        if wind_angle is None:
            wind_angle = 0.0  # Если не введено, принять как 0

    except Exception as e:
        messagebox.showerror("Ошибка ввода", str(e))
        root.destroy()
        exit()

    root.destroy()
    return angle, wind_speed, wind_angle

# -------------------------------------------------------------------
# Визуализация траектории и пули
# -------------------------------------------------------------------
def visualize(positions, cartridge, launch_angle, wind_velocity):
    """
    Создаёт анимацию траектории пули.
    
    Параметры:
    - positions: массив позиций пули (м)
    - cartridge: экземпляр класса Cartridge
    - launch_angle: угол выстрела в градусах
    - wind_velocity: скорость ветра (вектор)
    """
    fig, ax = plt.subplots(figsize=(12, 6))
    max_x = np.max(positions[:,0]) * 1.1
    max_y = np.max(positions[:,1]) * 1.1 if np.max(positions[:,1]) > 0 else 1
    ax.set_xlim(0, max_x)
    ax.set_ylim(0, max_y)
    ax.set_xlabel("Расстояние (м)")
    ax.set_ylabel("Высота (м)")
    ax.set_title(f"Траектория пули 6,0×40 мм при угле выстрела {launch_angle}°")

    # Линия траектории
    trajectory, = ax.plot

Герр Фауст, [30.09.2024 6:26]
([], [], lw=2, label="Траектория пули", color='blue')

    # Пуля (используется изображение, если доступно)
    try:
        bullet_img = imread('bullet.png')  # Замените на путь к вашему изображению пули
        bullet_box = OffsetImage(bullet_img, zoom=0.05, resample=True)
        bullet_ab = AnnotationBbox(bullet_box, (0,0), frameon=False)
        ax.add_artist(bullet_ab)
        use_image = True
    except FileNotFoundError:
        # Если изображение не найдено, используем прямоугольник
        bullet_width = cartridge.diameter
        bullet_height = bullet_width * 2
        bullet_rect = Rectangle((0,0), bullet_width, bullet_height, fc='red', ec='black', label="Пуля")
        ax.add_patch(bullet_rect)
        use_image = False

    # Легенда
    ax.legend()

    # Настройка сетки
    ax.grid(True, which='both', linestyle='--', linewidth=0.5)

    # Инициализация анимации
    def init():
        trajectory.set_data([], [])
        if use_image:
            bullet_ab.xybox = (0,0)
            bullet_ab.set_visible(False)
        else:
            bullet_rect.set_xy((0,0))
        return trajectory,

    # Функция анимации
    def animate(frame):
        # Обновление траектории
        trajectory.set_data(positions[:frame,0], positions[:frame,1])

        # Обновление позиции пули
        bullet_x = positions[frame,0]
        bullet_y = positions[frame,1]
        
        if use_image:
            bullet_ab.xybox = (bullet_x, bullet_y)
            bullet_ab.set_visible(True)
        else:
            bullet_rect.set_xy((bullet_x, bullet_y))
            # Вращение пули (упрощено)
            angle = (cartridge.spin_rate / 60) * times[frame] * 360 % 360
            trans = Affine2D().rotate_deg(angle) + ax.transData
            bullet_rect.set_transform(trans)
        
        return trajectory,

    # Создание анимации
    ani = FuncAnimation(fig, animate, frames=len(positions),
                        init_func=init, interval=1, blit=True, repeat=False)

    plt.show()

# -------------------------------------------------------------------
# Функция для вывода результатов симуляции
# -------------------------------------------------------------------
def print_simulation_results(positions, times, launch_angle):
    """
    Выводит основные результаты симуляции.
    
    Параметры:
    - positions: массив позиций пули (м)
    - times: массив времён (с)
    - launch_angle: угол выстрела в градусах
    """
    if len(positions) == 0:
        print("Нет данных для отображения.")
        return

    max_distance = np.max(positions[:,0])
    max_height = np.max(positions[:,1])
    flight_time = times[-1]
    impact_x = positions[-1,0]
    impact_y = positions[-1,1]

    print("\nРезультаты симуляции:")
    print(f"Угол выстрела: {launch_angle}°")
    print(f"Время полёта: {flight_time:.3f} с")
    print(f"Дальность: {impact_x:.2f} м")
    print(f"Максимальная высота: {max_height:.2f} м")

# -------------------------------------------------------------------
# Основная функция
# -------------------------------------------------------------------
if __name__ == "__main__":
    # Создание экземпляра патрона
    cartridge = Cartridge()

    # Получение пользовательского ввода
    launch_angle, wind_speed, wind_angle = get_user_input()

    # Рассчёт ветровой скорости в компонентах X и Y
    wind_rad = np.radians(wind_angle)
    wind_velocity = np.array([
        wind_speed * np.cos(wind_rad),
        wind_speed * np.sin(wind_rad)
    ])

    # Проведение симуляции
    positions, times = simulate_motion_rk4(cartridge, launch_angle, wind_velocity)

    # Визуализация результатов
    visualize(positions, cartridge, launch_angle, wind_velocity)

    # Вывод результатов в консоль
    print_simulation_results(positions, times, launch_angle)
```
Убери нежелательные строки