Salome HOME
22860: EDF 9944 SMESH: Regression when scaling a mesh
[modules/smesh.git] / src / SMESH_SWIG / smeshBuilder.py
index ce0a35594f1a35befb4d9109ad41333536073ffd..1445061eb1d05cb0f4b40d5a6b6e67b1e8d7c908 100644 (file)
@@ -207,12 +207,15 @@ def GetName(obj):
     raise RuntimeError, "Null or invalid object"
 
 ## Prints error message if a hypothesis was not assigned.
-def TreatHypoStatus(status, hypName, geomName, isAlgo):
+def TreatHypoStatus(status, hypName, geomName, isAlgo, mesh):
     if isAlgo:
         hypType = "algorithm"
     else:
         hypType = "hypothesis"
         pass
+    reason = ""
+    if hasattr( status, "__getitem__" ):
+        status,reason = status[0],status[1]
     if status == HYP_UNKNOWN_FATAL :
         reason = "for unknown reason"
     elif status == HYP_INCOMPATIBLE :
@@ -235,17 +238,24 @@ def TreatHypoStatus(status, hypName, geomName, isAlgo):
     elif status == HYP_HIDING_ALGO:
         reason = "it hides algorithms of lower dimensions by generating elements of all dimensions"
     elif status == HYP_NEED_SHAPE:
-        reason = "Algorithm can't work without shape"
+        reason = "algorithm can't work without shape"
+    elif status == HYP_INCOMPAT_HYPS:
+        pass
     else:
         return
-    hypName = '"' + hypName + '"'
-    geomName= '"' + geomName+ '"'
-    if status < HYP_UNKNOWN_FATAL and not geomName =='""':
-        print hypName, "was assigned to",    geomName,"but", reason
-    elif not geomName == '""':
-        print hypName, "was not assigned to",geomName,":", reason
+    where = geomName
+    if where:
+        where = '"%s"' % geomName
+        if mesh:
+            meshName = GetName( mesh )
+            if meshName and meshName != NO_NAME:
+                where = '"%s" in "%s"' % ( geomName, meshName )
+    if status < HYP_UNKNOWN_FATAL and where:
+        print '"%s" was assigned to %s but %s' %( hypName, where, reason )
+    elif where:
+        print '"%s" was not assigned to %s : %s' %( hypName, where, reason )
     else:
-        print hypName, "was not assigned:", reason
+        print '"%s" was not assigned : %s' %( hypName, reason )
         pass
 
 ## Private method. Add geom (sub-shape of the main shape) into the study if not yet there
@@ -383,6 +393,9 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
     def init_smesh(self,theStudy,geompyD = None):
         #print "init_smesh"
         self.SetCurrentStudy(theStudy,geompyD)
+        if theStudy:
+            global notebook
+            notebook.myStudy = theStudy
 
     ## Creates a mesh. This can be either an empty mesh, possibly having an underlying geometry,
     #  or a mesh wrapping a CORBA mesh given as a parameter.
@@ -453,7 +466,9 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
     #  @return SMESH.AxisStruct
     #  @ingroup l1_auxiliary
     def GetAxisStruct(self,theObj):
+        import GEOM
         edges = self.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"] )
@@ -465,14 +480,18 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
             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])
-            return axis
+            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 )
             axis = AxisStruct(p1[0], p1[1], p1[2], p2[0]-p1[0], p2[1]-p1[1], p2[2]-p1[2])
-            return axis
-        return None
+            axis._mirrorType = SMESH.SMESH_MeshEditor.AXIS
+        elif theObj.GetShapeType() == GEOM.VERTEX:
+            x,y,z = self.geompyD.PointCoordinates( theObj )
+            axis = AxisStruct( x,y,z, 1,0,0,)
+            axis._mirrorType = SMESH.SMESH_MeshEditor.POINT
+        return axis
 
     # From SMESH_Gen interface:
     # ------------------------
@@ -517,6 +536,12 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
             notebook = salome_notebook.NoteBook( theStudy )
         else:
             notebook = salome_notebook.NoteBook( salome_notebook.PseudoStudyForNoteBook() )
+        if theStudy:
+            sb = theStudy.NewBuilder()
+            sc = theStudy.FindComponent("SMESH")
+            if sc: sb.LoadWith(sc, self)
+            pass
+        pass
 
     ## Gets the current study
     #  @ingroup l1_auxiliary
@@ -608,7 +633,7 @@ class smeshBuilder(object, SMESH._objref_SMESH_Gen):
     #                  pass result of Mesh.GetIDSource( list_of_ids, type ) as meshPart
     #  @param meshName a name of the new mesh
     #  @param toCopyGroups to create in the new mesh groups the copied elements belongs to
-    #  @param toKeepIDs to preserve IDs of the copied elements or not
+    #  @param toKeepIDs to preserve order of the copied elements or not
     #  @return an instance of Mesh class
     def CopyMesh( self, meshPart, meshName, toCopyGroups=False, toKeepIDs=False):
         if (isinstance( meshPart, Mesh )):
@@ -1517,7 +1542,7 @@ class Mesh:
             smeshgui.SetMeshIcon( salome.ObjectToID( self.mesh ), False, True )
             salome.sg.updateObjBrowser(1)
 
-    ## Computes a tetrahedral mesh using AutomaticLength + MEFISTO + NETGEN
+    ## Computes a tetrahedral mesh using AutomaticLength + MEFISTO + Tetrahedron
     #  @param fineness [0.0,1.0] defines mesh fineness
     #  @return True or False
     #  @ingroup l3_algos_basic
@@ -1530,8 +1555,7 @@ class Mesh:
             self.Triangle().LengthFromEdges()
             pass
         if dim > 2 :
-            from salome.NETGENPlugin.NETGENPluginBuilder import NETGEN
-            self.Tetrahedron(NETGEN)
+            self.Tetrahedron()
             pass
         return self.Compute()
 
@@ -1578,13 +1602,13 @@ class Mesh:
             AssureGeomPublished( self, geom, "shape for %s" % hyp.GetName())
             status = self.mesh.AddHypothesis(geom, hyp)
         else:
-            status = HYP_BAD_GEOMETRY
+            status = HYP_BAD_GEOMETRY,""
         hyp_name = GetName( hyp )
         geom_name = ""
         if geom:
             geom_name = geom.GetName()
         isAlgo = hyp._narrow( SMESH_Algo )
-        TreatHypoStatus( status, hyp_name, geom_name, isAlgo )
+        TreatHypoStatus( status, hyp_name, geom_name, isAlgo, self )
         return status
 
     ## Return True if an algorithm of hypothesis is assigned to a given shape
@@ -1858,7 +1882,12 @@ class Mesh:
     #  @ingroup l2_grps_create
     def MakeGroupByIds(self, groupName, elementType, elemIDs):
         group = self.mesh.CreateGroup(elementType, groupName)
-        group.Add(elemIDs)
+        if hasattr( elemIDs, "GetIDs" ):
+            if hasattr( elemIDs, "SetMesh" ):
+                elemIDs.SetMesh( self.GetMesh() )
+            group.AddFrom( elemIDs )
+        else:
+            group.Add(elemIDs)
         return group
 
     ## Creates a mesh group by the given conditions
@@ -1870,7 +1899,7 @@ class Mesh:
     #  @param UnaryOp FT_LogicalNOT or FT_Undefined
     #  @param Tolerance the tolerance used by FT_BelongToGeom, FT_BelongToSurface,
     #         FT_LyingOnGeom, FT_CoplanarFaces criteria
