Salome HOME
Merge 'master' branch into 'V9_dev' branch.
[modules/smesh.git] / src / SMESH_SWIG / smeshBuilder.py
index bace171b6cf7ddccb9d3e9ae49dc75ca8a57b62d..d1e2f3bb23584320f531ab0386672fb146f5d52f 100644 (file)
@@ -84,6 +84,10 @@ import salome
 from salome.geom import geomBuilder
 
 import SMESH # This is necessary for back compatibility
+import omniORB                                   # back compatibility
+SMESH.MED_V2_1 = omniORB.EnumItem("MED_V2_1", 0) # back compatibility
+SMESH.MED_V2_2 = omniORB.EnumItem("MED_V2_2", 1) # back compatibility
+
 from   SMESH import *
 from   salome.smesh.smesh_algorithm import Mesh_Algorithm
 
@@ -1025,6 +1029,8 @@ class smeshBuilder(SMESH._objref_SMESH_Gen):
             functor = aFilterMgr.CreateLength()
         elif theCriterion == FT_Length2D:
             functor = aFilterMgr.CreateLength2D()
+        elif theCriterion == FT_Deflection2D:
+            functor = aFilterMgr.CreateDeflection2D()
         elif theCriterion == FT_NodeConnectivityNumber:
             functor = aFilterMgr.CreateNodeConnectivityNumber()
         elif theCriterion == FT_BallDiameter:
@@ -1212,6 +1218,18 @@ class smeshBuilder(SMESH._objref_SMESH_Gen):
         aMeasurements.UnRegister()
         return value
 
+    ## Get gravity center of all nodes of the mesh object.
+    #  @param obj mesh, submesh or group
+    #  @return three components of the gravity center: x,y,z
+    #  @ingroup l1_measurements
+    def GetGravityCenter(self, obj):
+        if isinstance(obj, Mesh): obj = obj.mesh
+        if isinstance(obj, Mesh_Algorithm): obj = obj.GetSubMesh()
+        aMeasurements = self.CreateMeasurements()
+        pointStruct = aMeasurements.GravityCenter(obj)
+        aMeasurements.UnRegister()
+        return pointStruct.x, pointStruct.y, pointStruct.z
+
     pass # end of class smeshBuilder
 
 import omniORB
@@ -1839,13 +1857,10 @@ class Mesh(metaclass=MeshMeta):
 
     ## 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
-    #  @param f is the file name
+    #  @param fileName is the file name
     #  @param 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.
-    #  @param 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.
     #  @param overwrite boolean parameter for overwriting/not overwriting the file
     #  @param meshPart a part of mesh (group, sub-mesh) to export instead of the mesh
     #  @param autoDimension if @c True (default), a space dimension of a MED mesh can be either
@@ -1861,17 +1876,33 @@ class Mesh(metaclass=MeshMeta):
     #         - 'f' stands for "_faces _" field;
     #         - 's' stands for "_solids _" field.
     #  @ingroup l2_impexp
-    def ExportMED(self, f, auto_groups=0, version=MED_V2_2,
-                  overwrite=1, meshPart=None, autoDimension=True, fields=[], geomAssocFields=''):
+    def ExportMED(self, *args, **kwargs):
+        # 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
+        meshPart        = args[3] if len(args) > 3 else None
+        autoDimension   = args[4] if len(args) > 4 else True
+        fields          = args[5] if len(args) > 5 else []
+        geomAssocFields = args[6] if len(args) > 6 else ''
+        # process keywords arguments
+        auto_groups     = kwargs.get("auto_groups", auto_groups)
+        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)
+        # invoke engine's function
         if meshPart or fields or geomAssocFields:
             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,
+            self.mesh.ExportPartToMED( meshPart, fileName, auto_groups, overwrite, autoDimension,
                                        fields, geomAssocFields)
         else:
-            self.mesh.ExportToMEDX(f, auto_groups, version, overwrite, autoDimension)
+            self.mesh.ExportMED(fileName, auto_groups, overwrite, autoDimension)
 
     ## Export the mesh in a file in SAUV format
     #  @param f is the file name
@@ -1929,8 +1960,11 @@ class Mesh(metaclass=MeshMeta):
     #  @param f is the file name
     #  @param overwrite boolean parameter for overwriting/not overwriting the file
     #  @param meshPart a part of mesh (group, sub-mesh) to export instead of the mesh
+    #  @param groupElemsByType if true all elements of same entity type are exported at ones,
+    #         else elements are exported in order of their IDs which can cause creation
+    #         of multiple cgns sections
     #  @ingroup l2_impexp
