Salome HOME
Quality Info: tolerance change does not influence on Nb double nodes
[modules/smesh.git] / src / Controls / SMESH_Controls.cxx
index 719cd643048cdbfd47da12d5f405e78382fe8016..06c40dae2ad9c8b21d5ec8098df9528899d990c8 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2019  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
@@ -233,7 +233,7 @@ bool NumericalFunctor::GetPoints(const int       theId,
     return false;
 
   const SMDS_MeshElement* anElem = myMesh->FindElement( theId );
-  if ( !anElem || anElem->GetType() != this->GetType() )
+  if ( !IsApplicable( anElem ))
     return false;
 
   return GetPoints( anElem, theRes );
@@ -292,6 +292,24 @@ double NumericalFunctor::Round( const double & aVal )
   return ( myPrecision >= 0 ) ? floor( aVal * myPrecisionValue + 0.5 ) / myPrecisionValue : aVal;
 }
 
+//================================================================================
+/*!
+ * \brief Return true if a value can be computed for a given element.
+ *        Some NumericalFunctor's are meaningful for elements of a certain
+ *        geometry only.
+ */
+//================================================================================
+
+bool NumericalFunctor::IsApplicable( const SMDS_MeshElement* element ) const
+{
+  return element && element->GetType() == this->GetType();
+}
+
+bool NumericalFunctor::IsApplicable( long theElementId ) const
+{
+  return IsApplicable( myMesh->FindElement( theElementId ));
+}
+
 //================================================================================
 /*!
  * \brief Return histogram of functor values
@@ -901,6 +919,11 @@ double AspectRatio::GetValue( const TSequenceOfXYZ& P )
   return 0;
 }
 
+bool AspectRatio::IsApplicable( const SMDS_MeshElement* element ) const
+{
+  return ( NumericalFunctor::IsApplicable( element ) && !element->IsPoly() );
+}
+
 double AspectRatio::GetBadRate( double Value, int /*nbNodes*/ ) const
 {
   // the aspect ratio is in the range [1.0,infinity]
@@ -1007,6 +1030,11 @@ double AspectRatio3D::GetValue( long theId )
   return aVal;
 }
 
