Salome HOME
23462: [CEA 2142] Import12D fails
[modules/smesh.git] / src / Controls / SMESH_Controls.cxx
index b00c87e68d56cb87ab6aa425c65c3fcabc2ecbbb..9485d983eca2f5929d0385946c9afb3d3fff3a7c 100644 (file)
@@ -40,6 +40,7 @@
 
 #include <BRepAdaptor_Surface.hxx>
 #include <BRepBndLib.hxx>
+#include <BRepBuilderAPI_Copy.hxx>
 #include <BRepClass_FaceClassifier.hxx>
 #include <BRep_Tool.hxx>
 #include <Geom_CylindricalSurface.hxx>
@@ -133,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
@@ -2115,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
@@ -2613,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);
 }
 
@@ -2661,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
 */
 //================================================================================
 
@@ -3219,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( ' ' );
 
@@ -3950,9 +3987,9 @@ SMDSAbs_ElementType BelongToMeshGroup::GetType() const
   return myGroup ? myGroup->GetType() : SMDSAbs_All;
 }
 
-/*
-  ElementsOnSurface
-*/
+//================================================================================
+//  ElementsOnSurface
+//================================================================================
 
 ElementsOnSurface::ElementsOnSurface()
 {
@@ -4086,18 +4123,29 @@ bool ElementsOnSurface::isOnSurface( const SMDS_MeshNode* theNode )
 }
 
 
-/*
-  ElementsOnShape
-*/
+//================================================================================
+//  ElementsOnShape
+//================================================================================
+
+namespace {
+  const int theIsCheckedFlag = 0x0000100;
+}
 
 struct ElementsOnShape::Classifier
 {
-  Classifier(const TopoDS_Shape& s, double tol) { Init(s,tol); }
-  void Init(const TopoDS_Shape& s, double tol);
-  bool IsOut(const gp_Pnt& p)        { return myIsChecked = true, (this->*myIsOutFun)( p ); }
+  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(); }
-  Bnd_B3d* GetBndBox()               { return & myBox; }
-  bool& IsChecked()                  { return myIsChecked; }
+  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);
@@ -4106,20 +4154,23 @@ private:
   bool isOutOfVertex(const gp_Pnt& p);
   bool isBox        (const TopoDS_Shape& s);
 
-  bool (Classifier::* myIsOutFun)(const gp_Pnt& p);
-  BRepClass3d_SolidClassifier mySolidClfr;
-  Bnd_B3d                     myBox;
-  GeomAPI_ProjectPointOnSurf  myProjFace;
-  GeomAPI_ProjectPointOnCurve myProjEdge;
-  gp_Pnt                      myVertexXYZ;
-  TopoDS_Shape                myShape;
-  double                      myTol;
-  bool                        myIsChecked;
+  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:
@@ -4145,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;
@@ -4217,6 +4287,7 @@ void ElementsOnShape::SetShape (const TopoDS_Shape&       theShape,
 
   if ( shapeChanges )
   {
+    // find most complex shapes
     TopTools_IndexedMapOfShape shapesMap;
     TopAbs_ShapeEnum shapeTypes[4] = { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX };
     TopExp_Explorer sub;
@@ -4233,7 +4304,7 @@ void ElementsOnShape::SetShape (const TopoDS_Shape&       theShape,
     clearClassifiers();
     myClassifiers.resize( shapesMap.Extent() );
     for ( int i = 0; i < shapesMap.Extent(); ++i )
-      myClassifiers[ i ] = new Classifier( shapesMap( i+1 ), myToler );
+      myClassifiers[ i ].Init( shapesMap( i+1 ), myToler );
   }
 
   if ( theType == SMDSAbs_Node )
@@ -4249,20 +4320,28 @@ 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;
@@ -4270,9 +4349,12 @@ bool ElementsOnShape::IsSatisfy (long elemId)
   gp_XYZ centerXYZ (0, 0, 0);
 
   if ( !myOctree && myClassifiers.size() > 5 )
-    myOctree = new OctreeClassifier( myClassifiers );
-
-  std::vector< Classifier* >& classifiers = myOctree ? myWorkClassifiers : myClassifiers;
+  {
+    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))
@@ -4287,37 +4369,103 @@ bool ElementsOnShape::IsSatisfy (long elemId)
       {
         myWorkClassifiers.clear();
         myOctree->GetClassifiersAtPoint( aPnt, myWorkClassifiers );
-      }
-      for ( size_t i = 0; i < classifiers.size(); ++i )
-        classifiers[i]->IsChecked() = false;
 
-      for ( size_t i = 0; i < classifiers.size() && isNodeOut; ++i )
-        if ( !classifiers[i]->IsChecked() )
-          isNodeOut = classifiers[i]->IsOut( aPnt );
+        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 < classifiers.size() && !isSatisfy; ++i )
-      isSatisfy = ! classifiers[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;
 }
 
