$self->{ERRSTR} = 'no points array, or x and y arrays.'; return undef;
}
+ my $mode = _first($opts{mode}, 0);
+
if ($opts{'fill'}) {
unless (UNIVERSAL::isa($opts{'fill'}, 'Imager::Fill')) {
# assume it's a hash ref
return undef;
}
}
- i_poly_aa_cfill($self->{IMG}, $opts{'x'}, $opts{'y'},
- $opts{'fill'}{'fill'});
+ i_poly_aa_cfill_m($self->{IMG}, $opts{'x'}, $opts{'y'},
+ $mode, $opts{'fill'}{'fill'});
}
else {
my $color = _color($opts{'color'});
$self->{ERRSTR} = $Imager::ERRSTR;
return;
}
- i_poly_aa($self->{IMG}, $opts{'x'}, $opts{'y'}, $color);
+ i_poly_aa_m($self->{IMG}, $opts{'x'}, $opts{'y'}, $mode, $color);
}
return $self;
}
+sub polypolygon {
+ my ($self, %opts) = @_;
+
+ $self->_valid_image("polypolygon")
+ or return;
+
+ my $points = $opts{points};
+ $points
+ or return $self->_set_error("polypolygon: missing required points");
+
+ my $mode = _first($opts{mode}, "evenodd");
+
+ if ($opts{filled}) {
+ my $color = _color(_first($opts{color}, [ 0, 0, 0, 0 ]))
+ or return $self->_set_error($Imager::ERRSTR);
+
+ i_poly_poly_aa($self->{IMG}, $points, $mode, $color)
+ or return $self->_set_error($self->_error_as_msg);
+ }
+ elsif ($opts{fill}) {
+ my $fill = $opts{fill};
+ $self->_valid_fill($fill, "polypolygon")
+ or return;
+
+ i_poly_poly_aa_cfill($self->{IMG}, $points, $mode, $fill->{fill})
+ or return $self->_set_error($self->_error_as_msg);
+ }
+ else {
+ my $color = _color(_first($opts{color}, [ 0, 0, 0, 255 ]))
+ or return $self->_set_error($Imager::ERRSTR);
+
+ my $rimg = $self->{IMG};
+
+ if (_first($opts{aa}, 1)) {
+ for my $poly (@$points) {
+ my $xp = $poly->[0];
+ my $yp = $poly->[1];
+ for my $i (0 .. $#$xp - 1) {
+ i_line_aa($rimg, $xp->[$i], $yp->[$i], $xp->[$i+1], $yp->[$i+1],
+ $color, 0);
+ }
+ i_line_aa($rimg, $xp->[$#$xp], $yp->[$#$yp], $xp->[0], $yp->[0],
+ $color, 0);
+ }
+ }
+ else {
+ for my $poly (@$points) {
+ my $xp = $poly->[0];
+ my $yp = $poly->[1];
+ for my $i (0 .. $#$xp - 1) {
+ i_line($rimg, $xp->[$i], $yp->[$i], $xp->[$i+1], $yp->[$i+1],
+ $color, 0);
+ }
+ i_line($rimg, $xp->[$#$xp], $yp->[$#$yp], $xp->[0], $yp->[0],
+ $color, 0);
+ }
+ }
+ }
+
+ return $self;
+}
# this the multipoint bezier curve
# this is here more for testing that actual usage since
polyline() - L<Imager::Draw/polyline()>
+polypolygon() - L<Imager::Draw/polypolygon()>
+
preload() - L<Imager::Files/preload()>
read() - L<Imager::Files/read()> - read a single image from an image file
#include "imperl.h"
+#define ARRAY_COUNT(array) (sizeof(array)/sizeof(*array))
+
/*
Context object management
const i_fsample_t *samples;
} i_fsample_list;
+typedef struct {
+ size_t count;
+ const i_polygon_t *polygons;
+} i_polygon_list;
+
/*
Allocate memory that will be discarded when mortals are discarded.
char *name;
int value;
};
-static int lookup_name(struct value_name *names, int count, char *name, int def_value)
+static int lookup_name(const struct value_name *names, int count, char *name, int def_value)
{
int i;
for (i = 0; i < count; ++i)
}
}
+static struct value_name
+poly_fill_mode_names[] =
+{
+ { "evenodd", i_pfm_evenodd },
+ { "nonzero", i_pfm_nonzero }
+};
+
+static i_poly_fill_mode_t
+S_get_poly_fill_mode(pTHX_ SV *sv) {
+ if (looks_like_number(sv)) {
+ IV work = SvIV(sv);
+ if (work < (IV)i_pfm_evenodd || work > (IV)i_pfm_nonzero)
+ work = (IV)i_pfm_evenodd;
+ return (i_poly_fill_mode_t)work;
+ }
+ else {
+ return (i_poly_fill_mode_t)lookup_name
+ (poly_fill_mode_names, ARRAY_COUNT(poly_fill_mode_names),
+ SvPV_nolen(sv), i_pfm_evenodd);
+ }
+}
+
+static void
+S_get_polygon_list(pTHX_ i_polygon_list *polys, SV *sv) {
+ AV *av;
+ int i;
+ i_polygon_t *s;
+
+ SvGETMAGIC(sv);
+ if (!SvOK(sv) || !SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVAV)
+ croak("polys must be an arrayref");
+
+ av = (AV*)SvRV(sv);
+ polys->count = av_len(av) + 1;
+ if (polys->count < 1)
+ croak("polypolygon: no polygons provided");
+ s = malloc_temp(aTHX_ sizeof(i_polygon_t) * polys->count);
+ for (i = 0; i < polys->count; ++i) {
+ SV **poly_sv = av_fetch(av, i, 0);
+ AV *poly_av;
+ SV **x_sv, **y_sv;
+ AV *x_av, *y_av;
+ double *x_data, *y_data;
+ ssize_t j;
+ ssize_t point_count;
+
+ if (!poly_sv)
+ croak("poly_polygon: nothing found for polygon %d", i);
+ /* needs to be another av */
+ SvGETMAGIC(*poly_sv);
+ if (!SvOK(*poly_sv) || !SvROK(*poly_sv) || SvTYPE(SvRV(*poly_sv)) != SVt_PVAV)
+ croak("poly_polygon: polygon %d isn't an arrayref", i);
+ poly_av = (AV*)SvRV(*poly_sv);
+ /* with two elements */
+ if (av_len(poly_av) != 1)
+ croak("poly_polygon: polygon %d should contain two arrays", i);
+ x_sv = av_fetch(poly_av, 0, 0);
+ y_sv = av_fetch(poly_av, 1, 0);
+ if (!x_sv)
+ croak("poly_polygon: polygon %d has no x elements", i);
+ if (!y_sv)
+ croak("poly_polygon: polygon %d has no y elements", i);
+ SvGETMAGIC(*x_sv);
+ SvGETMAGIC(*y_sv);
+ if (!SvOK(*x_sv) || !SvROK(*x_sv) || SvTYPE(SvRV(*x_sv)) != SVt_PVAV)
+ croak("poly_polygon: polygon %d x elements isn't an array", i);
+ if (!SvOK(*y_sv) || !SvROK(*y_sv) || SvTYPE(SvRV(*y_sv)) != SVt_PVAV)
+ croak("poly_polygon: polygon %d y elements isn't an array", i);
+ x_av = (AV*)SvRV(*x_sv);
+ y_av = (AV*)SvRV(*y_sv);
+ if (av_len(x_av) != av_len(y_av))
+ croak("poly_polygon: polygon %d x and y arrays different lengths", i+1);
+ point_count = av_len(x_av)+1;
+ x_data = malloc_temp(aTHX_ sizeof(double) * point_count * 2);
+ y_data = x_data + point_count;
+
+ for (j = 0; j < point_count; ++j) {
+ SV **x_item_sv = av_fetch(x_av, j, 0);
+ SV **y_item_sv = av_fetch(y_av, j, 0);
+ x_data[j] = x_item_sv ? SvNV(*x_item_sv) : 0;
+ y_data[j] = y_item_sv ? SvNV(*y_item_sv) : 0;
+ }
+ s[i].x = x_data;
+ s[i].y = y_data;
+ s[i].count = point_count;
+ }
+ polys->polygons = s;
+}
+
/* loads the segments of a fountain fill into an array */
static i_fountain_seg *
load_fount_segs(pTHX_ AV *asegs, int *count) {
i_bezier_multi(im,size_x,x,y,val);
int
-i_poly_aa(im,x,y,val)
+i_poly_aa_m(im,x,y,mode,val)
Imager::ImgRaw im
double *x
double *y
+ i_poly_fill_mode_t mode
Imager::Color val
PREINIT:
STRLEN size_x;
CODE:
if (size_x != size_y)
croak("Imager: x and y arrays to i_poly_aa must be equal length\n");
- RETVAL = i_poly_aa(im, size_x, x, y, val);
+ RETVAL = i_poly_aa_m(im, size_x, x, y, mode, val);
OUTPUT:
RETVAL
int
-i_poly_aa_cfill(im, x, y, fill)
+i_poly_aa_cfill_m(im, x, y, mode, fill)
Imager::ImgRaw im
double *x
double *y
+ i_poly_fill_mode_t mode
Imager::FillHandle fill
PREINIT:
STRLEN size_x;
CODE:
if (size_x != size_y)
croak("Imager: x and y arrays to i_poly_aa_cfill must be equal length\n");
- RETVAL = i_poly_aa_cfill(im, size_x, x, y, fill);
+ RETVAL = i_poly_aa_cfill_m(im, size_x, x, y, mode, fill);
OUTPUT:
RETVAL
+int
+i_poly_poly_aa(im, polys, mode, color)
+ Imager::ImgRaw im
+ i_polygon_list polys
+ i_poly_fill_mode_t mode
+ Imager::Color color
+ CODE:
+ RETVAL = i_poly_poly_aa(im, polys.count, polys.polygons, mode, color);
+ OUTPUT:
+ RETVAL
+
+int
+i_poly_poly_aa_cfill(im, polys, mode, fill)
+ Imager::ImgRaw im
+ i_polygon_list polys
+ i_poly_fill_mode_t mode
+ Imager::FillHandle fill
+ CODE:
+ RETVAL = i_poly_poly_aa_cfill(im, polys.count, polys.polygons, mode, fill);
+ OUTPUT:
+ RETVAL
+
undef_int
i_flood_fill(im,seedx,seedy,dcol)
Imager::ImgRaw im
t/250-draw/030-paste.t Test the paste() method
t/250-draw/040-rubthru.t Test the rubthrough() method
t/250-draw/050-polyaa.t polygon()
+t/250-draw/060-polypoly.t polypolygon()
t/250-draw/100-fill.t fills
t/250-draw/200-compose.t compose()
t/300-transform/010-scale.t scale(), scaleX() and scaleY()
void i_bezier_multi(i_img *im,int l,const double *x,const double *y,const i_color *val);
int i_poly_aa (i_img *im,int l,const double *x,const double *y,const i_color *val);
int i_poly_aa_cfill(i_img *im,int l,const double *x,const double *y,i_fill_t *fill);
+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);
+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);
+extern 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);
+extern 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);
undef_int i_flood_fill (i_img *im,i_img_dim seedx,i_img_dim seedy, const i_color *dcol);
undef_int i_flood_cfill(i_img *im, i_img_dim seedx, i_img_dim seedy, i_fill_t *fill);
size_t count;
} i_polygon_t;
+typedef enum i_poly_fill_mode_tag {
+ i_pfm_evenodd,
+ i_pfm_nonzero
+} i_poly_fill_mode_t;
+
/* Generic fills */
struct i_fill_tag;
i_mutex_unlock,
im_context_slot_new,
im_context_slot_set,
- im_context_slot_get
+ im_context_slot_get,
+
+ /* level 9 */
+ i_poly_poly_aa,
+ i_poly_poly_aa_cfill,
+ i_poly_aa_m,
+ i_poly_aa_cfill_m
};
/* in general these functions aren't called by Imager internally, but
#define i_flood_fill_border(im, seedx, seedy, dcol, border) ((im_extt->f_i_flood_fill_border)((im), (seedx), (seedy), (dcol), (border)))
#define i_flood_cfill_border(im, seedx, seedy, fill, border) ((im_extt->f_i_flood_cfill_border)((im), (seedx), (seedy), (fill), (border)))
+#define i_poly_aa_m(im, count, x, y, mode, c) ((im_extt->f_i_poly_aa_m)((im), (count), (x), (y), (mode), (c)))
+#define i_poly_aa_cfill_m(im, count, x, y, mode, fill) ((im_extt->f_i_poly_aa_m)((im), (count), (x), (y), (mode), (fill)))
+#define i_poly_poly_aa(im, count, polys, mode, c) ((im_extt->f_i_poly_poly_aa)((im), (count), (polys), (mode), (c)))
+#define i_poly_poly_aa_cfill(im, count, polys, mode, fill) ((im_extt->f_i_poly_poly_aa_cfill)((im), (count), (polys), (mode), (fill)))
+
#define i_copyto(im, src, x1, y1, x2, y2, tx, ty) \
((im_extt->f_i_copyto)((im), (src), (x1), (y1), (x2), (y2), (tx), (ty)))
#define i_copyto_trans(im, src, x1, y1, x2, y2, tx, ty, trans) \
size_t (*f_io_slurp)(i_io_glue_t *ig, unsigned char **c);
void (*f_io_glue_destroy)(i_io_glue_t *ig);
- /* IMAGER_API_LEVEL 8 functions will be added here */
+ /* IMAGER_API_LEVEL 8 */
i_img *(*f_im_img_8_new)(im_context_t ctx, i_img_dim xsize, i_img_dim ysize, int channels);
i_img *(*f_im_img_16_new)(im_context_t ctx, i_img_dim xsize, i_img_dim ysize, int channels);
i_img *(*f_im_img_double_new)(im_context_t ctx, i_img_dim xsize, i_img_dim ysize, int channels);
im_slot_t (*f_im_context_slot_new)(im_slot_destroy_t);
int (*f_im_context_slot_set)(im_context_t, im_slot_t, void *);
void *(*f_im_context_slot_get)(im_context_t, im_slot_t);
+
+ /* IMAGER_API_LEVEL 9 */
+ int (*f_i_poly_poly_aa)(i_img *im, int count, const i_polygon_t *polys,
+ i_poly_fill_mode_t mode, const i_color *val);
+ int (*f_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);
+ int (*f_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);
+ int (*f_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);
+
+ /* IMAGER_API_LEVEL 10 functions will be added here */
+
+
} im_ext_funcs;
#define PERL_FUNCTION_TABLE_NAME "Imager::__ext_func_table"
=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 *
=back
+=item polypolygon()
+
+C<FIXME>
+
=item setpixel()
$img->setpixel(x=>50, y=>70, color=>$color);
pcord miny,maxy;
pcord minx,maxx;
int updown; /* -1 means down, 0 vertical, 1 up */
+ int dir; /* 1 for down, -1 for up */
} p_line;
typedef struct {
(l->y1 > l->y2) ? -1 : 1
:
(l->y1 > l->y2) ? 1 : -1;
+ l->dir = l->y1 < l->y2 ? 1 : -1;
POLY_DEB( printf("marking left line %d as %s(%d)\n", l->n,
l->updown ? l->updown == 1 ? "up" : "down" : "vert", l->updown, l->updown)
(r->y1 > r->y2) ? -1 : 1
:
(r->y1 > r->y2) ? 1 : -1;
+ r->dir = r->y1 < r->y2 ? 1 : -1;
POLY_DEB( printf("marking right line %d as %s(%d)\n", r->n,
r->updown ? r->updown == 1 ? "up" : "down" : "vert", r->updown, r->updown)
static int
i_poly_poly_aa_low(i_img *im, int count, const i_polygon_t *polys,
- void *ctx, scanline_flusher flusher) {
+ i_poly_fill_mode_t mode, void *ctx,
+ scanline_flusher flusher) {
int i ,k; /* Index variables */
i_img_dim clc; /* Lines inside current interval */
/* initialize to avoid compiler warnings */
tempy = i_min(cscl*16+16, pset[i+1].y);
POLY_DEB( printf("evaluating scan line %d \n", cscl) );
- for(k=0; k<clc-1; k+=2) {
- POLY_DEB( printf("evaluating slice %d\n", k) );
- render_slice_scanline(&templine, cscl, lset+tllist[k].n, lset+tllist[k+1].n, scan_miny, scan_maxy);
+ if (mode == i_pfm_evenodd) {
+ for(k=0; k<clc-1; k+=2) {
+ POLY_DEB( printf("evaluating slice %d\n", k) );
+ render_slice_scanline(&templine, cscl, lset+tllist[k].n, lset+tllist[k+1].n, scan_miny, scan_maxy);
+ }
+ }
+ else {
+ k = 0;
+ while (k < clc) {
+ p_line *left = lset + tllist[k++].n;
+ p_line *current;
+ int acc = left->dir;
+
+ while (k < clc && acc) {
+ current = lset + tllist[k++].n;
+ acc += current->dir;
+ }
+ if (acc == 0) {
+ render_slice_scanline(&templine, cscl, left, current,
+ scan_miny, scan_maxy);
+ }
+ }
}
if (16*coarse(tempy) == tempy) {
POLY_DEB( printf("flushing scan line %d\n", cscl) );
int
i_poly_poly_aa(i_img *im, int count, const i_polygon_t *polys,
- const i_color *val) {
+ i_poly_fill_mode_t mode, const i_color *val) {
i_color c = *val;
- return i_poly_poly_aa_low(im, count, polys, &c, scanline_flush);
+ return i_poly_poly_aa_low(im, count, polys, mode, &c, scanline_flush);
+}
+
+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) {
+ i_polygon_t poly;
+
+ poly.count = l;
+ poly.x = x;
+ poly.y = y;
+ return i_poly_poly_aa(im, 1, &poly, mode, val);
}
int
poly.count = l;
poly.x = x;
poly.y = y;
- return i_poly_poly_aa(im, 1, &poly, val);
+ return i_poly_poly_aa(im, 1, &poly, i_pfm_evenodd, val);
}
struct poly_render_state {
int
i_poly_poly_aa_cfill(i_img *im, int count, const i_polygon_t *polys,
- i_fill_t *fill) {
+ i_poly_fill_mode_t mode, i_fill_t *fill) {
struct poly_render_state ctx;
int result;
ctx.fill = fill;
ctx.cover = mymalloc(im->xsize);
- result = i_poly_poly_aa_low(im, count, polys, &ctx, scanline_flush_render);
+ result = i_poly_poly_aa_low(im, count, polys, mode, &ctx,
+ scanline_flush_render);
myfree(ctx.cover);
i_render_done(&ctx.render);
return result;
}
+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) {
+ i_polygon_t poly;
+
+ poly.count = l;
+ poly.x = x;
+ poly.y = y;
+
+ return i_poly_poly_aa_cfill(im, 1, &poly, mode, fill);
+}
+
int
i_poly_aa_cfill(i_img *im, int l, const double *x, const double *y,
i_fill_t *fill) {
poly.x = x;
poly.y = y;
- return i_poly_poly_aa_cfill(im, 1, &poly, fill);
+ return i_poly_poly_aa_cfill(im, 1, &poly, i_pfm_evenodd, fill);
}
#!perl -w
use strict;
-use Test::More tests => 18;
+use Test::More tests => 24;
use Imager qw/NC/;
use Imager::Test qw(is_image is_color3);
-d "testout" or mkdir "testout";
-Imager::init_log("testout/t75aapolyaa.log",1);
+my @out_files;
+
+END {
+ unless ($ENV{IMAGER_KEEP_FILES}) {
+ unlink @out_files;
+ rmdir "testout";
+ }
+}
+
+Imager->open_log(log => "testout/250-polyaa.log");
+push @out_files, "testout/250-polyaa.log";
my $red = Imager::Color->new(255,0,0);
my $green = Imager::Color->new(0,255,0);
my $blue = Imager::Color->new(0,0,255);
my $white = Imager::Color->new(255,255,255);
+my $black = Imager::Color->new(0, 0, 0);
{ # artifacts with multiple vertical lobes
# https://rt.cpan.org/Ticket/Display.html?id=43518
ok($im->polygon(points => \@pts,
color => $white),
"draw with inside point");
- ok($im->write(file => "testout/t75inside.ppm"), "save to file");
+ ok($im->write(file => "testout/250-poly-inside.ppm"), "save to file");
+ push @out_files, "testout/250-poly-inside.ppm";
# both scanlines should be the same
my $line0 = $im->crop(top => 0, height => 1);
my $line1 = $im->crop(top => 1, height => 1);
my ($x, $y) = array_to_refpair(@data);
- ok(Imager::i_poly_aa($img->{IMG}, $x, $y, $white), "primitive poly");
+ ok(Imager::i_poly_aa_m($img->{IMG}, $x, $y, 0, $white), "primitive poly");
- ok($img->write(file=>"testout/t75.ppm"), "write to file")
+ ok($img->write(file=>"testout/250-poly.ppm"), "write to file")
or diag $img->errstr;
+ push @out_files, "testout/250-poly.ppm";
my $zoom = make_zoom($img, 8, \@data, $red);
ok($zoom, "make zoom of primitive");
- $zoom->write(file=>"testout/t75zoom.ppm") or die $zoom->errstr;
+ $zoom->write(file=>"testout/250-poly-zoom.ppm") or die $zoom->errstr;
+ push @out_files, "testout/250-poly-zoom.ppm";
}
{
)
);
my ($x, $y) = array_to_refpair(@data);
- Imager::i_poly_aa($img->{IMG}, $x, $y, NC(rand(255), rand(255), rand(255)))
+ Imager::i_poly_aa_m($img->{IMG}, $x, $y, 0, NC(rand(255), rand(255), rand(255)))
or $good = 0;
}
- $img->write(file=>"testout/t75big.ppm") or die $img->errstr;
+ $img->write(file=>"testout/250-poly-big.ppm") or die $img->errstr;
ok($good, "primitive squares");
+ push @out_files, "testout/250-poly-big.ppm";
}
{
), "method call")
or diag $img->errstr();
- $img->write(file=>"testout/t75wave.ppm") or die $img->errstr;
+ $img->write(file=>"testout/250-poly-wave.ppm") or die $img->errstr;
+ push @out_files, "testout/250-poly-wave.ppm";
}
{
), "bug check")
or diag $img->errstr();
- make_zoom($img,20,\@data, $blue)->write(file=>"testout/t75wavebug.ppm") or die $img->errstr;
+ make_zoom($img,20,\@data, $blue)->write(file=>"testout/250-poly-wavebug.ppm") or die $img->errstr;
+ push @out_files, "testout/250-poly-wavebug.ppm";
}
{
],
), "poly filled with hatch")
or diag $img->errstr();
- $img->write(file=>"testout/t75wave_fill.ppm") or die $img->errstr;
+ $img->write(file=>"testout/250-poly-wave_fill.ppm") or die $img->errstr;
+ push @out_files, "testout/250-poly-wave_fill.ppm";
}
{
],
), "hatched to 16-bit image")
or diag $img->errstr();
- $img->write(file=>"testout/t75wave_fill16.ppm") or die $img->errstr;
+ $img->write(file=>"testout/250-poly-wave_fill16.ppm") or die $img->errstr;
+ push @out_files, "testout/250-poly-wave_fill16.ppm";
}
-Imager::malloc_state();
+{
+ my $img = Imager->new(xsize => 100, ysize => 100);
+ my $poly =
+ [
+ [
+ [ 10, 90, 90, 10 ],
+ [ 10, 10, 90, 90 ],
+ ],
+ [
+ [ 20, 45, 45, 20 ],
+ [ 20, 20, 80, 80 ],
+ ],
+ [
+ [ 55, 55, 80, 80 ],
+ [ 20, 80, 80, 20 ],
+ ],
+ ];
+ ok($img->polypolygon
+ (
+ points => $poly,
+ filled => 1,
+ color => $white,
+ ), "default polypolygon");
+ push @out_files, "testout/250-poly-ppeo.ppm";
+ ok($img->write(file => "testout/250-poly-ppeo.ppm"),
+ "save to file");
+ my $cmp_eo = Imager->new(xsize => 100, ysize => 100);
+ $cmp_eo->box(filled => 1, color => $white, box => [ 10, 10, 89, 89 ]);
+ $cmp_eo->box(filled => 1, color => $black, box => [ 20, 20, 44, 79 ]);
+ $cmp_eo->box(filled => 1, color => $black, box => [ 55, 20, 79, 79 ]);
+ is_image($img, $cmp_eo, "check even/odd matches");
+ $img = Imager->new(xsize => 100, ysize => 100);
+ ok($img->polypolygon
+ (
+ points => $poly,
+ filled => 1,
+ color => $white,
+ mode => "nonzero",
+ ), "default polypolygon");
+ my $cmp_nz = Imager->new(xsize => 100, ysize => 100);
+ $cmp_nz->box(filled => 1, color => $white, box => [ 10, 10, 89, 89 ]);
+ $cmp_nz->box(filled => 1, color => $black, box => [ 55, 20, 79, 79 ]);
+ is_image($img, $cmp_nz, "check non-zero matches");
+ push @out_files, "testout/250-poly-ppnz.ppm";
+ ok($img->write(file => "testout/250-poly-ppnz.ppm"),
+ "save to file");
+}
+Imager->close_log;
+
+Imager::malloc_state();
#initialized in a BEGIN, later
my %primitives;
--- /dev/null
+#!perl -w
+
+use strict;
+use Test::More tests => 12;
+
+use Imager qw/NC/;
+use Imager::Test qw(is_image is_color3);
+
+sub PI () { 3.14159265358979323846 }
+
+-d "testout" or mkdir "testout";
+
+my @cleanup;
+push @cleanup, "testout/060-polypoly.log";
+Imager->open_log(log => "testout/060-polypoly.log");
+
+my $red = NC(255,0,0);
+my $green = NC(0,255,0);
+my $blue = NC(0,0,255);
+my $white = NC(255,255,255);
+my $black = NC(0, 0, 0);
+
+END {
+ unlink @cleanup unless $ENV{IMAGER_KEEP_FILES};
+ rmdir "testout";
+}
+
+{
+ my $out = "testout/060-ppsimple.ppm";
+ my $im = Imager->new(xsize => 100, ysize => 100);
+ ok($im->polypolygon
+ (
+ filled => 1,
+ color => $red,
+ points =>
+ [
+ [
+ [ 20, 20, 40, 40 ],
+ [ 20, 80, 80, 20 ],
+ ],
+ [
+ [ 60, 60, 80, 80 ],
+ [ 20, 80, 80, 20 ],
+ ],
+ ]
+ ), "simple filled polypolygon");
+ ok($im->write(file => $out), "save to $out");
+ my $cmp = Imager->new(xsize => 100, ysize => 100);
+ $cmp->box(filled => 1, color => $red, box => [ 20, 20, 39, 79 ]);
+ $cmp->box(filled => 1, color => $red, box => [ 60, 20, 79, 79 ]);
+ is_image($im, $cmp, "check expected output");
+ push @cleanup, $out;
+}
+
+{
+ my $im = Imager->new(xsize => 100, ysize => 100);
+ my $cross_cw =
+ [
+ [
+ [ 10, 90, 90, 10 ],
+ [ 40, 40, 60, 60 ],
+ ],
+ [
+ [ 40, 60, 60, 40 ],
+ [ 10, 10, 90, 90 ],
+ ],
+ ];
+ ok($im->polypolygon
+ (
+ filled => 1,
+ color => $red,
+ points =>$cross_cw,
+ mode => "nonzero",
+ ), "cross polypolygon nz");
+ save($im, "060-ppcrossnz.ppm");
+ my $cmp = Imager->new(xsize => 100, ysize => 100);
+ $cmp->box(filled => 1, color => $red, box => [ 10, 40, 89, 59 ]);
+ $cmp->box(filled => 1, color => $red, box => [ 40, 10, 59, 89 ]);
+ is_image($im, $cmp, "check expected output");
+
+ my $im2 = Imager->new(xsize => 100, ysize => 100);
+ ok($im2->polypolygon
+ (
+ filled => 1,
+ color => $red,
+ points =>$cross_cw,
+ #mode => "nonzero", # default to evenodd
+ ), "cross polypolygon eo");
+ save($im2, "060-ppcrosseo.ppm");
+
+ $cmp->box(filled => 1, color => $black, box => [ 40, 40, 59, 59 ]);
+ is_image($im2, $cmp, "check expected output");
+
+ # same as cross_cw except that the second box is in reversed order
+ my $cross_diff =
+ [
+ [
+ [ 10, 90, 90, 10 ],
+ [ 40, 40, 60, 60 ],
+ ],
+ [
+ [ 40, 60, 60, 40 ],
+ [ 90, 90, 10, 10 ],
+ ],
+ ];
+ my $im3 = Imager->new(xsize => 100, ysize => 100);
+ ok($im3->polypolygon
+ (
+ filled => 1,
+ color => $red,
+ points => $cross_diff,
+ mode => "nonzero",
+ ), "cross polypolygon diff");
+ is_image($im3, $cmp, "check expected output");
+ save($im3, "060-ppcrossdiff.ppm");
+}
+
+Imager->close_log;
+
+sub save {
+ my ($im, $file) = @_;
+
+ $file = "testout/" . $file;
+ push @cleanup, $file;
+ ok($im->write(file => $file), "save to $file");
+}
i_box_filled(im, 11, 25, 19, 29, &blue);
i_flood_cfill_border(im, 15, 25, hatch, &black);
+ {
+ double x[3];
+ double y[3];
+ i_polygon_t poly;
+ x[0] = 55;
+ y[0] = 25;
+ x[1] = 55;
+ y[1] = 50;
+ x[2] = 70;
+ y[2] = 50;
+ i_poly_aa_m(im, 3, x, y, i_pfm_evenodd, &red);
+ x[2] = 40;
+ i_poly_aa_cfill_m(im, 3, x, y, i_pfm_evenodd, hatch);
+ y[0] = 65;
+ poly.x = x;
+ poly.y = y;
+ poly.count = 3;
+ i_poly_poly_aa(im, 1, &poly, i_pfm_nonzero, &green);
+ x[2] = 70;
+ i_poly_poly_aa_cfill(im, 1, &poly, i_pfm_nonzero, hatch);
+ }
+
i_fill_destroy(fount_fill);
i_fill_destroy(fhatch_fill);
i_fill_destroy(solid_fill);
i_img_destroy(im);
return NULL;
}
-
+
return im;
}
i_channel_list T_IM_CHANNEL_LIST
i_sample_list T_IM_SAMPLE_LIST
i_fsample_list T_IM_FSAMPLE_LIST
+i_polygon_list T_IM_POLYGON_LIST
off_t T_OFF_T
i_img_dim * T_AVARRAY
i_color * T_AVARRAY
+i_poly_fill_mode_t T_I_POLY_FILL_MODE_T
#############################################################################
INPUT
croak(\"$pname: no samples provided in $var\");
}
+T_IM_POLYGON_LIST
+ S_get_polygon_list(aTHX_ &$var, $arg);
+
T_AVARRAY
STMT_START {
SV* const xsub_tmp_sv = $arg;
}
} STMT_END
+T_I_POLY_FILL_MODE_T
+ $var = S_get_poly_fill_mode(aTHX_ $arg);
+
+
+
#############################################################################
OUTPUT