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 #include "art/libart.h"
29 #include "art/art_svp_intersect.h"
30 #include "art/art_svp_ops.h"
40 //----------------------------------------- svp renderer ----------------------------------------
51 typedef struct _renderpoint
54 signed char direction;
57 typedef struct _renderline
64 typedef struct _renderbuf
73 static inline void add_pixel(renderbuf_t*buf, double x, int y, signed char direction)
77 p.direction = direction;
79 if(x >= buf->bbox.xmax || y >= buf->bbox.ymax || y < buf->bbox.ymin)
81 renderline_t*l = &buf->lines[y-buf->bbox.ymin];
83 if(l->num == l->size) {
85 l->points = (renderpoint_t*)rfx_realloc(l->points, l->size * sizeof(renderpoint_t));
87 l->points[l->num] = p;
91 #define INT(x) ((int)((x)+16)-16)
92 static void add_line(renderbuf_t*buf, double x1, double y1, double x2, double y2, signed char direction)
99 double ny1, ny2, stepx;
111 ny1 = INT(y1) + 1.0 + CUT;
114 ny2 = INT(y2) - 1.0 + CUT;
120 x1 = x1 + (ny1-y1)*stepx;
121 x2 = x2 + (ny2-y2)*stepx;
129 double xx = startx + posx;
130 add_pixel(buf, xx, posy, direction);
136 static int compare_renderpoints(const void * _a, const void * _b)
138 renderpoint_t*a = (renderpoint_t*)_a;
139 renderpoint_t*b = (renderpoint_t*)_b;
140 if(a->x < b->x) return -1;
141 if(a->x > b->x) return 1;
145 static void fill_bitwise(unsigned char*line, int x1, int x2)
149 int b1 = 0xff >> (x1&7);
150 int b2 = 0xff << (1+7-(x2&7));
155 memset(&line[p1+1], 255, p2-(p1+1));
160 unsigned char* render_svp(ArtSVP*svp, intbbox_t*bbox, double zoom, ArtWindRule rule)
162 renderbuf_t _buf, *buf=&_buf;
163 buf->width = (bbox->xmax - bbox->xmin);
164 buf->height = (bbox->ymax - bbox->ymin);
167 int width8 = (buf->width+7) >> 3;
168 unsigned char* image = (unsigned char*)malloc(width8*buf->height);
169 memset(image, 0, width8*buf->height);
171 buf->lines = (renderline_t*)rfx_alloc(buf->height*sizeof(renderline_t));
173 for(y=0;y<buf->height;y++) {
174 memset(&buf->lines[y], 0, sizeof(renderline_t));
175 buf->lines[y].points = 0;
176 buf->lines[y].num = 0;
180 for(t=0;t<svp->n_segs;t++) {
181 ArtSVPSeg* seg = &svp->segs[t];
183 for(s=0;s<seg->n_points-1;s++) {
184 int dir = seg->dir? 1 : -1;
185 add_line(buf, seg->points[s].x, seg->points[s].y, seg->points[s+1].x, seg->points[s+1].y, dir);
188 for(y=0;y<buf->height;y++) {
189 renderpoint_t*points = buf->lines[y].points;
190 unsigned char*line = &image[width8*y];
192 int num = buf->lines[y].num;
194 qsort(points, num, sizeof(renderpoint_t), compare_renderpoints);
199 renderpoint_t*p = &points[n];
200 int x = (int)(p->x - bbox->xmin);
207 if(fill && x!=lastx) {
208 fill_bitwise(line, lastx, x);
210 wind += p->direction;
211 if(rule == ART_WIND_RULE_INTERSECT) {
213 } else if (rule == ART_WIND_RULE_NONZERO) {
215 } else if (rule == ART_WIND_RULE_ODDEVEN) {
217 } else { // rule == ART_WIND_RULE_POSITIVE
222 if(fill && lastx!=buf->width)
223 fill_bitwise(line, lastx, buf->width);
226 for(y=0;y<buf->height;y++) {
227 if(buf->lines[y].points) {
228 free(buf->lines[y].points);
230 memset(&buf->lines[y], 0, sizeof(renderline_t));
232 free(buf->lines);buf->lines=0;
236 #define MAX_WIDTH 8192
237 #define MAX_HEIGHT 4096
239 intbbox_t get_svp_bbox(ArtSVP*svp, double zoom)
242 intbbox_t b = {0,0,0,0};
243 if(svp->n_segs && svp->segs[0].n_points) {
244 b.xmin = svp->segs[0].points[0].x;
245 b.ymin = svp->segs[0].points[0].y;
246 b.xmax = svp->segs[0].points[0].x;
247 b.ymax = svp->segs[0].points[0].y;
249 for(t=0;t<svp->n_segs;t++) {
250 ArtSVPSeg* seg = &svp->segs[t];
252 for(s=0;s<seg->n_points;s++) {
253 double x = seg->points[s].x*zoom;
254 double y = seg->points[s].y*zoom;
259 if(x1 < b.xmin) b.xmin = x1;
260 if(y1 < b.ymin) b.ymin = y1;
261 if(x2 > b.xmax) b.xmax = x2;
262 if(y2 > b.xmax) b.ymax = y2;
265 if(b.xmax > (int)(MAX_WIDTH*zoom))
266 b.xmax = (int)(MAX_WIDTH*zoom);
267 if(b.ymax > (int)(MAX_HEIGHT*zoom))
268 b.ymax = (int)(MAX_HEIGHT*zoom);
269 if(b.xmin < -(int)(MAX_WIDTH*zoom))
270 b.xmin = -(int)(MAX_WIDTH*zoom);
271 if(b.ymin < -(int)(MAX_HEIGHT*zoom))
272 b.ymin = -(int)(MAX_HEIGHT*zoom);
279 b.width = b.xmax - b.xmin;
280 b.height = b.ymax - b.ymin;
284 #define B11100000 0xe0
285 #define B01110000 0x70
286 #define B00111000 0x38
287 #define B00011100 0x1c
288 #define B00001110 0x0e
289 #define B00000111 0x07
290 #define B10000000 0x80
291 #define B01000000 0x40
292 #define B00100000 0x20
293 #define B00010000 0x10
294 #define B00001000 0x08
295 #define B00000100 0x04
296 #define B00000010 0x02
297 #define B00000001 0x01
299 int compare_bitmaps(intbbox_t*bbox, unsigned char*data1, unsigned char*data2)
303 int height = bbox->height;
304 int width = bbox->width;
305 int width8 = (width+7) >> 3;
306 unsigned char*l1 = &data1[width8];
307 unsigned char*l2 = &data2[width8];
309 for(y=1;y<height-1;y++) {
310 for(x=0;x<width8;x++) {
311 unsigned a = l1[x-width8] & l1[x] & l1[x+width8];
312 unsigned b = l2[x-width8] & l2[x] & l2[x+width8];
314 if((a&B11100000) && !(l2[x]&B01000000))
316 if((a&B01110000) && !(l2[x]&B00100000))
318 if((a&B00111000) && !(l2[x]&B00010000))
320 if((a&B00011100) && !(l2[x]&B00001000))
322 if((a&B00001110) && !(l2[x]&B00000100))
324 if((a&B00000111) && !(l2[x]&B00000010))
327 if((b&B11100000) && !(l1[x]&B01000000))
329 if((b&B01110000) && !(l1[x]&B00100000))
331 if((b&B00111000) && !(l1[x]&B00010000))
333 if((b&B00011100) && !(l1[x]&B00001000))
335 if((b&B00001110) && !(l1[x]&B00000100))
337 if((b&B00000111) && !(l1[x]&B00000010))
347 //-----------------------------------------------------------------------------------------------
349 static ArtVpath* gfxline_to_ArtVpath(gfxline_t*line, char fill)
351 ArtVpath *vec = NULL;
356 /* factor which determines into how many line fragments a spline is converted */
357 double subfraction = 2.4;//0.3
361 if(l2->type == gfx_moveTo) {
363 } else if(l2->type == gfx_lineTo) {
365 } else if(l2->type == gfx_splineTo) {
366 int parts = (int)(sqrt(fabs(l2->x-2*l2->sx+x) + fabs(l2->y-2*l2->sy+y))*subfraction);
367 if(!parts) parts = 1;
377 vec = art_new (ArtVpath, len+1);
382 if(l2->type == gfx_moveTo) {
383 vec[pos].code = ART_MOVETO_OPEN;
388 } else if(l2->type == gfx_lineTo) {
389 vec[pos].code = ART_LINETO;
394 } else if(l2->type == gfx_splineTo) {
396 int parts = (int)(sqrt(fabs(l2->x-2*l2->sx+x) + fabs(l2->y-2*l2->sy+y))*subfraction);
397 if(!parts) parts = 1;
398 double stepsize = 1.0/parts;
399 for(i=0;i<=parts;i++) {
400 double t = (double)i*stepsize;
401 vec[pos].code = ART_LINETO;
402 vec[pos].x = l2->x*t*t + 2*l2->sx*t*(1-t) + x*(1-t)*(1-t);
403 vec[pos].y = l2->y*t*t + 2*l2->sy*t*(1-t) + y*(1-t)*(1-t);
412 vec[pos++].code = ART_END;
416 /* Fix "dotted" lines. Those are lines where singular points are created
417 by a moveto x,y lineto x,y combination. We "fix" these by shifting the
418 point in the lineto a little bit to the right
419 These should only occur in strokes, not in fills, so do this only
420 when we know we're not filling.
423 for(t=0;vec[t].code!=ART_END;t++) {
424 if(t>0 && (vec[t-1].code==ART_MOVETO_OPEN || vec[t-1].code==ART_MOVETO)
425 && vec[t].code==ART_LINETO && vec[t+1].code!=ART_LINETO &&
426 vec[t-1].x == vec[t].x &&
427 vec[t-1].y == vec[t].y) {
433 /* Find adjacent identical points. If an ajdacent pair of identical
434 points is found, the second is removed.
435 So moveto x,y lineto x,y becomes moveto x,y
436 lineto x,y lineto x,y becomes lineto x,y
437 lineto x,y moveto x,y becomes lineto x,y
438 moveto x,y moveto x,y becomes moveto x,y
439 lineto x,y lineto x2,y2 becomes lineto x2,y2 (if dir(x,y) ~= dir(x2,y2))
445 if(vec[pos].code == ART_END) {
446 vec[outpos++] = vec[pos++];
450 char samedir = 0, samepoint = 0;
452 double dx = vec[pos].x-vec[pos-1].x;
453 double dy = vec[pos].y-vec[pos-1].y;
454 /*if(pos<len-1 && vec[pos].code == ART_LINETO && vec[pos+1].code == ART_LINETO) {
455 double dx2 = vec[pos+1].x-vec[pos].x;
456 double dy2 = vec[pos+1].y-vec[pos].y;
457 if(fabs(dx*dy2 - dy*dx2) < 0.0001 && dx*dx2 + dy*dy2 >= 0) {
461 if(fabs(dx) + fabs(dy) < 0.0001) {
465 if(!samepoint && !samedir) {
466 vec[outpos++] = vec[pos++];
475 static void shear_svp(ArtSVP*svp, double v)
477 /* do a "shearing" on the polygon. We do this to eliminate all
478 horizontal lines (which libart can't handle properly, even though
482 for(t=0;t<svp->n_segs;t++) {
483 ArtSVPSeg* seg = &svp->segs[t];
485 for(s=0;s<seg->n_points;s++) {
486 ArtPoint* point = &seg->points[s];
487 point->y += point->x*v;
492 static double find_shear_value(ArtSVP*svp)
494 /* We try random values until we find one
495 where there's no slope below a given value, or if that fails,
496 at least no slope of 0 */
503 for(t=0;t<svp->n_segs;t++) {
504 ArtSVPSeg* seg = &svp->segs[t];
506 for(s=0;s<seg->n_points-1;s++) {
507 ArtPoint* p1 = &seg->points[s];
508 ArtPoint* p2 = &seg->points[s+1];
509 double dx = p2->x - p1->x;
510 double dy = p2->y - p1->y;
516 if(tries<100 && dx && fabs(dy / dx) < 1e-5) {
526 v = lrand48() / 2000000000.0;
532 void show_path(ArtSVP*path)
535 printf("Segments: %d\n", path->n_segs);
536 for(t=0;t<path->n_segs;t++) {
537 ArtSVPSeg* seg = &path->segs[t];
538 printf("Segment %d: %d points, %s, BBox: (%f,%f,%f,%f)\n",
539 t, seg->n_points, seg->dir==0?"UP ":"DOWN",
540 seg->bbox.x0, seg->bbox.y0, seg->bbox.x1, seg->bbox.y1);
542 for(p=0;p<seg->n_points;p++) {
543 ArtPoint* point = &seg->points[p];
544 printf(" (%f,%f)\n", point->x, point->y);
551 typedef struct svp_segment_part
556 } svp_segment_part_t;
558 int compare_double(const void*_y1, const void*_y2)
560 const double*y1 = _y1;
561 const double*y2 = _y2;
562 if(*y1<*y2) return -1;
563 if(*y1>*y2) return 1;
567 int compare_seg_start(const void*_s1, const void*_s2)
569 svp_segment_part_t*s1 = *(svp_segment_part_t**)_s1;
570 svp_segment_part_t*s2 = *(svp_segment_part_t**)_s2;
571 if(s1->y1 < s2->y1) return -1;
572 if(s1->y1 > s2->y1) return 1;
576 int compare_seg_end(const void*_s1, const void*_s2)
578 svp_segment_part_t*s1 = *(svp_segment_part_t**)_s1;
579 svp_segment_part_t*s2 = *(svp_segment_part_t**)_s2;
580 if(s1->y2 < s2->y2) return -1;
581 if(s1->y2 > s2->y2) return 1;
585 void clean_svp(ArtSVP*svp)
592 for(t=0;t<svp->n_segs;t++) {
593 ArtSVPSeg* seg = &svp->segs[t];
597 oldpoints += seg->n_points;
598 for(p=0;p<seg->n_points;p++) {
599 ArtPoint* p1 = &seg->points[p];
600 if(!p || lasty!=p1->y) {
601 seg->points[pos] = seg->points[p];
607 newpoints += seg->n_points;
610 oldsegs = svp->n_segs;
611 for(t=0;t<svp->n_segs;t++) {
612 if(svp->segs[t].n_points > 1) {
613 svp->segs[pos++] = svp->segs[t];
617 newsegs = svp->n_segs;
618 if(newsegs < oldsegs || newpoints < oldpoints) {
619 msg("<verbose> Simplified polygon from %d points to %d points, %d to %d segs",
620 oldpoints, newpoints, oldsegs, newsegs);
624 int check_svp(ArtSVP*svp)
626 /* count number of y coordinates and segs */
630 for(t=0;t<svp->n_segs;t++) {
631 if(!svp->segs[t].n_points) {
632 msg("<error> svp contains segment with zero points\n");
635 num_points += svp->segs[t].n_points;
636 num_segs += svp->segs[t].n_points - 1;
639 /* create segs and ys */
640 double*y = malloc(sizeof(double)*num_points);
641 svp_segment_part_t*segs = malloc(sizeof(svp_segment_part_t)*num_segs);
642 svp_segment_part_t**seg_start = malloc(sizeof(svp_segment_part_t*)*num_segs);
643 svp_segment_part_t**seg_end = malloc(sizeof(svp_segment_part_t*)*num_segs);
647 for(t=0;t<svp->n_segs;t++) {
648 ArtSVPSeg* seg = &svp->segs[t];
650 for(p=0;p<seg->n_points;p++) {
651 y[c1++] = seg->points[p].y;
652 assert(c1 <= num_points);
654 for(p=0;p<seg->n_points-1;p++) {
655 ArtPoint* p1 = &seg->points[p];
656 ArtPoint* p2 = &seg->points[p+1];
660 msg("<error> bad svp, y in seg is non-increasing %.16f -> %.16f\n", p1->y, p2->y);
663 segs[num_segs].y1 = p1->y;
664 segs[num_segs].y2 = p2->y;
665 segs[num_segs].active = 0;
666 seg_start[num_segs] = &segs[num_segs];
667 seg_end[num_segs] = &segs[num_segs];
673 qsort(y, num_points, sizeof(double), compare_double);
674 qsort(seg_start, num_segs, sizeof(svp_segment_part_t*), compare_seg_start);
675 qsort(seg_end, num_segs, sizeof(svp_segment_part_t*), compare_seg_end);
677 double lasty = num_points?y[0]+1:0;
680 double bleedy1=0,bleedy2 = 0;
681 for(t=0;t<num_points;t++) {
685 for(s=0;s<num_segs;s++) {
686 if(segs[s].y1==y[t]) {
687 /* segment is starting */
690 } else if(segs[s].y2==y[t]) {
707 msg("<verbose> svp bleeds from y=%.16f to y=%.16f (%d/%d active segments)\n",
710 free(y);free(segs);free(seg_start);free(seg_end);
722 void write_svp_postscript(const char*filename, ArtSVP*svp)
726 printf("writing %s\n", filename);
727 FILE*fi = fopen(filename, "wb");
729 double xmin=0,ymin=0,xmax=0,ymax=0;
730 fprintf(fi, "%% begin\n");
731 for (i = 0; i < svp->n_segs; i++) {
732 for (j = 0; j < svp->segs[i].n_points; j++) {
733 double x = svp->segs[i].points[j].x;
734 double y = svp->segs[i].points[j].y;
739 if(x < xmin) xmin = x;
740 if(x > xmax) xmax = x;
741 if(y < ymin) ymin = y;
742 if(y > ymax) ymax = y;
746 if(xmax == xmin) xmax=xmin+1;
747 if(ymax == ymin) ymax=ymin+1;
749 for (i = 0; i < svp->n_segs; i++)
751 fprintf(fi, "%g setgray\n", svp->segs[i].dir ? 0.7 : 0);
752 for (j = 0; j < svp->segs[i].n_points; j++)
754 //fprintf(fi, "%g %g %s\n",
755 // 20 + 550*(svp->segs[i].points[j].x-xmin)/(xmax-xmin),
756 // 820 - 800*(svp->segs[i].points[j].y-ymin)/(ymax-ymin),
757 // j ? "lineto" : "moveto");
758 fprintf(fi, "%.32f %.32f %s\n",
759 svp->segs[i].points[j].x,
760 svp->segs[i].points[j].y,
761 j ? "lineto" : "moveto");
763 fprintf(fi, "stroke\n");
766 fprintf(fi, "showpage\n");
770 void write_vpath_postscript(const char*filename, ArtVpath*path)
772 FILE*fi = fopen(filename, "wb");
774 double xmin=0,ymin=0,xmax=0,ymax=0;
775 fprintf(fi, "%% begin\n");
778 while(p->code != ART_END) {
779 if(p->code == ART_MOVETO || p->code == ART_MOVETO_OPEN) {
781 fprintf(fi, "stroke\n");
783 fprintf(fi, "0.0 setgray\n");
784 fprintf(fi, "%.32f %.32f moveto\n", p->x, p->y);
786 fprintf(fi, "%.32f %.32f lineto\n", p->x, p->y);
791 fprintf(fi, "stroke\n");
792 fprintf(fi, "showpage\n");
796 void write_gfxline_postscript(const char*filename, gfxline_t*line)
798 FILE*fi = fopen(filename, "wb");
800 fprintf(fi, "%% begin\n");
803 if(line->type == gfx_moveTo) {
805 fprintf(fi, "stroke\n");
807 fprintf(fi, "0.0 setgray\n");
808 fprintf(fi, "%.32f %.32f moveto\n", line->x, line->y);
810 fprintf(fi, "%.32f %.32f lineto\n", line->x, line->y);
815 fprintf(fi, "stroke\n");
816 fprintf(fi, "showpage\n");
820 static int vpath_len(ArtVpath*svp)
823 while(svp->code != ART_END) {
830 int gfxline_len(gfxline_t*line)
841 static ArtVpath*pvpath= 0;
842 static int cmppos(const void*_p1, const void*_p2)
846 ArtVpath*v1 = &pvpath[*p1];
847 ArtVpath*v2 = &pvpath[*p2];
850 else if(v1->y > v2->y)
852 else if(v1->x < v2->x)
854 else if(v1->x > v2->x)
860 #define PERTURBATION 2e-3
861 static void my_perturb(ArtVpath*vpath)
864 int len = vpath_len(vpath);
865 int*pos = (int*)malloc(len*sizeof(int));
869 qsort(pos, len, sizeof(int), cmppos);
873 while(t2<len && !cmppos(&pos[t],&pos[t2])) {
877 double dx = (PERTURBATION * rand ()) / RAND_MAX - PERTURBATION * 0.5;
878 double dy = (PERTURBATION * rand ()) / RAND_MAX - PERTURBATION * 0.5;
881 vpath[pos[s]].x += dx;
882 vpath[pos[s]].y += dy;
890 static ArtSVP* gfxfillToSVP(gfxline_t*line, int perturb)
892 ArtVpath* vec = gfxline_to_ArtVpath(line, 1);
893 msg("<verbose> Casting gfxline of %d segments (%d line segments) to a gfxpoly", gfxline_len(line), vpath_len(vec));
896 //ArtVpath* vec2 = art_vpath_perturb(vec);
901 ArtSVP *svp = art_svp_from_vpath(vec);
908 // double shear = find_shear_value(svp);
909 // gfxline_t*line = gfxpoly_to_gfxline((gfxpoly_t*)svp);
910 // gfxline_t*l = line;
912 // l->y += l->x*shear;
913 // l->sy += l->sx*shear;
916 // svp = (ArtSVP*)gfxpoly_fillToPoly(line);
917 // printf("shearing svp by %.16f\n", shear);
921 // art_svp_free(svp);
922 // shear_svp(result, -shear);
927 extern const ArtSVP* current_svp;
928 extern void art_report_error();
929 extern int art_error_in_intersector;
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;