]> SALOME platform Git repositories - modules/smesh.git/blob - src/Tools/MGCleanerPlug/MGCleanerMonPlugDialog.py
Salome HOME
new gui
[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         """
142         for RB in self.GBOptim.findChildren(QRadioButton,):
143             if RB.isChecked()==True:
144                text+="Optimisation ='"+RB.text()+"'\n"
145                break
146         for RB in self.GBUnit.findChildren(QRadioButton,):
147             if RB.isChecked()==True:
148                text+="Units ='"+RB.text()+"'\n"
149         text+='Chordal_Tolerance_Deviation='+str(self.SP_Tolerance.value())+'\n'
150         text+='Ridge_Detection=' + str(self.CB_Ridge.isChecked())+'\n'
151         text+='Split_Edge='      + str(self.CB_SplitEdge.isChecked())+'\n'
152         text+='Point_Smoothing=' + str(self.CB_Point.isChecked())+'\n'
153         text+='Geometrical_Approximation='+ str(self.SP_Geomapp.value())  +'\n'
154         text+='Ridge_Angle='              + str(self.SP_Ridge.value())    +'\n'
155         text+='Maximum_Size='             + str(self.SP_MaxSize.value())  +'\n'
156         text+='Minimum_Size='             + str(self.SP_MaxSize.value())  +'\n'
157         text+='Mesh_Gradation='           + str(self.SP_Gradation.value())+'\n'
158         text+='Verbosity='                + str(self.SP_Verbosity.value())+'\n'
159         text+='\n\n'
160         """
161         try:
162            f=open(self.paramsFile,'a')
163         except:
164            QMessageBox.warning(self, "File", "Unable to open "+self.paramsFile)
165            return
166         try:
167            f.write(text)
168         except:
169            QMessageBox.warning(self, "File", "Unable to write "+self.paramsFile)
170            return
171         f.close()
172
173   def PBLoadPressed(self):
174         try:
175            f=open(self.paramsFile,'r')
176         except :
177            QMessageBox.warning(self, "File", "Unable to open "+self.paramsFile)
178            return
179         try:
180            text=f.read()
181         except :
182            QMessageBox.warning(self, "File", "Unable to read "+self.paramsFile)
183            return
184         f.close()
185         d={}
186         exec text in d
187         for RB in self.GBOptim.findChildren(QRadioButton,):
188             if d['Optimisation']== RB.text():
189                RB.setChecked(True)
190                break
191         for RB in self.GBUnit.findChildren(QRadioButton,):
192             if d['Units']==RB.text():
193                RB.setChecked(True)
194                break
195         self.SP_Tolerance.setValue(d['Chordal_Tolerance_Deviation'])
196
197         self.CB_Ridge.setChecked(d['Ridge_Detection'])
198         self.CB_Point.setChecked(d['Point_Smoothing'])
199         self.CB_SplitEdge.setChecked(d['Split_Edge'])
200         self.SP_Geomapp.setValue(d['Geometrical_Approximation'])
201         self.SP_Ridge.setValue(d['Ridge_Angle'])
202         self.SP_MaxSize.setValue(d['Maximum_Size'])
203         self.SP_MinSize.setValue(d['Minimum_Size'])
204         self.SP_Gradation.setValue(d['Mesh_Gradation'])
205
206         self.SP_Verbosity.setValue(d['Verbosity'])
207         self.SP_Memory.setValue(d['Memory'])
208
209
210   def PBCancelPressed(self):
211         self.close()
212
213   def PBMeshFilePressed(self):
214        fd = QFileDialog(self, "select an existing Mesh file", self.LE_MeshFile.text(), "Mesh-Files (*.mesh);;All Files (*)")
215        if fd.exec_():
216           infile = fd.selectedFiles()[0]
217           self.LE_MeshFile.setText(infile)
218           self.fichierIn=infile.toLatin1()
219
220   def setParamsFileName(self):
221        fd = QFileDialog(self, "select a file", self.LE_ParamsFile.text(), "dat Files (*.dat);;All Files (*)")
222        if fd.exec_():
223           infile = fd.selectedFiles()[0]
224           self.LE_ParamsFile.setText(infile)
225           self.paramsFile=infile.toLatin1()
226
227   def meshFileNameChanged(self):
228       self.fichierIn=self.LE_MeshFile.text()
229       if os.path.exists(self.fichierIn): return
230       QMessageBox.warning( self, "Unknown File", "File doesn't exist")
231
232   def paramsFileNameChanged(self):
233       self.paramsFile=self.LE_ParamsFile.text()
234
235   def PBMeshSmeshPressed(self):
236       import salome
237       import smesh
238       from salome.kernel import studyedit
239       from salome.smesh.smeshstudytools import SMeshStudyTools
240       from salome.gui import helper as guihelper
241       from omniORB import CORBA
242
243       mySObject, myEntry = guihelper.getSObjectSelected()
244       if CORBA.is_nil(mySObject) or mySObject==None:
245          QMessageBox.critical(self, "Mesh", "select an input mesh")
246          return
247       self.smeshStudyTool = SMeshStudyTools()
248       self.__selectedMesh = self.smeshStudyTool.getMeshObjectFromSObject(mySObject)
249       if CORBA.is_nil(self.__selectedMesh):
250          QMessageBox.critical(self, "Mesh", "select an input mesh")
251          return
252       myName = mySObject.GetName()
253       self.MeshIn=myName
254       self.LE_MeshSmesh.setText(myName)
255
256   def prepareFichier(self):
257       self.fichierIn="/tmp/PourMGCleaner_"+str(self.num)+".mesh"
258       import SMESH
259       self.__selectedMesh.ExportGMF(self.__selectedMesh,self.fichierIn, True)
260
261   def PrepareLigneCommande(self):
262       """
263       #use doc examples of mg-cleaner:
264       ls -al /data/tmplgls/salome/prerequis/install/COMMON_64/MeshGems-1.0/bin
265       source /data/tmplgls/salome/prerequis/install/LICENSE/dlim8.var.sh
266       export PATH=/data/tmplgls/salome/prerequis/install/COMMON_64/MeshGems-1.0/bin/Linux_64:$PATH
267       cp -r /data/tmplgls/salome/prerequis/install/COMMON_64/MeshGems-1.0/examples .
268       cd examples
269       mg-cleaner.exe --help
270       mg-cleaner.exe --in case7.mesh --out case7-test.mesh --check
271       mg-cleaner.exe case7.mesh case7-fix.mesh --fix
272       mg-cleaner.exe --in Porsche.mesh --out Porsche-test.mesh --check
273       mg-cleaner.exe --in Porsche.mesh --out Porschefix.mesh --fix
274       mg-cleaner.exe --in Porsche.mesh --out PorscheNewfix.mesh --fix --resolution_length 0.03
275       """
276       
277       #self.commande="mg-cleaner.exe --in " + self.fichierIn + " --out " + self.fichierOut + " --fix2pass" 
278       #return True
279       if self.fichierIn=="" and self.MeshIn=="" :
280         QMessageBox.critical(self, "Mesh", "select an input mesh")
281         return False
282       if self.MeshIn!="" : self.prepareFichier()
283       if not (os.path.isfile(self.fichierIn)):
284         QMessageBox.critical(self, "File", "unable to read GMF Mesh in "+str(self.fichierIn))
285         return False
286      
287       self.commande="mg-cleaner.exe"
288       verbosity=str(self.SP_Verbosity.value())
289       self.commande+=" --verbose " + verbosity
290       self.commande+=" --in " + self.fichierIn
291       deb=os.path.splitext(self.fichierIn)
292       self.fichierOut=deb[0] + "_fix.mesh"
293       self.commande+=" --out "+self.fichierOut
294       if self.RB_Fix1.isChecked():
295         self.commande+=" --fix1pass"
296       else:
297         if self.RB_Fix2.isChecked():
298           self.commande+=" --fix2pass"
299         else:
300           self.commande+=" --check"
301       if self.CB_PreserveTopology.isChecked():
302         self.commande+=" --topology respect"
303       else:
304         self.commande+=" --topology ignore"
305       if self.CB_FillHoles.isChecked(): #no fill holes default
306         self.commande+=" --min_hole_size " + str(self.SP_minHoleSize.value())
307       if not self.CB_computedToleranceDisplacement.isChecked(): #computed default
308         self.commande+=" --tolerance_displacement " + str(self.SP_toleranceDisplacement.value())
309       if not self.CB_computedResolutionLength.isChecked(): #computed default
310         self.commande+=" --tolerance_displacement " + str(self.SP_resolutionLength.value())
311       self.commande+=" --folding_angle " + str(self.SP_foldingAngle.value())
312       if self.CB_RemeshPlanes.isChecked(): #no remesh default
313         self.commande+=" --remesh_planes"
314       if not self.CB_computedOverlapDistance.isChecked(): #computed default
315         self.commande+=" --overlap_distance " + str(self.SP_overlapDistance.value())
316       self.commande+=" --overlap_angle " + str(self.SP_overlapAngle.value())
317       return True
318       
319   def clean(self):
320       self.RB_Check.setChecked(False)
321       self.RB_Fix1.setChecked(False)
322       self.RB_Fix2.setChecked(True)
323       self.CB_PreserveTopology.setChecked(False)
324       self.CB_FillHoles.setChecked(False)
325       self.CB_RemeshPlanes.setChecked(False)
326       
327       self.SP_minHoleSize.setProperty("value", 0)
328       self.SP_toleranceDisplacement.setProperty("value", 0)
329       self.SP_resolutionLength.setProperty("value", 0)
330       self.SP_foldingAngle.setProperty("value", 15)
331       self.SP_overlapDistance.setProperty("value", 0)
332       self.SP_overlapAngle.setProperty("value", 15)
333       self.SP_Verbosity.setProperty("value", 3)
334       
335       self.CB_computedToleranceDisplacement.setChecked(True)
336       self.CB_computedResolutionLength.setChecked(True)
337       self.CB_computedOverlapDistance.setChecked(True)
338
339 __dialog=None
340 def getDialog():
341     """
342     This function returns a singleton instance of the plugin dialog.
343     c est obligatoire pour faire un show sans parent...
344     """
345     global __dialog
346     if __dialog is None:
347         __dialog = MGCleanerMonPlugDialog()
348     #else :
349     #   __dialog.clean()
350     return __dialog
351
352
353 #
354 # ==============================================================================
355 # Basic use cases and unit test functions
356 # ==============================================================================
357 #
358 def TEST_MGCleanerMonPlugDialog():
359     print 'TEST_MGCleanerMonPlugDialog'
360     import sys
361     from PyQt4.QtGui import QApplication
362     from PyQt4.QtCore import QObject, SIGNAL, SLOT
363     app = QApplication(sys.argv)
364     QObject.connect(app, SIGNAL("lastWindowClosed()"), app, SLOT("quit()"))
365
366     dlg=MGCleanerMonPlugDialog()
367     dlg.show()
368     sys.exit(app.exec_())
369
370 if __name__ == "__main__":
371     TEST_MGCleanerMonPlugDialog()