Perlでフラクタルツリーを描く
コッホ曲線を描くスクリプトをいじってたら出来ちゃいました。
use v5.14;
use strict;
use warnings;
use Imager;
use constant N => 9;
use constant WIDTH => 600;
use constant HEIGHT => 600;
my $margin = 50;
my ( $x0, $y0 ) = ( 0, HEIGHT - $margin );
my @gen = (
[ 0.6, 0.3 ],
[ 0.6, -0.3 ]
);
my $lines = [
[
[ 300, 0 ],
[ 300, 150 ]
]
];
my $img = Imager->new(
xsize => WIDTH, ysize => HEIGHT );
foreach my $n ( 0..N ) {
$img->box( filled => 1, color => 'white' );
if ( 0 < $n ) {
say "lines = ", scalar(@{$lines}), ", \$n = ", scalar(@gen) ** ($n - 1);
$lines = generate( $lines, scalar(@gen) ** ($n - 1) );
}
foreach my $line ( @{$lines} ) {
my @tmp = map {
[ int($x0 + $_->[0]), int($y0 - $_->[1]) ];
} @{$line};
$img->polyline( points => \@tmp, color => 'black' );
}
my $dst_file = ($0 =~ s/\.pl//r) . "_${n}.png";
$img->write( file => $dst_file ) or die $img->errstr;
}
sub generate {
my $lines = shift;
my $n = shift;
my @result = @{$lines};
for (my $i=1; $i<=$n; $i++) {
my $line = $lines->[-$i];
my ( $st, $en ) = @{$line};
my $dx = $en->[0] - $st->[0];
my $dy = $en->[1] - $st->[1];
push @result, map {
my ( $x, $y ) = ( $_->[0], $_->[1] );
# x2 = $x * cos(a) - $y * sin(a) + st.x;
# y2 = $x * sin(a) - $y * cos(a) + st.y;
# sin(a) = dy / 1.0, cos(a) = dx / 1.0
[
$en,
[
($x * $dx) - ($y * $dy) + $en->[0],
($x * $dy) + ($y * $dx) + $en->[1]
]
];
} @gen;
}
return \@result;
}
追加した枝の数を渡して、そこから枝を作って・・・、
みたいな感じの実装になっております。
どんどん線分が増えてアレな感じもしますが、
最終的にSVGを出力するなら、これで良いような気がします。
どうしても気になるようなら、参照しない枝は先に出力してしまうとか、
方法はいろいろあるんじゃないですかね。
という訳で、このスクリプトの実行結果はこんな感じ。
おしまい。

Leave a Comment