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 qtsalome import *
30 class MonYamsPlugDialog(Ui_YamsPlugDialog,QWidget):
34 QWidget.__init__(self)
36 self.connecterSignaux()
42 self.__selectedMesh=None
44 # complex whith QResources: not used
45 # The icon are supposed to be located in the $SMESH_ROOT_DIR/share/salome/resources/smesh folder,
46 # other solution could be in the same folder than this python module file:
47 # iconfolder=os.path.dirname(os.path.abspath(__file__))
49 self.iconfolder=os.environ["SMESH_ROOT_DIR"]+"/share/salome/resources/smesh"
50 #print "monYamsPlugDialog iconfolder",iconfolder
52 icon.addFile(os.path.join(self.iconfolder,"select1.png"))
53 self.PB_LoadHyp.setIcon(icon)
54 self.PB_LoadHyp.setToolTip("hypothesis from Salome Object Browser")
55 self.PB_SaveHyp.setIcon(icon)
56 self.PB_SaveHyp.setToolTip("hypothesis to Salome Object Browser")
57 self.PB_MeshSmesh.setIcon(icon)
58 self.PB_MeshSmesh.setToolTip("source mesh from Salome Object Browser")
60 icon.addFile(os.path.join(self.iconfolder,"open.png"))
61 self.PB_ParamsFileExplorer.setIcon(icon)
62 self.PB_Load.setIcon(icon)
63 self.PB_Load.setToolTip("hypothesis from file")
64 self.PB_Save.setIcon(icon)
65 self.PB_Save.setToolTip("hypothesis to file")
66 self.PB_MeshFile.setIcon(icon)
67 self.PB_MeshFile.setToolTip("source mesh from a file in disk")
69 #Ces parametres ne sont pas remis à rien par le clean
70 self.paramsFile= os.path.abspath(os.path.join(os.environ["HOME"],".yams.dat"))
71 self.LE_ParamsFile.setText(self.paramsFile)
72 self.LE_MeshFile.setText("")
73 self.LE_MeshSmesh.setText("")
75 v1=QDoubleValidator(self)
77 #v1.setTop(1000.) #per thousand... only if relative
79 self.SP_Tolerance.setValidator(v1)
80 self.SP_Tolerance.titleForWarning="Chordal Tolerance"
85 def connecterSignaux(self) :
86 self.PB_Cancel.clicked.connect(self.PBCancelPressed)
87 self.PB_Default.clicked.connect(self.clean)
88 self.PB_Help.clicked.connect(self.PBHelpPressed)
89 self.PB_OK.clicked.connect(self.PBOKPressed)
91 self.PB_Load.clicked.connect(self.PBLoadPressed)
92 self.PB_Save.clicked.connect(self.PBSavePressed)
93 self.PB_LoadHyp.clicked.connect(self.PBLoadHypPressed)
94 self.PB_SaveHyp.clicked.connect(self.PBSaveHypPressed)
96 self.PB_MeshFile.clicked.connect(self.PBMeshFilePressed)
97 self.PB_MeshSmesh.clicked.connect(self.PBMeshSmeshPressed)
98 self.LE_MeshSmesh.returnPressed.connect(self.meshSmeshNameChanged)
99 self.PB_ParamsFileExplorer.clicked.connect(self.setParamsFileName)
100 self.LE_MeshFile.returnPressed.connect(self.meshFileNameChanged)
101 self.LE_ParamsFile.returnPressed.connect(self.paramsFileNameChanged)
103 def PBHelpPressed(self):
105 sgPyQt = SalomePyQt.SalomePyQt()
107 mydir=os.environ["SMESH_ROOT_DIR"]
109 QMessageBox.warning(self, "Help", "Help unavailable $SMESH_ROOT_DIR not found")
112 maDoc=mydir+"/share/doc/salome/gui/SMESH/yams/index.html"
113 sgPyQt.helpContext(maDoc,"")
115 #maDoc=mydir+"/share/doc/salome/gui/SMESH/yams/_downloads/mg-surfopt_user_manual.pdf"
116 #command="xdg-open "+maDoc+";"
117 #subprocess.call(command, shell=True)
119 def PBOKPressed(self):
120 if not(self.PrepareLigneCommande()):
122 #QMessageBox.warning(self, "Compute", "Command not found")
124 maFenetre=MonViewText(self,self.commande)
126 def enregistreResultat(self):
129 from salome.kernel import studyedit
130 from salome.smesh import smeshBuilder
131 smesh = smeshBuilder.New(salome.myStudy)
133 if not os.path.isfile(self.fichierOut):
134 QMessageBox.warning(self, "Compute", "Result file "+self.fichierOut+" not found")
136 maStudy=studyedit.getActiveStudy()
137 smesh.SetCurrentStudy(maStudy)
138 (outputMesh, status) = smesh.CreateMeshesFromGMF(self.fichierOut)
139 name=str(self.LE_MeshSmesh.text())
141 initialMeshObject=None
143 a=str(self.fichierIn)
144 name=os.path.basename(os.path.splitext(a)[0])
147 initialMeshObject=maStudy.FindObjectByName(name ,"SMESH")[0]
149 meshname = name+"_YAMS_"+str(self.num)
150 smesh.SetName(outputMesh.GetMesh(), meshname)
151 outputMesh.Compute() #no algorithms message for "Mesh_x" has been computed with warnings: - global 1D algorithm is missing
153 self.editor = studyedit.getStudyEditor()
154 moduleEntry=self.editor.findOrCreateComponent("SMESH","SMESH")
155 HypReMeshEntry = self.editor.findOrCreateItem(
156 moduleEntry, name = "Plugins Hypotheses", icon="mesh_tree_hypo.png") #, comment = "HypoForRemeshing" )
158 monStudyBuilder=maStudy.NewBuilder()
159 monStudyBuilder.NewCommand()
160 newStudyIter=monStudyBuilder.NewObject(HypReMeshEntry)
161 self.editor.setAttributeValue(newStudyIter, "AttributeName", "YAMS Parameters_"+str(self.num))
162 self.editor.setAttributeValue(newStudyIter, "AttributeComment", self.getResumeData(separator=" ; "))
164 SOMesh=maStudy.FindObjectByName(meshname ,"SMESH")[0]
166 if initialMeshFile!=None:
167 newStudyFileName=monStudyBuilder.NewObject(SOMesh)
168 self.editor.setAttributeValue(newStudyFileName, "AttributeName", "meshFile")
169 self.editor.setAttributeValue(newStudyFileName, "AttributeExternalFileDef", initialMeshFile)
170 self.editor.setAttributeValue(newStudyFileName, "AttributeComment", initialMeshFile)
172 if initialMeshObject!=None:
173 newLink=monStudyBuilder.NewObject(SOMesh)
174 monStudyBuilder.Addreference(newLink, initialMeshObject)
176 newLink=monStudyBuilder.NewObject(SOMesh)
177 monStudyBuilder.Addreference(newLink, newStudyIter)
179 if salome.sg.hasDesktop(): salome.sg.updateObjBrowser(0)
183 def PBSavePressed(self):
184 from datetime import datetime
185 if not(self.PrepareLigneCommande()): return
186 text = "# YAMS hypothesis parameters\n"
187 text += "# Params for mesh : " + self.LE_MeshSmesh.text() +"\n"
188 text += datetime.now().strftime("# Date : %d/%m/%y %H:%M:%S\n")
189 text += "# Command : "+self.commande+"\n"
190 text += self.getResumeData(separator="\n")
194 f=open(self.paramsFile,"a")
196 QMessageBox.warning(self, "File", "Unable to open "+self.paramsFile)
201 QMessageBox.warning(self, "File", "Unable to write "+self.paramsFile)
205 def PBSaveHypPressed(self):
206 """save hypothesis in Object Browser"""
209 from salome.kernel import studyedit
210 from salome.smesh import smeshBuilder
211 smesh = smeshBuilder.New(salome.myStudy)
213 maStudy=studyedit.getActiveStudy()
214 smesh.SetCurrentStudy(maStudy)
216 self.editor = studyedit.getStudyEditor()
217 moduleEntry=self.editor.findOrCreateComponent("SMESH","SMESH")
218 HypReMeshEntry = self.editor.findOrCreateItem(
219 moduleEntry, name = "Plugins Hypotheses", icon="mesh_tree_hypo.png") #, comment = "HypoForRemeshing" )
221 monStudyBuilder=maStudy.NewBuilder()
222 monStudyBuilder.NewCommand()
223 newStudyIter=monStudyBuilder.NewObject(HypReMeshEntry)
224 self.editor.setAttributeValue(newStudyIter, "AttributeName", "YAMS Parameters_"+str(self.num))
225 self.editor.setAttributeValue(newStudyIter, "AttributeComment", self.getResumeData(separator=" ; "))
227 if salome.sg.hasDesktop(): salome.sg.updateObjBrowser(0)
231 def SP_toStr(self, widget):
232 """only for a QLineEdit widget"""
233 #cr, pos=widget.validator().validate(res, 0) #n.b. "1,3" is acceptable !locale!
235 val=float(widget.text())
237 QMessageBox.warning(self, widget.titleForWarning, "float value is incorrect: '"+widget.text()+"'")
238 res=str(widget.validator().bottom())
239 widget.setProperty("text", res)
241 valtest=widget.validator().bottom()
244 QMessageBox.warning(self, widget.titleForWarning, "float value is under minimum: "+str(val)+" < "+str(valtest))
246 widget.setProperty("text", res)
248 valtest=widget.validator().top()
251 QMessageBox.warning(self, widget.titleForWarning, "float value is over maximum: "+str(val)+" > "+str(valtest))
253 widget.setProperty("text", res)
257 def getResumeData(self, separator="\n"):
259 for RB in self.GBOptim.findChildren(QRadioButton,):
260 if RB.isChecked()==True:
261 text+="Optimisation="+RB.text()+separator
263 if self.RB_Absolute.isChecked():
264 text+="Units=absolute"+separator
266 text+="Units=relative"+separator
267 v=self.SP_toStr(self.SP_Tolerance)
268 text+="ChordalToleranceDeviation="+v+separator
269 text+="RidgeDetection="+str(self.CB_Ridge.isChecked())+separator
270 text+="SplitEdge="+str(self.CB_SplitEdge.isChecked())+separator
271 text+="PointSmoothing="+str(self.CB_Point.isChecked())+separator
272 text+="GeometricalApproximation="+str(self.SP_Geomapp.value())+separator
273 text+="RidgeAngle="+str(self.SP_Ridge.value())+separator
274 text+="MaximumSize="+str(self.SP_MaxSize.value())+separator
275 text+="MinimumSize="+str(self.SP_MinSize.value())+separator
276 text+="MeshGradation="+str(self.SP_Gradation.value())+separator
277 text+="Verbosity="+str(self.SP_Verbosity.value())+separator
278 text+="Memory="+str(self.SP_Memory.value())+separator
281 def loadResumeData(self, hypothesis, separator="\n"):
284 for slig in reversed(text.split(separator)):
286 #print "load ResumeData",lig
287 if lig=="": continue #skip blanck lines
288 if lig[0]=="#": break
290 tit,value=lig.split("=")
291 if tit=="Optimisation":
292 #no need: exlusives QRadioButton
293 #for RB in self.GBOptim.findChildren(QRadioButton,):
294 # RB.setChecked(False)
295 for RB in self.GBOptim.findChildren(QRadioButton,):
296 if RB.text()==value :
300 if value=="absolute":
301 self.RB_Absolute.setChecked(True)
302 self.RB_Relative.setChecked(False)
304 self.RB_Absolute.setChecked(False)
305 self.RB_Relative.setChecked(True)
306 if tit=="ChordalToleranceDeviation": self.SP_Tolerance.setProperty("text", float(value))
307 if tit=="RidgeDetection": self.CB_Ridge.setChecked(value=="True")
308 if tit=="SplitEdge": self.CB_SplitEdge.setChecked(value=="True")
309 if tit=="PointSmoothing": self.CB_Point.setChecked(value=="True")
310 if tit=="GeometricalApproximation": self.SP_Geomapp.setProperty("value", float(value))
311 if tit=="RidgeAngle": self.SP_Ridge.setProperty("value", float(value))
312 if tit=="MaximumSize": self.SP_MaxSize.setProperty("value", float(value))
313 if tit=="MinimumSize": self.SP_MinSize.setProperty("value", float(value))
314 if tit=="MeshGradation": self.SP_Gradation.setProperty("value", float(value))
315 if tit=="Verbosity": self.SP_Verbosity.setProperty("value", int(float(value)))
316 if tit=="Memory": self.SP_Memory.setProperty("value", float(value))
318 QMessageBox.warning(self, "load YAMS Hypothesis", "Problem on '"+lig+"'")
320 def PBLoadPressed(self):
321 """load last hypothesis saved in tail of file"""
323 f=open(self.paramsFile,"r")
325 QMessageBox.warning(self, "File", "Unable to open "+self.paramsFile)
330 QMessageBox.warning(self, "File", "Unable to read "+self.paramsFile)
333 self.loadResumeData(text, separator="\n")
335 def PBLoadHypPressed(self):
336 """load hypothesis saved in Object Browser"""
337 #QMessageBox.warning(self, "load Object Browser YAMS hypothesis", "TODO")
339 from salome.kernel import studyedit
340 from salome.smesh.smeshstudytools import SMeshStudyTools
341 from salome.gui import helper as guihelper
342 from omniORB import CORBA
344 mySObject, myEntry = guihelper.getSObjectSelected()
345 if CORBA.is_nil(mySObject) or mySObject==None:
346 QMessageBox.critical(self, "Hypothese", "select an Object Browser YAMS hypothesis")
349 text=mySObject.GetComment()
352 if "Optimisation=" not in text:
353 QMessageBox.critical(self, "Load Hypothese", "Object Browser selection not a YAMS Hypothesis")
355 self.loadResumeData(text, separator=" ; ")
358 def PBCancelPressed(self):
361 def PBMeshFilePressed(self):
362 fd = QFileDialog(self, "select an existing Mesh file", self.LE_MeshFile.text(), "Mesh-Files (*.mesh);;All Files (*)")
364 infile = fd.selectedFiles()[0]
365 self.LE_MeshFile.setText(infile)
366 self.fichierIn=unicode(infile).encode("latin-1")
368 self.LE_MeshSmesh.setText("")
370 def setParamsFileName(self):
371 fd = QFileDialog(self, "select a file", self.LE_ParamsFile.text(), "dat Files (*.dat);;All Files (*)")
373 infile = fd.selectedFiles()[0]
374 self.LE_ParamsFile.setText(infile)
375 self.paramsFile=unicode(infile).encode("latin-1")
377 def meshFileNameChanged(self):
378 self.fichierIn=str(self.LE_MeshFile.text())
379 #print "meshFileNameChanged", self.fichierIn
380 if os.path.exists(self.fichierIn):
381 self.__selectedMesh=None
383 self.LE_MeshSmesh.setText("")
385 QMessageBox.warning(self, "Mesh file", "File doesn't exist")
387 def meshSmeshNameChanged(self):
388 """only change by GUI mouse selection, otherwise clear"""
389 self.__selectedMesh = None
391 self.LE_MeshSmesh.setText("")
395 def paramsFileNameChanged(self):
396 self.paramsFile=self.LE_ParamsFile.text()
398 def PBMeshSmeshPressed(self):
399 from omniORB import CORBA
401 from salome.kernel import studyedit
402 from salome.smesh.smeshstudytools import SMeshStudyTools
403 from salome.gui import helper as guihelper
404 from salome.smesh import smeshBuilder
405 smesh = smeshBuilder.New(salome.myStudy)
407 mySObject, myEntry = guihelper.getSObjectSelected()
408 if CORBA.is_nil(mySObject) or mySObject==None:
409 #QMessageBox.critical(self, "Mesh", "select an input mesh")
410 self.LE_MeshSmesh.setText("")
412 self.LE_MeshFile.setText("")
415 self.smeshStudyTool = SMeshStudyTools()
417 self.__selectedMesh = self.smeshStudyTool.getMeshObjectFromSObject(mySObject)
419 QMessageBox.critical(self, "Mesh", "select an input mesh")
421 if CORBA.is_nil(self.__selectedMesh):
422 QMessageBox.critical(self, "Mesh", "select an input mesh")
424 myName = mySObject.GetName()
425 #print "MeshSmeshNameChanged", myName
427 self.LE_MeshSmesh.setText(myName)
428 self.LE_MeshFile.setText("")
431 def prepareFichier(self):
432 self.fichierIn=tempfile.mktemp(suffix=".meshb",prefix="ForSurfOpt_")
433 if os.path.exists(self.fichierIn):
434 os.remove(self.fichierIn)
435 self.__selectedMesh.ExportGMF(self.__selectedMesh, self.fichierIn, True)
437 def PrepareLigneCommande(self):
438 if self.fichierIn=="" and self.MeshIn=="":
439 QMessageBox.critical(self, "Mesh", "select an input mesh")
441 if self.__selectedMesh!=None: self.prepareFichier()
442 if not (os.path.isfile(self.fichierIn)):
443 QMessageBox.critical(self, "File", "unable to read GMF Mesh in "+str(self.fichierIn))
446 self.commande="mg-surfopt.exe"
448 for obj in self.GBOptim.findChildren(QRadioButton,):
451 self.style=obj.objectName().remove(0,3)
452 self.style.replace("_","-")
457 style = unicode(self.style).encode("latin-1")
458 # Translation of old Yams options to new MG-SurfOpt options
460 self.commande+= " --optimisation only"
462 self.commande+= " --Hausdorff_like yes"
464 self.commande+= " --enrich no"
466 self.commande+= " --Hausdorff_like yes --enrich no"
468 self.commande+= " --uniform_flat_subdivision yes"
470 self.commande+= " --sand_paper yes"
472 self.commande+= " -O G" # This option has not been updated to the new option style yet
474 deb=os.path.splitext(self.fichierIn)
475 self.fichierOut=deb[0] + "_output.meshb"
477 tolerance=self.SP_toStr(self.SP_Tolerance)
478 if not self.RB_Absolute.isChecked():
480 self.commande+=" --chordal_error %s"%tolerance
482 if self.CB_Ridge.isChecked() == False : self.commande+=" --compute_ridges no"
483 if self.CB_Point.isChecked() == False : self.commande+=" --optimisation no"
484 if self.CB_SplitEdge.isChecked()== True : self.commande+=" --element_order quadratic"
485 if self.SP_Geomapp.value() != 15.0 : self.commande+=" --geometric_approximation_angle %f"%self.SP_Geomapp.value()
486 if self.SP_Ridge.value() != 45.0 : self.commande+=" --ridge_angle %f"%self.SP_Ridge.value()
487 if self.SP_MaxSize.value() != 100 : self.commande+=" --max_size %f" %self.SP_MaxSize.value()
488 if self.SP_MinSize.value() != 5 : self.commande+=" --min_size %f" %self.SP_MinSize.value()
489 if self.SP_Gradation.value() != 1.3 : self.commande+=" --gradation %f" %self.SP_Gradation.value()
490 if self.SP_Memory.value() != 0 : self.commande+=" --max_memory %d" %self.SP_Memory.value()
491 if self.SP_Verbosity.value() != 3 : self.commande+=" --verbose %d" %self.SP_Verbosity.value()
493 self.commande+=" --in " + self.fichierIn
494 self.commande+=" --out " + self.fichierOut
500 self.RB_0.setChecked(True)
501 #no need: exlusives QRadioButton
502 #self.RB_G.setChecked(False)
503 #self.RB_U.setChecked(False)
504 #self.RB_S.setChecked(False)
505 #self.RB_2.setChecked(False)
506 #self.RB_1.setChecked(False)
507 self.RB_Relative.setChecked(True)
508 #no need: exlusives QRadioButton
509 #self.RB_Absolute.setChecked(False)
510 self.SP_Tolerance.setProperty("text", "0.001")
511 self.SP_Geomapp.setProperty("value", 15.0)
512 self.SP_Ridge.setProperty("value", 45.0)
513 self.SP_Gradation.setProperty("value", 1.3)
514 self.CB_Ridge.setChecked(True)
515 self.CB_Point.setChecked(True)
516 self.CB_SplitEdge.setChecked(False)
517 self.SP_MaxSize.setProperty("value", 100)
518 self.SP_MinSize.setProperty("value", 5)
519 self.SP_Verbosity.setProperty("value", 3)
520 self.SP_Memory.setProperty("value", 0)
521 self.PBMeshSmeshPressed()
522 self.TWOptions.setCurrentIndex(0) # Reset current active tab to the first tab
527 This function returns a singleton instance of the plugin dialog.
528 It is mandatory in order to call show without a parent ...
532 __dialog = MonYamsPlugDialog()
538 # ==============================================================================
539 # Basic use cases and unit test functions
540 # ==============================================================================
542 def TEST_MonYamsPlugDialog():
544 from qtsalome import QApplication
545 app = QApplication(sys.argv)
546 app.lastWindowClosed.connect(app.quit)
548 dlg=MonYamsPlugDialog()
550 sys.exit(app.exec_())
552 if __name__ == "__main__":
553 TEST_MonYamsPlugDialog()