This is an old project of mine, but I really like it, so it’s gone through many revisions.
The current python source is a new version I typed up recently, past versions included a few extra bits and pieces, one had the ability to erase as well as add dots, usually this effect can be achieved with good colouring anyway.
Code
By defult this version of the code produces the frames for animation, for single images, remove the second line and unindent everything after.
Or just change the frame count to “for frame in range(1):”
from math import cos,sin,pi
for frame in range(100):
a=sin(frame/1600.0*pi*2)
"""#child=(angle,scale,child,child)
testSectionA=(.1,1,(.2,1,(.25,1,(.2,.9,(-pi/2,.8,"B"),(pi/2,.8,"C")))))
testSectionB=(.1,1,(.2,1,(.2,1,(.2,1,(2,.85,"B"),(0,.85,"A")))))
testSectionC=(.15,.95,(.3,.95,(.3,1,(.3,1,(4,.8,"C"),(0,.85,"A")))))"""
testSectionA=(a,1,(a,1,(a,1,(a,.9,(a,1,(-pi/2,.7+.2*sin(frame/200.0*pi),"A"),(pi/2,.7+.2*sin(frame/200.0*pi),"A"),(a,.9,(a,.9,"A")))))))
class dotfractal:
def __init__(self,startpos=(0,400),startradius=80,startangle=-pi/2.0,
startsection="A",sections={"A":testSectionA},
maxdepth=8):
self.startpos=startpos
self.startradius=startradius
self.startangle=startangle
self.startsection=startsection
self.sections=sections
self.maxdepth=maxdepth
self.dots=[[] for i in range(maxdepth+1)]
def render(self):
self.sections[self.startsection]
self.drawdot(self.sections[self.startsection],self.startpos,self.startradius,self.startangle,self.maxdepth,0)
return self.draw()
def draw(self):
from PIL import Image,ImageDraw
imres=(1080,720)
hw=int(imres[0]*.5)
hh=int(imres[1]*.5)
im=Image.new("RGB",imres,(0,0,0))
dr=ImageDraw.Draw(im)
for j in self.dots:
for i in j:
position,radius,depth=i
left=position[0]-radius+hw
top=position[1]-radius+hh
right=position[0]+radius+hw
bottom=position[1]+radius+hh
dr.ellipse((left,top,right,bottom),fill=(depth*32,128-depth*10,128-depth*10))
#dr.ellipse((left,top,right,bottom),fill=(255,0,depth*24))
return im
def drawdot(self,sequence,position,radius,angle,depth,iteration):
currentdot=position,radius,depth
self.dots[depth].append(currentdot)
##produce children
children=sequence[2:]
if depth>0:
for i in children:
if isinstance(i,str):
self.drawdot(self.sections[i],position,radius,angle,depth-1,iteration+1)
else:
childseq=i
childradius=radius*i[1]
childangle=angle+i[0]
w=radius+childradius
childpos=(position[0]+cos(childangle)*w,position[1]+sin(childangle)*w)
self.drawdot(childseq,childpos,childradius,childangle,depth,iteration)
df=dotfractal(maxdepth=7,startsection="A",startradius=30,sections={"A":testSectionA})
im=df.render()
im.save("%04d.png"%frame)
0