"""
By K. Urner, Oregon Curriculum Network
Last modified April 14, 2001

coords, povray, functions (plus some other modules) are all
contained in python101.zip, linked from
http://www.inetarena.com/~pdx4d/ocn/numeracy0.html

"""

from __future__ import nested_scopes
from coords import Qvector
import povray, functions, ciphers
from ciphers import P,mkdict
from random import choice

# vertices needed for our shapes (using quadray coordinates)

v0,v1,v2,v3 = map(Qvector,[(1,0,0,0),(0,1,0,0),
                           (0,0,1,0),(0,0,0,1)])
v4,v5,v6,v7 = -v0,-v1,-v2,-v3

ciphers._domain = ['A','B','C','D','E','F','G','H']

colors  = {'A':'Red','B':'Blue','C':'Orange','D':'Yellow',
           'E':'Magenta','F':'Pink','G':'Violet','H':'Green'} 

class Polyhedron:

    def getedges(self):
        # Extract edges from faces list

        output = []
        for face in self.faces:
            for i in range(len(face)):
                edge = [face[i],face[i-1]]
                edge.sort()
                if (tuple(edge) not in output):
                    output.append(tuple(edge))            
        return output
    
    def listp(self):
        """
        List the permutations in pgroup
        """
        for i in self.pgroup:
            print i

    def mkperm(self,n):
       """
       Multiply randomly selected permutations from
       pgroup together, starting with the identity
       permutation.  Randomly choose and multiply n times
       """
       result = self.pgroup[-1]
       for i in range(n):
           result *= choice(self.pgroup)
       return result

    def rotate(self,perm):
        """
        Apply permutation to corners of a polyhedron -- an
        operation analogous to rotation about an axis by a
        fixed increment
        """
        for i in range(len(self.corners)):
            corner = self.corners[i]
            self.corners[i] = perm.dict[corner]

    def randroll(self,n):
        """
        Like rolling a die:  make a permutation as a
        product of randomly chosen permutations, and
        apply it to self (tetrahedron object)
        """
        p = self.mkperm(n)
        self.rotate(p)

    def display(self,filename):
        """
        Output polyhedron, with color-coded vertices,
        to a povray file (extension .pov)
        """
        myfile = povray.Povray(filename+".pov")
        myfile.sphradius = 0.1  # spheres relatively fatter than edges

        # edges will be black

        myfile.cylcolor = "Black"
        # include some axes in the picture

        functions.xyzaxes(myfile,2) 
        for a,b in self.edges:
            myfile.edge(a,b)
        i=0
        for corner in self.corners:
            # associate colors with spheres, so we can

            # tell them apart

            myfile.sphcolor = colors[corner]
            myfile.point(eval('v'+str(i)))
            i += 1            
        myfile.close()
                
class Tetrahedron(Polyhedron):

    # create a list of the 12 rotational permutations

    # for the tetrahedron, including the identity permutation


    pgroup = [ P([('A','B','C')]),  # 120 degree face rotations

               P([('A','B','D')]),
               P([('A','C','D')]),
               P([('B','C','D')]),
               P([('A','B'),('C','D')]),  # opposite mid-edge axes

               P([('A','C'),('B','D')]),
               P([('A','D'),('B','C')]),
               P([])]

    for i in range(4):    #  add 240 degree face rotations

        pgroup.append(pgroup[i]**2)

    # and here is a list of the faces

    faces = [(v0,v1,v2),(v0,v2,v3),(v0,v3,v1),(v1,v2,v3)]

    def __init__(self):
        # this ordering will change as permutations

        # are applied

        self.corners = ['A','B','C','D']
        self.edges = self.getedges()

class Cube(Polyhedron):

    # create a list of the 24 rotational permutations

    # for the cube, including the identity permutation


    pgroup = [ P([('A','H','C','F'),('G','B','E','D')]), # face axes

               P([('A','H','B','G'),('F','C','E','D')]),
               P([('D','G','A','F'),('E','B','H','C')]),
               P([('H','E','F'),('B','D','A')]),  # axis C-G

               P([('B','D','C'),('H','G','F')]),  # axis E-A

               P([('E','H','G'),('C','A','D')]),  # axis B-F

               P([('B','C','A'),('E','F','G')]),  # axis H-D

               P([('E','C'),('A','G'),('D','H'),('B','F')]), # vertex axes

               P([('D','F'),('H','B'),('C','G'),('A','E')]),
               P([('C','F'),('B','G'),('A','E'),('D','H')]),
               P([('E','D'),('H','A'),('F','B'),('G','C')]),
               P([('E','B'),('A','F'),('G','C'),('H','D')]),
               P([('H','C'),('D','G'),('A','E'),('B','F')]),               
               P([])]

    for i in range(3):    #  add 180 and 270 degree face rotations

        pgroup.append(pgroup[i]**2)
        pgroup.append(pgroup[i]**3)

    for i in range(3,7):  # add 240 degree opposite corner rotations

        pgroup.append(pgroup[i]**2)

    # A  B  C  D  E  F  G  H     <-- starting positions

    # v0 v1 v2 v3 v4 v5 v6 v7

    
    # and here is a list of the faces

    faces = ((v0,v7,v2,v5),(v0,v7,v1,v6),(v1,v4,v2,v7),
             (v1,v4,v3,v6),(v3,v6,v0,v5),(v2,v4,v3,v5))

    def __init__(self):
        # this ordering will change as permutations

        # are applied

        self.corners = ['A','B','C','D','E','F','G','H']
        self.edges = self.getedges()        
        
def genpix(n, shape):
    """
    Generate n pictures of the tetrahedron, each
    time randomly permuted by one of the 12 in
    pgroup
    """
    for i in range(n):
        shape.randroll(5)
        shape.display(shape.__class__.__name__+str(i))
# code highlighted using py2html.py version 0.8