mirror of
https://git.salome-platform.org/gitpub/modules/smesh.git
synced 2024-12-27 01:40:33 +05:00
bos #32738 [CEA] Scaled Jacobian quality mesh measure for volumetric elements.
Erase non tracke files Adding some comments on SMESH_Controls. Fixing compilation warning on SMDS_VolumeTool and add missing lines in interface files. Add implemented tests to tests.set Correction on SMESH_msg_fr and copyright msg of python test.
This commit is contained in:
parent
e0552dbb7f
commit
9ac965c0e3
9
doc/examples/filters_ex40.py
Normal file
9
doc/examples/filters_ex40.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# Scaled Jacobian
|
||||||
|
|
||||||
|
# create mesh with volumes
|
||||||
|
from mechanic import *
|
||||||
|
|
||||||
|
# get volumes with scaled jacobian > 0.75
|
||||||
|
filter = smesh_builder.GetFilter(SMESH.VOLUME, SMESH.FT_ScaledJacobian, SMESH.FT_MoreThan, 0.75 )
|
||||||
|
ids = mesh.GetIdsFromFilter(filter)
|
||||||
|
print("Number of volumes with scaled jacobian > 0.75:", len(ids))
|
24
doc/examples/quality_controls_ex24.py
Normal file
24
doc/examples/quality_controls_ex24.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Scaled Jacobian
|
||||||
|
|
||||||
|
from mechanic import *
|
||||||
|
|
||||||
|
# Criterion : Scaled Jacobian > 0.75
|
||||||
|
scaledJacobian = 0.75
|
||||||
|
|
||||||
|
aFilter = smesh_builder.GetFilter(SMESH.VOLUME, SMESH.FT_ScaledJacobian, SMESH.FT_MoreThan, scaledJacobian)
|
||||||
|
|
||||||
|
anIds = mesh.GetIdsFromFilter(aFilter)
|
||||||
|
|
||||||
|
# print the result
|
||||||
|
print("Criterion: Scaled Jacobian > ", scaledJacobian, " Nb = ", len(anIds))
|
||||||
|
j = 1
|
||||||
|
for i in range(len(anIds)):
|
||||||
|
if j > 20: j = 1; print("")
|
||||||
|
print(anIds[i], end=' ')
|
||||||
|
j = j + 1
|
||||||
|
pass
|
||||||
|
print("")
|
||||||
|
|
||||||
|
# create a group
|
||||||
|
aGroup = mesh.CreateEmptyGroup(SMESH.FACE, "Scaled Jacobian > " + repr(scaledJacobian))
|
||||||
|
aGroup.Add(anIds)
|
@ -73,6 +73,7 @@ SET(BAD_TESTS
|
|||||||
filters_ex36.py
|
filters_ex36.py
|
||||||
filters_ex37.py
|
filters_ex37.py
|
||||||
filters_ex38.py
|
filters_ex38.py
|
||||||
|
filters_ex40.py
|
||||||
filters_node_nb_conn.py
|
filters_node_nb_conn.py
|
||||||
filters_belong2group.py
|
filters_belong2group.py
|
||||||
generate_flat_elements.py
|
generate_flat_elements.py
|
||||||
@ -119,6 +120,7 @@ SET(BAD_TESTS
|
|||||||
quality_controls_ex20.py
|
quality_controls_ex20.py
|
||||||
quality_controls_ex21.py
|
quality_controls_ex21.py
|
||||||
quality_controls_ex22.py
|
quality_controls_ex22.py
|
||||||
|
quality_controls_ex24.py
|
||||||
quality_controls_defl.py
|
quality_controls_defl.py
|
||||||
split_biquad.py
|
split_biquad.py
|
||||||
transforming_meshes_ex01.py
|
transforming_meshes_ex01.py
|
||||||
|
BIN
doc/gui/images/scaled_jacobian.png
Normal file
BIN
doc/gui/images/scaled_jacobian.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
BIN
doc/gui/images/scaled_jacobian_hexa.png
Normal file
BIN
doc/gui/images/scaled_jacobian_hexa.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
BIN
doc/gui/images/scaled_jacobian_mesh_tetra.png
Normal file
BIN
doc/gui/images/scaled_jacobian_mesh_tetra.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
BIN
doc/gui/images/scaled_jacobian_tetra.png
Normal file
BIN
doc/gui/images/scaled_jacobian_tetra.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
@ -48,6 +48,7 @@ Volume quality controls:
|
|||||||
* :ref:`aspect_ratio_3d_page`
|
* :ref:`aspect_ratio_3d_page`
|
||||||
* :ref:`volume_page`
|
* :ref:`volume_page`
|
||||||
* :ref:`max_element_length_3d_page`
|
* :ref:`max_element_length_3d_page`
|
||||||
|
* :ref:`scaled_jacobian_page`
|
||||||
* :ref:`bare_border_volumes_page`
|
* :ref:`bare_border_volumes_page`
|
||||||
* :ref:`over_constrained_volumes_page`
|
* :ref:`over_constrained_volumes_page`
|
||||||
* :ref:`double_elements_page`
|
* :ref:`double_elements_page`
|
||||||
@ -100,3 +101,4 @@ To manage the quality controls call pop-up in the VTK viewer and select "Control
|
|||||||
bare_border_volumes.rst
|
bare_border_volumes.rst
|
||||||
over_constrained_volumes.rst
|
over_constrained_volumes.rst
|
||||||
scalar_bar.rst
|
scalar_bar.rst
|
||||||
|
scaled_jacobian.rst
|
42
doc/gui/input/scaled_jacobian.rst
Normal file
42
doc/gui/input/scaled_jacobian.rst
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
.. _scaled_jacobian_page:
|
||||||
|
|
||||||
|
***************
|
||||||
|
Scaled Jacobian
|
||||||
|
***************
|
||||||
|
|
||||||
|
The **Scaled Jacobian** mesh quality criteria, is a scalar measure of the deviation from the perfect element in the geometrical sense, this measure normalize the range of reported values
|
||||||
|
between [0,1] for a normal element, the value of 1 is considered a perfect element and 0 a element with a collapsed side. Negative values are also accepted for invalid elements.
|
||||||
|
|
||||||
|
The **Scaled Jacobian** is implemented for volumetric elements returning 0 for polyhedrons. For tetrahedron and hexahedron the close form
|
||||||
|
is defined in `[1] <https://gitlab.kitware.com/third-party/verdict/-/blob/master/SAND2007-2853p.pdf>`_, for pyramids the minimum scaled jacobian of the four tetrahedrons formed
|
||||||
|
in the four vertices of the pyramid base is reported, for pentahedrons a decomposition into tetrahedron is also done and finally for hexahedron prisms the minimum scaled jacobian between two pentahedrons and one hexahedron is reported.
|
||||||
|
|
||||||
|
* Geometrically the Scaled Jacobian of a **tetrahedron** can be understood by the follow figure:
|
||||||
|
|
||||||
|
.. image:: ../images/scaled_jacobian_tetra.png
|
||||||
|
:align: center
|
||||||
|
|
||||||
|
The reported Scaled Jacobian will be 1 if :math:`\alpha=45^{\circ}`
|
||||||
|
|
||||||
|
* For **hexadrons** this measure return 1 for the perfect non rotated elements:
|
||||||
|
|
||||||
|
.. image:: ../images/scaled_jacobian_hexa.png
|
||||||
|
:align: center
|
||||||
|
|
||||||
|
The reported Scaled Jacobian will be 1 if :math:`\alpha=0^{\circ}` for all the vertices
|
||||||
|
|
||||||
|
|
||||||
|
*To visualize the Scaled Jacobian quality criterion in your mesh:*
|
||||||
|
|
||||||
|
.. |img| image:: ../images/scaled_jacobian.png
|
||||||
|
|
||||||
|
#. Display your mesh in the viewer.
|
||||||
|
#. Choose **Controls > Volume Controls > Scaled Jacobian** or click *"Scaled Jacobian"* button |img| of the toolbar.
|
||||||
|
|
||||||
|
Your mesh will be displayed in the viewer with its elements colored according to the applied mesh quality control criterion:
|
||||||
|
|
||||||
|
.. image:: ../images/scaled_jacobian_mesh_tetra.png
|
||||||
|
:align: center
|
||||||
|
|
||||||
|
|
||||||
|
**See Also** a sample TUI Script of a :ref:`tui_scaled_jacobian` filter.
|
@ -61,6 +61,24 @@ filters 3D mesh elements (volumes) according to the aspect ratio value:
|
|||||||
|
|
||||||
**See also:** :ref:`tui_aspect_ratio_3d`
|
**See also:** :ref:`tui_aspect_ratio_3d`
|
||||||
|
|
||||||
|
.. _filter_scaled_jacobian:
|
||||||
|
|
||||||
|
Scaled Jacobian
|
||||||
|
===============
|
||||||
|
|
||||||
|
filters 3D mesh elements (volumes) according to the scaled jacobian value:
|
||||||
|
|
||||||
|
* element type is *SMESH.VOLUME*
|
||||||
|
* functor type is *SMESH.FT_ScaledJacobian*
|
||||||
|
* threshold is floating point value
|
||||||
|
|
||||||
|
.. literalinclude:: ../../examples/filters_ex40.py
|
||||||
|
:language: python
|
||||||
|
|
||||||
|
:download:`Download this script <../../examples/filters_ex40.py>`
|
||||||
|
|
||||||
|
**See also:** :ref:`tui_scaled_jacobian`
|
||||||
|
|
||||||
.. _filter_warping_angle:
|
.. _filter_warping_angle:
|
||||||
|
|
||||||
Warping angle
|
Warping angle
|
||||||
|
@ -240,3 +240,13 @@ Element Diameter 3D
|
|||||||
:language: python
|
:language: python
|
||||||
|
|
||||||
:download:`Download this script <../../examples/quality_controls_ex22.py>`
|
:download:`Download this script <../../examples/quality_controls_ex22.py>`
|
||||||
|
|
||||||
|
.. _tui_scaled_jacobian:
|
||||||
|
|
||||||
|
Scaled Jacobian
|
||||||
|
===================
|
||||||
|
|
||||||
|
.. literalinclude:: ../../examples/quality_controls_ex24.py
|
||||||
|
:language: python
|
||||||
|
|
||||||
|
:download:`Download this script <../../examples/quality_controls_ex24.py>`
|
||||||
|
@ -48,6 +48,7 @@ module SMESH
|
|||||||
FT_Skew,
|
FT_Skew,
|
||||||
FT_Area,
|
FT_Area,
|
||||||
FT_Volume3D,
|
FT_Volume3D,
|
||||||
|
FT_ScaledJacobian,
|
||||||
FT_MaxElementLength2D,
|
FT_MaxElementLength2D,
|
||||||
FT_MaxElementLength3D,
|
FT_MaxElementLength3D,
|
||||||
FT_FreeBorders,
|
FT_FreeBorders,
|
||||||
@ -170,6 +171,7 @@ module SMESH
|
|||||||
};
|
};
|
||||||
interface BallDiameter : NumericalFunctor{};
|
interface BallDiameter : NumericalFunctor{};
|
||||||
interface NodeConnectivityNumber : NumericalFunctor{};
|
interface NodeConnectivityNumber : NumericalFunctor{};
|
||||||
|
interface ScaledJacobian : NumericalFunctor{};
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -598,6 +600,7 @@ module SMESH
|
|||||||
MultiConnection2D CreateMultiConnection2D();
|
MultiConnection2D CreateMultiConnection2D();
|
||||||
BallDiameter CreateBallDiameter();
|
BallDiameter CreateBallDiameter();
|
||||||
NodeConnectivityNumber CreateNodeConnectivityNumber();
|
NodeConnectivityNumber CreateNodeConnectivityNumber();
|
||||||
|
ScaledJacobian CreateScaledJacobian();
|
||||||
/*!
|
/*!
|
||||||
* Create logical functors ( predicates )
|
* Create logical functors ( predicates )
|
||||||
*/
|
*/
|
||||||
|
BIN
resources/mesh_scaled_jacobian.png
Normal file
BIN
resources/mesh_scaled_jacobian.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.2 KiB |
@ -2351,6 +2351,70 @@ SMDSAbs_ElementType NodeConnectivityNumber::GetType() const
|
|||||||
return SMDSAbs_Node;
|
return SMDSAbs_Node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
/*
|
||||||
|
Class : ScaledJacobian
|
||||||
|
Description : Functor returning the ScaledJacobian for volumetric elements
|
||||||
|
*/
|
||||||
|
//================================================================================
|
||||||
|
|
||||||
|
double ScaledJacobian::GetValue( long theElementId )
|
||||||
|
{
|
||||||
|
if ( theElementId && myMesh ) {
|
||||||
|
SMDS_VolumeTool aVolumeTool;
|
||||||
|
if ( aVolumeTool.Set( myMesh->FindElement( theElementId )))
|
||||||
|
return aVolumeTool.GetScaledJacobian();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
//VTK version not used because lack of implementation for HEXAGONAL_PRISM.
|
||||||
|
//Several mesh quality measures implemented in vtkMeshQuality can be accessed left here as reference
|
||||||
|
double aVal = 0;
|
||||||
|
myCurrElement = myMesh->FindElement( theElementId );
|
||||||
|
if ( myCurrElement )
|
||||||
|
{
|
||||||
|
VTKCellType cellType = myCurrElement->GetVtkType();
|
||||||
|
vtkUnstructuredGrid* grid = const_cast<SMDS_Mesh*>( myMesh )->GetGrid();
|
||||||
|
vtkCell* avtkCell = grid->GetCell( myCurrElement->GetVtkID() );
|
||||||
|
switch ( cellType )
|
||||||
|
{
|
||||||
|
case VTK_QUADRATIC_TETRA:
|
||||||
|
case VTK_TETRA:
|
||||||
|
aVal = Round( vtkMeshQuality::TetScaledJacobian( avtkCell ));
|
||||||
|
break;
|
||||||
|
case VTK_QUADRATIC_HEXAHEDRON:
|
||||||
|
case VTK_HEXAHEDRON:
|
||||||
|
aVal = Round( vtkMeshQuality::HexScaledJacobian( avtkCell ));
|
||||||
|
break;
|
||||||
|
case VTK_QUADRATIC_WEDGE:
|
||||||
|
case VTK_WEDGE: //Pentahedron
|
||||||
|
aVal = Round( vtkMeshQuality::WedgeScaledJacobian( avtkCell ));
|
||||||
|
break;
|
||||||
|
case VTK_QUADRATIC_PYRAMID:
|
||||||
|
case VTK_PYRAMID:
|
||||||
|
aVal = Round( vtkMeshQuality::PyramidScaledJacobian( avtkCell ));
|
||||||
|
break;
|
||||||
|
case VTK_HEXAGONAL_PRISM:
|
||||||
|
case VTK_POLYHEDRON:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return aVal;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
double ScaledJacobian::GetBadRate( double Value, int /*nbNodes*/ ) const
|
||||||
|
{
|
||||||
|
return Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
SMDSAbs_ElementType ScaledJacobian::GetType() const
|
||||||
|
{
|
||||||
|
return SMDSAbs_Volume;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
PREDICATES
|
PREDICATES
|
||||||
*/
|
*/
|
||||||
|
@ -405,6 +405,17 @@ namespace SMESH{
|
|||||||
virtual SMDSAbs_ElementType GetType() const;
|
virtual SMDSAbs_ElementType GetType() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Class : ScaledJacobian
|
||||||
|
Description : Functor returning the ScaledJacobian as implemeted in VTK for volumetric elements
|
||||||
|
*/
|
||||||
|
class SMESHCONTROLS_EXPORT ScaledJacobian: public virtual NumericalFunctor{
|
||||||
|
public:
|
||||||
|
virtual double GetValue( long theNodeId );
|
||||||
|
virtual double GetBadRate( double Value, int nbNodes ) const;
|
||||||
|
virtual SMDSAbs_ElementType GetType() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
PREDICATES
|
PREDICATES
|
||||||
|
@ -953,6 +953,14 @@ void SMESH_ActorDef::SetControlMode( eControl theMode, bool theCheckEntityMode )
|
|||||||
myControlActor = my3DActor;
|
myControlActor = my3DActor;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case eScaledJacobian:
|
||||||
|
{
|
||||||
|
SMESH::Controls::ScaledJacobian* aControl = new SMESH::Controls::ScaledJacobian();
|
||||||
|
aControl->SetPrecision( myControlsPrecision );
|
||||||
|
myFunctor.reset( aControl );
|
||||||
|
myControlActor = my3DActor;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case eMaxElementLength2D:
|
case eMaxElementLength2D:
|
||||||
{
|
{
|
||||||
SMESH::Controls::MaxElementLength2D* aControl = new SMESH::Controls::MaxElementLength2D();
|
SMESH::Controls::MaxElementLength2D* aControl = new SMESH::Controls::MaxElementLength2D();
|
||||||
@ -1112,7 +1120,6 @@ void SMESH_ActorDef::SetControlMode( eControl theMode, bool theCheckEntityMode )
|
|||||||
QString aTitle = QString(myScalarBarActor->GetTitle());
|
QString aTitle = QString(myScalarBarActor->GetTitle());
|
||||||
aTitle.replace(QRegExp("(:\\s).*"),"\\1"+ QString::number(GetNumberControlEntities()));
|
aTitle.replace(QRegExp("(:\\s).*"),"\\1"+ QString::number(GetNumberControlEntities()));
|
||||||
myScalarBarActor->SetTitle(aTitle.toUtf8().constData());
|
myScalarBarActor->SetTitle(aTitle.toUtf8().constData());
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(theCheckEntityMode){
|
if(theCheckEntityMode){
|
||||||
|
@ -139,7 +139,7 @@ class SMESHOBJECT_EXPORT SMESH_Actor: public SALOME_Actor
|
|||||||
|
|
||||||
enum eControl{eNone, eLength, eLength2D, eDeflection2D, eFreeBorders, eFreeEdges, eFreeNodes,
|
enum eControl{eNone, eLength, eLength2D, eDeflection2D, eFreeBorders, eFreeEdges, eFreeNodes,
|
||||||
eFreeFaces, eMultiConnection, eArea, eTaper, eAspectRatio,
|
eFreeFaces, eMultiConnection, eArea, eTaper, eAspectRatio,
|
||||||
eMinimumAngle, eWarping, eSkew, eAspectRatio3D, eMultiConnection2D, eVolume3D,
|
eMinimumAngle, eWarping, eSkew, eAspectRatio3D, eMultiConnection2D, eVolume3D, eScaledJacobian,
|
||||||
eMaxElementLength2D, eMaxElementLength3D, eBareBorderFace, eBareBorderVolume,
|
eMaxElementLength2D, eMaxElementLength3D, eBareBorderFace, eBareBorderVolume,
|
||||||
eOverConstrainedFace, eOverConstrainedVolume, eCoincidentNodes,
|
eOverConstrainedFace, eOverConstrainedVolume, eCoincidentNodes,
|
||||||
eCoincidentElems1D, eCoincidentElems2D, eCoincidentElems3D, eNodeConnectivityNb,
|
eCoincidentElems1D, eCoincidentElems2D, eCoincidentElems3D, eNodeConnectivityNb,
|
||||||
|
@ -80,9 +80,17 @@ static int Tetra_RE [4][4] = { // REVERSED -> FORWARD (EXTERNAL)
|
|||||||
{ 0, 3, 2, 0 }};
|
{ 0, 3, 2, 0 }};
|
||||||
static int Tetra_nbN [] = { 3, 3, 3, 3 };
|
static int Tetra_nbN [] = { 3, 3, 3, 3 };
|
||||||
|
|
||||||
//
|
/*
|
||||||
// PYRAMID
|
// N1 +---------+ N2
|
||||||
//
|
// | \ / |
|
||||||
|
// | \ / |
|
||||||
|
// | \ / |
|
||||||
|
// | /+\ | PYRAMID
|
||||||
|
// | / N4\ |
|
||||||
|
// | / \ |
|
||||||
|
// |/ \|
|
||||||
|
// N0 +---------+ N3
|
||||||
|
*/
|
||||||
static int Pyramid_F [5][5] = { // FORWARD == EXTERNAL
|
static int Pyramid_F [5][5] = { // FORWARD == EXTERNAL
|
||||||
{ 0, 1, 2, 3, 0 }, // All faces have external normals
|
{ 0, 1, 2, 3, 0 }, // All faces have external normals
|
||||||
{ 0, 4, 1, 0, 4 },
|
{ 0, 4, 1, 0, 4 },
|
||||||
@ -363,13 +371,18 @@ struct XYZ {
|
|||||||
inline XYZ operator-( const XYZ& other );
|
inline XYZ operator-( const XYZ& other );
|
||||||
inline XYZ operator+( const XYZ& other );
|
inline XYZ operator+( const XYZ& other );
|
||||||
inline XYZ Crossed( const XYZ& other );
|
inline XYZ Crossed( const XYZ& other );
|
||||||
|
inline XYZ operator-();
|
||||||
inline double Dot( const XYZ& other );
|
inline double Dot( const XYZ& other );
|
||||||
inline double Magnitude();
|
inline double Magnitude();
|
||||||
inline double SquareMagnitude();
|
inline double SquareMagnitude();
|
||||||
|
inline XYZ Normalize();
|
||||||
};
|
};
|
||||||
inline XYZ XYZ::operator-( const XYZ& Right ) {
|
inline XYZ XYZ::operator-( const XYZ& Right ) {
|
||||||
return XYZ(x - Right.x, y - Right.y, z - Right.z);
|
return XYZ(x - Right.x, y - Right.y, z - Right.z);
|
||||||
}
|
}
|
||||||
|
inline XYZ XYZ::operator-() {
|
||||||
|
return XYZ(-x,-y,-z);
|
||||||
|
}
|
||||||
inline XYZ XYZ::operator+( const XYZ& Right ) {
|
inline XYZ XYZ::operator+( const XYZ& Right ) {
|
||||||
return XYZ(x + Right.x, y + Right.y, z + Right.z);
|
return XYZ(x + Right.x, y + Right.y, z + Right.z);
|
||||||
}
|
}
|
||||||
@ -387,6 +400,13 @@ inline double XYZ::Magnitude() {
|
|||||||
inline double XYZ::SquareMagnitude() {
|
inline double XYZ::SquareMagnitude() {
|
||||||
return (x * x + y * y + z * z);
|
return (x * x + y * y + z * z);
|
||||||
}
|
}
|
||||||
|
inline XYZ XYZ::Normalize() {
|
||||||
|
double magnitude = Magnitude();
|
||||||
|
if ( magnitude != 0.0 )
|
||||||
|
return XYZ(x /= magnitude,y /= magnitude,z /= magnitude );
|
||||||
|
else
|
||||||
|
return XYZ(x,y,z);
|
||||||
|
}
|
||||||
|
|
||||||
//================================================================================
|
//================================================================================
|
||||||
/*!
|
/*!
|
||||||
@ -694,7 +714,6 @@ static double getTetraVolume(const SMDS_MeshNode* n1,
|
|||||||
//function : GetSize
|
//function : GetSize
|
||||||
//purpose : Return element volume
|
//purpose : Return element volume
|
||||||
//=======================================================================
|
//=======================================================================
|
||||||
|
|
||||||
double SMDS_VolumeTool::GetSize() const
|
double SMDS_VolumeTool::GetSize() const
|
||||||
{
|
{
|
||||||
double V = 0.;
|
double V = 0.;
|
||||||
@ -847,6 +866,334 @@ double SMDS_VolumeTool::GetSize() const
|
|||||||
return V;
|
return V;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//=======================================================================
|
||||||
|
//function : getTetraScaledJacobian
|
||||||
|
//purpose : Given the smesh nodes in the canonical order of the tetrahedron, return the scaled jacobian
|
||||||
|
//=======================================================================
|
||||||
|
static double getTetraScaledJacobian(const SMDS_MeshNode* n0,
|
||||||
|
const SMDS_MeshNode* n1,
|
||||||
|
const SMDS_MeshNode* n2,
|
||||||
|
const SMDS_MeshNode* n3)
|
||||||
|
{
|
||||||
|
const double sqrt = std::sqrt(2.0);
|
||||||
|
// Get the coordinates
|
||||||
|
XYZ p0( n0 );
|
||||||
|
XYZ p1( n1 );
|
||||||
|
XYZ p2( n2 );
|
||||||
|
XYZ p3( n3 );
|
||||||
|
// Define the edges connecting the nodes
|
||||||
|
XYZ L0 = p1-p0;
|
||||||
|
XYZ L1 = p2-p1;
|
||||||
|
XYZ L2 = p2-p0; // invert the definition of doc to get the proper orientation of the crossed product
|
||||||
|
XYZ L3 = p3-p0;
|
||||||
|
XYZ L4 = p3-p1;
|
||||||
|
XYZ L5 = p3-p2;
|
||||||
|
double Jacobian = L2.Crossed( L0 ).Dot( L3 );
|
||||||
|
double norm0 = L0.Magnitude();
|
||||||
|
double norm1 = L1.Magnitude();
|
||||||
|
double norm2 = L2.Magnitude();
|
||||||
|
double norm3 = L3.Magnitude();
|
||||||
|
double norm4 = L4.Magnitude();
|
||||||
|
double norm5 = L5.Magnitude();
|
||||||
|
|
||||||
|
std::array<double, 5> norms{};
|
||||||
|
norms[0] = Jacobian;
|
||||||
|
norms[1] = norm3*norm4*norm5;
|
||||||
|
norms[2] = norm1*norm2*norm5;
|
||||||
|
norms[3] = norm0*norm1*norm4;
|
||||||
|
norms[4] = norm0*norm2*norm3;
|
||||||
|
|
||||||
|
auto findMaxNorm = std::max_element(norms.begin(), norms.end());
|
||||||
|
double maxNorm = *findMaxNorm;
|
||||||
|
|
||||||
|
if ( std::fabs( maxNorm ) < std::numeric_limits<double>::min() )
|
||||||
|
maxNorm = std::numeric_limits<double>::max();
|
||||||
|
|
||||||
|
return Jacobian * sqrt / maxNorm;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=======================================================================
|
||||||
|
//function : getPyramidScaledJacobian
|
||||||
|
//purpose : Given the pyramid, compute the scaled jacobian of the four tetrahedrons and return the minimun value.
|
||||||
|
//=======================================================================
|
||||||
|
static double getPyramidScaledJacobian(const SMDS_MeshNode* n0,
|
||||||
|
const SMDS_MeshNode* n1,
|
||||||
|
const SMDS_MeshNode* n2,
|
||||||
|
const SMDS_MeshNode* n3,
|
||||||
|
const SMDS_MeshNode* n4)
|
||||||
|
{
|
||||||
|
const double sqrt = std::sqrt(2.0);
|
||||||
|
std::array<double, 4> tetScaledJacobian{};
|
||||||
|
tetScaledJacobian[0] = getTetraScaledJacobian(n0, n1, n3, n4);
|
||||||
|
tetScaledJacobian[1] = getTetraScaledJacobian(n1, n2, n0, n4);
|
||||||
|
tetScaledJacobian[2] = getTetraScaledJacobian(n2, n3, n1, n4);
|
||||||
|
tetScaledJacobian[3] = getTetraScaledJacobian(n3, n0, n2, n4);
|
||||||
|
|
||||||
|
auto minEntry = std::min_element(tetScaledJacobian.begin(), tetScaledJacobian.end());
|
||||||
|
|
||||||
|
double scaledJacobian = (*minEntry) * 2.0/sqrt;
|
||||||
|
return scaledJacobian < 1.0 ? scaledJacobian : 1.0 - (scaledJacobian - 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=======================================================================
|
||||||
|
//function : getHexaScaledJacobian
|
||||||
|
//purpose : Evaluate the scaled jacobian on the eight vertices of the hexahedron and return the minimal registered value
|
||||||
|
//remark : Follow the reference numeration described at the top of the class.
|
||||||
|
//=======================================================================
|
||||||
|
static double getHexaScaledJacobian(const SMDS_MeshNode* n0,
|
||||||
|
const SMDS_MeshNode* n1,
|
||||||
|
const SMDS_MeshNode* n2,
|
||||||
|
const SMDS_MeshNode* n3,
|
||||||
|
const SMDS_MeshNode* n4,
|
||||||
|
const SMDS_MeshNode* n5,
|
||||||
|
const SMDS_MeshNode* n6,
|
||||||
|
const SMDS_MeshNode* n7)
|
||||||
|
{
|
||||||
|
// Scaled jacobian is an scalar quantity measuring the deviation of the geometry from the perfect geometry
|
||||||
|
// Get the coordinates
|
||||||
|
XYZ p0( n0 );
|
||||||
|
XYZ p1( n1 );
|
||||||
|
XYZ p2( n2 );
|
||||||
|
XYZ p3( n3 );
|
||||||
|
XYZ p4( n4 );
|
||||||
|
XYZ p5( n5 );
|
||||||
|
XYZ p6( n6 );
|
||||||
|
XYZ p7( n7 );
|
||||||
|
|
||||||
|
// Define the edges connecting the nodes
|
||||||
|
XYZ L0 = (p1-p0).Normalize();
|
||||||
|
XYZ L1 = (p2-p1).Normalize();
|
||||||
|
XYZ L2 = (p3-p2).Normalize();
|
||||||
|
XYZ L3 = (p3-p0).Normalize();
|
||||||
|
XYZ L4 = (p4-p0).Normalize();
|
||||||
|
XYZ L5 = (p5-p1).Normalize();
|
||||||
|
XYZ L6 = (p6-p2).Normalize();
|
||||||
|
XYZ L7 = (p7-p3).Normalize();
|
||||||
|
XYZ L8 = (p5-p4).Normalize();
|
||||||
|
XYZ L9 = (p6-p5).Normalize();
|
||||||
|
XYZ L10 = (p7-p6).Normalize();
|
||||||
|
XYZ L11 = (p7-p4).Normalize();
|
||||||
|
XYZ X0 = (p1-p0+p2-p3+p6-p7+p5-p4).Normalize();
|
||||||
|
XYZ X1 = (p3-p0+p2-p1+p7-p4+p6-p5).Normalize();
|
||||||
|
XYZ X2 = (p4-p0+p7-p3+p5-p1+p6-p2).Normalize();
|
||||||
|
|
||||||
|
std::array<double, 9> scaledJacobian{};
|
||||||
|
//Scaled jacobian of nodes following their numeration
|
||||||
|
scaledJacobian[0] = L4.Crossed( L3).Dot( L0 ); // For L0
|
||||||
|
scaledJacobian[1] = L5.Crossed(-L0).Dot( L1 ); // For L1
|
||||||
|
scaledJacobian[2] = L6.Crossed(-L1).Dot( L2 ); // For L2
|
||||||
|
scaledJacobian[3] = L7.Crossed(-L2).Dot(-L3 ); // For L3
|
||||||
|
scaledJacobian[4] = -L4.Crossed( L8).Dot( L11 ); // For L11
|
||||||
|
scaledJacobian[5] = -L5.Crossed( L9).Dot(-L8 ); // For L8
|
||||||
|
scaledJacobian[6] = -L6.Crossed(L10).Dot(-L9 ); // For L9
|
||||||
|
scaledJacobian[7] = -L7.Crossed(-L11).Dot(-L10 ); // For L10
|
||||||
|
scaledJacobian[8] = X2.Crossed( X1).Dot( X0 ); // For principal axes
|
||||||
|
|
||||||
|
auto minScaledJacobian = std::min_element(scaledJacobian.begin(), scaledJacobian.end());
|
||||||
|
return *minScaledJacobian;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//=======================================================================
|
||||||
|
//function : getTetraNormalizedJacobian
|
||||||
|
//purpose : Return the jacobian of the tetrahedron based on normalized vectors
|
||||||
|
//=======================================================================
|
||||||
|
static double getTetraNormalizedJacobian(const SMDS_MeshNode* n0,
|
||||||
|
const SMDS_MeshNode* n1,
|
||||||
|
const SMDS_MeshNode* n2,
|
||||||
|
const SMDS_MeshNode* n3)
|
||||||
|
{
|
||||||
|
const double sqrt = std::sqrt(2.0);
|
||||||
|
// Get the coordinates
|
||||||
|
XYZ p0( n0 );
|
||||||
|
XYZ p1( n1 );
|
||||||
|
XYZ p2( n2 );
|
||||||
|
XYZ p3( n3 );
|
||||||
|
// Define the normalized edges connecting the nodes
|
||||||
|
XYZ L0 = (p1-p0).Normalize();
|
||||||
|
XYZ L2 = (p2-p0).Normalize(); // invert the definition of doc to get the proper orientation of the crossed product
|
||||||
|
XYZ L3 = (p3-p0).Normalize();
|
||||||
|
return L2.Crossed( L0 ).Dot( L3 );
|
||||||
|
}
|
||||||
|
|
||||||
|
//=======================================================================
|
||||||
|
//function : getPentaScaledJacobian
|
||||||
|
//purpose : Evaluate the scaled jacobian on the pentahedron based on decomposed tetrahedrons
|
||||||
|
//=======================================================================
|
||||||
|
/*
|
||||||
|
// + N1
|
||||||
|
// /|\
|
||||||
|
// / | \
|
||||||
|
// / | \
|
||||||
|
// / | \
|
||||||
|
// N0 +---------+ N2
|
||||||
|
// | | | NUMERATION RERENCE FOLLOWING POSSITIVE RIGHT HAND RULE
|
||||||
|
// | + N4 |
|
||||||
|
// | / \ | PENTAHEDRON
|
||||||
|
// | / \ |
|
||||||
|
// | / \ |
|
||||||
|
// |/ \|
|
||||||
|
// N3 +---------+ N5
|
||||||
|
//
|
||||||
|
// N1
|
||||||
|
// +
|
||||||
|
// |\
|
||||||
|
// /| \
|
||||||
|
// / | \
|
||||||
|
// N0 +--|---+ N2 TETRAHEDRON ASSOCIATED TO N0
|
||||||
|
// \ | / Numeration passed to getTetraScaledJacobian
|
||||||
|
// \ | / N0=N0; N1=N2; N2=N3; N3=N1
|
||||||
|
// \| /
|
||||||
|
// |/
|
||||||
|
// +
|
||||||
|
// N3
|
||||||
|
//
|
||||||
|
// N1
|
||||||
|
// +
|
||||||
|
// /|\
|
||||||
|
// / | \
|
||||||
|
// / | \
|
||||||
|
// N2 +---|---+ N5 TETRAHEDRON ASSOCIATED TO N2
|
||||||
|
// \ | / Numeration passed to getTetraScaledJacobian
|
||||||
|
// \ | / N0=N2; N1=N5; N2=N0; N3=N1
|
||||||
|
// \ |/
|
||||||
|
// \|
|
||||||
|
// +
|
||||||
|
// N0
|
||||||
|
//
|
||||||
|
// N4
|
||||||
|
// +
|
||||||
|
// /|\
|
||||||
|
// / | \
|
||||||
|
// / | \
|
||||||
|
// N3 +---|---+ N0 TETRAHEDRON ASSOCIATED TO N3
|
||||||
|
// \ | / Numeration passed to getTetraScaledJacobian
|
||||||
|
// \ | / N0=N3; N1=N0; N2=N5; N3=N4
|
||||||
|
// \ | /
|
||||||
|
// \|/
|
||||||
|
// +
|
||||||
|
// N5
|
||||||
|
//
|
||||||
|
// N3
|
||||||
|
// +
|
||||||
|
// /|\
|
||||||
|
// / | \
|
||||||
|
// / | \
|
||||||
|
// N1 +---|---+ N2 TETRAHEDRON ASSOCIATED TO N1
|
||||||
|
// \ | / Numeration passed to getTetraScaledJacobian
|
||||||
|
// \ | / N0=N1; N1=N2; N2=N0; N3=N3
|
||||||
|
// \ | /
|
||||||
|
// \|/
|
||||||
|
// +
|
||||||
|
// N0
|
||||||
|
//
|
||||||
|
// ...
|
||||||
|
*/
|
||||||
|
static double getPentaScaledJacobian(const SMDS_MeshNode* n0,
|
||||||
|
const SMDS_MeshNode* n1,
|
||||||
|
const SMDS_MeshNode* n2,
|
||||||
|
const SMDS_MeshNode* n3,
|
||||||
|
const SMDS_MeshNode* n4,
|
||||||
|
const SMDS_MeshNode* n5)
|
||||||
|
{
|
||||||
|
std::array<double, 6> scaledJacobianOfReferenceTetra{};
|
||||||
|
scaledJacobianOfReferenceTetra[0] = getTetraNormalizedJacobian(n0, n2, n3, n1); // For n0
|
||||||
|
scaledJacobianOfReferenceTetra[1] = getTetraNormalizedJacobian(n2, n5, n0, n1); // For n2
|
||||||
|
scaledJacobianOfReferenceTetra[2] = getTetraNormalizedJacobian(n3, n0, n5, n4); // For n3
|
||||||
|
scaledJacobianOfReferenceTetra[3] = getTetraNormalizedJacobian(n5, n3, n2, n4); // For n5
|
||||||
|
scaledJacobianOfReferenceTetra[4] = getTetraNormalizedJacobian(n1, n2, n0, n3); // For n1
|
||||||
|
scaledJacobianOfReferenceTetra[5] = getTetraNormalizedJacobian(n4, n3, n5, n2); // For n4
|
||||||
|
|
||||||
|
auto minScaledJacobian = std::min_element(scaledJacobianOfReferenceTetra.begin(), scaledJacobianOfReferenceTetra.end());
|
||||||
|
double minScalJac = (*minScaledJacobian)* 2.0 / std::sqrt(3.0);
|
||||||
|
|
||||||
|
if (minScalJac > 0)
|
||||||
|
return std::min(minScalJac, std::numeric_limits<double>::max());
|
||||||
|
|
||||||
|
return std::max(minScalJac, -std::numeric_limits<double>::max());
|
||||||
|
}
|
||||||
|
|
||||||
|
//=======================================================================
|
||||||
|
//function : getHexaPrismScaledJacobian
|
||||||
|
//purpose : Evaluate the scaled jacobian on the hexaprism by decomposing the goemetry into three 1hexa + 2 pentahedrons
|
||||||
|
//=======================================================================
|
||||||
|
static double getHexaPrismScaledJacobian(const SMDS_MeshNode* n0,
|
||||||
|
const SMDS_MeshNode* n1,
|
||||||
|
const SMDS_MeshNode* n2,
|
||||||
|
const SMDS_MeshNode* n3,
|
||||||
|
const SMDS_MeshNode* n4,
|
||||||
|
const SMDS_MeshNode* n5,
|
||||||
|
const SMDS_MeshNode* n6,
|
||||||
|
const SMDS_MeshNode* n7,
|
||||||
|
const SMDS_MeshNode* n8,
|
||||||
|
const SMDS_MeshNode* n9,
|
||||||
|
const SMDS_MeshNode* n10,
|
||||||
|
const SMDS_MeshNode* n11)
|
||||||
|
{
|
||||||
|
// The Pentahedron from the left
|
||||||
|
// n0=n0; n1=n1; n2=n2; n3=n6; n4=n7, n5=n8;
|
||||||
|
double scaledJacobianPentleft = getPentaScaledJacobian( n0, n1, n2, n6, n7, n8 );
|
||||||
|
// The core Hexahedron
|
||||||
|
// n0=n0; n1=n2, n2=n3; n3=n5; n4=n6; n5=n8; n6=n9; n7=n11
|
||||||
|
double scaledJacobianHexa = getHexaScaledJacobian( n0, n2, n3, n5, n6, n8, n9, n11 );
|
||||||
|
// The Pentahedron from the right
|
||||||
|
// n0=n5; n1=n4; n2=n3; n3=n11; n4=n10; n5=n9
|
||||||
|
double scaledJacobianPentright = getPentaScaledJacobian( n5, n4, n3, n11, n10, n9 );
|
||||||
|
|
||||||
|
return std::min( scaledJacobianHexa, std::min( scaledJacobianPentleft, scaledJacobianPentright ) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//=======================================================================
|
||||||
|
//function : GetScaledJacobian
|
||||||
|
//purpose : Return element Scaled Jacobian using the generic definition given
|
||||||
|
// in https://gitlab.kitware.com/third-party/verdict/-/blob/master/SAND2007-2853p.pdf
|
||||||
|
//=======================================================================
|
||||||
|
|
||||||
|
double SMDS_VolumeTool::GetScaledJacobian() const
|
||||||
|
{
|
||||||
|
|
||||||
|
// For Tetra, call directly the getTetraScaledJacobian
|
||||||
|
double scaledJacobian = 0.;
|
||||||
|
|
||||||
|
VolumeType type = GetVolumeType();
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case TETRA:
|
||||||
|
case QUAD_TETRA:
|
||||||
|
scaledJacobian = getTetraScaledJacobian( myVolumeNodes[0], myVolumeNodes[1], myVolumeNodes[2], myVolumeNodes[3] );
|
||||||
|
break;
|
||||||
|
case HEXA:
|
||||||
|
case QUAD_HEXA:
|
||||||
|
scaledJacobian = getHexaScaledJacobian( myVolumeNodes[0], myVolumeNodes[1], myVolumeNodes[2], myVolumeNodes[3],
|
||||||
|
myVolumeNodes[4], myVolumeNodes[5], myVolumeNodes[6], myVolumeNodes[7] );
|
||||||
|
break;
|
||||||
|
case PYRAM:
|
||||||
|
case QUAD_PYRAM:
|
||||||
|
scaledJacobian = getPyramidScaledJacobian( myVolumeNodes[0], myVolumeNodes[1], myVolumeNodes[2], myVolumeNodes[3], myVolumeNodes[4] );
|
||||||
|
break;
|
||||||
|
case PENTA:
|
||||||
|
case QUAD_PENTA:
|
||||||
|
scaledJacobian = getPentaScaledJacobian( myVolumeNodes[0], myVolumeNodes[1],
|
||||||
|
myVolumeNodes[2], myVolumeNodes[3],
|
||||||
|
myVolumeNodes[4], myVolumeNodes[5] );
|
||||||
|
break;
|
||||||
|
case HEX_PRISM:
|
||||||
|
scaledJacobian = getHexaPrismScaledJacobian( myVolumeNodes[0], myVolumeNodes[1], myVolumeNodes[2], myVolumeNodes[3],
|
||||||
|
myVolumeNodes[4], myVolumeNodes[5], myVolumeNodes[6], myVolumeNodes[7],
|
||||||
|
myVolumeNodes[8], myVolumeNodes[9], myVolumeNodes[10], myVolumeNodes[11]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return scaledJacobian;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//=======================================================================
|
//=======================================================================
|
||||||
//function : GetBaryCenter
|
//function : GetBaryCenter
|
||||||
//purpose :
|
//purpose :
|
||||||
|
@ -103,6 +103,9 @@ class SMDS_EXPORT SMDS_VolumeTool
|
|||||||
double GetSize() const;
|
double GetSize() const;
|
||||||
// Return element volume
|
// Return element volume
|
||||||
|
|
||||||
|
double GetScaledJacobian() const;
|
||||||
|
// Return the scaled jacobian
|
||||||
|
|
||||||
bool GetBaryCenter (double & X, double & Y, double & Z) const;
|
bool GetBaryCenter (double & X, double & Y, double & Z) const;
|
||||||
|
|
||||||
bool IsOut(double X, double Y, double Z, double tol) const;
|
bool IsOut(double X, double Y, double Z, double tol) const;
|
||||||
|
@ -1162,6 +1162,8 @@ namespace
|
|||||||
type = QObject::tr( "EQUAL_VOLUME" );
|
type = QObject::tr( "EQUAL_VOLUME" );
|
||||||
else if ( dynamic_cast< SMESH::Controls::NodeConnectivityNumber* >( f.get() ) )
|
else if ( dynamic_cast< SMESH::Controls::NodeConnectivityNumber* >( f.get() ) )
|
||||||
type = QObject::tr( "NODE_CONNECTIVITY_NB" );
|
type = QObject::tr( "NODE_CONNECTIVITY_NB" );
|
||||||
|
else if ( dynamic_cast< SMESH::Controls::ScaledJacobian* >( f.get() ) )
|
||||||
|
type = QObject::tr( "SCALED_JACOBIAN" );
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1778,6 +1780,7 @@ namespace
|
|||||||
ActionControl.Bind( SMESHOp::OpEqualFace, SMESH_Actor::eCoincidentElems2D );
|
ActionControl.Bind( SMESHOp::OpEqualFace, SMESH_Actor::eCoincidentElems2D );
|
||||||
ActionControl.Bind( SMESHOp::OpAspectRatio3D, SMESH_Actor::eAspectRatio3D );
|
ActionControl.Bind( SMESHOp::OpAspectRatio3D, SMESH_Actor::eAspectRatio3D );
|
||||||
ActionControl.Bind( SMESHOp::OpVolume, SMESH_Actor::eVolume3D );
|
ActionControl.Bind( SMESHOp::OpVolume, SMESH_Actor::eVolume3D );
|
||||||
|
ActionControl.Bind( SMESHOp::OpScaledJacobian, SMESH_Actor::eScaledJacobian );
|
||||||
ActionControl.Bind( SMESHOp::OpMaxElementLength3D, SMESH_Actor::eMaxElementLength3D );
|
ActionControl.Bind( SMESHOp::OpMaxElementLength3D, SMESH_Actor::eMaxElementLength3D );
|
||||||
ActionControl.Bind( SMESHOp::OpBareBorderVolume, SMESH_Actor::eBareBorderVolume );
|
ActionControl.Bind( SMESHOp::OpBareBorderVolume, SMESH_Actor::eBareBorderVolume );
|
||||||
ActionControl.Bind( SMESHOp::OpOverConstrainedVolume, SMESH_Actor::eOverConstrainedVolume );
|
ActionControl.Bind( SMESHOp::OpOverConstrainedVolume, SMESH_Actor::eOverConstrainedVolume );
|
||||||
@ -3902,6 +3905,7 @@ bool SMESHGUI::OnGUIEvent( int theCommandID )
|
|||||||
case SMESHOp::OpEqualFace:
|
case SMESHOp::OpEqualFace:
|
||||||
case SMESHOp::OpAspectRatio3D:
|
case SMESHOp::OpAspectRatio3D:
|
||||||
case SMESHOp::OpVolume:
|
case SMESHOp::OpVolume:
|
||||||
|
case SMESHOp::OpScaledJacobian:
|
||||||
case SMESHOp::OpMaxElementLength3D:
|
case SMESHOp::OpMaxElementLength3D:
|
||||||
case SMESHOp::OpBareBorderVolume:
|
case SMESHOp::OpBareBorderVolume:
|
||||||
case SMESHOp::OpOverConstrainedVolume:
|
case SMESHOp::OpOverConstrainedVolume:
|
||||||
@ -4213,6 +4217,7 @@ void SMESHGUI::initialize( CAM_Application* app )
|
|||||||
createSMESHAction( SMESHOp::OpBareBorderVolume, "BARE_BORDER_VOLUME", "ICON_BARE_BORDER_VOLUME", 0, true );
|
createSMESHAction( SMESHOp::OpBareBorderVolume, "BARE_BORDER_VOLUME", "ICON_BARE_BORDER_VOLUME", 0, true );
|
||||||
createSMESHAction( SMESHOp::OpOverConstrainedVolume, "OVER_CONSTRAINED_VOLUME", "ICON_OVER_CONSTRAINED_VOLUME", 0, true );
|
createSMESHAction( SMESHOp::OpOverConstrainedVolume, "OVER_CONSTRAINED_VOLUME", "ICON_OVER_CONSTRAINED_VOLUME", 0, true );
|
||||||
createSMESHAction( SMESHOp::OpEqualVolume, "EQUAL_VOLUME", "ICON_EQUAL_VOLUME", 0, true );
|
createSMESHAction( SMESHOp::OpEqualVolume, "EQUAL_VOLUME", "ICON_EQUAL_VOLUME", 0, true );
|
||||||
|
createSMESHAction( SMESHOp::OpScaledJacobian, "SCALED_JACOBIAN", "ICON_SCALED_JACOBIAN", 0, true );
|
||||||
createSMESHAction( SMESHOp::OpOverallMeshQuality, "OVERALL_MESH_QUALITY", "ICON_OVL_MESH_QUALITY" );
|
createSMESHAction( SMESHOp::OpOverallMeshQuality, "OVERALL_MESH_QUALITY", "ICON_OVL_MESH_QUALITY" );
|
||||||
|
|
||||||
createSMESHAction( SMESHOp::OpNode, "NODE", "ICON_DLG_NODE" );
|
createSMESHAction( SMESHOp::OpNode, "NODE", "ICON_DLG_NODE" );
|
||||||
@ -4353,7 +4358,7 @@ void SMESHGUI::initialize( CAM_Application* app )
|
|||||||
<< SMESHOp::OpOverConstrainedFace << SMESHOp::OpEqualFace // face controls
|
<< SMESHOp::OpOverConstrainedFace << SMESHOp::OpEqualFace // face controls
|
||||||
<< SMESHOp::OpAspectRatio3D << SMESHOp::OpVolume
|
<< SMESHOp::OpAspectRatio3D << SMESHOp::OpVolume
|
||||||
<< SMESHOp::OpMaxElementLength3D << SMESHOp::OpBareBorderVolume
|
<< SMESHOp::OpMaxElementLength3D << SMESHOp::OpBareBorderVolume
|
||||||
<< SMESHOp::OpOverConstrainedVolume << SMESHOp::OpEqualVolume; // volume controls
|
<< SMESHOp::OpOverConstrainedVolume << SMESHOp::OpEqualVolume << SMESHOp::OpScaledJacobian; // volume controls
|
||||||
QActionGroup* aCtrlGroup = new QActionGroup( application()->desktop() );
|
QActionGroup* aCtrlGroup = new QActionGroup( application()->desktop() );
|
||||||
aCtrlGroup->setExclusive( true );
|
aCtrlGroup->setExclusive( true );
|
||||||
for( int i = 0; i < aCtrlActions.size(); i++ )
|
for( int i = 0; i < aCtrlActions.size(); i++ )
|
||||||
@ -4469,6 +4474,7 @@ void SMESHGUI::initialize( CAM_Application* app )
|
|||||||
createMenu( SMESHOp::OpBareBorderVolume, volumeId, -1 );
|
createMenu( SMESHOp::OpBareBorderVolume, volumeId, -1 );
|
||||||
createMenu( SMESHOp::OpOverConstrainedVolume, volumeId, -1 );
|
createMenu( SMESHOp::OpOverConstrainedVolume, volumeId, -1 );
|
||||||
createMenu( SMESHOp::OpEqualVolume, volumeId, -1 );
|
createMenu( SMESHOp::OpEqualVolume, volumeId, -1 );
|
||||||
|
createMenu( SMESHOp::OpScaledJacobian, volumeId, -1 );
|
||||||
createMenu( separator(), ctrlId, -1 );
|
createMenu( separator(), ctrlId, -1 );
|
||||||
createMenu( SMESHOp::OpReset, ctrlId, -1 );
|
createMenu( SMESHOp::OpReset, ctrlId, -1 );
|
||||||
createMenu( separator(), ctrlId, -1 );
|
createMenu( separator(), ctrlId, -1 );
|
||||||
@ -4626,6 +4632,7 @@ void SMESHGUI::initialize( CAM_Application* app )
|
|||||||
createTool( SMESHOp::OpBareBorderVolume, ctrl3dTb );
|
createTool( SMESHOp::OpBareBorderVolume, ctrl3dTb );
|
||||||
createTool( SMESHOp::OpOverConstrainedVolume, ctrl3dTb );
|
createTool( SMESHOp::OpOverConstrainedVolume, ctrl3dTb );
|
||||||
createTool( SMESHOp::OpEqualVolume, ctrl3dTb );
|
createTool( SMESHOp::OpEqualVolume, ctrl3dTb );
|
||||||
|
createTool( SMESHOp::OpScaledJacobian, ctrl3dTb );
|
||||||
|
|
||||||
int addElemTb = createTool( tr( "TB_ADD" ), QString( "SMESHAddElementToolbar" ) ) ;
|
int addElemTb = createTool( tr( "TB_ADD" ), QString( "SMESHAddElementToolbar" ) ) ;
|
||||||
createTool( SMESHOp::OpNode, addElemTb );
|
createTool( SMESHOp::OpNode, addElemTb );
|
||||||
@ -5103,6 +5110,10 @@ void SMESHGUI::initialize( CAM_Application* app )
|
|||||||
popupMgr()->setRule( action( SMESHOp::OpEqualVolume ), aMeshInVtkHasVolumes, QtxPopupMgr::VisibleRule );
|
popupMgr()->setRule( action( SMESHOp::OpEqualVolume ), aMeshInVtkHasVolumes, QtxPopupMgr::VisibleRule );
|
||||||
popupMgr()->setRule( action( SMESHOp::OpEqualVolume ), "controlMode = 'eCoincidentElems3D'", QtxPopupMgr::ToggleRule );
|
popupMgr()->setRule( action( SMESHOp::OpEqualVolume ), "controlMode = 'eCoincidentElems3D'", QtxPopupMgr::ToggleRule );
|
||||||
|
|
||||||
|
popupMgr()->insert ( action( SMESHOp::OpScaledJacobian ), aSubId, -1 );
|
||||||
|
popupMgr()->setRule( action( SMESHOp::OpScaledJacobian ), aMeshInVtkHasVolumes, QtxPopupMgr::VisibleRule );
|
||||||
|
popupMgr()->setRule( action( SMESHOp::OpScaledJacobian ), "controlMode = 'eScaledJacobian'", QtxPopupMgr::ToggleRule );
|
||||||
|
|
||||||
popupMgr()->insert( separator(), anId, -1 );
|
popupMgr()->insert( separator(), anId, -1 );
|
||||||
|
|
||||||
popupMgr()->insert( action( SMESHOp::OpShowScalarBar ), anId, -1 );
|
popupMgr()->insert( action( SMESHOp::OpShowScalarBar ), anId, -1 );
|
||||||
|
@ -1568,6 +1568,7 @@ void SMESHGUI_FilterTable::updateAdditionalWidget()
|
|||||||
aCriterion == SMESH::FT_Skew ||
|
aCriterion == SMESH::FT_Skew ||
|
||||||
aCriterion == SMESH::FT_Area ||
|
aCriterion == SMESH::FT_Area ||
|
||||||
aCriterion == SMESH::FT_Volume3D ||
|
aCriterion == SMESH::FT_Volume3D ||
|
||||||
|
aCriterion == SMESH::FT_ScaledJacobian ||
|
||||||
aCriterion == SMESH::FT_MaxElementLength2D ||
|
aCriterion == SMESH::FT_MaxElementLength2D ||
|
||||||
aCriterion == SMESH::FT_MaxElementLength3D ||
|
aCriterion == SMESH::FT_MaxElementLength3D ||
|
||||||
aCriterion == SMESH::FT_Length ||
|
aCriterion == SMESH::FT_Length ||
|
||||||
@ -1816,6 +1817,7 @@ void SMESHGUI_FilterTable::onCriterionChanged (const int row, const int /*col*/,
|
|||||||
case SMESH::FT_Skew:
|
case SMESH::FT_Skew:
|
||||||
case SMESH::FT_Area:
|
case SMESH::FT_Area:
|
||||||
case SMESH::FT_Volume3D:
|
case SMESH::FT_Volume3D:
|
||||||
|
case SMESH::FT_ScaledJacobian:
|
||||||
case SMESH::FT_MaxElementLength2D:
|
case SMESH::FT_MaxElementLength2D:
|
||||||
case SMESH::FT_MaxElementLength3D: anIsDoubleCriterion = true; break;
|
case SMESH::FT_MaxElementLength3D: anIsDoubleCriterion = true; break;
|
||||||
|
|
||||||
@ -2284,6 +2286,7 @@ const QMap<int, QString>& SMESHGUI_FilterTable::getCriteria (const int theType)
|
|||||||
aCriteria[ SMESH::FT_EqualVolumes ] = tr("EQUAL_VOLUME");
|
aCriteria[ SMESH::FT_EqualVolumes ] = tr("EQUAL_VOLUME");
|
||||||
aCriteria[ SMESH::FT_EntityType ] = tr("ENTITY_TYPE");
|
aCriteria[ SMESH::FT_EntityType ] = tr("ENTITY_TYPE");
|
||||||
aCriteria[ SMESH::FT_ConnectedElements ] = tr("CONNECTED_ELEMS");
|
aCriteria[ SMESH::FT_ConnectedElements ] = tr("CONNECTED_ELEMS");
|
||||||
|
aCriteria[ SMESH::FT_ScaledJacobian ] = tr("SCALED_JACOBIAN");
|
||||||
}
|
}
|
||||||
return aCriteria;
|
return aCriteria;
|
||||||
}
|
}
|
||||||
|
@ -1684,6 +1684,8 @@ QString SMESHGUI_ElemInfo::ctrl2str( int control )
|
|||||||
title = tr( "AREA_ELEMENTS" ); break;
|
title = tr( "AREA_ELEMENTS" ); break;
|
||||||
case SMESH::FT_Volume3D:
|
case SMESH::FT_Volume3D:
|
||||||
title = tr( "VOLUME_3D_ELEMENTS" ); break;
|
title = tr( "VOLUME_3D_ELEMENTS" ); break;
|
||||||
|
case SMESH::FT_ScaledJacobian:
|
||||||
|
title = tr( "SCALED_JACOBIAN" ); break;
|
||||||
case SMESH::FT_MaxElementLength2D:
|
case SMESH::FT_MaxElementLength2D:
|
||||||
title = tr( "MAX_ELEMENT_LENGTH_2D" ); break;
|
title = tr( "MAX_ELEMENT_LENGTH_2D" ); break;
|
||||||
case SMESH::FT_MaxElementLength3D:
|
case SMESH::FT_MaxElementLength3D:
|
||||||
|
@ -122,6 +122,7 @@ namespace SMESHOp {
|
|||||||
OpBareBorderVolume = 3303, // MENU CONTROLS - VOLUMES WITH BARE BORDER
|
OpBareBorderVolume = 3303, // MENU CONTROLS - VOLUMES WITH BARE BORDER
|
||||||
OpOverConstrainedVolume = 3304, // MENU CONTROLS - OVERCONSTRAINED VOLUMES
|
OpOverConstrainedVolume = 3304, // MENU CONTROLS - OVERCONSTRAINED VOLUMES
|
||||||
OpEqualVolume = 3305, // MENU CONTROLS - DOUBLE VOLUMES
|
OpEqualVolume = 3305, // MENU CONTROLS - DOUBLE VOLUMES
|
||||||
|
OpScaledJacobian = 3306, // MENU CONTROLS - SCALED JACOBIAN
|
||||||
OpOverallMeshQuality = 3400, // MENU CONTROLS - OVERALL MESH QUALITY
|
OpOverallMeshQuality = 3400, // MENU CONTROLS - OVERALL MESH QUALITY
|
||||||
// Modification -------------------//--------------------------------
|
// Modification -------------------//--------------------------------
|
||||||
OpNode = 4000, // MENU MODIFICATION - ADD - NODE
|
OpNode = 4000, // MENU MODIFICATION - ADD - NODE
|
||||||
|
@ -371,6 +371,7 @@ QString SMESHGUI_Selection::controlMode( int ind ) const
|
|||||||
case SMESH_Actor::eMultiConnection2D: mode = "eMultiConnection2D"; break;
|
case SMESH_Actor::eMultiConnection2D: mode = "eMultiConnection2D"; break;
|
||||||
case SMESH_Actor::eArea: mode = "eArea"; break;
|
case SMESH_Actor::eArea: mode = "eArea"; break;
|
||||||
case SMESH_Actor::eVolume3D: mode = "eVolume3D"; break;
|
case SMESH_Actor::eVolume3D: mode = "eVolume3D"; break;
|
||||||
|
case SMESH_Actor::eScaledJacobian: mode = "eScaledJacobian"; break;
|
||||||
case SMESH_Actor::eMaxElementLength2D: mode = "eMaxElementLength2D"; break;
|
case SMESH_Actor::eMaxElementLength2D: mode = "eMaxElementLength2D"; break;
|
||||||
case SMESH_Actor::eMaxElementLength3D: mode = "eMaxElementLength3D"; break;
|
case SMESH_Actor::eMaxElementLength3D: mode = "eMaxElementLength3D"; break;
|
||||||
case SMESH_Actor::eTaper: mode = "eTaper"; break;
|
case SMESH_Actor::eTaper: mode = "eTaper"; break;
|
||||||
@ -429,6 +430,7 @@ bool SMESHGUI_Selection::isNumFunctor( int ind ) const
|
|||||||
case SMESH_Actor::eMultiConnection2D:
|
case SMESH_Actor::eMultiConnection2D:
|
||||||
case SMESH_Actor::eArea:
|
case SMESH_Actor::eArea:
|
||||||
case SMESH_Actor::eVolume3D:
|
case SMESH_Actor::eVolume3D:
|
||||||
|
case SMESH_Actor::eScaledJacobian:
|
||||||
case SMESH_Actor::eMaxElementLength2D:
|
case SMESH_Actor::eMaxElementLength2D:
|
||||||
case SMESH_Actor::eMaxElementLength3D:
|
case SMESH_Actor::eMaxElementLength3D:
|
||||||
case SMESH_Actor::eTaper:
|
case SMESH_Actor::eTaper:
|
||||||
|
@ -941,6 +941,9 @@ bool SMESH::SelectionProxy::elementControl( int id, int control, double precisio
|
|||||||
case SMESH::FT_BallDiameter:
|
case SMESH::FT_BallDiameter:
|
||||||
functor.reset( new SMESH::Controls::BallDiameter() );
|
functor.reset( new SMESH::Controls::BallDiameter() );
|
||||||
break;
|
break;
|
||||||
|
case SMESH::FT_ScaledJacobian:
|
||||||
|
functor.reset( new SMESH::Controls::ScaledJacobian() );
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1009,6 +1012,9 @@ bool SMESH::SelectionProxy::elementControl( int id, int control, double precisio
|
|||||||
case SMESH::FT_BallDiameter:
|
case SMESH::FT_BallDiameter:
|
||||||
functor = manager->CreateBallDiameter();
|
functor = manager->CreateBallDiameter();
|
||||||
break;
|
break;
|
||||||
|
case SMESH::FT_ScaledJacobian:
|
||||||
|
functor = manager->CreateScaledJacobian();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -611,6 +611,10 @@
|
|||||||
<source>ICON_VOLUME_3D</source>
|
<source>ICON_VOLUME_3D</source>
|
||||||
<translation>mesh_volume_3d.png</translation>
|
<translation>mesh_volume_3d.png</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>ICON_SCALED_JACOBIAN</source>
|
||||||
|
<translation>mesh_scaled_jacobian.png</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>ICON_BARE_BORDER_VOLUME</source>
|
<source>ICON_BARE_BORDER_VOLUME</source>
|
||||||
<translation>bare_border_volume.png</translation>
|
<translation>bare_border_volume.png</translation>
|
||||||
|
@ -95,6 +95,10 @@
|
|||||||
<source>BARE_BORDER_VOLUME</source>
|
<source>BARE_BORDER_VOLUME</source>
|
||||||
<translation>Volumes with bare border</translation>
|
<translation>Volumes with bare border</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>SCALED_JACOBIAN</source>
|
||||||
|
<translation>Scaled Jacobian</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>OVER_CONSTRAINED_VOLUME</source>
|
<source>OVER_CONSTRAINED_VOLUME</source>
|
||||||
<translation>Over-constrained volumes</translation>
|
<translation>Over-constrained volumes</translation>
|
||||||
@ -1316,6 +1320,10 @@
|
|||||||
<source>MEN_VOLUME_3D</source>
|
<source>MEN_VOLUME_3D</source>
|
||||||
<translation>Volume</translation>
|
<translation>Volume</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>MEN_SCALED_JACOBIAN</source>
|
||||||
|
<translation>Scaled Jacobian</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>MEN_WARP</source>
|
<source>MEN_WARP</source>
|
||||||
<translation>Warping Angle</translation>
|
<translation>Warping Angle</translation>
|
||||||
@ -3912,6 +3920,10 @@ Use Display Entity menu command to show them.
|
|||||||
<source>STB_VOLUME_3D</source>
|
<source>STB_VOLUME_3D</source>
|
||||||
<translation>Volume</translation>
|
<translation>Volume</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>STB_SCALED_JACOBIAN</source>
|
||||||
|
<translation>Scaled Jacobian</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>STB_WARP</source>
|
<source>STB_WARP</source>
|
||||||
<translation>Warping angle</translation>
|
<translation>Warping angle</translation>
|
||||||
@ -4624,6 +4636,10 @@ Use Display Entity menu command to show them.
|
|||||||
<source>TOP_VOLUME_3D</source>
|
<source>TOP_VOLUME_3D</source>
|
||||||
<translation>Volume</translation>
|
<translation>Volume</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>TOP_SCALED_JACOBIAN</source>
|
||||||
|
<translation>Scaled Jacobian</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>TOP_WARP</source>
|
<source>TOP_WARP</source>
|
||||||
<translation>Warping angle</translation>
|
<translation>Warping angle</translation>
|
||||||
@ -6496,6 +6512,10 @@ Please enter correct value and try again</translation>
|
|||||||
<source>VOLUME_3D</source>
|
<source>VOLUME_3D</source>
|
||||||
<translation>Volume</translation>
|
<translation>Volume</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>SCALED_JACOBIAN</source>
|
||||||
|
<translation>Scaled Jacobian</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>WARPING</source>
|
<source>WARPING</source>
|
||||||
<translation>Warping</translation>
|
<translation>Warping</translation>
|
||||||
|
@ -99,6 +99,10 @@
|
|||||||
<source>OVER_CONSTRAINED_VOLUME</source>
|
<source>OVER_CONSTRAINED_VOLUME</source>
|
||||||
<translation>Volumes sur-contraints</translation>
|
<translation>Volumes sur-contraints</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>SCALED_JACOBIAN</source>
|
||||||
|
<translation>Jacobien normalisé</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>MIN_DIAG_ELEMENTS</source>
|
<source>MIN_DIAG_ELEMENTS</source>
|
||||||
<translation>Diagonale minimum</translation>
|
<translation>Diagonale minimum</translation>
|
||||||
@ -1316,6 +1320,10 @@
|
|||||||
<source>MEN_VOLUME_3D</source>
|
<source>MEN_VOLUME_3D</source>
|
||||||
<translation>Volume</translation>
|
<translation>Volume</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>MEN_SCALED_JACOBIAN</source>
|
||||||
|
<translation>Jacobien normalisé</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>MEN_WARP</source>
|
<source>MEN_WARP</source>
|
||||||
<translation>Angle de déformation</translation>
|
<translation>Angle de déformation</translation>
|
||||||
@ -3911,6 +3919,10 @@ Utilisez le menu "Visualiser une entité" pour les afficher.
|
|||||||
<source>STB_VOLUME_3D</source>
|
<source>STB_VOLUME_3D</source>
|
||||||
<translation>Volume</translation>
|
<translation>Volume</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>STB_SCALED_JACOBIAN</source>
|
||||||
|
<translation>Jacobien normalisé</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>STB_WARP</source>
|
<source>STB_WARP</source>
|
||||||
<translation>Angle de déformation</translation>
|
<translation>Angle de déformation</translation>
|
||||||
@ -4623,6 +4635,10 @@ Utilisez le menu "Visualiser une entité" pour les afficher.
|
|||||||
<source>TOP_VOLUME_3D</source>
|
<source>TOP_VOLUME_3D</source>
|
||||||
<translation>Volume</translation>
|
<translation>Volume</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>TOP_SCALED_JACOBIAN</source>
|
||||||
|
<translation>Jacobien normalisé</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>TOP_WARP</source>
|
<source>TOP_WARP</source>
|
||||||
<translation>Angle de déformation</translation>
|
<translation>Angle de déformation</translation>
|
||||||
|
@ -71,6 +71,10 @@
|
|||||||
<source>NODE_CONNECTIVITY_NB</source>
|
<source>NODE_CONNECTIVITY_NB</source>
|
||||||
<translation>節点接続番号</translation>
|
<translation>節点接続番号</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>SCALED_JACOBIAN</source>
|
||||||
|
<translation>スケーリングされたヤコビアン</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>FREE_EDGES</source>
|
<source>FREE_EDGES</source>
|
||||||
<translation>フリーエッジ</translation>
|
<translation>フリーエッジ</translation>
|
||||||
@ -1119,6 +1123,10 @@
|
|||||||
<source>MEN_VOLUME_3D</source>
|
<source>MEN_VOLUME_3D</source>
|
||||||
<translation>ボリューム</translation>
|
<translation>ボリューム</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>MEN_SCALED_JACOBIAN</source>
|
||||||
|
<translation>スケーリングされたヤコビアン</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>MEN_WARP</source>
|
<source>MEN_WARP</source>
|
||||||
<translation>変形の角度</translation>
|
<translation>変形の角度</translation>
|
||||||
@ -3519,6 +3527,10 @@
|
|||||||
<source>STB_VOLUMES</source>
|
<source>STB_VOLUMES</source>
|
||||||
<translation>ボリューム</translation>
|
<translation>ボリューム</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>STB_SCALED_JACOBIAN</source>
|
||||||
|
<translation>スケーリングされたヤコビアン</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>STB_VOLUME_3D</source>
|
<source>STB_VOLUME_3D</source>
|
||||||
<translation>ボリューム</translation>
|
<translation>ボリューム</translation>
|
||||||
@ -4183,6 +4195,10 @@
|
|||||||
<source>TOP_VOLUMES</source>
|
<source>TOP_VOLUMES</source>
|
||||||
<translation>ボリューム</translation>
|
<translation>ボリューム</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>TOP_SCALED_JACOBIAN</source>
|
||||||
|
<translation>スケーリングされたヤコビアン</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>TOP_VOLUME_3D</source>
|
<source>TOP_VOLUME_3D</source>
|
||||||
<translation>ボリューム</translation>
|
<translation>ボリューム</translation>
|
||||||
@ -5921,7 +5937,7 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>VOLUME_3D</source>
|
<source>VOLUME_3D</source>
|
||||||
<translation>ボリューム</translation>
|
<translation>スケーリングされたヤコビアン</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>WARPING</source>
|
<source>WARPING</source>
|
||||||
|
@ -301,6 +301,8 @@ namespace {
|
|||||||
// - FT_Deflection2D = 22
|
// - FT_Deflection2D = 22
|
||||||
// v 9.3.0: FT_Undefined == 50, new items:
|
// v 9.3.0: FT_Undefined == 50, new items:
|
||||||
// - FT_Length3D = 22
|
// - FT_Length3D = 22
|
||||||
|
// v 9.12.0: FT_Undefined == 51, new items:
|
||||||
|
// - FT_ScaledJacobian = 8
|
||||||
//
|
//
|
||||||
// It's necessary to continue recording this history and to fill
|
// It's necessary to continue recording this history and to fill
|
||||||
// undef2newItems (see below) accordingly.
|
// undef2newItems (see below) accordingly.
|
||||||
@ -325,6 +327,7 @@ namespace {
|
|||||||
undef2newItems[ 48 ].push_back( 22 );
|
undef2newItems[ 48 ].push_back( 22 );
|
||||||
undef2newItems[ 49 ].push_back( 22 );
|
undef2newItems[ 49 ].push_back( 22 );
|
||||||
undef2newItems[ 50 ].push_back( 22 );
|
undef2newItems[ 50 ].push_back( 22 );
|
||||||
|
undef2newItems[ 51 ].push_back( 8 );
|
||||||
|
|
||||||
ASSERT( undef2newItems.rbegin()->first == SMESH::FT_Undefined );
|
ASSERT( undef2newItems.rbegin()->first == SMESH::FT_Undefined );
|
||||||
}
|
}
|
||||||
|
@ -460,6 +460,21 @@ namespace SMESH {
|
|||||||
return SMESH::FT_Volume3D;
|
return SMESH::FT_Volume3D;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Class : ScaledJacobian_i
|
||||||
|
Description : Functor for calculating volume of 3D element
|
||||||
|
*/
|
||||||
|
ScaledJacobian_i::ScaledJacobian_i()
|
||||||
|
{
|
||||||
|
myNumericalFunctorPtr.reset( new Controls::ScaledJacobian() );
|
||||||
|
myFunctorPtr = myNumericalFunctorPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctorType ScaledJacobian_i::GetFunctorType()
|
||||||
|
{
|
||||||
|
return SMESH::FT_ScaledJacobian;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Class : MaxElementLength2D_i
|
Class : MaxElementLength2D_i
|
||||||
Description : Functor for calculating maximum length of 2D element
|
Description : Functor for calculating maximum length of 2D element
|
||||||
@ -2126,6 +2141,13 @@ namespace SMESH {
|
|||||||
return anObj._retn();
|
return anObj._retn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScaledJacobian_ptr FilterManager_i::CreateScaledJacobian()
|
||||||
|
{
|
||||||
|
SMESH::ScaledJacobian_i* aServant = new SMESH::ScaledJacobian_i();
|
||||||
|
SMESH::ScaledJacobian_var anObj = aServant->_this();
|
||||||
|
TPythonDump()<<aServant<<" = "<<this<<".CreateScaledJacobian()";
|
||||||
|
return anObj._retn();
|
||||||
|
}
|
||||||
|
|
||||||
MaxElementLength2D_ptr FilterManager_i::CreateMaxElementLength2D()
|
MaxElementLength2D_ptr FilterManager_i::CreateMaxElementLength2D()
|
||||||
{
|
{
|
||||||
@ -3076,6 +3098,9 @@ namespace SMESH {
|
|||||||
case SMESH::FT_NodeConnectivityNumber:
|
case SMESH::FT_NodeConnectivityNumber:
|
||||||
aFunctor = aFilterMgr->CreateNodeConnectivityNumber();
|
aFunctor = aFilterMgr->CreateNodeConnectivityNumber();
|
||||||
break;
|
break;
|
||||||
|
case SMESH::FT_ScaledJacobian:
|
||||||
|
aFunctor = aFilterMgr->CreateScaledJacobian();
|
||||||
|
break;
|
||||||
|
|
||||||
// Predicates
|
// Predicates
|
||||||
|
|
||||||
@ -3512,6 +3537,7 @@ namespace SMESH {
|
|||||||
case FT_Skew : return "Skew";
|
case FT_Skew : return "Skew";
|
||||||
case FT_Area : return "Area";
|
case FT_Area : return "Area";
|
||||||
case FT_Volume3D : return "Volume3D";
|
case FT_Volume3D : return "Volume3D";
|
||||||
|
case FT_ScaledJacobian : return "ScaledJacobian";
|
||||||
case FT_MaxElementLength2D : return "Max element length 2D";
|
case FT_MaxElementLength2D : return "Max element length 2D";
|
||||||
case FT_MaxElementLength3D : return "Max element length 3D";
|
case FT_MaxElementLength3D : return "Max element length 3D";
|
||||||
case FT_BelongToMeshGroup : return "Belong to Mesh Group";
|
case FT_BelongToMeshGroup : return "Belong to Mesh Group";
|
||||||
@ -3568,6 +3594,7 @@ namespace SMESH {
|
|||||||
else if ( theStr.equals( "Skew" ) ) return FT_Skew;
|
else if ( theStr.equals( "Skew" ) ) return FT_Skew;
|
||||||
else if ( theStr.equals( "Area" ) ) return FT_Area;
|
else if ( theStr.equals( "Area" ) ) return FT_Area;
|
||||||
else if ( theStr.equals( "Volume3D" ) ) return FT_Volume3D;
|
else if ( theStr.equals( "Volume3D" ) ) return FT_Volume3D;
|
||||||
|
else if ( theStr.equals( "ScaledJacobian" ) ) return FT_ScaledJacobian;
|
||||||
else if ( theStr.equals( "Max element length 2D" ) ) return FT_MaxElementLength2D;
|
else if ( theStr.equals( "Max element length 2D" ) ) return FT_MaxElementLength2D;
|
||||||
else if ( theStr.equals( "Max element length 3D" ) ) return FT_MaxElementLength3D;
|
else if ( theStr.equals( "Max element length 3D" ) ) return FT_MaxElementLength3D;
|
||||||
else if ( theStr.equals( "Belong to Mesh Group" ) ) return FT_BelongToMeshGroup;
|
else if ( theStr.equals( "Belong to Mesh Group" ) ) return FT_BelongToMeshGroup;
|
||||||
@ -4141,6 +4168,7 @@ namespace SMESH {
|
|||||||
"FT_Skew",
|
"FT_Skew",
|
||||||
"FT_Area",
|
"FT_Area",
|
||||||
"FT_Volume3D",
|
"FT_Volume3D",
|
||||||
|
"FT_ScaledJacobian",
|
||||||
"FT_MaxElementLength2D",
|
"FT_MaxElementLength2D",
|
||||||
"FT_MaxElementLength3D",
|
"FT_MaxElementLength3D",
|
||||||
"FT_FreeBorders",
|
"FT_FreeBorders",
|
||||||
|
@ -352,6 +352,18 @@ namespace SMESH
|
|||||||
FunctorType GetFunctorType();
|
FunctorType GetFunctorType();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Class : ScaledJacobian_i
|
||||||
|
Description : Functor returning the scaled jacobian
|
||||||
|
*/
|
||||||
|
class SMESH_I_EXPORT ScaledJacobian_i: public virtual POA_SMESH::ScaledJacobian,
|
||||||
|
public virtual NumericalFunctor_i
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ScaledJacobian_i();
|
||||||
|
FunctorType GetFunctorType();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
PREDICATES
|
PREDICATES
|
||||||
@ -1113,6 +1125,7 @@ namespace SMESH
|
|||||||
Skew_ptr CreateSkew();
|
Skew_ptr CreateSkew();
|
||||||
Area_ptr CreateArea();
|
Area_ptr CreateArea();
|
||||||
Volume3D_ptr CreateVolume3D();
|
Volume3D_ptr CreateVolume3D();
|
||||||
|
ScaledJacobian_ptr CreateScaledJacobian();
|
||||||
MaxElementLength2D_ptr CreateMaxElementLength2D();
|
MaxElementLength2D_ptr CreateMaxElementLength2D();
|
||||||
MaxElementLength3D_ptr CreateMaxElementLength3D();
|
MaxElementLength3D_ptr CreateMaxElementLength3D();
|
||||||
Length_ptr CreateLength();
|
Length_ptr CreateLength();
|
||||||
|
@ -414,6 +414,7 @@ namespace SMESH
|
|||||||
case FT_Skew: myStream<< "aSkew"; break;
|
case FT_Skew: myStream<< "aSkew"; break;
|
||||||
case FT_Area: myStream<< "aArea"; break;
|
case FT_Area: myStream<< "aArea"; break;
|
||||||
case FT_Volume3D: myStream<< "aVolume3D"; break;
|
case FT_Volume3D: myStream<< "aVolume3D"; break;
|
||||||
|
case FT_ScaledJacobian: myStream<< "aScaledJacobian"; break;
|
||||||
case FT_MaxElementLength2D: myStream<< "aMaxElementLength2D"; break;
|
case FT_MaxElementLength2D: myStream<< "aMaxElementLength2D"; break;
|
||||||
case FT_MaxElementLength3D: myStream<< "aMaxElementLength3D"; break;
|
case FT_MaxElementLength3D: myStream<< "aMaxElementLength3D"; break;
|
||||||
case FT_FreeBorders: myStream<< "aFreeBorders"; break;
|
case FT_FreeBorders: myStream<< "aFreeBorders"; break;
|
||||||
|
@ -1233,6 +1233,8 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ):
|
|||||||
functor = aFilterMgr.CreateNodeConnectivityNumber()
|
functor = aFilterMgr.CreateNodeConnectivityNumber()
|
||||||
elif theCriterion == FT_BallDiameter:
|
elif theCriterion == FT_BallDiameter:
|
||||||
functor = aFilterMgr.CreateBallDiameter()
|
functor = aFilterMgr.CreateBallDiameter()
|
||||||
|
elif theCriterion == FT_ScaledJacobian:
|
||||||
|
functor = aFilterMgr.CreateScaledJacobian()
|
||||||
else:
|
else:
|
||||||
print("Error: given parameter is not numerical functor type.")
|
print("Error: given parameter is not numerical functor type.")
|
||||||
aFilterMgr.UnRegister()
|
aFilterMgr.UnRegister()
|
||||||
@ -7469,6 +7471,19 @@ class Mesh(metaclass = MeshMeta):
|
|||||||
|
|
||||||
return self.FunctorValue(SMESH.FT_Skew, elemId)
|
return self.FunctorValue(SMESH.FT_Skew, elemId)
|
||||||
|
|
||||||
|
def GetScaledJacobian(self, elemId):
|
||||||
|
"""
|
||||||
|
Get the scaled jacobian of 3D element id
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
elemId: mesh element ID
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
the scaled jacobian
|
||||||
|
"""
|
||||||
|
|
||||||
|
return self.FunctorValue(SMESH.FT_ScaledJacobian, elemId)
|
||||||
|
|
||||||
def GetMinMax(self, funType, meshPart=None):
|
def GetMinMax(self, funType, meshPart=None):
|
||||||
"""
|
"""
|
||||||
Return minimal and maximal value of a given functor.
|
Return minimal and maximal value of a given functor.
|
||||||
|
144
test/SMESH_controls_scaled_jacobian.py
Normal file
144
test/SMESH_controls_scaled_jacobian.py
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
# -*- coding: iso-8859-1 -*-
|
||||||
|
# Copyright (C) 2016-2023 CEA/DEN, EDF R&D
|
||||||
|
#
|
||||||
|
# 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 : SMESH_controls_scaled_jacobian.py
|
||||||
|
# Author : Cesar Conopoima
|
||||||
|
# Module : SMESH
|
||||||
|
#
|
||||||
|
import salome
|
||||||
|
import math
|
||||||
|
salome.salome_init_without_session()
|
||||||
|
|
||||||
|
import GEOM
|
||||||
|
import SMESH
|
||||||
|
from salome.geom import geomBuilder
|
||||||
|
from salome.smesh import smeshBuilder
|
||||||
|
|
||||||
|
def assertWithDelta( refval, testvals, delta ):
|
||||||
|
return ( refval <= testvals+delta and refval >= testvals-delta )
|
||||||
|
|
||||||
|
geompy = geomBuilder.New()
|
||||||
|
smesh_builder = smeshBuilder.New()
|
||||||
|
|
||||||
|
Box_1 = geompy.MakeBoxDXDYDZ(10, 10, 10)
|
||||||
|
geompy.addToStudy( Box_1, 'Box_1' )
|
||||||
|
|
||||||
|
smesh = smeshBuilder.New()
|
||||||
|
|
||||||
|
Mesh_1 = smesh.Mesh(Box_1,'Mesh_1')
|
||||||
|
NETGEN_1D_2D_3D = Mesh_1.Tetrahedron(algo=smeshBuilder.NETGEN_1D2D3D)
|
||||||
|
Done = Mesh_1.Compute()
|
||||||
|
|
||||||
|
if not Done:
|
||||||
|
raise Exception("Error when computing NETGEN_1D2D3D Mesh for quality control test")
|
||||||
|
|
||||||
|
#For tetra elements
|
||||||
|
perfect = 1.0
|
||||||
|
externals = math.sqrt( 2.0 )/2.0
|
||||||
|
notPerfectElements = smesh.GetFilter(SMESH.VOLUME, SMESH.FT_ScaledJacobian, SMESH.FT_LessThan, perfect - 1e-12 )
|
||||||
|
perfectElements = smesh.GetFilter(SMESH.VOLUME, SMESH.FT_ScaledJacobian, SMESH.FT_EqualTo, perfect )
|
||||||
|
externalElements = smesh.GetFilter(SMESH.VOLUME, SMESH.FT_ScaledJacobian, SMESH.FT_EqualTo, externals )
|
||||||
|
|
||||||
|
notPerfectIds = Mesh_1.GetIdsFromFilter(notPerfectElements)
|
||||||
|
perfectIds = Mesh_1.GetIdsFromFilter(perfectElements)
|
||||||
|
externalsIds = Mesh_1.GetIdsFromFilter(externalElements)
|
||||||
|
|
||||||
|
assert( len(notPerfectIds) == 4 )
|
||||||
|
assert( len(perfectIds) == 1 )
|
||||||
|
assert( len(externalsIds) == 4 )
|
||||||
|
|
||||||
|
# Test GetScaledJacobian by elementId
|
||||||
|
for id in range(len(perfectIds)):
|
||||||
|
assert( assertWithDelta( perfect, Mesh_1.GetScaledJacobian( perfectIds[ id ] ), 1e-12) )
|
||||||
|
|
||||||
|
for id in range(len(externalsIds)):
|
||||||
|
assert( assertWithDelta( externals, Mesh_1.GetScaledJacobian( externalsIds[ id ] ), 1e-12) )
|
||||||
|
|
||||||
|
#For hexa elements
|
||||||
|
Mesh_2 = smesh.Mesh(Box_1,'Mesh_2')
|
||||||
|
Cartesian_3D = Mesh_2.BodyFitted()
|
||||||
|
Body_Fitting_Parameters_1 = Cartesian_3D.SetGrid([ [ '5.0' ], [ 0, 1 ]],[ [ '5.0' ], [ 0, 1 ]],[ [ '5.0' ], [ 0, 1 ]],4,0)
|
||||||
|
Done = Mesh_2.Compute()
|
||||||
|
|
||||||
|
if not Done:
|
||||||
|
raise Exception("Error when computing BodyFitted Mesh for quality control test")
|
||||||
|
|
||||||
|
notPerfectIds = Mesh_2.GetIdsFromFilter(notPerfectElements)
|
||||||
|
perfectIds = Mesh_2.GetIdsFromFilter(perfectElements)
|
||||||
|
|
||||||
|
assert( len(notPerfectIds) == 0 )
|
||||||
|
assert( len(perfectIds) == 8 )
|
||||||
|
|
||||||
|
# Test GetScaledJacobian by elementId
|
||||||
|
for id in range(len(perfectIds)):
|
||||||
|
assert( assertWithDelta( perfect, Mesh_2.GetScaledJacobian( perfectIds[ id ] ), 1e-12) )
|
||||||
|
|
||||||
|
#For hexa elements with poor quality
|
||||||
|
Mesh_3 = smesh.Mesh(Box_1,'Mesh_3')
|
||||||
|
Cartesian_3D = Mesh_3.BodyFitted()
|
||||||
|
Body_Fitting_Parameters_1 = Cartesian_3D.SetGrid([ [ '5.0' ], [ 0, 1 ]],[ [ '5.0' ], [ 0, 1 ]],[ [ '5.0' ], [ 0, 1 ]],4,0)
|
||||||
|
Body_Fitting_Parameters_1.SetAxesDirs( SMESH.DirStruct( SMESH.PointStruct ( 1, 0, 1 )), SMESH.DirStruct( SMESH.PointStruct ( 0, 1, 0 )), SMESH.DirStruct( SMESH.PointStruct ( 0, 0, 1 )) )
|
||||||
|
Done = Mesh_3.Compute()
|
||||||
|
|
||||||
|
if not Done:
|
||||||
|
raise Exception("Error when computing BodyFitted Distorted Mesh for quality control test")
|
||||||
|
|
||||||
|
#Polyhedrons return zero scaled jacobian because of lack for a decomposition into simpler forms
|
||||||
|
Polys = 0.0
|
||||||
|
#Hexahedrons that are distorted by an angle of 45
|
||||||
|
# Scaled Jacobian which is a measure of elements distortion
|
||||||
|
# will return cos(45) = math.sqrt( 2.0 )/2.0
|
||||||
|
distorted = math.sqrt( 2.0 )/2.0
|
||||||
|
polysElements = smesh.GetFilter(SMESH.VOLUME, SMESH.FT_ScaledJacobian, SMESH.FT_EqualTo, Polys )
|
||||||
|
distortedElements = smesh.GetFilter(SMESH.VOLUME, SMESH.FT_ScaledJacobian, SMESH.FT_EqualTo, distorted )
|
||||||
|
|
||||||
|
polysIds = Mesh_3.GetIdsFromFilter(polysElements)
|
||||||
|
distortedIds = Mesh_3.GetIdsFromFilter(distortedElements)
|
||||||
|
|
||||||
|
assert( len(polysIds) == 4 )
|
||||||
|
assert( len(distortedIds) == 8 )
|
||||||
|
|
||||||
|
# Test GetScaledJacobian by elementId
|
||||||
|
for id in range(len(distortedIds)):
|
||||||
|
assert( assertWithDelta( distorted, Mesh_3.GetScaledJacobian( distortedIds[ id ] ), 1e-12 ) )
|
||||||
|
|
||||||
|
#Test the pentahedron
|
||||||
|
Mesh_4 = smesh.Mesh(Box_1,'Mesh_4')
|
||||||
|
Cartesian_3D = Mesh_4.BodyFitted()
|
||||||
|
Body_Fitting_Parameters_1 = Cartesian_3D.SetGrid([ [ '4' ], [ 0, 1 ]],[ [ '4' ], [ 0, 1 ]],[ [ '4' ], [ 0, 1 ]],4,0)
|
||||||
|
Body_Fitting_Parameters_1.SetAxesDirs( SMESH.DirStruct( SMESH.PointStruct ( 1, 0, 1 )), SMESH.DirStruct( SMESH.PointStruct ( 0, 1, 0 )), SMESH.DirStruct( SMESH.PointStruct ( 0, 0, 1 )) )
|
||||||
|
Body_Fitting_Parameters_1.SetSizeThreshold( 4 )
|
||||||
|
Body_Fitting_Parameters_1.SetToAddEdges( 0 )
|
||||||
|
Body_Fitting_Parameters_1.SetGridSpacing( [ '2' ], [ 0, 1 ], 0 )
|
||||||
|
Body_Fitting_Parameters_1.SetGridSpacing( [ '2' ], [ 0, 1 ], 1 )
|
||||||
|
Body_Fitting_Parameters_1.SetGridSpacing( [ '2' ], [ 0, 1 ], 2 )
|
||||||
|
Done = Mesh_4.Compute()
|
||||||
|
|
||||||
|
if not Done:
|
||||||
|
raise Exception("Error when computing BodyFitted Distorted Mesh for quality control test")
|
||||||
|
|
||||||
|
pentahedrons = 0.6
|
||||||
|
pentasAndPolys = smesh.GetFilter(SMESH.VOLUME, SMESH.FT_ScaledJacobian, SMESH.FT_LessThan, pentahedrons )
|
||||||
|
#Distorted hexas
|
||||||
|
|
||||||
|
polysIds = Mesh_4.GetIdsFromFilter(polysElements)
|
||||||
|
pentasAndPolysIds = Mesh_4.GetIdsFromFilter(pentasAndPolys)
|
||||||
|
|
||||||
|
assert( len(pentasAndPolysIds) - len(polysIds) == 10 )
|
@ -44,6 +44,7 @@ SET(BAD_TESTS
|
|||||||
SMESH_box3_tetra.py
|
SMESH_box3_tetra.py
|
||||||
SMESH_box_tetra.py
|
SMESH_box_tetra.py
|
||||||
SMESH_controls.py
|
SMESH_controls.py
|
||||||
|
SMESH_controls_scaled_jacobian.py
|
||||||
SMESH_fixation_netgen.py
|
SMESH_fixation_netgen.py
|
||||||
SMESH_fixation_tetra.py
|
SMESH_fixation_tetra.py
|
||||||
SMESH_flight_skin.py
|
SMESH_flight_skin.py
|
||||||
|
Loading…
Reference in New Issue
Block a user