-    def ExportCGNS(self, f, overwrite=1, meshPart=None):
+    def ExportCGNS(self, f, overwrite=1, meshPart=None, groupElemsByType=False):
         unRegister = genObjUnRegister()
         if isinstance( meshPart, list ):
             meshPart = self.GetIDSource( meshPart, SMESH.ALL )
@@ -1939,7 +1973,7 @@ class Mesh(metaclass=MeshMeta):
             meshPart = meshPart.mesh
         elif not meshPart:
             meshPart = self.mesh
-        self.mesh.ExportCGNS(meshPart, f, overwrite)
+        self.mesh.ExportCGNS(meshPart, f, overwrite, groupElemsByType)
 
     ## Export the mesh in a file in GMF format.
     #  GMF files must have .mesh extension for the ASCII format and .meshb for
@@ -1961,10 +1995,36 @@ class Mesh(metaclass=MeshMeta):
     ## Deprecated, used only for compatibility! Please, use 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
-    #  @param f the file name
-    #  @param 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.
+    #  @param fileName the file name
+    #  @param opt boolean parameter for creating/not creating
+    #         the groups Group_On_All_Nodes, Group_On_All_Faces, ...
+    #  @param overwrite boolean parameter for overwriting/not overwriting the file
+    #  @param autoDimension if @c 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.<br>
+    #         If @a autoDimension is @c False, the space dimension is always 3.
+    #  @ingroup l2_impexp
+    def ExportToMED(self, *args, **kwargs):
+        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)
+        # invoke engine's function
+        self.mesh.ExportMED(fileName, auto_groups, overwrite, autoDimension)
+
+    ## Deprecated, used only for compatibility! Please, use 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
+    #  @param fileName the file name
     #  @param opt boolean parameter for creating/not creating
     #         the groups Group_On_All_Nodes, Group_On_All_Faces, ...
     #  @param overwrite boolean parameter for overwriting/not overwriting the file
@@ -1974,8 +2034,20 @@ class Mesh(metaclass=MeshMeta):
     #         - 3D in the rest cases.<br>
     #         If @a autoDimension is @c False, the space dimension is always 3.
     #  @ingroup l2_impexp
-    def ExportToMED(self, f, version=MED_V2_2, opt=0, overwrite=1, autoDimension=True):
-        self.mesh.ExportToMEDX(f, opt, version, overwrite, autoDimension)
+    def ExportToMEDX(self, *args, **kwargs):
+        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)
+        # invoke engine's function
+        self.mesh.ExportMED(fileName, auto_groups, overwrite, autoDimension)
 
     # Operations with groups:
     # ----------------------
@@ -2059,6 +2131,8 @@ class Mesh(metaclass=MeshMeta):
     #  @ingroup l2_grps_create
     def MakeGroupByIds(self, groupName, elementType, elemIDs):
         group = self.mesh.CreateGroup(elementType, groupName)
+        if isinstance( elemIDs, Mesh ):
+            elemIDs = elemIDs.GetMesh()
         if hasattr( elemIDs, "GetIDs" ):
             if hasattr( elemIDs, "SetMesh" ):
                 elemIDs.SetMesh( self.GetMesh() )
@@ -2339,10 +2413,10 @@ class Mesh(metaclass=MeshMeta):
         return self.editor.MakeIDSource(ids, elemType)
 
 
-    # Get informations about mesh contents:
+    # Get information about mesh contents:
     # ------------------------------------
 
-    ## Get the mesh stattistic
+    ## Get the mesh statistic
     #  @return dictionary type element - count of elements
     #  @ingroup l1_meshinfo
     def GetMeshInfo(self, obj = None):
@@ -3155,6 +3229,16 @@ class Mesh(metaclass=MeshMeta):
     def GetPointState(self, x, y, z):
         return self.editor.GetPointState(x, y, z)
 
+    ## Check if a 2D mesh is manifold
+    #  @ingroup l1_controls
+    def IsManifold(self):
+        return self.editor.IsManifold()
+
+    ## Check if orientation of 2D elements is coherent
+    #  @ingroup l1_controls
+    def IsCoherentOrientation2D(self):
+        return self.editor.IsCoherentOrientation2D()
+
     ## Find the node closest to a point and moves it to a point location
     #  @param x  the X coordinate of a point
     #  @param y  the Y coordinate of a point
