For two-dimensional figures, rotational symmetry governs how many times a pattern repeats round 360 degrees, while adding reflections mirrors the objects within their sector.
LB has the easy ability to call Windows dll's, in particular one to read a pixel's colour, and another to fill to the boundary of a region. Together these make for a lot of colourful fun!
The code below allows you to choose what symmetry to use, and draws the black outline. Be careful to draw slowly and leave no gaps. You can then choose a colour for each area, and the corresponding areas all will be coloured too. A further option is to get it to flash each area independently of its symmetry partners in random colours. You have too an option to save-as=bitmap.
By calling ImageMagick you could save as GIF or create animations. I find it easy to do these 'by hand'.
Output of other related versions- you can add random colour fills within the LB code, or add them with an area-fill tool in your favourite image processing software;
-
-
Note this is still a work-in-progress. Plenty of ideas still for development, see the remmed lines for examples!
'**********************************************************************
'** **
'** kaleidoscope9.bas tenochtitlanuk June 2018 **
'** **
'**********************************************************************
' to-dos:
' fast movement leaves gaps. Save all previous positions and 'echos'?
' add an 'undo' to the fill? NO Just re-use 'fill'.
' change 'save' routine so won't save over another saved image. DONE
' check area allowed to draw in and show appropriately ( as originally). DONE
' Guidance notes. DONE
' Undo the arc before saving. ( overwrite in background colour? DONE
global radius, theta, hdc, hw, targetcolor, pi
pi =4 *atn( 1)
nomainwin ' un-rem for debugging..
BackgroundColor$ = "red"
WindowWidth =900
WindowHeight =600
button #w.b1, "Save Image", [saveImage], LR, 110, 20
button #w.b2, "Sparkle", [sparkle], LR, 110, 80
statictext #w.st, "", 610, 30, 260, 280
statictext #w.st2, "", 650, 330, 170, 40
notice "Edit values of N and kal to alter symmetries used."
' _________________________________________________________________________________________________
N =5 ' number of rotations /symmetry <<<<<<<<<<
kal =0 ' kal =0 for N-fold symmetry, kal =1 for added kaleidoscope reflections.<<<<<<<<<<
' ________________________________________________________________________________________________
open "Paint your star!" for graphics_nsb as #w
s$ ="" +chr$( 13)+_
" Hold down LeftButton and drag in" +chr$( 13) +_
" marked zone to draw." +chr$( 13) +chr$( 13)+_
" Right click to get a colour selector" +chr$( 13) +_
" to fill am area." +chr$( 13) +chr$( 13)+_
" NB You can ONLY draw in the" +chr$( 13) +_
" indicated area. Rotations and" +chr$( 13) +_
" mirroring apply automatically." +chr$( 13) +chr$( 13)+_
" Edit N and kal to alter symmetry &" +chr$( 13) +_
" rotations and whether you want" +chr$( 13) +_
" Kaleidoscope reflections." +chr$( 13) +chr$( 13)+_
" Save button allows your creation" +chr$( 13) +_
" to be saved."
hw =hwnd( #w) ' <<<<<<<<<<<<<<<<<
calldll #user32, "GetDC", hw as ulong, hdc as ulong ' <<<<<<<<<<<<<<<<<
#w "trapclose quit"
#w "when leftButtonMove [paint]"
#w "when rightButtonUp [colFill]"
#w "color 240 240 240 ; flush"
#w.st s$
#w.st2 " Current rotations ="; N
if kal =0 then
#w.st2 " Current rotations ="; N; " Reflections are OFF."
else
#w.st2 " Current rotations ="; N; chr$( 13); " Reflections are ON."
end if
th1 =int( 360 /N /2)
#w "color black"
if kal =0 then
call pie 300, 300, 252, 0 -th1, 2 *th1
else
call pie 300, 300, 252, 0, th1
end if
#w "backcolor 240 240 240"
#w "up ; size 3 ; goto 300 300 ; down ; circle 250 ; size 4" ' large size so gaps less likely
#w "color black"
wait
[paint]
x =MouseX -300
y =300 -MouseY
radius =( x^2 +y^2)^0.5
theta =180 /pi *atan2( y, x)
if theta >180 /N or radius <20 or radius >250 then wait
if kal =1 then
if theta <0 -180 /N or theta >=0 then wait
else
if theta <0 -180 /N or theta >=180 /N then wait
end if
for i =0 to N -1
angle =i *360 /N
call set radius, angle -theta
if kal =1 then call set radius, angle +theta
next i
wait
[colFill]
xVar =MouseX -300: yVar =MouseY -300 ' w.r.t. centre of graphic area
print "Mouse clicked for fill colour at "; xVar; ", "; yVar; " from centre."
colordialog "0 0 0", fillCol$
if fillCol$ ="" or fillCol$ ="black" or fillCol$ ="0 0 0" then [colFill]
#w "color "; fillCol$; " ; backcolor "; fillCol$
targetcolor =0 ' this is the colour of the outline to fill out to.
radius =( xVar^2 +yVar^2)^0.5
theta =180 /pi *atan2( yVar, xVar)
print " This was radius "; int( radius); " angle "; int( theta); " degrees clockwise w.r.t. centre."
for i =0 to N -1
angle =i *360 /N
xV =300 +int( radius *cosRad( angle +theta)) ' using coordinates w.r.t. top left as origin
yV =300 +int( radius *sinRad( angle +theta))
#w "size 8 ; down ; set "; xV; " "; yV
#w "up ; size 3"
print " Fill from "; using( "####", xV); " "; using( "####", yV)
calldll #gdi32, "ExtFloodFill",_
hdc as ulong,_
xV as long,_
yV as long,_
targetcolor as long,_
_FLOODFILLBORDER as long,_ 'ie fill out 'til this colour is met... <<<<<<<<<<<<<<<<<<<<<<<<<<
result as long
xV =300 +int( radius *cosRad( angle -theta))
yV =300 +int( radius *sinRad( angle -theta))
print " Fill from "; using( "####", xV); " "; using( "####", yV)
calldll #gdi32, "ExtFloodFill",_
hdc as ulong,_
xV as long,_
yV as long,_
targetcolor as long,_
_FLOODFILLBORDER as long,_ 'ie fill out 'til this colour is met... <<<<<<<<<<<<<<<<<<<<<<<<<<
result as long
next i
#w "color black ; down"
scan
wait
function sinRad( t)
sinRad =sin( t *pi /180)
end function
function cosRad( t)
cosRad =cos( t *pi /180)
end function
[saveImage]
#w "color 180 180 40; size 4 ; down"
if kal =0 then
call pie 300, 300, 252, 0 -th1, 2 *th1
else
call pie 300, 300, 252, 0, th1
end if
#w "getbmp scr 0 0 595 580"
filedialog "Save As...", "default.bmp", fn$
if fn$ <>"" then bmpsave "scr", fn$ else bmpsave "scr", "default.bmp"
#w "color black"
wait
sub set r, t
if r <250 then
t =t *pi /180
x =300 +r *cos( t): y =300 +r *sin( t)
#w "set "; x; " "; y
end if
end sub
sub pie x, y, r, startAngle, spanAngle
#w "down ; size 2"
for i =startAngle to startAngle +spanAngle
xs =int( 1.04 *r *cosRad( i))
ys =int( 1.04 *r *sinRad( i))
#w "set "; 300 +xs; " "; 300 +ys
next i
end sub
function atan2( y, x)
pi =atn( 1) *4
if x <>0 then arctan = atn( y /x)
select case
case x >0
atan2 =arctan
case y >=0 and x <0
atan2 =pi +arctan
case y <0 and x <0
atan2 =arctan -pi
case y >0 and x =0
atan2 =pi /2
case y <0 and x =0
atan2 =pi /-2
end select
end function
sub quit h$
calldll #user32, "ReleaseDC", hw as ulong, hdc as ulong, ret as void 'release the DC <<<<<<
close #w
end
end sub
[sparkle]
for sp =1 to 2000
[pt]
x =int( 500 *rnd( 1)): y =int( 500 *rnd( 1))
if ( ( x -250)^2 +( y -250)^2)^0.5 >=248 then [pt]
xF =x +50
yF =y +50
calldll #gdi32, "GetPixel", hdc as ulong, x as long, y as long, pixcol as long
bl = int( pixcol /( 256*256))
gr = int( (pixcol -bl *256*256) / 256)
re = int( pixcol -bl *256*256 - gr *256)
if pixcol <>0 then
r$ =str$( 56 +int( 200 *rnd( 1)))
g$ =str$( 56 +int( 200 *rnd( 1)))
b$ =str$( 56 +int( 200 *rnd( 1)))
choice$ =r$ +" " +g$ +" " +b$
#w "backcolor "; choice$
calldll #gdi32, "ExtFloodFill",_
hdc as ulong,_
xF as long,_
yF as long,_
targetcolor as long,_
_FLOODFILLBORDER as long,_ ' ' ie fill out 'til this colour is met... <<<<<<<<<<<<<<<<<<<<<<<<<<
result as long
scan
'calldll #kernel32, "Sleep", 50 as long, ret as void
end if
next sp
wait
'sub q h$
' close #wM
' end
'end sub