1655593d0Sbostic /*-
2655593d0Sbostic * %sccs.include.proprietary.c%
3655593d0Sbostic */
4655593d0Sbostic
5956c6c94Sralph #ifndef lint
6*37071c60Sbostic static char sccsid[] = "@(#)crtplot.c 4.7 (Berkeley) 01/07/94";
7655593d0Sbostic #endif /* not lint */
8956c6c94Sralph
9956c6c94Sralph /*
10956c6c94Sralph This plotting routine interprets plot commands and outputs them onto
11956c6c94Sralph intelligent terminals (ie, terminals with clear screen and cursor
12956c6c94Sralph addressability. It uses the curses library. It should be compiled
13956c6c94Sralph as follows:
14956c6c94Sralph cc crtdriver.c crtplot.c -lcurses -ltermcap -lm
15956c6c94Sralph Note: This requires as slightly modified driver from the standard driver
16956c6c94Sralph because some function names conflicted with the curses library.
17956c6c94Sralph (That's what you get when you have a flat name space!)
18956c6c94Sralph */
19956c6c94Sralph
20956c6c94Sralph
21956c6c94Sralph #include <curses.h>
22956c6c94Sralph #include <math.h>
23956c6c94Sralph #include <signal.h>
246f136989Storek #include <stdlib.h>
256f136989Storek #include <string.h>
26956c6c94Sralph
27956c6c94Sralph
28956c6c94Sralph /* These map from plot routine coordinates to screen coordinates. */
29956c6c94Sralph #define scaleX(x) (int) ((x-lowX)*rangeX + 0.5)
30956c6c94Sralph #define scaleY(y) (int) (LINES-0.5 - ((y-lowY)*rangeY))
31956c6c94Sralph
32956c6c94Sralph #define plot_movech(y, x, ch) { plot_move(x, y); plot_addch(ch); }
33956c6c94Sralph
34956c6c94Sralph
35956c6c94Sralph static double lowX, rangeX; /* min and range of x */
36956c6c94Sralph static double lowY, rangeY; /* min and range of y */
37956c6c94Sralph static int lastX, lastY; /* last point plotted */
38956c6c94Sralph
39956c6c94Sralph
40956c6c94Sralph /* This routine just moves the cursor. */
screen_move(y,x)41956c6c94Sralph screen_move(y, x)
42956c6c94Sralph int x,y;
43956c6c94Sralph {
44956c6c94Sralph /* must check for automatic wrap at last col */
45956c6c94Sralph if (!AM || (y < LINES -1) || (x < COLS -1)) {
46956c6c94Sralph mvcur(lastY, lastX, y, x);
47956c6c94Sralph lastY = y;
48956c6c94Sralph lastX = x;
49956c6c94Sralph }
50956c6c94Sralph }
51956c6c94Sralph
52956c6c94Sralph
53956c6c94Sralph /* This routine assumes the cursor is positioned correctly. */
plot_addch(ch)54956c6c94Sralph plot_addch(ch)
55956c6c94Sralph char ch;
56956c6c94Sralph {
5763b2a11cSelan _putchar(ch);
58956c6c94Sralph if (++lastX >= COLS) {
59956c6c94Sralph if (AM) {
60956c6c94Sralph lastX = 0;
61956c6c94Sralph lastY++;
62956c6c94Sralph } else {
63956c6c94Sralph lastX = COLS - 1;
64956c6c94Sralph }
65956c6c94Sralph }
66956c6c94Sralph }
67956c6c94Sralph
68956c6c94Sralph
69956c6c94Sralph
70956c6c94Sralph
71956c6c94Sralph /* See the curses manual for what is been done and why. */
openpl()72956c6c94Sralph openpl()
73956c6c94Sralph {
74956c6c94Sralph char *sp;
7574d2773bSbostic void closepl();
76956c6c94Sralph
77956c6c94Sralph gettmode();
78956c6c94Sralph if (sp=getenv("TERM"))
79956c6c94Sralph setterm(sp);
80956c6c94Sralph signal(SIGINT, closepl);
81956c6c94Sralph
82956c6c94Sralph }
83956c6c94Sralph
84956c6c94Sralph
85956c6c94Sralph
86956c6c94Sralph
8774d2773bSbostic void
closepl()88956c6c94Sralph closepl()
89956c6c94Sralph {
90956c6c94Sralph signal(SIGINT, SIG_IGN);
91956c6c94Sralph /* Leave cursor at top of screen. */
92956c6c94Sralph mvcur(LINES-1, COLS-1, 0, 0);
93956c6c94Sralph endwin();
94956c6c94Sralph exit(0);
95956c6c94Sralph }
96956c6c94Sralph
97956c6c94Sralph
98956c6c94Sralph
plot_move(x,y)99956c6c94Sralph plot_move(x,y)
100956c6c94Sralph int x, y;
101956c6c94Sralph {
102956c6c94Sralph screen_move(scaleY(y), scaleX(x));
103956c6c94Sralph }
104956c6c94Sralph
105956c6c94Sralph
106956c6c94Sralph
line(x0,y0,x1,y1)107956c6c94Sralph line(x0, y0, x1, y1)
108956c6c94Sralph int x0, y0, x1, y1;
109956c6c94Sralph {
110956c6c94Sralph plot_movech(y0, x0, '*');
111956c6c94Sralph dda_line('*', scaleX(x0), scaleY(y0), scaleX(x1), scaleY(y1));
112956c6c94Sralph }
113956c6c94Sralph
label(str)114956c6c94Sralph label(str)
115956c6c94Sralph char *str;
116956c6c94Sralph {
117956c6c94Sralph reg i, length;
118956c6c94Sralph
119956c6c94Sralph if ( (length=strlen(str)) > (COLS-lastX) )
120956c6c94Sralph length = COLS - lastX;
121956c6c94Sralph for (i=0; i<length; ++i)
122956c6c94Sralph plot_addch(str[i]);
123956c6c94Sralph }
124956c6c94Sralph
125eb9b57b3Sbostic void
cputchar(ch)126eb9b57b3Sbostic cputchar(ch)
127eb9b57b3Sbostic int ch;
128eb9b57b3Sbostic {
129eb9b57b3Sbostic (void)putchar(ch);
130eb9b57b3Sbostic }
131eb9b57b3Sbostic
plot_erase()132956c6c94Sralph plot_erase()
133956c6c94Sralph {
134956c6c94Sralph /*
135956c6c94Sralph Some of these functions probably belong in openpl(). However, if the
136956c6c94Sralph input is being typed in, putting them in openpl would not work
137956c6c94Sralph since "noecho", etc would prevent (sort of) input. Notice that
138956c6c94Sralph the driver calls openpl before doing anything. This is actually
139956c6c94Sralph wrong, but it is what whoever originally wrote the driver decided
140956c6c94Sralph to do. (openpl() in libplot does nothing -- that is the main problem!)
141956c6c94Sralph */
142eb9b57b3Sbostic tputs(TI, 0, cputchar);
143eb9b57b3Sbostic tputs(VS, 0, cputchar);
144956c6c94Sralph
145956c6c94Sralph noecho();
146956c6c94Sralph nonl();
147eb9b57b3Sbostic tputs(CL, LINES, cputchar);
148956c6c94Sralph mvcur(0, COLS-1, LINES-1, 0);
149956c6c94Sralph lastX = 0;
150956c6c94Sralph lastY = LINES-1;
151956c6c94Sralph }
152956c6c94Sralph
point(x,y)153956c6c94Sralph point(x, y)
154956c6c94Sralph int x,y;
155956c6c94Sralph {
156956c6c94Sralph plot_movech(y, x, '*');
157956c6c94Sralph }
158956c6c94Sralph
159956c6c94Sralph
cont(x,y)160956c6c94Sralph cont(x, y)
161956c6c94Sralph int x,y;
162956c6c94Sralph {
163956c6c94Sralph dda_line('*', lastX-1, lastY, scaleX(x), scaleY(y));
164956c6c94Sralph }
165956c6c94Sralph
166956c6c94Sralph
space(x0,y0,x1,y1)167956c6c94Sralph space(x0, y0, x1, y1)
168956c6c94Sralph int x0, y0, x1, y1;
169956c6c94Sralph {
170956c6c94Sralph lowX = (double) x0;
171956c6c94Sralph lowY = (double) y0;
172956c6c94Sralph rangeX = COLS/(double) (x1 - x0);
173956c6c94Sralph rangeY = LINES/(double) (y1 - y0);
174956c6c94Sralph }
175956c6c94Sralph
176956c6c94Sralph
linemod(string)177956c6c94Sralph linemod(string)
178956c6c94Sralph char *string;
179956c6c94Sralph {
180956c6c94Sralph }
181956c6c94Sralph
182956c6c94Sralph
183956c6c94Sralph
184956c6c94Sralph /* See Neuman & Sproul for explanation and rationale. */
185956c6c94Sralph /* Does not plot first point -- assumed that it is already plotted */
dda_line(ch,x0,y0,x1,y1)186956c6c94Sralph dda_line(ch, x0, y0, x1, y1)
187956c6c94Sralph char ch;
188956c6c94Sralph int x0, y0, x1, y1; /* already transformed to screen coords */
189956c6c94Sralph {
190956c6c94Sralph int length, i;
191956c6c94Sralph double deltaX, deltaY;
192956c6c94Sralph double x, y;
193956c6c94Sralph
194956c6c94Sralph length = abs(x1 - x0);
195956c6c94Sralph if (abs(y1 -y0) > length)
196956c6c94Sralph length = abs(y1 - y0);
197956c6c94Sralph
198956c6c94Sralph if (length == 0)
199956c6c94Sralph return;
200956c6c94Sralph
201956c6c94Sralph deltaX = (double) (x1 - x0)/(double) length;
202956c6c94Sralph deltaY = (double) (y1 - y0)/(double) length;
203956c6c94Sralph
204956c6c94Sralph x = (double) x0 + 0.5;
205956c6c94Sralph y = (double) y0 + 0.5;
206956c6c94Sralph
207956c6c94Sralph for (i=0; i < length; ++i)
208956c6c94Sralph {
209956c6c94Sralph x += deltaX;
210956c6c94Sralph y += deltaY;
211956c6c94Sralph screen_move((int) floor(y), (int) floor(x));
212956c6c94Sralph plot_addch(ch);
213956c6c94Sralph }
214956c6c94Sralph }
215956c6c94Sralph
216956c6c94Sralph
circle(xc,yc,r)217956c6c94Sralph circle (xc,yc,r)
218956c6c94Sralph int xc,yc,r;
219956c6c94Sralph {
220956c6c94Sralph arc(xc,yc, xc+r,yc, xc-r,yc);
221956c6c94Sralph arc(xc,yc, xc-r,yc, xc+r,yc);
222956c6c94Sralph }
223956c6c94Sralph
224956c6c94Sralph
225956c6c94Sralph /* should include test for equality? */
226956c6c94Sralph #define side(x,y) (a*(x)+b*(y)+c > 0.0 ? 1 : -1)
227956c6c94Sralph
arc(xc,yc,xbeg,ybeg,xend,yend)228956c6c94Sralph arc(xc,yc,xbeg,ybeg,xend,yend)
229956c6c94Sralph int xc,yc,xbeg,ybeg,xend,yend;
230956c6c94Sralph {
231956c6c94Sralph double r, radius, costheta, sintheta;
232956c6c94Sralph double a, b, c, x, y, tempX;
233956c6c94Sralph int right_side;
234956c6c94Sralph
235956c6c94Sralph xbeg -= xc; ybeg -= yc;
236956c6c94Sralph xend -= xc; yend -= yc;
237956c6c94Sralph
238956c6c94Sralph /* probably should check that arc is truely circular */
239956c6c94Sralph /* Note: r is in screen coordinates. */
240956c6c94Sralph r = sqrt( rangeX*rangeX*xbeg*xbeg + rangeY*rangeY*ybeg*ybeg);
241956c6c94Sralph
242956c6c94Sralph /*
243956c6c94Sralph This method is reasonably efficient, clean, and clever.
244956c6c94Sralph The easy part is generating the next point on the arc. This is
245956c6c94Sralph done by rotating the points by the angle theta. Theta is chosen
246956c6c94Sralph so that no rotation will cause more than one pixel of a move.
247956c6c94Sralph This corresponds to a triangle having 'x side' of r and 'y side' of 1.
248956c6c94Sralph The rotation is done (way) below inside the loop.
249956c6c94Sralph */
250956c6c94Sralph if (r <= 1.0) {
251956c6c94Sralph /* radius is mapped to length < 1*/
252956c6c94Sralph point(xc,yc);
253956c6c94Sralph return;
254956c6c94Sralph }
255956c6c94Sralph
256956c6c94Sralph radius = sqrt(r*r + 1.0);
257956c6c94Sralph sintheta = 1.0/radius;
258956c6c94Sralph costheta = r/radius;
259956c6c94Sralph
260956c6c94Sralph /*
261956c6c94Sralph The hard part of drawing an arc is figuring out when to stop.
262956c6c94Sralph This method works by drawing the line from the beginning point
263956c6c94Sralph to the ending point. This splits the plane in half, with the
264956c6c94Sralph arc that we wish to draw on one side of the line. If we evaluate
265956c6c94Sralph side(x,y) = a*x + b*y + c, then all of the points on one side of the
266956c6c94Sralph line will result in side being positive, and all the points on the
267956c6c94Sralph other side of the line will result in side being negative.
268956c6c94Sralph
269956c6c94Sralph We want to draw the arc in a counter-clockwise direction, so we
270956c6c94Sralph must find out what the sign of "side" is for a point which is to the
271956c6c94Sralph "right" of a line drawn from "beg" to "end". A point which must lie
272956c6c94Sralph on the right is [xbeg + (yend-ybeg), ybeg - (xend-xbeg)]. (This
273956c6c94Sralph point is perpendicular to the line at "beg").
274956c6c94Sralph
275956c6c94Sralph Thus, we compute "side" of the above point, and then compare the
276956c6c94Sralph sign of side for each new point with the sign of the above point.
277956c6c94Sralph When they are different, we terminate the loop.
278956c6c94Sralph */
279956c6c94Sralph
280956c6c94Sralph a = (double) (yend - ybeg);
281956c6c94Sralph b = (double) (xend - xbeg);
282956c6c94Sralph c = (double) (yend*xbeg - xend*ybeg);
283956c6c94Sralph right_side = side(xbeg + (yend-ybeg),
284956c6c94Sralph ybeg - (xend-xbeg) );
285956c6c94Sralph
286956c6c94Sralph x = xbeg;
287956c6c94Sralph y = ybeg;
288956c6c94Sralph plot_move(xbeg+xc, ybeg+yc);
289956c6c94Sralph do {
290956c6c94Sralph dda_line('*',lastX-1, lastY, scaleX(xc + x), scaleY(yc + y ));
291956c6c94Sralph /*
292956c6c94Sralph screen_move( scaleY(yc + y), scaleX(xc + x) );
293956c6c94Sralph plot_addch('*');
294956c6c94Sralph */
295956c6c94Sralph tempX = x;
296956c6c94Sralph x = x*costheta - y*sintheta;
297956c6c94Sralph y = tempX*sintheta + y*costheta;
298956c6c94Sralph } while( side(x,y) == right_side );
299956c6c94Sralph }
300