polygon intersector: improved test routines
[swftools.git] / lib / gfxpoly.c
index acf2de3..76352af 100644 (file)
 #include "gfxtools.h"
 #include "gfxpoly.h"
 #include "mem.h"
 #include "gfxtools.h"
 #include "gfxpoly.h"
 #include "mem.h"
+#ifdef INTERNAL_LIBART
 #include "art/libart.h"
 #include "art/art_svp_intersect.h"
 #include "art/art_svp_ops.h"
 #include "art/libart.h"
 #include "art/art_svp_intersect.h"
 #include "art/art_svp_ops.h"
+#else
+#include <libart_lgpl/libart.h>
+#include <libart_lgpl/art_svp_intersect.h>
+#include <libart_lgpl/art_svp_ops.h>
+#endif
 #include "log.h"
 #include <assert.h>
 #include <memory.h>
 #include "log.h"
 #include <assert.h>
 #include <memory.h>
@@ -233,6 +239,9 @@ unsigned char* render_svp(ArtSVP*svp, intbbox_t*bbox, double zoom, ArtWindRule r
     return image;
 }
 
     return image;
 }
 
+#define MAX_WIDTH 8192
+#define MAX_HEIGHT 4096
+
 intbbox_t get_svp_bbox(ArtSVP*svp, double zoom)
 {
     int t;
 intbbox_t get_svp_bbox(ArtSVP*svp, double zoom)
 {
     int t;
@@ -256,9 +265,23 @@ intbbox_t get_svp_bbox(ArtSVP*svp, double zoom)
             if(x1 < b.xmin) b.xmin = x1;
             if(y1 < b.ymin) b.ymin = y1;
             if(x2 > b.xmax) b.xmax = x2;
             if(x1 < b.xmin) b.xmin = x1;
             if(y1 < b.ymin) b.ymin = y1;
             if(x2 > b.xmax) b.xmax = x2;
-            if(y2 > b.xmax) b.ymax = y2;
+            if(y2 > b.ymax) b.ymax = y2;
         }
     }
         }
     }
+    if(b.xmax > (int)(MAX_WIDTH*zoom))
+       b.xmax = (int)(MAX_WIDTH*zoom);
+    if(b.ymax > (int)(MAX_HEIGHT*zoom))
+       b.ymax = (int)(MAX_HEIGHT*zoom);
+    if(b.xmin < -(int)(MAX_WIDTH*zoom))
+       b.xmin = -(int)(MAX_WIDTH*zoom);
+    if(b.ymin < -(int)(MAX_HEIGHT*zoom))
+       b.ymin = -(int)(MAX_HEIGHT*zoom);
+    
+    if(b.xmin > b.xmax) 
+       b.xmin = b.xmax;
+    if(b.ymin > b.ymax) 
+       b.ymin = b.ymax;
+
     b.width = b.xmax - b.xmin;
     b.height = b.ymax - b.ymin;
     return b;
     b.width = b.xmax - b.xmin;
     b.height = b.ymax - b.ymin;
     return b;
@@ -281,49 +304,37 @@ intbbox_t get_svp_bbox(ArtSVP*svp, double zoom)
 
 int compare_bitmaps(intbbox_t*bbox, unsigned char*data1, unsigned char*data2)
 {
 
 int compare_bitmaps(intbbox_t*bbox, unsigned char*data1, unsigned char*data2)
 {
-    int similar = 0;
+    if(!data1 || !data2) 
+        return 0;
     int x,y;
     int height = bbox->height;
     int width = bbox->width;
     int width8 = (width+7) >> 3;
     unsigned char*l1 = &data1[width8];
     unsigned char*l2 = &data2[width8];
     int x,y;
     int height = bbox->height;
     int width = bbox->width;
     int width8 = (width+7) >> 3;
     unsigned char*l1 = &data1[width8];
     unsigned char*l2 = &data2[width8];
-    int fail = 0;
     for(y=1;y<height-1;y++) {
         for(x=0;x<width8;x++) {
             unsigned a = l1[x-width8] & l1[x] & l1[x+width8];
             unsigned b = l2[x-width8] & l2[x] & l2[x+width8];
     for(y=1;y<height-1;y++) {
         for(x=0;x<width8;x++) {
             unsigned a = l1[x-width8] & l1[x] & l1[x+width8];
             unsigned b = l2[x-width8] & l2[x] & l2[x+width8];
-
-            if((a&B11100000) && !(l2[x]&B01000000))
-                fail == 1;
-            if((a&B01110000) && !(l2[x]&B00100000))
-                fail == 1;
-            if((a&B00111000) && !(l2[x]&B00010000))
-                fail == 1;
-            if((a&B00011100) && !(l2[x]&B00001000))
-                fail == 1;
-            if((a&B00001110) && !(l2[x]&B00000100))
-                fail == 1;
-            if((a&B00000111) && !(l2[x]&B00000010))
-                fail == 1;
-
-            if((b&B11100000) && !(l1[x]&B01000000))
-                fail == 1;
-            if((b&B01110000) && !(l1[x]&B00100000))
-                fail == 1;
-            if((b&B00111000) && !(l1[x]&B00010000))
-                fail == 1;
-            if((b&B00011100) && !(l1[x]&B00001000))
-                fail == 1;
-            if((b&B00001110) && !(l1[x]&B00000100))
-                fail == 1;
-            if((b&B00000111) && !(l1[x]&B00000010))
-                fail == 1;
+            
+            if((a&B11100000) && !(l2[x]&B01000000)) return 0;
+            if((a&B01110000) && !(l2[x]&B00100000)) return 0;
+            if((a&B00111000) && !(l2[x]&B00010000)) return 0;
+            if((a&B00011100) && !(l2[x]&B00001000)) return 0;
+            if((a&B00001110) && !(l2[x]&B00000100)) return 0;
+            if((a&B00000111) && !(l2[x]&B00000010)) return 0;
+
+            if((b&B11100000) && !(l1[x]&B01000000)) return 0;
+            if((b&B01110000) && !(l1[x]&B00100000)) return 0;
+            if((b&B00111000) && !(l1[x]&B00010000)) return 0;
+            if((b&B00011100) && !(l1[x]&B00001000)) return 0;
+            if((b&B00001110) && !(l1[x]&B00000100)) return 0;
+            if((b&B00000111) && !(l1[x]&B00000010)) return 0;
         }
         l1 += width8;
         l2 += width8;
     }
         }
         l1 += width8;
         l2 += width8;
     }
-    return !fail;
+    return 1;
 }
 
 
 }
 
 
