[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.
This commit is contained in:
cconopoima 2023-10-16 09:37:41 +01:00
parent 3b570ddfbe
commit 9a170f0e1e
16 changed files with 363 additions and 29 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 174 KiB

View File

@ -65,6 +65,8 @@ This dialog allows to define
* **Create Faces** check-box activates creation on mesh faces. * **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. * **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. * **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: * **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. * 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.

View File

@ -1063,6 +1063,15 @@ module StdMeshers
void SetToCreateFaces(in boolean toCreate); void SetToCreateFaces(in boolean toCreate);
boolean GetToCreateFaces(); 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 * Return axes at which a number of generated hexahedra is maximal
*/ */

View File

@ -2137,6 +2137,52 @@ bool SMDS_VolumeTool::IsFreeFace( int faceIndex, const SMDS_MeshElement** otherV
return isFree; 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 * \brief Thorough check that only one volume is built on the face nodes

View File

@ -188,6 +188,12 @@ class SMDS_EXPORT SMDS_VolumeTool
bool IsFreeFace( int faceIndex, const SMDS_MeshElement** otherVol=0 ) const; bool IsFreeFace( int faceIndex, const SMDS_MeshElement** otherVol=0 ) const;
// Fast check that only one volume is built on nodes of a given face // Fast check that only one volume is built on nodes of a given face
// otherVol returns another volume sharing the given facet // 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; bool IsFreeFaceAdv( int faceIndex, const SMDS_MeshElement** otherVol=0 ) const;
// Thorough check that all volumes built on the face nodes lays on one side // Thorough check that all volumes built on the face nodes lays on one side

View File

@ -67,7 +67,9 @@ StdMeshers_CartesianParameters3D::StdMeshers_CartesianParameters3D(int h
_toAddEdges( false ), _toAddEdges( false ),
_toConsiderInternalFaces( false ), _toConsiderInternalFaces( false ),
_toUseThresholdForInternalFaces( false ), _toUseThresholdForInternalFaces( false ),
_toCreateFaces( false ) _toCreateFaces( false ),
_toUseQuanta(false),
_quanta(0.01)
{ {
_name = "CartesianParameters3D"; // used by "Cartesian_3D" _name = "CartesianParameters3D"; // used by "Cartesian_3D"
_param_algo_dim = 3; // 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 //function : IsDefined
//purpose : Return true if parameters are well defined //purpose : Return true if parameters are well defined
@ -823,7 +856,9 @@ std::ostream & StdMeshers_CartesianParameters3D::SaveTo(std::ostream & save)
save << " " << _toConsiderInternalFaces save << " " << _toConsiderInternalFaces
<< " " << _toUseThresholdForInternalFaces << " " << _toUseThresholdForInternalFaces
<< " " << _toCreateFaces; << " " << _toCreateFaces
<< " " << _toUseQuanta
<< " " << _quanta;
return save; return save;
} }
@ -889,6 +924,9 @@ std::istream & StdMeshers_CartesianParameters3D::LoadFrom(std::istream & load)
load >> _toCreateFaces; load >> _toCreateFaces;
} }
if ( load >> _toUseQuanta )
load >> _quanta;
return load; return load;
} }

View File

@ -157,6 +157,19 @@ public:
void SetToCreateFaces(bool toCreate); void SetToCreateFaces(bool toCreate);
bool GetToCreateFaces() const { return _toCreateFaces; } 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 * \brief Return true if parameters are well defined
@ -193,6 +206,8 @@ public:
bool _toConsiderInternalFaces; bool _toConsiderInternalFaces;
bool _toUseThresholdForInternalFaces; bool _toUseThresholdForInternalFaces;
bool _toCreateFaces; bool _toCreateFaces;
bool _toUseQuanta;
double _quanta;
}; };
#endif #endif

View File

