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 intbbox_t get_svp_bbox(ArtSVP*svp, double zoom)
239 intbbox_t b = {0,0,0,0};
240 if(svp->n_segs && svp->segs[0].n_points) {
241 b.xmin = svp->segs[0].points[0].x;
242 b.ymin = svp->segs[0].points[0].y;
243 b.xmax = svp->segs[0].points[0].x;
244 b.ymax = svp->segs[0].points[0].y;
246 for(t=0;t<svp->n_segs;t++) {
247 ArtSVPSeg* seg = &svp->segs[t];
249 for(s=0;s<seg->n_points;s++) {
250 double x = seg->points[s].x*zoom;
251 double y = seg->points[s].y*zoom;
256 if(x1 < b.xmin) b.xmin = x1;
257 if(y1 < b.ymin) b.ymin = y1;
258 if(x2 > b.xmax) b.xmax = x2;
259 if(y2 > b.xmax) b.ymax = y2;
262 b.width = b.xmax - b.xmin;
263 b.height = b.ymax - b.ymin;
267 #define B11100000 0xe0
268 #define B01110000 0x70
269 #define B00111000 0x38
270 #define B00011100 0x1c
271 #define B00001110 0x0e
272 #define B00000111 0x07
273 #define B10000000 0x80
274 #define B01000000 0x40
275 #define B00100000 0x20
276 #define B00010000 0x10
277 #define B00001000 0x08
278 #define B00000100 0x04
279 #define B00000010 0x02
280 #define B00000001 0x01
282 int compare_bitmaps(intbbox_t*bbox, unsigned char*data1, unsigned char*data2)
286 int height = bbox->height;
287 int width = bbox->width;
288 int width8 = (width+7) >> 3;
289 unsigned char*l1 = &data1[width8];
290 unsigned char*l2 = &data2[width8];
292 for(y=1;y<height-1;y++) {
293 for(x=0;x<width8;x++) {
294 unsigned a = l1[x-width8] & l1[x] & l1[x+width8];
295 unsigned b = l2[x-width8] & l2[x] & l2[x+width8];
297 if((a&B11100000) && !(l2[x]&B01000000))
299 if((a&B01110000) && !(l2[x]&B00100000))
301 if((a&B00111000) && !(l2[x]&B00010000))
303 if((a&B00011100) && !(l2[x]&B00001000))
305 if((a&B00001110) && !(l2[x]&B00000100))
307 if((a&B00000111) && !(l2[x]&B00000010))
310 if((b&B11100000) && !(l1[x]&B01000000))
312 if((b&B01110000) && !(l1[x]&B00100000))
314 if((b&B00111000) && !(l1[x]&B00010000))
316 if((b&B00011100) && !(l1[x]&B00001000))
318 if((b&B00001110) && !(l1[x]&B00000100))
320 if((b&B00000111) && !(l1[x]&B00000010))
330 //-----------------------------------------------------------------------------------------------
332 static ArtVpath* gfxline_to_ArtVpath(gfxline_t*line, char fill)
334 ArtVpath *vec = NULL;
339 /* factor which determines into how many line fragments a spline is converted */
340 double subfraction = 2.4;//0.3
344 if(l2->type == gfx_moveTo) {
346 } else if(l2->type == gfx_lineTo) {
348 } else if(l2->type == gfx_splineTo) {
349 int parts = (int)(sqrt(fabs(l2->x-2*l2->sx+x) + fabs(l2->y-2*l2->sy+y))*subfraction);
350 if(!parts) parts = 1;
360 vec = art_new (ArtVpath, len+1);
365 if(l2->type == gfx_moveTo) {
366 vec[pos].code = ART_MOVETO_OPEN;
371 } else if(l2->type == gfx_lineTo) {
372 vec[pos].code = ART_LINETO;
377 } else if(l2->type == gfx_splineTo) {
379 int parts = (int)(sqrt(fabs(l2->x-2*l2->sx+x) + fabs(l2->y-2*l2->sy+y))*subfraction);
380 if(!parts) parts = 1;
381 double stepsize = 1.0/parts;
382 for(i=0;i<=parts;i++) {
383 double t = (double)i*stepsize;
384 vec[pos].code = ART_LINETO;
385 vec[pos].x = l2->x*t*t + 2*l2->sx*t*(1-t) + x*(1-t)*(1-t);
386 vec[pos].y = l2->y*t*t + 2*l2->sy*t*(1-t) + y*(1-t)*(1-t);
395 vec[pos++].code = ART_END;
399 /* Fix "dotted" lines. Those are lines where singular points are created
400 by a moveto x,y lineto x,y combination. We "fix" these by shifting the
401 point in the lineto a little bit to the right
402 These should only occur in strokes, not in fills, so do this only
403 when we know we're not filling.
406 for(t=0;vec[t].code!=ART_END;t++) {
407 if(t>0 && (vec[t-1].code==ART_MOVETO_OPEN || vec[t-1].code==ART_MOVETO)
408 && vec[t].code==ART_LINETO && vec[t+1].code!=ART_LINETO &&
409 vec[t-1].x == vec[t].x &&
410 vec[t-1].y == vec[t].y) {
416 /* Find adjacent identical points. If an ajdacent pair of identical
417 points is found, the second is removed.
418 So moveto x,y lineto x,y becomes moveto x,y
419 lineto x,y lineto x,y becomes lineto x,y
420 lineto x,y moveto x,y becomes lineto x,y
421 moveto x,y moveto x,y becomes moveto x,y
422 lineto x,y lineto x2,y2 becomes lineto x2,y2 (if dir(x,y) ~= dir(x2,y2))
428 if(vec[pos].code == ART_END) {
429 vec[outpos++] = vec[pos++];
433 char samedir = 0, samepoint = 0;
435 double dx = vec[pos].x-vec[pos-1].x;
436 double dy = vec[pos].y-vec[pos-1].y;
437 /*if(pos<len-1 && vec[pos].code == ART_LINETO && vec[pos+1].code == ART_LINETO) {
438 double dx2 = vec[pos+1].x-vec[pos].x;
439 double dy2 = vec[pos+1].y-vec[pos].y;
440 if(fabs(dx*dy2 - dy*dx2) < 0.0001 && dx*dx2 + dy*dy2 >= 0) {
444 if(fabs(dx) + fabs(dy) < 0.0001) {
448 if(!samepoint && !samedir) {
449 vec[outpos++] = vec[pos++];
458 static void shear_svp(ArtSVP*svp, double v)
460 /* do a "shearing" on the polygon. We do this to eliminate all
461 horizontal lines (which libart can't handle properly, even though
465 for(t=0;t<svp->n_segs;t++) {
466 ArtSVPSeg* seg = &svp->segs[t];
468 for(s=0;s<seg->n_points;s++) {
469 ArtPoint* point = &seg->points[s];
470 point->y += point->x*v;
475 static double find_shear_value(ArtSVP*svp)
477 /* We try random values until we find one
478 where there's no slope below a given value, or if that fails,
479 at least no slope of 0 */
486 for(t=0;t<svp->n_segs;t++) {
487 ArtSVPSeg* seg = &svp->segs[t];
489 for(s=0;s<seg->n_points-1;s++) {
490 ArtPoint* p1 = &seg->points[s];
491 ArtPoint* p2 = &seg->points[s+1];
492 double dx = p2->x - p1->x;
493 double dy = p2->y - p1->y;
499 if(tries<100 && dx && fabs(dy / dx) < 1e-5) {
509 v = lrand48() / 2000000000.0;
515 void show_path(ArtSVP*path)
518 printf("Segments: %d\n", path->n_segs);
519 for(t=0;t<path->n_segs;t++) {
520 ArtSVPSeg* seg = &path->segs[t];
521 printf("Segment %d: %d points, %s, BBox: (%f,%f,%f,%f)\n",
522 t, seg->n_points, seg->dir==0?"UP ":"DOWN",
523 seg->bbox.x0, seg->bbox.y0, seg->bbox.x1, seg->bbox.y1);
525 for(p=0;p<seg->n_points;p++) {
526 ArtPoint* point = &seg->points[p];
527 printf(" (%f,%f)\n", point->x, point->y);
534 typedef struct svp_segment_part
539 } svp_segment_part_t;
541 int compare_double(const void*_y1, const void*_y2)
543 const double*y1 = _y1;
544 const double*y2 = _y2;
545 if(*y1<*y2) return -1;
546 if(*y1>*y2) return 1;
550 int compare_seg_start(const void*_s1, const void*_s2)
552 svp_segment_part_t*s1 = *(svp_segment_part_t**)_s1;
553 svp_segment_part_t*s2 = *(svp_segment_part_t**)_s2;
554 if(s1->y1 < s2->y1) return -1;
555 if(s1->y1 > s2->y1) return 1;
559 int compare_seg_end(const void*_s1, const void*_s2)
561 svp_segment_part_t*s1 = *(svp_segment_part_t**)_s1;
562 svp_segment_part_t*s2 = *(svp_segment_part_t**)_s2;
563 if(s1->y2 < s2->y2) return -1;
564 if(s1->y2 > s2->y2) return 1;
568 void clean_svp(ArtSVP*svp)
575 for(t=0;t<svp->n_segs;t++) {
576 ArtSVPSeg* seg = &svp->segs[t];
580 oldpoints += seg->n_points;
581 for(p=0;p<seg->n_points;p++) {
582 ArtPoint* p1 = &seg->points[p];
583 if(!p || lasty!=p1->y) {
584 seg->points[pos] = seg->points[p];
590 newpoints += seg->n_points;
593 oldsegs = svp->n_segs;
594 for(t=0;t<svp->n_segs;t++) {
595 if(svp->segs[t].n_points > 1) {
596 svp->segs[pos++] = svp->segs[t];
600 newsegs = svp->n_segs;
601 if(newsegs < oldsegs || newpoints < oldpoints) {
602 msg("<verbose> Simplified polygon from %d points to %d points, %d to %d segs",
603 oldpoints, newpoints, oldsegs, newsegs);
607 int check_svp(ArtSVP*svp)
609 /* count number of y coordinates and segs */
613 for(t=0;t<svp->n_segs;t++) {
614 if(!svp->segs[t].n_points) {
615 msg("<error> svp contains segment with zero points\n");
618 num_points += svp->segs[t].n_points;
619 num_segs += svp->segs[t].n_points - 1;
622 /* create segs and ys */
623 double*y = malloc(sizeof(double)*num_points);
624 svp_segment_part_t*segs = malloc(sizeof(svp_segment_part_t)*num_segs);
625 svp_segment_part_t**seg_start = malloc(sizeof(svp_segment_part_t*)*num_segs);
626 svp_segment_part_t**seg_end = malloc(sizeof(svp_segment_part_t*)*num_segs);
630 for(t=0;t<svp->n_segs;t++) {
631 ArtSVPSeg* seg = &svp->segs[t];
633 for(p=0;p<seg->n_points;p++) {
634 y[c1++] = seg->points[p].y;
635 assert(c1 <= num_points);
637 for(p=0;p<seg->n_points-1;p++) {
638 ArtPoint* p1 = &seg->points[p];
639 ArtPoint* p2 = &seg->points[p+1];
643 msg("<error> bad svp, y in seg is non-increasing %.16f -> %.16f\n", p1->y, p2->y);
646 segs[num_segs].y1 = p1->y;
647 segs[num_segs].y2 = p2->y;
648 segs[num_segs].active = 0;
649 seg_start[num_segs] = &segs[num_segs];
650 seg_end[num_segs] = &segs[num_segs];
656 qsort(y, num_points, sizeof(double), compare_double);
657 qsort(seg_start, num_segs, sizeof(svp_segment_part_t*), compare_seg_start);
658 qsort(seg_end, num_segs, sizeof(svp_segment_part_t*), compare_seg_end);
660 double lasty = y[0]+1;
663 double bleedy1=0,bleedy2 = 0;
664 for(t=0;t<num_points;t++) {
668 for(s=0;s<num_segs;s++) {
669 if(segs[s].y1==y[t]) {
670 /* segment is starting */
673 } else if(segs[s].y2==y[t]) {
690 msg("<verbose> svp bleeds from y=%.16f to y=%.16f (%d/%d active segments)\n",
693 free(y);free(segs);free(seg_start);free(seg_end);
705 void write_svp_postscript(const char*filename, ArtSVP*svp)
709 printf("writing %s\n", filename);
710 FILE*fi = fopen(filename, "wb");
712 double xmin=0,ymin=0,xmax=0,ymax=0;
713 fprintf(fi, "%% begin\n");
714 for (i = 0; i < svp->n_segs; i++) {
715 for (j = 0; j < svp->segs[i].n_points; j++) {
716 double x = svp->segs[i].points[j].x;
717 double y = svp->segs[i].points[j].y;
722 if(x < xmin) xmin = x;
723 if(x > xmax) xmax = x;
724 if(y < ymin) ymin = y;
725 if(y > ymax) ymax = y;
729 if(xmax == xmin) xmax=xmin+1;
730 if(ymax == ymin) ymax=ymin+1;
732 for (i = 0; i < svp->n_segs; i++)
734 fprintf(fi, "%g setgray\n", svp->segs[i].dir ? 0.7 : 0);
735 for (j = 0; j < svp->segs[i].n_points; j++)
737 //fprintf(fi, "%g %g %s\n",
738 // 20 + 550*(svp->segs[i].points[j].x-xmin)/(xmax-xmin),
739 // 820 - 800*(svp->segs[i].points[j].y-ymin)/(ymax-ymin),
740 // j ? "lineto" : "moveto");
741 fprintf(fi, "%.32f %.32f %s\n",
742 svp->segs[i].points[j].x,
743 svp->segs[i].points[j].y,
744 j ? "lineto" : "moveto");
746 fprintf(fi, "stroke\n");
749 fprintf(fi, "showpage\n");
753 void write_vpath_postscript(const char*filename, ArtVpath*path)
755 FILE*fi = fopen(filename, "wb");
757 double xmin=0,ymin=0,xmax=0,ymax=0;
758 fprintf(fi, "%% begin\n");
761 while(p->code != ART_END) {
762 if(p->code == ART_MOVETO || p->code == ART_MOVETO_OPEN) {
764 fprintf(fi, "stroke\n");
766 fprintf(fi, "0.0 setgray\n");
767 fprintf(fi, "%.32f %.32f moveto\n", p->x, p->y);
769 fprintf(fi, "%.32f %.32f lineto\n", p->x, p->y);
774 fprintf(fi, "stroke\n");
775 fprintf(fi, "showpage\n");
779 void write_gfxline_postscript(const char*filename, gfxline_t*line)
781 FILE*fi = fopen(filename, "wb");
783 fprintf(fi, "%% begin\n");
786 if(line->type == gfx_moveTo) {
788 fprintf(fi, "stroke\n");
790 fprintf(fi, "0.0 setgray\n");
791 fprintf(fi, "%.32f %.32f moveto\n", line->x, line->y);
793 fprintf(fi, "%.32f %.32f lineto\n", line->x, line->y);
798 fprintf(fi, "stroke\n");
799 fprintf(fi, "showpage\n");
803 static int vpath_len(ArtVpath*svp)
806 while(svp->code != ART_END) {
813 int gfxline_len(gfxline_t*line)
824 static ArtVpath*pvpath= 0;
825 static int cmppos(const void*_p1, const void*_p2)
829 ArtVpath*v1 = &pvpath[*p1];
830 ArtVpath*v2 = &pvpath[*p2];
833 else if(v1->y > v2->y)
835 else if(v1->x < v2->x)
837 else if(v1->x > v2->x)
843 #define PERTURBATION 2e-3
844 static void my_perturb(ArtVpath*vpath)
847 int len = vpath_len(vpath);
848 int*pos = (int*)malloc(len*sizeof(int));
852 qsort(pos, len, sizeof(int), cmppos);
856 while(t2<len && !cmppos(&pos[t],&pos[t2])) {
860 double dx = (PERTURBATION * rand ()) / RAND_MAX - PERTURBATION * 0.5;
861 double dy = (PERTURBATION * rand ()) / RAND_MAX - PERTURBATION * 0.5;
864 vpath[pos[s]].x += dx;
865 vpath[pos[s]].y += dy;
873 static ArtSVP* gfxfillToSVP(gfxline_t*line, int perturb)
875 ArtVpath* vec = gfxline_to_ArtVpath(line, 1);
876 msg("<verbose> Casting gfxline of %d segments (%d line segments) to a gfxpoly", gfxline_len(line), vpath_len(vec));
879 //ArtVpath* vec2 = art_vpath_perturb(vec);
884 ArtSVP *svp = art_svp_from_vpath(vec);
891 // double shear = find_shear_value(svp);
892 // gfxline_t*line = gfxpoly_to_gfxline((gfxpoly_t*)svp);
893 // gfxline_t*l = line;
895 // l->y += l->x*shear;
896 // l->sy += l->sx*shear;
899 // svp = (ArtSVP*)gfxpoly_fillToPoly(line);
900 // printf("shearing svp by %.16f\n", shear);
904 // art_svp_free(svp);
905 // shear_svp(result, -shear);
910 extern const ArtSVP* current_svp;
911 extern void art_report_error();
912 extern int art_error_in_intersector;
914 ArtSVP* run_intersector(ArtSVP*svp, ArtWindRule rule)
916 ArtSvpWriter * swr = art_svp_writer_rewind_new(rule);
919 intbbox_t bbox = get_svp_bbox(svp, zoom);
921 art_svp_intersector(svp, swr);
922 ArtSVP*result = art_svp_writer_rewind_reap(swr);
924 if(!check_svp(result)) {
925 current_svp = result;
926 art_report_error(); // might set art_error_in_intersector
928 unsigned char*data1 = render_svp(svp, &bbox, zoom, rule);
929 unsigned char*data2 = render_svp(result, &bbox, zoom, ART_WIND_RULE_ODDEVEN);
930 msg("<verbose> Comparing polygon renderings of size %dx%d and %dx%d", bbox.width, bbox.height, bbox.width, bbox.height);
931 if(!compare_bitmaps(&bbox, data1, data2)) {
932 msg("<verbose> Bad SVP rewinding result- polygons don't match");
933 current_svp = result;
934 art_report_error(); // might set art_error_in_intersector
940 if(art_error_in_intersector) {
941 msg("<verbose> Error in polygon processing");
942 art_svp_free(result);
943 art_error_in_intersector=0;
949 gfxline_t* gfxpoly_to_gfxline(gfxpoly_t*poly)
951 ArtSVP*svp = (ArtSVP*)poly;
956 msg("<verbose> Casting polygon of %d segments back to gfxline", svp->n_segs);
958 for(t=0;t<svp->n_segs;t++) {
959 size += svp->segs[t].n_points;
962 gfxline_t* lines = (gfxline_t*)rfx_alloc(sizeof(gfxline_t)*size);
964 for(t=0;t<svp->n_segs;t++) {
965 ArtSVPSeg* seg = &svp->segs[t];
967 for(p=0;p<seg->n_points;p++) {
968 lines[pos].type = p==0?gfx_moveTo:gfx_lineTo;
969 ArtPoint* point = &seg->points[p];
970 lines[pos].x = point->x;
971 lines[pos].y = point->y;
972 lines[pos].next = &lines[pos+1];
977 lines[pos-1].next = 0;
984 gfxpoly_t* gfxpoly_fillToPoly(gfxline_t*line)
986 /* I'm not sure whether doing perturbation here is actually
987 a good idea- if that line has been run through the machine
988 several times already, it might be safer to leave it alone,
989 since it should already be in a format libart can handle */
991 ArtSVP* svp = gfxfillToSVP(line, 1);
993 ArtSVP* svp = gfxfillToSVP(line, 0);
998 static int counter = 0;
999 sprintf(filename, "svp%d.ps", counter);
1000 write_svp_postscript(filename, svp);
1001 sprintf(filename, "gfxline%d.ps", counter);
1002 write_gfxline_postscript(filename, line);
1005 /* we do xor-filling by default, so dir is always 1
1006 (actually for oddeven rewinding it makes no difference, but
1010 for(t=0; t<svp->n_segs; t++) {
1011 svp->segs[t].dir = 1;
1014 /* for some reason, we need to rewind / self-intersect the polygons that gfxfillToSVP
1015 returns- art probably uses a different fill mode (circular?) for vpaths */
1016 ArtSVP*svp_uncrossed=0;
1019 sprintf(filename, "svp%d_in.ps", counter);
1020 write_svp_postscript(filename, svp);
1024 svp_uncrossed = run_intersector(svp, ART_WIND_RULE_ODDEVEN);
1029 return (gfxpoly_t*)svp;
1032 gfxpoly_t* gfxpoly_intersect(gfxpoly_t*poly1, gfxpoly_t*poly2)
1036 static int counter = 0;
1038 ArtSVP* svp1 = (ArtSVP*)poly1;
1039 ArtSVP* svp2 = (ArtSVP*)poly2;
1040 msg("<verbose> Intersecting two polygons of %d and %d segments", svp1->n_segs, svp2->n_segs);
1044 sprintf(filename, "isvp%d_src1.ps", counter);
1045 write_svp_postscript(filename, svp1);
1046 sprintf(filename, "isvp%d_src2.ps", counter);
1047 write_svp_postscript(filename, svp2);
1050 ArtSVP* svp3 = art_svp_merge (svp1, svp2);
1053 sprintf(filename, "isvp%d_src.ps", counter);
1054 write_svp_postscript(filename, svp3);
1057 //write_svp_postscript("svp.ps", svp3);
1058 ArtSVP*svp_new = run_intersector(svp3, ART_WIND_RULE_INTERSECT);
1060 art_free (svp3); /* shallow free because svp3 contains shared segments */
1063 sprintf(filename, "isvp%d.ps", counter);
1064 write_svp_postscript(filename, svp_new);
1069 //write_svp_postscript("svp_new.ps", svp_new);
1071 return (gfxpoly_t*)svp_new;
1074 gfxpoly_t* gfxpoly_union(gfxpoly_t*poly1, gfxpoly_t*poly2)
1076 ArtSVP* svp1 = (ArtSVP*)poly1;
1077 ArtSVP* svp2 = (ArtSVP*)poly2;
1078 msg("<verbose> Unifying two polygons of %d and %d segments", svp1->n_segs, svp2->n_segs);
1080 ArtSVP* svp = art_svp_union(svp1, svp2);
1081 return (gfxpoly_t*)svp;
1084 gfxpoly_t* gfxpoly_strokeToPoly(gfxline_t*line, gfxcoord_t width, gfx_capType cap_style, gfx_joinType joint_style, double miterLimit)
1086 ArtVpath* vec = gfxline_to_ArtVpath(line, 0);
1087 msg("<verbose> Casting gfxline of %d segments to a stroke-polygon", gfxline_len(line));
1089 ArtVpath* vec2 = art_vpath_perturb(vec);
1093 ArtSVP *svp = art_svp_vpath_stroke (vec,
1094 (joint_style==gfx_joinMiter)?ART_PATH_STROKE_JOIN_MITER:
1095 ((joint_style==gfx_joinRound)?ART_PATH_STROKE_JOIN_ROUND:
1096 ((joint_style==gfx_joinBevel)?ART_PATH_STROKE_JOIN_BEVEL:ART_PATH_STROKE_JOIN_BEVEL)),
1097 (cap_style==gfx_capButt)?ART_PATH_STROKE_CAP_BUTT:
1098 ((cap_style==gfx_capRound)?ART_PATH_STROKE_CAP_ROUND:
1099 ((cap_style==gfx_capSquare)?ART_PATH_STROKE_CAP_SQUARE:ART_PATH_STROKE_CAP_SQUARE)),
1101 miterLimit, //miter_limit
1105 return (gfxpoly_t*)svp;
1108 gfxline_t* gfxline_circularToEvenOdd(gfxline_t*line)
1110 msg("<verbose> Converting circular-filled gfxline of %d segments to even-odd filled gfxline", gfxline_len(line));
1111 ArtSVP* svp = gfxfillToSVP(line, 1);
1113 /* TODO: ART_WIND_RULE_POSITIVE means that a shape is visible if
1114 positive and negative line segments add up to something positive.
1115 I *think* that clockwise fill in PDF is defined in a way, however,
1116 that the *last* shape's direction will determine whether something
1118 ArtSVP* svp_rewinded;
1120 svp_rewinded = run_intersector(svp, ART_WIND_RULE_POSITIVE);
1126 gfxline_t* result = gfxpoly_to_gfxline((gfxpoly_t*)svp_rewinded);
1128 art_svp_free(svp_rewinded);
1132 gfxpoly_t* gfxpoly_createbox(double x1, double y1,double x2, double y2)
1134 ArtVpath *vec = art_new (ArtVpath, 5+1);
1135 vec[0].code = ART_MOVETO;
1138 vec[1].code = ART_LINETO;
1141 vec[2].code = ART_LINETO;
1144 vec[3].code = ART_LINETO;
1147 vec[4].code = ART_LINETO;
1150 vec[5].code = ART_END;
1153 ArtSVP *svp = art_svp_from_vpath(vec);
1155 return (gfxpoly_t*)svp;
1158 void gfxpoly_free(gfxpoly_t*poly)
1160 ArtSVP*svp = (ArtSVP*)poly;