"""
This version adds an instance variable self.keep
that propagates though the scaling method to
the next of kin. For example:
>>> import ch
>>> c = ch.Cube()
>>> c.volume
3
>>> c.keep
[]
>>> bigc = c * 2
>>> bigc.volume
24
>>> c.keep.append("gem")
>>> c.keep
['gem']
>>> bigc.keep
['gem']
>>>
"""
from math import sqrt as radical
phi = (1 + radical(5))/2
class Poly( object):
def __init__(self, edge = 1, edge_name = "edge",
volume = 1, greekname = "Tetrahedron",
platonic = True, dual = "Tetrahedron", keep=[]):
self.edge = edge
self.edge_name = edge_name
self.volume = volume
self.greekname = greekname
self.platonic = platonic
self.dual = dual
self.keep = keep
def scale(self, scalefactor):
edge = self.edge * scalefactor # edge unbound to self
volume = self.volume * pow(scalefactor, 3) # likewise volume
# print("DEBUG: a star is born: a new %s" % self.__class__.__name__)
return self.__class__(*(edge, self.edge_name, volume, self.greekname,
self.platonic, self.dual, self.keep))
__mul__ = __rmul__ = scale # e.g. tetra = tetra * 3
def __repr__(self):
return "Polyhedron of type %s (vol: %s)" % (self.greekname, self.volume)
class Tetra( Poly ):
pass
class Cube( Poly ):
def __init__(self, edge = 1, edge_name = "any face diagonal",
volume = 3, greekname = "Cube",
platonic=True, dual="Octahedron", keep=[]):
super(Cube, self).__init__(*(edge, edge_name, volume,
greekname, platonic, dual, keep))
class Octa( Poly ):
def __init__(self, edge = 1, edge_name = "any edge",
volume = 4, greekname = "Octahedron",
platonic=True, dual="Cube", keep=[]):
super(Octa, self).__init__(*(edge, edge_name, volume,
greekname, platonic, dual, keep))
class R_Dodeca( Poly ):
def __init__(self, edge = 1, edge_name = "any long face diagonal",
volume = 6, greekname = "Rhombic Dodecahedron",
platonic=False, dual="Cuboctahedron",keep=[]):
super(R_Dodeca, self).__init__(*(edge, edge_name, volume,
greekname, platonic, dual, keep))
class R_Triac( Poly ):
def __init__(self, edge = radical(2)/2, edge_name = "any long face
diagonal",
volume = 7.5, greekname = "Rhombic Triacontahedron",
platonic=False, dual="Icosidodecahedron", keep=[]):
super(R_Triac, self).__init__(*(edge, edge_name, volume,
greekname, platonic, dual, keep))
class Icosa ( Poly ):
def __init__(self, edge = 1.0, edge_name = "any edge",
volume = 5 * phi**2 * radical(2), greekname = "Icosahedron",
platonic=True, dual="Pentagonal Dodecahedron", keep=[]):
super(Icosa, self).__init__(*(edge, edge_name, volume,
greekname, platonic, dual, keep))
class P_Dodeca ( Poly ):
def __init__(self, edge = 1/phi, edge_name = "any edge",
volume = (phi**2 + 1) * 3 * radical(2), greekname =
"Pentagonal Dodecahedron",
platonic=True, dual="Icosahedron", keep=[]):
super(P_Dodeca, self).__init__(*(edge, edge_name, volume,
greekname, platonic, dual))
class Cubocta ( Poly ):
def __init__(self, edge = 1, edge_name = "any edge",
volume = 20, greekname = "Cuboctahedron",
platonic=False, dual = "Rhombic Dodecahedron", keep=[]):
super(Cubocta, self).__init__(*(edge, edge_name, volume,
greekname, platonic, dual))
def test1():
c = Cube()
print "First shape: %s" % c
print "Dual: %s Platonic: %s" % (c.dual, c.platonic)
d = P_Dodeca()
print "Second shape: %s" % d
print "Dual: %s Platonic: %s" % (d.dual, d.platonic)
def test2():
print "\n\nVolumes Table\n============="
for shape in (Tetra(), Cube(), Octa(), R_Triac()*pow(2./3,1./3),
R_Dodeca(), R_Triac(), P_Dodeca(), Icosa(), Cubocta()):
poly = "{0} ({1} = {2:.4g})".format(shape.greekname,
shape.edge_name, shape.edge)
print "{0:<60}{1:>8.4g}".format(poly, shape.volume)
def test3():
print "\n\nDuals Table\n=========="
for shape in (Tetra(), Cube(), Octa(), R_Dodeca(), R_Triac(),
P_Dodeca(), Icosa(), Cubocta()):
print "{0:<30}{1}".format(shape.greekname+"
*"[int(shape.platonic)], shape.dual)
print "\n * = Platonic"
if __name__ == "__main__":
# test1()
test2()
test3()