polygon documentation
authorTony Cook <tony@develop-help.com>
Sat, 6 Sep 2014 00:17:44 +0000 (10:17 +1000)
committerTony Cook <tony@develop-help.com>
Sun, 25 Jan 2015 03:29:08 +0000 (14:29 +1100)
apidocs.perl
lib/Imager/API.pod
lib/Imager/APIRef.pod
lib/Imager/Draw.pod
polygon.c
xt/x20spell.t

index 1a6ed07..55804e0 100644 (file)
@@ -102,6 +102,12 @@ Imager::APIRef - Imager's C API - reference.
 
   i_color color;
   color.rgba.r = 255; color.rgba.g = 0; color.rgba.b = 255;
+  double x[] = { ... };
+  double y[] = { ... };
+  i_polygon_t poly;
+  poly.count = sizeof(x) / sizeof(*x);
+  poly.x = x;
+  poly.y = y;
 
 EOS
 
index 15abf65..19f36e3 100644 (file)
@@ -181,6 +181,45 @@ type back to perl.
 
 See L</Context objects> for more information.
 
+=head2 i_polygon_t
+
+Represents a single polygon supplied to i_poly_poly_aa() and
+i_poly_poly_aa_cfill().
+
+This is a structure with 3 members:
+
+=over
+
+=item *
+
+C<x>, C<y> - pointers to the first elements of arrays of doubles that define
+the vertices of the polygon.
+
+=item *
+
+C<count> - the number of values in each of the C<x> and C<y> arrays.
+
+=back
+
+=head2 i_poly_fill_mode_t
+
+An enumerated type of the possible fill modes for polygons:
+
+=over
+
+=item *
+
+C<i_pfm_evenodd> - if areas overlap an odd number of times, they
+are filled, and are otherwise unfilled.
+
+=item *
+
+C<i_pfm_nonzero> - areas that have an unbalanced clockwise and
+anti-clockwise boundary are filled.  This is the same as
+C<WindingRule> for X and C<WINDING> for Win32 GDI.
+
+=back
+
 =head1 Create an XS module using the Imager API
 
 =head2 Foo.pm
index 11927d5..89554be 100644 (file)
@@ -12,6 +12,12 @@ Imager::APIRef - Imager's C API - reference.
 
   i_color color;
   color.rgba.r = 255; color.rgba.g = 0; color.rgba.b = 255;
+  double x[] = { ... };
+  double y[] = { ... };
+  i_polygon_t poly;
+  poly.count = sizeof(x) / sizeof(*x);
+  poly.x = x;
+  poly.y = y;
 
 
   # Blit tools
@@ -38,6 +44,10 @@ Imager::APIRef - Imager's C API - reference.
   i_flood_cfill(im, 50, 50, fill);
   i_flood_fill_border(im, 50, 50, &color, &border);
   i_flood_cfill_border(im, 50, 50, fill, border);
+  i_poly_poly_aa(im, 1, &poly, mode, color);
+  i_poly_aa_m(im, count, x, y, mode, color);
+  i_poly_poly_aa_cfill(im, 1, &poly, mode, fill);
+  i_poly_aa_cfill(im, count, x, y, mode, fill);
 
   # Error handling
   im_clear_error(aIMCTX);
@@ -770,6 +780,58 @@ Returns the number of pixels set.
 =for comment
 From: File imext.c
 
+=item i_poly_aa_cfill_m(im, count, x, y, mode, fill)
+
+  i_poly_aa_cfill(im, count, x, y, mode, fill);
+
+Fill a polygon defined by the points specified by the x and y arrays with
+the fill specified by C<fill>.
+
+
+=for comment
+From: File polygon.c
+
+=item i_poly_aa_m(im, count, x, y, mode, color)
+
+  i_poly_aa_m(im, count, x, y, mode, color);
+
+Fill a polygon defined by the points specified by the x and y arrays with
+the color specified by C<color>.
+
+
+=for comment
+From: File polygon.c
+
+=item i_poly_poly_aa(im, count, polys, mode, color)
+
+  i_poly_poly_aa(im, 1, &poly, mode, color);
+
+Fill the C<count> polygons defined by C<polys> the color specified by
+C<color>.
+
+At least one polygon must be supplied.
+
+All polygons must have at least 3 points.
+
+
+=for comment
+From: File polygon.c
+
+=item i_poly_poly_aa_cfill(im, count, polys, mode, fill)
+
+  i_poly_poly_aa_cfill(im, 1, &poly, mode, fill);
+
+Fill the C<count> polygons defined by C<polys> the fill specified by
+C<fill>.
+
+At least one polygon must be supplied.
+
+All polygons must have at least 3 points.
+
+
+=for comment
+From: File polygon.c
+
 =item i_ppal(im, left, right, y, indexes)
 
 
@@ -2368,22 +2430,6 @@ will change:
 
 =item *
 
-B<i_poly_aa_cfill_m>
-
-=item *
-
-B<i_poly_aa_m>
-
-=item *
-
-B<i_poly_poly_aa>
-
-=item *
-
-B<i_poly_poly_aa_cfill>
-
-=item *
-
 B<im_lhead>
 
 =item *
