3 Various boolean polygon functions.
5 Part of the swftools package.
7 Copyright (c) 2005 Matthias Kramm <kramm@quiss.org>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
23 #include "../config.h"
24 #include "gfxdevice.h"
28 #ifdef INTERNAL_LIBART
29 #include "art/libart.h"
30 #include "art/art_svp_intersect.h"
31 #include "art/art_svp_ops.h"
33 #include <libart_lgpl/libart.h>
34 #include <libart_lgpl/art_svp_intersect.h>
35 #include <libart_lgpl/art_svp_ops.h>
46 //----------------------------------------- svp renderer ----------------------------------------
57 typedef struct _renderpoint
60 signed char direction;
63 typedef struct _renderline
70 typedef struct _renderbuf
79 static inline void add_pixel(renderbuf_t*buf, double x, int y, signed char direction)
83 p.direction = direction;
85 if(x >= buf->bbox.xmax || y >= buf->bbox.ymax || y < buf->bbox.ymin)
87 renderline_t*l = &buf->lines[y-buf->bbox.ymin];
89 if(l->num == l->size) {
91 l->points = (renderpoint_t*)rfx_realloc(l->points, l->size * sizeof(renderpoint_t));
93 l->points[l->num] = p;
97 #define INT(x) ((int)((x)+16)-16)
98 static void add_line(renderbuf_t*buf, double x1, double y1, double x2, double y2, signed char direction)
105 double ny1, ny2, stepx;
117 ny1 = INT(y1) + 1.0 + CUT;
120 ny2 = INT(y2) - 1.0 + CUT;
126 x1 = x1 + (ny1-y1)*stepx;
127 x2 = x2 + (ny2-y2)*stepx;
135 double xx = startx + posx;
136 add_pixel(buf, xx, posy, direction);
142 static int compare_renderpoints(const void * _a, const void * _b)
144 renderpoint_t*a = (renderpoint_t*)_a;
145 renderpoint_t*b = (renderpoint_t*)_b;
146 if(a->x < b->x) return -1;
147 if(a->x > b->x) return 1;
151 static void fill_bitwise(unsigned char*line, int x1, int x2)
155 int b1 = 0xff >> (x1&7);
156 int b2 = 0xff << (1+7-(x2&7));
161 memset(&line[p1+1], 255, p2-(p1+1));
166 unsigned char* render_svp(ArtSVP*svp, intbbox_t*bbox, double zoom, ArtWindRule rule)
168 renderbuf_t _buf, *buf=&_buf;
169 buf->width = (bbox->xmax - bbox->xmin);
170 buf->height = (bbox->ymax - bbox->ymin);
173 int width8 = (buf->width+7) >> 3;
174 unsigned char* image = (unsigned char*)malloc(width8*buf->height);
175 memset(image, 0, width8*buf->height);
177 buf->lines = (renderline_t*)rfx_alloc(buf->height*sizeof(renderline_t));
179 for(y=0;y<buf->height;y++) {
180 memset(&buf->lines[y], 0, sizeof(renderline_t));
181 buf->lines[y].points = 0;
182 buf->lines[y].num = 0;
186 for(t=0;t<svp->n_segs;t++) {
187 ArtSVPSeg* seg = &svp->segs[t];
189 for(s=0;s<seg->n_points-1;s++) {
190 int dir = seg->dir? 1 : -1;
191 add_line(buf, seg->points[s].x, seg->points[s].y, seg->points[s+1].x, seg->points[s+1].y, dir);
194 for(y=0;y<buf->height;y++) {
195 renderpoint_t*points = buf->lines[y].points;
196 unsigned char*line = &image[width8*y];
198 int num = buf->lines[y].num;
200 qsort(points, num, sizeof(renderpoint_t), compare_renderpoints);
205 renderpoint_t*p = &points[n];
206 int x = (int)(p->x - bbox->xmin);
213 if(fill && x!=lastx) {
214 fill_bitwise(line, lastx, x);
216 wind += p->direction;
217 if(rule == ART_WIND_RULE_INTERSECT) {
219 } else if (rule == ART_WIND_RULE_NONZERO) {
221 } else if (rule == ART_WIND_RULE_ODDEVEN) {
223 } else { // rule == ART_WIND_RULE_POSITIVE
228 if(fill && lastx!=buf->width)
229 fill_bitwise(line, lastx, buf->width);
232 for(y=0;y<buf->height;y++) {
233 if(buf->lines[y].points) {
234 free(buf->lines[y].points);
236 memset(&buf->lines[y], 0, sizeof(renderline_t));
238 free(buf->lines);buf->lines=0;
242 #define MAX_WIDTH 8192
243 #define MAX_HEIGHT 4096
245 intbbox_t get_svp_bbox(ArtSVP*svp, double zoom)
248 intbbox_t b = {0,0,0,0};
249 if(svp->n_segs && svp->segs[0].n_points) {
250 b.xmin = svp->segs[0].points[0].x;
251 b.ymin = svp->segs[0].points[0].y;
252 b.xmax = svp->segs[0].points[0].x;
253 b.ymax = svp->segs[0].points[0].y;
255 for(t=0;t<svp->n_segs;t++) {
256 ArtSVPSeg* seg = &svp->segs[t];
258 for(s=0;s<seg->n_points;s++) {
259 double x = seg->points[s].x*zoom;
260 double y = seg->points[s].y*zoom;
265 if(x1 < b.xmin) b.xmin = x1;
266 if(y1 < b.ymin) b.ymin = y1;
267 if(x2 > b.xmax) b.xmax = x2;
268 if(y2 > b.xmax) b.ymax = y2;
271 if(b.xmax > (int)(MAX_WIDTH*zoom))
272 b.xmax = (int)(MAX_WIDTH*zoom);
273 if(b.ymax > (int)(MAX_HEIGHT*zoom))
274 b.ymax = (int)(MAX_HEIGHT*zoom);
275 if(b.xmin < -(int)(MAX_WIDTH*zoom))
276 b.xmin = -(int)(MAX_WIDTH*zoom);
277 if(b.ymin < -(int)(MAX_HEIGHT*zoom))
278 b.ymin = -(int)(MAX_HEIGHT*zoom);
285 b.width = b.xmax - b.xmin;
286 b.height = b.ymax - b.ymin;
290 #define B11100000 0xe0
291 #define B01110000 0x70
292 #define B00111000 0x38
293 #define B00011100 0x1c
294 #define B00001110 0x0e
295 #define B00000111 0x07
296 #define B10000000 0x80
297 #define B01000000 0x40
298 #define B00100000 0x20
299 #define B00010000 0x10
300 #define B00001000 0x08
301 #define B00000100 0x04
302 #define B00000010 0x02
303 #define B00000001 0x01
305 int compare_bitmaps(intbbox_t*bbox, unsigned char*data1, unsigned char*data2)
309 int height = bbox->height;
310 int width = bbox->width;
311 int width8 = (width+7) >> 3;
312 unsigned char*l1 = &data1[width8];
313 unsigned char*l2 = &data2[width8];
315 for(y=1;y<height-1;y++) {
316 for(x=0;x<width8;x++) {
317 unsigned a = l1[x-width8] & l1[x] & l1[x+width8];
318 unsigned b = l2[x-width8] & l2[x] & l2[x+width8];
320 if((a&B11100000) && !(l2[x]&B01000000))
322 if((a&B01110000) && !(l2[x]&B00100000))
324 if((a&B00111000) && !(l2[x]&B00010000))
326 if((a&B00011100) && !(l2[x]&B00001000))
328 if((a&B00001110) && !(l2[x]&B00000100))
330 if((a&B00000111) && !(l2[x]&B00000010))
333 if((b&B11100000) && !(l1[x]&B01000000))
335 if((b&B01110000) && !(l1[x]&B00100000))
337 if((b&B00111000) && !(l1[x]&B00010000))
339 if((b&B00011100) && !(l1[x]&B00001000))
341 if((b&B00001110) && !(l1[x]&B00000100))
343 if((b&B00000111) && !(l1[x]&B00000010))
353 //-----------------------------------------------------------------------------------------------
355 static ArtVpath* gfxline_to_ArtVpath(gfxline_t*line, char fill)
357 ArtVpath *vec = NULL;
362 /* factor which determines into how many line fragments a spline is converted */
363 double subfraction = 2.4;//0.3
367 if(l2->type == gfx_moveTo) {
369 } else if(l2->type == gfx_lineTo) {
371 } else if(l2->type == gfx_splineTo) {
372 int parts = (int)(sqrt(fabs(l2->x-2*l2->sx+x) + fabs(l2->y-2*l2->sy+y))*subfraction);
373 if(!parts) parts = 1;
383 vec = art_new (ArtVpath, len+1);
388 if(l2->type == gfx_moveTo) {
389 vec[pos].code = ART_MOVETO_OPEN;
394 } else if(l2->type == gfx_lineTo) {
395 vec[pos].code = ART_LINETO;
400 } else if(l2->type == gfx_splineTo) {
402 int parts = (int)(sqrt(fabs(l2->x-2*l2->sx+x) + fabs(l2->y-2*l2->sy+y))*subfraction);
403 if(!parts) parts = 1;
404 double stepsize = 1.0/parts;
405 for(i=0;i<=parts;i++) {
406 double t = (double)i*stepsize;
407 vec[pos].code = ART_LINETO;
408 vec[pos].x = l2->x*t*t + 2*l2->sx*t*(1-t) + x*(1-t)*(1-t);
409 vec[pos].y = l2->y*t*t + 2*l2->sy*t*(1-t) + y*(1-t)*(1-t);
418 vec[pos++].code = ART_END;
422 /* Fix "dotted" lines. Those are lines where singular points are created
423 by a moveto x,y lineto x,y combination. We "fix" these by shifting the
424 point in the lineto a little bit to the right
425 These should only occur in strokes, not in fills, so do this only
426 when we know we're not filling.
429 for(t=0;vec[t].code!=ART_END;t++) {
430 if(t>0 && (vec[t-1].code==ART_MOVETO_OPEN || vec[t-1].code==ART_MOVETO)
431 && vec[t].code==ART_LINETO && vec[t+1].code!=ART_LINETO &&
432 vec[t-1].x == vec[t].x &&
433 vec[t-1].y == vec[t].y) {
439 /* Find adjacent identical points. If an ajdacent pair of identical
440 points is found, the second is removed.
441 So moveto x,y lineto x,y becomes moveto x,y
442 lineto x,y lineto x,y becomes lineto x,y
443 lineto x,y moveto x,y becomes lineto x,y
444 moveto x,y moveto x,y becomes moveto x,y
445 lineto x,y lineto x2,y2 becomes lineto x2,y2 (if dir(x,y) ~= dir(x2,y2))
451 if(vec[pos].code == ART_END) {
452 vec[outpos++] = vec[pos++];
456 char samedir = 0, samepoint = 0;
458 double dx = vec[pos].x-vec[pos-1].x;
459 double dy = vec[pos].y-vec[pos-1].y;
460 /*if(pos<len-1 && vec[pos].code == ART_LINETO && vec[pos+1].code == ART_LINETO) {
461 double dx2 = vec[pos+1].x-vec[pos].x;
462 double dy2 = vec[pos+1].y-vec[pos].y;
463 if(fabs(dx*dy2 - dy*dx2) < 0.0001 && dx*dx2 + dy*dy2 >= 0) {
467 if(fabs(dx) + fabs(dy) < 0.0001) {
471 if(!samepoint && !samedir) {
472 vec[outpos++] = vec[pos++];
481 static void shear_svp(ArtSVP*svp, double v)
483 /* do a "shearing" on the polygon. We do this to eliminate all
484 horizontal lines (which libart can't handle properly, even though
488 for(t=0;t<svp->n_segs;t++) {
489 ArtSVPSeg* seg = &svp->segs[t];
491 for(s=0;s<seg->n_points;s++) {
492 ArtPoint* point = &seg->points[s];
493 point->y += point->x*v;
498 static double find_shear_value(ArtSVP*svp)
500 /* We try random values until we find one
501 where there's no slope below a given value, or if that fails,
502 at least no slope of 0 */
509 for(t=0;t<svp->n_segs;t++) {
510 ArtSVPSeg* seg = &svp->segs[t];
512 for(s=0;s<seg->n_points-1;s++) {
513 ArtPoint* p1 = &seg->points[s];
514 ArtPoint* p2 = &seg->points[s+1];
515 double dx = p2->x - p1->x;
516 double dy = p2->y - p1->y;
522 if(tries<100 && dx && fabs(dy / dx) < 1e-5) {
532 v = lrand48() / 2000000000.0;
538 void show_path(ArtSVP*path)
541 printf("Segments: %d\n", path->n_segs);
542 for(t=0;t<path->n_segs;t++) {
543 ArtSVPSeg* seg = &path->segs[t];
544 printf("Segment %d: %d points, %s, BBox: (%f,%f,%f,%f)\n",
545 t, seg->n_points, seg->dir==0?"UP ":"DOWN",
546 seg->bbox.x0, seg->bbox.y0, seg->bbox.x1, seg->bbox.y1);
548 for(p=0;p<seg->n_points;p++) {
549 ArtPoint* point = &seg->points[p];
550 printf(" (%f,%f)\n", point->x, point->y);
557 typedef struct svp_segment_part
562 } svp_segment_part_t;
564 int compare_double(const void*_y1, const void*_y2)
566 const double*y1 = _y1;
567 const double*y2 = _y2;
568 if(*y1<*y2) return -1;
569 if(*y1>*y2) return 1;
573 int compare_seg_start(const void*_s1, const void*_s2)
575 svp_segment_part_t*s1 = *(svp_segment_part_t**)_s1;
576 svp_segment_part_t*s2 = *(svp_segment_part_t**)_s2;
577 if(s1->y1 < s2->y1) return -1;
578 if(s1->y1 > s2->y1) return 1;
582 int compare_seg_end(const void*_s1, const void*_s2)
584 svp_segment_part_t*s1 = *(svp_segment_part_t**)_s1;
585 svp_segment_part_t*s2 = *(svp_segment_part_t**)_s2;
586 if(s1->y2 < s2->y2) return -1;
587 if(s1->y2 > s2->y2) return 1;
591 void clean_svp(ArtSVP*svp)
598 for(t=0;t<svp->n_segs;t++) {
599 ArtSVPSeg* seg = &svp->segs[t];
603 oldpoints += seg->n_points;
604 for(p=0;p<seg->n_points;p++) {
605 ArtPoint* p1 = &seg->points[p];
606 if(!p || lasty!=p1->y) {
607 seg->points[pos] = seg->points[p];
613 newpoints += seg->n_points;
616 oldsegs = svp->n_segs;
617 for(t=0;t<svp->n_segs;t++) {
618 if(svp->segs[t].n_points > 1) {
619 svp->segs[pos++] = svp->segs[t];
623 newsegs = svp->n_segs;
624 if(newsegs < oldsegs || newpoints < oldpoints) {
625 msg("<verbose> Simplified polygon from %d points to %d points, %d to %d segs",
626 oldpoints, newpoints, oldsegs, newsegs);
630 int check_svp(ArtSVP*svp)
632 /* count number of y coordinates and segs */
636 for(t=0;t<svp->n_segs;t++) {
637 if(!svp->segs[t].n_points) {
638 msg("<error> svp contains segment with zero points\n");
641 num_points += svp->segs[t].n_points;
642 num_segs += svp->segs[t].n_points - 1;
645 /* create segs and ys */
646 double*y = malloc(sizeof(double)*num_points);
647 svp_segment_part_t*segs = malloc(sizeof(svp_segment_part_t)*num_segs);
648 svp_segment_part_t**seg_start = malloc(sizeof(svp_segment_part_t*)*num_segs);
649 svp_segment_part_t**seg_end = malloc(sizeof(svp_segment_part_t*)*num_segs);
653 for(t=0;t<svp->n_segs;t++) {
654 ArtSVPSeg* seg = &svp->segs[t];
656 for(p=0;p<seg->n_points;p++) {
657 y[c1++] = seg->points[p].y;
658 assert(c1 <= num_points);
660 for(p=0;p<seg->n_points-1;p++) {
661 ArtPoint* p1 = &seg->points[p];
662 ArtPoint* p2 = &seg->points[p+1];
666 msg("<error> bad svp, y in seg is non-increasing %.16f -> %.16f\n", p1->y, p2->y);
669 segs[num_segs].y1 = p1->y;
670 segs[num_segs].y2 = p2->y;
671 segs[num_segs].active = 0;
672 seg_start[num_segs] = &segs[num_segs];
673 seg_end[num_segs] = &segs[num_segs];
679 qsort(y, num_points, sizeof(double), compare_double);
680 qsort(seg_start, num_segs, sizeof(svp_segment_part_t*), compare_seg_start);
681 qsort(seg_end, num_segs, sizeof(svp_segment_part_t*), compare_seg_end);
683 double lasty = num_points?y[0]+1:0;
686 double bleedy1=0,bleedy2 = 0;
687 for(t=0;t<num_points;t++) {
691 for(s=0;s<num_segs;s++) {
692 if(segs[s].y1==y[t]) {
693 /* segment is starting */
696 } else if(segs[s].y2==y[t]) {
713 msg("<verbose> svp bleeds from y=%.16f to y=%.16f (%d/%d active segments)\n",
716 free(y);free(segs);free(seg_start);free(seg_end);
728 void write_svp_postscript(const char*filename, ArtSVP*svp)
732 FILE*fi = fopen(filename, "wb");
734 double xmin=0,ymin=0,xmax=0,ymax=0;
735 fprintf(fi, "%% begin\n");
736 for (i = 0; i < svp->n_segs; i++) {
737 for (j = 0; j < svp->segs[i].n_points; j++) {
738 double x = svp->segs[i].points[j].x;
739 double y = svp->segs[i].points[j].y;
744 if(x < xmin) xmin = x;
745 if(x > xmax) xmax = x;
746 if(y < ymin) ymin = y;
747 if(y > ymax) ymax = y;
751 if(xmax == xmin) xmax=xmin+1;
752 if(ymax == ymin) ymax=ymin+1;
754 for (i = 0; i < svp->n_segs; i++)
756 fprintf(fi, "%g setgray\n", svp->segs[i].dir ? 0.7 : 0);
757 for (j = 0; j < svp->segs[i].n_points; j++)
759 //fprintf(fi, "%g %g %s\n",
760 // 20 + 550*(svp->segs[i].points[j].x-xmin)/(xmax-xmin),
761 // 820 - 800*(svp->segs[i].points[j].y-ymin)/(ymax-ymin),
762 // j ? "lineto" : "moveto");
763 fprintf(fi, "%.32f %.32f %s\n",
764 svp->segs[i].points[j].x,
765 svp->segs[i].points[j].y,
766 j ? "lineto" : "moveto");
768 fprintf(fi, "stroke\n");
771 fprintf(fi, "showpage\n");
775 void write_vpath_postscript(const char*filename, ArtVpath*path)
777 FILE*fi = fopen(filename, "wb");
779 double xmin=0,ymin=0,xmax=0,ymax=0;
780 fprintf(fi, "%% begin\n");
783 while(p->code != ART_END) {
784 if(p->code == ART_MOVETO || p->code == ART_MOVETO_OPEN) {
786 fprintf(fi, "stroke\n");
788 fprintf(fi, "0.0 setgray\n");
789 fprintf(fi, "%.32f %.32f moveto\n", p->x, p->y);
791 fprintf(fi, "%.32f %.32f lineto\n", p->x, p->y);
796 fprintf(fi, "stroke\n");
797 fprintf(fi, "showpage\n");
801 void write_gfxline_postscript(const char*filename, gfxline_t*line)
803 FILE*fi = fopen(filename, "wb");
805 fprintf(fi, "%% begin\n");
808 if(line->type == gfx_moveTo) {
810 fprintf(fi, "stroke\n");
812 fprintf(fi, "0.0 setgray\n");
813 fprintf(fi, "%.32f %.32f moveto\n", line->x, line->y);
815 fprintf(fi, "%.32f %.32f lineto\n", line->x, line->y);
820 fprintf(fi, "stroke\n");
821 fprintf(fi, "showpage\n");
825 static int vpath_len(ArtVpath*svp)
828 while(svp->code != ART_END) {
835 int gfxline_len(gfxline_t*line)
846 static ArtVpath*pvpath= 0;
847 static int cmppos(const void*_p1, const void*_p2)
851 ArtVpath*v1 = &pvpath[*p1];
852 ArtVpath*v2 = &pvpath[*p2];
855 else if(v1->y > v2->y)
857 else if(v1->x < v2->x)
859 else if(v1->x > v2->x)
865 #define PERTURBATION 2e-3
866 static void my_perturb(ArtVpath*vpath)
869 int len = vpath_len(vpath);
870 int*pos = (int*)malloc(len*sizeof(int));
874 qsort(pos, len, sizeof(int), cmppos);
878 while(t2<len && !cmppos(&pos[t],&pos[t2])) {
882 double dx = (PERTURBATION * rand ()) / RAND_MAX - PERTURBATION * 0.5;
883 double dy = (PERTURBATION * rand ()) / RAND_MAX - PERTURBATION * 0.5;
886 vpath[pos[s]].x += dx;
887 vpath[pos[s]].y += dy;
895 static ArtSVP* gfxfillToSVP(gfxline_t*line, int perturb)
897 ArtVpath* vec = gfxline_to_ArtVpath(line, 1);
898 msg("<verbose> Casting gfxline of %d segments (%d line segments) to a gfxpoly", gfxline_len(line), vpath_len(vec));
901 //ArtVpath* vec2 = art_vpath_perturb(vec);
906 ArtSVP *svp = art_svp_from_vpath(vec);
913 // double shear = find_shear_value(svp);
914 // gfxline_t*line = gfxpoly_to_gfxline((gfxpoly_t*)svp);
915 // gfxline_t*l = line;
917 // l->y += l->x*shear;
918 // l->sy += l->sx*shear;
921 // svp = (ArtSVP*)gfxpoly_fillToPoly(line);
922 // printf("shearing svp by %.16f\n", shear);
926 // art_svp_free(svp);
927 // shear_svp(result, -shear);
931 ArtSVP* run_intersector(ArtSVP*svp, ArtWindRule rule)
933 ArtSvpWriter * swr = art_svp_writer_rewind_new(rule);
936 intbbox_t bbox = get_svp_bbox(svp, zoom);
938 art_svp_intersector(svp, swr);
939 ArtSVP*result = art_svp_writer_rewind_reap(swr);
941 if(!check_svp(result)) {
942 current_svp = result;
943 art_report_error(); // might set art_error_in_intersector
945 msg("<verbose> Comparing polygon renderings of size %dx%d and %dx%d", bbox.width, bbox.height, bbox.width, bbox.height);
946 unsigned char*data1 = render_svp(svp, &bbox, zoom, rule);
947 unsigned char*data2 = render_svp(result, &bbox, zoom, ART_WIND_RULE_ODDEVEN);
948 if(!compare_bitmaps(&bbox, data1, data2)) {
949 msg("<verbose> Bad SVP rewinding result- polygons don't match");
950 current_svp = result;
951 art_report_error(); // might set art_error_in_intersector
957 if(art_error_in_intersector) {
958 msg("<verbose> Error in polygon processing");
959 art_svp_free(result);
960 art_error_in_intersector=0;
966 gfxline_t* gfxpoly_to_gfxline(gfxpoly_t*poly)
968 ArtSVP*svp = (ArtSVP*)poly;
973 msg("<verbose> Casting polygon of %d segments back to gfxline", svp->n_segs);
975 for(t=0;t<svp->n_segs;t++) {
976 size += svp->segs[t].n_points;
979 gfxline_t* lines = (gfxline_t*)rfx_alloc(sizeof(gfxline_t)*size);
981 for(t=0;t<svp->n_segs;t++) {
982 ArtSVPSeg* seg = &svp->segs[t];
984 for(p=0;p<seg->n_points;p++) {
985 lines[pos].type = p==0?gfx_moveTo:gfx_lineTo;
986 ArtPoint* point = &seg->points[p];
987 lines[pos].x = point->x;
988 lines[pos].y = point->y;
989 lines[pos].next = &lines[pos+1];
994 lines[pos-1].next = 0;
1001 gfxpoly_t* gfxpoly_fillToPoly(gfxline_t*line)
1003 /* I'm not sure whether doing perturbation here is actually
1004 a good idea- if that line has been run through the machinery
1005 several times already, it might be safer to leave it alone,
1006 since it should already be in a format libart can handle */
1008 ArtSVP* svp = gfxfillToSVP(line, 1);
1010 ArtSVP* svp = gfxfillToSVP(line, 0);
1015 static int counter = 0;
1016 sprintf(filename, "svp%d.ps", counter);
1017 write_svp_postscript(filename, svp);
1018 sprintf(filename, "gfxline%d.ps", counter);
1019 write_gfxline_postscript(filename, line);
1022 /* we do xor-filling by default, so dir is always 1
1023 (actually for oddeven rewinding it makes no difference, but
1027 for(t=0; t<svp->n_segs; t++) {
1028 svp->segs[t].dir = 1;
1031 /* for some reason, we need to rewind / self-intersect the polygons that gfxfillToSVP
1032 returns- art probably uses a different fill mode (circular?) for vpaths */
1033 ArtSVP*svp_uncrossed=0;
1036 sprintf(filename, "svp%d_in.ps", counter);
1037 write_svp_postscript(filename, svp);
1041 svp_uncrossed = run_intersector(svp, ART_WIND_RULE_ODDEVEN);
1046 return (gfxpoly_t*)svp;
1049 gfxpoly_t* gfxpoly_intersect(gfxpoly_t*poly1, gfxpoly_t*poly2)
1053 static int counter = 0;
1055 ArtSVP* svp1 = (ArtSVP*)poly1;
1056 ArtSVP* svp2 = (ArtSVP*)poly2;
1057 msg("<verbose> Intersecting two polygons of %d and %d segments", svp1->n_segs, svp2->n_segs);
1061 sprintf(filename, "isvp%d_src1.ps", counter);
1062 write_svp_postscript(filename, svp1);
1063 sprintf(filename, "isvp%d_src2.ps", counter);
1064 write_svp_postscript(filename, svp2);
1067 ArtSVP* svp3 = art_svp_merge (svp1, svp2);
1070 sprintf(filename, "isvp%d_src.ps", counter);
1071 write_svp_postscript(filename, svp3);
1074 //write_svp_postscript("svp.ps", svp3);
1075 ArtSVP*svp_new = run_intersector(svp3, ART_WIND_RULE_INTERSECT);
1077 art_free (svp3); /* shallow free because svp3 contains shared segments */
1080 sprintf(filename, "isvp%d.ps", counter);
1081 write_svp_postscript(filename, svp_new);
1086 //write_svp_postscript("svp_new.ps", svp_new);
1088 return (gfxpoly_t*)svp_new;
1091 gfxpoly_t* gfxpoly_union(gfxpoly_t*poly1, gfxpoly_t*poly2)
1093 ArtSVP* svp1 = (ArtSVP*)poly1;
1094 ArtSVP* svp2 = (ArtSVP*)poly2;
1095 msg("<verbose> Unifying two polygons of %d and %d segments", svp1->n_segs, svp2->n_segs);
1097 ArtSVP* svp = art_svp_union(svp1, svp2);
1098 return (gfxpoly_t*)svp;
1101 gfxpoly_t* gfxpoly_strokeToPoly(gfxline_t*line, gfxcoord_t width, gfx_capType cap_style, gfx_joinType joint_style, double miterLimit)
1103 ArtVpath* vec = gfxline_to_ArtVpath(line, 0);
1104 msg("<verbose> Casting gfxline of %d segments to a stroke-polygon", gfxline_len(line));
1106 ArtVpath* vec2 = art_vpath_perturb(vec);
1110 ArtSVP *svp = art_svp_vpath_stroke (vec,
1111 (joint_style==gfx_joinMiter)?ART_PATH_STROKE_JOIN_MITER:
1112 ((joint_style==gfx_joinRound)?ART_PATH_STROKE_JOIN_ROUND:
1113 ((joint_style==gfx_joinBevel)?ART_PATH_STROKE_JOIN_BEVEL:ART_PATH_STROKE_JOIN_BEVEL)),
1114 (cap_style==gfx_capButt)?ART_PATH_STROKE_CAP_BUTT:
1115 ((cap_style==gfx_capRound)?ART_PATH_STROKE_CAP_ROUND:
1116 ((cap_style==gfx_capSquare)?ART_PATH_STROKE_CAP_SQUARE:ART_PATH_STROKE_CAP_SQUARE)),
1118 miterLimit, //miter_limit
1122 return (gfxpoly_t*)svp;
1125 gfxline_t* gfxline_circularToEvenOdd(gfxline_t*line)
1127 msg("<verbose> Converting circular-filled gfxline of %d segments to even-odd filled gfxline", gfxline_len(line));
1128 ArtSVP* svp = gfxfillToSVP(line, 1);
1130 /* TODO: ART_WIND_RULE_POSITIVE means that a shape is visible if
1131 positive and negative line segments add up to something positive.
1132 I *think* that clockwise fill in PDF is defined in a way, however,
1133 that the *last* shape's direction will determine whether something
1135 ArtSVP* svp_rewinded;
1137 svp_rewinded = run_intersector(svp, ART_WIND_RULE_POSITIVE);
1143 gfxline_t* result = gfxpoly_to_gfxline((gfxpoly_t*)svp_rewinded);
1145 art_svp_free(svp_rewinded);
1149 gfxpoly_t* gfxpoly_createbox(double x1, double y1,double x2, double y2)
1151 ArtVpath *vec = art_new (ArtVpath, 5+1);
1152 vec[0].code = ART_MOVETO;
1155 vec[1].code = ART_LINETO;
1158 vec[2].code = ART_LINETO;
1161 vec[3].code = ART_LINETO;
1164 vec[4].code = ART_LINETO;
1167 vec[5].code = ART_END;
1170 ArtSVP *svp = art_svp_from_vpath(vec);
1172 return (gfxpoly_t*)svp;
1175 void gfxpoly_free(gfxpoly_t*poly)
1177 ArtSVP*svp = (ArtSVP*)poly;