From 1746a461949c030eb46ccb860e586ade2e5de5e3 Mon Sep 17 00:00:00 2001 From: Paul RASCLE Date: Thu, 24 Nov 2016 19:00:44 +0100 Subject: [PATCH] Zcracks plugin adaptation to new Zcracks tool --- src/Tools/ZCracksPlug/CMakeLists.txt | 36 +- src/Tools/ZCracksPlug/Zset.py | 140 + src/Tools/ZCracksPlug/__init__.py | 76 + src/Tools/ZCracksPlug/casTests/CMakeLists.txt | 32 + src/Tools/ZCracksPlug/casTests/__init__.py | 0 src/Tools/ZCracksPlug/casTests/genereCube.py | 197 + src/Tools/ZCracksPlug/casTests/launchCas.py | 277 + .../ZCracksPlug/casTests/launchManuel.py | 27 + src/Tools/ZCracksPlug/ellipse.py | 202 + src/Tools/ZCracksPlug/genereCrack.py | 235 + src/Tools/ZCracksPlug/images.qrc | 7 + src/Tools/ZCracksPlug/images/Rectangle.svg | 1082 +++ src/Tools/ZCracksPlug/images/Sphere.svg | 614 ++ src/Tools/ZCracksPlug/images/big_loader.gif | Bin 0 -> 4874 bytes .../ZCracksPlug/images/schema_ellipse.png | Bin 0 -> 53055 bytes .../ZCracksPlug/images/schema_rectangle.png | Bin 0 -> 43996 bytes .../ZCracksPlug/images/schema_shpere.png | Bin 0 -> 23230 bytes src/Tools/ZCracksPlug/images_rc.py | 7580 +++++++++++++++++ src/Tools/ZCracksPlug/main.py | 514 ++ src/Tools/ZCracksPlug/output.py | 53 + src/Tools/ZCracksPlug/readme.sh | 6 + src/Tools/ZCracksPlug/rectangle.py | 226 + src/Tools/ZCracksPlug/sphere.py | 70 + src/Tools/ZCracksPlug/utilityFunctions.py | 485 ++ src/Tools/ZCracksPlug/zcracks.js | 0 src/Tools/ZCracksPlug/zcracks.pro | 2 + src/Tools/ZCracksPlug/zcracks.pro.user | 160 + src/Tools/ZCracksPlug/zcracks.ui | 1726 ++++ src/Tools/ZCracksPlug/zcracksLaunch.py | 5 + src/Tools/ZCracksPlug/zcracks_plugin.py | 25 +- src/Tools/ZCracksPlug/zcracks_ui.py | 738 ++ src/Tools/smesh_plugins.py | 20 +- 32 files changed, 14504 insertions(+), 31 deletions(-) create mode 100644 src/Tools/ZCracksPlug/Zset.py create mode 100644 src/Tools/ZCracksPlug/__init__.py create mode 100644 src/Tools/ZCracksPlug/casTests/CMakeLists.txt create mode 100644 src/Tools/ZCracksPlug/casTests/__init__.py create mode 100644 src/Tools/ZCracksPlug/casTests/genereCube.py create mode 100644 src/Tools/ZCracksPlug/casTests/launchCas.py create mode 100644 src/Tools/ZCracksPlug/casTests/launchManuel.py create mode 100644 src/Tools/ZCracksPlug/ellipse.py create mode 100644 src/Tools/ZCracksPlug/genereCrack.py create mode 100644 src/Tools/ZCracksPlug/images.qrc create mode 100644 src/Tools/ZCracksPlug/images/Rectangle.svg create mode 100644 src/Tools/ZCracksPlug/images/Sphere.svg create mode 100644 src/Tools/ZCracksPlug/images/big_loader.gif create mode 100644 src/Tools/ZCracksPlug/images/schema_ellipse.png create mode 100644 src/Tools/ZCracksPlug/images/schema_rectangle.png create mode 100644 src/Tools/ZCracksPlug/images/schema_shpere.png create mode 100644 src/Tools/ZCracksPlug/images_rc.py create mode 100644 src/Tools/ZCracksPlug/main.py create mode 100644 src/Tools/ZCracksPlug/output.py create mode 100644 src/Tools/ZCracksPlug/readme.sh create mode 100644 src/Tools/ZCracksPlug/rectangle.py create mode 100644 src/Tools/ZCracksPlug/sphere.py create mode 100644 src/Tools/ZCracksPlug/utilityFunctions.py create mode 100644 src/Tools/ZCracksPlug/zcracks.js create mode 100644 src/Tools/ZCracksPlug/zcracks.pro create mode 100644 src/Tools/ZCracksPlug/zcracks.pro.user create mode 100644 src/Tools/ZCracksPlug/zcracks.ui create mode 100755 src/Tools/ZCracksPlug/zcracksLaunch.py create mode 100644 src/Tools/ZCracksPlug/zcracks_ui.py diff --git a/src/Tools/ZCracksPlug/CMakeLists.txt b/src/Tools/ZCracksPlug/CMakeLists.txt index fabf877a5..288b9d783 100644 --- a/src/Tools/ZCracksPlug/CMakeLists.txt +++ b/src/Tools/ZCracksPlug/CMakeLists.txt @@ -17,19 +17,43 @@ # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # -IF(SALOME_BUILD_DOC) - ADD_SUBDIRECTORY(doc) -ENDIF(SALOME_BUILD_DOC) +ADD_SUBDIRECTORY(casTests) + +INCLUDE(UsePyQt) # --- scripts --- # scripts / static SET(plugin_SCRIPTS - zcracks_plugin.py + __init__.py + ellipse.py + genereCrack.py + images_rc.py + main.py + output.py + rectangle.py + sphere.py + utilityFunctions.py + zcracks_plugin.py + Zset.py ) +SET(command_SCRIPTS + zcracksLaunch.py +) -# --- rules --- +# --- resources --- -SALOME_INSTALL_SCRIPTS("${plugin_SCRIPTS}" ${SALOME_SMESH_INSTALL_PLUGINS}) +# uic files / to be processed by pyuic +SET(_pyuic_files + zcracks.ui +) + +# scripts / pyuic wrappings +PYQT_WRAP_UIC(_pyuic_SCRIPTS ${_pyuic_files}) + +# --- rules --- +SALOME_INSTALL_SCRIPTS("${plugin_SCRIPTS}" ${SALOME_INSTALL_PYTHON}/Zcracks) +SALOME_INSTALL_SCRIPTS("${_pyuic_SCRIPTS}" ${SALOME_INSTALL_PYTHON}/Zcracks) +SALOME_INSTALL_SCRIPTS("${command_SCRIPTS}" ${SALOME_INSTALL_BINS}) diff --git a/src/Tools/ZCracksPlug/Zset.py b/src/Tools/ZCracksPlug/Zset.py new file mode 100644 index 000000000..464619e2b --- /dev/null +++ b/src/Tools/ZCracksPlug/Zset.py @@ -0,0 +1,140 @@ + +import os, tempfile, shutil +import utilityFunctions as uF +from output import message + +def medToGeo(medFile, geoFile, tmpdir, opt=[], verbose=0): + medLoc=os.path.dirname(medFile) + medName=os.path.basename(medFile) + inpFile=os.path.join(tmpdir,'import.inp') + zfile = open(inpFile,'w') + zfile.write('****mesher\n') + zfile.write(' ***mesh %s\n' %(geoFile.replace('.geo','')+'.geo')) + zfile.write(' **import med %s\n' %medName) + for x in opt: + zfile.write(x+'\n') + zfile.write('****return\n') + zfile.close() + commande='cd %s; Zrun -m %s' %(medLoc,inpFile) + if verbose!=0: commande+=' >> %s' %os.path.join(tmpdir,'log.msg') + res=os.system(commande) + + return(res) + + #os.remove(inpFile) + + +def geoToMed(medFile, geoFile, tmpdir, opt=[], verbose=0): + medLoc=os.path.dirname(medFile) + medName=os.path.basename(medFile) + inpFile=os.path.join(tmpdir,'export.inp') + zfile = open(inpFile,'w') + zfile.write('****mesher\n') + zfile.write(' ***mesh\n') + zfile.write(' **open %s\n' %geoFile) + for x in opt: + zfile.write(x+'\n') + zfile.write(' **export med %s\n' %medName) + zfile.write('****return\n') + zfile.close() + commande='cd %s; Zrun -m %s' %(medLoc,inpFile) + if verbose!=0: commande+=' >> %s' %os.path.join(tmpdir,'log.msg') + res=os.system(commande) + #print ' -------- ' + #print res + #print ' -------- ' + return(res) + + +def launchZcrack(minS, maxS, + saneN, crackN, crackedN, + grad, quad, extrL, + nbLay, nbIter, + Gvol, Gfac, Gedg, Gnod, + surfOpt, tmpdir, cas2D, refine, verbose=0, ): + + zfile = open(os.path.join(tmpdir,'insert.z7p'),'w') + zfile.write(' #include \n') + zfile.write(' int main()\n{\n') + zfile.write(' init_var();\n') + + if cas2D==True: + zfile.write(' if_2D=1;\n') + zfile.write(' thickness.resize(1);\n') + zfile.write(' thickness[0]=-1.;\n') + + zfile.write(' format="geo";\n') + zfile.write(' gradation=%e;\n' %grad) + zfile.write(' min_size= %e;\n' %minS) + zfile.write(' max_size=%e;\n' %maxS) + zfile.write(' nb_velem=%d;\n' %(nbLay*2)) + zfile.write(' nb_iter=%d;\n' %nbIter) + zfile.write(' sane_name="%s";\n' %saneN.replace('.geo','')) + #zfile.write(' crack_name="%s";\n' %crackN.replace('.geo','')) + zfile.write(' convert_surface("%s");\n' %crackN.replace('.geo','')) + zfile.write(' cracked_name="%s";\n' %crackedN.replace('.geo','')) + + if Gfac!='': zfile.write(' faset_names="%s";\n' %(Gfac[0] if type(Gfac)==list else Gfac)) + if Gnod!='': zfile.write(' nset_names="%s";\n' %(Gnod[0] if type(Gnod)==list else Gnod)) + if Gvol!='': zfile.write(' elset_names="%s";\n' %(Gvol[0] if type(Gvol)==list else Gvol)) + if Gedg!='': zfile.write(' liset_names="%s";\n' %(Gedg[0] if type(Gedg)==list else Gedg)) + if surfOpt!='': + zfile.write(' yams_options="%s";\n' %surfOpt) + + if refine: zfile.write(' if_must_refine=1;\n') + + if extrL<=1.E-12: + zfile.write(' if_must_define_elset=0;\n') + else: + zfile.write(' if_must_define_elset=1;\n') + if extrL==[]: + zfile.write(' elset_radius=%e;\n' %maxS) + else: + zfile.write(' elset_radius=%e;\n' %extrL) + + zfile.write(' nice_cut(20.0);\n}\n\n') + zfile.close() + commande='Zrun -zp %s' %(os.path.join(tmpdir,'insert.z7p')) + if verbose!=0: commande+=' >> %s' %os.path.join(tmpdir,'log.msg') + res=os.system(commande) + #print ' -------- ' + #print res + #print ' -------- ' + return(res) + + + +def insertCrack(data, names, tmpdir='./zcracks_temp', verbose=0): + + saneN=names['saneGeoName'] + crackN=names['crackGeoName'] + crackedN=names['crackedGeoName'] + + minS=data['minSize'][0] + maxS=data['maxSize'][0] + extrL=data['extractLength'][0] + + grad = data['gradation'][0] if 'gradation' in data.keys() else 1.3 + quad = data['quad'] if 'quad' in data.keys() else False + cas2D = data['is2D'] if 'is2D' in data.keys() else False + refine = data['refine'] if 'refine' in data.keys() else False + nbLay = data['layers'][0] if 'layers' in data.keys() else 5 + nbIter = data['iterations'][0] if 'iterations' in data.keys() else 2 + + Gvol = data['grVol'] if 'grVol' in data.keys() else '' + Gfac = data['grFace'] if 'grFace' in data.keys() else '' + Gedg = data['grEdge'] if 'grEdge' in data.keys() else '' + Gnod = data['grNodes'] if 'grNodes' in data.keys() else '' + surfOpt = data['surfopt'] if 'surfopt' in data.keys() else '' + + + if not os.path.isdir(tmpdir): os.mkdir(tmpdir) + curDir=os.getcwd() + os.chdir(tmpdir) + res=launchZcrack(minS, maxS, saneN, crackN, crackedN,grad, quad, extrL, + nbLay, nbIter,Gvol, Gfac, Gedg, Gnod,surfOpt, tmpdir, cas2D, refine, verbose) + os.chdir(curDir) + return(res) + + +#def TUI(data, names, tmpdir='./zcracks_temp', verbose=0) diff --git a/src/Tools/ZCracksPlug/__init__.py b/src/Tools/ZCracksPlug/__init__.py new file mode 100644 index 000000000..61ea883f4 --- /dev/null +++ b/src/Tools/ZCracksPlug/__init__.py @@ -0,0 +1,76 @@ +import sys, os, shutil, pickle, tempfile +import main, genereCrack, Zset +import utilityFunctions as uF + +#commande="/bin/bash -c ""source $HOME/zebulon/Z8.6.6_NEW/do_config_bash""" +#os.system(commande) + +def IHM(): + + try: + from PyQt5.QtWidgets import QApplication + except: + from PyQt4.QtGui import QApplication + + app = QApplication(sys.argv) + myapp = main.ShipHolderApplication() + myapp.show() + sys.exit(app.exec_()) + + +def SCRIPT(dataFile=None, data=None, dim=3, names=None): + if dim!=3 and dim!=2: + print 'ERROR' + return(False) + + if dataFile==None and data==None: + print 'One of dataFile or data is mandatory' + return(False) + + if data==None: data=pickle.load(open(dataFile,'r')) + + print data + + tmpdir=tempfile.mkdtemp() + uF.removeFromSessionPath('LD_LIBRARY_PATH', 'Meshgems-2111') + + if names==None: names={'saneGeoName':'salome_sane', 'crackGeoName':'salome_crack', 'crackedGeoName':'salome_cracked'} + + crackedMed=data['crackedName'] + crackMed=os.path.join(tmpdir,'crackMed.med') + saneMed=data['saneName'] + + saneGeo=os.path.join(tmpdir,names['saneGeoName']+'.geo') + crackGeo=os.path.join(tmpdir,names['crackGeoName']+'.geo') + crackedGeo=os.path.join(tmpdir,names['crackedGeoName']+'.geo') + + for f in [crackMed, crackedMed, saneGeo, crackGeo, crackedGeo]: + if os.path.isfile(f): os.remove(f) + + print crackMed + genereCrack.main(data, crackMed) + goOn=os.path.isfile(crackMed) + + if goOn: Zset.medToGeo(crackMed, crackGeo, tmpdir) + goOn=os.path.isfile(crackGeo) + + if dim==3: + if goOn: Zset.medToGeo(saneMed,saneGeo, tmpdir) + elif dim==2: + if goOn: Zset.medToGeo(saneMed,saneGeo, tmpdir, opt=[' **to_3d']) + goOn=os.path.isfile(saneGeo) + + if goOn: Zset.insertCrack(data, names, tmpdir) + goOn=os.path.isfile(crackedGeo) + + if goOn: Zset.geoToMed(crackedMed, crackedGeo, tmpdir) + goOn=os.path.isfile(crackedMed) + + if goOn: maxAR=uF.extendElsets(crackedMed) + + shutil.rmtree(tmpdir) + + return([os.path.isfile(crackedMed), maxAR]) + + + diff --git a/src/Tools/ZCracksPlug/casTests/CMakeLists.txt b/src/Tools/ZCracksPlug/casTests/CMakeLists.txt new file mode 100644 index 000000000..f1fcad706 --- /dev/null +++ b/src/Tools/ZCracksPlug/casTests/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright (C) 2012-2016 EDF R&D +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +# --- scripts --- + +# scripts / static +SET(plugin_SCRIPTS + __init__.py + genereCube.py + launchCas.py + launchManuel.py +) + +# --- rules --- + +SALOME_INSTALL_SCRIPTS("${plugin_SCRIPTS}" ${SALOME_INSTALL_PYTHON}/Zcracks/casTests) diff --git a/src/Tools/ZCracksPlug/casTests/__init__.py b/src/Tools/ZCracksPlug/casTests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/Tools/ZCracksPlug/casTests/genereCube.py b/src/Tools/ZCracksPlug/casTests/genereCube.py new file mode 100644 index 000000000..2ab20472e --- /dev/null +++ b/src/Tools/ZCracksPlug/casTests/genereCube.py @@ -0,0 +1,197 @@ +# -*- coding: utf-8 -*- + +### +### This file is generated automatically by SALOME v7.7.0 with dump python functionality +### + +import salome + +salome.salome_init() +theStudy = salome.myStudy + +import salome_notebook +notebook = salome_notebook.NoteBook(theStudy) + +### +### GEOM component +### + + +#L = 1. +#N = 20 #Nombre d elements sur un cote + +def cube3D(L, N, outFile): + + N=int(N) + from salome.geom import geomBuilder + + geompy = geomBuilder.New(theStudy) + + eps=L*1.e-6 + + O = geompy.MakeVertex(0, 0, 0) + OX = geompy.MakeVectorDXDYDZ(1, 0, 0) + OY = geompy.MakeVectorDXDYDZ(0, 1, 0) + OZ = geompy.MakeVectorDXDYDZ(0, 0, 1) + cube = geompy.MakeBoxDXDYDZ(L, L, L) + geompy.TranslateDXDYDZ(cube, -L/2., -L/2., -L/2.) + + epais=1./(2.*N) + larg=L*1.1 + + boxX = geompy.MakeBoxDXDYDZ(epais, larg, larg) + geompy.TranslateDXDYDZ(boxX, -epais/2., -larg/2., -larg/2.) + boxXM = geompy.TranslateDXDYDZ(boxX, -L/2., 0., 0., theCopy=True) + boxXP = geompy.TranslateDXDYDZ(boxX, L/2., 0., 0., theCopy=True) + + boxY = geompy.MakeBoxDXDYDZ(larg, epais, larg) + geompy.TranslateDXDYDZ(boxY, -larg/2., -epais/2., -larg/2.) + boxYM = geompy.TranslateDXDYDZ(boxY, 0., -L/2., 0., theCopy=True) + boxYP = geompy.TranslateDXDYDZ(boxY, 0., L/2., 0., theCopy=True) + + boxZ = geompy.MakeBoxDXDYDZ(larg, larg, epais) + geompy.TranslateDXDYDZ(boxZ, -larg/2., -larg/2., -epais/2.) + boxZM = geompy.TranslateDXDYDZ(boxZ, 0., 0., -L/2., theCopy=True) + boxZP = geompy.TranslateDXDYDZ(boxZ, 0., 0., L/2., theCopy=True) + + box = geompy.MakeBoxDXDYDZ(larg, larg, larg) + + boxXPLUS = geompy.TranslateDXDYDZ(box, 0., -larg/2., -larg/2., theCopy=True) + boxXMOIN = geompy.TranslateDXDYDZ(box, -larg, -larg/2., -larg/2., theCopy=True) + + boxYPLUS = geompy.TranslateDXDYDZ(box, -larg/2., 0., -larg/2., theCopy=True) + boxYMOIN = geompy.TranslateDXDYDZ(box, -larg/2., -larg, -larg/2., theCopy=True) + + boxZPLUS = geompy.TranslateDXDYDZ(box, -larg/2., -larg/2., 0., theCopy=True) + boxZMOIN = geompy.TranslateDXDYDZ(box, -larg/2., -larg/2., -larg, theCopy=True) + + + from salome.smesh import smeshBuilder + import SMESH + + smesh = smeshBuilder.New(theStudy) + Nb_Segments_1 = smesh.CreateHypothesis('NumberOfSegments') + Nb_Segments_1.SetNumberOfSegments( N ) + Length_From_Edges_1 = smesh.CreateHypothesis('LengthFromEdges') + Regular_1D = smesh.CreateHypothesis('Regular_1D') + NETGEN_2D_ONLY = smesh.CreateHypothesis('NETGEN_2D_ONLY', 'NETGENEngine') + Hexa_3D = smesh.CreateHypothesis('Hexa_3D') + Maillage_1 = smesh.Mesh(cube) + status = Maillage_1.AddHypothesis(Nb_Segments_1) + status = Maillage_1.AddHypothesis(Regular_1D) + Quadrangle_2D = Maillage_1.Quadrangle(algo=smeshBuilder.QUADRANGLE) + status = Maillage_1.AddHypothesis(Hexa_3D) + isDone = Maillage_1.Compute() + + geometries = [boxXPLUS, boxXMOIN, boxYPLUS, boxYMOIN, boxZPLUS, boxZMOIN] + + noms = ['VOLXP', 'VOLXM', 'VOLYP', 'VOLYM', 'VOLZP', 'VOLZM'] + + for cont, geo in enumerate(geometries): + aCriteria = smesh.GetCriterion(SMESH.VOLUME,SMESH.FT_BelongToGeom,SMESH.FT_Undefined, geo) + aFilter_1 = smesh.GetFilterFromCriteria([aCriteria]) + aFilter_1.SetMesh(Maillage_1.GetMesh()) + VOLUME_temp = Maillage_1.GroupOnFilter( SMESH.VOLUME, noms[cont], aFilter_1 ) + + nbAdded, Maillage_1, Group = Maillage_1.MakeBoundaryElements( SMESH.BND_2DFROM3D, '', '', 0, [ VOLUME_temp ]) + + geometries = [boxX, boxXM, boxXP, + boxY, boxYM, boxYP, + boxZ, boxZM, boxZP] + + noms = ['FACEX', 'FACEXM', 'FACEXP', + 'FACEY', 'FACEYM', 'FACEYP', + 'FACEZ', 'FACEZM', 'FACEZP'] + + for cont, geo in enumerate(geometries): + aCriteria = smesh.GetCriterion(SMESH.FACE,SMESH.FT_BelongToGeom,SMESH.FT_Undefined, geo) + aFilter_1 = smesh.GetFilterFromCriteria([aCriteria]) + aFilter_1.SetMesh(Maillage_1.GetMesh()) + FACE_temp = Maillage_1.GroupOnFilter( SMESH.FACE, noms[cont], aFilter_1 ) + + Maillage_1.ExportMED( outFile, 0, SMESH.MED_V2_2, 1, None ,1) + + #if salome.sg.hasDesktop(): + #salome.sg.updateObjBrowser(1) + + + +def cube2D(L, N, outFile): + + N=int(N) + from salome.geom import geomBuilder + + geompy = geomBuilder.New(theStudy) + + eps=L*1.e-6 + + O = geompy.MakeVertex(0, 0, 0) + OX = geompy.MakeVectorDXDYDZ(1, 0, 0) + OY = geompy.MakeVectorDXDYDZ(0, 1, 0) + OZ = geompy.MakeVectorDXDYDZ(0, 0, 1) + face = geompy.MakeFaceHW(L, L, 1) + + epais=1./(2.*N) + larg=L*1.1 + + boxX = geompy.MakeBoxDXDYDZ(epais, larg, epais) + geompy.TranslateDXDYDZ(boxX, -epais/2., -larg/2., -epais/2.) + boxXM = geompy.TranslateDXDYDZ(boxX, -L/2., 0., 0., theCopy=True) + boxXP = geompy.TranslateDXDYDZ(boxX, L/2., 0., 0., theCopy=True) + + boxY = geompy.MakeBoxDXDYDZ(larg, epais, epais) + geompy.TranslateDXDYDZ(boxY, -larg/2., -epais/2., -epais/2.) + boxYM = geompy.TranslateDXDYDZ(boxY, 0., -L/2., 0., theCopy=True) + boxYP = geompy.TranslateDXDYDZ(boxY, 0., L/2., 0., theCopy=True) + + box = geompy.MakeBoxDXDYDZ(larg, larg, epais) + + boxXPLUS = geompy.TranslateDXDYDZ(box, 0., -larg/2., -epais/2., theCopy=True) + boxXMOIN = geompy.TranslateDXDYDZ(box, -larg, -larg/2., -epais/2., theCopy=True) + + boxYPLUS = geompy.TranslateDXDYDZ(box, -larg/2., 0., -epais/2., theCopy=True) + boxYMOIN = geompy.TranslateDXDYDZ(box, -larg/2., -larg, -epais/2., theCopy=True) + + + from salome.smesh import smeshBuilder + import SMESH + + smesh = smeshBuilder.New(theStudy) + Nb_Segments_1 = smesh.CreateHypothesis('NumberOfSegments') + Nb_Segments_1.SetNumberOfSegments( N ) + Length_From_Edges_1 = smesh.CreateHypothesis('LengthFromEdges') + Regular_1D = smesh.CreateHypothesis('Regular_1D') + NETGEN_2D_ONLY = smesh.CreateHypothesis('NETGEN_2D_ONLY', 'NETGENEngine') + Maillage_1 = smesh.Mesh(face) + + status = Maillage_1.AddHypothesis(Nb_Segments_1) + status = Maillage_1.AddHypothesis(Regular_1D) + Quadrangle_2D = Maillage_1.Quadrangle(algo=smeshBuilder.QUADRANGLE) + isDone = Maillage_1.Compute() + + geometries = [boxXPLUS, boxXMOIN, boxYPLUS, boxYMOIN] + + noms = ['FACEXP', 'FACEXM', 'FACEYP', 'FACEYM'] + + for cont, geo in enumerate(geometries): + aCriteria = smesh.GetCriterion(SMESH.FACE,SMESH.FT_BelongToGeom,SMESH.FT_Undefined, geo) + aFilter_1 = smesh.GetFilterFromCriteria([aCriteria]) + aFilter_1.SetMesh(Maillage_1.GetMesh()) + FACE_temp = Maillage_1.GroupOnFilter( SMESH.FACE, noms[cont], aFilter_1 ) + + nbAdded, Maillage_1, Group = Maillage_1.MakeBoundaryElements( SMESH.BND_1DFROM2D, '', '', 0, [ FACE_temp ]) + + geometries = [boxX, boxXM, boxXP, boxY, boxYM, boxYP] + + noms = ['EDGEX', 'EDGEXM', 'EDGEXP', 'EDGEY', 'EDGEYM', 'EDGEYP'] + + for cont, geo in enumerate(geometries): + aCriteria = smesh.GetCriterion(SMESH.EDGE,SMESH.FT_BelongToGeom,SMESH.FT_Undefined, geo) + aFilter_1 = smesh.GetFilterFromCriteria([aCriteria]) + aFilter_1.SetMesh(Maillage_1.GetMesh()) + EDGE_temp = Maillage_1.GroupOnFilter( SMESH.EDGE, noms[cont], aFilter_1 ) + + Maillage_1.ExportMED( outFile, 0, SMESH.MED_V2_2, 1, None ,1) + + #if salome.sg.hasDesktop(): + #salome.sg.updateObjBrowser(1) \ No newline at end of file diff --git a/src/Tools/ZCracksPlug/casTests/launchCas.py b/src/Tools/ZCracksPlug/casTests/launchCas.py new file mode 100644 index 000000000..e4a4d163c --- /dev/null +++ b/src/Tools/ZCracksPlug/casTests/launchCas.py @@ -0,0 +1,277 @@ + +from Zcracks import genereCrack, Zset +from Zcracks import utilityFunctions as uF +import genereCube + +from math import sqrt + + +if False: + import Zcracks + from Zcracks import casTests + from Zcracks.casTests import launchCas + launchCas.LAUNCH(['10']) + +import os, shutil +import tempfile +import string + +#tmpdir = "/local00/home/B27118/projets/Zcracks/Zcracks/casTests/tmpdir" +#if not os.path.isdir(tmpdir): os.mkdir(tmpdir) +tmpdir=tempfile.mktemp(prefix='tmpZcracks') +print "tmpdir=", tmpdir + +meshgemsdir=os.environ('MESHGEMSHOME') +if len(meshgemsdir) > 0: + meshgems=string.split(meshgemsdir,os.sep)[-1] + uF.removeFromSessionPath('LD_LIBRARY_PATH', meshgems) + +def LAUNCH(listCas=[]): + if type(listCas)!=list: listCas=[listCas] + + N=20 + L=1. + te=L/N + offset=te/2. + genereCube.cube3D(L, N, os.path.join(tmpdir,'cube3D.med')) + genereCube.cube2D(L, N, os.path.join(tmpdir,'cube2D.med')) + crack={} + synthese={} + + # -------- # + # CAS 2D # + # -------- # + data={'minSize':[te/10.], 'maxSize':[te], 'extractLength':[2.*te], 'is2D':True, 'crack':crack, + 'grEdge':['EDGEXP EDGEXM EDGEYP EDGEYM']} + + cas='1' + crack['actif']='Ellipse' + crack[crack['actif']]={'Rayon':[L/2.], 'Centre':[L/2., offset, 0.], 'Normale':[0., 1., 0.]} + if cas in listCas or listCas==[]: + synthese[cas]=execute2D(data, cas) + + cas='2' + crack['actif']='Ellipse' + crack[crack['actif']]={'Rayon':[L], 'Centre':[L/2., 0., 0.], 'Normale':[1., 1., 0.]} + if cas in listCas or listCas==[]: + synthese[cas]=execute2D(data, cas) + + cas='3' + crack['actif']='Ellipse' + crack[crack['actif']]={'Rayon':[L*sqrt(2.)], 'Centre':[-L/2., L/2., 0.], 'Normale':[1., 1., 0.]} + if cas in listCas or listCas==[]: + synthese[cas]=execute2D(data, cas) + + cas='4' + crack['actif']='Ellipse' + crack[crack['actif']]={'Rayon':[L/4.], 'Centre':[0., offset, 0.], 'Normale':[0., 1., 0.]} + if cas in listCas or listCas==[]: + synthese[cas]=execute2D(data, cas) + + data['grFace']=['FACEXM FACEXP'] + cas='5' + crack['actif']='Ellipse'; crack[crack['actif']]={'Rayon':[L/4.], 'Centre':[0., offset, 0.], 'Normale':[0., 1., 0.]} + if cas in listCas or listCas==[]: + synthese[cas]=execute2D(data, cas) + + cas='6' + crack['actif']='Ellipse' + crack[crack['actif']]={'Rayon':[L/8.], 'Centre':[-L/16., offset, 0.], 'Normale':[0., 1., 0.]} + if cas in listCas or listCas==[]: + synthese[cas]=execute2D(data, cas) + + + data['grFace']=[''] + cas='7' + crack['actif']='Sphere' + crack[crack['actif']]={'Rayon':[L/4.], 'Centre':[0., 0., 0.]} + if cas in listCas or listCas==[]: + synthese[cas]=execute2D(data, cas) + + cas='8' + crack['actif']='Sphere' + crack[crack['actif']]={'Rayon':[L/4.], 'Centre':[L/2., 0., 0.]} + if cas in listCas or listCas==[]: + synthese[cas]=execute2D(data, cas) + + data['grFace']=['FACEXM FACEXP'] + cas='9' + crack['actif']='Sphere' + crack['Sphere']={'Rayon':[L/4.], 'Centre':[0., 0., 0.]} + if cas in listCas or listCas==[]: + synthese[cas]=execute2D(data, cas) + + # -------- # + # CAS 3D # + # -------- # + data['grEdge']=[''] + data['grFace']=['FACEXP FACEXM FACEYP FACEYM FACEZP FACEZM'] + data['is2D']=False + + cas='10' + crack['actif']='Rectangle' + crack[crack['actif']]={'Centre':[L/2., offset, 0.], 'Normale':[0., 1., 0.], 'Direction':[1., 0., 0.], 'Longueur':[L/2.], 'Largeur':[L]} + if cas in listCas or listCas==[]: + synthese[cas]=execute3D(data, cas) + + cas='11' + crack['actif']='Sphere' + crack[crack['actif']]={'Rayon':[L/4.], 'Centre':[0., 0., 0.]} + if cas in listCas or listCas==[]: + synthese[cas]=execute3D(data, cas) + + cas='12' + crack['actif']='Ellipse' + crack[crack['actif']]={'Centre':[L/4., L/4., L/4.], 'Normale':[1., 1., 1.], 'Rayon':[L]} + if cas in listCas or listCas==[]: + synthese[cas]=execute3D(data, cas) + + cas='13' + crack['actif']='Sphere' + crack[crack['actif']]={'Rayon':[L/4.], 'Centre':[L/2., 0., 0.]} + if cas in listCas or listCas==[]: + synthese[cas]=execute3D(data, cas) + + cas='14' + crack['actif']='Ellipse' + crack[crack['actif']]={'Rayon':[L/4.], 'Centre':[L/2., offset, 0.], 'Normale':[0., 1., 0.]} + if cas in listCas or listCas==[]: + synthese[cas]=execute3D(data, cas) + + cas='15' + crack['actif']='Rectangle' + crack[crack['actif']]={'Centre':[L/2., 0., 0.], 'Normale':[0., 1., 0.], 'Direction':[-1., 0., 0.], + 'Longueur':[L/2.], 'Largeur':[L], 'Rayon entaille':[te*1.5]} + if cas in listCas or listCas==[]: + synthese[cas]=execute3D(data, cas) + + cas='16' + crack['actif']='Rectangle' + crack[crack['actif']]={'Centre':[L/2., offset, 0.], 'Normale':[0., 1., 0.], 'Direction':[1., 0., 0.], + 'Longueur':[L/2.], 'Largeur':[L/4.], 'Rayon':[2.*te]} + if cas in listCas or listCas==[]: + synthese[cas]=execute3D(data, cas) + + cas='17' + crack['actif']='Rectangle' + crack[crack['actif']]={'Centre':[0., offset, 0.], 'Normale':[0., 1., 0.], 'Direction':[1., 0., 0.], + 'Longueur':[L/4.]} + if cas in listCas or listCas==[]: + synthese[cas]=execute3D(data, cas) + + cas='18' + crack['actif']='Rectangle' + crack[crack['actif']]={'Centre':[0., 0., 0.], 'Normale':[1., 1., 0.], 'Direction':[1., -1., 0.], + 'Longueur':[L], 'Angle':[180.]} + if cas in listCas or listCas==[]: + synthese[cas]=execute3D(data, cas) + + + data['grVol']=['VOLYP VOLYM'] + + cas='19' + crack['actif']='Rectangle' + crack[crack['actif']]={'Centre':[0., 0., 0.], 'Normale':[0., 1., 0.], 'Direction':[1., 0., 0.], + 'Longueur':[L], 'Angle':[180.]} + if cas in listCas or listCas==[]: + synthese[cas]=execute3D(data, cas) + + data['grVol']=['VOLXP VOLXM'] + + cas='20' + crack['actif']='Sphere' + crack[crack['actif']]={'Rayon':[L/4.], 'Centre':[0., 0., 0.]} + if cas in listCas or listCas==[]: + synthese[cas]=execute3D(data, cas) + + data['grVol']=['VOLYP VOLYM'] + + cas='21' + crack['actif']='Ellipse' + crack[crack['actif']]={'Rayon':[L/4.], 'Centre':[L/2., offset, 0.], 'Normale':[0., 1., 0.]} + if cas in listCas or listCas==[]: + synthese[cas]=execute3D(data, cas) + + OK=[] + NOOK=[] + for s in synthese.keys(): + if synthese[s]: + OK.append(s) + else: + NOOK.append(s) + + print 'OK:' + print OK + print ' ' + print 'NOOK:' + print NOOK + print ' ' + + return(synthese) + + + +def execute3D(data, cas): + names={'saneGeoName':'cube3D', 'crackGeoName':'crack'+cas, 'crackedGeoName':'cracked'+cas} + + crackMed=os.path.join(tmpdir,'crack'+cas+'.med') + crackedMed=os.path.join(tmpdir,'cracked'+cas+'.med') + + saneGeo=os.path.join(tmpdir,names['saneGeoName'],'.geo') + crackGeo=os.path.join(tmpdir,names['crackGeoName'],'.geo') + crackedGeo=os.path.join(tmpdir,names['crackedGeoName'],'.geo') + + for f in [crackMed, crackedMed, saneGeo, crackGeo, crackedGeo]: + if os.path.isfile(f): os.remove(f) + + genereCrack.main(data, crackMed) + + Zset.medToGeo(os.path.join(tmpdir,names['saneGeoName']),names['saneGeoName'], tmpdir) + Zset.medToGeo(crackMed, names['crackGeoName'], tmpdir) + Zset.insertCrack(data, names, tmpdir) + shutil.copy(os.path.join(tmpdir,'_mesh_out_to_ghs3d.mesh'),os.path.join(tmpdir,'mesh'+cas+'.mesh')) + shutil.copy(os.path.join(tmpdir,'insert.z7p'),os.path.join(tmpdir,'insert'+cas+'.z7p')) + + Zset.geoToMed(crackedMed, names['crackedGeoName'], tmpdir) + + if os.path.isfile(crackedMed): + uF.extendElsets(crackedMed) + maxAR=uF.getMaxAspectRatio(tmpdir) + return(maxAR<30. and maxAR>=1.) + else: + return(False) + + + +def execute2D(data, cas): + names={'saneGeoName':'cube2D', 'crackGeoName':'crack'+cas, 'crackedGeoName':'cracked'+cas} + + crackMed=os.path.join(tmpdir,'crack'+cas+'.med') + crackedMed=os.path.join(tmpdir,'cracked'+cas+'.med') + + saneGeo=os.path.join(tmpdir,names['saneGeoName'],'.geo') + crackGeo=os.path.join(tmpdir,names['crackGeoName'],'.geo') + crackedGeo=os.path.join(tmpdir,names['crackedGeoName'],'.geo') + + for f in [crackMed, crackedMed, saneGeo, crackGeo, crackedGeo]: + if os.path.isfile(f): os.remove(f) + + genereCrack.main(data, crackMed) + + Zset.medToGeo(os.path.join(tmpdir,names['saneGeoName']),names['saneGeoName'], tmpdir, opt=[' **to_3d']) + Zset.medToGeo(crackMed, names['crackGeoName'], tmpdir) + Zset.insertCrack(data, names, tmpdir) + shutil.copy(os.path.join(tmpdir,'_mesh_out_.mesh'),os.path.join(tmpdir,'mesh'+cas+'.mesh')) + shutil.copy(os.path.join(tmpdir,'insert.z7p'),os.path.join(tmpdir,'insert'+cas+'.z7p')) + Zset.geoToMed(crackedMed, names['crackedGeoName'], tmpdir) + + if os.path.isfile(crackedMed): + uF.extendElsets(crackedMed) + maxAR=uF.getMaxAspectRatio(tmpdir) + return(maxAR<30. and maxAR>=1.) + else: + return(False) + + + + diff --git a/src/Tools/ZCracksPlug/casTests/launchManuel.py b/src/Tools/ZCracksPlug/casTests/launchManuel.py new file mode 100644 index 000000000..1eadd07c6 --- /dev/null +++ b/src/Tools/ZCracksPlug/casTests/launchManuel.py @@ -0,0 +1,27 @@ + +import os, tempfile + +directory=tempfile.mktemp(prefix='tmpZcracks') +print "directory=", tmpdir + +# Tous les cas +listCas=['1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21'] + +# Cas sans les aretes ou faces sur la fissure : +listCas=['1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','20'] + +synthese={} + +for cas in listCas: + result=os.path.join(directory,'cracked'+cas+'.geo') + if os.path.isfile(result): os.remove(result) + try: + os.remove(os.path.join(directory,'cracked'+cas+'.geo')) + except: + pass + os.system('cd '+directory+';Zrun -zp insert'+cas+'.z7p') + + synthese[cas]= os.path.isfile(result) + +print synthese + diff --git a/src/Tools/ZCracksPlug/ellipse.py b/src/Tools/ZCracksPlug/ellipse.py new file mode 100644 index 000000000..9ffeb8b66 --- /dev/null +++ b/src/Tools/ZCracksPlug/ellipse.py @@ -0,0 +1,202 @@ +# -*- coding: utf-8 -*- + +### +### This file is generated automatically by SALOME v7.7.1 with dump python functionality +### + + +import sys, numpy +import salome + +salome.salome_init() +theStudy = salome.myStudy + +import salome_notebook +notebook = salome_notebook.NoteBook(theStudy) + +### +### GEOM component +### + +import GEOM +from salome.geom import geomBuilder +import math +import SALOMEDS +import utilityFunctions as uF +from output import message + +#ellipse.generate(data_demi_grand_axe, data_centre, data_normale,data_direction, data_demi_petit_axe, data_angle, rayon_entaille,extension, outFile) +#if True: + #data_demi_grand_axe = 2. + #data_centre = [0., 0., 0.] + #data_normale = [1., 0., 0.] + #data_direction = [0., 1., 0.] + #data_demi_petit_axe = 1. + #data_angle=180. + #rayon_entaille=0.1 + #extension=0.1 + #outFile='/home/I60976/00_PROJETS/2015_INTEGRATION_ZCRACKS/zcracks_salome/test.med' + + +def generate(data_demi_grand_axe, data_centre, data_normale, + data_direction, data_demi_petit_axe, data_angle, + rayon_entaille, extension, outFile): + + Vnormale, Vdirection, Vortho = uF.calcCoordVectors(data_normale, data_direction) + Vcentre = numpy.array(data_centre) + + geompy = geomBuilder.New(theStudy) + + O = geompy.MakeVertex(0, 0, 0) + OX = geompy.MakeVectorDXDYDZ(1, 0, 0) + OY = geompy.MakeVectorDXDYDZ(0, 1, 0) + OZ = geompy.MakeVectorDXDYDZ(0, 0, 1) + CENTRE = geompy.MakeVertex(Vcentre[0], Vcentre[1], Vcentre[2]) + NORMALE = geompy.MakeVectorDXDYDZ(Vnormale[0], Vnormale[1], Vnormale[2]) + DIRECTION = geompy.MakeVectorDXDYDZ(Vdirection[0], Vdirection[1], Vdirection[2]) + DIRECTION_op = geompy.MakeVectorDXDYDZ(-Vdirection[0], -Vdirection[1], -Vdirection[2]) + V3 = geompy.MakeVectorDXDYDZ(Vortho[0], Vortho[1], Vortho[2]) + V3_op = geompy.MakeVectorDXDYDZ(-Vortho[0], -Vortho[1], -Vortho[2]) + if data_demi_grand_axe >= data_demi_petit_axe: + ELLIPSE = geompy.MakeEllipse(CENTRE, NORMALE, data_demi_grand_axe, data_demi_petit_axe, DIRECTION) + else: + ELLIPSE = geompy.MakeEllipse(CENTRE, NORMALE, data_demi_petit_axe, data_demi_grand_axe, V3) + + if rayon_entaille<1.e-12: + FELLIPSE = geompy.MakeFaceWires([ELLIPSE], 1) + dim=2 + else: + dim=3 + VP1=Vcentre+Vdirection*(data_demi_grand_axe-rayon_entaille)+Vnormale*rayon_entaille + VP2=Vcentre+Vdirection*(data_demi_grand_axe) + VP3=Vcentre+Vdirection*(data_demi_grand_axe-rayon_entaille)-Vnormale*rayon_entaille + PE1=geompy.MakeVertex(VP1[0], VP1[1], VP1[2]) + PE2=geompy.MakeVertex(VP2[0], VP2[1], VP2[2]) + PE3=geompy.MakeVertex(VP3[0], VP3[1], VP3[2]) + ARC = geompy.MakeArc(PE1, PE2, PE3) + TUYAU = geompy.MakePipe(ARC, ELLIPSE) + subShapesList=geompy.GetFreeBoundary(TUYAU)[1] + entailleFace1 = geompy.MakeFaceWires([subShapesList[0]], 1) + entailleFace2 = geompy.MakeFaceWires([subShapesList[1]], 1) + FELLIPSE = geompy.MakeShell([TUYAU, entailleFace1, entailleFace2]) + + edgesIDs = geompy.SubShapeAllIDs(FELLIPSE, geompy.ShapeType["EDGE"]) + edges = geompy.CreateGroup(FELLIPSE, geompy.ShapeType["EDGE"]) + geompy.UnionIDs(edges, edgesIDs) + geompy.addToStudy( FELLIPSE, 'FELLIPSE' ) + geompy.addToStudyInFather( FELLIPSE , edges, 'edges' ) + + hauteur=numpy.max([data_demi_grand_axe,data_demi_petit_axe])*1.1 + + eps=1.E-05 + bool_boite=True + extrusion=numpy.max([1.,rayon_entaille])*1.1 + if ( (data_angle>(eps)) and (data_angle<(180.-eps)) ): + rayon2=hauteur*numpy.tan(data_angle*numpy.pi/180./2.) + + B1=geompy.MakeTranslationVectorDistance(CENTRE,DIRECTION,hauteur) + B2=geompy.MakeTranslationVectorDistance(B1,V3,rayon2) + geompy.TranslateVectorDistance(B1,V3_op,rayon2, False) + LB01 = geompy.MakeLineTwoPnt(CENTRE, B1) + LB02 = geompy.MakeLineTwoPnt(CENTRE, B2) + LB12 = geompy.MakeLineTwoPnt(B1, B2) + plan_BOITE = geompy.MakeFaceWires([LB01, LB02, LB12], True) + + BOITE = geompy.MakePrismVecH2Ways(plan_BOITE, NORMALE, extrusion) + + FACE_FISSURE = geompy.MakeCommonList([FELLIPSE, BOITE]) + + elif ( (data_angle>=(180.-eps)) and (data_angle<=(180.+eps)) ): + VP1=Vcentre+Vortho*hauteur + VP2=Vcentre-Vortho*hauteur + VP3=Vcentre-Vortho*hauteur+Vdirection*hauteur + VP4=Vcentre+Vortho*hauteur+Vdirection*hauteur + + Sommet_1 = geompy.MakeVertex(VP1[0], VP1[1], VP1[2]) + Sommet_2 = geompy.MakeVertex(VP2[0], VP2[1], VP2[2]) + Sommet_3 = geompy.MakeVertex(VP3[0], VP3[1], VP3[2]) + Sommet_4 = geompy.MakeVertex(VP4[0], VP4[1], VP4[2]) + + Ligne_1 = geompy.MakeLineTwoPnt(Sommet_1, Sommet_2) + Ligne_2 = geompy.MakeLineTwoPnt(Sommet_2, Sommet_3) + Ligne_3 = geompy.MakeLineTwoPnt(Sommet_3, Sommet_4) + Ligne_4 = geompy.MakeLineTwoPnt(Sommet_4, Sommet_1) + + Contour_1 = geompy.MakeWire([Ligne_1, Ligne_2, Ligne_3, Ligne_4], 1e-07) + Face_1 = geompy.MakeFaceWires([Contour_1], 1) + BOITE = geompy.MakePrismVecH2Ways(Face_1, NORMALE, extrusion) + FACE_FISSURE = geompy.MakeCommonList([FELLIPSE, BOITE]) + + elif ( (data_angle>(180.+eps)) and (data_angle<(360.-eps)) ): + rayon2=hauteur*numpy.tan((360.-data_angle)*numpy.pi/180./2.) + + B1=geompy.MakeTranslationVectorDistance(CENTRE,DIRECTION_op,hauteur) + B2=geompy.MakeTranslationVectorDistance(B1,V3,rayon2) + geompy.TranslateVectorDistance(B1,V3_op,rayon2, False) + LB01 = geompy.MakeLineTwoPnt(CENTRE, B1) + LB02 = geompy.MakeLineTwoPnt(CENTRE, B2) + LB12 = geompy.MakeLineTwoPnt(B1, B2) + plan_BOITE = geompy.MakeFaceWires([LB01, LB02, LB12], True) + extrusion=numpy.max([1.,rayon_entaille])*1.1 + BOITE = geompy.MakePrismVecH2Ways(plan_BOITE, NORMALE, extrusion) + + FACE_FISSURE = geompy.MakeCutList(FELLIPSE, [BOITE]) + + elif ( (data_angle<=(eps)) or (data_angle>=(360.-eps)) ): + bool_boite=False + FACE_FISSURE = FELLIPSE + + else: + message('E','Angle non prevu') + + if bool_boite: + #geompy.addToStudy( BOITE, 'BOITE' ) + newEdgesIDs = geompy.SubShapeAllIDs(FACE_FISSURE, geompy.ShapeType["EDGE"]) + newEdges = geompy.CreateGroup(FACE_FISSURE, geompy.ShapeType["EDGE"]) + geompy.UnionIDs(newEdges, newEdgesIDs) + + [oldEdges] = geompy.RestoreGivenSubShapes(FACE_FISSURE, [FELLIPSE, edges], GEOM.FSM_GetInPlace, True, False) + + toExtrude = geompy.CutListOfGroups([newEdges], [oldEdges]) + + if extension>1.e-12: + extrusion = geompy.MakePrismVecH(toExtrude, DIRECTION_op, extension) + try: + FACE_FISSURE = geompy.MakeFuseList([FACE_FISSURE, extrusion], False, True) + except: + FACE_FISSURE = geompy.MakeFuseList([FACE_FISSURE, extrusion], False, False) + + #geompy.addToStudy( FACE_FISSURE, 'FACE_FISSURE' ) + + #geompy.addToStudy( FACE_FISSURE, 'FACE_FISSURE' ) + + import SMESH, SALOMEDS + from salome.smesh import smeshBuilder + smesh = smeshBuilder.New(theStudy) + + A=numpy.pi/(30.) + minAxes=numpy.min([data_demi_grand_axe,data_demi_petit_axe]) + maxAxes=numpy.max([data_demi_grand_axe,data_demi_petit_axe]) + R=minAxes**2/maxAxes + + if rayon_entaille>1.e-12: + R=numpy.min([R,rayon_entaille]) + A=numpy.pi/(15.) + + chordal, minSize = uF.calcElemSize(A, R) + maxSize=maxAxes/5. + + Maillage=uF.meshCrack(FACE_FISSURE, minSize, maxSize, chordal, dim) + + try: + Maillage.ExportMED( outFile, 0, SMESH.MED_V2_2, 1, None ,1) + smesh.SetName(Maillage.GetMesh(), 'MAILLAGE_FISSURE') + except: + print 'ExportToMEDX() failed. Invalid file name?' + + + ## Set names of Mesh objects + + + if salome.sg.hasDesktop(): + salome.sg.updateObjBrowser(1) diff --git a/src/Tools/ZCracksPlug/genereCrack.py b/src/Tools/ZCracksPlug/genereCrack.py new file mode 100644 index 000000000..372772b43 --- /dev/null +++ b/src/Tools/ZCracksPlug/genereCrack.py @@ -0,0 +1,235 @@ +import os, shutil +import sphere, ellipse, rectangle +import utilityFunctions as uF +from output import message + +def main(data, outFile): + activeCrack=data['crack']['actif'] + crack=data['crack'][activeCrack] + + res=False + + if activeCrack == 'Ellipse': + res=generateEllipse(crack, outFile) + + elif activeCrack == 'Rectangle': + res=generateRectangle(crack, outFile) + + elif activeCrack == 'Sphere': + res=generateSphere(crack, outFile) + + elif activeCrack == 'Custom': + res=generateCustom(crack, outFile) + + return(res) + + +def generateEllipse(crack, outFile): + res=True + test=uF.testStrictRange(crack['Rayon']) + if not test: + message('E','Bad Rayon',goOn=True) + res=False + demiGrandAxe=crack['Rayon'][0] + + if 'Rayon 2' not in crack.keys(): crack['Rayon 2']=[] + if len(crack['Rayon 2'])==0: + demiPetitAxe=demiGrandAxe + else: + test=uF.testStrictRange(crack['Rayon 2']) + if not test: + message('E','Bad Rayon 2',goOn=True) + res=False + demiPetitAxe=crack['Rayon 2'][0] + + test=uF.test3dVector(crack['Centre']) + if not test: + message('E','Invalid Centre',goOn=True) + res=False + centre=crack['Centre'] + + test=uF.test3dVector(crack['Normale']) + if not test: + message('E','Invalid Normale',goOn=True) + res=False + normale=crack['Normale'] + + if 'Direction' not in crack.keys(): crack['Direction']=[] + if len(crack['Direction'])==0: + if normale==[1.,0.,0.]: + direction=[0.,1.,0.] + else: + direction=[1.,0.,0.] + else: + test=uF.test3dVector(crack['Direction']) + if not test: + message('E','Invalid Direction',goOn=True) + res=False + direction=crack['Direction'] + test=(direction!=normale) + if not test: + message('E','Normale and Direction are equals',goOn=True) + res=False + + if 'Angle' not in crack.keys(): crack['Angle']=[] + if len(crack['Angle'])==0: + angle=0.0 + else: + test=uF.testRange(crack['Angle'], inf=0.0, sup=360.) + if not test: + message('E','Angle not valid or out of range 0 to 360',goOn=True) + res=False + angle=crack['Angle'][0] + + if 'Rayon entaille' not in crack.keys(): crack['Rayon entaille']=[] + if len(crack['Rayon entaille'])==0: + rayon_entaille=0.0 + else: + test=uF.testStrictRange(crack['Rayon entaille'], inf=0.0) + if not test: + message('E','rayon entaille not valid or negative',goOn=True) + res=False + rayon_entaille=crack['Rayon entaille'][0] + + if 'Extension' not in crack.keys(): crack['Extension']=[] + if len(crack['Extension'])==0: + extension=0.0 + else: + test=uF.testStrictRange(crack['Extension'], inf=0.0) + if not test: + message('E','extension not valid or negative',goOn=True) + res=False + extension=crack['Extension'][0] + + if res: + ellipse.generate(demiGrandAxe, centre, normale, + direction, demiPetitAxe, angle, + rayon_entaille, extension, outFile) + return(True) + else: + return(False) + +def generateRectangle(crack, outFile): + res=True + test=uF.testStrictRange(crack['Longueur']) + if not test: + message('E','Bad Longueur',goOn=True) + res=False + longueur=crack['Longueur'][0] + + if 'Largeur' not in crack.keys(): crack['Largeur']=[] + if len(crack['Largeur'])==0: + largeur=longueur + else: + test=uF.testStrictRange(crack['Largeur']) + if not test: + message('E','Bad Largeur',goOn=True) + res=False + largeur=crack['Largeur'][0] + + test=uF.test3dVector(crack['Centre']) + if not test: + message('E','Invalid Centre',goOn=True) + res=False + centre=crack['Centre'] + + test=uF.test3dVector(crack['Normale']) + if not test: + message('E','Invalid Normale',goOn=True) + res=False + normale=crack['Normale'] + + test=uF.test3dVector(crack['Direction']) + if not test: + message('E','Invalid Direction',goOn=True) + res=False + direction=crack['Direction'] + + if 'Angle' not in crack.keys(): crack['Angle']=[] + if len(crack['Angle'])==0: + angle=0.0 + else: + test=uF.testRange(crack['Angle'], inf=0.0, sup=360.) + if not test: + message('E','Angle not valid or out of range 0 to 360',goOn=True) + res=False + angle=crack['Angle'][0] + + if 'Rayon' not in crack.keys(): crack['Rayon']=[] + if len(crack['Rayon'])==0: + rayon=0.0 + else: + test=uF.testRange(crack['Rayon'], inf=0.0) + if not test: + message('E','Rayon not valid',goOn=True) + res=False + rayon=crack['Rayon'][0] + + if 'Rayon entaille' not in crack.keys(): crack['Rayon entaille']=[] + if len(crack['Rayon entaille'])==0: + rayon_entaille=0.0 + else: + test=uF.testStrictRange(crack['Rayon entaille'], inf=0.0) + if not test: + message('E','rayon entaille not valid or negative',goOn=True) + res=False + rayon_entaille=crack['Rayon entaille'][0] + + if res: + rectangle.generate(longueur,largeur,centre, + normale,direction,angle, + rayon,rayon_entaille,outFile) + return(True) + else: + return(False) + +def generateSphere(crack, outFile): + res=True + test=uF.testStrictRange(crack['Rayon']) + if not test: + message('E','Bad Rayon',goOn=True) + res=False + rayon=crack['Rayon'][0] + + test=uF.test3dVector(crack['Centre']) + if not test: + message('E','Invalid Centre',goOn=True) + res=False + centre=crack['Centre'] + + if res: + sphere.generate(rayon,centre,outFile) + return(True) + else: + return(False) + +def generateCustom(crack, outFile): + res=True + test=os.path.isfile(crack['med file']) + if not test: + message('E','crack med file missing',goOn=True) + res=False + + import salome + salome.salome_init() + theStudy = salome.myStudy + import salome_notebook + notebook = salome_notebook.NoteBook(theStudy) + import SMESH, SALOMEDS + from salome.smesh import smeshBuilder + + smesh = smeshBuilder.New(theStudy) + ([Maillage_1], status) = smesh.CreateMeshesFromMED(crack['med file']) + isCrack=False + for group in Maillage_1.GetGroups(): + if [group.GetType(), group.GetName()]==[SMESH.NODE, 'crack']: isCrack=True + if isCrack: + shutil.copy(crack['med file'],outFile) + else: + Group_1 = Maillage_1.CreateEmptyGroup( SMESH.NODE, 'crack' ) + nbAdd = Group_1.AddFrom( Maillage_1.GetMesh() ) + Maillage_1.ExportMED( outFile, 0, SMESH.MED_V2_2, 1, None ,1) + return(True) + + + diff --git a/src/Tools/ZCracksPlug/images.qrc b/src/Tools/ZCracksPlug/images.qrc new file mode 100644 index 000000000..c8177fcaf --- /dev/null +++ b/src/Tools/ZCracksPlug/images.qrc @@ -0,0 +1,7 @@ + + + images/schema_shpere.png + images/schema_ellipse.png + images/schema_rectangle.png + + diff --git a/src/Tools/ZCracksPlug/images/Rectangle.svg b/src/Tools/ZCracksPlug/images/Rectangle.svg new file mode 100644 index 000000000..ab1d9adba --- /dev/null +++ b/src/Tools/ZCracksPlug/images/Rectangle.svg @@ -0,0 +1,1082 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + Largeur Longueur + Direction + + Normale + Angle Centre + + + + Direction + Normale Centre + + + + + + + + + Rayon entaille + + + Rayon + Carré + + + Rectangle Rectangle tronqué + Rectangle bords arrondis + + + + + + + + + + Exemples : + Entaille droite + diff --git a/src/Tools/ZCracksPlug/images/Sphere.svg b/src/Tools/ZCracksPlug/images/Sphere.svg new file mode 100644 index 000000000..3147bb792 --- /dev/null +++ b/src/Tools/ZCracksPlug/images/Sphere.svg @@ -0,0 +1,614 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + Centre + + + Rayon + + + + diff --git a/src/Tools/ZCracksPlug/images/big_loader.gif b/src/Tools/ZCracksPlug/images/big_loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..9b53d5bf6bd84225028e8344082b77ee6f7abd32 GIT binary patch literal 4874 zcmZ{oXH-*LyM=eEk)k1xP^1Kqjub^HmJ^E7ktR)4nurLBqLc`j1P~HJkuDt)dhZA* z9TK`AML<9SL5dU`;_+}nzj2S>9pmobYp);gnCqEyzS_DMR8;Nl!SSF<1hBomJvBAe z+S;0tk%7nK4GawU`T2KucY*)s6W(PtI&W^KscwA!xSRq6w0BJSI~2wOAOP9@U-qvB zpt~Ck-NNT8D}4>Sc9IcJH`81SO59dnc*qXicc1YoS@&DtZO-t}k>!hI(C;zb)Y1p@ z?&}rXl#Um9^{nBWX3KmGPd7=Y+QUo;?tz$l+?8JjLa+=Jv%2iFTbF$sJNuGth}PKs=B7O?pb|9w6r-Hh6^Y%| zr10xj(3vrkW(Bs)itL^Q1;_3b-O8N4WEIclDQ0EvKsqjvML@4A?EkwW|*L1ebtBIJhQ^9 zef8BVV`Yv#X@(6oYm;@JE7N@qwd*s@fviGCjdh!Ij2M|~{f*B)Ee_K3(~X|je_3&7 z;c5OTMIeGOY;L6r%>eK*wlOjnd#;fPEJ=Wnhtq%J4=xXMS!xjou(jFOmY`h_oXbuf z*jYQk@Pi|8SBdB8g{(Yd++7!9tnfG|%Oyoyo*ByG+2B zg+=?R$v@1TESFei;0dPNZZRo9gL2*%cB;ND)68}GJTUQ;*_IiKkzPg{P(qF#63Z!A zF0cd?2wrJ6e7J(D`0|ya2=L@e*>F%ndv?1{c8~dUAtiC?uWX_MIxAVU4;I8niXY1yK=dR4{KJm{XKS+2;3xCF5gL*9#Dd
    ;UL@K9}ua)flf- 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 TzJ5tf4rhhD<+wuufYbj2ubJMV literal 0 HcmV?d00001 diff --git a/src/Tools/ZCracksPlug/images/schema_ellipse.png b/src/Tools/ZCracksPlug/images/schema_ellipse.png new file mode 100644 index 0000000000000000000000000000000000000000..158bb71e0c5981ac74590c76249bbb61940d1669 GIT binary patch literal 53055 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 literal 0 HcmV?d00001 diff --git a/src/Tools/ZCracksPlug/images/schema_rectangle.png b/src/Tools/ZCracksPlug/images/schema_rectangle.png new file mode 100644 index 0000000000000000000000000000000000000000..622e3477a855b47e2ed6c6472d3290623e3ec817 GIT binary patch literal 43996 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 literal 0 HcmV?d00001 diff --git a/src/Tools/ZCracksPlug/images/schema_shpere.png b/src/Tools/ZCracksPlug/images/schema_shpere.png new file mode 100644 index 0000000000000000000000000000000000000000..9754aed8996ef003c9ac5c10660a0d827a69d823 GIT binary patch literal 23230 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 + Bentaille = rayon_entaille>1e-12 + + A=numpy.pi/(15.) + maxSize=numpy.min([data_longueur,data_largeur])/4. + if Bentaille: + dim=3 + if Brayon: + R=numpy.min([data_rayon,rayon_entaille]) + chordal, minSize = uF.calcElemSize(A, R) + else: + chordal, minSize = uF.calcElemSize(A, rayon_entaille) + else: + dim=2 + if Brayon: + chordal, minSize = uF.calcElemSize(A, data_rayon) + else: + minSize=numpy.min([data_longueur,data_largeur])/10. + maxSize=minSize + chordal=1. + + Vnormale, Vdirection, Vortho = uF.calcCoordVectors(data_normale, data_direction) + Vcentre = numpy.array(data_centre) + + geompy = geomBuilder.New(theStudy) + + O = geompy.MakeVertex(0, 0, 0) + OX = geompy.MakeVectorDXDYDZ(1, 0, 0) + OY = geompy.MakeVectorDXDYDZ(0, 1, 0) + OZ = geompy.MakeVectorDXDYDZ(0, 0, 1) + CENTRE = geompy.MakeVertex(Vcentre[0], Vcentre[1], Vcentre[2]) + NORMALE = geompy.MakeVectorDXDYDZ(Vnormale[0], Vnormale[1], Vnormale[2]) + DIRECTION = geompy.MakeVectorDXDYDZ(Vdirection[0], Vdirection[1], Vdirection[2]) + DIRECTION_op = geompy.MakeVectorDXDYDZ(-Vdirection[0], -Vdirection[1], -Vdirection[2]) + V3 = geompy.MakeVectorDXDYDZ(Vortho[0], Vortho[1], Vortho[2]) + V3_op = geompy.MakeVectorDXDYDZ(-Vortho[0], -Vortho[1], -Vortho[2]) + + VP1=Vcentre+Vdirection*data_longueur+Vortho*data_largeur + VP2=Vcentre-Vdirection*data_longueur+Vortho*data_largeur + VP3=Vcentre-Vdirection*data_longueur-Vortho*data_largeur + VP4=Vcentre+Vdirection*data_longueur-Vortho*data_largeur + + Sommet_1 = geompy.MakeVertex(VP1[0], VP1[1], VP1[2]) + Sommet_2 = geompy.MakeVertex(VP2[0], VP2[1], VP2[2]) + Sommet_3 = geompy.MakeVertex(VP3[0], VP3[1], VP3[2]) + Sommet_4 = geompy.MakeVertex(VP4[0], VP4[1], VP4[2]) + + Ligne_1 = geompy.MakeLineTwoPnt(Sommet_1, Sommet_2) + Ligne_2 = geompy.MakeLineTwoPnt(Sommet_2, Sommet_3) + Ligne_3 = geompy.MakeLineTwoPnt(Sommet_3, Sommet_4) + Ligne_4 = geompy.MakeLineTwoPnt(Sommet_4, Sommet_1) + + Contour_1 = geompy.MakeWire([Ligne_1, Ligne_2, Ligne_3, Ligne_4], 1e-07) + + if Brayon or Bentaille: + vertexOfRect=geompy.SubShapeAllIDs(Contour_1, geompy.ShapeType["VERTEX"]) + Contour_1 = geompy.MakeFillet1D(Contour_1, data_rayon + rayon_entaille, vertexOfRect) + + if not Bentaille: + RECTANGLE = geompy.MakeFaceWires([Contour_1], 1) + else: + VP1=Vcentre+Vdirection*(data_longueur-rayon_entaille)+Vnormale*rayon_entaille + VP2=Vcentre+Vdirection*(data_longueur) + VP3=Vcentre+Vdirection*(data_longueur-rayon_entaille)-Vnormale*rayon_entaille + PE1=geompy.MakeVertex(VP1[0], VP1[1], VP1[2]) + PE2=geompy.MakeVertex(VP2[0], VP2[1], VP2[2]) + PE3=geompy.MakeVertex(VP3[0], VP3[1], VP3[2]) + ARC = geompy.MakeArc(PE1, PE2, PE3) + TUYAU = geompy.MakePipe(ARC, Contour_1) + subShapesList=geompy.GetFreeBoundary(TUYAU)[1] + entailleFace1 = geompy.MakeFaceWires([subShapesList[0]], 1) + entailleFace2 = geompy.MakeFaceWires([subShapesList[1]], 1) + RECTANGLE = geompy.MakeShell([TUYAU, entailleFace1, entailleFace2]) + + #edgesIDs = geompy.SubShapeAllIDs(RECTANGLE, geompy.ShapeType["EDGE"]) + #edges = geompy.CreateGroup(RECTANGLE, geompy.ShapeType["EDGE"]) + #geompy.UnionIDs(edges, edgesIDs) + #geompy.addToStudy( RECTANGLE, 'RECTANGLE' ) + #geompy.addToStudyInFather( RECTANGLE , edges, 'edges' ) + + hauteur=data_longueur*1.1 + + eps=1.E-05 + bool_boite=True + extrusion=numpy.max([1.,rayon_entaille])*1.1 + + if ( (data_angle>(eps)) and (data_angle<(180.-eps)) ): + rayon2=hauteur*numpy.tan(data_angle*numpy.pi/180./2.) + + B1=geompy.MakeTranslationVectorDistance(CENTRE,DIRECTION,hauteur) + B2=geompy.MakeTranslationVectorDistance(B1,V3,rayon2) + geompy.TranslateVectorDistance(B1,V3_op,rayon2, False) + LB01 = geompy.MakeLineTwoPnt(CENTRE, B1) + LB02 = geompy.MakeLineTwoPnt(CENTRE, B2) + LB12 = geompy.MakeLineTwoPnt(B1, B2) + plan_BOITE = geompy.MakeFaceWires([LB01, LB02, LB12], True) + extrusion=numpy.max([1.,rayon_entaille])*1.1 + BOITE = geompy.MakePrismVecH2Ways(plan_BOITE, NORMALE, extrusion) + + FACE_FISSURE = geompy.MakeCommonList([RECTANGLE, BOITE]) + + elif ( (data_angle>=(180.-eps)) and (data_angle<=(180.+eps)) ): + VP1=Vcentre+Vortho*data_largeur*1.1 + VP2=Vcentre-Vortho*data_largeur*1.1 + VP3=Vcentre-Vortho*data_largeur*1.1+Vdirection*data_longueur*1.1 + VP4=Vcentre+Vortho*data_largeur*1.1+Vdirection*data_longueur*1.1 + + Sommet_5 = geompy.MakeVertex(VP1[0], VP1[1], VP1[2]) + Sommet_6 = geompy.MakeVertex(VP2[0], VP2[1], VP2[2]) + Sommet_7 = geompy.MakeVertex(VP3[0], VP3[1], VP3[2]) + Sommet_8 = geompy.MakeVertex(VP4[0], VP4[1], VP4[2]) + + Ligne_5 = geompy.MakeLineTwoPnt(Sommet_5, Sommet_6) + Ligne_6 = geompy.MakeLineTwoPnt(Sommet_6, Sommet_7) + Ligne_7 = geompy.MakeLineTwoPnt(Sommet_7, Sommet_8) + Ligne_8 = geompy.MakeLineTwoPnt(Sommet_8, Sommet_5) + + Contour_2 = geompy.MakeWire([Ligne_5, Ligne_6, Ligne_7, Ligne_8], 1e-07) + Face_2 = geompy.MakeFaceWires([Contour_2], 1) + BOITE = geompy.MakePrismVecH2Ways(Face_2, NORMALE, extrusion) + FACE_FISSURE = geompy.MakeCommonList([RECTANGLE, BOITE]) + + #geompy.addToStudy( RECTANGLE, 'RECTANGLE' ) + #geompy.addToStudy( BOITE, 'BOITE' ) + #geompy.addToStudy( FACE_FISSURE, 'FACE_FISSURE' ) + + elif ( (data_angle>(180.+eps)) and (data_angle<(360.-eps)) ): + rayon2=hauteur*numpy.tan((360.-data_angle)*numpy.pi/180./2.) + B1=geompy.MakeTranslationVectorDistance(CENTRE,DIRECTION_op,hauteur) + B2=geompy.MakeTranslationVectorDistance(B1,V3,rayon2) + geompy.TranslateVectorDistance(B1,V3_op,rayon2, False) + LB01 = geompy.MakeLineTwoPnt(CENTRE, B1) + LB02 = geompy.MakeLineTwoPnt(CENTRE, B2) + LB12 = geompy.MakeLineTwoPnt(B1, B2) + plan_BOITE = geompy.MakeFaceWires([LB01, LB02, LB12], True) + extrusion=numpy.max([1.,rayon_entaille])*1.1 + BOITE = geompy.MakePrismVecH2Ways(plan_BOITE, NORMALE, extrusion) + FACE_FISSURE = geompy.MakeCutList(RECTANGLE, [BOITE]) + + elif ( (data_angle<=(eps)) or (data_angle>=(360.-eps)) ): + bool_boite=False + FACE_FISSURE = RECTANGLE + + else: + message('E','Angle non prevu') + + #if bool_boite: + #newEdgesIDs = geompy.SubShapeAllIDs(FACE_FISSURE, geompy.ShapeType["EDGE"]) + #newEdges = geompy.CreateGroup(FACE_FISSURE, geompy.ShapeType["EDGE"]) + #geompy.UnionIDs(newEdges, newEdgesIDs) + + #[oldEdges] = geompy.RestoreGivenSubShapes(FACE_FISSURE, [RECTANGLE, edges], GEOM.FSM_GetInPlace, True, False) + + #toExtrude = geompy.CutListOfGroups([newEdges], [oldEdges]) + + #if extension>1.e-12: + #extrusion = geompy.MakePrismVecH(toExtrude, DIRECTION_op, extension) + #try: + #FACE_FISSURE = geompy.MakeFuseList([FACE_FISSURE, extrusion], False, True) + #except: + #FACE_FISSURE = geompy.MakeFuseList([FACE_FISSURE, extrusion], False, False) + + #geompy.addToStudy( FACE_FISSURE, 'FACE_FISSURE' ) + + # + # SMESH component + # + + import SMESH, SALOMEDS + from salome.smesh import smeshBuilder + smesh = smeshBuilder.New(theStudy) + + Maillage=uF.meshCrack(FACE_FISSURE, minSize, maxSize, chordal, dim) + + try: + Maillage.ExportMED( outFile, 0, SMESH.MED_V2_2, 1, None ,1) + smesh.SetName(Maillage.GetMesh(), 'MAILLAGE_FISSURE') + except: + print 'ExportToMEDX() failed. Invalid file name?' + + + if salome.sg.hasDesktop(): + salome.sg.updateObjBrowser(1) diff --git a/src/Tools/ZCracksPlug/sphere.py b/src/Tools/ZCracksPlug/sphere.py new file mode 100644 index 000000000..79542b2c5 --- /dev/null +++ b/src/Tools/ZCracksPlug/sphere.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- + +### +### This file is generated automatically by SALOME v7.7.1 with dump python functionality +### + +import sys, numpy +import salome + +salome.salome_init() +theStudy = salome.myStudy + +import salome_notebook +notebook = salome_notebook.NoteBook(theStudy) + +### +### GEOM component +### + +import GEOM +from salome.geom import geomBuilder +import math +import SALOMEDS +import utilityFunctions as uF +from output import message + +#import GEOM_Gen.ild + +def generate(data_rayon,data_centre,outFile): + #data_rayon = 0.1 + #data_centre = [1., 1., 01.] + + geompy = geomBuilder.New(theStudy) + + O = geompy.MakeVertex(0, 0, 0) + OX = geompy.MakeVectorDXDYDZ(1, 0, 0) + OY = geompy.MakeVectorDXDYDZ(0, 1, 0) + OZ = geompy.MakeVectorDXDYDZ(0, 0, 1) + + SPHERE = geompy.MakeSphereR(data_rayon) + geompy.TranslateDXDYDZ(SPHERE, data_centre[0], data_centre[1], data_centre[2]) + [FACE_FISSURE] = geompy.ExtractShapes(SPHERE, geompy.ShapeType["FACE"], True) + + # + # SMESH component + # + + import SMESH, SALOMEDS + from salome.smesh import smeshBuilder + + smesh = smeshBuilder.New(theStudy) + + A=numpy.pi/(20.) + chordal, minSize = uF.calcElemSize(A, data_rayon) + maxSize=data_rayon/3. + + Maillage=uF.meshCrack(FACE_FISSURE, minSize, maxSize, chordal, dim=3) + + try: + Maillage.ExportMED( outFile, 0, SMESH.MED_V2_2, 1, None ,1) + smesh.SetName(Maillage.GetMesh(), 'MAILLAGE_FISSURE') + except: + print 'ExportToMEDX() failed. Invalid file name?' + + + ## Set names of Mesh objects + + + if salome.sg.hasDesktop(): + salome.sg.updateObjBrowser(1) diff --git a/src/Tools/ZCracksPlug/utilityFunctions.py b/src/Tools/ZCracksPlug/utilityFunctions.py new file mode 100644 index 000000000..36db72580 --- /dev/null +++ b/src/Tools/ZCracksPlug/utilityFunctions.py @@ -0,0 +1,485 @@ +#import sys +#sys.path.append('/home/I60976/00_PROJETS/2015_INTEGRATION_ZCRACKS/zcracks_salome/zcracks') + +import numpy, subprocess, sys +from os import remove, getpid, path, environ +from output import message + +def calcCoordVectors(normalIN, directionIN): + V3TEMP=numpy.cross(normalIN,directionIN) + directionTEMP=numpy.cross(V3TEMP,normalIN) + + normalOUT=numpy.array(normalIN)/numpy.linalg.norm(normalIN) + directionOUT=numpy.array(directionTEMP)/numpy.linalg.norm(directionTEMP) + V3OUT=numpy.array(V3TEMP)/numpy.linalg.norm(V3TEMP) + return(normalOUT, directionOUT, V3OUT) + + +def testStrictRange(x, inf=0.0, sup=False): + test=False + c1=(type(x)==list) + if c1: + c2=(len(x)==1) + if c2: + c3=(type(x[0])==type(inf)) + if c3: + c4=(x[0]>inf) + c5=True + if sup!=False: + c5=(x[0]=inf) + c5=True + if sup!=False: + c5=(x[0]<=sup) + if c4 and c5: + test=True + return(test) + +def check(data): + OK=True + + test=False + c1=(data['crackedName']!='') + if c1: + test=True + if not test: + message('E','Invalid Cracked name',goOn=True) + OK=False + + test=False + c1=path.isfile(data['saneName']) + if c1: + c2=(data['saneName']!=data['crackedName']) + if c2: + test=True + else: + message('E','sane mesh and cracked mesh are identical',goOn=True) + OK=False + if not test: + message('E','Bad sane mesh file',goOn=True) + OK=False + + test=testStrictRange(data['minSize']) + if not test: + message('E','invalid min size',goOn=True) + OK=False + + test=testStrictRange(data['maxSize']) + if not test: + message('E','invalid max size',goOn=True) + OK=False + + if OK: + test=(data['maxSize'][0]>=data['minSize'][0]) + if not test: + message('E','min size greater than max size',goOn=True) + OK=False + + test=testStrictRange(data['extractLength']) + if not test: + message('E','invalid extract length',goOn=True) + OK=False + + test=testRange(data['gradation'], inf=1.0) + if not test: + message('E','invalid Gradation',goOn=True) + OK=False + + test=testRange(data['layers'], inf=1) + if not test: + message('E','invalid layers',goOn=True) + OK=False + + test=testRange(data['iterations'], inf=1) + if not test: + message('E','invalid iterations',goOn=True) + OK=False + return(OK) + + +def calcElemSize(A, R): + x=R*(1.-numpy.cos(A/2.)) + h=R*numpy.sin(A/2.) + return(x, h) + +def meshCrack(geomObject, minSize, maxSize, chordal, dim): + import salome + + salome.salome_init() + theStudy = salome.myStudy + + import SMESH, SALOMEDS + from salome.smesh import smeshBuilder + smesh = smeshBuilder.New(theStudy) + Maillage = smesh.Mesh(geomObject) + + if dim==3: + MG_CADSurf = Maillage.Triangle(algo=smeshBuilder.MG_CADSurf) + MG_CADSurf_Parameters = MG_CADSurf.Parameters() + MG_CADSurf_Parameters.SetPhysicalMesh( 0 ) + MG_CADSurf_Parameters.SetGeometricMesh( 1 ) + MG_CADSurf_Parameters.SetMinSize( minSize ) + MG_CADSurf_Parameters.SetMaxSize( maxSize ) + MG_CADSurf_Parameters.SetChordalError( chordal ) + + elif dim==2: + Regular_1D = Maillage.Segment() + Adaptive = Regular_1D.Adaptive(minSize,maxSize,chordal) + NETGEN_2D_ONLY = Maillage.Triangle(algo=smeshBuilder.NETGEN_2D) + else: + message('E',"error in mesh dimension",goOn=True) + + isDone = Maillage.Compute() + + #crack1 = Maillage.CreateEmptyGroup( SMESH.NODE, 'crack' ) + #nbAdd = crack1.AddFrom( Maillage.GetMesh() ) + #crack2 = Maillage.CreateEmptyGroup( SMESH.NODE, 'surface' ) + #nbAdd = crack2.AddFrom( Maillage.GetMesh() ) + + return(Maillage) + +def extendElsets(meshFile, outFile=None): + + if outFile==None: outFile=meshFile + + if not path.isfile(meshFile): + message('E','Mesh med file is not valid') + return('error') + + import SMESH, salome + #salome.salome_init() + theStudy = salome.myStudy + from salome.smesh import smeshBuilder + smesh = smeshBuilder.New(theStudy) + + ([mesh], status) = smesh.CreateMeshesFromMED(meshFile) + + mesh=cleanGroups(mesh) + + # Node color status + nodeList=mesh.GetNodesId() + volElemList=mesh.GetElementsByType(SMESH.VOLUME) + surfElemList=mesh.GetElementsByType(SMESH.FACE) + edgeElemList=mesh.GetElementsByType(SMESH.EDGE) + colorList=[-1]*len(nodeList) + + case2D=True + for group in mesh.GetGroups(): + if group.GetType()==SMESH.VOLUME and group.GetName()[:5]=='sides' : case2D=False + + sides=[] + for group in mesh.GetGroups(): + if case2D: + if group.GetType()==SMESH.FACE and group.GetName()[:5]=='sides': + sides.append(group) + else: + if group.GetType()==SMESH.VOLUME and group.GetName()[:5]=='sides': + sides.append(group) + + sortedSides=[None]*len(sides) + for group in sides: + N=group.GetName().replace('sides','').replace('_bset','').replace(' ','') + N=int(N) + sortedSides[N]=group + + elems=group.GetIDs() + for elemId in elems: + for elemNodeId in mesh.GetElemNodes(elemId) : + colorList[elemNodeId-1]=N + #print colorList + + crackOnly=True + for iN in range(len(sides)/2): + side0=sortedSides[2*iN] + side1=sortedSides[2*iN+1] + elemsOfside0=side0.GetIDs() + elemsOfside1=side1.GetIDs() + NodesOfside0=[] + NodesOfside1=[] + for elem in elemsOfside0: NodesOfside0+=mesh.GetElemNodes(elem) + for elem in elemsOfside1: NodesOfside1+=mesh.GetElemNodes(elem) + front=set(NodesOfside0).intersection(set(NodesOfside1)) + if len(front)==0: crackOnly=False + + if crackOnly: + mesh.ExportMED(outFile, 0, SMESH.MED_V2_2, 1, None ,1) + return('crack') + + # Propagates color using elem connectivity + # Always propagates max color + + #elemToTreat=volElemList + + #while len(elemToTreat)>0 : + #print len(elemToTreat) + #for elemId in elemToTreat: + #minColor=sys.maxint + #maxColor=-sys.maxint + #for elemNodeId in mesh.GetElemNodes(elemId) : + #nodeColor=colorList[elemNodeId-1] + #if nodeColormaxColor : maxColor=nodeColor + #if minColor!=maxColor : + #elemToTreat.remove(elemId) + #for elemNodeId in mesh.GetElemNodes(elemId) : + #colorList[elemNodeId-1]=maxColor + + ifChanged=True + if case2D: + elemList=[surfElemList,edgeElemList] + grElemList=[[],[]] + else: + elemList=[volElemList,surfElemList,edgeElemList] + grElemList=[[],[],[]] + + while ifChanged : + ifChanged=False + for elemId in elemList[0]: + minColor=sys.maxint + maxColor=-sys.maxint + for elemNodeId in mesh.GetElemNodes(elemId) : + nodeColor=colorList[elemNodeId-1] + if nodeColormaxColor : maxColor=nodeColor + if minColor!=maxColor : + ifChanged = True + for elemNodeId in mesh.GetElemNodes(elemId) : + colorList[elemNodeId-1]=maxColor + + for l in grElemList: + for x in range(len(sides)): + l.append([]) + + for N, el in enumerate(elemList): + for elemId in el: + elemNodesId=mesh.GetElemNodes(elemId) + elemColor=colorList[elemNodesId[0]-1] + if elemColor>=0: + grElemList[N][elemColor].append(elemId) + + #for elemId in surfElemList: + #elemNodesId=mesh.GetElemNodes(elemId) + #elemColor=colorList[elemNodesId[0]-1] + #if elemColor>=0: + #selem[elemColor].append(elemId) + + for n in range(len(sides)): + if case2D: + mesh.MakeGroupByIds('Extended_side%d' %n ,SMESH.FACE,grElemList[0][n]) + mesh.MakeGroupByIds('Extended_side%d' %n ,SMESH.EDGE,grElemList[1][n]) + else: + mesh.MakeGroupByIds('Extended_side%d' %n ,SMESH.VOLUME,grElemList[0][n]) + mesh.MakeGroupByIds('Extended_side%d' %n ,SMESH.FACE,grElemList[1][n]) + mesh.MakeGroupByIds('Extended_side%d' %n ,SMESH.EDGE,grElemList[2][n]) + + if outFile==None: outFile=meshFile + mesh.ExportMED(outFile, 0, SMESH.MED_V2_2, 1, None ,1) + return(True) + + +def cleanGroups(mesh): + import SMESH + for group in mesh.GetGroups(): + if '_bset' in group.GetName(): + group.SetName(group.GetName().replace('_bset','')) + + if group.GetType()==SMESH.NODE: + if group.GetName() in ['SURFACE','lip','SFRONT_NODES','FRONT']: mesh.RemoveGroup(group) + + #elif group.GetType()==SMESH.EDGE: + + elif group.GetType()==SMESH.FACE: + if group.GetName() in ['SURFACE','Nlip']: + mesh.RemoveGroup(group) + + elif group.GetType()==SMESH.VOLUME: + if (group.GetName() in ['ELSET0','AUTO']) or (group.GetName()[:4] in ['SIDE']) : + mesh.RemoveGroup(group) + + return(mesh) + + +def getMaxAspectRatio(tmpdir): + logFile=path.join(tmpdir,'MESHING_OUTPUT') + print logFile + if not path.isfile(logFile): return(-1) + + import re + f = open(logFile, "r") + for line in f: + if re.search("WORST ELEMENT QUALITY", line): maxAR=line + + f.close() + for r in [' ','WORSTELEMENTQUALITY','\n']: maxAR=maxAR.replace(r,'') + return(float(maxAR)) + + +#def extendElsets(meshFile): + #if not path.isfile(meshFile): + #message('E','Mesh med file is not valid') + #return(-1) + + #import SMESH, salome + ##salome.salome_init() + #theStudy = salome.myStudy + #from salome.smesh import smeshBuilder + #smesh = smeshBuilder.New(theStudy) + + #([mesh], status) = smesh.CreateMeshesFromMED(meshFile) + + ## Node color status + #nodeList=mesh.GetNodesId() + #colorList=[0]*len(nodeList) + + ## Init using SIDE0 SIDE1 + #for group in mesh.GetGroups(): + #if group.GetType()==SMESH.FACE : + #color=0 + #if group.GetName()[0:4]=='SIDE0' : + #color=1 + #elif group.GetName()[0:4]=='SIDE1' : + #color=2 + #else : continue + ## Get faces + #faces=group.GetIDs() + ## Set faces nodes to given color + #for face_id in faces : + #for face_node_id in mesh.GetElemNodes(face_id) : + #colorList[face_node_id-1]=color + + ## Propagates color using elem connectivity + ## Always propagates max color + #volElemList=mesh.GetElementsByType(SMESH.VOLUME) + #ifChanged=True + #while ifChanged : + #ifChanged=False + #minColor=100 + #maxColor=0 + #for elemId in volElemList: + #for elemNodeId in mesh.GetElemNodes(elemId) : + #nodeColor=colorList[elemNodeId-1] + #if nodeColormaxColor : maxColor=nodeColor + #if minColor!=maxColor : + #ifChanged = True + #for elemNodeId in mesh.GetElemNodes(elemId) : + #colorList[elemNodeId-1]=maxColor + + #velem0 = [] + #velem1 = [] + #for elemId in volElemList: + #elemNodesId=mesh.GetElemNodes(elemId) + #elemColor=colorList[elemNodesId[0]-1] + #if(elemColor==1) : velem0.append(elemId) + #if(elemColor==2) : velem1.append(elemId) + + #mesh.MakeGroupByIds('SIDE_co',SMESH.VOLUME,velem0) + #mesh.MakeGroupByIds('SIDE_ext',SMESH.VOLUME,velem1) + + #surfElemList=mesh.GetElementsByType(SMESH.FACE) + #selem0 = [] + #selem1 = [] + #nbelem0=0 + #nbelem1=0 + + #for elemId in surfElemList: + #elemNodesId=mesh.GetElemNodes(elemId) + #elemColor=colorList[elemNodesId[0]-1] + #if(elemColor==1) : selem0.append(elemId) + #if(elemColor==2) : selem1.append(elemId) + + #mesh.MakeGroupByIds('SIDE_co',SMESH.FACE,selem0) + #mesh.MakeGroupByIds('SIDE_ext',SMESH.FACE,selem1) + + #maxAR=0. + #for elem in volElemList: + #maxAR=max(mesh.GetAspectRatio(elem),maxAR) + #for elem in surfElemList: + #maxAR=max(mesh.GetAspectRatio(elem),maxAR) + + #mesh.ExportMED(meshFile, 0, SMESH.MED_V2_2, 1, None ,1) + #return(maxAR) + + +def removeFromSessionPath(envVar, patern): + if type(patern) is not list: patern=[patern] + if type(envVar) is not list: envVar=[envVar] + + for env in envVar: + path=environ[env] + listPath=path.split(':') + for p in listPath: + for pat in patern: + if pat in p: + path=path.replace(p,'') + path.replace('::',':') + environ[env]=path + + +#def isPlane(geomObject, eps=1.e-9): + #import salome + #salome.salome_init() + #theStudy = salome.myStudy + + #import salome_notebook + #notebook = salome_notebook.NoteBook(theStudy) + + #import GEOM + #from salome.geom import geomBuilder + #geompy = geomBuilder.New(theStudy) + + #Vs=geompy.SubShapeAll(geomObject, geompy.ShapeType["VERTEX"]) + #if len(Vs)<=3: + #return(True) + #elif len(Vs)>3: + #P0=numpy.array(geompy.GetPosition(Vs[0])[:3]) + #P1=numpy.array(geompy.GetPosition(Vs[1])[:3]) + #P2=numpy.array(geompy.GetPosition(Vs[2])[:3]) + #V01=P1-P0 + #V02=P2-P0 + #V12=P2-P1 + #norm01=numpy.linalg.norm(V01) + #norm02=numpy.linalg.norm(V02) + #norm12=numpy.linalg.norm(V12) + #if (norm01 + + + RunConfiguration0-BaseEnvironmentBase + 2 + + + RunConfiguration0-CommandLineArguments + + + + RunConfiguration0-ProFile + zcracks.pro + + + RunConfiguration0-RunConfiguration.name + zcracks + + + RunConfiguration0-UseDyldImageSuffix + false + + + RunConfiguration0-UseTerminal + false + + + RunConfiguration0-UserEnvironmentChanges + + + + RunConfiguration0-UserSetName + false + + + RunConfiguration0-UserSetWorkingDirectory + false + + + RunConfiguration0-UserWorkingDirectory + + + + RunConfiguration0-type + Qt4ProjectManager.Qt4RunConfiguration + + + activeRunConfiguration + 0 + + + activebuildconfiguration + Debug + + + buildConfiguration-Debug + + Debug + 0 + 0 + 2 + + + + buildConfiguration-Release + + Release + 0 + 0 + + + + buildconfiguration-Debug-buildstep0 + + Debug + + + + buildconfiguration-Debug-buildstep1 + + Debug + + + + buildconfiguration-Debug-cleanstep0 + + Debug + true + + clean + + + + + buildconfiguration-Release-buildstep0 + + Release + + + + buildconfiguration-Release-buildstep1 + + Release + + + + buildconfiguration-Release-cleanstep0 + + Release + + + + buildconfigurations + + Debug + Release + + + + buildstep0 + + + + + + + buildstep1 + + + + + + buildsteps + + trolltech.qt4projectmanager.qmake + trolltech.qt4projectmanager.make + + + + cleanstep0 + + + true + + + + cleansteps + + trolltech.qt4projectmanager.make + + + + defaultFileEncoding + System + + + project + + + diff --git a/src/Tools/ZCracksPlug/zcracks.ui b/src/Tools/ZCracksPlug/zcracks.ui new file mode 100644 index 000000000..d464158f1 --- /dev/null +++ b/src/Tools/ZCracksPlug/zcracks.ui @@ -0,0 +1,1726 @@ + + + Zui + + + + 0 + 0 + 709 + 540 + + + + + 709 + 540 + + + + + 709 + 540 + + + + + + + + + 255 + 255 + 255 + + + + + + + + + 255 + 255 + 255 + + + + + + + + + 255 + 255 + 255 + + + + + + + + Zcracks interface - version dev + + + + + + + + 3 + 497 + 301 + 37 + + + + + + + + 85 + 35 + + + + + 85 + 35 + + + + Clear all paramters + + + Reset + + + + + + + + 85 + 35 + + + + + 85 + 35 + + + + Save parameters in a file + + + Save + + + + + + + + 85 + 35 + + + + + 85 + 35 + + + + Load all parameters from a file + + + Load + + + + + + + + + 344 + 490 + 360 + 51 + + + + + + + + 100 + 35 + + + + + 100 + 35 + + + + Exit Zcracks + + + Cancel + + + + + + + + 100 + 35 + + + + + 100 + 35 + + + + Launch crack insertion + + + Apply + + + + + + + + 130 + 35 + + + + + 130 + 35 + + + + Launch crack insertion and quit + + + Apply and close + + + + + + + + + 3 + 6 + 309 + 255 + + + + QFrame::Panel + + + QFrame::Raised + + + 2 + + + 0 + + + + + -2 + 21 + 311 + 81 + + + + + 10 + + + 0 + + + 10 + + + 0 + + + 6 + + + + + + 112 + 0 + + + + + 76 + 16777215 + + + + Name of the resulting cracked mesh + + + + + + + + + + + + + + + Cracked name + + + + + + + + 118 + 0 + + + + file adress (ex: /home/A123456/cracked.med) + + + true + + + + + + + + 100 + 16777215 + + + + Name of the sane mesh + + + Sane mesh + + + + + + + file adress (ex: /home/A123456/cuve.med) + + + true + + + + + + + + + + + + + + 28 + 28 + + + + + 28 + 28 + + + + ... + + + + + + + + 28 + 28 + + + + + 28 + 28 + + + + ... + + + + + + + + + 0 + 0 + 311 + 28 + + + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + + + 118 + 118 + 117 + + + + + + + 118 + 118 + 117 + + + + + + + 255 + 255 + 255 + + + + + + + 118 + 118 + 117 + + + + + + + + + 75 + true + + + + General parameters + + + Mesh parameters + + + Qt::AlignCenter + + + + + + -2 + 102 + 311 + 161 + + + + + 10 + + + 0 + + + 10 + + + 0 + + + + + Maximum mesh size + + + Maximum size + + + + + + + Extraction length (optionnal) + + + Extraction length + + + + + + + float (ex: 1.E-04) + + + true + + + + + + + float (ex: 1.E-03) + + + true + + + + + + + float (ex: 1.E-04) + + + true + + + + + + + Quadratic cracked mesh + + + Quadratic + + + + + + + false + + + Use Barsoum (quarter nodes) elements at crack front + + + Barsoum + + + + + + + Minimum mesh size + + + Minimum size + + + + + + + + + + 2 + 265 + 309 + 226 + + + + QFrame::Panel + + + QFrame::Raised + + + 2 + + + 0 + + + + + -1 + 0 + 311 + 28 + + + + + 75 + true + + + + Groups to save (limit list to vital groups) + + + Groups + + + Qt::AlignCenter + + + + + + 0 + 14 + 311 + 220 + + + + + 10 + + + 10 + + + + + Groups of volumes to keep + + + Volumes + + + + + + + groups separated by a space (ex: Gr1 Gr2 Gr3) + + + true + + + + + + + Groups of faces to keep + + + Faces + + + + + + + groups separated by a space (ex: Gr1 Gr2 Gr3) + + + true + + + + + + + + + + + + + Groups of edges to keep + + + Edges + + + + + + + groups separated by a space (ex: Gr1 Gr2 Gr3) + + + true + + + + + + + Groups of nodes to keep + + + Nodes + + + + + + + groups separated by a space (ex: Gr1 Gr2 Gr3) + + + true + + + + + + + + 40 + 28 + + + + Load + + + + + + + + 40 + 28 + + + + Load + + + + + + + + 40 + 28 + + + + Load + + + + + + + + 40 + 28 + + + + Load + + + + + + + + 80 + 28 + + + + Load all + + + + + + + + + + 317 + 6 + 388 + 333 + + + + QFrame::Panel + + + QFrame::Raised + + + 2 + + + 0 + + + + + 4 + 23 + 378 + 306 + + + + + 0 + 270 + + + + + 16777215 + 331 + + + + 2 + + + + Ellipse + + + + + 0 + 0 + 375 + 271 + + + + + 0 + 0 + + + + + 16777215 + 301 + + + + + 0 + 0 + + + + + false + + + + false + + + Qt::DefaultContextMenu + + + false + + + + Centre + + + + 75 + false + true + + + + + + Normale + + + + 75 + true + + + + + + Rayon + + + + 75 + true + + + + + + Direction + + + + + Rayon 2 + + + + + Angle + + + + + Rayon entaille + + + + + Extension + + + + + Valeur + + + + + + + + + 75 + true + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + + + + + 75 + true + + + + + + + + + + 75 + true + + + + + + + + + + + + + + + + + + + + + + + 330 + 0 + 40 + 25 + + + + <html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Fissure de forme elliptique :</span></p><p><img src=":/newPrefix/images/schema_ellipse.png"/><br/></p><p><span style=" font-weight:600; text-decoration: underline;">Centre</span> : Coordonnées du centre de l'ellipse (ex: 0 0 1)</p><p><span style=" font-weight:600; text-decoration: underline;">Normale</span> : Coordonnées du vecteur normal à l'ellipse (ex: 1 0 0)</p><p><span style=" font-weight:600; text-decoration: underline;">Rayon</span> : Rayon de l'ellipse le long du vecteur direction (ex: 1.0e1)</p><p><span style=" text-decoration: underline;">Direction</span> : Coordonnées du vecteur direction de l'ellipse (ex: 0 1 0). Nécessaire pour une ellipse</p><p><span style=" text-decoration: underline;">Rayon 2</span> : Rayon de l'ellipse le long du vecteur orthogonal à normale et direction (ex: 1.0e1). Si vide égal à Rayon</p><p><span style=" text-decoration: underline;">Angle</span> : Angle en degrés pour une ellipse tronquée (ex: 180.). Si vide, l'ellipse n'est pas tronquée</p><p><span style=" text-decoration: underline;">Rayon entaille</span> : Rayon du fond d'entaille. (ex: 1.0e1). Si vide, la fissure est plane sans entaille</p><p><span style=" text-decoration: underline;">Extension</span> : Longueur d'extension de l'ellipse tronquée dans le long de la direction opposée à Direction (ex: 1.0)</p><p><span style=" font-weight:600; font-style:italic;">Gras : Informations obligatoires</span></p></body></html> + + + ? + + + Qt::AlignCenter + + + + + + Rectangle + + + + + 0 + 0 + 375 + 271 + + + + + 16777215 + 301 + + + + + Centre + + + + 75 + true + + + + + + Normale + + + + 75 + true + + + + + + Longueur + + + + 75 + true + + + + + + Direction + + + + 75 + true + + + + + + Largeur + + + + + Rayon + + + + + Angle + + + + + Rayon entaille + + + + + Valeur + + + + + + + + + + + + + + + + + + + + + + + + + + + 330 + 0 + 40 + 25 + + + + <html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Fissure de forme rectangulaire :</span></p><p><img src=":/newPrefix/images/schema_rectangle.png"/><br/></p><p><span style=" font-weight:600; text-decoration: underline;">Centre</span> : Coordonnées du centre du rectangle (ex: 0 0 1)</p><p><span style=" font-weight:600; text-decoration: underline;">Normale</span> : Coordonnées du vecteur normal au rectangle (ex: 1 0 0)</p><p><span style=" font-weight:600; text-decoration: underline;">Longueur</span> : Demie longueur du rectangle le long du vecteur direction (ex: 1.0e1)</p><p><span style=" font-weight:600; text-decoration: underline;">Direction</span> : Coordonnées du vecteur direction du rectangle (ex: 0 1 0)</p><p><span style=" text-decoration: underline;">Largeur</span> : Demie largeur du rectangle le long du vecteur orthogonal à normale et direction (ex: 1.0e1). Si vide, égal à Longueur</p><p><span style=" text-decoration: underline;">Rayon </span>: Rayon du congé aux angles du rectangle (ex: 1.0e1). Si vide, pas de congé</p><p><span style=" text-decoration: underline;">Angle</span> : Angle en degrés pour un rectangle tronqué (ex: 180.). Si vide, le rectangle n'est pas tronquée</p><p><span style=" text-decoration: underline;">Rayon entaille</span> : Rayon du fond d'entaille. (ex: 1.0e1). Si vide, la fissure est plane sans entaille</p><p><span style=" font-weight:600; font-style:italic;">Gras : Informations obligatoires</span></p></body></html> + + + ? + + + Qt::AlignCenter + + + + + + Sphere + + + + + 0 + 0 + 375 + 272 + + + + + 16777215 + 301 + + + + + Centre + + + + 75 + true + + + + + + Rayon + + + + 75 + true + + + + + + Valeur + + + + + + + 330 + 0 + 40 + 25 + + + + <html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Fissure de forme spherique :</span></p><p><img src=":/newPrefix/images/schema_shpere.png"/><br/></p><p><span style=" font-weight:600; text-decoration: underline;">Centre</span> : Coordonnées du centre de la sphere (ex: 0 0 1)</p><p><span style=" font-weight:600; text-decoration: underline;">Rayon</span> : Rayon de la sphere (ex: 1.0e1)</p><p><span style=" font-weight:600; font-style:italic;">Gras : Informations obligatoires</span></p></body></html> + + + ? + + + Qt::AlignCenter + + + + + + Custom + + + + + 0 + 0 + 375 + 271 + + + + + 16777215 + 301 + + + + + med file + + + + 75 + true + + + + + + File + + + + 50 + false + + + + + + + + + + + + + 330 + 0 + 40 + 25 + + + + <html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Fissure de forme personnalisée :</span></p><p><span style=" font-weight:600; text-decoration: underline;">Med file</span> : Adresse du maillage décrivant la fissure (ex: $HOME/PROJETX/fissure3.med)</p><p><span style=" font-style:italic;">Le maillage de la fissure doit être une surface composée de tétrahèdres linéaires uniquement.</span></p><p><span style=" font-weight:600; font-style:italic;">Gras : Informations obligatoires</span></p></body></html> + + + ? + + + Qt::AlignCenter + + + + + + + + 0 + 0 + 381 + 28 + + + + + 75 + true + + + + Crack automatic generation + + + Crack + + + Qt::AlignCenter + + + + + + true + + + + 317 + 344 + 388 + 147 + + + + QFrame::Panel + + + QFrame::Raised + + + 2 + + + 0 + + + + + 6 + 2 + 171 + 23 + + + + + 75 + true + + + + Advanced options (Use with caution) + + + Advanced options + + + + + + 0 + 24 + 427 + 106 + + + + + + 1 + 35 + 381 + 40 + + + + + 10 + + + 0 + + + 10 + + + 0 + + + + + + 85 + 28 + + + + + 85 + 28 + + + + Load all parameters from a file + + + Quick View + + + + + + + + 67 + 28 + + + + + 16777215 + 28 + + + + SURFOPT options + + + SURFOPT + + + + + + + + 0 + 28 + + + + + 16777215 + 28 + + + + string + + + true + + + + + + + + + + + + 0 + 80 + 81 + 26 + + + + Check if sane mesh is a surface + + + 2D case + + + + + + 90 + 80 + 92 + 26 + + + + Check to refine sane mesh before crack insertion + + + Pre refine + + + + + + 2 + 6 + 381 + 30 + + + + + 10 + + + 0 + + + 10 + + + 0 + + + + + + 0 + 28 + + + + Mesh increase parameter + + + Gradation + + + + + + + + 40 + 28 + + + + float (ex: 1.3) + + + true + + + 1.3 + + + + + + + + 50 + 28 + + + + Constant size layers number + + + Layers + + + + + + + + 69 + 0 + + + + + 16777215 + 28 + + + + Remeshing iterations number + + + Iterations + + + + + + + + 30 + 28 + + + + + 35 + 16777215 + + + + integer (ex: 5) + + + true + + + 5 + + + + + + + + 30 + 28 + + + + + 30 + 28 + + + + integer (ex: 2) + + + true + + + 2 + + + + + + + widget + CBAdvanced + + + + + + + diff --git a/src/Tools/ZCracksPlug/zcracksLaunch.py b/src/Tools/ZCracksPlug/zcracksLaunch.py new file mode 100755 index 000000000..fa7acf20e --- /dev/null +++ b/src/Tools/ZCracksPlug/zcracksLaunch.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import Zcracks +Zcracks.IHM() diff --git a/src/Tools/ZCracksPlug/zcracks_plugin.py b/src/Tools/ZCracksPlug/zcracks_plugin.py index efc45b187..60a09a8e7 100644 --- a/src/Tools/ZCracksPlug/zcracks_plugin.py +++ b/src/Tools/ZCracksPlug/zcracks_plugin.py @@ -18,21 +18,14 @@ # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # -import SalomePyQt -sgPyQt = SalomePyQt.SalomePyQt() -import eficasSalome - -class EficasForZcracks(eficasSalome.MyEficas): - """ - """ - def __init__(self, fichier = None, version = None): - eficasSalome.MyEficas.__init__(self, sgPyQt.getDesktop(), - "ZCRACKS", - fichier, version = version) - #sgPyQt.createView(custom_appli.widgetname, self) - +import os def ZcracksLct(context): - - window=EficasForZcracks() - window.show() + import os,subprocess + command = ". ${ZCRACKSHOME}/salome_do_config.sh ; " + command += 'zcracksLaunch.py &' + if command is not "": + try: + subprocess.check_call(command, executable = '/bin/bash', shell = True, bufsize=-1) + except Exception, e: + print "Error: ",e diff --git a/src/Tools/ZCracksPlug/zcracks_ui.py b/src/Tools/ZCracksPlug/zcracks_ui.py new file mode 100644 index 000000000..9b5d278b3 --- /dev/null +++ b/src/Tools/ZCracksPlug/zcracks_ui.py @@ -0,0 +1,738 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'zcracks.ui' +# +# Created: Wed Oct 19 07:56:41 2016 +# by: PyQt4 UI code generator 4.9.6 +# +# WARNING! All changes made in this file will be lost! + +from PyQt4 import QtCore, QtGui + +try: + _fromUtf8 = QtCore.QString.fromUtf8 +except AttributeError: + def _fromUtf8(s): + return s + +try: + _encoding = QtGui.QApplication.UnicodeUTF8 + def _translate(context, text, disambig): + return QtGui.QApplication.translate(context, text, disambig, _encoding) +except AttributeError: + def _translate(context, text, disambig): + return QtGui.QApplication.translate(context, text, disambig) + +class Ui_Zui(object): + def setupUi(self, Zui): + Zui.setObjectName(_fromUtf8("Zui")) + Zui.resize(709, 540) + Zui.setMinimumSize(QtCore.QSize(709, 540)) + Zui.setMaximumSize(QtCore.QSize(709, 540)) + palette = QtGui.QPalette() + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Base, brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Base, brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Base, brush) + Zui.setPalette(palette) + Zui.setTitle(_fromUtf8("")) + self.horizontalLayoutWidget = QtGui.QWidget(Zui) + self.horizontalLayoutWidget.setGeometry(QtCore.QRect(3, 497, 301, 37)) + self.horizontalLayoutWidget.setObjectName(_fromUtf8("horizontalLayoutWidget")) + self.horizontalLayout = QtGui.QHBoxLayout(self.horizontalLayoutWidget) + self.horizontalLayout.setMargin(0) + self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout")) + self.btReset = QtGui.QPushButton(self.horizontalLayoutWidget) + self.btReset.setMinimumSize(QtCore.QSize(85, 35)) + self.btReset.setMaximumSize(QtCore.QSize(85, 35)) + self.btReset.setObjectName(_fromUtf8("btReset")) + self.horizontalLayout.addWidget(self.btReset) + self.btSave = QtGui.QPushButton(self.horizontalLayoutWidget) + self.btSave.setMinimumSize(QtCore.QSize(85, 35)) + self.btSave.setMaximumSize(QtCore.QSize(85, 35)) + self.btSave.setObjectName(_fromUtf8("btSave")) + self.horizontalLayout.addWidget(self.btSave) + self.btLoad = QtGui.QPushButton(self.horizontalLayoutWidget) + self.btLoad.setMinimumSize(QtCore.QSize(85, 35)) + self.btLoad.setMaximumSize(QtCore.QSize(85, 35)) + self.btLoad.setObjectName(_fromUtf8("btLoad")) + self.horizontalLayout.addWidget(self.btLoad) + self.horizontalLayoutWidget_2 = QtGui.QWidget(Zui) + self.horizontalLayoutWidget_2.setGeometry(QtCore.QRect(344, 490, 360, 51)) + self.horizontalLayoutWidget_2.setObjectName(_fromUtf8("horizontalLayoutWidget_2")) + self.horizontalLayout_2 = QtGui.QHBoxLayout(self.horizontalLayoutWidget_2) + self.horizontalLayout_2.setMargin(0) + self.horizontalLayout_2.setObjectName(_fromUtf8("horizontalLayout_2")) + self.btCancel = QtGui.QPushButton(self.horizontalLayoutWidget_2) + self.btCancel.setMinimumSize(QtCore.QSize(100, 35)) + self.btCancel.setMaximumSize(QtCore.QSize(100, 35)) + self.btCancel.setObjectName(_fromUtf8("btCancel")) + self.horizontalLayout_2.addWidget(self.btCancel) + self.btApply = QtGui.QPushButton(self.horizontalLayoutWidget_2) + self.btApply.setMinimumSize(QtCore.QSize(100, 35)) + self.btApply.setMaximumSize(QtCore.QSize(100, 35)) + self.btApply.setObjectName(_fromUtf8("btApply")) + self.horizontalLayout_2.addWidget(self.btApply) + self.btApplyClose = QtGui.QPushButton(self.horizontalLayoutWidget_2) + self.btApplyClose.setMinimumSize(QtCore.QSize(130, 35)) + self.btApplyClose.setMaximumSize(QtCore.QSize(130, 35)) + self.btApplyClose.setObjectName(_fromUtf8("btApplyClose")) + self.horizontalLayout_2.addWidget(self.btApplyClose) + self.frame = QtGui.QFrame(Zui) + self.frame.setGeometry(QtCore.QRect(3, 6, 309, 255)) + self.frame.setFrameShape(QtGui.QFrame.Panel) + self.frame.setFrameShadow(QtGui.QFrame.Raised) + self.frame.setLineWidth(2) + self.frame.setMidLineWidth(0) + self.frame.setObjectName(_fromUtf8("frame")) + self.gridLayoutWidget = QtGui.QWidget(self.frame) + self.gridLayoutWidget.setGeometry(QtCore.QRect(-2, 21, 311, 81)) + self.gridLayoutWidget.setObjectName(_fromUtf8("gridLayoutWidget")) + self.gridLayout = QtGui.QGridLayout(self.gridLayoutWidget) + self.gridLayout.setSpacing(6) + self.gridLayout.setContentsMargins(10, 0, 10, 0) + self.gridLayout.setObjectName(_fromUtf8("gridLayout")) + self.txtCrackedName = QtGui.QLabel(self.gridLayoutWidget) + self.txtCrackedName.setMinimumSize(QtCore.QSize(112, 0)) + self.txtCrackedName.setMaximumSize(QtCore.QSize(76, 16777215)) + self.txtCrackedName.setStatusTip(_fromUtf8("")) + self.txtCrackedName.setWhatsThis(_fromUtf8("")) + self.txtCrackedName.setAccessibleName(_fromUtf8("")) + self.txtCrackedName.setAccessibleDescription(_fromUtf8("")) + self.txtCrackedName.setObjectName(_fromUtf8("txtCrackedName")) + self.gridLayout.addWidget(self.txtCrackedName, 0, 0, 1, 1) + self.valCrackedName = QtGui.QLineEdit(self.gridLayoutWidget) + self.valCrackedName.setMinimumSize(QtCore.QSize(118, 0)) + self.valCrackedName.setAutoFillBackground(True) + self.valCrackedName.setObjectName(_fromUtf8("valCrackedName")) + self.gridLayout.addWidget(self.valCrackedName, 0, 1, 1, 1) + self.txtSaneName = QtGui.QLabel(self.gridLayoutWidget) + self.txtSaneName.setMaximumSize(QtCore.QSize(100, 16777215)) + self.txtSaneName.setObjectName(_fromUtf8("txtSaneName")) + self.gridLayout.addWidget(self.txtSaneName, 1, 0, 1, 1) + self.valSaneName = QtGui.QLineEdit(self.gridLayoutWidget) + self.valSaneName.setToolTip(_fromUtf8("file adress (ex: /home/A123456/cuve.med)")) + self.valSaneName.setAutoFillBackground(True) + self.valSaneName.setInputMask(_fromUtf8("")) + self.valSaneName.setText(_fromUtf8("")) + self.valSaneName.setObjectName(_fromUtf8("valSaneName")) + self.gridLayout.addWidget(self.valSaneName, 1, 1, 1, 1) + self.btLoadCracked = QtGui.QPushButton(self.gridLayoutWidget) + self.btLoadCracked.setMinimumSize(QtCore.QSize(28, 28)) + self.btLoadCracked.setMaximumSize(QtCore.QSize(28, 28)) + self.btLoadCracked.setObjectName(_fromUtf8("btLoadCracked")) + self.gridLayout.addWidget(self.btLoadCracked, 0, 2, 1, 1) + self.btLoadSane = QtGui.QPushButton(self.gridLayoutWidget) + self.btLoadSane.setMinimumSize(QtCore.QSize(28, 28)) + self.btLoadSane.setMaximumSize(QtCore.QSize(28, 28)) + self.btLoadSane.setObjectName(_fromUtf8("btLoadSane")) + self.gridLayout.addWidget(self.btLoadSane, 1, 2, 1, 1) + self.cracked_name_2 = QtGui.QLabel(self.frame) + self.cracked_name_2.setGeometry(QtCore.QRect(0, 0, 311, 28)) + palette = QtGui.QPalette() + brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.WindowText, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Text, brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.BrightText, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.ButtonText, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.WindowText, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Text, brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.BrightText, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.ButtonText, brush) + brush = QtGui.QBrush(QtGui.QColor(118, 118, 117)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.WindowText, brush) + brush = QtGui.QBrush(QtGui.QColor(118, 118, 117)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Text, brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.BrightText, brush) + brush = QtGui.QBrush(QtGui.QColor(118, 118, 117)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.ButtonText, brush) + self.cracked_name_2.setPalette(palette) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.cracked_name_2.setFont(font) + self.cracked_name_2.setAlignment(QtCore.Qt.AlignCenter) + self.cracked_name_2.setObjectName(_fromUtf8("cracked_name_2")) + self.gridLayoutWidget_3 = QtGui.QWidget(self.frame) + self.gridLayoutWidget_3.setGeometry(QtCore.QRect(-2, 102, 311, 161)) + self.gridLayoutWidget_3.setObjectName(_fromUtf8("gridLayoutWidget_3")) + self.gridLayout_3 = QtGui.QGridLayout(self.gridLayoutWidget_3) + self.gridLayout_3.setContentsMargins(10, 0, 10, 0) + self.gridLayout_3.setObjectName(_fromUtf8("gridLayout_3")) + self.txtMaxSize = QtGui.QLabel(self.gridLayoutWidget_3) + self.txtMaxSize.setObjectName(_fromUtf8("txtMaxSize")) + self.gridLayout_3.addWidget(self.txtMaxSize, 1, 0, 1, 1) + self.txtExtractLength = QtGui.QLabel(self.gridLayoutWidget_3) + self.txtExtractLength.setObjectName(_fromUtf8("txtExtractLength")) + self.gridLayout_3.addWidget(self.txtExtractLength, 2, 0, 1, 1) + self.valMinSize = QtGui.QLineEdit(self.gridLayoutWidget_3) + self.valMinSize.setAutoFillBackground(True) + self.valMinSize.setObjectName(_fromUtf8("valMinSize")) + self.gridLayout_3.addWidget(self.valMinSize, 0, 1, 1, 1) + self.valMaxSize = QtGui.QLineEdit(self.gridLayoutWidget_3) + self.valMaxSize.setAutoFillBackground(True) + self.valMaxSize.setObjectName(_fromUtf8("valMaxSize")) + self.gridLayout_3.addWidget(self.valMaxSize, 1, 1, 1, 1) + self.valExtractLength = QtGui.QLineEdit(self.gridLayoutWidget_3) + self.valExtractLength.setAutoFillBackground(True) + self.valExtractLength.setObjectName(_fromUtf8("valExtractLength")) + self.gridLayout_3.addWidget(self.valExtractLength, 2, 1, 1, 1) + self.CBQuad = QtGui.QCheckBox(self.gridLayoutWidget_3) + self.CBQuad.setObjectName(_fromUtf8("CBQuad")) + self.gridLayout_3.addWidget(self.CBQuad, 3, 0, 1, 1) + self.CBBarsoum = QtGui.QCheckBox(self.gridLayoutWidget_3) + self.CBBarsoum.setEnabled(False) + self.CBBarsoum.setObjectName(_fromUtf8("CBBarsoum")) + self.gridLayout_3.addWidget(self.CBBarsoum, 3, 1, 1, 1) + self.txtMinSize = QtGui.QLabel(self.gridLayoutWidget_3) + self.txtMinSize.setObjectName(_fromUtf8("txtMinSize")) + self.gridLayout_3.addWidget(self.txtMinSize, 0, 0, 1, 1) + self.frame_2 = QtGui.QFrame(Zui) + self.frame_2.setGeometry(QtCore.QRect(2, 265, 309, 226)) + self.frame_2.setFrameShape(QtGui.QFrame.Panel) + self.frame_2.setFrameShadow(QtGui.QFrame.Raised) + self.frame_2.setLineWidth(2) + self.frame_2.setMidLineWidth(0) + self.frame_2.setObjectName(_fromUtf8("frame_2")) + self.labelCrackedName = QtGui.QLabel(self.frame_2) + self.labelCrackedName.setGeometry(QtCore.QRect(-1, 0, 311, 28)) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.labelCrackedName.setFont(font) + self.labelCrackedName.setAlignment(QtCore.Qt.AlignCenter) + self.labelCrackedName.setObjectName(_fromUtf8("labelCrackedName")) + self.gridLayoutWidget_2 = QtGui.QWidget(self.frame_2) + self.gridLayoutWidget_2.setGeometry(QtCore.QRect(0, 14, 311, 220)) + self.gridLayoutWidget_2.setObjectName(_fromUtf8("gridLayoutWidget_2")) + self.gridLayout_2 = QtGui.QGridLayout(self.gridLayoutWidget_2) + self.gridLayout_2.setMargin(10) + self.gridLayout_2.setSpacing(10) + self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2")) + self.txtGrVol = QtGui.QLabel(self.gridLayoutWidget_2) + self.txtGrVol.setObjectName(_fromUtf8("txtGrVol")) + self.gridLayout_2.addWidget(self.txtGrVol, 0, 0, 1, 1) + self.valGrVol = QtGui.QLineEdit(self.gridLayoutWidget_2) + self.valGrVol.setAutoFillBackground(True) + self.valGrVol.setObjectName(_fromUtf8("valGrVol")) + self.gridLayout_2.addWidget(self.valGrVol, 0, 1, 1, 1) + self.txtGrFace = QtGui.QLabel(self.gridLayoutWidget_2) + self.txtGrFace.setToolTip(_fromUtf8("Groups of faces to keep")) + self.txtGrFace.setObjectName(_fromUtf8("txtGrFace")) + self.gridLayout_2.addWidget(self.txtGrFace, 1, 0, 1, 1) + self.valGrFace = QtGui.QLineEdit(self.gridLayoutWidget_2) + self.valGrFace.setToolTip(_fromUtf8("groups separated by a space (ex: Gr1 Gr2 Gr3)")) + self.valGrFace.setAutoFillBackground(True) + self.valGrFace.setInputMask(_fromUtf8("")) + self.valGrFace.setText(_fromUtf8("")) + self.valGrFace.setObjectName(_fromUtf8("valGrFace")) + self.gridLayout_2.addWidget(self.valGrFace, 1, 1, 1, 1) + self.txtGrEdge = QtGui.QLabel(self.gridLayoutWidget_2) + self.txtGrEdge.setObjectName(_fromUtf8("txtGrEdge")) + self.gridLayout_2.addWidget(self.txtGrEdge, 2, 0, 1, 1) + self.valGrEdge = QtGui.QLineEdit(self.gridLayoutWidget_2) + self.valGrEdge.setAutoFillBackground(True) + self.valGrEdge.setObjectName(_fromUtf8("valGrEdge")) + self.gridLayout_2.addWidget(self.valGrEdge, 2, 1, 1, 1) + self.txtGrNode = QtGui.QLabel(self.gridLayoutWidget_2) + self.txtGrNode.setObjectName(_fromUtf8("txtGrNode")) + self.gridLayout_2.addWidget(self.txtGrNode, 3, 0, 1, 1) + self.valGrNode = QtGui.QLineEdit(self.gridLayoutWidget_2) + self.valGrNode.setAutoFillBackground(True) + self.valGrNode.setObjectName(_fromUtf8("valGrNode")) + self.gridLayout_2.addWidget(self.valGrNode, 3, 1, 1, 1) + self.btGrVol = QtGui.QPushButton(self.gridLayoutWidget_2) + self.btGrVol.setMaximumSize(QtCore.QSize(40, 28)) + self.btGrVol.setObjectName(_fromUtf8("btGrVol")) + self.gridLayout_2.addWidget(self.btGrVol, 0, 2, 1, 1) + self.btGrFace = QtGui.QPushButton(self.gridLayoutWidget_2) + self.btGrFace.setMaximumSize(QtCore.QSize(40, 28)) + self.btGrFace.setObjectName(_fromUtf8("btGrFace")) + self.gridLayout_2.addWidget(self.btGrFace, 1, 2, 1, 1) + self.btGrEdge = QtGui.QPushButton(self.gridLayoutWidget_2) + self.btGrEdge.setMaximumSize(QtCore.QSize(40, 28)) + self.btGrEdge.setObjectName(_fromUtf8("btGrEdge")) + self.gridLayout_2.addWidget(self.btGrEdge, 2, 2, 1, 1) + self.btGrNode = QtGui.QPushButton(self.gridLayoutWidget_2) + self.btGrNode.setMaximumSize(QtCore.QSize(40, 28)) + self.btGrNode.setObjectName(_fromUtf8("btGrNode")) + self.gridLayout_2.addWidget(self.btGrNode, 3, 2, 1, 1) + self.btGrAll = QtGui.QPushButton(self.gridLayoutWidget_2) + self.btGrAll.setMaximumSize(QtCore.QSize(80, 28)) + self.btGrAll.setObjectName(_fromUtf8("btGrAll")) + self.gridLayout_2.addWidget(self.btGrAll, 4, 1, 1, 1) + self.frame_3 = QtGui.QFrame(Zui) + self.frame_3.setGeometry(QtCore.QRect(317, 6, 388, 333)) + self.frame_3.setFrameShape(QtGui.QFrame.Panel) + self.frame_3.setFrameShadow(QtGui.QFrame.Raised) + self.frame_3.setLineWidth(2) + self.frame_3.setMidLineWidth(0) + self.frame_3.setObjectName(_fromUtf8("frame_3")) + self.tabWidget = QtGui.QTabWidget(self.frame_3) + self.tabWidget.setGeometry(QtCore.QRect(4, 23, 378, 306)) + self.tabWidget.setMinimumSize(QtCore.QSize(0, 270)) + self.tabWidget.setMaximumSize(QtCore.QSize(16777215, 331)) + self.tabWidget.setObjectName(_fromUtf8("tabWidget")) + self.ongletEllipse = QtGui.QWidget() + self.ongletEllipse.setObjectName(_fromUtf8("ongletEllipse")) + self.tabEllipse = QtGui.QTableWidget(self.ongletEllipse) + self.tabEllipse.setGeometry(QtCore.QRect(0, 0, 375, 271)) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.tabEllipse.sizePolicy().hasHeightForWidth()) + self.tabEllipse.setSizePolicy(sizePolicy) + self.tabEllipse.setMaximumSize(QtCore.QSize(16777215, 301)) + self.tabEllipse.setBaseSize(QtCore.QSize(0, 0)) + font = QtGui.QFont() + font.setUnderline(False) + self.tabEllipse.setFont(font) + self.tabEllipse.setMouseTracking(False) + self.tabEllipse.setContextMenuPolicy(QtCore.Qt.DefaultContextMenu) + self.tabEllipse.setAutoFillBackground(False) + self.tabEllipse.setObjectName(_fromUtf8("tabEllipse")) + self.tabEllipse.setColumnCount(1) + self.tabEllipse.setRowCount(8) + item = QtGui.QTableWidgetItem() + font = QtGui.QFont() + font.setBold(True) + font.setItalic(False) + font.setWeight(75) + item.setFont(font) + self.tabEllipse.setVerticalHeaderItem(0, item) + item = QtGui.QTableWidgetItem() + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + item.setFont(font) + self.tabEllipse.setVerticalHeaderItem(1, item) + item = QtGui.QTableWidgetItem() + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + item.setFont(font) + self.tabEllipse.setVerticalHeaderItem(2, item) + item = QtGui.QTableWidgetItem() + self.tabEllipse.setVerticalHeaderItem(3, item) + item = QtGui.QTableWidgetItem() + self.tabEllipse.setVerticalHeaderItem(4, item) + item = QtGui.QTableWidgetItem() + self.tabEllipse.setVerticalHeaderItem(5, item) + item = QtGui.QTableWidgetItem() + self.tabEllipse.setVerticalHeaderItem(6, item) + item = QtGui.QTableWidgetItem() + self.tabEllipse.setVerticalHeaderItem(7, item) + item = QtGui.QTableWidgetItem() + self.tabEllipse.setHorizontalHeaderItem(0, item) + item = QtGui.QTableWidgetItem() + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + item.setFont(font) + brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) + brush.setStyle(QtCore.Qt.NoBrush) + item.setBackground(brush) + brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) + brush.setStyle(QtCore.Qt.NoBrush) + item.setForeground(brush) + self.tabEllipse.setItem(0, 0, item) + item = QtGui.QTableWidgetItem() + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + item.setFont(font) + self.tabEllipse.setItem(1, 0, item) + item = QtGui.QTableWidgetItem() + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + item.setFont(font) + self.tabEllipse.setItem(2, 0, item) + item = QtGui.QTableWidgetItem() + self.tabEllipse.setItem(3, 0, item) + item = QtGui.QTableWidgetItem() + self.tabEllipse.setItem(4, 0, item) + item = QtGui.QTableWidgetItem() + self.tabEllipse.setItem(5, 0, item) + self.infoEllipse = QtGui.QLabel(self.ongletEllipse) + self.infoEllipse.setGeometry(QtCore.QRect(330, 0, 40, 25)) + self.infoEllipse.setAlignment(QtCore.Qt.AlignCenter) + self.infoEllipse.setObjectName(_fromUtf8("infoEllipse")) + self.tabWidget.addTab(self.ongletEllipse, _fromUtf8("")) + self.ongletRectangle = QtGui.QWidget() + self.ongletRectangle.setObjectName(_fromUtf8("ongletRectangle")) + self.tabRectangle = QtGui.QTableWidget(self.ongletRectangle) + self.tabRectangle.setGeometry(QtCore.QRect(0, 0, 375, 271)) + self.tabRectangle.setMaximumSize(QtCore.QSize(16777215, 301)) + self.tabRectangle.setObjectName(_fromUtf8("tabRectangle")) + self.tabRectangle.setColumnCount(1) + self.tabRectangle.setRowCount(8) + item = QtGui.QTableWidgetItem() + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + item.setFont(font) + self.tabRectangle.setVerticalHeaderItem(0, item) + item = QtGui.QTableWidgetItem() + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + item.setFont(font) + self.tabRectangle.setVerticalHeaderItem(1, item) + item = QtGui.QTableWidgetItem() + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + item.setFont(font) + self.tabRectangle.setVerticalHeaderItem(2, item) + item = QtGui.QTableWidgetItem() + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + item.setFont(font) + self.tabRectangle.setVerticalHeaderItem(3, item) + item = QtGui.QTableWidgetItem() + self.tabRectangle.setVerticalHeaderItem(4, item) + item = QtGui.QTableWidgetItem() + self.tabRectangle.setVerticalHeaderItem(5, item) + item = QtGui.QTableWidgetItem() + self.tabRectangle.setVerticalHeaderItem(6, item) + item = QtGui.QTableWidgetItem() + self.tabRectangle.setVerticalHeaderItem(7, item) + item = QtGui.QTableWidgetItem() + self.tabRectangle.setHorizontalHeaderItem(0, item) + item = QtGui.QTableWidgetItem() + self.tabRectangle.setItem(3, 0, item) + item = QtGui.QTableWidgetItem() + self.tabRectangle.setItem(4, 0, item) + item = QtGui.QTableWidgetItem() + self.tabRectangle.setItem(5, 0, item) + item = QtGui.QTableWidgetItem() + self.tabRectangle.setItem(6, 0, item) + self.infoRectangle = QtGui.QLabel(self.ongletRectangle) + self.infoRectangle.setGeometry(QtCore.QRect(330, 0, 40, 25)) + self.infoRectangle.setAlignment(QtCore.Qt.AlignCenter) + self.infoRectangle.setObjectName(_fromUtf8("infoRectangle")) + self.tabWidget.addTab(self.ongletRectangle, _fromUtf8("")) + self.ongletSphere = QtGui.QWidget() + self.ongletSphere.setObjectName(_fromUtf8("ongletSphere")) + self.tabSphere = QtGui.QTableWidget(self.ongletSphere) + self.tabSphere.setGeometry(QtCore.QRect(0, 0, 375, 272)) + self.tabSphere.setMaximumSize(QtCore.QSize(16777215, 301)) + self.tabSphere.setObjectName(_fromUtf8("tabSphere")) + self.tabSphere.setColumnCount(1) + self.tabSphere.setRowCount(2) + item = QtGui.QTableWidgetItem() + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + item.setFont(font) + self.tabSphere.setVerticalHeaderItem(0, item) + item = QtGui.QTableWidgetItem() + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + item.setFont(font) + self.tabSphere.setVerticalHeaderItem(1, item) + item = QtGui.QTableWidgetItem() + self.tabSphere.setHorizontalHeaderItem(0, item) + self.infoSphere = QtGui.QLabel(self.ongletSphere) + self.infoSphere.setGeometry(QtCore.QRect(330, 0, 40, 25)) + self.infoSphere.setAlignment(QtCore.Qt.AlignCenter) + self.infoSphere.setObjectName(_fromUtf8("infoSphere")) + self.tabWidget.addTab(self.ongletSphere, _fromUtf8("")) + self.ongletPerso = QtGui.QWidget() + self.ongletPerso.setObjectName(_fromUtf8("ongletPerso")) + self.tabPerso = QtGui.QTableWidget(self.ongletPerso) + self.tabPerso.setGeometry(QtCore.QRect(0, 0, 375, 271)) + self.tabPerso.setMaximumSize(QtCore.QSize(16777215, 301)) + self.tabPerso.setObjectName(_fromUtf8("tabPerso")) + self.tabPerso.setColumnCount(1) + self.tabPerso.setRowCount(1) + item = QtGui.QTableWidgetItem() + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + item.setFont(font) + self.tabPerso.setVerticalHeaderItem(0, item) + item = QtGui.QTableWidgetItem() + font = QtGui.QFont() + font.setBold(False) + font.setWeight(50) + item.setFont(font) + self.tabPerso.setHorizontalHeaderItem(0, item) + item = QtGui.QTableWidgetItem() + self.tabPerso.setItem(0, 0, item) + self.infoCustom = QtGui.QLabel(self.ongletPerso) + self.infoCustom.setGeometry(QtCore.QRect(330, 0, 40, 25)) + self.infoCustom.setAlignment(QtCore.Qt.AlignCenter) + self.infoCustom.setObjectName(_fromUtf8("infoCustom")) + self.tabWidget.addTab(self.ongletPerso, _fromUtf8("")) + self.labelCrackName = QtGui.QLabel(self.frame_3) + self.labelCrackName.setGeometry(QtCore.QRect(0, 0, 381, 28)) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.labelCrackName.setFont(font) + self.labelCrackName.setAlignment(QtCore.Qt.AlignCenter) + self.labelCrackName.setObjectName(_fromUtf8("labelCrackName")) + self.frame_4 = QtGui.QFrame(Zui) + self.frame_4.setEnabled(True) + self.frame_4.setGeometry(QtCore.QRect(317, 344, 388, 147)) + self.frame_4.setFrameShape(QtGui.QFrame.Panel) + self.frame_4.setFrameShadow(QtGui.QFrame.Raised) + self.frame_4.setLineWidth(2) + self.frame_4.setMidLineWidth(0) + self.frame_4.setObjectName(_fromUtf8("frame_4")) + self.CBAdvanced = QtGui.QCheckBox(self.frame_4) + self.CBAdvanced.setGeometry(QtCore.QRect(6, 2, 171, 23)) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.CBAdvanced.setFont(font) + self.CBAdvanced.setObjectName(_fromUtf8("CBAdvanced")) + self.widget = QtGui.QWidget(self.frame_4) + self.widget.setGeometry(QtCore.QRect(0, 24, 427, 106)) + self.widget.setObjectName(_fromUtf8("widget")) + self.gridLayoutWidget_9 = QtGui.QWidget(self.widget) + self.gridLayoutWidget_9.setGeometry(QtCore.QRect(1, 35, 381, 40)) + self.gridLayoutWidget_9.setObjectName(_fromUtf8("gridLayoutWidget_9")) + self.gridLayout_9 = QtGui.QGridLayout(self.gridLayoutWidget_9) + self.gridLayout_9.setContentsMargins(10, 0, 10, 0) + self.gridLayout_9.setObjectName(_fromUtf8("gridLayout_9")) + self.btVisu = QtGui.QPushButton(self.gridLayoutWidget_9) + self.btVisu.setMinimumSize(QtCore.QSize(85, 28)) + self.btVisu.setMaximumSize(QtCore.QSize(85, 28)) + self.btVisu.setObjectName(_fromUtf8("btVisu")) + self.gridLayout_9.addWidget(self.btVisu, 0, 0, 1, 1) + self.txtSurfopt = QtGui.QLabel(self.gridLayoutWidget_9) + self.txtSurfopt.setMinimumSize(QtCore.QSize(67, 28)) + self.txtSurfopt.setMaximumSize(QtCore.QSize(16777215, 28)) + self.txtSurfopt.setObjectName(_fromUtf8("txtSurfopt")) + self.gridLayout_9.addWidget(self.txtSurfopt, 0, 1, 1, 1) + self.valSurfopt = QtGui.QLineEdit(self.gridLayoutWidget_9) + self.valSurfopt.setMinimumSize(QtCore.QSize(0, 28)) + self.valSurfopt.setMaximumSize(QtCore.QSize(16777215, 28)) + self.valSurfopt.setAutoFillBackground(True) + self.valSurfopt.setText(_fromUtf8("")) + self.valSurfopt.setObjectName(_fromUtf8("valSurfopt")) + self.gridLayout_9.addWidget(self.valSurfopt, 0, 2, 1, 1) + self.CBIs2D = QtGui.QCheckBox(self.widget) + self.CBIs2D.setGeometry(QtCore.QRect(0, 80, 81, 26)) + self.CBIs2D.setObjectName(_fromUtf8("CBIs2D")) + self.CBRefine = QtGui.QCheckBox(self.widget) + self.CBRefine.setGeometry(QtCore.QRect(90, 80, 92, 26)) + self.CBRefine.setObjectName(_fromUtf8("CBRefine")) + self.gridLayoutWidget_8 = QtGui.QWidget(self.widget) + self.gridLayoutWidget_8.setGeometry(QtCore.QRect(2, 6, 381, 30)) + self.gridLayoutWidget_8.setObjectName(_fromUtf8("gridLayoutWidget_8")) + self.gridLayout_8 = QtGui.QGridLayout(self.gridLayoutWidget_8) + self.gridLayout_8.setContentsMargins(10, 0, 10, 0) + self.gridLayout_8.setObjectName(_fromUtf8("gridLayout_8")) + self.txtGradation = QtGui.QLabel(self.gridLayoutWidget_8) + self.txtGradation.setMinimumSize(QtCore.QSize(0, 28)) + self.txtGradation.setObjectName(_fromUtf8("txtGradation")) + self.gridLayout_8.addWidget(self.txtGradation, 0, 0, 1, 1) + self.valGradation = QtGui.QLineEdit(self.gridLayoutWidget_8) + self.valGradation.setMinimumSize(QtCore.QSize(40, 28)) + self.valGradation.setAutoFillBackground(True) + self.valGradation.setObjectName(_fromUtf8("valGradation")) + self.gridLayout_8.addWidget(self.valGradation, 0, 1, 1, 1) + self.txtLayers = QtGui.QLabel(self.gridLayoutWidget_8) + self.txtLayers.setMinimumSize(QtCore.QSize(50, 28)) + self.txtLayers.setObjectName(_fromUtf8("txtLayers")) + self.gridLayout_8.addWidget(self.txtLayers, 0, 2, 1, 1) + self.txtIterations = QtGui.QLabel(self.gridLayoutWidget_8) + self.txtIterations.setMinimumSize(QtCore.QSize(69, 0)) + self.txtIterations.setMaximumSize(QtCore.QSize(16777215, 28)) + self.txtIterations.setObjectName(_fromUtf8("txtIterations")) + self.gridLayout_8.addWidget(self.txtIterations, 0, 4, 1, 1) + self.valLayers = QtGui.QLineEdit(self.gridLayoutWidget_8) + self.valLayers.setMinimumSize(QtCore.QSize(30, 28)) + self.valLayers.setMaximumSize(QtCore.QSize(35, 16777215)) + self.valLayers.setAutoFillBackground(True) + self.valLayers.setObjectName(_fromUtf8("valLayers")) + self.gridLayout_8.addWidget(self.valLayers, 0, 3, 1, 1) + self.valIterations = QtGui.QLineEdit(self.gridLayoutWidget_8) + self.valIterations.setMinimumSize(QtCore.QSize(30, 28)) + self.valIterations.setMaximumSize(QtCore.QSize(30, 28)) + self.valIterations.setAutoFillBackground(True) + self.valIterations.setObjectName(_fromUtf8("valIterations")) + self.gridLayout_8.addWidget(self.valIterations, 0, 5, 1, 1) + + self.retranslateUi(Zui) + self.tabWidget.setCurrentIndex(2) + QtCore.QMetaObject.connectSlotsByName(Zui) + + def retranslateUi(self, Zui): + Zui.setWindowTitle(_translate("Zui", "Zcracks interface - version dev", None)) + self.btReset.setToolTip(_translate("Zui", "Clear all paramters", None)) + self.btReset.setText(_translate("Zui", "Reset", None)) + self.btSave.setToolTip(_translate("Zui", "Save parameters in a file", None)) + self.btSave.setText(_translate("Zui", "Save", None)) + self.btLoad.setToolTip(_translate("Zui", "Load all parameters from a file", None)) + self.btLoad.setText(_translate("Zui", "Load", None)) + self.btCancel.setToolTip(_translate("Zui", "Exit Zcracks", None)) + self.btCancel.setText(_translate("Zui", "Cancel", None)) + self.btApply.setToolTip(_translate("Zui", "Launch crack insertion", None)) + self.btApply.setText(_translate("Zui", "Apply", None)) + self.btApplyClose.setToolTip(_translate("Zui", "Launch crack insertion and quit", None)) + self.btApplyClose.setText(_translate("Zui", "Apply and close", None)) + self.txtCrackedName.setToolTip(_translate("Zui", "Name of the resulting cracked mesh", None)) + self.txtCrackedName.setText(_translate("Zui", "Cracked name", None)) + self.valCrackedName.setToolTip(_translate("Zui", "file adress (ex: /home/A123456/cracked.med)", None)) + self.txtSaneName.setToolTip(_translate("Zui", "Name of the sane mesh", None)) + self.txtSaneName.setText(_translate("Zui", "Sane mesh", None)) + self.btLoadCracked.setText(_translate("Zui", "...", None)) + self.btLoadSane.setText(_translate("Zui", "...", None)) + self.cracked_name_2.setToolTip(_translate("Zui", "General parameters", None)) + self.cracked_name_2.setText(_translate("Zui", "Mesh parameters", None)) + self.txtMaxSize.setToolTip(_translate("Zui", "Maximum mesh size", None)) + self.txtMaxSize.setText(_translate("Zui", "Maximum size", None)) + self.txtExtractLength.setToolTip(_translate("Zui", "Extraction length (optionnal)", None)) + self.txtExtractLength.setText(_translate("Zui", "Extraction length", None)) + self.valMinSize.setToolTip(_translate("Zui", "float (ex: 1.E-04)", None)) + self.valMaxSize.setToolTip(_translate("Zui", "float (ex: 1.E-03)", None)) + self.valExtractLength.setToolTip(_translate("Zui", "float (ex: 1.E-04)", None)) + self.CBQuad.setToolTip(_translate("Zui", "Quadratic cracked mesh", None)) + self.CBQuad.setText(_translate("Zui", "Quadratic", None)) + self.CBBarsoum.setToolTip(_translate("Zui", "Use Barsoum (quarter nodes) elements at crack front", None)) + self.CBBarsoum.setText(_translate("Zui", "Barsoum", None)) + self.txtMinSize.setToolTip(_translate("Zui", "Minimum mesh size", None)) + self.txtMinSize.setText(_translate("Zui", "Minimum size", None)) + self.labelCrackedName.setToolTip(_translate("Zui", "Groups to save (limit list to vital groups)", None)) + self.labelCrackedName.setText(_translate("Zui", "Groups", None)) + self.txtGrVol.setToolTip(_translate("Zui", "Groups of volumes to keep", None)) + self.txtGrVol.setText(_translate("Zui", "Volumes", None)) + self.valGrVol.setToolTip(_translate("Zui", "groups separated by a space (ex: Gr1 Gr2 Gr3)", None)) + self.txtGrFace.setText(_translate("Zui", "Faces", None)) + self.txtGrEdge.setToolTip(_translate("Zui", "Groups of edges to keep", None)) + self.txtGrEdge.setText(_translate("Zui", "Edges", None)) + self.valGrEdge.setToolTip(_translate("Zui", "groups separated by a space (ex: Gr1 Gr2 Gr3)", None)) + self.txtGrNode.setToolTip(_translate("Zui", "Groups of nodes to keep", None)) + self.txtGrNode.setText(_translate("Zui", "Nodes", None)) + self.valGrNode.setToolTip(_translate("Zui", "groups separated by a space (ex: Gr1 Gr2 Gr3)", None)) + self.btGrVol.setText(_translate("Zui", "Load", None)) + self.btGrFace.setText(_translate("Zui", "Load", None)) + self.btGrEdge.setText(_translate("Zui", "Load", None)) + self.btGrNode.setText(_translate("Zui", "Load", None)) + self.btGrAll.setText(_translate("Zui", "Load all", None)) + item = self.tabEllipse.verticalHeaderItem(0) + item.setText(_translate("Zui", "Centre", None)) + item = self.tabEllipse.verticalHeaderItem(1) + item.setText(_translate("Zui", "Normale", None)) + item = self.tabEllipse.verticalHeaderItem(2) + item.setText(_translate("Zui", "Rayon", None)) + item = self.tabEllipse.verticalHeaderItem(3) + item.setText(_translate("Zui", "Direction", None)) + item = self.tabEllipse.verticalHeaderItem(4) + item.setText(_translate("Zui", "Rayon 2", None)) + item = self.tabEllipse.verticalHeaderItem(5) + item.setText(_translate("Zui", "Angle", None)) + item = self.tabEllipse.verticalHeaderItem(6) + item.setText(_translate("Zui", "Rayon entaille", None)) + item = self.tabEllipse.verticalHeaderItem(7) + item.setText(_translate("Zui", "Extension", None)) + item = self.tabEllipse.horizontalHeaderItem(0) + item.setText(_translate("Zui", "Valeur", None)) + __sortingEnabled = self.tabEllipse.isSortingEnabled() + self.tabEllipse.setSortingEnabled(False) + self.tabEllipse.setSortingEnabled(__sortingEnabled) + self.infoEllipse.setToolTip(_translate("Zui", "

    Fissure de forme elliptique :


    Centre : Coordonnées du centre de l\'ellipse (ex: 0 0 1)

    Normale : Coordonnées du vecteur normal à l\'ellipse (ex: 1 0 0)

    Rayon : Rayon de l\'ellipse le long du vecteur direction (ex: 1.0e1)

    Direction : Coordonnées du vecteur direction de l\'ellipse (ex: 0 1 0). Nécessaire pour une ellipse

    Rayon 2 : Rayon de l\'ellipse le long du vecteur orthogonal à normale et direction (ex: 1.0e1). Si vide égal à Rayon

    Angle : Angle en degrés pour une ellipse tronquée (ex: 180.). Si vide, l\'ellipse n\'est pas tronquée

    Rayon entaille : Rayon du fond d\'entaille. (ex: 1.0e1). Si vide, la fissure est plane sans entaille

    Extension : Longueur d\'extension de l\'ellipse tronquée dans le long de la direction opposée à Direction (ex: 1.0)

    Gras : Informations obligatoires

    ", None)) + self.infoEllipse.setText(_translate("Zui", "?", None)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.ongletEllipse), _translate("Zui", "Ellipse", None)) + item = self.tabRectangle.verticalHeaderItem(0) + item.setText(_translate("Zui", "Centre", None)) + item = self.tabRectangle.verticalHeaderItem(1) + item.setText(_translate("Zui", "Normale", None)) + item = self.tabRectangle.verticalHeaderItem(2) + item.setText(_translate("Zui", "Longueur", None)) + item = self.tabRectangle.verticalHeaderItem(3) + item.setText(_translate("Zui", "Direction", None)) + item = self.tabRectangle.verticalHeaderItem(4) + item.setText(_translate("Zui", "Largeur", None)) + item = self.tabRectangle.verticalHeaderItem(5) + item.setText(_translate("Zui", "Rayon", None)) + item = self.tabRectangle.verticalHeaderItem(6) + item.setText(_translate("Zui", "Angle", None)) + item = self.tabRectangle.verticalHeaderItem(7) + item.setText(_translate("Zui", "Rayon entaille", None)) + item = self.tabRectangle.horizontalHeaderItem(0) + item.setText(_translate("Zui", "Valeur", None)) + __sortingEnabled = self.tabRectangle.isSortingEnabled() + self.tabRectangle.setSortingEnabled(False) + self.tabRectangle.setSortingEnabled(__sortingEnabled) + self.infoRectangle.setToolTip(_translate("Zui", "

    Fissure de forme rectangulaire :


    Centre : Coordonnées du centre du rectangle (ex: 0 0 1)

    Normale : Coordonnées du vecteur normal au rectangle (ex: 1 0 0)

    Longueur : Demie longueur du rectangle le long du vecteur direction (ex: 1.0e1)

    Direction : Coordonnées du vecteur direction du rectangle (ex: 0 1 0)

    Largeur : Demie largeur du rectangle le long du vecteur orthogonal à normale et direction (ex: 1.0e1). Si vide, égal à Longueur

    Rayon : Rayon du congé aux angles du rectangle (ex: 1.0e1). Si vide, pas de congé

    Angle : Angle en degrés pour un rectangle tronqué (ex: 180.). Si vide, le rectangle n\'est pas tronquée

    Rayon entaille : Rayon du fond d\'entaille. (ex: 1.0e1). Si vide, la fissure est plane sans entaille

    Gras : Informations obligatoires

    ", None)) + self.infoRectangle.setText(_translate("Zui", "?", None)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.ongletRectangle), _translate("Zui", "Rectangle", None)) + item = self.tabSphere.verticalHeaderItem(0) + item.setText(_translate("Zui", "Centre", None)) + item = self.tabSphere.verticalHeaderItem(1) + item.setText(_translate("Zui", "Rayon", None)) + item = self.tabSphere.horizontalHeaderItem(0) + item.setText(_translate("Zui", "Valeur", None)) + self.infoSphere.setToolTip(_translate("Zui", "

    Fissure de forme spherique :


    Centre : Coordonnées du centre de la sphere (ex: 0 0 1)

    Rayon : Rayon de la sphere (ex: 1.0e1)

    Gras : Informations obligatoires

    ", None)) + self.infoSphere.setText(_translate("Zui", "?", None)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.ongletSphere), _translate("Zui", "Sphere", None)) + item = self.tabPerso.verticalHeaderItem(0) + item.setText(_translate("Zui", "med file", None)) + item = self.tabPerso.horizontalHeaderItem(0) + item.setText(_translate("Zui", "File", None)) + __sortingEnabled = self.tabPerso.isSortingEnabled() + self.tabPerso.setSortingEnabled(False) + self.tabPerso.setSortingEnabled(__sortingEnabled) + self.infoCustom.setToolTip(_translate("Zui", "

    Fissure de forme personnalisée :

    Med file : Adresse du maillage décrivant la fissure (ex: $HOME/PROJETX/fissure3.med)

    Le maillage de la fissure doit être une surface composée de tétrahèdres linéaires uniquement.

    Gras : Informations obligatoires

    ", None)) + self.infoCustom.setText(_translate("Zui", "?", None)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.ongletPerso), _translate("Zui", "Custom", None)) + self.labelCrackName.setToolTip(_translate("Zui", "Crack automatic generation", None)) + self.labelCrackName.setText(_translate("Zui", "Crack", None)) + self.CBAdvanced.setToolTip(_translate("Zui", "Advanced options (Use with caution)", None)) + self.CBAdvanced.setText(_translate("Zui", "Advanced options", None)) + self.btVisu.setToolTip(_translate("Zui", "Load all parameters from a file", None)) + self.btVisu.setText(_translate("Zui", "Quick View", None)) + self.txtSurfopt.setToolTip(_translate("Zui", "SURFOPT options", None)) + self.txtSurfopt.setText(_translate("Zui", "SURFOPT", None)) + self.valSurfopt.setToolTip(_translate("Zui", "string", None)) + self.CBIs2D.setToolTip(_translate("Zui", "Check if sane mesh is a surface", None)) + self.CBIs2D.setText(_translate("Zui", "2D case", None)) + self.CBRefine.setToolTip(_translate("Zui", "Check to refine sane mesh before crack insertion", None)) + self.CBRefine.setText(_translate("Zui", "Pre refine", None)) + self.txtGradation.setToolTip(_translate("Zui", "Mesh increase parameter", None)) + self.txtGradation.setText(_translate("Zui", "Gradation", None)) + self.valGradation.setToolTip(_translate("Zui", "float (ex: 1.3)", None)) + self.valGradation.setText(_translate("Zui", "1.3", None)) + self.txtLayers.setToolTip(_translate("Zui", "Constant size layers number", None)) + self.txtLayers.setText(_translate("Zui", "Layers", None)) + self.txtIterations.setToolTip(_translate("Zui", "Remeshing iterations number", None)) + self.txtIterations.setText(_translate("Zui", "Iterations", None)) + self.valLayers.setToolTip(_translate("Zui", "integer (ex: 5)", None)) + self.valLayers.setText(_translate("Zui", "5", None)) + self.valIterations.setToolTip(_translate("Zui", "integer (ex: 2)", None)) + self.valIterations.setText(_translate("Zui", "2", None)) + +import images_rc diff --git a/src/Tools/smesh_plugins.py b/src/Tools/smesh_plugins.py index 3c81d72fa..2b2ad4b60 100644 --- a/src/Tools/smesh_plugins.py +++ b/src/Tools/smesh_plugins.py @@ -17,9 +17,10 @@ # # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # -# Author : Guillaume Boulant (EDF) +# Author : Guillaume Boulant (EDF) # import salome_pluginsmanager +import os try: from spadderPlugin import runSpadderPlugin @@ -75,15 +76,16 @@ except: salome_pluginsmanager.logger.info('ERROR: Meshed Pipe with a crack plug-in is unavailable') pass -# ZCracks plugin requires the module EFICAS to be installed -# thus it is first tested if this module is available before -# adding the plugin to salome_pluginsmanager +# ZCracks plugin requires the Zcracks tool try: - import eficasSalome - from zcracks_plugin import ZcracksLct - salome_pluginsmanager.AddFunction('Run Zcrack', - 'Run Zcrack', - ZcracksLct) + zcracksHome=os.environ['ZCRACKSHOME'] + if len(zcracksHome) > 1: + #print 'ZCRACKSHOME ', zcracksHome + from Zcracks.zcracks_plugin import ZcracksLct + salome_pluginsmanager.AddFunction('Run Zcrack', + 'Run Zcrack', + ZcracksLct) except: + #print 'probleme zcracks' salome_pluginsmanager.logger.info('ERROR: Zcrack plug-in is unavailable') pass -- 2.30.2