Salome HOME
[bos #38052][EDF](2023-T3) Option to replace polyhedrons by hexahedrons in the body... cce/38052Fitting 31/head
authorcconopoima <cesar.conopoima@gmail.com>
Mon, 16 Oct 2023 08:37:41 +0000 (09:37 +0100)
committercconopoima <cesar.conopoima@gmail.com>
Tue, 23 Jan 2024 17:25:57 +0000 (17:25 +0000)
Including quanta option to hypothesis with persistence. Working version w/o support to add faces on the boundary elements.

Intermedial commit.

Intermedial commit.

Adding documentation and test.

Final adjust for conformity with NRT.

16 files changed:
doc/gui/images/cartesian3D_hyp.png
doc/gui/input/cartesian_algo.rst
idl/SMESH_BasicHypothesis.idl
src/SMDS/SMDS_VolumeTool.cxx
src/SMDS/SMDS_VolumeTool.hxx
src/StdMeshers/StdMeshers_CartesianParameters3D.cxx
src/StdMeshers/StdMeshers_CartesianParameters3D.hxx
src/StdMeshers/StdMeshers_Cartesian_3D.cxx
src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.cxx
src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.h
src/StdMeshersGUI/StdMeshers_msg_en.ts
src/StdMeshersGUI/StdMeshers_msg_fr.ts
src/StdMeshers_I/StdMeshers_CartesianParameters3D_i.cxx
src/StdMeshers_I/StdMeshers_CartesianParameters3D_i.hxx
test/body_fitting_quanta_sphere.py [new file with mode: 0644]
test/tests.set

index 9f4c59a033bf1f2081553c72d6c564c2d25db971..768150dac7551773f05a8054f093bfd62782006d 100644 (file)
Binary files a/doc/gui/images/cartesian3D_hyp.png and b/doc/gui/images/cartesian3D_hyp.png differ
index 7cf7695a0afd0b5d1a29709a36678744b2eda6e7..199f30469e7c5a9397163a885936821970222bc4 100644 (file)
@@ -65,6 +65,8 @@ This dialog allows to define
 * **Create Faces** check-box activates creation on mesh faces.
 * **Consider Shared and Internal Faces** check-box activates treatment of faces shared by solids and internal. By default the algorithm considers only outer boundaries of the geometry.
 * **Apply Threshold to Shared / Internal Faces** check-box activates application of **Threshold** to cells cut by shared and internal faces, that can cause appearance of holes inside the mesh.
+* **Set Quanta** check-box activates application of **Quanta Value** to replace **polyhedrons** by hexahedrons at the boundary of the geometry. 
+* **Quanta Value** the relation between the volume of a polyhedrons and the equivalent hexahedron at the solid boundary. When **Set Quanta** is checked, those elements are replaced by hexahedrons if the volume of the polyhedron divided by the equivalente hexahedron is bigger than **Quanta**.  
 * **Definition mode** allows choosing how Cartesian structured grid is defined. Location of nodes along each grid axis is defined individually:
     
        * You can specify the **Coordinates** of grid nodes. **Insert** button inserts a node at **Step** distance (negative or positive) from the selected node. **Delete** button removes the selected node. Double click on a coordinate in the list enables its edition. **Note** that node coordinates are measured along directions of axes that can differ from the directions of the Global Coordinate System.
index 8f74876e835c7d17f49d44c9b40d2b5e927207b0..eb46c3c788bbe3b947224249daf112153538f72e 100644 (file)
@@ -1062,6 +1062,15 @@ module StdMeshers
      */
     void SetToCreateFaces(in boolean toCreate);
     boolean GetToCreateFaces();
+    
+    /*!
+     * Enable creation of mesh faces.
+     */
+    void SetToUseQuanta(in boolean toUseQuanta);
+    boolean GetToUseQuanta();
+
+    void SetQuanta(in double quanta) raises (SALOME::SALOME_Exception);
+    double GetQuanta();
 
     /*!
      * Return axes at which a number of generated hexahedra is maximal
index cdf86308cbc7c91da86adf5eee94ad34598b4231..4475f7a829ecdb484e7f2685aacd85c9ee5d7c34 100644 (file)
@@ -2137,6 +2137,52 @@ bool SMDS_VolumeTool::IsFreeFace( int faceIndex, const SMDS_MeshElement** otherV
   return isFree;
 }
 
+//================================================================================
+/*!
+ * \brief Check that only one volume is built on the face nodes
+ *        Different to IsFreeFace function, all nodes of the face are checked.
+ *        For non conforming meshes, the face that is not conform with the neighbor 
+ *        will be identify as free.
+ */
+//================================================================================
+
+bool SMDS_VolumeTool::IsFreeFaceCheckAllNodes( int faceIndex, const SMDS_MeshElement** otherVol/*=0*/ ) const
+{
+  const bool isFree = true;
+
+  if ( !setFace( faceIndex ))
+    return !isFree;
+
+  const SMDS_MeshNode** nodes = GetFaceNodes( faceIndex );
+
+  const int  di = myVolume->IsQuadratic() ? 2 : 1;
+  const int nbN = myCurFace.myNbNodes/di;
+  std::vector<bool> allNodesCoincideWithNeighbor(nbN,false);
+
+  for (int nodeId = 0; nodeId < nbN; nodeId++)
+  {
+    SMDS_ElemIteratorPtr eIt = nodes[nodeId]->GetInverseElementIterator( SMDSAbs_Volume );
+    int count = 0;
+    while ( eIt->more() )
+    {
+      const SMDS_MeshElement* vol = eIt->next();
+      if ( vol == myVolume )
+        continue;
+      else
+      {
+        count++;
+      }
+    }
+
+    if ( count==0 /*free corner in the face means free face*/)
+    {
+      if ( otherVol ) *otherVol = 0;
+      return true;
+    }
+  }
+  return IsFreeFace( faceIndex, otherVol );
+}
+
 //================================================================================
 /*!
  * \brief Thorough check that only one volume is built on the face nodes
index f207b8369b5869e29d9df0ed671d2747f5481f2b..56affdd48636c854eb3248ecf9586980bf4925f2 100644 (file)
@@ -188,6 +188,12 @@ class SMDS_EXPORT SMDS_VolumeTool
   bool IsFreeFace(  int faceIndex, const SMDS_MeshElement** otherVol=0 ) const;
   // Fast check that only one volume is built on nodes of a given face
   // otherVol returns another volume sharing the given facet
+  // Function works for conforming mesh.
+
+  bool IsFreeFaceCheckAllNodes(  int faceIndex, const SMDS_MeshElement** otherVol=0 ) const;
+  // Check that only one volume is built on nodes of a given face
+  // otherVol returns another volume sharing the given facet
+  // Function to be used on mesh with non conforming elements. The face shared between 
 
   bool IsFreeFaceAdv(  int faceIndex, const SMDS_MeshElement** otherVol=0 ) const;
   // Thorough check that all volumes built on the face nodes lays on one side
index 627f5d71f63b0492cce232bf7f3cdeb303cc4a4a..66256788b7cc1727776f2bccf32f8f2e3c92d129 100644 (file)
@@ -67,7 +67,9 @@ StdMeshers_CartesianParameters3D::StdMeshers_CartesianParameters3D(int         h
     _toAddEdges( false ),
     _toConsiderInternalFaces( false ),
     _toUseThresholdForInternalFaces( false ),
-    _toCreateFaces( false )
+    _toCreateFaces( false ),
+    _toUseQuanta(false),
+    _quanta(0.01)
 {
   _name = "CartesianParameters3D"; // used by "Cartesian_3D"
   _param_algo_dim = 3; // 3D
@@ -774,6 +776,37 @@ void StdMeshers_CartesianParameters3D::SetToCreateFaces(bool toCreate)
   }
 }
 
+//=======================================================================
+//function : SetToUseQuanta
+//purpose  : Enables use of quanta
+//=======================================================================
+
+void StdMeshers_CartesianParameters3D::SetToUseQuanta(bool toUseQuanta)
+{
+  if ( _toUseQuanta != toUseQuanta )
+  {
+    _toUseQuanta = toUseQuanta;
+    NotifySubMeshesHypothesisModification();
+  }
+}
+
+//=======================================================================
+//function : SetQuanta
+//purpose  : Set size quanta value
+//=======================================================================
+
+void StdMeshers_CartesianParameters3D::SetQuanta(const double quanta)
+{
+  if ( quanta < 1e-6 || quanta > 1.0 )
+    throw SALOME_Exception(LOCALIZED("Quanta must be in the range [0.01,1] "));
+
+  bool changed = (_quanta != quanta); 
+  _quanta = quanta;
+  
+  if ( changed )
+    NotifySubMeshesHypothesisModification();
+}
+
 //=======================================================================
 //function : IsDefined
 //purpose  : Return true if parameters are well defined
@@ -823,7 +856,9 @@ std::ostream & StdMeshers_CartesianParameters3D::SaveTo(std::ostream & save)
 
   save << " " << _toConsiderInternalFaces
        << " " << _toUseThresholdForInternalFaces
-       << " " << _toCreateFaces;
+       << " " << _toCreateFaces
+       << " " << _toUseQuanta
+       << " " << _quanta;
 
   return save;
 }
@@ -889,6 +924,9 @@ std::istream & StdMeshers_CartesianParameters3D::LoadFrom(std::istream & load)
     load >> _toCreateFaces;
   }
 
+  if ( load >> _toUseQuanta )
+    load >> _quanta;
+
   return load;
 }
 
index d42b0bfba743f0fc0e9fa21dbc15da8d8892c7a3..a913e830cd4e8c1712a8c2533ced5e21ac9c3cf5 100644 (file)
@@ -157,6 +157,19 @@ public:
   void SetToCreateFaces(bool toCreate);
   bool GetToCreateFaces() const { return _toCreateFaces; }
 
+  /*!
+   * \brief Enables use of quanta for hexahedrons at the solid external boundary
+   */
+  void SetToUseQuanta(bool toUseQuanta);
+  bool GetToUseQuanta() const { return _toUseQuanta; }
+
+  /*!
+   * \brief Value of the quanta (volPolyhedron/volHexahedron) to use
+   * \remark value [0.1, 1.0]
+   */
+  void SetQuanta(const double quanta );
+  double GetQuanta() const { return _quanta; }
+
 
   /*!
    * \brief Return true if parameters are well defined
@@ -193,6 +206,8 @@ public:
   bool   _toConsiderInternalFaces;
   bool   _toUseThresholdForInternalFaces;
   bool   _toCreateFaces;
+  bool   _toUseQuanta;
+  double _quanta;
 };
 
 #endif
index 7a172ddd66d651e9c8397a419bd202e51628a4b2..afd8d1866941b37db9fb61ada70824daec634315 100644 (file)
@@ -469,7 +469,9 @@ namespace
     // index shift within _nodes of nodes of a cell from the 1st node
     int                _nodeShift[8];
 
-    vector< const SMDS_MeshNode* >    _nodes; // mesh nodes at grid nodes
+    vector< const SMDS_MeshNode* >    _nodes;          // mesh nodes at grid nodes
+    vector< const SMDS_MeshNode* >    _allBorderNodes; // mesh nodes between the bounding box and the geometry boundary
+
     vector< const F_IntersectPoint* > _gridIntP; // grid node intersection with geometry
     ObjectPool< E_IntersectPoint >    _edgeIntPool; // intersections with EDGEs
     ObjectPool< F_IntersectPoint >    _extIntPool; // intersections with extended INTERNAL FACEs
@@ -481,6 +483,8 @@ namespace
     bool                              _toConsiderInternalFaces;
     bool                              _toUseThresholdForInternalFaces;
     double                            _sizeThreshold;
+    bool                              _toUseQuanta;
+    double                            _quanta;
 
     SMESH_MesherHelper*               _helper;
 
@@ -691,7 +695,8 @@ namespace
     // --------------------------------------------------------------------------------
     struct _Node //!< node either at a hexahedron corner or at intersection
     {
-      const SMDS_MeshNode*    _node; // mesh node at hexahedron corner
+      const SMDS_MeshNode*    _node;        // mesh node at hexahedron corner
+      const SMDS_MeshNode*    _boundaryCornerNode; // missing mesh node due to hex truncation on the boundary
       const B_IntersectPoint* _intPoint;
       const _Face*            _usedInFace;
       char                    _isInternalFlags;
@@ -700,6 +705,8 @@ namespace
         :_node(n), _intPoint(ip), _usedInFace(0), _isInternalFlags(0) {} 
       const SMDS_MeshNode*    Node() const
       { return ( _intPoint && _intPoint->_node ) ? _intPoint->_node : _node; }
+      const SMDS_MeshNode*    BoundaryNode() const
+      { return _node ? _node : _boundaryCornerNode; }
       const E_IntersectPoint* EdgeIntPnt() const
       { return static_cast< const E_IntersectPoint* >( _intPoint ); }
       const F_IntersectPoint* FaceIntPnt() const
@@ -1882,6 +1889,7 @@ namespace
     const size_t nbGridNodes = _coords[0].size() * _coords[1].size() * _coords[2].size();
     vector< TGeomID > shapeIDVec( nbGridNodes, theUndefID );
     _nodes.resize( nbGridNodes, 0 );
+    _allBorderNodes.resize( nbGridNodes, 0 );
     _gridIntP.resize( nbGridNodes, NULL );
 
     SMESHDS_Mesh* mesh = helper.GetMeshDS();
@@ -1932,10 +1940,11 @@ namespace
               if ( ++nodeCoord <  coordEnd )
                 nodeParam = *nodeCoord - *coord0;
               else
-                break;
+                break;                
             }
             if ( nodeCoord == coordEnd ) break;
           }
+          
           // create a mesh node on a GridLine at ip if it does not coincide with a grid node
           if ( nodeParam > ip->_paramOnLine + _tol )
           {
@@ -1996,6 +2005,14 @@ namespace
             SetOnShape( _nodes[ nodeIndex ], *_gridIntP[ nodeIndex ], & v );
             UpdateFacesOfVertex( *_gridIntP[ nodeIndex ], v );
           }
+          else if ( _toUseQuanta && !_allBorderNodes[ nodeIndex ] /*add all nodes outside the body. Used to reconstruct the hexahedrals when polys are not desired!*/)
+          {
+            gp_XYZ xyz = ( _coords[0][x] * _axes[0] +
+                           _coords[1][y] * _axes[1] +
+                           _coords[2][z] * _axes[2] );
+            _allBorderNodes[ nodeIndex ] = mesh->AddNode( xyz.X(), xyz.Y(), xyz.Z() );
+            mesh->SetNodeInVolume( _allBorderNodes[ nodeIndex ], shapeIDVec[ nodeIndex ]);
+          }
         }
 
 #ifdef _MY_DEBUG_
