home *** CD-ROM | disk | FTP | other *** search
- PROGRAM GRAPHDEMO
- C original for BBC Master Scientific from C.Johnson
- C modified by K.M.Crennell for Archimedes Dec 91
- C ********************* CopyRight 'Fortran Friends' 1992 ****************
- C If you want to distribute any of this code in your own programs, please
- C acknowledge the 'Fortran Friends' PD library and send us a copy.
- C ************************************************************************
- C
- C libraries needed Graphics, Utils
- C
- C demo of X,Y graph drawing routine GRAPH
- PARAMETER (MAXPTS=100)
- REAL X(MAXPTS),Y(MAXPTS)
- CHARACTER C*1,TEX*80
- C screen constants set in subroutine INIT
- COMMON /GRAF/ IX0,IY0,IX1,IY1,IXL,IYL,IXR,IYR,
- 1 IUXAXT,IUYAXT,IUXAYT,IUYAYT,IXAXT,IYAXT,IXAYT,IYAYT,KSQ,
- 2 LXHI,LYR,LXTS,LXTL,LYTS,LYTL,ISUPX,ISUPY,
- 3 KOLB,KOLF,XMIN,YMIN,XMAX,YMAX,SCALEX,SCALEY,MASKX,MASKY
- C
- C read in data from file, N = no of X,Y points read
- CALL GETDAT(X,Y,N,MAXPTS)
- C set window in which to draw graph
- CALL GWIND(100,300,956,956)
- C initialisation call to GRAPH to find the scale factor
- C neded to plot the X,Y points on this screen
- CALL GRAPH(X,Y,N,0,IER)
- IF(IER.NE.0)GOTO80
- C ask to plot the points joined by a line between them
- C in a different colour
- CALL GCOL(0,15)
- CALL GRAPH(X,Y,N,1,IER)
- IF(IER.NE.0)GOTO80
- C ask to plot the points as square markers
- CALL GRAPH(X,Y,N,2,IER)
- IF(IER.NE.0)GOTO80
- C
- TEX='Press <Spacebar> to exit, or S to save graph :- '
- CALL WOG(IX0+336,IY1-64,TEX)
- C=CHAR(IGET())
- IF (C.EQ.'S') CALL SCRNSV
- CALL VDU(12)
- IF(IER.EQ.0)STOP
- 80 WRITE(*,*) '*** Bad value for IOPT (',IER,') ***'
- STOP 'Fatal error! Program terminated.'
- END
- C
- SUBROUTINE GETDAT(X,Y,N,MAXPTS)
- C reads X,Y data, returns N no of points read,
- C MAXPTS = maximum no allowed.
- REAL X(*),Y(*)
- CHARACTER FNAME*30
- WRITE(*,*) ' Fortran Graph plotter V1.0'
- WRITE(*,*) ' ----------------------------'
- WRITE(*,*)
- WRITE(*,*) ' Data file name ='
- READ(*,9000) FNAME
- 9000 FORMAT(A)
- C FNAME='GraphData'
- OPEN(UNIT=1,FILE=FNAME)
- N=1
- 20 READ(1,*,END=80) X(N),Y(N)
- N=N+1
- IF(N.LE.MAXPTS)GOTO20
- 80 N=N-1
- RETURN
- END
- C start of utilities **********************
- C
- SUBROUTINE AXIS(Z1,Z2,I)
- C The axis is not drawn here, just the tick lines and numbers. C minimum Z1 and Max Z2 I=1 Xaxis, =2 Y axis
- C
- IF (Z1.GT.Z2) THEN
- C allow for user having got it backwards???
- T=Z1
- Z1=Z2
- Z2=T
- END IF
- M=0
- A=0.0
- N=0
- B=0.0
- IF (Z1.NE.0.0) M=NINT(LOG10(ABS(Z1)))
- IF (Z2.NE.0.0) N=NINT(LOG10(ABS(Z2)))
- C find the power of 10 for the min & max numbers
- IF (M.GT.N) THEN
- N1=M
- ELSE
- N1=N
- END IF
- A=Z1*10.0**(-N1)
- B=Z2*10.0**(-N1)
- IF (ABS(B-A).LT.0.2) THEN
- A1=A
- B1=B
- ELSE
- A1=ROUND(A,1)
- B1=ROUND(B,1)
- END IF
- IF(I.EQ.1)THEN
- C write out the tickmarks and associated numbers for X axis
- CALL XTICKS(A1,B1,N1)
- ELSE
- C tickmarks and numbers for Y axis
- CALL YTICKS(A1,B1,N1)
- ENDIF
- RETURN
- END
- SUBROUTINE DELTA(RANGE,NTICKS,D,NM)
- C calculates the value of D which makes the NTICKS tick marks
- C evenly spaced within the distance RANGE and at 'nice' values 1,2, or 5
- C ALSO returns the number of minor tickmarks, NM, plotted within D
- REAL DT(3)
- C LOG10(1) log10(2) Log10(5)
- DATA DT/ 0 ,0.301030, 0.69897/
- C DXT =Minimum distance between ticks in X axis
- DXT=RANGE/FLOAT(NTICKS)
- X=LOG10(DXT)
- IDX=INT(X)
- DDX=X-IDX
- C IDX exponent of DXT DDX = mantissa
- C DXT=10**(IDX+DDX) where 0 < DDX < 1 want next biggest 'nice' no.
- IF(DDX.LT.0.)THEN
- DDX=DDX+1.
- IDX=IDX-1
- ENDIF
- IF(DDX.GT.DT(1).AND.DDX.LT.DT(2))DX=2
- IF(DDX.GT.DT(2).AND.DDX.LT.DT(3))DX=5
- IF(DDX.GE.DT(3))DX=10
- D=DX*10.**IDX
- C get number of minor tickmarks to return
- NM=1
- IF(DX.EQ.2.)NM=3
- IF(DX.EQ.5.)NM=4
- RETURN
- END
- C
- SUBROUTINE DRAWLN(X,Y,N)
- C draw line through the X,Y points
- REAL X(*),Y(*)
- COMMON /GRAF/ IX0,IY0,IX1,IY1,IXL,IYL,IXR,IYR,
- 1 IUXAXT,IUYAXT,IUXAYT,IUYAYT,IXAXT,IYAXT,IXAYT,IYAYT,KSQ,
- 2 LXHI,LYR,LXTS,LXTL,LYTS,LYTL,ISUPX,ISUPY,
- 3 KOLB,KOLF,XMIN,YMIN,XMAX,YMAX,SCALEX,SCALEY,MASKX,MASKY
- C
- CALL MOVE(ISCRN(X(1),0,1),ISCRN(Y(1),0,2))
- DO 10 I=2,N
- 10 CALL DRAW(ISCRN(X(I),0,1),ISCRN(Y(I),0,2))
- RETURN
- END
- C
- SUBROUTINE DRPNTS(X,Y,N)
- C draws a filled square, size KSQ, in background colour,KOLB,
- C outlined in foreground colour KOLF at each of the N points in X,Y
- REAL X(*),Y(*)
- COMMON /GRAF/ IX0,IY0,IX1,IY1,IXL,IYL,IXR,IYR,
- 1 IUXAXT,IUYAXT,IUXAYT,IUYAYT,IXAXT,IYAXT,IXAYT,IYAYT,KSQ,
- 2 LXHI,LYR,LXTS,LXTL,LYTS,LYTL,ISUPX,ISUPY,
- 3 KOLB,KOLF,XMIN,YMIN,XMAX,YMAX,SCALEX,SCALEY,MASKX,MASKY
- L=KSQ/2
- N0=0
- DO 10 I=1,N
- IXP=ISCRN(X(I),N0,1)
- IYP=ISCRN(Y(I),N0,2)
- CALL GCOL(0,KOLB)
- CALL RECTAN(IXP-L,IYP-L,IXP+L,IYP+L,.TRUE.)
- CALL GCOL(0,KOLF)
- CALL RECTAN(IXP-L,IYP-L,IXP+L,IYP+L,.FALSE.)
- 10 CONTINUE
- RETURN
- END
- C
- SUBROUTINE GRAPH(X,Y,N,IOPT,IER)
- REAL X(*),Y(*)
- COMMON /GRAF/ IX0,IY0,IX1,IY1,IXL,IYL,IXR,IYR,
- 1 IUXAXT,IUYAXT,IUXAYT,IUYAYT,IXAXT,IYAXT,IXAYT,IYAYT,KSQ,
- 2 LXHI,LYR,LXTS,LXTL,LYTS,LYTL,ISUPX,ISUPY,
- 3 KOLB,KOLF,XMIN,YMIN,XMAX,YMAX,SCALEX,SCALEY,MASKX,MASKY
- C
- C IOPT=0 => Does scaling, draws frame and axes
- C
- C IOPT=1 => Draws line through X and Y values.
- C
- C IOPT=2 => Draws points through X and Y data using squares.
- C
- IER=0
- C error returns zero if OK
- IF(IOPT.LT.0.OR.IOPT.GT.2)THEN
- IER=IOPT
- RETURN
- ENDIF
- GOTO (100,200,300),IOPT+1
- C
- 100 CONTINUE
- CALL SCALE(X,Y,N)
- C scale the user points to fit screen and set up constants
- CALL GCOL(0,KOLF)
- C Outline the drawing area along the axes
- CALL RECTAN(IXL,IYL,IXR,IYR,.FALSE.)
- C draw the axes
- CALL AXIS(XMIN,XMAX,1)
- CALL AXIS(YMIN,YMAX,2)
- RETURN
- C draw a line through the points
- 200 CALL DRAWLN(X,Y,N)
- RETURN
- C draw the points with marker, no line
- 300 CALL DRPNTS(X,Y,N)
- RETURN
- END
- SUBROUTINE INIT
- C CALLED FROM SCALE to initialise screen constants
- COMMON /GRAF/ IX0,IY0,IX1,IY1,IXL,IYL,IXR,IYR,
- 1 IUXAXT,IUYAXT,IUXAYT,IUYAYT,IXAXT,IYAXT,IXAYT,IYAYT,KSQ,
- 2 LXHI,LYR,LXTS,LXTL,LYTS,LYTL,ISUPX,ISUPY,
- 3 KOLB,KOLF,XMIN,YMIN,XMAX,YMAX,SCALEX,SCALEY,MASKX,MASKY
- C
- C (IX0,IY0) to (IX1,IY1) screen (or window) size (rasters)
- C IX0=0
- C IY0=0
- C IX1=1280
- C IY1=960
- C get the graphics window size
- IX0=ISHFT(MVDUVAR(128),MODEVAR(-1,4))
- IX1=ISHFT(MVDUVAR(130),MODEVAR(-1,4))
- IY0=ISHFT(MVDUVAR(129),MODEVAR(-1,5))
- IY1=ISHFT(MVDUVAR(131),MODEVAR(-1,5))
- CALL CLG
- C background and foreground colours
- KOLB=0
- KOLF=7
- C screen co-ordinates must be divisible by 4
- C MASKX=?IFFFFFFFE
- C MASKY=?IFFFFFFFE
- MASKX=ISHFT(-1,MODEVAR(-1,4))
- MASKY=ISHFT(-1,MODEVAR(-1,5))
- C (IXL,IYL) to (IXR,IYR) graph drawing area (rasters)
- IXL=IX0+160
- IXR=IX1-100
- IYL=IY0+128
- IYR=IY1-100
- C side of square marker (rasters)
- KSQ=16
- C position of numbers on X axis relative to tick line
- IUXAXT= 40
- IUYAXT= IYL-32
- C and on Y axis
- IUXAYT= IX0+48
- IUYAYT= 12
- C amounts to left for short and long Y tick marks
- LYTS= 16
- LYTL= 28
- C amount to right where Y marks stop
- LYR= 8
- C amounts below X axis for short and long tickmarks
- LXTS= 16
- LXTL= 28
- C amount above X axis where all marks stop
- LXHI = 8
- C position of X axis text centre of IXl,IXR
- IXAXT= IX0+(IXR-IXL) *0.5
- IYAXT= IYL-64
- C position of Y axis text relative to IXL,IYR
- IXAYT= 80
- IYAYT= 64
- C relative position of exponent same for X and Y
- ISUPX= +16
- ISUPY= +16
- RETURN
- END
- C
- FUNCTION ISCRN(Z,N,I)
- C converts user variable Z into a screen variable, N= power of 10
- C I=1 for X, =2 for Y
- COMMON /GRAF/ IX0,IY0,IX1,IY1,IXL,IYL,IXR,IYR,
- 1 IUXAXT,IUYAXT,IUXAYT,IUYAYT,IXAXT,IYAXT,IXAYT,IYAYT,KSQ,
- 2 LXHI,LYR,LXTS,LXTL,LYTS,LYTL,ISUPX,ISUPY,
- 3 KOLB,KOLF,XMIN,YMIN,XMAX,YMAX,SCALEX,SCALEY,MASKX,MASKY
- C MASKX,MAXY are MODE dependent, set by routine SCALE
- XY=Z
- IF(N.NE.0)XY=XY*(10.0**N)
- IF(I.EQ.1) ISCRN=IAND(IXL+INT((XY-XMIN)*SCALEX),MASKX)
- IF(I.EQ.2) ISCRN=IAND(IYL+INT((XY-YMIN)*SCALEY),MASKY)
- RETURN
- END
- C
- SUBROUTINE OUTINT(IX,IY,N)
- C writes out an integer on screen
- CHARACTER *10 WORK
- WRITE(WORK,101)N
- 101 FORMAT(I4)
- CALL WOG(IX,IY,WORK)
- RETURN
- END
- C
- SUBROUTINE OUTNUM(IX,IY,X)
- C outputs a floating point number to the screen
- CHARACTER * 10 WORK
- C is there a format to write out leading zeros?
- IF(X.GE.1.0)THEN
- WRITE(WORK,101)X
- ELSE
- IF(X.GE.0.0)THEN
- WRITE(WORK,102)X
- ELSE
- IF(X.GT.-1.0)THEN
- WRITE(WORK,104)-X
- ELSE
- WRITE(WORK,103)-X
- ENDIF
- ENDIF
- ENDIF
- CALL WOG(IX,IY,WORK)
- RETURN
- 101 FORMAT(1X, F4.2)
- 102 FORMAT(1X,'0',F3.2)
- 103 FORMAT( F4.2)
- 104 FORMAT( '-0',F3.2)
- END
- C
- FUNCTION ROUND(X,IC)
- T=10.0*ABS(X)+FLOAT(IC)-0.5
- ROUND=SIGN(1.0,X)*FLOAT(INT(T))*0.1
- RETURN
- END
- C
- SUBROUTINE SCALE(X,Y,N)
- REAL X(*),Y(*)
- COMMON /GRAF/ IX0,IY0,IX1,IY1,IXL,IYL,IXR,IYR,
- 1 IUXAXT,IUYAXT,IUXAYT,IUYAYT,IXAXT,IYAXT,IXAYT,IYAYT,KSQ,
- 2 LXHI,LYR,LXTS,LXTL,LYTS,LYTL,ISUPX,ISUPY,
- 3 KOLB,KOLF,XMIN,YMIN,XMAX,YMAX,SCALEX,SCALEY,MASKX,MASKY
- C set up constants for scaling to screen
- CALL INIT
- C find Max and min in user data
- XMIN=9999999.999
- XMAX=-XMIN
- YMIN=XMIN
- YMAX=-YMIN
- DO 10 I=1,N
- Z=X(I)
- IF (Z.LT.XMIN) XMIN=X(I)
- IF (Z.GT.XMAX) XMAX=X(I)
- Z=Y(I)
- IF (Z.LT.YMIN) YMIN=Y(I)
- IF (Z.GT.YMAX) YMAX=Y(I)
- 10 CONTINUE
- Z=(XMIN+XMAX)*0.5
- ZC=(XMAX-XMIN)*0.5
- XMIN=Z-1.05*ZC
- XMAX=Z+1.05*ZC
- Z=(YMIN+YMAX)*0.5
- ZC=(YMAX-YMIN)*0.5
- YMIN=Z-1.05*ZC
- YMAX=Z+1.05*ZC
- SCALEX=FLOAT(IXR-IXL)/(XMAX-XMIN)
- SCALEY=FLOAT(IYR-IYL)/(YMAX-YMIN)
- RETURN
- END
- C
- SUBROUTINE SCRNSV
- C saves the screen somehow for later printing, Drawfile?
- RETURN
- END
- C
- CHARACTER*1 FUNCTION UPCASE(CHR)
- C converts the character in CHR to upper case
- CHARACTER CHR*1
- UPCASE=CHR
- IF (CHR.GE.'a') UPCASE=CHAR(ICHAR(CHR)-32)
- RETURN
- END
- C
- SUBROUTINE XTICKS(X1,X2,N)
- C puts tick marks and numbers on the X axis between minimum at X1 and
- C max at X2. N=exponent of the X1 and X2
- COMMON /GRAF/ IX0,IY0,IX1,IY1,IXL,IYL,IXR,IYR,
- 1 IUXAXT,IUYAXT,IUXAYT,IUYAYT,IXAXT,IYAXT,IXAYT,IYAYT,KSQ,
- 2 LXHI,LYR,LXTS,LXTL,LYTS,LYTL,ISUPX,ISUPY,
- 3 KOLB,KOLF,XMIN,YMIN,XMAX,YMAX,SCALEX,SCALEY,MASKX,MASKY
- C try 8 ticklines
- NT=8
- C decide on spacing assume X2 > X1
- C DELTA finds a 'nice' one, returned in D
- C also returns NMIN no of minor tickmarks to be inserted within D
- CALL DELTA(X2-X1,NT,D,NMIN)
- C find NP, how many to do
- NP=2+INT((X2-X1)/D)
- X=X1-D
- C for -ve values start at next higher point?
- C IF(X1.LT.0)X=X+D
- IYP=IYL-LXTL
- IYQ=IYL+LXHI
- C Y values for major and minor tick lines
- MYP=IYL-LXTS
- MYQ=IYL+LXHI
- C CX is spacing of the minor tickmarks
- CX=D/FLOAT(NMIN+1)
- DO 20 I=1,NP
- X=X+D
- IF(X.GT.X2)GOTO20
- C output the numbers as XTEMP rounded
- XTEMP=SIGN(1.,X)*INT(100.*ABS(X)+0.5)*0.01
- IXP=ISCRN(X,N,1)
- CALL OUTNUM(IXP-IUXAXT,IUYAXT,XTEMP)
- C output the major ticklines
- CALL LINE(IXP,IYP,IXP,IYQ)
- C now the minor ticklines
- DO 10 J=1,NMIN
- IXP=ISCRN(X+J*CX,N,1)
- IF(IXP.GT.IXR)GOTO20
- CALL LINE(IXP,MYP,IXP,MYQ)
- 10 CONTINUE
- 20 CONTINUE
- CALL WOG(IXAXT,IYAXT,'X*10')
- I=IXAXT+ISUPX
- IF(N.LT.0)I=I+16
- IF(N.NE.1)CALL OUTINT(I,IYAXT+ISUPY,N)
- RETURN
- END
- C
- SUBROUTINE YTICKS(Y1,Y2,N)
- C plots ticklines and number for the Y axis
- C between minimum at Y1 and Max at Y2
- COMMON /GRAF/ IX0,IY0,IX1,IY1,IXL,IYL,IXR,IYR,
- 1 IUXAXT,IUYAXT,IUXAYT,IUYAYT,IXAXT,IYAXT,IXAYT,IYAYT,KSQ,
- 2 LXHI,LYR,LXTS,LXTL,LYTS,LYTL,ISUPX,ISUPY,
- 3 KOLB,KOLF,XMIN,YMIN,XMAX,YMAX,SCALEX,SCALEY,MASKX,MASKY
- C try 16 ticklines
- NT=16
- C decide on spacing assume Y2 > Y1
- C DELTA finds a 'nice' one, returned in D
- C also returns NMIN no of minor tickmarks to be inserted within D
- CALL DELTA(Y2-Y1,NT,D,NMIN)
- C find NP, how many to do
- NP=2+INT((Y2-Y1)/D)
- Y=Y1-D
- C IF(Y1.LT.0)Y=Y+D need this???
- IXP=IXL-LYTL
- IXQ=IXL+LYR
- C Y values for major and minor tick lines
- MXP=IXL-LYTS
- MXQ=IXL+LYR
- C CY is spacing of the minor tickmarks
- CY=D/FLOAT(NMIN+1)
- DO 20 I=1,NP
- Y=Y+D
- C output the numbers as XTEMP rounded
- YTEMP=SIGN(1.,Y)*INT(100.*ABS(Y)+0.5)*0.01
- IYP=ISCRN(Y,N,2)
- CALL OUTNUM(IUXAYT,IYP+IUYAYT,YTEMP)
- C output the major ticklines
- CALL LINE(IXP,IYP,IXQ,IYP)
- C now the minor ticklines
- DO 10 J=1,NMIN
- IYP=ISCRN(Y+J*CY,N,2)
- IF(IYP.GT.IYR)GOTO20
- CALL LINE(MXP,IYP,MXQ,IYP)
- 10 CONTINUE
- 20 CONTINUE
-
- C label Y axix units
- IYP=IYR+IYAYT
- IXP=IXL-IXAYT
- CALL WOG(IXP,IYP,'Y*10')
- I=IXP+ISUPX
- IF(N.LT.0)I=I+16
- IF(N.NE.1)CALL OUTINT(I,IYP+ISUPY,N)
- RETURN
- END
-