@@ -361,11 +372,13 @@ static ArtVpath* gfxline_to_ArtVpath(gfxline_t*line, char fill)
 
     pos = 0;
     l2 = line;
 
     pos = 0;
     l2 = line;
+    int lastmove=-1;
     while(l2) {
        if(l2->type == gfx_moveTo) {
            vec[pos].code = ART_MOVETO_OPEN;
            vec[pos].x = l2->x;
            vec[pos].y = l2->y;
     while(l2) {
        if(l2->type == gfx_moveTo) {
            vec[pos].code = ART_MOVETO_OPEN;
            vec[pos].x = l2->x;
            vec[pos].y = l2->y;
+            lastmove=pos;
            pos++; 
            assert(pos<=len);
        } else if(l2->type == gfx_lineTo) {
            pos++; 
            assert(pos<=len);
        } else if(l2->type == gfx_lineTo) {
@@ -390,6 +403,16 @@ static ArtVpath* gfxline_to_ArtVpath(gfxline_t*line, char fill)
        }
        x = l2->x;
        y = l2->y;
        }
        x = l2->x;
        y = l2->y;
+       
+        /* let closed line segments start w/ MOVETO instead of MOVETO_OPEN */
+        if(lastmove>=0 && l2->type!=gfx_moveTo && (!l2->next || l2->next->type == gfx_moveTo)) {
+            if(vec[lastmove].x == l2->x &&
+               vec[lastmove].y == l2->y) {
+                assert(vec[lastmove].code == ART_MOVETO_OPEN);
+                vec[lastmove].code = ART_MOVETO;
+            }
+        }
+
        l2 = l2->next;
     }
     vec[pos++].code = ART_END;
        l2 = l2->next;
     }
     vec[pos++].code = ART_END;
