+//=======================================================================
+// name : SetMesh
+// Purpose : Set mesh
+//=======================================================================
+void RangeOfIds::SetMesh( const SMDS_Mesh* theMesh )
+{
+ myMesh = theMesh;
+}
+
+//=======================================================================
+// name : AddToRange
+// Purpose : Add ID to the range
+//=======================================================================
+bool RangeOfIds::AddToRange( long theEntityId )
+{
+ myIds.Add( theEntityId );
+ return true;
+}
+
+//=======================================================================
+// name : GetRangeStr
+// Purpose : Get range as a string.
+// Example: "1,2,3,50-60,63,67,70-"
+//=======================================================================
+void RangeOfIds::GetRangeStr( TCollection_AsciiString& theResStr )
+{
+ theResStr.Clear();
+
+ TColStd_SequenceOfInteger anIntSeq;
+ TColStd_SequenceOfAsciiString aStrSeq;
+
+ TColStd_MapIteratorOfMapOfInteger anIter( myIds );
+ for ( ; anIter.More(); anIter.Next() )
+ {
+ int anId = anIter.Key();
+ TCollection_AsciiString aStr( anId );
+ anIntSeq.Append( anId );
+ aStrSeq.Append( aStr );
+ }
+
+ for ( int i = 1, n = myMin.Length(); i <= n; i++ )
+ {
+ int aMinId = myMin( i );
+ int aMaxId = myMax( i );
+
+ TCollection_AsciiString aStr;
+ if ( aMinId != IntegerFirst() )
+ aStr += aMinId;
+
+ aStr += "-";
+
+ if ( aMaxId != IntegerLast() )
+ aStr += aMaxId;
+
+ // find position of the string in result sequence and insert string in it
+ if ( anIntSeq.Length() == 0 )
+ {
+ anIntSeq.Append( aMinId );
+ aStrSeq.Append( aStr );
+ }
+ else
+ {
+ if ( aMinId < anIntSeq.First() )
+ {
+ anIntSeq.Prepend( aMinId );
+ aStrSeq.Prepend( aStr );
+ }
+ else if ( aMinId > anIntSeq.Last() )
+ {
+ anIntSeq.Append( aMinId );
+ aStrSeq.Append( aStr );
+ }
+ else
+ for ( int j = 1, k = anIntSeq.Length(); j <= k; j++ )
+ if ( aMinId < anIntSeq( j ) )
+ {
+ anIntSeq.InsertBefore( j, aMinId );
+ aStrSeq.InsertBefore( j, aStr );
+ break;
+ }
+ }
+ }
+
+ if ( aStrSeq.Length() == 0 )
+ return;
+
+ theResStr = aStrSeq( 1 );
+ for ( int j = 2, k = aStrSeq.Length(); j <= k; j++ )
+ {
+ theResStr += ",";
+ theResStr += aStrSeq( j );
+ }
+}
+
+//=======================================================================
+// name : SetRangeStr
+// Purpose : Define range with string
+// Example of entry string: "1,2,3,50-60,63,67,70-"
+//=======================================================================
+bool RangeOfIds::SetRangeStr( const TCollection_AsciiString& theStr )
+{
+ myMin.Clear();
+ myMax.Clear();
+ myIds.Clear();
+
+ TCollection_AsciiString aStr = theStr;
+ for ( int i = 1; i <= aStr.Length(); ++i )
+ {
+ char c = aStr.Value( i );
+ if ( !isdigit( c ) && c != ',' && c != '-' )
+ aStr.SetValue( i, ',');
+ }
+ aStr.RemoveAll( ' ' );
+
+ TCollection_AsciiString tmpStr = aStr.Token( ",", 1 );
+ int i = 1;
+ while ( tmpStr != "" )
+ {
+ tmpStr = aStr.Token( ",", i++ );
+ int aPos = tmpStr.Search( '-' );
+
+ if ( aPos == -1 )
+ {
+ if ( tmpStr.IsIntegerValue() )
+ myIds.Add( tmpStr.IntegerValue() );
+ else
+ return false;
+ }
+ else
+ {
+ TCollection_AsciiString aMaxStr = tmpStr.Split( aPos );
+ TCollection_AsciiString aMinStr = tmpStr;
+
+ while ( aMinStr.Search( "-" ) != -1 ) aMinStr.RemoveAll( '-' );
+ while ( aMaxStr.Search( "-" ) != -1 ) aMaxStr.RemoveAll( '-' );
+
+ if ( (!aMinStr.IsEmpty() && !aMinStr.IsIntegerValue()) ||
+ (!aMaxStr.IsEmpty() && !aMaxStr.IsIntegerValue()) )
+ return false;
+
+ myMin.Append( aMinStr.IsEmpty() ? IntegerFirst() : aMinStr.IntegerValue() );
+ myMax.Append( aMaxStr.IsEmpty() ? IntegerLast() : aMaxStr.IntegerValue() );
+ }
+ }
+
+ return true;
+}
+
+//=======================================================================
+// name : GetType
+// Purpose : Get type of supported entities
+//=======================================================================
+SMDSAbs_ElementType RangeOfIds::GetType() const
+{
+ return myType;
+}
+
+//=======================================================================
+// name : SetType
+// Purpose : Set type of supported entities
+//=======================================================================
+void RangeOfIds::SetType( SMDSAbs_ElementType theType )
+{
+ myType = theType;
+}
+
+//=======================================================================
+// name : IsSatisfy
+// Purpose : Verify whether entity satisfies to this rpedicate
+//=======================================================================
+bool RangeOfIds::IsSatisfy( long theId )
+{
+ if ( !myMesh )
+ return false;
+
+ if ( myType == SMDSAbs_Node )
+ {
+ if ( myMesh->FindNode( theId ) == 0 )
+ return false;
+ }
+ else
+ {
+ const SMDS_MeshElement* anElem = myMesh->FindElement( theId );
+ if ( anElem == 0 || (myType != anElem->GetType() && myType != SMDSAbs_All ))
+ return false;
+ }
+
+ if ( myIds.Contains( theId ) )
+ return true;
+
+ for ( int i = 1, n = myMin.Length(); i <= n; i++ )
+ if ( theId >= myMin( i ) && theId <= myMax( i ) )
+ return true;
+
+ return false;
+}
+
+/*
+ Class : Comparator
+ Description : Base class for comparators
+*/
+Comparator::Comparator():
+ myMargin(0)
+{}
+
+Comparator::~Comparator()
+{}
+
+void Comparator::SetMesh( const SMDS_Mesh* theMesh )
+{
+ if ( myFunctor )
+ myFunctor->SetMesh( theMesh );
+}
+
+void Comparator::SetMargin( double theValue )
+{
+ myMargin = theValue;
+}
+
+void Comparator::SetNumFunctor( NumericalFunctorPtr theFunct )
+{
+ myFunctor = theFunct;
+}
+
+SMDSAbs_ElementType Comparator::GetType() const
+{
+ return myFunctor ? myFunctor->GetType() : SMDSAbs_All;
+}
+
+double Comparator::GetMargin()
+{
+ return myMargin;
+}
+
+
+/*
+ Class : LessThan
+ Description : Comparator "<"
+*/
+bool LessThan::IsSatisfy( long theId )
+{
+ return myFunctor && myFunctor->GetValue( theId ) < myMargin;
+}
+
+
+/*
+ Class : MoreThan
+ Description : Comparator ">"
+*/
+bool MoreThan::IsSatisfy( long theId )
+{
+ return myFunctor && myFunctor->GetValue( theId ) > myMargin;
+}
+
+
+/*
+ Class : EqualTo
+ Description : Comparator "="
+*/
+EqualTo::EqualTo():
+ myToler(Precision::Confusion())
+{}
+
+bool EqualTo::IsSatisfy( long theId )
+{
+ return myFunctor && fabs( myFunctor->GetValue( theId ) - myMargin ) < myToler;
+}
+
+void EqualTo::SetTolerance( double theToler )
+{
+ myToler = theToler;
+}
+
+double EqualTo::GetTolerance()
+{
+ return myToler;
+}
+
+/*
+ Class : LogicalNOT
+ Description : Logical NOT predicate
+*/
+LogicalNOT::LogicalNOT()
+{}
+
+LogicalNOT::~LogicalNOT()
+{}
+
+bool LogicalNOT::IsSatisfy( long theId )
+{
+ return myPredicate && !myPredicate->IsSatisfy( theId );
+}
+
+void LogicalNOT::SetMesh( const SMDS_Mesh* theMesh )
+{
+ if ( myPredicate )
+ myPredicate->SetMesh( theMesh );
+}
+
+void LogicalNOT::SetPredicate( PredicatePtr thePred )
+{
+ myPredicate = thePred;
+}
+
+SMDSAbs_ElementType LogicalNOT::GetType() const
+{
+ return myPredicate ? myPredicate->GetType() : SMDSAbs_All;
+}
+
+
+/*
+ Class : LogicalBinary
+ Description : Base class for binary logical predicate
+*/
+LogicalBinary::LogicalBinary()
+{}
+
+LogicalBinary::~LogicalBinary()
+{}
+
+void LogicalBinary::SetMesh( const SMDS_Mesh* theMesh )
+{
+ if ( myPredicate1 )
+ myPredicate1->SetMesh( theMesh );
+
+ if ( myPredicate2 )
+ myPredicate2->SetMesh( theMesh );
+}
+
+void LogicalBinary::SetPredicate1( PredicatePtr thePredicate )
+{
+ myPredicate1 = thePredicate;
+}
+
+void LogicalBinary::SetPredicate2( PredicatePtr thePredicate )
+{
+ myPredicate2 = thePredicate;
+}
+
+SMDSAbs_ElementType LogicalBinary::GetType() const
+{
+ if ( !myPredicate1 || !myPredicate2 )
+ return SMDSAbs_All;
+
+ SMDSAbs_ElementType aType1 = myPredicate1->GetType();
+ SMDSAbs_ElementType aType2 = myPredicate2->GetType();
+
+ return aType1 == aType2 ? aType1 : SMDSAbs_All;
+}
+
+
+/*
+ Class : LogicalAND
+ Description : Logical AND
+*/
+bool LogicalAND::IsSatisfy( long theId )
+{
+ return
+ myPredicate1 &&
+ myPredicate2 &&
+ myPredicate1->IsSatisfy( theId ) &&
+ myPredicate2->IsSatisfy( theId );
+}
+
+
+/*
+ Class : LogicalOR
+ Description : Logical OR
+*/
+bool LogicalOR::IsSatisfy( long theId )
+{
+ return
+ myPredicate1 &&
+ myPredicate2 &&
+ (myPredicate1->IsSatisfy( theId ) ||
+ myPredicate2->IsSatisfy( theId ));
+}
+
+
+/*
+ FILTER
+*/
+
+// #ifdef WITH_TBB
+// #include <tbb/parallel_for.h>
+// #include <tbb/enumerable_thread_specific.h>
+
+// namespace Parallel
+// {
+// typedef tbb::enumerable_thread_specific< TIdSequence > TIdSeq;
+
+// struct Predicate
+// {
+// const SMDS_Mesh* myMesh;
+// PredicatePtr myPredicate;
+// TIdSeq & myOKIds;
+// Predicate( const SMDS_Mesh* m, PredicatePtr p, TIdSeq & ids ):
+// myMesh(m), myPredicate(p->Duplicate()), myOKIds(ids) {}
+// void operator() ( const tbb::blocked_range<size_t>& r ) const
+// {
+// for ( size_t i = r.begin(); i != r.end(); ++i )
+// if ( myPredicate->IsSatisfy( i ))
+// myOKIds.local().push_back();
+// }
+// }
+// }
+// #endif
+
+Filter::Filter()
+{}
+
+Filter::~Filter()
+{}
+
+void Filter::SetPredicate( PredicatePtr thePredicate )
+{
+ myPredicate = thePredicate;
+}
+
+void Filter::GetElementsId( const SMDS_Mesh* theMesh,
+ PredicatePtr thePredicate,
+ TIdSequence& theSequence )
+{
+ theSequence.clear();
+
+ if ( !theMesh || !thePredicate )
+ return;
+
+ thePredicate->SetMesh( theMesh );
+
+ SMDS_ElemIteratorPtr elemIt = theMesh->elementsIterator( thePredicate->GetType() );
+ if ( elemIt ) {
+ while ( elemIt->more() ) {
+ const SMDS_MeshElement* anElem = elemIt->next();
+ long anId = anElem->GetID();
+ if ( thePredicate->IsSatisfy( anId ) )
+ theSequence.push_back( anId );
+ }
+ }
+}
+
+void Filter::GetElementsId( const SMDS_Mesh* theMesh,
+ Filter::TIdSequence& theSequence )
+{
+ GetElementsId(theMesh,myPredicate,theSequence);
+}
+
+/*
+ ManifoldPart
+*/
+
+typedef std::set<SMDS_MeshFace*> TMapOfFacePtr;
+
+/*
+ Internal class Link
+*/
+
+ManifoldPart::Link::Link( SMDS_MeshNode* theNode1,
+ SMDS_MeshNode* theNode2 )
+{
+ myNode1 = theNode1;
+ myNode2 = theNode2;
+}
+
+ManifoldPart::Link::~Link()
+{
+ myNode1 = 0;
+ myNode2 = 0;
+}
+
+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();