Salome HOME
23462: [CEA 2142] Import12D fails
[modules/smesh.git] / src / Controls / SMESH_Controls.cxx
index bc79e1fc70abe3bc8d254029b6c9ab20bdf0201e..9485d983eca2f5929d0385946c9afb3d3fff3a7c 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2016  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
@@ -39,6 +39,8 @@
 #include <Basics_Utils.hxx>
 
 #include <BRepAdaptor_Surface.hxx>
+#include <BRepBndLib.hxx>
+#include <BRepBuilderAPI_Copy.hxx>
 #include <BRepClass_FaceClassifier.hxx>
 #include <BRep_Tool.hxx>
 #include <Geom_CylindricalSurface.hxx>
@@ -132,7 +134,7 @@ namespace {
     //  +-----+------+  +-----+------+ 
     //  |            |  |            |
     //  |            |  |            |
-    // result sould be 2 in both cases
+    // result should be 2 in both cases
     //
     int aResult0 = 0, aResult1 = 0;
      // last node, it is a medium one in a quadratic edge
@@ -1832,10 +1834,10 @@ void Length2D::GetValues(TValues& theValues)
         dynamic_cast<const SMDS_VtkFace*>(anElem);
       // use special nodes iterator
       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
-      long aNodeId[4];
+      long aNodeId[4] = { 0,0,0,0 };
       gp_Pnt P[4];
 
-      double aLength;
+      double aLength = 0;
       const SMDS_MeshElement* aNode;
       if(anIter->more()){
         aNode = anIter->next();
@@ -1869,7 +1871,7 @@ void Length2D::GetValues(TValues& theValues)
     }
     else {
       SMDS_ElemIteratorPtr aNodesIter = anElem->nodesIterator();
-      long aNodeId[2];
+      long aNodeId[2] = {0,0};
       gp_Pnt P[3];
 
       double aLength;
@@ -1957,7 +1959,7 @@ double MultiConnection2D::GetValue( long theElementId )
       SMDS_ElemIteratorPtr anIter = aFaceElem->nodesIterator();
       if (!anIter) break;
 
-      const SMDS_MeshNode *aNode, *aNode0;
+      const SMDS_MeshNode *aNode, *aNode0 = 0;
       TColStd_MapOfInteger aMap, aMapPrev;
 
       for (i = 0; i <= len; i++) {
@@ -2038,7 +2040,7 @@ void MultiConnection2D::GetValues(MValues& theValues)
         (anElem)->interlacedNodesElemIterator();
     else
       aNodesIter = anElem->nodesIterator();
-    long aNodeId[3];
+    long aNodeId[3] = {0,0,0};
 
     //int aNbConnects=0;
     const SMDS_MeshNode* aNode0;
@@ -2114,6 +2116,42 @@ SMDSAbs_ElementType BallDiameter::GetType() const
   return SMDSAbs_Ball;
 }
 
+//================================================================================
+/*
+  Class       : NodeConnectivityNumber
+  Description : Functor returning number of elements connected to a node
+*/
+//================================================================================
+
+double NodeConnectivityNumber::GetValue( long theId )
+{
+  double nb = 0;
+
+  if ( const SMDS_MeshNode* node = myMesh->FindNode( theId ))
+  {
+    SMDSAbs_ElementType type;
+    if ( myMesh->NbVolumes() > 0 )
+      type = SMDSAbs_Volume;
+    else if ( myMesh->NbFaces() > 0 )
+      type = SMDSAbs_Face;
+    else if ( myMesh->NbEdges() > 0 )
+      type = SMDSAbs_Edge;
+    else
+      return 0;
+    nb = node->NbInverseElements( type );
+  }
+  return nb;
+}
+
+double NodeConnectivityNumber::GetBadRate( double Value, int /*nbNodes*/ ) const
+{
+  return Value;
+}
+
+SMDSAbs_ElementType NodeConnectivityNumber::GetType() const
+{
+  return SMDSAbs_Node;
+}
 
 /*
                             PREDICATES
@@ -2511,7 +2549,7 @@ void FreeEdges::GetBoreders(TBorders& theBorders)
         interlacedNodesElemIterator();
     else
       aNodesIter = anElem->nodesIterator();
-    long aNodeId[2];
+    long aNodeId[2] = {0,0};
     const SMDS_MeshElement* aNode;
     if(aNodesIter->more()){
       aNode = aNodesIter->next();
@@ -2612,7 +2650,7 @@ bool FreeFaces::IsSatisfy( long theId )
   for ( ; volItr != volEnd; ++volItr )
     if ( (*volItr).second >= nbNode )
        nbVol++;
-  // face is not free if number of volumes constructed on thier nodes more than one
+  // face is not free if number of volumes constructed on their nodes more than one
   return (nbVol < 2);
 }
 
@@ -2660,7 +2698,7 @@ SMDSAbs_ElementType LinearOrQuadratic::GetType() const
 //================================================================================
 /*
   Class       : GroupColor
-  Description : Functor for check color of group to whic mesh element belongs to
+  Description : Functor for check color of group to which mesh element belongs to
 */
 //================================================================================
 
@@ -3218,7 +3256,7 @@ bool RangeOfIds::SetRangeStr( const TCollection_AsciiString& theStr )
   {
     char c = aStr.Value( i );
     if ( !isdigit( c ) && c != ',' && c != '-' )
-      aStr.SetValue( i, ' ');
+      aStr.SetValue( i, ',');
   }
   aStr.RemoveAll( ' ' );
 
@@ -3949,9 +3987,9 @@ SMDSAbs_ElementType BelongToMeshGroup::GetType() const
   return myGroup ? myGroup->GetType() : SMDSAbs_All;
 }
 
-/*
-  ElementsOnSurface
-*/
+//================================================================================
+//  ElementsOnSurface
+//================================================================================
 
 ElementsOnSurface::ElementsOnSurface()
 {
@@ -4085,15 +4123,71 @@ bool ElementsOnSurface::isOnSurface( const SMDS_MeshNode* theNode )
 }
 
 
-/*
-  ElementsOnShape
-*/
+//================================================================================
+//  ElementsOnShape
+//================================================================================
 
-ElementsOnShape::ElementsOnShape()
-  : //myMesh(0),
-    myType(SMDSAbs_All),
-    myToler(Precision::Confusion()),
-    myAllNodesFlag(false)
+namespace {
+  const int theIsCheckedFlag = 0x0000100;
+}
+
+struct ElementsOnShape::Classifier
+{
+  Classifier() { mySolidClfr = 0; myFlags = 0; }
+  ~Classifier();
+  void Init(const TopoDS_Shape& s, double tol, const Bnd_B3d* box = 0 );
+  bool IsOut(const gp_Pnt& p)        { return SetChecked( true ), (this->*myIsOutFun)( p ); }
+  TopAbs_ShapeEnum ShapeType() const { return myShape.ShapeType(); }
+  const TopoDS_Shape& Shape() const  { return myShape; }
+  const Bnd_B3d* GetBndBox() const   { return & myBox; }
+  bool IsChecked()                   { return myFlags & theIsCheckedFlag; }
+  bool IsSetFlag( int flag ) const   { return myFlags & flag; }
+  void SetChecked( bool is ) { is ? SetFlag( theIsCheckedFlag ) : UnsetFlag( theIsCheckedFlag ); }
+  void SetFlag  ( int flag ) { myFlags |= flag; }
+  void UnsetFlag( int flag ) { myFlags &= ~flag; }
+
+private:
+  bool isOutOfSolid (const gp_Pnt& p);
+  bool isOutOfBox   (const gp_Pnt& p);
+  bool isOutOfFace  (const gp_Pnt& p);
+  bool isOutOfEdge  (const gp_Pnt& p);
+  bool isOutOfVertex(const gp_Pnt& p);
+  bool isBox        (const TopoDS_Shape& s);
+
+  bool (Classifier::*          myIsOutFun)(const gp_Pnt& p);
+  BRepClass3d_SolidClassifier* mySolidClfr; // ptr because of a run-time forbidden copy-constructor
+  Bnd_B3d                      myBox;
+  GeomAPI_ProjectPointOnSurf   myProjFace;
+  GeomAPI_ProjectPointOnCurve  myProjEdge;
+  gp_Pnt                       myVertexXYZ;
+  TopoDS_Shape                 myShape;
+  double                       myTol;
+  int                          myFlags;
+};
+
+struct ElementsOnShape::OctreeClassifier : public SMESH_Octree
+{
+  OctreeClassifier( const std::vector< ElementsOnShape::Classifier* >& classifiers );
+  OctreeClassifier( const OctreeClassifier*                           otherTree,
+                    const std::vector< ElementsOnShape::Classifier >& clsOther,
+                    std::vector< ElementsOnShape::Classifier >&       cls );
+  void GetClassifiersAtPoint( const gp_XYZ& p,
+                              std::vector< ElementsOnShape::Classifier* >& classifiers );
+protected:
+  OctreeClassifier() {}
+  SMESH_Octree* newChild() const { return new OctreeClassifier; }
+  void          buildChildrenData();
+  Bnd_B3d*      buildRootBox();
+
+  std::vector< ElementsOnShape::Classifier* > myClassifiers;
+};
+
+
+ElementsOnShape::ElementsOnShape():
+  myOctree(0),
+  myType(SMDSAbs_All),
+  myToler(Precision::Confusion()),
+  myAllNodesFlag(false)
 {
 }
 
@@ -4102,6 +4196,25 @@ ElementsOnShape::~ElementsOnShape()
   clearClassifiers();
 }
 
