4 A generic structure for providing vector drawing.
5 (Helper routines, spline approximation, simple text drawers)
7 Copyright (C) 2003 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 */
29 static char* getToken(const char**p)
33 while(**p && strchr(" ,\t\n\r", **p)) {
37 while(**p && !strchr(" ,\t\n\r", **p)) {
40 result = malloc((*p)-start+1);
41 memcpy(result,start,(*p)-start+1);
42 result[(*p)-start] = 0;
46 void draw_conicTo(drawer_t*draw, FPOINT* c, FPOINT* to)
48 FPOINT* pos = &draw->pos;
50 c1.x = (pos->x + 2 * c->x) / 3;
51 c1.y = (pos->y + 2 * c->y) / 3;
52 c2.x = (2 * c->x + to->x) / 3;
53 c2.y = (2 * c->y + to->y) / 3;
54 draw_cubicTo(draw, &c1,&c2,to);
59 void draw_string(drawer_t*draw, const char*string)
61 const char*p = string;
63 char*token = getToken(&p);
66 if(!strncmp(token, "moveTo", 6)) {
68 to.x = atoi(getToken(&p));
69 to.y = atoi(getToken(&p));
70 draw->moveTo(draw, &to);
72 else if(!strncmp(token, "lineTo", 6)) {
74 to.x = atoi(getToken(&p));
75 to.y = atoi(getToken(&p));
76 draw->lineTo(draw, &to);
78 else if(!strncmp(token, "curveTo", 7) || !strncmp(token, "splineTo", 8)) {
80 mid.x = atoi(getToken(&p));
81 mid.y = atoi(getToken(&p));
82 to.x = atoi(getToken(&p));
83 to.y = atoi(getToken(&p));
84 draw->splineTo(draw, &mid, &to);
86 else if(!strncmp(token, "cubicTo", 5)) {
88 mid1.x = atoi(getToken(&p));
89 mid1.y = atoi(getToken(&p));
90 mid2.x = atoi(getToken(&p));
91 mid2.y = atoi(getToken(&p));
92 to.x = atoi(getToken(&p));
93 to.y = atoi(getToken(&p));
94 draw_cubicTo(draw, &mid1, &mid2, &to);
96 else fprintf(stderr, "drawer: Warning: unknown primitive '%s'", token);
109 struct SPLINEPOINT start;
110 struct SPLINEPOINT control;
111 struct SPLINEPOINT end;
116 struct SPLINEPOINT start;
117 struct SPLINEPOINT control1;
118 struct SPLINEPOINT control2;
119 struct SPLINEPOINT end;
122 static inline struct SPLINEPOINT cspline_getpoint(const struct cspline*s, double t)
124 struct SPLINEPOINT p;
128 double mtmt = mt*(1-t);
129 double mtmtmt = mtmt*(1-t);
130 p.x= s->end.x*ttt + 3*s->control2.x*tt*mt
131 + 3*s->control1.x*t*mtmt + s->start.x*mtmtmt;
132 p.y= s->end.y*ttt + 3*s->control2.y*tt*mt
133 + 3*s->control1.y*t*mtmt + s->start.y*mtmtmt;
136 static struct SPLINEPOINT qspline_getpoint(const struct qspline*s, double t)
138 struct SPLINEPOINT p;
139 p.x= s->end.x*t*t + 2*s->control.x*t*(1-t) + s->start.x*(1-t)*(1-t);
140 p.y= s->end.y*t*t + 2*s->control.y*t*(1-t) + s->start.y*(1-t)*(1-t);
144 static int approximate3(const struct cspline*s, struct qspline*q, int size, double quality2)
146 unsigned int gran = 0;
147 unsigned int istep = 0x80000000;
148 unsigned int istart = 0;
152 while(istart<0x80000000)
154 unsigned int iend = istart + istep;
155 double start = istart/(double)0x80000000;
156 double end = iend/(double)0x80000000;
159 char left = 0,recurse=0;
163 /* create simple approximation: a qspline which run's through the
164 qspline point at 0.5 */
165 test.start = cspline_getpoint(s, start);
166 test.control = cspline_getpoint(s, (start+end)/2);
167 test.end = cspline_getpoint(s, end);
168 /* fix the control point:
169 move it so that the new spline does runs through it */
170 test.control.x = -(test.end.x + test.start.x)/2 + 2*(test.control.x);
171 test.control.y = -(test.end.y + test.start.y)/2 + 2*(test.control.y);
173 /* depending on where we are in the spline, we either try to match
174 the left or right tangent */
178 pos = left?start:end;
180 test.control.x = s->end.x*(3*qpos) + 3*s->control2.x*(2*pos-3*qpos) +
181 3*s->control1.x*(1-4*pos+3*qpos) + s->start.x*(-3+6*pos-3*qpos);
182 test.control.y = s->end.y*(3*qpos) + 3*s->control2.y*(2*pos-3*qpos) +
183 3*s->control1.y*(1-4*pos+3*qpos) + s->start.y*(-3+6*pos-3*qpos);
185 test.control.x *= (end-start)/2;
186 test.control.y *= (end-start)/2;
187 test.control.x += test.start.x;
188 test.control.y += test.start.y;
190 test.control.x *= -(end-start)/2;
191 test.control.y *= -(end-start)/2;
192 test.control.x += test.end.x;
193 test.control.y += test.end.y;
196 /* measure the spline's accurancy, by taking a number of probes */
198 for(t=0;t<probes;t++) {
199 struct SPLINEPOINT qr1,qr2,cr1,cr2;
200 double pos = 0.5/(probes*2)*(t*2+1);
203 qr1 = qspline_getpoint(&test, pos);
204 cr1 = cspline_getpoint(s, start+pos*(end-start));
213 qr2 = qspline_getpoint(&test, (1-pos));
214 cr2 = cspline_getpoint(s, start+(1-pos)*(end-start));
225 if(recurse && istep>1 && size-level > num) {
232 while(!(istart & istep)) {
241 void draw_cubicTo(drawer_t*draw, FPOINT* control1, FPOINT* control2, FPOINT* to)
243 struct qspline q[128];
246 double maxerror = (500-(quality*5)>1?500-(quality*5):1)/20.0;
248 int num = approximate3(&c, q, 128, maxerror*maxerror);
251 c.start.x = draw->pos.x;
252 c.start.y = draw->pos.y;
253 c.control1.x = control1->x;
254 c.control1.y = control1->y;
255 c.control2.x = control2->x;
256 c.control2.y = control2->y;
263 mid.x = q[t].control.x;
264 mid.y = q[t].control.y;
267 draw->splineTo(draw, &mid, &to);