@@ -2668,11 +2685,16 @@ namespace
     {
       _hexNodes[iN]._isInternalFlags = 0;
 
+      // Grid  node 
       _hexNodes[iN]._node     = _grid->_nodes   [ _origNodeInd + _grid->_nodeShift[iN] ];
       _hexNodes[iN]._intPoint = _grid->_gridIntP[ _origNodeInd + _grid->_nodeShift[iN] ];
 
+      if ( _grid->_allBorderNodes[ _origNodeInd + _grid->_nodeShift[iN] ] ) 
+        _hexNodes[iN]._boundaryCornerNode = _grid->_allBorderNodes [ _origNodeInd + _grid->_nodeShift[iN] ];
+      
       if ( _hexNodes[iN]._node && !solid->Contains( _hexNodes[iN]._node->GetShapeID() ))
         _hexNodes[iN]._node = 0;
+
       if ( _hexNodes[iN]._intPoint && !solid->ContainsAny( _hexNodes[iN]._intPoint->_faceIDs ))
         _hexNodes[iN]._intPoint = 0;
 
@@ -4808,6 +4830,7 @@ namespace
   {
     F_IntersectPoint noIntPnt;
     const bool toCheckNodePos = _grid->IsToCheckNodePos();
+    const bool useQuanta      = _grid->_toUseQuanta;
 
     int nbAdded = 0;
     // add elements resulted from hexahedron intersection
@@ -4854,28 +4877,40 @@ namespace
         }
       } // loop to get nodes
 
