Salome HOME
[bos #35147] [EDF] (2023-T1) Decompose Viscous Layer API. cce/35147VL 20/head
authorcconopoima <cesar.conopoima@gmail.com>
Tue, 25 Jul 2023 19:15:25 +0000 (16:15 -0300)
committercconopoima <cesar.conopoima@gmail.com>
Wed, 18 Oct 2023 10:53:54 +0000 (11:53 +0100)
Delete .vscode/settings.json

Publish shrinkGeometry.

Refactor StdMeshers_Cartesian_3D and StdMeshers_Cartesian_VL classes to allow passing an arbitrary shrink mesh to the viscous layer builder. Use StdMeshers_Cartesian_VL in StdMeshers_ViscousLayerBuilder to handle geometry shrinking and viscous layer building.

Create maps to link shrink solid and the solid assign to the shrink mesh. Code cleanup.

Defining map btw original shape (TopAbs_COMPOUND) and result shrink object. Refactor to support viscous layer of faces. Code clean up and add of tests.

Documentation and code cleanup

erase debug comment.

Modif after code review.

Avoid compilation warning from ViscousLayerBuilder and ViscousLayerBuilder_i classes.

19 files changed:
doc/examples/defining_hypotheses_vlapi_ex17.py [new file with mode: 0644]
doc/examples/tests.set
doc/gui/input/additional_hypo.rst
doc/gui/input/tui_defining_hypotheses.rst
idl/SMESH_BasicHypothesis.idl
src/SMESH_SWIG/StdMeshersBuilder.py
src/StdMeshers/CMakeLists.txt
src/StdMeshers/StdMeshers_Cartesian_3D.cxx
src/StdMeshers/StdMeshers_Cartesian_VL.cxx
src/StdMeshers/StdMeshers_Cartesian_VL.hxx
src/StdMeshers/StdMeshers_ViscousLayerBuilder.cxx [new file with mode: 0644]
src/StdMeshers/StdMeshers_ViscousLayerBuilder.hxx [new file with mode: 0644]
src/StdMeshers_I/CMakeLists.txt
src/StdMeshers_I/StdMeshers_ViscousLayerBuilder_i.cxx [new file with mode: 0644]
src/StdMeshers_I/StdMeshers_ViscousLayerBuilder_i.hxx [new file with mode: 0644]
src/StdMeshers_I/StdMeshers_i.cxx
test/test_vlapi_growthlayer.py [new file with mode: 0644]
test/test_vlapi_shrinkgeometry.py [new file with mode: 0644]
test/tests.set

diff --git a/doc/examples/defining_hypotheses_vlapi_ex17.py b/doc/examples/defining_hypotheses_vlapi_ex17.py
new file mode 100644 (file)
index 0000000..3f4ed36
--- /dev/null
@@ -0,0 +1,84 @@
+# Viscous layers construction
+
+import salome
+salome.salome_init_without_session()
+
+import SMESH
+from salome.geom import geomBuilder
+from salome.smesh import smeshBuilder
+
+geom_builder = geomBuilder.New()
+smesh_builder = smeshBuilder.New()
+
+X = geom_builder.MakeVectorDXDYDZ( 1,0,0 )
+O = geom_builder.MakeVertex( 100,50,50 )
+plane = geom_builder.MakePlane( O, X, 200 ) # plane YZ
+
+box = geom_builder.MakeBoxDXDYDZ(200,100,100)
+
+shape = geom_builder.MakeHalfPartition( box, plane )
+
+faces = geom_builder.SubShapeAllSorted(shape, geom_builder.ShapeType["FACE"])
+face1 = faces[1]
+# 4 left, 34 middle, 50 right
+# Have to pass the middle face id, otherwise it is going to create two disjoint boxes
+# because the common face is not going to be ignored and both boxes are going to shrink
+# in this direction too
+ignoreFaces = [4,34,50]
+
+geom_builder.addToStudy( shape, "shape" )
+geom_builder.addToStudyInFather( shape, face1, "face1")
+
+# 3D Viscous layers
+mesh = smesh_builder.Mesh(shape, "CFD")
+
+ViscousBuilder = mesh.ViscousLayerBuilder()
+thickness = 20 
+numberOfLayers = 10
+stretchFactor = 1.5
+groupName = "Boundary layers"
+ViscousBuilder.setBuilderParameters( thickness, numberOfLayers, stretchFactor, 
+                                                ignoreFaces,                # optional
+                                                groupName = groupName )     # optional
+
+Shrinkshape = ViscousBuilder.GetShrinkGeometry()
+
+shrinkMesh = smesh_builder.Mesh(Shrinkshape, "Shrink")
+shrinkMesh.Segment().NumberOfSegments( 4 )
+faces = geom_builder.SubShapeAllSorted(Shrinkshape, geom_builder.ShapeType["FACE"])
+shrinkFace1 = faces[1]
+
+shrinkMesh.Triangle()
+shrinkMesh.Quadrangle(shrinkFace1)
+algo3D = shrinkMesh.Tetrahedron()
+
+if not shrinkMesh.Compute(): raise Exception("Error when computing Mesh")
+
+#Add viscous layer
+FinalMesh = ViscousBuilder.AddLayers( shrinkMesh )
+
+mesh.MakeGroup("Tetras",SMESH.VOLUME,SMESH.FT_ElemGeomType,"=",SMESH.Geom_TETRA)
+mesh.MakeGroup("Pyras",SMESH.VOLUME,SMESH.FT_ElemGeomType,"=",SMESH.Geom_PYRAMID)
+mesh.MakeGroup("Prims",SMESH.VOLUME,SMESH.FT_ElemGeomType,"=",SMESH.Geom_PENTA)
+
+# 2D Viscous layers
+
+# 3 edges of the 4 edges of face1
+edgeIds = geom_builder.SubShapeAllIDs( face1, geom_builder.ShapeType["EDGE"])[:-1]
+
+mesh = smesh_builder.Mesh(face1,"Face1")
+ViscousBuilder = mesh.ViscousLayerBuilder()
+ViscousBuilder.setBuilderParameters( 2, 3, 1.5, 
+                                    edgeIds, True, # optional
+                                    groupName = groupName )     # optional
+
+#For 2D, edges are not selectable (to be developed in occt) the entire face is shrink
+shrinkFace = ViscousBuilder.GetShrinkGeometry()
+shrinkMesh = smesh_builder.Mesh(shrinkFace, "VicsousLayers2D")
+
+shrinkMesh.Segment().NumberOfSegments( 5 )
+algo2D = shrinkMesh.Triangle()
+
+if not shrinkMesh.Compute(): raise Exception("Error when computing Mesh of shrink face")
+
+FinalMeshFace = ViscousBuilder.AddLayers( shrinkMesh )
\ No newline at end of file
index 86d5e8787abbbd9e21434284a0b71a26b269897d..273c4b4ab0b2b8f2a5f4ae3371f27a5aa8976150 100644 (file)
@@ -37,6 +37,7 @@ SET(BAD_TESTS
   defining_hypotheses_ex10.py
   defining_hypotheses_ex11.py
   defining_hypotheses_ex17.py
+  defining_hypotheses_vlapi_ex17.py
   defining_hypotheses_adaptive1d.py
   filters_ex01.py
   filters_ex02.py
index 73a916bb8818f869dc40da37e5b4c600a9a645c6..21c42ea8288d41b31fc670bdcf37308da8c5dc8e 100644 (file)
@@ -136,6 +136,27 @@ computations.
 
 **See also** a sample TUI script of a :ref:`tui_viscous_layers`.
 
+.. _viscous_layers_api_anchor:
+
+Viscous Layers API
+####################################
+
+The Viscous layer API is available on TUI. Allows to compute a shrink version of the geometry. This shrank version can be passed to any mesher and be used to
+build the viscous layer from the mesh computed in the shrank geometry. The current implementation only support the **Face offset** method to extrude the 
+nodes from the shrank mesh to the original geometry. 
+
+This implementation supports 3D (Solids and Solid Compound) and 2D (Face) geometries. For the 3D case, the faces Ids are
+used to identify the faces (perpendicular to it) where the solid is to be reduced. For the 2D case, the edges Ids can be provided but will not have any effect
+on the geometry computation (this control is not available in the opencascade library), therefore, for this case the entire face is shrank.
+
+The Viscous Layer API receive the same parameters as the Viscous Layers Hypothesis and implements four methods:
+
+* The constructor ``ViscousLayerBuilder()``
+* The parameters definitions ``setBuilderParameters(...)``
+* The ``GetShrinkGeometry()`` method that returns the shrink version of the original geomtry.
+* The ``AddLayers( shrinkMesh )`` method that returns the complet version of the mesh (shrink+viscous layer)
+
+**See also** a sample TUI script of a :ref:`tui_viscous_layers_api`.
 
 .. _quadratic_mesh_anchor:
 
index 2832d9423df3f97d89f34ae8afd231318114b2f3..0121a0ce0079d636875c5a472f02cbacc507e4e4 100644 (file)
@@ -251,6 +251,16 @@ Viscous layers construction
 
 :download:`Download this script <../../examples/defining_hypotheses_ex17.py>`
 
+.. _tui_viscous_layers_api:
+
+Viscous layers API construction
+###########################
+
+.. literalinclude:: ../../examples/defining_hypotheses_vlapi_ex17.py
+    :language: python
+
+:download:`Download this script <../../examples/defining_hypotheses_vlapi_ex17.py>`
+
 .. _tui_radial_prism:
 
 Radial Prism example
index 2cd7513665314989dd583b5c14e6676d8877993d..30281a309df91e47a258b11338d9ab37938cb4c1 100644 (file)
 #ifndef _SMESH_BASICHYPOTHESIS_IDL_
 #define _SMESH_BASICHYPOTHESIS_IDL_
 
+#include "GEOM_Gen.idl"
+
 #include "SALOME_Exception.idl"
 #include "SMESH_Hypothesis.idl"
 #include "SMESH_Mesh.idl"
-
 /*!
  * StdMeshers: interfaces to standard hypotheses and algorithms
  */
@@ -1247,6 +1248,39 @@ module StdMeshers
   interface StdMeshers_Cartesian_3D : SMESH::SMESH_3D_Algo
   {
   };
+  /*!
+   * StdMeshers_Cartesian_3D: interface of "ViscousLayerBuilder" algorithm
+   */
+  interface StdMeshers_ViscousLayerBuilder : SMESH::SMESH_2D_Algo
+  {
+    /*!
+     * Set faces to exclude from the definition of face to shrink
+     */
+    void SetIgnoreFaces(in SMESH::long_array faceIDs) raises (SALOME::SALOME_Exception);
+    // SMESH::long_array GetIgnoreFaces();
+
+    /*!
+     * Set faces either to exclude from treatment or to make the offset geometry on.
+     */
+    void SetFaces(in SMESH::long_array faceIDs,
+                  in boolean           toIgnore) raises (SALOME::SALOME_Exception);
+    // SMESH::long_array GetFaces();
+    // boolean           GetIsToIgnoreFaces();
+
+    void SetTotalThickness(in double thickness) raises (SALOME::SALOME_Exception);
+    void SetNumberLayers(in short numberOfLayers ) raises (SALOME::SALOME_Exception);
+    void SetStretchFactor(in double strechFactor ) raises (SALOME::SALOME_Exception);
+    void SetMethod( in VLExtrusionMethod how );
+    void SetGroupName(in string name);
+
+    GEOM::GEOM_Object GetShrinkGeometry( in SMESH::SMESH_Mesh finalMesh, in GEOM::GEOM_Object theObject );
+
+    /*!
+     * Build the prismatic layer from the shrink mesh
+     */
+    boolean AddLayers( in SMESH::SMESH_Mesh sourceMesh, in SMESH::SMESH_Mesh finalMesh, in GEOM::GEOM_Object theObject );
+
+  };
 
 };
 
index 05d3ffd8e229ff215f6c2ad373dbe53f553fa8af..015050e122e06f443c0daf92493389a0f0f2ba73 100644 (file)
@@ -25,6 +25,7 @@ LIBRARY = "libStdMeshersEngine.so"
 
 from salome.smesh.smesh_algorithm import Mesh_Algorithm
 import StdMeshers
+from salome.geom import geomBuilder
 
 #----------------------------
 # Mesh algo type identifiers
@@ -2013,3 +2014,106 @@ class StdMeshersBuilder_UseExisting_2D(Mesh_Algorithm):
         pass
 
     pass # end of StdMeshersBuilder_UseExisting_2D class
+    
+class StdMeshersBuilder_ViscousLayer(Mesh_Algorithm):
+    """ Defines the prismatic layer builder.
+
+    It is created by calling smeshBuilder.Mesh.ViscousLayerBuilder(geom=TheGeometry)
+    """
+    
+    meshMethod = "ViscousLayerBuilder"
+    """
+    name of the dynamic method in smeshBuilder.Mesh class
+    """
+    algoType   = "ViscousLayerBuilder"
+    """
+    type of algorithm used with helper function in smeshBuilder.Mesh class
+    """
+    docHelper  = "Viscous layer builder for 2D and 3D geometries"
+    """
+    doc string of the method
+    """
+    
+    # On create method it will call create method from mesh python class
+    # 
+    def __init__(self, mesh, geom = 0 ):
+        """
+        Private constructor.
+
+        Parameters:
+            mesh: parent mesh object algorithm is assigned to
+            geom: geometry (shape/sub-shape) algorithm is assigned to;
+                if it is :code:`0` (default), the algorithm is assigned to the main shape
+        """        
+        self.thickness          = None
+        self.numberOfLayers     = None
+        self.stretchFactor      = None
+        self.elementsId         = []
+        self.isElementToIgnore  = True
+        self.extrMethod         = StdMeshers.SURF_OFFSET_SMOOTH
+        self.groupName          = ""
+        self.shrinkGeometry     = None
+        self.algo               = self.Create(mesh, geom, self.algoType)     
+        pass
+
+    def setBuilderParameters( self, thickness, numberOfLayers, stretchFactor, elementsId=[], 
+                                    isElementToIgnore=True, extrMethod=StdMeshers.SURF_OFFSET_SMOOTH, groupName="" ):            
+        self.thickness          = thickness
+        self.numberOfLayers     = numberOfLayers
+        self.stretchFactor      = stretchFactor
+        self.elementsId         = elementsId        # can be faces or edges
+        self.isElementToIgnore  = isElementToIgnore
+        self.extrMethod         = extrMethod
+        self.groupName          = groupName
+
+        self.algo.SetTotalThickness( thickness )
+        self.algo.SetNumberLayers( numberOfLayers )
+        self.algo.SetStretchFactor( stretchFactor )
+        
+        #Faces are set based on int ids so if a collection of face geom objects is recived cast it to int 
+        if elementsId and isinstance( elementsId, geomBuilder.GEOM._objref_GEOM_Object ):
+            elementsId = [ elementsId ]
+        if elementsId and isinstance( elementsId[0], geomBuilder.GEOM._objref_GEOM_Object ):
+            elementsIDs = []
+            for shape in elementsId:
+                try:
+                  ff = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["FACE"] )
+                  if ( len( ff ) == 0 ):
+                    #try to get edges
+                    ff = self.mesh.geompyD.SubShapeAll( shape, self.mesh.geompyD.ShapeType["EDGE"] )
+
+                  for f in ff:
+                    elementsIDs.append( self.mesh.geompyD.GetSubShapeID(self.mesh.geom, f))
+                except:
+                  # try to get the SHAPERSTUDY engine directly, because GetGen does not work because of
+                  # simplification of access in geomBuilder: omniORB.registerObjref
+                  from SHAPERSTUDY_utils import getEngine
+                  gen = getEngine()
+                  if gen:
+                    aShapeOp = gen.GetIShapesOperations()
+                    ff = aShapeOp.ExtractSubShapes( shape, self.mesh.geompyD.ShapeType["FACE"], False)
+                    if (len(ff)==0):
+                        #try to get edges
+                        ff = aShapeOp.ExtractSubShapes( shape, self.mesh.geompyD.ShapeType["EDGE"], False)
+                    for f in ff:
+                      elementsIDs.append( aShapeOp.GetSubShapeIndex( self.mesh.geom, f ))
+            elementsId = elementsIDs
+
+        self.algo.SetFaces( elementsId, isElementToIgnore )    
+        self.algo.SetGroupName( groupName )   
+        self.algo.SetMethod( extrMethod )        
+        
+    def GetShrinkGeometry( self ):
+        if isinstance(self.geom, geomBuilder.GEOM._objref_GEOM_Object):
+            self.shrinkGeometry = self.algo.GetShrinkGeometry( self.mesh.GetMesh(), self.geom )
+        
+        return self.shrinkGeometry
+
+    def AddLayers( self, shrinkMesh ):
+        success = self.algo.AddLayers( shrinkMesh.GetMesh(), self.mesh.GetMesh(), self.geom )
+        if ( success ):
+            return self.mesh  #Return the original mesh of the builder
+        else:
+            return shrinkMesh
+
+    pass # end of StdMeshersBuilder_ViscousLayer class
\ No newline at end of file
index 44715862777a24c77f49fc29ddbebb3f8bb77c41..349b74825e3a32a328954048a6cefa2d709b9a8d 100644 (file)
@@ -125,6 +125,7 @@ SET(StdMeshers_HEADERS
   StdMeshers_PolygonPerFace_2D.hxx
   StdMeshers_PolyhedronPerSolid_3D.hxx
   StdMeshers_BlockRenumber.hxx
+  StdMeshers_ViscousLayerBuilder.hxx
 )
 
 # --- sources ---
