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
.ymax
) 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 static int compare_bitmaps(intbbox_t
*bbox
, unsigned char*data1
, unsigned char*data2
)
304 int height
= bbox
->height
;
305 int width
= bbox
->width
;
306 int width8
= (width
+7) >> 3;
307 unsigned char*l1
= &data1
[width8
];
308 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
)) return 0;
315 if((a
&B01110000
) && !(l2
[x
]&B00100000
)) return 0;
316 if((a
&B00111000
) && !(l2
[x
]&B00010000
)) return 0;
317 if((a
&B00011100
) && !(l2
[x
]&B00001000
)) return 0;
318 if((a
&B00001110
) && !(l2
[x
]&B00000100
)) return 0;
319 if((a
&B00000111
) && !(l2
[x
]&B00000010
)) return 0;
321 if((b
&B11100000
) && !(l1
[x
]&B01000000
)) return 0;
322 if((b
&B01110000
) && !(l1
[x
]&B00100000
)) return 0;
323 if((b
&B00111000
) && !(l1
[x
]&B00010000
)) return 0;
324 if((b
&B00011100
) && !(l1
[x
]&B00001000
)) return 0;
325 if((b
&B00001110
) && !(l1
[x
]&B00000100
)) return 0;
326 if((b
&B00000111
) && !(l1
[x
]&B00000010
)) return 0;
335 //-----------------------------------------------------------------------------------------------
337 static ArtVpath
* gfxline_to_ArtVpath(gfxline_t
*line
, char fill
)
339 ArtVpath
*vec
= NULL
;
344 /* factor which determines into how many line fragments a spline is converted */
345 double subfraction
= 2.4;//0.3
349 if(l2
->type
== gfx_moveTo
) {
351 } else if(l2
->type
== gfx_lineTo
) {
353 } else if(l2
->type
== gfx_splineTo
) {
354 int parts
= (int)(sqrt(fabs(l2
->x
-2*l2
->sx
+x
) + fabs(l2
->y
-2*l2
->sy
+y
))*subfraction
);
355 if(!parts
) parts
= 1;
365 vec
= art_new (ArtVpath
, len
+1);
371 if(l2
->type
== gfx_moveTo
) {
372 vec
[pos
].code
= ART_MOVETO_OPEN
;
378 } else if(l2
->type
== gfx_lineTo
) {
379 vec
[pos
].code
= ART_LINETO
;
384 } else if(l2
->type
== gfx_splineTo
) {
386 int parts
= (int)(sqrt(fabs(l2
->x
-2*l2
->sx
+x
) + fabs(l2
->y
-2*l2
->sy
+y
))*subfraction
);
387 if(!parts
) parts
= 1;
388 double stepsize
= 1.0/parts
;
389 for(i
=0;i
<=parts
;i
++) {
390 double t
= (double)i
*stepsize
;
391 vec
[pos
].code
= ART_LINETO
;
392 vec
[pos
].x
= l2
->x
*t
*t
+ 2*l2
->sx
*t
*(1-t
) + x
*(1-t
)*(1-t
);
393 vec
[pos
].y
= l2
->y
*t
*t
+ 2*l2
->sy
*t
*(1-t
) + y
*(1-t
)*(1-t
);
401 /* let closed line segments start w/ MOVETO instead of MOVETO_OPEN */
402 if(lastmove
>=0 && l2
->type
!=gfx_moveTo
&& (!l2
->next
|| l2
->next
->type
== gfx_moveTo
)) {
403 if(vec
[lastmove
].x
== l2
->x
&&
404 vec
[lastmove
].y
== l2
->y
) {
405 assert(vec
[lastmove
].code
== ART_MOVETO_OPEN
);
406 vec
[lastmove
].code
= ART_MOVETO
;
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 one 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) {
527 v
= lrand48() / 2000000000.0;;
529 v
= rand() / 2000000000.0;
531 #error "no lrand48()/rand() implementation found"
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 = gfxline_from_gfxpoly((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
* gfxline_from_gfxpoly(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_from_fill(gfxline_t
*line
, double gridsize
)
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_from_stroke(gfxline_t
*line
, gfxcoord_t width
, gfx_capType cap_style
, gfx_joinType joint_style
, double miterLimit
, double gridsize
)
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
* gfxpoly_circular_to_evenodd(gfxline_t
*line
, double gridsize
)
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 ArtSVP
* svp_rewinded
;
1132 svp_rewinded
= run_intersector(svp
, ART_WIND_RULE_NONZERO
);
1138 gfxline_t
* result
= gfxline_from_gfxpoly((gfxpoly_t
*)svp_rewinded
);
1140 art_svp_free(svp_rewinded
);
1144 gfxpoly_t
* gfxpoly_createbox(double x1
, double y1
,double x2
, double y2
, double gridsize
)
1146 ArtVpath
*vec
= art_new (ArtVpath
, 5+1);
1147 vec
[0].code
= ART_MOVETO
;
1150 vec
[1].code
= ART_LINETO
;
1153 vec
[2].code
= ART_LINETO
;
1156 vec
[3].code
= ART_LINETO
;
1159 vec
[4].code
= ART_LINETO
;
1162 vec
[5].code
= ART_END
;
1165 ArtSVP
*svp
= art_svp_from_vpath(vec
);
1167 return (gfxpoly_t
*)svp
;
1170 void gfxpoly_destroy(gfxpoly_t
*poly
)
1172 ArtSVP
*svp
= (ArtSVP
*)poly
;