Salome HOME
0022108: EDF 2547 SMESH: Duplicate elements only
[modules/smesh.git] / src / SMESH_SWIG / smeshBuilder.py
index 25bf8e9e0e1d0393af5ba052ecd1d4b30cc98277..5a753f1bffda14a57f7581eab56ec9ebdfe9cdba 100644 (file)
@@ -259,15 +259,15 @@ def AssureGeomPublished(mesh, geom, name=''):
     return
 
 ## Return the first vertex of a geometrical edge by ignoring orientation
-def FirstVertexOnCurve(edge):
-    vv = geomBuilder.SubShapeAll( edge, geomBuilder.geomBuilder.ShapeType["VERTEX"])
+def FirstVertexOnCurve(mesh, edge):
+    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   = geomBuilder.MakeVertexOnCurve(edge,0.)
-    xyz  = geomBuilder.PointCoordinates( v0 ) # coords of the first vertex
-    xyz1 = geomBuilder.PointCoordinates( vv[0] )
-    xyz2 = geomBuilder.PointCoordinates( vv[1] )
+    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] )
@@ -285,6 +285,7 @@ def FirstVertexOnCurve(edge):
 smeshInst = None
 engine = None
 doLcc = False
+created = False
 
 ## This class allows to create, load or manipulate meshes
 #  It has a set of methods to create load or copy meshes, to combine several meshes.
@@ -312,7 +313,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
         global engine
         global smeshInst
         global doLcc
-        #print "__new__", engine, smeshInst, doLcc
+        #print "==== __new__", engine, smeshInst, doLcc
 
         if smeshInst is None:
             # smesh engine is either retrieved from engine, or created
@@ -327,26 +328,30 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
                     # FindOrLoadComponent called:
                     # 1. CORBA resolution of server
                     # 2. the __new__ method is called again
-                    #print "smeshInst = lcc.FindOrLoadComponent ", engine, smeshInst, doLcc
+                    #print "==== smeshInst = lcc.FindOrLoadComponent ", engine, smeshInst, doLcc
                     smeshInst = salome.lcc.FindOrLoadComponent( "FactoryServer", "SMESH" )
             else:
                 # FindOrLoadComponent not called
                 if smeshInst is None:
                     # smeshBuilder instance is created from lcc.FindOrLoadComponent
-                    #print "smeshInst = super(smeshBuilder,cls).__new__(cls) ", engine, smeshInst, doLcc
+                    #print "==== smeshInst = super(smeshBuilder,cls).__new__(cls) ", engine, smeshInst, doLcc
                     smeshInst = super(smeshBuilder,cls).__new__(cls)
                 else:
                     # smesh engine not created: existing engine found
-                    #print "existing ", engine, smeshInst, doLcc
+                    #print "==== existing ", engine, smeshInst, doLcc
                     pass
-
+            #print "====1 ", smeshInst
             return smeshInst
 
+        #print "====2 ", smeshInst
         return smeshInst
 
     def __init__(self):
-        #print "__init__"
-        SMESH._objref_SMESH_Gen.__init__(self)
+        global created
+        #print "--------------- smeshbuilder __init__ ---", created
+        if not created:
+          created = True
+          SMESH._objref_SMESH_Gen.__init__(self)
 
     ## Dump component to the Python script
     #  This method overrides IDL function to allow default values for the parameters.
@@ -515,25 +520,19 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
         return aMesh
 
     ## Creates a Mesh object(s) importing data from the given MED file
-    #  @return a list of Mesh class instances
+    #  @return a tuple ( list of Mesh class instances, SMESH.DriverMED_ReadStatus )
     #  @ingroup l2_impexp
     def CreateMeshesFromMED( self,theFileName ):
         aSmeshMeshes, aStatus = SMESH._objref_SMESH_Gen.CreateMeshesFromMED(self,theFileName)
-        aMeshes = []
-        for iMesh in range(len(aSmeshMeshes)) :
-            aMesh = Mesh(self, self.geompyD, aSmeshMeshes[iMesh])
-            aMeshes.append(aMesh)
+        aMeshes = [ Mesh(self, self.geompyD, m) for m in aSmeshMeshes ]
         return aMeshes, aStatus
 
     ## Creates a Mesh object(s) importing data from the given SAUV file
-    #  @return a list of Mesh class instances
+    #  @return a tuple ( list of Mesh class instances, SMESH.DriverMED_ReadStatus )
     #  @ingroup l2_impexp
     def CreateMeshesFromSAUV( self,theFileName ):
         aSmeshMeshes, aStatus = SMESH._objref_SMESH_Gen.CreateMeshesFromSAUV(self,theFileName)
-        aMeshes = []
-        for iMesh in range(len(aSmeshMeshes)) :
-            aMesh = Mesh(self, self.geompyD, aSmeshMeshes[iMesh])
-            aMeshes.append(aMesh)
+        aMeshes = [ Mesh(self, self.geompyD, m) for m in aSmeshMeshes ]
         return aMeshes, aStatus
 
     ## Creates a Mesh object importing data from the given STL file
