.........1.........2.........3.........4.........5.........6.........7.........8

LIGHT SCREEN DESIGNER
ZX Computing, October/November 1985
Part 08 of 13


Before I start on this article, I'd like to point out one error which
occurred in the last issue. It's in the CALC_CENTRE routine - in fact
it's the very last instruction in this routine. The instruction
currently reads E9 - JP (HL). This is incorrect. It should read C9 -
RET. The byte occurs at location E12F. You can cure this error in
BASIC by typing POKE 57647,201.

This article is all about ARCs. An arc is a curved line which is, in
fact, a portion of a circle. In BASIC you can draw an arc using the
DRAW statement. In our program we'll be able to do it in three
different ways - take a look at Figure One [PART08.GIF]. The first
option, ARC_RAD, is the same as in BASIC. It draws an arc from the
origin cursor to the main cursor, and the angle through which the arc
turns must be specified separately - in this case it must be INPUT.
The remaining two options are different. ARC_USING again draws an arc
from the origin to the main cursor, but this time the centre of
curvature must be specified with the marker cursor. Finally, ARC_THRU
draws an arc from the origin, through the marker, and onto the main
cursor. Note that all arcs are drawn anticlockwise.

You should be aware of the shortcomings of the routines. Consider
ARC_USING for instance. For it to work properly, the centre of
curvature should lie on an imaginary line dividing the other two
points. If you specify a centre a long way from this imaginary line
then you may not get what you expect. Remember also, that the arc is
drawn anticlockwise - this means that if you get the main and origin
cursors the wrong way round you'll also not get what you expect. For
ARC_THRU to work properly, the cursors should be the right way round -
first the origin cursor, then the marker cursor, then the main cursor
- in an anticlockwise curve. If you don't do this then the program
will try to draw an anticlockwise curve from the origin cursor to the
main cursor, along an imaginary circle which passes through all three
points. Finally I should add that ARC_THRU will not work if the three
points are in a straight line (this is because it is then impossible
to consider an imaginary circle passing through all three points).

The machine code in this article involves a lot of useful stuff - one
particular example of which could be very, very, useful in other
programs. It's a subroutine located at address E168, called
INPUT_ITEM. It needs the subroutine CHECK_INPUT (here at address E14E)
in order for it to work, but bearing that in mind it may stand alone.
Its purpose is to simulate the BASIC INPUT statement. It can also
supply a "help" prompt. I can demonstrate this best by example. If you
type INPUT A or INPUT LINE A$ you don't get any kind of help at all -
just a 'C' cursor. If you type INPUT A$ however, you get two sets of
quotes, with the 'C' cursor between the quotes. This "quote quote"
string is what I mean by a help prompt. A help prompt may be any
sequence of characters which is supplied for you as part of the input
string. The subroutine may be called providing that the registers A,
B, C, and HL are properly initialised. A must contain A0 (INPUT LINE
string), 20 (INPUT string), or 60 (INPUT number); C must contain the
number of characters in any help prompt (or one, if there is no
prompt); B must contain the position within the prompt of the 'C'
cursor, plus one (or one, if there is no prompt); HL is a pointer
which must contain the address of an "enter" character, which must be
the last byte of a prompt string, if one exists. For an example of
this, watch the way in which the subroutine is called in this article.

There is also a useful subroutine at address E248 called CALC_FN,
which executes a single calculator instruction (held in the B
register) without corrupting the calculator's memories.

To make the routines given in this article work it is necessary to
incorporate their addresses into the command addresses table. The
necessary modifications are shown in Figure 2.

-----------------------------------------------------------------------------
Figure 2. Modifications to the command addresses table.

DB4C 29E2               DEFW E229,ARC_RAD   (DRAW_ARC_RAD)
DB5C A5E2               DEFW E2A5,ARC_USING (DRAW_ARC_USING)
DB6C C5E2               DEFW E2C5,ARC_THRU  (DRAW_ARC_THRU)
-----------------------------------------------------------------------------

