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 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 mydir=os.environ["SMESH_ROOT_DIR"]
108 QMessageBox.warning(self, "Help", "Help unavailable $SMESH_ROOT_DIR not found")
110 maDoc=mydir+"/share/doc/salome/gui/SMESH/yams/_downloads/mg-surfopt_user_manual.pdf"
111 command="xdg-open "+maDoc+";"
112 subprocess.call(command, shell=True)
114 def PBOKPressed(self):
115 if not(self.PrepareLigneCommande()):
117 #QMessageBox.warning(self, "Compute", "Command not found")
119 maFenetre=MonViewText(self,self.commande)
121 def enregistreResultat(self):
124 from salome.kernel import studyedit
125 from salome.smesh import smeshBuilder
126 smesh = smeshBuilder.New(salome.myStudy)
128 if not os.path.isfile(self.fichierOut):
129 QMessageBox.warning(self, "Compute", "Result file "+self.fichierOut+" not found")
131 maStudy=studyedit.getActiveStudy()
132 smesh.SetCurrentStudy(maStudy)
133 (outputMesh, status) = smesh.CreateMeshesFromGMF(self.fichierOut)
134 name=str(self.LE_MeshSmesh.text())
136 initialMeshObject=None
138 a=str(self.fichierIn)
139 name=os.path.basename(os.path.splitext(a)[0])
142 initialMeshObject=maStudy.FindObjectByName(name ,"SMESH")[0]
144 meshname = name+"_YAMS_"+str(self.num)
145 smesh.SetName(outputMesh.GetMesh(), meshname)
146 outputMesh.Compute() #no algorithms message for "Mesh_x" has been computed with warnings: - global 1D algorithm is missing
148 self.editor = studyedit.getStudyEditor()
149 moduleEntry=self.editor.findOrCreateComponent("SMESH","SMESH")
150 HypReMeshEntry = self.editor.findOrCreateItem(
151 moduleEntry, name = "Plugins Hypotheses", icon="mesh_tree_hypo.png") #, comment = "HypoForRemeshing" )
153 monStudyBuilder=maStudy.NewBuilder()
154 monStudyBuilder.NewCommand()
155 newStudyIter=monStudyBuilder.NewObject(HypReMeshEntry)
156 self.editor.setAttributeValue(newStudyIter, "AttributeName", "YAMS Parameters_"+str(self.num))
157 self.editor.setAttributeValue(newStudyIter, "AttributeComment", self.getResumeData(separator=" ; "))
159 SOMesh=maStudy.FindObjectByName(meshname ,"SMESH")[0]
161 if initialMeshFile!=None:
162 newStudyFileName=monStudyBuilder.NewObject(SOMesh)
163 self.editor.setAttributeValue(newStudyFileName, "AttributeName", "meshFile")
164 self.editor.setAttributeValue(newStudyFileName, "AttributeExternalFileDef", initialMeshFile)
165 self.editor.setAttributeValue(newStudyFileName, "AttributeComment", initialMeshFile)
167 if initialMeshObject!=None:
168 newLink=monStudyBuilder.NewObject(SOMesh)
169 monStudyBuilder.Addreference(newLink, initialMeshObject)
171 newLink=monStudyBuilder.NewObject(SOMesh)
172 monStudyBuilder.Addreference(newLink, newStudyIter)
174 if salome.sg.hasDesktop(): salome.sg.updateObjBrowser(0)
178 def PBSavePressed(self):
179 from datetime import datetime
180 if not(self.PrepareLigneCommande()): return
181 text = "# YAMS hypothesis parameters\n"
182 text += "# Params for mesh : " + self.LE_MeshSmesh.text() +"\n"
183 text += datetime.now().strftime("# Date : %d/%m/%y %H:%M:%S\n")
184 text += "# Command : "+self.commande+"\n"
185 text += self.getResumeData(separator="\n")
189 f=open(self.paramsFile,"a")
191 QMessageBox.warning(self, "File", "Unable to open "+self.paramsFile)
196 QMessageBox.warning(self, "File", "Unable to write "+self.paramsFile)
200 def PBSaveHypPressed(self):
201 """save hypothesis in Object Browser"""
204 from salome.kernel import studyedit
205 from salome.smesh import smeshBuilder
206 smesh = smeshBuilder.New(salome.myStudy)
208 maStudy=studyedit.getActiveStudy()
209 smesh.SetCurrentStudy(maStudy)
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" )
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=" ; "))
222 if salome.sg.hasDesktop(): salome.sg.updateObjBrowser(0)
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!
230 val=float(widget.text())
232 QMessageBox.warning(self, widget.titleForWarning, "float value is incorrect: '"+widget.text()+"'")
233 res=str(widget.validator().bottom())
234 widget.setProperty("text", res)
236 valtest=widget.validator().bottom()
239 QMessageBox.warning(self, widget.titleForWarning, "float value is under minimum: "+str(val)+" < "+str(valtest))
241 widget.setProperty("text", res)
243 valtest=widget.validator().top()
246 QMessageBox.warning(self, widget.titleForWarning, "float value is over maximum: "+str(val)+" > "+str(valtest))
248 widget.setProperty("text", res)
252 def getResumeData(self, separator="\n"):
254 for RB in self.GBOptim.findChildren(QRadioButton,):
255 if RB.isChecked()==True:
256 text+="Optimisation="+RB.text()+separator
258 if self.RB_Absolute.isChecked():
259 text+="Units=absolute"+separator
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
276 def loadResumeData(self, hypothesis, separator="\n"):
279 for slig in reversed(text.split(separator)):
281 #print "load ResumeData",lig
282 if lig=="": continue #skip blanck lines
283 if lig[0]=="#": break
285 tit,value=lig.split("=")
286 if tit=="Optimisation":
287 #no need: exlusives QRadioButton
288 #for RB in self.GBOptim.findChildren(QRadioButton,):
289 # RB.setChecked(False)
290 for RB in self.GBOptim.findChildren(QRadioButton,):
291 if RB.text()==value :
295 if value=="absolute":
296 self.RB_Absolute.setChecked(True)
297 self.RB_Relative.setChecked(False)
299 self.RB_Absolute.setChecked(False)
300 self.RB_Relative.setChecked(True)
301 if tit=="ChordalToleranceDeviation": self.SP_Tolerance.setProperty("text", float(value))
302 if tit=="RidgeDetection": self.CB_Ridge.setChecked(value=="True")
303 if tit=="SplitEdge": self.CB_SplitEdge.setChecked(value=="True")
304 if tit=="PointSmoothing": self.CB_Point.setChecked(value=="True")
305 if tit=="GeometricalApproximation": self.SP_Geomapp.setProperty("value", float(value))
306 if tit=="RidgeAngle": self.SP_Ridge.setProperty("value", float(value))
307 if tit=="MaximumSize": self.SP_MaxSize.setProperty("value", float(value))
308 if tit=="MinimumSize": self.SP_MinSize.setProperty("value", float(value))
309 if tit=="MeshGradation": self.SP_Gradation.setProperty("value", float(value))
310 if tit=="Verbosity": self.SP_Verbosity.setProperty("value", int(float(value)))
311 if tit=="Memory": self.SP_Memory.setProperty("value", float(value))
313 QMessageBox.warning(self, "load YAMS Hypothesis", "Problem on '"+lig+"'")
315 def PBLoadPressed(self):
316 """load last hypothesis saved in tail of file"""
318 f=open(self.paramsFile,"r")
320 QMessageBox.warning(self, "File", "Unable to open "+self.paramsFile)
325 QMessageBox.warning(self, "File", "Unable to read "+self.paramsFile)
328 self.loadResumeData(text, separator="\n")
330 def PBLoadHypPressed(self):
331 """load hypothesis saved in Object Browser"""
332 #QMessageBox.warning(self, "load Object Browser YAMS hypothesis", "TODO")
334 from salome.kernel import studyedit
335 from salome.smesh.smeshstudytools import SMeshStudyTools
336 from salome.gui import helper as guihelper
337 from omniORB import CORBA
339 mySObject, myEntry = guihelper.getSObjectSelected()
340 if CORBA.is_nil(mySObject) or mySObject==None:
341 QMessageBox.critical(self, "Hypothese", "select an Object Browser YAMS hypothesis")
344 text=mySObject.GetComment()
347 if "Optimisation=" not in text:
348 QMessageBox.critical(self, "Load Hypothese", "Object Browser selection not a YAMS Hypothesis")
350 self.loadResumeData(text, separator=" ; ")
353 def PBCancelPressed(self):
356 def PBMeshFilePressed(self):
357 fd = QFileDialog(self, "select an existing Mesh file", self.LE_MeshFile.text(), "Mesh-Files (*.mesh);;All Files (*)")
359 infile = fd.selectedFiles()[0]
360 self.LE_MeshFile.setText(infile)
361 self.fichierIn=infile.toLatin1()
363 self.LE_MeshSmesh.setText("")
365 def setParamsFileName(self):
366 fd = QFileDialog(self, "select a file", self.LE_ParamsFile.text(), "dat Files (*.dat);;All Files (*)")
368 infile = fd.selectedFiles()[0]
369 self.LE_ParamsFile.setText(infile)
370 self.paramsFile=infile.toLatin1()
372 def meshFileNameChanged(self):
373 self.fichierIn=str(self.LE_MeshFile.text())
374 #print "meshFileNameChanged", self.fichierIn
375 if os.path.exists(self.fichierIn):
376 self.__selectedMesh=None
378 self.LE_MeshSmesh.setText("")
380 QMessageBox.warning(self, "Mesh file", "File doesn't exist")
382 def meshSmeshNameChanged(self):
383 """only change by GUI mouse selection, otherwise clear"""
384 self.__selectedMesh = None
386 self.LE_MeshSmesh.setText("")
390 def paramsFileNameChanged(self):
391 self.paramsFile=self.LE_ParamsFile.text()
393 def PBMeshSmeshPressed(self):
394 from omniORB import CORBA
396 from salome.kernel import studyedit
397 from salome.smesh.smeshstudytools import SMeshStudyTools
398 from salome.gui import helper as guihelper
399 from salome.smesh import smeshBuilder
400 smesh = smeshBuilder.New(salome.myStudy)
402 mySObject, myEntry = guihelper.getSObjectSelected()
403 if CORBA.is_nil(mySObject) or mySObject==None:
404 QMessageBox.critical(self, "Mesh", "select an input mesh")
406 self.smeshStudyTool = SMeshStudyTools()
408 self.__selectedMesh = self.smeshStudyTool.getMeshObjectFromSObject(mySObject)
410 QMessageBox.critical(self, "Mesh", "select an input mesh")
412 if CORBA.is_nil(self.__selectedMesh):
413 QMessageBox.critical(self, "Mesh", "select an input mesh")
415 myName = mySObject.GetName()
416 #print "MeshSmeshNameChanged", myName
418 self.LE_MeshSmesh.setText(myName)
419 self.LE_MeshFile.setText("")
422 def prepareFichier(self):
423 self.fichierIn="/tmp/ForSurfOpt_"+str(self.num)+".meshb"
424 self.__selectedMesh.ExportGMF(self.__selectedMesh, self.fichierIn, True)
426 def PrepareLigneCommande(self):
427 if self.fichierIn=="" and self.MeshIn=="":
428 QMessageBox.critical(self, "Mesh", "select an input mesh")
430 if self.__selectedMesh!=None: self.prepareFichier()
431 if not (os.path.isfile(self.fichierIn)):
432 QMessageBox.critical(self, "File", "unable to read GMF Mesh in "+str(self.fichierIn))
435 self.commande="mg-surfopt.exe"
437 for obj in self.GBOptim.findChildren(QRadioButton,):
440 self.style=obj.objectName().remove(0,3)
441 self.style.replace("_","-")
446 style = self.style.toLatin1()
447 # Translation of old Yams options to new MG-SurfOpt options
449 self.commande+= " --optimisation only"
451 self.commande+= " --Hausdorff_like yes"
453 self.commande+= " --enrich no"
455 self.commande+= " --Hausdorff_like yes --enrich no"
457 self.commande+= " --uniform_flat_subdivision yes"
459 self.commande+= " --sand_paper yes"
461 self.commande+= " -O G" # This option has not been updated to the new option style yet
463 deb=os.path.splitext(self.fichierIn)
464 self.fichierOut=deb[0] + "_output.meshb"
466 tolerance=self.SP_toStr(self.SP_Tolerance)
467 if not self.RB_Absolute.isChecked():
469 self.commande+=" --chordal_error %s"%tolerance
471 if self.CB_Ridge.isChecked() == False : self.commande+=" --compute_ridges no"
472 if self.CB_Point.isChecked() == False : self.commande+=" --optimisation no"
473 if self.CB_SplitEdge.isChecked()== True : self.commande+=" --element_order quadratic"
474 if self.SP_Geomapp.value() != 15.0 : self.commande+=" --geometric_approximation_angle %f"%self.SP_Geomapp.value()
475 if self.SP_Ridge.value() != 45.0 : self.commande+=" --ridge_angle %f"%self.SP_Ridge.value()
476 if self.SP_MaxSize.value() != 100 : self.commande+=" --max_size %f" %self.SP_MaxSize.value()
477 if self.SP_MinSize.value() != 5 : self.commande+=" --min_size %f" %self.SP_MinSize.value()
478 if self.SP_Gradation.value() != 1.3 : self.commande+=" --gradation %f" %self.SP_MaxSize.value()
479 if self.SP_Memory.value() != 0 : self.commande+=" --max_memory %d" %self.SP_Memory.value()
480 if self.SP_Verbosity.value() != 3 : self.commande+=" --max_memory %d" %self.SP_Verbosity.value()
482 self.commande+=" --in " + self.fichierIn
483 self.commande+=" --out " + self.fichierOut
489 self.RB_0.setChecked(True)
490 #no need: exlusives QRadioButton
491 #self.RB_G.setChecked(False)
492 #self.RB_U.setChecked(False)
493 #self.RB_S.setChecked(False)
494 #self.RB_2.setChecked(False)
495 #self.RB_1.setChecked(False)
496 self.RB_Relative.setChecked(True)
497 #no need: exlusives QRadioButton
498 #self.RB_Absolute.setChecked(False)
499 self.SP_Tolerance.setProperty("text", "0.001")
500 self.SP_Geomapp.setProperty("value", 15.0)
501 self.SP_Ridge.setProperty("value", 45.0)
502 self.SP_Gradation.setProperty("value", 1.3)
503 self.CB_Ridge.setChecked(True)
504 self.CB_Point.setChecked(True)
505 self.CB_SplitEdge.setChecked(False)
506 self.SP_MaxSize.setProperty("value", -2.0)
507 self.SP_MinSize.setProperty("value", -2.0)
508 self.SP_Verbosity.setProperty("value", 3)
509 self.SP_Memory.setProperty("value", 0)
514 This function returns a singleton instance of the plugin dialog.
515 c est obligatoire pour faire un show sans parent...
519 __dialog = MonYamsPlugDialog()
525 # ==============================================================================
526 # Basic use cases and unit test functions
527 # ==============================================================================
529 def TEST_MonYamsPlugDialog():
531 from PyQt4.QtGui import QApplication
532 from PyQt4.QtCore import QObject, SIGNAL, SLOT
533 app = QApplication(sys.argv)
534 QObject.connect(app, SIGNAL("lastWindowClosed()"), app, SLOT("quit()"))
536 dlg=MonYamsPlugDialog()
538 sys.exit(app.exec_())
540 if __name__ == "__main__":
541 TEST_MonYamsPlugDialog()