- // separate loops
- int nbNew = 0;
- bool foundLoop = (nbSimple > nbUnique);
- while (foundLoop) {
- foundLoop = false;
- set<const SMDS_MeshNode*> 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
-// in all elements.
-//=======================================================================
-
-void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
-{
- MESSAGE("MergeNodes");
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
-
- SMESHDS_Mesh* aMesh = GetMeshDS();
-
- TNodeNodeMap nodeNodeMap; // node to replace - new node
- set<const SMDS_MeshElement*> elems; // all elements with changed nodes
- list< int > rmElemIds, rmNodeIds;
-
- // Fill nodeNodeMap and elems
-
- TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
- for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
- list<const SMDS_MeshNode*>& nodes = *grIt;
- list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
- const SMDS_MeshNode* nToKeep = *nIt;
- //MESSAGE("node to keep " << nToKeep->GetID());
- for ( ++nIt; nIt != nodes.end(); nIt++ ) {
- const SMDS_MeshNode* nToRemove = *nIt;
- nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
- if ( nToRemove != nToKeep ) {
- //MESSAGE(" node to remove " << nToRemove->GetID());
- rmNodeIds.push_back( nToRemove->GetID() );
- AddToSameGroups( nToKeep, nToRemove, aMesh );
- }
-
- SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
- while ( invElemIt->more() ) {
- const SMDS_MeshElement* elem = invElemIt->next();
- elems.insert(elem);
- }
- }
- }
- // Change element nodes or remove an element
-
- set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
- for ( ; eIt != elems.end(); eIt++ ) {
- const SMDS_MeshElement* elem = *eIt;
- //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
- int nbNodes = elem->NbNodes();
- int aShapeId = FindShape( elem );
-
- set<const SMDS_MeshNode*> nodeSet;
- vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
- int iUnique = 0, iCur = 0, nbRepl = 0;
- vector<int> iRepl( nbNodes );
-
- // get new seq of nodes
- SMDS_ElemIteratorPtr itN = elem->nodesIterator();
- while ( itN->more() ) {
- const SMDS_MeshNode* n =
- static_cast<const SMDS_MeshNode*>( itN->next() );
-
- TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
- if ( nnIt != nodeNodeMap.end() ) { // n sticks
- n = (*nnIt).second;
- // BUG 0020185: begin
- {
- bool stopRecur = false;
- set<const SMDS_MeshNode*> nodesRecur;
- nodesRecur.insert(n);
- while (!stopRecur) {
- TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
- if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
- n = (*nnIt_i).second;
- if (!nodesRecur.insert(n).second) {
- // error: recursive dependancy
- stopRecur = true;
- }
- }
- else
- stopRecur = true;
- }
- }
- // BUG 0020185: end
- }
- curNodes[ iCur ] = n;
- bool isUnique = nodeSet.insert( n ).second;
- if ( isUnique )
- uniqueNodes[ iUnique++ ] = n;
- else
- iRepl[ nbRepl++ ] = iCur;
- iCur++;
- }
-
- // Analyse element topology after replacement
-
- bool isOk = true;
- int nbUniqueNodes = nodeSet.size();
- //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
- if ( nbNodes != nbUniqueNodes ) { // some nodes stick
- // Polygons and Polyhedral volumes
- if (elem->IsPoly()) {
-
- if (elem->GetType() == SMDSAbs_Face) {
- // Polygon
- vector<const SMDS_MeshNode *> face_nodes (nbNodes);
- int inode = 0;
- for (; inode < nbNodes; inode++) {
- face_nodes[inode] = curNodes[inode];
- }
-
- vector<const SMDS_MeshNode *> polygons_nodes;
- vector<int> quantities;
- int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
- if (nbNew > 0) {
- inode = 0;
- for (int iface = 0; iface < nbNew; iface++) {
- int nbNodes = quantities[iface];
- vector<const SMDS_MeshNode *> 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);
- }
-
- MESSAGE("ChangeElementNodes MergeNodes Polygon");
- //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
- vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
- int quid =0;
- if (nbNew > 0) quid = nbNew - 1;
- vector<int> newquant(quantities.begin()+quid, quantities.end());
- const SMDS_MeshElement* newElem = 0;
- newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
- myLastCreatedElems.Append(newElem);
- if ( aShapeId && newElem )
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
- rmElemIds.push_back(elem->GetID());
- }
- 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 analyzed in order to check volume validity
- const SMDS_VtkVolume* aPolyedre =
- dynamic_cast<const SMDS_VtkVolume*>( elem );
- if (aPolyedre) {
- int nbFaces = aPolyedre->NbFaces();
-
- vector<const SMDS_MeshNode *> poly_nodes;
- vector<int> quantities;
-
- for (int iface = 1; iface <= nbFaces; iface++) {
- int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
- vector<const SMDS_MeshNode *> 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)
- {
- MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
- //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
- const SMDS_MeshElement* newElem = 0;
- newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
- myLastCreatedElems.Append(newElem);
- if ( aShapeId && newElem )
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
- rmElemIds.push_back(elem->GetID());
- }
- }
- else {
- rmElemIds.push_back(elem->GetID());
- }
- }
- }
- else {
- }
-
- continue;
- } // poly element
-
- // Regular elements
- // TODO not all the possible cases are solved. Find something more generic?
- switch ( nbNodes ) {
- case 2: ///////////////////////////////////// EDGE
- isOk = false; break;
- case 3: ///////////////////////////////////// TRIANGLE
- isOk = false; break;
- case 4:
- if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
- isOk = false;
- else { //////////////////////////////////// QUADRANGLE
- if ( nbUniqueNodes < 3 )
- isOk = false;
- else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
- isOk = false; // opposite nodes stick
- //MESSAGE("isOk " << isOk);
- }
- break;
- case 6: ///////////////////////////////////// PENTAHEDRON
- if ( nbUniqueNodes == 4 ) {
- // ---------------------------------> tetrahedron
- if (nbRepl == 3 &&
- iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
- // all top nodes stick: reverse a bottom
- uniqueNodes[ 0 ] = curNodes [ 1 ];
- uniqueNodes[ 1 ] = curNodes [ 0 ];
- }
- else if (nbRepl == 3 &&
- iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
- // all bottom nodes stick: set a top before
- uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
- uniqueNodes[ 0 ] = curNodes [ 3 ];
- uniqueNodes[ 1 ] = curNodes [ 4 ];
- uniqueNodes[ 2 ] = curNodes [ 5 ];
- }
- else if (nbRepl == 4 &&
- iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
- // a lateral face turns into a line: reverse a bottom
- uniqueNodes[ 0 ] = curNodes [ 1 ];
- uniqueNodes[ 1 ] = curNodes [ 0 ];
- }
- else
- isOk = false;
- }
- else if ( nbUniqueNodes == 5 ) {
- // PENTAHEDRON --------------------> 2 tetrahedrons
- if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
- // a bottom node sticks with a linked top one
- // 1.
- 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
- uniqueNodes[ 0 ] = curNodes [ 1 ];
- uniqueNodes[ 1 ] = curNodes [ 0 ];
- nbUniqueNodes = 4;
- }
- else
- isOk = false;
- }
- else
- isOk = false;
- break;
- case 8: {
- if(elem->IsQuadratic()) { // Quadratic quadrangle
- // 1 5 2
- // +---+---+
- // | |
- // | |
- // 4+ +6
- // | |
- // | |
- // +---+---+
- // 0 7 3
- isOk = false;
- if(nbRepl==2) {
- MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
- }
- if(nbRepl==3) {
- MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2]);
- 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;
- }
- }
- if(nbRepl==4) {
- MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3]);
- }
- if(nbRepl==5) {
- MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
- }
- break;
- }
- //////////////////////////////////// HEXAHEDRON
- isOk = false;
- SMDS_VolumeTool hexa (elem);
- hexa.SetExternalNormal();
- if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
- //////////////////////// HEX ---> 1 tetrahedron
- for ( int iFace = 0; iFace < 6; iFace++ ) {
- const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
- if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
- curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
- curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
- // one face turns into a point ...
- int iOppFace = hexa.GetOppFaceIndex( iFace );
- ind = hexa.GetFaceNodesIndices( iOppFace );
- int nbStick = 0;
- for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
- if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
- nbStick++;
- }
- if ( nbStick == 1 ) {
- // ... and the opposite one - into a triangle.
- // set a top node
- ind = hexa.GetFaceNodesIndices( iFace );
- uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
- isOk = true;
- }
- break;
- }
- }
- }
- else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
- //////////////////////// HEX ---> 1 prism
- int nbTria = 0, iTria[3];
- const int *ind; // indices of face nodes
- // look for triangular faces
- for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
- ind = hexa.GetFaceNodesIndices( iFace );
- TIDSortedNodeSet faceNodes;
- for ( iCur = 0; iCur < 4; iCur++ )
- faceNodes.insert( curNodes[ind[iCur]] );
- if ( faceNodes.size() == 3 )
- iTria[ nbTria++ ] = iFace;
- }
- // check if triangles are opposite
- if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
- {
- isOk = true;
- // set nodes of the bottom triangle
- ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
- vector<int> indB;
- for ( iCur = 0; iCur < 4; iCur++ )
- if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
- indB.push_back( ind[iCur] );
- if ( !hexa.IsForward() )
- std::swap( indB[0], indB[2] );
- for ( iCur = 0; iCur < 3; iCur++ )
- uniqueNodes[ iCur ] = curNodes[indB[iCur]];
- // set nodes of the top triangle
- const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
- for ( iCur = 0; iCur < 3; ++iCur )
- for ( int j = 0; j < 4; ++j )
- if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
- {
- uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
- break;
- }
- }
- break;
- }
- else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
- //////////////////// HEXAHEDRON ---> 2 tetrahedrons
- for ( int iFace = 0; iFace < 6; iFace++ ) {
- const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
- if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
- curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
- curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
- // one face turns into a point ...
- int iOppFace = hexa.GetOppFaceIndex( iFace );
- ind = hexa.GetFaceNodesIndices( iOppFace );
- int nbStick = 0;
- iUnique = 2; // reverse a tetrahedron 1 bottom
- for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
- if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
- nbStick++;
- else if ( iUnique >= 0 )
- uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
- }
- if ( nbStick == 0 ) {
- // ... and the opposite one is a quadrangle
- // set a top node
- const int* indTop = hexa.GetFaceNodesIndices( iFace );
- uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
- nbUniqueNodes = 4;
- // tetrahedron 2
- 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;
- }
- break;
- }
- }
- }
- else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
- ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
- // find indices of quad and tri faces
- int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
- for ( iFace = 0; iFace < 6; iFace++ ) {
- const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
- nodeSet.clear();
- for ( iCur = 0; iCur < 4; iCur++ )
- nodeSet.insert( curNodes[ind[ iCur ]] );
- nbUniqueNodes = nodeSet.size();
- if ( nbUniqueNodes == 3 )
- iTriFace[ nbTri++ ] = iFace;
- else if ( nbUniqueNodes == 4 )
- iQuadFace[ nbQuad++ ] = iFace;
- }
- if (nbQuad == 2 && nbTri == 4 &&
- hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
- // 2 opposite quadrangles stuck with a diagonal;
- // sample groups of merged indices: (0-4)(2-6)
- // --------------------------------------------> 2 tetrahedrons
- const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
- const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
- int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
- if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
- curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
- // stuck with 0-2 diagonal
- i0 = ind1[ 3 ];
- i1d = ind1[ 0 ];
- i2 = ind1[ 1 ];
- i3d = ind1[ 2 ];
- i0t = ind2[ 1 ];
- i2t = ind2[ 3 ];
- }
- else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
- curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
- // stuck with 1-3 diagonal
- i0 = ind1[ 0 ];
- i1d = ind1[ 1 ];
- i2 = ind1[ 2 ];
- i3d = ind1[ 3 ];
- i0t = ind2[ 0 ];
- i2t = ind2[ 1 ];
- }
- else {
- ASSERT(0);
- }
- // tetrahedron 1
- uniqueNodes[ 0 ] = curNodes [ i0 ];
- uniqueNodes[ 1 ] = curNodes [ i1d ];
- uniqueNodes[ 2 ] = curNodes [ i3d ];
- uniqueNodes[ 3 ] = curNodes [ i0t ];
- nbUniqueNodes = 4;
- // tetrahedron 2
- SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
- curNodes[ i2 ],
- curNodes[ i3d ],
- curNodes[ i2t ]);
- myLastCreatedElems.Append(newElem);
- if ( aShapeId )
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
- isOk = true;
- }
- else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
- ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
- // --------------------------------------------> prism
- // find 2 opposite triangles
- nbUniqueNodes = 6;
- for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
- if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
- // find indices of kept and replaced nodes
- // and fill unique nodes of 2 opposite triangles
- const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
- const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
- const SMDS_MeshNode** hexanodes = hexa.GetNodes();
- // fill unique nodes
- iUnique = 0;
- isOk = true;
- for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
- const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
- const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
- if ( n == nInit ) {
- // iCur of a linked node of the opposite face (make normals co-directed):
- int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
- // check that correspondent corners of triangles are linked
- if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
- isOk = false;
- else {
- uniqueNodes[ iUnique ] = n;
- uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
- iUnique++;
- }
- }
- }
- break;
- }
- }
- }
- } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
- else
- {
- MESSAGE("MergeNodes() removes hexahedron "<< elem);
- }
- break;
- } // HEXAHEDRON
-
- default:
- isOk = false;
- } // switch ( nbNodes )
-
- } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
-
- if ( isOk ) { // the elem remains valid after sticking nodes
- if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
- {
- // Change nodes of polyedre
- const SMDS_VtkVolume* aPolyedre =
- dynamic_cast<const SMDS_VtkVolume*>( elem );
- if (aPolyedre) {
- int nbFaces = aPolyedre->NbFaces();
-
- vector<const SMDS_MeshNode *> poly_nodes;
- vector<int> 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 // replace non-polyhedron elements
- {
- const SMDSAbs_ElementType etyp = elem->GetType();
- const int elemId = elem->GetID();
- const bool isPoly = (elem->GetEntityType() == SMDSEntity_Polygon);
- uniqueNodes.resize(nbUniqueNodes);
-
- SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
-
- aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
- SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
- if ( sm && newElem )
- sm->AddElement( newElem );
- if ( elem != newElem )
- ReplaceElemInGroups( elem, newElem, aMesh );
- }
- }
- else {
- // Remove invalid regular element or invalid polygon
- rmElemIds.push_back( elem->GetID() );
- }
-
- } // loop on elements
-
- // Remove bad elements, then equal nodes (order important)
-
- Remove( rmElemIds, false );
- Remove( rmNodeIds, true );
-
-}
-
-
-// ========================================================
-// class : SortableElement
-// purpose : allow sorting elements basing on their nodes
-// ========================================================
-class SortableElement : public set <const SMDS_MeshElement*>
-{
-public:
-
- SortableElement( const SMDS_MeshElement* theElem )
- {
- myElem = theElem;
- SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
- while ( nodeIt->more() )
- this->insert( nodeIt->next() );
- }
-
- const SMDS_MeshElement* Get() const
- { return myElem; }
-
- void Set(const SMDS_MeshElement* e) const
- { myElem = e; }
-
-
-private:
- mutable const SMDS_MeshElement* myElem;
-};
-
-//=======================================================================
-//function : FindEqualElements
-//purpose : Return list of group of elements built on the same nodes.
-// Search among theElements or in the whole mesh if theElements is empty
-//=======================================================================
-void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
- TListOfListOfElementsID & theGroupsOfElementsID)
-{
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
-
- typedef set<const SMDS_MeshElement*> TElemsSet;
- typedef map< SortableElement, int > TMapOfNodeSet;
- typedef list<int> TGroupOfElems;
-
- TElemsSet elems;
- if ( theElements.empty() )
- { // get all elements in the mesh
- SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
- while ( eIt->more() )
- elems.insert( elems.end(), eIt->next());
- }
- else
- elems = theElements;
-
- vector< TGroupOfElems > arrayOfGroups;
- TGroupOfElems groupOfElems;
- TMapOfNodeSet mapOfNodeSet;
-
- TElemsSet::iterator elemIt = elems.begin();
- for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
- const SMDS_MeshElement* curElem = *elemIt;
- SortableElement SE(curElem);
- int ind = -1;
- // check uniqueness
- pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
- if( !(pp.second) ) {
- TMapOfNodeSet::iterator& itSE = pp.first;
- ind = (*itSE).second;
- arrayOfGroups[ind].push_back(curElem->GetID());
- }
- else {
- groupOfElems.clear();
- groupOfElems.push_back(curElem->GetID());
- arrayOfGroups.push_back(groupOfElems);
- i++;
- }
- }
-
- vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
- for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
- groupOfElems = *groupIt;
- if ( groupOfElems.size() > 1 ) {
- groupOfElems.sort();
- theGroupsOfElementsID.push_back(groupOfElems);
- }
- }
-}
-
-//=======================================================================
-//function : MergeElements
-//purpose : In each given group, substitute all elements by the first one.
-//=======================================================================
-
-void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
-{
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
-
- typedef list<int> TListOfIDs;
- TListOfIDs rmElemIds; // IDs of elems to remove
-
- SMESHDS_Mesh* aMesh = GetMeshDS();
-
- TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
- while ( groupsIt != theGroupsOfElementsID.end() ) {
- TListOfIDs& aGroupOfElemID = *groupsIt;
- aGroupOfElemID.sort();
- int elemIDToKeep = aGroupOfElemID.front();
- const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
- aGroupOfElemID.pop_front();
- TListOfIDs::iterator idIt = aGroupOfElemID.begin();
- while ( idIt != aGroupOfElemID.end() ) {
- int elemIDToRemove = *idIt;
- const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
- // add the kept element in groups of removed one (PAL15188)
- AddToSameGroups( elemToKeep, elemToRemove, aMesh );
- rmElemIds.push_back( elemIDToRemove );
- ++idIt;
- }
- ++groupsIt;
- }
-
- Remove( rmElemIds, false );
-}
-
-//=======================================================================
-//function : MergeEqualElements
-//purpose : Remove all but one of elements built on the same nodes.
-//=======================================================================
-
-void SMESH_MeshEditor::MergeEqualElements()
-{
- set<const SMDS_MeshElement*> aMeshElements; /* empty input -
- to merge equal elements in the whole mesh */
- TListOfListOfElementsID aGroupsOfElementsID;
- FindEqualElements(aMeshElements, aGroupsOfElementsID);
- MergeElements(aGroupsOfElementsID);
-}
-
-//=======================================================================
-//function : FindFaceInSet
-//purpose : Return a face having linked nodes n1 and n2 and which is
-// - not in avoidSet,
-// - in elemSet provided that !elemSet.empty()
-// i1 and i2 optionally returns indices of n1 and n2
-//=======================================================================
-
-const SMDS_MeshElement*
-SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
- const SMDS_MeshNode* n2,
- const TIDSortedElemSet& elemSet,
- const TIDSortedElemSet& avoidSet,
- int* n1ind,
- int* n2ind)
-
-{
- int i1, i2;
- const SMDS_MeshElement* face = 0;
-
- SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
- //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
- while ( invElemIt->more() && !face ) // loop on inverse faces of n1
- {
- //MESSAGE("in while ( invElemIt->more() && !face )");
- const SMDS_MeshElement* elem = invElemIt->next();
- if (avoidSet.count( elem ))
- continue;
- if ( !elemSet.empty() && !elemSet.count( elem ))
- continue;
- // index of n1
- i1 = elem->GetNodeIndex( n1 );
- // find a n2 linked to n1
- int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
- for ( int di = -1; di < 2 && !face; di += 2 )
- {
- i2 = (i1+di+nbN) % nbN;
- if ( elem->GetNode( i2 ) == n2 )
- face = elem;
- }
- if ( !face && elem->IsQuadratic())
- {
- // analysis for quadratic elements using all nodes
- const SMDS_VtkFace* F =
- dynamic_cast<const SMDS_VtkFace*>(elem);
- if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
- // use special nodes iterator
- SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
- const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
- for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
- {
- const SMDS_MeshNode* n = cast2Node( anIter->next() );
- if ( n1 == prevN && n2 == n )
- {
- face = elem;
- }
- else if ( n2 == prevN && n1 == n )
- {
- face = elem; swap( i1, i2 );
- }
- prevN = n;
- }
- }
- }
- if ( n1ind ) *n1ind = i1;
- if ( n2ind ) *n2ind = i2;
- return face;
-}
-
-//=======================================================================
-//function : findAdjacentFace
-//purpose :
-//=======================================================================
-
-static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
- const SMDS_MeshNode* n2,
- const SMDS_MeshElement* elem)
-{
- TIDSortedElemSet elemSet, avoidSet;
- if ( elem )
- avoidSet.insert ( elem );
- return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
-}
-
-//=======================================================================
-//function : FindFreeBorder
-//purpose :
-//=======================================================================
-
-#define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
-
-bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
- const SMDS_MeshNode* theSecondNode,
- const SMDS_MeshNode* theLastNode,
- list< const SMDS_MeshNode* > & theNodes,
- list< const SMDS_MeshElement* >& theFaces)
-{
- if ( !theFirstNode || !theSecondNode )
- return false;
- // find border face between theFirstNode and theSecondNode
- const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
- if ( !curElem )
- return false;
-
- theFaces.push_back( curElem );
- theNodes.push_back( theFirstNode );
- theNodes.push_back( theSecondNode );
-
- //vector<const SMDS_MeshNode*> nodes;
- const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
- TIDSortedElemSet foundElems;
- bool needTheLast = ( theLastNode != 0 );
-
- while ( nStart != theLastNode ) {
- if ( nStart == theFirstNode )
- return !needTheLast;
-
- // find all free border faces sharing form nStart
-
- list< const SMDS_MeshElement* > curElemList;
- list< const SMDS_MeshNode* > nStartList;
- SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
- while ( invElemIt->more() ) {
- const SMDS_MeshElement* e = invElemIt->next();
- if ( e == curElem || foundElems.insert( e ).second ) {
- // get nodes
- int iNode = 0, nbNodes = e->NbNodes();
- //const SMDS_MeshNode* nodes[nbNodes+1];
- vector<const SMDS_MeshNode*> nodes(nbNodes+1);
-
- if(e->IsQuadratic()) {
- const SMDS_VtkFace* F =
- dynamic_cast<const SMDS_VtkFace*>(e);
- if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
- // use special nodes iterator
- SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
- while( anIter->more() ) {
- nodes[ iNode++ ] = cast2Node(anIter->next());
- }
- }
- else {
- SMDS_ElemIteratorPtr nIt = e->nodesIterator();
- while ( nIt->more() )
- nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
- }
- nodes[ iNode ] = nodes[ 0 ];
- // check 2 links
- for ( iNode = 0; iNode < nbNodes; iNode++ )
- if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
- (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
- ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
- {
- nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
- curElemList.push_back( e );