From: cconopoima Date: Mon, 16 Oct 2023 08:37:41 +0000 (+0100) Subject: [bos #38052][EDF](2023-T3) Option to replace polyhedrons by hexahedrons in the body... X-Git-Tag: V9_13_0a1~21^2 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=refs%2Fheads%2Fcce%2F38052Fitting;p=modules%2Fsmesh.git [bos #38052][EDF](2023-T3) Option to replace polyhedrons by hexahedrons in the body frontier based in a predefined volume relation. 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. --- diff --git a/doc/gui/images/cartesian3D_hyp.png b/doc/gui/images/cartesian3D_hyp.png index 9f4c59a03..768150dac 100644 Binary files a/doc/gui/images/cartesian3D_hyp.png and b/doc/gui/images/cartesian3D_hyp.png differ diff --git a/doc/gui/input/cartesian_algo.rst b/doc/gui/input/cartesian_algo.rst index 7cf7695a0..199f30469 100644 --- a/doc/gui/input/cartesian_algo.rst +++ b/doc/gui/input/cartesian_algo.rst @@ -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. diff --git a/idl/SMESH_BasicHypothesis.idl b/idl/SMESH_BasicHypothesis.idl index 8f74876e8..eb46c3c78 100644 --- a/idl/SMESH_BasicHypothesis.idl +++ b/idl/SMESH_BasicHypothesis.idl @@ -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 diff --git a/src/SMDS/SMDS_VolumeTool.cxx b/src/SMDS/SMDS_VolumeTool.cxx index cdf86308c..4475f7a82 100644 --- a/src/SMDS/SMDS_VolumeTool.cxx +++ b/src/SMDS/SMDS_VolumeTool.cxx @@ -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 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 diff --git a/src/SMDS/SMDS_VolumeTool.hxx b/src/SMDS/SMDS_VolumeTool.hxx index f207b8369..56affdd48 100644 --- a/src/SMDS/SMDS_VolumeTool.hxx +++ b/src/SMDS/SMDS_VolumeTool.hxx @@ -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 diff --git a/src/StdMeshers/StdMeshers_CartesianParameters3D.cxx b/src/StdMeshers/StdMeshers_CartesianParameters3D.cxx index 627f5d71f..66256788b 100644 --- a/src/StdMeshers/StdMeshers_CartesianParameters3D.cxx +++ b/src/StdMeshers/StdMeshers_CartesianParameters3D.cxx @@ -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; } diff --git a/src/StdMeshers/StdMeshers_CartesianParameters3D.hxx b/src/StdMeshers/StdMeshers_CartesianParameters3D.hxx index d42b0bfba..a913e830c 100644 --- a/src/StdMeshers/StdMeshers_CartesianParameters3D.hxx +++ b/src/StdMeshers/StdMeshers_CartesianParameters3D.hxx @@ -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 diff --git a/src/StdMeshers/StdMeshers_Cartesian_3D.cxx b/src/StdMeshers/StdMeshers_Cartesian_3D.cxx index 7a172ddd6..afd8d1866 100644 --- a/src/StdMeshers/StdMeshers_Cartesian_3D.cxx +++ b/src/StdMeshers/StdMeshers_Cartesian_3D.cxx @@ -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> splitQuantities; - std::vector > splitNodes; - if ( checkPolyhedronValidity( volDef, splitQuantities, splitNodes ) == 1 ) - { - v = addPolyhedronToMesh( volDef, helper, nodes, volDef->_quantities ); + { + if ( !useQuanta ) + { + // split polyhedrons of with disjoint volumes + std::vector> splitQuantities; + std::vector > 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 ); diff --git a/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.cxx b/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.cxx index 181675278..675f377cc 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.cxx +++ b/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.cxx @@ -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() ); +} diff --git a/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.h b/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.h index 31775e68e..ae2d93476 100644 --- a/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.h +++ b/src/StdMeshersGUI/StdMeshersGUI_CartesianParamCreator.h @@ -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; diff --git a/src/StdMeshersGUI/StdMeshers_msg_en.ts b/src/StdMeshersGUI/StdMeshers_msg_en.ts index 1bc267a67..85a684bc6 100644 --- a/src/StdMeshersGUI/StdMeshers_msg_en.ts +++ b/src/StdMeshersGUI/StdMeshers_msg_en.ts @@ -586,6 +586,14 @@ Consider creating another hypothesis instead of using this one for this mesh/sub USE_THRESHOLD_FOR_INTERNAL_FACES Apply Threshold to Shared / Internal Faces + + SET_QUANTA + Set Quanta + + + QUANTA_VALUE + Quanta Value + AXIS_X Axis X diff --git a/src/StdMeshersGUI/StdMeshers_msg_fr.ts b/src/StdMeshersGUI/StdMeshers_msg_fr.ts index 7f958397d..1558c5476 100644 --- a/src/StdMeshersGUI/StdMeshers_msg_fr.ts +++ b/src/StdMeshersGUI/StdMeshers_msg_fr.ts @@ -562,6 +562,14 @@ Veuillez plutôt créer une autre hypothèse à la place de celle-ci pour ce mai USE_THRESHOLD_FOR_INTERNAL_FACES Appliquer le seuil aux faces partagées/internes + + SET_QUANTA + Utiliser Quanta + + + QUANTA_VALUE + Valeur Quanta + AXIS_X Axe X diff --git a/src/StdMeshers_I/StdMeshers_CartesianParameters3D_i.cxx b/src/StdMeshers_I/StdMeshers_CartesianParameters3D_i.cxx index b549257db..040b39d88 100644 --- a/src/StdMeshers_I/StdMeshers_CartesianParameters3D_i.cxx +++ b/src/StdMeshers_I/StdMeshers_CartesianParameters3D_i.cxx @@ -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 diff --git a/src/StdMeshers_I/StdMeshers_CartesianParameters3D_i.hxx b/src/StdMeshers_I/StdMeshers_CartesianParameters3D_i.hxx index 8da36bc38..7d439d537 100644 --- a/src/StdMeshers_I/StdMeshers_CartesianParameters3D_i.hxx +++ b/src/StdMeshers_I/StdMeshers_CartesianParameters3D_i.hxx @@ -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 index 000000000..553d6f7e5 --- /dev/null +++ b/test/body_fitting_quanta_sphere.py @@ -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() diff --git a/test/tests.set b/test/tests.set index 2462533f5..66a2564f7 100644 --- a/test/tests.set +++ b/test/tests.set @@ -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