X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSMESHUtils%2FSMESH_FreeBorders.cxx;h=ae6efa6db59278e06f30a04153a023fdbedb271a;hb=1746a461949c030eb46ccb860e586ade2e5de5e3;hp=939178f739fac9b744261c3a1941f9344bdb74d5;hpb=fd96feab4b58b9ebe8706e44b35006e0122d682e;p=modules%2Fsmesh.git diff --git a/src/SMESHUtils/SMESH_FreeBorders.cxx b/src/SMESHUtils/SMESH_FreeBorders.cxx index 939178f73..ae6efa6db 100644 --- a/src/SMESHUtils/SMESH_FreeBorders.cxx +++ b/src/SMESHUtils/SMESH_FreeBorders.cxx @@ -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 // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -36,6 +36,7 @@ #include #include +#include #include using namespace SMESH_MeshAlgos; @@ -54,13 +55,15 @@ namespace BNode(const SMDS_MeshNode * node): SMESH_TNodeXYZ( node ) {} const SMDS_MeshNode * Node() const { return _node; } - void AddLinked( BEdge* e ) const; - void AddClose ( const BEdge* e, double u ) const; + void AddLinked( BEdge* e ) const; + void AddClose ( const BEdge* e, double u ) const; BEdge* GetCloseEdge( size_t i ) const { return myCloseEdges[i].first; } double GetCloseU( size_t i ) const { return myCloseEdges[i].second; } BEdge* GetCloseEdgeOfBorder( int borderID, double * u = 0 ) const; - bool IsCloseEdge( const BEdge* ) const; + bool HasCloseEdgeWithNode( const BNode* n ) const; + bool IsCloseEdge( const BEdge*, double * u = 0 ) const; bool operator<(const BNode& other) const { return Node()->GetID() < other.Node()->GetID(); } + double SquareDistance(const BNode& e2) const { return ( e2 - *this ).SquareModulus(); } }; /*! * \brief Edge of a free border @@ -132,6 +135,12 @@ namespace myNext->SetID( id + 1 ); } } + //================================================================================ + /*! + * \brief Checks if a point is closer to this BEdge than tol + */ + //================================================================================ + bool IsOut( const gp_XYZ& point, const double tol, double& u ) const { gp_XYZ me = *myBNode2 - *myBNode1; @@ -144,13 +153,19 @@ namespace double dist2 = ( point - proj ).SquareModulus(); return ( dist2 > tol * tol ); } + //================================================================================ + /*! + * \brief Checks if two BEdges can be considered as overlapping + */ + //================================================================================ + bool IsOverlappingProjection( const BEdge* toE, const double u, bool is1st ) const { // is1st shows which end of toE is projected on this at u double u2; const double eps = 0.1; - if ( toE == myBNode1->GetCloseEdgeOfBorder( toE->myBorderID, &u2 ) || - toE == myBNode2->GetCloseEdgeOfBorder( toE->myBorderID, &u2 )) + if ( myBNode1->IsCloseEdge( toE, &u2 ) || + myBNode2->IsCloseEdge( toE, &u2 )) return (( 0 < u2 && u2 < 1 ) && // u2 is proj param of myBNode's on toE ( Abs( u2 - int( !is1st )) > eps )); @@ -159,32 +174,131 @@ namespace return Abs( u - u2 ) > eps; return false; } + //================================================================================ + /*! + * \brief Finds all neighbor BEdge's having the same close borders + */ + //================================================================================ + bool GetRangeOfSameCloseBorders(BEdge* eRange[2], const std::set< int >& bordIDs) { if ( this->myCloseBorders != bordIDs ) return false; - eRange[0] = this; - while ( eRange[0]->myPrev && eRange[0]->myPrev->myCloseBorders == bordIDs ) + if ( bordIDs.size() == 1 && bordIDs.count( myBorderID )) // border close to self { - if ( eRange[0]->myPrev == this /*|| eRange[0]->myPrev->myInGroup*/ ) - break; - eRange[0] = eRange[0]->myPrev; - } - - eRange[1] = this; - if ( eRange[0]->myPrev != this ) // not closed range - while ( eRange[1]->myNext && eRange[1]->myNext->myCloseBorders == bordIDs ) + double u; + eRange[0] = this; + while ( eRange[0]->myBNode1->GetCloseEdgeOfBorder( myBorderID, &u )) { - if ( eRange[1]->myNext == this /*|| eRange[1]->myNext->myInGroup*/ ) + if ( eRange[0]->myPrev == this || u < 0 || u > 1 ) + break; + eRange[0] = eRange[0]->myPrev; + } + eRange[1] = this; + while ( eRange[1]->myBNode2->GetCloseEdgeOfBorder( myBorderID, &u )) + { + if ( eRange[1]->myNext == this || u < 0 || u > 1 ) break; eRange[1] = eRange[1]->myNext; } + } + else + { + eRange[0] = this; + while ( eRange[0]->myPrev && eRange[0]->myPrev->myCloseBorders == bordIDs ) + { + if ( eRange[0]->myPrev == this ) + break; + eRange[0] = eRange[0]->myPrev; + } - return ( eRange[0] != eRange[1] ); + eRange[1] = this; + if ( eRange[0]->myPrev != this ) // not closed border + while ( eRange[1]->myNext && eRange[1]->myNext->myCloseBorders == bordIDs ) + { + if ( eRange[1]->myNext == this ) + break; + eRange[1] = eRange[1]->myNext; + } + } + + if ( eRange[0] == eRange[1] ) + { + std::set::iterator closeBord = eRange[0]->myCloseBorders.begin(); + for ( ; closeBord != eRange[0]->myCloseBorders.end(); ++closeBord ) + { + if ( BEdge* be = eRange[0]->myBNode1->GetCloseEdgeOfBorder( *closeBord )) + if ( be->myCloseBorders == eRange[0]->myCloseBorders ) + return true; + if ( BEdge* be = eRange[0]->myBNode2->GetCloseEdgeOfBorder( *closeBord )) + if ( be->myCloseBorders == eRange[0]->myCloseBorders ) + return true; + } + return false; + } + return true; } }; // class BEdge + //================================================================================ + /*! + * \brief Checks if all border parts include the whole closed border, and if so + * returns \c true and choose starting BEdge's with most coincident nodes + */ + //================================================================================ + + bool chooseStartOfClosedBorders( std::vector< BEdge* >& ranges ) // PAL23078#c21002 + { + bool allClosed = true; + for ( size_t iR = 1; iR < ranges.size() && allClosed; iR += 2 ) + allClosed = ( ranges[ iR-1 ]->myPrev == ranges[ iR ] ); + if ( !allClosed ) + return allClosed; + + double u, minDiff = Precision::Infinite(); + std::vector< BEdge* > start( ranges.size() / 2 ); + BEdge* range0 = start[0] = ranges[0]; + do + { + double maxDiffU = 0; + double maxDiff = 0; + for ( size_t iR = 3; iR < ranges.size(); iR += 2 ) + { + int borderID = ranges[iR]->myBorderID; + if ( BEdge* e = start[0]->myBNode1->GetCloseEdgeOfBorder( borderID, & u )) + { + start[ iR / 2 ] = e; + double diffU = Min( Abs( u ), Abs( 1.-u )); + double diff = e->myBNode1->SquareDistance( *e->myBNode2 ) * diffU * diffU; + maxDiffU = Max( diffU, maxDiffU ); + maxDiff = Max( diff, maxDiff ); + } + } + if ( maxDiff < minDiff ) + { + minDiff = maxDiff; + for ( size_t iR = 1; iR < ranges.size(); iR += 2 ) + { + ranges[ iR-1 ] = start[ iR/2 ]; + ranges[ iR ] = ranges[ iR-1]->myPrev; + } + } + if ( maxDiffU < 1e-6 ) + break; + start[0] = start[0]->myNext; + } + while ( start[0] != range0 ); + + return allClosed; + } + + //================================================================================ + /*! + * \brief Tries to include neighbor BEdge's into a border part + */ + //================================================================================ + void extendPart( BEdge* & e1, BEdge* & e2, const std::set< int >& bordIDs, int groupID ) { if (( e1->myPrev == e2 ) || @@ -197,8 +311,7 @@ namespace if ( e1->myPrev ) { for ( bord = bordIDs.begin(); bord != bordIDs.end(); ++bord ) - if (( *bord != e1->myBorderID ) && - (( be = e1->myBNode1->GetCloseEdgeOfBorder( *bord, &u ))) && + if ((( be = e1->myBNode1->GetCloseEdgeOfBorder( *bord, &u ))) && ( be->myInGroup == groupID ) && ( 0 < u && u < 1 ) && ( be->IsOverlappingProjection( e1->myPrev, u, false ))) @@ -206,12 +319,17 @@ namespace e1 = e1->myPrev; break; } + if ( bord == bordIDs.end() && // not extended + e1->myBNode1->HasCloseEdgeWithNode( e1->myPrev->myBNode1 )) + { + e1 = e1->myPrev; + } + e1->myInGroup = groupID; } if ( e2->myNext ) { for ( bord = bordIDs.begin(); bord != bordIDs.end(); ++bord ) - if (( *bord != e2->myBorderID ) && - (( be = e2->myBNode2->GetCloseEdgeOfBorder( *bord, &u ))) && + if ((( be = e2->myBNode2->GetCloseEdgeOfBorder( *bord, &u ))) && ( be->myInGroup == groupID ) && ( 0 < u && u < 1 ) && ( be->IsOverlappingProjection( e2->myNext, u, true ))) @@ -219,9 +337,21 @@ namespace e2 = e2->myNext; break; } + if ( bord == bordIDs.end() && // not extended + e2->myBNode2->HasCloseEdgeWithNode( e2->myNext->myBNode2 )) + { + e2 = e2->myNext; + } + e2->myInGroup = groupID; } } + //================================================================================ + /*! + * \brief Connect BEdge's incident at this node + */ + //================================================================================ + void BNode::AddLinked( BEdge* e ) const { myLinkedEdges.reserve(2); @@ -244,7 +374,7 @@ namespace void BNode::AddClose ( const BEdge* e, double u ) const { if ( ! e->Contains( this )) - myCloseEdges.push_back( make_pair( const_cast< BEdge* >( e ), u )); + myCloseEdges.push_back( std::make_pair( const_cast< BEdge* >( e ), u )); } BEdge* BNode::GetCloseEdgeOfBorder( int borderID, double * uPtr ) const { @@ -261,11 +391,22 @@ namespace if ( uPtr ) *uPtr = u; return e; } - bool BNode::IsCloseEdge( const BEdge* e ) const + bool BNode::HasCloseEdgeWithNode( const BNode* n ) const + { + for ( size_t i = 0; i < myCloseEdges.size(); ++i ) + if ( GetCloseEdge( i )->Contains( n ) && + 0 < GetCloseU( i ) && GetCloseU( i ) < 1 ) + return true; + return false; + } + bool BNode::IsCloseEdge( const BEdge* e, double * uPtr ) const { for ( size_t i = 0; i < myCloseEdges.size(); ++i ) if ( e == GetCloseEdge( i ) ) + { + if ( uPtr ) *uPtr = GetCloseU( i ); return true; + } return false; } @@ -287,19 +428,6 @@ namespace } // namespace -// struct needed for NCollection_Map -struct TLinkHasher -{ - static int HashCode(const SMESH_TLink& link, int aLimit) - { - return ::HashCode( link.node1()->GetID() + link.node2()->GetID(), aLimit ); - } - static Standard_Boolean IsEqual(const SMESH_TLink& l1, const SMESH_TLink& l2) - { - return ( l1.node1() == l2.node1() && l1.node2() == l2.node2() ); - } -}; - //================================================================================ /* * Returns groups of TFreeBorder's coincident within the given tolerance. @@ -313,8 +441,9 @@ void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh& mesh, CoincidentFreeBorders & foundFreeBordes) { // find free links - typedef NCollection_DataMap TLink2FaceMap; + typedef NCollection_DataMap TLink2FaceMap; TLink2FaceMap linkMap; + int nbSharedLinks = 0; SMDS_FaceIteratorPtr faceIt = mesh.facesIterator(); while ( faceIt->more() ) { @@ -327,27 +456,36 @@ void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh& mesh, { const SMDS_MeshNode* n1 = nodeIt->next(); SMESH_TLink link( n0, n1 ); - if ( !linkMap.Bind( link, face )) - linkMap.UnBind( link ); + if ( const SMDS_MeshElement** faceInMap = linkMap.ChangeSeek( link )) + { + nbSharedLinks += bool( *faceInMap ); + *faceInMap = 0; + } + else + { + linkMap.Bind( link, face ); + } n0 = n1; } } - if ( linkMap.IsEmpty() ) + if ( linkMap.Extent() == nbSharedLinks ) return; // form free borders std::set < BNode > bNodes; - std::vector< BEdge > bEdges( linkMap.Extent() ); + std::vector< BEdge > bEdges( linkMap.Extent() - nbSharedLinks ); TLink2FaceMap::Iterator linkIt( linkMap ); - for ( int iEdge = 0; linkIt.More(); linkIt.Next(), ++iEdge ) + for ( int iEdge = 0; linkIt.More(); linkIt.Next() ) { + if ( !linkIt.Value() ) continue; const SMESH_TLink & link = linkIt.Key(); std::set< BNode >::iterator n1 = bNodes.insert( BNode( link.node1() )).first; std::set< BNode >::iterator n2 = bNodes.insert( BNode( link.node2() )).first; bEdges[ iEdge ].Set( &*n1, &*n2, linkIt.Value(), iEdge+1 ); n1->AddLinked( & bEdges[ iEdge ] ); n2->AddLinked( & bEdges[ iEdge ] ); + ++iEdge; } linkMap.Clear(); @@ -515,9 +653,9 @@ void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh& mesh, // form groups of coincident parts of free borders - TFreeBorderPart part; - TCoincidentGroup group; - vector< BEdge* > ranges; // couples of edges delimiting parts + TFreeBorderPart part; + TCoincidentGroup group; + std::vector< BEdge* > ranges; // couples of edges delimiting parts BEdge* be = 0; // a current edge int skipGroup = bEdges.size(); // a group ID used to avoid repeating treatment of edges @@ -563,36 +701,44 @@ void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh& mesh, } beRange[1]->myInGroup = groupID; + // get starting edge of each close border + closeEdges.clear(); + be = beRange[0]; + if ( be->myCloseBorders.empty() ) + be = beRange[0]->myNext; + std::set::iterator closeBord = be->myCloseBorders.begin(); + for ( ; closeBord != be->myCloseBorders.end(); ++closeBord ) + if ( BEdge* e = be->myBNode2->GetCloseEdgeOfBorder( *closeBord )) + closeEdges.push_back( e ); + + for ( size_t iE = 0; iE < closeEdges.size(); ++iE ) + if ( be->myCloseBorders != closeEdges[iE]->myCloseBorders ) + { + closeBord = closeEdges[iE]->myCloseBorders.begin(); + for ( ; closeBord != closeEdges[iE]->myCloseBorders.end(); ++closeBord ) + if ( !be->myCloseBorders.count( *closeBord )) + if ( BEdge* e = closeEdges[iE]->myBNode2->GetCloseEdgeOfBorder( *closeBord )) + if ( std::find( closeEdges.begin(), closeEdges.end(), e ) == closeEdges.end() ) + closeEdges.push_back( e ); + } + // add parts of other borders BEdge* be1st = beRange[0]; - closeEdges.clear(); - std::set::iterator closeBord = be1st->myCloseBorders.begin(); - for ( ; closeBord != be1st->myCloseBorders.end(); ++closeBord ) - closeEdges.push_back( be1st->myBNode2->GetCloseEdgeOfBorder( *closeBord )); - for ( size_t iE = 0; iE < closeEdges.size(); ++iE ) { be = closeEdges[ iE ]; if ( !be ) continue; bool ok = be->GetRangeOfSameCloseBorders( beRange, be->myCloseBorders ); - if ( !ok && be->myPrev ) - ok = be->myPrev->GetRangeOfSameCloseBorders( beRange, be1st->myCloseBorders ); - if ( !ok && be->myNext ) - ok = be->myNext->GetRangeOfSameCloseBorders( beRange, be1st->myCloseBorders ); + // if ( !ok && be->myPrev ) + // ok = be->myPrev->GetRangeOfSameCloseBorders( beRange, be1st->myCloseBorders ); + // if ( !ok && be->myNext ) + // ok = be->myNext->GetRangeOfSameCloseBorders( beRange, be1st->myCloseBorders ); if ( !ok ) continue; be = beRange[0]; - if ( be->myCloseBorders != be1st->myCloseBorders ) - { - //add missing edges to closeEdges - closeBord = be->myCloseBorders.begin(); - for ( ; closeBord != be->myCloseBorders.end(); ++closeBord ) - if ( !be1st->myCloseBorders.count( *closeBord )) - closeEdges.push_back( be->myBNode2->GetCloseEdgeOfBorder( *closeBord )); - } ranges.push_back( beRange[0] ); ranges.push_back( beRange[1] ); @@ -608,8 +754,9 @@ void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh& mesh, if ( ranges.size() > 2 ) { - for ( size_t iR = 1; iR < ranges.size(); iR += 2 ) - extendPart( ranges[ iR-1 ], ranges[ iR ], be1st->myCloseBorders, groupID ); + if ( !chooseStartOfClosedBorders( ranges )) + for ( size_t iR = 1; iR < ranges.size(); iR += 2 ) + extendPart( ranges[ iR-1 ], ranges[ iR ], be1st->myCloseBorders, groupID ); // fill in a group beRange[0] = ranges[0]; @@ -645,9 +792,11 @@ void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh& mesh, part._node2 = beRange[0]->myID + 1; part._nodeLast = beRange[1]->myID + 1; } + // if ( group[0]._node2 != part._node2 ) group.push_back( part ); } - foundFreeBordes._coincidentGroups.push_back( group ); + //if ( group.size() > 1 ) + foundFreeBordes._coincidentGroups.push_back( group ); } else {