X-Git-Url: http://git.salome-platform.org/gitweb/?p=modules%2Fsmesh.git;a=blobdiff_plain;f=src%2FSMESH_SWIG%2FsmeshBuilder.py;h=2a6238966f401e92c36ec8af83f72b22cd9b9e5f;hp=147d8dd9cd7b839156ed410c1611559b1483d893;hb=6472eab132825fec572beda8276947593f85ffa1;hpb=9133087aaad73df476f99957974ad9770458860a diff --git a/src/SMESH_SWIG/smeshBuilder.py b/src/SMESH_SWIG/smeshBuilder.py index 147d8dd9c..2a6238966 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-2019 CEA/DEN, EDF R&D, OPEN CASCADE # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -303,7 +303,9 @@ 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(): ## get a name @@ -316,27 +318,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 """ @@ -473,6 +461,24 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): obj,name = name,obj return Mesh(self, self.geompyD, obj, 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): """ Return a long value from enumeration @@ -511,8 +517,8 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): 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): @@ -525,13 +531,13 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): 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.") 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 @@ -561,28 +567,29 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): :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 @@ -731,10 +738,10 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): 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 @@ -743,24 +750,38 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): 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 CopyMesh( self, meshPart, meshName, toCopyGroups=False, toKeepIDs=False): @@ -780,11 +801,46 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): 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 @@ -903,7 +959,8 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): 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 @@ -954,7 +1011,8 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): 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 @@ -1142,6 +1200,8 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): 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: @@ -1179,11 +1239,30 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): 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" } @@ -1391,13 +1470,16 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): def GetGravityCenter(self, obj): """ - Get gravity center of all nodes of the mesh object. + 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) + 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() @@ -1406,6 +1488,28 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): 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 @@ -1539,14 +1643,15 @@ class Mesh(metaclass = MeshMeta): 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() + if self.geom: + self.geompyD = self.geom.GetGen() + pass pass def GetMesh(self): @@ -1559,6 +1664,18 @@ class Mesh(metaclass = MeshMeta): 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 @@ -1966,7 +2083,14 @@ class Mesh(metaclass = MeshMeta): 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 ` @@ -2188,11 +2312,17 @@ class Mesh(metaclass = MeshMeta): 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. + 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. """ # process positional arguments #args = [i for i in args if i not in [SMESH.MED_V2_1, SMESH.MED_V2_2]] # backward compatibility @@ -2204,6 +2334,7 @@ class Mesh(metaclass = MeshMeta): 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. # process keywords arguments auto_groups = kwargs.get("auto_groups", auto_groups) minor = kwargs.get("minor", minor) @@ -2212,14 +2343,20 @@ class Mesh(metaclass = MeshMeta): autoDimension = kwargs.get("autoDimension", autoDimension) fields = kwargs.get("fields", fields) geomAssocFields = kwargs.get("geomAssocFields", geomAssocFields) + z_tolerance = kwargs.get("zTolerance", z_tolerance) + # invoke engine's function - if meshPart or fields or geomAssocFields: + if meshPart or fields or geomAssocFields or z_tolerance > 0: 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) + self.mesh.ExportPartToMED( meshPart, fileName, auto_groups, minor, overwrite, autoDimension, - fields, geomAssocFields) + fields, geomAssocFields, z_tolerance) else: self.mesh.ExportMED(fileName, auto_groups, minor, overwrite, autoDimension) @@ -2405,6 +2542,25 @@ class Mesh(metaclass = MeshMeta): 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. + + 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: # ---------------------- @@ -2473,7 +2629,7 @@ class Mesh(metaclass = MeshMeta): 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 @@ -2635,6 +2791,10 @@ class Mesh(metaclass = MeshMeta): 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) @@ -2809,7 +2969,7 @@ class Mesh(metaclass = MeshMeta): 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. @@ -2835,6 +2995,22 @@ class Mesh(metaclass = MeshMeta): 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): """ @@ -2953,8 +3129,6 @@ class Mesh(metaclass = MeshMeta): 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" } @@ -3444,16 +3618,20 @@ class Mesh(metaclass = MeshMeta): 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): """ @@ -3627,26 +3805,40 @@ class Mesh(metaclass = MeshMeta): 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: # ------------------------------------ @@ -3678,7 +3870,9 @@ class Mesh(metaclass = MeshMeta): 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) @@ -3799,6 +3993,10 @@ class Mesh(metaclass = MeshMeta): 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) @@ -3812,6 +4010,10 @@ class Mesh(metaclass = MeshMeta): 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) @@ -3822,6 +4024,10 @@ class Mesh(metaclass = MeshMeta): 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() @@ -4166,8 +4372,6 @@ class Mesh(metaclass = MeshMeta): 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): @@ -4188,6 +4392,19 @@ class Mesh(metaclass = MeshMeta): 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: @@ -4211,6 +4428,41 @@ class Mesh(metaclass = MeshMeta): 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 elements, 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 @@ -4251,6 +4503,10 @@ class Mesh(metaclass = MeshMeta): 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) @@ -4290,8 +4546,8 @@ class Mesh(metaclass = MeshMeta): 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 @@ -4381,6 +4637,10 @@ class Mesh(metaclass = MeshMeta): 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) @@ -4405,6 +4665,10 @@ class Mesh(metaclass = MeshMeta): 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) @@ -4428,6 +4692,10 @@ class Mesh(metaclass = MeshMeta): 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() @@ -4451,6 +4719,10 @@ class Mesh(metaclass = MeshMeta): 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() @@ -4468,6 +4740,10 @@ class Mesh(metaclass = MeshMeta): 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 ): @@ -4485,10 +4761,14 @@ class Mesh(metaclass = MeshMeta): 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() @@ -4501,10 +4781,14 @@ class Mesh(metaclass = MeshMeta): 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() @@ -4525,6 +4809,10 @@ class Mesh(metaclass = MeshMeta): * 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)) @@ -4537,6 +4825,10 @@ class Mesh(metaclass = MeshMeta): 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 ): @@ -4561,6 +4853,10 @@ class Mesh(metaclass = MeshMeta): 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 ): @@ -4592,6 +4888,10 @@ class Mesh(metaclass = MeshMeta): 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() @@ -4621,6 +4921,10 @@ class Mesh(metaclass = MeshMeta): 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: @@ -4665,6 +4969,10 @@ class Mesh(metaclass = MeshMeta): 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 @@ -4729,6 +5037,10 @@ class Mesh(metaclass = MeshMeta): 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 # /|# /| @@ -4886,6 +5198,10 @@ class Mesh(metaclass = MeshMeta): 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 ): @@ -4913,6 +5229,10 @@ class Mesh(metaclass = MeshMeta): 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: @@ -4986,7 +5306,7 @@ class Mesh(metaclass = MeshMeta): 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 @@ -5163,7 +5483,8 @@ class Mesh(metaclass = MeshMeta): 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 @@ -5177,15 +5498,19 @@ class Mesh(metaclass = MeshMeta): 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 @@ -5210,13 +5535,17 @@ class Mesh(metaclass = MeshMeta): 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): @@ -5277,6 +5606,8 @@ class Mesh(metaclass = MeshMeta): if isinstance( Elements, list ): if not Elements: 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 ) @@ -5378,9 +5709,10 @@ class Mesh(metaclass = MeshMeta): 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. @@ -5389,20 +5721,22 @@ class Mesh(metaclass = MeshMeta): 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 @@ -5420,15 +5754,18 @@ class Mesh(metaclass = MeshMeta): 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, @@ -5442,9 +5779,9 @@ class Mesh(metaclass = MeshMeta): 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 @@ -5485,9 +5822,9 @@ class Mesh(metaclass = MeshMeta): 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. @@ -5503,6 +5840,8 @@ class Mesh(metaclass = MeshMeta): 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, @@ -5524,9 +5863,9 @@ class Mesh(metaclass = MeshMeta): 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. @@ -5562,9 +5901,9 @@ class Mesh(metaclass = MeshMeta): 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. @@ -5600,9 +5939,9 @@ class Mesh(metaclass = MeshMeta): 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. @@ -6062,7 +6401,7 @@ class Mesh(metaclass = MeshMeta): 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 @@ -6073,13 +6412,23 @@ class Mesh(metaclass = MeshMeta): """ 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) @@ -6090,48 +6439,88 @@ class Mesh(metaclass = MeshMeta): 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() @@ -6151,12 +6540,12 @@ class Mesh(metaclass = MeshMeta): 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 :option:`groupName` == "" + a :class:`group ` containing the new faces; or :code:`None` if `groupName` == "" """ @@ -6164,7 +6553,7 @@ class Mesh(metaclass = MeshMeta): 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, groupName ) + return self.editor.FillHole( holeNodes, groupName ) def FindCoincidentFreeBorders (self, tolerance=0.): """ @@ -6201,6 +6590,10 @@ class Mesh(metaclass = MeshMeta): 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 ): @@ -6232,6 +6625,10 @@ class Mesh(metaclass = MeshMeta): 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, @@ -6245,6 +6642,10 @@ class Mesh(metaclass = MeshMeta): 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, @@ -6257,6 +6658,10 @@ class Mesh(metaclass = MeshMeta): 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, @@ -6275,6 +6680,10 @@ class Mesh(metaclass = MeshMeta): 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, @@ -6283,7 +6692,7 @@ class Mesh(metaclass = MeshMeta): 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 @@ -6614,7 +7023,7 @@ class Mesh(metaclass = MeshMeta): 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 @@ -6624,12 +7033,12 @@ class Mesh(metaclass = MeshMeta): 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: @@ -6639,7 +7048,18 @@ class Mesh(metaclass = MeshMeta): 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 ): """ @@ -6682,56 +7102,112 @@ class Mesh(metaclass = MeshMeta): 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. @@ -6874,17 +7350,19 @@ class meshProxy(SMESH._objref_SMESH_Mesh): 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]] - while len(args) < 4: # !!!! nb of parameters for ExportToMED IDL's method - args.append(True) - SMESH._objref_SMESH_Mesh.ExportMED(self, *args) + 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]] - while len(args) < 4: # !!!! nb of parameters for ExportToMED IDL's method - args.append(True) - SMESH._objref_SMESH_Mesh.ExportMED(self, *args) + 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) pass omniORB.registerObjref(SMESH._objref_SMESH_Mesh._NP_RepositoryId, meshProxy) @@ -7140,7 +7618,7 @@ 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 """