X-Git-Url: http://git.salome-platform.org/gitweb/?p=modules%2Fsmesh.git;a=blobdiff_plain;f=src%2FSMESHUtils%2FSMESH_FreeBorders.cxx;h=b4d4649473c768dce8669e0121878fbb7afcf4b3;hp=87951012c3389ea15cbe6a9d36b54565862f7a6e;hb=0fc0831670e27a5611b941c52dc152fd63964515;hpb=5482b99d07dd144fd5be299e722f39a81de3b5be diff --git a/src/SMESHUtils/SMESH_FreeBorders.cxx b/src/SMESHUtils/SMESH_FreeBorders.cxx index 87951012c..b4d464947 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-2020 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; @@ -62,6 +63,7 @@ namespace 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 @@ -90,7 +92,7 @@ namespace myNodes[0] = node1->Node(); myNodes[1] = node2->Node(); myFace = face; - setId( ID ); // mesh element ID + setID( ID ); // mesh element ID } bool IsInGroup() const { @@ -129,10 +131,19 @@ namespace if ( myID < 0 ) { myID = id; - if ( myNext ) - myNext->SetID( id + 1 ); + + for ( BEdge* be = myNext; be && be->myID < 0; be = be->myNext ) + { + be->myID = ++id; + } } } + //================================================================================ + /*! + * \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; @@ -145,6 +156,12 @@ 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 @@ -160,6 +177,12 @@ 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 ) @@ -221,6 +244,64 @@ namespace } }; // 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 ) || @@ -268,6 +349,12 @@ namespace } } + //================================================================================ + /*! + * \brief Connect BEdge's incident at this node + */ + //================================================================================ + void BNode::AddLinked( BEdge* e ) const { myLinkedEdges.reserve(2); @@ -670,8 +757,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]; @@ -736,3 +824,136 @@ void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh& mesh, } // SMESH_MeshAlgos::FindCoincidentFreeBorders() +//================================================================================ +/* + * Returns all TFreeBorder's. Optionally check if the mesh is manifold + * and if faces are correctly oriented. + */ +//================================================================================ + +void SMESH_MeshAlgos::FindFreeBorders(SMDS_Mesh& theMesh, + TFreeBorderVec & theFoundFreeBordes, + const bool theClosedOnly, + bool* theIsManifold, + bool* theIsGoodOri) +{ + bool isManifold = true; + + // find free links + typedef NCollection_DataMap TLink2FaceMap; + TLink2FaceMap linkMap; + int nbSharedLinks = 0; + SMDS_FaceIteratorPtr faceIt = theMesh.facesIterator(); + while ( faceIt->more() ) + { + const SMDS_MeshElement* face = faceIt->next(); + if ( !face ) continue; + + const SMDS_MeshNode* n0 = face->GetNode( face->NbNodes() - 1 ); + SMDS_NodeIteratorPtr nodeIt = face->interlacedNodesIterator(); + while ( nodeIt->more() ) + { + const SMDS_MeshNode* n1 = nodeIt->next(); + SMESH_TLink link( n0, n1 ); + if ( const SMDS_MeshElement** faceInMap = linkMap.ChangeSeek( link )) + { + if ( *faceInMap ) + { + if ( theIsGoodOri && *theIsGoodOri && !IsRightOrder( *faceInMap, n1, n0 )) + *theIsGoodOri = false; + } + else + { + isManifold = false; + } + nbSharedLinks += bool( *faceInMap ); + *faceInMap = 0; + } + else + { + linkMap.Bind( link, face ); + } + n0 = n1; + } + } + if ( theIsManifold ) + *theIsManifold = isManifold; + + if ( linkMap.Extent() == nbSharedLinks ) + return; + + // form free borders + std::set < BNode > bNodes; + std::vector< BEdge > bEdges( linkMap.Extent() - nbSharedLinks ); + + TLink2FaceMap::Iterator linkIt( linkMap ); + 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(); + + // assign IDs to borders + std::vector< BEdge* > borders; // 1st of connected (via myPrev and myNext) edges + std::set< BNode >::iterator bn = bNodes.begin(); + for ( ; bn != bNodes.end(); ++bn ) + { + for ( size_t i = 0; i < bn->myLinkedEdges.size(); ++i ) + { + if ( bn->myLinkedEdges[i]->myBorderID < 0 ) + { + BEdge* be = bn->myLinkedEdges[i]; + int borderID = borders.size(); + borders.push_back( be ); + for ( ; be && be->myBorderID < 0; be = be->myNext ) + { + be->myBorderID = borderID; + be->Orient(); + } + bool isClosed = ( be == bn->myLinkedEdges[i] ); + if ( !isClosed && theClosedOnly ) + { + borders.pop_back(); + continue; + } + be = bn->myLinkedEdges[i]->myPrev; + for ( ; be && be->myBorderID < 0; be = be->myPrev ) + { + be->myBorderID = borderID; + be->Orient(); + } + if ( !isClosed ) + while ( borders.back()->myPrev ) + borders.back() = borders.back()->myPrev; + } + } + } + theFoundFreeBordes.resize( borders.size() ); + for ( size_t i = 0; i < borders.size(); ++i ) + { + TFreeBorder & bordNodes = theFoundFreeBordes[ i ]; + BEdge* be = borders[i]; + + size_t cnt = 1; + for ( be = be->myNext; be && be != borders[i]; be = be->myNext ) + ++cnt; + bordNodes.resize( cnt + 1 ); + + BEdge* beLast; + for ( be = borders[i], cnt = 0; + be && cnt < bordNodes.size()-1; + be = be->myNext, ++cnt ) + { + bordNodes[ cnt ] = be->myBNode1->Node(); + beLast = be; + } + bordNodes.back() = beLast->myBNode2->Node(); + } +}