Salome HOME
Update copyright
[modules/smesh.git] / src / Controls / SMESH_Controls.cxx
index 5238b982f3c55ee99f83bf4048d2096b2f866e3c..04a587dba823b7d45d5c18dc90b83c1a568363a7 100644 (file)
@@ -1,23 +1,23 @@
-//  Copyright (C) 2007-2010  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2011  CEA/DEN, EDF R&D, OPEN CASCADE
 //
-//  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
-//  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+// Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
 //
-//  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.
+// 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.
 //
-//  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.
+// 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
+// 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
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 
 #include "SMESH_ControlsDef.hxx"
@@ -66,6 +66,8 @@
 #include "SMESHDS_Mesh.hxx"
 #include "SMESHDS_GroupBase.hxx"
 
+#include <vtkMeshQuality.h>
+
 /*
                             AUXILIARY METHODS
 */
@@ -250,11 +252,11 @@ bool NumericalFunctor::GetPoints(const SMDS_MeshElement* anElem,
   if ( anElem->IsQuadratic() ) {
     switch ( anElem->GetType() ) {
     case SMDSAbs_Edge:
-      anIter = static_cast<const SMDS_QuadraticEdge*>
+      anIter = dynamic_cast<const SMDS_VtkEdge*>
         (anElem)->interlacedNodesElemIterator();
       break;
     case SMDSAbs_Face:
-      anIter = static_cast<const SMDS_QuadraticFaceOfNodes*>
+      anIter = dynamic_cast<const SMDS_VtkFace*>
         (anElem)->interlacedNodesElemIterator();
       break;
     default:
@@ -284,24 +286,25 @@ long  NumericalFunctor::GetPrecision() const
 void  NumericalFunctor::SetPrecision( const long thePrecision )
 {
   myPrecision = thePrecision;
+  myPrecisionValue = pow( 10., (double)( myPrecision ) );
 }
 
 double NumericalFunctor::GetValue( long theId )
 {
+  double aVal = 0;
+
   myCurrElement = myMesh->FindElement( theId );
+
   TSequenceOfXYZ P;
   if ( GetPoints( theId, P ))
-  {
-    double aVal = GetValue( P );
-    if ( myPrecision >= 0 )
-    {
-      double prec = pow( 10., (double)( myPrecision ) );
-      aVal = floor( aVal * prec + 0.5 ) / prec;
-    }
-    return aVal;
-  }
+    aVal = Round( GetValue( P ));
 
-  return 0.;
+  return aVal;
+}
+
+double NumericalFunctor::Round( const double & aVal )
+{
+  return ( myPrecision >= 0 ) ? floor( aVal * myPrecisionValue + 0.5 ) / myPrecisionValue : aVal;
 }
 
 //================================================================================
@@ -310,12 +313,16 @@ double NumericalFunctor::GetValue( long theId )
  *  \param nbIntervals - number of intervals
  *  \param nbEvents - number of mesh elements having values within i-th interval
  *  \param funValues - boundaries of intervals
+ *  \param elements - elements to check vulue of; empty list means "of all"
+ *  \param minmax - boundaries of diapason of values to divide into intervals
  */
 //================================================================================
 
 void NumericalFunctor::GetHistogram(int                  nbIntervals,
                                     std::vector<int>&    nbEvents,
-                                    std::vector<double>& funValues)
+                                    std::vector<double>& funValues,
+                                    const vector<int>&   elements,
+                                    const double*        minmax)
 {
   if ( nbIntervals < 1 ||
        !myMesh ||
@@ -326,13 +333,30 @@ void NumericalFunctor::GetHistogram(int                  nbIntervals,
 
   // get all values sorted
   std::multiset< double > values;
-  SMDS_ElemIteratorPtr elemIt = myMesh->elementsIterator(GetType());
-  while ( elemIt->more() )
-    values.insert( GetValue( elemIt->next()->GetID() ));
+  if ( elements.empty() )
+  {
+    SMDS_ElemIteratorPtr elemIt = myMesh->elementsIterator(GetType());
+    while ( elemIt->more() )
+      values.insert( GetValue( elemIt->next()->GetID() ));
+  }
+  else
+  {
+    vector<int>::const_iterator id = elements.begin();
+    for ( ; id != elements.end(); ++id )
+      values.insert( GetValue( *id ));
+  }
 
+  if ( minmax )
+  {
+    funValues[0] = minmax[0];
+    funValues[nbIntervals] = minmax[1];
+  }
+  else
+  {
+    funValues[0] = *values.begin();
+    funValues[nbIntervals] = *values.rbegin();
+  }
   // case nbIntervals == 1
-  funValues[0] = *values.begin();
-  funValues[nbIntervals] = *values.rbegin();
   if ( nbIntervals == 1 )
   {
     nbEvents[0] = values.size();
@@ -350,15 +374,21 @@ void NumericalFunctor::GetHistogram(int                  nbIntervals,
   std::multiset< double >::iterator min = values.begin(), max;
   for ( int i = 0; i < nbIntervals; ++i )
   {
+    // find end value of i-th interval
     double r = (i+1) / double( nbIntervals );
     funValues[i+1] = funValues.front() * (1-r) + funValues.back() * r;
+
+    // count values in the i-th interval if there are any
     if ( min != values.end() && *min <= funValues[i+1] )
     {
-      max = values.upper_bound( funValues[i+1] ); // greater than funValues[i+1], or end()
+      // find the first value out of the interval
+      max = values.upper_bound( funValues[i+1] ); // max is greater than funValues[i+1], or end()
       nbEvents[i] = std::distance( min, max );
       min = max;
     }
   }
+  // add values larger than minmax[1]
+  nbEvents.back() += std::distance( min, values.end() );
 }
 
 //=======================================================================
@@ -902,6 +932,28 @@ namespace{
 
 }
 
+double AspectRatio3D::GetValue( long theId )
+{
+  double aVal = 0;
+  myCurrElement = myMesh->FindElement( theId );
+  if ( myCurrElement && myCurrElement->GetVtkType() == VTK_TETRA )
+  {
+    // Action from CoTech | ACTION 31.3:
+    // EURIWARE BO: Homogenize the formulas used to calculate the Controls in SMESH to fit with
+    // those of ParaView. The library used by ParaView for those calculations can be reused in SMESH.
+    vtkUnstructuredGrid* grid = SMDS_Mesh::_meshList[myCurrElement->getMeshId()]->getGrid();
+    if ( vtkCell* avtkCell = grid->GetCell( myCurrElement->getVtkId() ))
+      aVal = Round( vtkMeshQuality::TetAspectRatio( avtkCell ));
+  }
+  else
+  {
+    TSequenceOfXYZ P;
+    if ( GetPoints( myCurrElement, P ))
+      aVal = Round( GetValue( P ));
+  }
+  return aVal;
+}
+
 double AspectRatio3D::GetValue( const TSequenceOfXYZ& P )
 {
   double aQuality = 0.0;
@@ -1622,10 +1674,10 @@ void Length2D::GetValues(TValues& theValues){
     const SMDS_MeshFace* anElem = anIter->next();
 
     if(anElem->IsQuadratic()) {
-      const SMDS_QuadraticFaceOfNodes* F =
-        static_cast<const SMDS_QuadraticFaceOfNodes*>(anElem);
+      const SMDS_VtkFace* F =
+        dynamic_cast<const SMDS_VtkFace*>(anElem);
       // use special nodes iterator
-      SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
+      SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
       long aNodeId[4];
       gp_Pnt P[4];
 
@@ -1819,7 +1871,7 @@ void MultiConnection2D::GetValues(MValues& theValues){
     const SMDS_MeshFace* anElem = anIter->next();
     SMDS_ElemIteratorPtr aNodesIter;
     if ( anElem->IsQuadratic() )
-      aNodesIter = static_cast<const SMDS_QuadraticFaceOfNodes*>
+      aNodesIter = dynamic_cast<const SMDS_VtkFace*>
         (anElem)->interlacedNodesElemIterator();
     else
       aNodesIter = anElem->nodesIterator();
@@ -1902,7 +1954,118 @@ SMDSAbs_ElementType BadOrientedVolume::GetType() const
   return SMDSAbs_Volume;
 }
 
+/*
+  Class       : BareBorderVolume
+*/
+
+bool BareBorderVolume::IsSatisfy(long theElementId )
+{
+  SMDS_VolumeTool  myTool;
+  if ( myTool.Set( myMesh->FindElement(theElementId)))
+  {
+    for ( int iF = 0; iF < myTool.NbFaces(); ++iF )
+      if ( myTool.IsFreeFace( iF ))
+      {
+        const SMDS_MeshNode** n = myTool.GetFaceNodes(iF);
+        vector< const SMDS_MeshNode*> nodes( n, n+myTool.NbFaceNodes(iF));
+        if ( !myMesh->FindElement( nodes, SMDSAbs_Face, /*Nomedium=*/false))
+          return true;
+      }
+  }
+  return false;
+}
+
+/*
+  Class       : BareBorderFace
+*/
+
+bool BareBorderFace::IsSatisfy(long theElementId )
+{
+  bool ok = false;
+  if ( const SMDS_MeshElement* face = myMesh->FindElement(theElementId))
+  {
+    if ( face->GetType() == SMDSAbs_Face )
+    {
+      int nbN = face->NbCornerNodes();
+      for ( int i = 0; i < nbN && !ok; ++i )
+      {
+        // check if a link is shared by another face
+        const SMDS_MeshNode* n1 = face->GetNode( i );
+        const SMDS_MeshNode* n2 = face->GetNode( (i+1)%nbN );
+        SMDS_ElemIteratorPtr fIt = n1->GetInverseElementIterator( SMDSAbs_Face );
+        bool isShared = false;
+        while ( !isShared && fIt->more() )
+        {
+          const SMDS_MeshElement* f = fIt->next();
+          isShared = ( f != face && f->GetNodeIndex(n2) != -1 );
+        }
+        if ( !isShared )
+        {
+          myLinkNodes.resize( 2 + face->IsQuadratic());
+          myLinkNodes[0] = n1;
+          myLinkNodes[1] = n2;
+          if ( face->IsQuadratic() )
+            myLinkNodes[2] = face->GetNode( i+nbN );
+          ok = !myMesh->FindElement( myLinkNodes, SMDSAbs_Edge, /*noMedium=*/false);
+        }
+      }
+    }
+  }
+  return ok;
+}
+
+/*
+  Class       : OverConstrainedVolume
+*/
+
+bool OverConstrainedVolume::IsSatisfy(long theElementId )
+{
+  // An element is over-constrained if it has N-1 free borders where
+  // N is the number of edges/faces for a 2D/3D element.
+  SMDS_VolumeTool  myTool;
+  if ( myTool.Set( myMesh->FindElement(theElementId)))
+  {
+    int nbSharedFaces = 0;
+    for ( int iF = 0; iF < myTool.NbFaces(); ++iF )
+      if ( !myTool.IsFreeFace( iF ) && ++nbSharedFaces > 1 )
+        break;
+    return ( nbSharedFaces == 1 );
+  }
+  return false;
+}
+
+/*
+  Class       : OverConstrainedFace
+*/
 
+bool OverConstrainedFace::IsSatisfy(long theElementId )
+{
+  // An element is over-constrained if it has N-1 free borders where
+  // N is the number of edges/faces for a 2D/3D element.
+  if ( const SMDS_MeshElement* face = myMesh->FindElement(theElementId))
+    if ( face->GetType() == SMDSAbs_Face )
+    {
+      int nbSharedBorders = 0;
+      int nbN = face->NbCornerNodes();
+      for ( int i = 0; i < nbN; ++i )
+      {
+        // check if a link is shared by another face
+        const SMDS_MeshNode* n1 = face->GetNode( i );
+        const SMDS_MeshNode* n2 = face->GetNode( (i+1)%nbN );
+        SMDS_ElemIteratorPtr fIt = n1->GetInverseElementIterator( SMDSAbs_Face );
+        bool isShared = false;
+        while ( !isShared && fIt->more() )
+        {
+          const SMDS_MeshElement* f = fIt->next();
+          isShared = ( f != face && f->GetNodeIndex(n2) != -1 );
+        }
+        if ( isShared && ++nbSharedBorders > 1 )
+          break;
+      }
+      return ( nbSharedBorders == 1 );
+    }
+  return false;
+}
 
 /*
   Class       : FreeBorders
@@ -1978,7 +2141,7 @@ bool FreeEdges::IsSatisfy( long theId )
 
   SMDS_ElemIteratorPtr anIter;
   if ( aFace->IsQuadratic() ) {
-    anIter = static_cast<const SMDS_QuadraticFaceOfNodes*>
+    anIter = dynamic_cast<const SMDS_VtkFace*>
       (aFace)->interlacedNodesElemIterator();
   }
   else {
@@ -2047,7 +2210,7 @@ void FreeEdges::GetBoreders(TBorders& theBorders)
     long anElemId = anElem->GetID();
     SMDS_ElemIteratorPtr aNodesIter;
     if ( anElem->IsQuadratic() )
-      aNodesIter = static_cast<const SMDS_QuadraticFaceOfNodes*>(anElem)->
+      aNodesIter = static_cast<const SMDS_VtkFace*>(anElem)->
         interlacedNodesElemIterator();
     else
       aNodesIter = anElem->nodesIterator();
@@ -2588,8 +2751,8 @@ bool RangeOfIds::SetRangeStr( const TCollection_AsciiString& theStr )
       while ( aMinStr.Search( "-" ) != -1 ) aMinStr.RemoveAll( '-' );
       while ( aMaxStr.Search( "-" ) != -1 ) aMaxStr.RemoveAll( '-' );
 
-      if ( !aMinStr.IsEmpty() && !aMinStr.IsIntegerValue() ||
-           !aMaxStr.IsEmpty() && !aMaxStr.IsIntegerValue() )
+      if ( (!aMinStr.IsEmpty() && !aMinStr.IsIntegerValue()) ||
+           (!aMaxStr.IsEmpty() && !aMaxStr.IsIntegerValue()) )
         return false;
 
       myMin.Append( aMinStr.IsEmpty() ? IntegerFirst() : aMinStr.IntegerValue() );
@@ -2635,7 +2798,7 @@ bool RangeOfIds::IsSatisfy( long theId )
   else
   {
     const SMDS_MeshElement* anElem = myMesh->FindElement( theId );
-    if ( anElem == 0 || myType != anElem->GetType() && myType != SMDSAbs_All )
+    if ( anElem == 0 || (myType != anElem->GetType() && myType != SMDSAbs_All ))
       return false;
   }
 
@@ -2826,8 +2989,8 @@ bool LogicalOR::IsSatisfy( long theId )
   return
     myPredicate1 &&
     myPredicate2 &&
-    myPredicate1->IsSatisfy( theId ) ||
-    myPredicate2->IsSatisfy( theId );
+    (myPredicate1->IsSatisfy( theId ) ||
+    myPredicate2->IsSatisfy( theId ));
 }
 
 
@@ -3225,7 +3388,7 @@ void ManifoldPart::expandBoundary
 void ManifoldPart::getFacesByLink( const ManifoldPart::Link& theLink,
                                    ManifoldPart::TVectorOfFacePtr& theFaces ) const
 {
-  SMDS_Mesh::SetOfFaces aSetOfFaces;
+  std::set<SMDS_MeshCell *> aSetOfFaces;
   // take all faces that shared first node
   SMDS_ElemIteratorPtr anItr = theLink.myNode1->facesIterator();
   for ( ; anItr->more(); )
@@ -3233,7 +3396,7 @@ void ManifoldPart::getFacesByLink( const ManifoldPart::Link& theLink,
     SMDS_MeshFace* aFace = (SMDS_MeshFace*)anItr->next();
     if ( !aFace )
       continue;
-    aSetOfFaces.Add( aFace );
+    aSetOfFaces.insert( aFace );
   }
   // take all faces that shared second node
   anItr = theLink.myNode2->facesIterator();
@@ -3241,7 +3404,7 @@ void ManifoldPart::getFacesByLink( const ManifoldPart::Link& theLink,
   for ( ; anItr->more(); )
   {
     SMDS_MeshFace* aFace = (SMDS_MeshFace*)anItr->next();
-    if ( aSetOfFaces.Contains( aFace ) )
+    if ( aSetOfFaces.count( aFace ) )
       theFaces.push_back( aFace );
   }
 }