Salome HOME
merge from BR_pluginMGCleaner tag mergeto_v7_main_17jun13
[modules/smesh.git] / src / Tools / YamsPlug / monYamsPlugDialog.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 YamsPlugDialog import Ui_YamsPlugDialog
26 from monViewText import MonViewText
27 from PyQt4.QtGui import *
28 from PyQt4.QtCore import *
29
30
31 class MonYamsPlugDialog(Ui_YamsPlugDialog,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.commande=""
42     self.num=1
43     self.__selectedMesh=None
44
45     # complex whith QResources: not used
46     # The icon are supposed to be located in the $SMESH_ROOT_DIR/share/salome/resources/smesh folder,
47     # other solution could be in the same folder than this python module file:
48     # iconfolder=os.path.dirname(os.path.abspath(__file__))
49
50     self.iconfolder=os.environ["SMESH_ROOT_DIR"]+"/share/salome/resources/smesh"
51     #print "monYamsPlugDialog iconfolder",iconfolder
52     icon = QIcon()
53     icon.addFile(os.path.join(self.iconfolder,"select1.png"))
54     self.PB_LoadHyp.setIcon(icon)
55     self.PB_LoadHyp.setToolTip("hypothesis from Salome Object Browser")
56     self.PB_SaveHyp.setIcon(icon)
57     self.PB_SaveHyp.setToolTip("hypothesis to Salome Object Browser")
58     self.PB_MeshSmesh.setIcon(icon)
59     self.PB_MeshSmesh.setToolTip("source mesh from Salome Object Browser")
60     icon = QIcon()
61     icon.addFile(os.path.join(self.iconfolder,"open.png"))
62     self.PB_ParamsFileExplorer.setIcon(icon)
63     self.PB_Load.setIcon(icon)
64     self.PB_Load.setToolTip("hypothesis from file")
65     self.PB_Save.setIcon(icon)
66     self.PB_Save.setToolTip("hypothesis to file")
67     self.PB_MeshFile.setIcon(icon)
68     self.PB_MeshFile.setToolTip("source mesh from a file in disk")
69
70     #Ces parametres ne sont pas remis à rien par le clean
71     self.paramsFile= os.path.abspath(os.path.join(os.environ["HOME"],".yams.dat"))
72     self.LE_ParamsFile.setText(self.paramsFile)
73     self.LE_MeshFile.setText("")
74     self.LE_MeshSmesh.setText("")
75     
76     v1=QDoubleValidator(self)
77     v1.setBottom(0.)
78     #v1.setTop(1000.) #per thousand... only if relative
79     v1.setDecimals(2)
80     self.SP_Tolerance.setValidator(v1)
81     self.SP_Tolerance.titleForWarning="Chordal Tolerance"
82     
83     self.resize(800, 600)
84     self.clean()
85
86   def connecterSignaux(self) :
87     self.connect(self.PB_Cancel,SIGNAL("clicked()"),self.PBCancelPressed)
88     self.connect(self.PB_Default,SIGNAL("clicked()"),self.clean)
89     self.connect(self.PB_Help,SIGNAL("clicked()"),self.PBHelpPressed)
90     self.connect(self.PB_OK,SIGNAL("clicked()"),self.PBOKPressed)
91     
92     self.connect(self.PB_Load,SIGNAL("clicked()"),self.PBLoadPressed)
93     self.connect(self.PB_Save,SIGNAL("clicked()"),self.PBSavePressed)
94     self.connect(self.PB_LoadHyp,SIGNAL("clicked()"),self.PBLoadHypPressed)
95     self.connect(self.PB_SaveHyp,SIGNAL("clicked()"),self.PBSaveHypPressed)
96     
97     self.connect(self.PB_MeshFile,SIGNAL("clicked()"),self.PBMeshFilePressed)
98     self.connect(self.PB_MeshSmesh,SIGNAL("clicked()"),self.PBMeshSmeshPressed)
99     self.connect(self.LE_MeshSmesh,SIGNAL("returnPressed()"),self.meshSmeshNameChanged)
100     self.connect(self.PB_ParamsFileExplorer,SIGNAL("clicked()"),self.setParamsFileName)
101     self.connect(self.LE_MeshFile,SIGNAL("returnPressed()"),self.meshFileNameChanged)
102     self.connect(self.LE_ParamsFile,SIGNAL("returnPressed()"),self.paramsFileNameChanged)
103
104   def PBHelpPressed(self):
105     try :
106       mydir=os.environ["SMESH_ROOT_DIR"]
107     except Exception:
108       QMessageBox.warning(self, "Help", "Help unavailable $SMESH_ROOT_DIR not found")
109       return
110     maDoc=mydir+"/share/doc/salome/gui/SMESH/yams/_downloads/YamsWhitePaper_3.2.pdf"
111     command="xdg-open "+maDoc+";"
112     subprocess.call(command, shell=True)
113
114   def PBOKPressed(self):
115     if not(self.PrepareLigneCommande()):
116       #warning done yet
117       #QMessageBox.warning(self, "Compute", "Command not found")
118       return
119     maFenetre=MonViewText(self,self.commande)
120
121   def enregistreResultat(self):
122     import smesh
123     import SMESH
124     import salome
125     from salome.kernel import studyedit
126
127     if not os.path.isfile(self.fichierOut):
128       QMessageBox.warning(self, "Compute", "Result file "+self.fichierOut+" not found")
129
130     maStudy=studyedit.getActiveStudy()
131     smesh.SetCurrentStudy(maStudy)
132     (outputMesh, status) = smesh.CreateMeshesFromGMF(self.fichierOut)
133     name=str(self.LE_MeshSmesh.text())
134     initialMeshFile=None
135     initialMeshObject=None
136     if name=="":
137       a=str(self.fichierIn)
138       name=os.path.basename(os.path.splitext(a)[0])
139       initialMeshFile=a
140     else:
141       initialMeshObject=maStudy.FindObjectByName(name ,"SMESH")[0]
142
143     meshname = name+"_YAMS_"+str(self.num)
144     smesh.SetName(outputMesh.GetMesh(), meshname)
145     outputMesh.Compute() #no algorithms message for "Mesh_x" has been computed with warnings: -  global 1D algorithm is missing
146
147     self.editor = studyedit.getStudyEditor()    # 
148     moduleEntry=self.editor.findOrCreateComponent("SMESH","SMESH")
149     HypReMeshEntry = self.editor.findOrCreateItem(
150         moduleEntry, name = "Plugins Hypotheses", icon="mesh_tree_hypo.png") #, comment = "HypoForRemeshing" )
151
152     monStudyBuilder=maStudy.NewBuilder()
153     monStudyBuilder.NewCommand()
154     newStudyIter=monStudyBuilder.NewObject(HypReMeshEntry)
155     self.editor.setAttributeValue(newStudyIter, "AttributeName", "YAMS Parameters_"+str(self.num))
156     self.editor.setAttributeValue(newStudyIter, "AttributeComment", self.getResumeData(separator=" ; "))
157     
158     SOMesh=maStudy.FindObjectByName(meshname ,"SMESH")[0]
159     
160     if initialMeshFile!=None:
161       newStudyFileName=monStudyBuilder.NewObject(SOMesh)
162       self.editor.setAttributeValue(newStudyFileName, "AttributeName", "meshFile")
163       self.editor.setAttributeValue(newStudyFileName, "AttributeExternalFileDef", initialMeshFile)
164       self.editor.setAttributeValue(newStudyFileName, "AttributeComment", initialMeshFile)
165
166     if initialMeshObject!=None:
167       newLink=monStudyBuilder.NewObject(SOMesh)
168       monStudyBuilder.Addreference(newLink, initialMeshObject)
169
170     newLink=monStudyBuilder.NewObject(SOMesh)
171     monStudyBuilder.Addreference(newLink, newStudyIter)
172
173     if salome.sg.hasDesktop(): salome.sg.updateObjBrowser(0)
174     self.num+=1
175     return True
176
177   def PBSavePressed(self,NomHypo=False):
178     from datetime import datetime
179     if not(self.PrepareLigneCommande()): return
180     text = "# YAMS hypothesis parameters\n" 
181     text += "# Params for mesh : " +  self.LE_MeshSmesh.text() +"\n"
182     text += datetime.now().strftime("# Date : %d/%m/%y %H:%M:%S\n")
183     text += "# Command : "+self.commande+"\n"
184     text += self.getResumeData(separator="\n")
185     text += "\n\n"
186
187     try:
188       f=open(self.paramsFile,"a")
189     except:
190       QMessageBox.warning(self, "File", "Unable to open "+self.paramsFile)
191       return
192     try:
193       f.write(text)
194     except:
195       QMessageBox.warning(self, "File", "Unable to write "+self.paramsFile)
196       return
197     f.close()
198
199   def PBSaveHypPressed(self):
200     """save hypothesis in Object Browser"""
201     #QMessageBox.warning(self, "save Object Browser YAMS Hypothesis", "TODO")
202     
203     import smesh
204     import SMESH
205     import salome
206     from salome.kernel import studyedit
207
208     maStudy=studyedit.getActiveStudy()
209     smesh.SetCurrentStudy(maStudy)
210     
211     self.editor = studyedit.getStudyEditor()
212     moduleEntry=self.editor.findOrCreateComponent("SMESH","SMESH")
213     HypReMeshEntry = self.editor.findOrCreateItem(
214         moduleEntry, name = "Plugins Hypotheses", icon="mesh_tree_hypo.png") #, comment = "HypoForRemeshing" )
215     
216     monStudyBuilder=maStudy.NewBuilder()
217     monStudyBuilder.NewCommand()
218     newStudyIter=monStudyBuilder.NewObject(HypReMeshEntry)
219     self.editor.setAttributeValue(newStudyIter, "AttributeName", "YAMS Parameters_"+str(self.num))
220     self.editor.setAttributeValue(newStudyIter, "AttributeComment", self.getResumeData(separator=" ; "))
221     
222     if salome.sg.hasDesktop(): salome.sg.updateObjBrowser(0)
223     self.num+=1
224     return True
225
226   def SP_toStr(self, widget):
227     """only for a QLineEdit widget"""
228     #cr, pos=widget.validator().validate(res, 0) #n.b. "1,3" is acceptable !locale!
229     try:
230       val=float(widget.text())
231     except:
232       QMessageBox.warning(self, widget.titleForWarning, "float value is incorrect: '"+widget.text()+"'")
233       res=str(widget.validator().bottom())
234       widget.setProperty("text", res)
235       return res
236     valtest=widget.validator().bottom()
237     if valtest!=None:
238       if val<valtest:
239         QMessageBox.warning(self, widget.titleForWarning, "float value is under minimum: "+str(val)+" < "+str(valtest))
240         res=str(valtest)
241         widget.setProperty("text", res)
242         return res
243     valtest=widget.validator().top()
244     if valtest!=None:
245       if val>valtest:
246         QMessageBox.warning(self, widget.titleForWarning, "float value is over maximum: "+str(val)+" > "+str(valtest))
247         res=str(valtest)
248         widget.setProperty("text", res)
249         return res    
250     return str(val)
251
252   def getResumeData(self, separator="\n"):
253     text=""
254     for RB in self.GBOptim.findChildren(QRadioButton,):
255       if RB.isChecked()==True:
256         text+="Optimisation="+RB.text()+separator
257         break
258     if self.RB_Absolute.isChecked():
259       text+="Units=absolute"+separator
260     else:
261       text+="Units=relative"+separator
262     v=self.SP_toStr(self.SP_Tolerance)
263     text+="ChordalToleranceDeviation="+v+separator
264     text+="RidgeDetection="+str(self.CB_Ridge.isChecked())+separator
265     text+="SplitEdge="+str(self.CB_SplitEdge.isChecked())+separator
266     text+="PointSmoothing="+str(self.CB_Point.isChecked())+separator
267     text+="GeometricalApproximation="+str(self.SP_Geomapp.value())+separator
268     text+="RidgeAngle="+str(self.SP_Ridge.value())+separator
269     text+="MaximumSize="+str(self.SP_MaxSize.value())+separator
270     text+="MinimumSize="+str(self.SP_MinSize.value())+separator
271     text+="MeshGradation="+str(self.SP_Gradation.value())+separator
272     text+="Verbosity="+str(self.SP_Verbosity.value())+separator
273     text+="Memory="+str(self.SP_Memory.value())+separator
274     return str(text)
275
276   def loadResumeData(self, hypothesis, separator="\n"):
277     text=str(hypothesis)
278     self.clean()
279     for slig in reversed(text.split(separator)):
280       lig=slig.strip()
281       #print "load ResumeData",lig
282       if lig=="": continue #skip blanck lines
283       if lig[0]=="#": break
284       try:
285         tit,value=lig.split("=")
286         if tit=="Optimisation":
287           for RB in self.GBUnit.findChildren(QRadioButton,):
288             RB.setChecked(False)
289           for RB in self.GBUnit.findChildren(QRadioButton,):
290             if RB.text()==value :
291               RB.setChecked(True)
292               break
293         if tit=="Units":
294           if value=="absolute":
295             self.RB_Absolute.setChecked(True)
296             self.RB_Relative.setChecked(False)
297           else:
298             self.RB_Absolute.setChecked(False)
299             self.RB_Relative.setChecked(True)
300         if tit=="ChordalToleranceDeviation": self.SP_Tolerance.setProperty("text", float(value))
301         if tit=="RidgeDetection": self.CB_Ridge.setChecked(value=="True")
302         if tit=="SplitEdge": self.CB_SplitEdge.setChecked(value=="True")
303         if tit=="PointSmoothing": self.CB_Point.setChecked(value=="True")
304         if tit=="GeometricalApproximation": self.SP_Geomapp.setProperty("value", float(value))
305         if tit=="RidgeAngle": self.SP_Ridge.setProperty("value", float(value))
306         if tit=="MaximumSize": self.SP_MaxSize.setProperty("value", float(value))
307         if tit=="MinimumSize": self.SP_MinSize.setProperty("value", float(value))
308         if tit=="MeshGradation": self.SP_Gradation.setProperty("value", float(value))
309         if tit=="Verbosity": self.SP_Verbosity.setProperty("value", int(float(value)))
310         if tit=="Memory": self.SP_Memory.setProperty("value", float(value))
311       except:
312         QMessageBox.warning(self, "load YAMS Hypothesis", "Problem on '"+lig+"'")
313
314   def PBLoadPressed(self):
315     """load last hypothesis saved in tail of file"""
316     try:
317       f=open(self.paramsFile,"r")
318     except:
319       QMessageBox.warning(self, "File", "Unable to open "+self.paramsFile)
320       return
321     try:
322       text=f.read()
323     except:
324       QMessageBox.warning(self, "File", "Unable to read "+self.paramsFile)
325       return
326     f.close()
327     self.loadResumeData(text, separator="\n")
328
329   def PBLoadHypPressed(self):
330     """load hypothesis saved in Object Browser"""
331     #QMessageBox.warning(self, "load Object Browser YAMS hypothesis", "TODO")
332     import salome
333     from salome.kernel import studyedit
334     from salome.smesh.smeshstudytools import SMeshStudyTools
335     from salome.gui import helper as guihelper
336     from omniORB import CORBA
337
338     mySObject, myEntry = guihelper.getSObjectSelected()
339     if CORBA.is_nil(mySObject) or mySObject==None:
340       QMessageBox.critical(self, "Hypothese", "select an Object Browser YAMS hypothesis")
341       return
342     
343     text=mySObject.GetComment()
344     
345     #a verification
346     if "Optimisation=" not in text:
347       QMessageBox.critical(self, "Load Hypothese", "Object Browser selection not a YAMS Hypothesis")
348       return
349     self.loadResumeData(text, separator=" ; ")
350     return
351     
352   def PBCancelPressed(self):
353     self.close()
354
355   def PBMeshFilePressed(self):
356     fd = QFileDialog(self, "select an existing Mesh file", self.LE_MeshFile.text(), "Mesh-Files (*.mesh);;All Files (*)")
357     if fd.exec_():
358       infile = fd.selectedFiles()[0]
359       self.LE_MeshFile.setText(infile)
360       self.fichierIn=infile.toLatin1()
361       self.MeshIn=""
362       self.LE_MeshSmesh.setText("")
363
364   def setParamsFileName(self):
365     fd = QFileDialog(self, "select a file", self.LE_ParamsFile.text(), "dat Files (*.dat);;All Files (*)")
366     if fd.exec_():
367       infile = fd.selectedFiles()[0]
368       self.LE_ParamsFile.setText(infile)
369       self.paramsFile=infile.toLatin1()
370
371   def meshFileNameChanged(self):
372     self.fichierIn=str(self.LE_MeshFile.text())
373     #print "meshFileNameChanged", self.fichierIn
374     if os.path.exists(self.fichierIn): 
375       self.__selectedMesh=None
376       self.MeshIn=""
377       self.LE_MeshSmesh.setText("")
378       return
379     QMessageBox.warning(self, "Mesh file", "File doesn't exist")
380
381   def meshSmeshNameChanged(self):
382     """only change by GUI mouse selection, otherwise clear"""
383     self.__selectedMesh = None
384     self.MeshIn=""
385     self.LE_MeshSmesh.setText("")
386     self.fichierIn=""
387     return
388
389   def paramsFileNameChanged(self):
390     self.paramsFile=self.LE_ParamsFile.text()
391
392   def PBMeshSmeshPressed(self):
393     import salome
394     import smesh
395     from salome.kernel import studyedit
396     from salome.smesh.smeshstudytools import SMeshStudyTools
397     from salome.gui import helper as guihelper
398     from omniORB import CORBA
399
400     mySObject, myEntry = guihelper.getSObjectSelected()
401     if CORBA.is_nil(mySObject) or mySObject==None:
402       QMessageBox.critical(self, "Mesh", "select an input mesh")
403       return
404     self.smeshStudyTool = SMeshStudyTools()
405     try:
406       self.__selectedMesh = self.smeshStudyTool.getMeshObjectFromSObject(mySObject)
407     except:
408       QMessageBox.critical(self, "Mesh", "select an input mesh")
409       return
410     if CORBA.is_nil(self.__selectedMesh):
411       QMessageBox.critical(self, "Mesh", "select an input mesh")
412       return
413     myName = mySObject.GetName()
414     #print "MeshSmeshNameChanged", myName
415     self.MeshIn=myName
416     self.LE_MeshSmesh.setText(myName)
417     self.LE_MeshFile.setText("")
418     self.fichierIn=""
419
420   def prepareFichier(self):
421     self.fichierIn="/tmp/ForYams_"+str(self.num)+".mesh"
422     import SMESH
423     self.__selectedMesh.ExportGMF(self.__selectedMesh, self.fichierIn, True)
424
425   def PrepareLigneCommande(self):
426     if self.fichierIn=="" and self.MeshIn=="":
427       QMessageBox.critical(self, "Mesh", "select an input mesh")
428       return False
429     if self.__selectedMesh!=None: self.prepareFichier()
430     if not (os.path.isfile(self.fichierIn)):
431       QMessageBox.critical(self, "File", "unable to read GMF Mesh in "+str(self.fichierIn))
432       return False
433     
434     self.commande="yams"
435     verbosity=str(self.SP_Verbosity.value())
436     self.commande+=" -v "+verbosity
437     for obj in self.GBOptim.findChildren(QRadioButton,):
438       try:
439         if obj.isChecked():
440           self.style=obj.objectName().remove(0,3)
441           self.style.replace("_","-")
442           break
443       except:
444         pass
445     self.commande+=" -O "+self.style.toLatin1()
446
447     deb=os.path.splitext(self.fichierIn)
448     self.fichierOut=deb[0] + ".d.meshb"
449
450     if self.RB_Absolute.isChecked()==True :
451         self.commande+=" -Dabsolute"
452     else :
453         self.commande+=" -Drelative"
454     
455     v=self.SP_toStr(self.SP_Tolerance)
456     self.commande+=",tolerance="+v
457     if self.CB_Ridge.isChecked()==False : self.commande+=",-nr"
458     if self.CB_Point.isChecked()==False : self.commande+=",-ns"
459     if self.SP_Geomapp.value()!=0.04 : self.commande+=",geomapp=%f"%self.SP_Geomapp.value()
460     if self.SP_Ridge.value()!=45.0 : self.commande+=",ridge=%f"%self.SP_Ridge.value()
461     if self.SP_MaxSize.value()!=100 : self.commande+=",maxsize=%f"%self.SP_MaxSize.value()
462     if self.SP_MinSize.value()!=5 : self.commande+=",minsize=%f"%self.SP_MinSize.value()
463     if self.SP_Gradation.value()!=1.3 : self.commande+=",gradation=%f"%self.SP_MaxSize.value()
464     if self.CB_SplitEdge.isChecked()==True : self.commande+=",splitedge=1"
465
466     if self.SP_Verbosity.value()!=3 : self.commande+=" -v %d"%self.SP_Verbosity.value()
467     if self.SP_Memory.value()!=0 : self.commande+=" -m %d"%self.SP_Memory.value()
468
469     self.commande+=" "+self.fichierIn
470     return True
471
472   def clean(self):
473     self.RB_0.setChecked(True)
474     self.RB_G.setChecked(False)
475     self.RB_U.setChecked(False)
476     self.RB_S.setChecked(False)
477     self.RB_2.setChecked(False)
478     self.RB_1.setChecked(False)
479     self.RB_Absolute.setChecked(False)
480     self.RB_Relative.setChecked(True)
481     self.SP_Tolerance.setProperty("text", "10.")
482     self.SP_Geomapp.setProperty("value", 0.04)
483     self.SP_Ridge.setProperty("value", 45.0)
484     self.SP_Gradation.setProperty("value", 1.3)
485     self.CB_Ridge.setChecked(True)
486     self.CB_Point.setChecked(True)
487     self.CB_SplitEdge.setChecked(False)
488     self.SP_MaxSize.setProperty("value", -2.0)
489     self.SP_MinSize.setProperty("value", -2.0)
490     self.SP_Verbosity.setProperty("value", 3)
491     self.SP_Memory.setProperty("value", 0)
492
493 __dialog=None
494 def getDialog():
495     """
496     This function returns a singleton instance of the plugin dialog.
497     c est obligatoire pour faire un show sans parent...
498     """
499     global __dialog
500     if __dialog is None:
501         __dialog = MonYamsPlugDialog()
502     #else :
503     #   __dialog.clean()
504     return __dialog
505
506 #
507 # ==============================================================================
508 # Basic use cases and unit test functions
509 # ==============================================================================
510 #
511 def TEST_MonYamsPlugDialog():
512   #print "TEST_YamsMonPlugDialog"
513   import sys
514   from PyQt4.QtGui import QApplication
515   from PyQt4.QtCore import QObject, SIGNAL, SLOT
516   app = QApplication(sys.argv)
517   QObject.connect(app, SIGNAL("lastWindowClosed()"), app, SLOT("quit()"))
518
519   dlg=MonYamsPlugDialog()
520   dlg.show()
521   sys.exit(app.exec_())
522
523 if __name__ == "__main__":
524   TEST_MonYamsPlugDialog()
525   pass