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

""" 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()

On Sun, Mar 8, 2015 at 6:31 PM, kirby urner <kirby.urner@gmail.com> wrote:
""" 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
Here's a link to the rendered graphic should you go to the trouble to run the .pov file output by the Python script above: https://www.flickr.com/photos/kirbyurner/16140315443/ Running POSIX, so it looks like this to render the above picture $ povray +H768 +W1024 +Q9 +A0.3 bridges.pov Kirby
participants (1)
-
kirby urner