package Math::Fractal::DLA::Explode;
use Math::Fractal::DLA qw(:all);
use strict;
use warnings;
use Exporter;
use GD;
our @ISA = qw(Math::Fractal::DLA Exporter);
our @EXPORT_OK = qw();
our @EXPORT = qw();
our $VERSION = 0.21;
sub new
{
my $param = shift;
my $class = ref($param) || $param;
my $self = new Math::Fractal::DLA;
$self->{TYPE} = "Explode";
bless ($self,$class);
return $self;
} # new
sub generate
{
my $self = $_[0];
# Set the starting point in the matrix
# if the value is not available it'll be set to the middle of the image
if (($self->{START}->[0]) && ($self->{START}->[1]))
{
$self->{MATRIX}->[$self->{START}->[0]][$self->{START}->[1]] = 1;
}
else
{
$self->{START}->[0] = int($self->{IMG_WIDTH} / 2);
$self->{START}->[1] = int($self->{IMG_HEIGHT} / 2);
$self->{MATRIX}->[$self->{START}->[0]][$self->{START}->[1]] = 1;
}
$self->addLogMessage("Fractal mode ".$self->{TYPE});
my $setpoints = 0;
my $points = $self->{POINTS};
my $color_interval = int($points / $self->{COLORS});
my $color_value = 0;
my $newpoint = 1;
my $width = $self->{IMG_WIDTH}; my $height = $self->{IMG_HEIGHT};
my $x_min = 0; my $x_max = $width; my $y_min = 0; my $y_max = $height;
if (${$self->{START}}[0] - 2 > 0) { $x_min = ${$self->{START}}[0] - 2; }
if (${$self->{START}}[0] + 2 < $width) { $x_max = $x_max = ${$self->{START}}[0] + 2; }
if (${$self->{START}}[1] - 2 > 0) { $y_min = $y_min = ${$self->{START}}[1] - 2; }
if (${$self->{START}}[1] + 2 < $height) { $y_max = ${$self->{START}}[1] + 2; }
$self->addLogMessage("Starting point: ".${$self->{START}}[0]." ".${$self->{START}}[1]);
my $rand_width = $x_max - $x_min;
my $rand_height = $y_max - $y_min;
my $direction = -1;
my $steps = 500;
$self->addLogMessage("Starting area:");
$self->addLogMessage("min X: ".$x_min." max X: ".$x_max);
$self->addLogMessage("min Y: ".$y_min." max Y: ".$y_max);
while ($setpoints < $points)
{
if ((($setpoints % $color_interval) == 0) && ($newpoint == 1))
{ $color_value ++; $self->addLogMessage("New color $color_value after $setpoints points"); }
$newpoint = 0;
$rand_width = $x_max - $x_min;
$rand_height = $y_max - $y_min;
my $x = 0; my $y = 0;
$direction++;
if ($direction == 4) { $direction = 0; }
if ($direction == 0)
{ $x = $x_min + sprintf("%.0f",rand($rand_width)); $y = $y_min; $steps = $rand_height; }
elsif ($direction == 1)
{ $y = $y_min + sprintf("%.0f",rand($rand_height)); $x = $x_max; $steps = $rand_width; }
elsif ($direction == 2)
{ $x = $x_min + sprintf("%.0f",rand($rand_width)); $y = $y_max; $steps = $rand_height; }
elsif ($direction == 3)
{ $y = $y_min + sprintf("%.0f",rand($rand_height)); $x = $x_min; $steps = $rand_width; }
if ($self->{MATRIX}->[$x][$y] > 0) { $setpoints ++; next; }
for (my $i = 0; $i < $steps; $i ++)
{
if (($self->{MATRIX}->[$x-1][$y] > 0) ||
($self->{MATRIX}->[$x+1][$y] > 0) ||
($self->{MATRIX}->[$x][$y-1] > 0) ||
($self->{MATRIX}->[$x][$y+1] > 0))
{
$self->{MATRIX}->[$x][$y] = $color_value;
$setpoints ++;
$newpoint = 1;
last;
}
else
{
if (($direction == 0) && ($y_max > ($y + 1))) { $y = $y + 1; }
elsif ($direction == 1) { $x = $x - 1; }
elsif ($direction == 2) { $y = $y - 1; }
elsif ($direction == 3) { $x = $x + 1; }
}
}
if (($x == $x_min) && ($x_min > 0)) { $x_min = $x_min - 1; }
elsif (($x == $x_max) && ($x_max < $width - 1)) { $x_max = $x_max + 1; }
elsif (($y == $y_min) && ($y_min > 0)) { $y_min = $y_min - 1; }
elsif (($y == $y_max) && ($y_max < $height - 1)) { $y_max = $y_max + 1; }
}
if ($self->{DEBUG}) { $self->drawRectangle(x_min => $x_min, x_max => $x_max,y_min => $y_min, y_max => $y_max); }
$self->createImage();
} # generate
# Set the start position for the fractal
# Parameter: x => x-axis, y => y => y-axis
sub setStartPosition
{
my $self = shift;
my %coordinate = @_;
foreach my $coord (keys %coordinate)
{
if ($coordinate{$coord} !~ /^\d+$/) { $self->exitOnError("Parameter $coord not valid"); }
}
if ($coordinate{x} > $self->{IMG_WIDTH}) { $self->exitOnError("Parameter x is outside of image"); }
if ($coordinate{y} > $self->{IMG_HEIGHT}) { $self->exitOnError("Parameter y is outside of image"); }
@{$self->{START}} = ($coordinate{x},$coordinate{y});
return 1;
} # setStartPosition
# Draws a rectangle
# Parameter: x_min => xxx, x_max => xxx, y_min => xxx, y_max => xxx
sub drawRectangle
{
my $self = shift;
my %para = @_;
$self->addLogMessage("Area: x_min: ".$para{x_min}." x_max: ".$para{x_max}." y_min: ".$para{y_min}." y_max: ".$para{y_max});
for (my $a = $para{x_min}; $a <= $para{x_max}; $a++)
{
$self->{MATRIX}->[$a][$para{y_min}] = 1;
$self->{MATRIX}->[$a][$para{y_max}] = 1;
}
for (my $a = $para{y_min}; $a <= $para{y_max}; $a++)
{
$self->{MATRIX}->[$para{x_min}][$a] = 1;
$self->{MATRIX}->[$para{x_max}][$a] = 1;
}
} # drawRectangle
1;
__END__
# Below is the documentation for Math::Fractal::DLA::Explode
=head1 NAME
Math::Fractal::DLA::Explode
=head1 SYNOPSIS
use Math::Fractal::DLA::Explode;
$fractal = new Math::Fractal::DLA::Explode;
# Set the values of Math::Fractal::DLA
$fractal->debug( debug => 1, logfile => FILE );
.
.
$fractal->setColors(5);
# Set the target point (center of the explosion)
$self->setStartPosition ( x => X, y => Y );
# Generate the fractal
$fractal->generate();
# Write the generated fractal to a file
$fractal->writeFile();
=head1 DESCRIPTION
Math::Fractal::DLA::Explode is the implementation of a standard Diffusion Limited Aggregation (DLA) fractal
=head1 OVERVIEW
The module Math::Fractal::DLA::Explode is the implementation of the most widely known type of DLA fractals. The fractal is created by single particles which move from an outter rectangle towards the target area. By hitting the area the particle becomes a part of the target area and the fractal grows.
=head1 METHODS
Math::Fractal::DLA::Explode extends the super class with two methods:
=over 4
=item setStartPosition ( x => X, y => Y )
Sets the position where the fractal will start to grow
=item generate ( )
Generates the fractal
=back
=head1 AUTHOR
Wolfgang Gruber, w.gruber@urldirect.at
=head1 SEE ALSO
Math::Fractal::DLA
Lincoln D. Stein's GD module
=head1 COPYRIGHT
Copyright (c) 2002 by Wolfgang Gruber. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
=cut