Trailing-Edge
-
PDP-10 Archives
-
decuslib10-12
-
43,50547/pltlib/v12a/plot.mac
There are 3 other files named plot.mac in the archive. Click here to see a list.
SUBTTL Contents -- PLOT.MAC
; Table of Contents for PLOT.MAC
;
;
; Section Page
;
; 1. Contents
; 1.1 PLOT.MAC . . . . . . . . . . . . . . . . . . . 0
; 1.2 PLTDSK.MAC . . . . . . . . . . . . . . . . . . 2
; 1.3 PLTRGS.MAC . . . . . . . . . . . . . . . . . . 3
; 1.4 PLTTEK.MAC . . . . . . . . . . . . . . . . . . 4
; 1.5 PLTIOD.MAC . . . . . . . . . . . . . . . . . . 5
; 2. Assembly instructions and Feature-Test settings . . . 6
; 3. Other definitions . . . . . . . . . . . . . . . . . . 7
; 4. Data definitions
; 4.1 Naming conventions . . . . . . . . . . . . . . 8
; 4.2 PPDATA - Per-plotter macro . . . . . . . . . . 9
; 5. Subroutine PLOT
; 5.1 Get the X and Y coordinates to move to . . . . 11
; 5.2 Table of plotter functions . . . . . . . . . . 12
; 5.3 PLOTIT - Translate, scale, and rotate coordi . 14
; 5.4 MOVDN and MOVUP - move the pen . . . . . . . . 15
; 6. Main routines
; 6.1 ERASE - Clear the screen . . . . . . . . . . 16
; 6.2 FACTOR - Change the scaling factor . . . . . . 17
; 6.3 GETWIN - Get status of universal window . . . 18
; 6.4 NEWPEN - Change pen color or line type . . . . 19
; 6.5 OPRTXT - Send message to OPR when plot comes . 20
; 6.6 PAUSEP - Temporarily turn off a plotter . . . 21
; 6.7 PLOTCH - Output characters to a plotter . . . 22
; 6.8 PLOTER - Define an alias plotter . . . . . . . 23
; 6.9 PLOTOF - Temporarily turn off a plotter . . . 24
; 6.10 PLOTOK - Get status of the plotter . . . . . . 25
; 6.11 PLOTON - Resume output to a plotter . . . . . 26
; 6.12 PLOTS - Initialize the plotter . . . . . . . 27
; 6.13 ROTATE - Change angle of rotation for the pl . 28
; 6.14 SETWIN - Set universal window for large plot . 29
; 6.15 SUBWIN - Set/reset/status of sub-window . . . 31
; 6.16 TITLE - Use hardware character generator . . 34
; 6.17 TITLEP - Check if TITLE is possible for plot . 35
; 6.18 WHERE - Get current pen position . . . . . . 36
; 6.19 XHAIRS - Trigger crosshairs TEK 4012 or GIGI . 37
; 7. Plotter initialization
; 7.1 Determine plotter type . . . . . . . . . . . . 38
; 7.2 Set default values . . . . . . . . . . . . . . 40
; 8. Rotation
; 8.1 TWIST and UNTWST . . . . . . . . . . . . . . . 41
; 8.2 INC2FP - Convert increments to floatint-poin . 42
; 9. Window clipping
; 9.1 CHECK . . . . . . . . . . . . . . . . . . . . 43
; 9.2 "Plot Window was Exceeded" message . . . . . . 45
; 9.3 COMP . . . . . . . . . . . . . . . . . . . . . 46
; 9.4 COMPX and COMPY . . . . . . . . . . . . . . . 47
; 9.5 GETX and CHKX . . . . . . . . . . . . . . . . 48
; 9.6 COMPM and NEWOLD . . . . . . . . . . . . . . . 49
; 10. End of PLOT.MAC (Must be assembled with PLTIOD.MAC) . 50
SUBTTL Contents -- PLTDSK.MAC
; Table of Contents for PLTDSK.MAC
;
;
; Section Page
;
; 1. Revision History for PLTDSK.MAC . . . . . . . . . . . 2
; 2. PPDATA macro expansion . . . . . . . . . . . . . . . . 2
; 3. INI - Initialize spooled plotter . . . . . . . . . . . 3
; 4. FIN - Finish the plot . . . . . . . . . . . . . . . . 4
; 5. Subroutine OPRTXT and DSKPAS . . . . . . . . . . . . . 5
; 6. Pen moving routines . . . . . . . . . . . . . . . . . 6
; 7. Header/Trailer
; 7.1 Create text . . . . . . . . . . . . . . . . . 8
; 7.2 Utility subroutines . . . . . . . . . . . . . 9
; 7.3 Numberic output routines . . . . . . . . . . . 10
; 7.4 Output the prepared text . . . . . . . . . . . 11
SUBTTL Contents -- PLTRGS.MAC
; Table of Contents for PLTRGS.MAC
;
;
; Section Page
;
; 1. Revision History for PLTRGS.MAC . . . . . . . . . . . 1
; 2. PPDATA macro expansion . . . . . . . . . . . . . . . . 2
; 3. Database . . . . . . . . . . . . . . . . . . . . . . . 3
; 4. INItialize, FINish . . . . . . . . . . . . . . . . . . 4
; 5. RGSPAS - Pause, plot-on, or plot-off . . . . . . . . . 5
; 6. RGSMOV - Move to beam to new position . . . . . . . . 5
; 7. NEWPEN - Change pen colors . . . . . . . . . . . . . . 7
; 8. TITLE - Plot text . . . . . . . . . . . . . . . . . . 8
; 9. XHAIRS - allow the user the use the crosshairs . . . . 9
SUBTTL Contents -- PLTTEK.MAC
; Table of Contents for PLTTEK.MAC
;
;
; Section Page
;
; 1. Revision History for PLTTEK.MAC . . . . . . . . . . . 1
; 2. PPDATA macro expansion . . . . . . . . . . . . . . . . 3
; 3. Database . . . . . . . . . . . . . . . . . . . . . . . 4
; 4. INItialize, FINish, and Pause . . . . . . . . . . . . 4
; 5. TEKMOV - Move to beam to new position . . . . . . . . 6
; 6. XHAIRS - allow the user the use the crosshairs . . . . 6
SUBTTL Contents -- PLTIOD.MAC
; Table of Contents for PLTIOD.MAC
;
;
; Section Page
;
; 1. ALCOR and DECOR
; 1.1 Set up disk (or TTY) buffers . . . . . . . . . 1
; 1.2 Release disk (or TTY) buffers . . . . . . . . 2
; 2. OUTDMP, OUTSTG, OUTWRD - Output a string of bytes . . 3
; 3. RETZER, RETM1, CPOPJ, CPOPJ1, T1POPJ, T2POPJ . . . . . 3
; 4. Output numbers and bytes . . . . . . . . . . . . . . . 4
; 5. Bufferred I/O, TOPS-10 and TOPS-20 . . . . . . . . . . 5
; 6. GETNAM - Get file name from caller . . . . . . . . . . 6
; 7. NEWFIL - Create new file name . . . . . . . . . . . . 7
; 8. Open output file . . . . . . . . . . . . . . . . . . . 8
; 9. Translate 'TTY' to appropriate plotter type . . . . . 9
; 10. TTYINI - Set up terminal . . . . . . . . . . . . . . . 11
; 11. Terminal I/O routines . . . . . . . . . . . . . . . . 13
; 12. I/O routines - Read window limits from SYS:PRIV.SYS . 15
; 13. Misc - IFX.X and IFX.Y . . . . . . . . . . . . . . . . 16
; 14. ALCHN and DECHN . . . . . . . . . . . . . . . . . . . 16
; 15. Data area
; 15.1 Global variables . . . . . . . . . . . . . . . 16
; 15.2 Temporary variables . . . . . . . . . . . . . 16
; 16. Literals and END statement . . . . . . . . . . . . . . 18
SUBTTL Assembly instructions and Feature-Test settings
SEARCH PLTUNV ;Search the universal file
SALL
TTL (<PLOT - Pen moving routine>,MAIN)
;Assembly instructions:
; .COMPILE PLOT.REL=PLOT.MAC+PLTxxx.MAC+PLTIOD.MAC
;PLOT.MAC contains the entry points and main routines.
;PLTIOD.MAC has I/O routines, data definitions, and the END statement.
;PLTxxx.MAC is one or more of the following:
; PLTARD * ARDS graphic terminal
; PLTCAL * Outputs directly to CALCOMP XY-10 plotter, 1 byte per increment
; PLTDSK Compressed DSK: data, must be expanded by PLTSPL or SPROUT
; PLTHEW * Hewlett Packard plotter
; PLTLPT * Draw plots on the lineprinter
; PLTPT6 * Houston Instruments PTC6 plotter controller
; PLTPTC * Houston Instruments PTC5 plotter controller
; PLTQUM * QUME mechanism in DIABLO or GENCOM hardcopy terminal
; PLTRGS ReGIS (VT125, GIGI, and DMP-4R)
; PLTTEK 4010 Series Tektronix terminals; 4006, 4014, 4025, etc
; "*" means this module has NOT been tested at CSM
;NOTE: There are no TOPS-10 dependencies in PLOT.MAC; all UUOs are in PLTIOD.
;Feature-test settings defined in PLTUNV.UNV
FTDBUG==FTDBUG ;Features for debugging PLOT.REL with DDT
FTKA== FTKA ;FIXR instruction instead of IFX.1 subroutine
FTDSKO==FTDSKO ;'UUOS', 'FILOP.', 'FOROTS', or 'JSYS'
FTAPLT==FTAPLT ;Nonzero to have multiple plotters active
;Feature-tests that affect PLOT.REL only
TOPS20< ND FTHEAD,0> ;Don't bother with headers/trailers for 20's
TOPS20< ND FTDSK,0> ;Code to read/write disk pages not written yet
TOPS20< ND FTPRIV,0> ;No DSK I/O yet
ND FT2CC,0 ;Do not pass Control-C to previous .JBINT routine
ND FTXHCC,0 ;Do not pass Control-C to caller in subroutine XHAIRS
ND FTPRIV,-1 ;Subroutine SETWIN reads SYS:PRIV.DAT/PHYSICALONLY
ND FTHEAD,-1 ;Headers and trailers plotted in the .PLT file
;0 for no headers, +1 to use put in .PLT file as ASCII text
;List of external routines
IFL FTHEAD,<EXTERN SYMBOL,SETSYM> ;Called by TITLE if no hardware set
EXTERN SIN.,COS. ;Math routines from FORLIB
EXTERN TRACE. ;Routines from FORLIB
EXTERN ALCOR.,DECOR. ;Memory management in FOROTS
EXTERN .PLOT. ;Default plotter for CALL PLOTS(IERR,0)
;(set to ASCII /TEK/ in SYS:TEKPLT.REL)
IFN FTKA,< EXTERN IFX.1> ;Convert number in T1 to integer
IFE <FTDSKO-'UUOS'>,< EXTERN ALCHN., DECHN.> ;Ask FOROTS for I/O channel
SUBTTL Other definitions
;Default values, may be changed at will
ND DFWINS,11.0 ;Default window size in inches
IFE FTAPLT,<PLTNUM==2> ;Only 'SPOOL' and 'TTY' active if FTAPLT=0
ND PLTNUM,5 ;Allow for 5 active plotters via subroutine PLOTER.
ND DTTPLT,ASCII/TEK/ ;Default 'TTY' plotter for CALL PLOT(IERR,'TTY')
;Special character definitions
BS== 10 ;Backspace
TAB==11 ;Tab
LF== 12 ;Linefeed
VT== 13 ;Vertical tab
FF== 14 ;Formfeed
CR== 15 ;Carriage return
ESC==33 ;Escape
;ACs defined in PLTUNV
T0=T0
T1=T1
T2=T2
T3=T3
T4=T4
P1=P1
P2=P2
P3=P3
P4=P4
X=X
Y=Y
L=L
P=P
;Special AC definitions
B=G3 ;Used in CHECK for Y = M*X + B
M=G4
NEW.BD=G5 ;Flags for boundry checking
PURGE G3,G4,G5 ;P1 and P2 are available
SUBTTL Data definitions -- Naming conventions
;Variables are of 4 types:
;
;1. Global - Applies to all plotters, whether they are active or not.
; Example: X and Y set by PLOT for subroutine WHERE.
; Format: x.xxxx - Directly addressable
;
;2. Per plotter - Applies to each active plotter and defined for all plotters.
; Example: Current pen position and status.
; Format: xxxx.x(P4) - Indexed by P4
;
;3. Local - Applies to only one plotter, defined by LCDATA macro.
; Example: Calls to PLOT for PLTDSK, old position for PLTTEK.
; Format: xxxx.x(P4) - Indexed by P4
;
;4. Temporary - Usually trashed between calls to PLOT.
; Example: Argument for the SIN and COS functions.
; Format: Arbitrary - Directly addressable
;
;Other naming conventions:
;
; Bit value definitions - Flags and masks.
; Example: P4.ACT is on if plotter is active
; Format: aa.xxx - aa is word (or AC), xxx is name
;
; Per plotter constants - dispatch table for plotter
; Example: PUSHJ P,@PLTINI(P4) ;Initialize the plot
; Format: PLTxxx(P4) - Indexed by P4
;
; Local symbols for device drivers
; Example: TEK.TX - character to set text mode
; Format: xxx.xx
;The convolutions with global and per-plotter variables allows a program to
;do something like display a smaller rotated plot on the Tektronix while
;sending data to the spooled plotter. Things such as rotation angle and
;offset can be set independently by using PLOTOF to turn off all the other
;plotters.
;Accumulator P3 is an AOBJN pointer to PLTTAB, the table of active plotters.
;PLTTAB is used for storing P4, which has the address of the plotter specific
;data area in the right half, and flags in the left half. The flags are
;initialized from the LH of the HISEG copy of PLTTYP.
P4.ACT==400000,,0 ;Plotter is currently active (must be sign bit)
P4.INI==200000,,0 ;Plotter has been initialized by call to PLOTS
P4.TTY==100000,,0 ;In HISEG = Graphics terminal, default output to TTY:
;In P4 = Output is to a TTY:, dump buffers often
P4.TT8== 40000,,0 ;Outputing to TTY in binary, generate parity
P4.OUP== 20000,,0 ;Old position pen up (OLD.BD invalid in CHECK routine)
P4.WIN== 10000,,0 ;Too late to call subroutine SETWIN
;;;;;;== 7777,,0 ;(unused)
ND FTTERM,0 ;Gets defined as non-zero if any graphics terminals
SUBTTL Data definitions -- PPDATA - Per-plotter macro
;Definitions for LH of PLTINI(P4)
IN.BYT==770000,,0 ;Initial byte size (36, 18, 8, or 7)
IN.ACK== 4000,,0 ;Terminal sends ACKs, set up input buffer also
;;;;;;== 2000,,0 ;(unused) (puts IN.MOD on an octal boundry)
IN.MOD== 1700,,0 ;I/O mode (.IOASC or .IOBIN)
;;;;;;== 140,,0 ;(unused)
;;;;;;== 37,,0 ;Must be zero for @PLTINI(P4)
;Definitions for LH of PLTFIN(P4)
FN.SIZ==777_33 ;Size of data area (including local and per-plotter)
;;;;;;== 740,,0 ;(unused)
;;;;;;== 37,,0 ;Must be zero for @PLTFIN(P4)
;Definitions for PLTSPC(P4)
;The LH has 18 flags, one for each routine this plotter supports.
;The RH is an address, PUSHJed to with one of the flag bits set in T1
SP.PEN==1B0 ;NEWPEN - Change pen color
SP.CLR==1B1 ;ERASE - Clear the screen
SP.XHR==1B2 ;XHAIRS - Trigger crosshairs on Tektronix and GIGI
SP.OPR==1B3 ;OPRTXT - Send message to OPR via PLTSPL/SPROUT
SP.TTL==1B4 ;TITLE - Has hardware character generator
SP.PAS==1B5 ;PAUSEP - Pause plot for a few seconds
;;.LIN==1B6 ;xxxxxx - Sets line type (solid vs dashed)
;Definitions for CURR.P(P4)
PN.DWN== 1 ;Pen is down
PN.FL1== 2 ;Flag 1 (long mode)
PN.FL2== 4 ;Flag 2
;;;;;;== 70 ;(unused)
PN.COL== 7700 ;Pen color
;;;;;;==770000 ;(unused)
;The XBLOCK macro is used to assign offsets in the LCDATA macro expansion
DEFINE XBLOCK(LABEL,SIZE),<LABEL==<..==..+SIZE>-SIZE>
XLIST ;Definition of PPDATA macro
DEFINE PPDATA (NM),< LALL
NM'.DA: ;HISEG copy of plotter dispatch table
PHASE 0 ;All these definitions must be indexed by P4
PLTEXT:!NM'EXT,,CHAIN ;Extension of PLOT file ,, pointer to prototype
PLTTYP:!EXP NM'TYP ;Plotter type bits (P4.TTY in particular)
PLTNAM:!-NM'LEN,,NM'NAM ;Pointer to name or actual name for PLOTS
PLTINI:! NM'BYT!NM'INI ;Initialize the plotter (byte size in LH)
PLTFIN:!NM'SIZ_33+NM'FIN;Size of data area ,, finish off the plot
PLTMOV:!EXP NM'MOV ;Move the pen, T1=0 for pen up, T1=-1 for pen down
PLTPAS:!EXP NM'PAS ;T1=-1 to pause, T1=0 for ASCII, T1=+1 for resume
PLTSPC:! NM'FLG!NM'SPC ;Special routine (NEWPEN,ERASE,XHAIRS,OPRTXT)
PLTINX:!EXP NM'INX ;Increments per inch for X in floating point
PLTINY:!EXP NM'INY ;Increments per inch for Y in floating point
PLTMAX:!EXP NM'MAX ;Max increments X ,, Max increments Y
PLTDAT:! ..==LOCL.D ;Set pseudo location counter for local data
LCDATA ;Expand macro for local data
NM'SIZ==.. ;Size of this plotter's data area
IFG <NM'SIZ-PLTSIZ>,<PLTSIZ==NM'SIZ> ;Remember size of biggest data area
DEPHASE
CHAIN==NM'.DA ;Update pointer
SALL ;End of PPDATA macro
IFN NM'TYP&P4.TTY,<FTTERM==-1> ;Define feature-test if for terminal
> ;End of DEFINE PPDATA
LIST
PLTSIZ=<PLTLEN=<PLTBYT=<PLTFLG=0>>>;Dummy definitions for prototype
DEFINE LCDATA,<> ; " " " "
PPDATA (PLT) ;Expand PPDATA macro to define PLTDAT and CHAIN
;Note: When P4 is setup to point to the data in the LOSEG, PLTTYP(P4) has
; special flags unique to that plotter subtype (Tek 4014 vs 4010) and
; PLTNAM(P4) is the ASCII name that was used in CALL PLOTS(IERR,NAME).
; The RH of PLTEXT(P4) points to the original prototype in the HISEG.
; PLTINI through PLTDAT-1 refer to constants that have been BLT'ed down
; to the LOSEG.
PAGE
PHASE PLTDAT ;Start of variables common to all plotters
FILE.D:!BLOCK 1 ;Output device in use 'TTY' or 'DSK'
FILE.N:!BLOCK 1 ;Output file name (same as program name)
ZERO.F==. ;First word to zero on initialization
BUFR.N:!BLOCK 1 ;I/O channel number ,, addr of buffer
BUFR.H:!BLOCK 3 ;3-word buffer header
BUFR.P==BUFR.H+1 ;Byte pointer
BUFR.C==BUFR.H+2 ;Byte count for this buffer
BYTE.C:!BLOCK 1 ;Total number of bytes output to this plotter
CURR.P: BLOCK 1 ;Current pen status (0)
CURR.X: BLOCK 2 ;Current position, in increments (0)
CURR.Y=CURR.X+1 ;Current position, in increments (0)
MAXP.X: BLOCK 2 ;Highest X position, in increments (0)
MAXP.Y=MAXP.X+1 ;Highest Y position, in increments (0)
WMIN.X: BLOCK 2 ;Left edge of current window (0.0)
WMIN.Y=WMIN.X+1 ;Bottom edge of current window (0.0)
WMAX.X: BLOCK 2 ;Right edge of current window (11.0)
WMAX.Y=WMAX.X+1 ;Top edge of current window (11.0)
;---------------------------------------------------------------------
ZERO.R=. ;First word to zero on reset
OLDP.X: BLOCK 2 ;Old pen position, in inches (0.0)
OLDP.Y=OLDP.X+1 ;Old pen position, in inches (0.0)
OLD.BD: BLOCK 1 ;Old boundry flags (0)
ROTA.A: BLOCK 1 ;Angle of rotation (0.0)
ROTA.S: BLOCK 2 ;Sine of rotation (0.0)
ROTA.C=ROTA.S+1 ;Cosine of rotation (1.0)
ROTA.H: BLOCK 2 ;Horizontal offset after rotation (0.0)
ROTA.V=ROTA.H+1 ;Vertical offset after rotation (0.0)
FACT.X: BLOCK 2 ;Scaling factor (1.0)
FACT.Y=FACT.X+1 ;Scaling factor (1.0)
SUBW.F: BLOCK 1 ;-1 if subwindow active, +1 if defined (0)
SMIN.X: BLOCK 2 ;Left edge of subwindow
SMIN.Y=SMIN.X+1 ;Bottom edge of subwindow
SMAX.X: BLOCK 2 ;Right edge of subwindow
SMAX.Y=SMAX.X+1 ;Top edge of subwindow
ZERO.L==.-1 ;Last word to zero
LOCL.D: ;Start of LCDATA
DEPHASE
RELOC 0 ;Make sure LOSEG counter is correct
RELOC PLT.DA+PLTEXT+1 ;Keep PLT.DA+PLTEXT, reclaim all else
CHAIN==0 ;Set for end/beginning of chain
PLTSIZ==0 ;Actual size defined later
PURGE PLTLEN,PLTBYT,PLTFLG ;Delete dummy symbols
SUBTTL Subroutine PLOT -- Get the X and Y coordinates to move to
;CALL PLOT (X,Y,IFUNC)
ENTRY %PLOT
SIXBIT /%PLOT/ ;This is here for subroutine TRACE.
%PLOT: MOVEM L,SAVEL ;Save pointer to arg list
AOS C.PLOT ;Count this call to plot
MOVE X,@0(L) ;Get the caller's X
MOVE Y,@1(L) ;Get the caller's Y
MOVE T1,@2(L) ;Get caller's function
;Routine to move the pen.
;Calling sequence:
; DMOVE X,(coordinates in inches)
; MOVEI T1,(function code) ;+2, +3, or -3 for normal moves
; PUSHJ P,PLOT
; *return*
; Uses P3, P4, L, and all temp ACs
PLOT: MOVEM T1,S.ORIG ;Negative codes reset the origin
MOVM T2,T1 ;Get absolute value of function
CAILE T2,^D999 ;Called with floating point arg?
ERRSTR (FTL,<Illegal call to PLOT, code must be less than 1000>)
CAILE T2,MAXFUN ;Is it more than max?
MOVEI T2,MAXFUN+1 ;Yes, function 999 ends the plot
SKIPGE T1,FUNCS(T2) ;Skip if normal pen movement function
PJRST (T1) ;Functions 0 and 999 are special cased
;The routines in the FUNCS list expect T2, X, and Y to be set up.
;They return with T1, X, and Y adjusted.
PUSHJ P,(T1) ;Convert delta or polar to (X,Y), set T1
MOVEM T1,P.DOWN ;-1 for pen down, 0 for pen up
DMOVEM X,X.CALL ;Save caller's position for subroutine WHERE
MOVSI P3,-PLTNUM ;Number of plotters
PLOT1: SKIPGE P4,PLTTAB(P3) ;Is this plotter active?
PUSHJ P,PLOTIT ;Yes, move the pen
MOVEM P4,PLTTAB(P3) ;Save new status
AOBJN P3,PLOT1 ;Loop for all plotters
SKIPL S.ORIG ;Is function code negative?
JRST PLOT2 ;No,
DMOVE X,X.CALL ;Yes, set origin
FADRM X,X.ORIG ; to caller's arguments so
FADRM Y,Y.ORIG ; CALL PLOT(0.0,0.0,3) will return to here
PLOT2: MOVE L,SAVEL ;Restore AC 16
POPJ P, ;Return from PLOT
SUBTTL Subroutine PLOT -- Table of plotter functions
FUNCS: FUNC0!1B0 ;Pause output to plotter *special routine*
FUNC1 ;Use the last pen value
FUNC2 ;Cause the pen to be down
FUNC3 ;Cause the pen to be up
FUNC4 ;Go shift the origin (without moving the pen)
FUNC5 ;Go set up for delta X and Y movement (old pen)
FUNC6 ;Go set up for delta X and Y movement (pen down)
FUNC7 ;Go set up for delta X and Y movement (pen up)
FUNC8 ;Go set up for polar coordinates (DEG. - old pen)
FUNC9 ;Go set up for polar coordinates (DEG. - pen down)
FUNC10 ;Go set up for polar coordinates (DEG. - pen up)
FUNC11 ;Go set up for polar coordinates (RAD. - old pen)
FUNC12 ;Go set up for polar coordinates (RAD. - pen down)
FUNC13 ;Go set up for polar coordinates (RAD. - pen up)
MAXFUN==.-FUNCS-1 ;Set up for the maximum number of functions
FUNC99!1B0 ;Finish plot *special routine*
FUNC0: MOVSI P3,-PLTNUM ;0 - Pause the plotter
FUNC0A: SKIPL P4,PLTTAB(P3) ;Is plotter active?
JRST FUNC0B ;No, try next one
PUSHJ P,PLOTUP ;Tell it to move to (X,Y)
SETO T1, ;-1 for pause
PUSHJ P,@PLTPAS(P4) ;Tell it to pause
FUNC0B: AOBJN P3,FUNC0A ;Loop through all
POPJ P, ;Return from PLOT(X,Y,0)
;Functions 1, 5, 8, or 11 - Move without changing pen up/down status
;X and Y have the co-ordinates, T2 has the function code
FUNC1: MOVE T1,P.DOWN ;Get old pen down status
CAIN T2,1 ;Function 1, 5, 8, or 11?
POPJ P, ;Yes, X, Y, and T1 are all set
FUNC2: CAIE T2,2 ;2 - Move with pen down (P.DOWN=-1)
FUNC3: TDZA T1,T1 ;3 - Move with pen up (P.DOWN=0)
SETO T1, ;Set down flag
POPJ P, ;Virtual position in X,Y, pen flag in T1
FUNC4: SKIPG S.ORIG ;4 - Shift origin, make current position (X,Y)
SETZB X,Y ;Make current position (0,0) for function -4
MOVMS S.ORIG ;Tell PLOT1 not to bother changing origin
DMOVE T1,X.CALL ;Get current position
FSBR T1,X ;Calculate new offset
FSBR T2,Y
DMOVEM T1,X.ORIG ;Remember new origin
MOVEI T2,3 ;Translate code 4 to code 3
JRST FUNC1 ;Set pen/up code and continue
;More PLOT functions
PI%180: 173435750650 ;PI over 180, 3.14/180 = 1/57.29 = 0.01745329252
;(In octal because MACRO is off in the LSB)
FUNC5: ;Move relative to current position
FUNC6:
FUNC7: SUBI T2,4 ;Convert the function to 1, 2 or 3
FADR X,X.CALL ;Add delta to old X
FADR Y,Y.CALL ;Add delta to old Y
JRST FUNC1 ;Check for pen up/down
FUNC8: ;Move to X inches at Y degrees
FUNC9:
FUNC10: SUBI T2,7 ;Convert the function to 1, 2 or 3
FMPR Y,PI%180 ;Convert degrees to radians
JRST FUN13A ;Go to it
FUNC11: ;Move to X inches at Y radians
FUNC12:
FUNC13: SUBI T2,^D10 ;Convert the function to 1, 2 or 3
FUN13A: MOVEM Y,ANGLE ;Store radian angle
MOVE Y,X ;Duplicate radius
XMOVEI L,[-1,,0 ;1 argument
REAL ANGLE ;Angle in radians
]+1 ;Point to args
PUSHJ P,COS.## ;Get the cosine of the angle
FMPR X,T0 ;Cosine times radius
PUSHJ P,SIN.## ;Get the sine of the angle
FMPR Y,T0 ;Sine times radius
JRST FUNC1 ;Check for pen up/down
FUNC99: MOVSI P3,-PLTNUM ;Finish the plot
FUN99A: SKIPL P4,PLTTAB(P3) ;Is this plotter active?
JRST FUN99B ;No, try next one
;Should check for -999, and abort the plot
PUSHJ P,FINPLT ;Yes, finish up
PUSHJ P,DEAPLT ;Deassign the plotter data base
FUN99B: AOBJN P3,FUN99A ;Loop for all
POPJ P, ;Return from PLOT(X,Y,999)
;Close output file, enter here with P3 and P4 set up
FINPLT: PUSHJ P,PL.FIN ;Reset rotation and scaling factors
PUSHJ P,@PLTFIN(P4) ;Finish the plot
TXNE P4,P4.TTY ;Output going to a TTY?
PUSHJ P,TTYFIN ;Yes, clear the GAG bit
PUSHJ P,CLSFIL ;Close file, release channel, deassign buffer
TXZ P4,P4.ACT!P4.INI;Plotter is not active
MOVEM P4,PLTTAB(P3) ;Store flags
POPJ P, ;Return to FUNC99 or PLOTS
SUBTTL Subroutine PLOT -- PLOTIT - Translate, scale, and rotate coordinates
;Routine to position with the pen up. Called by by PLOT(X,Y,0) to force
;movement before pausing, and by PLOTS to put the pen in a known position.
PLOTUP: SETZB T1,P.DOWN ;Move to (X,Y) with pen up
PUSHJ P,PLOTI1 ;Account for origin and rotation
PJRST MOVUPX ;Go there (should never be outside the window)
;Routine to move pen subject to window checking
;Calling sequence:
; DMOVE X,(position in inches)
; PUSHJ P,PLOTUP or PUSHJ P,PLOTDN
; *return* Line may be clipped if it exceeds the window
PLOTDN: SETOB T1,P.DOWN ;Move to (X,Y) with pen down
JRST PLOTI1 ;Coordinates are already in X and Y
;Xcall,Ycall = X and Y as supplied by the caller (after polar conversion)
;Xorigin,Yorigin = Origin as set by CALL PLOT (Xorigin,Yorigin,-3)
;Xfactor,Yfactor = Scaling factor as set by CALL FACTOR (Xfactor,Yfactor)
;Xrot,Yrot,SIN,COS = Rotation as set by CALL ROTATE (-1,Xrot,Yrot,Angle)
;
; X1 = (Xcall + Xorigin) * Xfactor ;Global translation
; Y1 = (Ycall + Yorigin) * Yfactor ; with local scaling.
; Xout = X1*COS(Angle) - Y1*SIN(Angle) + Xrot ;Local rotation and
; Yout = Y1*COS(Angle) + X1*SIN(Angle) + Yrot ; local translation.
;
;Window checking is done after scaling, rotation, and translation.
;That is, the window boundries are always vertical and horizontal, and in
;absolute inches. To optimize pen movement, consecutive pen-up moves are
;merged into one when the next pen-down move occurs.
;Call with X.CALL, Y.CALL, and P.DOWN set
PLOTIT: DMOVE X,X.CALL ;Get X and Y arguments
PLOTI1: TXO P4,P4.WIN ;Too late to call SETWIN, plotting has started
FADR X,X.ORIG ;Adjust for the
FADR Y,Y.ORIG ; global origin
FMPR X,FACT.X(P4) ;Scale the data
FMPR Y,FACT.Y(P4) ; for this plotter
SKIPE ROTA.A(P4) ;If this plot is rotated,
PUSHJ P,TWIST ; adjust X and Y
FADR X,ROTA.H(P4) ;Add in the horizontal
FADR Y,ROTA.V(P4) ; and vertical offsets after rotation
DMOVEM X,X.NEWP ;Save new position
SKIPL P.DOWN ;Move with pen down?
JRST [DMOVEM X,OLDP.X(P4) ;No, just update old position
TXO P4,P4.OUP ;The old position is up, OLD.BD is invalid
POPJ P, ] ;Move the pen later
PJRST CHECK ;Do window checking and call MOVUP and MOVDN
SUBTTL Subroutine PLOT -- MOVDN and MOVUP - move the pen
;Routine to actually move the pen.
;Calling sequence:
; DMOVE X,(absolute position in inches, after rotation)
; PUSHJ P,MOVDN or PUSHJ P,MOVUP
; *return*
MOVUPX: DMOVE X,OLDP.X(P4) ;Get position of CALL PLOT(X,Y,3)
TXZN P4,P4.OUP ;Was old position with pen up?
POPJ P, ;No, no pen is already in position
PFALL MOVUP ;Yes, force movement with pen up
;Here when moving the pen. Keep track of highest position
MOVUP: TDZA T1,T1 ;T1 has 0 to move with pen up
MOVDN: SETO T1, ;T1 has -1 to move with pen down
CAMLE X,MAXP.X(P4) ;Is this the max X position?
MOVEM X,MAXP.X(P4) ;Yes, save coordinate (in floating point)
CAMLE Y,MAXP.Y(P4) ;Is this the max Y position?
MOVEM Y,MAXP.Y(P4) ;Yes
PUSHJ P,FP2INC ;Convert to increments
SKIPL X ;Negative?
SKIPGE Y
PUSHJ P,GO2DDT ;Yes, bug
PJRST @PLTMOV(P4) ;Move with pen down
.JBBPT==76
GO2DDT: SKIPE .JBBPT ;Is DDT loaded?
JSR @.JBBPT ;Yes, hit breakpoint zero
POPJ P,
;Routine to convert floating-point inches to increments
;Calling sequence:
; DMOVE X,(position in inches)
; PUSHJ FP2INC
; *return*
FP2INC: FMPR X,PLTINX(P4) ;Convert to increments
IFE FTKA,<FIXR X,X> ;Convert to integer
IFN FTKA,<PUSHJ P,IFX.X>
FMPR Y,PLTINY(P4) ;Convert to increments
IFE FTKA,<FIXR Y,Y> ;Convert to integer
IFN FTKA,<PUSHJ P,IFX.Y>
POPJ P,
SUBTTL Main routines -- ERASE - Clear the screen
;CALL ERASE
ENTRY %ERASE
SIXBIT /%ERASE/
%ERASE: MOVEM L,SAVEL ;Preserve AC16 across call
MOVSI P3,-PLTNUM ;Get length of table
ERASE1: SKIPL P4,PLTTAB(P3) ;Is this plotter active?
JRST ERASE2 ;No, try next one
MOVSI T1,(SP.CLR) ;Bit to test
MOVE T2,PLTSPC(P4) ;Get flags for special routine
TDNE T1,T2 ;Does this plotter support ERASE?
PUSHJ P,(T2) ;Yes, call it with SP.CLR in T1
ERASE2: AOBJN P3,ERASE1 ;Loop for all plotters
MOVE L,SAVEL ;Restore AC16
POPJ P, ;Return from ERASE
SUBTTL Main routines -- FACTOR - Change the scaling factor
;CALL FACTOR (XFACT,YFACT)
;Note: Factors are NOT cumulative. CALL FACTOR(1.0) will reset to normal size
ENTRY %FACTOR
SIXBIT /%FACTO/
%FACTOR:MOVEM L,SAVEL ;Preserve AC16 across call
MOVE X,@0(L) ;Get scaling factor for X (1.0 is normal)
MOVE Y,@1(L) ;Get scaling factor for Y
SKIPN X ;Non-zero?
MOVE X,X.FACT ;No, keep factors unchanged
SKIPN Y
MOVE Y,Y.FACT
DMOVE T1,X.FACT ;Get old factors
FDVR T1,X ;Ratio of old over new
FDVR T2,Y
FMPRM T1,X.ORIG ;Change the offsets so that
FMPRM T2,Y.ORIG ; (X+X.ORIG)*FACT.X does not change position
DMOVEM X,X.FACT ;Save for subroutine WHERE
MOVSI P3,-PLTNUM ;Get length of table
FACTO1: SKIPL P4,PLTTAB(P3) ;Is this plotter active?
JRST FACTO2 ;No, try next one
MOVEM X,FACT.X(P4) ;Set to new factor (non-cumulative)
MOVEM Y,FACT.Y(P4) ; (Call WHERE to get current factors)
FACTO2: AOBJN P3,FACTO1 ;Loop for all plotters
MOVE L,SAVEL ;Restore AC16
POPJ P, ;Return from FACTOR
SUBTTL Main routines -- GETWIN - Get status of universal window
;CALL GETWIN (XORIG,YORIG,XWIND,YWIND,XMAXW,YMAXW,IPRIV)
;**** INCOMPLETE ** UNDOCUMENTED ** INCOMPLETE ** UNDOCUMENTED ** INCOMPLETE ***
ENTRY %GETWIN
SIXBIT /%GETWI/
%GETWIN:MOVEM L,SAVEL ;Preserve AC 16
SKIPN X.WMAX ;If GETLIM has not been called,
PUSHJ P,GETLIM ; read limits from SYS:PRIV.SYS
DMOVE X,X.ORIG ;Get CALL PLOT(XORIG,YORIG,-3) values
MOVEM X,@0(L) ;Return XORIG
MOVEM Y,@1(L) ; and YORIG
HRROI T1,P.WIND ;Set up POP pointer to the data
POP T1,@6(L) ;P.WIND privilege bits (0)
POP T1,@5(L) ;Y.WMAX max Y limit (from PRIV.SYS)
POP T1,@4(L) ;X.WMAX max X limit
POP T1,@3(L) ;Y.WIND current Y limit (from SETWIN)
POP T1,@2(L) ;X.WIND current X limit
MOVE L,SAVEL ;Restore AC 16
POPJ P, ;Return from GETWIN
;**** INCOMPLETE ** UNDOCUMENTED ** INCOMPLETE ** UNDOCUMENTED ** INCOMPLETE ***
SUBTTL Main routines -- NEWPEN - Change pen color or line type
;CALL NEWPEN (IPEN,IERR)
;The routines in PLTUNV handle the case of being called as a function.
ENTRY %NEWPEN
SIXBIT /%NEWPEN/
%NEWPEN:MOVE T0,@0(L) ;Get pen number or name
JUMPN T0,NEWPE0 ;Nonzero, go set it
MOVE T0,C.NPEN ;Zero, get previous pen color
MOVEM T0,@1(L) ;Store as IERR
POPJ P, ;Return with value in T0
NEWPE0: MOVEM T0,C.NPEN ;Store
MOVSI P3,-PLTNUM ;Get size of table
NEWPE1: SKIPL P4,PLTTAB(P3) ;Is this plotter active?
JRST NEWPE2 ;No, try next one
PUSHJ P,MOVUPX ;Yes, make sure pen is positioned correctly
MOVSI T1,(SP.PEN) ;Bit to test
MOVE T2,PLTSPC(P4) ;Get flags for special routine
TDNE T1,T2 ;Does this plotter support NEWPEN?
PUSHJ P,(T2) ;Yes, call it with SP.PEN in T1
TXNE P4,P4.TTY ;Output to a TTY?
PUSHJ P,DUMPBF ;Yes, dump the buffer
MOVEM P4,PLTTAB(P3) ;Incase any of the flag bits have changed
NEWPE2: AOBJN P3,NEWPE1 ;Loop for all plotters
POPJ P, ;Return from NEWPEN
SUBTTL Main routines -- OPRTXT - Send message to OPR when plot comes out
;CALL OPRTXT ('Message for the OPR') !Literal or CHARACTER string
;The routines in PLTUNV handle the old arguments of array and byte count
ENTRY %OPRTXT
SIXBIT /OPRTXT/
%OPRTXT:MOVEM L,SAVEL ;Preserve AC 16
DMOVE T1,@0(L) ;Get byte string descriptor
DMOVEM T1,P.BYTE ;Store pointer and counter
MOVSI P3,-PLTNUM ;Get size of table
OPRTX1: SKIPL P4,PLTTAB(P3) ;Is this plotter active?
JRST OPRTX2 ;No, try next one
MOVSI T1,(SP.OPR) ;Bit to test
MOVE T2,PLTSPC(P4) ;Get flags for special routine
TDNE T1,T2 ;Does this plotter support OPRTXT?
PUSHJ P,(T2) ;Yes, call it with SP.OPR in T1
OPRTX2: AOBJN P3,OPRTX1 ;Loop for all plotters
MOVE L,SAVEL ;Restore AC 16
POPJ P, ;Return from OPRTXT
SUBTTL Main routines -- PAUSEP - Temporarily turn off a plotter
;CALL PAUSEP (NSEC)
ENTRY %PAUSEP
SIXBIT /%PAUSE/
%PAUSE: MOVEM L,SAVEL ;Preserve AC16 across call
MOVSI P3,-PLTNUM ;Get size of table
PAUSE1: SKIPL P4,PLTTAB(P3) ;Is this plotter active?
JRST PAUSE2 ;No, try next one
SKIPL T1,@0(L) ;Get number of seconds
CAILE T1,^D60 ;Reasonable?
MOVEI T1,^D60 ;No, 1 minute is max
IMULI T1,^D1000 ;Convert to milliseconds
;Need a routine to put an OPCODE in the spooled output file
TXNE P4,P4.TTY ;Output to a graphics terminal?
PUSHJ P,TOWAIT ;Yes, wait
PAUSE2: AOBJN P3,PAUSE1 ;Loop for all plotters
MOVE L,SAVEL ;Restore AC16
POPJ P, ;Return from PAUSEP
SUBTTL Main routines -- PLOTCH - Output characters to a plotter
;CALL PLOTCH ('TEK','!COLOR BLUE')
ENTRY %PLTCH
SIXBIT /%PLTCH/
%PLTCH: MOVEM L,SAVEL ;Preserve AC16 across call
MOVE T1,@0(L) ;Get name from caller
PUSHJ P,SETYPE ;Set up P4 for type of plotter
JRST PLTCH1 ;No such plotter
TXNE P4,P4.TTY ;Output to a TTY?
TXNN P4,P4.ACT ; and plotter active?
JRST PLTCH1 ;No
PUSHJ P,MOVUPX ;Make sure pen is positioned
DMOVE T1,@1(L) ;Get byte pointer and count
PUSHJ P,OUTWRD ;Output the string
PUSHJ P,DUMPBF ;Dump buffer
PLTCH1: MOVE L,SAVEL ;Restore AC16
POPJ P, ;Return from PLOTCH
SUBTTL Main routines -- PLOTER - Define an alias plotter
IFN FTAPLT,< ;If alias plotters are allowed,
;CALL PLOTER ('SPOOL','FUBAR',IERR)
ENTRY %PLTER
SIXBIT /%PLTER/
%PLTER: MOVEM L,SAVEL ;Preserve AC16 across call
MOVE T1,@0(L) ;Get name from caller
PUSHJ P,SPTYPE ;Set up P4 for the type of plotter
JRST [SETOM @1(L) ;P4 is zero if no such plotter
JRST PLTER9] ;Don't set X and Y
;**** INCOMPLETE ** UNDOCUMENTED ** INCOMPLETE ** UNDOCUMENTED ** INCOMPLETE ***
PLTER9: MOVE L,SAVEL ;Restore AC16
POPJ P, ;Return from PLOTER
> ;End of IFN FTAPLT
SUBTTL Main routines -- PLOTOF - Temporarily turn off a plotter
;CALL PLOTOF ('TEK')
ENTRY %PLTOF
SIXBIT /%PLTOF/
%PLTOF: MOVEM L,SAVEL ;Preserve AC16 across call
MOVE T1,@0(L) ;Get name from caller
PUSHJ P,SETYPE ;Set up P4 for type of plotter
JRST PLTOF1 ;No such plotter
TXZN P4,P4.ACT ;Is plotter active?
JRST PLTOF1 ;No
MOVEI T1,0 ;0 to temporarily turn plotter off
PUSHJ P,@PLTPAS(P4) ;Tell terminal to switch back to ASCII
MOVEM P4,PLTTAB(P3) ;Store with bit off
TXNE P4,P4.TTY ;Output to a terminal?
PUSHJ P,TTASCM ;Yes, set TTY to ASCII mode
PLTOF1: MOVE L,SAVEL ;Restore AC16
POPJ P, ;Return from PLOTOF
SUBTTL Main routines -- PLOTOK - Get status of the plotter
;CALL PLOTOK ('SPOOL',IOK,X,Y)
;**** INCOMPLETE ** UNDOCUMENTED ** INCOMPLETE ** UNDOCUMENTED ** INCOMPLETE ***
ENTRY %PLTOK
SIXBIT /%PLTOK/
%PLTOK: MOVEM L,SAVEL ;Preserve AC16 across call
MOVE T1,@0(L) ;Get name from caller
PUSHJ P,SETYPE ;Set up P4 for the type of plotter
JRST [SETOM @1(L) ;No such plotter
JRST PLTOK9] ;Don't set X and Y
MOVEI T1,0 ;0 means plotter not in use
TXNE T1,P4.INI ;Initialized?
MOVEI T1,1 ;1 means temporarily off
TXNE P4,P4.ACT ;Active?
MOVEI T1,2 ;2 means active
MOVEM T1,@1(L) ;Return IOK
DMOVE X,CURR.X(P4) ;Get current position in increments
PUSHJ P,INC2FP ;Convert to floating-point and un-rotate
MOVEM X,@2(L) ;Return X
MOVEM Y,@3(L) ;Return Y
PLTOK9: MOVE L,SAVEL ;Restore AC16
POPJ P, ;Return from PLOTOK
;**** INCOMPLETE ** UNDOCUMENTED ** INCOMPLETE ** UNDOCUMENTED ** INCOMPLETE ***
SUBTTL Main routines -- PLOTON - Resume output to a plotter
;CALL PLOTON ('TEK')
ENTRY %PLTON
SIXBIT /%PLTON/
%PLTON: MOVEM L,SAVEL ;Preserve AC16 across call
MOVE T1,@0(L) ;Get name from caller
PUSHJ P,SETYPE ;Set up P4 for type of plotter
JRST PLTON1 ;No such plotter
TXNN P4,P4.INI ;Has this plotter been initialized?
JRST PLTON1 ;No, leave it alone
TXOE P4,P4.ACT ;Yes, re-activate it
JRST PLTON1 ;Already on
TXNE P4,P4.TTY ;Output to a terinal?
PUSHJ P,TTBINM ;Yes, set TTY to BINARY plotting mode
MOVEI T1,1 ;+1 to resume plotting
PUSHJ P,@PLTPAS(P4) ;Tell terminal to switch to graphics mode
MOVEM P4,PLTTAB(P3) ;Store new status
PLTON1: MOVE L,SAVEL ;Restore AC16
POPJ P, ;Return from PLOTON
SUBTTL Main routines -- PLOTS - Initialize the plotter
;CALL PLOTS (IERR,'SPOOL','DSK:TEST.PLT')
;Decode the plotter type (if present) and the output file name (if present),
;allocate space in the LOSEG for variables, open the plot file, initialize
;all its variables, and return IERR=0 if all went well.
;The routines in PLTUNV do conversion to FORTRAN-77 CHARACTER variables
ENTRY %PLOTS
SIXBIT /%PLOTS/
%PLOTS: MOVEM L,SAVEL ;Preserve AC16 across call
SKIPE T1,@0(L) ;Get IERR value
MOVEM T1,Z.ERRC ;Save error counter if non-zero
SETOM @0(L) ;Assume failure
;Set up the output device and file name first. This is so that
;CALL PLOTS(IERR,'TTY','TTY2:') can decide on 'TEK' vs 'GIGI' routine.
DMOVE T2,@2(L) ;Get byte pointer/count to name
PLOTS0: PUSHJ P,GETNAM ;Set default output device and file name
;Determine which type of plotter to activate
MOVE T1,@1(L) ;Get plotter type
PUSHJ P,SPTYPE ;Search name tables and set up T2, P3, and P4
POPJ P, ;No match, IERR is -1 (No such plotter)
MOVEM T1,Z.FLAG ;Save plotter sub-type flags
JUMPE P3,PLOTS2 ;OK if not already active
;Here when IPLT matches the name of a plotter that was previously set up.
TXNN P4,P4.INI ;Is it really active
JRST PLOTS4 ;No, use pre-defined alias data area
PUSHJ P,ISACTV ;See if the channel or JFN is still assigned
JRST PLOTS1 ;Not active, program must have been restarted
ERRSTR (WRN,<% PLOT - Subroutine PLOTS called with plotter already active>)
PUSHJ P,TRACE
PUSHJ P,FINPLT ;Finish off old plot
PLOTS1: PUSH P,PLTEXT(P4) ;Save pointer to original data in HISEG
PUSHJ P,DEAPLT ;Deallocate the plot data area
POP P,T1
HRR P4,T1 ;Point to prototype
PAGE
;Find a slot in PLTTAB to store flags and pointer for this plotter
;P4 points to the prototype data
PLOTS2: MOVSI P3,-PLTNUM ;Get size of PLTTAB
PLOTS3: SKIPN PLTTAB(P3) ;Is this slot open?
JRST PLOTS4 ;Yes
AOBJN P3,PLOTS3 ;No, try next one
SOS @0(L) ;No room, set IERR is -2 (Too many plotters)
POPJ P, ;Return from PLOTS
;Here to deallocate the plotter database that was obtained at PLOTS4.
DEAPLT: IFN FTAPLT,< ;Preserve data set up by PLOTER routine
TXNE P4,P4.ALS ;Is this an alias?
POPJ P, ;Yes, leave it be
> ;End of IFN FTAPLT
MOVEI T1,(P4) ;Address of data area
PUSHJ P,DECOR ;Release that memory
SETZM PLTTAB(P3) ;Free up the slot
POPJ P,
PLOTS4: LDB T1,[POINTR PLTFIN(P4),FN.SIZ] ;Get size of data area
PUSHJ P,ALCOR ;Set T1 to point to free space in BUFFER
;P3 points into PLTTAB, P4 points to HISEG data, T1 points to LOSEG area
MOVE T2,T1 ;BLT will destroy 2nd copy
HRL T2,P4 ;Source ,, destination
BLT T2,PLTDAT-1(T1) ;Copy constants from HISEG to LOSEG
MOVE T2,PLTNAM(P4) ;Get pointer to names
HRRM P4,PLTEXT(T1) ;Store pointer to prototype
HRR P4,T1 ;Now P4 points to LOSEG data (flags in LH)
MOVE T3,0(T2) ;Get primary alias
MOVEM T3,Z.NUMB ;Store small integer for subroutine WHERE
MOVE T1,Z.FLAG ;Get the plotter sub-type flags
MOVEM T1,PLTTYP(P4) ;Store
MOVE T1,Z.CALL ;Get argument to PLOTS
MOVEM T1,PLTNAM(P4) ;Store for PLOTOF('TTY')
PUSHJ P,SETODV ;Set FILE.D(P4) to output device, DSK: or TTY:
PUSHJ P,PL.INI ;Set up factors, offsets, rotation, etc
PAGE
HRLI P4,(P4.ACT!P4.INI) ;Set LH of P4 for active and initialized
PUSHJ P,OPNFIL ;Open output file, set T1=0 if OK
MOVE L,SAVEL ;Restore AC16
MOVEM T1,@0(L) ;Return error flag
JUMPN T1,CPOPJ ;Abort if flag not zero
PUSHJ P,TTYINI ;Set P4.TTY and P4.TT8 as appropriate
MOVEM P4,PLTTAB(P3) ;Store flags
PUSHJ P,@PLTINI(P4) ;Do device dependent initialization
PLOTS6: SETZB X,Y ;Move to (0,0)
DMOVEM X,X.CALL ;Remember coordinate
PUSHJ P,PLOTUP ;Initialize the rest of the variables
SETZB X,Y ;Now put the pen down at the origin
PUSHJ P,PLOTDN ; so that CALL PLOT(X,Y,1) works right
TXNE P4,P4.TTY ;Output going to a TTY?
PUSHJ P,DUMPBF ;Yes, dump output buffer now
POPJ P, ;Return from PLOTS
SUBTTL Main routines -- ROTATE - Change angle of rotation for the plot
;CALL ROTATE (IFUNC,XORG,YORG,ANGLE)
ENTRY %ROTATE
SIXBIT /%ROTAT/
%ROTATE:MOVEM L,SAVEL ;Preserve AC 16 across call
MOVE T1,@0(L) ;Get IFUNC
MOVE X,@1(L) ;Get X
MOVE Y,@2(L) ;Get Y
MOVE T2,@3(L) ;Get new ANGLE
MOVE T3,A.ROTA ;Get old ANGLE
;0 to clear, positive to sum angles, negative to set angle
SKIPG T1 ;Is IFUNC positive?
SETZM A.ROTA ;No, clear the old rotation angle
JUMPN T1,ROTAT1 ;Is IFUNC zero?
DMOVE X,X.ROTA ;Yes, get old coords for origin of rotation
MOVEM X,@1(L) ;Return the X value
MOVEM Y,@2(L) ;Return the Y value
MOVEM T3,@3(L) ;Return the old ANGLE
SETZB X,Y ;Clear offsets
MOVEI T2,0 ;Clear rotation for all active plotters
;IFUNC nonzero, set up for rotation
ROTAT1: DMOVEM X,X.ROTA ;Save origin of rotation
FADRB T2,A.ROTA ;Sum up the angles of rotation
FMPR T2,PI%180 ;Convert to radians
MOVEM T2,ANGLE ;Store
SETZM X.ORIG ;Cancel relative origin
SETZM Y.ORIG
XMOVEI L,[-1,,0 ;1 argument
REAL ANGLE ;Angle in radians
]+1 ;Point to args
PUSHJ P,COS.## ;Get the cosine of the angle
PUSH P,T0 ;Save for a while
XMOVEI L,[-1,,0 ;1 argument
REAL ANGLE ;Angle in radians
]+1 ;Point to args
PUSHJ P,SIN.## ;Get the sine of the angle
POP P,T1 ;SIN in T0, COS in T1
MOVE T2,A.ROTA ;Get current angle (in degrees)
DMOVE X,X.ROTA ;Get offset
;Set SIN, COS, and offset for all active plotters
MOVSI P3,-PLTNUM ;Get length of table
ROTAT2: SKIPL P4,PLTTAB(P3) ;Is plotter active?
JRST ROTAT3 ;No, try next one
DMOVEM T0,ROTA.S(P4) ;Store SIN and COS
MOVEM T2,ROTA.A(P4) ;Store angle
DMOVEM X,ROTA.H(P4) ;Store horizontal and vertical offset
ROTAT3: AOBJN P3,ROTAT2 ;Loop for all plotters
MOVE L,SAVEL ;Restore AC 16
POPJ P,
SUBTTL Main routines -- SETWIN - Set universal window for large plots
;CALL SETWIN (XWIND,YWIND,XWMAX,YWMAX,IPRIV)
ENTRY %SETWIN
SIXBIT /%SETWI/
%SETWIN:MOVE X,@(L) ;Get caller's arguments
MOVE Y,@1(L) ; for max X and Y
DMOVEM X,X.WIND ;Save
SKIPN X.WMAX ;Has GETLIM been called?
PUSHJ P,GETLIM ;No, get limits from SYS:PRIV.SYS
SKIPLE X,X.WIND ;X and Y must
SKIPG Y,Y.WIND ; be positive
JRST SETWI4 ;Error
DMOVE T1,X.WMAX ;Get max limits from PRIV.SYS
MOVEM T1,@2(L) ;Return XWMAX
MOVEM T2,@3(L) ; and YWMAX
SETWI1: MOVE T4,P.WIND ;Get privs
CAIG T3,-5 ;User specified 5 arguments?
MOVEM T4,@4(L) ;Yes
MOVSI P3,-PLTNUM ;Get size of table
SETWI2: SKIPL P4,PLTTAB(P3) ;Is this plotter active?
JRST SETWI3 ;No, skip it
TXOA P4,P4.WIN ;Is call to SETWIN allowed? **KLUDGE**
JRST SETWI5 ;Illegal call to SETWIN
SETZB T1,T2 ;Lower limits are zero
DMOVE X,X.WIND ;Get caller's argument
PUSHJ P,SETWIN ;Set WMAX.X(P4)
SETWI3: AOBJN P3,SETWI2 ;Loop for all plotters
MOVE L,SAVEL ;Restore AC16
POPJ P, ;Return from SETWIN
PAGE
;Here when an error was detected
SETWI4: SETOM S.ORIG ;Pretend it was a call to
PUSHJ P,FUNC99 ; PLOT(X,Y,999) and abort plot
ERRSTR (FTL,<? SETWIN - Illegal window size, call GETWIN to get size>)
PJRST TRACE ;Trace subroutine calls
SETWI5: SETOM S.ORIG ;Pretend it was a call to
PUSHJ P,FUNC99 ; PLOT(X,Y,999) and abort plot
ERRSTR (FTL,<? SETWIN - Cannot call SETWIN after PLOT has started>)
PJRST TRACE.## ;Trace subroutine calls
;Set current window size, respecting physical limits and PRIV.SYS limits
;Calling sequence:
; DMOVE T1,(requested minimums in inches)
; DMOVE X,(requested maximums in inches)
; PUSHJ P,SETWIN
; *return* Changes T1, T2, X, Y, WMIN.X(P4) and WMAX.X(P4)
SETWIN: DMOVEM T1,TEMP ;Save minimums for a while
SKIPN X.WIND ;If %SETWIN has not been called,
MOVEM X,X.WIND ; pretend CALL SETWIN(11.0,11.0)
SKIPN Y.WIND
MOVEM Y,Y.WIND
PUSHJ P,CHKLIM ;Convert X and Y from inches to max increments
DMOVEM X,WMAX.X(P4) ;Store current maximums
DMOVE X,TEMP ;Get minimums
PUSHJ P,CHKLIM ;Convert X and Y from inches to min increments
DMOVEM X,WMIN.X(P4) ;Store current minimums
POPJ P, ;Return to %SETWIN, %SUBWIN, or PL.INI
CHKLIM: SKIPGE X ;Limits must be positive
MOVEI X,0
SKIPGE Y
MOVEI Y,0
SKIPN X.WIND ;Check if SETWIN has been called
JRST CHKLM1 ;No explicit universal window
CAMLE X,X.WIND ;Subwindow must be within universal window
MOVE X,X.WIND
CAMLE Y,Y.WIND
MOVE Y,Y.WIND
CHKLM1: SKIPE X.WMAX ;Has PRIV.SYS been read?
TXNE P4,P4.TTY ;Output to a terminal?
JRST CHKLM2 ;Just use device maximums
CAMLE X,X.WMAX ;Must be within max limits in PRIV.SYS
MOVE X,X.WMAX
CAMLE Y,Y.WMAX
MOVE Y,Y.WMAX
CHKLM2: HLRE T1,PLTMAX(P4) ;Get max X increments
FLOAT T1 ;Convert to F.P.
FDVR T1,PLTINX(P4) ;Convert to inches
CAMLE X,T1 ;User limit smaller than plotter limit?
MOVE X,T1 ;No, set to physical limitation
HRRE T2,PLTMAX(P4) ;Same for Y
FLOAT T2
FDVR T2,PLTINY(P4)
CAMLE Y,T2
MOVE Y,T2
POPJ P, ;Return with X and Y set up
SUBTTL Main routines -- SUBWIN - Set/reset/status of sub-window
; Subroutine %SUBWIN - this routine sets up the subwindow
; Calling sequence:
; CALL SUBWIN(IFUNC,IVALUE,XO,YO,WIDTH,HEIGTH)
ENTRY %SUBWIN
SIXBIT /%SUBWI/
%SUBWI: MOVEM L,SAVEL ;Preserve AC16
SKIPN X.WMAX ;Has GETLIM been called?
PUSHJ P,GETLIM ;No, get limits from SYS:PRIV.SYS
SETOM @1(L) ;Assume failure
MOVE T1,@0(L) ;Get function argument
SKIPL T1 ;Check for positive function value
CAILE T1,MAXSUB ;And in range
SKIPA ;Check if 'SET'
PJRST @SFUN(T1) ;Go to the right function routine
PUSHJ P,UPCASE ;Convert arg in T1 to uppercase, no spaces
MOVSI T2,-4 ;Check 4 commands
SUBWN1: CAMN T1,SUBWNC(T2) ;Check if match
PJRST @SFUN(T2) ;Yes
AOBJN T2,SUBWN1 ;No
POPJ P, ;Return IVALUE=-1 for unknown command
SUBWNC: ASCII /SET/
ASCII /READ/
ASCII /OFF/
ASCII /ON/
SFUN: IFIW SFUN0 ;Set up the subwindow
IFIW SFUN1 ;Return the current subwindow size
IFIW SFUN2 ;Clear the subwindow checking
IFIW SFUN3 ;Re-enable the subwindow checking
MAXSUB==.-SFUN-1 ;Max SUBWIN function defined
;IFUNC = 0 - Set up subwindow
SFUN0: SKIPL X,@4(L) ;Get positive width
SKIPGE Y,@5(L) ;Get positive height
POPJ P, ;Return with IVALUE=-1 for error
SETZM @1(L) ;Set IVALUE=0
MOVE T1,@2(L) ;Get the lower left corner
MOVE T2,@3(L) ; of the subwindow
FADR X,T1 ;Get the max X of the subwindow
FADR Y,T2 ;Get the max Y of the subwindow
DMOVEM T1,TEMP+2 ;Store minimums
DMOVEM X,TEMP+4 ;Store maximums
MOVSI P3,-PLTNUM ;Number of plotters
SFUN0A: SKIPL P4,PLTTAB(P3) ;Is this plotter active?
JRST SFUN0B ;No, try next one
SETOM SUBW.F(P4) ;Subwindow is defined and in use
DMOVE T1,TEMP+2 ;Get minimums
DMOVE X,TEMP+4 ;Get maximums
DMOVEM T1,SMIN.X(P4) ;Save subwindow
DMOVEM X,SMAX.X(P4) ; parameters
PUSHJ P,SETWIN ;Set current window size
TXO P4,P4.OUP ;Flag that OLD.BD is invalid
MOVEM P4,PLTTAB(P3) ;Store flag bits
SFUN0B: AOBJN P3,SFUN0A ;Loop for all plotters
MOVE L,SAVEL ;Restore AC16
;IFUNC=1 - Return status of subwindow
SFUN1: MOVSI P3,-PLTNUM ;Get number of plotters
SKIPL P4,PLTTAB(P3) ;Is this one active
AOBJN P3,.-1 ;No, look for first active plotter
SKIPL P3 ;If no plotters are currently active,
MOVE P4,PLTTAB+0 ; use the first one
TRNE P4,-1 ;Don't check if no data area
SKIPN SUBW.F(P4) ;Flag =-1 if in use, +1 if disabled
POPJ P, ;IVALUE=-1 means subwindow never defined
DMOVE X,SMIN.X(P4) ;Get the bottom of the subwindow
MOVEM X,@2(L) ;Return the lower left hand
MOVEM Y,@3(L) ; of the window the caller
DMOVE T1,SMAX.X(P4) ;The upper bound of subwindow
FSBR T1,X ;Get the width of the window
FSBR T2,Y ;Get the height of the window
MOVEM T1,@4(L) ;Return the width to the caller
MOVEM T2,@5(L) ;Return the height to the caller
SKIPL SUBW.F(P4) ;Skip if in use
TDZA T1,T1 ;IVALUE=0 means subwindow is not in use
MOVEI T1,1 ;IVALUE=1 means subwindow is in use
MOVEM T1,@1(L) ;Return this to the caller
POPJ P,
;IFUNC=2 - Disable subwindow checking
SFUN2: MOVSI P3,-PLTNUM ;Number of plotters
SFUN2A: SKIPGE P4,PLTTAB(P3) ;Is this plotter active?
SKIPN SUBW.F(P4) ;Yes, has a subwindow been defined?
JRST SFUN2B ;No, try next one
MOVMS SUBW.F(P4) ;+1 means defined but disabled
SETZB T1,T2 ;Set min to 0.0
DMOVE X,X.WIND ;Set max to 11.0
PUSHJ P,SETWIN ;Reset window limits
SETZM @1(L) ;Set IVALUE to good
SFUN2B: AOBJN P3,SFUN2A ;Loop for all plotters
POPJ P,
;IFUNC=3 - Re-enable subwindow checking
SFUN3: MOVSI P3,-PLTNUM ;Number of plotters
SFUN3A: SKIPGE P4,PLTTAB(P3) ;Is this plotter active?
SKIPN SUBW.F(P4) ;Yes, has a subwindow been defined?
JRST SFUN3B ;No, try next one
SETOM SUBW.F(P4) ;-1 means defined and enabled
DMOVE T1,SMIN.X(P4) ;Get previous minimums
DMOVE X,SMAX.X(P4) ; and maximums
PUSHJ P,SETWIN ;Set current window limits to these values
SETZM @1(L) ;Set IVALUE to good
SFUN3B: AOBJN P3,SFUN3A ;Loop for all plotters
POPJ P,
SUBTTL Main routines -- TITLE - Use hardware character generator
; CALL TITLE (X,Y,HEIGHT,ICHAR,ANGLE,NUMCHR)
; sometimes equivalent to:
; CALL SETSYM('NUMBER',0,IOLD) !Get current table number
; CALL SETSYM('TABLE',1,IERR) !Change to standard table
; CALL SYMBOL (X,Y,HEIGHT,ICHAR,ANGLE,NUMCHR)
; CALL SETSYM('TABLE',IOLD,IERR) !Back to previous table
ENTRY %TITLE
SIXBIT /%TITLE/
%TITLE: MOVEM L,SAVEL ;Preserve AC 16
MOVSI P3,-PLTNUM ;Get size of table
TITLE1: SKIPL P4,PLTTAB(P3) ;Is this plotter active?
JRST TITLE2 ;No, try next one
MOVE X,@0(L) ;Get coordinates of title
MOVE Y,@1(L)
PUSHJ P,PLOTUP ;Move pen to that position
MOVSI T1,(SP.TTL) ;Bit to test
MOVE T2,PLTSPC(P4) ;Get flags for special routine
TDNE T1,T2 ;Does this plotter support TITLE?
PUSHJ P,(T2) ;Yes, call it with SP.TTL in T1
MOVEM P4,PLTTAB(P3) ;Incase any of the flag bits have changed
TITLE2: AOBJN P3,TITLE1 ;Loop for all plotters
MOVE L,SAVEL ;Restore AC 16
POPJ P, ;Return from TITLE
SUBTTL Main routines -- TITLEP - Check if TITLE is possible for plotter
;IF(TITLEP('GIGI')) CALL TITLE(X,Y,H,'Testing',0.0)
ENTRY %TITLP
SIXBIT /%TITLP/
%TITLP: MOVEM L,SAVEL ;Preserve AC16 across call
MOVE T1,@0(L) ;Get name from caller
PUSHJ P,SETYPE ;Set up P4 for type of plotter
JRST TITLP1 ;No such plotter, return .FALSE.
MOVSI T1,(SP.TTL) ;Bit to test
TDNN T1,PLTSPC(P4) ;Is this special routine implemented?
TITLP1: TDZA T0,T0 ;No, return .FALSE.
SETO T0, ;Yes, return .TRUE.
POPJ P, ;Return from TITLEP with flag in T0
SUBTTL Main routines -- WHERE - Get current pen position
;CALL WHERE (X,Y,XFAC,IPLT,YFAC)
;NOTE: Returns values from GLOBAL data section.
; Call PLOTOK to get per-plotter data.
ENTRY %WHERE
SIXBIT /%WHERE/
%WHERE: MOVEM L,SAVEL ;Preserve AC 16
DMOVE X,X.CALL ;Get virtual position
MOVEM X,@0(L) ;Return data to caller
MOVEM Y,@1(L) ; ...
MOVE T2,X.FACT ;Get latest factor
MOVEM T2,@2(L) ;Return XFAC
MOVE T2,Z.NUMB ;Get the plotter number (a small integer)
MOVEM T2,@3(L) ;Return IPLT
MOVE T2,Y.FACT ;Get latest factor in Y direction
MOVEM T2,@4(L) ;Return YFAC
WHERE9: MOVE L,SAVEL ;Restore AC 16
POPJ P, ;Return from WHERE
SUBTTL Main routines -- XHAIRS - Trigger crosshairs TEK 4012 or GIGI
;CALL XHAIRS (X,Y,LETTER,ISTRNG)
ENTRY %XHAIRS
SIXBIT /%XHAIR/
%XHAIRS:MOVEM L,SAVEL ;Preserve AC 16
MOVSI P3,-PLTNUM ;Get size of table
XHR1: SKIPL P4,PLTTAB(P3) ;Is this plotter active?
JRST XHR2 ;No, try next one
MOVSI T1,(SP.XHR) ;Bit to test
MOVE T2,PLTSPC(P4) ;Get flags for special routine
TDNE T1,T2 ;Does this plotter support XHAIRS?
PUSHJ P,(T2) ;Yes, call it with SP.XHR in T1
XHR2: AOBJN P3,XHR1 ;Loop for all plotters
MOVE L,SAVEL ;Restore AC 16
POPJ P, ;Return from XHAIRS
SUBTTL Plotter initialization -- Determine plotter type
;SPTYPE - Set Plotter Type (for PLOTS)
;Routine to determine type of plotter given its name.
;Argument in T1 is either a 5 letter name in single quotes, or an integer.
;Check PLTTAB to see if plotter is already active, then search the chain
;of plotter definitions.
;
;Calling sequence:
; MOVE T1,[ASCII /plotter-name/] or MOVE T1,[DEC plotter-number]
; PUSHJ P,SPTYPE
; *error return* ;No such plotter
; *normal return* ;P4 points to data, T1 has flags
; ;P3 non-zero if found in active plotter table
SPTYP0: PUSHJ P,SPTYPT ;Translate 'TTY' to 'TEK' or 'GIGI'
PFALL SPTYPE ;Try again
SPTYPE: PUSHJ P,SETYPE ;Is there a plotter by this name initialized?
TDZA P3,P3 ;No, follow chain of plotter definitions
JRST CPOPJ1 ;Yes, skip return with AOBJN pointer in P3
;Here with caller's argument in T2 (after conversion to uppercase)
CAMN T2,[ASCII /TTY/];For generic terminal?
JRST SPTYP0 ;Yes, determine terminal type
MOVEI P4,PLT.DA-PLTEXT;Start at beginning of chain
SPTYP1: HRRZ P4,PLTEXT(P4) ;Get pointer to plotter data
JUMPE P4,CPOPJ ;End is when chain pointer is zero
HLL P4,PLTTYP(P4) ;Get flags for THIS plotter
MOVE T3,PLTNAM(P4) ;Get AOBJN pointer to list of names
SPTYP2: MOVE T1,2(T3) ;Get sub-type flags
CAME T2,0(T3) ;Match integer number?
CAMN T2,1(T3) ; or as ASCII?
JRST CPOPJ1 ;Yes, T1 and P4 set up, P3 is zero
ADDI T3,2 ;No, skip past flags
AOBJN T3,SPTYP2 ;Try other subtypes of this plotter
JRST SPTYP1 ;Follow the chain to next plotter type
;Routine to find a previously initialized plotter
;Calling sequence:
; MOVE T1,[ASCII /plotter-name/]
; PUSHJ P,SETYPE
; *error return* ;No such plotter (T2 has plotter-name)
; *normal return* ;P4 and P3 point to data, T1 has sub-type flags
SETYPE: CAMN T1,BLANKS ;If argument is spaces,
MOVE T1,Z.NUMB ; use previous value (small integer)
SKIPN T1 ;If still zero, get default from .PLOT. module,
MOVE T1,.PLOT.## ; FORLIB.REL has /SPOOL/, TEKPLT.REL has /TEK/
TLNN T1,774000 ;Anything in 1st char?
JRST SETYP2 ;No, T2 has positive integer
PUSHJ P,UPCASE ;Convert T1 to uppercase
CAME T1,[ASCII /PLT/];For generic plotter?
CAMN T1,[ASCII /PLOT/];If so, use the default plotter type,
MOVE T1,.PLOT.## ; either ASCII/SPOOL/ or ASCII/TEK/
SETYP2: MOVEM T1,Z.CALL ;Save converted name
MOVE T2,T1 ;Index will be returned in T1
MOVSI P3,-PLTNUM ;Size of table
SETYP3: SKIPN P4,PLTTAB(P3) ;Get pointer to data area
JRST SETYP4 ;Skip zeroed slots
MOVE T1,PLTTYP(P4) ;Get flags
CAMN T2,PLTNAM(P4) ;Exact match on name?
JRST CPOPJ1 ;Yes, P3 and P4 set up and non-zero
SETYP4: AOBJN P3,SETYP3 ;No, loop
SETZB P3,P4 ;No match
POPJ P,
;Convert argument in T2 to uppercase without trailing blanks for compares
UPCASE: MOVE T2,[POINT 7,T1] ;Fetch/store in T1
UPCAS1: ILDB T3,T2 ;Get a char
CAIE T3,40 ;Space?
CAIL T3,140 ;Lower case?
SUBI T3,40 ;Yes, convert it
DPB T3,T2 ;Put it back where it came from
TLNE T2,760000 ;Done all 5 chars?
JRST UPCAS1 ;No
POPJ P, ;Yes
SUBTTL Plotter initialization -- Set default values
;Set most of per-plotter area and all local variables to zero.
;Clear rotation and set factoring
PL.INI: MOVEI T1,ZERO.F(P4) ;Starting address
LDB T2,[POINTR PLTFIN(P4),FN.SIZ] ;Size of data area
ADDI T2,-1(P4) ;Address of last loc in data area
PUSHJ P,PLFIN ;Zero variables, reset factors
;Set default window for clipping
MOVE X,[DFWINS] ;Get default window size
MOVE Y,X ; ...
SETZB T1,T2 ;Set minimums to 0
PJRST SETWIN ;Set WMAX.X(P4), WMAX.Y(P4) and return
;Here to reset certain variables to finish the plot
;T1 has first address, T2 as last address
PL.FIN: MOVEI T1,ZERO.R(P4) ;Starting address for finishing plot
MOVEI T2,ZERO.L(P4) ;Last addr to reset
PLFIN: SETZM (T1) ;Zero first location
HRL T1,T1 ;Source
ADDI T1,1 ;Destination
BLT T1,(T2) ;Zero to last location
MOVSI T1,(1.0) ;Get floating-point unity
MOVEM T1,ROTA.C(P4) ;Set cosine
MOVEM T1,FACT.X(P4) ;Set scaling factor
MOVEM T1,FACT.Y(P4) ; ...
SETZB X,Y ;Clear position
DMOVEM X,X.ORIG ;Clear origin
POPJ P,
SUBTTL Rotation -- TWIST and UNTWST
; Subroutine UNTWST - this routine is used to find the real coordinate
; from a rotated coordinate
; Calling sequence:
; DMOVE X,(coordinates)
; PUSHJ P,UNTWST
; *return*
; Uses T1, T2, changes X and Y
UNTWST: MOVNS ROTA.S(P4) ;Unrotate by using SIN(-ANG)=-SIN(ANG)
PUSHJ P,TWIST ; and COS(-ANG)=COS(ANG)
MOVNS ROTA.S(P4) ;Restore SIN
POPJ P, ;Return
; Subroutine TWIST - this routine is used for rotation of axis
; Calling sequence:
; DMOVE X,(coordinates)
; PUSHJ P,TWIST
; *return*
; Uses T1, T2, changes X and Y
; X = X*COS - Y*SIN
; Y = Y*COS + X*SIN
TWIST: MOVE T1,X ;Get a copy of X
MOVE T2,Y ;Get a copy of Y
FMPR T2,ROTA.S(P4) ;Rotate the X
FMPR X,ROTA.C(P4) ; ..
FSBR X,T2 ; ..
FMPR T1,ROTA.S(P4) ;Rotate the Y
FMPR Y,ROTA.C(P4) ; ..
FADR Y,T1 ; ..
POPJ P,
SUBTTL Rotation -- INC2FP - Convert increments to floatint-point
; Subroutine INC2FP - This routine translates the current position from
;increments to floating-point inches by undoing the following equations:
;
; X1 = (Xcall + Xorigin) * Xfactor
; Y1 = (Ycall + Yorigin) * Yfactor
; Xinc = ( X1*COS(Angle) - Y1*SIN(Angle) + Xrot ) * Increments
; Yinc = ( Y1*COS(Angle) + X1*SIN(Angle) + Yrot ) * Increments
;Calling sequence:
; DMOVE X,(position in increments)
; PUSHJ P,INC2FP ;Called from PLTOK and XHAIRS
; *return* ;with X and Y in floating-point
; Uses T1 and T2
INC2FP: FLOAT X ;Convert increments
FLOAT Y ; to floating point
FDVR X,PLTINX(P4) ;Convert to inches
FDVR Y,PLTINY(P4)
FSBR X,ROTA.H(P4) ;Subtract horizonal
FSBR Y,ROTA.V(P4) ; and vertical offsets
SKIPN ROTA.A(P4) ;If rotated,
PUSHJ P,UNTWST ; un-rotate
FDVR X,FACT.X(P4) ;Un-factor
FDVR Y,FACT.Y(P4)
FSBR X,X.ORIG ;Cancel current origin
FSBR Y,X.ORIG
POPJ P, ;Return with X and Y to match X.CALL and Y.CALL
SUBTTL Window clipping -- CHECK
; Subroutine CHECK - this routine checks to see the line fits in the window.
;Call with new position in (X.NEWP,Y.NEWP) and old in (OLDP.X(P4),OLDP.Y(P4)).
;Special definitions for NEW.BD and OLD.BD
BD.LOW==1 ;Line crossed the lower boundry
BD.HI== 2 ;Line crossed the upper boundry
CHECK: TXNN P4,P4.OUP ;Move up to OLDP.X?
JRST CHECK1 ;No, old point is with pen down, OLD.BD is set
DMOVE X,OLDP.X(P4) ;Yes, don't trust OLD.BD (see PLOTI2)
MOVEI NEW.BD,0 ;Clear flag in case inside window
PUSHJ P,CHKX ;Go check X
TLO NEW.BD,(T2) ;Set BD.HI or BD.LOW in left half
PUSHJ P,CHKY ;Go check Y
TRO NEW.BD,(T2) ;Set BD.HI or BD.LOW in right half
MOVEM NEW.BD,OLD.BD(P4);Remember whether point is outside the window
CHECK1: DMOVE X,X.NEWP ;Get new position
MOVEI NEW.BD,0 ;Clear flag in case inside window
PUSHJ P,CHKX ;Go check X
TLO NEW.BD,(T2) ;Set BD.HI or BD.LOW in left half
PUSHJ P,CHKY ;Go check Y
TRO NEW.BD,(T2) ;Set BD.HI or BD.LOW in right half
;Check for the following combinations: ININ, INOUT, OUTIN, OUTOUT
;If OLD.BD and NEW.BD are both zero, then the line is entirely inside
SKIPN T2,OLD.BD(P4) ;Get status of old point
JUMPE NEW.BD,ININ ;Plot the line if both points are inside window
JUMPE NEW.BD,OUTIN ;Going from OUT to IN if new point is OK
JUMPE T2,INOUT ;Going from IN to OUT if old point is OK
;Must be OUT to OUT, maybe it crosses a corner
TLNE T2,BD.LOW ;Starts to the left
TLNN NEW.BD,BD.LOW ; and ends to the left?
SKIPA ;No, check further
JRST OUTOK ;Yes, don't make a mark on the paper
TLNE T2,BD.HI ;Starts to the right
TLNN NEW.BD,BD.HI ; and ends to the right?
SKIPA ;
JRST OUTOK ;
TRNE T2,BD.LOW ;Starts below
TRNN NEW.BD,BD.LOW ; and ends below?
SKIPA ;
JRST OUTOK ;
TRNE T2,BD.HI ;Starts above
TRNN NEW.BD,BD.HI ; and ends above?
JRST OUTOUT ;No, line goes OUTIN, ININ, INOUT
JRST OUTOK ;Yes, don't make a mark on the paper
;Here for a line that is entirely inside the window
ININ: DMOVE X,OLDP.X(P4) ;Get old position
TXZE P4,P4.OUP ;Is old position with pen up?
PUSHJ P,MOVUP ;Yes, move there
INOK: DMOVE X,X.NEWP ;Get ending coordinates of this line
PUSHJ P,MOVDN ;Move the pen there
OUTOK: DMOVE X,X.NEWP ;Get new position
DMOVEM X,OLDP.X(P4) ;Save as old position
MOVEM NEW.BD,OLD.BD(P4) ;Save intercept flags
TXZ P4,P4.OUP ;Old position, pen down, OLD.BD is valid
POPJ P,
;Here for a line that goes from outside to outside, but part of it is visible
;It is possible to cross a corner of the window, or outside a corner.
OUTOUT: PUSHJ P,OUTIN1 ;First find where the line comes into the window
JRST OUTOK ;Line never comes in the window, is always out
JRST INOUT0 ;Now draw part of line until it hits the window
DEFINE BUGJMP(ADDR),<PUSHJ P,GO2DDT>
;Here for a line that goes from outside to inside
OUTIN: PUSHJ P,OUTIN1 ;Find where the line comes into the window
BUGJMP OUTOK ;Should never happen
JRST INOK ;Go plot the line to the new point
OUTIN1: PUSHJ P,COMPM ;Go compute the slope and Y intercept
PUSHJ P,NEWOLD ;Find correct intercept (set up X and Y)
PUSHJ P,COMP ;Compute the intercept point
PJRST NEWOLD ;Line is not visible
AOS (P) ;Line is visible
PUSHJ P,MOVUP ;Move to edge of window
PJRST NEWOLD ;Restore old and new points
;Here for a line that goes from inside to outside
INOUT: DMOVE X,OLDP.X(P4) ;Get old position
TXZE P4,P4.OUP ;Is old position with pen up?
PUSHJ P,MOVUP ;Yes, move there first
PUSHJ P,COMPM ;Go compute slope and the Y intercept
INOUT0: DMOVE X,X.NEWP ;Get destination
PUSHJ P,COMP ;Go compute the intercept point
BUGJMP OUTOK ;Should never happen
PUSHJ P,MOVDN ;Move to the edge of the window
PUSHJ P,PWEMES ;Output the Plot Window Exceeded message
JRST OUTOK ;Set OLDP.X and OLD.BD
SUBTTL Window clipping -- "Plot Window was Exceeded" message
PWEMES: TXNN P4,P4.TTY ;Output to a terminal?
SKIPN Z.ERRC ; or message counter at zero?
POPJ P, ;Yes, no warnings
;This really should be a warning, and type X.CALL and Y.CALL
ERRSTR (MSG,<
%Plot Window was Exceeded >)
SKIPL Z.ERRC ;Was counter negative?
JRST [SOS Z.ERRC ;No, just count down to zero
POPJ P, ]
AOS Z.ERRC ;Yes, count up to zero
PJRST TRACE ;And trace subroutine calls
SUBTTL Window clipping -- COMP
; Subroutine COMP - this routine computes X and Y that is closest to the
; given point and on the window, uses T1, T2, and T3
; Calling sequence:
; DMOVE X,[coordinates in inches]
; PUSHJ P,COMP
; *error return* ;Line does not intersect the window
; *normal return* ;New coordinates are in X and Y
COMP: DMOVEM X,TEMP+0 ;Save for a bit
PUSHJ P,COMPX ;Go compute X from a given Y
JRST [DMOVE X,TEMP+0 ;Get back original coordinates
PJRST COMPY] ;Computed X not in window, compute Y from X
DMOVEM X,TEMP+0 ;Store X and Y for later testing
PUSHJ P,COMPY ;Go compute Y from a given X
JRST COMP0 ;Computed Y not in window, use X and Y in TEMP
MOVE T1,TEMP+0 ;Calculate distance from previous (X,Y)
FSBR T1,X.NEWP
MOVMS T1 ;This will avoid %FRSAPR floating-underflow
MOVE T2,TEMP+1 ;R2 = (X-XNEW)**2 + (Y-YNEW)**2
FSBR T2,Y.NEWP
MOVMS T2
FADR T1,T2 ;T1 has distance for TEMP+0 and TEMP+1
MOVE T2,X ;Calculate distance from new (X,Y)
FSBR T2,X.NEWP
MOVMS T2
MOVE T3,Y
FSBR T3,Y.NEWP
MOVMS T3
FADR T2,T3 ;T2 has distance for X and Y
CAMG T2,T1 ;Newest (X,Y) closer to (X.NEWP,Y.NEWP)?
JRST COMP1 ;Yes, X and Y set up
COMP0: DMOVE X,TEMP+0 ;No, previous X and Y were better
COMP1: AOS (P) ;Coordinates have been found
POPJ P, ;Return
SUBTTL Window clipping -- COMPX and COMPY
; Subroutine COMPX - this routine computes X from a given Y and then
; sees if it is in the window, uses T1 and T2
; Calling sequence:
; PUSHJ P,COMPX
; *error return* ;Computed X is outside window
; *normal return* ;X OK
COMPX: PUSHJ P,GETY ;Get closest Y that is on the border
JUMPE M,COMPX0 ;Use closest X border if horizonal
CAIN M,1 ;If vertical or nearly vertical,
JRST COMPX1 ; use the caller's X value
MOVE X,Y ;Compute X using X = (Y - B) / M
FSBR X,B
FDVR X,M
PJRST CHKX ;Go test this new X
COMPX1: SKIPA X,X.NEWP ;Use new X position for a vertical line
COMPX0: PUSHJ P,GETX ;Get border X for a horizonal line
PJRST CHKX ;Check if this X is in the window
COMPY: PUSHJ P,GETX ;Get closest X that is on the border
JUMPE M,COMPY0 ;Use caller's Y if horizontal or nearly so
CAIN M,1 ;If vertical,
JRST COMPY1 ;Use closest border Y
MOVE Y,M ;Compute Y using Y = M * X + B
FMPR Y,X
FADR Y,B
PJRST CHKY ;Go test this new Y
COMPY0: SKIPA Y,Y.NEWP ;Use new Y position for a horizonal line
COMPY1: PUSHJ P,GETY ;Go border Y for vertical line
PJRST CHKY ;Check if this Y is in the window
SUBTTL Window clipping -- GETX and CHKX
; Subroutine GETX (or GETY) - this routine gets lowest or highest X (or Y)
; allowable based on flags in NEW.BD
; Calling sequence:
; PUSHJ P,GETX ;(or PUSHJ P,GETY)
; *return*
GETX: TLNN NEW.BD,BD.HI ;Skip if the point is above the window
SKIPA X,WMIN.X(P4) ;Get the bottom of the window
MOVE X,WMAX.X(P4) ;Get the top of the window
POPJ P, ;Return
GETY: TRNN NEW.BD,BD.HI ;Skip if the point is to the right of window
SKIPA Y,WMIN.Y(P4) ;Get the left side of the window
MOVE Y,WMAX.Y(P4) ;Get the right side of the window
POPJ P, ;Return
; Subroutine CHKX (or CHKY) - this routine checks to see this X (or Y)
; is in the window, uses T1 and T2
; Calling sequence:
; PUSHJ P,CHKX ;or PUSHJ P,CHKY
; *error return* ;The X (or Y) is outside window, T2 has flags
; *normal return* ;The value is in the window
; On return, T1 has error distance
CHKX: SKIPA T1,X ;Get X in the right place
CHKY: SKIPA T1,Y ;Get Y in the right place
TDZA T2,T2 ;Set up to test X
MOVEI T2,1 ;Set up to test Y
ADDI T2,0(P4) ;Point to data area
CAMGE T1,WMIN.X(T2) ;Is point greater than minimum?
JRST CHKLOW ;No, below or to the left of the window
CAMG T1,WMAX.X(T2) ;Is point greater than maximum?
JRST CHKOK ;No, point is inside window
CHKHI: FSBR T1,WMAX.X(T2) ;Subtract the top of the window off
MOVEI T2,BD.HI ;Set the flag for to high
JRST CHKZER ;Check for zero
CHKLOW: FSBR T1,WMIN.X(T2) ;Subtract the bottom of the window off
MOVEI T2,BD.LOW ;Set the flag for to low
PFALL CHKZER ;Check for zero
CHKZER: MOVMS T1 ;Get absolute value
CAMG T1,[DEC 0.01] ;Error return of too big
CHKOK: AOS (P) ;Make for skip return
POPJ P, ;Return from CHKX/CHKY
SUBTTL Window clipping -- COMPM and NEWOLD
; Subroutine COMPM - this routine computes the slope and Y intercept of a line,
; puts results in M and B, uses T1
; Calling sequence:
; PUSHJ P,COMPM
; *return* ;The slope is in M and the Y intercept is in B
; ; if M contains a 0 the slope is horizonal
; ; if M contains a 1 the slope is vertical
COMPM: MOVE T1,Y.NEWP ;Get the new Y
FSBR T1,OLDP.Y(P4) ;Subtract the old Y from the new Y
MOVE M,X.NEWP ;Get the new X
FSBR M,OLDP.X(P4) ;Subtract the old X from the new X
PUSHJ P,TOL ;See if delta Y is almost zero
JRST COMPM0 ;OK, the line isn't horizonal
MOVEI M,0 ;Set the slope to zero (for a horizonal line)
POPJ P, ;Return
COMPM0: EXCH T1,M ;Exchange delta X and delta Y
PUSHJ P,TOL ;Set if delta X is equal to zero
JRST COMPM1 ;OK, the line isn't vertical
MOVEI M,1 ;Set the slope to one (for a vertical line)
POPJ P, ;Return
COMPM1: FDVR M,T1 ;M = dY / dX
MOVN B,X.NEWP ;Get negative of new X value
FMPR B,M ;Muliply by the slope
FADR B,Y.NEWP ;B = Y - X * M
POPJ P, ;Return
TOL: CAMG T1,[DEC 0.001] ;Check for small positive number
CAMGE T1,[DEC -0.001] ;Check for small negative number
POPJ P, ;Error, not close enough to zero
AOS (P) ;Close enough for government work
POPJ P,
; Subroutine NEWOLD - this routine switches the new point with the old point
; Calling sequence:
; PUSHJ P,NEWOLD
; *return* ;NEW.* is switched with OLD.*
NEWOLD: DMOVE X,X.NEWP ;Get new position
EXCH X,OLDP.X(P4) ;Exchange
EXCH Y,OLDP.Y(P4) ; with old
DMOVEM X,X.NEWP ; position
EXCH NEW.BD,OLD.BD(P4) ;Exchange boundry flags
POPJ P, ;Return
SUBTTL End of PLOT.MAC (Must be assembled with PLTIOD.MAC)
LITPLT: LIT ;Localize the literals
;.COMPILE PLOT.REL=PLTDSK.MAC+PLTRGS.MAC+PLTTEK.MAC+PLTIOD.MAC
PAGE ;End of PLOT.MAC