-    #  @return SMESH_Group
+    #  @return SMESH_GroupOnFilter
     #  @ingroup l2_grps_create
     def MakeGroup(self,
                   groupName,
@@ -1887,40 +1916,32 @@ class Mesh:
     ## Creates a mesh group by the given criterion
     #  @param groupName the name of the mesh group
     #  @param Criterion the instance of Criterion class
-    #  @return SMESH_Group
+    #  @return SMESH_GroupOnFilter
     #  @ingroup l2_grps_create
     def MakeGroupByCriterion(self, groupName, Criterion):
-        aFilterMgr = self.smeshpyD.CreateFilterManager()
-        aFilter = aFilterMgr.CreateFilter()
-        aCriteria = []
-        aCriteria.append(Criterion)
-        aFilter.SetCriteria(aCriteria)
-        group = self.MakeGroupByFilter(groupName, aFilter)
-        aFilterMgr.UnRegister()
-        return group
+        return self.MakeGroupByCriteria( groupName, [Criterion] )
 
     ## Creates a mesh group by the given criteria (list of criteria)
     #  @param groupName the name of the mesh group
     #  @param theCriteria the list of criteria
-    #  @return SMESH_Group
+    #  @param binOp binary operator used when binary operator of criteria is undefined
+    #  @return SMESH_GroupOnFilter
     #  @ingroup l2_grps_create
-    def MakeGroupByCriteria(self, groupName, theCriteria):
-        aFilterMgr = self.smeshpyD.CreateFilterManager()
-        aFilter = aFilterMgr.CreateFilter()
-        aFilter.SetCriteria(theCriteria)
+    def MakeGroupByCriteria(self, groupName, theCriteria, binOp=SMESH.FT_LogicalAND):
+        aFilter = self.smeshpyD.GetFilterFromCriteria( theCriteria, binOp )
         group = self.MakeGroupByFilter(groupName, aFilter)
-        aFilterMgr.UnRegister()
         return group
 
     ## Creates a mesh group by the given filter
     #  @param groupName the name of the mesh group
     #  @param theFilter the instance of Filter class
-    #  @return SMESH_Group
+    #  @return SMESH_GroupOnFilter
     #  @ingroup l2_grps_create
     def MakeGroupByFilter(self, groupName, theFilter):
-        group = self.CreateEmptyGroup(theFilter.GetElementType(), groupName)
-        theFilter.SetMesh( self.mesh )
-        group.AddFrom( theFilter )
+        #group = self.CreateEmptyGroup(theFilter.GetElementType(), groupName)
+        #theFilter.SetMesh( self.mesh )
+        #group.AddFrom( theFilter )
+        group = self.GroupOnFilter( theFilter.GetElementType(), groupName, theFilter )
         return group
 
     ## Removes a group
@@ -2570,7 +2591,7 @@ class Mesh:
 
     ## Get measure structure specifying bounding box data of the specified object(s)
     #  @param IDs single source object or list of source objects or list of nodes/elements IDs
-    #  @param isElem if @a objects is a list of IDs, @c True value in this parameters specifies that @a objects are elements,
+    #  @param isElem if @a IDs is a list of IDs, @c True value in this parameters specifies that @a objects are elements,
     #  @c False specifies that @a objects are nodes
     #  @return Measure structure
     #  @sa BoundingBox()
@@ -2956,6 +2977,37 @@ class Mesh:
             theFace = -1
         return self.editor.Reorient2D( the2DObject, theDirection, theFace, thePoint )
 
+    ## Reorient faces according to adjacent volumes.
+    #  @param the2DObject is a mesh, sub-mesh, group or list of
+    #         either IDs of faces or face groups.
+    #  @param the3DObject is a mesh, sub-mesh, group or list of IDs of volumes.
+    #  @param theOutsideNormal to orient faces to have their normals
+    #         pointing either \a outside or \a inside the adjacent volumes.
+    #  @return number of reoriented faces.
+    #  @ingroup l2_modif_changori
+    def Reorient2DBy3D(self, the2DObject, the3DObject, theOutsideNormal=True ):
+        unRegister = genObjUnRegister()
+        # check the2DObject
+        if not isinstance( the2DObject, list ):
+            the2DObject = [ the2DObject ]
+        elif the2DObject and isinstance( the2DObject[0], int ):
+            the2DObject = self.GetIDSource( the2DObject, SMESH.FACE )
+            unRegister.set( the2DObject )
+            the2DObject = [ the2DObject ]
+        for i,obj2D in enumerate( the2DObject ):
+            if isinstance( obj2D, Mesh ):
+                the2DObject[i] = obj2D.GetMesh()
+            if isinstance( obj2D, list ):
+                the2DObject[i] = self.GetIDSource( obj2D, SMESH.FACE )
+                unRegister.set( the2DObject[i] )
+        # check the3DObject
+        if isinstance( the3DObject, Mesh ):
+            the3DObject = the3DObject.GetMesh()
+        if isinstance( the3DObject, list ):
+            the3DObject = self.GetIDSource( the3DObject, SMESH.VOLUME )
+            unRegister.set( the3DObject )
+        return self.editor.Reorient2DBy3D( the2DObject, the3DObject, theOutsideNormal )
+
     ## Fuses the neighbouring triangles into quadrangles.
     #  @param IDsOfElements The triangles to be fused,
     #  @param theCriterion  is a numerical functor, in terms of enum SMESH.FunctorType, used to
@@ -3341,11 +3393,11 @@ class Mesh:
     #  them with quadratic with the same id.
     #  @param theForce3d new node creation method:
     #         0 - the medium node lies at the geometrical entity from which the mesh element is built
-    #         1 - the medium node lies at the middle of the line segments connecting start and end node of a mesh element
+    #         1 - the medium node lies at the middle of the line segments connecting two nodes of a mesh element
     #  @param theSubMesh a group or a sub-mesh to convert; WARNING: in this case the mesh can become not conformal
     #  @param theToBiQuad If True, converts the mesh to bi-quadratic
     #  @ingroup l2_modif_tofromqu
-    def ConvertToQuadratic(self, theForce3d, theSubMesh=None, theToBiQuad=False):
+    def ConvertToQuadratic(self, theForce3d=False, theSubMesh=None, theToBiQuad=False):
         if isinstance( theSubMesh, Mesh ):
             theSubMesh = theSubMesh.mesh
         if theToBiQuad:
@@ -3410,7 +3462,7 @@ class Mesh:
 
     ##
     # @brief Creates missing boundary elements around either the whole mesh or 
-    #    groups of 2D elements
+    #    groups of elements
     #  @param dimension - defines type of boundary elements to create
     #  @param groupName - a name of group to store all boundary elements in,
     #    "" means not to create the group
@@ -3418,7 +3470,7 @@ class Mesh:
     #    mesh + created boundary elements; "" means not to create the new mesh
     #  @param toCopyAll - if true, the whole initial mesh will be copied into
     #    the new mesh else only boundary elements will be copied into the new mesh
-    #  @param groups - groups of 2D elements to make boundary around
+    #  @param groups - groups of elements to make boundary around
     #  @retval tuple( long, mesh, groups )
     #                 long - number of added boundary elements
     #                 mesh - the mesh where elements were added to
@@ -3431,12 +3483,12 @@ class Mesh:
         if mesh: mesh = self.smeshpyD.Mesh(mesh)
         return nb, mesh, group
 
-    ## Renumber mesh nodes
+    ## Renumber mesh nodes (Obsolete, does nothing)
     #  @ingroup l2_modif_renumber
     def RenumberNodes(self):
         self.editor.RenumberNodes()
 
-    ## Renumber mesh elements
+    ## Renumber mesh elements (Obsole, does nothing)
     #  @ingroup l2_modif_renumber
     def RenumberElements(self):
         self.editor.RenumberElements()
@@ -3616,6 +3668,44 @@ class Mesh:
                                       ExtrFlags, SewTolerance)
         return []
 
