! Geometric Utilities for EDWIN, capitalising on device specific features. !############################################################################ !# # !# This is a module from the EDWIN Graphics Package, which was developed # !# in the Department of Computer Science, at Edinburgh University, from # !# 1978 to the present day, release 5 of EDWIN in October 1984. # !# # !# The principal author of the EDWIN Graphics Package was J Gordon Hughes, # !# while working for the Edinburgh University Computer Sceince Department. # !# Parts of EDWIN have been produced by many different people, too many # !# too mention, working for different departments of Edinburgh and Leeds # !# Universities. # !# # !# This module is regarded as being in the public domain, and the authors # !# and accept no responsibility regarding the uses to which the software # !# will be put. # !# # !############################################################################ record format POINTFM (integer X, Y) record format LINEFM (long real A, B, C) ! IMP Maths routines from Imp include maths ! Routines from EDWIN from Edwin include consts from Edwin include specs from Edwin include shapes from Edwin include iprocs from Edwin include icodes const integer MAX POINT = 360 external routine RECTANGLE alias "EDWIN_RECTANGLE" (integer XL, YL, XU, YU) ! This draws a rectangle. integer SHADE MODE PDF INSERT (13, XL, YL); PDF INSERT (13, XU, YU) GET ATTRIBUTE (ATT SHADE MODE, SHADE MODE) if SHADE MODE = OUTLINE start CLIP (XL, YL, 0) CLIP (XU, YL, 1); CLIP (XU, YU, 1) CLIP (XL, YU, 1); CLIP (XL, YL, 1) else MAP TO DEVICE COORDS (XL, YL) DRIVE DEVICE (12, XL, YL) MAP TO DEVICE COORDS (XU, YU) DRIVE DEVICE (13, XU, YU) finish end ! This is a routine for drawing clipped polygons, using the Sutherland- ! Hodgman algorithm, CACM Vol 17, Page 32, Jan 74. external routine POLYGON alias "EDWIN_POLYGON" (integer NUM E, record (POINTFM) array name AP) const integer LAST = 3 integer PTR, ANY OUT, STAGE, XL, XR, YB, YT, SHADE MODE, L, W record (POINTFM) FIRST PT, C, D record (POINTFM) array F, S (0:3) byte integer array FIRST OF, OUT (0:3) routine GET RID OF (record (POINTFM) name P) if ANY OUT=FALSE start DRIVE DEVICE (10, 3, 0) if SHADE MODE#OUTLINE CLIP (P_X, P_Y, 0) FIRST PT = P ANY OUT = TRUE finish CLIP (P_X, P_Y, 1) end routine spec DEAL WITH POINT (record (POINTFM) name P) routine OUTPUT (record (POINTFM) name P) OUT (STAGE) = TRUE GET RID OF (P) and return if STAGE = LAST STAGE = STAGE + 1 DEAL WITH POINT (P) STAGE = STAGE - 1 end integer fn INTERSECT (record (POINTFM) name S,P) ! Note if point is on the line it is assumed to intersect it. switch SW(0:3) -> SW(STAGE) SW(0): ! XL result = TRUE if S_X<=XL<P_X or P_X<=XL<S_X result = FALSE SW(2): ! XR result = TRUE if S_X<=XR<P_X or P_X<=XR<S_X result = FALSE SW(1): ! YB result = TRUE if S_Y<=YB<P_Y or P_Y<=YB<S_Y result = FALSE SW(3): ! YT result = TRUE if S_Y<=YT<P_Y or P_Y<=YT<S_Y result = FALSE end integer fn visible (record (POINTFM) name S) switch SW(0:3) -> SW(STAGE) SW(0): result = TRUE if S_X>=XL result = FALSE SW(2): result = TRUE if S_X<=XR result = FALSE SW(1): result = TRUE if S_Y>=YB result = FALSE SW(3): result = TRUE if S_Y<=YT result = FALSE end routine compute intersect (record (POINTFM) name I, P, S) ! Computes intersect I from points P and S. switch SW(0:3) -> SW(STAGE) SW(0): I_X = XL I_Y = MUL DIV (P_Y-S_Y, XL-S_X, P_X-S_X) + S_Y return SW(2): I_X = XR I_Y = MUL DIV (P_Y-S_Y, XR-S_X, P_X-S_X) + S_Y return SW(1): I_X = MUL DIV (P_X-S_X, YB-S_Y, P_Y-S_Y) + S_X I_Y = YB return SW(3): I_X = MUL DIV (P_X-S_X, YT-S_Y, P_Y-S_Y) + S_X I_Y = YT end routine DEAL WITH INTERSECT (record (POINTFM) name P) record (POINTFM) I if FIRST OF (STAGE)=TRUE start COMPUTE INTERSECT (I, P, S(STAGE)) and OUTPUT (I) if INTERSECT (P, S(STAGE)) = TRUE else F(STAGE) = P FIRST OF (STAGE) = TRUE finish end routine DEAL WITH POINT (record (POINTFM) name P) DEAL WITH INTERSECT (P) S(STAGE) = P OUTPUT (P) if VISIBLE (P) = TRUE end ANY OUT = FALSE GET ATTRIBUTE (ATT SHADE MODE, SHADE MODE) NUM E = NUM E - 1 if AP(NUM E)_X=AP(1)_X and AP(NUM E)_Y=AP(1)_Y if NUM E = 4 start ! It is 4 sided, but is it worth making it an orthogonal box? if AP(1)_X = AP(2)_X and AP(2)_Y = AP(3)_Y and - AP(3)_X = AP(4)_X and AP(4)_Y = AP(1)_Y start L = |AP(2)_X - AP(3)_X| W = |AP(1)_Y - AP(2)_Y| if REM(L,2)=0 and REM(W,2)=0 start { No rounding would arise } if AP(2)_X > AP(3)_X then C_X = AP(3)_X else C_X = AP(2)_X C_X = C_X + L//2 if AP(2)_Y > AP(1)_Y then C_Y = AP(1)_Y else C_Y = AP(2)_Y C_Y = C_Y + W//2 -> Do As Polygon if L=0 or W=0 { Co-incident points } Rectangle (AP(1)_x, AP(1)_y, AP(3)_x, AP(3)_y) return finish else if AP(1)_Y = AP(2)_Y and AP(2)_X = AP(3)_X and - AP(3)_Y = AP(4)_Y and AP(4)_X = AP(1)_X L = |AP(1)_X - AP(2)_X| W = |AP(2)_Y - AP(3)_Y| if REM(L,2)=0 and REM(W,2)=0 start { No rounding would arise } if AP(2)_X > AP(1)_X then C_X = AP(1)_X else C_X = AP(2)_X C_X = C_X + L//2 if AP(2)_Y > AP(3)_Y then C_Y = AP(3)_Y else C_Y = AP(2)_Y C_Y = C_Y + W//2 -> Do As Polygon if L=0 or W=0 { Co-incident points } Rectangle (AP(1)_x, AP(1)_y, AP(3)_x, AP(3)_y) return finish finish finish Do as Polygon: if STORING>=0 start; ! Optimise the adding of the points to the PDF STAGE = OUTPUT STREAM SELECT OUTPUT (STORING) WRITE (6, 1); WRITE (NUME, 1) for PTR = 1, 1, NUME cycle WRITE (AP(PTR)_X, 1) WRITE (AP(PTR)_Y, 1) NEWLINE if PTR&7=0 repeat NEWLINE SELECT OUTPUT (STAGE) finish if Shade Mode = Outline start CLIP (AP(1)_X, AP(1)_Y, 0) for PTR = 1, 1, NUME cycle CLIP (AP(PTR)_X, AP(PTR)_Y, 1) repeat CLIP (AP(1)_X, AP(1)_Y, 1) else if CLIPPING>=0 start; ! Only clip if the user asks to INQUIRE WINDOW (XL,XR,YB,YT) STAGE = 0 FIRST OF (PTR) = FALSE and OUT(PTR) = FALSE for PTR=0,1,3 DEAL WITH POINT (AP(PTR)) for PTR = 1,1,NUM E for STAGE = 0,1,3 cycle DEAL WITH INTERSECT (F(STAGE)) if OUT(STAGE) = TRUE repeat return unless ANYOUT=TRUE else GET RID OF (AP(PTR)) for PTR = 1,1,NUM E finish GET RID OF (FIRST PT); ! To close the polygon. DRIVE DEVICE (10, 1, 0) finish end external routine CIRCLE alias "EDWIN_CIRCLE" (integer RAD) ! RAD is the radius. ! The circle is INSIDE the polygon. ! The circle drawing routine is based on an original one by JRCC. const real D TO R = 57.2958; ! Magic number converts degrees to rads. integer I, X, Y, W, XL, XR, YB, YT, PX, PY, DEVICE, CHORD STEP, STORE integer SHADE MODE long real RA, RR, CONT record (POINTFM) array PTS (1:361) PDF INSERT (14, RAD, 0) if CLIPPING>=0 start INQUIRE POSITION (PX, PY) INQUIRE WINDOW (XL, XR, YB, YT) return unless XL-RAD <= PX <= XR+RAD and YB-RAD <= PY <= YT+RAD finish DEVICE = DEVICE DATA_DEV NO GET ATTRIBUTE (ATT SHADE MODE, SHADE MODE) if DEVICE=HP Plotter or DEVICE=X5A or DEVICE=Versatec or c DEVICE=Postscript {%or DEVICE=??? %or DEVICE=???} start I = 0; Y = 0 MAP TO DEVICE COORDS (I, Y) MAP TO DEVICE COORDS (RAD, Y) DRIVE DEVICE (14, |I-RAD|, 0) { Hardware circle } return finish GET ATTRIBUTE (ATT CHORD STEP, CHORD STEP) STORE = STORING; STORING = -1 INQUIRE POSITION (PX, PY) RR = RAD * (2 - Cos(CHORD STEP/2/DtoR)) PTS(1)_X = PX + INT(RR) PTS(1)_Y = PY CONT = CHORD STEP I = 2 cycle RA = CONT / DtoR PTS(I)_X = PX + INT(RR * COS(RA)) PTS(I)_Y = PY + INT(RR * SIN(RA)) CONT = CONT + CHORD STEP exit if CONT>360 I = I + 1 repeat POLYGON (I, PTS) MOVE ABS (PX, PY) STORING = STORE end ! Utilties to draw ARCs and SECTORs routine FIND POINTS (integer RAD, CX, CY, SA, FA, integer name PTR, record (POINTFM) array name AP) integer A, STEP GET ATTRIBUTE (ATT CHORD STEP, STEP) A = SA cycle AP(PTR)_X = int(Rad * Cos(A/DtoR)) + CX AP(PTR)_Y = int(Rad * Sin(A/DtoR)) + CY exit if A = FA PTR = PTR + 1 if SA < FA start A = A + STEP A = FA if A > FA else A = A - STEP A = FA if A < FA finish repeat end external routine ARC alias "EDWIN_ARC" (integer OX, OY, RAD, START ANG, END ANG) record (POINTFM) array P (1:361) integer PTR, I PTR = 1 FIND POINTS (RAD, OX, OY, START ANG, END ANG, PTR, P) MOVE ABS (P(1)_X, P(1)_Y) LINE ABS (P(I)_X, P(I)_Y) for I=2,1,PTR end external routine SECTOR alias "EDWIN_SECTOR" (integer OX, OY, RAD, START ANG, END ANG) record (POINTFM) array P (1:363) integer PTR P(1)_X = OX; P(1)_Y = OY PTR = 2 FIND POINTS (RAD, OX, OY, START ANG, END ANG, PTR, P) PTR = PTR + 1 P (PTR)_X = OX; P(PTR)_Y = OY POLYGON (PTR, P) end end of file