Code: Select all
REM Program to demonstrate fitting a PolyBézier curve to several data points
REM Version 1.0 by Richard Russell, http://www.rtrussell.co.uk/, 19-Nov-2019
REM Compatible with both 'BBC BASIC for Windows' and 'BBC BASIC for SDL 2.0'
BB4W% = INKEY$(-256) == "W"
VDU 23,22,640;500;8,20,16,128+8
ON ERROR PROCcleanup : IF ERR=17 CHAIN @lib$+"../examples/tools/touchide" ELSE MODE 3 : PRINT REPORT$ : END
ON CLOSE PROCcleanup : QUIT
IF BB4W% THEN
INSTALL @lib$ + "GDIPLIB"
PROC_gdipinit
*FONT Arial, 18
ELSE
INSTALL @lib$ + "aagfxlib"
OSCLI "FONT """ + @lib$ + "DejaVuSans"", 18"
ENDIF
INSTALL @lib$ + "arraylib"
OFF : VDU 5
DIM X(9), Y(9)
Y(0) = 500 : X(9) = 1280 : Y(9) = 500
FOR I% = 1 TO 8
X(I%) = (I%-1) * 160 + RND(160)
Y(I%) = 300 + RND(300)
NEXT
title$ = "Drag the points to make a new polyBézier curve"
title% = (1280 - WIDTH(title$)) / 2
*REFRESH OFF
selected% = 0
oldB% = 0
oldX% = 0
oldY% = 0
REPEAT
CLS
GCOL 0 : VDU 30 : PLOT 0, title%, 0 : PRINT title$;
FOR I% = 0 TO 9
PROCbezierspline(X(I%), Y(I%), I% = 0)
NEXT
FOR I% = 1 TO 8
IF BB4W% THEN
IF I% = selected% C% = &FF008000 ELSE C% = &FF0000FF
brush% = FN_gdipcreatebrush(C%)
PROC_gdipsector(brush%, X(I%), Y(I%), 16, 16, 0, 360)
PROC_gdipdeletebrush(brush%)
ELSE
IF I% = selected% C% = &FF008000 ELSE C% = &FFFF0000
PROC_aasector(X(I%), Y(I%), 16, 16, 0, 360, C%)
ENDIF
NEXT
change% = FALSE
REPEAT
MOUSE X%, Y%, B%
IF B% IF B% <> oldB% THEN
near% = -1
dist% = &7FFFFFFF
oldsel% = selected%
FOR I% = 1 TO 8
D% = (X% - X(I%))^2 + (Y% - Y(I%))^2
IF D% < dist% dist% = D% : near% = I%
NEXT
IF dist% < 50*50 selected% = near% ELSE selected% = 0
IF selected% <> oldsel% change% = TRUE
oldX% = X% : oldY% = Y%
ENDIF
IF B% IF selected% > 0 THEN
IF X% <> oldX% X(selected%) += X% - oldX% : change% = TRUE
IF Y% <> oldY% Y(selected%) += Y% - oldY% : change% = TRUE
ENDIF
oldX% = X% : oldY% = Y% : oldB% = B%
CASE INKEY(1) OF
WHEN 9: selected% += 1 : change% = TRUE : IF selected% > 8 selected% = 1
WHEN 155: selected% -= 1 : change% = TRUE : IF selected% < 1 selected% = 8
WHEN 136: IF selected% > 0 X(selected%) -= 4 : change% = TRUE
WHEN 137: IF selected% > 0 X(selected%) += 4 : change% = TRUE
WHEN 138: IF selected% > 0 Y(selected%) -= 4 : change% = TRUE
WHEN 139: IF selected% > 0 Y(selected%) += 4 : change% = TRUE
ENDCASE
IF BB4W% SYS "InvalidateRect", @hwnd%, FALSE
*REFRESH
UNTIL change%
UNTIL FALSE
END
REM Calculate and draw a PolyBézier curve from a set of data points:
DEF PROCbezierspline(x, y, F%)
LOCAL pen%, cpx(), cpy()
PRIVATE N%, x(),y() : IF F% N% = 0
DIM x(3), y(3), cpx(2), cpy(2)
x() = x(1), x(2), x(3), x
y() = y(1), y(2), y(3), y
N% += 1 : IF N% < 4 ENDPROC
PROCcpcalc(x(), cpx())
PROCcpcalc(y(), cpy())
IF BB4W% THEN
pen% = FN_gdipcreatepen(&FFFF0000, 0, 6)
PROC_gdipbezier(pen%, x(1), y(1), cpx(1), cpy(1), cpx(2), cpy(2), x(2), y(2))
PROC_gdipdeletepen(pen%)
ELSE
PROC_aabezier(x(1), y(1), cpx(1), cpy(1), cpx(2), cpy(2), x(2), y(2), 6, &FF0000FF, 0)
ENDIF
ENDPROC
REM Calculate control points:
DEF PROCcpcalc(v(), cp())
LOCAL I%, b, rhs(), tmp()
DIM rhs(2), tmp(2)
rhs(0) = v(0) + 2*v(1)
rhs(1) = 4*v(1) + 2*v(2)
rhs(2) = (8*v(2) + v(3)) / 2
b = 2
cp(0) = rhs(0) / b
FOR I% = 1 TO 2
tmp(I%) = 1 / b
IF I% = 1 b = 4.0 - tmp(I%) ELSE b = 3.5 - tmp(I%)
cp(I%) = (rhs(I%) - cp(I%-1)) / b
NEXT
FOR I% = 1 TO 2
cp(2-I%) -= tmp(3-I%) * cp(3-I%)
NEXT
cp(2) = 2*v(2) - cp(2)
ENDPROC
DEF PROCcleanup
ON ERROR OFF
*REFRESH ON
IF BB4W% PROC_gdipexit
ENDPROC