@@ -3275,7 +3359,7 @@ class Mesh(metaclass=MeshMeta):
     #          Type SMESH.FunctorType._items in the Python Console to see all items.
     #          Note that not all items correspond to numerical functors.
     #  @param MaxAngle      is the maximum angle between element normals at which the fusion
-    #          is still performed; theMaxAngle is mesured in radians.
+    #          is still performed; theMaxAngle is measured in radians.
     #          Also it could be a name of variable which defines angle in degrees.
     #  @return TRUE in case of success, FALSE otherwise.
     #  @ingroup l2_modif_unitetri
@@ -3294,7 +3378,7 @@ class Mesh(metaclass=MeshMeta):
     #          Type SMESH.FunctorType._items in the Python Console to see all items.
     #          Note that not all items correspond to numerical functors.
     #  @param MaxAngle   a max angle between element normals at which the fusion
-    #          is still performed; theMaxAngle is mesured in radians.
+    #          is still performed; theMaxAngle is measured in radians.
     #  @return TRUE in case of success, FALSE otherwise.
     #  @ingroup l2_modif_unitetri
     def TriToQuadObject (self, theObject, theCriterion, MaxAngle):
@@ -3306,7 +3390,7 @@ class Mesh(metaclass=MeshMeta):
         return self.editor.TriToQuadObject(theObject, Functor, MaxAngle)
 
     ## Split quadrangles into triangles.
-    #  @param IDsOfElements the faces to be splitted.
+    #  @param IDsOfElements the faces to be split.
     #  @param theCriterion is a numerical functor, in terms of enum SMESH.FunctorType, used to
     #         choose a diagonal for splitting. If @a theCriterion is None, which is a default
     #         value, then quadrangles will be split by the smallest diagonal.
@@ -3342,7 +3426,7 @@ class Mesh(metaclass=MeshMeta):
 
     ## Split each of given quadrangles into 4 triangles. A node is added at the center of
     #  a quadrangle.
-    #  @param theElements the faces to be splitted. This can be either mesh, sub-mesh,
+    #  @param theElements the faces to be split. This can be either mesh, sub-mesh,
     #         group or a list of face IDs. By default all quadrangles are split
     #  @ingroup l2_modif_cutquadr
     def QuadTo4Tri (self, theElements=[]):
@@ -3357,7 +3441,7 @@ class Mesh(metaclass=MeshMeta):
         return self.editor.QuadTo4Tri( theElements )
 
     ## Split quadrangles into triangles.
-    #  @param IDsOfElements the faces to be splitted
+    #  @param IDsOfElements the faces to be split
     #  @param Diag13        is used to choose a diagonal for splitting.
     #  @return TRUE in case of success, FALSE otherwise.
     #  @ingroup l2_modif_cutquadr
@@ -3378,7 +3462,7 @@ class Mesh(metaclass=MeshMeta):
         return self.editor.SplitQuadObject(theObject, Diag13)
 
     ## Find a better splitting of the given quadrangle.
-    #  @param IDOfQuad   the ID of the quadrangle to be splitted.
+    #  @param IDOfQuad   the ID of the quadrangle to be split.
     #  @param theCriterion  is a numerical functor, in terms of enum SMESH.FunctorType, used to
     #         choose a diagonal for splitting.
     #         Type SMESH.FunctorType._items in the Python Console to see all items.
@@ -4657,6 +4741,24 @@ class Mesh(metaclass=MeshMeta):
     def MergeEqualElements(self):
         self.editor.MergeEqualElements()
 
+    ## Returns all or only closed free borders
+    #  @return list of SMESH.FreeBorder's
+    #  @ingroup l2_modif_trsf
+    def FindFreeBorders(self, ClosedOnly=True):
+        return self.editor.FindFreeBorders( ClosedOnly )
+
+    ## Fill with 2D elements a hole defined by a SMESH.FreeBorder.
+    #  @param FreeBorder 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 FindFreeBorders() to get nodes of holes.
+    #  @ingroup l2_modif_trsf
+    def FillHole(self, holeNodes):
+        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 )
+
     ## Return groups of FreeBorder's coincident within the given tolerance.
     #  @param tolerance the tolerance. If the tolerance <= 0.0 then one tenth of an average
     #         size of elements adjacent to free borders being compared is used.
@@ -4932,12 +5034,12 @@ class Mesh(metaclass=MeshMeta):
 
     ## Identify the elements that will be affected by node duplication (actual duplication is not performed.
     #  This method is the first step of DoubleNodeElemGroupsInRegion.
