note
kikuchiyo
Oh, no need to be so serious about it. I wrote this for fun. Streching the limits of perl (or Goo::Canvas specifically) was the point.
<br>
In fact, the slowness is caused by the fact that I create 360×300 = 10800 rectangle objects, and every time the mouse moves, all of them gets updated. I wrote a modified version that uses C for the Julia iteration:<br>
<readmore>
<code>
#!/usr/bin/perl
use strict;
use warnings;
use Gtk2 -init;
use Gtk2::Ex::Dialogs;
use Gtk2::Gdk::Keysyms;
use Glib ':constants';
use Goo::Canvas;
use Inline C => Config => CCFLAGS => '-O3 -msse3 -mfpmath=sse -march=core2 -ffast-math';
use Inline C => 'DATA';
# setting up default sizes
my $xbox = 360;
my $ybox = 300;
my $boxsize = 2;
my $centerx = 0;
my $centery = 0;
my $wsize = 4;
my $pmax = $centerx + $wsize / 2;
my $pmin = $centerx - $wsize / 2;
my $qmax = $centery + $wsize / 2 * $ybox/$xbox;
my $qmin = $centery - $wsize / 2 * $ybox/$xbox;
my $A = ($pmax-$pmin)/$xbox;
my $C = ($qmax-$qmin)/$ybox;
#print "$pmax, $pmin, $qmax, $qmin, $A, $C\n";
my $kmax=100;
# setting up palette
my @palette = map { '#'.sprintf("%02x", int(sqrt($_/$kmax)*256)).
sprintf("%02x", int(($_/$kmax)**3*256)).
sprintf("%02x", int(sin(3.14159*$_/$kmax)*256)) } (0..$kmax-1);
$palette[-1] = '#000000';
# Create the main window
my $win = new Gtk2::Window ( "toplevel" );
$win->signal_connect ("delete_event", sub { Gtk2->main_quit; });
#$win->signal_connect ("configure_event", \&win_expose);
$win->set_title( "Julia set demo" );
$win->set_border_width (6);
#$win->maximize;
$win->set_resizable (0);
$win->resize(700, 500);
my $vbox = Gtk2::VBox->new (0, 6);
$win->add ($vbox);
# Creating the canvas
my $canvas = Goo::Canvas->new();
$canvas->set_size_request($xbox*$boxsize, $ybox*$boxsize);
$canvas->set_bounds(0, 0, $xbox*$boxsize, $ybox*$boxsize);
my $white = Gtk2::Gdk::Color->new (0xFFFF, 0xFFFF, 0xFFFF);
$canvas->modify_base('normal', $white );
$vbox->pack_start($canvas, 1, 1, 0);
my $root = $canvas->get_root_item();
my $g = Goo::Canvas::Group->new($root);
my $rect = Goo::Canvas::Rect->new(
$g, 0, 0, $xbox*$boxsize, $ybox*$boxsize,
'line-width' => 1,
'stroke-color' => 'white', #invisible on white bg
'fill-color' => 'white', # must be filled for mouse event sensitivity
'title' => 'bg_white_rect',
);
# Creating the colored rectangles that make up the Julia set
my @pixels;
foreach my $x (0..$xbox-1) {
foreach my $y (0..$ybox-1) {
$pixels[$x][$y] = Goo::Canvas::Rect->new(
$g,
$x*$boxsize,
$y*$boxsize,
$boxsize,
$boxsize,
'line-width' => 0,
#'stroke-color' => 'white',
'fill-color' => 'white',
'pointer-events' => 'GOO_CANVAS_EVENTS_NONE',
#'title' => 'bg_white_rect',
);
}
}
$g->signal_connect('button-release-event', \&on_background_motion_notify); #'motion-notify-event', \&on_background_motion_notify);
$canvas->can_focus(TRUE);
$canvas->grab_focus($root);
$win->show_all;
main Gtk2;
# replotting on mouse movement
sub on_background_motion_notify {
my ($group, $item, $ev) = @_;
my $cy = $C*int(($ev->y)/$boxsize) + $qmin; #///
my $cx = $A*int(($ev->x)/$boxsize) + $pmin;
#print $ev->x," ,",$ev->y," ,$cx ,$cy\n";
my ($k, $x, $y, $x2, $y2);
foreach my $p (0..$xbox-1) {
foreach my $q (0..$ybox-1) {
$k = julia_iter($p, $q, $A, $C, $pmin, $qmin, $kmax, $cx, $cy);
$pixels[$p][$q]->set(
'fill-color' => $palette[$k],
);
}
}
return TRUE;
}
__DATA__
__C__
int julia_iter (int p, int q, double A, double C, double pmin, double qmin, int kmax, double cx, double cy) {
int k = 0;
double x = A*p + pmin;
double y = C*q + qmin;
double x2 = x*x;
double y2 = y*y;
while (x2+y2<4 && k<kmax) {
y=2*x*y+cy;
x=x2-y2+cx;
x2=x*x;
y2=y*y;
k++;
}
return k;
}
</code>
</readmore>
Profiling this shows that the julia_iter function (that calculates the new color) needs 3 us while the set method for the rectangles takes 12 us.
813179
813185