X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fgfxpoly.c;h=4dd27a7c16ebfdcaef0ed29a5c2fcaab1645a220;hb=a622c54ae5ea502d261557187406504b223705bf;hp=6392f535b2d790e3f14e007ddf68a5c0445254cb;hpb=dded149e9730fb089e8238872b2d117f0eaf7454;p=swftools.git diff --git a/lib/gfxpoly.c b/lib/gfxpoly.c index 6392f53..4dd27a7 100644 --- a/lib/gfxpoly.c +++ b/lib/gfxpoly.c @@ -24,7 +24,10 @@ #include "gfxdevice.h" #include "gfxtools.h" #include "gfxpoly.h" +#include "mem.h" #include "art/libart.h" +#include "art/art_svp_intersect.h" +#include "log.h" #include #include #include @@ -103,9 +106,9 @@ static ArtVpath* gfxline_to_ArtVpath(gfxline_t*line, char fill) int t; for(t=0;vec[t].code!=ART_END;t++) { if(t>0 && vec[t-1].code==ART_MOVETO && vec[t].code==ART_LINETO - && vec[t+1].code!=ART_LINETO - && vec[t-1].x == vec[t].x - && vec[t-1].y == vec[t].y) { + && vec[t+1].code!=ART_LINETO && + vec[t-1].x == vec[t].x && + vec[t-1].y == vec[t].y) { vec[t].x += 0.01; } x = vec[t].x; @@ -114,23 +117,29 @@ static ArtVpath* gfxline_to_ArtVpath(gfxline_t*line, char fill) } /* Find adjacent identical points. If an ajdacent pair of identical - points is found, the moveto is removed (unless both are movetos). - So moveto x,y lineto x,y becomes lineto x,y + points is found, the second 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 moveto x,y moveto x,y becomes moveto x,y + lineto x,y lineto x2,y2 becomes lineto x2,y2 (if dir(x,y) ~= dir(x2,y2)) */ - int t; + int t = 1; while(t < pos) { - int t = 1; - if ((vec[t-1].x == vec[t].x) && (vec[t-1].y == vec[t].y)) { - // adjacent identical points; remove one - int type = ART_MOVETO; - if(vec[t-1].code==ART_LINETO || vec[t].code==ART_LINETO) - type = ART_LINETO; - memcpy(&vec[t], &vec[t+1], sizeof(vec[0]) * (pos - t)); - vec[t].code = type; + double dx = vec[t].x-vec[t-1].x; + double dy = vec[t].y-vec[t-1].y; + char samedir = 0; + if(tn_segs; i++) { + for (j = 0; j < svp->segs[i].n_points; j++) { + double x = svp->segs[i].points[j].x; + double y = svp->segs[i].points[j].y; + if(i==0 && j==0) { + xmin = xmax = x; + ymin = ymax = y; + } else { + if(x < xmin) xmin = x; + if(x > xmax) xmax = x; + if(y < ymin) ymin = y; + if(y > ymax) ymax = y; + } + } + } + if(xmax == xmin) xmax=xmin+1; + if(ymax == ymin) ymax=ymin+1; + + for (i = 0; i < svp->n_segs; i++) + { + fprintf(fi, "%g setgray\n", svp->segs[i].dir ? 0.7 : 0); + for (j = 0; j < svp->segs[i].n_points; j++) + { + fprintf(fi, "%g %g %s\n", + 20 + 550*(svp->segs[i].points[j].x-xmin)/(xmax-xmin), + 820 - 800*(svp->segs[i].points[j].y-ymin)/(ymax-ymin), + j ? "lineto" : "moveto"); + } + fprintf(fi, "stroke\n"); + } + + fprintf(fi, "showpage\n"); + fclose(fi); +} + +void write_vpath_postscript(const char*filename, ArtVpath*path) +{ + FILE*fi = fopen(filename, "wb"); + int i, j; + double xmin=0,ymin=0,xmax=0,ymax=0; + fprintf(fi, "%% begin\n"); + ArtVpath*p = path; + char first = 1; + while(p->code != ART_END) { + if(p->code == ART_MOVETO || p->code == ART_MOVETO_OPEN) { + if(!first) + fprintf(fi, "stroke\n"); + first = 0; + fprintf(fi, "1 setgray\n"); + fprintf(fi, "%.32f %.32f moveto\n", p->x, p->y); + } else { + fprintf(fi, "%.32f %.32f lineto\n", p->x, p->y); + } + p++; + } + if(!first) + fprintf(fi, "stroke\n"); + fprintf(fi, "showpage\n"); + fclose(fi); +} + +static int vpath_len(ArtVpath*svp) +{ + int len = 0; + while(svp->code != ART_END) { + svp ++; + len ++; + } + return len; +} + +int gfxline_len(gfxline_t*line) +{ + gfxline_t*i = line; + int len = 0; + while(i) { + len ++; + i = i->next; + } + return len; +} + + +static int debug = 0; +static ArtSVP* gfxfillToSVP(gfxline_t*line, int perturb) { ArtVpath* vec = gfxline_to_ArtVpath(line, 1); + msg(" Casting gfxline of %d segments (%d line segments) to a gfxpoly", gfxline_len(line), vpath_len(vec)); + if(perturb) { ArtVpath* vec2 = art_vpath_perturb(vec); free(vec); vec = vec2; } ArtSVP *svp = art_svp_from_vpath(vec); + if(debug) { + write_vpath_postscript("vpath.ps", vec); + write_svp_postscript("polygon.ps", svp); + } free(vec); +#if 0 // We need to make sure that the SVP we now have bounds an area (i.e. the // source line wound anticlockwise) rather than excludes an area (i.e. the // line wound clockwise). It seems that PDF (or xpdf) is less strict about @@ -276,6 +382,8 @@ ArtSVP* gfxfillToSVP(gfxline_t*line, int perturb) svp->segs[i].dir = 1; } } +#endif + return svp; } @@ -285,6 +393,9 @@ gfxline_t* gfxpoly_to_gfxline(gfxpoly_t*poly) int size = 0; int t; int pos = 0; + + msg(" Casting polygon of %d segments back to gfxline", svp->n_segs); + for(t=0;tn_segs;t++) { size += svp->segs[t].n_points + 1; } @@ -309,25 +420,32 @@ gfxline_t* gfxpoly_to_gfxline(gfxpoly_t*poly) return 0; } } - gfxpoly_t* gfxpoly_fillToPoly(gfxline_t*line) { ArtSVP* svp = gfxfillToSVP(line, 1); - if (svp->n_segs > 500) - { - int lineParts = 0; - gfxline_t* lineCursor = line; - while(lineCursor != NULL) - { - if(lineCursor->type != gfx_moveTo) ++lineParts; - lineCursor = lineCursor->next; - } - fprintf(stderr, "arts_fill abandonning shape with %d segments (%d line parts)\n", svp->n_segs, lineParts); - art_svp_free(svp); - return (gfxpoly_t*)gfxpoly_strokeToPoly(0, 0, gfx_capButt, gfx_joinMiter, 0); + + /* we do xor-filling by default, so dir is always 1 + (actually for oddeven rewinding it makes no difference, but + it's "cleaner") + */ + int t; + for(t=0; tn_segs; t++) { + svp->segs[t].dir = 1; } - ArtSVP* svp2 = art_svp_rewind_uncrossed(art_svp_uncross(svp),ART_WIND_RULE_ODDEVEN); - art_svp_free(svp);svp=svp2; + + /* for some reason, we need to rewind / self-intersect the polygons that gfxfillToSVP + returns- art probably uses a different fill mode (circular?) for vpaths */ + ArtSVP*svp_uncrossed=0; +#ifdef ART_USE_NEW_INTERSECTOR + ArtSvpWriter * swr = art_svp_writer_rewind_new(ART_WIND_RULE_ODDEVEN); + art_svp_intersector(svp, swr); + svp_uncrossed = art_svp_writer_rewind_reap(swr); +#else + svp_uncrossed = art_svp_rewind_uncrossed(art_svp_uncross(svp),ART_WIND_RULE_ODDEVEN); +#endif + art_svp_free(svp); + svp=svp_uncrossed; + return (gfxpoly_t*)svp; } @@ -335,6 +453,7 @@ gfxpoly_t* gfxpoly_intersect(gfxpoly_t*poly1, gfxpoly_t*poly2) { ArtSVP* svp1 = (ArtSVP*)poly1; ArtSVP* svp2 = (ArtSVP*)poly2; + msg(" Intersecting two polygons of %d and %d segments", svp1->n_segs, svp2->n_segs); ArtSVP* svp = art_svp_intersect(svp1, svp2); return (gfxpoly_t*)svp; @@ -344,6 +463,7 @@ gfxpoly_t* gfxpoly_union(gfxpoly_t*poly1, gfxpoly_t*poly2) { ArtSVP* svp1 = (ArtSVP*)poly1; ArtSVP* svp2 = (ArtSVP*)poly2; + msg(" Unifying two polygons of %d and %d segments", svp1->n_segs, svp2->n_segs); ArtSVP* svp = art_svp_union(svp1, svp2); return (gfxpoly_t*)svp; @@ -352,6 +472,7 @@ gfxpoly_t* gfxpoly_union(gfxpoly_t*poly1, gfxpoly_t*poly2) gfxpoly_t* gfxpoly_strokeToPoly(gfxline_t*line, gfxcoord_t width, gfx_capType cap_style, gfx_joinType joint_style, double miterLimit) { ArtVpath* vec = gfxline_to_ArtVpath(line, 0); + msg(" Casting gfxline of %d segments to a stroke-polygon", gfxline_len(line)); ArtSVP *svp = art_svp_vpath_stroke (vec, (joint_style==gfx_joinMiter)?ART_PATH_STROKE_JOIN_MITER: @@ -370,11 +491,27 @@ gfxpoly_t* gfxpoly_strokeToPoly(gfxline_t*line, gfxcoord_t width, gfx_capType ca gfxline_t* gfxline_circularToEvenOdd(gfxline_t*line) { + msg(" Converting circular-filled gfxline of %d segments to even-odd filled gfxline", gfxline_len(line)); ArtSVP* svp = gfxfillToSVP(line, 1); - ArtSVP* svp2 = art_svp_rewind_uncrossed(art_svp_uncross(svp),ART_WIND_RULE_POSITIVE); - gfxline_t* result = gfxpoly_to_gfxline((gfxpoly_t*)svp2); + + /* 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; +#ifdef ART_USE_NEW_INTERSECTOR + ArtSvpWriter * swr = art_svp_writer_rewind_new (ART_WIND_RULE_POSITIVE); + art_svp_intersector(svp, swr); + svp_rewinded = art_svp_writer_rewind_reap(swr); +#else + error + svp_rewinded = art_svp_rewind_uncrossed(art_svp_uncross(svp),ART_WIND_RULE_POSITIVE); +#endif + + gfxline_t* result = gfxpoly_to_gfxline((gfxpoly_t*)svp_rewinded); art_svp_free(svp); - art_svp_free(svp2); + art_svp_free(svp_rewinded); return result; }