1219b2ee8SDavid du Colombier #include <u.h> 2219b2ee8SDavid du Colombier #include <libc.h> 3219b2ee8SDavid du Colombier #include <bio.h> 4219b2ee8SDavid du Colombier #include "../common/common.h" 5219b2ee8SDavid du Colombier #include "tr2post.h" 6219b2ee8SDavid du Colombier 7219b2ee8SDavid du Colombier BOOLEAN drawflag = FALSE; 8219b2ee8SDavid du Colombier 9219b2ee8SDavid du Colombier void 10219b2ee8SDavid du Colombier cover(double x, double y) { 11219b2ee8SDavid du Colombier } 12219b2ee8SDavid du Colombier 13219b2ee8SDavid du Colombier void 14219b2ee8SDavid du Colombier drawspline(Biobufhdr *Bp, int flag) { /* flag!=1 connect end points */ 15219b2ee8SDavid du Colombier int x[100], y[100]; 16219b2ee8SDavid du Colombier int i, N; 17219b2ee8SDavid du Colombier /* 18219b2ee8SDavid du Colombier * 19219b2ee8SDavid du Colombier * Spline drawing routine for Postscript printers. The complicated stuff is 20219b2ee8SDavid du Colombier * handled by procedure Ds, which should be defined in the library file. I've 21219b2ee8SDavid du Colombier * seen wrong implementations of troff's spline drawing, so fo the record I'll 22219b2ee8SDavid du Colombier * write down the parametric equations and the necessary conversions to Bezier 23219b2ee8SDavid du Colombier * cubic splines (as used in Postscript). 24219b2ee8SDavid du Colombier * 25219b2ee8SDavid du Colombier * 26219b2ee8SDavid du Colombier * Parametric equation (x coordinate only): 27219b2ee8SDavid du Colombier * 28219b2ee8SDavid du Colombier * 29219b2ee8SDavid du Colombier * (x2 - 2 * x1 + x0) 2 (x0 + x1) 30219b2ee8SDavid du Colombier * x = ------------------ * t + (x1 - x0) * t + --------- 31219b2ee8SDavid du Colombier * 2 2 32219b2ee8SDavid du Colombier * 33219b2ee8SDavid du Colombier * 34219b2ee8SDavid du Colombier * The coefficients in the Bezier cubic are, 35219b2ee8SDavid du Colombier * 36219b2ee8SDavid du Colombier * 37219b2ee8SDavid du Colombier * A = 0 38219b2ee8SDavid du Colombier * B = (x2 - 2 * x1 + x0) / 2 39219b2ee8SDavid du Colombier * C = x1 - x0 40219b2ee8SDavid du Colombier * 41219b2ee8SDavid du Colombier * 42219b2ee8SDavid du Colombier * while the current point is, 43219b2ee8SDavid du Colombier * 44219b2ee8SDavid du Colombier * current-point = (x0 + x1) / 2 45219b2ee8SDavid du Colombier * 46219b2ee8SDavid du Colombier * Using the relationships given in the Postscript manual (page 121) it's easy to 47219b2ee8SDavid du Colombier * see that the control points are given by, 48219b2ee8SDavid du Colombier * 49219b2ee8SDavid du Colombier * 50219b2ee8SDavid du Colombier * x0' = (x0 + 5 * x1) / 6 51219b2ee8SDavid du Colombier * x1' = (x2 + 5 * x1) / 6 52219b2ee8SDavid du Colombier * x2' = (x1 + x2) / 2 53219b2ee8SDavid du Colombier * 54219b2ee8SDavid du Colombier * 55219b2ee8SDavid du Colombier * where the primed variables are the ones used by curveto. The calculations 56219b2ee8SDavid du Colombier * shown above are done in procedure Ds using the coordinates set up in both 57219b2ee8SDavid du Colombier * the x[] and y[] arrays. 58219b2ee8SDavid du Colombier * 59219b2ee8SDavid du Colombier * A simple test of whether your spline drawing is correct would be to use cip 60219b2ee8SDavid du Colombier * to draw a spline and some tangent lines at appropriate points and then print 61219b2ee8SDavid du Colombier * the file. 62219b2ee8SDavid du Colombier * 63219b2ee8SDavid du Colombier */ 64219b2ee8SDavid du Colombier 65219b2ee8SDavid du Colombier for (N=2; N<sizeof(x)/sizeof(x[0]); N++) 66219b2ee8SDavid du Colombier if (Bgetfield(Bp, 'd', &x[N], 0)<=0 || Bgetfield(Bp, 'd', &y[N], 0)<=0) 67219b2ee8SDavid du Colombier break; 68219b2ee8SDavid du Colombier 69219b2ee8SDavid du Colombier x[0] = x[1] = hpos; 70219b2ee8SDavid du Colombier y[0] = y[1] = vpos; 71219b2ee8SDavid du Colombier 72219b2ee8SDavid du Colombier for (i = 1; i < N; i++) { 73219b2ee8SDavid du Colombier x[i+1] += x[i]; 74219b2ee8SDavid du Colombier y[i+1] += y[i]; 75219b2ee8SDavid du Colombier } 76219b2ee8SDavid du Colombier 77219b2ee8SDavid du Colombier x[N] = x[N-1]; 78219b2ee8SDavid du Colombier y[N] = y[N-1]; 79219b2ee8SDavid du Colombier 80219b2ee8SDavid du Colombier for (i = ((flag!=1)?0:1); i < ((flag!=1)?N-1:N-2); i++) { 81219b2ee8SDavid du Colombier endstring(); 82219b2ee8SDavid du Colombier if (pageon()) 83219b2ee8SDavid du Colombier Bprint(Bstdout, "%d %d %d %d %d %d Ds\n", x[i], y[i], x[i+1], y[i+1], x[i+2], y[i+2]); 84219b2ee8SDavid du Colombier /* if (dobbox == TRUE) { /* could be better */ 85219b2ee8SDavid du Colombier /* cover((double)(x[i] + x[i+1])/2,(double)-(y[i] + y[i+1])/2); 86219b2ee8SDavid du Colombier /* cover((double)x[i+1], (double)-y[i+1]); 87219b2ee8SDavid du Colombier /* cover((double)(x[i+1] + x[i+2])/2, (double)-(y[i+1] + y[i+2])/2); 88219b2ee8SDavid du Colombier /* } 89219b2ee8SDavid du Colombier */ 90219b2ee8SDavid du Colombier } 91219b2ee8SDavid du Colombier 92219b2ee8SDavid du Colombier hpos = x[N]; /* where troff expects to be */ 93219b2ee8SDavid du Colombier vpos = y[N]; 94219b2ee8SDavid du Colombier } 95219b2ee8SDavid du Colombier 96219b2ee8SDavid du Colombier void 97219b2ee8SDavid du Colombier draw(Biobufhdr *Bp) { 98219b2ee8SDavid du Colombier 99219b2ee8SDavid du Colombier int r, x1, y1, x2, y2, i; 100219b2ee8SDavid du Colombier int d1, d2; 101219b2ee8SDavid du Colombier 102219b2ee8SDavid du Colombier drawflag = TRUE; 103219b2ee8SDavid du Colombier r = Bgetrune(Bp); 104219b2ee8SDavid du Colombier switch(r) { 105219b2ee8SDavid du Colombier case 'l': 106219b2ee8SDavid du Colombier if (Bgetfield(Bp, 'd', &x1, 0)<=0 || Bgetfield(Bp, 'd', &y1, 0)<=0 || Bgetfield(Bp, 'r', &i, 0)<=0) 107219b2ee8SDavid du Colombier error(FATAL, "draw line function, destination coordinates not found.\n"); 108219b2ee8SDavid du Colombier 109219b2ee8SDavid du Colombier endstring(); 110219b2ee8SDavid du Colombier if (pageon()) 111219b2ee8SDavid du Colombier Bprint(Bstdout, "%d %d %d %d Dl\n", hpos, vpos, hpos+x1, vpos+y1); 112219b2ee8SDavid du Colombier hpos += x1; 113219b2ee8SDavid du Colombier vpos += y1; 114219b2ee8SDavid du Colombier break; 115219b2ee8SDavid du Colombier case 'c': 116219b2ee8SDavid du Colombier if (Bgetfield(Bp, 'd', &d1, 0)<=0) 117219b2ee8SDavid du Colombier error(FATAL, "draw circle function, diameter coordinates not found.\n"); 118219b2ee8SDavid du Colombier 119219b2ee8SDavid du Colombier endstring(); 120219b2ee8SDavid du Colombier if (pageon()) 121219b2ee8SDavid du Colombier Bprint(Bstdout, "%d %d %d %d De\n", hpos, vpos, d1, d1); 122219b2ee8SDavid du Colombier hpos += d1; 123219b2ee8SDavid du Colombier break; 124219b2ee8SDavid du Colombier case 'e': 125219b2ee8SDavid du Colombier if (Bgetfield(Bp, 'd', &d1, 0)<=0 || Bgetfield(Bp, 'd', &d2, 0)<=0) 126219b2ee8SDavid du Colombier error(FATAL, "draw ellipse function, diameter coordinates not found.\n"); 127219b2ee8SDavid du Colombier 128219b2ee8SDavid du Colombier endstring(); 129219b2ee8SDavid du Colombier if (pageon()) 130219b2ee8SDavid du Colombier Bprint(Bstdout, "%d %d %d %d De\n", hpos, vpos, d1, d2); 131219b2ee8SDavid du Colombier hpos += d1; 132219b2ee8SDavid du Colombier break; 133219b2ee8SDavid du Colombier case 'a': 134219b2ee8SDavid du Colombier if (Bgetfield(Bp, 'd', &x1, 0)<=0 || Bgetfield(Bp, 'd', &y1, 0)<=0 || Bgetfield(Bp, 'd', &x2, 0)<=0 || Bgetfield(Bp, 'd', &y2, 0)<=0) 135219b2ee8SDavid du Colombier error(FATAL, "draw arc function, coordinates not found.\n"); 136219b2ee8SDavid du Colombier 137219b2ee8SDavid du Colombier endstring(); 138219b2ee8SDavid du Colombier if (pageon()) 139219b2ee8SDavid du Colombier Bprint(Bstdout, "%d %d %d %d %d %d Da\n", hpos, vpos, x1, y1, x2, y2); 140219b2ee8SDavid du Colombier hpos += x1 + x2; 141219b2ee8SDavid du Colombier vpos += y1 + y2; 142219b2ee8SDavid du Colombier break; 143219b2ee8SDavid du Colombier case 'q': 144219b2ee8SDavid du Colombier drawspline(Bp, 1); 145219b2ee8SDavid du Colombier break; 146219b2ee8SDavid du Colombier case '~': 147219b2ee8SDavid du Colombier drawspline(Bp, 2); 148219b2ee8SDavid du Colombier break; 149219b2ee8SDavid du Colombier default: 150219b2ee8SDavid du Colombier error(FATAL, "unknown draw function <%c>\n", r); 151219b2ee8SDavid du Colombier break; 152219b2ee8SDavid du Colombier } 153219b2ee8SDavid du Colombier } 154*7dd7cddfSDavid du Colombier 155*7dd7cddfSDavid du Colombier #ifdef NOTYET 156*7dd7cddfSDavid du Colombier void 157*7dd7cddfSDavid du Colombier beginpath(Biobufhdr *Bp, int copy) { 158*7dd7cddfSDavid du Colombier 159*7dd7cddfSDavid du Colombier /* 160*7dd7cddfSDavid du Colombier * Called from devcntrl() whenever an "x X BeginPath" command is read. It's used 161*7dd7cddfSDavid du Colombier * to mark the start of a sequence of drawing commands that should be grouped 162*7dd7cddfSDavid du Colombier * together and treated as a single path. By default the drawing procedures in 163*7dd7cddfSDavid du Colombier * *drawfile treat each drawing command as a separate object, and usually start 164*7dd7cddfSDavid du Colombier * with a newpath (just as a precaution) and end with a stroke. The newpath and 165*7dd7cddfSDavid du Colombier * stroke isolate individual drawing commands and make it impossible to deal with 166*7dd7cddfSDavid du Colombier * composite objects. "x X BeginPath" can be used to mark the start of drawing 167*7dd7cddfSDavid du Colombier * commands that should be grouped together and treated as a single object, and 168*7dd7cddfSDavid du Colombier * part of what's done here ensures that the PostScript drawing commands defined 169*7dd7cddfSDavid du Colombier * in *drawfile skip the newpath and stroke, until after the next "x X DrawPath" 170*7dd7cddfSDavid du Colombier * command. At that point the path that's been built up can be manipulated in 171*7dd7cddfSDavid du Colombier * various ways (eg. filled and/or stroked with a different line width). 172*7dd7cddfSDavid du Colombier * 173*7dd7cddfSDavid du Colombier * Color selection is one of the options that's available in parsebuf(), 174*7dd7cddfSDavid du Colombier * so if we get here we add *colorfile to the output file before doing 175*7dd7cddfSDavid du Colombier * anything important. 176*7dd7cddfSDavid du Colombier * 177*7dd7cddfSDavid du Colombier */ 178*7dd7cddfSDavid du Colombier 179*7dd7cddfSDavid du Colombier if (inpath == FALSE) { 180*7dd7cddfSDavid du Colombier endstring(); 181*7dd7cddfSDavid du Colombier getdraw(); 182*7dd7cddfSDavid du Colombier getcolor(); 183*7dd7cddfSDavid du Colombier Bprint(Bstdout, "gsave\n"); 184*7dd7cddfSDavid du Colombier Bprint(Bstdout, "newpath\n"); 185*7dd7cddfSDavid du Colombier Bprint(Bstdout, "%d %d m\n", hpos, vpos); 186*7dd7cddfSDavid du Colombier Bprint(Bstdout, "/inpath true def\n"); 187*7dd7cddfSDavid du Colombier if ( copy == TRUE ) 188*7dd7cddfSDavid du Colombier fprintf(tf, "%s", buf); 189*7dd7cddfSDavid du Colombier inpath = TRUE; 190*7dd7cddfSDavid du Colombier } 191*7dd7cddfSDavid du Colombier } 192*7dd7cddfSDavid du Colombier #endif 193