1 /*
2 * @(#)short.c 1.2 01/03/85
3 *
4 * Routines for the "short" commands of the SUN Gremlin picture editor.
5 *
6 * Mark Opperman (opcode@monet.BERKELEY)
7 *
8 */
9
10 #include <suntool/tool_hs.h>
11 #include "icondata.h"
12 #include "gremlin.h"
13
14 /* imports from graphics files */
15
16 extern GRClear();
17 extern GRCurrentSet();
18 extern GRCurrentSetOn();
19 extern GRCurrentSetOff();
20 extern GRDisplayPoint();
21 extern GRSetCurve();
22 extern GRSetTextPos();
23
24 /* imports from undodb.c */
25
26 extern UNForget();
27
28 /* imports from display.c */
29
30 extern DISClearSetDisplay();
31 extern DISScreenAdd();
32 extern DISScreenErase();
33
34 /* imports from database files */
35
36 extern ELT *DBCopy();
37 extern ELT *DBCreateElt();
38
39 extern POINT *PTMakePoint();
40 extern POINT *PTMakeTextPoints();
41
42 extern DBDelete();
43 extern DBClearElt();
44 extern DBXform();
45 extern DBBounded();
46 extern DBAddSet();
47 extern DBClearSet();
48
49 /* imports from long.c */
50
51 extern LGIncludeSet();
52 extern CP(); /* clear points */
53 extern CSP(); /* clear show points */
54
55 /* imports from menu.c */
56
57 extern MNHighLt();
58 extern MNUnHighLt();
59
60 extern HiBrush[];
61 extern HiBuffer[];
62 extern HiFont[];
63 extern HiMode[];
64 extern HiSize[];
65
66 int adj[4] = { 0, 0, 1, 2 };
67
68 /* imports from help.c */
69
70 extern help();
71
72 /* imports from text.c */
73
74 extern TxMsgOK();
75 extern TxPutMsg();
76 extern text_putvalue();
77 extern text_restorebuf();
78
79 /* imports from C */
80
81 extern char *malloc();
82
83 /* imports from main.c */
84
85 extern ELT *PICTURE; /* current PICTURE database */
86 extern ELT *cset; /* current set database */
87 extern ELT *MEN[]; /* pointers for user symbols */
88 extern ELT arhead; /* arrow head template */
89
90 extern POINT MENPOINT[]; /* pointers used fo user symbols */
91 extern POINT *POINTLIST; /* accumulated point list */
92
93 extern CBRUSH; /* current brush */
94 extern Gridon; /* grid mode flag */
95 extern SEQ; /* point sequence number */
96 extern Adjustment; /* point adjustment mode */
97 extern GravityOn; /* gravity mode flag */
98 extern CHANGED; /* PICTURE changed flag */
99 extern CsetOn; /* current set displayed on */
100
101 extern (*lastcommand)(); /* previous command */
102 extern lasttext; /* TRUE if previous command wants text */
103 extern struct pixwin *pix_pw;
104
105 extern SHUpdate(), SHAgain(), SHDrawArc(), SHDrawCurve(), SHCopy(),
106 SHDefineSet(), SHErase(), SHSetArea(), SHGravity(),
107 SHGrid(), SHRotate(), SHScale(), SHTranslate(),
108 SHDrawVector(), SHMAdjust(), SHBox(), SHArrow(),
109 SHSave1(), SHSave2(), SHSave3(), SHSave4();
110
111 extern LGUndo();
112
113 #define twoPi 6.2832
114
115 static char nopnt[18] = "not enough points";
116 static char noset[15] = "no current set";
117
118 /*
119 * The following two arrays define the short commands and the routines
120 * that process them.
121 */
122 static char shcmds[] = { '\14', '.', '1', '2', '3', '4', '?', 'a', 'b',
123 'c', 'd', 'e', 'f', 'g', 'q', 'r',
124 's', 't', 'u', 'v', 'w', 'x', 'z', '\0'};
125
126 static (*(shrtns[]))() = {
127 SHUpdate, /* redraw screen */
128 SHAgain, /* repeat last command */
129 SHSave1, /* save user symbol */
130 SHSave2, /* save user symbol */
131 SHSave3, /* save user symbol */
132 SHSave4, /* save user symbol */
133 help, /* help screen */
134 SHDrawArc, /* draw arc */
135 SHDrawCurve, /* draw curve */
136 SHCopy, /* copy current set */
137 SHDefineSet, /* define current set */
138 SHErase, /* erase elements */
139 SHSetArea, /* select area for current set */
140 SHGravity, /* gravity */
141 SHGrid, /* toggle grid display */
142 SHRotate, /* rotate current set */
143 SHScale, /* scale current set */
144 SHTranslate, /* translate current set */
145 LGUndo, /* undo last command */
146 SHDrawVector, /* draw vectors */
147 SHArrow, /* arrowhead */
148 SHBox, /* rectangle from two points */
149 SHMAdjust /* manhattan adjust */
150 };
151
152
153 /*
154 * SHLookup searches a table of characters to find one that matches a
155 * the given character.
156 * If c is a valid command character, its index is returned;
157 * if c is the null command, -2 is returned, else -1 is returned.
158 */
SHLookup(c,table)159 SHLookup(c, table)
160 char c; /* char to be looked up */
161 register char table[]; /* pointer to the valid commands */
162 {
163 register index;
164
165 if ((c == ' ') || (c == '\0'))
166 return(-2);
167
168 for (index=0; table[index] != '\0'; index++) {
169 if (table[index] == c)
170 return(index);
171 if (table[index] > c)
172 return(-1);
173 }
174
175 return(-1);
176 } /* end SHLookup */
177
178
179 /*
180 * This routine reads in, looks up, and executes a short command.
181 */
SHCommand(command)182 SHCommand(command)
183 register char *command;
184 {
185 register index;
186
187 if ((index = SHLookup(*command, shcmds)) == -2)
188 return;
189
190 if (index >= 0) {
191 GRCurrentSetOn();
192 TxMsgOK();
193 (*(shrtns[index]))();
194 }
195 else
196 error("no such command");
197 } /* end SHCommand */
198
199
200 /*
201 * Repeat previous command.
202 */
SHAgain()203 SHAgain()
204 {
205 if (lasttext)
206 text_restorebuf();
207 (*lastcommand)();
208 }
209
210
211 /*
212 * This routine creates and displays a VECTOR element from the
213 * points previously specified.
214 */
SHDrawVector()215 SHDrawVector()
216 {
217 register POINT *p1, *p2;
218 register ELT *e1;
219 POINT *plist;
220 char *txt;
221
222 if (SEQ < 2) { /* not enough points */
223 error(nopnt);
224 return;
225 }
226
227 UNForget();
228
229 DISClearSetDisplay();
230 DBClearSet();
231
232 plist = PTInit();
233 p1 = POINTLIST;
234 (void) PTMakePoint(p1->x, p1->y, &plist);
235 p2 = PTNextPoint(p1);
236
237 while (!Nullpoint(p2)) {
238 (void) PTMakePoint(p2->x, p2->y, &plist);
239 p1 = p2;
240 p2 = PTNextPoint(p1);
241 }
242
243 txt = malloc(1);
244 *txt = '\0';
245 e1 = DBCreateElt(VECTOR, plist, CBRUSH, 0, txt, &PICTURE);
246 DISScreenAdd(e1, pixmask | csetmask);
247 DBAddSet(e1);
248
249 CP();
250 CHANGED = TRUE;
251 } /* end SHDrawVector */
252
253
254 /*
255 * This routine creates and displays an ARC element based on the
256 * points previously defined. If 3 or more points are defined, the
257 * extent of the arc is calculated as the angle formed by the
258 * respective lines through the second and third points and the first
259 * point. If only 2 points are specified, a full circle is drawn.
260 */
SHDrawArc()261 SHDrawArc()
262 {
263 register POINT *p1, *p2;
264 register ELT *e1;
265 POINT *plist;
266 char *txt;
267 float a1, a2, angle, radius;
268
269 if (SEQ < 2) { /* not enough points */
270 error(nopnt);
271 return;
272 }
273
274 UNForget();
275
276 plist = PTInit();
277 p1 = POINTLIST;
278 p2 = PTNextPoint(p1);
279 radius = sqrt((double) ((p2->x - p1->x) * (p2->x - p1->x) +
280 (p2->y - p1->y) * (p2->y - p1->y)));
281 if (radius == 0.0) {
282 error("zero radius");
283 return;
284 }
285
286 CSP();
287
288 if (SEQ == 2) { /* draw full circle */
289 angle = 0;
290 /* Add extra positioning points */
291 (void) PTMakePoint(p1->x, p1->y, &plist);
292 (void) PTMakePoint(p2->x, p2->y, &plist);
293 (void) PTMakePoint(p1->x, p1->y + radius, &plist);
294 (void) PTMakePoint(p1->x, p1->y - radius, &plist);
295 (void) PTMakePoint(p1->x + radius, p1->y, &plist);
296 (void) PTMakePoint(p1->x - radius, p1->y, &plist);
297 }
298 else {
299 (void) PTMakePoint(POINTLIST->x, POINTLIST->y, &plist);
300 p1 = PTNextPoint(POINTLIST);
301 (void) PTMakePoint(p1->x, p1->y, &plist);
302 p2 = PTNextPoint(p1);
303 a1 = atan2((p1->x - POINTLIST->x), (p1->y - POINTLIST->y));
304 a2 = atan2((p2->x - POINTLIST->x), (p2->y - POINTLIST->y));
305 angle = a1 - a2;
306 if (angle < 0.0)
307 angle += twoPi;
308
309 /* Set second point to lie on arc */
310 (void) PTMakePoint((radius * sin(a2) + POINTLIST->x),
311 (radius * cos(a2) + POINTLIST->y), &plist);
312 angle *= 360.0/twoPi; /* convert to degrees */
313 }
314
315 DISClearSetDisplay();
316 DBClearSet();
317
318 txt = malloc(1);
319 *txt = '\0';
320 e1 = DBCreateElt(ARC, plist, CBRUSH, (int) (angle + 0.5), txt, &PICTURE);
321
322 DISScreenAdd(e1, pixmask | csetmask);
323 DBAddSet(e1);
324
325 CP();
326 CHANGED = TRUE;
327 } /* end SHDrawARc */
328
329
330 /*
331 * Draw curve object.
332 */
SHDrawCurve()333 SHDrawCurve()
334 {
335 register POINT *p1;
336 register ELT *e1;
337 POINT *plist;
338 char *txt;
339
340 if (SEQ < 2) {
341 error("need at least 2 points");
342 return;
343 }
344
345 plist = PTInit();
346 p1 = POINTLIST;
347
348 do {
349 (void) PTMakePoint(p1->x, p1->y, &plist);
350 p1 = PTNextPoint(p1);
351 } while (!Nullpoint(p1));
352
353 if (GRSetCurve(plist) != 0) {
354 error("too many consecutive knots at same place");
355 return;
356 }
357
358 UNForget();
359
360 txt = malloc(1);
361 *txt = '\0';
362 e1 = DBCreateElt(CURVE, plist, CBRUSH, 0, txt, &PICTURE);
363
364 DISClearSetDisplay();
365 DBClearSet();
366 DISScreenAdd(e1, pixmask | csetmask);
367 DBAddSet(e1);
368
369 CP();
370 CHANGED = TRUE;
371 } /* end SHDrawCurve */
372
373
374 /*
375 * This routine erases selected elements from the screen and deletes
376 * them from the picture database.
377 */
SHErase()378 SHErase()
379 {
380 register ELT *e1;
381
382 if (DBNullelt(cset)) {
383 error(noset);
384 return;
385 }
386
387 UNForget();
388
389 fasterase();
390
391 while (!DBNullelt(cset)) { /* delete elements in current set */
392 /*
393 DISScreenErase(cset, pixmask | csetmask);
394 */
395 e1 = DBNextofSet(cset);
396 DBDelete(cset, &PICTURE);
397 cset = e1;
398 }
399
400 CHANGED = TRUE;
401 } /* end SHErase */
402
403
404 /*
405 * This routine toggles the gravity mode.
406 */
SHGravity()407 SHGravity()
408 {
409 if (GravityOn = !GravityOn)
410 MNHighLt(HiMode[3]);
411 else
412 MNUnHighLt(HiMode[3]);
413 } /* End GravityOn */
414
415
416 /*
417 * This routine toggles the display of the grid.
418 */
SHGrid()419 SHGrid()
420 {
421 if (Gridon = !Gridon)
422 GRDisplayGrid();
423 else
424 GRBlankGrid();
425 } /* end SHGrid */
426
427
428 /*
429 * Manhattan Adjust -
430 * This routine toggles the adjustment mode.
431 */
SHMAdjust()432 SHMAdjust()
433 {
434 if (Adjustment == MAN) {
435 MNUnHighLt(HiMode[adj[MAN]]);
436 Adjustment = NOADJ;
437 }
438 else {
439 if (Adjustment != NOADJ)
440 MNUnHighLt(HiMode[adj[Adjustment]]);
441 MNHighLt(HiMode[adj[MAN]]);
442 Adjustment = MAN;
443 }
444 } /* end SHMAdjust */
445
446
447 /*
448 * This routine defines the current set based upon previously
449 * defined points to select elements. If no points are specified
450 * the entire picture becomes the current set. In this case, the
451 * old current set is not erased (optimization) and any elements
452 * not in it are added. Otherwise, the new current set can not be
453 * guaranteed to contain the old current set, and so it is erased
454 * and set to empty before adding the new elements.
455 */
SHDefineSet()456 SHDefineSet()
457 {
458 if (SEQ > 0) { /* redefine current set */
459 DISClearSetDisplay();
460 DBClearSet();
461 }
462
463 CSP();
464 LGIncludeSet();
465 } /* end SHDefineSet */
466
467
468 /*
469 * This routine defines the current set by selecting all elements
470 * bounded by a rectangle whose diagonal is defined by specifed points.
471 */
SHSetArea()472 SHSetArea()
473 {
474 if (SEQ < 2) {
475 error(nopnt);
476 return;
477 }
478
479 if (DBNullelt(PICTURE))
480 return;
481
482 DISClearSetDisplay();
483 DBClearSet();
484
485 SHMSetArea();
486 } /* end SHSetArea */
487
488
489 /*
490 * This routine ADDS to the current set all elements bounded by a
491 * rectangle whose diagonal is defined by two specifed points.
492 */
SHMSetArea()493 SHMSetArea()
494 {
495 register ELT *e1;
496 float x1, y1, x2, y2;
497
498 if (SEQ < 2) {
499 error(nopnt);
500 return;
501 }
502
503 if (DBNullelt(PICTURE))
504 return;
505
506 x1 = POINTLIST->x;
507 y1 = POINTLIST->y;
508 x2 = PTNextPoint(POINTLIST)->x;
509 y2 = PTNextPoint(POINTLIST)->y;
510 e1 = PICTURE;
511
512 while (!DBNullelt(e1)) {
513 if (DBBounded(e1, x1, y1, x2, y2)) {
514 DISScreenAdd(e1, csetmask);
515 DBAddSet(e1);
516 }
517 e1 = DBNextElt(e1);
518 }
519
520 CP();
521 } /* end SHMSetArea */
522
523
524 /*
525 * This routine translates the elements in the current set as defined
526 * by points. The translation is accomplished by defining a transformation
527 * matrix and calling DBXform.
528 */
SHTranslate()529 SHTranslate()
530 {
531 register ELT *e1;
532 register POINT *p1;
533 float xmat[3][2];
534
535 if (DBNullelt(cset)) {
536 error(noset);
537 return;
538 }
539
540 if (SEQ < 2) { /* not enough points */
541 error(nopnt);
542 return;
543 }
544
545 UNForget();
546
547 p1 = PTNextPoint(POINTLIST);
548 xmat[0][0] = xmat[1][1] = 1; /* set up translation matrix */
549 xmat[1][0] = xmat[0][1] = 0;
550 xmat[2][0] = p1->x - POINTLIST->x;
551 xmat[2][1] = p1->y - POINTLIST->y;
552 e1 = cset;
553
554 fasterase();
555
556 while (!DBNullelt(e1)) {
557 /*
558 DISScreenErase(e1, pixmask | csetmask);
559 */
560 TxMsgOK();
561 DBXform(e1, xmat, &PICTURE);
562 DISScreenAdd(e1, pixmask | csetmask);
563 e1 = DBNextofSet(e1);
564 }
565
566 CP();
567 CHANGED = TRUE;
568 } /* end SHTranslate */
569
570
571 /*
572 * This routine copies the elements in the current set as defined
573 * by points. To copy, the current set pointer is cleared so that new
574 * elements as added by DBCopy can be used to comprise the new current
575 * set. A pointer is maintained to the old current set which is traversed
576 * to determine the elements to be copied. This process continues for all
577 * points specified.
578 *
579 * NOTE: This assumes that the DBClearSet routine does not alter the
580 * pointers between elements in the set (which is currently true),
581 * and must be changed it this does not hold.
582 */
SHCopy()583 SHCopy()
584 {
585 register ELT *e1, *e2;
586 register POINT *p1, *p2;
587 float xmat[3][2];
588
589 if (DBNullelt(cset)) {
590 error(noset);
591 return;
592 }
593
594 if (SEQ < 2) { /* not enough points */
595 error(nopnt);
596 return;
597 }
598
599 UNForget();
600
601 p1 = POINTLIST;
602 p2 = PTNextPoint(POINTLIST);
603
604 while (!Nullpoint(p2)) {
605 xmat[0][0] = xmat[1][1] = 1; /* set up translation matrix */
606 xmat[1][0] = xmat[0][1] = 0;
607 xmat[2][0] = p2->x - p1->x;
608 xmat[2][1] = p2->y - p1->y;
609 e1 = cset;
610
611 DISClearSetDisplay();
612 DBClearSet(); /* Dependent on Clearset preserving pointers */
613
614 while (!DBNullelt(e1)) {
615 e2 = DBCopy(e1, xmat, &PICTURE);
616 DISScreenAdd(e2, pixmask | csetmask);
617 DBAddSet(e2);
618 e1 = DBNextofSet(e1);
619 }
620
621 p1 = p2;
622 p2 = PTNextPoint(p2);
623 }
624
625 CP();
626 CHANGED = TRUE;
627 } /* end SHCopy */
628
629
630 /*
631 * This routine rotates the elements in the current set as defined
632 * by points. The rotation is accomplished by defining a transformation
633 * matrix and calling DBXform.
634 */
SHRotate()635 SHRotate()
636 {
637 register ELT *elt;
638 register POINT *p1, *p2;
639 POINT pos;
640 float xmat[3][2], angle, s, c;
641
642 if (DBNullelt(cset)) {
643 error(noset);
644 return;
645 }
646
647 if (SEQ < 3) { /* not enough points */
648 error(nopnt);
649 return;
650 }
651
652 UNForget();
653
654 p1 = PTNextPoint(POINTLIST); /* calculate rotation angle */
655 p2 = PTNextPoint(p1);
656 angle = (float) atan2((p2->x - POINTLIST->x), (p2->y - POINTLIST->y)) -
657 (float) atan2((p1->x - POINTLIST->x), (p1->y - POINTLIST->y));
658 s = (float) sin(angle);
659 c = (float) cos(angle);
660
661 /* Define transformation matrix to translate set to origin, rotate,
662 and translate back. */
663
664 xmat[0][0] = c;
665 xmat[0][1] = -s;
666 xmat[1][0] = s;
667 xmat[1][1] = c;
668 xmat[2][0] = (-c) * POINTLIST->x - s * POINTLIST->y + POINTLIST->x;
669 xmat[2][1] = (-c) * POINTLIST->y + s * POINTLIST->x + POINTLIST->y;
670
671 elt = cset;
672 /* DISClearSetDisplay(); */
673
674 fasterase();
675
676 while (!DBNullelt(elt)) {
677 /* DISScreenErase(elt, pixmask); */
678 TxMsgOK();
679 DBXform(elt, xmat, &PICTURE);
680
681 if (TEXT(elt->type)) {
682 GRSetTextPos(elt->textpt, elt->type, elt->brushf, elt->size,
683 elt->ptlist, &pos);
684 elt->ptlist = PTMakeTextPoints(elt->textpt, elt->brushf, elt->size,
685 elt->ptlist, &pos);
686 }
687
688 DISScreenAdd(elt, pixmask | csetmask);
689 elt = DBNextofSet(elt);
690 }
691
692 CP();
693 CHANGED = TRUE;
694 } /* end SHRotate */
695
696
697 /*
698 * This routine scales the elements in the current set as defined
699 * by points. The scaling is accomplished by defining a transformation
700 * matrix and calling DBXform.
701 */
SHScale()702 SHScale()
703 {
704 register ELT *elt;
705 register POINT *p1, *p2;
706 POINT pos;
707 float xmat[3][2], d1, d2, scalex, scaley;
708
709 if (DBNullelt(cset)) {
710 error(noset);
711 return;
712 }
713
714 if (SEQ < 3) { /* not enough points */
715 error(nopnt);
716 return;
717 }
718
719 UNForget();
720
721 p1 = PTNextPoint(POINTLIST);
722 p2 = PTNextPoint(p1);
723 d1 = sqrt(pow((p1->x - POINTLIST->x), 2.0) +
724 pow((p1->y - POINTLIST->y), 2.0));
725 d2 = sqrt( pow((p2->x - POINTLIST->x), 2.0) +
726 pow((p2->y - POINTLIST->y), 2.0));
727
728 if (d1 == 0) {
729 error("infinite scale");
730 return;
731 }
732
733 scalex = scaley = d2 / d1;
734
735 /* create transformation matrix to translate set to origin,
736 performaing the scaling and translating back */
737
738 xmat[0][0] = scalex;
739 xmat[1][1] = scaley;
740 xmat[1][0] = xmat[0][1] = 0;
741 xmat[2][0] = - POINTLIST->x * (scalex - 1.0);
742 xmat[2][1] = - POINTLIST->y * (scaley - 1.0);
743
744 elt = cset;
745 fasterase();
746 /* DISClearSetDisplay(); */
747
748 while (!DBNullelt(elt)) {
749 /* DISScreenErase(elt, pixmask); */
750 TxMsgOK();
751 DBXform(elt, xmat, &PICTURE);
752
753 if (TEXT(elt->type)) {
754 GRSetTextPos(elt->textpt, elt->type, elt->brushf,
755 elt->size, elt->ptlist, &pos);
756 elt->ptlist = PTMakeTextPoints(elt->textpt, elt->brushf,
757 elt->size, elt->ptlist, &pos);
758 }
759
760 DISScreenAdd(elt, pixmask | csetmask);
761 elt = DBNextofSet(elt);
762 }
763
764 CP();
765 CHANGED = TRUE;
766 } /* end SHScale */
767
768
769 /*
770 * This routine redraws the graphics screen by clearing the screen ,
771 * redisplaying the menu and adding each element back to the display.
772 */
SHUpdate()773 SHUpdate()
774 {
775 register ELT *e1;
776 register POINT *plist;
777 POINT pos;
778 register i;
779
780 GRClear(pixmask | csetmask);
781
782 if (Gridon)
783 GRDisplayGrid();
784
785 e1 = PICTURE;
786 while (!DBNullelt(e1)) {
787 if (DBInCset(e1))
788 DISScreenAdd(e1, pixmask | csetmask);
789 else
790 DISScreenAdd(e1, pixmask);
791 e1 = DBNextElt(e1);
792 }
793
794 CsetOn = 1;
795
796 i = 0;
797 plist = POINTLIST;
798 while (!Nullpoint(plist)) {
799 GRDisplayPoint(plist->x, plist->y, i++);
800 plist = PTNextPoint(plist);
801 }
802 } /* end SHUpdate */
803
804
805 /*
806 * This local routine stores the current set in the specified
807 * user symbol.
808 */
809 static
savemen(sym)810 savemen(sym)
811 register sym;
812 {
813 register ELT *elt;
814 float xmat[3][2];
815
816 xmat[0][0] = xmat[1][1] = 1; /* set up copy transformation */
817 xmat[0][1] = xmat[1][0] = 0; /* matrix for no transformation */
818 xmat[2][0] = xmat[2][1] = 0;
819
820 while (!DBNullelt(MEN[sym])) { /* clear out existing symbols */
821 elt = DBNextElt(MEN[sym]);
822 DBClearElt(MEN[sym]);
823 MEN[sym] = elt;
824 }
825
826 elt = cset; /* copy current set to symbol */
827
828 while (!DBNullelt(elt)) {
829 (void) DBCopy(elt, xmat, &(MEN[sym]));
830 elt = DBNextofSet(elt);
831 }
832
833 if (SEQ == 0) { /* no positioning points */
834 MENPOINT[sym].x = 0;
835 MENPOINT[sym].y = 0;
836 }
837 else {
838 MENPOINT[sym].x = POINTLIST->x;
839 MENPOINT[sym].y = POINTLIST->y;
840 }
841
842 if (!DBNullelt(MEN[sym]))
843 MNHighLt(HiBuffer[sym]);
844 else
845 MNUnHighLt(HiBuffer[sym]);
846
847 CP();
848 CHANGED = TRUE;
849 } /* end savemen */
850
851
852 /*
853 * This routine saves the current set in user symbol 1 by
854 * calling savemen.
855 */
SHSave1()856 SHSave1()
857 {
858 savemen(0);
859 }
860
861
862 /*
863 * This routine saves the current set in user symbol 2 by
864 * calling savemen.
865 */
SHSave2()866 SHSave2()
867 {
868 savemen(1);
869 }
870
871
872 /*
873 * This routine saves the current set in user symbol 3 by
874 * calling savemen.
875 */
SHSave3()876 SHSave3()
877 {
878 savemen(2);
879 }
880
881
882 /*
883 * This routine saves the current set in user symbol 4 by
884 * calling savemen.
885 */
SHSave4()886 SHSave4()
887 {
888 savemen(3);
889 }
890
891
892 /*
893 * This routine creates and displays a rectangle whose diagonal is
894 * defined by two points. The routine uses the coordinates of these
895 * points to define a VECTOR element with the appropriate vertices.
896 */
SHBox()897 SHBox()
898 {
899 register POINT *p1, *p2;
900 register ELT *e1;
901 POINT *plist;
902 char *txt;
903
904 if (SEQ < 2) {
905 error("not enough points");
906 return;
907 }
908
909 UNForget();
910
911 p1 = POINTLIST;
912 p2 = PTNextPoint(p1);
913 plist = PTInit(); /* create points for vector elements which define
914 the rectangle */
915 (void) PTMakePoint(p1->x, p1->y, &plist);
916 (void) PTMakePoint(p1->x, p2->y, &plist);
917 (void) PTMakePoint(p2->x, p2->y, &plist);
918 (void) PTMakePoint(p2->x, p1->y, &plist);
919 (void) PTMakePoint(p1->x, p1->y, &plist); /* close rectangle */
920 txt = malloc(1);
921 *txt = '\0';
922
923 DISClearSetDisplay();
924 DBClearSet();
925 e1 = DBCreateElt(VECTOR, plist, CBRUSH, 0, txt, &PICTURE);
926 DISScreenAdd(e1, pixmask | csetmask);
927 DBAddSet(e1);
928
929 CP();
930 CHANGED = TRUE;
931 } /* end SHBox */
932
933
934 /*
935 * This routine draws arrow heads by 'copying' the arrow head template
936 * into the picture appropriately transformed.
937 */
SHArrow()938 SHArrow()
939 {
940 register ELT *e1;
941 POINT p1;
942 register POINT *p2;
943 float xmat[3][2], angle, s, c;
944
945 if (SEQ < 2) { /* not enough points */
946 error(nopnt);
947 return;
948 }
949
950 UNForget();
951
952 p1.x = POINTLIST->x - 1;
953 p1.y = POINTLIST->y;
954 p2 = PTNextPoint(POINTLIST);
955 angle = (float) atan2((p2->x - POINTLIST->x),(p2->y - POINTLIST->y)) -
956 (float) atan2((p1.x - POINTLIST->x),(p1.y - POINTLIST->y));
957 s = (float) sin(angle);
958 c = (float) cos(angle);
959
960 /* Define transformation matrix to translate element from origin
961 and rotate. */
962
963 xmat[0][0] = c;
964 xmat[0][1] = -s;
965 xmat[1][0] = s;
966 xmat[1][1] = c;
967 xmat[2][0] = POINTLIST->x;
968 xmat[2][1] = POINTLIST->y;
969
970 DISClearSetDisplay(); /* the new current set */
971 DBClearSet(); /* clear old set in preparation to make */
972 arhead.brushf = CBRUSH;
973 e1 = DBCopy(&arhead, xmat, &PICTURE);
974 DISScreenAdd(e1, pixmask | csetmask);
975 DBAddSet(e1);
976
977 CP();
978 CHANGED = TRUE;
979 } /* end SHArrow */
980
981 /*
982 * Turn off any "showpoints" and erase the current set by XORing
983 * the cset pixrect with the picture. ONLY to be used when the
984 * current set will be redrawn immediately afterwards.
985 */
fasterase()986 fasterase()
987 {
988 CSP(); /* clear show points */
989
990 GRCurrentSetOff(); /* erase current set */
991 CsetOn = 1; /* ON, the current must be redrawn */
992 GRClear(csetmask);
993 }
994