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