```"""
Author:  Kirby Urner, 4D Solutions, Sept. 15 2005
Version #: 1.3

Developed for a Saturday Academy class (PSU, Portland)[1]
In a curriculum context, some parts are left unfinished, plus
even this version is suggestive of possible enhancements,
e.g. the Camera and Header APIs could be far more developed.

[1] this is during a time after SA had moved to PSU from OGI
"""

class Vector(object):

color = 'Red'

def __init__(self, xyz):
self.xyz = xyz

def write(self):
basic = "cylinder {<0,0,0>, <%s,%s,%s>, 0.1" % self.xyz
return "%s %s" % (basic, "pigment { color %s } no_shadow }" % self.color)

def __repr__(self):
return "Vector <%s, %s, %s>" % self.xyz

def __mul__(self, scalar):
xyz = tuple([scalar * i for i in self.xyz])
return Vector(xyz)

xyz = tuple([ i+j for i,j in zip(self.xyz, other.xyz)])
return Vector(xyz)

def _get_xyz(self):
return '<%s, %s, %s>' % self.xyz

def _get_length(self):
return pow(sum([i**2 for i in xyz]), 0.5)

coords = property(_get_xyz)

length = property(_get_length)

class Edge(object):

color = 'Red'

def __init__(self, v0, v1):
self.v0 = v0
self.v1 = v1

def __repr__(self):
return "Edge %s, %s" % (self.v0.coords, self.v1.coords)

def write(self):
basic = "cylinder {%s, %s, 0.1" % (self.v0.coords, self.v1.coords)
return "%s %s" % (basic, "pigment { color %s } no_shadow }" % self.color)

class Vertex(object):

color = 'Red'

def __init__(self, v0):
self.v0 = v0

def __repr__(self):

def write(self):
basic = "sphere {%s, %s" % (self.v0.coords, self.radius)
return "%s %s" % (basic, "pigment { color %s } no_shadow}" % self.color)

class Polyhedron(object):

color = 'Red'

def __init__(self, vertsdict, faces):
self.verts = vertsdict
self.faces = faces
self.edges = self.__get_edges()

def __repr__(self):
return "Polyhedron: %s vertices, %s edges, %s faces" \
% (len(self.verts), len(self.edges), len(self.faces))

def __get_edges(self):
"""
take a list of face-tuples and distill
all the unique edges,
e.g. ((1,2,3)) => ((1,2),(2,3),(3,1))
e.g. icosahedron has 20 faces and 30 unique edges
( = cubocta 24 + tetra's 6 edges to squares per
jitterbug)
"""
uniqueset = set()
for f in self.faces:
edgetries = zip(f, f[1:]+ (f[0],))
for e in edgetries:
e = tuple(sorted(e))
return tuple(uniqueset)

def write(self, name):
"""
generate the edges and vertices in POV-Ray
scene description language
"""
lines = ['#declare %s = union {' % name]
for e in self.edges:
edge = Edge( self.verts[e[0]], self.verts[e[1]] )
edge.color = self.color
lines.append(edge.write())
for v in self.verts.values():
sphere = Vertex(v)
sphere.color = self.color
lines.append(sphere.write())
lines.append("}")
lines.append("object {%s}\n" % name)
return '\n'.join(lines)

def __mul__(self, scalar):
newvectors = {}
for v in self.verts:
newvectors[v] = self.verts[v] * scalar
return Polyhedron(newvectors, self.faces)

# defaults

bgcolor = "color Gray50"
lightloc0 = "<300, 300, -1000>"
lightloc1 = "<-300, 300, -1000>"
lightcolor = "White"

@staticmethod
def write():
return """
#include "colors.inc"

background { %(bgcolor)s }
light_source{ %(lightloc0)s %(lightcolor)s }
light_source{ %(lightloc1)s %(lightcolor)s }

class Camera (object):

# defaults

look_at  = 0
location = '<0, .1, -25>'

@staticmethod
def write():
return """
camera {
location %(location)s
look_at %(look_at)s
}
""" % Camera.__dict__

def buildicosa():

"""
Build an icosahedron from three mutually perpendicular
golden rectangles
"""

phi = (1 + pow(5,0.5))/2.0

verts = {# 2*phi x 2 rectangle in XZ

1:Vector((-phi,  0,  -1)),
2:Vector((-phi,  0,   1)),
3:Vector(( phi,  0,   1)),
4:Vector(( phi,  0,  -1)),
# 2*phi x 2 rectange in XY

5:Vector(( -1,  phi,  0)),
6:Vector((  1,  phi,  0)),
7:Vector((  1, -phi,  0)),
8:Vector(( -1, -phi,  0)),
# 2*phi x 2 rectange in YZ

9:Vector((  0,  1,  phi)),
10:Vector((  0, -1,  phi)),
11:Vector((  0, -1, -phi)),
12:Vector((  0,  1, -phi))}

faces = ((5,6,9),(5,9,2),(5,2,1),(5,1,12),(5,12,6),
(1,11,12),(11,12,4),(12,4,6),(4,6,3),(6,3,9),
(3,9,10),(9,10,2),(10,2,8),(2,8,1),(8,1,11),
(7,11,4),(7,4,3),(7,3,10),(7,10,8),(7,8,11))

return verts, faces

def main():
icosa = Polyhedron(*buildicosa())

# overwriting defaults:

# Halloweeny skin (or Princetonian as the case may be)

icosa.color = 'Orange'
Camera.location = '<2, 4, -3>'
f = file('icosa.pov','w')
print >> f, Camera.write()
print >> f, icosa.write("bigicosa") # shapes need a name

# added a lush green interior icosa, why not?

# smaller is edgewise 80% of original,

# 0.512 original volume

icosasmall = icosa * 0.8
icosasmall.color = 'Green'
print >> f, icosasmall.write("smallicosa")

f.close()  # just to be neat & tidy

if __name__ == '__main__':
main()

```
`# code highlighted using py2html.py version 0.8`