Day 22
(4)

L-Systemによる分岐構造の生成

#recursive#tree#3d
L-Systemによる分岐構造の生成のサムネイル

✅ 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)