Code
from math import sin, cos, pi, acos
def linspace(start, stop , n):
delta = (stop - start)/(n-1)
return [start + delta*i for i in range(int(n))]
def polar_closed_curve(func, points_per_rotation, num_rots, stroke='#000000', fill='none', stroke_width=None):
domain = linspace(0, 2*pi*num_rots, points_per_rotation*num_rots)
fvalues = map(func, domain)
fvalues = [Point(r*cos(t), r*sin(t)) for r,t in zip(fvalues, domain)]
if stroke_width:
return polygon(fvalues, stroke=stroke, fill=fill, stroke_width=stroke_width)
return polygon(fvalues, stroke=stroke, fill=fill)
#The petal for the outermost pattern. An intersection of two circles less a larger circle from below
def outer_leaf(r, pts):
theta = 3*pi/180
r_point = [r*sin(theta), r*cos(theta)]
l_point = [-r*sin(theta), r*cos(theta)]
phi = 10*pi/180
center_left = [-r*sin(phi), r*cos(phi)]
center_right = [r*sin(phi), r*cos(phi)]
half_center_dist = r*sin(phi)
radioos = (center_left[0] - r_point[0])**2 + (center_left[1] - r_point[1])**2
radioos = radioos**0.5
start_angle = acos((r_point[0] - center_left[0])/radioos)
end_angle = acos(half_center_dist/radioos)
delta = (end_angle-start_angle)/pts
blade = []
for i in range(pts):
blade.append(Point(center_left[0] + radioos*cos(start_angle+i*delta), center_left[1] + radioos*sin(start_angle+i*delta)))
start_angle, end_angle = pi - end_angle, pi - start_angle
delta = (end_angle-start_angle)/pts
for i in range(pts):
blade.append(Point(center_right[0] + radioos*cos(start_angle+i*delta), center_right[1] + radioos*sin(start_angle+i*delta)))
start_angle = pi/2+theta
end_angle = pi/2 - theta
delta = (end_angle-start_angle)/pts
for i in range(pts+2):
blade.append(Point(r*cos(start_angle+i*delta), r*sin(start_angle+i*delta)))
return blade
leaf_radius = 85
def three_pflower(t):
return leaf_radius*sin(3*t)
#Calculate the radius of the inner tangent circle
min_error = 9999999999999
best_r = None
for t in linspace(pi/6+0.05,pi/3, 10000):
perp_slope = -(3*cos(3*t)*cos(t) - sin(3*t)*sin(t))/(3*cos(3*t)*sin(t) + sin(3*t)*cos(t))
x0, y0 = leaf_radius*sin(3*t)*cos(t), leaf_radius*sin(3*t)*sin(t)
y = -perp_slope*x0 + y0
r = leaf_radius - y
error = abs(r**2 - ((y0-y)**2+x0**2))
if error < min_error and y < leaf_radius:
min_error = error
best_r = r
radius_ratio = best_r/leaf_radius
#Create the orange flower with a discrete yet smooth gradient
start = [255, 162, 0]
end = [255, 232, 191]
num_grad = 5
delta = [(e - s)/num_grad for e,s in zip(end, start)]
flower = []
for i in range(0, num_grad):
curr_color = [s + i*d for s, d in zip(start, delta)]
scale_fac = 1-i/num_grad
if i != 0:
flower.append(polar_closed_curve(three_pflower, 400*scale_fac, 1/2, fill=color(*curr_color), stroke=color(*curr_color), stroke_width=0) | scale(scale_fac))
else:
flower.append(polar_closed_curve(three_pflower, 400*scale_fac, 1/2, fill=color(*curr_color), stroke=color(0,0,0)) | scale(scale_fac))
flower = Group(flower)
outer_petals = [polygon(outer_leaf(leaf_radius, 30), stroke='none', fill='#ffffff') | repeat(60, rotate(6))]
outer_petals.append(polygon(outer_leaf(leaf_radius, 30), stroke='none', fill='#fbff00') | scale(2) | translate(y=-(leaf_radius+3)) | rotate(3) | repeat(60, rotate(6)))
outer_petals.append(polygon(outer_leaf(leaf_radius, 30), stroke='none', fill='#ff9d00') | scale(3) | translate(y=-2*(leaf_radius+3)) | repeat(60, rotate(6)))
outer_petals.append(polygon(outer_leaf(leaf_radius, 30), stroke='none', fill='#d9400d') | scale(4) | translate(y=-3*(leaf_radius+3)) | rotate(3) | repeat(60, rotate(6)))
outer_petals.append(polygon(outer_leaf(leaf_radius, 30), stroke='none', fill='#ba0404') | scale(5) | translate(y=-4*(leaf_radius+3)) | repeat(60, rotate(6)))
outer_petals = Group(outer_petals[::-1])
background = circle(r=4*leaf_radius, fill='#131c47')
outer = circle(r=leaf_radius, fill='#DF362D')
pretty_curvy_rings = polar_closed_curve(lambda t: leaf_radius+leaf_radius/10*(sin(9*t)-1), 300, 1, stroke='#3B0918', fill=color(0, 0, 255, 0.2)) | repeat(25, rotate(3) | scale(0.9))
pookalam = Group([background, outer_petals, outer, pretty_curvy_rings, flower])
def build_fractal(depth, centre, leaf_radius, ctr):
global pookalam
if depth == 0:
return
tancircle_dist = leaf_radius*(1-radius_ratio)
if depth % 2 == 1:
fill = '#3B0918'
stroke = '#DF362D'
c_fill = color(12, 255, 34, 0.1)
else:
fill = '#DF362D'
stroke = '#3B0918'
c_fill = color(0, 0, 255, 0.1)
smaller_thing = Group([
circle(x=centre[0], y=centre[1]+tancircle_dist, r=leaf_radius*radius_ratio, stroke_width=3*radius_ratio**ctr, fill=fill),
polar_closed_curve(lambda t: leaf_radius+leaf_radius/10*(sin(9*t)-1), 300, 1, stroke=stroke, fill=c_fill, stroke_width=3*radius_ratio**ctr)
| repeat(25, rotate(3) | scale(0.9)) | scale(radius_ratio) | translate(x=centre[0], y=centre[1]+tancircle_dist),
(flower | scale(radius_ratio**ctr) | translate(x=centre[0], y=centre[1]+tancircle_dist)),
]) | repeat(3, Rotate(120, anchor=Point(*centre)))
pookalam += smaller_thing
for i in range(3):
build_fractal(depth-1, [centre[0]+tancircle_dist*sin(2*pi/3*i), centre[1]+tancircle_dist*cos(2*pi/3*i)], leaf_radius*radius_ratio, ctr+1)
build_fractal(3, [0,0], leaf_radius, 1)
show(pookalam)