1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2007-2014 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, or (at your option) any later version.
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 YamsPlugDialog_ui import Ui_YamsPlugDialog
26 from monViewText import MonViewText
27 from PyQt4.QtGui import *
28 from PyQt4.QtCore import *
31 class MonYamsPlugDialog(Ui_YamsPlugDialog,QWidget):
35 QWidget.__init__(self)
37 self.connecterSignaux()
43 self.__selectedMesh=None
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__))
50 self.iconfolder=os.environ["SMESH_ROOT_DIR"]+"/share/salome/resources/smesh"
51 #print "monYamsPlugDialog iconfolder",iconfolder
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")
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")
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("")
76 v1=QDoubleValidator(self)
78 #v1.setTop(1000.) #per thousand... only if relative
80 self.SP_Tolerance.setValidator(v1)
81 self.SP_Tolerance.titleForWarning="Chordal Tolerance"
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)
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)
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)
104 def PBHelpPressed(self):
106 sgPyQt = SalomePyQt.SalomePyQt()
108 mydir=os.environ["SMESH_ROOT_DIR"]
110 QMessageBox.warning(self, "Help", "Help unavailable $SMESH_ROOT_DIR not found")
113 maDoc=mydir+"/share/doc/salome/gui/SMESH/yams/index.html"
114 sgPyQt.helpContext(maDoc,"")
116 #maDoc=mydir+"/share/doc/salome/gui/SMESH/yams/_downloads/mg-surfopt_user_manual.pdf"
117 #command="xdg-open "+maDoc+";"
118 #subprocess.call(command, shell=True)
120 def PBOKPressed(self):
121 if not(self.PrepareLigneCommande()):
123 #QMessageBox.warning(self, "Compute", "Command not found")
125 maFenetre=MonViewText(self,self.commande)
127 def enregistreResultat(self):
130 from salome.kernel import studyedit
131 from salome.smesh import smeshBuilder
132 smesh = smeshBuilder.New(salome.myStudy)
134 if not os.path.isfile(self.fichierOut):
135 QMessageBox.warning(self, "Compute", "Result file "+self.fichierOut+" not found")
137 maStudy=studyedit.getActiveStudy()
138 smesh.SetCurrentStudy(maStudy)
139 (outputMesh, status) = smesh.CreateMeshesFromGMF(self.fichierOut)
140 name=str(self.LE_MeshSmesh.text())
142 initialMeshObject=None
144 a=str(self.fichierIn)
145 name=os.path.basename(os.path.splitext(a)[0])
148 initialMeshObject=maStudy.FindObjectByName(name ,"SMESH")[0]
150 meshname = name+"_YAMS_"+str(self.num)
151 smesh.SetName(outputMesh.GetMesh(), meshname)
152 outputMesh.Compute() #no algorithms message for "Mesh_x" has been computed with warnings: - global 1D algorithm is missing
154 self.editor = studyedit.getStudyEditor()
155 moduleEntry=self.editor.findOrCreateComponent("SMESH","SMESH")
156 HypReMeshEntry = self.editor.findOrCreateItem(
157 moduleEntry, name = "Plugins Hypotheses", icon="mesh_tree_hypo.png") #, comment = "HypoForRemeshing" )
159 monStudyBuilder=maStudy.NewBuilder()
160 monStudyBuilder.NewCommand()
161 newStudyIter=monStudyBuilder.NewObject(HypReMeshEntry)
162 self.editor.setAttributeValue(newStudyIter, "AttributeName", "YAMS Parameters_"+str(self.num))
163 self.editor.setAttributeValue(newStudyIter, "AttributeComment", self.getResumeData(separator=" ; "))
165 SOMesh=maStudy.FindObjectByName(meshname ,"SMESH")[0]
167 if initialMeshFile!=None:
168 newStudyFileName=monStudyBuilder.NewObject(SOMesh)
169 self.editor.setAttributeValue(newStudyFileName, "AttributeName", "meshFile")
170 self.editor.setAttributeValue(newStudyFileName, "AttributeExternalFileDef", initialMeshFile)
171 self.editor.setAttributeValue(newStudyFileName, "AttributeComment", initialMeshFile)
173 if initialMeshObject!=None:
174 newLink=monStudyBuilder.NewObject(SOMesh)
175 monStudyBuilder.Addreference(newLink, initialMeshObject)
177 newLink=monStudyBuilder.NewObject(SOMesh)
178 monStudyBuilder.Addreference(newLink, newStudyIter)
180 if salome.sg.hasDesktop(): salome.sg.updateObjBrowser(0)
184 def PBSavePressed(self):
185 from datetime import datetime
186 if not(self.PrepareLigneCommande()): return
187 text = "# YAMS hypothesis parameters\n"
188 text += "# Params for mesh : " + self.LE_MeshSmesh.text() +"\n"
189 text += datetime.now().strftime("# Date : %d/%m/%y %H:%M:%S\n")
190 text += "# Command : "+self.commande+"\n"
191 text += self.getResumeData(separator="\n")
195 f=open(self.paramsFile,"a")
197 QMessageBox.warning(self, "File", "Unable to open "+self.paramsFile)
202 QMessageBox.warning(self, "File", "Unable to write "+self.paramsFile)
206 def PBSaveHypPressed(self):
207 """save hypothesis in Object Browser"""
210 from salome.kernel import studyedit
211 from salome.smesh import smeshBuilder
212 smesh = smeshBuilder.New(salome.myStudy)
214 maStudy=studyedit.getActiveStudy()
215 smesh.SetCurrentStudy(maStudy)
217 self.editor = studyedit.getStudyEditor()
218 moduleEntry=self.editor.findOrCreateComponent("SMESH","SMESH")
219 HypReMeshEntry = self.editor.findOrCreateItem(
220 moduleEntry, name = "Plugins Hypotheses", icon="mesh_tree_hypo.png") #, comment = "HypoForRemeshing" )
222 monStudyBuilder=maStudy.NewBuilder()
223 monStudyBuilder.NewCommand()
224 newStudyIter=monStudyBuilder.NewObject(HypReMeshEntry)
225 self.editor.setAttributeValue(newStudyIter, "AttributeName", "YAMS Parameters_"+str(self.num))
226 self.editor.setAttributeValue(newStudyIter, "AttributeComment", self.getResumeData(separator=" ; "))
228 if salome.sg.hasDesktop(): salome.sg.updateObjBrowser(0)
232 def SP_toStr(self, widget):
233 """only for a QLineEdit widget"""
234 #cr, pos=widget.validator().validate(res, 0) #n.b. "1,3" is acceptable !locale!
236 val=float(widget.text())
238 QMessageBox.warning(self, widget.titleForWarning, "float value is incorrect: '"+widget.text()+"'")
239 res=str(widget.validator().bottom())
240 widget.setProperty("text", res)
242 valtest=widget.validator().bottom()
245 QMessageBox.warning(self, widget.titleForWarning, "float value is under minimum: "+str(val)+" < "+str(valtest))
247 widget.setProperty("text", res)
249 valtest=widget.validator().top()
252 QMessageBox.warning(self, widget.titleForWarning, "float value is over maximum: "+str(val)+" > "+str(valtest))
254 widget.setProperty("text", res)
258 def getResumeData(self, separator="\n"):
260 for RB in self.GBOptim.findChildren(QRadioButton,):
261 if RB.isChecked()==True:
262 text+="Optimisation="+RB.text()+separator
264 if self.RB_Absolute.isChecked():
265 text+="Units=absolute"+separator
267 text+="Units=relative"+separator
268 v=self.SP_toStr(self.SP_Tolerance)
269 text+="ChordalToleranceDeviation="+v+separator
270 text+="RidgeDetection="+str(self.CB_Ridge.isChecked())+separator
271 text+="SplitEdge="+str(self.CB_SplitEdge.isChecked())+separator
272 text+="PointSmoothing="+str(self.CB_Point.isChecked())+separator
273 text+="GeometricalApproximation="+str(self.SP_Geomapp.value())+separator
274 text+="RidgeAngle="+str(self.SP_Ridge.value())+separator
275 text+="MaximumSize="+str(self.SP_MaxSize.value())+separator
276 text+="MinimumSize="+str(self.SP_MinSize.value())+separator
277 text+="MeshGradation="+str(self.SP_Gradation.value())+separator
278 text+="Verbosity="+str(self.SP_Verbosity.value())+separator
279 text+="Memory="+str(self.SP_Memory.value())+separator
282 def loadResumeData(self, hypothesis, separator="\n"):
285 for slig in reversed(text.split(separator)):
287 #print "load ResumeData",lig
288 if lig=="": continue #skip blanck lines
289 if lig[0]=="#": break
291 tit,value=lig.split("=")
292 if tit=="Optimisation":
293 #no need: exlusives QRadioButton
294 #for RB in self.GBOptim.findChildren(QRadioButton,):
295 # RB.setChecked(False)
296 for RB in self.GBOptim.findChildren(QRadioButton,):
297 if RB.text()==value :
301 if value=="absolute":
302 self.RB_Absolute.setChecked(True)
303 self.RB_Relative.setChecked(False)
305 self.RB_Absolute.setChecked(False)
306 self.RB_Relative.setChecked(True)
307 if tit=="ChordalToleranceDeviation": self.SP_Tolerance.setProperty("text", float(value))
308 if tit=="RidgeDetection": self.CB_Ridge.setChecked(value=="True")
309 if tit=="SplitEdge": self.CB_SplitEdge.setChecked(value=="True")
310 if tit=="PointSmoothing": self.CB_Point.setChecked(value=="True")
311 if tit=="GeometricalApproximation": self.SP_Geomapp.setProperty("value", float(value))
312 if tit=="RidgeAngle": self.SP_Ridge.setProperty("value", float(value))
313 if tit=="MaximumSize": self.SP_MaxSize.setProperty("value", float(value))
314 if tit=="MinimumSize": self.SP_MinSize.setProperty("value", float(value))
315 if tit=="MeshGradation": self.SP_Gradation.setProperty("value", float(value))
316 if tit=="Verbosity": self.SP_Verbosity.setProperty("value", int(float(value)))
317 if tit=="Memory": self.SP_Memory.setProperty("value", float(value))
319 QMessageBox.warning(self, "load YAMS Hypothesis", "Problem on '"+lig+"'")
321 def PBLoadPressed(self):
322 """load last hypothesis saved in tail of file"""
324 f=open(self.paramsFile,"r")
326 QMessageBox.warning(self, "File", "Unable to open "+self.paramsFile)
331 QMessageBox.warning(self, "File", "Unable to read "+self.paramsFile)
334 self.loadResumeData(text, separator="\n")
336 def PBLoadHypPressed(self):
337 """load hypothesis saved in Object Browser"""
338 #QMessageBox.warning(self, "load Object Browser YAMS hypothesis", "TODO")
340 from salome.kernel import studyedit
341 from salome.smesh.smeshstudytools import SMeshStudyTools
342 from salome.gui import helper as guihelper
343 from omniORB import CORBA
345 mySObject, myEntry = guihelper.getSObjectSelected()
346 if CORBA.is_nil(mySObject) or mySObject==None:
347 QMessageBox.critical(self, "Hypothese", "select an Object Browser YAMS hypothesis")
350 text=mySObject.GetComment()
353 if "Optimisation=" not in text:
354 QMessageBox.critical(self, "Load Hypothese", "Object Browser selection not a YAMS Hypothesis")
356 self.loadResumeData(text, separator=" ; ")
359 def PBCancelPressed(self):
362 def PBMeshFilePressed(self):
363 fd = QFileDialog(self, "select an existing Mesh file", self.LE_MeshFile.text(), "Mesh-Files (*.mesh);;All Files (*)")
365 infile = fd.selectedFiles()[0]
366 self.LE_MeshFile.setText(infile)
367 self.fichierIn=infile.toLatin1()
369 self.LE_MeshSmesh.setText("")
371 def setParamsFileName(self):
372 fd = QFileDialog(self, "select a file", self.LE_ParamsFile.text(), "dat Files (*.dat);;All Files (*)")
374 infile = fd.selectedFiles()[0]
375 self.LE_ParamsFile.setText(infile)
376 self.paramsFile=infile.toLatin1()
378 def meshFileNameChanged(self):
379 self.fichierIn=str(self.LE_MeshFile.text())
380 #print "meshFileNameChanged", self.fichierIn
381 if os.path.exists(self.fichierIn):
382 self.__selectedMesh=None
384 self.LE_MeshSmesh.setText("")
386 QMessageBox.warning(self, "Mesh file", "File doesn't exist")
388 def meshSmeshNameChanged(self):
389 """only change by GUI mouse selection, otherwise clear"""
390 self.__selectedMesh = None
392 self.LE_MeshSmesh.setText("")
396 def paramsFileNameChanged(self):
397 self.paramsFile=self.LE_ParamsFile.text()
399 def PBMeshSmeshPressed(self):
400 from omniORB import CORBA
402 from salome.kernel import studyedit
403 from salome.smesh.smeshstudytools import SMeshStudyTools
404 from salome.gui import helper as guihelper
405 from salome.smesh import smeshBuilder
406 smesh = smeshBuilder.New(salome.myStudy)
408 mySObject, myEntry = guihelper.getSObjectSelected()
409 if CORBA.is_nil(mySObject) or mySObject==None:
410 #QMessageBox.critical(self, "Mesh", "select an input mesh")
411 self.LE_MeshSmesh.setText("")
413 self.LE_MeshFile.setText("")
416 self.smeshStudyTool = SMeshStudyTools()
418 self.__selectedMesh = self.smeshStudyTool.getMeshObjectFromSObject(mySObject)
420 QMessageBox.critical(self, "Mesh", "select an input mesh")
422 if CORBA.is_nil(self.__selectedMesh):
423 QMessageBox.critical(self, "Mesh", "select an input mesh")
425 myName = mySObject.GetName()
426 #print "MeshSmeshNameChanged", myName
428 self.LE_MeshSmesh.setText(myName)
429 self.LE_MeshFile.setText("")
432 def prepareFichier(self):
433 self.fichierIn="/tmp/ForSurfOpt_"+str(self.num)+".meshb"
434 self.__selectedMesh.ExportGMF(self.__selectedMesh, self.fichierIn, True)
436 def PrepareLigneCommande(self):
437 if self.fichierIn=="" and self.MeshIn=="":
438 QMessageBox.critical(self, "Mesh", "select an input mesh")
440 if self.__selectedMesh!=None: self.prepareFichier()
441 if not (os.path.isfile(self.fichierIn)):
442 QMessageBox.critical(self, "File", "unable to read GMF Mesh in "+str(self.fichierIn))
445 self.commande="mg-surfopt.exe"
447 for obj in self.GBOptim.findChildren(QRadioButton,):
450 self.style=obj.objectName().remove(0,3)
451 self.style.replace("_","-")
456 style = self.style.toLatin1()
457 # Translation of old Yams options to new MG-SurfOpt options
459 self.commande+= " --optimisation only"
461 self.commande+= " --Hausdorff_like yes"
463 self.commande+= " --enrich no"
465 self.commande+= " --Hausdorff_like yes --enrich no"
467 self.commande+= " --uniform_flat_subdivision yes"
469 self.commande+= " --sand_paper yes"
471 self.commande+= " -O G" # This option has not been updated to the new option style yet
473 deb=os.path.splitext(self.fichierIn)
474 self.fichierOut=deb[0] + "_output.meshb"
476 tolerance=self.SP_toStr(self.SP_Tolerance)
477 if not self.RB_Absolute.isChecked():
479 self.commande+=" --chordal_error %s"%tolerance
481 if self.CB_Ridge.isChecked() == False : self.commande+=" --compute_ridges no"
482 if self.CB_Point.isChecked() == False : self.commande+=" --optimisation no"
483 if self.CB_SplitEdge.isChecked()== True : self.commande+=" --element_order quadratic"
484 if self.SP_Geomapp.value() != 15.0 : self.commande+=" --geometric_approximation_angle %f"%self.SP_Geomapp.value()
485 if self.SP_Ridge.value() != 45.0 : self.commande+=" --ridge_angle %f"%self.SP_Ridge.value()
486 if self.SP_MaxSize.value() != 100 : self.commande+=" --max_size %f" %self.SP_MaxSize.value()
487 if self.SP_MinSize.value() != 5 : self.commande+=" --min_size %f" %self.SP_MinSize.value()
488 if self.SP_Gradation.value() != 1.3 : self.commande+=" --gradation %f" %self.SP_MaxSize.value()
489 if self.SP_Memory.value() != 0 : self.commande+=" --max_memory %d" %self.SP_Memory.value()
490 if self.SP_Verbosity.value() != 3 : self.commande+=" --verbose %d" %self.SP_Verbosity.value()
492 self.commande+=" --in " + self.fichierIn
493 self.commande+=" --out " + self.fichierOut
499 self.RB_0.setChecked(True)
500 #no need: exlusives QRadioButton
501 #self.RB_G.setChecked(False)
502 #self.RB_U.setChecked(False)
503 #self.RB_S.setChecked(False)
504 #self.RB_2.setChecked(False)
505 #self.RB_1.setChecked(False)
506 self.RB_Relative.setChecked(True)
507 #no need: exlusives QRadioButton
508 #self.RB_Absolute.setChecked(False)
509 self.SP_Tolerance.setProperty("text", "0.001")
510 self.SP_Geomapp.setProperty("value", 15.0)
511 self.SP_Ridge.setProperty("value", 45.0)
512 self.SP_Gradation.setProperty("value", 1.3)
513 self.CB_Ridge.setChecked(True)
514 self.CB_Point.setChecked(True)
515 self.CB_SplitEdge.setChecked(False)
516 self.SP_MaxSize.setProperty("value", 100)
517 self.SP_MinSize.setProperty("value", 5)
518 self.SP_Verbosity.setProperty("value", 3)
519 self.SP_Memory.setProperty("value", 0)
520 self.PBMeshSmeshPressed()
521 self.TWOptions.setCurrentIndex(0) # Reset current active tab to the first tab
526 This function returns a singleton instance of the plugin dialog.
527 It is mandatory in order to call show without a parent ...
531 __dialog = MonYamsPlugDialog()
537 # ==============================================================================
538 # Basic use cases and unit test functions
539 # ==============================================================================
541 def TEST_MonYamsPlugDialog():
543 from PyQt4.QtGui import QApplication
544 from PyQt4.QtCore import QObject, SIGNAL, SLOT
545 app = QApplication(sys.argv)
546 QObject.connect(app, SIGNAL("lastWindowClosed()"), app, SLOT("quit()"))
548 dlg=MonYamsPlugDialog()
550 sys.exit(app.exec_())
552 if __name__ == "__main__":
553 TEST_MonYamsPlugDialog()