[Edu-sig] Exhibit: Python + POV-Ray (one of my favorite ways to get graphics)

kirby urner kirby.urner at gmail.com
Mon Mar 9 02:31:40 CET 2015


"""
Author:  Kirby Urner, 4D Solutions, Sept. 15 2005
Last modified:  March 7, 2015
Version #: 1.7
(c) MIT Licence

Developed for Bridges Conference to add graphic to paper

Prototype shows two of the six plastic panels held in
place by spokes.  In the final assembly, spokes are replaced
by chains in tension hooked to the six tetrahedron ribs on one
end, and to brass fixture inserts in the six panel centers.

Other materials and tension schemes apply.
"""

class Vector:

    texture = 'T_Chrome_4D'

    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, "texture {%s} no_shadow }" % self.texture)

    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)

    def __add__(self, other):
        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):

    texture = 'T_Chrome_4D'

    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.05" % (self.v0.coords, self.v1.coords)
        return "%s %s" % (basic, "texture {%s}  no_shadow }" % self.texture)


class Vertex(object):

    texture = 'T_Chrome_4D'
    radius = 0.05

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

    def __repr__(self):
        return "Sphere %s, radius = %s" % (self.v0.coords, self.radius)

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

class Polyhedron:

    texture = '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))
                uniqueset.add(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.texture = self.texture
            lines.append(edge.write())
        for v in self.verts.values():
            sphere = Vertex(v)
            sphere.texture = self.texture
            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)

class Header (object):

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

    @staticmethod
    def write():
        return """

#version 3.6; // 3.7;
global_settings{ assumed_gamma 1.0 }
#default{ finish{ ambient 0.1 diffuse 0.9 }}

#include "colors.inc"
#include "textures.inc"
#include "woods.inc"
#include "glass_old.inc"

// sun -------------------------------------------------------------
light_source{<1500,2000,-2500> color White*0.7}
light_source{<-500, 500,-2500> color Yellow*0.7}
// sky -------------------------------------------------------------
sphere{<0,0,0>,1 hollow
       texture{pigment{gradient <0,1,0>
                       color_map{[0    color White]          //<---2
                                 [0.15 color White]
                                 [1.0  color Blue]}}
               finish {ambient 1 diffuse 0} }
       scale 10000}

//==================================================================

#include "colors.inc"
#include "metals.inc"
#include "glass.inc"

"""


class Camera:

    # 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

rt2 = pow(2, 1/2)


def build_cube():
    """
    The hexahedron panels need no glue to adhere thanks to
    beveling and inward pull of the six chains.
    """

    verts = {# octants left of Z plane
              1:Vector((-rt2,  -rt2,  rt2)),
              2:Vector((-rt2,  -rt2, -rt2)),
              3:Vector((-rt2,   rt2, -rt2)),
              4:Vector((-rt2,   rt2,  rt2)),
             # octants right of Z plane
              5:Vector(( rt2,  -rt2,  rt2)),
              6:Vector(( rt2,  -rt2, -rt2)),
              7:Vector(( rt2,   rt2, -rt2)),
              8:Vector(( rt2,   rt2,  rt2))}

    faces = ((1,2,3,4), (4,8,7,3), (8,5,6,7), (1,2,6,5),
             (2,3,7,6), (1,4,8,5))

    return verts, faces

def build_tetrahedron():

    verts = {# octants left of Z plane
              2:Vector((-rt2,  -rt2, -rt2)),
              4:Vector((-rt2,   rt2,  rt2)),
             # octants right of Z plane
              5:Vector(( rt2,  -rt2,  rt2)),
              7:Vector(( rt2,   rt2, -rt2))}

    faces = ((4,5,2),(4,5,7),(2,7,5),(2,7,4))

    return verts, faces

def write_boxes(name):
    defines =  "#declare Face = box{{ < -{0},-{0},-{0}>, <{0},{0},-{0}>
texture{{ T_Ruby_Glass }} }}\n".format(rt2)
    defines += "object{Face}\n"
    defines += "object{Face rotate <0, 180, 0>}\n"
    return defines

def build_spokes():
    """
    to be replaced with chains, springs, or wires / ropes with turnbuckle
adjustment
    """
    scalar = 0.25

    verts = {
              'A0' : Vector((-rt2,     0,  0)),
              'B0' : Vector((   0,  -rt2,  0)),
              'C0' : Vector((   0,     0,  -rt2)),
              'D0' : Vector(( rt2,     0,  0)),
              'E0' : Vector((   0,   rt2,  0)),
              'F0' : Vector((   0,     0,   rt2)),
              'A1' : Vector((-rt2,     0,  0)) * scalar,
              'B1' : Vector((   0,  -rt2,  0)) * scalar,
              'C1' : Vector((   0,     0,  -rt2)) * scalar,
              'D1' : Vector(( rt2,     0,  0)) * scalar,
              'E1' : Vector((   0,   rt2,  0)) * scalar,
              'F1' : Vector((   0,     0,   rt2)) * scalar }

    faces = (('A0', 'A1'), ('B0', 'B1'), ('C0', 'C1'),('D0',
'D1'),('E0','E1'),('F0','F1'))

    return verts, faces

def main():
    cube = Polyhedron(*build_cube())
    tetra = Polyhedron(*build_tetrahedron()) * 0.25
    spokes = Polyhedron(*build_spokes())

    # overwriting defaults:

    cube.texture = 'T_Wood33'
    tetra.texture = 'T_Silver_4D'
    spokes.texture = 'T_Brass_4D'
    Header.bgcolor = 'Gray20'
    Header.lightloc1 = '<0, 0, 0>'
    Camera.location = '<2, 4, -3>'
    f = open('bridges.pov','w')
    print(Header.write(), file = f)
    print(Camera.write(), file = f)
    print(cube.write("duo_tet"), file=f) # shapes need a name
    print(tetra.write("tet"), file=f) # shapes need a name
    print(spokes.write("spokes"), file=f) # shapes need a name
    print(write_boxes("boxes"), file=f) # shapes need a name

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

if __name__ == '__main__':
    main()
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/edu-sig/attachments/20150308/bc34fd93/attachment-0001.html>


More information about the Edu-sig mailing list