#!/usr/app/bin/perl

eval 'exec /usr/app/bin/perl  -S $0 ${1+"$@"}'
    if 0; # not running under some shell

# <sjburges@gimp.org> 
#
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>

####-----
# 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.
#



# 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, and sweeping counter-clockwise.", 0, [-360, 360, 1]],
   [PF_SLIDER, 'arc_angle', "How many degrees to arc through.", 360, [-360, 360, 1]]
  ],
  [],
  [],
  sub {
    my($img,$layer, $shape, $fade_dir, $points, 
       $inside_pixels, $outside_pixels, $start_angle, $arc_angle) =@_;
    
    $pi = 3.1415927;
    
    # Special case 360
    if (abs($arc_angle) == 360) 
      {
        $end_angle = $start_angle + $arc_angle - abs ($arc_angle/$points);
      }
    else 
      {
        $end_angle = $start_angle + $arc_angle;
      }
      
    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
        # do $points worth
        for ($i = 0;
             $i < $points;
	     #$angle <$end_angle*$pi/180-0.01; 
             $i++ )
          {
            $angle = $i * abs($start_angle-$end_angle)*$pi/($points-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) 
              {        
                $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;
             $i < $points;
             $i++ )
          {
            $angle = $i * abs($start_angle-$end_angle)*$pi/($points-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) 
            {        
              $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;
