X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSMESH_SWIG%2FsmeshBuilder.py;h=2c7211828d54774216d8c8a6fbdb613a0d35b386;hb=HEAD;hp=05710d64c2853f408ab41c40654f6194f17a92d2;hpb=e7811c61c3565ada368be484f20e7fcac4a9f2cb;p=modules%2Fsmesh.git diff --git a/src/SMESH_SWIG/smeshBuilder.py b/src/SMESH_SWIG/smeshBuilder.py index 05710d64c..607314411 100644 --- a/src/SMESH_SWIG/smeshBuilder.py +++ b/src/SMESH_SWIG/smeshBuilder.py @@ -1,4 +1,4 @@ -# Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE +# Copyright (C) 2007-2024 CEA, EDF, OPEN CASCADE # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -24,12 +24,102 @@ import salome from salome.geom import geomBuilder import SMESH # This is necessary for back compatibility -from SMESH import * -from salome.smesh.smesh_algorithm import Mesh_Algorithm +import omniORB # back compatibility +SMESH.MED_V2_1 = 11 #omniORB.EnumItem("MED_V2_1", 11) # back compatibility: use number > MED minor version +SMESH.MED_V2_2 = 12 #omniORB.EnumItem("MED_V2_2", 12) # back compatibility: latest minor will be used +SMESH.MED_MINOR_0 = 20 # back compatibility +SMESH.MED_MINOR_1 = 21 # back compatibility +SMESH.MED_MINOR_2 = 22 # back compatibility +SMESH.MED_MINOR_3 = 23 # back compatibility +SMESH.MED_MINOR_4 = 24 # back compatibility +SMESH.MED_MINOR_5 = 25 # back compatibility +SMESH.MED_MINOR_6 = 26 # back compatibility +SMESH.MED_MINOR_7 = 27 # back compatibility +SMESH.MED_MINOR_8 = 28 # back compatibility +SMESH.MED_MINOR_9 = 29 # back compatibility + +from SMESH import * +from salome.smesh.smesh_algorithm import Mesh_Algorithm +from StdMeshers import BlockCS import SALOME import SALOMEDS import os +import inspect + +# In case the omniORBpy EnumItem class does not fully support Python 3 +# (for instance in version 4.2.1-2), the comparison ordering methods must be +# defined +# +try: + SMESH.Entity_Triangle < SMESH.Entity_Quadrangle +except TypeError: + def enumitem_eq(self, other): + try: + if isinstance(other, omniORB.EnumItem): + if other._parent_id == self._parent_id: + return self._v == other._v + else: + return self._parent_id == other._parent_id + else: + return id(self) == id(other) + except: + return id(self) == id(other) + + def enumitem_lt(self, other): + try: + if isinstance(other, omniORB.EnumItem): + if other._parent_id == self._parent_id: + return self._v < other._v + else: + return self._parent_id < other._parent_id + else: + return id(self) < id(other) + except: + return id(self) < id(other) + + def enumitem_le(self, other): + try: + if isinstance(other, omniORB.EnumItem): + if other._parent_id == self._parent_id: + return self._v <= other._v + else: + return self._parent_id <= other._parent_id + else: + return id(self) <= id(other) + except: + return id(self) <= id(other) + + def enumitem_gt(self, other): + try: + if isinstance(other, omniORB.EnumItem): + if other._parent_id == self._parent_id: + return self._v > other._v + else: + return self._parent_id > other._parent_id + else: + return id(self) > id(other) + except: + return id(self) > id(other) + + def enumitem_ge(self, other): + try: + if isinstance(other, omniORB.EnumItem): + if other._parent_id == self._parent_id: + return self._v >= other._v + else: + return self._parent_id >= other._parent_id + else: + return id(self) >= id(other) + except: + return id(self) >= id(other) + + omniORB.EnumItem.__eq__ = enumitem_eq + omniORB.EnumItem.__lt__ = enumitem_lt + omniORB.EnumItem.__le__ = enumitem_le + omniORB.EnumItem.__gt__ = enumitem_gt + omniORB.EnumItem.__ge__ = enumitem_ge + class MeshMeta(type): """Private class used to workaround a problem that sometimes isinstance(m, Mesh) returns False @@ -63,7 +153,7 @@ def ParseParameters(*args): Parameters = "" hasVariables = False varModifFun=None - if args and callable( args[-1] ): + if args and callable(args[-1]): args, varModifFun = args[:-1], args[-1] for parameter in args: @@ -72,7 +162,7 @@ def ParseParameters(*args): if isinstance(parameter,str): # check if there is an inexistent variable name if not notebook.isVariable(parameter): - raise ValueError, "Variable with name '" + parameter + "' doesn't exist!!!" + raise ValueError("Variable with name '" + parameter + "' doesn't exist!!!") parameter = notebook.get(parameter) hasVariables = True if varModifFun: @@ -108,8 +198,7 @@ def __initAxisStruct(ax,*args): Parameters are stored in AxisStruct.parameters attribute """ if len( args ) != 6: - raise RuntimeError,\ - "Bad nb args (%s) passed in SMESH.AxisStruct(x,y,z,dx,dy,dz)"%(len( args )) + raise RuntimeError("Bad nb args (%s) passed in SMESH.AxisStruct(x,y,z,dx,dy,dz)"%(len( args ))) ax.x, ax.y, ax.z, ax.vx, ax.vy, ax.vz, ax.parameters,hasVars = ParseParameters(*args) pass SMESH.AxisStruct.__init__ = __initAxisStruct @@ -127,7 +216,7 @@ NO_NAME = "NoName" def GetName(obj): """ Return a name of an object - + Returns: object name """ @@ -141,13 +230,8 @@ def GetName(obj): except: ior = None if ior: - # CORBA object - studies = salome.myStudyManager.GetOpenStudies() - for sname in studies: - s = salome.myStudyManager.GetStudyByName(sname) - if not s: continue - sobj = s.FindObjectIOR(ior) - if not sobj: continue + sobj = salome.myStudy.FindObjectIOR(ior) + if sobj: return sobj.GetName() if hasattr(obj, "GetName"): # unknown CORBA object, having GetName() method @@ -160,7 +244,7 @@ def GetName(obj): # unknown non-CORBA object, having GetName() method return obj.GetName() pass - raise RuntimeError, "Null or invalid object" + raise RuntimeError("Null or invalid object") def TreatHypoStatus(status, hypName, geomName, isAlgo, mesh): """ @@ -173,21 +257,21 @@ def TreatHypoStatus(status, hypName, geomName, isAlgo, mesh): pass reason = "" if hasattr( status, "__getitem__" ): - status,reason = status[0],status[1] - if status == HYP_UNKNOWN_FATAL : + status, reason = status[0], status[1] + if status == HYP_UNKNOWN_FATAL: reason = "for unknown reason" - elif status == HYP_INCOMPATIBLE : + elif status == HYP_INCOMPATIBLE: reason = "this hypothesis mismatches the algorithm" - elif status == HYP_NOTCONFORM : + elif status == HYP_NOTCONFORM: reason = "a non-conform mesh would be built" - elif status == HYP_ALREADY_EXIST : + elif status == HYP_ALREADY_EXIST: if isAlgo: return # it does not influence anything reason = hypType + " of the same dimension is already assigned to this shape" - elif status == HYP_BAD_DIM : + elif status == HYP_BAD_DIM: reason = hypType + " mismatches the shape" elif status == HYP_CONCURRENT : reason = "there are concurrent hypotheses on sub-shapes" - elif status == HYP_BAD_SUBSHAPE : + elif status == HYP_BAD_SUBSHAPE: reason = "the shape is neither the main one, nor its sub-shape, nor a valid group" elif status == HYP_BAD_GEOMETRY: reason = "the algorithm is not applicable to this geometry" @@ -209,25 +293,22 @@ def TreatHypoStatus(status, hypName, geomName, isAlgo, mesh): if meshName and meshName != NO_NAME: where = '"%s" shape in "%s" mesh ' % ( geomName, meshName ) if status < HYP_UNKNOWN_FATAL and where: - print '"%s" was assigned to %s but %s' %( hypName, where, reason ) + print('"%s" was assigned to %s but %s' %( hypName, where, reason )) elif where: - print '"%s" was not assigned to %s : %s' %( hypName, where, reason ) + print('"%s" was not assigned to %s : %s' %( hypName, where, reason )) else: - print '"%s" was not assigned : %s' %( hypName, reason ) + print('"%s" was not assigned : %s' %( hypName, reason )) pass def AssureGeomPublished(mesh, geom, name=''): """ Private method. Add geom (sub-shape of the main shape) into the study if not yet there """ - if not isinstance( geom, geomBuilder.GEOM._objref_GEOM_Object ): + if not mesh.smeshpyD.IsEnablePublish(): + return + if not hasattr( geom, "GetShapeType" ): return - if not geom.GetStudyEntry() and \ - mesh.smeshpyD.GetCurrentStudy(): - ## set the study - studyID = mesh.smeshpyD.GetCurrentStudy()._get_StudyId() - if studyID != mesh.geompyD.myStudyId: - mesh.geompyD.init_geom( mesh.smeshpyD.GetCurrentStudy()) + if not geom.GetStudyEntry(): ## get a name if not name and geom.GetShapeType() != geomBuilder.GEOM.COMPOUND: # for all groups SubShapeName() return "Compound_-1" @@ -238,27 +319,13 @@ def AssureGeomPublished(mesh, geom, name=''): mesh.geompyD.addToStudyInFather( mesh.geom, geom, name ) return -def FirstVertexOnCurve(mesh, edge): - """ - Returns: - the first vertex of a geometrical edge by ignoring orientation - """ - vv = mesh.geompyD.SubShapeAll( edge, geomBuilder.geomBuilder.ShapeType["VERTEX"]) - if not vv: - raise TypeError, "Given object has no vertices" - if len( vv ) == 1: return vv[0] - v0 = mesh.geompyD.MakeVertexOnCurve(edge,0.) - xyz = mesh.geompyD.PointCoordinates( v0 ) # coords of the first vertex - xyz1 = mesh.geompyD.PointCoordinates( vv[0] ) - xyz2 = mesh.geompyD.PointCoordinates( vv[1] ) - dist1, dist2 = 0,0 - for i in range(3): - dist1 += abs( xyz[i] - xyz1[i] ) - dist2 += abs( xyz[i] - xyz2[i] ) - if dist1 < dist2: - return vv[0] - else: - return vv[1] +# def FirstVertexOnCurve(mesh, edge): +# """ +# Returns: +# the first vertex of a geometrical edge by ignoring orientation +# """ +# return mesh.geompyD.GetVertexByIndex( edge, 0, False ) + smeshInst = None """ @@ -269,7 +336,7 @@ engine = None doLcc = False created = False -class smeshBuilder(object, SMESH._objref_SMESH_Gen): +class smeshBuilder( SMESH._objref_SMESH_Gen, object ): """ This class allows to create, load or manipulate meshes. It has a set of methods to create, load or copy meshes, to combine several meshes, etc. @@ -288,16 +355,16 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): PrecisionConfusion = smeshPrecisionConfusion # TopAbs_State enumeration - [TopAbs_IN, TopAbs_OUT, TopAbs_ON, TopAbs_UNKNOWN] = range(4) + [TopAbs_IN, TopAbs_OUT, TopAbs_ON, TopAbs_UNKNOWN] = list(range(4)) # Methods of splitting a hexahedron into tetrahedra Hex_5Tet, Hex_6Tet, Hex_24Tet, Hex_2Prisms, Hex_4Prisms = 1, 2, 3, 1, 2 - def __new__(cls): + def __new__(cls, *args): global engine global smeshInst global doLcc - #print "==== __new__", engine, smeshInst, doLcc + #print("==== __new__", engine, smeshInst, doLcc) if smeshInst is None: # smesh engine is either retrieved from engine, or created @@ -312,30 +379,31 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): # FindOrLoadComponent called: # 1. CORBA resolution of server # 2. the __new__ method is called again - #print "==== smeshInst = lcc.FindOrLoadComponent ", engine, smeshInst, doLcc + #print("==== smeshInst = lcc.FindOrLoadComponent ", engine, smeshInst, doLcc) smeshInst = salome.lcc.FindOrLoadComponent( "FactoryServer", "SMESH" ) else: # FindOrLoadComponent not called if smeshInst is None: # smeshBuilder instance is created from lcc.FindOrLoadComponent - #print "==== smeshInst = super(smeshBuilder,cls).__new__(cls) ", engine, smeshInst, doLcc + #print("==== smeshInst = super(smeshBuilder,cls).__new__(cls) ", engine, smeshInst, doLcc) smeshInst = super(smeshBuilder,cls).__new__(cls) else: # smesh engine not created: existing engine found - #print "==== existing ", engine, smeshInst, doLcc + #print("==== existing ", engine, smeshInst, doLcc) pass - #print "====1 ", smeshInst + #print("====1 ", smeshInst) return smeshInst - #print "====2 ", smeshInst + #print("====2 ", smeshInst) return smeshInst - def __init__(self): + def __init__(self, *args): global created - #print "--------------- smeshbuilder __init__ ---", created + #print("--------------- smeshbuilder __init__ ---", created) if not created: - created = True - SMESH._objref_SMESH_Gen.__init__(self) + created = True + SMESH._objref_SMESH_Gen.__init__(self, *args) + def DumpPython(self, theStudy, theIsPublished=True, theIsMultiFile=True): """ @@ -358,32 +426,29 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): else: val = "false" SMESH._objref_SMESH_Gen.SetOption(self, "historical_python_dump", val) - def init_smesh(self,theStudy,geompyD = None): + def init_smesh(self,geompyD = None): """ - Set the current study and Geometry component + Set Geometry component """ - - #print "init_smesh" - self.SetCurrentStudy(theStudy,geompyD) - if theStudy: - global notebook - notebook.myStudy = theStudy + #print("init_smesh") + self.UpdateStudy(geompyD) + notebook.myStudy = salome.myStudy def Mesh(self, obj=0, name=0): """ - Create a mesh. This mesh can be either + Create a mesh. This mesh can be either * an empty mesh not bound to geometry, if *obj* == 0 * an empty mesh bound to geometry, if *obj* is GEOM.GEOM_Object * a mesh wrapping a :class:`CORBA mesh ` given as *obj* parameter. Parameters: - obj: either + obj: either 1. a :class:`CORBA mesh ` got by calling e.g. :: - salome.myStudy.FindObjectID("0:1:2:3").GetObject() + salome.myStudy.FindObjectID("0:1:2:3").GetObject() 2. a geometrical object for meshing 3. none. @@ -395,7 +460,41 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): if isinstance(obj,str): obj,name = name,obj - return Mesh(self,self.geompyD,obj,name) + return Mesh(self, self.geompyD, obj, name) + + def ParallelMesh(self, obj, name=0, split_geom=True): + """ + Create a parallel mesh. + + Parameters: + obj: geometrical object for meshing + name: the name for the new mesh. + split_geom: If True split the geometry and create the assoicated + sub meshes + + Returns: + an instance of class :class:`ParallelMesh`. + """ + return ParallelMesh(self, self.geompyD, obj, + split_geom=split_geom, name=name) + + def RemoveMesh( self, mesh ): + """ + Delete a mesh + """ + if isinstance( mesh, Mesh ): + mesh = mesh.GetMesh() + pass + if not isinstance( mesh, SMESH._objref_SMESH_Mesh ): + raise TypeError("%s is not a mesh" % mesh ) + so = salome.ObjectToSObject( mesh ) + if so: + sb = salome.myStudy.NewBuilder() + sb.RemoveObjectWithChildren( so ) + else: + mesh.UnRegister() + pass + return def EnumToLong(self,theItem): """ @@ -422,7 +521,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): elif isinstance(c, str): val = c else: - raise ValueError, "Color value should be of string or SALOMEDS.Color type" + raise ValueError("Color value should be of string or SALOMEDS.Color type") return val def GetPointStruct(self,theVertex): @@ -435,8 +534,8 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): Returns: :class:`SMESH.PointStruct` """ - - [x, y, z] = self.geompyD.PointCoordinates(theVertex) + geompyD = theVertex.GetGen() + [x, y, z] = geompyD.PointCoordinates(theVertex) return PointStruct(x,y,z) def GetDirStruct(self,theVector): @@ -449,13 +548,13 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): Returns: :class:`SMESH.DirStruct` """ - - vertices = self.geompyD.SubShapeAll( theVector, geomBuilder.geomBuilder.ShapeType["VERTEX"] ) + geompyD = theVector.GetGen() + vertices = geompyD.SubShapeAll( theVector, geomBuilder.geomBuilder.ShapeType["VERTEX"] ) if(len(vertices) != 2): - print "Error: vector object is incorrect." + print("Error: vector object is incorrect.") return None - p1 = self.geompyD.PointCoordinates(vertices[0]) - p2 = self.geompyD.PointCoordinates(vertices[1]) + p1 = geompyD.PointCoordinates(vertices[0]) + p2 = geompyD.PointCoordinates(vertices[1]) pnt = PointStruct(p2[0]-p1[0], p2[1]-p1[1], p2[2]-p1[2]) dirst = DirStruct(pnt) return dirst @@ -485,28 +584,29 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): :class:`SMESH.AxisStruct` """ import GEOM - edges = self.geompyD.SubShapeAll( theObj, geomBuilder.geomBuilder.ShapeType["EDGE"] ) + geompyD = theObj.GetGen() + edges = geompyD.SubShapeAll( theObj, geomBuilder.geomBuilder.ShapeType["EDGE"] ) axis = None if len(edges) > 1: - vertex1, vertex2 = self.geompyD.SubShapeAll( edges[0], geomBuilder.geomBuilder.ShapeType["VERTEX"] ) - vertex3, vertex4 = self.geompyD.SubShapeAll( edges[1], geomBuilder.geomBuilder.ShapeType["VERTEX"] ) - vertex1 = self.geompyD.PointCoordinates(vertex1) - vertex2 = self.geompyD.PointCoordinates(vertex2) - vertex3 = self.geompyD.PointCoordinates(vertex3) - vertex4 = self.geompyD.PointCoordinates(vertex4) + vertex1, vertex2 = geompyD.SubShapeAll( edges[0], geomBuilder.geomBuilder.ShapeType["VERTEX"] ) + vertex3, vertex4 = geompyD.SubShapeAll( edges[1], geomBuilder.geomBuilder.ShapeType["VERTEX"] ) + vertex1 = geompyD.PointCoordinates(vertex1) + vertex2 = geompyD.PointCoordinates(vertex2) + vertex3 = geompyD.PointCoordinates(vertex3) + vertex4 = geompyD.PointCoordinates(vertex4) v1 = [vertex2[0]-vertex1[0], vertex2[1]-vertex1[1], vertex2[2]-vertex1[2]] v2 = [vertex4[0]-vertex3[0], vertex4[1]-vertex3[1], vertex4[2]-vertex3[2]] normal = [ v1[1]*v2[2]-v2[1]*v1[2], v1[2]*v2[0]-v2[2]*v1[0], v1[0]*v2[1]-v2[0]*v1[1] ] axis = AxisStruct(vertex1[0], vertex1[1], vertex1[2], normal[0], normal[1], normal[2]) axis._mirrorType = SMESH.SMESH_MeshEditor.PLANE elif len(edges) == 1: - vertex1, vertex2 = self.geompyD.SubShapeAll( edges[0], geomBuilder.geomBuilder.ShapeType["VERTEX"] ) - p1 = self.geompyD.PointCoordinates( vertex1 ) - p2 = self.geompyD.PointCoordinates( vertex2 ) + vertex1, vertex2 = geompyD.SubShapeAll( edges[0], geomBuilder.geomBuilder.ShapeType["VERTEX"] ) + p1 = geompyD.PointCoordinates( vertex1 ) + p2 = geompyD.PointCoordinates( vertex2 ) axis = AxisStruct(p1[0], p1[1], p1[2], p2[0]-p1[0], p2[1]-p1[1], p2[2]-p1[2]) axis._mirrorType = SMESH.SMESH_MeshEditor.AXIS elif theObj.GetShapeType() == GEOM.VERTEX: - x,y,z = self.geompyD.PointCoordinates( theObj ) + x,y,z = geompyD.PointCoordinates( theObj ) axis = AxisStruct( x,y,z, 1,0,0,) axis._mirrorType = SMESH.SMESH_MeshEditor.POINT return axis @@ -544,37 +644,37 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): return SMESH._objref_SMESH_Gen.IsEmbeddedMode(self) - def SetCurrentStudy( self, theStudy, geompyD = None ): + def UpdateStudy( self, geompyD = None ): """ - Set the current study. Calling SetCurrentStudy( None ) allows to - switch **off** automatic pubilishing in the Study of mesh objects. + Update the current study. Calling UpdateStudy() allows to + update meshes at switching GEOM->SMESH """ - + #self.UpdateStudy() if not geompyD: from salome.geom import geomBuilder geompyD = geomBuilder.geom + if not geompyD: + geompyD = geomBuilder.New() pass self.geompyD=geompyD self.SetGeomEngine(geompyD) - SMESH._objref_SMESH_Gen.SetCurrentStudy(self,theStudy) - global notebook - if theStudy: - notebook = salome_notebook.NoteBook( theStudy ) - else: - notebook = salome_notebook.NoteBook( salome_notebook.PseudoStudyForNoteBook() ) - if theStudy: - sb = theStudy.NewBuilder() - sc = theStudy.FindComponent("SMESH") - if sc: sb.LoadWith(sc, self) - pass + SMESH._objref_SMESH_Gen.UpdateStudy(self) + sb = salome.myStudy.NewBuilder() + sc = salome.myStudy.FindComponent("SMESH") + if sc: + sb.LoadWith(sc, self) pass - def GetCurrentStudy(self): + def SetEnablePublish( self, theIsEnablePublish ): """ - Get the current study + Set enable publishing in the study. Calling SetEnablePublish( False ) allows to + switch **off** publishing in the Study of mesh objects. """ + #self.SetEnablePublish(theIsEnablePublish) + SMESH._objref_SMESH_Gen.SetEnablePublish(self,theIsEnablePublish) + global notebook + notebook = salome_notebook.NoteBook( theIsEnablePublish ) - return SMESH._objref_SMESH_Gen.GetCurrentStudy(self) def CreateMeshesFromUNV( self,theFileName ): """ @@ -593,7 +693,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): Create a Mesh object(s) importing data from the given MED file Returns: - a tuple ( list of class :class:`Mesh` instances, + a tuple ( list of class :class:`Mesh` instances, :class:`SMESH.DriverMED_ReadStatus` ) """ @@ -601,18 +701,6 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): aMeshes = [ Mesh(self, self.geompyD, m) for m in aSmeshMeshes ] return aMeshes, aStatus - def CreateMeshesFromSAUV( self,theFileName ): - """ - Create a Mesh object(s) importing data from the given SAUV file - - Returns: - a tuple ( list of class :class:`Mesh` instances, :class:`SMESH.DriverMED_ReadStatus` ) - """ - - aSmeshMeshes, aStatus = SMESH._objref_SMESH_Gen.CreateMeshesFromSAUV(self,theFileName) - aMeshes = [ Mesh(self, self.geompyD, m) for m in aSmeshMeshes ] - return aMeshes, aStatus - def CreateMeshesFromSTL( self, theFileName ): """ Create a Mesh object importing data from the given STL file @@ -650,15 +738,28 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): aSmeshMesh, error = SMESH._objref_SMESH_Gen.CreateMeshesFromGMF(self, theFileName, True) - if error.comment: print "*** CreateMeshesFromGMF() errors:\n", error.comment + if error.comment: print("*** CreateMeshesFromGMF() errors:\n", error.comment) return Mesh(self, self.geompyD, aSmeshMesh), error + def CreateMeshesFromMESHIO(self, theFileName): + """ + Create a Mesh object(s) importing data from from any file supported by meshio library. + + Returns: + a tuple ( list of class :class:`Mesh` instances, + :class:`SMESH.DriverMED_ReadStatus` ) + """ + + aSmeshMeshes, aStatus = SMESH._objref_SMESH_Gen.CreateMeshesFromMESHIO(self, theFileName) + aMeshes = [ Mesh(self, self.geompyD, m) for m in aSmeshMeshes ] + return aMeshes, aStatus + def Concatenate( self, meshes, uniteIdenticalGroups, mergeNodesAndElements = False, mergeTolerance = 1e-5, allGroups = False, - name = ""): + name = "", meshToAppendTo = None): """ - Concatenate the given meshes into one mesh. All groups of input meshes will be - present in the new mesh. + Concatenate the given meshes into one mesh, optionally to meshToAppendTo. + All groups of input meshes will be present in the new mesh. Parameters: meshes: :class:`meshes, sub-meshes, groups or filters ` to combine into one mesh @@ -667,32 +768,66 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): mergeTolerance: tolerance for merging nodes allGroups: forces creation of groups corresponding to every input mesh name: name of a new mesh + meshToAppendTo: a mesh to append all given meshes Returns: an instance of class :class:`Mesh` + + See also: + :meth:`Mesh.Append` """ if not meshes: return None - for i,m in enumerate(meshes): - if isinstance(m, Mesh): + if not isinstance( meshes, list ): + meshes = [ meshes ] + for i,m in enumerate( meshes ): + if isinstance( m, Mesh ): meshes[i] = m.GetMesh() - mergeTolerance,Parameters,hasVars = ParseParameters(mergeTolerance) - meshes[0].SetParameters(Parameters) + mergeTolerance,Parameters,hasVars = ParseParameters( mergeTolerance ) + if hasattr(meshes[0], "SetParameters"): + meshes[0].SetParameters( Parameters ) + else: + meshes[0].GetMesh().SetParameters( Parameters ) + if isinstance( meshToAppendTo, Mesh ): + meshToAppendTo = meshToAppendTo.GetMesh() if allGroups: aSmeshMesh = SMESH._objref_SMESH_Gen.ConcatenateWithGroups( - self,meshes,uniteIdenticalGroups,mergeNodesAndElements,mergeTolerance) + self,meshes,uniteIdenticalGroups,mergeNodesAndElements, + mergeTolerance,meshToAppendTo ) else: aSmeshMesh = SMESH._objref_SMESH_Gen.Concatenate( - self,meshes,uniteIdenticalGroups,mergeNodesAndElements,mergeTolerance) - aMesh = Mesh(self, self.geompyD, aSmeshMesh, name=name) + self,meshes,uniteIdenticalGroups,mergeNodesAndElements, + mergeTolerance,meshToAppendTo ) + + aMesh = Mesh( self, self.geompyD, aSmeshMesh, name=name ) return aMesh + def CreateDualMesh( self, mesh, meshName, adaptToShape): + """ + Create a dual of a mesh. + + Parameters: + mesh: Tetrahedron mesh + :class:`mesh, `. + + meshName: a name of the new mesh + adpatToShape: if true project boundary points on shape + + Returns: + an instance of class :class:`Mesh` + """ + if isinstance( mesh, Mesh ): + mesh = mesh.GetMesh() + dualMesh = SMESH._objref_SMESH_Gen.CreateDualMesh(self, mesh, meshName, adaptToShape) + return Mesh(self, self.geompyD, dualMesh) + + def CopyMesh( self, meshPart, meshName, toCopyGroups=False, toKeepIDs=False): """ Create a mesh by copying a part of another mesh. Parameters: - meshPart: a part of mesh to copy, either + meshPart: a part of mesh to copy, either :class:`mesh, sub-mesh, group or filter `. To copy nodes or elements not forming any mesh object, pass result of :meth:`Mesh.GetIDSource` as *meshPart* @@ -704,11 +839,46 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): an instance of class :class:`Mesh` """ - if (isinstance( meshPart, Mesh )): + if isinstance( meshPart, Mesh ): meshPart = meshPart.GetMesh() mesh = SMESH._objref_SMESH_Gen.CopyMesh( self,meshPart,meshName,toCopyGroups,toKeepIDs ) return Mesh(self, self.geompyD, mesh) + def CopyMeshWithGeom( self, sourceMesh, newGeom, meshName="", toCopyGroups=True, + toReuseHypotheses=True, toCopyElements=True): + """ + Create a mesh by copying a mesh definition (hypotheses and groups) to a new geometry. + It is supposed that the new geometry is a modified geometry of *sourceMesh*. + To facilitate and speed up the operation, consider using + "Set presentation parameters and sub-shapes from arguments" option in + a dialog of geometrical operation used to create the new geometry. + + Parameters: + sourceMesh: the mesh to copy definition of. + newGeom: the new geometry. + meshName: an optional name of the new mesh. If omitted, the mesh name is kept. + toCopyGroups: to create groups in the new mesh. + toReuseHypotheses: to reuse hypotheses of the *sourceMesh*. + toCopyElements: to copy mesh elements present on non-modified sub-shapes of + *sourceMesh*. + Returns: + tuple ( ok, newMesh, newGroups, newSubMeshes, newHypotheses, invalidEntries ) + *invalidEntries* are study entries of objects whose + counterparts are not found in the *newGeom*, followed by entries + of mesh sub-objects that are invalid because they depend on a not found + preceding sub-shape + """ + if isinstance( sourceMesh, Mesh ): + sourceMesh = sourceMesh.GetMesh() + + ok, newMesh, newGroups, newSubMeshes, newHypotheses, invalidEntries = \ + SMESH._objref_SMESH_Gen.CopyMeshWithGeom( self, sourceMesh, newGeom, meshName, + toCopyGroups, + toReuseHypotheses, + toCopyElements) + return ( ok, Mesh(self, self.geompyD, newMesh), + newGroups, newSubMeshes, newHypotheses, invalidEntries ) + def GetSubShapesId( self, theMainObject, theListOfSubObjects ): """ Return IDs of sub-shapes @@ -797,7 +967,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): """ if not CritType in SMESH.FunctorType._items: - raise TypeError, "CritType should be of SMESH.FunctorType" + raise TypeError("CritType should be of SMESH.FunctorType") aCriterion = self.GetEmptyCriterion() aCriterion.TypeOfElement = elementType aCriterion.Type = self.EnumToLong(CritType) @@ -827,12 +997,13 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): name = aCriterion.ThresholdStr if not name: name = "%s_%s"%(aThreshold.GetShapeType(), id(aThreshold)%10000) - aCriterion.ThresholdID = self.geompyD.addToStudy( aThreshold, name ) + geompyD = aThreshold.GetGen() + aCriterion.ThresholdID = geompyD.addToStudy( aThreshold, name ) # or a name of GEOM object elif isinstance( aThreshold, str ): aCriterion.ThresholdStr = aThreshold else: - raise TypeError, "The Threshold should be a shape." + raise TypeError("The Threshold should be a shape.") if isinstance(UnaryOp,float): aCriterion.Tolerance = UnaryOp UnaryOp = FT_Undefined @@ -841,10 +1012,10 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): # Check that Threshold is a group if isinstance(aThreshold, SMESH._objref_SMESH_GroupBase): if aThreshold.GetType() != elementType: - raise ValueError, "Group type mismatches Element type" + raise ValueError("Group type mismatches Element type") aCriterion.ThresholdStr = aThreshold.GetName() aCriterion.ThresholdID = salome.orb.object_to_string( aThreshold ) - study = self.GetCurrentStudy() + study = salome.myStudy if study: so = study.FindObjectIOR( aCriterion.ThresholdID ) if so: @@ -852,13 +1023,13 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): if entry: aCriterion.ThresholdID = entry else: - raise TypeError, "The Threshold should be a Mesh Group" + raise TypeError("The Threshold should be a Mesh Group") elif CritType == FT_RangeOfIds: # Check that Threshold is string if isinstance(aThreshold, str): aCriterion.ThresholdStr = aThreshold else: - raise TypeError, "The Threshold should be a string." + raise TypeError("The Threshold should be a string.") elif CritType == FT_CoplanarFaces: # Check the Threshold if isinstance(aThreshold, int): @@ -866,11 +1037,10 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): elif isinstance(aThreshold, str): ID = int(aThreshold) if ID < 1: - raise ValueError, "Invalid ID of mesh face: '%s'"%aThreshold + raise ValueError("Invalid ID of mesh face: '%s'"%aThreshold) aCriterion.ThresholdID = aThreshold else: - raise TypeError,\ - "The Threshold should be an ID of mesh face and not '%s'"%aThreshold + raise TypeError("The Threshold should be an ID of mesh face and not '%s'"%aThreshold) elif CritType == FT_ConnectedElements: # Check the Threshold if isinstance(aThreshold, geomBuilder.GEOM._objref_GEOM_Object): # shape @@ -879,12 +1049,13 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): name = aThreshold.GetName() if not name: name = "%s_%s"%(aThreshold.GetShapeType(), id(aThreshold)%10000) - aCriterion.ThresholdID = self.geompyD.addToStudy( aThreshold, name ) + geompyD = aThreshold.GetGen() + aCriterion.ThresholdID = geompyD.addToStudy( aThreshold, name ) elif isinstance(aThreshold, int): # node id aCriterion.Threshold = aThreshold elif isinstance(aThreshold, list): # 3 point coordinates if len( aThreshold ) < 3: - raise ValueError, "too few point coordinates, must be 3" + raise ValueError("too few point coordinates, must be 3") aCriterion.ThresholdStr = " ".join( [str(c) for c in aThreshold[:3]] ) elif isinstance(aThreshold, str): if aThreshold.isdigit(): @@ -892,9 +1063,8 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): else: aCriterion.ThresholdStr = aThreshold # hope that it's point coordinates else: - raise TypeError,\ - "The Threshold should either a VERTEX, or a node ID, "\ - "or a list of point coordinates and not '%s'"%aThreshold + raise TypeError("The Threshold should either a VERTEX, or a node ID, "\ + "or a list of point coordinates and not '%s'"%aThreshold) elif CritType == FT_ElemGeomType: # Check the Threshold try: @@ -904,7 +1074,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): if isinstance(aThreshold, int): aCriterion.Threshold = aThreshold else: - raise TypeError, "The Threshold should be an integer or SMESH.GeometryType." + raise TypeError("The Threshold should be an integer or SMESH.GeometryType.") pass pass elif CritType == FT_EntityType: @@ -916,7 +1086,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): if isinstance(aThreshold, int): aCriterion.Threshold = aThreshold else: - raise TypeError, "The Threshold should be an integer or SMESH.EntityType." + raise TypeError("The Threshold should be an integer or SMESH.EntityType.") pass pass @@ -925,7 +1095,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): try: aCriterion.ThresholdStr = self.ColorToString(aThreshold) except: - raise TypeError, "The threshold value should be of SALOMEDS.Color type" + raise TypeError("The threshold value should be of SALOMEDS.Color type") pass elif CritType in [FT_FreeBorders, FT_FreeEdges, FT_FreeNodes, FT_FreeFaces, FT_LinearOrQuadratic, FT_BadOrientedVolume, @@ -943,7 +1113,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): aThreshold = float(aThreshold) aCriterion.Threshold = aThreshold except: - raise TypeError, "The Threshold should be a number." + raise TypeError("The Threshold should be a number.") return None if Threshold == FT_LogicalNOT or UnaryOp == FT_LogicalNOT: @@ -1046,6 +1216,8 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): functor = aFilterMgr.CreateAspectRatio3D() elif theCriterion == FT_Warping: functor = aFilterMgr.CreateWarping() + elif theCriterion == FT_Warping3D: + functor = aFilterMgr.CreateWarping3D() elif theCriterion == FT_MinimumAngle: functor = aFilterMgr.CreateMinimumAngle() elif theCriterion == FT_Taper: @@ -1068,14 +1240,18 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): functor = aFilterMgr.CreateLength() elif theCriterion == FT_Length2D: functor = aFilterMgr.CreateLength2D() + elif theCriterion == FT_Length3D: + functor = aFilterMgr.CreateLength3D() elif theCriterion == FT_Deflection2D: functor = aFilterMgr.CreateDeflection2D() elif theCriterion == FT_NodeConnectivityNumber: functor = aFilterMgr.CreateNodeConnectivityNumber() elif theCriterion == FT_BallDiameter: functor = aFilterMgr.CreateBallDiameter() + elif theCriterion == FT_ScaledJacobian: + functor = aFilterMgr.CreateScaledJacobian() else: - print "Error: given parameter is not numerical functor type." + print("Error: given parameter is not numerical functor type.") aFilterMgr.UnRegister() return functor @@ -1105,11 +1281,30 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): return hyp + def GetHypothesisParameterValues( self, hypType, libName, mesh, shape, initParams ): + """ + Create hypothesis initialized according to parameters + + Parameters: + hypType (string): hypothesis type + libName (string): plug-in library name + mesh: optional mesh by which a hypotheses can initialize self + shape: optional geometry by size of which a hypotheses can initialize self + initParams: structure SMESH.HypInitParams defining how to initialize a hypothesis + + Returns: + created hypothesis instance + """ + if isinstance( mesh, Mesh ): + mesh = mesh.GetMesh() + if isinstance( initParams, (bool,int)): + initParams = SMESH.HypInitParams( not initParams, 1.0, not mesh ) + return SMESH._objref_SMESH_Gen.GetHypothesisParameterValues(self, hypType, libName, + mesh, shape, initParams ) + def GetMeshInfo(self, obj): """ Get the mesh statistic. - Use :meth:`smeshBuilder.EnumToLong` to get an integer from - an item of :class:`SMESH.EntityType`. Returns: dictionary { :class:`SMESH.EntityType` - "count of elements" } @@ -1143,7 +1338,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): Returns: minimum distance value - See also: + See also: :meth:`GetMinDistance` """ @@ -1171,7 +1366,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): Returns: :class:`SMESH.Measure` structure or None if input data is invalid - See also: + See also: :meth:`MinDistance` """ @@ -1218,7 +1413,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): Returns: tuple of six values (minX, minY, minZ, maxX, maxY, maxZ) - See also: + See also: :meth:`GetBoundingBox` """ @@ -1239,7 +1434,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): Returns: :class:`SMESH.Measure` structure - See also: + See also: :meth:`BoundingBox` """ @@ -1317,13 +1512,16 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): def GetGravityCenter(self, obj): """ - Get gravity center of all nodes of the mesh object. - - Parameters: + Get gravity center of all nodes of a mesh object. + + Parameters: obj: :class:`mesh, sub-mesh, group or filter ` - Returns: - Three components of the gravity center (x,y,z) + Returns: + Three components of the gravity center (x,y,z) + + See also: + :meth:`Mesh.BaryCenter` """ if isinstance(obj, Mesh): obj = obj.mesh if isinstance(obj, Mesh_Algorithm): obj = obj.GetSubMesh() @@ -1332,6 +1530,28 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen): aMeasurements.UnRegister() return pointStruct.x, pointStruct.y, pointStruct.z + def GetAngle(self, p1, p2, p3 ): + """ + Computes a radian measure of an angle defined by 3 points: <(p1,p2,p3) + + Parameters: + p1,p2,p3: coordinates of 3 points defined by either SMESH.PointStruct + or list [x,y,z] + + Returns: + Angle in radians + """ + if isinstance( p1, list ): p1 = PointStruct(*p1) + if isinstance( p2, list ): p2 = PointStruct(*p2) + if isinstance( p3, list ): p3 = PointStruct(*p3) + + aMeasurements = self.CreateMeasurements() + angle = aMeasurements.Angle(p1,p2,p3) + aMeasurements.UnRegister() + + return angle + + pass # end of class smeshBuilder import omniORB @@ -1339,7 +1559,7 @@ omniORB.registerObjref(SMESH._objref_SMESH_Gen._NP_RepositoryId, smeshBuilder) """Registering the new proxy for SMESH.SMESH_Gen""" -def New( study, instance=None, instanceGeom=None): +def New( instance=None, instanceGeom=None): """ Create a new smeshBuilder instance. The smeshBuilder class provides the Python interface to create or load meshes. @@ -1349,10 +1569,9 @@ def New( study, instance=None, instanceGeom=None): import salome salome.salome_init() from salome.smesh import smeshBuilder - smesh = smeshBuilder.New(salome.myStudy) + smesh = smeshBuilder.New() Parameters: - study: SALOME study, generally obtained by salome.myStudy. instance: CORBA proxy of SMESH Engine. If None, the default Engine is used. instanceGeom: CORBA proxy of GEOM Engine. If None, the default Engine is used. Returns: @@ -1361,19 +1580,24 @@ def New( study, instance=None, instanceGeom=None): global engine global smeshInst global doLcc + if instance and isinstance( instance, SALOMEDS._objref_Study ): + import sys + sys.stderr.write("Warning: 'study' argument is no more needed in smeshBuilder.New(). Consider updating your script!!!\n\n") + instance = None engine = instance if engine is None: - doLcc = True + doLcc = True smeshInst = smeshBuilder() assert isinstance(smeshInst,smeshBuilder), "Smesh engine class is %s but should be smeshBuilder.smeshBuilder. Import salome.smesh.smeshBuilder before creating the instance."%smeshInst.__class__ - smeshInst.init_smesh(study, instanceGeom) + smeshInst.init_smesh(instanceGeom) return smeshInst # Public class: Mesh # ================== -class Mesh: + +class Mesh(metaclass = MeshMeta): """ This class allows defining and managing a mesh. It has a set of methods to build a mesh on the given geometry, including the definition of sub-meshes. @@ -1381,13 +1605,13 @@ class Mesh: new nodes and elements and by changing the existing entities), to get information about a mesh and to export a mesh in different formats. """ - __metaclass__ = MeshMeta geom = 0 mesh = 0 editor = 0 - def __init__(self, smeshpyD, geompyD, obj=0, name=0): + def __init__(self, smeshpyD, geompyD, obj=0, name=0, parallel=False): + """ Constructor @@ -1401,8 +1625,8 @@ class Mesh: name: Study name of the mesh """ - self.smeshpyD=smeshpyD - self.geompyD=geompyD + self.smeshpyD = smeshpyD + self.geompyD = geompyD if obj is None: obj = 0 objHasName = False @@ -1411,18 +1635,20 @@ class Mesh: self.geom = obj objHasName = True # publish geom of mesh (issue 0021122) - if not self.geom.GetStudyEntry() and smeshpyD.GetCurrentStudy(): + if not self.geom.GetStudyEntry(): objHasName = False - studyID = smeshpyD.GetCurrentStudy()._get_StudyId() - if studyID != geompyD.myStudyId: - geompyD.init_geom( smeshpyD.GetCurrentStudy()) - pass + geompyD.init_geom() if name: geo_name = name + " shape" else: geo_name = "%s_%s to mesh"%(self.geom.GetShapeType(), id(self.geom)%100) geompyD.addToStudy( self.geom, geo_name ) - self.SetMesh( self.smeshpyD.CreateMesh(self.geom) ) + if parallel and isinstance(self, ParallelMesh): + mymesh = self.smeshpyD.CreateParallelMesh(self.geom) + mymesh2 = mymesh._narrow(SMESH._objref_SMESH_Mesh) + self.SetMesh( mymesh ) + else: + self.SetMesh( self.smeshpyD.CreateMesh(self.geom) ) elif isinstance(obj, SMESH._objref_SMESH_Mesh): self.SetMesh(obj) @@ -1464,15 +1690,26 @@ class Mesh: Parameters: theMesh: a :class:`SMESH.SMESH_Mesh` object """ - - # do not call Register() as this prevents mesh servant deletion at closing study #if self.mesh: self.mesh.UnRegister() self.mesh = theMesh if self.mesh: #self.mesh.Register() self.geom = self.mesh.GetShapeToMesh() - pass + if self.geom: + self.geompyD = None + try: + if salome.sg.hasDesktop(): + so = salome.ObjectToSObject( self.geom ) + comp = so.GetFatherComponent() + if comp.ComponentDataType() == "SHAPERSTUDY": + import shaperBuilder + self.geompyD = shaperBuilder.New() + except: + pass + if not self.geompyD: + self.geompyD = self.geom.GetGen() + pass def GetMesh(self): """ @@ -1484,6 +1721,18 @@ class Mesh: return self.mesh + def GetEngine(self): + """ + Return a smeshBuilder instance created this mesh + """ + return self.smeshpyD + + def GetGeomEngine(self): + """ + Return a geomBuilder instance + """ + return self.geompyD + def GetName(self): """ Get the name of the mesh @@ -1523,7 +1772,7 @@ class Mesh: algo1D = mesh.Segment(geom=Edge_1) - creates a sub-mesh on *Edge_1* and assign Wire Discretization algorithm to it. + create a sub-mesh on *Edge_1* and assign Wire Discretization algorithm to it. The created sub-mesh can be retrieved from the algorithm:: submesh = algo1D.GetSubMesh() @@ -1553,6 +1802,12 @@ class Mesh: self.mesh = self.smeshpyD.CreateMesh(geom) + def HasShapeToMesh(self): + """ + Return ``True`` if this mesh is based on geometry + """ + return self.mesh.HasShapeToMesh() + def Load(self): """ Load mesh from the study after opening the study @@ -1645,7 +1900,6 @@ class Mesh: geom = self.geom return self.smeshpyD.Evaluate(self.mesh, geom) - def Compute(self, geom=0, discardModifs=False, refresh=False): """ Compute the mesh and return the status of the computation @@ -1662,21 +1916,18 @@ class Mesh: """ if geom == 0 or not isinstance(geom, geomBuilder.GEOM._objref_GEOM_Object): - if self.geom == 0: - geom = self.mesh.GetShapeToMesh() - else: - geom = self.geom + geom = self.mesh.GetShapeToMesh() ok = False try: if discardModifs and self.mesh.HasModificationsToDiscard(): # issue 0020693 self.mesh.Clear() ok = self.smeshpyD.Compute(self.mesh, geom) - except SALOME.SALOME_Exception, ex: - print "Mesh computation failed, exception caught:" - print " ", ex.details.text + except SALOME.SALOME_Exception as ex: + print("Mesh computation failed, exception caught:") + print(" ", ex.details.text) except: import traceback - print "Mesh computation failed, exception caught:" + print("Mesh computation failed, exception caught:") traceback.print_exc() if True:#not ok: allReasons = "" @@ -1753,18 +2004,23 @@ class Mesh: else: msg += " has not been computed" if allReasons != "": msg += ":" else: msg += "." - print msg - print allReasons + print(msg) + print(allReasons) pass - if salome.sg.hasDesktop() and self.mesh.GetStudyId() >= 0: - if not isinstance( refresh, list): # not a call from subMesh.Compute() - smeshgui = salome.ImportComponentGUI("SMESH") - smeshgui.Init(self.mesh.GetStudyId()) - smeshgui.SetMeshIcon( salome.ObjectToID( self.mesh ), ok, (self.NbNodes()==0) ) - if refresh: salome.sg.updateObjBrowser(True) + if salome.sg: + if salome.sg.hasDesktop(): + if not isinstance( refresh, list): # not a call from subMesh.Compute() + if refresh: salome.sg.updateObjBrowser() return ok + def CheckCompute(self): + """ + Check if the mesh was properly compute + """ + if not self.mesh.IsComputedOK(): + raise Exception("Could not compute {}".format(self.GetName())) + def GetComputeErrors(self, shape=0 ): """ Return a list of error messages (:class:`SMESH.ComputeError`) of the last :meth:`Compute` @@ -1797,11 +2053,9 @@ class Mesh: try: shapeText = "" mainIOR = salome.orb.object_to_string( self.GetShape() ) - for sname in salome.myStudyManager.GetOpenStudies(): - s = salome.myStudyManager.GetStudyByName(sname) - if not s: continue - mainSO = s.FindObjectIOR(mainIOR) - if not mainSO: continue + s = salome.myStudy + mainSO = s.FindObjectIOR(mainIOR) + if mainSO: if subShapeID == 1: shapeText = '"%s"' % mainSO.GetName() subIt = s.NewChildIterator(mainSO) @@ -1854,7 +2108,7 @@ class Mesh: pass groups = [] - for algoName, shapes in algo2shapes.items(): + for algoName, shapes in list(algo2shapes.items()): while shapes: groupType = self.smeshpyD.EnumToLong( shapes[0].GetShapeType() ) otherTypeShapes = [] @@ -1890,10 +2144,20 @@ class Mesh: def SetMeshOrder(self, submeshes): """ - Set order in which concurrent sub-meshes should be meshed + Set priority of sub-meshes. It works in two ways: + + * For sub-meshes with assigned algorithms of same dimension generating mesh of + *several dimensions*, it sets the order in which the sub-meshes are computed. + * For the rest sub-meshes, it sets the order in which the sub-meshes are checked + when looking for meshing parameters to apply to a sub-shape. To impose the + order in which sub-meshes with uni-dimensional algorithms are computed, + call **submesh.Compute()** in a desired order. Parameters: submeshes: list of lists of :class:`sub-meshes ` + + Warning: the method is for setting the order for all sub-meshes at once: + SetMeshOrder( [ [sm1, sm2, sm3], [sm4, sm5] ] ) """ return self.mesh.SetMeshOrder(submeshes) @@ -1907,12 +2171,8 @@ class Mesh: """ self.mesh.Clear() - if ( salome.sg.hasDesktop() and - salome.myStudyManager.GetStudyByID( self.mesh.GetStudyId() ) ): - smeshgui = salome.ImportComponentGUI("SMESH") - smeshgui.Init(self.mesh.GetStudyId()) - smeshgui.SetMeshIcon( salome.ObjectToID( self.mesh ), False, True ) - if refresh: salome.sg.updateObjBrowser(True) + if ( salome.sg.hasDesktop() ): + if refresh: salome.sg.updateObjBrowser() def ClearSubMesh(self, geomId, refresh=False): """ @@ -1925,14 +2185,11 @@ class Mesh: self.mesh.ClearSubMesh(geomId) if salome.sg.hasDesktop(): - smeshgui = salome.ImportComponentGUI("SMESH") - smeshgui.Init(self.mesh.GetStudyId()) - smeshgui.SetMeshIcon( salome.ObjectToID( self.mesh ), False, True ) - if refresh: salome.sg.updateObjBrowser(True) + if refresh: salome.sg.updateObjBrowser() def AutomaticTetrahedralization(self, fineness=0): """ - Compute a tetrahedral mesh using AutomaticLength + MEFISTO + Tetrahedron + Compute a tetrahedral mesh using AutomaticLength + Triangle + Tetrahedron Parameters: fineness: [0.0,1.0] defines mesh fineness @@ -2011,7 +2268,7 @@ class Mesh: AssureGeomPublished( self, geom, "shape for %s" % hyp.GetName()) status = self.mesh.AddHypothesis(geom, hyp) else: - status = HYP_BAD_GEOMETRY,"" + status = HYP_BAD_GEOMETRY, "" hyp_name = GetName( hyp ) geom_name = "" if geom: @@ -2068,7 +2325,7 @@ class Mesh: return self.mesh.RemoveHypothesis( shape, hyp ) hypName = GetName( hyp ) geoName = GetName( shape ) - print "WARNING: RemoveHypothesis() failed as '%s' is not assigned to '%s' shape" % ( hypName, geoName ) + print("WARNING: RemoveHypothesis() failed as '%s' is not assigned to '%s' shape" % ( hypName, geoName )) return None def GetHypothesisList(self, geom): @@ -2095,22 +2352,97 @@ class Mesh: pass pass - def ExportMED(self, f, auto_groups=0, version=MED_V2_2, - overwrite=1, meshPart=None, autoDimension=True, fields=[], geomAssocFields=''): + def ExportMEDCoupling(self, *args, **kwargs): + """ + Export the mesh in a memory representation. + + Parameters: + auto_groups (boolean): parameter for creating/not creating + the groups Group_On_All_Nodes, Group_On_All_Faces, ... ; + the typical use is auto_groups=False. + overwrite (boolean): parameter for overwriting/not overwriting the file + meshPart: a part of mesh (:class:`sub-mesh, group or filter `) + to export instead of the mesh + autoDimension: if *True* (default), a space dimension of a MED mesh can be either + + - 1D if all mesh nodes lie on OX coordinate axis, or + - 2D if all mesh nodes lie on XOY coordinate plane, or + - 3D in the rest cases. + + If *autoDimension* is *False*, the space dimension is always 3. + fields: list of GEOM fields defined on the shape to mesh. + geomAssocFields: each character of this string means a need to export a + corresponding field; correspondence between fields and characters + is following: + + - 'v' stands for "_vertices_" field; + - 'e' stands for "_edges_" field; + - 'f' stands for "_faces_" field; + - 's' stands for "_solids_" field. + + zTolerance (float): tolerance in Z direction. If Z coordinate of a node is + close to zero within a given tolerance, the coordinate is set to zero. + If *ZTolerance* is negative (default), the node coordinates are kept as is. + saveNumbers(boolean) : enable saving numbers of nodes and cells. + """ + auto_groups = args[0] if len(args) > 0 else False + meshPart = args[1] if len(args) > 1 else None + autoDimension = args[2] if len(args) > 2 else True + fields = args[3] if len(args) > 3 else [] + geomAssocFields = args[4] if len(args) > 4 else '' + z_tolerance = args[5] if len(args) > 5 else -1. + saveNumbers = args[6] if len(args) > 6 else True + # process keywords arguments + auto_groups = kwargs.get("auto_groups", auto_groups) + meshPart = kwargs.get("meshPart", meshPart) + autoDimension = kwargs.get("autoDimension", autoDimension) + fields = kwargs.get("fields", fields) + geomAssocFields = kwargs.get("geomAssocFields", geomAssocFields) + z_tolerance = kwargs.get("zTolerance", z_tolerance) + saveNumbers = kwargs.get("saveNumbers", saveNumbers) + + # invoke engine's function + if meshPart or fields or geomAssocFields or z_tolerance > 0 or not saveNumbers: + unRegister = genObjUnRegister() + if isinstance( meshPart, list ): + meshPart = self.GetIDSource( meshPart, SMESH.ALL ) + unRegister.set( meshPart ) + + z_tolerance,Parameters,hasVars = ParseParameters(z_tolerance) + self.mesh.SetParameters(Parameters) + + intPtr = self.mesh.ExportPartToMEDCoupling(meshPart, auto_groups, autoDimension, + fields, geomAssocFields, z_tolerance, + saveNumbers ) + import medcoupling + dab = medcoupling.FromPyIntPtrToDataArrayByte(intPtr) + return medcoupling.MEDFileData.New(dab) + else: + intPtr = self.mesh.ExportMEDCoupling(auto_groups, autoDimension) + import medcoupling + dab = medcoupling.FromPyIntPtrToDataArrayByte(intPtr) + return medcoupling.MEDFileMesh.New(dab) + + def ExportMED(self, *args, **kwargs): """ Export the mesh in a file in MED format allowing to overwrite the file if it exists or add the exported data to its contents Parameters: - f: is the file name - auto_groups: boolean parameter for creating/not creating + fileName: is the file name + auto_groups (boolean): parameter for creating/not creating the groups Group_On_All_Nodes, Group_On_All_Faces, ... ; the typical use is auto_groups=False. - version: MED format version (MED_V2_1 or MED_V2_2, - the latter meaning any current version). The parameter is - obsolete since MED_V2_1 is no longer supported. - overwrite: boolean parameter for overwriting/not overwriting the file - meshPart: a part of mesh (:class:`sub-mesh, group or filter `) to export instead of the mesh + version (int): define the version (xy, where version is x.y.z) of MED file format. + For instance med 3.2.1 is coded 3*10+2 = 32, med 4.0.0 is coded 4*10+0 = 40. + The rules of compatibility to write a mesh in an older version than + the current version depend on the current version. For instance, + with med 4.0 it is possible to write/append med files in 4.0.0 (default) + or 3.2.1 or 3.3.1 formats. + If the version is equal to -1, the version is not changed (default). + overwrite (boolean): parameter for overwriting/not overwriting the file + meshPart: a part of mesh (:class:`sub-mesh, group or filter `) + to export instead of the mesh autoDimension: if *True* (default), a space dimension of a MED mesh can be either - 1D if all mesh nodes lie on OX coordinate axis, or @@ -2119,73 +2451,100 @@ class Mesh: If *autoDimension* is *False*, the space dimension is always 3. fields: list of GEOM fields defined on the shape to mesh. - geomAssocFields: each character of this string means a need to export a - corresponding field; correspondence between fields and characters is following: - - 'v' stands for "_vertices _" field; - - 'e' stands for "_edges _" field; - - 'f' stands for "_faces _" field; - - 's' stands for "_solids _" field. - """ + geomAssocFields: each character of this string means a need to export a + corresponding field; correspondence between fields and characters + is following: + + - 'v' stands for "_vertices_" field; + - 'e' stands for "_edges_" field; + - 'f' stands for "_faces_" field; + - 's' stands for "_solids_" field. + + zTolerance (float): tolerance in Z direction. If Z coordinate of a node is + close to zero within a given tolerance, the coordinate is set to zero. + If *ZTolerance* is negative (default), the node coordinates are kept as is. + saveNumbers (boolean) : enable saving numbers of nodes and cells. + """ + # process positional arguments + #args = [i for i in args if i not in [SMESH.MED_V2_1, SMESH.MED_V2_2]] # backward compatibility + fileName = args[0] + auto_groups = args[1] if len(args) > 1 else False + version = args[2] if len(args) > 2 else -1 + overwrite = args[3] if len(args) > 3 else True + meshPart = args[4] if len(args) > 4 else None + autoDimension = args[5] if len(args) > 5 else True + fields = args[6] if len(args) > 6 else [] + geomAssocFields = args[7] if len(args) > 7 else '' + z_tolerance = args[8] if len(args) > 8 else -1. + saveNumbers = args[9] if len(args) > 9 else True + # process keywords arguments + auto_groups = kwargs.get("auto_groups", auto_groups) + version = kwargs.get("version", version) + version = kwargs.get("minor", version) + overwrite = kwargs.get("overwrite", overwrite) + meshPart = kwargs.get("meshPart", meshPart) + autoDimension = kwargs.get("autoDimension", autoDimension) + fields = kwargs.get("fields", fields) + geomAssocFields = kwargs.get("geomAssocFields", geomAssocFields) + z_tolerance = kwargs.get("zTolerance", z_tolerance) + saveNumbers = kwargs.get("saveNumbers", saveNumbers) + + if isinstance( meshPart, Mesh): + meshPart = meshPart.GetMesh() - if meshPart or fields or geomAssocFields: + # invoke engine's function + if meshPart or fields or geomAssocFields or z_tolerance > 0 or not saveNumbers: unRegister = genObjUnRegister() if isinstance( meshPart, list ): meshPart = self.GetIDSource( meshPart, SMESH.ALL ) unRegister.set( meshPart ) - self.mesh.ExportPartToMED( meshPart, f, auto_groups, version, overwrite, autoDimension, - fields, geomAssocFields) - else: - self.mesh.ExportToMEDX(f, auto_groups, version, overwrite, autoDimension) - - def ExportSAUV(self, f, auto_groups=0): - """ - Export the mesh in a file in SAUV format - - Parameters: - f: is the file name - auto_groups: boolean parameter for creating/not creating - the groups Group_On_All_Nodes, Group_On_All_Faces, ... ; - the typical use is auto_groups=False. - """ + z_tolerance,Parameters,hasVars = ParseParameters(z_tolerance) + self.mesh.SetParameters(Parameters) - self.mesh.ExportSAUV(f, auto_groups) + self.mesh.ExportPartToMED( meshPart, fileName, auto_groups, + version, overwrite, autoDimension, + fields, geomAssocFields, z_tolerance, saveNumbers ) + else: + self.mesh.ExportMED(fileName, auto_groups, version, overwrite, autoDimension) - def ExportDAT(self, f, meshPart=None): + def ExportDAT(self, f, meshPart=None, renumber=True): """ Export the mesh in a file in DAT format Parameters: f: the file name meshPart: a part of mesh (:class:`sub-mesh, group or filter `) to export instead of the mesh + renumber(boolean): enable renumbering nodes and cells in order to eliminate holes in numbering """ - if meshPart: + if meshPart or not renumber: unRegister = genObjUnRegister() if isinstance( meshPart, list ): meshPart = self.GetIDSource( meshPart, SMESH.ALL ) unRegister.set( meshPart ) - self.mesh.ExportPartToDAT( meshPart, f ) + self.mesh.ExportPartToDAT( meshPart, f, renumber ) else: - self.mesh.ExportDAT(f) + self.mesh.ExportDAT( f, renumber ) - def ExportUNV(self, f, meshPart=None): + def ExportUNV(self, f, meshPart=None, renumber=True): """ Export the mesh in a file in UNV format Parameters: f: the file name meshPart: a part of mesh (:class:`sub-mesh, group or filter `) to export instead of the mesh + renumber(boolean): enable renumbering nodes and cells in order to eliminate holes in numbering """ - if meshPart: + if meshPart or not renumber: unRegister = genObjUnRegister() if isinstance( meshPart, list ): meshPart = self.GetIDSource( meshPart, SMESH.ALL ) unRegister.set( meshPart ) - self.mesh.ExportPartToUNV( meshPart, f ) + self.mesh.ExportPartToUNV( meshPart, f, renumber ) else: - self.mesh.ExportUNV(f) + self.mesh.ExportUNV( f, renumber ) def ExportSTL(self, f, ascii=1, meshPart=None): """ @@ -2229,6 +2588,26 @@ class Mesh: meshPart = self.mesh self.mesh.ExportCGNS(meshPart, f, overwrite, groupElemsByType) + def ExportStructuredCGNS(self, f, overwrite=1, meshPart=None ): + """ + Export the mesh in a file in Structured CGNS format + + Parameters: + f: is the file name + overwrite: boolean parameter for overwriting/not overwriting the file + meshPart: a part of mesh (:class:`sub-mesh, group or filter `) to export instead of the mesh + """ + + unRegister = genObjUnRegister() + if isinstance( meshPart, list ): + meshPart = self.GetIDSource( meshPart, SMESH.ALL ) + unRegister.set( meshPart ) + if isinstance( meshPart, Mesh ): + meshPart = meshPart.mesh + elif not meshPart: + meshPart = self.mesh + self.mesh.ExportStructuredCGNS(meshPart, f, overwrite) + def ExportGMF(self, f, meshPart=None): """ Export the mesh in a file in GMF format. @@ -2250,18 +2629,91 @@ class Mesh: meshPart = self.mesh self.mesh.ExportGMF(meshPart, f, True) - def ExportToMED(self, f, version=MED_V2_2, opt=0, overwrite=1, autoDimension=True): + def ExportMESHIO( + self, + fileName, + selectedFilter, + meshPart + ): + """ + Exports a part of mesh to a file with meshio library + through an intermediate MED file. + + Parametrs described below are the same as for ExportMED() method. + However, we know that _pyMesh::Process(const Handle(_pyCommand)& theCommand) method + change a position of meshPart argument when dump to a Python script for whatever reason + this way: + - to 5th place for ExportMED command + - to last place for the rest commands + + So, for this method meshPart moved to the end of the args. + Look at src/SMESH_I/SMESH_2smeshpy.cxx for related source code. + + The same note is for the name of the method that was dumped as ExportPartToMESHIO(), + but then processing just removes PartTo from the middle of the name as it was done + for all export methods. + + Parameters: + fileName: is the file name + selectedFilter: filter string selected by user in a file dialog + meshPart: a part of mesh (:class:`sub-mesh, group or filter `) + to export instead of the mesh + """ + + if isinstance(meshPart, Mesh): + meshPart = meshPart.GetMesh() + + self.mesh.ExportPartToMESHIO( + meshPart, + fileName, + selectedFilter + ) + + + def ExportToMED(self, *args, **kwargs): """ Deprecated, used only for compatibility! Please, use :meth:`ExportMED` method instead. Export the mesh in a file in MED format allowing to overwrite the file if it exists or add the exported data to its contents Parameters: - f: the file name - version: MED format version (MED_V2_1 or MED_V2_2, - the latter meaning any current version). The parameter is - obsolete since MED_V2_1 is no longer supported. - opt: boolean parameter for creating/not creating + fileName: the file name + opt (boolean): parameter for creating/not creating + the groups Group_On_All_Nodes, Group_On_All_Faces, ... + overwrite: boolean parameter for overwriting/not overwriting the file + autoDimension: if *True* (default), a space dimension of a MED mesh can be either + + - 1D if all mesh nodes lie on OX coordinate axis, or + - 2D if all mesh nodes lie on XOY coordinate plane, or + - 3D in the rest cases. + + If **autoDimension** is *False*, the space dimension is always 3. + """ + + print("WARNING: ExportToMED() is deprecated, use ExportMED() instead") + # process positional arguments + #args = [i for i in args if i not in [SMESH.MED_V2_1, SMESH.MED_V2_2]] # backward compatibility + fileName = args[0] + auto_groups = args[1] if len(args) > 1 else False + overwrite = args[2] if len(args) > 2 else True + autoDimension = args[3] if len(args) > 3 else True + # process keywords arguments + auto_groups = kwargs.get("opt", auto_groups) # old keyword name + auto_groups = kwargs.get("auto_groups", auto_groups) # new keyword name + overwrite = kwargs.get("overwrite", overwrite) + autoDimension = kwargs.get("autoDimension", autoDimension) + minor = -1 + # invoke engine's function + self.mesh.ExportMED(fileName, auto_groups, minor, overwrite, autoDimension) + + def ExportToMEDX(self, *args, **kwargs): + """ + Deprecated, used only for compatibility! Please, use ExportMED() method instead. + Export the mesh in a file in MED format + + Parameters: + fileName: the file name + opt (boolean): parameter for creating/not creating the groups Group_On_All_Nodes, Group_On_All_Faces, ... overwrite: boolean parameter for overwriting/not overwriting the file autoDimension: if *True* (default), a space dimension of a MED mesh can be either @@ -2271,19 +2723,50 @@ class Mesh: - 3D in the rest cases. If **autoDimension** is *False*, the space dimension is always 3. + """ + + print("WARNING: ExportToMEDX() is deprecated, use ExportMED() instead") + # process positional arguments + #args = [i for i in args if i not in [SMESH.MED_V2_1, SMESH.MED_V2_2]] # backward compatibility + fileName = args[0] + auto_groups = args[1] if len(args) > 1 else False + overwrite = args[2] if len(args) > 2 else True + autoDimension = args[3] if len(args) > 3 else True + # process keywords arguments + auto_groups = kwargs.get("auto_groups", auto_groups) + overwrite = kwargs.get("overwrite", overwrite) + autoDimension = kwargs.get("autoDimension", autoDimension) + minor = -1 + # invoke engine's function + self.mesh.ExportMED(fileName, auto_groups, minor, overwrite, autoDimension) + return + + + def Append(self, meshes, uniteIdenticalGroups = True, + mergeNodesAndElements = False, mergeTolerance = 1e-5, allGroups = False): """ + Append given meshes into this mesh. + All groups of input meshes will be created in this mesh. - self.mesh.ExportToMEDX(f, opt, version, overwrite, autoDimension) + Parameters: + meshes: :class:`meshes, sub-meshes, groups or filters ` to append + uniteIdenticalGroups: if True, groups with same names are united, else they are renamed + mergeNodesAndElements: if True, equal nodes and elements are merged + mergeTolerance: tolerance for merging nodes + allGroups: forces creation of groups corresponding to every input mesh + """ + self.smeshpyD.Concatenate( meshes, uniteIdenticalGroups, + mergeNodesAndElements, mergeTolerance, allGroups, + meshToAppendTo = self.GetMesh() ) # Operations with groups: # ---------------------- - def CreateEmptyGroup(self, elementType, name): """ - Create an empty mesh group + Create an empty standalone mesh group Parameters: - elementType: the :class:`type ` of elements in the group; + elementType: the :class:`type ` of elements in the group; either of (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME) name: the name of the mesh group @@ -2315,7 +2798,7 @@ class Mesh: def GroupOnGeom(self, grp, name="", typ=None): """ Create a mesh group based on the geometrical object *grp* - and gives a *name*. + and give it a *name*. if *name* is not defined the name of the geometric group is used Parameters: @@ -2343,26 +2826,33 @@ class Mesh: tgeo = str(shape.GetShapeType()) if tgeo == "VERTEX": typ = NODE - elif tgeo == "EDGE": + elif tgeo == "EDGE" or tgeo == "WIRE": typ = EDGE elif tgeo == "FACE" or tgeo == "SHELL": typ = FACE elif tgeo == "SOLID" or tgeo == "COMPSOLID": typ = VOLUME elif tgeo == "COMPOUND": - sub = self.geompyD.SubShapeAll( shape, self.geompyD.ShapeType["SHAPE"]) + try: + sub = self.geompyD.SubShapeAll( shape, self.geompyD.ShapeType["SHAPE"]) + except: + # try to get the SHAPERSTUDY engine directly, because GetGen does not work because of + # simplification of access in geomBuilder: omniORB.registerObjref + from SHAPERSTUDY_utils import getEngine + gen = getEngine() + if gen: + sub = gen.GetIShapesOperations().ExtractSubShapes(shape, self.geompyD.ShapeType["SHAPE"], False) if not sub: - raise ValueError,"_groupTypeFromShape(): empty geometric group or compound '%s'" % GetName(shape) + raise ValueError("_groupTypeFromShape(): empty geometric group or compound '%s'" % GetName(shape)) return self._groupTypeFromShape( sub[0] ) else: - raise ValueError, \ - "_groupTypeFromShape(): invalid geometry '%s'" % GetName(shape) + raise ValueError("_groupTypeFromShape(): invalid geometry '%s'" % GetName(shape)) return typ def GroupOnFilter(self, typ, name, filter): """ - Create a mesh group with given *name* based on the *filter* which - is a special type of group dynamically updating it's contents during + Create a mesh group with given *name* based on the *filter*. + It is a special type of group dynamically updating it's contents during mesh modification Parameters: @@ -2506,21 +2996,25 @@ class Mesh: Parameters: group (SMESH.SMESH_GroupBase): group to remove + + Note: + This operation can create gaps in numeration of nodes or elements. + Call :meth:`RenumberElements` to remove the gaps. """ self.mesh.RemoveGroupWithContents(group) def GetGroups(self, elemType = SMESH.ALL): """ - Get the list of groups existing in the mesh in the order - of creation (starting from the oldest one) + Get the list of groups existing in the mesh in the order of creation + (starting from the oldest one) Parameters: elemType (SMESH.ElementType): type of elements the groups contain; by default groups of elements of all types are returned Returns: - a sequence of :class:`SMESH.SMESH_GroupBase` + a list of :class:`SMESH.SMESH_GroupBase` """ groups = self.mesh.GetGroups() @@ -2610,7 +3104,6 @@ class Mesh: Returns: instance of :class:`SMESH.SMESH_Group` """ - return self.mesh.UnionListOfGroups(groups, name) def IntersectGroups(self, group1, group2, name): @@ -2641,7 +3134,6 @@ class Mesh: Returns: instance of :class:`SMESH.SMESH_Group` """ - return self.mesh.IntersectListOfGroups(groups, name) def CutGroups(self, main_group, tool_group, name): @@ -2682,7 +3174,7 @@ class Mesh: Create a standalone group of entities basing on nodes of other groups. Parameters: - groups: list of reference :class:`sub-meshes, groups or filters `, of any type. + groups: list of :class:`sub-meshes, groups or filters `, of any type. elemType: a type of elements to include to the new group; either of (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME). name: a name of the new group. @@ -2708,6 +3200,22 @@ class Mesh: groups = [groups] return self.mesh.CreateDimGroup(groups, elemType, name, nbCommonNodes, underlyingOnly) + def FaceGroupsSeparatedByEdges( self, sharpAngle, createEdges=False, useExistingEdges=False ): + """ + Distribute all faces of the mesh among groups using sharp edges and optionally + existing 1D elements as group boundaries. + + Parameters: + sharpAngle: edge is considered sharp if an angle between normals of + adjacent faces is more than \a sharpAngle in degrees. + createEdges (boolean): to create 1D elements for detected sharp edges. + useExistingEdges (boolean): to use existing edges as group boundaries + Returns: + ListOfGroups - the created :class:`groups ` + """ + sharpAngle,Parameters,hasVars = ParseParameters( sharpAngle ) + self.mesh.SetParameters(Parameters) + return self.mesh.FaceGroupsSeparatedByEdges( sharpAngle, createEdges, useExistingEdges ); def ConvertToStandalone(self, group): """ @@ -2772,16 +3280,6 @@ class Mesh: return self.mesh.GetId() - def GetStudyId(self): - """ - Get the study Id - - Returns: - integer value, which is the study Id of the mesh - """ - - return self.mesh.GetStudyId() - def HasDuplicatedGroupNamesMED(self): """ Check the group names for duplications. @@ -2836,8 +3334,6 @@ class Mesh: def GetMeshInfo(self, obj = None): """ Get the mesh statistic. - Use :meth:`smeshBuilder.EnumToLong` to get an integer from - an item of :class:`SMESH.EntityType`. Returns: dictionary { :class:`SMESH.EntityType` - "count of elements" } @@ -3221,7 +3717,7 @@ class Mesh: Return the type of mesh element or node Returns: - the value from :class:`SMESH.ElementType` enumeration. + the value from :class:`SMESH.ElementType` enumeration. Return SMESH.ALL if element or node with the given ID does not exist """ @@ -3327,16 +3823,20 @@ class Mesh: return self.mesh.GetNodeXYZ(id) - def GetNodeInverseElements(self, id): + def GetNodeInverseElements(self, id, elemType=SMESH.ALL): """ Return list of IDs of inverse elements for the given node. If there is no node for the given ID - return an empty list + Parameters: + id: node ID + elementType: :class:`type of elements ` (SMESH.EDGE, SMESH.FACE, SMESH.VOLUME, etc.) + Returns: list of integer values """ - return self.mesh.GetNodeInverseElements(id) + return self.mesh.GetNodeInverseElements(id,elemType) def GetNodePosition(self,NodeID): """ @@ -3510,26 +4010,40 @@ class Mesh: Returns: a list of three double values + + See also: + :meth:`smeshBuilder.GetGravityCenter` """ return self.mesh.BaryCenter(id) - def GetIdsFromFilter(self, theFilter): + def GetIdsFromFilter(self, filter, meshParts=[] ): """ Pass mesh elements through the given filter and return IDs of fitting elements Parameters: - theFilter: :class:`SMESH.Filter` + filter: :class:`SMESH.Filter` + meshParts: list of mesh parts (:class:`sub-mesh, group or filter `) to filter Returns: a list of ids See Also: :meth:`SMESH.Filter.GetIDs` + :meth:`SMESH.Filter.GetElementsIdFromParts` """ - theFilter.SetMesh( self.mesh ) - return theFilter.GetIDs() + filter.SetMesh( self.mesh ) + + if meshParts: + if isinstance( meshParts, Mesh ): + filter.SetMesh( meshParts.GetMesh() ) + return theFilter.GetIDs() + if isinstance( meshParts, SMESH._objref_SMESH_IDSource ): + meshParts = [ meshParts ] + return filter.GetElementsIdFromParts( meshParts ) + + return filter.GetIDs() # Get mesh measurements information: # ------------------------------------ @@ -3561,7 +4075,9 @@ class Mesh: isElem2: *True* if *id2* is element id, *False* if it is node id Returns: - minimum distance value **GetMinDistance()** + minimum distance value + See Also: + :meth:`GetMinDistance` """ aMeasure = self.GetMinDistance(id1, id2, isElem1, isElem2) @@ -3613,7 +4129,7 @@ class Mesh: Returns: tuple of six values (minX, minY, minZ, maxX, maxY, maxZ) - See Also: + See Also: :meth:`GetBoundingBox()` """ @@ -3636,7 +4152,7 @@ class Mesh: Returns: :class:`SMESH.Measure` structure - See Also: + See Also: :meth:`BoundingBox()` """ @@ -3682,6 +4198,10 @@ class Mesh: Returns: True or False + + Note: + This operation can create gaps in numeration of elements. + Call :meth:`RenumberElements` to remove the gaps. """ return self.editor.RemoveElements(IDsOfElements) @@ -3695,16 +4215,34 @@ class Mesh: Returns: True or False + + Note: + This operation can create gaps in numeration of nodes. + Call :meth:`RenumberElements` to remove the gaps. """ return self.editor.RemoveNodes(IDsOfNodes) + def RemoveNodeWithReconnection(self, nodeID ): + """ + Remove a node along with changing surrounding faces to cover a hole. + + Parameters: + nodeID: ID of node to remove + """ + + return self.editor.RemoveNodeWithReconnection( nodeID ) + def RemoveOrphanNodes(self): """ Remove all orphan (free) nodes from mesh Returns: number of the removed nodes + + Note: + This operation can create gaps in numeration of nodes. + Call :meth:`RenumberElements` to remove the gaps. """ return self.editor.RemoveOrphanNodes() @@ -3750,7 +4288,7 @@ class Mesh: Returns: an object (a new group or a temporary :class:`SMESH.SMESH_IDSource`) holding IDs of new and/or found 0D elements. IDs of 0D elements - can be retrieved from the returned object by + can be retrieved from the returned object by calling :meth:`GetIDs() ` """ @@ -3886,7 +4424,7 @@ class Mesh: def SetNodeOnVertex(self, NodeID, Vertex): """ - Binds a node to a vertex + Bind a node to a vertex Parameters: NodeID: a node ID @@ -3902,14 +4440,14 @@ class Mesh: VertexID = Vertex try: self.editor.SetNodeOnVertex(NodeID, VertexID) - except SALOME.SALOME_Exception, inst: - raise ValueError, inst.details.text + except SALOME.SALOME_Exception as inst: + raise ValueError(inst.details.text) return True def SetNodeOnEdge(self, NodeID, Edge, paramOnEdge): """ - Stores the node position on an edge + Store the node position on an edge Parameters: NodeID: a node ID @@ -3926,13 +4464,13 @@ class Mesh: EdgeID = Edge try: self.editor.SetNodeOnEdge(NodeID, EdgeID, paramOnEdge) - except SALOME.SALOME_Exception, inst: - raise ValueError, inst.details.text + except SALOME.SALOME_Exception as inst: + raise ValueError(inst.details.text) return True def SetNodeOnFace(self, NodeID, Face, u, v): """ - Stores node position on a face + Store node position on a face Parameters: NodeID: a node ID @@ -3950,13 +4488,13 @@ class Mesh: FaceID = Face try: self.editor.SetNodeOnFace(NodeID, FaceID, u, v) - except SALOME.SALOME_Exception, inst: - raise ValueError, inst.details.text + except SALOME.SALOME_Exception as inst: + raise ValueError(inst.details.text) return True def SetNodeInVolume(self, NodeID, Solid): """ - Binds a node to a solid + Bind a node to a solid Parameters: NodeID: a node ID @@ -3972,8 +4510,8 @@ class Mesh: SolidID = Solid try: self.editor.SetNodeInVolume(NodeID, SolidID) - except SALOME.SALOME_Exception, inst: - raise ValueError, inst.details.text + except SALOME.SALOME_Exception as inst: + raise ValueError(inst.details.text) return True def SetMeshElementOnShape(self, ElementID, Shape): @@ -3994,8 +4532,8 @@ class Mesh: ShapeID = Shape try: self.editor.SetMeshElementOnShape(ElementID, ShapeID) - except SALOME.SALOME_Exception, inst: - raise ValueError, inst.details.text + except SALOME.SALOME_Exception as inst: + raise ValueError(inst.details.text) return True @@ -4049,8 +4587,6 @@ class Mesh: the ID of a node """ - #preview = self.mesh.GetMeshEditPreviewer() - #return preview.MoveClosestNodeToPoint(x, y, z, -1) return self.editor.FindNodeClosestTo(x, y, z) def FindElementsByPoint(self, x, y, z, elementType = SMESH.ALL, meshPart=None): @@ -4066,16 +4602,28 @@ class Mesh: Returns: list of IDs of found elements """ - if meshPart: return self.editor.FindAmongElementsByPoint( meshPart, x, y, z, elementType ); else: return self.editor.FindElementsByPoint(x, y, z, elementType) + def ProjectPoint(self, x,y,z, elementType, meshObject=None): + """ + Project a point to a mesh object. + Return ID of an element of given type where the given point is projected + and coordinates of the projection point. + In the case if nothing found, return -1 and [] + """ + if isinstance( meshObject, Mesh ): + meshObject = meshObject.GetMesh() + if not meshObject: + meshObject = self.GetMesh() + return self.editor.ProjectPoint( x,y,z, elementType, meshObject ) + def GetPointState(self, x, y, z): """ Return point state in a closed 2D mesh in terms of TopAbs_State enumeration: - 0-IN, 1-OUT, 2-ON, 3-UNKNOWN. + smesh.TopAbs_IN, smesh.TopAbs_OUT, smesh.TopAbs_ON and smesh.TopAbs_UNKNOWN. UNKNOWN state means that either mesh is wrong or the analysis fails. """ @@ -4095,6 +4643,41 @@ class Mesh: return self.editor.IsCoherentOrientation2D() + def Get1DBranches( self, edges, startNode = 0 ): + """ + Partition given 1D elements into groups of contiguous edges. + A node where number of meeting edges != 2 is a group end. + An optional startNode is used to orient groups it belongs to. + + Returns: + A list of edge groups and a list of corresponding node groups, + where the group is a list of IDs of edges or nodes, like follows + [[[branch_edges_1],[branch_edges_2]], [[branch_nodes_1],[branch_nodes_2]]]. + If a group is closed, the first and last nodes of the group are same. + """ + if isinstance( edges, Mesh ): + edges = edges.GetMesh() + unRegister = genObjUnRegister() + if isinstance( edges, list ): + edges = self.GetIDSource( edges, SMESH.EDGE ) + unRegister.set( edges ) + return self.editor.Get1DBranches( edges, startNode ) + + def FindSharpEdges( self, angle, addExisting=False ): + """ + Return sharp edges of faces and non-manifold ones. + Optionally add existing edges. + + Parameters: + angle: angle (in degrees) between normals of adjacent faces to detect sharp edges + addExisting: to return existing edges (1D elements) as well + + Returns: + list of FaceEdge structures + """ + angle = ParseParameters( angle )[0] + return self.editor.FindSharpEdges( angle, addExisting ) + def MeshToPassThroughAPoint(self, x, y, z): """ Find the node closest to a point and moves it to a point location @@ -4135,10 +4718,38 @@ class Mesh: Returns: False if proper faces were not found + + Note: + This operation can create gaps in numeration of elements. + Call :meth:`RenumberElements` to remove the gaps. """ return self.editor.DeleteDiag(NodeID1, NodeID2) + def AddNodeOnSegment(self, Node1, Node2, position = 0.5): + """ + Replace each triangle bound by Node1-Node2 segment with + two triangles by connecting a node made on the link with a node + opposite to the link. + + Parameters: + Node1: ID of the first node + Node2: ID of the second node + position: location [0,1] of the new node on the segment + """ + return self.editor.AddNodeOnSegment(Node1, Node2, position) + + def AddNodeOnFace(self, face, x, y, z): + """ + Split a face into triangles by adding a new node onto the face + and connecting the new node with face nodes + + Parameters: + face: ID of the face + x,y,z: coordinates of the new node + """ + return self.editor.AddNodeOnFace(face, x, y, z) + def Reorient(self, IDsOfElements=None): """ Reorient elements by ids @@ -4174,8 +4785,8 @@ class Mesh: Reorient faces contained in *the2DObject*. Parameters: - the2DObject: is a :class:`mesh, sub-mesh, group or filter ` or list of IDs of 2D elements - theDirection: is a desired direction of normal of *theFace*. + the2DObject: a :class:`mesh, sub-mesh, group or filter ` or list of IDs of 2D elements + theDirection: a desired direction of normal of *theFace*. It can be either a GEOM vector or a list of coordinates [x,y,z]. theFaceOrPoint: defines a face of *the2DObject* whose normal will be compared with theDirection. It can be either ID of face or a point @@ -4212,6 +4823,29 @@ class Mesh: theFace = -1 return self.editor.Reorient2D( the2DObject, theDirection, theFace, thePoint ) + def Reorient2DByNeighbours(self, objectFaces, referenceFaces=[]): + """ + Reorient faces contained in a list of *objectFaces* + equally to faces contained in a list of *referenceFaces*. + + Parameters: + objectFaces: list of :class:`mesh, sub-mesh, group, filter ` holding faces to reorient. + referenceFaces: list of :class:`sub-mesh, group, filter ` holding reference faces. It can be empty, then any face in *objectFaces* is used as the reference. + + Returns: + number of reoriented faces. + """ + if not isinstance( objectFaces, list ): + objectFaces = [ objectFaces ] + for i,obj2D in enumerate( objectFaces ): + if isinstance( obj2D, Mesh ): + objectFaces[i] = obj2D.GetMesh() + if not isinstance( referenceFaces, list ): + referenceFaces = [ referenceFaces ] + + return self.editor.Reorient2DByNeighbours( objectFaces, referenceFaces ) + + def Reorient2DBy3D(self, the2DObject, the3DObject, theOutsideNormal=True ): """ Reorient faces according to adjacent volumes. @@ -4265,6 +4899,10 @@ class Mesh: Returns: True in case of success, False otherwise. + + Note: + This operation can create gaps in numeration of elements. + Call :meth:`RenumberElements` to remove the gaps. """ MaxAngle,Parameters,hasVars = ParseAngles(MaxAngle) @@ -4289,6 +4927,10 @@ class Mesh: Returns: True in case of success, False otherwise. + + Note: + This operation can create gaps in numeration of elements. + Call :meth:`RenumberElements` to remove the gaps. """ MaxAngle,Parameters,hasVars = ParseAngles(MaxAngle) @@ -4312,6 +4954,10 @@ class Mesh: Returns: True in case of success, False otherwise. + + Note: + This operation can create gaps in numeration of elements. + Call :meth:`RenumberElements` to remove the gaps. """ if IDsOfElements == []: IDsOfElements = self.GetElementsId() @@ -4335,6 +4981,10 @@ class Mesh: Returns: True in case of success, False otherwise. + + Note: + This operation can create gaps in numeration of elements. + Call :meth:`RenumberElements` to remove the gaps. """ if ( isinstance( theObject, Mesh )): theObject = theObject.GetMesh() @@ -4349,9 +4999,13 @@ class Mesh: a quadrangle. Parameters: - theElements: the faces to be splitted. This can be either + theElements: the faces to be splitted. This can be either :class:`mesh, sub-mesh, group, filter ` or a list of face IDs. By default all quadrangles are split + + Note: + This operation can create gaps in numeration of elements. + Call :meth:`RenumberElements` to remove the gaps. """ unRegister = genObjUnRegister() if isinstance( theElements, Mesh ): @@ -4369,10 +5023,14 @@ class Mesh: Parameters: IDsOfElements: the faces to be splitted - Diag13: is used to choose a diagonal for splitting. + Diag13 (boolean): is used to choose a diagonal for splitting. Returns: True in case of success, False otherwise. + + Note: + This operation can create gaps in numeration of elements. + Call :meth:`RenumberElements` to remove the gaps. """ if IDsOfElements == []: IDsOfElements = self.GetElementsId() @@ -4385,10 +5043,14 @@ class Mesh: Parameters: theObject: the object from which the list of elements is taken, this is :class:`mesh, sub-mesh, group or filter ` - Diag13: is used to choose a diagonal for splitting. + Diag13 (boolean): is used to choose a diagonal for splitting. Returns: True in case of success, False otherwise. + + Note: + This operation can create gaps in numeration of elements. + Call :meth:`RenumberElements` to remove the gaps. """ if ( isinstance( theObject, Mesh )): theObject = theObject.GetMesh() @@ -4406,9 +5068,13 @@ class Mesh: to numerical functors. Returns: - * 1 if 1-3 diagonal is better, - * 2 if 2-4 diagonal is better, + * 1 if 1-3 diagonal is better, + * 2 if 2-4 diagonal is better, * 0 if error occurs. + + Note: + This operation can create gaps in numeration of elements. + Call :meth:`RenumberElements` to remove the gaps. """ return self.editor.BestSplit(IDOfQuad, self.smeshpyD.GetFunctor(theCriterion)) @@ -4421,6 +5087,10 @@ class Mesh: method: flags passing splitting method: smesh.Hex_5Tet, smesh.Hex_6Tet, smesh.Hex_24Tet. smesh.Hex_5Tet - to split the hexahedron into 5 tetrahedrons, etc. + + Note: + This operation can create gaps in numeration of elements. + Call :meth:`RenumberElements` to remove the gaps. """ unRegister = genObjUnRegister() if isinstance( elems, Mesh ): @@ -4445,6 +5115,10 @@ class Mesh: Parameters: elems: elements to split\: :class:`mesh, sub-mesh, group, filter ` or element IDs; if None (default), all bi-quadratic elements will be split + + Note: + This operation can create gaps in numeration of elements. + Call :meth:`RenumberElements` to remove the gaps. """ unRegister = genObjUnRegister() if elems and isinstance( elems, list ) and isinstance( elems[0], int ): @@ -4476,6 +5150,10 @@ class Mesh: allDomains: if :code:`False`, only hexahedra adjacent to one closest to *startHexPoint* are split, else *startHexPoint* is used to find the facet to split in all domains present in *elems*. + + Note: + This operation can create gaps in numeration of elements. + Call :meth:`RenumberElements` to remove the gaps. """ # IDSource unRegister = genObjUnRegister() @@ -4505,6 +5183,10 @@ class Mesh: def SplitQuadsNearTriangularFacets(self): """ Split quadrangle faces near triangular facets of volumes + + Note: + This operation can create gaps in numeration of elements. + Call :meth:`RenumberElements` to remove the gaps. """ faces_array = self.GetElementsByType(SMESH.FACE) for face_id in faces_array: @@ -4539,7 +5221,7 @@ class Mesh: This operation uses :doc:`pattern_mapping` functionality for splitting. Parameters: - theObject: the object from which the list of hexahedrons is taken; + theObject: the object from which the list of hexahedrons is taken; this is :class:`mesh, sub-mesh, group or filter ` theNode000,theNode001: within the range [0,7]; gives the orientation of the pattern relatively each hexahedron: the (0,0,0) key-point of the pattern @@ -4549,6 +5231,10 @@ class Mesh: Returns: True in case of success, False otherwise. + + Note: + This operation can create gaps in numeration of elements. + Call :meth:`RenumberElements` to remove the gaps. """ # Pattern: # 5.---------.6 @@ -4585,12 +5271,12 @@ class Mesh: pattern = self.smeshpyD.GetPattern() isDone = pattern.LoadFromFile(pattern_tetra) if not isDone: - print 'Pattern.LoadFromFile :', pattern.GetErrorCode() + print('Pattern.LoadFromFile :', pattern.GetErrorCode()) return isDone pattern.ApplyToHexahedrons(self.mesh, theObject.GetIDs(), theNode000, theNode001) isDone = pattern.MakeMesh(self.mesh, False, False) - if not isDone: print 'Pattern.MakeMesh :', pattern.GetErrorCode() + if not isDone: print('Pattern.MakeMesh :', pattern.GetErrorCode()) # split quafrangle faces near triangular facets of volumes self.SplitQuadsNearTriangularFacets() @@ -4613,6 +5299,10 @@ class Mesh: Returns: True in case of success, False otherwise. + + Note: + This operation can create gaps in numeration of elements. + Call :meth:`RenumberElements` to remove the gaps. """ # Pattern: 5.---------.6 # /|# /| @@ -4644,12 +5334,12 @@ class Mesh: pattern = self.smeshpyD.GetPattern() isDone = pattern.LoadFromFile(pattern_prism) if not isDone: - print 'Pattern.LoadFromFile :', pattern.GetErrorCode() + print('Pattern.LoadFromFile :', pattern.GetErrorCode()) return isDone pattern.ApplyToHexahedrons(self.mesh, theObject.GetIDs(), theNode000, theNode001) isDone = pattern.MakeMesh(self.mesh, False, False) - if not isDone: print 'Pattern.MakeMesh :', pattern.GetErrorCode() + if not isDone: print('Pattern.MakeMesh :', pattern.GetErrorCode()) # Split quafrangle faces near triangular facets of volumes self.SplitQuadsNearTriangularFacets() @@ -4770,6 +5460,10 @@ class Mesh: Warning: If *theSubMesh* is provided, the mesh can become non-conformal + + Note: + This operation can create gaps in numeration of nodes or elements. + Call :meth:`RenumberElements` to remove the gaps. """ if isinstance( theSubMesh, Mesh ): @@ -4783,7 +5477,7 @@ class Mesh: self.editor.ConvertToQuadratic(theForce3d) error = self.editor.GetLastError() if error and error.comment: - print error.comment + print(error.comment) return error def ConvertFromQuadratic(self, theSubMesh=None): @@ -4797,6 +5491,10 @@ class Mesh: Warning: If *theSubMesh* is provided, the mesh can become non-conformal + + Note: + This operation can create gaps in numeration of nodes or elements. + Call :meth:`RenumberElements` to remove the gaps. """ if theSubMesh: @@ -4852,6 +5550,32 @@ class Mesh: if mesh: mesh = self.smeshpyD.Mesh(mesh) return mesh, group + def MakeBoundaryOfEachElement(self, groupName="", meshName="", toCopyAll=False, groups=[] ): + """ + Create boundary elements around the whole mesh or groups of elements + + Parameters: + groupName: a name of group to store all boundary elements in, + "" means not to create the group + meshName: a name of a new mesh, which is a copy of the initial + mesh + created boundary elements; "" means not to create the new mesh + toCopyAll: if True, the whole initial mesh will be copied into + the new mesh else only boundary elements will be copied into the new mesh + groups: list of :class:`sub-meshes, groups or filters ` of elements to make boundary around + + Returns: + tuple( long, mesh, group ) + - long - number of added boundary elements + - mesh - the :class:`Mesh` where elements were added to + - group - the :class:`group ` of boundary elements or None + """ + dimension=SMESH.BND_2DFROM3D + toCreateAllElements = True # create all boundary elements in the mesh + nb, mesh, group = self.editor.MakeBoundaryElements( dimension,groupName,meshName, + toCopyAll,toCreateAllElements,groups) + if mesh: mesh = self.smeshpyD.Mesh(mesh) + return nb, mesh, group + def MakeBoundaryElements(self, dimension=SMESH.BND_2DFROM3D, groupName="", meshName="", toCopyAll=False, groups=[]): """ @@ -4870,14 +5594,14 @@ class Mesh: groups: list of :class:`sub-meshes, groups or filters ` of elements to make boundary around Returns: - tuple( long, mesh, groups ) + tuple( long, mesh, group ) - long - number of added boundary elements - mesh - the :class:`Mesh` where elements were added to - group - the :class:`group ` of boundary elements or None """ - + toCreateAllElements = False # create only elements in the boundary of the solid nb, mesh, group = self.editor.MakeBoundaryElements(dimension,groupName,meshName, - toCopyAll,groups) + toCopyAll,toCreateAllElements,groups) if mesh: mesh = self.smeshpyD.Mesh(mesh) return nb, mesh, group @@ -5015,7 +5739,7 @@ class Mesh: of all steps, else - size of each step Returns: - the list of created :class:`groups ` if *MakeGroups* == True, + the list of created :class:`groups ` if *MakeGroups* == True, empty list otherwise """ @@ -5047,7 +5771,8 @@ class Mesh: NbOfSteps, Tolerance, MakeGroups, TotalAngle) def ExtrusionSweepObjects(self, nodes, edges, faces, StepVector, NbOfSteps, MakeGroups=False, - scaleFactors=[], linearVariation=False, basePoint=[] ): + scaleFactors=[], linearVariation=False, basePoint=[], + angles=[], anglesVariation=False): """ Generate new elements by extrusion of the given elements and nodes @@ -5061,15 +5786,19 @@ class Mesh: NbOfSteps: the number of steps MakeGroups: forces the generation of new groups from existing ones scaleFactors: optional scale factors to apply during extrusion - linearVariation: if *True*, scaleFactors are spread over all *scaleFactors*, - else scaleFactors[i] is applied to nodes at the i-th extrusion step - basePoint: optional scaling center; if not provided, a gravity center of + linearVariation: if *True*, *scaleFactors* are spread over all *NbOfSteps*, + else *scaleFactors* [i] is applied to nodes at the i-th extrusion step + basePoint: optional scaling and rotation center; if not provided, a gravity center of nodes and elements being extruded is used as the scaling center. It can be either - a list of tree components of the point or - a node ID or - a GEOM point + angles: list of angles in radians. Nodes at each extrusion step are rotated + around *basePoint*, additionally to previous steps. + anglesVariation: forces the computation of rotation angles as linear + variation of the given *angles* along path steps Returns: the list of created :class:`groups ` if *MakeGroups* == True, empty list otherwise @@ -5088,19 +5817,23 @@ class Mesh: if isinstance( basePoint, int): xyz = self.GetNodeXYZ( basePoint ) if not xyz: - raise RuntimeError, "Invalid node ID: %s" % basePoint + raise RuntimeError("Invalid node ID: %s" % basePoint) basePoint = xyz if isinstance( basePoint, geomBuilder.GEOM._objref_GEOM_Object ): basePoint = self.geompyD.PointCoordinates( basePoint ) NbOfSteps,Parameters,hasVars = ParseParameters(NbOfSteps) - Parameters = StepVector.PS.parameters + var_separator + Parameters + scaleFactors,scaleParameters,hasVars = ParseParameters(scaleFactors) + angles,angleParameters,hasVars = ParseAngles(angles) + Parameters = StepVector.PS.parameters + var_separator + \ + Parameters + var_separator + \ + scaleParameters + var_separator + angleParameters self.mesh.SetParameters(Parameters) return self.editor.ExtrusionSweepObjects( nodes, edges, faces, - StepVector, NbOfSteps, + StepVector, NbOfSteps, MakeGroups, scaleFactors, linearVariation, basePoint, - MakeGroups) + angles, anglesVariation ) def ExtrusionSweep(self, IDsOfElements, StepVector, NbOfSteps, MakeGroups=False, IsNodes = False): @@ -5160,7 +5893,9 @@ class Mesh: Elements = [ Elements.GetMesh() ] if isinstance( Elements, list ): if not Elements: - raise RuntimeError, "Elements empty!" + raise RuntimeError("Elements empty!") + if isinstance( Elements[0], Mesh ): + Elements = [ Elements[0].GetMesh() ] if isinstance( Elements[0], int ): Elements = self.GetIDSource( Elements, SMESH.ALL ) unRegister.set( Elements ) @@ -5262,9 +5997,10 @@ class Mesh: return self.editor.AdvancedExtrusion(IDsOfElements, StepVector, NbOfSteps, ExtrFlags, SewTolerance, MakeGroups) - def ExtrusionAlongPathObjects(self, Nodes, Edges, Faces, PathMesh, PathShape=None, + def ExtrusionAlongPathObjects(self, Nodes, Edges, Faces, PathObject, PathShape=None, NodeStart=1, HasAngles=False, Angles=[], LinearVariation=False, - HasRefPoint=False, RefPoint=[0,0,0], MakeGroups=False): + HasRefPoint=False, RefPoint=[0,0,0], MakeGroups=False, + ScaleFactors=[], ScalesVariation=False): """ Generate new elements by extrusion of the given elements and nodes along the path. The path of extrusion must be a meshed edge. @@ -5273,23 +6009,25 @@ class Mesh: Nodes: nodes to extrude: a list including ids, :class:`a mesh, sub-meshes, groups or filters ` Edges: edges to extrude: a list including ids, :class:`a mesh, sub-meshes, groups or filters ` Faces: faces to extrude: a list including ids, :class:`a mesh, sub-meshes, groups or filters ` - PathMesh: 1D mesh or 1D sub-mesh, along which proceeds the extrusion - PathShape: shape (edge) defines the sub-mesh of PathMesh if PathMesh - contains not only path segments, else it can be None + PathObject: :class:`mesh, sub-mesh, group or filter ` containing edges along which proceeds the extrusion + PathShape: optional shape (edge or wire) which defines the sub-mesh of the mesh defined by *PathObject* if the mesh contains not only path segments, else it can be None NodeStart: the first or the last node on the path. Defines the direction of extrusion - HasAngles: allows the shape to be rotated around the path - to get the resulting mesh in a helical fashion - Angles: list of angles + HasAngles: not used obsolete + Angles: list of angles in radians. Nodes at each extrusion step are rotated + around *basePoint*, additionally to previous steps. LinearVariation: forces the computation of rotation angles as linear variation of the given Angles along path steps HasRefPoint: allows using the reference point - RefPoint: the reference point around which the shape is rotated (the mass center of the - shape by default). The User can specify any point as the Reference Point. + RefPoint: optional scaling and rotation center (mass center of the extruded + elements by default). The User can specify any point as the Reference Point. *RefPoint* can be either GEOM Vertex, [x,y,z] or :class:`SMESH.PointStruct` MakeGroups: forces the generation of new groups from existing ones + ScaleFactors: optional scale factors to apply during extrusion + ScalesVariation: if *True*, *scaleFactors* are spread over all *NbOfSteps*, + else *scaleFactors* [i] is applied to nodes at the i-th extrusion step Returns: - list of created :class:`groups ` and + list of created :class:`groups ` and :class:`error code ` Example: :ref:`tui_extrusion_along_path` """ @@ -5304,15 +6042,18 @@ class Mesh: if isinstance( RefPoint, list ): if not RefPoint: RefPoint = [0,0,0] RefPoint = SMESH.PointStruct( *RefPoint ) - if isinstance( PathMesh, Mesh ): - PathMesh = PathMesh.GetMesh() + if isinstance( PathObject, Mesh ): + PathObject = PathObject.GetMesh() Angles,AnglesParameters,hasVars = ParseAngles(Angles) - Parameters = AnglesParameters + var_separator + RefPoint.parameters + ScaleFactors,ScalesParameters,hasVars = ParseParameters(ScaleFactors) + Parameters = AnglesParameters + var_separator + \ + RefPoint.parameters + var_separator + ScalesParameters self.mesh.SetParameters(Parameters) return self.editor.ExtrusionAlongPathObjects(Nodes, Edges, Faces, - PathMesh, PathShape, NodeStart, + PathObject, PathShape, NodeStart, HasAngles, Angles, LinearVariation, - HasRefPoint, RefPoint, MakeGroups) + HasRefPoint, RefPoint, MakeGroups, + ScaleFactors, ScalesVariation) def ExtrusionAlongPathX(self, Base, Path, NodeStart, HasAngles=False, Angles=[], LinearVariation=False, @@ -5326,9 +6067,9 @@ class Mesh: Base: :class:`mesh, sub-mesh, group, filter `, or list of ids of elements for extrusion Path: 1D mesh or 1D sub-mesh, along which proceeds the extrusion NodeStart: the start node from Path. Defines the direction of extrusion - HasAngles: allows the shape to be rotated around the path - to get the resulting mesh in a helical fashion - Angles: list of angles in radians + HasAngles: not used obsolete + Angles: list of angles in radians. Nodes at each extrusion step are rotated + around *basePoint*, additionally to previous steps. LinearVariation: forces the computation of rotation angles as linear variation of the given Angles along path steps HasRefPoint: allows using the reference point @@ -5369,9 +6110,9 @@ class Mesh: PathMesh: mesh containing a 1D sub-mesh on the edge, along which proceeds the extrusion PathShape: shape (edge) defines the sub-mesh for the path NodeStart: the first or the last node on the edge. Defines the direction of extrusion - HasAngles: allows the shape to be rotated around the path - to get the resulting mesh in a helical fashion - Angles: list of angles in radians + HasAngles: not used obsolete + Angles: list of angles in radians. Nodes at each extrusion step are rotated + around *basePoint*, additionally to previous steps. HasRefPoint: allows using the reference point RefPoint: the reference point around which the shape is rotated (the mass center of the shape by default). The User can specify any point as the Reference Point. @@ -5387,6 +6128,8 @@ class Mesh: Example: :ref:`tui_extrusion_along_path` """ + if not IDsOfElements: + IDsOfElements = [ self.GetMesh() ] n,e,f = [],IDsOfElements,IDsOfElements gr,er = self.ExtrusionAlongPathObjects(n,e,f, PathMesh, PathShape, NodeStart, HasAngles, Angles, @@ -5408,9 +6151,9 @@ class Mesh: PathMesh: mesh containing a 1D sub-mesh on the edge, along which the extrusion proceeds PathShape: shape (edge) defines the sub-mesh for the path NodeStart: the first or the last node on the edge. Defines the direction of extrusion - HasAngles: allows the shape to be rotated around the path - to get the resulting mesh in a helical fashion - Angles: list of angles + HasAngles: not used obsolete + Angles: list of angles in radians. Nodes at each extrusion step are rotated + around *basePoint*, additionally to previous steps. HasRefPoint: allows using the reference point RefPoint: the reference point around which the shape is rotated (the mass center of the shape by default). The User can specify any point as the Reference Point. @@ -5420,7 +6163,7 @@ class Mesh: variation of the given Angles along path steps Returns: - list of created :class:`groups ` and + list of created :class:`groups ` and :class:`error code ` if *MakeGroups* == True, only :class:`error code ` otherwise Example: :ref:`tui_extrusion_along_path` @@ -5446,9 +6189,9 @@ class Mesh: PathMesh: mesh containing a 1D sub-mesh on the edge, along which the extrusion proceeds PathShape: shape (edge) defines the sub-mesh for the path NodeStart: the first or the last node on the edge. Defines the direction of extrusion - HasAngles: allows the shape to be rotated around the path - to get the resulting mesh in a helical fashion - Angles: list of angles + HasAngles: not used obsolete + Angles: list of angles in radians. Nodes at each extrusion step are rotated + around *basePoint*, additionally to previous steps. HasRefPoint: allows using the reference point RefPoint: the reference point around which the shape is rotated (the mass center of the shape by default). The User can specify any point as the Reference Point. @@ -5458,7 +6201,7 @@ class Mesh: variation of the given Angles along path steps Returns: - list of created :class:`groups ` and + list of created :class:`groups ` and :class:`error code ` if *MakeGroups* == True, only :class:`error code ` otherwise Example: :ref:`tui_extrusion_along_path` @@ -5484,9 +6227,9 @@ class Mesh: PathMesh: mesh containing a 1D sub-mesh on the edge, along which the extrusion proceeds PathShape: shape (edge) defines the sub-mesh for the path NodeStart: the first or the last node on the edge. Defines the direction of extrusion - HasAngles: allows the shape to be rotated around the path - to get the resulting mesh in a helical fashion - Angles: list of angles + HasAngles: not used obsolete + Angles: list of angles in radians. Nodes at each extrusion step are rotated + around *basePoint*, additionally to previous steps. HasRefPoint: allows using the reference point RefPoint: the reference point around which the shape is rotated (the mass center of the shape by default). The User can specify any point as the Reference Point. @@ -5496,7 +6239,7 @@ class Mesh: variation of the given Angles along path steps Returns: - list of created :class:`groups ` and + list of created :class:`groups ` and :class:`error code ` if *MakeGroups* == True, only :class:`error code ` otherwise Example: :ref:`tui_extrusion_along_path` @@ -5516,7 +6259,7 @@ class Mesh: Parameters: IDsOfElements: list of elements ids Mirror: is :class:`SMESH.AxisStruct` or geom object (point, line, plane) - theMirrorType: smeshBuilder.POINT, smeshBuilder.AXIS or smeshBuilder.PLANE. + theMirrorType: smesh.POINT, smesh.AXIS or smesh.PLANE. If the *Mirror* is a geom object this parameter is unnecessary Copy: allows to copy element (Copy is 1) or to replace with its mirroring (Copy is 0) MakeGroups: forces the generation of new groups from existing ones (if Copy) @@ -5544,7 +6287,7 @@ class Mesh: Parameters: IDsOfElements: the list of elements ids Mirror: is :class:`SMESH.AxisStruct` or geom object (point, line, plane) - theMirrorType: smeshBuilder.POINT, smeshBuilder.AXIS or smeshBuilder.PLANE. + theMirrorType: smesh.POINT, smesh.AXIS or smesh.PLANE. If the *Mirror* is a geom object this parameter is unnecessary MakeGroups: to generate new groups from existing ones NewMeshName: a name of the new mesh to create @@ -5571,7 +6314,7 @@ class Mesh: Parameters: theObject: :class:`mesh, sub-mesh, group or filter ` Mirror: :class:`SMESH.AxisStruct` or geom object (point, line, plane) - theMirrorType: smeshBuilder.POINT, smeshBuilder.AXIS or smeshBuilder.PLANE. + theMirrorType: smesh.POINT, smesh.AXIS or smesh.PLANE. If the *Mirror* is a geom object this parameter is unnecessary Copy: allows copying the element (Copy==True) or replacing it with its mirror (Copy==False) MakeGroups: forces the generation of new groups from existing ones (if Copy) @@ -5599,7 +6342,7 @@ class Mesh: Parameters: theObject: :class:`mesh, sub-mesh, group or filter ` Mirror: :class:`SMESH.AxisStruct` or geom object (point, line, plane) - theMirrorType: smeshBuilder.POINT, smeshBuilder.AXIS or smeshBuilder.PLANE. + theMirrorType: smesh.POINT, smesh.AXIS or smesh.PLANE. If the *Mirror* is a geom object this parameter is unnecessary MakeGroups: forces the generation of new groups from existing ones NewMeshName: the name of the new mesh to create @@ -5746,9 +6489,9 @@ class Mesh: if ( isinstance( thePoint, list )): thePoint = PointStruct( thePoint[0], thePoint[1], thePoint[2] ) if ( isinstance( theScaleFact, float )): - theScaleFact = [theScaleFact] + theScaleFact = [theScaleFact] if ( isinstance( theScaleFact, int )): - theScaleFact = [ float(theScaleFact)] + theScaleFact = [ float(theScaleFact)] self.mesh.SetParameters(thePoint.parameters) @@ -5780,9 +6523,9 @@ class Mesh: if ( isinstance( thePoint, list )): thePoint = PointStruct( thePoint[0], thePoint[1], thePoint[2] ) if ( isinstance( theScaleFact, float )): - theScaleFact = [theScaleFact] + theScaleFact = [theScaleFact] if ( isinstance( theScaleFact, int )): - theScaleFact = [ float(theScaleFact)] + theScaleFact = [ float(theScaleFact)] self.mesh.SetParameters(thePoint.parameters) mesh = self.editor.ScaleMakeMesh(theObject, thePoint, theScaleFact, @@ -5906,7 +6649,7 @@ class Mesh: theObject (SMESH.SMESH_IDSource): the source object (mesh, sub-mesh, group or filter) theValue (float): signed offset size MakeGroups (boolean): forces the generation of new groups from existing ones - CopyElements (boolean): if *NewMeshName* is empty, True means to keep original elements, + CopyElements (boolean): if *NewMeshName* is empty, True means to keep original elements, False means to remove original elements. NewMeshName (string): the name of a mesh to create. If empty, offset elements are added to this mesh @@ -5919,8 +6662,8 @@ class Mesh: theValue,Parameters,hasVars = ParseParameters(Value) mesh_groups = self.editor.Offset(theObject, Value, MakeGroups, CopyElements, NewMeshName) self.mesh.SetParameters(Parameters) - # if mesh_groups[0]: - # return Mesh( self.smeshpyD, self.geompyD, mesh_groups[0] ), mesh_groups[1] + if mesh_groups[0]: + return Mesh( self.smeshpyD, self.geompyD, mesh_groups[0] ), mesh_groups[1] return mesh_groups def FindCoincidentNodes (self, Tolerance, SeparateCornerAndMediumNodes=False): @@ -5942,11 +6685,11 @@ class Mesh: def FindCoincidentNodesOnPart (self, SubMeshOrGroup, Tolerance, exceptNodes=[], SeparateCornerAndMediumNodes=False): """ - Find groups of ajacent nodes within Tolerance. + Find groups of adjacent nodes within Tolerance. Parameters: Tolerance: the value of tolerance - SubMeshOrGroup: :class:`sub-mesh, group or filter ` + SubMeshOrGroup: list of :class:`sub-meshes, groups or filters ` or of node IDs exceptNodes: list of either SubMeshes, Groups or node IDs to exclude from search SeparateCornerAndMediumNodes: if *True*, in quadratic mesh puts corner and medium nodes in separate groups thus preventing @@ -5957,13 +6700,23 @@ class Mesh: """ unRegister = genObjUnRegister() - if (isinstance( SubMeshOrGroup, Mesh )): - SubMeshOrGroup = SubMeshOrGroup.GetMesh() + if not isinstance( SubMeshOrGroup, list ): + SubMeshOrGroup = [ SubMeshOrGroup ] + for i,obj in enumerate( SubMeshOrGroup ): + if isinstance( obj, Mesh ): + SubMeshOrGroup = [ obj.GetMesh() ] + break + if isinstance( obj, int ): + SubMeshOrGroup = [ self.GetIDSource( SubMeshOrGroup, SMESH.NODE )] + unRegister.set( SubMeshOrGroup ) + break + if not isinstance( exceptNodes, list ): exceptNodes = [ exceptNodes ] if exceptNodes and isinstance( exceptNodes[0], int ): exceptNodes = [ self.GetIDSource( exceptNodes, SMESH.NODE )] unRegister.set( exceptNodes ) + return self.editor.FindCoincidentNodesOnPartBut(SubMeshOrGroup, Tolerance, exceptNodes, SeparateCornerAndMediumNodes) @@ -5974,48 +6727,88 @@ class Mesh: Parameters: GroupsOfNodes: a list of groups of nodes IDs for merging. E.g. [[1,12,13],[25,4]] means that nodes 12, 13 and 4 will be removed and replaced - in all elements and groups by nodes 1 and 25 correspondingly + in all elements and mesh groups by nodes 1 and 25 correspondingly NodesToKeep: nodes to keep in the mesh: a list of groups, sub-meshes or node IDs. If *NodesToKeep* does not include a node to keep for some group to merge, then the first node in the group is kept. AvoidMakingHoles: prevent merging nodes which cause removal of elements becoming invalid + + Note: + This operation can create gaps in numeration of nodes or elements. + Call :meth:`RenumberElements` to remove the gaps. """ - # NodesToKeep are converted to SMESH.SMESH_IDSource in meshEditor.MergeNodes() self.editor.MergeNodes( GroupsOfNodes, NodesToKeep, AvoidMakingHoles ) - def FindEqualElements (self, MeshOrSubMeshOrGroup=None): + def FindEqualElements (self, MeshOrSubMeshOrGroup=None, exceptElements=[]): """ Find the elements built on the same nodes. Parameters: - MeshOrSubMeshOrGroup: :class:`mesh, sub-mesh, group or filter ` + MeshOrSubMeshOrGroup: :class:`mesh, sub-meshes, groups or filters ` or element IDs to check for equal elements + exceptElements: list of either SubMeshes, Groups or elements IDs to exclude from search + Returns: the list of groups of equal elements IDs (e.g. [[1,12,13],[4,25]]) """ - if not MeshOrSubMeshOrGroup: - MeshOrSubMeshOrGroup=self.mesh + unRegister = genObjUnRegister() + if MeshOrSubMeshOrGroup is None: + MeshOrSubMeshOrGroup = [ self.mesh ] elif isinstance( MeshOrSubMeshOrGroup, Mesh ): - MeshOrSubMeshOrGroup = MeshOrSubMeshOrGroup.GetMesh() - return self.editor.FindEqualElements( MeshOrSubMeshOrGroup ) - - def MergeElements(self, GroupsOfElementsID): + MeshOrSubMeshOrGroup = [ MeshOrSubMeshOrGroup.GetMesh() ] + elif not isinstance( MeshOrSubMeshOrGroup, list ): + MeshOrSubMeshOrGroup = [ MeshOrSubMeshOrGroup ] + if isinstance( MeshOrSubMeshOrGroup[0], int ): + MeshOrSubMeshOrGroup = [ self.GetIDSource( MeshOrSubMeshOrGroup, SMESH.ALL )] + unRegister.set( MeshOrSubMeshOrGroup ) + for item in MeshOrSubMeshOrGroup: + if isinstance( item, Mesh ): + MeshOrSubMeshOrGroup = [ item.GetMesh() ] + + if not isinstance( exceptElements, list ): + exceptElements = [ exceptElements ] + if exceptElements and isinstance( exceptElements[0], int ): + exceptElements = [ self.GetIDSource( exceptElements, SMESH.ALL )] + unRegister.set( exceptElements ) + + return self.editor.FindEqualElements( MeshOrSubMeshOrGroup, exceptElements ) + + def MergeElements(self, GroupsOfElementsID, ElementsToKeep=[]): """ Merge elements in each given group. Parameters: GroupsOfElementsID: a list of groups (lists) of elements IDs for merging (e.g. [[1,12,13],[25,4]] means that elements 12, 13 and 4 will be removed and - replaced in all groups by elements 1 and 25) + replaced in all mesh groups by elements 1 and 25) + ElementsToKeep: elements to keep in the mesh: a list of groups, sub-meshes or node IDs. + If *ElementsToKeep* does not include an element to keep for some group to merge, + then the first element in the group is kept. + + Note: + This operation can create gaps in numeration of elements. + Call :meth:`RenumberElements` to remove the gaps. """ - self.editor.MergeElements(GroupsOfElementsID) + unRegister = genObjUnRegister() + if ElementsToKeep: + if not isinstance( ElementsToKeep, list ): + ElementsToKeep = [ ElementsToKeep ] + if isinstance( ElementsToKeep[0], int ): + ElementsToKeep = [ self.GetIDSource( ElementsToKeep, SMESH.ALL )] + unRegister.set( ElementsToKeep ) + + self.editor.MergeElements( GroupsOfElementsID, ElementsToKeep ) def MergeEqualElements(self): """ Leave one element and remove all other elements built on the same nodes. + + Note: + This operation can create gaps in numeration of elements. + Call :meth:`RenumberElements` to remove the gaps. """ self.editor.MergeEqualElements() @@ -6030,22 +6823,25 @@ class Mesh: return self.editor.FindFreeBorders( ClosedOnly ) - def FillHole(self, holeNodes): + def FillHole(self, holeNodes, groupName=""): """ Fill with 2D elements a hole defined by a SMESH.FreeBorder. Parameters: - FreeBorder: either a SMESH.FreeBorder or a list on node IDs. These nodes + holeNodes: either a SMESH.FreeBorder or a list on node IDs. These nodes must describe all sequential nodes of the hole border. The first and the last nodes must be the same. Use :meth:`FindFreeBorders` to get nodes of holes. + groupName (string): name of a group to add new faces + Returns: + a :class:`group ` containing the new faces; or :code:`None` if `groupName` == "" """ if holeNodes and isinstance( holeNodes, list ) and isinstance( holeNodes[0], int ): holeNodes = SMESH.FreeBorder(nodeIDs=holeNodes) if not isinstance( holeNodes, SMESH.FreeBorder ): - raise TypeError, "holeNodes must be either SMESH.FreeBorder or list of integer and not %s" % holeNodes - self.editor.FillHole( holeNodes ) + raise TypeError("holeNodes must be either SMESH.FreeBorder or list of integer and not %s" % holeNodes) + return self.editor.FillHole( holeNodes, groupName ) def FindCoincidentFreeBorders (self, tolerance=0.): """ @@ -6082,6 +6878,10 @@ class Mesh: Returns: a number of successfully sewed groups + + Note: + This operation can create gaps in numeration of nodes or elements. + Call :meth:`RenumberElements` to remove the gaps. """ if freeBorders and isinstance( freeBorders, list ): @@ -6092,7 +6892,7 @@ class Mesh: coincidentGroups = [] for nodeList in freeBorders: if not nodeList or len( nodeList ) % 3: - raise ValueError, "Wrong number of nodes in this group: %s" % nodeList + raise ValueError("Wrong number of nodes in this group: %s" % nodeList) group = [] while nodeList: group.append ( SMESH.FreeBorderPart( len(borders), 0, 1, 2 )) @@ -6113,6 +6913,10 @@ class Mesh: Returns: :class:`error code ` + + Note: + This operation can create gaps in numeration of nodes or elements. + Call :meth:`RenumberElements` to remove the gaps. """ return self.editor.SewFreeBorders(FirstNodeID1, SecondNodeID1, LastNodeID1, @@ -6126,6 +6930,10 @@ class Mesh: Returns: :class:`error code ` + + Note: + This operation can create gaps in numeration of elements. + Call :meth:`RenumberElements` to remove the gaps. """ return self.editor.SewConformFreeBorders(FirstNodeID1, SecondNodeID1, LastNodeID1, @@ -6138,6 +6946,10 @@ class Mesh: Returns: :class:`error code ` + + Note: + This operation can create gaps in numeration of elements. + Call :meth:`RenumberElements` to remove the gaps. """ return self.editor.SewBorderToSide(FirstNodeIDOnFreeBorder, SecondNodeIDOnFreeBorder, LastNodeIDOnFreeBorder, @@ -6156,6 +6968,10 @@ class Mesh: Returns: :class:`error code ` + + Note: + This operation can create gaps in numeration of nodes. + Call :meth:`RenumberElements` to remove the gaps. """ return self.editor.SewSideElements(IDsOfSide1Elements, IDsOfSide2Elements, @@ -6164,7 +6980,7 @@ class Mesh: def ChangeElemNodes(self, ide, newIDs): """ - Set new nodes for the given element. + Set new nodes for the given element. Number of nodes should be kept. Parameters: ide: the element ID @@ -6214,17 +7030,17 @@ class Mesh: Parameters: theElements: container of elements to duplicate. It can be a - :class:`mesh, sub-mesh, group, filter ` + :class:`mesh, sub-mesh, group, filter ` or a list of element IDs. If *theElements* is a :class:`Mesh`, elements of highest dimension are duplicated theGroupName: a name of group to contain the generated elements. If a group with such a name already exists, the new elements - are added to the existng group, else a new group is created. + are added to the existing group, else a new group is created. If *theGroupName* is empty, new elements are not added in any group. Returns: - a :class:`group ` where the new elements are added. + a :class:`group ` where the new elements are added. None if *theGroupName* == "". """ @@ -6449,6 +7265,7 @@ class Mesh: return self.editor.AffectedElemGroupsInRegion(theElems, theNodesNot, theShape) def DoubleNodesOnGroupBoundaries(self, theDomains, createJointElems, onAllBoundaries=False ): + """ Double nodes on shared faces between groups of volumes and create flat elements on demand. The list of groups must describe a partition of the mesh volumes. @@ -6492,9 +7309,9 @@ class Mesh: return self.editor.CreateHoleSkin( radius, theShape, groupName, theNodesCoords ) def MakePolyLine(self, segments, groupName='', isPreview=False ): - """ + """ Create a polyline consisting of 1D mesh elements each lying on a 2D element of - the initial mesh. Positions of new nodes are found by cutting the mesh by the + the initial triangle mesh. Positions of new nodes are found by cutting the mesh by the plane passing through pairs of points specified by each :class:`SMESH.PolySegment` structure. If there are several paths connecting a pair of points, the shortest path is selected by the module. Position of the cutting plane is defined by the two @@ -6504,13 +7321,13 @@ class Mesh: The vector goes from the middle point to the projection point. In case of planar mesh, the vector is normal to the mesh. - *segments* [i].vector returns the used vector which goes from the middle point to its projection. + In preview mode, *segments* [i].vector returns the used vector which goes from the middle point to its projection. - Parameters: + Parameters: segments: list of :class:`SMESH.PolySegment` defining positions of cutting planes. groupName: optional name of a group where created mesh segments will be added. - - """ + + """ editor = self.editor if isPreview: editor = self.mesh.GetMeshEditPreviewer() @@ -6519,7 +7336,18 @@ class Mesh: segments[i].vector = seg.vector if isPreview: return editor.GetPreviewData() - return None + return None + + def MakeSlot(self, segmentGroup, width ): + """ + Create a slot of given width around given 1D elements lying on a triangle mesh. + The slot is constructed by cutting faces by cylindrical surfaces made + around each segment. Segments are expected to be created by MakePolyLine(). + + Returns: + FaceEdge's located at the slot boundary + """ + return self.editor.MakeSlot( segmentGroup, width ) def GetFunctor(self, funcType ): """ @@ -6562,56 +7390,112 @@ class Mesh: def GetLength(self, elemId=None): """ - Get length of 1D element or sum of lengths of all 1D mesh elements + Get length of given 1D elements or of all 1D mesh elements Parameters: - elemId: mesh element ID (if not defined - sum of length of all 1D elements will be calculated) + elemId: either a mesh element ID or a list of IDs or :class:`sub-mesh, group or filter `. By default sum length of all 1D elements will be calculated. Returns: - element's length value if *elemId* is specified or sum of all 1D mesh elements' lengths otherwise + Sum of lengths of given elements """ length = 0 if elemId == None: length = self.smeshpyD.GetLength(self) + elif isinstance(elemId, SMESH._objref_SMESH_IDSource): + length = self.smeshpyD.GetLength(elemId) + elif elemId == []: + length = 0 + elif isinstance(elemId, list) and isinstance(elemId[0], SMESH._objref_SMESH_IDSource): + for obj in elemId: + length += self.smeshpyD.GetLength(obj) + elif isinstance(elemId, list) and isinstance(elemId[0], int): + unRegister = genObjUnRegister() + obj = self.GetIDSource( elemId ) + unRegister.set( obj ) + length = self.smeshpyD.GetLength( obj ) else: length = self.FunctorValue(SMESH.FT_Length, elemId) return length def GetArea(self, elemId=None): """ - Get area of 2D element or sum of areas of all 2D mesh elements - elemId mesh element ID (if not defined - sum of areas of all 2D elements will be calculated) + Get area of given 2D elements or of all 2D mesh elements + + Parameters: + elemId: either a mesh element ID or a list of IDs or :class:`sub-mesh, group or filter `. By default sum area of all 2D elements will be calculated. Returns: - element's area value if *elemId* is specified or sum of all 2D mesh elements' areas otherwise + Area of given element's if *elemId* is specified or sum of all 2D mesh elements' areas otherwise """ area = 0 if elemId == None: area = self.smeshpyD.GetArea(self) + elif isinstance(elemId, SMESH._objref_SMESH_IDSource): + area = self.smeshpyD.GetArea(elemId) + elif elemId == []: + area = 0 + elif isinstance(elemId, list) and isinstance(elemId[0], SMESH._objref_SMESH_IDSource): + for obj in elemId: + area += self.smeshpyD.GetArea(obj) + elif isinstance(elemId, list) and isinstance(elemId[0], int): + unRegister = genObjUnRegister() + obj = self.GetIDSource( elemId ) + unRegister.set( obj ) + area = self.smeshpyD.GetArea( obj ) else: area = self.FunctorValue(SMESH.FT_Area, elemId) return area def GetVolume(self, elemId=None): """ - Get volume of 3D element or sum of volumes of all 3D mesh elements + Get volume of given 3D elements or of all 3D mesh elements Parameters: - elemId: mesh element ID (if not defined - sum of volumes of all 3D elements will be calculated) + elemId: either a mesh element ID or a list of IDs or :class:`sub-mesh, group or filter `. By default sum volume of all 3D elements will be calculated. Returns: - element's volume value if *elemId* is specified or sum of all 3D mesh elements' volumes otherwise + Sum element's volume value if *elemId* is specified or sum of all 3D mesh elements' volumes otherwise """ volume = 0 if elemId == None: - volume = self.smeshpyD.GetVolume(self) + volume= self.smeshpyD.GetVolume(self) + elif isinstance(elemId, SMESH._objref_SMESH_IDSource): + volume= self.smeshpyD.GetVolume(elemId) + elif elemId == []: + volume = 0 + elif isinstance(elemId, list) and isinstance(elemId[0], SMESH._objref_SMESH_IDSource): + for obj in elemId: + volume+= self.smeshpyD.GetVolume(obj) + elif isinstance(elemId, list) and isinstance(elemId[0], int): + unRegister = genObjUnRegister() + obj = self.GetIDSource( elemId ) + unRegister.set( obj ) + volume= self.smeshpyD.GetVolume( obj ) else: volume = self.FunctorValue(SMESH.FT_Volume3D, elemId) return volume + def GetAngle(self, node1, node2, node3 ): + """ + Computes a radian measure of an angle defined by 3 nodes: <(node1,node2,node3) + + Parameters: + node1,node2,node3: IDs of the three nodes + + Returns: + Angle in radians [0,PI]. -1 if failure case. + """ + p1 = self.GetNodeXYZ( node1 ) + p2 = self.GetNodeXYZ( node2 ) + p3 = self.GetNodeXYZ( node3 ) + if p1 and p2 and p3: + return self.smeshpyD.GetAngle( p1,p2,p3 ) + return -1. + + def GetMaxElementLength(self, elemId): """ Get maximum element length. @@ -6659,6 +7543,19 @@ class Mesh: return self.FunctorValue(SMESH.FT_Warping, elemId) + def GetWarping3D(self, elemId): + """ + Get warping angle of faces element of 3D elements. + + Parameters: + elemId: mesh element ID + + Returns: + element's warping angle value + """ + + return self.FunctorValue(SMESH.FT_Warping3D, elemId) + def GetMinimumAngle(self, elemId): """ Get minimum angle of 2D element. @@ -6698,6 +7595,19 @@ class Mesh: return self.FunctorValue(SMESH.FT_Skew, elemId) + def GetScaledJacobian(self, elemId): + """ + Get the scaled jacobian of 3D element id + + Parameters: + elemId: mesh element ID + + Returns: + the scaled jacobian + """ + + return self.FunctorValue(SMESH.FT_ScaledJacobian, elemId) + def GetMinMax(self, funType, meshPart=None): """ Return minimal and maximal value of a given functor. @@ -6732,34 +7642,514 @@ class Mesh: pass # end of Mesh class +def _copy_gmsh_param(dim, local_param, global_param): + if dim==3: + local_param.SetMaxSize(global_param.GetMaxSize()) + local_param.SetMinSize(global_param.GetMinSize()) + local_param.Set3DAlgo(global_param.Get3DAlgo()) + local_param.SetRecombineAll(global_param.GetRecombineAll()) + local_param.SetSubdivAlgo(global_param.GetSubdivAlgo()) + local_param.SetRemeshAlgo(global_param.GetRemeshAlgo()) + local_param.SetRemeshPara(global_param.GetRemeshPara()) + local_param.SetSmouthSteps(global_param.GetSmouthSteps()) + local_param.SetSizeFactor(global_param.GetSizeFactor()) + local_param.SetUseIncomplElem(global_param.GetUseIncomplElem()) + local_param.SetMeshCurvatureSize(global_param.GetMeshCurvatureSize()) + local_param.SetSecondOrder(global_param.GetSecondOrder()) + local_param.SetIs2d(global_param.GetIs2d()) + elif dim==2: + local_param.SetMaxSize(global_param.GetMaxSize()) + local_param.SetMinSize(global_param.GetMinSize()) + local_param.Set2DAlgo(global_param.Get2DAlgo()) + local_param.SetRecomb2DAlgo(global_param.GetRecomb2DAlgo()) + local_param.SetRecombineAll(global_param.GetRecombineAll()) + local_param.SetSubdivAlgo(global_param.GetSubdivAlgo()) + local_param.SetRemeshAlgo(global_param.GetRemeshAlgo()) + local_param.SetRemeshPara(global_param.GetRemeshPara()) + local_param.SetSmouthSteps(global_param.GetSmouthSteps()) + local_param.SetSizeFactor(global_param.GetSizeFactor()) + local_param.SetUseIncomplElem(global_param.GetUseIncomplElem()) + local_param.SetMeshCurvatureSize(global_param.GetMeshCurvatureSize()) + local_param.SetSecondOrder(global_param.GetSecondOrder()) + local_param.SetIs2d(global_param.GetIs2d()) + +def _copy_netgen_param(dim, local_param, global_param): + """ + Create 1D/2D/3D netgen parameters from a NETGEN 1D2D3D parameter + """ + if dim==1: + #TODO: More global conversion ? or let user define it + local_param.NumberOfSegments(int(global_param.GetMaxSize())) + elif dim==2: + local_param.SetMaxSize(global_param.GetMaxSize()) + local_param.SetMinSize(global_param.GetMinSize()) + local_param.SetOptimize(global_param.GetOptimize()) + local_param.SetFineness(global_param.GetFineness()) + local_param.SetNbSegPerEdge(global_param.GetNbSegPerEdge()) + local_param.SetNbSegPerRadius(global_param.GetNbSegPerRadius()) + #TODO: Why the 0.9 to have same results + local_param.SetGrowthRate(global_param.GetGrowthRate()*0.9) + local_param.SetChordalError(global_param.GetChordalError()) + local_param.SetChordalErrorEnabled(global_param.GetChordalErrorEnabled()) + local_param.SetUseSurfaceCurvature(global_param.GetUseSurfaceCurvature()) + local_param.SetUseDelauney(global_param.GetUseDelauney()) + local_param.SetQuadAllowed(global_param.GetQuadAllowed()) + local_param.SetWorstElemMeasure(global_param.GetWorstElemMeasure()) + local_param.SetCheckChartBoundary(global_param.GetCheckChartBoundary()) + local_param.SetNbThreads(global_param.GetNbThreads()) + else: + local_param.SetMaxSize(global_param.GetMaxSize()) + local_param.SetMinSize(global_param.GetMinSize()) + local_param.SetOptimize(global_param.GetOptimize()) + local_param.SetCheckOverlapping(global_param.GetCheckOverlapping()) + local_param.SetCheckChartBoundary(global_param.GetCheckChartBoundary()) + local_param.SetFineness(global_param.GetFineness()) + local_param.SetNbSegPerEdge(global_param.GetNbSegPerEdge()) + local_param.SetNbSegPerRadius(global_param.GetNbSegPerRadius()) + local_param.SetGrowthRate(global_param.GetGrowthRate()) + local_param.SetNbThreads(global_param.GetNbThreads()) + + +def _shaperstudy2geom(geompyD, shaper_obj): + """ + Convertion of shaper object to geom object + + Parameters: + geompyD: geomBuilder instance + shaper_obj: Shaper study object + + Returns: + geom object + + """ + import tempfile + #Writing shaperstudy object into a brep file + fid, tmp_file = tempfile.mkstemp(suffix='.brep') + with open(fid, 'wb') as f: + f.write(shaper_obj.GetShapeStream()) + # Reimporting brep file into geom + real_geom = geompyD.ImportBREP(tmp_file) + os.remove(tmp_file) + + return real_geom + + +def _split_geom(geompyD, geom): + """ + Splitting geometry into n solids and a 2D/1D compound + + Parameters: + geompyD: geomBuilder instance + geom: geometrical object for meshing + + Returns: + compound containing all the 1D,2D elements + list of solids + """ + + # Splitting geometry into 3D elements and all the 2D/1D into one compound + object_solids = geompyD.ExtractShapes(geom, geompyD.ShapeType["SOLID"], + True) + + solids = [] + isolid = 0 + for solid in object_solids: + isolid += 1 + geompyD.addToStudyInFather( geom, solid, 'Solid_{}'.format(isolid) ) + solids.append(solid) + # If geom is a solid ExtractShapes will return nothin in that case geom is the solids + if isolid == 0: + solids = [geom] + + faces = [] + iface = 0 + solid_faces = geompyD.ExtractShapes(geom, geompyD.ShapeType["FACE"], + True) + for face in solid_faces: + faces.append(face) + iface += 1 + geompyD.addToStudyInFather(geom, face, + 'Face_{}'.format(iface)) + + return faces, solids + + +MULTITHREAD, MULTINODE = range(2) +class ParallelismSettings: + """ + Defines the parameters for the parallelism of ParallelMesh + """ + def __init__(self, mesh): + """ + Construsctor + + Parameters: + mesh: Instance of ParallelMesh + """ + if not(isinstance(mesh, ParallelMesh)): + raise ValueError("mesh should be a ParallelMesh") + + self._mesh = mesh + + +class MTParallelismSettings(ParallelismSettings): + """ + Defines the parameters for the parallelism of ParallelMesh using MultiThreading + """ + def __init__(self, mesh): + ParallelismSettings.__init__(self, mesh) + + # Multithreading methods + def SetNbThreads(self, nbThreads): + """ Set the number of threads for multithread """ + if nbThreads < 1: + raise ValueError("Number of threads must be stricly greater than 1") + + self._mesh.mesh.SetNbThreads(nbThreads) + + def GetNbThreads(self): + """ Get Number of threads """ + return self._mesh.mesh.GetNbThreads() + + def __str__(self): + """ str conversion """ + string = "\nParameter for MultiThreading parallelism:\n" + string += "NbThreads: {}\n".format(self.GetNbThreads()) + + return string + + +class MNParallelismSettings(ParallelismSettings): + """ + Defines the parameters for the parallelism of ParallelMesh using MultiNodal + """ + def __init__(self, mesh): + ParallelismSettings.__init__(self, mesh) + + def GetResource(self): + """ Get the resource on which to run """ + return self._mesh.mesh.GetResource() + + def SetResource(self, resource): + """ Set the resource on which to run """ + self._mesh.mesh.SetResource(resource) + + def SetNbProc(self, nbProc): + """ Set the number of Processor for multinode """ + if nbProc < 1: + raise ValueError("Number of Proc must be stricly greater than 1") + self._mesh.mesh.SetNbProc(nbProc) + + def GetNbProc(self): + """ Get Number of Processor """ + return self._mesh.mesh.GetNbProc() + + def SetNbProcPerNode(self, nbProcPerNode): + """ Set the number of Processor Per Node for multinode """ + if nbProcPerNode < 1: + raise ValueError("Number of Processor Per Node must be stricly greater than 1") + + self._mesh.mesh.SetNbProcPerNode(nbProcPerNode) + + def GetNbProcPerNode(self): + """ Get Number of Processor Per Node """ + return self._mesh.mesh.GetNbProcPerNode() + + def SetNbNode(self, nbNode): + """ Set the number of Node for multinode """ + if nbNode < 1: + raise ValueError("Number of Node must be stricly greater than 1") + self._mesh.mesh.SetNbNode(nbNode) + + def GetNbNode(self): + """ Get Number of Node """ + return self._mesh.mesh.GetNbNode() + + def SetWcKey(self, wcKey): + """ Set the number of Node for multinode """ + self._mesh.mesh.SetWcKey(wcKey) + + def GetWcKey(self): + """ Get Number of Node """ + return self._mesh.mesh.GetWcKey() + + def SetWalltime(self, walltime): + """ Set the number of Node for multinode """ + self._mesh.mesh.SetWalltime(walltime) + + def GetWalltime(self): + """ Get Number of Node """ + return self._mesh.mesh.GetWalltime() + + def __str__(self): + """ str conversion """ + string = "\nParameter for MultiNode parallelism:\n" + string += "Reource: {}\n".format(self.GetResource()) + string += "NbProc: {}\n".format(self.GetNbProc()) + string += "NbProcPerNode: {}\n".format(self.GetNbProcPerNode()) + string += "NbNode: {}\n".format(self.GetNbNode()) + string += "WcKey: {}\n".format(self.GetWcKey()) + string += "Walltime: {}\n".format(self.GetWalltime()) + + return string + + +class ParallelMesh(Mesh): + """ + Surcharge on Mesh for parallel computation of a mesh + """ + def __init__(self, smeshpyD, geompyD, geom, split_geom=True, name=0): + """ + Create a parallel mesh. + + Parameters: + smeshpyD: instance of smeshBuilder + geompyD: instance of geomBuilder + geom: geometrical object for meshing + split_geom: If true will divide geometry on solids and 1D/2D + coumpound and create the associated submeshes + name: the name for the new mesh. + + Returns: + an instance of class :class:`ParallelMesh`. + """ + + if not isinstance(geom, geomBuilder.GEOM._objref_GEOM_Object): + raise ValueError("geom argument must be a geometry") + + try: + import SHAPERSTUDY + shaper_object = SHAPERSTUDY.SHAPERSTUDY_ORB._objref_SHAPER_Object + has_shaper = True + except ImportError: + shaper_object = int + has_shaper = False + + # If we have a shaper object converting it into geom (temporary solution) + if isinstance(geom, shaper_object): + self._geom_obj = _shaperstudy2geom(geompyD, geom) + elif isinstance(geom, geomBuilder.GEOM._objref_GEOM_Object): + self._geom_obj = geom + else: + msg= "" + if not has_shaper: + msg = "\nShaper was not compiled" + raise Exception("Could not handle geom format {}.{} ".format(type(geom), msg)) + + # Splitting geometry into one geom containing 1D and 2D elements and a + # list of 3D elements + super(ParallelMesh, self).__init__(smeshpyD, geompyD, self._geom_obj, name, parallel=True) + + if split_geom: + self._faces, self._solids = _split_geom(geompyD, self._geom_obj) + + self._param = None + + def _build_submeshes(self, mesher2D, mesher3D): + """ + Contruct the submeshes for a parallel use of smesh + + Parameters: + mesher2D: name of 2D mesher for 2D parallel compute (NETGEN) + mesher3D: name of 3D mesher for 3D parallel compute (NETGEN or + GMSH) + """ + + # Building global 2D mesher + if mesher3D: + if mesher3D == "NETGEN": + algo2D = "NETGEN_2D" + elif mesher3D == "GMSH": + algo2D = "GMSH_2D" + else: + raise ValueError("mesher3D should be either NETGEN or GMSH") + + self._algo2d = self.Triangle(geom=self._geom_obj, algo=algo2D) + + # Parallel 2D + if mesher2D: + #Means that we want to mesh face of solids in parallel and not + #the volume + self._algo2d = [] + #For the moment use AutomaticLength based on finesse + # TODO: replace by input hypothesis + self._algo1d = self.Segment(geom=self._geom_obj) + + for face_id, face in enumerate(self._faces): + name = "face_{}".format(face_id) + algo2d = self.Triangle(geom=face, algo="NETGEN_2D_Remote") + self._algo2d.append(algo2d) + + if mesher3D: + self._algo3d = [] + for solid_id, solid in enumerate(self._solids): + name = "Solid_{}".format(solid_id) + if ( mesher3D == "NETGEN" ): + algo3d = self.Tetrahedron(geom=solid, algo="NETGEN_3D_Remote") + self._algo3d.append(algo3d) + elif ( mesher3D == "GMSH" ): + algo3d = self.Tetrahedron(geom=solid, algo="GMSH_3D_Remote") + self._algo3d.append(algo3d) + + def GetNbSolids(self): + """ + Return the number of 3D solids + """ + return len(self._solids) + + def GetNbFaces(self): + """ + Return the number of 2D faces + """ + return len(self._faces) + + def GetParallelismMethod(self): + """ Get the parallelims method """ + return self.mesh.GetParallelismMethod() + + def SetParallelismMethod(self, method): + """ Set the parallelims method """ + if method not in [MULTITHREAD , MULTINODE]: + raise ValueError("Parallelism method can only be 0:MultiThread or 1:MultiNode") + + self.mesh.SetParallelismMethod(method) + + if method == MULTITHREAD: + self._param = MTParallelismSettings(self) + else: + self._param = MNParallelismSettings(self) + + def GetParallelismSettings(self): + """ + Return class to set parameters for the parallelism + """ + if self._param is None: + raise Exception("You need to set Parallelism method first (SetParallelismMethod)") + return self._param + + def AddGlobalHypothesis(self, hyp): + """ + Split hypothesis to apply it to all the submeshes: + - the 1D+2D + - each of the 3D solids + + Parameters: + hyp: a hypothesis to assign + + """ + if isinstance(hyp, NETGENPlugin._objref_NETGENPlugin_Hypothesis): + copy_param = _copy_netgen_param + mesher3D = "NETGEN" + elif isinstance(hyp, GMSHPlugin._objref_GMSHPlugin_Hypothesis): + copy_param = _copy_gmsh_param + mesher3D = "GMSH" + else: + raise ValueError("param must come from NETGENPlugin or GMSHPlugin") + + self.mesh.SetParallelismDimension(3) + self._build_submeshes(None, mesher3D) + + param2d = self._algo2d.Parameters() + copy_param(2, param2d, hyp) + + for algo3d in self._algo3d: + param3d = algo3d.Parameters() + copy_param(3, param3d, hyp) + + def Add2DGlobalHypothesis(self, hyp): + """ + Split hypothesis to apply it to all the submeshes: + - the 1D + - each of the 2D faces + + Parameters: + hyp: a hypothesis to assign + + """ + if isinstance(hyp, NETGENPlugin._objref_NETGENPlugin_Hypothesis): + copy_param = _copy_netgen_param + mesher2D = "NETGEN" + else: + raise ValueError("param must come from NETGENPlugin") + + self.mesh.SetParallelismDimension(2) + self._build_submeshes(mesher2D, None) + + param1d = self._algo1d + copy_param(1, param1d, hyp) + + for algo2d in self._algo2d: + param2d = algo2d.Parameters() + copy_param(2, param2d, hyp) + + pass # End of ParallelMesh class meshProxy(SMESH._objref_SMESH_Mesh): """ Private class used to compensate change of CORBA API of SMESH_Mesh for backward compatibility with old dump scripts which call SMESH_Mesh directly and not via smeshBuilder.Mesh """ - def __init__(self): - SMESH._objref_SMESH_Mesh.__init__(self) + def __init__(self,*args): + SMESH._objref_SMESH_Mesh.__init__(self,*args) def __deepcopy__(self, memo=None): - new = self.__class__() + new = self.__class__(self) return new def CreateDimGroup(self,*args): # 2 args added: nbCommonNodes, underlyingOnly if len( args ) == 3: args += SMESH.ALL_NODES, True - return SMESH._objref_SMESH_Mesh.CreateDimGroup( self, *args ) - pass + return SMESH._objref_SMESH_Mesh.CreateDimGroup(self, *args) + def ExportToMEDX(self, *args): # function removed + print("WARNING: ExportToMEDX() is deprecated, use ExportMED() instead") + #args = [i for i in args if i not in [SMESH.MED_V2_1, SMESH.MED_V2_2]] + SMESH._objref_SMESH_Mesh.ExportMED(self, *args) + def ExportToMED(self, *args): # function removed + print("WARNING: ExportToMED() is deprecated, use ExportMED() instead") + #args = [i for i in args if i not in [SMESH.MED_V2_1, SMESH.MED_V2_2]] + args2 = list(args) + while len(args2) < 5: # !!!! nb of parameters for ExportToMED IDL's method + args2.append(True) + SMESH._objref_SMESH_Mesh.ExportMED(self, *args2) + def ExportPartToMED(self, *args): # 'version' parameter removed + #args = [i for i in args if i not in [SMESH.MED_V2_1, SMESH.MED_V2_2]] + SMESH._objref_SMESH_Mesh.ExportPartToMED(self, *args) + def ExportMED(self, *args): # signature of method changed + #args = [i for i in args if i not in [SMESH.MED_V2_1, SMESH.MED_V2_2]] + args2 = list(args) + while len(args2) < 5: # !!!! nb of parameters for ExportToMED IDL's method + args2.append(True) + SMESH._objref_SMESH_Mesh.ExportMED(self, *args2) + def ExportUNV(self, *args): # renumber arg added + if len( args ) == 1: + args += True, + return SMESH._objref_SMESH_Mesh.ExportUNV(self, *args) + def ExportDAT(self, *args): # renumber arg added + if len( args ) == 1: + args += True, + return SMESH._objref_SMESH_Mesh.ExportDAT(self, *args) + omniORB.registerObjref(SMESH._objref_SMESH_Mesh._NP_RepositoryId, meshProxy) +class parallelMeshProxy(SMESH._objref_SMESH_ParallelMesh): + def __init__(self,*args): + SMESH._objref_SMESH_ParallelMesh.__init__(self,*args) + def __deepcopy__(self, memo=None): + new = self.__class__(self) + return new +omniORB.registerObjref(SMESH._objref_SMESH_ParallelMesh._NP_RepositoryId, parallelMeshProxy) + + + class submeshProxy(SMESH._objref_SMESH_subMesh): + """ Private class wrapping SMESH.SMESH_SubMesh in order to add Compute() """ - def __init__(self): - SMESH._objref_SMESH_subMesh.__init__(self) + def __init__(self,*args): + SMESH._objref_SMESH_subMesh.__init__(self,*args) self.mesh = None def __deepcopy__(self, memo=None): - new = self.__class__() + new = self.__class__(self) return new def Compute(self,refresh=False): @@ -6781,11 +8171,8 @@ class submeshProxy(SMESH._objref_SMESH_subMesh): ok = self.mesh.Compute( self.GetSubShape(),refresh=[] ) - if salome.sg.hasDesktop() and self.mesh.GetStudyId() >= 0: - smeshgui = salome.ImportComponentGUI("SMESH") - smeshgui.Init(self.mesh.GetStudyId()) - smeshgui.SetMeshIcon( salome.ObjectToID( self ), ok, (self.GetNumberOfElements()==0) ) - if refresh: salome.sg.updateObjBrowser(True) + if salome.sg.hasDesktop(): + if refresh: salome.sg.updateObjBrowser() pass return ok @@ -6799,8 +8186,8 @@ class meshEditor(SMESH._objref_SMESH_MeshEditor): compatibility with old dump scripts which call SMESH_MeshEditor directly and not via smeshBuilder.Mesh """ - def __init__(self): - SMESH._objref_SMESH_MeshEditor.__init__(self) + def __init__(self,*args): + SMESH._objref_SMESH_MeshEditor.__init__( self, *args) self.mesh = None def __getattr__(self, name ): # method called if an attribute not found if not self.mesh: # look for name() method in Mesh class @@ -6809,10 +8196,10 @@ class meshEditor(SMESH._objref_SMESH_MeshEditor): return getattr( self.mesh, name ) if name == "ExtrusionAlongPathObjX": return getattr( self.mesh, "ExtrusionAlongPathX" ) # other method name - print "meshEditor: attribute '%s' NOT FOUND" % name + print("meshEditor: attribute '%s' NOT FOUND" % name) return None def __deepcopy__(self, memo=None): - new = self.__class__() + new = self.__class__(self) return new def FindCoincidentNodes(self,*args): # a 2nd arg added (SeparateCornerAndMediumNodes) if len( args ) == 1: args += False, @@ -6885,13 +8272,13 @@ class algoCreator: """ Store a python class of algorithm """ - if type( algoClass ).__name__ == 'classobj' and \ + if inspect.isclass(algoClass) and \ hasattr( algoClass, "algoType"): self.algoTypeToClass[ algoClass.algoType ] = algoClass if not self.defaultAlgoType and \ hasattr( algoClass, "isDefault") and algoClass.isDefault: self.defaultAlgoType = algoClass.algoType - #print "Add",algoClass.algoType, "dflt",self.defaultAlgoType + #print("Add",algoClass.algoType, "dflt",self.defaultAlgoType) def copy(self, mesh): """ @@ -6939,10 +8326,10 @@ class algoCreator: algoType = self.defaultAlgoType if not algoType and self.algoTypeToClass: algoType = sorted( self.algoTypeToClass.keys() )[0] - if self.algoTypeToClass.has_key( algoType ): - #print "Create algo",algoType + if algoType in self.algoTypeToClass: + #print("Create algo",algoType) return self.algoTypeToClass[ algoType ]( self.mesh, shape ) - raise RuntimeError, "No class found for algo type %s" % algoType + raise RuntimeError( "No class found for algo type %s" % algoType) return None class hypMethodWrapper: @@ -6953,7 +8340,7 @@ class hypMethodWrapper: def __init__(self, hyp, method): self.hyp = hyp self.method = method - #print "REBIND:", method.__name__ + #print("REBIND:", method.__name__) return def __call__(self,*args): @@ -6964,7 +8351,7 @@ class hypMethodWrapper: if not args: return self.method( self.hyp, *args ) # hypothesis method with no args - #print "MethWrapper.__call__",self.method.__name__, args + #print("MethWrapper.__call__", self.method.__name__, args) try: parsed = ParseParameters(*args) # replace variables with their values self.hyp.SetVarParameter( parsed[-2], self.method.__name__ ) @@ -6972,11 +8359,11 @@ class hypMethodWrapper: except omniORB.CORBA.BAD_PARAM: # raised by hypothesis method call # maybe there is a replaced string arg which is not variable result = self.method( self.hyp, *args ) - except ValueError, detail: # raised by ParseParameters() + except ValueError as detail: # raised by ParseParameters() try: result = self.method( self.hyp, *args ) except omniORB.CORBA.BAD_PARAM: - raise ValueError, detail # wrong variable name + raise ValueError(detail) # wrong variable name return result pass @@ -7004,30 +8391,30 @@ class genObjUnRegister: if genObj and hasattr( genObj, "UnRegister" ): genObj.UnRegister() -for pluginName in os.environ[ "SMESH_MeshersList" ].split( ":" ): +for pluginName in os.environ[ "SMESH_MeshersList" ].split( os.pathsep ): """ Bind methods creating mesher plug-ins to the Mesh class """ - # print "pluginName: ", pluginName + # print("pluginName: ", pluginName) pluginBuilderName = pluginName + "Builder" try: exec( "from salome.%s.%s import *" % (pluginName, pluginBuilderName)) - except Exception, e: + except Exception as e: from salome_utils import verbose - if verbose(): print "Exception while loading %s: %s" % ( pluginBuilderName, e ) + if verbose(): print("Exception while loading %s: %s" % ( pluginBuilderName, e )) continue exec( "from salome.%s import %s" % (pluginName, pluginBuilderName)) plugin = eval( pluginBuilderName ) - # print " plugin:" , str(plugin) + # print(" plugin:" , str(plugin)) # add methods creating algorithms to Mesh for k in dir( plugin ): if k[0] == '_': continue algo = getattr( plugin, k ) - # print " algo:", str(algo) - if type( algo ).__name__ == 'classobj' and hasattr( algo, "meshMethod" ): - # print " meshMethod:" , str(algo.meshMethod) + #print(" algo:", str(algo)) + if inspect.isclass(algo) and hasattr(algo, "meshMethod"): + #print(" meshMethod:" , str(algo.meshMethod)) if not hasattr( Mesh, algo.meshMethod ): setattr( Mesh, algo.meshMethod, algoCreator( algo.meshMethod )) pass