+//================================================================================
+/*
+ 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<const SMDS_MeshNode*> aNodes;
+ std::vector<long> 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);
+ }
+}
+