+Predicate* ElementsOnShape::clone() const
+{
+  ElementsOnShape* cln = new ElementsOnShape();
+  cln->SetAllNodes ( myAllNodesFlag );
+  cln->SetTolerance( myToler );
+  cln->SetMesh     ( myMeshModifTracer.GetMesh() );
+  cln->myShape = myShape; // avoid creation of myClassifiers
+  cln->SetShape    ( myShape, myType );
+  cln->myClassifiers.resize( myClassifiers.size() );
+  for ( size_t i = 0; i < myClassifiers.size(); ++i )
+    cln->myClassifiers[ i ].Init( BRepBuilderAPI_Copy( myClassifiers[ i ].Shape()),
+                                  myToler, myClassifiers[ i ].GetBndBox() );
+  if ( myOctree ) // copy myOctree
+  {
+    cln->myOctree = new OctreeClassifier( myOctree, myClassifiers, cln->myClassifiers );
+  }
+  return cln;
+}
+
 SMDSAbs_ElementType ElementsOnShape::GetType() const
 {
   return myType;
@@ -4167,27 +4280,32 @@ void ElementsOnShape::setNodeIsOut( const SMDS_MeshNode* n, bool  isOut )
 void ElementsOnShape::SetShape (const TopoDS_Shape&       theShape,
                                 const SMDSAbs_ElementType theType)
 {
+  bool shapeChanges = ( myShape != theShape );
   myType  = theType;
   myShape = theShape;
   if ( myShape.IsNull() ) return;
 
-  TopTools_IndexedMapOfShape shapesMap;
-  TopAbs_ShapeEnum shapeTypes[4] = { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX };
-  TopExp_Explorer sub;
-  for ( int i = 0; i < 4; ++i )
+  if ( shapeChanges )
   {
-    if ( shapesMap.IsEmpty() )
-      for ( sub.Init( myShape, shapeTypes[i] ); sub.More(); sub.Next() )
-        shapesMap.Add( sub.Current() );
-    if ( i > 0 )
-      for ( sub.Init( myShape, shapeTypes[i], shapeTypes[i-1] ); sub.More(); sub.Next() )
-        shapesMap.Add( sub.Current() );
-  }
+    // find most complex shapes
+    TopTools_IndexedMapOfShape shapesMap;
+    TopAbs_ShapeEnum shapeTypes[4] = { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX };
+    TopExp_Explorer sub;
+    for ( int i = 0; i < 4; ++i )
+    {
+      if ( shapesMap.IsEmpty() )
+        for ( sub.Init( myShape, shapeTypes[i] ); sub.More(); sub.Next() )
+          shapesMap.Add( sub.Current() );
+      if ( i > 0 )
+        for ( sub.Init( myShape, shapeTypes[i], shapeTypes[i-1] ); sub.More(); sub.Next() )
+          shapesMap.Add( sub.Current() );
+    }
 
-  clearClassifiers();
-  myClassifiers.resize( shapesMap.Extent() );
-  for ( int i = 0; i < shapesMap.Extent(); ++i )
-    myClassifiers[ i ] = new TClassifier( shapesMap( i+1 ), myToler );
+    clearClassifiers();
+    myClassifiers.resize( shapesMap.Extent() );
+    for ( int i = 0; i < shapesMap.Extent(); ++i )
+      myClassifiers[ i ].Init( shapesMap( i+1 ), myToler );
+  }
 
   if ( theType == SMDSAbs_Node )
   {
@@ -4202,23 +4320,42 @@ void ElementsOnShape::SetShape (const TopoDS_Shape&       theShape,
 
 void ElementsOnShape::clearClassifiers()
 {
-  for ( size_t i = 0; i < myClassifiers.size(); ++i )
-    delete myClassifiers[ i ];
+  // for ( size_t i = 0; i < myClassifiers.size(); ++i )
+  //   delete myClassifiers[ i ];
   myClassifiers.clear();
+
+  delete myOctree;
+  myOctree = 0;
 }
 
-bool ElementsOnShape::IsSatisfy (long elemId)
+bool ElementsOnShape::IsSatisfy( long elemId )
 {
-  const SMDS_Mesh*        mesh = myMeshModifTracer.GetMesh();
-  const SMDS_MeshElement* elem =
-    ( myType == SMDSAbs_Node ? mesh->FindNode( elemId ) : mesh->FindElement( elemId ));
-  if ( !elem || myClassifiers.empty() )
+  if ( myClassifiers.empty() )
+    return false;
+
+  const SMDS_Mesh* mesh = myMeshModifTracer.GetMesh();
+  if ( myType == SMDSAbs_Node )
+    return IsSatisfy( mesh->FindNode( elemId ));
+  return IsSatisfy( mesh->FindElement( elemId ));
+}
+
+bool ElementsOnShape::IsSatisfy (const SMDS_MeshElement* elem)
+{
+  if ( !elem )
     return false;
 
   bool isSatisfy = myAllNodesFlag, isNodeOut;
 
   gp_XYZ centerXYZ (0, 0, 0);
 
+  if ( !myOctree && myClassifiers.size() > 5 )
+  {
+    myWorkClassifiers.resize( myClassifiers.size() );
+    for ( size_t i = 0; i < myClassifiers.size(); ++i )
+      myWorkClassifiers[ i ] = & myClassifiers[ i ];
+    myOctree = new OctreeClassifier( myWorkClassifiers );
+  }
+
   SMDS_ElemIteratorPtr aNodeItr = elem->nodesIterator();
   while (aNodeItr->more() && (isSatisfy == myAllNodesFlag))
   {
@@ -4228,99 +4365,198 @@ bool ElementsOnShape::IsSatisfy (long elemId)
     isNodeOut = true;
     if ( !getNodeIsOut( aPnt._node, isNodeOut ))
     {
-      for ( size_t i = 0; i < myClassifiers.size() && isNodeOut; ++i )
-        isNodeOut = myClassifiers[i]->IsOut( aPnt );
+      if ( myOctree )
+      {
+        myWorkClassifiers.clear();
+        myOctree->GetClassifiersAtPoint( aPnt, myWorkClassifiers );
+
+        for ( size_t i = 0; i < myWorkClassifiers.size(); ++i )
+          myWorkClassifiers[i]->SetChecked( false );
 
+        for ( size_t i = 0; i < myWorkClassifiers.size() && isNodeOut; ++i )
+          if ( !myWorkClassifiers[i]->IsChecked() )
+            isNodeOut = myWorkClassifiers[i]->IsOut( aPnt );
+      }
+      else
+      {
+        for ( size_t i = 0; i < myClassifiers.size() && isNodeOut; ++i )
+          isNodeOut = myClassifiers[i].IsOut( aPnt );
+      }
       setNodeIsOut( aPnt._node, isNodeOut );
     }
     isSatisfy = !isNodeOut;
   }
 
   // Check the center point for volumes MantisBug 0020168
-  if (isSatisfy &&
-      myAllNodesFlag &&
-      myClassifiers[0]->ShapeType() == TopAbs_SOLID)
+  if ( isSatisfy &&
+       myAllNodesFlag &&
+       myClassifiers[0].ShapeType() == TopAbs_SOLID )
   {
     centerXYZ /= elem->NbNodes();
     isSatisfy = false;
-    for ( size_t i = 0; i < myClassifiers.size() && !isSatisfy; ++i )
-      isSatisfy = ! myClassifiers[i]->IsOut( centerXYZ );
+    if ( myOctree )
+      for ( size_t i = 0; i < myWorkClassifiers.size() && !isSatisfy; ++i )
+        isSatisfy = ! myWorkClassifiers[i]->IsOut( centerXYZ );
+    else
+      for ( size_t i = 0; i < myClassifiers.size() && !isSatisfy; ++i )
+        isSatisfy = ! myClassifiers[i].IsOut( centerXYZ );
   }
 
   return isSatisfy;
 }
 
-TopAbs_ShapeEnum ElementsOnShape::TClassifier::ShapeType() const
+bool ElementsOnShape::IsSatisfy (const SMDS_MeshNode* node,
+                                 TopoDS_Shape*        okShape)
 {
-  return myShape.ShapeType();
-}
+  if ( !node )
+    return false;
 
-bool ElementsOnShape::TClassifier::IsOut(const gp_Pnt& p)
-{
-  return (this->*myIsOutFun)( p );
+  if ( !myOctree && myClassifiers.size() > 5 )
+  {
+    myWorkClassifiers.resize( myClassifiers.size() );
+    for ( size_t i = 0; i < myClassifiers.size(); ++i )
+      myWorkClassifiers[ i ] = & myClassifiers[ i ];
+    myOctree = new OctreeClassifier( myWorkClassifiers );
+  }
+
+  bool isNodeOut = true;
+
+  if ( okShape || !getNodeIsOut( node, isNodeOut ))
+  {
+    SMESH_NodeXYZ aPnt = node;
+    if ( myOctree )
+    {
+      myWorkClassifiers.clear();
+      myOctree->GetClassifiersAtPoint( aPnt, myWorkClassifiers );
+
+      for ( size_t i = 0; i < myWorkClassifiers.size(); ++i )
+        myWorkClassifiers[i]->SetChecked( false );
+
+      for ( size_t i = 0; i < myWorkClassifiers.size(); ++i )
+        if ( !myWorkClassifiers[i]->IsChecked() &&
+             !myWorkClassifiers[i]->IsOut( aPnt ))
+        {
+          isNodeOut = false;
+          if ( okShape )
+            *okShape = myWorkClassifiers[i]->Shape();
+          break;
+        }
+    }
+    else
+    {
+      for ( size_t i = 0; i < myClassifiers.size(); ++i )
+        if ( !myClassifiers[i].IsOut( aPnt ))
+        {
+          isNodeOut = false;
+          if ( okShape )
+            *okShape = myWorkClassifiers[i]->Shape();
+          break;
+        }
+    }
+    setNodeIsOut( node, isNodeOut );
+  }
+
+  return !isNodeOut;
 }
 
-void ElementsOnShape::TClassifier::Init (const TopoDS_Shape& theShape, double theTol)
+void ElementsOnShape::Classifier::Init( const TopoDS_Shape& theShape,
+                                        double              theTol,
+                                        const Bnd_B3d*      theBox )
 {
   myShape = theShape;
   myTol   = theTol;
+  myFlags = 0;
+
+  bool isShapeBox = false;
   switch ( myShape.ShapeType() )
   {
-  case TopAbs_SOLID: {
-    if ( isBox( theShape ))
+  case TopAbs_SOLID:
+  {
+    if (( isShapeBox = isBox( theShape )))
     {
-      myIsOutFun = & ElementsOnShape::TClassifier::isOutOfBox;
+      myIsOutFun = & ElementsOnShape::Classifier::isOutOfBox;
     }
     else
     {
-      mySolidClfr.Load(theShape);
-      myIsOutFun = & ElementsOnShape::TClassifier::isOutOfSolid;
+      mySolidClfr = new BRepClass3d_SolidClassifier(theShape);
+      myIsOutFun = & ElementsOnShape::Classifier::isOutOfSolid;
     }
     break;
   }
-  case TopAbs_FACE:  {
+  case TopAbs_FACE:
+  {
     Standard_Real u1,u2,v1,v2;
     Handle(Geom_Surface) surf = BRep_Tool::Surface( TopoDS::Face( theShape ));
     surf->Bounds( u1,u2,v1,v2 );
     myProjFace.Init(surf, u1,u2, v1,v2, myTol );
-    myIsOutFun = & ElementsOnShape::TClassifier::isOutOfFace;
+    myIsOutFun = & ElementsOnShape::Classifier::isOutOfFace;
     break;
   }
-  case TopAbs_EDGE:  {
+  case TopAbs_EDGE:
+  {
     Standard_Real u1, u2;
-    Handle(Geom_Curve) curve = BRep_Tool::Curve( TopoDS::Edge(theShape), u1, u2);
+    Handle(Geom_Curve) curve = BRep_Tool::Curve( TopoDS::Edge( theShape ), u1, u2);
     myProjEdge.Init(curve, u1, u2);
-    myIsOutFun = & ElementsOnShape::TClassifier::isOutOfEdge;
+    myIsOutFun = & ElementsOnShape::Classifier::isOutOfEdge;
     break;
   }
-  case TopAbs_VERTEX:{
+  case TopAbs_VERTEX:
+  {
     myVertexXYZ = BRep_Tool::Pnt( TopoDS::Vertex( theShape ) );
-    myIsOutFun = & ElementsOnShape::TClassifier::isOutOfVertex;
+    myIsOutFun = & ElementsOnShape::Classifier::isOutOfVertex;
     break;
   }
   default:
-    throw SALOME_Exception("Programmer error in usage of ElementsOnShape::TClassifier");
+    throw SALOME_Exception("Programmer error in usage of ElementsOnShape::Classifier");
+  }
+
+  if ( !isShapeBox )
+  {
+    if ( theBox )
+    {
+      myBox = *theBox;
+    }
+    else
+    {
+      Bnd_Box box;
+      BRepBndLib::Add( myShape, box );
+      myBox.Clear();
+      myBox.Add( box.CornerMin() );
+      myBox.Add( box.CornerMax() );
+      gp_XYZ halfSize = 0.5 * ( box.CornerMax().XYZ() - box.CornerMin().XYZ() );
+      for ( int iDim = 1; iDim <= 3; ++iDim )
+      {
+        double x = halfSize.Coord( iDim );
+        halfSize.SetCoord( iDim, x + Max( myTol, 1e-2 * x ));
+      }
+      myBox.SetHSize( halfSize );
+    }
   }
 }
 
-bool ElementsOnShape::TClassifier::isOutOfSolid (const gp_Pnt& p)
+ElementsOnShape::Classifier::~Classifier()
+{
+  delete mySolidClfr; mySolidClfr = 0;
+}
+
+bool ElementsOnShape::Classifier::isOutOfSolid (const gp_Pnt& p)
 {
-  mySolidClfr.Perform( p, myTol );
-  return ( mySolidClfr.State() != TopAbs_IN && mySolidClfr.State() != TopAbs_ON );
+  mySolidClfr->Perform( p, myTol );
+  return ( mySolidClfr->State() != TopAbs_IN && mySolidClfr->State() != TopAbs_ON );
 }
 
-bool ElementsOnShape::TClassifier::isOutOfBox (const gp_Pnt& p)
+bool ElementsOnShape::Classifier::isOutOfBox (const gp_Pnt& p)
 {
   return myBox.IsOut( p.XYZ() );
 }
 
-bool ElementsOnShape::TClassifier::isOutOfFace  (const gp_Pnt& p)
+bool ElementsOnShape::Classifier::isOutOfFace  (const gp_Pnt& p)
 {
   myProjFace.Perform( p );
   if ( myProjFace.IsDone() && myProjFace.LowerDistance() <= myTol )
   {
     // check relatively to the face
-    Quantity_Parameter u, v;
+    Standard_Real u, v;
     myProjFace.LowerDistanceParameters(u, v);
     gp_Pnt2d aProjPnt (u, v);
     BRepClass_FaceClassifier aClsf ( TopoDS::Face( myShape ), aProjPnt, myTol );
@@ -4330,18 +4566,18 @@ bool ElementsOnShape::TClassifier::isOutOfFace  (const gp_Pnt& p)
   return true;
 }
 
-bool ElementsOnShape::TClassifier::isOutOfEdge  (const gp_Pnt& p)
+bool ElementsOnShape::Classifier::isOutOfEdge  (const gp_Pnt& p)
 {
   myProjEdge.Perform( p );
   return ! ( myProjEdge.NbPoints() > 0 && myProjEdge.LowerDistance() <= myTol );
 }
 
-bool ElementsOnShape::TClassifier::isOutOfVertex(const gp_Pnt& p)
+bool ElementsOnShape::Classifier::isOutOfVertex(const gp_Pnt& p)
 {
   return ( myVertexXYZ.Distance( p ) > myTol );
 }
 
-bool ElementsOnShape::TClassifier::isBox (const TopoDS_Shape& theShape)
+bool ElementsOnShape::Classifier::isBox (const TopoDS_Shape& theShape)
 {
   TopTools_IndexedMapOfShape vMap;
   TopExp::MapShapes( theShape, TopAbs_VERTEX, vMap );
@@ -4368,6 +4604,118 @@ bool ElementsOnShape::TClassifier::isBox (const TopoDS_Shape& theShape)
   return true;
 }
 
+ElementsOnShape::
+OctreeClassifier::OctreeClassifier( const std::vector< ElementsOnShape::Classifier* >& classifiers )
+  :SMESH_Octree( new SMESH_TreeLimit )
+{
+  myClassifiers = classifiers;
+  compute();
+}
+
+ElementsOnShape::
+OctreeClassifier::OctreeClassifier( const OctreeClassifier*                           otherTree,
+                                    const std::vector< ElementsOnShape::Classifier >& clsOther,
+                                    std::vector< ElementsOnShape::Classifier >&       cls )
+  :SMESH_Octree( new SMESH_TreeLimit )
+{
+  myBox = new Bnd_B3d( *otherTree->getBox() );
+
+  if (( myIsLeaf = otherTree->isLeaf() ))
+  {
+    myClassifiers.resize( otherTree->myClassifiers.size() );
+    for ( size_t i = 0; i < otherTree->myClassifiers.size(); ++i )
+    {
+      int ind = otherTree->myClassifiers[i] - & clsOther[0];
+      myClassifiers[ i ] = & cls[ ind ];
+    }
+  }
+  else if ( otherTree->myChildren )
+  {
+    myChildren = new SMESH_Tree< Bnd_B3d, 8 > * [ 8 ];
+    for ( int i = 0; i < nbChildren(); i++ )
+      myChildren[i] =
+        new OctreeClassifier( static_cast<const OctreeClassifier*>( otherTree->myChildren[i]),
+                              clsOther, cls );
+  }
+}
+
+void ElementsOnShape::
+OctreeClassifier::GetClassifiersAtPoint( const gp_XYZ& point,
+                                         std::vector< ElementsOnShape::Classifier* >& result )
+{
+  if ( getBox()->IsOut( point ))
+    return;
+
+  if ( isLeaf() )
+  {
+    for ( size_t i = 0; i < myClassifiers.size(); ++i )
+      if ( !myClassifiers[i]->GetBndBox()->IsOut( point ))
+        result.push_back( myClassifiers[i] );
+  }
+  else
+  {
+    for (int i = 0; i < nbChildren(); i++)
+      ((OctreeClassifier*) myChildren[i])->GetClassifiersAtPoint( point, result );
+  }
+}
+
+void ElementsOnShape::OctreeClassifier::buildChildrenData()
+{
+  // distribute myClassifiers among myChildren
+
+  const int childFlag[8] = { 0x0000001,
+                             0x0000002,
+                             0x0000004,
+                             0x0000008,
+                             0x0000010,
+                             0x0000020,
+                             0x0000040,
+                             0x0000080 };
+  int nbInChild[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+  for ( size_t i = 0; i < myClassifiers.size(); ++i )
+  {
+    for ( int j = 0; j < nbChildren(); j++ )
+    {
+      if ( !myClassifiers[i]->GetBndBox()->IsOut( *myChildren[j]->getBox() ))
+      {
+        myClassifiers[i]->SetFlag( childFlag[ j ]);
+        ++nbInChild[ j ];
+      }
+    }
+  }
+
+  for ( int j = 0; j < nbChildren(); j++ )
+  {
+    OctreeClassifier* child = static_cast<OctreeClassifier*>( myChildren[ j ]);
+    child->myClassifiers.resize( nbInChild[ j ]);
+    for ( size_t i = 0; nbInChild[ j ] && i < myClassifiers.size(); ++i )
+    {
+      if ( myClassifiers[ i ]->IsSetFlag( childFlag[ j ]))
+      {
+        --nbInChild[ j ];
+        child->myClassifiers[ nbInChild[ j ]] = myClassifiers[ i ];
+        myClassifiers[ i ]->UnsetFlag( childFlag[ j ]);
+      }
+    }
+  }
+  SMESHUtils::FreeVector( myClassifiers );
+
+  // define if a child isLeaf()
+  for ( int i = 0; i < nbChildren(); i++ )
+  {
+    OctreeClassifier* child = static_cast<OctreeClassifier*>( myChildren[ i ]);
+    child->myIsLeaf = ( child->myClassifiers.size() <= 5  );
+  }
+}
+
+Bnd_B3d* ElementsOnShape::OctreeClassifier::buildRootBox()
+{
+  Bnd_B3d* box = new Bnd_B3d;
+  for ( size_t i = 0; i < myClassifiers.size(); ++i )
+    box->Add( *myClassifiers[i]->GetBndBox() );
+  return box;
+}
 
 /*
   Class       : BelongToGeom
@@ -4377,25 +4725,38 @@ bool ElementsOnShape::TClassifier::isBox (const TopoDS_Shape& theShape)
 
 BelongToGeom::BelongToGeom()
   : myMeshDS(NULL),
-    myType(SMDSAbs_All),
+    myType(SMDSAbs_NbElementTypes),
     myIsSubshape(false),
     myTolerance(Precision::Confusion())
 {}
 
+Predicate* BelongToGeom::clone() const
+{
+  BelongToGeom* cln = new BelongToGeom( *this );
+  cln->myElementsOnShapePtr.reset( static_cast<ElementsOnShape*>( myElementsOnShapePtr->clone() ));
+  return cln;
+}
+
 void BelongToGeom::SetMesh( const SMDS_Mesh* theMesh )
 {
-  myMeshDS = dynamic_cast<const SMESHDS_Mesh*>(theMesh);
-  init();
+  if ( myMeshDS != theMesh )
+  {
+    myMeshDS = dynamic_cast<const SMESHDS_Mesh*>(theMesh);
+    init();
+  }
 }
 
 void BelongToGeom::SetGeom( const TopoDS_Shape& theShape )
 {
-  myShape = theShape;
-  init();
+  if ( myShape != theShape )
+  {
+    myShape = theShape;
+    init();
+  }
 }
 
 static bool IsSubShape (const TopTools_IndexedMapOfShape& theMap,
-                        const TopoDS_Shape& theShape)
+                        const TopoDS_Shape&               theShape)
 {
   if (theMap.Contains(theShape)) return true;
 
@@ -4417,7 +4778,7 @@ static bool IsSubShape (const TopTools_IndexedMapOfShape& theMap,
 
 void BelongToGeom::init()
 {
-  if (!myMeshDS || myShape.IsNull()) return;
+  if ( !myMeshDS || myShape.IsNull() ) return;
 
   // is sub-shape of main shape?
   TopoDS_Shape aMainShape = myMeshDS->ShapeToMesh();
@@ -4426,40 +4787,33 @@ void BelongToGeom::init()
   }
   else {
     TopTools_IndexedMapOfShape aMap;
-    TopExp::MapShapes(aMainShape, aMap);
-    myIsSubshape = IsSubShape(aMap, myShape);
+    TopExp::MapShapes( aMainShape, aMap );
+    myIsSubshape = IsSubShape( aMap, myShape );
+    if ( myIsSubshape )
+    {
+      aMap.Clear();
+      TopExp::MapShapes( myShape, aMap );
+      mySubShapesIDs.Clear();
+      for ( int i = 1; i <= aMap.Extent(); ++i )
+      {
+        int subID = myMeshDS->ShapeToIndex( aMap( i ));
+        if ( subID > 0 )
+          mySubShapesIDs.Add( subID );
+      }
+    }
   }
 
   //if (!myIsSubshape) // to be always ready to check an element not bound to geometry
   {
-    myElementsOnShapePtr.reset(new ElementsOnShape());
-    myElementsOnShapePtr->SetTolerance(myTolerance);
-    myElementsOnShapePtr->SetAllNodes(true); // "belong", while false means "lays on"
-    myElementsOnShapePtr->SetMesh(myMeshDS);
-    myElementsOnShapePtr->SetShape(myShape, myType);
+    if ( !myElementsOnShapePtr )
+      myElementsOnShapePtr.reset( new ElementsOnShape() );
+    myElementsOnShapePtr->SetTolerance( myTolerance );
+    myElementsOnShapePtr->SetAllNodes( true ); // "belong", while false means "lays on"
+    myElementsOnShapePtr->SetMesh( myMeshDS );
+    myElementsOnShapePtr->SetShape( myShape, myType );
   }
 }
 
-static bool IsContains( const SMESHDS_Mesh*     theMeshDS,
-                        const TopoDS_Shape&     theShape,
-                        const SMDS_MeshElement* theElem,
-                        TopAbs_ShapeEnum        theFindShapeEnum,
-                        TopAbs_ShapeEnum        theAvoidShapeEnum = TopAbs_SHAPE )
-{
-  TopExp_Explorer anExp( theShape,theFindShapeEnum,theAvoidShapeEnum );
-
-  while( anExp.More() )
-  {
-    const TopoDS_Shape& aShape = anExp.Current();
-    if( SMESHDS_SubMesh* aSubMesh = theMeshDS->MeshElements( aShape ) ){
-      if( aSubMesh->Contains( theElem ) )
-        return true;
-    }
-    anExp.Next();
-  }
-  return false;
-}
-
 bool BelongToGeom::IsSatisfy (long theId)
 {
   if (myMeshDS == 0 || myShape.IsNull())
@@ -4470,51 +4824,28 @@ bool BelongToGeom::IsSatisfy (long theId)
     return myElementsOnShapePtr->IsSatisfy(theId);
   }
 
-  // Case of submesh
+  // Case of sub-mesh
+
   if (myType == SMDSAbs_Node)
   {
-    if( const SMDS_MeshNode* aNode = myMeshDS->FindNode( theId ) )
+    if ( const SMDS_MeshNode* aNode = myMeshDS->FindNode( theId ))
     {
       if ( aNode->getshapeId() < 1 )
         return myElementsOnShapePtr->IsSatisfy(theId);
-
-      const SMDS_PositionPtr& aPosition = aNode->GetPosition();
-      SMDS_TypeOfPosition aTypeOfPosition = aPosition->GetTypeOfPosition();
-      switch( aTypeOfPosition )
-      {
-      case SMDS_TOP_VERTEX : return ( IsContains( myMeshDS,myShape,aNode,TopAbs_VERTEX ));
-      case SMDS_TOP_EDGE   : return ( IsContains( myMeshDS,myShape,aNode,TopAbs_EDGE ));
-      case SMDS_TOP_FACE   : return ( IsContains( myMeshDS,myShape,aNode,TopAbs_FACE ));
-      case SMDS_TOP_3DSPACE: return ( IsContains( myMeshDS,myShape,aNode,TopAbs_SOLID ) ||
-                                      IsContains( myMeshDS,myShape,aNode,TopAbs_SHELL ));
-      default:;
-      }
+      else
+        return mySubShapesIDs.Contains( aNode->getshapeId() );
     }
   }
   else
   {
     if ( const SMDS_MeshElement* anElem = myMeshDS->FindElement( theId ))
     {
-      if ( anElem->getshapeId() < 1 )
-        return myElementsOnShapePtr->IsSatisfy(theId);
-
-      if( myType == SMDSAbs_All )
+      if ( anElem->GetType() == myType )
       {
-        return ( IsContains( myMeshDS,myShape,anElem,TopAbs_EDGE ) ||
-                 IsContains( myMeshDS,myShape,anElem,TopAbs_FACE ) ||
-                 IsContains( myMeshDS,myShape,anElem,TopAbs_SOLID )||
-                 IsContains( myMeshDS,myShape,anElem,TopAbs_SHELL ));
-      }
-      else if( myType == anElem->GetType() )
-      {
-        switch( myType )
-        {
-        case SMDSAbs_Edge  : return ( IsContains( myMeshDS,myShape,anElem,TopAbs_EDGE ));
-        case SMDSAbs_Face  : return ( IsContains( myMeshDS,myShape,anElem,TopAbs_FACE ));
-        case SMDSAbs_Volume: return ( IsContains( myMeshDS,myShape,anElem,TopAbs_SOLID )||
-                                      IsContains( myMeshDS,myShape,anElem,TopAbs_SHELL ));
-        default:;
-        }
+        if ( anElem->getshapeId() < 1 )
+          return myElementsOnShapePtr->IsSatisfy(theId);
+        else
+          return mySubShapesIDs.Contains( anElem->getshapeId() );
       }
     }
   }
@@ -4524,8 +4855,11 @@ bool BelongToGeom::IsSatisfy (long theId)
 
 void BelongToGeom::SetType (SMDSAbs_ElementType theType)
 {
-  myType = theType;
-  init();
+  if ( myType != theType )
+  {
+    myType = theType;
+    init();
+  }
 }
 
 SMDSAbs_ElementType BelongToGeom::GetType() const
@@ -4546,8 +4880,7 @@ const SMESHDS_Mesh* BelongToGeom::GetMeshDS() const
 void BelongToGeom::SetTolerance (double theTolerance)
 {
   myTolerance = theTolerance;
-  if (!myIsSubshape)
-    init();
+  init();
 }
 
 double BelongToGeom::GetTolerance()
@@ -4558,26 +4891,39 @@ double BelongToGeom::GetTolerance()
 /*
   Class       : LyingOnGeom
   Description : Predicate for verifying whether entiy lying or partially lying on
-                specified geometrical support
+  specified geometrical support
 */
 
 LyingOnGeom::LyingOnGeom()
   : myMeshDS(NULL),
-    myType(SMDSAbs_All),
+    myType(SMDSAbs_NbElementTypes),
     myIsSubshape(false),
     myTolerance(Precision::Confusion())
 {}
 
+Predicate* LyingOnGeom::clone() const
+{
+  LyingOnGeom* cln = new LyingOnGeom( *this );
+  cln->myElementsOnShapePtr.reset( static_cast<ElementsOnShape*>( myElementsOnShapePtr->clone() ));
+  return cln;
+}
+
 void LyingOnGeom::SetMesh( const SMDS_Mesh* theMesh )
 {
-  myMeshDS = dynamic_cast<const SMESHDS_Mesh*>(theMesh);
-  init();
+  if ( myMeshDS != theMesh )
+  {
+    myMeshDS = dynamic_cast<const SMESHDS_Mesh*>(theMesh);
+    init();
+  }
 }
 
 void LyingOnGeom::SetGeom( const TopoDS_Shape& theShape )
 {
-  myShape = theShape;
-  init();
+  if ( myShape != theShape )
+  {
+    myShape = theShape;
+    init();
+  }
 }
 
 void LyingOnGeom::init()
@@ -4605,13 +4951,14 @@ void LyingOnGeom::init()
         mySubShapesIDs.Add( subID );
     }
   }
-  else
+  // else // to be always ready to check an element not bound to geometry
   {
-    myElementsOnShapePtr.reset(new ElementsOnShape());
-    myElementsOnShapePtr->SetTolerance(myTolerance);
-    myElementsOnShapePtr->SetAllNodes(false); // lays on, while true means "belong"
-    myElementsOnShapePtr->SetMesh(myMeshDS);
-    myElementsOnShapePtr->SetShape(myShape, myType);
+    if ( !myElementsOnShapePtr )
+      myElementsOnShapePtr.reset( new ElementsOnShape() );
+    myElementsOnShapePtr->SetTolerance( myTolerance );
+    myElementsOnShapePtr->SetAllNodes( false ); // lays on, while true means "belong"
+    myElementsOnShapePtr->SetMesh( myMeshDS );
+    myElementsOnShapePtr->SetShape( myShape, myType );
   }
 }
 
@@ -4633,7 +4980,7 @@ bool LyingOnGeom::IsSatisfy( long theId )
   if ( mySubShapesIDs.Contains( elem->getshapeId() ))
     return true;
 
-  if ( elem->GetType() != SMDSAbs_Node )
+  if ( elem->GetType() != SMDSAbs_Node && elem->GetType() == myType )
   {
     SMDS_ElemIteratorPtr nodeItr = elem->nodesIterator();
     while ( nodeItr->more() )
@@ -4649,8 +4996,11 @@ bool LyingOnGeom::IsSatisfy( long theId )
 
 void LyingOnGeom::SetType( SMDSAbs_ElementType theType )
 {
-  myType = theType;
-  init();
+  if ( myType != theType )
+  {
+    myType = theType;
+    init();
+  }
 }
 
 SMDSAbs_ElementType LyingOnGeom::GetType() const
@@ -4671,8 +5021,7 @@ const SMESHDS_Mesh* LyingOnGeom::GetMeshDS() const
 void LyingOnGeom::SetTolerance (double theTolerance)
 {
   myTolerance = theTolerance;
-  if (!myIsSubshape)
-    init();
+  init();
 }
 
 double LyingOnGeom::GetTolerance()
@@ -4680,39 +5029,6 @@ double LyingOnGeom::GetTolerance()
   return myTolerance;
 }
 
-bool LyingOnGeom::Contains( const SMESHDS_Mesh*     theMeshDS,
-                            const TopoDS_Shape&     theShape,
-                            const SMDS_MeshElement* theElem,
-                            TopAbs_ShapeEnum        theFindShapeEnum,
-                            TopAbs_ShapeEnum        theAvoidShapeEnum )
-{
-  // if (IsContains(theMeshDS, theShape, theElem, theFindShapeEnum, theAvoidShapeEnum))
-  //   return true;
-
-  // TopTools_MapOfShape aSubShapes;
-  // TopExp_Explorer exp( theShape, theFindShapeEnum, theAvoidShapeEnum );
-  // for ( ; exp.More(); exp.Next() )
-  // {
-  //   const TopoDS_Shape& aShape = exp.Current();
-  //   if ( !aSubShapes.Add( aShape )) continue;
-
-  //   if ( SMESHDS_SubMesh* aSubMesh = theMeshDS->MeshElements( aShape ))
-  //   {
-  //     if ( aSubMesh->Contains( theElem ))
-  //       return true;
-
-  //     SMDS_ElemIteratorPtr nodeItr = theElem->nodesIterator();
-  //     while ( nodeItr->more() )
-  //     {
-  //       const SMDS_MeshElement* aNode = nodeItr->next();
-  //       if ( aSubMesh->Contains( aNode ))
-  //         return true;
-  //     }
-  //   }
-  // }
-  return false;
-}
-
 TSequenceOfXYZ::TSequenceOfXYZ(): myElem(0)
 {}