Trailing-Edge
-
PDP-10 Archives
-
decuslib10-12
-
43,50547/pltlib/v12/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 . . . . . . . . . . . . . . . . . . . 1
; 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 PLOTER - Define an alias plotter . . . . . . . 22
; 6.8 PLOTOF - Temporarily turn off a plotter . . . 23
; 6.9 PLOTOK - Get status of the plotter . . . . . . 24
; 6.10 PLOTON - Resume output to a plotter . . . . . 25
; 6.11 PLOTS - Initialize the plotter . . . . . . . 26
; 6.12 ROTATE - Change angle of rotation for the pl . 27
; 6.13 SETWIN - Set universal window for large plot . 28
; 6.14 SUBWIN - Set/reset/status of sub-window . . . 30
; 6.15 TITLE - Use hardware character generator . . 33
; 6.16 WHERE - Get current pen position . . . . . . 34
; 6.17 XHAIRS - Trigger crosshairs TEK 4012 or GIGI . 35
; 7. Plotter initialization
; 7.1 Determine plotter type . . . . . . . . . . . . 36
; 7.2 Set default values . . . . . . . . . . . . . . 38
; 8. Rotation
; 8.1 TWIST and UNTWST . . . . . . . . . . . . . . . 39
; 8.2 INC2FP - Convert increments to floatint-poin . 40
; 9. Window clipping
; 9.1 CHECK . . . . . . . . . . . . . . . . . . . . 41
; 9.2 "Plot Window was Exceeded" message . . . . . . 43
; 9.3 COMP . . . . . . . . . . . . . . . . . . . . . 44
; 9.4 COMPX and COMPY . . . . . . . . . . . . . . . 45
; 9.5 GETX and CHKX . . . . . . . . . . . . . . . . 46
; 9.6 COMPM and NEWOLD . . . . . . . . . . . . . . . 47
; 10. End of PLOT.MAC (Must be assembled with PLTIOD.MAC) . 48
SUBTTL Contents -- PLTDSK.MAC
; Table of Contents for PLTDSK.MAC
;
;
; Section Page
;
; 1. Spooler - writes compressed output to DSK: . . . . . . 1
; 2. Revision History for PLTDSK.MAC . . . . . . . . . . . 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. ReGIS for GIGI, VT125, and DMP4R . . . . . . . . . . . 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 . . . . . . . . 6
; 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. TEKTRONIX 4010-series Graphics Terminals . . . . . . . 1
; 2. PPDATA macro expansion . . . . . . . . . . . . . . . . 3
; 3. Database . . . . . . . . . . . . . . . . . . . . . . . 4
; 4. INItialize, FINish, and Pause . . . . . . . . . . . . 5
; 5. TEKMOV - Move to beam to new position . . . . . . . . 6
; 6. XHAIRS - allow the user the use the crosshairs . . . . 7
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. Output numbers and bytes . . . . . . . . . . . . . . . 4
; 4. GETNAM - Decode output file spec . . . . . . . . . . . 5
; 5. NEWFIL - Create new file name . . . . . . . . . . . . 6
; 6. Open output file . . . . . . . . . . . . . . . . . . . 7
; 7. Translate 'TTY' to appropriate plotter type . . . . . 8
; 8. TTYINI - Set up terminal . . . . . . . . . . . . . . . 9
; 9. Terminal I/O routines . . . . . . . . . . . . . . . . 11
; 10. I/O routines - Read window limits from SYS:PRIV.SYS . 13
; 11. Misc - IFX.X and IFX.Y . . . . . . . . . . . . . . . . 14
; 12. Data area
; 12.1 Global variables . . . . . . . . . . . . . . . 15
; 12.2 Temporary variables . . . . . . . . . . . . . 16
; 13. Literals and END statement . . . . . . . . . . . . . . 17
SUBTTL Assembly instructions and Feature-Test settings
SEARCH PLTUNV ;Search the universal file
SALL
TTL (<PLOT - Pen moving routine>)
;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
; 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
;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
FTHEAD==FTHEAD ;Headers and trailers plotted in the .PLT file
FTKA== FTKA ;FIXR instruction instead of IFX.1 subroutine
FTPRIV==FTPRIV ;Subroutine SETWIN reads SYS:PRIV.DAT/PHYSICALONLY
FT701== FT701 ;0=603A, -1=701, +1=use OPEN/LOOKUP if FILOP. fails
FTAPLT==FTAPLT ;Nonzero to have multiple plotters active
;Feature-tests that affect PLOT.REL only
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 FTHEAD,-1 ;Plot headers and trailers in the .PLT file
;0 for no headers, +1 to use SPROUT's version of SETSYM/SYMBOL
ND FTPRIV,-1 ;Make subroutine SETWIN read SYS:PRIV.DAT
;List of external routines
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
IFN FTDBUG,<.PLOT.:: ASCII /SPOOL/ >
IFE FTDBUG,< 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 FT701,< 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
;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
;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
;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
PLTTYP:! NM'TYP!CHAIN ;Plotter type bits ,, pointer to previous plotter
PLTNAM:!-NM'LEN,,NM'NAM ;Pointer to list of names for PLOTS
PLTINI:! NM'BYT!NM'INI ;Initialize the plotter (byte size & mode 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)
PLTINC:!EXP NM'INC ;Increments per inch in floating point
PLTMAX:!EXP NM'MAX ;Max increments X ,, Max increments Y
PLTEXT:!EXP NM'EXT ;Extension of PLOT file ,, 0
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
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+PLTTYP+1 ;Keep PLT.DA+PLTTYP, 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,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
MOVEI 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
TXNE P4,P4.TTY ;Output going to a TTY?
PUSHJ P,TTYFIN ;Yes, clear the GAG bit
PUSHJ P,RELFIL ;Release channel
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
PUSHJ P,CLSFIL ;Close output file
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 MOVUP ;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.
;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*
;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
PJRST @PLTMOV(P4) ;Move with pen down
;Routine to convert floating-point inches to increments
;Calling sequence:
; DMOVE X,(position in inches)
; PUSHJ FP2INC
; *return*
FP2INC: FMPR X,PLTINC(P4) ;Convert to increments
IFE FTKA,<FIXR X,X> ;Convert to integer
IFN FTKA,<PUSHJ P,IFX.X>
FMPR Y,PLTINC(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 /FACTOR/
%FACTOR:MOVEM L,SAVEL ;Preserve AC16 across call
MOVE X,@0(L) ;Get scaling factor for X (1.0 is normal)
MOVE Y,X ;Duplicate in case only 1 arg
HLRZ T1,-1(L) ;Get count of arguments
CAIGE T1,-1 ;More than 1 arg?
MOVE Y,@1(L) ;Yes, get scaling factor for Y
SKIPN X ;Non-zero?
MOVSI X,(1.0) ;No, keep factors unchanged
SKIPN Y
MOVSI Y,(1.0)
FMPRM X,X.FACT ;Save for subroutine WHERE
FMPRM Y,Y.FACT
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)
ENTRY %GETWIN
SIXBIT /GETWIN/
%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
;************************* Design of this routine is not finished! ******
SUBTTL Main routines -- NEWPEN - Change pen color or line type
;CALL NEWPEN (IPEN,IERR) {or IERR=NEWPEN(IPEN)}
;This routine is documented as a subroutine, but it also acts as a function
;to be compatible with the old calling sequence.
ENTRY %NEWPEN
SIXBIT /NEWPEN/
%NEWPEN:MOVE T0,[T1,,SAVET1] ;Preserve all ACs
BLT T0,SAVEL ; in case called as a function
MOVE T0,@0(L) ;Get pen number
JUMPG T0,NEWPE0 ;Positive, go set it
MOVE T0,C.NPEN ;Zero, get previous pen color
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
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
NEWPE2: AOBJN P3,NEWPE1 ;Loop for all plotters
MOVSI L,SAVE0 ;Source,,destination
BLT L,L ;Restore ACs in case called as a function
POPJ P, ;Return from NEWPEN
SUBTTL Main routines -- OPRTXT - Send message to OPR when plot comes out
;CALL OPRTXT ('Message for the OPR',NCHAR)
ENTRY %OPRTXT
SIXBIT /OPRTXT/
%OPRTXT:MOVEM L,SAVEL ;Preserve AC 16
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 /PAUSEP/
%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
MOVSI T1,(SP.PAS) ;Bit to test
MOVE T2,PLTSPC(P4) ;Get flags for special routine
TDNE T1,T2 ;Does this plotter support PAUSEP?
PUSHJ P,(T2) ;Yes, call it with SP.PAS in T1
PAUSE2: AOBJN P3,PAUSE1 ;Loop for all plotters
MOVE L,SAVEL ;Restore AC16
POPJ P, ;Return from PAUSEP
SUBTTL Main routines -- PLOTER - Define an alias plotter
IFN FTAPLT,< ;If alias plotters are allowed,
;CALL PLOTER ('SPOOL','FUBAR')
ENTRY %PLTER
SIXBIT /PLOTER/
%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
;************************* Design of this routine is not finished! ******
PLTER9: MOVE L,SAVEL ;Restore AC16
POPJ P, ;Return from PLOTOK
> ;End of IFN FTAPLT
SUBTTL Main routines -- PLOTOF - Temporarily turn off a plotter
;CALL PLOTOF ('TEK')
ENTRY %PLTOF
SIXBIT /PLOTOF/
%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)
ENTRY %PLTOK
SIXBIT /PLOTOK/
%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
;********** Design of this subroutine not finished ************************
SUBTTL Main routines -- PLOTON - Resume output to a plotter
;CALL PLOTON ('TEK')
ENTRY %PLTON
SIXBIT /PLOTON/
%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
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
TXNE P4,P4.TTY ;Output to a terinal?
PUSHJ P,TTBINM ;Yes, set TTY to BINARY plotting mode
PLTON1: MOVE L,SAVEL ;Restore AC16
POPJ P, ;Return from PLOTON
SUBTTL Main routines -- PLOTS - Initialize the plotter
;CALL PLOTS (IERR)
;CALL PLOTS (IERR,IPLT,DNAME)
;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.
ENTRY %PLOTS
SIXBIT /PLOTS/
%PLOTS: MOVEM L,SAVEL ;Preserve AC16 across call
SKIPE T1,@0(L) ;Get IERR value
MOVEM T1,E.PLOT ;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.
MOVEI T2,0 ;Assume filename not given in call
HLRZ T1,-1(L) ;Get count of args
CAIG T1,-3 ;Optional third arg present?
MOVEI T2,@2(L) ;Yes get addr of array
PUSHJ P,GETNAM ;Set D.PLOT and F.PLOT to device and file name
;Determine which type of plotter to activate
MOVEI T1,0 ;Use default plotter if type not specified
HLRZ T2,-1(L) ;Get count of args
CAIG T2,-2 ;Optional second arg present?
MOVE T1,@1(L) ;Yes, get it (an integer or 5 chars of ASCII)
PUSHJ P,SPTYPE ;Search name tables and set up T1, P3, and P4
POPJ P, ;No match, IERR is -1 (No such plotter)
MOVEM T1,T.PLOT ;Save pointer to plotter name
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 (<% PLOT - Subroutine PLOTS called with plotter already active>)
PUSHJ P,TRACE.##
PUSHJ P,FINPLT ;Finish off old plot
PLOTS1: PUSHJ P,DEAPLT ;Deallocate the plot data area
MOVE T1,T.PLOT ;Restore T1
PAGE
;Find a slot in PLTTAB to store flags and pointer for this plotter
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
HRR P4,T1 ;Now P4 points to LOSEG data (flags in LH)
MOVE T3,0(T2) ;Get primary alias
EXCH T3,T.PLOT ;Store small integer for subroutine WHERE
MOVE T4,(T3) ;Get word which matched IPLT
MOVEM T4,PLTNAM(P4) ;Store in LOSEG
SUB T3,T2 ;Get offset into name table
HRRZM T3,PLTTYP(P4) ;Save as plotter sub-type
PUSHJ P,SETODV ;Set up output device, DSK: or TTY:
MOVEM T1,FILE.D(P4) ;Store device used by this plotter
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
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 /ROTATE/
%ROTATE:MOVEM L,SAVEL ;Preserve AC 16 across call
MOVE T1,@(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
SETZ T2, ;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
MOVEI 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
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)
;CALL SETWIN (XWIND,YWIND,XWMAX,YWMAX,IPRIV)
ENTRY %SETWIN
SIXBIT /SETWIN/
%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
HLRZ T3,-1(L) ;Get number of arguments
CAIG T3,-4 ;4 of them?
JRST [MOVEM T1,@2(L) ;Yes, return XWMAX
MOVEM T2,@3(L) ; and YWMAX
JRST SETWI1 ] ;Let caller worry about arguments too big
CAMG X,X.WMAX ;Only 2 args,
CAMLE Y,Y.WMAX ; if X or Y is out of range
JRST SETWI4 ; then fatal error
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 (<? SETWIN - Illegal window size, call GETWIN to get size>)
PUSHJ P,TRACE.## ;Trace subroutine calls
POPJ P,
SETWI5: SETOM S.ORIG ;Pretend it was a call to
PUSHJ P,FUNC99 ; PLOT(X,Y,999) and abort plot
ERRSTR (<? SETWIN - Cannot call SETWIN after PLOT has started>)
PUSHJ P,TRACE.## ;Trace subroutine calls
POPJ P,
;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
PUSHJ P,CHKLIM ;Check if X and Y are in range
DMOVEM X,WMAX.X(P4) ;Store current maximums
DMOVE X,TEMP ;Get minimums
PUSHJ P,CHKLIM ;Check if X and Y are in range
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: HLRZ T1,PLTMAX(P4) ;Get max X increments
FLOAT T1 ;Convert to F.P.
FDVR T1,PLTINC(P4) ;Convert to inches
CAMLE X,T1 ;User limit smaller than plotter limit?
MOVE X,T1 ;No, set to physical limitation
HRRZ T2,PLTMAX(P4) ;Same for Y
FLOAT T2
FDVR T2,PLTINC(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 /SUBWIN/
%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
SKIPL T1,@0(L) ;Check for positive function value
CAILE T1,MAXSUB ;And in range
POPJ P, ;Go give an error return
PJRST @SFUN(T1) ;Go to the right function routine
SFUN: SFUN0 ;Set up the subwindow
SFUN1 ;Return the current subwindow size
SFUN2 ;Clear the subwindow checking
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
SETZM WMIN.X(P4) ;Set current window
SETZM WMIN.Y(P4) ; minimums to 0.0
DMOVE X,X.WIND ; and maximums
DMOVEM X,WMAX.X(P4) ; to SETWIN's value
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('QUERY',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
;First check to see if all active plotters have hardware characters
MOVSI T1,(SP.TTL) ;Bit to test
SETO T2, ;Assume OK
MOVSI P3,-PLTNUM ;Get size of table
TITLE1: SKIPL P4,PLTTAB(P3) ;Is this plotter active?
JRST TITLE2 ;No, try next one
TDNN T1,PLTSPC(P4) ;Does this plotter support TITLE?
SETZ T2, ;Not OK
TITLE2: AOBJN P3,TITLE1 ;Loop for all plotters
JUMPE T2,TITLEX ;Have to call SYMBOL if no hardware
MOVSI P3,-PLTNUM ;Pass 2 to do it
TITLE3: SKIPL P4,PLTTAB(P3) ;Look at only active plotters
JRST TITLE4 ; ...
MOVSI T1,(SP.TTL) ;Which routine to do
MOVE T2,PLTSPC(P4) ;Addr of routine in RH
PUSHJ P,(T2) ;Call routine with SP.TTL set in T1
TITLE4: AOBJN P3,TITLE1 ;Loop for all
MOVE L,SAVEL ;Restore AC 16
POPJ P, ;Return from TITLE
PAGE
;Here to call subroutine SYMBOL. First CALL SETSYM('TABLE',1,IERR)
TITLEX: MOVEI T1,[ASCII/QUERY/]
MOVEM T1,TEMP+0 ;Read current table number
SETZM TEMP+1 ;Zero dummy argument
MOVEI L,SSARGS ;Point to args
PUSHJ P,SETSYM## ;Read the number of the current symbol table
PUSH P,TEMP+2 ;Save answer
DMOVE T1,[EXP ASCII/TABLE/,1]
DMOVEM T1,TEMP+0 ;Set to table #1
MOVEI L,SSARGS ;Point to args
PUSHJ P,SETSYM## ;Do it
MOVE L,SAVEL ;Point to original args
PUSHJ P,SYMBOL## ;Let SYMBOL do the dirty work
MOVE T1,[ASCII/TABLE/]
MOVEM T1,TEMP+0 ;Reset the function code
POP P,TEMP+1 ;Get back previous table number
MOVEI L,SSARGS ;Point to SETSYM args
PJRST SETSYM## ;Restore symbol table and return from TITLE
-3,,0 ;3 args
SSARGS: INTEGER TEMP+0 ;Function to perform
INTEGER TEMP+1 ;Argument to function
INTEGER TEMP+2 ;Answer/error flag
SUBTTL Main routines -- WHERE - Get current pen position
;CALL WHERE (X,Y)
;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) ; ...
HLRE T1,-1(L) ;Get argument count
ADDI T1,2 ;Account for X and Y args
AOJG T1,WHERE9 ;Stop if not 3 args
MOVE T2,X.FACT ;Get latest factor
MOVEM T2,@2(L) ;Return XFAC
AOJG T1,WHERE9 ;Stop if not 4 args
MOVE T2,T.PLOT ;Get the plotter type (a small integer)
MOVEM T2,@3(L) ;Return IPLT
AOJG T1,WHERE9 ;Stop if not 5 args
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 /XHAIRS/
%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 points to name
; ;P3 non-zero if found in active plotter table
SPTYPE: PUSHJ P,SETYPE ;Is there a plotter by this name initialized?
TDZA P3,P3 ;No, clear flag and follow the chain
JRST CPOPJ1 ;Yes, skip return with AOBJN pointer in P3
;Here with name (such as 'TEK') in T3 or number (such as 4010) in T2
CAMN T3,[ASCII /TTY/];For generic terminal?
JRST [PUSHJ P,SPTYPT ;Yes, translate it to 'TEK' or 'GIGI'
JRST SPTYPE] ;Try the translated name
MOVEI P4,PLT.DA-PLTTYP;Start at beginning of chain
SPTYP1: HRRZ P4,PLTTYP(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 T1,PLTNAM(P4) ;Get AOBJN pointer to list of names
SPTYP2: CAME T3,(T1) ;Match name?
CAMN T2,(T1) ; or as integer?
JRST CPOPJ1 ;Yes, T1, P3, and P4 are set up
AOBJN T1,SPTYP2 ;No, 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
; *normal return* ;P4 points to data (P3 has AOBJN pointer)
SETYPE: PUSHJ P,GTPNUM ;Get plotter number in T2 and/or name in T3
CAME T3,[ASCII /PLT/];For generic plotter?
CAMN T3,[ASCII /PLOT/];If so, use the default plotter type,
MOVE T3,.PLOT. ; either ASCII/SPOOL/ or ASCII/TEK/
MOVSI P3,-PLTNUM ;Size of table
SETYP1: SKIPN P4,PLTTAB(P3) ;Get pointer to data area
JRST SETYP2 ;Skip zeroed slots
CAMN T3,PLTNAM(P4) ;Exact match on name?
POPJ P, ;Yes, P3 and P4 set up and non-zero
SETYP2: AOBJN P3,SETYP1 ;No, loop
SETZB P3,P4 ;No match
POPJ P,
;Routine to get plotter number and/or name
;Call with name in T1, returns integer in T2 and uppercase in T3
GTPNUM: CAMN T1,BLANKS ;If argument is spaces,
MOVE T1,T.PLOT ; use previous value
SKIPN T3,T1 ;If still zero, get default from .PLOT. module,
MOVE T3,.PLOT. ; FORLIB.REL has /SPOOL/, TEKPLT.REL has /TEK/
SETZ T2, ;Clear number
TLNN T3,774000 ;Anything in 1st char?
POPJ P, ;No, T3 has integer
MOVE T1,[POINT 7,T3] ;Fetch/store in T3
GTPNM1: ILDB T4,T1 ;Get a char
CAIE T4,40 ;Space?
CAIL T4,140 ;Lower case?
SUBI T4,40 ;Yes, convert it
DPB T4,T1 ;Put it back where it came from
CAIL T4,"0" ;Numeric?
CAILE T4,"9" ; ...
JRST GTPNM2 ;No
IMULI T2,^D10 ;Yes, shift over number
ADDI T2,-"0"(T4) ;Add in digit
GTPNM2: TLNE T1,760000 ;Done all 5 chars?
JRST GTPNM1 ;No
POPJ P,
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
MOVSI T1,-PLTNUM ;Number of plotters
SKIPL PLTTAB(T1) ;Are any active?
AOBJN T1,.-1
SKIPL T1 ;If any one is active,
POPJ P, ; leave X.ORIG alone
DMOVEM X,X.ORIG ;Clear origin
DMOVEM X,X.WIND ; and SETWIN limits
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,PLTINC(P4) ;Convert to inches
FDVR Y,PLTINC(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.
;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, get the old position
SETZ NEW.BD, ;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
SETZ NEW.BD, ;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
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
HRRZ T1,T2 ;Get the old Y intercept flag
CAIN T1,(NEW.BD) ;Both above or both below the window?
JUMPN T1,OUTOK ;Jump if line is entirely outside
HLRZS T2 ;Get the old X intercept flag
HLRZ T3,NEW.BD ;Get the new X intercept flag
CAIN T2,(T3) ;Both to left or both to right of window?
JUMPN T2,OUTOK ;Jump if line is entirely outside
JRST OUTOUT ;Line goes OUTIN, ININ, INOUT
;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.BD no longer invalid
POPJ P,
;Here for a line that goes from outside to outside, but part of it is visible
OUTOUT: PUSHJ P,OUTIN1 ;First find where the line comes into the window
JRST INOUT0 ;Now draw part of line until it hits the window
;Here for a line that goes from outside to inside
OUTIN: PUSHJ P,OUTIN1 ;Find where the line comes into the window
JRST INOK ;Go plot the line to the new point
OUTIN1: PUSHJ P,COMPM ;Go compute the slope and Y intercept
PUSHJ P,NEWOLD ;Make COMP find point closest to old position
PUSHJ P,COMP ;Compute the intercept point
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: PUSHJ P,COMP ;Go compute the intercept point
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 E.PLOT ; or message counter at zero?
POPJ P, ;Yes, no warnings
;This really should be a warning, and type X.CALL and Y.CALL
ERRSTR (<Plot Window was Exceeded>)
SKIPL E.PLOT ;Was counter negative?
JRST [SOS E.PLOT ;No, just count down to zero
POPJ P, ]
AOS E.PLOT ;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
; *normal return* ;New coordinates are in X and Y
COMP: PUSHJ P,COMPX ;Go compute X from a given Y
JRST [PUSHJ P,COMPY ;Computed X not in window, compute Y from X
JFCL ;Should always skip
POPJ P, ] ;Use Y based on 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)?
POPJ P, ;Yes, X and Y set up
COMP0: DMOVE X,TEMP+0 ;No, previous X and Y were better
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
SETZ M, ;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