Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options

The horribly slow Julia set viewer with the extremely inefficient plotting method

by kikuchiyo (Monk)
on Dec 17, 2009 at 12:59 UTC ( #813179=CUFP: print w/replies, xml ) Need Help??

Behold! This is a simple demo that plots a Julia set, the defining coordinate of which being taken from the mouse cursor position. This effect is achieved by defining 360300 pieces of small rectangles on the canvas, then recalculating and changing the color of every rectangle on every motion notify event. This seems to be very slow (1-2 fps at best on my machine), hence the title.

The demo needs Gtk2 and Goo::Canvas to run.

#!/usr/bin/perl use strict; use warnings; use Gtk2 -init; use Gtk2::Ex::Dialogs; use Gtk2::Gdk::Keysyms; use Glib ':constants'; use Goo::Canvas; # 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 sensit +ivity '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', #'title' => 'bg_white_rect', ); } } $g->signal_connect('motion-notify-event', \&on_background_motion_notif +y); $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 = 0; $x = $A*$p + $pmin; $y = $C*$q + $qmin; $x2 = $x*$x; $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++; } $pixels[$p][$q]->set( 'fill-color' => $palette[$k], ); } } return TRUE; }

  • Comment on The horribly slow Julia set viewer with the extremely inefficient plotting method
  • Download Code

Replies are listed 'Best First'.
Re: The horribly slow Julia set viewer with the extremely inefficient plotting method
by zentara (Archbishop) on Dec 17, 2009 at 13:52 UTC
    This seems to be very slow are pushing the calculation limits of perl by doing 500 updates on the slightest mouse motion....this app seems simple have the prototype in convert it to c for speed..... the gtk+ c tutorial is not too hard.

    ...if you want to keep Perl, but speed it up, ...... stop updating ALL rectangles everytime... blank it out, and as you fill in color, at 100 rectangles at a time, leave them set ..... so you can minimize the number being dynamically changed from 500 down to 100 or even 50

    .... if i were doing it, i would shove the 500 initial rectangles into an array, and loop thru them, say 50 or 100 at a time, and see the effect..... a big circular array of rects

    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku
      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.
      In fact, the slowness is caused by the fact that I create 360300 = 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:
      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.
        To illustrate the point, here is a version that does not use Goo::Canvas and rectangles at all, it builds up a string of rgb pixels instead and uses that to create a pixbuf, which in turn gets displayed on a DrawingArea.

        This is actually fast enough to be usable, as the animation is quite smooth on my machine.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: CUFP [id://813179]
Approved by Corion
Front-paged by Arunbear
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (10)
As of 2017-07-20 20:12 GMT
Find Nodes?
    Voting Booth?
    I came, I saw, I ...

    Results (314 votes). Check out past polls.