3 Various utility functions for dealing with gfxdevices.
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 */
32 typedef struct _linedraw_internal
36 } linedraw_internal_t
;
38 static void linedraw_moveTo(gfxdrawer_t
*d
, gfxcoord_t x
, gfxcoord_t y
)
40 linedraw_internal_t
*i
= (linedraw_internal_t
*)d
->internal
;
41 gfxline_t
*l
= (gfxline_t
*)rfx_alloc(sizeof(gfxline_t
));
43 if((int)((d
->x
* 5120) == (int)(x
* 5120)) &&
44 (int)((d
->y
* 5120) == (int)(y
* 5120))) {
45 /* never mind- we're already there */
59 static void linedraw_lineTo(gfxdrawer_t
*d
, gfxcoord_t x
, gfxcoord_t y
)
61 linedraw_internal_t
*i
= (linedraw_internal_t
*)d
->internal
;
62 gfxline_t
*l
= (gfxline_t
*)rfx_alloc(sizeof(gfxline_t
));
65 /* starts with a line, not with a moveto. That needs we first
66 need an explicit moveto to (0,0) */
67 linedraw_moveTo(d
, 0, 0);
81 static void linedraw_splineTo(gfxdrawer_t
*d
, gfxcoord_t sx
, gfxcoord_t sy
, gfxcoord_t x
, gfxcoord_t y
)
83 linedraw_internal_t
*i
= (linedraw_internal_t
*)d
->internal
;
84 gfxline_t
*l
= (gfxline_t
*)rfx_alloc(sizeof(gfxline_t
));
87 /* starts with a line, not with a moveto. That needs we first
88 need an explicit moveto to (0,0) */
89 linedraw_moveTo(d
, 0, 0);
92 l
->type
= gfx_splineTo
;
104 static void* linedraw_result(gfxdrawer_t
*d
)
106 linedraw_internal_t
*i
= (linedraw_internal_t
*)d
->internal
;
107 void*result
= (void*)i
->start
;
109 memset(d
, 0, sizeof(gfxdrawer_t
));
113 void gfxdrawer_target_gfxline(gfxdrawer_t
*d
)
115 linedraw_internal_t
*i
= (linedraw_internal_t
*)rfx_calloc(sizeof(linedraw_internal_t
));
119 d
->moveTo
= linedraw_moveTo
;
120 d
->lineTo
= linedraw_lineTo
;
121 d
->splineTo
= linedraw_splineTo
;
122 d
->result
= linedraw_result
;
125 typedef struct _qspline_abc
131 typedef struct qspline_t
138 typedef struct cspline_t
146 static void mkspline(qspline_abc_t
*s
, double x
, double y
, gfxline_t
*l
)
149 Form 1: x = t*t*l->x + 2*t*(1-t)*l->sx + (1-t)*(1-t)*x;
150 Form 2: x = a*t*t + b*t + c
152 s
->cx
= x
; s
->bx
= 2*l
->sx
- 2*x
; s
->ax
= l
->x
- 2*l
->sx
+ x
;
153 s
->cy
= y
; s
->by
= 2*l
->sy
- 2*y
; s
->ay
= l
->y
- 2*l
->sy
+ y
;
156 static void spline_get_controlpoint(qspline_abc_t
*q
, double t1
, double t2
, double*dx
, double*dy
)
159 double nax
= q
->ax
*dt
*dt
;
160 double nay
= q
->ay
*dt
*dt
;
161 double nbx
= 2*q
->ax
*dt
*t1
+ q
->bx
*dt
;
162 double nby
= 2*q
->ay
*dt
*t1
+ q
->by
*dt
;
163 double ncx
= q
->ax
*t1
*t1
+ q
->bx
*t1
+ q
->cx
;
164 double ncy
= q
->ay
*t1
*t1
+ q
->by
*t1
+ q
->cy
;
169 static double get_spline_len(qspline_abc_t
*s
)
171 int parts
= (int)(sqrt(fabs(s
->ax
) + fabs(s
->ay
))*3);
176 if(parts
< 3) parts
= 3;
178 r2
= 1.0/(parts
*parts
);
181 double dx
= s
->ax
*(2*i
+1)*r2
+ s
->bx
*r
;
182 double dy
= s
->ay
*(2*i
+1)*r2
+ s
->by
*r
;
183 len
+= sqrt(dx
*dx
+dy
*dy
);
185 /*printf("Spline from %f,%f to %f,%f has len %f (%f)\n", s->cx, s->cy,
186 s->cx + s->bx + s->ax,
187 s->cy + s->by + s->ay, len,
188 sqrt((s->bx + s->ax)*(s->bx + s->ax) + (s->by + s->ay)*(s->by + s->ay))
190 assert(len+0.5 >= sqrt((s->bx + s->ax)*(s->bx + s->ax) + (s->by + s->ay)*(s->by + s->ay)));
195 void gfxtool_draw_dashed_line(gfxdrawer_t
*d
, gfxline_t
*line
, float*r
, float phase
)
198 double linepos
,nextpos
;
202 if(line
&& line
->type
!= gfx_moveTo
) {
203 fprintf(stderr
, "gfxtool: outline doesn't start with a moveTo");
209 for(i
=0;r
[i
]>=0;i
++) {
212 if(!r
|| (r
[0]<=0 && r
[0]>-0.01) || dashlen
<0.001) {
213 // no dashing. just draw the thing
215 if(line
->type
== gfx_moveTo
) {
216 d
->moveTo(d
, line
->x
, line
->y
);
217 } else if(line
->type
== gfx_lineTo
) {
218 d
->lineTo(d
, line
->x
, line
->y
);
219 } else if(line
->type
== gfx_splineTo
) {
220 d
->splineTo(d
, line
->sx
, line
->sy
, line
->x
, line
->y
);
226 if(r
[0]<0 || phase
<0) {
227 fprintf(stderr
, "gfxtool: invalid (negative) dashes: %f, phase=%f", r
[0], phase
);
231 for(;line
;line
=line
->next
) {
232 if(line
->type
== gfx_moveTo
) {
233 d
->moveTo(d
, line
->x
, line
->y
);
234 on
= 1; nextpos
= r
[0]; apos
= 0; linepos
= 0;
235 x
= line
->x
; y
= line
->y
;
236 while(linepos
< phase
) {
237 //printf("[+] linepos: %f, phase: %f, on:%d, apos:%d nextpos:%f\n", linepos, phase, on, apos, nextpos);
239 if(linepos
< phase
) {
247 //printf("[k] linepos: %f, phase: %f, on:%d, apos:%d nextpos:%f \n", linepos, phase, on, apos, nextpos);
248 } else if(line
->type
== gfx_lineTo
) {
249 double dx
= line
->x
- x
;
250 double dy
= line
->y
- y
;
251 double len
= sqrt(dx
*dx
+dy
*dy
);
254 double lineend
= linepos
+len
;
259 assert(nextpos
>=linepos
);
260 //printf("(line) on:%d apos: %d nextpos: %f, line pos: %f, line end: %f\n", on, apos, nextpos, linepos, linepos+len);
261 while(nextpos
<lineend
) {
262 double nx
= x
+ vx
*(nextpos
-linepos
);
263 double ny
= y
+ vy
*(nextpos
-linepos
);
264 if(on
) {d
->lineTo(d
, nx
,ny
);/*printf("lineTo %f\n", nextpos);*/}
265 else {d
->moveTo(d
, nx
,ny
);/*printf("moveTo %f\n", nextpos);*/}
273 //printf("lineTo %f\n", 1.0);
274 d
->lineTo(d
, line
->x
,line
->y
);
276 x
= line
->x
; y
= line
->y
;
277 } else if(line
->type
== gfx_splineTo
) {
279 double len
, lineend
,lastt
;
280 mkspline(&q
, x
, y
, line
);
282 len
= get_spline_len(&q
);
283 //printf("%f %f -> %f %f, len: %f\n", x, y, line->x, line->y, len);
286 lineend
= linepos
+len
;
289 printf("%f !< %f\n", nextpos
, linepos
);
290 assert(nextpos
>=linepos
);
291 //printf("(spline) on:%d apos: %d nextpos: %f, line pos: %f, line end: %f\n", on, apos, nextpos, linepos, linepos+len);
292 while(nextpos
<lineend
) {
293 double t
= (nextpos
-linepos
)/len
;
294 //printf("%f (%f-%f) apos=%d r[apos]=%f\n", t, nextpos, linepos, apos, r[apos]);
295 double nx
= q
.ax
*t
*t
+q
.bx
*t
+q
.cx
;
296 double ny
= q
.ay
*t
*t
+q
.by
*t
+q
.cy
;
299 spline_get_controlpoint(&q
, lastt
, t
, &sx
, &sy
);
300 d
->splineTo(d
, sx
, sy
, nx
,ny
);
301 //printf("splineTo %f\n", nextpos);
304 //printf("moveTo %f\n", nextpos);
315 spline_get_controlpoint(&q
, lastt
, 1, &sx
, &sy
);
316 d
->splineTo(d
, sx
, sy
, line
->x
,line
->y
);
317 //printf("splineTo %f\n", 1.0);
319 x
= line
->x
; y
= line
->y
;
324 gfxline_t
* gfxline_clone(gfxline_t
*line
)
329 gfxline_t
*n
= (gfxline_t
*)rfx_calloc(sizeof(gfxline_t
));
343 static char splineIsStraight(double x
, double y
, gfxline_t
*l
)
345 if(l
->type
== gfx_moveTo
)
347 if(l
->type
== gfx_lineTo
)
353 if(fabs(dx
*sy
- dy
*sx
) < 0.000001 && (dx
*sx
+ dy
*sy
) >= 0) {
359 void gfxline_optimize(gfxline_t
*line
)
362 /* step 1: convert splines to lines, where possible */
365 if(l
->type
== gfx_splineTo
&& splineIsStraight(x
,y
,l
)) {
366 l
->type
= gfx_lineTo
;
372 /* step 2: combine adjacent lines and splines, where possible */
374 while(l
&& l
->next
) {
375 gfxline_t
*next
= l
->next
;
378 if(l
->type
== gfx_lineTo
&& next
->type
== gfx_lineTo
) {
381 double nx
= next
->x
-l
->x
;
382 double ny
= next
->y
-l
->y
;
383 if(fabs(dx
*ny
- dy
*nx
) < 0.000001 && (dx
*nx
+ dy
*ny
) >= 0) {
386 } else if(l
->type
== gfx_splineTo
&& next
->type
== gfx_splineTo
) {
390 l
->next
= next
->next
;
405 gfxline_t
* gfxtool_dash_line(gfxline_t
*line
, float*dashes
, float phase
)
409 gfxdrawer_target_gfxline(&d
);
410 gfxtool_draw_dashed_line(&d
, line
, dashes
, phase
);
411 result
= (gfxline_t
*)d
.result(&d
);
415 void gfxline_show(gfxline_t
*l
, FILE*fi
)
418 if(l
->type
== gfx_moveTo
) {
419 fprintf(fi
, "moveTo %.2f,%.2f\n", l
->x
, l
->y
);
421 if(l
->type
== gfx_lineTo
) {
422 fprintf(fi
, "lineTo %.2f,%.2f\n", l
->x
, l
->y
);
424 if(l
->type
== gfx_splineTo
) {
425 fprintf(fi
, "splineTo %.2f,%.2f %.2f,%.2f\n", l
->sx
, l
->sy
, l
->x
, l
->y
);
431 void gfxline_free(gfxline_t
*l
)
433 if(l
&& (l
+1) == l
->next
) {
447 static inline gfxpoint_t
cspline_getpoint(const struct cspline_t
*s
, double t
)
453 double mtmt
= mt
*(1-t
);
454 double mtmtmt
= mtmt
*(1-t
);
455 p
.x
= s
->end
.x
*ttt
+ 3*s
->control2
.x
*tt
*mt
456 + 3*s
->control1
.x
*t
*mtmt
+ s
->start
.x
*mtmtmt
;
457 p
.y
= s
->end
.y
*ttt
+ 3*s
->control2
.y
*tt
*mt
458 + 3*s
->control1
.y
*t
*mtmt
+ s
->start
.y
*mtmtmt
;
461 static gfxpoint_t
qspline_getpoint(const qspline_t
*s
, double t
)
464 p
.x
= s
->end
.x
*t
*t
+ 2*s
->control
.x
*t
*(1-t
) + s
->start
.x
*(1-t
)*(1-t
);
465 p
.y
= s
->end
.y
*t
*t
+ 2*s
->control
.y
*t
*(1-t
) + s
->start
.y
*(1-t
)*(1-t
);
469 static int approximate3(const cspline_t
*s
, qspline_t
*q
, int size
, double quality2
)
471 unsigned int gran
= 0;
472 unsigned int istep
= 0x80000000;
473 unsigned int istart
= 0;
477 while(istart
<0x80000000)
479 unsigned int iend
= istart
+ istep
;
480 double start
= istart
/(double)0x80000000;
481 double end
= iend
/(double)0x80000000;
484 char left
= 0,recurse
=0;
489 /* create simple approximation: a qspline_t which run's through the
490 qspline_t point at 0.5 */
491 test
.start
= cspline_getpoint(s
, start
);
492 test
.control
= cspline_getpoint(s
, (start
+end
)/2);
493 test
.end
= cspline_getpoint(s
, end
);
494 /* fix the control point:
495 move it so that the new spline does runs through it */
496 test
.control
.x
= -(test
.end
.x
+ test
.start
.x
)/2 + 2*(test
.control
.x
);
497 test
.control
.y
= -(test
.end
.y
+ test
.start
.y
)/2 + 2*(test
.control
.y
);
499 /* depending on where we are in the spline, we either try to match
500 the left or right tangent */
504 pos
= left
?start
:end
;
506 test
.control
.x
= s
->end
.x
*(3*qpos
) + 3*s
->control2
.x
*(2*pos
-3*qpos
) +
507 3*s
->control1
.x
*(1-4*pos
+3*qpos
) + s
->start
.x
*(-3+6*pos
-3*qpos
);
508 test
.control
.y
= s
->end
.y
*(3*qpos
) + 3*s
->control2
.y
*(2*pos
-3*qpos
) +
509 3*s
->control1
.y
*(1-4*pos
+3*qpos
) + s
->start
.y
*(-3+6*pos
-3*qpos
);
511 test
.control
.x
*= (end
-start
)/2;
512 test
.control
.y
*= (end
-start
)/2;
513 test
.control
.x
+= test
.start
.x
;
514 test
.control
.y
+= test
.start
.y
;
516 test
.control
.x
*= -(end
-start
)/2;
517 test
.control
.y
*= -(end
-start
)/2;
518 test
.control
.x
+= test
.end
.x
;
519 test
.control
.y
+= test
.end
.y
;
524 /* measure the spline's accurancy, by taking a number of probes */
525 for(t
=0;t
<probes
;t
++) {
526 gfxpoint_t qr1
,qr2
,cr1
,cr2
;
527 double pos
= 0.5/(probes
*2)*(t
*2+1);
530 qr1
= qspline_getpoint(&test
, pos
);
531 cr1
= cspline_getpoint(s
, start
+pos
*(end
-start
));
540 qr2
= qspline_getpoint(&test
, (1-pos
));
541 cr2
= cspline_getpoint(s
, start
+(1-pos
)*(end
-start
));
551 #else // quadratic error: *much* faster!
553 /* convert control point representation to
554 d*x^3 + c*x^2 + b*x + a */
555 dx
= s
->end
.x
- s
->control2
.x
*3 + s
->control1
.x
*3 - s
->start
.x
;
556 dy
= s
->end
.y
- s
->control2
.y
*3 + s
->control1
.y
*3 - s
->start
.y
;
558 /* we need to do this for the subspline between [start,end], not [0,1]
559 as a transformation of t->a*t+b does nothing to highest coefficient
560 of the spline except multiply it with a^3, we just need to modify
562 {double m
= end
-start
;
567 /* use the integral over (f(x)-g(x))^2 between 0 and 1
568 to measure the approximation quality.
569 (it boils down to const*d^2) */
570 recurse
= (dx
*dx
+ dy
*dy
> quality2
);
573 if(recurse
&& istep
>1 && size
-level
> num
) {
580 while(!(istart
& istep
)) {
589 void gfxdraw_conicTo(gfxdrawer_t
*draw
, double cx
, double cy
, double tox
, double toy
, double quality
)
591 double c1x
= (draw
->x
+ 2 * cx
) / 3;
592 double c1y
= (draw
->y
+ 2 * cy
) / 3;
593 double c2x
= (2 * cx
+ tox
) / 3;
594 double c2y
= (2 * cy
+ toy
) / 3;
595 gfxdraw_cubicTo(draw
, c1x
, c1y
, c2x
, c2y
, tox
, toy
, quality
);
599 void gfxdraw_cubicTo(gfxdrawer_t
*draw
, double c1x
, double c1y
, double c2x
, double c2y
, double x
, double y
, double quality
)
603 double maxerror
= quality
>0 ? quality
: 1.0;
615 num
= approximate3(&c
, q
, 128, maxerror
);
620 mid
.x
= q
[t
].control
.x
;
621 mid
.y
= q
[t
].control
.y
;
624 draw
->splineTo(draw
, mid
.x
, mid
.y
, to
.x
, to
.y
);
628 gfxbbox_t
gfxbbox_expand_to_point(gfxbbox_t box
, gfxcoord_t x
, gfxcoord_t y
)
630 if(box
.xmin
==0 && box
.ymin
==0 && box
.xmax
==0 && box
.ymax
==0) {
635 if(x
==0 && y
==0) box
.xmax
= 0.0000001;
649 void gfxbbox_intersect(gfxbbox_t
*box1
, gfxbbox_t
*box2
)
651 if(box2
->xmin
> box1
->xmin
)
652 box1
->xmin
= box2
->xmin
;
653 if(box2
->ymin
> box1
->ymin
)
654 box1
->ymin
= box2
->ymin
;
655 if(box2
->xmax
< box1
->xmax
)
656 box1
->xmax
= box2
->xmax
;
657 if(box2
->ymax
> box1
->ymax
)
658 box1
->ymax
= box2
->ymax
;
659 if(box1
->xmin
> box1
->xmax
)
660 box1
->xmax
= box1
->xmin
;
661 if(box1
->ymin
> box1
->ymax
)
662 box1
->ymax
= box1
->ymin
;
665 gfxbbox_t
gfxline_getbbox(gfxline_t
*line
)
668 gfxbbox_t bbox
= {0,0,0,0};
671 if(line
->type
== gfx_moveTo
) {
673 } else if(line
->type
== gfx_lineTo
) {
674 if(last
) bbox
= gfxbbox_expand_to_point(bbox
, x
, y
);
675 bbox
= gfxbbox_expand_to_point(bbox
, line
->x
, line
->y
);
677 } else if(line
->type
== gfx_splineTo
) {
678 if(last
) bbox
= gfxbbox_expand_to_point(bbox
, x
, y
);
679 bbox
= gfxbbox_expand_to_point(bbox
, line
->sx
, line
->sy
);
680 bbox
= gfxbbox_expand_to_point(bbox
, line
->x
, line
->y
);
690 gfxline_t
* gfxline_append(gfxline_t
*line1
, gfxline_t
*line2
)
692 gfxline_t
*l
= line1
;;
702 void gfxline_transform(gfxline_t
*line
, gfxmatrix_t
*matrix
)
705 double x
= matrix
->m00
*line
->x
+ matrix
->m10
*line
->y
+ matrix
->tx
;
706 double y
= matrix
->m01
*line
->x
+ matrix
->m11
*line
->y
+ matrix
->ty
;
709 if(line
->type
== gfx_splineTo
) {
710 double sx
= matrix
->m00
*line
->sx
+ matrix
->m10
*line
->sy
+ matrix
->tx
;
711 double sy
= matrix
->m01
*line
->sx
+ matrix
->m11
*line
->sy
+ matrix
->ty
;
719 void gfxmatrix_dump(gfxmatrix_t
*m
, FILE*fi
, char*prefix
)
721 fprintf(fi
, "%f %f | %f\n", m
->m00
, m
->m10
, m
->tx
);
722 fprintf(fi
, "%f %f | %f\n", m
->m01
, m
->m11
, m
->ty
);
725 void gfxmatrix_transform(gfxmatrix_t
*m
, double* v
, double*dest
)
727 dest
[0] = m
->m00
*v
[0] + m
->m10
*v
[1] + m
->tx
;
728 dest
[1] = m
->m01
*v
[0] + m
->m11
*v
[1] + m
->ty
;
730 void gfxmatrix_invert(gfxmatrix_t
*m
, gfxmatrix_t
*dest
)
732 double det
= m
->m00
* m
->m11
- m
->m10
* m
->m01
;
734 memset(dest
, 0, sizeof(gfxmatrix_t
));
738 dest
->m00
= m
->m11
* det
;
739 dest
->m01
= -m
->m01
* det
;
740 dest
->m10
= -m
->m10
* det
;
741 dest
->m11
= m
->m00
* det
;
742 dest
->tx
= -(dest
->m00
* m
->tx
+ dest
->m10
* m
->ty
);
743 dest
->ty
= -(dest
->m01
* m
->tx
+ dest
->m11
* m
->ty
);
745 void gfxmatrix_unit(gfxmatrix_t
*m
)
747 memset(m
, 0, sizeof(gfxmatrix_t
));
751 void gfxmatrix_multiply(gfxmatrix_t
*m1
, gfxmatrix_t
*m2
, gfxmatrix_t
*dest
)
753 dest
->m00
= m1
->m00
*m2
->m00
+ m1
->m10
*m2
->m01
;
754 dest
->m01
= m1
->m01
*m2
->m00
+ m1
->m11
*m2
->m01
;
755 dest
->m10
= m1
->m00
*m2
->m10
+ m1
->m10
*m2
->m11
;
756 dest
->m11
= m1
->m01
*m2
->m10
+ m1
->m11
*m2
->m11
;
757 dest
->tx
= m1
->m00
*m2
->tx
+ m1
->m10
*m2
->ty
+ m1
->tx
;
758 dest
->ty
= m1
->m01
*m2
->tx
+ m1
->m11
*m2
->ty
+ m1
->ty
;
761 gfxfontlist_t
* gfxfontlist_create()
763 /* Initial list ist empty */
767 gfxfont_t
*gfxfontlist_findfont(gfxfontlist_t
*list
, char*id
)
769 gfxfontlist_t
*l
= list
;
771 if(!strcmp((char*)l
->font
->id
, id
)) {
778 char gfxfontlist_hasfont(gfxfontlist_t
*list
, gfxfont_t
*font
)
780 gfxfontlist_t
*l
= list
;
782 if(!strcmp((char*)l
->font
->id
, font
->id
)) {
789 gfxfontlist_t
*gfxfontlist_addfont(gfxfontlist_t
*list
, gfxfont_t
*font
)
791 gfxfontlist_t
*last
=0,*l
= list
;
794 if(l
->font
== font
) {
795 return list
; // we already know this font
800 fprintf(stderr
, "Tried to add zero font\n");
802 l
= (gfxfontlist_t
*)rfx_calloc(sizeof(gfxfontlist_t
));
812 void gfxfontlist_free(gfxfontlist_t
*list
, char deletefonts
)
814 gfxfontlist_t
*l
= list
;
816 gfxfontlist_t
*next
= l
->next
;
817 if(deletefonts
&& l
->font
) {
818 gfxfont_free(l
->font
);l
->font
=0;
826 gfxline_t
*gfxline_makerectangle(int x1
,int y1
,int x2
, int y2
)
828 gfxline_t
* line
= (gfxline_t
*)rfx_calloc(sizeof(gfxline_t
)*5);
829 line
[0].x
= x1
;line
[0].y
= y1
;line
[0].type
= gfx_moveTo
;line
[0].next
= &line
[1];
830 line
[1].x
= x2
;line
[1].y
= y1
;line
[1].type
= gfx_lineTo
;line
[1].next
= &line
[2];
831 line
[2].x
= x2
;line
[2].y
= y2
;line
[2].type
= gfx_lineTo
;line
[2].next
= &line
[3];
832 line
[3].x
= x1
;line
[3].y
= y2
;line
[3].type
= gfx_lineTo
;line
[3].next
= &line
[4];
833 line
[4].x
= x1
;line
[4].y
= y1
;line
[4].type
= gfx_lineTo
;
837 gfxline_t
*gfxline_makecircle(double x
,double y
,double rx
, double ry
)
841 double begin
= 0.7070;
842 gfxline_t
* line
= (gfxline_t
*)rfx_calloc(sizeof(gfxline_t
)*9);
844 line
[0].type
= gfx_moveTo
;
845 line
[0].x
= x
+begin
*rx
;
846 line
[0].y
= y
+begin
*ry
;
848 line
[t
-1].next
= &line
[t
];
849 line
[t
].type
= gfx_splineTo
;
852 #define R(nr,cx,cy,mx,my) \
853 line[nr].sx = line[nr-1].x + (cx); \
854 line[nr].sy = line[nr-1].y + (cy); \
855 line[nr].x = line[nr].sx + (mx); \
856 line[nr].y = line[nr].sy + (my);
857 R(1, -C1
*rx
, C1
*ry
, -C2
*rx
, 0);
858 R(2, -C2
*rx
, 0, -C1
*rx
, -C1
*ry
);
859 R(3, -C1
*rx
, -C1
*ry
, 0, -C2
*ry
);
860 R(4, 0, -C2
*ry
, C1
*rx
, -C1
*ry
);
861 R(5, C1
*rx
, -C1
*ry
, C2
*rx
, 0);
862 R(6, C2
*rx
, 0, C1
*rx
, C1
*ry
);
863 R(7, C1
*rx
, C1
*ry
, 0, C2
*ry
);
864 R(8, 0, C2
*ry
, -C1
*rx
, C1
*ry
);
868 gfxbbox_t
* gfxline_isrectangle(gfxline_t
*_l
)
873 gfxline_t
*l
= gfxline_clone(_l
);
888 if(xc
==2 && x
!=x1
&& x
!=x2
) {fail
=1;break;}
889 else if(xc
>=1 && x
==x1
) {left
=0;}
890 else if(xc
==2 && x
==x2
) {left
=1;}
891 else if(xc
==1 && x
!=x1
) {x2
= x
; xc
=2; left
=1;}
892 else if(xc
==0) {x1
= x
; xc
=1;left
=0;}
893 else {fprintf(stderr
, "Internal error in rectangle detection\n");}
895 if(yc
==2 && y
!=y1
&& y
!=y2
) {fail
=1;break;}
896 else if(yc
>=1 && y
==y1
) {top
=0;}
897 else if(yc
==2 && y
==y2
) {top
=1;}
898 else if(yc
==1 && y
!=y1
) {y2
= y
; yc
=2; top
=1;}
899 else if(yc
==0) {y1
= y
; yc
=1;top
=0;}
900 else {fprintf(stderr
, "Internal error in rectangle detection\n");}
902 char pos
=top
<<1|left
;
905 /* diagonal lines not allowed */
910 /* no corner except the first one may be touched twice */
911 if(pos
&& (corners
& 1<<pos
)) {
914 /* mark which corners have been touched so far */
922 if(corners
!=0x0f) return 0; // not all 4 corners reached
924 if(x2
<x1
) {double x
= x2
;x2
=x1
;x1
=x
;}
925 if(y2
<y1
) {double y
= y2
;y2
=y1
;y1
=y
;}
927 gfxbbox_t
*r
= malloc(sizeof(gfxbbox_t
));
928 r
->xmin
= x1
; r
->ymin
= y1
;
929 r
->xmax
= x2
; r
->ymax
= y2
;
933 void gfximage_transform(gfximage_t
*img
, gfxcxform_t
*cxform
)
936 int size
= img
->width
*img
->height
;
942 rr
= (int)(cxform
->rr
*256);gr
= (int)(cxform
->gr
*256);
943 rg
= (int)(cxform
->rg
*256);gg
= (int)(cxform
->gg
*256);
944 rb
= (int)(cxform
->rb
*256);gb
= (int)(cxform
->gb
*256);
945 ra
= (int)(cxform
->ra
*256);ga
= (int)(cxform
->ga
*256);
946 br
= (int)(cxform
->br
*256);ar
= (int)(cxform
->ar
*256);tr
= (int)(cxform
->tr
*256);
947 bg
= (int)(cxform
->bg
*256);ag
= (int)(cxform
->ag
*256);tg
= (int)(cxform
->tg
*256);
948 bb
= (int)(cxform
->bb
*256);ab
= (int)(cxform
->ab
*256);tb
= (int)(cxform
->tb
*256);
949 ba
= (int)(cxform
->ba
*256);aa
= (int)(cxform
->aa
*256);ta
= (int)(cxform
->ta
*256);
951 for(t
=0;t
<size
;t
++) {
952 gfxcolor_t
*pixel
= &img
->data
[t
];
953 unsigned char r
= (pixel
->r
* rr
+ pixel
->g
* rg
+ pixel
->b
* rb
+ pixel
->a
* ra
+ tr
) / 256;
954 unsigned char g
= (pixel
->r
* gr
+ pixel
->g
* gg
+ pixel
->b
* gb
+ pixel
->a
* ga
+ tg
) / 256;
955 unsigned char b
= (pixel
->r
* br
+ pixel
->g
* bg
+ pixel
->b
* bb
+ pixel
->a
* ba
+ tb
) / 256;
956 unsigned char a
= (pixel
->r
* ar
+ pixel
->g
* ag
+ pixel
->b
* ab
+ pixel
->a
* aa
+ ta
) / 256;
963 void gfxline_dump(gfxline_t
*line
, FILE*fi
, char*prefix
)
966 if(line
->type
== gfx_moveTo
) {
967 fprintf(fi
, "%smoveTo %.2f %.2f\n", prefix
, line
->x
, line
->y
);
968 } else if(line
->type
== gfx_lineTo
) {
969 fprintf(fi
, "%slineTo %.2f %.2f\n", prefix
, line
->x
, line
->y
);
970 } else if(line
->type
== gfx_splineTo
) {
971 fprintf(fi
, "%ssplineTo (%.2f %.2f) %.2f %.2f\n", prefix
, line
->sx
, line
->sy
, line
->x
, line
->y
);