From: asozinov Date: Mon, 15 May 2023 15:14:50 +0000 (+0100) Subject: [bos #32739][CEA] 3D warp X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=5b323f63446c838c8783792fc1fccf651b537371;p=modules%2Fsmesh.git [bos #32739][CEA] 3D warp added new eControl added new case for 3DWarp Added new class for 3D Warp Added 3D warp for use as filter Threshold of criteria Fix problem when the Threshold checkbox on Scalar Bar Properties does not remove elements outside of the range --- 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() } +// 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*/) +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