From a0db244869b918aab5582bc4b4d39f592e849a97 Mon Sep 17 00:00:00 2001 From: eap Date: Wed, 6 Dec 2006 16:12:11 +0000 Subject: [PATCH] PAL13473 (Build repetitive mesh): 1) add FindMatchingNodes() 2) make FindFreeBorder() public --- src/SMESH/SMESH_MeshEditor.cxx | 242 +++++++++++++++++++++++++++++---- src/SMESH/SMESH_MeshEditor.hxx | 44 +++++- 2 files changed, 255 insertions(+), 31 deletions(-) diff --git a/src/SMESH/SMESH_MeshEditor.cxx b/src/SMESH/SMESH_MeshEditor.cxx index c0a3b2771..8e1df0059 100644 --- a/src/SMESH/SMESH_MeshEditor.cxx +++ b/src/SMESH/SMESH_MeshEditor.cxx @@ -73,7 +73,6 @@ using namespace std; using namespace SMESH::Controls; -typedef map TNodeNodeMap; typedef map > TElemOfNodeListMap; typedef map > TElemOfElemListMap; typedef map > TNodeOfNodeListMap; @@ -83,7 +82,7 @@ typedef TNodeOfNodeListMap::iterator TNodeOfNode typedef map > TElemOfVecOfNnlmiMap; //typedef map > TElemOfVecOfMapNodesMap; -typedef pair NLink; +typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink; //======================================================================= //function : SMESH_MeshEditor @@ -874,7 +873,7 @@ bool SMESH_MeshEditor::QuadToTri (map & theElems, } else { - // split qudratic quadrangle + // split quadratic quadrangle // get surface elem is on if ( aShapeId != helper.GetSubShapeID() ) { @@ -945,7 +944,7 @@ bool SMESH_MeshEditor::QuadToTri (map & theElems, } aMesh->ChangeElementNodes( elem, N, 6 ); - } // qudratic case + } // quadratic case // care of a new element @@ -4364,7 +4363,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) list& nodes = *grIt; list::iterator nIt = nodes.begin(); const SMDS_MeshNode* nToKeep = *nIt; - for ( ; nIt != nodes.end(); nIt++ ) { + for ( ++nIt; nIt != nodes.end(); nIt++ ) { const SMDS_MeshNode* nToRemove = *nIt; nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep )); if ( nToRemove != nToKeep ) { @@ -5064,17 +5063,17 @@ static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1, } //======================================================================= -//function : findFreeBorder +//function : FindFreeBorder //purpose : //======================================================================= #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge -static bool findFreeBorder (const SMDS_MeshNode* theFirstNode, - const SMDS_MeshNode* theSecondNode, - const SMDS_MeshNode* theLastNode, - list< const SMDS_MeshNode* > & theNodes, - list< const SMDS_MeshElement* > & theFaces) +bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode, + const SMDS_MeshNode* theSecondNode, + const SMDS_MeshNode* theLastNode, + list< const SMDS_MeshNode* > & theNodes, + list< const SMDS_MeshElement* >& theFaces) { if ( !theFirstNode || !theSecondNode ) return false; @@ -5173,7 +5172,7 @@ static bool findFreeBorder (const SMDS_MeshNode* theFirstNode, cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ]; cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ]; // find one more free border - if ( ! findFreeBorder( nIgnore, nStart, theLastNode, *cNL, *cFL )) { + if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) { cNL->clear(); cFL->clear(); } @@ -5217,7 +5216,7 @@ bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1, { list< const SMDS_MeshNode* > nodes; list< const SMDS_MeshElement* > faces; - return findFreeBorder( theNode1, theNode2, theNode3, nodes, faces); + return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces); } //======================================================================= @@ -5253,7 +5252,7 @@ SMESH_MeshEditor::Sew_Error // Free border 1 // -------------- - if (!findFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode, + if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode, nSide[0], eSide[0])) { MESSAGE(" Free Border 1 not found " ); aResult = SEW_BORDER1_NOT_FOUND; @@ -5261,7 +5260,7 @@ SMESH_MeshEditor::Sew_Error if (theSideIsFreeBorder) { // Free border 2 // -------------- - if (!findFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode, + if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode, nSide[1], eSide[1])) { MESSAGE(" Free Border 2 not found " ); aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND ); @@ -5366,11 +5365,12 @@ SMESH_MeshEditor::Sew_Error checkedLinkIDs.clear(); gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() ); - SMDS_ElemIteratorPtr invElemIt - = prevSideNode->GetInverseElementIterator(); - while ( invElemIt->more() ) { // loop on inverse elements on the Side 2 + // loop on inverse elements of current node (prevSideNode) on the Side 2 + SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator(); + while ( invElemIt->more() ) + { const SMDS_MeshElement* elem = invElemIt->next(); - // prepare data for a loop on links, of a face or a volume + // prepare data for a loop on links coming to prevSideNode, of a face or a volume int iPrevNode, iNode = 0, nbNodes = elem->NbNodes(); const SMDS_MeshNode* faceNodes[ nbNodes ]; bool isVolume = volume.Set( elem ); @@ -5421,7 +5421,8 @@ SMESH_MeshEditor::Sew_Error long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n ); bool isJustChecked = !checkedLinkIDs.insert( iLink ).second; if (!isJustChecked && - foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() ) { + foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() ) + { // test a link geometrically gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() ); bool linkIsBetter = false; @@ -5460,6 +5461,7 @@ SMESH_MeshEditor::Sew_Error // find the next border link to compare with gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() ); searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 ); + // move to next border node if sideNode is before forward border node (bordPos) while ( *nBordIt != theBordLastNode && !searchByDir ) { prevBordNode = *nBordIt; nBordIt++; @@ -6731,15 +6733,15 @@ SMESH_MeshEditor::Sew_Error set< long > linkIdSet; // links to process linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 )); - typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > TPairOfNodes; - list< TPairOfNodes > linkList[2]; - linkList[0].push_back( TPairOfNodes( theFirstNode1, theSecondNode1 )); - linkList[1].push_back( TPairOfNodes( theFirstNode2, theSecondNode2 )); + typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink; + list< NLink > linkList[2]; + linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 )); + linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 )); // loop on links in linkList; find faces by links and append links // of the found faces to linkList - list< TPairOfNodes >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ; + list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ; for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) { - TPairOfNodes link[] = { *linkIt[0], *linkIt[1] }; + NLink link[] = { *linkIt[0], *linkIt[1] }; long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second ); if ( linkIdSet.find( linkID ) == linkIdSet.end() ) continue; @@ -6946,8 +6948,8 @@ SMESH_MeshEditor::Sew_Error //const SMDS_MeshNode* n2 = nodes[ iNode + 1]; const SMDS_MeshNode* n1 = fnodes1[ iNode ]; const SMDS_MeshNode* n2 = fnodes1[ iNode + 1]; - linkList[0].push_back ( TPairOfNodes( n1, n2 )); - linkList[1].push_back ( TPairOfNodes( nReplaceMap[n1], nReplaceMap[n2] )); + linkList[0].push_back ( NLink( n1, n2 )); + linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] )); } } } // 2 faces found @@ -7010,3 +7012,187 @@ SMESH_MeshEditor::Sew_Error return aResult; } + +/*! + * \brief A sorted pair of nodes + */ +struct TLink: public NLink +{ + TLink(const SMDS_MeshNode* n1, const SMDS_MeshNode* n2 ):NLink( n1, n2 ) + { if ( n1 < n2 ) std::swap( first, second ); } + TLink(const NLink& link ):NLink( link ) + { if ( first < second ) std::swap( first, second ); } +}; + +//================================================================================ + /*! + * \brief Find corresponding nodes in two sets of faces + * \param theSide1 - first face set + * \param theSide2 - second first face + * \param theFirstNode1 - a boundary node of set 1 + * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1 + * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1 + * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1 + * \param nReplaceMap - output map of corresponding nodes + * \retval bool - is a success or not + */ +//================================================================================ + +//#define DEBUG_MATCHING_NODES + +SMESH_MeshEditor::Sew_Error +SMESH_MeshEditor::FindMatchingNodes(set& theSide1, + set& theSide2, + const SMDS_MeshNode* theFirstNode1, + const SMDS_MeshNode* theFirstNode2, + const SMDS_MeshNode* theSecondNode1, + const SMDS_MeshNode* theSecondNode2, + TNodeNodeMap & nReplaceMap) +{ + set * faceSetPtr[] = { &theSide1, &theSide2 }; + + nReplaceMap.clear(); + if ( theFirstNode1 != theFirstNode2 ) + nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 )); + if ( theSecondNode1 != theSecondNode2 ) + nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 )); + + set< TLink > linkSet; // set of nodes where order of nodes is ignored + linkSet.insert( TLink( theFirstNode1, theSecondNode1 )); + + list< NLink > linkList[2]; + linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 )); + linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 )); + + // loop on links in linkList; find faces by links and append links + // of the found faces to linkList + list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ; + for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) { + NLink link[] = { *linkIt[0], *linkIt[1] }; + if ( linkSet.find( link[0] ) == linkSet.end() ) + continue; + + // by links, find faces in the face sets, + // and find indices of link nodes in the found faces; + // in a face set, there is only one or no face sharing a link + // --------------------------------------------------------------- + + const SMDS_MeshElement* face[] = { 0, 0 }; + list notLinkNodes[2]; + //bool reverse[] = { false, false }; // order of notLinkNodes + int nbNodes[2]; + for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides + { + const SMDS_MeshNode* n1 = link[iSide].first; + const SMDS_MeshNode* n2 = link[iSide].second; + set * faceSet = faceSetPtr[ iSide ]; + set< const SMDS_MeshElement* > facesOfNode1; + for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link + { + // during a loop of the first node, we find all faces around n1, + // during a loop of the second node, we find one face sharing both n1 and n2 + const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link + SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(); + while ( fIt->more() ) { // loop on faces sharing a node + const SMDS_MeshElement* f = fIt->next(); + if (f->GetType() == SMDSAbs_Face && + faceSet->find( f ) != faceSet->end() && // f is in face set + ! facesOfNode1.insert( f ).second ) // f encounters twice + { + if ( face[ iSide ] ) { + MESSAGE( "2 faces per link " ); + return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES ); + } + face[ iSide ] = f; + faceSet->erase( f ); + + // get not link nodes + int nbN = f->NbNodes(); + if ( f->IsQuadratic() ) + nbN /= 2; + nbNodes[ iSide ] = nbN; + list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ]; + int i1 = f->GetNodeIndex( n1 ); + int i2 = f->GetNodeIndex( n2 ); + int iEnd = nbN, iBeg = -1, iDelta = 1; + bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 ); + if ( reverse ) { + std::swap( iEnd, iBeg ); iDelta = -1; + } + int i = i2; + while ( true ) { + i += iDelta; + if ( i == iEnd ) i = iBeg + iDelta; + if ( i == i1 ) break; + nodes.push_back ( f->GetNode( i ) ); + } + } + } + } + } + // check similarity of elements of the sides + if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) { + MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 )); + if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found + return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES ); + } + else { + return SEW_TOPO_DIFF_SETS_OF_ELEMENTS; + } + } + + // set nodes to merge + // ------------------- + + if ( face[0] && face[1] ) { + if ( nbNodes[0] != nbNodes[1] ) { + MESSAGE("Diff nb of face nodes"); + return SEW_TOPO_DIFF_SETS_OF_ELEMENTS; + } +#ifdef DEBUG_MATCHING_NODES + cout << " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID() + << " F 1: " << face[0]; + cout << "| Link 2: " << link[1].first->GetID() <<" "<< link[1].second->GetID() + << " F 2: " << face[1] << " | Bind: "<::iterator n1 = notLinkNodes[0].begin(); + list::iterator n2 = notLinkNodes[1].begin(); + for ( int i = 0 ; i < nbN - 2; ++i ) { +#ifdef DEBUG_MATCHING_NODES + cout << (*n1)->GetID() << " to " << (*n2)->GetID() << endl; +#endif + nReplaceMap.insert( make_pair( *(n1++), *(n2++) )); + } + } + + // add other links of the face 1 to linkList + // ----------------------------------------- + + const SMDS_MeshElement* f0 = face[0]; + const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 ); + for ( int i = 0; i < nbN; i++ ) + { + const SMDS_MeshNode* n2 = f0->GetNode( i ); + pair< set< TLink >::iterator, bool > iter_isnew = + linkSet.insert( TLink( n1, n2 )); + if ( !iter_isnew.second ) { // already in a set: no need to process + linkSet.erase( iter_isnew.first ); + } + else // new in set == encountered for the first time: add + { +#ifdef DEBUG_MATCHING_NODES + cout << "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "; + cout << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " << endl; +#endif + linkList[0].push_back ( NLink( n1, n2 )); + linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] )); + } + n1 = n2; + } + } // 2 faces found + } // loop on link lists + + return SEW_OK; +} diff --git a/src/SMESH/SMESH_MeshEditor.hxx b/src/SMESH/SMESH_MeshEditor.hxx index 3c891d1a3..c3edb03e1 100644 --- a/src/SMESH/SMESH_MeshEditor.hxx +++ b/src/SMESH/SMESH_MeshEditor.hxx @@ -37,17 +37,18 @@ #include "gp_Dir.hxx" #include "TColStd_HSequenceOfReal.hxx" #include "SMESH_MesherHelper.hxx" +#include "SMDS_MeshElement.hxx" #include #include typedef map > TElemOfElemListMap; +typedef map TNodeNodeMap; -typedef map RemoveQuadNodeMap; +typedef map RemoveQuadNodeMap; typedef map::iterator ItRemoveQuadNodeMap; -class SMDS_MeshElement; class SMDS_MeshFace; class SMDS_MeshNode; class gp_Ax1; @@ -64,6 +65,16 @@ public: { return e1->GetID() < e2->GetID(); } }; typedef set< const SMDS_MeshElement*, TIDCompare > TIDSortedElemSet; + + /*! + * \brief Insert element in a map of elements sorted by ID + * \param elem - element to insert + * \param elemMap - the map to fill in + */ + static void Insert(const SMDS_MeshElement* elem, + std::map & elemMap) { + elemMap.insert( make_pair( elem->GetID(), elem )); + } public: @@ -282,6 +293,13 @@ public: const SMDS_MeshNode* theNode3 = 0); // Return true if the three nodes are on a free border + static bool FindFreeBorder (const SMDS_MeshNode* theFirstNode, + const SMDS_MeshNode* theSecondNode, + const SMDS_MeshNode* theLastNode, + std::list< const SMDS_MeshNode* > & theNodes, + std::list< const SMDS_MeshElement* >& theFaces); + // Return nodes and faces of a free border if found + enum Sew_Error { SEW_OK, // for SewFreeBorder() @@ -294,7 +312,8 @@ public: SEW_DIFF_NB_OF_ELEMENTS, SEW_TOPO_DIFF_SETS_OF_ELEMENTS, SEW_BAD_SIDE1_NODES, - SEW_BAD_SIDE2_NODES + SEW_BAD_SIDE2_NODES, + SEW_INTERNAL_ERROR }; @@ -392,6 +411,25 @@ public: // - not in avoidSet, // - in elemSet provided that !elemSet.empty() + /*! + * \brief Find corresponding nodes in two sets of faces + * \param theSide1 - first face set + * \param theSide2 - second first face + * \param theFirstNode1 - a boundary node of set 1 + * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1 + * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1 + * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1 + * \param nReplaceMap - output map of corresponding nodes + * \retval Sew_Error - is a success or not + */ + static Sew_Error FindMatchingNodes(set& theSide1, + set& theSide2, + const SMDS_MeshNode* theFirstNode1, + const SMDS_MeshNode* theFirstNode2, + const SMDS_MeshNode* theSecondNode1, + const SMDS_MeshNode* theSecondNode2, + TNodeNodeMap & nReplaceMap); + /*! * \brief Returns true if given node is medium * \param n - node to check -- 2.39.2