Kirby writes -
Yes. I'm meaning to pursue Scott's suggestion to look at Ruth Chabay's code.
FWIW, PyGeo's copy of Ruth's povexport module extends it a bit, allowing, for example, export of the VPython "faces" (triangle mesh) primitives. The export of the "faces" relies on some functionality not added to Pov-ray until version 3.5. Art
ajsiegel@optonline.net wrote:
Kirby writes -
Yes. I'm meaning to pursue Scott's suggestion to look at Ruth Chabay's code. FWIW, PyGeo's copy of Ruth's povexport module extends it a bit, allowing, for example, export of the VPython "faces" (triangle mesh) primitives. The export of the "faces" relies on some functionality not added to Pov-ray until version 3.5.
Art
I looked over the code I thought I had re-done, and it was not what I remembered working on. Here is a working version that doesn't build up a massive string, but rather writes to a destination. If you need a destination, make a CStringIO and use it. It would be fun to try and mix this with the PyGeo code. # ruth chabay, carnegie mellon university (rchabay@andrew.cmu.edu) # $Id: povexport.py 1.3 2004/05/31 19:56:05 daniels Exp daniels $ # v1.0 2000-12-17 # Markus Gritsch (gritsch@iue.tuwien.ac.at) # v.1.1 2001-03-09 # *) replaced 'scene' by 'display' everywhere # *) added spheres at the joints of a curve # *) consistent pov_texture usage in process_arrow() also for the shaft # *) ambient light, light sources, up, and fov are now handled correctly # *) some cosmetic changes to the code # v.1.1.1 2001-03-22 # *) added 'shadowless' keyword to export() # Ruth Chabay # 2001-06-23 # hack to fix error in export_curve introduced by Python 2.1 # now can't assign obj.color = array(...) # Markus Gritsch (gritsch@iue.tuwien.ac.at) # v.1.2 2001-11-23 # *) added 'xy_ratio' and 'custom_text' keywords to export() # *) the pov-strings are now directly written to a file # Scott David Daniels (Scott.Daniels@Acm.Org) # v.1.3 2004-May-31 Move code to output rather than concatenate text. """This module exports a VPython scene as POV-Ray scene description code. Lights and camera location from the current visual scene are included. Optionally, you may specify a list of include files, and pov textures for objects. For an example of its use, see 'povexample.py' convex objects are not exported. """ from visual import * from string import rfind __version__ = '0.1' ihat=vector(1, 0, 0) jhat=vector(0, 1, 0) khat=vector(0, 0, 1) def getpolar(a): # a is a vector # find rotation angles (standard polar coord) xy = sqrt(a.x**2 + a.y**2) theta = atan2(xy, a.z) phi = atan2(a.y, a.x) return theta, phi def process_frame(a, dest): # add in frame rotations & translations (may be nested) frame_code = '' fr = a.frame while fr: # orientation of frame.axis theta, phi = getpolar(fr.axis) aup = fr.up*1.0 # find rotation around x-axis (if fr.up <> jhat) # "undo" theta & phi rotations so can find alpha aup = rotate(aup, axis=khat, angle=-phi) aup = rotate(aup, axis=jhat, angle=pi/2.0-theta) a_sin = dot(cross(jhat, norm(aup)), ihat) a_cos = dot(norm(aup), jhat) alpha = atan2(a_sin, a_cos) frx=alpha*180./pi fry=-90+theta*180./pi frz=phi*180./pi print >>dest, ' rotate <%f, %f, %f>' % (frx, fry, frz) print >>dest, ' translate <%f, %f, %f>' % (fr.x, fr.y, fr.z) fr = fr.frame def add_texture(a, dest): # add in user-specified texture (will override color) try: print >>dest, ' texture { %s }' % a.pov_texture except AttributeError: pass def export_sphere(a, dest): print >>dest, """ sphere { <%(posx)f, %(posy)f, %(posz)f>, %(radius)f pigment { color rgb <%(red)f, %(green)f, %(blue)f> } """ % { 'posx':a.x, 'posy':a.y, 'posz':a.z, 'radius':a.radius, 'red':a.red, 'green':a.green, 'blue':a.blue } process_frame(a, dest) add_texture(a, dest) print >>dest, "}" def export_box(a, dest): # create box at origin along x-axis # then rotate around x,y,z axes # then translate to final location # find rotations theta, phi = getpolar(a.axis) # find rotation around x-axis (if a.up <> jhat) # "undo" theta & phi rotations so can find alpha aup = a.up*1.0 aup = rotate(aup, axis=khat, angle=-phi) aup = rotate(aup, axis=jhat, angle=pi/2.0-theta) a_sin = dot(cross(jhat, norm(aup)), ihat) a_cos = dot(norm(aup), jhat) alpha = atan2(a_sin, a_cos) # pos of visual box is at center # generate two opposite corners for povray pos1=vector(0, 0, 0) - a.size / 2.0 pos2=vector(0, 0, 0) + a.size / 2.0 print >>dest, """ box { <%(posx)f, %(posy)f, %(posz)f>, <%(pos2x)f, %(pos2y)f, %(pos2z)f> pigment {color rgb <%(red)f, %(green)f, %(blue)f>} rotate <%(rotx)f, %(roty)f, %(rotz)f> translate <%(transx)f, %(transy)f, %(transz)f>""" % { 'posx':pos1.x, 'posy':pos1.y, 'posz':pos1.z, 'pos2x':pos2.x, 'pos2y':pos2.y, 'pos2z':pos2.z, 'rotx':alpha*180./pi, 'roty':-90.+theta*180./pi, 'rotz':phi*180./pi, 'transx':a.x, 'transy':a.y, 'transz':a.z, 'red':a.red, 'green':a.green, 'blue':a.blue } process_frame(a, dest) add_texture(a, dest) print >>dest, "}" def export_cylinder(a, dest): endpt1=a.pos endpt2=a.pos+a.axis print >>dest, """cylinder { <%(posx)f, %(posy)f, %(posz)f>,<%(pos2x)f, %(pos2y)f, %(pos2z)f>, %(radius)f pigment { color rgb <%(red)f, %(green)f, %(blue)f> }""" % { 'posx':a.x, 'posy':a.y, 'posz':a.z, 'pos2x':endpt2.x, 'pos2y':endpt2.y, 'pos2z':endpt2.z, 'red':a.red, 'green':a.green, 'blue':a.blue, 'radius':a.radius } process_frame(a, dest) add_texture(a, dest) print >>dest, "}" def export_curve(a, dest): object_code = '' if len(a.pos) > 1: ii = 0 radius = max(0, a.radius) ccyl = cylinder(pos=a.pos[0], axis=a.pos[0] - a.pos[0], radius=radius or .1, color=tuple(a.color[0]), frame=a.frame, visible=0) csph = sphere(pos=a.pos[0], radius=ccyl.radius, color=tuple(a.color[0]), frame=a.frame, visible=0) if hasattr(a, 'pov_texture'): csph.pov_texture = ccyl.pov_texture = a.pov_texture for ii in xrange(len(a.pos) - 1): # create a dummy cylinder to export csph.pos = ccyl.pos = a.pos[ii] ccyl.axis = a.pos[ii+1] - a.pos[ii] csph.radius = ccyl.radius = radius or mag(ccyl.axis) / 200. csph.color = ccyl.color = tuple(a.color[ii]) export_cylinder(ccyl, dest) export_sphere(csph, dest) ii = ii+1 ii = len(a.pos) - 1 csph.pos = a.pos[ii] # csph.radius is identical csph.color = tuple(a.color[ii]) export_sphere(csph, dest) elif len(a.pos) == 1 and a.radius > 0: csph = sphere(pos=a.pos[0], radius=a.radius, color=tuple(a.color[0]), frame=a.frame, visible=0) if hasattr(a, 'pov_texture'): csph.pov_texture = a.pov_texture export_sphere(csph, dest) def export_ring(a, dest): theta, phi = getpolar(a.axis) print >>dest, """ torus { %(radius)f, %(minorradius)f pigment { color rgb <%(red)f, %(green)f, %(blue)f> } rotate <0.0, 0.0, -90.0> // align with x-axis rotate <%(rotx)f, %(roty)f, %(rotz)f> translate <%(transx)f, %(transy)f, %(transz)f>""" % { 'radius':a.radius, 'minorradius':a.thickness, 'transx':a.x, 'transy':a.y, 'transz':a.z, 'rotx':0.0, 'roty':-90.+theta*180./pi, 'rotz':phi*180./pi, 'red':a.red, 'green':a.green, 'blue':a.blue } process_frame(a, dest) add_texture(a, dest) print >>dest, "}" def export_arrow(a, dest): pyramid_template = """ object {Pyramid pigment { color rgb <%(red)f, %(green)f, %(blue)f> } scale <%(scalex)f, %(scaley)f, %(scalez)f> rotate <0, 0, -90> // align with x-axis rotate <%(rotx)f, %(roty)f, %(rotz)f> translate <%(transx)f, %(transy)f, %(transz)f> } """ al = a.length hl = a.headlength sl = al-hl # length of shaft hw = a.headwidth sw = a.shaftwidth # head is a pyramid ppos = a.pos+a.axis*(sl/al) theta, phi = getpolar(a.axis) print >>dest, """ object {Pyramid pigment { color rgb <%(red)f, %(green)f, %(blue)f> } scale <%(scalex)f, %(scaley)f, %(scalez)f> rotate <0, 0, -90> // align with x-axis rotate <%(rotx)f, %(roty)f, %(rotz)f> translate <%(transx)f, %(transy)f, %(transz)f> """ % { 'scalex':hw, 'scaley':hl, 'scalez':hw, 'rotx':0., 'roty':-90.+theta*180./pi, 'rotz':phi*180./pi, 'red':a.red, 'green':a.green, 'blue':a.blue, 'transx':ppos.x, 'transy':ppos.y, 'transz':ppos.z } process_frame(a, dest) add_texture(a, dest) print >>dest, "}" # shaft is a box; need to create a dummy box abox = box(pos=a.pos+a.axis*(sl/al)/2.0, axis=a.axis*(sl/al), up = a.up, width=a.shaftwidth, height=a.shaftwidth, color=a.color, frame=a.frame, visible = 0) if hasattr(a, 'pov_texture'): abox.pov_texture = a.pov_texture export_box(abox, dest) ## ??? inhibit process_frame code. ??? def export_cone(a, dest): pos2 = a.pos + a.axis print >>dest, """ cone { <%(posx)f, %(posy)f, %(posz)f>, %(radius)f <%(pos2x)f, %(pos2y)f, %(pos2z)f>, %(minorradius)f pigment { color rgb <%(red)f, %(green)f, %(blue)f> }""" % { 'radius':a.radius, 'minorradius':0.0, 'posx':a.x, 'posy':a.y, 'posz':a.z, 'pos2x':pos2.x, 'pos2y':pos2.y, 'pos2z':pos2.z, 'red':a.red, 'green':a.green, 'blue':a.blue } process_frame(a, dest) add_texture(a, dest) print >>dest, "}" def dontexport(a, dest): pass export_table = dict( sphere=export_sphere, box=export_box, cylinder=export_cylinder, curve=export_curve, ring=export_ring, arrow=export_arrow, cone=export_cone, frame=dontexport) def export(display=None, filename=None, include_list=None, xy_ratio=4./3., custom_text='', shadowless=False): if display is None: # no display specified so find active display dummy = sphere(visible=0) display = dummy.display del dummy if filename is None: filename = display.title + '.pov' dest = open(filename, 'wt') print >>dest, '// povray code generated by povexport.py v%s' % __version__ if include_list is not None: for x in include_list: print >>dest, '#include "%s"\n' % x print >>dest, custom_text # The next is needed only for arrows. print >>dest, """// Four-sided pyramid from shapes2.inc, slightly modified. #declare Pyramid = union { triangle { <-1, 0, -1>, <+1, 0, -1>, <0, 1, 0> } triangle { <+1, 0, -1>, <+1, 0, +1>, <0, 1, 0> } triangle { <-1, 0, +1>, <+1, 0, +1>, <0, 1, 0> } triangle { <-1, 0, +1>, <-1, 0, -1>, <0, 1, 0> } triangle { <-1, 0, -1>, <-1, 0, +1>, <1, 0, 1> } triangle { <-1, 0, -1>, <+1, 0, -1>, <1, 0, 1> } scale <.5, 1, .5> // so height = width = 1 }""" print >>dest, 'global_settings { ambient_light rgb', print >>dest, '<%(a)f, %(a)f, %(a)f> }' % {'a': display.ambient * 10} print >>dest, 'background { color rgb <%(r)f, %(g)f, %(b)f> }' % { 'r':display.background[0], 'g':display.background[1], 'b':display.background[2] } # begin povray setup for i in arange(len(display.lights)): # reproduce visual lighting (not ideal, but good approximation) light = display.lights[i] # vector in direction of light intensity = mag(light) # intensity of light (all lights are white) pos = norm(light) * max(display.range) * 100.0 # far away to simulate parallel light print >>dest, """light_source { <%(posx)f, %(posy)f, %(posz)f> color rgb <%(int)f, %(int)f, %(int)f>""" % { 'posx':pos.x, 'posy':pos.y, 'posz':pos.z, 'int':intensity*5/3.} if shadowless: print >>dest, ' shadowless' print >>dest, '}' ## ??? Frame code for lights??? cpos = display.mouse.camera ctr = display.center cup = display.up print >>dest, """camera { right <-%(xyratio)f, 0, 0> //visual uses right-handed coord. system location <%(posx)f, %(posy)f, %(posz)f> sky <%(upx)f, %(upy)f, %(upz)f> look_at <%(pos2x)f, %(pos2y)f, %(pos2z)f> angle %(fov)f rotate <0, 0, 0> }""" % { 'xyratio':xy_ratio, 'posx':cpos.x, 'posy':cpos.y, 'posz':cpos.z, 'upx':cup.x, 'upy':cup.y, 'upz':cup.z, 'pos2x':ctr.x, 'pos2y':ctr.y, 'pos2z':ctr.z, 'fov':display.fov*180/pi } exports = export_table.copy() for obj in display.objects: name = str(obj.__class__) try: function = exports[name] except AttributeError: print 'WARNING: export function for %s not implemented' % name exports[name] = dontexport # Only report each type once. else: function(obj, dest) dest.close() return 'The export() function no longer returns the scene as an\n' \ 'endless POV-Ray string, but saves it to a file instead.' if __name__ == '__main__': import sys print 'povexport %s\nPython %s' % (__version__, sys.version) print __doc__
-----Original Message----- From: edu-sig-bounces@python.org [mailto:edu-sig-bounces@python.org] On Behalf Of Scott David Daniels Sent: Monday, May 31, 2004 4:04 PM To: edu-sig@python.org Subject: [Edu-sig] Re: VPython
I looked over the code I thought I had re-done, and it was not what I remembered working on. Here is a working version that doesn't build up a massive string, but rather writes to a destination. If you need a destination, make a CStringIO and use it. It would be fun to try and mix this with the PyGeo code.
I gave it a whirl with PyGeo. About the furthest I've ever gotten into string processing (not fun to me) was my effort to follow and extend Ruth's povexport.py code. So that I am not sure I follow what you are accomplishing versus the "stock" code. I did end up writing to a file your version and my modified version of Ruth's, and notice that while they are in substance the same, yours is more coherently formatted. Which is significant if one wants, as I sometimes do, to do some hand editing to an export file. I can't swear that the formatting issues I see in my version are Ruth's issue, or something I cause by my futzing with it. Could you explain better the "use case" difference between your version and Ruth's? 2 BTWs: 1. I seemed to have needed to change AttributeError to KeyError on line 344. 2. The functionality I would like to see is PovRay automatically called to render the exported code - rather than requiring a separate look for the file and call to PovRay. At a practical level, this would provide for a more coherent workflow - looking at what you got and redoing it until you have it as you want to see it. But I don't have the confidence that I could accomplish this sensibly in a crossplatform way, that would fail gracefully, not require config files (where is the pvengine executable?), etc. Any thoughts? Art
Arthur wrote:
I looked over the code I thought I had re-done, and it was not what I remembered working on. Here is a working version that doesn't build up a massive string, but rather writes to a destination. If you need a destination, make a CStringIO and use it. It would be fun to try and mix this with the PyGeo code. OK, I sure mangled that explanation. I should have said: If you need a string, use a CStringIO as the destination and unpack when done.
I gave it a whirl with PyGeo.
About the furthest I've ever gotten into string processing (not fun to me) was my effort to follow and extend Ruth's povexport.py code. So that I am not sure I follow what you are accomplishing versus the "stock" code. ... Could you explain better the "use case" difference between your version and Ruth's? I have images with tens of thousands of truncated torii. The torii get turned into curves, and the resultant file is massive. Unfortunately, the N**2 effect of string concatenation was making these runs take a _long_ time.
2 BTWs:
1. I seemed to have needed to change AttributeError to KeyError on line 344. Most likely correct.
2. The functionality I would like to see is PovRay automatically called to render the exported code - rather than requiring a separate look for the file and call to PovRay. At a practical level, this would provide for a more coherent workflow - looking at what you got and redoing it until you have it as you want to see it. But I don't have the confidence that I could accomplish this sensibly in a crossplatform way, that would fail gracefully, not require config files (where is the pvengine executable?), etc. Any thoughts? I do know the pov-ray people have been pretty insistent on making sure nobody repackages it in a way you don't see their interface. I think we'd need to wait for the repackaging they are in the midst of.
-Scott David Daniels Scott.Daniels@Acm.Org
2. The functionality I would like to see is PovRay automatically called to render the exported code - rather than requiring a separate look for the file and call to PovRay. At a practical level, this would provide for a more coherent workflow - looking at what you got and redoing it until you have it as you want to see it. But I don't have the confidence that I could accomplish this sensibly in a crossplatform way, that would fail gracefully, not require config files (where is the pvengine executable?), etc. Any thoughts?
I do know the pov-ray people have been pretty insistent on making sure nobody repackages it in a way you don't see their interface. I think we'd need to wait for the repackaging they are in the midst of.
-Scott David Daniels Scott.Daniels@Acm.Org
I think it's fine to invoke povray from within Python using os.system or some such. Povray remains an independent program with its own identity. I have a pov.py that looks like this, which might give some ideas. But yes, in this version the paths to the pvengine are hardcoded. It'd take some doing (not a lot) to make this more friendly to configure (not my need at this time). But at least I test for which operating system (no Mac option as yet). def render(filename="default.pov"): if os.name == 'linux2': linuxcomm = "povray +V +W640 +H480 +FN16 +AM2 +Q9 +A0.3 +P +L/home/urnerk/include" print "Rendering... (this will take some time)" os.system(linuxcomm+" +I"+filename) if os.name == 'nt': wincomm = '"c:\\program files\\POV-Ray for Windows v3.5\\bin\\pvengine" -V fpp.ini' print "Rendering... (this will take some time)" # os.system(wincomm+" +I"+filename) os.system(wincomm) Note -- the fpp.ini thing shows another way to invoke povray, with all the command line settings pre-saved in a file (which my Python code also happens to write). Kirby
participants (4)
-
ajsiegelīŧ optonline.net
-
Arthur
-
Kirby Urner
-
Scott David Daniels