access to poly_poly from perl as polypolygon()
[imager.git] / t / 250-draw / 050-polyaa.t
CommitLineData
1c5252ed 1#!perl -w
02d1d628 2
1c5252ed 3use strict;
0d80f37e 4use Test::More tests => 24;
02d1d628 5
1c5252ed
TC
6use Imager qw/NC/;
7use Imager::Test qw(is_image is_color3);
02d1d628 8
9982a307 9sub PI () { 3.14159265358979323846 }
02d1d628 10
40e78f96
TC
11-d "testout" or mkdir "testout";
12
0d80f37e
TC
13my @out_files;
14
15END {
16 unless ($ENV{IMAGER_KEEP_FILES}) {
17 unlink @out_files;
18 rmdir "testout";
19 }
20}
21
22Imager->open_log(log => "testout/250-polyaa.log");
23push @out_files, "testout/250-polyaa.log";
1c5252ed
TC
24
25my $red = Imager::Color->new(255,0,0);
26my $green = Imager::Color->new(0,255,0);
27my $blue = Imager::Color->new(0,0,255);
28my $white = Imager::Color->new(255,255,255);
0d80f37e 29my $black = Imager::Color->new(0, 0, 0);
1c5252ed
TC
30
31{ # artifacts with multiple vertical lobes
32 # https://rt.cpan.org/Ticket/Display.html?id=43518
33 # previously this would have a full coverage pixel at (0,0) caused
34 # by the (20,0.5) point in the right lobe
35
36 my @pts =
37 (
38 [ 0.5, -9 ],
39 [ 10, -9 ],
40 [ 10, 11 ],
41 [ 15, 11 ],
42 [ 15, -9 ],
43 [ 17, -9 ],
44 [ 20, 0.5 ],
45 [ 17, 11 ],
46 [ 0.5, 11 ],
47 );
48 my $im = Imager->new(xsize => 10, ysize => 2);
49 ok($im->polygon(points => \@pts,
50 color => $white),
51 "draw with inside point");
0d80f37e
TC
52 ok($im->write(file => "testout/250-poly-inside.ppm"), "save to file");
53 push @out_files, "testout/250-poly-inside.ppm";
1c5252ed
TC
54 # both scanlines should be the same
55 my $line0 = $im->crop(top => 0, height => 1);
56 my $line1 = $im->crop(top => 1, height => 1);
57 is_image($line0, $line1, "both scanlines should be the same");
58}
02d1d628 59
1c5252ed
TC
60{ # check vertical edges are consistent
61 my $im = Imager->new(xsize => 10, ysize => 10);
62 ok($im->polygon(points => [ [ 0.5, 0 ], [ 9.25, 0 ],
63 [ 9.25, 10 ], [ 0.5, 10 ] ],
64 color => $white,
65 aa => 1),
66 "draw polygon with mid pixel vertical edges")
67 or diag $im->errstr;
68 my @line0 = $im->getscanline(y => 0);
69 my $im2 = Imager->new(xsize => 10, ysize => 10);
70 for my $y (0..9) {
71 $im2->setscanline(y => $y, pixels => \@line0);
72 }
73 is_image($im, $im2, "all scan lines should be the same");
74 is_color3($line0[0], 128, 128, 128, "(0,0) should be 50% coverage");
75 is_color3($line0[9], 64, 64, 64, "(9,0) should be 25% coverage");
9982a307
AMH
76}
77
1c5252ed
TC
78{ # check horizontal edges are consistent
79 my $im = Imager->new(xsize => 10, ysize => 10);
80 ok($im->polygon(points => [ [ 0, 0.5 ], [ 0, 9.25 ],
81 [ 10, 9.25 ], [ 10, 0.5 ] ],
82 color => $white,
83 aa => 1),
84 "draw polygon with mid-pixel horizontal edges");
85 is_deeply([ $im->getsamples(y => 0, channels => [ 0 ]) ],
86 [ (128) x 10 ],
87 "all of line 0 should be 50% coverage");
88 is_deeply([ $im->getsamples(y => 9, channels => [ 0 ]) ],
89 [ (64) x 10 ],
90 "all of line 9 should be 25% coverage");
91}
9982a307 92
1c5252ed
TC
93{
94 my $img = Imager->new(xsize=>20, ysize=>10);
95 my @data = translate(5.5,5,
96 rotate(0,
97 scale(5, 5,
98 get_polygon(n_gon => 5)
99 )
100 )
101 );
102
103
104 my ($x, $y) = array_to_refpair(@data);
0d80f37e 105 ok(Imager::i_poly_aa_m($img->{IMG}, $x, $y, 0, $white), "primitive poly");
9982a307 106
0d80f37e 107 ok($img->write(file=>"testout/250-poly.ppm"), "write to file")
1c5252ed 108 or diag $img->errstr;
0d80f37e 109 push @out_files, "testout/250-poly.ppm";
d0e7bfee 110
1c5252ed
TC
111 my $zoom = make_zoom($img, 8, \@data, $red);
112 ok($zoom, "make zoom of primitive");
0d80f37e
TC
113 $zoom->write(file=>"testout/250-poly-zoom.ppm") or die $zoom->errstr;
114 push @out_files, "testout/250-poly-zoom.ppm";
1c5252ed 115}
d0e7bfee 116
1c5252ed
TC
117{
118 my $img = Imager->new(xsize=>300, ysize=>100);
119
120 my $good = 1;
121 for my $n (0..55) {
122 my @data = translate(20+20*($n%14),18+20*int($n/14),
123 rotate(15*$n/PI,
124 scale(15, 15,
125 get_polygon('box')
126 )
127 )
128 );
129 my ($x, $y) = array_to_refpair(@data);
0d80f37e 130 Imager::i_poly_aa_m($img->{IMG}, $x, $y, 0, NC(rand(255), rand(255), rand(255)))
1c5252ed
TC
131 or $good = 0;
132 }
133
0d80f37e 134 $img->write(file=>"testout/250-poly-big.ppm") or die $img->errstr;
d0e7bfee 135
1c5252ed 136 ok($good, "primitive squares");
0d80f37e 137 push @out_files, "testout/250-poly-big.ppm";
1c5252ed 138}
fe24d684 139
1c5252ed
TC
140{
141 my $img = Imager->new(xsize => 300, ysize => 300);
142 ok($img -> polygon(color=>$white,
143 points => [
144 translate(150,150,
145 rotate(45*PI/180,
146 scale(70,70,
147 get_polygon('wavycircle', 32*8, sub { 1.2+1*cos(4*$_) }))))
148 ],
149 ), "method call")
150 or diag $img->errstr();
151
0d80f37e
TC
152 $img->write(file=>"testout/250-poly-wave.ppm") or die $img->errstr;
153 push @out_files, "testout/250-poly-wave.ppm";
1c5252ed 154}
fe24d684 155
1c5252ed
TC
156{
157 my $img = Imager->new(xsize=>10,ysize=>6);
158 my @data = translate(165,5,
159 scale(80,80,
160 get_polygon('wavycircle', 32*8, sub { 1+1*cos(4*$_) })));
161
162 ok($img -> polygon(color=>$white,
fe24d684
AMH
163 points => [
164 translate(165,5,
165 scale(80,80,
166 get_polygon('wavycircle', 32*8, sub { 1+1*cos(4*$_) })))
167 ],
1c5252ed
TC
168 ), "bug check")
169 or diag $img->errstr();
fe24d684 170
0d80f37e 171 make_zoom($img,20,\@data, $blue)->write(file=>"testout/250-poly-wavebug.ppm") or die $img->errstr;
fe24d684 172
0d80f37e 173 push @out_files, "testout/250-poly-wavebug.ppm";
1c5252ed 174}
fe24d684 175
1c5252ed
TC
176{
177 my $img = Imager->new(xsize=>300, ysize=>300);
178 ok($img->polygon(fill=>{ hatch=>'cross1', fg=>'00FF00', bg=>'0000FF', dx=>3 },
43c5dacb
TC
179 points => [
180 translate(150,150,
181 scale(70,70,
182 get_polygon('wavycircle', 32*8, sub { 1+1*cos(4*$_) })))
183 ],
1c5252ed
TC
184 ), "poly filled with hatch")
185 or diag $img->errstr();
0d80f37e
TC
186 $img->write(file=>"testout/250-poly-wave_fill.ppm") or die $img->errstr;
187 push @out_files, "testout/250-poly-wave_fill.ppm";
1c5252ed 188}
43c5dacb 189
1c5252ed
TC
190{
191 my $img = Imager->new(xsize=>300, ysize=>300, bits=>16);
192 ok($img->polygon(fill=>{ hatch=>'cross1', fg=>'00FF00', bg=>'0000FF' },
43c5dacb
TC
193 points => [
194 translate(150,150,
195 scale(70,70,
196 get_polygon('wavycircle', 32*8, sub { 1+1*cos(5*$_) })))
197 ],
1c5252ed
TC
198 ), "hatched to 16-bit image")
199 or diag $img->errstr();
0d80f37e
TC
200 $img->write(file=>"testout/250-poly-wave_fill16.ppm") or die $img->errstr;
201 push @out_files, "testout/250-poly-wave_fill16.ppm";
1c5252ed 202}
9982a307 203
0d80f37e
TC
204{
205 my $img = Imager->new(xsize => 100, ysize => 100);
206 my $poly =
207 [
208 [
209 [ 10, 90, 90, 10 ],
210 [ 10, 10, 90, 90 ],
211 ],
212 [
213 [ 20, 45, 45, 20 ],
214 [ 20, 20, 80, 80 ],
215 ],
216 [
217 [ 55, 55, 80, 80 ],
218 [ 20, 80, 80, 20 ],
219 ],
220 ];
221 ok($img->polypolygon
222 (
223 points => $poly,
224 filled => 1,
225 color => $white,
226 ), "default polypolygon");
227 push @out_files, "testout/250-poly-ppeo.ppm";
228 ok($img->write(file => "testout/250-poly-ppeo.ppm"),
229 "save to file");
230 my $cmp_eo = Imager->new(xsize => 100, ysize => 100);
231 $cmp_eo->box(filled => 1, color => $white, box => [ 10, 10, 89, 89 ]);
232 $cmp_eo->box(filled => 1, color => $black, box => [ 20, 20, 44, 79 ]);
233 $cmp_eo->box(filled => 1, color => $black, box => [ 55, 20, 79, 79 ]);
234 is_image($img, $cmp_eo, "check even/odd matches");
235 $img = Imager->new(xsize => 100, ysize => 100);
236 ok($img->polypolygon
237 (
238 points => $poly,
239 filled => 1,
240 color => $white,
241 mode => "nonzero",
242 ), "default polypolygon");
243 my $cmp_nz = Imager->new(xsize => 100, ysize => 100);
244 $cmp_nz->box(filled => 1, color => $white, box => [ 10, 10, 89, 89 ]);
245 $cmp_nz->box(filled => 1, color => $black, box => [ 55, 20, 79, 79 ]);
246 is_image($img, $cmp_nz, "check non-zero matches");
247 push @out_files, "testout/250-poly-ppnz.ppm";
248 ok($img->write(file => "testout/250-poly-ppnz.ppm"),
249 "save to file");
250}
9982a307 251
0d80f37e
TC
252Imager->close_log;
253
254Imager::malloc_state();
9982a307 255
1c5252ed
TC
256#initialized in a BEGIN, later
257my %primitives;
258my %polygens;
9982a307
AMH
259
260sub get_polygon {
261 my $name = shift;
262 if (exists $primitives{$name}) {
263 return @{$primitives{$name}};
264 }
265
266 if (exists $polygens{$name}) {
267 return $polygens{$name}->(@_);
268 }
269
270 die "polygon spec: $name unknown\n";
271}
272
273
274sub make_zoom {
275 my ($img, $sc, $polydata, $linecolor) = @_;
276
277 # scale with nearest neighboor sampling
278 my $timg = $img->scale(scalefactor=>$sc, qtype=>'preview');
279
280 # draw the grid
1c5252ed 281 for(my $lx=0; $lx<$timg->getwidth(); $lx+=$sc) {
9982a307
AMH
282 $timg->line(color=>$green, x1=>$lx, x2=>$lx, y1=>0, y2=>$timg->getheight(), antialias=>0);
283 }
284
1c5252ed 285 for(my $ly=0; $ly<$timg->getheight(); $ly+=$sc) {
9982a307
AMH
286 $timg->line(color=>$green, y1=>$ly, y2=>$ly, x1=>0, x2=>$timg->getwidth(), antialias=>0);
287 }
288 my @data = scale($sc, $sc, @$polydata);
289 push(@data, $data[0]);
290 my ($x, $y) = array_to_refpair(@data);
291
292 $timg->polyline(color=>$linecolor, 'x'=>$x, 'y'=>$y, antialias=>0);
293 return $timg;
294}
295
296# utility functions to manipulate point data
297
298sub scale {
299 my ($x, $y, @data) = @_;
300 return map { [ $_->[0]*$x , $_->[1]*$y ] } @data;
301}
302
303sub translate {
304 my ($x, $y, @data) = @_;
305 map { [ $_->[0]+$x , $_->[1]+$y ] } @data;
306}
307
308sub rotate {
309 my ($rad, @data) = @_;
310 map { [ $_->[0]*cos($rad)+$_->[1]*sin($rad) , $_->[1]*cos($rad)-$_->[0]*sin($rad) ] } @data;
311}
312
313sub array_to_refpair {
314 my (@x, @y);
315 for (@_) {
316 push(@x, $_->[0]);
317 push(@y, $_->[1]);
318 }
319 return \@x, \@y;
320}
321
322
323
324BEGIN {
325%primitives = (
326 box => [ [-0.5,-0.5], [0.5,-0.5], [0.5,0.5], [-0.5,0.5] ],
327 triangle => [ [0,0], [1,0], [1,1] ],
328 );
02d1d628 329
9982a307
AMH
330%polygens = (
331 wavycircle => sub {
332 my $numv = shift;
333 my $radfunc = shift;
334 my @radians = map { $_*2*PI/$numv } 0..$numv-1;
335 my @radius = map { $radfunc->($_) } @radians;
336 map {
d0e7bfee 337 [ $radius[$_] * cos($radians[$_]), $radius[$_] * sin($radians[$_]) ]
9982a307
AMH
338 } 0..$#radians;
339 },
340 n_gon => sub {
341 my $N = shift;
342 map {
343 [ cos($_*2*PI/$N), sin($_*2*PI/$N) ]
344 } 0..$N-1;
345 },
346);
347}