along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include <stdio.h>
#include <memory.h>
#include <math.h>
#include <assert.h>
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;
static double get_spline_len(qspline_abc_t*s)
{
- //int parts = (int)(sqrt(abs(l2->x-2*l2->sx+x) + abs(l2->y-2*l2->sy+y)/3));
+ int parts = (int)(sqrt(fabs(s->ax) + fabs(s->ay))*3);
int i;
double len = 0;
- for(i=0;i<128;i++)
+ double r;
+ double r2;
+ if(parts < 3) parts = 3;
+ r = 1.0/parts;
+ r2 = 1.0/(parts*parts);
+ for(i=0;i<parts;i++)
{
- double t = i*(1/128.0);
- double dx = 2*s->ax*t + s->bx;
- double dy = 2*s->ay*t + s->by;
+ double dx = s->ax*(2*i+1)*r2 + s->bx*r;
+ double dy = s->ay*(2*i+1)*r2 + s->by*r;
len += sqrt(dx*dx+dy*dy);
}
- return len / 128;
+ /*printf("Spline from %f,%f to %f,%f has len %f (%f)\n", s->cx, s->cy,
+ s->cx + s->bx + s->ax,
+ s->cy + s->by + s->ay, len,
+ sqrt((s->bx + s->ax)*(s->bx + s->ax) + (s->by + s->ay)*(s->by + s->ay))
+ );
+ assert(len+0.5 >= sqrt((s->bx + s->ax)*(s->bx + s->ax) + (s->by + s->ay)*(s->by + s->ay)));
+ */
+ return len;
}
-void gfxtool_draw_dashed_line(gfxdrawer_t*d, gfxline_t*line, float*r)
+void gfxtool_draw_dashed_line(gfxdrawer_t*d, gfxline_t*line, float*r, float phase)
{
double x=0,y=0;
- int apos = 0;
- double linepos = 0;
- double nextpos = 0;
- char on = 1;
+ double linepos,nextpos;
+ char on;
+ int apos;
+
+ if(line && line->type != gfx_moveTo) {
+ fprintf(stderr, "gfxtool: outline doesn't start with a moveTo");
+ return;
+ }
+ if(!r || r[0]<0 || phase<0) {
+ fprintf(stderr, "gfxtool: invalid dashes");
+ return;
+ }
+
for(;line;line=line->next) {
if(line->type == gfx_moveTo) {
d->moveTo(d, line->x, line->y);
- apos = 0; nextpos = 0; on = 1; linepos = 0;
+ on = 1; nextpos = r[0]; apos = 0; linepos = 0;
x = line->x; y = line->y;
+ while(linepos < phase) {
+ //printf("[+] linepos: %f, phase: %f, on:%d, apos:%d nextpos:%f\n", linepos, phase, on, apos, nextpos);
+ linepos += r[apos];
+ if(linepos < phase) {
+ on ^= 1;
+ if(r[++apos]<0)
+ apos = 0;
+ nextpos += r[apos];
+ }
+ }
+ linepos = phase;
+ //printf("[k] linepos: %f, phase: %f, on:%d, apos:%d nextpos:%f \n", linepos, phase, on, apos, nextpos);
} else if(line->type == gfx_lineTo) {
double dx = line->x - x;
double dy = line->y - y;
double len = sqrt(dx*dx+dy*dy);
+ double vx;
+ double vy;
+ double lineend = linepos+len;
if(len==0)
continue;
- double vx = dx/len;
- double vy = dy/len;
- double lineend = linepos+len;
+ vx = dx/len;
+ vy = dy/len;
assert(nextpos>=linepos);
- //printf("nextpos: %f, line end: %f\n", nextpos, linepos+len);
+ //printf("(line) on:%d apos: %d nextpos: %f, line pos: %f, line end: %f\n", on, apos, nextpos, linepos, linepos+len);
while(nextpos<lineend) {
double nx = x + vx*(nextpos-linepos);
double ny = y + vy*(nextpos-linepos);
- if(on) d->lineTo(d, nx,ny);
- else d->moveTo(d, nx,ny);
+ if(on) {d->lineTo(d, nx,ny);/*printf("lineTo %f\n", nextpos);*/}
+ else {d->moveTo(d, nx,ny);/*printf("moveTo %f\n", nextpos);*/}
on^=1;
+ if(r[++apos]<0)
+ apos = 0;
nextpos+=r[apos];
- apos++;
- if(r[apos]==0)
- apos = 1;
}
linepos = lineend;
if(on) {
+ //printf("lineTo %f\n", 1.0);
d->lineTo(d, line->x,line->y);
}
x = line->x; y = line->y;
} else if(line->type == gfx_splineTo) {
qspline_abc_t q;
+ double len, lineend,lastt;
mkspline(&q, x, y, line);
- double len = get_spline_len(&q);
+ len = get_spline_len(&q);
//printf("%f %f -> %f %f, len: %f\n", x, y, line->x, line->y, len);
if(len==0)
continue;
- double lineend = linepos+len;
- double lastt = 0;
+ lineend = linepos+len;
+ lastt = 0;
if(nextpos<linepos)
printf("%f !< %f\n", nextpos, linepos);
assert(nextpos>=linepos);
+ //printf("(spline) on:%d apos: %d nextpos: %f, line pos: %f, line end: %f\n", on, apos, nextpos, linepos, linepos+len);
while(nextpos<lineend) {
double t = (nextpos-linepos)/len;
+ //printf("%f (%f-%f) apos=%d r[apos]=%f\n", t, nextpos, linepos, apos, r[apos]);
double nx = q.ax*t*t+q.bx*t+q.cx;
double ny = q.ay*t*t+q.by*t+q.cy;
if(on) {
double sx,sy;
spline_get_controlpoint(&q, lastt, t, &sx, &sy);
d->splineTo(d, sx, sy, nx,ny);
+ //printf("splineTo %f\n", nextpos);
} else {
d->moveTo(d, nx,ny);
+ //printf("moveTo %f\n", nextpos);
}
lastt = t;
on^=1;
+ if(r[++apos]<0)
+ apos = 0;
nextpos+=r[apos];
- apos++;
- if(r[apos]==0)
- apos = 1;
}
linepos = lineend;
if(on) {
double sx,sy;
spline_get_controlpoint(&q, lastt, 1, &sx, &sy);
d->splineTo(d, sx, sy, line->x,line->y);
+ //printf("splineTo %f\n", 1.0);
}
x = line->x; y = line->y;
}
}
}
-gfxline_t* gfxtool_dash_line(gfxline_t*line, float*dashes)
+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;
+}
+
+gfxline_t* gfxtool_dash_line(gfxline_t*line, float*dashes, float phase)
{
gfxdrawer_t d;
+ gfxline_t*result;
gfxdrawer_target_gfxline(&d);
- gfxtool_draw_dashed_line(&d, line, dashes);
- gfxline_t*result= (gfxline_t*)d.result(&d);
+ gfxtool_draw_dashed_line(&d, line, dashes, phase);
+ result= (gfxline_t*)d.result(&d);
return result;
}
while(l) {
next = l->next;
l->next = 0;
- free(l);
+ 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, char*prefix)
+{
+ while(line) {
+ if(line->type == gfx_moveTo) {
+ fprintf(fi, "%smoveTo %.2f %.2f\n", prefix, line->x, line->y);
+ } else if(line->type == gfx_lineTo) {
+ fprintf(fi, "%slineTo %.2f %.2f\n", prefix, line->x, line->y);
+ } else if(line->type == gfx_splineTo) {
+ 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);
+}