1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2007-2015 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 qtsalome import *
29 class MonYamsPlugDialog(Ui_YamsPlugDialog,QWidget):
33 QWidget.__init__(self)
35 self.connecterSignaux()
41 self.__selectedMesh=None
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__))
48 self.iconfolder=os.environ["SMESH_ROOT_DIR"]+"/share/salome/resources/smesh"
49 #print "monYamsPlugDialog iconfolder",iconfolder
51 icon.addFile(os.path.join(self.iconfolder,"select1.png"))
52 self.PB_LoadHyp.setIcon(icon)
53 self.PB_LoadHyp.setToolTip("hypothesis from Salome Object Browser")
54 self.PB_SaveHyp.setIcon(icon)
55 self.PB_SaveHyp.setToolTip("hypothesis to Salome Object Browser")
56 self.PB_MeshSmesh.setIcon(icon)
57 self.PB_MeshSmesh.setToolTip("source mesh from Salome Object Browser")
59 icon.addFile(os.path.join(self.iconfolder,"open.png"))
60 self.PB_ParamsFileExplorer.setIcon(icon)
61 self.PB_Load.setIcon(icon)
62 self.PB_Load.setToolTip("hypothesis from file")
63 self.PB_Save.setIcon(icon)
64 self.PB_Save.setToolTip("hypothesis to file")
65 self.PB_MeshFile.setIcon(icon)
66 self.PB_MeshFile.setToolTip("source mesh from a file in disk")
68 #Ces parametres ne sont pas remis à rien par le clean
69 self.paramsFile= os.path.abspath(os.path.join(os.environ["HOME"],".yams.dat"))
70 self.LE_ParamsFile.setText(self.paramsFile)
71 self.LE_MeshFile.setText("")
72 self.LE_MeshSmesh.setText("")
74 v1=QDoubleValidator(self)
76 #v1.setTop(1000.) #per thousand... only if relative
78 self.SP_Tolerance.setValidator(v1)
79 self.SP_Tolerance.titleForWarning="Chordal Tolerance"
84 def connecterSignaux(self) :
85 self.PB_Cancel.clicked.connect(self.PBCancelPressed)
86 self.PB_Default.clicked.connect(self.clean)
87 self.PB_Help.clicked.connect(self.PBHelpPressed)
88 self.PB_OK.clicked.connect(self.PBOKPressed)
90 self.PB_Load.clicked.connect(self.PBLoadPressed)
91 self.PB_Save.clicked.connect(self.PBSavePressed)
92 self.PB_LoadHyp.clicked.connect(self.PBLoadHypPressed)
93 self.PB_SaveHyp.clicked.connect(self.PBSaveHypPressed)
95 self.PB_MeshFile.clicked.connect(self.PBMeshFilePressed)
96 self.PB_MeshSmesh.clicked.connect(self.PBMeshSmeshPressed)
97 self.LE_MeshSmesh.returnPressed.connect(self.meshSmeshNameChanged)
98 self.PB_ParamsFileExplorer.clicked.connect(self.setParamsFileName)
99 self.LE_MeshFile.returnPressed.connect(self.meshFileNameChanged)
100 self.LE_ParamsFile.returnPressed.connect(self.paramsFileNameChanged)
102 def PBHelpPressed(self):
104 sgPyQt = SalomePyQt.SalomePyQt()
106 mydir=os.environ["SMESH_ROOT_DIR"]
108 QMessageBox.warning(self, "Help", "Help unavailable $SMESH_ROOT_DIR not found")
111 maDoc=mydir+"/share/doc/salome/gui/SMESH/yams/index.html"
112 sgPyQt.helpContext(maDoc,"")
114 #maDoc=mydir+"/share/doc/salome/gui/SMESH/yams/_downloads/mg-surfopt_user_manual.pdf"
115 #command="xdg-open "+maDoc+";"
116 #subprocess.call(command, shell=True)
118 def PBOKPressed(self):
119 if not(self.PrepareLigneCommande()):
121 #QMessageBox.warning(self, "Compute", "Command not found")
123 maFenetre=MonViewText(self,self.commande)
125 def enregistreResultat(self):
128 from salome.kernel import studyedit
129 from salome.smesh import smeshBuilder
130 smesh = smeshBuilder.New(salome.myStudy)
132 if not os.path.isfile(self.fichierOut):
133 QMessageBox.warning(self, "Compute", "Result file "+self.fichierOut+" not found")
135 maStudy=studyedit.getActiveStudy()
136 smesh.SetCurrentStudy(maStudy)
137 (outputMesh, status) = smesh.CreateMeshesFromGMF(self.fichierOut)
138 name=str(self.LE_MeshSmesh.text())
140 initialMeshObject=None
142 a=str(self.fichierIn)
143 name=os.path.basename(os.path.splitext(a)[0])
146 initialMeshObject=maStudy.FindObjectByName(name ,"SMESH")[0]
148 meshname = name+"_YAMS_"+str(self.num)
149 smesh.SetName(outputMesh.GetMesh(), meshname)
150 outputMesh.Compute() #no algorithms message for "Mesh_x" has been computed with warnings: - global 1D algorithm is missing
152 self.editor = studyedit.getStudyEditor()
153 moduleEntry=self.editor.findOrCreateComponent("SMESH","SMESH")
154 HypReMeshEntry = self.editor.findOrCreateItem(
155 moduleEntry, name = "Plugins Hypotheses", icon="mesh_tree_hypo.png") #, comment = "HypoForRemeshing" )
157 monStudyBuilder=maStudy.NewBuilder()
158 monStudyBuilder.NewCommand()
159 newStudyIter=monStudyBuilder.NewObject(HypReMeshEntry)
160 self.editor.setAttributeValue(newStudyIter, "AttributeName", "YAMS Parameters_"+str(self.num))
161 self.editor.setAttributeValue(newStudyIter, "AttributeComment", self.getResumeData(separator=" ; "))
163 SOMesh=maStudy.FindObjectByName(meshname ,"SMESH")[0]
165 if initialMeshFile!=None:
166 newStudyFileName=monStudyBuilder.NewObject(SOMesh)
167 self.editor.setAttributeValue(newStudyFileName, "AttributeName", "meshFile")
168 self.editor.setAttributeValue(newStudyFileName, "AttributeExternalFileDef", initialMeshFile)
169 self.editor.setAttributeValue(newStudyFileName, "AttributeComment", initialMeshFile)
171 if initialMeshObject!=None:
172 newLink=monStudyBuilder.NewObject(SOMesh)
173 monStudyBuilder.Addreference(newLink, initialMeshObject)
175 newLink=monStudyBuilder.NewObject(SOMesh)
176 monStudyBuilder.Addreference(newLink, newStudyIter)
178 if salome.sg.hasDesktop(): salome.sg.updateObjBrowser(0)
182 def PBSavePressed(self):
183 from datetime import datetime
184 if not(self.PrepareLigneCommande()): return
185 text = "# YAMS hypothesis parameters\n"
186 text += "# Params for mesh : " + self.LE_MeshSmesh.text() +"\n"
187 text += datetime.now().strftime("# Date : %d/%m/%y %H:%M:%S\n")
188 text += "# Command : "+self.commande+"\n"
189 text += self.getResumeData(separator="\n")
193 f=open(self.paramsFile,"a")
195 QMessageBox.warning(self, "File", "Unable to open "+self.paramsFile)
200 QMessageBox.warning(self, "File", "Unable to write "+self.paramsFile)
204 def PBSaveHypPressed(self):
205 """save hypothesis in Object Browser"""
208 from salome.kernel import studyedit
209 from salome.smesh import smeshBuilder
210 smesh = smeshBuilder.New(salome.myStudy)
212 maStudy=studyedit.getActiveStudy()
213 smesh.SetCurrentStudy(maStudy)
215 self.editor = studyedit.getStudyEditor()
216 moduleEntry=self.editor.findOrCreateComponent("SMESH","SMESH")
217 HypReMeshEntry = self.editor.findOrCreateItem(
218 moduleEntry, name = "Plugins Hypotheses", icon="mesh_tree_hypo.png") #, comment = "HypoForRemeshing" )
220 monStudyBuilder=maStudy.NewBuilder()
221 monStudyBuilder.NewCommand()
222 newStudyIter=monStudyBuilder.NewObject(HypReMeshEntry)
223 self.editor.setAttributeValue(newStudyIter, "AttributeName", "YAMS Parameters_"+str(self.num))
224 self.editor.setAttributeValue(newStudyIter, "AttributeComment", self.getResumeData(separator=" ; "))
226 if salome.sg.hasDesktop(): salome.sg.updateObjBrowser(0)
230 def SP_toStr(self, widget):
231 """only for a QLineEdit widget"""
232 #cr, pos=widget.validator().validate(res, 0) #n.b. "1,3" is acceptable !locale!
234 val=float(widget.text())
236 QMessageBox.warning(self, widget.titleForWarning, "float value is incorrect: '"+widget.text()+"'")
237 res=str(widget.validator().bottom())
238 widget.setProperty("text", res)
240 valtest=widget.validator().bottom()
243 QMessageBox.warning(self, widget.titleForWarning, "float value is under minimum: "+str(val)+" < "+str(valtest))
245 widget.setProperty("text", res)
247 valtest=widget.validator().top()
250 QMessageBox.warning(self, widget.titleForWarning, "float value is over maximum: "+str(val)+" > "+str(valtest))
252 widget.setProperty("text", res)
256 def getResumeData(self, separator="\n"):
258 for RB in self.GBOptim.findChildren(QRadioButton,):
259 if RB.isChecked()==True:
260 text+="Optimisation="+RB.text()+separator
262 if self.RB_Absolute.isChecked():
263 text+="Units=absolute"+separator
265 text+="Units=relative"+separator
266 v=self.SP_toStr(self.SP_Tolerance)
267 text+="ChordalToleranceDeviation="+v+separator
268 text+="RidgeDetection="+str(self.CB_Ridge.isChecked())+separator
269 text+="SplitEdge="+str(self.CB_SplitEdge.isChecked())+separator
270 text+="PointSmoothing="+str(self.CB_Point.isChecked())+separator
271 text+="GeometricalApproximation="+str(self.SP_Geomapp.value())+separator
272 text+="RidgeAngle="+str(self.SP_Ridge.value())+separator
273 text+="MaximumSize="+str(self.SP_MaxSize.value())+separator
274 text+="MinimumSize="+str(self.SP_MinSize.value())+separator
275 text+="MeshGradation="+str(self.SP_Gradation.value())+separator
276 text+="Verbosity="+str(self.SP_Verbosity.value())+separator
277 text+="Memory="+str(self.SP_Memory.value())+separator
280 def loadResumeData(self, hypothesis, separator="\n"):
283 for slig in reversed(text.split(separator)):
285 #print "load ResumeData",lig
286 if lig=="": continue #skip blanck lines
287 if lig[0]=="#": break
289 tit,value=lig.split("=")
290 if tit=="Optimisation":
291 #no need: exlusives QRadioButton
292 #for RB in self.GBOptim.findChildren(QRadioButton,):
293 # RB.setChecked(False)
294 for RB in self.GBOptim.findChildren(QRadioButton,):
295 if RB.text()==value :
299 if value=="absolute":
300 self.RB_Absolute.setChecked(True)
301 self.RB_Relative.setChecked(False)
303 self.RB_Absolute.setChecked(False)
304 self.RB_Relative.setChecked(True)
305 if tit=="ChordalToleranceDeviation": self.SP_Tolerance.setProperty("text", float(value))
306 if tit=="RidgeDetection": self.CB_Ridge.setChecked(value=="True")
307 if tit=="SplitEdge": self.CB_SplitEdge.setChecked(value=="True")
308 if tit=="PointSmoothing": self.CB_Point.setChecked(value=="True")
309 if tit=="GeometricalApproximation": self.SP_Geomapp.setProperty("value", float(value))
310 if tit=="RidgeAngle": self.SP_Ridge.setProperty("value", float(value))
311 if tit=="MaximumSize": self.SP_MaxSize.setProperty("value", float(value))
312 if tit=="MinimumSize": self.SP_MinSize.setProperty("value", float(value))
313 if tit=="MeshGradation": self.SP_Gradation.setProperty("value", float(value))
314 if tit=="Verbosity": self.SP_Verbosity.setProperty("value", int(float(value)))
315 if tit=="Memory": self.SP_Memory.setProperty("value", float(value))
317 QMessageBox.warning(self, "load YAMS Hypothesis", "Problem on '"+lig+"'")
319 def PBLoadPressed(self):
320 """load last hypothesis saved in tail of file"""
322 f=open(self.paramsFile,"r")
324 QMessageBox.warning(self, "File", "Unable to open "+self.paramsFile)
329 QMessageBox.warning(self, "File", "Unable to read "+self.paramsFile)
332 self.loadResumeData(text, separator="\n")
334 def PBLoadHypPressed(self):
335 """load hypothesis saved in Object Browser"""
336 #QMessageBox.warning(self, "load Object Browser YAMS hypothesis", "TODO")
338 from salome.kernel import studyedit
339 from salome.smesh.smeshstudytools import SMeshStudyTools
340 from salome.gui import helper as guihelper
341 from omniORB import CORBA
343 mySObject, myEntry = guihelper.getSObjectSelected()
344 if CORBA.is_nil(mySObject) or mySObject==None:
345 QMessageBox.critical(self, "Hypothese", "select an Object Browser YAMS hypothesis")
348 text=mySObject.GetComment()
351 if "Optimisation=" not in text:
352 QMessageBox.critical(self, "Load Hypothese", "Object Browser selection not a YAMS Hypothesis")
354 self.loadResumeData(text, separator=" ; ")
357 def PBCancelPressed(self):
360 def PBMeshFilePressed(self):
361 fd = QFileDialog(self, "select an existing Mesh file", self.LE_MeshFile.text(), "Mesh-Files (*.mesh);;All Files (*)")
363 infile = fd.selectedFiles()[0]
364 self.LE_MeshFile.setText(infile)
365 self.fichierIn=unicode(infile).encode("latin-1")
367 self.LE_MeshSmesh.setText("")
369 def setParamsFileName(self):
370 fd = QFileDialog(self, "select a file", self.LE_ParamsFile.text(), "dat Files (*.dat);;All Files (*)")
372 infile = fd.selectedFiles()[0]
373 self.LE_ParamsFile.setText(infile)
374 self.paramsFile=unicode(infile).encode("latin-1")
376 def meshFileNameChanged(self):
377 self.fichierIn=str(self.LE_MeshFile.text())
378 #print "meshFileNameChanged", self.fichierIn
379 if os.path.exists(self.fichierIn):
380 self.__selectedMesh=None
382 self.LE_MeshSmesh.setText("")
384 QMessageBox.warning(self, "Mesh file", "File doesn't exist")
386 def meshSmeshNameChanged(self):
387 """only change by GUI mouse selection, otherwise clear"""
388 self.__selectedMesh = None
390 self.LE_MeshSmesh.setText("")
394 def paramsFileNameChanged(self):
395 self.paramsFile=self.LE_ParamsFile.text()
397 def PBMeshSmeshPressed(self):
398 from omniORB import CORBA
400 from salome.kernel import studyedit
401 from salome.smesh.smeshstudytools import SMeshStudyTools
402 from salome.gui import helper as guihelper
403 from salome.smesh import smeshBuilder
404 smesh = smeshBuilder.New(salome.myStudy)
406 mySObject, myEntry = guihelper.getSObjectSelected()
407 if CORBA.is_nil(mySObject) or mySObject==None:
408 #QMessageBox.critical(self, "Mesh", "select an input mesh")
409 self.LE_MeshSmesh.setText("")
411 self.LE_MeshFile.setText("")
414 self.smeshStudyTool = SMeshStudyTools()
416 self.__selectedMesh = self.smeshStudyTool.getMeshObjectFromSObject(mySObject)
418 QMessageBox.critical(self, "Mesh", "select an input mesh")
420 if CORBA.is_nil(self.__selectedMesh):
421 QMessageBox.critical(self, "Mesh", "select an input mesh")
423 myName = mySObject.GetName()
424 #print "MeshSmeshNameChanged", myName
426 self.LE_MeshSmesh.setText(myName)
427 self.LE_MeshFile.setText("")
430 def prepareFichier(self):
431 self.fichierIn="/tmp/ForSurfOpt_"+str(self.num)+".meshb"
432 self.__selectedMesh.ExportGMF(self.__selectedMesh, self.fichierIn, True)
434 def PrepareLigneCommande(self):
435 if self.fichierIn=="" and self.MeshIn=="":
436 QMessageBox.critical(self, "Mesh", "select an input mesh")
438 if self.__selectedMesh!=None: self.prepareFichier()
439 if not (os.path.isfile(self.fichierIn)):
440 QMessageBox.critical(self, "File", "unable to read GMF Mesh in "+str(self.fichierIn))
443 self.commande="mg-surfopt.exe"
445 for obj in self.GBOptim.findChildren(QRadioButton,):
448 self.style=obj.objectName().remove(0,3)
449 self.style.replace("_","-")
454 style = unicode(self.style).encode("latin-1")
455 # Translation of old Yams options to new MG-SurfOpt options
457 self.commande+= " --optimisation only"
459 self.commande+= " --Hausdorff_like yes"
461 self.commande+= " --enrich no"
463 self.commande+= " --Hausdorff_like yes --enrich no"
465 self.commande+= " --uniform_flat_subdivision yes"
467 self.commande+= " --sand_paper yes"
469 self.commande+= " -O G" # This option has not been updated to the new option style yet
471 deb=os.path.splitext(self.fichierIn)
472 self.fichierOut=deb[0] + "_output.meshb"
474 tolerance=self.SP_toStr(self.SP_Tolerance)
475 if not self.RB_Absolute.isChecked():
477 self.commande+=" --chordal_error %s"%tolerance
479 if self.CB_Ridge.isChecked() == False : self.commande+=" --compute_ridges no"
480 if self.CB_Point.isChecked() == False : self.commande+=" --optimisation no"
481 if self.CB_SplitEdge.isChecked()== True : self.commande+=" --element_order quadratic"
482 if self.SP_Geomapp.value() != 15.0 : self.commande+=" --geometric_approximation_angle %f"%self.SP_Geomapp.value()
483 if self.SP_Ridge.value() != 45.0 : self.commande+=" --ridge_angle %f"%self.SP_Ridge.value()
484 if self.SP_MaxSize.value() != 100 : self.commande+=" --max_size %f" %self.SP_MaxSize.value()
485 if self.SP_MinSize.value() != 5 : self.commande+=" --min_size %f" %self.SP_MinSize.value()
486 if self.SP_Gradation.value() != 1.3 : self.commande+=" --gradation %f" %self.SP_Gradation.value()
487 if self.SP_Memory.value() != 0 : self.commande+=" --max_memory %d" %self.SP_Memory.value()
488 if self.SP_Verbosity.value() != 3 : self.commande+=" --verbose %d" %self.SP_Verbosity.value()
490 self.commande+=" --in " + self.fichierIn
491 self.commande+=" --out " + self.fichierOut
497 self.RB_0.setChecked(True)
498 #no need: exlusives QRadioButton
499 #self.RB_G.setChecked(False)
500 #self.RB_U.setChecked(False)
501 #self.RB_S.setChecked(False)
502 #self.RB_2.setChecked(False)
503 #self.RB_1.setChecked(False)
504 self.RB_Relative.setChecked(True)
505 #no need: exlusives QRadioButton
506 #self.RB_Absolute.setChecked(False)
507 self.SP_Tolerance.setProperty("text", "0.001")
508 self.SP_Geomapp.setProperty("value", 15.0)
509 self.SP_Ridge.setProperty("value", 45.0)
510 self.SP_Gradation.setProperty("value", 1.3)
511 self.CB_Ridge.setChecked(True)
512 self.CB_Point.setChecked(True)
513 self.CB_SplitEdge.setChecked(False)
514 self.SP_MaxSize.setProperty("value", 100)
515 self.SP_MinSize.setProperty("value", 5)
516 self.SP_Verbosity.setProperty("value", 3)
517 self.SP_Memory.setProperty("value", 0)
518 self.PBMeshSmeshPressed()
519 self.TWOptions.setCurrentIndex(0) # Reset current active tab to the first tab
524 This function returns a singleton instance of the plugin dialog.
525 It is mandatory in order to call show without a parent ...
529 __dialog = MonYamsPlugDialog()
535 # ==============================================================================
536 # Basic use cases and unit test functions
537 # ==============================================================================
539 def TEST_MonYamsPlugDialog():
541 from qtsalome import QApplication
542 app = QApplication(sys.argv)
543 app.lastWindowClosed.connect(app.quit)
545 dlg=MonYamsPlugDialog()
547 sys.exit(app.exec_())
549 if __name__ == "__main__":
550 TEST_MonYamsPlugDialog()