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);
389 if(l2->type == gfx_moveTo) {
390 vec[pos].code = ART_MOVETO_OPEN;
396 } else if(l2->type == gfx_lineTo) {
397 vec[pos].code = ART_LINETO;
402 } else if(l2->type == gfx_splineTo) {
404 int parts = (int)(sqrt(fabs(l2->x-2*l2->sx+x) + fabs(l2->y-2*l2->sy+y))*subfraction);
405 if(!parts) parts = 1;
406 double stepsize = 1.0/parts;
407 for(i=0;i<=parts;i++) {
408 double t = (double)i*stepsize;
409 vec[pos].code = ART_LINETO;
410 vec[pos].x = l2->x*t*t + 2*l2->sx*t*(1-t) + x*(1-t)*(1-t);
411 vec[pos].y = l2->y*t*t + 2*l2->sy*t*(1-t) + y*(1-t)*(1-t);
419 /* let closed line segments start w/ MOVETO instead of MOVETO_OPEN */
420 if(lastmove>=0 && l2->type!=gfx_moveTo && (!l2->next || l2->next->type == gfx_moveTo)) {
421 if(vec[lastmove].x == l2->x &&
422 vec[lastmove].y == l2->y) {
423 assert(vec[lastmove].code == ART_MOVETO_OPEN);
424 vec[lastmove].code = ART_MOVETO;
430 vec[pos++].code = ART_END;
434 /* Fix "dotted" lines. Those are lines where singular points are created
435 by a moveto x,y lineto x,y combination. We "fix" these by shifting the
436 point in the lineto a little bit to the right
437 These should only occur in strokes, not in fills, so do this only
438 when we know we're not filling.
441 for(t=0;vec[t].code!=ART_END;t++) {
442 if(t>0 && (vec[t-1].code==ART_MOVETO_OPEN || vec[t-1].code==ART_MOVETO)
443 && vec[t].code==ART_LINETO && vec[t+1].code!=ART_LINETO &&
444 vec[t-1].x == vec[t].x &&
445 vec[t-1].y == vec[t].y) {
451 /* Find adjacent identical points. If an ajdacent pair of identical
452 points is found, the second one is removed.
453 So moveto x,y lineto x,y becomes moveto x,y
454 lineto x,y lineto x,y becomes lineto x,y
455 lineto x,y moveto x,y becomes lineto x,y
456 moveto x,y moveto x,y becomes moveto x,y
457 lineto x,y lineto x2,y2 becomes lineto x2,y2 (if dir(x,y) ~= dir(x2,y2))
463 if(vec[pos].code == ART_END) {
464 vec[outpos++] = vec[pos++];
468 char samedir = 0, samepoint = 0;
470 double dx = vec[pos].x-vec[pos-1].x;
471 double dy = vec[pos].y-vec[pos-1].y;
472 /*if(pos<len-1 && vec[pos].code == ART_LINETO && vec[pos+1].code == ART_LINETO) {
473 double dx2 = vec[pos+1].x-vec[pos].x;
474 double dy2 = vec[pos+1].y-vec[pos].y;
475 if(fabs(dx*dy2 - dy*dx2) < 0.0001 && dx*dx2 + dy*dy2 >= 0) {
479 if(fabs(dx) + fabs(dy) < 0.0001) {
483 if(!samepoint && !samedir) {
484 vec[outpos++] = vec[pos++];
493 static void shear_svp(ArtSVP*svp, double v)
495 /* do a "shearing" on the polygon. We do this to eliminate all
496 horizontal lines (which libart can't handle properly, even though
500 for(t=0;t<svp->n_segs;t++) {
501 ArtSVPSeg* seg = &svp->segs[t];
503 for(s=0;s<seg->n_points;s++) {
504 ArtPoint* point = &seg->points[s];
505 point->y += point->x*v;
510 static double find_shear_value(ArtSVP*svp)
512 /* We try random values until we find one
513 where there's no slope below a given value, or if that fails,
514 at least no slope of 0 */
521 for(t=0;t<svp->n_segs;t++) {
522 ArtSVPSeg* seg = &svp->segs[t];
524 for(s=0;s<seg->n_points-1;s++) {
525 ArtPoint* p1 = &seg->points[s];
526 ArtPoint* p2 = &seg->points[s+1];
527 double dx = p2->x - p1->x;
528 double dy = p2->y - p1->y;
534 if(tries<100 && dx && fabs(dy / dx) < 1e-5) {
545 v = lrand48() / 2000000000.0;;
547 v = rand() / 2000000000.0;
549 #error "no lrand48()/rand() implementation found"
556 void show_path(ArtSVP*path)
559 printf("Segments: %d\n", path->n_segs);
560 for(t=0;t<path->n_segs;t++) {
561 ArtSVPSeg* seg = &path->segs[t];
562 printf("Segment %d: %d points, %s, BBox: (%f,%f,%f,%f)\n",
563 t, seg->n_points, seg->dir==0?"UP ":"DOWN",
564 seg->bbox.x0, seg->bbox.y0, seg->bbox.x1, seg->bbox.y1);
566 for(p=0;p<seg->n_points;p++) {
567 ArtPoint* point = &seg->points[p];
568 printf(" (%f,%f)\n", point->x, point->y);
575 typedef struct svp_segment_part
580 } svp_segment_part_t;
582 int compare_double(const void*_y1, const void*_y2)
584 const double*y1 = _y1;
585 const double*y2 = _y2;
586 if(*y1<*y2) return -1;
587 if(*y1>*y2) return 1;
591 int compare_seg_start(const void*_s1, const void*_s2)
593 svp_segment_part_t*s1 = *(svp_segment_part_t**)_s1;
594 svp_segment_part_t*s2 = *(svp_segment_part_t**)_s2;
595 if(s1->y1 < s2->y1) return -1;
596 if(s1->y1 > s2->y1) return 1;
600 int compare_seg_end(const void*_s1, const void*_s2)
602 svp_segment_part_t*s1 = *(svp_segment_part_t**)_s1;
603 svp_segment_part_t*s2 = *(svp_segment_part_t**)_s2;
604 if(s1->y2 < s2->y2) return -1;
605 if(s1->y2 > s2->y2) return 1;
609 void clean_svp(ArtSVP*svp)
616 for(t=0;t<svp->n_segs;t++) {
617 ArtSVPSeg* seg = &svp->segs[t];
621 oldpoints += seg->n_points;
622 for(p=0;p<seg->n_points;p++) {
623 ArtPoint* p1 = &seg->points[p];
624 if(!p || lasty!=p1->y) {
625 seg->points[pos] = seg->points[p];
631 newpoints += seg->n_points;
634 oldsegs = svp->n_segs;
635 for(t=0;t<svp->n_segs;t++) {
636 if(svp->segs[t].n_points > 1) {
637 svp->segs[pos++] = svp->segs[t];
641 newsegs = svp->n_segs;
642 if(newsegs < oldsegs || newpoints < oldpoints) {
643 msg("<verbose> Simplified polygon from %d points to %d points, %d to %d segs",
644 oldpoints, newpoints, oldsegs, newsegs);
648 int check_svp(ArtSVP*svp)
650 /* count number of y coordinates and segs */
654 for(t=0;t<svp->n_segs;t++) {
655 if(!svp->segs[t].n_points) {
656 msg("<error> svp contains segment with zero points\n");
659 num_points += svp->segs[t].n_points;
660 num_segs += svp->segs[t].n_points - 1;
663 /* create segs and ys */
664 double*y = malloc(sizeof(double)*num_points);
665 svp_segment_part_t*segs = malloc(sizeof(svp_segment_part_t)*num_segs);
666 svp_segment_part_t**seg_start = malloc(sizeof(svp_segment_part_t*)*num_segs);
667 svp_segment_part_t**seg_end = malloc(sizeof(svp_segment_part_t*)*num_segs);
671 for(t=0;t<svp->n_segs;t++) {
672 ArtSVPSeg* seg = &svp->segs[t];
674 for(p=0;p<seg->n_points;p++) {
675 y[c1++] = seg->points[p].y;
676 assert(c1 <= num_points);
678 for(p=0;p<seg->n_points-1;p++) {
679 ArtPoint* p1 = &seg->points[p];
680 ArtPoint* p2 = &seg->points[p+1];
684 msg("<error> bad svp, y in seg is non-increasing %.16f -> %.16f\n", p1->y, p2->y);
687 segs[num_segs].y1 = p1->y;
688 segs[num_segs].y2 = p2->y;
689 segs[num_segs].active = 0;
690 seg_start[num_segs] = &segs[num_segs];
691 seg_end[num_segs] = &segs[num_segs];
697 qsort(y, num_points, sizeof(double), compare_double);
698 qsort(seg_start, num_segs, sizeof(svp_segment_part_t*), compare_seg_start);
699 qsort(seg_end, num_segs, sizeof(svp_segment_part_t*), compare_seg_end);
701 double lasty = num_points?y[0]+1:0;
704 double bleedy1=0,bleedy2 = 0;
705 for(t=0;t<num_points;t++) {
709 for(s=0;s<num_segs;s++) {
710 if(segs[s].y1==y[t]) {
711 /* segment is starting */
714 } else if(segs[s].y2==y[t]) {
731 msg("<verbose> svp bleeds from y=%.16f to y=%.16f (%d/%d active segments)\n",
734 free(y);free(segs);free(seg_start);free(seg_end);
746 void write_svp_postscript(const char*filename, ArtSVP*svp)
750 FILE*fi = fopen(filename, "wb");
752 double xmin=0,ymin=0,xmax=0,ymax=0;
753 fprintf(fi, "%% begin\n");
754 for (i = 0; i < svp->n_segs; i++) {
755 for (j = 0; j < svp->segs[i].n_points; j++) {
756 double x = svp->segs[i].points[j].x;
757 double y = svp->segs[i].points[j].y;
762 if(x < xmin) xmin = x;
763 if(x > xmax) xmax = x;
764 if(y < ymin) ymin = y;
765 if(y > ymax) ymax = y;
769 if(xmax == xmin) xmax=xmin+1;
770 if(ymax == ymin) ymax=ymin+1;
772 for (i = 0; i < svp->n_segs; i++)
774 fprintf(fi, "%g setgray\n", svp->segs[i].dir ? 0.7 : 0);
775 for (j = 0; j < svp->segs[i].n_points; j++)
777 //fprintf(fi, "%g %g %s\n",
778 // 20 + 550*(svp->segs[i].points[j].x-xmin)/(xmax-xmin),
779 // 820 - 800*(svp->segs[i].points[j].y-ymin)/(ymax-ymin),
780 // j ? "lineto" : "moveto");
781 fprintf(fi, "%.32f %.32f %s\n",
782 svp->segs[i].points[j].x,
783 svp->segs[i].points[j].y,
784 j ? "lineto" : "moveto");
786 fprintf(fi, "stroke\n");
789 fprintf(fi, "showpage\n");
793 void write_vpath_postscript(const char*filename, ArtVpath*path)
795 FILE*fi = fopen(filename, "wb");
797 double xmin=0,ymin=0,xmax=0,ymax=0;
798 fprintf(fi, "%% begin\n");
801 while(p->code != ART_END) {
802 if(p->code == ART_MOVETO || p->code == ART_MOVETO_OPEN) {
804 fprintf(fi, "stroke\n");
806 fprintf(fi, "0.0 setgray\n");
807 fprintf(fi, "%.32f %.32f moveto\n", p->x, p->y);
809 fprintf(fi, "%.32f %.32f lineto\n", p->x, p->y);
814 fprintf(fi, "stroke\n");
815 fprintf(fi, "showpage\n");
819 void write_gfxline_postscript(const char*filename, gfxline_t*line)
821 FILE*fi = fopen(filename, "wb");
823 fprintf(fi, "%% begin\n");
826 if(line->type == gfx_moveTo) {
828 fprintf(fi, "stroke\n");
830 fprintf(fi, "0.0 setgray\n");
831 fprintf(fi, "%.32f %.32f moveto\n", line->x, line->y);
833 fprintf(fi, "%.32f %.32f lineto\n", line->x, line->y);
838 fprintf(fi, "stroke\n");
839 fprintf(fi, "showpage\n");
843 static int vpath_len(ArtVpath*svp)
846 while(svp->code != ART_END) {
853 int gfxline_len(gfxline_t*line)
864 static ArtVpath*pvpath= 0;
865 static int cmppos(const void*_p1, const void*_p2)
869 ArtVpath*v1 = &pvpath[*p1];
870 ArtVpath*v2 = &pvpath[*p2];
873 else if(v1->y > v2->y)
875 else if(v1->x < v2->x)
877 else if(v1->x > v2->x)
883 #define PERTURBATION 2e-3
884 static void my_perturb(ArtVpath*vpath)
887 int len = vpath_len(vpath);
888 int*pos = (int*)malloc(len*sizeof(int));
892 qsort(pos, len, sizeof(int), cmppos);
896 while(t2<len && !cmppos(&pos[t],&pos[t2])) {
900 double dx = (PERTURBATION * rand ()) / RAND_MAX - PERTURBATION * 0.5;
901 double dy = (PERTURBATION * rand ()) / RAND_MAX - PERTURBATION * 0.5;
904 vpath[pos[s]].x += dx;
905 vpath[pos[s]].y += dy;
913 static ArtSVP* gfxfillToSVP(gfxline_t*line, int perturb)
915 ArtVpath* vec = gfxline_to_ArtVpath(line, 1);
916 msg("<verbose> Casting gfxline of %d segments (%d line segments) to a gfxpoly", gfxline_len(line), vpath_len(vec));
919 //ArtVpath* vec2 = art_vpath_perturb(vec);
924 ArtSVP *svp = art_svp_from_vpath(vec);
931 // double shear = find_shear_value(svp);
932 // gfxline_t*line = gfxpoly_to_gfxline((gfxpoly_t*)svp);
933 // gfxline_t*l = line;
935 // l->y += l->x*shear;
936 // l->sy += l->sx*shear;
939 // svp = (ArtSVP*)gfxpoly_fillToPoly(line);
940 // printf("shearing svp by %.16f\n", shear);
944 // art_svp_free(svp);
945 // shear_svp(result, -shear);
949 ArtSVP* run_intersector(ArtSVP*svp, ArtWindRule rule)
951 ArtSvpWriter * swr = art_svp_writer_rewind_new(rule);
954 intbbox_t bbox = get_svp_bbox(svp, zoom);
956 art_svp_intersector(svp, swr);
957 ArtSVP*result = art_svp_writer_rewind_reap(swr);
959 if(!check_svp(result)) {
960 current_svp = result;
961 art_report_error(); // might set art_error_in_intersector
963 msg("<verbose> Comparing polygon renderings of size %dx%d and %dx%d", bbox.width, bbox.height, bbox.width, bbox.height);
964 unsigned char*data1 = render_svp(svp, &bbox, zoom, rule);
965 unsigned char*data2 = render_svp(result, &bbox, zoom, ART_WIND_RULE_ODDEVEN);
966 if(!compare_bitmaps(&bbox, data1, data2)) {
967 msg("<verbose> Bad SVP rewinding result- polygons don't match");
968 current_svp = result;
969 art_report_error(); // might set art_error_in_intersector
975 if(art_error_in_intersector) {
976 msg("<verbose> Error in polygon processing");
977 art_svp_free(result);
978 art_error_in_intersector=0;
984 gfxline_t* gfxpoly_to_gfxline(gfxpoly_t*poly)
986 ArtSVP*svp = (ArtSVP*)poly;
991 msg("<verbose> Casting polygon of %d segments back to gfxline", svp->n_segs);
993 for(t=0;t<svp->n_segs;t++) {
994 size += svp->segs[t].n_points;
997 gfxline_t* lines = (gfxline_t*)rfx_alloc(sizeof(gfxline_t)*size);
999 for(t=0;t<svp->n_segs;t++) {
1000 ArtSVPSeg* seg = &svp->segs[t];
1002 for(p=0;p<seg->n_points;p++) {
1003 lines[pos].type = p==0?gfx_moveTo:gfx_lineTo;
1004 ArtPoint* point = &seg->points[p];
1005 lines[pos].x = point->x;
1006 lines[pos].y = point->y;
1007 lines[pos].next = &lines[pos+1];
1012 lines[pos-1].next = 0;
1019 gfxpoly_t* gfxpoly_fillToPoly(gfxline_t*line)
1021 /* I'm not sure whether doing perturbation here is actually
1022 a good idea- if that line has been run through the machinery
1023 several times already, it might be safer to leave it alone,
1024 since it should already be in a format libart can handle */
1026 ArtSVP* svp = gfxfillToSVP(line, 1);
1028 ArtSVP* svp = gfxfillToSVP(line, 0);
1033 static int counter = 0;
1034 sprintf(filename, "svp%d.ps", counter);
1035 write_svp_postscript(filename, svp);
1036 sprintf(filename, "gfxline%d.ps", counter);
1037 write_gfxline_postscript(filename, line);
1040 /* we do xor-filling by default, so dir is always 1
1041 (actually for oddeven rewinding it makes no difference, but
1045 for(t=0; t<svp->n_segs; t++) {
1046 svp->segs[t].dir = 1;
1049 /* for some reason, we need to rewind / self-intersect the polygons that gfxfillToSVP
1050 returns- art probably uses a different fill mode (circular?) for vpaths */
1051 ArtSVP*svp_uncrossed=0;
1054 sprintf(filename, "svp%d_in.ps", counter);
1055 write_svp_postscript(filename, svp);
1059 svp_uncrossed = run_intersector(svp, ART_WIND_RULE_ODDEVEN);
1064 return (gfxpoly_t*)svp;
1067 gfxpoly_t* gfxpoly_intersect(gfxpoly_t*poly1, gfxpoly_t*poly2)
1071 static int counter = 0;
1073 ArtSVP* svp1 = (ArtSVP*)poly1;
1074 ArtSVP* svp2 = (ArtSVP*)poly2;
1075 msg("<verbose> Intersecting two polygons of %d and %d segments", svp1->n_segs, svp2->n_segs);
1079 sprintf(filename, "isvp%d_src1.ps", counter);
1080 write_svp_postscript(filename, svp1);
1081 sprintf(filename, "isvp%d_src2.ps", counter);
1082 write_svp_postscript(filename, svp2);
1085 ArtSVP* svp3 = art_svp_merge (svp1, svp2);
1088 sprintf(filename, "isvp%d_src.ps", counter);
1089 write_svp_postscript(filename, svp3);
1092 //write_svp_postscript("svp.ps", svp3);
1093 ArtSVP*svp_new = run_intersector(svp3, ART_WIND_RULE_INTERSECT);
1095 art_free (svp3); /* shallow free because svp3 contains shared segments */
1098 sprintf(filename, "isvp%d.ps", counter);
1099 write_svp_postscript(filename, svp_new);
1104 //write_svp_postscript("svp_new.ps", svp_new);
1106 return (gfxpoly_t*)svp_new;
1109 gfxpoly_t* gfxpoly_union(gfxpoly_t*poly1, gfxpoly_t*poly2)
1111 ArtSVP* svp1 = (ArtSVP*)poly1;
1112 ArtSVP* svp2 = (ArtSVP*)poly2;
1113 msg("<verbose> Unifying two polygons of %d and %d segments", svp1->n_segs, svp2->n_segs);
1115 ArtSVP* svp = art_svp_union(svp1, svp2);
1116 return (gfxpoly_t*)svp;
1119 gfxpoly_t* gfxpoly_strokeToPoly(gfxline_t*line, gfxcoord_t width, gfx_capType cap_style, gfx_joinType joint_style, double miterLimit)
1121 ArtVpath* vec = gfxline_to_ArtVpath(line, 0);
1122 msg("<verbose> Casting gfxline of %d segments to a stroke-polygon", gfxline_len(line));
1124 ArtVpath* vec2 = art_vpath_perturb(vec);
1128 ArtSVP *svp = art_svp_vpath_stroke (vec,
1129 (joint_style==gfx_joinMiter)?ART_PATH_STROKE_JOIN_MITER:
1130 ((joint_style==gfx_joinRound)?ART_PATH_STROKE_JOIN_ROUND:
1131 ((joint_style==gfx_joinBevel)?ART_PATH_STROKE_JOIN_BEVEL:ART_PATH_STROKE_JOIN_BEVEL)),
1132 (cap_style==gfx_capButt)?ART_PATH_STROKE_CAP_BUTT:
1133 ((cap_style==gfx_capRound)?ART_PATH_STROKE_CAP_ROUND:
1134 ((cap_style==gfx_capSquare)?ART_PATH_STROKE_CAP_SQUARE:ART_PATH_STROKE_CAP_SQUARE)),
1136 miterLimit, //miter_limit
1140 return (gfxpoly_t*)svp;
1143 gfxline_t* gfxline_circularToEvenOdd(gfxline_t*line)
1145 msg("<verbose> Converting circular-filled gfxline of %d segments to even-odd filled gfxline", gfxline_len(line));
1146 ArtSVP* svp = gfxfillToSVP(line, 1);
1148 /* TODO: ART_WIND_RULE_POSITIVE means that a shape is visible if
1149 positive and negative line segments add up to something positive.
1150 I *think* that clockwise fill in PDF is defined in a way, however,
1151 that the *last* shape's direction will determine whether something
1153 ArtSVP* svp_rewinded;
1155 svp_rewinded = run_intersector(svp, ART_WIND_RULE_POSITIVE);
1161 gfxline_t* result = gfxpoly_to_gfxline((gfxpoly_t*)svp_rewinded);
1163 art_svp_free(svp_rewinded);
1167 gfxpoly_t* gfxpoly_createbox(double x1, double y1,double x2, double y2)
1169 ArtVpath *vec = art_new (ArtVpath, 5+1);
1170 vec[0].code = ART_MOVETO;
1173 vec[1].code = ART_LINETO;
1176 vec[2].code = ART_LINETO;
1179 vec[3].code = ART_LINETO;
1182 vec[4].code = ART_LINETO;
1185 vec[5].code = ART_END;
1188 ArtSVP *svp = art_svp_from_vpath(vec);
1190 return (gfxpoly_t*)svp;
1193 void gfxpoly_free(gfxpoly_t*poly)
1195 ArtSVP*svp = (ArtSVP*)poly;