#!/usr/bin/perl

use Gimp;
use Gimp::Fu;
use Gimp::Util;
use constant PI => 3.1415926;

# find an equivalent polar value in the range of 0 to 2 pi
sub find_in_2pi {
  my ($ang) = @_;
  return $ang - int($ang/(2*PI))*2*PI + 2*PI if $ang < 0;
  return $ang - int($ang/(2*PI))*2*PI;
}

podregister {
    # Special case 360
    if (abs($arc_angle) == 360) {
        $end_angle = $start_angle + $arc_angle - abs ($arc_angle/$spokes);
    } else {
      $end_angle = $start_angle + $arc_angle;
    }

    $image->undo_group_start;

    Gimp->progress_init("Burst");
    $progress_increment = 1/$spokes;
    $progress = 0;

    my $dumb;
    ($dumb, $x1, $y1, $x2, $y2) = $image->selection_bounds;
    # $image->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
        # do $spokes worth
        for ($i = 0;
             $i < $spokes;
	     #$angle <$end_angle*PI/180-0.01;
             $i++ )
          {
            $angle = $i * abs($start_angle-$end_angle)*PI/($spokes-1)/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;

            if ($fade_dir == 1)
              {
                $drawable->paintbrush_default(4, [$x, $y, $x_start, $y_start]);
              }
            else
              {
                $drawable->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;
             $i < $spokes;
             $i++ )
          {
            $angle = $i * abs($start_angle-$end_angle)*PI/($spokes-1)/180;
            $angle += $start_angle*PI/180;

            # get the slope
            $m = sin($angle)/cos($angle);
            if (abs($m*$width/2) < $height/2)
              { # 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)
            {
              $drawable->paintbrush_default(4, [$x, $y, $x_start, $y_start]);
            }
          else
            {
              $drawable->paintbrush_default(4, [$x_start, $y_start, $x, $y]);
            }
          $progress += $progress_increment;
          Gimp->progress_update($progress);
        }
    }
  $image->undo_group_end;
  ();
};

exit main;
__END__

=head1 NAME

burst - Bursts from a central location

=head1 SYNOPSIS

<Image>/Filters/Render/Burst...

=head1 DESCRIPTION

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

=head1 PARAMETERS

 [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_SPINNER, 'start_angle', "Angle to start at, with 0 being left, and sweeping counter-clockwise.", 0, [-360, 360, 1]],
 [PF_SPINNER, 'arc_angle', "How many degrees to arc through.", 360, [-360, 360, 1]]

=head1 IMAGE TYPES

*

=head1 AUTHOR

Seth Burgess

=head1 DATE

1999-07-31

=head1 HISTORY

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
interesting 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>

Revision 03/18/2000
Changed second angle to be a sweep measurement, not an absolute angle (I
found that I was calculating a lot more by hand than I should be when
using it)

Also fixed up a bug that I'd covered up, and did a decent for loop for
a change.  Fixed up rectangle to not mess up on corner areas.

Lastly, I added a special case for 360 degrees - don't redraw the last
line for a full circle; instead re-adjust end point.  I'm not entirely
happy with this solution, but its close to what I expect to happen.  I
don't desire to litter the interface with more strange options if possible
and I suspect most users will never notice.

Revision 08/10/2003
Changed PF_SLIDER to PF_SPINNER, since they're a whole lot nicer to work with
this type of operation - getting it "close" is pretty annoying with
sliders.

=head1 LICENSE

Seth Burgess <sjburges@gimp.org>

Distributed under the same terms as Gimp-Perl.
