gimp/plug-ins/perl/examples/burst

241 lines
7.8 KiB
Perl
Executable File

#!/usr/bin/perl
# <sjburges@gimp.org> (original release)
#
use Gimp;
use Gimp::Fu;
use Gimp::Util;
# This script was requested by jimmac, and I thought it sounded moderately
# useful. I could have just made a couple selection masks and made it
# moderately useful, but instead I redid all the math myself to make it
# intresting and have a really nice effect on the end points (rather than
# chopping off odd-shaped brushes when the ellipse ends).
# Its good to exercise the ol geometry skills every now and then ;)
# Enjoy,
# Seth Burgess <sjburges@gimp.org>
# Gimp::set_trace(TRACE_ALL);
# find an equivalent polar value in the range of 0 to 2 pi
sub find_in_2pi
{
my ($ang) = @_;
if ($ang < 0)
{
return ($ang - int($ang/(2*3.1415926))*2*3.1415926 + 2*3.1415926);
}
return ($ang - int($ang/(2*3.1415926))*2*3.1415926);
}
# actual script
register "burst",
"Bursts from a central location\n",
"Creates a Burst of various sizes from the center of the currently
selected areas. Can create either an elliptical burst, or some portion
of said burst. Also, you can specify how much (in pixels) to leave blank on
the inside and the outside of the burst. This uses whatever the current
brush settings are, and lets you control which direction to have it draw the
fades from if you have Fade set\n",
"Seth Burgess",
"Seth Burgess <sjburges\@gimp.org>",
"1999-07-31",
N_"<Image>/Filters/Render/Burst...",
"*",
[
[PF_RADIO, "shape", "Shape To Burst Into", 0, [Rectangle => 1, Ellipse=> 0]],
[PF_RADIO, "fade_dir", "Fade Direction (if fade is set)", 0, [In => 1, Out => 0]],
[PF_VALUE, 'spokes', "How many spokes", 16],
[PF_VALUE, 'inside_pixels', "Inside Pixels", 10],
[PF_VALUE, 'outside_pixels', "Outside Pixels", 10],
[PF_SLIDER, 'start_angle', "Angle to start at, with 0 being left sweeping counter-clockwise.", 0, [-360, 360, 1]],
[PF_SLIDER, 'end_angle', "Angle to end at, with 0 being left sweeping counter-clockwise.", 360, [-360, 360, 1]]
],
[],
[],
sub {
my($img,$layer, $shape, $fade_dir, $points,
$inside_pixels, $outside_pixels, $start_angle, $end_angle) =@_;
$pi = 3.1415927;
eval { $img->undo_push_group_start };
Gimp->progress_init("Burst");
$progress_increment = 1/$points;
$progress = 0;
($dumb, $x1, $y1, $x2, $y2) = $img->selection_bounds;
$img->selection_none;
$width = $x2 - $x1;
$height = $y2 - $y1;
# print "X1 = $x1, X2 = $x2, Y1 = $y1, Y2 = $y2\n";
$center_x = $x1 + $width/2;
$center_y = $y1 + $height/2;
if ($start_angle > $end_angle)
{ # swap them
$angle = $end_angle;
$end_angle = $start_angle;
$start_angle = $angle;
}
if ($shape == 0)
{ #ellipse
# the for loop just increments $i until $angle is big enough
for ($i = 0, $angle=$start_angle*$pi/180;
$angle <$end_angle*$pi/180-0.01;
$i++ )
{
$angle = $i * abs($start_angle-$end_angle)*$pi/$points/180;
$angle += $start_angle*$pi/180;
# use the major/minor axis description of an ellipse:
# x^2 y^2
# --- + --- = 1
# a^2 b^2
#
# where a is the x axis, b is the y axis, and the equation of
# a line passing through 0 (y=mb). Solve for x&y, and pick the
# correct one for the angle.
$a = $width/2 - $outside_pixels;
$b = $height/2 - $outside_pixels;
# dimensions for an "inside ellipse"
$c = ($a>$b)?$inside_pixels:$inside_pixels*$a/$b;
$d = ($a>$b)?$inside_pixels*$b/$a:$inside_pixels;
# get the slope
$m = sin($angle)/cos($angle);
if ($m ==0) { $m = 0.000000000001; } #avoid div by 0
if ($c ==0) { $c = 0.000000000001; } #avoid div by 0
if ($d ==0) { $d = 0.000000000001; } #avoid div by 0
# find the positive solution of the quadratic for the endpoints
$x = sqrt(1/((1/$a/$a)+($m*$m/$b/$b)));
$y = sqrt(1/((1/($m*$m*$a*$a))+(1/$b/$b)));
# and find the starting points in the same manner
$x_start = sqrt(1/((1/$c/$c)+($m*$m/$d/$d)));
$y_start = sqrt(1/((1/($m*$m*$c*$c))+(1/$d/$d)));
# pick the right solution of the quadratic
if ((find_in_2pi($angle) < $pi/2) || (find_in_2pi($angle) > 3*$pi/2))
{
$x = -$x;
$x_start = -$x_start;
}
if (find_in_2pi($angle) > $pi)
{
$y = -$y;
$y_start = -$y_start;
}
# do translations to center stuff
$x = $x + $center_x;
$y = $y + $center_y;
$x_start = $x_start + $center_x;
$y_start = $y_start + $center_y;
# print "X = $x, Y = $y, M = $m\n";
if ($fade_dir == 1)
{
$layer->paintbrush_default(4, [$x, $y, $x_start, $y_start]);
}
else
{
$layer->paintbrush_default(4, [$x_start, $y_start, $x, $y]);
}
$progress += $progress_increment;
Gimp->progress_update($progress);
}
}
else
{ #rectangle
# The idea here is to see where the line intersects with the
# rightmost line. If the abs of that is higer than the height,
# see where it intersects the top instead.
#print "width = $width, height = $height\n";
for ($i = 0, $angle=$start_angle*$pi/180;
$angle <$end_angle*$pi/180-0.01;
$i++ )
{
$angle = $i * abs($start_angle-$end_angle)*$pi/$points/180;
$angle += $start_angle*$pi/180;
# get the slope
$m = sin($angle)/cos($angle);
# print "M = $m\n";
if (abs($m*$width/2) < $height/2-$outside_pixels)
{ # draw on the right/left borders
$x = $width/2-$outside_pixels;
$y = $m*($width/2-$outside_pixels);
$x_start = ($width>$height)
?$inside_pixels
:$inside_pixels*$width/$height;
$y_start = ($width>$height)
?$m*$inside_pixels
:$m*$inside_pixels*$width/$height;
}
else
{ # draw on the top/bottom borders
$y = $height/2-$outside_pixels;
$x = ($height/2-$outside_pixels)/$m;
$y_start = ($width>$height)
?$inside_pixels*$height/$width
:$inside_pixels;
$x_start = ($width>$height)
?$inside_pixels*$height/$width/$m
:$inside_pixels/$m;
}
# the method of finding points by lines like above makes picking right
# values kinda icky, as shown by these if statements.
if ((find_in_2pi($angle) <= $pi/2) || (find_in_2pi($angle) > 3*$pi/2))
{
$x = -abs($x);
$x_start = -abs($x_start);
}
else
{
$x = abs($x);
$x_start = abs($x_start);
}
if (find_in_2pi($angle) > $pi)
{
$y = -abs($y);
$y_start = -abs($y_start);
}
else
{
$y = abs($y);
$y_start = abs($y_start);
}
# do translations to center stuff
$x = $x + $center_x;
$y = $y + $center_y;
$x_start = $x_start + $center_x;
$y_start = $y_start + $center_y;
if ($fade_dir == 1)
{
$layer->paintbrush_default(4, [$x, $y, $x_start, $y_start]);
}
else
{
$layer->paintbrush_default(4, [$x_start, $y_start, $x, $y]);
}
$progress += $progress_increment;
Gimp->progress_update($progress);
}
}
eval { $img->undo_push_group_end };
return();
};
exit main;