X-Git-Url: http://git.salome-platform.org/gitweb/?p=modules%2Fsmesh.git;a=blobdiff_plain;f=src%2FSMESH%2FSMESH_MeshEditor.cxx;h=48c10820fcfa14520ac6ed91d9b081cf865bf2be;hp=c2584ba8676044a055e0a144796eb13171e4d3a4;hb=9150fb3db9f16daea68ed8b24447aaadc171b61e;hpb=95f31e3a95f3c9f5ab427af08a0634e78fd34494 diff --git a/src/SMESH/SMESH_MeshEditor.cxx b/src/SMESH/SMESH_MeshEditor.cxx index c2584ba86..48c10820f 100644 --- a/src/SMESH/SMESH_MeshEditor.cxx +++ b/src/SMESH/SMESH_MeshEditor.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE // // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS @@ -19,6 +19,7 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // + // SMESH SMESH : idl implementation based on 'SMESH' unit's classes // File : SMESH_MeshEditor.cxx // Created : Mon Apr 12 16:10:22 2004 @@ -34,31 +35,44 @@ #include "SMDS_SpacePosition.hxx" #include "SMDS_QuadraticFaceOfNodes.hxx" #include "SMDS_MeshGroup.hxx" +#include "SMDS_SetIterator.hxx" #include "SMESHDS_Group.hxx" #include "SMESHDS_Mesh.hxx" -#include "SMESH_subMesh.hxx" +#include "SMESH_Algo.hxx" #include "SMESH_ControlsDef.hxx" +#include "SMESH_Group.hxx" #include "SMESH_MesherHelper.hxx" #include "SMESH_OctreeNode.hxx" -#include "SMESH_Group.hxx" +#include "SMESH_subMesh.hxx" #include "utilities.h" +#include +#include #include #include #include +#include #include +#include #include +#include #include #include +#include #include +#include +#include +#include #include +#include #include #include #include #include +#include #include #include #include @@ -70,10 +84,13 @@ #include #include #include + #include #include #include +#include +#include #define cast2Node(elem) static_cast( elem ) @@ -82,13 +99,8 @@ using namespace SMESH::Controls; typedef map > TElemOfNodeListMap; typedef map > TElemOfElemListMap; -//typedef map > TNodeOfNodeVecMap; -//typedef TNodeOfNodeVecMap::iterator TNodeOfNodeVecMapItr; -//typedef map > TElemOfVecOfMapNodesMap; -struct TNodeXYZ : public gp_XYZ { - TNodeXYZ( const SMDS_MeshNode* n ):gp_XYZ( n->X(), n->Y(), n->Z() ) {} -}; +typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator; //======================================================================= //function : SMESH_MeshEditor @@ -116,14 +128,7 @@ SMESH_MeshEditor::AddElement(const vector & node, int nbnode = node.size(); SMESHDS_Mesh* mesh = GetMeshDS(); switch ( type ) { - case SMDSAbs_Edge: - if ( nbnode == 2 ) - if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID); - else e = mesh->AddEdge (node[0], node[1] ); - else if ( nbnode == 3 ) - if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID); - else e = mesh->AddEdge (node[0], node[1], node[2] ); - break; + case SMDSAbs_Face: if ( !isPoly ) { if (nbnode == 3) @@ -147,6 +152,7 @@ SMESH_MeshEditor::AddElement(const vector & node, else e = mesh->AddPolygonalFace (node ); } break; + case SMDSAbs_Volume: if ( !isPoly ) { if (nbnode == 4) @@ -204,7 +210,31 @@ SMESH_MeshEditor::AddElement(const vector & node, node[12],node[13],node[14],node[15], node[16],node[17],node[18],node[19] ); } + break; + + case SMDSAbs_Edge: + if ( nbnode == 2 ) + if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID); + else e = mesh->AddEdge (node[0], node[1] ); + else if ( nbnode == 3 ) + if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID); + else e = mesh->AddEdge (node[0], node[1], node[2] ); + break; + + case SMDSAbs_0DElement: + if ( nbnode == 1 ) + if ( ID ) e = mesh->Add0DElementWithID(node[0], ID); + else e = mesh->Add0DElement (node[0] ); + break; + + case SMDSAbs_Node: + if ( ID ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID); + else e = mesh->AddNode (node[0]->X(), node[0]->Y(), node[0]->Z()); + break; + + default:; } + if ( e ) myLastCreatedElems.Append( e ); return e; } @@ -237,8 +267,8 @@ SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector & nodeIDs // Modify a compute state of sub-meshes which become empty //======================================================================= -bool SMESH_MeshEditor::Remove (const list< int >& theIDs, - const bool isNodes ) +int SMESH_MeshEditor::Remove (const list< int >& theIDs, + const bool isNodes ) { myLastCreatedElems.Clear(); myLastCreatedNodes.Clear(); @@ -246,6 +276,7 @@ bool SMESH_MeshEditor::Remove (const list< int >& theIDs, SMESHDS_Mesh* aMesh = GetMeshDS(); set< SMESH_subMesh *> smmap; + int removed = 0; list::const_iterator it = theIDs.begin(); for ( ; it != theIDs.end(); it++ ) { const SMDS_MeshElement * elem; @@ -265,23 +296,24 @@ bool SMESH_MeshEditor::Remove (const list< int >& theIDs, smmap.insert( sm ); } // Find sub-meshes to notify about modification -// SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator(); -// while ( nodeIt->more() ) { -// const SMDS_MeshNode* node = static_cast( nodeIt->next() ); -// const SMDS_PositionPtr& aPosition = node->GetPosition(); -// if ( aPosition.get() ) { -// if ( int aShapeID = aPosition->GetShapeId() ) { -// if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) ) -// smmap.insert( sm ); -// } -// } -// } + // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator(); + // while ( nodeIt->more() ) { + // const SMDS_MeshNode* node = static_cast( nodeIt->next() ); + // const SMDS_PositionPtr& aPosition = node->GetPosition(); + // if ( aPosition.get() ) { + // if ( int aShapeID = aPosition->GetShapeId() ) { + // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) ) + // smmap.insert( sm ); + // } + // } + // } // Do remove if ( isNodes ) aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem )); else aMesh->RemoveElement( elem ); + removed++; } // Notify sub-meshes about modification @@ -291,11 +323,11 @@ bool SMESH_MeshEditor::Remove (const list< int >& theIDs, (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED ); } -// // Check if the whole mesh becomes empty -// if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) ) -// sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + // // Check if the whole mesh becomes empty + // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) ) + // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); - return true; + return removed; } //======================================================================= @@ -1102,6 +1134,7 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, //function : BestSplit //purpose : Find better diagonal for cutting. //======================================================================= + int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad, SMESH::Controls::NumericalFunctorPtr theCrit) { @@ -1143,6 +1176,542 @@ int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad, return -1; } +namespace +{ + // Methods of splitting volumes into tetra + + const int theHexTo5_1[5*4+1] = + { + 0, 1, 2, 5, 0, 4, 5, 7, 0, 2, 3, 7, 2, 5, 6, 7, 0, 5, 2, 7, -1 + }; + const int theHexTo5_2[5*4+1] = + { + 1, 2, 3, 6, 1, 4, 5, 6, 0, 1, 3, 4, 3, 4, 6, 7, 1, 3, 4, 6, -1 + }; + const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 }; + + const int theHexTo6_1[6*4+1] = + { + 1, 5, 6, 0, 0, 1, 2, 6, 0, 4, 5, 6, 0, 4, 6, 7, 0, 2, 3, 6, 0, 3, 7, 6, -1 + }; + const int theHexTo6_2[6*4+1] = + { + 2, 6, 7, 1, 1, 2, 3, 7, 1, 5, 6, 7, 1, 5, 7, 4, 1, 3, 0, 7, 1, 0, 4, 7, -1 + }; + const int theHexTo6_3[6*4+1] = + { + 3, 7, 4, 2, 2, 3, 0, 4, 2, 6, 7, 4, 2, 6, 4, 5, 2, 0, 1, 4, 2, 1, 5, 4, -1 + }; + const int theHexTo6_4[6*4+1] = + { + 0, 4, 5, 3, 3, 0, 1, 5, 3, 7, 4, 5, 3, 7, 5, 6, 3, 1, 2, 5, 3, 2, 6, 5, -1 + }; + const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 }; + + const int thePyraTo2_1[2*4+1] = + { + 0, 1, 2, 4, 0, 2, 3, 4, -1 + }; + const int thePyraTo2_2[2*4+1] = + { + 1, 2, 3, 4, 1, 3, 0, 4, -1 + }; + const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 }; + + const int thePentaTo3_1[3*4+1] = + { + 0, 1, 2, 3, 1, 3, 4, 2, 2, 3, 4, 5, -1 + }; + const int thePentaTo3_2[3*4+1] = + { + 1, 2, 0, 4, 2, 4, 5, 0, 0, 4, 5, 3, -1 + }; + const int thePentaTo3_3[3*4+1] = + { + 2, 0, 1, 5, 0, 5, 3, 1, 1, 5, 3, 4, -1 + }; + const int thePentaTo3_4[3*4+1] = + { + 0, 1, 2, 3, 1, 3, 4, 5, 2, 3, 1, 5, -1 + }; + const int thePentaTo3_5[3*4+1] = + { + 1, 2, 0, 4, 2, 4, 5, 3, 0, 4, 2, 3, -1 + }; + const int thePentaTo3_6[3*4+1] = + { + 2, 0, 1, 5, 0, 5, 3, 4, 1, 5, 0, 4, -1 + }; + const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3, + thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 }; + + struct TTriangleFacet //!< stores indices of three nodes of tetra facet + { + int _n1, _n2, _n3; + TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {} + bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); } + bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const; + }; + struct TSplitMethod + { + int _nbTetra; + const int* _connectivity; //!< foursomes of tetra connectivy finished by -1 + bool _baryNode; //!< additional node is to be created at cell barycenter + bool _ownConn; //!< to delete _connectivity in destructor + map _faceBaryNode; //!< map face index to node at BC of face + + TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false) + : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {} + ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; } + bool hasFacet( const TTriangleFacet& facet ) const + { + const int* tetConn = _connectivity; + for ( ; tetConn[0] >= 0; tetConn += 4 ) + if (( facet.contains( tetConn[0] ) + + facet.contains( tetConn[1] ) + + facet.contains( tetConn[2] ) + + facet.contains( tetConn[3] )) == 3 ) + return true; + return false; + } + }; + + //======================================================================= + /*! + * \brief return TSplitMethod for the given element + */ + //======================================================================= + + TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags) + { + const int iQ = vol.Element()->IsQuadratic() ? 2 : 1; + + // at HEXA_TO_24 method, each face of volume is split into triangles each based on + // an edge and a face barycenter; tertaherdons are based on triangles and + // a volume barycenter + const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 ); + + // Find out how adjacent volumes are split + + vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side + int hasAdjacentSplits = 0, maxTetConnSize = 0; + for ( int iF = 0; iF < vol.NbFaces(); ++iF ) + { + int nbNodes = vol.NbFaceNodes( iF ) / iQ; + maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2)); + if ( nbNodes < 4 ) continue; + + list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ]; + const int* nInd = vol.GetFaceNodesIndices( iF ); + if ( nbNodes == 4 ) + { + TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] ); + TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] ); + if ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 ); + else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 ); + } + else + { + int iCom = 0; // common node of triangle faces to split into + for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom ) + { + TTriangleFacet t012( nInd[ iQ * ( iCom )], + nInd[ iQ * ( (iCom+1)%nbNodes )], + nInd[ iQ * ( (iCom+2)%nbNodes )]); + TTriangleFacet t023( nInd[ iQ * ( iCom )], + nInd[ iQ * ( (iCom+2)%nbNodes )], + nInd[ iQ * ( (iCom+3)%nbNodes )]); + if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() )) + { + triaSplits.push_back( t012 ); + triaSplits.push_back( t023 ); + break; + } + } + } + if ( !triaSplits.empty() ) + hasAdjacentSplits = true; + } + + // Among variants of split method select one compliant with adjacent volumes + + TSplitMethod method; + if ( !vol.Element()->IsPoly() && !is24TetMode ) + { + int nbVariants = 2, nbTet = 0; + const int** connVariants = 0; + switch ( vol.Element()->GetEntityType() ) + { + case SMDSEntity_Hexa: + case SMDSEntity_Quad_Hexa: + if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 ) + connVariants = theHexTo5, nbTet = 5; + else + connVariants = theHexTo6, nbTet = 6, nbVariants = 4; + break; + case SMDSEntity_Pyramid: + case SMDSEntity_Quad_Pyramid: + connVariants = thePyraTo2; nbTet = 2; + break; + case SMDSEntity_Penta: + case SMDSEntity_Quad_Penta: + connVariants = thePentaTo3; nbTet = 3; nbVariants = 6; + break; + default: + nbVariants = 0; + } + for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant ) + { + // check method compliancy with adjacent tetras, + // all found splits must be among facets of tetras described by this method + method = TSplitMethod( nbTet, connVariants[variant] ); + if ( hasAdjacentSplits && method._nbTetra > 0 ) + { + bool facetCreated = true; + for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF ) + { + list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin(); + for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet ) + facetCreated = method.hasFacet( *facet ); + } + if ( !facetCreated ) + method = TSplitMethod(0); // incompatible method + } + } + } + if ( method._nbTetra < 1 ) + { + // No standard method is applicable, use a generic solution: + // each facet of a volume is split into triangles and + // each of triangles and a volume barycenter form a tetrahedron. + + int* connectivity = new int[ maxTetConnSize + 1 ]; + method._connectivity = connectivity; + method._ownConn = true; + method._baryNode = true; + + int connSize = 0; + int baryCenInd = vol.NbNodes(); + for ( int iF = 0; iF < vol.NbFaces(); ++iF ) + { + const int nbNodes = vol.NbFaceNodes( iF ) / iQ; + const int* nInd = vol.GetFaceNodesIndices( iF ); + // find common node of triangle facets of tetra to create + int iCommon = 0; // index in linear numeration + const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ]; + if ( !triaSplits.empty() ) + { + // by found facets + const TTriangleFacet* facet = &triaSplits.front(); + for ( ; iCommon < nbNodes-1 ; ++iCommon ) + if ( facet->contains( nInd[ iQ * iCommon ]) && + facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ])) + break; + } + else if ( nbNodes > 3 && !is24TetMode ) + { + // find the best method of splitting into triangles by aspect ratio + SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio); + map< double, int > badness2iCommon; + const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF ); + int nbVariants = ( nbNodes == 4 ? 2 : nbNodes ); + for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon ) + for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast ) + { + SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon )], + nodes[ iQ*((iLast-1)%nbNodes)], + nodes[ iQ*((iLast )%nbNodes)]); + double badness = getBadRate( &tria, aspectRatio ); + badness2iCommon.insert( make_pair( badness, iCommon )); + } + // use iCommon with lowest badness + iCommon = badness2iCommon.begin()->second; + } + if ( iCommon >= nbNodes ) + iCommon = 0; // something wrong + + // fill connectivity of tetrahedra based on a current face + int nbTet = nbNodes - 2; + if ( is24TetMode && nbNodes > 3 && triaSplits.empty()) + { + method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 )); + int faceBaryCenInd = baryCenInd + method._faceBaryNode.size(); + nbTet = nbNodes; + for ( int i = 0; i < nbTet; ++i ) + { + int i1 = i, i2 = (i+1) % nbNodes; + if ( !vol.IsFaceExternal( iF )) swap( i1, i2 ); + connectivity[ connSize++ ] = nInd[ iQ * i1 ]; + connectivity[ connSize++ ] = nInd[ iQ * i2 ]; + connectivity[ connSize++ ] = faceBaryCenInd; + connectivity[ connSize++ ] = baryCenInd; + } + } + else + { + for ( int i = 0; i < nbTet; ++i ) + { + int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes; + if ( !vol.IsFaceExternal( iF )) swap( i1, i2 ); + connectivity[ connSize++ ] = nInd[ iQ * iCommon ]; + connectivity[ connSize++ ] = nInd[ iQ * i1 ]; + connectivity[ connSize++ ] = nInd[ iQ * i2 ]; + connectivity[ connSize++ ] = baryCenInd; + } + } + method._nbTetra += nbTet; + } + connectivity[ connSize++ ] = -1; + } + return method; + } + //================================================================================ + /*! + * \brief Check if there is a tetraherdon adjacent to the given element via this facet + */ + //================================================================================ + + bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const + { + // find the tetrahedron including the three nodes of facet + const SMDS_MeshNode* n1 = elem->GetNode(_n1); + const SMDS_MeshNode* n2 = elem->GetNode(_n2); + const SMDS_MeshNode* n3 = elem->GetNode(_n3); + SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume); + while ( volIt1->more() ) + { + const SMDS_MeshElement* v = volIt1->next(); + if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra )) + continue; + SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume); + while ( volIt2->more() ) + if ( v != volIt2->next() ) + continue; + SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume); + while ( volIt3->more() ) + if ( v == volIt3->next() ) + return true; + } + return false; + } + + //======================================================================= + /*! + * \brief A key of a face of volume + */ + //======================================================================= + + struct TVolumeFaceKey: pair< int, pair< int, int> > + { + TVolumeFaceKey( SMDS_VolumeTool& vol, int iF ) + { + TIDSortedNodeSet sortedNodes; + const int iQ = vol.Element()->IsQuadratic() ? 2 : 1; + int nbNodes = vol.NbFaceNodes( iF ); + const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF ); + for ( int i = 0; i < nbNodes; i += iQ ) + sortedNodes.insert( fNodes[i] ); + TIDSortedNodeSet::iterator n = sortedNodes.begin(); + first = (*(n++))->GetID(); + second.first = (*(n++))->GetID(); + second.second = (*(n++))->GetID(); + } + }; +} // namespace + +//======================================================================= +//function : SplitVolumesIntoTetra +//purpose : Split volumic elements into tetrahedra. +//======================================================================= + +void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, + const int theMethodFlags) +{ + // std-like iterator on coordinates of nodes of mesh element + typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator; + NXyzIterator xyzEnd; + + SMDS_VolumeTool volTool; + SMESH_MesherHelper helper( *GetMesh()); + + SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1); + SMESHDS_SubMesh* fSubMesh = subMesh; + + SMESH_SequenceOfElemPtr newNodes, newElems; + + // map face of volume to it's baricenrtic node + map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode; + double bc[3]; + + TIDSortedElemSet::const_iterator elem = theElems.begin(); + for ( ; elem != theElems.end(); ++elem ) + { + SMDSAbs_EntityType geomType = (*elem)->GetEntityType(); + if ( geomType <= SMDSEntity_Quad_Tetra ) + continue; // tetra or face or ... + + if ( !volTool.Set( *elem )) continue; // not volume? strange... + + TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags ); + if ( splitMethod._nbTetra < 1 ) continue; + + // find submesh to add new tetras to + if ( !subMesh || !subMesh->Contains( *elem )) + { + int shapeID = FindShape( *elem ); + helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh + subMesh = GetMeshDS()->MeshElements( shapeID ); + } + int iQ; + if ( (*elem)->IsQuadratic() ) + { + iQ = 2; + // add quadratic links to the helper + for ( int iF = 0; iF < volTool.NbFaces(); ++iF ) + { + const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF ); + for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ ) + helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] ); + } + helper.SetIsQuadratic( true ); + } + else + { + iQ = 1; + helper.SetIsQuadratic( false ); + } + vector nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() ); + if ( splitMethod._baryNode ) + { + // make a node at barycenter + volTool.GetBaryCenter( bc[0], bc[1], bc[2] ); + SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] ); + nodes.push_back( gcNode ); + newNodes.Append( gcNode ); + } + if ( !splitMethod._faceBaryNode.empty() ) + { + // make or find baricentric nodes of faces + map::iterator iF_n = splitMethod._faceBaryNode.begin(); + for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n ) + { + map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n = + volFace2BaryNode.insert + ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first; + if ( !f_n->second ) + { + volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] ); + newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] )); + } + nodes.push_back( iF_n->second = f_n->second ); + } + } + + // make tetras + helper.SetElementsOnShape( true ); + vector tetras( splitMethod._nbTetra ); // splits of a volume + const int* tetConn = splitMethod._connectivity; + for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 ) + newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ], + nodes[ tetConn[1] ], + nodes[ tetConn[2] ], + nodes[ tetConn[3] ])); + + ReplaceElemInGroups( *elem, tetras, GetMeshDS() ); + + // Split faces on sides of the split volume + + const SMDS_MeshNode** volNodes = volTool.GetNodes(); + for ( int iF = 0; iF < volTool.NbFaces(); ++iF ) + { + const int nbNodes = volTool.NbFaceNodes( iF ) / iQ; + if ( nbNodes < 4 ) continue; + + // find an existing face + vector fNodes( volTool.GetFaceNodes( iF ), + volTool.GetFaceNodes( iF ) + nbNodes*iQ ); + while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes )) + { + // make triangles + helper.SetElementsOnShape( false ); + vector< const SMDS_MeshElement* > triangles; + + map::iterator iF_n = splitMethod._faceBaryNode.find(iF); + if ( iF_n != splitMethod._faceBaryNode.end() ) + { + for ( int iN = 0; iN < nbNodes*iQ; iN += iQ ) + { + const SMDS_MeshNode* n1 = fNodes[iN]; + const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ]; + const SMDS_MeshNode *n3 = iF_n->second; + if ( !volTool.IsFaceExternal( iF )) + swap( n2, n3 ); + triangles.push_back( helper.AddFace( n1,n2,n3 )); + } + } + else + { + // among possible triangles create ones discribed by split method + const int* nInd = volTool.GetFaceNodesIndices( iF ); + int nbVariants = ( nbNodes == 4 ? 2 : nbNodes ); + int iCom = 0; // common node of triangle faces to split into + list< TTriangleFacet > facets; + for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom ) + { + TTriangleFacet t012( nInd[ iQ * ( iCom )], + nInd[ iQ * ( (iCom+1)%nbNodes )], + nInd[ iQ * ( (iCom+2)%nbNodes )]); + TTriangleFacet t023( nInd[ iQ * ( iCom )], + nInd[ iQ * ( (iCom+2)%nbNodes )], + nInd[ iQ * ( (iCom+3)%nbNodes )]); + if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 )) + { + facets.push_back( t012 ); + facets.push_back( t023 ); + for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast ) + facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom )], + nInd[ iQ * ((iLast-1)%nbNodes )], + nInd[ iQ * ((iLast )%nbNodes )])); + break; + } + } + list< TTriangleFacet >::iterator facet = facets.begin(); + for ( ; facet != facets.end(); ++facet ) + { + if ( !volTool.IsFaceExternal( iF )) + swap( facet->_n2, facet->_n3 ); + triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ], + volNodes[ facet->_n2 ], + volNodes[ facet->_n3 ])); + } + } + // find submesh to add new triangles in + if ( !fSubMesh || !fSubMesh->Contains( face )) + { + int shapeID = FindShape( face ); + fSubMesh = GetMeshDS()->MeshElements( shapeID ); + } + for ( int i = 0; i < triangles.size(); ++i ) + { + if ( !triangles.back() ) continue; + if ( fSubMesh ) + fSubMesh->AddElement( triangles.back()); + newElems.Append( triangles.back() ); + } + ReplaceElemInGroups( face, triangles, GetMeshDS() ); + GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false ); + } + + } // loop on volume faces to split them into triangles + + GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false ); + + } // loop on volumes to split + + myLastCreatedNodes = newNodes; + myLastCreatedElems = newElems; +} + //======================================================================= //function : AddToSameGroups //purpose : add elemToAdd to the groups the elemInGroups belongs to @@ -1184,10 +1753,11 @@ void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem, } } -//======================================================================= -//function : ReplaceElemInGroups -//purpose : replace elemToRm by elemToAdd in the all groups -//======================================================================= +//================================================================================ +/*! + * \brief Replace elemToRm by elemToAdd in the all groups + */ +//================================================================================ void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm, const SMDS_MeshElement* elemToAdd, @@ -1204,6 +1774,29 @@ void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm, } } +//================================================================================ +/*! + * \brief Replace elemToRm by elemToAdd in the all groups + */ +//================================================================================ + +void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm, + const vector& elemToAdd, + SMESHDS_Mesh * aMesh) +{ + const set& groups = aMesh->GetGroups(); + if (!groups.empty()) + { + set::const_iterator grIt = groups.begin(); + for ( ; grIt != groups.end(); grIt++ ) { + SMESHDS_Group* group = dynamic_cast( *grIt ); + if ( group && group->SMDSGroup().Remove( elemToRm ) ) + for ( int i = 0; i < elemToAdd.size(); ++i ) + group->SMDSGroup().Add( elemToAdd[ i ] ); + } + } +} + //======================================================================= //function : QuadToTri //purpose : Cut quadrangles into triangles. @@ -1407,7 +2000,7 @@ double getAngle(const SMDS_MeshElement * tr1, // and able to return nodes by that ID // ================================================= class LinkID_Gen { - public: +public: LinkID_Gen( const SMESHDS_Mesh* theMesh ) :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1) @@ -1430,7 +2023,7 @@ class LinkID_Gen { return true; } - private: +private: LinkID_Gen(); const SMESHDS_Mesh* myMesh; long myMaxID; @@ -1739,15 +2332,15 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems, //============================================================================= static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] ) { - if ( i1 == i2 ) - return; - int tmp = idNodes[ i1 ]; - idNodes[ i1 ] = idNodes[ i2 ]; - idNodes[ i2 ] = tmp; - gp_Pnt Ptmp = P[ i1 ]; - P[ i1 ] = P[ i2 ]; - P[ i2 ] = Ptmp; - DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")"); +if ( i1 == i2 ) +return; +int tmp = idNodes[ i1 ]; +idNodes[ i1 ] = idNodes[ i2 ]; +idNodes[ i2 ] = tmp; +gp_Pnt Ptmp = P[ i1 ]; +P[ i1 ] = P[ i2 ]; +P[ i2 ] = Ptmp; +DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")"); } //======================================================================= @@ -1758,7 +2351,7 @@ static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] ) //======================================================================= int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh, - int idNodes[] ) +int idNodes[] ) { gp_Pnt P[4]; int i; @@ -1787,10 +2380,10 @@ int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh, i = 1; swap ( i, i + 1, idNodes, P ); -// for ( int ii = 0; ii < 4; ii++ ) { -// const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] ); -// DUMPSO( ii << "(" << idNodes[ii] <<") : "<X()<<" "<Y()<<" "<Z()); -// } + // for ( int ii = 0; ii < 4; ii++ ) { + // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] ); + // DUMPSO( ii << "(" << idNodes[ii] <<") : "<X()<<" "<Y()<<" "<Z()); + // } } return i; } @@ -1906,7 +2499,7 @@ bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh, faceNodes.insert( idNodes[ 2 ] ); faceNodes.insert( idNodes[ iMin ] ); DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ] - << " leastDist = " << leastDist); + << " leastDist = " << leastDist); if ( leastDist <= DBL_MIN ) break; } @@ -1944,11 +2537,11 @@ bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh, P[ i ] = P[ i+1 ]; P[ i+1 ] = Ptmp; } -// else -// for ( int ii = 0; ii < 4; ii++ ) { -// const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] ); -// DUMPSO( ii << "(" << idNodes[ii] <<") : "<X()<<" "<Y()<<" "<Z()); -// } + // else + // for ( int ii = 0; ii < 4; ii++ ) { + // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] ); + // DUMPSO( ii << "(" << idNodes[ii] <<") : "<X()<<" "<Y()<<" "<Z()); + // } // Gravity center of the top and bottom faces gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.; @@ -2000,11 +2593,11 @@ bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh, swap( 5, 7, idNodes, P ); } -// DUMPSO( "OUTPUT: ========================================"); -// for ( i = 0; i < 8; i++ ) { -// float *p = ugrid->GetPoint(idNodes[i]); -// DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]); -// } + // DUMPSO( "OUTPUT: ========================================"); + // for ( i = 0; i < 8; i++ ) { + // float *p = ugrid->GetPoint(idNodes[i]); + // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]); + // } return true; }*/ @@ -2012,11 +2605,11 @@ bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh, //================================================================================ /*! * \brief Return nodes linked to the given one - * \param theNode - the node - * \param linkedNodes - the found nodes - * \param type - the type of elements to check - * - * Medium nodes are ignored + * \param theNode - the node + * \param linkedNodes - the found nodes + * \param type - the type of elements to check + * + * Medium nodes are ignored */ //================================================================================ @@ -2050,8 +2643,8 @@ void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode, iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb ); iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb ); } - linkedNodes.insert( elem->GetNode( iAfter )); - linkedNodes.insert( elem->GetNode( iBefore )); + linkedNodes.insert( elem->GetNodeWrap( iAfter )); + linkedNodes.insert( elem->GetNodeWrap( iBefore )); } } } @@ -2296,14 +2889,14 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, } int nbElemOnFace = 0; itElem = theElems.begin(); - // loop on not yet smoothed elements: look for elems on a face + // loop on not yet smoothed elements: look for elems on a face while ( itElem != theElems.end() ) { if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() ) break; // all elements found const SMDS_MeshElement* elem = *itElem; if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 || - ( faceSubMesh && !faceSubMesh->Contains( elem ))) { + ( faceSubMesh && !faceSubMesh->Contains( elem ))) { ++itElem; continue; } @@ -2362,19 +2955,19 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, if ( uvMap.find( node ) == uvMap.end() ) uvCheckNodes.push_back( node ); // add nodes of elems sharing node -// SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face); -// while ( eIt->more() ) { -// const SMDS_MeshElement* e = eIt->next(); -// if ( e != elem ) { -// SMDS_ElemIteratorPtr nIt = e->nodesIterator(); -// while ( nIt->more() ) { -// const SMDS_MeshNode* n = -// static_cast( nIt->next() ); -// if ( uvMap.find( n ) == uvMap.end() ) -// uvCheckNodes.push_back( n ); -// } -// } -// } + // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face); + // while ( eIt->more() ) { + // const SMDS_MeshElement* e = eIt->next(); + // if ( e != elem ) { + // SMDS_ElemIteratorPtr nIt = e->nodesIterator(); + // while ( nIt->more() ) { + // const SMDS_MeshNode* n = + // static_cast( nIt->next() ); + // if ( uvMap.find( n ) == uvMap.end() ) + // uvCheckNodes.push_back( n ); + // } + // } + // } } // check UV on face list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin(); @@ -2456,7 +3049,7 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, if(elem->IsQuadratic()) nbn = nbn/2; // loop on elem links: insert them in linkNbMap - const SMDS_MeshNode* curNode, *prevNode = elem->GetNode( nbn ); + const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn ); for ( int iN = 0; iN < nbn; ++iN ) { curNode = elem->GetNode( iN ); NLink link; @@ -2780,47 +3373,51 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ]; const SMDS_MeshNode* node = nnIt->first; const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second; - if ( listNewNodes.empty() ) + if ( listNewNodes.empty() ) { return; + } - issimple[iNode] = (listNewNodes.size()==nbSteps); + issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium itNN[ iNode ] = listNewNodes.begin(); prevNod[ iNode ] = node; nextNod[ iNode ] = listNewNodes.front(); -//cout<<"iNode="<GetID() ); + //INFOS( " Too many same nodes of element " << elem->GetID() ); return; } -// if( elem->IsQuadratic() && nbSame>0 ) { -// MESSAGE( "Can not rotate quadratic element " << elem->GetID() ); -// return; -// } + // if( elem->IsQuadratic() && nbSame>0 ) { + // MESSAGE( "Can not rotate quadratic element " << elem->GetID() ); + // return; + // } int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0; + int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes ); if ( nbSame > 0 ) { - iBeforeSame = ( iSameNode == 0 ? nbNodes - 1 : iSameNode - 1 ); - iAfterSame = ( iSameNode + 1 == nbNodes ? 0 : iSameNode + 1 ); + iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 ); + iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 ); iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 ); } -//if(nbNodes==8) -//cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1] -// <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4] -// <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5] -// <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<GetID() << " can not be created" ); + return; + } + else if(nbSame==2) { + // 2d order Pentahedron with 15 nodes + //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6, + // int n12,int n23,int n31,int n45,int n56,int n64, + // int n14,int n25,int n36, int ID); + int n1,n2,n4,n5; + if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) { + // iBeforeSame is same too + n1 = iBeforeSame; + n2 = iOpposSame; + n4 = iSameNode; + n5 = iAfterSame; + } + else { + // iAfterSame is same too + n1 = iSameNode; + n2 = iBeforeSame; + n4 = iAfterSame; + n5 = iOpposSame; + } + int n12,n45,n14,n25; + if(i0>0) { //reversed case + n12 = n1 + 4; + n45 = n5 + 4; + n14 = n4 + 4; + n25 = n2 + 4; + } + else { + n12 = n2 + 4; + n45 = n4 + 4; + n14 = n1 + 4; + n25 = n5 + 4; + } + aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2], + prevNod[n4], prevNod[n5], nextNod[n5], + prevNod[n12], midlNod[n2], nextNod[n12], + prevNod[n45], midlNod[n5], nextNod[n45], + prevNod[n14], prevNod[n25], nextNod[n25]); } break; } @@ -3276,7 +3977,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]); if ( !f ) myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] )); - else if ( nodes[ 1 ] != f->GetNode( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) + else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) aMesh->ChangeElementNodes( f, nodes, nbn ); break; } @@ -3284,7 +3985,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]); if ( !f ) myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] )); - else if ( nodes[ 1 ] != f->GetNode( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) + else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) aMesh->ChangeElementNodes( f, nodes, nbn ); break; } @@ -3293,20 +3994,40 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, if(nbn==6) { /////// quadratic triangle const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5] ); - if ( !f ) + if ( !f ) { myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5])); - else if ( nodes[ 2 ] != f->GetNode( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) - aMesh->ChangeElementNodes( f, nodes, nbn ); + } + else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) { + const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6]; + tmpnodes[0] = nodes[0]; + tmpnodes[1] = nodes[2]; + tmpnodes[2] = nodes[4]; + tmpnodes[3] = nodes[1]; + tmpnodes[4] = nodes[3]; + tmpnodes[5] = nodes[5]; + aMesh->ChangeElementNodes( f, tmpnodes, nbn ); + } } else { /////// quadratic quadrangle const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6], nodes[1], nodes[3], nodes[5], nodes[7] ); - if ( !f ) + if ( !f ) { myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6], nodes[1], nodes[3], nodes[5], nodes[7])); - else if ( nodes[ 2 ] != f->GetNode( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) - aMesh->ChangeElementNodes( f, nodes, nbn ); + } + else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) { + const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8]; + tmpnodes[0] = nodes[0]; + tmpnodes[1] = nodes[2]; + tmpnodes[2] = nodes[4]; + tmpnodes[3] = nodes[6]; + tmpnodes[4] = nodes[1]; + tmpnodes[5] = nodes[3]; + tmpnodes[6] = nodes[5]; + tmpnodes[7] = nodes[7]; + aMesh->ChangeElementNodes( f, tmpnodes, nbn ); + } } } else { //////// polygon @@ -3314,7 +4035,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes ); if ( !f ) myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes)); - else if ( nodes[ 1 ] != f->GetNode( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) + else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) aMesh->ChangeElementNodes( f, nodes, nbn ); } } @@ -3427,20 +4148,25 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems, // loop on elem nodes SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) - { + while ( itN->more() ) { // check if a node has been already sweeped const SMDS_MeshNode* node = cast2Node( itN->next() ); + + gp_XYZ aXYZ( node->X(), node->Y(), node->Z() ); + double coord[3]; + aXYZ.Coord( coord[0], coord[1], coord[2] ); + bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol ); + TNodeOfNodeListMapItr nIt = mapNewNodes.find( node ); if ( nIt == mapNewNodes.end() ) { nIt = mapNewNodes.insert( make_pair( node, list() )).first; list& listNewNodes = nIt->second; // make new nodes - gp_XYZ aXYZ( node->X(), node->Y(), node->Z() ); - double coord[3]; - aXYZ.Coord( coord[0], coord[1], coord[2] ); - bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol ); + //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() ); + //double coord[3]; + //aXYZ.Coord( coord[0], coord[1], coord[2] ); + //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol ); const SMDS_MeshNode * newNode = node; for ( int i = 0; i < theNbSteps; i++ ) { if ( !isOnAxis ) { @@ -3461,37 +4187,52 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems, newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); myLastCreatedNodes.Append(newNode); srcNodes.Append( node ); + listNewNodes.push_back( newNode ); + } + else { + listNewNodes.push_back( newNode ); + if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) { + listNewNodes.push_back( newNode ); + } } - listNewNodes.push_back( newNode ); } } - else { + /* + else { // if current elem is quadratic and current node is not medium // we have to check - may be it is needed to insert additional nodes if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) { - list< const SMDS_MeshNode* > & listNewNodes = nIt->second; - if(listNewNodes.size()==theNbSteps) { - listNewNodes.clear(); - // make new nodes - gp_XYZ aXYZ( node->X(), node->Y(), node->Z() ); - double coord[3]; - aXYZ.Coord( coord[0], coord[1], coord[2] ); - const SMDS_MeshNode * newNode = node; - for(int i = 0; iAddNode( coord[0], coord[1], coord[2] ); - myLastCreatedNodes.Append(newNode); - listNewNodes.push_back( newNode ); - srcNodes.Append( node ); - aTrsf2.Transforms( coord[0], coord[1], coord[2] ); - newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - listNewNodes.push_back( newNode ); - } - } + list< const SMDS_MeshNode* > & listNewNodes = nIt->second; + if(listNewNodes.size()==theNbSteps) { + listNewNodes.clear(); + // make new nodes + //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() ); + //double coord[3]; + //aXYZ.Coord( coord[0], coord[1], coord[2] ); + const SMDS_MeshNode * newNode = node; + if ( !isOnAxis ) { + for(int i = 0; iAddNode( coord[0], coord[1], coord[2] ); + cout<<" 3 AddNode: "<AddNode( coord[0], coord[1], coord[2] ); + cout<<" 4 AddNode: "<& theAngles, - const bool theHasRefPoint, - const gp_Pnt& theRefPoint, - const bool theMakeGroups) +SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, + SMESH_subMesh* theTrack, + const SMDS_MeshNode* theN1, + const bool theHasAngles, + list& theAngles, + const bool theLinearVariation, + const bool theHasRefPoint, + const gp_Pnt& theRefPoint, + const bool theMakeGroups) { myLastCreatedElems.Clear(); myLastCreatedNodes.Clear(); - // source elements for each generated one - SMESH_SequenceOfElemPtr srcElems, srcNodes; - - int j, aNbTP, aNbE, aNb; - double aT1, aT2, aT, aAngle, aX, aY, aZ; + int aNbE; std::list aPrms; - std::list::iterator aItD; TIDSortedElemSet::iterator itElem; - Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2; - gp_Pnt aP3D, aV0; - gp_Vec aVec; gp_XYZ aGC; - Handle(Geom_Curve) aC3D; TopoDS_Edge aTrackEdge; TopoDS_Vertex aV1, aV2; @@ -3816,11 +4550,6 @@ SMESH_MeshEditor::Extrusion_Error SMDSAbs_ElementType aTypeE; TNodeOfNodeListMap mapNewNodes; - TElemOfVecOfNnlmiMap mapElemNewNodes; - TElemOfElemListMap newElemsMap; - - aTolVec=1.e-7; - aTolVec2=aTolVec*aTolVec; // 1. Check data aNbE = theElements.size(); @@ -3831,7 +4560,7 @@ SMESH_MeshEditor::Extrusion_Error // 1.1 Track Pattern ASSERT( theTrack ); - SMESHDS_SubMesh* pSubMeshDS=theTrack->GetSubMeshDS(); + SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS(); aItE = pSubMeshDS->GetElements(); while ( aItE->more() ) { @@ -3842,63 +4571,327 @@ SMESH_MeshEditor::Extrusion_Error return EXTR_PATH_NOT_EDGE; } + list fullList; + const TopoDS_Shape& aS = theTrack->GetSubShape(); - // Sub shape for the Pattern must be an Edge - if ( aS.ShapeType() != TopAbs_EDGE ) + // Sub shape for the Pattern must be an Edge or Wire + if( aS.ShapeType() == TopAbs_EDGE ) { + aTrackEdge = TopoDS::Edge( aS ); + // the Edge must not be degenerated + if ( BRep_Tool::Degenerated( aTrackEdge ) ) + return EXTR_BAD_PATH_SHAPE; + TopExp::Vertices( aTrackEdge, aV1, aV2 ); + aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes(); + const SMDS_MeshNode* aN1 = aItN->next(); + aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes(); + const SMDS_MeshNode* aN2 = aItN->next(); + // starting node must be aN1 or aN2 + if ( !( aN1 == theN1 || aN2 == theN1 ) ) + return EXTR_BAD_STARTING_NODE; + aItN = pSubMeshDS->GetNodes(); + while ( aItN->more() ) { + const SMDS_MeshNode* pNode = aItN->next(); + const SMDS_EdgePosition* pEPos = + static_cast( pNode->GetPosition().get() ); + double aT = pEPos->GetUParameter(); + aPrms.push_back( aT ); + } + //Extrusion_Error err = + MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList); + } + else if( aS.ShapeType() == TopAbs_WIRE ) { + list< SMESH_subMesh* > LSM; + TopTools_SequenceOfShape Edges; + SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true); + while(itSM->more()) { + SMESH_subMesh* SM = itSM->next(); + LSM.push_back(SM); + const TopoDS_Shape& aS = SM->GetSubShape(); + Edges.Append(aS); + } + list< list > LLPPs; + int startNid = theN1->GetID(); + TColStd_MapOfInteger UsedNums; + int NbEdges = Edges.Length(); + int i = 1; + for(; i<=NbEdges; i++) { + int k = 0; + list< SMESH_subMesh* >::iterator itLSM = LSM.begin(); + for(; itLSM!=LSM.end(); itLSM++) { + k++; + if(UsedNums.Contains(k)) continue; + aTrackEdge = TopoDS::Edge( Edges.Value(k) ); + SMESH_subMesh* locTrack = *itLSM; + SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS(); + TopExp::Vertices( aTrackEdge, aV1, aV2 ); + aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes(); + const SMDS_MeshNode* aN1 = aItN->next(); + aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes(); + const SMDS_MeshNode* aN2 = aItN->next(); + // starting node must be aN1 or aN2 + if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue; + // 2. Collect parameters on the track edge + aPrms.clear(); + aItN = locMeshDS->GetNodes(); + while ( aItN->more() ) { + const SMDS_MeshNode* pNode = aItN->next(); + const SMDS_EdgePosition* pEPos = + static_cast( pNode->GetPosition().get() ); + double aT = pEPos->GetUParameter(); + aPrms.push_back( aT ); + } + list LPP; + //Extrusion_Error err = + MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP); + LLPPs.push_back(LPP); + UsedNums.Add(k); + // update startN for search following egde + if( aN1->GetID() == startNid ) startNid = aN2->GetID(); + else startNid = aN1->GetID(); + break; + } + } + list< list >::iterator itLLPP = LLPPs.begin(); + list firstList = *itLLPP; + list::iterator itPP = firstList.begin(); + for(; itPP!=firstList.end(); itPP++) { + fullList.push_back( *itPP ); + } + SMESH_MeshEditor_PathPoint PP1 = fullList.back(); + fullList.pop_back(); + itLLPP++; + for(; itLLPP!=LLPPs.end(); itLLPP++) { + list currList = *itLLPP; + itPP = currList.begin(); + SMESH_MeshEditor_PathPoint PP2 = currList.front(); + gp_Dir D1 = PP1.Tangent(); + gp_Dir D2 = PP2.Tangent(); + gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2, + (D1.Z()+D2.Z())/2 ) ); + PP1.SetTangent(Dnew); + fullList.push_back(PP1); + itPP++; + for(; itPP!=firstList.end(); itPP++) { + fullList.push_back( *itPP ); + } + PP1 = fullList.back(); + fullList.pop_back(); + } + // if wire not closed + fullList.push_back(PP1); + // else ??? + } + else { return EXTR_BAD_PATH_SHAPE; + } - aTrackEdge = TopoDS::Edge( aS ); - // the Edge must not be degenerated - if ( BRep_Tool::Degenerated( aTrackEdge ) ) - return EXTR_BAD_PATH_SHAPE; + return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation, + theHasRefPoint, theRefPoint, theMakeGroups); +} - TopExp::Vertices( aTrackEdge, aV1, aV2 ); - aT1=BRep_Tool::Parameter( aV1, aTrackEdge ); - aT2=BRep_Tool::Parameter( aV2, aTrackEdge ); - aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes(); - const SMDS_MeshNode* aN1 = aItN->next(); +//======================================================================= +//function : ExtrusionAlongTrack +//purpose : +//======================================================================= +SMESH_MeshEditor::Extrusion_Error +SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, + SMESH_Mesh* theTrack, + const SMDS_MeshNode* theN1, + const bool theHasAngles, + list& theAngles, + const bool theLinearVariation, + const bool theHasRefPoint, + const gp_Pnt& theRefPoint, + const bool theMakeGroups) +{ + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + + int aNbE; + std::list aPrms; + TIDSortedElemSet::iterator itElem; + + gp_XYZ aGC; + TopoDS_Edge aTrackEdge; + TopoDS_Vertex aV1, aV2; + + SMDS_ElemIteratorPtr aItE; + SMDS_NodeIteratorPtr aItN; + SMDSAbs_ElementType aTypeE; - aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes(); - const SMDS_MeshNode* aN2 = aItN->next(); + TNodeOfNodeListMap mapNewNodes; - // starting node must be aN1 or aN2 - if ( !( aN1 == theN1 || aN2 == theN1 ) ) - return EXTR_BAD_STARTING_NODE; + // 1. Check data + aNbE = theElements.size(); + // nothing to do + if ( !aNbE ) + return EXTR_NO_ELEMENTS; - aNbTP = pSubMeshDS->NbNodes() + 2; + // 1.1 Track Pattern + ASSERT( theTrack ); - // 1.2. Angles - vector aAngles( aNbTP ); + SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS(); - for ( j=0; j < aNbTP; ++j ) { - aAngles[j] = 0.; + aItE = pMeshDS->elementsIterator(); + while ( aItE->more() ) { + const SMDS_MeshElement* pE = aItE->next(); + aTypeE = pE->GetType(); + // Pattern must contain links only + if ( aTypeE != SMDSAbs_Edge ) + return EXTR_PATH_NOT_EDGE; } - if ( theHasAngles ) { - aItD = theAngles.begin(); - for ( j=1; (aItD != theAngles.end()) && (j fullList; + + const TopoDS_Shape& aS = theTrack->GetShapeToMesh(); + // Sub shape for the Pattern must be an Edge or Wire + if( aS.ShapeType() == TopAbs_EDGE ) { + aTrackEdge = TopoDS::Edge( aS ); + // the Edge must not be degenerated + if ( BRep_Tool::Degenerated( aTrackEdge ) ) + return EXTR_BAD_PATH_SHAPE; + TopExp::Vertices( aTrackEdge, aV1, aV2 ); + aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes(); + const SMDS_MeshNode* aN1 = aItN->next(); + aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes(); + const SMDS_MeshNode* aN2 = aItN->next(); + // starting node must be aN1 or aN2 + if ( !( aN1 == theN1 || aN2 == theN1 ) ) + return EXTR_BAD_STARTING_NODE; + aItN = pMeshDS->nodesIterator(); + while ( aItN->more() ) { + const SMDS_MeshNode* pNode = aItN->next(); + if( pNode==aN1 || pNode==aN2 ) continue; + const SMDS_EdgePosition* pEPos = + static_cast( pNode->GetPosition().get() ); + double aT = pEPos->GetUParameter(); + aPrms.push_back( aT ); + } + //Extrusion_Error err = + MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList); + } + else if( aS.ShapeType() == TopAbs_WIRE ) { + list< SMESH_subMesh* > LSM; + TopTools_SequenceOfShape Edges; + TopExp_Explorer eExp(aS, TopAbs_EDGE); + for(; eExp.More(); eExp.Next()) { + TopoDS_Edge E = TopoDS::Edge( eExp.Current() ); + if( BRep_Tool::Degenerated(E) ) continue; + SMESH_subMesh* SM = theTrack->GetSubMesh(E); + if(SM) { + LSM.push_back(SM); + Edges.Append(E); + } + } + list< list > LLPPs; + int startNid = theN1->GetID(); + TColStd_MapOfInteger UsedNums; + int NbEdges = Edges.Length(); + int i = 1; + for(; i<=NbEdges; i++) { + int k = 0; + list< SMESH_subMesh* >::iterator itLSM = LSM.begin(); + for(; itLSM!=LSM.end(); itLSM++) { + k++; + if(UsedNums.Contains(k)) continue; + aTrackEdge = TopoDS::Edge( Edges.Value(k) ); + SMESH_subMesh* locTrack = *itLSM; + SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS(); + TopExp::Vertices( aTrackEdge, aV1, aV2 ); + aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes(); + const SMDS_MeshNode* aN1 = aItN->next(); + aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes(); + const SMDS_MeshNode* aN2 = aItN->next(); + // starting node must be aN1 or aN2 + if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue; + // 2. Collect parameters on the track edge + aPrms.clear(); + aItN = locMeshDS->GetNodes(); + while ( aItN->more() ) { + const SMDS_MeshNode* pNode = aItN->next(); + const SMDS_EdgePosition* pEPos = + static_cast( pNode->GetPosition().get() ); + double aT = pEPos->GetUParameter(); + aPrms.push_back( aT ); + } + list LPP; + //Extrusion_Error err = + MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP); + LLPPs.push_back(LPP); + UsedNums.Add(k); + // update startN for search following egde + if( aN1->GetID() == startNid ) startNid = aN2->GetID(); + else startNid = aN1->GetID(); + break; + } } + list< list >::iterator itLLPP = LLPPs.begin(); + list firstList = *itLLPP; + list::iterator itPP = firstList.begin(); + for(; itPP!=firstList.end(); itPP++) { + fullList.push_back( *itPP ); + } + SMESH_MeshEditor_PathPoint PP1 = fullList.back(); + fullList.pop_back(); + itLLPP++; + for(; itLLPP!=LLPPs.end(); itLLPP++) { + list currList = *itLLPP; + itPP = currList.begin(); + SMESH_MeshEditor_PathPoint PP2 = currList.front(); + gp_Pnt P1 = PP1.Pnt(); + //cout<<" PP1: Pnt("<GetNodes(); - while ( aItN->more() ) { - const SMDS_MeshNode* pNode = aItN->next(); - const SMDS_EdgePosition* pEPos = - static_cast( pNode->GetPosition().get() ); - aT = pEPos->GetUParameter(); - aPrms.push_back( aT ); - } +//======================================================================= +//function : MakeEdgePathPoints +//purpose : auxilary for ExtrusionAlongTrack +//======================================================================= +SMESH_MeshEditor::Extrusion_Error +SMESH_MeshEditor::MakeEdgePathPoints(std::list& aPrms, + const TopoDS_Edge& aTrackEdge, + bool FirstIsStart, + list& LPP) +{ + Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2; + aTolVec=1.e-7; + aTolVec2=aTolVec*aTolVec; + double aT1, aT2; + TopoDS_Vertex aV1, aV2; + TopExp::Vertices( aTrackEdge, aV1, aV2 ); + aT1=BRep_Tool::Parameter( aV1, aTrackEdge ); + aT2=BRep_Tool::Parameter( aV2, aTrackEdge ); + // 2. Collect parameters on the track edge + aPrms.push_front( aT1 ); + aPrms.push_back( aT2 ); // sort parameters aPrms.sort(); - if ( aN1 == theN1 ) { + if( FirstIsStart ) { if ( aT1 > aT2 ) { aPrms.reverse(); } @@ -3908,33 +4901,86 @@ SMESH_MeshEditor::Extrusion_Error aPrms.reverse(); } } - // 3. Path Points SMESH_MeshEditor_PathPoint aPP; - vector aPPs( aNbTP ); - // - aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 ); - // - aItD = aPrms.begin(); - for ( j=0; aItD != aPrms.end(); ++aItD, ++j ) { - aT = *aItD; + Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 ); + std::list::iterator aItD = aPrms.begin(); + for(; aItD != aPrms.end(); ++aItD) { + double aT = *aItD; + gp_Pnt aP3D; + gp_Vec aVec; aC3D->D1( aT, aP3D, aVec ); aL2 = aVec.SquareMagnitude(); if ( aL2 < aTolVec2 ) return EXTR_CANT_GET_TANGENT; - gp_Dir aTgt( aVec ); - aAngle = aAngles[j]; - aPP.SetPnt( aP3D ); aPP.SetTangent( aTgt ); - aPP.SetAngle( aAngle ); aPP.SetParameter( aT ); - aPPs[j]=aPP; + LPP.push_back(aPP); + } + return EXTR_OK; +} + + +//======================================================================= +//function : MakeExtrElements +//purpose : auxilary for ExtrusionAlongTrack +//======================================================================= +SMESH_MeshEditor::Extrusion_Error +SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements, + list& fullList, + const bool theHasAngles, + list& theAngles, + const bool theLinearVariation, + const bool theHasRefPoint, + const gp_Pnt& theRefPoint, + const bool theMakeGroups) +{ + //cout<<"MakeExtrElements fullList.size() = "< aPPs(aNbTP); + // Angles + if( theHasAngles && theAngles.size()>0 && theLinearVariation ) { + LinearAngleVariation(aNbTP-1, theAngles); + } + vector aAngles( aNbTP ); + int j = 0; + for(; j::iterator aItD = theAngles.begin(); + for ( j=1; (aItD != theAngles.end()) && (j::iterator itPP = fullList.begin(); + for(; itPP!=fullList.end(); itPP++) { + j++; + SMESH_MeshEditor_PathPoint PP = *itPP; + PP.SetAngle(aAngles[j]); + aPPs[j] = PP; } + TNodeOfNodeListMap mapNewNodes; + TElemOfVecOfNnlmiMap mapElemNewNodes; + TElemOfElemListMap newElemsMap; + TIDSortedElemSet::iterator itElem; + double aX, aY, aZ; + int aNb; + SMDSAbs_ElementType aTypeE; + // source elements for each generated one + SMESH_SequenceOfElemPtr srcElems, srcNodes; + // 3. Center of rotation aV0 - aV0 = theRefPoint; + gp_Pnt aV0 = theRefPoint; + gp_XYZ aGC; if ( !theHasRefPoint ) { aNb = 0; aGC.SetCoord( 0.,0.,0. ); @@ -3945,19 +4991,19 @@ SMESH_MeshEditor::Extrusion_Error SMDS_ElemIteratorPtr itN = elem->nodesIterator(); while ( itN->more() ) { - const SMDS_MeshNode* node = static_cast( itN->next() ); - aX = node->X(); - aY = node->Y(); - aZ = node->Z(); - - if ( mapNewNodes.find( node ) == mapNewNodes.end() ) { - list aLNx; - mapNewNodes[node] = aLNx; - // - gp_XYZ aXYZ( aX, aY, aZ ); - aGC += aXYZ; - ++aNb; - } + const SMDS_MeshNode* node = static_cast( itN->next() ); + aX = node->X(); + aY = node->Y(); + aZ = node->Z(); + + if ( mapNewNodes.find( node ) == mapNewNodes.end() ) { + list aLNx; + mapNewNodes[node] = aLNx; + // + gp_XYZ aXYZ( aX, aY, aZ ); + aGC += aXYZ; + ++aNb; + } } } aGC /= aNb; @@ -3986,65 +5032,66 @@ SMESH_MeshEditor::Extrusion_Error ++nodeIndex; // check if a node has been already processed const SMDS_MeshNode* node = - static_cast( itN->next() ); + static_cast( itN->next() ); TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node ); if ( nIt == mapNewNodes.end() ) { nIt = mapNewNodes.insert( make_pair( node, list() )).first; list& listNewNodes = nIt->second; - // make new nodes - aX = node->X(); aY = node->Y(); aZ = node->Z(); - - Standard_Real aAngle1x, aAngleT1T0, aTolAng; - gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x; - gp_Ax1 anAx1, anAxT1T0; - gp_Dir aDT1x, aDT0x, aDT1T0; - - aTolAng=1.e-4; - - aV0x = aV0; - aPN0.SetCoord(aX, aY, aZ); - - const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0]; - aP0x = aPP0.Pnt(); - aDT0x= aPP0.Tangent(); - - for ( j = 1; j < aNbTP; ++j ) { - const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j]; - aP1x = aPP1.Pnt(); - aDT1x = aPP1.Tangent(); - aAngle1x = aPP1.Angle(); - - gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0; - // Translation - gp_Vec aV01x( aP0x, aP1x ); - aTrsf.SetTranslation( aV01x ); - - // traslated point - aV1x = aV0x.Transformed( aTrsf ); - aPN1 = aPN0.Transformed( aTrsf ); - - // rotation 1 [ T1,T0 ] - aAngleT1T0=-aDT1x.Angle( aDT0x ); - if (fabs(aAngleT1T0) > aTolAng) { - aDT1T0=aDT1x^aDT0x; - anAxT1T0.SetLocation( aV1x ); - anAxT1T0.SetDirection( aDT1T0 ); - aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 ); - - aPN1 = aPN1.Transformed( aTrsfRotT1T0 ); - } + // make new nodes + aX = node->X(); aY = node->Y(); aZ = node->Z(); + + Standard_Real aAngle1x, aAngleT1T0, aTolAng; + gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x; + gp_Ax1 anAx1, anAxT1T0; + gp_Dir aDT1x, aDT0x, aDT1T0; + + aTolAng=1.e-4; + + aV0x = aV0; + aPN0.SetCoord(aX, aY, aZ); + + const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0]; + aP0x = aPP0.Pnt(); + aDT0x= aPP0.Tangent(); + //cout<<"j = 0 PP: Pnt("< aTolAng) { + aDT1T0=aDT1x^aDT0x; + anAxT1T0.SetLocation( aV1x ); + anAxT1T0.SetDirection( aDT1T0 ); + aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 ); + + aPN1 = aPN1.Transformed( aTrsfRotT1T0 ); + } - // rotation 2 - if ( theHasAngles ) { - anAx1.SetLocation( aV1x ); - anAx1.SetDirection( aDT1x ); - aTrsfRot.SetRotation( anAx1, aAngle1x ); + // rotation 2 + if ( theHasAngles ) { + anAx1.SetLocation( aV1x ); + anAx1.SetDirection( aDT1x ); + aTrsfRot.SetRotation( anAx1, aAngle1x ); - aPN1 = aPN1.Transformed( aTrsfRot ); - } + aPN1 = aPN1.Transformed( aTrsfRot ); + } - // make new node + // make new node if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) { // create additional node double x = ( aPN1.X() + aPN0.X() )/2.; @@ -4055,19 +5102,19 @@ SMESH_MeshEditor::Extrusion_Error srcNodes.Append( node ); listNewNodes.push_back( newNode ); } - aX = aPN1.X(); - aY = aPN1.Y(); - aZ = aPN1.Z(); - const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ ); + aX = aPN1.X(); + aY = aPN1.Y(); + aZ = aPN1.Z(); + const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ ); myLastCreatedNodes.Append(newNode); srcNodes.Append( node ); - listNewNodes.push_back( newNode ); + listNewNodes.push_back( newNode ); - aPN0 = aPN1; - aP0x = aP1x; - aV0x = aV1x; - aDT0x = aDT1x; - } + aPN0 = aPN1; + aP0x = aP1x; + aV0x = aV1x; + aDT0x = aDT1x; + } } else { @@ -4116,10 +5163,67 @@ SMESH_MeshEditor::Extrusion_Error return EXTR_OK; } + //======================================================================= -//function : Transform -//purpose : +//function : LinearAngleVariation +//purpose : auxilary for ExtrusionAlongTrack //======================================================================= +void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps, + list& Angles) +{ + int nbAngles = Angles.size(); + if( nbSteps > nbAngles ) { + vector theAngles(nbAngles); + list::iterator it = Angles.begin(); + int i = -1; + for(; it!=Angles.end(); it++) { + i++; + theAngles[i] = (*it); + } + list res; + double rAn2St = double( nbAngles ) / double( nbSteps ); + double angPrev = 0, angle; + for ( int iSt = 0; iSt < nbSteps; ++iSt ) { + double angCur = rAn2St * ( iSt+1 ); + double angCurFloor = floor( angCur ); + double angPrevFloor = floor( angPrev ); + if ( angPrevFloor == angCurFloor ) + angle = rAn2St * theAngles[ int( angCurFloor ) ]; + else { + int iP = int( angPrevFloor ); + double angPrevCeil = ceil(angPrev); + angle = ( angPrevCeil - angPrev ) * theAngles[ iP ]; + + int iC = int( angCurFloor ); + if ( iC < nbAngles ) + angle += ( angCur - angCurFloor ) * theAngles[ iC ]; + + iP = int( angPrevCeil ); + while ( iC-- > iP ) + angle += theAngles[ iC ]; + } + res.push_back(angle); + angPrev = angCur; + } + Angles.clear(); + it = res.begin(); + for(; it!=res.end(); it++) + Angles.push_back( *it ); + } +} + + +//================================================================================ +/*! + * \brief Move or copy theElements applying theTrsf to their nodes + * \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes + * \param theTrsf - transformation to apply + * \param theCopy - if true, create translated copies of theElems + * \param theMakeGroups - if true and theCopy, create translated groups + * \param theTargetMesh - mesh to copy translated elements into + * \retval SMESH_MeshEditor::PGroupIDs - list of ids of created groups + */ +//================================================================================ SMESH_MeshEditor::PGroupIDs SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, @@ -4147,6 +5251,7 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, groupPostfix = "translated"; break; case gp_Scale: + case gp_CompoundTrsf: // different scale by axis groupPostfix = "scaled"; break; default: @@ -4157,7 +5262,7 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, SMESH_MeshEditor targetMeshEditor( theTargetMesh ); SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0; SMESHDS_Mesh* aMesh = GetMeshDS(); - + // map old node to new one TNodeNodeMap nodeMap; @@ -4169,7 +5274,36 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, // source elements for each generated one SMESH_SequenceOfElemPtr srcElems, srcNodes; - // loop on theElems + // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh + list orphanCopy; // copies of orphan nodes + vector orphanNode; // original orphan nodes + + if ( theElems.empty() ) // transform the whole mesh + { + // add all elements + SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator(); + while ( eIt->more() ) theElems.insert( eIt->next() ); + // add orphan nodes + SMDS_MeshElementIDFactory idFactory; + SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator(); + while ( nIt->more() ) + { + const SMDS_MeshNode* node = nIt->next(); + if ( node->NbInverseElements() == 0 && !theElems.insert( node ).second ) + { + // node was not inserted into theElems because an element with the same ID + // is already there. As a work around we insert a copy of node with + // an ID = - + orphanCopy.push_back( *node ); // copy node + SMDS_MeshNode* nodeCopy = &orphanCopy.back(); + int uniqueID = -orphanNode.size(); + orphanNode.push_back( node ); + idFactory.BindID( uniqueID, nodeCopy ); + theElems.insert( nodeCopy ); + } + } + } + // loop on theElems to transorm nodes TIDSortedElemSet::iterator itElem; for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { const SMDS_MeshElement* elem = *itElem; @@ -4180,8 +5314,10 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, SMDS_ElemIteratorPtr itN = elem->nodesIterator(); while ( itN->more() ) { - // check if a node has been already transformed const SMDS_MeshNode* node = cast2Node( itN->next() ); + if ( node->GetID() < 0 ) + node = orphanNode[ -node->GetID() ]; + // check if a node has been already transformed pair n2n_isnew = nodeMap.insert( make_pair ( node, node )); if ( !n2n_isnew.second ) @@ -4239,7 +5375,7 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, REV_FACE = 3, REV_HEXA = 4, // = nbNodes - 4 FORWARD = 5 - }; + }; int index[][8] = { { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID @@ -4340,18 +5476,18 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, } } break; - default:; + default:; + } + continue; } - continue; - } - // Regular elements - int* i = index[ FORWARD ]; - if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes - if ( elemType == SMDSAbs_Face ) - i = index[ REV_FACE ]; - else - i = index[ nbNodes - 4 ]; + // Regular elements + int* i = index[ FORWARD ]; + if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes + if ( elemType == SMDSAbs_Face ) + i = index[ REV_FACE ]; + else + i = index[ nbNodes - 4 ]; if(elem->IsQuadratic()) { static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; @@ -4411,10 +5547,8 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, } } else if ( theCopy ) { - if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) { - myLastCreatedElems.Append( copy ); + if ( AddElement( nodes, elem->GetType(), elem->IsPoly() )) srcElems.Append( elem ); - } } else { // reverse element as it was reversed by transformation @@ -4558,33 +5692,32 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, return newGroupIDs; } -//======================================================================= -//function : FindCoincidentNodes -//purpose : Return list of group of nodes close to each other within theTolerance -// Search among theNodes or in the whole mesh if theNodes is empty using -// an Octree algorithm -//======================================================================= +//================================================================================ +/*! + * \brief Return list of group of nodes close to each other within theTolerance + * Search among theNodes or in the whole mesh if theNodes is empty using + * an Octree algorithm + */ +//================================================================================ -void SMESH_MeshEditor::FindCoincidentNodes (set & theNodes, - const double theTolerance, - TListOfListOfNodes & theGroupsOfNodes) +void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes, + const double theTolerance, + TListOfListOfNodes & theGroupsOfNodes) { myLastCreatedElems.Clear(); myLastCreatedNodes.Clear(); - set nodes; if ( theNodes.empty() ) { // get all nodes in the mesh - SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(); + SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true); while ( nIt->more() ) - nodes.insert( nodes.end(),nIt->next()); + theNodes.insert( theNodes.end(),nIt->next()); } - else - nodes=theNodes; - SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance); + SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance); } + //======================================================================= /*! * \brief Implementation of search for the node closest to point @@ -4593,31 +5726,58 @@ void SMESH_MeshEditor::FindCoincidentNodes (set & theNodes struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher { + //--------------------------------------------------------------------- /*! * \brief Constructor */ SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh ) { - set nodes; + myMesh = ( SMESHDS_Mesh* ) theMesh; + + TIDSortedNodeSet nodes; if ( theMesh ) { - SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(); + SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true); while ( nIt->more() ) nodes.insert( nodes.end(), nIt->next() ); } myOctreeNode = new SMESH_OctreeNode(nodes) ; + + // get max size of a leaf box + SMESH_OctreeNode* tree = myOctreeNode; + while ( !tree->isLeaf() ) + { + SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator(); + if ( cIt->more() ) + tree = cIt->next(); + } + myHalfLeafSize = tree->maxSize() / 2.; } + + //--------------------------------------------------------------------- + /*! + * \brief Move node and update myOctreeNode accordingly + */ + void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt ) + { + myOctreeNode->UpdateByMoveNode( node, toPnt ); + myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() ); + } + + //--------------------------------------------------------------------- /*! * \brief Do it's job */ const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt ) { SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() ); + map dist2Nodes; + myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize ); + if ( !dist2Nodes.empty() ) + return dist2Nodes.begin()->second; list nodes; - const double precision = 1e-6; - myOctreeNode->NodesAround( &tgtNode, &nodes, precision ); + //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize ); double minSqDist = DBL_MAX; - Bnd_B3d box; if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt { // sort leafs by their distance from thePnt @@ -4626,20 +5786,26 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher list< SMESH_OctreeNode* > treeList; list< SMESH_OctreeNode* >::iterator trIt; treeList.push_back( myOctreeNode ); + + SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() ); + bool pointInside = myOctreeNode->isInside( &pointNode, myHalfLeafSize ); for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt) { SMESH_OctreeNode* tree = *trIt; - if ( !tree->isLeaf() ) { // put children to the queue + if ( !tree->isLeaf() ) // put children to the queue + { + if ( pointInside && !tree->isInside( &pointNode, myHalfLeafSize )) continue; SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator(); while ( cIt->more() ) treeList.push_back( cIt->next() ); } - else if ( tree->NbNodes() ) { // put tree to treeMap - tree->getBox( box ); + else if ( tree->NbNodes() ) // put a tree to the treeMap + { + const Bnd_B3d& box = tree->getBox(); double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() )); pair it_in = treeMap.insert( make_pair( sqDist, tree )); if ( !it_in.second ) // not unique distance to box center - treeMap.insert( it_in.first, make_pair( sqDist - 1e-13*treeMap.size(), tree )); + treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree )); } } // find distance after which there is no sense to check tree's @@ -4647,7 +5813,7 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher TDistTreeMap::iterator sqDist_tree = treeMap.begin(); if ( treeMap.size() > 5 ) { SMESH_OctreeNode* closestTree = sqDist_tree->second; - closestTree->getBox( box ); + const Bnd_B3d& box = closestTree->getBox(); double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() ); sqLimit = limit * limit; } @@ -4664,7 +5830,7 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher const SMDS_MeshNode* closestNode = 0; list::iterator nIt = nodes.begin(); for ( ; nIt != nodes.end(); ++nIt ) { - double sqDist = thePnt.SquareDistance( TNodeXYZ( *nIt ) ); + double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) ); if ( minSqDist > sqDist ) { closestNode = *nIt; minSqDist = sqDist; @@ -4672,12 +5838,23 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher } return closestNode; } + + //--------------------------------------------------------------------- /*! * \brief Destructor */ ~SMESH_NodeSearcherImpl() { delete myOctreeNode; } + + //--------------------------------------------------------------------- + /*! + * \brief Return the node tree + */ + const SMESH_OctreeNode* getTree() const { return myOctreeNode; } + private: SMESH_OctreeNode* myOctreeNode; + SMESHDS_Mesh* myMesh; + double myHalfLeafSize; // max size of a leaf box }; //======================================================================= @@ -4691,6 +5868,921 @@ SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() return new SMESH_NodeSearcherImpl( GetMeshDS() ); } +// ======================================================================== +namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() +{ + const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree + const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152 + const double NodeRadius = 1e-9; // to enlarge bnd box of element + + //======================================================================= + /*! + * \brief Octal tree of bounding boxes of elements + */ + //======================================================================= + + class ElementBndBoxTree : public SMESH_Octree + { + public: + + ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance = NodeRadius ); + void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems); + void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems); + ~ElementBndBoxTree(); + + protected: + ElementBndBoxTree() {} + SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; } + void buildChildrenData(); + Bnd_B3d* buildRootBox(); + private: + //!< Bounding box of element + struct ElementBox : public Bnd_B3d + { + const SMDS_MeshElement* _element; + int _refCount; // an ElementBox can be included in several tree branches + ElementBox(const SMDS_MeshElement* elem, double tolerance); + }; + vector< ElementBox* > _elements; + }; + + //================================================================================ + /*! + * \brief ElementBndBoxTree creation + */ + //================================================================================ + + ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance) + :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. )) + { + int nbElems = mesh.GetMeshInfo().NbElements( elemType ); + _elements.reserve( nbElems ); + + SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType ); + while ( elemIt->more() ) + _elements.push_back( new ElementBox( elemIt->next(),tolerance )); + + if ( _elements.size() > MaxNbElemsInLeaf ) + compute(); + else + myIsLeaf = true; + } + + //================================================================================ + /*! + * \brief Destructor + */ + //================================================================================ + + ElementBndBoxTree::~ElementBndBoxTree() + { + for ( int i = 0; i < _elements.size(); ++i ) + if ( --_elements[i]->_refCount <= 0 ) + delete _elements[i]; + } + + //================================================================================ + /*! + * \brief Return the maximal box + */ + //================================================================================ + + Bnd_B3d* ElementBndBoxTree::buildRootBox() + { + Bnd_B3d* box = new Bnd_B3d; + for ( int i = 0; i < _elements.size(); ++i ) + box->Add( *_elements[i] ); + return box; + } + + //================================================================================ + /*! + * \brief Redistrubute element boxes among children + */ + //================================================================================ + + void ElementBndBoxTree::buildChildrenData() + { + for ( int i = 0; i < _elements.size(); ++i ) + { + for (int j = 0; j < 8; j++) + { + if ( !_elements[i]->IsOut( myChildren[j]->getBox() )) + { + _elements[i]->_refCount++; + ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]); + } + } + _elements[i]->_refCount--; + } + _elements.clear(); + + for (int j = 0; j < 8; j++) + { + ElementBndBoxTree* child = static_cast( myChildren[j]); + if ( child->_elements.size() <= MaxNbElemsInLeaf ) + child->myIsLeaf = true; + + if ( child->_elements.capacity() - child->_elements.size() > 1000 ) + child->_elements.resize( child->_elements.size() ); // compact + } + } + + //================================================================================ + /*! + * \brief Return elements which can include the point + */ + //================================================================================ + + void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point, + TIDSortedElemSet& foundElems) + { + if ( level() && getBox().IsOut( point.XYZ() )) + return; + + if ( isLeaf() ) + { + for ( int i = 0; i < _elements.size(); ++i ) + if ( !_elements[i]->IsOut( point.XYZ() )) + foundElems.insert( _elements[i]->_element ); + } + else + { + for (int i = 0; i < 8; i++) + ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems ); + } + } + + //================================================================================ + /*! + * \brief Return elements which can be intersected by the line + */ + //================================================================================ + + void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line, + TIDSortedElemSet& foundElems) + { + if ( level() && getBox().IsOut( line )) + return; + + if ( isLeaf() ) + { + for ( int i = 0; i < _elements.size(); ++i ) + if ( !_elements[i]->IsOut( line )) + foundElems.insert( _elements[i]->_element ); + } + else + { + for (int i = 0; i < 8; i++) + ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems ); + } + } + + //================================================================================ + /*! + * \brief Construct the element box + */ + //================================================================================ + + ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance) + { + _element = elem; + _refCount = 1; + SMDS_ElemIteratorPtr nIt = elem->nodesIterator(); + while ( nIt->more() ) + Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() ))); + Enlarge( tolerance ); + } + +} // namespace + +//======================================================================= +/*! + * \brief Implementation of search for the elements by point and + * of classification of point in 2D mesh + */ +//======================================================================= + +struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher +{ + SMESHDS_Mesh* _mesh; + ElementBndBoxTree* _ebbTree; + SMESH_NodeSearcherImpl* _nodeSearcher; + SMDSAbs_ElementType _elementType; + double _tolerance; + bool _outerFacesFound; + set _outerFaces; // empty means "no internal faces at all" + + SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh ) + : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {} + ~SMESH_ElementSearcherImpl() + { + if ( _ebbTree ) delete _ebbTree; _ebbTree = 0; + if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0; + } + virtual int FindElementsByPoint(const gp_Pnt& point, + SMDSAbs_ElementType type, + vector< const SMDS_MeshElement* >& foundElements); + virtual TopAbs_State GetPointState(const gp_Pnt& point); + + void GetElementsNearLine( const gp_Ax1& line, + SMDSAbs_ElementType type, + vector< const SMDS_MeshElement* >& foundElems); + double getTolerance(); + bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face, + const double tolerance, double & param); + void findOuterBoundary(const SMDS_MeshElement* anyOuterFace); + bool isOuterBoundary(const SMDS_MeshElement* face) const + { + return _outerFaces.empty() || _outerFaces.count(face); + } + struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState()) + { + const SMDS_MeshElement* _face; + gp_Vec _faceNorm; + bool _coincides; //!< the line lays in face plane + TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false) + : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {} + }; + struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary()) + { + SMESH_TLink _link; + TIDSortedElemSet _faces; + TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face) + : _link( n1, n2 ), _faces( &face, &face + 1) {} + }; +}; + +ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i) +{ + return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0) + << ", _coincides="<GetMeshInfo(); + + _tolerance = 0; + if ( _nodeSearcher && meshInfo.NbNodes() > 1 ) + { + double boxSize = _nodeSearcher->getTree()->maxSize(); + _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/; + } + else if ( _ebbTree && meshInfo.NbElements() > 0 ) + { + double boxSize = _ebbTree->maxSize(); + _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/; + } + if ( _tolerance == 0 ) + { + // define tolerance by size of a most complex element + int complexType = SMDSAbs_Volume; + while ( complexType > SMDSAbs_All && + meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 ) + --complexType; + if ( complexType == SMDSAbs_All ) return 0; // empty mesh + + double elemSize; + if ( complexType == int( SMDSAbs_Node )) + { + SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator(); + elemSize = 1; + if ( meshInfo.NbNodes() > 2 ) + elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() ); + } + else + { + const SMDS_MeshElement* elem = + _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next(); + SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator(); + SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() )); + while ( nodeIt->more() ) + { + double dist = n1.Distance( cast2Node( nodeIt->next() )); + elemSize = max( dist, elemSize ); + } + } + _tolerance = 1e-4 * elemSize; + } + } + return _tolerance; +} + +//================================================================================ +/*! + * \brief Find intersection of the line and an edge of face and return parameter on line + */ +//================================================================================ + +bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line, + const SMDS_MeshElement* face, + const double tol, + double & param) +{ + int nbInts = 0; + param = 0; + + GeomAPI_ExtremaCurveCurve anExtCC; + Handle(Geom_Curve) lineCurve = new Geom_Line( line ); + + int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes(); + for ( int i = 0; i < nbNodes && nbInts < 2; ++i ) + { + GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )), + SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); + anExtCC.Init( lineCurve, edge); + if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol) + { + Quantity_Parameter pl, pe; + anExtCC.LowerDistanceParameters( pl, pe ); + param += pl; + if ( ++nbInts == 2 ) + break; + } + } + if ( nbInts > 0 ) param /= nbInts; + return nbInts > 0; +} +//================================================================================ +/*! + * \brief Find all faces belonging to the outer boundary of mesh + */ +//================================================================================ + +void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace) +{ + if ( _outerFacesFound ) return; + + // Collect all outer faces by passing from one outer face to another via their links + // and BTW find out if there are internal faces at all. + + // checked links and links where outer boundary meets internal one + set< SMESH_TLink > visitedLinks, seamLinks; + + // links to treat with already visited faces sharing them + list < TFaceLink > startLinks; + + // load startLinks with the first outerFace + startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace)); + _outerFaces.insert( outerFace ); + + TIDSortedElemSet emptySet; + while ( !startLinks.empty() ) + { + const SMESH_TLink& link = startLinks.front()._link; + TIDSortedElemSet& faces = startLinks.front()._faces; + + outerFace = *faces.begin(); + // find other faces sharing the link + const SMDS_MeshElement* f; + while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces ))) + faces.insert( f ); + + // select another outer face among the found + const SMDS_MeshElement* outerFace2 = 0; + if ( faces.size() == 2 ) + { + outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin()); + } + else if ( faces.size() > 2 ) + { + seamLinks.insert( link ); + + // link direction within the outerFace + gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()), + SMESH_MeshEditor::TNodeXYZ( link.node2())); + int i1 = outerFace->GetNodeIndex( link.node1() ); + int i2 = outerFace->GetNodeIndex( link.node2() ); + bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 ); + if ( rev ) n1n2.Reverse(); + // outerFace normal + gp_XYZ ofNorm, fNorm; + if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false )) + { + // direction from the link inside outerFace + gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2; + // sort all other faces by angle with the dirInOF + map< double, const SMDS_MeshElement* > angle2Face; + set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin(); + for ( ; face != faces.end(); ++face ) + { + if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false )) + continue; + gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2; + double angle = dirInOF.AngleWithRef( dirInF, n1n2 ); + if ( angle < 0 ) angle += 2*PI; + angle2Face.insert( make_pair( angle, *face )); + } + if ( !angle2Face.empty() ) + outerFace2 = angle2Face.begin()->second; + } + } + // store the found outer face and add its links to continue seaching from + if ( outerFace2 ) + { + _outerFaces.insert( outerFace ); + int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 ); + for ( int i = 0; i < nbNodes; ++i ) + { + SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes)); + if ( visitedLinks.insert( link2 ).second ) + startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 )); + } + } + startLinks.pop_front(); + } + _outerFacesFound = true; + + if ( !seamLinks.empty() ) + { + // There are internal boundaries touching the outher one, + // find all faces of internal boundaries in order to find + // faces of boundaries of holes, if any. + + } + else + { + _outerFaces.clear(); + } +} + +//======================================================================= +/*! + * \brief Find elements of given type where the given point is IN or ON. + * Returns nb of found elements and elements them-selves. + * + * 'ALL' type means elements of any type excluding nodes and 0D elements + */ +//======================================================================= + +int SMESH_ElementSearcherImpl:: +FindElementsByPoint(const gp_Pnt& point, + SMDSAbs_ElementType type, + vector< const SMDS_MeshElement* >& foundElements) +{ + foundElements.clear(); + + double tolerance = getTolerance(); + + // ================================================================================= + if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement ) + { + if ( !_nodeSearcher ) + _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh ); + + const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point ); + if ( !closeNode ) return foundElements.size(); + + if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance ) + return foundElements.size(); // to far from any node + + if ( type == SMDSAbs_Node ) + { + foundElements.push_back( closeNode ); + } + else + { + SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement ); + while ( elemIt->more() ) + foundElements.push_back( elemIt->next() ); + } + } + // ================================================================================= + else // elements more complex than 0D + { + if ( !_ebbTree || _elementType != type ) + { + if ( _ebbTree ) delete _ebbTree; + _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, tolerance ); + } + TIDSortedElemSet suspectElems; + _ebbTree->getElementsNearPoint( point, suspectElems ); + TIDSortedElemSet::iterator elem = suspectElems.begin(); + for ( ; elem != suspectElems.end(); ++elem ) + if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance )) + foundElements.push_back( *elem ); + } + return foundElements.size(); +} + +//================================================================================ +/*! + * \brief Classify the given point in the closed 2D mesh + */ +//================================================================================ + +TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point) +{ + double tolerance = getTolerance(); + if ( !_ebbTree || _elementType != SMDSAbs_Face ) + { + if ( _ebbTree ) delete _ebbTree; + _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face ); + } + // Algo: analyse transition of a line starting at the point through mesh boundary; + // try three lines parallel to axis of the coordinate system and perform rough + // analysis. If solution is not clear perform thorough analysis. + + const int nbAxes = 3; + gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() }; + map< double, TInters > paramOnLine2TInters[ nbAxes ]; + list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line + multimap< int, int > nbInt2Axis; // to find the simplest case + for ( int axis = 0; axis < nbAxes; ++axis ) + { + gp_Ax1 lineAxis( point, axisDir[axis]); + gp_Lin line ( lineAxis ); + + TIDSortedElemSet suspectFaces; // faces possibly intersecting the line + _ebbTree->getElementsNearLine( lineAxis, suspectFaces ); + + // Intersect faces with the line + + map< double, TInters > & u2inters = paramOnLine2TInters[ axis ]; + TIDSortedElemSet::iterator face = suspectFaces.begin(); + for ( ; face != suspectFaces.end(); ++face ) + { + // get face plane + gp_XYZ fNorm; + if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue; + gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm ); + + // perform intersection + IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane )); + if ( !intersection.IsDone() ) + continue; + if ( intersection.IsInQuadric() ) + { + tangentInters[ axis ].push_back( TInters( *face, fNorm, true )); + } + else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 ) + { + gp_Pnt intersectionPoint = intersection.Point(1); + if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance )) + u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm ))); + } + } + // Analyse intersections roughly + + int nbInter = u2inters.size(); + if ( nbInter == 0 ) + return TopAbs_OUT; + + double f = u2inters.begin()->first, l = u2inters.rbegin()->first; + if ( nbInter == 1 ) // not closed mesh + return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN; + + if ( fabs( f ) < tolerance || fabs( l ) < tolerance ) + return TopAbs_ON; + + if ( (f<0) == (l<0) ) + return TopAbs_OUT; + + int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0)); + int nbIntAfterPoint = nbInter - nbIntBeforePoint; + if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 ) + return TopAbs_IN; + + nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis )); + + if ( _outerFacesFound ) break; // pass to thorough analysis + + } // three attempts - loop on CS axes + + // Analyse intersections thoroughly. + // We make two loops maximum, on the first one we only exclude touching intersections, + // on the second, if situation is still unclear, we gather and use information on + // position of faces (internal or outer). If faces position is already gathered, + // we make the second loop right away. + + for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo ) + { + multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin(); + for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis ) + { + int axis = nb_axis->second; + map< double, TInters > & u2inters = paramOnLine2TInters[ axis ]; + + gp_Ax1 lineAxis( point, axisDir[axis]); + gp_Lin line ( lineAxis ); + + // add tangent intersections to u2inters + double param; + list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin(); + for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt ) + if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param )) + u2inters.insert(make_pair( param, *tgtInt )); + tangentInters[ axis ].clear(); + + // Count intersections before and after the point excluding touching ones. + // If hasPositionInfo we count intersections of outer boundary only + + int nbIntBeforePoint = 0, nbIntAfterPoint = 0; + double f = numeric_limits::max(), l = -numeric_limits::max(); + map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1; + bool ok = ! u_int1->second._coincides; + while ( ok && u_int1 != u2inters.end() ) + { + double u = u_int1->first; + bool touchingInt = false; + if ( ++u_int2 != u2inters.end() ) + { + // skip intersections at the same point (if the line passes through edge or node) + int nbSamePnt = 0; + while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance ) + { + ++nbSamePnt; + ++u_int2; + } + + // skip tangent intersections + int nbTgt = 0; + const SMDS_MeshElement* prevFace = u_int1->second._face; + while ( ok && u_int2->second._coincides ) + { + if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() ) + ok = false; + else + { + nbTgt++; + u_int2++; + ok = ( u_int2 != u2inters.end() ); + } + } + if ( !ok ) break; + + // skip intersections at the same point after tangent intersections + if ( nbTgt > 0 ) + { + double u2 = u_int2->first; + ++u_int2; + while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance ) + { + ++nbSamePnt; + ++u_int2; + } + } + // decide if we skipped a touching intersection + if ( nbSamePnt + nbTgt > 0 ) + { + double minDot = numeric_limits::max(), maxDot = -numeric_limits::max(); + map< double, TInters >::iterator u_int = u_int1; + for ( ; u_int != u_int2; ++u_int ) + { + if ( u_int->second._coincides ) continue; + double dot = u_int->second._faceNorm * line.Direction(); + if ( dot > maxDot ) maxDot = dot; + if ( dot < minDot ) minDot = dot; + } + touchingInt = ( minDot*maxDot < 0 ); + } + } + if ( !touchingInt ) + { + if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face )) + { + if ( u < 0 ) + ++nbIntBeforePoint; + else + ++nbIntAfterPoint; + } + if ( u < f ) f = u; + if ( u > l ) l = u; + } + + u_int1 = u_int2; // to next intersection + + } // loop on intersections with one line + + if ( ok ) + { + if ( fabs( f ) < tolerance || fabs( l ) < tolerance ) + return TopAbs_ON; + + if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0) + return TopAbs_OUT; + + if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh + return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN; + + if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 ) + return TopAbs_IN; + + if ( (f<0) == (l<0) ) + return TopAbs_OUT; + + if ( hasPositionInfo ) + return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT; + } + } // loop on intersections of the tree lines - thorough analysis + + if ( !hasPositionInfo ) + { + // gather info on faces position - is face in the outer boundary or not + map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ]; + findOuterBoundary( u2inters.begin()->second._face ); + } + + } // two attempts - with and w/o faces position info in the mesh + + return TopAbs_UNKNOWN; +} + +//======================================================================= +/*! + * \brief Return elements possibly intersecting the line + */ +//======================================================================= + +void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line, + SMDSAbs_ElementType type, + vector< const SMDS_MeshElement* >& foundElems) +{ + if ( !_ebbTree || _elementType != type ) + { + if ( _ebbTree ) delete _ebbTree; + _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type ); + } + TIDSortedElemSet suspectFaces; // elements possibly intersecting the line + _ebbTree->getElementsNearLine( line, suspectFaces ); + foundElems.assign( suspectFaces.begin(), suspectFaces.end()); +} + +//======================================================================= +/*! + * \brief Return SMESH_ElementSearcher + */ +//======================================================================= + +SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher() +{ + return new SMESH_ElementSearcherImpl( *GetMeshDS() ); +} + +//======================================================================= +/*! + * \brief Return true if the point is IN or ON of the element + */ +//======================================================================= + +bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol ) +{ + if ( element->GetType() == SMDSAbs_Volume) + { + return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol ); + } + + // get ordered nodes + + vector< gp_XYZ > xyz; + + SMDS_ElemIteratorPtr nodeIt = element->nodesIterator(); + if ( element->IsQuadratic() ) + if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast(element)) + nodeIt = f->interlacedNodesElemIterator(); + else if (const SMDS_QuadraticEdge* e =dynamic_cast(element)) + nodeIt = e->interlacedNodesElemIterator(); + + while ( nodeIt->more() ) + xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() ))); + + int i, nbNodes = element->NbNodes(); + + if ( element->GetType() == SMDSAbs_Face ) // -------------------------------------------------- + { + // compute face normal + gp_Vec faceNorm(0,0,0); + xyz.push_back( xyz.front() ); + for ( i = 0; i < nbNodes; ++i ) + { + gp_Vec edge1( xyz[i+1], xyz[i]); + gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] ); + faceNorm += edge1 ^ edge2; + } + double normSize = faceNorm.Magnitude(); + if ( normSize <= tol ) + { + // degenerated face: point is out if it is out of all face edges + for ( i = 0; i < nbNodes; ++i ) + { + SMDS_MeshNode n1( xyz[i].X(), xyz[i].Y(), xyz[i].Z() ); + SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() ); + SMDS_MeshEdge edge( &n1, &n2 ); + if ( !isOut( &edge, point, tol )) + return false; + } + return true; + } + faceNorm /= normSize; + + // check if the point lays on face plane + gp_Vec n2p( xyz[0], point ); + if ( fabs( n2p * faceNorm ) > tol ) + return true; // not on face plane + + // check if point is out of face boundary: + // define it by closest transition of a ray point->infinity through face boundary + // on the face plane. + // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool + // to find intersections of the ray with the boundary. + gp_Vec ray = n2p; + gp_Vec plnNorm = ray ^ faceNorm; + normSize = plnNorm.Magnitude(); + if ( normSize <= tol ) return false; // point coincides with the first node + plnNorm /= normSize; + // for each node of the face, compute its signed distance to the plane + vector dist( nbNodes + 1); + for ( i = 0; i < nbNodes; ++i ) + { + gp_Vec n2p( xyz[i], point ); + dist[i] = n2p * plnNorm; + } + dist.back() = dist.front(); + // find the closest intersection + int iClosest = -1; + double rClosest, distClosest = 1e100;; + gp_Pnt pClosest; + for ( i = 0; i < nbNodes; ++i ) + { + double r; + if ( fabs( dist[i]) < tol ) + r = 0.; + else if ( fabs( dist[i+1]) < tol ) + r = 1.; + else if ( dist[i] * dist[i+1] < 0 ) + r = dist[i] / ( dist[i] - dist[i+1] ); + else + continue; // no intersection + gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r; + gp_Vec p2int ( point, pInt); + if ( p2int * ray > -tol ) // right half-space + { + double intDist = p2int.SquareMagnitude(); + if ( intDist < distClosest ) + { + iClosest = i; + rClosest = r; + pClosest = pInt; + distClosest = intDist; + } + } + } + if ( iClosest < 0 ) + return true; // no intesections - out + + // analyse transition + gp_Vec edge( xyz[iClosest], xyz[iClosest+1] ); + gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face + gp_Vec p2int ( point, pClosest ); + bool out = (edgeNorm * p2int) < -tol; + if ( rClosest > 0. && rClosest < 1. ) // not node intersection + return out; + + // ray pass through a face node; analyze transition through an adjacent edge + gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ]; + gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ]; + gp_Vec edgeAdjacent( p1, p2 ); + gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm ); + bool out2 = (edgeNorm2 * p2int) < -tol; + + bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0; + return covexCorner ? (out || out2) : (out && out2); + } + if ( element->GetType() == SMDSAbs_Edge ) // -------------------------------------------------- + { + // point is out of edge if it is NOT ON any straight part of edge + // (we consider quadratic edge as being composed of two straight parts) + for ( i = 1; i < nbNodes; ++i ) + { + gp_Vec edge( xyz[i-1], xyz[i]); + gp_Vec n1p ( xyz[i-1], point); + double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude(); + if ( dist > tol ) + continue; + gp_Vec n2p( xyz[i], point ); + if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol ) + continue; + return false; // point is ON this part + } + return true; + } + // Node or 0D element ------------------------------------------------------------------------- + { + gp_Vec n2p ( xyz[0], point ); + return n2p.Magnitude() <= tol; + } + return true; +} + //======================================================================= //function : SimplifyFace //purpose : @@ -4809,7 +6901,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator(); while ( invElemIt->more() ) { const SMDS_MeshElement* elem = invElemIt->next(); - elems.insert(elem); + elems.insert(elem); } } } @@ -5343,24 +7435,24 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) // ======================================================== class SortableElement : public set { - public: +public: SortableElement( const SMDS_MeshElement* theElem ) - { - myElem = theElem; - SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator(); - while ( nodeIt->more() ) - this->insert( nodeIt->next() ); - } + { + myElem = theElem; + SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator(); + while ( nodeIt->more() ) + this->insert( nodeIt->next() ); + } const SMDS_MeshElement* Get() const - { return myElem; } + { return myElem; } void Set(const SMDS_MeshElement* e) const - { myElem = e; } + { myElem = e; } - private: +private: mutable const SMDS_MeshElement* myElem; }; @@ -5370,7 +7462,7 @@ class SortableElement : public set // Search among theElements or in the whole mesh if theElements is empty //======================================================================= void SMESH_MeshEditor::FindEqualElements(set & theElements, - TListOfListOfElementsID & theGroupsOfElementsID) + TListOfListOfElementsID & theGroupsOfElementsID) { myLastCreatedElems.Clear(); myLastCreatedNodes.Clear(); @@ -5468,7 +7560,7 @@ void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElemen void SMESH_MeshEditor::MergeEqualElements() { set aMeshElements; /* empty input - - to merge equal elements in the whole mesh */ + to merge equal elements in the whole mesh */ TListOfListOfElementsID aGroupsOfElementsID; FindEqualElements(aMeshElements, aGroupsOfElementsID); MergeElements(aGroupsOfElementsID); @@ -5479,83 +7571,65 @@ void SMESH_MeshEditor::MergeEqualElements() //purpose : Return a face having linked nodes n1 and n2 and which is // - not in avoidSet, // - in elemSet provided that !elemSet.empty() +// i1 and i2 optionally returns indices of n1 and n2 //======================================================================= const SMDS_MeshElement* - SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1, - const SMDS_MeshNode* n2, - const TIDSortedElemSet& elemSet, - const TIDSortedElemSet& avoidSet) +SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1, + const SMDS_MeshNode* n2, + const TIDSortedElemSet& elemSet, + const TIDSortedElemSet& avoidSet, + int* n1ind, + int* n2ind) { + int i1, i2; + const SMDS_MeshElement* face = 0; + SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face); - while ( invElemIt->more() ) { // loop on inverse elements of n1 + while ( invElemIt->more() && !face ) // loop on inverse faces of n1 + { const SMDS_MeshElement* elem = invElemIt->next(); - if (avoidSet.find( elem ) != avoidSet.end() ) + if (avoidSet.count( elem )) continue; - if ( !elemSet.empty() && elemSet.find( elem ) == elemSet.end()) + if ( !elemSet.empty() && !elemSet.count( elem )) continue; - // get face nodes and find index of n1 - int i1, nbN = elem->NbNodes(), iNode = 0; - //const SMDS_MeshNode* faceNodes[ nbN ], *n; - vector faceNodes( nbN ); - const SMDS_MeshNode* n; - SMDS_ElemIteratorPtr nIt = elem->nodesIterator(); - while ( nIt->more() ) { - faceNodes[ iNode ] = static_cast( nIt->next() ); - if ( faceNodes[ iNode++ ] == n1 ) - i1 = iNode - 1; - } + // index of n1 + i1 = elem->GetNodeIndex( n1 ); // find a n2 linked to n1 - if(!elem->IsQuadratic()) { - for ( iNode = 0; iNode < 2; iNode++ ) { - if ( iNode ) // node before n1 - n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ]; - else // node after n1 - n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ]; - if ( n == n2 ) - return elem; - } - } - else { // analysis for quadratic elements - bool IsFind = false; - // check using only corner nodes - for ( iNode = 0; iNode < 2; iNode++ ) { - if ( iNode ) // node before n1 - n = faceNodes[ i1 == 0 ? nbN/2 - 1 : i1 - 1 ]; - else // node after n1 - n = faceNodes[ i1 + 1 == nbN/2 ? 0 : i1 + 1 ]; - if ( n == n2 ) - IsFind = true; - } - if(IsFind) { - return elem; - } - else { - // check using all nodes - const SMDS_QuadraticFaceOfNodes* F = - static_cast(elem); - // use special nodes iterator - iNode = 0; - SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator(); - while ( anIter->more() ) { - faceNodes[iNode] = static_cast(anIter->next()); - if ( faceNodes[ iNode++ ] == n1 ) - i1 = iNode - 1; - } - for ( iNode = 0; iNode < 2; iNode++ ) { - if ( iNode ) // node before n1 - n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ]; - else // node after n1 - n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ]; - if ( n == n2 ) { - return elem; - } + int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes(); + for ( int di = -1; di < 2 && !face; di += 2 ) + { + i2 = (i1+di+nbN) % nbN; + if ( elem->GetNode( i2 ) == n2 ) + face = elem; + } + if ( !face && elem->IsQuadratic()) + { + // analysis for quadratic elements using all nodes + const SMDS_QuadraticFaceOfNodes* F = + static_cast(elem); + // use special nodes iterator + SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator(); + const SMDS_MeshNode* prevN = cast2Node( anIter->next() ); + for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ ) + { + const SMDS_MeshNode* n = cast2Node( anIter->next() ); + if ( n1 == prevN && n2 == n ) + { + face = elem; + } + else if ( n2 == prevN && n1 == n ) + { + face = elem; swap( i1, i2 ); } + prevN = n; } - } // end analysis for quadratic elements + } } - return 0; + if ( n1ind ) *n1ind = i1; + if ( n2ind ) *n2ind = i2; + return face; } //======================================================================= @@ -5599,7 +7673,7 @@ bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirst //vector nodes; const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode; - set < const SMDS_MeshElement* > foundElems; + TIDSortedElemSet foundElems; bool needTheLast = ( theLastNode != 0 ); while ( nStart != theLastNode ) { @@ -5618,7 +7692,7 @@ bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirst int iNode = 0, nbNodes = e->NbNodes(); //const SMDS_MeshNode* nodes[nbNodes+1]; vector nodes(nbNodes+1); - + if(e->IsQuadratic()) { const SMDS_QuadraticFaceOfNodes* F = static_cast(e); @@ -5738,15 +7812,15 @@ bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1, //======================================================================= SMESH_MeshEditor::Sew_Error - SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode, - const SMDS_MeshNode* theBordSecondNode, - const SMDS_MeshNode* theBordLastNode, - const SMDS_MeshNode* theSideFirstNode, - const SMDS_MeshNode* theSideSecondNode, - const SMDS_MeshNode* theSideThirdNode, - const bool theSideIsFreeBorder, - const bool toCreatePolygons, - const bool toCreatePolyedrs) +SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode, + const SMDS_MeshNode* theBordSecondNode, + const SMDS_MeshNode* theBordLastNode, + const SMDS_MeshNode* theSideFirstNode, + const SMDS_MeshNode* theSideSecondNode, + const SMDS_MeshNode* theSideThirdNode, + const bool theSideIsFreeBorder, + const bool toCreatePolygons, + const bool toCreatePolyedrs) { myLastCreatedElems.Clear(); myLastCreatedNodes.Clear(); @@ -6000,7 +8074,7 @@ SMESH_MeshEditor::Sew_Error TListOfListOfNodes nodeGroupsToMerge; if ( nbNodes[0] == nbNodes[1] || - ( theSideIsFreeBorder && !theSideThirdNode)) { + ( theSideIsFreeBorder && !theSideThirdNode)) { // all nodes are to be merged @@ -6626,7 +8700,7 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, int nbElem = 0; if( !theSm ) return nbElem; - const bool notFromGroups = false; + vector nbNodeInFaces; SMDS_ElemIteratorPtr ElemItr = theSm->GetElements(); while(ElemItr->more()) { @@ -6636,59 +8710,61 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, int id = elem->GetID(); int nbNodes = elem->NbNodes(); - vector aNds (nbNodes); - - for(int i = 0; i < nbNodes; i++) - { - aNds[i] = elem->GetNode(i); - } SMDSAbs_ElementType aType = elem->GetType(); - GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups); + vector nodes (elem->begin_nodes(), elem->end_nodes()); + if ( elem->GetEntityType() == SMDSEntity_Polyhedra ) + nbNodeInFaces = static_cast( elem )->GetQuanities(); + + GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false); const SMDS_MeshElement* NewElem = 0; switch( aType ) { case SMDSAbs_Edge : - { - NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d); - break; - } + { + NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d); + break; + } case SMDSAbs_Face : - { - switch(nbNodes) { - case 3: - NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d); - break; - case 4: - NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d); - break; - default: - continue; + switch(nbNodes) + { + case 3: + NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d); + break; + case 4: + NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d); + break; + default: + NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d); + continue; + } + break; } - break; - } case SMDSAbs_Volume : - { - switch(nbNodes) { - case 4: - NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d); - break; - case 6: - NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d); - break; - case 8: - NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], - aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d); - break; - default: - continue; + switch(nbNodes) + { + case 4: + NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d); + break; + case 5: + NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d); + break; + case 6: + NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d); + break; + case 8: + NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], + nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d); + break; + default: + NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d); + } + break; } - break; - } default : continue; } @@ -6709,7 +8785,6 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d) SMESH_MesherHelper aHelper(*myMesh); aHelper.SetIsQuadratic( true ); - const bool notFromGroups = false; int nbCheckedElems = 0; if ( myMesh->HasShapeToMesh() ) @@ -6736,11 +8811,11 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d) const SMDS_MeshEdge* edge = aEdgeItr->next(); if(edge && !edge->IsQuadratic()) { - int id = edge->GetID(); - const SMDS_MeshNode* n1 = edge->GetNode(0); - const SMDS_MeshNode* n2 = edge->GetNode(1); + int id = edge->GetID(); + const SMDS_MeshNode* n1 = edge->GetNode(0); + const SMDS_MeshNode* n2 = edge->GetNode(1); - meshDS->RemoveFreeElement(edge, smDS, notFromGroups); + meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false); const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d); ReplaceElemInGroups( edge, NewEdge, GetMeshDS()); @@ -6754,29 +8829,25 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d) int id = face->GetID(); int nbNodes = face->NbNodes(); - vector aNds (nbNodes); - - for(int i = 0; i < nbNodes; i++) - { - aNds[i] = face->GetNode(i); - } + vector nodes ( face->begin_nodes(), face->end_nodes()); - meshDS->RemoveFreeElement(face, smDS, notFromGroups); + meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false); SMDS_MeshFace * NewFace = 0; switch(nbNodes) { case 3: - NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d); - break; + NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d); + break; case 4: - NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d); - break; + NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d); + break; default: - continue; + NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d); } ReplaceElemInGroups( face, NewFace, GetMeshDS()); } + vector nbNodeInFaces; SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator(); while(aVolumeItr->more()) { @@ -6785,36 +8856,43 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d) int id = volume->GetID(); int nbNodes = volume->NbNodes(); - vector aNds (nbNodes); - - for(int i = 0; i < nbNodes; i++) - { - aNds[i] = volume->GetNode(i); - } + vector nodes (volume->begin_nodes(), volume->end_nodes()); + if ( volume->GetEntityType() == SMDSEntity_Polyhedra ) + nbNodeInFaces = static_cast(volume)->GetQuanities(); - meshDS->RemoveFreeElement(volume, smDS, notFromGroups); + meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false); SMDS_MeshVolume * NewVolume = 0; switch(nbNodes) { case 4: - NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], - aNds[3], id, theForce3d ); - break; + NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], + nodes[3], id, theForce3d ); + break; + case 5: + NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], + nodes[3], nodes[4], id, theForce3d); + break; case 6: - NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], - aNds[3], aNds[4], aNds[5], id, theForce3d); - break; + NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], + nodes[3], nodes[4], nodes[5], id, theForce3d); + break; case 8: - NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], - aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d); - break; + NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], + nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d); + break; default: - continue; + NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d); } ReplaceElemInGroups(volume, NewVolume, meshDS); } } + + if ( !theForce3d && !getenv("NO_FixQuadraticElements")) + { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion + aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh + aHelper.FixQuadraticElements(); + } } //======================================================================= @@ -6840,29 +8918,29 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm, { int id = elem->GetID(); int nbNodes = elem->NbNodes(); - vector aNds, mediumNodes; - aNds.reserve( nbNodes ); + vector nodes, mediumNodes; + nodes.reserve( nbNodes ); mediumNodes.reserve( nbNodes ); for(int i = 0; i < nbNodes; i++) { - const SMDS_MeshNode* n = elem->GetNode(i); + const SMDS_MeshNode* n = elem->GetNode(i); - if( elem->IsMediumNode( n ) ) + if( elem->IsMediumNode( n ) ) mediumNodes.push_back( n ); - else - aNds.push_back( n ); + else + nodes.push_back( n ); } - if( aNds.empty() ) continue; + if( nodes.empty() ) continue; SMDSAbs_ElementType aType = elem->GetType(); //remove old quadratic element meshDS->RemoveFreeElement( elem, theSm, notFromGroups ); - SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id ); + SMDS_MeshElement * NewElem = AddElement( nodes, aType, false, id ); ReplaceElemInGroups(elem, NewElem, meshDS); if( theSm && NewElem ) - theSm->AddElement( NewElem ); + theSm->AddElement( NewElem ); // remove medium nodes vector::iterator nIt = mediumNodes.begin(); @@ -6874,7 +8952,7 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm, ( n->GetPosition()->GetShapeId() )); else meshDS->RemoveFreeNode( n, theSm ); - } + } } } } @@ -6900,7 +8978,7 @@ bool SMESH_MeshEditor::ConvertFromQuadratic() } } } - + int totalNbElems = GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes(); if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes @@ -6918,12 +8996,12 @@ bool SMESH_MeshEditor::ConvertFromQuadratic() //======================================================================= SMESH_MeshEditor::Sew_Error - SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, - TIDSortedElemSet& theSide2, - const SMDS_MeshNode* theFirstNode1, - const SMDS_MeshNode* theFirstNode2, - const SMDS_MeshNode* theSecondNode1, - const SMDS_MeshNode* theSecondNode2) +SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, + TIDSortedElemSet& theSide2, + const SMDS_MeshNode* theFirstNode1, + const SMDS_MeshNode* theFirstNode2, + const SMDS_MeshNode* theSecondNode1, + const SMDS_MeshNode* theSecondNode2) { myLastCreatedElems.Clear(); myLastCreatedNodes.Clear(); @@ -7162,40 +9240,40 @@ SMESH_MeshEditor::Sew_Error const SMDS_MeshElement* aFreeFace = freeFaceList.front(); faceSet->insert( aFreeFace ); // complete a node set with nodes of a found free face -// for ( iNode = 0; iNode < ; iNode++ ) -// nodeSet->insert( fNodes[ iNode ] ); + // for ( iNode = 0; iNode < ; iNode++ ) + // nodeSet->insert( fNodes[ iNode ] ); } } // loop on volumes of a side -// // complete a set of faces if new nodes in a nodeSet appeared -// // ---------------------------------------------------------- -// if ( nodeSetSize != nodeSet->size() ) { -// for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide -// SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face); -// while ( fIt->more() ) { // loop on faces sharing a node -// const SMDS_MeshElement* f = fIt->next(); -// if ( faceSet->find( f ) == faceSet->end() ) { -// // check if all nodes are in nodeSet and -// // complete setOfFaceNodeSet if they are -// set faceNodeSet; -// SMDS_ElemIteratorPtr nodeIt = f->nodesIterator(); -// bool allInSet = true; -// while ( nodeIt->more() && allInSet ) { // loop on nodes of a face -// const SMDS_MeshNode* n = static_cast( nodeIt->next() ); -// if ( nodeSet->find( n ) == nodeSet->end() ) -// allInSet = false; -// else -// faceNodeSet.insert( n ); -// } -// if ( allInSet ) { -// faceSet->insert( f ); -// setOfFaceNodeSet.insert( faceNodeSet ); -// } -// } -// } -// } -// } + // // complete a set of faces if new nodes in a nodeSet appeared + // // ---------------------------------------------------------- + // if ( nodeSetSize != nodeSet->size() ) { + // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide + // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face); + // while ( fIt->more() ) { // loop on faces sharing a node + // const SMDS_MeshElement* f = fIt->next(); + // if ( faceSet->find( f ) == faceSet->end() ) { + // // check if all nodes are in nodeSet and + // // complete setOfFaceNodeSet if they are + // set faceNodeSet; + // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator(); + // bool allInSet = true; + // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face + // const SMDS_MeshNode* n = static_cast( nodeIt->next() ); + // if ( nodeSet->find( n ) == nodeSet->end() ) + // allInSet = false; + // else + // faceNodeSet.insert( n ); + // } + // if ( allInSet ) { + // faceSet->insert( f ); + // setOfFaceNodeSet.insert( faceNodeSet ); + // } + // } + // } + // } + // } } // Create temporary faces, if there are volumes given } // loop on sides @@ -7301,10 +9379,10 @@ SMESH_MeshEditor::Sew_Error nbl++; if(iSide==0) notLinkNodes1[nbl] = n; - //notLinkNodes1.push_back(n); + //notLinkNodes1.push_back(n); else notLinkNodes2[nbl] = n; - //notLinkNodes2.push_back(n); + //notLinkNodes2.push_back(n); } //faceNodes[ iSide ][ iNode++ ] = n; if(iSide==0) { @@ -7385,7 +9463,7 @@ SMESH_MeshEditor::Sew_Error //nReplaceMap.insert( TNodeNodeMap::value_type // ( notLinkNodes[0][0], notLinkNodes[1][0] )); nReplaceMap.insert( TNodeNodeMap::value_type - ( notLinkNodes1[0], notLinkNodes2[0] )); + ( notLinkNodes1[0], notLinkNodes2[0] )); } else { for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides @@ -7406,7 +9484,7 @@ SMESH_MeshEditor::Sew_Error // ( notLinkNodes[0][1], notLinkNodes[1][1] )); for(int nn=0; nnempty() || !faceSetPtr[1]->empty() )) { + ( linkIt[0] != linkList[0].end() || + !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) { MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) << - " " << (faceSetPtr[1]->empty())); + " " << (faceSetPtr[1]->empty())); aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS; } @@ -7504,17 +9582,17 @@ SMESH_MeshEditor::Sew_Error } //================================================================================ - /*! - * \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 - */ +/*! + * \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 + */ //================================================================================ #ifdef _DEBUG_ @@ -7631,8 +9709,8 @@ SMESH_MeshEditor::FindMatchingNodes(set& theSide1, } #ifdef DEBUG_MATCHING_NODES MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID() - << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" " - << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ; + << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" " + << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ; #endif int nbN = nbNodes[0]; { @@ -7663,7 +9741,7 @@ SMESH_MeshEditor::FindMatchingNodes(set& theSide1, { #ifdef DEBUG_MATCHING_NODES MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " " - << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " ); + << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " ); #endif linkList[0].push_back ( NLink( n1, n2 )); linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] )); @@ -7676,6 +9754,105 @@ SMESH_MeshEditor::FindMatchingNodes(set& theSide1, return SEW_OK; } +//================================================================================ +/*! + \brief Creates a hole in a mesh by doubling the nodes of some particular elements + \param theElems - the list of elements (edges or faces) to be replicated + The nodes for duplication could be found from these elements + \param theNodesNot - list of nodes to NOT replicate + \param theAffectedElems - the list of elements (cells and edges) to which the + replicated nodes should be associated to. + \return TRUE if operation has been completed successfully, FALSE otherwise +*/ +//================================================================================ + +bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems, + const TIDSortedElemSet& theNodesNot, + const TIDSortedElemSet& theAffectedElems ) +{ + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + + if ( theElems.size() == 0 ) + return false; + + SMESHDS_Mesh* aMeshDS = GetMeshDS(); + if ( !aMeshDS ) + return false; + + bool res = false; + std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode; + // duplicate elements and nodes + res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true ); + // replce nodes by duplications + res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false ); + return res; +} + +//================================================================================ +/*! + \brief Creates a hole in a mesh by doubling the nodes of some particular elements + \param theMeshDS - mesh instance + \param theElems - the elements replicated or modified (nodes should be changed) + \param theNodesNot - nodes to NOT replicate + \param theNodeNodeMap - relation of old node to new created node + \param theIsDoubleElem - flag os to replicate element or modify + \return TRUE if operation has been completed successfully, FALSE otherwise +*/ +//================================================================================ + +bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS, + const TIDSortedElemSet& theElems, + const TIDSortedElemSet& theNodesNot, + std::map< const SMDS_MeshNode*, + const SMDS_MeshNode* >& theNodeNodeMap, + const bool theIsDoubleElem ) +{ + // iterate on through element and duplicate them (by nodes duplication) + bool res = false; + TIDSortedElemSet::const_iterator elemItr = theElems.begin(); + for ( ; elemItr != theElems.end(); ++elemItr ) + { + const SMDS_MeshElement* anElem = *elemItr; + if (!anElem) + continue; + + bool isDuplicate = false; + // duplicate nodes to duplicate element + std::vector newNodes( anElem->NbNodes() ); + SMDS_ElemIteratorPtr anIter = anElem->nodesIterator(); + int ind = 0; + while ( anIter->more() ) + { + + SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next(); + SMDS_MeshNode* aNewNode = aCurrNode; + if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() ) + aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ]; + else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() ) + { + // duplicate node + aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() ); + theNodeNodeMap[ aCurrNode ] = aNewNode; + myLastCreatedNodes.Append( aNewNode ); + } + isDuplicate |= (aCurrNode != aNewNode); + newNodes[ ind++ ] = aNewNode; + } + if ( !isDuplicate ) + continue; + + if ( theIsDoubleElem ) + AddElement(newNodes, anElem->GetType(), anElem->IsPoly()); + else + theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() ); + + res = true; + } + return res; +} + +//================================================================================ /*! \brief Creates a hole in a mesh by doubling the nodes of some particular elements \param theNodes - identifiers of nodes to be doubled @@ -7684,6 +9861,8 @@ SMESH_MeshEditor::FindMatchingNodes(set& theSide1, they not assigned to elements \return TRUE if operation has been completed successfully, FALSE otherwise */ +//================================================================================ + bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, const std::list< int >& theListOfModifiedElems ) { @@ -7764,3 +9943,362 @@ bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, return true; } + +namespace { + + //================================================================================ + /*! + \brief Check if element located inside shape + \return TRUE if IN or ON shape, FALSE otherwise + */ + //================================================================================ + + template + bool isInside(const SMDS_MeshElement* theElem, + Classifier& theClassifier, + const double theTol) + { + gp_XYZ centerXYZ (0, 0, 0); + SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator(); + while (aNodeItr->more()) + centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next())); + + gp_Pnt aPnt = centerXYZ / theElem->NbNodes(); + theClassifier.Perform(aPnt, theTol); + TopAbs_State aState = theClassifier.State(); + return (aState == TopAbs_IN || aState == TopAbs_ON ); + } + + //================================================================================ + /*! + * \brief Classifier of the 3D point on the TopoDS_Face + * with interaface suitable for isInside() + */ + //================================================================================ + + struct _FaceClassifier + { + Extrema_ExtPS _extremum; + BRepAdaptor_Surface _surface; + TopAbs_State _state; + + _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT) + { + _extremum.Initialize( _surface, + _surface.FirstUParameter(), _surface.LastUParameter(), + _surface.FirstVParameter(), _surface.LastVParameter(), + _surface.Tolerance(), _surface.Tolerance() ); + } + void Perform(const gp_Pnt& aPnt, double theTol) + { + _state = TopAbs_OUT; + _extremum.Perform(aPnt); + if ( _extremum.IsDone() ) + for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol) + _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT ); + } + TopAbs_State State() const + { + return _state; + } + }; +} + +//================================================================================ +/*! + \brief Creates a hole in a mesh by doubling the nodes of some particular elements + \param theElems - group of of elements (edges or faces) to be replicated + \param theNodesNot - group of nodes not to replicate + \param theShape - shape to detect affected elements (element which geometric center + located on or inside shape). + The replicated nodes should be associated to affected elements. + \return TRUE if operation has been completed successfully, FALSE otherwise +*/ +//================================================================================ + +bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems, + const TIDSortedElemSet& theNodesNot, + const TopoDS_Shape& theShape ) +{ + if ( theShape.IsNull() ) + return false; + + const double aTol = Precision::Confusion(); + auto_ptr< BRepClass3d_SolidClassifier> bsc3d; + auto_ptr<_FaceClassifier> aFaceClassifier; + if ( theShape.ShapeType() == TopAbs_SOLID ) + { + bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));; + bsc3d->PerformInfinitePoint(aTol); + } + else if (theShape.ShapeType() == TopAbs_FACE ) + { + aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape))); + } + + // iterates on indicated elements and get elements by back references from their nodes + TIDSortedElemSet anAffected; + TIDSortedElemSet::const_iterator elemItr = theElems.begin(); + for ( ; elemItr != theElems.end(); ++elemItr ) + { + SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr; + if (!anElem) + continue; + + SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator(); + while ( nodeItr->more() ) + { + const SMDS_MeshNode* aNode = cast2Node(nodeItr->next()); + if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() ) + continue; + SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator(); + while ( backElemItr->more() ) + { + const SMDS_MeshElement* curElem = backElemItr->next(); + if ( curElem && theElems.find(curElem) == theElems.end() && + ( bsc3d.get() ? + isInside( curElem, *bsc3d, aTol ) : + isInside( curElem, *aFaceClassifier, aTol ))) + anAffected.insert( curElem ); + } + } + } + return DoubleNodes( theElems, theNodesNot, anAffected ); +} + +//================================================================================ +/*! + * \brief Generates skin mesh (containing 2D cells) from 3D mesh + * The created 2D mesh elements based on nodes of free faces of boundary volumes + * \return TRUE if operation has been completed successfully, FALSE otherwise + */ +//================================================================================ + +bool SMESH_MeshEditor::Make2DMeshFrom3D() +{ + // iterates on volume elements and detect all free faces on them + SMESHDS_Mesh* aMesh = GetMeshDS(); + if (!aMesh) + return false; + //bool res = false; + int nbFree = 0, nbExisted = 0, nbCreated = 0; + SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator(); + while(vIt->more()) + { + const SMDS_MeshVolume* volume = vIt->next(); + SMDS_VolumeTool vTool( volume ); + vTool.SetExternalNormal(); + const bool isPoly = volume->IsPoly(); + const bool isQuad = volume->IsQuadratic(); + for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ ) + { + if (!vTool.IsFreeFace(iface)) + continue; + nbFree++; + vector nodes; + int nbFaceNodes = vTool.NbFaceNodes(iface); + const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface); + int inode = 0; + for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1) + nodes.push_back(faceNodes[inode]); + if (isQuad) + for ( inode = 1; inode < nbFaceNodes; inode += 2) + nodes.push_back(faceNodes[inode]); + + // add new face based on volume nodes + if (aMesh->FindFace( nodes ) ) { + nbExisted++; + continue; // face already exsist + } + AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1); + nbCreated++; + } + } + return ( nbFree==(nbExisted+nbCreated) ); +} + +namespace +{ + inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node) + { + if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() )) + return n; + return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() ); + } +} +//================================================================================ +/*! + * \brief Creates missing boundary elements + * \param elements - elements whose boundary is to be checked + * \param dimension - defines type of boundary elements to create + * \param group - a group to store created boundary elements in + * \param targetMesh - a mesh to store created boundary elements in + * \param toCopyElements - if true, the checked elements will be copied into the targetMesh + * \param toCopyExistingBondary - if true, not only new but also pre-existing + * boundary elements will be copied into the targetMesh + */ +//================================================================================ + +void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, + Bnd_Dimension dimension, + SMESH_Group* group/*=0*/, + SMESH_Mesh* targetMesh/*=0*/, + bool toCopyElements/*=false*/, + bool toCopyExistingBondary/*=false*/) +{ + SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge; + SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume; + // hope that all elements are of the same type, do not check them all + if ( !elements.empty() && (*elements.begin())->GetType() != elemType ) + throw SALOME_Exception(LOCALIZED("wrong element type")); + + if ( !targetMesh ) + toCopyElements = toCopyExistingBondary = false; + + SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh ); + SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS(); + + SMDS_VolumeTool vTool; + TIDSortedElemSet emptySet, avoidSet; + int inode; + + typedef vector TConnectivity; + + SMDS_ElemIteratorPtr eIt; + if (elements.empty()) + eIt = aMesh->elementsIterator(elemType); + else + eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() )); + + while (eIt->more()) + { + const SMDS_MeshElement* elem = eIt->next(); + const int iQuad = elem->IsQuadratic(); + + // 1. For an elem, get present bnd elements and connectivities of missing bnd elements + vector presentBndElems; + vector missingBndElems; + TConnectivity nodes; + if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------ + { + vTool.SetExternalNormal(); + for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ ) + { + if (!vTool.IsFreeFace(iface)) + continue; + int nbFaceNodes = vTool.NbFaceNodes(iface); + const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface); + if ( missType == SMDSAbs_Edge ) // boundary edges + { + nodes.resize( 2+iQuad ); + for ( int i = 0; i < nbFaceNodes; i += 1+iQuad) + { + for ( int j = 0; j < nodes.size(); ++j ) + nodes[j] =nn[i+j]; + if ( const SMDS_MeshElement* edge = + aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0)) + presentBndElems.push_back( edge ); + else + missingBndElems.push_back( nodes ); + } + } + else // boundary face + { + nodes.clear(); + for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad) + nodes.push_back( nn[inode] ); + if (iQuad) + for ( inode = 1; inode < nbFaceNodes; inode += 2) + nodes.push_back( nn[inode] ); + + if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) ) + presentBndElems.push_back( f ); + else + missingBndElems.push_back( nodes ); + } + } + } + else // elem is a face ------------------------------------------ + { + avoidSet.clear(), avoidSet.insert( elem ); + int nbNodes = elem->NbCornerNodes(); + nodes.resize( 2 /*+ iQuad*/); + for ( int i = 0; i < nbNodes; i++ ) + { + nodes[0] = elem->GetNode(i); + nodes[1] = elem->GetNode((i+1)%nbNodes); + if ( FindFaceInSet( nodes[0], nodes[1], emptySet, avoidSet)) + continue; // not free link + + //if ( iQuad ) + //nodes[2] = elem->GetNode( i + nbNodes ); + if ( const SMDS_MeshElement* edge = + aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true)) + presentBndElems.push_back( edge ); + else + missingBndElems.push_back( nodes ); + } + } + + // 2. Add missing boundary elements + if ( targetMesh != myMesh ) + // instead of making a map of nodes in this mesh and targetMesh, + // we create nodes with same IDs. We can renumber them later, if needed + for ( int i = 0; i < missingBndElems.size(); ++i ) + { + TConnectivity& srcNodes = missingBndElems[i]; + TConnectivity nodes( srcNodes.size() ); + for ( inode = 0; inode < nodes.size(); ++inode ) + nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] ); + tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4); + } + else + for ( int i = 0; i < missingBndElems.size(); ++i ) + { + TConnectivity& nodes = missingBndElems[i]; + tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4); + } + + // 3. Copy present boundary elements + if ( toCopyExistingBondary ) + for ( int i = 0 ; i < presentBndElems.size(); ++i ) + { + const SMDS_MeshElement* e = presentBndElems[i]; + TConnectivity nodes( e->NbNodes() ); + for ( inode = 0; inode < nodes.size(); ++inode ) + nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) ); + tgtEditor.AddElement(nodes, missType, e->IsPoly()); + // leave only missing elements in tgtEditor.myLastCreatedElems + tgtEditor.myLastCreatedElems.Remove( tgtEditor.myLastCreatedElems.Size() ); + } + } // loop on given elements + + // 4. Fill group with missing boundary elements + if ( group ) + { + if ( SMESHDS_Group* g = dynamic_cast( group->GetGroupDS() )) + for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i ) + g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 )); + } + tgtEditor.myLastCreatedElems.Clear(); + + // 5. Copy given elements + if ( toCopyElements ) + { + if (elements.empty()) + eIt = aMesh->elementsIterator(elemType); + else + eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() )); + while (eIt->more()) + { + const SMDS_MeshElement* elem = eIt->next(); + TConnectivity nodes( elem->NbNodes() ); + for ( inode = 0; inode < nodes.size(); ++inode ) + nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) ); + tgtEditor.AddElement(nodes, elemType, elem->IsPoly()); + + tgtEditor.myLastCreatedElems.Clear(); + } + } + return; +}