minor bugfixes and speed improvements in polygon intersector
[swftools.git] / lib / gfxpoly / convert.c
1 #include <stdlib.h>
2 #include <math.h>
3 #include <string.h>
4 #include "../gfxdevice.h"
5 #include "../mem.h"
6 #include "poly.h"
7
8 /* factor that determines into how many line fragments a spline is converted */
9 #define SUBFRACTION (2.4)
10
11 static edge_t*edge_new(int x1, int y1, int x2, int y2)
12 {
13     edge_t*s = rfx_calloc(sizeof(edge_t));
14     s->a.x = x1;
15     s->a.y = y1;
16     s->b.x = x2;
17     s->b.y = y2;
18     return s;
19 }
20
21 static inline void gfxpoly_add_edge(gfxpoly_t*poly, double _x1, double _y1, double _x2, double _y2)
22 {
23     /* we clamp to 31 bit instead of 32 bit because we use
24        a (x1-x2) shortcut when comparing coordinates
25     */
26     if(_x1 < -0x40000000) _x1 = -0x40000000;
27     if(_x1 >  0x3fffffff) _x1 =  0x3fffffff;
28     if(_y1 < -0x40000000) _y1 = -0x40000000;
29     if(_y1 >  0x3fffffff) _y1 =  0x3fffffff;
30     if(_x2 < -0x40000000) _x2 = -0x40000000;
31     if(_x2 >  0x3fffffff) _x2 =  0x3fffffff;
32     if(_y2 < -0x40000000) _y2 = -0x40000000;
33     if(_y2 >  0x3fffffff) _y2 =  0x3fffffff;
34
35     int x1 = ceil(_x1);
36     int y1 = ceil(_y1);
37     int x2 = ceil(_x2);
38     int y2 = ceil(_y2);
39
40     if(x1!=x2 || y1!=y2) {
41         edge_t*s = edge_new(x1, y1, x2, y2);
42         s->next = poly->edges;
43         poly->edges = s;
44     }
45 }
46
47 gfxpoly_t* gfxpoly_from_gfxline(gfxline_t*line, double gridsize)
48 {
49     gfxpoly_t*p = gfxpoly_new(gridsize);
50
51     double z = 1.0 / gridsize;
52
53     double lastx=0, lasty=0;
54     assert(!line || line[0].type == gfx_moveTo);
55     while(line) {
56         double x = line->x*z;
57         double y = line->y*z;
58         if(line->type == gfx_moveTo) {
59         } else if(line->type == gfx_lineTo) {
60             gfxpoly_add_edge(p, lastx, lasty, x, y);
61         } else if(line->type == gfx_splineTo) {
62             int parts = (int)(sqrt(fabs(line->x-2*line->sx+lastx) + 
63                                    fabs(line->y-2*line->sy+lasty))*SUBFRACTION);
64             if(!parts) parts = 1;
65             double stepsize = 1.0/parts;
66             int i;
67             for(i=0;i<parts;i++) {
68                 double t = (double)i*stepsize;
69                 double sx = (line->x*t*t + 2*line->sx*t*(1-t) + x*(1-t)*(1-t))*z;
70                 double sy = (line->y*t*t + 2*line->sy*t*(1-t) + y*(1-t)*(1-t))*z;
71                 gfxpoly_add_edge(p, lastx, lasty, sx, sy);
72                 lastx = sx;
73                 lasty = sy;
74             }
75             gfxpoly_add_edge(p, lastx, lasty, x, y);
76         }
77         lastx = x;
78         lasty = y;
79         line = line->next;
80     }
81     
82     gfxline_free(line);
83     return p;
84 }
85
86 typedef struct _gfxstroke {
87     segment_dir_t dir;
88     point_t*stroke;
89     fillstyle_t*fs;
90     int num_points;
91 } gfxstroke_t;
92 typedef struct _gfxcompactpoly {
93     double gridsize;
94     int num_strokes;
95     gfxstroke_t strokes[0];
96 } gfxcompactpoly_t;
97
98 static char* readline(FILE*fi)
99 {
100     char c;
101     while(1) {
102         int l = fread(&c, 1, 1, fi);
103         if(!l)
104             return 0;
105         if(c!=10 || c!=13)
106             break;
107     }
108     char line[256];
109     int pos = 0;
110     while(1) {
111         line[pos++] = c;
112         line[pos] = 0;
113         int l = fread(&c, 1, 1, fi);
114         if(!l || c==10 || c==13) {
115             return strdup(line);
116         }
117     }
118 }
119
120 gfxpoly_t* gfxpoly_from_file(const char*filename, double gridsize)
121 {
122     gfxpoly_t*p = gfxpoly_new(gridsize);
123
124     double z = 1.0 / gridsize;
125
126     FILE*fi = fopen(filename, "rb");
127     if(!fi) {
128         perror(filename);
129         return 0;
130     }
131     int count = 0;
132     double g = 0;
133     double lastx=0,lasty=0;
134     while(1) {
135         char*line = readline(fi);
136         if(!line)
137             break;
138         double x,y;
139         char s[256];
140         if(sscanf(line, "%lf %lf %s", &x, &y, &s) == 3) {
141             x*=z;
142             y*=z;
143             if(s && !strcmp(s,"moveto")) {
144                 count++;
145             } else if(s && !strcmp(s,"lineto")) {
146                 gfxpoly_add_edge(p, lastx, lasty, x, y);
147                 count++;
148             } else {
149                 printf("invalid command: %s\n", s);
150             }
151             lastx = x;
152             lasty = y;
153         } else if(sscanf(line, "%% gridsize %lf", &g) == 1) {
154             p->gridsize = g;
155         }
156         free(line);
157     }
158     fclose(fi);
159     if(g) {
160         printf("loaded %d points from %s (gridsize %f)\n", count, filename, g);
161     } else {
162         printf("loaded %d points from %s\n", count, filename);
163     }
164     return p;
165 }