1 /* @(#)graphics2.c 1.2 04/18/83
2 *
3 * Copyright -C- 1982 Barry S. Roitblat
4 *
5 * This file contains more routines for implementing the graphics primitives
6 * for the gremlin picture editor
7 *
8 * (Modified from software written by John Ousterhout for the caesar
9 * program)
10 */
11
12 #include "gremlin.h"
13 #include "grem2.h"
14
15 /* imports from graphics1.c */
16
17 extern GRsetlinestyle(), GRsetcharstyle(), GRsetcharsize(),
18 GRsetpos(), GRoutxy20(), GRSetRead();
19 extern FILE *display;
20 extern int curx, cury, rmask, GrXMax, GrYMax, charysize, charxsize, descenders;
21
22 /* imports from main.c */
23
24 extern error();
25
26 /* The following is available to the outside world */
27
28 int artmode;
29
GRVector(point1,point2,style)30 GRVector(point1,point2,style)
31 POINT *point1,*point2;
32 int style;
33 {
34 GRsetlinestyle(style);
35 GRsetpos((int) point1->x,(int) point1->y);
36 putc('A',display); /* Draw vector absolute */
37 GRoutxy20((int) point2->x,(int) point2->y);
38 curx = point2->x;
39 cury = point2->y;
40 (void) fflush(display);
41 }
42
43
RelativeVector(x,y)44 static RelativeVector(x, y)
45 float x, y;
46 /*
47 * This routine outputs the proper character sequence to the AED
48 * to draw a vector in the current line style and from the current position
49 * to the point (x, y).
50 */
51
52 {
53 int nextx, nexty;
54
55 nextx = (int) x;
56 nexty = (int) y;
57
58 putc('A', display); /* draw vector absolute */
59 GRoutxy20(nextx, nexty); /* output coordinates */
60 curx = nextx;
61 cury = nexty;
62 } /* end RelativeVector */
63
64
65 #define pi 3.14159265357
66 #define log2_10 3.321915
67
68 int
GRArc(center,cpoint,angle,style)69 GRArc(center,cpoint,angle,style)
70 POINT *center, *cpoint;
71 double angle;
72 int style;
73 {
74 double xs, ys, radius, resolution, t1, epsalon, fullcircle;
75 double degreesperpoint;
76 int i, extent;
77 POINT next;
78
79 xs = cpoint->x - center->x;
80 ys = cpoint->y - center->y;
81 if ((xs == 0) && (ys == 0)) /* radius = 0 */
82 {
83 error("zero radius");
84 return(-1);
85 }
86
87 /* calculate drawing parameters */
88
89 radius = sqrt(xs * xs + ys * ys);
90 t1 = floor(log10(radius) * log2_10);
91 resolution = pow(2.0, t1);
92 epsalon = 1.0 / resolution;
93 fullcircle = ceil(2 * pi * resolution);
94 degreesperpoint = 360.0 / fullcircle;
95
96 if (angle == 0)
97 {
98 extent = fullcircle;
99 if ( (int) radius < 128) /* manageable by AED hardware */
100 {
101 GRsetpos((int) center->x, (int) center->y);
102 GRsetlinestyle(style);
103 putc('O',display); /* draw circle */
104 putc(((int) radius) &0377, display);
105 return(0);
106 }
107 }
108 else extent = angle/degreesperpoint;
109
110 GRsetpos((int) cpoint->x, (int) cpoint->y);
111 GRsetlinestyle(style);
112 for (i=0; i<extent; ++i)
113 {
114 xs -= epsalon * ys;
115 next.x = xs + center->x ; /* round */
116 ys += epsalon * xs;
117 next.y = ys + center->y ; /* round */
118 RelativeVector(next.x, next.y);
119 } /* end for */;
120 return(0);
121 } /* end GRArc */;
122
123
124 #define MAXPOINTS 200
125
Paramaterize(x,y,h,n)126 static Paramaterize(x, y, h, n)
127 float x[MAXPOINTS], y[MAXPOINTS], h[MAXPOINTS];
128 int n;
129 /* This routine calculates parameteric values for use in calculating
130 * curves. The parametric values are returned in the array u. The values
131 * are an approximation of cumulative arc lengths of the curve (uses cord
132 * length). For additional information, see paper cited below.
133 */
134
135 {
136 int i,j;
137 float u[MAXPOINTS];
138
139 for (i=1; i<=n; ++i)
140 {
141 u[i] = 0;
142 for (j=1; j<i; ++j)
143 {
144 u[i] += sqrt(pow((double) (x[j+1] - x[j]), (double) 2.0)
145 + pow((double) (y[j+1] - y[j]), (double) 2.0));
146 }
147 }
148 for (i=1; i<n; ++i)
149 h[i] = u[i+1] - u[i];
150 } /* end Paramaterize */
151
PeriodicSpline(h,z,dz,d2z,d3z,npoints)152 static PeriodicSpline(h, z, dz, d2z, d3z, npoints)
153 float h[MAXPOINTS], z[MAXPOINTS]; /* Point list and paramaterization */
154 float dz[MAXPOINTS]; /* to return the 1st derivative */
155 float d2z[MAXPOINTS], d3z[MAXPOINTS]; /* 2nd and 3rd derivatives */
156 int npoints; /* number of valid points */
157 /*
158 * This routine solves for the cubic polynomial to fit a spline
159 * curve to the the points specified by the list of values.
160 * The Curve generated is periodic. The alogrithms for this
161 * curve are from the "Spline Curve Techniques" paper cited below.
162 */
163
164 {
165 float d[MAXPOINTS];
166 float deltaz[MAXPOINTS], a[MAXPOINTS], b[MAXPOINTS];
167 float c[MAXPOINTS], r[MAXPOINTS], s[MAXPOINTS];
168 int i;
169
170 /* step 1 */
171 for (i=1; i<npoints; ++i)
172 {
173 if (h[i] != 0)
174 deltaz[i] = (z[i+1] - z[i]) / h[i];
175 else
176 deltaz[i] = 0;
177 }
178 h[0] = h[npoints-1];
179 deltaz[0] = deltaz[npoints-1];
180
181 /* step 2 */
182 for (i=1; i<npoints-1; ++i)
183 {
184 d[i] = deltaz[i+1] - deltaz[i];
185 }
186 d[0] = deltaz[1] - deltaz[0];
187
188 /* step 3a */
189 a[1] = 2 * (h[0] + h[1]);
190 if (a[1] == 0) return(-1); /* 3 consecutive knots at same point */
191 b[1] = d[0];
192 c[1] = h[0];
193 for (i=2; i<npoints-1; ++i)
194 {
195 a[i] = 2 * (h[i-1] + h[i]) - pow((double) h[i-1], (double) 2.0)
196 / a[i-1];
197 if (a[i] == 0) return(-1); /* 3 consec knots at same point */
198 b[i] = d[i-1] - h[i-1] * b[i-1]/a[i-1];
199 c[i] = -h[i-1] * c[i-1]/a[i-1];
200 }
201
202 /* step 3b */
203 r[npoints-1] = 1;
204 s[npoints-1] = 0;
205 for (i=npoints-2; i>0; --i)
206 {
207 r[i] = -(h[i] * r[i+1] + c[i])/a[i];
208 s[i] = (6 * b[i] - h[i] * s[i+1])/a[i];
209 }
210
211 /* step 4 */
212 d2z[npoints-1] = (6 * d[npoints-2] - h[0] * s[1]
213 - h[npoints-1] * s[npoints-2])
214 / (h[0] * r[1] + h[npoints-1] * r[npoints-2]
215 + 2 * (h[npoints-2] + h[0]));
216 for (i=1; i<npoints-1; ++i)
217 {
218 d2z[i] = r[i] * d2z[npoints-1] + s[i];
219 }
220 d2z[npoints] = d2z[1];
221
222 /* step 5 */
223 for (i=1; i<npoints; ++i)
224 {
225 dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i+1])/6;
226 if (h[i] != 0)
227 d3z[i] = (d2z[i+1] - d2z[i])/h[i];
228 else
229 d3z[i] = 0;
230 }
231 return(0);
232 } /* end PeriodicSpline */
233
234
NaturalEndSpline(h,z,dz,d2z,d3z,npoints)235 static NaturalEndSpline(h, z, dz, d2z, d3z, npoints)
236 float h[MAXPOINTS], z[MAXPOINTS]; /* Point list and parameterization */
237 float dz[MAXPOINTS]; /* to return the 1st derivative */
238 float d2z[MAXPOINTS], d3z[MAXPOINTS]; /* 2nd and 3rd derivatives */
239 int npoints; /* number of valid points */
240 /*
241 * This routine solves for the cubic polynomial to fit a spline
242 * curve the the points specified by the list of values. The alogrithms for
243 * this curve are from the "Spline Curve Techniques" paper cited below.
244 */
245
246 {
247 float d[MAXPOINTS];
248 float deltaz[MAXPOINTS], a[MAXPOINTS], b[MAXPOINTS];
249 int i;
250
251 /* step 1 */
252 for (i=1; i<npoints; ++i)
253 {
254 if (h[i] != 0)
255 deltaz[i] = (z[i+1] - z[i]) / h[i];
256 else
257 deltaz[i] = 0;
258 }
259 deltaz[0] = deltaz[npoints-1];
260
261 /* step 2 */
262 for (i=1; i<npoints-1; ++i)
263 {
264 d[i] = deltaz[i+1] - deltaz[i];
265 }
266 d[0] = deltaz[1] - deltaz[0];
267
268 /* step 3 */
269 a[0] = 2 * (h[2] + h[1]);
270 if (a[0] == 0) return(-1); /* 3 consec knots at same point */
271 b[0] = d[1];
272 for (i=1; i<npoints-2; ++i)
273 {
274 a[i] = 2 * (h[i+1] + h[i+2]) - pow((double) h[i+1],(double) 2.0)
275 / a[i-1];
276 if (a[i] == 0) return(-1); /* 3 consec knots at same point */
277 b[i] = d[i+1] - h[i+1] * b[i-1]/a[i-1];
278 }
279
280 /* step 4 */
281 d2z[npoints] = d2z[1] = 0;
282 for (i=npoints-1; i>1; --i)
283 {
284 d2z[i] = (6 * b[i-2] - h[i] *d2z[i+1])/a[i-2];
285 }
286
287 /* step 5 */
288 for (i=1; i<npoints; ++i)
289 {
290 dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i+1])/6;
291 if (h[i] != 0)
292 d3z[i] = (d2z[i+1] - d2z[i])/h[i];
293 else
294 d3z[i] = 0;
295 }
296 return(0);
297 } /* end NaturalEndSpline */
298
299
300 #define PointsPerInterval 16
301
GRCurve(pointlist,style)302 GRCurve(pointlist,style)
303 POINT *pointlist;
304 int style;
305 /*
306 * This routine generates a smooth curve through a set of points. The
307 * method used is the parametric spline curve on unit knot mesh described
308 * in "Spline Curve Techniques" by Patrick Baudelaire, Robert Flegal, and
309 * Robert Sproull -- Xerox Parc.
310 */
311 {
312 float h[MAXPOINTS];
313 float x[MAXPOINTS], y[MAXPOINTS], dx[MAXPOINTS], dy[MAXPOINTS];
314 float d2x[MAXPOINTS], d2y[MAXPOINTS], d3x[MAXPOINTS], d3y[MAXPOINTS];
315 float t, t2, t3, xinter, yinter;
316 POINT *ptr;
317 int numpoints, i, j, k, stat;
318
319 GRsetlinestyle(style);
320 GRsetpos((int) pointlist->x, (int) pointlist->y);
321
322 /* Copy point list to array for easier access */
323
324 ptr = pointlist;
325 for (i=1; (!Nullpoint(ptr)); ++i)
326 {
327 x[i] = ptr->x;
328 y[i] = ptr->y;
329 if (i >= MAXPOINTS - 1) break;
330 ptr = PTNextPoint(ptr);
331 }
332
333 /* Solve for derivatives of the curve at each point
334 * separately for x and y (parametric).
335 */
336 numpoints = i - 1;
337 Paramaterize(x, y, h, numpoints);
338 stat = 0;
339 if ((x[1] == x[numpoints]) && (y[1] == y[numpoints]))/* closed curve */
340 {
341 stat |= PeriodicSpline(h, x, dx, d2x, d3x, numpoints);
342 stat |= PeriodicSpline(h, y, dy, d2y, d3y, numpoints);
343 }
344 else
345 {
346 stat |= NaturalEndSpline(h, x, dx, d2x, d3x, numpoints);
347 stat |= NaturalEndSpline(h, y, dy, d2y, d3y, numpoints);
348 }
349 if (stat != 0) return(-1); /* error occurred */
350
351 /* generate the curve using the above information and
352 * PointsPerInterval vectors between each specified knot.
353 */
354
355 for (j=1; j<numpoints; ++j)
356 {
357 for (k=0; k<=PointsPerInterval; ++k)
358 {
359 t = (float) k * h[j] / (float) PointsPerInterval;
360 t2 = t * t;
361 t3 = t * t * t;
362 xinter = x[j] + t * dx[j] + t2 * d2x[j]/2.0
363 + t3 * d3x[j]/6.0;
364 yinter = y[j] + t * dy[j] + t2 * d2y[j]/2.0
365 + t3 * d3y[j]/6.0;
366 RelativeVector(xinter, yinter);
367 } /* end for k */
368 } /* end for j */
369 return(0);
370 } /* end GRCurve */
371
372
373
GRPutText(justify,point1,font,size,string,pos)374 GRPutText(justify,point1,font,size,string,pos)
375 int justify, font, size;
376 POINT *point1, *pos;
377 char string[];
378 {
379 int length, nchars, i;
380
381 GRsetcharstyle(font);
382 GRsetcharsize(size);
383 nchars = strlen(string);
384 length = nchars * charxsize ;
385 switch (justify)
386 {
387 case BOTLEFT: pos->x = point1->x;
388 pos->y = point1->y;
389 break;
390 case BOTCENT: pos->x = point1->x - (length/2);
391 pos->y = point1->y;
392 break;
393 case BOTRIGHT: pos->x = point1->x - length;
394 pos->y = point1->y;
395 break;
396 case CENTLEFT: pos->x = point1->x;
397 pos->y = point1->y - (charysize/2);
398 break;
399 case CENTCENT: pos->x = point1->x - (length/2);
400 pos->y = point1->y - (charysize/2);
401 break;
402 case CENTRIGHT: pos->x = point1->x - length;
403 pos->y = point1->y - (charysize/2);
404 break;
405 case TOPLEFT: pos->x = point1->x;
406 pos->y = point1->y - charysize + descenders;
407 break;
408 case TOPCENT: pos->x = point1->x - (length/2);
409 pos->y = point1->y - charysize + descenders;
410 break;
411 case TOPRIGHT: pos->x = point1->x - length;
412 pos->y = point1->y - charysize + descenders;
413 break;
414 }
415 if ((pos->x < 0) || ((pos->x + length - charxsize) > GrXMax))
416 {
417 TxPutMsg("\7string too long");
418 }
419 if (( pos->y + charysize ) > GrYMax )
420 pos->y = GrYMax - charysize;
421 if (pos->y < 0) pos->y = 0;
422 GRsetpos((int) pos->x, (int) pos->y);
423 putc('\6',display); /* enter text mode */
424 for ( i=0; i<nchars; ++i )
425 {
426 putc(string[i],display);
427 }
428 fputs("\33Q", display); /* re-enter graphics mode */
429 GRoutxy20(curx,cury);
430 (void) fflush(display);
431 } /* end PutText */;
432
433
GRClear(mask)434 GRClear(mask)
435 int mask;
436 /*
437 * This routine clears the memory planes enabled by mask.
438 * The read mask is first set to avoid an annoying flash when the
439 * clear is performed.
440 */
441
442 {
443 int savemask;
444
445 savemask = rmask;
446 GRSetRead(rmask & ~mask);
447 GRsetwmask(mask);
448 putc('~',display);
449 GRSetRead(savemask);
450 (void) fflush(display);
451 } /* end GRClear */
452
GRDisplayPoint(x,y,number,mark)453 GRDisplayPoint(x, y, number, mark)
454 int x, y, number, mark;
455 /*
456 * This routine displays a point on the screen. The point is
457 * displayed as a '+' centered about the point (x,y) and followed by
458 * number.
459 */
460
461 {
462 POINT p1, p2;
463 int psize;
464
465 if (artmode) psize = 1;
466 else psize = halfpoint;
467 GRsetwmask(pointmask);
468 p1.y = p2.y = y;
469 p1.x = x - psize;
470 p2.x = x + psize;
471 GRVector(&p1, &p2, mark);
472 p1.x = p2.x = x;
473 p1.y = y - psize;
474 p2.y = y + psize;
475 GRVector(&p1, &p2, mark);
476 if ( !artmode )
477 {
478 GRsetcharsize(pointchar);
479 GRsetpos( (x + numspace), (y - charysize/2 + 1) );
480 fprintf(display,"\6%d\33",number);
481 }
482 GRsetpos(x, y);
483 (void) fflush(display);
484 } /* end DisplayPoint */
485
486
487
GRErasePoint(x,y,number)488 GRErasePoint(x, y, number)
489 int x, y, number;
490 /*
491 * This routine erases the specified point by redrawing it in the
492 * background color
493 */
494
495 {
496 GRDisplayPoint(x, y, number, eraseany);
497 } /* end ErasePoint */
498
499
GRBlankPoints()500 GRBlankPoints()
501 /*
502 * This routine clears all displayed points by clearing
503 * the memory plane they are written on.
504 */
505
506 {
507 GRClear(pointmask);
508 } /* end BlankPoints */
509