Thread Lindenmayer-Systeme (ein schneller Hack)
(0 answers)
Opened by neniro at 2009-04-26 16:38
Inspiriert, durch einige Python Artikel unter http://natesoares.com/writing/python-fractals-6/ und den Wikipedia-Eintrag: http://en.wikipedia.org/wiki/Lindenmayer_system#Ex... habe ich ein klein wenig gespielt:
Code (perl): (dl
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 #!/usr/bin/perl use strict; use warnings; use Data::Dumper; use Carp; package Turtle; use Math::Trig; use Imager; sub new { my $class = shift; my ($x, $y, $angle, $dir, $step, $color, $file) = @_; my $self = { "xpos" => $x || 20, "ypos" => $y || 800-20, "angle" => $angle || 60, "dir" => $dir || 0, "step" => $step || 4, "color" => $color, "img" => Imager->new( xsize=>1048,ysize=>800 ), "file" => $file || 'turtle.bmp', }; return bless $self, $class; } sub move { my $self = shift; my $rad = deg2rad($self->{"dir"}); $self->{"xpos"} += int 0.5 + (cos($rad) * $self->{"step"}); $self->{"ypos"} += int 0.5 + (sin($rad) * $self->{"step"}); } sub draw { my $self = shift; my $rad = deg2rad($self->{"dir"}); my ($x1, $y1) = ($self->{"xpos"}, $self->{"ypos"}); my $x2 = int 0.5 + ($x1 + cos($rad) * $self->{"step"}); my $y2 = int 0.5 + ($y1 + sin($rad) * $self->{"step"}); # line($x1, $y1, $x2, $y2); # from Imager or GD ... $self->{"img"}->line( x1 => $x1, x2 => $x2, y1 => $y1, y2 => $y2, aa=>1, color => Imager::Color->new( 255, 255, 255 ) ); $self->{"xpos"} = $x2; $self->{"ypos"} = $y2; } sub turn_left { my $self = shift; $self->{"dir"} = $self->{"dir"} + $self->{"angle"} > 360 ? $self->{"dir"} - 360 + $self->{"angle"} : $self->{"dir"} + $self->{"angle"} ; } sub turn_right { my $self = shift; $self->{"dir"} = $self->{"dir"} - $self->{"angle"} < 0 ? $self->{"dir"} + 360 - $self->{"angle"} : $self->{"dir"} - $self->{"angle"} ; } sub to_png { my $self = shift; $self->{"img"}->write(file=>$self->{"file"}) or die $self->{"img"}->errstr; } 1; package Lindenmayer; sub new { my ( $class, $axiom, $rules ) = @_; my $self = { "rules" => __generate_rules($rules), "axiom" => $axiom, "cache" => [$axiom], "iter" => undef, }; bless $self, $class; return $self; } sub create_iterator { my $self = shift; $self->{"iter"} = sub { $self->{"axiom"} = $self->{"rules"}->($self->{"axiom"}); push @{$self->{"cache"}}, $self->{"axiom"}; return $self->{"cache"}->[-1]; }; return $self->{"iter"}; } sub get_index { my $self = shift; my $n = shift || -1; return $self->{"cache"}->[$n] if exists $self->{"cache"}->[$n]; $self->create_iterator() unless defined $self->{"iter"}; $self->{"iter"}->() for $#{$self->{"cache"}}+1 .. $n; return $self->{"cache"}->[$n]; } sub __generate_rules { my $rules = shift; return sub { my @token = split //, shift; return join '', map { exists $rules->{$_} ? $rules->{$_} : $_ } @token; }; } 1; package main; my $rules = { A => "B-A-B", B => "A+B+A" }; my $axiom = "A"; my $sierpinski = Lindenmayer->new($axiom, $rules); my $turtle = Turtle->new; my $turtle_lut = { A => sub{$turtle->draw}, B => sub{$turtle->draw}, "-" => sub{$turtle->turn_left}, "+" => sub{$turtle->turn_right} }; $turtle_lut->{$_}->() for split //, $sierpinski->get_index(8); $turtle->to_png(); Eine Klasse Turtle realisiert (noch) sehr primitive Turtle-Grafiken unter Verwendung von Imager, die andere Klasse Lindenmayer generiert aus dem Axiom und den Regeln iterativ komplexere Ausdrücke. Das ganze ist noch recht "quick and dirty", aber zeichnet schon ganz hübsche Bilder. -- yet another amateur perl hacker
|