A few words of explanation on some of the other subroutines given
here. ANGLE (at address E265) calculates an angle. It effectively
draws an imaginary line from the centre of curvature to either the
origin or the main cursor, and calculates the angle between this line
and the horizontal. SWAP_MEMS (E296) exchanges the origin cursor with
the main cursor within the calculator memories.

The Light Screen Designer series is now almost complete - the eleventh
part will be the final part [Actually, the thirteenth part was the
final part. JimG]. In the next issue I shall concentrate on the TEXT
option - writing messages onto the screen. I leave you now with this
month's programs.

-----------------------------------------------------------------------------
E14E 2A615C   CHK_INPUT LD   HL,(WORKSP)   ;Point CH_ADD to the start of
E151 225D5C             LD   (CH_ADD),HL   ;the INPUT string
E154 CDFB24             CALL SCANNING      ;Evaluate or check the expression
E157 3A3B5C             LD   A,(FLAGS)
E15A FD5637             LD   D,(FLAGX)     ;Check that the type of input
E15D AA                 XOR  D             ;(numeric or string) matches
E15E E640               AND  #40           ;that expected
E160 2004               JR   NZ,INP_WRONG  ;Jump if not
E162 DF                 RST  #18           ;A= byte following expression
E163 FE0D               CP   "enter"       ;Return provided that the
E165 C8                 RET  Z             ;byte is "enter"
E166 CF       INP_WRONG RST  #08           ;Use the error handling routine
E167 0B                 DEFB #0B           ;to generate a flashing "?"

E168 E5       INPUT_ITM PUSH HL            ;Stack the registers
E169 C5                 PUSH BC
E16A F5                 PUSH AF
E16B AF                 XOR  A             ;A= 0
E16C CD0116             CALL CHAN_OPEN     ;Select channel zero (lower screen)
E16F ED5B615C           LD   DE,(WORKSP)
E173 2A635C             LD   HL,(STKBOT)   ;Clear the workspace without
E176 CDE519             CALL RECLAIM_1     ;destroying the calculator stack
E179 21715C             LD   HL,FLAGX
E17C 7E                 LD   A,(HL)        ;A= (FLAGX)
E17D E61F               AND  #1F           ;Clear bits relating to INPUT
E17F C1                 POP  BC            ;B= new values for FLAGX bits
E180 B0                 OR   B
E181 77                 LD   (HL),A        ;Assign new bits of (FLAGX)
E182 C1                 POP  BC            ;C= length of INPUT prompt
E183 C5                 PUSH BC
E184 0600               LD   B,#00
E186 F7                 RST  #30           ;Create sufficient room in workspace
E187 F1                 POP  AF            ;A= position of "C" cursor
E188 D1                 POP  DE            ;DE points to last byte of prompt
E189 EB                 EX   DE,HL
E18A EDB8               LDDR               ;Store prompt message in workspace
E18C 13       I_PR_LOOP INC  DE
E18D 3D                 DEC  A
E18E 20FC               JR   NZ,I_PR_LOOP
E190 ED535B5C           LD   (K_CUR),DE    ;Store position of "C" cursor
E194 FDCB377E           BIT  7,(FLAGX)
E198 2026               JR   NZ,I_LINE_1   ;Jump if doing INPUT LINE
E19A 2A5D5C             LD   HL,(CH_ADD)   ;Stack two of the system variables
E19D E5                 PUSH HL
E19E 2A3D5C             LD   HL,(ERR_SP)
E1A1 E5                 PUSH HL
E1A2 21A2E1   IERRORRET LD   HL,IERRORRET  ;Return here in case of
E1A5 E5                 PUSH HL            ;syntax error
E1A6 ED733D5C           LD   (ERR_SP),SP
E1AA 2A615C             LD   HL,(WORKSP)   ;HL points to INPUT string
E1AD CDA711             CALL REMOVE_FP     ;Remove any five-byte-forms
E1B0 FD3600FF           LD   (ERR_NR),#FF  ;Cancel any syntax error
E1B4 CD2C0F             CALL EDITOR        ;Input the expression
E1B7 FDCB01BE           RES  7,(FLAGS)     ;Signal "checking syntax"
E1BB CD4EE1             CALL CHK_INPUT     ;Check for syntax errors
E1BE 1803               JR   I_CONT
E1C0 CD2C0F   I_LINE_1  CALL EDITOR        ;Input the LINE string
E1C3 FD362200 I_CONT    LD   (K_CUR hi),#00;Cancel the "C" cursor
E1C7 CD1D11             CALL ED_COPY       ;Print input string in lower screen
E1CA ED4B825C           LD   BC,(ECHO_E)   ;BC= coords of last byte
                                           ;in lower part of screen
