Routines |
Prev: 2320 | Up: Map | Next: 247D |
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:
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 | 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:
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 |