merge circle outline branch
authorTony Cook <tony@develop=help.com>
Thu, 25 Feb 2010 08:37:52 +0000 (08:37 +0000)
committerTony Cook <tony@develop=help.com>
Thu, 25 Feb 2010 08:37:52 +0000 (08:37 +0000)
Changes
Imager.pm
Imager.xs
draw.c
imager.h
lib/Imager/Draw.pod
t/t21draw.t
typemap

diff --git a/Changes b/Changes
index 2e5dded..e03569d 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,5 +1,11 @@
 Imager release history.  Older releases can be found in Changes.old
 
+Imager 0.73 - unreleased
+===========
+
+ - implement outline circles, both anti-aliased and not
+   https://rt.cpan.org/Ticket/Display.html?id=19755
+
 Imager 0.72 - 09 Dec 2009
 ===========
 
index b7d475c..ab501b4 100644 (file)
--- a/Imager.pm
+++ b/Imager.pm
@@ -2791,12 +2791,18 @@ sub box {
 sub arc {
   my $self=shift;
   unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
-  my $dflcl=i_color_new(255,255,255,255);
-  my %opts=(color=>$dflcl,
-           'r'=>_min($self->getwidth(),$self->getheight())/3,
-           'x'=>$self->getwidth()/2,
-           'y'=>$self->getheight()/2,
-           'd1'=>0, 'd2'=>361, @_);
+  my $dflcl= [ 255, 255, 255, 255];
+  my $good = 1;
+  my %opts=
+    (
+     color=>$dflcl,
+     'r'=>_min($self->getwidth(),$self->getheight())/3,
+     'x'=>$self->getwidth()/2,
+     'y'=>$self->getheight()/2,
+     'd1'=>0, 'd2'=>361, 
+     filled => 1,
+     @_,
+    );
   if ($opts{aa}) {
     if ($opts{fill}) {
       unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
@@ -2810,7 +2816,7 @@ sub arc {
       i_arc_aa_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'},
                     $opts{'d2'}, $opts{fill}{fill});
     }
-    else {
+    elsif ($opts{filled}) {
       my $color = _color($opts{'color'});
       unless ($color) { 
        $self->{ERRSTR} = $Imager::ERRSTR; 
@@ -2825,6 +2831,15 @@ sub arc {
                 $opts{'d1'}, $opts{'d2'}, $color); 
       }
     }
+    else {
+      my $color = _color($opts{'color'});
+      if ($opts{d2} - $opts{d1} >= 360) {
+       $good = i_circle_out_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{'r'}, $color);
+      }
+      else {
+       $good = i_arc_out_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{'r'}, $opts{'d1'}, $opts{'d2'}, $color);
+      }
+    }
   }
   else {
     if ($opts{fill}) {
@@ -2843,12 +2858,26 @@ sub arc {
       my $color = _color($opts{'color'});
       unless ($color) { 
        $self->{ERRSTR} = $Imager::ERRSTR; 
-       return; 
+       return;
+      }
+      if ($opts{filled}) {
+       i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
+             $opts{'d1'}, $opts{'d2'}, $color); 
+      }
+      else {
+       if ($opts{d1} == 0 && $opts{d2} == 361) {
+         $good = i_circle_out($self->{IMG}, $opts{x}, $opts{y}, $opts{r}, $color);
+       }
+       else {
+         $good = i_arc_out($self->{IMG}, $opts{x}, $opts{y}, $opts{r}, $opts{d1}, $opts{d2}, $color);
+       }
       }
-      i_arc($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},
-           $opts{'d1'}, $opts{'d2'}, $color); 
     }
   }
+  unless ($good) {
+    $self->_set_error($self->_error_as_msg);
+    return;
+  }
 
   return $self;
 }
index 080be4e..3821025 100644 (file)
--- a/Imager.xs
+++ b/Imager.xs
@@ -1468,6 +1468,41 @@ i_circle_aa(im,x,y,rad,val)
              float     rad
           Imager::Color    val
 
+int
+i_circle_out(im,x,y,rad,val)
+    Imager::ImgRaw     im
+            i_img_dim     x
+            i_img_dim     y
+             i_img_dim     rad
+          Imager::Color    val
+
+int
+i_circle_out_aa(im,x,y,rad,val)
+    Imager::ImgRaw     im
+            i_img_dim     x
+            i_img_dim     y
+             i_img_dim     rad
+          Imager::Color    val
+
+int
+i_arc_out(im,x,y,rad,d1,d2,val)
+    Imager::ImgRaw     im
+            i_img_dim     x
+            i_img_dim     y
+             i_img_dim     rad
+            float d1
+            float d2
+          Imager::Color    val
+
+int
+i_arc_out_aa(im,x,y,rad,d1,d2,val)
+    Imager::ImgRaw     im
+            i_img_dim     x
+            i_img_dim     y
+             i_img_dim     rad
+            float d1
+            float d2
+          Imager::Color    val
 
 
 void
diff --git a/draw.c b/draw.c
index baeca5c..1d84d95 100644 (file)
--- a/draw.c
+++ b/draw.c
@@ -5,6 +5,74 @@
 #include "imrender.h"
 #include <limits.h>
 
