"""
Radical Math, Portland, Oregon (April, 2010)

A reading and Python module (GPL, 4Dsolutions.net)
"""

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"

def testall():
    # test1()
    test2()
    test3()
    
if __name__ == "__main__":
    testall()