-    #  @param theElems - list of groups of elements (edges or faces) to be replicated
+    #  @param theElems - list of groups of nodes or elements (edges or faces) to be replicated
     #  @param theNodesNot - list of groups of nodes not to replicated
     #  @param theShape - shape to detect affected elements (element which geometric center
     #         located on or inside shape).
     #         The replicated nodes should be associated to affected elements.
-    #  @return groups of affected elements
+    #  @return groups of affected elements in order: volumes, faces, edges
     #  @ingroup l2_modif_duplicat
     def AffectedElemGroupsInRegion(self, theElems, theNodesNot, theShape):
         return self.editor.AffectedElemGroupsInRegion(theElems, theNodesNot, theShape)
@@ -4972,8 +5074,41 @@ class Mesh(metaclass=MeshMeta):
     def CreateHoleSkin(self, radius, theShape, groupName, theNodesCoords):
         return self.editor.CreateHoleSkin( radius, theShape, groupName, theNodesCoords )
 
-    def _getFunctor(self, funcType ):
-        fn = self.functors[ EnumToLong(funcType) ]
+    ## 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
+    #  plane passing through pairs of points specified by each 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
+    #  points and an optional vector lying on the plane specified by a PolySegment.
+    #  By default the vector is defined by Mesh module as following. A middle point
+    #  of the two given points is computed. The middle point is projected to the mesh.
+    #  The vector goes from the middle point to the projection point. In case of planar
+    #  mesh, the vector is normal to the mesh.
+    #  @param segments - PolySegment's defining positions of cutting planes.
+    #         Return the used vector which goes from the middle point to its projection.
+    #  @param groupName - optional name of a group where created mesh segments will
+    #         be added.
+    #  @ingroup l2_modif_duplicat
+    def MakePolyLine(self, segments, groupName='', isPreview=False ):
+        editor = self.editor
+        if isPreview:
+            editor = self.mesh.GetMeshEditPreviewer()
+        segmentsRes = editor.MakePolyLine( segments, groupName )
+        for i, seg in enumerate( segmentsRes ):
+            segments[i].vector = seg.vector
+        if isPreview:
+            return editor.GetPreviewData()
+        return None        
+
+    ## Return a cached numerical functor by its type.
+    #  @param theCriterion functor type - an item of SMESH.FunctorType enumeration.
+    #          Type SMESH.FunctorType._items in the Python Console to see all items.
+    #          Note that not all items correspond to numerical functors.
+    #  @return SMESH_NumericalFunctor. The functor is already initialized
+    #          with a mesh
+    #  @ingroup l1_measurements
+    def GetFunctor(self, funcType ):
+        fn = self.functors[ funcType._v ]
         if not fn:
             fn = self.smeshpyD.GetFunctor(funcType)
             fn.SetMesh(self.mesh)
@@ -4988,7 +5123,7 @@ class Mesh(metaclass=MeshMeta):
     #  @return the functor value or zero in case of invalid arguments
     #  @ingroup l1_measurements
     def FunctorValue(self, funcType, elemId, isElem=True):
-        fn = self._getFunctor( funcType )
+        fn = self.GetFunctor( funcType )
         if fn.GetElementType() == self.GetElementType(elemId, isElem):
             val = fn.GetValue(elemId)
         else:
@@ -5094,7 +5229,7 @@ class Mesh(metaclass=MeshMeta):
             unRegister.set( meshPart )
         if isinstance( meshPart, Mesh ):
             meshPart = meshPart.mesh
-        fun = self._getFunctor( funType )
+        fun = self.GetFunctor( funType )
         if fun:
             if meshPart:
                 if hasattr( meshPart, "SetMesh" ):
@@ -5121,7 +5256,25 @@ class meshProxy(SMESH._objref_SMESH_Mesh):
     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 )
+        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]]
+        while len(args) < 4:  # !!!! nb of parameters for ExportToMED IDL's method
+            args.append(True)
+        SMESH._objref_SMESH_Mesh.ExportMED(self, *args)
+    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)
     pass
 omniORB.registerObjref(SMESH._objref_SMESH_Mesh._NP_RepositoryId, meshProxy)
 
@@ -5293,7 +5446,7 @@ class algoCreator:
         if not algoType:
             algoType = self.defaultAlgoType
         if not algoType and self.algoTypeToClass:
-            algoType = list(self.algoTypeToClass.keys())[0]
+            algoType = sorted( self.algoTypeToClass.keys() )[0]
         if algoType in self.algoTypeToClass:
             #print "Create algo",algoType