X-Git-Url: http://git.salome-platform.org/gitweb/?p=modules%2Fsmesh.git;a=blobdiff_plain;f=src%2FSMESH%2FSMESH_MeshEditor.cxx;h=c0a3b277175707f0459d8a81a2f6056725ea6833;hp=f6b3c05205013e1fd013d7f9499bce430060b7a8;hb=104ff7b2818ce4d0f8a38d840abd3e5c70190668;hpb=5496cb6ab14315c9116496df1c62fc0c0a7bcc3d diff --git a/src/SMESH/SMESH_MeshEditor.cxx b/src/SMESH/SMESH_MeshEditor.cxx index f6b3c0520..c0a3b2771 100644 --- a/src/SMESH/SMESH_MeshEditor.cxx +++ b/src/SMESH/SMESH_MeshEditor.cxx @@ -1,23 +1,23 @@ // SMESH SMESH : idl implementation based on 'SMESH' unit's classes // // Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // // // @@ -28,14 +28,20 @@ #include "SMESH_MeshEditor.hxx" -#include "SMESH_ControlsDef.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 "SMESHDS_Group.hxx" #include "SMESHDS_Mesh.hxx" + #include "SMESH_subMesh.hxx" #include "SMESH_ControlsDef.hxx" +#include "SMESH_MesherHelper.hxx" #include "utilities.h" @@ -48,17 +54,22 @@ #include #include #include +#include #include #include #include -#include #include - +#include +#include +#include +#include +#include +#include +#include +#include #include -#include "utilities.h" - using namespace std; using namespace SMESH::Controls; @@ -67,11 +78,16 @@ typedef map > TElemOfNode typedef map > TElemOfElemListMap; typedef map > TNodeOfNodeListMap; typedef TNodeOfNodeListMap::iterator TNodeOfNodeListMapItr; +//typedef map > TNodeOfNodeVecMap; +//typedef TNodeOfNodeVecMap::iterator TNodeOfNodeVecMapItr; typedef map > TElemOfVecOfNnlmiMap; +//typedef map > TElemOfVecOfMapNodesMap; + +typedef pair NLink; //======================================================================= //function : SMESH_MeshEditor -//purpose : +//purpose : //======================================================================= SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh ): @@ -88,13 +104,14 @@ myMesh( theMesh ) bool SMESH_MeshEditor::Remove (const list< int >& theIDs, const bool isNodes ) { + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); SMESHDS_Mesh* aMesh = GetMeshDS(); set< SMESH_subMesh *> smmap; - + list::const_iterator it = theIDs.begin(); - for ( ; it != theIDs.end(); it++ ) - { + for ( ; it != theIDs.end(); it++ ) { const SMDS_MeshElement * elem; if ( isNodes ) elem = aMesh->FindNode( *it ); @@ -105,16 +122,12 @@ bool SMESH_MeshEditor::Remove (const list< int >& theIDs, // Find sub-meshes to notify about modification SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator(); - while ( nodeIt->more() ) - { + while ( nodeIt->more() ) { const SMDS_MeshNode* node = static_cast( nodeIt->next() ); const SMDS_PositionPtr& aPosition = node->GetPosition(); if ( aPosition.get() ) { - int aShapeID = aPosition->GetShapeId(); - if ( aShapeID ) { - TopoDS_Shape aShape = aMesh->IndexToShape( aShapeID ); - SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShape ); - if ( sm ) + if ( int aShapeID = aPosition->GetShapeId() ) { + if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) ) smmap.insert( sm ); } } @@ -133,6 +146,11 @@ bool SMESH_MeshEditor::Remove (const list< int >& theIDs, for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ ) (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED ); } + + // Check if the whole mesh becomes empty + if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) ) + sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE ); + return true; } @@ -144,12 +162,14 @@ bool SMESH_MeshEditor::Remove (const list< int >& theIDs, int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem) { + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + SMESHDS_Mesh * aMesh = GetMeshDS(); if ( aMesh->ShapeToMesh().IsNull() ) return 0; - if ( theElem->GetType() == SMDSAbs_Node ) - { + if ( theElem->GetType() == SMDSAbs_Node ) { const SMDS_PositionPtr& aPosition = static_cast( theElem )->GetPosition(); if ( aPosition.get() ) @@ -160,25 +180,22 @@ int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem) TopoDS_Shape aShape; // the shape a node is on SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator(); - while ( nodeIt->more() ) - { + while ( nodeIt->more() ) { const SMDS_MeshNode* node = static_cast( nodeIt->next() ); const SMDS_PositionPtr& aPosition = node->GetPosition(); if ( aPosition.get() ) { - int aShapeID = aPosition->GetShapeId(); - SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ); - if ( sm ) - { - if ( sm->Contains( theElem )) - return aShapeID; - if ( aShape.IsNull() ) - aShape = aMesh->IndexToShape( aShapeID ); - } - else - { - //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID ); - } + int aShapeID = aPosition->GetShapeId(); + SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ); + if ( sm ) { + if ( sm->Contains( theElem )) + return aShapeID; + if ( aShape.IsNull() ) + aShape = aMesh->IndexToShape( aShapeID ); + } + else { + //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID ); } + } } // None of nodes is on a proper shape, @@ -188,17 +205,108 @@ int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem) return 0; } TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape )); - for ( ; ancIt.More(); ancIt.Next() ) - { - SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() ); - if ( sm && sm->Contains( theElem )) - return aMesh->ShapeToIndex( ancIt.Value() ); + for ( ; ancIt.More(); ancIt.Next() ) { + SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() ); + if ( sm && sm->Contains( theElem )) + return aMesh->ShapeToIndex( ancIt.Value() ); } //MESSAGE ("::FindShape() - SHAPE NOT FOUND") return 0; } +//======================================================================= +//function : IsMedium +//purpose : +//======================================================================= + +bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node, + const SMDSAbs_ElementType typeToCheck) +{ + bool isMedium = false; + SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(); + while (it->more()) { + const SMDS_MeshElement* elem = it->next(); + isMedium = elem->IsMediumNode(node); + if ( typeToCheck == SMDSAbs_All || elem->GetType() == typeToCheck ) + break; + } + return isMedium; +} + +//======================================================================= +//function : ShiftNodesQuadTria +//purpose : auxilary +// Shift nodes in the array corresponded to quadratic triangle +// example: (0,1,2,3,4,5) -> (1,2,0,4,5,3) +//======================================================================= +static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[]) +{ + const SMDS_MeshNode* nd1 = aNodes[0]; + aNodes[0] = aNodes[1]; + aNodes[1] = aNodes[2]; + aNodes[2] = nd1; + const SMDS_MeshNode* nd2 = aNodes[3]; + aNodes[3] = aNodes[4]; + aNodes[4] = aNodes[5]; + aNodes[5] = nd2; +} + +//======================================================================= +//function : GetNodesFromTwoTria +//purpose : auxilary +// Shift nodes in the array corresponded to quadratic triangle +// example: (0,1,2,3,4,5) -> (1,2,0,4,5,3) +//======================================================================= +static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1, + const SMDS_MeshElement * theTria2, + const SMDS_MeshNode* N1[], + const SMDS_MeshNode* N2[]) +{ + SMDS_ElemIteratorPtr it = theTria1->nodesIterator(); + int i=0; + while(i<6) { + N1[i] = static_cast( it->next() ); + i++; + } + if(it->more()) return false; + it = theTria2->nodesIterator(); + i=0; + while(i<6) { + N2[i] = static_cast( it->next() ); + i++; + } + if(it->more()) return false; + + int sames[3] = {-1,-1,-1}; + int nbsames = 0; + int j; + for(i=0; i<3; i++) { + for(j=0; j<3; j++) { + if(N1[i]==N2[j]) { + sames[i] = j; + nbsames++; + break; + } + } + } + if(nbsames!=2) return false; + if(sames[0]>-1) { + ShiftNodesQuadTria(N1); + if(sames[1]>-1) { + ShiftNodesQuadTria(N1); + } + } + i = sames[0] + sames[1] + sames[2]; + for(; i<2; i++) { + ShiftNodesQuadTria(N2); + } + // now we receive following N1 and N2 (using numeration as above image) + // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6) + // i.e. first nodes from both arrays determ new diagonal + return true; +} + //======================================================================= //function : InverseDiag //purpose : Replace two neighbour triangles with ones built on the same 4 nodes @@ -209,73 +317,121 @@ int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem) bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1, const SMDS_MeshElement * theTria2 ) { + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + if (!theTria1 || !theTria2) return false; + const SMDS_FaceOfNodes* F1 = dynamic_cast( theTria1 ); - if (!F1) return false; const SMDS_FaceOfNodes* F2 = dynamic_cast( theTria2 ); - if (!F2) return false; + if (F1 && F2) { - // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A - // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ | - // |/ | | \| - // B +--+ 2 B +--+ 2 + // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A + // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ | + // |/ | | \| + // B +--+ 2 B +--+ 2 - // put nodes in array and find out indices of the same ones - const SMDS_MeshNode* aNodes [6]; - int sameInd [] = { 0, 0, 0, 0, 0, 0 }; - int i = 0; - SMDS_ElemIteratorPtr it = theTria1->nodesIterator(); - while ( it->more() ) - { - aNodes[ i ] = static_cast( it->next() ); - - if ( i > 2 ) // theTria2 - // find same node of theTria1 - for ( int j = 0; j < 3; j++ ) - if ( aNodes[ i ] == aNodes[ j ]) { - sameInd[ j ] = i; - sameInd[ i ] = j; - break; - } - // next - i++; - if ( i == 3 ) { - if ( it->more() ) - return false; // theTria1 is not a triangle - it = theTria2->nodesIterator(); + // put nodes in array and find out indices of the same ones + const SMDS_MeshNode* aNodes [6]; + int sameInd [] = { 0, 0, 0, 0, 0, 0 }; + int i = 0; + SMDS_ElemIteratorPtr it = theTria1->nodesIterator(); + while ( it->more() ) { + aNodes[ i ] = static_cast( it->next() ); + + if ( i > 2 ) // theTria2 + // find same node of theTria1 + for ( int j = 0; j < 3; j++ ) + if ( aNodes[ i ] == aNodes[ j ]) { + sameInd[ j ] = i; + sameInd[ i ] = j; + break; + } + // next + i++; + if ( i == 3 ) { + if ( it->more() ) + return false; // theTria1 is not a triangle + it = theTria2->nodesIterator(); + } + if ( i == 6 && it->more() ) + return false; // theTria2 is not a triangle } - if ( i == 6 && it->more() ) - return false; // theTria2 is not a triangle - } - - // find indices of 1,2 and of A,B in theTria1 - int iA = 0, iB = 0, i1 = 0, i2 = 0; - for ( i = 0; i < 6; i++ ) - { - if ( sameInd [ i ] == 0 ) - if ( i < 3 ) i1 = i; - else i2 = i; - else if (i < 3) - if ( iA ) iB = i; - else iA = i; - } - // nodes 1 and 2 should not be the same - if ( aNodes[ i1 ] == aNodes[ i2 ] ) - return false; - - - // theTria1: A->2 - aNodes[ iA ] = aNodes[ i2 ]; - // theTria2: B->1 - aNodes[ sameInd[ iB ]] = aNodes[ i1 ]; + + // find indices of 1,2 and of A,B in theTria1 + int iA = 0, iB = 0, i1 = 0, i2 = 0; + for ( i = 0; i < 6; i++ ) { + if ( sameInd [ i ] == 0 ) + if ( i < 3 ) i1 = i; + else i2 = i; + else if (i < 3) + if ( iA ) iB = i; + else iA = i; + } + // nodes 1 and 2 should not be the same + if ( aNodes[ i1 ] == aNodes[ i2 ] ) + return false; - //MESSAGE( theTria1 << theTria2 ); + // theTria1: A->2 + aNodes[ iA ] = aNodes[ i2 ]; + // theTria2: B->1 + aNodes[ sameInd[ iB ]] = aNodes[ i1 ]; - GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 ); - GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 ); + //MESSAGE( theTria1 << theTria2 ); + + GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 ); + GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 ); + + //MESSAGE( theTria1 << theTria2 ); - //MESSAGE( theTria1 << theTria2 ); + return true; + + } // end if(F1 && F2) + + // check case of quadratic faces + const SMDS_QuadraticFaceOfNodes* QF1 = + dynamic_cast (theTria1); + if(!QF1) return false; + const SMDS_QuadraticFaceOfNodes* QF2 = + dynamic_cast (theTria2); + if(!QF2) return false; + + // 5 + // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9) + // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8) + // | / | + // 7 + + + 6 + // | /9 | + // |/ | + // 4 +--+--+ 3 + // 8 + + const SMDS_MeshNode* N1 [6]; + const SMDS_MeshNode* N2 [6]; + if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2)) + return false; + // now we receive following N1 and N2 (using numeration as above image) + // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6) + // i.e. first nodes from both arrays determ new diagonal + + const SMDS_MeshNode* N1new [6]; + const SMDS_MeshNode* N2new [6]; + N1new[0] = N1[0]; + N1new[1] = N2[0]; + N1new[2] = N2[1]; + N1new[3] = N1[4]; + N1new[4] = N2[3]; + N1new[5] = N1[5]; + N2new[0] = N1[0]; + N2new[1] = N1[1]; + N2new[2] = N2[0]; + N2new[3] = N1[3]; + N2new[4] = N2[5]; + N2new[5] = N1[4]; + // replaces nodes in faces + GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 ); + GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 ); return true; } @@ -307,9 +463,17 @@ static bool findTriangles(const SMDS_MeshNode * theNode1, if ( elem->GetType() == SMDSAbs_Face && emap.find( elem ) != emap.end() ) if ( theTria1 ) { - theTria2 = elem; + // theTria1 must be element with minimum ID + if( theTria1->GetID() < elem->GetID() ) { + theTria2 = elem; + } + else { + theTria2 = theTria1; + theTria1 = elem; + } break; - } else { + } + else { theTria1 = elem; } } @@ -326,6 +490,9 @@ static bool findTriangles(const SMDS_MeshNode * theNode1, bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1, const SMDS_MeshNode * theNode2) { + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + MESSAGE( "::InverseDiag()" ); const SMDS_MeshElement *tr1, *tr2; @@ -333,55 +500,65 @@ bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1, return false; const SMDS_FaceOfNodes* F1 = dynamic_cast( tr1 ); - if (!F1) return false; + //if (!F1) return false; const SMDS_FaceOfNodes* F2 = dynamic_cast( tr2 ); - if (!F2) return false; - - // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A - // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ | - // |/ | | \| - // B +--+ 2 B +--+ 2 - - // put nodes in array - // and find indices of 1,2 and of A in tr1 and of B in tr2 - int i, iA1 = 0, i1 = 0; - const SMDS_MeshNode* aNodes1 [3]; - SMDS_ElemIteratorPtr it; - for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) { - aNodes1[ i ] = static_cast( it->next() ); - if ( aNodes1[ i ] == theNode1 ) - iA1 = i; // node A in tr1 - else if ( aNodes1[ i ] != theNode2 ) - i1 = i; // node 1 - } - int iB2 = 0, i2 = 0; - const SMDS_MeshNode* aNodes2 [3]; - for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) { - aNodes2[ i ] = static_cast( it->next() ); - if ( aNodes2[ i ] == theNode2 ) - iB2 = i; // node B in tr2 - else if ( aNodes2[ i ] != theNode1 ) - i2 = i; // node 2 - } - - // nodes 1 and 2 should not be the same - if ( aNodes1[ i1 ] == aNodes2[ i2 ] ) - return false; + //if (!F2) return false; + if (F1 && F2) { + + // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A + // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ | + // |/ | | \| + // B +--+ 2 B +--+ 2 + + // put nodes in array + // and find indices of 1,2 and of A in tr1 and of B in tr2 + int i, iA1 = 0, i1 = 0; + const SMDS_MeshNode* aNodes1 [3]; + SMDS_ElemIteratorPtr it; + for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) { + aNodes1[ i ] = static_cast( it->next() ); + if ( aNodes1[ i ] == theNode1 ) + iA1 = i; // node A in tr1 + else if ( aNodes1[ i ] != theNode2 ) + i1 = i; // node 1 + } + int iB2 = 0, i2 = 0; + const SMDS_MeshNode* aNodes2 [3]; + for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) { + aNodes2[ i ] = static_cast( it->next() ); + if ( aNodes2[ i ] == theNode2 ) + iB2 = i; // node B in tr2 + else if ( aNodes2[ i ] != theNode1 ) + i2 = i; // node 2 + } + + // nodes 1 and 2 should not be the same + if ( aNodes1[ i1 ] == aNodes2[ i2 ] ) + return false; - // tr1: A->2 - aNodes1[ iA1 ] = aNodes2[ i2 ]; - // tr2: B->1 - aNodes2[ iB2 ] = aNodes1[ i1 ]; + // tr1: A->2 + aNodes1[ iA1 ] = aNodes2[ i2 ]; + // tr2: B->1 + aNodes2[ iB2 ] = aNodes1[ i1 ]; - //MESSAGE( tr1 << tr2 ); + //MESSAGE( tr1 << tr2 ); - GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 ); - GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 ); + GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 ); + GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 ); - //MESSAGE( tr1 << tr2 ); + //MESSAGE( tr1 << tr2 ); + + return true; + } - return true; - + // check case of quadratic faces + const SMDS_QuadraticFaceOfNodes* QF1 = + dynamic_cast (tr1); + if(!QF1) return false; + const SMDS_QuadraticFaceOfNodes* QF2 = + dynamic_cast (tr2); + if(!QF2) return false; + return InverseDiag(tr1,tr2); } //======================================================================= @@ -397,12 +574,16 @@ bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [], const SMDS_MeshElement * tr1, const SMDS_MeshElement * tr2 ) { + if( tr1->NbNodes() != tr2->NbNodes() ) + return false; // find the 4-th node to insert into tr1 const SMDS_MeshNode* n4 = 0; SMDS_ElemIteratorPtr it = tr2->nodesIterator(); - while ( !n4 && it->more() ) - { + int i=0; + //while ( !n4 && it->more() ) { + while ( !n4 && i<3 ) { const SMDS_MeshNode * n = static_cast( it->next() ); + i++; bool isDiag = ( n == theNode1 || n == theNode2 ); if ( !isDiag ) n4 = n; @@ -410,19 +591,19 @@ bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [], // Make an array of nodes to be in a quadrangle int iNode = 0, iFirstDiag = -1; it = tr1->nodesIterator(); - while ( it->more() ) - { + i=0; + //while ( it->more() ) { + while ( i<3 ) { const SMDS_MeshNode * n = static_cast( it->next() ); + i++; bool isDiag = ( n == theNode1 || n == theNode2 ); - if ( isDiag ) - { + if ( isDiag ) { if ( iFirstDiag < 0 ) iFirstDiag = iNode; else if ( iNode - iFirstDiag == 1 ) theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes } - else if ( n == n4 ) - { + else if ( n == n4 ) { return false; // tr1 and tr2 should not have all the same nodes } theQuadNodes[ iNode++ ] = n; @@ -443,6 +624,9 @@ bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [], bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1, const SMDS_MeshNode * theNode2) { + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + MESSAGE( "::DeleteDiag()" ); const SMDS_MeshElement *tr1, *tr2; @@ -450,59 +634,167 @@ bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1, return false; const SMDS_FaceOfNodes* F1 = dynamic_cast( tr1 ); - if (!F1) return false; + //if (!F1) return false; const SMDS_FaceOfNodes* F2 = dynamic_cast( tr2 ); - if (!F2) return false; + //if (!F2) return false; + if (F1 && F2) { - const SMDS_MeshNode* aNodes [ 4 ]; - if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 )) - return false; + const SMDS_MeshNode* aNodes [ 4 ]; + if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 )) + return false; + + //MESSAGE( endl << tr1 << tr2 ); - //MESSAGE( endl << tr1 << tr2 ); + GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 ); + myLastCreatedElems.Append(tr1); + GetMeshDS()->RemoveElement( tr2 ); + + //MESSAGE( endl << tr1 ); + + return true; + } - GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 ); + // check case of quadratic faces + const SMDS_QuadraticFaceOfNodes* QF1 = + dynamic_cast (tr1); + if(!QF1) return false; + const SMDS_QuadraticFaceOfNodes* QF2 = + dynamic_cast (tr2); + if(!QF2) return false; + + // 5 + // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9) + // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8) + // | / | + // 7 + + + 6 + // | /9 | + // |/ | + // 4 +--+--+ 3 + // 8 + + const SMDS_MeshNode* N1 [6]; + const SMDS_MeshNode* N2 [6]; + if(!GetNodesFromTwoTria(tr1,tr2,N1,N2)) + return false; + // now we receive following N1 and N2 (using numeration as above image) + // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6) + // i.e. first nodes from both arrays determ new diagonal + + const SMDS_MeshNode* aNodes[8]; + aNodes[0] = N1[0]; + aNodes[1] = N1[1]; + aNodes[2] = N2[0]; + aNodes[3] = N2[1]; + aNodes[4] = N1[3]; + aNodes[5] = N2[5]; + aNodes[6] = N2[3]; + aNodes[7] = N1[5]; + + GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 ); + myLastCreatedElems.Append(tr1); GetMeshDS()->RemoveElement( tr2 ); - //MESSAGE( endl << tr1 ); + // remove middle node (9) + GetMeshDS()->RemoveNode( N1[4] ); return true; } //======================================================================= //function : Reorient -//purpose : Reverse the normal of theFace -// Return false if theFace is null +//purpose : Reverse theElement orientation //======================================================================= -bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theFace) +bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem) { - if (!theFace) return false; - const SMDS_FaceOfNodes* F = dynamic_cast( theFace ); - if (!F) return false; + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); - const SMDS_MeshNode* aNodes [4], *tmpNode; - int i = 0; - SMDS_ElemIteratorPtr it = theFace->nodesIterator(); - while ( it->more() ) - aNodes[ i++ ] = static_cast( it->next() ); + if (!theElem) + return false; + SMDS_ElemIteratorPtr it = theElem->nodesIterator(); + if ( !it || !it->more() ) + return false; - // exchange nodes with indeces 0 and 2 - tmpNode = aNodes[ 0 ]; - aNodes[ 0 ] = aNodes[ 2 ]; - aNodes[ 2 ] = tmpNode; + switch ( theElem->GetType() ) { - //MESSAGE( theFace ); + case SMDSAbs_Edge: + case SMDSAbs_Face: { + if(!theElem->IsQuadratic()) { + int i = theElem->NbNodes(); + vector aNodes( i ); + while ( it->more() ) + aNodes[ --i ]= static_cast( it->next() ); + return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() ); + } + else { + // quadratic elements + if(theElem->GetType()==SMDSAbs_Edge) { + vector aNodes(3); + aNodes[1]= static_cast( it->next() ); + aNodes[0]= static_cast( it->next() ); + aNodes[2]= static_cast( it->next() ); + return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 ); + } + else { + int nbn = theElem->NbNodes(); + vector aNodes(nbn); + aNodes[0]= static_cast( it->next() ); + int i=1; + for(; i( it->next() ); + } + for(i=0; i( it->next() ); + } + return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn ); + } + } + } + case SMDSAbs_Volume: { + if (theElem->IsPoly()) { + const SMDS_PolyhedralVolumeOfNodes* aPolyedre = + static_cast( theElem ); + if (!aPolyedre) { + MESSAGE("Warning: bad volumic element"); + return false; + } - GetMeshDS()->ChangeElementNodes( theFace, aNodes, theFace->NbNodes() ); + int nbFaces = aPolyedre->NbFaces(); + vector poly_nodes; + vector quantities (nbFaces); + + // reverse each face of the polyedre + for (int iface = 1; iface <= nbFaces; iface++) { + int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface); + quantities[iface - 1] = nbFaceNodes; + + for (inode = nbFaceNodes; inode >= 1; inode--) { + const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode); + poly_nodes.push_back(curNode); + } + } + + return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities ); - //MESSAGE( theFace ); + } + else { + SMDS_VolumeTool vTool; + if ( !vTool.Set( theElem )) + return false; + vTool.Inverse(); + return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() ); + } + } + default:; + } - return true; + return false; } //======================================================================= //function : getBadRate -//purpose : +//purpose : //======================================================================= static double getBadRate (const SMDS_MeshElement* theElem, @@ -512,17 +804,21 @@ static double getBadRate (const SMDS_MeshElement* theElem, if ( !theElem || !theCrit->GetPoints( theElem, P )) return 1e100; return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() ); + //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() ); } - + //======================================================================= //function : QuadToTri //purpose : Cut quadrangles into triangles. // theCrit is used to select a diagonal to cut //======================================================================= -bool SMESH_MeshEditor::QuadToTri (set & theElems, +bool SMESH_MeshEditor::QuadToTri (map & theElems, SMESH::Controls::NumericalFunctorPtr theCrit) { + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + MESSAGE( "::QuadToTri()" ); if ( !theCrit.get() ) @@ -530,15 +826,19 @@ bool SMESH_MeshEditor::QuadToTri (set & theElems, SMESHDS_Mesh * aMesh = GetMeshDS(); - set< const SMDS_MeshElement * >::iterator itElem; - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) - { - const SMDS_MeshElement* elem = (*itElem); - if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() != 4 ) + Handle(Geom_Surface) surface; + SMESH_MesherHelper helper( *GetMesh() ); + + map::iterator itElem; + for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { + const SMDS_MeshElement* elem = (*itElem).second; + if ( !elem || elem->GetType() != SMDSAbs_Face ) + continue; + if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 )) continue; // retrieve element nodes - const SMDS_MeshNode* aNodes [4]; + const SMDS_MeshNode* aNodes [8]; SMDS_ElemIteratorPtr itN = elem->nodesIterator(); int i = 0; while ( itN->more() ) @@ -549,39 +849,161 @@ bool SMESH_MeshEditor::QuadToTri (set & theElems, SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] ); SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] ); aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit ); - + 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 ); int aShapeId = FindShape( elem ); - //MESSAGE( "aBadRate1 = " << aBadRate1 << "; aBadRate2 = " << aBadRate2 - // << " ShapeID = " << aShapeId << endl << elem ); - - if ( aBadRate1 <= aBadRate2 ) { - // tr1 + tr2 is better - aMesh->ChangeElementNodes( elem, aNodes, 3 ); - //MESSAGE( endl << elem ); + const SMDS_MeshElement* newElem = 0; + + if( !elem->IsQuadratic() ) { - elem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] ); + // split liner quadrangle + + if ( aBadRate1 <= aBadRate2 ) { + // tr1 + tr2 is better + aMesh->ChangeElementNodes( elem, aNodes, 3 ); + newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] ); + } + else { + // tr3 + tr4 is better + aMesh->ChangeElementNodes( elem, &aNodes[1], 3 ); + newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] ); + } } else { - // tr3 + tr4 is better - aMesh->ChangeElementNodes( elem, &aNodes[1], 3 ); - //MESSAGE( endl << elem ); - elem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] ); - } - //MESSAGE( endl << elem ); + // split qudratic quadrangle + + // get surface elem is on + if ( aShapeId != helper.GetSubShapeID() ) { + surface.Nullify(); + TopoDS_Shape shape; + if ( aShapeId > 0 ) + shape = aMesh->IndexToShape( aShapeId ); + if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) { + TopoDS_Face face = TopoDS::Face( shape ); + surface = BRep_Tool::Surface( face ); + if ( !surface.IsNull() ) + 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; + } + 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(); + } + const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() ); + myLastCreatedNodes.Append(newN); + + // create a new element + const SMDS_MeshNode* N[6]; + if ( aBadRate1 <= aBadRate2 ) { + N[0] = aNodes[0]; + N[1] = aNodes[1]; + N[2] = aNodes[2]; + N[3] = aNodes[4]; + N[4] = aNodes[5]; + N[5] = newN; + newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0], + aNodes[6], aNodes[7], newN ); + } + else { + N[0] = aNodes[1]; + N[1] = aNodes[2]; + N[2] = aNodes[3]; + N[3] = aNodes[5]; + N[4] = aNodes[6]; + N[5] = newN; + newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1], + aNodes[7], aNodes[4], newN ); + } + aMesh->ChangeElementNodes( elem, N, 6 ); + + } // qudratic case + + // care of a new element + + myLastCreatedElems.Append(newElem); + AddToSameGroups( newElem, elem, aMesh ); // put a new triangle on the same shape if ( aShapeId ) - aMesh->SetMeshElementOnShape( elem, aShapeId ); + aMesh->SetMeshElementOnShape( newElem, aShapeId ); } - return true; } +//======================================================================= +//function : BestSplit +//purpose : Find better diagonal for cutting. +//======================================================================= +int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad, + SMESH::Controls::NumericalFunctorPtr theCrit) +{ + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + + if (!theCrit.get()) + return -1; + + if (!theQuad || theQuad->GetType() != SMDSAbs_Face ) + return -1; + + if( theQuad->NbNodes()==4 || + (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) { + + // retrieve element nodes + const SMDS_MeshNode* aNodes [4]; + SMDS_ElemIteratorPtr itN = theQuad->nodesIterator(); + int i = 0; + //while (itN->more()) + while (i<4) { + aNodes[ i++ ] = static_cast( itN->next() ); + } + // compare two sets of possible triangles + double aBadRate1, aBadRate2; // to what extent a set is bad + SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] ); + SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] ); + aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit ); + + 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 ); + + if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better + return 1; // diagonal 1-3 + + return 2; // diagonal 2-4 + } + return -1; +} + //======================================================================= //function : AddToSameGroups //purpose : add elemToAdd to the groups the elemInGroups belongs to @@ -600,52 +1022,161 @@ void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd, } } + +//======================================================================= +//function : RemoveElemFromGroups +//purpose : Remove removeelem to the groups the elemInGroups belongs to +//======================================================================= +void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem, + SMESHDS_Mesh * aMesh) +{ + const set& groups = aMesh->GetGroups(); + if (!groups.empty()) + { + set::const_iterator GrIt = groups.begin(); + for (; GrIt != groups.end(); GrIt++) + { + SMESHDS_Group* grp = dynamic_cast(*GrIt); + if (!grp || grp->IsEmpty()) continue; + grp->SMDSGroup().Remove(removeelem); + } + } +} + + //======================================================================= //function : QuadToTri //purpose : Cut quadrangles into triangles. // theCrit is used to select a diagonal to cut //======================================================================= -bool SMESH_MeshEditor::QuadToTri (std::set & theElems, - const bool the13Diag) +bool SMESH_MeshEditor::QuadToTri (std::map & theElems, + const bool the13Diag) { + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + MESSAGE( "::QuadToTri()" ); SMESHDS_Mesh * aMesh = GetMeshDS(); - set< const SMDS_MeshElement * >::iterator itElem; - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) - { - const SMDS_MeshElement* elem = (*itElem); - if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() != 4 ) - continue; + Handle(Geom_Surface) surface; + SMESH_MesherHelper helper( *GetMesh() ); - // retrieve element nodes - const SMDS_MeshNode* aNodes [4]; - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - int i = 0; - while ( itN->more() ) - aNodes[ i++ ] = static_cast( itN->next() ); + map::iterator itElem; + for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { + const SMDS_MeshElement* elem = (*itElem).second; + if ( !elem || elem->GetType() != SMDSAbs_Face ) + continue; + bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8; + if(!isquad) continue; - int aShapeId = FindShape( elem ); - const SMDS_MeshElement* newElem = 0; - if ( the13Diag ) - { - aMesh->ChangeElementNodes( elem, aNodes, 3 ); - newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] ); - } - else - { - aMesh->ChangeElementNodes( elem, &aNodes[1], 3 ); - newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] ); + if(elem->NbNodes()==4) { + // retrieve element nodes + const SMDS_MeshNode* aNodes [4]; + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + int i = 0; + while ( itN->more() ) + aNodes[ i++ ] = static_cast( itN->next() ); + + int aShapeId = FindShape( elem ); + const SMDS_MeshElement* newElem = 0; + if ( the13Diag ) { + aMesh->ChangeElementNodes( elem, aNodes, 3 ); + newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] ); + } + else { + aMesh->ChangeElementNodes( elem, &aNodes[1], 3 ); + newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] ); + } + myLastCreatedElems.Append(newElem); + // put a new triangle on the same shape and add to the same groups + if ( aShapeId ) + aMesh->SetMeshElementOnShape( newElem, aShapeId ); + AddToSameGroups( newElem, elem, aMesh ); } - // put a new triangle on the same shape and add to the same groups + // Quadratic quadrangle + + if( elem->NbNodes()==8 && elem->IsQuadratic() ) { + + // get surface elem is on + int aShapeId = FindShape( elem ); + if ( aShapeId != helper.GetSubShapeID() ) { + surface.Nullify(); + TopoDS_Shape shape; + if ( aShapeId > 0 ) + shape = aMesh->IndexToShape( aShapeId ); + if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) { + TopoDS_Face face = TopoDS::Face( shape ); + surface = BRep_Tool::Surface( face ); + if ( !surface.IsNull() ) + helper.SetSubShape( shape ); + } + } - if ( aShapeId ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); + 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 ]; + } + } - AddToSameGroups( newElem, elem, aMesh ); + // 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; + } + else { + TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() ); + gp_XY uv( 0,0 ); + for(i=0; i<4; i++) + uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode ); + uv /= 4.; + p = surface->Value( uv.X(), uv.Y() ).XYZ(); + } + const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() ); + myLastCreatedNodes.Append(newN); + + // create a new element + const SMDS_MeshElement* newElem = 0; + const SMDS_MeshNode* N[6]; + if ( the13Diag ) { + N[0] = aNodes[0]; + N[1] = aNodes[1]; + N[2] = aNodes[2]; + N[3] = aNodes[4]; + N[4] = aNodes[5]; + N[5] = newN; + newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0], + aNodes[6], aNodes[7], newN ); + } + else { + N[0] = aNodes[1]; + N[1] = aNodes[2]; + N[2] = aNodes[3]; + N[3] = aNodes[5]; + N[4] = aNodes[6]; + N[5] = newN; + newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1], + aNodes[7], aNodes[4], newN ); + } + myLastCreatedElems.Append(newElem); + aMesh->ChangeElementNodes( elem, N, 6 ); + // put a new triangle on the same shape and add to the same groups + if ( aShapeId ) + aMesh->SetMeshElementOnShape( newElem, aShapeId ); + AddToSameGroups( newElem, elem, aMesh ); + } } return true; @@ -653,7 +1184,7 @@ bool SMESH_MeshEditor::QuadToTri (std::set & theElems, //======================================================================= //function : getAngle -//purpose : +//purpose : //======================================================================= double getAngle(const SMDS_MeshElement * tr1, @@ -668,18 +1199,24 @@ double getAngle(const SMDS_MeshElement * tr1, if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) || !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 )) return angle; - gp_Vec N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) ); + gp_Vec N1,N2; + if(!tr1->IsQuadratic()) + N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) ); + else + N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) ); if ( N1.SquareMagnitude() <= gp::Resolution() ) return angle; - gp_Vec N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) ); + if(!tr2->IsQuadratic()) + N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) ); + else + N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) ); if ( N2.SquareMagnitude() <= gp::Resolution() ) return angle; - + // find the first diagonal node n1 in the triangles: // take in account a diagonal link orientation const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 }; - for ( int t = 0; t < 2; t++ ) - { + for ( int t = 0; t < 2; t++ ) { SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator(); int i = 0, iDiag = -1; while ( it->more()) { @@ -709,7 +1246,6 @@ double getAngle(const SMDS_MeshElement * tr1, // class generating a unique ID for a pair of nodes // and able to return nodes by that ID // ================================================= - class LinkID_Gen { public: @@ -740,6 +1276,7 @@ class LinkID_Gen { long myMaxID; }; + //======================================================================= //function : TriToQuad //purpose : Fuse neighbour triangles into quadrangles. @@ -748,75 +1285,89 @@ class LinkID_Gen { // fusion is still performed. //======================================================================= -bool SMESH_MeshEditor::TriToQuad (set & theElems, +bool SMESH_MeshEditor::TriToQuad (map & theElems, SMESH::Controls::NumericalFunctorPtr theCrit, const double theMaxAngle) { + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + MESSAGE( "::TriToQuad()" ); if ( !theCrit.get() ) return false; SMESHDS_Mesh * aMesh = GetMeshDS(); - LinkID_Gen aLinkID_Gen( aMesh ); - + //LinkID_Gen aLinkID_Gen( aMesh ); // Prepare data for algo: build // 1. map of elements with their linkIDs // 2. map of linkIDs with their elements - map< long, list< const SMDS_MeshElement* > > mapLi_listEl; - map< long, list< const SMDS_MeshElement* > >::iterator itLE; - map< const SMDS_MeshElement*, set< long > > mapEl_setLi; - map< const SMDS_MeshElement*, set< long > >::iterator itEL; - - set::iterator itElem; - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) - { - const SMDS_MeshElement* elem = (*itElem); - if ( !elem || elem->NbNodes() != 3 ) - continue; + //map< long, list< const SMDS_MeshElement* > > mapLi_listEl; + //map< long, list< const SMDS_MeshElement* > >::iterator itLE; + //map< const SMDS_MeshElement*, set< long > > mapEl_setLi; + //map< const SMDS_MeshElement*, set< long > >::iterator itEL; + + map< NLink, list< const SMDS_MeshElement* > > mapLi_listEl; + map< NLink, list< const SMDS_MeshElement* > >::iterator itLE; + map< const SMDS_MeshElement*, set< NLink > > mapEl_setLi; + map< const SMDS_MeshElement*, set< NLink > >::iterator itEL; + + map::iterator itElem; + for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { + const SMDS_MeshElement* elem = (*itElem).second; + //if ( !elem || elem->NbNodes() != 3 ) + // continue; + if(!elem || elem->GetType() != SMDSAbs_Face ) continue; + bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic()); + if(!IsTria) continue; // retrieve element nodes const SMDS_MeshNode* aNodes [4]; SMDS_ElemIteratorPtr itN = elem->nodesIterator(); int i = 0; - while ( itN->more() ) + //while ( itN->more() ) + while ( i<3 ) aNodes[ i++ ] = static_cast( itN->next() ); ASSERT( i == 3 ); aNodes[ 3 ] = aNodes[ 0 ]; // fill maps - for ( i = 0; i < 3; i++ ) - { - long linkID = aLinkID_Gen.GetLinkID( aNodes[ i ], aNodes[ i+1 ] ); + for ( i = 0; i < 3; i++ ) { + //long linkID = aLinkID_Gen.GetLinkID( aNodes[ i ], aNodes[ i+1 ] ); + NLink link(( aNodes[i] < aNodes[i+1] ? aNodes[i] : aNodes[i+1] ), + ( aNodes[i] < aNodes[i+1] ? aNodes[i+1] : aNodes[i] )); // check if elements sharing a link can be fused - itLE = mapLi_listEl.find( linkID ); - if ( itLE != mapLi_listEl.end() ) - { - if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link + //itLE = mapLi_listEl.find( linkID ); + itLE = mapLi_listEl.find( link ); + if ( itLE != mapLi_listEl.end() ) { + if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link continue; const SMDS_MeshElement* elem2 = (*itLE).second.front(); -// if ( FindShape( elem ) != FindShape( elem2 )) -// continue; // do not fuse triangles laying on different shapes + //if ( FindShape( elem ) != FindShape( elem2 )) + // continue; // do not fuse triangles laying on different shapes if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle ) continue; // avoid making badly shaped quads (*itLE).second.push_back( elem ); } - else - mapLi_listEl[ linkID ].push_back( elem ); - mapEl_setLi [ elem ].insert( linkID ); + else { + //mapLi_listEl[ linkID ].push_back( elem ); + mapLi_listEl[ link ].push_back( elem ); + } + //mapEl_setLi [ elem ].insert( linkID ); + mapEl_setLi [ elem ].insert( link ); } } // Clean the maps from the links shared by a sole element, ie // links to which only one element is bound in mapLi_listEl - for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) - { + for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) { int nbElems = (*itLE).second.size(); if ( nbElems < 2 ) { const SMDS_MeshElement* elem = (*itLE).second.front(); - long link = (*itLE).first; + //long link = (*itLE).first; + NLink link = (*itLE).first; mapEl_setLi[ elem ].erase( link ); if ( mapEl_setLi[ elem ].empty() ) mapEl_setLi.erase( elem ); @@ -824,19 +1375,16 @@ bool SMESH_MeshEditor::TriToQuad (set & theElems, } // Algo: fuse triangles into quadrangles - - while ( ! mapEl_setLi.empty() ) - { + + while ( ! mapEl_setLi.empty() ) { // Look for the start element: // the element having the least nb of shared links const SMDS_MeshElement* startElem = 0; int minNbLinks = 4; - for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) - { + for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) { int nbLinks = (*itEL).second.size(); - if ( nbLinks < minNbLinks ) - { + if ( nbLinks < minNbLinks ) { startElem = (*itEL).first; minNbLinks = nbLinks; if ( minNbLinks == 1 ) @@ -846,17 +1394,16 @@ bool SMESH_MeshEditor::TriToQuad (set & theElems, // search elements to fuse starting from startElem or links of elements // fused earlyer - startLinks - list< long > startLinks; - while ( startElem || !startLinks.empty() ) - { - while ( !startElem && !startLinks.empty() ) - { + //list< long > startLinks; + list< NLink > startLinks; + while ( startElem || !startLinks.empty() ) { + while ( !startElem && !startLinks.empty() ) { // Get an element to start, by a link - long linkId = startLinks.front(); + //long linkId = startLinks.front(); + NLink linkId = startLinks.front(); startLinks.pop_front(); itLE = mapLi_listEl.find( linkId ); - if ( itLE != mapLi_listEl.end() ) - { + if ( itLE != mapLi_listEl.end() ) { list< const SMDS_MeshElement* > & listElem = (*itLE).second; list< const SMDS_MeshElement* >::iterator itE = listElem.begin(); for ( ; itE != listElem.end() ; itE++ ) @@ -866,69 +1413,83 @@ bool SMESH_MeshEditor::TriToQuad (set & theElems, } } - if ( startElem ) - { + if ( startElem ) { // Get candidates to be fused - const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0; - long link12, link13; + //long link12, link13; + NLink link12, link13; startElem = 0; ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() ); - set< long >& setLi = mapEl_setLi[ tr1 ]; + //set< long >& setLi = mapEl_setLi[ tr1 ]; + set< NLink >& setLi = mapEl_setLi[ tr1 ]; ASSERT( !setLi.empty() ); - set< long >::iterator itLi; - for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ ) - { - long linkID = (*itLi); + //set< long >::iterator itLi; + set< NLink >::iterator itLi; + for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ ) { + //long linkID = (*itLi); + NLink linkID = (*itLi); itLE = mapLi_listEl.find( linkID ); if ( itLE == mapLi_listEl.end() ) continue; + const SMDS_MeshElement* elem = (*itLE).second.front(); if ( elem == tr1 ) elem = (*itLE).second.back(); mapLi_listEl.erase( itLE ); if ( mapEl_setLi.find( elem ) == mapEl_setLi.end()) continue; - if ( tr2 ) - { + if ( tr2 ) { tr3 = elem; link13 = linkID; } - else - { + else { tr2 = elem; link12 = linkID; } // add other links of elem to list of links to re-start from - set< long >& links = mapEl_setLi[ elem ]; - set< long >::iterator it; - for ( it = links.begin(); it != links.end(); it++ ) - { - long linkID2 = (*it); + //set< long >& links = mapEl_setLi[ elem ]; + //set< long >::iterator it; + set< NLink >& links = mapEl_setLi[ elem ]; + set< NLink >::iterator it; + for ( it = links.begin(); it != links.end(); it++ ) { + //long linkID2 = (*it); + NLink linkID2 = (*it); if ( linkID2 != linkID ) startLinks.push_back( linkID2 ); } } // Get nodes of possible quadrangles - const SMDS_MeshNode *n12 [4], *n13 [4]; bool Ok12 = false, Ok13 = false; + //const SMDS_MeshNode *linkNode1, *linkNode2; const SMDS_MeshNode *linkNode1, *linkNode2; - if ( tr2 && - aLinkID_Gen.GetNodes( link12, linkNode1, linkNode2 ) && - getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 )) - Ok12 = true; - if ( tr3 && - aLinkID_Gen.GetNodes( link13, linkNode1, linkNode2 ) && - getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 )) - Ok13 = true; + if(tr2) { + //const SMDS_MeshNode *linkNode1 = link12.first; + //const SMDS_MeshNode *linkNode2 = link12.second; + linkNode1 = link12.first; + linkNode2 = link12.second; + //if ( tr2 && + // aLinkID_Gen.GetNodes( link12, linkNode1, linkNode2 ) && + // getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 )) + // Ok12 = true; + if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 )) + Ok12 = true; + } + if(tr3) { + linkNode1 = link13.first; + linkNode2 = link13.second; + //if ( tr3 && + // aLinkID_Gen.GetNodes( link13, linkNode1, linkNode2 ) && + // getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 )) + // Ok13 = true; + if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 )) + Ok13 = true; + } // Choose a pair to fuse - - if ( Ok12 && Ok13 ) - { + if ( Ok12 && Ok13 ) { SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] ); SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] ); double aBadRate12 = getBadRate( &quad12, theCrit ); @@ -939,24 +1500,98 @@ bool SMESH_MeshEditor::TriToQuad (set & theElems, Ok13 = false; } - // Make quadrangles // and remove fused elems and removed links from the maps - mapEl_setLi.erase( tr1 ); - if ( Ok12 ) - { + if ( Ok12 ) { mapEl_setLi.erase( tr2 ); mapLi_listEl.erase( link12 ); - aMesh->ChangeElementNodes( tr1, n12, 4 ); - aMesh->RemoveElement( tr2 ); + if(tr1->NbNodes()==3) { + if( tr1->GetID() < tr2->GetID() ) { + aMesh->ChangeElementNodes( tr1, n12, 4 ); + myLastCreatedElems.Append(tr1); + aMesh->RemoveElement( tr2 ); + } + else { + aMesh->ChangeElementNodes( tr2, n12, 4 ); + myLastCreatedElems.Append(tr2); + aMesh->RemoveElement( tr1); + } + } + else { + const SMDS_MeshNode* N1 [6]; + const SMDS_MeshNode* N2 [6]; + GetNodesFromTwoTria(tr1,tr2,N1,N2); + // now we receive following N1 and N2 (using numeration as above image) + // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6) + // i.e. first nodes from both arrays determ new diagonal + const SMDS_MeshNode* aNodes[8]; + aNodes[0] = N1[0]; + aNodes[1] = N1[1]; + aNodes[2] = N2[0]; + aNodes[3] = N2[1]; + aNodes[4] = N1[3]; + aNodes[5] = N2[5]; + aNodes[6] = N2[3]; + aNodes[7] = N1[5]; + if( tr1->GetID() < tr2->GetID() ) { + GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 ); + myLastCreatedElems.Append(tr1); + GetMeshDS()->RemoveElement( tr2 ); + } + else { + GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 ); + myLastCreatedElems.Append(tr2); + GetMeshDS()->RemoveElement( tr1 ); + } + // remove middle node (9) + GetMeshDS()->RemoveNode( N1[4] ); + } } - else if ( Ok13 ) - { + else if ( Ok13 ) { mapEl_setLi.erase( tr3 ); mapLi_listEl.erase( link13 ); - aMesh->ChangeElementNodes( tr1, n13, 4 ); - aMesh->RemoveElement( tr3 ); + if(tr1->NbNodes()==3) { + if( tr1->GetID() < tr2->GetID() ) { + aMesh->ChangeElementNodes( tr1, n13, 4 ); + myLastCreatedElems.Append(tr1); + aMesh->RemoveElement( tr3 ); + } + else { + aMesh->ChangeElementNodes( tr3, n13, 4 ); + myLastCreatedElems.Append(tr3); + aMesh->RemoveElement( tr1 ); + } + } + else { + const SMDS_MeshNode* N1 [6]; + const SMDS_MeshNode* N2 [6]; + GetNodesFromTwoTria(tr1,tr3,N1,N2); + // now we receive following N1 and N2 (using numeration as above image) + // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6) + // i.e. first nodes from both arrays determ new diagonal + const SMDS_MeshNode* aNodes[8]; + aNodes[0] = N1[0]; + aNodes[1] = N1[1]; + aNodes[2] = N2[0]; + aNodes[3] = N2[1]; + aNodes[4] = N1[3]; + aNodes[5] = N2[5]; + aNodes[6] = N2[3]; + aNodes[7] = N1[5]; + if( tr1->GetID() < tr2->GetID() ) { + GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 ); + myLastCreatedElems.Append(tr1); + GetMeshDS()->RemoveElement( tr3 ); + } + else { + GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 ); + myLastCreatedElems.Append(tr3); + GetMeshDS()->RemoveElement( tr1 ); + } + // remove middle node (9) + GetMeshDS()->RemoveNode( N1[4] ); + } } // Next element to fuse: the rejected one @@ -966,17 +1601,17 @@ bool SMESH_MeshEditor::TriToQuad (set & theElems, } // if ( startElem ) } // while ( startElem || !startLinks.empty() ) } // while ( ! mapEl_setLi.empty() ) - + return true; } -#define DUMPSO(txt) \ +/*#define DUMPSO(txt) \ // cout << txt << endl; //============================================================================= -/*! - * - */ +// +// +// //============================================================================= static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] ) { @@ -1056,7 +1691,7 @@ bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh, } DUMPSO( "========================================"); - + set faceNodes; // ids of bottom face nodes, to be found set checkedId1; // ids of tried 2-nd nodes Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane @@ -1075,7 +1710,7 @@ bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh, checkedId1.insert ( id1 ); break; } - + // Find the 3-d node so that 1-2-3 triangle to be on a hexa face, // ie that all but meybe one (id3 which is on the same face) nodes // lay on the same side from the triangle plane. @@ -1176,7 +1811,7 @@ bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh, } } - + // Set nodes of the found bottom face in good order DUMPSO( " Found bottom face: "); i = SortQuadNodes( theMesh, idNodes ); @@ -1200,7 +1835,7 @@ bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh, Standard_Real upDirSize = upDir.Magnitude(); if ( upDirSize <= gp::Resolution() ) return false; upDir / upDirSize; - + // Assure that the bottom face normal points up gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) ); Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) ); @@ -1248,7 +1883,7 @@ bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh, // } return true; -} +}*/ //======================================================================= //function : laplacianSmooth @@ -1256,52 +1891,77 @@ bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh, // connected to that node along an element edge //======================================================================= -void laplacianSmooth(SMESHDS_Mesh * theMesh, - const SMDS_MeshNode* theNode, - const set & theElems, - const set & theFixedNodes) +void laplacianSmooth(const SMDS_MeshNode* theNode, + const Handle(Geom_Surface)& theSurface, + map< const SMDS_MeshNode*, gp_XY* >& theUVMap) { // find surrounding nodes + set< const SMDS_MeshNode* > nodeSet; SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(); while ( elemIt->more() ) { const SMDS_MeshElement* elem = elemIt->next(); - if ( theElems.find( elem ) == theElems.end() ) + if ( elem->GetType() != SMDSAbs_Face ) continue; - int i = 0, iNode = 0; - const SMDS_MeshNode* aNodes [4]; - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) - { - aNodes[ i ] = static_cast( itN->next() ); - if ( aNodes[ i ] == theNode ) - iNode = i; - else - nodeSet.insert( aNodes[ i ] ); - i++; - } - if ( elem->NbNodes() == 4 ) { // remove an opposite node - iNode += ( iNode < 2 ) ? 2 : -2; - nodeSet.erase( aNodes[ iNode ]); + for ( int i = 0; i < elem->NbNodes(); ++i ) { + if ( elem->GetNode( i ) == theNode ) { + // add linked nodes + int iBefore = i - 1; + int iAfter = i + 1; + if ( elem->IsQuadratic() ) { + int nbCorners = elem->NbNodes() / 2; + if ( iAfter >= nbCorners ) + iAfter = 0; // elem->GetNode() wraps index + if ( iBefore == -1 ) + iBefore = nbCorners - 1; + } + nodeSet.insert( elem->GetNode( iAfter )); + nodeSet.insert( elem->GetNode( iBefore )); + break; + } } } // compute new coodrs + double coord[] = { 0., 0., 0. }; set< const SMDS_MeshNode* >::iterator nodeSetIt = nodeSet.begin(); for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) { const SMDS_MeshNode* node = (*nodeSetIt); - coord[0] += node->X(); - coord[1] += node->Y(); - coord[2] += node->Z(); + if ( theSurface.IsNull() ) { // smooth in 3D + coord[0] += node->X(); + coord[1] += node->Y(); + coord[2] += node->Z(); + } + else { // smooth in 2D + ASSERT( theUVMap.find( node ) != theUVMap.end() ); + gp_XY* uv = theUVMap[ node ]; + coord[0] += uv->X(); + coord[1] += uv->Y(); + } + } + int nbNodes = nodeSet.size(); + if ( !nbNodes ) + return; + coord[0] /= nbNodes; + coord[1] /= nbNodes; + + if ( !theSurface.IsNull() ) { + ASSERT( theUVMap.find( theNode ) != theUVMap.end() ); + theUVMap[ theNode ]->SetCoord( coord[0], coord[1] ); + gp_Pnt p3d = theSurface->Value( coord[0], coord[1] ); + coord[0] = p3d.X(); + coord[1] = p3d.Y(); + coord[2] = p3d.Z(); } - double nbNodes = nodeSet.size(); - theMesh->MoveNode (theNode, - coord[0]/nbNodes, - coord[1]/nbNodes, - coord[2]/nbNodes); + else + coord[2] /= nbNodes; + + // move node + + const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]); } //======================================================================= @@ -1310,45 +1970,81 @@ void laplacianSmooth(SMESHDS_Mesh * theMesh, // surrounding elements //======================================================================= -void centroidalSmooth(SMESHDS_Mesh * theMesh, - const SMDS_MeshNode* theNode, - const set & theElems, - const set & theFixedNodes) +void centroidalSmooth(const SMDS_MeshNode* theNode, + const Handle(Geom_Surface)& theSurface, + map< const SMDS_MeshNode*, gp_XY* >& theUVMap) { gp_XYZ aNewXYZ(0.,0.,0.); SMESH::Controls::Area anAreaFunc; double totalArea = 0.; int nbElems = 0; + // compute new XYZ + SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(); while ( elemIt->more() ) { const SMDS_MeshElement* elem = elemIt->next(); - if ( theElems.find( elem ) == theElems.end() ) + if ( elem->GetType() != SMDSAbs_Face ) continue; - nbElems++; gp_XYZ elemCenter(0.,0.,0.); SMESH::Controls::TSequenceOfXYZ aNodePoints; SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) - { + int nn = elem->NbNodes(); + if(elem->IsQuadratic()) nn = nn/2; + int i=0; + //while ( itN->more() ) { + while ( i( itN->next() ); + i++; gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() ); aNodePoints.push_back( aP ); + if ( !theSurface.IsNull() ) { // smooth in 2D + ASSERT( theUVMap.find( aNode ) != theUVMap.end() ); + gp_XY* uv = theUVMap[ aNode ]; + aP.SetCoord( uv->X(), uv->Y(), 0. ); + } elemCenter += aP; } double elemArea = anAreaFunc.GetValue( aNodePoints ); totalArea += elemArea; - elemCenter /= elem->NbNodes(); + elemCenter /= nn; aNewXYZ += elemCenter * elemArea; } aNewXYZ /= totalArea; - theMesh->MoveNode (theNode, - aNewXYZ.X(), - aNewXYZ.Y(), - aNewXYZ.Z()); + if ( !theSurface.IsNull() ) { + theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() ); + aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ(); + } + + // move node + + const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z()); +} + +//======================================================================= +//function : getClosestUV +//purpose : return UV of closest projection +//======================================================================= + +static bool getClosestUV (Extrema_GenExtPS& projector, + const gp_Pnt& point, + gp_XY & result) +{ + projector.Perform( point ); + if ( projector.IsDone() ) { + double u, v, minVal = DBL_MAX; + for ( int i = projector.NbExt(); i > 0; i-- ) + if ( projector.Value( i ) < minVal ) { + minVal = projector.Value( i ); + projector.Point( i ).Parameter( u, v ); + } + result.SetCoord( u, v ); + return true; + } + return false; } //======================================================================= @@ -1361,128 +2057,519 @@ void centroidalSmooth(SMESHDS_Mesh * theMesh, // on edges and boundary nodes are always fixed. //======================================================================= -void SMESH_MeshEditor::Smooth (set & theElems, +void SMESH_MeshEditor::Smooth (map & theElems, set & theFixedNodes, const SmoothMethod theSmoothMethod, const int theNbIterations, - double theTgtAspectRatio) + double theTgtAspectRatio, + const bool the2D) { + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()"); + if ( theTgtAspectRatio < 1.0 ) + theTgtAspectRatio = 1.0; + + const double disttol = 1.e-16; + + SMESH::Controls::AspectRatio aQualityFunc; + SMESHDS_Mesh* aMesh = GetMeshDS(); + if ( theElems.empty() ) { - // add all faces + // add all faces to theElems SMDS_FaceIteratorPtr fIt = aMesh->facesIterator(); - while ( fIt->more() ) - theElems.insert( fIt->next() ); + while ( fIt->more() ) { + const SMDS_MeshElement* face = fIt->next(); + theElems.insert( make_pair(face->GetID(),face) ); + } } + // get all face ids theElems are on + set< int > faceIdSet; + map::iterator itElem; + if ( the2D ) + for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { + int fId = FindShape( (*itElem).second ); + // check that corresponding submesh exists and a shape is face + if (fId && + faceIdSet.find( fId ) == faceIdSet.end() && + aMesh->MeshElements( fId )) { + TopoDS_Shape F = aMesh->IndexToShape( fId ); + if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE ) + faceIdSet.insert( fId ); + } + } + faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face + + // =============================================== + // smooth elements on each TopoDS_Face separately + // =============================================== + + set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end + for ( ; fId != faceIdSet.rend(); ++fId ) { + // get face surface and submesh + Handle(Geom_Surface) surface; + SMESHDS_SubMesh* faceSubMesh = 0; + TopoDS_Face face; + double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l; + double u1 = 0, u2 = 0, v1 = 0, v2 = 0; + bool isUPeriodic = false, isVPeriodic = false; + if ( *fId ) { + face = TopoDS::Face( aMesh->IndexToShape( *fId )); + surface = BRep_Tool::Surface( face ); + faceSubMesh = aMesh->MeshElements( *fId ); + fToler2 = BRep_Tool::Tolerance( face ); + fToler2 *= fToler2 * 10.; + isUPeriodic = surface->IsUPeriodic(); + if ( isUPeriodic ) + vPeriod = surface->UPeriod(); + isVPeriodic = surface->IsVPeriodic(); + if ( isVPeriodic ) + uPeriod = surface->VPeriod(); + surface->Bounds( u1, u2, v1, v2 ); + } + // --------------------------------------------------------- + // for elements on a face, find movable and fixed nodes and + // compute UV for them + // --------------------------------------------------------- + bool checkBoundaryNodes = false; + bool isQuadratic = false; + set setMovableNodes; + map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2; + list< gp_XY > listUV; // uvs the 2 uvMaps refer to + list< const SMDS_MeshElement* > elemsOnFace; + + Extrema_GenExtPS projector; + GeomAdaptor_Surface surfAdaptor; + if ( !surface.IsNull() ) { + surfAdaptor.Load( surface ); + projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 ); + } + int nbElemOnFace = 0; + itElem = theElems.begin(); + // loop on not yet smoothed elements: look for elems on a face + while ( itElem != theElems.end() ) { + if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() ) + break; // all elements found + + const SMDS_MeshElement* elem = (*itElem).second; + if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 || + ( faceSubMesh && !faceSubMesh->Contains( elem ))) { + ++itElem; + continue; + } + elemsOnFace.push_back( elem ); + theElems.erase( itElem++ ); + nbElemOnFace++; - set setMovableNodes; - - // Fill setMovableNodes - - map< const SMDS_MeshNode*, int > mapNodeNbFaces; - set< const SMDS_MeshElement* >::iterator itElem; - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) - { - const SMDS_MeshElement* elem = (*itElem); - if ( !elem || elem->GetType() != SMDSAbs_Face ) - continue; + if ( !isQuadratic ) + isQuadratic = elem->IsQuadratic(); - SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) { - const SMDS_MeshNode* node = - static_cast( itN->next() ); + // get movable nodes of elem + const SMDS_MeshNode* node; + SMDS_TypeOfPosition posType; + SMDS_ElemIteratorPtr itN = elem->nodesIterator(); + int nn = 0, nbn = elem->NbNodes(); + if(elem->IsQuadratic()) + nbn = nbn/2; + while ( nn++ < nbn ) { + node = static_cast( itN->next() ); + const SMDS_PositionPtr& pos = node->GetPosition(); + posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE; + if (posType != SMDS_TOP_EDGE && + posType != SMDS_TOP_VERTEX && + theFixedNodes.find( node ) == theFixedNodes.end()) + { + // check if all faces around the node are on faceSubMesh + // because a node on edge may be bound to face + SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(); + bool all = true; + if ( faceSubMesh ) { + while ( eIt->more() && all ) { + const SMDS_MeshElement* e = eIt->next(); + if ( e->GetType() == SMDSAbs_Face ) + all = faceSubMesh->Contains( e ); + } + } + if ( all ) + setMovableNodes.insert( node ); + else + checkBoundaryNodes = true; + } + if ( posType == SMDS_TOP_3DSPACE ) + checkBoundaryNodes = true; + } - if ( theFixedNodes.find( node ) != theFixedNodes.end() ) + if ( surface.IsNull() ) continue; - // if node is on edge => it is fixed - SMDS_PositionPtr aPositionPtr = node->GetPosition(); - if ( aPositionPtr.get() && - (aPositionPtr->GetTypeOfPosition() == SMDS_TOP_EDGE || - aPositionPtr->GetTypeOfPosition() == SMDS_TOP_VERTEX)) { - theFixedNodes.insert( node ); - continue; + // get nodes to check UV + list< const SMDS_MeshNode* > uvCheckNodes; + itN = elem->nodesIterator(); + nn = 0; nbn = elem->NbNodes(); + if(elem->IsQuadratic()) + nbn = nbn/2; + while ( nn++ < nbn ) { + node = static_cast( itN->next() ); + if ( uvMap.find( node ) == uvMap.end() ) + uvCheckNodes.push_back( node ); + // add nodes of elems sharing node +// SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(); +// while ( eIt->more() ) { +// const SMDS_MeshElement* e = eIt->next(); +// if ( e != elem && e->GetType() == SMDSAbs_Face ) { +// SMDS_ElemIteratorPtr nIt = e->nodesIterator(); +// while ( nIt->more() ) { +// const SMDS_MeshNode* n = +// static_cast( nIt->next() ); +// if ( uvMap.find( n ) == uvMap.end() ) +// uvCheckNodes.push_back( n ); +// } +// } +// } + } + // check UV on face + list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin(); + for ( ; n != uvCheckNodes.end(); ++n ) { + node = *n; + gp_XY uv( 0, 0 ); + const SMDS_PositionPtr& pos = node->GetPosition(); + posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE; + // get existing UV + switch ( posType ) { + case SMDS_TOP_FACE: { + SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get(); + uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() ); + break; + } + case SMDS_TOP_EDGE: { + TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() ); + Handle(Geom2d_Curve) pcurve; + if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE ) + pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l ); + if ( !pcurve.IsNull() ) { + double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter(); + uv = pcurve->Value( u ).XY(); + } + break; + } + case SMDS_TOP_VERTEX: { + TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() ); + if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX ) + uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY(); + break; + } + default:; + } + // check existing UV + bool project = true; + gp_Pnt pNode ( node->X(), node->Y(), node->Z() ); + double dist1 = DBL_MAX, dist2 = 0; + if ( posType != SMDS_TOP_3DSPACE ) { + dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() )); + project = dist1 > fToler2; + } + if ( project ) { // compute new UV + gp_XY newUV; + if ( !getClosestUV( projector, pNode, newUV )) { + MESSAGE("Node Projection Failed " << node); + } + else { + if ( isUPeriodic ) + newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 )); + if ( isVPeriodic ) + newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 )); + // check new UV + if ( posType != SMDS_TOP_3DSPACE ) + dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() )); + if ( dist2 < dist1 ) + uv = newUV; + } + } + // store UV in the map + listUV.push_back( uv ); + uvMap.insert( make_pair( node, &listUV.back() )); + } + } // loop on not yet smoothed elements + + if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() ) + checkBoundaryNodes = true; + + // fix nodes on mesh boundary + + if ( checkBoundaryNodes ) { + typedef pair TLink; + map< TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace + map< TLink, int >::iterator link_nb; + // put all elements links to linkNbMap + list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin(); + for ( ; elemIt != elemsOnFace.end(); ++elemIt ) { + const SMDS_MeshElement* elem = (*elemIt); + int nbn = elem->NbNodes(); + if(elem->IsQuadratic()) + nbn = nbn/2; + // loop on elem links: insert them in linkNbMap + const SMDS_MeshNode* curNode, *prevNode = elem->GetNode( nbn ); + for ( int iN = 0; iN < nbn; ++iN ) { + curNode = elem->GetNode( iN ); + TLink link; + if ( curNode < prevNode ) link = make_pair( curNode , prevNode ); + else link = make_pair( prevNode , curNode ); + prevNode = curNode; + link_nb = linkNbMap.find( link ); + if ( link_nb == linkNbMap.end() ) + linkNbMap.insert( make_pair ( link, 1 )); + else + link_nb->second++; + } + } + // remove nodes that are in links encountered only once from setMovableNodes + for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) { + if ( link_nb->second == 1 ) { + setMovableNodes.erase( link_nb->first.first ); + setMovableNodes.erase( link_nb->first.second ); + } } - // fill mapNodeNbFaces in order to detect fixed boundary nodes - map::iterator nodeNbFacesIt = - mapNodeNbFaces.find ( node ); - if ( nodeNbFacesIt == mapNodeNbFaces.end() ) - mapNodeNbFaces.insert( map::value_type( node, 1 )); - else - (*nodeNbFacesIt).second++; } - } - // put not fixed nodes in setMovableNodes - map::iterator nodeNbFacesIt = - mapNodeNbFaces.begin(); - for ( ; nodeNbFacesIt != mapNodeNbFaces.end(); nodeNbFacesIt++ ) { - const SMDS_MeshNode* node = (*nodeNbFacesIt).first; - // a node is on free boundary if it is shared by 1-2 faces - if ( (*nodeNbFacesIt).second > 2 ) - setMovableNodes.insert( node ); - else - theFixedNodes.insert( node ); - } - - // SMOOTHING // - if ( theTgtAspectRatio < 1.0 ) - theTgtAspectRatio = 1.0; + // ----------------------------------------------------- + // for nodes on seam edge, compute one more UV ( uvMap2 ); + // find movable nodes linked to nodes on seam and which + // are to be smoothed using the second UV ( uvMap2 ) + // ----------------------------------------------------- + + set nodesNearSeam; // to smooth using uvMap2 + if ( !surface.IsNull() ) { + TopExp_Explorer eExp( face, TopAbs_EDGE ); + for ( ; eExp.More(); eExp.Next() ) { + TopoDS_Edge edge = TopoDS::Edge( eExp.Current() ); + if ( !BRep_Tool::IsClosed( edge, face )) + continue; + SMESHDS_SubMesh* sm = aMesh->MeshElements( edge ); + if ( !sm ) continue; + // find out which parameter varies for a node on seam + double f,l; + gp_Pnt2d uv1, uv2; + Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l ); + if ( pcurve.IsNull() ) continue; + uv1 = pcurve->Value( f ); + edge.Reverse(); + pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l ); + if ( pcurve.IsNull() ) continue; + uv2 = pcurve->Value( f ); + int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2; + // assure uv1 < uv2 + if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) { + gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp; + } + // get nodes on seam and its vertices + list< const SMDS_MeshNode* > seamNodes; + SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes(); + while ( nSeamIt->more() ) { + const SMDS_MeshNode* node = nSeamIt->next(); + if ( !isQuadratic || !IsMedium( node )) + seamNodes.push_back( node ); + } + TopExp_Explorer vExp( edge, TopAbs_VERTEX ); + for ( ; vExp.More(); vExp.Next() ) { + sm = aMesh->MeshElements( vExp.Current() ); + if ( sm ) { + nSeamIt = sm->GetNodes(); + while ( nSeamIt->more() ) + seamNodes.push_back( nSeamIt->next() ); + } + } + // loop on nodes on seam + list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin(); + for ( ; noSeIt != seamNodes.end(); ++noSeIt ) { + const SMDS_MeshNode* nSeam = *noSeIt; + map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam ); + if ( n_uv == uvMap.end() ) + continue; + // set the first UV + n_uv->second->SetCoord( iPar, uv1.Coord( iPar )); + // set the second UV + listUV.push_back( *n_uv->second ); + listUV.back().SetCoord( iPar, uv2.Coord( iPar )); + if ( uvMap2.empty() ) + uvMap2 = uvMap; // copy the uvMap contents + uvMap2[ nSeam ] = &listUV.back(); + + // collect movable nodes linked to ones on seam in nodesNearSeam + SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(); + while ( eIt->more() ) { + const SMDS_MeshElement* e = eIt->next(); + if ( e->GetType() != SMDSAbs_Face ) + continue; + int nbUseMap1 = 0, nbUseMap2 = 0; + SMDS_ElemIteratorPtr nIt = e->nodesIterator(); + int nn = 0, nbn = e->NbNodes(); + if(e->IsQuadratic()) nbn = nbn/2; + while ( nn++ < nbn ) + { + const SMDS_MeshNode* n = + static_cast( nIt->next() ); + if (n == nSeam || + setMovableNodes.find( n ) == setMovableNodes.end() ) + continue; + // add only nodes being closer to uv2 than to uv1 + gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ), + 0.5 * ( n->Y() + nSeam->Y() ), + 0.5 * ( n->Z() + nSeam->Z() )); + gp_XY uv; + getClosestUV( projector, pMid, uv ); + if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) { + nodesNearSeam.insert( n ); + nbUseMap2++; + } + else + nbUseMap1++; + } + // for centroidalSmooth all element nodes must + // be on one side of a seam + if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) { + SMDS_ElemIteratorPtr nIt = e->nodesIterator(); + nn = 0; + while ( nn++ < nbn ) { + const SMDS_MeshNode* n = + static_cast( nIt->next() ); + setMovableNodes.erase( n ); + } + } + } + } // loop on nodes on seam + } // loop on edge of a face + } // if ( !face.IsNull() ) - SMESH::Controls::AspectRatio aQualityFunc; + if ( setMovableNodes.empty() ) { + MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!"); + continue; // goto next face + } - for ( int it = 0; it < theNbIterations; it++ ) - { - Standard_Real maxDisplacement = 0.; - set::iterator movableNodesIt - = setMovableNodes.begin(); - for ( ; movableNodesIt != setMovableNodes.end(); movableNodesIt++ ) - { - const SMDS_MeshNode* node = (*movableNodesIt); - gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() ); + // ------------- + // SMOOTHING // + // ------------- + + int it = -1; + double maxRatio = -1., maxDisplacement = -1.; + set::iterator nodeToMove; + for ( it = 0; it < theNbIterations; it++ ) { + maxDisplacement = 0.; + nodeToMove = setMovableNodes.begin(); + for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) { + const SMDS_MeshNode* node = (*nodeToMove); + gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() ); + + // smooth + bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() ); + if ( theSmoothMethod == LAPLACIAN ) + laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap ); + else + centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap ); - // smooth - if ( theSmoothMethod == LAPLACIAN ) - laplacianSmooth( aMesh, node, theElems, theFixedNodes ); - else - centroidalSmooth( aMesh, node, theElems, theFixedNodes ); + // node displacement + gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() ); + Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus(); + if ( aDispl > maxDisplacement ) + maxDisplacement = aDispl; + } + // no node movement => exit + //if ( maxDisplacement < 1.e-16 ) { + if ( maxDisplacement < disttol ) { + MESSAGE("-- no node movement --"); + break; + } - // displacement - gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() ); - Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus(); - if ( aDispl > maxDisplacement ) - maxDisplacement = aDispl; - } - // no node movement => exit - if ( maxDisplacement < 1.e-16 ) { - MESSAGE("-- no node movement -- maxDisplacement: " << maxDisplacement << " it "<< it); - break; + // check elements quality + maxRatio = 0; + list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin(); + for ( ; elemIt != elemsOnFace.end(); ++elemIt ) { + const SMDS_MeshElement* elem = (*elemIt); + if ( !elem || elem->GetType() != SMDSAbs_Face ) + continue; + SMESH::Controls::TSequenceOfXYZ aPoints; + if ( aQualityFunc.GetPoints( elem, aPoints )) { + double aValue = aQualityFunc.GetValue( aPoints ); + if ( aValue > maxRatio ) + maxRatio = aValue; + } + } + if ( maxRatio <= theTgtAspectRatio ) { + MESSAGE("-- quality achived --"); + break; + } + if (it+1 == theNbIterations) { + MESSAGE("-- Iteration limit exceeded --"); + } + } // smoothing iterations + + MESSAGE(" Face id: " << *fId << + " Nb iterstions: " << it << + " Displacement: " << maxDisplacement << + " Aspect Ratio " << maxRatio); + + // --------------------------------------- + // new nodes positions are computed, + // record movement in DS and set new UV + // --------------------------------------- + nodeToMove = setMovableNodes.begin(); + for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) { + SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove); + aMesh->MoveNode( node, node->X(), node->Y(), node->Z() ); + map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node ); + if ( node_uv != uvMap.end() ) { + gp_XY* uv = node_uv->second; + node->SetPosition + ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() ))); + } } - // check elements quality - double maxRatio = 0; - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) + // move medium nodes of quadratic elements + if ( isQuadratic ) { - const SMDS_MeshElement* elem = (*itElem); - if ( !elem || elem->GetType() != SMDSAbs_Face ) - continue; - SMESH::Controls::TSequenceOfXYZ aPoints; - if ( aQualityFunc.GetPoints( elem, aPoints )) { - double aValue = aQualityFunc.GetValue( aPoints ); - if ( aValue > maxRatio ) - maxRatio = aValue; + SMESH_MesherHelper helper( *GetMesh() ); + if ( !face.IsNull() ) + helper.SetSubShape( face ); + list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin(); + for ( ; elemIt != elemsOnFace.end(); ++elemIt ) { + const SMDS_QuadraticFaceOfNodes* QF = + dynamic_cast (*elemIt); + if(QF) { + vector Ns; + Ns.reserve(QF->NbNodes()+1); + SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator(); + while ( anIter->more() ) + Ns.push_back( anIter->next() ); + Ns.push_back( Ns[0] ); + double x, y, z; + for(int i=0; iNbNodes(); i=i+2) { + if ( !surface.IsNull() ) { + gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] ); + gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] ); + gp_XY uv = ( uv1 + uv2 ) / 2.; + gp_Pnt xyz = surface->Value( uv.X(), uv.Y() ); + x = xyz.X(); y = xyz.Y(); z = xyz.Z(); + } + else { + x = (Ns[i]->X() + Ns[i+2]->X())/2; + y = (Ns[i]->Y() + Ns[i+2]->Y())/2; + z = (Ns[i]->Z() + Ns[i+2]->Z())/2; + } + if( fabs( Ns[i+1]->X() - x ) > disttol || + fabs( Ns[i+1]->Y() - y ) > disttol || + fabs( Ns[i+1]->Z() - z ) > disttol ) { + // we have to move i+1 node + aMesh->MoveNode( Ns[i+1], x, y, z ); + } + } + } } } - if ( maxRatio <= theTgtAspectRatio ) { - MESSAGE("-- quality achived -- maxRatio " << maxRatio << " it "<< it); - break; - } - if (it+1 == theNbIterations) { - MESSAGE("-- Iteration limit exceeded --"); - } - } + + } // loop on face ids + } //======================================================================= @@ -1523,38 +2610,58 @@ static bool isReverse(const SMDS_MeshNode* prevNodes[], static void sweepElement(SMESHDS_Mesh* aMesh, const SMDS_MeshElement* elem, const vector & newNodesItVec, - list& newElems) + list& newElems, + const int nbSteps, + SMESH_SequenceOfElemPtr& myLastCreatedElems) { // Loop on elem nodes: // find new nodes and detect same nodes indices int nbNodes = elem->NbNodes(); list::const_iterator itNN[ nbNodes ]; - const SMDS_MeshNode* prevNod[ nbNodes ], *nextNod[ nbNodes ]; + const SMDS_MeshNode* prevNod[ nbNodes ], *nextNod[ nbNodes ], *midlNod[ nbNodes ]; int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0; + vector sames(nbNodes); - for ( iNode = 0; iNode < nbNodes; iNode++ ) - { + bool issimple[nbNodes]; + + for ( iNode = 0; iNode < nbNodes; iNode++ ) { TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ]; const SMDS_MeshNode* node = nnIt->first; const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second; if ( listNewNodes.empty() ) return; + if(listNewNodes.size()==nbSteps) { + issimple[iNode] = true; + } + else { + issimple[iNode] = false; + } + itNN[ iNode ] = listNewNodes.begin(); prevNod[ iNode ] = node; nextNod[ iNode ] = listNewNodes.front(); +//cout<<"iNode="<GetID() ); return; } +// if( elem->IsQuadratic() && nbSame>0 ) { +// MESSAGE( "Can not rotate quadratic element " << elem->GetID() ); +// return; +// } + int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0; if ( nbSame > 0 ) { iBeforeSame = ( iSameNode == 0 ? nbNodes - 1 : iSameNode - 1 ); @@ -1562,6 +2669,12 @@ static void sweepElement(SMESHDS_Mesh* aMesh, iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 ); } +//if(nbNodes==8) +//cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1] +// <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4] +// <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5] +// <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]< 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) { @@ -1576,84 +2689,224 @@ static void sweepElement(SMESHDS_Mesh* aMesh, } // make new elements - int iStep, nbSteps = newNodesItVec[ 0 ]->second.size(); - for (iStep = 0; iStep < nbSteps; iStep++ ) - { + int iStep;//, nbSteps = newNodesItVec[ 0 ]->second.size(); + for (iStep = 0; iStep < nbSteps; iStep++ ) { // get next nodes for ( iNode = 0; iNode < nbNodes; iNode++ ) { - nextNod[ iNode ] = *itNN[ iNode ]; - itNN[ 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() || + elem->IsQuadratic() && elem->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 ]++; + } + } } SMDS_MeshElement* aNewElem = 0; - switch ( nbNodes ) - { - case 1: { // NODE - if ( nbSame == 0 ) - aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] ); - break; - } - case 2: { // EDGE + if(!elem->IsPoly()) { + switch ( nbNodes ) { + case 0: + return; + case 1: { // NODE + if ( nbSame == 0 ) { + if(issimple[0]) + aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] ); + else + aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] ); + } + 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 ] ); + break; + } - if ( nbSame == 0 ) - aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ], - nextNod[ 1 ], nextNod[ 0 ] ); - else - aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ], - nextNod[ iNotSameNode ] ); - 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 ], + nextNod[ iSameNode ]); + + else // 2 same nodes: --- tetrahedron + aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], + nextNod[ iNotSameNode ]); + } + 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 + 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 + return; + } + break; + } + case 4: { // QUADRANGLE + + if ( nbSame == 0 ) // --- hexahedron + aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ], + nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]); + + 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 ], + nextNod[ iOpposSame ], nextNod[ iBeforeSame ] ); + } + 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 ], + prevNod[ iAfterSame ], nextNod[ iAfterSame ]); + else + // iAfterSame is same too + 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 + 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]); + } + break; + } + case 8: { // quadratic quadrangle + // 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]); + } + 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); + break; + } + } } - case 3: { // TRIANGLE - if ( nbSame == 0 ) // --- pentahedron - aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], - nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] ); + if(!aNewElem) { + // realized for extrusion only + vector polyedre_nodes (nbNodes*2 + 4*nbNodes); + vector quantities (nbNodes + 2); - else if ( nbSame == 1 ) // --- pyramid - aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iBeforeSame ], - nextNod[ iBeforeSame ], nextNod[ iAfterSame ], - nextNod[ iSameNode ]); - - else // 2 same nodes: --- tetrahedron - aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], - nextNod[ iNotSameNode ]); - break; - } - case 4: { // QUADRANGLE + quantities[0] = nbNodes; // bottom of prism + for (int inode = 0; inode < nbNodes; inode++) { + polyedre_nodes[inode] = prevNod[inode]; + } - if ( nbSame == 0 ) // --- hexahedron - aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ], - nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]); + quantities[1] = nbNodes; // top of prism + for (int inode = 0; inode < nbNodes; inode++) { + polyedre_nodes[nbNodes + inode] = nextNod[inode]; + } - else if ( nbSame == 1 ) // --- pyramid + pentahedron - { - aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iBeforeSame ], - nextNod[ iBeforeSame ], nextNod[ iAfterSame ], - nextNod[ iSameNode ]); - newElems.push_back( aNewElem ); - aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ], - prevNod[ iAfterSame ], nextNod[ iBeforeSame ], - nextNod[ iOpposSame ], nextNod[ iAfterSame ] ); - } - else if ( nbSame == 2 ) // pentahedron - { - if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) - // iBeforeSame is same too - aNewElem = aMesh->AddVolume (prevNod[ iOpposSame ], prevNod[ iBeforeSame ], - nextNod[ iOpposSame ], prevNod[ iAfterSame ], - prevNod[ iSameNode ], nextNod[ iAfterSame ]); - else - // iAfterSame is same too - aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iSameNode ], - nextNod[ iBeforeSame ], prevNod[ iOpposSame ], - prevNod[ iAfterSame ], nextNod[ iOpposSame ]); + 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]; } - break; - } - default: - return; + aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities); } - if ( aNewElem ) + + if ( aNewElem ) { newElems.push_back( aNewElem ); + myLastCreatedElems.Append(aNewElem); + } // set new prev nodes for ( iNode = 0; iNode < nbNodes; iNode++ ) @@ -1671,90 +2924,145 @@ static void makeWalls (SMESHDS_Mesh* aMesh, TNodeOfNodeListMap & mapNewNodes, TElemOfElemListMap & newElemsMap, TElemOfVecOfNnlmiMap & elemNewNodesMap, - set& elemSet) + map& elemSet, + const int nbSteps, + SMESH_SequenceOfElemPtr& myLastCreatedElems) { ASSERT( newElemsMap.size() == elemNewNodesMap.size() ); // 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 ); SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(); int nbInitElems = 0; - while ( eIt->more() && nbInitElems < 2 ) - if ( elemSet.find( eIt->next() ) != elemSet.end() ) + const SMDS_MeshElement* el = 0; + SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only + while ( eIt->more() && nbInitElems < 2 ) { + el = eIt->next(); + SMDSAbs_ElementType type = el->GetType(); + if ( type == SMDSAbs_Volume || type < highType ) continue; + if ( type > highType ) { + nbInitElems = 0; + highType = type; + } + if ( elemSet.find(el->GetID()) != elemSet.end() ) nbInitElems++; + } if ( nbInitElems < 2 ) { - vector newNodesItVec( 1, nList ); - list newEdges; - sweepElement( aMesh, node, newNodesItVec, newEdges ); + bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node); + if(!NotCreateEdge) { + vector newNodesItVec( 1, nList ); + list newEdges; + sweepElement( aMesh, node, newNodesItVec, newEdges, nbSteps, myLastCreatedElems ); + } } } // Make a ceiling for each element ie an equal element of last new nodes. // Find free links of faces - make edges and sweep them into faces. - + 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 ( elem->GetType() == SMDSAbs_Edge ) - { + if ( elem->GetType() == SMDSAbs_Edge ) { // create a ceiling edge - aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(), - vecNewNodes[ 1 ]->second.back() ); + if (!elem->IsQuadratic()) { + if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(), + vecNewNodes[ 1 ]->second.back())) + myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(), + vecNewNodes[ 1 ]->second.back())); + } + else { + if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(), + vecNewNodes[ 1 ]->second.back(), + vecNewNodes[ 2 ]->second.back())) + myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(), + vecNewNodes[ 1 ]->second.back(), + vecNewNodes[ 2 ]->second.back())); + } } if ( elem->GetType() != SMDSAbs_Face ) continue; + if(itElem->second.size()==0) continue; + bool hasFreeLinks = false; - set avoidSet; - avoidSet.insert( elem ); + map avoidSet; + avoidSet.insert( make_pair(elem->GetID(),elem) ); - // loop on a face nodes set aFaceLastNodes; int iNode, nbNodes = vecNewNodes.size(); - for ( iNode = 0; iNode < nbNodes; iNode++ ) - { - aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() ); - // look for free links of a face - int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1; - const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first; - const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first; - // check if a link is free - if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) - { - hasFreeLinks = true; - // make an edge and a ceiling for a new edge - if ( !aMesh->FindEdge( n1, n2 )) - aMesh->AddEdge( n1, n2 ); - n1 = vecNewNodes[ iNode ]->second.back(); - n2 = vecNewNodes[ iNext ]->second.back(); - if ( !aMesh->FindEdge( n1, n2 )) - aMesh->AddEdge( n1, n2 ); + if(!elem->IsQuadratic()) { + // loop on the face nodes + for ( iNode = 0; iNode < nbNodes; iNode++ ) { + aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() ); + // look for free links of the face + int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1; + const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first; + const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first; + // check if a link is free + if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) { + hasFreeLinks = true; + // make an edge and a ceiling for a new edge + if ( !aMesh->FindEdge( n1, n2 )) { + myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); + } + n1 = vecNewNodes[ iNode ]->second.back(); + n2 = vecNewNodes[ iNext ]->second.back(); + if ( !aMesh->FindEdge( n1, n2 )) { + myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); + } + } + } + } + else { // elem is quadratic face + int nbn = nbNodes/2; + for ( iNode = 0; iNode < nbn; iNode++ ) { + aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() ); + int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1; + const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first; + const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first; + // check if a link is free + if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, 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 )); + } + n1 = vecNewNodes[ iNode ]->second.back(); + n2 = vecNewNodes[ iNext ]->second.back(); + n3 = vecNewNodes[ iNode+nbn ]->second.back(); + if ( !aMesh->FindEdge( n1, n2, n3 )) { + myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); + } + } + } + for ( iNode = nbn; iNode < 2*nbn; iNode++ ) { + aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() ); } } + // sweep free links into faces - if ( hasFreeLinks ) - { + if ( hasFreeLinks ) { list & newVolumes = itElem->second; - int iStep, nbSteps = vecNewNodes[0]->second.size(); + int iStep; //, nbSteps = vecNewNodes[0]->second.size(); int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps; set initNodeSet, faceNodeSet; for ( iNode = 0; iNode < nbNodes; iNode++ ) initNodeSet.insert( vecNewNodes[ iNode ]->first ); - for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) - { + for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) { list::iterator v = newVolumes.begin(); iVol = 0; while ( iVol++ < volNb ) v++; @@ -1762,28 +3070,70 @@ static void makeWalls (SMESHDS_Mesh* aMesh, list< int > fInd; SMDS_VolumeTool vTool( *v ); int iF, nbF = vTool.NbFaces(); - for ( iF = 0; iF < nbF; iF ++ ) + for ( iF = 0; iF < nbF; iF ++ ) { if (vTool.IsFreeFace( iF ) && vTool.GetFaceNodes( iF, faceNodeSet ) && initNodeSet != faceNodeSet) // except an initial face fInd.push_back( iF ); + } if ( fInd.empty() ) continue; // create faces for all steps - for ( iStep = 0; iStep < nbSteps; iStep++ ) - { + // if such a face has been already created by sweep of edge, assure that its orientation is OK + for ( iStep = 0; iStep < nbSteps; iStep++ ) { vTool.Set( *v ); vTool.SetExternalNormal(); list< int >::iterator ind = fInd.begin(); - for ( ; ind != fInd.end(); ind++ ) - { + for ( ; ind != fInd.end(); ind++ ) { const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind ); - switch ( vTool.NbFaceNodes( *ind ) ) { - case 3: - aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ); break; - case 4: - aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ); break; + int nbn = vTool.NbFaceNodes( *ind ); + switch ( nbn ) { + case 3: { ///// triangle + const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]); + if ( !f ) + myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] )); + else if ( nodes[ 1 ] != f->GetNode( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) + aMesh->ChangeElementNodes( f, nodes, nbn ); + break; + } + case 4: { ///// quadrangle + const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]); + if ( !f ) + myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] )); + else if ( nodes[ 1 ] != f->GetNode( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) + aMesh->ChangeElementNodes( f, nodes, nbn ); + break; + } + default: + if( (*v)->IsQuadratic() ) { + if(nbn==6) { /////// quadratic triangle + const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], + nodes[1], nodes[3], nodes[5] ); + if ( !f ) + myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], + nodes[1], nodes[3], nodes[5])); + else if ( nodes[ 2 ] != f->GetNode( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) + aMesh->ChangeElementNodes( f, nodes, nbn ); + } + else { /////// 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 ) + myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6], + nodes[1], nodes[3], nodes[5], nodes[7])); + else if ( nodes[ 2 ] != f->GetNode( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) + aMesh->ChangeElementNodes( f, nodes, nbn ); + } + } + else { //////// polygon + vector polygon_nodes ( nodes, &nodes[nbn] ); + const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes ); + if ( !f ) + myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes)); + else if ( nodes[ 1 ] != f->GetNode( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) + aMesh->ChangeElementNodes( f, nodes, nbn ); + } } } // go to the next volume @@ -1794,44 +3144,72 @@ static void makeWalls (SMESHDS_Mesh* aMesh, } // sweep free links into faces // make a ceiling face with a normal external to a volume - + SMDS_VolumeTool lastVol( itElem->second.back() ); + int iF = lastVol.GetFaceIndex( aFaceLastNodes ); - if ( iF >= 0 ) - { + if ( iF >= 0 ) { lastVol.SetExternalNormal(); const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF ); - switch ( lastVol.NbFaceNodes( iF ) ) { + int nbn = lastVol.NbFaceNodes( iF ); + switch ( nbn ) { case 3: if (!hasFreeLinks || !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ])) - aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ); + myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] )); break; case 4: if (!hasFreeLinks || !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ])) - aMesh->AddFace( 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 } - } // loop on swept elements } //======================================================================= //function : RotationSweep -//purpose : +//purpose : //======================================================================= -void SMESH_MeshEditor::RotationSweep(set & theElems, +void SMESH_MeshEditor::RotationSweep(map & theElems, const gp_Ax1& theAxis, const double theAngle, const int theNbSteps, const double theTol) { + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + MESSAGE( "RotationSweep()"); gp_Trsf aTrsf; aTrsf.SetRotation( theAxis, theAngle ); + gp_Trsf aTrsf2; + aTrsf2.SetRotation( theAxis, theAngle/2. ); gp_Lin aLine( theAxis ); double aSqTol = theTol * theTol; @@ -1843,10 +3221,9 @@ void SMESH_MeshEditor::RotationSweep(set & theElems, TElemOfElemListMap newElemsMap; // loop on theElems - set< const SMDS_MeshElement* >::iterator itElem; - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) - { - const SMDS_MeshElement* elem = (*itElem); + map::iterator itElem; + for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { + const SMDS_MeshElement* elem = (*itElem).second; if ( !elem ) continue; vector & newNodesItVec = mapElemNewNodes[ elem ]; @@ -1860,8 +3237,7 @@ void SMESH_MeshEditor::RotationSweep(set & theElems, const SMDS_MeshNode* node = static_cast( itN->next() ); TNodeOfNodeListMapItr nIt = mapNewNodes.find( node ); - if ( nIt == mapNewNodes.end() ) - { + if ( nIt == mapNewNodes.end() ) { nIt = mapNewNodes.insert( make_pair( node, list() )).first; list& listNewNodes = nIt->second; @@ -1873,49 +3249,165 @@ void SMESH_MeshEditor::RotationSweep(set & theElems, const SMDS_MeshNode * newNode = node; for ( int i = 0; i < theNbSteps; i++ ) { if ( !isOnAxis ) { - aTrsf.Transforms( coord[0], coord[1], coord[2] ); + if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) { + // create two nodes + 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); + 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] ); + } newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); + myLastCreatedNodes.Append(newNode); } 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; + for(int i = 0; iAddNode( coord[0], coord[1], coord[2] ); + myLastCreatedNodes.Append(newNode); + listNewNodes.push_back( newNode ); + aTrsf2.Transforms( coord[0], coord[1], coord[2] ); + newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); + myLastCreatedNodes.Append(newNode); + listNewNodes.push_back( newNode ); + } + } + } + } newNodesItVec.push_back( nIt ); } // make new elements - sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem] ); + sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem], theNbSteps, myLastCreatedElems ); } - makeWalls( aMesh, mapNewNodes, newElemsMap, mapElemNewNodes, theElems ); + makeWalls( aMesh, mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, myLastCreatedElems ); } + + //======================================================================= -//function : ExtrusionSweep +//function : CreateNode //purpose : //======================================================================= +const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x, + const double y, + const double z, + const double tolnode, + SMESH_SequenceOfNode& aNodes) +{ + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + + gp_Pnt P1(x,y,z); + SMESHDS_Mesh * aMesh = myMesh->GetMeshDS(); + + // try to search in sequence of existing nodes + // if aNodes.Length()>0 we 'nave to use given sequence + // else - use all nodes of mesh + if(aNodes.Length()>0) { + int i; + for(i=1; i<=aNodes.Length(); i++) { + gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z()); + if(P1.Distance(P2)nodesIterator(); + while(itn->more()) { + const SMDS_MeshNode* aN = static_cast (itn->next()); + gp_Pnt P2(aN->X(),aN->Y(),aN->Z()); + if(P1.Distance(P2)AddNode(x,y,z); + myLastCreatedNodes.Append(NewNode); + return NewNode; +} + + +//======================================================================= +//function : ExtrusionSweep +//purpose : +//======================================================================= -void SMESH_MeshEditor::ExtrusionSweep(set & theElems, - const gp_Vec& theStep, - const int theNbSteps) +void SMESH_MeshEditor::ExtrusionSweep + (map & theElems, + const gp_Vec& theStep, + const int theNbSteps, + TElemOfElemListMap& newElemsMap, + const int theFlags, + const double theTolerance) { - gp_Trsf aTrsf; - aTrsf.SetTranslation( theStep ); + ExtrusParam aParams; + aParams.myDir = gp_Dir(theStep); + aParams.myNodes.Clear(); + aParams.mySteps = new TColStd_HSequenceOfReal; + int i; + for(i=1; i<=theNbSteps; i++) + aParams.mySteps->Append(theStep.Magnitude()); + + ExtrusionSweep(theElems,aParams,newElemsMap,theFlags,theTolerance); + +} + + +//======================================================================= +//function : ExtrusionSweep +//purpose : +//======================================================================= + +void SMESH_MeshEditor::ExtrusionSweep + (map & theElems, + ExtrusParam& theParams, + TElemOfElemListMap& newElemsMap, + const int theFlags, + const double theTolerance) +{ + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); SMESHDS_Mesh* aMesh = GetMeshDS(); + int nbsteps = theParams.mySteps->Length(); + TNodeOfNodeListMap mapNewNodes; + //TNodeOfNodeVecMap mapNewNodes; TElemOfVecOfNnlmiMap mapElemNewNodes; - TElemOfElemListMap newElemsMap; + //TElemOfVecOfMapNodesMap mapElemNewNodes; // loop on theElems - set< const SMDS_MeshElement* >::iterator itElem; - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) - { + map::iterator itElem; + for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { // check element type - const SMDS_MeshElement* elem = (*itElem); + const SMDS_MeshElement* elem = (*itElem).second; if ( !elem ) continue; vector & newNodesItVec = mapElemNewNodes[ elem ]; + //vector & newNodesItVec = mapElemNewNodes[ elem ]; newNodesItVec.reserve( elem->NbNodes() ); // loop on elem nodes @@ -1926,30 +3418,106 @@ void SMESH_MeshEditor::ExtrusionSweep(set & theElems, const SMDS_MeshNode* node = static_cast( itN->next() ); TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node ); - if ( nIt == mapNewNodes.end() ) - { + //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); // make new nodes double coord[] = { node->X(), node->Y(), node->Z() }; - for ( int i = 0; i < theNbSteps; i++ ) { - aTrsf.Transforms( coord[0], coord[1], coord[2] ); - const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); - listNewNodes.push_back( newNode ); + //int nbsteps = theParams.mySteps->Length(); + for ( int i = 0; i < nbsteps; i++ ) { + if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) { + // create additional 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.; + 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); + listNewNodes.push_back( newNode ); + } + } + //aTrsf.Transforms( coord[0], coord[1], coord[2] ); + 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 ); + //vecNewNodes[i]=newNode; + } + else { + const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); + myLastCreatedNodes.Append(newNode); + 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); + 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); + listNewNodes.push_back( newNode ); + } + } + } } } newNodesItVec.push_back( nIt ); } // make new elements - sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem] ); + sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem], nbsteps, myLastCreatedElems ); + } + + if( theFlags & EXTRUSION_FLAG_BOUNDARY ) { + makeWalls( aMesh, mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, myLastCreatedElems ); } - makeWalls( aMesh, mapNewNodes, newElemsMap, mapElemNewNodes, theElems ); } + //======================================================================= //class : SMESH_MeshEditor_PathPoint -//purpose : auxiliary class +//purpose : auxiliary class //======================================================================= class SMESH_MeshEditor_PathPoint { public: @@ -1993,10 +3561,10 @@ protected: //======================================================================= //function : ExtrusionAlongTrack -//purpose : +//purpose : //======================================================================= -SMESH_MeshEditor::Extrusion_Error - SMESH_MeshEditor::ExtrusionAlongTrack (std::set & theElements, +SMESH_MeshEditor::Extrusion_Error + SMESH_MeshEditor::ExtrusionAlongTrack (std::map & theElements, SMESH_subMesh* theTrack, const SMDS_MeshNode* theN1, const bool theHasAngles, @@ -2004,12 +3572,15 @@ SMESH_MeshEditor::Extrusion_Error const bool theHasRefPoint, const gp_Pnt& theRefPoint) { + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + MESSAGE("SMESH_MeshEditor::ExtrusionAlongTrack") int j, aNbTP, aNbE, aNb; double aT1, aT2, aT, aAngle, aX, aY, aZ; std::list aPrms; std::list::iterator aItD; - std::set< const SMDS_MeshElement* >::iterator itElem; + std::map::iterator itElem; Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2; gp_Pnt aP3D, aV0; @@ -2070,7 +3641,7 @@ SMESH_MeshEditor::Extrusion_Error aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes(); const SMDS_MeshNode* aN2 = aItN->next(); - // starting node must be aN1 or aN2 + // starting node must be aN1 or aN2 if ( !( aN1 == theN1 || aN2 == theN1 ) ) return EXTR_BAD_STARTING_NODE; @@ -2082,16 +3653,16 @@ SMESH_MeshEditor::Extrusion_Error for ( j=0; j < aNbTP; ++j ) { aAngles[j] = 0.; } - + if ( theHasAngles ) { aItD = theAngles.begin(); - for ( j=0; (aItD != theAngles.end()) && (jnodesIterator(); while ( itN->more() ) { @@ -2178,7 +3749,7 @@ SMESH_MeshEditor::Extrusion_Error for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) { // check element type - const SMDS_MeshElement* elem = (*itElem); + const SMDS_MeshElement* elem = (*itElem).second; aTypeE = elem->GetType(); if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) ) continue; @@ -2191,16 +3762,16 @@ SMESH_MeshEditor::Extrusion_Error while ( itN->more() ) { // check if a node has been already processed - const SMDS_MeshNode* node = + const SMDS_MeshNode* node = static_cast( itN->next() ); TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node ); if ( nIt == mapNewNodes.end() ) { nIt = mapNewNodes.insert( make_pair( node, list() )).first; list& listNewNodes = nIt->second; - + // make new nodes aX = node->X(); aY = node->Y(); aZ = node->Z(); - + Standard_Real aAngle1x, aAngleT1T0, aTolAng; gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x; gp_Ax1 anAx1, anAxT1T0; @@ -2220,16 +3791,16 @@ SMESH_MeshEditor::Extrusion_Error aP1x = aPP1.Pnt(); aDT1x = aPP1.Tangent(); aAngle1x = aPP1.Angle(); - - gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0; + + gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0; // Translation gp_Vec aV01x( aP0x, aP1x ); aTrsf.SetTranslation( aV01x ); - + // traslated point aV1x = aV0x.Transformed( aTrsf ); aPN1 = aPN0.Transformed( aTrsf ); - + // rotation 1 [ T1,T0 ] aAngleT1T0=-aDT1x.Angle( aDT0x ); if (fabs(aAngleT1T0) > aTolAng) { @@ -2237,7 +3808,7 @@ SMESH_MeshEditor::Extrusion_Error anAxT1T0.SetLocation( aV1x ); anAxT1T0.SetDirection( aDT1T0 ); aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 ); - + aPN1 = aPN1.Transformed( aTrsfRotT1T0 ); } @@ -2246,43 +3817,90 @@ SMESH_MeshEditor::Extrusion_Error anAx1.SetLocation( aV1x ); anAx1.SetDirection( aDT1x ); aTrsfRot.SetRotation( anAx1, aAngle1x ); - + aPN1 = aPN1.Transformed( aTrsfRot ); } // make new node + if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) { + // create additional node + double x = ( aPN1.X() + aPN0.X() )/2.; + double y = ( aPN1.Y() + aPN0.Y() )/2.; + double z = ( aPN1.Z() + aPN0.Z() )/2.; + const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z); + myLastCreatedNodes.Append(newNode); + listNewNodes.push_back( newNode ); + } aX = aPN1.X(); aY = aPN1.Y(); aZ = aPN1.Z(); const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ ); + myLastCreatedNodes.Append(newNode); listNewNodes.push_back( newNode ); - + aPN0 = aPN1; aP0x = aP1x; aV0x = aV1x; aDT0x = aDT1x; } } + + 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()==aNbTP-1) { + vector aNodes(2*(aNbTP-1)); + gp_XYZ P(node->X(), node->Y(), node->Z()); + list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin(); + int i; + for(i=0; iX() + P.X() )/2.; + double y = ( N->Y() + P.Y() )/2.; + double z = ( N->Z() + P.Z() )/2.; + const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z); + myLastCreatedNodes.Append(newN); + aNodes[2*i] = newN; + aNodes[2*i+1] = N; + P = gp_XYZ(N->X(),N->Y(),N->Z()); + } + listNewNodes.clear(); + for(i=0; i<2*(aNbTP-1); i++) { + listNewNodes.push_back(aNodes[i]); + } + } + } + } + newNodesItVec.push_back( nIt ); } // make new elements - sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem] ); + //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem], + // newNodesItVec[0]->second.size(), myLastCreatedElems ); + sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem], + aNbTP-1, myLastCreatedElems ); } - - makeWalls( aMesh, mapNewNodes, newElemsMap, mapElemNewNodes, theElements ); + + makeWalls( aMesh, mapNewNodes, newElemsMap, mapElemNewNodes, theElements, + aNbTP-1, myLastCreatedElems ); return EXTR_OK; } //======================================================================= //function : Transform -//purpose : +//purpose : //======================================================================= -void SMESH_MeshEditor::Transform (set & theElems, +void SMESH_MeshEditor::Transform (map & theElems, const gp_Trsf& theTrsf, const bool theCopy) { + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + bool needReverse; switch ( theTrsf.Form() ) { case gp_PntMirror: @@ -2300,13 +3918,12 @@ void SMESH_MeshEditor::Transform (set & theElems, // elements sharing moved nodes; those of them which have all // nodes mirrored but are not in theElems are to be reversed - set inverseElemSet; + map inverseElemSet; // loop on theElems - set< const SMDS_MeshElement* >::iterator itElem; - for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) - { - const SMDS_MeshElement* elem = (*itElem); + map::iterator itElem; + for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { + const SMDS_MeshElement* elem = (*itElem).second; if ( !elem ) continue; @@ -2314,11 +3931,11 @@ void SMESH_MeshEditor::Transform (set & theElems, SMDS_ElemIteratorPtr itN = elem->nodesIterator(); while ( itN->more() ) { - // check if a node has been already transormed + // check if a node has been already transformed const SMDS_MeshNode* node = static_cast( itN->next() ); if (nodeMap.find( node ) != nodeMap.end() ) - continue; + continue; double coord[3]; coord[0] = node->X(); @@ -2326,17 +3943,25 @@ void SMESH_MeshEditor::Transform (set & theElems, coord[2] = node->Z(); theTrsf.Transforms( coord[0], coord[1], coord[2] ); const SMDS_MeshNode * newNode = node; - if ( theCopy ) + if ( theCopy ) { newNode = aMesh->AddNode( coord[0], coord[1], coord[2] ); - else + myLastCreatedNodes.Append(newNode); + } + else { aMesh->MoveNode( node, coord[0], coord[1], coord[2] ); + // node position on shape becomes invalid + const_cast< SMDS_MeshNode* > ( node )->SetPosition + ( SMDS_SpacePosition::originSpacePosition() ); + } nodeMap.insert( TNodeNodeMap::value_type( node, newNode )); // keep inverse elements if ( !theCopy && needReverse ) { SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator(); - while ( invElemIt->more() ) - inverseElemSet.insert( invElemIt->next() ); + while ( invElemIt->more() ) { + const SMDS_MeshElement* iel = invElemIt->next(); + inverseElemSet.insert( make_pair(iel->GetID(),iel) ); + } } } } @@ -2347,12 +3972,12 @@ void SMESH_MeshEditor::Transform (set & theElems, return; if ( !inverseElemSet.empty()) { - set::iterator invElemIt = inverseElemSet.begin(); + map::iterator invElemIt = inverseElemSet.begin(); for ( ; invElemIt != inverseElemSet.end(); invElemIt++ ) theElems.insert( *invElemIt ); } - // replicate or reverse elements + // replicate or reverse elements enum { REV_TETRA = 0, // = nbNodes - 4 @@ -2363,23 +3988,100 @@ void SMESH_MeshEditor::Transform (set & theElems, FORWARD = 5 }; int index[][8] = { - { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA + { 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 + { 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); + for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) { + const SMDS_MeshElement* elem = (*itElem).second; 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 ( theCopy ) { + myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes)); + } + else { + aMesh->ChangePolygonNodes(elem, poly_nodes); + } + } + break; + case SMDSAbs_Volume: + { + // ATTENTION: Reversing is not yet done!!! + const SMDS_PolyhedralVolumeOfNodes* aPolyedre = + (const SMDS_PolyhedralVolumeOfNodes*) 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 ( theCopy ) { + myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities)); + } + 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 ) @@ -2387,12 +4089,46 @@ void SMESH_MeshEditor::Transform (set & theElems, 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 const SMDS_MeshNode* nodes[8]; int iNode = 0; SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) - { + while ( itN->more() ) { const SMDS_MeshNode* node = static_cast( itN->next() ); TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node ); @@ -2403,31 +4139,55 @@ void SMESH_MeshEditor::Transform (set & theElems, if ( iNode != nbNodes ) continue; // not all nodes transformed - if ( theCopy ) - { + if ( theCopy ) { // add a new element switch ( elemType ) { case SMDSAbs_Edge: - aMesh->AddEdge( nodes[ 0 ], nodes[ 1 ] ); + if ( nbNodes == 2 ) + myLastCreatedElems.Append(aMesh->AddEdge( nodes[ 0 ], nodes[ 1 ] )); + else + myLastCreatedElems.Append(aMesh->AddEdge( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] )); break; case SMDSAbs_Face: if ( nbNodes == 3 ) - aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ); - else - aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] , nodes[ 3 ]); + myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] )); + else if(nbNodes==4) + myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] , nodes[ 3 ])); + else if(nbNodes==6) + myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[1], nodes[2], nodes[3], + nodes[4], nodes[5])); + else // nbNodes==8 + myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[1], nodes[2], nodes[3], + nodes[4], nodes[5], nodes[6], nodes[7])); break; case SMDSAbs_Volume: if ( nbNodes == 4 ) - aMesh->AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] , nodes[ 3 ] ); + myLastCreatedElems.Append(aMesh->AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] , nodes[ 3 ] )); else if ( nbNodes == 8 ) - aMesh->AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] , nodes[ 3 ], - nodes[ 4 ], nodes[ 5 ], nodes[ 6 ] , nodes[ 7 ]); + myLastCreatedElems.Append(aMesh->AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] , nodes[ 3 ], + nodes[ 4 ], nodes[ 5 ], nodes[ 6 ] , nodes[ 7 ])); else if ( nbNodes == 6 ) - aMesh->AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] , nodes[ 3 ], - nodes[ 4 ], nodes[ 5 ]); + myLastCreatedElems.Append(aMesh->AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] , nodes[ 3 ], + nodes[ 4 ], nodes[ 5 ])); else if ( nbNodes == 5 ) - aMesh->AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] , nodes[ 3 ], - nodes[ 4 ]); + myLastCreatedElems.Append(aMesh->AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] , nodes[ 3 ], + nodes[ 4 ])); + else if(nbNodes==10) + myLastCreatedElems.Append(aMesh->AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], + nodes[5], nodes[6], nodes[7], nodes[8], nodes[9])); + else if(nbNodes==13) + myLastCreatedElems.Append(aMesh->AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], + nodes[5], nodes[6], nodes[7], nodes[8], nodes[9], + nodes[10], nodes[11], nodes[12])); + else if(nbNodes==15) + myLastCreatedElems.Append(aMesh->AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], + nodes[5], nodes[6], nodes[7], nodes[8], nodes[9], + nodes[10], nodes[11], nodes[12], nodes[13], nodes[14])); + else // nbNodes==20 + myLastCreatedElems.Append(aMesh->AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], + nodes[5], nodes[6], nodes[7], nodes[8], nodes[9], + nodes[10], nodes[11], nodes[12], nodes[13], nodes[14], + nodes[15], nodes[16], nodes[17], nodes[18], nodes[19])); break; default:; } @@ -2451,6 +4211,9 @@ void SMESH_MeshEditor::FindCoincidentNodes (set & theNodes const double theTolerance, TListOfListOfNodes & theGroupsOfNodes) { + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + double tol2 = theTolerance * theTolerance; list nodes; @@ -2463,7 +4226,7 @@ void SMESH_MeshEditor::FindCoincidentNodes (set & theNodes else { nodes.insert( nodes.end(), theNodes.begin(), theNodes.end() ); - } + } list::iterator it2, it1 = nodes.begin(); for ( ; it1 != nodes.end(); it1++ ) @@ -2484,7 +4247,10 @@ void SMESH_MeshEditor::FindCoincidentNodes (set & theNodes groupPtr = & theGroupsOfNodes.back(); groupPtr->push_back( n1 ); } - groupPtr->push_back( n2 ); + if(groupPtr->front()>n2) + groupPtr->push_front( n2 ); + else + groupPtr->push_back( n2 ); it2 = nodes.erase( it2 ); it2--; } @@ -2492,6 +4258,88 @@ void SMESH_MeshEditor::FindCoincidentNodes (set & theNodes } } +//======================================================================= +//function : SimplifyFace +//purpose : +//======================================================================= +int SMESH_MeshEditor::SimplifyFace (const vector faceNodes, + vector& poly_nodes, + vector& quantities) const +{ + int nbNodes = faceNodes.size(); + + if (nbNodes < 3) + return 0; + + set nodeSet; + + // get simple seq of nodes + const SMDS_MeshNode* simpleNodes[ nbNodes ]; + int iSimple = 0, nbUnique = 0; + + simpleNodes[iSimple++] = faceNodes[0]; + nbUnique++; + for (int iCur = 1; iCur < nbNodes; iCur++) { + if (faceNodes[iCur] != simpleNodes[iSimple - 1]) { + simpleNodes[iSimple++] = faceNodes[iCur]; + if (nodeSet.insert( faceNodes[iCur] ).second) + nbUnique++; + } + } + int nbSimple = iSimple; + if (simpleNodes[nbSimple - 1] == simpleNodes[0]) { + nbSimple--; + iSimple--; + } + + if (nbUnique < 3) + return 0; + + // separate loops + int nbNew = 0; + bool foundLoop = (nbSimple > nbUnique); + while (foundLoop) { + foundLoop = false; + set loopSet; + for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) { + const SMDS_MeshNode* n = simpleNodes[iSimple]; + if (!loopSet.insert( n ).second) { + foundLoop = true; + + // separate loop + int iC = 0, curLast = iSimple; + for (; iC < curLast; iC++) { + if (simpleNodes[iC] == n) break; + } + int loopLen = curLast - iC; + if (loopLen > 2) { + // create sub-element + nbNew++; + quantities.push_back(loopLen); + for (; iC < curLast; iC++) { + poly_nodes.push_back(simpleNodes[iC]); + } + } + // shift the rest nodes (place from the first loop position) + for (iC = curLast + 1; iC < nbSimple; iC++) { + simpleNodes[iC - loopLen] = simpleNodes[iC]; + } + nbSimple -= loopLen; + iSimple -= loopLen; + } + } // for (iSimple = 0; iSimple < nbSimple; iSimple++) + } // while (foundLoop) + + if (iSimple > 2) { + nbNew++; + quantities.push_back(iSimple); + for (int i = 0; i < iSimple; i++) + poly_nodes.push_back(simpleNodes[i]); + } + + return nbNew; +} + //======================================================================= //function : MergeNodes //purpose : In each group, the cdr of nodes are substituted by the first one @@ -2500,6 +4348,9 @@ void SMESH_MeshEditor::FindCoincidentNodes (set & theNodes void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) { + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + SMESHDS_Mesh* aMesh = GetMeshDS(); TNodeNodeMap nodeNodeMap; // node to replace - new node @@ -2509,13 +4360,11 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) // Fill nodeNodeMap and elems TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin(); - for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) - { + for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) { list& nodes = *grIt; list::iterator nIt = nodes.begin(); const SMDS_MeshNode* nToKeep = *nIt; - for ( ; nIt != nodes.end(); nIt++ ) - { + for ( ; nIt != nodes.end(); nIt++ ) { const SMDS_MeshNode* nToRemove = *nIt; nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep )); if ( nToRemove != nToKeep ) { @@ -2524,15 +4373,16 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) } SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator(); - while ( invElemIt->more() ) - elems.insert( invElemIt->next() ); + while ( invElemIt->more() ) { + const SMDS_MeshElement* elem = invElemIt->next(); + elems.insert(elem); + } } } - // Change element nodes or remove an element + // Change element nodes or remove an element set::iterator eIt = elems.begin(); - for ( ; eIt != elems.end(); eIt++ ) - { + for ( ; eIt != elems.end(); eIt++ ) { const SMDS_MeshElement* elem = *eIt; int nbNodes = elem->NbNodes(); int aShapeId = FindShape( elem ); @@ -2543,8 +4393,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) // get new seq of nodes SMDS_ElemIteratorPtr itN = elem->nodesIterator(); - while ( itN->more() ) - { + while ( itN->more() ) { const SMDS_MeshNode* n = static_cast( itN->next() ); @@ -2564,8 +4413,95 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) bool isOk = true; int nbUniqueNodes = nodeSet.size(); - if ( nbNodes != nbUniqueNodes ) // some nodes stick - { + if ( nbNodes != nbUniqueNodes ) { // some nodes stick + // Polygons and Polyhedral volumes + if (elem->IsPoly()) { + + if (elem->GetType() == SMDSAbs_Face) { + // Polygon + vector face_nodes (nbNodes); + int inode = 0; + for (; inode < nbNodes; inode++) { + face_nodes[inode] = curNodes[inode]; + } + + vector polygons_nodes; + vector quantities; + int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities); + + if (nbNew > 0) { + inode = 0; + for (int iface = 0; iface < nbNew - 1; iface++) { + int nbNodes = quantities[iface]; + vector poly_nodes (nbNodes); + for (int ii = 0; ii < nbNodes; ii++, inode++) { + poly_nodes[ii] = polygons_nodes[inode]; + } + SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes); + myLastCreatedElems.Append(newElem); + if (aShapeId) + aMesh->SetMeshElementOnShape(newElem, aShapeId); + } + aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]); + } + else { + rmElemIds.push_back(elem->GetID()); + } + + } + else if (elem->GetType() == SMDSAbs_Volume) { + // Polyhedral volume + if (nbUniqueNodes < 4) { + rmElemIds.push_back(elem->GetID()); + } + else { + // each face has to be analized in order to check volume validity + const SMDS_PolyhedralVolumeOfNodes* aPolyedre = + static_cast( elem ); + if (aPolyedre) { + int nbFaces = aPolyedre->NbFaces(); + + vector poly_nodes; + vector quantities; + + for (int iface = 1; iface <= nbFaces; iface++) { + int nbFaceNodes = aPolyedre->NbFaceNodes(iface); + vector faceNodes (nbFaceNodes); + + for (int inode = 1; inode <= nbFaceNodes; inode++) { + const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode); + TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode); + if (nnIt != nodeNodeMap.end()) { // faceNode sticks + faceNode = (*nnIt).second; + } + faceNodes[inode - 1] = faceNode; + } + + SimplifyFace(faceNodes, poly_nodes, quantities); + } + + if (quantities.size() > 3) { + // to be done: remove coincident faces + } + + if (quantities.size() > 3) + aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities); + else + rmElemIds.push_back(elem->GetID()); + + } + else { + rmElemIds.push_back(elem->GetID()); + } + } + } + else { + } + + continue; + } + + // Regular elements switch ( nbNodes ) { case 2: ///////////////////////////////////// EDGE isOk = false; break; @@ -2612,11 +4548,12 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) { // a bottom node sticks with a linked top one // 1. - SMDS_MeshElement* newElem = + SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ 3 ], curNodes[ 4 ], curNodes[ 5 ], curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]); + myLastCreatedElems.Append(newElem); if ( aShapeId ) aMesh->SetMeshElementOnShape( newElem, aShapeId ); // 2. : reverse a bottom @@ -2630,7 +4567,96 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) else isOk = false; break; - case 8: { //////////////////////////////////// HEXAHEDRON + case 8: { + if(elem->IsQuadratic()) { // Quadratic quadrangle + // 1 5 2 + // +---+---+ + // | | + // | | + // 4+ +6 + // | | + // | | + // +---+---+ + // 0 7 3 + isOk = false; + if(nbRepl==3) { + nbUniqueNodes = 6; + if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) { + uniqueNodes[0] = curNodes[0]; + uniqueNodes[1] = curNodes[2]; + uniqueNodes[2] = curNodes[3]; + uniqueNodes[3] = curNodes[5]; + uniqueNodes[4] = curNodes[6]; + uniqueNodes[5] = curNodes[7]; + isOk = true; + } + if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) { + uniqueNodes[0] = curNodes[0]; + uniqueNodes[1] = curNodes[1]; + uniqueNodes[2] = curNodes[2]; + uniqueNodes[3] = curNodes[4]; + uniqueNodes[4] = curNodes[5]; + uniqueNodes[5] = curNodes[6]; + isOk = true; + } + if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) { + uniqueNodes[0] = curNodes[1]; + uniqueNodes[1] = curNodes[2]; + uniqueNodes[2] = curNodes[3]; + uniqueNodes[3] = curNodes[5]; + uniqueNodes[4] = curNodes[6]; + uniqueNodes[5] = curNodes[0]; + isOk = true; + } + if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) { + uniqueNodes[0] = curNodes[0]; + uniqueNodes[1] = curNodes[1]; + uniqueNodes[2] = curNodes[3]; + uniqueNodes[3] = curNodes[4]; + uniqueNodes[4] = curNodes[6]; + uniqueNodes[5] = curNodes[7]; + isOk = true; + } + if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) { + uniqueNodes[0] = curNodes[0]; + uniqueNodes[1] = curNodes[2]; + uniqueNodes[2] = curNodes[3]; + uniqueNodes[3] = curNodes[1]; + uniqueNodes[4] = curNodes[6]; + uniqueNodes[5] = curNodes[7]; + isOk = true; + } + if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) { + uniqueNodes[0] = curNodes[0]; + uniqueNodes[1] = curNodes[1]; + uniqueNodes[2] = curNodes[2]; + uniqueNodes[3] = curNodes[4]; + uniqueNodes[4] = curNodes[5]; + uniqueNodes[5] = curNodes[7]; + isOk = true; + } + if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) { + uniqueNodes[0] = curNodes[0]; + uniqueNodes[1] = curNodes[1]; + uniqueNodes[2] = curNodes[3]; + uniqueNodes[3] = curNodes[4]; + uniqueNodes[4] = curNodes[2]; + uniqueNodes[5] = curNodes[7]; + isOk = true; + } + if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) { + uniqueNodes[0] = curNodes[0]; + uniqueNodes[1] = curNodes[1]; + uniqueNodes[2] = curNodes[2]; + uniqueNodes[3] = curNodes[4]; + uniqueNodes[4] = curNodes[5]; + uniqueNodes[5] = curNodes[3]; + isOk = true; + } + } + break; + } + //////////////////////////////////// HEXAHEDRON isOk = false; SMDS_VolumeTool hexa (elem); hexa.SetExternalNormal(); @@ -2688,11 +4714,12 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]]; nbUniqueNodes = 4; // tetrahedron 2 - SMDS_MeshElement* newElem = + SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ind[ 0 ]], curNodes[ind[ 3 ]], curNodes[ind[ 2 ]], curNodes[indTop[ 0 ]]); + myLastCreatedElems.Append(newElem); if ( aShapeId ) aMesh->SetMeshElementOnShape( newElem, aShapeId ); isOk = true; @@ -2758,6 +4785,7 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) curNodes[ i2 ], curNodes[ i3d ], curNodes[ i2t ]); + myLastCreatedElems.Append(newElem); if ( aShapeId ) aMesh->SetMeshElementOnShape( newElem, aShapeId ); isOk = true; @@ -2806,11 +4834,44 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) } // switch ( nbNodes ) } // if ( nbNodes != nbUniqueNodes ) // some nodes stick - - if ( isOk ) - aMesh->ChangeElementNodes( elem, uniqueNodes, nbUniqueNodes ); - else + + if ( isOk ) { + if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) { + // Change nodes of polyedre + const SMDS_PolyhedralVolumeOfNodes* aPolyedre = + static_cast( elem ); + if (aPolyedre) { + int nbFaces = aPolyedre->NbFaces(); + + vector poly_nodes; + vector quantities (nbFaces); + + for (int iface = 1; iface <= nbFaces; iface++) { + int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface); + quantities[iface - 1] = nbFaceNodes; + + for (inode = 1; inode <= nbFaceNodes; inode++) { + const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode); + + TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode ); + if (nnIt != nodeNodeMap.end()) { // curNode sticks + curNode = (*nnIt).second; + } + poly_nodes.push_back(curNode); + } + } + aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities ); + } + } + else { + // Change regular element or polygon + aMesh->ChangeElementNodes( elem, uniqueNodes, nbUniqueNodes ); + } + } + else { + // Remove invalid regular element or invalid polygon rmElemIds.push_back( elem->GetID() ); + } } // loop on elements @@ -2821,6 +4882,35 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) } + +// ================================================= +// class : SortableElement +// purpose : auxilary +// ================================================= +class SortableElement : public set +{ + public: + + SortableElement( const SMDS_MeshElement* theElem ) + { + myID = theElem->GetID(); + SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator(); + while ( nodeIt->more() ) + this->insert( nodeIt->next() ); + } + + const long GetID() const + { return myID; } + + void SetID(const long anID) const + { myID = anID; } + + + private: + mutable long myID; +}; + + //======================================================================= //function : MergeEqualElements //purpose : Remove all but one of elements built on the same nodes. @@ -2828,6 +4918,9 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes) void SMESH_MeshEditor::MergeEqualElements() { + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + SMESHDS_Mesh* aMesh = GetMeshDS(); SMDS_EdgeIteratorPtr eIt = aMesh->edgesIterator(); @@ -2838,8 +4931,7 @@ void SMESH_MeshEditor::MergeEqualElements() for ( int iDim = 1; iDim <= 3; iDim++ ) { - set< set > setOfNodeSet; - + set< SortableElement > setOfNodeSet; while ( 1 ) { // get next element const SMDS_MeshElement* elem = 0; @@ -2852,16 +4944,21 @@ void SMESH_MeshEditor::MergeEqualElements() } if ( !elem ) break; - // get elem nodes - set nodeSet; - SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator(); - while ( nodeIt->more() ) - nodeSet.insert( nodeIt->next() ); + SortableElement SE(elem); // check uniqueness - bool isUnique = setOfNodeSet.insert( nodeSet ).second; - if ( !isUnique ) - rmElemIds.push_back( elem->GetID() ); + pair< set::iterator, bool> pp = setOfNodeSet.insert(SE); + if( !(pp.second) ) { + set::iterator itSE = pp.first; + SortableElement SEold = *itSE; + if( SEold.GetID() > SE.GetID() ) { + rmElemIds.push_back( SEold.GetID() ); + (*itSE).SetID(SE.GetID()); + } + else { + rmElemIds.push_back( SE.GetID() ); + } + } } } @@ -2878,17 +4975,17 @@ void SMESH_MeshEditor::MergeEqualElements() const SMDS_MeshElement* SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, - const set& elemSet, - const set& avoidSet) + const map& elemSet, + const map& avoidSet) { SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(); while ( invElemIt->more() ) { // loop on inverse elements of n1 const SMDS_MeshElement* elem = invElemIt->next(); if (elem->GetType() != SMDSAbs_Face || - avoidSet.find( elem ) != avoidSet.end() ) + avoidSet.find( elem->GetID() ) != avoidSet.end() ) continue; - if ( !elemSet.empty() && elemSet.find( elem ) == elemSet.end()) + if ( !elemSet.empty() && elemSet.find( elem->GetID() ) == elemSet.end()) continue; // get face nodes and find index of n1 int i1, nbN = elem->NbNodes(), iNode = 0; @@ -2900,36 +4997,75 @@ const SMDS_MeshElement* i1 = iNode - 1; } // find a n2 linked to n1 - for ( iNode = 0; iNode < 2; iNode++ ) { - if ( iNode ) // node before n1 - n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ]; - else // node after n1 - n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ]; - if ( n == n2 ) - return elem; + if(!elem->IsQuadratic()) { + for ( iNode = 0; iNode < 2; iNode++ ) { + if ( iNode ) // node before n1 + n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ]; + else // node after n1 + n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ]; + if ( n == n2 ) + return elem; + } } + else { // analysis for quadratic elements + bool IsFind = false; + // check using only corner nodes + for ( iNode = 0; iNode < 2; iNode++ ) { + if ( iNode ) // node before n1 + n = faceNodes[ i1 == 0 ? nbN/2 - 1 : i1 - 1 ]; + else // node after n1 + n = faceNodes[ i1 + 1 == nbN/2 ? 0 : i1 + 1 ]; + if ( n == n2 ) + IsFind = true; + } + if(IsFind) { + return elem; + } + else { + // check using all nodes + const SMDS_QuadraticFaceOfNodes* F = + static_cast(elem); + // use special nodes iterator + iNode = 0; + SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator(); + while ( anIter->more() ) { + faceNodes[iNode] = static_cast(anIter->next()); + if ( faceNodes[ iNode++ ] == n1 ) + i1 = iNode - 1; + } + for ( iNode = 0; iNode < 2; iNode++ ) { + if ( iNode ) // node before n1 + n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ]; + else // node after n1 + n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ]; + if ( n == n2 ) { + return elem; + } + } + } + } // end analysis for quadratic elements } return 0; } //======================================================================= //function : findAdjacentFace -//purpose : +//purpose : //======================================================================= static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* elem) { - set elemSet, avoidSet; + map elemSet, avoidSet; if ( elem ) - avoidSet.insert ( elem ); - SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet ); + avoidSet.insert ( make_pair(elem->GetID(),elem) ); + return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet ); } - + //======================================================================= //function : findFreeBorder -//purpose : +//purpose : //======================================================================= #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge @@ -2951,12 +5087,12 @@ static bool findFreeBorder (const SMDS_MeshNode* theFirstNode, theNodes.push_back( theFirstNode ); theNodes.push_back( theSecondNode ); - const SMDS_MeshNode* nodes [5], *nIgnore = theFirstNode, * nStart = theSecondNode; + //vector nodes; + const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode; set < const SMDS_MeshElement* > foundElems; bool needTheLast = ( theLastNode != 0 ); - while ( nStart != theLastNode ) - { + while ( nStart != theLastNode ) { if ( nStart == theFirstNode ) return !needTheLast; @@ -2967,13 +5103,24 @@ static bool findFreeBorder (const SMDS_MeshNode* theFirstNode, SMDS_ElemIteratorPtr invElemIt = nStart->facesIterator(); while ( invElemIt->more() ) { const SMDS_MeshElement* e = invElemIt->next(); - if ( e == curElem || foundElems.insert( e ).second ) - { + if ( e == curElem || foundElems.insert( e ).second ) { // get nodes - SMDS_ElemIteratorPtr nIt = e->nodesIterator(); int iNode = 0, nbNodes = e->NbNodes(); - while ( nIt->more() ) - nodes[ iNode++ ] = static_cast( nIt->next() ); + const SMDS_MeshNode* nodes[nbNodes+1]; + if(e->IsQuadratic()) { + const SMDS_QuadraticFaceOfNodes* F = + static_cast(e); + // use special nodes iterator + SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator(); + while( anIter->more() ) { + nodes[ iNode++ ] = anIter->next(); + } + } + else { + SMDS_ElemIteratorPtr nIt = e->nodesIterator(); + while ( nIt->more() ) + nodes[ iNode++ ] = static_cast( nIt->next() ); + } nodes[ iNode ] = nodes[ 0 ]; // check 2 links for ( iNode = 0; iNode < nbNodes; iNode++ ) @@ -3075,7 +5222,7 @@ bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1, //======================================================================= //function : SewFreeBorder -//purpose : +//purpose : //======================================================================= SMESH_MeshEditor::Sew_Error @@ -3085,8 +5232,13 @@ SMESH_MeshEditor::Sew_Error const SMDS_MeshNode* theSideFirstNode, const SMDS_MeshNode* theSideSecondNode, const SMDS_MeshNode* theSideThirdNode, - bool theSideIsFreeBorder) + const bool theSideIsFreeBorder, + const bool toCreatePolygons, + const bool toCreatePolyedrs) { + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + MESSAGE("::SewFreeBorder()"); Sew_Error aResult = SEW_OK; @@ -3106,8 +5258,7 @@ SMESH_MeshEditor::Sew_Error MESSAGE(" Free Border 1 not found " ); aResult = SEW_BORDER1_NOT_FOUND; } - if (theSideIsFreeBorder) - { + if (theSideIsFreeBorder) { // Free border 2 // -------------- if (!findFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode, @@ -3119,8 +5270,7 @@ SMESH_MeshEditor::Sew_Error if ( aResult != SEW_OK ) return aResult; - if (!theSideIsFreeBorder) - { + if (!theSideIsFreeBorder) { // Side 2 // -------------- @@ -3146,8 +5296,7 @@ SMESH_MeshEditor::Sew_Error gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() ); double tol2 = 1.e-8; gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 ); - if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) - { + if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) { // Need node movement. // find X and Z axes to create trsf @@ -3166,7 +5315,7 @@ SMESH_MeshEditor::Sew_Error toBordSys.SetTransformation( toBordAx ); fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx ); fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() ); - + // move for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) { const SMDS_MeshNode* n = *nBordIt; @@ -3176,8 +5325,7 @@ SMESH_MeshEditor::Sew_Error nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz )); } } - else - { + else { // just insert nodes XYZ in the nBordXYZ map for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) { const SMDS_MeshNode* n = *nBordIt; @@ -3196,7 +5344,7 @@ SMESH_MeshEditor::Sew_Error LinkID_Gen aLinkID_Gen( GetMeshDS() ); set foundSideLinkIDs, checkedLinkIDs; SMDS_VolumeTool volume; - const SMDS_MeshNode* faceNodes[ 4 ]; + //const SMDS_MeshNode* faceNodes[ 4 ]; const SMDS_MeshNode* sideNode; const SMDS_MeshElement* sideElem; @@ -3224,17 +5372,32 @@ SMESH_MeshEditor::Sew_Error const SMDS_MeshElement* elem = invElemIt->next(); // prepare data for a loop on links, of a face or a volume int iPrevNode, iNode = 0, nbNodes = elem->NbNodes(); + const SMDS_MeshNode* faceNodes[ nbNodes ]; bool isVolume = volume.Set( elem ); const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : faceNodes; if ( isVolume ) // --volume hasVolumes = true; - else if ( nbNodes > 2 ) { // --face + //else if ( nbNodes > 2 ) { // --face + else if ( elem->GetType()==SMDSAbs_Face ) { // --face // retrieve all face nodes and find iPrevNode - an index of the prevSideNode - SMDS_ElemIteratorPtr nIt = elem->nodesIterator(); - while ( nIt->more() ) { - nodes[ iNode ] = static_cast( nIt->next() ); - if ( nodes[ iNode++ ] == prevSideNode ) - iPrevNode = iNode - 1; + if(elem->IsQuadratic()) { + const SMDS_QuadraticFaceOfNodes* F = + static_cast(elem); + // use special nodes iterator + SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator(); + while( anIter->more() ) { + nodes[ iNode ] = anIter->next(); + if ( nodes[ iNode++ ] == prevSideNode ) + iPrevNode = iNode - 1; + } + } + else { + SMDS_ElemIteratorPtr nIt = elem->nodesIterator(); + while ( nIt->more() ) { + nodes[ iNode ] = static_cast( nIt->next() ); + if ( nodes[ iNode++ ] == prevSideNode ) + iPrevNode = iNode - 1; + } } // there are 2 links to check nbNodes = 2; @@ -3247,7 +5410,8 @@ SMESH_MeshEditor::Sew_Error if ( isVolume ) { if ( !volume.IsLinked( n, prevSideNode )) continue; - } else { + } + else { if ( iNode ) // a node before prevSideNode n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ]; else // a node after prevSideNode @@ -3307,7 +5471,7 @@ SMESH_MeshEditor::Sew_Error } while ( sideNode != theSideSecondNode ); - if ( hasVolumes && sideNodes.size () != bordNodes.size() ) { + if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) { MESSAGE("VOLUME SPLITTING IS FORBIDDEN"); return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden } @@ -3331,7 +5495,7 @@ SMESH_MeshEditor::Sew_Error nIt[0]++, nIt[1]++ ) { nodeGroupsToMerge.push_back( list() ); - nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep + nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep nodeGroupsToMerge.back().push_back( *nIt[0] ); // tp remove } } @@ -3388,7 +5552,7 @@ SMESH_MeshEditor::Sew_Error double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]); double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]); double minSegLen = Min( nextParam - minParam, maxParam - prevParam ); - + // choose to insert or to merge nodes double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ]; if ( Abs( du ) <= minSegLen * 0.2 ) { @@ -3431,15 +5595,19 @@ SMESH_MeshEditor::Sew_Error list & nodeList = (*insertMapIt).second; const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front(); const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front(); - InsertNodesIntoLink( elem, n12, n22, nodeList ); + InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons ); // 2. perform insertion into the link of adjacent faces while (true) { const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem ); if ( adjElem ) - InsertNodesIntoLink( adjElem, n12, n22, nodeList ); + InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons ); else break; } + if (toCreatePolyedrs) { + // perform insertion into the links of adjacent volumes + UpdateVolumes(n12, n22, nodeList); + } // 3. find an element appeared on n1 and n2 after the insertion insertMap.erase( elem ); elem = findAdjacentFace( n1, n2, 0 ); @@ -3466,179 +5634,808 @@ SMESH_MeshEditor::Sew_Error } } } - while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end()); + while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end()); + + // perform insertion of nodes into elements + + for (insertMapIt = insertMap.begin(); + insertMapIt != insertMap.end(); + insertMapIt++ ) + { + const SMDS_MeshElement* elem = (*insertMapIt).first; + list & nodeList = (*insertMapIt).second; + const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front(); + const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front(); + + InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons ); + + if ( !theSideIsFreeBorder ) { + // look for and insert nodes into the faces adjacent to elem + while (true) { + const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem ); + if ( adjElem ) + InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons ); + else + break; + } + } + if (toCreatePolyedrs) { + // perform insertion into the links of adjacent volumes + UpdateVolumes(n1, n2, nodeList); + } + } + + } // end: insert new nodes + + MergeNodes ( nodeGroupsToMerge ); + + return aResult; +} + +//======================================================================= +//function : InsertNodesIntoLink +//purpose : insert theNodesToInsert into theFace between theBetweenNode1 +// and theBetweenNode2 and split theElement +//======================================================================= + +void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace, + const SMDS_MeshNode* theBetweenNode1, + const SMDS_MeshNode* theBetweenNode2, + list& theNodesToInsert, + const bool toCreatePoly) +{ + if ( theFace->GetType() != SMDSAbs_Face ) return; + + // find indices of 2 link nodes and of the rest nodes + int iNode = 0, il1, il2, i3, i4; + il1 = il2 = i3 = i4 = -1; + const SMDS_MeshNode* nodes[ theFace->NbNodes() ]; + + if(theFace->IsQuadratic()) { + const SMDS_QuadraticFaceOfNodes* F = + static_cast(theFace); + // use special nodes iterator + SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator(); + while( anIter->more() ) { + const SMDS_MeshNode* n = anIter->next(); + if ( n == theBetweenNode1 ) + il1 = iNode; + else if ( n == theBetweenNode2 ) + il2 = iNode; + else if ( i3 < 0 ) + i3 = iNode; + else + i4 = iNode; + nodes[ iNode++ ] = n; + } + } + else { + SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator(); + while ( nodeIt->more() ) { + const SMDS_MeshNode* n = static_cast( nodeIt->next() ); + if ( n == theBetweenNode1 ) + il1 = iNode; + else if ( n == theBetweenNode2 ) + il2 = iNode; + else if ( i3 < 0 ) + i3 = iNode; + else + i4 = iNode; + nodes[ iNode++ ] = n; + } + } + if ( il1 < 0 || il2 < 0 || i3 < 0 ) + return ; + + // arrange link nodes to go one after another regarding the face orientation + bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 ); + list aNodesToInsert = theNodesToInsert; + if ( reverse ) { + iNode = il1; + il1 = il2; + il2 = iNode; + aNodesToInsert.reverse(); + } + // check that not link nodes of a quadrangles are in good order + int nbFaceNodes = theFace->NbNodes(); + if ( nbFaceNodes == 4 && i4 - i3 != 1 ) { + iNode = i3; + i3 = i4; + i4 = iNode; + } + + if (toCreatePoly || theFace->IsPoly()) { + + iNode = 0; + vector poly_nodes (nbFaceNodes + aNodesToInsert.size()); + + // add nodes of face up to first node of link + bool isFLN = false; + + if(theFace->IsQuadratic()) { + const SMDS_QuadraticFaceOfNodes* F = + static_cast(theFace); + // use special nodes iterator + SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator(); + while( anIter->more() && !isFLN ) { + const SMDS_MeshNode* n = anIter->next(); + poly_nodes[iNode++] = n; + if (n == nodes[il1]) { + isFLN = true; + } + } + // add nodes to insert + list::iterator nIt = aNodesToInsert.begin(); + for (; nIt != aNodesToInsert.end(); nIt++) { + poly_nodes[iNode++] = *nIt; + } + // add nodes of face starting from last node of link + while ( anIter->more() ) { + poly_nodes[iNode++] = anIter->next(); + } + } + else { + SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator(); + while ( nodeIt->more() && !isFLN ) { + const SMDS_MeshNode* n = static_cast( nodeIt->next() ); + poly_nodes[iNode++] = n; + if (n == nodes[il1]) { + isFLN = true; + } + } + // add nodes to insert + list::iterator nIt = aNodesToInsert.begin(); + for (; nIt != aNodesToInsert.end(); nIt++) { + poly_nodes[iNode++] = *nIt; + } + // add nodes of face starting from last node of link + while ( nodeIt->more() ) { + const SMDS_MeshNode* n = static_cast( nodeIt->next() ); + poly_nodes[iNode++] = n; + } + } + + // edit or replace the face + SMESHDS_Mesh *aMesh = GetMeshDS(); + + if (theFace->IsPoly()) { + aMesh->ChangePolygonNodes(theFace, poly_nodes); + } + else { + int aShapeId = FindShape( theFace ); + + SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes); + myLastCreatedElems.Append(newElem); + if ( aShapeId && newElem ) + aMesh->SetMeshElementOnShape( newElem, aShapeId ); + + aMesh->RemoveElement(theFace); + } + return; + } + + if( !theFace->IsQuadratic() ) { + + // put aNodesToInsert between theBetweenNode1 and theBetweenNode2 + int nbLinkNodes = 2 + aNodesToInsert.size(); + const SMDS_MeshNode* linkNodes[ nbLinkNodes ]; + linkNodes[ 0 ] = nodes[ il1 ]; + linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ]; + list::iterator nIt = aNodesToInsert.begin(); + for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) { + linkNodes[ iNode++ ] = *nIt; + } + // decide how to split a quadrangle: compare possible variants + // and choose which of splits to be a quadrangle + int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad; + if ( nbFaceNodes == 3 ) { + iBestQuad = nbSplits; + i4 = i3; + } + else if ( nbFaceNodes == 4 ) { + SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio); + double aBestRate = DBL_MAX; + for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) { + i1 = 0; i2 = 1; + double aBadRate = 0; + // evaluate elements quality + for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) { + if ( iSplit == iQuad ) { + SMDS_FaceOfNodes quad (linkNodes[ i1++ ], + linkNodes[ i2++ ], + nodes[ i3 ], + nodes[ i4 ]); + aBadRate += getBadRate( &quad, aCrit ); + } + else { + SMDS_FaceOfNodes tria (linkNodes[ i1++ ], + linkNodes[ i2++ ], + nodes[ iSplit < iQuad ? i4 : i3 ]); + aBadRate += getBadRate( &tria, aCrit ); + } + } + // choice + if ( aBadRate < aBestRate ) { + iBestQuad = iQuad; + aBestRate = aBadRate; + } + } + } + + // create new elements + SMESHDS_Mesh *aMesh = GetMeshDS(); + int aShapeId = FindShape( theFace ); + + i1 = 0; i2 = 1; + for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) { + SMDS_MeshElement* newElem = 0; + if ( iSplit == iBestQuad ) + newElem = aMesh->AddFace (linkNodes[ i1++ ], + linkNodes[ i2++ ], + nodes[ i3 ], + nodes[ i4 ]); + else + newElem = aMesh->AddFace (linkNodes[ i1++ ], + linkNodes[ i2++ ], + nodes[ iSplit < iBestQuad ? i4 : i3 ]); + myLastCreatedElems.Append(newElem); + if ( aShapeId && newElem ) + aMesh->SetMeshElementOnShape( newElem, aShapeId ); + } + + // change nodes of theFace + const SMDS_MeshNode* newNodes[ 4 ]; + newNodes[ 0 ] = linkNodes[ i1 ]; + newNodes[ 1 ] = linkNodes[ i2 ]; + newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ]; + newNodes[ 3 ] = nodes[ i4 ]; + aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 ); + } // end if(!theFace->IsQuadratic()) + else { // theFace is quadratic + // we have to split theFace on simple triangles and one simple quadrangle + int tmp = il1/2; + int nbshift = tmp*2; + // shift nodes in nodes[] by nbshift + int i,j; + for(i=0; iAddFace(nodes[3],nodes[4],nodes[5]); + myLastCreatedElems.Append(newElem); + if ( aShapeId && newElem ) + aMesh->SetMeshElementOnShape( newElem, aShapeId ); + if(theFace->IsMediumNode(nodes[il1])) { + // create quadrangle + newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]); + myLastCreatedElems.Append(newElem); + if ( aShapeId && newElem ) + aMesh->SetMeshElementOnShape( newElem, aShapeId ); + n1 = 1; + n2 = 2; + n3 = 3; + } + else { + // create quadrangle + newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]); + myLastCreatedElems.Append(newElem); + if ( aShapeId && newElem ) + aMesh->SetMeshElementOnShape( newElem, aShapeId ); + n1 = 0; + n2 = 1; + n3 = 5; + } + } + else { // nbFaceNodes==8 - quadratic quadrangle + SMDS_MeshElement* newElem = + aMesh->AddFace(nodes[3],nodes[4],nodes[5]); + myLastCreatedElems.Append(newElem); + if ( aShapeId && newElem ) + aMesh->SetMeshElementOnShape( newElem, aShapeId ); + newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]); + myLastCreatedElems.Append(newElem); + if ( aShapeId && newElem ) + aMesh->SetMeshElementOnShape( newElem, aShapeId ); + newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]); + myLastCreatedElems.Append(newElem); + if ( aShapeId && newElem ) + aMesh->SetMeshElementOnShape( newElem, aShapeId ); + if(theFace->IsMediumNode(nodes[il1])) { + // create quadrangle + newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]); + myLastCreatedElems.Append(newElem); + if ( aShapeId && newElem ) + aMesh->SetMeshElementOnShape( newElem, aShapeId ); + n1 = 1; + n2 = 2; + n3 = 3; + } + else { + // create quadrangle + newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]); + myLastCreatedElems.Append(newElem); + if ( aShapeId && newElem ) + aMesh->SetMeshElementOnShape( newElem, aShapeId ); + n1 = 0; + n2 = 1; + n3 = 7; + } + } + // create needed triangles using n1,n2,n3 and inserted nodes + int nbn = 2 + aNodesToInsert.size(); + const SMDS_MeshNode* aNodes[nbn]; + aNodes[0] = nodes[n1]; + aNodes[nbn-1] = nodes[n2]; + list::iterator nIt = aNodesToInsert.begin(); + for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) { + aNodes[iNode++] = *nIt; + } + for(i=1; iAddFace(aNodes[i-1],aNodes[i],nodes[n3]); + myLastCreatedElems.Append(newElem); + if ( aShapeId && newElem ) + aMesh->SetMeshElementOnShape( newElem, aShapeId ); + } + // remove old quadratic face + aMesh->RemoveElement(theFace); + } +} - // perform insertion of nodes into elements +//======================================================================= +//function : UpdateVolumes +//purpose : +//======================================================================= +void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1, + const SMDS_MeshNode* theBetweenNode2, + list& theNodesToInsert) +{ + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); - for (insertMapIt = insertMap.begin(); - insertMapIt != insertMap.end(); - insertMapIt++ ) - { - const SMDS_MeshElement* elem = (*insertMapIt).first; - list & nodeList = (*insertMapIt).second; - const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front(); - const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front(); + SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(); + while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1 + const SMDS_MeshElement* elem = invElemIt->next(); + if (elem->GetType() != SMDSAbs_Volume) + continue; - InsertNodesIntoLink( elem, n1, n2, nodeList ); + // check, if current volume has link theBetweenNode1 - theBetweenNode2 + SMDS_VolumeTool aVolume (elem); + if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2)) + continue; - if ( !theSideIsFreeBorder ) { - // look for and insert nodes into the faces adjacent to elem - while (true) { - const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem ); - if ( adjElem ) - InsertNodesIntoLink( adjElem, n1, n2, nodeList ); - else - break; + // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2 + int iface, nbFaces = aVolume.NbFaces(); + vector poly_nodes; + vector quantities (nbFaces); + + for (iface = 0; iface < nbFaces; iface++) { + int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0; + // faceNodes will contain (nbFaceNodes + 1) nodes, last = first + const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface); + + for (int inode = 0; inode < nbFaceNodes; inode++) { + poly_nodes.push_back(faceNodes[inode]); + + if (nbInserted == 0) { + if (faceNodes[inode] == theBetweenNode1) { + if (faceNodes[inode + 1] == theBetweenNode2) { + nbInserted = theNodesToInsert.size(); + + // add nodes to insert + list::iterator nIt = theNodesToInsert.begin(); + for (; nIt != theNodesToInsert.end(); nIt++) { + poly_nodes.push_back(*nIt); + } + } + } + else if (faceNodes[inode] == theBetweenNode2) { + if (faceNodes[inode + 1] == theBetweenNode1) { + nbInserted = theNodesToInsert.size(); + + // add nodes to insert in reversed order + list::iterator nIt = theNodesToInsert.end(); + nIt--; + for (; nIt != theNodesToInsert.begin(); nIt--) { + poly_nodes.push_back(*nIt); + } + poly_nodes.push_back(*nIt); + } + } + else { + } } } + quantities[iface] = nbFaceNodes + nbInserted; } - } // end: insert new nodes + // Replace or update the volume + SMESHDS_Mesh *aMesh = GetMeshDS(); - MergeNodes ( nodeGroupsToMerge ); + if (elem->IsPoly()) { + aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities); - return aResult; + } + else { + int aShapeId = FindShape( elem ); + + SMDS_MeshElement* newElem = + aMesh->AddPolyhedralVolume(poly_nodes, quantities); + myLastCreatedElems.Append(newElem); + if (aShapeId && newElem) + aMesh->SetMeshElementOnShape(newElem, aShapeId); + + aMesh->RemoveElement(elem); + } + } } //======================================================================= -//function : InsertNodesIntoLink -//purpose : insert theNodesToInsert into theFace between theBetweenNode1 -// and theBetweenNode2 and split theElement +//function : ConvertElemToQuadratic +//purpose : //======================================================================= - -void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace, - const SMDS_MeshNode* theBetweenNode1, - const SMDS_MeshNode* theBetweenNode2, - list& theNodesToInsert) +void SMESH_MeshEditor::ConvertElemToQuadratic(SMESHDS_SubMesh *theSm, + SMESH_MesherHelper* theHelper, + const bool theForce3d) { - if ( theFace->GetType() != SMDSAbs_Face ) return; + if( !theSm ) return; + SMESHDS_Mesh* meshDS = GetMeshDS(); + SMDS_ElemIteratorPtr ElemItr = theSm->GetElements(); + while(ElemItr->more()) + { + const SMDS_MeshElement* elem = ElemItr->next(); + if( !elem ) continue; - // find indices of 2 link nodes and of the rest nodes - int iNode = 0, il1, il2, i3, i4; - il1 = il2 = i3 = i4 = -1; - const SMDS_MeshNode* nodes[ 8 ]; - SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator(); - while ( nodeIt->more() ) { - const SMDS_MeshNode* n = static_cast( nodeIt->next() ); - if ( n == theBetweenNode1 ) - il1 = iNode; - else if ( n == theBetweenNode2 ) - il2 = iNode; - else if ( i3 < 0 ) - i3 = iNode; - else - i4 = iNode; - nodes[ iNode++ ] = n; - } - if ( il1 < 0 || il2 < 0 || i3 < 0 ) - return ; + int id = elem->GetID(); + int nbNodes = elem->NbNodes(); + vector aNds (nbNodes); + + for(int i = 0; i < nbNodes; i++) + { + aNds[i] = elem->GetNode(i); + } - // arrange link nodes to go one after another regarding the face orientation - bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 ); - if ( reverse ) { - iNode = il1; - il1 = il2; - il2 = iNode; - theNodesToInsert.reverse(); + SMDSAbs_ElementType aType = elem->GetType(); + const SMDS_MeshElement* NewElem = 0; + + switch( aType ) + { + case SMDSAbs_Edge : + { + meshDS->RemoveFreeElement(elem, theSm); + NewElem = theHelper->AddQuadraticEdge(aNds[0], aNds[1], id, theForce3d); + break; + } + case SMDSAbs_Face : + { + if(elem->IsQuadratic()) continue; + + meshDS->RemoveFreeElement(elem, theSm); + switch(nbNodes) + { + case 3: + NewElem = theHelper->AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d); + break; + case 4: + NewElem = theHelper->AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d); + break; + default: + continue; + } + break; + } + case SMDSAbs_Volume : + { + if( elem->IsQuadratic() ) continue; + + meshDS->RemoveFreeElement(elem, theSm); + switch(nbNodes) + { + case 4: + NewElem = theHelper->AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, true); + break; + case 6: + NewElem = theHelper->AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, true); + break; + case 8: + NewElem = theHelper->AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], + aNds[4], aNds[5], aNds[6], aNds[7], id, true); + break; + default: + continue; + } + break; + } + default : + continue; + } + if( NewElem ) + { + AddToSameGroups( NewElem, elem, meshDS); + theSm->AddElement( NewElem ); + } } - // check that not link nodes of a quadrangles are in good order - int nbFaceNodes = theFace->NbNodes(); - if ( nbFaceNodes == 4 && i4 - i3 != 1 ) { - iNode = i3; - i3 = i4; - i4 = iNode; - } - - // put theNodesToInsert between theBetweenNode1 and theBetweenNode2 - int nbLinkNodes = 2 + theNodesToInsert.size(); - const SMDS_MeshNode* linkNodes[ nbLinkNodes ]; - linkNodes[ 0 ] = nodes[ il1 ]; - linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ]; - list::iterator nIt = theNodesToInsert.begin(); - for ( iNode = 1; nIt != theNodesToInsert.end(); nIt++ ) { - linkNodes[ iNode++ ] = *nIt; +} + +//======================================================================= +//function : ConvertToQuadratic +//purpose : +//======================================================================= +void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d) +{ + SMESHDS_Mesh* meshDS = GetMeshDS(); + + SMESH_MesherHelper* aHelper = new SMESH_MesherHelper(*myMesh); + aHelper->SetKeyIsQuadratic( true ); + const TopoDS_Shape& aShape = meshDS->ShapeToMesh(); + + if ( !aShape.IsNull() && GetMesh()->GetSubMeshContaining(aShape) ) + { + SMESH_subMesh *aSubMesh = GetMesh()->GetSubMeshContaining(aShape); + + const map < int, SMESH_subMesh * >& aMapSM = aSubMesh->DependsOn(); + map < int, SMESH_subMesh * >::const_iterator itsub; + for (itsub = aMapSM.begin(); itsub != aMapSM.end(); itsub++) + { + SMESHDS_SubMesh *sm = ((*itsub).second)->GetSubMeshDS(); + aHelper->SetSubShape( (*itsub).second->GetSubShape() ); + ConvertElemToQuadratic(sm, aHelper, theForce3d); + } + aHelper->SetSubShape( aSubMesh->GetSubShape() ); + ConvertElemToQuadratic(aSubMesh->GetSubMeshDS(), aHelper, theForce3d); } - // decide how to split a quadrangle: compare possible variants - // and choose which of splits to be a quadrangle - int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad; - if ( nbFaceNodes == 3 ) + else { - iBestQuad = nbSplits; - i4 = i3; + SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator(); + while(aEdgeItr->more()) + { + const SMDS_MeshEdge* edge = aEdgeItr->next(); + if(edge) + { + int id = edge->GetID(); + const SMDS_MeshNode* n1 = edge->GetNode(0); + const SMDS_MeshNode* n2 = edge->GetNode(1); + + RemoveElemFromGroups (edge, meshDS); + meshDS->SMDS_Mesh::RemoveFreeElement(edge); + + const SMDS_QuadraticEdge* NewEdge = aHelper->AddQuadraticEdge(n1, n2, id, theForce3d); + AddToSameGroups(NewEdge, edge, meshDS); + } + } + SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator(); + while(aFaceItr->more()) + { + const SMDS_MeshFace* face = aFaceItr->next(); + if(!face || face->IsQuadratic() ) continue; + + int id = face->GetID(); + int nbNodes = face->NbNodes(); + vector aNds (nbNodes); + + for(int i = 0; i < nbNodes; i++) + { + aNds[i] = face->GetNode(i); + } + + RemoveElemFromGroups (face, meshDS); + meshDS->SMDS_Mesh::RemoveFreeElement(face); + + SMDS_MeshFace * NewFace = 0; + switch(nbNodes) + { + case 3: + NewFace = aHelper->AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d); + break; + case 4: + NewFace = aHelper->AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d); + break; + default: + continue; + } + AddToSameGroups(NewFace, face, meshDS); + } + SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator(); + while(aVolumeItr->more()) + { + const SMDS_MeshVolume* volume = aVolumeItr->next(); + if(!volume || volume->IsQuadratic() ) continue; + + int id = volume->GetID(); + int nbNodes = volume->NbNodes(); + vector aNds (nbNodes); + + for(int i = 0; i < nbNodes; i++) + { + aNds[i] = volume->GetNode(i); + } + + RemoveElemFromGroups (volume, meshDS); + meshDS->SMDS_Mesh::RemoveFreeElement(volume); + + SMDS_MeshVolume * NewVolume = 0; + switch(nbNodes) + { + case 4: + NewVolume = aHelper->AddVolume(aNds[0], aNds[1], aNds[2], + aNds[3], id, true ); + break; + case 6: + NewVolume = aHelper->AddVolume(aNds[0], aNds[1], aNds[2], + aNds[3], aNds[4], aNds[5], id, true); + break; + case 8: + NewVolume = aHelper->AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], + aNds[4], aNds[5], aNds[6], aNds[7], id, true); + break; + default: + continue; + } + AddToSameGroups(NewVolume, volume, meshDS); + } } - else if ( nbFaceNodes == 4 ) + delete aHelper; +} + +//======================================================================= +//function : RemoveQuadElem +//purpose : +//======================================================================= +void SMESH_MeshEditor::RemoveQuadElem(SMESHDS_SubMesh *theSm, + SMDS_ElemIteratorPtr theItr, + RemoveQuadNodeMap& theRemoveNodeMap) +{ + SMESHDS_Mesh* meshDS = GetMeshDS(); + while( theItr->more() ) { - SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio); - double aBestRate = DBL_MAX; - for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) { - i1 = 0; i2 = 1; - double aBadRate = 0; - // evaluate elements quality - for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) { - if ( iSplit == iQuad ) { - SMDS_FaceOfNodes quad (linkNodes[ i1++ ], - linkNodes[ i2++ ], - nodes[ i3 ], - nodes[ i4 ]); - aBadRate += getBadRate( &quad, aCrit ); - } - else { - SMDS_FaceOfNodes tria (linkNodes[ i1++ ], - linkNodes[ i2++ ], - nodes[ iSplit < iQuad ? i4 : i3 ]); - aBadRate += getBadRate( &tria, aCrit ); - } + const SMDS_MeshElement* elem = theItr->next(); + if( elem ) + { + if( !elem->IsQuadratic() ) + continue; + + int id = elem->GetID(); + + int nbNodes = elem->NbNodes(), idx = 0; + vector aNds; + + for(int i = 0; i < nbNodes; i++) + { + const SMDS_MeshNode* n = elem->GetNode(i); + + if( elem->IsMediumNode( n ) ) + { + ItRemoveQuadNodeMap itRNM = theRemoveNodeMap.find( n ); + if( itRNM == theRemoveNodeMap.end() ) + { + theRemoveNodeMap.insert(RemoveQuadNodeMap::value_type( n,theSm )); + } + } + else + aNds.push_back( n ); } - // choice - if ( aBadRate < aBestRate ) { - iBestQuad = iQuad; - aBestRate = aBadRate; + + idx = aNds.size(); + if( !idx ) continue; + SMDSAbs_ElementType aType = elem->GetType(); + + //remove old quadratic elements + meshDS->RemoveFreeElement( elem, theSm ); + + SMDS_MeshElement * NewElem = 0; + switch(aType) + { + case SMDSAbs_Edge: + NewElem = meshDS->AddEdgeWithID( aNds[0], aNds[1] ,id ); + break; + case SMDSAbs_Face: + if( idx==3 ) NewElem = meshDS->AddFaceWithID( aNds[0], + aNds[1], aNds[2], id ); + if( idx==4 ) NewElem = meshDS->AddFaceWithID( aNds[0], + aNds[1], aNds[2], aNds[3],id ); + break; + case SMDSAbs_Volume: + if( idx==4 ) NewElem = meshDS->AddVolumeWithID( aNds[0], + aNds[1], aNds[2], aNds[3], id ); + if( idx==6 ) NewElem = meshDS->AddVolumeWithID( aNds[0], + aNds[1], aNds[2], aNds[3], + aNds[4], aNds[5], id ); + if( idx==8 ) NewElem = meshDS->AddVolumeWithID(aNds[0], + aNds[1], aNds[2], aNds[3], + aNds[4], aNds[5], aNds[6], + aNds[7] ,id ); + break; + default: + break; } + + AddToSameGroups(NewElem, elem, meshDS); + if( theSm ) + theSm->AddElement( NewElem ); + } + } +} +//======================================================================= +//function : ConvertFromQuadratic +//purpose : +//======================================================================= +bool SMESH_MeshEditor::ConvertFromQuadratic() +{ + SMESHDS_Mesh* meshDS = GetMeshDS(); + RemoveQuadNodeMap aRemoveNodeMap; + + const TopoDS_Shape& aShape = meshDS->ShapeToMesh(); + + if ( !aShape.IsNull() && GetMesh()->GetSubMeshContaining(aShape) ) + { + SMESH_subMesh *aSubMesh = GetMesh()->GetSubMeshContaining(aShape); + + const map < int, SMESH_subMesh * >& aMapSM = aSubMesh->DependsOn(); + map < int, SMESH_subMesh * >::const_iterator itsub; + for (itsub = aMapSM.begin(); itsub != aMapSM.end(); itsub++) + { + SMESHDS_SubMesh *sm = ((*itsub).second)->GetSubMeshDS(); + if( sm ) + RemoveQuadElem( sm, sm->GetElements(), aRemoveNodeMap ); } + SMESHDS_SubMesh *Sm = aSubMesh->GetSubMeshDS(); + if( Sm ) + RemoveQuadElem( Sm, Sm->GetElements(), aRemoveNodeMap ); + } + else + { + SMESHDS_SubMesh *aSM = 0; + RemoveQuadElem( aSM, meshDS->elementsIterator(), aRemoveNodeMap ); } - // create new elements - SMESHDS_Mesh *aMesh = GetMeshDS(); - int aShapeId = FindShape( theFace ); - - i1 = 0; i2 = 1; - for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) { - SMDS_MeshElement* newElem = 0; - if ( iSplit == iBestQuad ) - newElem = aMesh->AddFace (linkNodes[ i1++ ], - linkNodes[ i2++ ], - nodes[ i3 ], - nodes[ i4 ]); - else - newElem = aMesh->AddFace (linkNodes[ i1++ ], - linkNodes[ i2++ ], - nodes[ iSplit < iBestQuad ? i4 : i3 ]); - if ( aShapeId && newElem ) - aMesh->SetMeshElementOnShape( newElem, aShapeId ); + //remove all quadratic nodes + ItRemoveQuadNodeMap itRNM = aRemoveNodeMap.begin(); + for ( ; itRNM != aRemoveNodeMap.end(); itRNM++ ) + { + meshDS->RemoveFreeNode( (*itRNM).first, (*itRNM).second ); } - // change nodes of theFace - const SMDS_MeshNode* newNodes[ 4 ]; - newNodes[ 0 ] = linkNodes[ i1 ]; - newNodes[ 1 ] = linkNodes[ i2 ]; - newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ]; - newNodes[ 3 ] = nodes[ i4 ]; - aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 ); + return true; } //======================================================================= //function : SewSideElements -//purpose : +//purpose : //======================================================================= SMESH_MeshEditor::Sew_Error - SMESH_MeshEditor::SewSideElements (set& theSide1, - set& theSide2, + SMESH_MeshEditor::SewSideElements (map& theSide1, + map& theSide2, const SMDS_MeshNode* theFirstNode1, const SMDS_MeshNode* theFirstNode2, const SMDS_MeshNode* theSecondNode1, const SMDS_MeshNode* theSecondNode2) { + myLastCreatedElems.Clear(); + myLastCreatedNodes.Clear(); + MESSAGE ("::::SewSideElements()"); if ( theSide1.size() != theSide2.size() ) return SEW_DIFF_NB_OF_ELEMENTS; @@ -3665,28 +6462,45 @@ SMESH_MeshEditor::Sew_Error set * faceSetPtr[] = { &faceSet1, &faceSet2 }; set * volSetPtr[] = { &volSet1, &volSet2 }; set * nodeSetPtr[] = { &nodeSet1, &nodeSet2 }; - set * elemSetPtr[] = { &theSide1, &theSide2 }; + map * elemSetPtr[] = { &theSide1, &theSide2 }; int iSide, iFace, iNode; for ( iSide = 0; iSide < 2; iSide++ ) { set * nodeSet = nodeSetPtr[ iSide ]; - set * elemSet = elemSetPtr[ iSide ]; + map * elemSet = elemSetPtr[ iSide ]; set * faceSet = faceSetPtr[ iSide ]; set * volSet = volSetPtr [ iSide ]; - set::iterator vIt, eIt; + set::iterator vIt; + map::iterator eIt; set::iterator nIt; - // ----------------------------------------------------------- - // 1a. Collect nodes of existing faces - // and build set of face nodes in order to detect missing - // faces corresponing to sides of volumes - // ----------------------------------------------------------- + // check that given nodes belong to given elements + const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2; + const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2; + int firstIndex = -1, secondIndex = -1; + for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) { + const SMDS_MeshElement* elem = (*eIt).second; + if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 ); + if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 ); + if ( firstIndex > -1 && secondIndex > -1 ) break; + } + if ( firstIndex < 0 || secondIndex < 0 ) { + // we can simply return until temporary faces created + return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES; + } + + // ----------------------------------------------------------- + // 1a. Collect nodes of existing faces + // and build set of face nodes in order to detect missing + // faces corresponing to sides of volumes + // ----------------------------------------------------------- set< set > setOfFaceNodeSet; // loop on the given element of a side for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) { - const SMDS_MeshElement* elem = *eIt; + //const SMDS_MeshElement* elem = *eIt; + const SMDS_MeshElement* elem = (*eIt).second; if ( elem->GetType() == SMDSAbs_Face ) { faceSet->insert( elem ); set faceNodeSet; @@ -3735,10 +6549,9 @@ SMESH_MeshEditor::Sew_Error // face does not exist // ------------------------------------------------------------------------- - if ( !volSet->empty() ) - { + if ( !volSet->empty() ) { //int nodeSetSize = nodeSet->size(); - + // loop on given volumes for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) { SMDS_VolumeTool vol (*vIt); @@ -3757,17 +6570,29 @@ SMESH_MeshEditor::Sew_Error bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second; if ( isNewFace ) { // no such a face is given but it still can exist, check it - if ( nbNodes == 3 ) + if ( nbNodes == 3 ) { aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] ); - else + } + 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); + } } if ( !aFreeFace ) { // create a temporary face - if ( nbNodes == 3 ) + if ( nbNodes == 3 ) { aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] ); - else + } + else if ( nbNodes == 4 ) { aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] ); + } + else { + vector poly_nodes ( fNodes, & fNodes[nbNodes]); + aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes); + } } if ( aFreeFace ) freeFaceList.push_back( aFreeFace ); @@ -3791,7 +6616,7 @@ SMESH_MeshEditor::Sew_Error const SMDS_MeshElement* e = invElemIt->next(); if ( faceSet->find( e ) != faceSet->end() ) nbSharedNodes++; - if ( elemSet->find( e ) != elemSet->end() ) + if ( elemSet->find( e->GetID() ) != elemSet->end() ) nbSharedNodes++; } } @@ -3799,7 +6624,7 @@ SMESH_MeshEditor::Sew_Error maxNbNodes = nbSharedNodes; fIt++; } - else + else freeFaceList.erase( fIt++ ); // here fIt++ occures before erase } if ( freeFaceList.size() > 1 ) @@ -3808,10 +6633,10 @@ SMESH_MeshEditor::Sew_Error // choose a face most close to the bary center of the opposite side gp_XYZ aBC( 0., 0., 0. ); set addedNodes; - set * elemSet2 = elemSetPtr[ 1 - iSide ]; + map * elemSet2 = elemSetPtr[ 1 - iSide ]; eIt = elemSet2->begin(); for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) { - SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator(); + SMDS_ElemIteratorPtr nodeIt = (*eIt).second->nodesIterator(); while ( nodeIt->more() ) { // loop on free face nodes const SMDS_MeshNode* n = static_cast( nodeIt->next() ); @@ -3913,8 +6738,7 @@ SMESH_MeshEditor::Sew_Error // loop on links in linkList; find faces by links and append links // of the found faces to linkList list< TPairOfNodes >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ; - for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) - { + for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) { TPairOfNodes link[] = { *linkIt[0], *linkIt[1] }; long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second ); if ( linkIdSet.find( linkID ) == linkIdSet.end() ) @@ -3926,8 +6750,12 @@ SMESH_MeshEditor::Sew_Error // --------------------------------------------------------------- const SMDS_MeshElement* face[] = { 0, 0 }; - const SMDS_MeshNode* faceNodes[ 2 ][ 5 ]; - const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 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); int iLinkNode[2][2]; for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides const SMDS_MeshNode* n1 = link[iSide].first; @@ -3951,40 +6779,109 @@ SMESH_MeshEditor::Sew_Error faceSet->erase( f ); // get face nodes and find ones of a link iNode = 0; - 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; - faceNodes[ iSide ][ iNode++ ] = n; + 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_QuadraticFaceOfNodes* F = + static_cast(f); + // use special nodes iterator + SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator(); + 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]; } - faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ]; } } } } + // check similarity of elements of the sides if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) { MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 )); - if ( nReplaceMap.size() == 2 ) // faces on input nodes not found + if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES ); - else + } + else { aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS; + } break; // do not return because it s necessary to remove tmp faces } // set nodes to merge // ------------------- - if ( face[0] && face[1] ) - { + if ( face[0] && face[1] ) { int nbNodes = face[0]->NbNodes(); if ( nbNodes != face[1]->NbNodes() ) { MESSAGE("Diff nb of face nodes"); @@ -3992,9 +6889,12 @@ SMESH_MeshEditor::Sew_Error break; // do not return because it s necessary to remove tmp faces } bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle - if ( nbNodes == 3 ) + if ( nbNodes == 3 ) { + //nReplaceMap.insert( TNodeNodeMap::value_type + // ( notLinkNodes[0][0], notLinkNodes[1][0] )); nReplaceMap.insert( TNodeNodeMap::value_type - ( notLinkNodes[0][0], notLinkNodes[1][0] )); + ( notLinkNodes1[0], notLinkNodes2[0] )); + } else { for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides // analyse link orientation in faces @@ -4008,34 +6908,44 @@ SMESH_MeshEditor::Sew_Error 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] )); + //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::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 = nodes[ iNode ]; + //const SMDS_MeshNode* n2 = nodes[ iNode + 1]; + const SMDS_MeshNode* n1 = fnodes1[ iNode ]; + const SMDS_MeshNode* n2 = fnodes1[ iNode + 1]; linkList[0].push_back ( TPairOfNodes( n1, n2 )); linkList[1].push_back ( TPairOfNodes( nReplaceMap[n1], nReplaceMap[n2] )); } @@ -4067,8 +6977,7 @@ SMESH_MeshEditor::Sew_Error // loop on nodes replacement map TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt; for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ ) - if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) - { + if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) { const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first; nodeIDsToRemove.push_back( nToRemove->GetID() ); // loop on elements sharing nToRemove @@ -4077,7 +6986,7 @@ SMESH_MeshEditor::Sew_Error const SMDS_MeshElement* e = invElemIt->next(); // get a new suite of nodes: make replacement int nbReplaced = 0, i = 0, nbNodes = e->NbNodes(); - const SMDS_MeshNode* nodes[ 8 ]; + vector< const SMDS_MeshNode*> nodes( nbNodes ); SMDS_ElemIteratorPtr nIt = e->nodesIterator(); while ( nIt->more() ) { const SMDS_MeshNode* n = @@ -4093,9 +7002,9 @@ SMESH_MeshEditor::Sew_Error // elemIDsToRemove.push_back( e->GetID() ); // else if ( nbReplaced ) - aMesh->ChangeElementNodes( e, nodes, nbNodes ); + aMesh->ChangeElementNodes( e, & nodes[0], nbNodes ); } - } + } Remove( nodeIDsToRemove, true );