Sempre dal libro del post precedente generazione di alberi frattali con algoritmo di Tokunaga
import random
import matplotlib.pyplot as plt
import numpy as np
# --- 1. CLASSE DATI (Ramo) ---
class Ramo:
"""Rappresenta un segmento con il suo Ordine di Strahler."""
def __init__(self, ordine, nome=None):
self.ordine = ordine
self.nome = nome if nome else f"Ramo-{ordine}"
self.affluenti = []
# Dati per la visualizzazione (inizializzati durante la generazione)
self.x1, self.y1 = 0, 0
self.x2, self.y2 = 0, 0
self.spessore = 1.0
def aggiungi_affluente(self, ramo):
self.affluenti.append(ramo)
# --- 2. LOGICA DI GENERAZIONE E VISUALIZZAZIONE ---
def genera_tokunaga_tree_ricorsivo(
ordine_corrente,
ordine_max,
a, c,
x_start, y_start,
angolo_base,
lunghezza_base
):
"""
Genera un Tokunaga Tree ricorsivamente e calcola le coordinate per la stampa.
"""
# Calcola le coordinate finali
angolo_rad = np.deg2rad(angolo_base)
x_end = x_start + lunghezza_base * np.cos(angolo_rad)
y_end = y_start + lunghezza_base * np.sin(angolo_rad)
# Crea il nodo Ramo
ramo_principale = Ramo(ordine_corrente)
ramo_principale.x1, ramo_principale.y1 = x_start, y_start
ramo_principale.x2, ramo_principale.y2 = x_end, y_end
# Lo spessore è proporzionale all'ordine (per l'estetica)
ramo_principale.spessore = ordine_corrente * 0.5
# 1. Caso Base: Se l'ordine è 1, non ha affluenti ricorsivi.
if ordine_corrente == 1:
ramo_principale.nome = "Sorgente"
return ramo_principale
# 2. Affluente Principale (di ordine i-1)
# L'affluente principale continua nella stessa direzione con un ordine inferiore.
# Calcolo lunghezza e angoli per il prossimo livello
lunghezza_successiva = lunghezza_base * 0.7 # Riduzione della lunghezza
angolo_deviazione = 20 # Angolo massimo di deviazione
# L'affluente principale si unisce alla fine (x_end, y_end)
affluente_principale = genera_tokunaga_tree_ricorsivo(
ordine_corrente - 1, ordine_max, a, c,
x_end, y_end,
angolo_base + random.uniform(-1, 1) * 5, # Leggera variazione
lunghezza_successiva
)
ramo_principale.aggiungi_affluente(affluente_principale)
# 3. Affluenti Laterali (Side Branching) secondo la regola di Tokunaga
for i in range(1, ordine_corrente - 1): # L'ordine i è sempre < ordine_corrente - 1
k = ordine_corrente - i
# Tokunaga: T_k = a * c^(k-1)
num_medio_affluenti = a * (c ** (k - 1)) if k >= 1 else 0
# Determinazione del numero di affluenti laterali da aggiungere (in modo casuale)
num_affluenti = int(num_medio_affluenti)
if random.random() < (num_medio_affluenti % 1):
num_affluenti += 1
for n in range(num_affluenti):
# Posizione di giunzione: lungo il ramo principale (casualizzata)
t = random.uniform(0.2, 0.8) # Tra il 20% e l'80% della lunghezza
x_affluente_start = x_start + t * (x_end - x_start)
y_affluente_start = y_start + t * (y_end - y_start)
# Angolo dell'affluente laterale
deviazione_laterale = random.choice([1, -1]) * random.uniform(25, 45)
angolo_affluente = angolo_base + deviazione_laterale
affluente_laterale = genera_tokunaga_tree_ricorsivo(
i, ordine_max, a, c,
x_affluente_start, y_affluente_start,
angolo_affluente,
lunghezza_successiva * 0.8 # Sono un po' più corti
)
ramo_principale.aggiungi_affluente(affluente_laterale)
return ramo_principale
def disegna_albero(ramo, ax):
"""Disegna ricorsivamente il ramo e tutti i suoi affluenti."""
# Disegna il ramo corrente
line, = ax.plot(
[ramo.x1, ramo.x2],
[ramo.y1, ramo.y2],
color='blue',
linewidth=ramo.spessore,
alpha=0.8
)
# Chiama ricorsivamente per gli affluenti
for affluente in ramo.affluenti:
disegna_albero(affluente, ax)
# --- 3. ESECUZIONE E PLOT ---
# Parametri del Critical Tokunaga Model (adattati per la visualizzazione)
A_PARAM = 1.3
C_PARAM = 2.3
ORDINE_FINALE = 5
LUNGHEZZA_INIZIALE = 10.0
# Punti di partenza (alla base del plot) e direzione (verso l'alto)
X_START, Y_START = 0, -10
ANGOLO_INIZIALE = 90
# Generazione dell'albero
albero_radice = genera_tokunaga_tree_ricorsivo(
ORDINE_FINALE, ORDINE_FINALE,
A_PARAM, C_PARAM,
X_START, Y_START,
ANGOLO_INIZIALE,
LUNGHEZZA_INIZIALE
)
# Configurazione del Plot Matplotlib
fig, ax = plt.subplots(figsize=(8, 8))
ax.set_title(f"Tokunaga Tree (Ordine Max={ORDINE_FINALE}, a={A_PARAM}, c={C_PARAM})")
ax.set_aspect('equal', adjustable='box')
ax.axis('off') # Nasconde gli assi
# Disegno dell'albero
disegna_albero(albero_radice, ax)
# Imposta i limiti per vedere bene tutto l'albero
ax.set_xlim(-20, 20)
ax.set_ylim(-15, 20)
plt.show()

Nessun commento:
Posta un commento