E1CE CDD90D             CALL CL_SET        ;Store this as print position
E1D1 21715C             LD   HL,FLAGX
E1D4 CBAE               RES  5,(HL)        ;Signal "edit mode"
E1D6 CB7E               BIT  7,(HL)
E1D8 CBBE               RES  7,(HL)        ;Cancel any INPUT LINE flag
E1DA 201C               JR   NZ,I_LINE_2   ;Jump if INPUT LINE
E1DC E1                 POP  HL            ;Cancel IERRORRET address
E1DD E1                 POP  HL
E1DE 223D5C             LD   (ERR_SP),HL   ;Restore error pointer
E1E1 E1                 POP  HL
E1E2 225F5C             LD   (X_PTR),HL    ;Store CH_ADD temporarily in X_PTR
E1E5 FDCB01FE           SET  7,(FLAGS)     ;Signal "evaluating"
E1E9 CD4EE1             CALL CHK_INPUT     ;Evaluate the expression
E1EC 2A5F5C             LD   HL,(X_PTR)
E1EF FD362600           LD   (X_PTR hi),#00;Cancel X_PTR
E1F3 225D5C             LD   (CH_ADD),HL   ;Restore CH_ADD to its former value
E1F6 180F               JR   I_EXIT
-----------------------------------------------------------------------------
E1F8 2A635C   I_LINE_2  LD   HL,(STKBOT)
E1FB ED5B615C           LD   DE,(WORKSP)
E1FF 37                 SCF
E200 ED52               SBC  HL,DE         ;HL= length of INPUT LINE string
E202 44                 LD   B,H
E203 4D                 LD   C,L
E204 CDB22A             CALL STK_STO_$     ;Stack onto calculator stack
E207 C36E0D   I_EXIT    JP   CLS_LOWER     ;Empty the lower part of the 
                                           ;screen and return

E20A ED4B0EDB STARTLINE LD   BC,(ORIGIN+2) ;BC= coords of origin cursor
E20E CDEADE             CALL ADJUST_B      ;Adjust to ROM convention
E211 ED437D5C           LD   (COORDS),BC   ;Store as "last point plotted"
E215 C3A0E0             JP   GETCURSOR     ;Get cursor coordinates into
                                           ;calculator memories and return
-----------------------------------------------------------------------------
E218 CD0AE2   ARC_START CALL STARTLINE     ;Prepare to start arc
E21B EF                 RST  #28           ;Activate the calculator
E21C E5                 recall M5          Cx
E21D E1                 recall M1          Cx,Ox
E21E 03                 subtract           Cx-Ox
E21F E4                 recall M4          Cx-Ox,Cy
     E0                 recall M0          Cx-Ox,Cy,Oy
     03                 subtract           Cx-Ox,Cy-Oy
E222 38                 end calc           ;These are the first two
E223 C9                 RET                ;DRAW parameters

E224 28292A   ARC_HELP
     A70D               DEFM ()*PI
