From: Matthias Kramm Date: Wed, 7 Apr 2010 23:41:57 +0000 (-0700) Subject: made gfxpoly_check test for correct circular filling X-Git-Tag: version-0-9-1~5^2~10 X-Git-Url: http://git.asbjorn.biz/?p=swftools.git;a=commitdiff_plain;h=eac1308d474f42fb9a7f8c89b1a02ff63c7c60e2 made gfxpoly_check test for correct circular filling --- diff --git a/lib/gfxpoly/poly.c b/lib/gfxpoly/poly.c index 02193df..9ffc770 100644 --- a/lib/gfxpoly/poly.c +++ b/lib/gfxpoly/poly.c @@ -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;snum_points;s++) { point_t p = stroke->points[s]; - int num = (s>=1 && snum_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 && snum_points-1)?2:1; // mid points are two points (start+end) + int num_circ = (s>=1 && snum_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(xp.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 } diff --git a/lib/gfxpoly/poly.h b/lib/gfxpoly/poly.h index 180a4f1..ccbf65e 100644 --- a/lib/gfxpoly/poly.h +++ b/lib/gfxpoly/poly.h @@ -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); diff --git a/lib/gfxpoly/renderpoly.c b/lib/gfxpoly/renderpoly.c index 9594bd2..989dfc8 100644 --- a/lib/gfxpoly/renderpoly.c +++ b/lib/gfxpoly/renderpoly.c @@ -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;tnum_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); + } } diff --git a/lib/gfxpoly/stroke.c b/lib/gfxpoly/stroke.c index 9735c1b..b9ccb10 100644 --- a/lib/gfxpoly/stroke.c +++ b/lib/gfxpoly/stroke.c @@ -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; diff --git a/lib/gfxpoly/test.c b/lib/gfxpoly/test.c index 509f3ee..a7ba9d7 100644 --- a/lib/gfxpoly/test.c +++ b/lib/gfxpoly/test.c @@ -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; diff --git a/lib/gfxpoly/test_stroke.c b/lib/gfxpoly/test_stroke.c index 0e292cd..06ae2b6 100644 --- a/lib/gfxpoly/test_stroke.c +++ b/lib/gfxpoly/test_stroke.c @@ -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); diff --git a/lib/gfxpoly/wind.c b/lib/gfxpoly/wind.c index f0eb110..e7cf95d 100644 --- a/lib/gfxpoly/wind.c +++ b/lib/gfxpoly/wind.c @@ -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 = {