+int
+i_ppix_norm(i_img *im, i_img_dim x, i_img_dim y, i_color const *col) {
+  i_color src;
+  i_color work;
+  int dest_alpha;
+  int remains;
+
+  if (!col->channel[3])
+    return 0;
+
+  switch (im->channels) {
+  case 1:
+    work = *col;
+    i_adapt_colors(2, 4, &work, 1);
+    i_gpix(im, x, y, &src);
+    remains = 255 - work.channel[1];
+    src.channel[0] = (src.channel[0] * remains
+                     + work.channel[0] * work.channel[1]) / 255;
+    return i_ppix(im, x, y, &src);
+
+  case 2:
+    work = *col;
+    i_adapt_colors(2, 4, &work, 1);
+    i_gpix(im, x, y, &src);
+    dest_alpha = work.channel[1] + remains * src.channel[1] / 255;
+    if (work.channel[1] == 255) {
+      return i_ppix(im, x, y, &work);
+    }
+    else {
+      src.channel[0] = (work.channel[1] * work.channel[0]
+                       + remains * src.channel[0] * src.channel[1] / 255) / dest_alpha;
+      src.channel[1] = dest_alpha;
+      return i_ppix(im, x, y, &src);
+    }
+
+  case 3:
+    work = *col;
+    i_gpix(im, x, y, &src);
+    remains = 255 - work.channel[3];
+    src.channel[0] = (src.channel[0] * remains
+                     + work.channel[0] * work.channel[3]) / 255;
+    src.channel[1] = (src.channel[1] * remains
+                     + work.channel[1] * work.channel[3]) / 255;
+    src.channel[2] = (src.channel[2] * remains
+                     + work.channel[2] * work.channel[3]) / 255;
+    return i_ppix(im, x, y, &src);
+
+  case 4:
+    work = *col;
+    i_gpix(im, x, y, &src);
+    dest_alpha = work.channel[3] + remains * src.channel[3] / 255;
+    if (work.channel[3] == 255) {
+      return i_ppix(im, x, y, &work);
+    }
+    else {
+      src.channel[0] = (work.channel[3] * work.channel[0]
+                       + remains * src.channel[0] * src.channel[3] / 255) / dest_alpha;
+      src.channel[1] = (work.channel[3] * work.channel[1]
+                       + remains * src.channel[1] * src.channel[3] / 255) / dest_alpha;
+      src.channel[2] = (work.channel[3] * work.channel[2]
+                       + remains * src.channel[2] * src.channel[3] / 255) / dest_alpha;
+      src.channel[3] = dest_alpha;
+      return i_ppix(im, x, y, &src);
+    }
+  }
+  return 0;
+}
+
 static void
 cfill_from_btm(i_img *im, i_fill_t *fill, struct i_bitmap *btm, 
               int bxmin, int bxmax, int bymin, int bymax);