-----------------------------------------------------------------------------
E229 C5       ARC_RAD   PUSH BC            ;Stack cursor coordinates
E22A CD18E2             CALL ARC_START     ;Initialise calculator
E22D CDCCDC             CALL MESSAGE       ;Print prompt message in
E230 07                 DEFB #07           ;lower part of screen
E231 CDB6DD             CALL DRCURSORS     ;Draw cursors on screen
E234 3E60               LD   A,#60         ;Signal "input number"
E236 010502             LD   BC,#0205      ;B= position of "C" cursor
                                           ;C= length of help prompt
E239 2128E2             LD   HL,ARC_HELP+4
E23C CD68E1             CALL INPUT_ITM     ;Input number of radians
E23F CDB6DD             CALL DRCURSORS     ;Erase cursors from screen
E242 CD9423   ARC_END   CALL DRAW_ARC      ;Draw the arc
E245 C399E0             JP   CC_MOVE       ;Move the origin cursor and return

E248 C5       CALC_FN   PUSH BC
E249 011E00             LD   BC,#001E
E24C F7                 RST  #30           ;Make room in the workspace
E24D 11E3FF             LD   DE,#FFE3
E250 19                 ADD  HL,DE         ;HL points to start of space
E251 22685C             LD   (MEMBOT),HL   ;Use space as calculator memory
E254 C1                 POP  BC            ;B= calculator function code
E255 EF                 RST  #28           ;Use calculator to carry out
E256 3B38               DEFB #3B,#38       ;required function
E258 ED5B615C           LD   DE,(WORKSP)
E25C 2A635C             LD   HL,(STKBOT)
E25F CDE519             CALL RECLAIM_1     ;Reclaim memory just used
E262 C3CB16             JP   SET_STK+6     ;Restore original memory
-----------------------------------------------------------------------------
E265 EF       ANGLE     RST  #28           ;Engage the calculator
E266 A3                 const pi/2         PI/2
E267 E4                 recall M4          PI/2,Cy
     E2                 recall M2          PI/2,Cy,My
     03                 substract          PI/2,Cy-My
E26A 36                 lt zero            PI/2,Cy<My?
     30                 not                PI/2,Cy>=My?
E26C 0002               jump true ANGLE_1  PI/2
E26E 1B                 negate             -PI/2
E26F E5       ANGLE_1   recall M5          1PI/2,Cx
E270 E3                 recall M3          1PI/2,Cx,Mx
E271 03                 subtract           1PI/2,Cx-Mx
E272 30                 eq zero            1PI/2,Cx=Mx?
     001D               jump true ANGLE_3  1PI/2
E275 E4                 recall M4          1PI/2,Cy
     E2                 recall M2          1PI/2,Cy,My
     03                 subtract           1PI/2,Cy-My
E278 E5                 recall M5          1PI/2,Cy-My,Cx
E279 E3                 recall M3          1PI/2,Cy-My,Cx,Mx
E27A 03                 subtract           1PI/2,Cy-My,Cx-Mx
E27B 05                 divide             c
E27C 38                 end calc
E27D 0624               LD B,"atn"         ;Calculator code for ATN
E27F CD48E2             CALL CALC_FN       1PI/2,ATN((Cy-My)/(Cx-Mx))
E282 EF                 RST  #28
E283 E5                 recall M5          1PI/2,ATN((Cy-My)/(Cx-Mx)),Cx
E284 E3                 recall M3          1PI/2,ATN((Cy-My)/(Cx-Mx)),Cx,Mx
E285 03                 subtract           1PI/2,ATN((Cy-My)/(Cx-Mx)),Cx-Mx
E286 36                 lt zero            1PI/2,ATN((Cy-My)/(Cx-Mx)),Cx<Mx?
     0005               jump true ANGLE_2  1PI/2,ATN((Cy-My)/(Cx-Mx))
