Salome HOME
Merge branch 'V9_9_BR'
[modules/smesh.git] / src / SMESH_SWIG / smeshBuilder.py
index 21456eed4fa3dfa94caf9f422c7606214f39f0e6..ddf5fc97a11a7e233f74247943aa1a5651c9e92b 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2020  CEA/DEN, EDF R&D, OPEN CASCADE
+# Copyright (C) 2007-2022  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
@@ -38,8 +38,9 @@ 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 SMESH import *
+from salome.smesh.smesh_algorithm import Mesh_Algorithm
+from StdMeshers import BlockCS
 
 import SALOME
 import SALOMEDS
@@ -684,18 +685,6 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ):
         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
@@ -1650,9 +1639,19 @@ class Mesh(metaclass = MeshMeta):
             #self.mesh.Register()
             self.geom = self.mesh.GetShapeToMesh()
             if self.geom:
-                self.geompyD = self.geom.GetGen()
+                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
-        pass
 
     def GetMesh(self):
         """
@@ -1951,9 +1950,10 @@ class Mesh(metaclass = MeshMeta):
                 print(msg)
                 print(allReasons)
             pass
-        if salome.sg.hasDesktop():
-            if not isinstance( refresh, list): # not a call from subMesh.Compute()
-                if refresh: salome.sg.updateObjBrowser()
+        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
 
@@ -2287,6 +2287,78 @@ class Mesh(metaclass = MeshMeta):
             self.mesh.RemoveHypothesis( self.geom, hyp )
             pass
         pass
+
+    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 <SMESH.SMESH_IDSource>`)
+                    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
@@ -2305,7 +2377,8 @@ class Mesh(metaclass = MeshMeta):
                         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 <SMESH.SMESH_IDSource>`) to export instead of the mesh
+                meshPart: a part of mesh (:class:`sub-mesh, group or filter <SMESH.SMESH_IDSource>`)
+                        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
@@ -2326,6 +2399,7 @@ class Mesh(metaclass = MeshMeta):
                 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
@@ -2338,6 +2412,7 @@ class Mesh(metaclass = MeshMeta):
         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)
@@ -2348,9 +2423,13 @@ class Mesh(metaclass = MeshMeta):
         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()
 
         # invoke engine's function
-        if meshPart or fields or geomAssocFields or z_tolerance > 0:
+        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 )
@@ -2361,59 +2440,47 @@ class Mesh(metaclass = MeshMeta):
 
             self.mesh.ExportPartToMED( meshPart, fileName, auto_groups,
                                        version, overwrite, autoDimension,
-                                       fields, geomAssocFields, z_tolerance)
+                                       fields, geomAssocFields, z_tolerance, saveNumbers )
         else:
             self.mesh.ExportMED(fileName, 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.
-        """
-
-        self.mesh.ExportSAUV(f, auto_groups)
-
-    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 <SMESH.SMESH_IDSource>`) 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 <SMESH.SMESH_IDSource>`) 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):
         """
@@ -4031,6 +4098,16 @@ class Mesh(metaclass = MeshMeta):
 
         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
@@ -4449,7 +4526,7 @@ class Mesh(metaclass = MeshMeta):
 
         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
+             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.
         """
@@ -4524,6 +4601,30 @@ class Mesh(metaclass = MeshMeta):
 
         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
@@ -4597,6 +4698,29 @@ class Mesh(metaclass = MeshMeta):
             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 <SMESH.SMESH_IDSource>` holding faces to reorient.
+                 referenceFaces: list of :class:`sub-mesh, group, filter <SMESH.SMESH_IDSource>` 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.
@@ -7376,6 +7500,14 @@ class meshProxy(SMESH._objref_SMESH_Mesh):
         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)
     pass
 omniORB.registerObjref(SMESH._objref_SMESH_Mesh._NP_RepositoryId, meshProxy)