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 */
30 static char* getToken(const char**p
)
34 while(**p
&& strchr(" ,\t\n\r", **p
)) {
38 while(**p
&& !strchr(" ,\t\n\r", **p
)) {
41 result
= malloc((*p
)-start
+1);
42 memcpy(result
,start
,(*p
)-start
+1);
43 result
[(*p
)-start
] = 0;
47 void draw_conicTo(drawer_t
*draw
, FPOINT
* c
, FPOINT
* to
)
49 FPOINT
* pos
= &draw
->pos
;
51 c1
.x
= (pos
->x
+ 2 * c
->x
) / 3;
52 c1
.y
= (pos
->y
+ 2 * c
->y
) / 3;
53 c2
.x
= (2 * c
->x
+ to
->x
) / 3;
54 c2
.y
= (2 * c
->y
+ to
->y
) / 3;
55 draw_cubicTo(draw
, &c1
,&c2
,to
);
60 void draw_string(drawer_t
*draw
, const char*string
)
62 const char*p
= string
;
64 char*token
= getToken(&p
);
67 if(!strncmp(token
, "moveTo", 6)) {
69 to
.x
= atoi(getToken(&p
));
70 to
.y
= atoi(getToken(&p
));
71 draw
->moveTo(draw
, &to
);
73 else if(!strncmp(token
, "lineTo", 6)) {
75 to
.x
= atoi(getToken(&p
));
76 to
.y
= atoi(getToken(&p
));
77 draw
->lineTo(draw
, &to
);
79 else if(!strncmp(token
, "curveTo", 7) || !strncmp(token
, "splineTo", 8)) {
81 mid
.x
= atoi(getToken(&p
));
82 mid
.y
= atoi(getToken(&p
));
83 to
.x
= atoi(getToken(&p
));
84 to
.y
= atoi(getToken(&p
));
85 draw
->splineTo(draw
, &mid
, &to
);
87 else if(!strncmp(token
, "conicTo", 5)) {
89 mid
.x
= atoi(getToken(&p
));
90 mid
.y
= atoi(getToken(&p
));
91 to
.x
= atoi(getToken(&p
));
92 to
.y
= atoi(getToken(&p
));
93 draw_conicTo(draw
, &mid
, &to
);
95 else if(!strncmp(token
, "cubicTo", 5)) {
97 mid1
.x
= atoi(getToken(&p
));
98 mid1
.y
= atoi(getToken(&p
));
99 mid2
.x
= atoi(getToken(&p
));
100 mid2
.y
= atoi(getToken(&p
));
101 to
.x
= atoi(getToken(&p
));
102 to
.y
= atoi(getToken(&p
));
103 draw_cubicTo(draw
, &mid1
, &mid2
, &to
);
105 else fprintf(stderr
, "drawer: Warning: unknown primitive '%s'\n", token
);
118 struct SPLINEPOINT start
;
119 struct SPLINEPOINT control
;
120 struct SPLINEPOINT end
;
125 struct SPLINEPOINT start
;
126 struct SPLINEPOINT control1
;
127 struct SPLINEPOINT control2
;
128 struct SPLINEPOINT end
;
131 static inline struct SPLINEPOINT
cspline_getpoint(const struct cspline
*s
, double t
)
133 struct SPLINEPOINT p
;
137 double mtmt
= mt
*(1-t
);
138 double mtmtmt
= mtmt
*(1-t
);
139 p
.x
= s
->end
.x
*ttt
+ 3*s
->control2
.x
*tt
*mt
140 + 3*s
->control1
.x
*t
*mtmt
+ s
->start
.x
*mtmtmt
;
141 p
.y
= s
->end
.y
*ttt
+ 3*s
->control2
.y
*tt
*mt
142 + 3*s
->control1
.y
*t
*mtmt
+ s
->start
.y
*mtmtmt
;
145 static struct SPLINEPOINT
qspline_getpoint(const struct qspline
*s
, double t
)
147 struct SPLINEPOINT p
;
148 p
.x
= s
->end
.x
*t
*t
+ 2*s
->control
.x
*t
*(1-t
) + s
->start
.x
*(1-t
)*(1-t
);
149 p
.y
= s
->end
.y
*t
*t
+ 2*s
->control
.y
*t
*(1-t
) + s
->start
.y
*(1-t
)*(1-t
);
153 static int approximate3(const struct cspline
*s
, struct qspline
*q
, int size
, double quality2
)
155 unsigned int gran
= 0;
156 unsigned int istep
= 0x80000000;
157 unsigned int istart
= 0;
161 while(istart
<0x80000000)
163 unsigned int iend
= istart
+ istep
;
164 double start
= istart
/(double)0x80000000;
165 double end
= iend
/(double)0x80000000;
168 char left
= 0,recurse
=0;
172 /* create simple approximation: a qspline which run's through the
173 qspline point at 0.5 */
174 test
.start
= cspline_getpoint(s
, start
);
175 test
.control
= cspline_getpoint(s
, (start
+end
)/2);
176 test
.end
= cspline_getpoint(s
, end
);
177 /* fix the control point:
178 move it so that the new spline does runs through it */
179 test
.control
.x
= -(test
.end
.x
+ test
.start
.x
)/2 + 2*(test
.control
.x
);
180 test
.control
.y
= -(test
.end
.y
+ test
.start
.y
)/2 + 2*(test
.control
.y
);
182 /* depending on where we are in the spline, we either try to match
183 the left or right tangent */
187 pos
= left
?start
:end
;
189 test
.control
.x
= s
->end
.x
*(3*qpos
) + 3*s
->control2
.x
*(2*pos
-3*qpos
) +
190 3*s
->control1
.x
*(1-4*pos
+3*qpos
) + s
->start
.x
*(-3+6*pos
-3*qpos
);
191 test
.control
.y
= s
->end
.y
*(3*qpos
) + 3*s
->control2
.y
*(2*pos
-3*qpos
) +
192 3*s
->control1
.y
*(1-4*pos
+3*qpos
) + s
->start
.y
*(-3+6*pos
-3*qpos
);
194 test
.control
.x
*= (end
-start
)/2;
195 test
.control
.y
*= (end
-start
)/2;
196 test
.control
.x
+= test
.start
.x
;
197 test
.control
.y
+= test
.start
.y
;
199 test
.control
.x
*= -(end
-start
)/2;
200 test
.control
.y
*= -(end
-start
)/2;
201 test
.control
.x
+= test
.end
.x
;
202 test
.control
.y
+= test
.end
.y
;
205 /* measure the spline's accurancy, by taking a number of probes */
207 for(t
=0;t
<probes
;t
++) {
208 struct SPLINEPOINT qr1
,qr2
,cr1
,cr2
;
209 double pos
= 0.5/(probes
*2)*(t
*2+1);
212 qr1
= qspline_getpoint(&test
, pos
);
213 cr1
= cspline_getpoint(s
, start
+pos
*(end
-start
));
222 qr2
= qspline_getpoint(&test
, (1-pos
));
223 cr2
= cspline_getpoint(s
, start
+(1-pos
)*(end
-start
));
234 if(recurse
&& istep
>1 && size
-level
> num
) {
241 while(!(istart
& istep
)) {
250 void draw_cubicTo(drawer_t
*draw
, FPOINT
* control1
, FPOINT
* control2
, FPOINT
* to
)
252 struct qspline q
[128];
255 double maxerror
= (500-(quality
*5)>1?500-(quality
*5):1)/20.0;
258 c
.start
.x
= draw
->pos
.x
;
259 c
.start
.y
= draw
->pos
.y
;
260 c
.control1
.x
= control1
->x
;
261 c
.control1
.y
= control1
->y
;
262 c
.control2
.x
= control2
->x
;
263 c
.control2
.y
= control2
->y
;
267 num
= approximate3(&c
, q
, 128, maxerror
*maxerror
);
272 mid
.x
= q
[t
].control
.x
;
273 mid
.y
= q
[t
].control
.y
;
276 draw
->splineTo(draw
, &mid
, &to
);