-      const SMDS_MeshElement* v = 0;
-      
+      const SMDS_MeshElement* v = 0;      
       if ( !volDef->_quantities.empty() )
-      {      
-        // split polyhedrons of with disjoint volumes
-        std::vector<std::vector<int>> splitQuantities;
-        std::vector<std::vector< const SMDS_MeshNode* > > splitNodes;
-        if ( checkPolyhedronValidity( volDef, splitQuantities, splitNodes ) == 1 )
-        {
-          v = addPolyhedronToMesh( volDef, helper, nodes, volDef->_quantities );
+      {                      
+        if ( !useQuanta )
+        {
+          // split polyhedrons of with disjoint volumes
+          std::vector<std::vector<int>> splitQuantities;
+          std::vector<std::vector< const SMDS_MeshNode* > > splitNodes;
+          if ( checkPolyhedronValidity( volDef, splitQuantities, splitNodes ) == 1 )
+            v = addPolyhedronToMesh( volDef, helper, nodes, volDef->_quantities );
+          else
+          {
+            int counter = -1;
+            for (size_t id = 0; id < splitQuantities.size(); id++)
+            {
+              v = addPolyhedronToMesh( volDef, helper, splitNodes[ id ], splitQuantities[ id ] );
+              if ( id < splitQuantities.size()-1 )
+                volDef->_brotherVolume.push_back( v );
+              counter++;
+            }
+            nbAdded += counter;
+          }
         }
         else
         {
-          int counter = -1;
-          for (size_t id = 0; id < splitQuantities.size(); id++)
-          {
-            v = addPolyhedronToMesh( volDef, helper, splitNodes[ id ], splitQuantities[ id ] );
-            if ( id < splitQuantities.size()-1 )
-              volDef->_brotherVolume.push_back( v );
-            counter++;
-          }
-          nbAdded += counter;
+          const double quanta = _grid->_quanta;
+          double polyVol      = volDef->_size;
+          double hexaVolume   = _sideLength[0] * _sideLength[1] * _sideLength[2];          
+          if ( hexaVolume > 0.0 && polyVol/hexaVolume >= quanta /*set the volume if the relation is satisfied*/)
+            v = helper.AddVolume( _hexNodes[0].BoundaryNode(), _hexNodes[2].BoundaryNode(),
+                                  _hexNodes[3].BoundaryNode(), _hexNodes[1].BoundaryNode(),
+                                  _hexNodes[4].BoundaryNode(), _hexNodes[6].BoundaryNode(),
+                                  _hexNodes[7].BoundaryNode(), _hexNodes[5].BoundaryNode() );
+          
         }
       }
       else
@@ -4945,6 +4980,8 @@ namespace
   //================================================================================
   /*!
    * \brief Return true if the element is in a hole
+   * \remark consider a cell to be in a hole if all links in any direction
+   *          comes OUT of geometry
    */
   bool Hexahedron::isInHole() const
   {
@@ -5695,25 +5732,24 @@ namespace
     SMESH_MeshEditor::ElemFeatures face( SMDSAbs_Face );
     SMESHDS_Mesh* meshDS = helper.GetMeshDS();
 
+    bool isQuantaSet =  _grid->_toUseQuanta;    
     // check if there are internal or shared FACEs
     bool hasInternal = ( !_grid->_geometry.IsOneSolid() ||
-                         _grid->_geometry._soleSolid.HasInternalFaces() );
+                         _grid->_geometry._soleSolid.HasInternalFaces() );   
 
     for ( size_t iV = 0; iV < boundaryVolumes.size(); ++iV )
     {
       if ( !vTool.Set( boundaryVolumes[ iV ]))
         continue;
-
       TGeomID solidID = vTool.Element()->GetShapeID();
       Solid *   solid = _grid->GetOneOfSolids( solidID );
 
       // find boundary facets
-
       bndFacets.clear();
       for ( int iF = 0, n = vTool.NbFaces(); iF < n; iF++ )
       {
         const SMDS_MeshElement* otherVol;
-        bool isBoundary = vTool.IsFreeFace( iF, &otherVol );
+        bool isBoundary = isQuantaSet ? vTool.IsFreeFaceCheckAllNodes( iF, &otherVol ) : vTool.IsFreeFace( iF, &otherVol );
         if ( isBoundary )
         {
           bndFacets.push_back( iF );
@@ -5735,7 +5771,6 @@ namespace
         continue;
 
       // create faces
-
       if ( !vTool.IsPoly() )
         vTool.SetExternalNormal();
       for ( size_t i = 0; i < bndFacets.size(); ++i ) // loop on boundary facets
@@ -5763,7 +5798,7 @@ namespace
             if ( nn[ iN ]->GetPosition()->GetDim() == 2 )
               faceID = nn[ iN ]->GetShapeID();
           }
-          if ( faceID == 0 )
+          if ( faceID == 0 && !isQuantaSet /*if quanta is set boundary nodes at boundary does not coincide with any geometrical face */ )
             faceID = findCommonFace( face.myNodes, helper.GetMesh() );
 
           bool toCheckFace = faceID && (( !isBoundary ) ||
@@ -5780,7 +5815,7 @@ namespace
             // if ( !faceID && !isBoundary )
             //   continue;
           }
-          if ( !faceID && !isBoundary )
+          if ( !faceID && !isBoundary && !isQuantaSet )
             continue;
         }
 
@@ -6625,6 +6660,8 @@ bool StdMeshers_Cartesian_3D::Compute(SMESH_Mesh &         theMesh,
     grid._toConsiderInternalFaces        = _hyp->GetToConsiderInternalFaces();
     grid._toUseThresholdForInternalFaces = _hyp->GetToUseThresholdForInternalFaces();
     grid._sizeThreshold                  = _hyp->GetSizeThreshold();
+    grid._toUseQuanta                    = _hyp->GetToUseQuanta();
+    grid._quanta                         = _hyp->GetQuanta();
     if ( _isComputeOffset )
     {
       grid._toAddEdges = true;
@@ -6763,6 +6800,15 @@ bool StdMeshers_Cartesian_3D::Compute(SMESH_Mesh &         theMesh,
           grid._nodes[i]->setIsMarked( true );
         }
 
+      for ( size_t i = 0; i < grid._allBorderNodes.size(); ++i )
+        if ( grid._allBorderNodes[i] &&
+             !grid._allBorderNodes[i]->IsNull() &&
+             grid._allBorderNodes[i]->NbInverseElements() == 0 )
+        {
+          nodesToRemove.push_back( grid._allBorderNodes[i] );
+          grid._allBorderNodes[i]->setIsMarked( true );
+        }
+
       // do remove
       for ( size_t i = 0; i < nodesToRemove.size(); ++i )
         meshDS->RemoveFreeNode( nodesToRemove[i], /*smD=*/0, /*fromGroups=*/false );
index 1816752784a6ad77e014a63e29dc022ec612e0b6..675f377cc33731d1b1272bb541ef1794ce8ffa4f 100644 (file)
@@ -830,6 +830,17 @@ QFrame* StdMeshersGUI_CartesianParamCreator::buildFrame()
   myUseThresholdForInternalFaces = new QCheckBox( tr("USE_THRESHOLD_FOR_INTERNAL_FACES"), GroupC1 );
   argGroupLayout->addWidget( myUseThresholdForInternalFaces, row, 0, 1, 2 );
   row++;
+  mySetQuanta = new QCheckBox( tr("SET_QUANTA"), GroupC1 );
+  argGroupLayout->addWidget( mySetQuanta, row, 0, 1, 2 );
+  row++;
+
+  argGroupLayout->addWidget( new QLabel( tr("QUANTA_VALUE"), GroupC1 ), row, 0 );
+  myQuanta = new SMESHGUI_SpinBox( GroupC1 );
+  myQuanta->setAcceptNames( false );
+  myQuanta->RangeStepAndValidator( 1e-6, 1, 0.05, "length_precision" );
+  myQuanta->setEnabled(false);
+  argGroupLayout->addWidget( myQuanta, row, 1 );  
+  row++;
 
   // 3)  Grid definition
   QTabWidget* tabWdg = new QTabWidget( fr );
@@ -935,6 +946,7 @@ QFrame* StdMeshersGUI_CartesianParamCreator::buildFrame()
   connect( resetBtn,        SIGNAL( clicked(bool)),             SLOT( onResetAxes(bool)));
   connect( myConsiderInternalFaces,      SIGNAL( toggled(bool)),
            myUseThresholdForInternalFaces, SLOT( setEnabled(bool)));
+  connect( mySetQuanta,     SIGNAL( clicked(bool)), SLOT( onSetQuanta(bool)) );
   for ( int i = 0; i < 3; ++i )
   {
     connect( myXDirSpin[i], SIGNAL(valueChanged   (const QString&)),
@@ -1011,6 +1023,10 @@ void StdMeshersGUI_CartesianParamCreator::retrieveParams() const
   myCreateFaces->setChecked( h->GetToCreateFaces() );
   myConsiderInternalFaces->setChecked( h->GetToConsiderInternalFaces() );
   myUseThresholdForInternalFaces->setChecked( h->GetToUseThresholdForInternalFaces() );
+  mySetQuanta->setChecked( h->GetToUseQuanta() );
+  myQuanta->setValue( h->GetQuanta() );
+  if (h->GetToUseQuanta())
+    myQuanta->setEnabled(true);
 
   // grid definition
   for ( int ax = 0; ax < 3; ++ax )
@@ -1101,6 +1117,8 @@ QString StdMeshersGUI_CartesianParamCreator::storeParams() const
     h->SetToCreateFaces( myCreateFaces->isChecked() );
     h->SetToConsiderInternalFaces( myConsiderInternalFaces->isChecked() );
     h->SetToUseThresholdForInternalFaces( myUseThresholdForInternalFaces->isChecked() );
+    h->SetToUseQuanta( mySetQuanta->isChecked() );
+    h->SetQuanta( myQuanta->text().toDouble() );
 
     // grid
     for ( int ax = 0; ax < 3; ++ax )
@@ -1453,3 +1471,19 @@ void StdMeshersGUI_CartesianParamCreator::onGridModeChanged(int)
 
   myFixedPointGrp->setEnabled( haveSpacing );
 }
+
+//================================================================================
+/*!
+ * \brief Enable and disable quanta value combo box 
+ */
+//================================================================================
+
+void StdMeshersGUI_CartesianParamCreator::onSetQuanta(bool)
+{
+  StdMeshers::StdMeshers_CartesianParameters3D_var h =
+    StdMeshers::StdMeshers_CartesianParameters3D::_narrow( hypothesis() );
+  if ( h->_is_nil() )
+    return;
+
+  myQuanta->setEnabled( mySetQuanta->isChecked() );
+}
index 31775e68e87a2167b173935a37c4baffb58112bb..ae2d934764ae985aeceb247b4d1110ddaa49a119 100644 (file)
@@ -147,6 +147,7 @@ private slots:
   void             onOptimalAxes(bool);
   void             onResetAxes(bool);
   void             onGridModeChanged(int);
+  void             onSetQuanta(bool);
 
 private:
   QLineEdit*                  myName;
@@ -155,6 +156,8 @@ private:
   QCheckBox*                  myCreateFaces;
   QCheckBox*                  myConsiderInternalFaces;
   QCheckBox*                  myUseThresholdForInternalFaces;
+  QCheckBox*                  mySetQuanta;
+  SMESHGUI_SpinBox*           myQuanta;
 
   StdMeshersGUI::GridAxisTab* myAxisTabs[3];
   QGroupBox*                  myFixedPointGrp;
index 1bc267a678baf755a93ddda786c4664398237706..85a684bc6ea978614d8fe4e35aded752610a456b 100644 (file)
@@ -586,6 +586,14 @@ Consider creating another hypothesis instead of using this one for this mesh/sub
         <source>USE_THRESHOLD_FOR_INTERNAL_FACES</source>
         <translation>Apply Threshold to Shared / Internal Faces</translation>
     </message>
+    <message>
+        <source>SET_QUANTA</source>
+        <translation>Set Quanta</translation>
+    </message>
+    <message>
+        <source>QUANTA_VALUE</source>
+        <translation>Quanta Value</translation>
+    </message>
     <message>
         <source>AXIS_X</source>
         <translation>Axis X</translation>
index 7f958397d7b596bc5af37845146472b20fc5287d..1558c5476399904b9b793279d976c09afc98a556 100644 (file)
@@ -562,6 +562,14 @@ Veuillez plutôt créer une autre hypothèse à la place de celle-ci pour ce mai
         <source>USE_THRESHOLD_FOR_INTERNAL_FACES</source>
         <translation>Appliquer le seuil aux faces partagées/internes</translation>
     </message>
+    <message>
+        <source>SET_QUANTA</source>
+        <translation>Utiliser Quanta</translation>
+    </message>
+    <message>
+        <source>QUANTA_VALUE</source>
+        <translation>Valeur Quanta</translation>
+    </message>
     <message>
         <source>AXIS_X</source>
         <translation>Axe X</translation>
index b549257db270a3061a753faaec0ebaae16ff4635..040b39d88e26205680682c7dc06e5ee441e66844 100644 (file)
@@ -418,6 +418,63 @@ CORBA::Boolean StdMeshers_CartesianParameters3D_i::GetToCreateFaces()
   return GetImpl()->GetToCreateFaces();
 }
 
+
+//=======================================================================
+//function : SetToUseQuanta
+//purpose  : Enables use of quanta value.
+//=======================================================================
+
+void  StdMeshers_CartesianParameters3D_i::SetToUseQuanta(CORBA::Boolean toUseQuanta)
+{
+  if ( GetToUseQuanta() == toUseQuanta )
+    return;
+  GetImpl()->SetToUseQuanta( toUseQuanta );
+  SMESH::TPythonDump() << _this() << ".SetToUseQuanta( " << toUseQuanta << " )";
+}
+
+//=======================================================================
+//function : GetToUseQuanta
+//purpose  : Check the value of toUseQuanta option
+//=======================================================================
+
+CORBA::Boolean StdMeshers_CartesianParameters3D_i::GetToUseQuanta()
+{
+  return GetImpl()->GetToUseQuanta();
+}
+
+//=============================================================================
+/*!
+ *  SetQuanta
+ */
+//=============================================================================
+
+void StdMeshers_CartesianParameters3D_i::SetQuanta(CORBA::Double quanta)
+  
+{
+  ASSERT( myBaseImpl );
+  try {
+    this->GetImpl()->SetQuanta(quanta);
+  }
+  catch ( SALOME_Exception& S_ex ) {
+    THROW_SALOME_CORBA_EXCEPTION( S_ex.what(), SALOME::BAD_PARAM );
+  }
+
+  if ( GetToUseQuanta() )
+    // Update Python script
+    SMESH::TPythonDump() << _this() << ".SetQuanta( " << SMESH::TVar(quanta) << " )";
+}
+
+//=============================================================================
+/*!
+ *  GetQuanta
+ */
+//=============================================================================
+
+CORBA::Double StdMeshers_CartesianParameters3D_i::GetQuanta()
+{
+  return this->GetImpl()->GetQuanta();
+}
+
 //=======================================================================
 //function : IsGridBySpacing
 //purpose  : Return true if the grid is defined by spacing functions and
index 8da36bc38171440c6d4577d8999a420690bc67bd..7d439d537c31c2b4cb91539daabd2cf00484bfea 100644 (file)
@@ -125,6 +125,17 @@ class STDMESHERS_I_EXPORT StdMeshers_CartesianParameters3D_i:
   void SetToCreateFaces(CORBA::Boolean toCreate);
   CORBA::Boolean GetToCreateFaces();
 
+  /*!
+   * Set quanta option to allow replace polyhedrons by hexahedrons
+   */
+  void SetToUseQuanta(CORBA::Boolean toUseQuanta);
+  CORBA::Boolean GetToUseQuanta();
+
+  /*!
+   * Define the quanta value
+   */
+  void SetQuanta(CORBA::Double quanta);
+  CORBA::Double GetQuanta();
 
   /*!
    * \brief Return true if the grid is defined by spacing functions and
diff --git a/test/body_fitting_quanta_sphere.py b/test/body_fitting_quanta_sphere.py
new file mode 100644 (file)
index 0000000..553d6f7
--- /dev/null
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+
+import salome
+salome.salome_init()
+import GEOM
+from salome.geom import geomBuilder
+geompy = geomBuilder.New()
+
+import SMESH, SALOMEDS
+from salome.smesh import smeshBuilder
+smesh =  smeshBuilder.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)
+Sphere_1 = geompy.MakeSphereR(100)
+geompy.addToStudy( O, 'O' )
+geompy.addToStudy( OX, 'OX' )
+geompy.addToStudy( OY, 'OY' )
+geompy.addToStudy( OZ, 'OZ' )
+geompy.addToStudy( Sphere_1, 'Sphere_1' )
+
+Mesh_1 = smesh.Mesh(Sphere_1,'Mesh_1')
+Cartesian_3D = Mesh_1.BodyFitted()
+Body_Fitting_Parameters_1 = Cartesian_3D.SetGrid([ [ '34.641' ], [ 0, 1 ]],[ [ '34.641' ], [ 0, 1 ]],[ [ '34.641' ], [ 0, 1 ]],4,0)
+Body_Fitting_Parameters_1.SetToUseQuanta( 1 )
+Body_Fitting_Parameters_1.SetQuanta( 0.8 )
+isDone = Mesh_1.Compute()
+
+Polys   = Mesh_1.NbPolyhedrons()
+Hexas1  = Mesh_1.NbHexas()
+
+#No polyhedrons in the mesh
+assert(Polys==0)
+
+Body_Fitting_Parameters_1.SetQuanta( 0.2 )
+isDone = Mesh_1.Compute()
+
+Polys   = Mesh_1.NbPolyhedrons()
+Hexas2  = Mesh_1.NbHexas()
+
+#Still no polyhedrons in the mesh
+assert(Polys==0)
+
+#Numher of hexahedrons is bigger for hexas2 becuase quanta value is smaller
+assert( Hexas1 < Hexas2 )
+
+if salome.sg.hasDesktop():
+  salome.sg.updateObjBrowser()
index 2462533f5b92e2c064d3a0885c269f1709e6e067..66a2564f745fcdd96a9ad630e1f86b8c1a68850a 100644 (file)
@@ -32,6 +32,7 @@ SET(BAD_TESTS
   blocFissure_07_without_session.py
   body_fitting_viscous_layer_cylinder.py
   body_fitting_viscous_layer_tpipe.py
+  body_fitting_quanta_sphere.py
   ex04_cube5tetraHexa.py
   ex21_lamp.py
   ex29_refine.py