X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSMESH%2FSMESH_MeshEditor.cxx;h=191d7a4b33b32cb66af64a67dc43f56d9ea22d78;hb=462f12d6107310b1375c9105d1ebe4665f2de226;hp=8bb6d8c780f4b356d00d32d03ae9ed1523d6a666;hpb=33fc29c42a41139519566e0044e9abe0ef403367;p=modules%2Fsmesh.git diff --git a/src/SMESH/SMESH_MeshEditor.cxx b/src/SMESH/SMESH_MeshEditor.cxx index 8bb6d8c78..191d7a4b3 100644 --- a/src/SMESH/SMESH_MeshEditor.cxx +++ b/src/SMESH/SMESH_MeshEditor.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2011 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2012 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 @@ -18,22 +18,19 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // 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 // Author : Edward AGAPOV (eap) -#define CHRONODEF #include "SMESH_MeshEditor.hxx" #include "SMDS_FaceOfNodes.hxx" #include "SMDS_VolumeTool.hxx" #include "SMDS_EdgePosition.hxx" -#include "SMDS_PolyhedralVolumeOfNodes.hxx" #include "SMDS_FacePosition.hxx" #include "SMDS_SpacePosition.hxx" -//#include "SMDS_QuadraticFaceOfNodes.hxx" #include "SMDS_MeshGroup.hxx" #include "SMDS_LinearEdge.hxx" #include "SMDS_Downward.hxx" @@ -54,6 +51,7 @@ #include "utilities.h" #include +#include #include #include #include @@ -79,6 +77,7 @@ #include #include #include +#include #include #include #include @@ -89,7 +88,7 @@ #include #include -#include +#include #include #include @@ -98,6 +97,9 @@ #include #include +#include +#include + #define cast2Node(elem) static_cast( elem ) using namespace std; @@ -118,6 +120,19 @@ SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh ) { } +//================================================================================ +/*! + * \brief Clears myLastCreatedNodes and myLastCreatedElems + */ +//================================================================================ + +void SMESH_MeshEditor::CrearLastCreated() +{ + myLastCreatedNodes.Clear(); + myLastCreatedElems.Clear(); +} + + //======================================================================= /*! * \brief Add element @@ -128,7 +143,8 @@ SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector & node, const SMDSAbs_ElementType type, const bool isPoly, - const int ID) + const int ID, + const double ballDiameter) { //MESSAGE("AddElement " < & node, else e = mesh->AddFace (node[0], node[1], node[2], node[3], node[4], node[5], node[6], node[7] ); } + else if (nbnode == 9) { + if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], + node[4], node[5], node[6], node[7], node[8], ID); + else e = mesh->AddFace (node[0], node[1], node[2], node[3], + node[4], node[5], node[6], node[7], node[8] ); + } } else { if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID); else e = mesh->AddPolygonalFace (node ); @@ -195,6 +217,14 @@ SMESH_MeshEditor::AddElement(const vector & node, node[4], node[5], node[6], node[7], node[8], node[9] ); } + else if (nbnode == 12) { + if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], + node[4], node[5], node[6], node[7], + node[8], node[9], node[10], node[11], ID); + else e = mesh->AddVolume (node[0], node[1], node[2], node[3], + node[4], node[5], node[6], node[7], + node[8], node[9], node[10], node[11] ); + } else if (nbnode == 13) { if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], node[4], node[5], node[6], node[7], @@ -227,6 +257,22 @@ SMESH_MeshEditor::AddElement(const vector & node, node[12],node[13],node[14],node[15], node[16],node[17],node[18],node[19] ); } + else if (nbnode == 27) { + if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], + node[4], node[5], node[6], node[7], + node[8], node[9], node[10],node[11], + node[12],node[13],node[14],node[15], + node[16],node[17],node[18],node[19], + node[20],node[21],node[22],node[23], + node[24],node[25],node[26], ID); + else e = mesh->AddVolume (node[0], node[1], node[2], node[3], + node[4], node[5], node[6], node[7], + node[8], node[9], node[10],node[11], + node[12],node[13],node[14],node[15], + node[16],node[17],node[18],node[19], + node[20],node[21],node[22],node[23], + node[24],node[25],node[26] ); + } } break; @@ -253,6 +299,11 @@ SMESH_MeshEditor::AddElement(const vector & node, else e = mesh->AddNode (node[0]->X(), node[0]->Y(), node[0]->Z()); break; + case SMDSAbs_Ball: + if ( ID >= 1 ) e = mesh->AddBallWithID(node[0], ballDiameter, ID); + else e = mesh->AddBall (node[0], ballDiameter); + break; + default:; } if ( e ) myLastCreatedElems.Append( e ); @@ -351,6 +402,44 @@ int SMESH_MeshEditor::Remove (const list< int >& theIDs, return removed; } +//================================================================================ +/*! + * \brief Create 0D elements on all nodes of the given object except those + * nodes on which a 0D element already exists. + * \param elements - Elements on whose nodes to create 0D elements; if empty, + * the all mesh is treated + * \param all0DElems - returns all 0D elements found or created on nodes of \a elements + */ +//================================================================================ + +void SMESH_MeshEditor::Create0DElementsOnAllNodes( const TIDSortedElemSet& elements, + TIDSortedElemSet& all0DElems ) +{ + typedef SMDS_SetIterator TSetIterator; + SMDS_ElemIteratorPtr elemIt; + if ( elements.empty() ) + elemIt = GetMeshDS()->elementsIterator( SMDSAbs_Node ); + else + elemIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() )); + + while ( elemIt->more() ) + { + const SMDS_MeshElement* e = elemIt->next(); + SMDS_ElemIteratorPtr nodeIt = e->nodesIterator(); + while ( nodeIt->more() ) + { + const SMDS_MeshNode* n = cast2Node( nodeIt->next() ); + SMDS_ElemIteratorPtr it0D = n->GetInverseElementIterator( SMDSAbs_0DElement ); + if ( it0D->more() ) + all0DElems.insert( it0D->next() ); + else { + myLastCreatedElems.Append( GetMeshDS()->Add0DElement( n )); + all0DElems.insert( myLastCreatedElems.Last() ); + } + } + } +} + //======================================================================= //function : FindShape //purpose : Return an index of the shape theElem is on @@ -456,6 +545,25 @@ static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[]) aNodes[5] = nd2; } +//======================================================================= +//function : edgeConnectivity +//purpose : auxilary +// return number of the edges connected with the theNode. +// if theEdges has connections with the other type of the +// elements, return -1 +//======================================================================= +static int nbEdgeConnectivity(const SMDS_MeshNode* theNode) +{ + SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(); + int nb=0; + while(elemIt->more()) { + elemIt->next(); + nb++; + } + return nb; +} + + //======================================================================= //function : GetNodesFromTwoTria //purpose : auxilary @@ -1003,6 +1111,135 @@ bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem) return false; } +//================================================================================ +/*! + * \brief Reorient faces. + * \param theFaces - the faces to reorient. If empty the whole mesh is meant + * \param theDirection - desired direction of normal of \a theFace + * \param theFace - one of \a theFaces that sould be oriented according to + * \a theDirection and whose orientation defines orientation of other faces + * \return number of reoriented faces. + */ +//================================================================================ + +int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet & theFaces, + const gp_Dir& theDirection, + const SMDS_MeshElement * theFace) +{ + int nbReori = 0; + if ( !theFace || theFace->GetType() != SMDSAbs_Face ) return nbReori; + + if ( theFaces.empty() ) + { + SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator(/*idInceasingOrder=*/true); + while ( fIt->more() ) + theFaces.insert( theFaces.end(), fIt->next() ); + } + + // orient theFace according to theDirection + gp_XYZ normal; + SMESH_Algo::FaceNormal( theFace, normal, /*normalized=*/false ); + if ( normal * theDirection.XYZ() < 0 ) + nbReori += Reorient( theFace ); + + // Orient other faces + + set< const SMDS_MeshElement* > startFaces, visitedFaces; + TIDSortedElemSet avoidSet; + set< SMESH_TLink > checkedLinks; + pair< set< SMESH_TLink >::iterator, bool > linkIt_isNew; + + if ( theFaces.size() > 1 )// leave 1 face to prevent finding not selected faces + theFaces.erase( theFace ); + startFaces.insert( theFace ); + + int nodeInd1, nodeInd2; + const SMDS_MeshElement* otherFace; + vector< const SMDS_MeshElement* > facesNearLink; + vector< std::pair< int, int > > nodeIndsOfFace; + + set< const SMDS_MeshElement* >::iterator startFace = startFaces.begin(); + while ( !startFaces.empty() ) + { + startFace = startFaces.begin(); + theFace = *startFace; + startFaces.erase( startFace ); + if ( !visitedFaces.insert( theFace ).second ) + continue; + + avoidSet.clear(); + avoidSet.insert(theFace); + + NLink link( theFace->GetNode( 0 ), 0 ); + + const int nbNodes = theFace->NbCornerNodes(); + for ( int i = 0; i < nbNodes; ++i ) // loop on links of theFace + { + link.second = theFace->GetNode(( i+1 ) % nbNodes ); + linkIt_isNew = checkedLinks.insert( link ); + if ( !linkIt_isNew.second ) + { + // link has already been checked and won't be encountered more + // if the group (theFaces) is manifold + //checkedLinks.erase( linkIt_isNew.first ); + } + else + { + facesNearLink.clear(); + nodeIndsOfFace.clear(); + while (( otherFace = FindFaceInSet( link.first, link.second, + theFaces, avoidSet, &nodeInd1, &nodeInd2 ))) + if ( otherFace != theFace) + { + facesNearLink.push_back( otherFace ); + nodeIndsOfFace.push_back( make_pair( nodeInd1, nodeInd2 )); + avoidSet.insert( otherFace ); + } + if ( facesNearLink.size() > 1 ) + { + // NON-MANIFOLD mesh shell ! + // select a face most co-directed with theFace, + // other faces won't be visited this time + gp_XYZ NF, NOF; + SMESH_Algo::FaceNormal( theFace, NF, /*normalized=*/false ); + double proj, maxProj = -1; + for ( size_t i = 0; i < facesNearLink.size(); ++i ) { + SMESH_Algo::FaceNormal( facesNearLink[i], NOF, /*normalized=*/false ); + if (( proj = Abs( NF * NOF )) > maxProj ) { + maxProj = proj; + otherFace = facesNearLink[i]; + nodeInd1 = nodeIndsOfFace[i].first; + nodeInd2 = nodeIndsOfFace[i].second; + } + } + // not to visit rejected faces + for ( size_t i = 0; i < facesNearLink.size(); ++i ) + if ( facesNearLink[i] != otherFace && theFaces.size() > 1 ) + visitedFaces.insert( facesNearLink[i] ); + } + else if ( facesNearLink.size() == 1 ) + { + otherFace = facesNearLink[0]; + nodeInd1 = nodeIndsOfFace.back().first; + nodeInd2 = nodeIndsOfFace.back().second; + } + if ( otherFace && otherFace != theFace) + { + // link must be reverse in otherFace if orientation ot otherFace + // is same as that of theFace + if ( abs(nodeInd2-nodeInd1) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 ) + { + nbReori += Reorient( otherFace ); + } + startFaces.insert( otherFace ); + } + } + std::swap( link.first, link.second ); // reverse the link + } + } + return nbReori; +} + //======================================================================= //function : getBadRate //purpose : @@ -1045,15 +1282,11 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, const SMDS_MeshElement* elem = *itElem; if ( !elem || elem->GetType() != SMDSAbs_Face ) continue; - if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 )) + if ( elem->NbCornerNodes() != 4 ) continue; // retrieve element nodes - const SMDS_MeshNode* aNodes [8]; - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - int i = 0; - while ( itN->more() ) - aNodes[ i++ ] = static_cast( itN->next() ); + vector< const SMDS_MeshNode* > aNodes( elem->begin_nodes(), elem->end_nodes() ); // compare two sets of possible triangles double aBadRate1, aBadRate2; // to what extent a set is bad @@ -1072,6 +1305,8 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, if( !elem->IsQuadratic() ) { // split liner quadrangle + // for MaxElementLength2D functor we return minimum diagonal for splitting, + // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4) if ( aBadRate1 <= aBadRate2 ) { // tr1 + tr2 is better newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] ); @@ -1100,38 +1335,41 @@ bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems, helper.SetSubShape( shape ); } } - // get elem nodes - const SMDS_MeshNode* aNodes [8]; - const SMDS_MeshNode* inFaceNode = 0; - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - int i = 0; - while ( itN->more() ) { - aNodes[ i++ ] = static_cast( itN->next() ); - if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() && - aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) - { - inFaceNode = aNodes[ i-1 ]; - } - } // find middle point for (0,1,2,3) // and create a node in this point; - gp_XYZ p( 0,0,0 ); - if ( surface.IsNull() ) { - for(i=0; i<4; i++) - p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() ); - p /= 4; + const SMDS_MeshNode* newN = 0; + if ( aNodes.size() == 9 ) + { + // SMDSEntity_BiQuad_Quadrangle + newN = aNodes.back(); } - else { - TopoDS_Face face = TopoDS::Face( helper.GetSubShape() ); - gp_XY uv( 0,0 ); - for(i=0; i<4; i++) - uv += helper.GetNodeUV( face, aNodes[i], inFaceNode ); - uv /= 4.; - p = surface->Value( uv.X(), uv.Y() ).XYZ(); + else + { + gp_XYZ p( 0,0,0 ); + if ( surface.IsNull() ) + { + for ( int i = 0; i < 4; i++ ) + p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() ); + p /= 4; + } + else + { + const SMDS_MeshNode* inFaceNode = 0; + if ( helper.GetNodeUVneedInFaceNode() ) + for ( size_t i = 0; i < aNodes.size() && !inFaceNode; ++i ) + if ( aNodes[ i ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) + inFaceNode = aNodes[ i ]; + + TopoDS_Face face = TopoDS::Face( helper.GetSubShape() ); + gp_XY uv( 0,0 ); + for ( int i = 0; i < 4; i++ ) + uv += helper.GetNodeUV( face, aNodes[i], inFaceNode ); + uv /= 4.; + p = surface->Value( uv.X(), uv.Y() ).XYZ(); + } + newN = aMesh->AddNode( p.X(), p.Y(), p.Z() ); + myLastCreatedNodes.Append(newN); } - const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() ); - myLastCreatedNodes.Append(newN); - // create a new element if ( aBadRate1 <= aBadRate2 ) { newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0], @@ -1202,7 +1440,8 @@ int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad, SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] ); SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] ); aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit ); - + // for MaxElementLength2D functor we return minimum diagonal for splitting, + // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4) if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better return 1; // diagonal 1-3 @@ -1379,6 +1618,7 @@ namespace { case SMDSEntity_Hexa: case SMDSEntity_Quad_Hexa: + case SMDSEntity_TriQuad_Hexa: if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 ) connVariants = theHexTo5, nbTet = 5; else @@ -1420,13 +1660,15 @@ namespace // each facet of a volume is split into triangles and // each of triangles and a volume barycenter form a tetrahedron. + const bool isHex27 = ( vol.Element()->GetEntityType() == SMDSEntity_TriQuad_Hexa ); + int* connectivity = new int[ maxTetConnSize + 1 ]; method._connectivity = connectivity; method._ownConn = true; - method._baryNode = true; + method._baryNode = !isHex27; // to create central node or not int connSize = 0; - int baryCenInd = vol.NbNodes(); + int baryCenInd = vol.NbNodes() - int( isHex27 ); for ( int iF = 0; iF < vol.NbFaces(); ++iF ) { const int nbNodes = vol.NbFaceNodes( iF ) / iQ; @@ -1451,14 +1693,17 @@ namespace const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF ); int nbVariants = ( nbNodes == 4 ? 2 : nbNodes ); for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon ) + { + double badness = 0; 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 )); + badness += getBadRate( &tria, aspectRatio ); } + badness2iCommon.insert( make_pair( badness, iCommon )); + } // use iCommon with lowest badness iCommon = badness2iCommon.begin()->second; } @@ -1469,8 +1714,17 @@ namespace 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(); + int faceBaryCenInd; + if ( isHex27 ) + { + faceBaryCenInd = vol.GetCenterNodeIndex( iF ); + method._faceBaryNode[ iF ] = vol.GetNodes()[ faceBaryCenInd ]; + } + else + { + method._faceBaryNode[ iF ] = 0; + faceBaryCenInd = baryCenInd + method._faceBaryNode.size(); + } nbTet = nbNodes; for ( int i = 0; i < nbTet; ++i ) { @@ -1495,9 +1749,13 @@ namespace } } method._nbTetra += nbTet; - } + + } // loop on volume faces + connectivity[ connSize++ ] = -1; - } + + } // end of generic solution + return method; } //================================================================================ @@ -1516,16 +1774,18 @@ namespace while ( volIt1->more() ) { const SMDS_MeshElement* v = volIt1->next(); - if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra )) + SMDSAbs_EntityType type = v->GetEntityType(); + if ( type != SMDSEntity_Tetra && type != SMDSEntity_Quad_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; + if ( type == SMDSEntity_Quad_Tetra && v->GetNodeIndex( n1 ) > 3 ) + continue; // medium node not allowed + const int ind2 = v->GetNodeIndex( n2 ); + if ( ind2 < 0 || 3 < ind2 ) + continue; + const int ind3 = v->GetNodeIndex( n3 ); + if ( ind3 < 0 || 3 < ind3 ) + continue; + return true; } return false; } @@ -1536,7 +1796,7 @@ namespace */ //======================================================================= - struct TVolumeFaceKey: pair< int, pair< int, int> > + struct TVolumeFaceKey: pair< pair< int, int>, pair< int, int> > { TVolumeFaceKey( SMDS_VolumeTool& vol, int iF ) { @@ -1547,16 +1807,17 @@ namespace 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(); + first.first = (*(n++))->GetID(); + first.second = (*(n++))->GetID(); + second.first = (*(n++))->GetID(); + second.second = ( sortedNodes.size() > 3 ) ? (*(n++))->GetID() : 0; } }; } // namespace //======================================================================= //function : SplitVolumesIntoTetra -//purpose : Split volumic elements into tetrahedra. +//purpose : Split volume elements into tetrahedra. //======================================================================= void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, @@ -1571,7 +1832,7 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1); SMESHDS_SubMesh* fSubMesh = 0;//subMesh; - + SMESH_SequenceOfElemPtr newNodes, newElems; // map face of volume to it's baricenrtic node @@ -1581,11 +1842,13 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, TIDSortedElemSet::const_iterator elem = theElems.begin(); for ( ; elem != theElems.end(); ++elem ) { + if ( (*elem)->GetType() != SMDSAbs_Volume ) + continue; SMDSAbs_EntityType geomType = (*elem)->GetEntityType(); - if ( geomType <= SMDSEntity_Quad_Tetra ) - continue; // tetra or face or ... + if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra ) + continue; - if ( !volTool.Set( *elem )) continue; // not volume? strange... + if ( !volTool.Set( *elem, /*ignoreCentralNodes=*/false )) continue; // strange... TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags ); if ( splitMethod._nbTetra < 1 ) continue; @@ -1605,8 +1868,9 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, 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] ); + int nbN = volTool.NbFaceNodes( iF ) - bool( volTool.GetCenterNodeIndex(iF) > 0 ); + for ( int iN = 0; iN < nbN; iN += iQ ) + helper.AddTLinkNode( fNodes[iN], fNodes[iN+2], fNodes[iN+1] ); } helper.SetIsQuadratic( true ); } @@ -1633,7 +1897,7 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, { map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n = volFace2BaryNode.insert - ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first; + ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), iF_n->second )).first; if ( !f_n->second ) { volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] ); @@ -1664,8 +1928,9 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, // find an existing face vector fNodes( volTool.GetFaceNodes( iF ), - volTool.GetFaceNodes( iF ) + nbNodes*iQ ); - while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes )) + volTool.GetFaceNodes( iF ) + volTool.NbFaceNodes( iF )); + while ( const SMDS_MeshElement* face = GetMeshDS()->FindElement( fNodes, SMDSAbs_Face, + /*noMedium=*/false)) { // make triangles helper.SetElementsOnShape( false ); @@ -1683,7 +1948,7 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, 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 *n2 = fNodes[(iN+iQ)%(nbNodes*iQ)]; const SMDS_MeshNode *n3 = iF_n->second; if ( !volTool.IsFaceExternal( iF )) swap( n2, n3 ); @@ -1744,6 +2009,13 @@ void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems, GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false ); + if ( geomType == SMDSEntity_TriQuad_Hexa ) + { + // remove medium nodes that could become free + for ( int i = 20; i < volTool.NbNodes(); ++i ) + if ( volNodes[i]->NbInverseElements() == 0 ) + GetMeshDS()->RemoveNode( volNodes[i] ); + } } // loop on volumes to split myLastCreatedNodes = newNodes; @@ -1988,7 +2260,7 @@ double getAngle(const SMDS_MeshElement * tr1, const SMDS_MeshNode * n1, const SMDS_MeshNode * n2) { - double angle = 2*PI; // bad angle + double angle = 2. * M_PI; // bad angle // get normals SMESH::Controls::TSequenceOfXYZ P1, P2; @@ -2673,7 +2945,7 @@ void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode, const SMDS_MeshElement* elem = elemIt->next(); if(elem->GetType() == SMDSAbs_0DElement) continue; - + SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator(); if ( elem->GetType() == SMDSAbs_Volume ) { @@ -2881,7 +3153,7 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, SMDS_FaceIteratorPtr fIt = aMesh->facesIterator(); while ( fIt->more() ) { const SMDS_MeshElement* face = fIt->next(); - theElems.insert( face ); + theElems.insert( theElems.end(), face ); } } // get all face ids theElems are on @@ -3362,30 +3634,22 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems, //function : isReverse //purpose : Return true if normal of prevNodes is not co-directied with // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]). -// iNotSame is where prevNodes and nextNodes are different +// iNotSame is where prevNodes and nextNodes are different. +// If result is true then future volume orientation is OK //======================================================================= -static bool isReverse(vector prevNodes, - vector nextNodes, - const int nbNodes, - const int iNotSame) +static bool isReverse(const SMDS_MeshElement* face, + const vector& prevNodes, + const vector& nextNodes, + const int iNotSame) { - int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 ); - int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 ); - - const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ]; - const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ]; - const SMDS_MeshNode* nP = prevNodes[ iNotSame ]; - const SMDS_MeshNode* nN = nextNodes[ iNotSame ]; - gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() ); - gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() ); - gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() ); - gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() ); + SMESH_TNodeXYZ pP = prevNodes[ iNotSame ]; + SMESH_TNodeXYZ pN = nextNodes[ iNotSame ]; + gp_XYZ extrDir( pN - pP ), faceNorm; + SMESH_Algo::FaceNormal( face, faceNorm, /*normalized=*/false ); - gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN ); - - return (vA ^ vB) * vN < 0.0; + return faceNorm * extrDir < 0.0; } //======================================================================= @@ -3408,305 +3672,294 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, //MESSAGE("sweepElement " << nbSteps); SMESHDS_Mesh* aMesh = GetMeshDS(); + const int nbNodes = elem->NbNodes(); + const int nbCorners = elem->NbCornerNodes(); + SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of + polyhedron creation !!! */ // Loop on elem nodes: // find new nodes and detect same nodes indices - int nbNodes = elem->NbNodes(); vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes ); vector prevNod( nbNodes ); vector nextNod( nbNodes ); vector midlNod( nbNodes ); - int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0; + int iNode, nbSame = 0, nbDouble = 0, iNotSameNode = 0; vector sames(nbNodes); - vector issimple(nbNodes); + vector isSingleNode(nbNodes); for ( iNode = 0; iNode < nbNodes; iNode++ ) { - TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ]; - const SMDS_MeshNode* node = nnIt->first; + 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); // is node medium - - itNN[ iNode ] = listNewNodes.begin(); + itNN [ iNode ] = listNewNodes.begin(); prevNod[ iNode ] = node; nextNod[ iNode ] = listNewNodes.front(); - if( !elem->IsQuadratic() || !issimple[iNode] ) { - if ( prevNod[ iNode ] != nextNod [ iNode ]) - iNotSameNode = iNode; - else { - iSameNode = iNode; - //nbSame++; + + isSingleNode[iNode] = (listNewNodes.size()==nbSteps); /* medium node of quadratic or + corner node of linear */ + if ( prevNod[ iNode ] != nextNod [ iNode ]) + nbDouble += !isSingleNode[iNode]; + + if( iNode < nbCorners ) { // check corners only + if ( prevNod[ iNode ] == nextNod [ iNode ]) sames[nbSame++] = iNode; - } + else + iNotSameNode = iNode; } } - //cerr<<" nbSame = "< 2) { MESSAGE( " Too many same nodes of element " << elem->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; - // } - - int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0; - int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes ); - if ( nbSame > 0 ) { - iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 ); - iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 ); - iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 ); + if ( elem->GetType() == SMDSAbs_Face && !isReverse( elem, prevNod, nextNod, iNotSameNode )) + { + // fix nodes order to have bottom normal external + if ( baseType == SMDSEntity_Polygon ) + { + std::reverse( itNN.begin(), itNN.end() ); + std::reverse( prevNod.begin(), prevNod.end() ); + std::reverse( midlNod.begin(), midlNod.end() ); + std::reverse( nextNod.begin(), nextNod.end() ); + std::reverse( isSingleNode.begin(), isSingleNode.end() ); + } + else + { + const vector& ind = SMDS_MeshCell::reverseSmdsOrder( baseType ); + SMDS_MeshCell::applyInterlace( ind, itNN ); + SMDS_MeshCell::applyInterlace( ind, prevNod ); + SMDS_MeshCell::applyInterlace( ind, nextNod ); + SMDS_MeshCell::applyInterlace( ind, midlNod ); + SMDS_MeshCell::applyInterlace( ind, isSingleNode ); + if ( nbSame > 0 ) + { + sames[nbSame] = iNotSameNode; + for ( int j = 0; j <= nbSame; ++j ) + for ( size_t i = 0; i < ind.size(); ++i ) + if ( ind[i] == sames[j] ) + { + sames[j] = i; + break; + } + iNotSameNode = sames[nbSame]; + } + } } - //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]< 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) { - //MESSAGE("Reversed elem " << elem ); - i0 = 2; - i2 = 0; - if ( nbSame > 0 ) - std::swap( iBeforeSame, iAfterSame ); + int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0; + if ( nbSame > 0 ) { + iSameNode = sames[ nbSame-1 ]; + iBeforeSame = ( iSameNode + nbCorners - 1 ) % nbCorners; + iAfterSame = ( iSameNode + 1 ) % nbCorners; + iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 ); } // make new elements - const SMDS_MeshElement* lastElem = elem; - for (int iStep = 0; iStep < nbSteps; iStep++ ) { + for (int iStep = 0; iStep < nbSteps; iStep++ ) + { // get next nodes - for ( iNode = 0; iNode < nbNodes; iNode++ ) { - if(issimple[iNode]) { - nextNod[ iNode ] = *itNN[ iNode ]; - itNN[ iNode ]++; - } - else { - if( elem->GetType()==SMDSAbs_Node ) { - // we have to use two nodes - midlNod[ iNode ] = *itNN[ iNode ]; - itNN[ iNode ]++; - nextNod[ iNode ] = *itNN[ iNode ]; - itNN[ iNode ]++; - } - else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) { - // we have to use each second node - //itNN[ iNode ]++; - nextNod[ iNode ] = *itNN[ iNode ]; - itNN[ iNode ]++; - } - else { - // we have to use two nodes - midlNod[ iNode ] = *itNN[ iNode ]; - itNN[ iNode ]++; - nextNod[ iNode ] = *itNN[ iNode ]; - itNN[ iNode ]++; - } - } + for ( iNode = 0; iNode < nbNodes; iNode++ ) + { + midlNod[ iNode ] = isSingleNode[iNode] ? 0 : *itNN[ iNode ]++; + nextNod[ iNode ] = *itNN[ iNode ]++; } + SMDS_MeshElement* aNewElem = 0; - if(!elem->IsPoly()) { - switch ( nbNodes ) { - case 0: - return; - case 1: { // NODE + /*if(!elem->IsPoly())*/ { + switch ( baseType ) { + case SMDSEntity_0D: + case SMDSEntity_Node: { // sweep NODE if ( nbSame == 0 ) { - if(issimple[0]) + if ( isSingleNode[0] ) aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] ); else aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] ); } + else + return; break; } - case 2: { // EDGE - if ( nbSame == 0 ) - aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ], - nextNod[ 1 ], nextNod[ 0 ] ); - else - aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ], - nextNod[ iNotSameNode ] ); + case SMDSEntity_Edge: { // sweep EDGE + if ( nbDouble == 0 ) + { + if ( nbSame == 0 ) // ---> quadrangle + aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ], + nextNod[ 1 ], nextNod[ 0 ] ); + else // ---> triangle + aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ], + nextNod[ iNotSameNode ] ); + } + else // ---> polygon + { + vector poly_nodes; + poly_nodes.push_back( prevNod[0] ); + poly_nodes.push_back( prevNod[1] ); + if ( prevNod[1] != nextNod[1] ) + { + if ( midlNod[1]) poly_nodes.push_back( midlNod[1]); + poly_nodes.push_back( nextNod[1] ); + } + if ( prevNod[0] != nextNod[0] ) + { + poly_nodes.push_back( nextNod[0] ); + if ( midlNod[0]) poly_nodes.push_back( midlNod[0]); + } + switch ( poly_nodes.size() ) { + case 3: + aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ], poly_nodes[ 2 ]); + break; + case 4: + aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ], + poly_nodes[ 2 ], poly_nodes[ 3 ]); + break; + default: + aNewElem = aMesh->AddPolygonalFace (poly_nodes); + } + } break; } - - case 3: { // TRIANGLE or quadratic edge - if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE - - if ( nbSame == 0 ) // --- pentahedron - aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], - nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] ); - - else if ( nbSame == 1 ) // --- pyramid - aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ], - nextNod[ iAfterSame ], nextNod[ iBeforeSame ], + case SMDSEntity_Triangle: // TRIANGLE ---> + { + if ( nbDouble > 0 ) break; + if ( nbSame == 0 ) // ---> pentahedron + aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], + nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] ); + + else if ( nbSame == 1 ) // ---> pyramid + aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ], + nextNod[ iAfterSame ], nextNod[ iBeforeSame ], nextNod[ iSameNode ]); - else // 2 same nodes: --- tetrahedron - aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], + else // 2 same nodes: ---> tetrahedron + aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], nextNod[ iNotSameNode ]); + break; } - else { // quadratic edge - if(nbSame==0) { // quadratic quadrangle - aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1], - midlNod[0], nextNod[2], midlNod[1], prevNod[2]); - } - else if(nbSame==1) { // quadratic triangle - if(sames[0]==2) { - return; // medium node on axis + case SMDSEntity_Quad_Edge: // sweep quadratic EDGE ---> + { + if ( nbSame == 2 ) + return; + if ( nbDouble+nbSame == 2 ) + { + if(nbSame==0) { // ---> quadratic quadrangle + aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0], + prevNod[2], midlNod[1], nextNod[2], midlNod[0]); } - else if(sames[0]==0) { - aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1], - nextNod[2], midlNod[1], prevNod[2]); + else { //(nbSame==1) // ---> quadratic triangle + if(sames[0]==2) { + return; // medium node on axis + } + else if(sames[0]==0) + aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1], + nextNod[2], midlNod[1], prevNod[2]); + else // sames[0]==1 + aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1], + midlNod[0], nextNod[2], prevNod[2]); } - else { // sames[0]==1 - aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1], - midlNod[0], nextNod[2], prevNod[2]); + } + else if ( nbDouble == 3 ) + { + if ( nbSame == 0 ) { // ---> bi-quadratic quadrangle + aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0], + prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]); } } - else { + else return; - } + break; } - break; - } - case 4: { // QUADRANGLE + case SMDSEntity_Quadrangle: { // sweep QUADRANGLE ---> + if ( nbDouble > 0 ) break; - if ( nbSame == 0 ) // --- hexahedron - aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ], - nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]); + if ( nbSame == 0 ) // ---> hexahedron + aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], prevNod[ 3 ], + nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ], nextNod[ 3 ]); - else if ( nbSame == 1 ) { // --- pyramid + pentahedron - aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ], - nextNod[ iAfterSame ], nextNod[ iBeforeSame ], + else if ( nbSame == 1 ) { // ---> pyramid + pentahedron + aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ], + nextNod[ iAfterSame ], nextNod[ iBeforeSame ], nextNod[ iSameNode ]); newElems.push_back( aNewElem ); - aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ], - prevNod[ iBeforeSame ], nextNod[ iAfterSame ], + aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ], + prevNod[ iBeforeSame ], nextNod[ iAfterSame ], nextNod[ iOpposSame ], nextNod[ iBeforeSame ] ); } - else if ( nbSame == 2 ) { // pentahedron + else if ( nbSame == 2 ) { // ---> pentahedron if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) // iBeforeSame is same too aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ], - nextNod[ iOpposSame ], prevNod[ iSameNode ], + nextNod[ iOpposSame ], prevNod[ iSameNode ], prevNod[ iAfterSame ], nextNod[ iAfterSame ]); else // iAfterSame is same too - aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ], + aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ], nextNod[ iBeforeSame ], prevNod[ iAfterSame ], prevNod[ iOpposSame ], nextNod[ iOpposSame ]); } break; } - case 6: { // quadratic triangle - // create pentahedron with 15 nodes + case SMDSEntity_Quad_Triangle: { // sweep Quadratic TRIANGLE ---> + if ( nbDouble+nbSame != 3 ) break; if(nbSame==0) { - if(i0>0) { // reversed case - aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1], - nextNod[0], nextNod[2], nextNod[1], - prevNod[5], prevNod[4], prevNod[3], - nextNod[5], nextNod[4], nextNod[3], - midlNod[0], midlNod[2], midlNod[1]); - } - else { // not reversed case - aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], - nextNod[0], nextNod[1], nextNod[2], - prevNod[3], prevNod[4], prevNod[5], - nextNod[3], nextNod[4], nextNod[5], - midlNod[0], midlNod[1], midlNod[2]); - } + // ---> pentahedron with 15 nodes + aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], + nextNod[0], nextNod[1], nextNod[2], + prevNod[3], prevNod[4], prevNod[5], + nextNod[3], nextNod[4], nextNod[5], + midlNod[0], midlNod[1], midlNod[2]); } else if(nbSame==1) { - // 2d order pyramid of 13 nodes - //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, - // int n12,int n23,int n34,int n41, - // int n15,int n25,int n35,int n45, int ID); - int n5 = iSameNode; - int n1,n4,n41,n15,n45; - if(i0>0) { // reversed case - n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 ); - n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 ); - n41 = n1 + 3; - n15 = n5 + 3; - n45 = n4 + 3; - } - else { - n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 ); - n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 ); - n41 = n4 + 3; - n15 = n1 + 3; - n45 = n5 + 3; - } - aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1], - nextNod[n4], prevNod[n4], prevNod[n5], - midlNod[n1], nextNod[n41], - midlNod[n4], prevNod[n41], - prevNod[n15], nextNod[n15], - nextNod[n45], prevNod[n45]); + // ---> 2d order pyramid of 13 nodes + int apex = iSameNode; + int i0 = ( apex + 1 ) % nbCorners; + int i1 = ( apex - 1 + nbCorners ) % nbCorners; + int i0a = apex + 3; + int i1a = i1 + 3; + int i01 = i0 + 3; + aNewElem = aMesh->AddVolume(prevNod[i1], prevNod[i0], + nextNod[i0], nextNod[i1], prevNod[apex], + prevNod[i01], midlNod[i0], + nextNod[i01], midlNod[i1], + prevNod[i1a], prevNod[i0a], + nextNod[i0a], nextNod[i1a]); } else if(nbSame==2) { - // 2d order tetrahedron of 10 nodes - //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, - // int n12,int n23,int n31, - // int n14,int n24,int n34, int ID); + // ---> 2d order tetrahedron of 10 nodes int n1 = iNotSameNode; - int n2,n3,n12,n23,n31; - if(i0>0) { // reversed case - n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 ); - n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 ); - n12 = n2 + 3; - n23 = n3 + 3; - n31 = n1 + 3; - } - else { - n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 ); - n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 ); - n12 = n1 + 3; - n23 = n2 + 3; - n31 = n3 + 3; - } + int n2 = ( n1 + 1 ) % nbCorners; + int n3 = ( n1 + nbCorners - 1 ) % nbCorners; + int n12 = n1 + 3; + int n23 = n2 + 3; + int n31 = n3 + 3; aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1], prevNod[n12], prevNod[n23], prevNod[n31], midlNod[n1], nextNod[n12], nextNod[n31]); } break; } - case 8: { // quadratic quadrangle - if(nbSame==0) { - // create hexahedron with 20 nodes - if(i0>0) { // reversed case - aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1], - nextNod[0], nextNod[3], nextNod[2], nextNod[1], - prevNod[7], prevNod[6], prevNod[5], prevNod[4], - nextNod[7], nextNod[6], nextNod[5], nextNod[4], - midlNod[0], midlNod[3], midlNod[2], midlNod[1]); - } - else { // not reversed case - aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3], - nextNod[0], nextNod[1], nextNod[2], nextNod[3], - prevNod[4], prevNod[5], prevNod[6], prevNod[7], - nextNod[4], nextNod[5], nextNod[6], nextNod[7], - midlNod[0], midlNod[1], midlNod[2], midlNod[3]); - } + case SMDSEntity_Quad_Quadrangle: { // sweep Quadratic QUADRANGLE ---> + if( nbSame == 0 ) { + if ( nbDouble != 4 ) break; + // ---> hexahedron with 20 nodes + aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3], + nextNod[0], nextNod[1], nextNod[2], nextNod[3], + prevNod[4], prevNod[5], prevNod[6], prevNod[7], + nextNod[4], nextNod[5], nextNod[6], nextNod[7], + midlNod[0], midlNod[1], midlNod[2], midlNod[3]); } - else if(nbSame==1) { - // --- pyramid + pentahedron - can not be created since it is needed - // additional middle node ot the center of face + else if(nbSame==1) { + // ---> pyramid + pentahedron - can not be created since it is needed + // additional middle node at the center of face INFOS( " Sweep for face " << elem->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); + else if( nbSame == 2 ) { + if ( nbDouble != 2 ) break; + // ---> 2d order Pentahedron with 15 nodes int n1,n2,n4,n5; if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) { // iBeforeSame is same too @@ -3722,19 +3975,10 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, 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; - } + int n12 = n2 + 4; + int n45 = n4 + 4; + int n14 = n1 + 4; + int n25 = n5 + 4; aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2], prevNod[n4], prevNod[n5], nextNod[n5], prevNod[n12], midlNod[n2], nextNod[n12], @@ -3743,57 +3987,95 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, } break; } - default: { - // realized for extrusion only - //vector polyedre_nodes (nbNodes*2 + 4*nbNodes); - //vector quantities (nbNodes + 2); - - //quantities[0] = nbNodes; // bottom of prism - //for (int inode = 0; inode < nbNodes; inode++) { - // polyedre_nodes[inode] = prevNod[inode]; - //} - - //quantities[1] = nbNodes; // top of prism - //for (int inode = 0; inode < nbNodes; inode++) { - // polyedre_nodes[nbNodes + inode] = nextNod[inode]; - //} - - //for (int iface = 0; iface < nbNodes; iface++) { - // quantities[iface + 2] = 4; - // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1; - // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface]; - // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface]; - // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface]; - // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface]; - //} - //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities); + case SMDSEntity_BiQuad_Quadrangle: { // sweep BiQuadratic QUADRANGLE ---> + + if( nbSame == 0 && nbDouble == 9 ) { + // ---> tri-quadratic hexahedron with 27 nodes + aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3], + nextNod[0], nextNod[1], nextNod[2], nextNod[3], + prevNod[4], prevNod[5], prevNod[6], prevNod[7], + nextNod[4], nextNod[5], nextNod[6], nextNod[7], + midlNod[0], midlNod[1], midlNod[2], midlNod[3], + prevNod[8], // bottom center + midlNod[4], midlNod[5], midlNod[6], midlNod[7], + nextNod[8], // top center + midlNod[8]);// elem center + } + else + { + return; + } break; } - } - } - - if(!aNewElem) { - // realized for extrusion only - vector polyedre_nodes (nbNodes*2 + 4*nbNodes); - vector quantities (nbNodes + 2); + case SMDSEntity_Polygon: { // sweep POLYGON - quantities[0] = nbNodes; // bottom of prism - for (int inode = 0; inode < nbNodes; inode++) { - polyedre_nodes[inode] = prevNod[inode]; + if ( nbNodes == 6 && nbSame == 0 && nbDouble == 0 ) { + // ---> hexagonal prism + aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], + prevNod[3], prevNod[4], prevNod[5], + nextNod[0], nextNod[1], nextNod[2], + nextNod[3], nextNod[4], nextNod[5]); + } + break; } + case SMDSEntity_Ball: + return; - quantities[1] = nbNodes; // top of prism - for (int inode = 0; inode < nbNodes; inode++) { - polyedre_nodes[nbNodes + inode] = nextNod[inode]; + default: + break; } + } - for (int iface = 0; iface < nbNodes; iface++) { - quantities[iface + 2] = 4; - int inextface = (iface == nbNodes - 1) ? 0 : iface + 1; - polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface]; - polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface]; - polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface]; - polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface]; + if ( !aNewElem && elem->GetType() == SMDSAbs_Face ) // try to create a polyherdal prism + { + if ( baseType != SMDSEntity_Polygon ) + { + const std::vector& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType); + SMDS_MeshCell::applyInterlace( ind, prevNod ); + SMDS_MeshCell::applyInterlace( ind, nextNod ); + SMDS_MeshCell::applyInterlace( ind, midlNod ); + SMDS_MeshCell::applyInterlace( ind, itNN ); + SMDS_MeshCell::applyInterlace( ind, isSingleNode ); + baseType = SMDSEntity_Polygon; // WARNING: change baseType !!!! + } + vector polyedre_nodes (nbNodes*2 + 4*nbNodes); + vector quantities (nbNodes + 2); + polyedre_nodes.clear(); + quantities.clear(); + + // bottom of prism + for (int inode = 0; inode < nbNodes; inode++) + polyedre_nodes.push_back( prevNod[inode] ); + quantities.push_back( nbNodes ); + + // top of prism + polyedre_nodes.push_back( nextNod[0] ); + for (int inode = nbNodes; inode-1; --inode ) + polyedre_nodes.push_back( nextNod[inode-1] ); + quantities.push_back( nbNodes ); + + // side faces + for (int iface = 0; iface < nbNodes; iface++) + { + const int prevNbNodes = polyedre_nodes.size(); + int inextface = (iface+1) % nbNodes; + polyedre_nodes.push_back( prevNod[inextface] ); + polyedre_nodes.push_back( prevNod[iface] ); + if ( prevNod[iface] != nextNod[iface] ) + { + if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]); + polyedre_nodes.push_back( nextNod[iface] ); + } + if ( prevNod[inextface] != nextNod[inextface] ) + { + polyedre_nodes.push_back( nextNod[inextface] ); + if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]); + } + const int nbFaceNodes = polyedre_nodes.size() - prevNbNodes; + if ( nbFaceNodes > 2 ) + quantities.push_back( nbFaceNodes ); + else // degenerated face + polyedre_nodes.resize( prevNbNodes ); } aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities); } @@ -3802,7 +4084,6 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem, newElems.push_back( aNewElem ); myLastCreatedElems.Append(aNewElem); srcElements.Append( elem ); - lastElem = aNewElem; } // set new prev nodes @@ -3831,16 +4112,18 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, const int nbSteps, SMESH_SequenceOfElemPtr& srcElements) { - MESSAGE("makeWalls"); ASSERT( newElemsMap.size() == elemNewNodesMap.size() ); SMESHDS_Mesh* aMesh = GetMeshDS(); // Find nodes belonging to only one initial element - sweep them to get edges. TNodeOfNodeListMapItr nList = mapNewNodes.begin(); - for ( ; nList != mapNewNodes.end(); nList++ ) { + for ( ; nList != mapNewNodes.end(); nList++ ) + { const SMDS_MeshNode* node = static_cast( nList->first ); + if ( newElemsMap.count( node )) + continue; // node was extruded into edge SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(); int nbInitElems = 0; const SMDS_MeshElement* el = 0; @@ -3853,11 +4136,10 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, nbInitElems = 0; highType = type; } - if ( elemSet.find(el) != elemSet.end() ) - nbInitElems++; + nbInitElems += elemSet.count(el); } if ( nbInitElems < 2 ) { - bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node); + bool NotCreateEdge = el && el->IsMediumNode(node); if(!NotCreateEdge) { vector newNodesItVec( 1, nList ); list newEdges; @@ -3871,15 +4153,18 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, TElemOfElemListMap::iterator itElem = newElemsMap.begin(); TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin(); - for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) { + for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) + { const SMDS_MeshElement* elem = itElem->first; vector& vecNewNodes = itElemNodes->second; if(itElem->second.size()==0) continue; + const bool isQuadratic = elem->IsQuadratic(); + if ( elem->GetType() == SMDSAbs_Edge ) { // create a ceiling edge - if (!elem->IsQuadratic()) { + if ( !isQuadratic ) { if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(), vecNewNodes[ 1 ]->second.back())) { myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(), @@ -3908,7 +4193,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, set aFaceLastNodes; int iNode, nbNodes = vecNewNodes.size(); - if(!elem->IsQuadratic()) { + if ( !isQuadratic ) { // loop on the face nodes for ( iNode = 0; iNode < nbNodes; iNode++ ) { aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() ); @@ -3940,12 +4225,14 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1; const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first; const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first; + const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first; // check if a link is free - if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) { + if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet ) && + ! SMESH_MeshEditor::FindFaceInSet ( n1, n3, elemSet, avoidSet ) && + ! SMESH_MeshEditor::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) { hasFreeLinks = true; // make an edge and a ceiling for a new edge // find medium node - const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first; if ( !aMesh->FindEdge( n1, n2, n3 )) { myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge srcElements.Append( myLastCreatedElems.Last() ); @@ -3959,7 +4246,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, } } } - for ( iNode = nbn; iNode < 2*nbn; iNode++ ) { + for ( iNode = nbn; iNode < nbNodes; iNode++ ) { aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() ); } } @@ -3977,12 +4264,11 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, } for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) { list::iterator v = newVolumes.begin(); - iVol = 0; - while ( iVol++ < volNb ) v++; + std::advance( v, volNb ); // find indices of free faces of a volume and their source edges list< int > freeInd; list< const SMDS_MeshElement* > srcEdges; // source edges of free faces - SMDS_VolumeTool vTool( *v ); + SMDS_VolumeTool vTool( *v, /*ignoreCentralNodes=*/false ); int iF, nbF = vTool.NbFaces(); for ( iF = 0; iF < nbF; iF ++ ) { if (vTool.IsFreeFace( iF ) && @@ -4017,8 +4303,8 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, // create faces for all steps; // if such a face has been already created by sweep of edge, // assure that its orientation is OK - for ( int iStep = 0; iStep < nbSteps; iStep++ ) { - vTool.Set( *v ); + for ( int iStep = 0; iStep < nbSteps; iStep++ ) { + vTool.Set( *v, /*ignoreCentralNodes=*/false ); vTool.SetExternalNormal(); const int nextShift = vTool.IsForward() ? +1 : -1; list< int >::iterator ind = freeInd.begin(); @@ -4027,91 +4313,114 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, { const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind ); int nbn = vTool.NbFaceNodes( *ind ); - if ( ! (*v)->IsPoly() ) - switch ( nbn ) { - case 3: { ///// triangle - const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]); - if ( !f || - nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift )) - { - const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ], - nodes[ 1 ], - nodes[ 1 + nextShift ] }; - if ( f ) - aMesh->ChangeElementNodes( f, &newOrder[0], nbn ); - else - myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ], - newOrder[ 2 ] )); - } - break; + const SMDS_MeshElement * f = 0; + if ( nbn == 3 ) ///// triangle + { + f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]); + if ( !f || + nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift )) + { + const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ], + nodes[ 1 ], + nodes[ 1 + nextShift ] }; + if ( f ) + aMesh->ChangeElementNodes( f, &newOrder[0], nbn ); + else + myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ], + newOrder[ 2 ] )); } - case 4: { ///// quadrangle - const SMDS_MeshFace * f = - aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]); - if ( !f || - nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift )) - { - const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ], - nodes[ 2 ], nodes[ 2+nextShift ] }; - if ( f ) - aMesh->ChangeElementNodes( f, &newOrder[0], nbn ); - else - myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ], - newOrder[ 2 ], newOrder[ 3 ])); - } - break; + } + else if ( nbn == 4 ) ///// quadrangle + { + f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]); + if ( !f || + nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift )) + { + const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ], + nodes[ 2 ], nodes[ 2+nextShift ] }; + if ( f ) + aMesh->ChangeElementNodes( f, &newOrder[0], nbn ); + else + myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ], + newOrder[ 2 ], newOrder[ 3 ])); } - case 6: { /////// quadratic triangle - const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], - nodes[1], nodes[3], nodes[5] ); - if ( !f || - nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift )) - { - const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift], - nodes[2], - nodes[2 + 2*nextShift], - nodes[3 - 2*nextShift], - nodes[3], - nodes[3 + 2*nextShift]}; - if ( f ) - aMesh->ChangeElementNodes( f, &newOrder[0], nbn ); - else - myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], - newOrder[ 1 ], - newOrder[ 2 ], - newOrder[ 3 ], - newOrder[ 4 ], - newOrder[ 5 ] )); - } - break; + } + else if ( nbn == 6 && isQuadratic ) /////// quadratic triangle + { + f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5] ); + if ( !f || + nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift )) + { + const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift], + nodes[2], + nodes[2 + 2*nextShift], + nodes[3 - 2*nextShift], + nodes[3], + nodes[3 + 2*nextShift]}; + if ( f ) + aMesh->ChangeElementNodes( f, &newOrder[0], nbn ); + else + myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], + newOrder[ 1 ], + newOrder[ 2 ], + newOrder[ 3 ], + newOrder[ 4 ], + newOrder[ 5 ] )); } - default: /////// 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 || - nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift )) - { - const SMDS_MeshNode* newOrder[8] = { nodes[0], - nodes[4 - 2*nextShift], - nodes[4], - nodes[4 + 2*nextShift], - nodes[1], - nodes[5 - 2*nextShift], - nodes[5], - nodes[5 + 2*nextShift] }; - if ( f ) - aMesh->ChangeElementNodes( f, &newOrder[0], nbn ); - else - myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ], - newOrder[ 2 ], newOrder[ 3 ], - newOrder[ 4 ], newOrder[ 5 ], - newOrder[ 6 ], newOrder[ 7 ])); - } - } // switch ( nbn ) - - else { //////// polygon - - vector polygon_nodes ( nodes, &nodes[nbn] ); + } + else if ( nbn == 8 && isQuadratic ) /////// quadratic quadrangle + { + f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6], + nodes[1], nodes[3], nodes[5], nodes[7] ); + if ( !f || + nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift )) + { + const SMDS_MeshNode* newOrder[8] = { nodes[0], + nodes[4 - 2*nextShift], + nodes[4], + nodes[4 + 2*nextShift], + nodes[1], + nodes[5 - 2*nextShift], + nodes[5], + nodes[5 + 2*nextShift] }; + if ( f ) + aMesh->ChangeElementNodes( f, &newOrder[0], nbn ); + else + myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ], + newOrder[ 2 ], newOrder[ 3 ], + newOrder[ 4 ], newOrder[ 5 ], + newOrder[ 6 ], newOrder[ 7 ])); + } + } + else if ( nbn == 9 && isQuadratic ) /////// bi-quadratic quadrangle + { + f = aMesh->FindElement( vector( nodes, nodes+nbn ), + SMDSAbs_Face, /*noMedium=*/false); + if ( !f || + nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift )) + { + const SMDS_MeshNode* newOrder[9] = { nodes[0], + nodes[4 - 2*nextShift], + nodes[4], + nodes[4 + 2*nextShift], + nodes[1], + nodes[5 - 2*nextShift], + nodes[5], + nodes[5 + 2*nextShift], + nodes[8] }; + if ( f ) + aMesh->ChangeElementNodes( f, &newOrder[0], nbn ); + else + myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ], + newOrder[ 2 ], newOrder[ 3 ], + newOrder[ 4 ], newOrder[ 5 ], + newOrder[ 6 ], newOrder[ 7 ], + newOrder[ 8 ])); + } + } + else //////// polygon + { + vector polygon_nodes ( nodes, nodes+nbn ); const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes ); if ( !f || nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift )) @@ -4140,48 +4449,53 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes, // Make a ceiling face with a normal external to a volume - SMDS_VolumeTool lastVol( itElem->second.back() ); + SMDS_VolumeTool lastVol( itElem->second.back(), /*ignoreCentralNodes=*/false ); int iF = lastVol.GetFaceIndex( aFaceLastNodes ); if ( iF >= 0 ) { lastVol.SetExternalNormal(); const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF ); int nbn = lastVol.NbFaceNodes( iF ); - switch ( nbn ) { - case 3: + if ( nbn == 3 ) { if (!hasFreeLinks || !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ])) myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] )); - break; - case 4: + } + else if ( nbn == 4 ) + { if (!hasFreeLinks || !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ])) - myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] )); - break; - default: - if(itElem->second.back()->IsQuadratic()) { - if(nbn==6) { - if (!hasFreeLinks || - !aMesh->FindFace(nodes[0], nodes[2], nodes[4], - nodes[1], nodes[3], nodes[5]) ) { - myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], - nodes[1], nodes[3], nodes[5])); - } - } - else { // nbn==8 - if (!hasFreeLinks || - !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6], - nodes[1], nodes[3], nodes[5], nodes[7]) ) - myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6], - nodes[1], nodes[3], nodes[5], nodes[7])); - } - } - else { - vector polygon_nodes ( nodes, &nodes[nbn] ); - if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes)) - myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes)); - } - } // switch + myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ])); + } + else if ( nbn == 6 && isQuadratic ) + { + if (!hasFreeLinks || + !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5]) ) + myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], + nodes[1], nodes[3], nodes[5])); + } + else if ( nbn == 8 && isQuadratic ) + { + if (!hasFreeLinks || + !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6], + nodes[1], nodes[3], nodes[5], nodes[7]) ) + myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6], + nodes[1], nodes[3], nodes[5], nodes[7])); + } + else if ( nbn == 9 && isQuadratic ) + { + if (!hasFreeLinks || + !aMesh->FindElement(vector( nodes, nodes+nbn ), + SMDSAbs_Face, /*noMedium=*/false) ) + myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6], + nodes[1], nodes[3], nodes[5], nodes[7], + nodes[8])); + } + else { + vector polygon_nodes ( nodes, nodes + nbn ); + if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes)) + myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes)); + } while ( srcElements.Length() < myLastCreatedElems.Length() ) srcElements.Append( myLastCreatedElems.Last() ); @@ -4224,6 +4538,9 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems, TElemOfVecOfNnlmiMap mapElemNewNodes; TElemOfElemListMap newElemsMap; + const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) + + myMesh->NbFaces(ORDER_QUADRATIC) + + myMesh->NbVolumes(ORDER_QUADRATIC) ); // loop on theElems TIDSortedElemSet::iterator itElem; for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { @@ -4235,7 +4552,8 @@ 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() ); @@ -4244,33 +4562,43 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems, 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; + TNodeOfNodeListMapItr nIt = + mapNewNodes.insert( make_pair( node, list() )).first; + list& listNewNodes = nIt->second; + if ( listNewNodes.empty() ) + { + // check if we are to create medium nodes between corner ones + bool needMediumNodes = false; + if ( isQuadraticMesh ) + { + SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(); + while (it->more() && !needMediumNodes ) + { + const SMDS_MeshElement* invElem = it->next(); + if ( invElem != elem && !theElems.count( invElem )) continue; + needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) ); + if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle ) + needMediumNodes = true; + } + } // 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 ); const SMDS_MeshNode * newNode = node; for ( int i = 0; i < theNbSteps; i++ ) { if ( !isOnAxis ) { - if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) { - // create two nodes + if ( needMediumNodes ) // create a medium node + { aTrsf2.Transforms( coord[0], coord[1], coord[2] ); - //aTrsf.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 ); aTrsf2.Transforms( coord[0], coord[1], coord[2] ); - //aTrsf.Transforms( coord[0], coord[1], coord[2] ); } else { aTrsf.Transforms( coord[0], coord[1], coord[2] ); } + // create a corner node newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); myLastCreatedNodes.Append(newNode); srcNodes.Append( node ); @@ -4278,48 +4606,11 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems, } else { listNewNodes.push_back( newNode ); - if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) { - listNewNodes.push_back( newNode ); - } + // if ( needMediumNodes ) + // listNewNodes.push_back( newNode ); } } } - /* - 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; - 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: "<GetMeshDS(); @@ -4376,7 +4667,7 @@ const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x, // create new node and return it const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z); - myLastCreatedNodes.Append(NewNode); + //myLastCreatedNodes.Append(NewNode); return NewNode; } @@ -4421,7 +4712,6 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems, const int theFlags, const double theTolerance) { - MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance); myLastCreatedElems.Clear(); myLastCreatedNodes.Clear(); @@ -4437,6 +4727,9 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems, TElemOfVecOfNnlmiMap mapElemNewNodes; //TElemOfVecOfMapNodesMap mapElemNewNodes; + const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) + + myMesh->NbFaces(ORDER_QUADRATIC) + + myMesh->NbVolumes(ORDER_QUADRATIC) ); // loop on theElems TIDSortedElemSet::iterator itElem; for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { @@ -4446,7 +4739,6 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems, continue; vector & newNodesItVec = mapElemNewNodes[ elem ]; - //vector & newNodesItVec = mapElemNewNodes[ elem ]; newNodesItVec.reserve( elem->NbNodes() ); // loop on elem nodes @@ -4455,21 +4747,33 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems, { // check if a node has been already sweeped const SMDS_MeshNode* node = cast2Node( itN->next() ); - TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node ); - //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node ); - if ( nIt == mapNewNodes.end() ) { - nIt = mapNewNodes.insert( make_pair( node, list() )).first; - //nIt = mapNewNodes.insert( make_pair( node, vector() )).first; - list& listNewNodes = nIt->second; - //vector& vecNewNodes = nIt->second; - //vecNewNodes.reserve(nbsteps); - + TNodeOfNodeListMap::iterator nIt = + mapNewNodes.insert( make_pair( node, list() )).first; + list& listNewNodes = nIt->second; + if ( listNewNodes.empty() ) + { // make new nodes + + // check if we are to create medium nodes between corner ones + bool needMediumNodes = false; + if ( isQuadraticMesh ) + { + SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(); + while (it->more() && !needMediumNodes ) + { + const SMDS_MeshElement* invElem = it->next(); + if ( invElem != elem && !theElems.count( invElem )) continue; + needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) ); + if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle ) + needMediumNodes = true; + } + } + double coord[] = { node->X(), node->Y(), node->Z() }; - //int nbsteps = theParams.mySteps->Length(); - for ( int i = 0; i < nbsteps; i++ ) { - if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) { - // create additional node + for ( int i = 0; i < nbsteps; i++ ) + { + if ( needMediumNodes ) // create a medium node + { double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.; double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.; double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.; @@ -4485,7 +4789,7 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems, listNewNodes.push_back( newNode ); } } - //aTrsf.Transforms( coord[0], coord[1], coord[2] ); + // create a corner node coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1); coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1); coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1); @@ -4493,55 +4797,12 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems, const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2], theTolerance, theParams.myNodes); listNewNodes.push_back( newNode ); - //vecNewNodes[i]=newNode; } else { const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); myLastCreatedNodes.Append(newNode); srcNodes.Append( node ); listNewNodes.push_back( newNode ); - //vecNewNodes[i]=newNode; - } - } - } - 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()==nbsteps) { - listNewNodes.clear(); - double coord[] = { node->X(), node->Y(), node->Z() }; - for ( int i = 0; i < nbsteps; i++ ) { - double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1); - double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1); - double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1); - if( theFlags & EXTRUSION_FLAG_SEW ) { - const SMDS_MeshNode * newNode = CreateNode(x, y, z, - theTolerance, theParams.myNodes); - listNewNodes.push_back( newNode ); - } - else { - const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z); - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - listNewNodes.push_back( newNode ); - } - coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1); - coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1); - coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1); - if( theFlags & EXTRUSION_FLAG_SEW ) { - const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2], - theTolerance, theParams.myNodes); - listNewNodes.push_back( newNode ); - } - else { - const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); - myLastCreatedNodes.Append(newNode); - srcNodes.Append( node ); - listNewNodes.push_back( newNode ); - } - } } } } @@ -4561,52 +4822,6 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems, return newGroupIDs; } -/* -//======================================================================= -//class : SMESH_MeshEditor_PathPoint -//purpose : auxiliary class -//======================================================================= -class SMESH_MeshEditor_PathPoint { -public: -SMESH_MeshEditor_PathPoint() { -myPnt.SetCoord(99., 99., 99.); -myTgt.SetCoord(1.,0.,0.); -myAngle=0.; -myPrm=0.; -} -void SetPnt(const gp_Pnt& aP3D){ -myPnt=aP3D; -} -void SetTangent(const gp_Dir& aTgt){ -myTgt=aTgt; -} -void SetAngle(const double& aBeta){ -myAngle=aBeta; -} -void SetParameter(const double& aPrm){ -myPrm=aPrm; -} -const gp_Pnt& Pnt()const{ -return myPnt; -} -const gp_Dir& Tangent()const{ -return myTgt; -} -double Angle()const{ -return myAngle; -} -double Parameter()const{ -return myPrm; -} - -protected: -gp_Pnt myPnt; -gp_Dir myTgt; -double myAngle; -double myPrm; -}; -*/ - //======================================================================= //function : ExtrusionAlongTrack //purpose : @@ -4663,7 +4878,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, list fullList; const TopoDS_Shape& aS = theTrack->GetSubShape(); - // Sub shape for the Pattern must be an Edge or Wire + // 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 @@ -4687,8 +4902,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, } //Extrusion_Error err = MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList); - } - else if( aS.ShapeType() == TopAbs_WIRE ) { + } else if( aS.ShapeType() == TopAbs_WIRE ) { list< SMESH_subMesh* > LSM; TopTools_SequenceOfShape Edges; SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true); @@ -4701,6 +4915,7 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, list< list > LLPPs; int startNid = theN1->GetID(); TColStd_MapOfInteger UsedNums; + int NbEdges = Edges.Length(); int i = 1; for(; i<=NbEdges; i++) { @@ -4834,8 +5049,125 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements, list fullList; const TopoDS_Shape& aS = theTrack->GetShapeToMesh(); - // Sub shape for the Pattern must be an Edge or Wire - if( aS.ShapeType() == TopAbs_EDGE ) { + + if( aS == SMESH_Mesh::PseudoShape() ) { + //Mesh without shape + const SMDS_MeshNode* currentNode = NULL; + const SMDS_MeshNode* prevNode = theN1; + std::vector aNodesList; + aNodesList.push_back(theN1); + int nbEdges = 0, conn=0; + const SMDS_MeshElement* prevElem = NULL; + const SMDS_MeshElement* currentElem = NULL; + int totalNbEdges = theTrack->NbEdges(); + SMDS_ElemIteratorPtr nIt; + + //check start node + if( !theTrack->GetMeshDS()->Contains(theN1) ) { + return EXTR_BAD_STARTING_NODE; + } + + conn = nbEdgeConnectivity(theN1); + if(conn > 2) + return EXTR_PATH_NOT_EDGE; + + aItE = theN1->GetInverseElementIterator(); + prevElem = aItE->next(); + currentElem = prevElem; + //Get all nodes + if(totalNbEdges == 1 ) { + nIt = currentElem->nodesIterator(); + currentNode = static_cast(nIt->next()); + if(currentNode == prevNode) + currentNode = static_cast(nIt->next()); + aNodesList.push_back(currentNode); + } else { + nIt = currentElem->nodesIterator(); + while( nIt->more() ) { + currentNode = static_cast(nIt->next()); + if(currentNode == prevNode) + currentNode = static_cast(nIt->next()); + aNodesList.push_back(currentNode); + + //case of the closed mesh + if(currentNode == theN1) { + nbEdges++; + break; + } + + conn = nbEdgeConnectivity(currentNode); + if(conn > 2) { + return EXTR_PATH_NOT_EDGE; + }else if( conn == 1 && nbEdges > 0 ) { + //End of the path + nbEdges++; + break; + }else { + prevNode = currentNode; + aItE = currentNode->GetInverseElementIterator(); + currentElem = aItE->next(); + if( currentElem == prevElem) + currentElem = aItE->next(); + nIt = currentElem->nodesIterator(); + prevElem = currentElem; + nbEdges++; + } + } + } + + if(nbEdges != totalNbEdges) + return EXTR_PATH_NOT_EDGE; + + TopTools_SequenceOfShape Edges; + double x1,x2,y1,y2,z1,z2; + list< list > LLPPs; + int startNid = theN1->GetID(); + for(int i = 1; i < aNodesList.size(); i++) { + x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X(); + y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y(); + z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z(); + TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2)); + list LPP; + aPrms.clear(); + MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP); + LLPPs.push_back(LPP); + if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID(); + else startNid = aNodesList[i-1]->GetID(); + + } + + 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(); + SMESH_MeshEditor_PathPoint PP2; + fullList.pop_back(); + itLLPP++; + for(; itLLPP!=LLPPs.end(); itLLPP++) { + list currList = *itLLPP; + itPP = currList.begin(); + 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!=currList.end(); itPP++) { + fullList.push_back( *itPP ); + } + PP1 = fullList.back(); + fullList.pop_back(); + } + fullList.push_back(PP1); + + } // Sub-shape for the Pattern must be an Edge or Wire + else if( aS.ShapeType() == TopAbs_EDGE ) { aTrackEdge = TopoDS::Edge( aS ); // the Edge must not be degenerated if ( BRep_Tool::Degenerated( aTrackEdge ) ) @@ -5458,196 +5790,162 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, for ( ; invElemIt != inverseElemSet.end(); invElemIt++ ) theElems.insert( *invElemIt ); - // replicate or reverse elements - // TODO revoir ordre reverse vtk - enum { - REV_TETRA = 0, // = nbNodes - 4 - REV_PYRAMID = 1, // = nbNodes - 4 - REV_PENTA = 2, // = nbNodes - 4 - 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 - { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA - { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE - { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA - { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD - }; + // Replicate or reverse elements + std::vector iForw; for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { const SMDS_MeshElement* elem = *itElem; - if ( !elem || elem->GetType() == SMDSAbs_Node ) - continue; + if ( !elem ) continue; - int nbNodes = elem->NbNodes(); - int elemType = elem->GetType(); + SMDSAbs_GeometryType geomType = elem->GetGeomType(); + int nbNodes = elem->NbNodes(); + if ( geomType == SMDSGeom_NONE ) continue; // node - if (elem->IsPoly()) { - // Polygon or Polyhedral Volume - switch ( elemType ) { - case SMDSAbs_Face: - { - vector poly_nodes (nbNodes); - int iNode = 0; - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while (itN->more()) { - const SMDS_MeshNode* node = - static_cast(itN->next()); - TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node); - if (nodeMapIt == nodeMap.end()) - break; // not all nodes transformed - if (needReverse) { - // reverse mirrored faces and volumes - poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second; - } else { - poly_nodes[iNode] = (*nodeMapIt).second; - } - iNode++; - } - if ( iNode != nbNodes ) - continue; // not all nodes transformed + switch ( geomType ) { - if ( theTargetMesh ) { - myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes)); - srcElems.Append( elem ); - } - else if ( theCopy ) { - myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes)); - srcElems.Append( elem ); - } - else { - aMesh->ChangePolygonNodes(elem, poly_nodes); + case SMDSGeom_POLYGON: // ---------------------- polygon + { + vector poly_nodes (nbNodes); + int iNode = 0; + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while (itN->more()) { + const SMDS_MeshNode* node = + static_cast(itN->next()); + TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node); + if (nodeMapIt == nodeMap.end()) + break; // not all nodes transformed + if (needReverse) { + // reverse mirrored faces and volumes + poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second; + } else { + poly_nodes[iNode] = (*nodeMapIt).second; } + iNode++; } - break; - case SMDSAbs_Volume: - { - // ATTENTION: Reversing is not yet done!!! - const SMDS_VtkVolume* aPolyedre = - dynamic_cast( elem ); - if (!aPolyedre) { - MESSAGE("Warning: bad volumic element"); - continue; - } - - vector poly_nodes; - vector quantities; + if ( iNode != nbNodes ) + continue; // not all nodes transformed - bool allTransformed = true; - int nbFaces = aPolyedre->NbFaces(); - for (int iface = 1; iface <= nbFaces && allTransformed; iface++) { - int nbFaceNodes = aPolyedre->NbFaceNodes(iface); - for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) { - const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode); - TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node); - if (nodeMapIt == nodeMap.end()) { - allTransformed = false; // not all nodes transformed - } else { - poly_nodes.push_back((*nodeMapIt).second); - } - } - quantities.push_back(nbFaceNodes); - } - if ( !allTransformed ) - continue; // not all nodes transformed - - if ( theTargetMesh ) { - myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities)); - srcElems.Append( elem ); - } - else if ( theCopy ) { - myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities)); - srcElems.Append( elem ); - } - else { - aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities); - } + if ( theTargetMesh ) { + myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes)); + srcElems.Append( elem ); + } + else if ( theCopy ) { + myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes)); + srcElems.Append( elem ); + } + else { + aMesh->ChangePolygonNodes(elem, poly_nodes); } - break; - default:; } - continue; - } + break; - // 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}; - i = anIds; - if(needReverse) { - if(nbNodes==3) { // quadratic edge - static int anIds[] = {1,0,2}; - i = anIds; + case SMDSGeom_POLYHEDRA: // ------------------ polyhedral volume + { + const SMDS_VtkVolume* aPolyedre = + dynamic_cast( elem ); + if (!aPolyedre) { + MESSAGE("Warning: bad volumic element"); + continue; } - else if(nbNodes==6) { // quadratic triangle - static int anIds[] = {0,2,1,5,4,3}; - i = anIds; + + vector poly_nodes; poly_nodes.reserve( nbNodes ); + vector quantities; quantities.reserve( nbNodes ); + + bool allTransformed = true; + int nbFaces = aPolyedre->NbFaces(); + for (int iface = 1; iface <= nbFaces && allTransformed; iface++) { + int nbFaceNodes = aPolyedre->NbFaceNodes(iface); + for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) { + const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode); + TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node); + if (nodeMapIt == nodeMap.end()) { + allTransformed = false; // not all nodes transformed + } else { + poly_nodes.push_back((*nodeMapIt).second); + } + if ( needReverse && allTransformed ) + std::reverse( poly_nodes.end() - nbFaceNodes, poly_nodes.end() ); + } + quantities.push_back(nbFaceNodes); } - else if(nbNodes==8) { // quadratic quadrangle - static int anIds[] = {0,3,2,1,7,6,5,4}; - i = anIds; + if ( !allTransformed ) + continue; // not all nodes transformed + + if ( theTargetMesh ) { + myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities)); + srcElems.Append( elem ); } - else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes - static int anIds[] = {0,2,1,3,6,5,4,7,9,8}; - i = anIds; + else if ( theCopy ) { + myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities)); + srcElems.Append( elem ); } - else if(nbNodes==13) { // quadratic pyramid of 13 nodes - static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10}; - i = anIds; + else { + aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities); } - else if(nbNodes==15) { // quadratic pentahedron with 15 nodes - static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13}; - i = anIds; + } + break; + + case SMDSGeom_BALL: // -------------------- Ball + { + if ( !theCopy && !theTargetMesh ) continue; + + TNodeNodeMap::iterator nodeMapIt = nodeMap.find( elem->GetNode(0) ); + if (nodeMapIt == nodeMap.end()) + continue; // not all nodes transformed + + double diameter = static_cast(elem)->GetDiameter(); + if ( theTargetMesh ) { + myLastCreatedElems.Append(aTgtMesh->AddBall( nodeMapIt->second, diameter )); + srcElems.Append( elem ); } - else { // nbNodes==20 - quadratic hexahedron with 20 nodes - static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17}; - i = anIds; + else { + myLastCreatedElems.Append(aMesh->AddBall( nodeMapIt->second, diameter )); + srcElems.Append( elem ); } } - } + break; - // find transformed nodes - vector nodes(nbNodes); - int iNode = 0; - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) { - const SMDS_MeshNode* node = - static_cast( itN->next() ); - TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node ); - if ( nodeMapIt == nodeMap.end() ) - break; // not all nodes transformed - nodes[ i [ iNode++ ]] = (*nodeMapIt).second; - } - if ( iNode != nbNodes ) - continue; // not all nodes transformed + default: // ----------------------- Regular elements + + while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() ); + const std::vector& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType() ); + const std::vector& i = needReverse ? iRev : iForw; - if ( theTargetMesh ) { - if ( SMDS_MeshElement* copy = - targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) { - myLastCreatedElems.Append( copy ); - srcElems.Append( elem ); + // find transformed nodes + vector nodes(nbNodes); + int iNode = 0; + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + while ( itN->more() ) { + const SMDS_MeshNode* node = + static_cast( itN->next() ); + TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node ); + if ( nodeMapIt == nodeMap.end() ) + break; // not all nodes transformed + nodes[ i [ iNode++ ]] = (*nodeMapIt).second; } - } - else if ( theCopy ) { - if ( AddElement( nodes, elem->GetType(), elem->IsPoly() )) - srcElems.Append( elem ); - } - else { - // reverse element as it was reversed by transformation - if ( nbNodes > 2 ) - aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes ); - } - } + if ( iNode != nbNodes ) + continue; // not all nodes transformed + + if ( theTargetMesh ) { + if ( SMDS_MeshElement* copy = + targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) { + myLastCreatedElems.Append( copy ); + srcElems.Append( elem ); + } + } + else if ( theCopy ) { + if ( AddElement( nodes, elem->GetType(), elem->IsPoly() )) + srcElems.Append( elem ); + } + else { + // reverse element as it was reversed by transformation + if ( nbNodes > 2 ) + aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes ); + } + } // switch ( geomType ) + + } // loop on elements PGroupIDs newGroupIDs; @@ -5658,332 +5956,6 @@ SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems, return newGroupIDs; } - -////======================================================================= -////function : Scale -////purpose : -////======================================================================= -// -//SMESH_MeshEditor::PGroupIDs -//SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems, -// const gp_Pnt& thePoint, -// const std::list& theScaleFact, -// const bool theCopy, -// const bool theMakeGroups, -// SMESH_Mesh* theTargetMesh) -//{ -// MESSAGE("Scale"); -// myLastCreatedElems.Clear(); -// myLastCreatedNodes.Clear(); -// -// SMESH_MeshEditor targetMeshEditor( theTargetMesh ); -// SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0; -// SMESHDS_Mesh* aMesh = GetMeshDS(); -// -// double scaleX=1.0, scaleY=1.0, scaleZ=1.0; -// std::list::const_iterator itS = theScaleFact.begin(); -// scaleX = (*itS); -// if(theScaleFact.size()==1) { -// scaleY = (*itS); -// scaleZ= (*itS); -// } -// if(theScaleFact.size()==2) { -// itS++; -// scaleY = (*itS); -// scaleZ= (*itS); -// } -// if(theScaleFact.size()>2) { -// itS++; -// scaleY = (*itS); -// itS++; -// scaleZ= (*itS); -// } -// -// // map old node to new one -// TNodeNodeMap nodeMap; -// -// // elements sharing moved nodes; those of them which have all -// // nodes mirrored but are not in theElems are to be reversed -// TIDSortedElemSet inverseElemSet; -// -// // source elements for each generated one -// SMESH_SequenceOfElemPtr srcElems, srcNodes; -// -// // loop on theElems -// TIDSortedElemSet::iterator itElem; -// for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { -// const SMDS_MeshElement* elem = *itElem; -// if ( !elem ) -// continue; -// -// // loop on elem nodes -// SMDS_ElemIteratorPtr itN = elem->nodesIterator(); -// while ( itN->more() ) { -// -// // check if a node has been already transformed -// const SMDS_MeshNode* node = cast2Node( itN->next() ); -// pair n2n_isnew = -// nodeMap.insert( make_pair ( node, node )); -// if ( !n2n_isnew.second ) -// continue; -// -// //double coord[3]; -// //coord[0] = node->X(); -// //coord[1] = node->Y(); -// //coord[2] = node->Z(); -// //theTrsf.Transforms( coord[0], coord[1], coord[2] ); -// double dx = (node->X() - thePoint.X()) * scaleX; -// double dy = (node->Y() - thePoint.Y()) * scaleY; -// double dz = (node->Z() - thePoint.Z()) * scaleZ; -// if ( theTargetMesh ) { -// //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] ); -// const SMDS_MeshNode * newNode = -// aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz ); -// n2n_isnew.first->second = newNode; -// myLastCreatedNodes.Append(newNode); -// srcNodes.Append( node ); -// } -// else if ( theCopy ) { -// //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); -// const SMDS_MeshNode * newNode = -// aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz ); -// n2n_isnew.first->second = newNode; -// myLastCreatedNodes.Append(newNode); -// srcNodes.Append( node ); -// } -// else { -// //aMesh->MoveNode( node, coord[0], coord[1], coord[2] ); -// aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz ); -// // node position on shape becomes invalid -// const_cast< SMDS_MeshNode* > ( node )->SetPosition -// ( SMDS_SpacePosition::originSpacePosition() ); -// } -// -// // keep inverse elements -// //if ( !theCopy && !theTargetMesh && needReverse ) { -// // SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator(); -// // while ( invElemIt->more() ) { -// // const SMDS_MeshElement* iel = invElemIt->next(); -// // inverseElemSet.insert( iel ); -// // } -// //} -// } -// } -// -// // either create new elements or reverse mirrored ones -// //if ( !theCopy && !needReverse && !theTargetMesh ) -// if ( !theCopy && !theTargetMesh ) -// return PGroupIDs(); -// -// TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin(); -// for ( ; invElemIt != inverseElemSet.end(); invElemIt++ ) -// theElems.insert( *invElemIt ); -// -// // replicate or reverse elements -// -// enum { -// REV_TETRA = 0, // = nbNodes - 4 -// REV_PYRAMID = 1, // = nbNodes - 4 -// REV_PENTA = 2, // = nbNodes - 4 -// 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 -// { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA -// { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE -// { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA -// { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD -// }; -// -// for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) -// { -// const SMDS_MeshElement* elem = *itElem; -// if ( !elem || elem->GetType() == SMDSAbs_Node ) -// continue; -// -// int nbNodes = elem->NbNodes(); -// int elemType = elem->GetType(); -// -// if (elem->IsPoly()) { -// // Polygon or Polyhedral Volume -// switch ( elemType ) { -// case SMDSAbs_Face: -// { -// vector poly_nodes (nbNodes); -// int iNode = 0; -// SMDS_ElemIteratorPtr itN = elem->nodesIterator(); -// while (itN->more()) { -// const SMDS_MeshNode* node = -// static_cast(itN->next()); -// TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node); -// if (nodeMapIt == nodeMap.end()) -// break; // not all nodes transformed -// //if (needReverse) { -// // // reverse mirrored faces and volumes -// // poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second; -// //} else { -// poly_nodes[iNode] = (*nodeMapIt).second; -// //} -// iNode++; -// } -// if ( iNode != nbNodes ) -// continue; // not all nodes transformed -// -// if ( theTargetMesh ) { -// myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes)); -// srcElems.Append( elem ); -// } -// else if ( theCopy ) { -// myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes)); -// srcElems.Append( elem ); -// } -// else { -// aMesh->ChangePolygonNodes(elem, poly_nodes); -// } -// } -// break; -// case SMDSAbs_Volume: -// { -// // ATTENTION: Reversing is not yet done!!! -// const SMDS_VtkVolume* aPolyedre = -// dynamic_cast( elem ); -// if (!aPolyedre) { -// MESSAGE("Warning: bad volumic element"); -// continue; -// } -// -// vector poly_nodes; -// vector quantities; -// -// bool allTransformed = true; -// int nbFaces = aPolyedre->NbFaces(); -// for (int iface = 1; iface <= nbFaces && allTransformed; iface++) { -// int nbFaceNodes = aPolyedre->NbFaceNodes(iface); -// for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) { -// const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode); -// TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node); -// if (nodeMapIt == nodeMap.end()) { -// allTransformed = false; // not all nodes transformed -// } else { -// poly_nodes.push_back((*nodeMapIt).second); -// } -// } -// quantities.push_back(nbFaceNodes); -// } -// if ( !allTransformed ) -// continue; // not all nodes transformed -// -// if ( theTargetMesh ) { -// myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities)); -// srcElems.Append( elem ); -// } -// else if ( theCopy ) { -// myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities)); -// srcElems.Append( elem ); -// } -// else { -// aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities); -// } -// } -// break; -// default:; -// } -// 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 ]; -// -// 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}; -// i = anIds; -// //if(needReverse) { -// // if(nbNodes==3) { // quadratic edge -// // static int anIds[] = {1,0,2}; -// // i = anIds; -// // } -// // else if(nbNodes==6) { // quadratic triangle -// // static int anIds[] = {0,2,1,5,4,3}; -// // i = anIds; -// // } -// // else if(nbNodes==8) { // quadratic quadrangle -// // static int anIds[] = {0,3,2,1,7,6,5,4}; -// // i = anIds; -// // } -// // else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes -// // static int anIds[] = {0,2,1,3,6,5,4,7,9,8}; -// // i = anIds; -// // } -// // else if(nbNodes==13) { // quadratic pyramid of 13 nodes -// // static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10}; -// // i = anIds; -// // } -// // else if(nbNodes==15) { // quadratic pentahedron with 15 nodes -// // static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13}; -// // i = anIds; -// // } -// // else { // nbNodes==20 - quadratic hexahedron with 20 nodes -// // static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17}; -// // i = anIds; -// // } -// //} -// } -// -// // find transformed nodes -// vector nodes(nbNodes); -// int iNode = 0; -// SMDS_ElemIteratorPtr itN = elem->nodesIterator(); -// while ( itN->more() ) { -// const SMDS_MeshNode* node = -// static_cast( itN->next() ); -// TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node ); -// if ( nodeMapIt == nodeMap.end() ) -// break; // not all nodes transformed -// nodes[ i [ iNode++ ]] = (*nodeMapIt).second; -// } -// if ( iNode != nbNodes ) -// continue; // not all nodes transformed -// -// if ( theTargetMesh ) { -// if ( SMDS_MeshElement* copy = -// targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) { -// myLastCreatedElems.Append( copy ); -// srcElems.Append( elem ); -// } -// } -// else if ( theCopy ) { -// if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) { -// myLastCreatedElems.Append( copy ); -// srcElems.Append( elem ); -// } -// } -// else { -// // reverse element as it was reversed by transformation -// if ( nbNodes > 2 ) -// aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes ); -// } -// } -// -// PGroupIDs newGroupIDs; -// -// if ( theMakeGroups && theCopy || -// theMakeGroups && theTargetMesh ) { -// string groupPostfix = "scaled"; -// newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh ); -// } -// -// return newGroupIDs; -//} - - //======================================================================= /*! * \brief Create groups of elements made during transformation @@ -6005,26 +5977,32 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, // Sort existing groups by types and collect their names // to store an old group and a generated new one - typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup; + typedef pair< SMESHDS_GroupBase*, SMESHDS_Group* > TOldNewGroup; vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes ); + vector< TOldNewGroup* > orderedOldNewGroups; // in order of old groups // group names set< string > groupNames; - // - SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0; + SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups(); - while ( groupIt->more() ) { + if ( !groupIt->more() ) return newGroupIDs; + + int newGroupID = mesh->GetGroupIds().back()+1; + while ( groupIt->more() ) + { SMESH_Group * group = groupIt->next(); if ( !group ) continue; SMESHDS_GroupBase* groupDS = group->GetGroupDS(); if ( !groupDS || groupDS->IsEmpty() ) continue; groupNames.insert( group->GetName() ); groupDS->SetStoreName( group->GetName() ); - groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup )); + SMESHDS_Group* newGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), + groupDS->GetType() ); + groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, newGroup )); + orderedOldNewGroups.push_back( & groupsByType[ groupDS->GetType() ].back() ); } - // Groups creation + // Loop on nodes and elements to add them in new groups - // loop on nodes and elements for ( int isNodes = 0; isNodes < 2; ++isNodes ) { const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens; @@ -6041,7 +6019,7 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, continue; } list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ]; - if ( groupsOldNew.empty() ) { + if ( groupsOldNew.empty() ) { // no groups of this type at all while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem ) ++iElem; // skip all elements made by sourceElem continue; @@ -6055,58 +6033,56 @@ SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens, if ( const SMDS_MeshElement* resElem = elems( ++iElem )) if ( resElem != sourceElem ) resultElems.push_back( resElem ); - // do not generate element groups from node ones - if ( sourceElem->GetType() == SMDSAbs_Node && - elems( iElem )->GetType() != SMDSAbs_Node ) - continue; // add resultElems to groups made by ones the sourceElem belongs to list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end(); for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew ) { SMESHDS_GroupBase* oldGroup = gOldNew->first; - if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup + if ( oldGroup->Contains( sourceElem )) // sourceElem is in oldGroup { - SMDS_MeshGroup* & newGroup = gOldNew->second; - if ( !newGroup )// create a new group - { - // make a name - string name = oldGroup->GetStoreName(); - if ( !targetMesh ) { - name += "_"; - name += postfix; - int nb = 0; - while ( !groupNames.insert( name ).second ) // name exists - { - if ( nb == 0 ) { - name += "_1"; - } - else { - TCollection_AsciiString nbStr(nb+1); - name.resize( name.rfind('_')+1 ); - name += nbStr.ToCString(); - } - ++nb; - } - } - // make a group - int id; - SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(), - name.c_str(), id ); - SMESHDS_Group* groupDS = static_cast(group->GetGroupDS()); - newGroup = & groupDS->SMDSGroup(); - newGroupIDs->push_back( id ); - } - // fill in a new group + SMDS_MeshGroup & newGroup = gOldNew->second->SMDSGroup(); list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt; for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt ) - newGroup->Add( *resElemIt ); + newGroup.Add( *resElemIt ); } } } // loop on created elements }// loop on nodes and elements + // Create new SMESH_Groups from SMESHDS_Groups and remove empty SMESHDS_Groups + + for ( size_t i = 0; i < orderedOldNewGroups.size(); ++i ) + { + SMESHDS_GroupBase* oldGroupDS = orderedOldNewGroups[i]->first; + SMESHDS_Group* newGroupDS = orderedOldNewGroups[i]->second; + if ( newGroupDS->IsEmpty() ) + { + mesh->GetMeshDS()->RemoveGroup( newGroupDS ); + } + else + { + // make a name + string name = oldGroupDS->GetStoreName(); + if ( !targetMesh ) { + name += "_"; + name += postfix; + int nb = 1; + while ( !groupNames.insert( name ).second ) // name exists + name = SMESH_Comment( oldGroupDS->GetStoreName() ) << "_" << postfix << "_" << nb++; + } + newGroupDS->SetStoreName( name.c_str() ); + + // make a SMESH_Groups + mesh->AddGroup( newGroupDS ); + newGroupIDs->push_back( newGroupDS->GetID() ); + + // set group type + newGroupDS->SetType( newGroupDS->GetElements()->next()->GetType() ); + } + } + return newGroupIDs; } @@ -6218,7 +6194,7 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher } else if ( tree->NbNodes() ) // put a tree to the treeMap { - const Bnd_B3d& box = tree->getBox(); + 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 @@ -6230,7 +6206,7 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher TDistTreeMap::iterator sqDist_tree = treeMap.begin(); if ( treeMap.size() > 5 ) { SMESH_OctreeNode* closestTree = sqDist_tree->second; - const Bnd_B3d& box = closestTree->getBox(); + const Bnd_B3d& box = *closestTree->getBox(); double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() ); sqLimit = limit * limit; } @@ -6280,7 +6256,7 @@ private: */ //======================================================================= -SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() +SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() { return new SMESH_NodeSearcherImpl( GetMeshDS() ); } @@ -6302,16 +6278,22 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() { public: - ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius ); - void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems); + ElementBndBoxTree(const SMDS_Mesh& mesh, + SMDSAbs_ElementType elemType, + SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), + double tolerance = NodeRadius ); + void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems ); void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems); + void getElementsInSphere ( const gp_XYZ& center, + const double radius, TIDSortedElemSet& foundElems); + size_t getSize() { return std::max( _size, _elements.size() ); } ~ElementBndBoxTree(); protected: - ElementBndBoxTree() {} - SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; } - void buildChildrenData(); - Bnd_B3d* buildRootBox(); + ElementBndBoxTree():_size(0) {} + SMESH_Octree* newChild() const { return new ElementBndBoxTree; } + void buildChildrenData(); + Bnd_B3d* buildRootBox(); private: //!< Bounding box of element struct ElementBox : public Bnd_B3d @@ -6321,6 +6303,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() ElementBox(const SMDS_MeshElement* elem, double tolerance); }; vector< ElementBox* > _elements; + size_t _size; }; //================================================================================ @@ -6330,7 +6313,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() //================================================================================ ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance) - :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. )) + :SMESH_Octree( new SMESH_TreeLimit( MaxLevel, /*minSize=*/0. )) { int nbElems = mesh.GetMeshInfo().NbElements( elemType ); _elements.reserve( nbElems ); @@ -6339,10 +6322,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() while ( elemIt->more() ) _elements.push_back( new ElementBox( elemIt->next(),tolerance )); - if ( _elements.size() > MaxNbElemsInLeaf ) - compute(); - else - myIsLeaf = true; + compute(); } //================================================================================ @@ -6384,7 +6364,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() { for (int j = 0; j < 8; j++) { - if ( !_elements[i]->IsOut( myChildren[j]->getBox() )) + if ( !_elements[i]->IsOut( *myChildren[j]->getBox() )) { _elements[i]->_refCount++; ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]); @@ -6392,7 +6372,8 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() } _elements[i]->_refCount--; } - _elements.clear(); + _size = _elements.size(); + SMESHUtils::FreeVector( _elements ); // = _elements.clear() + free memory for (int j = 0; j < 8; j++) { @@ -6401,7 +6382,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() child->myIsLeaf = true; if ( child->_elements.capacity() - child->_elements.size() > 1000 ) - child->_elements.resize( child->_elements.size() ); // compact + SMESHUtils::CompactVector( child->_elements ); } } @@ -6414,7 +6395,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems) { - if ( level() && getBox().IsOut( point.XYZ() )) + if ( getBox()->IsOut( point.XYZ() )) return; if ( isLeaf() ) @@ -6439,7 +6420,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line, TIDSortedElemSet& foundElems) { - if ( level() && getBox().IsOut( line )) + if ( getBox()->IsOut( line )) return; if ( isLeaf() ) @@ -6455,6 +6436,32 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() } } + //================================================================================ + /*! + * \brief Return elements from leaves intersecting the sphere + */ + //================================================================================ + + void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ& center, + const double radius, + TIDSortedElemSet& foundElems) + { + if ( getBox()->IsOut( center, radius )) + return; + + if ( isLeaf() ) + { + for ( int i = 0; i < _elements.size(); ++i ) + if ( !_elements[i]->IsOut( center, radius )) + foundElems.insert( _elements[i]->_element ); + } + else + { + for (int i = 0; i < 8; i++) + ((ElementBndBoxTree*) myChildren[i])->getElementsInSphere( center, radius, foundElems ); + } + } + //================================================================================ /*! * \brief Construct the element box @@ -6467,7 +6474,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint() _refCount = 1; SMDS_ElemIteratorPtr nIt = elem->nodesIterator(); while ( nIt->more() ) - Add( SMESH_TNodeXYZ( cast2Node( nIt->next() ))); + Add( SMESH_TNodeXYZ( nIt->next() )); Enlarge( tolerance ); } @@ -6502,6 +6509,8 @@ struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher SMDSAbs_ElementType type, vector< const SMDS_MeshElement* >& foundElements); virtual TopAbs_State GetPointState(const gp_Pnt& point); + virtual const SMDS_MeshElement* FindClosestTo( const gp_Pnt& point, + SMDSAbs_ElementType type ); void GetElementsNearLine( const gp_Ax1& line, SMDSAbs_ElementType type, @@ -6612,12 +6621,12 @@ bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& lin 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_TNodeXYZ( face->GetNode( i )), - SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); + SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); anExtCC.Init( lineCurve, edge); if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol) { @@ -6666,7 +6675,7 @@ void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerF while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces ))) faces.insert( f ); - // select another outer face among the found + // select another outer face among the found const SMDS_MeshElement* outerFace2 = 0; if ( faces.size() == 2 ) { @@ -6698,7 +6707,7 @@ void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerF continue; gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2; double angle = dirInOF.AngleWithRef( dirInF, n1n2 ); - if ( angle < 0 ) angle += 2*PI; + if ( angle < 0 ) angle += 2. * M_PI; angle2Face.insert( make_pair( angle, *face )); } if ( !angle2Face.empty() ) @@ -6726,7 +6735,7 @@ void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerF // 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 { @@ -6739,7 +6748,7 @@ void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerF * \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 + * 'ALL' type means elements of any type excluding nodes, balls and 0D elements */ //======================================================================= @@ -6753,7 +6762,7 @@ FindElementsByPoint(const gp_Pnt& point, double tolerance = getTolerance(); // ================================================================================= - if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement ) + if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement || type == SMDSAbs_Ball) { if ( !_nodeSearcher ) _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh ); @@ -6770,7 +6779,7 @@ FindElementsByPoint(const gp_Pnt& point, } else { - SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement ); + SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( type ); while ( elemIt->more() ) foundElements.push_back( elemIt->next() ); } @@ -6787,12 +6796,103 @@ FindElementsByPoint(const gp_Pnt& point, _ebbTree->getElementsNearPoint( point, suspectElems ); TIDSortedElemSet::iterator elem = suspectElems.begin(); for ( ; elem != suspectElems.end(); ++elem ) - if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance )) + if ( !SMESH_MeshEditor::IsOut( *elem, point, tolerance )) foundElements.push_back( *elem ); } return foundElements.size(); } +//======================================================================= +/*! + * \brief Find an element of given type most close to the given point + * + * WARNING: Only face search is implemeneted so far + */ +//======================================================================= + +const SMDS_MeshElement* +SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt& point, + SMDSAbs_ElementType type ) +{ + const SMDS_MeshElement* closestElem = 0; + + if ( type == SMDSAbs_Face ) + { + if ( !_ebbTree || _elementType != type ) + { + if ( _ebbTree ) delete _ebbTree; + _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt ); + } + TIDSortedElemSet suspectElems; + _ebbTree->getElementsNearPoint( point, suspectElems ); + + if ( suspectElems.empty() && _ebbTree->maxSize() > 0 ) + { + gp_Pnt boxCenter = 0.5 * ( _ebbTree->getBox()->CornerMin() + + _ebbTree->getBox()->CornerMax() ); + double radius; + if ( _ebbTree->getBox()->IsOut( point.XYZ() )) + radius = point.Distance( boxCenter ) - 0.5 * _ebbTree->maxSize(); + else + radius = _ebbTree->maxSize() / pow( 2., _ebbTree->getHeight()) / 2; + while ( suspectElems.empty() ) + { + _ebbTree->getElementsInSphere( point.XYZ(), radius, suspectElems ); + radius *= 1.1; + } + } + double minDist = std::numeric_limits::max(); + multimap< double, const SMDS_MeshElement* > dist2face; + TIDSortedElemSet::iterator elem = suspectElems.begin(); + for ( ; elem != suspectElems.end(); ++elem ) + { + double dist = SMESH_MeshEditor::GetDistance( dynamic_cast(*elem), + point ); + if ( dist < minDist + 1e-10) + { + minDist = dist; + dist2face.insert( dist2face.begin(), make_pair( dist, *elem )); + } + } + if ( !dist2face.empty() ) + { + multimap< double, const SMDS_MeshElement* >::iterator d2f = dist2face.begin(); + closestElem = d2f->second; + // if there are several elements at the same distance, select one + // with GC closest to the point + typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator; + double minDistToGC = 0; + for ( ++d2f; d2f != dist2face.end() && fabs( d2f->first - minDist ) < 1e-10; ++d2f ) + { + if ( minDistToGC == 0 ) + { + gp_XYZ gc(0,0,0); + gc = accumulate( TXyzIterator(closestElem->nodesIterator()), + TXyzIterator(), gc ) / closestElem->NbNodes(); + minDistToGC = point.SquareDistance( gc ); + } + gp_XYZ gc(0,0,0); + gc = accumulate( TXyzIterator( d2f->second->nodesIterator()), + TXyzIterator(), gc ) / d2f->second->NbNodes(); + double d = point.SquareDistance( gc ); + if ( d < minDistToGC ) + { + minDistToGC = d; + closestElem = d2f->second; + } + } + // cout << "FindClosestTo( " <GetID() << " DIST " << minDist << endl; + } + } + else + { + // NOT IMPLEMENTED SO FAR + } + return closestElem; +} + + //================================================================================ /*! * \brief Classify the given point in the closed 2D mesh @@ -6846,7 +6946,7 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point) else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 ) { gp_Pnt intersectionPoint = intersection.Point(1); - if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance )) + if ( !SMESH_MeshEditor::IsOut( *face, intersectionPoint, tolerance )) u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm ))); } } @@ -6854,7 +6954,7 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point) int nbInter = u2inters.size(); if ( nbInter == 0 ) - return TopAbs_OUT; + return TopAbs_OUT; double f = u2inters.begin()->first, l = u2inters.rbegin()->first; if ( nbInter == 1 ) // not closed mesh @@ -6988,7 +7088,7 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point) return TopAbs_ON; if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0) - return TopAbs_OUT; + return TopAbs_OUT; if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN; @@ -7064,7 +7164,7 @@ SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr */ //======================================================================= -bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol ) +bool SMESH_MeshEditor::IsOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol ) { if ( element->GetType() == SMDSAbs_Volume) { @@ -7111,7 +7211,7 @@ bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& poi for ( i = 0; i < nbNodes; ++i ) { SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] ); - if ( !isOut( &edge, point, tol )) + if ( !IsOut( &edge, point, tol )) return false; } return true; @@ -7217,6 +7317,170 @@ bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& poi return true; } +//======================================================================= + +namespace +{ + // Position of a point relative to a segment + // . . + // . LEFT . + // . . + // VERTEX 1 o----ON-----> VERTEX 2 + // . . + // . RIGHT . + // . . + enum PositionName { POS_LEFT = 1, POS_VERTEX = 2, POS_RIGHT = 4, //POS_ON = 8, + POS_ALL = POS_LEFT | POS_RIGHT | POS_VERTEX }; + struct PointPos + { + PositionName _name; + int _index; // index of vertex or segment + + PointPos( PositionName n, int i=-1 ): _name(n), _index(i) {} + bool operator < (const PointPos& other ) const + { + if ( _name == other._name ) + return ( _index < 0 || other._index < 0 ) ? false : _index < other._index; + return _name < other._name; + } + }; + + //================================================================================ + /*! + * \brief Return of a point relative to a segment + * \param point2D - the point to analyze position of + * \param xyVec - end points of segments + * \param index0 - 0-based index of the first point of segment + * \param posToFindOut - flags of positions to detect + * \retval PointPos - point position + */ + //================================================================================ + + PointPos getPointPosition( const gp_XY& point2D, + const gp_XY* segEnds, + const int index0 = 0, + const int posToFindOut = POS_ALL) + { + const gp_XY& p1 = segEnds[ index0 ]; + const gp_XY& p2 = segEnds[ index0+1 ]; + const gp_XY grad = p2 - p1; + + if ( posToFindOut & POS_VERTEX ) + { + // check if the point2D is at "vertex 1" zone + gp_XY pp1[2] = { p1, gp_XY( p1.X() - grad.Y(), + p1.Y() + grad.X() ) }; + if ( getPointPosition( point2D, pp1, 0, POS_LEFT|POS_RIGHT )._name == POS_LEFT ) + return PointPos( POS_VERTEX, index0 ); + + // check if the point2D is at "vertex 2" zone + gp_XY pp2[2] = { p2, gp_XY( p2.X() - grad.Y(), + p2.Y() + grad.X() ) }; + if ( getPointPosition( point2D, pp2, 0, POS_LEFT|POS_RIGHT )._name == POS_RIGHT ) + return PointPos( POS_VERTEX, index0 + 1); + } + double edgeEquation = + ( point2D.X() - p1.X() ) * grad.Y() - ( point2D.Y() - p1.Y() ) * grad.X(); + return PointPos( edgeEquation < 0 ? POS_LEFT : POS_RIGHT, index0 ); + } +} + +//======================================================================= +/*! + * \brief Return minimal distance from a point to a face + * + * Currently we ignore non-planarity and 2nd order of face + */ +//======================================================================= + +double SMESH_MeshEditor::GetDistance( const SMDS_MeshFace* face, + const gp_Pnt& point ) +{ + double badDistance = -1; + if ( !face ) return badDistance; + + // coordinates of nodes (medium nodes, if any, ignored) + typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator; + vector xyz( TXyzIterator( face->nodesIterator()), TXyzIterator() ); + xyz.resize( face->NbCornerNodes()+1 ); + + // transformation to get xyz[0] lies on the origin, xyz[1] lies on the Z axis, + // and xyz[2] lies in the XZ plane. This is to pass to 2D space on XZ plane. + gp_Trsf trsf; + gp_Vec OZ ( xyz[0], xyz[1] ); + gp_Vec OX ( xyz[0], xyz[2] ); + if ( OZ.Magnitude() < std::numeric_limits::min() ) + { + if ( xyz.size() < 4 ) return badDistance; + OZ = gp_Vec ( xyz[0], xyz[2] ); + OX = gp_Vec ( xyz[0], xyz[3] ); + } + gp_Ax3 tgtCS; + try { + tgtCS = gp_Ax3( xyz[0], OZ, OX ); + } + catch ( Standard_Failure ) { + return badDistance; + } + trsf.SetTransformation( tgtCS ); + + // move all the nodes to 2D + vector xy( xyz.size() ); + for ( size_t i = 0;i < xyz.size()-1; ++i ) + { + gp_XYZ p3d = xyz[i]; + trsf.Transforms( p3d ); + xy[i].SetCoord( p3d.X(), p3d.Z() ); + } + xyz.back() = xyz.front(); + xy.back() = xy.front(); + + // // move the point in 2D + gp_XYZ tmpPnt = point.XYZ(); + trsf.Transforms( tmpPnt ); + gp_XY point2D( tmpPnt.X(), tmpPnt.Z() ); + + // loop on segments of the face to analyze point position ralative to the face + set< PointPos > pntPosSet; + for ( size_t i = 1; i < xy.size(); ++i ) + { + PointPos pos = getPointPosition( point2D, &xy[0], i-1 ); + pntPosSet.insert( pos ); + } + + // compute distance + PointPos pos = *pntPosSet.begin(); + // cout << "Face " << face->GetID() << " DIST: "; + switch ( pos._name ) + { + case POS_LEFT: { + // point is most close to a segment + gp_Vec p0p1( point, xyz[ pos._index ] ); + gp_Vec p1p2( xyz[ pos._index ], xyz[ pos._index+1 ]); // segment vector + p1p2.Normalize(); + double projDist = p0p1 * p1p2; // distance projected to the segment + gp_Vec projVec = p1p2 * projDist; + gp_Vec distVec = p0p1 - projVec; + // cout << distVec.Magnitude() << ", SEG " << face->GetNode(pos._index)->GetID() + // << " - " << face->GetNodeWrap(pos._index+1)->GetID() << endl; + return distVec.Magnitude(); + } + case POS_RIGHT: { + // point is inside the face + double distToFacePlane = tmpPnt.Y(); + // cout << distToFacePlane << ", INSIDE " << endl; + return Abs( distToFacePlane ); + } + case POS_VERTEX: { + // point is most close to a node + gp_Vec distVec( point, xyz[ pos._index ]); + // cout << distVec.Magnitude() << " VERTEX " << face->GetNode(pos._index)->GetID() << endl; + return distVec.Magnitude(); + } + } + return badDistance; +} + //======================================================================= //function : SimplifyFace //purpose : @@ -7384,15 +7648,13 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) } } // BUG 0020185: end - iRepl[ nbRepl++ ] = iCur; } curNodes[ iCur ] = n; bool isUnique = nodeSet.insert( n ).second; - if ( isUnique ) { + if ( isUnique ) uniqueNodes[ iUnique++ ] = n; - if ( nbRepl && iRepl[ nbRepl-1 ] == iCur ) - --nbRepl; // n do not stick to a node of the elem - } + else + iRepl[ nbRepl++ ] = iCur; iCur++; } @@ -7985,32 +8247,29 @@ private: //purpose : Return list of group of elements built on the same nodes. // Search among theElements or in the whole mesh if theElements is empty //======================================================================= -void SMESH_MeshEditor::FindEqualElements(set & theElements, - TListOfListOfElementsID & theGroupsOfElementsID) + +void SMESH_MeshEditor::FindEqualElements(TIDSortedElemSet & theElements, + TListOfListOfElementsID & theGroupsOfElementsID) { myLastCreatedElems.Clear(); myLastCreatedNodes.Clear(); - typedef set TElemsSet; typedef map< SortableElement, int > TMapOfNodeSet; typedef list TGroupOfElems; - TElemsSet elems; if ( theElements.empty() ) { // get all elements in the mesh SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator(); while ( eIt->more() ) - elems.insert( elems.end(), eIt->next()); + theElements.insert( theElements.end(), eIt->next()); } - else - elems = theElements; vector< TGroupOfElems > arrayOfGroups; TGroupOfElems groupOfElems; TMapOfNodeSet mapOfNodeSet; - TElemsSet::iterator elemIt = elems.begin(); - for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) { + TIDSortedElemSet::iterator elemIt = theElements.begin(); + for ( int i = 0, j=0; elemIt != theElements.end(); ++elemIt, ++j ) { const SMDS_MeshElement* curElem = *elemIt; SortableElement SE(curElem); int ind = -1; @@ -8083,8 +8342,8 @@ void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElemen void SMESH_MeshEditor::MergeEqualElements() { - set aMeshElements; /* empty input - - to merge equal elements in the whole mesh */ + TIDSortedElemSet aMeshElements; /* empty input == + to merge equal elements in the whole mesh */ TListOfListOfElementsID aGroupsOfElementsID; FindEqualElements(aMeshElements, aGroupsOfElementsID); MergeElements(aGroupsOfElementsID); @@ -9224,6 +9483,30 @@ void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode } } +namespace +{ + //================================================================================ + /*! + * \brief Transform any volume into data of SMDSEntity_Polyhedra + */ + //================================================================================ + + void volumeToPolyhedron( const SMDS_MeshElement* elem, + vector & nodes, + vector & nbNodeInFaces ) + { + nodes.clear(); + nbNodeInFaces.clear(); + SMDS_VolumeTool vTool ( elem ); + for ( int iF = 0; iF < vTool.NbFaces(); ++iF ) + { + const SMDS_MeshNode** fNodes = vTool.GetFaceNodes( iF ); + nodes.insert( nodes.end(), fNodes, fNodes + vTool.NbFaceNodes( iF )); + nbNodeInFaces.push_back( vTool.NbFaceNodes( iF )); + } + } +} + //======================================================================= /*! * \brief Convert elements contained in a submesh to quadratic @@ -9239,6 +9522,7 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, if( !theSm ) return nbElem; vector nbNodeInFaces; + vector nodes; SMDS_ElemIteratorPtr ElemItr = theSm->GetElements(); while(ElemItr->more()) { @@ -9246,14 +9530,19 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, const SMDS_MeshElement* elem = ElemItr->next(); if( !elem || elem->IsQuadratic() ) continue; - int id = elem->GetID(); - int nbNodes = elem->NbNodes(); - SMDSAbs_ElementType aType = elem->GetType(); - - vector nodes (elem->begin_nodes(), elem->end_nodes()); - if ( elem->GetEntityType() == SMDSEntity_Polyhedra ) + // get elem data needed to re-create it + // + const int id = elem->GetID(); + const int nbNodes = elem->NbNodes(); + const SMDSAbs_ElementType aType = elem->GetType(); + const SMDSAbs_EntityType aGeomType = elem->GetEntityType(); + nodes.assign(elem->begin_nodes(), elem->end_nodes()); + if ( aGeomType == SMDSEntity_Polyhedra ) nbNodeInFaces = static_cast( elem )->GetQuantities(); + else if ( aGeomType == SMDSEntity_Hexagonal_Prism ) + volumeToPolyhedron( elem, nodes, nbNodeInFaces ); + // remove a linear element GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false); const SMDS_MeshElement* NewElem = 0; @@ -9283,21 +9572,22 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, } case SMDSAbs_Volume : { - switch(nbNodes) + switch( aGeomType ) { - case 4: + case SMDSEntity_Tetra: NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d); break; - case 5: + case SMDSEntity_Pyramid: NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d); break; - case 6: + case SMDSEntity_Penta: NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d); break; - case 8: + case SMDSEntity_Hexa: NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d); break; + case SMDSEntity_Hexagonal_Prism: default: NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d); } @@ -9310,8 +9600,6 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, if( NewElem ) theSm->AddElement( NewElem ); } -// if (!GetMeshDS()->isCompacted()) -// GetMeshDS()->compactMesh(); return nbElem; } @@ -9319,6 +9607,7 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm, //function : ConvertToQuadratic //purpose : //======================================================================= + void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d) { SMESHDS_Mesh* meshDS = GetMeshDS(); @@ -9368,19 +9657,19 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d) const SMDS_MeshFace* face = aFaceItr->next(); if(!face || face->IsQuadratic() ) continue; - int id = face->GetID(); - int nbNodes = face->NbNodes(); + const int id = face->GetID(); + const SMDSAbs_EntityType type = face->GetEntityType(); vector nodes ( face->begin_nodes(), face->end_nodes()); meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false); SMDS_MeshFace * NewFace = 0; - switch(nbNodes) + switch( type ) { - case 3: + case SMDSEntity_Triangle: NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d); break; - case 4: + case SMDSEntity_Quadrangle: NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d); break; default: @@ -9395,33 +9684,35 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d) const SMDS_MeshVolume* volume = aVolumeItr->next(); if(!volume || volume->IsQuadratic() ) continue; - int id = volume->GetID(); - int nbNodes = volume->NbNodes(); + const int id = volume->GetID(); + const SMDSAbs_EntityType type = volume->GetEntityType(); vector nodes (volume->begin_nodes(), volume->end_nodes()); - if ( volume->GetEntityType() == SMDSEntity_Polyhedra ) + if ( type == SMDSEntity_Polyhedra ) nbNodeInFaces = static_cast(volume)->GetQuantities(); + else if ( type == SMDSEntity_Hexagonal_Prism ) + volumeToPolyhedron( volume, nodes, nbNodeInFaces ); meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false); SMDS_MeshVolume * NewVolume = 0; - switch(nbNodes) + switch ( type ) { - case 4: - NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], - nodes[3], id, theForce3d ); + case SMDSEntity_Tetra: + 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(nodes[0], nodes[1], nodes[2], - nodes[3], nodes[4], nodes[5], id, theForce3d); - break; - case 8: + case SMDSEntity_Hexa: NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d); break; + case SMDSEntity_Pyramid: + NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], + nodes[3], nodes[4], id, theForce3d); + break; + case SMDSEntity_Penta: + NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], + nodes[3], nodes[4], nodes[5], id, theForce3d); + break; + case SMDSEntity_Hexagonal_Prism: default: NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d); } @@ -9432,7 +9723,7 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d) if ( !theForce3d ) { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh - aHelper.FixQuadraticElements(); + aHelper.FixQuadraticElements(myError); } } @@ -9440,7 +9731,7 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d) /*! * \brief Makes given elements quadratic * \param theForce3d - if true, the medium nodes will be placed in the middle of link - * \param theElements - elements to make quadratic + * \param theElements - elements to make quadratic */ //================================================================================ @@ -9450,8 +9741,8 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, if ( theElements.empty() ) return; // we believe that all theElements are of the same type - SMDSAbs_ElementType elemType = (*theElements.begin())->GetType(); - + const SMDSAbs_ElementType elemType = (*theElements.begin())->GetType(); + // get all nodes shared by theElements TIDSortedNodeSet allNodes; TIDSortedElemSet::iterator eIt = theElements.begin(); @@ -9527,8 +9818,8 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() ) continue; - int id = elem->GetID(); - SMDSAbs_ElementType type = elem->GetType(); + const int id = elem->GetID(); + const SMDSAbs_ElementType type = elem->GetType(); vector nodes ( elem->begin_nodes(), elem->end_nodes()); if ( !smDS || !smDS->Contains( elem )) @@ -9538,7 +9829,7 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, SMDS_MeshElement * newElem = 0; switch( nodes.size() ) { - case 4: // cases for most multiple element types go first (for optimization) + case 4: // cases for most frequently used element types go first (for optimization) if ( type == SMDSAbs_Volume ) newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d); else @@ -9572,7 +9863,7 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, if ( !theForce3d && !getenv("NO_FixQuadraticElements")) { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh - helper.FixQuadraticElements(); + helper.FixQuadraticElements( myError ); } } @@ -9788,20 +10079,20 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, SMESHDS_Mesh* aMesh = GetMeshDS(); // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh - set faceSet1, faceSet2; + TIDSortedElemSet faceSet1, faceSet2; set volSet1, volSet2; set nodeSet1, nodeSet2; - set * faceSetPtr[] = { &faceSet1, &faceSet2 }; - set * volSetPtr[] = { &volSet1, &volSet2 }; + TIDSortedElemSet * faceSetPtr[] = { &faceSet1, &faceSet2 }; + set * volSetPtr[] = { &volSet1, &volSet2 }; set * nodeSetPtr[] = { &nodeSet1, &nodeSet2 }; - TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 }; + TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 }; int iSide, iFace, iNode; list tempFaceList; for ( iSide = 0; iSide < 2; iSide++ ) { set * nodeSet = nodeSetPtr[ iSide ]; - TIDSortedElemSet * elemSet = elemSetPtr[ iSide ]; - set * faceSet = faceSetPtr[ iSide ]; + TIDSortedElemSet * elemSet = elemSetPtr[ iSide ]; + TIDSortedElemSet * faceSet = faceSetPtr[ iSide ]; set * volSet = volSetPtr [ iSide ]; set::iterator vIt; TIDSortedElemSet::iterator eIt; @@ -9903,16 +10194,8 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second; if ( isNewFace ) { // no such a face is given but it still can exist, check it - if ( nbNodes == 3 ) { - aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] ); - } - else if ( nbNodes == 4 ) { - aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] ); - } - else { - vector poly_nodes ( fNodes, & fNodes[nbNodes]); - aFreeFace = aMesh->FindFace(poly_nodes); - } + vector nodes ( fNodes, fNodes + nbNodes); + aFreeFace = aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false ); } if ( !aFreeFace ) { // create a temporary face @@ -9929,19 +10212,20 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes); aFreeFace = aMesh->AddPolygonalFace(poly_nodes); } + if ( aFreeFace ) + tempFaceList.push_back( aFreeFace ); } - if ( aFreeFace ) { + + if ( aFreeFace ) freeFaceList.push_back( aFreeFace ); - tempFaceList.push_back( aFreeFace ); - } } // loop on faces of a volume - // choose one of several free faces - // -------------------------------------- + // choose one of several free faces of a volume + // -------------------------------------------- if ( freeFaceList.size() > 1 ) { // choose a face having max nb of nodes shared by other elems of a side - int maxNbNodes = -1/*, nbExcludedFaces = 0*/; + int maxNbNodes = -1; list::iterator fIt = freeFaceList.begin(); while ( fIt != freeFaceList.end() ) { // loop on free faces int nbSharedNodes = 0; @@ -9952,18 +10236,20 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator(); while ( invElemIt->more() ) { const SMDS_MeshElement* e = invElemIt->next(); - if ( faceSet->find( e ) != faceSet->end() ) - nbSharedNodes++; - if ( elemSet->find( e ) != elemSet->end() ) - nbSharedNodes++; + nbSharedNodes += faceSet->count( e ); + nbSharedNodes += elemSet->count( e ); } } - if ( nbSharedNodes >= maxNbNodes ) { + if ( nbSharedNodes > maxNbNodes ) { maxNbNodes = nbSharedNodes; + freeFaceList.erase( freeFaceList.begin(), fIt++ ); + } + else if ( nbSharedNodes == maxNbNodes ) { fIt++; } - else + else { freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase + } } if ( freeFaceList.size() > 1 ) { @@ -10064,9 +10350,9 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead if ( theFirstNode1 != theFirstNode2 ) - nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 )); + nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 )); if ( theSecondNode1 != theSecondNode2 ) - nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 )); + nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 )); LinkID_Gen aLinkID_Gen( GetMeshDS() ); set< long > linkIdSet; // links to process @@ -10079,10 +10365,11 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, // loop on links in linkList; find faces by links and append links // of the found faces to linkList list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ; - for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) { + for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) + { NLink link[] = { *linkIt[0], *linkIt[1] }; long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second ); - if ( linkIdSet.find( linkID ) == linkIdSet.end() ) + if ( !linkIdSet.count( linkID ) ) continue; // by links, find faces in the face sets, @@ -10091,120 +10378,37 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, // --------------------------------------------------------------- const SMDS_MeshElement* face[] = { 0, 0 }; - //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ]; - vector fnodes1(9); - vector fnodes2(9); - //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ; - vector notLinkNodes1(6); - vector notLinkNodes2(6); + vector fnodes[2]; int iLinkNode[2][2]; + TIDSortedElemSet avoidSet; for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides const SMDS_MeshNode* n1 = link[iSide].first; const SMDS_MeshNode* n2 = link[iSide].second; - set * faceSet = faceSetPtr[ iSide ]; - set< const SMDS_MeshElement* > fMap; - for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link - const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link - SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face); - while ( fIt->more() ) { // loop on faces sharing a node - const SMDS_MeshElement* f = fIt->next(); - if (faceSet->find( f ) != faceSet->end() && // f is in face set - ! fMap.insert( f ).second ) // f encounters twice - { - if ( face[ iSide ] ) { - MESSAGE( "2 faces per link " ); - aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES; - break; - } - face[ iSide ] = f; - faceSet->erase( f ); - // get face nodes and find ones of a link - iNode = 0; - int nbl = -1; - if(f->IsPoly()) { - if(iSide==0) { - fnodes1.resize(f->NbNodes()+1); - notLinkNodes1.resize(f->NbNodes()-2); - } - else { - fnodes2.resize(f->NbNodes()+1); - notLinkNodes2.resize(f->NbNodes()-2); - } - } - if(!f->IsQuadratic()) { - SMDS_ElemIteratorPtr nIt = f->nodesIterator(); - while ( nIt->more() ) { - const SMDS_MeshNode* n = - static_cast( nIt->next() ); - if ( n == n1 ) { - iLinkNode[ iSide ][ 0 ] = iNode; - } - else if ( n == n2 ) { - iLinkNode[ iSide ][ 1 ] = iNode; - } - //else if ( notLinkNodes[ iSide ][ 0 ] ) - // notLinkNodes[ iSide ][ 1 ] = n; - //else - // notLinkNodes[ iSide ][ 0 ] = n; - else { - nbl++; - if(iSide==0) - notLinkNodes1[nbl] = n; - //notLinkNodes1.push_back(n); - else - notLinkNodes2[nbl] = n; - //notLinkNodes2.push_back(n); - } - //faceNodes[ iSide ][ iNode++ ] = n; - if(iSide==0) { - fnodes1[iNode++] = n; - } - else { - fnodes2[iNode++] = n; - } - } - } - else { // f->IsQuadratic() - const SMDS_VtkFace* F = - dynamic_cast(f); - if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace")); - // use special nodes iterator - SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator(); - while ( anIter->more() ) { - const SMDS_MeshNode* n = - static_cast( anIter->next() ); - if ( n == n1 ) { - iLinkNode[ iSide ][ 0 ] = iNode; - } - else if ( n == n2 ) { - iLinkNode[ iSide ][ 1 ] = iNode; - } - else { - nbl++; - if(iSide==0) { - notLinkNodes1[nbl] = n; - } - else { - notLinkNodes2[nbl] = n; - } - } - if(iSide==0) { - fnodes1[iNode++] = n; - } - else { - fnodes2[iNode++] = n; - } - } - } - //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ]; - if(iSide==0) { - fnodes1[iNode] = fnodes1[0]; - } - else { - fnodes2[iNode] = fnodes1[0]; - } - } + //cout << "Side " << iSide << " "; + //cout << "L( " << n1->GetID() << ", " << n2->GetID() << " ) " << endl; + // find a face by two link nodes + face[ iSide ] = FindFaceInSet( n1, n2, *faceSetPtr[ iSide ], avoidSet, + &iLinkNode[iSide][0], &iLinkNode[iSide][1] ); + if ( face[ iSide ]) + { + //cout << " F " << face[ iSide]->GetID() <erase( face[ iSide ]); + // put face nodes to fnodes + if ( face[ iSide ]->IsQuadratic() ) + { + // use interlaced nodes iterator + const SMDS_VtkFace* F = dynamic_cast( face[ iSide ]); + if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace")); + SMDS_ElemIteratorPtr nIter = F->interlacedNodesElemIterator(); + while ( nIter->more() ) + fnodes[ iSide ].push_back( cast2Node( nIter->next() )); + } + else + { + fnodes[ iSide ].assign( face[ iSide ]->begin_nodes(), + face[ iSide ]->end_nodes() ); } + fnodes[ iSide ].push_back( fnodes[ iSide ].front()); } } @@ -10217,86 +10421,60 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, else { aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS; } - break; // do not return because it s necessary to remove tmp faces + break; // do not return because it's necessary to remove tmp faces } // set nodes to merge // ------------------- if ( face[0] && face[1] ) { - int nbNodes = face[0]->NbNodes(); + const int nbNodes = face[0]->NbNodes(); if ( nbNodes != face[1]->NbNodes() ) { MESSAGE("Diff nb of face nodes"); aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS; break; // do not return because it s necessary to remove tmp faces } - bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle - if ( nbNodes == 3 ) { - //nReplaceMap.insert( TNodeNodeMap::value_type - // ( notLinkNodes[0][0], notLinkNodes[1][0] )); - nReplaceMap.insert( TNodeNodeMap::value_type - ( notLinkNodes1[0], notLinkNodes2[0] )); + bool reverse[] = { false, false }; // order of nodes in the link + for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides + // analyse link orientation in faces + int i1 = iLinkNode[ iSide ][ 0 ]; + int i2 = iLinkNode[ iSide ][ 1 ]; + reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1; } - else { - for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides - // analyse link orientation in faces - int i1 = iLinkNode[ iSide ][ 0 ]; - int i2 = iLinkNode[ iSide ][ 1 ]; - reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1; - // if notLinkNodes are the first and the last ones, then - // their order does not correspond to the link orientation - if (( i1 == 1 && i2 == 2 ) || - ( i1 == 2 && i2 == 1 )) - reverse[ iSide ] = !reverse[ iSide ]; - } - if ( reverse[0] == reverse[1] ) { - //nReplaceMap.insert( TNodeNodeMap::value_type - // ( notLinkNodes[0][0], notLinkNodes[1][0] )); - //nReplaceMap.insert( TNodeNodeMap::value_type - // ( notLinkNodes[0][1], notLinkNodes[1][1] )); - for(int nn=0; nn 0; --i, i1 += di1, i2 += di2 ) + { + nReplaceMap.insert ( make_pair ( fnodes[0][ ( i1 + nbNodes ) % nbNodes ], + fnodes[1][ ( i2 + nbNodes ) % nbNodes ])); } // add other links of the faces to linkList // ----------------------------------------- - //const SMDS_MeshNode** nodes = faceNodes[ 0 ]; for ( iNode = 0; iNode < nbNodes; iNode++ ) { - //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] ); - linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] ); + linkID = aLinkID_Gen.GetLinkID( fnodes[0][iNode], fnodes[0][iNode+1] ); pair< set::iterator, bool > iter_isnew = linkIdSet.insert( linkID ); if ( !iter_isnew.second ) { // already in a set: no need to process linkIdSet.erase( iter_isnew.first ); } else // new in set == encountered for the first time: add { - //const SMDS_MeshNode* n1 = nodes[ iNode ]; - //const SMDS_MeshNode* n2 = nodes[ iNode + 1]; - const SMDS_MeshNode* n1 = fnodes1[ iNode ]; - const SMDS_MeshNode* n2 = fnodes1[ iNode + 1]; + const SMDS_MeshNode* n1 = fnodes[0][ iNode ]; + const SMDS_MeshNode* n2 = fnodes[0][ iNode + 1]; linkList[0].push_back ( NLink( n1, n2 )); linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] )); } } } // 2 faces found + + if ( faceSetPtr[0]->empty() || faceSetPtr[1]->empty() ) + break; + } // loop on link lists if ( aResult == SEW_OK && - ( linkIt[0] != linkList[0].end() || + ( //linkIt[0] != linkList[0].end() || !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) { MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) << " " << (faceSetPtr[1]->empty())); @@ -10307,13 +10485,13 @@ SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1, // 3. Replace nodes in elements of the side 1 and remove replaced nodes // ==================================================================== - // delete temporary faces: they are in reverseElements of actual nodes + // delete temporary faces // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator(); // while ( tmpFaceIt->more() ) // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() ); -// list::iterator tmpFaceIt = tempFaceList.begin(); -// for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt) -// aMesh->RemoveElement(*tmpFaceIt); + list::iterator tmpFaceIt = tempFaceList.begin(); + for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt) + aMesh->RemoveElement(*tmpFaceIt); if ( aResult != SEW_OK) return aResult; @@ -10549,7 +10727,7 @@ SMESH_MeshEditor::FindMatchingNodes(set& theSide1, \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 + \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 */ @@ -10612,8 +10790,8 @@ bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS, std::vector newNodes( anElem->NbNodes() ); SMDS_ElemIteratorPtr anIter = anElem->nodesIterator(); int ind = 0; - while ( anIter->more() ) - { + while ( anIter->more() ) + { SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next(); SMDS_MeshNode* aNewNode = aCurrNode; @@ -10648,14 +10826,14 @@ bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS, /*! \brief Creates a hole in a mesh by doubling the nodes of some particular elements \param theNodes - identifiers of nodes to be doubled - \param theModifiedElems - identifiers of elements to be updated by the new (doubled) - nodes. If list of element identifiers is empty then nodes are doubled but + \param theModifiedElems - identifiers of elements to be updated by the new (doubled) + nodes. If list of element identifiers is empty then nodes are doubled but they not assigned to elements \return TRUE if operation has been completed successfully, FALSE otherwise */ //================================================================================ -bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, +bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, const std::list< int >& theListOfModifiedElems ) { MESSAGE("DoubleNodes"); @@ -10696,7 +10874,7 @@ bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, std::map< SMDS_MeshElement*, vector > anElemToNodes; std::list< int >::const_iterator anElemIter; - for ( anElemIter = theListOfModifiedElems.begin(); + for ( anElemIter = theListOfModifiedElems.begin(); anElemIter != theListOfModifiedElems.end(); ++anElemIter ) { int aCurr = *anElemIter; @@ -10708,8 +10886,8 @@ bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, SMDS_ElemIteratorPtr anIter = anElem->nodesIterator(); int ind = 0; - while ( anIter->more() ) - { + while ( anIter->more() ) + { SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next(); if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() ) { @@ -10722,7 +10900,7 @@ bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, anElemToNodes[ anElem ] = aNodeArr; } - // Change nodes of elements + // Change nodes of elements std::map< SMDS_MeshElement*, vector >::iterator anElemToNodesIter = anElemToNodes.begin(); @@ -10804,6 +10982,70 @@ namespace { }; } +//================================================================================ +/*! + \brief Identify the elements that will be affected by node duplication (actual duplication is not performed. + This method is the first step of DoubleNodeElemGroupsInRegion. + \param theElems - list of groups of elements (edges or faces) to be replicated + \param theNodesNot - list of groups of nodes not to replicated + \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 groups of affected elements + \sa DoubleNodeElemGroupsInRegion() + */ +//================================================================================ + +bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theElems, + const TIDSortedElemSet& theNodesNot, + const TopoDS_Shape& theShape, + TIDSortedElemSet& theAffectedElems) +{ + 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::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 ))) + theAffectedElems.insert( curElem ); + } + } + } + return true; +} + //================================================================================ /*! \brief Creates a hole in a mesh by doubling the nodes of some particular elements @@ -10934,8 +11176,9 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector volume to modify) // with all the faces shared by 2 domains (group of elements) // and corresponding volume of this domain, for each shared face. - // a volume has a face shared by 2 domains if it has a neighbor which is not in is domain. + // a volume has a face shared by 2 domains if it has a neighbor which is not in his domain. + //MESSAGE("Domain " << idom); const TIDSortedElemSet& domain = theElems[idom]; TIDSortedElemSet::const_iterator elemItr = domain.begin(); for (; elemItr != domain.end(); ++elemItr) @@ -10944,6 +11187,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vectorgetVtkId(); + //MESSAGE(" vtkId " << vtkId << " smdsId " << anElem->GetID()); int neighborsVtkIds[NBMAXNEIGHBORS]; int downIds[NBMAXNEIGHBORS]; unsigned char downTypes[NBMAXNEIGHBORS]; @@ -10961,6 +11205,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector cells; - cells.clear(); vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId); for (int i=0; i, std::vector > edgesMultiDomains; // nodes of edge --> ordered domains - std::map > mutipleNodes; // nodes muti domains with domain order + std::map > mutipleNodes; // nodes multi domains with domain order + std::map > mutipleNodesToFace; // nodes multi domains with domain order to transform in Face (junction between 3 or more 2D domains) for (int idomain = 0; idomain < theElems.size(); idomain++) { @@ -11044,16 +11290,18 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector oldNodes; oldNodes.clear(); grid->GetNodeIds(oldNodes, face.cellId, face.cellType); - bool isMultipleDetected = false; std::set::iterator itn = oldNodes.begin(); for (; itn != oldNodes.end(); ++itn) { int oldId = *itn; - //MESSAGE(" node " << oldId); + //MESSAGE("-+-+-a node " << oldId); if (!nodeDomains.count(oldId)) nodeDomains[oldId] = emptyMap; // create an empty entry for node if (nodeDomains[oldId].empty()) - nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain + { + nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain + //MESSAGE("-+-+-b oldNode " << oldId << " domain " << idomain); + } std::map::iterator itdom = domvol.begin(); for (; itdom != domvol.end(); ++itdom) { @@ -11065,7 +11313,6 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector orderedDoms; //MESSAGE("multiple node " << oldId); - isMultipleDetected =true; if (mutipleNodes.count(oldId)) orderedDoms = mutipleNodes[oldId]; else @@ -11085,90 +11332,125 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vectorAddNode(coords[0], coords[1], coords[2]); int newId = newNode->getVtkId(); nodeDomains[oldId][idom] = newId; // cloned node for other domains - //MESSAGE(" newNode " << newId << " oldNode " << oldId << " size=" <= 3) - { - //MESSAGE("confirm multiple node " << oldId); - isMultipleDetected =true; + //MESSAGE("-+-+-c oldNode " << oldId << " domain " << idomain << " newNode " << newId << " domain " << idom << " size=" < domvol = itface->second; + if (!domvol.count(idomain)) + continue; + DownIdType face = itface->first; + //MESSAGE(" --- face " << face.cellId); + std::set oldNodes; + oldNodes.clear(); + grid->GetNodeIds(oldNodes, face.cellId, face.cellType); + int nbMultipleNodes = 0; + std::set::iterator itn = oldNodes.begin(); + for (; itn != oldNodes.end(); ++itn) + { + int oldId = *itn; + if (mutipleNodes.count(oldId)) + nbMultipleNodes++; + } + if (nbMultipleNodes > 1) // check if an edge of the face is shared between 3 or more domains { //MESSAGE("multiple Nodes detected on a shared face"); int downId = itface->first.cellId; unsigned char cellType = itface->first.cellType; - int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId); - const int *downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId); - const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId); - for (int ie =0; ie < nbEdges; ie++) + // --- shared edge or shared face ? + if ((cellType == VTK_LINE) || (cellType == VTK_QUADRATIC_EDGE)) // shared edge (between two faces) { int nodes[3]; - int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes); - if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1])) + int nbNodes = grid->getDownArray(cellType)->getNodes(downId, nodes); + for (int i=0; i< nbNodes; i=i+nbNodes-1) // i=0 , i=nbNodes-1 + if (mutipleNodes.count(nodes[i])) + if (!mutipleNodesToFace.count(nodes[i])) + mutipleNodesToFace[nodes[i]] = mutipleNodes[nodes[i]]; + } + else // shared face (between two volumes) + { + int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId); + const int* downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId); + const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId); + for (int ie =0; ie < nbEdges; ie++) { - vector vn0 = mutipleNodes[nodes[0]]; - vector vn1 = mutipleNodes[nodes[nbNodes - 1]]; - sort( vn0.begin(), vn0.end() ); - sort( vn1.begin(), vn1.end() ); - if (vn0 == vn1) + int nodes[3]; + int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes); + if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1])) { - //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]); - double *coords = grid->GetPoint(nodes[0]); - gp_Pnt p0(coords[0], coords[1], coords[2]); - coords = grid->GetPoint(nodes[nbNodes - 1]); - gp_Pnt p1(coords[0], coords[1], coords[2]); - gp_Pnt gref; - int vtkVolIds[1000]; // an edge can belong to a lot of volumes - map domvol; // domain --> a volume with the edge - map angleDom; // oriented angles between planes defined by edge and volume centers - int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]); - for (int id=0; id < vn0.size(); id++) + vector vn0 = mutipleNodes[nodes[0]]; + vector vn1 = mutipleNodes[nodes[nbNodes - 1]]; + vector doms; + for (int i0 = 0; i0 < vn0.size(); i0++) + for (int i1 = 0; i1 < vn1.size(); i1++) + if (vn0[i0] == vn1[i1]) + doms.push_back(vn0[i0]); + if (doms.size() >2) { - int idom = vn0[id]; - for (int ivol=0; ivolGetPoint(nodes[0]); + gp_Pnt p0(coords[0], coords[1], coords[2]); + coords = grid->GetPoint(nodes[nbNodes - 1]); + gp_Pnt p1(coords[0], coords[1], coords[2]); + gp_Pnt gref; + int vtkVolIds[1000]; // an edge can belong to a lot of volumes + map domvol; // domain --> a volume with the edge + map angleDom; // oriented angles between planes defined by edge and volume centers + int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]); + for (int id=0; id < doms.size(); id++) { - int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]); - SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId); - if (theElems[idom].count(elem)) + int idom = doms[id]; + for (int ivol=0; ivol(elem); - domvol[idom] = svol; - //MESSAGE(" domain " << idom << " volume " << elem->GetID()); - double values[3]; - vtkIdType npts = 0; - vtkIdType* pts = 0; - grid->GetCellPoints(vtkVolIds[ivol], npts, pts); - SMDS_VtkVolume::gravityCenter(grid, pts, npts, values); - if (id ==0) + int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]); + SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId); + if (theElems[idom].count(elem)) { - gref.SetXYZ(gp_XYZ(values[0], values[1], values[2])); - angleDom[idom] = 0; + SMDS_VtkVolume* svol = dynamic_cast(elem); + domvol[idom] = svol; + //MESSAGE(" domain " << idom << " volume " << elem->GetID()); + double values[3]; + vtkIdType npts = 0; + vtkIdType* pts = 0; + grid->GetCellPoints(vtkVolIds[ivol], npts, pts); + SMDS_VtkVolume::gravityCenter(grid, pts, npts, values); + if (id ==0) + { + gref.SetXYZ(gp_XYZ(values[0], values[1], values[2])); + angleDom[idom] = 0; + } + else + { + gp_Pnt g(values[0], values[1], values[2]); + angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pisecond << " angle " << ib->first); + } + for (int ino = 0; ino < nbNodes; ino++) + vnodes.push_back(nodes[ino]); + edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains } - map sortedDom; // sort domains by angle - for (map::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia) - sortedDom[ia->second] = ia->first; - vector vnodes; - vector vdom; - for (map::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib) - { - vdom.push_back(ib->second); - //MESSAGE(" ordered domain " << ib->second << " angle " << ib->first); - } - for (int ino = 0; ino < nbNodes; ino++) - vnodes.push_back(nodes[ino]); - edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains } } } @@ -11188,6 +11470,14 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vectormyMesh->AddGroup(SMDSAbs_Face, joints2DName.c_str(), idg); + SMESHDS_Group *joints2DGrp = dynamic_cast(mapOfJunctionGroups[joints2DName]->GetGroupDS()); + string joints3DName = "joints3D"; + mapOfJunctionGroups[joints3DName] = this->myMesh->AddGroup(SMDSAbs_Volume, joints3DName.c_str(), idg); + SMESHDS_Group *joints3DGrp = dynamic_cast(mapOfJunctionGroups[joints3DName]->GetGroupDS()); + itface = faceDomains.begin(); for (; itface != faceDomains.end(); ++itface) { @@ -11203,7 +11493,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vectorsecond; itdom++; int dom2 = itdom->first; - SMDS_MeshVolume *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains, + SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains, nodeQuadDomains); stringstream grpname; grpname << "j_"; @@ -11211,21 +11501,51 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vectormyMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg); + mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str(), idg); SMESHDS_Group *sgrp = dynamic_cast(mapOfJunctionGroups[namegrp]->GetGroupDS()); if (sgrp) sgrp->Add(vol->GetID()); + if (vol->GetType() == SMDSAbs_Volume) + joints3DGrp->Add(vol->GetID()); + else if (vol->GetType() == SMDSAbs_Face) + joints2DGrp->Add(vol->GetID()); } } // --- create volumes on multiple domain intersection if requested + // iterate on mutipleNodesToFace // iterate on edgesMultiDomains if (createJointElems) { + // --- iterate on mutipleNodesToFace + + std::map >::iterator itn = mutipleNodesToFace.begin(); + for (; itn != mutipleNodesToFace.end(); ++itn) + { + int node = itn->first; + vector orderDom = itn->second; + vector orderedNodes; + for (int idom = 0; idom GetMeshDS()->AddFaceFromVtkIds(orderedNodes); + + stringstream grpname; + grpname << "m2j_"; + grpname << 0 << "_" << 0; + int idg; + string namegrp = grpname.str(); + if (!mapOfJunctionGroups.count(namegrp)) + mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str(), idg); + SMESHDS_Group *sgrp = dynamic_cast(mapOfJunctionGroups[namegrp]->GetGroupDS()); + if (sgrp) + sgrp->Add(face->GetID()); + } + + // --- iterate on edgesMultiDomains + std::map, std::vector >::iterator ite = edgesMultiDomains.begin(); for (; ite != edgesMultiDomains.end(); ++ite) { @@ -11244,11 +11564,8 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vectorGetMeshDS()->AddVolumeFromVtkIds(orderedNodes); - stringstream grpname; - grpname << "mj_"; - grpname << 0 << "_" << 0; int idg; - string namegrp = grpname.str(); + string namegrp = "jointsMultiples"; if (!mapOfJunctionGroups.count(namegrp)) mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg); SMESHDS_Group *sgrp = dynamic_cast(mapOfJunctionGroups[namegrp]->GetGroupDS()); @@ -11257,7 +11574,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector& nodesCoords, + std::vector >& listOfListOfNodes) +{ + MESSAGE("--------------------------------"); + MESSAGE("SMESH_MeshEditor::CreateHoleSkin"); + MESSAGE("--------------------------------"); + + // --- zone of volumes to remove is given : + // 1 either by a geom shape (one or more vertices) and a radius, + // 2 either by a group of nodes (representative of the shape)to use with the radius, + // 3 either by a group of nodes where all the elements build on one of this nodes are to remove, + // In the case 2, the group of nodes is an external group of nodes from another mesh, + // In the case 3, the group of nodes is an internal group of the mesh (obtained for instance by a filter), + // defined by it's name. + + SMESHDS_GroupBase* groupDS = 0; + SMESH_Mesh::GroupIteratorPtr groupIt = this->myMesh->GetGroups(); + while ( groupIt->more() ) + { + groupDS = 0; + SMESH_Group * group = groupIt->next(); + if ( !group ) continue; + groupDS = group->GetGroupDS(); + if ( !groupDS || groupDS->IsEmpty() ) continue; + std::string grpName = group->GetName(); + //MESSAGE("grpName=" << grpName); + if (grpName == groupName) + break; + else + groupDS = 0; + } + + bool isNodeGroup = false; + bool isNodeCoords = false; + if (groupDS) + { + if (groupDS->GetType() != SMDSAbs_Node) + return; + isNodeGroup = true; // a group of nodes exists and it is in this mesh + } + + if (nodesCoords.size() > 0) + isNodeCoords = true; // a list o nodes given by their coordinates + //MESSAGE("---" << isNodeGroup << " " << isNodeCoords); + + // --- define groups to build + + int idg; // --- group of SMDS volumes + string grpvName = groupName; + grpvName += "_vol"; + SMESH_Group *grp = this->myMesh->AddGroup(SMDSAbs_Volume, grpvName.c_str(), idg); + if (!grp) + { + MESSAGE("group not created " << grpvName); + return; + } + SMESHDS_Group *sgrp = dynamic_cast(grp->GetGroupDS()); + + int idgs; // --- group of SMDS faces on the skin + string grpsName = groupName; + grpsName += "_skin"; + SMESH_Group *grps = this->myMesh->AddGroup(SMDSAbs_Face, grpsName.c_str(), idgs); + if (!grps) + { + MESSAGE("group not created " << grpsName); + return; + } + SMESHDS_Group *sgrps = dynamic_cast(grps->GetGroupDS()); + + int idgi; // --- group of SMDS faces internal (several shapes) + string grpiName = groupName; + grpiName += "_internalFaces"; + SMESH_Group *grpi = this->myMesh->AddGroup(SMDSAbs_Face, grpiName.c_str(), idgi); + if (!grpi) + { + MESSAGE("group not created " << grpiName); + return; + } + SMESHDS_Group *sgrpi = dynamic_cast(grpi->GetGroupDS()); + + int idgei; // --- group of SMDS faces internal (several shapes) + string grpeiName = groupName; + grpeiName += "_internalEdges"; + SMESH_Group *grpei = this->myMesh->AddGroup(SMDSAbs_Edge, grpeiName.c_str(), idgei); + if (!grpei) + { + MESSAGE("group not created " << grpeiName); + return; + } + SMESHDS_Group *sgrpei = dynamic_cast(grpei->GetGroupDS()); + + // --- build downward connectivity + + SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS(); + meshDS->BuildDownWardConnectivity(true); + SMDS_UnstructuredGrid* grid = meshDS->getGrid(); + + // --- set of volumes detected inside + + std::set setOfInsideVol; + std::set setOfVolToCheck; + + std::vector gpnts; + gpnts.clear(); + + if (isNodeGroup) // --- a group of nodes is provided : find all the volumes using one or more of this nodes + { + MESSAGE("group of nodes provided"); + SMDS_ElemIteratorPtr elemIt = groupDS->GetElements(); + while ( elemIt->more() ) + { + const SMDS_MeshElement* elem = elemIt->next(); + if (!elem) + continue; + const SMDS_MeshNode* node = dynamic_cast(elem); + if (!node) + continue; + SMDS_MeshElement* vol = 0; + SMDS_ElemIteratorPtr volItr = node->GetInverseElementIterator(SMDSAbs_Volume); + while (volItr->more()) + { + vol = (SMDS_MeshElement*)volItr->next(); + setOfInsideVol.insert(vol->getVtkId()); + sgrp->Add(vol->GetID()); + } + } + } + else if (isNodeCoords) + { + MESSAGE("list of nodes coordinates provided"); + int i = 0; + int k = 0; + while (i < nodesCoords.size()-2) + { + double x = nodesCoords[i++]; + double y = nodesCoords[i++]; + double z = nodesCoords[i++]; + gp_Pnt p = gp_Pnt(x, y ,z); + gpnts.push_back(p); + MESSAGE("TopoDS_Vertex " << k++ << " " << p.X() << " " << p.Y() << " " << p.Z()); + } + } + else // --- no group, no coordinates : use the vertices of the geom shape provided, and radius + { + MESSAGE("no group of nodes provided, using vertices from geom shape, and radius"); + TopTools_IndexedMapOfShape vertexMap; + TopExp::MapShapes( theShape, TopAbs_VERTEX, vertexMap ); + gp_Pnt p = gp_Pnt(0,0,0); + if (vertexMap.Extent() < 1) + return; + + for ( int i = 1; i <= vertexMap.Extent(); ++i ) + { + const TopoDS_Vertex& vertex = TopoDS::Vertex( vertexMap( i )); + p = BRep_Tool::Pnt(vertex); + gpnts.push_back(p); + MESSAGE("TopoDS_Vertex " << i << " " << p.X() << " " << p.Y() << " " << p.Z()); + } + } + + if (gpnts.size() > 0) + { + int nodeId = 0; + const SMDS_MeshNode* startNode = theNodeSearcher->FindClosestTo(gpnts[0]); + if (startNode) + nodeId = startNode->GetID(); + MESSAGE("nodeId " << nodeId); + + double radius2 = radius*radius; + MESSAGE("radius2 " << radius2); + + // --- volumes on start node + + setOfVolToCheck.clear(); + SMDS_MeshElement* startVol = 0; + SMDS_ElemIteratorPtr volItr = startNode->GetInverseElementIterator(SMDSAbs_Volume); + while (volItr->more()) + { + startVol = (SMDS_MeshElement*)volItr->next(); + setOfVolToCheck.insert(startVol->getVtkId()); + } + if (setOfVolToCheck.empty()) + { + MESSAGE("No volumes found"); + return; + } + + // --- starting with central volumes then their neighbors, check if they are inside + // or outside the domain, until no more new neighbor volume is inside. + // Fill the group of inside volumes + + std::map mapOfNodeDistance2; + mapOfNodeDistance2.clear(); + std::set setOfOutsideVol; + while (!setOfVolToCheck.empty()) + { + std::set::iterator it = setOfVolToCheck.begin(); + int vtkId = *it; + MESSAGE("volume to check, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); + bool volInside = false; + vtkIdType npts = 0; + vtkIdType* pts = 0; + grid->GetCellPoints(vtkId, npts, pts); + for (int i=0; iGetPoint(pts[i]); + gp_Pnt aPoint = gp_Pnt(coords[0], coords[1], coords[2]); + distance2 = 1.E40; + for (int j=0; jAdd(meshDS->fromVtkToSmds(vtkId)); + break; + } + } + if (volInside) + { + setOfInsideVol.insert(vtkId); + MESSAGE(" volume inside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); + int neighborsVtkIds[NBMAXNEIGHBORS]; + int downIds[NBMAXNEIGHBORS]; + unsigned char downTypes[NBMAXNEIGHBORS]; + int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId); + for (int n = 0; n < nbNeighbors; n++) + if (!setOfInsideVol.count(neighborsVtkIds[n]) ||setOfOutsideVol.count(neighborsVtkIds[n])) + setOfVolToCheck.insert(neighborsVtkIds[n]); + } + else + { + setOfOutsideVol.insert(vtkId); + MESSAGE(" volume outside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); + } + setOfVolToCheck.erase(vtkId); + } + } + + // --- for outside hexahedrons, check if they have more than one neighbor volume inside + // If yes, add the volume to the inside set + + bool addedInside = true; + std::set setOfVolToReCheck; + while (addedInside) + { + MESSAGE(" --------------------------- re check"); + addedInside = false; + std::set::iterator itv = setOfInsideVol.begin(); + for (; itv != setOfInsideVol.end(); ++itv) + { + int vtkId = *itv; + int neighborsVtkIds[NBMAXNEIGHBORS]; + int downIds[NBMAXNEIGHBORS]; + unsigned char downTypes[NBMAXNEIGHBORS]; + int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId); + for (int n = 0; n < nbNeighbors; n++) + if (!setOfInsideVol.count(neighborsVtkIds[n])) + setOfVolToReCheck.insert(neighborsVtkIds[n]); + } + setOfVolToCheck = setOfVolToReCheck; + setOfVolToReCheck.clear(); + while (!setOfVolToCheck.empty()) + { + std::set::iterator it = setOfVolToCheck.begin(); + int vtkId = *it; + if (grid->GetCellType(vtkId) == VTK_HEXAHEDRON) + { + MESSAGE("volume to recheck, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); + int countInside = 0; + int neighborsVtkIds[NBMAXNEIGHBORS]; + int downIds[NBMAXNEIGHBORS]; + unsigned char downTypes[NBMAXNEIGHBORS]; + int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId); + for (int n = 0; n < nbNeighbors; n++) + if (setOfInsideVol.count(neighborsVtkIds[n])) + countInside++; + MESSAGE("countInside " << countInside); + if (countInside > 1) + { + MESSAGE(" volume inside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); + setOfInsideVol.insert(vtkId); + sgrp->Add(meshDS->fromVtkToSmds(vtkId)); + addedInside = true; + } + else + setOfVolToReCheck.insert(vtkId); + } + setOfVolToCheck.erase(vtkId); + } + } + + // --- map of Downward faces at the boundary, inside the global volume + // map of Downward faces on the skin of the global volume (equivalent to SMDS faces on the skin) + // fill group of SMDS faces inside the volume (when several volume shapes) + // fill group of SMDS faces on the skin of the global volume (if skin) + + std::map boundaryFaces; // boundary faces inside the volume --> corresponding cell + std::map skinFaces; // faces on the skin of the global volume --> corresponding cell + std::set::iterator it = setOfInsideVol.begin(); + for (; it != setOfInsideVol.end(); ++it) + { + int vtkId = *it; + //MESSAGE(" vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId)); + int neighborsVtkIds[NBMAXNEIGHBORS]; + int downIds[NBMAXNEIGHBORS]; + unsigned char downTypes[NBMAXNEIGHBORS]; + int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId, true); + for (int n = 0; n < nbNeighbors; n++) + { + int neighborDim = SMDS_Downward::getCellDimension(grid->GetCellType(neighborsVtkIds[n])); + if (neighborDim == 3) + { + if (! setOfInsideVol.count(neighborsVtkIds[n])) // neighbor volume is not inside : face is boundary + { + DownIdType face(downIds[n], downTypes[n]); + boundaryFaces[face] = vtkId; + } + // if the face between to volumes is in the mesh, get it (internal face between shapes) + int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]); + if (vtkFaceId >= 0) + { + sgrpi->Add(meshDS->fromVtkToSmds(vtkFaceId)); + // find also the smds edges on this face + int nbEdges = grid->getDownArray(downTypes[n])->getNumberOfDownCells(downIds[n]); + const int* dEdges = grid->getDownArray(downTypes[n])->getDownCells(downIds[n]); + const unsigned char* dTypes = grid->getDownArray(downTypes[n])->getDownTypes(downIds[n]); + for (int i = 0; i < nbEdges; i++) + { + int vtkEdgeId = grid->getDownArray(dTypes[i])->getVtkCellId(dEdges[i]); + if (vtkEdgeId >= 0) + sgrpei->Add(meshDS->fromVtkToSmds(vtkEdgeId)); + } + } + } + else if (neighborDim == 2) // skin of the volume + { + DownIdType face(downIds[n], downTypes[n]); + skinFaces[face] = vtkId; + int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]); + if (vtkFaceId >= 0) + sgrps->Add(meshDS->fromVtkToSmds(vtkFaceId)); + } + } + } + + // --- identify the edges constituting the wire of each subshape on the skin + // define polylines with the nodes of edges, equivalent to wires + // project polylines on subshapes, and partition, to get geom faces + + std::map > shapeIdToVtkIdSet; // shapeId --> set of vtkId on skin + std::set emptySet; + emptySet.clear(); + std::set shapeIds; + + SMDS_ElemIteratorPtr itelem = sgrps->GetElements(); + while (itelem->more()) + { + const SMDS_MeshElement *elem = itelem->next(); + int shapeId = elem->getshapeId(); + int vtkId = elem->getVtkId(); + if (!shapeIdToVtkIdSet.count(shapeId)) + { + shapeIdToVtkIdSet[shapeId] = emptySet; + shapeIds.insert(shapeId); + } + shapeIdToVtkIdSet[shapeId].insert(vtkId); + } + + std::map > shapeIdToEdges; // shapeId --> set of downward edges + std::set emptyEdges; + emptyEdges.clear(); + + std::map >::iterator itShape = shapeIdToVtkIdSet.begin(); + for (; itShape != shapeIdToVtkIdSet.end(); ++itShape) + { + int shapeId = itShape->first; + MESSAGE(" --- Shape ID --- "<< shapeId); + shapeIdToEdges[shapeId] = emptyEdges; + + std::vector nodesEdges; + + std::set::iterator its = itShape->second.begin(); + for (; its != itShape->second.end(); ++its) + { + int vtkId = *its; + MESSAGE(" " << vtkId); + int neighborsVtkIds[NBMAXNEIGHBORS]; + int downIds[NBMAXNEIGHBORS]; + unsigned char downTypes[NBMAXNEIGHBORS]; + int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId); + for (int n = 0; n < nbNeighbors; n++) + { + if (neighborsVtkIds[n]<0) // only smds faces are considered as neighbors here + continue; + int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]); + const SMDS_MeshElement* elem = meshDS->FindElement(smdsId); + if ( shapeIds.count(elem->getshapeId()) && !sgrps->Contains(elem)) // edge : neighbor in the set of shape, not in the group + { + DownIdType edge(downIds[n], downTypes[n]); + if (!shapeIdToEdges[shapeId].count(edge)) + { + shapeIdToEdges[shapeId].insert(edge); + int vtkNodeId[3]; + int nbNodes = grid->getDownArray(downTypes[n])->getNodes(downIds[n],vtkNodeId); + nodesEdges.push_back(vtkNodeId[0]); + nodesEdges.push_back(vtkNodeId[nbNodes-1]); + MESSAGE(" --- nodes " << vtkNodeId[0]+1 << " " << vtkNodeId[nbNodes-1]+1); + } + } + } + } + + std::list order; + order.clear(); + if (nodesEdges.size() > 0) + { + order.push_back(nodesEdges[0]); MESSAGE(" --- back " << order.back()+1); // SMDS id = VTK id + 1; + nodesEdges[0] = -1; + order.push_back(nodesEdges[1]); MESSAGE(" --- back " << order.back()+1); + nodesEdges[1] = -1; // do not reuse this edge + bool found = true; + while (found) + { + int nodeTofind = order.back(); // try first to push back + int i = 0; + for (i = 0; i use the previous one + if (nodesEdges[i-1] < 0) + found = false; + else + { + order.push_back(nodesEdges[i-1]); MESSAGE(" --- back " << order.back()+1); + nodesEdges[i-1] = -1; + } + else // even ==> use the next one + if (nodesEdges[i+1] < 0) + found = false; + else + { + order.push_back(nodesEdges[i+1]); MESSAGE(" --- back " << order.back()+1); + nodesEdges[i+1] = -1; + } + } + if (found) + continue; + // try to push front + found = true; + nodeTofind = order.front(); // try to push front + for (i = 0; i use the previous one + if (nodesEdges[i-1] < 0) + found = false; + else + { + order.push_front(nodesEdges[i-1]); MESSAGE(" --- front " << order.front()+1); + nodesEdges[i-1] = -1; + } + else // even ==> use the next one + if (nodesEdges[i+1] < 0) + found = false; + else + { + order.push_front(nodesEdges[i+1]); MESSAGE(" --- front " << order.front()+1); + nodesEdges[i+1] = -1; + } + } + } + + + std::vector nodes; + nodes.push_back(shapeId); + std::list::iterator itl = order.begin(); + for (; itl != order.end(); itl++) + { + nodes.push_back((*itl) + 1); // SMDS id = VTK id + 1; + MESSAGE(" ordered node " << nodes[nodes.size()-1]); + } + listOfListOfNodes.push_back(nodes); + } + + // partition geom faces with blocFissure + // mesh blocFissure and geom faces of the skin (external wires given, triangle algo to choose) + // mesh volume around blocFissure (skin triangles and quadrangle given, tetra algo to choose) + + return; +} + + //================================================================================ /*! * \brief Generates skin mesh (containing 2D cells) from 3D mesh @@ -11535,10 +12382,10 @@ bool SMESH_MeshEditor::Make2DMeshFrom3D() while(vIt->more()) { const SMDS_MeshVolume* volume = vIt->next(); - SMDS_VolumeTool vTool( volume ); + SMDS_VolumeTool vTool( volume, /*ignoreCentralNodes=*/false ); vTool.SetExternalNormal(); - const bool isPoly = volume->IsPoly(); - const bool isQuad = volume->IsQuadratic(); + //const bool isPoly = volume->IsPoly(); + const int iQuad = volume->IsQuadratic(); for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ ) { if (!vTool.IsFreeFace(iface)) @@ -11548,18 +12395,20 @@ bool SMESH_MeshEditor::Make2DMeshFrom3D() int nbFaceNodes = vTool.NbFaceNodes(iface); const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface); int inode = 0; - for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1) + for ( ; inode < nbFaceNodes; inode += iQuad+1) nodes.push_back(faceNodes[inode]); - if (isQuad) + if (iQuad) { // add medium nodes for ( inode = 1; inode < nbFaceNodes; inode += 2) nodes.push_back(faceNodes[inode]); - + if ( nbFaceNodes == 9 ) // bi-quadratic quad + nodes.push_back(faceNodes[8]); + } // add new face based on volume nodes - if (aMesh->FindFace( nodes ) ) { + if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) { nbExisted++; continue; // face already exsist } - AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1); + AddElement(nodes, SMDSAbs_Face, ( !iQuad && nbFaceNodes/(iQuad+1) > 4 )); nbCreated++; } } @@ -11620,6 +12469,8 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() ); presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2; + SMESH_MesherHelper helper( *myMesh ); + const TopAbs_ShapeEnum missShapeType = ( missType==SMDSAbs_Face ? TopAbs_FACE : TopAbs_EDGE ); SMDS_VolumeTool vTool; TIDSortedElemSet avoidSet; const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet; @@ -11644,7 +12495,7 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, vector presentBndElems; vector missingBndElems; TConnectivity nodes; - if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------ + if ( vTool.Set(elem, /*ignoreCentralNodes=*/true) ) // elem is a volume -------------- { vTool.SetExternalNormal(); const SMDS_MeshElement* otherVol = 0; @@ -11663,7 +12514,7 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, 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)) + aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false)) presentBndElems.push_back( edge ); else missingBndElems.push_back( nodes ); @@ -11674,11 +12525,15 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, nodes.clear(); for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad) nodes.push_back( nn[inode] ); - if (iQuad) + if (iQuad) // add medium nodes for ( inode = 1; inode < nbFaceNodes; inode += 2) nodes.push_back( nn[inode] ); + int iCenter = vTool.GetCenterNodeIndex(iface); // for HEX27 + if ( iCenter > 0 ) + nodes.push_back( vTool.GetNodes()[ iCenter ] ); - if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) ) + if (const SMDS_MeshElement * f = aMesh->FindElement( nodes, + SMDSAbs_Face, /*noMedium=*/false )) presentBndElems.push_back( f ); else missingBndElems.push_back( nodes ); @@ -11736,9 +12591,9 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] ); if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes, missType, - /*noMedium=*/true)) + /*noMedium=*/false)) continue; - tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4); + tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4); ++nbAddedBnd; } else @@ -11747,10 +12602,39 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, TConnectivity& nodes = missingBndElems[i]; if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes, missType, - /*noMedium=*/true)) + /*noMedium=*/false)) continue; - tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4); + SMDS_MeshElement* elem = + tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4); ++nbAddedBnd; + + // try to set a new element to a shape + if ( myMesh->HasShapeToMesh() ) + { + bool ok = true; + set< pair > mediumShapes; + const int nbN = nodes.size() / (iQuad+1 ); + for ( inode = 0; inode < nbN && ok; ++inode ) + { + pair i_stype = + helper.GetMediumPos( nodes[inode], nodes[(inode+1)%nbN]); + if (( ok = ( i_stype.first > 0 && i_stype.second >= TopAbs_FACE ))) + mediumShapes.insert( make_pair ( i_stype.second, i_stype.first )); + } + if ( ok && mediumShapes.size() > 1 ) + { + set< pair >::iterator stype_i = mediumShapes.begin(); + pair stype_i_0 = *stype_i; + for ( ++stype_i; stype_i != mediumShapes.end() && ok; ++stype_i ) + { + if (( ok = ( stype_i->first != stype_i_0.first ))) + ok = helper.IsSubShape( aMesh->IndexToShape( stype_i->second ), + aMesh->IndexToShape( stype_i_0.second )); + } + } + if ( ok && mediumShapes.begin()->first == missShapeType ) + aMesh->SetMeshElementOnShape( elem, mediumShapes.begin()->second ); + } } // ---------------------------------- @@ -11770,7 +12654,7 @@ int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements, { presentEditor->myLastCreatedElems.Append(presentBndElems[i]); } - + } // loop on given elements // ---------------------------------------------