@@ -545,18 +544,15 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
         return aMesh
 
     ## Creates Mesh objects importing data from the given CGNS file
-    #  @return an instance of Mesh class
+    #  @return a tuple ( list of Mesh class instances, SMESH.DriverMED_ReadStatus )
     #  @ingroup l2_impexp
     def CreateMeshesFromCGNS( self, theFileName ):
         aSmeshMeshes, aStatus = SMESH._objref_SMESH_Gen.CreateMeshesFromCGNS(self,theFileName)
-        aMeshes = []
-        for iMesh in range(len(aSmeshMeshes)) :
-            aMesh = Mesh(self, self.geompyD, aSmeshMeshes[iMesh])
-            aMeshes.append(aMesh)
+        aMeshes = [ Mesh(self, self.geompyD, m) for m in aSmeshMeshes ]
         return aMeshes, aStatus
 
     ## Creates a Mesh object importing data from the given GMF file
-    #  @return [ an instance of Mesh class, SMESH::ComputeError ]
+    #  @return [ an instance of Mesh class, SMESH.ComputeError ]
     #  @ingroup l2_impexp
     def CreateMeshesFromGMF( self, theFileName ):
         aSmeshMesh, error = SMESH._objref_SMESH_Gen.CreateMeshesFromGMF(self,
@@ -670,10 +666,10 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
                      Tolerance=1e-07):
         if not CritType in SMESH.FunctorType._items:
             raise TypeError, "CritType should be of SMESH.FunctorType"
-        aCriterion = self.GetEmptyCriterion()
+        aCriterion               = self.GetEmptyCriterion()
         aCriterion.TypeOfElement = elementType
-        aCriterion.Type = self.EnumToLong(CritType)
-        aCriterion.Tolerance = Tolerance
+        aCriterion.Type          = self.EnumToLong(CritType)
+        aCriterion.Tolerance     = Tolerance
 
         aThreshold = Threshold
 
@@ -727,6 +723,30 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
             else:
                 raise ValueError,\
                       "The Threshold should be an ID of mesh face and not '%s'"%aThreshold
+        elif CritType == FT_ConnectedElements:
+            # Checks the Threshold
+            if isinstance(aThreshold, geomBuilder.GEOM._objref_GEOM_Object): # shape
+                aCriterion.ThresholdID = aThreshold.GetStudyEntry()
+                if not aCriterion.ThresholdID:
+                    name = aThreshold.GetName()
+                    if not name:
+                        name = "%s_%s"%(aThreshold.GetShapeType(), id(aThreshold)%10000)
+                    aCriterion.ThresholdID = self.geompyD.addToStudy( aThreshold, name )
+            elif isinstance(aThreshold, int): # node id
+                aCriterion.Threshold = aThreshold
+            elif isinstance(aThreshold, list): # 3 point coordinates
+                if len( aThreshold ) < 3:
+                    raise ValueError, "too few point coordinates, must be 3"
+                aCriterion.ThresholdStr = " ".join( [str(c) for c in aThreshold[:3]] )
+            elif isinstance(aThreshold, str):
+                if aThreshold.isdigit():
+                    aCriterion.Threshold = aThreshold # node id
+                else:
+                    aCriterion.ThresholdStr = aThreshold # hope that it's point coordinates
+            else:
+                raise ValueError,\
+                      "The Threshold should either a VERTEX, or a node ID, "\
+                      "or a list of point coordinates and not '%s'"%aThreshold
         elif CritType == FT_ElemGeomType:
             # Checks the Threshold
             try:
@@ -803,6 +823,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
     #  @param UnaryOp  FT_LogicalNOT or FT_Undefined
     #  @param Tolerance the tolerance used by FT_BelongToGeom, FT_BelongToSurface,
     #         FT_LyingOnGeom, FT_CoplanarFaces and FT_EqualNodes criteria
+    #  @param mesh the mesh to initialize the filter with
     #  @return SMESH_Filter
     #
     #  <a href="../tui_filters_page.html#tui_filters">Example of Filters usage</a>
@@ -812,13 +833,17 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
                   Compare=FT_EqualTo,
                   Threshold="",
                   UnaryOp=FT_Undefined,
-                  Tolerance=1e-07):
+                  Tolerance=1e-07,
+                  mesh=None):
         aCriterion = self.GetCriterion(elementType, CritType, Compare, Threshold, UnaryOp, FT_Undefined,Tolerance)
         aFilterMgr = self.CreateFilterManager()
         aFilter = aFilterMgr.CreateFilter()
         aCriteria = []
         aCriteria.append(aCriterion)
         aFilter.SetCriteria(aCriteria)
+        if mesh:
+            if isinstance( mesh, Mesh ): aFilter.SetMesh( mesh.GetMesh() )
+            else                       : aFilter.SetMesh( mesh )
         aFilterMgr.UnRegister()
         return aFilter
 
@@ -1329,7 +1354,10 @@ class Mesh:
                 if errText: errText += ". "
                 errText += err.comment
                 if allReasons != "":allReasons += "\n"
