Routines 
Prev: 2320  Up: Map  Next: 247D 
The address of this routine is found in the parameter table.
This routine is entered with the coordinates 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 anticlockwise through an angle G radians.
The routine has four parts:
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 mem0 is set to SIN (G/2), mem1 to Y, and mem5 to G.


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 mem5)  
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 mem0)  
23A4  DEFB $02  delete: X, Y are now on the stack.  
23A5  DEFB $C1  st_mem_1: (Y is copied to mem1).  
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 restacked 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 mem0 to mem4 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. Mem0 will hold X0 and mem5 Y0. Mem1 and mem2 will hold the initial displacements for the first arc, U and V; and mem3 and mem4 will hold COS (G/A) and SIN (G/A) for use in the arcdrawing 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/2G/2*A), hence with true displacements:
These formulae can be checked from a diagram, using the normal expansion of COS (PQ) and SIN (PQ), where Q=G/2G/2*A.


23C4  PUSH BC  Save the arccounter 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 mem1).  
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 mem2).  
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, GG/A  
23DA  DEFB $A2  stk_half: X, Y, Y*W, X*W, GG/A, 1/2  
23DB  DEFB $04  multiply: X, Y, Y*W, X*W, G/2G/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 mem5).  
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 mem0).  
23E2  DEFB $02  delete: X, Y, Y*W, X*W  
23E3  DEFB $C2  st_mem_2: (X*W is copied to mem2).  
23E4  DEFB $02  delete: X, Y, Y*W  
23E5  DEFB $C1  st_mem_1: (Y*W is copied to mem1).  
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 mem1)  
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 FX*W*SIN F=V  
23F6  DEFB $C2  st_mem_2: (V is copied to mem2).  
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 mem0).  
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 mem5).  
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 arccounter in B.  
This entry point is used by the routine at CIRCLE.
iv. The arcdrawing loop. This is entered at ARC_START with the coordinates of the starting point on top of the stack, and the initial displacements for the first arc in mem1 and mem2. 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 coordinates, then X2=X1*COS NY1*SIN N, and Y2=X1*SIN N+Y1*COS N. But because the origin is here at the increments, say Un=Xn+1Xn and Vn=Yn+1Yn, 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 Un1 and Vn1. 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: Un1  
2427  DEFB $31  duplicate: Un1, Un1  
2428  DEFB $E3  get_mem_3: Un1, Un1, COS(G/A)  
2429  DEFB $04  multiply: Un1, Un1*COS(G/A)  
242A  DEFB $E2  get_mem_2: Un1, Un1*COS(G/A), Vn1  
242B  DEFB $E4  get_mem_4: Un1, Un1*COS(G/A), Vn1, SIN(G/A)  
242C  DEFB $04  multiply: Un1, Un1*COS(G/A), Vn1*SIN(G/A)  
242D  DEFB $03  subtract: Un1, Un1*COS(G/A)Vn1*SIN(G/A)=Un  
242E  DEFB $C1  st_mem_1: (Un is copied to mem1).  
242F  DEFB $02  delete: Un1  
2430  DEFB $E4  get_mem_4: Un1, SIN(G/A)  
2431  DEFB $04  multiply: Un1*SIN(G/A)  
2432  DEFB $E2  get_mem_2: Un1*SIN(G/A), Vn1  
2433  DEFB $E3  get_mem_3: Un1*SIN(G/A), Vn1, COS(G/A)  
2434  DEFB $04  multiply: Un1*SIN(G/A), Vn1*COS(G/A)  
2435  DEFB $0F  addition: Un1*SIN(G/A)+Vn1*COS(G/A)=Vn  
2436  DEFB $C2  st_mem_2: (Vn is copied to mem2).  
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 arccounter.  
243A  RST $28  X0+X, Y0+y, Xn, Yn  
243B  DEFB $C0  st_mem_0: (Yn is copied to mem0).  
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 linedrawing 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 mem0).  
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 arccounter is restored.  
245D  DJNZ ARC_LOOP  Jump if more arcs to draw.  
ARC_END  245F  RST $28  
2460  DEFB $02  delete: The coordinates 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 Xcoordinate 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+XXz'  
246C  DEFB $01  exchange: X0+XXz', Y0+Y  
246D  DEFB $38  end_calc  
246E  LD A,($5C7E)  The Ycoordinate is obtained from COORDS and stacked.  
2471  CALL STACK_A  
2474  RST $28  X0+XXz', Y0+Y, Yz'  
2475  DEFB $03  subtract: X0+XXz', Y0+YYz'  
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 