index 5a1497e..c9b19e5 100644 (file)
@@ -121,6 +121,35 @@ Currently you can create opaque or transparent plain color fills,
 hatched fills, image based fills and fountain fills.  See
 L<Imager::Fill> for more information.
 
+=head2 Polygon Fill Modes
+
+When filling a polygon that overlaps itself, or when filling several
+polygons with polypolygon() that overlap each other, you can supply a
+C<mode> parameter that controls how the overlap is resolved.  This can
+have one of two possible values:
+
+=over
+
+=item *
+
+C<evenodd> - if areas overlap an odd number of times, they are filled,
+and are otherwise unfilled.  This is the default and the historical
+Imager polygon fill mode.
+
+=item *
+
+C<nonzero> - areas that have an unbalanced clockwise and
+anti-clockwise boundary are filled.  This is the same as
+C<WindingRule> for X and C<WINDING> for Win32 GDI.
+
+=back
+
+C<nonzero> allows polygons to overlap, either with itself, or with
+another polygon in the same polypolygon() call, without producing
+unfilled area in the overlap, and also allows areas to be cut out of
+the area by specifying the points making up a cut-out in the opposite
+order.
+
 =head2 List of primitives
 
 =over
@@ -434,8 +463,62 @@ Default: black.  Overridden by C<fill>.
 
 C<fill> - the fill for the filled circle.  See L</"Fill Parameters">
 
+=item *
+
+C<mode> - fill mode for the polygon.  See L</"Polygon Fill Modes">
+
+=back
+
+Note: the points specified are as offsets from the top-left of the
+image, I<not> as pixel locations.  This means that:
+
+  $img->polygon(points => [ [ 0, 0 ], [ 1, 0 ], [ 1, 1 ], [ 0, 1 ] ]);
+
+fills only a single pixel at C<(0, 0)>, not four.
+
+=item polypolygon()
+X<polypolygon() method>X<methods, polypolygon>
+
+  $img->polypolygon(points => $points, color => $color);
+
+Draw multiple polygons, either filled or unfilled.
+
+=over
+
+=item *
+
+C<points> - is an array reference containing polygon definitions, each
+polygon definition is a reference to an array containing two arrays,
+one each for the C<x> and C<y> co-ordinates.
+
+=item *
+
+C<filled> - if true, fill the polygons with the color defined by
+C<color>.
+
+=item *
+
+C<color> - the color to draw the polygons with if C<fill> is not
+supplied.
+
+=item *
+
+C<fill> - fill the polygons with this fill if supplied.
+
+=item *
+
+C<mode> - fill mode for the polygon.  See L</"Polygon Fill Modes">
+
 =back
 
+Note: the points specified are as offsets from the top-left of the
+image, I<not> as pixel locations.  This means that:
+
+  $img->polypolygon(points => [ [ [ 0, 1, 1, 0 ], [ 0, 0, 1, 1 ] ] ],
+                    filled => 1);
+
+fills only a single pixel at C<(0, 0)>, not four.
+
 =item flood_fill()
 
 X<flood_fill>You can fill a region that all has the same color using
@@ -480,10 +563,6 @@ supplied as a L</"Color Parameters">.
 
 =back
 
-=item polypolygon()
-
-C<FIXME>
-
 =item setpixel()
 
   $img->setpixel(x=>50, y=>70, color=>$color);
index 559c070..58ac8ec 100644 (file)
--- a/polygon.c
+++ b/polygon.c
@@ -1,3 +1,4 @@
+#define IMAGER_NO_CONTEXT
 #include "imager.h"
 #include "draw.h"
 #include "log.h"
@@ -196,14 +197,14 @@ lines_in_interval(p_line *lset, int l, p_slice *tllist, pcord minc, pcord maxc)
 
 static
 void