@@ -414,7 +437,7 @@ static ArtVpath* gfxline_to_ArtVpath(gfxline_t*line, char fill)
     }
 
     /* Find adjacent identical points. If an ajdacent pair of identical
     }
 
     /* Find adjacent identical points. If an ajdacent pair of identical
-       points is found, the second is removed.
+       points is found, the second one is removed.
        So moveto x,y lineto x,y becomes moveto x,y
           lineto x,y lineto x,y becomes lineto x,y
           lineto x,y moveto x,y becomes lineto x,y
        So moveto x,y lineto x,y becomes moveto x,y
           lineto x,y lineto x,y becomes lineto x,y
           lineto x,y moveto x,y becomes lineto x,y
@@ -506,7 +529,13 @@ static double find_shear_value(ArtSVP*svp)
         }
         if(!fail) 
             break;
         }
         if(!fail) 
             break;
-        v = lrand48() / 2000000000.0;
+#ifdef HAVE_LRAND48
+       v = lrand48() / 2000000000.0;;
+#elif HAVE_RAND
+        v = rand() / 2000000000.0;
+#else
+#error "no lrand48()/rand() implementation found"
+#endif
         tries++;
     }
     return v;
         tries++;
     }
     return v;
@@ -657,7 +686,7 @@ int check_svp(ArtSVP*svp)
     qsort(seg_start, num_segs, sizeof(svp_segment_part_t*), compare_seg_start);
     qsort(seg_end, num_segs, sizeof(svp_segment_part_t*), compare_seg_end);
 
     qsort(seg_start, num_segs, sizeof(svp_segment_part_t*), compare_seg_start);
     qsort(seg_end, num_segs, sizeof(svp_segment_part_t*), compare_seg_end);
 
-    double lasty = y[0]+1;
+    double lasty = num_points?y[0]+1:0;
     int num_active = 0;
     int bleed = 0;
     double bleedy1=0,bleedy2 = 0;
     int num_active = 0;
     int bleed = 0;
     double bleedy1=0,bleedy2 = 0;
@@ -706,7 +735,6 @@ void write_svp_postscript(const char*filename, ArtSVP*svp)
 {
     if(!svp)
        return;
 {
     if(!svp)
        return;
-    printf("writing %s\n", filename);
     FILE*fi = fopen(filename, "wb");
     int i, j;
     double xmin=0,ymin=0,xmax=0,ymax=0;
     FILE*fi = fopen(filename, "wb");
     int i, j;
     double xmin=0,ymin=0,xmax=0,ymax=0;
@@ -906,11 +934,6 @@ static ArtSVP* gfxfillToSVP(gfxline_t*line, int perturb)
 //#endif
 
 
 //#endif
 
 
-
-extern const ArtSVP* current_svp;
-extern void art_report_error();
-extern int art_error_in_intersector;
-
 ArtSVP* run_intersector(ArtSVP*svp, ArtWindRule rule)
 {
     ArtSvpWriter * swr = art_svp_writer_rewind_new(rule);
 ArtSVP* run_intersector(ArtSVP*svp, ArtWindRule rule)
 {
     ArtSvpWriter * swr = art_svp_writer_rewind_new(rule);
@@ -925,9 +948,9 @@ ArtSVP* run_intersector(ArtSVP*svp, ArtWindRule rule)
        current_svp = result;
        art_report_error(); // might set art_error_in_intersector
     } else {
        current_svp = result;
        art_report_error(); // might set art_error_in_intersector
     } else {
+        msg("<verbose> Comparing polygon renderings of size %dx%d and %dx%d", bbox.width, bbox.height, bbox.width, bbox.height);
         unsigned char*data1 = render_svp(svp, &bbox, zoom, rule);
         unsigned char*data2 = render_svp(result, &bbox, zoom, ART_WIND_RULE_ODDEVEN);
         unsigned char*data1 = render_svp(svp, &bbox, zoom, rule);
         unsigned char*data2 = render_svp(result, &bbox, zoom, ART_WIND_RULE_ODDEVEN);
-        msg("<verbose> Comparing polygon renderings of size %dx%d and %dx%d", bbox.width, bbox.height, bbox.width, bbox.height);
         if(!compare_bitmaps(&bbox, data1, data2)) {
             msg("<verbose> Bad SVP rewinding result- polygons don't match");
             current_svp = result;
         if(!compare_bitmaps(&bbox, data1, data2)) {
             msg("<verbose> Bad SVP rewinding result- polygons don't match");
             current_svp = result;
@@ -984,7 +1007,7 @@ gfxline_t* gfxpoly_to_gfxline(gfxpoly_t*poly)
 gfxpoly_t* gfxpoly_fillToPoly(gfxline_t*line)
 {
     /* I'm not sure whether doing perturbation here is actually
 gfxpoly_t* gfxpoly_fillToPoly(gfxline_t*line)
 {
     /* I'm not sure whether doing perturbation here is actually
-       a good idea- if that line has been run through the machine
+       a good idea- if that line has been run through the machinery
        several times already, it might be safer to leave it alone,
        since it should already be in a format libart can handle */
 #ifdef PERTURBATE
        several times already, it might be safer to leave it alone,
        since it should already be in a format libart can handle */
 #ifdef PERTURBATE
@@ -1110,14 +1133,9 @@ gfxline_t* gfxline_circularToEvenOdd(gfxline_t*line)
     msg("<verbose> Converting circular-filled gfxline of %d segments to even-odd filled gfxline", gfxline_len(line));
     ArtSVP* svp = gfxfillToSVP(line, 1);
 
     msg("<verbose> Converting circular-filled gfxline of %d segments to even-odd filled gfxline", gfxline_len(line));
     ArtSVP* svp = gfxfillToSVP(line, 1);
 
-    /* TODO: ART_WIND_RULE_POSITIVE means that a shape is visible if
-             positive and negative line segments add up to something positive.
-             I *think* that clockwise fill in PDF is defined in a way, however,
-             that the *last* shape's direction will determine whether something
-             is filled */
     ArtSVP* svp_rewinded;
     
     ArtSVP* svp_rewinded;
     
-    svp_rewinded = run_intersector(svp, ART_WIND_RULE_POSITIVE);
+    svp_rewinded = run_intersector(svp, ART_WIND_RULE_NONZERO);
     if(!svp_rewinded) {
        art_svp_free(svp);
        return 0;
     if(!svp_rewinded) {
        art_svp_free(svp);
        return 0;