def runCommand(cmd,RaiseError=True): """Run a command and raise error if exited with error.""" GD.message("Running command: %s" % cmd) sta,out = commands.getstatusoutput(cmd) if sta != 0 and RaiseError: raise RuntimeError, "Error while executing command:\n %s" % cmd return sta,out
def detect(): """Check if we have calpy and if so, add its path to sys.path.""" global calpy_path calpy = utils.hasExternal('calpy') if not calpy: return GD.message("You have calpy version %s" % calpy) path = '' calpy = calpy.split('-')[0] # trim the version trailer if utils.checkVersion('calpy','0.3.4-rev3',external=True) >= 0: sta,out = utils.runCommand('calpy --whereami') if not sta: path = os.path.dirname(out) GD.debug("I found calpy in %s" % path) if not path: trypaths = [ '/usr/local/lib', '/usr/local' ] for p in trypaths: path = '%s/calpy-%s' % (p,calpy) if os.path.exists(path): GD.debug('path exists: %s' % path) break else: GD.debug('path does not exist: %s' % path) path = '' if path: GD.message("I found calpy in '%s'" % path) sys.path.append(path) calpy_path = path
def read_Formex(fn): GD.message("Reading file %s" % fn) t = timer.Timer() F = Formex.read(fn) nelems, nplex = F.f.shape[0:2] GD.message("Read %d elems of plexitude %d in %s seconds" % (nelems, nplex, t.seconds())) return F
def readSelection(select=True,draw=True,multi=True): """Read a Surface (or list) from asked file name(s). If select is True (default), this becomes the current selection. If select and draw are True (default), the selection is drawn. """ types = [ 'Surface Files (*.gts *.stl *.off *.neu *.smesh)', 'All Files (*)' ] fn = askFilename(GD.cfg['workdir'],types,exist=True,multi=multi) if not multi: fn = [ fn ] if fn: chdir(fn[0]) names = map(utils.projectName,fn) GD.gui.setBusy() surfaces = map(read_Surface,fn) for i,S in enumerate(surfaces): S.setProp(i) GD.gui.setBusy(False) export(dict(zip(names,surfaces))) if select: GD.message("Set selection to %s" % str(names)) selection.set(names) if draw: if max([named(s).nfaces() for s in selection]) < 100000 or ack(""" This is a large model and drawing could take quite some time. You should consider coarsening the model before drawing it. Shall I proceed with the drawing now? """): selection.draw() return fn
def create_tetgen_volume(): """Generate a volume tetraeder mesh inside an stl surface.""" types = [ 'STL/OFF Files (*.stl *.off)', 'All Files (*)' ] fn = askFilename(GD.cfg['workdir'],types,exist=True,multi=False) if os.path.exists(fn): sta,out = utils.runCommand('tetgen -z %s' % fn) GD.message(out)
def congratulations(name,version,typ='module'): """Report a detected module/program.""" if GD.options.debug: if version: GD.message("Congratulations! You have %s (%s)" % (name,version)) else: GD.message("ALAS! I could not find %s '%s' on your system" % (typ,name))
def remove_triangles(elems,remove): """Remove triangles from a surface mesh. elems is a (nelems,3) integer array of triangles. remove is a (nremove,3) integer array of triangles to remove. Returns a (nelems-nremove,3) integer array with the triangles of nelems where the triangles of remove have been removed. """ print elems,remove GD.message("Removing %s out of %s triangles" % (remove.shape[0],elems.shape[0])) magic = elems.max()+1 mag1 = magic_numbers(elems,magic) mag2 = magic_numbers(remove,magic) mag1.sort() mag2.sort() nelems = mag1.shape[0] pos = mag1.searchsorted(mag2) mag1[pos] = -1 mag1 = mag1[mag1 >= 0] elems = demagic(mag1,magic) GD.message("Actually removed %s triangles, leaving %s" % (nelems-mag1.shape[0],elems.shape[0])) return elems
def printSettings(self): for i,v in enumerate(self.all): GD.message(""" ## VIEWPORTS ## Viewport %s; Active:%s; Current:%s; Settings: %s """ % (i,v in self.active, v == self.current, v.settings))
def clip_surface(): """Clip the stl model.""" if not check_surface(): return itemlist = [['axis',0],['begin',0.0],['end',1.0],['nodes','any']] res,accept = widgets.inputDialog(itemlist,'Clipping Parameters').getResult() if accept: updateGUI() nodes,elems = PF['old_surface'] = PF['surface'] F = Formex(nodes[elems]) bb = F.bbox() GD.message("Original bbox: %s" % bb) xmi = bb[0][0] xma = bb[1][0] dx = xma-xmi axis = int(res[0][1]) xc1 = xmi + float(res[1][1]) * dx xc2 = xmi + float(res[2][1]) * dx nodid = res[3][1] print nodid clear() draw(F,color='yellow') w = F.test(nodes='any',dir=axis,min=xc1,max=xc2) F = F.clip(w) draw(F,clor='red')
def read_surface(types=['stl/off','stl','off','neu','smesh','gts'],show=True): """Read STL model from file fn. If no file is given, one is asked. The file fn should exist and contain a valid STL model. The STL model is stored in the Formex F. The workdir and project name are set from the filename. The Formex is stored under the project basename. The model is displayed. """ if type(types) == str: types = [ types ] types = map(utils.fileDescription,types) fn = askFilename(GD.cfg['workdir'],types,exist=True) if fn: chdir(fn) set_project(utils.projectName(fn)) GD.message("Reading file %s" % fn) GD.gui.setBusy() t = timer.Timer() nodes,elems =stl.readSurface(fn) GD.message("Time to import stl: %s seconds" % t.seconds()) GD.gui.setBusy(False) set_surface(nodes,elems) if show: show_surface(view='front') if ack('Convert to Formex?'): name = toFormex() # This is convenient for the user if name: formex_menu.setSelection(name) #formex_menu.drawSelection() return fn
def checkExternal(name,command=None,answer=None): """Check if the named external command is available on the system. name is the generic command name, command is the command as it will be executed to check its operation, answer is a regular expression to match positive answers from the command. answer should contain at least one group. In case of a match, the contents of the match will be stored in the GD.external dict with name as the key. If the result does not match the specified answer, an empty value is inserted. Usually, command will contain an option to display the version, and the answer re contains a group to select the version string from the result. As a convenience, we provide a list of predeclared external commands, that can be checked by their name alone. """ if command is None or answer is None: cmd,ans = known_externals.get(name,(name,'(.+)\n')) if command is None: command = cmd if answer is None: answer = ans m = re.match(answer,commands.getoutput(command)) if m: value = m.group(1) GD.message("Congratulations! You have %s (%s)" % (name,value)) else: value = '' GD.external[name] = value return value
def printBbox(self): """Print the bbox of the current selection.""" objects = self.check() for n,o in zip(self.names,objects): GD.message("Object %s has bbox %s" % (n,o.bbox())) if len(self.names) > 1: GD.message("Overal bbox is %s" % bbox(objects))
def selectStepInc(self): res = askItems([('Step',self.DB.step,'select',self.DB.res.keys())]) if res: step = int(res['Step']) res = askItems([('Increment',None,'select',self.DB.res[step].keys())]) if res: inc = int(res['Increment']) GD.message("Step %s; Increment %s;" % (step,inc)) self.DB.setStepInc(step,inc)
def breakpt(msg=None): """Set a breakpoint where the script can be halted on pressing a button. If an argument is specified, it will be written to the message board. """ if exitrequested: if msg is not None: GD.message(msg) raise Exit
def closeProject(): global the_project,the_project_saved if not (the_project_saved or the_project is None): GD.message("Closing project %s" % the_project.filename) GD .message("Project contents: %s" % the_project.keys()) the_project.save() GD.PF = {} GD.PF.update(the_project) GD.gui.setcurproj('None') the_project = None
def show_volume(): """Display the volume model.""" if PF['volume'] is None: return nodes,elems = PF['volume'] F = Formex(nodes[elems]) GD.message("BBOX = %s" % F.bbox()) clear() draw(F,color='random',eltype='tet') PF['vol_model'] = F
def show_shrinked(): """Display the surface model in shrinked mode. This is based on the stl model. """ if check_stl(): F = PF['stl_model'] GD.message("BBOX = %s" % F.bbox()) clear() draw(F.shrink(0.8),color=PF['stl_color'])
def export_stl(): """Export an stl model stored in Formex F in Abaqus .inp format.""" global project,F if ack("Creating nodes and elements.\nFor a large model, this could take quite some time!"): GD.app.processEvents() GD.message("Creating nodes and elements.") nodes,elems = F.feModel() nnodes = nodes.shape[0] nelems = elems.shape[0] GD.message("There are %d unique nodes and %d triangle elements in the model." % (nnodes,nelems)) stl_abq.abq_export(project+'.inp',nodes,elems,'S3',"Created by stl_examples.py")
def writeSelection(): """Writes the currently selected Formex to .formex file.""" F = selection.check(single=True) if F: name = selection.names[0] fn = askFilename(GD.cfg['workdir'],file="%s.formex" % name, filter=['(*.formex)','*'],exist=False) if fn: GD.message("Writing Formex '%s' to file '%s'" % (name,fn)) chdir(fn) F.write(fn)
def showBboxB(): """Draw the bbox on the current selection.""" global bboxB FL = selection.check() if FL: bb = bbox(FL) GD.message("Bbox of selection: %s" % bb) nx = array([4,4,4]) bboxB = actors.CoordPlaneActor(nx=nx,ox=bb[0],dx=(bb[1]-bb[0])/nx) GD.canvas.addActor(bboxB) GD.canvas.update()
def write_surface(types=['surface','gts','stl','off','neu','smesh']): F = selection.check(single=True) if F: if type(types) == str: types = [ types ] types = map(utils.fileDescription,types) fn = askFilename(GD.cfg['workdir'],types,exist=False) if fn: GD.message("Exporting surface model to %s" % fn) GD.gui.setBusy() F.write(fn) GD.gui.setBusy(False)
def postABQ(self,fn=None): """Translate an Abaqus .fil file in a postproc script.""" types = [ 'Abaqus results file (*.fil)' ] fn = askFilename(GD.cfg['workdir'],types,exist=True) if fn: chdir(fn) name,ext = os.path.splitext(fn) post = name+'.post' cmd = "%s/lib/postabq %s > %s" % (GD.cfg['pyformexdir'],fn,post) sta,out = utils.runCommand(cmd) if sta: GD.message(out)
def drawGL(self,mode,color=None,alpha=None): """Draw the surface.""" print "SURFACE.DRAWGL" if mode.endswith('wire'): self.drawGL(mode[:-4],color=color) self.drawGL('wireframe',color=asarray(black)) return if alpha is None: alpha = self.alpha if color == None: color = self.color ## if mode == 'wireframe': ## # adapt color array to edgeselect ## color = concatenate([self.color,self.color,self.color],axis=-1) ## color = color.reshape((-1,2))[self.edgeselect] if color is None: # no color pass elif color.dtype.kind == 'f' and color.ndim == 1: # single color GL.glColor(append(color,alpha)) color = None elif color.dtype.kind == 'i': # color index color = self.colormap[color] else: # a full color array : use as is pass #print "SURFACE COLOR = %s" % str(color) if self.linewidth is not None: GL.glLineWidth(self.linewidth) t = timer.Timer() if mode=='wireframe' : #print color.shape #print self.edges.shape #print self.faces.shape rev = reverseIndex(self.faces) if color is not None: color = color[rev[:,-1]] drawLineElems(self.coords,self.edges,color) else: self.refresh() drawTriangleElems(self.coords,self.elems,mode,color,alpha) GD.message("Drawing time: %s seconds" % t.seconds())
def refine(self,max_edges=None,min_cost=None, log=False, verbose=False): """Refine the surface using gtsrefine.""" if max_edges is None and min_cost is None: max_edges = self.nedges() * 2 cmd = 'gtsrefine' if max_edges: cmd += ' -n %d' % max_edges if min_cost: cmd += ' -c %d' % min_cost if log: cmd += ' -L' if verbose: cmd += ' -v' tmp = tempfile.mktemp('.gts') tmp1 = tempfile.mktemp('.gts') GD.message("Writing temp file %s" % tmp) self.write(tmp,'gts') GD.message("Refining with command\n %s" % cmd) cmd += ' < %s > %s' % (tmp,tmp1) sta,out = runCommand(cmd) os.remove(tmp) if sta or verbose: GD.message(out) GD.message("Reading refined model from %s" % tmp1) self.__init__(*read_gts(tmp1)) os.remove(tmp1)
def breakpt(msg=None): """Set a breakpoint where the script can be halted on a signal. If an argument is specified, it will be written to the message board. The exitrequested signal is usually emitted by pressing a button in the GUI. In nongui mode the stopatbreakpt function can be called from another thread. """ global exitrequested if exitrequested: if msg is not None: GD.message(msg) exitrequested = False # reset for next time raise Exit
def pick(mode='actor',single=False,front=False,func=None): """Enter interactive picking mode and return selection. See viewport.py for more details. This function differs in that it provides default highlighting during the picking operation. """ GD.message("Select %s" % mode) selection_buttons = widgets.ButtonBox('Selection:',['Cancel','OK'],[GD.canvas.cancel_selection,GD.canvas.accept_selection]) GD.gui.statusbar.addWidget(selection_buttons) if func is None: func = highlight_funcs.get(mode,None) sel = GD.canvas.pick(mode,single,front,func) GD.gui.statusbar.removeWidget(selection_buttons) return sel
def fill_holes(): global F,oldF fn = project + '.stl' fn1 = project + '-closed.stl' if os.path.exists(fn): sta,out = commands.getstatusoutput('admesh %s -f -a %s' % (fn,fn1)) GD.message(out) if sta == 0: clear() linewidth(1) draw(F,color='yellow',view='front') oldF = F linewidth(2) GD.gui.setBusy() stl.readSurface(fn1) GD.gui.setBusy(False)
def chdir(fn): """Change the current pyFormex working directory. If fn is a directory name, the current directory is set to fn. If fn is a file name, the current directory is set to the directory holding fn. In either case, the current dirctory is stored in GD.cfg['workdir'] for persistence between pyFormex invocations. If fn does not exist, nothing is done. """ if os.path.exists: if not os.path.isdir(fn): fn = os.path.dirname(fn) os.chdir(fn) GD.cfg['workdir'] = fn GD.message("Your current workdir is %s" % os.getcwd())
def read_surface(fn='',types=['stl/off','stl','off','neu','smesh','gts'],convert=None,show=True): """Read STL model from file fn. If no file is given, one is asked. The file fn should exist and contain a valid surface model. The STL model is stored in the Formex F. The workdir and project name are set from the filename. The Formex is stored under the project basename. The model is displayed. If convert == True, the model is converted to a Formex. If convert == False, it will not be converted. The default is to ask the user. """ if not (fn and os.path.exists(fn)): if type(types) == str: types = [ types ] types = map(utils.fileDescription,types) fn = askFilename(GD.cfg['workdir'],types,exist=True) if fn: chdir(fn) set_project(utils.projectName(fn)) GD.message("Reading file %s" % fn) GD.gui.setBusy() t = timer.Timer() nodes,elems =stl.readSurface(fn) GD.message("Time to import surface: %s seconds" % t.seconds()) GD.gui.setBusy(False) set_surface(nodes,elems) if show: show_surface(view='front') if convert is None: convert = ack('Convert to Formex?') if convert: GD.debug("GOING") name = toFormex(PF.get('project','')) # This is convenient for the user if name: formex_menu.setSelection(name) if show: formex_menu.drawSelection() else: pass return fn
def partitionSelection(): """Partition the selection.""" F = checkSelection(single=True) if not F: return name = selection[0] GD.message("Partitioning Formex '%s'" % name) cuts = partition.partition(F) GD.message("Subsequent cutting planes: %s" % cuts) if ack("Save cutting plane data?"): types = ["Text Files (*.txt)", "All Files (*)"] fn = askFilename(GD.cfg["workdir"], types, exist=False) if fn: chdir(fn) fil = file(fn, "w") fil.write("%s\n" % cuts) fil.close()