Package PyFoam :: Package Applications :: Module STLUtility
[hide private]
[frames] | no frames]

Source Code for Module PyFoam.Applications.STLUtility

  1  """ 
  2  Application-class that implements pyFoamSTLUtility.py 
  3  """ 
  4  from optparse import OptionGroup 
  5   
  6  from .PyFoamApplication import PyFoamApplication 
  7  from PyFoam.Basics.STLFile import STLFile 
  8  from PyFoam.Basics.RestructuredTextHelper import RestructuredTextHelper 
  9  from PyFoam.Basics.FoamOptionParser import Subcommand 
 10   
 11  from os import path 
 12  import sys,re 
 13   
 14  from PyFoam.ThirdParty.six import print_ 
 15   
16 -class STLUtility(PyFoamApplication):
17 - def __init__(self, 18 args=None, 19 **kwargs):
20 description="""\ 21 This utility does some basic manipulations with STL-files 22 """ 23 PyFoamApplication.__init__(self, 24 args=args, 25 description=description, 26 usage="%prog COMMAND [<source1.stl> <source2.stl> ...]", 27 changeVersion=False, 28 subcommands=True, 29 **kwargs)
30
31 - def addOptions(self):
32 # Building the subcommands 33 joinCmd=Subcommand(name='join', 34 help="Join STL-files into one", 35 aliases=("cat",), 36 nr=2, 37 exactNr=False) 38 self.parser.addSubcommand(joinCmd) 39 40 namesCmd=Subcommand(name='names', 41 help="Report names of patches in the STLs", 42 aliases=("list",), 43 nr=0, 44 exactNr=False) 45 self.parser.addSubcommand(namesCmd) 46 47 infoCmd=Subcommand(name='info', 48 help="Reports about the STL-files", 49 aliases=("report",), 50 nr=0, 51 exactNr=False) 52 self.parser.addSubcommand(infoCmd) 53 54 removeCmd=Subcommand(name='remove', 55 help="Remove patches from the STL-file", 56 aliases=("erase","blank",), 57 nr=0, 58 exactNr=False) 59 self.parser.addSubcommand(removeCmd) 60 61 mergeCmd=Subcommand(name='merge', 62 help="Merge patches and put them into a new patch", 63 aliases=("move",), 64 nr=0, 65 exactNr=False) 66 self.parser.addSubcommand(mergeCmd) 67 mergeCmd.parser.add_option("--new-patch-name", 68 action="store", 69 dest="newName", 70 default=None, 71 help="Name of the patch that is added") 72 73 # Add option groups to parsers 74 for cmd in [joinCmd,removeCmd,mergeCmd]: 75 outOpts=OptionGroup(cmd.parser, 76 "Write Options", 77 "Where the resulting STL is written to") 78 outOpts.add_option("--to-stdout", 79 action="store_true", 80 dest="stdout", 81 default=False, 82 help="Instead of writing to file write to stdout (used for piping into other commands)") 83 outOpts.add_option("--force-write", 84 action="store_true", 85 dest="forceWrite", 86 default=False, 87 help="Force writing if the file already exists") 88 outOpts.add_option("--stl-file", 89 action="store", 90 dest="stlFile", 91 default=None, 92 help="Write to this filename") 93 cmd.parser.add_option_group(outOpts) 94 95 for cmd in [namesCmd,infoCmd,removeCmd,mergeCmd]: 96 inOpts=OptionGroup(cmd.parser, 97 "Read Options", 98 "Which STLs are read") 99 inOpts.add_option("--from-stdin", 100 action="store_true", 101 dest="stdin", 102 default=False, 103 help="Instead of reading from file read from stdin (used for piping into other commands)") 104 cmd.parser.add_option_group(inOpts) 105 106 for cmd in [removeCmd,mergeCmd]: 107 patchOpts=OptionGroup(cmd.parser, 108 "Patch selection", 109 "Which patches to operate on") 110 patchOpts.add_option("--patch-name", 111 action="append", 112 dest="patchNames", 113 default=[], 114 help="Name of the patch to work on. Can be selected more than once") 115 patchOpts.add_option("--select-expression", 116 action="append", 117 dest="patchExpr", 118 default=[], 119 help="Regular expressions fitting the patches. Can be selected more than once") 120 121 cmd.parser.add_option_group(patchOpts)
122
123 - def run(self):
124 sources=None 125 if "stdin" in self.opts.__dict__: 126 if self.opts.stdin: 127 if len(self.parser.getArgs())>0: 128 self.error("If --from-stdin specified no arguments are allowed but we have",self.parser.getArgs()) 129 sources=[STLFile(sys.stdin)] 130 if sources==None: 131 sources=[STLFile(f) for f in self.parser.getArgs()] 132 133 if self.cmdname in ["remove","merge"]: 134 if len(sources)!=1: 135 self.error("Only one input allowed for",self.cmdname) 136 137 if self.cmdname in ["remove","merge"]: 138 if len(self.opts.patchExpr)==0 and len(self.opts.patchNames)==0: 139 self.error("Neither --patch-name nor --select-expression specified") 140 for e in self.opts.patchExpr: 141 expr=re.compile(e) 142 for s in sources: 143 for p in s.patchInfo(): 144 if expr.match(p["name"]): 145 self.opts.patchNames.append(p["name"]) 146 if len(self.opts.patchNames)==0: 147 self.error("No patches fit the provided regular expressions") 148 149 if self.cmdname in ["remove","join","merge"]: 150 # Check whether output is correct 151 if self.opts.stdout and self.opts.stlFile: 152 self.error("Can't specify --to-stdout and --stl-file at the same time") 153 154 if self.opts.stlFile: 155 if path.exists(self.opts.stlFile): 156 if not self.opts.forceWrite: 157 self.error("File",self.opts.stlFile,"does allready exist. Use --force-write to overwrite") 158 outputTo=self.opts.stlFile 159 elif self.opts.stdout: 160 outputTo=sys.stdout 161 else: 162 self.error("Specify either --to-stdout or --stld-file") 163 164 rst=RestructuredTextHelper() 165 166 if self.cmdname=="names": 167 print_(rst.buildHeading("Patch names",level=RestructuredTextHelper.LevelSection)) 168 for s in sources: 169 print_(rst.buildHeading(s.filename(),level=RestructuredTextHelper.LevelSubSection)) 170 for p in s.patchInfo(): 171 print_(p["name"]) 172 173 elif self.cmdname=="info": 174 print_(rst.buildHeading("Patch info",level=RestructuredTextHelper.LevelSection)) 175 for s in sources: 176 print_(rst.buildHeading(s.filename(),level=RestructuredTextHelper.LevelSubSection)) 177 tab=rst.table() 178 tab[0]=["name","facets","range in file","bounding box"] 179 tab.addLine(head=True) 180 for i,p in enumerate(s.patchInfo()): 181 tab[(i+1,0)]=p["name"] 182 tab[(i+1,1)]=p["facets"] 183 tab[(i+1,2)]="%d-%d" % (p["start"],p["end"]) 184 tab[(i+1,3)]="(%g %g %g) - (%g %g %g)" % tuple(p["min"]+p["max"]) 185 186 print_(tab) 187 188 elif self.cmdname=="join": 189 result=STLFile() 190 for s in sources: 191 result+=s 192 193 result.writeTo(outputTo) 194 elif self.cmdname=="remove": 195 s=sources[0] 196 s.erasePatches(self.opts.patchNames) 197 s.writeTo(outputTo) 198 elif self.cmdname=="merge": 199 if self.opts.newName==None: 200 self.error("Specify --new-patch-name") 201 s=sources[0] 202 s.mergePatches(self.opts.patchNames,self.opts.newName) 203 s.writeTo(outputTo) 204 else: 205 self.error("Unimplemented subcommand",self.cmdname)
206 207 # Should work with Python3 and Python2 208