Package PyFoam :: Package Basics :: Module STLFile
[hide private]
[frames] | no frames]

Source Code for Module PyFoam.Basics.STLFile

  1  #  ICE Revision: $Id$ 
  2  """Read a STL file and do simple manipulations""" 
  3   
  4  from os import path 
  5  from PyFoam.Error import error 
  6   
  7  from PyFoam.ThirdParty.six import next as iterNext 
  8   
9 -class STLFile(object):
10 """Store a complete STL-file and do simple manipulations with it""" 11 12 noName="<no name given>" 13
14 - def __init__(self,fName=None):
15 """ 16 @param fName: filename of the STL-file. If None then an empty file is created 17 """ 18 self._fp=None 19 if hasattr(fName, 'read'): 20 # seems to be a filehandle 21 self._fp=fName 22 if hasattr(fName,'name'): 23 self._filename=fName.name 24 else: 25 self._filename="<filehandle>" 26 else: 27 self._filename=fName 28 29 if self._fp==None: 30 if fName!=None: 31 self._contents=[l.strip() for l in open(fName).readlines()] 32 else: 33 self._contents=[] 34 else: 35 self._contents=[l.strip() for l in self._fp.readlines()] 36 37 self.resetInfo()
38
39 - def resetInfo(self):
40 """Set cached info to nothing""" 41 self._patchInfo=None
42
43 - def filename(self):
44 """The filename (without the full patch)""" 45 if self._filename==None: 46 return "<no filename given>" 47 else: 48 return path.basename(self._filename)
49
50 - def expectedToken(self,l,token,i):
51 if l.strip().find(token)!=0: 52 error("'%s' expected in line %d of %s" % (token,i+1,self.filename()))
53
54 - def erasePatches(self,patchNames):
55 """Erase the patches in the list""" 56 processed=[] 57 58 keep=True 59 currentName=None 60 61 for l in self._contents: 62 nextState=keep 63 parts=l.split() 64 if len(parts)>0: 65 if parts[0]=="endsolid": 66 nextState=True 67 if currentName!=parts[1]: 68 error("Patch name",parts[1],"Expected",currentName) 69 currentName=None 70 elif parts[0]=="solid": 71 currentName=parts[1] 72 if currentName in patchNames: 73 keep=False 74 nextState=False 75 if keep: 76 processed.append(l) 77 keep=nextState 78 79 self._contents=processed
80
81 - def mergePatches(self,patchNames,targetPatchName):
82 """Merge the patches in the list and put them into a new patch""" 83 84 processed=[] 85 saved=[] 86 87 keep=True 88 currentName=None 89 90 for l in self._contents: 91 nextState=keep 92 parts=l.split() 93 if len(parts)>0: 94 if parts[0]=="endsolid": 95 nextState=True 96 if currentName!=parts[1]: 97 error("Patch name",parts[1],"Expected",currentName) 98 currentName=None 99 elif parts[0]=="solid": 100 currentName=parts[1] 101 if currentName in patchNames: 102 keep=False 103 nextState=False 104 if keep: 105 processed.append(l) 106 elif len(parts)>0: 107 if parts[0] not in ["solid","endsolid"]: 108 saved.append(l) 109 keep=nextState 110 111 self._contents=processed 112 113 self._contents.append("solid "+targetPatchName) 114 self._contents+=saved 115 self._contents.append("endsolid "+targetPatchName)
116
117 - def patchInfo(self):
118 """Get info about the patches. A list of dictionaries with the relevant information""" 119 if self._patchInfo: 120 return self._patchInfo 121 122 self._patchInfo=[] 123 124 newPatch=True 125 126 e=enumerate(self._contents) 127 128 goOn=True 129 while goOn: 130 try: 131 i,l=iterNext(e) 132 if newPatch: 133 self.expectedToken(l,"solid",i) 134 info={} 135 if len(l.split())<2: 136 info["name"]=self.noName 137 else: 138 info["name"]=l.split()[1] 139 info["start"]=i+1 140 info["facets"]=0 141 info["min"]=[1e100]*3 142 info["max"]=[-1e100]*3 143 newPatch=False 144 elif l.strip().find("endsolid")==0: 145 info["end"]=i+1 146 self._patchInfo.append(info) 147 newPatch=True 148 else: 149 self.expectedToken(l,"facet normal",i) 150 i,l=iterNext(e) 151 self.expectedToken(l,"outer loop",i) 152 for v in range(3): 153 i,l=iterNext(e) 154 self.expectedToken(l,"vertex",i) 155 info["min"]=[min(m) for m in zip(info["min"], 156 [float(v) for v in l.strip().split()[1:4]])] 157 info["max"]=[max(m) for m in zip(info["max"], 158 [float(v) for v in l.strip().split()[1:4]])] 159 i,l=iterNext(e) 160 self.expectedToken(l,"endloop",i) 161 i,l=iterNext(e) 162 self.expectedToken(l,"endfacet",i) 163 info["facets"]+=1 164 except StopIteration: 165 goOn=False 166 167 168 if not newPatch: 169 error("File",self.filename(),"seems to be incomplete") 170 171 return self._patchInfo
172
173 - def writeTo(self,fName):
174 """Write to a file""" 175 if hasattr(fName, 'write'): 176 f=fName 177 else: 178 f=open(fName,"w") 179 180 f.write("\n".join(self._contents))
181
182 - def __iter__(self):
183 for l in self._contents: 184 yield l
185
186 - def __iadd__(self,other):
187 self.resetInfo() 188 189 fName=path.splitext(other.filename())[0] 190 moreThanOne=len(other.patchInfo())>1 191 192 nr=1 193 194 for l in other: 195 if l.strip().find("solid")==0 or l.strip().find("endsolid")==0: 196 parts=l.split() 197 if len(parts)==1: 198 l=parts[0]+" "+fName 199 if moreThanOne: 200 l+="_%04d" % nr 201 else: 202 l=parts[0]+" %s:%s" %(fName," ".join(parts[1:])) 203 if parts[0]=="solid": 204 nr+=1 205 206 self._contents.append(l) 207 208 return self
209 210 # Should work with Python3 and Python2 211