Day 22
(4)
L-Systemによる分岐構造の生成
#recursive#tree#3d

✅ Inputs
- axiom: str – 初期文字列(例: "F")
- rules: dict – 書き換えルール(例: {"F": "F[+F]F[-F]F"})
- angle: float – 回転角度(度単位、すべての回転に共通)
- length: float – 各枝の長さ
- depth: int – ルール展開の反復回数(世代数)
- pipe_radius: float – Pipeの太さ(線を太く可視化するための設定)
✅ Outputs
- results: list of Brep – L-Systemに従って生成された分岐構造をPipeで可視化した形状群
✅ Code
import Rhino.Geometry as rg
import math
# === 🔧 入力パラメータ例 ===
axiom = "F"
rules = {"F": "F[+F]F[-F]F"} # F = Forward(枝を伸ばす)
angle = 40.5 # 度単位
length = 10.0
depth = 4
pipe_radius = 0.5
# === 🧭 コマンドの意味(記号のマッピング表)
# command_meanings = {
# "F": "前進して線を描く(Forward)",
# "+": "左に回転(Z軸)",
# "-": "右に回転(Z軸)",
# "&": "下に回転(X軸)",
# "^": "上に回転(X軸)",
# "\\": "左にロール(進行方向軸)",
# "/": "右にロール(進行方向軸)",
# "[": "現在の位置と向きを保存",
# "]": "保存した状態に戻す"
# }
# === 🧬 L-Systemの展開
def expand_lsystem(axiom, rules, depth):
result = axiom
for _ in range(depth):
next_result = ""
for char in result:
next_result += rules.get(char, char)
result = next_result
return result
# === 🐢 Turtle描画(3Dベース)
def interpret_lsystem(lsys_string, angle_deg, length):
pos_stack = []
dir_stack = []
pos = rg.Point3d(0, 0, 0)
dir = rg.Vector3d(0, 0, 1) # Z方向に成長
up = rg.Vector3d(1, 0, 0)
right = rg.Vector3d(0, 1, 0)
lines = []
angle_rad = math.radians(angle_deg)
xform_stack = []
for char in lsys_string:
if char == "F": # Forward
new_pos = pos + dir * length
lines.append(rg.Line(pos, new_pos))
pos = new_pos
elif char == "+": # 左に回転(Z軸)
xform = rg.Transform.Rotation(angle_rad, up, pos)
dir.Transform(xform)
elif char == "-": # 右に回転(Z軸)
xform = rg.Transform.Rotation(-angle_rad, up, pos)
dir.Transform(xform)
elif char == "&": # 下に回転(X軸)
xform = rg.Transform.Rotation(angle_rad, right, pos)
dir.Transform(xform)
elif char == "^": # 上に回転(X軸)
xform = rg.Transform.Rotation(-angle_rad, right, pos)
dir.Transform(xform)
elif char == "\\": # 左ロール(Z軸をねじる)
xform = rg.Transform.Rotation(angle_rad, dir, pos)
up.Transform(xform)
right.Transform(xform)
elif char == "/": # 右ロール
xform = rg.Transform.Rotation(-angle_rad, dir, pos)
up.Transform(xform)
right.Transform(xform)
elif char == "[": # 状態保存
pos_stack.append(rg.Point3d(pos))
dir_stack.append(rg.Vector3d(dir))
xform_stack.append((rg.Vector3d(up), rg.Vector3d(right)))
elif char == "]": # 状態復元
if pos_stack and dir_stack:
pos = pos_stack.pop()
dir = dir_stack.pop()
up, right = xform_stack.pop()
return [l.ToNurbsCurve() for l in lines]
# === 🚀 実行
lsys_string = expand_lsystem(axiom, rules, depth)
curves = interpret_lsystem(lsys_string, angle, length)
results = []
for c in curves:
pipes = rg.Brep.CreatePipe(c, pipe_radius, False, rg.PipeCapMode.Round, True, 0.001, 0.001)
if pipes:
results.extend(pipes)