+bool ManifoldPart::Link::IsEqual( const ManifoldPart::Link& theLink ) const
+{
+ if ( myNode1 == theLink.myNode1 &&
+ myNode2 == theLink.myNode2 )
+ return true;
+ else if ( myNode1 == theLink.myNode2 &&
+ myNode2 == theLink.myNode1 )
+ return true;
+ else
+ return false;
+}
+
+bool ManifoldPart::Link::operator<( const ManifoldPart::Link& x ) const
+{
+ if(myNode1 < x.myNode1) return true;
+ if(myNode1 == x.myNode1)
+ if(myNode2 < x.myNode2) return true;
+ return false;
+}
+
+bool ManifoldPart::IsEqual( const ManifoldPart::Link& theLink1,
+ const ManifoldPart::Link& theLink2 )
+{
+ return theLink1.IsEqual( theLink2 );
+}
+
+ManifoldPart::ManifoldPart()
+{
+ myMesh = 0;
+ myAngToler = Precision::Angular();
+ myIsOnlyManifold = true;
+}
+
+ManifoldPart::~ManifoldPart()
+{
+ myMesh = 0;
+}
+
+void ManifoldPart::SetMesh( const SMDS_Mesh* theMesh )
+{
+ myMesh = theMesh;
+ process();
+}
+
+SMDSAbs_ElementType ManifoldPart::GetType() const
+{ return SMDSAbs_Face; }
+
+bool ManifoldPart::IsSatisfy( long theElementId )
+{
+ return myMapIds.Contains( theElementId );
+}
+
+void ManifoldPart::SetAngleTolerance( const double theAngToler )
+{ myAngToler = theAngToler; }
+
+double ManifoldPart::GetAngleTolerance() const
+{ return myAngToler; }
+
+void ManifoldPart::SetIsOnlyManifold( const bool theIsOnly )
+{ myIsOnlyManifold = theIsOnly; }
+
+void ManifoldPart::SetStartElem( const long theStartId )
+{ myStartElemId = theStartId; }
+
+bool ManifoldPart::process()
+{
+ myMapIds.Clear();
+ myMapBadGeomIds.Clear();
+
+ myAllFacePtr.clear();
+ myAllFacePtrIntDMap.clear();
+ if ( !myMesh )
+ return false;
+
+ // collect all faces into own map
+ SMDS_FaceIteratorPtr anFaceItr = myMesh->facesIterator();
+ for (; anFaceItr->more(); )
+ {
+ SMDS_MeshFace* aFacePtr = (SMDS_MeshFace*)anFaceItr->next();
+ myAllFacePtr.push_back( aFacePtr );
+ myAllFacePtrIntDMap[aFacePtr] = myAllFacePtr.size()-1;
+ }
+
+ SMDS_MeshFace* aStartFace = (SMDS_MeshFace*)myMesh->FindElement( myStartElemId );
+ if ( !aStartFace )
+ return false;
+
+ // the map of non manifold links and bad geometry
+ TMapOfLink aMapOfNonManifold;
+ TColStd_MapOfInteger aMapOfTreated;
+
+ // begin cycle on faces from start index and run on vector till the end
+ // and from begin to start index to cover whole vector
+ const int aStartIndx = myAllFacePtrIntDMap[aStartFace];
+ bool isStartTreat = false;
+ for ( int fi = aStartIndx; !isStartTreat || fi != aStartIndx ; fi++ )
+ {
+ if ( fi == aStartIndx )
+ isStartTreat = true;
+ // as result next time when fi will be equal to aStartIndx
+
+ SMDS_MeshFace* aFacePtr = myAllFacePtr[ fi ];
+ if ( aMapOfTreated.Contains( aFacePtr->GetID() ) )
+ continue;
+
+ aMapOfTreated.Add( aFacePtr->GetID() );
+ TColStd_MapOfInteger aResFaces;
+ if ( !findConnected( myAllFacePtrIntDMap, aFacePtr,
+ aMapOfNonManifold, aResFaces ) )
+ continue;
+ TColStd_MapIteratorOfMapOfInteger anItr( aResFaces );
+ for ( ; anItr.More(); anItr.Next() )
+ {
+ int aFaceId = anItr.Key();
+ aMapOfTreated.Add( aFaceId );
+ myMapIds.Add( aFaceId );
+ }
+
+ if ( fi == int( myAllFacePtr.size() - 1 ))
+ fi = 0;
+ } // end run on vector of faces
+ return !myMapIds.IsEmpty();
+}
+
+static void getLinks( const SMDS_MeshFace* theFace,
+ ManifoldPart::TVectorOfLink& theLinks )
+{
+ int aNbNode = theFace->NbNodes();
+ SMDS_ElemIteratorPtr aNodeItr = theFace->nodesIterator();
+ int i = 1;
+ SMDS_MeshNode* aNode = 0;
+ for ( ; aNodeItr->more() && i <= aNbNode; )
+ {
+
+ SMDS_MeshNode* aN1 = (SMDS_MeshNode*)aNodeItr->next();
+ if ( i == 1 )
+ aNode = aN1;
+ i++;
+ SMDS_MeshNode* aN2 = ( i >= aNbNode ) ? aNode : (SMDS_MeshNode*)aNodeItr->next();
+ i++;
+ ManifoldPart::Link aLink( aN1, aN2 );
+ theLinks.push_back( aLink );
+ }
+}
+
+bool ManifoldPart::findConnected
+ ( const ManifoldPart::TDataMapFacePtrInt& theAllFacePtrInt,
+ SMDS_MeshFace* theStartFace,
+ ManifoldPart::TMapOfLink& theNonManifold,
+ TColStd_MapOfInteger& theResFaces )
+{
+ theResFaces.Clear();
+ if ( !theAllFacePtrInt.size() )
+ return false;
+
+ if ( getNormale( theStartFace ).SquareModulus() <= gp::Resolution() )
+ {
+ myMapBadGeomIds.Add( theStartFace->GetID() );
+ return false;
+ }
+
+ ManifoldPart::TMapOfLink aMapOfBoundary, aMapToSkip;
+ ManifoldPart::TVectorOfLink aSeqOfBoundary;
+ theResFaces.Add( theStartFace->GetID() );
+ ManifoldPart::TDataMapOfLinkFacePtr aDMapLinkFace;
+
+ expandBoundary( aMapOfBoundary, aSeqOfBoundary,
+ aDMapLinkFace, theNonManifold, theStartFace );
+
+ bool isDone = false;
+ while ( !isDone && aMapOfBoundary.size() != 0 )
+ {
+ bool isToReset = false;
+ ManifoldPart::TVectorOfLink::iterator pLink = aSeqOfBoundary.begin();
+ for ( ; !isToReset && pLink != aSeqOfBoundary.end(); ++pLink )
+ {
+ ManifoldPart::Link aLink = *pLink;
+ if ( aMapToSkip.find( aLink ) != aMapToSkip.end() )
+ continue;
+ // each link could be treated only once
+ aMapToSkip.insert( aLink );
+
+ ManifoldPart::TVectorOfFacePtr aFaces;
+ // find next
+ if ( myIsOnlyManifold &&
+ (theNonManifold.find( aLink ) != theNonManifold.end()) )
+ continue;
+ else
+ {
+ getFacesByLink( aLink, aFaces );
+ // filter the element to keep only indicated elements
+ ManifoldPart::TVectorOfFacePtr aFiltered;
+ ManifoldPart::TVectorOfFacePtr::iterator pFace = aFaces.begin();
+ for ( ; pFace != aFaces.end(); ++pFace )
+ {
+ SMDS_MeshFace* aFace = *pFace;
+ if ( myAllFacePtrIntDMap.find( aFace ) != myAllFacePtrIntDMap.end() )
+ aFiltered.push_back( aFace );
+ }
+ aFaces = aFiltered;
+ if ( aFaces.size() < 2 ) // no neihgbour faces
+ continue;
+ else if ( myIsOnlyManifold && aFaces.size() > 2 ) // non manifold case
+ {
+ theNonManifold.insert( aLink );
+ continue;
+ }
+ }
+
+ // compare normal with normals of neighbor element
+ SMDS_MeshFace* aPrevFace = aDMapLinkFace[ aLink ];
+ ManifoldPart::TVectorOfFacePtr::iterator pFace = aFaces.begin();
+ for ( ; pFace != aFaces.end(); ++pFace )
+ {
+ SMDS_MeshFace* aNextFace = *pFace;
+ if ( aPrevFace == aNextFace )
+ continue;
+ int anNextFaceID = aNextFace->GetID();
+ if ( myIsOnlyManifold && theResFaces.Contains( anNextFaceID ) )
+ // should not be with non manifold restriction. probably bad topology
+ continue;
+ // check if face was treated and skipped
+ if ( myMapBadGeomIds.Contains( anNextFaceID ) ||
+ !isInPlane( aPrevFace, aNextFace ) )
+ continue;
+ // add new element to connected and extend the boundaries.
+ theResFaces.Add( anNextFaceID );
+ expandBoundary( aMapOfBoundary, aSeqOfBoundary,
+ aDMapLinkFace, theNonManifold, aNextFace );
+ isToReset = true;
+ }
+ }
+ isDone = !isToReset;
+ }
+
+ return !theResFaces.IsEmpty();
+}
+
+bool ManifoldPart::isInPlane( const SMDS_MeshFace* theFace1,
+ const SMDS_MeshFace* theFace2 )
+{
+ gp_Dir aNorm1 = gp_Dir( getNormale( theFace1 ) );
+ gp_XYZ aNorm2XYZ = getNormale( theFace2 );
+ if ( aNorm2XYZ.SquareModulus() <= gp::Resolution() )
+ {
+ myMapBadGeomIds.Add( theFace2->GetID() );
+ return false;
+ }
+ if ( aNorm1.IsParallel( gp_Dir( aNorm2XYZ ), myAngToler ) )
+ return true;
+
+ return false;
+}
+
+void ManifoldPart::expandBoundary
+ ( ManifoldPart::TMapOfLink& theMapOfBoundary,
+ ManifoldPart::TVectorOfLink& theSeqOfBoundary,
+ ManifoldPart::TDataMapOfLinkFacePtr& theDMapLinkFacePtr,
+ ManifoldPart::TMapOfLink& theNonManifold,
+ SMDS_MeshFace* theNextFace ) const
+{
+ ManifoldPart::TVectorOfLink aLinks;
+ getLinks( theNextFace, aLinks );
+ int aNbLink = (int)aLinks.size();
+ for ( int i = 0; i < aNbLink; i++ )
+ {
+ ManifoldPart::Link aLink = aLinks[ i ];
+ if ( myIsOnlyManifold && (theNonManifold.find( aLink ) != theNonManifold.end()) )
+ continue;
+ if ( theMapOfBoundary.find( aLink ) != theMapOfBoundary.end() )
+ {
+ if ( myIsOnlyManifold )
+ {
+ // remove from boundary
+ theMapOfBoundary.erase( aLink );
+ ManifoldPart::TVectorOfLink::iterator pLink = theSeqOfBoundary.begin();
+ for ( ; pLink != theSeqOfBoundary.end(); ++pLink )
+ {
+ ManifoldPart::Link aBoundLink = *pLink;
+ if ( aBoundLink.IsEqual( aLink ) )
+ {
+ theSeqOfBoundary.erase( pLink );
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ theMapOfBoundary.insert( aLink );
+ theSeqOfBoundary.push_back( aLink );
+ theDMapLinkFacePtr[ aLink ] = theNextFace;
+ }
+ }
+}
+
+void ManifoldPart::getFacesByLink( const ManifoldPart::Link& theLink,
+ ManifoldPart::TVectorOfFacePtr& theFaces ) const
+{
+
+ // take all faces that shared first node
+ SMDS_ElemIteratorPtr anItr = theLink.myNode1->GetInverseElementIterator( SMDSAbs_Face );
+ SMDS_StdIterator< const SMDS_MeshElement*, SMDS_ElemIteratorPtr > faces( anItr ), facesEnd;
+ std::set<const SMDS_MeshElement *> aSetOfFaces( faces, facesEnd );
+
+ // take all faces that shared second node
+ anItr = theLink.myNode2->GetInverseElementIterator( SMDSAbs_Face );
+ // find the common part of two sets
+ for ( ; anItr->more(); )
+ {
+ const SMDS_MeshElement* aFace = anItr->next();
+ if ( aSetOfFaces.count( aFace ))
+ theFaces.push_back( (SMDS_MeshFace*) aFace );
+ }
+}
+
+/*
+ Class : BelongToMeshGroup
+ Description : Verify whether a mesh element is included into a mesh group
+*/
+BelongToMeshGroup::BelongToMeshGroup(): myGroup( 0 )
+{
+}
+
+void BelongToMeshGroup::SetGroup( SMESHDS_GroupBase* g )
+{
+ myGroup = g;
+}
+
+void BelongToMeshGroup::SetStoreName( const std::string& sn )
+{
+ myStoreName = sn;
+}
+
+void BelongToMeshGroup::SetMesh( const SMDS_Mesh* theMesh )
+{
+ if ( myGroup && myGroup->GetMesh() != theMesh )
+ {
+ myGroup = 0;
+ }
+ if ( !myGroup && !myStoreName.empty() )
+ {
+ if ( const SMESHDS_Mesh* aMesh = dynamic_cast<const SMESHDS_Mesh*>(theMesh))
+ {
+ const std::set<SMESHDS_GroupBase*>& grps = aMesh->GetGroups();
+ std::set<SMESHDS_GroupBase*>::const_iterator g = grps.begin();
+ for ( ; g != grps.end() && !myGroup; ++g )
+ if ( *g && myStoreName == (*g)->GetStoreName() )
+ myGroup = *g;
+ }
+ }
+ if ( myGroup )
+ {
+ myGroup->IsEmpty(); // make GroupOnFilter update its predicate
+ }
+}
+
+bool BelongToMeshGroup::IsSatisfy( long theElementId )
+{
+ return myGroup ? myGroup->Contains( theElementId ) : false;
+}
+
+SMDSAbs_ElementType BelongToMeshGroup::GetType() const
+{
+ return myGroup ? myGroup->GetType() : SMDSAbs_All;
+}
+
+//================================================================================
+// ElementsOnSurface
+//================================================================================
+
+ElementsOnSurface::ElementsOnSurface()
+{
+ myIds.Clear();
+ myType = SMDSAbs_All;
+ mySurf.Nullify();
+ myToler = Precision::Confusion();
+ myUseBoundaries = false;
+}
+
+ElementsOnSurface::~ElementsOnSurface()
+{
+}
+
+void ElementsOnSurface::SetMesh( const SMDS_Mesh* theMesh )
+{
+ myMeshModifTracer.SetMesh( theMesh );
+ if ( myMeshModifTracer.IsMeshModified())
+ process();
+}
+
+bool ElementsOnSurface::IsSatisfy( long theElementId )
+{
+ return myIds.Contains( theElementId );
+}
+
+SMDSAbs_ElementType ElementsOnSurface::GetType() const
+{ return myType; }
+
+void ElementsOnSurface::SetTolerance( const double theToler )
+{
+ if ( myToler != theToler )
+ {
+ myToler = theToler;
+ process();
+ }
+}
+
+double ElementsOnSurface::GetTolerance() const
+{ return myToler; }
+
+void ElementsOnSurface::SetUseBoundaries( bool theUse )
+{
+ if ( myUseBoundaries != theUse ) {
+ myUseBoundaries = theUse;
+ SetSurface( mySurf, myType );
+ }
+}
+
+void ElementsOnSurface::SetSurface( const TopoDS_Shape& theShape,
+ const SMDSAbs_ElementType theType )
+{
+ myIds.Clear();
+ myType = theType;
+ mySurf.Nullify();
+ if ( theShape.IsNull() || theShape.ShapeType() != TopAbs_FACE )
+ return;
+ mySurf = TopoDS::Face( theShape );
+ BRepAdaptor_Surface SA( mySurf, myUseBoundaries );
+ Standard_Real
+ u1 = SA.FirstUParameter(),
+ u2 = SA.LastUParameter(),
+ v1 = SA.FirstVParameter(),
+ v2 = SA.LastVParameter();
+ Handle(Geom_Surface) surf = BRep_Tool::Surface( mySurf );
+ myProjector.Init( surf, u1,u2, v1,v2 );
+ process();
+}
+
+void ElementsOnSurface::process()
+{
+ myIds.Clear();
+ if ( mySurf.IsNull() )
+ return;
+
+ if ( !myMeshModifTracer.GetMesh() )
+ return;
+
+ myIds.ReSize( myMeshModifTracer.GetMesh()->GetMeshInfo().NbElements( myType ));
+
+ SMDS_ElemIteratorPtr anIter = myMeshModifTracer.GetMesh()->elementsIterator( myType );
+ for(; anIter->more(); )
+ process( anIter->next() );
+}
+
+void ElementsOnSurface::process( const SMDS_MeshElement* theElemPtr )
+{
+ SMDS_ElemIteratorPtr aNodeItr = theElemPtr->nodesIterator();
+ bool isSatisfy = true;
+ for ( ; aNodeItr->more(); )
+ {
+ SMDS_MeshNode* aNode = (SMDS_MeshNode*)aNodeItr->next();
+ if ( !isOnSurface( aNode ) )
+ {
+ isSatisfy = false;
+ break;
+ }
+ }
+ if ( isSatisfy )
+ myIds.Add( theElemPtr->GetID() );
+}
+
+bool ElementsOnSurface::isOnSurface( const SMDS_MeshNode* theNode )
+{
+ if ( mySurf.IsNull() )
+ return false;
+
+ gp_Pnt aPnt( theNode->X(), theNode->Y(), theNode->Z() );
+ // double aToler2 = myToler * myToler;
+// if ( mySurf->IsKind(STANDARD_TYPE(Geom_Plane)))
+// {
+// gp_Pln aPln = Handle(Geom_Plane)::DownCast(mySurf)->Pln();
+// if ( aPln.SquareDistance( aPnt ) > aToler2 )
+// return false;
+// }
+// else if ( mySurf->IsKind(STANDARD_TYPE(Geom_CylindricalSurface)))
+// {
+// gp_Cylinder aCyl = Handle(Geom_CylindricalSurface)::DownCast(mySurf)->Cylinder();
+// double aRad = aCyl.Radius();
+// gp_Ax3 anAxis = aCyl.Position();
+// gp_XYZ aLoc = aCyl.Location().XYZ();
+// double aXDist = anAxis.XDirection().XYZ() * ( aPnt.XYZ() - aLoc );
+// double aYDist = anAxis.YDirection().XYZ() * ( aPnt.XYZ() - aLoc );
+// if ( fabs(aXDist*aXDist + aYDist*aYDist - aRad*aRad) > aToler2 )
+// return false;
+// }
+// else
+// return false;
+ myProjector.Perform( aPnt );
+ bool isOn = ( myProjector.IsDone() && myProjector.LowerDistance() <= myToler );
+
+ return isOn;
+}
+
+
+//================================================================================
+// ElementsOnShape
+//================================================================================
+
+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; }
+ 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 ); }
+ 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)
+{
+}
+
+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;
+}
+
+void ElementsOnShape::SetTolerance (const double theToler)
+{
+ if (myToler != theToler) {
+ myToler = theToler;
+ SetShape(myShape, myType);
+ }
+}
+
+double ElementsOnShape::GetTolerance() const
+{
+ return myToler;
+}
+
+void ElementsOnShape::SetAllNodes (bool theAllNodes)
+{
+ myAllNodesFlag = theAllNodes;
+}
+
+void ElementsOnShape::SetMesh (const SMDS_Mesh* theMesh)
+{
+ myMeshModifTracer.SetMesh( theMesh );
+ if ( myMeshModifTracer.IsMeshModified())
+ {
+ size_t nbNodes = theMesh ? theMesh->NbNodes() : 0;
+ if ( myNodeIsChecked.size() == nbNodes )
+ {
+ std::fill( myNodeIsChecked.begin(), myNodeIsChecked.end(), false );
+ }
+ else
+ {
+ SMESHUtils::FreeVector( myNodeIsChecked );
+ SMESHUtils::FreeVector( myNodeIsOut );
+ myNodeIsChecked.resize( nbNodes, false );
+ myNodeIsOut.resize( nbNodes );
+ }
+ }
+}
+
+bool ElementsOnShape::getNodeIsOut( const SMDS_MeshNode* n, bool& isOut )
+{
+ if ( n->GetID() >= (int) myNodeIsChecked.size() ||
+ !myNodeIsChecked[ n->GetID() ])
+ return false;
+
+ isOut = myNodeIsOut[ n->GetID() ];
+ return true;
+}
+
+void ElementsOnShape::setNodeIsOut( const SMDS_MeshNode* n, bool isOut )
+{
+ if ( n->GetID() < (int) myNodeIsChecked.size() )
+ {
+ myNodeIsChecked[ n->GetID() ] = true;
+ myNodeIsOut [ n->GetID() ] = isOut;
+ }
+}
+
+void ElementsOnShape::SetShape (const TopoDS_Shape& theShape,
+ const SMDSAbs_ElementType theType)
+{
+ bool shapeChanges = ( myShape != theShape );
+ myType = theType;
+ myShape = theShape;
+ if ( myShape.IsNull() ) return;
+
+ if ( shapeChanges )
+ {
+ // 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 ].Init( shapesMap( i+1 ), myToler );
+ }
+
+ if ( theType == SMDSAbs_Node )
+ {
+ SMESHUtils::FreeVector( myNodeIsChecked );
+ SMESHUtils::FreeVector( myNodeIsOut );
+ }
+ else
+ {
+ std::fill( myNodeIsChecked.begin(), myNodeIsChecked.end(), false );
+ }
+}
+
+void ElementsOnShape::clearClassifiers()
+{
+ // for ( size_t i = 0; i < myClassifiers.size(); ++i )
+ // delete myClassifiers[ i ];
+ myClassifiers.clear();
+
+ delete myOctree;
+ myOctree = 0;
+}
+
+bool ElementsOnShape::IsSatisfy( long elemId )
+{
+ 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 );
+ }
+
+ for ( int i = 0, nb = elem->NbNodes(); i < nb && (isSatisfy == myAllNodesFlag); ++i )
+ {
+ SMESH_TNodeXYZ aPnt( elem->GetNode( i ));
+ centerXYZ += aPnt;
+
+ isNodeOut = true;
+ if ( !getNodeIsOut( aPnt._node, isNodeOut ))
+ {
+ 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 )
+ {
+ centerXYZ /= elem->NbNodes();
+ isSatisfy = false;
+ 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;
+}
+
+//================================================================================
+/*!
+ * \brief Check and optionally return a satisfying shape
+ */
+//================================================================================
+
+bool ElementsOnShape::IsSatisfy (const SMDS_MeshNode* node,
+ TopoDS_Shape* okShape)