Thread Lindenmayer-Systeme (ein schneller Hack) (0 answers)
Opened by neniro at 2009-04-26 16:38

neniro
 2009-04-26 16:38
#120927 #120927
User since
2008-12-14
79 Artikel
BenutzerIn
[default_avatar]
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 CPAN: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

View full thread Lindenmayer-Systeme (ein schneller Hack)