Designer

This file is part of and Miscellaneous Programs. Download the collection to get this file.
Date: 198x
Type: Program
Platform(s): TS 2068

This program is a vector-based line-drawing designer that allows users to create, display, scale, rotate, and delete line drawings stored as a compact binary string. Lines are encoded as pairs of 16-bit signed coordinates packed into a string variable using CHR$ encoding, with each line segment occupying exactly 8 bytes. The program implements a Cohen–Sutherland-style line clipping algorithm using four DEF FN functions (B, C, D, E) to clip lines against a configurable viewport defined by LF, RT, BT, and TP boundaries. A cursor routine at line 250 uses blinking PLOT/OVER 1 to show the current position, with keyboard controls for single-pixel and 10-pixel movement in both axes. Scale and rotation transformations are applied at display time using standard 2D rotation matrix arithmetic, without modifying the stored coordinate data.


Program Structure

The program is organized into distinct subroutines separated by REM labels, entered via a menu at line 640. Control flow is summarized below:

LinesLabel / Role
10Entry point — jumps directly to the menu
20–130LINE DRAW — clips and plots a line segment
140–240CURSER — interactive point placement with keyboard
250–370Cursor movement and key-read loop
380–570ROTATE / SCALE — transforms and redraws all stored lines
580–630DELETE LINE — removes a line from the data string
640–790MENU — top-level dispatcher and save/verify
800–930BASIC SETUP — initialises variables and DEF FN definitions
910DATA statement used as a decode template during redraw
920Diagnostic loop — prints raw byte codes of A$ (not called from menu)

Data Storage Format

Each line segment is stored as 8 bytes in the string A$. The four 16-bit coordinates (X1, Y1, X2, Y2) are each encoded as two bytes using CHR$ INT(val/256) + CHR$ (val MOD 256), assembled by DEF FN A$() and DEF FN B$() and concatenated by DEF FN C$(). Retrieval uses DEF FN A() = 256*CODE(A$(I1)) + CODE A$(I1+1), giving a simple big-endian 16-bit unsigned decode. The FOR I=2 TO LEN A$ STEP 8 loop at line 440 iterates over each stored segment.

Line Clipping Algorithm

Lines 30–110 implement a clipping algorithm roughly analogous to Cohen–Sutherland. The variable ED holds the clipping boundary value for whichever edge is being tested. Four DEF FN functions compute intersection points:

  • FN B() — X intercept when clipping P1 at a horizontal boundary
  • FN C() — X intercept when clipping P2 at a horizontal boundary
  • FN D() — Y intercept when clipping P1 at a vertical boundary
  • FN E() — Y intercept when clipping P2 at a vertical boundary

Line 30 performs the trivial reject: if both endpoints lie outside the same edge, OT=1 is set and the subroutine returns immediately. The final range check at line 120 guards against any floating-point imprecision before issuing PLOT/DRAW.

Rotation and Scaling

When option 3 (Scale/Rotate) or 4 (Delete) is chosen, the routine at line 380 prompts for an angle (converted to radians via AN*PI/180) and a scale factor S. During redraw (lines 480–510), the 2D rotation matrix is applied:

  • X_new = O1 + INT((x*COS AN + y*SIN AN))
  • Y_new = O2 + INT((-x*SIN AN + y*COS AN))

The origin (O1, O2) is chosen interactively. Scaling is implicit in the DATA at line 910, where the raw stored coordinates are divided by S before being assigned to the rotation inputs ((FN A()-O1)/S). This means scaling is applied to the offset from origin, which is geometrically correct.

The DATA / RESTORE Decode Trick

Line 910 is a clever (and fragile) self-referential decode mechanism. It is both a DATA statement and contains live calls to FN A(). The RESTORE 910 / READ sequence at lines 460–470 reads the 12 items from line 910’s DATA list, which includes expressions like (FN A()-O1)/S. Because Spectrum BASIC evaluates DATA items as expressions at READ time, each call to FN A() reads successive pairs of bytes from A$ using the current value of I1, which is itself incremented by the READ I,... I1+2,... pattern. This is a highly unusual use of DATA as executable code.

Cursor Routine

The cursor at line 250 uses PLOT BRIGHT 1; OVER 1 followed by a short PAUSE 2 then PLOT BRIGHT 0; OVER 1 to create a blinking pixel cursor without permanently altering the screen. Movement keys are:

KeyAction
5 / 8X −1 / +1
T / IX −10 / +10
6 / 7Y −1 / +1
Y / UY −10 / +10
1Set point (PLOT and return)
0Quit / cancel
2Move to origin

