TECHNICAL GRAPHICS
by Toni Baker
part 1 of 3, ZX Computing January 1987

Toni Baker begins a new graphics series on line drawing	techniques.


Welcome to a new graphics series. The purpose of this series is to
explore the technical possibilities of line drawings. With line
drawings we can draw three dimensional objects such as the animated
figure which was featured in last month's ZX Computing. In this series
we shall keep things nice and simple. We will cover the principles of
three dimensional drawing, but we won't attempt to do complicated
things like removing hidden detail or shading in according to the
light - that is something for perhaps a future series to cover.


Clipping

The first article is intended to cover the principles of clipping. You
see, we have to start at the beginning. In order to do any line
drawing at all, we must be able to draw straight lines. The DRAW
statement in BASIC will draw a straight line successfully provided
that the whole of the line will fit on the screen. Now suppose that
the line will not fit on the screen - for instance PLOT 20,20 followed
by DRAW 250,250. If you were to try out this example you'd get the
error report "B Integer out of range" and the program would stop
running. It would be useful, therefore, to have a routine which would
draw only that part of the line which lies within the screen area.

This idea is called "clipping", because a portion of the line at one
or both ends will be "clipped" and the line will be shortened. It is
of course possible that the entire line will be outside of the screen
area, and should be "clipped" away altogether - ie. nothing at all
would be drawn on the screen.

Let's see how this idea of clipping works. Take a look at Figure 1
[TECH1_1.GIF]. The rectangle represents the screen area. Suppose we
want to draw a line from point (P1,Q1) to point (P2,Q2), as shown in
the diagram. To clip the line we have to move both end-points closer
together, until the line segment will fit on the screen. This is done
in four stages. First we find the point (P1',Q1'), which is the point
where the line meets the vertical edge of the screen, and then we find
the point (P1",Q1"), which is the point where the line meets the
horizontal edge of the screen. In the same way we move the point
(P2,Q2) first of all to (P2',Q2') and finally to (P2",Q2"). You can
see that the line segment from (P1",Q1") to (P2",Q2") lies wholly
within the screen and may be drawn normally.

The same principle will work even if the line we wish to clip is not
in exactly the position shown in Figure 1. Wherever (P1,Q1) lies, we
must first calculate (PI',Q1') which will move the point to the
nearest vertical edge only if the point is to the left or to the right
of the screen (otherwise leave it where it is); then we can calculate
(P1",Q1") by moving the point if necessary (i. if it is above or below
the screen) to the nearest horizontal edge.

Special provision must be made for lines which are entirely outside
the screen. If both end- points lie to the left of the screen then the
whole of the line is also to the left of the screen, and need not be
drawn. This is also true if both end-points are to the right of the
screen, or if both end-points are above the screen, or if both
end-points are below the screen. In each of these cases the line is
clipped away completely, and nothing should be drawn at all.

There are other positions of line which lie entirely outside the
screen area, and these ore more difficult to detect. Figure 2
[TECH1_23.GIF] shows examples of this kind of line. If the only thing
you know about such a line are the coordinates of the end-points then
it is remarkably difficult for a program to work out whether the line
will or will not intersect the screen. Fortunately, the way round the
problem is very simple. All you have to do is to work out P (P1",Q1")
and (P2",Q2") using the algorithm above, and if any of the
co-ordinates is still outside the screen area then the line should not
be drawn.


Getting around

Circles may be drawn by actually drawing a number of very small line
segments which give the illusion of a continuous curve. In other
words, instead of drawing a circle, we actually draw a many-sided
regular polygon. The greater the number of sides, the closer the
result is to a circle. The number of sides should ideally be a
multiple of four, so that the finished result will be symmetrical. The
number you need for any given radius turns out to be roughly PI*SQR(R)
where R is the radius - this works well with the resolution possible
on the Spectrum. If we now subject each side of the polygon to the
clipping algorithm, so that it will not be drawn if it lies off the
screen, or so that only part of it will be drawn if it crosses the
screen edge, then you will find that the result is a clipped circle,
whereby only that part of the circle which falls on the screen area
will be drawn, and the rest will be ignored.

Extending the principle just a little further, we can use the same
idea to draw other types of curve than just circles. I have included a
routine which will in fact drawn an ellipse - a sort of squashed
circle. Since a circle is in fact a special form of ellipse then the
same routine will also draw circle.