+    ## Generates new elements by extrusion along the normal to a discretized surface or wire
+    #  @param Elements container of elements to extrude;
+    #         it can be Mesh, Group, Sub-mesh, Filter or list of IDs;
+    #         Only faces can be extruded so far. Sub-mesh sould be a sub-mesh on geom faces.
+    #  @param StepSize length of one extrusion step (the total extrusion
+    #         length will be \a NbOfSteps * \a StepSize ).
+    #  @param NbOfSteps number of extrusion steps.
+    #  @param ByAverageNormal if True each node is translated by \a StepSize
+    #         along the average of the normal vectors to the faces sharing the node;
+    #         else each node is translated along the same average normal till
+    #         intersection with the plane got by translation of the face sharing
+    #         the node along its own normal by \a StepSize.
+    #  @param UseInputElemsOnly to use only \a Elements when computing extrusion direction
+    #         for every node of \a Elements.
+    #  @param MakeGroups forces generation of new groups from existing ones.
+    #  @param Dim dimension of elements to extrude: 2 - faces or 1 - edges. Extrusion of edges
+    #         is not yet implemented. This parameter is used if \a Elements contains
+    #         both faces and edges, i.e. \a Elements is a Mesh.
+    #  @return the list of created groups (SMESH_GroupBase) if \a MakeGroups=True,
+    #          empty list otherwise.
+    #  @ingroup l2_modif_extrurev
+    def ExtrusionByNormal(self, Elements, StepSize, NbOfSteps,
+                          ByAverageNormal=False, UseInputElemsOnly=True, MakeGroups=False, Dim = 2):
+        unRegister = genObjUnRegister()
+        if isinstance( Elements, Mesh ):
+            Elements = Elements.GetMesh()
+        if isinstance( Elements, list ):
+            if not Elements:
+                raise RuntimeError, "List of element IDs is empty!"
+            if not isinstance( Elements[0], int ):
+                raise RuntimeError, "List must contain element IDs and not %s"% Elements[0]
+            Elements = self.GetIDSource( Elements, SMESH.ALL )
+            unRegister.set( Elements )
+        StepSize,NbOfSteps,Parameters,hasVars = ParseParameters(StepSize,NbOfSteps)
+        self.mesh.SetParameters(Parameters)
+        return self.editor.ExtrusionByNormal(Elements, StepSize, NbOfSteps,
+                                             UseInputElemsOnly, ByAverageNormal, MakeGroups, Dim)
+
     ## Generates new elements by extrusion of the elements which belong to the object
     #  @param theObject the object which elements should be processed.
     #                   It can be a mesh, a sub mesh or a group.
