polygon intersector: performance improvements and bugfixes
[swftools.git] / lib / gfxpoly / convert.c
1 #include <stdlib.h>
2 #include <math.h>
3 #include <assert.h>
4 #include <string.h>
5 #include "../gfxdevice.h"
6 #include "../mem.h"
7 #include "poly.h"
8
9 static edge_t*edge_new(int x1, int y1, int x2, int y2)
10 {
11     edge_t*s = rfx_calloc(sizeof(edge_t));
12     s->a.x = x1;
13     s->a.y = y1;
14     s->b.x = x2;
15     s->b.y = y2;
16     return s;
17 }
18
19 static inline void gfxpoly_add_edge(gfxpoly_t*poly, double _x1, double _y1, double _x2, double _y2)
20 {
21     int x1 = ceil(_x1);
22     int y1 = ceil(_y1);
23     int x2 = ceil(_x2);
24     int y2 = ceil(_y2);
25     if(x1!=x2 || y1!=y2) {
26         edge_t*s = edge_new(x1, y1, x2, y2);
27         s->next = poly->edges;
28         poly->edges = s;
29     }
30 }
31
32 gfxpoly_t* gfxpoly_from_gfxline(gfxline_t*line, double gridsize)
33 {
34     gfxpoly_t*p = gfxpoly_new(gridsize);
35
36     /* factor that determines into how many line fragments a spline is converted */
37     double subfraction = 2.4;//0.3
38
39     double z = 1.0 / gridsize;
40
41     double lastx=0, lasty=0;
42     assert(!line || line[0].type == gfx_moveTo);
43     while(line) {
44         double x = line->x*z;
45         double y = line->y*z;
46         if(line->type == gfx_moveTo) {
47         } else if(line->type == gfx_lineTo) {
48             gfxpoly_add_edge(p, lastx, lasty, x, y);
49         } else if(line->type == gfx_splineTo) {
50             int parts = (int)(sqrt(fabs(line->x-2*line->sx+lastx) + 
51                                    fabs(line->y-2*line->sy+lasty))*subfraction);
52             if(!parts) parts = 1;
53             double stepsize = 1.0/parts;
54             int i;
55             for(i=0;i<parts;i++) {
56                 double t = (double)i*stepsize;
57                 double sx = (line->x*t*t + 2*line->sx*t*(1-t) + x*(1-t)*(1-t))*z;
58                 double sy = (line->y*t*t + 2*line->sy*t*(1-t) + y*(1-t)*(1-t))*z;
59                 gfxpoly_add_edge(p, lastx, lasty, sx, sy);
60                 lastx = sx;
61                 lasty = sy;
62             }
63             gfxpoly_add_edge(p, lastx, lasty, x, y);
64         }
65         lastx = x;
66         lasty = y;
67         line = line->next;
68     }
69
70     gfxline_free(line);
71     return p;
72 }
73
74 static char* readline(FILE*fi)
75 {
76     char c;
77     while(1) {
78         int l = fread(&c, 1, 1, fi);
79         if(!l)
80             return 0;
81         if(c!=10 || c!=13)
82             break;
83     }
84     char line[256];
85     int pos = 0;
86     while(1) {
87         line[pos++] = c;
88         line[pos] = 0;
89         int l = fread(&c, 1, 1, fi);
90         if(!l || c==10 || c==13) {
91             return strdup(line);
92         }
93     }
94 }
95
96 gfxpoly_t* gfxpoly_from_file(const char*filename, double gridsize)
97 {
98     gfxpoly_t*p = gfxpoly_new(gridsize);
99
100     double z = 1.0 / gridsize;
101
102     FILE*fi = fopen(filename, "rb");
103     if(!fi) {
104         perror(filename);
105         return 0;
106     }
107     int count = 0;
108     double lastx=0,lasty=0;
109     while(1) {
110         char*line = readline(fi);
111         if(!line)
112             break;
113         double x,y;
114         char s[256];
115         if(sscanf(line, "%lf %lf %s", &x, &y, &s) == 3) {
116             x*=z;
117             y*=z;
118             if(s && !strcmp(s,"moveto")) {
119                 count++;
120             } else if(s && !strcmp(s,"lineto")) {
121                 gfxpoly_add_edge(p, lastx, lasty, x, y);
122                 count++;
123             } else {
124                 printf("invalid command: %s\n", s);
125             }
126             lastx = x;
127             lasty = y;
128         }
129         free(line);
130     }
131     fclose(fi);
132     printf("loaded %d points from %s\n", count, filename);
133     return p;
134 }