@@ -290,7 +358,7 @@ i_arc_aa(i_img *im, double x, double y, double rad, double d1, double d2,
   double *xvals, *yvals;
   int count;
 
-  arc_poly(&count, &xvals, &yvals, x, y, rad, d1, d2);
+  arc_poly(&count, &xvals, &yvals, x+0.5, y+0.5, rad, d1, d2);
 
   i_poly_aa(im, count, xvals, yvals, val);
 
@@ -458,6 +526,518 @@ i_circle_aa(i_img *im, float x, float y, float rad, const i_color *val) {
   i_mmarray_dst(&dot);
 }
 
+/*
+=item i_circle_out(im, x, y, r, col)
+
+=category Drawing
+=synopsis i_circle_out(im, 50, 50, 45, &color);
+
+Draw a circle outline centered at (x,y) with radius r,
+non-anti-aliased.
+
+Parameters:
+
+=over
+
+=item *
+
+(x, y) - the center of the circle
+
+=item *
+
+r - the radius of the circle in pixels, must be non-negative
+
+=back
+
+Returns non-zero on success.
+
+Implementation:
+
+=cut
+*/
+
+int
+i_circle_out(i_img *im, i_img_dim xc, i_img_dim yc, i_img_dim r,
+            const i_color *col) {
+  i_img_dim x, y;
+  i_img_dim dx, dy;
+  int error;
+
+  i_clear_error();
+
+  if (r < 0) {
+    i_push_error(0, "circle: radius must be non-negative");
+    return 0;
+  }
+
+  i_ppix(im, xc+r, yc, col);
+  i_ppix(im, xc-r, yc, col);
+  i_ppix(im, xc, yc+r, col);
+  i_ppix(im, xc, yc-r, col);
+
+  x = 0;
+  y = r;
+  dx = 1;
+  dy = -2 * r;
+  error = 1 - r;
+  while (x < y) {
+    if (error >= 0) {
+      --y;
+      dy += 2;
+      error += dy;
+    }
+    ++x;
+    dx += 2;
+    error += dx;
+
+    i_ppix(im, xc + x, yc + y, col);
+    i_ppix(im, xc + x, yc - y, col);
+    i_ppix(im, xc - x, yc + y, col);
+    i_ppix(im, xc - x, yc - y, col);
+    if (x != y) {
+      i_ppix(im, xc + y, yc + x, col);
+      i_ppix(im, xc + y, yc - x, col);
+      i_ppix(im, xc - y, yc + x, col);
+      i_ppix(im, xc - y, yc - x, col);
+    }
+  }
+
+  return 1;
+}
+
+/*
+=item arc_seg(angle)
+
+Convert an angle in degrees into an angle measure we can generate
+simply from the numbers we have when drawing the circle.
+
+=back
+*/
+
+static i_img_dim
+arc_seg(double angle, int scale) {
+  i_img_dim seg = (angle + 45) / 90;
+  double remains = angle - seg * 90; /* should be in the range [-45,45] */
+  int sign = remains < 0 ? -1 : remains ? 1 : 0;
+
+  while (seg > 4)
+    seg -= 4;
+  if (seg == 4 && remains > 0)
+    seg = 0;
+
+  return scale * (seg * 2 + sin(remains * PI/180));
+}
+
+/*
+=item i_arc_out(im, x, y, r, d1, d2, col)
+
+=category Drawing
+=synopsis i_arc_out(im, 50, 50, 45, 45, 135, &color);
+
+Draw an arc outline centered at (x,y) with radius r, non-anti-aliased
+over the angle range d1 through d2 degrees.
+
+Parameters:
+
+=over
+
+=item *
+
+(x, y) - the center of the circle
+
+=item *
+
+r - the radius of the circle in pixels, must be non-negative
+
+=item *
+
+d1, d2 - the range of angles to draw the arc over, in degrees.
+
+=back
+
+Returns non-zero on success.
+
+Implementation:
+
+=cut
+*/
+
+int
+i_arc_out(i_img *im, i_img_dim xc, i_img_dim yc, i_img_dim r,
+         float d1, float d2, const i_color *col) {
+  i_img_dim x, y;
+  i_img_dim dx, dy;
+  int error;
+  i_img_dim segs[2][2];
+  int seg_count;
+  i_img_dim sin_th;
+  i_img_dim seg_d1, seg_d2;
+  int seg_num;
+  double inv_r;
+  i_img_dim scale = r + 1;
+  i_img_dim seg1 = scale * 2;
+  i_img_dim seg2 = scale * 4;
+  i_img_dim seg3 = scale * 6;
+  i_img_dim seg4 = scale * 8;
+
+  i_clear_error();
+
+  if (r <= 0) {
+    i_push_error(0, "arc: radius must be non-negative");
+    return 0;
+  }
+  if (d1 + 360 <= d2)
+    return i_circle_out(im, xc, yc, r, col);
+
+  if (d1 < 0)
+    d1 += 360 * floor((-d1 + 359) / 360);
+  if (d2 < 0)
+    d2 += 360 * floor((-d2 + 359) / 360);
+  d1 = fmod(d1, 360);
+  d2 = fmod(d2, 360);
+  seg_d1 = arc_seg(d1, scale);
+  seg_d2 = arc_seg(d2, scale);
+  if (seg_d2 < seg_d1) {
+    /* split into two segments */
+    segs[0][0] = 0;
+    segs[0][1] = seg_d2;
+    segs[1][0] = seg_d1;
+    segs[1][1] = seg4;
+    seg_count = 2;
+  }
+  else {
+    segs[0][0] = seg_d1;
+    segs[0][1] = seg_d2;
+    seg_count = 1;
+  }
+
+  for (seg_num = 0; seg_num < seg_count; ++seg_num) {
+    i_img_dim seg_start = segs[seg_num][0];
+    i_img_dim seg_end = segs[seg_num][1];
+    if (seg_start == 0)
+      i_ppix(im, xc+r, yc, col);
+    if (seg_start <= seg1 && seg_end >= seg1)
+      i_ppix(im, xc, yc+r, col);
+    if (seg_start <= seg2 && seg_end >= seg2)
+      i_ppix(im, xc-r, yc, col);
+    if (seg_start <= seg3 && seg_end >= seg3)
+      i_ppix(im, xc, yc-r, col);
+
+    y = 0;
+    x = r;
+    dy = 1;
+    dx = -2 * r;
+    error = 1 - r;
+    while (y < x) {
+      if (error >= 0) {
+       --x;
+       dx += 2;
+       error += dx;
+      }
+      ++y;
+      dy += 2;
+      error += dy;
+      
+      sin_th = y;
+      if (seg_start <= sin_th && seg_end >= sin_th)
+       i_ppix(im, xc + x, yc + y, col);
+      if (seg_start <= seg1 - sin_th && seg_end >= seg1 - sin_th)
+       i_ppix(im, xc + y, yc + x, col);
+
+      if (seg_start <= seg1 + sin_th && seg_end >= seg1 + sin_th)
+       i_ppix(im, xc - y, yc + x, col);
+      if (seg_start <= seg2 - sin_th && seg_end >= seg2 - sin_th)
+       i_ppix(im, xc - x, yc + y, col);
+      
+      if (seg_start <= seg2 + sin_th && seg_end >= seg2 + sin_th)
+       i_ppix(im, xc - x, yc - y, col);
+      if (seg_start <= seg3 - sin_th && seg_end >= seg3 - sin_th)
+       i_ppix(im, xc - y, yc - x, col);
+
+      if (seg_start <= seg3 + sin_th && seg_end >= seg3 + sin_th)
+       i_ppix(im, xc + y, yc - x, col);
+      if (seg_start <= seg4 - sin_th && seg_end >= seg4 - sin_th)
+       i_ppix(im, xc + x, yc - y, col);
+    }
+  }
+
+  return 1;
+}
+
+static double
+cover(i_img_dim r, i_img_dim j) {
+  float rjsqrt = sqrt(r*r - j*j);
+
+  return ceil(rjsqrt) - rjsqrt;
+}
+
+/*
+=item i_circle_out_aa(im, xc, yc, r, col)
+
+=synopsis i_circle_out_aa(im, 50, 50, 45, &color);
+
+Draw a circle outline centered at (x,y) with radius r, anti-aliased.
+
+Parameters:
+
+=over
+
+=item *
+
+(xc, yc) - the center of the circle
+
+=item *
+
+r - the radius of the circle in pixels, must be non-negative
+
+=item *
+
+col - an i_color for the color to draw in.
+
+=back
+
+Returns non-zero on success.
+
+=cut
+
+Based on "Fast Anti-Aliased Circle Generation", Xiaolin Wu, Graphics
+Gems.
+
+I use floating point for I<D> since for large circles the precision of
+a [0,255] value isn't sufficient when approaching the end of the
+octant.
+
+*/
+
+int
+i_circle_out_aa(i_img *im, i_img_dim xc, i_img_dim yc, i_img_dim r, const i_color *col) {
+  i_img_dim i, j;
+  double t;
+  i_color workc = *col;
+  int orig_alpha = col->channel[3];
+
+  i_clear_error();
+  if (r <= 0) {
+    i_push_error(0, "arc: radius must be non-negative");
+    return 0;
+  }
+  i = r;
+  j = 0;
+  t = 0;
+  i_ppix_norm(im, xc+i, yc+j, col);
+  i_ppix_norm(im, xc-i, yc+j, col);
+  i_ppix_norm(im, xc+j, yc+i, col);
+  i_ppix_norm(im, xc+j, yc-i, col);
+
+  while (i > j+1) {
+    double d;
+    int cv, inv_cv;
+    i_color p;
+    int ch;
+    j++;
+    d = cover(r, j);
+    cv = (int)(d * 255 + 0.5);
+    inv_cv = 255-cv;
+    if (d < t) {
+      --i;
+    }
+    if (inv_cv) {
+      workc.channel[3] = orig_alpha * inv_cv / 255;
+      i_ppix_norm(im, xc+i, yc+j, &workc);
+      i_ppix_norm(im, xc-i, yc+j, &workc);
+      i_ppix_norm(im, xc+i, yc-j, &workc);
+      i_ppix_norm(im, xc-i, yc-j, &workc);
+
+      if (i != j) {
+       i_ppix_norm(im, xc+j, yc+i, &workc);
+       i_ppix_norm(im, xc-j, yc+i, &workc);
+       i_ppix_norm(im, xc+j, yc-i, &workc);
+       i_ppix_norm(im, xc-j, yc-i, &workc);
+      }
+    }
+    if (cv && i > j) {
+      workc.channel[3] = orig_alpha * cv / 255;
+      i_ppix_norm(im, xc+i-1, yc+j, &workc);
+      i_ppix_norm(im, xc-i+1, yc+j, &workc);
+      i_ppix_norm(im, xc+i-1, yc-j, &workc);
+      i_ppix_norm(im, xc-i+1, yc-j, &workc);
+
+      if (j != i-1) {
+       i_ppix_norm(im, xc+j, yc+i-1, &workc);
+       i_ppix_norm(im, xc-j, yc+i-1, &workc);
+       i_ppix_norm(im, xc+j, yc-i+1, &workc);
+       i_ppix_norm(im, xc-j, yc-i+1, &workc);
+      }
+    }
+    t = d;
+  }
+
+  return 1;
+}
+
+/*
+=item i_arc_out_aa(im, xc, yc, r, d1, d2, col)
+
+=synopsis i_arc_out_aa(im, 50, 50, 45, 45, 125, &color);
+
+Draw a circle arc outline centered at (x,y) with radius r, from angle
+d1 degrees through angle d2 degrees, anti-aliased.
+
+Parameters:
+
+=over
+
+=item *
+
+(xc, yc) - the center of the circle
+
+=item *
+
+r - the radius of the circle in pixels, must be non-negative
+
+=item *
+
+d1, d2 - the range of angle in degrees to draw the arc through.  If
+d2-d1 >= 360 a full circle is drawn.
+
+=back
+
+Returns non-zero on success.
+
+=cut
+
+Based on "Fast Anti-Aliased Circle Generation", Xiaolin Wu, Graphics
+Gems.
+
+*/
+
+int
+i_arc_out_aa(i_img *im, i_img_dim xc, i_img_dim yc, i_img_dim r, float d1, float d2, const i_color *col) {
+  i_img_dim i, j;
+  double t;
+  i_color workc = *col;
+  i_img_dim segs[2][2];
+  int seg_count;
+  i_img_dim sin_th;
+  i_img_dim seg_d1, seg_d2;
+  int seg_num;
+  int orig_alpha = col->channel[3];
+  i_img_dim scale = r + 1;
+  i_img_dim seg1 = scale * 2;
+  i_img_dim seg2 = scale * 4;
+  i_img_dim seg3 = scale * 6;
+  i_img_dim seg4 = scale * 8;
+
+  i_clear_error();
+  if (r <= 0) {
+    i_push_error(0, "arc: radius must be non-negative");
+    return 0;
+  }
+  if (d1 + 360 <= d2)
+    return i_circle_out_aa(im, xc, yc, r, col);
+
+  if (d1 < 0)
+    d1 += 360 * floor((-d1 + 359) / 360);
+  if (d2 < 0)
+    d2 += 360 * floor((-d2 + 359) / 360);
+  d1 = fmod(d1, 360);
+  d2 = fmod(d2, 360);
+  seg_d1 = arc_seg(d1, scale);
+  seg_d2 = arc_seg(d2, scale);
+  if (seg_d2 < seg_d1) {
+    /* split into two segments */
+    segs[0][0] = 0;
+    segs[0][1] = seg_d2;
+    segs[1][0] = seg_d1;
+    segs[1][1] = seg4;
+    seg_count = 2;
+  }
+  else {
+    segs[0][0] = seg_d1;
+    segs[0][1] = seg_d2;
+    seg_count = 1;
+  }
+
+  for (seg_num = 0; seg_num < seg_count; ++seg_num) {
+    i_img_dim seg_start = segs[seg_num][0];
+    i_img_dim seg_end = segs[seg_num][1];
+
+    i = r;
+    j = 0;
+    t = 0;
+
+    if (seg_start == 0)
+      i_ppix_norm(im, xc+i, yc+j, col);
+    if (seg_start <= seg1 && seg_end >= seg1)
+      i_ppix_norm(im, xc+j, yc+i, col);
+    if (seg_start <= seg2 && seg_end >= seg2)
+      i_ppix_norm(im, xc-i, yc+j, col);
+    if (seg_start <= seg3 && seg_end >= seg3)
+      i_ppix_norm(im, xc+j, yc-i, col);
+    
+    while (i > j+1) {
+      int cv, inv_cv;
+      i_color p;
+      int ch;
+      double d;
+      j++;
+      d = cover(r, j);
+      cv = (int)(d * 255 + 0.5);
+      inv_cv = 255-cv;
+      if (d < t) {
+       --i;
+      }
+      sin_th = j;
+      if (inv_cv) {
+       workc.channel[3] = orig_alpha * inv_cv / 255;
+
+       if (seg_start <= sin_th && seg_end >= sin_th)
+         i_ppix_norm(im, xc+i, yc+j, &workc);
+       if (seg_start <= seg2 - sin_th && seg_end >= seg2 - sin_th)
+         i_ppix_norm(im, xc-i, yc+j, &workc);
+       if (seg_start <= seg4 - sin_th && seg_end >= seg4 - sin_th)
+         i_ppix_norm(im, xc+i, yc-j, &workc);
+       if (seg_start <= seg2 + sin_th && seg_end >= seg2 + sin_th)
+         i_ppix_norm(im, xc-i, yc-j, &workc);
+       
+       if (i != j) {
+         if (seg_start <= seg1 - sin_th && seg_end >= seg1 - sin_th)
+           i_ppix_norm(im, xc+j, yc+i, &workc);
+         if (seg_start <= seg1 + sin_th && seg_end >= seg1 + sin_th)
+           i_ppix_norm(im, xc-j, yc+i, &workc);
+         if (seg_start <= seg3 + sin_th && seg_end >= seg3 + sin_th)
+           i_ppix_norm(im, xc+j, yc-i, &workc);
+         if (seg_start <= seg3 - sin_th && seg_end >= seg3 - sin_th)
+           i_ppix_norm(im, xc-j, yc-i, &workc);
+       }
+      }
+      if (cv && i > j) {
+       workc.channel[3] = orig_alpha * cv / 255;
+       if (seg_start <= sin_th && seg_end >= sin_th)
+         i_ppix_norm(im, xc+i-1, yc+j, &workc);
+       if (seg_start <= seg2 - sin_th && seg_end >= seg2 - sin_th)
+         i_ppix_norm(im, xc-i+1, yc+j, &workc);
+       if (seg_start <= seg4 - sin_th && seg_end >= seg4 - sin_th)
+         i_ppix_norm(im, xc+i-1, yc-j, &workc);
+       if (seg_start <= seg2 + sin_th && seg_end >= seg2 + sin_th)
+         i_ppix_norm(im, xc-i+1, yc-j, &workc);
+       
+       if (seg_start <= seg1 - sin_th && seg_end >= seg1 - sin_th)
+         i_ppix_norm(im, xc+j, yc+i-1, &workc);
+       if (seg_start <= seg1 + sin_th && seg_end >= seg1 + sin_th)
+         i_ppix_norm(im, xc-j, yc+i-1, &workc);
+       if (seg_start <= seg3 + sin_th && seg_end >= seg3 + sin_th)
+         i_ppix_norm(im, xc+j, yc-i+1, &workc);
+       if (seg_start <= seg3 - sin_th && seg_end >= seg3 - sin_th)
+         i_ppix_norm(im, xc-j, yc-i+1, &workc);
+      }
+      t = d;
+    }
+  }
+
+  return 1;
+}
+
 /*
 =item i_box(im, x1, y1, x2, y2, color)
 
index e44311c..e8246ce 100644 (file)
--- a/imager.h
+++ b/imager.h
@@ -168,10 +168,14 @@ void i_box_cfill(i_img *im, int x1, int y1, int x2, int y2, i_fill_t *fill);
 void i_line        (i_img *im,int x1,int y1,int x2,int y2,const i_color *val, int endp);
 void i_line_aa     (i_img *im,int x1,int y1,int x2,int y2,const i_color *val, int endp);
 void i_arc         (i_img *im,int x,int y,float rad,float d1,float d2,const i_color *val);
+int i_arc_out(i_img *im,i_img_dim x,i_img_dim y,i_img_dim rad,float d1,float d2,const i_color *val);
+int i_arc_out_aa(i_img *im,i_img_dim x,i_img_dim y,i_img_dim rad,float d1,float d2,const i_color *val);
 void i_arc_aa         (i_img *im, double x, double y, double rad, double d1, double d2, const i_color *val);
 void i_arc_cfill(i_img *im,int x,int y,float rad,float d1,float d2,i_fill_t *fill);
 void i_arc_aa_cfill(i_img *im,double x,double y,double rad,double d1,double d2,i_fill_t *fill);
 void i_circle_aa   (i_img *im,float x, float y,float rad,const i_color *val);
+int i_circle_out   (i_img *im,i_img_dim x, i_img_dim y, i_img_dim rad,const i_color *val);
+int i_circle_out_aa   (i_img *im,i_img_dim x, i_img_dim y, i_img_dim rad,const i_color *val);
 void i_copyto      (i_img *im,i_img *src,int x1,int y1,int x2,int y2,int tx,int ty);
 void i_copyto_trans(i_img *im,i_img *src,int x1,int y1,int x2,int y2,int tx,int ty,const i_color *trans);
 i_img* i_copy        (i_img *src);
index c41f9c4..139b9ea 100644 (file)
@@ -276,12 +276,17 @@ filled.  See L<"Fill Parameters">.
   $img->arc(color=>$red, r=>20, x=>200, y=>100, d1=>10, d2=>20 );
 
 This creates a filled red arc with a 'center' at (200, 100) and spans
-10 degrees and the slice has a radius of 20. [NOTE: arc has a BUG in
-it right now for large differences in angles.]
+10 degrees and the slice has a radius of 20.
+
 It's also possible to supply a C<fill> parameter.
 
+To draw just an arc outline - just the curve, not the radius lines,
+set filled to 0:
+
 Parameters:
 
+  $img->arc(color=>$red, r=>20, x=>200, y=>100, d1=>10, d2=>20, filled=>0 );
+
 =over
 
 =item *
@@ -316,6 +321,10 @@ aa - if true the filled arc is drawn anti-aliased.  Default: false.
 Anti-aliased arc() is experimental for now, I'm not entirely happy
 with the results in some cases.
 
+=item *
+
+filled - set to 0 to draw only an outline.
+
 =back
 
   # arc going through angle zero:
@@ -335,8 +344,9 @@ instead of a color parameter.
 
   $img->circle(r => 50, x=> 150, y => 150, fill=>{ hatch => 'stipple' });
 
-The circle is always filled but that might change, so always pass a 
-filled=>1 parameter if you want it to be filled.
+To draw a circular outline, set C<filled> to 0:
+
+  $img->circle(color=>$green, r=>50, x=>200, y=>100, aa=>1, filled=>0);
 
 =over
 
@@ -361,6 +371,10 @@ fill - the fill for the filled circle.  See L<"Fill Parameters">
 
 aa - if true the filled circle is drawn anti-aliased.  Default: false.
 
+=item *
+
+filled - set to 0 to just draw an outline.
+
 =back
 
 =item polygon
index 318ff9c..cf7f358 100644 (file)
@@ -1,16 +1,10 @@
 #!perl -w
-# Before `make install' is performed this script should be runnable with
-# `make test'. After `make install' it should work as `perl test.pl'
-
-######################### We start with some black magic to print on failure.
-
-# Change 1..1 below to 1..last_test_to_print .
-# (It may become useful if the test is moved to ./t subdirectory.)
 use strict;
-use Test::More tests => 43;
-my $loaded;
+use Test::More tests => 235;
+use Imager ':all';
+use Imager::Test qw(is_color3);
+use constant PI => 3.14159265358979;
 
-BEGIN { use_ok(Imager=>':all'); }
 init_log("testout/t21draw.log",1);
 
 my $redobj = NC(255, 0, 0);
@@ -21,126 +15,265 @@ my $blueobj = NC(0, 0, 255);
 my $blue = { hue=>240, saturation=>1, value=>1 };
 my $white = '#FFFFFF';
 
-my $img = Imager->new(xsize=>100, ysize=>500);
-
-ok($img->box(color=>$blueobj, xmin=>10, ymin=>10, xmax=>48, ymax=>18),
-   "box with color obj");
-ok($img->box(color=>$blue, xmin=>10, ymin=>20, xmax=>48, ymax=>28),
-   "box with color");
-ok($img->box(color=>$redobj, xmin=>10, ymin=>30, xmax=>28, ymax=>48, filled=>1),
-   "filled box with color obj");
-ok($img->box(color=>$red, xmin=>30, ymin=>30, xmax=>48, ymax=>48, filled=>1),
-   "filled box with color");
-
-ok($img->arc('x'=>75, 'y'=>25, r=>24, color=>$redobj),
-   "filled arc with colorobj");
-
-ok($img->arc('x'=>75, 'y'=>25, r=>20, color=>$green),
-   "filled arc with colorobj");
-ok($img->arc('x'=>75, 'y'=>25, r=>18, color=>$white, d1=>325, d2=>225),
-   "filled arc with color");
-
-ok($img->arc('x'=>75, 'y'=>25, r=>18, color=>$blue, d1=>225, d2=>325),
-   "filled arc with color");
-ok($img->arc('x'=>75, 'y'=>25, r=>15, color=>$green, aa=>1),
-   "filled arc with color");
-
-ok($img->line(color=>$blueobj, x1=>5, y1=>55, x2=>35, y2=>95),
-   "line with colorobj");
-
-# FIXME - neither the start nor end-point is set for a non-aa line
-my $c = Imager::i_get_pixel($img->{IMG}, 5, 55);
-ok(color_cmp($c, $blueobj) == 0, "# TODO start point not set");
-
-ok($img->line(color=>$red, x1=>10, y1=>55, x2=>40, y2=>95, aa=>1),
-   "aa line with color");
-ok($img->line(color=>$green, x1=>15, y1=>55, x2=>45, y2=>95, antialias=>1),
-   "antialias line with color");
-
-ok($img->polyline(points=>[ [ 55, 55 ], [ 90, 60 ], [ 95, 95] ],
-                  color=>$redobj),
-   "polyline points with color obj");
-ok($img->polyline('x'=>[ 55, 85, 90 ], 'y'=>[60, 65, 95], color=>$green, aa=>1),
-   "polyline xy with color aa");
-ok($img->polyline('x'=>[ 55, 80, 85 ], 'y'=>[65, 70, 95], color=>$green, 
-                  antialias=>1),
-   "polyline xy with color antialias");
-
-ok($img->setpixel('x'=>[35, 37, 39], 'y'=>[55, 57, 59], color=>$red),
-   "set array of pixels");
-ok($img->setpixel('x'=>39, 'y'=>55, color=>$green),
-   "set single pixel");
-use Imager::Color::Float;
-my $flred = Imager::Color::Float->new(1, 0, 0, 0);
-my $flgreen = Imager::Color::Float->new(0, 1, 0, 0);
-ok($img->setpixel('x'=>[41, 43, 45], 'y'=>[55, 57, 59], color=>$flred),
-   "set array of float pixels");
-ok($img->setpixel('x'=>45, 'y'=>55, color=>$flgreen),
-   "set single float pixel");
-my @gp = $img->getpixel('x'=>[41, 43, 45], 'y'=>[55, 57, 59]);
-ok(grep($_->isa('Imager::Color'), @gp) == 3, "check getpixel result type");
-ok(grep(color_cmp($_, NC(255, 0, 0)) == 0, @gp) == 3, 
-   "check getpixel result colors");
-my $gp = $img->getpixel('x'=>45, 'y'=>55);
-ok($gp->isa('Imager::Color'), "check scalar getpixel type");
-ok(color_cmp($gp, NC(0, 255, 0)) == 0, "check scalar getpixel color");
-@gp = $img->getpixel('x'=>[35, 37, 39], 'y'=>[55, 57, 59], type=>'float');
-ok(grep($_->isa('Imager::Color::Float'), @gp) == 3, 
-   "check getpixel float result type");
-ok(grep(color_cmp($_, $flred) == 0, @gp) == 3,
-   "check getpixel float result type");
-$gp = $img->getpixel('x'=>39, 'y'=>55, type=>'float');
-ok($gp->isa('Imager::Color::Float'), "check scalar float getpixel type");
-ok(color_cmp($gp, $flgreen) == 0, "check scalar float getpixel color");
-
-# more complete arc tests
-ok($img->arc(x=>25, 'y'=>125, r=>20, d1=>315, d2=>45, color=>$greenobj),
-   "color arc through angle 0");
-# use diff combine here to make sure double writing is noticable
-ok($img->arc(x=>75, 'y'=>125, r=>20, d1=>315, d2=>45,
-            fill => { solid=>$blueobj, combine => 'diff' }),
-   "fill arc through angle 0");
-ok($img->arc(x=>25, 'y'=>175, r=>20, d1=>315, d2=>225, color=>$redobj),
-   "concave color arc");
-angle_marker($img, 25, 175, 23, 315, 225);
-ok($img->arc(x=>75, 'y'=>175, r=>20, d1=>315, d2=>225,
-            fill => { solid=>$greenobj, combine=>'diff' }),
-   "concave fill arc");
-angle_marker($img, 75, 175, 23, 315, 225);
-ok($img->arc(x=>25, y=>225, r=>20, d1=>135, d2=>45, color=>$redobj),
-   "another concave color arc");
-angle_marker($img, 25, 225, 23, 45, 135);
-ok($img->arc(x=>75, y=>225, r=>20, d1=>135, d2=>45, 
-            fill => { solid=>$blueobj, combine=>'diff' }),
-   "another concave fillarc");
-angle_marker($img, 75, 225, 23, 45, 135);
-ok($img->arc(x=>25, y=>275, r=>20, d1=>135, d2=>45, color=>$redobj, aa=>1),
-   "concave color arc aa");
-ok($img->arc(x=>75, y=>275, r=>20, d1=>135, d2=>45, 
-            fill => { solid=>$blueobj, combine=>'diff' }, aa=>1),
-   "concave fill arc aa");
-
-ok($img->circle(x=>25, y=>325, r=>20, color=>$redobj),
-   "color circle no aa");
-ok($img->circle(x=>75, y=>325, r=>20, color=>$redobj, aa=>1),
-   "color circle aa");
-ok($img->circle(x=>25, 'y'=>375, r=>20, 
-               fill => { hatch=>'stipple', fg=>$blueobj, bg=>$redobj }),
-   "fill circle no aa");
-ok($img->circle(x=>75, 'y'=>375, r=>20, aa=>1,
-               fill => { hatch=>'stipple', fg=>$blueobj, bg=>$redobj }),
-   "fill circle aa");
-
-ok($img->arc(x=>50, y=>450, r=>45, d1=>135, d2=>45, 
-            fill => { solid=>$blueobj, combine=>'diff' }),
-   "another concave fillarc");
-angle_marker($img, 50, 450, 47, 45, 135);
-
-ok($img->write(file=>'testout/t21draw.ppm'),
-   "saving output");
+{
+  my $img = Imager->new(xsize=>100, ysize=>500);
+
+  ok($img->box(color=>$blueobj, xmin=>10, ymin=>10, xmax=>48, ymax=>18),
+     "box with color obj");
+  ok($img->box(color=>$blue, xmin=>10, ymin=>20, xmax=>48, ymax=>28),
+     "box with color");
+  ok($img->box(color=>$redobj, xmin=>10, ymin=>30, xmax=>28, ymax=>48, filled=>1),
+     "filled box with color obj");
+  ok($img->box(color=>$red, xmin=>30, ymin=>30, xmax=>48, ymax=>48, filled=>1),
+     "filled box with color");
+
+  ok($img->arc('x'=>75, 'y'=>25, r=>24, color=>$redobj),
+     "filled arc with colorobj");
+
+  ok($img->arc('x'=>75, 'y'=>25, r=>20, color=>$green),
+     "filled arc with colorobj");
+  ok($img->arc('x'=>75, 'y'=>25, r=>18, color=>$white, d1=>325, d2=>225),
+     "filled arc with color");
+
+  ok($img->arc('x'=>75, 'y'=>25, r=>18, color=>$blue, d1=>225, d2=>325),
+     "filled arc with color");
+  ok($img->arc('x'=>75, 'y'=>25, r=>15, color=>$green, aa=>1),
+     "filled arc with color");
+
+  ok($img->line(color=>$blueobj, x1=>5, y1=>55, x2=>35, y2=>95),
+     "line with colorobj");
+
+  # FIXME - neither the start nor end-point is set for a non-aa line
+  my $c = Imager::i_get_pixel($img->{IMG}, 5, 55);
+  ok(color_cmp($c, $blueobj) == 0, "# TODO start point not set");
+
+  ok($img->line(color=>$red, x1=>10, y1=>55, x2=>40, y2=>95, aa=>1),
+     "aa line with color");
+  ok($img->line(color=>$green, x1=>15, y1=>55, x2=>45, y2=>95, antialias=>1),
+     "antialias line with color");
+
+  ok($img->polyline(points=>[ [ 55, 55 ], [ 90, 60 ], [ 95, 95] ],
+                   color=>$redobj),
+     "polyline points with color obj");
+  ok($img->polyline('x'=>[ 55, 85, 90 ], 'y'=>[60, 65, 95], color=>$green, aa=>1),
+     "polyline xy with color aa");
+  ok($img->polyline('x'=>[ 55, 80, 85 ], 'y'=>[65, 70, 95], color=>$green, 
+                   antialias=>1),
+     "polyline xy with color antialias");
+
+  ok($img->setpixel('x'=>[35, 37, 39], 'y'=>[55, 57, 59], color=>$red),
+     "set array of pixels");
+  ok($img->setpixel('x'=>39, 'y'=>55, color=>$green),
+     "set single pixel");
+  use Imager::Color::Float;
+  my $flred = Imager::Color::Float->new(1, 0, 0, 0);
+  my $flgreen = Imager::Color::Float->new(0, 1, 0, 0);
+  ok($img->setpixel('x'=>[41, 43, 45], 'y'=>[55, 57, 59], color=>$flred),
+     "set array of float pixels");
+  ok($img->setpixel('x'=>45, 'y'=>55, color=>$flgreen),
+     "set single float pixel");
+  my @gp = $img->getpixel('x'=>[41, 43, 45], 'y'=>[55, 57, 59]);
+  ok(grep($_->isa('Imager::Color'), @gp) == 3, "check getpixel result type");
+  ok(grep(color_cmp($_, NC(255, 0, 0)) == 0, @gp) == 3, 
+     "check getpixel result colors");
+  my $gp = $img->getpixel('x'=>45, 'y'=>55);
+  ok($gp->isa('Imager::Color'), "check scalar getpixel type");
+  ok(color_cmp($gp, NC(0, 255, 0)) == 0, "check scalar getpixel color");
+  @gp = $img->getpixel('x'=>[35, 37, 39], 'y'=>[55, 57, 59], type=>'float');
+  ok(grep($_->isa('Imager::Color::Float'), @gp) == 3, 
+     "check getpixel float result type");
+  ok(grep(color_cmp($_, $flred) == 0, @gp) == 3,
+     "check getpixel float result type");
+  $gp = $img->getpixel('x'=>39, 'y'=>55, type=>'float');
+  ok($gp->isa('Imager::Color::Float'), "check scalar float getpixel type");
+  ok(color_cmp($gp, $flgreen) == 0, "check scalar float getpixel color");
+
+  # more complete arc tests
+  ok($img->arc(x=>25, 'y'=>125, r=>20, d1=>315, d2=>45, color=>$greenobj),
+     "color arc through angle 0");
+  # use diff combine here to make sure double writing is noticable
+  ok($img->arc(x=>75, 'y'=>125, r=>20, d1=>315, d2=>45,
+              fill => { solid=>$blueobj, combine => 'diff' }),
+     "fill arc through angle 0");
+  ok($img->arc(x=>25, 'y'=>175, r=>20, d1=>315, d2=>225, color=>$redobj),
+     "concave color arc");
+  angle_marker($img, 25, 175, 23, 315, 225);
+  ok($img->arc(x=>75, 'y'=>175, r=>20, d1=>315, d2=>225,
+              fill => { solid=>$greenobj, combine=>'diff' }),
+     "concave fill arc");
+  angle_marker($img, 75, 175, 23, 315, 225);
+  ok($img->arc(x=>25, y=>225, r=>20, d1=>135, d2=>45, color=>$redobj),
+     "another concave color arc");
+  angle_marker($img, 25, 225, 23, 45, 135);
+  ok($img->arc(x=>75, y=>225, r=>20, d1=>135, d2=>45, 
+              fill => { solid=>$blueobj, combine=>'diff' }),
+     "another concave fillarc");
+  angle_marker($img, 75, 225, 23, 45, 135);
+  ok($img->arc(x=>25, y=>275, r=>20, d1=>135, d2=>45, color=>$redobj, aa=>1),
+     "concave color arc aa");
+  ok($img->arc(x=>75, y=>275, r=>20, d1=>135, d2=>45, 
+              fill => { solid=>$blueobj, combine=>'diff' }, aa=>1),
+     "concave fill arc aa");
+
+  ok($img->circle(x=>25, y=>325, r=>20, color=>$redobj),
+     "color circle no aa");
+  ok($img->circle(x=>75, y=>325, r=>20, color=>$redobj, aa=>1),
+     "color circle aa");
+  ok($img->circle(x=>25, 'y'=>375, r=>20, 
+                 fill => { hatch=>'stipple', fg=>$blueobj, bg=>$redobj }),
+     "fill circle no aa");
+  ok($img->circle(x=>75, 'y'=>375, r=>20, aa=>1,
+                 fill => { hatch=>'stipple', fg=>$blueobj, bg=>$redobj }),
+     "fill circle aa");
+
+  ok($img->arc(x=>50, y=>450, r=>45, d1=>135, d2=>45, 
+              fill => { solid=>$blueobj, combine=>'diff' }),
+     "another concave fillarc");
+  angle_marker($img, 50, 450, 47, 45, 135);
+
+  ok($img->write(file=>'testout/t21draw.ppm'),
+     "saving output");
+}
+
+{
+  my $im = Imager->new(xsize => 400, ysize => 400);
+  ok($im->arc(x => 200, y => 202, r => 10, filled => 0),
+     "draw circle outline");
+  is_color3($im->getpixel(x => 200, y => 202), 0, 0, 0,
+           "check center not filled");
+  ok($im->arc(x => 198, y => 200, r => 13, filled => 0, color => "#f88"),
+     "draw circle outline");
+  is_color3($im->getpixel(x => 198, y => 200), 0, 0, 0,
+           "check center not filled");
+  ok($im->arc(x => 200, y => 200, r => 24, filled => 0, color => "#0ff"),
+     "draw circle outline");
+  my $r = 40;
+  while ($r < 180) {
+    ok($im->arc(x => 200, y => 200, r => $r, filled => 0, color => "#ff0"),
+       "draw circle outline r $r");
+    $r += 15;
+  }
+  ok($im->write(file => "testout/t21circout.ppm"),
+     "save arc outline");
+}
+
+{
+  my $im = Imager->new(xsize => 400, ysize => 400);
+  {
+    my $lc = Imager::Color->new(32, 32, 32);
+    my $an = 0;
+    while ($an < 360) {
+      my $an_r = $an * PI / 180;
+      my $ca = cos($an_r);
+      my $sa = sin($an_r);
+      $im->line(aa => 1, color => $lc,
+               x1 => 198 + 5 * $ca, y1 => 202 + 5 * $sa,
+               x2 => 198 + 190 * $ca, y2 => 202 + 190 * $sa);
+      $an += 5;
+    }
+  }
+  my $d1 = 0;
+  my $r = 20;
+  while ($d1 < 350) {
+    ok($im->arc(x => 198, y => 202, r => $r, d1 => $d1, d2 => $d1+300, filled => 0),
+       "draw arc outline r$r d1$d1 len 300");
+    ok($im->arc(x => 198, y => 202, r => $r+3, d1 => $d1, d2 => $d1+40, filled => 0, color => '#FFFF00'),
+       "draw arc outline r$r d1$d1 len 40");
+    $d1 += 15;
+    $r += 6;
+  }
+  is_color3($im->getpixel(x => 198, y => 202), 0, 0, 0,
+           "check center not filled");
+  ok($im->write(file => "testout/t21arcout.ppm"),
+     "save arc outline");
+}
+
+{
+  my $im = Imager->new(xsize => 400, ysize => 400);
+  ok($im->arc(x => 197, y => 201, r => 10, filled => 0, aa => 1, color => 'white'),
+     "draw circle outline");
+  is_color3($im->getpixel(x => 197, y => 201), 0, 0, 0,
+           "check center not filled");
+  ok($im->arc(x => 197, y => 205, r => 13, filled => 0, color => "#f88", aa => 1),
+     "draw circle outline");
+  is_color3($im->getpixel(x => 197, y => 205), 0, 0, 0,
+           "check center not filled");
+  ok($im->arc(x => 190, y => 215, r => 24, filled => 0, color => [0,0, 255, 128], aa => 1),
+     "draw circle outline");
+  my $r = 40;
+  while ($r < 190) {
+    ok($im->arc(x => 197, y => 201, r => $r, filled => 0, aa => 1, color => '#ff0'), "draw aa circle rad $r");
+    $r += 7;
+  }
+  ok($im->write(file => "testout/t21aacircout.ppm"),
+     "save arc outline");
+}
+
+{
+  my $im = Imager->new(xsize => 400, ysize => 400);
+  {
+    my $lc = Imager::Color->new(32, 32, 32);
+    my $an = 0;
+    while ($an < 360) {
+      my $an_r = $an * PI / 180;
+      my $ca = cos($an_r);
+      my $sa = sin($an_r);
+      $im->line(aa => 1, color => $lc,
+               x1 => 198 + 5 * $ca, y1 => 202 + 5 * $sa,
+               x2 => 198 + 190 * $ca, y2 => 202 + 190 * $sa);
+      $an += 5;
+    }
+  }
+  my $d1 = 0;
+  my $r = 20;
+  while ($d1 < 350) {
+    ok($im->arc(x => 198, y => 202, r => $r, d1 => $d1, d2 => $d1+300, filled => 0, aa => 1),
+       "draw aa arc outline r$r d1$d1 len 300");
+    ok($im->arc(x => 198, y => 202, r => $r+3, d1 => $d1, d2 => $d1+40, filled => 0, color => '#FFFF00', aa => 1),
+       "draw aa arc outline r$r d1$d1 len 40");
+    $d1 += 15;
+    $r += 6;
+  }
+  is_color3($im->getpixel(x => 198, y => 202), 0, 0, 0,
+           "check center not filled");
+  ok($im->write(file => "testout/t21aaarcout.ppm"),
+     "save arc outline");
+}
+
+{
+  my $im = Imager->new(xsize => 400, ysize => 400);
+
+  my $an = 0;
+  my $step = 15;
+  while ($an <= 360-$step) {
+    my $cx = int(200 + 20 * cos(($an+$step/2) * PI / 180));
+    my $cy = int(200 + 20 * sin(($an+$step/2) * PI / 180));
+
+    ok($im->arc(x => $cx, y => $cy, aa => 1, color => "#fff", 
+               d1 => $an, d2 => $an+$step, filled => 0, r => 170),
+      "angle starting from $an");
+    ok($im->arc(x => $cx, y => $cy, aa => 1, color => "#ff0", 
+               d1 => $an, d2 => $an+$step, r => 168),
+      "filled angle starting from $an");
+
+    $an += $step;
+  }
+  ok($im->write(file => "testout/t21aaarcs.ppm"),
+     "save arc outline");
+}
+
 
 malloc_state();
 
+unless ($ENV{IMAGER_KEEP_FILES}) {
+  unlink "testout/t21draw.ppm";
+  unlink "testout/t21circout.ppm";
+  unlink "testout/t21aacircout.ppm";
+  unlink "testout/t21arcout.ppm";
+  unlink "testout/t21aaarcout.ppm";
+  unlink "testout/t21aaarcs.ppm";
+}
+
 sub color_cmp {
   my ($l, $r) = @_;
   my @l = $l->rgba;
@@ -151,8 +284,6 @@ sub color_cmp {
       || $l[2] <=> $r[2];
 }
 
-use constant PI => 4 * atan2(1,1);
-
 sub angle_marker {
   my ($img, $x, $y, $radius, @angles) = @_;
 
diff --git a/typemap b/typemap
index 4438d08..28159ad 100644 (file)
--- a/typemap
+++ b/typemap
@@ -14,6 +14,7 @@ undef_int             T_IV_U
 undef_neg_int           T_IV_NEGU
 HASH                   T_HVREF
 utf8_str               T_UTF8_STR
+i_img_dim              T_IV
 
 # these types are for use by Inline, which can't handle types containing ::
 Imager__Color           T_PTROBJ_INV