X-Git-Url: http://git.asbjorn.biz/?p=swftools.git;a=blobdiff_plain;f=lib%2Fdrawer.c;h=671ac84aa07b3ef2a606da6ae0c0e817c7235839;hp=e02fed4c59b95c1f5cc400fe7727f2f5b7718e2d;hb=879d0eec420fe0fd5ddcd56c8fe62b82a6744edd;hpb=715b18c27f5e29e8bba7d2fa136c4fdce0cdad9d diff --git a/lib/drawer.c b/lib/drawer.c index e02fed4..671ac84 100644 --- a/lib/drawer.c +++ b/lib/drawer.c @@ -25,20 +25,32 @@ #include #include #include +#include #include "drawer.h" static char* getToken(const char**p) { const char*start; char*result; - while(**p && strchr(" ,\t\n\r", **p)) { + while(**p && strchr(" ,()\t\n\r", **p)) { (*p)++; } start = *p; - while(**p && !strchr(" ,\t\n\r", **p)) { + + /* + SVF pathdata can exclude whitespace after L and M commands. + Ref: http://www.w3.org/TR/SVG11/paths.html#PathDataGeneralInformation + This allows us to use svg files output from gnuplot. + Also checks for relative MoveTo and LineTo (m and l). + 051106 Magnus Lundin, lundin@mlu.mine.nu + */ + if (strchr("LMlm", **p) && (isdigit(*(*p+1))||strchr("+-", *(*p+1)))) { + (*p)++; + } + else while(**p && !strchr(" ,()\t\n\r", **p)) { (*p)++; } - result = malloc((*p)-start+1); + result = (char*)malloc((*p)-start+1); memcpy(result,start,(*p)-start+1); result[(*p)-start] = 0; return result; @@ -57,44 +69,126 @@ void draw_conicTo(drawer_t*draw, FPOINT* c, FPOINT* to) draw->pos = *to; } +/* convenience routine */ +static void draw_conicTo2(drawer_t*draw, double x1, double y1, double x2, double y2) +{ + FPOINT c1,c2; + c1.x = x1; + c1.y = y1; + c2.x = x2; + c2.y = y2; + draw_conicTo(draw, &c1, &c2); +} +/* convenience routine */ +static void draw_moveTo2(drawer_t*draw, double x, double y) +{ + FPOINT c; + c.x = x; c.y = y; + draw->moveTo(draw, &c); +} +/* convenience routine */ +static void draw_lineTo2(drawer_t*draw, double x, double y) +{ + FPOINT c; + c.x = x; c.y = y; + draw->lineTo(draw, &c); +} + +static float getFloat(const char** p) +{ + char* token = getToken(p); + float result = atof(token); + free(token); + return result; +} + void draw_string(drawer_t*draw, const char*string) { const char*p = string; while(*p) { char*token = getToken(&p); - if(!token || !*token) + if(!token) + break; + if (!*token) + { + free(token); break; - if(!strncmp(token, "moveTo", 6)) { + } + if(!strncmp(token, "moveTo", 6) || + !strncmp(token, "M", 1) //svg + ) { FPOINT to; - to.x = atoi(getToken(&p)); - to.y = atoi(getToken(&p)); + to.x = getFloat(&p); + to.y = getFloat(&p); draw->moveTo(draw, &to); } - else if(!strncmp(token, "lineTo", 6)) { + else if(!strncmp(token, "lineTo", 6) || + !strncmp(token, "L", 1) //svg + ) { FPOINT to; - to.x = atoi(getToken(&p)); - to.y = atoi(getToken(&p)); + to.x = getFloat(&p); + to.y = getFloat(&p); draw->lineTo(draw, &to); } else if(!strncmp(token, "curveTo", 7) || !strncmp(token, "splineTo", 8)) { FPOINT mid,to; - mid.x = atoi(getToken(&p)); - mid.y = atoi(getToken(&p)); - to.x = atoi(getToken(&p)); - to.y = atoi(getToken(&p)); + mid.x = getFloat(&p); + mid.y = getFloat(&p); + to.x = getFloat(&p); + to.y = getFloat(&p); draw->splineTo(draw, &mid, &to); } - else if(!strncmp(token, "cubicTo", 5)) { + else if(!strncmp(token, "conicTo", 5)) { + FPOINT mid,to; + mid.x = getFloat(&p); + mid.y = getFloat(&p); + to.x = getFloat(&p); + to.y = getFloat(&p); + draw_conicTo(draw, &mid, &to); + } + else if(!strncmp(token, "circle", 6)) { + int mx,my,r; + double r2; + mx = getFloat(&p); + my = getFloat(&p); + r = getFloat(&p); + r2 = 0.70710678118654757*r; + draw_moveTo2(draw, mx, my-r); + draw_conicTo2(draw, mx+r2, my-r2, mx+r, my); + draw_conicTo2(draw, mx+r2, my+r2, mx, my+r); + draw_conicTo2(draw, mx-r2, my+r2, mx-r, my); + draw_conicTo2(draw, mx-r2, my-r2, mx, my-r); + } + else if(!strncmp(token, "box", 3)) { + int x1,y1,x2,y2; + x1 = getFloat(&p); + y1 = getFloat(&p); + x2 = getFloat(&p); + y2 = getFloat(&p); + draw_moveTo2(draw, x1, y1); + draw_lineTo2(draw, x1, y2); + draw_lineTo2(draw, x2, y2); + draw_lineTo2(draw, x2, y1); + draw_lineTo2(draw, x1, y1); + } + else if(!strncmp(token, "cubicTo", 5) || + !strncmp(token, "C", 1) //svg + ) { FPOINT mid1,mid2,to; - mid1.x = atoi(getToken(&p)); - mid1.y = atoi(getToken(&p)); - mid2.x = atoi(getToken(&p)); - mid2.y = atoi(getToken(&p)); - to.x = atoi(getToken(&p)); - to.y = atoi(getToken(&p)); + mid1.x = getFloat(&p); + mid1.y = getFloat(&p); + mid2.x = getFloat(&p); + mid2.y = getFloat(&p); + to.x = getFloat(&p); + to.y = getFloat(&p); draw_cubicTo(draw, &mid1, &mid2, &to); } - else fprintf(stderr, "drawer: Warning: unknown primitive '%s'", token); + else if(!strncmp(token, "z", 1) //svg + ) { + // ignore + } + else + fprintf(stderr, "drawer: Warning: unknown primitive '%s'\n", token); free(token); } @@ -194,8 +288,9 @@ static int approximate3(const struct cspline*s, struct qspline*q, int size, doub test.control.y += test.end.y; } +#define PROBES +#ifdef PROBES /* measure the spline's accurancy, by taking a number of probes */ - for(t=0;tend.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) + */ + recurse = (dx*dx + dy*dy > quality2); +#endif if(recurse && istep>1 && size-level > num) { istep >>= 1; @@ -243,11 +361,9 @@ void draw_cubicTo(drawer_t*draw, FPOINT* control1, FPOINT* control2, FPOINT* t { struct qspline q[128]; struct cspline c; - double quality = 80; - double maxerror = (500-(quality*5)>1?500-(quality*5):1)/20.0; - - int num = approximate3(&c, q, 128, maxerror*maxerror); - int t; + //double quality = 80; + double maxerror = 1;//(500-(quality*5)>1?500-(quality*5):1)/20.0; + int t,num; c.start.x = draw->pos.x; c.start.y = draw->pos.y; @@ -257,6 +373,8 @@ void draw_cubicTo(drawer_t*draw, FPOINT* control1, FPOINT* control2, FPOINT* t c.control2.y = control2->y; c.end.x = to->x; c.end.y = to->y; + + num = approximate3(&c, q, 128, maxerror*maxerror); for(t=0;t