@@ -190,6 +191,7 @@ SET(StdMeshers_SOURCES
   StdMeshers_PolygonPerFace_2D.cxx
   StdMeshers_PolyhedronPerSolid_3D.cxx
   StdMeshers_BlockRenumber.cxx
+  StdMeshers_ViscousLayerBuilder.cxx
 )
 
 # --- rules ---
index 7fb50a747dcc9f5a75081ee3daca0cc62b186958..1223736d05dbd059d49e07a3663a232f29b3f137 100644 (file)
@@ -182,6 +182,17 @@ bool StdMeshers_Cartesian_3D::CheckHypothesis (SMESH_Mesh&          aMesh,
 
 namespace
 {
+  /*!
+   * \brief Temporary mesh to hold 
+   */
+  struct TmpMesh: public SMESH_Mesh
+  {
+    TmpMesh() {
+      _isShapeToMesh = (_id = 0);
+      _meshDS  = new SMESHDS_Mesh( _id, true );
+    }
+  };
+
   typedef int                     TGeomID; // IDs of sub-shapes
   typedef TopTools_ShapeMapHasher TShapeHasher; // non-oriented shape hasher
   typedef std::array< int, 3 >    TIJK;
@@ -6406,13 +6417,15 @@ bool StdMeshers_Cartesian_3D::Compute(SMESH_Mesh &         theMesh,
     if ( offsetShape.IsNull() )
       throw SALOME_Exception( error );
 
-    SMESH_Mesh* offsetMesh = builder.MakeOffsetMesh();
+    SMESH_Mesh* offsetMesh = new TmpMesh(); 
+    offsetMesh->ShapeToMesh( offsetShape );
+    offsetMesh->GetSubMesh( offsetShape )->DependsOn();
 
     this->_isComputeOffset = true;
     if ( ! this->Compute( *offsetMesh, offsetShape ))
       return false;
 
-    return builder.MakeViscousLayers( theMesh, theShape );
+    return builder.MakeViscousLayers( *offsetMesh, theMesh, theShape );
   }
 
   // The algorithm generates the mesh in following steps:
index ee1a4f0cc232f03f718f0cdc223e31ca46a15e0a..784996922ec273625cff20d3382b1f4c31ded6fb 100644 (file)
@@ -30,6 +30,7 @@
 #include <SMESHDS_Mesh.hxx>
 #include <SMESHDS_SubMesh.hxx>
 #include <SMESH_Algo.hxx>
+#include <SMESH_MeshAlgos.hxx>
 #include <SMESH_Mesh.hxx>
 #include <SMESH_MeshEditor.hxx>
 #include <SMESH_MesherHelper.hxx>
 #include <SMESH_subMesh.hxx>
 
 #include <BRepAdaptor_Curve.hxx>
-#include <BRepTopAdaptor_FClass2d.hxx>
 #include <BRep_Builder.hxx>
+#include <BRepBuilderAPI_MakeFace.hxx>
+#include <BRepGProp.hxx>
+#include <BRepTopAdaptor_FClass2d.hxx>
 #include <BRep_Tool.hxx>
+#include <GProp_GProps.hxx>
 #include <ShapeAnalysis_Curve.hxx>
 #include <ShapeAnalysis_Surface.hxx>
 #include <TopExp.hxx>
@@ -138,6 +142,7 @@ namespace
     SMESHDS_SubMesh* sm = theOffsetMDS->MeshElements( theEOS._offsetShape );
     if ( !sm || sm->NbElements() == 0 || sm->NbNodes() == 0 )
       return;
+
     theEOS._edges.resize( sm->NbNodes() );
 
     const TopoDS_Face& initFace = TopoDS::Face( theEOS._initShape );
@@ -189,13 +194,17 @@ namespace
 
   void projectToEdge( VLEdgesOnShape & theEOS,
                       SMESHDS_Mesh*    theOffsetMDS,
-                      TNode2VLEdge &   theN2E )
+                      TNode2VLEdge &   theN2E,
+                      bool createVertex )
   {
     SMESHDS_SubMesh* sm = theOffsetMDS->MeshElements( theEOS._offsetShape );
     if ( !sm || sm->NbElements() == 0 )
       return;
-    theEOS._edges.resize( sm->NbNodes() );
 
+    int addVertexNode = createVertex ? 1 : 0;
+    theEOS._edges.resize( sm->NbNodes() + addVertexNode ); // +1 to set the vertex 
+    
     ShapeAnalysis_Curve projector;
     BRepAdaptor_Curve   initCurve( TopoDS::Edge( theEOS._initShape ));
     const double        tol = Precision::Confusion();
@@ -227,8 +236,39 @@ namespace
 
       theN2E.Bind( offP.Node(), &vlEdge );
     }
+
+    if ( createVertex )
+    {
+      // It is possible to define the vertex projections from the existing edges
+      // EOS._offsetShape the edge generated from the original edge
+      // Get the first vertex of both edges to define the connecting edges
+      auto offsetEdge = TopoDS::Edge( theEOS._offsetShape );
+      auto initEdge   = TopoDS::Edge( theEOS._initShape );
+      TopoDS_Vertex offsetVertex;
+      TopoDS_Vertex initVertex;
+      
+      if ( offsetEdge.Orientation() == TopAbs_FORWARD )
+      {
+        offsetVertex  = TopExp::FirstVertex ( offsetEdge );
+        initVertex    = TopExp::FirstVertex ( initEdge ); 
+      }
+      else
+      {
+        offsetVertex  = TopExp::LastVertex ( offsetEdge );
+        initVertex    = TopExp::LastVertex ( initEdge ); 
+      }
+
+      VLEdge & vlEdge = theEOS._edges[ iN ];
+      vlEdge._nodes.resize( 2 );
+      vlEdge._nodes[0] = SMESH_Algo::VertexNode( offsetVertex, theOffsetMDS );
+      
+      gp_Pnt offP = BRep_Tool::Pnt( initVertex );
+      
+      vlEdge._nodes[1] = theOffsetMDS->AddNode( offP.X(), offP.Y(), offP.Z() );
+      theN2E.Bind( vlEdge._nodes[0].Node(), &vlEdge );
+    }
     return;
-  }
+  }  
 
   //================================================================================
   /*!
@@ -445,13 +485,12 @@ namespace
             prism2polyhedron( vNodes, volumElem );
 
           if ( const SMDS_MeshElement* vol = editor.AddElement( vNodes, volumElem ))
-            vol->setIsMarked( true ); // to add to group
+            vol->setIsMarked( true ); // to add to group          
         }
       }
       else // at inlet/outlet
-      {
         makePolyhedron( edgesVec, vNodes, editor, volumElem );
-      }
+
       editor.ClearLastCreated();
 
       // move the face to the top of prisms, on mesh boundary
@@ -467,6 +506,7 @@ namespace
    *  \param [inout] theMesh - offset mesh to fill in
    *  \param [inout] theN2E - map of node to VLEdge
    *  \param [inout] theFaceID - ID of WOVL FACE for new faces to set on
+   *  \param [in]    isMainShape2D - used to identify the geometry where the new elements are included
    *  \return bool - ok
    */
   //================================================================================
