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 *
32 class MonYamsPlugDialog(Ui_YamsPlugDialog,QWidget):
36 QWidget.__init__(self)
38 self.connecterSignaux()
44 self.__selectedMesh=None
46 # complex with 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 "MGSurfOptPlugDialog 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 a rien par le clean
72 self.paramsFile= os.path.abspath(os.path.join(os.environ["HOME"],".MGSurfOpt.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.PB_Cancel.clicked.connect(self.PBCancelPressed)
89 self.PB_Default.clicked.connect(self.clean)
90 self.PB_Help.clicked.connect(self.PBHelpPressed)
91 self.PB_OK.clicked.connect(self.PBOKPressed)
93 self.PB_Load.clicked.connect(self.PBLoadPressed)
94 self.PB_Save.clicked.connect(self.PBSavePressed)
95 self.PB_LoadHyp.clicked.connect(self.PBLoadHypPressed)
96 self.PB_SaveHyp.clicked.connect(self.PBSaveHypPressed)
98 self.PB_MeshFile.clicked.connect(self.PBMeshFilePressed)
99 self.PB_MeshSmesh.clicked.connect(self.PBMeshSmeshPressed)
100 self.LE_MeshSmesh.returnPressed.connect(self.meshSmeshNameChanged)
101 self.PB_ParamsFileExplorer.clicked.connect(self.setParamsFileName)
102 self.LE_MeshFile.returnPressed.connect(self.meshFileNameChanged)
103 self.LE_ParamsFile.returnPressed.connect(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()
135 if not os.path.isfile(self.fichierOut):
136 QMessageBox.warning(self, "Compute", "Result file "+self.fichierOut+" not found")
138 maStudy=salome.myStudy
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+"_MGSO_"+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", "MGSurfOpt 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()
185 def PBSavePressed(self):
186 from datetime import datetime
187 if not(self.PrepareLigneCommande()): return
188 text = "# MGSurfOpt 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_risky(self):
209 save hypothesis in Object Browser outside GEOM ou MESH
210 WARNING: at root of Object Browser is not politically correct
214 if verbose: print("save hypothesis in Object Browser")
217 #how ??? icon = "mesh_tree_hypo.png"
218 namei = "MGSurfOpt Parameters_%i" % self.num
219 datai = self.getResumeData(separator=" ; ")
221 myStudy = salome.myStudy
222 myBuilder = myStudy.NewBuilder()
223 #myStudy.IsStudyLocked()
224 myComponent = myStudy.FindComponent(name)
225 if myComponent == None:
226 print("myComponent not found, create")
227 myComponent = myBuilder.NewComponent(name)
228 AName = myBuilder.FindOrCreateAttribute(myComponent, "AttributeName")
230 ACmt = myBuilder.FindOrCreateAttribute(myComponent, "AttributeComment")
233 myObject = myBuilder.NewObject(myComponent)
234 AName = myBuilder.FindOrCreateAttribute(myObject, "AttributeName")
235 AName.SetValue(namei)
236 ACmt = myBuilder.FindOrCreateAttribute(myObject, "AttributeComment")
239 if salome.sg.hasDesktop(): salome.sg.updateObjBrowser()
241 if verbose: print(("save %s in Object Browser done: %s\n%s" % (name, myObject.GetID(), datai)))
244 def PBSaveHypPressed(self):
246 save hypothesis in Object Browser
247 bug: affichage ne marche pas si inclusion dans dans GEOM ou MESH depuis salome 730
251 from salome.kernel import studyedit
252 from salome.smesh import smeshBuilder
253 #[PAL issue tracker:issue1871] Les nouveaux objets ne s'affichent pas dans SMESH
254 QMessageBox.warning(self, "Save", "waiting for fix: Object Browser will not display hypothesis")
256 if verbose: print("save hypothesis in Object Browser")
257 smesh = smeshBuilder.New()
259 maStudy=salome.myStudy
262 self.editor = studyedit.getStudyEditor()
263 moduleEntry=self.editor.findOrCreateComponent("SMESH","SMESH")
264 HypReMeshEntry = self.editor.findOrCreateItem(
265 moduleEntry, name = "Plugins Hypotheses", icon="mesh_tree_hypo.png")
266 #, comment = "HypothesisForRemeshing" )
268 monStudyBuilder=maStudy.NewBuilder()
269 monStudyBuilder.NewCommand()
270 newStudyIter=monStudyBuilder.NewObject(HypReMeshEntry)
271 name = "MGSurfOpt Parameters_%i" % self.num
272 self.editor.setAttributeValue(newStudyIter, "AttributeName", name)
273 data = self.getResumeData(separator=" ; ")
274 self.editor.setAttributeValue(newStudyIter, "AttributeComment", data)
276 if salome.sg.hasDesktop(): salome.sg.updateObjBrowser()
278 if verbose: print(("save %s in Object Browser done:\n%s" % (name, data)))
281 def SP_toStr(self, widget):
282 """only for a QLineEdit widget"""
283 #cr, pos=widget.validator().validate(res, 0) #n.b. "1,3" is acceptable !locale!
285 val=float(widget.text())
287 QMessageBox.warning(self, widget.titleForWarning, "float value is incorrect: '"+widget.text()+"'")
288 res=str(widget.validator().bottom())
289 widget.setProperty("text", res)
291 valtest=widget.validator().bottom()
294 QMessageBox.warning(self, widget.titleForWarning, "float value is under minimum: "+str(val)+" < "+str(valtest))
296 widget.setProperty("text", res)
298 valtest=widget.validator().top()
301 QMessageBox.warning(self, widget.titleForWarning, "float value is over maximum: "+str(val)+" > "+str(valtest))
303 widget.setProperty("text", res)
307 def getResumeData(self, separator="\n"):
309 for RB in self.GBOptim.findChildren(QRadioButton,):
310 if RB.isChecked()==True:
311 text+="Optimisation="+RB.text()+separator
313 if self.RB_Absolute.isChecked():
314 text+="Units=absolute"+separator
316 text+="Units=relative"+separator
317 v=self.SP_toStr(self.SP_Tolerance)
318 text+="ChordalToleranceDeviation="+v+separator
319 text+="RidgeDetection="+str(self.CB_Ridge.isChecked())+separator
320 text+="SplitEdge="+str(self.CB_SplitEdge.isChecked())+separator
321 text+="PointSmoothing="+str(self.CB_Point.isChecked())+separator
322 text+="GeometricalApproximation="+str(self.SP_Geomapp.value())+separator
323 text+="RidgeAngle="+str(self.SP_Ridge.value())+separator
324 text+="MaximumSize="+str(self.SP_MaxSize.value())+separator
325 text+="MinimumSize="+str(self.SP_MinSize.value())+separator
326 text+="MeshGradation="+str(self.SP_Gradation.value())+separator
327 text+="Verbosity="+str(self.SP_Verbosity.value())+separator
328 text+="Memory="+str(self.SP_Memory.value())+separator
331 def loadResumeData(self, hypothesis, separator="\n"):
334 for slig in reversed(text.split(separator)):
336 #print "load ResumeData",lig
337 if lig=="": continue #skip blanck lines
338 if lig[0]=="#": break
340 tit,value=lig.split("=")
341 if tit=="Optimisation":
342 #no need: exlusives QRadioButton
343 #for RB in self.GBOptim.findChildren(QRadioButton,):
344 # RB.setChecked(False)
345 for RB in self.GBOptim.findChildren(QRadioButton,):
346 if RB.text()==value :
350 if value=="absolute":
351 self.RB_Absolute.setChecked(True)
352 self.RB_Relative.setChecked(False)
354 self.RB_Absolute.setChecked(False)
355 self.RB_Relative.setChecked(True)
356 if tit=="ChordalToleranceDeviation": self.SP_Tolerance.setProperty("text", float(value))
357 if tit=="RidgeDetection": self.CB_Ridge.setChecked(value=="True")
358 if tit=="SplitEdge": self.CB_SplitEdge.setChecked(value=="True")
359 if tit=="PointSmoothing": self.CB_Point.setChecked(value=="True")
360 if tit=="GeometricalApproximation": self.SP_Geomapp.setProperty("value", float(value))
361 if tit=="RidgeAngle": self.SP_Ridge.setProperty("value", float(value))
362 if tit=="MaximumSize": self.SP_MaxSize.setProperty("value", float(value))
363 if tit=="MinimumSize": self.SP_MinSize.setProperty("value", float(value))
364 if tit=="MeshGradation": self.SP_Gradation.setProperty("value", float(value))
365 if tit=="Verbosity": self.SP_Verbosity.setProperty("value", int(float(value)))
366 if tit=="Memory": self.SP_Memory.setProperty("value", float(value))
368 QMessageBox.warning(self, "load MGSurfOpt Hypothesis", "Problem on '"+lig+"'")
370 def PBLoadPressed(self):
371 """load last hypothesis saved in tail of file"""
373 f=open(self.paramsFile,"r")
375 QMessageBox.warning(self, "File", "Unable to open "+self.paramsFile)
380 QMessageBox.warning(self, "File", "Unable to read "+self.paramsFile)
383 self.loadResumeData(text, separator="\n")
385 def PBLoadHypPressed(self):
386 """load hypothesis saved in Object Browser"""
387 #QMessageBox.warning(self, "load Object Browser MGSurfOpt hypothesis", "TODO")
389 from salome.kernel import studyedit
390 from salome.smesh.smeshstudytools import SMeshStudyTools
391 from salome.gui import helper as guihelper
392 from omniORB import CORBA
394 mySObject, myEntry = guihelper.getSObjectSelected()
395 if CORBA.is_nil(mySObject) or mySObject==None:
396 QMessageBox.critical(self, "Hypothese", "select an Object Browser MGSurfOpt hypothesis")
399 text=mySObject.GetComment()
402 if "Optimisation=" not in text:
403 QMessageBox.critical(self, "Load Hypothese", "Object Browser selection not a MGSurfOptHypothesis")
405 self.loadResumeData(text, separator=" ; ")
408 def PBCancelPressed(self):
411 def PBMeshFilePressed(self):
412 fd = QFileDialog(self, "select an existing Mesh file", self.LE_MeshFile.text(), "Mesh-Files (*.mesh);;All Files (*)")
414 infile = fd.selectedFiles()[0]
415 self.LE_MeshFile.setText(infile)
416 self.fichierIn=str(infile).encode("latin-1")
418 self.LE_MeshSmesh.setText("")
420 def setParamsFileName(self):
421 fd = QFileDialog(self, "select a file", self.LE_ParamsFile.text(), "dat Files (*.dat);;All Files (*)")
423 infile = fd.selectedFiles()[0]
424 self.LE_ParamsFile.setText(infile)
425 self.paramsFile=str(infile).encode("latin-1")
427 def meshFileNameChanged(self):
428 self.fichierIn=str(self.LE_MeshFile.text())
429 #print "meshFileNameChanged", self.fichierIn
430 if os.path.exists(self.fichierIn):
431 self.__selectedMesh=None
433 self.LE_MeshSmesh.setText("")
435 QMessageBox.warning(self, "Mesh file", "File doesn't exist")
437 def meshSmeshNameChanged(self):
438 """only change by GUI mouse selection, otherwise clear"""
439 self.__selectedMesh = None
441 self.LE_MeshSmesh.setText("")
445 def paramsFileNameChanged(self):
446 self.paramsFile=self.LE_ParamsFile.text()
448 def PBMeshSmeshPressed(self):
449 from omniORB import CORBA
451 from salome.kernel import studyedit
452 from salome.smesh.smeshstudytools import SMeshStudyTools
453 from salome.gui import helper as guihelper
454 from salome.smesh import smeshBuilder
455 smesh = smeshBuilder.New()
457 mySObject, myEntry = guihelper.getSObjectSelected()
458 if CORBA.is_nil(mySObject) or mySObject==None:
459 QMessageBox.critical(self, "Mesh", "select an input mesh")
460 #self.LE_MeshSmesh.setText("")
462 #self.LE_MeshFile.setText("")
465 self.smeshStudyTool = SMeshStudyTools()
467 self.__selectedMesh = self.smeshStudyTool.getMeshObjectFromSObject(mySObject)
469 QMessageBox.critical(self, "Mesh", "select an input mesh")
471 if CORBA.is_nil(self.__selectedMesh):
472 QMessageBox.critical(self, "Mesh", "select an input mesh")
474 myName = mySObject.GetName()
475 #print "MeshSmeshNameChanged", myName
477 self.LE_MeshSmesh.setText(myName)
478 self.LE_MeshFile.setText("")
481 def prepareFichier(self):
482 self.fichierIn=tempfile.mktemp(suffix=".mesh",prefix="ForSurfOpt_")
483 if os.path.exists(self.fichierIn):
484 os.remove(self.fichierIn)
485 self.__selectedMesh.ExportGMF(self.__selectedMesh, self.fichierIn, True)
487 def PrepareLigneCommande(self):
488 if self.fichierIn=="" and self.MeshIn=="":
489 QMessageBox.critical(self, "Mesh", "select an input mesh")
491 if self.__selectedMesh!=None: self.prepareFichier()
492 if not (os.path.isfile(self.fichierIn)):
493 QMessageBox.critical(self, "File", "unable to read GMF Mesh in "+str(self.fichierIn))
496 self.commande="mg-surfopt.exe"
498 for obj in self.GBOptim.findChildren(QRadioButton,):
501 self.style=obj.objectName().remove(0,3)
502 self.style.replace("_","-")
507 style = str(self.style).encode("latin-1")
508 # Translation of old Yams options to new MG-SurfOpt options
510 self.commande+= " --optimisation only"
512 self.commande+= " --Hausdorff_like yes"
514 self.commande+= " --enrich no"
516 self.commande+= " --Hausdorff_like yes --enrich no"
518 self.commande+= " --uniform_flat_subdivision yes"
520 self.commande+= " --sand_paper yes"
522 self.commande+= " -O G" # This option has not been updated to the new option style yet
524 deb=os.path.splitext(self.fichierIn)
525 self.fichierOut=deb[0] + "_output.mesh"
527 tolerance=self.SP_toStr(self.SP_Tolerance)
528 if not self.RB_Absolute.isChecked():
530 self.commande+=" --chordal_error %s"%tolerance
532 if self.CB_Ridge.isChecked() == False : self.commande+=" --compute_ridges no"
533 if self.CB_Point.isChecked() == False : self.commande+=" --optimisation no"
534 if self.CB_SplitEdge.isChecked()== True : self.commande+=" --element_order quadratic"
535 if self.SP_Geomapp.value() != 15.0 : self.commande+=" --geometric_approximation_angle %f"%self.SP_Geomapp.value()
536 if self.SP_Ridge.value() != 45.0 : self.commande+=" --ridge_angle %f"%self.SP_Ridge.value()
537 if self.SP_MaxSize.value() != 100 : self.commande+=" --max_size %f" %self.SP_MaxSize.value()
538 if self.SP_MinSize.value() != 5 : self.commande+=" --min_size %f" %self.SP_MinSize.value()
539 if self.SP_Gradation.value() != 1.3 : self.commande+=" --gradation %f" %self.SP_Gradation.value()
540 if self.SP_Memory.value() != 0 : self.commande+=" --max_memory %d" %self.SP_Memory.value()
541 if self.SP_Verbosity.value() != 3 : self.commande+=" --verbose %d" %self.SP_Verbosity.value()
543 self.commande+=" --in " + self.fichierIn
544 self.commande+=" --out " + self.fichierOut
550 self.RB_0.setChecked(True)
551 #no need: exlusives QRadioButton
552 #self.RB_G.setChecked(False)
553 #self.RB_U.setChecked(False)
554 #self.RB_S.setChecked(False)
555 #self.RB_2.setChecked(False)
556 #self.RB_1.setChecked(False)
557 self.RB_Relative.setChecked(True)
558 #no need: exlusives QRadioButton
559 #self.RB_Absolute.setChecked(False)
560 self.SP_Tolerance.setProperty("text", "0.001")
561 self.SP_Geomapp.setProperty("value", 15.0)
562 self.SP_Ridge.setProperty("value", 45.0)
563 self.SP_Gradation.setProperty("value", 1.3)
564 self.CB_Ridge.setChecked(True)
565 self.CB_Point.setChecked(True)
566 self.CB_SplitEdge.setChecked(False)
567 self.SP_MaxSize.setProperty("value", 100)
568 self.SP_MinSize.setProperty("value", 5)
569 self.SP_Verbosity.setProperty("value", 3)
570 self.SP_Memory.setProperty("value", 0)
571 #self.PBMeshSmeshPressed() #do not that! problem if done in load surfopt hypo from object browser
572 self.TWOptions.setCurrentIndex(0) # Reset current active tab to the first tab
577 This function returns a singleton instance of the plugin dialog.
578 It is mandatory in order to call show without a parent ...
582 __dialog = MonYamsPlugDialog()
588 # ==============================================================================
589 # Basic use cases and unit test functions
590 # ==============================================================================
592 def TEST_MonYamsPlugDialog():
594 from qtsalome import QApplication
595 app = QApplication(sys.argv)
596 app.lastWindowClosed.connect(app.quit)
598 dlg=MonYamsPlugDialog()
600 sys.exit(app.exec_())
602 if __name__ == "__main__":
603 TEST_MonYamsPlugDialog()