def __init__(self,kind=None,keys=None,set=None,type='FIELD',variable='PRESELECT',extra='',**options): """ Create new output request. - `type`: 'FIELD' or 'HISTORY' - `kind`: None, 'NODE', or 'ELEMENT' (first character suffices) - `extra`: an extra string to be added to the command line. This allows to add Abaqus options not handled by this constructor. The string will be appended to the command line preceded by a comma. For kind=='': - `variable`: 'ALL', 'PRESELECT' or '' For kind=='NODE' or 'ELEMENT': - `keys`: a list of output identifiers (compatible with kind type) - `set`: a single item or a list of items, where each item is either a property number or a node/element set name for which the results should be written. If no set is specified, the default is 'Nall' for kind=='NODE' and 'Eall' for kind='ELEMENT' """ if 'history' in options: GD.warning("The `history` argument in an output request is deprecated.\nPlease use `type='history'` instead.") if 'numberinterval' in options: GD.warning("The `numberinterval` argument in an output request is deprecated.\nPlease use the `extra` argument instead.") if kind: kind = kind[0].upper() if set is None: set = "%sall" % kind Dict.__init__(self,{'kind':kind}) if kind is None: self.update({'type':type,'variable':variable,'extra':extra}) else: self.update({'keys':keys,'set':set})
def createMovieInteractive(): """Create a movie from a saved sequence of images. """ if not image.multisave: pf.warning('You need to start multisave mode first!') return names = image.multisave[0] glob = names.glob() res = draw.askItems( [ _I('files', glob), _I('encoder', choices=['mencoder', 'convert', 'ffmpeg']), _G('Mencoder', [ _I('fps', 10), _I('vbirate', 800), ]), _G('Convert', [ _I('delay', 1), _I('colors', 256), ]), ], enablers = [ ('encoder', 'mencoder', 'Mencoder'), ('encoder', 'convert', 'Convert'), ]) if not res: return pf.GUI.setBusy() image.createMovie(**res) pf.GUI.setBusy(False)
def okColor(self, color, colormap=None): """Compute a color usable by the shader. The shader (currently) only supports 3*float type of colors: - None - single color (separate for front and back faces) - vertex colors """ if isinstance(color, str): if color == 'prop' and hasattr(self.object, 'prop'): color = self.object.prop elif color == 'random': # create random colors color = np.random.rand(self.object.nelems(), 3) elif color.startswith('fld:'): # get colors from a named field fld = self.object.getField(color[4:]) if fld and fld.fldtype == 'node': color = fld.data colormap = None else: pf.warning("Could not set color from field %s" % color) color, colormap = saneColorSet(color, colormap, self.fcoords.shape) if color is not None: if color.dtype.kind == 'i': # We have a color index if colormap is None: colormap = np.array(colors.palette) color = colormap[color] return color
def createMovie(encoder='ffmpeg'): """Create a movie from a saved sequence of images. encoder is one of: 'ffmpeg, mencoder, convert' """ if not multisave: pf.warning('You need to start multisave mode first!') return names,format,quality,window,border,hotkey,autosave,rootcrop = multisave glob = names.glob() ## if glob.split('.')[-1] != 'jpg': ## pf.warning("Currently you need to save in 'jpg' format to create movies") ## return if encoder == 'convert': cmd = "convert -delay 1 -colors 256 %s output.gif" % names.glob() elif encoder == 'mencoder': cmd = "mencoder -ovc lavc -fps 5 -o output.avi %s" % names.glob() elif encoder == 'mencoder1': cmd = "mencoder \"mf://%s\" -mf fps=10 -o output1.avi -ovc lavc -lavcopts vcodec=msmpeg4v2:vbitrate=800" % names.glob() else: cmd = "ffmpeg -qscale 1 -r 1 -i %s output.mp4" % names.glob() pf.debug(cmd) utils.runCommand(cmd)
def createMovieInteractive(): """Create a movie from a saved sequence of images. """ if not image.multisave: pf.warning('You need to start multisave mode first!') return names = image.multisave[0] glob = names.glob() res = draw.askItems( [ _I('files',glob), _I('encoder',choices=['mencoder','convert','ffmpeg']), _G('Mencoder',[ _I('fps',10), _I('vbirate',800), ]), _G('Convert',[ _I('delay',1), _I('colors',256), ]), ], enablers = [ ('encoder','mencoder','Mencoder'), ('encoder','convert','Convert'), ]) if not res: return pf.GUI.setBusy() image.createMovie(**res) pf.GUI.setBusy(False)
def submitJob(srcdir,tgtdir,include=[],delete_old=True): """Submit a cluster job in srcdir to the tgtdir. This will copy the specified include files from srcdir to the tgtdir, making sure that a file '*.request' is only copied after all other files have been copied. If no includes are given, all files in the srcdir are copied. For example, to submit a simple abaqus job from a folder with multiple job files, you can do:: submitJob('myjobdir','bumpfs1:bumper/requests/jobname',include=['*.inp']) To submit a job having its own input folder equal to the job name, do:: submitJob('myjobdir/jobname','bumpfs1:bumper/requests/jobname') """ if delete_old: P = rsyncFiles(srcdir,tgtdir,include=[],exclude=['*'],exclude_first=True,opts=' -rv --delete --delete-excluded') if P.sta: pf.warning("Could not delete old files from request folder!") if include: P = rsyncFiles(srcdir,tgtdir,include=include,exclude=['*']) else: P = rsyncFiles(srcdir,tgtdir,exclude=['*.request'],include=include,exclude_first=True) if P.sta: print(P.out) else: P = rsyncFiles(srcdir,tgtdir,include=['*.request'],exclude=['*']) if P.sta: pf.warning("Some error occurred during file transfer!")
def readAttrib(self,attrib=None,**kargs): """Read an Attributes dict defined on the last read geometry. """ try: self.geometry.attrib(**attrib) except: # Attributes readback may produce an error with # complex data types, e.g. vertex color array pf.warning("GeometryFile.read: Error while reading an Attribute block. The current version does not support the readback of some complex attribute data types (like a vertex color array). All attributes in this block will be skipped.")
def openProject(fn=None,exist=False,access=['wr','rw','w','r'],default=None): """Open a (new or old) Project file. A dialog is presented to ask the user for a Project file name and the access modalities. The parameters help in setting sensible defaults for the user and in delimiting his options. Depending on he results of the dialog, either a new project is created or an old one is opened, or nothing is done. If a project is opened, it is returned, else the return value is None. Parameters: - `fn`: filename: if specified, the Project file dialog will start with the specified file, otherwise it will start in the current directory. - `exist`: boolean: if False (default), the user can create new project files as well as open existing ones. Use exist=True or :func:`openExistingProject` to only accept existing project files. - `access`: a list of :class:`Project` access modes to be presented to the user. - `default`: the access mode that is presented as default to the user. If not specified, the first option of `access` will be the default. """ if type(access) == str: access = [access] cur = fn if fn else '.' typ = utils.fileDescription(['pyf','all']) res = widgets.ProjectSelection(cur,typ,exist=exist,access=access,default=default,convert=True).getResult() if not res: return fn = res.fn if not fn.endswith('.pyf'): fn += '.pyf' access = res.acc compression = res.cpr convert = res.cvt signature = pf.fullVersion() # OK, we have all data, now create/open the project pf.message("Opening project %s" % fn) pf.GUI.setBusy() # loading may take a while try: proj = project.Project(fn,access=access,convert=convert,signature=signature,compression=compression) if proj.signature != signature: pf.warning("The project was written with %s, while you are now running %s. If the latter is the newer one, this should probably not cause any problems. Saving is always done in the current format of the running version. Save your project and this message will be avoided on the next reopening." % (proj.signature,signature)) except: proj = None raise finally: pf.GUI.setBusy(False) proj.hits = 0 pf.debug("START COUNTING HITS",pf.DEBUG.PROJECT) return proj
def openProject(fn=None,exist=False,access=['wr', 'rw', 'w', 'r'],default=None): """Open a (new or old) Project file. A dialog is presented to ask the user for a Project file name and the access modalities. The parameters help in setting sensible defaults for the user and in delimiting his options. Depending on he results of the dialog, either a new project is created or an old one is opened, or nothing is done. If a project is opened, it is returned, else the return value is None. Parameters: - `fn`: filename: if specified, the Project file dialog will start with the specified file, otherwise it will start in the current directory. - `exist`: boolean: if False (default), the user can create new project files as well as open existing ones. Use exist=True or :func:`openExistingProject` to only accept existing project files. - `access`: a list of :class:`Project` access modes to be presented to the user. - `default`: the access mode that is presented as default to the user. If not specified, the first option of `access` will be the default. """ if isinstance(access, str): access = [access] cur = fn if fn else '.' res = widgets.ProjectSelection(cur, ['pyf', 'all'], exist=exist, access=access, default=default, convert=True).getResults() if not res: return fn = res.fn if not fn.endswith('.pyf'): fn += '.pyf' access = res.acc compression = res.cpr convert = res.cvt signature = pf.fullVersion() # OK, we have all data, now create/open the project print("Opening project %s" % fn) pf.GUI.setBusy() # loading may take a while try: proj = project.Project(fn, access=access, convert=convert, signature=signature, compression=compression) if proj.signature != signature: pf.warning("The project was written with %s, while you are now running %s. If the latter is the newer one, this should probably not cause any problems. Saving is always done in the current format of the running version. Save your project and this message will be avoided on the next reopening." % (proj.signature, signature)) except: proj = None raise finally: pf.GUI.setBusy(False) proj.hits = 0 pf.debug("START COUNTING HITS", pf.DEBUG.PROJECT) return proj
def check(trypaths=None): """Warn the user that calpy was not found.""" if calpy_path is None: detect(trypaths) try: import calpy except ImportError: pass if not utils.hasModule('calpy',check=True): GD.warning("sys.path=%s\nSorry, I can not run this example, because you do not have calpy installed (at least not in a place where I can find it)." % sys.path) exit()
def write(self, geom, name=None, sep=None): """Write any geometry object to the geometry file. `geom` is one of the Geometry data types of pyFormex or a list or dict of such objects. It can also be a WebGL objdict. Currently exported geometry objects are :class:`Coords`, :class:`Formex`, :class:`Mesh`, :class:`PolyLine`, :class:`BezierSpline`. The geometry object is written to the file using the specified separator, or the default. """ self.checkWritable() if isinstance(geom, dict): for name in geom: self.write(geom[name], name, sep) elif isinstance(geom, list): if name is None: for obj in geom: if hasattr(obj, 'obj'): #This must be a WebGL object dict self.writeDict(obj, sep=sep) else: if hasattr(obj, 'name'): objname = obj.name else: objname = None self.write(obj, objname, sep) else: name = utils.NameSequence(name) for obj in geom: self.write(obj, name.next(), sep) elif hasattr(geom, 'write_geom'): geom.write_geom(self, name, sep) else: try: writefunc = getattr(self, 'write' + geom.__class__.__name__) except: warning( "Can not (yet) write objects of type %s to geometry file: skipping" % type(geom)) return try: writefunc(geom, name, sep) except: warning( "Error while writing objects of type %s to geometry file: skipping" % type(geom)) raise
def addScene(self,name=None,camera=True): """Add the current OpenGL scene to the WebGL model. This method adds all the geometry in the current viewport to the WebGL model. By default it will also add the current camera and export the scene as a completed WebGL model with the given name. Parameters: - `name`: a string with the name of the model for the current scene. When multiple scenes are exported, they will be identified by this name. This name is also used as the basename for the exported geometry files. For a single scene export, the name may be omitted, and will then be set equal to the name of the WebGL exporter. If no name is specified, the model is not exported. This allows the user to add more scenes to the same model, and then to explicitely export it with :func:`exportScene`. - `camera`: bool or dict : if True, sets the current viewport camera as the camera in the WebGL model. If False the default camera values of WebGL will be used. If dict the camera values will be taken from the dictionary. """ self._actors = List() self._gui = [] self.bgcolor = pf.canvas.settings.bgcolor print("Exporting %s actors from current scene" % len(pf.canvas.actors)) sorted_actors = [ a for a in pf.canvas.actors if a.opak ] + [ a for a in pf.canvas.actors if not a.opak ] for i, a in enumerate(sorted_actors): o = a.object atype = type(a).__name__ otype = type(o).__name__ pf.debug("Actor %s: %s %s Shape=(%s,%s) Color=%s"% (i, atype, otype, o.nelems(), o.nplex(), a.color), pf.DEBUG.WEBGL) self.addActor(a) if camera is True: ca = pf.canvas.camera print(ca.report()) if not np.allclose(ca.area,((0.,0.),(1.,1.))): pf.warning("You current display uses soft zooming. The exported WebGL model currently does not have that feature, so the displayed area may be different from the pyFormex view.\nTo create a pyFormex display without soft zooming, use Camera->ZoomAll and the zoom in or out using only the Camera->DollyIn and/or Camera->Dolly/Out.") self.setCamera(focus=ca.focus, position=ca.eye, up=ca.upvector) elif camera is False: self._camera = None else: self.setCamera(**camera) if name: self.exportScene(name)
def checkImageFormat(fmt,verbose=False): """Checks image format; if verbose, warn if it is not. Returns the image format, or None if it is not OK. """ GD.debug("Format requested: %s" % fmt) GD.debug("Formats available: %s" % imageFormats()) if fmt in imageFormats(): if fmt == 'tex' and verbose: GD.warning("This will only write a LaTeX fragment to include the 'eps' image\nYou have to create the .eps image file separately.\n") return fmt else: if verbose: error("Sorry, can not save in %s format!\n" "I suggest you use 'png' format ;)"%fmt) return None
def createMovie(): """Create a movie from a saved sequence of images.""" if not multisave: GD.warning('You need to start multisave mode first!') return names,format,window,border,hotkey,autosave,rootcrop = multisave glob = names.glob() if glob.split('.')[-1] != 'jpg': GD.warning("Currently you need to save in 'jpg' format to create movies") return #cmd = "mencoder -ovc lavc -fps 5 -o output.avi %s" % names.glob() cmd = "ffmpeg -r 1 -i %s output.mp4" % names.glob() GD.debug(cmd) utils.runCommand(cmd)
def check(trypaths=None): """Warn the user that calpy was not found.""" if calpy_path is None: detect(trypaths) try: import calpy except ImportError: pass if utils.hasModule('calpy', check=True): return True else: pf.warning( "sys.path=%s\nSorry, I can not run this example, because you do not have calpy installed (at least not in a place where I can find it)." % sys.path) return False
def write(self,geom,name=None,sep=None): """Write any geometry object to the geometry file. `geom` is one of the Geometry data types of pyFormex or a list or dict of such objects. It can also be a WebGL objdict. Currently exported geometry objects are :class:`Coords`, :class:`Formex`, :class:`Mesh`, :class:`PolyLine`, :class:`BezierSpline`. The geometry object is written to the file using the specified separator, or the default. """ self.checkWritable() if isinstance(geom,dict): for name in geom: self.write(geom[name],name,sep) elif isinstance(geom,list): if name is None: for obj in geom: if hasattr(obj,'obj'): #This must be a WebGL object dict self.writeDict(obj,sep=sep) else: if hasattr(obj,'name'): objname = obj.name else: objname = None self.write(obj,objname,sep) else: name = utils.NameSequence(name) for obj in geom: self.write(obj,name.next(),sep) elif hasattr(geom,'write_geom'): geom.write_geom(self,name,sep) else: try: writefunc = getattr(self,'write'+geom.__class__.__name__) except: warning("Can not (yet) write objects of type %s to geometry file: skipping" % type(geom)) return try: writefunc(geom,name,sep) except: warning("Error while writing objects of type %s to geometry file: skipping" % type(geom)) raise
def addMaterial(self, material): """Create or replace the material properties of the element. If the argument is a dict, it will be added to the global MaterialDB. If the argument is a string, this string will be used as a key to search in the global MaterialDB. """ if isinstance(material, str) : if material in _matDB: self.material = _matDB[material] else: pf.warning("Material '%s' is not in the database" % material) elif isinstance(material, dict): _matDB[material['name']] = CDict(material) self.material = _matDB[material['name']] elif material==None: self.material=material else: raise ValueError,"Expected a string or a dict"
def checkImageFormat(fmt, verbose=True): """Checks image format; if verbose, warn if it is not. Returns the image format, or None if it is not OK. """ pf.debug("Format requested: %s" % fmt, pf.DEBUG.IMAGE) pf.debug("Formats available: %s" % imageFormats(), pf.DEBUG.IMAGE) if fmt in imageFormats(): if fmt == 'tex' and verbose: pf.warning( "This will only write a LaTeX fragment to include the 'eps' image\nYou have to create the .eps image file separately.\n" ) return fmt else: if verbose: import draw draw.error("Sorry, can not save in %s format!\n" "I suggest you use 'png' format ;)" % fmt) return None
def addMaterial(self, material): """Create or replace the material properties of the element. If the argument is a dict, it will be added to the global MaterialDB. If the argument is a string, this string will be used as a key to search in the global MaterialDB. """ if isinstance(material, str) : if material in _matDB: self.material = _matDB[material] else: pf.warning("Material '%s' is not in the database" % material) elif isinstance(material, dict): _matDB[material['name']] = CDict(material) self.material = _matDB[material['name']] elif material is None: self.material=material else: raise ValueError("Expected a string or a dict")
def checkPrintSyntax(filename): """Check whether the script in the given files uses print function syntax. Returns the compiled object if no error was found during compiling. Returns the filename if an error was found and correction has been attempted. Raises an exception if an error is found and no correction attempted. """ with open(filename, 'r') as f: try: script = f.read() scr = compile(script, filename, 'exec') return scr except SyntaxError as err: if re.compile('.*print +[^ (]').match(err.text): ans = pf.warning( """.. Syntax error in line %s of %s:: %s It looks like your are using a print statement instead of the print function. In order to prepare you for the future (Python3), pyFormex already enforces the use of the print function. This means that you have to change any print statement from:: print something into a print function call:: print(something) You can try an automatic conversion with the command:: 2to3 -f print -%s If you want, I can run this command for you now. Beware though! This will overwrite the contents of file %s. Also, the automatic conversion is not guaranteed to work, because there may be other errors. """ % (err.lineno, err.filename, err.text, filename, filename), actions=['Not this time', 'Convert now'], ) if ans == 'Convert now': print(ans) if convertPrintSyntax(filename): print( "Script properly converted, now running the converted script" ) return filename raise
def toggleAppScript(): import apps appname = pf.cfg['curfile'] if utils.is_script(appname): appdir = apps.findAppDir(os.path.dirname(appname)) if appdir: appname = os.path.basename(appname) if appname.endswith('.py'): appname = appname[:-3] pkgname = appdir.pkg appname = "%s.%s" % (pkgname,appname) pf.GUI.setcurfile(appname) else: pf.warning("This script is not in an application directory.\n\nYou should add the directory path '%s' to the application paths before you can run this file as an application.") else: fn = apps.findAppSource(appname) if os.path.exists(fn): pf.GUI.setcurfile(fn) else: pf.warning("I can not find the source file for this application.")
def editPreferences(): """Edit the preferences file This allows the user to edit all his stored preferences through his normal editor. The current preferences are saved to the user preferences file before it is loaded in the editor. When the user saves the preferences file, the stored preferences will be reloaded into pyFormex. This will remain active until the user selects the 'File->Save Preferences Now' option from the GUI. """ from ..main import savePreferences if pf.preffile is None: pf.warning("You have no writable preferences file") return if not savePreferences(): if pf.warning("Could not save to preferences file %s\nEdit the file anyway?" % pf.preffile) == 'Cancel': return pf.GUI.filewatch.addWatch(pf.preffile, reloadPreferences) P = draw.editFile(pf.preffile)
def addSection(self, section): """Create or replace the section properties of the element. If 'section' is a dict, it will be added to the global SectionDB. If 'section' is a string, this string will be used as a key to search in the global SectionDB. """ if isinstance(section, str): if section in _secDB: self.section = _secDB[section] else: pf.warning("Section '%s' is not in the database" % section) elif isinstance(section, dict): # WE COULD ADD AUTOMATIC CALCULATION OF SECTION PROPERTIES #self.computeSection(section) #print(section) _secDB[section['name']] = CDict(section) self.section = _secDB[section['name']] elif section is None: self.section = section else: raise ValueError("Expected a string or a dict")
def addSection(self, section): """Create or replace the section properties of the element. If 'section' is a dict, it will be added to the global SectionDB. If 'section' is a string, this string will be used as a key to search in the global SectionDB. """ if isinstance(section, str): if section in _secDB: self.section = _secDB[section] else: pf.warning("Section '%s' is not in the database" % section) elif isinstance(section,dict): # WE COULD ADD AUTOMATIC CALCULATION OF SECTION PROPERTIES #self.computeSection(section) #print(section) _secDB[section['name']] = CDict(section) self.section = _secDB[section['name']] elif section==None: self.section = section else: raise ValueError,"Expected a string or a dict"
def writeGeometry(self,geom,name=None,sep=None): """Write a single Geometry object to the Geometry File. Writes a single Geometry object to the Geometry File, using the specified name and separator. Parameters: - `geom`: a supported Geometry type object. Currently supported Geometry objects are :class:`Coords`, :class:`Formex`, :class:`Mesh`, :class:`PolyLine`, :class:`BezierSpline`. Other types are skipped, and a message is written, but processing continues. - `name`: string: the name of the object to be stored in the file. If not specified, and the object has an `attrib` dict containing a name, that value is used. Else an object name is generated from the file name. On readback, the object names are used as keys to store the objects in a dict. - `sep`: string: defines the separator to be used for writing this object. If not specified, the value given in the constructor will be used. This argument allows to override it on a per object base. Returns 1 if the object has been written, 0 otherwise. """ self.checkWritable() try: writefunc = getattr(self, 'write'+geom.__class__.__name__) except: pf.warning("Can not (yet) write objects of type %s to geometry file: skipping" % type(geom)) return 1 if name is None: name = geom.attrib.name if name is None: name = next(self.autoname) try: writefunc(geom, name, sep) except: pf.warning("Error while writing objects of type %s to geometry file: skipping" % type(geom)) raise if geom.attrib and Version(self.version) >= Version('2.0'): try: self.writeAttrib(geom.attrib) except: pf.warning("Error while writing objects of type %s to geometry file: skipping" % type(geom)) raise return 0
def checkPrintSyntax(filename): """Check whether the script in the given files uses print function syntax. Returns the compiled object if no error was found during compiling. Returns the filename if an error was found and correction has been attempted. Raises an exception if an error is found and no correction attempted. """ with open(filename,'r') as f: try: script = f.read() scr = compile(script,filename,'exec') return scr except SyntaxError as err: if re.compile('.*print +[^ (]').match(err.text): ans = pf.warning(""".. Syntax error in line %s of %s:: %s It looks like your are using a print statement instead of the print function. In order to prepare you for the future (Python3), pyFormex already enforces the use of the print function. This means that you have to change any print statement from:: print something into a print function call:: print(something) You can try an automatic conversion with the command:: 2to3 -f print -%s If you want, I can run this command for you now. Beware though! This will overwrite the contents of file %s. Also, the automatic conversion is not guaranteed to work, because there may be other errors. """ % (err.lineno,err.filename,err.text,filename,filename),actions=['Not this time','Convert now'],) if ans == 'Convert now': print(ans) if convertPrintSyntax(filename): message("Script properly converted, now running the converted script") return filename raise
def multitask(tasks, nproc=-1): """Perform tasks in parallel. Runs a number of tasks in parallel over a number of subprocesses. Parameters: - `tasks` : a list of (function,args) tuples, where function is a callable and args is a tuple with the arguments to be passed to the function. - ` nproc`: the number of subprocesses to be started. This may be different from the number of tasks to run: processes finishing a task will pick up a next one. There is no benefit in starting more processes than the number of tasks or the number of processing units available. The default will set `nproc` to the minimum of these two values. """ if nproc < 0: nproc = min(len(tasks), cpu_count()) pf.debug("Multiprocessing using %s processors" % nproc, pf.DEBUG.MULTI) # if pf.scriptMode == 'script': if __name__ == '__draw__': if pf.warning(""".. Multiprocessing in 'script' mode ================================ You are trying to use multiprocessing while running in 'script' mode. Multiprocessing in 'script' mode may cause pyFormex to hang indefinitely. We strongly advice you to cancel the operation now and to run your application in 'app' mode. Multiprocessing runs fine in 'app' mode. """, actions=[ 'Cancel', 'I know the risks and insist on continuing' ]) == 'Cancel': return pool = Pool(nproc) res = pool.map(dofunc, tasks) pool.close() return res
def run(argv=[]): """This is a fairly generic main() function. It is responsible for reading the configuration file(s), processing the command line options and starting the application. The basic configuration file is 'pyformexrc' located in the pyformex directory. It should always be present and be left unchanged. You can copy this file to another location if you want to make changes. By default, pyformex will try to read the following extra configuration files (in this order: default settings: <pyformexdir>/pyformexrc system-wide settings: /etc/pyformexrc user settings: $HOME/.pyformex/pyformexrc local settings $PWD/.pyformexrc Also, an extra config file can be specified in the command line. Config file settings always override previous ones. On exit, the preferences that were changed are written to the last read config file. Changed settings are those that differ from the settings in all but the last one. """ # Create a config instance pyformex.cfg = Config() # Fill in the pyformexdir and homedir variables # (use a read, not an update) if os.name == 'posix': homedir = os.environ['HOME'] elif os.name == 'nt': homedir = os.environ['HOMEDRIVE']+os.environ['HOMEPATH'] pyformex.cfg.read("pyformexdir = '%s'\n" % pyformexdir) pyformex.cfg.read("homedir = '%s'\n" % homedir) # Read the defaults (before the options) defaults = os.path.join(pyformexdir,"pyformexrc") pyformex.cfg.read(defaults) # Process options import optparse from optparse import make_option as MO parser = optparse.OptionParser( # THE Qapp options are removed, because it does not seem to work !!! # SEE the comments in the gui.startGUI function usage = "usage: %prog [<options>] [ [ scriptname [scriptargs] ] ...]", version = utils.FullVersion(), description = pyformex.Description, formatter = optparse.TitledHelpFormatter(), option_list=[ MO("--gui", action="store_true", dest="gui", default=None, help="start the GUI (default if no scriptfile argument is given)", ), MO("--nogui", action="store_false", dest="gui", default=None, help="do not load the GUI (default if a scriptfile argument is given)", ), MO("--interactive",'-i', action="store_true", dest="interactive", default=False, help="Go into interactive mode after processing the command line parameters. This is implied by the --gui option.", ), MO("--force-dri", action="store_true", dest="dri", default=None, help="Force use of Direct Rendering", ), MO("--force-nodri", action="store_false", dest="dri", default=None, help="Disables the Direct Rendering", ), MO("--uselib", action="store_true", dest="uselib", default=None, help="Use the pyFormex C lib if available. This is the default.", ), MO("--nouselib", action="store_false", dest="uselib", default=None, help="Do not use the pyFormex C-lib.", ), MO("--fastencode", action="store_true", dest="fastencode", default=False, help="Use a fast algorithm to encode edges.", ), MO("--norst2html", action="store_false", dest="rst2html", default=True, help="Do not try to convert rst messages to html before displaying.", ), MO("--config", action="store", dest="config", default=None, help="Use file CONFIG for settings", ), MO("--nodefaultconfig", action="store_true", dest="nodefaultconfig", default=False, help="Skip the default site and user config files. This option can only be used in conjunction with the --config option.", ), MO("--redirect", action="store_true", dest="redirect", default=False, help="Redirect standard output to the message board (ignored with --nogui)", ), MO("--debug", action="store_const", dest="debug", const=-1, help="display debugging info to sys.stdout", ), MO("--debuglevel", action="store", dest="debug", type="int", default=0, help="display debugging info to sys.stdout", ), ## MO("--classify", ## action="store_true", dest="classify", default=False, ## help="classify the examples in categories", ## ), MO("--newviewports", action="store_true", dest="newviewports", default=False, help="Use the new multiple viewport canvas implementation. This is an experimental feature only intended for developers.", ), MO("--testmodule", action="store", dest="testmodule", default=None, help="Run the docstring tests for module TESTMODULE. TESTMODULE is the name of the module, using . as path separator.", ), MO("--test", action="store_true", dest="test", default=False, help="testing mode: only for developers!", ), MO("--testexecutor", action="store_true", dest="executor", default=False, help="test alternate executor: only for developers!", ), MO("--remove", action="store_true", dest="remove", default=False, help="remove the pyformex installation and exit", ), MO("--whereami", action="store_true", dest="whereami", default=False, help="show where the pyformex package is installed and exit", ), MO("--detect", action="store_true", dest="detect", default=False, help="show detected helper software and exit", ), ]) pyformex.options, args = parser.parse_args(argv) pyformex.print_help = parser.print_help # process options if pyformex.options.nodefaultconfig and not pyformex.options.config: print("\nInvalid options: --nodefaultconfig but no --config option\nDo pyformex --help for help on options.\n") sys.exit() pyformex.debug("Options: %s" % pyformex.options) ########## Process special options which will not start pyFormex ####### if pyformex.options.remove or \ pyformex.options.whereami or \ pyformex.options.detect or \ pyformex.options.testmodule: if pyformex.options.remove: remove_pyFormex(pyformexdir,pyformex.scriptdir) if pyformex.options.whereami or pyformex.options.debug : print("Script started from %s" % pyformex.scriptdir) print("I found pyFormex in %s " % pyformexdir) print("Current Python sys.path: %s" % sys.path) if pyformex.options.detect or pyformex.options.debug : print("Detecting all installed helper software") utils.checkExternal() print(utils.reportDetected()) if pyformex.options.testmodule: for a in pyformex.options.testmodule.split(','): test_module(a) sys.exit() ########### Read the config files #################### # These values should not be changed pyformex.cfg.userprefs = os.path.join(pyformex.cfg.userconfdir,'pyformexrc') pyformex.cfg.autorun = os.path.join(pyformex.cfg.userconfdir,'startup.py') # Set the config files if pyformex.options.nodefaultconfig: sysprefs = [] userprefs = [] else: sysprefs = [ pyformex.cfg.siteprefs ] userprefs = [ pyformex.cfg.userprefs ] if os.path.exists(pyformex.cfg.localprefs): userprefs.append(pyformex.cfg.localprefs) if pyformex.options.config: userprefs.append(pyformex.options.config) if len(userprefs) == 0: # We should always have a place to store the user preferences userprefs = [ pyformex.cfg.userprefs ] pyformex.preffile = os.path.abspath(userprefs[-1]) # Settings will be saved here # Read all but the last as reference for f in filter(os.path.exists,sysprefs + userprefs[:-1]): pyformex.debug("Reading config file %s" % f) pyformex.cfg.read(f) pyformex.refcfg = pyformex.cfg pyformex.debug("="*60) pyformex.debug("RefConfig: %s" % pyformex.refcfg) # Use the last as place to save preferences pyformex.prefcfg = Config(default=refLookup) if os.path.exists(pyformex.preffile): pyformex.debug("Reading config file %s" % pyformex.preffile) pyformex.prefcfg.read(pyformex.preffile) pyformex.debug("="*60) pyformex.debug("Config: %s" % pyformex.prefcfg) # Fix incompatible changes in configuration apply_config_changes(pyformex.prefcfg) # Create an empty one for the session settings pyformex.cfg = Config(default=prefLookup) # This should probably be changed to options overriding config # Set option from config if it was not explicitely given if pyformex.options.uselib is None: pyformex.options.uselib = pyformex.cfg['uselib'] # Set default --nogui if first remaining argument is a pyformex script. if pyformex.options.gui is None: pyformex.options.gui = not (len(args) > 0 and utils.is_pyFormex(args[0])) if pyformex.options.gui: pyformex.options.interactive = True # Set Revision and run svnclean if we run from an SVN version if svnversion: setRevision() svnclean = os.path.join(pyformexdir,'svnclean') if os.path.exists(svnclean): try: utils.runCommand(svnclean) except: print("Error while executing %s, we ignore it and continue" % svnclean) def getSVNURL(): sta,out = utils.runCommand("cd %s;svn info | grep -F 'URL:'"%pyformexdir) if sta == 0: return out else: return '' ## s = getSVNURL() ## print s ## import re ## m = re.match(".*//(?P<user>[^@]*)@svn\.berlios\.de.*",s) ## pyformex.svnuser = m.group('user') ## print pyformex.svnuser ###### We have the config and options all set up ############ filterWarnings() def _format_warning(message,category,filename,lineno,line=None): """Replace the default warnings.formatwarning This allows the warnings being called using a simple mnemonic string. The full message is then found from the message module. """ import messages message = messages.getMessage(message) message = """.. pyFormex Warning ================ %s `Called from:` %s `line:` %s """ % (message,filename,lineno) if line: message += "%s\n" % line return message if pyformex.cfg['warnings/nice']: import warnings warnings.formatwarning = _format_warning # Start the GUI if needed # Importing the gui should be done after the config is set !! if pyformex.options.gui: from gui import guimain pyformex.debug("GUI version") res = guimain.startGUI(args) if res != 0: print("Could not start the pyFormex GUI: %s" % res) return res # EXIT # Display the startup warnings and messages if startup_warnings: if pyformex.cfg['startup_warnings']: pyformex.warning(startup_warnings) else: print(startup_warnings) if startup_messages: print(startup_messages) pyformex.debug(utils.reportDetected()) #print(pyformex.cfg.keys()) #print(pyformex.refcfg.keys()) # # Qt4 may have changed the locale. # Since a LC_NUMERIC setting other than C may cause lots of troubles # with reading and writing files (formats become incompatible!) # we put it back to a sane setting # utils.setSaneLocale() # Initialize the libraries #print("NOW LOAIDNG LIBS") #import lib #lib.init_libs(pyformex.options.uselib,pyformex.options.gui) # Prepend the autorun scripts ar = pyformex.cfg.get('autorun','') if ar : if type(ar) is str: ar = [ ar ] # expand tilde, as would bash ar = map(utils.tildeExpand,ar) args[0:0] = [ fn for fn in ar if os.path.exists(fn) ] # remaining args are interpreted as scripts and their parameters res = 0 if args: pyformex.debug("Remaining args: %s" % args) from script import processArgs res = processArgs(args) if res: if pyformex.options.gui: pyformex.message("There was an error while executing a script") else: return res # EXIT else: pyformex.debug("stdin is a tty: %s" % sys.stdin.isatty()) # Play script from stdin # Can we check for interactive session: stdin connected to terminal? #from script import playScript #playScript(sys.stdin) # after processing all args, go into interactive mode if pyformex.options.gui and pyformex.app: res = guimain.runGUI() ## elif pyformex.options.interactive: ## print("Enter your script and end with CTRL-D") ## from script import playScript ## playScript(sys.stdin) #Save the preferences that have changed savePreferences() # Exit return res
def writeSection(fil,prop): """Write an element section. prop is a an element property record with a section and eltype attribute """ out = "" setname = esetName(prop) el = prop.section eltype = prop.eltype.upper() mat = el.material if mat is not None: fil.write(fmtMaterial(mat)) if eltype in connector_elems: fil.write(fmtConnectorSection(el,setname)) elif eltype in frame_elems: fil.write(fmtFrameSection(el,setname)) elif eltype in truss_elems: if el.sectiontype.upper() == 'GENERAL': fil.write("""*SOLID SECTION, ELSET=%s, MATERIAL=%s %s """ %(setname,el.material.name, float(el.cross_section))) elif el.sectiontype.upper() == 'CIRC': fil.write("""*SOLID SECTION, ELSET=%s, MATERIAL=%s %s """ %(setname,el.material.name, float(el.radius)**2*pi)) ############ ##BEAM elements ########################## elif eltype in beam_elems: if el.integrate: fil.write(fmtBeamSection(el,setname)) else: fil.write(fmtGeneralBeamSection(el,setname)) ############ ## SHELL elements ########################## elif eltype in shell_elems: fil.write(fmtShellSection(el,setname,mat.name)) ############ ## SURFACE elements ########################## elif eltype in surface_elems: if el.sectiontype.upper() == 'SURFACE': fil.write("""*SURFACE SECTION, ELSET=%s \n""" % setname) ############ ## MEMBRANE elements ########################## elif eltype in membrane_elems: if el.sectiontype.upper() == 'MEMBRANE': if mat is not None: fil.write("""*MEMBRANE SECTION, ELSET=%s, MATERIAL=%s %s \n""" % (setname,mat.name,float(el.thickness))) ############ ## 3DSOLID elements ########################## elif eltype in solid3d_elems: if el.sectiontype.upper() == '3DSOLID': if mat is not None: fil.write("""*SOLID SECTION, ELSET=%s, MATERIAL=%s %s \n""" % (setname,mat.name,1.)) ############ ## 2D SOLID elements ########################## elif eltype in solid2d_elems: if el.sectiontype.upper() == 'SOLID': if mat is not None: fil.write("""*SOLID SECTION, ELSET=%s, MATERIAL=%s %s \n""" % (setname,mat.name,float(el.thickness))) ############ ## RIGID elements ########################## elif eltype in ['R2D2','RB2D2','RB3D2','RAX2','R3D3','R3D4']: if el.sectiontype.upper() == 'RIGID': fil.write("""*RIGID BODY,REFNODE=%s,density=%s, ELSET=%s\n""" % (el.nodeset,el.density,setname)) ############ ## UNSUPPORTED elements ########################## else: GD.warning('Sorry, elementtype %s is not yet supported' % eltype)
def save(filename=None,window=False,multi=False,hotkey=True,autosave=False,border=False,rootcrop=False,format=None,verbose=False): """Saves an image to file or Starts/stops multisave maode. With a filename and multi==False (default), the current viewport rendering is saved to the named file. With a filename and multi==True, multisave mode is started. Without a filename, multisave mode is turned off. Two subsequent calls starting multisave mode without an intermediate call to turn it off, do not cause an error. The first multisave mode will implicitely be ended before starting the second. In multisave mode, each call to saveNext() will save an image to the next generated file name. Filenames are generated by incrementing a numeric part of the name. If the supplied filename (after removing the extension) has a trailing numeric part, subsequent images will be numbered continuing from this number. Otherwise a numeric part '-000' will be added to the filename. If window is True, the full pyFormex window is saved. If window and border are True, the window decorations will be included. If window is False, only the current canvas viewport is saved. If hotkey is True, a new image will be saved by hitting the 'S' key. If autosave is True, a new image will be saved on each execution of the 'draw' function. If neither hotkey nor autosave are True, images can only be saved by executing the saveNext() function from a script. If no format is specified, it is derived from the filename extension. fmt should be one of the valid formats as returned by imageFormats() If verbose=True, error/warnings are activated. This is usually done when this function is called from the GUI. """ global multisave # Leave multisave mode if no filename or starting new multisave mode if multisave and (filename is None or multi): GD.message("Leave multisave mode") QtCore.QObject.disconnect(GD.gui,QtCore.SIGNAL("Save"),saveNext) multisave = None if filename is None: return #chdir(filename) name,ext = os.path.splitext(filename) # Get/Check format if not format: # is None: format = checkImageFormat(imageFormatFromExt(ext)) if not format: return if multi: # Start multisave mode names = utils.NameSequence(name,ext) if os.path.exists(names.peek()): next = names.next() GD.message("Start multisave mode to files: %s (%s)" % (names.name,format)) #print hotkey if hotkey: QtCore.QObject.connect(GD.gui,QtCore.SIGNAL("Save"),saveNext) if verbose: GD.warning("Each time you hit the '%s' key,\nthe image will be saved to the next number." % GD.cfg['keys/save']) multisave = (names,format,window,border,hotkey,autosave,rootcrop) print "MULTISAVE %s "% str(multisave) return multisave is None else: # Save the image if window: if rootcrop: sta = save_main_window(filename,format,border=border) else: sta = save_window(filename,format) else: sta = save_canvas(GD.canvas,filename,format) if sta: GD.debug("Error while saving image %s" % filename) else: GD.message("Image file %s written" % filename) return
def save(filename=None, window=False, multi=False, hotkey=True, autosave=False, border=False, rootcrop=False, format=None, quality=-1, size=None, verbose=False): """Saves an image to file or Starts/stops multisave mode. With a filename and multi==False (default), the current viewport rendering is saved to the named file. With a filename and multi==True, multisave mode is started. Without a filename, multisave mode is turned off. Two subsequent calls starting multisave mode without an intermediate call to turn it off, do not cause an error. The first multisave mode will implicitely be ended before starting the second. In multisave mode, each call to saveNext() will save an image to the next generated file name. Filenames are generated by incrementing a numeric part of the name. If the supplied filename (after removing the extension) has a trailing numeric part, subsequent images will be numbered continuing from this number. Otherwise a numeric part '-000' will be added to the filename. If window is True, the full pyFormex window is saved. If window and border are True, the window decorations will be included. If window is False, only the current canvas viewport is saved. If hotkey is True, a new image will be saved by hitting the 'S' key. If autosave is True, a new image will be saved on each execution of the 'draw' function. If neither hotkey nor autosave are True, images can only be saved by executing the saveNext() function from a script. If no format is specified, it is derived from the filename extension. fmt should be one of the valid formats as returned by imageFormats() If verbose=True, error/warnings are activated. This is usually done when this function is called from the GUI. """ #print "SAVE: quality=%s" % quality global multisave # Leave multisave mode if no filename or starting new multisave mode if multisave and (filename is None or multi): pf.message("Leave multisave mode") pf.GUI.signals.SAVE.disconnect(saveNext) multisave = None if filename is None: return #chdir(filename) name, ext = os.path.splitext(filename) # Get/Check format if not format: # is None: format = checkImageFormat(imageFormatFromExt(ext)) if not format: return if multi: # Start multisave mode names = utils.NameSequence(name, ext) if os.path.exists(names.peek()): next = names.next() pf.message("Start multisave mode to files: %s (%s)" % (names.name, format)) if hotkey: pf.GUI.signals.SAVE.connect(saveNext) if verbose: pf.warning( "Each time you hit the '%s' key,\nthe image will be saved to the next number." % pf.cfg['keys/save']) multisave = (names, format, quality, size, window, border, hotkey, autosave, rootcrop) print("MULTISAVE %s " % str(multisave)) return multisave is None else: # Save the image if window: if rootcrop: sta = save_main_window(filename, format, quality, border=border) else: sta = save_window(filename, format, quality) else: if size == pf.canvas.getSize(): size = None sta = save_canvas(pf.canvas, filename, format, quality, size) if sta: pf.debug("Error while saving image %s" % filename, pf.DEBUG.IMAGE) else: pf.message("Image file %s written" % filename) return
def updateQt4Bindings(): pf.warning("You changed the Python Qt4 bindings setting to '%s'.\nThis setting will only become active after you restart pyFormex." % pf.cfg['gui/bindings'])
def run(argv=[]): """This is a fairly generic main() function. It is responsible for reading the configuration file(s), processing the command line options and starting the application. The basic configuration file is 'pyformexrc' located in the pyformex directory. It should always be present and be left unchanged. You can copy this file to another location if you want to make changes. By default, pyformex will try to read the following extra configuration files (in this order: default settings: <pyformexdir>/pyformexrc system-wide settings: /etc/pyformexrc user settings: $HOME/.pyformex/pyformexrc local settings $PWD/.pyformexrc Also, an extra config file can be specified in the command line. Config file settings always override previous ones. On exit, the preferences that were changed are written to the last read config file. Changed settings are those that differ from the settings in all but the last one. """ # Create a config instance pf.cfg = Config() # Fill in the pyformexdir and homedir variables # (use a read, not an update) if os.name == 'posix': homedir = os.environ['HOME'] elif os.name == 'nt': homedir = os.environ['HOMEDRIVE'] + os.environ['HOMEPATH'] pf.cfg.read("pyformexdir = '%s'\n" % pyformexdir) pf.cfg.read("homedir = '%s'\n" % homedir) # Read the defaults (before the options) defaults = os.path.join(pyformexdir, "pyformexrc") pf.cfg.read(defaults) # Process options import optparse from optparse import make_option as MO parser = optparse.OptionParser( # THE Qapp options are removed, because it does not seem to work !!! # SEE the comments in the gui.startGUI function usage="usage: %prog [<options>] [ [ scriptname [scriptargs] ] ...]", version=pf.fullVersion(), description=pf.Description, formatter=optparse.TitledHelpFormatter(), option_list=[ MO( "--gui", action="store_true", dest="gui", default=None, help= "Start the GUI (this is the default when no scriptname argument is given)", ), MO( "--nogui", action="store_false", dest="gui", default=None, help= "Do not start the GUI (this is the default when a scriptname argument is given)", ), MO( "--interactive", action="store_true", dest="interactive", default=False, help= "Go into interactive mode after processing the command line parameters. This is implied by the --gui option.", ), MO( "--dri", action="store_true", dest="dri", default=None, help= "Use Direct Rendering Infrastructure. By default, direct rendering will be used if available.", ), MO( "--nodri", action="store_false", dest="dri", default=None, help= "Do not use the Direct Rendering Infrastructure. This may be used to turn off the direc rendering, e.g. to allow better capturing of images and movies.", ), MO( "--uselib", action="store_true", dest="uselib", default=None, help= "Use the pyFormex C lib if available. This is the default.", ), MO( "--nouselib", action="store_false", dest="uselib", default=None, help="Do not use the pyFormex C-lib.", ), MO( "--commands", action="store_true", dest="commands", default=False, help= "Use the commands module to execute external commands. Default is to use the subprocess module.", ), MO( "--config", action="store", dest="config", default=None, help="Use file CONFIG for settings", ), MO( "--nodefaultconfig", action="store_true", dest="nodefaultconfig", default=False, help= "Skip the default site and user config files. This option can only be used in conjunction with the --config option.", ), MO( "--redirect", action="store_true", dest="redirect", default=None, help= "Redirect standard output to the message board (ignored with --nogui)", ), MO( "--noredirect", action="store_false", dest="redirect", help="Do not redirect standard output to the message board.", ), MO( "--debug", action="store", dest="debug", default='', help= "Display debugging information to sys.stdout. The value is a comma-separated list of (case-insensitive) strings corresponding with the attributes of the DebugLevels class. The individual values are OR-ed together to produce a final debug value. The special value 'all' can be used to switch on all debug info.", ), MO( "--debuglevel", action="store", dest="debuglevel", type="int", default=0, help= "Display debugging info to sys.stdout. The value is an int with the bits of the requested debug levels set. A value of -1 switches on all debug info. If this option is used, it overrides the --debug option.", ), MO( "--newviewports", action="store_true", dest="newviewports", default=False, help= "Use the new multiple viewport canvas implementation. This is an experimental feature only intended for developers.", ), MO( "--testmodule", action="store", dest="testmodule", default=None, help= "Run the docstring tests for module TESTMODULE. TESTMODULE is the name of the module, using . as path separator.", ), MO( "--testcamera", action="store_true", dest="testcamera", default=False, help="Print camera settings whenever they change.", ), MO( "--testexecutor", action="store_true", dest="executor", default=False, help="Test alternate executor: only for developers!", ), MO( "--memtrack", action="store_true", dest="memtrack", default=False, help="Track memory for leaks. This is only for developers.", ), MO( "--fastnurbs", action="store_true", dest="fastnurbs", default=False, help="Test C library nurbs drawing: only for developers!", ), MO( "--pyside", action="store_true", dest="pyside", default=None, help="Use the PySide bindings for QT4 libraries", ), MO( "--pyqt4", action="store_false", dest="pyside", default=None, help="Use the PyQt4 bindings for QT4 libraries", ), MO( "--opengl2", action="store_true", dest="opengl2", default=False, help= "Use the new OpenGL rendering engine. This is an experimental feature only intended for developers.", ), MO( "--listfiles", action="store_true", dest="listfiles", default=False, help="List the pyformex Python source files.", ), MO( "--search", action="store_true", dest="search", default=False, help= "Search the pyformex source for a specified pattern and exit. This can optionally be followed by -- followed by options for the grep command and/or '-a' to search all files in the extended search path. The final argument is the pattern to search. '-e' before the pattern will interprete this as an extended regular expression. '-l' option only lists the names of the matching files.", ), MO( "--remove", action="store_true", dest="remove", default=False, help= "Remove the pyFormex installation and exit. This option only works when pyFormex was installed from a tarball release using the supplied install procedure. If you install from a distribution package (e.g. Debian), you should use your distribution's package tools to remove pyFormex. If you run pyFormex directly from SVN sources, you should just remove the whole checked out source tree.", ), MO( "--whereami", action="store_true", dest="whereami", default=False, help="Show where the pyformex package is installed and exit", ), MO( "--detect", action="store_true", dest="detect", default=False, help="Show detected helper software and exit", ), ]) pf.options, args = parser.parse_args(argv) pf.print_help = parser.print_help # Set debug level if pf.options.debug and not pf.options.debuglevel: pf.options.debuglevel = pf.debugLevel(pf.options.debug.split(',')) # process options if pf.options.nodefaultconfig and not pf.options.config: print( "\nInvalid options: --nodefaultconfig but no --config option\nDo pyformex --help for help on options.\n" ) sys.exit() pf.debug("Options: %s" % pf.options, pf.DEBUG.ALL) ########## Process special options which will not start pyFormex ####### if pf.options.testmodule: for a in pf.options.testmodule.split(','): test_module(a) return if pf.options.remove: remove_pyFormex(pyformexdir, pf.bindir) return if pf.options.whereami: # or pf.options.detect : pf.options.debuglevel |= pf.DEBUG.INFO pf.debug("pyformex script started from %s" % pf.bindir, pf.DEBUG.INFO) pf.debug("I found pyFormex installed in %s " % pyformexdir, pf.DEBUG.INFO) pf.debug("Current Python sys.path: %s" % sys.path, pf.DEBUG.INFO) if pf.options.detect: print("Detecting installed helper software") utils.checkExternal() print(utils.reportDetected()) if pf.options.whereami or pf.options.detect: return ########### Read the config files #################### # These values should not be changed pf.cfg.userprefs = os.path.join(pf.cfg.userconfdir, 'pyformexrc') # Set the config files if pf.options.nodefaultconfig: sysprefs = [] userprefs = [] else: sysprefs = [pf.cfg.siteprefs] userprefs = [pf.cfg.userprefs] if os.path.exists(pf.cfg.localprefs): userprefs.append(pf.cfg.localprefs) if pf.options.config: userprefs.append(pf.options.config) if len(userprefs) == 0: # We should always have a place to store the user preferences userprefs = [pf.cfg.userprefs] pf.preffile = os.path.abspath(userprefs[-1]) # Settings will be saved here # Read all but the last as reference for f in filter(os.path.exists, sysprefs + userprefs[:-1]): pf.debug("Reading config file %s" % f, pf.DEBUG.CONFIG) pf.cfg.read(f) pf.refcfg = pf.cfg pf.debug("=" * 60, pf.DEBUG.CONFIG) pf.debug("RefConfig: %s" % pf.refcfg, pf.DEBUG.CONFIG) # Use the last as place to save preferences pf.prefcfg = Config(default=refLookup) if os.path.exists(pf.preffile): pf.debug("Reading config file %s" % pf.preffile, pf.DEBUG.CONFIG) pf.prefcfg.read(pf.preffile) pf.debug("=" * 60, pf.DEBUG.CONFIG) pf.debug("Config: %s" % pf.prefcfg, pf.DEBUG.CONFIG) # Fix incompatible changes in configuration apply_config_changes(pf.prefcfg) # Create an empty one for the session settings pf.cfg = Config(default=prefLookup) #################################################################### ## Post config initialization ## # process non-starting options dependent on config if pf.options.search or pf.options.listfiles: if len(args) > 0: opts = [a for a in args if a.startswith('-')] args = [a for a in args if not a in opts] if '-a' in opts: opts.remove('-a') extended = True else: extended = False if len(args) > 1: files = args[1:] else: files = utils.sourceFiles(relative=True, extended=extended) if pf.options.listfiles: print('\n'.join(files)) else: cmd = "grep %s '%s' %s" % (' '.join(opts), args[0], ''.join( [" '%s'" % f for f in files])) #print(cmd) os.system(cmd) return # process other options dependent on config if pf.options.pyside is None: pf.options.pyside = pf.cfg['gui/bindings'].lower() == 'pyside' # process options that override the config if pf.options.redirect is not None: pf.cfg['gui/redirect'] = pf.options.redirect delattr(pf.options, 'redirect') # avoid abuse #print "REDIRECT",pf.cfg['gui/redirect'] ################################################################### # This should probably be changed to options overriding config # Set option from config if it was not explicitely given if pf.options.uselib is None: pf.options.uselib = pf.cfg['uselib'] # Set default --nogui if first remaining argument is a pyformex script. if pf.options.gui is None: pf.options.gui = not (len(args) > 0 and utils.is_pyFormex(args[0])) if pf.options.gui: pf.options.interactive = True # If we run from an source version, we should set the proper revision # number and run the svnclean procedure. if pf.installtype in 'SG': svnclean = os.path.join(pyformexdir, 'svnclean') if os.path.exists(svnclean): try: utils.system(svnclean) except: print("Error while executing %s, we ignore it and continue" % svnclean) ###### We have the config and options all set up ############ filterWarnings() def _format_warning(message, category, filename, lineno, line=None): """Replace the default warnings.formatwarning This allows the warnings being called using a simple mnemonic string. The full message is then found from the message module. """ import messages message = messages.getMessage(message) message = """.. pyFormex Warning ================ %s `Called from:` %s `line:` %s """ % (message, filename, lineno) if line: message += "%s\n" % line return message if pf.cfg['warnings/nice']: import warnings warnings.formatwarning = _format_warning utils.checkModule('numpy', fatal=True) # Make sure pf.PF is a Project from project import Project pf.PF = Project() utils.setSaneLocale() # Set application paths pf.debug("Loading AppDirs", pf.DEBUG.INFO) import apps apps.setAppDirs() # Start the GUI if needed # Importing the gui should be done after the config is set !! if pf.options.gui: from gui import guimain pf.debug("GUI version", pf.DEBUG.INFO) res = guimain.startGUI(args) if res != 0: print("Could not start the pyFormex GUI: %s" % res) return res # EXIT # Display the startup warnings and messages if startup_warnings: if pf.cfg['startup_warnings']: pf.warning(startup_warnings) else: print(startup_warnings) if startup_messages: print(startup_messages) if pf.options.debuglevel & pf.DEBUG.INFO: # NOTE: inside an if to avoid computing the report when not printed pf.debug(utils.reportDetected(), pf.DEBUG.INFO) # # Qt4 may have changed the locale. # Since a LC_NUMERIC setting other than C may cause lots of troubles # with reading and writing files (formats become incompatible!) # we put it back to a sane setting # utils.setSaneLocale() # Initialize the libraries #import lib #lib.init_libs(pf.options.uselib,pf.options.gui) # Prepend the autorun script ar = pf.cfg.get('autorun', '') if ar and os.path.exists(ar): args[0:0] = [ar] # remaining args are interpreted as scripts and their parameters res = 0 if args: pf.debug("Remaining args: %s" % args, pf.DEBUG.INFO) from script import processArgs res = processArgs(args) if res: if pf.options.gui: pf.message("There was an error while executing a script") else: return res # EXIT else: pf.debug("stdin is a tty: %s" % sys.stdin.isatty(), pf.DEBUG.INFO) # Play script from stdin # Can we check for interactive session: stdin connected to terminal? #from script import playScript #playScript(sys.stdin) # after processing all args, go into interactive mode if pf.options.gui and pf.app: res = guimain.runGUI() ## elif pf.options.interactive: ## print("Enter your script and end with CTRL-D") ## from script import playScript ## playScript(sys.stdin) #Save the preferences that have changed savePreferences() # Exit return res
def runApp(appname, argv=[], refresh=False, lock=True, check=True): """Run a pyFormex application. A pyFormex application is a Python module that can be loaded in pyFormex and that contains a function 'run()'. Running the application is equivalent to executing this function. Parameters: - `appname`: name of the module in Python dot notation. The module should live in a path included the the a file holding a pyFormex script. - `argv`: list of arguments. This variable can be changed by the app and the resulting argv will be returned to the caller. Returns the exit value of the run function. A zero value is supposed to mean a normal exit. """ global exitrequested if check and len(pf.scriptlock) > 0: print("!!Not executing because a script lock has been set: %s" % pf.scriptlock) return from pyformex import apps from pyformex.timer import Timer t = Timer() print("Loading application %s with refresh=%s" % (appname, refresh)) app = apps.load(appname, refresh=refresh) if app is None: errmsg = "An error occurred while loading application %s" % appname if pf.GUI: if apps._traceback and pf.cfg['showapploaderrors']: print(apps._traceback) from pyformex.gui import draw fn = apps.findAppSource(appname) if os.path.exists(fn): errmsg += "\n\nYou may try executing the application as a script,\n or you can load the source file in the editor." res = draw.ask(errmsg, choices=[ 'Run as script', 'Load in editor', "Don't bother" ]) if res[0] in 'RL': if res[0] == 'L': draw.editFile(fn) elif res[0] == 'R': pf.GUI.setcurfile(fn) draw.runScript(fn) else: errmsg += "and I can not find the application source file." draw.error(errmsg) else: error(errmsg) return if hasattr(app, '_opengl2') and not app._opengl2: pf.warning( "This Example can not yet be run under the pyFormex opengl2 engine.\n" ) return if hasattr(app, '_status') and app._status == 'unchecked': pf.warning( "This looks like an Example script that has been automatically converted to the pyFormex Application model, but has not been checked yet as to whether it is working correctly in App mode.\nYou can help here by running and rerunning the example, checking that it works correctly, and where needed fixing it (or reporting the failure to us). If the example runs well, you can change its status to 'checked'" ) if lock: scriptLock('__auto/app__') msg = "Running application '%s' from %s" % (appname, app.__file__) pf.scriptName = appname if pf.GUI: pf.GUI.startRun() pf.GUI.apphistory.add(appname) pf.GUI.board.write(msg, color='green') else: print(msg) pf.debug(" Passing arguments: %s" % argv, pf.DEBUG.SCRIPT) app._args_ = argv try: try: res = app.run() except SystemExit: print("EXIT FROM APP") pass except: raise finally: if hasattr(app, 'atExit'): app.atExit() if pf.cfg['autoglobals']: g = app.__dict__ autoExport(g) if lock: scriptRelease('__auto/app__') # release the lock if pf.GUI: pf.GUI.stopRun() pf.debug(" Arguments left after execution: %s" % argv, pf.DEBUG.SCRIPT) msg = "Finished %s in %s seconds" % (appname, t.seconds()) if pf.GUI: pf.GUI.board.write(msg, color='green') else: print(msg) pf.debug("Memory: %s" % vmSize(), pf.DEBUG.MEM) return res
def createCylinder(): pf.warning("This function has been moved to the Geometry menu")
def runApp(appname,argv=[],refresh=False): global exitrequested if len(pf.scriptlock) > 0: pf.message("!!Not executing because a script lock has been set: %s" % pf.scriptlock) #print(pf.scriptlock) return import apps from timer import Timer t = Timer() pf.message("Loading application %s with refresh=%s" % (appname,refresh)) app = apps.load(appname,refresh=refresh) if app is None: errmsg = "An error occurred while loading application %s" % appname if pf.GUI: if apps._traceback and pf.cfg['showapploaderrors']: print(apps._traceback) from gui import draw fn = apps.findAppSource(appname) if os.path.exists(fn): errmsg += "\n\nYou may try executing the application as a script,\n or you can load the source file in the editor." res = draw.ask(errmsg,choices=['Run as script', 'Load in editor', "Don't bother"]) if res[0] in 'RL': if res[0] == 'L': draw.editFile(fn) elif res[0] == 'R': pf.GUI.setcurfile(fn) draw.runScript(fn) else: errmsg += "and I can not find the application source file." draw.error(errmsg) else: error(errmsg) return if hasattr(app,'_status') and app._status == 'unchecked': pf.warning("This looks like an Example script that has been automatically converted to the pyFormex Application model, but has not been checked yet as to whether it is working correctly in App mode.\nYou can help here by running and rerunning the example, checking that it works correctly, and where needed fixing it (or reporting the failure to us). If the example runs well, you can change its status to 'checked'") scriptLock('__auto__') msg = "Running application '%s' from %s" % (appname,app.__file__) pf.scriptName = appname if pf.GUI: pf.GUI.startRun() pf.GUI.apphistory.add(appname) pf.board.write(msg,color='green') else: message(msg) pf.debug(" Passing arguments: %s" % argv,pf.DEBUG.SCRIPT) app._args_ = argv try: try: res = app.run() except _Exit: pass except _ExitSeq: exitrequested = True except: raise finally: if hasattr(app,'atExit'): app.atExit() if pf.cfg['autoglobals']: g = app.__dict__ exportNames = listAll(clas=Geometry,dic=g) pf.PF.update([(k,g[k]) for k in exportNames]) scriptRelease('__auto__') # release the lock if pf.GUI: pf.GUI.stopRun() pf.debug(" Arguments left after execution: %s" % argv,pf.DEBUG.SCRIPT) msg = "Finished %s in %s seconds" % (appname,t.seconds()) if pf.GUI: pf.board.write(msg,color='green') else: message(msg) pf.debug("Memory: %s" % vmSize(),pf.DEBUG.MEM)
def save(filename=None, window=False, multi=False, hotkey=True, autosave=False, border=False, grab=False, format=None, quality=-1, size=None, verbose=False, alpha=True, rootcrop=None): """Saves an image to file or Starts/stops multisave mode. With a filename and multi==False (default), the current viewport rendering is saved to the named file. With a filename and multi==True, multisave mode is started. Without a filename, multisave mode is turned off. Two subsequent calls starting multisave mode without an intermediate call to turn it off, do not cause an error. The first multisave mode will implicitely be ended before starting the second. In multisave mode, each call to saveNext() will save an image to the next generated file name. Filenames are generated by incrementing a numeric part of the name. If the supplied filename (after removing the extension) has a trailing numeric part, subsequent images will be numbered continuing from this number. Otherwise a numeric part '-000' will be added to the filename. If window is True, the full pyFormex window is saved. If window and border are True, the window decorations will be included. If window is False, only the current canvas viewport is saved. If grab is True, the external 'import' program is used to grab the window from the screen buffers. This is required by the border and window options. If hotkey is True, a new image will be saved by hitting the 'S' key. If autosave is True, a new image will be saved on each execution of the 'draw' function. If neither hotkey nor autosave are True, images can only be saved by executing the saveNext() function from a script. If no format is specified, it is derived from the filename extension. fmt should be one of the valid formats as returned by imageFormats() If verbose=True, error/warnings are activated. This is usually done when this function is called from the GUI. """ #print "SAVE: quality=%s" % quality global multisave if rootcrop is not None: pf.warning("image.save does no longer support the 'rootcrop' option") # Leave multisave mode if no filename or starting new multisave mode if multisave and (filename is None or multi): print("Leave multisave mode") if multisave[6]: pf.GUI.signals.SAVE.disconnect(saveNext) multisave = None if filename is None: return #chdir(filename) name, ext = os.path.splitext(filename) # Get/Check format if not format: # is None: format = checkImageFormat(imageFormatFromExt(ext)) if not format: return if multi: # Start multisave mode names = utils.NameSequence(name, ext) if os.path.exists(names.peek()): next = names.next() print("Start multisave mode to files: %s (%s)" % (names.name, format)) if hotkey: pf.GUI.signals.SAVE.connect(saveNext) if verbose: pf.warning( "Each time you hit the '%s' key,\nthe image will be saved to the next number." % pf.cfg['keys/save']) multisave = (names, format, quality, size, window, border, hotkey, autosave, grab) print("MULTISAVE %s " % str(multisave)) return multisave is None else: # Save the image if grab: # Grab from X server buffers (needs external) # # TODO: configure command to grab screen rectangle # if window: if border: windowname = 'root' crop = pf.GUI.frameGeometry().getRect() else: windowname = None crop = None else: windowname = None crop = 'canvas' sta = save_window(filename, format, quality, windowname=windowname, crop=crop) else: # Get from OpenGL rendering if size == pf.canvas.getSize(): # TODO: # We could grab from the OpenGL buffers here!! size = None # Render in an off-screen buffer and grab from there # # TODO: the offscreen buffer should be properly initialized # according to the current canvas # sta = save_canvas(pf.canvas, filename, format, quality, size, alpha) if sta: pf.debug("Error while saving image %s" % filename, pf.DEBUG.IMAGE) else: print("Image file %s written" % filename) return
def read(self,count=-1,warn_version=True): """Read objects from a pyFormex Geometry File. This function reads objects from a Geometry File until the file ends, or until `count` objects have been read. The File should have been opened for reading. A count may be specified to limit the number of objects read. Returns a dict with the objects read. The keys of the dict are the object names found in the file. If the file does not contain object names, they will be autogenerated from the file name. Note that PGF files of version 1.0 are no longer supported. The use of formats 1.1 to 1.5 is deprecated, and users are urged to upgrade these files to a newer format. Support for these formats may be removed in future. """ if self.writing: print("File is opened for writing, not reading.") return {} self.results = OrderedDict() self.geometry = None # used to make sure fields follow geom block if Version(self.version) < Version('1.6'): if warn_version: pf.warning("This is an old PGF format (%s). We recommend you to convert it to a newer format. The geometry import menu contains an item to upgrade a PGF file to the latest format (%s)." % (self.version,GeometryFile._version_)) return self.readLegacy(count) while True: s = self.fil.readline() if len(s) == 0: # end of file break if s.startswith('#'): # Remove the leading '#' and space s = s[1:].strip() if s.startswith('objtype'): if count > 0 and len(self.results) >= count: break self.readGeometry(**self.decode(s)) elif s.startswith('field'): self.readField(**self.decode(s)) elif s.startswith('attrib'): self.readAttrib(**self.decode(s)) elif s.startswith('pyFormex Geometry File'): # we have a new header line self.readHeader(s) # Unrecognized lines are silently ignored, whether starting # with a '#' or not. # We recommend to start all comments lines with a '#' though. self.file.close() return self.results
def image2numpy(image,resize=(0,0),order='RGBA',flip=True,indexed=None,expand=None): """Transform an image to a Numpy array. Parameters: - `image`: a QImage or any data that can be converted to a QImage, e.g. the name of an image file, in any of the formats supported by Qt. The image can be a full color image or an indexed type. Only 32bit and 8bit images are currently supported. - `resize`: a tuple of two integers (width,height). Positive value will force the image to be resized to this value. - `order`: string with a permutation of the characters 'RGBA', defining the order in which the colors are returned. Default is RGBA, so that result[...,0] gives the red component. Note however that QImage stores in ARGB order. You may also specify a subset of the 'RGBA' characters, in which case you will only get some of the color components. An often used value is 'RGB' to get the colors without the alpha value. - `flip`: boolean: if True, the image scanlines are flipped upside down. This is practical because image files are usually stored in top down order, while OpenGL uses an upwards positive direction, requiring a flip to show the image upright. - `indexed`: True, False or None. - If True, the result will be an indexed image where each pixel color is an index into a color table. Non-indexed image data will be converted. - If False, the result will be a full color array specifying the color of each pixel. Indexed images will be converted. - If None (default), no conversion is done and the resulting data are dependent on the image format. In all cases both a color and a colortable will be returned, but the latter will be None for non-indexed images. - `expand`: deprecated, retained for compatibility Returns: - if `indexed` is False: an int8 array with shape (height,width,4), holding the 4 components of the color of each pixel. Order of the components is as specified by the `order` argument. Indexed image formats will be expanded to a full color array. - if `indexed` is True: a tuple (colors,colortable) where colors is an (height,width) shaped int array of indices into the colortable, which is an int8 array with shape (ncolors,4). - if `indexed` is None (default), a tuple (colors,colortable) is returned, the type of which depend on the original image format: - for indexed formats, colors is an int (height,width) array of indices into the colortable, which is an int8 array with shape (ncolors,4). - for non-indexed formats, colors is a full (height,width,4) array and colortable is None. """ if expand is not None: utils.warn("depr_image2numpy_arg") indexed = not expand image = resizeImage(image,*resize) if indexed: image = image.convertToFormat(QImage.Format_Indexed8) h,w = image.height(),image.width() if image.format() in (QImage.Format_ARGB32_Premultiplied, QImage.Format_ARGB32, QImage.Format_RGB32): buf = image.bits() if not pf.options.pyside: buf = buf.asstring(image.numBytes()) ar = np.frombuffer(buf,dtype='ubyte',count=image.numBytes()).reshape(h,w,4) idx = [ 'BGRA'.index(c) for c in order ] ar = ar[...,idx] ct = None elif image.format() == QImage.Format_Indexed8: ct = np.array(image.colorTable(),dtype=np.uint32) #print("IMAGE FORMAT is INDEXED with %s colors" % ct.shape[0]) ct = ct.view(np.uint8).reshape(-1,4) idx = [ 'BGRA'.index(c) for c in order ] ct = ct[...,idx] buf = image.bits() if not pf.options.pyside: buf = buf.asstring(image.numBytes()) ar = np.frombuffer(buf,dtype=np.uint8) if ar.size != w*h: pf.warning("Size of image data (%s) does not match the reported dimensions: %s x %s = %s" % (ar.size,w,h,w*h)) #ar = ar[:w*h] ar = ar.reshape(h,-1) #print "IMAGE SHAPE IS %s" % str(ar.shape) else: raise ValueError("image2numpy only supports 32bit and 8bit images") # Put upright as expected if flip: ar = np.flipud(ar) # Convert indexed to nonindexed if requested if indexed is False and ct is not None: ar = ct[ar] ct = None # Return only full colors if requested if indexed is False: return ar else: return ar,ct
def run(args=[]): """The pyFormex main function. After pyFormex launcher script has correctly set up the Python import paths, this function is executed. It is responsible for reading the configuration file(s), processing the command line options and starting the application. The basic configuration file is 'pyformexrc' located in the pyFormex main directory. It should always be present and be left unchanged. If you want to make changes, copy (parts of) this file to another location where you can change them. Then make sure pyFormex reads you modifications file. By default, pyFormex will try to read the following configuration files if they are present (and in this order):: default settings: <pyformexdir>/pyformexrc (always loaded) system-wide settings: /etc/pyformex.conf user settings: <configdir>/pyformex/pyformex.conf local settings $PWD/.pyformexrc Also, an extra config file can be specified in the command line, using the --config option. The system-wide and user settings can be skipped by using the --nodefaultconfig option. Config files are loaded in the above order. Settings always override those loaded from a previous file. When pyFormex exits, the preferences that were changed are written to the last read config file. Changed settings are those that differ from the settings obtained after loading all but the last config file. If none of the optional config files exists, a new user settings file will be created, and an error will occur if the <configdir> path is not writable. """ if pf.isString(args): args = args.split() ## Parse the arguments ## parseArguments(args) ## Process special options which do not start pyFormex ## if processReportOptions(): return ## Migrate the user configuration files ## migrateUserConfig() ## Load the user configuration ## loadUserConfig() ## Process special options which do not start pyFormex ## if processReportOptions2(): return ## Process options that override the config ## if pf.options.pyside is not None: pf.cfg['gui/bindings'] = 'PySide' if pf.options.pyside else 'PyQt4' if pf.options.redirect is not None: pf.cfg['gui/redirect'] = pf.options.redirect delattr(pf.options, 'redirect') # avoid abuse utils.setSaneLocale() ## Check required modules ## software.checkModule('numpy', fatal=True) # Initialize the libraries if pf.options.uselib is None: pf.options.uselib = pf.cfg['uselib'] from pyformex import lib # TODO: # without this, we get a crash. Maybe config related? pf.cfg['gui/startup_warning'] = None ## Activate the warning filters activateWarningFilters() # Make sure pf.PF is a Project from pyformex.project import Project pf.PF = Project() # Set application paths pf.debug("Loading AppDirs", pf.DEBUG.INFO) from pyformex import apps apps.setAppDirs() # Start the GUI if needed # Importing the gui should be done after the config is set !! # Set default --nogui if first remaining argument is a pyformex script. args = pf.options.args if pf.options.gui is None: pf.options.gui = not (len(args) > 0 and utils.is_pyFormex(args[0])) if pf.options.gui: if pf.options.mesa: os.environ['LIBGL_ALWAYS_SOFTWARE'] = '1' from pyformex.gui import guimain pf.debug("GUI version", pf.DEBUG.INFO) res = guimain.startGUI(args) if res != 0: print("Could not start the pyFormex GUI: %s" % res) return res # EXIT # Display the startup warnings and messages if pf.startup_warnings: if pf.cfg['startup_warnings']: pf.warning(pf.startup_warnings) else: print("*** WARNING ***\n" + pf.startup_warnings + "****************\n") if pf.startup_messages: print(pf.startup_messages) if pf.options.debuglevel & pf.DEBUG.INFO: # NOTE: inside an if to avoid computing the report when not printed pf.debug(software.reportSoftware(), pf.DEBUG.INFO) # # Qt4 may have changed the locale. # Since a LC_NUMERIC setting other than C may cause lots of troubles # with reading and writing files (formats become incompatible!) # we put it back to a sane setting # utils.setSaneLocale() # Startup done pf.started = True print("pyFormex started from %s" % pf.executable) # Prepend the inline script if pf.options.script: args[0:0] = ['-c', pf.options.script] # Prepend the autorun script ar = pf.cfg.get('autorun', '') if ar and os.path.exists(ar): args[0:0] = [ar] # remaining args are interpreted as scripts/apps and their parameters res = 0 if args: pf.debug("Remaining args: %s" % args, pf.DEBUG.INFO) from pyformex.script import processArgs res = processArgs(args) if res: if pf.options.gui: print("There was an error while executing a script") else: return res # EXIT else: pf.debug("stdin is a tty: %s" % sys.stdin.isatty(), pf.DEBUG.INFO) # Play script from stdin # Can we check for interactive session: stdin connected to terminal? #from script import playScript #playScript(sys.stdin) # after processing all args, and we have a gui, go into interactive mode if pf.options.gui and pf.app: res = guimain.runGUI() #Save the preferences that have changed savePreferences() # Exit return res
def image2numpy(image, resize=(0, 0), order='RGBA', flip=True, indexed=None, expand=None): """Transform an image to a Numpy array. Parameters: - `image`: a QImage or any data that can be converted to a QImage, e.g. the name of an image file, in any of the formats supported by Qt. The image can be a full color image or an indexed type. Only 32bit and 8bit images are currently supported. - `resize`: a tuple of two integers (width,height). Positive value will force the image to be resized to this value. - `order`: string with a permutation of the characters 'RGBA', defining the order in which the colors are returned. Default is RGBA, so that result[...,0] gives the red component. Note however that QImage stores in ARGB order. You may also specify a subset of the 'RGBA' characters, in which case you will only get some of the color components. An often used value is 'RGB' to get the colors without the alpha value. - `flip`: boolean: if True, the image scanlines are flipped upside down. This is practical because image files are usually stored in top down order, while OpenGL uses an upwards positive direction, requiring a flip to show the image upright. - `indexed`: True, False or None. - If True, the result will be an indexed image where each pixel color is an index into a color table. Non-indexed image data will be converted. - If False, the result will be a full color array specifying the color of each pixel. Indexed images will be converted. - If None (default), no conversion is done and the resulting data are dependent on the image format. In all cases both a color and a colortable will be returned, but the latter will be None for non-indexed images. - `expand`: deprecated, retained for compatibility Returns: - if `indexed` is False: an int8 array with shape (height,width,4), holding the 4 components of the color of each pixel. Order of the components is as specified by the `order` argument. Indexed image formats will be expanded to a full color array. - if `indexed` is True: a tuple (colors,colortable) where colors is an (height,width) shaped int array of indices into the colortable, which is an int8 array with shape (ncolors,4). - if `indexed` is None (default), a tuple (colors,colortable) is returned, the type of which depend on the original image format: - for indexed formats, colors is an int (height,width) array of indices into the colortable, which is an int8 array with shape (ncolors,4). - for non-indexed formats, colors is a full (height,width,4) array and colortable is None. """ if expand is not None: utils.warn("depr_image2numpy_arg") indexed = not expand image = resizeImage(image, *resize) if indexed: image = image.convertToFormat(QImage.Format_Indexed8) h, w = image.height(), image.width() if image.format() in (QImage.Format_ARGB32_Premultiplied, QImage.Format_ARGB32, QImage.Format_RGB32): buf = image.bits() if not pf.options.pyside: buf = buf.asstring(image.numBytes()) ar = np.frombuffer(buf, dtype='ubyte', count=image.numBytes()).reshape(h, w, 4) idx = ['BGRA'.index(c) for c in order] ar = ar[..., idx] ct = None elif image.format() == QImage.Format_Indexed8: ct = np.array(image.colorTable(), dtype=np.uint32) #print("IMAGE FORMAT is INDEXED with %s colors" % ct.shape[0]) ct = ct.view(np.uint8).reshape(-1, 4) idx = ['BGRA'.index(c) for c in order] ct = ct[..., idx] buf = image.bits() if not pf.options.pyside: buf = buf.asstring(image.numBytes()) ar = np.frombuffer(buf, dtype=np.uint8) if ar.size != w * h: pf.warning( "Size of image data (%s) does not match the reported dimensions: %s x %s = %s" % (ar.size, w, h, w * h)) #ar = ar[:w*h] ar = ar.reshape(h, -1) #print "IMAGE SHAPE IS %s" % str(ar.shape) else: raise ValueError("image2numpy only supports 32bit and 8bit images") # Put upright as expected if flip: ar = np.flipud(ar) # Convert indexed to nonindexed if requested if indexed is False and ct is not None: ar = ct[ar] ct = None # Return only full colors if requested if indexed is False: return ar else: return ar, ct
def runApp(appname, argv=[], refresh=False): global exitrequested if len(pf.scriptlock) > 0: pf.message("!!Not executing because a script lock has been set: %s" % pf.scriptlock) #print(pf.scriptlock) return import apps from timer import Timer t = Timer() pf.message("Loading application %s with refresh=%s" % (appname, refresh)) app = apps.load(appname, refresh=refresh) if app is None: errmsg = "An error occurred while loading application %s" % appname if pf.GUI: if apps._traceback and pf.cfg['showapploaderrors']: print(apps._traceback) from gui import draw fn = apps.findAppSource(appname) if os.path.exists(fn): errmsg += "\n\nYou may try executing the application as a script,\n or you can load the source file in the editor." res = draw.ask(errmsg, choices=[ 'Run as script', 'Load in editor', "Don't bother" ]) if res[0] in 'RL': if res[0] == 'L': draw.editFile(fn) elif res[0] == 'R': pf.GUI.setcurfile(fn) draw.runScript(fn) else: errmsg += "and I can not find the application source file." draw.error(errmsg) else: error(errmsg) return if hasattr(app, '_status') and app._status == 'unchecked': pf.warning( "This looks like an Example script that has been automatically converted to the pyFormex Application model, but has not been checked yet as to whether it is working correctly in App mode.\nYou can help here by running and rerunning the example, checking that it works correctly, and where needed fixing it (or reporting the failure to us). If the example runs well, you can change its status to 'checked'" ) scriptLock('__auto__') msg = "Running application '%s' from %s" % (appname, app.__file__) pf.scriptName = appname if pf.GUI: pf.GUI.startRun() pf.GUI.apphistory.add(appname) pf.board.write(msg, color='green') else: message(msg) pf.debug(" Passing arguments: %s" % argv, pf.DEBUG.SCRIPT) app._args_ = argv try: try: res = app.run() except _Exit: pass except _ExitSeq: exitrequested = True except: raise finally: if hasattr(app, 'atExit'): app.atExit() if pf.cfg['autoglobals']: g = app.__dict__ exportNames = listAll(clas=Geometry, dic=g) pf.PF.update([(k, g[k]) for k in exportNames]) scriptRelease('__auto__') # release the lock if pf.GUI: pf.GUI.stopRun() pf.debug(" Arguments left after execution: %s" % argv, pf.DEBUG.SCRIPT) msg = "Finished %s in %s seconds" % (appname, t.seconds()) if pf.GUI: pf.board.write(msg, color='green') else: message(msg) pf.debug("Memory: %s" % vmSize(), pf.DEBUG.MEM)