-
Notifications
You must be signed in to change notification settings - Fork 34
/
LSystem.pm
81 lines (64 loc) · 2.29 KB
/
LSystem.pm
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
#!/usr/bin/perl
# Written by [email protected], adapted by John Cristy.
# Later adopted and improved by Daniel "Trizen" Șuteu.
# Defined rules:
# + Turn clockwise
# - Turn counter-clockwise
# : Mirror
# [ Begin branch
# ] End branch
# Any upper case letter draws a line.
# Any lower case letter is a no-op.
package LSystem {
use 5.010;
use strict;
use warnings;
use lib qw(.);
use Turtle;
use Image::Magick;
use Math::Trig qw(deg2rad);
sub new {
my ($class, %opt) = @_;
my %state = (
theta => deg2rad($opt{angle} // 90),
scale => $opt{scale} // 1,
xoff => $opt{xoff} // 0,
yoff => $opt{yoff} // 0,
len => $opt{len} // 5,
color => $opt{color} // 'black',
turtle => Turtle->new($opt{width} // 1000, $opt{height} // 1000, deg2rad($opt{turn} // 0), 1),
);
bless \%state, $class;
}
sub translate {
my ($self, $letter) = @_;
my %table = (
'+' => sub { $self->{turtle}->turn($self->{theta}); }, # Turn clockwise
'-' => sub { $self->{turtle}->turn(-$self->{theta}); }, # Turn counter-clockwise
':' => sub { $self->{turtle}->mirror(); }, # Mirror
'[' => sub { push(@{$self->{statestack}}, [$self->{turtle}->state()]); }, # Begin branch
']' => sub { $self->{turtle}->setstate(@{pop(@{$self->{statestack}})}); }, # End branch
);
if (exists $table{$letter}) {
$table{$letter}->();
}
elsif ($letter =~ /^[[:upper:]]\z/) {
$self->{turtle}->forward($self->{len}, $self);
}
}
sub turtle {
my ($self) = @_;
$self->{turtle};
}
sub execute {
my ($self, $string, $repetitions, $filename, %rules) = @_;
for (1 .. $repetitions) {
$string =~ s{(.)}{$rules{$1} // $1}eg;
}
foreach my $command (split(//, $string)) {
$self->translate($command);
}
$self->{turtle}->save_as($filename);
}
}
1;