<div dir="ltr">"""<br>Author:  Kirby Urner, 4D Solutions, Sept. 15 2005<br>Last modified:  March 7, 2015<br>Version #: 1.7<br>(c) MIT Licence<br><br>Developed for Bridges Conference to add graphic to paper<br><br>Prototype shows two of the six plastic panels held in<br>place by spokes.  In the final assembly, spokes are replaced<br>by chains in tension hooked to the six tetrahedron ribs on one<br>end, and to brass fixture inserts in the six panel centers.<br><br>Other materials and tension schemes apply.<br>"""<br><br>class Vector:<br><br>    texture = 'T_Chrome_4D'<br><br>    def __init__(self, xyz):<br>        self.xyz = xyz<br><br>    def write(self):<br>        basic = "cylinder {<0,0,0>, <%s,%s,%s>, 0.1" % self.xyz<br>        return "%s %s" % (basic, "texture {%s} no_shadow }" % self.texture)<br><br>    def __repr__(self):<br>        return "Vector <%s, %s, %s>" % self.xyz<br><br>    def __mul__(self, scalar):<br>        xyz = tuple([scalar * i for i in self.xyz])<br>        return Vector(xyz)<br><br>    def __add__(self, other):<br>        xyz = tuple([ i+j for i,j in zip(self.xyz, other.xyz)])<br>        return Vector(xyz)<br><br>    def _get_xyz(self):<br>        return '<%s, %s, %s>' % self.xyz<br><br>    def _get_length(self):<br>        return pow(sum([i**2 for i in xyz]), 0.5)<br><br>    coords = property(_get_xyz)<br><br>    length = property(_get_length)<br><br><br>class Edge(object):<br><br>    texture = 'T_Chrome_4D'<br><br>    def __init__(self, v0, v1):<br>        self.v0 = v0<br>        self.v1 = v1<br><br>    def __repr__(self):<br>        return "Edge %s, %s" % (self.v0.coords, self.v1.coords)<br><br>    def write(self):<br>        basic = "cylinder {%s, %s, 0.05" % (self.v0.coords, self.v1.coords)<br>        return "%s %s" % (basic, "texture {%s}  no_shadow }" % self.texture)<br><br><br>class Vertex(object):<br><br>    texture = 'T_Chrome_4D'<br>    radius = 0.05<br><br>    def __init__(self, v0):<br>        self.v0 = v0<br><br>    def __repr__(self):<br>        return "Sphere %s, radius = %s" % (self.v0.coords, self.radius)<br><br>    def write(self):<br>        basic = "sphere {%s, %s" % (self.v0.coords, self.radius)<br>        return "%s %s" % (basic, "texture {%s} no_shadow }" % self.texture)<br><br>class Polyhedron:<br><br>    texture = 'Red'<br><br>    def __init__(self, vertsdict, faces):<br>        self.verts = vertsdict<br>        self.faces = faces<br>        self.edges = self.__get_edges()<br><br>    def __repr__(self):<br>        return "Polyhedron: %s vertices, %s edges, %s faces" \<br>               % (len(self.verts), len(self.edges), len(self.faces))<br><br>    def __get_edges(self):<br>        """<br>        take a list of face-tuples and distill<br>        all the unique edges,<br>        e.g. ((1,2,3)) => ((1,2),(2,3),(3,1))<br>        e.g. icosahedron has 20 faces and 30 unique edges<br>        ( = cubocta 24 + tetra's 6 edges to squares per<br>        jitterbug)<br>        """<br>        uniqueset = set()<br>        for f in self.faces:<br>            edgetries = zip(f, f[1:]+ (f[0],))<br>            for e in edgetries:<br>                e = tuple(sorted(e))<br>                uniqueset.add(e)<br>        return tuple(uniqueset)<br><br>    def write(self, name):<br>        """<br>        generate the edges and vertices in POV-Ray<br>        scene description language<br>        """<br>        lines = ['#declare %s = union {' % name]<br>        for e in self.edges:<br>            edge = Edge( self.verts[e[0]], self.verts[e[1]] )<br>            edge.texture = self.texture<br>            lines.append(edge.write())<br>        for v in self.verts.values():<br>            sphere = Vertex(v)<br>            sphere.texture = self.texture<br>            lines.append(sphere.write())<br>        lines.append("}")<br>        lines.append("object {%s}\n" % name)<br>        return '\n'.join(lines)<br><br>    def __mul__(self, scalar):<br>        newvectors = {}<br>        for v in self.verts:<br>            newvectors[v] = self.verts[v] * scalar<br>        return Polyhedron(newvectors, self.faces)<br><br>class Header (object):<br><br>    # defaults<br>    bgcolor = "color White"<br>    lightloc0 = "<300, 300, -1000>"<br>    lightloc1 = "<-300, 300, -1000>"<br>    lightcolor = "White"<br><br>    @staticmethod<br>    def write():<br>        return """<br><br>#version 3.6; // 3.7;<br>global_settings{ assumed_gamma 1.0 }<br>#default{ finish{ ambient 0.1 diffuse 0.9 }}<br><br>#include "colors.inc"<br>#include "textures.inc"<br>#include "woods.inc"<br>#include "glass_old.inc"<br><br>// sun -------------------------------------------------------------<br>light_source{<1500,2000,-2500> color White*0.7}<br>light_source{<-500, 500,-2500> color Yellow*0.7}<br>// sky -------------------------------------------------------------<br>sphere{<0,0,0>,1 hollow<br>       texture{pigment{gradient <0,1,0><br>                       color_map{[0    color White]          //<---2<br>                                 [0.15 color White]<br>                                 [1.0  color Blue]}}<br>               finish {ambient 1 diffuse 0} }<br>       scale 10000}<br><br>//==================================================================<br><br>#include "colors.inc"<br>#include "metals.inc"<br>#include "glass.inc"<br><br>"""<br><br><br>class Camera:<br><br>    # defaults<br>    look_at  = 0<br>    location = '<0, .1, -25>'<br><br>    @staticmethod<br>    def write():<br>        return """<br>camera {<br>  location %(location)s<br>  look_at %(look_at)s<br>}<br>""" % Camera.__dict__<br><br>def buildicosa():<br><br>    """<br>    Build an icosahedron from three mutually perpendicular<br>    golden rectangles<br>    """<br><br>    phi = (1 + pow(5,0.5))/2.0<br><br>    verts = {# 2*phi x 2 rectangle in XZ<br>              1:Vector((-phi,  0,  -1)),<br>              2:Vector((-phi,  0,   1)),<br>              3:Vector(( phi,  0,   1)),<br>              4:Vector(( phi,  0,  -1)),<br>             # 2*phi x 2 rectange in XY<br>              5:Vector(( -1,  phi,  0)),<br>              6:Vector((  1,  phi,  0)),<br>              7:Vector((  1, -phi,  0)),<br>              8:Vector(( -1, -phi,  0)),<br>             # 2*phi x 2 rectange in YZ<br>              9:Vector((  0,  1,  phi)),<br>             10:Vector((  0, -1,  phi)),<br>             11:Vector((  0, -1, -phi)),<br>             12:Vector((  0,  1, -phi))}<br><br>    faces = ((5,6,9),(5,9,2),(5,2,1),(5,1,12),(5,12,6),<br>             (1,11,12),(11,12,4),(12,4,6),(4,6,3),(6,3,9),<br>             (3,9,10),(9,10,2),(10,2,8),(2,8,1),(8,1,11),<br>             (7,11,4),(7,4,3),(7,3,10),(7,10,8),(7,8,11))<br><br>    return verts, faces<br><br>rt2 = pow(2, 1/2)<br><br><br>def build_cube():<br>    """<br>    The hexahedron panels need no glue to adhere thanks to<br>    beveling and inward pull of the six chains.    <br>    """<br><br>    verts = {# octants left of Z plane<br>              1:Vector((-rt2,  -rt2,  rt2)),<br>              2:Vector((-rt2,  -rt2, -rt2)),<br>              3:Vector((-rt2,   rt2, -rt2)),<br>              4:Vector((-rt2,   rt2,  rt2)),<br>             # octants right of Z plane<br>              5:Vector(( rt2,  -rt2,  rt2)),<br>              6:Vector(( rt2,  -rt2, -rt2)),<br>              7:Vector(( rt2,   rt2, -rt2)),<br>              8:Vector(( rt2,   rt2,  rt2))}<br><br>    faces = ((1,2,3,4), (4,8,7,3), (8,5,6,7), (1,2,6,5),<br>             (2,3,7,6), (1,4,8,5))<br><br>    return verts, faces<br><br>def build_tetrahedron():<br><br>    verts = {# octants left of Z plane<br>              2:Vector((-rt2,  -rt2, -rt2)),<br>              4:Vector((-rt2,   rt2,  rt2)),<br>             # octants right of Z plane<br>              5:Vector(( rt2,  -rt2,  rt2)),<br>              7:Vector(( rt2,   rt2, -rt2))}<br><br>    faces = ((4,5,2),(4,5,7),(2,7,5),(2,7,4))<br><br>    return verts, faces<br><br>def write_boxes(name):<br>    defines =  "#declare Face = box{{ < -{0},-{0},-{0}>, <{0},{0},-{0}> texture{{ T_Ruby_Glass }} }}\n".format(rt2)<br>    defines += "object{Face}\n"<br>    defines += "object{Face rotate <0, 180, 0>}\n"<br>    return defines<br><br>def build_spokes():<br>    """<br>    to be replaced with chains, springs, or wires / ropes with turnbuckle adjustment<br>    """<br>    scalar = 0.25<br><br>    verts = {<br>              'A0' : Vector((-rt2,     0,  0)),<br>              'B0' : Vector((   0,  -rt2,  0)),<br>              'C0' : Vector((   0,     0,  -rt2)),<br>              'D0' : Vector(( rt2,     0,  0)),<br>              'E0' : Vector((   0,   rt2,  0)),<br>              'F0' : Vector((   0,     0,   rt2)),<br>              'A1' : Vector((-rt2,     0,  0)) * scalar,<br>              'B1' : Vector((   0,  -rt2,  0)) * scalar,<br>              'C1' : Vector((   0,     0,  -rt2)) * scalar,<br>              'D1' : Vector(( rt2,     0,  0)) * scalar,<br>              'E1' : Vector((   0,   rt2,  0)) * scalar,<br>              'F1' : Vector((   0,     0,   rt2)) * scalar }<br><br>    faces = (('A0', 'A1'), ('B0', 'B1'), ('C0', 'C1'),('D0', 'D1'),('E0','E1'),('F0','F1'))<br><br>    return verts, faces<br><br>def main():<br>    cube = Polyhedron(*build_cube())<br>    tetra = Polyhedron(*build_tetrahedron()) * 0.25<br>    spokes = Polyhedron(*build_spokes())<br><br>    # overwriting defaults:<br><br>    cube.texture = 'T_Wood33'<br>    tetra.texture = 'T_Silver_4D'<br>    spokes.texture = 'T_Brass_4D'<br>    Header.bgcolor = 'Gray20'<br>    Header.lightloc1 = '<0, 0, 0>'<br>    Camera.location = '<2, 4, -3>'<br>    f = open('bridges.pov','w')<br>    print(Header.write(), file = f)<br>    print(Camera.write(), file = f)<br>    print(cube.write("duo_tet"), file=f) # shapes need a name<br>    print(tetra.write("tet"), file=f) # shapes need a name<br>    print(spokes.write("spokes"), file=f) # shapes need a name<br>    print(write_boxes("boxes"), file=f) # shapes need a name<br><br>    f.close()  # just to be neat & tidy<br><br>if __name__ == '__main__':<br>    main()<br><br><br></div>