@@ -474,7 +514,8 @@ namespace
   bool makeFaces( VLEdgesOnShape & theEOS,
                   SMESH_Mesh*      theMesh,
                   TNode2VLEdge   & theN2E,
-                  const TGeomID    theFaceID)
+                  const TGeomID    theFaceID,
+                  bool isMainShape2D = false )
   {
     SMESHDS_SubMesh* sm = theMesh->GetMeshDS()->MeshElements( theEOS._offsetShape );
     if ( !sm || sm->NbElements() == 0 )
@@ -486,6 +527,27 @@ namespace
     std::vector< const SMDS_MeshNode* > fNodes( 4 );
     std::vector<const SMDS_MeshElement *> foundVolum;
     std::vector< VLEdge*> edgesVec;
+    TIDSortedElemSet  refSetFace;
+    
+    // Check orientation of face and re
+    gp_XYZ refNormalVector(0.0,0.0,0.0);
+    if ( isMainShape2D )
+    {
+      SMESHDS_Mesh* offsetMDS = theMesh->GetMeshDS();
+      for ( SMDS_ElemIteratorPtr eIt = offsetMDS->elementsIterator(); eIt->more(); )
+      {
+        const SMDS_MeshElement* refFace = eIt->next(); // define the ref
+        if ( refFace->GetType() == SMDSAbs_Face )
+        {
+          SMESH_MeshAlgos::FaceNormal( refFace, refNormalVector, /*normalized=*/true );
+          break;
+        }
+      }
+      if ( refNormalVector.X() == 0.0 && refNormalVector.Y() == 0.0 && refNormalVector.Z() == 0.0 )
+        throw SALOME_Exception("No 2D element found in the mesh!\n");
+
+    }
+    
     for ( SMDS_ElemIteratorPtr eIt = sm->GetElements(); eIt->more(); )
     {
       const SMDS_MeshElement* edge = eIt->next();
@@ -503,6 +565,7 @@ namespace
         edgesVec[ i ] = theN2E( n );
       }
       size_t nbFaces = edgesVec[0]->_nodes.size() - 1;
+
       for ( size_t iF = 0; iF < nbFaces; ++iF )
       {
         fNodes[ 0 ] = edgesVec[ 0 ]->_nodes[ iF ].Node();
@@ -519,13 +582,20 @@ namespace
             TIDSortedElemSet faces = { face }, volumes = { foundVolum[0] };
             editor.Reorient2DBy3D( faces, volumes, /*outside=*/true );
           }
+          else if ( isMainShape2D )
+          {
+            gp_XYZ elementNormal;
+            SMESH_MeshAlgos::FaceNormal( face, elementNormal, /*normalized=*/true );
+            if ( elementNormal * refNormalVector < 0.0 /* diff orientation from the ref element */)
+              editor.Reorient( face );
+          }
         }
       }
       editor.ClearLastCreated();
 
       // move the face to the top of prisms, on mesh boundary
       //theMesh->GetMeshDS()->ChangeElementNodes( face, fNodes.data(), nbNodes );
-    }
+    }    
     return true;
   }
 
@@ -790,11 +860,16 @@ StdMeshers_Cartesian_VL::ViscousBuilder::ViscousBuilder( const StdMeshers_Viscou
   {
     const TopoDS_Shape& face = faces( i );
     TGeomID fID = iniMDS->ShapeToIndex( face );
-    if ( _shapesWVL.count( fID ))
+    bool isMainShape2D = (mainShape.ShapeType() == TopAbs_FACE) ? true : false;
+
+    if ( _shapesWVL.count( fID ) && !isMainShape2D )
       continue;
+
     for ( TopExp_Explorer exp( face, TopAbs_EDGE ); exp.More(); exp.Next() )
       _edge2facesWOVL[ iniMDS->ShapeToIndex( exp.Current() )].push_back( fID );
   }
+  
+  // When 2D meshing Need to add edges where segments need to be added due to geometry shrink
   return;
 }
 
@@ -806,7 +881,96 @@ StdMeshers_Cartesian_VL::ViscousBuilder::ViscousBuilder( const StdMeshers_Viscou
 
 StdMeshers_Cartesian_VL::ViscousBuilder::~ViscousBuilder()
 {
-  delete _offsetMesh; _offsetMesh = 0;
+  delete _offsetMesh; //_offsetMesh = 0;
+}
+
+//================================================================================
+/*!
+ * \brief Create an offset solid from a given one
+ *  \param [in] theShape - input shape can be a solid, solidcompound or a compound with solids
+ *  \param [in] theMesh - main mesh
+ *  \param [out] theError - error description
+ *  \return TopoDS_Shape - result offset shape of the same type as the received shape
+ */
+//================================================================================
+
+TopoDS_Shape StdMeshers_Cartesian_VL::ViscousBuilder::MakeOffsetSolid(const TopoDS_Shape & theShape,
+                                                                        SMESH_Mesh &         theMesh,
+                                                                        std::string &        theError )
+{
+  double offset = -_hyp->GetTotalThickness();
+  double    tol = Precision::Confusion();
+  TopAbs_ShapeEnum typeOfShape = theShape.ShapeType();
+
+  TopTools_IndexedMapOfShape shapeList;
+  TopExp::MapShapes( theShape, TopAbs_SOLID, shapeList );
+  std::vector<TopoDS_Shape> shrinkBodies;
+
+  for ( int i = 1; i <= shapeList.Size(); ++i )
+  {
+    auto solid = shapeList( i );
+      // If Shape is solid call direct 
+    BRepOffset_MakeOffset * makeOffset = new BRepOffset_MakeOffset();
+    makeOffset->Initialize( solid, offset, tol, BRepOffset_Skin, /*Intersection=*/false,
+                          /*selfInter=*/false, GeomAbs_Intersection);
+
+    // exclude inlet FACEs
+    SMESHDS_Mesh* meshDS = theMesh.GetMeshDS();
+    for ( TopExp_Explorer fEx( theShape, TopAbs_FACE ); fEx.More(); fEx.Next() )
+    {
+      TGeomID fID = meshDS->ShapeToIndex( fEx.Current() );
+      if ( !_shapesWVL.count( fID ))
+        makeOffset->SetOffsetOnFace( TopoDS::Face( fEx.Current()), 0 );
+    }
+
+    makeOffset->MakeOffsetShape();
+    if ( makeOffset->IsDone() )
+    {
+      shrinkBodies.push_back( makeOffset->Shape() );
+      _makeOffsetCollection.push_back( makeOffset );
+    }
+    else
+    {
+      switch ( makeOffset->Error() )
+      {
+      case BRepOffset_NoError:
+        theError = "OK. Offset performed successfully.";break;
+      case BRepOffset_BadNormalsOnGeometry:
+        theError = "Degenerated normal on input data.";break;
+      case BRepOffset_C0Geometry:
+        theError = "C0 continuity of input data.";break;
+      case BRepOffset_NullOffset:
+        theError = "Null offset of all faces.";break;
+      case BRepOffset_NotConnectedShell:
+        theError = "Incorrect set of faces to remove, the remaining shell is not connected.";break;
+      case BRepOffset_CannotTrimEdges:
+        theError = "Can not trim edges.";break;
+      case BRepOffset_CannotFuseVertices:
+        theError = "Can not fuse vertices.";break;
+      case BRepOffset_CannotExtentEdge:
+        theError = "Can not extent edge.";break;
+      default:
+        theError = "operation not done.";
+      }
+      theError = "BRepOffset_MakeOffset error: " + theError;
+
+      return TopoDS_Shape();
+    }    
+  }
+  
+  if ( typeOfShape == TopAbs_COMPOUND || typeOfShape == TopAbs_COMPSOLID )
+  {
+    _solidCompound.SetGlue( BOPAlgo_GlueFull );
+    _solidCompound.SetToFillHistory( true );
+    for ( auto solid : shrinkBodies )
+      _solidCompound.AddArgument( solid );
+
+    _solidCompound.Perform();
+    return _solidCompound.Shape();
+  }
+  else
+    return shrinkBodies[ 0 ]; // return one solid
+
 }
 
 //================================================================================
@@ -824,91 +988,155 @@ StdMeshers_Cartesian_VL::ViscousBuilder::MakeOffsetShape(const TopoDS_Shape & th
                                                          SMESH_Mesh &         theMesh,
                                                          std::string &        theError )
 {
-  double offset = -_hyp->GetTotalThickness();
-  double    tol = Precision::Confusion();
-  _makeOffset.Initialize( theShape, offset, tol, BRepOffset_Skin, /*Intersection=*/false,
-                          /*selfInter=*/false, GeomAbs_Intersection );
-  // exclude inlet FACEs
-  SMESHDS_Mesh* meshDS = theMesh.GetMeshDS();
-  for ( TopExp_Explorer fEx( theShape, TopAbs_FACE ); fEx.More(); fEx.Next() )
-  {
-    TGeomID fID = meshDS->ShapeToIndex( fEx.Current() );
-    if ( !_shapesWVL.count( fID ))
-      _makeOffset.SetOffsetOnFace( TopoDS::Face( fEx.Current()), 0 );
-  }
+  double offset                 = -_hyp->GetTotalThickness();
+  double    tol                 = Precision::Confusion();
+  TopAbs_ShapeEnum typeOfShape  = theShape.ShapeType();
 
-  _makeOffset.MakeOffsetShape();
-  if ( _makeOffset.IsDone() )
+  // Switch here for the treatment of faces
+  if ( typeOfShape == TopAbs_FACE )
   {
-    _offsetShape = _makeOffset.Shape();
-    SMESH_MesherHelper::WriteShape( _offsetShape );////
-
-    _offsetMesh->ShapeToMesh( _offsetShape );
-    _offsetMesh->GetSubMesh( _offsetShape )->DependsOn();
+    TopoDS_Face face = TopoDS::Face( theShape );
+    GProp_GProps gprops;
+    BRepGProp::SurfaceProperties(face, gprops); // Stores results in gprops
+    double faceArea = gprops.Mass();
+
+    _makeFaceOffset = BRepOffsetAPI_MakeOffset( face, GeomAbs_Intersection );
+    _makeFaceOffset.Perform( offset );
+    TopoDS_Wire wireFrame   = TopoDS::Wire( _makeFaceOffset.Shape() );
+    TopoDS_Face shrinkFace  = TopoDS::Face( BRepBuilderAPI_MakeFace( wireFrame, false ) );
+    BRepGProp::SurfaceProperties(shrinkFace, gprops); // Stores results in gprops
+    double sArea = gprops.Mass();
+
+    if ( sArea > faceArea /*recompute the shrink face because offset was done in the contrary direction as expected*/)
+    {
+      _makeFaceOffset.Perform( -offset );
+      wireFrame  = TopoDS::Wire( _makeFaceOffset.Shape() );
+      shrinkFace = TopoDS::Face( BRepBuilderAPI_MakeFace( wireFrame, false ) );
+    }
+    _offsetShape = shrinkFace;
     return _offsetShape;
   }
-
-  switch ( _makeOffset.Error() )
+  else
   {
-  case BRepOffset_NoError:
-    theError = "OK. Offset performed successfully.";break;
-  case BRepOffset_BadNormalsOnGeometry:
-    theError = "Degenerated normal on input data.";break;
-  case BRepOffset_C0Geometry:
-    theError = "C0 continuity of input data.";break;
-  case BRepOffset_NullOffset:
-    theError = "Null offset of all faces.";break;
-  case BRepOffset_NotConnectedShell:
-    theError = "Incorrect set of faces to remove, the remaining shell is not connected.";break;
-  case BRepOffset_CannotTrimEdges:
-    theError = "Can not trim edges.";break;
-  case BRepOffset_CannotFuseVertices:
-    theError = "Can not fuse vertices.";break;
-  case BRepOffset_CannotExtentEdge:
-    theError = "Can not extent edge.";break;
-  default:
-    theError = "operation not done.";
-  }
-  theError = "BRepOffset_MakeOffset error: " + theError;
-
-  return TopoDS_Shape();
+    _offsetShape = MakeOffsetSolid( theShape, theMesh, theError );
+    return _offsetShape;
+  }  
 }
 
 //================================================================================
 /*!
- * \brief Return a sub-shape of the offset shape generated from a given initial sub-shape
+ * \brief Return the list of sub-shape of the same type of the offset shape generated from a given initial sub-shape
  */
 //================================================================================
 
-TopoDS_Shape StdMeshers_Cartesian_VL::ViscousBuilder::getOffsetSubShape( const TopoDS_Shape& S )
+void StdMeshers_Cartesian_VL::ViscousBuilder::getOffsetSubShape( const TopoDS_Shape& S, std::vector<TopoDS_Shape>& subShapeList )
+{  
+  for( auto offset : _makeOffsetCollection )
+  {
+    const TopTools_ListOfShape& newShapes = offset->Generated( S );
+    if ( newShapes.Size() == 0 )
+      continue; // keep searching
+
+    for ( const TopoDS_Shape& ns : newShapes )
+    {
+      if ( ns.ShapeType() == S.ShapeType() )
+      {
+        if  ( _solidCompound.Arguments().Size() == 0 /* only one solid shrank*/ )
+        {
+          subShapeList.push_back( ns );
+        }
+        else
+        {
+          // In boolean operations the shapes are modified or deleted
+          const TopTools_ListOfShape& newGlueShapes = _solidCompound.Modified( ns );
+          for ( TopoDS_Shape& ngs : newGlueShapes )
+            if ( ngs.ShapeType() == ns.ShapeType() /*&& !ngs.Checked()*/  )
+              subShapeList.push_back( ngs );
+          
+          if ( newGlueShapes.Size() == 0 && !_solidCompound.IsDeleted( ns ) )
+            subShapeList.push_back( ns );
+        }
+      }            
+    }      
+  }     
+
+  // check for _makeFaceOffset in face shrink
+  if ( _makeOffsetCollection.size()  == 0 )
+  {
+    const TopTools_ListOfShape& newShapes = _makeFaceOffset.Generated( S );
+    for ( const TopoDS_Shape& ns : newShapes )
+    {
+      if ( ns.ShapeType() == S.ShapeType() )
+        return subShapeList.push_back( ns );
+    }
+  }
+}
+
+bool StdMeshers_Cartesian_VL::ViscousBuilder::CheckGeometryMaps( SMESH_Mesh &        offsetMesh,
+                                                                  const TopoDS_Shape & theShape  )
 {
-  const TopTools_ListOfShape& newShapes = _makeOffset.Generated( S );
-  for ( const TopoDS_Shape& ns : newShapes )
-    if ( ns.ShapeType() == S.ShapeType() )
-      return ns;
-  return TopoDS_Shape();
+  SMESHDS_Mesh* offsetMDS       = offsetMesh.GetMeshDS();
+  TopoDS_Shape shrinkGeomToMesh = offsetMDS->ShapeToMesh();  
+
+  TopTools_IndexedMapOfShape shrinkGeomMap;
+  TopExp::MapShapes( shrinkGeomToMesh, shrinkGeomMap );
+  TopTools_IndexedMapOfShape offsetGeomMap;
+  TopExp::MapShapes( _offsetShape, offsetGeomMap );
+
+  // loop on sub-shapes to project nodes from offset boundary to initial boundary
+  TopAbs_ShapeEnum types[3] = { TopAbs_VERTEX, TopAbs_EDGE, TopAbs_FACE };
+  for ( TopAbs_ShapeEnum shType : types )
+  {
+    TopTools_IndexedMapOfShape shapes;
+    TopExp::MapShapes( theShape, shType, shapes );
+    for ( int i = 1; i <= shapes.Size(); ++i )
+    {
+      // For each type of geometry check the existence of one or more equivalents
+      std::vector<TopoDS_Shape> listOfShapes;
+      getOffsetSubShape( shapes(i), listOfShapes );
+      if ( listOfShapes.size() == 0 ) return false;
+    }
+  }
+  return true;
 }
 
 //================================================================================
 /*!
  * \brief Create prismatic mesh between _offsetShape and theShape
+ *  \remark Build the viscous layer from the iteration of shrink geometry
  *  \param [out] theMesh - mesh to fill in
  *  \param [in] theShape - initial shape
  *  \return bool - is Ok
  */
 //================================================================================
 
-bool StdMeshers_Cartesian_VL::ViscousBuilder::MakeViscousLayers( SMESH_Mesh &         theMesh,
+bool StdMeshers_Cartesian_VL::ViscousBuilder::MakeViscousLayers( SMESH_Mesh &        offsetMesh,
+                                                                 SMESH_Mesh &         theMesh,
                                                                  const TopoDS_Shape & theShape )
 {
-  SMESHDS_Mesh* offsetMDS = _offsetMesh->GetMeshDS();
-  SMESHDS_Mesh*   initMDS = theMesh.GetMeshDS();
+  SMESHDS_Mesh* offsetMDS       = offsetMesh.GetMeshDS();
+  SMESHDS_Mesh*   initMDS       = theMesh.GetMeshDS();
+  TopoDS_Shape shrinkGeomToMesh = offsetMDS->ShapeToMesh();  
+  bool isMainShape2D = (theShape.ShapeType() == TopAbs_FACE) ? true : false;
+
+  // Validate map of shrink+joint geometry elements
+  if ( !CheckGeometryMaps(offsetMesh, theShape ) && !isMainShape2D )
+    throw SALOME_Exception("All elements from the shrink geometry were not match to the original geometry\n");
+
+  
+  initMDS->ClearMesh(); // avoid mesh superposition on multiple calls of addLayers
   offsetMDS->SetAllCellsNotMarked();
 
+  TopTools_IndexedMapOfShape shrinkGeomMap;
+  TopExp::MapShapes( shrinkGeomToMesh, shrinkGeomMap );
+
+  TopTools_IndexedMapOfShape offsetGeomMap;
+  TopExp::MapShapes( _offsetShape, offsetGeomMap );
+
   // Compute heights of viscous layers
   std::vector< double > vlH;
   computeVLHeight( _hyp, vlH );
-
+  
   std::vector< VLEdgesOnShape > edgesOnShape;
   edgesOnShape.reserve( offsetMDS->MaxShapeIndex() + 1 );
   TNode2VLEdge n2e;
@@ -923,55 +1151,64 @@ bool StdMeshers_Cartesian_VL::ViscousBuilder::MakeViscousLayers( SMESH_Mesh &
     {
       edgesOnShape.resize( edgesOnShape.size() + 1 );
       VLEdgesOnShape& EOS = edgesOnShape.back();
-
+      std::vector<TopoDS_Shape> listOfShapes;
       EOS._initShape    = shapes( i );
-      EOS._offsetShape  = getOffsetSubShape( EOS._initShape );
-      EOS._initShapeID  = initMDS->ShapeToIndex( EOS._initShape );
-      EOS._hasVL        = _shapesWVL.count( EOS._initShapeID );
-      EOS._toCheckCoinc = false;
-      if ( !EOS._hasVL )
-        continue;
-
-      // project boundary nodes of offset mesh to boundary of init mesh
-      // (new nodes are created in the offset mesh)
-      switch( EOS._offsetShape.ShapeType() ) {
-      case TopAbs_VERTEX:
-      {
-        EOS._edges.resize( 1 );
-        EOS._edges[0]._nodes.resize( 2 );
-        EOS._edges[0]._nodes[0] = SMESH_Algo::VertexNode( TopoDS::Vertex( EOS._offsetShape ),
-                                                          offsetMDS );
-        gp_Pnt offP = BRep_Tool::Pnt( TopoDS::Vertex( EOS._initShape ));
-        EOS._edges[0]._nodes[1] = offsetMDS->AddNode( offP.X(), offP.Y(), offP.Z() );
-        //EOS._edges[0]._length   = offP.Distance( EOS._edges[0]._nodes[0] );
-        n2e.Bind( EOS._edges[0]._nodes[0].Node(), & EOS._edges[0] );
-        break;
-      }
-      case TopAbs_EDGE:
-      {
-        projectToEdge( EOS, offsetMDS, n2e );
-        break;
-      }
-      case TopAbs_FACE:
+      
+      // Get a list of subShapes of the same type generated from the same face
+      // It is the case with split objects.
+      getOffsetSubShape( EOS._initShape, listOfShapes );
+      for ( TopoDS_Shape& shrinkShape : listOfShapes )
       {
-        projectToFace( EOS, offsetMDS, n2e );
-        break;
-      }
-      default:;
-      }
+        int shapeId       = offsetGeomMap.FindIndex( shrinkShape );        
+        EOS._offsetShape  = shrinkGeomMap.FindKey( shapeId );     
+        EOS._initShapeID  = initMDS->ShapeToIndex( EOS._initShape );
+        EOS._hasVL        = _shapesWVL.count( EOS._initShapeID );
+
+        EOS._toCheckCoinc = false;
+        if ( !EOS._hasVL )
+          continue;
+
+        // project boundary nodes of offset mesh to boundary of init mesh
+        // (new nodes are created in the offset mesh)
+        switch( EOS._offsetShape.ShapeType() ) {
+        case TopAbs_VERTEX:
+        {
+          EOS._edges.resize( 1 );
+          EOS._edges[0]._nodes.resize( 2 );
+          EOS._edges[0]._nodes[0] = SMESH_Algo::VertexNode( TopoDS::Vertex( EOS._offsetShape ),
+                                                            offsetMDS );
+          gp_Pnt offP = BRep_Tool::Pnt( TopoDS::Vertex( EOS._initShape ));
+          EOS._edges[0]._nodes[1] = offsetMDS->AddNode( offP.X(), offP.Y(), offP.Z() );
+          //EOS._edges[0]._length   = offP.Distance( EOS._edges[0]._nodes[0] );
+          n2e.Bind( EOS._edges[0]._nodes[0].Node(), & EOS._edges[0] );
+          break;
+        }
+        case TopAbs_EDGE:
+        {
+          projectToEdge( EOS, offsetMDS, n2e, isMainShape2D /* add vertex from edges*/ );
+          break;
+        }
+        case TopAbs_FACE:
+        {
+          projectToFace( EOS, offsetMDS, n2e );
+          break;
+        }
+        default:;
+        }
 
-      // create nodes of layers
-      if ( _hyp->GetNumberLayers() > 1 )
-      {
-        //if ( _shapesWVL.count( EOS._initShapeID ))
-        for ( size_t i = 0; i < EOS._edges.size(); ++i )
+        // create nodes of layers
+        if ( _hyp->GetNumberLayers() > 1 )
         {
-          divideVLEdge( &EOS._edges[ i ], vlH, offsetMDS );
+          //if ( _shapesWVL.count( EOS._initShapeID ))
+          for ( size_t i = 0; i < EOS._edges.size(); ++i )
+          {
+            divideVLEdge( &EOS._edges[ i ], vlH, offsetMDS );
+          }
         }
-      }
-    } // loop on shapes
+      } // loop on generated shrink shape
+    }//loop on original shape
   } // loop on shape types
-
+  
   // create prisms
   bool prismsOk = true;
   for ( size_t i = 0; i < edgesOnShape.size(); ++i )
@@ -979,10 +1216,11 @@ bool StdMeshers_Cartesian_VL::ViscousBuilder::MakeViscousLayers( SMESH_Mesh &
     VLEdgesOnShape& EOS = edgesOnShape[ i ];
     if ( EOS._initShape.ShapeType() == TopAbs_FACE && EOS._hasVL )
     {
-      if ( !makePrisms( EOS, _offsetMesh, n2e ))
+      if ( !makePrisms( EOS, &offsetMesh, n2e ))
         prismsOk = false;
     }
   }
+
   if ( prismsOk )
   {
     // create faces on FACEs WOVL
@@ -994,22 +1232,40 @@ bool StdMeshers_Cartesian_VL::ViscousBuilder::MakeViscousLayers( SMESH_Mesh &
         auto e2f = _edge2facesWOVL.find( EOS._initShapeID );
         if ( e2f != _edge2facesWOVL.end() && !e2f->second.empty() )
         {
-          TopoDS_Shape f = initMDS->IndexToShape( e2f->second[0] );
-          TopoDS_Shape f2 = getOffsetSubShape( f );
-          //cout << e2f->second[0] << " OFF " << offsetMDS->ShapeToIndex( f2 ) << endl;
-          makeFaces( EOS, _offsetMesh, n2e, offsetMDS->ShapeToIndex( f2 ) );
+          TopoDS_Shape  f = initMDS->IndexToShape( e2f->second[0] );
+          std::vector<TopoDS_Shape> listOfShapes;
+          getOffsetSubShape( f, listOfShapes );
+          for( TopoDS_Shape& subShape : listOfShapes )
+          {
+            int shapeId   = offsetGeomMap.FindIndex( subShape );
+            TopoDS_Shape f2 = shrinkGeomMap.FindKey( shapeId );     
+            makeFaces( EOS, & offsetMesh, n2e, offsetMDS->ShapeToIndex( f2 ) );
+          }        
         }
       }
     }
   }
 
-  // copy offset mesh to the main one
+  if ( isMainShape2D )
+  {
+     // create faces on FACEs of the inflate viscous layer in 2D faces
+    for ( size_t i = 0; i < edgesOnShape.size(); ++i )
+    {
+      VLEdgesOnShape& EOS = edgesOnShape[ i ];
+      if ( EOS._initShape.ShapeType() == TopAbs_EDGE && EOS._hasVL /* iterate in market edges with viscous layer*/)
+      {
+        int shapeId = offsetMDS->ShapeToIndex( shrinkGeomToMesh );
+        makeFaces( EOS, & offsetMesh, n2e, shapeId, isMainShape2D ); // pass face Id of shrink geometry
+      }
+    }
+  }
+
+   // copy offset mesh to the main one
   initMDS->Modified();
   initMDS->CompactMesh();
   smIdType nShift = initMDS->NbNodes();
   TGeomID solidID = initMDS->ShapeToIndex( theShape );
-  copyMesh( _offsetMesh, & theMesh, solidID );
-
+  copyMesh( & offsetMesh, & theMesh, solidID );
 
   if ( !prismsOk )
   {
@@ -1028,9 +1284,9 @@ bool StdMeshers_Cartesian_VL::ViscousBuilder::MakeViscousLayers( SMESH_Mesh &
   {
     VLEdgesOnShape& EOS = edgesOnShape[ i ];
     if ( EOS._hasVL )
-      setBnd2Sub( EOS, &theMesh, _offsetMesh, n2e, nShift, nodesToCheckCoinc );
+      setBnd2Sub( EOS, &theMesh, &offsetMesh, n2e, nShift, nodesToCheckCoinc );
     else
-      setBnd2FVWL( EOS, &theMesh, _offsetMesh, nShift );
+      setBnd2FVWL( EOS, &theMesh, &offsetMesh, nShift );
   }
 
   // merge coincident nodes
@@ -1052,5 +1308,6 @@ bool StdMeshers_Cartesian_VL::ViscousBuilder::MakeViscousLayers( SMESH_Mesh &
     }
   }
 
+
   return prismsOk;
-}
+}
\ No newline at end of file
index f8f1c7dca5b2f85c71fdf1ab74225d2a2c420b25..daec1236127fc7f890ef6c32973a9bd610b80284 100644 (file)
 #ifndef __StdMeshers_Cartesian_VL_HXX__
 #define __StdMeshers_Cartesian_VL_HXX__
 
+#include <BOPAlgo_Builder.hxx>
 #include <BRepOffset_MakeOffset.hxx>
+#include <BRepOffsetAPI_MakeOffset.hxx>
+
 #include <set>
 #include <map>
 #include <vector>
 
+class TopoDS_Face;
 class StdMeshers_ViscousLayers;
 class SMESH_Mesh;
 
@@ -47,23 +51,34 @@ namespace StdMeshers_Cartesian_VL
 
     TopoDS_Shape MakeOffsetShape(const TopoDS_Shape & theShape,
                                  SMESH_Mesh &         theMesh,
-                                 std::string &        theError );
+                                 std::string &        theError );                              
 
     SMESH_Mesh*  MakeOffsetMesh();
 
-    bool         MakeViscousLayers( SMESH_Mesh &         theMesh,
-                                    const TopoDS_Shape & theShape );
-
+    bool         MakeViscousLayers( SMESH_Mesh &         offsetMesh,
+                                    SMESH_Mesh &         theMesh,
+                                    const TopoDS_Shape & theShape );                 
+    
   private:
+    
+    TopoDS_Shape MakeOffsetSolid(const TopoDS_Shape & theShape,
+                                 SMESH_Mesh &         theMesh,
+                                 std::string &        theError );   
+
+    bool         CheckGeometryMaps( SMESH_Mesh &         offsetMesh,
+                                    const TopoDS_Shape & theShape );             
 
-    TopoDS_Shape getOffsetSubShape( const TopoDS_Shape& S );
+    void getOffsetSubShape( const TopoDS_Shape& S, std::vector<TopoDS_Shape>& listOfShapes );
 
     const StdMeshers_ViscousLayers* _hyp;
     BRepOffset_MakeOffset           _makeOffset;
+    std::vector<BRepOffset_MakeOffset*> _makeOffsetCollection;  // collection to  
+    BRepOffsetAPI_MakeOffset        _makeFaceOffset;            // to define shrink of planar faces. The face is shrink in all 
+    BOPAlgo_Builder                 _solidCompound;             // to glue solids with common faces after shrinking then with BRepOffset_MakeOffset
     SMESH_Mesh*                     _offsetMesh;
     TopoDS_Shape                    _offsetShape;
-    std::set< int >                 _shapesWVL; // shapes with viscous layers
-    std::map< int, std::vector< int > > _edge2facesWOVL; // EDGE 2 FACEs w/o VL
+    std::set< int >                 _shapesWVL;                 // shapes with viscous layers
+    std::map< int, std::vector< int > > _edge2facesWOVL;        // EDGE 2 FACEs w/o VL
   };
 }
 
diff --git a/src/StdMeshers/StdMeshers_ViscousLayerBuilder.cxx b/src/StdMeshers/StdMeshers_ViscousLayerBuilder.cxx
new file mode 100644 (file)
index 0000000..e6a6ff3
--- /dev/null
@@ -0,0 +1,134 @@
+// Copyright (C) 2007-2023  CEA, EDF, OPEN CASCADE
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+// File      : StdMeshers_ViscousLayerBuilder.cxx
+// Module    : SMESH
+// Author    : Cesar Conopoima (cce)
+//
+
+#include "SMESHDS_Mesh.hxx"
+#include "SMESH_ControlsDef.hxx"
+#include "SMESH_Gen.hxx"
+#include "SMESH_Mesh.hxx"
+#include "SMESH_MeshAlgos.hxx"
+#include "SMESH_MeshEditor.hxx"
+#include "SMESH_MesherHelper.hxx"
+#include "StdMeshers_ViscousLayerBuilder.hxx"
+
+#include <TopoDS.hxx>
+
+#include <vector>
+
+//=======================================================================
+//function : StdMeshers_ViscousLayerBuilder
+//purpose  : Implements 
+//=======================================================================
+
+StdMeshers_ViscousLayerBuilder::StdMeshers_ViscousLayerBuilder(int        hypId,
+                                                                SMESH_Gen* gen)
+  : SMESH_2D_Algo(hypId, gen)
+{
+  _name = "StdMeshers_ViscousLayerBuilder";
+  _hyp    = new StdMeshers_ViscousLayers2D( hypId, gen );  
+}
+
+bool StdMeshers_ViscousLayerBuilder::CheckHypothesis(SMESH_Mesh&                          aMesh,
+                                                      const TopoDS_Shape&                  aShape,
+                                                      SMESH_Hypothesis::Hypothesis_Status& aStatus)
+{
+  (void) aMesh;
+  (void) aShape;
+  (void) aStatus;
+  return true;
+}
+
+bool StdMeshers_ViscousLayerBuilder::Compute(SMESH_Mesh& /*aMesh*/, const TopoDS_Shape& /*aShape*/)
+{
+  return true;
+}
+
+bool StdMeshers_ViscousLayerBuilder::Evaluate(SMESH_Mesh & /*aMesh*/, const TopoDS_Shape & /*aShape*/,
+                                                MapShapeNbElems& /*aResMap*/ )
+{
+  return true;
+}
+
+bool StdMeshers_ViscousLayerBuilder::IsApplicable( const TopoDS_Shape &S, bool /*toCheckAll*/, int algoDim )
+{
+  if ( S.ShapeType() > TopAbs_FACE )
+    return false;
+
+  return ( std::abs( algoDim ) == 3 || std::abs( algoDim ) == 2 ) ? true : false;
+}
+
+void StdMeshers_ViscousLayerBuilder::SetBndShapes(const std::vector<int>& faceIds, bool toIgnore)
+{
+  _hyp->SetBndShapes( faceIds, toIgnore );  
+} // --------------------------------------------------------------------------------
+void StdMeshers_ViscousLayerBuilder::SetTotalThickness(double thickness)
+{
+  _hyp->SetTotalThickness( thickness );
+} // --------------------------------------------------------------------------------
+void StdMeshers_ViscousLayerBuilder::SetNumberLayers(int nb)
+{
+  _hyp->SetNumberLayers( nb );
+} // --------------------------------------------------------------------------------
+void StdMeshers_ViscousLayerBuilder::SetStretchFactor(double factor)
+{
+  _hyp->SetStretchFactor( factor );
+} // --------------------------------------------------------------------------------
+void StdMeshers_ViscousLayerBuilder::SetMethod( StdMeshers_ViscousLayers::ExtrusionMethod method )
+{
+  _hyp->SetMethod( method );
+} // --------------------------------------------------------------------------------
+void StdMeshers_ViscousLayerBuilder::SetGroupName(const std::string& name)
+{
+  _hyp->SetGroupName( name );
+} 
+
+//=======================================================================
+//function : ~StdMeshers_ViscousLayerBuilder
+//purpose  :
+//=======================================================================
+
+StdMeshers_ViscousLayerBuilder::~StdMeshers_ViscousLayerBuilder()
+{
+}
+
+TopoDS_Shape StdMeshers_ViscousLayerBuilder::GetShrinkGeometry( SMESH_Mesh & theMesh, const TopoDS_Shape& theShape )
+{
+  _vlBuilder  = new StdMeshers_Cartesian_VL::ViscousBuilder( _hyp, theMesh, theShape );
+
+  std::string error = "";
+  _offsetShape = _vlBuilder->MakeOffsetShape( theShape, theMesh, error );
+  if ( error != "" )
+    throw SALOME_Exception( error );
+  
+  return _offsetShape;
+}
+
+bool StdMeshers_ViscousLayerBuilder::AddLayers( SMESH_Mesh & shrinkMesh, SMESH_Mesh & theMesh, const TopoDS_Shape& theShape )
+{
+  bool success = _vlBuilder->MakeViscousLayers( shrinkMesh, theMesh, theShape );
+  
+  if ( !success )
+    throw SALOME_Exception( "Error building viscous layer from shrink geometry." );
+
+  return success;
+}
diff --git a/src/StdMeshers/StdMeshers_ViscousLayerBuilder.hxx b/src/StdMeshers/StdMeshers_ViscousLayerBuilder.hxx
new file mode 100644 (file)
index 0000000..2238a22
--- /dev/null
@@ -0,0 +1,107 @@
+// Copyright (C) 2007-2023  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
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+//  File   : StdMeshers_ViscousLayersBuilder.hxx
+//  Module : SMESH
+//
+#ifndef _SMESH_ViscourLayerBuilder_HXX_
+#define _SMESH_ViscourLayerBuilder_HXX_
+
+#include <BRepOffset_MakeOffset.hxx>
+#include <BRepOffset_Offset.hxx>
+
+#include "SMESH_StdMeshers.hxx"
+#include "SMESH_Hypothesis.hxx"
+#include "StdMeshers_Cartesian_VL.hxx"
+#include "StdMeshers_ViscousLayers.hxx"
+#include "StdMeshers_ViscousLayers2D.hxx"
+
+
+class STDMESHERS_EXPORT StdMeshers_ViscousLayerBuilder: public SMESH_2D_Algo
+{
+ public:
+  StdMeshers_ViscousLayerBuilder(int hypId, SMESH_Gen* gen);
+  ~StdMeshers_ViscousLayerBuilder();
+
+  virtual bool CheckHypothesis(SMESH_Mesh&                          aMesh,
+                               const TopoDS_Shape&                  aShape,
+                               SMESH_Hypothesis::Hypothesis_Status& aStatus);
+
+  virtual bool Compute(SMESH_Mesh& /*aMesh*/, const TopoDS_Shape& /*aShape*/ );
+
+  virtual bool Evaluate(SMESH_Mesh & /*aMesh*/, const TopoDS_Shape & /*aShape*/,
+                        MapShapeNbElems& /*aResMap*/ );
+
+  /*!
+   * \brief Check if the algo is applicable to the geometry and dimension
+  */
+  virtual bool IsApplicable( const TopoDS_Shape &S, bool /*toCheckAll*/, int algoDim );  
+
+  void   SetBndShapes(const std::vector<int>& shapeIds, bool toIgnore);
+  // std::vector<int> GetBndShapes() const { return _shapeIds; }
+  // bool   IsToIgnoreShapes() const { return _isToIgnoreShapes; }
+
+  void   SetTotalThickness(double thickness);
+  // double GetTotalThickness() const { return _thickness; }
+
+  void   SetNumberLayers(int nb);
+  // int    GetNumberLayers() const { return _nbLayers; }
+
+  void   SetStretchFactor(double factor);
+  // double GetStretchFactor() const { return _stretchFactor; }
+
+  void   SetMethod( StdMeshers_ViscousLayers::ExtrusionMethod how );
+  // StdMeshers_ViscousLayers::ExtrusionMethod GetMethod() const { return _method; }
+
+  // name of a group to create
+  void SetGroupName(const std::string& name);
+  // const std::string& GetGroupName() const { return _groupName; }
+
+   /*!
+   * \brief Compute a shrink version of the geometry. 
+   *        Use the BRepOffset_MakeOffset to perfom the operations for Solids. 
+   *        Use BRepBuilderAPI_MakeFace to perform the operation for planar faces.
+   * \remark For possitive offsets, planar faces are shrink in all directions BRepBuilderAPI_MakeFace does not support coarse grained edge selection.
+    * \param theMesh - the built mesh
+    * \param theShape - the geometry to be shrink
+    * \retval TopoDS_Shape - a new shape of the shrink geometry
+   */
+  TopoDS_Shape GetShrinkGeometry( SMESH_Mesh & theMesh, const TopoDS_Shape & theShape );
+
+    /*!
+   * \brief Build the elements of the viscous layer based on the shrinkMesh and copied to theMesh 
+    * \param shrinkMesh - the mesh defined on the shrink geometry
+    * \param theMesh - the final mesh with the combination of the shrink mesh and the viscous layer
+    * \param theShape - the original geometry
+    * \retval bool - Ok if success in the operation
+   */
+  bool AddLayers( SMESH_Mesh & shrinkMesh, SMESH_Mesh & theMesh, const TopoDS_Shape & theShape );
+
+  private:
+    
+    
+    StdMeshers_ViscousLayers2D*                     _hyp;
+    StdMeshers_Cartesian_VL::ViscousBuilder*  _vlBuilder;
+
+    BRepOffset_MakeOffset                     _makeOffset;
+    BRepOffset_Offset                     _makeFaceOffset;
+    TopoDS_Shape                             _offsetShape;
+};
+
+#endif
index 40ec1b50d5e5df1500f53ff38b8f6c3d6bd32f86..286f6f4d1527b07f58681c801e4ca451e1c04919 100644 (file)
@@ -115,6 +115,7 @@ SET(StdMeshersEngine_HEADERS
   StdMeshers_PolygonPerFace_2D_i.hxx
   StdMeshers_PolyhedronPerSolid_3D_i.hxx
   StdMeshers_BlockRenumber_i.hxx
+  StdMeshers_ViscousLayerBuilder_i.hxx
 )
 # --- sources ---
 
@@ -169,6 +170,7 @@ SET(StdMeshersEngine_SOURCES
   StdMeshers_PolygonPerFace_2D_i.cxx
   StdMeshers_PolyhedronPerSolid_3D_i.cxx
   StdMeshers_BlockRenumber_i.cxx
+  StdMeshers_ViscousLayerBuilder_i.cxx
 )
 
 # --- rules ---
diff --git a/src/StdMeshers_I/StdMeshers_ViscousLayerBuilder_i.cxx b/src/StdMeshers_I/StdMeshers_ViscousLayerBuilder_i.cxx
new file mode 100644 (file)
index 0000000..3fc1561
--- /dev/null
@@ -0,0 +1,205 @@
+// Copyright (C) 2007-2023  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
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+//  SMESH SMESH_I : idl implementation based on 'SMESH' unit's classes
+//  File   : StdMeshers_ViscousLayers_i.cxx
+//  Module : SMESH
+//
+#include "StdMeshers_ViscousLayerBuilder_i.hxx"
+
+#include "SMESH_Gen.hxx"
+#include "SMESH_Gen_i.hxx"
+#include "SMESH_Group.hxx"
+#include "SMESH_Group_i.hxx"
+#include "SMESH_PythonDump.hxx"
+
+#include "BRepTools.hxx"
+#include "Utils_CorbaException.hxx"
+#include "utilities.h"
+
+#include <TCollection_AsciiString.hxx>
+
+#include CORBA_SERVER_HEADER(SMESH_Group)
+
+using namespace std;
+
+//=============================================================================
+/*!
+ *  StdMeshers_ViscousLayerBuilder_i::StdMeshers_ViscousLayerBuilder_i
+ *
+ *  Constructor
+ */
+//=============================================================================
+
+StdMeshers_ViscousLayerBuilder_i::StdMeshers_ViscousLayerBuilder_i( PortableServer::POA_ptr thePOA,
+                                                                      ::SMESH_Gen*            theGenImpl )
+  : SALOME::GenericObj_i( thePOA ), 
+      SMESH_Hypothesis_i( thePOA ),
+      SMESH_Algo_i( thePOA ),
+      SMESH_2D_Algo_i( thePOA )
+{
+  myBaseImpl = new ::StdMeshers_ViscousLayerBuilder( theGenImpl->GetANewId(),
+                                                      theGenImpl );
+}
+
+::StdMeshers_ViscousLayerBuilder* StdMeshers_ViscousLayerBuilder_i::GetImpl()
+{
+  return ( ::StdMeshers_ViscousLayerBuilder* )myBaseImpl;
+}
+
+//================================================================================
+/*!
+ * \brief Verify whether hypothesis supports given entity type 
+  * \param type - dimension (see SMESH::Dimension enumeration)
+  * \retval CORBA::Boolean - TRUE if dimension is supported, FALSE otherwise
+ * 
+ * Verify whether hypothesis supports given entity type (see SMESH::Dimension enumeration)
+ */
+//================================================================================  
+CORBA::Boolean StdMeshers_ViscousLayerBuilder_i::IsDimSupported( SMESH::Dimension type )
+{
+  return type == SMESH::DIM_3D || type == SMESH::DIM_2D;
+}
+
+void StdMeshers_ViscousLayerBuilder_i::SetFaces(const ::SMESH::long_array& faceIDs,
+                                                  CORBA::Boolean             toIgnore)
+{
+  vector<int> ids( faceIDs.length() );
+  for ( unsigned i = 0; i < ids.size(); ++i )
+    if (( ids[i] = faceIDs[i] ) < 1 )
+      THROW_SALOME_CORBA_EXCEPTION( "Invalid face id", SALOME::BAD_PARAM );
+
+  GetImpl()->SetBndShapes( ids, toIgnore );
+
+  SMESH::TPythonDump() << _this() << ".SetFaces( " << faceIDs << ", " << toIgnore << " )";
+}
+
+
+void StdMeshers_ViscousLayerBuilder_i::SetIgnoreFaces(const ::SMESH::long_array& faceIDs)
+{
+  vector<int> ids( faceIDs.length() );
+  for ( unsigned i = 0; i < ids.size(); ++i )
+    if (( ids[i] = faceIDs[i] ) < 1 )
+      THROW_SALOME_CORBA_EXCEPTION( "Invalid face id", SALOME::BAD_PARAM );
+  GetImpl()->SetBndShapes( ids, /*toIgnore=*/true );
+  SMESH::TPythonDump() << _this() << ".SetIgnoreFaces( " << faceIDs << " )";
+}
+
+void StdMeshers_ViscousLayerBuilder_i::SetTotalThickness(::CORBA::Double thickness)
+{
+  if ( thickness < 1e-100 )
+    THROW_SALOME_CORBA_EXCEPTION( "Invalid thickness", SALOME::BAD_PARAM );
+  GetImpl()->SetTotalThickness(thickness);
+  SMESH::TPythonDump() << _this() << ".SetTotalThickness( " << SMESH::TVar(thickness) << " )";
+}
+
+void StdMeshers_ViscousLayerBuilder_i::SetNumberLayers(::CORBA::Short nb)
+{
+  if ( nb < 1 )
+    THROW_SALOME_CORBA_EXCEPTION( "Invalid number of layers", SALOME::BAD_PARAM );
+  GetImpl()->SetNumberLayers( nb );
+  SMESH::TPythonDump() << _this() << ".SetNumberLayers( " << SMESH::TVar(nb) << " )";
+}
+
+void StdMeshers_ViscousLayerBuilder_i::SetStretchFactor(::CORBA::Double factor)
+{
+  if ( factor < 1 )
+    THROW_SALOME_CORBA_EXCEPTION( "Invalid stretch factor, it must be >= 1.0", SALOME::BAD_PARAM );
+  GetImpl()->SetStretchFactor(factor);
+  SMESH::TPythonDump() << _this() << ".SetStretchFactor( " << SMESH::TVar(factor) << " )";
+}
+
+void StdMeshers_ViscousLayerBuilder_i::SetMethod( ::StdMeshers::VLExtrusionMethod how )
+{
+  GetImpl()->SetMethod( ::StdMeshers_ViscousLayers::ExtrusionMethod( how ));
+  const char* methNames[3] = { "SURF_OFFSET_SMOOTH",
+                               "FACE_OFFSET",
+                               "NODE_OFFSET" };
+  if ( how >= 0 && how < 3 )
+    SMESH::TPythonDump() << _this() << ".SetMethod( StdMeshers." << methNames[ how ]<< " )";
+}
+
+void StdMeshers_ViscousLayerBuilder_i::SetGroupName(const char* name)
+{
+  GetImpl()->SetGroupName( name );
+  SMESH::TPythonDump() << _this() << ".SetGroupName( '" << name << "' )";
+}
+
+GEOM::GEOM_Object_ptr StdMeshers_ViscousLayerBuilder_i::GetShrinkGeometry( SMESH::SMESH_Mesh_ptr finalMesh, GEOM::GEOM_Object_ptr theShapeObject )
+{
+  
+  GEOM::GEOM_Object_var aShapeObj;
+  TopoDS_Shape theShape        = StdMeshers_ObjRefUlils::GeomObjectToShape( theShapeObject );
+  SMESH_Mesh_i* theFinalMesh_i = SMESH::DownCast< SMESH_Mesh_i* >( finalMesh );
+  TopoDS_Shape shrinkGeometry;
+  
+  try 
+  {
+    shrinkGeometry = GetImpl()->GetShrinkGeometry( theFinalMesh_i->GetImpl(), theShape );
+  }
+  catch ( std::exception& exc )
+  {
+    std::cout << exc.what() << "\n";
+    THROW_SALOME_CORBA_EXCEPTION( exc.what(), SALOME::INTERNAL_ERROR  );
+    return aShapeObj; // Maybe better to return a init and empty object(?)
+  }
+
+  if ( !shrinkGeometry.IsNull() )
+  {     
+    std::ostringstream streamShape;
+    //Write TopoDS_Shape in ASCII format to the stream
+    BRepTools::Write(shrinkGeometry, streamShape);
+    //Returns the number of bytes that have been stored in the stream's buffer.
+    int size = streamShape.str().size();
+    //Allocate octect buffer of required size
+    CORBA::Octet* OctetBuf = SALOMEDS::TMPFile::allocbuf(size);
+    //Copy ostrstream content to the octect buffer
+    memcpy(OctetBuf, streamShape.str().c_str(), size);
+    //Create and return TMPFile
+    SALOMEDS::TMPFile_var SeqFile = new SALOMEDS::TMPFile(size,size,OctetBuf,1);
+    // Get the geom engine
+    GEOM::GEOM_Gen_var geomEngine = theShapeObject->GetGen();
+    auto iOp                      = geomEngine->GetIInsertOperations();
+    aShapeObj                     = iOp->RestoreShape( SeqFile );
+    geomEngine->AddInStudy( aShapeObj, "Shrink", GEOM::GEOM_Object::_nil());        
+  }
+
+  return aShapeObj;
+}
+
+CORBA::Boolean StdMeshers_ViscousLayerBuilder_i::AddLayers( SMESH::SMESH_Mesh_ptr shrinkMesh, SMESH::SMESH_Mesh_ptr finalMesh, GEOM::GEOM_Object_ptr theShapeObject )
+{
+  TopoDS_Shape theShape         = StdMeshers_ObjRefUlils::GeomObjectToShape( theShapeObject );
+  SMESH_Mesh_i* shrinkMesh_i    = SMESH::DownCast< SMESH_Mesh_i* >( shrinkMesh );
+  SMESH_Mesh_i* theFinalMesh_i  = SMESH::DownCast< SMESH_Mesh_i* >( finalMesh );
+  
+  bool success = GetImpl()->AddLayers( shrinkMesh_i->GetImpl(), theFinalMesh_i->GetImpl(), theShape );  
+  
+  return success;
+}
+//=============================================================================
+/*!
+ *  StdMeshers_ViscousLayerBuilder_i::~StdMeshers_ViscousLayerBuilder_i
+ *
+ *  Destructor
+ */
+//=============================================================================
+StdMeshers_ViscousLayerBuilder_i::~StdMeshers_ViscousLayerBuilder_i()
+{
+}
\ No newline at end of file
diff --git a/src/StdMeshers_I/StdMeshers_ViscousLayerBuilder_i.hxx b/src/StdMeshers_I/StdMeshers_ViscousLayerBuilder_i.hxx
new file mode 100644 (file)
index 0000000..b6957f1
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright (C) 2007-2023  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
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+//  File   : StdMeshers_ViscousLayerBuilder_i.hxx
+//  Module : SMESH
+//
+#ifndef _SMESH_ViscousLayersBuilder_I_HXX_
+#define _SMESH_ViscousLayersBuilder_I_HXX_
+
+#include "SMESH_StdMeshers_I.hxx"
+
+#include <SALOMEconfig.h>
+#include CORBA_SERVER_HEADER(SMESH_BasicHypothesis)
+
+#include "SMESH_2D_Algo_i.hxx"
+#include "SMESH_Hypothesis_i.hxx"
+#include "SMESH_Mesh_i.hxx"
+#include "StdMeshers_ViscousLayerBuilder.hxx"
+#include "StdMeshers_ObjRefUlils.hxx"
+
+class SMESH_Gen;
+
+class STDMESHERS_I_EXPORT StdMeshers_ViscousLayerBuilder_i: 
+  public virtual POA_StdMeshers::StdMeshers_ViscousLayerBuilder,
+  public virtual SMESH_2D_Algo_i
+{
+ public:
+  // Constructor
+  StdMeshers_ViscousLayerBuilder_i( PortableServer::POA_ptr thePOA,
+                                      ::SMESH_Gen*            theGenImpl );
+  // Destructor
+  virtual ~StdMeshers_ViscousLayerBuilder_i();
+
+  // Verify whether algorithm supports given entity type 
+  CORBA::Boolean IsDimSupported( SMESH::Dimension type );
+
+  // Get implementation
+  ::StdMeshers_ViscousLayerBuilder* GetImpl();  
+
+  void SetIgnoreFaces(const ::SMESH::long_array& faceIDs);
+  void SetFaces(const SMESH::long_array& faceIDs,
+                CORBA::Boolean           toIgnore);
+  void SetTotalThickness(::CORBA::Double thickness);
+  void SetNumberLayers(::CORBA::Short nb);
+  void SetStretchFactor(::CORBA::Double factor);
+  void SetMethod( ::StdMeshers::VLExtrusionMethod how );
+  void SetGroupName(const char* name);
+
+  // Compute and return the shrink geometry 
+  GEOM::GEOM_Object_ptr GetShrinkGeometry( SMESH::SMESH_Mesh_ptr finalMesh, GEOM::GEOM_Object_ptr theShapeObject );
+
+  // Build the viscous layer on the specified faces/edges available in the sourceMesh and consolidate the result in the finalMesh
+  CORBA::Boolean AddLayers( SMESH::SMESH_Mesh_ptr sourceMesh, SMESH::SMESH_Mesh_ptr finalMesh, GEOM::GEOM_Object_ptr theShapeObject );
+  
+};
+
+#endif
index 51fdef1a6e184dd1dc017c65ef1214551963bd2a..b22321f16fdcf4f11c224bf48a477e4241579d9c 100644 (file)
@@ -77,6 +77,7 @@
 #include "StdMeshers_UseExisting_1D2D_i.hxx"
 #include "StdMeshers_ViscousLayers2D_i.hxx"
 #include "StdMeshers_ViscousLayers_i.hxx"
+#include "StdMeshers_ViscousLayerBuilder_i.hxx"
 
 namespace SMESH {
   class ApplicableToAny
@@ -206,7 +207,7 @@ STDMESHERS_I_EXPORT
     else if (strcmp(aHypName, "CartesianParameters3D") == 0)
       aCreator = new StdHypothesisCreator_i<StdMeshers_CartesianParameters3D_i>;
     else if (strcmp(aHypName, "BlockRenumber") == 0)
-      aCreator = new StdHypothesisCreator_i<StdMeshers_BlockRenumber_i>;
+      aCreator = new StdHypothesisCreator_i<StdMeshers_BlockRenumber_i>;    
 
     // Algorithms
     else if (strcmp(aHypName, "Regular_1D") == 0)
@@ -248,7 +249,9 @@ STDMESHERS_I_EXPORT
     else if (strcmp(aHypName, "PolygonPerFace_2D") == 0)
       aCreator = new StdHypothesisCreator_i<StdMeshers_PolygonPerFace_2D_i>;
     else if (strcmp(aHypName, "PolyhedronPerSolid_3D") == 0)
-      aCreator = new StdHypothesisCreator_i<StdMeshers_PolyhedronPerSolid_3D_i>;
+      aCreator = new StdHypothesisCreator_i<StdMeshers_PolyhedronPerSolid_3D_i>;    
+    else if (strcmp(aHypName, "ViscousLayerBuilder") == 0)
+      aCreator = new StdHypothesisCreator_i<StdMeshers_ViscousLayerBuilder_i>;
 
     return aCreator;
   }
diff --git a/test/test_vlapi_growthlayer.py b/test/test_vlapi_growthlayer.py
new file mode 100644 (file)
index 0000000..a82afed
--- /dev/null
@@ -0,0 +1,145 @@
+#  -*- coding: iso-8859-1 -*-
+# Copyright (C) 2007-2023  CEA, EDF, OPEN CASCADE
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+import math
+import salome
+salome.salome_init_without_session()
+
+import GEOM
+import SHAPERSTUDY
+from salome.geom import geomBuilder
+from salome.smesh import smeshBuilder
+from salome.shaper import model
+
+def assertAlmostEqual(a,b,tol):
+   if ( abs(a-b) < tol ):
+      return True
+   else:
+      print( "not close vals", a, b ) 
+      return False
+
+
+geompy = geomBuilder.New()
+
+O = geompy.MakeVertex(0, 0, 0)
+OX = geompy.MakeVectorDXDYDZ(1, 0, 0)
+OY = geompy.MakeVectorDXDYDZ(0, 1, 0)
+OZ = geompy.MakeVectorDXDYDZ(0, 0, 1)
+
+# create a disk
+geompy.addToStudy( O, 'O' )
+geompy.addToStudy( OX, 'OX' )
+geompy.addToStudy( OY, 'OY' )
+geompy.addToStudy( OZ, 'OZ' )
+Box = geompy.MakeBox(0,0,0,10,10,10)
+
+smesh_builder = smeshBuilder.New()
+
+MesherBox = smesh_builder.Mesh(Box, "Box")
+viscousBuilder = MesherBox.ViscousLayerBuilder()
+
+#############BOX AND TETRA ELEMENTS
+#Set prismatic layer parameters
+offset = 0.7
+numLayers = 4
+viscousBuilder.setBuilderParameters( offset, numLayers, 1.2, [13], False )
+ShrinkBox = viscousBuilder.GetShrinkGeometry()
+
+#Mesh the shrink box
+MesherShinkBox = smesh_builder.Mesh(ShrinkBox, "ShrinkMesh")
+ShrinkBoxMesh = MesherShinkBox.Tetrahedron(smeshBuilder.NETGEN_1D2D3D)
+
+#Compute 
+success = MesherShinkBox.Compute()
+assert( success )
+assert( MesherShinkBox.NbVolumes() == 5 ) # if Fails! change the default value of volumes when meshing with Netgen!
+
+FinalMesh = viscousBuilder.AddLayers( MesherShinkBox )
+assert( FinalMesh.NbVolumes() == 5 + numLayers * 2 )    # here 2 stands for the number of face elements per face in the box
+assert( FinalMesh.NbFaces() == 6 *  2 + 4 * numLayers ) # here is the number of face elements for the box + the new faces in the VL. (6 is the number of sides in the box)
+
+#Testing the configuration where face 13 is ignored and so the offset is applied to all other faces
+viscousBuilder.setBuilderParameters( offset, numLayers, 1.2, [13], True )
+ShrinkBox2 = viscousBuilder.GetShrinkGeometry()
+#Mesh the shrink box
+MesherShinkBox2 = smesh_builder.Mesh(ShrinkBox2, "ShrinkMesh2")
+ShrinkBoxMesh2 = MesherShinkBox2.Tetrahedron(smeshBuilder.NETGEN_1D2D3D)
+
+#Compute 
+success = MesherShinkBox2.Compute()
+assert( success )
+
+#Test the number of elements on the shrink mesh
+assert( MesherShinkBox2.NbVolumes() == 5 ) # if Fails! change the default (default hypo) number of volumes when meshing with Netgen!
+
+FinalMesh2 = viscousBuilder.AddLayers( MesherShinkBox2 )
+
+assert( FinalMesh2.NbVolumes() == 5 + numLayers * 2 * 5  )   # here 2 stands for the number of face elements per face in the box
+assert( FinalMesh2.NbFaces() == 6 *  2 + 4 * numLayers ) # here is the number of face elements for the box + the new faces in the VL. (6 is the number of sides in the box)
+#############END BOX AND TETRA ELEMENTS
+
+#############MESH SQUARE FACE
+Face = geompy.MakeFaceHW(5, 5, 1)
+Disk = geompy.MakeDiskR(5, 1)
+
+MesherSqr = smesh_builder.Mesh(Face, "Face")
+viscousBuilder = MesherSqr.ViscousLayerBuilder()
+#Set prismatic layer parameters
+offset = 0.5
+numberOfLayers = 6
+viscousBuilder.setBuilderParameters( offset, numberOfLayers, 1.2 )
+ShrinkFace = viscousBuilder.GetShrinkGeometry()
+#Mesh the shrink face
+MesherShinkFace = smesh_builder.Mesh(ShrinkFace, "ShrinkFaceMesh")
+algo = MesherShinkFace.Segment()
+numOfSegments = 4
+algo.NumberOfSegments(numOfSegments)
+ShrinkFaceMesh = MesherShinkFace.Triangle()
+#Compute 
+success = MesherShinkFace.Compute()
+assert( success )
+numFaceElementShrinkGeom = MesherShinkFace.NbFaces()
+FinalFaceMesh = viscousBuilder.AddLayers( MesherShinkFace )
+# Check the number of additional elements
+# numOfSegments * 4 * numberOfLayers
+finalNumOfElements = FinalFaceMesh.NbFaces()
+assert( numFaceElementShrinkGeom + 4 * numOfSegments * numberOfLayers == finalNumOfElements )
+
+#############END MESH SQUARE FACE
+
+#############MESH CIRCULAR FACE
+MesherCircle = smesh_builder.Mesh(Disk, "Disk")
+viscousBuilder = MesherCircle.ViscousLayerBuilder()
+viscousBuilder.setBuilderParameters( offset, numberOfLayers, 1.2 )
+ShrinkCircle = viscousBuilder.GetShrinkGeometry()
+MesherShinkCircle = smesh_builder.Mesh(ShrinkCircle, "ShrinkCircleMesh")
+algo = MesherShinkCircle.Segment()
+numOfSegments = 12
+algo.NumberOfSegments(numOfSegments)
+ShrinkCircleMesh = MesherShinkCircle.Triangle()
+
+#Compute 
+success = MesherShinkCircle.Compute()
+numFaceElementShrinkGeom = MesherShinkCircle.NbFaces()
+assert( success )
+FinalCircleMesh = viscousBuilder.AddLayers( MesherShinkCircle )
+finalNumOfElements = FinalCircleMesh.NbFaces()
+assert( numFaceElementShrinkGeom + numOfSegments * numberOfLayers == finalNumOfElements )
+#############END MESH CIRCULAR FACE
\ No newline at end of file
diff --git a/test/test_vlapi_shrinkgeometry.py b/test/test_vlapi_shrinkgeometry.py
new file mode 100644 (file)
index 0000000..3dccd02
--- /dev/null
@@ -0,0 +1,209 @@
+#  -*- coding: iso-8859-1 -*-
+# Copyright (C) 2007-2023  CEA, EDF, OPEN CASCADE
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+import math
+import salome
+salome.salome_init_without_session()
+
+import GEOM
+import SHAPERSTUDY
+from salome.geom import geomBuilder
+from salome.smesh import smeshBuilder
+from salome.shaper import model
+
+def assertAlmostEqual(a,b,tol):
+   if ( abs(a-b) < tol ):
+      return True
+   else:
+      print( "not close vals", a, b ) 
+      return False
+
+
+geompy = geomBuilder.New()
+
+O = geompy.MakeVertex(0, 0, 0)
+OX = geompy.MakeVectorDXDYDZ(1, 0, 0)
+OY = geompy.MakeVectorDXDYDZ(0, 1, 0)
+OZ = geompy.MakeVectorDXDYDZ(0, 0, 1)
+
+# create a disk
+geompy.addToStudy( O, 'O' )
+geompy.addToStudy( OX, 'OX' )
+geompy.addToStudy( OY, 'OY' )
+geompy.addToStudy( OZ, 'OZ' )
+Box = geompy.MakeBox(0,0,0,10,10,10)
+
+smesh_builder = smeshBuilder.New()
+
+MesherBox = smesh_builder.Mesh(Box, "Box")
+viscousBuilder = MesherBox.ViscousLayerBuilder()
+
+#Set prismatic layer parameters
+offset = 0.1
+
+####SHRINK THE BOX IN ALL DIRECTIONS
+#No list of faces is passed and the isToIgnore flag true by default so the offset if applied to the entire geometry
+viscousBuilder.setBuilderParameters( offset, 4, 1.2 )
+ShrinkBox = viscousBuilder.GetShrinkGeometry()
+
+BoxProperties = geompy.BasicProperties(Box)
+ShrinkBoxProperties = geompy.BasicProperties(ShrinkBox)
+assert( BoxProperties[2] > ShrinkBoxProperties[2] )
+
+assert( assertAlmostEqual( BoxProperties[2], (10.0)**(3.0), 1e-12 ) )
+#The geometry is shrank in all directions
+assert( assertAlmostEqual( ShrinkBoxProperties[2], (10.0-offset*2)**(3), 1e-12 ) ) 
+####END SHRINK THE BOX IN ALL DIRECTIONS
+
+####SHRINK THE BOX EXCEPT FOR ONE FACE
+viscousBuilder = MesherBox.ViscousLayerBuilder()
+selectableFaces = geompy.SubShapeAllSortedCentresIDs(Box, geompy.ShapeType["FACE"])
+# Set face 1 TO BE ignored
+viscousBuilder.setBuilderParameters( offset, 4, 1.2, [ selectableFaces[ 0 ] ], True  ) # Shrink in all faces except face id
+ShrinkBox = viscousBuilder.GetShrinkGeometry()
+ShrinkBoxProperties = geompy.BasicProperties(ShrinkBox)
+selectableShrinkFaces = geompy.SubShapeAllSortedCentresIDs(ShrinkBox, geompy.ShapeType["FACE"])
+assert( assertAlmostEqual( ShrinkBoxProperties[2], (10.0-offset*2)**(2)*(10.0-offset), 1e-12 ) ) 
+####END SHRINK THE BOX EXCEPT FOR ONE FACE
+
+####SHRINK THE BOX IN DIRECTION OF ONLY ONE FACE
+# Set face 1 TO NOT be ignored
+viscousBuilder.setBuilderParameters( offset, 4, 1.2, [ selectableFaces[ 0 ] ], False ) # Shrink only the faceid
+ShrinkBox = viscousBuilder.GetShrinkGeometry()
+ShrinkBoxProperties = geompy.BasicProperties(ShrinkBox)
+assert( assertAlmostEqual( ShrinkBoxProperties[2], (10.0)**(2)*(10.0-offset), 1e-12 ) ) 
+selectableShrinkFaces = geompy.SubShapeAllSortedCentresIDs(ShrinkBox, geompy.ShapeType["FACE"])
+####END SHRINK THE BOX IN DIRECTION OF ONLY ONE FACE
+
+####DO NOT SHRINK THE BOX
+viscousBuilder.setBuilderParameters( offset, 4, 1.2, isElementToIgnore = False )
+ShrinkBox = viscousBuilder.GetShrinkGeometry()
+BoxProperties = geompy.BasicProperties(Box)
+ShrinkBoxProperties = geompy.BasicProperties(ShrinkBox)
+assert( assertAlmostEqual( BoxProperties[2], ShrinkBoxProperties[2], 1e-12) )
+####END DO NOT SHRINK THE BOX
+
+####SHRINK THE ENTIRE SPHERE
+#Test shrinking sphere
+Radius = 10.0
+Sphere = geompy.MakeSphere(0,0,0,Radius)
+MesherSphere = smesh_builder.Mesh(Sphere, "Sphere")
+viscousBuilder = MesherSphere.ViscousLayerBuilder()
+viscousBuilder.setBuilderParameters( offset, 4, 1.2 )
+ShrinkSphere = viscousBuilder.GetShrinkGeometry()
+ShrinkSphereProperties = geompy.BasicProperties(ShrinkSphere)
+assert( ShrinkSphereProperties[2] < 4.0/3.0*math.pi * Radius**3 )
+assert( assertAlmostEqual( ShrinkSphereProperties[2], 4.0/3.0*math.pi*(10.0-offset)**(3), 1e-12 ) ) 
+####END SHRINK THE ENTIRE SPHERE
+
+####SHRINK THE ENTIRE CYLINDER
+#Test shrinking cylinder 
+Cylinder = geompy.MakeCylinderRH(10,30)
+MesherCylinder = smesh_builder.Mesh(Cylinder, "Cylinder")
+viscousBuilder = MesherCylinder.ViscousLayerBuilder()
+viscousBuilder.setBuilderParameters( offset, 4, 1.2 )
+ShrinkCylinder = viscousBuilder.GetShrinkGeometry()
+CylinderProp = geompy.BasicProperties(Cylinder)
+ShirnkCylinderProp = geompy.BasicProperties(ShrinkCylinder)
+
+assert( CylinderProp[2] > ShirnkCylinderProp[2] )
+####END SHRINK THE ENTIRE CYLINDER
+
+####SHRINK THE ENTIRE TUBE
+#Test shrinking tube
+Circle_1 = geompy.MakeCircle(None, None, 20)
+Circle_2 = geompy.MakeCircle(None, None, 10)
+Face_1 = geompy.MakeFaceWires([Circle_1, Circle_2], 1)
+Tube = geompy.MakePrismDXDYDZ(Face_1, 0, 0, 100)
+
+MesherTube = smesh_builder.Mesh(Tube, "Tube")
+viscousBuilder = MesherTube.ViscousLayerBuilder()
+viscousBuilder.setBuilderParameters( offset, 4, 1.2 )
+ShrinkTube = viscousBuilder.GetShrinkGeometry()
+TubeProp = geompy.BasicProperties(Tube)
+ShirnkTubeProp = geompy.BasicProperties(ShrinkTube)
+assert( TubeProp[2] > ShirnkTubeProp[2] )
+####END SHRINK THE ENTIRE TUBE
+
+####SHRINK COMPOUND OBJECT TO GENERATE COMPOUND WITH COMMON FACE
+X     = geompy.MakeVectorDXDYDZ( 1,0,0 )
+O     = geompy.MakeVertex( 100,50,50 )
+plane = geompy.MakePlane( O, X, 200 ) # plane YZ
+lX    = 200
+lYlZ  = 100
+box   = geompy.MakeBoxDXDYDZ(lX,lYlZ,lYlZ)
+sBox  = geompy.MakeHalfPartition( box, plane )
+
+# Generate a uniquebody whit coincident faces
+# 4 left, 34 middle, 50 right
+ignoreFaces = [4,34,50]
+geompy.addToStudy( sBox, "SisterBox" )
+MesherSBox = smesh_builder.Mesh( sBox, "SisterBoxMesh") 
+ViscousBuilder = MesherSBox.ViscousLayerBuilder()
+thickness = 20 
+numberOfLayers = 10
+stretchFactor = 1.5
+ViscousBuilder.setBuilderParameters( thickness, numberOfLayers, stretchFactor, ignoreFaces )
+ShrinkSBox = ViscousBuilder.GetShrinkGeometry()
+SBoxProp = geompy.BasicProperties(sBox)
+ShirnksBoxProp = geompy.BasicProperties(ShrinkSBox)
+assert( assertAlmostEqual(ShirnksBoxProp[2], lX * (lYlZ - 2.0*thickness)**(2.0), 1e-12 ) )
+####END SHRINK COMPOUND OBJECT TO GENERATE COMPUND WITH COMMON FACE
+
+
+####SHRINK COMPOUND OBJECT TO GENERATE TWO DISJOINT SOLIDS
+ignoreFaces = [4,50]
+ViscousBuilder.setBuilderParameters( thickness, numberOfLayers, stretchFactor, ignoreFaces )
+ShrinkSBox2 = ViscousBuilder.GetShrinkGeometry()
+SBoxProp = geompy.BasicProperties(sBox)
+ShirnksBoxProp2 = geompy.BasicProperties(ShrinkSBox2)
+assert( assertAlmostEqual(ShirnksBoxProp2[2], (lX -2.0*thickness) * (lYlZ - 2.0*thickness)**(2.0), 1e-12 ) )
+####END SHRINK COMPOUND OBJECT TO GENERATE TWO DISJOINT SOLIDS
+
+
+######SHRINK SQUARE
+offset = 0.5
+numberOfLayers = 6
+Face = geompy.MakeFaceHW(5, 5, 1)
+MesherSqr = smesh_builder.Mesh(Face, "Face")
+viscousBuilder = MesherSqr.ViscousLayerBuilder()
+viscousBuilder.setBuilderParameters( offset, numberOfLayers, 1.2 )
+ShrinkFace = viscousBuilder.GetShrinkGeometry()
+
+FaceProperties = geompy.BasicProperties(Face)
+ShrinkFaceProperties = geompy.BasicProperties(ShrinkFace)
+#Test smaller face
+assert( ShrinkFaceProperties[1] < FaceProperties[1] )
+assertAlmostEqual( ShrinkFaceProperties[1], (5.0-offset*2.0)**(2.0), 1e-12 )
+######END SHRINK SQUARE
+
+######SHRINK CIRCLE
+Disk = geompy.MakeDiskR(5, 1)
+
+#Test with circle 
+MesherCircle = smesh_builder.Mesh(Disk, "Disk")
+viscousBuilder = MesherCircle.ViscousLayerBuilder()
+viscousBuilder.setBuilderParameters( offset, numberOfLayers, 1.2 )
+ShrinkCircle = viscousBuilder.GetShrinkGeometry()
+FaceProperties = geompy.BasicProperties(Disk)
+ShrinkFaceProperties = geompy.BasicProperties(ShrinkCircle)
+
+assert( ShrinkFaceProperties[1] < FaceProperties[1] )
+######END SHRINK CIRCLE
index 0248899d0bb66724e5311f09e5892ea82859d187..ff3dede4cdf4e43a95241c1ab660cb5023d4f1a4 100644 (file)
@@ -37,6 +37,7 @@ SET(BAD_TESTS
   ex29_refine.py
   ex_MakePolyLine.py
   test_smeshplugins.py
+  test_vlapi_growthlayer.py
   PAL_MESH_041_mesh.py
   PAL_MESH_043_3D.py
   SMESH_BelongToGeom.py
@@ -77,6 +78,7 @@ SET(GOOD_TESTS
   create_penta_biquad.py
   extrusion_penta_biquad.py
   test_polyhedron_per_solid.py
+  test_vlapi_shrinkgeometry.py
 
   ex01_cube2build.py
   ex02_cube2primitive.py