Prev: 2320 Up: Map Next: 247D
2382: 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.
Input
Output
DRAW 2382 RST $18 Get the current character.
2383 CP "," If it is a comma, then jump.
2385 JR Z,DR_3_PRMS
2387 CALL CHECK_END Move on to next statement if checking syntax.
238A JP LINE_DRAW Jump to just draw the line.
DR_3_PRMS 238D RST $20 Get next character (the angle).
238E CALL CLASS_06 Angle to calculator stack.
2391 CALL CHECK_END Move on to next statement if checking syntax.
2394 RST $28 X, Y, G are on the stack.
2395 DEFB $C5 st_mem_5: (G is copied to mem-5)
2396 DEFB $A2 stk_half: X, Y, G, 0.5
2397 DEFB $04 multiply: X, Y, G/2
2398 DEFB $1F sin: X, Y, SIN (G/2)
2399 DEFB $31 duplicate: X, Y, SIN (G/2), SIN (G/2)
239A DEFB $30 f_not: X, Y, SIN (G/2), (0/1)
239B DEFB $30 f_not: X, Y, SIN (G/2), (1/0)
239C DEFB $00 jump_true: X, Y, SIN (G/2)
239D DEFB $06 to DR_SIN_NZ (if SIN (G/2)=0 i.e. G=2πN just draw a straight line).
239E DEFB $02 delete: X, Y
239F DEFB $38 end_calc
23A0 JP LINE_DRAW Line X0, Y0 to X0+X, Y0+Y.
DR_SIN_NZ 23A3 DEFB $C0 st_mem_0: (SIN (G/2) is copied to mem-0)
23A4 DEFB $02 delete: X, Y are now on the stack.
23A5 DEFB $C1 st_mem_1: (Y is copied to mem-1).
23A6 DEFB $02 delete: X
23A7 DEFB $31 duplicate: X, X
23A8 DEFB $2A abs: X, X' (X'=ABS X)
23A9 DEFB $E1 get_mem_1: X, X', Y
23AA DEFB $01 exchange: X, Y, X'
23AB DEFB $E1 get_mem_1: X, Y, X', Y
23AC DEFB $2A abs: X, Y, X', Y' (Y'=ABS Y)
23AD DEFB $0F addition: X, Y, X'+Y'
23AE DEFB $E0 get_mem_0: X, Y, X'+Y', SIN (G/2)
23AF DEFB $05 division: X, Y, (X'+Y')/SIN (G/2)=Z', say
23B0 DEFB $2A abs: X, Y, Z (Z=ABS Z')
23B1 DEFB $E0 get_mem_0: X, Y, Z, SIN (G/2)
23B2 DEFB $01 exchange: X, Y, SIN (G/2), Z
23B3 DEFB $3D re_stack: (Z is re-stacked to make sure that its exponent is available).
23B4 DEFB $38 end_calc
23B5 LD A,(HL) Get exponent of Z.
23B6 CP $81 If Z is greater than or equal to 1, jump.
23B8 JR NC,DR_PRMS
23BA RST $28 X, Y, SIN (G/2), Z
23BB DEFB $02 delete: X, Y, SIN (G/2)
23BC DEFB $02 delete: X, Y
23BD DEFB $38 end_calc
23BE 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 23C1 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.
23C4 PUSH BC Save the arc-counter in B.
23C5 RST $28 X, Y, SIN(G/2), Z
23C6 DEFB $02 delete: X, Y, SIN(G/2)
23C7 DEFB $E1 get_mem_1: X, Y, SIN(G/2), SIN(G/2*A)
23C8 DEFB $01 exchange: X, Y, SIN(G/2*A), SIN(G/2)
23C9 DEFB $05 division: X, Y, SIN(G/2*A)/SIN(G/2)=W
23CA DEFB $C1 st_mem_1: (W is copied to mem-1).
23CB DEFB $02 delete: X, Y
23CC DEFB $01 exchange: Y, X
23CD DEFB $31 duplicate: Y, X, X
23CE DEFB $E1 get_mem_1: Y, X, X, W
23CF DEFB $04 multiply: Y, X, X*W
23D0 DEFB $C2 st_mem_2: (X*W is copied to mem-2).
23D1 DEFB $02 delete: Y, X
23D2 DEFB $01 exchange: X, Y
23D3 DEFB $31 duplicate: X, Y, Y
23D4 DEFB $E1 get_mem_1: X, Y, Y, W
23D5 DEFB $04 multiply: X, Y, Y*W
23D6 DEFB $E2 get_mem_2: X, Y, Y*W, X*W
23D7 DEFB $E5 get_mem_5: X, Y, Y*W, X*W,G
23D8 DEFB $E0 get_mem_0: X, Y, Y*W, X*W, G, G/A
23D9 DEFB $03 subtract: X, Y, Y*W, X*W, G-G/A
23DA DEFB $A2 stk_half: X, Y, Y*W, X*W, G-G/A, 1/2
23DB DEFB $04 multiply: X, Y, Y*W, X*W, G/2-G/2*A=F
23DC DEFB $31 duplicate: X, Y, Y*W, X*W, F, F
23DD DEFB $1F sin: X, Y, Y*W, X*W, F, SIN F
23DE DEFB $C5 st_mem_5: (SIN F is copied to mem-5).
23DF DEFB $02 delete: X, Y, Y*W, X*W,F
23E0 DEFB $20 cos: X, Y, Y*W, X*W, COS F
23E1 DEFB $C0 st_mem_0: (COS F is copied to mem-0).
23E2 DEFB $02 delete: X, Y, Y*W, X*W
23E3 DEFB $C2 st_mem_2: (X*W is copied to mem-2).
23E4 DEFB $02 delete: X, Y, Y*W
23E5 DEFB $C1 st_mem_1: (Y*W is copied to mem-1).
23E6 DEFB $E5 get_mem_5: X, Y, Y*W, SIN F
23E7 DEFB $04 multiply: X, Y, Y*W*SIN F
23E8 DEFB $E0 get_mem_0: X, Y, Y*W*SIN F, X*W
23E9 DEFB $E2 get_mem_2: X, Y, Y*W*SIN F, X*W, COS F
23EA DEFB $04 multiply: X, Y, Y*W*SIN F, X*W*COS F
23EB DEFB $0F addition: X, Y, Y*W*SIN F+X*W*COS F=U
23EC DEFB $E1 get_mem_1: X, Y, U, Y*W
23ED DEFB $01 exchange: X, Y, Y*W, U
23EE DEFB $C1 st_mem_1: (U is copied to mem-1)
23EF DEFB $02 delete: X, Y, Y*W
23F0 DEFB $E0 get_mem_0: X, Y, Y*W, COS F
23F1 DEFB $04 multiply: X, Y, Y*W*COS F
23F2 DEFB $E2 get_mem_2: X, Y, Y*W*COS F, X*W
23F3 DEFB $E5 get_mem_5: X, Y, Y*W*COS F, X*W, SIN F
23F4 DEFB $04 multiply: X, Y, Y*W*COS F, X*W*SIN F
23F5 DEFB $03 subtract: X, Y, Y*W*COS F-X*W*SIN F=V
23F6 DEFB $C2 st_mem_2: (V is copied to mem-2).
23F7 DEFB $2A abs: X, Y, V' (V'=ABS V)
23F8 DEFB $E1 get_mem_1: X, Y, V', U
23F9 DEFB $2A abs: X, Y, V', U' (U'=ABS U)
23FA DEFB $0F addition: X, Y, U'+V'
23FB DEFB $02 delete: X, Y
23FC DEFB $38 end_calc: (DE now points to U'+V').
23FD LD A,(DE) Get exponent of U'+V'.
23FE CP $81 If U'+V' is less than 1, just tidy the stack and draw the line from X0, Y0 to X0+X, Y0+Y.
2400 POP BC
2401 JP C,LINE_DRAW
2404 PUSH BC Otherwise, continue with the parameters: X, Y, on the stack.
2405 RST $28
2406 DEFB $01 exchange: Y, X
2407 DEFB $38 end_calc
2408 LD A,($5C7D) Get X0 from COORDS into A and so on to the stack.
240B CALL STACK_A
240E RST $28 Y, X, X0
240F DEFB $C0 st_mem_0: (X0 is copied to mem-0).
2410 DEFB $0F addition: Y, X0+X
2411 DEFB $01 exchange: X0+X, Y
2412 DEFB $38 end_calc
2413 LD A,($5C7E) Get Y0 from COORDS into A and so on to the stack.
2416 CALL STACK_A
2419 RST $28 X0+X, Y, Y0
241A DEFB $C5 st_mem_5: (Y0 is copied to mem-5).
241B DEFB $0F addition: X0+X, Y0+Y
241C DEFB $E0 get_mem_0: X0+X, Y0+Y, X0
241D DEFB $E5 get_mem_5: X0+X, Y0+Y, X0, Y0
241E DEFB $38 end_calc
241F 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 2420 DEC B B counts the passes through the loop.
2421 JR Z,ARC_END Jump when B has reached zero.
2423 JR ARC_START Jump into the loop to start.
ARC_LOOP 2425 RST $28 (See text above for the stack).
2426 DEFB $E1 get_mem_1: Un-1
2427 DEFB $31 duplicate: Un-1, Un-1
2428 DEFB $E3 get_mem_3: Un-1, Un-1, COS(G/A)
2429 DEFB $04 multiply: Un-1, Un-1*COS(G/A)
242A DEFB $E2 get_mem_2: Un-1, Un-1*COS(G/A), Vn-1
242B DEFB $E4 get_mem_4: Un-1, Un-1*COS(G/A), Vn-1, SIN(G/A)
242C DEFB $04 multiply: Un-1, Un-1*COS(G/A), Vn-1*SIN(G/A)
242D DEFB $03 subtract: Un-1, Un-1*COS(G/A)-Vn-1*SIN(G/A)=Un
242E DEFB $C1 st_mem_1: (Un is copied to mem-1).
242F DEFB $02 delete: Un-1
2430 DEFB $E4 get_mem_4: Un-1, SIN(G/A)
2431 DEFB $04 multiply: Un-1*SIN(G/A)
2432 DEFB $E2 get_mem_2: Un-1*SIN(G/A), Vn-1
2433 DEFB $E3 get_mem_3: Un-1*SIN(G/A), Vn-1, COS(G/A)
2434 DEFB $04 multiply: Un-1*SIN(G/A), Vn-1*COS(G/A)
2435 DEFB $0F addition: Un-1*SIN(G/A)+Vn-1*COS(G/A)=Vn
2436 DEFB $C2 st_mem_2: (Vn is copied to mem-2).
2437 DEFB $02 delete: (As noted in the text, the stack in fact holds X0+X, Y0+Y, Xn and Yn).
2438 DEFB $38 end_calc
ARC_START 2439 PUSH BC Save the arc-counter.
243A RST $28 X0+X, Y0+y, Xn, Yn
243B DEFB $C0 st_mem_0: (Yn is copied to mem-0).
243C DEFB $02 delete: X0+X, Y0+Y, Xn
243D DEFB $E1 get_mem_1: X0+X, Y0+Y, Xn, Un
243E DEFB $0F addition: X0+X, Y0+Y, Xn+Un=Xn+1
243F DEFB $31 duplicate: X0+X, Y0+Y, Xn+1, Xn+1
2440 DEFB $38 end_calc
2441 LD A,($5C7D) Next Xn', the approximate value of Xn reached by the line-drawing subroutine is copied from COORDS to A and hence to the stack.
2444 CALL STACK_A
2447 RST $28 X0+X, Y0+Y, Xn+1, Xn'
2448 DEFB $03 subtract: X0+X, Y0+Y, Xn+1, Xn+1, Xn'-Xn'=Un'
2449 DEFB $E0 get_mem_0: X0+X, Y0+Y, Xn+1, Un', Yn
244A DEFB $E2 get_mem_2: X0+X, Y0+Y, Xn+1, Un', Yn, Vn
244B DEFB $0F addition: X0+X, Y0+Y, Xn+1, Un', Yn+Vn=Yn+1
244C DEFB $C0 st_mem_0: (Yn+1 is copied to mem-0).
244D DEFB $01 exchange: X0+X, Y0+Y, Xn+1, Yn+1, Un'
244E DEFB $E0 get_mem_0: X0+X, Y0+Y, Xn+1, Yn+1, Un', Yn+1
244F DEFB $38 end_calc
2450 LD A,($5C7E) Yn', approximate like Xn', is copied from COORDS to A and hence to the stack.
2453 CALL STACK_A
2456 RST $28 X0+X, Y0+Y, Xn+1, Yn+1, Un', Yn+1, Yn'
2457 DEFB $03 subtract: X0+X, Y0+Y, Xn+1, Yn+1, Un', Vn'
2458 DEFB $38 end_calc
2459 CALL DRAW_LINE The next 'arc' is drawn.
245C POP BC The arc-counter is restored.
245D DJNZ ARC_LOOP Jump if more arcs to draw.
ARC_END 245F RST $28
2460 DEFB $02 delete: The co-ordinates of the end of the last arc that was drawn are now deleted from the stack.
2461 DEFB $02
2462 DEFB $01 exchange: Y0+Y, X0+X
2463 DEFB $38 end_calc
2464 LD A,($5C7D) The X-co-ordinate of the end of the last arc that was drawn, say Xz', is copied from COORDS to the stack.
2467 CALL STACK_A
246A RST $28
246B DEFB $03 subtract: Y0+Y, X0+X-Xz'
246C DEFB $01 exchange: X0+X-Xz', Y0+Y
246D DEFB $38 end_calc
246E LD A,($5C7E) The Y-co-ordinate is obtained from COORDS and stacked.
2471 CALL STACK_A
2474 RST $28 X0+X-Xz', Y0+Y, Yz'
2475 DEFB $03 subtract: X0+X-Xz', Y0+Y-Yz'
2476 DEFB $38 end_calc
LINE_DRAW 2477 CALL DRAW_LINE The final arc is drawn to reach X0+X, Y0+Y (or close the circle).
247A JP TEMPS Exit, setting temporary colours.
Prev: 2320 Up: Map Next: 247D