+bool AspectRatio3D::IsApplicable( const SMDS_MeshElement* element ) const
+{
+  return ( NumericalFunctor::IsApplicable( element ) && !element->IsPoly() );
+}
+
 double AspectRatio3D::GetValue( const TSequenceOfXYZ& P )
 {
   double aQuality = 0.0;
@@ -1015,11 +1043,11 @@ double AspectRatio3D::GetValue( const TSequenceOfXYZ& P )
   int nbNodes = P.size();
 
   if( myCurrElement->IsQuadratic() ) {
-    if(nbNodes==10) nbNodes=4; // quadratic tetrahedron
+    if     (nbNodes==10) nbNodes=4; // quadratic tetrahedron
     else if(nbNodes==13) nbNodes=5; // quadratic pyramid
     else if(nbNodes==15) nbNodes=6; // quadratic pentahedron
     else if(nbNodes==20) nbNodes=8; // quadratic hexahedron
-    else if(nbNodes==27) nbNodes=8; // quadratic hexahedron
+    else if(nbNodes==27) nbNodes=8; // tri-quadratic hexahedron
     else return aQuality;
   }
 
@@ -1296,6 +1324,11 @@ SMDSAbs_ElementType AspectRatio3D::GetType() const
 */
 //================================================================================
 
+bool Warping::IsApplicable( const SMDS_MeshElement* element ) const
+{
+  return NumericalFunctor::IsApplicable( element ) && element->NbNodes() == 4;
+}
+
 double Warping::GetValue( const TSequenceOfXYZ& P )
 {
   if ( P.size() != 4 )
@@ -1360,6 +1393,11 @@ SMDSAbs_ElementType Warping::GetType() const
 */
 //================================================================================
 
+bool Taper::IsApplicable( const SMDS_MeshElement* element ) const
+{
+  return ( NumericalFunctor::IsApplicable( element ) && element->NbNodes() == 4 );
+}
+
 double Taper::GetValue( const TSequenceOfXYZ& P )
 {
   if ( P.size() != 4 )
@@ -1418,6 +1456,11 @@ static inline double skewAngle( const gp_XYZ& p1, const gp_XYZ& p2, const gp_XYZ
   return v1.Magnitude() < gp::Resolution() || v2.Magnitude() < gp::Resolution() ? 0. : v1.Angle( v2 );
 }
 
+bool Skew::IsApplicable( const SMDS_MeshElement* element ) const
+{
+  return ( NumericalFunctor::IsApplicable( element ) && element->NbNodes() <= 4 );
+}
+
 double Skew::GetValue( const TSequenceOfXYZ& P )
 {
   if ( P.size() != 3 && P.size() != 4 )
@@ -1532,13 +1575,36 @@ SMDSAbs_ElementType Length::GetType() const
   return SMDSAbs_Edge;
 }
 
+//================================================================================
+/*
+  Class       : Length3D
+  Description : Functor for calculating minimal length of element edge
+*/
+//================================================================================
+
+Length3D::Length3D():
+  Length2D ( SMDSAbs_Volume )
+{
+}
+
 //================================================================================
 /*
   Class       : Length2D
-  Description : Functor for calculating minimal length of edge
+  Description : Functor for calculating minimal length of element edge
 */
 //================================================================================
 
+Length2D::Length2D( SMDSAbs_ElementType type ):
+  myType ( type )
+{
+}
+
+bool Length2D::IsApplicable( const SMDS_MeshElement* element ) const
+{
+  return ( NumericalFunctor::IsApplicable( element ) &&
+           element->GetEntityType() != SMDSEntity_Polyhedra );
+}
+
 double Length2D::GetValue( const TSequenceOfXYZ& P )
 {
   double aVal = 0;
@@ -1783,7 +1849,7 @@ double Length2D::GetBadRate( double Value, int /*nbNodes*/ ) const
 
 SMDSAbs_ElementType Length2D::GetType() const
 {
-  return SMDSAbs_Face;
+  return myType;
 }
 
 Length2D::Value::Value(double theLength,long thePntId1, long thePntId2):
@@ -1805,84 +1871,90 @@ bool Length2D::Value::operator<(const Length2D::Value& x) const
 
 void Length2D::GetValues(TValues& theValues)
 {
-  TValues aValues;
-  for ( SMDS_FaceIteratorPtr anIter = myMesh->facesIterator(); anIter->more(); )
+  if ( myType == SMDSAbs_Face )
   {
-    const SMDS_MeshFace* anElem = anIter->next();
-    if ( anElem->IsQuadratic() )
+    for ( SMDS_FaceIteratorPtr anIter = myMesh->facesIterator(); anIter->more(); )
     {
-      // use special nodes iterator
-      SMDS_NodeIteratorPtr anIter = anElem->interlacedNodesIterator();
-      long aNodeId[4] = { 0,0,0,0 };
-      gp_Pnt P[4];
-
-      double aLength = 0;
-      if ( anIter->more() )
-      {
-        const SMDS_MeshNode* aNode = anIter->next();
-        P[0] = P[1] = SMESH_NodeXYZ( aNode );
-        aNodeId[0] = aNodeId[1] = aNode->GetID();
-        aLength = 0;
-      }
-      for ( ; anIter->more(); )
+      const SMDS_MeshFace* anElem = anIter->next();
+      if ( anElem->IsQuadratic() )
       {
-        const SMDS_MeshNode* N1 = anIter->next();
-        P[2] = SMESH_NodeXYZ( N1 );
-        aNodeId[2] = N1->GetID();
-        aLength = P[1].Distance(P[2]);
-        if(!anIter->more()) break;
-        const SMDS_MeshNode* N2 = anIter->next();
-        P[3] = SMESH_NodeXYZ( N2 );
-        aNodeId[3] = N2->GetID();
-        aLength += P[2].Distance(P[3]);
+        // use special nodes iterator
+        SMDS_NodeIteratorPtr anIter = anElem->interlacedNodesIterator();
+        long aNodeId[4] = { 0,0,0,0 };
+        gp_Pnt P[4];
+
+        double aLength = 0;
+        if ( anIter->more() )
+        {
+          const SMDS_MeshNode* aNode = anIter->next();
+          P[0] = P[1] = SMESH_NodeXYZ( aNode );
+          aNodeId[0] = aNodeId[1] = aNode->GetID();
+          aLength = 0;
+        }
+        for ( ; anIter->more(); )
+        {
+          const SMDS_MeshNode* N1 = anIter->next();
+          P[2] = SMESH_NodeXYZ( N1 );
+          aNodeId[2] = N1->GetID();
+          aLength = P[1].Distance(P[2]);
+          if(!anIter->more()) break;
+          const SMDS_MeshNode* N2 = anIter->next();
+          P[3] = SMESH_NodeXYZ( N2 );
+          aNodeId[3] = N2->GetID();
+          aLength += P[2].Distance(P[3]);
+          Value aValue1(aLength,aNodeId[1],aNodeId[2]);
+          Value aValue2(aLength,aNodeId[2],aNodeId[3]);
+          P[1] = P[3];
+          aNodeId[1] = aNodeId[3];
+          theValues.insert(aValue1);
+          theValues.insert(aValue2);
+        }
+        aLength += P[2].Distance(P[0]);
         Value aValue1(aLength,aNodeId[1],aNodeId[2]);
-        Value aValue2(aLength,aNodeId[2],aNodeId[3]);
-        P[1] = P[3];
-        aNodeId[1] = aNodeId[3];
+        Value aValue2(aLength,aNodeId[2],aNodeId[0]);
         theValues.insert(aValue1);
         theValues.insert(aValue2);
       }
-      aLength += P[2].Distance(P[0]);
-      Value aValue1(aLength,aNodeId[1],aNodeId[2]);
-      Value aValue2(aLength,aNodeId[2],aNodeId[0]);
-      theValues.insert(aValue1);
-      theValues.insert(aValue2);
-    }
-    else {
-      SMDS_NodeIteratorPtr aNodesIter = anElem->nodeIterator();
-      long aNodeId[2] = {0,0};
-      gp_Pnt P[3];
+      else {
+        SMDS_NodeIteratorPtr aNodesIter = anElem->nodeIterator();
+        long aNodeId[2] = {0,0};
+        gp_Pnt P[3];
+
+        double aLength;
+        const SMDS_MeshElement* aNode;
+        if ( aNodesIter->more())
+        {
+          aNode = aNodesIter->next();
+          P[0] = P[1] = SMESH_NodeXYZ( aNode );
+          aNodeId[0] = aNodeId[1] = aNode->GetID();
+          aLength = 0;
+        }
+        for( ; aNodesIter->more(); )
+        {
+          aNode = aNodesIter->next();
+          long anId = aNode->GetID();
 
-      double aLength;
-      const SMDS_MeshElement* aNode;
-      if ( aNodesIter->more())
-      {
-        aNode = aNodesIter->next();
-        P[0] = P[1] = SMESH_NodeXYZ( aNode );
-        aNodeId[0] = aNodeId[1] = aNode->GetID();
-        aLength = 0;
-      }
-      for( ; aNodesIter->more(); )
-      {
-        aNode = aNodesIter->next();
-        long anId = aNode->GetID();
+          P[2] = SMESH_NodeXYZ( aNode );
+
+          aLength = P[1].Distance(P[2]);
 
-        P[2] = SMESH_NodeXYZ( aNode );
+          Value aValue(aLength,aNodeId[1],anId);
+          aNodeId[1] = anId;
+          P[1] = P[2];
+          theValues.insert(aValue);
+        }
 
-        aLength = P[1].Distance(P[2]);
+        aLength = P[0].Distance(P[1]);
 
-        Value aValue(aLength,aNodeId[1],anId);
-        aNodeId[1] = anId;
-        P[1] = P[2];
+        Value aValue(aLength,aNodeId[0],aNodeId[1]);
         theValues.insert(aValue);
       }
-
-      aLength = P[0].Distance(P[1]);
-
-      Value aValue(aLength,aNodeId[0],aNodeId[1]);
-      theValues.insert(aValue);
     }
   }
+  else
+  {
+    // not implemented
+  }
 }
 
 //================================================================================
@@ -2364,6 +2436,15 @@ SMDSAbs_ElementType CoincidentNodes::GetType() const
   return SMDSAbs_Node;
 }
 
+void CoincidentNodes::SetTolerance( const double theToler )
+{
+  if ( myToler != theToler )
+  {
+    SetMesh(0);
+    myToler = theToler;
+  }
+}
+
 void CoincidentNodes::SetMesh( const SMDS_Mesh* theMesh )
 {
   myMeshModifTracer.SetMesh( theMesh );
@@ -2493,18 +2574,14 @@ void FreeEdges::SetMesh( const SMDS_Mesh* theMesh )
 
 bool FreeEdges::IsFreeEdge( const SMDS_MeshNode** theNodes, const int theFaceId  )
 {
-  TColStd_MapOfInteger aMap;
-  for ( int i = 0; i < 2; i++ )
+  SMDS_ElemIteratorPtr anElemIter = theNodes[ 0 ]->GetInverseElementIterator(SMDSAbs_Face);
+  while( anElemIter->more() )
   {
-    SMDS_ElemIteratorPtr anElemIter = theNodes[ i ]->GetInverseElementIterator(SMDSAbs_Face);
-    while( anElemIter->more() )
+    if ( const SMDS_MeshElement* anElem = anElemIter->next())
     {
-      if ( const SMDS_MeshElement* anElem = anElemIter->next())
-      {
-        const int anId = anElem->GetID();
-        if ( anId != theFaceId && !aMap.Add( anId ))
-          return false;
-      }
+      const int anId = anElem->GetID();
+      if ( anId != theFaceId && anElem->GetNodeIndex( theNodes[1] ) >= 0 )
+        return false;
     }
   }
   return true;
@@ -4170,6 +4247,7 @@ struct ElementsOnShape::Classifier
   TopAbs_ShapeEnum ShapeType() const { return myShape.ShapeType(); }
   const TopoDS_Shape& Shape() const  { return myShape; }
   const Bnd_B3d* GetBndBox() const   { return & myBox; }
+  double Tolerance() const           { return myTol; }
   bool IsChecked()                   { return myFlags & theIsCheckedFlag; }
   bool IsSetFlag( int flag ) const   { return myFlags & flag; }
   void SetChecked( bool is ) { is ? SetFlag( theIsCheckedFlag ) : UnsetFlag( theIsCheckedFlag ); }
@@ -4203,6 +4281,8 @@ struct ElementsOnShape::OctreeClassifier : public SMESH_Octree
                     std::vector< ElementsOnShape::Classifier >&       cls );
   void GetClassifiersAtPoint( const gp_XYZ& p,
                               std::vector< ElementsOnShape::Classifier* >& classifiers );
+  size_t GetSize();
+
 protected:
   OctreeClassifier() {}
   SMESH_Octree* newChild() const { return new OctreeClassifier; }
@@ -4228,6 +4308,21 @@ ElementsOnShape::~ElementsOnShape()
 
 Predicate* ElementsOnShape::clone() const
 {
+  size_t size = sizeof( *this );
+  if ( myOctree )
+    size += myOctree->GetSize();
+  if ( !myClassifiers.empty() )
+    size += sizeof( myClassifiers[0] ) * myClassifiers.size();
+  if ( !myWorkClassifiers.empty() )
+    size += sizeof( myWorkClassifiers[0] ) * myWorkClassifiers.size();
+  if ( size > 1e+9 ) // 1G
+  {
+#ifdef _DEBUG_
+    std::cout << "Avoid ElementsOnShape::clone(), too large: " << size << " bytes " << std::endl;
+#endif
+    return 0;
+  }
+
   ElementsOnShape* cln = new ElementsOnShape();
   cln->SetAllNodes ( myAllNodesFlag );
   cln->SetTolerance( myToler );
@@ -4384,12 +4479,13 @@ bool ElementsOnShape::IsSatisfy (const SMDS_MeshElement* elem)
     for ( size_t i = 0; i < myClassifiers.size(); ++i )
       myWorkClassifiers[ i ] = & myClassifiers[ i ];
     myOctree = new OctreeClassifier( myWorkClassifiers );
+
+    SMESHUtils::FreeVector( myWorkClassifiers );
   }
 
-  SMDS_ElemIteratorPtr aNodeItr = elem->nodesIterator();
-  while (aNodeItr->more() && (isSatisfy == myAllNodesFlag))
+  for ( int i = 0, nb = elem->NbNodes(); i < nb  && (isSatisfy == myAllNodesFlag); ++i )
   {
-    SMESH_TNodeXYZ aPnt( aNodeItr->next() );
+    SMESH_TNodeXYZ aPnt( elem->GetNode( i ));
     centerXYZ += aPnt;
 
     isNodeOut = true;
@@ -4555,7 +4651,15 @@ void ElementsOnShape::Classifier::Init( const TopoDS_Shape& theShape,
     else
     {
       Bnd_Box box;
-      BRepBndLib::Add( myShape, box );
+      if ( myShape.ShapeType() == TopAbs_FACE )
+      {
+        BRepAdaptor_Surface SA( TopoDS::Face( myShape ), /*useBoundaries=*/false );
+        if ( SA.GetType() == GeomAbs_BSplineSurface )
+          BRepBndLib::AddOptimal( myShape, box,
+                                  /*useTriangulation=*/true, /*useShapeTolerance=*/true );
+      }
+      if ( box.IsVoid() )
+        BRepBndLib::Add( myShape, box );
       myBox.Clear();
       myBox.Add( box.CornerMin() );
       myBox.Add( box.CornerMax() );
@@ -4575,19 +4679,19 @@ ElementsOnShape::Classifier::~Classifier()
   delete mySolidClfr; mySolidClfr = 0;
 }
 
-bool ElementsOnShape::Classifier::isOutOfSolid (const gp_Pnt& p)
+bool ElementsOnShape::Classifier::isOutOfSolid( const gp_Pnt& p )
 {
   if ( isOutOfBox( p )) return true;
   mySolidClfr->Perform( p, myTol );
   return ( mySolidClfr->State() != TopAbs_IN && mySolidClfr->State() != TopAbs_ON );
 }
 
-bool ElementsOnShape::Classifier::isOutOfBox (const gp_Pnt& p)
+bool ElementsOnShape::Classifier::isOutOfBox( const gp_Pnt& p )
 {
   return myBox.IsOut( p.XYZ() );
 }
 
-bool ElementsOnShape::Classifier::isOutOfFace  (const gp_Pnt& p)
+bool ElementsOnShape::Classifier::isOutOfFace( const gp_Pnt& p )
 {
   if ( isOutOfBox( p )) return true;
   myProjFace.Perform( p );
@@ -4604,19 +4708,19 @@ bool ElementsOnShape::Classifier::isOutOfFace  (const gp_Pnt& p)
   return true;
 }
 
-bool ElementsOnShape::Classifier::isOutOfEdge  (const gp_Pnt& p)
+bool ElementsOnShape::Classifier::isOutOfEdge( const gp_Pnt& p )
 {
   if ( isOutOfBox( p )) return true;
   myProjEdge.Perform( p );
   return ! ( myProjEdge.NbPoints() > 0 && myProjEdge.LowerDistance() <= myTol );
 }
 
-bool ElementsOnShape::Classifier::isOutOfVertex(const gp_Pnt& p)
+bool ElementsOnShape::Classifier::isOutOfVertex( const gp_Pnt& p )
 {
   return ( myVertexXYZ.Distance( p ) > myTol );
 }
 
-bool ElementsOnShape::Classifier::isBox (const TopoDS_Shape& theShape)
+bool ElementsOnShape::Classifier::isBox(const TopoDS_Shape& theShape )
 {
   TopTools_IndexedMapOfShape vMap;
   TopExp::MapShapes( theShape, TopAbs_VERTEX, vMap );
@@ -4698,6 +4802,19 @@ OctreeClassifier::GetClassifiersAtPoint( const gp_XYZ& point,
   }
 }
 
+size_t ElementsOnShape::OctreeClassifier::GetSize()
+{
+  size_t res = sizeof( *this );
+  if ( !myClassifiers.empty() )
+    res += sizeof( myClassifiers[0] ) * myClassifiers.size();
+
+  if ( !isLeaf() )
+    for (int i = 0; i < nbChildren(); i++)
+      res += ((OctreeClassifier*) myChildren[i])->GetSize();
+
+  return res;
+}
+
 void ElementsOnShape::OctreeClassifier::buildChildrenData()
 {
   // distribute myClassifiers among myChildren
@@ -4744,7 +4861,8 @@ void ElementsOnShape::OctreeClassifier::buildChildrenData()
   for ( int i = 0; i < nbChildren(); i++ )
   {
     OctreeClassifier* child = static_cast<OctreeClassifier*>( myChildren[ i ]);
-    child->myIsLeaf = ( child->myClassifiers.size() <= 5  );
+    child->myIsLeaf = ( child->myClassifiers.size() <= 5  ||
+                        child->maxSize() < child->myClassifiers[0]->Tolerance() );
   }
 }
 
@@ -4771,8 +4889,13 @@ BelongToGeom::BelongToGeom()
 
 Predicate* BelongToGeom::clone() const
 {
-  BelongToGeom* cln = new BelongToGeom( *this );
-  cln->myElementsOnShapePtr.reset( static_cast<ElementsOnShape*>( myElementsOnShapePtr->clone() ));
+  BelongToGeom* cln = 0;
+  if ( myElementsOnShapePtr )
+    if ( ElementsOnShape* eos = static_cast<ElementsOnShape*>( myElementsOnShapePtr->clone() ))
+    {
+      cln = new BelongToGeom( *this );
+      cln->myElementsOnShapePtr.reset( eos );
+    }
   return cln;
 }
 
@@ -4783,6 +4906,8 @@ void BelongToGeom::SetMesh( const SMDS_Mesh* theMesh )
     myMeshDS = dynamic_cast<const SMESHDS_Mesh*>(theMesh);
     init();
   }
+  if ( myElementsOnShapePtr )
+    myElementsOnShapePtr->SetMesh( myMeshDS );
 }
 
 void BelongToGeom::SetGeom( const TopoDS_Shape& theShape )
@@ -4942,8 +5067,13 @@ LyingOnGeom::LyingOnGeom()
 
 Predicate* LyingOnGeom::clone() const
 {
-  LyingOnGeom* cln = new LyingOnGeom( *this );
-  cln->myElementsOnShapePtr.reset( static_cast<ElementsOnShape*>( myElementsOnShapePtr->clone() ));
+  LyingOnGeom* cln = 0;
+  if ( myElementsOnShapePtr )
+    if ( ElementsOnShape* eos = static_cast<ElementsOnShape*>( myElementsOnShapePtr->clone() ))
+    {
+      cln = new LyingOnGeom( *this );
+      cln->myElementsOnShapePtr.reset( eos );
+    }
   return cln;
 }
 
@@ -4954,6 +5084,8 @@ void LyingOnGeom::SetMesh( const SMDS_Mesh* theMesh )
     myMeshDS = dynamic_cast<const SMESHDS_Mesh*>(theMesh);
     init();
   }
+  if ( myElementsOnShapePtr )
+    myElementsOnShapePtr->SetMesh( myMeshDS );
 }
 
 void LyingOnGeom::SetGeom( const TopoDS_Shape& theShape )