#%%A-RCB-0094-SL-1 GRAPHIC -- DEFINITIONS # GRAPHIC must maintain its own mode table both to handle the #special features of logs and rotation, and to retain the #min, max and range values. It needs the latter since it #associates them with the X and Y axes instead of with the #plotter hardware axes. This means that BORDER and other GRAPHIC #routines will only work correctly if SCALE has been used to define #the plot. We could get the values from MODE, but we would have #to process them to get our orientation. # DEFINE ORIENT MODTAB(1) # Plot orientation variable DEFINE XLOG MODTAB(2) # Flag for Log X axis DEFINE YLOG MODTAB(3) # " " " Y " DEFINE XMAXU XMODTB(1) # Xmax -- User units DEFINE XMINU XMODTB(2) # Xmin -- " " DEFINE YMAXU XMODTB(3) # Ymax -- " " DEFINE YMINU XMODTB(4) # Ymin -- " " DEFINE XSCALI XMODTB(5) # X range -- Plotter units DEFINE YSCALI XMODTB(6) # Y " -- " " DEFINE IDIM 4 # Dimension for MODTAB DEFINE RDIM 6 # Dimension for XMODTAB DEFINE UFACTOR YMODTB(1) # Plotter units per inch DEFINE TALL 0 # Erect orientation DEFINE WIDE 1 # Rotated orientation DEFINE CLR 0 DEFINE SET 1 DEFINE XSELECT 1 DEFINE YSELECT 2 DEFINE SCALED 0 # Code for scaled data DEFINE SCADELTA 2 # Code for scaled delta data DEFINE UNSCALED 4 # Code for unscaled data DEFINE DOWN 9 # Causes MOVE to draw with pen down DEFINE TICKLONG 0.08 # Length of scale ticks -- inches DEFINE TICKGAP 0.1 # Space between numbers and ticks -- inches DEFINE TICKWIDE 1 # Width of ticks -- dots DEFINE CHAR BYTE DEFINE TYPER 5 DEFINE MAXSTR 80 DEFINE MAXMES 70 DEFINE SHORTSTR 20 DEFINE SAME 9999.0 DEFINE INTEG 'I' DEFINE FIXED 'F' DEFINE FLOATING 'E' DEFINE GENERAL 'G' DEFINE ZERO "60 DEFINE TRACEBK CALLPLERR2(LOG(-1.0)) DEFINE MMFACTOR 25.4 # mm per inch DEFINE SMALLHT 0.05 # Height for tiny letters -- inches DEFINE SMALLWID 0.04 # Width for tiny letters -- inches DEFINE TOLERANCE 1.0E-6 # Tolerance for arithmetic in SPAN DEFINE DEFAULTPATTERN "10421 # Pattern for GRID #%%A-RCB-0094-SL-1 GRAPHIC -- ANNOTE #.SUBR 6 SUBROUTINE ANNOTE (X,Y,STRING) REAL X,Y # Co-ordinates of lower left of string # in plotter units BYTE STRING (MAXSTR) # String to be printed #.DESCR #ANNOTE prints the string at the specified location. ANNOTE may be #used to print in any direction, and with any character orientation, if #the user looks after the angles. The initial setting of the angles #causes printing along the user X axis. The angles may always be reset #by calling ROTATE with the appropriate argument. ## INCLUDE MODTAB/LI CHAR STRNG1(MAXSTR) CALL PLSWAP (X,Y,X1,Y1) N = LONG(STRING) IF (N >> 0) [ DO I = 1,N+1 [STRNG1(I) = STRING(I) ] # Must move string since CALL NOTE (X1,Y1,STRNG1,N) # NOTE modifies it. ] RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- AXIS #.SUBR 6 SUBROUTINE AXIS (N) INTEGER N # Line width for axes #.DESCR #AXIS draws X and Y axes through user (0,0). AXIS is not recommended for #log-log or semilog plots since user (0,0) is off the plot (and #probably off the page). Also, AXIS will be messy with a linear plot #in which the origin is off the plot. ## INCLUDE MODTAB CALL MODE (-10,PATTN,DUM,DUM); CALL MODE (10,-1.0,SAME,SAME) CALL VECTOR (XMINU,0.0,XMAXU,0.0,N) CALL VECTOR (0.0,YMINU,0.0,YMAXU,N) CALL MODE (10,PATTN,SAME,SAME) RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- BORDER #.SUBR 6 SUBROUTINE BORDER (N) INTEGER N # Width of border #.DESCR #BORDER draws a border around the plot. ## INCLUDE MODTAB CALL MODE (-10,PATTN,DUM,DUM); CALL MODE (10,-1.0,SAME,SAME) CALL MOVE (0.0,0.0,N,SCALED) DO I = 1,4 [ IF (I<=2) X = XSCALI; ELSE X = 0.0 IF (I==2!I==3) Y = YSCALI; ELSE Y = 0.0 CALL MOVE (X,Y,,SCALED) ] CALL MODE (10,PATTN,SAME,SAME) RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- BOTTOM REAL FUNCTION BOTTOM (MINU,INCR,LOGFLG) REAL MINU, # Minimum value on plot -- user units INCR # Step size INTEGER LOGFLG # Flag for log scale # Returns position of lowest on-scale tick mark. For linear scales, #this is defined so that 0.0 is on a mark. # X is initialized to a value slightly greater than MINU, then #incremented down. IF (LOGFLG==SET) X = 100.0*MINU ELSE X = MINU + INCR - MOD (MINU,INCR) WHILE (X >= MINU) X = PLINCR (X,-INCR,LOGFLG) RETURN ( PLINCR(X,INCR,LOGFLG) ) END #%%A-RCB-0094-SL-1 GRAPHIC -- CHRSIZ #.SUBR 7 SUBROUTINE CHRSIZ (HEIGHT,WIDTH) REAL HEIGHT, # Desired character height in plotter units WIDTH # " " width " " " #.DESCR #CHRSIZ sets the specified character size. ## CALL MODE (4,HEIGHT,WIDTH,SAME) RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- CORNER #.SUBR 7 SUBROUTINE CORNER (X,Y) REAL X,Y # Co-ordinates of new software origin in # plotter units #.DESCR #CORNER sets the software origin to (X,Y) plotter units, relative #to the hardware origin. This establishes the lower left corner of #the plot. The hardware origin is in the lower left corner of the page #in its vertical orientation, about 3/8 inches from the left side and #5/16 inches from the bottom. The plotting area is 7.75 x 10.25 inches #(198 x 260 mm approx.) The initial software origin is (0.75,0.75). ## CALL PLSWAP (X,Y,X1,Y1) CALL MODE (-2,DUM,XLOW,XOFF) # Use DRAW to avoid swapping XLOW and CALL MODE (-3,DUM,YLOW,YOFF) # YLOW. CALL DRAW (X1+XLOW-XOFF, Y1+YLOW-YOFF, 1,1000) # If you mess with RETURN # the offsets, we look after it. END #%%A-RCB-0094-SL-1 GRAPHIC -- CTITLE #.SUBR 7 SUBROUTINE CTITLE (Y,STRING) REAL Y # Y co-ordinate for lower left corner # of STRING BYTE STRING(MAXSTR) # String to be printed #.DESCR #CTITLE prints the string at Y, centred on the plotting limits #(normally, the page). ## INCLUDE MODTAB REAL HIGH, LOW, SPAC IF (ORIENT==TALL) CALL MODE (-2,HIGH,LOW,DUM) ELSE CALL MODE (-3,HIGH,LOW,DUM) CALL MODE (-6,DUM,SPAC,DUM) X = 0.5*(HIGH+LOW-SPAC*LONG(STRING)) CALL ANNOTE (X,Y,STRING) RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- ENDJOB #.SUBR 4 SUBROUTINE ENDJOB #.DESCR #ENDJOB should be called after all plotting has been completed. ## CALL DRAW (0,0,0,9999) RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- ENDPLT #.SUBR 4 SUBROUTINE ENDPLT #.DESCR #ENDPLT should be called after each individual plot. #It prints the date and time in the lower right corner and terminates #the plot. ## INCLUDE MODTAB # Character size and line width are saved and restored. CHAR WORK(20), STRING(40); DATA WORK/19*' ',0/ CALL DATE (WORK); CALL TIME (WORK(12)) ENCODE (40,10,STRING) WORK 10 FORMAT (30X,T1,'CRNL-RCB ',20A1) CALL MODE (-4,OLDHT,OLDWID,DUM); CALL MODE (-6,OLDLIN,DUM,DUM) CALL CHRSIZ (SMALLHT*UFACTOR,SMALLWID*UFACTOR) CALL MODE (6,1.0,SAME,SAME) IF (ORIENT==TALL) [ CALL MODE (-2,X,DUM,DUM); CALL MODE (-3,DUM,Y,DUM) ] ELSE [ CALL MODE (-2,Y,DUM,DUM); CALL MODE (-3,X,DUM,DUM) Y = -Y ] # Different corner for WIDE format. CALL MODE (-6,DUM,SPAC,DUM) CALL ANNOTE (X-SPAC*LONG(STRING),Y,STRING) CALL CHRSIZ (OLDHT,OLDWID); CALL MODE (6,OLDLIN,SAME,SAME) CALL DRAW (0.0,0.0,1,9000) RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- FMTYPE CHAR FUNCTION FMTYPE (STRING,N) CHAR STRING(MAXSTR) # String containing the format to be analysed INTEGER N # Returns the format field width # FMTYPE returns the type of the format, as 'I', 'F', 'E', or 'G'. # N is set to the field width specified in the format. # Formats expected are strings of the forms: # 'Iw', 'Fw.d', 'Ew.d', '1PEw.d', 'Gw.d', '1PGw.d' CHAR CODES(4); DATA CODES /INTEG,FIXED,FLOATING,GENERAL/ NCHAR = LONG (STRING) I = 1; J = 1 WHILE (I<=NCHAR && STRING(I)^=CODES(J)) [ J = 1 + MOD(J,4) IF (J==1) I = I + 1 ] # Search the string for a code. N = 0 FOR (I=I+1; I<=NCHAR && STRING(I)>=ZERO; I=I+1) # Build number until N = 10*N + STRING(I) - ZERO # non-numeric encountered. # This makes N the field width. IF (N==0) [ CALL PLERR1 ('FMTYPE -- BAD FORMAT -- EXIT') TRACEBK CALL EXIT ] RETURN (CODES(J)) END #%%A-RCB-0094-SL-1 GRAPHIC -- GRID #.SUBR 14 SUBROUTINE GRID (XINCR,YINCR,PATTN,N) REAL XINCR, # Step in the X direction YINCR # " " " Y " INTEGER PATTN, # Binary mask for dots in grid lines -- see # fig. 3-6 of the Versatec manual [1]. Use: # -1 or "177777 for solid lines # "032323 for every second dot # "010421 for every fourth dot -- DEFAULT # 255 or "377 for dashes N # Line width -- DEFAULTs to 1 #.DESCR #GRID draws grid lines with spacings XINCR and YINCR. GRID may #be called twice with different increments and widths to obtain #heavy and light rulings. PATTN permits the user to produce various #forms of dotted and dashed lines to make the grid unobtrusive. #For a log axis, the interpretation of XINCR and YINCR is defined #by the function PLINCR. The original line mask is saved and restored. ## INCLUDE MODTAB REAL X,Y,PATTN1; INTEGER N1 CALL ARGCNT (NARGS) IF (NARGS>=3 && NULARG (PATTN)==1) PATTN1=PATTN; ELSE PATTN1=DEFAULTPATTERN IF (NARGS>=4 && NULARG (N)==1) N1 = N; ELSE N1 = 1 CALL MODE (-10,OLDPAT,DUM,DUM); CALL MODE (10,PATTN1,SAME,SAME) FOR (X=BOTTOM(XMINU,XINCR,XLOG); X<=XMAXU; X=PLINCR(X,XINCR,XLOG)) CALL VECTOR (X,YMINU, X,YMAXU,N1) FOR (Y=BOTTOM(YMINU,YINCR,YLOG); Y<=YMAXU; Y=PLINCR(Y,YINCR,YLOG)) CALL VECTOR (XMINU,Y, XMAXU,Y,N1) CALL MODE (10,OLDPAT,SAME,SAME) RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- LOGX #.SUBR 6 SUBROUTINE LOGX (I) INTEGER I # 1 to set log scale, 0 to clear #.DESCR #LOGX sets the X axis to logarithmic. #.NP #LOGY sets the Y axis to logarithmic. ## INCLUDE MODTAB IF (I==1) XLOG = SET ELSE XLOG = CLR RETURN ENTRY LOGY (I) IF (I==1) YLOG = SET ELSE YLOG = CLR RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- LONG INTEGER FUNCTION LONG (STRING) CHAR STRING (MAXSTR) # String to be examined # Returns the length of the string. The string must be delimited # by a zero byte. FOR (I=0; I<< MAXSTR && STRING(I+1)^=0; I=I+1) ; RETURN (I) END #%%A-RCB-0094-SL-1 GRAPHIC -- MARK SUBROUTINE MARK (VALUE,SELECT) REAL VALUE # Value of variable co-ordinate INTEGER SELECT # 1 for X axis, 2 for Y axis # Puts ticks on both borders. INCLUDE MODTAB IF (SELECT == XSELECT) [ A = 0.0; B = TICKLONG*UFACTOR # Set up for X = VALUE; Y = YMAXU ] # high tick. ELSE [ A = TICKLONG*UFACTOR; B = 0.0 # May be horiz X = XMAXU; Y = VALUE ] # or vert. CALL MOVE (X,Y,TICKWIDE) # Position and draw high tick. CALL MOVE (-A,-B,,SCADELTA) IF (SELECT == XSELECT) Y = YMINU; ELSE X = XMINU CALL MOVE (X,Y,TICKWIDE) # Position and draw low tick. CALL MOVE (A,B,,SCADELTA) IF (TICKLONG >>0.0) CALL MOVE (X,Y,1) # Position at low end of tick. RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- MOVE #.SUBR 13 SUBROUTINE MOVE (X,Y,N,CODE) REAL X,Y # Co-ordinates of the point INTEGER N, # 0 -- To move only # 1-8 -- To move and select line width # 9 -- To move with the pen down -- DEFAULT # 1000 -- To move and reset the origin # 600n -- For point-plot with dot size n CODE # 0,2,4 for scaled, scaled delta [1] and # unscaled data. DEFAULT is unscaled. #.DESCR #MOVE moves the pen to the specified position. Only N=9 will #cause a line to be drawn. Unscaled data means data in user units, #while scaled data refers to plotter units. Omitted parameters take #their default values. ## REAL X1,Y1; INTEGER N1,CODE1 CALL ARGCNT (NARGS) IF (NARGS>=3 && NULARG(N)==1) N1 = N; ELSE N1 = DOWN IF (NARGS>=4 && NULARG(CODE)==1) CODE1 = CODE; ELSE CODE1 = UNSCALED CALL PLSWAP (X,Y,X1,Y1,CODE1) CALL DRAW (X1,Y1,1,CODE1*110+N1) RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- PHPOSN #.SUBR 8 SUBROUTINE PHPOSN (DBSTEP,STEP,X,Y) REAL DBSTEP, # Y axis step in user units STEP, # " " " " plotter units X,Y # Co-ordinates for ANNOTE of 0 dB line, to right # of plot. #.DESCR #PHPOSN is an aid for plotting the phase curve of a Bode plot on #the same grid as the magnitude. DBSTEP should be the dB spacing of major #divisions. Using STEP, X, and Y, the user can then annotate the phase #grid marks to the right of the grid. #.NP #If DBSTEP corresponds to 90 degrees, then the y value for #phase (in units of dB) is obtained as #.SEG # Y = PHZERO + PHASE*DBSTEP/90.0 #.EEG #where PHZERO is the dB value for zero phase. ## INCLUDE MODTAB DY = (YMAXU-YMINU)/YSCALI STEP = DBSTEP/DY CALL MODE (-6,DUM,DUM,YSPAC) X = XSCALI + TICKGAP*UFACTOR IF (TICKLONG << 0.0) X = X - TICKLONG*UFACTOR Y = -(YMINU/DY) - YSPAC/4.0 RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- PLEDGE #.SUBR 6 SUBROUTINE PLEDGE (N) INTEGER N # Line width for border #.DESCR #PLEDGE draws a border around the plotting limits. ## REAL XMAX,XMIN,YMAX,YMIN CALL MODE (-10,PATTN,DUM,DUM); CALL MODE (10,-1.0,SAME,SAME) CALL MODE (-2,XMAX,XMIN,DUM) CALL MODE (-3,YMAX,YMIN,DUM) CALL DRAW (XMIN,YMIN,1,N) DO I = 1,4 [ IF (I<=2) X = XMAX; ELSE X = XMIN IF (I==2!I==3) Y = YMAX; ELSE Y = YMIN CALL DRAW (X,Y,1,9) ] CALL MODE (10,PATTN,SAME,SAME) RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- PLERR1 SUBROUTINE PLERR1 (STRING) CHAR STRING (MAXMES) # String containing error message # Prints the message and a traceback header. WRITE (TYPER,10) (STRING(I), I=1,LONG(STRING)) 10 FORMAT ('0', MAXMES A1) WRITE (TYPER,20) 20 FORMAT ('0------ TRACEBACK ------'/) RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- PLERR2 SUBROUTINE PLERR2 (X) # Prints trailer for traceback. X should be a function which will # cause an error. WRITE (TYPER,10) 10 FORMAT ('+--- END OF TRACEBACK ---'/) RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- PLINCR #.SUBR 8 REAL FUNCTION PLINCR (VAL, INCR, LOGFLG) REAL VAL, # Value to be incremented INCR # Increment to be used INTEGER LOGFLG # 0 for linear, 1 for logarithmic #.DESCR #PLINCR steps VAL by the indicated amount. If the axis is #logarithmic, INCR selects a table consisting of desired steps. #The sign of INCR always determines the direction of the change. #Initial values for the tables are: #.SEG # INCR = 1.0 1 # INCR = 2.0 1, 5 # INCR = 3.0 1, 2, 5 # INCR = 4.0 1, 2, 4, 6, 8 # INCR = 5.0 1, 2, 3, 4, 5, 6, 7, 8, 9 # INCR = 6.0 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 6, 7, 8, 9 #.EEG #More could be added, in any order. #.NP #PLINCR is used internally by GRID and TICKS. It is included in #the user's guide because it defines the meanings of XINCR and YINCR for #a log scale. ## INTEGER PNTR (7); INTEGER STABLE (50) # STABLE is 2-digit integers. DATA PNTR /1,4,8,13,20,31,46/ # PNTR is first of each row. DATA STABLE / 10, 100, 1000, 10, 50, 100, 1000, 10, 20, 50, 100, 1000, 10, 20, 40, 60, 80, 100, 1000, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 1000, 10, 15, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90, 100, 1000, 1000, 1000, 1000, 1000, 1000/ IF (LOGFLG == SET) [ ITEMP = 10.0*VNORM (VAL,TENS) + 0.1; TENS = 10.0*TENS NTABLE = (ABS(INCR) + 0.1) FOR (I=PNTR(NTABLE); ITEMP>>STABLE(I); I=I+1) # Find current ; # position in appropriate table IF (INCR>>0.0) [ # and bump it with care for wraparound. I = I + 1 IF (I>=PNTR(NTABLE+1)-1) [ I = PNTR(NTABLE)+1; TENS = 0.1*TENS] ] ELSE [ I = I - 1 IF (I<=5 && NULARG(CODE)==1) CODE1 = CODE ELSE CODE1 = SCALED X1 = X; Y1 = Y IF (CODE1 == UNSCALED) [ IF (XLOG == SET) X1 = LOG10(X1) IF (YLOG == SET) Y1 = LOG10(Y1) ] IF (ORIENT == WIDE) [ T = X1; X1 = -Y1; Y1 = T] RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- ROTATE #.SUBR 6 SUBROUTINE ROTATE (I) INTEGER I # 0 for tall, 1 for wide format plot #.DESCR #ROTATE sets ORIENT for tall or wide plots. All subsequent #plotting calls are interpreted in this user reference frame. #ROTATE also sets the annotation angle for text parallel to the #user X-axis and resets the orientation angle to 0. It may be used to #reset these angles following an unorthodox annotation. ## INCLUDE MODTAB THETA = 0.0 IF (I==TALL) [ORIENT = TALL; THETA = 0.0] ELSE IF (I==WIDE) [ORIENT = WIDE; THETA = 90.0] ELSE [ CALL PLERR1 ('ROTATE -- DATA ERROR -- IGNORED') TRACEBK ] CALL MODE (4,SAME,SAME,THETA) CALL MODE (5,SAME,0.0,SAME) RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- SCALE #.SUBR 15 SUBROUTINE SCALE (XLOW,XHIGH,XINCH,YLOW,YHIGH,YINCH,CONTRL) REAL XLOW, # Minimum X value in user units XHIGH, # Maximum X " " " " XINCH, # Length of X axis in plotter units YLOW, # Minimum Y value in user units YHIGH, # Maximum Y " " " " YINCH # Length of Y axis in plotter units INTEGER CONTRL # 0 -- no rationalization # 1 -- rationalize X # 2 -- " Y # 3 -- " X and Y -- DEFAULT #.DESCR #SCALE saves its arguments and sets scale factors for unscaled data. #The scale factors (user units/plotter unit) are adjusted to be #rational values -- currently 1, 2, 2.5, 4, 5, -- and decimal #multiples thereof. These are desirable scale factors since they #form the same set in (user units/plotter unit) and in #(plotter units/user unit), because 1/2 = .5 and 1/2.5 = .4. #The MODE table values are set as if they had been set by SCAN. #SCAN uses 1, 2, 4, 5, 6, 8, omitting the useful 2.5 and adding #6 and 8, both of which give odd scales. For a log scale, the scale #factor determined is in (decades/plotter unit). #.NP #The minimum and maximum values determined by SCALE establish #the position of (0,0) in user units (the user origin). This is used #for plotting unscaled data, and it need not be the same as the #software origin. #.NP #The optional parameter CONTRL permits the user to suppress #rationalization for either or both axes, thus enabling the generation #of odd scale factors. ## #%^ INCLUDE MODTAB REAL T1,T2; INTEGER CONTR1 CALL ARGCNT (NARGS) IF (NARGS>=7 && NULARG(CONTRL)==1) CONTR1 = CONTRL; ELSE CONTR1 = 3 XSCALI = XINCH; YSCALI = YINCH IF (XLOG == SET) [ T1 = LOG10(XLOW); T2 = LOG10(XHIGH) ] ELSE [ T1 = XLOW; T2 = XHIGH ] I = MOD (CONTR1,2) CALL SPAN (T1/XSCALI, T2/XSCALI, XMINU, XMAXU,I) # Scale the X. IF (YLOG == SET) [ T1 = LOG10(YLOW); T2 = LOG10(YHIGH) ] ELSE [ T1 = YLOW; T2 = YHIGH ] I = CONTR1/2 CALL SPAN (T1/YSCALI, T2/YSCALI, YMINU, YMAXU,I) # Scale the Y. CALL PLSWAP (XMAXU-XMINU, YMAXU-YMINU, XFACT, YFACT) # Swap, if wide. XMINU = XSCALI*XMINU; XMAXU = XSCALI*XMAXU # Convert these back to YMINU = YSCALI*YMINU; YMAXU = YSCALI*YMAXU # unscaled units. CALL PLSWAP (XMINU, YMINU, X, Y) # Need unscaled for MODE. IF (XLOG == SET) [ XMINU = 10.0**XMINU; XMAXU = 10.0**XMAXU ] # Undo IF (YLOG == SET) [ YMINU = 10.0**YMINU; YMAXU = 10.0**YMAXU ] # logs. XFACT = ABS(XFACT); YFACT = ABS(YFACT) # Positive scale factors. CALL MODE (8,X,XFACT,-X/XFACT) # Put them away. CALL MODE (9,Y,YFACT,-Y/YFACT) CALL PLSWAP (XSCALI,YSCALI,X,Y) CALL MODE (7,ABS(X),ABS(Y),SAME) RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- SIGNIT #.SUBR 6 SUBROUTINE SIGNIT (STRING) BYTE STRING(MAXSTR) # String to be printed #.DESCR #SIGNIT prints the string in small letters in the lower left #corner of the plot. It may be used to initial or otherwise #identify plots. ## INCLUDE MODTAB REAL X,Y IF (ORIENT==TALL) [ CALL MODE(-2,DUM,X,DUM); CALL MODE(-3,DUM,Y,DUM) ] ELSE [ CALL MODE (-2,Y,DUM,DUM); CALL MODE (-3,DUM,X,DUM) Y = -Y ] # Similar trick to ENDPLT. CALL MODE (-4,OLDHT,OLDWID,DUM); CALL MODE (-6,OLDLIN,DUM,DUM) CALL CHRSIZ (SMALLHT*UFACTOR,SMALLWID*UFACTOR) CALL MODE (6,1.0,SAME,SAME) CALL ANNOTE (X,Y,STRING) CALL CHRSIZ (OLDHT,OLDWID); CALL MODE (6,OLDLIN,SAME,SAME) RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- SIUNIT #.SUBR 4 SUBROUTINE SIUNIT #.DESCR #SIUNIT sets the plotter units to millimetres. ## INCLUDE MODTAB REAL GAIN UFACTOR = MMFACTOR CALL MODE (-1,GAIN,DUM,DUM) GAIN = UFACTOR/GAIN # Old units may not be 1.0 CALL MODE (1,UFACTOR,SAME,SAME) CALL MODE (-4,OLDHT,OLDWID,DUM) # Resetting the char size seems CALL MODE (4,OLDHT*GAIN,OLDWID*GAIN,SAME) # to help. RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- SPAN SUBROUTINE SPAN (LOW,HIGH,MIN,MAX,CODE) REAL LOW, # User's minimum value HIGH, # " maximum " MIN, # Computed minimum value MAX # " maximum " INTEGER CODE # 0 for no rationalization # 1 for rationalization # Returns rational maximum and minimum values. If desired, another #table of values with finer, less rational divisions could be supplied, #selected by a switch in the same way as LOGX. # The parameter, TOLERANCE, is provided to allow for floating #point arithmetic error, and to ensure that end tick marks are made, #if they are on-scale. Note that it is only applied to normalized #variables. REAL SCALES (10); DATA SCALES/1.0,2.0,2.5,4.0,5.0,10.0,4*100.0/ RANGE = HIGH - LOW IF (RANGE>>0.0) [ TEMP = VNORM (RANGE,TENS) IF (CODE == 1) [ FOR (I=1; TEMP>>SCALES(I)+TOLERANCE; I=I+1) # Find a scale. ; TEMP = SCALES(I) ] SCAL = (TEMP + 2.0*TOLERANCE)/TENS MAX = HIGH + 0.5*(SCAL - RANGE) # Centre the range. MIN = MAX - SCAL ] ELSE [ CALL PLERR1 ('SPAN -- NEGATIVE RANGE -- EXIT CALLED') # OOPS! TRACEBK CALL EXIT ] RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- STRTPL #.SUBR 4 SUBROUTINE STRTPL #.DESCR #STRTPL calls for option 2, 1 copy. It must be the first plotting #call of the run. ## CALL MODE (0,2.0,1.0,0.0) RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- SYMBOL #.SUBR 9 SUBROUTINE SYMBOL (I) BYTE I # Character code for symbol -- may be integer, # "octal, or ' ' character. Any character in # the character set supplied by the current # version of VPY may be used. #.DESCR #SYMBOL plots the given symbol at the current pen position. ## CHAR J CALL MODE (-5,DUM,DUM,OLD) CALL MODE (5,SAME,SAME,0.0) # No line for NOTE. CALL DRAW (X,Y,-1,0) # Where are we? J = I # Don't trust NOTE. CALL NOTE (X,Y,J,-1) # Plot it. CALL MODE (5,SAME,SAME,OLD) RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- TICKS #.SUBR 9 SUBROUTINE TICKS (XINCR,XFMT,YINCR,YFMT) REAL XINCR, # Step in the X direction YINCR # " " " Y " BYTE XFMT(MAXSTR), # Format for X numbering YFMT(MAXSTR) # " " Y " #.DESCR #TICKS plots tick marks in the borders, using the user-specified #increments. The ticks are annotated using the specified formats which #may be 'Iw', 'Fw.d', 'Ew.d', '1PEw.d, 'Gw.d', or '1PGw.d'. #If the format is omitted, the tick is not numbered. #TICKS assumes that the field width includes space for a sign, and it #centres the value on the mark, as if the sign was not there. So, #always leave one extra space for the sign. For a log axis, the #interpretation of XINCR and YINCR is defined by function PLINCR. ## INCLUDE MODTAB CALL ARGCNT (NARGS) CALL MODE (-10,PATTN,DUM,DUM); CALL MODE (10,-1.0,SAME,SAME) FOR (X=BOTTOM(XMINU,XINCR,XLOG); X<=XMAXU; X=PLINCR(X,XINCR,XLOG)) [ CALL MARK (X,XSELECT) IF (NARGS>=2 && NULARG(XFMT)==1) CALL TICNOT (X,XFMT,XSELECT) ] FOR (Y=BOTTOM(YMINU,YINCR,YLOG); Y<=YMAXU; Y=PLINCR(Y,YINCR,YLOG)) [ CALL MARK (Y,YSELECT) IF (NARGS>=4 && NULARG(YFMT)==1) CALL TICNOT (Y,YFMT,YSELECT) ] CALL MODE (10,PATTN,SAME,SAME) RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- TICNOT SUBROUTINE TICNOT (VALUE,STRING,SELECT) REAL VALUE # Value of variable co-ordinate. CHAR STRING(MAXSTR) # Format for numbering the mark. INTEGER SELECT # 1 for X axis, 2 for Y axis. # TICNOT prints VALUE in the vicinity of the current pen # position. It should be called with the pen at the outer end of # the relevant mark. INCLUDE MODTAB CHAR FMTYPE CHAR WORK (SHORTSTR), INFO (SHORTSTR); DATA WORK /'(',19*' '/ N = MIN(SHORTSTR-2,LONG(STRING)) # Put (string) into WORK FOR (I=1; I<=N; I=I+1) WORK(I+1) = STRING(I) WORK(I+1) = ')' IF (FMTYPE(STRING,N) == INTEG) [ # and use it for a FORMAT. I = VALUE+SIGN(0.1,VALUE); ENCODE (N,WORK,INFO) I # Round for I. ] ELSE ENCODE (N,WORK,INFO) VALUE CALL MODE (-6,DUM,XSPAC,YSPAC) IF(SELECT==XSELECT) # Position for the number. CALL MOVE (-((N+1)*XSPAC)/2.0,-(TICKGAP*UFACTOR+YSPAC),1,SCADELTA) ELSE CALL MOVE (-(TICKGAP*UFACTOR+N*XSPAC),-YSPAC/4.0,1,SCADELTA) CALL DRAW (X,Y,-1,0); CALL NOTE (X,Y,INFO,N) # Put the number here. RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- UPNOTE #.SUBR 8 SUBROUTINE UPNOTE (X,Y,STRING) REAL X,Y # Co-ordinates of lower left of STRING # in plotter units. BYTE STRING(MAXSTR) # String to be printed. #.DESCR #UPNOTE prints a vertical annotation starting at (X,Y). #This may be used for labelling the Y axis. ## CALL MODE (-4,DUM,DUM,THETA) CALL MODE (4,SAME,SAME,THETA+90.0) CALL ANNOTE (X,Y,STRING) CALL MODE (4,SAME,SAME,THETA) RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- VECTOR #.SUBR 14 SUBROUTINE VECTOR (X1,Y1,X2,Y2,N,CODE) REAL X1,Y1, # Co-ordinates of the first point X2,Y2 # " " " second point INTEGER N, # 0 -- To draw with current line width -- DEFAULT # 1-8 -- To draw with new line width # 9 -- To draw to the first point with the # pen down, then continue # drawing to the second point. # 600n -- for point-plot with dot size n CODE # 0,2,4 for scaled, scaled delta [1] and # unscaled data. DEFAULT is unscaled. #.DESCR #VECTOR draws a vector from the first point to the second. For #N=9 it also draws from the current pen position to the first point. #Unscaled data means data in user units, while scaled data refers to #plotter units. Omitted parameters take their default values. ## REAL X(2), Y(2); INTEGER N1, CODE1 CALL ARGCNT(NARGS) IF (NARGS>=5 && NULARG(N)==1) N1 = N; ELSE N1 = 0 IF (NARGS>=6 && NULARG(CODE)==1) CODE1 = CODE; ELSE CODE1 = UNSCALED CALL PLSWAP (X1,Y1,X(1),Y(1),CODE1) CALL PLSWAP (X2,Y2,X(2),Y(2),CODE1) CALL DRAW (X,Y,2,CODE1*110+N1) RETURN END #%%A-RCB-0094-SL-1 GRAPHIC -- VNORM REAL FUNCTION VNORM (VAL,TENS) REAL VAL, # Value to be normalized TENS # Scale factor # Returns VAL normalized to the interval (1,10]. TENS is set #so that VAL = VNORM/TENS. # Note that we could use ALOG10 and 10**X to do this, but the #algorithms for ALOG and EXP are much more complicated and potentially #less accurate, and the program would be harder to follow. Also, the #method used produces tight,efficient loops. T = ABS (VAL); TENS = 1.0 WHILE (T<=1.0) [ T = 10.0*T; TENS = 10.0*TENS ] WHILE (T>>10.0) [ T = 0.1*T; TENS = 0.1*TENS ] RETURN (T) END #%%A-RCB-0094-SL-1 GRAPHIC -- WIDTH #.SUBR 6 SUBROUTINE WIDTH (N) INTEGER N # Desired line width #.DESCR #WIDTH sets the line width for subsequent lines. It also sets the #character line width for lettering. ## CALL DRAW (0,0,1,330+N) # Set width for lines X = N CALL MODE (6,X,SAME,SAME) # and for characters. RETURN END