made gfxpoly_check test for correct circular filling
authorMatthias Kramm <kramm@quiss.org>
Wed, 7 Apr 2010 23:41:57 +0000 (16:41 -0700)
committerMatthias Kramm <kramm@quiss.org>
Wed, 7 Apr 2010 23:41:57 +0000 (16:41 -0700)
lib/gfxpoly/poly.c
lib/gfxpoly/poly.h
lib/gfxpoly/renderpoly.c
lib/gfxpoly/stroke.c
lib/gfxpoly/test.c
lib/gfxpoly/test_stroke.c
lib/gfxpoly/wind.c

index 02193df..9ffc770 100644 (file)
@@ -165,10 +165,11 @@ int gfxpoly_size(gfxpoly_t*poly)
     return edges;
 }
 
-char gfxpoly_check(gfxpoly_t*poly)
+char gfxpoly_check(gfxpoly_t*poly, char updown)
 {
     current_polygon = poly;
-    dict_t*d = dict_new2(&point_type);
+    dict_t*d1 = dict_new2(&point_type);
+    dict_t*d2 = dict_new2(&point_type);
     int s,t;
     gfxpolystroke_t*stroke = poly->strokes;
     for(;stroke;stroke=stroke->next) {
@@ -180,26 +181,54 @@ char gfxpoly_check(gfxpoly_t*poly)
           that the endpoint multiplicity is two */
        for(s=0;s<stroke->num_points;s++) {
            point_t p = stroke->points[s];
-           int num = (s>=1 && s<stroke->num_points-1)?2:1; // mid points are two points (start+end)
-           if(!dict_contains(d, &p)) {
-               dict_put(d, &p, (void*)(ptroff_t)num);
+           int num_xor = (s>=1 && s<stroke->num_points-1)?2:1; // mid points are two points (start+end)
+           int num_circ = (s>=1 && s<stroke->num_points-1)?0:(s==0?1:-1);
+           if(stroke->dir==DIR_UP)
+               num_circ=-num_circ;
+
+           if(!dict_contains(d1, &p)) {
+               dict_put(d1, &p, (void*)(ptroff_t)num_xor);
+               if(updown) {
+                   assert(!dict_contains(d2, &p));
+                   dict_put(d2, &p, (void*)(ptroff_t)num_circ);
+               }
            } else {
-               int count = (ptroff_t)dict_lookup(d, &p);
-               dict_del(d, &p);
-               count+=num;
-               dict_put(d, &p, (void*)(ptroff_t)count);
+               int count = (ptroff_t)dict_lookup(d1, &p);
+               dict_del(d1, &p);
+               count+=num_xor;
+               dict_put(d1, &p, (void*)(ptroff_t)count);
+
+               if(updown) {
+                   assert(dict_contains(d2, &p));
+                   count = (ptroff_t)dict_lookup(d2, &p);
+                   dict_del(d2, &p);
+                   count+=num_circ;
+                   dict_put(d2, &p, (void*)(ptroff_t)count);
+               }
            }
        }
     }
-    DICT_ITERATE_ITEMS(d, point_t*, p, void*, c) {
-        int count = (ptroff_t)c;
+    DICT_ITERATE_ITEMS(d1, point_t*, p1, void*, c1) {
+        int count = (ptroff_t)c1;
         if(count&1) {
-            fprintf(stderr, "Point (%d,%d) occurs %d times\n", p->x, p->y, count);
-            dict_destroy(d);
+            fprintf(stderr, "Point (%d,%d) occurs %d times\n", p1->x, p1->y, count);
+            dict_destroy(d1);
            return 0;
         }
     }
-    dict_destroy(d);
+    if(updown) {
+       DICT_ITERATE_ITEMS(d2, point_t*, p2, void*, c2) {
+           int count = (ptroff_t)c2;
+           if(count!=0) {
+               if(count>0) fprintf(stderr, "Point (%d,%d) has %d more incoming than outgoing segments\n", p2->x, p2->y, count);
+               if(count<0) fprintf(stderr, "Point (%d,%d) has %d more outgoing than incoming segments\n", p2->x, p2->y, -count);
+               dict_destroy(d2);
+               return 0;
+           }
+       }
+    }
+    dict_destroy(d1);
+    dict_destroy(d2);
     return 1;
 }
 
@@ -1198,17 +1227,13 @@ static void add_horizontals(gfxpoly_t*poly, windrule_t*windrule, windcontext_t*c
         actlist_verify(actlist, y-1);
 #endif
        edgestyle_t*fill = 0;
-       int dir_up = 0;
-       int dir_down = 0;
+       int wind = 0;
 
         do {
            assert(e->s1->fs);
             if(fill && x != e->p.x) {
-#ifdef DEBUG
-                fprintf(stderr, "%d) draw horizontal line from %d to %d\n", y, x, e->p.x);
-#endif
+               assert(abs(wind)==1);
                assert(x<e->p.x);
-               assert(dir_up || dir_down);
 
                 gfxpolystroke_t*stroke = rfx_calloc(sizeof(gfxpolystroke_t));
                stroke->next = poly->strokes;
@@ -1216,27 +1241,28 @@ static void add_horizontals(gfxpoly_t*poly, windrule_t*windrule, windcontext_t*c
 
                stroke->num_points = 2;
                stroke->points = malloc(sizeof(point_t)*2);
-               if(dir_up < 0 || dir_down > 0) {
-                   stroke->dir = DIR_UP;
-               } else {
+
+               if(wind>0) {
                    stroke->dir = DIR_DOWN;
+               } else {
+                   stroke->dir = DIR_UP;
                }
+#ifdef DEBUG
+                fprintf(stderr, "%d) draw horizontal line from %d to %d (dir=%s)\n", y, x, e->p.x, stroke->dir==DIR_UP?"up":"down");
+#endif
 
                stroke->fs = fill;
                point_t a,b;
                 a.y = b.y = y;
-               /* we draw from low x to high x so that left/right fillstyles add up
-                   (because the horizontal line's fill style controls the area *below* the line)
-                */
-                a.x = e->p.x;
-                b.x = x;
+                a.x = x;
+                b.x = e->p.x;
                stroke->points[0] = a;
                stroke->points[1] = b;
 #ifdef CHECKS
                /* the output should always be intersection free polygons, so check this horizontal
                   line isn't puncturing any segments in the active list */
-               segment_t* start = actlist_find(actlist, b, b);
-               segment_t* s = actlist_find(actlist, a, a);
+               segment_t* start = actlist_find(actlist, a, a);
+               segment_t* s = actlist_find(actlist, b, b);
                while(s!=start) {
                    assert(s->a.y == y || s->b.y == y);
                    s = s->left;
@@ -1258,14 +1284,14 @@ static void add_horizontals(gfxpoly_t*poly, windrule_t*windrule, windcontext_t*c
                     e->s2 = 0;
                     hqueue_put(&hqueue, e);
                     left = actlist_left(actlist, s);
-                   dir_down += e->s1->dir==DIR_UP?1:-1;
+                   wind += e->s1->dir==DIR_DOWN?-1:1;
                     break;
                 }
                 case EVENT_END: {
                     left = actlist_left(actlist, s);
                     actlist_delete(actlist, s);
                    advance_stroke(0, &hqueue, s->stroke, s->polygon_nr, s->stroke_pos);
-                   dir_up += e->s1->dir==DIR_UP?1:-1;
+                   wind += e->s1->dir==DIR_DOWN?1:-1;
                     break;
                 }
                 default: assert(0);
@@ -1297,11 +1323,11 @@ static void add_horizontals(gfxpoly_t*poly, windrule_t*windrule, windcontext_t*c
 #endif
 
 #ifdef DEBUG
-            fprintf(stderr, "%d) event=%s[%d] left:[%d] x:%d\n",
+            fprintf(stderr, "%d) event=%s[%d] left:[%d] x:%d dir:%s\n",
                     y, e->type==EVENT_START?"start":"end",
                     s->nr,
                     left?left->nr:-1,
-                    x);
+                    x, s->dir==DIR_UP?"up":"down");
 #endif
 
             if(e->type == EVENT_END)
@@ -1314,6 +1340,13 @@ static void add_horizontals(gfxpoly_t*poly, windrule_t*windrule, windcontext_t*c
 #ifdef CHECKS
        edgestyle_t*bleeding = fill;
         assert(!bleeding);
+       segment_t*s = actlist_leftmost(actlist);
+       int dir = 0;
+       while(s) {
+           dir += s->dir==DIR_UP?-1:1;
+           s = actlist_right(actlist, s);
+       }
+       assert(!dir);
 #endif
     }
 
index 180a4f1..ccbf65e 100644 (file)
@@ -93,7 +93,7 @@ typedef struct _segment {
 
 void gfxpoly_fail(char*expr, char*file, int line, const char*function);
 
-char gfxpoly_check(gfxpoly_t*poly);
+char gfxpoly_check(gfxpoly_t*poly, char updown);
 int gfxpoly_num_segments(gfxpoly_t*poly);
 int gfxpoly_size(gfxpoly_t*poly);
 void gfxpoly_dump(gfxpoly_t*poly);
index 9594bd2..989dfc8 100644 (file)
@@ -48,7 +48,7 @@ static inline void add_pixel(renderbuf_t*buf, double x, int y, segment_dir_t dir
     l->num++;
 }
 #define CUT 0.5
-static void add_line(renderbuf_t*buf, double x1, double y1, double x2, double y2, edgestyle_t*fs, int polygon_nr)
+static void add_line(renderbuf_t*buf, double x1, double y1, double x2, double y2, edgestyle_t*fs, segment_dir_t dir, int polygon_nr)
 {
     x1 *= buf->zoom;
     y1 *= buf->zoom;
@@ -56,13 +56,14 @@ static void add_line(renderbuf_t*buf, double x1, double y1, double x2, double y2
     y2 *= buf->zoom;
     double diffx, diffy;
     double ny1, ny2, stepx;
-    segment_dir_t dir = DIR_DOWN;
+
     if(y2 < y1) {
-        dir = DIR_UP;
+        dir ^= DIR_UP^DIR_DOWN;
         double x,y;
        x = x1;x1 = x2;x2=x;
        y = y1;y1 = y2;y2=y;
     }
+
     diffx = x2 - x1;
     diffy = y2 - y1;
     ny1 = floor(y1)+CUT;
@@ -86,6 +87,8 @@ static void add_line(renderbuf_t*buf, double x1, double y1, double x2, double y2
     double posx=0;
     double startx = x1;
 
+    //printf("line %d from %f to %f dir=%s\n", polygon_nr, y1, y2, dir==DIR_UP?"up":"down");
+
     while(posy<=endy) {
         double xx = startx + posx;
         add_pixel(buf, xx, posy, dir, fs, polygon_nr);
@@ -145,7 +148,7 @@ unsigned char* render_polygon(gfxpoly_t*polygon, intbbox_t*bbox, double zoom, wi
        for(t=0;t<stroke->num_points-1;t++) {
            point_t a = stroke->points[t];
            point_t b = stroke->points[t+1];
-           add_line(buf, a.x, a.y, b.x, b.y, stroke->fs, polygon_nr);
+           add_line(buf, a.x, a.y, b.x, b.y, stroke->fs, stroke->dir, polygon_nr);
        }
     }
 
@@ -179,6 +182,8 @@ unsigned char* render_polygon(gfxpoly_t*polygon, intbbox_t*bbox, double zoom, wi
             fill_bitwise(line, lastx, width8*8);
            assert(line[width8-1]&0x01);
            bleeding = 1;
+           exit(1);
+
         }
     }
     
index 9735c1b..b9ccb10 100644 (file)
@@ -225,7 +225,7 @@ gfxpoly_t* gfxpoly_from_stroke(gfxline_t*line, gfxcoord_t width, gfx_capType cap
     gfxdrawer_target_poly(&d, gridsize);
     draw_stroke(line, &d, width, cap_style, joint_style, miterLimit);
     gfxpoly_t*poly = (gfxpoly_t*)d.result(&d);
-    assert(gfxpoly_check(poly));
+    assert(gfxpoly_check(poly, 1));
     gfxpoly_t*poly2 = gfxpoly_process(poly, 0, &windrule_circular, &onepolygon);
     gfxpoly_destroy(poly);
     return poly2;
index 509f3ee..a7ba9d7 100644 (file)
@@ -173,7 +173,7 @@ int test0(int argn, char*argv[])
     gfxline_t*box3 = gfxline_makerectangle(-100,-100,100,100);
     //gfxline_append(box2, box3);
 
-    gfxpoly_check(gfxpoly_from_stroke(box1, 2.0, gfx_capRound, gfx_joinRound, 0, 0.05));
+    gfxpoly_check(gfxpoly_from_stroke(box1, 2.0, gfx_capRound, gfx_joinRound, 0, 0.05), 1);
 
     gfxmatrix_t matrix;
     memset(&matrix, 0, sizeof(gfxmatrix_t));
@@ -451,18 +451,19 @@ void test4(int argn, char*argv[])
 
         double zoom = 1.0;
 
-        if(!gfxpoly_check(poly1)) {
+        if(!gfxpoly_check(poly1, 0)) {
             printf("bad polygon\n");
             continue;
         }
 
         gfxpoly_t*poly2 = gfxpoly_process(poly1, 0, rule, &onepolygon);
+       assert(gfxpoly_check(poly2, 1));
 
        int pass;
        for(pass=0;pass<2;pass++) {
            intbbox_t bbox = intbbox_from_polygon(poly1, zoom);
            unsigned char*bitmap1 = render_polygon(poly1, &bbox, zoom, rule, &onepolygon);
-           unsigned char*bitmap2 = render_polygon(poly2, &bbox, zoom, &windrule_evenodd, &onepolygon);
+           unsigned char*bitmap2 = render_polygon(poly2, &bbox, zoom, &windrule_circular, &onepolygon);
            if(!bitmap_ok(&bbox, bitmap1) || !bitmap_ok(&bbox, bitmap2)) {
                save_two_bitmaps(&bbox, bitmap1, bitmap2, "error.png");
                assert(!"error in bitmaps");
@@ -473,7 +474,7 @@ void test4(int argn, char*argv[])
            }
            free(bitmap1);
            free(bitmap2);
-           
+
            // second pass renders the 90° rotated version
            rotate90(poly1);
            rotate90(poly2);
@@ -519,7 +520,7 @@ void extract_polygons_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color)
        fprintf(stderr, "%d segments (max so far: %d/%d)\n", size, max_segments, max_any_segments);
     }
 
-    if(!gfxpoly_check(poly1)) {
+    if(!gfxpoly_check(poly1, 0)) {
         gfxpoly_destroy(poly1);
         fprintf(stderr, "bad polygon\n");
         return;
index 0e292cd..06ae2b6 100644 (file)
@@ -77,7 +77,7 @@ int test_stroke1()
 
        //gfxpoly_t*p = gfxpoly_fromstroke(l, width, gfx_capRound, gfx_joinRound, 500);
        gfxpoly_t*p1 = gfxpoly_from_stroke(l, width, gfx_capRound, gfx_joinRound, 500, 0.05);
-       assert(gfxpoly_check(p1));
+       assert(gfxpoly_check(p1, 1));
        
        //gfxpoly_t*p2 = gfxpoly_from_fill(f, 0.05);
        gfxline_t*l2 = gfxline_clone(l);
@@ -92,10 +92,10 @@ int test_stroke1()
                          s, -c,  -(350+x1)*s+(350+y1)*c+350};
        gfxline_transform(l2, &m);
        gfxpoly_t*p2 = gfxpoly_from_stroke(l2, width, gfx_capRound, gfx_joinRound, 500, 0.05);
-       assert(gfxpoly_check(p2));
+       assert(gfxpoly_check(p2, 1));
 
        gfxpoly_t*p3 = gfxpoly_intersect(p1, p2);
-       assert(gfxpoly_check(p3));
+       assert(gfxpoly_check(p3, 1));
        
        //gfxpoly_t*p4 = gfxpoly_from_fill(f, 0.05);
        //gfxpoly_t*p5 = gfxpoly_intersect(p1, p4);
index f0eb110..e7cf95d 100644 (file)
@@ -58,13 +58,10 @@ windstate_t circular_add(windcontext_t*context, windstate_t left, edgestyle_t*ed
 
 edgestyle_t* circular_diff(windstate_t*left, windstate_t*right)
 {
-    if(left->is_filled==right->is_filled) {
+    if(left->is_filled==right->is_filled)
         return 0;
-    } else if(left->is_filled) {
-        return &edgestyle_down;
-    } else {//right->is_filled
-        return &edgestyle_up;
-    }
+    else
+        return &edgestyle_default;
 }
 
 windrule_t windrule_circular = {