Skip to content

Instantly share code, notes, and snippets.

@acdimalev
Created September 14, 2012 22:39
Show Gist options
  • Save acdimalev/3725404 to your computer and use it in GitHub Desktop.
Save acdimalev/3725404 to your computer and use it in GitHub Desktop.
from math import *
# settings
n = 4
radii = [1/2.0 * sqrt((2.0 ** i - 1) / (2.0 ** n - 1)) for i in range(1, n + 1)]
# calculate bezier
a = 2 * pi / n ** 2
x = 8/3.0 * ( cos(a/2) - 1/8.0 * cos(a) - 1/2.0 )
y = ( cos(a) - x ) / tan(a) + sin(a)
dx = x - cos(a)
dy = y - sin(a)
d = sqrt(dx ** 2 + dy ** 2)
# render crazy shapes
class Shape:
def __init__(self, a, r1, r2):
self.path = []
v1, v2, v3, v4 = self.verts(a)
self.path.append( "L %s" % self.scaled(r2, (v1,)) )
self.r = [r1, r1, r2]
def __str__(self):
path = " ".join(self.path)
return '<path d="%s" fill="black" />\n' % path
def extend(self, r1):
self.r[1] = r1
def advance(self, a):
r0, r1, r2 = self.r
v1, v2, v3, v4 = self.verts(a)
self.path.append( "C %s" % self.scaled(r2, (v2, v3, v4)) )
if r1 < r0:
self.path.insert( 0, "L %s" % self.scaled(r0, (v1,)) )
if r1 != 0:
self.path.insert( 0, "C %s" % self.scaled(r1, (v3, v2, v1)) )
self.r[0] = r1
def close(self):
self.path.append("Z")
self.path.insert(0, "M 0 0")
def scaled(self, s, va):
list = []
for x, y in va:
list.append( "%s %s" % (s * x, s * y) )
return " ".join(list)
def verts(self, a):
a = pi / 2.0 + pi / 2 ** n - angle
b = pi / 2.0 - pi / 2 ** n - angle
v1 = ( cos(a), -sin(a) )
v2 = ( cos(a) + d * sin(a), -sin(a) + d * cos(a) )
v3 = ( cos(b) - d * sin(b), -sin(b) - d * cos(b) )
v4 = ( cos(b), -sin(b) )
return v1, v2, v3, v4
elements = []
shapes = (n + 1) * [None]
for i in range(1, 2 ** n + 1):
angle = 2 * pi * i / (2 ** n)
if not shapes[0]:
if not shapes[1]:
shapes[0] = Shape(a, 0, radii[0])
else:
shapes[0] = shapes[1]
shapes[0].extend(0);
else:
shapes[0].close()
elements.append( str(shapes[0]) )
shapes[0] = None
for j in range(1, n):
if not shapes[j]:
if not shapes[j + 1]:
shapes[j] = Shape(a, radii[j - 1], radii[j])
else:
shapes[j] = shapes[j + 1]
shapes[j].extend(radii[j - 1])
break
shapes[j] = None
for shape in set(shapes):
if shape: shape.advance(a)
# ...to a document
print """<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny"
viewBox="-1 -1 2 2">
<desc></desc>
%s
</svg>""" % " ".join(elements)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment