diff --git a/doc/examples/filters_ex41.py b/doc/examples/filters_ex41.py new file mode 100644 index 000000000..30fec5452 --- /dev/null +++ b/doc/examples/filters_ex41.py @@ -0,0 +1,9 @@ +# Warping 3D + +# create mesh +from mechanic import * + +# get faces with warping angle = 2.0e-13 with tolerance 5.0e-14 +filter = smesh_builder.GetFilter(SMESH.VOLUME, SMESH.FT_Warping3D, "=", 2.0e-13, Tolerance=5.0e-14) +ids = mesh.GetIdsFromFilter(filter) +print("Number of volumes with warping = 2.0e-13 (tolerance 5.0e-14):", len(ids)) diff --git a/doc/examples/quality_controls_ex23.py b/doc/examples/quality_controls_ex23.py new file mode 100644 index 000000000..f34704a5d --- /dev/null +++ b/doc/examples/quality_controls_ex23.py @@ -0,0 +1,25 @@ +# Warping + +from mechanic import * + +# Criterion : WARP ANGLE > 1e-15 +wa_margin = 1e-15 + +aFilter = smesh_builder.GetFilter(SMESH.VOLUME, SMESH.FT_Warping3D, SMESH.FT_MoreThan, wa_margin) + +anIds = mesh.GetIdsFromFilter(aFilter) + +# print the result +print("Criterion: Warp > ", wa_margin, " 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.VOLUME, "Warp > " + repr(wa_margin)) + +aGroup.Add(anIds) diff --git a/doc/gui/images/image_warping3D.jpg b/doc/gui/images/image_warping3D.jpg new file mode 100644 index 000000000..1795d1bd8 Binary files /dev/null and b/doc/gui/images/image_warping3D.jpg differ diff --git a/doc/gui/input/about_quality_controls.rst b/doc/gui/input/about_quality_controls.rst index 7c7250b48..1c48d1657 100644 --- a/doc/gui/input/about_quality_controls.rst +++ b/doc/gui/input/about_quality_controls.rst @@ -47,6 +47,7 @@ Volume quality controls: * :ref:`aspect_ratio_3d_page` * :ref:`volume_page` +* :ref:`warping_3d_page` * :ref:`max_element_length_3d_page` * :ref:`scaled_jacobian_page` * :ref:`bare_border_volumes_page` @@ -98,6 +99,7 @@ To manage the quality controls call pop-up in the VTK viewer and select "Control aspect_ratio_3d.rst volume.rst max_element_length_3d.rst + warping_3d.rst bare_border_volumes.rst over_constrained_volumes.rst scalar_bar.rst diff --git a/doc/gui/input/tui_filters.rst b/doc/gui/input/tui_filters.rst index 314defd31..db22d5ecf 100644 --- a/doc/gui/input/tui_filters.rst +++ b/doc/gui/input/tui_filters.rst @@ -97,6 +97,24 @@ filters 2D mesh elements (faces) according to the warping angle value: **See also:** :ref:`tui_warping` +.. _filter_warping_3d: + +Warping 3D +============= + +filters 3D mesh elements (volumes) according to the maximum warping angle value of the faces of volumes: + +* element type is *SMESH.VOLUME* +* functor type is *SMESH.FT_Warping3D* +* threshold is floating point value (warping angle) + +.. literalinclude:: ../../examples/filters_ex41.py + :language: python + +:download:`Download this script <../../examples/filters_ex41.py>` + +**See also:** :ref:`tui_warping_3d` + .. _filter_minimum_angle: Minimum angle diff --git a/doc/gui/input/tui_quality_controls.rst b/doc/gui/input/tui_quality_controls.rst index 69d770493..478b8073e 100644 --- a/doc/gui/input/tui_quality_controls.rst +++ b/doc/gui/input/tui_quality_controls.rst @@ -250,3 +250,13 @@ Scaled Jacobian :language: python :download:`Download this script <../../examples/quality_controls_ex24.py>` + +.. _tui_warping_3d: + +Warping 3D +======= + +.. literalinclude:: ../../examples/quality_controls_ex23.py + :language: python + +:download:`Download this script <../../examples/quality_controls_ex23.py>` diff --git a/doc/gui/input/warping_3d.rst b/doc/gui/input/warping_3d.rst new file mode 100644 index 000000000..60503578f --- /dev/null +++ b/doc/gui/input/warping_3d.rst @@ -0,0 +1,24 @@ +.. _warping_3d_page: + +******* +Warping 3D +******* + +3D Warping control compute warping angle on each faces of volume elements. + +The page :ref:`warping_page` provide information about computing warping angle for 2D element + +*To apply the Warping quality criterion to your mesh:* + +.. |img| image:: ../images/image39.png + +#. Display your mesh in the viewer. +#. Choose **Controls > Volume Controls > Warping 3D** or click *"Warping 3D"* 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/image_warping3D.jpg + :align: center + + +**See Also** a sample TUI Script of a :ref:`tui_warping_3d` filter. diff --git a/idl/SMESH_Filter.idl b/idl/SMESH_Filter.idl index 4876d8d00..05cfa6dc4 100644 --- a/idl/SMESH_Filter.idl +++ b/idl/SMESH_Filter.idl @@ -42,7 +42,8 @@ module SMESH { FT_AspectRatio, FT_AspectRatio3D, - FT_Warping, + FT_Warping, + FT_Warping3D, FT_MinimumAngle, FT_Taper, FT_Skew, @@ -138,6 +139,7 @@ module SMESH interface AspectRatio : NumericalFunctor{}; interface AspectRatio3D : NumericalFunctor{}; interface Warping : NumericalFunctor{}; + interface Warping3D : NumericalFunctor {}; interface Taper : NumericalFunctor{}; interface Skew : NumericalFunctor{}; interface Area : NumericalFunctor{}; @@ -586,6 +588,7 @@ module SMESH AspectRatio CreateAspectRatio(); AspectRatio3D CreateAspectRatio3D(); Warping CreateWarping(); + Warping3D CreateWarping3D(); Taper CreateTaper(); Skew CreateSkew(); Area CreateArea(); diff --git a/src/Controls/SMESH_Controls.cxx b/src/Controls/SMESH_Controls.cxx index 92c616606..578557775 100644 --- a/src/Controls/SMESH_Controls.cxx +++ b/src/Controls/SMESH_Controls.cxx @@ -1423,21 +1423,7 @@ bool Warping::IsApplicable( const SMDS_MeshElement* element ) const double Warping::GetValue( const TSequenceOfXYZ& P ) { - if ( P.size() != 4 ) - return 0; - - gp_XYZ G = ( P( 1 ) + P( 2 ) + P( 3 ) + P( 4 ) ) / 4.; - - double A1 = ComputeA( P( 1 ), P( 2 ), P( 3 ), G ); - double A2 = ComputeA( P( 2 ), P( 3 ), P( 4 ), G ); - double A3 = ComputeA( P( 3 ), P( 4 ), P( 1 ), G ); - double A4 = ComputeA( P( 4 ), P( 1 ), P( 2 ), G ); - - double val = Max( Max( A1, A2 ), Max( A3, A4 ) ); - - const double eps = 0.1; // val is in degrees - - return val < eps ? 0. : val; + return ComputeValue(P); } double Warping::ComputeA( const gp_XYZ& thePnt1, @@ -1464,6 +1450,25 @@ double Warping::ComputeA( const gp_XYZ& thePnt1, return asin( fabs( H / L ) ) * 180. / M_PI; } +double Warping::ComputeValue(const TSequenceOfXYZ& thePoints) const +{ + if (thePoints.size() != 4) + return 0; + + gp_XYZ G = (thePoints(1) + thePoints(2) + thePoints(3) + thePoints(4)) / 4.; + + double A1 = ComputeA(thePoints(1), thePoints(2), thePoints(3), G); + double A2 = ComputeA(thePoints(2), thePoints(3), thePoints(4), G); + double A3 = ComputeA(thePoints(3), thePoints(4), thePoints(1), G); + double A4 = ComputeA(thePoints(4), thePoints(1), thePoints(2), G); + + double val = Max(Max(A1, A2), Max(A3, A4)); + + const double eps = 0.1; // val is in degrees + + return val < eps ? 0. : val; +} + double Warping::GetBadRate( double Value, int /*nbNodes*/ ) const { // the warp is in the range [0.0,PI/2] @@ -1478,6 +1483,93 @@ SMDSAbs_ElementType Warping::GetType() const } +//================================================================================ +/* + Class : Warping3D + Description : Functor for calculating warping +*/ +//================================================================================ + +bool Warping3D::IsApplicable(const SMDS_MeshElement* element) const +{ + return NumericalFunctor::IsApplicable(element);//&& element->NbNodes() == 4; +} + +double Warping3D::GetValue(long theId) +{ + double aVal = 0; + myCurrElement = myMesh->FindElement(theId); + if (myCurrElement) + { + WValues aValues; + ProcessVolumeELement(aValues); + for (const auto& aValue: aValues) + { + aVal = Max(aVal, aValue.myWarp); + } + } + return aVal; +} + +double Warping3D::GetValue(const TSequenceOfXYZ& P) +{ + return ComputeValue(P); +} + +SMDSAbs_ElementType Warping3D::GetType() const +{ + return SMDSAbs_Volume; +} + +bool Warping3D::Value::operator<(const Warping3D::Value& x) const +{ + if (myPntIds.size() != x.myPntIds.size()) + return myPntIds.size() < x.myPntIds.size(); + + for (int anInd = 0; anInd < myPntIds.size(); ++anInd) + if (myPntIds[anInd] != x.myPntIds[anInd]) + return myPntIds[anInd] != x.myPntIds[anInd]; + + return false; +} + +// Compute value on each face of volume +void Warping3D::ProcessVolumeELement(WValues& theValues) +{ + SMDS_VolumeTool aVTool(myCurrElement); + double aCoord[3]; + for (int aFaceID = 0; aFaceID < aVTool.NbFaces(); ++aFaceID) + { + TSequenceOfXYZ aPoints; + std::set aNodes; + std::vector aNodeIds; + const SMDS_MeshNode** aNodesPtr = aVTool.GetFaceNodes(aFaceID); + + if (aNodesPtr) + { + for (int i = 0; i < aVTool.NbFaceNodes(aFaceID); ++i) + { + aNodesPtr[i]->GetXYZ(aCoord); + aPoints.push_back(gp_XYZ{ aCoord[0], aCoord[1], aCoord[2] }); + aNodeIds.push_back(aNodesPtr[i]->GetID()); + } + double aWarp = GetValue(aPoints); + Value aVal{ aWarp, aNodeIds }; + + theValues.push_back(aVal); + } + } +} + +void Warping3D::GetValues(WValues& theValues) +{ + for (SMDS_VolumeIteratorPtr anIter = myMesh->volumesIterator(); anIter->more(); ) + { + myCurrElement = anIter->next(); + ProcessVolumeELement(theValues); + } +} + //================================================================================ /* Class : Taper diff --git a/src/Controls/SMESH_ControlsDef.hxx b/src/Controls/SMESH_ControlsDef.hxx index d6456eab4..456f4b30a 100644 --- a/src/Controls/SMESH_ControlsDef.hxx +++ b/src/Controls/SMESH_ControlsDef.hxx @@ -246,9 +246,35 @@ namespace SMESH{ virtual SMDSAbs_ElementType GetType() const; virtual bool IsApplicable( const SMDS_MeshElement* element ) const; - private: + protected: double ComputeA( const gp_XYZ&, const gp_XYZ&, const gp_XYZ&, const gp_XYZ& ) const; + double ComputeValue( const TSequenceOfXYZ& thePoints ) const; }; + + /* + Class : Warping3D + Description : Functor for calculating warping + */ + class SMESHCONTROLS_EXPORT Warping3D: public virtual Warping { + public: + virtual bool IsApplicable(const SMDS_MeshElement* element) const; + virtual double GetValue(const TSequenceOfXYZ& thePoints); + virtual double GetValue(long theId); + virtual SMDSAbs_ElementType GetType() const; + + struct Value { + double myWarp; + std::vector myPntIds; + bool operator<(const Value& x) const; + }; + + typedef std::vector WValues; + void GetValues(WValues& theValues); + + private: + void ProcessVolumeELement(WValues& theValues); + }; + typedef boost::shared_ptr Warping3DPtr; /* diff --git a/src/OBJECT/SMESH_Actor.cxx b/src/OBJECT/SMESH_Actor.cxx index 8e21c3d5a..2799e4494 100644 --- a/src/OBJECT/SMESH_Actor.cxx +++ b/src/OBJECT/SMESH_Actor.cxx @@ -1013,6 +1013,14 @@ void SMESH_ActorDef::SetControlMode( eControl theMode, bool theCheckEntityMode ) myControlActor = my2DActor; break; } + case eWarping3D: + { + SMESH::Controls::Warping3D* aControl = new SMESH::Controls::Warping3D(); + aControl->SetPrecision(myControlsPrecision); + myFunctor.reset(aControl); + myControlActor = my3DActor; + break; + } case eSkew: { SMESH::Controls::Skew* aControl = new SMESH::Controls::Skew(); @@ -1078,6 +1086,10 @@ void SMESH_ActorDef::SetControlMode( eControl theMode, bool theCheckEntityMode ) my1DExtActor->SetExtControlMode(myFunctor,myScalarBarActor,myLookupTable); UpdateDistribution(); break; + case eWarping3D: + my2DExtActor->SetExtControlMode(myFunctor, myScalarBarActor, myLookupTable); + UpdateDistribution(); + break; default: myControlActor->SetControlMode(myFunctor,myScalarBarActor,myLookupTable); UpdateDistribution(); @@ -1543,6 +1555,7 @@ void SMESH_ActorDef::SetVisibility(int theMode, bool theIsUpdateRepersentation) case eBareBorderFace: case eOverConstrainedFace: case eCoincidentElems2D: + case eWarping3D: my2DExtActor->VisibilityOn(); break; case eBareBorderVolume: @@ -1558,7 +1571,8 @@ void SMESH_ActorDef::SetVisibility(int theMode, bool theIsUpdateRepersentation) if ( GetPickable( )) myPickableActor->VisibilityOn(); - if ( GetRepresentation() != ePoint ) + if ( GetRepresentation() != ePoint && + !(IsClipThresholdOn() && GetActorForThreshold() != myControlActor)) // Avoid calling VisibilityOn if for display result of Threshold Criteria need only ExtActor { if(myEntityMode & e0DElements ){ my0DActor->VisibilityOn(); @@ -2502,11 +2516,27 @@ void SMESH_ActorDef::UpdateScalarBar() } -// Hides the cells beyond threshold if isThresholdOn == true. -void SMESH_ActorDef::ClipThreshold(bool isThresholdOn, double min /*= 0.0*/, double max /*= 0.0*/) +// Get Actor for Threshold criteria compute +SMESH_DeviceActor* SMESH_ActorDef::GetActorForThreshold() { + switch (myControlMode) { + case eLength2D: + return my1DExtActor; + case eWarping3D: + return my2DExtActor; + default:; + return myControlActor; + } +} + +// Hides the cells beyond threshold if isThresholdOn == true. +void SMESH_ActorDef::ClipThreshold(bool isThresholdOn,double min /*= 0.0*/, double max /*= 0.0*/) +{ + SMESH_DeviceActor* anActor = GetActorForThreshold(); + if (anActor != myControlActor) + myControlActor->VisibilityOff(); + myIsClipThresholdOn = isThresholdOn; - if (isThresholdOn) { // Initialize the filter @@ -2514,7 +2544,7 @@ void SMESH_ActorDef::ClipThreshold(bool isThresholdOn, double min /*= 0.0*/, dou // We have set scalar data with SMESH_DeviceActor::SetControlMode() call as vtkDataSetAttributes::SCALARS. // So, we don't need to pass an array name in SetInputArrayToProcess(). - threshold->SetInputConnection(myControlActor->myMergeFilter->GetOutputPort()); + threshold->SetInputConnection(anActor->myMergeFilter->GetOutputPort()); threshold->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_CELLS, vtkDataSetAttributes::SCALARS); // Set range @@ -2528,12 +2558,18 @@ void SMESH_ActorDef::ClipThreshold(bool isThresholdOn, double min /*= 0.0*/, dou // Add to the filters' chain vtkAlgorithmOutput* port = threshold->GetOutputPort(); - myControlActor->myPassFilter[0]->SetInputConnection(port); + anActor->myPassFilter[0]->SetInputConnection(port); } else { // Restore the filters' chain - myControlActor->SetImplicitFunctionUsed(myControlActor->myIsImplicitFunctionUsed); + anActor->SetImplicitFunctionUsed(anActor->myIsImplicitFunctionUsed); + // Restore Actor filters when after Controls, which not use ExtACtor was called Controls, which use ExtActor + // For avoid artifact's + if (anActor != myControlActor) + myControlActor->SetImplicitFunctionUsed(myControlActor->myIsImplicitFunctionUsed); + + myControlActor->VisibilityOn(); } } diff --git a/src/OBJECT/SMESH_Actor.h b/src/OBJECT/SMESH_Actor.h index 9dc3e579c..15519a24c 100644 --- a/src/OBJECT/SMESH_Actor.h +++ b/src/OBJECT/SMESH_Actor.h @@ -38,6 +38,7 @@ class vtkUnstructuredGrid; class SMESH_ScalarBarActor; +class SMESH_DeviceActor; class vtkPlane; class vtkImplicitBoolean; @@ -139,7 +140,7 @@ class SMESHOBJECT_EXPORT SMESH_Actor: public SALOME_Actor enum eControl{eNone, eLength, eLength2D, eDeflection2D, eFreeBorders, eFreeEdges, eFreeNodes, eFreeFaces, eMultiConnection, eArea, eTaper, eAspectRatio, - eMinimumAngle, eWarping, eSkew, eAspectRatio3D, eMultiConnection2D, eVolume3D, eScaledJacobian, + eMinimumAngle, eWarping, eSkew, eAspectRatio3D, eWarping3D, eMultiConnection2D, eVolume3D, eScaledJacobian, eMaxElementLength2D, eMaxElementLength3D, eBareBorderFace, eBareBorderVolume, eOverConstrainedFace, eOverConstrainedVolume, eCoincidentNodes, eCoincidentElems1D, eCoincidentElems2D, eCoincidentElems3D, eNodeConnectivityNb, @@ -167,6 +168,7 @@ class SMESHOBJECT_EXPORT SMESH_Actor: public SALOME_Actor virtual void UpdateScalarBar() = 0; virtual void UpdateDistribution() = 0; virtual void ClipThreshold(bool isThresholdOn, double min = 0.0, double max = 0.0) = 0; + virtual SMESH_DeviceActor* GetActorForThreshold() = 0; virtual bool IsClipThresholdOn() const = 0; virtual void SetWireframeOff(bool isWireframeOff) = 0; virtual bool IsWireframeOff() const = 0; diff --git a/src/OBJECT/SMESH_ActorDef.h b/src/OBJECT/SMESH_ActorDef.h index bb53280c1..49a326b69 100644 --- a/src/OBJECT/SMESH_ActorDef.h +++ b/src/OBJECT/SMESH_ActorDef.h @@ -226,6 +226,7 @@ class SMESH_ActorDef : public SMESH_Actor virtual void UpdateScalarBar(); virtual void UpdateDistribution(); + virtual SMESH_DeviceActor* GetActorForThreshold(); virtual void ClipThreshold(bool isThresholdOn, double min = 0.0, double max = 0.0); virtual bool IsClipThresholdOn() const { return myIsClipThresholdOn; } virtual void SetWireframeOff(bool isWireframeOff); diff --git a/src/OBJECT/SMESH_DeviceActor.cxx b/src/OBJECT/SMESH_DeviceActor.cxx index 313f73801..be17fe3c3 100644 --- a/src/OBJECT/SMESH_DeviceActor.cxx +++ b/src/OBJECT/SMESH_DeviceActor.cxx @@ -504,6 +504,80 @@ SMESH_DeviceActor theLookupTable->SetRange(aScalars->GetRange()); theLookupTable->Build(); + myMergeFilter->SetScalarsData(aDataSet); + aDataSet->Delete(); + } + else if (Warping3D* aWarping3D = dynamic_cast(theFunctor.get())){ + + SMESH::Controls::Warping3D::WValues aValues; + + aWarping3D->GetValues(aValues); + vtkUnstructuredGrid* aDataSet = vtkUnstructuredGrid::New(); + vtkUnstructuredGrid* aGrid = myVisualObj->GetUnstructuredGrid(); + + aDataSet->SetPoints(aGrid->GetPoints()); + + vtkIdType aNbCells = aValues.size(); + + vtkDoubleArray* aScalars = vtkDoubleArray::New(); + aScalars->SetNumberOfComponents(1); + aScalars->SetNumberOfTuples(aNbCells); + + vtkIdType aCellsSize = 3 * aNbCells; + vtkCellArray* aConnectivity = vtkCellArray::New(); + aConnectivity->Allocate(aCellsSize, 0); + + vtkUnsignedCharArray* aCellTypesArray = vtkUnsignedCharArray::New(); + aCellTypesArray->SetNumberOfComponents(1); + aCellTypesArray->Allocate(aNbCells* aCellTypesArray->GetNumberOfComponents()); + + Warping3D::WValues::const_iterator anIter = aValues.begin(); + aNbCells = 0; + for (; anIter != aValues.end(); anIter++) { + + const Warping3D::Value& aValue = *anIter; + vtkIdList* anIdList = vtkIdList::New(); + anIdList->SetNumberOfIds(aValue.myPntIds.size()); + bool isExist = true; + for (int i = 0; i < aValue.myPntIds.size(); ++i) + { + int aVTKId = myVisualObj->GetNodeVTKId(aValue.myPntIds[i]); + if (aVTKId < 0) + { + isExist = false; + break; + } + anIdList->SetId(i, aVTKId); + } + if (isExist) + { + aConnectivity->InsertNextCell(anIdList); + aCellTypesArray->InsertNextValue(VTK_POLYGON); + aScalars->SetValue(aNbCells, aValue.myWarp); + aNbCells++; + } + } + aCellTypesArray->SetNumberOfTuples(aNbCells); + aScalars->SetNumberOfTuples(aNbCells); + + vtkIdTypeArray* aCellLocationsArray = vtkIdTypeArray::New(); + aCellLocationsArray->SetNumberOfComponents(1); + aCellLocationsArray->SetNumberOfTuples(aNbCells); + + aConnectivity->InitTraversal(); + vtkIdType const* pts(nullptr); + for (vtkIdType idType = 0, npts; aConnectivity->GetNextCell(npts, pts); idType++) + aCellLocationsArray->SetValue(idType, aConnectivity->GetTraversalLocation(npts)); + + aDataSet->SetCells(aCellTypesArray, aCellLocationsArray, aConnectivity); + SetUnstructuredGrid(aDataSet); + + aDataSet->GetCellData()->SetScalars(aScalars); + aScalars->Delete(); + + theLookupTable->SetRange(aScalars->GetRange()); + theLookupTable->Build(); + myMergeFilter->SetScalarsData(aDataSet); aDataSet->Delete(); } diff --git a/src/SMESHGUI/SMESHGUI.cxx b/src/SMESHGUI/SMESHGUI.cxx index aa02081d9..69cbc7390 100644 --- a/src/SMESHGUI/SMESHGUI.cxx +++ b/src/SMESHGUI/SMESHGUI.cxx @@ -1121,6 +1121,8 @@ namespace type = QObject::tr( "ASPECTRATIO_3D_ELEMENTS" ); else if ( dynamic_cast< SMESH::Controls::Warping* >( f.get() ) ) type = QObject::tr( "WARP_ELEMENTS" ); + else if (dynamic_cast(f.get())) + type = QObject::tr("WARP_3D_ELEMENTS"); else if ( dynamic_cast< SMESH::Controls::Taper* >( f.get() ) ) type = QObject::tr( "TAPER_ELEMENTS" ); else if ( dynamic_cast< SMESH::Controls::Skew* >( f.get() ) ) @@ -1780,6 +1782,7 @@ namespace ActionControl.Bind( SMESHOp::OpMaxElementLength2D, SMESH_Actor::eMaxElementLength2D ); ActionControl.Bind( SMESHOp::OpEqualFace, SMESH_Actor::eCoincidentElems2D ); ActionControl.Bind( SMESHOp::OpAspectRatio3D, SMESH_Actor::eAspectRatio3D ); + ActionControl.Bind( SMESHOp::OpWarping3D, SMESH_Actor::eWarping3D ); ActionControl.Bind( SMESHOp::OpVolume, SMESH_Actor::eVolume3D ); ActionControl.Bind( SMESHOp::OpScaledJacobian, SMESH_Actor::eScaledJacobian ); ActionControl.Bind( SMESHOp::OpMaxElementLength3D, SMESH_Actor::eMaxElementLength3D ); @@ -3906,6 +3909,7 @@ bool SMESHGUI::OnGUIEvent( int theCommandID ) case SMESHOp::OpMaxElementLength2D: case SMESHOp::OpEqualFace: case SMESHOp::OpAspectRatio3D: + case SMESHOp::OpWarping3D: case SMESHOp::OpVolume: case SMESHOp::OpScaledJacobian: case SMESHOp::OpMaxElementLength3D: @@ -4214,6 +4218,7 @@ void SMESHGUI::initialize( CAM_Application* app ) createSMESHAction( SMESHOp::OpMaxElementLength2D, "MAX_ELEMENT_LENGTH_2D", "ICON_MAX_ELEMENT_LENGTH_2D", 0, true ); createSMESHAction( SMESHOp::OpEqualFace, "EQUAL_FACE", "ICON_EQUAL_FACE", 0, true ); createSMESHAction( SMESHOp::OpAspectRatio3D, "ASPECT_3D", "ICON_ASPECT_3D", 0, true ); + createSMESHAction( SMESHOp::OpWarping3D, "WARP_3D", "ICON_WARP", 0, true); createSMESHAction( SMESHOp::OpVolume, "VOLUME_3D", "ICON_VOLUME_3D", 0, true ); createSMESHAction( SMESHOp::OpMaxElementLength3D, "MAX_ELEMENT_LENGTH_3D", "ICON_MAX_ELEMENT_LENGTH_3D", 0, true ); createSMESHAction( SMESHOp::OpBareBorderVolume, "BARE_BORDER_VOLUME", "ICON_BARE_BORDER_VOLUME", 0, true ); @@ -4359,7 +4364,7 @@ void SMESHGUI::initialize( CAM_Application* app ) << SMESHOp::OpMinimumAngle << SMESHOp::OpWarpingAngle << SMESHOp::OpSkew << SMESHOp::OpMaxElementLength2D << SMESHOp::OpBareBorderFace << SMESHOp::OpOverConstrainedFace << SMESHOp::OpEqualFace // face controls - << SMESHOp::OpAspectRatio3D << SMESHOp::OpVolume + << SMESHOp::OpAspectRatio3D << SMESHOp::OpVolume << SMESHOp::OpWarping3D << SMESHOp::OpMaxElementLength3D << SMESHOp::OpBareBorderVolume << SMESHOp::OpOverConstrainedVolume << SMESHOp::OpEqualVolume << SMESHOp::OpScaledJacobian; // volume controls QActionGroup* aCtrlGroup = new QActionGroup( application()->desktop() ); @@ -4472,6 +4477,7 @@ void SMESHGUI::initialize( CAM_Application* app ) createMenu( SMESHOp::OpEqualFace, faceId, -1 ); createMenu( SMESHOp::OpDeflection2D, faceId, -1 ); createMenu( SMESHOp::OpAspectRatio3D, volumeId, -1 ); + createMenu( SMESHOp::OpWarping3D, volumeId, -1 ); createMenu( SMESHOp::OpVolume, volumeId, -1 ); createMenu( SMESHOp::OpMaxElementLength3D, volumeId, -1 ); createMenu( SMESHOp::OpBareBorderVolume, volumeId, -1 ); @@ -4631,6 +4637,7 @@ void SMESHGUI::initialize( CAM_Application* app ) int ctrl3dTb = createTool( tr( "TB_CTRL3D" ), QString( "SMESHVolumeControlsToolbar" ) ) ; createTool( SMESHOp::OpAspectRatio3D, ctrl3dTb ); + createTool( SMESHOp::OpWarping3D, ctrl3dTb ); createTool( SMESHOp::OpVolume, ctrl3dTb ); createTool( SMESHOp::OpMaxElementLength3D, ctrl3dTb ); createTool( SMESHOp::OpBareBorderVolume, ctrl3dTb ); @@ -5095,6 +5102,10 @@ void SMESHGUI::initialize( CAM_Application* app ) popupMgr()->setRule( action( SMESHOp::OpAspectRatio3D ), aMeshInVtkHasVolumes, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( SMESHOp::OpAspectRatio3D ), "controlMode = 'eAspectRatio3D'", QtxPopupMgr::ToggleRule ); + popupMgr()->insert ( action( SMESHOp::OpWarping3D ), aSubId, -1 ); + popupMgr()->setRule( action( SMESHOp::OpWarping3D ), aMeshInVtkHasVolumes, QtxPopupMgr::VisibleRule ); + popupMgr()->setRule( action( SMESHOp::OpWarping3D), "controlMode = 'eWarping3D'", QtxPopupMgr::ToggleRule ); + popupMgr()->insert ( action( SMESHOp::OpVolume ), aSubId, -1 ); popupMgr()->setRule( action( SMESHOp::OpVolume ), aMeshInVtkHasVolumes, QtxPopupMgr::VisibleRule ); popupMgr()->setRule( action( SMESHOp::OpVolume ), "controlMode = 'eVolume3D'", QtxPopupMgr::ToggleRule ); diff --git a/src/SMESHGUI/SMESHGUI_FilterDlg.cxx b/src/SMESHGUI/SMESHGUI_FilterDlg.cxx index a01f2a9a1..98439f06e 100644 --- a/src/SMESHGUI/SMESHGUI_FilterDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_FilterDlg.cxx @@ -1563,6 +1563,7 @@ void SMESHGUI_FilterTable::updateAdditionalWidget() bool isDbl = ( aCriterion == SMESH::FT_AspectRatio || aCriterion == SMESH::FT_AspectRatio3D || aCriterion == SMESH::FT_Warping || + aCriterion == SMESH::FT_Warping3D || aCriterion == SMESH::FT_MinimumAngle || aCriterion == SMESH::FT_Taper || aCriterion == SMESH::FT_Skew || @@ -1606,6 +1607,7 @@ const char* SMESHGUI_FilterTable::getPrecision( const int aType ) case SMESH::FT_Taper: retval = "parametric_precision"; break; case SMESH::FT_Warping: + case SMESH::FT_Warping3D: case SMESH::FT_MinimumAngle: case SMESH::FT_Skew: case SMESH::FT_CoplanarFaces: @@ -1812,6 +1814,7 @@ void SMESHGUI_FilterTable::onCriterionChanged (const int row, const int /*col*/, case SMESH::FT_AspectRatio: case SMESH::FT_AspectRatio3D: case SMESH::FT_Warping: + case SMESH::FT_Warping3D: case SMESH::FT_MinimumAngle: case SMESH::FT_Taper: case SMESH::FT_Skew: @@ -2270,6 +2273,7 @@ const QMap& SMESHGUI_FilterTable::getCriteria (const int theType) if (aCriteria.isEmpty()) { aCriteria[ SMESH::FT_AspectRatio3D ] = tr("ASPECT_RATIO_3D"); + aCriteria[ SMESH::FT_Warping3D ] = tr("WARPING_3D"); aCriteria[ SMESH::FT_RangeOfIds ] = tr("RANGE_OF_IDS"); aCriteria[ SMESH::FT_BelongToMeshGroup ] = tr("BELONG_TO_MESH_GROUP"); aCriteria[ SMESH::FT_BelongToGeom ] = tr("BELONG_TO_GEOM"); diff --git a/src/SMESHGUI/SMESHGUI_MeshInfo.cxx b/src/SMESHGUI/SMESHGUI_MeshInfo.cxx index 2aef4b2d2..24c610d78 100644 --- a/src/SMESHGUI/SMESHGUI_MeshInfo.cxx +++ b/src/SMESHGUI/SMESHGUI_MeshInfo.cxx @@ -1674,6 +1674,8 @@ QString SMESHGUI_ElemInfo::ctrl2str( int control ) title = tr( "ASPECTRATIO_3D_ELEMENTS" ); break; case SMESH::FT_Warping: title = tr( "WARP_ELEMENTS" ); break; + case SMESH::FT_Warping3D: + title = tr( "WARP_3D_ELEMENTS" ); break; case SMESH::FT_MinimumAngle: title = tr( "MINIMUMANGLE_ELEMENTS" ); break; case SMESH::FT_Taper: diff --git a/src/SMESHGUI/SMESHGUI_Operations.h b/src/SMESHGUI/SMESHGUI_Operations.h index 6ae97b6e4..bdf6e7382 100644 --- a/src/SMESHGUI/SMESHGUI_Operations.h +++ b/src/SMESHGUI/SMESHGUI_Operations.h @@ -123,6 +123,7 @@ namespace SMESHOp { OpOverConstrainedVolume = 3304, // MENU CONTROLS - OVERCONSTRAINED VOLUMES OpEqualVolume = 3305, // MENU CONTROLS - DOUBLE VOLUMES OpScaledJacobian = 3306, // MENU CONTROLS - SCALED JACOBIAN + OpWarping3D = 3307, // MENU CONTROLS - Warping 3D OpOverallMeshQuality = 3400, // MENU CONTROLS - OVERALL MESH QUALITY // Modification -------------------//-------------------------------- OpNode = 4000, // MENU MODIFICATION - ADD - NODE diff --git a/src/SMESHGUI/SMESHGUI_Selection.cxx b/src/SMESHGUI/SMESHGUI_Selection.cxx index dad619032..5669e9ead 100644 --- a/src/SMESHGUI/SMESHGUI_Selection.cxx +++ b/src/SMESHGUI/SMESHGUI_Selection.cxx @@ -377,6 +377,7 @@ QString SMESHGUI_Selection::controlMode( int ind ) const case SMESH_Actor::eTaper: mode = "eTaper"; break; case SMESH_Actor::eAspectRatio: mode = "eAspectRatio"; break; case SMESH_Actor::eAspectRatio3D: mode = "eAspectRatio3D"; break; + case SMESH_Actor::eWarping3D: mode = "eWarping3D"; break; case SMESH_Actor::eMinimumAngle: mode = "eMinimumAngle"; break; case SMESH_Actor::eWarping: mode = "eWarping"; break; case SMESH_Actor::eSkew: mode = "eSkew"; break; @@ -438,6 +439,7 @@ bool SMESHGUI_Selection::isNumFunctor( int ind ) const case SMESH_Actor::eAspectRatio3D: case SMESH_Actor::eMinimumAngle: case SMESH_Actor::eWarping: + case SMESH_Actor::eWarping3D: case SMESH_Actor::eSkew: result = true; break; diff --git a/src/SMESHGUI/SMESHGUI_SelectionProxy.cxx b/src/SMESHGUI/SMESHGUI_SelectionProxy.cxx index a555136fd..6d7afa4e3 100644 --- a/src/SMESHGUI/SMESHGUI_SelectionProxy.cxx +++ b/src/SMESHGUI/SMESHGUI_SelectionProxy.cxx @@ -908,6 +908,9 @@ bool SMESH::SelectionProxy::elementControl( int id, int control, double precisio case SMESH::FT_Warping: functor.reset( new SMESH::Controls::Warping() ); break; + case SMESH::FT_Warping3D: + functor.reset(new SMESH::Controls::Warping3D()); + break; case SMESH::FT_MinimumAngle: functor.reset( new SMESH::Controls::MinimumAngle() ); break; @@ -979,6 +982,9 @@ bool SMESH::SelectionProxy::elementControl( int id, int control, double precisio case SMESH::FT_Warping: functor = manager->CreateWarping(); break; + case SMESH::FT_Warping3D: + functor = manager->CreateWarping3D(); + break; case SMESH::FT_MinimumAngle: functor = manager->CreateMinimumAngle(); break; diff --git a/src/SMESHGUI/SMESH_msg_en.ts b/src/SMESHGUI/SMESH_msg_en.ts index 48c73b054..8c6f0359b 100644 --- a/src/SMESHGUI/SMESH_msg_en.ts +++ b/src/SMESHGUI/SMESH_msg_en.ts @@ -115,6 +115,10 @@ ASPECTRATIO_3D_ELEMENTS Aspect Ratio 3D + + WARPING_3D_ELEMENTS + Warping 3D + ASPECTRATIO_ELEMENTS Aspect Ratio @@ -1332,6 +1336,10 @@ MEN_WARP Warping Angle + + MEN_WARP_3D + Warping 3D + MEN_WHAT_IS Mesh Element Information @@ -3936,6 +3944,10 @@ Use Display Entity menu command to show them. STB_WARP Warping angle + + STB_WARP_3D + Warping angle + STB_WHAT_IS Show information about the mesh node or element @@ -4656,6 +4668,10 @@ Use Display Entity menu command to show them. TOP_WARP Warping angle + + TOP_WARP_3D + Warping 3D + TOP_WHAT_IS Mesh Element Information @@ -4680,6 +4696,10 @@ Use Display Entity menu command to show them. WARP_ELEMENTS Warping + + WARP_3D_ELEMENTS + Warping 3D + MEN_FILE_INFO File Information @@ -6297,6 +6317,10 @@ Please check input data and try again ASPECT_RATIO_3D Aspect ratio 3D + + WARPING_3D + Warping 3D + BAD_ORIENTED_VOLUME Bad oriented volume diff --git a/src/SMESHGUI/SMESH_msg_fr.ts b/src/SMESHGUI/SMESH_msg_fr.ts index 96818910a..9d00671ae 100644 --- a/src/SMESHGUI/SMESH_msg_fr.ts +++ b/src/SMESHGUI/SMESH_msg_fr.ts @@ -1332,6 +1332,10 @@ MEN_WARP Angle de déformation + + MEN_WARP_3D + Déformation 3D + MEN_WHAT_IS Information sur un élément de maillage @@ -3935,6 +3939,10 @@ Utilisez le menu "Visualiser une entité" pour les afficher. STB_WARP Angle de déformation + + STB_WARP_3D + Déformation 3D + STB_WHAT_IS Information sur un élément ou un nœud de maillage @@ -4655,6 +4663,10 @@ Utilisez le menu "Visualiser une entité" pour les afficher. TOP_WARP Angle de déformation + + TOP_WARP_3D + Déformation 3D + TOP_WHAT_IS Information sur l'élément de maillage @@ -4679,6 +4691,10 @@ Utilisez le menu "Visualiser une entité" pour les afficher. WARP_ELEMENTS Déformation + + WARP_3D_ELEMENTS + Déformation 3D + MEN_FILE_INFO Information sur le fichier du maillage diff --git a/src/SMESHGUI/SMESH_msg_ja.ts b/src/SMESHGUI/SMESH_msg_ja.ts index 07b8fcef0..a2704dba5 100644 --- a/src/SMESHGUI/SMESH_msg_ja.ts +++ b/src/SMESHGUI/SMESH_msg_ja.ts @@ -1131,6 +1131,10 @@ MEN_WARP 変形の角度 + + MEN_WARP_3D + 3Dワープ + MEN_WHAT_IS メッシュ要素について @@ -3539,6 +3543,10 @@ STB_WARP 変形の角度 + + STB_WARP_3D + 3Dワープ + STB_WHAT_IS 要素またはメッシュ ノードについて @@ -4207,6 +4215,10 @@ TOP_WARP 変形の角度 + + TOP_WARP_3D + 3Dワープ + TOP_WHAT_IS メッシュの要素に関する情報 @@ -4231,6 +4243,10 @@ WARP_ELEMENTS 変形 + + WARP_3D_ELEMENTS + 3D 変形 + MEN_FILE_INFO MEDファイルの情報 diff --git a/src/SMESH_I/SMESH_2smeshpy.cxx b/src/SMESH_I/SMESH_2smeshpy.cxx index 06d536b85..5d6fbc10f 100644 --- a/src/SMESH_I/SMESH_2smeshpy.cxx +++ b/src/SMESH_I/SMESH_2smeshpy.cxx @@ -303,6 +303,8 @@ namespace { // - FT_Length3D = 22 // v 9.12.0: FT_Undefined == 51, new items: // - FT_ScaledJacobian = 8 + // v 9.12.0: FT_Undefined == 52, new items: + // - FT_Warping3D = 4 // // It's necessary to continue recording this history and to fill // undef2newItems (see below) accordingly. @@ -328,6 +330,7 @@ namespace { undef2newItems[ 49 ].push_back( 22 ); undef2newItems[ 50 ].push_back( 22 ); undef2newItems[ 51 ].push_back( 8 ); + undef2newItems[ 52 ].push_back( 4 ); ASSERT( undef2newItems.rbegin()->first == SMESH::FT_Undefined ); } diff --git a/src/SMESH_I/SMESH_Filter_i.cxx b/src/SMESH_I/SMESH_Filter_i.cxx index a38f03943..5448c6699 100644 --- a/src/SMESH_I/SMESH_Filter_i.cxx +++ b/src/SMESH_I/SMESH_Filter_i.cxx @@ -399,6 +399,20 @@ namespace SMESH { return SMESH::FT_Warping; } + /* + Class : Warping3D_i + Description : Functor for calculating warping + */ + Warping3D_i::Warping3D_i() + { + myNumericalFunctorPtr.reset(new Controls::Warping3D()); + myFunctorPtr = myNumericalFunctorPtr; + } + + FunctorType Warping3D_i::GetFunctorType() + { + return SMESH::FT_Warping3D; + } /* Class : Taper_i @@ -2106,6 +2120,14 @@ namespace SMESH { } + Warping3D_ptr FilterManager_i::CreateWarping3D() + { + SMESH::Warping3D_i* aServant = new SMESH::Warping3D_i(); + SMESH::Warping3D_var anObj = aServant->_this(); + TPythonDump() << aServant << " = " << this << ".CreateWarping3D()"; + return anObj._retn(); + } + Taper_ptr FilterManager_i::CreateTaper() { SMESH::Taper_i* aServant = new SMESH::Taper_i(); @@ -3071,6 +3093,9 @@ namespace SMESH { case SMESH::FT_Warping: aFunctor = aFilterMgr->CreateWarping(); break; + case SMESH::FT_Warping3D: + aFunctor = aFilterMgr->CreateWarping3D(); + break; case SMESH::FT_MinimumAngle: aFunctor = aFilterMgr->CreateMinimumAngle(); break; @@ -3532,6 +3557,7 @@ namespace SMESH { { case FT_AspectRatio : return "Aspect ratio"; case FT_Warping : return "Warping"; + case FT_Warping3D : return "Warping 3D"; case FT_MinimumAngle : return "Minimum angle"; case FT_Taper : return "Taper"; case FT_Skew : return "Skew"; @@ -3589,6 +3615,7 @@ namespace SMESH { { if ( theStr.equals( "Aspect ratio" ) ) return FT_AspectRatio; else if ( theStr.equals( "Warping" ) ) return FT_Warping; + else if ( theStr.equals( "Warping 3D" ) ) return FT_Warping3D; else if ( theStr.equals( "Minimum angle" ) ) return FT_MinimumAngle; else if ( theStr.equals( "Taper" ) ) return FT_Taper; else if ( theStr.equals( "Skew" ) ) return FT_Skew; @@ -4163,6 +4190,7 @@ namespace SMESH { "FT_AspectRatio", "FT_AspectRatio3D", "FT_Warping", + "FT_Warping3D", "FT_MinimumAngle", "FT_Taper", "FT_Skew", diff --git a/src/SMESH_I/SMESH_Filter_i.hxx b/src/SMESH_I/SMESH_Filter_i.hxx index 54f0f9c09..941620134 100644 --- a/src/SMESH_I/SMESH_Filter_i.hxx +++ b/src/SMESH_I/SMESH_Filter_i.hxx @@ -164,6 +164,19 @@ namespace SMESH Warping_i(); FunctorType GetFunctorType(); }; + + /* + Class : Warping3D_i + Description : Functor for calculating 3D warping + */ + class SMESH_I_EXPORT Warping3D_i : public virtual POA_SMESH::Warping3D, + public virtual NumericalFunctor_i + { + public: + Warping3D_i(); + FunctorType GetFunctorType(); + }; + /* @@ -1121,6 +1134,7 @@ namespace SMESH AspectRatio_ptr CreateAspectRatio(); AspectRatio3D_ptr CreateAspectRatio3D(); Warping_ptr CreateWarping(); + Warping3D_ptr CreateWarping3D(); Taper_ptr CreateTaper(); Skew_ptr CreateSkew(); Area_ptr CreateArea(); diff --git a/src/SMESH_I/SMESH_PythonDump.cxx b/src/SMESH_I/SMESH_PythonDump.cxx index f388424ed..a07d95377 100644 --- a/src/SMESH_I/SMESH_PythonDump.cxx +++ b/src/SMESH_I/SMESH_PythonDump.cxx @@ -409,6 +409,7 @@ namespace SMESH case FT_AspectRatio: myStream<< "aAspectRatio"; break; case FT_AspectRatio3D: myStream<< "aAspectRatio3D"; break; case FT_Warping: myStream<< "aWarping"; break; + case FT_Warping3D: myStream<< "aWarping3D"; break; case FT_MinimumAngle: myStream<< "aMinimumAngle"; break; case FT_Taper: myStream<< "aTaper"; break; case FT_Skew: myStream<< "aSkew"; break; diff --git a/src/SMESH_SWIG/smeshBuilder.py b/src/SMESH_SWIG/smeshBuilder.py index 9d32e76fa..1bb9a251b 100644 --- a/src/SMESH_SWIG/smeshBuilder.py +++ b/src/SMESH_SWIG/smeshBuilder.py @@ -1203,6 +1203,8 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): functor = aFilterMgr.CreateAspectRatio3D() elif theCriterion == FT_Warping: functor = aFilterMgr.CreateWarping() + elif theCriterion == FT_Warping3D: + functor = aFilterMgr.CreateWarping3D() elif theCriterion == FT_MinimumAngle: functor = aFilterMgr.CreateMinimumAngle() elif theCriterion == FT_Taper: @@ -7460,6 +7462,19 @@ class Mesh(metaclass = MeshMeta): return self.FunctorValue(SMESH.FT_Warping, elemId) + def GetWarping3D(self, elemId): + """ + Get warping angle of faces element of 3D elements. + + Parameters: + elemId: mesh element ID + + Returns: + element's warping angle value + """ + + return self.FunctorValue(SMESH.FT_Warping3D, elemId) + def GetMinimumAngle(self, elemId): """ Get minimum angle of 2D element. diff --git a/test/SMESH_controls_3D_warping.py b/test/SMESH_controls_3D_warping.py new file mode 100644 index 000000000..ce792d4aa --- /dev/null +++ b/test/SMESH_controls_3D_warping.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python + +import os +import sys +import salome +import tempfile + +salome.salome_init() + + +def getTmpFileName(ext): + """ + get a tmp file name + """ + tempdir = tempfile.gettempdir() + tmp_file = tempfile.NamedTemporaryFile(suffix=".%s"%ext , dir=tempdir, delete=False) + tmp_filename = tmp_file.name + return tmp_filename + +### +### SHAPER component +### + +from salome.shaper import model + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 1, 7) +Point_2 = model.addPoint(Part_1_doc, 1, 0, 1.5) +Point_3 = model.addPoint(Part_1_doc, 0.5, 0, 3.5) +Sphere_1 = model.addSphere(Part_1_doc, model.selection("VERTEX", "Point_1"), 0.75) +Cylinder_2 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "Point_2"), model.selection("EDGE", "PartSet/OX"), 0.6, 3) +Fuse_1_objects_1 = [model.selection("SOLID", "Cylinder_2_1"), + model.selection("SOLID", "Cylinder_1_1"), + model.selection("SOLID", "Sphere_1_1")] +Fuse_1 = model.addFuse(Part_1_doc, Fuse_1_objects_1, keepSubResults = True) +model.end() + +expected_volume = 25.881416712512 +model.testResultsVolumes(Fuse_1, [expected_volume]) + +### +### SHAPERSTUDY component +### + +model.publishToShaperStudy() +import SHAPERSTUDY +Fuse_1_1, = SHAPERSTUDY.shape(model.featureStringId(Fuse_1)) + +### +### SMESH component +### + +import SMESH, SALOMEDS +from salome.smesh import smeshBuilder + +smesh = smeshBuilder.New() +# Surface Mesh +# ============ + +Mesh_1 = smesh.Mesh(Fuse_1_1, "Mesh_1") +NETGEN_1D_2D = Mesh_1.Triangle(algo=smeshBuilder.NETGEN_1D2D) +NETGEN_2D_Parameters_1 = NETGEN_1D_2D.Parameters() +NETGEN_2D_Parameters_1.SetMaxSize( 0.75 ) +NETGEN_2D_Parameters_1.SetMinSize( 0 ) +NETGEN_2D_Parameters_1.SetSecondOrder( 0 ) +NETGEN_2D_Parameters_1.SetOptimize( 1 ) +NETGEN_2D_Parameters_1.SetFineness( 5 ) +NETGEN_2D_Parameters_1.SetGrowthRate( 0.1 ) +NETGEN_2D_Parameters_1.SetNbSegPerEdge( 2 ) +NETGEN_2D_Parameters_1.SetNbSegPerRadius( 4 ) + +isDone = Mesh_1.Compute() + +if not isDone: + raise Exception("Error when computing the surface mesh") + +# MG-Hexa mesh +# ============ + +MG_Hexa = Mesh_1.Hexahedron(algo=smeshBuilder.MG_Hexa) +isDone = Mesh_1.Compute() + +if not isDone: + raise Exception("Error when computing volumes with MG-Hexa") + +volume = smesh.GetVolume(Mesh_1) +#print("volume: ", volume) +assert abs(volume-expected_volume)/expected_volume < 0.03 + +assert Mesh_1.NbTriangles() == 0 + +nb_hexa = Mesh_1.NbHexas() +assert Mesh_1.NbVolumes() == nb_hexa + +# MG-Hexa mesh with layers +# ======================== + +MG_Hexa_Parameters = MG_Hexa.Parameters() +MG_Hexa_Parameters.SetNbLayers( 3 ) +MG_Hexa_Parameters.SetFirstLayerSize( 0.01 ) +MG_Hexa_Parameters.SetGrowth( 1.1 ) +MG_Hexa_Parameters.SetFacesWithLayers( [ 10, 3 ] ) +MG_Hexa_Parameters.SetImprintedFaces( [ 18, 20, 22 ] ) + +isDone = Mesh_1.Compute() + +if not isDone: + raise Exception("Error when computing volumes with MG-Hexa and layers") + +nb_hexa_with_layers = Mesh_1.NbHexas() +assert Mesh_1.NbVolumes() == nb_hexa_with_layers +assert nb_hexa < nb_hexa_with_layers + +volume_with_layers = smesh.GetVolume(Mesh_1) +#print("volume_with_layers: ", volume_with_layers) +assert abs(volume_with_layers-expected_volume)/expected_volume < 0.05 + +gr_small_volume = Mesh_1.MakeGroup("small_volumes_layers", + SMESH.VOLUME, + CritType=SMESH.FT_Volume3D, + Compare=SMESH.FT_LessThan, + Threshold=8e-5, + Tolerance=1e-07) + +layers_volume = smesh.GetVolume(gr_small_volume) +#print("layers_volume: ", layers_volume) +assert layers_volume < 0.9 + +# check max Warp3D +max_warp3D = Mesh_1.GetMinMax(SMESH.FT_Warping3D)[1] +print("max_warp3D: ", max_warp3D) +# Check that some elements are warped +assert max_warp3D > 1 + +gr_warp3D = Mesh_1.MakeGroup("warp3D", + SMESH.VOLUME, + CritType=SMESH.FT_Warping3D, + Compare=SMESH.FT_MoreThan, + Threshold=1, + Tolerance=1e-07) + +# Check the group has some elements +assert gr_warp3D.Size() > 0 + +# create a mesh with the faces of the hexaedra thanks to medcoupling +umesh_3D = Mesh_1.ExportMEDCoupling()[0] +# create faces +umesh_2D,d0,d1,d2,d3=umesh_3D.buildDescendingConnectivity() + +# export the 2D mesh in a tmp file +tmp_filename = getTmpFileName("med") +umesh_2D.write(tmp_filename) + +# import it in SMESH +([Mesh_faces], status) = smesh.CreateMeshesFromMED( tmp_filename ) + +gr_warp2D = Mesh_faces.MakeGroup("warp2D", + SMESH.FACE, + CritType=SMESH.FT_Warping, + Compare=SMESH.FT_MoreThan, + Threshold=1, + Tolerance=1e-07) + +# check max Warp3D +max_warp2D = Mesh_faces.GetMinMax(SMESH.FT_Warping)[1] +print("max_warp2D: ", max_warp2D) +assert max_warp2D > 1 + +assert abs(max_warp2D-max_warp3D)/max_warp2D < 1e-5 + +os.remove(tmp_filename) + +if salome.sg.hasDesktop(): + salome.sg.updateObjBrowser() diff --git a/test/tests.set b/test/tests.set index 66a2564f7..fb8380f90 100644 --- a/test/tests.set +++ b/test/tests.set @@ -47,6 +47,7 @@ SET(BAD_TESTS SMESH_box_tetra.py SMESH_controls.py SMESH_controls_scaled_jacobian.py + SMESH_controls_3D_warping.py SMESH_fixation_netgen.py SMESH_fixation_tetra.py SMESH_flight_skin.py