+ // 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
+{
+ std::set<SMDS_MeshCell *> aSetOfFaces;
+ // take all faces that shared first node
+ SMDS_ElemIteratorPtr anItr = theLink.myNode1->facesIterator();
+ for ( ; anItr->more(); )
+ {
+ SMDS_MeshFace* aFace = (SMDS_MeshFace*)anItr->next();
+ if ( !aFace )
+ continue;
+ aSetOfFaces.insert( aFace );
+ }
+ // take all faces that shared second node
+ anItr = theLink.myNode2->facesIterator();
+ // find the common part of two sets
+ for ( ; anItr->more(); )
+ {
+ SMDS_MeshFace* aFace = (SMDS_MeshFace*)anItr->next();
+ if ( aSetOfFaces.count( aFace ) )
+ theFaces.push_back( 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 )
+ myIds.Clear();
+ myToler = theToler;
+}
+
+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; }
+ 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