| Routines

2320: THE 'CIRCLE' COMMAND ROUTINE

The address of this routine is found in the parameter table. This routine draws an approximation to the circle with centre co-ordinates X and Y and radius Z. These numbers are rounded to the nearest integer before use. Thus Z must be less than 87.5, even when (X,Y) is in the centre of the screen. The method used is to draw a series of arcs approximated by straight lines. CIRCLE has four parts: i. Tests the radius. If its modulus is less than 1, just plot X,Y. ii. Calls CD_PRMS1, which is used to set the initial parameters for both CIRCLE and DRAW. iii. Sets up the remaining parameters for CIRCLE, including the initial displacement for the first 'arc' (a straight line in fact). iv. Jumps to DRW_STEPS to use the arc-drawing loop. Parts i. to iii. will now be explained in turn. i. The radius, say Z', is obtained from the calculator stack. Its modulus Z is formed and used from now on. If Z is less than 1, it is deleted from the stack and the point X,Y is plotted by a jump to PLOT.
CIRCLE | 2320 | RST $18 | Get the present character.
| 2321 | CP "," | Test for comma.
| 2323 | JP NZ,REPORT_C | If not so, report the error.
| 2326 | RST $20 | Get next character (the radius).
| 2327 | CALL CLASS_06 | Radius to calculator stack.
| 232A | CALL CHECK_END | Move to consider next statement if checking syntax.
| 232D | RST $28 | Use calculator.
| 232E | DEFB $2A | abs: X, Y, Z
| 232F | DEFB $3D | re_stack: Z is re-stacked; its exponent is therefore available.
| 2330 | DEFB $38 | end_calc
| 2331 | LD A,(HL) | Get exponent of radius.
| 2332 | CP $81 | Test whether radius less than 1.
| 2334 | JR NC,C_R_GRE_1 | If not, jump.
| 2336 | RST $28 | If less, delete it from the stack.
| 2337 | DEFB $02 | delete: X, Y
| 2338 | DEFB $38 | end_calc
| 2339 | JR PLOT | Just plot the point X, Y.
ii. 2π is stored in mem-5 and CD_PRMS1 is called. This subroutine stores in the B register the number of arcs required for the circle, viz. A=4*INT (π*SQR Z/4)+4, hence 4, 8, 12, etc., up to a maximum of 32. It also stores in mem-0 to mem-4 the quantities 2π/A, SIN(π/A), 0, COS (2π/A) and SIN (2π/A).
C_R_GRE_1 | 233B | RST $28 |
| 233C | DEFB $A3 | stk_pi_2: X, Y, Z, π/2
| 233D | DEFB $38 | end_calc
| 233E | LD (HL),$83 | Now increase exponent to +83, changing π/2 into 2π.
| 2340 | RST $28 | X, Y, Z, 2π.
| 2341 | DEFB $C5 | st_mem_5: (2π is copied to mem-5)
| 2342 | DEFB $02 | delete: X, Y, Z
| 2343 | DEFB $38 | end_calc
| 2344 | CALL CD_PRMS1 | Set the initial parameters.
iii. A test is made to see whether the initial 'arc' length is less than 1. If it is, a jump is made simply to plot X, Y. Otherwise, the parameters are set: X+Z and X-Z*SIN (π/A) are stacked twice as start and end point, and copied to COORDS as well; zero and 2*Z*SIN (π/A) are stored in mem-1 and mem-2 as initial increments, giving as first 'arc' the vertical straight line joining X+Z, y-Z*SIN (π/A) and X+Z, Y+Z*SIN (π/A). The arc-drawing loop at DRW_STEPS will ensure that all subsequent points remain on the same circle as these two points, with incremental angle 2π/A. But it is clear that these 2 points in fact subtend this angle at the point X+Z*(1-COS (π/A)), Y not at X, Y. Hence the end points of each arc of the circle are displaced right by an amount 2*(1-COS (π/A)), which is less than half a pixel, and rounds to one pixel at most.
| 2347 | PUSH BC | Save the arc-count in B.
| 2348 | RST $28 | X, Y, Z
| 2349 | DEFB $31 | duplicate: X, Y, Z, Z
| 234A | DEFB $E1 | get_mem_1: X, Y, Z, Z, SIN (π/A)
| 234B | DEFB $04 | multiply: X, Y, Z, Z*SIN (π/A)
| 234C | DEFB $38 | end_calc
| 234D | LD A,(HL) | Z*SIN (π/A) is half the initial 'arc' length; it is tested to see whether it is less than 0.5.
| 234E | CP $80
| 2350 | JR NC,C_ARC_GE1 | If not, the jump is made.
| 2352 | RST $28 |
| 2353 | DEFB $02 | delete: X, Y, Z
| 2354 | DEFB $02 | delete: X, Y
| 2355 | DEFB $38 | end_calc
| 2356 | POP BC | Clear the machine stack.
| 2357 | JP PLOT | Jump to plot X, Y.
C_ARC_GE1 | 235A | RST $28 | X, Y, Z, Z*SIN (π/A)
| 235B | DEFB $C2 | st_mem_2: (Z*SIN (π/A) to mem-2 for now)
| 235C | DEFB $01 | exchange: X, Y, Z*SIN (π/A), Z
| 235D | DEFB $C0 | st_mem_0: X, Y, Z*SIN (π/A), Z (Z is copied to mem-0)
| 235E | DEFB $02 | delete: X, Y, Z*SIN (π/A)
| 235F | DEFB $03 | subtract: X, Y-Z*SIN (π/A)
| 2360 | DEFB $01 | exchange: Y-Z*SIN (π/A), X
| 2361 | DEFB $E0 | get_mem_0: Y-Z*SIN (π/A), X, Z
| 2362 | DEFB $0F | addition: Y-Z*SIN (π/A), X+Z
| 2363 | DEFB $C0 | st_mem_0: (X+Z is copied to mem-0)
| 2364 | DEFB $01 | exchange: X+Z, Y-Z*SIN (π/A)
| 2365 | DEFB $31 | duplicate: X+Z, Y-Z*SIN (π/A), Y-Z*SIN (π/A)
| 2366 | DEFB $E0 | get_mem_0: sa, sb, sb, sa
| 2367 | DEFB $01 | exchange: sa, sb, sa, sb
| 2368 | DEFB $31 | duplicate: sa, sb, sa, sb, sb
| 2369 | DEFB $E0 | get_mem_0: sa, sb, sa, sb, sb, sa
| 236A | DEFB $A0 | stk_zero: sa, sb, sa, sb, sb, sa, 0
| 236B | DEFB $C1 | st_mem_1: (mem-1 is set to zero)
| 236C | DEFB $02 | delete: sa, sb, sa, sb, sb, sa
| 236D | DEFB $38 | end_calc
(Here sa denotes X+Z and sb denotes Y-Z*SIN (π/A).)
| 236E | INC (IY+$62) | Incrementing the exponent byte of mem-2 sets mem-2 to 2*Z*SIN(π/A).
| 2371 | CALL FIND_INT1 | The last value X+Z is moved from the stack to A and copied to L.
| 2374 | LD L,A
| 2375 | PUSH HL | It is saved in HL.
| 2376 | CALL FIND_INT1 | Y-Z*SIN (π/A) goes from the stack to A and is copied to H. HL now holds the initial point.
| 2379 | POP HL
| 237A | LD H,A
| 237B | LD ($5C7D),HL | It is copied to COORDS.
| 237E | POP BC | The arc-count is restored.
| 237F | JP DRW_STEPS | The jump is made to DRW_STEPS.
(The stack now holds X+Z, Y-Z*SIN (π/A), Y-Z*SIN (π/A), X+Z.)