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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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