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