Appendix A: A routine for plotting arrows

Previous: 27 How I came to write this book
Next: Appendix B: A routine for plotting grids

Appendix A: A routine for plotting arrows

This routine draws 10 different arrow types (N_ARROW) which may be colour filled (N_FILL = 1) or simply outlined (N_FILL = 0). KOLOUR is the colour value returned by a call to RGB@. The apex of the arrow is at real world coordinates (X1,Y1) and the real world tail is at (X2,Y2). The ‘database’ of relative X and Y coordinates is set up in the DATA statements, with the start position in the database for each type of arrow specified in the array of N.

The routine could be easily modified to draw a different coloured outline to the fill, but in that case the fill should probably be done before the outline. The source code is:

      OPTIONS (INTL, DREAL)

      SUBROUTINE ARROW (X1, Y1, X2, Y2, N_ARROW, KOLOUR, N_FILL) 
C     ******************************************************************
C     *     THIS SUBROUTINE PLOTS 10 DIFFERENT ARROW SYMBOLS.          *
C     *     THERE ARE TEN OF THESE, CALLED BY                          *
C     *     THE VALUE OF THE PARAMETER "N". THE APEX OF THE            *
C     *     ARROW IS PLOTTED AT (X1,Y1) AND THE PEN FINISHES           *
C     *     AT COORDINATES (X2,Y2) WHICH IS THE TAIL.                  *
C     ******************************************************************
      DIMENSION X(72),Y(72),NBASE(11), iXX(70), iYY(70)  ! Internal info
      COMMON / CW_SCALING / iWIN_Handle, IXRES, IYRES, SCXY, XMID, YMID
C       CW+ Graphics handle, screen pixels in x & y, scale factor in 
C       real-world coords per pixel, real world x & y coords of centre
C       of screen.
      INCLUDE 
C     ----------------------------- STATEMENT FUNCTIONS ----------------
       IPOSX(XX) = (XX-XMID)/SCXY + IXRES/2 + 0.5
       IPOSY(YY) = IYRES/2 - (YY-YMID)/SCXY + 0.5
C     ------------------------------------------------------------------
        DATA X/1.0,    1.0,    0.0,    1.0,    1.0,
     1         0.5,    0.5,    0.0,    0.5,    0.5,    1.0,
     2         1.0,    1.0,    0.0,    1.0,    1.0,
     3         1.0,    1.15,   0.0,    1.15,   1.0,
     4         1.0,    1.0,    0.35,   0.65,   0.35,   0.0,
     5         0.35,   0.65,   0.35,   1.0,    1.0,
     6         1.0,    1.0,    0.475,  0.665,  0.5,    0.0,
     7         0.5,    0.665,  0.475,  1.0,    1.0,
     8         1.0,    1.0,    0.5,    0.57,   0.0,    0.57,
     9         0.5,    1.0,    1.0,
     A         0.0,    0.25,   0.0,    0.25,   0.0,    1.0,
     B         1.0,    1.914,  1.414,  0.0,    1.414,  1.914,  1.0,
     C         1.0,    2.0,    1.0,    0.0,    1.0,    2.0,    1.0/
        DATA Y/0.0,    0.1667, 0.0,   -0.1667, 0.0,
     1         0.0,    0.0833, 0.0,   -0.0833, 0.0,    0.0,
     2         0.0,    1.8,    0.0,   -1.8,    0.0,
     3         0.0,    0.1667, 0.0,   -0.1667, 0.0,
     4         0.0,    0.1,    0.1,    0.375,  0.375,  0.0,
     5        -0.375, -0.375, -0.1,   -0.1,    0.0,
     6         0.0,    0.14,   0.14,   0.335,  0.5,    0.0,
     7        -0.5,   -0.335, -0.14,  -0.14,   0.0,
     8         0.0,    0.075,  0.075,  0.175,  0.0,   -0.175,
     9        -0.075, -0.075,  0.0,
     A         0.0,    0.5,    0.0,   -0.5,    0.0,    0.0,
     B         0.0,    0.914,  1.414,  0.0,   -1.414, -0.914,  0.0,
     C         0.0,    1.5,    1.5,    0.0,   -1.5,   -1.5,    0.0/
        DATA NBASE / 1, 6, 12, 17, 22, 33, 44, 53, 59, 66, 73/
C       ----------------------------------------------------------------
        DELX   = X2-X1
        DELY   = Y2-Y1
        VECTOR = DSQRT (DELX*DELX + DELY*DELY)
        IF (DELX .EQ. 0.0D0) DELX = 1.0D-10
        ANGLE = DATAN2 (DELY, DELX)
        CA    = DCOS (ANGLE)
        SA    = DSIN (ANGLE)
        NB    = N_Arrow
        IF (NB .LT. 1  .OR.  NB .GT. 10) NB = 2

        K   = NBASE (NB)
        LB  = 1

15      CONTINUE
         XK  =  X(K)
         YK  =  Y(K)
         XP  = (XK*CA - YK*SA)*VECTOR + X1
         YP  = (XK*SA + YK*CA)*VECTOR + Y1

        IF (K .EQ. NBASE(NB)) THEN
           iXX(1) = iPOSX(XP)
           iYY(1) = iPOSY(YP)
           K  = K + 1
           GO TO 15
        ELSE IF (K .LT. NBASE(NB+1)) THEN
           LB = LB + 1
           iXX(LB) = iPOSX(XP)
           iYY(LB) = iPOSY(YP)
           K  = K + 1
           GO TO 15
        ELSE IF (K .EQ. NBASE(NB+1)) THEN
           CALL DRAW_POLYLINE@ (iXX, iYY, LB, KOLOUR)
              IF (N_Fill .NE. 0) THEN
              iXX(LB+1) = iXX(1)
              iYY(LB+1) = iYY(1)
              CALL DRAW_FILLED_POLYGON@ (iXX, iYY, LB+1, KOLOUR)
              ENDIF
        ENDIF

        RETURN
        END


The routine was originally written in the era of pen plotters and these arrows are intended to be drawn as relatively large features on a drawing surface. Typical examples of use include North arrows, road markings, load vectors on structures et cetera. It can easily be modified to permit a different colour for the outline than for the fill, but if that is done, I suggest drawing the outline after the fill and that might change the logic slightly.

Engineering drawings indicate scale by a number of means including by drawing grids (Appendix B), scale bars and dimension lines. The arrowheads in the arrow routine above are not intended for dimension line work because the arrowheads scale with the length of the shaft. The same basic methodology can of course be used for dimension lines, but you would have to write your own routine. If you do so, then the scaling of the head is typically a function of the line thickness rather than the length of line. The dots per inch setting can be obtained for the drawing surface and the head scaled appropriately. If the line is relatively thick then you should not carry it through to the complete end, because that will give a square tip to the arrow head and it is better to hold the line back so that a proper point appears on the arrow. When applying a numeric dimension to a dimension line it is necessary to blank out the middle of the dimension line so that the text is readable and not overwritten over the line itself. When using raster graphics, you can draw the whole line and then draw over it in white, but on a vector graphics device like a pen plotter, you have to compute the gap and not draw it in the first instance.

It is possible to modify this routine to draw arbitrary symbols instead of arrows, in which case it is only really necessary to change the lists of coordinates to match the symbols, for example 5 and 6 pointed stars etc. I had the equivalent routine to draw characters, but ClearWin+ has ample facilities (unlike the pen plotters of old, where the font scaling was different from manufacturer to manufacturer, there might not be italic or Greek letters, and so on).

Figure A.1 A selection of arrows drawn over a grid (see Appendix B).
Basket
Empty
 
Copyright © 1999-2024 Silverfrost Limited