1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2007-2016 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
26 from YamsPlugDialog_ui import Ui_YamsPlugDialog
27 from monViewText import MonViewText
28 from PyQt4.QtGui import *
29 from PyQt4.QtCore import *
32 class MonYamsPlugDialog(Ui_YamsPlugDialog,QWidget):
36 QWidget.__init__(self)
38 self.connecterSignaux()
44 self.__selectedMesh=None
46 # complex whith QResources: not used
47 # The icon are supposed to be located in the $SMESH_ROOT_DIR/share/salome/resources/smesh folder,
48 # other solution could be in the same folder than this python module file:
49 # iconfolder=os.path.dirname(os.path.abspath(__file__))
51 self.iconfolder=os.environ["SMESH_ROOT_DIR"]+"/share/salome/resources/smesh"
52 #print "monYamsPlugDialog iconfolder",iconfolder
54 icon.addFile(os.path.join(self.iconfolder,"select1.png"))
55 self.PB_LoadHyp.setIcon(icon)
56 self.PB_LoadHyp.setToolTip("hypothesis from Salome Object Browser")
57 self.PB_SaveHyp.setIcon(icon)
58 self.PB_SaveHyp.setToolTip("hypothesis to Salome Object Browser")
59 self.PB_MeshSmesh.setIcon(icon)
60 self.PB_MeshSmesh.setToolTip("source mesh from Salome Object Browser")
62 icon.addFile(os.path.join(self.iconfolder,"open.png"))
63 self.PB_ParamsFileExplorer.setIcon(icon)
64 self.PB_Load.setIcon(icon)
65 self.PB_Load.setToolTip("hypothesis from file")
66 self.PB_Save.setIcon(icon)
67 self.PB_Save.setToolTip("hypothesis to file")
68 self.PB_MeshFile.setIcon(icon)
69 self.PB_MeshFile.setToolTip("source mesh from a file in disk")
71 #Ces parametres ne sont pas remis à rien par le clean
72 self.paramsFile= os.path.abspath(os.path.join(os.environ["HOME"],".yams.dat"))
73 self.LE_ParamsFile.setText(self.paramsFile)
74 self.LE_MeshFile.setText("")
75 self.LE_MeshSmesh.setText("")
77 v1=QDoubleValidator(self)
79 #v1.setTop(1000.) #per thousand... only if relative
81 self.SP_Tolerance.setValidator(v1)
82 self.SP_Tolerance.titleForWarning="Chordal Tolerance"
87 def connecterSignaux(self) :
88 self.connect(self.PB_Cancel,SIGNAL("clicked()"),self.PBCancelPressed)
89 self.connect(self.PB_Default,SIGNAL("clicked()"),self.clean)
90 self.connect(self.PB_Help,SIGNAL("clicked()"),self.PBHelpPressed)
91 self.connect(self.PB_OK,SIGNAL("clicked()"),self.PBOKPressed)
93 self.connect(self.PB_Load,SIGNAL("clicked()"),self.PBLoadPressed)
94 self.connect(self.PB_Save,SIGNAL("clicked()"),self.PBSavePressed)
95 self.connect(self.PB_LoadHyp,SIGNAL("clicked()"),self.PBLoadHypPressed)
96 self.connect(self.PB_SaveHyp,SIGNAL("clicked()"),self.PBSaveHypPressed)
98 self.connect(self.PB_MeshFile,SIGNAL("clicked()"),self.PBMeshFilePressed)
99 self.connect(self.PB_MeshSmesh,SIGNAL("clicked()"),self.PBMeshSmeshPressed)
100 self.connect(self.LE_MeshSmesh,SIGNAL("returnPressed()"),self.meshSmeshNameChanged)
101 self.connect(self.PB_ParamsFileExplorer,SIGNAL("clicked()"),self.setParamsFileName)
102 self.connect(self.LE_MeshFile,SIGNAL("returnPressed()"),self.meshFileNameChanged)
103 self.connect(self.LE_ParamsFile,SIGNAL("returnPressed()"),self.paramsFileNameChanged)
105 def PBHelpPressed(self):
107 sgPyQt = SalomePyQt.SalomePyQt()
109 mydir=os.environ["SMESH_ROOT_DIR"]
111 QMessageBox.warning(self, "Help", "Help unavailable $SMESH_ROOT_DIR not found")
114 maDoc=mydir+"/share/doc/salome/gui/SMESH/yams/index.html"
115 sgPyQt.helpContext(maDoc,"")
117 #maDoc=mydir+"/share/doc/salome/gui/SMESH/yams/_downloads/mg-surfopt_user_manual.pdf"
118 #command="xdg-open "+maDoc+";"
119 #subprocess.call(command, shell=True)
121 def PBOKPressed(self):
122 if not(self.PrepareLigneCommande()):
124 #QMessageBox.warning(self, "Compute", "Command not found")
126 maFenetre=MonViewText(self,self.commande)
128 def enregistreResultat(self):
131 from salome.kernel import studyedit
132 from salome.smesh import smeshBuilder
133 smesh = smeshBuilder.New(salome.myStudy)
135 if not os.path.isfile(self.fichierOut):
136 QMessageBox.warning(self, "Compute", "Result file "+self.fichierOut+" not found")
138 maStudy=studyedit.getActiveStudy()
139 smesh.SetCurrentStudy(maStudy)
140 (outputMesh, status) = smesh.CreateMeshesFromGMF(self.fichierOut)
141 name=str(self.LE_MeshSmesh.text())
143 initialMeshObject=None
145 a=str(self.fichierIn)
146 name=os.path.basename(os.path.splitext(a)[0])
149 initialMeshObject=maStudy.FindObjectByName(name ,"SMESH")[0]
151 meshname = name+"_YAMS_"+str(self.num)
152 smesh.SetName(outputMesh.GetMesh(), meshname)
153 outputMesh.Compute() #no algorithms message for "Mesh_x" has been computed with warnings: - global 1D algorithm is missing
155 self.editor = studyedit.getStudyEditor()
156 moduleEntry=self.editor.findOrCreateComponent("SMESH","SMESH")
157 HypReMeshEntry = self.editor.findOrCreateItem(
158 moduleEntry, name = "Plugins Hypotheses", icon="mesh_tree_hypo.png") #, comment = "HypoForRemeshing" )
160 monStudyBuilder=maStudy.NewBuilder()
161 monStudyBuilder.NewCommand()
162 newStudyIter=monStudyBuilder.NewObject(HypReMeshEntry)
163 self.editor.setAttributeValue(newStudyIter, "AttributeName", "YAMS Parameters_"+str(self.num))
164 self.editor.setAttributeValue(newStudyIter, "AttributeComment", self.getResumeData(separator=" ; "))
166 SOMesh=maStudy.FindObjectByName(meshname ,"SMESH")[0]
168 if initialMeshFile!=None:
169 newStudyFileName=monStudyBuilder.NewObject(SOMesh)
170 self.editor.setAttributeValue(newStudyFileName, "AttributeName", "meshFile")
171 self.editor.setAttributeValue(newStudyFileName, "AttributeExternalFileDef", initialMeshFile)
172 self.editor.setAttributeValue(newStudyFileName, "AttributeComment", initialMeshFile)
174 if initialMeshObject!=None:
175 newLink=monStudyBuilder.NewObject(SOMesh)
176 monStudyBuilder.Addreference(newLink, initialMeshObject)
178 newLink=monStudyBuilder.NewObject(SOMesh)
179 monStudyBuilder.Addreference(newLink, newStudyIter)
181 if salome.sg.hasDesktop(): salome.sg.updateObjBrowser(0)
185 def PBSavePressed(self):
186 from datetime import datetime
187 if not(self.PrepareLigneCommande()): return
188 text = "# YAMS hypothesis parameters\n"
189 text += "# Params for mesh : " + self.LE_MeshSmesh.text() +"\n"
190 text += datetime.now().strftime("# Date : %d/%m/%y %H:%M:%S\n")
191 text += "# Command : "+self.commande+"\n"
192 text += self.getResumeData(separator="\n")
196 f=open(self.paramsFile,"a")
198 QMessageBox.warning(self, "File", "Unable to open "+self.paramsFile)
203 QMessageBox.warning(self, "File", "Unable to write "+self.paramsFile)
207 def PBSaveHypPressed(self):
208 """save hypothesis in Object Browser"""
211 from salome.kernel import studyedit
212 from salome.smesh import smeshBuilder
213 smesh = smeshBuilder.New(salome.myStudy)
215 maStudy=studyedit.getActiveStudy()
216 smesh.SetCurrentStudy(maStudy)
218 self.editor = studyedit.getStudyEditor()
219 moduleEntry=self.editor.findOrCreateComponent("SMESH","SMESH")
220 HypReMeshEntry = self.editor.findOrCreateItem(
221 moduleEntry, name = "Plugins Hypotheses", icon="mesh_tree_hypo.png") #, comment = "HypoForRemeshing" )
223 monStudyBuilder=maStudy.NewBuilder()
224 monStudyBuilder.NewCommand()
225 newStudyIter=monStudyBuilder.NewObject(HypReMeshEntry)
226 self.editor.setAttributeValue(newStudyIter, "AttributeName", "YAMS Parameters_"+str(self.num))
227 self.editor.setAttributeValue(newStudyIter, "AttributeComment", self.getResumeData(separator=" ; "))
229 if salome.sg.hasDesktop(): salome.sg.updateObjBrowser(0)
233 def SP_toStr(self, widget):
234 """only for a QLineEdit widget"""
235 #cr, pos=widget.validator().validate(res, 0) #n.b. "1,3" is acceptable !locale!
237 val=float(widget.text())
239 QMessageBox.warning(self, widget.titleForWarning, "float value is incorrect: '"+widget.text()+"'")
240 res=str(widget.validator().bottom())
241 widget.setProperty("text", res)
243 valtest=widget.validator().bottom()
246 QMessageBox.warning(self, widget.titleForWarning, "float value is under minimum: "+str(val)+" < "+str(valtest))
248 widget.setProperty("text", res)
250 valtest=widget.validator().top()
253 QMessageBox.warning(self, widget.titleForWarning, "float value is over maximum: "+str(val)+" > "+str(valtest))
255 widget.setProperty("text", res)
259 def getResumeData(self, separator="\n"):
261 for RB in self.GBOptim.findChildren(QRadioButton,):
262 if RB.isChecked()==True:
263 text+="Optimisation="+RB.text()+separator
265 if self.RB_Absolute.isChecked():
266 text+="Units=absolute"+separator
268 text+="Units=relative"+separator
269 v=self.SP_toStr(self.SP_Tolerance)
270 text+="ChordalToleranceDeviation="+v+separator
271 text+="RidgeDetection="+str(self.CB_Ridge.isChecked())+separator
272 text+="SplitEdge="+str(self.CB_SplitEdge.isChecked())+separator
273 text+="PointSmoothing="+str(self.CB_Point.isChecked())+separator
274 text+="GeometricalApproximation="+str(self.SP_Geomapp.value())+separator
275 text+="RidgeAngle="+str(self.SP_Ridge.value())+separator
276 text+="MaximumSize="+str(self.SP_MaxSize.value())+separator
277 text+="MinimumSize="+str(self.SP_MinSize.value())+separator
278 text+="MeshGradation="+str(self.SP_Gradation.value())+separator
279 text+="Verbosity="+str(self.SP_Verbosity.value())+separator
280 text+="Memory="+str(self.SP_Memory.value())+separator
283 def loadResumeData(self, hypothesis, separator="\n"):
286 for slig in reversed(text.split(separator)):
288 #print "load ResumeData",lig
289 if lig=="": continue #skip blanck lines
290 if lig[0]=="#": break
292 tit,value=lig.split("=")
293 if tit=="Optimisation":
294 #no need: exlusives QRadioButton
295 #for RB in self.GBOptim.findChildren(QRadioButton,):
296 # RB.setChecked(False)
297 for RB in self.GBOptim.findChildren(QRadioButton,):
298 if RB.text()==value :
302 if value=="absolute":
303 self.RB_Absolute.setChecked(True)
304 self.RB_Relative.setChecked(False)
306 self.RB_Absolute.setChecked(False)
307 self.RB_Relative.setChecked(True)
308 if tit=="ChordalToleranceDeviation": self.SP_Tolerance.setProperty("text", float(value))
309 if tit=="RidgeDetection": self.CB_Ridge.setChecked(value=="True")
310 if tit=="SplitEdge": self.CB_SplitEdge.setChecked(value=="True")
311 if tit=="PointSmoothing": self.CB_Point.setChecked(value=="True")
312 if tit=="GeometricalApproximation": self.SP_Geomapp.setProperty("value", float(value))
313 if tit=="RidgeAngle": self.SP_Ridge.setProperty("value", float(value))
314 if tit=="MaximumSize": self.SP_MaxSize.setProperty("value", float(value))
315 if tit=="MinimumSize": self.SP_MinSize.setProperty("value", float(value))
316 if tit=="MeshGradation": self.SP_Gradation.setProperty("value", float(value))
317 if tit=="Verbosity": self.SP_Verbosity.setProperty("value", int(float(value)))
318 if tit=="Memory": self.SP_Memory.setProperty("value", float(value))
320 QMessageBox.warning(self, "load YAMS Hypothesis", "Problem on '"+lig+"'")
322 def PBLoadPressed(self):
323 """load last hypothesis saved in tail of file"""
325 f=open(self.paramsFile,"r")
327 QMessageBox.warning(self, "File", "Unable to open "+self.paramsFile)
332 QMessageBox.warning(self, "File", "Unable to read "+self.paramsFile)
335 self.loadResumeData(text, separator="\n")
337 def PBLoadHypPressed(self):
338 """load hypothesis saved in Object Browser"""
339 #QMessageBox.warning(self, "load Object Browser YAMS hypothesis", "TODO")
341 from salome.kernel import studyedit
342 from salome.smesh.smeshstudytools import SMeshStudyTools
343 from salome.gui import helper as guihelper
344 from omniORB import CORBA
346 mySObject, myEntry = guihelper.getSObjectSelected()
347 if CORBA.is_nil(mySObject) or mySObject==None:
348 QMessageBox.critical(self, "Hypothese", "select an Object Browser YAMS hypothesis")
351 text=mySObject.GetComment()
354 if "Optimisation=" not in text:
355 QMessageBox.critical(self, "Load Hypothese", "Object Browser selection not a YAMS Hypothesis")
357 self.loadResumeData(text, separator=" ; ")
360 def PBCancelPressed(self):
363 def PBMeshFilePressed(self):
364 fd = QFileDialog(self, "select an existing Mesh file", self.LE_MeshFile.text(), "Mesh-Files (*.mesh);;All Files (*)")
366 infile = fd.selectedFiles()[0]
367 self.LE_MeshFile.setText(infile)
368 self.fichierIn=infile.toLatin1()
370 self.LE_MeshSmesh.setText("")
372 def setParamsFileName(self):
373 fd = QFileDialog(self, "select a file", self.LE_ParamsFile.text(), "dat Files (*.dat);;All Files (*)")
375 infile = fd.selectedFiles()[0]
376 self.LE_ParamsFile.setText(infile)
377 self.paramsFile=infile.toLatin1()
379 def meshFileNameChanged(self):
380 self.fichierIn=str(self.LE_MeshFile.text())
381 #print "meshFileNameChanged", self.fichierIn
382 if os.path.exists(self.fichierIn):
383 self.__selectedMesh=None
385 self.LE_MeshSmesh.setText("")
387 QMessageBox.warning(self, "Mesh file", "File doesn't exist")
389 def meshSmeshNameChanged(self):
390 """only change by GUI mouse selection, otherwise clear"""
391 self.__selectedMesh = None
393 self.LE_MeshSmesh.setText("")
397 def paramsFileNameChanged(self):
398 self.paramsFile=self.LE_ParamsFile.text()
400 def PBMeshSmeshPressed(self):
401 from omniORB import CORBA
403 from salome.kernel import studyedit
404 from salome.smesh.smeshstudytools import SMeshStudyTools
405 from salome.gui import helper as guihelper
406 from salome.smesh import smeshBuilder
407 smesh = smeshBuilder.New(salome.myStudy)
409 mySObject, myEntry = guihelper.getSObjectSelected()
410 if CORBA.is_nil(mySObject) or mySObject==None:
411 #QMessageBox.critical(self, "Mesh", "select an input mesh")
412 self.LE_MeshSmesh.setText("")
414 self.LE_MeshFile.setText("")
417 self.smeshStudyTool = SMeshStudyTools()
419 self.__selectedMesh = self.smeshStudyTool.getMeshObjectFromSObject(mySObject)
421 QMessageBox.critical(self, "Mesh", "select an input mesh")
423 if CORBA.is_nil(self.__selectedMesh):
424 QMessageBox.critical(self, "Mesh", "select an input mesh")
426 myName = mySObject.GetName()
427 #print "MeshSmeshNameChanged", myName
429 self.LE_MeshSmesh.setText(myName)
430 self.LE_MeshFile.setText("")
433 def prepareFichier(self):
434 self.fichierIn=tempfile.mktemp(suffix=".meshb",prefix="ForSurfOpt_")
435 if os.path.exists(self.fichierIn):
436 os.remove(self.fichierIn)
437 self.__selectedMesh.ExportGMF(self.__selectedMesh, self.fichierIn, True)
439 def PrepareLigneCommande(self):
440 if self.fichierIn=="" and self.MeshIn=="":
441 QMessageBox.critical(self, "Mesh", "select an input mesh")
443 if self.__selectedMesh!=None: self.prepareFichier()
444 if not (os.path.isfile(self.fichierIn)):
445 QMessageBox.critical(self, "File", "unable to read GMF Mesh in "+str(self.fichierIn))
448 self.commande="mg-surfopt.exe"
450 for obj in self.GBOptim.findChildren(QRadioButton,):
453 self.style=obj.objectName().remove(0,3)
454 self.style.replace("_","-")
459 style = self.style.toLatin1()
460 # Translation of old Yams options to new MG-SurfOpt options
462 self.commande+= " --optimisation only"
464 self.commande+= " --Hausdorff_like yes"
466 self.commande+= " --enrich no"
468 self.commande+= " --Hausdorff_like yes --enrich no"
470 self.commande+= " --uniform_flat_subdivision yes"
472 self.commande+= " --sand_paper yes"
474 self.commande+= " -O G" # This option has not been updated to the new option style yet
476 deb=os.path.splitext(self.fichierIn)
477 self.fichierOut=deb[0] + "_output.meshb"
479 tolerance=self.SP_toStr(self.SP_Tolerance)
480 if not self.RB_Absolute.isChecked():
482 self.commande+=" --chordal_error %s"%tolerance
484 if self.CB_Ridge.isChecked() == False : self.commande+=" --compute_ridges no"
485 if self.CB_Point.isChecked() == False : self.commande+=" --optimisation no"
486 if self.CB_SplitEdge.isChecked()== True : self.commande+=" --element_order quadratic"
487 if self.SP_Geomapp.value() != 15.0 : self.commande+=" --geometric_approximation_angle %f"%self.SP_Geomapp.value()
488 if self.SP_Ridge.value() != 45.0 : self.commande+=" --ridge_angle %f"%self.SP_Ridge.value()
489 if self.SP_MaxSize.value() != 100 : self.commande+=" --max_size %f" %self.SP_MaxSize.value()
490 if self.SP_MinSize.value() != 5 : self.commande+=" --min_size %f" %self.SP_MinSize.value()
491 if self.SP_Gradation.value() != 1.3 : self.commande+=" --gradation %f" %self.SP_Gradation.value()
492 if self.SP_Memory.value() != 0 : self.commande+=" --max_memory %d" %self.SP_Memory.value()
493 if self.SP_Verbosity.value() != 3 : self.commande+=" --verbose %d" %self.SP_Verbosity.value()
495 self.commande+=" --in " + self.fichierIn
496 self.commande+=" --out " + self.fichierOut
502 self.RB_0.setChecked(True)
503 #no need: exlusives QRadioButton
504 #self.RB_G.setChecked(False)
505 #self.RB_U.setChecked(False)
506 #self.RB_S.setChecked(False)
507 #self.RB_2.setChecked(False)
508 #self.RB_1.setChecked(False)
509 self.RB_Relative.setChecked(True)
510 #no need: exlusives QRadioButton
511 #self.RB_Absolute.setChecked(False)
512 self.SP_Tolerance.setProperty("text", "0.001")
513 self.SP_Geomapp.setProperty("value", 15.0)
514 self.SP_Ridge.setProperty("value", 45.0)
515 self.SP_Gradation.setProperty("value", 1.3)
516 self.CB_Ridge.setChecked(True)
517 self.CB_Point.setChecked(True)
518 self.CB_SplitEdge.setChecked(False)
519 self.SP_MaxSize.setProperty("value", 100)
520 self.SP_MinSize.setProperty("value", 5)
521 self.SP_Verbosity.setProperty("value", 3)
522 self.SP_Memory.setProperty("value", 0)
523 self.PBMeshSmeshPressed()
524 self.TWOptions.setCurrentIndex(0) # Reset current active tab to the first tab
529 This function returns a singleton instance of the plugin dialog.
530 It is mandatory in order to call show without a parent ...
534 __dialog = MonYamsPlugDialog()
540 # ==============================================================================
541 # Basic use cases and unit test functions
542 # ==============================================================================
544 def TEST_MonYamsPlugDialog():
546 from PyQt4.QtGui import QApplication
547 from PyQt4.QtCore import QObject, SIGNAL, SLOT
548 app = QApplication(sys.argv)
549 QObject.connect(app, SIGNAL("lastWindowClosed()"), app, SLOT("quit()"))
551 dlg=MonYamsPlugDialog()
553 sys.exit(app.exec_())
555 if __name__ == "__main__":
556 TEST_MonYamsPlugDialog()