1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2007-2013 EDF R&D
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2.1 of the License.
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # Lesser General Public License for more details.
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
25 from MGCleanerPlugDialog import Ui_MGCleanerPlugDialog
26 from MGCleanerMonViewText import MGCleanerMonViewText
27 from PyQt4.QtGui import *
28 from PyQt4.QtCore import *
31 class MGCleanerMonPlugDialog(Ui_MGCleanerPlugDialog,QWidget):
35 QWidget.__init__(self)
37 self.connecterSignaux()
43 # complex whith QResources: not used
44 # The icon are supposed to be located in the $SMESH_ROOT_DIR/share/salome/resources/smesh folder,
45 # other solution could be in the same folder than this python module file:
46 # iconfolder=os.path.dirname(os.path.abspath(__file__))
48 iconfolder=os.environ["SMESH_ROOT_DIR"]+"/share/salome/resources/smesh"
49 #print "MGCleanerMonPlugDialog iconfolder",iconfolder
51 icon.addFile(os.path.join(iconfolder,"select1.png"))
52 self.PB_MeshSmesh.setIcon(icon)
54 icon.addFile(os.path.join(iconfolder,"open.png"))
55 self.PB_ParamsFileExplorer.setIcon(icon)
57 #Ces parametres ne sont pas remis à rien par le clean
58 self.paramsFile= os.path.abspath(os.path.join(os.environ["HOME"],".MGCleaner.dat"))
59 self.LE_ParamsFile.setText(self.paramsFile)
60 self.LE_MeshFile.setText("")
61 self.LE_MeshSmesh.setText("")
65 def connecterSignaux(self) :
66 self.connect(self.PB_Cancel,SIGNAL("clicked()"),self.PBCancelPressed)
67 self.connect(self.PB_Default,SIGNAL("clicked()"),self.clean)
68 self.connect(self.PB_Help,SIGNAL("clicked()"),self.PBHelpPressed)
69 self.connect(self.PB_Load,SIGNAL("clicked()"),self.PBLoadPressed)
70 self.connect(self.PB_OK,SIGNAL("clicked()"),self.PBOKPressed)
71 self.connect(self.PB_Save,SIGNAL("clicked()"),self.PBSavePressed)
72 self.connect(self.PB_MeshFile,SIGNAL("clicked()"),self.PBMeshFilePressed)
73 self.connect(self.PB_MeshSmesh,SIGNAL("clicked()"),self.PBMeshSmeshPressed)
74 self.connect(self.PB_ParamsFileExplorer,SIGNAL("clicked()"),self.setParamsFileName)
75 self.connect(self.LE_MeshFile,SIGNAL("returnPressed()"),self.meshFileNameChanged)
76 self.connect(self.LE_ParamsFile,SIGNAL("returnPressed()"),self.paramsFileNameChanged)
78 #QtCore.QObject.connect(self.checkBox, QtCore.SIGNAL("stateChanged(int)"), self.change)
79 self.connect(self.CB_FillHoles,SIGNAL("stateChanged(int)"),self.SP_MinHoleSize.setEnabled)
80 self.connect(self.CB_ComputedToleranceDisplacement,SIGNAL("stateChanged(int)"),self.SP_ToleranceDisplacement.setDisabled)
81 self.connect(self.CB_ComputedResolutionLength,SIGNAL("stateChanged(int)"),self.SP_ResolutionLength.setDisabled)
82 self.connect(self.CB_ComputedOverlapDistance,SIGNAL("stateChanged(int)"),self.SP_OverlapDistance.setDisabled)
84 def PBHelpPressed(self):
86 mydir=os.environ["SMESH_ROOT_DIR"]
88 QMessageBox.warning( self, "Help unavailable $SMESH_ROOT_DIR not found")
89 maDoc=mydir+"/share/doc/salome/gui/SMESH/MGCleaner/_downloads/mg-cleaner_user_manual.pdf"
90 command="xdg-open "+maDoc+";"
91 subprocess.call(command, shell=True)
94 def PBOKPressed(self):
95 if not(self.PrepareLigneCommande()): return
96 self.PBSavePressed(NomHypo=True)
97 maFenetre=MGCleanerMonViewText(self,self.commande)
98 if os.path.isfile(self.fichierOut): self.enregistreResultat()
100 def enregistreResultat(self):
104 from salome.kernel import studyedit
106 maStudy=studyedit.getActiveStudy()
107 smesh.SetCurrentStudy(maStudy)
108 (outputMesh, status) = smesh.CreateMeshesFromGMF(self.fichierOut)
109 meshname = "MGCleaner"+str(self.num)
110 smesh.SetName(outputMesh.GetMesh(), meshname)
114 self.editor = studyedit.getStudyEditor() #
115 moduleEntry=self.editor.findOrCreateComponent("SMESH","SMESH")
116 HypReMeshEntry = self.editor.findOrCreateItem( moduleEntry, name = "HypoForRemesh",
117 comment = "HypoForRemeshing")
118 monStudyBuilder=maStudy.NewBuilder();
119 monStudyBuilder.NewCommand();
120 newStudyIter=monStudyBuilder.NewObject(HypReMeshEntry)
121 aNameAttrib=monStudyBuilder.FindOrCreateAttribute(newStudyIter,"AttributeName")
122 hypoName = "anHypo_MGCleaner_"+str(self.num)
123 aNameAttrib.SetValue(hypoName)
124 aCommentAttrib=monStudyBuilder.FindOrCreateAttribute(newStudyIter,"AttributeComment")
125 aCommentAttrib.SetValue(str(self.commande))
127 SOMesh=maStudy.FindObjectByName(meshname ,"SMESH")[0]
128 newLink=monStudyBuilder.NewObject(SOMesh)
129 monStudyBuilder.Addreference(newLink, newStudyIter);
130 if salome.sg.hasDesktop(): salome.sg.updateObjBrowser(0)
134 def PBSavePressed(self,NomHypo=False):
136 text = "# Params for Hypothese : anHypo_MGCleaner_"+str(self.num - 1)+"\n"
138 text = "# Save intermediate params \n"
139 text += "# Params for mesh : " + self.LE_MeshSmesh.text() +"\n"
141 if self.RB_Fix1.isChecked():
142 CheckOrFix="fix1pass"
144 if self.RB_Fix2.isChecked():
145 CheckOrFix="fix2pass"
148 text+="CheckOrFix=" + CheckOrFix+"\n"
150 text+="PreserveTopology=" + str(self.CB_PreserveTopology.isChecked())+"\n"
151 text+="FillHoles=" + str(self.CB_FillHoles.isChecked())+"\n"
152 text+="MinHoleSize=" + str(self.SP_MinHoleSize.value())+"\n"
153 text+="ComputedToleranceDisplacement=" + str(self.CB_ComputedToleranceDisplacement.isChecked())+"\n"
154 text+="ToleranceDisplacement=" + str(self.SP_ToleranceDisplacement.value())+"\n"
155 text+="ComputedResolutionLength=" + str(self.CB_ComputedResolutionLength.isChecked())+"\n"
156 text+="ResolutionLength=" + str(self.SP_ResolutionLength.value())+"\n"
157 text+="FoldingAngle=" + str(self.SP_FoldingAngle.value())+"\n"
158 text+="RemeshPlanes=" + str(self.CB_RemeshPlanes.isChecked())+"\n"
159 text+="ComputedOverlapDistance=" + str(self.CB_ComputedOverlapDistance.isChecked())+"\n"
160 text+="OverlapDistance=" + str(self.SP_OverlapDistance.value())+"\n"
161 text+="OverlapAngle=" + str(self.SP_OverlapAngle.value())+"\n"
162 text+="Verbosity=" + str(self.SP_Verbosity.value())+"\n"
166 f=open(self.paramsFile,"a")
168 QMessageBox.warning(self, "File", "Unable to open "+self.paramsFile)
173 QMessageBox.warning(self, "File", "Unable to write "+self.paramsFile)
177 def PBLoadPressed(self):
179 f=open(self.paramsFile,"r")
181 QMessageBox.warning(self, "File", "Unable to open "+self.paramsFile)
186 QMessageBox.warning(self, "File", "Unable to read "+self.paramsFile)
191 for slig in reversed(text.split("\n")):
193 #print "load params",self.paramsFile,lig
194 if lig=="": continue #skip blanck lines
195 if lig[0]=="#": break
197 tit,value=lig.split("=")
198 if tit=="CheckOrFix":
199 self.RB_Fix1.setChecked(False)
200 self.RB_Fix2.setChecked(False)
201 self.RB_Check.setChecked(False)
202 if value=="fix1pass": self.RB_Fix1.setChecked(True)
203 if value=="fix2pass": self.RB_Fix2.setChecked(True)
204 if value=="check": self.RB_Check.setChecked(True)
205 if tit=="PreserveTopology": self.CB_PreserveTopology.setChecked(bool(value))
206 if tit=="FillHoles": self.CB_FillHoles.setChecked(bool(value))
207 if tit=="MinHoleSize": self.SP_MinHoleSize.setProperty("value", float(value))
208 if tit=="ComputedToleranceDisplacement": self.CB_ComputedToleranceDisplacement.setChecked(bool(value))
209 if tit=="ToleranceDisplacement": self.SP_ToleranceDisplacement.setProperty("value", float(value))
210 if tit=="ComputedResolutionLength": self.CB_ComputedResolutionLength.setChecked(bool(value))
211 if tit=="ResolutionLength": self.SP_ResolutionLength.setProperty("value", float(value))
212 if tit=="FoldingAngle": self.SP_FoldingAngle.setProperty("value", float(value))
213 if tit=="RemeshPlanes": self.CB_RemeshPlanes.setChecked(bool(value))
214 if tit=="ComputedOverlapDistance": self.CB_ComputedOverlapDistance.setChecked(bool(value))
215 if tit=="OverlapDistance": self.SP_OverlapDistance.setProperty("value", float(value))
216 if tit=="OverlapAngle": self.SP_OverlapAngle.setProperty("value", float(value))
217 if tit=="Verbosity": self.SP_Verbosity.setProperty("value", int(float(value)))
219 QMessageBox.warning(self, "File", "Problem to read '"+lig+"'")
222 def PBCancelPressed(self):
225 def PBMeshFilePressed(self):
226 fd = QFileDialog(self, "select an existing Mesh file", self.LE_MeshFile.text(), "Mesh-Files (*.mesh);;All Files (*)")
228 infile = fd.selectedFiles()[0]
229 self.LE_MeshFile.setText(infile)
230 self.fichierIn=infile.toLatin1()
232 def setParamsFileName(self):
233 fd = QFileDialog(self, "select a file", self.LE_ParamsFile.text(), "dat Files (*.dat);;All Files (*)")
235 infile = fd.selectedFiles()[0]
236 self.LE_ParamsFile.setText(infile)
237 self.paramsFile=infile.toLatin1()
239 def meshFileNameChanged(self):
240 self.fichierIn=self.LE_MeshFile.text()
241 if os.path.exists(self.fichierIn): return
242 QMessageBox.warning( self, "Unknown File", "File doesn't exist")
244 def paramsFileNameChanged(self):
245 self.paramsFile=self.LE_ParamsFile.text()
247 def PBMeshSmeshPressed(self):
250 from salome.kernel import studyedit
251 from salome.smesh.smeshstudytools import SMeshStudyTools
252 from salome.gui import helper as guihelper
253 from omniORB import CORBA
255 mySObject, myEntry = guihelper.getSObjectSelected()
256 if CORBA.is_nil(mySObject) or mySObject==None:
257 QMessageBox.critical(self, "Mesh", "select an input mesh")
259 self.smeshStudyTool = SMeshStudyTools()
260 self.__selectedMesh = self.smeshStudyTool.getMeshObjectFromSObject(mySObject)
261 if CORBA.is_nil(self.__selectedMesh):
262 QMessageBox.critical(self, "Mesh", "select an input mesh")
264 myName = mySObject.GetName()
266 self.LE_MeshSmesh.setText(myName)
268 def prepareFichier(self):
269 self.fichierIn="/tmp/PourMGCleaner_"+str(self.num)+".mesh"
271 self.__selectedMesh.ExportGMF(self.__selectedMesh,self.fichierIn, True)
273 def PrepareLigneCommande(self):
275 #use doc examples of mg-cleaner:
276 ls -al /data/tmplgls/salome/prerequis/install/COMMON_64/MeshGems-1.0/bin
277 source /data/tmplgls/salome/prerequis/install/LICENSE/dlim8.var.sh
278 export PATH=/data/tmplgls/salome/prerequis/install/COMMON_64/MeshGems-1.0/bin/Linux_64:$PATH
279 cp -r /data/tmplgls/salome/prerequis/install/COMMON_64/MeshGems-1.0/examples .
281 mg-cleaner.exe --help
282 mg-cleaner.exe --in case7.mesh --out case7-test.mesh --check
283 mg-cleaner.exe case7.mesh case7-fix.mesh --fix
284 mg-cleaner.exe --in Porsche.mesh --out Porsche-test.mesh --check
285 mg-cleaner.exe --in Porsche.mesh --out Porschefix.mesh --fix
286 mg-cleaner.exe --in Porsche.mesh --out PorscheNewfix.mesh --fix --resolution_length 0.03
289 #self.commande="mg-cleaner.exe --in " + self.fichierIn + " --out " + self.fichierOut + " --fix2pass"
291 if self.fichierIn=="" and self.MeshIn=="" :
292 QMessageBox.critical(self, "Mesh", "select an input mesh")
294 if self.MeshIn!="" : self.prepareFichier()
295 if not (os.path.isfile(self.fichierIn)):
296 QMessageBox.critical(self, "File", "unable to read GMF Mesh in "+str(self.fichierIn))
299 self.commande="mg-cleaner.exe"
300 verbosity=str(self.SP_Verbosity.value())
301 self.commande+=" --verbose " + verbosity
302 self.commande+=" --in " + self.fichierIn
303 deb=os.path.splitext(self.fichierIn)
304 self.fichierOut=deb[0] + "_fix.mesh"
305 self.commande+=" --out "+self.fichierOut
306 if self.RB_Fix1.isChecked():
307 self.commande+=" --fix1pass"
309 if self.RB_Fix2.isChecked():
310 self.commande+=" --fix2pass"
312 self.commande+=" --check"
313 if self.CB_PreserveTopology.isChecked():
314 self.commande+=" --topology respect"
316 self.commande+=" --topology ignore"
317 if self.CB_FillHoles.isChecked(): #no fill holes default
318 self.commande+=" --min_hole_size " + str(self.SP_MinHoleSize.value())
319 if not self.CB_ComputedToleranceDisplacement.isChecked(): #computed default
320 self.commande+=" --tolerance_displacement " + str(self.SP_ToleranceDisplacement.value())
321 if not self.CB_ComputedResolutionLength.isChecked(): #computed default
322 self.commande+=" --tolerance_displacement " + str(self.SP_ResolutionLength.value())
323 self.commande+=" --folding_angle " + str(self.SP_FoldingAngle.value())
324 if self.CB_RemeshPlanes.isChecked(): #no remesh default
325 self.commande+=" --remesh_planes"
326 if not self.CB_ComputedOverlapDistance.isChecked(): #computed default
327 self.commande+=" --overlap_distance " + str(self.SP_OverlapDistance.value())
328 self.commande+=" --overlap_angle " + str(self.SP_OverlapAngle.value())
332 self.RB_Check.setChecked(False)
333 self.RB_Fix1.setChecked(False)
334 self.RB_Fix2.setChecked(True)
335 self.CB_PreserveTopology.setChecked(False)
336 self.CB_FillHoles.setChecked(False)
337 self.CB_RemeshPlanes.setChecked(False)
339 self.SP_MinHoleSize.setProperty("value", 0)
340 self.SP_ToleranceDisplacement.setProperty("value", 0)
341 self.SP_ResolutionLength.setProperty("value", 0)
342 self.SP_FoldingAngle.setProperty("value", 15)
343 self.SP_OverlapDistance.setProperty("value", 0)
344 self.SP_OverlapAngle.setProperty("value", 15)
345 self.SP_Verbosity.setProperty("value", 3)
347 self.CB_ComputedToleranceDisplacement.setChecked(True)
348 self.CB_ComputedResolutionLength.setChecked(True)
349 self.CB_ComputedOverlapDistance.setChecked(True)
354 This function returns a singleton instance of the plugin dialog.
355 c est obligatoire pour faire un show sans parent...
359 __dialog = MGCleanerMonPlugDialog()
366 # ==============================================================================
367 # Basic use cases and unit test functions
368 # ==============================================================================
370 def TEST_MGCleanerMonPlugDialog():
371 print "TEST_MGCleanerMonPlugDialog"
373 from PyQt4.QtGui import QApplication
374 from PyQt4.QtCore import QObject, SIGNAL, SLOT
375 app = QApplication(sys.argv)
376 QObject.connect(app, SIGNAL("lastWindowClosed()"), app, SLOT("quit()"))
378 dlg=MGCleanerMonPlugDialog()
380 sys.exit(app.exec_())
382 if __name__ == "__main__":
383 TEST_MGCleanerMonPlugDialog()