E289 01                 exchange           ATN((Cy-My)/(Cx-Mx)),1PI/2
     02                 delete             ATN((Cy-My)/(Cx-Mx))
     3305               jump ANGLE_3
E28D 01       ANGLE_2   exchange           ATN((Cy-My)/(Cx-Mx)),1PI/2
     31                 duplicate          ATN((Cy-My)/(Cx-Mx)),1PI/2,1PI/2
     0F                 add                ATN((Cy-My)/(Cx-Mx)),1PI
E290 0F                 add                ATN((Cy-My)/(Cx-Mx))1PI
E291 38                 end calc
E292 C9                 RET
-----------------------------------------------------------------------------
E293 CD65E2   ANGLESWAP CALL ANGLE         ;Calculate angle
E296 EF       SWAP_MEMS RST  #28           ;Use the calculator
E297 E0                 recall M0          Oy
E298 E1                 recall M1          Oy,Ox
E299 E4                 recall M4          Oy,Ox,Cy
     E5                 recall M5          Oy,Ox,Cy,Cx
     C1                 store M1           (M1 now stores Cx)
E29C 02                 delete             Oy,Ox,Cy
E29D C0                 store M0           (M0 now stores Cy)
E29E 02                 delete             Oy,Ox
E29F C5                 store M5           (M5 now stores Ox)
E2A0 02                 delete             Oy
E2A1 C4                 store M4           (M4 now stores Oy)
     02                 delete
     38                 end calc
E2A4 C9                 RET
-----------------------------------------------------------------------------
E2A5 CD22E0   ARC_USING CALL TEST_MRKR     ;Return if marker not active
E2A8 C5                 PUSH BC            ;Stack coordinates
E2A9 CD18E2             CALL ARC_START     ;Initialise calculator
E2AC CD93E2   ARC_US_2  CALL ANGLESWAP     ;Calculate main cursor angle
E2AF CD93E2             CALL ANGLESWAP     ;Calculate origin cursor angle
E2B2 EF                 RST  #28           ;Activate the calculator
E2B3 03                 subtract           X,Y,Ac-Ao
E2B4 31                 duplicate          X,Y,Ac-Ao,Ac-Ao
     37                 gt zero            X,Y,Ac-Ao,Ac>Ao?
     0007               jump true ARC_US_3 X,Y,Ac-Ao
E2B8 A3                 const pi/2         X,Y,Ac-Ao,PI/2
E2B9 38                 end calc
E2BA 34                 INC  (HL)          X,Y,Ac-Ao,PI
E2BB 34                 INC  (HL)          X,Y,Ac-Ao,2*PI
E2BC EF                 RST  #28
E2BD 0F                 add                X,Y,Ac-Ao+2*PI
E2BE 38       ARC_US_3  end calc           ;Calculator stack now contains
                                           ;DRAW parameters
E2BF CD38DF             CALL CANCEL_MK     ;Cancel marker cursor
E2C2 C342E2             JP   ARC_END

E2C5 CD22E0   ARC_THRU  CALL TEST_MRKR     ;Return if marker not in use
E2C8 C5                 PUSH BC            ;Stack cursor coordinates
E2C9 CD18E2             CALL ARC_START     ;Initialise calculator
E2CC CDF8E0             CALL CALC_CENT     ;Calculate centre of curvature
E2CF CDA0E0             CALL GETCURSOR     ;Restore calculator memories
E2D2 111400             LD   DE,#0014
E2D5 19                 ADD  HL,DE
E2D6 22655C             LD   (STKEND),HL   ;Restore calculator stack
E2D9 EF                 RST  #28           X,Y,centre_x,centre_y
E2DA C2                 store M2           (M2 now stores centre_y)
     02                 delete             X,Y,centre_x
     C3                 store M3           (M3 now stores centre_x)
E2DD 02                 delete             X,Y
E2DE 38                 end calc
E2DF 18CB               JR   ARC_US_2
-----------------------------------------------------------------------------
