Number: 346
Title: FIG format output has broken bezier splines
Submitter: Andrew Sadler
Date: Mon Sep 1 19:27:34 2003
Subsys: Output generation
Version: 1.8.10
System: *-*-
Severity: minor
Problem:
dot -Tfig ... gives FIG v3.2 files but the spline model used by xFig is different to that user by "dot" (X-spline vs Cubic-Bezier?) the points emitted give a poor approximation to the intended curve.

Attached is a patch to figgen.c which gives significantly better results.

In the attached example note the line from "z1 -> z4".
Input:

digraph partition {
        alpha [label="$\Alpha$"];

        z4 [label="$s_4$"];
        z1 [label="$s_1$"];
        z2 [label="$s_2$"];
        z3 [label="$s_3$"];

        z1 -> z1  [label="$\{abc\}$"];
        z2 -> z2  [label="$\{dgh\}$"];
        z3 -> z3  [label="$\{eij\}$"];
        z4 -> z4  [label="$\{fkl\}$"];

        z2 -> z1  [label="$\{d\}$"];
        z4 -> z2  [label="$\{f\}$"];
        z3 -> z1  [label="$\{e\}$"];
        z4 -> z3  [label="$\{k\}$"];
        z1 -> z4  [label="$\{a\}$"];

}
Comments:
The patch is against the 1.8.10 release version of figgen.c in dotneato/common, though the problem exists in the current release (1.10) but I don't have this source to hand.
Fix:

32,34d31
< /* Number of points to split splines into */
< #define BEZIERSUBDIVISION 6
<
119,134d115
<
< static point
< figfpt(pointf p)
< {
<       point   rv;
<
<       if (Rot == 0) {
<               rv.x = (int)(Scale * p.x);
<               rv.y = Scale * (int)( 2 * PB.UR.y - p.y );
<       } else {
<               rv.x = Scale * (int)( 2 * PB.UR.x - p.y );
<               rv.y = (int)(Scale * p.x);
<       }
<       return rv;
< }
<
472c453
<       int sub_type=4;         /* always 4 for opened X-spline */
---
>       int sub_type=4;         /* always 2 for opened interpolated spline */
487,519d467
<       pointf          p0, V[4];
<       point           p1;
<       int             j, step;
<       int count=0;
<       int size;
<
<       char * buffer;
<       char * buf;
<       buffer = malloc((npoints+1)*(BEZIERSUBDIVISION+1)*20*sizeof(char));
<       buf = buffer;
<
<       V[3].x = A[0].x; V[3].y = A[0].y;
<       /* Write first point in line */
<       count++;
<       p0.x = A[0].x;
<       p0.y = A[0].y;
<       p1 = figfpt(p0);
<       size = sprintf(buf," %d %d",p1.x,p1.y);
<       buf += size;
<       /* write subsequent points */
<       for (i = 0; i+3 < n; i += 3) {
<               V[0] = V[3];
<               for (j = 1; j <= 3; j++) {
<                       V[j].x  = A[i+j].x; V[j].y = A[i+j].y;
<               }
<               for (step = 1; step <= BEZIERSUBDIVISION; step++) {
<                       count++;
<                       p1 = figfpt(Bezier(V, 3, (double)step/BEZIERSUBDIVISION, NULL, NULL));
<                       size = sprintf(buf," %d %d",p1.x,p1.y);
<                       buf += size;
<               }
<       }
<
534,540c482,485
<               count);
<
<       fprintf(Output_file," %sn", buffer); /* print points */
<       free(buffer);
<       for (i = 0; i < count; i++) {
<               fprintf(Output_file," %d", i%(count-1)?1:0); /* -1 on all */
<       }
---
>               npoints);
>       figptarray(A,n,0); /* open shape */
>       for (i = 0; i < n; i++)
>               fprintf(Output_file," %d", i%(n-1)?1:-1); /* -1 on first and last */

Owner: ellson
Status: Fixed (2 Sept 2003)