Notable Techniques and Idioms

  • Boolean arithmetic for boundary selection: LET ED=(TP AND Y1>TP)+(BT AND Y1<BT) uses Spectrum BASIC’s boolean values (1/0) multiplied by the boundary coordinate to select which edge value to use — avoiding an IF branch.
  • OVER 1 for non-destructive overlay: Used extensively for the cursor blink and for previewing a line before confirming it.
  • String as binary array: A$ serves as a byte array for coordinate storage, manipulated with CODE, CHR$, and string slicing.
  • In-place deletion: Line 630 removes a segment with A$(TO I-1)+A$(I+8 TO) and adjusts the loop counter I=I-8.
  • VAL-free GO TO: The program uses direct line numbers in GO TO/GO SUB rather than VAL "nnn" optimizations.

Content

Related Products

Related Articles

Related Content

Image Gallery

Designer

Source Code

   10 GO TO 640: REM DESIGNER
   20 REM LINE DRAW 
   30 IF (X1<LF AND X2<LF) OR (X1>RT AND X2>RT) OR (Y1>TP AND Y2>TP) OR (Y1<BT AND Y2<BT) THEN LET OT=1: RETURN 
   40 LET ED=(TP AND Y1>TP)+(BT AND Y1<BT)
   50 IF Y1<BT OR Y1>TP THEN LET X1=FN B(): LET Y1=ED
   60 LET ED=(TP AND Y2>TP)+(BT AND Y2<BT)
   70 IF Y2<BT OR Y2>TP THEN LET X2=FN C(): LET Y2=ED
   80 LET ED=(RT AND X1>RT)+(LF AND X1<LF)
   90 IF X1<LF OR X1>RT THEN LET Y1=FN D(): LET X1=ED
  100 LET ED=(RT AND X2>RT)+(LF AND X2<LF)
  110 IF X2<LF OR X2>RT THEN LET Y2=FN E(): LET X2=ED
  120 IF X1-LF>=0 AND X2-LF>=0 AND X1-LF<=255 AND X2-LF<=255 AND Y1-BT>=0 AND Y1-BT<=167 AND Y2-BT>=0 AND Y2-BT<=167 THEN PLOT X1-LF,Y1-BT+8: DRAW INT (X2-X1),INT (Y2-Y1)
  130 RETURN 
  140 REM CURSER
  150 LET AN=0: LET S=1: GO SUB 400
  160 PRINT AT 21,0;"X1=";O1;TAB 8;"Y1=";O2,R$: LET X=O1: LET Y=O2
  170 GO SUB 250: IF T$="2" THEN GO SUB 400: PRINT AT 21,16;R$: LET X=O1: LET Y=O2: GO TO 160
  180 LET X5=X: LET Y5=Y: IF T$="0" THEN RETURN 
  190 PRINT AT 21,0;"X2=";X;"  ";AT 21,8;"Y2=";Y;"  ": PAUSE 50: GO SUB 250: IF T$="2" THEN GO SUB 400: PRINT AT 21,16;R$: LET X=O1: LET Y=O2: GO TO 190
  200 IF T$="0" THEN RETURN 
  210 RESTORE : READ X2,X4,Y2,Y4,X1,Y1,X3,Y3: OVER 1: GO SUB 20
  220 INPUT "OK?";Q$: IF Q$="Y" OR Q$="y" THEN OVER 0: LET A$=FN C$()
  230 GO SUB 20: OVER 0: PRINT AT 21,0;"X1";AT 21,8;"Y1": IF Q$<>"Y" OR Q$<>"y" THEN PLOT OVER 1;X3-LF,Y3-BT+8: PLOT OVER 1;X4-LF,Y4-BT+8
  240 GO TO 170
  250 PLOT BRIGHT 1; OVER 1;X-LF,Y-BT+8: PAUSE 2: PLOT BRIGHT 0; OVER 1;X-LF,Y-BT+8: LET T$=INKEY$: IF T$="" THEN GO TO 250
  260 LET X=X+(T$="8")-(T$="5")
  270 LET X=X+10*(T$="I")-10*(T$="T")
  280 LET Y=Y+(T$="7")-(T$="6")
  290 LET Y=Y+10*(T$="U")-10*(T$="Y")
  300 IF X>RT THEN LET X=RT
  310 IF X<LF THEN LET X=LF
  320 IF Y>TP THEN LET Y=TP
  330 IF Y<BT THEN LET Y=BT
  340 IF T$="1" THEN PLOT OVER 1;X-LF,Y-BT+8: RETURN 
  350 IF T$="0" OR T$="2" THEN RETURN 
  360 PRINT AT 21,3;X;"  ";AT 21,11;Y;"  "
  370 GO TO 250
  380 REM ROTATE
  390 INPUT "ANGLE? ",AN: LET AN=AN*PI/180: INPUT "SCALE FACTOR? ",S: IF S=0 THEN LET S=1
  400 INPUT "COORDINATES OF ORIGIN? "'O1,O2: IF Z$="2" AND O1<127 THEN LET O1=127
  410 IF Z$="2" AND O2<83 THEN LET O2=83
  420 LET LF=O1-127: LET BT=O2-83: LET RT=LF+255: LET TP=BT+167
  430 CLS 
  440 FOR I=2 TO LEN A$ STEP 8
  450 IF I>LEN A$ THEN LET SR=0: GO TO 640
  460 RESTORE 910
  470 READ I1,X1,I1,Y1,I1,X2,I1,Y2,X3,X4,Y3,Y4
  480 LET X1=O1+INT (X3*COS AN+Y3*SIN AN)
  490 LET X2=O1+INT (X4*COS AN+Y4*SIN AN)
  500 LET Y1=O2+INT (-X3*SIN AN+Y3*COS AN)
  510 LET Y2=O2+INT (-X4*SIN AN+Y4*COS AN)
  520 IF SR=1 THEN OVER 1
  530 GO SUB 20: IF SR=1 THEN GO SUB 580: IF T$="0" THEN LET T$="": LET SR=0: RETURN 
  540 NEXT I: LET SR=0
  550 INPUT """ENTER"" = CONTINUE /""COP""= COPY  ";Q$
  560 IF Q$="COP" THEN COPY 
  570 RETURN 
  580 REM DELETE LINE 
  590 PRINT OVER 0;AT 21,0;"YCONFIRMNDELETE0QUIT": LET OT=0: OVER 1: GO SUB 20: GO SUB 20: LET T$=INKEY$: IF OT=1 THEN GO TO 620
  600 IF T$<>"0" AND T$<>"Y" AND T$<>"y" AND T$<>"N" AND T$<>"n" THEN GO TO 580
  610 IF T$="0" THEN RETURN 
  620 OVER 0: IF T$="Y" OR T$="y" OR OT=1 THEN GO SUB 20: RETURN 
  630 OVER 1: GO SUB 20: PAUSE 50: OVER 0: LET A$=A$( TO I-1)+A$(I+8 TO ): LET I=I-8: RETURN 
  640 REM MENU
  650 BORDER 0: INK 0: PAPER 6: CLS : PRINT PAPER 2; INK 7;AT 1,12;"DESIGNER"
  660 PRINT 'TAB 13; FLASH 1;"SELECT"; FLASH 0''"  1) INITIALIZE DISPLAY"
  670 PRINT '"  2) ADD NEW LINES"''"  3) SCALE/ROTATE"
  680 PRINT '"  4) DELETE LINES"''"  5) STOP "
  690 LET R$="  0QUIT1DEF2MOVE"
  700 INPUT Z$: CLS 
  710 IF Z$="1" THEN GO SUB 800
  720 IF Z$="2" THEN GO SUB 140
  730 IF Z$="3" THEN LET SR=0: GO SUB 380
  740 IF Z$="4" THEN LET SR=1: GO SUB 380
  750 IF Z$="5" THEN GO TO 780
  760 CLS : GO TO 640
  770 DATA X,X,Y,Y,X5,Y5,X1,Y1
  780 INPUT "DO YOU WISH TO SAVE THIS DESIGN?";Q$: IF Q$="Y" OR Q$="y" THEN SAVE "DESIGNER": PRINT "REWIND THE TAPE THEN ANY KEY    WILL LET YOU VERIFY ": PAUSE 0: VERIFY "DESIGNER": PRINT " VERIFY COMPLETE"
  790 STOP 
  800 REM BASIC SETUP
  810 LET LF=0: LET BT=LF: LET TP=167: LET RT=255: LET A$=""
  820 DEF FN A()=256*CODE (A$(I1))+CODE A$(I1+1)
  830 DEF FN A$()=CHR$ INT (X3/256)+CHR$ (X3-256*INT (X3/256))+CHR$ INT (Y3/256)+CHR$ (Y3-256*INT (Y3/256))
  840 DEF FN B$()=CHR$ INT (X4/256)+CHR$ (X4-256*INT (X4/256))+CHR$ INT (Y4/256)+CHR$ (Y4-256*INT (Y4/256))
  850 DEF FN B()=X1+(X2-X1)*(ED-Y1)/(Y2-Y1)
  860 DEF FN C()=X2+(X1-X2)*(ED-Y2)/(Y1-Y2)
  870 DEF FN D()=Y1+(Y2-Y1)*(ED-X1)/(X2-X1)
  880 DEF FN E()=Y2+(Y1-Y2)*(ED-X2)/(X1-X2)
  890 DEF FN C$()=A$+FN A$()+FN B$()
  900 LET A$=" ": RETURN 
  910 DATA I,(FN A()-O1)/S,I1+2,(FN A()-O2)/S,I1+2,(FN A()-O1)/S,I1+2,(FN A()-O2)/S,X1,X2,Y1,Y2
  920 FOR F=1 TO LEN A$: PRINT CODE A$(F): NEXT F
  930 SAVE "DESIGNER" LINE 10

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

People

No people associated with this content.

Scroll to Top