-mark_updown_slices(p_line *lset, p_slice *tllist, int count) {
+mark_updown_slices(pIMCTX, p_line *lset, p_slice *tllist, int count) {
   p_line *l, *r;
   int k;
   for(k=0; k<count; k+=2) {
     l = lset + tllist[k].n;
 
     if (l->y1 == l->y2) {
-      mm_log((1, "mark_updown_slices: horizontal line being marked: internal error!\n"));
+      im_log((aIMCTX,1, "mark_updown_slices: horizontal line being marked: internal error!\n"));
       exit(3);
     }
 
@@ -221,13 +222,13 @@ mark_updown_slices(p_line *lset, p_slice *tllist, int count) {
              );
 
     if (k+1 >= count) {
-      mm_log((1, "Invalid polygon spec, odd number of line crossings.\n"));
+      im_log((aIMCTX, 1, "Invalid polygon spec, odd number of line crossings.\n"));
       return;
     }
 
     r = lset + tllist[k+1].n;
     if (r->y1 == r->y2) {
-      mm_log((1, "mark_updown_slices: horizontal line being marked: internal error!\n"));
+      im_log((aIMCTX, 1, "mark_updown_slices: horizontal line being marked: internal error!\n"));
       exit(3);
     }
 
@@ -454,14 +455,29 @@ i_poly_poly_aa_low(i_img *im, int count, const i_polygon_t *polys,
   p_line  *lset;               /* List of lines in polygon */
   p_slice *tllist;             /* List of slices */
   size_t pcount, lcount;
+  dIMCTX;
 
-  mm_log((1, "i_poly_poly_aa_low(im %p, count %d, polys %p, ctx %p, flusher %p)\n", im, count, polys, ctx, flusher));
+  im_log((aIMCTX, 1, "i_poly_poly_aa_low(im %p, count %d, polys %p, ctx %p, flusher %p)\n", im, count, polys, ctx, flusher));
+
+  i_clear_error();
+
+  if (count < 1) {
+    i_push_error(0, "no polygons to draw");
+    return 0;
+  }
+
+  for (k = 0; k < count; ++k) {
+    if (polys[k].count < 3) {
+      i_push_errorf(0, "polygons must have at least 3 points");
+      return 0;
+    }
+  }
 
   for (k = 0; k < count; ++k) {
     const i_polygon_t *p = polys + k;
-    mm_log((2, "poly %d\n", k));
+    im_log((aIMCTX, 2, "poly %d\n", k));
     for(i = 0; i < p->count; i++) {
-      mm_log((2, " (%.2f, %.2f)\n", p->x[i], p->y[i]));
+      im_log((aIMCTX, 2, " (%.2f, %.2f)\n", p->x[i], p->y[i]));
     }
   }
 
@@ -510,7 +526,7 @@ i_poly_poly_aa_low(i_img *im, int count, const i_polygon_t *polys,
     clc = lines_in_interval(lset, lcount, tllist, pset[i].y, pset[i+1].y);
     qsort(tllist, clc, sizeof(p_slice), (int(*)(const void *,const void *))p_compx);
 
-    mark_updown_slices(lset, tllist, clc);
+    mark_updown_slices(aIMCTX, lset, tllist, clc);
 
     POLY_DEB
       (
@@ -594,6 +610,21 @@ i_poly_poly_aa_low(i_img *im, int count, const i_polygon_t *polys,
   return 1;
 }
 
+/*
+=item i_poly_poly_aa(im, count, polys, mode, color)
+=synopsis i_poly_poly_aa(im, 1, &poly, mode, color);
+=category Drawing
+
+Fill the C<count> polygons defined by C<polys> the color specified by
+C<color>.
+
+At least one polygon must be supplied.
+
+All polygons must have at least 3 points.
+
+=cut
+*/
+
 int
 i_poly_poly_aa(i_img *im, int count, const i_polygon_t *polys,
               i_poly_fill_mode_t mode, const i_color *val) {
@@ -601,6 +632,17 @@ i_poly_poly_aa(i_img *im, int count, const i_polygon_t *polys,
   return i_poly_poly_aa_low(im, count, polys, mode, &c, scanline_flush);
 }
 
+/*
+=item i_poly_aa_m(im, count, x, y, mode, color)
+=synopsis i_poly_aa_m(im, count, x, y, mode, color);
+=category Drawing
+
+Fill a polygon defined by the points specified by the x and y arrays with
+the color specified by C<color>.
+
+=cut
+*/
+
 int
 i_poly_aa_m(i_img *im, int l, const double *x, const double *y,
            i_poly_fill_mode_t mode, const i_color *val) {
@@ -653,6 +695,21 @@ scanline_flush_render(i_img *im, ss_scanline *ss, int y, void *ctx) {
   }
 }
 
+/*
+=item i_poly_poly_aa_cfill(im, count, polys, mode, fill)
+=synopsis i_poly_poly_aa_cfill(im, 1, &poly, mode, fill);
+=category Drawing
+
+Fill the C<count> polygons defined by C<polys> the fill specified by
+C<fill>.
+
+At least one polygon must be supplied.
+
+All polygons must have at least 3 points.
+
+=cut
+*/
+
 int
 i_poly_poly_aa_cfill(i_img *im, int count, const i_polygon_t *polys,
                     i_poly_fill_mode_t mode, i_fill_t *fill) {
@@ -672,6 +729,17 @@ i_poly_poly_aa_cfill(i_img *im, int count, const i_polygon_t *polys,
   return result;
 }
 
+/*
+=item i_poly_aa_cfill_m(im, count, x, y, mode, fill)
+=synopsis i_poly_aa_cfill(im, count, x, y, mode, fill);
+=category Drawing
+
+Fill a polygon defined by the points specified by the x and y arrays with
+the fill specified by C<fill>.
+
+=cut
+*/
+
 int
 i_poly_aa_cfill_m(i_img *im, int l, const double *x, const double *y, 
                i_poly_fill_mode_t mode, i_fill_t *fill) {
index 1f268d5..9661e0e 100644 (file)
@@ -19,6 +19,7 @@ CGI
 CMYK
 CPAN
 FreeType
+GDI
 GIF
 HSV
 Hrafnkelsson