1 /*	hgraph.c	1.3	(Berkeley) 83/08/03
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	50
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 char *tsize[];
20 
21 
22 extern double scale;		/* imports from main.c */
23 extern double troffscale;
24 extern point();
25 extern int linethickness;
26 extern int linmod;
27 extern int lastx;
28 extern int lasty;
29 extern int lastyline;
30 extern int ytop;
31 extern int ybottom;
32 extern int xleft;
33 extern int xright;
34 
35 
36 /*----------------------------------------------------------------------------*
37  | Routine:	HGPrintElt (element_pointer)
38  |
39  | Results:	examines a picture element and calls the appropriate
40  |		routine(s) to print them according to their type.
41  |		After the picture is drawn, current position is (lastx, lasty).
42  *----------------------------------------------------------------------------*/
43 
44 HGPrintElt(element)
45 ELT *element;
46 {
47     register POINT *p1;
48     register POINT *p2;
49     register int length;
50 
51     if ( !DBNullelt(element) ) {
52 	p1 = element->ptlist;		/* p1 always has first point */
53         if (TEXT(element->type)) {
54             HGSetFont(element->brushf, element->size);
55             HGPutText(element->type, *p1, element->textpt);
56         } else {
57 	    HGSetBrush(element->brushf);	/* graphics need brush set */
58             switch (element->type) {
59 
60                  case ARC:  p2 = PTNextPoint(p1);
61 			    doarc(*p1, *p2, element->size);
62                             break;
63 
64                case CURVE:  tmove(p1);
65 			    printf("\\D'g");
66                             while (!Nullpoint((p1 = PTNextPoint(p1)))) {
67                                 dx((double) p1->x);
68                                 dy((double) p1->y);
69                             }  /* end while */;
70 			    putchar('\'');
71                             break;
72 
73               case VECTOR:  length = 1;		/* keep track of line length */
74 			    tmove(p1);	   /* so single lines don't get long */
75                             while (!Nullpoint((p1 = PTNextPoint(p1)))) {
76 				printf("\\D'l");
77                                 dx((double) p1->x);
78                                 dy((double) p1->y);
79 				putchar('\'');
80 				if (length++ > MAXVECT) {
81 				    tmove (p1);
82 				    length = 1;
83 				}
84                             }  /* end while */
85                             break;
86             }  /* end switch */
87         }  /* end else Text */
88     }  /* end if */
89 }  /* end PrintElt */
90 
91 
92 /*----------------------------------------------------------------------------*
93  | Routine:	HGPutText (justification, position_point, string)
94  |
95  | Results:	given the justification, a point to position with, and a
96  |		string to put, HGPutText first sends the string into a
97  |		diversion, moves to the positioning point, then outputs local
98  |		vertical and horizontal motions as needed to justify the text.
99  |		After all motions are done, the diversion is printed out.
100  *----------------------------------------------------------------------------*/
101 
102 HGPutText(justify,pnt,string)
103 int justify;
104 POINT pnt;
105 char string[];
106 {
107     printf(".di gt\n\\&%s\n.di", string);	/* divert the text. */
108     tmove(&pnt);				/* move to positioning point */
109     switch (justify) {
110 					/* local vertical motions */
111         case CENTLEFT:
112         case CENTCENT:
113        case CENTRIGHT:	printf("\\v'(\\n(dnu+1m)/2u'");	/* down half */
114 			break;
115 
116 	 case TOPLEFT:
117 	 case TOPCENT:
118         case TOPRIGHT:	printf("\\v'\\n(dnu+1m'");		/* down whole */
119     }
120 
121     switch (justify) {
122 					/* local horizontal motions */
123 	 case BOTCENT:
124         case CENTCENT:
125 	 case TOPCENT:	printf("\\h'-\\n(dlu/2u'");	/* back half */
126 			break;
127 
128         case BOTRIGHT:
129        case CENTRIGHT:
130         case TOPRIGHT:	printf("\\h'-\\n(dlu'");	/* back whole */
131     }
132 				/* now print the text.  The (cr) at the end */
133     printf("\\c\n.gt\n");	/* results in a blank line in the output.  It */
134 				/* is necessary to break the "\c" directive. */
135 } /* end HGPutText */
136 
137 
138 /*----------------------------------------------------------------------------*
139  | Routine:	doarc (center_point, start_point, angle)
140  |
141  | Results:	produces either drawarc command or a drawcircle command
142  |		depending on the angle needed to draw through.
143  *----------------------------------------------------------------------------*/
144 
145 doarc (cp, sp, angle)
146 POINT cp;
147 POINT sp;
148 int angle;
149 {
150 	double radius = len(cp, sp);
151 	double radians;
152 
153 
154 	if (angle) {		/* arc with angle */
155 	    tmove (&sp);		/* starting point first */
156 	    printf("\\D'a");
157 	    dx((double) cp.x);		/* move to center */
158 	    dy((double) cp.y);
159 
160 	    radians = acos((sp.x - cp.x) / radius);	  /* angle of ending */
161 	    if (cp.y - sp.y < 0.0)			 /* point calculated */
162 		radians = twopi - radians;		 /* from start point */
163 	    radians += ((double) angle) * (pi / 180.0);	  /* and arc's angle */
164 	    if (radians > twopi) radians -= twopi;
165 
166 	    dx(cp.x + cos(radians) * radius);	/* move to ending point */
167 	    dy(cp.y - sin(radians) * radius);
168 
169 	} else {		/* a full circle (angle == 0) */
170 	    cp.x -= radius;
171 	    tmove(&cp);			/* move to the left point first */
172 					/* draw circle with given diameter */
173 	    printf("\\D'c %du", (int) ((radius + radius) * troffscale));
174 	}
175 	putchar('\'');		/* finish the command */
176 }
177 
178 
179 /*----------------------------------------------------------------------------*
180  | Routine:	HGSetFont (font_number, Point_size)
181  |
182  | Results:	ALWAYS outputs a .ft and .ps directive to troff.  This is
183  |		done because someone may change stuff inside a text string.
184  *----------------------------------------------------------------------------*/
185 
186 HGSetFont(font, size)
187 int font, size;
188 {
189     cr();
190     printf(".ft %s\n.ps %s\n", tfont[font-1], tsize[size-1]);
191 }
192 
193 
194 /*----------------------------------------------------------------------------*
195  | Routine:	HGSetBrush (line_mode)
196  |
197  | Results:	generates the troff commands to set up the line width and
198  |		style of subsequent lines.  Does nothing if no change is needed.
199  |
200  | Side Efct:	sets "linmode" and "linethicknes"
201  *----------------------------------------------------------------------------*/
202 
203 HGSetBrush(mode)
204 int mode;
205 {
206     if (linmod != style[--mode]) {
207 	cr();
208 	printf ("\\D's %du'",linmod = style[mode]);
209     }
210     if (linethickness != thick[mode]) {
211 	cr();
212 	printf ("\\D't %du'", linethickness = thick[mode]);
213     }
214 }
215 
216 
217 /*----------------------------------------------------------------------------*
218  | Routine:	dx (x_destination)
219  |
220  | Results:	scales and outputs a number for delta x (with a leading space)
221  |		given "lastx" and x_destination.
222  |
223  | Side Efct:	resets "lastx" to x_destination.
224  *----------------------------------------------------------------------------*/
225 
226 dx(x)
227 double x;
228 {
229     register int ix = (int) (x * troffscale);
230 
231     printf(" %du", ix - lastx);
232     lastx = ix;
233 }
234 
235 
236 /*----------------------------------------------------------------------------*
237  | Routine:	dy (y_destination)
238  |
239  | Results:	scales and outputs a number for delta y (with a leading space)
240  |		given "lastyline" and y_destination.
241  |
242  | Side Efct:	resets "lastyline" to y_destination.  Since "line" vertical
243  |		motions don't affect "page" ones, "lasty" isn't updated.
244  *----------------------------------------------------------------------------*/
245 
246 dy(y)
247 double y;
248 {
249     register int iy = (int) (y * troffscale);
250 
251     printf(" %du", iy - lastyline);
252     lastyline = iy;
253 }
254 
255 
256 /*----------------------------------------------------------------------------*
257  | Routine:	tmove (point_pointer)
258  |
259  | Results:	produces horizontal and vertical moves for troff given the
260  |		pointer of a point to move to.
261  *----------------------------------------------------------------------------*/
262 
263 tmove(ptr)
264 POINT *ptr;
265 {
266     register int ix = (int) (ptr->x * troffscale);
267     register int iy = (int) (ptr->y * troffscale);
268     register int dx;
269     register int dy;
270 
271     cr();
272     if (dy = iy - lasty) {
273 	printf(".sp %du\n", dy);
274     }
275     lastyline = lasty = iy;
276     if (dx = ix - lastx) {
277 	printf("\\h'%du'", dx);
278 	lastx = ix;
279     }
280 }
281 
282 
283 /*----------------------------------------------------------------------------*
284  | Routine:	cr ( )
285  |
286  | Results:	breaks the output line up to not overrun troff with lines that
287  |		are too long.
288  |
289  | Side Efct:	sets "lastx" to "xleft" for troff's return to left margin
290  *----------------------------------------------------------------------------*/
291 
292 cr()
293 {
294     putchar('\n');
295     lastx = xleft;
296 }
297