Although all of the routines are in machine code, I have included some
codes which will allow the routines to be used in BASIC. To draw a
clipped line whose end-points are (P1,Q1) and (P2,Q2) then you may use
the BASIC statement: RANDOMIZE FN S(P1,Q1,P2,Q2)

To draw a clipped circle whose centre coordinates (X,Y) and whose
radius is R, then use the BASIC statement: RANDOMIZE FN C(X,Y,R)

And finally, to draw a clipped ellipse you need five parameters.
Use: RANDOMIZE FN E(X,Y,R,E,A)

The parameter list is exactly the same as that on the QL. X and Y are
the co-ordinates of the centre of the ellipse. R is the smaller
radius, and E (which I've assumed to be greater than one) is the ratio
of the larger to the smaller radius, A is the angle (in radians) which
the larger radius makes with the horizontal. Figure 3 [TECH1_23.GIF]
shows how all these parameters fit together to define a full ellipse.
Note that if E is less than one then for "larger" read "smaller" and
vice versa in the above description. Note also that if E equals one
then the "ellipse" will actually be a circle.

The program makes use of twenty calculator memories (ten for the
clipping routine, and ten more which deal with ellipse drawing). Since
the calculator only has six memories built in then it is necessary to
create the extra memory in the workspace using the RST 30 instruction,
and then point the system variable (MEM) to this memory. (MEM) should
be returned to its normal value of 5C92 at the end of the routine, and
this is done at the label FN_EXIT near the end of the machine code
program. The actual usage of these memories is detailed in Figure 4.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Figure 4

M0   X1      X coordinate of start of line - 127.5
M1   Y1      Y coordinate of start of line - 87.5
M2   X2      X coordinate of end of line - 127.5
M3   Y2      Y coordinate of end of line - 87.5
M4   S1      -1, 0 or 1; if X1 is left of, on, or right of screen respectively
M5   T1      -1, 0 or 1; if Y1 is below, on, or above screen respectively
M6   S2      -1, 0 or 1; if X2 is left of, on, or right of screen respectively
M7   T2      -1, 0 or 1; if Y2 is below, on, or above screen respectively
M8   127.5   Half the width of the screen
M9   87.5    Half the height of the screen
MA   E*R     Half the major axis of ellipse
MB   R       Half the minor axis of ellipse
MC   COS(A)  )- Inclination of major axis to horizontal
MD   SIN(A)  )- Inclination of major axis to horizontal
ME   A1      Angle subtended "so far"
MF   INCR    Amount by which A1 is incremented on each pass
M10  P       X coordinate of point on ellipse
M11  Q       Y coordinate of point on ellipse
M12  X       X coordinate of centre of ellipse
M13  Y       Y coordinate of centre of ellipse
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Finally, there is included a BASIC program (Figure 5) which
demonstrates the clipping routines by drawing a rather nice pattern
out of lines, circles and ellipses, which are too large to fit on the
screen. Give it a run and see what you think.

In machine code, the main clipping routine is the routine labelled
CLIP at address 8052, which requires P1,Q1,P2,Q2 at the top of the
calculator stack, in that order. The routine ELLIPSE at address 811E
will draw an ellipse. It requires the parameters X,Y,R,E,A, in that
order, at the top of the calculator stack. The entry point from BASIC
will be either FN_SEGMENT (address 817B), FN_CIRCLE (address 8186) or
FN_ELLIPSE (address 8192), depending upon whether FN S, FN C, or FN E
were used.

