minor bugfixes and speed improvements in polygon intersector
[swftools.git] / lib / gfxpoly / test.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <memory.h>
4 #include <math.h>
5 #include "../gfxtools.h"
6 #include "poly.h"
7 #include "convert.h"
8 #include "renderpoly.h"
9
10 gfxline_t*mkstar(int x1, int y1, int x2, int y2)
11 {
12     gfxline_t*l=0,*line = 0;
13     int x;
14     for(x=x1;x<=x2;x+=50) {
15         l = rfx_calloc(sizeof(gfxline_t));
16         l->type = gfx_moveTo;
17         l->x = x;l->y = y1;
18         line = gfxline_append(line, l);
19
20         l = rfx_calloc(sizeof(gfxline_t));
21         l->type = gfx_lineTo;
22         l->x = x2-x;l->y = y2;
23         line = gfxline_append(line, l);
24     }
25     return line;
26 }
27
28 gfxline_t* mkrandomshape(int range, int n)
29 {
30     int i;
31     gfxline_t* line = malloc(sizeof(gfxline_t)*n*2);
32     for(i=0;i<n;i++) {
33         line[i].type = i?gfx_lineTo:gfx_moveTo;
34         line[i].x = lrand48()%range - range/2;
35         line[i].y = lrand48()%range - range/2;
36         line[i].next = &line[i+1];
37         line[n*2-i-1].type = gfx_lineTo;
38         line[n*2-i-1].x = line[i].x;
39         line[n*2-i-1].y = line[i].y;
40         line[n*2-i-1].next = &line[n*2-i];
41     }
42     line[n*2-1].next = 0;
43     line[n-1].x = line[0].x;
44     line[n-1].y = line[0].y;
45     line[n-1].next = 0;
46 }
47
48 gfxline_t* mkchessboard()
49 {
50     gfxline_t*b = 0;
51     int x,y;
52     unsigned int r = 0;
53     int spacing = 20;
54
55     int num_caros = 40;
56     int l = 5;
57     char do_centerpiece=1;
58
59     //int num_caros = 4;
60     //int l=1;
61     //char do_centerpiece=0;
62
63     for(x=-l;x<=l;x++) 
64     for(y=-l;y<=l;y++) {
65         /* pseudo random */ 
66         r = crc32_add_byte(r, x);r = crc32_add_byte(r, y);
67         if(r&1) {
68             gfxline_t*box;
69             if(r&2) {
70                 box = gfxline_makerectangle(x*spacing,y*spacing,(x+1)*spacing,(y+1)*spacing);
71             } else {
72                 box = gfxline_makerectangle((x+1)*spacing,y*spacing,x*spacing,(y+1)*spacing);
73             }
74             b = gfxline_append(b, box);
75         }
76     }
77
78     int t;
79     for(t=0;t<num_caros;t++) {
80         r = crc32_add_byte(r, t);
81         int x=(r%10-5)*spacing;
82         int y=((r>>4)%10-5)*spacing;
83         int sizex = ((r>>8)%4)*spacing;
84         int sizey = sizex;
85         if(r&65536)
86             sizex = -sizex;
87         gfxline_t*l = malloc(sizeof(gfxline_t)*5);
88         l[0].type = gfx_moveTo;l[0].next = &l[1];
89         l[1].type = gfx_lineTo;l[1].next = &l[2];
90         l[2].type = gfx_lineTo;l[2].next = &l[3];
91         l[3].type = gfx_lineTo;l[3].next = &l[4];
92         l[4].type = gfx_lineTo;l[4].next = 0;
93         l[0].x = x;
94         l[0].y = y-sizey;
95         l[1].x = x+sizex;
96         l[1].y = y;
97         l[2].x = x;
98         l[2].y = y+sizey;
99         l[3].x = x-sizex;
100         l[3].y = y;
101         l[4].x = x;
102         l[4].y = y-sizey;
103         gfxline_append(b, l);
104     }
105     if(do_centerpiece)
106     for(t=0;t<5;t++) {
107         gfxline_t*l = gfxline_makerectangle(-9*spacing,-10,9*spacing,10);
108         gfxmatrix_t matrix;
109         memset(&matrix, 0, sizeof(gfxmatrix_t));
110         double ua=t*0.43;
111         matrix.m00=cos(ua);matrix.m10=sin(ua);
112         matrix.m01=-sin(ua);matrix.m11=cos(ua);
113         gfxline_transform(l, &matrix);
114         gfxline_append(b, l);
115     }
116     return b;
117 }
118
119 static windcontext_t onepolygon = {1};
120
121 int test0()
122 {
123     gfxline_t* b = mkchessboard();
124
125     gfxmatrix_t m;
126     memset(&m, 0, sizeof(gfxmatrix_t));
127     int t;
128     for(t=0;t<360;t++) {
129     m.m00 = cos(t*M_PI/180.0);
130     m.m01 = sin(t*M_PI/180.0);
131     m.m10 = -sin(t*M_PI/180.0);
132     m.m11 = cos(t*M_PI/180.0);
133     m.tx = 400*1.41/2;
134     m.ty = 400*1.41/2;
135     gfxline_transform(b, &m);
136
137     gfxpoly_t*poly = gfxpoly_from_gfxline(b, 0.05);
138     gfxpoly_t*poly2 = gfxpoly_process(poly, &windrule_evenodd, &onepolygon);
139     gfxpoly_destroy(poly2);
140     gfxpoly_destroy(poly);
141 }
142 }
143
144 int test1(int argn, char*argv[])
145 {
146     gfxline_t*box1 = gfxline_makerectangle(50,50,150,150);
147     // put box2 and box3 on top of each other *snicker*
148     gfxline_t*box2 = gfxline_makerectangle(100,100,200,200);
149     gfxline_t*box3 = gfxline_makerectangle(100,100,200,200);
150     gfxline_t*star = mkstar(50,50, 150,150);
151     gfxline_t*b = 0;
152     b = gfxline_append(b, box1);
153     b = gfxline_append(b, box2);
154     b = gfxline_append(b, box3);
155     //b = gfxline_append(b, star);
156
157     gfxmatrix_t matrix;
158     memset(&matrix, 0, sizeof(gfxmatrix_t));
159     double ua=0.1;
160     matrix.m00=cos(ua);matrix.m10=sin(ua);
161     matrix.m01=-sin(ua);matrix.m11=cos(ua);
162
163     //gfxline_transform(b, &matrix);
164
165     gfxpoly_t*poly = gfxpoly_from_gfxline(b, 0.05);
166     gfxline_free(box1);
167     gfxline_free(box2);
168     gfxline_free(box3);
169     gfxline_free(star);
170
171     gfxpoly_dump(poly);
172     gfxpoly_t*poly2 = gfxpoly_process(poly, &windrule_evenodd, &onepolygon);
173     gfxpoly_destroy(poly2);
174     gfxpoly_destroy(poly);
175 }
176
177 int test_square(int width, int height, int num, double gridsize, char bitmaptest)
178 {
179     int t;
180     gfxline_t* line = malloc(sizeof(gfxline_t)*num);
181     for(t=0;t<num;t++) {
182         line[t].type = t?gfx_lineTo:gfx_moveTo;
183         line[t].x = (lrand48()%width);
184         line[t].y = (lrand48()%height);
185         line[t].next = &line[t+1];
186     }
187     line[num-1].x = line[0].x;
188     line[num-1].y = line[0].y;
189     line[num-1].next = 0;
190     
191     gfxpoly_t*poly = gfxpoly_from_gfxline(line, gridsize);
192     gfxline_free(line);
193
194     windrule_t*rule = &windrule_circular;
195     gfxpoly_t*poly2 = gfxpoly_process(poly, rule, &onepolygon);
196     if(bitmaptest) {
197         intbbox_t bbox = intbbox_new(0, 0, width, height);
198         unsigned char*bitmap1 = render_polygon(poly, &bbox, 1.0, rule, &onepolygon);
199         unsigned char*bitmap2 = render_polygon(poly2, &bbox, 1.0, &windrule_evenodd, &onepolygon);
200         if(!compare_bitmaps(&bbox, bitmap1, bitmap2)) {
201             save_two_bitmaps(&bbox, bitmap1, bitmap2, "error.png");
202             assert(!"bitmaps don't match");
203         }
204     }
205     gfxpoly_destroy(poly2);
206     gfxpoly_destroy(poly);
207 }
208
209 int test2(int argn, char*argv[])
210 {
211     test_square(400,400, 3, 0.05, 1);
212
213     int t;
214     for(t=0;t<400;t++) {
215         test_square(400,400, 50, 0.05, 1);
216         test_square(200,3, 1000, 1.0, 0);
217         test_square(3,200, 1000, 1.0, 0);
218         test_square(10,10, 200, 1.0, 0);
219     }
220 }
221
222 #include "../rfxswf.h"
223 void test3(int argn, char*argv[])
224 {
225 #undef N
226 #undef RANGE
227 #define N 100
228 #define RANGE 400
229
230     //gfxline_t*line = mkrandomshape(RANGE, N);
231     //windrule_t*rule = &windrule_circular;
232     gfxline_t*line = mkchessboard();
233     //windrule_t*rule = &windrule_evenodd;
234     windrule_t*rule = &windrule_circular;
235
236     gfxmatrix_t m;
237     memset(&m, 0, sizeof(m));
238
239     SWF swf;
240     memset(&swf, 0, sizeof(SWF));
241     swf.movieSize.xmax = RANGE*20*1.41;
242     swf.movieSize.ymax = RANGE*20*1.41;
243     swf.fileVersion = 9;
244     swf.frameRate = 25*0x100;
245     TAG * tag = swf.firstTag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
246     swf_SetU8(tag, 0);
247     swf_SetU8(tag, 0);
248     swf_SetU8(tag, 0);
249
250     int t;
251     for(t=0;t<360;t++) {
252         m.m00 = cos(t*M_PI/180.0);
253         m.m01 = sin(t*M_PI/180.0);
254         m.m10 = -sin(t*M_PI/180.0);
255         m.m11 = cos(t*M_PI/180.0);
256         m.tx = RANGE*1.41/2;
257         m.ty = RANGE*1.41/2;
258
259         gfxline_t*l = gfxline_clone(line);
260         gfxline_transform(l, &m);
261         
262         gfxpoly_t*poly = gfxpoly_from_gfxline(l, 0.05);
263         gfxpoly_t*poly2 = gfxpoly_process(poly, rule, &onepolygon);
264
265         tag = swf_InsertTag(tag, ST_DEFINESHAPE);
266         SHAPE* s;
267         swf_ShapeNew(&s);
268         RGBA rgb;
269         rgb.r = rgb.g = 0x00; rgb.b = 0xff;
270         rgb.a = 255;
271         int fs = swf_ShapeAddSolidFillStyle(s,&rgb);
272         int ls = swf_ShapeAddLineStyle(s,20,&rgb);
273         swf_SetU16(tag,t+1);
274         swf_SetRect(tag,&swf.movieSize);
275         swf_SetShapeHeader(tag,s);
276
277 #define FILL
278 #ifdef FILL
279         swf_ShapeSetAll(tag,s,0,0,0,fs,0);
280         edge_t*e = poly2->edges;
281         while(e) {
282 #define ROTATE
283 #ifdef ROTATE
284             swf_ShapeSetMove(tag, s, e->a.y, e->a.x);
285             swf_ShapeSetLine(tag, s, e->b.y - e->a.y, e->b.x - e->a.x);
286 #else
287             swf_ShapeSetMove(tag, s, e->a.x, e->a.y);
288             swf_ShapeSetLine(tag, s, e->b.x - e->a.x, e->b.y - e->a.y);
289 #endif
290             e = e->next;
291         }
292 #else
293         swf_ShapeSetAll(tag,s,0,0,ls,0,0);
294         edge_t*e = poly2->edges;
295         while(e) {
296             swf_ShapeSetMove(tag, s, e->a.x, e->a.y);
297             swf_ShapeSetLine(tag, s, e->b.x - e->a.x, e->b.y - e->a.y);
298             
299             swf_ShapeSetCircle(tag, s, e->a.x, e->a.y, 5*20, 5*20);
300             swf_ShapeSetCircle(tag, s, e->b.x, e->b.y, 5*20, 5*20);
301             e = e->next;
302         }
303 #endif
304
305         swf_ShapeSetEnd(tag);
306         swf_ShapeFree(s);
307
308         gfxpoly_destroy(poly);
309         gfxpoly_destroy(poly2);
310
311         gfxline_free(l);
312    
313         if(t) {
314             tag = swf_InsertTag(tag,ST_REMOVEOBJECT2);
315             swf_SetU16(tag, t);
316         }
317         tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
318         swf_ObjectPlace(tag,t+1,t+1,NULL,NULL,NULL);
319
320         tag = swf_InsertTag(tag, ST_SHOWFRAME);
321     }
322     tag = swf_InsertTag(tag, ST_END);
323
324     swf_SaveSWF(&swf, "test.swf");
325 }
326
327 void rotate90(gfxpoly_t*poly)
328 {
329     edge_t*e = poly->edges;
330     while(e) {
331         point_t a = e->a;
332         point_t b = e->b;
333         e->a.x = a.y;
334         e->a.y = a.x;
335         e->b.x = b.y;
336         e->b.y = b.x;
337         e = e->next;
338     }
339 }
340
341 #include <dirent.h>
342 void test4(int argn, char*argv[])
343 {
344     char*dir = "ps";
345     DIR*_dir = opendir(dir);
346     if(!_dir) return;
347     struct dirent*file;
348     while(1) {
349         file = readdir(_dir);
350         if (!file) 
351             break;
352         if(!strstr(file->d_name, ".ps")) 
353             continue;
354
355         char* filename;
356
357         if(argn<2)
358             filename = allocprintf("%s/%s", dir, file->d_name);
359         else
360             filename = argv[1];
361
362         windrule_t*rule = &windrule_evenodd;
363         gfxpoly_t*poly = gfxpoly_from_file(filename, 1.0);//0.01);
364
365         if(argn!=2)
366             free(filename);
367
368         double zoom = 1.0;
369
370         if(!gfxpoly_check(poly)) {
371             printf("bad polygon\n");
372             continue;
373         }
374
375         gfxpoly_t*poly2 = gfxpoly_process(poly, rule, &onepolygon);
376
377         int pass;
378         for(pass=0;pass<2;pass++) {
379             intbbox_t bbox = intbbox_from_polygon(poly, zoom);
380             unsigned char*bitmap1 = render_polygon(poly, &bbox, zoom, rule, &onepolygon);
381             unsigned char*bitmap2 = render_polygon(poly2, &bbox, zoom, &windrule_evenodd, &onepolygon);
382             if(!bitmap_ok(&bbox, bitmap1) || !bitmap_ok(&bbox, bitmap2)) {
383                 save_two_bitmaps(&bbox, bitmap1, bitmap2, "error.png");
384                 assert(!"error in bitmaps");
385             }
386             if(!compare_bitmaps(&bbox, bitmap1, bitmap2)) {
387                 save_two_bitmaps(&bbox, bitmap1, bitmap2, "error.png");
388                 assert(!"bitmaps don't match");
389             }
390             free(bitmap1);
391             free(bitmap2);
392             
393             // second pass renders the 90° rotated version
394             rotate90(poly);
395             rotate90(poly2);
396         }
397
398         gfxpoly_destroy(poly);
399         gfxpoly_destroy(poly2);
400         if(argn==2) 
401             break;
402     }
403     closedir(_dir);
404 }
405
406 #include "../gfxdevice.h"
407 #include "../pdf/pdf.h"
408
409 void extract_polygons_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color) 
410 {
411     gfxpoly_t*poly = gfxpoly_from_gfxline(line, 0.05);
412     if(gfxpoly_size(poly)>100000) {
413         printf("%d segments (skipping)\n", gfxpoly_size(poly));
414         return;
415     } else {
416         printf("%d segments\n", gfxpoly_size(poly));
417     }
418
419     if(!gfxpoly_check(poly)) {
420         gfxpoly_destroy(poly);
421         printf("bad polygon\n");
422         return;
423     }
424
425     windrule_t*rule = &windrule_evenodd;
426         
427     double zoom = 1.0;
428     intbbox_t bbox = intbbox_from_polygon(poly, zoom);
429     unsigned char*bitmap1 = render_polygon(poly, &bbox, zoom, rule, &onepolygon);
430     if(!bitmap_ok(&bbox, bitmap1)) {
431         printf("bad polygon or error in renderer\n");
432         return;
433     }
434     gfxpoly_t*poly2 = gfxpoly_process(poly, rule, &onepolygon);
435     unsigned char*bitmap2 = render_polygon(poly2, &bbox, zoom, &windrule_evenodd, &onepolygon);
436     if(!bitmap_ok(&bbox, bitmap2)) {
437         save_two_bitmaps(&bbox, bitmap1, bitmap2, "error.png");
438         assert(!"error in bitmap");
439     }
440     if(!compare_bitmaps(&bbox, bitmap1, bitmap2)) {
441         save_two_bitmaps(&bbox, bitmap1, bitmap2, "error.png");
442         assert(!"bitmaps don't match");
443     }
444     free(bitmap1);
445     free(bitmap2);
446
447     gfxpoly_destroy(poly);
448     gfxpoly_destroy(poly2);
449 }
450 int extract_polygons_setparameter(gfxdevice_t*dev, const char*key, const char*value) {
451     return 0;
452 }
453 void extract_polygons_startclip(gfxdevice_t*dev, gfxline_t*line) 
454 {
455     extract_polygons_fill(dev, line, 0);
456 }
457 void extract_polygons_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*imgcoord2devcoord, gfxcxform_t*cxform)
458 {
459     extract_polygons_fill(dev, line, 0);
460 }
461 void extract_polygons_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*gradcoord2devcoord)
462 {
463     extract_polygons_fill(dev, line, 0);
464 }
465 void extract_polygons_drawlink(gfxdevice_t*dev, gfxline_t*line, const char*action)
466 {
467     extract_polygons_fill(dev, line, 0);
468 }
469 void extract_polygons_addfont(gfxdevice_t*dev, gfxfont_t*font)
470 {
471     int t;
472     for(t=0;t<font->num_glyphs;t++) {
473         //extract_polygons_fill(dev, font->glyphs[t].line, 0);
474     }
475 }
476 void extract_polygons_endclip(gfxdevice_t*dev)
477 {
478 }
479 void extract_polygons_stroke(gfxdevice_t*dev, gfxline_t*line, gfxcoord_t width, gfxcolor_t*color, gfx_capType cap_style, gfx_joinType joint_style, gfxcoord_t miterLimit)
480 {
481 }
482 void extract_polygons_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyph, gfxcolor_t*color, gfxmatrix_t*matrix)
483 {
484 }
485     
486 gfxdevice_t extract_polygons = 
487 {
488 name: "extract polygons",
489 setparameter:extract_polygons_setparameter,
490 startclip: extract_polygons_startclip,
491 endclip: extract_polygons_endclip,
492 stroke: extract_polygons_stroke,
493 fill: extract_polygons_fill,
494 fillbitmap: extract_polygons_fillbitmap,
495 fillgradient: extract_polygons_fillgradient,
496 addfont: extract_polygons_addfont,
497 drawchar: extract_polygons_drawchar,
498 drawlink: extract_polygons_drawlink,
499 startpage: 0,
500 endpage: 0,
501 geterror: 0,
502 finish: 0,
503 internal: 0
504 };
505
506 void test5(int argn, char*argv[])
507 {
508     gfxsource_t*driver = gfxsource_pdf_create();
509     char*dir = "pdfs";
510     DIR*_dir = opendir(dir);
511     if(!_dir) return;
512     struct dirent*file;
513     while(1) {
514         file = readdir(_dir);
515         if (!file) 
516             break;
517         if(!strstr(file->d_name, ".pdf")) 
518             continue;
519         char* filename = allocprintf("%s/%s", dir, file->d_name);
520
521         gfxdocument_t*doc = driver->open(driver, filename);
522         gfxdevice_t*out = &extract_polygons;
523         int t;
524         for(t=1;t<=doc->num_pages;t++) {
525             printf("%s (page %d)\n", filename, t);
526             gfxpage_t* page = doc->getpage(doc, t);
527             page->render(page, out);
528             page->destroy(page);
529         }
530         doc->destroy(doc);
531         free(filename);
532     }
533     closedir(_dir);
534     driver->destroy(driver);
535 }
536
537 int main(int argn, char*argv[])
538 {
539     test3(argn, argv);
540 }