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
17 - def __init__(self,
18 args=None,
19 **kwargs):
30
32
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
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
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
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
214