Here's a cut-down version of a little ditty I did with GDIP some time ago, if anyone is interested... If anyone wants the full version, let me know, and I'll find a way...
Code: Select all
REM Celtic_Knots v2.1 by David Marples 07/08/2007
REM It uses the GDIP library to generate anti-aliased curves
REM which is pretty, but won't work if you don't have the relevant bit of windows!
REM As the name suggests, it draws Celtic-style knotwork.
REM It works on the principle that if you draw each square as two lines, with one
REM going top left to bottom right overlying one going TR to BL, then it will always be valid.
REM Lines going through the corners are confusing, but consistent with this!
REM You can control how many squares horizontally and vertically are filled,
REM and whether or not the grid is shown.
REM You can choose the symmetry of the knot, with options being reflections horizontally or vertically,
REM or 2 or 4-fold rotational symmetry (the latter won't work with non-square arrays!).
REM By left-clicking on the knot, you can re-arrange the strands (symmetry setting can be changed for this)
REM Right-clicking on a strand will bring up a dialogue, allowing you to change to another pre-set colour pattern,
REM, alter the colour patterns, and change the width of the line for that colour pattern.
:
MODE 21:REM 800x600: try MODEs 0 (640x512), 23 (1024x768), or 15 (1280x1024) as alternatives
xres%=@vdu%!208
yres%=@vdu%!212
numsqx%=10
numsqy%=10
maxnumsq%=100
DIM sq&(maxnumsq%,maxnumsq%,3) :REM byte array to store colour and knot data
showgrid%=TRUE
knotdone%=FALSE
dia_shown%=FALSE
sym$="none"
DIM text% 255
PROCsetupGDI
PROCsetupcons
ON ERROR PROCtidycons:PROC_gdipexit:QUIT
ON CLOSE PROCtidycons:PROC_gdipexit:QUIT
ON SYS PROCdobuttons(@wparam%,@lparam%) : RETURN
DIM cols%(15,2) :REM stores data for 16 colour pairs
cols%()=&FFFFFF
cols%(0,1)=&000000
cols%(1,1)=&800000
cols%(2,1)=&008000
cols%(3,1)=&000080
cols%(4,1)=&808000
cols%(5,1)=&800080
cols%(6,1)=&008080
cols%(7,1)=&808080
cols%(8,1)=&B04040
cols%(9,1)=&40B040
cols%(10,1)=&4040B0
cols%(11,1)=&40B0B0
cols%(12,1)=&B0B040
cols%(13,1)=&B040B0
cols%(14,1)=&B0B0B0
cols%(15,1)=&F00000
sp%=2*yres% DIV (numsqy%+2)
REM Set initial background colour for all strands to white,
REM and set the line thickness to be 1/8 of the box size
FOR x%=0 TO 15
cols%(x%,0)=&FFFFFF
cols%(x%,2)=sp% DIV 8
NEXT x%
REPEAT
REM OK, so the main program doesn't do much! It waits for you to press a button,
REM or click the mouse, then leaps into action!
q$=INKEY$(1)
REM You CAN bail out this way, but you are meant to use the button!
MOUSE x%,y%,z%
IF z%<>0 THEN PROCmouse(x%,y%,z%)
REPEAT:MOUSE x%,y%,z%:UNTIL z%=0
UNTIL q$="q" OR q$="Q"
PROCtidycons
PROC_gdipexit
QUIT
:
DEFPROCmouse(x%,y%,z%)
LOCAL sp%,sx%,sy%,sz%,op%,newp%
REM A mouse button has been clicked: find where the mouse was at the time
IF NOT knotdone% THEN ENDPROC:REM we haven't drawn a knot to edit!
sp%=2*yres% DIV (numsqy%+2)
IF (2*yres% DIV (numsqx%+2))<sp% THEN sp%=2*yres% DIV (numsqx%+2)
IF x%<sp% OR y%<sp% OR x%>sp%*(numsqx%+1) OR y%>sp%*(numsqy%+1) OR dia_shown% THEN ENDPROC:REM outside the knot
sx%=(x% DIV sp%)
sy%=(y% DIV sp%)
REM sx% and sy% give the square we are in
x%-=sx%*sp%
y%-=sy%*sp%
IF 2*y%<sp% THEN
IF 2*x%<sp% THEN sz%=3 ELSE sz%=2
ELSE
IF 2*x%<sp% THEN sz%=0 ELSE sz%=1
ENDIF
REM sz% gives which corner we are in (0= top left, 1=top right, 2=br,3=bl)
IF 2*x%>sp% THEN x%=sp%-x%
IF 2*y%>sp% THEN y%=sp%-y%
sx%-=1
sy%-=1
IF z%=4 THEN
REM Left-click: reorganise knot
PROCchecksym
IF y%>x% THEN sq&(sx%,sy%,sz%)=1 ELSE sq&(sx%,sy%,sz%)=3
IF y%<4 AND x%<4 THEN sq&(sx%,sy%,sz%)=2
PROCsetpat(sq&(),numsqx%,numsqy%,sx%,sy%,sz%,sym$)
PROCspreadsym(sx%,sy%,sz%)
PROCclearcols
PROCsetcol(sq&(),numsqx%,numsqy%)
ELSE
REM Disabled in this cut-down version...
SYS "MessageBox", @hwnd%, "Line styling removed in this cut-dwn version", "Celtic Knot Can't!", 0
ENDIF
PROCdraw(numsqx%,numsqy%,xres%,yres%)
ENDPROC:REM PROCmouse
:
DEFPROCclearcols
LOCAL x%,y%,z%
REM reset all the colour bits to 0, to allow retracing
FOR x%=0 TO numsqx%-1
FOR y%=0 TO numsqy%-1
FOR z%=0 TO 3
sq&(x%,y%,z%)AND=3
NEXT z%
NEXT y%
NEXT x%
ENDPROC:REM clearcols
DEFPROCchecksym
LOCAL sel%
REM find out what symmetry is set, and return the relevant string
SYS "SendMessage", lb1%, &147,0,0 TO sel%
CASE sel% OF
WHEN 0:sym$="none"
WHEN 1:sym$="mh"
WHEN 2:sym$="mv"
WHEN 3:sym$="m4"
WHEN 4:sym$="r2"
WHEN 5:sym$="r4"
ENDCASE
ENDPROC :REM checksym
:
DEFFNvalidrange(n%,min%,max%)
IF n%<min% THEN =min%
IF n%>max% THEN =max%
=n%
:
DEFPROCdobuttons(w%,l%)
LOCAL content$,sel%,message$
w%=w% AND &FFFF
CASE w% OF
WHEN 1:
REM OK selected - check line width and close the dialogue box
cols%(newn%,2)=VAL(FNgetdlgtext(linechardlg%, 500))
IF cols%(newn%,2)<3 THEN cols%(newn%,2)=3:SYS "SetDlgItemText", !linechardlg%, 500, STR$(cols%(n%,2))
PROC_closedialog(linechardlg%)
dia_shown%=FALSE
WHEN 11:
REM change in number of squares horizontally
SYS "GetWindowText", eb1%, text%, 255
content$ = $$text%
numsqx%=FNvalidrange(VAL(content$),2,maxnumsq%)
SYS "SendMessage", eb1ud%, &467, 0, numsqx% : REM UDM_SETPOS
WHEN 21:
REM change in number of squares vertically
SYS "GetWindowText", eb2%, text%, 255
content$ = $$text%
numsqy%=FNvalidrange(VAL(content$),2,maxnumsq%)
SYS "SendMessage", eb2ud%, &467, 0, numsqy% : REM UDM_SETPOS
WHEN 31:
REM Button to draw knot has been pressed
REM First we need to get the size of knot to draw, from the edit boxes
SYS "GetWindowText", eb1%, text%, 255
content$ = $$text%
numsqx%=FNvalidrange(VAL(content$),2,maxnumsq%)
SYS "SendMessage", eb1ud%, &467, 0, numsqx% : REM UDM_SETPOS
SYS "GetWindowText", eb2%, text%, 255
content$ = $$text%
numsqy%=FNvalidrange(VAL(content$),2,maxnumsq%)
SYS "SendMessage", eb2ud%, &467, 0, numsqy% : REM UDM_SETPOS
REM now we need to sort out the symmetry required
PROCchecksym
REM Now call the routine to work out the knot and draw it
PROCdo_it
WHEN 32:
REM Show/Hide grid button pressed: toggle flag, toggle button, and if a knot has been calculated, redraw it
IF showgrid% THEN
showgrid%=FALSE
SYS "SetWindowText",gbut%,"Show grid"
ELSE
showgrid%=TRUE
SYS "SetWindowText",gbut%,"Hide grid"
ENDIF
IF knotdone% THEN CLG:PROCdraw(numsqx%,numsqy%,xres%,yres%)
WHEN 33: PROCtidycons:PROC_gdipexit:QUIT :REM "Quit"button pressed:let's get out of here!
WHEN 36:
REM "Help" button pressed
message$="Welcome to the Celtic Knot Drawing program, version 2.1, by David Marples"+CHR$(13)+CHR$(13)
message$+="It works on the principle that if you draw each square as two lines, with one going top left to bottom right and the"+CHR$(13)
message$+="overlying one going TR to BL, then it will always be valid."+CHR$(13)+CHR$(13)
message$+="By modifying the boxes at the top right, you can control how many squares horizontally and vertically are filled,"+CHR$(13)
message$+="and you can choose the symmetry of the knot, with options being reflections horizontally or vertically, or"+CHR$(13)
message$+="2 or 4-fold rotational symmetry (the latter won't work with non-square arrays!)."+CHR$(13)+CHR$(13)
message$+="When you are ready, click 'Draw it', and the knot will be generated."+CHR$(13)+CHR$(13)
message$+="By left-clicking on the knot, you can re-arrange the strands (symmetry setting can be changed for this)"+CHR$(13)
message$+="By clicking on the 'Hide Grid' button, you can toggle the square grid on and off."+CHR$(13)
SYS "MessageBox", @hwnd%, message$, "Celtic Knot Help", 0
ENDCASE
ENDPROC: REM PROCdobuttons
:
DEFPROCdo_it
LOCAL x%,y%,z%,tx%,ty%,tz%
REM Set up a square graphics window the size of the height of the screen (the rest will be used for controls)
VDU 24,0;0;2*yres%-1;2*yres%-1;
CLG
sq&()=&FF
FOR x%=0 TO numsqx%-1
FOR y%=0 TO numsqy%-1
FOR z%=0 TO 3
REM each square contains two lines: the bottom one runs top right to bottom left
REM and the upper one runs TL to BR: these 4 points are indicated by the z value (TL,TR,BR,BL)
IF sq&(x%,y%,z%)=&FF THEN
sq&(x%,y%,z%)=RND(3)
PROCsetpat(sq&(),numsqx%,numsqy%,x%,y%,z%,sym$)
tx%=numsqx%-x%-1
ty%=numsqy%- y%-1
REM deal with symmetry
CASE sym$ OF
WHEN "mh"
IF z%=0 OR z%=2 THEN tz%=z%+1 ELSE tz%=z%-1
sq&(tx%,y%,tz%)=sq&(x%,y%,z%)
PROCsetpat(sq&(),numsqx%,numsqy%,tx%,y%,tz%,sym$)
WHEN "mv"
tz%=3-z%
sq&(x%,ty%,tz%)=sq&(x%,y%,z%)
PROCsetpat(sq&(),numsqx%,numsqy%,x%,ty%,tz%,sym$)
WHEN "m4"
IF z%=0 OR z%=2 THEN tz%=z%+1 ELSE tz%=z%-1
sq&(tx%,y%,tz%)=sq&(x%,y%,z%)
PROCsetpat(sq&(),numsqx%,numsqy%,tx%,y%,tz%,sym$)
tz%=3-z%
sq&(x%,ty%,tz%)=sq&(x%,y%,z%)
PROCsetpat(sq&(),numsqx%,numsqy%,x%,ty%,tz%,sym$)
tz%=(z%+2) MOD 4
sq&(tx%,ty%,tz%)=sq&(x%,y%,z%)
PROCsetpat(sq&(),numsqx%,numsqy%,tx%,ty%,tz%,sym$)
WHEN "r2"
tz%=(z%+2) MOD 4
sq&(tx%,ty%,tz%)=sq&(x%,y%,z%)
PROCsetpat(sq&(),numsqx%,numsqy%,tx%,ty%,tz%,sym$)
WHEN "r4"
tz%=(z%+1) MOD 4
sq&(y%,tx%,tz%)=4-sq&(x%,y%,z%)
PROCsetpat(sq&(),numsqx%,numsqy%,y%,tx%,tz%,sym$)
tz%=(z%+2) MOD 4
sq&(tx%,ty%,tz%)=sq&(x%,y%,z%)
PROCsetpat(sq&(),numsqx%,numsqy%,tx%,ty%,tz%,sym$)
tz%=(z%+3) MOD 4
sq&(ty%,x%,tz%)=4-sq&(x%,y%,z%)
PROCsetpat(sq&(),numsqx%,numsqy%,ty%,x%,tz%,sym$)
ENDCASE
ENDIF
NEXT z%
NEXT y%
NEXT x%
knotdone%=TRUE
PROCsetcol(sq&(),numsqx%,numsqy%)
PROCdraw(numsqx%,numsqy%,xres%,yres%)
ENDPROC
:
DEFPROCspreadsym(x%,y%,z%)
LOCAL tx%,ty%,tz%
REM this routine handles changes in the knot due to edits, and makes changes appropriately symmetrical
tx%=numsqx%-x%-1
ty%=numsqy%- y%-1
CASE sym$ OF
WHEN "mh"
IF z%=0 OR z%=2 THEN tz%=z%+1 ELSE tz%=z%-1
sq&(tx%,y%,tz%)=sq&(x%,y%,z%)
PROCsetpat(sq&(),numsqx%,numsqy%,tx%,y%,tz%,sym$)
WHEN "mv"
tz%=3-z%
sq&(x%,ty%,tz%)=sq&(x%,y%,z%)
PROCsetpat(sq&(),numsqx%,numsqy%,x%,ty%,tz%,sym$)
WHEN "m4"
IF z%=0 OR z%=2 THEN tz%=z%+1 ELSE tz%=z%-1
sq&(tx%,y%,tz%)=sq&(x%,y%,z%)
PROCsetpat(sq&(),numsqx%,numsqy%,tx%,y%,tz%,sym$)
tz%=3-z%
sq&(x%,ty%,tz%)=sq&(x%,y%,z%)
PROCsetpat(sq&(),numsqx%,numsqy%,x%,ty%,tz%,sym$)
tz%=(z%+2) MOD 4
sq&(tx%,ty%,tz%)=sq&(x%,y%,z%)
PROCsetpat(sq&(),numsqx%,numsqy%,tx%,ty%,tz%,sym$)
WHEN "r2"
tz%=(z%+2) MOD 4
sq&(tx%,ty%,tz%)=sq&(x%,y%,z%)
PROCsetpat(sq&(),numsqx%,numsqy%,tx%,ty%,tz%,sym$)
WHEN "r4"
tz%=(z%+1) MOD 4
sq&(y%,tx%,tz%)=4-sq&(x%,y%,z%)
PROCsetpat(sq&(),numsqx%,numsqy%,y%,tx%,tz%,sym$)
tz%=(z%+2) MOD 4
sq&(tx%,ty%,tz%)=sq&(x%,y%,z%)
PROCsetpat(sq&(),numsqx%,numsqy%,tx%,ty%,tz%,sym$)
tz%=(z%+3) MOD 4
sq&(ty%,x%,tz%)=4-sq&(x%,y%,z%)
PROCsetpat(sq&(),numsqx%,numsqy%,ty%,x%,tz%,sym$)
ENDCASE
ENDPROC
:
DEFPROCsetpat(sq&(),numsqx%,numsqy%,x%,y%,z%,sym$)
LOCAL nsx%,nsy%
nsx%=numsqx%-1
nsy%=numsqy%-1
REM each corner can have one of 4 types: 0=corner of grid, the others indicate passes through in x, corner, or y directions
IF x%=0 AND (z%=0 OR z%=3) THEN sq&(x%,y%,z%)=3
IF x%=nsx% AND (z%=1 OR z%=2) THEN sq&(x%,y%,z%)=3
IF y%=0 AND (z%=2 OR z%=3) THEN sq&(x%,y%,z%)=1
IF y%=nsy% AND (z%=0 OR z%=1) THEN sq&(x%,y%,z%)=1
IF x%=0 AND y%=0 THEN sq&(x%,y%,3)=0
IF x%=0 AND y%=nsy% THEN sq&(x%,y%,0)=0
IF x%=nsx% AND y%=0 THEN sq&(x%,y%,2)=0
IF x%=nsx% AND y%=nsy% THEN sq&(x%,y%,1)=0
CASE z% OF
WHEN 0:
IF y%<nsy% THEN sq&(x%,y%+1,3)=sq&(x%,y%,z%):IF x%>0 THEN sq&(x%-1,y%+1,2)=sq&(x%,y%,z%)
IF x%>0 THEN sq&(x%-1,y%,1)=sq&(x%,y%,z%)
WHEN 1:
IF y%<nsy% THEN sq&(x%,y%+1,2)=sq&(x%,y%,z%):IF x%<nsx% THEN sq&(x%+1,y%+1,3)=sq&(x%,y%,z%)
IF x%<nsx% THEN sq&(x%+1,y%,0)=sq&(x%,y%,z%)
WHEN 2:
IF y%>0 THEN sq&(x%,y%-1,1)=sq&(x%,y%,z%):IF x%<nsx% THEN sq&(x%+1,y%-1,0)=sq&(x%,y%,z%)
IF x%<nsx% THEN sq&(x%+1,y%,3)=sq&(x%,y%,z%)
WHEN 3:
IF y%>0 THEN sq&(x%,y%-1,0)=sq&(x%,y%,z%):IF x%>0 THEN sq&(x%-1,y%-1,1)=sq&(x%,y%,z%)
IF x%>0 THEN sq&(x%-1,y%,2)=sq&(x%,y%,z%)
ENDCASE
ENDPROC
:
DEFPROCsetcol(sq&(),numsqx%,numsqy%)
LOCAL x%,y%,cn%,colbit%,tx%,ty%,nsx%,nsy%
REM Finds strands which aren't coloured yet, allocates them a colour,
REM and then follows along that strand to the end, or until it meets itself (using procfollow)
nsx%=numsqx%-1
nsy%=numsqy%-1
cn%=1
colbit%=(cn%*16) AND &F0
FOR x%=0 TO nsx%
FOR y%=0 TO nsy%
IF sq&(x%,y%,0) DIV 16=0 THEN
sq&(x%,y%,0)+=colbit%
REM sq&(x%,y%,2)+=colbit%
CASE sq&(x%,y%,0) AND 3 OF
WHEN 1:PROCfollow(sq&(),x%-1,y%,1,colbit%)
WHEN 2:PROCfollow(sq&(),x%-1,y%+1,2,colbit%)
WHEN 3:PROCfollow(sq&(),x%,y%+1,3,colbit%)
ENDCASE
CASE sq&(x%,y%,2) AND 3 OF
WHEN 1:PROCfollow(sq&(),x%+1,y%,3,colbit%)
WHEN 2:PROCfollow(sq&(),x%+1,y%-1,0,colbit%)
WHEN 3:PROCfollow(sq&(),x%,y%-1,1,colbit%)
ENDCASE
cn%+=1
IF cn%>15 THEN cn%=1
colbit%=(cn%*16) AND &F0
ENDIF
IF sq&(x%,y%,1)DIV 16=0 THEN
sq&(x%,y%,1)+=colbit%
REM sq&(x%,y%,3)+=colbit%
CASE sq&(x%,y%,1) AND 3 OF
WHEN 1:PROCfollow(sq&(),x%+1,y%,0,colbit%)
WHEN 2:PROCfollow(sq&(),x%+1,y%+1,3,colbit%)
WHEN 3:PROCfollow(sq&(),x%,y%+1,2,colbit%)
ENDCASE
CASE sq&(x%,y%,3) AND 3 OF
WHEN 1:PROCfollow(sq&(),x%-1,y%,2,colbit%)
WHEN 2:PROCfollow(sq&(),x%-1,y%-1,1,colbit%)
WHEN 3:PROCfollow(sq&(),x%,y%-1,0,colbit%)
ENDCASE
cn%+=1
IF cn%>15 THEN cn%=1
colbit%=(cn%*16) AND &F0
ENDIF
sq&(x%,y%,2)=16*(sq&(x%,y%,0) DIV 16)+(sq&(x%,y%,2) AND 3)
sq&(x%,y%,3)=16*(sq&(x%,y%,1) DIV 16)+(sq&(x%,y%,3) AND 3)
NEXT y%
NEXT x%
ENDPROC
:
DEFPROCfollow(sq&(),x%,y%,z%,colbit%)
REM OK, here's the bit that actually does the following!
IF (sq&(x%,y%,z%) AND &F0)<>colbit% THEN
CASE z% OF
WHEN 0:
sq&(x%,y%,0)=colbit%+(sq&(x%,y%,0)AND 3)
sq&(x%,y%,2)=colbit%+(sq&(x%,y%,2)AND 3)
CASE sq&(x%,y%,2) AND 3 OF
WHEN 1:PROCfollow(sq&(),x%+1,y%,3,colbit%)
WHEN 2:PROCfollow(sq&(),x%+1,y%-1,0,colbit%)
WHEN 3:PROCfollow(sq&(),x%,y%-1,1,colbit%)
ENDCASE
WHEN 1:
sq&(x%,y%,1)=colbit%+(sq&(x%,y%,1)AND 3)
sq&(x%,y%,3)=colbit%+(sq&(x%,y%,3)AND 3)
CASE sq&(x%,y%,3) AND 3 OF
WHEN 1:PROCfollow(sq&(),x%-1,y%,2,colbit%)
WHEN 2:PROCfollow(sq&(),x%-1,y%-1,1,colbit%)
WHEN 3:PROCfollow(sq&(),x%,y%-1,0,colbit%)
ENDCASE
WHEN 2:
sq&(x%,y%,2)=colbit%+(sq&(x%,y%,2)AND 3)
sq&(x%,y%,0)=colbit%+(sq&(x%,y%,0)AND 3)
CASE sq&(x%,y%,0) AND 3 OF
WHEN 1:PROCfollow(sq&(),x%-1,y%,1,colbit%)
WHEN 2:PROCfollow(sq&(),x%-1,y%+1,2,colbit%)
WHEN 3:PROCfollow(sq&(),x%,y%+1,3,colbit%)
ENDCASE
WHEN 3:
sq&(x%,y%,1)=colbit%+(sq&(x%,y%,1)AND 3)
sq&(x%,y%,3)=colbit%+(sq&(x%,y%,3)AND 3)
CASE sq&(x%,y%,1) AND 3 OF
WHEN 1:PROCfollow(sq&(),x%+1,y%,0,colbit%)
WHEN 2:PROCfollow(sq&(),x%+1,y%+1,3,colbit%)
WHEN 3:PROCfollow(sq&(),x%,y%+1,2,colbit%)
ENDCASE
ENDCASE
ENDIF
ENDPROC
:
DEFPROCdraw(numsqx%,numsqy%,xres%,yres%)
LOCAL x%,y%,sp%,pen%,dx1%,dy1%,dx2%,dy2%,c1%,c2%,nsx%,nsy%,pts%()
REM logically enough, draws the knot (and grid if required)
DIM pts%(3,1)
sp%=2*yres% DIV (numsqy%+2)
IF (2*yres% DIV (numsqx%+2))<sp% THEN sp%=2*yres% DIV (numsqx%+2)
nsx%=numsqx%-1
nsy%=numsqy%-1
CLG
IF showgrid% THEN
REM Show the grid of squares on which knot is constructed
FOR x%=1 TO numsqx%+1
LINE x%*sp%,sp%,x%*sp%,sp%*(numsqy%+1)
NEXT x%
FOR y%=1 TO numsqy%+1
LINE sp%,y%*sp%,sp%*(numsqx%+1),y%*sp%
NEXT y%
ENDIF
:
REM For each square, draw 2 lines using Bezier curves (points calculated in PROCsetarray)
FOR x%=0 TO nsx%
FOR y%=0 TO nsy%
CASE sq&(x%,y%,1) AND 3 OF
WHEN 1: dx1%=sp%:dy1%=3*sp% DIV 4
WHEN 2: dx1%=sp%:dy1%=sp%
WHEN 3: dx1%=3*sp% DIV 4:dy1%=sp%
WHEN 0:dx1%=3*sp% DIV 4:dy1%=3*sp% DIV 4
ENDCASE
CASE sq&(x%,y%,3) AND 3 OF
WHEN 1: dx2%=0:dy2%=sp% DIV 4
WHEN 2: dx2%=0:dy2%=0
WHEN 3: dx2%=sp% DIV 4:dy2%=0
WHEN 0:dx2%=sp% DIV 4:dy2%=sp% DIV 4
ENDCASE
PROCsetarray(pts%(),x%,y%,sp%,dx1%,dy1%,dx2%,dy2%)
c1%=(sq&(x%,y%,1) AND &F0) DIV 16
PROCdrawcurve(c1%,sp%)
:
CASE sq&(x%,y%,0) AND 3 OF
WHEN 1: dx1%=0:dy1%=3*sp% DIV 4
WHEN 2: dx1%=0:dy1%=sp%
WHEN 3: dx1%=sp% DIV 4:dy1%=sp%
WHEN 0:dx1%=sp% DIV 4:dy1%=3*sp% DIV 4
ENDCASE
CASE sq&(x%,y%,2) AND 3 OF
WHEN 1: dx2%=sp%:dy2%=sp% DIV 4
WHEN 2: dx2%=sp%:dy2%=0
WHEN 3: dx2%=3*sp% DIV 4:dy2%=0
WHEN 0:dx2%=3*sp% DIV 4:dy2%=sp% DIV 4
ENDCASE
PROCsetarray(pts%(),x%,y%,sp%,dx1%,dy1%,dx2%,dy2%)
c1%=(sq&(x%,y%,0) AND &F0) DIV 16
PROCdrawcurve(c1%,sp%)
NEXT y%
NEXT x%
FOR x%=0 TO nsx%
FOR y%=0 TO nsy%
IF (sq&(x%,y%,3) AND 3)=2 THEN
REM If line goes through diagonals, tidy up top line again
PROCsetarray(pts%(),x%,y%,sp%,sp% DIV 5,sp% DIV 5,-1*(sp% DIV 5),-1*(sp% DIV 5))
c1%=(sq&(x%,y%,1) AND &F0) DIV 16
PROCdrawcurve(c1%,sp%)
ENDIF
NEXT y%
NEXT x%
SYS "InvalidateRect", @hwnd%, 0, 0
ENDPROC
:
DEFPROCsetarray(pts%(),x%,y%,sp%,dx1%,dy1%,dx2%,dy2%)
REM set up curve in array pts%
pts%(0,0)=sp%*(x%+1)+dx1%
pts%(0,1)=sp%*(y%+1)+dy1%
CASE dx1% OF
WHEN 0: pts%(1,0)=pts%(0,0)+sp% DIV 2 :pts%(0,0)-=1
WHEN sp% DIV 4,3*sp% DIV 4:pts%(1,0)=pts%(0,0)
WHEN sp%: pts%(1,0)=pts%(0,0)-sp% DIV 2:pts%(0,0)+=1
WHEN sp% DIV 5:pts%(1,0)=sp%*(x%+1)
ENDCASE
CASE dy1% OF
WHEN 0: pts%(1,1)=pts%(0,1)+sp% DIV 2:pts%(0,1)-=1
WHEN sp% DIV 4,3*sp% DIV 4:pts%(1,1)=pts%(0,1)
WHEN sp%: pts%(1,1)=pts%(0,1)-sp% DIV 2:pts%(0,1)+=1
WHEN sp% DIV 5:pts%(1,1)=sp%*(y%+1)
ENDCASE
pts%(3,0)=sp%*(x%+1)+dx2%
pts%(3,1)=sp%*(y%+1)+dy2%
CASE dx2% OF
WHEN 0: pts%(2,0)=pts%(3,0)+sp% DIV 2:pts%(3,0)-=1
WHEN sp% DIV 4,3*sp% DIV 4:pts%(2,0)=pts%(3,0)
WHEN sp%: pts%(2,0)=pts%(3,0)-sp% DIV 2:pts%(3,0)+=1
WHEN -1*(sp% DIV 5):pts%(2,0)=sp%*(x%+1)
ENDCASE
CASE dy2% OF
WHEN 0: pts%(2,1)=pts%(3,1)+sp% DIV 2 :pts%(3,1)-=1
WHEN sp% DIV 4,3*sp% DIV 4:pts%(2,1)=pts%(3,1)
WHEN sp%: pts%(2,1)=pts%(3,1)-sp% DIV 2 :pts%(3,1)+=1
WHEN -1*(sp% DIV 5):pts%(2,1)=sp%*(y%+1)
ENDCASE
IF dx1%=0 AND dy1%=0 THEN pts%(0,0)+=sp% DIV 5:pts%(0,1)+=sp% DIV 5
IF dx1%=sp% AND dy1%=sp% THEN pts%(0,0)-=sp% DIV 5:pts%(0,1)-=sp% DIV 5
IF dx2%=0 AND dy2%=0 THEN pts%(3,0)+=sp% DIV 5:pts%(3,1)+=sp% DIV 5
IF dx2%=sp% AND dy2%=sp% THEN pts%(3,0)-=sp% DIV 5:pts%(3,1)-=sp% DIV 5
ENDPROC :REM PROCsetarray
:
DEFPROCdrawcurve(col%,sp%)
LOCAL w1%,w2%
REM Draw Bezier curve using GDIP, and colours set in cols%(col%)
REM Lines are drawn twice, once in background colour, then again in foreground (but thinner)
IF cols%(col%,2)=&FFFFFF THEN w1%=sp% DIV 8 ELSE w1%=cols%(col%,2)
w2%=w1% DIV 2
IF w2%=0 THEN w2%=1:w1%=3
pencolour% = &FF000000+cols%(col%,0) : REM. Opaque, colour background to col%
penstyle% = LineStartFlat + LineEndFlat
IF ((pts%(3,0)=sp%+(sp% DIV 4)) AND (pts%(3,1)=sp%+(sp% DIV 4))) OR ((pts%(3,0)=sp%*numsqx%+(3*sp% DIV 4)) AND (pts%(3,1)=sp%+(sp% DIV 4))) THEN penstyle%+=LineEndRoundAnchor
IF ((pts%(0,0)=sp%+(sp% DIV 4)) AND (pts%(0,1)=sp%*numsqy%+(3*sp% DIV 4))) OR ((pts%(0,0)=sp%*numsqx%+(3*sp% DIV 4)) AND (pts%(0,1)=sp%*numsqy%+(3*sp% DIV 4))) THEN penstyle%+=LineStartRoundAnchor
penwidth = w1%
pen% = FN_gdipcreatepen(pencolour%, penstyle%, penwidth)
PROC_gdipbezier(pen%, pts%(0,0),pts%(0,1), pts%(1,0),pts%(1,1),pts%(2,0),pts%(2,1),pts%(3,0),pts%(3,1))
PROC_gdipdeletepen(pen%)
pencolour% = &FF000000+cols%(col%,1) : REM. Opaque, foreground colour col%
penstyle% = LineStartFlat + LineEndFlat
IF ((pts%(3,0)=sp%+(sp% DIV 4)) AND (pts%(3,1)=sp%+(sp% DIV 4))) OR ((pts%(3,0)=sp%*numsqx%+(3*sp% DIV 4)) AND (pts%(3,1)=sp%+(sp% DIV 4))) THEN penstyle%+=LineEndRoundAnchor
IF ((pts%(0,0)=sp%+(sp% DIV 4)) AND (pts%(0,1)=sp%*numsqy%+(3*sp% DIV 4))) OR ((pts%(0,0)=sp%*numsqx%+(3*sp% DIV 4)) AND (pts%(0,1)=sp%*numsqy%+(3*sp% DIV 4))) THEN penstyle%+=LineStartRoundAnchor
penwidth = w2%
pen% = FN_gdipcreatepen(pencolour%, penstyle%, penwidth)
PROC_gdipbezier(pen%, pts%(0,0),pts%(0,1), pts%(1,0),pts%(1,1),pts%(2,0),pts%(2,1),pts%(3,0),pts%(3,1))
PROC_gdipdeletepen(pen%)
ENDPROC :REM PROCdrawcurve
:
DEFPROCsetupGDI
INSTALL @lib$+"gdiplib"
PROC_gdipinit
LineEndFlat = 0
LineEndSquare = 1
LineEndRound = 2
LineEndTriangle = 3
LineEndSquareAnchor = &11
LineEndRoundAnchor = &12
LineEndDiamond = &13
LineEndArrow = &14
LineStartFlat=0
LineStartSquare = &100
LineStartRound = &200
LineStartTriangle = &300
LineStartSquareAnchor = &1100
LineStartRoundAnchor = &1200
LineStartDiamond = &1300
LineStartArrow = &1400
ENDPROC: REM PROCsetupGDI
:
DEFPROCsetupcons
INSTALL @lib$+"WINLIB5"
butw%=130
buth%=20
lpos%=xres%-butw%-50
IF lpos%<yres%+1 THEN lpos%=yres%+1
hpos%=40 * yres%/512
hspace%=52 *yres%/512
*FONT ARIAL 12
VDU 5
REM set up edit box for no. of boxes horizontally
eb1%=FN_editbox("8",lpos%,hpos%,butw%+15,buth%,11,&812000)
eb1ud%=FN_createwindow("msctls_updown32","",0,0,0,0,12,&96,0)
SYS "SendMessage", eb1ud%, &469, eb1%, 0 : REM UDM_SETBUDDY
SYS "SendMessage", eb1ud%, &465, 2, (2 << 16)+maxnumsq% : REM UDM_SETRANGE
SYS "SendMessage", eb1ud%, &467, 0, numsqx% : REM UDM_SETPOS
MOVE lpos%*2,(yres%-hpos%)*2+40
PRINT "Squares horizontally"
REM set up edit box for no. of boxes vertically
eb2%=FN_editbox("8",lpos%,hpos%+hspace%,butw%+15,buth%,21,&12000)
eb2ud%=FN_createwindow("msctls_updown32","",0,0,0,0,22,&96,0)
SYS "SendMessage", eb2ud%, &469, eb2%, 0 : REM UDM_SETBUDDY
SYS "SendMessage", eb2ud%, &465, 2, (2 << 16)+maxnumsq% : REM UDM_SETRANGE
SYS "SendMessage", eb2ud%, &467, 0, numsqy% : REM UDM_SETPOS
MOVE lpos%*2,(yres%-hpos%-hspace%)*2+40
PRINT "Squares vertically"
REM set up list box to control symmetry
lb1%=FN_combobox("",lpos%,hpos%+hspace%*2,butw%,buth%*7,41,3)
SYS "SendMessage", lb1%, &143, 0, "None"
SYS "SendMessage", lb1%, &143, 0, "L/R mirror"
SYS "SendMessage", lb1%, &143, 0, "T/B mirror"
SYS "SendMessage", lb1%, &143, 0, "4-fold mirror"
SYS "SendMessage", lb1%, &143, 0, "Rotation order 2"
SYS "SendMessage", lb1%, &143, 0, "Rotation order 4"
SYS "SendMessage", lb1%, &14E, 0,0
MOVE lpos%*2,(yres%-hpos%-2*hspace%)*2+40
PRINT "Symmetry"
pbut%=FN_button("Draw it!",lpos%,hpos%+3*hspace%,butw%,buth%*2,31,&20000)
IF showgrid% THEN gbut%=FN_button("Hide grid",lpos%,hpos%+4*hspace%,butw%,buth%*2,32,&20000) ELSE gbut%=FN_button("Show grid",lpos%,hpos%+4*hspace%,butw%,buth%*2,32,&20000)
REM qbut%=FN_button("Save knot",lpos%,hpos%+5*hspace%,butw%,buth%*2,34,&10000)
REM qbut%=FN_button("Load knot",lpos%,hpos%+6*hspace%,butw%,buth%*2,35,&10000)
qbut%=FN_button("Help",lpos%,hpos%+7*hspace%,butw%,buth%*2,36,&10000)
qbut%=FN_button("Quit",lpos%,hpos%+8*hspace%,butw%,buth%*2,33,&10000)
VDU4
ENDPROC:REM PROCsetupcons
:
DEFPROCtidycons
PROC_closewindow(eb1ud%)
PROC_closewindow(eb1%)
PROC_closewindow(eb2ud%)
PROC_closewindow(eb2%)
PROC_closewindow(pbut%)
PROC_closewindow(gbut%)
PROC_closewindow(qbut%)
ENDPROC