@@ -3928,12 +4018,14 @@ class Mesh:
     #  @param MakeGroups forces the generation of new groups from existing ones (if Copy)
     #  @return list of created groups (SMESH_GroupBase) if MakeGroups=True, empty list otherwise
     #  @ingroup l2_modif_trsf
-    def Mirror(self, IDsOfElements, Mirror, theMirrorType, Copy=0, MakeGroups=False):
+    def Mirror(self, IDsOfElements, Mirror, theMirrorType=None, Copy=0, MakeGroups=False):
         if IDsOfElements == []:
             IDsOfElements = self.GetElementsId()
         if ( isinstance( Mirror, geomBuilder.GEOM._objref_GEOM_Object)):
-            Mirror = self.smeshpyD.GetAxisStruct(Mirror)
-        self.mesh.SetParameters(Mirror.parameters)
+            Mirror        = self.smeshpyD.GetAxisStruct(Mirror)
+            theMirrorType = Mirror._mirrorType
+        else:
+            self.mesh.SetParameters(Mirror.parameters)
         if Copy and MakeGroups:
             return self.editor.MirrorMakeGroups(IDsOfElements, Mirror, theMirrorType)
         self.editor.Mirror(IDsOfElements, Mirror, theMirrorType, Copy)
@@ -3948,12 +4040,14 @@ class Mesh:
     #  @param NewMeshName a name of the new mesh to create
     #  @return instance of Mesh class
     #  @ingroup l2_modif_trsf
-    def MirrorMakeMesh(self, IDsOfElements, Mirror, theMirrorType, MakeGroups=0, NewMeshName=""):
+    def MirrorMakeMesh(self, IDsOfElements, Mirror, theMirrorType=0, MakeGroups=0, NewMeshName=""):
         if IDsOfElements == []:
             IDsOfElements = self.GetElementsId()
         if ( isinstance( Mirror, geomBuilder.GEOM._objref_GEOM_Object)):
-            Mirror = self.smeshpyD.GetAxisStruct(Mirror)
-        self.mesh.SetParameters(Mirror.parameters)
+            Mirror        = self.smeshpyD.GetAxisStruct(Mirror)
+            theMirrorType = Mirror._mirrorType
+        else:
+            self.mesh.SetParameters(Mirror.parameters)
         mesh = self.editor.MirrorMakeMesh(IDsOfElements, Mirror, theMirrorType,
                                           MakeGroups, NewMeshName)
         return Mesh(self.smeshpyD,self.geompyD,mesh)
@@ -3967,12 +4061,14 @@ class Mesh:
     #  @param MakeGroups forces the generation of new groups from existing ones (if Copy)
     #  @return list of created groups (SMESH_GroupBase) if MakeGroups=True, empty list otherwise
     #  @ingroup l2_modif_trsf
-    def MirrorObject (self, theObject, Mirror, theMirrorType, Copy=0, MakeGroups=False):
+    def MirrorObject (self, theObject, Mirror, theMirrorType=None, Copy=0, MakeGroups=False):
         if ( isinstance( theObject, Mesh )):
             theObject = theObject.GetMesh()
         if ( isinstance( Mirror, geomBuilder.GEOM._objref_GEOM_Object)):
-            Mirror = self.smeshpyD.GetAxisStruct(Mirror)
-        self.mesh.SetParameters(Mirror.parameters)
+            Mirror        = self.smeshpyD.GetAxisStruct(Mirror)
+            theMirrorType = Mirror._mirrorType
+        else:
+            self.mesh.SetParameters(Mirror.parameters)
         if Copy and MakeGroups:
             return self.editor.MirrorObjectMakeGroups(theObject, Mirror, theMirrorType)
         self.editor.MirrorObject(theObject, Mirror, theMirrorType, Copy)
@@ -3987,12 +4083,14 @@ class Mesh:
     #  @param NewMeshName the name of the new mesh to create
     #  @return instance of Mesh class
     #  @ingroup l2_modif_trsf