-void ElementsOnShape::Classifier::Init (const TopoDS_Shape& theShape, double theTol)
+bool ElementsOnShape::IsSatisfy (const SMDS_MeshNode* node,
+                                 TopoDS_Shape*        okShape)
+{
+  if ( !node )
+    return false;
+
+  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::Classifier::Init( const TopoDS_Shape& theShape,
+                                        double              theTol,
+                                        const Bnd_B3d*      theBox )
 {
   myShape = theShape;
   myTol   = theTol;
+  myFlags = 0;
 
   bool isShapeBox = false;
   switch ( myShape.ShapeType() )
@@ -4330,7 +4478,7 @@ void ElementsOnShape::Classifier::Init (const TopoDS_Shape& theShape, double the
     }
     else
     {
-      mySolidClfr.Load(theShape);
+      mySolidClfr = new BRepClass3d_SolidClassifier(theShape);
       myIsOutFun = & ElementsOnShape::Classifier::isOutOfSolid;
     }
     break;
@@ -4364,25 +4512,37 @@ void ElementsOnShape::Classifier::Init (const TopoDS_Shape& theShape, double the
 
   if ( !isShapeBox )
   {
-    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 )
+    if ( theBox )
+    {
+      myBox = *theBox;
+    }
+    else
     {
-      double x = halfSize.Coord( iDim );
-      halfSize.SetCoord( iDim, x + Max( myTol, 1e-2 * x ));
+      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 );
     }
-    myBox.SetHSize( halfSize );
   }
 }
 
+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::Classifier::isOutOfBox (const gp_Pnt& p)
@@ -4396,7 +4556,7 @@ bool ElementsOnShape::Classifier::isOutOfFace  (const gp_Pnt& 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 );
@@ -4452,6 +4612,33 @@ OctreeClassifier::OctreeClassifier( const std::vector< ElementsOnShape::Classifi
   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 )
@@ -4475,26 +4662,50 @@ OctreeClassifier::GetClassifiersAtPoint( const gp_XYZ& point,
 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++)
+    for ( int j = 0; j < nbChildren(); j++ )
     {
       if ( !myClassifiers[i]->GetBndBox()->IsOut( *myChildren[j]->getBox() ))
       {
-        ((OctreeClassifier*)myChildren[j])->myClassifiers.push_back( myClassifiers[i]);
+        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++)
+  for ( int i = 0; i < nbChildren(); i++ )
   {
-    OctreeClassifier* child = static_cast<OctreeClassifier*>( myChildren[i]);
+    OctreeClassifier* child = static_cast<OctreeClassifier*>( myChildren[ i ]);
     child->myIsLeaf = ( child->myClassifiers.size() <= 5  );
-
-    if ( child->myClassifiers.capacity() - child->myClassifiers.size() > 100 )
-      SMESHUtils::CompactVector( child->myClassifiers );
   }
 }
 
@@ -4514,25 +4725,38 @@ Bnd_B3d* ElementsOnShape::OctreeClassifier::buildRootBox()
 
 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;
 
@@ -4554,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();
@@ -4563,8 +4787,20 @@ 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
@@ -4578,26 +4814,6 @@ void BelongToGeom::init()
   }
 }
 
-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())
@@ -4612,48 +4828,24 @@ bool BelongToGeom::IsSatisfy (long theId)
 
   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 )
-      {
-        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() )
+      if ( anElem->GetType() == myType )
       {
-        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() );
       }
     }
   }
@@ -4663,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
@@ -4685,8 +4880,7 @@ const SMESHDS_Mesh* BelongToGeom::GetMeshDS() const
 void BelongToGeom::SetTolerance (double theTolerance)
 {
   myTolerance = theTolerance;
-  if (!myIsSubshape)
-    init();
+  init();
 }
 
 double BelongToGeom::GetTolerance()
@@ -4697,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()
@@ -4773,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() )
@@ -4789,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
@@ -4811,8 +5021,7 @@ const SMESHDS_Mesh* LyingOnGeom::GetMeshDS() const
 void LyingOnGeom::SetTolerance (double theTolerance)
 {
   myTolerance = theTolerance;
-  if (!myIsSubshape)
-    init();
+  init();
 }
 
 double LyingOnGeom::GetTolerance()
@@ -4820,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)
 {}