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