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 (,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, ;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 ,< 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, ;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),-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 , ;Remember size of biggest data area DEPHASE CHAIN==NM'.DA ;Update pointer SALL ;End of PPDATA macro IFN NM'TYP&P4.TTY, ;Define feature-test if for terminal > ;End of DEFINE PPDATA LIST PLTSIZ=>>;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,) 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, ;Convert to integer IFN FTKA, FMPR Y,PLTINY(P4) ;Convert to increments IFE FTKA, ;Convert to integer IFN FTKA, 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,) 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,) 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), ;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