-    def MirrorObjectMakeMesh (self, theObject, Mirror, theMirrorType,MakeGroups=0, NewMeshName=""):
+    def MirrorObjectMakeMesh (self, theObject, Mirror, theMirrorType=0,MakeGroups=0,NewMeshName=""):
         if ( isinstance( theObject, Mesh )):
             theObject = theObject.GetMesh()
-        if (isinstance(Mirror, geomBuilder.GEOM._objref_GEOM_Object)):
-            Mirror = self.smeshpyD.GetAxisStruct(Mirror)
-        self.mesh.SetParameters(Mirror.parameters)
+        if ( isinstance( Mirror, geomBuilder.GEOM._objref_GEOM_Object)):
+            Mirror        = self.smeshpyD.GetAxisStruct(Mirror)
+            theMirrorType = Mirror._mirrorType
+        else:
+            self.mesh.SetParameters(Mirror.parameters)
         mesh = self.editor.MirrorObjectMakeMesh(theObject, Mirror, theMirrorType,
                                                 MakeGroups, NewMeshName)
         return Mesh( self.smeshpyD,self.geompyD,mesh )
@@ -4077,7 +4175,7 @@ class Mesh:
 
     ## Scales the object
     #  @param theObject - the object to translate (mesh, submesh, or group)
-    #  @param thePoint - base point for scale
+    #  @param thePoint - base point for scale (SMESH.PointStruct or list of 3 coordinates)
     #  @param theScaleFact - list of 1-3 scale factors for axises
     #  @param Copy - allows copying the translated elements
     #  @param MakeGroups - forces the generation of new groups from existing
@@ -4091,6 +4189,8 @@ class Mesh:
         if ( isinstance( theObject, list )):
             theObject = self.GetIDSource(theObject, SMESH.ALL)
             unRegister.set( theObject )
+        if ( isinstance( thePoint, list )):
+            thePoint = PointStruct( thePoint[0], thePoint[1], thePoint[2] )
         if ( isinstance( theScaleFact, float )):
              theScaleFact = [theScaleFact]
         if ( isinstance( theScaleFact, int )):
@@ -4105,7 +4205,7 @@ class Mesh:
 
     ## Creates a new mesh from the translated object
     #  @param theObject - the object to translate (mesh, submesh, or group)
-    #  @param thePoint - base point for scale
+    #  @param thePoint - base point for scale (SMESH.PointStruct or list of 3 coordinates)
     #  @param theScaleFact - list of 1-3 scale factors for axises
     #  @param MakeGroups - forces the generation of new groups from existing ones
     #  @param NewMeshName - the name of the newly created mesh
@@ -4117,6 +4217,8 @@ class Mesh:
         if ( isinstance( theObject, list )):
             theObject = self.GetIDSource(theObject,SMESH.ALL)
             unRegister.set( theObject )
+        if ( isinstance( thePoint, list )):
+            thePoint = PointStruct( thePoint[0], thePoint[1], thePoint[2] )
         if ( isinstance( theScaleFact, float )):
              theScaleFact = [theScaleFact]
         if ( isinstance( theScaleFact, int )):
@@ -4629,6 +4731,29 @@ class Mesh:
     def GetSkew(self, elemId):
         return self._valueFromFunctor(SMESH.FT_Skew, elemId)
 
+    ## Return minimal and maximal value of a given functor.
+    #  @param funType a functor type, an item of SMESH.FunctorType enum
+    #         (one of SMESH.FunctorType._items)
+    #  @param meshPart a part of mesh (group, sub-mesh) to treat
+    #  @return tuple (min,max)
+    #  @ingroup l1_measurements
+    def GetMinMax(self, funType, meshPart=None):
+        unRegister = genObjUnRegister()
+        if isinstance( meshPart, list ):
+            meshPart = self.GetIDSource( meshPart, SMESH.ALL )
+            unRegister.set( meshPart )
+        if isinstance( meshPart, Mesh ):
+            meshPart = meshPart.mesh
+        fun = self._getFunctor( funType )
+        if fun:
+            if meshPart:
+                hist = fun.GetLocalHistogram( 1, False, meshPart )
+            else:
+                hist = fun.GetHistogram( 1, False )
+            if hist:
+                return hist[0].min, hist[0].max
+        return None
+
     pass # end of Mesh class
 
 ## Helper class for wrapping of SMESH.SMESH_Pattern CORBA class