Perlでジュリア集合を描く(中編)
だいぶ時間があいてしまったけど、とりあえず続きを書く。
手順としてはこんな感じ。
- ランダムパラメータを使って、低解像度のデータを量産する
- 適当なパラメータでレンダリングする
- 使えそうなデータを選択して、データの生成範囲を再検討する
- パラメータを変更しながらレンダリング
非常に効率が悪いんだけど、
どうすればどういう感じになるのかも分からなければ、
良い感じにレンダリングする術もないので、今は仕方ない。
そんな感じで、パラメータと生成範囲を決めてデータを出力するスクリプトはこちら。
use v5.14;
use strict;
use warnings;
use Imager;
use Time::HiRes qw/time/;
use constant KL => 5000;
use constant KS => 2000;
use constant DST_DIR => './julia';
my @gen_info = (
{
a => [ -0.260693184726186,-0.687516709032337 ],
RS => -1.5,
RE => 1.5,
IS => -1.5,
IE => 1.5
},
{
a => [ -0.933335203860999,0.291308479429304 ],
RS => -1.7,
RE => 1.7,
IS => -1.7,
IE => 1.7
},
{
a => [ -0.305360385610307,0.778048402593683 ],
RS => -1.5,
RE => 1.5,
IS => -1.5,
IE => 1.5
},
{
a => [ 0.417568855329243,-0.141460590091484 ],
RS => -1.2,
RE => 1.2,
IS => -1.2,
IE => 1.2
}
);
if ( not -e DST_DIR ) {
mkdir DST_DIR;
}
local $| = 1;
my $i = 0;
foreach my $info ( @gen_info ) {
my ( $width, $height ) = ( KS, KS );
my $file_name = sprintf( '%03d_%d_%d.dat', $i++, $width, $height );
my $dst_file = join( '/', DST_DIR, $file_name );
if ( -e $dst_file ) {
next;
}
my $pixels = generate( $width, $height, $info );
if ( not $pixels ) {
next;
}
open( my $fh, '>', $dst_file ) or die "cannot open $dst_file : $!";
binmode( $fh );
foreach ( @{$pixels} ) {
print $fh pack('s*', @{$_});
}
close( $fh );
}
sub generate {
my ( $width, $height, $args ) = @_;
my ( $a_r, $a_i ) = @{$args->{a}};
my $dr = ( $args->{RE} - $args->{RS} ) / $width;
my $di = ( $args->{IE} - $args->{IS} ) / $height;
my $start = time();
printf( "%4d/%4d", 1, $height );
my @pixels = ();
for (my $iy=0; $iy<$height; $iy++) {
my $start_yloop = time();
my @buf = ();
for (my $ix=0; $ix<$width; $ix++) {
my $z_r = ($ix * $dr) + $args->{RS};
my $z_i = ($iy * $di) + $args->{IS};
my $i = -1;
foreach ( 0..KL ) {
my $z2_r = ($z_r * $z_r) - ($z_i * $z_i) + $a_r;
my $z2_i = (2.0 * $z_r * $z_i) + $a_i;
if ( 4 < (($z2_r * $z2_r) + ($z2_i * $z2_i)) ) {
$i = $_;
last;
}
( $z_r, $z_i ) = ( $z2_r, $z2_i );
}
push @buf, $i;
}
push @pixels, \@buf;
printf( "\r%4d/%4d", $iy + 1, $height );
if ( 1 < (time() - $start_yloop) ) {
printf( "\rtime out! %.2fsec\n", (time() - $start) );
return 0;
}
}
printf( "\rcomplete! %.2fsec\n", (time() - $start) );
return \@pixels;
}
とは言うものの、これをレンダリングしないといけないんだけどね。
おしまい。
Leave a Comment