Day 23
(4.5)

L-Systemで生成する立体的な木構造

#recursive#tree#3d
L-Systemで生成する立体的な木構造のサムネイル

✅ Inputs

  • axiom: str – 初期文字列(例: `"F"`)
  • rules: dict – 書き換えルール(例: `{"F": "F[+F][-F][^F][&F][\\F][/F]"}`)
  • angle: float – 各回転の角度(度)
  • base_length: float – 初期の枝の長さ
  • depth: int – ルール展開の反復回数(再帰深度)
  • decay: float – 各分岐で枝が短くなる比率(0.8 など)
  • pipe_radius: float – Pipeの太さ

✅ Outputs

  • results: list of Brep – 3D空間に立体的に分岐するL-System構造をPipeで可視化したもの

✅ Code

import Rhino.Geometry as rg
import math

# === 🔧 入力パラメータ例(全方向への分岐)
axiom = "F"
rules = {
    "F": "F[+F][-F][^F][&F][\\F][/F]"  # 全方向へバランスよく分岐
}
angle = 40.0         # 回転角度(度)
base_length = 100.0   # 初期枝の長さ
depth = 4            # 再帰深度
decay = 0.8          # 枝の長さ減衰率
pipe_radius = 1.0

# === 🧬 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 Turtle with Length Decay)
def interpret_lsystem(lsys_string, angle_deg, base_length, decay):
    pos_stack = []
    dir_stack = []
    up_stack = []
    right_stack = []
    length_stack = []

    pos = rg.Point3d(0, 0, 0)
    dir = rg.Vector3d(0, 0, 1)     # Z方向に伸びる
    up = rg.Vector3d(1, 0, 0)      # X軸方向
    right = rg.Vector3d(0, 1, 0)   # Y軸方向
    length = base_length

    lines = []
    angle_rad = math.radians(angle_deg)

    for char in lsys_string:
        if char == "F":
            new_pos = pos + dir * length
            lines.append(rg.Line(pos, new_pos))
            pos = new_pos
        elif char == "+":
            xform = rg.Transform.Rotation(angle_rad, up, pos)
            dir.Transform(xform)
        elif char == "-":
            xform = rg.Transform.Rotation(-angle_rad, up, pos)
            dir.Transform(xform)
        elif char == "&":
            xform = rg.Transform.Rotation(angle_rad, right, pos)
            dir.Transform(xform)
        elif char == "^":
            xform = rg.Transform.Rotation(-angle_rad, right, pos)
            dir.Transform(xform)
        elif char == "\\":
            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))
            up_stack.append(rg.Vector3d(up))
            right_stack.append(rg.Vector3d(right))
            length_stack.append(length)
            length *= decay  # 枝を短くする
        elif char == "]":
            pos = pos_stack.pop()
            dir = dir_stack.pop()
            up = up_stack.pop()
            right = right_stack.pop()
            length = length_stack.pop()

    return [l.ToNurbsCurve() for l in lines]

# === 🚀 実行
lsys_string = expand_lsystem(axiom, rules, depth)
curves = interpret_lsystem(lsys_string, angle, base_length, decay)

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)