Salome HOME
23619: EDF 18055 - Detection of sharp edges
[modules/smesh.git] / src / SMESH_SWIG / smeshBuilder.py
index d0bb913c11682872c1ef060c2bcc26a2d4dfd135..7037fd2eb8f984d87fc178934803f577f37f0e74 100755 (executable)
@@ -782,11 +782,46 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ):
                 an instance of class :class:`Mesh`
         """
 
                 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)
 
             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 geomtry.
+                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
+                preceeding 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
     def GetSubShapesId( self, theMainObject, theListOfSubObjects ):
         """
         Return IDs of sub-shapes
@@ -2190,12 +2225,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 
                         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:
+                        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.
 
                         - '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
         """
         # process positional arguments
         #args = [i for i in args if i not in [SMESH.MED_V2_1, SMESH.MED_V2_2]] # backward compatibility
@@ -2207,6 +2247,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 ''
         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)
         # process keywords arguments
         auto_groups     = kwargs.get("auto_groups", auto_groups)
         minor           = kwargs.get("minor", minor)
@@ -2215,14 +2256,20 @@ class Mesh(metaclass = MeshMeta):
         autoDimension   = kwargs.get("autoDimension", autoDimension)
         fields          = kwargs.get("fields", fields)
         geomAssocFields = kwargs.get("geomAssocFields", geomAssocFields)
         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
         # 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 )
             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,
             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)
 
         else:
             self.mesh.ExportMED(fileName, auto_groups, minor, overwrite, autoDimension)
 
@@ -2838,6 +2885,22 @@ class Mesh(metaclass = MeshMeta):
             groups = [groups]
         return self.mesh.CreateDimGroup(groups, elemType, name, nbCommonNodes, underlyingOnly)
 
             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 between 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 groups
+        """
+        sharpAngle,Parameters,hasVars = ParseParameters( sharpAngle )
+        self.mesh.SetParameters(Parameters)
+        return self.mesh.FaceGroupsSeparatedByEdges( sharpAngle, createEdges, useExistingEdges );
 
     def ConvertToStandalone(self, group):
         """
 
     def ConvertToStandalone(self, group):
         """
@@ -4193,6 +4256,17 @@ class Mesh(metaclass = MeshMeta):
         else:
             return self.editor.FindElementsByPoint(x, y, z, elementType)
 
         else:
             return self.editor.FindElementsByPoint(x, y, z, elementType)
 
+    def ProjectPoint(self, x,y,z, meshObject, elementType):
+        """
+        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()
+        return self.editor.ProjectPoint( x,y,z, meshObject, elementType )
+
     def GetPointState(self, x, y, z):
         """
         Return point state in a closed 2D mesh in terms of TopAbs_State enumeration:
     def GetPointState(self, x, y, z):
         """
         Return point state in a closed 2D mesh in terms of TopAbs_State enumeration:
@@ -4216,6 +4290,21 @@ class Mesh(metaclass = MeshMeta):
 
         return self.editor.IsCoherentOrientation2D()
 
 
         return self.editor.IsCoherentOrientation2D()
 
+    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
     def MeshToPassThroughAPoint(self, x, y, z):
         """
         Find the node closest to a point and moves it to a point location
@@ -4490,7 +4579,7 @@ class Mesh(metaclass = MeshMeta):
 
         Parameters:
                 IDsOfElements: the faces to be splitted
 
         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.
 
         Returns:
             True in case of success, False otherwise.
@@ -4506,7 +4595,7 @@ 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 <SMESH.SMESH_IDSource>`
         Parameters:
                 theObject: the object from which the list of elements is taken,
                         this is :class:`mesh, sub-mesh, group or filter <SMESH.SMESH_IDSource>`
-                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.
 
         Returns:
             True in case of success, False otherwise.
@@ -6156,12 +6245,12 @@ class Mesh(metaclass = MeshMeta):
         Fill with 2D elements a hole defined by a SMESH.FreeBorder.
 
         Parameters:
         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:
                 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 <SMESH.SMESH_GroupBase>` containing the new faces; or :code:`None` if :option:`groupName` == ""
+            a :class:`group <SMESH.SMESH_GroupBase>` containing the new faces; or :code:`None` if `groupName` == ""
         """
 
 
         """
 
 
@@ -6619,7 +6708,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
     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
         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
@@ -6629,12 +6718,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.
 
         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.
             segments: list of :class:`SMESH.PolySegment` defining positions of cutting planes.
             groupName: optional name of a group where created mesh segments will be added.
-            
+
         """    
         editor = self.editor
         if isPreview:
         """    
         editor = self.editor
         if isPreview: