| Routines

09090: THE 'DRAW' COMMAND ROUTINE

The address of this routine is found in the parameter table. This routine is entered with the co-ordinates of a point X0, Y0, say, in COORDS. If only two parameters X, Y are given with the DRAW command, it draws an approximation to a straight line from the point X0, Y0 to X0+X, Y0+Y. If a third parameter G is given, it draws an approximation to a circular arc from X0, Y0 to X0+X, Y0+Y turning anti-clockwise through an angle G radians. The routine has four parts: i. Just draws a line if only 2 parameters are given or if the diameter of the implied circle is less than 1. ii. Calls CD_PRMS1 to set the first parameters. iii. Sets up the remaining parameters, including the initial displacements for the first arc. iv. Enters the arc-drawing loop and draws the arc as a series of smaller arcs approximated by straight lines, calling the line-drawing subroutine at DRAW_LINE as necessary. Two subroutines, CD_PRMS1 and DRAW_LINE, follow the main routine. The above 4 parts of the main routine will now be treated in turn. i. If there are only 2 parameters, a jump is made to LINE_DRAW. A line is also drawn if the quantity Z=(ABS X+ABS Y)/ABS SIN(G/2) is less than 1. Z lies between 1 and 1.5 times the diameter of the implied circle. In this section mem-0 is set to SIN (G/2), mem-1 to Y, and mem-5 to G.
DRAW | 09090 | RST 24 | Get the current character.
| 09091 | CP "," | If it is a comma, then jump.
| 09093 | JR Z,DR_3_PRMS
| 09095 | CALL CHECK_END | Move on to next statement if checking syntax.
| 09098 | JP LINE_DRAW | Jump to just draw the line.
DR_3_PRMS | 09101 | RST 32 | Get next character (the angle).
| 09102 | CALL CLASS_06 | Angle to calculator stack.
| 09105 | CALL CHECK_END | Move on to next statement if checking syntax.
| 09108 | RST 40 | X, Y, G are on the stack.
| 09109 | DEFB 197 | st_mem_5: (G is copied to mem-5)
| 09110 | DEFB 162 | stk_half: X, Y, G, 0.5
| 09111 | DEFB 4 | multiply: X, Y, G/2
| 09112 | DEFB 31 | sin: X, Y, SIN (G/2)
| 09113 | DEFB 49 | duplicate: X, Y, SIN (G/2), SIN (G/2)
| 09114 | DEFB 48 | f_not: X, Y, SIN (G/2), (0/1)
| 09115 | DEFB 48 | f_not: X, Y, SIN (G/2), (1/0)
| 09116 | DEFB 0 | jump_true: X, Y, SIN (G/2)
| 09117 | DEFB 6 | to DR_SIN_NZ (if SIN (G/2)=0 i.e. G=2πN just draw a straight line).
| 09118 | DEFB 2 | delete: X, Y
| 09119 | DEFB 56 | end_calc
| 09120 | JP LINE_DRAW | Line X0, Y0 to X0+X, Y0+Y.
DR_SIN_NZ | 09123 | DEFB 192 | st_mem_0: (SIN (G/2) is copied to mem-0)
| 09124 | DEFB 2 | delete: X, Y are now on the stack.
| 09125 | DEFB 193 | st_mem_1: (Y is copied to mem-1).
| 09126 | DEFB 2 | delete: X
| 09127 | DEFB 49 | duplicate: X, X
| 09128 | DEFB 42 | abs: X, X' (X'=ABS X)
| 09129 | DEFB 225 | get_mem_1: X, X', Y
| 09130 | DEFB 1 | exchange: X, Y, X'
| 09131 | DEFB 225 | get_mem_1: X, Y, X', Y
| 09132 | DEFB 42 | abs: X, Y, X', Y' (Y'=ABS Y)
| 09133 | DEFB 15 | addition: X, Y, X'+Y'
| 09134 | DEFB 224 | get_mem_0: X, Y, X'+Y', SIN (G/2)
| 09135 | DEFB 5 | division: X, Y, (X'+Y')/SIN (G/2)=Z', say
| 09136 | DEFB 42 | abs: X, Y, Z (Z=ABS Z')
| 09137 | DEFB 224 | get_mem_0: X, Y, Z, SIN (G/2)
| 09138 | DEFB 1 | exchange: X, Y, SIN (G/2), Z
| 09139 | DEFB 61 | re_stack: (Z is re-stacked to make sure that its exponent is available).
| 09140 | DEFB 56 | end_calc
| 09141 | LD A,(HL) | Get exponent of Z.
| 09142 | CP 129 | If Z is greater than or equal to 1, jump.
| 09144 | JR NC,DR_PRMS
| 09146 | RST 40 | X, Y, SIN (G/2), Z
| 09147 | DEFB 2 | delete: X, Y, SIN (G/2)
| 09148 | DEFB 2 | delete: X, Y
| 09149 | DEFB 56 | end_calc
| 09150 | JP LINE_DRAW | Just draw the line from X0, Y0 to X0+X, Y0+Y.
ii. Just calls CD_PRMS1. This subroutine saves in the B register the number of shorter arcs required for the complete arc, viz. A=4*INT (G'*SQR Z/8)+4 (where G'=ABS G), or 252 if this expression exceeds 252 (as can happen with a large chord and a small angle). So A is a multiple of 4 from 4 to 252. The subroutine also stores in mem-0 to mem-4 the quantities G/A, SIN (G/2*A), 0, COS (G/A), SIN (G/A).
DR_PRMS | 09153 | CALL CD_PRMS1 | The subroutine is called.
iii. Sets up the rest of the parameters as follow. The stack will hold these 4 items, reading up to the top: X0+X and Y0+Y as end of last arc; then X0 and Y0 as beginning of first arc. Mem-0 will hold X0 and mem-5 Y0. Mem-1 and mem-2 will hold the initial displacements for the first arc, U and V; and mem-3 and mem-4 will hold COS (G/A) and SIN (G/A) for use in the arc-drawing loop. The formulae for U and V can be explained as follows. Instead of stepping along the final chord, of length L, say, with displacements X and Y, we want to step along an initial chord (which may be longer) of length L*W, where W=SIN (G/2*A)/SIN (G/2), with displacements X*W and Y*W, but turned through an angle (G/2-G/2*A), hence with true displacements: U=Y*W*SIN (G/2-G/2*A)+X*W*COS (G/2-G/2*A) Y=Y*W*COS (G/2-G/2*A)-X*W*SIN (G/2-G/2*A) These formulae can be checked from a diagram, using the normal expansion of COS (P-Q) and SIN (P-Q), where Q=G/2-G/2*A.
| 09156 | PUSH BC | Save the arc-counter in B.
| 09157 | RST 40 | X, Y, SIN(G/2), Z
| 09158 | DEFB 2 | delete: X, Y, SIN(G/2)
| 09159 | DEFB 225 | get_mem_1: X, Y, SIN(G/2), SIN(G/2*A)
| 09160 | DEFB 1 | exchange: X, Y, SIN(G/2*A), SIN(G/2)
| 09161 | DEFB 5 | division: X, Y, SIN(G/2*A)/SIN(G/2)=W
| 09162 | DEFB 193 | st_mem_1: (W is copied to mem-1).
| 09163 | DEFB 2 | delete: X, Y
| 09164 | DEFB 1 | exchange: Y, X
| 09165 | DEFB 49 | duplicate: Y, X, X
| 09166 | DEFB 225 | get_mem_1: Y, X, X, W
| 09167 | DEFB 4 | multiply: Y, X, X*W
| 09168 | DEFB 194 | st_mem_2: (X*W is copied to mem-2).
| 09169 | DEFB 2 | delete: Y, X
| 09170 | DEFB 1 | exchange: X, Y
| 09171 | DEFB 49 | duplicate: X, Y, Y
| 09172 | DEFB 225 | get_mem_1: X, Y, Y, W
| 09173 | DEFB 4 | multiply: X, Y, Y*W
| 09174 | DEFB 226 | get_mem_2: X, Y, Y*W, X*W
| 09175 | DEFB 229 | get_mem_5: X, Y, Y*W, X*W,G
| 09176 | DEFB 224 | get_mem_0: X, Y, Y*W, X*W, G, G/A
| 09177 | DEFB 3 | subtract: X, Y, Y*W, X*W, G-G/A
| 09178 | DEFB 162 | stk_half: X, Y, Y*W, X*W, G-G/A, 1/2
| 09179 | DEFB 4 | multiply: X, Y, Y*W, X*W, G/2-G/2*A=F
| 09180 | DEFB 49 | duplicate: X, Y, Y*W, X*W, F, F
| 09181 | DEFB 31 | sin: X, Y, Y*W, X*W, F, SIN F
| 09182 | DEFB 197 | st_mem_5: (SIN F is copied to mem-5).
| 09183 | DEFB 2 | delete: X, Y, Y*W, X*W,F
| 09184 | DEFB 32 | cos: X, Y, Y*W, X*W, COS F
| 09185 | DEFB 192 | st_mem_0: (COS F is copied to mem-0).
| 09186 | DEFB 2 | delete: X, Y, Y*W, X*W
| 09187 | DEFB 194 | st_mem_2: (X*W is copied to mem-2).
| 09188 | DEFB 2 | delete: X, Y, Y*W
| 09189 | DEFB 193 | st_mem_1: (Y*W is copied to mem-1).
| 09190 | DEFB 229 | get_mem_5: X, Y, Y*W, SIN F
| 09191 | DEFB 4 | multiply: X, Y, Y*W*SIN F
| 09192 | DEFB 224 | get_mem_0: X, Y, Y*W*SIN F, X*W
| 09193 | DEFB 226 | get_mem_2: X, Y, Y*W*SIN F, X*W, COS F
| 09194 | DEFB 4 | multiply: X, Y, Y*W*SIN F, X*W*COS F
| 09195 | DEFB 15 | addition: X, Y, Y*W*SIN F+X*W*COS F=U
| 09196 | DEFB 225 | get_mem_1: X, Y, U, Y*W
| 09197 | DEFB 1 | exchange: X, Y, Y*W, U
| 09198 | DEFB 193 | st_mem_1: (U is copied to mem-1)
| 09199 | DEFB 2 | delete: X, Y, Y*W
| 09200 | DEFB 224 | get_mem_0: X, Y, Y*W, COS F
| 09201 | DEFB 4 | multiply: X, Y, Y*W*COS F
| 09202 | DEFB 226 | get_mem_2: X, Y, Y*W*COS F, X*W
| 09203 | DEFB 229 | get_mem_5: X, Y, Y*W*COS F, X*W, SIN F
| 09204 | DEFB 4 | multiply: X, Y, Y*W*COS F, X*W*SIN F
| 09205 | DEFB 3 | subtract: X, Y, Y*W*COS F-X*W*SIN F=V
| 09206 | DEFB 194 | st_mem_2: (V is copied to mem-2).
| 09207 | DEFB 42 | abs: X, Y, V' (V'=ABS V)
| 09208 | DEFB 225 | get_mem_1: X, Y, V', U
| 09209 | DEFB 42 | abs: X, Y, V', U' (U'=ABS U)
| 09210 | DEFB 15 | addition: X, Y, U'+V'
| 09211 | DEFB 2 | delete: X, Y
| 09212 | DEFB 56 | end_calc: (DE now points to U'+V').
| 09213 | LD A,(DE) | Get exponent of U'+V'.
| 09214 | CP 129 | If U'+V' is less than 1, just tidy the stack and draw the line from X0, Y0 to X0+X, Y0+Y.
| 09216 | POP BC
| 09217 | JP C,LINE_DRAW
| 09220 | PUSH BC | Otherwise, continue with the parameters: X, Y, on the stack.
| 09221 | RST 40
| 09222 | DEFB 1 | exchange: Y, X
| 09223 | DEFB 56 | end_calc
| 09224 | LD A,(23677) | Get X0 from COORDS into A and so on to the stack.
| 09227 | CALL STACK_A
| 09230 | RST 40 | Y, X, X0
| 09231 | DEFB 192 | st_mem_0: (X0 is copied to mem-0).
| 09232 | DEFB 15 | addition: Y, X0+X
| 09233 | DEFB 1 | exchange: X0+X, Y
| 09234 | DEFB 56 | end_calc
| 09235 | LD A,(23678) | Get Y0 from COORDS into A and so on to the stack.
| 09238 | CALL STACK_A
| 09241 | RST 40 | X0+X, Y, Y0
| 09242 | DEFB 197 | st_mem_5: (Y0 is copied to mem-5).
| 09243 | DEFB 15 | addition: X0+X, Y0+Y
| 09244 | DEFB 224 | get_mem_0: X0+X, Y0+Y, X0
| 09245 | DEFB 229 | get_mem_5: X0+X, Y0+Y, X0, Y0
| 09246 | DEFB 56 | end_calc
| 09247 | POP BC | Restore the arc-counter in B.
This entry point is used by the routine at CIRCLE. iv. The arc-drawing loop. This is entered at ARC_START with the co-ordinates of the starting point on top of the stack, and the initial displacements for the first arc in mem-1 and mem-2. It uses simple trigonometry to ensure that all subsequent arcs will be drawn to points that lie on the same circle as the first two, subtending the same angle at the centre. It can be shown that if 2 points X1, Y1 and X2, Y2 lie on a circle and subtend an angle N at the centre, which is also the origin of co-ordinates, then X2=X1*COS N-Y1*SIN N, and Y2=X1*SIN N+Y1*COS N. But because the origin is here at the increments, say Un=Xn+1-Xn and Vn=Yn+1-Yn, thus achieving the desired result. The stack is shown below on the (n+1)th pass through the loop, as Xn and Yn are incremented by Un and Vn, after these are obtained from Un-1 and Vn-1. The 4 values on the top of the stack at ARC_LOOP are, in DRAW, reading upwards, X0+X, Y0+Y, Xn and Yn but to save space these are not shown until ARC_START. For the initial values in CIRCLE, see the end of CIRCLE, above. In CIRCLE too, the angle G must be taken to be 2π.
DRW_STEPS | 09248 | DEC B | B counts the passes through the loop.
| 09249 | JR Z,ARC_END | Jump when B has reached zero.
| 09251 | JR ARC_START | Jump into the loop to start.
ARC_LOOP | 09253 | RST 40 | (See text above for the stack).
| 09254 | DEFB 225 | get_mem_1: Un-1
| 09255 | DEFB 49 | duplicate: Un-1, Un-1
| 09256 | DEFB 227 | get_mem_3: Un-1, Un-1, COS(G/A)
| 09257 | DEFB 4 | multiply: Un-1, Un-1*COS(G/A)
| 09258 | DEFB 226 | get_mem_2: Un-1, Un-1*COS(G/A), Vn-1
| 09259 | DEFB 228 | get_mem_4: Un-1, Un-1*COS(G/A), Vn-1, SIN(G/A)
| 09260 | DEFB 4 | multiply: Un-1, Un-1*COS(G/A), Vn-1*SIN(G/A)
| 09261 | DEFB 3 | subtract: Un-1, Un-1*COS(G/A)-Vn-1*SIN(G/A)=Un
| 09262 | DEFB 193 | st_mem_1: (Un is copied to mem-1).
| 09263 | DEFB 2 | delete: Un-1
| 09264 | DEFB 228 | get_mem_4: Un-1, SIN(G/A)
| 09265 | DEFB 4 | multiply: Un-1*SIN(G/A)
| 09266 | DEFB 226 | get_mem_2: Un-1*SIN(G/A), Vn-1
| 09267 | DEFB 227 | get_mem_3: Un-1*SIN(G/A), Vn-1, COS(G/A)
| 09268 | DEFB 4 | multiply: Un-1*SIN(G/A), Vn-1*COS(G/A)
| 09269 | DEFB 15 | addition: Un-1*SIN(G/A)+Vn-1*COS(G/A)=Vn
| 09270 | DEFB 194 | st_mem_2: (Vn is copied to mem-2).
| 09271 | DEFB 2 | delete: (As noted in the text, the stack in fact holds X0+X, Y0+Y, Xn and Yn).
| 09272 | DEFB 56 | end_calc
ARC_START | 09273 | PUSH BC | Save the arc-counter.
| 09274 | RST 40 | X0+X, Y0+y, Xn, Yn
| 09275 | DEFB 192 | st_mem_0: (Yn is copied to mem-0).
| 09276 | DEFB 2 | delete: X0+X, Y0+Y, Xn
| 09277 | DEFB 225 | get_mem_1: X0+X, Y0+Y, Xn, Un
| 09278 | DEFB 15 | addition: X0+X, Y0+Y, Xn+Un=Xn+1
| 09279 | DEFB 49 | duplicate: X0+X, Y0+Y, Xn+1, Xn+1
| 09280 | DEFB 56 | end_calc
| 09281 | LD A,(23677) | Next Xn', the approximate value of Xn reached by the line-drawing subroutine is copied from COORDS to A and hence to the stack.
| 09284 | CALL STACK_A
| 09287 | RST 40 | X0+X, Y0+Y, Xn+1, Xn'
| 09288 | DEFB 3 | subtract: X0+X, Y0+Y, Xn+1, Xn+1, Xn'-Xn'=Un'
| 09289 | DEFB 224 | get_mem_0: X0+X, Y0+Y, Xn+1, Un', Yn
| 09290 | DEFB 226 | get_mem_2: X0+X, Y0+Y, Xn+1, Un', Yn, Vn
| 09291 | DEFB 15 | addition: X0+X, Y0+Y, Xn+1, Un', Yn+Vn=Yn+1
| 09292 | DEFB 192 | st_mem_0: (Yn+1 is copied to mem-0).
| 09293 | DEFB 1 | exchange: X0+X, Y0+Y, Xn+1, Yn+1, Un'
| 09294 | DEFB 224 | get_mem_0: X0+X, Y0+Y, Xn+1, Yn+1, Un', Yn+1
| 09295 | DEFB 56 | end_calc
| 09296 | LD A,(23678) | Yn', approximate like Xn', is copied from COORDS to A and hence to the stack.
| 09299 | CALL STACK_A
| 09302 | RST 40 | X0+X, Y0+Y, Xn+1, Yn+1, Un', Yn+1, Yn'
| 09303 | DEFB 3 | subtract: X0+X, Y0+Y, Xn+1, Yn+1, Un', Vn'
| 09304 | DEFB 56 | end_calc
| 09305 | CALL DRAW_LINE | The next 'arc' is drawn.
| 09308 | POP BC | The arc-counter is restored.
| 09309 | DJNZ ARC_LOOP | Jump if more arcs to draw.
ARC_END | 09311 | RST 40
| 09312 | DEFB 2 | delete: The co-ordinates of the end of the last arc that was drawn are now deleted from the stack.
| 09313 | DEFB 2
| 09314 | DEFB 1 | exchange: Y0+Y, X0+X
| 09315 | DEFB 56 | end_calc
| 09316 | LD A,(23677) | The X-co-ordinate of the end of the last arc that was drawn, say Xz', is copied from COORDS to the stack.
| 09319 | CALL STACK_A
| 09322 | RST 40 |
| 09323 | DEFB 3 | subtract: Y0+Y, X0+X-Xz'
| 09324 | DEFB 1 | exchange: X0+X-Xz', Y0+Y
| 09325 | DEFB 56 | end_calc
| 09326 | LD A,(23678) | The Y-co-ordinate is obtained from COORDS and stacked.
| 09329 | CALL STACK_A
| 09332 | RST 40 | X0+X-Xz', Y0+Y, Yz'
| 09333 | DEFB 3 | subtract: X0+X-Xz', Y0+Y-Yz'
| 09334 | DEFB 56 | end_calc
LINE_DRAW | 09335 | CALL DRAW_LINE | The final arc is drawn to reach X0+X, Y0+Y (or close the circle).
| 09338 | JP TEMPS | Exit, setting temporary colours.