@ -470,6 +470,8 @@ namespace
int _nodeShift[8]; 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 vector< const F_IntersectPoint* > _gridIntP; // grid node intersection with geometry
ObjectPool< E_IntersectPoint > _edgeIntPool; // intersections with EDGEs ObjectPool< E_IntersectPoint > _edgeIntPool; // intersections with EDGEs
ObjectPool< F_IntersectPoint > _extIntPool; // intersections with extended INTERNAL FACEs ObjectPool< F_IntersectPoint > _extIntPool; // intersections with extended INTERNAL FACEs
@ -481,6 +483,8 @@ namespace
bool _toConsiderInternalFaces; bool _toConsiderInternalFaces;
bool _toUseThresholdForInternalFaces; bool _toUseThresholdForInternalFaces;
double _sizeThreshold; double _sizeThreshold;
bool _toUseQuanta;
double _quanta;
SMESH_MesherHelper* _helper; SMESH_MesherHelper* _helper;
@ -692,6 +696,7 @@ namespace
struct _Node //!< node either at a hexahedron corner or at intersection 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 B_IntersectPoint* _intPoint;
const _Face* _usedInFace; const _Face* _usedInFace;
char _isInternalFlags; char _isInternalFlags;
@ -700,6 +705,8 @@ namespace
:_node(n), _intPoint(ip), _usedInFace(0), _isInternalFlags(0) {} :_node(n), _intPoint(ip), _usedInFace(0), _isInternalFlags(0) {}
const SMDS_MeshNode* Node() const const SMDS_MeshNode* Node() const
{ return ( _intPoint && _intPoint->_node ) ? _intPoint->_node : _node; } { return ( _intPoint && _intPoint->_node ) ? _intPoint->_node : _node; }
const SMDS_MeshNode* BoundaryNode() const
{ return _node ? _node : _boundaryCornerNode; }
const E_IntersectPoint* EdgeIntPnt() const const E_IntersectPoint* EdgeIntPnt() const
{ return static_cast< const E_IntersectPoint* >( _intPoint ); } { return static_cast< const E_IntersectPoint* >( _intPoint ); }
const F_IntersectPoint* FaceIntPnt() const const F_IntersectPoint* FaceIntPnt() const
@ -1882,6 +1889,7 @@ namespace
const size_t nbGridNodes = _coords[0].size() * _coords[1].size() * _coords[2].size(); const size_t nbGridNodes = _coords[0].size() * _coords[1].size() * _coords[2].size();
vector< TGeomID > shapeIDVec( nbGridNodes, theUndefID ); vector< TGeomID > shapeIDVec( nbGridNodes, theUndefID );
_nodes.resize( nbGridNodes, 0 ); _nodes.resize( nbGridNodes, 0 );
_allBorderNodes.resize( nbGridNodes, 0 );
_gridIntP.resize( nbGridNodes, NULL ); _gridIntP.resize( nbGridNodes, NULL );
SMESHDS_Mesh* mesh = helper.GetMeshDS(); SMESHDS_Mesh* mesh = helper.GetMeshDS();
@ -1936,6 +1944,7 @@ namespace
} }
if ( nodeCoord == coordEnd ) break; if ( nodeCoord == coordEnd ) break;
} }
// create a mesh node on a GridLine at ip if it does not coincide with a grid node // create a mesh node on a GridLine at ip if it does not coincide with a grid node
if ( nodeParam > ip->_paramOnLine + _tol ) if ( nodeParam > ip->_paramOnLine + _tol )
{ {
@ -1996,6 +2005,14 @@ namespace
SetOnShape( _nodes[ nodeIndex ], *_gridIntP[ nodeIndex ], & v ); SetOnShape( _nodes[ nodeIndex ], *_gridIntP[ nodeIndex ], & v );
UpdateFacesOfVertex( *_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_ #ifdef _MY_DEBUG_
@ -2668,11 +2685,16 @@ namespace
{ {
_hexNodes[iN]._isInternalFlags = 0; _hexNodes[iN]._isInternalFlags = 0;
// Grid node
_hexNodes[iN]._node = _grid->_nodes [ _origNodeInd + _grid->_nodeShift[iN] ]; _hexNodes[iN]._node = _grid->_nodes [ _origNodeInd + _grid->_nodeShift[iN] ];
_hexNodes[iN]._intPoint = _grid->_gridIntP[ _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() )) if ( _hexNodes[iN]._node && !solid->Contains( _hexNodes[iN]._node->GetShapeID() ))
_hexNodes[iN]._node = 0; _hexNodes[iN]._node = 0;
if ( _hexNodes[iN]._intPoint && !solid->ContainsAny( _hexNodes[iN]._intPoint->_faceIDs )) if ( _hexNodes[iN]._intPoint && !solid->ContainsAny( _hexNodes[iN]._intPoint->_faceIDs ))
_hexNodes[iN]._intPoint = 0; _hexNodes[iN]._intPoint = 0;
@ -4808,6 +4830,7 @@ namespace
{ {
F_IntersectPoint noIntPnt; F_IntersectPoint noIntPnt;
const bool toCheckNodePos = _grid->IsToCheckNodePos(); const bool toCheckNodePos = _grid->IsToCheckNodePos();
const bool useQuanta = _grid->_toUseQuanta;
int nbAdded = 0; int nbAdded = 0;
// add elements resulted from hexahedron intersection // add elements resulted from hexahedron intersection
@ -4855,16 +4878,15 @@ namespace
} // loop to get nodes } // loop to get nodes
const SMDS_MeshElement* v = 0; const SMDS_MeshElement* v = 0;
if ( !volDef->_quantities.empty() ) if ( !volDef->_quantities.empty() )
{
if ( !useQuanta )
{ {
// split polyhedrons of with disjoint volumes // split polyhedrons of with disjoint volumes
std::vector<std::vector<int>> splitQuantities; std::vector<std::vector<int>> splitQuantities;
std::vector<std::vector< const SMDS_MeshNode* > > splitNodes; std::vector<std::vector< const SMDS_MeshNode* > > splitNodes;
if ( checkPolyhedronValidity( volDef, splitQuantities, splitNodes ) == 1 ) if ( checkPolyhedronValidity( volDef, splitQuantities, splitNodes ) == 1 )
{
v = addPolyhedronToMesh( volDef, helper, nodes, volDef->_quantities ); v = addPolyhedronToMesh( volDef, helper, nodes, volDef->_quantities );
}
else else
{ {
int counter = -1; int counter = -1;
@ -4879,6 +4901,19 @@ namespace
} }
} }
else else
{
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
{ {
switch ( nodes.size() ) switch ( nodes.size() )
{ {
@ -4945,6 +4980,8 @@ namespace
//================================================================================ //================================================================================
/*! /*!
* \brief Return true if the element is in a hole * \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 bool Hexahedron::isInHole() const
{ {
@ -5695,6 +5732,7 @@ namespace
SMESH_MeshEditor::ElemFeatures face( SMDSAbs_Face ); SMESH_MeshEditor::ElemFeatures face( SMDSAbs_Face );
SMESHDS_Mesh* meshDS = helper.GetMeshDS(); SMESHDS_Mesh* meshDS = helper.GetMeshDS();
bool isQuantaSet = _grid->_toUseQuanta;
// check if there are internal or shared FACEs // check if there are internal or shared FACEs
bool hasInternal = ( !_grid->_geometry.IsOneSolid() || bool hasInternal = ( !_grid->_geometry.IsOneSolid() ||
_grid->_geometry._soleSolid.HasInternalFaces() ); _grid->_geometry._soleSolid.HasInternalFaces() );
@ -5703,17 +5741,15 @@ namespace
{ {
if ( !vTool.Set( boundaryVolumes[ iV ])) if ( !vTool.Set( boundaryVolumes[ iV ]))
continue; continue;
TGeomID solidID = vTool.Element()->GetShapeID(); TGeomID solidID = vTool.Element()->GetShapeID();
Solid * solid = _grid->GetOneOfSolids( solidID ); Solid * solid = _grid->GetOneOfSolids( solidID );
// find boundary facets // find boundary facets
bndFacets.clear(); bndFacets.clear();
for ( int iF = 0, n = vTool.NbFaces(); iF < n; iF++ ) for ( int iF = 0, n = vTool.NbFaces(); iF < n; iF++ )
{ {
const SMDS_MeshElement* otherVol; const SMDS_MeshElement* otherVol;
bool isBoundary = vTool.IsFreeFace( iF, &otherVol ); bool isBoundary = isQuantaSet ? vTool.IsFreeFaceCheckAllNodes( iF, &otherVol ) : vTool.IsFreeFace( iF, &otherVol );
if ( isBoundary ) if ( isBoundary )
{ {
bndFacets.push_back( iF ); bndFacets.push_back( iF );
@ -5735,7 +5771,6 @@ namespace
continue; continue;
// create faces // create faces
if ( !vTool.IsPoly() ) if ( !vTool.IsPoly() )
vTool.SetExternalNormal(); vTool.SetExternalNormal();
for ( size_t i = 0; i < bndFacets.size(); ++i ) // loop on boundary facets for ( size_t i = 0; i < bndFacets.size(); ++i ) // loop on boundary facets
@ -5763,7 +5798,7 @@ namespace
if ( nn[ iN ]->GetPosition()->GetDim() == 2 ) if ( nn[ iN ]->GetPosition()->GetDim() == 2 )
faceID = nn[ iN ]->GetShapeID(); 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() ); faceID = findCommonFace( face.myNodes, helper.GetMesh() );
bool toCheckFace = faceID && (( !isBoundary ) || bool toCheckFace = faceID && (( !isBoundary ) ||
@ -5780,7 +5815,7 @@ namespace
// if ( !faceID && !isBoundary ) // if ( !faceID && !isBoundary )
// continue; // continue;
} }
if ( !faceID && !isBoundary ) if ( !faceID && !isBoundary && !isQuantaSet )
continue; continue;
} }
@ -6625,6 +6660,8 @@ bool StdMeshers_Cartesian_3D::Compute(SMESH_Mesh & theMesh,
grid._toConsiderInternalFaces = _hyp->GetToConsiderInternalFaces(); grid._toConsiderInternalFaces = _hyp->GetToConsiderInternalFaces();
grid._toUseThresholdForInternalFaces = _hyp->GetToUseThresholdForInternalFaces(); grid._toUseThresholdForInternalFaces = _hyp->GetToUseThresholdForInternalFaces();
grid._sizeThreshold = _hyp->GetSizeThreshold(); grid._sizeThreshold = _hyp->GetSizeThreshold();
grid._toUseQuanta = _hyp->GetToUseQuanta();
grid._quanta = _hyp->GetQuanta();
if ( _isComputeOffset ) if ( _isComputeOffset )
{ {
grid._toAddEdges = true; grid._toAddEdges = true;
@ -6763,6 +6800,15 @@ bool StdMeshers_Cartesian_3D::Compute(SMESH_Mesh & theMesh,
grid._nodes[i]->setIsMarked( true ); 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 // do remove
for ( size_t i = 0; i < nodesToRemove.size(); ++i ) for ( size_t i = 0; i < nodesToRemove.size(); ++i )
meshDS->RemoveFreeNode( nodesToRemove[i], /*smD=*/0, /*fromGroups=*/false ); meshDS->RemoveFreeNode( nodesToRemove[i], /*smD=*/0, /*fromGroups=*/false );

View File

@ -830,6 +830,17 @@ QFrame* StdMeshersGUI_CartesianParamCreator::buildFrame()
myUseThresholdForInternalFaces = new QCheckBox( tr("USE_THRESHOLD_FOR_INTERNAL_FACES"), GroupC1 ); myUseThresholdForInternalFaces = new QCheckBox( tr("USE_THRESHOLD_FOR_INTERNAL_FACES"), GroupC1 );
argGroupLayout->addWidget( myUseThresholdForInternalFaces, row, 0, 1, 2 ); argGroupLayout->addWidget( myUseThresholdForInternalFaces, row, 0, 1, 2 );
row++; 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 // 3) Grid definition
QTabWidget* tabWdg = new QTabWidget( fr ); QTabWidget* tabWdg = new QTabWidget( fr );
@ -935,6 +946,7 @@ QFrame* StdMeshersGUI_CartesianParamCreator::buildFrame()
connect( resetBtn, SIGNAL( clicked(bool)), SLOT( onResetAxes(bool))); connect( resetBtn, SIGNAL( clicked(bool)), SLOT( onResetAxes(bool)));
connect( myConsiderInternalFaces, SIGNAL( toggled(bool)), connect( myConsiderInternalFaces, SIGNAL( toggled(bool)),
myUseThresholdForInternalFaces, SLOT( setEnabled(bool))); myUseThresholdForInternalFaces, SLOT( setEnabled(bool)));
connect( mySetQuanta, SIGNAL( clicked(bool)), SLOT( onSetQuanta(bool)) );
for ( int i = 0; i < 3; ++i ) for ( int i = 0; i < 3; ++i )
{ {
connect( myXDirSpin[i], SIGNAL(valueChanged (const QString&)), connect( myXDirSpin[i], SIGNAL(valueChanged (const QString&)),
@ -1011,6 +1023,10 @@ void StdMeshersGUI_CartesianParamCreator::retrieveParams() const
myCreateFaces->setChecked( h->GetToCreateFaces() ); myCreateFaces->setChecked( h->GetToCreateFaces() );
myConsiderInternalFaces->setChecked( h->GetToConsiderInternalFaces() ); myConsiderInternalFaces->setChecked( h->GetToConsiderInternalFaces() );
myUseThresholdForInternalFaces->setChecked( h->GetToUseThresholdForInternalFaces() ); myUseThresholdForInternalFaces->setChecked( h->GetToUseThresholdForInternalFaces() );
mySetQuanta->setChecked( h->GetToUseQuanta() );
myQuanta->setValue( h->GetQuanta() );
if (h->GetToUseQuanta())
myQuanta->setEnabled(true);
// grid definition // grid definition
for ( int ax = 0; ax < 3; ++ax ) for ( int ax = 0; ax < 3; ++ax )
@ -1101,6 +1117,8 @@ QString StdMeshersGUI_CartesianParamCreator::storeParams() const
h->SetToCreateFaces( myCreateFaces->isChecked() ); h->SetToCreateFaces( myCreateFaces->isChecked() );
h->SetToConsiderInternalFaces( myConsiderInternalFaces->isChecked() ); h->SetToConsiderInternalFaces( myConsiderInternalFaces->isChecked() );
h->SetToUseThresholdForInternalFaces( myUseThresholdForInternalFaces->isChecked() ); h->SetToUseThresholdForInternalFaces( myUseThresholdForInternalFaces->isChecked() );
h->SetToUseQuanta( mySetQuanta->isChecked() );
h->SetQuanta( myQuanta->text().toDouble() );
// grid // grid
for ( int ax = 0; ax < 3; ++ax ) for ( int ax = 0; ax < 3; ++ax )
@ -1453,3 +1471,19 @@ void StdMeshersGUI_CartesianParamCreator::onGridModeChanged(int)
myFixedPointGrp->setEnabled( haveSpacing ); 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() );
}

View File

@ -147,6 +147,7 @@ private slots:
void onOptimalAxes(bool); void onOptimalAxes(bool);
void onResetAxes(bool); void onResetAxes(bool);
void onGridModeChanged(int); void onGridModeChanged(int);
void onSetQuanta(bool);
private: private:
QLineEdit* myName; QLineEdit* myName;
@ -155,6 +156,8 @@ private:
QCheckBox* myCreateFaces; QCheckBox* myCreateFaces;
QCheckBox* myConsiderInternalFaces; QCheckBox* myConsiderInternalFaces;
QCheckBox* myUseThresholdForInternalFaces; QCheckBox* myUseThresholdForInternalFaces;
QCheckBox* mySetQuanta;
SMESHGUI_SpinBox* myQuanta;
StdMeshersGUI::GridAxisTab* myAxisTabs[3]; StdMeshersGUI::GridAxisTab* myAxisTabs[3];
QGroupBox* myFixedPointGrp; QGroupBox* myFixedPointGrp;

View 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> <source>USE_THRESHOLD_FOR_INTERNAL_FACES</source>
<translation>Apply Threshold to Shared / Internal Faces</translation> <translation>Apply Threshold to Shared / Internal Faces</translation>
</message> </message>
<message>
<source>SET_QUANTA</source>
<translation>Set Quanta</translation>
</message>
<message>
<source>QUANTA_VALUE</source>
<translation>Quanta Value</translation>
</message>
<message> <message>
<source>AXIS_X</source> <source>AXIS_X</source>
<translation>Axis X</translation> <translation>Axis X</translation>

View 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> <source>USE_THRESHOLD_FOR_INTERNAL_FACES</source>
<translation>Appliquer le seuil aux faces partagées/internes</translation> <translation>Appliquer le seuil aux faces partagées/internes</translation>
</message> </message>
<message>
<source>SET_QUANTA</source>
<translation>Utiliser Quanta</translation>
</message>
<message>
<source>QUANTA_VALUE</source>
<translation>Valeur Quanta</translation>
</message>
<message> <message>
<source>AXIS_X</source> <source>AXIS_X</source>
<translation>Axe X</translation> <translation>Axe X</translation>

View File

@ -418,6 +418,63 @@ CORBA::Boolean StdMeshers_CartesianParameters3D_i::GetToCreateFaces()
return GetImpl()->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 //function : IsGridBySpacing
//purpose : Return true if the grid is defined by spacing functions and //purpose : Return true if the grid is defined by spacing functions and

View File

@ -125,6 +125,17 @@ class STDMESHERS_I_EXPORT StdMeshers_CartesianParameters3D_i:
void SetToCreateFaces(CORBA::Boolean toCreate); void SetToCreateFaces(CORBA::Boolean toCreate);
CORBA::Boolean GetToCreateFaces(); 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 * \brief Return true if the grid is defined by spacing functions and

View File

@ -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()

View File

@ -32,6 +32,7 @@ SET(BAD_TESTS
blocFissure_07_without_session.py blocFissure_07_without_session.py
body_fitting_viscous_layer_cylinder.py body_fitting_viscous_layer_cylinder.py
body_fitting_viscous_layer_tpipe.py body_fitting_viscous_layer_tpipe.py
body_fitting_quanta_sphere.py
ex04_cube5tetraHexa.py ex04_cube5tetraHexa.py
ex21_lamp.py ex21_lamp.py
ex29_refine.py ex29_refine.py