def __init__(self): """ The init function """ debugMsg("Called Scene.__init__()") BaseScene.__init__(self) self.renderer = Renderer() self.xSize = 640 self.ySize = 480 # these variables are used to determin the location of the camera self.centre = None self.bounds = None self.objectList = []
class Scene(BaseScene): """ The main object controlling the scene. Scene object methods and classes overriding the BaseScene class. """ def __init__(self): """ The init function """ debugMsg("Called Scene.__init__()") BaseScene.__init__(self) self.renderer = Renderer() self.xSize = 640 self.ySize = 480 # these variables are used to determin the location of the camera self.centre = None self.bounds = None self.objectList = [] def add(self, obj): """ Add a new item to the scene @param obj: The object to add to the scene @type obj: object """ debugMsg("Called Scene.add()") if obj is None: raise ValueError, "You must specify an object to add" self.objectList.append(obj) return def place(self, obj): """ Place an object within a scene @param obj: The object to place within the scene @type obj: object """ debugMsg("Called Scene.place()") if obj is None: raise ValueError, "You must specify an object to place" return def render(self, pause=False, interactive=False, save=False): """ Render (or re-render) the scene Render the scene, either to screen, or to a buffer waiting for a save @param pause: Flag to wait at end of script evaluation for user input @type pause: boolean @param interactive: Whether or not to have interactive use of the output @type interactive: boolean @param save: Whether or not to save the output when render @type save: boolean """ debugMsg("Called Scene.render()") renderer = self.renderer # this is the string from which to make the ini file renderer.addToInitStack("; PyVisi Povray renderer module ini file") if pause: renderer.addToInitStack("Pause_When_Done=on") else: renderer.addToInitStack("Pause_When_Done=off") if interactive: print "Interactive mode not available with POVRAY renderer module" # add the standard headers evalString = "#include \"shapes.inc\"\n" evalString += "#include \"colors.inc\"\n" # add a camera (this should be its own object, and I should just # call some method of its own to get the info needed) # given the centre and bounds variables, determine the location and # look_at variables # do some checking first if self.centre is None or self.bounds is None: raise ValueError, "Model centre or bounds not defined." # calculate the y height yHeight = self.bounds[3] - self.bounds[2] xWidth = self.bounds[1] - self.bounds[0] if yHeight > xWidth: dist = yHeight else: dist = xWidth zDepth = self.bounds[5] - self.bounds[4] angle = 67.380*math.pi/180.0 # povray default opp = dist*1.5/2.0 adj = opp/math.tan(angle/2.0) loc = adj + zDepth/2.0 + self.centre[2] # now write the camera to file evalString += "camera {\n" evalString += " location <%f, %f, -%f>\n" % \ (self.centre[0], self.centre[1], loc) evalString += " direction <0, 0, 1>\n" evalString += " up <0, 1, 0>\n" evalString += " right <4/3, 0, 0>\n" evalString += " look_at <%f, %f, -%f>\n" % \ (self.centre[0], self.centre[1], self.centre[2]) evalString += "}\n" # add the light source evalString += "light_source {\n" evalString += " <0, 0, -500>\n" evalString += " colour White\n" evalString += "}\n" renderer.runString(evalString) # write the resolution settings iniString = "Width=%d\n" % self.xSize iniString += "Height=%d\n" % self.ySize # might as well have antialiasing going iniString += "Antialias=on" renderer.addToInitStack(iniString) # get all objects in the scene to render themselves for obj in self.objectList: obj.render() # if saving to file don't render to the screen if save: renderer.addToInitStack("Output_To_File=on") renderer.addToInitStack("Display=off") else: renderer.addToInitStack("Output_To_File=off") renderer.addToInitStack("Display=on") # optionally print out the evaluation stack to make sure we're doing # the right thing debugMsg("Here is the evaluation stack") debugMsg(60*"#") debugMsg(renderer.getEvalStack()) debugMsg(60*"#") if save: import re r = re.compile(r'\.\w+') self.fname = r.sub('', self.fname) povFname = "%s.pov" % self.fname iniFname = "%s.ini" % self.fname else: import time timeString = str(time.clock()) povFname = "povPlot%s.pov" % timeString iniFname = "povPlot%s.ini" % timeString renderer.addToInitStack("Input_File_Name=%s" % povFname) ### generate the pov file pov = open(povFname, "w") pov.write(renderer.getEvalStack()) pov.close() ### generate the ini file ini = open(iniFname, "w") ini.write(renderer.getInitStack()) ini.close() # now compile the string object into code, and execute it if os.system("povray %s" % iniFname) != 0: print "evalStack execution failed" print "evalStack = \'%s\'" % renderer.getEvalStack() return None # flush the evaluation stack debugMsg("Flusing evaluation stack") renderer.resetEvalStack() # flush the init stack debugMsg("Flushing init stack") renderer.resetInitStack() # clean up a bit os.unlink(povFname) os.unlink(iniFname) return def save(self, fname, format): """ Save the scene to a file Possible formats are: - PNG - TGA (uncompressed targa) - CTGA (compressed targa) - PPM - SYS (e.g. BMP on Windows, PICT on MacOS) @param fname: the name of the file to save to @type fname: string @param format: the image format of the output file @type format: Image object or string """ debugMsg("Called Scene.save()") self.renderer.runString("// Scene.save()") # if the format is passed in as a string or object, react # appropriately import types if type(format) is types.StringType: fmt = format.lower() else: fmt = format.format if fmt == "png": self.renderer.addToInitStack("Output_File_Type=N") elif fmt == "tga": self.renderer.addToInitStack("Output_File_Type=T") elif fmt == "ppm": self.renderer.addToInitStack("Output_File_Type=P") elif fmt == "ctga": self.renderer.addToInitStack("Output_File_Type=C") elif fmt == "sys": self.renderer.addToInitStack("Output_File_Type=S") else: raise ValueError, "Unknown graphics format. I got %s" % fmt self.fname = fname # rerender the scene to get the output self.render(save=True) return # set up an alias for the save method write = save def setBackgroundColor(self, *color): """ Sets the background color of the Scene @param color: The color to set the background to. Can be RGB or CMYK @type color: tuple """ debugMsg("Called Scene.setBackgroundColor()") # pity this code doesn't work.... # need to check on the values given in the *color array. # if they're greater than 1, scale so that the largest is 1 #maxColor = None #for i in range(len(color)): #if color[i] > 1: #maxColor = color[i] #print maxColor # ## if a maximum colour is found, then scale the colours #if maxColor is not None: #for i in range(len(color)): #color[i] = color[i]/maxColor # if color is of length 3, then we have rgb # if length is 4 then cmyk # if length is 1 then greyscale # otherwise barf if len(color) == 3: # ok, using rgb # probably should use a Color object or something # this will do in the meantime pass else: raise ValueError, "Sorry, only RGB color is supported at present" return def getBackgroundColor(self): """ Gets the current background colour/color setting of the Scene """ debugMsg("Called Scene.getBackgroundColor()") return