LSystem.pm 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. #!/usr/bin/perl
  2. # Written by jreed@itis.com, adapted by John Cristy.
  3. # Later adopted and improved by Daniel "Trizen" Șuteu.
  4. # Defined rules:
  5. # + Turn clockwise
  6. # - Turn counter-clockwise
  7. # : Mirror
  8. # [ Begin branch
  9. # ] End branch
  10. # Any upper case letter draws a line.
  11. # Any lower case letter is a no-op.
  12. package LSystem {
  13. use 5.010;
  14. use strict;
  15. use warnings;
  16. use lib qw(.);
  17. use Turtle;
  18. use Image::Magick;
  19. use Math::Trig qw(deg2rad);
  20. sub new {
  21. my ($class, %opt) = @_;
  22. my %state = (
  23. theta => deg2rad($opt{angle} // 90),
  24. scale => $opt{scale} // 1,
  25. xoff => $opt{xoff} // 0,
  26. yoff => $opt{yoff} // 0,
  27. len => $opt{len} // 5,
  28. color => $opt{color} // 'black',
  29. turtle => Turtle->new($opt{width} // 1000, $opt{height} // 1000, deg2rad($opt{turn} // 0), 1),
  30. );
  31. bless \%state, $class;
  32. }
  33. sub translate {
  34. my ($self, $letter) = @_;
  35. my %table = (
  36. '+' => sub { $self->{turtle}->turn($self->{theta}); }, # Turn clockwise
  37. '-' => sub { $self->{turtle}->turn(-$self->{theta}); }, # Turn counter-clockwise
  38. ':' => sub { $self->{turtle}->mirror(); }, # Mirror
  39. '[' => sub { push(@{$self->{statestack}}, [$self->{turtle}->state()]); }, # Begin branch
  40. ']' => sub { $self->{turtle}->setstate(@{pop(@{$self->{statestack}})}); }, # End branch
  41. );
  42. if (exists $table{$letter}) {
  43. $table{$letter}->();
  44. }
  45. elsif ($letter =~ /^[[:upper:]]\z/) {
  46. $self->{turtle}->forward($self->{len}, $self);
  47. }
  48. }
  49. sub turtle {
  50. my ($self) = @_;
  51. $self->{turtle};
  52. }
  53. sub execute {
  54. my ($self, $string, $repetitions, $filename, %rules) = @_;
  55. for (1 .. $repetitions) {
  56. $string =~ s{(.)}{$rules{$1} // $1}eg;
  57. }
  58. foreach my $command (split(//, $string)) {
  59. $self->translate($command);
  60. }
  61. $self->{turtle}->save_as($filename);
  62. }
  63. }
  64. 1;