giovedì 6 novembre 2025

Tokunaga Trees

 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

Kernel Panic QrCode

 In tanti anni ho visto qualche kernel panic, ma in questo formato non mi era mai successo    la cosa curiosa che al riavvio successivo ness...