linedraw_internal_t*i = (linedraw_internal_t*)d->internal;
gfxline_t*l = rfx_alloc(sizeof(gfxline_t));
l->type = gfx_moveTo;
+ if((int)((d->x * 5120) == (int)(x * 5120)) &&
+ (int)((d->y * 5120) == (int)(y * 5120))) {
+ /* never mind- we're already there */
+ return;
+
+ }
d->x = l->x = x;
d->y = l->y = y;
l->next = 0;
{
linedraw_internal_t*i = (linedraw_internal_t*)d->internal;
gfxline_t*l = rfx_alloc(sizeof(gfxline_t));
+
+ if(!i->start) {
+ /* starts with a line, not with a moveto. That needs we first
+ need an explicit moveto to (0,0) */
+ linedraw_moveTo(d, 0, 0);
+ }
+
l->type = gfx_lineTo;
d->x = l->x = x;
d->y = l->y = y;
+
l->next = 0;
if(i->next)
i->next->next = l;
{
linedraw_internal_t*i = (linedraw_internal_t*)d->internal;
gfxline_t*l = rfx_alloc(sizeof(gfxline_t));
+
+ if(!i->start) {
+ /* starts with a line, not with a moveto. That needs we first
+ need an explicit moveto to (0,0) */
+ linedraw_moveTo(d, 0, 0);
+ }
+
l->type = gfx_splineTo;
d->x = l->x = x;
d->y = l->y = y;
void gfxdrawer_target_gfxline(gfxdrawer_t*d)
{
linedraw_internal_t*i = (linedraw_internal_t*)rfx_calloc(sizeof(linedraw_internal_t));
+ d->x = 0x7fffffff;
+ d->y = 0x7fffffff;
d->internal = i;
d->moveTo = linedraw_moveTo;
d->lineTo = linedraw_lineTo;
}
}
+gfxline_t * gfxline_clone(gfxline_t*line)
+{
+ gfxline_t*dest = 0;
+ gfxline_t*pos = 0;
+ while(line) {
+ gfxline_t*n = rfx_calloc(sizeof(gfxline_t));
+ *n = *line;
+ n->next = 0;
+ if(!pos) {
+ dest = pos = n;
+ } else {
+ pos->next = n;
+ pos = n;
+ }
+ line = line->next;
+ }
+ return dest;
+}
+void gfxline_optimize(gfxline_t*line)
+{
+ gfxline_t*l = line;
+ /* step 1: convert splines to lines, where possible */
+ double x=0,y=0;
+ while(l) {
+ if(l->type == gfx_splineTo) {
+ double dx = l->x-x;
+ double dy = l->y-y;
+ double sx = l->sx-x;
+ double sy = l->sy-y;
+ if(fabs(dx*sy - dy*sx) < 0.000001 && (dx*sx + dy*sy) >= 0) {
+ l->type = gfx_lineTo;
+ }
+ }
+ x = l->x;
+ y = l->y;
+ l = l->next;
+ }
+ /* step 2: combine adjacent lines and splines, where possible */
+ l = line;
+ while(l && l->next) {
+ gfxline_t*next = l->next;
+ char combine = 0;
+ double sx=0,sy=0;
+ if(l->type == gfx_lineTo && next->type == gfx_lineTo) {
+ double dx = l->x-x;
+ double dy = l->y-y;
+ double nx = next->x-x;
+ double ny = next->y-y;
+ if(fabs(dx*ny - dy*nx) < 0.000001 && (dx*nx + dy*ny) >= 0) {
+ combine = 1;
+ }
+ } else if(l->type == gfx_splineTo && next->type == gfx_splineTo) {
+ /* TODO */
+ }
+ if(combine) {
+ l->next = next->next;
+ next->next = 0;
+ l->x = next->x;
+ l->y = next->y;
+ l->sx = sx;
+ l->sy = sy;
+ rfx_free(next);
+ } else {
+ x = l->x;
+ y = l->y;
+ l = l->next;
+ }
+ }
+}
+
gfxline_t* gfxtool_dash_line(gfxline_t*line, float*dashes, float phase)
{
gfxdrawer_t d;
void gfxline_show(gfxline_t*l, FILE*fi)
{
while(l) {
- if(l->type == moveTo) {
+ if(l->type == gfx_moveTo) {
fprintf(fi, "moveTo %.2f,%.2f\n", l->x, l->y);
}
- if(l->type == lineTo) {
+ if(l->type == gfx_lineTo) {
fprintf(fi, "lineTo %.2f,%.2f\n", l->x, l->y);
}
- if(l->type == splineTo) {
+ if(l->type == gfx_splineTo) {
fprintf(fi, "splineTo %.2f,%.2f %.2f,%.2f\n", l->sx, l->sy, l->x, l->y);
}
l = l->next;
void gfxline_free(gfxline_t*l)
{
- gfxline_t*next;
- while(l) {
- next = l->next;
- l->next = 0;
+ if(l && (l+1) == l->next) {
+ /* flattened */
rfx_free(l);
- l = next;
+ } else {
+ gfxline_t*next;
+ while(l) {
+ next = l->next;
+ l->next = 0;
+ rfx_free(l);
+ l = next;
+ }
}
}
test.control.y += test.end.y;
}
-#define PROBES
+//#define PROBES
#ifdef PROBES
/* measure the spline's accurancy, by taking a number of probes */
for(t=0;t<probes;t++) {
/* convert control point representation to
d*x^3 + c*x^2 + b*x + a */
-
- /* FIXME: we need to do this for the subspline between [start,end],
- not [0,1] */
dx= s->end.x - s->control2.x*3 + s->control1.x*3 - s->start.x;
dy= s->end.y - s->control2.y*3 + s->control1.y*3 - s->start.y;
+ /* we need to do this for the subspline between [start,end], not [0,1]
+ as a transformation of t->a*t+b does nothing to highest coefficient
+ of the spline except multiply it with a^3, we just need to modify
+ d here. */
+ {double m = end-start;
+ dx*=m*m*m;
+ dy*=m*m*m;
+ }
+
/* use the integral over (f(x)-g(x))^2 between 0 and 1
to measure the approximation quality.
- (it boils down to const*d^2)
- */
+ (it boils down to const*d^2) */
recurse = (dx*dx + dy*dy > quality2);
#endif
return num;
}
-void gfxdraw_cubicTo(gfxdrawer_t*draw, double c1x, double c1y, double c2x, double c2y, double x, double y)
+void gfxdraw_conicTo(gfxdrawer_t*draw, double cx, double cy, double tox, double toy, double quality)
+{
+ double c1x = (draw->x + 2 * cx) / 3;
+ double c1y = (draw->y + 2 * cy) / 3;
+ double c2x = (2 * cx + tox) / 3;
+ double c2y = (2 * cy + toy) / 3;
+ gfxdraw_cubicTo(draw, c1x, c1y, c2x, c2y, tox, toy, quality);
+}
+
+
+void gfxdraw_cubicTo(gfxdrawer_t*draw, double c1x, double c1y, double c2x, double c2y, double x, double y, double quality)
{
qspline_t q[128];
cspline_t c;
- double maxerror = 0.04;
+ double maxerror = quality>0 ? quality : 1.0;
int t,num;
c.start.x = draw->x;
c.end.x = x;
c.end.y = y;
- num = approximate3(&c, q, 128, maxerror*maxerror);
+ num = approximate3(&c, q, 128, maxerror);
for(t=0;t<num;t++) {
- FPOINT mid;
- FPOINT to;
+ gfxpoint_t mid;
+ gfxpoint_t to;
mid.x = q[t].control.x;
mid.y = q[t].control.y;
to.x = q[t].end.x;
gfxbbox_t gfxbbox_expand_to_point(gfxbbox_t box, gfxcoord_t x, gfxcoord_t y)
{
- if(box.xmin==0 || box.ymin==0 || box.xmax==0 || box.ymax==0) {
+ if(box.xmin==0 && box.ymin==0 && box.xmax==0 && box.ymax==0) {
box.xmin = x;
box.ymin = y;
box.xmax = x;
last = 0;
}
x = line->x;
- y = line->x;
+ y = line->y;
line = line->next;
}
return bbox;
}
-void gfxline_dump(gfxline_t*line, FILE*fi)
+void gfxline_dump(gfxline_t*line, FILE*fi, char*prefix)
{
while(line) {
if(line->type == gfx_moveTo) {
- fprintf(fi, "moveTo %.2f %.2f\n", line->x, line->y);
+ fprintf(fi, "%smoveTo %.2f %.2f\n", prefix, line->x, line->y);
} else if(line->type == gfx_lineTo) {
- fprintf(fi, "lineTo %.2f %.2f\n", line->x, line->y);
+ fprintf(fi, "%slineTo %.2f %.2f\n", prefix, line->x, line->y);
} else if(line->type == gfx_splineTo) {
- fprintf(fi, "splineTo (%.2f %.2f) %.2f %.2f\n", line->sx, line->sy, line->x, line->y);
+ fprintf(fi, "%ssplineTo (%.2f %.2f) %.2f %.2f\n", prefix, line->sx, line->sy, line->x, line->y);
+ }
+ line = line->next;
+ }
+}
+
+gfxline_t* gfxline_append(gfxline_t*line1, gfxline_t*line2)
+{
+ gfxline_t*l = line1;;
+ if(!l)
+ return line2;
+ while(l->next) {
+ l = l->next;
+ }
+ l->next = line2;
+ return line1;
+}
+
+void gfxline_transform(gfxline_t*line, gfxmatrix_t*matrix)
+{
+ while(line) {
+ double x = matrix->m00*line->x + matrix->m10*line->y + matrix->tx;
+ double y = matrix->m01*line->x + matrix->m11*line->y + matrix->ty;
+ line->x = x;
+ line->y = y;
+ if(line->type == gfx_splineTo) {
+ double sx = matrix->m00*line->sx + matrix->m10*line->sy + matrix->tx;
+ double sy = matrix->m01*line->sx + matrix->m11*line->sy + matrix->ty;
+ line->sx = sx;
+ line->sy = sy;
}
line = line->next;
}
}
+void gfxmatrix_dump(gfxmatrix_t*m, FILE*fi, char*prefix)
+{
+ fprintf(fi, "%f %f | %f\n", m->m00, m->m10, m->tx);
+ fprintf(fi, "%f %f | %f\n", m->m01, m->m11, m->ty);
+}
+
+void gfxmatrix_transform(gfxmatrix_t*m, double* v, double*dest)
+{
+ dest[0] = m->m00*v[0] + m->m10*v[1] + m->tx;
+ dest[1] = m->m01*v[0] + m->m11*v[1] + m->ty;
+}
+void gfxmatrix_invert(gfxmatrix_t*m, gfxmatrix_t*dest)
+{
+ double det = m->m00 * m->m11 - m->m10 * m->m01;
+ if(!det) {
+ memset(dest, 0, sizeof(gfxmatrix_t));
+ return;
+ }
+ det = 1/det;
+ dest->m00 = m->m11 * det;
+ dest->m01 = -m->m01 * det;
+ dest->m10 = -m->m10 * det;
+ dest->m11 = m->m00 * det;
+ dest->tx = -(dest->m00 * m->tx + dest->m10 * m->ty);
+ dest->ty = -(dest->m01 * m->tx + dest->m11 * m->ty);
+}
+
+gfxfontlist_t* gfxfontlist_create()
+{
+ /* Initial list ist empty */
+ return 0;
+}
+
+gfxfont_t*gfxfontlist_findfont(gfxfontlist_t*list, char*id)
+{
+ gfxfontlist_t*l = list;
+ while(l) {
+ if(!strcmp((char*)l->font->id, id)) {
+ return l->font;
+ }
+ l = l->next;
+ }
+ return 0;
+}
+char gfxfontlist_hasfont(gfxfontlist_t*list, gfxfont_t*font)
+{
+ gfxfontlist_t*l = list;
+ while(l) {
+ if(!strcmp((char*)l->font->id, font->id)) {
+ return 1;
+ }
+ l = l->next;
+ }
+ return 0;
+}
+gfxfontlist_t*gfxfontlist_addfont(gfxfontlist_t*list, gfxfont_t*font)
+{
+ gfxfontlist_t*last=0,*l = list;
+ while(l) {
+ last = l;
+ if(!strcmp((char*)l->font->id, font->id)) {
+ return list; // we already know this font
+ }
+ l = l->next;
+ }
+ if(!font) {
+ fprintf(stderr, "Tried to add zero font\n");
+ }
+ l = (gfxfontlist_t*)rfx_calloc(sizeof(gfxfontlist_t));
+ l->font = font;
+ l->next = 0;
+ if(last) {
+ last->next = l;
+ return list;
+ } else {
+ return l;
+ }
+}
+
+gfxline_t*gfxline_makerectangle(int x1,int y1,int x2, int y2)
+{
+ gfxline_t* line = (gfxline_t*)rfx_calloc(sizeof(gfxline_t)*5);
+ line[0].x = x1;line[0].y = y1;line[0].type = gfx_moveTo;line[0].next = &line[1];
+ line[1].x = x2;line[1].y = y1;line[1].type = gfx_lineTo;line[1].next = &line[2];
+ line[2].x = x2;line[2].y = y2;line[2].type = gfx_lineTo;line[2].next = &line[3];
+ line[3].x = x1;line[3].y = y2;line[3].type = gfx_lineTo;line[3].next = &line[4];
+ line[4].x = x1;line[4].y = y1;line[4].type = gfx_lineTo;
+ return line;
+}