In the next article in this series, we'll start taking a look at 3D,
beginning with isometric and other simple kinds of projection (don't
worry - it's easy). See you then.

PS. Thanks to M.P, Computers for the speedy repair of my microdrive unit.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Figure 5

  10 FOR i=0 TO PI STEP PI/20
  20 RANDOMIZE FN e(128,88,60,2,i)
  30 NEXT i
  40 FOR i=60 TO 120 STEP 20
  50 FOR j=0 TO 4
  60 LET a1=(2*j/5+.5)*PI
  70 LET a2=(2*(j+2)/5+.5)*PI
  80 RANDOMIZE FN s(128+i*COS a1,88+i*SIN a1,128+i*COS a2,88+i*SIN a2)
  90 NEXT j
 100 RANDOMIZE FN c(128,88,i)
 110 NEXT i
 120 DEF FN s(a,b,c,d)=USR 33147
 130 DEF FN c(x,y,r)=USR 33158
 140 DEF FN e(x,y,r,e,a)=USR 33170
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
8000 EF       CONVERT_X RST  #28           S
8001 E8                 recall M8          S,127.5
8002 04                 multiply           S*127.5
8003 31                 duplicate          S*127.5,S*127.5
     E0                 recall M0          S*127.5,S*127.5,X1
     03                 subtract           S*127.5,S*127.5-X1
8006 E3                 recall M3          S*127.5,S*127.5-X1,Y2
8007 E1                 recall M1          S*127.5,S*127.5-X1,Y2,Y1
8008 03                 subtract           S*127.5,S*127.5-X1,Y2-Y1
8009 04                 multiply           S*127.5,(S*127.5-X1)*(Y2-Y1)
800A E2                 recall M2          S*127.5,(S*127.5-X1)*(Y2-Y1),X2
     E0                 recall M0          S*127.5,(S*127.5-X1)*(Y2-Y1),X2,X1
     03                 subtract           S*127.5,(S*127.5-X1)*(Y2-Y1),X2-X1
800D 05                 divide             S*127.5,(S*127.5-X1)*(Y2-Y1)/(X2-X1)
800E E1                 recall M1          S*127.5,(S*127.5-X1)*(Y2-Y1)/(X2-X1),Y1
800F 0F                 add                S*127.5,Y1+(S*127.5-X1)*(Y2-Y1)/(X2-X1)
8010 01                 exchange           Y1+(S*127.5-X1)*(Y2-Y1)/(X2-X1),S*127.5
     38                 endcalc
8012 C9                 RET                ;Return from subroutine

8013 EF       CONVERT_Y RST  #28           T
8014 E9                 recall M9          T,87.5
8015 04                 multiply           T*87.5
8016 31                 duplicate          T*87.5,T*87.5
     E1                 recall M1          T*87.5,T*87.5,Y1
     03                 subtract           T*87.5,T*87.5-Y1
8019 E2                 recall M2          T*87.5,T*87.5-Y1,X2
     E0                 recall M0          T*87.5,T*87.5-Y1,X2,X1
     03                 subtract           T*87.5,T*87.5-Y1,X2-X1
801C 04                 multiply           T*87.5,(T*87.5-Y1)*(X2-X1)
801D E3                 recall M3          T*87.5,(T*87.5-Y1)*(X2-X1),Y2
801E E1                 recall M1          T*87.5,(T*87.5-Y1)*(X2-X1),Y2,Y1
801F 03                 subtract           T*87.5,(T*87.5-Y1)*(X2-X1),Y2-Y1
8020 05                 divide             T*87.5,(T*87.5-Y1)*(X2-X1)/(Y2-Y1)
8021 E0                 recall M0          T*87.5,(T*87.5-Y1)*(X2-X1)/(Y2-Y1),X1
8022 0F                 add                T*87.5,X1+(T*87.5-Y1)*(X2-X1)/(Y2-Y1)
8023 38                 endcalc
8024 C9                 RET                ;Return from subroutine

8025 2A685C   SETPARAMS LD   HL,(MEM)      ;HL points to calculator memories
8028 E5                 PUSH HL            ;Stack this address
8029 3E04               LD   A,#04         ;A= number of parameters to assign
802B 3D       SP_LOOP   DEC  A             ;Set Zero flag for final pass only
802C F5                 PUSH AF            ;Stack A register and Zero flag
802D F6E5               OR   #E5
802F 3C                 INC  A
8030 47                 LD   B,A           ;B= E8(1st&2nd pass) or E6(otherwise)
8031 EF                 RST  #28           ;Engage the calculator
8032 E0                 recall M0          X1
8033 31                 duplicate          X1,X1
     2A                 abs                X1,ABS(X1)
     3B                 execute B          X1,ABS(X1),127.5
8036 03                 subtract           X1,ABS(X1)-127.5
8037 37                 gt zero            X1,ABS(X1)>127.5?
8038 0003               jump true,SP_1     X1 (Jump if ABS(X1)>127.5)
803A 02                 delete
803B A0                 const zero         0
803C 29       SP_1      sgn                S1
803D C4                 store M4           (Memory M4 contains S1)
     02                 delete
     38                 endcalc
8040 2A685C             LD   HL,(MEM)      ;HL points to current memory base
8043 010500             LD   BC,#0005
8046 09                 ADD  HL,BC
8047 22685C             LD   (MEM),HL      ;Memory base now one memory higher up
804A F1                 POP  AF
804B 20DE               JR   NZ,SP_LOOP    ;Repeat four times.
;Note that on 2nd pass T1 is calculated from Y1, on 3rd pass S2 is calculated
;from X2, and on 4th pass T2 is calculated from Y2, because of the shift of
;memory base.
804D E1                 POP  HL
804E 22685C             LD   (MEM),HL      ;Restore memory base to M0
8051 C9                 RET                ;Return

8052 EF       CLIP      RST  #28           P1,Q1,P2,Q2
8053 34372F             stk data 87.5      P1,Q1,P2,Q2,87.5
8056 C9                 store M9           (Memory M9 contains 87.5)
8057 03                 subtract           P1,Q1,P2,Y2
8058 C3                 store M3           (Memory M3 contains Y2)
     02                 delete             P1,Q1,P2
     34377F             stk data 127.5     P1,Q1,P2,127.5
805D C8                 store M8           (Memory M8 contains 127.5)
805E 03                 subtract           P1,Q1,X2
805F C2                 store M2           (Memory M2 contains X2)
     02                 delete             P1,Q1
     E9                 recall M9          P1,Q1,87.5
8062 03                 subtract           P1,Y1
8063 C1                 store M1           (Memory M1 contains Y1)
8064 02                 delete             P1
8065 E8                 recall M8          P1,127.5
8066 03                 subtract           X1
8067 C0                 store M0           (Memory M0 contains X1)
8068 02                 delete
8069 38                 endcalc
806A CD2580             CALL SETPARAMS     ;Assign S1, T1, S2 and T2
806D EF                 RST  #28
806E E4                 recall M4          S1
     E6                 recall M6          S1,S2
     04                 multiply           S1*S2
8071 A1                 const one          S1*S2,1
8072 03                 subtract           S1*S2-1
8073 E5                 recall M5          S1*S2-1,T1
8074 E7                 recall M7          S1*S2-1,T1,T2
8075 04                 multiply           S1*S2-1,T1*T2
8076 A1                 const one          S1*S2-1,T1*T2,1
8077 03                 subtract           S1*S2-1,T1*T2-1
8078 04                 multiply           (S1*S2-1)*(T1*T2-1)
8079 38                 endcalc
807A CDD52D             CALL FP_TO_A       ;A= (S1*S2-1)*(T1*T2-1)
807D A7                 AND  A
807E C8                 RET  Z             ;Return if entire of line is above,
                                           ;below, or to one side of, the
                                           ;screen area
807F EF                 RST  #28
8080 E4                 recall M4          S1
     30                 eq zero            S1=0?
     0010               jump true,CLIP_1   Jump if S1=0
     E4                 recall M4          S1
8085 38                 endcalc
8086 CD0080             CALL CONVERT_X     Y1',X1'
8089 EF                 RST  #28           Y1',X1'
808A C0                 store M0           (Memory M0 contains X1')
808B 02                 delete             Y1'
808C C1                 store M1           (Memory M1 contains Y1')
808D 02                 delete
808E 38                 endcalc
808F CD2580             CALL SETPARAMS     ;Assign S1' and T1'
8092 EF                 RST  #28
8093 E5       CLIP_1    recall M5          T1'
8094 30                 eq zero            T1'=0?
     000B               jump true,CLIP_2   Jump if T1'=0
8097 E5                 recall M5          T1'
8098 38                 endcalc            T1'
8099 CD1380             CALL CONVERT_Y     Y1",X1"
809C EF                 RST  #28           Y1",X1"
809D C0                 store M0           (Memory M0 contains X1")
809E 02                 delete             Y1"
809F C1                 store M1           (Memory M1 contains Y1")
80A0 02                 delete
80A1 E6       CLIP_2    recall M6          S2
     30                 eq zero            S2=0?
80A3 0010               jump true,CLIP_3   Jump if S2=0
     E6                 recall M6          S2
80A6 38                 endcalc            S2
80A7 CD0080             CALL CONVERT_X     Y2',X2'
80AA EF                 RST  #28           Y2',X2'
80AB C2                 store M2           (Memory M2 contains X2')
     02                 delete             Y2'
     C3                 store M3           (Memory M3 contains Y2')
80AE 02                 delete
80AF 38                 endcalc
80B0 CD2580             CALL SETPARAMS     ;Assign S2' and T2'
80B3 EF                 RST  #28
80B4 E7       CLIP_3    recall M7          T2'
80B5 30                 eq zero            T2'=0?
     000B               jump true,CLIP_4   Jump if T2'=0
80B8 E7                 recall M7          T2'
80B9 38                 endcalc            T2'
80BA CD1380             CALL CONVERT_Y     Y2",X2"
80BD EF                 RST  #28           Y2",X2"
80BE C2                 store M2           (Memory M2 contains X2")
     02                 delete             Y2"
     C3                 store M3           (Memory M3 contains Y2")
80C1 02                 delete
80C2 38       CLIP_3    endcalc
80C3 CD2580             CALL SETPARAMS     ;Calculate S1", T1", S2" and T2"
80C6 EF                 RST  #28
80C7 E4                 recall M4          S1"
     E5                 recall M5          S1",T1"
     07                 or                 S1" OR T1"
80CA E6                 recall M6          S1" OR T1",S2"
     07                 or                 S1" OR T1" OR S2"
80CC E7                 recall M7          S1" OR T1" OR S2",T2"
80CD 07                 or                 S1" OR T1" OR S2" OR T2"
80CE 38                 endcalc            ;Switch off calculator
80CF CDD52D             CALL FP_TO_A       ;A= S1" OR T1" OR S2" OR T2"
80D2 A7                 AND  A
80D3 C0                 RET  NZ            ;Return if line still outside
                                           ;screen area
80D4 EF                 RST  #28           ;Switch on calculator
80D5 E2                 recall M2          X2"
     E8                 recall M8          X2",127.5
     A2                 const half         X2",127.5,0.5
80D8 0F                 add                X2",128
80D9 C8                 store M8           (Memory M8 contains 128)
80DA 0F                 add                X2"+128
80DB 27                 int                P2"
80DC C2                 store M2           (Memory M2 contains P2")
     E0                 recall M0          P2",X1"
     E8                 recall M8          P2",X1",128
80DF 0F                 add                P2",X1"+128
80E0 27                 int                P2",P1"
80E1 C0                 store M0           (Memory M0 contains P1")
80E2 03                 subtract           P2"-P1"
80E3 E3                 recall M3          P2"-P1",Y2"
80E4 E9                 recall M9          P2"-P1",Y2",87.5
80E5 A2                 const half         P2"-P1",Y2",87.5,0.5
80E6 0F                 add                P2"-P1",Y2",88
80E7 C9                 store M9           (Memory M9 contains 88)
80E8 0F                 add                P2"-P1",Y2"+88
80E9 27                 int                P2"-P1",Q2"
80EA C3                 store M3           (Memory M3 contains Q2")
     E1                 recall M1          P2"-P1",Q2",Y1"
     E9                 recall M9          P2"-P1",Q2",Y1",88
80ED 0F                 add                P2"-P1",Q2",Y1"+88
80EE 27                 int                P2"-P1",Q2",Q1"
80EF C1                 store M1           (Memory M1 contains Q1")
80F0 03                 subtract           P2"-P1",Q2"-Q1"
80F1 E0                 recall M0          P2"-P1",Q2"-Q1",P1"
80F2 E1                 recall M1          P2"-P1",Q2"-Q1",P1",Q1"
80F3 38                 endcalc
80F4 CDDC22             CALL PLOT          ;PLOT the first point of the line
80F7 C37724             JP   LINE_DRAW     ;DRAW the line segment, and return
80FA 00                 NOP
80FB 00                 NOP
80FC 00                 NOP                ;These three bytes unused

80FD EF       NXT_POINT RST  #28           ;Engage the calculator
80FE EA                 recall MA          E*R
     EE                 recall ME          E*R,A1
     20                 cos                E*R,COS(A1)
8101 04                 multiply           E*R*COS(A1)
8102 C8                 store M8           (Memory M8 contains E*R*COS(A1))
8103 EC                 recall MC          E*R*COS(A1),COS(A)
     04                 multiply           E*R*COS(A1)*COS(A)
     EB                 recall MB          E*R*COS(A1)*COS(A),R
8106 EE                 recall ME          E*R*COS(A1)*COS(A),R,A1
     1F                 sin                E*R*COS(A1)*COS(A),R,SIN(A1)
8108 04                 multiply           E*R*COS(A1)*COS(A),R*SIN(A1)
8109 C9                 store M9           (Memory M9 contains R*SIN(A1))
810A ED                 recall MD          E*R*COS(A1)*COS(A),R*SIN(A1),SIN(A)
810B 04                 multiply           E*R*COS(A1)*COS(A),R*SIN(A1)*SIN(A)
810C 03                 subtract           E*R*COS(A1)*COS(A)-R*SIN(A1)*SIN(A)
810D F2                 recall M12         E*R*COS(A1)*COS(A)-R*SIN(A1)*SIN(A),X
     0F                 add                X+E*R*COS(A1)*COS(A)-R*SIN(A1)*SIN(A)
     D0                 store M10          (Memory M10 contains P)
8110 02                 delete
8111 E8                 recall M8          E*R*COS(A1)
8112 ED                 recall MD          E*R*COS(A1),SIN(A)
8113 04                 multiply           E*R*COS(A1)*SIN(A)
8114 E9                 recall M9          E*R*COS(A1)*SIN(A),R*SIN(A1)
8115 EC                 recall MC          E*R*COS(A1)*SIN(A),R*SIN(A1),COS(A)
     04                 multiply           E*R*COS(A1)*SIN(A),R*SIN(A1)*COS(A)
     0F                 add                E*R*COS(A1)*SIN(A)+R*SIN(A1)*COS(A)
8118 F3                 recall M13         E*R*COS(A1)*SIN(A)+R*SIN(A1)*COS(A),Y
8119 0F                 add                Y+E*R*COS(A1)*SIN(A)+R*SIN(A1)*COS(A)
811A D1                 store M11          (Memory M11 contains Q)
811B 02                 delete
811C 38                 endcalc
811D C9                 RET                ;Return from subroutine

811E EF       ELLIPSE   RST  #28           X,Y,R,E,A
811F 31                 duplicate          X,Y,R,E,A,A
     20                 cos                X,Y,R,E,A,COS(A)
     CC                 store MC           (Memory MC contains COS(A))
8122 02                 delete             X,Y,R,E,A
8123 1F                 sin                X,Y,R,E,SIN(A)
8124 CD                 store MD           (Memory MD contains SIN(A))
     02                 delete             X,Y,R,E
     01                 exchange           X,Y,E,R
8127 CB                 store MB           (Memory MB contains R)
     04                 multiply           X,Y,E*R
8129 CA                 store MA           (Memory MA contains E*R)
     02                 delete             X,Y
     D3                 store M13          (Memory M13 contains Y)
812C 02                 delete             X
812D D2                 store M12          (Memory M12 contains X)
     02                 delete
     A0                 const zero         0
8130 CE                 store ME           (Memory ME contains zero)
     02                 delete
8132 EB                 recall MB          R
8133 2A                 abs                ABS(R)
     31                 duplicate          ABS(R),ABS(R)
     EA                 recall MA          ABS(R),ABS(R),E*R
8136 2A                 abs                ABS(R),ABS(R),ABS(E*R)
     03                 subtract           ABS(R),ABS(R)-ABS(E*R)
     37                 gt zero            ABS(R),ABS(R)>ABS(E*R)?
8139 0004               jump true,ELL_1    ABS(R) (Jump if ABS(R)>ABS(E*R))
813B 02                 delete
813C EA                 recall MA          E*R
     2A                 abs                ABS(E*R)
                                           (M = larger of ABS(R) or ABS(E*R))
     28       ELL_1     sqr                SQR(M)
813F A3                 const pi/2         SQR(M),PI/2
8140 04                 multiply           SQR(M)*PI/2
8141 38                 endcalc            SQR(M)*PI/2
8142 34                 INC  (HL)          SQR(M)*PI
8143 CDD52D             CALL FP_TO_A       ;A= SQR(M)*PI to nearest integer
8146 3806               JR   C,ELL_FC      ;Jump if SQR(M)*PI>255d
8148 E6FC               AND  #FC
814A C604               ADD  A,#04         ;A= no. of arcs needed for ellipse
814C 3002               JR   NC,ELL_DRAW   ;Jump if <256d
814E 3EFC     ELL_FC    LD   A,#FC         ;Use 252d arcs
8150 F5       ELL_DRAW  PUSH AF            ;Stack number of arcs needed
8151 CD282D             CALL STACK_A       ;Push onto calculator stack
8154 EF                 RST  #28           ARCS
8155 A3                 const pi/2         ARCS,PI/2
8156 38                 endcalc            ARCS,PI/2
8157 3683               LD   (HL),#83      ARCS,2*PI
8159 EF                 RST  #28           ARCS,2*PI
815A 01                 exchange           2*PI,ARCS
     05                 divide             2*PI/ARCS
     CF                 store MF           (Memory MF contains the amount by
                                           which the angle must be incremented
                                           at each pass)
815D 02                 delete
815E 38                 endcalc
815F CDFD80             CALL NXT_POINT     ;M10 contains P1 and M11 contains Q1
8162 C1                 POP  BC            ;B= ARCS
8163 C5       ELL_LOOP  PUSH BC
8164 EF                 RST  #28
8165 EE                 recall ME          A1
     EF                 recall MF          A1,INCR
8167 0F                 add                A1+INCR
8168 CE                 store ME           (Memory ME contains updated angle A1)
     02                 delete
816A F0                 recall M10         P1
816B F1                 recall M11         P1,Q1
816C 38                 endcalc            P1,Q1
816D CDFD80             CALL NXT_POINT     ;M10 contains P2 and M11 contains Q2
8170 EF                 RST  #28           P1,Q1
8171 F0                 recall M10         P1,Q1,P2
8172 F1                 recall M11         P1,Q1,P2,Q2
8173 38                 endcalc            P1,Q1,P2,Q2
8174 CD5280             CALL CLIP          ;Draw the line segment
8177 C1                 POP  BC            ;B= Arc count
8178 10E9               DJNZ ELL_LOOP      ;Loop back to draw entire of ellipse
817A C9                 RET                ;Return

817B 013200   FNSEGMENT LD   BC,#0032      ;BC= 5*10d
817E CDA681             CALL SET_UP        ;Create ten calculator memories, and
                                           ;push P1,Q1,P2,Q2 onto calc. stack
8181 CD5280             CALL CLIP          ;Draw the clipped line segment
8184 1815               JR   FN_EXIT       ;Jump to exit
8186 016400   FN_CIRCLE LD   BC,#0064      ;BC= 5*20d
8189 CDA681             CALL SET_UP        ;Create 20d calculator memories, and
                                           ;push X,Y,R onto calc. stack
818C EF                 RST  #28           X,Y,R
818D A1                 const one          X,Y,R,1
818E A0                 const zero         X,Y,R,1,0
818F 38                 endcalc
8190 1806               JR   FN_ELL_2      ;Jump to draw the clipped circle
8192 016400   FNELLIPSE LD   BC,#0064      ;BC= 5*20d
8195 CDA681             CALL SET_UP        ;Create 20d calculator memories, and
                                           ;push X,Y,R,E,A onto calc. stack
8198 CD1E81   FN_ELL_2  CALL ELLIPSE       ;Draw the ellipse (or circle)
819B 21925C   FN_EXIT   LD   HL,MEMBOT
819E 22685C             LD   (MEM),HL      ;Restore normal calulator memories
81A1 215827             LD   HL,#2758
81A4 D9                 EXX                ;HL'= 2758 to prevent system crash
81A5 C9                 RET                ;Return to BASIC

81A6 F7       SET_UP    RST  #30           ;Create space for calc. memories
81A7 ED53685C           LD   (MEM),DE      ;Move calc. memories accordingly
81AB 2A0B5C             LD   HL,(DEFADD)   ;HL points to first user-defined
                                           ;FN argument record
81AE 23       SU_LOOP   INC  HL
81AF 23                 INC  HL            ;HL points to next FN argument
81B0 CDB433             CALL STACK_NUM     ;Push this argument onto calc. stack
81B3 7E                 LD   A,(HL)
81B4 23                 INC  HL
81B5 FE2C               CP   #2C
81B7 28F5               JR   Z,SU_LOOP     ;Loop back if more arguments
81B9 C9                 RET                ;Return
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
