Google
 

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