File Coverage

blib/lib/Math/Fractal/DLA.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package Math::Fractal::DLA;
2            
3 1     1   41813 use strict;
  1         2  
  1         37  
4 1     1   4 use warnings;
  1         2  
  1         26  
5 1     1   6 use Carp;
  1         6  
  1         88  
6 1     1   5 use Exporter;
  1         2  
  1         38  
7 1     1   471 use GD;
  0            
  0            
8             use FileHandle;
9             use vars qw($AUTOLOAD);
10             use Log::LogLite;
11            
12             our @ISA = qw(Exporter);
13            
14             our @EXPORT = qw();
15             our @EXPORT_OK = qw(debug addLogMessage loadFile setSize setPoints setBackground setFile setColors setBaseColor writeFile getFractal createImage getDirection exitOnError);
16             our %EXPORT_TAGS = ( all=>[qw(debug addLogMessage loadFile setSize setPoints setBackground setFile setColors setBaseColor writeFile getFractal createImage getDirection exitOnError)] );
17            
18             our $VERSION = 0.21;
19            
20             # Constructor
21             sub new
22             {
23             my $param = shift;
24             my $class = ref($param) || $param;
25             my $self = {};
26            
27             # Set the random number generator
28             srand(time() ^ ($$ + ($$ << 15)));
29            
30             # Set default values
31             $self->{DEBUG} = 0;
32             $self->{POINTS} = 500;
33             $self->{COLORS} = 5;
34             $self->{OUTPUT} = "PNG";
35             $self->{IMG_WIDTH} = 400;
36             $self->{IMG_HEIGHT} = 200;
37             %{ $self->{BACKGROUND} } = (r => 255, g => 255, b => 255);
38             %{ $self->{BASECOLOR} } = (r => 10, g => 100, b => 100);
39             %{ $self->{VECTOR} } = (r => 50, g => 0, b => 0);
40             bless($self,$class);
41             return $self;
42             } # new
43            
44             # Set the type of the fractal and load the package
45             # Parameter: name of package
46             sub setType
47             {
48             my ($self,$type) = @_;
49             no strict 'refs';
50             unless ($type) { $self->exitOnError("No parameter defined"); }
51             eval
52             {
53             require "Math/Fractal/DLA/".$type.".pm";
54             };
55             if ($@)
56             { $self->exitOnError("Can't locate package Math::Fractal::DLA::".$type); }
57             $self->{TYPE} = $type;
58             } # setType
59            
60             # Switch debug mode on or off
61             # Parameter: debug => true || false, logfile => file name
62             sub debug
63             {
64             my $self = shift;
65             my %param = @_;
66             if ($param{debug})
67             {
68             $self->{DEBUG} = 1;
69             $self->{LOG} = new Log::LogLite($param{logfile});
70             $self->{LOG}->template(": ");
71             $self->addLogMessage("STARTING NEW DLA-FRACTAL..");
72             }
73             else
74             {
75             $self->{DEBUG} = 0;
76             }
77             } # debug
78            
79             # Add a message to the log file
80             # Parameter: message
81             sub addLogMessage
82             {
83             my ($self,$msg) = @_;
84             if ($self->{DEBUG})
85             {
86             $self->{LOG}->write($msg."\n",3);
87             }
88             } # addLogMessage
89            
90             # Load the image from a jpg or png image
91             # Parameter: filename
92             sub loadFile
93             {
94             my $self = shift;
95             my $filename = shift;
96             if (-s $filename)
97             {
98             if (($filename =~ /\.jpg$/) || ($filename =~ /\.jpeg$/))
99             {
100             $self->{IMAGE} = GD::Image->newFromJpeg($filename) || $self->exitOnError("Can't open image ".$filename);
101             $self->addLogMessage("Loading JPG from $filename");
102             $self->{OUTPUT} = "JPG";
103             }
104             elsif ($filename =~ /\.png$/)
105             {
106             $self->{IMAGE} = GD::Image->newFromPng($filename) || $self->exitOnError("Can't open image ".$filename);
107             $self->addLogMessage("Loading PNG from $filename");
108             $self->{OUTPUT} = "PNG";
109             }
110             my ($width,$height) = $self->{IMAGE}->getBounds();
111             $self->setSize(width => $width, height => $height);
112             }
113             else
114             { $self->exitOnError($filename." doesn't exist"); }
115             } # loadFile
116            
117             # Set the image size
118             # Parameter: width => xxx, height => xxx
119             sub setSize
120             {
121             my $self = shift;
122             my %param = @_;
123             if ($self->{IMAGE}) { $self->exitOnError("Can't resize existing image"); }
124             if ($param{width} !~ /^\d+$/) { $self->exitOnError("Parameter width is not a valid number"); }
125             if ($param{height} !~ /^\d+$/) { $self->exitOnError("Parameter height is not a valid number"); }
126             $self->{IMG_WIDTH} = $param{width};
127             $self->{IMG_HEIGHT} = $param{height};
128             $self->addLogMessage("Width: ".$param{width}.", Height: ".$param{height});
129             foreach my $x (0..$param{width}+1)
130             {
131             foreach my $y (0..$param{height}+1)
132             {
133             $self->{MATRIX}->[$x][$y] = 0;
134             }
135             }
136             return 1;
137             } # setSize
138            
139             # Set the number of points for the fractal
140             # Parameter: number of points
141             sub setPoints
142             {
143             my $self = shift;
144             my $number = shift;
145             if ($number)
146             {
147             unless ($number =~ /^\d+$/) { $self->exitOnError($number." is not a valid number"); }
148             $self->{POINTS} = $number;
149             $self->addLogMessage("Set max. ".$self->{POINTS}." points");
150             }
151             else { $self->exitOnError("No parameter defined"); }
152             } # setPoints
153            
154             # Get the number of points
155             sub getPoints
156             {
157             my $self = shift; return $self->{POINTS};
158             } # getPoints
159            
160             # Set the background color
161             # Parameter: r => xxx, g => xxx, b => xxx
162             sub setBackground
163             {
164             my $self = shift;
165             my %para = @_;
166             foreach my $color (keys %para)
167             {
168             unless (($para{$color} >= 0) && ($para{$color} <= 255)) { $self->exitOnError("Parameter $color is not a valid color"); }
169             }
170             %{ $self->{BACKGROUND} } = %para;
171             return 1;
172             } # setBackground
173            
174             # Set the output file
175             # Parameter: filename
176             sub setFile
177             {
178             my ($self,$filename) = @_;
179             $self->{FILE} = $filename;
180             $self->addLogMessage("Filename $filename");
181             if (($filename =~ /\.jpg$/) || ($filename =~ /\.jpeg$/))
182             { $self->{OUTPUT} = "JPG"; }
183             elsif ($filename =~ /\.png$/)
184             { $self->{OUTPUT} = "PNG"; }
185             $self->addLogMessage("Output mode: ".$self->{OUTPUT});
186             return 1;
187             } # setFile
188            
189             # Set the number of different colors
190             # Parameter: number
191             sub setColors
192             {
193             my ($self,$colors) = @_;
194             $self->{COLORS} = $colors;
195             return 1;
196             } # setColors
197            
198             # Set the base color
199             # Parameter: base_r => xxx, base_g => xxx, base_b => xxx, add_r => xxx, add_g => xxx, add_b => xxx
200             sub setBaseColor
201             {
202             my ($self) = shift;
203             my %para = @_;
204             foreach my $key (keys %para)
205             {
206             $key =~ /^[a-zA-Z]+_([rgb])$/;
207             my $colkey = $1;
208            
209             if (($key =~ /^base/) && ($para{$key} >= 0) && ($para{$key} <= 255))
210             { $self->{BASECOLOR}->{$colkey} = $para{$key}; }
211             elsif (($key =~ /^add/) && ($para{$key} >= -255) && ($para{$key} <= 255))
212             { $self->{VECTOR}->{$colkey} = $para{$key}; }
213             else
214             { $self->exitOnError($key." is not a valid parameter"); }
215             }
216             return 1;
217             } # setBaseColor
218            
219             # Draws a pixel
220             # Parameter: x => xxx, y => yyy, color => x
221             sub drawPixel
222             {
223             my $self = shift;
224             my %para = @_;
225             $self->{MATRIX}->[$para{x}][$para{y}] = $para{color};
226             } # drawPixel
227            
228             # Write the fractal to the file
229             sub writeFile
230             {
231             my ($self,$file) = @_;
232             if ($file) { $self->{FILE} = $file; }
233             if (-e $self->{FILE}) { unlink $self->{FILE}; }
234            
235             # Write to file
236             my $pic = new FileHandle;
237             $pic->open(">".$self->{FILE}) || $self->exitOnError("Can't open image ".$self->{FILE});
238             binmode $pic || $self->exitOnError("Can't change image ".$self->{FILE}." to binary mode");
239             if ($self->{OUTPUT} eq "PNG") { print $pic $self->{IMAGE}->png; }
240             elsif ($self->{OUTPUT} eq "JPG") { print $pic $self->{IMAGE}->jpeg(90); }
241             $pic->close();
242             return 1;
243             } # writeFile
244            
245             # Return the fractal for output
246             sub getFractal
247             {
248             my $self = shift;
249             if ($self->{OUTPUT} eq "PNG") { return $self->{IMAGE}->png; }
250             elsif ($self->{OUTPUT} eq "JPG") { return $self->{IMAGE}->jpeg(90); }
251             } # getFractal
252            
253             # Create the image with GD
254             sub createImage
255             {
256             my $self = $_[0];
257            
258             unless ($self->{IMAGE})
259             {
260             $self->{IMAGE} = new GD::Image($self->{IMG_WIDTH},$self->{IMG_HEIGHT});
261             $self->{IMAGE}->interlaced(0);
262             $self->{IMAGE}->transparent(-1);
263             my $bgcolor = $self->{IMAGE}->colorAllocate($self->{BACKGROUND}{r},$self->{BACKGROUND}{g},$self->{BACKGROUND}{b});
264             $self->{IMAGE}->rectangle(0,0,$self->{IMG_WIDTH},$self->{IMG_HEIGHT},$bgcolor);
265             }
266            
267             # Create the colors
268             my %color = %{ $self->{BASECOLOR} };
269             my @colors;
270             $colors[1] = $self->{IMAGE}->colorAllocate($color{r},$color{g},$color{b});
271             my %vector = %{ $self->{VECTOR} };
272             for (my $i = 2; $i <= $self->{COLORS}; $i ++)
273             {
274             if (($color{r} + $vector{r} < 256) && ($color{r} + $vector{r} >= 0)) { $color{r} += $vector{r}; }
275             if (($color{g} + $vector{g} < 256) && ($color{g} + $vector{g} >= 0)) { $color{g} += $vector{g}; }
276             if (($color{b} + $vector{b} < 256) && ($color{b} + $vector{b} >= 0)) { $color{b} += $vector{b}; }
277             $colors[$i] = $self->{IMAGE}->colorAllocate($color{r},$color{g},$color{b});
278             }
279            
280             foreach my $x (0..$self->{IMG_WIDTH})
281             {
282             foreach my $y (0..$self->{IMG_HEIGHT})
283             {
284             my $pixel_value = $self->{MATRIX}->[$x][$y];
285             if ($pixel_value > 0)
286             {
287             $self->{IMAGE}->setPixel($x,$y,$colors[$pixel_value]);
288             }
289             }
290             }
291             } # createImage
292            
293             # Get a random direction (0 - 3)
294             sub getDirection
295             {
296             return sprintf("%.0f",rand(3));
297             } # getDirection
298            
299             # Exit program if an error occured
300             # Parameter: message
301             sub exitOnError
302             {
303             my $self = shift;
304             my $msg = shift;
305             $self->addLogMessage($msg);
306             $self->debug(debug => 0);
307             croak($msg);
308             } # exitOnError
309            
310             # AUTOLOAD the missing methods
311             sub AUTOLOAD
312             {
313             our $AUTOLOAD;
314             my $self = shift;
315             my $method = $AUTOLOAD;
316             if ($method =~ /(.*)::(.*)$/) { $method = $2; }
317             no strict 'refs';
318             &{ "Math::Fractal::DLA::".$self->{TYPE}. "::".$method }($self,@_);
319             } # AUTOLOAD
320            
321             sub DESTROY
322             {
323             my $self = shift;
324             if ($self->{DEBUG})
325             {
326             $self->addLogMessage("CLOSING LOG-FILE\n");
327             }
328             } # DESTROY
329            
330             1;
331            
332             __END__