忍者ブログ

Memeplexes

プログラミング、3DCGとその他いろいろについて

かんがんL-system その2 描画

前回かんたんなL-systemのプログラムを書きました。
しかしその実行結果はわけがわからないものでした。

ABAABABAABAABABAABABA
というふうに、文字だけで、おもしろくありません。
L-systemはやはり描画してこそでしょう。

ソースコード

Algae.cs

using System;
using System.Collections.Generic;

namespace LSystem.Algae
{
    public class Algae
    {
        public AlgaeCell Root = new AlgaeCell { IsBig = false };
        public List<AlgaeCell> Cells = new List<AlgaeCell>();

        public Algae()
        {
            Cells.Add(Root);
        }

        public void Develop()
        {
            foreach (var cell in Cells)
            {
                cell.Update();
            }

            var newCells = new List<AlgaeCell>();

            foreach (var cell in Cells)
            {
                newCells.Add(cell);

                if (cell.CreatedChildren)
                {
                    newCells.Add(cell.Child1);
                    newCells.Add(cell.Child2);
                }
            }

            this.Cells = newCells;
        }

        public void ForEachTerminal(Action<AlgaeCell> executedInTerminal)
        {
            ForEachTerminal(executedInTerminal, Root);
        }

        public void ForEachTerminal(Action<AlgaeCell> executedInTerminal, AlgaeCell cell)
        {
            if (cell.HasChildren)
            {
                ForEachTerminal(executedInTerminal, cell.Child1);
                ForEachTerminal(executedInTerminal, cell.Child2);
            }
            else
            {
                executedInTerminal(cell);
            }
        }
    }

    public class AlgaeCell
    {
        public bool IsBig;
        public AlgaeCell Child1;
        public AlgaeCell Child2;

        public bool HasChildren
        {
            get { return Child1 != null; }
        }

        public bool CreatedChildren { get; private set; }

        public void Update()
        {
            CreatedChildren = false;

            if (HasChildren)
            {
                return;
            }

            if (IsBig)
            {
                this.Child1 = new AlgaeCell
                {
                    IsBig = true
                };
                this.Child2 = new AlgaeCell
                {
                    IsBig = false
                };
                CreatedChildren = true;
            }
            else
            {
                IsBig = true;
            }
        }
    }
}


MainWindow.xaml.cs

using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;

namespace LSystem.Algae
{
    public partial class MainWindow : Window
    {
        Algae algae = new Algae();

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            algae.Develop();

            Title = getText(algae.Root);
            canvas.Children.Clear();
            draw(algae.Root, new Vector(300, 100), 0);
        }

        private string getText(AlgaeCell cell)
        {
            var text = "";
            algae.ForEachTerminal((c) => text += c.IsBig ? "A" : "B");
            return text;
        }

        private void draw(AlgaeCell cell, Vector position, double angle)
        {
            var transform = new TransformGroup();
            transform.Children.Add(
                new ScaleTransform(cell.IsBig ? 1 : 0.5, cell.IsBig ? 1 : 0.5)
                );
            transform.Children.Add(new RotateTransform(angle));
            var endPosition = position 
                + transform.Value.Transform(new Vector(0, 100));

            var line = new Line
            {
                X1 = position.X,
                Y1 = position.Y,
                X2 = endPosition.X,
                Y2 = endPosition.Y,
                Stroke = cell.IsBig ? Brushes.Green : Brushes.LightGreen,
                StrokeThickness = 5
            };
            canvas.Children.Add(line);

            if (cell.HasChildren)
            {
                draw(
                    cell.Child1,
                    endPosition,
                    angle + 8
                    );
                draw(
                    cell.Child2,
                    endPosition,
                    angle - 8
                    );
            }
        }
    }
}

MainWindow.xaml

<Window x:Class="LSystem.Algae.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>

        <Canvas x:Name="canvas">

        </Canvas>
        <Button Height="24" VerticalAlignment="Bottom" HorizontalAlignment="Right" Width="58" Margin="0,0,10,10" Click="Button_Click">Next</Button>
    </Grid>
</Window>

実行結果

このプログラムを実行するとこうなります:

おお!!

なんとなく、藻類のように見えなくもないような気がしますね。
ただ、再帰で適当に描いたのとたいして変わりないじゃないかと言われると困りますが。

本来L-systemは文字とその変換だけでプログラムはすむはずなのですが、
ここではイメージというかフレイバーというかそういったものにこだわったソースコードにしてみました。
それにしては成長しきった細胞がいきなり現れたりという変な感じはしますが……

拍手[1回]

PR