]> SALOME platform Git repositories - modules/smesh.git/blob - src/Tools/MGCleanerPlug/MGCleanerMonPlugDialog.py
Salome HOME
save load params
[modules/smesh.git] / src / Tools / MGCleanerPlug / MGCleanerMonPlugDialog.py
1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2007-2013  EDF R&D
3 #
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.
8 #
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.
13 #
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
17 #
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 #
20
21 # Modules Python
22 # Modules Eficas
23
24 import os, subprocess
25 from MGCleanerPlugDialog import Ui_MGCleanerPlugDialog
26 from MGCleanerMonViewText import MGCleanerMonViewText
27 from PyQt4.QtGui import *
28 from PyQt4.QtCore import *
29
30
31 class MGCleanerMonPlugDialog(Ui_MGCleanerPlugDialog,QWidget):
32   """
33   """
34   def __init__(self):
35         QWidget.__init__(self)
36         self.setupUi(self)
37         self.connecterSignaux()
38         self.fichierIn=""
39         self.fichierOut=""
40         self.MeshIn="" 
41         self.num=1
42
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__))
47
48         iconfolder=os.environ["SMESH_ROOT_DIR"]+"/share/salome/resources/smesh"
49         #print "MGCleanerMonPlugDialog iconfolder",iconfolder
50         icon = QIcon()
51         icon.addFile(os.path.join(iconfolder,"select1.png"))
52         self.PB_MeshSmesh.setIcon(icon)
53         icon = QIcon()
54         icon.addFile(os.path.join(iconfolder,"open.png"))
55         self.PB_ParamsFileExplorer.setIcon(icon)
56
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("")
62         self.resize(800, 500)
63         self.clean()
64
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)
77
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)
83         
84   def PBHelpPressed(self):
85         try :
86           mydir=os.environ["SMESH_ROOT_DIR"]
87         except Exception:
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)
92
93
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()
99
100   def enregistreResultat(self):
101         import smesh
102         import SMESH
103         import salome
104         from salome.kernel import studyedit
105
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)
111         outputMesh.Compute()
112
113
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))
126         
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)
131         self.num+=1
132         return True
133
134   def PBSavePressed(self,NomHypo=False):
135         if NomHypo: 
136           text = "# Params for Hypothese : anHypo_MGCleaner_"+str(self.num - 1)+"\n"
137         else:
138           text = "# Save intermediate params \n" 
139         text += "# Params for mesh : " +  self.LE_MeshSmesh.text() +"\n"
140
141         if self.RB_Fix1.isChecked():
142           CheckOrFix="fix1pass"
143         else:
144           if self.RB_Fix2.isChecked():
145             CheckOrFix="fix2pass"
146           else:
147             CheckOrFix="check"
148         text+="CheckOrFix=" + CheckOrFix+"\n"
149         
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"
163         text+="\n\n"
164
165         try:
166            f=open(self.paramsFile,"a")
167         except:
168            QMessageBox.warning(self, "File", "Unable to open "+self.paramsFile)
169            return
170         try:
171            f.write(text)
172         except:
173            QMessageBox.warning(self, "File", "Unable to write "+self.paramsFile)
174            return
175         f.close()
176
177   def PBLoadPressed(self):
178         try:
179            f=open(self.paramsFile,"r")
180         except :
181            QMessageBox.warning(self, "File", "Unable to open "+self.paramsFile)
182            return
183         try:
184            text=f.read()
185         except :
186            QMessageBox.warning(self, "File", "Unable to read "+self.paramsFile)
187            return
188         f.close()
189         
190         self.clean()
191         for slig in reversed(text.split("\n")):
192           lig=slig.strip()
193           #print "load params",self.paramsFile,lig
194           if lig=="": continue #skip blanck lines
195           if lig[0]=="#": break
196           try:
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)))
218           except:
219             QMessageBox.warning(self, "File", "Problem to read '"+lig+"'")
220         
221
222   def PBCancelPressed(self):
223         self.close()
224
225   def PBMeshFilePressed(self):
226        fd = QFileDialog(self, "select an existing Mesh file", self.LE_MeshFile.text(), "Mesh-Files (*.mesh);;All Files (*)")
227        if fd.exec_():
228           infile = fd.selectedFiles()[0]
229           self.LE_MeshFile.setText(infile)
230           self.fichierIn=infile.toLatin1()
231
232   def setParamsFileName(self):
233        fd = QFileDialog(self, "select a file", self.LE_ParamsFile.text(), "dat Files (*.dat);;All Files (*)")
234        if fd.exec_():
235           infile = fd.selectedFiles()[0]
236           self.LE_ParamsFile.setText(infile)
237           self.paramsFile=infile.toLatin1()
238
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")
243
244   def paramsFileNameChanged(self):
245       self.paramsFile=self.LE_ParamsFile.text()
246
247   def PBMeshSmeshPressed(self):
248       import salome
249       import smesh
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
254
255       mySObject, myEntry = guihelper.getSObjectSelected()
256       if CORBA.is_nil(mySObject) or mySObject==None:
257          QMessageBox.critical(self, "Mesh", "select an input mesh")
258          return
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")
263          return
264       myName = mySObject.GetName()
265       self.MeshIn=myName
266       self.LE_MeshSmesh.setText(myName)
267
268   def prepareFichier(self):
269       self.fichierIn="/tmp/PourMGCleaner_"+str(self.num)+".mesh"
270       import SMESH
271       self.__selectedMesh.ExportGMF(self.__selectedMesh,self.fichierIn, True)
272
273   def PrepareLigneCommande(self):
274       """
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 .
280       cd 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
287       """
288       
289       #self.commande="mg-cleaner.exe --in " + self.fichierIn + " --out " + self.fichierOut + " --fix2pass" 
290       #return True
291       if self.fichierIn=="" and self.MeshIn=="" :
292         QMessageBox.critical(self, "Mesh", "select an input mesh")
293         return False
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))
297         return False
298      
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"
308       else:
309         if self.RB_Fix2.isChecked():
310           self.commande+=" --fix2pass"
311         else:
312           self.commande+=" --check"
313       if self.CB_PreserveTopology.isChecked():
314         self.commande+=" --topology respect"
315       else:
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())
329       return True
330       
331   def clean(self):
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)
338       
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)
346       
347       self.CB_ComputedToleranceDisplacement.setChecked(True)
348       self.CB_ComputedResolutionLength.setChecked(True)
349       self.CB_ComputedOverlapDistance.setChecked(True)
350
351 __dialog=None
352 def getDialog():
353     """
354     This function returns a singleton instance of the plugin dialog.
355     c est obligatoire pour faire un show sans parent...
356     """
357     global __dialog
358     if __dialog is None:
359         __dialog = MGCleanerMonPlugDialog()
360     #else :
361     #   __dialog.clean()
362     return __dialog
363
364
365 #
366 # ==============================================================================
367 # Basic use cases and unit test functions
368 # ==============================================================================
369 #
370 def TEST_MGCleanerMonPlugDialog():
371     print "TEST_MGCleanerMonPlugDialog"
372     import sys
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()"))
377
378     dlg=MGCleanerMonPlugDialog()
379     dlg.show()
380     sys.exit(app.exec_())
381
382 if __name__ == "__main__":
383     TEST_MGCleanerMonPlugDialog()