This program draws Bézier curves on screen by accepting a series of control-point coordinates from the user and computing the curve using the Bernstein polynomial basis. Up to 20 corner (control) points are supported, stored in arrays x() and y(). The curve is evaluated at 50 evenly spaced parameter values (controlled by variable a=50), calculating blending coefficients iteratively in array b() to avoid expensive factorial computation. Users can optionally overlay the polygonal control frame before rendering the smooth curve, and a menu system lets them list, edit, store, or re-render the current set of control points. POKEs to addresses 23730–23731 adjust a system variable, likely setting the printer buffer or similar system parameter.
Program Analysis
Program Structure
The program is organized around a top-level menu at line 40 that dispatches via a computed GO TO (f*100) at line 50, routing to one of four sections based on user input:
- Lines
100–190: Input mode — collect control points and trigger curve computation. - Lines
200–320: Alter mode — list, fix, or redraw control points (dispatched viaGO TO (200+h*30)). - Lines
400: Quit (STOP). - Lines
500–740: Subroutines — curve computation (510–640), draw routine (650–740), and coordinate validation (750–760).
A secondary menu at line 20 handles CLS, COPY (printer dump), or continuation, serving as a post-render hub before returning to the alter menu.
Bézier Curve Algorithm
The curve is computed using the Bernstein polynomial form of a Bézier curve. For n+1 control points, parameter j steps from 0 to 1 across a=50 sample points. The blending weights b(i) are built iteratively at line 560:
b(i+1) = (g-i)/i * j/(1-j) * b(i)
This recurrence relation avoids computing binomial coefficients directly and is numerically efficient in BASIC. The anchor points are set explicitly: c(1)=x(1), d(1)=y(1) and c(a)=x(g), d(a)=y(g), ensuring the curve passes exactly through the first and last control points.
Key Variables
| Variable | Purpose |
|---|---|
a | Number of curve sample points (50) |
g | Total number of control points entered |
n | g−1 (degree of the Bézier curve) |
x(i), y(i) | Control point coordinates (up to 20) |
b(i) | Bernstein blending weights at current parameter value |
c(e), d(e) | Computed curve point coordinates |
j | Parameter value along the curve (0 to 1) |
e | Loop index across sample points |
Notable Techniques
- Computed GO TO: Both
GO TO (f*100)at line50andGO TO (200+h*30)at line220act as jump tables, a common BASIC idiom for menu dispatch without long IF-THEN chains. - Iterative Bernstein weights: Rather than computing each binomial coefficient from scratch, the recurrence at line
560builds the next weight from the previous, reducing computation significantly for higher-degree curves. - Coordinate validation subroutine: Lines
750–760enforce screen bounds (x: 0–255, y: 0–175) via a loop with an INPUT prompt, preventing PLOT from receiving out-of-range values that would cause an error. - Frame + curve toggle: Lines
650–700optionally draw the polygonal control hull using PLOT/DRAW before the sampled curve points are plotted, giving the user a visual reference for the control structure. - INK 7 / INK 0 toggling: Lines
290,300, and320toggle ink color aroundPLOTcalls usingUSR 26727andUSR 26715— these USR calls with PLOT are suspicious and may be intended as machine code calls or are bugs resulting from a misuse of USR in a PLOT context. - System variable POKEs:
POKE 23730,30: POKE 23731,231at line10writes to the ZX Spectrum system area (RASP/PIP area or similar), likely adjusting a system parameter at startup.
Bugs and Anomalies
- Lines
290,300, and320usePLOT 175,USR 26727andPLOT 175,USR 26715.USRin this context calls a machine code routine and returns a value, so these PLOT statements would plot at coordinates derived from the machine code return value — almost certainly not the intended behavior. These lines may be remnants of an unfinished or ported section. - Line
200dispatches withGO TO (200+h*30)for values 1–4, targeting lines230,260,290, and320respectively. However, the “old” option (h=3) lands at line290and the “both” option (h=4) at line320, both of which contain the suspicious PLOT/USR constructs noted above. - In the Bernstein weight loop (line
560), ifj=1(i.e.,1-j=0), a division by zero would occur. This is avoided in practice because the loop runs frome=2 TO a-1, sojnever actually reaches 1; the endpoints are set manually. - The
b()array is dimensioned to 20 at line10but is indexed up ton+1(equal tog), so the limit of 20 control points is consistent with the array bounds.
Content
Source Code
1 REM COPY BORDER !@ GO SUB VAL <> COPY @! BORDER GO SUB VAL <>x
10 LET a=50: DIM x(20): DIM y(20): DIM b(20): DIM c(100): DIM d(100): POKE 23730,30: POKE 23731,231: GO TO 40
20 INPUT "1)cls 2)copy 3)continue ";t: IF t=1 THEN CLS
30 IF t=2 THEN COPY
40 INK 0: INPUT "1)begin 2)alter 3)store 4)quit";f
50 GO TO (f*100)
100 INPUT "total number of corners: ";g
110 IF g>20 THEN INPUT "MUST be <=20...try again:";g: GO TO 110
120 LET n=g-1: INPUT "first coordinates: x=";x;" y=";y: GO SUB 750
130 FOR i=1 TO n+1
140 LET x(i)=x: LET y(i)=y
150 PLOT x,y: IF i=n+1 THEN GO TO 180
160 INPUT "next coordinates: x=";x;" y=";y
170 GO SUB 750
180 NEXT i
190 GO SUB 510: GO TO 20
200 INPUT "1)list 2)fix 3)old 4)both 5)MM";h
210 IF h=5 THEN GO TO 20
220 GO TO (200+h*30)
230 CLS : PRINT "corner: (x) (y)"
240 FOR i=1 TO n+1: PRINT " ";i;")";TAB 10;x(i);TAB 17;y(i)
250 NEXT i: GO TO 200
260 INPUT "alter corner __? (0 if done)";i
270 IF i=0 THEN GO SUB 500: GO TO 200
280 INPUT "new coordinates: x=";x(i);" y=";y(i): GO TO 260
290 INK 7: PLOT 175,USR 26727: INK 0: GO TO 200
300 INK 7: PLOT 175,USR 26715: INK 0: GO TO 200
320 INK 7: PLOT 175,USR 26727: INK 0: GO SUB 650: GO TO 20
400 STOP
500 CLS
510 LET c(1)=x(1): LET d(1)=y(1)
530 FOR e=2 TO a-1
540 LET j=((e-1))/(a-1): LET b(1)=(1-j)^n
550 FOR i=1 TO n
560 LET b(i+1)=(g-i)/i*j/(1-j)*b(i)
570 NEXT i
580 LET c(e)=0: LET d(e)=0
590 FOR i=1 TO n+1
600 LET c(e)=c(e)+b(i)*x(i)
610 LET d(e)=d(e)+b(i)*y(i)
620 NEXT i
630 NEXT e
640 LET c(a)=x(g): LET d(a)=y(g)
650 INPUT "C)curve only F)frame & curve";z$
660 IF z$="c" THEN GO TO 710
670 FOR i=1 TO n
680 PLOT x(i),y(i)
690 DRAW x(i+1)-x(i),y(i+1)-y(i)
700 NEXT i
710 FOR e=2 TO a-1
720 PLOT c(e),d(e)
730 NEXT e
740 RETURN
750 IF x<=255 AND x>=0 AND y<=175 AND y>=0 THEN RETURN
760 INPUT "HEY!...x<256,y<176! x=";x;" y=";y: GO TO 750
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
