1 /*	hgraph.c	1.14	(Berkeley) 84/11/27
2  *
3  *     This file contains the graphics routines for converting gremlin
4  * pictures to troff input.
5  */
6 
7 #include "gprint.h"
8 
9 
10 #define  MAXVECT	40
11 #define  pi		3.14159265358979324
12 #define  twopi		(2.0 * pi)
13 #define  len(a, b)	sqrt((b.x-a.x) * (b.x-a.x) + (b.y-a.y) * (b.y-a.y))
14 
15 
16 extern int style[];	/* line and character styles */
17 extern int thick[];
18 extern char *tfont[];
19 extern int tsize[];
20 extern int stipple_index[];	/* stipple font index for stipples 1 - 8 */
21 extern char *stipple;		/* stipple type (cf or ug) */
22 
23 
24 extern double troffscale;	/* imports from main.c */
25 extern point();
26 extern int linethickness;
27 extern int linmod;
28 extern int lastx;
29 extern int lasty;
30 extern int lastyline;
31 extern int ytop;
32 extern int ybottom;
33 extern int xleft;
34 extern int xright;
35 
36 
37 /*----------------------------------------------------------------------------*
38  | Routine:	HGPrintElt (element_pointer, baseline)
39  |
40  | Results:	examines a picture element and calls the appropriate
41  |		routine(s) to print them according to their type.
42  |		After the picture is drawn, current position is (lastx, lasty).
43  *----------------------------------------------------------------------------*/
44 
45 HGPrintElt(element, baseline)
46 ELT *element;
47 int baseline;
48 {
49     register POINT *p1;
50     register POINT *p2;
51     register int length;
52     static int didstipple = 1;	/* flag to prevent multipe messages about no */
53 				/* stipple font requested from being printed */
54     float firstx, firsty;	/* for completing polygons */
55 
56     if ( !DBNullelt(element) && !Nullpoint((p1 = element->ptlist))) {
57 						/* p1 always has first point */
58         if (TEXT(element->type)) {
59             HGSetFont(element->brushf, element->size);
60             HGPutText(element->type, *p1, element->textpt);
61         } else {
62 	    if (element->brushf) {		/* if there is a brush, the */
63 		HGSetBrush(element->brushf);	/* graphics need it set */
64 	    }
65             switch (element->type) {
66 
67                  case ARC:  p2 = PTNextPoint(p1);
68 			    doarc(*p1, *p2, element->size);
69                             break;
70 
71                case CURVE:  tmove(p1);
72 			    printf("\\D'g");
73                             while (!Nullpoint((p1 = PTNextPoint(p1)))) {
74                                 dx((double) p1->x);
75                                 dy((double) p1->y);
76                             }  /* end while */;
77 			    putchar('\'');
78 			    cr();
79                             break;
80 
81 	      case VECTOR:  length = 1;		/* keep track of line length */
82 			    tmove(p1);	   /* so single lines don't get long */
83                             while (!Nullpoint((p1 = PTNextPoint(p1)))) {
84 				printf("\\D'l");
85                                 dx((double) p1->x);
86                                 dy((double) p1->y);
87 				putchar('\'');
88 				if (length++ > MAXVECT) {
89 				    cr();
90 				    tmove (p1);
91 				    length = 1;
92 				}
93                             }  /* end while */
94 			    cr();
95                             break;
96 
97 	     case POLYGON:  tmove(p1);
98 			    if (stipple) {
99 				didstipple = 1;
100 				if (element->brushf) {
101 				    printf("\\D'p %d",
102 					    element->size <= NSTIPPLES ?
103 					    stipple_index[element->size - 1] :
104 					    element->size);
105 				} else {
106 				    printf("\\D'P %d",
107 					    element->size <= NSTIPPLES ?
108 					    stipple_index[element->size - 1] :
109 					    element->size);
110 				}
111 			    } else {
112 				if (didstipple) {
113 				    error("no stipple font requested for picture at line %d", baseline);
114 				    didstipple = 0;
115 				}
116 				printf("\\D'p 0");
117 			    }
118 
119 			    firstx = p1->x;
120 			    firsty = p1->y;
121                             while (!Nullpoint((PTNextPoint(p1)))) {
122 				p1 = PTNextPoint(p1);
123                                 dx((double) p1->x);
124                                 dy((double) p1->y);
125                             }  /* end while */;
126 
127 			    /* close polygon if not done so by user */
128 			    if ((firstx != p1->x) || (firsty != p1->y)) {
129 				dx((double) firstx);
130 				dy((double) firsty);
131 			    }
132 
133 			    putchar('\'');
134 			    cr();
135                             break;
136             }  /* end switch */
137         }  /* end else Text */
138     }  /* end if */
139 }  /* end PrintElt */
140 
141 
142 /*----------------------------------------------------------------------------*
143  | Routine:	HGPutText (justification, position_point, string)
144  |
145  | Results:	given the justification, a point to position with, and a
146  |		string to put, HGPutText first sends the string into a
147  |		diversion, moves to the positioning point, then outputs local
148  |		vertical and horizontal motions as needed to justify the text.
149  |		After all motions are done, the diversion is printed out.
150  *----------------------------------------------------------------------------*/
151 
152 HGPutText(justify,pnt,string)
153 int justify;
154 POINT pnt;
155 register char *string;
156 {
157     int savelasty = lasty;		/* vertical motion for text is to be */
158 					/*   ignored.  save current y here */
159 
160     printf(".nr g8 \\n(.d\n");		/* save current vertical position. */
161     printf(".ds g9 \"");		/* define string containing the text. */
162     while (*string) {					/* put out the string */
163 	if (*string == '\\' && *(string+1) == '\\') {	/* one character at a */
164 	    printf("\\\\\\");				/* time replacing //  */
165 	    string++;					/* by //// to prevent */
166 	}						/* interpretation at  */
167 	printf("%c", *(string++));			/* printout time */
168     }
169     printf("\n");
170     tmove(&pnt);			/* move to positioning point */
171     switch (justify) {
172 					/* local vertical motions */
173 					/* (the numbers here are used to be */
174 					/* somewhat compatible with gprint) */
175         case CENTLEFT:
176         case CENTCENT:
177        case CENTRIGHT:	printf("\\v'0.85n'");		/* down half */
178 			break;
179 
180 	 case TOPLEFT:
181 	 case TOPCENT:
182         case TOPRIGHT:	printf("\\v'1.7n'");		/* down whole */
183     }
184 
185     switch (justify) {
186 					/* local horizontal motions */
187 	 case BOTCENT:
188         case CENTCENT:
189 	 case TOPCENT:	printf("\\h-\\w\\*(g9u/2u");	/* back half */
190 			break;
191 
192         case BOTRIGHT:
193        case CENTRIGHT:
194         case TOPRIGHT:	printf("\\h-\\w\\*(g9u");	/* back whole */
195     }
196 
197     printf("\\&\\*(g9\n");	/* now print the text. */
198     printf(".sp |\\n(g8u\n");	/* restore vertical position */
199     lasty = savelasty;		/* vertical position restored to where it was */
200     lastx = xleft;		/*   before text, also horizontal is at left */
201 } /* end HGPutText */
202 
203 
204 /*----------------------------------------------------------------------------*
205  | Routine:	doarc (center_point, start_point, angle)
206  |
207  | Results:	produces either drawarc command or a drawcircle command
208  |		depending on the angle needed to draw through.
209  *----------------------------------------------------------------------------*/
210 
211 doarc (cp, sp, angle)
212 POINT cp;
213 POINT sp;
214 int angle;
215 {
216 	double radius = len(cp, sp);
217 	double radians;
218 
219 
220 	if (angle) {		/* arc with angle */
221 	    tmove (&sp);		/* starting point first */
222 	    printf("\\D'a");
223 	    dx((double) cp.x);		/* move to center */
224 	    dy((double) cp.y);
225 
226 	    radians = acos((sp.x - cp.x) / radius);	  /* angle of ending */
227 	    if (cp.y - sp.y < 0.0)			 /* point calculated */
228 		radians = twopi - radians;		 /* from start point */
229 	    radians += ((double) angle) * (pi / 180.0);	  /* and arc's angle */
230 	    if (radians > twopi) radians -= twopi;
231 
232 	    dx(cp.x + cos(radians) * radius);	/* move to ending point */
233 	    dy(cp.y - sin(radians) * radius);
234 
235 	} else {		/* a full circle (angle == 0) */
236 	    cp.x -= radius;
237 	    tmove(&cp);			/* move to the left point first */
238 					/* draw circle with given diameter */
239 	    printf("\\D'c %du", (int) ((radius + radius) * troffscale));
240 	}
241 	putchar('\'');		/* finish the command */
242 	cr();
243 }
244 
245 
246 /*----------------------------------------------------------------------------*
247  | Routine:	HGSetFont (font_number, Point_size)
248  |
249  | Results:	ALWAYS outputs a .ft and .ps directive to troff.  This is
250  |		done because someone may change stuff inside a text string.
251  *----------------------------------------------------------------------------*/
252 
253 HGSetFont(font, size)
254 int font, size;
255 {
256     printf(".ft %s\n.ps %d\n", tfont[font-1], tsize[size-1]);
257 }
258 
259 
260 /*----------------------------------------------------------------------------*
261  | Routine:	HGSetBrush (line_mode)
262  |
263  | Results:	generates the troff commands to set up the line width and
264  |		style of subsequent lines.  Does nothing if no change is needed.
265  |
266  | Side Efct:	sets "linmode" and "linethicknes"
267  *----------------------------------------------------------------------------*/
268 
269 HGSetBrush(mode)
270 int mode;
271 {
272     register int printed = 0;
273 
274     if (linmod != style[--mode]) {
275 	printf ("\\D's %du'", linmod = style[mode]);
276 	printed = 1;
277     }
278     if (linethickness != thick[mode]) {
279 	printf ("\\D't %du'", linethickness = thick[mode]);
280 	printed = 1;
281     }
282     if (printed)
283 	cr();
284 }
285 
286 
287 /*----------------------------------------------------------------------------*
288  | Routine:	dx (x_destination)
289  |
290  | Results:	scales and outputs a number for delta x (with a leading space)
291  |		given "lastx" and x_destination.
292  |
293  | Side Efct:	resets "lastx" to x_destination.
294  *----------------------------------------------------------------------------*/
295 
296 dx(x)
297 double x;
298 {
299     register int ix = (int) (x * troffscale);
300 
301     printf(" %du", ix - lastx);
302     lastx = ix;
303 }
304 
305 
306 /*----------------------------------------------------------------------------*
307  | Routine:	dy (y_destination)
308  |
309  | Results:	scales and outputs a number for delta y (with a leading space)
310  |		given "lastyline" and y_destination.
311  |
312  | Side Efct:	resets "lastyline" to y_destination.  Since "line" vertical
313  |		motions don't affect "page" ones, "lasty" isn't updated.
314  *----------------------------------------------------------------------------*/
315 
316 dy(y)
317 double y;
318 {
319     register int iy = (int) (y * troffscale);
320 
321     printf(" %du", iy - lastyline);
322     lastyline = iy;
323 }
324 
325 
326 /*----------------------------------------------------------------------------*
327  | Routine:	tmove (point_pointer)
328  |
329  | Results:	produces horizontal and vertical moves for troff given the
330  |		pointer of a point to move to and knowing the current position.
331  |		Also puts out a horizontal move to start the line.
332  *----------------------------------------------------------------------------*/
333 
334 tmove(ptr)
335 POINT *ptr;
336 {
337     register int ix = (int) (ptr->x * troffscale);
338     register int iy = (int) (ptr->y * troffscale);
339     register int dx;
340     register int dy;
341 
342     if (dy = iy - lasty) {
343 	printf(".sp %du\n", dy);
344     }
345     lastyline = lasty = iy;		/* lasty is always set to current */
346     if (dx = ix - lastx) {
347 	printf("\\h'%du'", dx);
348 	lastx = ix;
349     }
350 }
351 
352 
353 /*----------------------------------------------------------------------------*
354  | Routine:	cr ( )
355  |
356  | Results:	Ends off an input line.  ".sp -1" is also added to counteract
357  |		the vertical move done at the end of text lines.
358  |
359  | Side Efct:	sets "lastx" to "xleft" for troff's return to left margin
360  *----------------------------------------------------------------------------*/
361 
362 cr()
363 {
364     printf("\n.sp -1\n");
365     lastx = xleft;
366 }
367