Некорректное построение обдуваемого ветром дерева Пифагора
Kлассическое, обнажённое и обнажённое обдуваемое ветром строятся как надо, а классическое обдуваемое ветром выходит криво. Прошу помочь с этой проблемой.
import tkinter as tk
from tkinter import ttk
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import numpy as np
class PythagorasTreeApp(tk.Tk):
def __init__(self):
super().__init__()
self.title("Pythagoras Tree")
self.geometry("800x600")
self.tree_type_var = tk.StringVar(value="classic")
self.wind_angle_var = tk.DoubleVar(value=10) # Угол в градусах
self.create_widgets()
self.plot_tree()
def create_widgets(self):
control_frame = ttk.Frame(self)
control_frame.pack(side=tk.LEFT, fill=tk.Y, padx=10, pady=10)
ttk.Label(control_frame, text="Iterations:").pack()
self.iterations_var = tk.IntVar(value=10)
self.iterations_entry = ttk.Entry(control_frame, textvariable=self.iterations_var)
self.iterations_entry.pack()
ttk.Label(control_frame, text="Tree Type:").pack()
ttk.Radiobutton(control_frame, text="Classic", variable=self.tree_type_var, value="classic",
command=self.plot_tree).pack(anchor=tk.W)
ttk.Radiobutton(control_frame, text="Naked", variable=self.tree_type_var, value="naked",
command=self.plot_tree).pack(anchor=tk.W)
ttk.Label(control_frame, text="Wind Angle (degrees):").pack()
self.wind_angle_entry = ttk.Entry(control_frame, textvariable=self.wind_angle_var)
self.wind_angle_entry.pack()
fig = Figure()
self.ax = fig.add_subplot(111)
self.canvas = FigureCanvasTkAgg(fig, master=self)
self.canvas.get_tk_widget().pack(side=tk.RIGHT, fill=tk.BOTH, expand=1)
def plot_tree(self):
self.ax.clear()
iterations = self.iterations_var.get()
tree_type = self.tree_type_var.get()
wind_angle_deg = self.wind_angle_var.get()
wind_angle_rad = np.deg2rad(wind_angle_deg) # Преобразование угла в радианы
if tree_type == "classic":
self.draw_classic_tree(self.ax, 0.5, 0, np.pi / 2, 0.1, wind_angle_rad, iterations)
elif tree_type == "naked":
self.draw_naked_tree(self.ax, 0.5, 0, np.pi / 2, 0.1, wind_angle_rad, iterations)
self.ax.set_aspect('equal')
self.canvas.draw()
def draw_classic_tree(self, ax, x, y, angle, length, wind_angle, depth):
if depth == 0:
return
# Координаты вершины квадрата
x2 = x + length * np.cos(angle)
y2 = y + length * np.sin(angle)
x3 = x2 + length * np.cos(angle - np.pi / 2)
y3 = y2 + length * np.sin(angle - np.pi / 2)
x4 = x + length * np.cos(angle - np.pi / 2)
y4 = y + length * np.sin(angle - np.pi / 2)
# Рисуем квадрат
square_x = [x, x2, x3, x4, x]
square_y = [y, y2, y3, y4, y]
ax.plot(square_x, square_y, color='green')
# Новая длина для следующего уровня
new_length = length * np.sqrt(2) / 2
# Корректируем координаты для новых ветвей
right_x = x + length * np.cos(angle + wind_angle)
right_y = y + length * np.sin(angle + wind_angle)
left_x = x3 + new_length * np.cos(angle + np.pi / 4 + wind_angle)
left_y = y3 + new_length * np.sin(angle + np.pi / 4 + wind_angle)
# Рекурсивные вызовы для левого и правого поддеревьев с учетом ветра
self.draw_classic_tree(ax, right_x, right_y, angle + np.pi / 4 + wind_angle, new_length, wind_angle, depth - 1)
self.draw_classic_tree(ax, left_x, left_y, angle - np.pi / 4 + wind_angle, new_length, wind_angle, depth - 1)
def draw_naked_tree(self, ax, x, y, angle, length, wind_angle, depth):
if depth == 0:
return
# Рисуем линию
x2 = x + length * np.cos(angle)
y2 = y + length * np.sin(angle)
ax.plot([x, x2], [y, y2], color='green')
# Новая длина для следующего уровня
new_length = length * np.sqrt(2) / 2
# Рекурсивные вызовы для левого и правого поддеревьев
self.draw_naked_tree(ax, x2, y2, angle + np.pi / 4 + wind_angle, new_length, wind_angle, depth - 1)
self.draw_naked_tree(ax, x2, y2, angle - np.pi / 4 + wind_angle, new_length, wind_angle, depth - 1)
if __name__ == "__main__":
app = PythagorasTreeApp()
app.mainloop()
Ответы (1 шт):
Автор решения: MBo
→ Ссылка
Обратите внимание, что размер квадратов для левого и правого обдуваемого дерева должен быть разным (это два катета прямоугольного треугольника).
(Может быть, в обнажённом тоже не совсем верно размеры считаются, не проверял)
# Новая длина для следующего уровня
new_length_l = length * np.sin(np.pi / 4 + wind_angle)
new_length_r = length * np.cos(np.pi / 4 + wind_angle)
# Корректируем координаты для новых ветвей
right_x = x3 + new_length_r * np.cos(angle + np.pi / 4 - wind_angle)
right_y = y3 + new_length_r * np.sin(angle + np.pi / 4 - wind_angle)
# Рекурсивные вызовы для левого и правого поддеревьев с учетом ветра
self.draw_classic_tree(ax, x2, y2, angle + np.pi / 4 - wind_angle, new_length_l, wind_angle, depth - 1)
self.draw_classic_tree(ax, right_x, right_y, angle - np.pi / 4 - wind_angle, new_length_r, wind_angle, depth - 1)