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(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
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
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
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
208