-                allReasons += '-  "%s" failed%s. Error: %s' %(err.algoName, shapeText, errText)
+                if ok:
+                    allReasons += '-  "%s"%s - %s' %(err.algoName, shapeText, errText)
+                else:
+                    allReasons += '-  "%s" failed%s. Error: %s' %(err.algoName, shapeText, errText)
                 pass
 
             # Treat hyp errors
@@ -1498,6 +1526,8 @@ class Mesh:
     #  @return SMESH.Hypothesis_Status
     #  @ingroup l2_hypotheses
     def RemoveHypothesis(self, hyp, geom=0):
+        if not hyp:
+            return None
         if isinstance( hyp, Mesh_Algorithm ):
             hyp = hyp.GetAlgorithm()
             pass
@@ -2018,6 +2048,12 @@ class Mesh:
     def NbTrianglesOfOrder(self, elementOrder):
         return self.mesh.NbTrianglesOfOrder(elementOrder)
 
+    ## Returns the number of biquadratic triangles in the mesh
+    #  @return an integer value
+    #  @ingroup l1_meshinfo
+    def NbBiQuadTriangles(self):
+        return self.mesh.NbBiQuadTriangles()
+
     ## Returns the number of quadrangles in the mesh
     #  @return an integer value
     #  @ingroup l1_meshinfo
@@ -2824,7 +2860,6 @@ class Mesh:
         return self.editor.TriToQuadObject(theObject, Functor, MaxAngle)
 
     ## Splits quadrangles into triangles.
-    #
     #  @param IDsOfElements the faces to be splitted.
     #  @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
@@ -2855,6 +2890,20 @@ class Mesh:
         Functor = self.smeshpyD.GetFunctor(theCriterion)
         return self.editor.QuadToTriObject(theObject, Functor)
 
+    ## Splits 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,
+    #         group or a list of face IDs. By default all quadrangles are split
+    #  @ingroup l2_modif_cutquadr
+    def QuadTo4Tri (self, theElements=[]):
+        if isinstance( theElements, Mesh ):
+            theElements = theElements.mesh
+        elif not theElements:
+            theElements = self.mesh
+        elif isinstance( theElements, list ):
+            theElements = self.GetIDSource( theElements, SMESH.FACE )
+        return self.editor.QuadTo4Tri( theElements )
+
     ## Splits quadrangles into triangles.
     #  @param IDsOfElements the faces to be splitted
     #  @param Diag13        is used to choose a diagonal for splitting.
@@ -3117,6 +3166,8 @@ class Mesh:
     #  @param theToBiQuad If True, converts the mesh to bi-quadratic
     #  @ingroup l2_modif_tofromqu
     def ConvertToQuadratic(self, theForce3d, theSubMesh=None, theToBiQuad=False):
+        if isinstance( theSubMesh, Mesh ):
+            theSubMesh = theSubMesh.mesh
         if theToBiQuad:
             self.editor.ConvertToBiQuadratic(theForce3d,theSubMesh)
         else:
@@ -3124,6 +3175,9 @@ class Mesh:
                 self.editor.ConvertToQuadraticObject(theForce3d,theSubMesh)
             else:
                 self.editor.ConvertToQuadratic(theForce3d)
+        error = self.editor.GetLastError()
+        if error and error.comment:
+            print error.comment
             
     ## Converts the mesh from quadratic to ordinary,
     #  deletes old quadratic elements, \n replacing
@@ -4079,7 +4133,30 @@ class Mesh:
     def GetLastCreatedElems(self):
         return self.editor.GetLastCreatedElems()
 
-     ## Creates a hole in a mesh by doubling the nodes of some particular elements
+    ## Clears sequences of nodes and elements created by mesh edition oparations
+    #  @ingroup l1_auxiliary
+    def ClearLastCreated(self):
+        self.editor.ClearLastCreated()
+
+    ## Creates Duplicates given elements, i.e. creates new elements based on the 
+    #  same nodes as the given ones.
+    #  @param theElements - container of elements to duplicate. It can be a Mesh,
+    #         sub-mesh, group, filter or a list of element IDs.
+    # @param theGroupName - a name of group to contain the generated elements.
+    #                    If a group with such a name already exists, the new elements
+    #                    are added to the existng group, else a new group is created.
+    #                    If \a theGroupName is empty, new elements are not added 
+    #                    in any group.
+    # @return a group where the new elements are added. None if theGroupName == "".
+    #  @ingroup l2_modif_edit
+    def DoubleElements(self, theElements, theGroupName=""):
+        if isinstance( theElements, Mesh ):
+            theElements = theElements.mesh
+        elif isinstance( theElements, list ):
+            theElements = self.GetIDSource( theElements, SMESH.ALL )
+        return self.editor.DoubleElements(theElements, theGroupName)
+
+    ## Creates a hole in a mesh by doubling the nodes of some particular elements
     #  @param theNodes identifiers of nodes to be doubled
     #  @param theModifiedElems identifiers of elements to be updated by the new (doubled)
     #         nodes. If list of element identifiers is empty then nodes are doubled but